#include <QKeyEvent>
#include <QClipboard>

#include "QFitsMainWindow.h"
#include "QFitsMainView.h"
#include "QFitsWidget1D.h"
#include "QFitsCubeSpectrum.h"
#include "QFitsSingleBuffer.h"
#include "QFitsGlobal.h"
#include "QFitsToolBar.h"
#include "fitting.h"
#include "qtdpuser.h"

QFitsWidget1D::QFitsWidget1D(QFitsBaseBuffer *bb) : QFitsBaseWidget(bb)
{
    QPalette pal(palette());
    pal.setColor(QPalette::Window, Qt::white);

//    setAutoFillBackground(true);
    setPalette(pal);


    fitx[0] = fitx[1] = fity[0] = fity[1] = 0.0;
    bstart = bend = ngauss = 0;
    heightupdate = posupdate = fwhmupdate = baseupdate = 0;
    currentStatusBarText = 0;
    dagain = gagain = bagain = false;
    fitgx.create(20, 1, R8);
    fitgy.create(20, 1, R8);
    types.create(10, 1, I1);
    params.create(10, 2, R8);
    fitparams.create(1, 1, R8);
    plotter = new QFitsView1D(this);
    rangeControl = new QFitsSpectrumRangeControl(this);
    connect(rangeControl, SIGNAL(channelRangeChanged()),
            this, SLOT(updateRange()));
    connect(plotter, SIGNAL(rangeChanged(const double &,const double &)), this, SLOT(rangeChanged(const double &,const double &)));
    fitresults = new QTableWidget(0, 4, this);
    QStringList headers;
    headers.append("Flux");
    headers.append("Height");
    headers.append("Center");
    headers.append("FWHM");
    fitresults->setHorizontalHeaderLabels(headers);
    fitresults->hide();

    fitestimates = new QFitsTransparentLabel(this, plotter);
    fitestimates->setGeometry(100, 100, 200, 200);
    fitestimates->hide();

    dpQtPlotStatusBarText.append("Mouse-left: select region; "
                               "Keys: d=Deblend Lines : -=subtract fit : "
                               "+=add fit : ESC=clear");
    dpQtPlotStatusBarText.append("Mouse-left: select region; "
                               "Keys: g=Gauss : l=Lorentz : f=fit : ESC=clear");
    dpQtPlotStatusBarText.append("d again : ESC=clear");
    dpQtPlotStatusBarText.append("g again : ESC=clear");
    dpQtPlotStatusBarText.append("l again : ESC=clear");
}

QFitsWidget1D::~QFitsWidget1D() {
    if (fitestimates) {
        delete fitestimates; fitestimates = NULL;
    }
    if (plotter) {
        delete plotter; plotter = NULL;
    }
}

void QFitsWidget1D::resizeEvent(QResizeEvent *e) {
    if (fitresults->isVisible()) {
        fitresults->move(0, 0);
        plotter->setGeometry(fitresults->width(),
                             0,
                             width() - fitresults->width(),
                             height() - rangeControl->height());
        fitresults->resize(fitresults->width(), height());
    } else {
        plotter->setGeometry(0, 0, width(), height() - rangeControl->height());
    }
    rangeControl->setGeometry(0, size().height()-rangeControl->height(),
                                   size().width(), rangeControl->height());
    QFitsBaseWidget::resizeEvent(e);
}

void QFitsWidget1D::paintEvent(QPaintEvent *e) {
    if ((fitparams.Nelements() > 1) || (fitx[0] != 0. && fitx[1] != 0)) {
        Fits    xvalues,
                yvalues;
//        int x1 = (int)(plotter->getCrpix() + (fitx[0] - plotter->getCrval()) /
//                                                                    plotter->getCdelt() + 0.5),
//            x2 = (int)(plotter->getCrpix() + (fitx[1] - plotter->getCrval()) /
//                                                                    plotter->getCdelt() + 0.5);
        int x1 = wavepix(fitx[0], plotter->getCrpix(), plotter->getCrval(), plotter->getCdelt(), plotter->isLogwave()),
            x2 = wavepix(fitx[1], plotter->getCrpix(), plotter->getCrval(), plotter->getCdelt(), plotter->isLogwave());
        xvalues.create(labs(x2 - x1) + 1, 1, R8);
        for (int i = 0; i < xvalues.Nelements(); i++) {
//            xvalues.r8data[i] = plotter->getCrval() +
//                                ((double)(i+MIN(x1,x2)) - plotter->getCrpix()) *
//                                                                 plotter->getCdelt();
            xvalues.r8data[i] = pixwave(i+MIN(x1,x2), plotter->getCrpix(), plotter->getCrval(), plotter->getCdelt(), plotter->isLogwave());
        }

        if (fitestimates->getShowEstimates()) {
            params.create(2 + fitestimates->getNlines() * 3, 2, R8);
            double s = (fitestimates->getEstimateFitY(1) - fitestimates->getEstimateFitY(0)) /
                       (fitestimates->getEstimateFitX(1) - fitestimates->getEstimateFitX(0));
            params.r8data[0] = fitestimates->getEstimateFitY(0) -
                               s * fitestimates->getEstimateFitX(0);
            params.r8data[1] = s;
            for (int g = 0; g < fitestimates->getNlines(); g++) {
                params.r8data[2+g*3] = fitestimates->getEstimateFitGY(g*2) -
                                       (fitestimates->getEstimateFitGX(g*2) * s + params.r8data[0]);
                params.r8data[3+g*3] = fitestimates->getEstimateFitGX(g*2);
                params.r8data[4+g*3] = 2.0 * fabs(fitestimates->getEstimateFitGX(g*2) -
                                                  fitestimates->getEstimateFitGX(g*2+1));
            }
        } else {
            params.copy(*(fitestimates->getFitResult()));
        }
        evaluate_multifunc(yvalues, xvalues, params, types);
        plotter->setData2(xvalues.r8data, yvalues.r8data, xvalues.Nelements());
    }
}

void QFitsWidget1D::keyReleaseEvent(QKeyEvent *e) {
    if (!e->isAutoRepeat()) {
        if (e->key() == Qt::Key_B) {
            QCursor mycursor = plotter->cursor();
            QPoint pos = plotter->mapFromGlobal(mycursor.pos());
            bend = pos.x();
            plotter->setSelectstart(QPoint(-1, -1));
            bagain = false;
            double xpos1 = plotter->pixelToWavelength(
                                        bstart - plotter->getMargin() - plotter->getFw());
            double xpos2 = plotter->pixelToWavelength(
                                          bend - plotter->getMargin() - plotter->getFw());

//            int start = (int)(plotter->getCrpix() + (xpos1 - plotter->getCrval()) /
//                                                          plotter->getCdelt() + 0.5);
//            int end = (int)(plotter->getCrpix() + (xpos2 - plotter->getCrval()) /
//                                                          plotter->getCdelt() + 0.5);
            int start = wavepix(xpos1, plotter->getCrpix(), plotter->getCrval(), plotter->getCdelt(), plotter->isLogwave());
            int end = wavepix(xpos2, plotter->getCrpix(), plotter->getCrval(), plotter->getCdelt(), plotter->isLogwave());
            if (!getMyBuffer()->isMultiBufferChild()) {
                dpuser_widget->executeCommand(
                        QString(getBufferIndex().c_str()) +
                        /*getMyBuffer()->getExtensionIndicesString() +*/ "[" +
                        QString::number(start) + ":" + QString::number(end) +
                        "] = 1/0");
            }
        }
    }
}

bool QFitsWidget1D::handleMousePressEvent(QMouseEvent *e) {
    bool rv = true;
    if (heightupdate) {
        heightupdate = 0;
        fitestimates->removeMarker2();
    } else if (posupdate) {
        posupdate = 0;
        fitestimates->removeMarker2();
    } else if (fwhmupdate) {
        fwhmupdate = 0;
        fitestimates->removeMarker2();
    } else if (baseupdate) {
        baseupdate = 0;
        fitestimates->removeMarker2();
    } else {
        rv = false;
    }
    return rv;
}

void QFitsWidget1D::updateScaling() {
    plotter->updateScaling();
}

void QFitsWidget1D::updateRange() {
    updateScaling();
}

void QFitsWidget1D::rangeChanged(const double &min, const double &max) {
    rangeControl->setPhysicalRange(min, max);
}

void QFitsWidget1D::setXRange(const double &min, const double &max) {
    plotter->setXRange(min, max);
}

void QFitsWidget1D::setYRange(const double &min, const double &max) {
    plotter->setYRange(min, max);
}

void QFitsWidget1D::setData() {
    plotter->setData();
    rangeControl->setSpectrum(plotter->getNdata(), plotter->getCrpix(), plotter->getCrval(), plotter->getCdelt(), plotter->isLogwave());
}

void QFitsWidget1D::hide() {
    fitestimates->hide();
    QWidget::hide();
}

void QFitsWidget1D::plotterKeyPressEvent(QKeyEvent *e) {
    QPoint pos;
    double dxpos, dypos;
    static bool firstfit = true;

    if (!e->isAutoRepeat()) {
        if ((e->key() == Qt::Key_D) || (e->key() == Qt::Key_G) ||
            (e->key() == Qt::Key_L) || (e->key() == Qt::Key_B))
        {
            QCursor mycursor = plotter->cursor();
            pos = plotter->mapFromGlobal(mycursor.pos());
            dxpos = plotter->pixelToWavelength(
                                       pos.x() - plotter->getMargin() - plotter->getFw());
            dypos = plotter->pixelToValue(pos.y());
        }
        switch (e->key()) {
            case Qt::Key_Escape:
                handleescape();
                break;
            case Qt::Key_D:
                if (baseupdate) {
                    baseupdate = 0;
                    fitestimates->removeMarker2();
                } else if (dagain && (dxpos > fitx[0])) {
                    fitx[1] = dxpos;
                    fity[1] = dypos;
                    dagain = false;
                    currentStatusBarText = 1;
                    emit statusbartext(
                        dpQtPlotStatusBarText[currentStatusBarText].toStdString().c_str());
                } else {
                    fitx[0] = dxpos;
                    fity[0] = dypos;
                    fitgx.create(20, 1, R8);
                    fitgy.create(20, 1, R8);
                    fitparams.create(1, 1, R8);
                    types.create(10, 1, I1);
                    ngauss = 0;
                    dagain = true;
                    gagain = false;
                    currentStatusBarText = 2;
                    emit statusbartext(
                        dpQtPlotStatusBarText[currentStatusBarText].toStdString().c_str());
                    if (firstfit) {
                        fitestimates->move(mapToGlobal(QPoint(0, 0)));
                        firstfit = false;
                    }
                }
                break;
            case Qt::Key_G:
                if (heightupdate) {
                    heightupdate = 0;
                    fitestimates->removeMarker2();
                } else if (posupdate) {
                    posupdate = 0;
                    fitestimates->removeMarker2();
                } else if (fwhmupdate) {
                    fwhmupdate = 0;
                    fitestimates->removeMarker2();
                } else if (gagain) {
                    fitgx.r8data[(ngauss-1)*2+1] = dxpos;
                    gagain = false;
                    currentStatusBarText = 1;
                    emit statusbartext(
                        dpQtPlotStatusBarText[currentStatusBarText].toStdString().c_str());
                } else {
                    if ((ngauss > 0) && (ngauss * 2 > fitgx.Naxis(1) - 2)) {
                        fitgx.resize(ngauss * 4);
                        fitgy.resize(ngauss * 4);
                        types.resize(ngauss * 2);
                    }
                    if ((fitx[0] != 0.0) && (fitx[1] != 0.0) &&
                        (dxpos > fitx[0]) && (dxpos < fitx[1]))
                    {
                        fitgx.r8data[ngauss*2] = dxpos;
                        fitgy.r8data[ngauss*2] = dypos;
                        fitgx.r8data[ngauss*2+1] = dxpos;
                        types.i1data[ngauss] = 0;
                        ngauss++;
                        gagain = true;
                        currentStatusBarText = 3;
                        emit statusbartext(
                            dpQtPlotStatusBarText[currentStatusBarText].toStdString().c_str());
                    }
                }
                break;
            case Qt::Key_L:
                if (heightupdate) {
                    heightupdate = 0;
                    fitestimates->removeMarker2();
                } else if (posupdate) {
                    posupdate = 0;
                    fitestimates->removeMarker2();
                } else if (fwhmupdate) {
                    fwhmupdate = 0;
                    fitestimates->removeMarker2();
                } else if (gagain) {
                    fitgx.r8data[(ngauss-1)*2+1] = dxpos;
                    gagain = false;
                    currentStatusBarText = 1;
                    emit statusbartext(
                        dpQtPlotStatusBarText[currentStatusBarText].toStdString().c_str());
                } else {
                    if ((ngauss > 0) && (ngauss * 2 > fitgx.Naxis(1) - 2)) {
                        fitgx.resize(ngauss * 4);
                        fitgy.resize(ngauss * 4);
                        types.resize(ngauss * 2);
                    }
                    if ((fitx[0] != 0.0) && (fitx[1] != 0.0) &&
                        (dxpos > fitx[0]) && (dxpos < fitx[1]))
                    {
                        fitgx.r8data[ngauss*2] = dxpos;
                        fitgy.r8data[ngauss*2] = dypos;
                        fitgx.r8data[ngauss*2+1] = dxpos;
                        types.i1data[ngauss] = 1;
                        ngauss++;
                        gagain = true;
                        currentStatusBarText = 4;
                        emit statusbartext(
                            dpQtPlotStatusBarText[currentStatusBarText].toStdString().c_str());
                    }
                }
                break;
            case Qt::Key_F:
                dofit();
                currentStatusBarText = 0;
                emit statusbartext(
                        dpQtPlotStatusBarText[currentStatusBarText].toStdString().c_str());
                break;
            case Qt::Key_Minus:
                subtractfit();
                break;
            case Qt::Key_Plus:
                addfit();
                break;
            case Qt::Key_B:
                if (!getMyBuffer()->isMultiBufferChild()) {
                    if (bagain) {
                        plotter->setSelectstart(QPoint(-1, -1));
                        bend = pos.x();
                        bagain = false;
                    } else {
                        plotter->setSelectstart(pos);
                        bstart = pos.x();
                        bagain = true;
                    }
                }
                break;
            default:
                fitsMainWindow->main_view->keyPressEvent(e);
                break;
        }
    } else {
        fitsMainWindow->main_view->keyPressEvent(e);
    }
    update();
}

void QFitsWidget1D::plotterMouseMoveEvent(QMouseEvent *e) {
    if (plotter->getNdata() == 0) {
        return;
    }

//    if (!isActiveWindow()) activateWindow();

    double value = 0.0;
    double xpos = plotter->pixelToWavelength(
                                  e->pos().x() - plotter->getMargin() - plotter->getFw());

//    int ppos = (int)(plotter->getCrpix() + (xpos - plotter->getCrval()) / plotter->getCdelt() + 0.5);
    int ppos = wavepix(xpos, plotter->getCrpix(), plotter->getCrval(), plotter->getCdelt(), plotter->isLogwave());
    if (ppos > 0 && ppos <= plotter->getNdata()) {
        value = plotter->getYdata()[ppos-1];
    }

    if (dagain && (xpos > fitx[0])) {
        double ypos = plotter->pixelToValue(e->pos().y());
        fitx[1] = xpos;
        fity[1] = ypos;
    }
    if (gagain) {
        double ypos = plotter->pixelToValue(e->pos().y());
        fitgy.r8data[(ngauss-1)*2] = ypos;
        fitgx.r8data[(ngauss-1)*2+1] = xpos;
    }
    if (bagain) {
        bend = e->pos().x();
    }
    if (heightupdate) {
        fitgy.r8data[(heightupdate-1)*2] = plotter->pixelToValue(e->pos().y());
    }
    if (posupdate) {
        double f = fitgx.r8data[(posupdate-1)*2+1] - fitgx.r8data[(posupdate-1)*2];
        double dx = xpos - fitgx.r8data[(posupdate-1)*2];
        double s = (fity[1] - fity[0]) / (fitx[1] - fitx[0]);

        fitgx.r8data[(posupdate-1)*2] = xpos;
        fitgx.r8data[(posupdate-1)*2+1] = xpos + f;
        fitgy.r8data[(posupdate-1)*2] = fitgy.r8data[(posupdate-1)*2] + s * dx;
    }
    if (fwhmupdate) {
        fitgx.r8data[(fwhmupdate-1)*2+1] = xpos;
    }
    if (baseupdate) {
        double ypos = plotter->pixelToValue(e->pos().y());
        fitx[baseupdate-1] = xpos;
        fity[baseupdate-1] = ypos;
    }
    if (dagain || gagain || bagain || heightupdate ||
        posupdate || fwhmupdate || baseupdate)
    {
        fitestimates->setFitEstimates(ngauss, fitx, fity, types, fitgx, fitgy);
    }
}

void QFitsWidget1D::enterEvent(QEvent *e) {
    emit statusbartext(dpQtPlotStatusBarText[currentStatusBarText].toStdString().c_str());
}

void QFitsWidget1D::updateHeight(int n) {
    heightupdate = n-1;
    int tmpX = plotter->wavelengthToPixel(
            fitestimates->getEstimateFitGX()->r8data[(heightupdate-1)*2]);
    int tmpY = plotter->valueToPixel(fitestimates->getEstimateFitGY()->r8data[(heightupdate-1)*2]);
    cursor().setPos(QPoint(tmpX, tmpY) +
                    mapToGlobal(QPoint(plotter->getMargin() + plotter->getFw(), 0)));
}

void QFitsWidget1D::updatePos(int n) {
    posupdate = n-1;
    int tmpX = plotter->wavelengthToPixel(fitestimates->getEstimateFitGX()->r8data[(posupdate-1)*2]);
    int tmpY = plotter->valueToPixel(fitestimates->getEstimateFitGY()->r8data[(posupdate-1)*2]);
    cursor().setPos(QPoint(tmpX, tmpY) +
                    mapToGlobal(QPoint(plotter->getMargin() + plotter->getFw(), 0)));
}

void QFitsWidget1D::updateFWHM(int n) {
    fwhmupdate = n-1;
    int tmpX = plotter->wavelengthToPixel(fitestimates->getEstimateFitGX()->r8data[(fwhmupdate-1)*2+1]);
    int tmpY = plotter->valueToPixel(fitestimates->getEstimateFitGY()->r8data[(fwhmupdate-1)*2]);
    cursor().setPos(QPoint(tmpX, tmpY) +
                    mapToGlobal(QPoint(plotter->getMargin() + plotter->getFw(), 0)));
}

void QFitsWidget1D::updateBase(int n) {
    if ((n > 2) || (n < 0)) {
        return;
    }
    baseupdate = n+1;
    int tmpX = plotter->wavelengthToPixel(fitestimates->getEstimateFitX(baseupdate-1));
    int tmpY = plotter->valueToPixel(fitestimates->getEstimateFitY(baseupdate-1));
    cursor().setPos(QPoint(tmpX, tmpY) +
                    mapToGlobal(QPoint(plotter->getMargin() + plotter->getFw(), 0)));
}

void QFitsWidget1D::dofit() {
    double chisq;

    if (fitx[0] == 0.0 && fitx[1] == 0.0)
        return;

    int i, x1, x2, g;
    Fits xvalues, yvalues, errors;

    double s = (fity[1] - fity[0]) / (fitx[1] - fitx[0]);
//    x1 = (int)(plotter->getCrpix() + (fitx[0] - plotter->getCrval()) / plotter->getCdelt() + 0.5);
//    x2 = (int)(plotter->getCrpix() + (fitx[1] - plotter->getCrval()) / plotter->getCdelt() + 0.5);
    x1 = wavepix(fitx[0], plotter->getCrpix(), plotter->getCrval(), plotter->getCdelt(), plotter->isLogwave());
    x2 = wavepix(fitx[1], plotter->getCrpix(), plotter->getCrval(), plotter->getCdelt(), plotter->isLogwave());

    xvalues.create(labs(x2 - x1) + 1, 1, R8);
    yvalues.create(labs(x2 - x1) + 1, 1, R8);
    errors.create(labs(x2 - x1) + 1, 1, R8);
    for (i = 0; i < xvalues.Nelements(); i++) {
//        xvalues.r8data[i] =
//            plotter->getCrval() + ((double)(i+1+MIN(x1,x2)) - plotter->getCrpix()) * plotter->getCdelt();
        xvalues.r8data[i] = pixwave(i+1+MIN(x1,x2), plotter->getCrpix(), plotter->getCrval(), plotter->getCdelt(), plotter->isLogwave());
        yvalues.r8data[i] = plotter->getYdata()[i+MIN(x1,x2)];
        errors.r8data[i] = 1.0;
    }
    fitparams.create(2+ngauss*3, 2, R8);

    fitparams.r8data[0] = fity[0] - s * fitx[0];
    fitparams.r8data[1] = s;
    for (g = 0; g < ngauss; g++) {
        fitparams.r8data[2+g*3] = fitgy[g*2] - (fitgx[g*2] * s + fitparams.r8data[0]);
        fitparams.r8data[3+g*3] = fitgx[g*2];
        fitparams.r8data[4+g*3] = 2.0 * fabs(fitgx[g*2] - fitgx[g*2+1]);
    }

    double min, max, xscale, xoffset, yoffset, yscale;
    bool good;

// we fit twice. First using the initial estimates to a rescaled version of the data
// and all errors set to one. Then we subtract the fit, estimate the error from the rms
// of the residual, and then fit again to the original data

// rescale yvalues to lie roughly between -1 and 1
    yoffset = yvalues.get_median();
    yvalues -= yoffset;
    yvalues.get_minmax(&min, &max);
    yscale = fabs(max-min);
    fitparams.r8data[0] = (fitparams.r8data[0] - yoffset) / yscale;
    fitparams.r8data[1] /= yscale;
    yvalues /= yscale;

    for (g = 0; g < ngauss; g++) {
            fitparams.r8data[2+g*3] = (fitparams.r8data[2+g*3]) / yscale;
    }

    // rescale xvalues to lie between 0 and 1
    xvalues.get_minmax(&min, &max);
    xoffset = min;
    xvalues -= min;

    xscale = max - min;
    xvalues /= xscale;

    fitparams.r8data[0] = fitparams.r8data[0] + fitparams.r8data[1] * xoffset;
    fitparams.r8data[1] *= xscale;
    for (g = 0; g < ngauss; g++) {
        fitparams.r8data[3+g*3] = (fitparams.r8data[3+g*3]) - xoffset;
        fitparams.r8data[3+g*3] = (fitparams.r8data[3+g*3]) / xscale;
        fitparams.r8data[4+g*3] = (fitparams.r8data[4+g*3]) / xscale;
    }

    good = multifuncfit(fitparams, &chisq, xvalues, yvalues, errors, types);

// rescale back
    fitparams.r8data[1] /= xscale;
    fitparams.r8data[0] = fitparams.r8data[0] - fitparams.r8data[1] * xoffset;

    fitparams.r8data[0] = fitparams[0] * yscale + yoffset;
    fitparams.r8data[1] *= yscale;

    fitparams.r8data[fitparams.C_I(0, 1)] =
                       (fitparams.r8data[fitparams.C_I(0, 1)]) * yoffset;

    for (g = 0; g < ngauss; g++) {
        fitparams.r8data[2+g*3] = (fitparams.r8data[2+g*3]) * yscale;
        fitparams.r8data[fitparams.C_I(2+g*3, 1)] =
                           (fitparams.r8data[fitparams.C_I(2+g*3, 1)]) * yscale;
    }
    for (g = 0; g < ngauss; g++) {
        fitparams.r8data[3+g*3] = (fitparams.r8data[3+g*3]) * xscale;
        fitparams.r8data[4+g*3] = (fitparams.r8data[4+g*3]) * xscale;
        fitparams.r8data[3+g*3] = (fitparams.r8data[3+g*3]) + xoffset;
        fitparams.r8data[fitparams.C_I(3+g*3, 1)] =
                           (fitparams.r8data[fitparams.C_I(3+g*3, 1)]) * xscale;
        fitparams.r8data[fitparams.C_I(4+g*3, 1)] =
                           (fitparams.r8data[fitparams.C_I(4+g*3, 1)]) * xscale;
    }

// now prepare for the second fit
    for (i = 0; i < xvalues.Nelements(); i++) {
        xvalues.r8data[i] = pixwave(i+1+MIN(x1,x2), plotter->getCrpix(), plotter->getCrval(), plotter->getCdelt(), plotter->isLogwave());
        yvalues.r8data[i] = plotter->getYdata()[i+MIN(x1,x2)];
    }
    Fits evalues;
    evaluate_multifunc(evalues, xvalues, params, types);
    evalues -= yvalues;
    double serror = evalues.get_meddev();
    for (i = 0; i < errors.Nelements(); i++) {
        errors.r8data[i] = serror;
    }
    good = multifuncfit(fitparams, &chisq, xvalues, yvalues, errors, types);

    updateTable(fitparams);
    update();
}

void QFitsWidget1D::handleescape() {
    dagain = false;
    gagain = false;
    fitx[0] = fitx[1] = fity[0] = fity[1] = 0.0;
    fitgx.create(20, 1, R8);
    fitgy.create(20, 1, R8);
    ngauss = 0;
    updateTable(params);
    fitestimates->hide();
    currentStatusBarText = 0;
    fitparams.create(1, 1, R8);
    plotter->removeData2();
    emit statusbartext(dpQtPlotStatusBarText[currentStatusBarText].toStdString().c_str());
}

void QFitsWidget1D::subtractfit() {
    if (fitparams.Nelements() > 1) {
        int i, x1, x2, g;
        Fits xvalues, yvalues, gparams;

//        x1 = (int)(plotter->getCrpix() + (fitx[0] - plotter->getCrval()) / plotter->getCdelt() + 0.5);
//        x2 = (int)(plotter->getCrpix() + (fitx[1] - plotter->getCrval()) / plotter->getCdelt() + 0.5);
        x1 = wavepix(fitx[0], plotter->getCrpix(), plotter->getCrval(), plotter->getCdelt(), plotter->isLogwave());
        x2 = wavepix(fitx[1], plotter->getCrpix(), plotter->getCrval(), plotter->getCdelt(), plotter->isLogwave());
        xvalues.create(labs(x2 - x1) + 1, 1, R8);
        for (i = 0; i < xvalues.Nelements(); i++) {
//            xvalues.r8data[i] =
//                plotter->getCrval() + ((double)(i+1+MIN(x1,x2)) - plotter->getCrpix()) * plotter->getCdelt();
            xvalues.r8data[i] = pixwave(i+1+MIN(x1,x2), plotter->getCrpix(), plotter->getCrval(), plotter->getCdelt(), plotter->isLogwave());
        }
        gparams.create(4, 1, R8);
        gparams.r8data[0] = 0.0;

        buffersLock.lockForWrite();

        dpuser_vars[getBufferIndex()].fvalue->setType(R8);
        for (g = 0; g < ngauss; g++) {
            gparams.r8data[1] = fitparams.r8data[2+g*3];
            gparams.r8data[2] = fitparams.r8data[3+g*3];
            gparams.r8data[3] = fitparams.r8data[4+g*3];

            evaluate_gauss(yvalues, xvalues, gparams);
            for (i = 0; i < xvalues.Naxis(1); i++) {
                dpuser_vars[getBufferIndex()].fvalue->r8data[i+MIN(x1,x2)] -= yvalues.r8data[i];
            }
        }
        for (i = 0; i < plotter->getNdata(); i++) {
            plotter->setYdata(i, dpuser_vars[getBufferIndex()].fvalue->r8data[i]);
        }
        buffersLock.unlock();

        update();
    }
}

void QFitsWidget1D::addfit() {
    if (fitparams.Nelements() > 1) {
        int i, x1, x2, g;
        Fits xvalues, yvalues, gparams;

//        x1 = (int)(plotter->getCrpix() + (fitx[0] - plotter->getCrval()) /
//                                                          plotter->getCdelt() + 0.5);
//        x2 = (int)(plotter->getCrpix() + (fitx[1] - plotter->getCrval()) /
//                                                          plotter->getCdelt() + 0.5);
        x1 = wavepix(fitx[0], plotter->getCrpix(), plotter->getCrval(), plotter->getCdelt(), plotter->isLogwave());
        x2 = wavepix(fitx[1], plotter->getCrpix(), plotter->getCrval(), plotter->getCdelt(), plotter->isLogwave());
        xvalues.create(labs(x2 - x1) + 1, 1, R8);
        for (i = 0; i < xvalues.Nelements(); i++) {
//            xvalues.r8data[i] = plotter->getCrval() +
//                                ((double)(i+1+MIN(x1,x2)) - plotter->getCrpix()) * plotter->getCdelt();
            xvalues.r8data[i] = pixwave(i+1+MIN(x1,x2), plotter->getCrpix(), plotter->getCrval(), plotter->getCdelt(), plotter->isLogwave());
        }
        gparams.create(4, 1, R8);
        gparams.r8data[0] = 0.0;

        buffersLock.lockForWrite();

        dpuser_vars[getBufferIndex()].fvalue->setType(R8);
        for (g = 0; g < ngauss; g++) {
            gparams.r8data[1] = fitparams.r8data[2+g*3];
            gparams.r8data[2] = fitparams.r8data[3+g*3];
            gparams.r8data[3] = fitparams.r8data[4+g*3];

            evaluate_gauss(yvalues, xvalues, gparams);
            for (i = 0; i < xvalues.Naxis(1); i++) {
                dpuser_vars[getBufferIndex()].fvalue->r8data[i+MIN(x1,x2)] += yvalues.r8data[i];
            }
        }
        for (i = 0; i < plotter->getNdata(); i++) {
            plotter->setYdata(i, dpuser_vars[getBufferIndex()].fvalue->r8data[i]);
        }
        buffersLock.unlock();

        update();
    }
}

void QFitsWidget1D::copyfit() {
    double flux;
    double fluxerr;
    double a, fwhm, da, dfwhm;
    QString text;

    text = "QFitsView 1D fit\n================\n";
    text += "Type,Flux,Height,Center,FWHM,d_Flux,d_Height,d_Center,d_FWHM\n";
    text += "a+bx,";
    text += QString::number(fitparams.ValueAt(fitparams.C_I(0))) + ",";
    text += QString::number(fitparams.ValueAt(fitparams.C_I(1))) + ",";
    text += QString::number(fitparams.ValueAt(fitparams.C_I(0,1))) + ",";
    text += QString::number(fitparams.ValueAt(fitparams.C_I(1,1))) + "\n";
    for (int g = 0; g < ngauss; g++) {
        flux = fluxerr = 0.0;
        a = fitparams.ValueAt(fitparams.C_I(2+g*3));
        fwhm = fitparams.ValueAt(fitparams.C_I(4+g*3));
        da = fitparams.ValueAt(fitparams.C_I(2+g*3, 1));
        dfwhm = fitparams.ValueAt(fitparams.C_I(4+g*3, 1));
        if (types[g] == 0) {
            flux = sqrt(M_PI / log(2.0)) / 2.0 * a * fabs(fwhm);
            fluxerr = sqrt(M_PI / log(2.0)) / 2.0 *
                      sqrt(fwhm*fwhm * da*da + a*a * dfwhm*dfwhm);
            text += "Gauss,";
        } else if (types[g] == 1) {
            flux = M_PI / 2.0 * a * fabs(fwhm);
            fluxerr = M_PI / 2.0 * sqrt(fwhm*fwhm * da*da + a*a * dfwhm*dfwhm);
            text += "Lorentz,";
        }

        // fill in fitparams
        for (int jj = 1; jj <= 8; jj++) {
            int x, y;
            QString txt;

            switch (jj) {
            case 1:
                text += QString::number(flux) + ",";
                break;
            case 2:
                text += QString::number(fitparams.ValueAt(fitparams.C_I(2+g*3))) + ",";
                break;
            case 3:
                text += QString::number(fitparams.ValueAt(fitparams.C_I(3+g*3)), 'g', 7) + ",";
                break;
            case 4:
                text += QString::number(fitparams.ValueAt(fitparams.C_I(4+g*3))) + ",";
                break;
            case 5:
                text += QString::number(fluxerr) + ",";
                break;
            case 6:
                text += QString::number(fitparams.ValueAt(fitparams.C_I(2+g*3, 1))) + ",";
                break;
            case 7:
                text += QString::number(fitparams.ValueAt(fitparams.C_I(3+g*3, 1))) + ",";
                break;
            case 8:
                text += QString::number(fitparams.ValueAt(fitparams.C_I(4+g*3, 1))) + "\n";
                break;
            }
        }
    }
    QApplication::clipboard()->setText(text);
}

void QFitsWidget1D::updateTable(const Fits &values) {
//    if (ngauss == 0) {
//        fitresults->hide();
//        fitestimates->deleteFitResults();
//    } else {
        fitestimates->setFitResults(fitx, fity, values);

        fitresults->setRowCount((values.Naxis(1) - 2) / 3 *2);
        QStringList headers;
        double flux;
        double fluxerr;
        double a, fwhm, da, dfwhm;

        for (int g = 0; g < ngauss; g++) {
            flux = fluxerr = 0.0;
            a = values.ValueAt(values.C_I(2+g*3));
            fwhm = values.ValueAt(values.C_I(4+g*3));
            da = values.ValueAt(values.C_I(2+g*3, 1));
            dfwhm = values.ValueAt(values.C_I(4+g*3, 1));
            if (types[g] == 0) {
                flux = sqrt(M_PI / log(2.0)) / 2.0 * a * fabs(fwhm);
                fluxerr = sqrt(M_PI / log(2.0)) / 2.0 *
                          sqrt(fwhm*fwhm * da*da + a*a * dfwhm*dfwhm);
            } else if (types[g] == 1) {
                flux = M_PI / 2.0 * a * fabs(fwhm);
                fluxerr = M_PI / 2.0 * sqrt(fwhm*fwhm * da*da + a*a * dfwhm*dfwhm);
            }
            // fill in values
            for (int jj = 1; jj <= 8; jj++) {
                int x, y;
                QString txt;

                switch (jj) {
                case 1:
                    x = g*2; y = 0; txt = QString::number(flux);
                    break;
                case 2:
                    x = g*2; y = 1; txt = QString::number(values.ValueAt(values.C_I(2+g*3)));
                    break;
                case 3:
                    x = g*2; y = 2; txt = QString::number(values.ValueAt(values.C_I(3+g*3)), 'g', 7);
                    break;
                case 4:
                    x = g*2; y = 3; txt = QString::number(values.ValueAt(values.C_I(4+g*3)));
                    break;
                case 5:
                    x = g*2+1; y = 0; txt = QString::number(fluxerr);
                    break;
                case 6:
                    x = g*2+1; y = 1; txt = QString::number(values.ValueAt(values.C_I(2+g*3, 1)));
                    break;
                case 7:
                    x = g*2+1; y = 2; txt = QString::number(values.ValueAt(values.C_I(3+g*3, 1)));
                    break;
                case 8:
                    x = g*2+1; y = 3; txt = QString::number(values.ValueAt(values.C_I(4+g*3, 1)));
                    break;
                }

                if (fitresults->item(x, y) != NULL) {
                    fitresults->item(x, y)->setText(txt);
                } else {
                    QTableWidgetItem *item = new QTableWidgetItem(txt);
                    item->setFlags(item->flags() ^ Qt::ItemIsEditable);
                    fitresults->setItem(x, y, item);
                }
            }

            if (types[g] == 0) {
                headers.append("Gauss");
            } else if (types[g] == 1) {
                headers.append("Lorentz");
            }
            headers.append("Errors");
        }
        fitresults->setHorizontalHeaderLabels(headers);
//    }
    resizeEvent(NULL);
}

QFitsTransparentLabel::QFitsTransparentLabel(QFitsWidget1D* parent, QFitsView1D *view)
                          : QDialog(view, Qt::Tool | Qt::FramelessWindowHint),
                          myParent(parent), myView(view)
{
    fitResult.create(1, 1, R8);
    hasFitResult = false;

    setAutoFillBackground(true);

    QPalette p;
    p.setColor(QPalette::Window, QColor(0, 0, 0, 150));
    p.setColor(QPalette::WindowText, QColor(255, 255, 255));
    setPalette(p);
    setMouseTracking(true);
    setAttribute(Qt::WA_ShowWithoutActivating);

    theCaption = new QFitsTransparentCaption(this);
    theCaption->setAlignment(Qt::AlignCenter);
    theCaption->setText("1D fitting");
    theCaption->adjustSize();
    theCaption->setGeometry(0, 0, width(), theCaption->height());

    closeButton = new QFitsSimplestButton(QIcon(":/xicon_red.svg").pixmap(10, 10), theCaption);
    connect(closeButton, SIGNAL(clicked()),
            myParent, SLOT(handleescape()));

    fitestimatesTab = new QFitsSimplestButton("fit estimates", this);
    fitestimatesTab->setGeometry(0, theCaption->height(), width() / 2, 20);
    fitestimatesTab->setAutoFillBackground(true);
    connect(fitestimatesTab, SIGNAL(clicked()),
            this, SLOT(fitestimatesClicked()));

    fitresultsTab = new QFitsSimplestButton("fit results", this);
    fitresultsTab->setGeometry(width() / 2, theCaption->height(), width() / 2, 20);
    fitresultsTab->setAutoFillBackground(true);
    connect(fitresultsTab, SIGNAL(clicked()),
            this, SLOT(fitresultsClicked()));

    viewArea = new QWidgetWithoutMouse(this);
    viewArea->setGeometry(0, fitestimatesTab->y() + fitestimatesTab->height(),
                          width(), height());

    fitButton = new QPushButton("Fit", viewArea);
    fitButton->setGeometry(5, 5, 50, 20);
    fitButton->setAutoDefault(false);
    fitButton->setFocusPolicy(Qt::NoFocus);
    connect(fitButton, SIGNAL(clicked()),
            myParent, SLOT(dofit()));

    subButton = new QPushButton("- fit", viewArea);
    subButton->setGeometry(60, 5, 50, 20);
    subButton->setAutoDefault(false);
    subButton->setFocusPolicy(Qt::NoFocus);
    subButton->hide();
    connect(subButton, SIGNAL(clicked()),
            myParent, SLOT(subtractfit()));

    addButton = new QPushButton("+ fit", viewArea);
    addButton->setGeometry(120, 5, 50, 20);
    addButton->setAutoDefault(false);
    addButton->setFocusPolicy(Qt::NoFocus);
    addButton->hide();
    connect(addButton, SIGNAL(clicked()),
            myParent, SLOT(addfit()));

    clipboardButton = new QPushButton("copy to clipboard", viewArea);
    clipboardButton->setGeometry(200, 5, 150, 20);
    clipboardButton->setAutoDefault(false);
    clipboardButton->setFocusPolicy(Qt::NoFocus);
    clipboardButton->hide();
    connect(clipboardButton, SIGNAL(clicked()),
            myParent, SLOT(copyfit()));

    l1 = new QLabelWithoutMouse(viewArea);
    l1->setGeometry(0, 0, 0, 0);
    l2 = new QLabelWithoutMouse(viewArea);
    l2->setAlignment(Qt::AlignHCenter);
    l3 = new QLabelWithoutMouse(viewArea);
    l3->setAlignment(Qt::AlignHCenter);
    l4 = new QLabelWithoutMouse(viewArea);
    l4->setAlignment(Qt::AlignHCenter);
    l5 = new QLabelWithoutMouse(viewArea);
    l5->setAlignment(Qt::AlignHCenter);
    QFontMetrics m(l1->font());
// TODO QT6

#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    l1->setMinimumSize(m.boundingRect("Lorentz:").width(), 10);
    int w = m.boundingRect("-0.00000e-00").width();
#else
    l1->setMinimumSize(m.horizontalAdvance("Lorentz:"), 10);
    int w = m.horizontalAdvance("-0.00000e-00");
#endif /* QT_VERSION */

    l2->setMinimumSize(w, 10);
    l3->setMinimumSize(w, 10);
    l4->setMinimumSize(w, 10);
    l5->setMinimumSize(w, 10);
    l1->move(5, fitButton->y() + fitButton->height() + 5);
    l2->move(l1->x() + l1->width() + 5, l1->y());
    l3->move(l2->x() + l2->width() + 5, l1->y());
    l4->move(l3->x() + l3->width() + 5, l1->y());
    l5->move(l4->x() + l4->width() + 5, l1->y());

    adjustSize();
    setMinimumSize(size());
    viewArea->resize(size().width(),
                     size().height() - fitButton->height() - fitButton->y() - 5);

    marker = new QLabel(viewArea);
    marker->setAutoFillBackground(true);
    p.setColor(QPalette::Window, QColor(0, 0, 255, 100));
    marker->setPalette(p);
    marker->stackUnder(l1);

    marker2 = new QLabel(viewArea);
    marker2->setAutoFillBackground(true);
    marker2->setGeometry(0, 0, 100, 30);
    marker2->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
    p.setColor(QPalette::Window, QColor(255, 0, 0, 100));
    marker2->setPalette(p);
    marker2->hide();

    setWindowOpacity(0.7);
    setFocusPolicy(Qt::NoFocus);

    showEstimates = true;
    nlines = -1;
}

void QFitsTransparentLabel::mouseMoveEvent(QMouseEvent *e) {
    if (nlines >= 0 && showEstimates) {
        int hh = l1->height() / (nlines+2);
        int which = (e->pos().y() - viewArea->y() - l1->y()) / hh;
        if (which > 0 && which <= nlines+1) {
            marker->setGeometry(0, l1->y() + which * hh, width(), hh);
            marker->show();
        } else {
            marker->hide();
        }
    } else {
        marker->hide();
    }

    myView->mouseMovedInSubwindow(e->globalPos());

    e->ignore();
    update();
}

void QFitsTransparentLabel::mouseDoubleClickEvent(QMouseEvent *e) {
    if (e->button() == Qt::LeftButton) {
        if (nlines >= 0) {
            int hh = l1->height() / (nlines+2);
            int which = (e->pos().y() - viewArea->y() - l1->y()) / hh;
            if (which > 1 && which <= nlines+1) {
                marker2->setGeometry(childAt(e->pos())->x(), l1->y() + which * hh,
                                     childAt(e->pos())->width(), hh);
                marker2->show();
                marker2->raise();
                if (childAt(e->pos())->x() == l3->x()) {
                    myParent->updateHeight(which);
                } else if (childAt(e->pos())->x() == l4->x()) {
                    myParent->updatePos(which);
                } else if (childAt(e->pos())->x() == l5->x()) {
                    myParent->updateFWHM(which);
                } else {
                    marker2->hide();
                }
            } else if (which == 1) {
                if ((childAt(e->pos())->x() == l2->x()) ||
                    (childAt(e->pos())->x() == l3->x()))
                {
                    myParent->updateBase(0);
                    marker2->setGeometry(l2->x(), l1->y() + which * hh,
                                         l2->width() + l3->width() + 5, hh);
                    marker2->show();
                    marker2->raise();
                } else if ((childAt(e->pos())->x() == l4->x()) ||
                           (childAt(e->pos())->x() == l5->x()))
                {
                    myParent->updateBase(1);
                    marker2->setGeometry(l4->x(), l1->y() + which * hh,
                                         l4->width() + l5->width() + 5, hh);
                    marker2->show();
                    marker2->raise();
                }
            } else {
                marker2->hide();
            }
        }
    }
}

void QFitsTransparentLabel::leaveEvent(QEvent *e) {
    marker->hide();
    update();
}

void QFitsTransparentLabel::fitestimatesClicked() {
    if (!showEstimates) {
        showEstimates = true;
        showValues();
        myView->update();
    }
}

void QFitsTransparentLabel::fitresultsClicked() {
    if (showEstimates) {
        showEstimates = false;
        showValues();
        myView->update();
    }
}

void QFitsTransparentLabel::removeMarker2() {
    marker2->hide();
}

double QFitsTransparentLabel::getEstimateFitX(int i) {
    double ret = 0.0/0.0;
    if ((i >= 0) && (i < 2)) {
        ret =  estimatefitx[i];
    }
    return ret;}

double QFitsTransparentLabel::getEstimateFitY(int i) {
    double ret = 0.0/0.0;
    if ((i >= 0) && (i < 2)) {
        ret =  estimatefity[i];
    }
    return ret;
}


void QFitsTransparentLabel::setFitResults(double *fitx, double *fity,
                                          const Fits &values)
{
    resultfitx[0] = fitx[0];
    resultfitx[1] = fitx[1];
    resultfity[0] = fity[0];
    resultfity[1] = fity[1];
    fitResult = values;
    hasFitResult = true;
    showEstimates = false;
    showValues();
}

void QFitsTransparentLabel::setFitEstimates(int nparams, double *fitx,
                                            double *fity, Fits &types,
                                            Fits &fitgx, Fits &fitgy)
{
    estimatefitx[0] = fitx[0];
    estimatefitx[1] = fitx[1];
    estimatefity[0] = fity[0];
    estimatefity[1] = fity[1];
    estimatefitgx = fitgx;
    estimatefitgy = fitgy;
    estimatetypes = types;
    estimatenparams = nparams;
    showEstimates = true;
    showValues();
}

void QFitsTransparentLabel::deleteFitResults() {
    hasFitResult = false;
}

void QFitsTransparentLabel::showValues() {
    if (estimatefitx[0] == 0.0 && estimatefitx[1] == 0.0) {
        hide();
    } else {
        QPalette p;
        p.setColor(QPalette::Window, QColor(0, 0, 255, 100));
        p.setColor(QPalette::WindowText, QColor(255, 255, 255));
        if (showEstimates) fitestimatesTab->setPalette(p);
        else fitresultsTab->setPalette(p);
        p.setColor(QPalette::Window, QColor(50, 50, 50, 150));
        p.setColor(QPalette::WindowText, QColor(150, 150, 150));
        if (showEstimates) fitresultsTab->setPalette(p);
        else fitestimatesTab->setPalette(p);

        int i, x1, x2, g, w;
        double a, fwhm, flux;
        QString ll1, ll2, ll3, ll4, ll5;

        ll1 = "Type\n";
        ll2 = "Flux\n";
        ll3 = "Height\n";
        ll4 = "Center\n";
        ll5 = "FWHM\n";

        if (showEstimates) {
            double s = (estimatefity[1] - estimatefity[0]) / (estimatefitx[1] -
                                                               estimatefitx[0]);

            ll1 += "Base:";
            ll2 += "x1="+QString::number(estimatefitx[0]);
            ll3 += "y1="+QString::number(estimatefity[0]);
            ll4 += "x2="+QString::number(estimatefitx[1]);
            ll5 += "y2="+QString::number(estimatefity[1]);

            for (g = 0; g < estimatenparams; g++) {
                if (estimatetypes[g] == 0) {
                    ll1 += "\nGauss:";
                } else if (estimatetypes[g] == 1) {
                    ll1 += "\nLorentz:";
                }
                a = estimatefitgy[g*2] -
                    (estimatefitgx[g*2] * s +estimatefity[0] - s * estimatefitx[0]);
                fwhm = 2.0 * fabs(estimatefitgx[g*2] - estimatefitgx[g*2+1]);
                if (estimatetypes[g] == 0) {
                    flux = sqrt(M_PI / log(2.0)) / 2.0 * a * fabs(fwhm);
                } else if (estimatetypes[g] == 1) {
                    flux = M_PI / 2.0 * a * fabs(fwhm);
                }
                ll2 += "\n";
                ll2 += QString::number(flux);;
                ll3 += "\n";
                ll3 += QString::number(estimatefitgy[g*2] -
                                       (estimatefitgx[g*2] * s + estimatefity[0] - s * estimatefitx[0]));
                ll4 += "\n";
                ll4 += QString::number(estimatefitgx[g*2]);
                ll5 += "\n";
                ll5 += QString::number(2.0 * fabs(estimatefitgx[g*2] - estimatefitgx[g*2+1]));
            }
            fitButton->show();
            subButton->hide();
            addButton->hide();
            clipboardButton->hide();
        } else {
            if (hasFitResult) {
                double fluxerr, da, dfwhm;
                double s = (resultfity[1] - resultfity[0]) / (resultfitx[1] - resultfitx[0]);

                ll1 += "Base:";
                ll2 += QString::number(fitResult.ValueAt(fitResult.C_I(0)));
                ll3 += QString::number(fitResult.ValueAt(fitResult.C_I(1)));
//                ll2 += QString::number(resultfity[0] - s * resultfitx[0]);
//                ll3 += QString::number(s);

                for (g = 0; g < estimatenparams; g++) {
                    flux = fluxerr = 0.0;
                    a = fitResult.ValueAt(fitResult.C_I(2+g*3));
                    fwhm = fitResult.ValueAt(fitResult.C_I(4+g*3));
                    da = fitResult.ValueAt(fitResult.C_I(2+g*3, 1));
                    dfwhm = fitResult.ValueAt(fitResult.C_I(4+g*3, 1));
                    if (estimatetypes[g] == 0) {
                        flux = sqrt(M_PI / log(2.0)) / 2.0 * a * fabs(fwhm);
                        fluxerr = sqrt(M_PI / log(2.0)) / 2.0 *
                                  sqrt(fwhm*fwhm * da*da + a*a * dfwhm*dfwhm);
                    } else if (estimatetypes[g] == 1) {
                        flux = M_PI / 2.0 * a * fabs(fwhm);
                        fluxerr = M_PI / 2.0 * sqrt(fwhm*fwhm * da*da + a*a * dfwhm*dfwhm);
                    }
                    if (estimatetypes[g] == 0) {
                        ll1 += "\nGauss";
                    } else if (estimatetypes[g] == 1) {
                        ll1 += "\nLorentz";
                    }
                    ll1 += "\nErrors";

                    ll2 += "\n";
                    ll2 += QString::number(flux);
                    ll3 += "\n";
                    ll3 += QString::number(fitResult.ValueAt(fitResult.C_I(2+g*3)));
                    ll4 += "\n";
                    ll4 += QString::number(fitResult.ValueAt(fitResult.C_I(3+g*3)), 'g', 7);
                    ll5 += "\n";
                    ll5 += QString::number(fitResult.ValueAt(fitResult.C_I(4+g*3)));
                    ll2 += "\n";
                    ll2 += QString::number(fluxerr);
                    ll3 += "\n";
                    ll3 += QString::number(fitResult.ValueAt(fitResult.C_I(2+g*3, 1)));
                    ll4 += "\n";
                    ll4 += QString::number(fitResult.ValueAt(fitResult.C_I(3+g*3, 1)));
                    ll5 += "\n";
                    ll5 += QString::number(fitResult.ValueAt(fitResult.C_I(4+g*3, 1)));
                }
            }
            fitButton->hide();
            subButton->show();
            addButton->show();
            clipboardButton->show();
        }

        w = l1->width();
        l1->setText(ll1);
        l1->adjustSize();
        if (l1->width() > w) {
            l1->setMinimumSize(l1->width(), 10);
        }
        w = l2->width();
        l2->setText(ll2);
        l2->adjustSize();
        if (l2->width() > w) {
            l2->setMinimumSize(l2->width(), 10);
        }
        w = l3->width();
        l3->setText(ll3);
        l3->adjustSize();
        if (l3->width() > w) {
            l3->setMinimumSize(l3->width(), 10);
        }
        w = l4->width();
        l4->setText(ll4);
        l4->adjustSize();
        if (l4->width() > w) {
            l4->setMinimumSize(l4->width(), 10);
        }
        w = l5->width();
        l5->setText(ll5);
        l5->adjustSize();
        if (l5->width() > w) {
            l5->setMinimumSize(l5->width(), 10);
        }
        l3->move(l2->x() + l2->width() + 5, l1->y());
        l4->move(l3->x() + l3->width() + 5, l1->y());
        l5->move(l4->x() + l4->width() + 5, l1->y());

        int hh = l1->height() / (nlines+3);
        int ww = 0;

        resize(l5->x() + l5->width() + 5 + ww,
               l5->y() + l5->height() + 5 + viewArea->y());
        viewArea->resize(size().width() - ww,
                         size().height() - theCaption->height() - theCaption->y() - 5);
        theCaption->setGeometry(0, 0, width(), theCaption->height());
        fitestimatesTab->resize(width() / 2, fitestimatesTab->height());
        fitresultsTab->setGeometry(width() / 2, fitestimatesTab->y(),
                                   width() / 2, fitresultsTab->height());
        if (width() > w) {
            setMinimumSize(width(), 10);
        }

        show();
        nlines = estimatenparams;
    }
}

QFitsTransparentCaption::QFitsTransparentCaption(QFitsTransparentLabel *parent)
                                              : QLabel(parent), myParent(parent)
{
    setAutoFillBackground(true);
    QPalette p;
    p.setColor(QPalette::Window, QColor(0, 0, 200, 150));
    p.setColor(QPalette::WindowText, QColor(255, 255, 255));
    setPalette(p);
    setCursor(Qt::ArrowCursor);
}

void QFitsTransparentCaption::mousePressEvent(QMouseEvent *e) {
    p = e->pos();
}

void QFitsTransparentCaption::mouseMoveEvent(QMouseEvent *e) {
    myParent->update();
    int nx = myParent->x() + e->pos().x() - p.x();
    int ny = myParent->y() + e->pos().y() - p.y();
    if (nx < 0) nx = 0;
    if (ny < 0) ny = 0;
    myParent->move(nx, ny);
}

QWidgetWithoutMouse::QWidgetWithoutMouse(QWidget *parent) : QWidget(parent) {
    setMouseTracking(true);
}

void QWidgetWithoutMouse::mouseMoveEvent(QMouseEvent *e) {
    e->ignore();
}

QLabelWithoutMouse::QLabelWithoutMouse(QWidget *parent) : QLabel(parent) {
    QPalette p;
    p.setColor(QPalette::WindowText, QColor(255, 255, 255));
    setPalette(p);
    setMouseTracking(true);
}

void QLabelWithoutMouse::mouseMoveEvent(QMouseEvent *e) {
    e->ignore();
}
