Skip to content
Snippets Groups Projects
petrack.cpp 149 KiB
Newer Older
/*
 * PeTrack - Software for tracking pedestrians movement in videos
 * Copyright (C) 2010-2021 Forschungszentrum Jülich GmbH,
 * Maik Boltes, Juliane Adrian, Ricardo Martin Brualla, Arne Graf, Paul Häger, Daniel Hillebrand,
 * Deniz Kilic, Paul Lieberenz, Daniel Salden, Tobias Schrödter, Ann Katrin Seemann
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

d.kilic's avatar
d.kilic committed
#include <QSignalMapper>
#include <QtOpenGL>
#include <QtWidgets>
d.kilic's avatar
d.kilic committed

// Added for Qt5 support
#include "aboutDialog.h"
#include "animation.h"
#include "autoCalib.h"
#include "backgroundItem.h"
#include "calibFilter.h"
#include "codeMarkerWidget.h"
d.kilic's avatar
d.kilic committed
#include "colorMarkerItem.h"
#include "colorMarkerWidget.h"
#include "colorRangeWidget.h"
d.kilic's avatar
d.kilic committed
#include "control.h"
#include "gridItem.h"
#include "imageItem.h"
#include "logoItem.h"
#include "moCapItem.h"
#include "multiColorMarkerItem.h"
#include "multiColorMarkerWidget.h"
#include "openMoCapDialog.h"
#include "pMessageBox.h"
#include "petrack.h"
#include "player.h"
#include "recognitionRoiItem.h"
#include "stereoItem.h"
#include "stereoWidget.h"
d.kilic's avatar
d.kilic committed
#include "tracker.h"
#include "trackerItem.h"
d.kilic's avatar
d.kilic committed
#include "trackerReal.h"
Schrödter, Tobias's avatar
Schrödter, Tobias committed
#include "trackingRoiItem.h"
#include "view.h"
#include <QtPrintSupport/QPrintDialog>
#include <QtPrintSupport/QPrinter>
d.kilic's avatar
d.kilic committed
#ifdef AVI
#include "aviFile.h"
#else
#include "aviFileWriter.h"
#endif
#include "IO.h"
d.kilic's avatar
d.kilic committed
#include "person.h"

#include <cmath>
Schrödter, Tobias's avatar
Schrödter, Tobias committed
#include <ctime>
d.kilic's avatar
d.kilic committed
#include <iomanip>
Schrödter, Tobias's avatar
Schrödter, Tobias committed
#include <opencv2/opencv.hpp>
d.kilic's avatar
d.kilic committed

// temp muss spaeter herausgenommen werden,
//  dient dazu, in anderen dateien um schnell ueber cw->temp1->value() an einstellbare daten zu kommen
d.kilic's avatar
d.kilic committed
Control *cw;

int Petrack::trcVersion = 0;

// Reihenfolge des anlegens der objekte ist sehr wichtig
Petrack::Petrack() :
    mExtrCalibration(mPersonStorage),
    mAuthors(IO::readAuthors(QCoreApplication::applicationDirPath() + "/.zenodo.json"))
d.kilic's avatar
d.kilic committed
{
    QIcon icon;
    icon.addFile(":/icon");          // about
d.kilic's avatar
d.kilic committed
    icon.addFile(":/icon_smallest"); // window title bar
    setWindowIcon(icon);
    mHeadSize            = -1;
    mCmPerPixel          = -1;
    mScene               = nullptr;
    mTracker             = nullptr;
    mTrackerReal         = nullptr; // damit beim zeichnen von control mit analysePlot nicht auf einen feheler laeuft
    mStatusLabelFPS      = nullptr;
    mStatusPosRealHeight = nullptr;
    mStatusLabelPosReal  = nullptr;
    mImageItem           = nullptr;
    mRecognitionChanged  = true;
    mTrackChanged        = true;
    mCoordItem           = nullptr;
    mImage               = nullptr;
d.kilic's avatar
d.kilic committed
    setLoading(true);

    setAcceptDrops(true);

    int space = 2;

    mBrightContrastFilter.disable();
    mBorderFilter.disable();
    mSwapFilter.disable();
    mBackgroundFilter.disable();
    mStereoContext = nullptr;
    mCalibFilter   = new CalibFilter; // schoener waere erst zu erzeugen, wenn video geladen wird, da sonst bei stereo
                                      // erst normealer und dann stereo objekt erzeugt wird
    mCalibFilter->disable(); // aber control widget greift schon bei erzeugung auf alle objekte zur einstellung zurueck
d.kilic's avatar
d.kilic committed

    mScene = new QGraphicsScene(this);

    mControlWidget = new Control(*this, *mScene, mReco);
    cw             = mControlWidget; // muss spaeter geloescht werden
d.kilic's avatar
d.kilic committed

    mStereoWidget = new StereoWidget(this);
    mStereoWidget->setWindowFlags(Qt::Window);
    mStereoWidget->setWindowTitle("Stereo parameter");

    mColorRangeWidget = new ColorRangeWidget(this);
    mColorRangeWidget->setWindowFlags(Qt::Window);
    mColorRangeWidget->setWindowTitle("Color range");

    mColorMarkerWidget = new ColorMarkerWidget(this);
    mColorMarkerWidget->setWindowFlags(Qt::Window);
    mColorMarkerWidget->setWindowTitle("Color marker parameter");

    mCodeMarkerWidget = new CodeMarkerWidget(this, mReco.getCodeMarkerOptions(), nullptr);
d.kilic's avatar
d.kilic committed
    mCodeMarkerWidget->setWindowFlags(Qt::Window);
    mCodeMarkerWidget->setWindowTitle("Code marker parameter");


    mMultiColorMarkerWidget = new MultiColorMarkerWidget(this);
    mMultiColorMarkerWidget->setWindowFlags(Qt::Window);
    mMultiColorMarkerWidget->setWindowTitle("MultiColor marker parameter");

    mImageItem = new ImageItem(this); // durch uebergabe von scene wird indirekt ein scene->addItem() aufgerufen
d.kilic's avatar
d.kilic committed

    mAnimation = new Animation(this);

    mLogoItem = new LogoItem(this); // durch uebergabe von scene wird indirekt ein scene->addItem() aufgerufen
    mLogoItem->setZValue(6);        // groesser heisst weiter oben
d.kilic's avatar
d.kilic committed

    mExtrCalibration.setMainWindow(this);

    mGridItem = new GridItem(this);
    mGridItem->setZValue(2.5); // durch uebergabe von scene wird indirekt ein scene->addItem() aufgerufen

    mCoordItem = new CoordItem(this);
    mCoordItem->setZValue(3); // groesser heisst weiter oben
    mImageItem->setCoordItem(mCoordItem);

    mTrackingRoiItem = new TrackingRoiItem(this);
    mTrackingRoiItem->setZValue(4); // groesser heisst weiter oben

    mRecognitionRoiItem = new RecognitionRoiItem(this);
    mRecognitionRoiItem->setZValue(5); // groesser heisst weiter oben


    mViewWidget = new ViewWidget(this);
    mView       = mViewWidget->view();
d.kilic's avatar
d.kilic committed
    mView->setScene(mScene);
    connect(mView, &GraphicsView::mouseDoubleClick, this, [this]() { this->openSequence(); });
    connect(mView, &GraphicsView::mouseShiftDoubleClick, this, &Petrack::addManualTrackPointOnlyVisible);
    connect(mView, &GraphicsView::mouseShiftControlDoubleClick, this, &Petrack::splitTrackPerson);
    connect(mView, &GraphicsView::mouseControlDoubleClick, this, &Petrack::addOrMoveManualTrackPoint);
    connect(mView, &GraphicsView::mouseRightDoubleClick, this, &Petrack::deleteTrackPoint);
    connect(mView, &GraphicsView::mouseMiddleDoubleClick, this, &Petrack::deleteTrackPointAll);
    connect(mView, &GraphicsView::mouseShiftWheel, this, &Petrack::skipToFrameWheel);
d.kilic's avatar
d.kilic committed

    mPlayerWidget = new Player(mAnimation, this);

    QVBoxLayout *vLayout = new QVBoxLayout;
    vLayout->setSpacing(space);
    vLayout->addWidget(mViewWidget);
    vLayout->addWidget(mPlayerWidget);

    //---------------------------

    mTracker     = new Tracker(this, mPersonStorage);
    mTrackerReal = new TrackerReal(this, mPersonStorage);
    mTrackerItem = new TrackerItem(this, mPersonStorage);
d.kilic's avatar
d.kilic committed
    mTrackerItem->setZValue(5); // groesser heisst weiter oben

    mControlWidget->getColorPlot()->setPersonStorage(&mPersonStorage);
d.kilic's avatar
d.kilic committed
#ifdef QWT
    mControlWidget->getAnalysePlot()->setTrackerReal(mTrackerReal);
#endif

    //---------------------------

    mStereoItem = new StereoItem(this);
    mStereoItem->setZValue(2); // groesser heisst weiter oben
d.kilic's avatar
d.kilic committed
    mStereoItem->setVisible(false);

    //---------------------------
d.kilic's avatar
d.kilic committed

    mColorMarkerItem = new ColorMarkerItem(this);
    mColorMarkerItem->setZValue(2); // groesser heisst weiter oben
d.kilic's avatar
d.kilic committed
    mColorMarkerItem->setVisible(false);
    //---------------------------

    mCodeMarkerItem = new CodeMarkerItem(this, mReco.getCodeMarkerOptions());
    mCodeMarkerItem->setZValue(2); // groesser heisst weiter oben
d.kilic's avatar
d.kilic committed
    mCodeMarkerItem->setVisible(false);
    //---------------------------

    mMultiColorMarkerItem = new MultiColorMarkerItem(this);
    mMultiColorMarkerItem->setZValue(2); // groesser heisst weiter oben
d.kilic's avatar
d.kilic committed
    mMultiColorMarkerItem->setVisible(false);

    //---------------------------

    mBackgroundItem = new BackgroundItem(this);
    mBackgroundItem->setZValue(2.2); // um so groesser um so hoeher um so eher zu sehen
    mBackgroundItem->setVisible(false);

    //---------------------------

    mMoCapItem = new MoCapItem(*this, *mAnimation, mMoCapController);
    mMoCapItem->setZValue(3); // um so groesser um so hoeher um so eher zu sehen

d.kilic's avatar
d.kilic committed
    /// Add Items
    mScene->addItem(mImageItem);
    mScene->addItem(mLogoItem);
    mScene->addItem(mGridItem);
    mScene->addItem(mCoordItem);
    mScene->addItem(mTrackingRoiItem);
    mScene->addItem(mRecognitionRoiItem);
    mScene->addItem(mTrackerItem);
    mScene->addItem(mStereoItem);
    mScene->addItem(mColorMarkerItem);
    mScene->addItem(mCodeMarkerItem);
    mScene->addItem(mMultiColorMarkerItem);
    mScene->addItem(mBackgroundItem);
    mScene->addItem(mMoCapItem);
d.kilic's avatar
d.kilic committed

    //---------------------------

    mCentralLayout = new QHBoxLayout;
    mCentralLayout->setMargin(space);
    mCentralWidget = new QFrame;
    mCentralWidget->setFrameStyle(QFrame::Sunken | QFrame::StyledPanel);
    mCentralWidget->setLayout(mCentralLayout);
    setCentralWidget(mCentralWidget);
d.kilic's avatar
d.kilic committed
    mSplitter = new QSplitter(this);
    // create playAndView-Widget to wrap layout, since QSplitter only accepts widgets
    QWidget *playAndView = new QWidget(this);
    playAndView->setLayout(vLayout);
    mSplitter->addWidget(playAndView);

    mSplitter->addWidget(mControlWidget);

    mSplitter->setStretchFactor(0, 1);
    mSplitter->setStretchFactor(1, 0);
d.kilic's avatar
d.kilic committed

    mCentralLayout->addWidget(mSplitter);


d.kilic's avatar
d.kilic committed
    setWindowTitle(tr("PeTrack"));

    //---------------------------
    mAutoCalib.setMainWindow(this);
    //---------------------------

    createActions();
    createMenus();
    createStatusBar();

d.kilic's avatar
d.kilic committed
    // TODO delete once we get Options to be value only (i.e. no Pointer/Ref anymore)
    mReco.getCodeMarkerOptions().setControlWidget(mControlWidget);
    mReco.getCodeMarkerOptions().setCodeMarkerItem(mCodeMarkerItem);
    mSeqFileName = QDir::currentPath(); // fuer allerersten Aufruf des Programms
d.kilic's avatar
d.kilic committed
    readSettings();

    saveXml(mDefaultSettings); // noch nicht noetig, da eh noch nicht fkt
d.kilic's avatar
d.kilic committed

    mShowFPS = 0;

    mTrcFileName = "";

    // initialer Aufruf, damit beim reinen Laden einer Videodatei die Defaultwerte in control genommen werden zum Setzen
    setHeadSize();

    // um im background subtraction filter das hoehenbild zu beruecksichtigen
    mBackgroundFilter.setStereoContext(&mStereoContext);

    mAutoBackTrack          = true;  // ist der default, dann wenn in XML-Datei nicht drin steht
d.kilic's avatar
d.kilic committed
    mAutoTrackOptimizeColor = false; // ist der default, dann wenn in XML-Datei nicht drin steht

    setLoading(false);
}
Petrack::~Petrack()
{
    delete mImage;
    delete cw;
    // hier muessten weitere stehen insb die im konstruktor erzeugt werden
    // aber da petrack nur vernichtet wird, wenn programm beendet wird, kann man sich das auch schenken
}

void Petrack::dragEnterEvent(QDragEnterEvent *event)
{
    if(event->mimeData()->hasUrls())
d.kilic's avatar
d.kilic committed
        event->acceptProposedAction();
d.kilic's avatar
d.kilic committed
}

/**
 * @brief Accepts dropped .pet, .trc and media files
 *
 * Opens the project for a .pet. Imports the trajectories for a .trc
 * and tries to open the sequence for any other kind of file.
 *
 * @param event
 */
d.kilic's avatar
d.kilic committed
void Petrack::dropEvent(QDropEvent *event)
{
    if(event->mimeData()->hasUrls())
d.kilic's avatar
d.kilic committed
    {
        if(event->mimeData()->urls().first().toLocalFile().right(4) == ".pet")
d.kilic's avatar
d.kilic committed
            openProject(event->mimeData()->urls().first().toLocalFile());
        else if(event->mimeData()->urls().first().toLocalFile().right(4) == ".trc")
d.kilic's avatar
d.kilic committed
            importTracker(event->mimeData()->urls().first().toLocalFile());
d.kilic's avatar
d.kilic committed
        else
d.kilic's avatar
d.kilic committed
            openSequence(event->mimeData()->urls().first().toLocalFile());
d.kilic's avatar
d.kilic committed
        event->acceptProposedAction();
    }
}

void Petrack::updateSceneRect()
{
    double iW = 0, iH = 0, bS = 0;
d.kilic's avatar
d.kilic committed

d.kilic's avatar
d.kilic committed
    {
        iW = mImage->width();
        iH = mImage->height();
        bS = getImageBorderSize();
    }

    if(mControlWidget->getCalibCoordShow())
d.kilic's avatar
d.kilic committed
    {
        double scale = mControlWidget->getCalibCoordScale() / 10.;
        double tX    = mControlWidget->getCalibCoordTransX() / 10.;
        double tY    = mControlWidget->getCalibCoordTransY() / 10.;
d.kilic's avatar
d.kilic committed

        // setzen der bounding box der scene
        // Faktor 1.1 dient dazu, dass auch Zahl "1" bei coord gut in sichtbaren Bereich passt
        double xMin = (tX - 1.1 * scale < -bS) ? tX - 1.1 * scale : -bS;
        double yMin = (tY - 1.1 * scale < -bS) ? tY - 1.1 * scale : -bS;
        double xMax = (tX + 1.1 * scale > iW - bS) ? tX + 1.1 * scale : iW - bS;
        double yMax = (tY + 1.1 * scale > iH - bS) ? tY + 1.1 * scale : iH - bS;
        mScene->setSceneRect(xMin, yMin, xMax - xMin, yMax - yMin);
d.kilic's avatar
d.kilic committed
    }
    else
d.kilic's avatar
d.kilic committed
        mScene->setSceneRect(-bS, -bS, iW, iH);
d.kilic's avatar
d.kilic committed
}

/**
 * @brief Loads the content of a .pet file into petrack
 *
 * @param doc the DOM of the .pet file
 * @param openSeq true, if sequence given in doc should be opened
 */
d.kilic's avatar
d.kilic committed
void Petrack::openXml(QDomDocument &doc, bool openSeq)
{
    QDomElement root = doc.firstChildElement("PETRACK");
    QString     seq;
    int         frame = -1, sourceFrameIn = -1, sourceFrameOut = -1;
    double      fps              = DEFAULT_FPS;
    int         onlyPeopleNr     = 1;
    QString     onlyPeopleNrList = "1";
    int         zoom = 250, rotate = 0, hScroll = 0, vScroll = 0;
d.kilic's avatar
d.kilic committed
    enum Camera cam = cameraUnset;
    setLoading(true);
    for(QDomElement elem = root.firstChildElement(); !elem.isNull(); elem = elem.nextSiblingElement())
    {
        if(elem.tagName() == "MAIN")
d.kilic's avatar
d.kilic committed
        {
            if(elem.hasAttribute("SRC"))
d.kilic's avatar
d.kilic committed
            {
                seq            = elem.attribute("SRC");
d.kilic's avatar
d.kilic committed
                QString tmpSeq = getExistingFile(seq, mProFileName);
                if(tmpSeq != "")
d.kilic's avatar
d.kilic committed
                    seq = tmpSeq;
d.kilic's avatar
d.kilic committed
            }
            if(elem.hasAttribute("STATUS_HEIGHT"))
d.kilic's avatar
d.kilic committed
            {
                if(mStatusPosRealHeight) // null kann eigentlich nicht vorkommen, da im constructor von petrack erzeugt
                                         // wird
d.kilic's avatar
d.kilic committed
                    mStatusPosRealHeight->setValue(elem.attribute("STATUS_HEIGHT").toDouble());
d.kilic's avatar
d.kilic committed
            }
        }
        else if(elem.tagName() == "STEREO")
d.kilic's avatar
d.kilic committed
        {
            mStereoWidget->getXml(elem);
        }
        else if(elem.tagName() == "COLOR_MARKER")
d.kilic's avatar
d.kilic committed
        {
            mColorMarkerWidget->getXml(elem);
        }
        else if(elem.tagName() == "CODE_MARKER")
d.kilic's avatar
d.kilic committed
        {
            mCodeMarkerWidget->getXml(elem);
        }
        else if(elem.tagName() == "MULTI_COLOR_MARKER")
d.kilic's avatar
d.kilic committed
        {
            mMultiColorMarkerWidget->getXml(elem);
        }
        else if(elem.tagName() == "MOCAP")
        {
            mMoCapController.getXml(elem);
        }
        else if(elem.tagName() == "CONTROL")
d.kilic's avatar
d.kilic committed
        {
            mControlWidget->getXml(elem);
            QDomElement tmpElem = (elem.firstChildElement("TRACKING")).firstChildElement("PATH");
            if(tmpElem.hasAttribute("ONLY_PEOPLE_NR"))
d.kilic's avatar
d.kilic committed
                onlyPeopleNr = tmpElem.attribute("ONLY_PEOPLE_NR").toInt();
            if(tmpElem.hasAttribute("ONLY_PEOPLE_NR_LIST"))
d.kilic's avatar
d.kilic committed
                onlyPeopleNrList = tmpElem.attribute("ONLY_PEOPLE_NR_LIST");
d.kilic's avatar
d.kilic committed
        }
        else if(elem.tagName() == "EXTR_CALIBRATION")
        else if(elem.tagName() == "PLAYER")
d.kilic's avatar
d.kilic committed
        {
            if(elem.hasAttribute("FRAME"))
d.kilic's avatar
d.kilic committed
            {
                frame = elem.attribute("FRAME").toInt();
            }
            if(elem.hasAttribute("FPS"))
d.kilic's avatar
d.kilic committed
            {
                fps = elem.attribute("FPS").toDouble();
            }
            if(elem.hasAttribute("SOURCE_FRAME_IN"))
d.kilic's avatar
d.kilic committed
            {
                sourceFrameIn = elem.attribute("SOURCE_FRAME_IN").toInt();
            }
            if(elem.hasAttribute("SOURCE_FRAME_OUT"))
d.kilic's avatar
d.kilic committed
            {
                sourceFrameOut = elem.attribute("SOURCE_FRAME_OUT").toInt();
            }
            if(elem.hasAttribute("PLAYER_SPEED_FIXED"))
d.kilic's avatar
d.kilic committed
            {
                mPlayerWidget->setPlayerSpeedLimited(elem.attribute("PLAYER_SPEED_FIXED").toInt());
d.kilic's avatar
d.kilic committed
            }
        }
        else if(elem.tagName() == "VIEW")
d.kilic's avatar
d.kilic committed
        {
            if(elem.hasAttribute("ANTIALIAS"))
d.kilic's avatar
d.kilic committed
            {
                mAntialiasAct->setChecked(elem.attribute("ANTIALIAS").toInt() == Qt::Checked);
d.kilic's avatar
d.kilic committed
            }
            if(elem.hasAttribute("OPENGL"))
d.kilic's avatar
d.kilic committed
            {
                mOpenGLAct->setChecked(elem.attribute("OPENGL").toInt() == Qt::Checked);
d.kilic's avatar
d.kilic committed
            }
            if(elem.hasAttribute("SAVE_TRANSFORMED"))
d.kilic's avatar
d.kilic committed
            {
                mCropZoomViewAct->setChecked(elem.attribute("SAVE_TRANSFORMED") == Qt::Checked);
d.kilic's avatar
d.kilic committed
            }
            if(elem.hasAttribute("TRANSFORMATION"))
d.kilic's avatar
d.kilic committed
            {
                QString     matStr = elem.attribute("TRANSFORMATION");
d.kilic's avatar
d.kilic committed
                QTextStream in(&matStr);
                in >> zoom >> rotate >> hScroll >> vScroll;
            }
            if(elem.hasAttribute("CAMERA"))
d.kilic's avatar
d.kilic committed
            {
                cam = (enum Camera) elem.attribute("CAMERA").toInt();
            }
            if(elem.hasAttribute("HIDE_CONTROLS"))
d.kilic's avatar
d.kilic committed
            {
                mHideControlsAct->setChecked(elem.attribute("HIDE_CONTROLS").toInt() == Qt::Checked);
d.kilic's avatar
d.kilic committed
            }
        }
        else if(elem.tagName() == "AUTO_TRACK")
d.kilic's avatar
d.kilic committed
        {
            if(elem.hasAttribute("BACK_TRACK"))
d.kilic's avatar
d.kilic committed
            {
                mAutoBackTrack = elem.attribute("BACK_TRACK").toInt();
            }
            if(elem.hasAttribute("OPTIMZE_COLOR"))
d.kilic's avatar
d.kilic committed
            {
                mAutoTrackOptimizeColor = elem.attribute("OPTIMZE_COLOR").toInt();
            }
        }
        else
            debout << "Unknown PETRACK tag " << elem.tagName() << std::endl;
d.kilic's avatar
d.kilic committed
    }
    // open koennte am schluss passieren, dann wuerde nicht erst unveraendertes bild angezeigt,
    // dafuer koennte es aber sein, dass werte zb bei fx nicht einstellbar sind!

    if(openSeq && (seq != ""))
d.kilic's avatar
d.kilic committed
        openSequence(seq); // wenn leer, dann kommt abfrage hoch, welche datei; abbrechen, wenn aktuelle gewuenscht
d.kilic's avatar
d.kilic committed

    mViewWidget->setZoomLevel(zoom);
    mViewWidget->setRotateLevel(rotate);
    mView->horizontalScrollBar()->setValue(hScroll);
    mView->verticalScrollBar()->setValue(vScroll);

    bool loaded = false;
    if(!mBackgroundFilter.getFilename().isEmpty())
d.kilic's avatar
d.kilic committed
    {
        if(!(loaded = mBackgroundFilter.load(mBackgroundFilter.getFilename())))
            debout << "Error: loading background file " << mBackgroundFilter.getFilename() << "!" << std::endl;
d.kilic's avatar
d.kilic committed
    }

    mPlayerWidget->setFrameInNum(sourceFrameIn == -1 ? mAnimation->getSourceInFrameNum() : sourceFrameIn);
    mPlayerWidget->setFrameOutNum(sourceFrameOut == -1 ? mAnimation->getSourceOutFrameNum() : sourceFrameOut);
d.kilic's avatar
d.kilic committed
    mPlayerWidget->update();

    if(frame != -1)
d.kilic's avatar
d.kilic committed
    {
        if(mControlWidget->filterBg->isChecked() &&
           !loaded) // mit dem anfangs geladenen bild wurde bereits faelschlicherweise bg bestimmt
        {
d.kilic's avatar
d.kilic committed
            mBackgroundFilter.reset(); // erst nach dem springen zu einem frame background bestimmen
d.kilic's avatar
d.kilic committed
        mPlayerWidget->skipToFrame(frame); // hier wird updateImage ausgefuehrt
    }
    else if(loaded)
d.kilic's avatar
d.kilic committed
        updateImage();
d.kilic's avatar
d.kilic committed

    // nicht schon in control, sonst loescht opensequence wieder tracker
    if(mTrcFileName != "")
d.kilic's avatar
d.kilic committed
    {
        // vorher loeschen aller trajektorien, da sonst nach start im ersten bild
        // mgl zwei trackpoints
        // beim haendischen importieren sind weiterhin parallele trajektorien moeglich (warnung wird ausgegeben)
        frame = 0; // default
        if((mPersonStorage.largestLastFrame() >= frame) && (getPersonStorage().smallestFirstFrame() <= frame))
d.kilic's avatar
d.kilic committed
        {
            mPersonStorage.clear();
d.kilic's avatar
d.kilic committed
            mTracker->reset();
        }
        importTracker(mTrcFileName);
    }

    mControlWidget->trackShowOnlyNr->setValue(onlyPeopleNr);
    mControlWidget->trackShowOnlyNrList->setText(onlyPeopleNrList);

    if(cam == cameraLeft)
d.kilic's avatar
d.kilic committed
        mCameraLeftViewAct->setChecked(true);
    else if(cam == cameraRight)
d.kilic's avatar
d.kilic committed
        mCameraRightViewAct->setChecked(true);
d.kilic's avatar
d.kilic committed
    setCamera();
    mPlayerWidget->setFPS(fps); // erst spaet setzen, damit Wert den des geladenen Videos ueberschreiben kann
    setLoading(false);
}

void Petrack::openProject(QString fileName, bool openSeq) // default fileName="", openSequence = true
{
    if(!QFileInfo(mProFileName).isDir()) // a project is already loaded
        if(!maybeSave())
d.kilic's avatar
d.kilic committed
            return;
d.kilic's avatar
d.kilic committed
    // if no destination file or folder is given
    if(fileName.isEmpty())
        fileName = QFileDialog::getOpenFileName(
            this,
            tr("Select project file"),
            QFileInfo(mProFileName).path(),
            tr("PeTrack project file (*.pet);;All files (*.*)"));

    if(!fileName.isEmpty())
d.kilic's avatar
d.kilic committed
    {
        QFile file(fileName);
        if(!file.open(QIODevice::ReadOnly))
d.kilic's avatar
d.kilic committed
        {
            PCritical(this, tr("PeTrack"), tr("Cannot open %1:\n%2.").arg(fileName, file.errorString()));
d.kilic's avatar
d.kilic committed
            return;
        }
        resetSettings();
        QDomDocument doc("PETRACK"); // eigentlich Pfad zu Beschreibungsdatei fuer Dateiaufbau
        if(!doc.setContent(&file))
d.kilic's avatar
d.kilic committed
        {
            PCritical(this, tr("PeTrack"), tr("Cannot read content from %1.").arg(fileName));
d.kilic's avatar
d.kilic committed
            file.close();
            return;
        }

        debout << "open " << fileName << std::endl;
d.kilic's avatar
d.kilic committed
        file.close();
        setProFileName(fileName);
d.kilic's avatar
d.kilic committed

        QDomElement root = doc.firstChildElement("PETRACK");
        if(root.hasAttribute("VERSION"))
            if(root.attribute("VERSION") != mPetrackVersion)
d.kilic's avatar
d.kilic committed
            {
                PWarning(
                    this,
                    tr("PeTrack"),
                    tr("Reading %1:\nDifferent version numbers %2 (application) and %3 (file) may cause problems.")
                        .arg(fileName, mPetrackVersion, root.attribute("VERSION")));
d.kilic's avatar
d.kilic committed
            }
d.kilic's avatar
d.kilic committed
        openXml(doc, openSeq);
        updateWindowTitle();
    }
}

void Petrack::saveXml(QDomDocument &doc)
{
    QDomElement elem;

    QDomElement root = doc.createElement("PETRACK");
    root.setAttribute("VERSION", mPetrackVersion);
d.kilic's avatar
d.kilic committed
    doc.appendChild(root);

    // main settings (window size, status hight)
    elem        = doc.createElement("MAIN");
d.kilic's avatar
d.kilic committed
    QString seq = "";
d.kilic's avatar
d.kilic committed
        seq = getFileList(mSeqFileName, mProFileName);
d.kilic's avatar
d.kilic committed

    elem.setAttribute("SRC", seq);
    elem.setAttribute("STATUS_HEIGHT", mStatusPosRealHeight->value());
    root.appendChild(elem);

    // control settings (right control widget)
    elem = doc.createElement("CONTROL");
    mControlWidget->setXml(elem);
    root.appendChild(elem);

    // Reprojection error extrinsic calib
    elem = doc.createElement("EXTR_CALIBRATION");
    mExtrCalibration.setXml(elem);
    root.appendChild(elem);

d.kilic's avatar
d.kilic committed
    // settings for stereo
    elem = doc.createElement("STEREO");
    mStereoWidget->setXml(elem);
    root.appendChild(elem);

    // settings for color marker
    elem = doc.createElement("COLOR_MARKER");
    mColorMarkerWidget->setXml(elem);
    root.appendChild(elem);

    // settings for code marker
    elem = doc.createElement("CODE_MARKER");
    mCodeMarkerWidget->setXml(elem);
    root.appendChild(elem);

    // settings for multicolor marker
    elem = doc.createElement("MULTI_COLOR_MARKER");
    mMultiColorMarkerWidget->setXml(elem);
    root.appendChild(elem);

    // settings for MoCap-Visualization
    elem = doc.createElement("MOCAP");
    mMoCapController.setXml(elem);
    root.appendChild(elem);

d.kilic's avatar
d.kilic committed
    // player settings (which frame, frame range)
    elem = doc.createElement("PLAYER");
    elem.setAttribute("FRAME", mPlayerWidget->getPos()); // == mAnimation->getCurrentFrameNum()
    elem.setAttribute("FPS", mAnimation->getFPS());
    elem.setAttribute("SOURCE_FRAME_IN", mPlayerWidget->getFrameInNum());
    elem.setAttribute("SOURCE_FRAME_OUT", mPlayerWidget->getFrameOutNum());
    elem.setAttribute("PLAYER_SPEED_FIXED", mPlayerWidget->getPlayerSpeedLimited());
d.kilic's avatar
d.kilic committed

    root.appendChild(elem);

    // view settings (zoom, rotate, alias, opengl)
    elem = doc.createElement("VIEW");
    elem.setAttribute("ANTIALIAS", mAntialiasAct->isChecked());
    elem.setAttribute("OPENGL", mOpenGLAct->isChecked());
    elem.setAttribute("SAVE_TRANSFORMED", mCropZoomViewAct->isChecked());
    elem.setAttribute(
        "TRANSFORMATION",
        QString("%1 %2 %3 %4")
            .arg(mViewWidget->getZoomLevel())
            .arg(mViewWidget->getRotateLevel())
            .arg(mView->horizontalScrollBar()->value())
            .arg(mView->verticalScrollBar()->value()));
#ifndef STEREO_DISABLED
d.kilic's avatar
d.kilic committed
    elem.setAttribute("CAMERA", mAnimation->getCamera());
#else
    elem.setAttribute("CAMERA", cameraUnset);
#endif
d.kilic's avatar
d.kilic committed
    elem.setAttribute("HIDE_CONTROLS", mHideControlsAct->isChecked());
    root.appendChild(elem);

    // auto track settings
    elem = doc.createElement("AUTO_TRACK");
    elem.setAttribute("BACK_TRACK", mAutoBackTrack);
    elem.setAttribute("OPTIMZE_COLOR", mAutoTrackOptimizeColor);
    root.appendChild(elem);
}

/// rueckgabewert zeigt an, ob gesichert werden konnte
d.kilic's avatar
d.kilic committed
bool Petrack::saveSameProject()
{
    return saveProject(mProFileName);
}

/// rueckgabewert zeigt an, ob gesichert werden konnte
d.kilic's avatar
d.kilic committed
bool Petrack::saveProject(QString fileName) // default fileName=""
{
    // if no destination file or folder is given
    if(fileName.isEmpty() && QFileInfo(mProFileName).isDir())
d.kilic's avatar
d.kilic committed
    {
        fileName = QFileDialog::getSaveFileName(
            this, tr("Select project file"), mProFileName, tr("PeTrack project file (*.pet);;All files (*.*)"));
d.kilic's avatar
d.kilic committed
    }

    if(!fileName.isEmpty())
d.kilic's avatar
d.kilic committed
    {
        setProFileName(fileName);
d.kilic's avatar
d.kilic committed
        QDomDocument doc("PETRACK"); // eigentlich Pfad zu Beschreibungsdatei fuer Dateiaufbau
        saveXml(doc);

        // file output
        QByteArray       byteArray;
        QXmlStreamWriter xmlStream(&byteArray);
d.kilic's avatar
d.kilic committed
        xmlStream.setAutoFormatting(true);
        xmlStream.setAutoFormattingIndent(4);

        xmlStream.writeStartDocument();
        xmlStream.writeDTD("<!DOCTYPE PETRACK>");

        QDomElement element = doc.documentElement();
        writeXmlElement(xmlStream, element);

        xmlStream.writeEndDocument();

        QFile file(fileName);
        if(!file.open(QFile::WriteOnly | QFile::Truncate | QFile::Text))
d.kilic's avatar
d.kilic committed
        {
            PCritical(this, tr("PeTrack"), tr("Cannot save %1:\n%2.").arg(fileName, file.errorString()));
d.kilic's avatar
d.kilic committed
            file.close();
            return false;
        }
        file.write(byteArray);
        file.close(); // also flushes the file

        statusBar()->showMessage(tr("Saved project to %1.").arg(fileName), 5000);
        debout << "save project to " << fileName << std::endl;
d.kilic's avatar
d.kilic committed

        updateWindowTitle();
        return true;
    }
    else
d.kilic's avatar
d.kilic committed
        return false;
d.kilic's avatar
d.kilic committed
}

void Petrack::writeXmlElement(QXmlStreamWriter &xmlStream, QDomElement element)
d.kilic's avatar
d.kilic committed
{
    xmlStream.writeStartElement(element.tagName());

    QVector<QString>       attribute_names;
d.kilic's avatar
d.kilic committed
    const QDomNamedNodeMap attributes = element.attributes();
    for(int i = 0; i < attributes.size(); ++i)
    {
d.kilic's avatar
d.kilic committed
        attribute_names.push_back(attributes.item(i).toAttr().name());
    }

    // TODO: check if sorting of elements fits our needs
d.kilic's avatar
d.kilic committed
    std::stable_sort(attribute_names.begin(), attribute_names.end()); // for a canonical XML

    // Wants this macro instead of range-based for loop
    foreach(QString name, attribute_names)
    {
d.kilic's avatar
d.kilic committed
        QDomAttr attr = element.attributeNode(name);
        xmlStream.writeAttribute(attr.name(), attr.value());
    }

    // order of child nodes is defined at creation
    if(element.hasChildNodes())
    {
d.kilic's avatar
d.kilic committed
        const QDomNodeList children = element.childNodes();
        for(int i = 0; i < children.size(); ++i)
        {
d.kilic's avatar
d.kilic committed
            writeXmlElement(xmlStream, children.at(i).toElement());
        }
    }

    xmlStream.writeEndElement();
}

/**
 * @brief Opens camera livestream from cam with camID
 * @param camID id of camera to use (defaults to 0)
 */
void Petrack::openCameraLiveStream(int camID /* =-1*/)
d.kilic's avatar
d.kilic committed
{
    if(camID == -1)
d.kilic's avatar
d.kilic committed
    {
        // if more than one camera connected show to choose
        // camID = selectedID;
        debout << "No camera ID delivered: Set CameraID to 0 (default Camera)" << std::endl;
d.kilic's avatar
d.kilic committed
        camID = 0; // default
    }
    if(!mAnimation->openCameraStream(camID))
d.kilic's avatar
d.kilic committed
    {
        PCritical(this, tr("PeTrack"), tr("Cannot start Camera Livestream."));
d.kilic's avatar
d.kilic committed
        return;
    }
    mSeqFileName = "camera live stream";
    debout << "open " << mSeqFileName << " (" << mAnimation->getNumFrames() << " frames; " << mAnimation->getFPS()
           << " fps; " << mAnimation->getSize().width() << "x" << mAnimation->getSize().height() << " pixel)"
           << std::endl; // size
d.kilic's avatar
d.kilic committed
    updateSequence();
    updateWindowTitle();
    mPlayerWidget->setFPS(mAnimation->getFPS());
    if(mOpenGLAct->isChecked())
d.kilic's avatar
d.kilic committed
        mLogoItem->fadeOut(1);
d.kilic's avatar
d.kilic committed
    else
d.kilic's avatar
d.kilic committed
        mLogoItem->fadeOut(50);
d.kilic's avatar
d.kilic committed
    updateCoord();

    mPlayerWidget->play(PlayerState::FORWARD);
d.kilic's avatar
d.kilic committed
}

void Petrack::openSequence(QString fileName) // default fileName = ""
{
    if(fileName.isEmpty())
        fileName = QFileDialog::getOpenFileName(
            this,
            tr("Open video or image sequence"),
            QFileInfo(mSeqFileName).path(),
            tr("All supported types (*.avi *.mpg *.mts *.m2t *.m2ts *.wmv *.mp4 *.mov *.mxf *.bmp *.dib *.jpeg *.jpg "
               "*.jpe *.png *.pbm *.pgm *.ppm *.sr *.ras *.tiff *.tif *.exr *.jp2);;Video (*.avi *.mpg *.mts *.m2ts "
               "*.m2t *.wmv *.mov *.mp4 *.mxf);;Images (*.bmp *.dib *.jpeg *.jpg *.jpe *.png *.pbm *.pgm *.ppm *.sr "
               "*.ras *.tiff *.tif *.exr *.jp2);;Windows bitmaps (*.bmp *.dib);;JPEG (*.jpeg *.jpg *.jpe);;Portable "
               "network graphics (*.png);;Portable image format (*.pbm *.pgm *.ppm);;Sun rasters (*.sr *.ras);;TIFF "
               "(*.tiff *.tif);;OpenEXR HDR (*.exr);;JPEG 2000 (*.jp2);;All files (*.*)"));
    if(!fileName.isEmpty())
d.kilic's avatar
d.kilic committed
    {
        if(!mAnimation->openAnimation(fileName))
d.kilic's avatar
d.kilic committed
        {
            PCritical(this, tr("PeTrack"), tr("Cannot load %1.").arg(fileName));
d.kilic's avatar
d.kilic committed
            return;
        }

        mCameraGroupView->setEnabled(mAnimation->isStereoVideo());
        mCameraMenu->setEnabled(mAnimation->isStereoVideo());

#ifdef STEREO
        if(mAnimation->isStereoVideo())
d.kilic's avatar
d.kilic committed
        {
            if(mStereoContext)
d.kilic's avatar
d.kilic committed
                delete mStereoContext;
            mStereoContext = new pet::StereoContext(this);
        }

        bool lastIsStereoVideo = mAnimation->isStereoVideo();
        if(mCalibFilter == NULL || (mAnimation->isStereoVideo() != lastIsStereoVideo))
d.kilic's avatar
d.kilic committed
        {
            bool lastCalibFilterEnabled = false;
            if(mCalibFilter != NULL)
d.kilic's avatar
d.kilic committed
            {
                lastCalibFilterEnabled = mCalibFilter->getEnabled();
                delete mCalibFilter;
            }
            if(mAnimation->isStereoVideo())
d.kilic's avatar
d.kilic committed
            {
                mCalibFilter = new CalibStereoFilter;
                ((CalibStereoFilter *) mCalibFilter)->setStereoContext(mStereoContext);
            }
            else
                mCalibFilter = new CalibFilter;
            mCalibFilter->setEnabled(lastCalibFilterEnabled);
        }
#endif
        mSeqFileName = fileName;
        debout << "open " << mSeqFileName << " (" << mAnimation->getNumFrames() << " frames; " << mAnimation->getFPS()
               << " fps; " << mAnimation->getSize().width() << "x" << mAnimation->getSize().height() << " pixel)"
               << std::endl; // size
d.kilic's avatar
d.kilic committed
        updateSequence();
        updateWindowTitle();
        mPlayerWidget->setFPS(mAnimation->getFPS());
        if(mOpenGLAct->isChecked())
d.kilic's avatar
d.kilic committed
            mLogoItem->fadeOut(1);
d.kilic's avatar
d.kilic committed
        else
d.kilic's avatar
d.kilic committed
            mLogoItem->fadeOut(50);
d.kilic's avatar
d.kilic committed
        updateCoord();
    }
}

void Petrack::openMoCapFile()
{
    OpenMoCapDialog dialog(this, mMoCapController);
    dialog.exec();
}

d.kilic's avatar
d.kilic committed
void Petrack::updateWindowTitle()
{
    QString title;
    QSize   size = mAnimation->getSize();
d.kilic's avatar
d.kilic committed

    if(QFileInfo(mProFileName).isDir())
        title = tr("PeTrack (v") + mPetrackVersion + tr("): ");
d.kilic's avatar
d.kilic committed
    else
    {
        title = tr("PeTrack (v") + mPetrackVersion + tr("): ") + QFileInfo(mProFileName).fileName();
        if(mAnimation->isVideo() || mAnimation->isImageSequence())
            title += "; ";
d.kilic's avatar
d.kilic committed
    }
    if(mAnimation->isVideo())
        title += "sequence: " + mAnimation->getCurrentFileName() + tr(" (%1").arg(mAnimation->getNumFrames()) +
                 tr(" frames; %1x%2").arg(size.width()).arg(size.height()) + " pixel)";
    else if(mAnimation->isImageSequence())
        title += "sequence: " + mAnimation->getCurrentFileName() + tr(" ... (%1").arg(mAnimation->getNumFrames()) +
                 tr(" frames; %1x%2").arg(size.width()).arg(size.height()) + " pixel)";
d.kilic's avatar
d.kilic committed
    setWindowTitle(title);
}

void Petrack::saveVideo()
{
    saveSequence(true, false);
}
void Petrack::saveVideoView()
{
    saveSequence(true, true);
}
void Petrack::saveImageSequence()
{
    saveSequence(false, false);
}
void Petrack::saveViewSequence()
{
    saveSequence(false, true);
}


/**
 * @brief Saves current sequence as avi-file or image sequence
 *
 * Saves the loaded image sequence or video from current frame on till the end.
 * One can save the sequence as is or one can save the view shown in PeTrack.
 *
 * @param saveVideo true, if wanting to save a video. Ignored when dest isn't empty
 * @param saveView true, if sequence should be saved as shown in PeTrack (with trajectories etc.)
 * @param dest destination file; if empty, the user chooses via a dialog
 */
d.kilic's avatar
d.kilic committed
void Petrack::saveSequence(bool saveVideo, bool saveView, QString dest) // default saveView= false, dest=""
{
    static QString lastDir;
    //    bool autoSave = false;
d.kilic's avatar
d.kilic committed

    // if no destination file or folder is given
    if(dest.isEmpty())
d.kilic's avatar
d.kilic committed
    {
        if(lastDir.isEmpty() && !mSeqFileName.isEmpty())
d.kilic's avatar
d.kilic committed
            lastDir = QFileInfo(mSeqFileName).path();
d.kilic's avatar
d.kilic committed

        if(saveVideo)
d.kilic's avatar
d.kilic committed
        {
            dest = QFileDialog::getSaveFileName(
                this,
                tr("Select video file"),
                lastDir,
                tr("Video (*.avi);;All files (*.*)")); //? *.mpg *.mpeg
d.kilic's avatar
d.kilic committed
        }
        else
        {
                dest = QFileDialog::getExistingDirectory(
                    this,
                    tr("Select directory to save view sequence"),
                    lastDir,
                    QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
d.kilic's avatar
d.kilic committed
            else
                dest = QFileDialog::getExistingDirectory(
                    this,
                    tr("Select directory to save image sequence"),
                    lastDir,
                    QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
d.kilic's avatar
d.kilic committed
        }
    }
    else // uebergabe von saveVideo spielt keine roll mehr, sondern wird hier analysiert anhand von Dateiendung
    {
        //        autoSave = true; // command line option
        if(dest.right(4) == ".avi")
d.kilic's avatar
d.kilic committed
            saveVideo = true;
d.kilic's avatar
d.kilic committed
        else
d.kilic's avatar
d.kilic committed
            saveVideo = false;
d.kilic's avatar
d.kilic committed
    }

    if(!dest.isEmpty() && mImage)
d.kilic's avatar
d.kilic committed
    {
        int     rest      = mAnimation->getNumFrames() - 1;
        int     numLength = 1;
        int     memPos    = mPlayerWidget->getPos();
        QString fileName  = "";
d.kilic's avatar
d.kilic committed
#ifdef AVI
        AviFile aviFile;
#else
        AviFileWriter aviFile;
#endif
        bool      formatIsSaveAble = false;
        bool      saveRet;
        QImage *  viewImage = nullptr;
        QPainter *painter   = nullptr;
        int       progEnd   = mAnimation->getSourceOutFrameNum() -
                      mPlayerWidget->getPos(); // nur wenn nicht an anfang gesprungen wird:-mPlayerWidget->getPos()
        cv::Mat iplImgFilteredBGR;
        bool    writeFrameRet   = false;
        bool    convert8To24bit = false;
        int     mult;
d.kilic's avatar
d.kilic committed


        if(saveVideo)
d.kilic's avatar
d.kilic committed
        {
d.kilic's avatar
d.kilic committed
            {
                if(mCropZoomViewAct->isChecked())
                    viewImage =
                        new QImage(mView->viewport()->width(), mView->viewport()->height(), QImage::Format_RGB32);
d.kilic's avatar
d.kilic committed
                else
d.kilic's avatar
d.kilic committed
                    viewImage = new QImage((int) mScene->width(), (int) mScene->height(), QImage::Format_RGB32);
d.kilic's avatar
d.kilic committed
                painter = new QPainter();
            }
            if(convert8To24bit)
d.kilic's avatar
d.kilic committed
                mult = 3;
d.kilic's avatar
d.kilic committed
            else
d.kilic's avatar
d.kilic committed
                mult = 1;
d.kilic's avatar
d.kilic committed

            bool ok = false;

                ok = aviFile.open(
                    dest.toStdString().c_str(),
                    viewImage->width(),
                    viewImage->height(),
                    viewImage->depth(),
                    mAnimation->getFPS());
d.kilic's avatar
d.kilic committed
            else
                ok = aviFile.open(
                    dest.toStdString().c_str(), mImg.cols, mImg.rows, mult * 8 * mImg.channels(), mAnimation->getFPS());
d.kilic's avatar
d.kilic committed
            {
                debout << "Error: opening AVI file: " << dest.toStdString().c_str() << std::endl;
d.kilic's avatar
d.kilic committed
                return;
            }
        }

        if(!saveVideo)
d.kilic's avatar
d.kilic committed
        {
d.kilic's avatar
d.kilic committed
            {
                if(mCropZoomViewAct->isChecked())
                    viewImage =
                        new QImage(mView->viewport()->width(), mView->viewport()->height(), QImage::Format_RGB32);
d.kilic's avatar
d.kilic committed
                else
d.kilic's avatar
d.kilic committed
                    viewImage = new QImage((int) mScene->width(), (int) mScene->height(), QImage::Format_RGB32);
d.kilic's avatar
d.kilic committed
                painter = new QPainter();
            }

            // test, if fileformat is supported
            if(mAnimation->isVideo())
d.kilic's avatar
d.kilic committed
            {
                // calculate string length of sequence number
                while((rest /= 10) > 0)
d.kilic's avatar
d.kilic committed
                    numLength++;
                fileName = (dest + "/" + mAnimation->getFileBase() + "%1.png")
                               .arg(mPlayerWidget->getPos(), numLength, 10, QChar('0'));
d.kilic's avatar
d.kilic committed
            }
            else
d.kilic's avatar
d.kilic committed
                fileName = dest + "/" + mAnimation->getCurrentFileName();
d.kilic's avatar
d.kilic committed

d.kilic's avatar
d.kilic committed
            {
                painter->begin(viewImage);
                if(mCropZoomViewAct->isChecked())
d.kilic's avatar
d.kilic committed
                    mView->render(painter);
d.kilic's avatar
d.kilic committed
                else
d.kilic's avatar
d.kilic committed
                    mScene->render(painter);
d.kilic's avatar
d.kilic committed
                painter->end();

                if(viewImage->save(fileName)) //, const char * format = 0 (format wird aus dateinamen geholt), int
                                              // quality = -1 default normal (0..100)
d.kilic's avatar
d.kilic committed
                {
                    formatIsSaveAble = true;
                    mPlayerWidget->frameForward();
                }
            }
            else if(mImage->save(fileName)) //, const char * format = 0 (format wird aus dateinamen geholt), int quality
                                            //= -1 default normal (0..100)
d.kilic's avatar
d.kilic committed
            {
                formatIsSaveAble = true;
                mPlayerWidget->frameForward();
            }
        }
        else if((mImgFiltered.channels() == 1) /*&& convert8To24bit*/)
d.kilic's avatar
d.kilic committed
        {
            size.width  = mImgFiltered.cols;
d.kilic's avatar
d.kilic committed
            size.height = mImgFiltered.rows;
            iplImgFilteredBGR.create(size, CV_8UC3);
        }

        QProgressDialog progress("", "Abort save", 0, progEnd, this);
        progress.setWindowModality(Qt::WindowModal); // blocks main window

        if(saveVideo)
d.kilic's avatar
d.kilic committed
        {
d.kilic's avatar
d.kilic committed
                progress.setLabelText("Save video view...");
d.kilic's avatar
d.kilic committed
            else
d.kilic's avatar
d.kilic committed
                progress.setLabelText("Save video...");
d.kilic's avatar
d.kilic committed
        {
d.kilic's avatar
d.kilic committed
                progress.setLabelText("Save view sequence...");
d.kilic's avatar
d.kilic committed
            else
d.kilic's avatar
d.kilic committed
                progress.setLabelText("Save image sequence...");
            progress.setValue(
                mPlayerWidget->getPos() - memPos); // -mempos nur, wenn nicht an den anfang gesprungen wird
d.kilic's avatar
d.kilic committed
            qApp->processEvents();
            if(progress.wasCanceled())
d.kilic's avatar
d.kilic committed
                break;
d.kilic's avatar
d.kilic committed

            if(saveVideo)
d.kilic's avatar
d.kilic committed
            {
                // video sequence
d.kilic's avatar
d.kilic committed
                {
                    painter->begin(viewImage);
                    if(mCropZoomViewAct->isChecked())
d.kilic's avatar
d.kilic committed
                        mView->render(painter);
d.kilic's avatar
d.kilic committed
                    else
d.kilic's avatar
d.kilic committed
                        mScene->render(painter);
d.kilic's avatar
d.kilic committed
                    painter->end();
                }
                if((mImgFiltered.channels() == 1) /* && convert8To24bit*/)
d.kilic's avatar
d.kilic committed
                {
                    cv::cvtColor(mImg, iplImgFilteredBGR, cv::COLOR_GRAY2BGR);
                        writeFrameRet = aviFile.appendFrame(
                            (const unsigned char *) viewImage->bits(),
                            true); // 2. param besagt, ob vertikal gespiegel werden soll
d.kilic's avatar
d.kilic committed
                    else
                        writeFrameRet = aviFile.appendFrame(
                            (const unsigned char *) iplImgFilteredBGR.data,
                            true); // 2. param besagt, ob vertikal gespiegel werden soll
d.kilic's avatar
d.kilic committed
                }
                else
                {
                    if(saveView)
                    {
                        writeFrameRet = aviFile.appendFrame(
                            (const unsigned char *) viewImage->bits(),
                            true); // 2. param besagt, ob vertikal gespiegel werden soll
                    }
                    else
                    {
                        writeFrameRet = aviFile.appendFrame(
                            (const unsigned char *) mImg.data,
                            true); // 2. param besagt, ob vertikal gespiegel werden soll
d.kilic's avatar
d.kilic committed
                    }
                }

                if(!writeFrameRet)
d.kilic's avatar
d.kilic committed
                {
                    progress.setValue(progEnd);
                    PCritical(
                        this,
                        tr("PeTrack"),
                        tr("Cannot save %1 maybe because of wrong file extension or unsupported codec.").arg(dest));
d.kilic's avatar
d.kilic committed
                    break;
                }
            }
            else
            {
                // single frame sequence
d.kilic's avatar
d.kilic committed
                {
                    painter->begin(viewImage);
                    if(mCropZoomViewAct->isChecked())
d.kilic's avatar
d.kilic committed
                        mView->render(painter);
d.kilic's avatar
d.kilic committed
                    else
d.kilic's avatar
d.kilic committed
                        mScene->render(painter);
d.kilic's avatar
d.kilic committed
                    painter->end();
                }
                if(mAnimation->isVideo())
d.kilic's avatar
d.kilic committed
                {
                    fileName = (dest + "/" + mAnimation->getFileBase() + "%1.png")
                                   .arg(mPlayerWidget->getPos(), numLength, 10, QChar('0'));
                    if(saveView)
d.kilic's avatar
d.kilic committed
                        saveRet = viewImage->save(fileName);
d.kilic's avatar
d.kilic committed
                    else
d.kilic's avatar
d.kilic committed
                        saveRet = mImage->save(fileName);
d.kilic's avatar
d.kilic committed
                }
                else if(formatIsSaveAble)
d.kilic's avatar
d.kilic committed
                {
                    fileName = dest + "/" + mAnimation->getCurrentFileName();
d.kilic's avatar
d.kilic committed
                        saveRet = viewImage->save(fileName);
d.kilic's avatar
d.kilic committed
                    else
d.kilic's avatar
d.kilic committed
                        saveRet = mImage->save(fileName);
d.kilic's avatar
d.kilic committed
                }
                else
                {
                    fileName = dest + "/" + QFileInfo(mAnimation->getCurrentFileName()).completeBaseName() + ".png";
d.kilic's avatar
d.kilic committed
                        saveRet = viewImage->save(fileName);
d.kilic's avatar
d.kilic committed
                    else
d.kilic's avatar
d.kilic committed
                        saveRet = mImage->save(fileName, "PNG"); //, int quality = -1 default normal (0..100)
d.kilic's avatar
d.kilic committed
                }
d.kilic's avatar
d.kilic committed
                {
                    progress.setValue(progEnd);
                    PCritical(this, tr("PeTrack"), tr("Cannot save %1.").arg(fileName));
d.kilic's avatar
d.kilic committed
                    break;
                }
            }
        } while(mPlayerWidget->frameForward());
d.kilic's avatar
d.kilic committed

        if(!saveVideo && saveView)
d.kilic's avatar
d.kilic committed
        {
            delete viewImage;
            delete painter;
        }

        // bei abbruch koennen es auch mPlayerWidget->getPos() frames sein, die bisher geschrieben wurden
        //-memPos nur, wenn nicht an den anfang gesprungen wird
        debout << "wrote " << mPlayerWidget->getPos() + 1 - memPos << " of " << mAnimation->getNumFrames() << " frames."
               << std::endl;
d.kilic's avatar
d.kilic committed
        progress.setValue(progEnd);

        if(saveVideo)
d.kilic's avatar
d.kilic committed
        {
            aviFile.close();
        }

        mPlayerWidget->skipToFrame(memPos);
        lastDir = dest;
    }
}

/**
 * @brief Saves the current View, including visualizations, in a file (.g. pdf)
 *
 * @param dest name of the saved file; if empty, a dialogue for the user opens
 */
void Petrack::saveView(QString dest) // default = ""
d.kilic's avatar
d.kilic committed
{
    static QString lastFile;

    if(mImage)
    {
        // if no destination file or folder is given
        if(dest.isEmpty())
d.kilic's avatar
d.kilic committed
        {
            if(lastFile.isEmpty() && !mSeqFileName.isEmpty())
d.kilic's avatar
d.kilic committed
                lastFile = QFileInfo(mSeqFileName).path();
d.kilic's avatar
d.kilic committed

            // alle unetrstuetzen fileformate erhaelt man mit
            // QImageReader::supportedImageFormats() and QImageWriter::supportedImageFormats()
            // gif muss nicht dabei sein, dazu muss qt mit -qt-gif uebersetzt worden sein
            dest = QFileDialog::getSaveFileName(
                this,
                tr("Select image file"),
                lastFile,
                tr("PDF (*.pdf);;Postscript (*.ps *.eps);;Windows bitmaps (*.bmp);;JPEG (*.jpeg *.jpg);;Portable "
                   "network graphics (*.png);;Portable image format (*.pbm *.pgm *.ppm);;X11 Bitmap or Pixmap (*.xbm "
                   "*.xpm);;Pixel Images (*.bmp *.jpeg *.jpg *.png *.pbm *.pgm *.ppm *.xbm *.xpm);;All supported types "
                   "(*pdf *ps *.eps *.bmp *.jpeg *.jpg *.png *.pbm *.pgm *.ppm *.xbm *.xpm);;All files (*.*)"));
d.kilic's avatar
d.kilic committed
        }

        if(!dest.isEmpty())
d.kilic's avatar
d.kilic committed
        {
            if(dest.right(4) == ".pdf" || dest.right(3) == ".ps" || dest.right(4) == ".eps")
d.kilic's avatar
d.kilic committed
            {
                QPrinter printer(QPrinter::ScreenResolution); // HighResolution?
                printer.setColorMode(QPrinter::Color);
                printer.setOutputFileName(dest);
                QPainter painter(&printer);
                if(mCropZoomViewAct->isChecked())
d.kilic's avatar
d.kilic committed
                    mView->render(&painter);
d.kilic's avatar
d.kilic committed
                else
d.kilic's avatar
d.kilic committed
                    mScene->render(&painter);
d.kilic's avatar
d.kilic committed
            }
            else
            {
                // schwarzer rand links und unten?!
                QImage *img;
                if(mCropZoomViewAct->isChecked())
d.kilic's avatar
d.kilic committed
                    img = new QImage(mView->viewport()->width(), mView->viewport()->height(), QImage::Format_RGB32);
d.kilic's avatar
d.kilic committed
                else
d.kilic's avatar
d.kilic committed
                    img = new QImage((int) mScene->width(), (int) mScene->height(), QImage::Format_RGB32);
d.kilic's avatar
d.kilic committed
                QPainter painter(img);
                if(mCropZoomViewAct->isChecked())
d.kilic's avatar
d.kilic committed
                    mView->render(&painter);
d.kilic's avatar
d.kilic committed
                else
d.kilic's avatar
d.kilic committed
                    mScene->render(&painter);
d.kilic's avatar
d.kilic committed
                painter.end();
                if(!img->save(dest)) //, "PNG"
                    PCritical(
                        this, tr("PeTrack"), tr("Cannot save %1 maybe because of wrong file extension.").arg(dest));
d.kilic's avatar
d.kilic committed
                delete img;
            }
            lastFile = dest;
        }
    }
}

void Petrack::saveImage(QString dest) // default = ""
d.kilic's avatar
d.kilic committed
{
    static QString lastFile;

    if(mImage)
    {
        // if no destination file or folder is given
        if(dest.isEmpty())
d.kilic's avatar
d.kilic committed
        {
            if(lastFile.isEmpty() && !mSeqFileName.isEmpty())
d.kilic's avatar
d.kilic committed
                lastFile = QFileInfo(mSeqFileName).path();
d.kilic's avatar
d.kilic committed


            // alle unetrstuetzen fileformate erhaelt man mit
            // QImageReader::supportedImageFormats() and QImageWriter::supportedImageFormats()
            // gif muss nict dabei sein, dazu muss qt mit -qt-gif uebesetz worden sein
            dest = QFileDialog::getSaveFileName(
                this,
                tr("Select image file"),
                lastFile,
                tr("PDF (*.pdf);;Postscript (*.ps *.eps);;Windows bitmaps (*.bmp);;JPEG (*.jpeg *.jpg);;Portable "
                   "network graphics (*.png);;Portable image format (*.pbm *.pgm *.ppm);;X11 Bitmap or Pixmap (*.xbm "
                   "*.xpm);;Pixel Images (*.bmp *.jpeg *.jpg *.png *.pbm *.pgm *.ppm *.xbm *.xpm);;All supported types "
                   "(*pdf *ps *.eps *.bmp *.jpeg *.jpg *.png *.pbm *.pgm *.ppm *.xbm *.xpm);;All files (*.*)"));
d.kilic's avatar
d.kilic committed
        }

        if(!dest.isEmpty())
d.kilic's avatar
d.kilic committed
        {
            if(dest.right(4) == ".pdf" || dest.right(3) == ".ps" || dest.right(4) == ".eps")
d.kilic's avatar
d.kilic committed
            {
                QPrinter printer(QPrinter::ScreenResolution); // HighResolution?
                printer.setColorMode(QPrinter::Color);
                printer.setOutputFileName(dest);
                QPainter painter(&printer);
                QRect    rect = painter.viewport();
                QSize    size = mImage->size();
d.kilic's avatar
d.kilic committed
                size.scale(rect.size(), Qt::KeepAspectRatio);
                painter.setViewport(rect.x(), rect.y(), size.width(), size.height());
                painter.setWindow(mImage->rect());
                painter.drawImage(0, 0, *mImage);
            }
            else
            {
                if(!mImage->save(dest)) //, "PNG"
                    PCritical(
                        this, tr("PeTrack"), tr("Cannot save %1 maybe because of wrong file extension.").arg(dest));
d.kilic's avatar
d.kilic committed
            }
            lastFile = dest;
        }
    }
}

void Petrack::print()
{
    if(mImage)
    {
        // HighResolution font zu gross! und laengere laufzeit und eher overflow
        // aber so pixelig und keine schoenen linien
        QPrinter printer(QPrinter::ScreenResolution); // ScreenResolution, HighResolution// liefert zu hause:
                                                      // QWin32PrintEngine::initialize: GetPrinter failed ()
        printer.setPageSize(QPageSize{QPageSize::PageSizeId::A4});
d.kilic's avatar
d.kilic committed
        QPrintDialog dialog(&printer, this);
        if(dialog.exec())
        {
d.kilic's avatar
d.kilic committed
            QPainter painter(&printer);
            mView->render(&painter);
        }
    }
    else
        PCritical(this, tr("PeTrack"), tr("Nothing to print!"));
d.kilic's avatar
d.kilic committed
}

void Petrack::resetSettings()
{
    mAnimation->reset();
    openXml(mDefaultSettings);
}

void Petrack::about()
{
    auto about = new AboutDialog(
        this,
        mPetrackVersion,
        mGitCommitID,
        mGitCommitDate,
        mGitCommitBranch,
        mCompilerID,
        mCompilerVersion,
        mCompileDate,
        mAuthors);
    about->show();
d.kilic's avatar
d.kilic committed
}


void Petrack::commandLineOptions()
{
    PMessageBox *mb = new PMessageBox{this, tr("Command line options"), commandLineOptionsString, QIcon()};
    mb->setModal(false);
d.kilic's avatar
d.kilic committed
    mb->setAttribute(Qt::WA_DeleteOnClose);
d.kilic's avatar
d.kilic committed
}

void Petrack::keyBindings()
{
    const QString out = tr(
        "<p>Beside the space bar all bindings only affect inside the image.</p>"
        "<dl><dt><kbd>Space bar</kbd></dt><dd>toggles between pause and last play direction</dd>"
        "<dt><kbd>Mouse scroll wheel</kbd></dt><dd>zooms in and out to or from the pixel of the image at the position "
        "of the mouse pointer</dd>"
        "<dt><kbd>Shift + mouse scroll wheel</kbd></dt><dd>plays forwards or backwards frame by frame</dd>"
        "<dt><kbd>Holding left mouse button</kbd></dt><dd>moves image</dd>"
        "<dt><kbd>Arrows up/down</kbd></dt><dd>zoom in/out</dd>"
        "<dt><kbd>Arrows left/right</kbd></dt><dd>frame back/forward</dd>"
        "<dt><kbd>Double-click left mouse button</kbd></dt><dd>opens video or image sequence</dd>"
        "<dt><kbd>Ctrl + double-click left mouse button</kbd></dt><dd>inserts new or moves near trackpoint</dd>"
        "<dt><kbd>Ctrl + Shift + double-click left mouse button</kbd></dt><dd>splits near trackpoint before actual "
        "frame</dd>"
        "<dt><kbd>Ctrl + double-click right mouse button</kbd></dt><dd>deletes a trajectory of a near trackpoint</dd>"
        "<dt><kbd>Shift + double-click right mouse button</kbd></dt><dd>deletes the past part of a trajectory of a "
        "near trackpoint</dd>"
        "<dt><kbd>Alt + double-click right mouse button</kbd></dt><dd>deletes the future part of a trajectory of a "
        "near trackpoint</dd>"
        "<dt><kbd>Ctrl + double-click middle mouse button</kbd></dt><dd>deletes all trajectories</dd>"
        "<dt><kbd>Shift + double-click middle mouse button</kbd></dt><dd>deletes the past part of all trajectories</dd>"
        "<dt><kbd>Alt + double-click middle mouse button</kbd></dt><dd>deletes the future part of all trajectories</dd>"
        "<dt><kbd>Shift + t</kbd></dt><dd>toggles tracking online calculation</dd>"
        "<dt><kbd>Shift + double-click left mouse button</kbd></dt><dd>inserts new or moves near trackpoint and "
        "enables showing only the modified trajectory</dd></dl>"
        "<p>Further key bindings you will find next to the entries of the menus.</p>");

    PMessageBox *mb = new PMessageBox(this, tr("Key Bindings"), out, QIcon());
d.kilic's avatar
d.kilic committed
    mb->setAttribute(Qt::WA_DeleteOnClose);
d.kilic's avatar
d.kilic committed

    mb->show();
}

void Petrack::onlineHelp()
{
    static QUrl url("https://jugit.fz-juelich.de/ped-dyn-emp/petrack/-/wikis/home");
    if(!(QDesktopServices::openUrl(url)))
        PCritical(this, tr("PeTrack"), tr("Cannot open external browser<br>with url ") + url.toString() + "!");
d.kilic's avatar
d.kilic committed
}

void Petrack::antialias()
{
    mView->setRenderHint(QPainter::Antialiasing, mAntialiasAct->isChecked());
}
void Petrack::opengl()
{
    mView->setViewport(mOpenGLAct->isChecked() ? new QGLWidget(QGLFormat(QGL::SampleBuffers)) : new QWidget);

    // alten freigeben wegen new????
}
void Petrack::reset()
{
    mViewWidget->resetView();
}
void Petrack::fitInView()
{
    mViewWidget->fitInView();
}
void Petrack::fitInROI()
{
    mViewWidget->fitInROI(getRecoRoiItem()->rect());
    // what about trackingRoi???
}
void Petrack::setGlobalFont()
{
d.kilic's avatar
d.kilic committed
    QFont font = QFontDialog::getFont(&ok, this->font(), this);
d.kilic's avatar
d.kilic committed
        this->setFont(font); // font is set to the font the user selected
d.kilic's avatar
d.kilic committed
        // the user canceled the dialog; font is set to the initial
        // value, in this case Times, 12.
    }
}

void Petrack::showHideControlWidget()
{
    // show | hide Control
    mViewWidget->hideControls(mHideControlsAct->isChecked());
}

void Petrack::setCamera()
{
#ifndef STEREO_DISABLED
    if(mAnimation)
d.kilic's avatar
d.kilic committed
    {
        if(mCameraLeftViewAct->isChecked())
d.kilic's avatar
d.kilic committed
        {
            if((mAnimation->getCamera()) != cameraLeft)
d.kilic's avatar
d.kilic committed
                mAnimation->setCamera(cameraLeft); // war: hier wird direkt bei Umstellung neu gelesen
            else
                return;
        }
        else if(mCameraRightViewAct->isChecked())
d.kilic's avatar
d.kilic committed
        {
            if((mAnimation->getCamera()) != cameraRight)
d.kilic's avatar
d.kilic committed
                mAnimation->setCamera(cameraRight); // war: hier wird direkt bei Umstellung neu gelesen
            else
                return;
        }
        else // kann eigentlich nicht vorkommen
        {
            mAnimation->setCamera(cameraUnset);
            return;
        }
        updateImage(mAnimation->getFrameAtIndex(
            mAnimation->getCurrentFrameNum())); // wird nur aufgerufen, wenn left / right sich geaendert hat
        // mPlayerWidget->updateImage();
        // mPlayerWidget->skipToFrame(mPlayerWidget->getPos()); // machtpasue!!
        // updateImage(true); // nur dies aufrufen, wenn nicht links rechts gleichzeitig gehalten wird
d.kilic's avatar
d.kilic committed
    }
d.kilic's avatar
d.kilic committed
}

/**
 * @brief Helper function to create Actions for the menu bar
 * @see Petrack::createMenus()
 */
d.kilic's avatar
d.kilic committed
void Petrack::createActions()
{
    mOpenSeqAct = new QAction(tr("&Open Sequence"), this);
    mOpenSeqAct->setShortcut(tr("Ctrl+Shift+O"));
    connect(mOpenSeqAct, SIGNAL(triggered()), this, SLOT(openSequence()));

    mOpenCameraAct = new QAction(tr("Open Camera Stream"), this);
    // mOpenCameraAct->setShortcut(tr("Ctrl+C")); // because of some reason it is sometimes fired with
    // Ctrl+LeftMouseButton ==> so disabled (it's also not really needed)
d.kilic's avatar
d.kilic committed
    connect(mOpenCameraAct, SIGNAL(triggered()), this, SLOT(openCameraLiveStream()));

    mOpenMoCapAct = new QAction(tr("Manage MoCap Files"), this);
    connect(mOpenMoCapAct, &QAction::triggered, this, &Petrack::openMoCapFile);

d.kilic's avatar
d.kilic committed
    mSaveSeqVidAct = new QAction(tr("Save Video"), this);
    // mSaveSeqVidAct->setShortcut(tr("Ctrl+E"));
d.kilic's avatar
d.kilic committed
    mSaveSeqVidAct->setEnabled(false);
    connect(mSaveSeqVidAct, SIGNAL(triggered()), this, SLOT(saveVideo()));

    mSaveSeqVidViewAct = new QAction(tr("Save Video View"), this);
    mSaveSeqVidViewAct->setShortcut(tr("Ctrl+E"));
    mSaveSeqVidViewAct->setEnabled(false);
    connect(mSaveSeqVidViewAct, SIGNAL(triggered()), this, SLOT(saveVideoView()));

    mSaveSeqImgAct = new QAction(tr("Save Image S&equence"), this);
    mSaveSeqImgAct->setShortcut(tr("Ctrl+F"));
    mSaveSeqImgAct->setEnabled(false);
    connect(mSaveSeqImgAct, SIGNAL(triggered()), this, SLOT(saveImageSequence()));

    mSaveSeqViewAct = new QAction(tr("Save View S&equence"), this);
    //    mSaveSeqViewAct->setShortcut(tr("Ctrl+F"));
    mSaveSeqViewAct->setEnabled(false);
    connect(mSaveSeqViewAct, SIGNAL(triggered()), this, SLOT(saveViewSequence()));

    mOpenPrAct = new QAction(tr("&Open Project"), this);
    mOpenPrAct->setShortcut(tr("Ctrl+O"));
    connect(mOpenPrAct, SIGNAL(triggered()), this, SLOT(openProject()));

    mSavePrAct = new QAction(tr("&Save Project As"), this);
    mSavePrAct->setShortcut(tr("Ctrl+Shift+S"));
    connect(mSavePrAct, SIGNAL(triggered()), this, SLOT(saveProject()));

    mSaveAct = new QAction(tr("&Save Project"), this);
    mSaveAct->setShortcut(tr("Ctrl+S"));
    connect(mSaveAct, SIGNAL(triggered()), this, SLOT(saveSameProject()));

    mSaveImageAct = new QAction(tr("&Save Image"), this);
    mSaveImageAct->setShortcut(tr("Ctrl+I"));
    mSaveImageAct->setEnabled(false);
    connect(mSaveImageAct, SIGNAL(triggered()), this, SLOT(saveImage()));

    mSaveViewAct = new QAction(tr("&Save View"), this);
    mSaveViewAct->setShortcut(tr("Ctrl+V"));
    mSaveViewAct->setEnabled(false);
    connect(mSaveViewAct, SIGNAL(triggered()), this, SLOT(saveView()));

    mPrintAct = new QAction(tr("&Print"), this);
    mPrintAct->setShortcut(tr("Ctrl+P"));
    mPrintAct->setEnabled(false);
    connect(mPrintAct, SIGNAL(triggered()), this, SLOT(print()));

    mResetSettingsAct = new QAction(tr("&Reset Settings"), this);
    //    mResetSettingsAct->setShortcut(tr("Ctrl+R"));
d.kilic's avatar
d.kilic committed
    mResetSettingsAct->setEnabled(false); // da es noch nicht fehlerfrei funktioniert
    connect(mResetSettingsAct, SIGNAL(triggered()), this, SLOT(resetSettings()));

    mExitAct = new QAction(tr("E&xit"), this);
    mExitAct->setShortcut(tr("Ctrl+Q"));
    connect(mExitAct, SIGNAL(triggered()), this, SLOT(close()));

    mAntialiasAct = new QAction(tr("&Antialias"), this);
    mAntialiasAct->setShortcut(tr("Ctrl+A"));
    mAntialiasAct->setCheckable(true);
    connect(mAntialiasAct, SIGNAL(triggered()), this, SLOT(antialias()));

    mFontAct = new QAction(tr("&Font"), this);
    connect(mFontAct, SIGNAL(triggered()), this, SLOT(setGlobalFont()));

    mHideControlsAct = new QAction(tr("&Hide controls"), this);
    mHideControlsAct->setShortcut(tr("Ctrl+H"));
    mHideControlsAct->setCheckable(true);
    connect(mHideControlsAct, SIGNAL(triggered()), this, SLOT(showHideControlWidget()));
    connect(mHideControlsAct, SIGNAL(changed()), this, SLOT(showHideControlWidget()));
d.kilic's avatar
d.kilic committed

    mCropZoomViewAct = new QAction(tr("&Transform while saving"), this); // Crop and zoom while saving
d.kilic's avatar
d.kilic committed
    mCropZoomViewAct->setCheckable(true);

    mOpenGLAct = new QAction(tr("Open&GL"), this);
    mOpenGLAct->setShortcut(tr("Ctrl+G"));
    mOpenGLAct->setCheckable(true);
    connect(mOpenGLAct, SIGNAL(triggered()), this, SLOT(opengl()));

    mResetAct = new QAction(tr("&Reset"), this);
    mResetAct->setShortcut(tr("Ctrl+R"));
    connect(mResetAct, SIGNAL(triggered()), this, SLOT(reset()));

    mFitViewAct =
        new QAction(tr("Fit in window"), this); // Resize to window; fit in view; show all; in fenster einpassen
d.kilic's avatar
d.kilic committed
    mFitViewAct->setShortcut(tr("Ctrl+0"));
    connect(mFitViewAct, SIGNAL(triggered()), this, SLOT(fitInView()));

    mFitROIAct = new QAction(tr("Fit in region of interest"), this); // Resize ROI to window; fit in view;
    mFitROIAct->setShortcut(tr("Ctrl+1"));
    connect(mFitROIAct, SIGNAL(triggered()), this, SLOT(fitInROI()));

    mCameraGroupView = new QActionGroup(this);
    // mCameraGroupView->addAction(mCameraLeftViewAct);
    // mCameraGroupView->addAction(mCameraRightViewAct);
d.kilic's avatar
d.kilic committed
    mCameraLeftViewAct = new QAction(tr("&Left"), mCameraGroupView);
    mCameraLeftViewAct->setShortcut(tr("Ctrl++Shift+L"));
    mCameraLeftViewAct->setCheckable(true);
    connect(mCameraLeftViewAct, SIGNAL(triggered()), this, SLOT(setCamera()));
    mCameraRightViewAct = new QAction(tr("&Right"), mCameraGroupView);
    mCameraRightViewAct->setShortcut(tr("Ctrl++Shift+R"));
    mCameraRightViewAct->setCheckable(true);
    connect(mCameraRightViewAct, SIGNAL(triggered()), this, SLOT(setCamera()));
    mCameraRightViewAct->setChecked(true); // right wird als default genommen, da reference image in triclops auch right
                                           // ist // erste trj wurden mit left gerechnet
d.kilic's avatar
d.kilic committed

    mLimitPlaybackSpeed = new QAction(tr("&Limit playback speed"));
    // Not checkable like Fix since this is also controlled through clicking on FPS and syncing currently would be
    // bothersome
    connect(
        mLimitPlaybackSpeed,
        &QAction::triggered,
        mPlayerWidget,
        [&]() { mPlayerWidget->setPlayerSpeedLimited(!mPlayerWidget->getPlayerSpeedLimited()); });
    mFixPlaybackSpeed = new QAction(tr("&Fix playback speed"));
    mFixPlaybackSpeed->setCheckable(true);
    connect(mFixPlaybackSpeed, &QAction::toggled, mPlayerWidget, &Player::setPlayerSpeedFixed);
    mSetToRealtime = new QAction(tr("&Realtime"));
    connect(
        mSetToRealtime, &QAction::triggered, mPlayerWidget, [&]() { mPlayerWidget->setSpeedRelativeToRealtime(1.0); });
    mSetTo2p00 = new QAction(tr("&x2"));
    connect(mSetTo2p00, &QAction::triggered, mPlayerWidget, [&]() { mPlayerWidget->setSpeedRelativeToRealtime(2.0); });
    mSetTo1p75 = new QAction(tr("&x1.75"));
    connect(mSetTo1p75, &QAction::triggered, mPlayerWidget, [&]() { mPlayerWidget->setSpeedRelativeToRealtime(1.75); });
    mSetTo1p50 = new QAction(tr("&x1.5"));
    connect(mSetTo1p50, &QAction::triggered, mPlayerWidget, [&]() { mPlayerWidget->setSpeedRelativeToRealtime(1.5); });
    mSetTo1p25 = new QAction(tr("&x1.25"));
    connect(mSetTo1p25, &QAction::triggered, mPlayerWidget, [&]() { mPlayerWidget->setSpeedRelativeToRealtime(1.25); });
    mSetTo0p75 = new QAction(tr("&x0.75"));
    connect(mSetTo0p75, &QAction::triggered, mPlayerWidget, [&]() { mPlayerWidget->setSpeedRelativeToRealtime(0.75); });
    mSetTo0p50 = new QAction(tr("&x0.5"));
    connect(mSetTo0p50, &QAction::triggered, mPlayerWidget, [&]() { mPlayerWidget->setSpeedRelativeToRealtime(0.5); });
    mSetTo0p25 = new QAction(tr("&x0.25"));
    connect(mSetTo0p25, &QAction::triggered, mPlayerWidget, [&]() { mPlayerWidget->setSpeedRelativeToRealtime(0.25); });
d.kilic's avatar
d.kilic committed

    mPlayerLooping = new QAction(tr("&Loop"));
    mPlayerLooping->setCheckable(true);
    connect(mPlayerLooping, &QAction::triggered, mPlayerWidget, &Player::setLooping);
d.kilic's avatar
d.kilic committed
    // -------------------------------------------------------------------------------------------------------


    mDelPastAct = new QAction(tr("&Past part of all trj."), this);
    connect(
        mDelPastAct,
        &QAction::triggered,
        this,
        [this]() { this->deleteTrackPointAll(PersonStorage::Direction::Previous); });
d.kilic's avatar
d.kilic committed

    mDelFutureAct = new QAction(tr("&Future part of all trj."), this);
    connect(
        mDelFutureAct,
        &QAction::triggered,
        this,
        [this]() { this->deleteTrackPointAll(PersonStorage::Direction::Following); });
d.kilic's avatar
d.kilic committed

    mDelAllRoiAct = new QAction(tr("&Trj. moving through ROI"), this);
    connect(mDelAllRoiAct, &QAction::triggered, this, &Petrack::deleteTrackPointROI);
d.kilic's avatar
d.kilic committed
    mDelPartRoiAct = new QAction(tr("Part of Trj. inside &ROI"), this);
    connect(mDelPartRoiAct, &QAction::triggered, this, &Petrack::deleteTrackPointInsideROI);
d.kilic's avatar
d.kilic committed

    // -------------------------------------------------------------------------------------------------------

    mCommandAct = new QAction(tr("&Command line options"), this);
    connect(mCommandAct, SIGNAL(triggered()), this, SLOT(commandLineOptions()));

    mKeyAct = new QAction(tr("&Key bindings"), this);
    connect(mKeyAct, SIGNAL(triggered()), this, SLOT(keyBindings()));

    mAboutAct = new QAction(tr("&About"), this);
    connect(mAboutAct, SIGNAL(triggered()), this, SLOT(about()));

    mOnlineHelpAct = new QAction(tr("Online &Help"), this);
    mOnlineHelpAct->setShortcut(tr("Ctrl+H"));
    connect(mOnlineHelpAct, SIGNAL(triggered()), this, SLOT(onlineHelp()));
}

/**
 * @brief Helper function building menues out of QActions
 * @see Petrack::createActions()
 */
d.kilic's avatar
d.kilic committed
void Petrack::createMenus()
{
    mFileMenu = new QMenu(tr("&File"), this);
    mFileMenu->addAction(mOpenPrAct);
    mFileMenu->addAction(mSaveAct);
    mFileMenu->addAction(mSavePrAct);
    mFileMenu->addSeparator();
    mFileMenu->addAction(mOpenSeqAct);
    mFileMenu->addAction(mOpenCameraAct);
    mFileMenu->addAction(mOpenMoCapAct);
d.kilic's avatar
d.kilic committed
    mFileMenu->addAction(mSaveSeqVidAct);
    mFileMenu->addAction(mSaveSeqVidViewAct);
    mFileMenu->addAction(mSaveImageAct);
    mFileMenu->addAction(mSaveSeqImgAct);
    mFileMenu->addAction(mSaveViewAct);
    mFileMenu->addAction(mSaveSeqViewAct);
    mFileMenu->addAction(mPrintAct);
    mFileMenu->addSeparator();
    mFileMenu->addAction(mResetSettingsAct);
    mFileMenu->addSeparator();
    mFileMenu->addAction(mExitAct);

    mViewMenu = new QMenu(tr("&View"), this);
    mViewMenu->addAction(mAntialiasAct);
    mViewMenu->addAction(mOpenGLAct);
    mViewMenu->addAction(mCropZoomViewAct);
    mCameraMenu = mViewMenu->addMenu(tr("&Camera"));
    mCameraMenu->addAction(mCameraLeftViewAct);
    mCameraMenu->addAction(mCameraRightViewAct);
    mViewMenu->addAction(mFixPlaybackSpeed);
    mViewMenu->addAction(mLimitPlaybackSpeed);
    mPlaybackSpeedMenu = mViewMenu->addMenu(tr("&Playback speed"));
    mPlaybackSpeedMenu->addAction(mSetToRealtime);
    mPlaybackSpeedMenu->addAction(mSetTo2p00);
    mPlaybackSpeedMenu->addAction(mSetTo1p75);
    mPlaybackSpeedMenu->addAction(mSetTo1p50);
    mPlaybackSpeedMenu->addAction(mSetTo1p25);
    mPlaybackSpeedMenu->addAction(mSetTo0p75);
    mPlaybackSpeedMenu->addAction(mSetTo0p50);
    mPlaybackSpeedMenu->addAction(mSetTo0p25);
d.kilic's avatar
d.kilic committed
    mViewMenu->addAction(mPlayerLooping);
d.kilic's avatar
d.kilic committed
    mViewMenu->addSeparator();
    mViewMenu->addAction(mFitViewAct);
    mViewMenu->addAction(mFitROIAct);
    mViewMenu->addAction(mResetAct);
    mViewMenu->addSeparator();
    mViewMenu->addAction(mFontAct);
    mViewMenu->addSeparator();
    mViewMenu->addAction(mHideControlsAct);

    mDeleteMenu = new QMenu(tr("&Delete"), this);
    mDeleteMenu->addAction(mDelPastAct);
    mDeleteMenu->addAction(mDelFutureAct);
    mDeleteMenu->addAction(mDelAllRoiAct);
    mDeleteMenu->addAction(mDelPartRoiAct);

    mHelpMenu = new QMenu(tr("&Help"), this);
    mHelpMenu->addAction(mCommandAct);
    mHelpMenu->addAction(mKeyAct);
    mHelpMenu->addAction(mAboutAct);
    mHelpMenu->addAction(mOnlineHelpAct);

    menuBar()->addMenu(mFileMenu);
    menuBar()->addMenu(mViewMenu);
    menuBar()->addMenu(mDeleteMenu);
    menuBar()->addMenu(mHelpMenu);

    mCameraMenu->setEnabled(false);
}

/**
 * @brief Helper function to create status bar at the bottom of the window
 */
d.kilic's avatar
d.kilic committed
void Petrack::createStatusBar()
{
    QFont f("Courier", 12, QFont::Bold); // Times Helvetica, Normal
d.kilic's avatar
d.kilic committed
    statusBar()->setMaximumHeight(28);
    statusBar()->showMessage(tr("Ready"));
    statusBar()->addPermanentWidget(mStatusLabelStereo = new QLabel(" "));
    statusBar()->addPermanentWidget(mStatusLabelTime = new QLabel(" "));
    statusBar()->addPermanentWidget(mStatusLabelFPS = new QLabel(" "));
    statusBar()->addPermanentWidget(mStatusPosRealHeight = new QDoubleSpinBox());
    connect(mStatusPosRealHeight, SIGNAL(valueChanged(double)), this, SLOT(setStatusPosReal()));

    statusBar()->addPermanentWidget(mStatusLabelPosReal = new QLabel(" "));
    statusBar()->addPermanentWidget(mStatusLabelPos = new QLabel(" "));
    statusBar()->addPermanentWidget(mStatusLabelColor = new QLabel(" "));
    mStatusLabelStereo->setFont(f);
    mStatusLabelStereo->setMinimumWidth(200);
    mStatusLabelTime->setFont(f);
    mStatusLabelTime->setMinimumWidth(200);
    mStatusLabelFPS->setFont(f);
    mStatusLabelFPS->setMinimumWidth(80);
d.kilic's avatar
d.kilic committed
    mStatusLabelFPS->setAutoFillBackground(true);
    mStatusLabelFPS->setToolTip("Click to adapt play rate to fps rate");
    mStatusPosRealHeight->setRange(-999.9, 9999.9); // in cm
    mStatusPosRealHeight->setDecimals(1);
    mStatusPosRealHeight->setFont(f);
    mStatusLabelPosReal->setFont(f);
    mStatusLabelPosReal->setMinimumWidth(340);
    mStatusLabelPos->setFont(f);
    mStatusLabelPos->setMinimumWidth(100);
    mStatusLabelColor->setFont(f);
    mStatusLabelColor->setMinimumWidth(90);
    mStatusLabelColor->setAutoFillBackground(true);
}

void Petrack::resetUI()
{
d.kilic's avatar
d.kilic committed
    ///
    ///  Reset all UI elements to default settings
    ///  Noetig damit alle UI Elemente, welche in der neu geladenen Projekt-Datei z.B. noch nicht vorhanden sind, auf
    ///  sinnvolle Werte gesetzt werden. Anderenfalls kommt es evtl. beim nacheinander laden verschiedener Projekte zu
    ///  einem Programmabsturz
d.kilic's avatar
d.kilic committed
    ///
    return;
d.kilic's avatar
d.kilic committed
    mSeqFileName = "";
    mAnimation->free();
d.kilic's avatar
d.kilic committed
    {
        mImage->fill(QColor::fromRgb(255, 255, 255));
d.kilic's avatar
d.kilic committed
        mImageItem->setImage(mImage);
        mLogoItem->show();
    }
    mStatusPosRealHeight->setValue(180.0);
    /// calibration params
    /// image filters
    mControlWidget->filterBrightContrast->setCheckState(Qt::Unchecked);
    mControlWidget->filterBrightParam->setValue(0);
    mControlWidget->filterContrastParam->setValue(0);

    mControlWidget->filterBorder->setCheckState(Qt::Unchecked);
    mControlWidget->filterBorderParamSize->setValue(0);
    QColor defaultBorder = Qt::black;
    getBorderFilter()->getBorderColR()->setValue(defaultBorder.red());
    getBorderFilter()->getBorderColG()->setValue(defaultBorder.green());
    getBorderFilter()->getBorderColB()->setValue(defaultBorder.blue());

    mControlWidget->filterBg->setCheckState(Qt::Unchecked);
    mControlWidget->filterBgDeleteNumber->setValue(3);
    mControlWidget->filterBgDeleteTrj->setCheckState(Qt::Checked);
    mControlWidget->filterBgShow->setCheckState(Qt::Unchecked);
    mControlWidget->filterBgUpdate->setCheckState(Qt::Unchecked);
    getBackgroundFilter()->setFilename(nullptr);
d.kilic's avatar
d.kilic committed
    getBackgroundFilter()->reset();

    mControlWidget->filterSwap->setCheckState(Qt::Unchecked);
    mControlWidget->filterSwapH->setCheckState(Qt::Unchecked);
    mControlWidget->filterSwapV->setCheckState(Qt::Unchecked);

    /// intrinsic params
    mControlWidget->apply->setCheckState(Qt::Unchecked);
    mControlWidget->fx->setValue(1000);
    mControlWidget->fy->setValue(1000);
    mControlWidget->cx->setValue(960);
    mControlWidget->cx->setMinimum(0);
    mControlWidget->cx->setMaximum(mControlWidget->cx->value() * 2);
d.kilic's avatar
d.kilic committed
    mControlWidget->cy->setValue(540);
    mControlWidget->cx->setMinimum(0);
    mControlWidget->cy->setMaximum(mControlWidget->cy->value() * 2);
d.kilic's avatar
d.kilic committed
    mControlWidget->r2->setValue(0);
    mControlWidget->r4->setValue(0);
    mControlWidget->r6->setValue(0);
    mControlWidget->tx->setValue(0);
    mControlWidget->ty->setValue(0);
    mControlWidget->quadAspectRatio->setCheckState(Qt::Unchecked);
    mControlWidget->fixCenter->setCheckState(Qt::Unchecked);
    mControlWidget->tangDist->setCheckState(Qt::Checked);
    getAutoCalib()->setBoardSizeX(6);
    getAutoCalib()->setBoardSizeY(8);
    getAutoCalib()->setSquareSize(5.0);
    getAutoCalib()->setCalibFiles(QStringList());

    /// extrinsic params
    mControlWidget->trans1->setValue(0);
    mControlWidget->trans2->setValue(0);
    mControlWidget->trans3->setValue(-500);
    mControlWidget->rot1->setValue(0);
    mControlWidget->rot2->setValue(0);
    mControlWidget->rot3->setValue(0);
    getExtrCalibration()->setExtrCalibFile(nullptr);
d.kilic's avatar
d.kilic committed

    /// coord system
    mControlWidget->coordShow->setCheckState(Qt::Unchecked);
    mControlWidget->coordFix->setCheckState(Qt::Unchecked);
    mControlWidget->coordTab->setCurrentIndex(0);
    // 3D
    mControlWidget->coord3DTransX->setValue(0);
    mControlWidget->coord3DTransY->setValue(0);
    mControlWidget->coord3DTransZ->setValue(0);
    mControlWidget->coord3DAxeLen->setValue(200);
    mControlWidget->coord3DSwapX->setCheckState(Qt::Unchecked);
    mControlWidget->coord3DSwapY->setCheckState(Qt::Unchecked);
    mControlWidget->coord3DSwapZ->setCheckState(Qt::Unchecked);
    mControlWidget->extCalibPointsShow->setCheckState(Qt::Unchecked);
    mControlWidget->extVanishPointsShow->setCheckState(Qt::Unchecked);
    // 2D
    mControlWidget->coordTransX->setValue(0);
    mControlWidget->coordTransY->setValue(0);
    mControlWidget->coordRotate->setValue(0);
    mControlWidget->coordScale->setValue(100);
    mControlWidget->coordAltitude->setValue(535);
    mControlWidget->coordUnit->setValue(100);
    mControlWidget->coordUseIntrinsic->setCheckState(Qt::Unchecked);

    /// alignment grid
    mControlWidget->gridShow->setCheckState(Qt::Unchecked);
    mControlWidget->gridFix->setCheckState(Qt::Unchecked);
    mControlWidget->gridTab->setCurrentIndex(0);
    // 3D
    mControlWidget->grid3DTransX->setValue(0);
    mControlWidget->grid3DTransY->setValue(0);
    mControlWidget->grid3DTransZ->setValue(0);
    mControlWidget->grid3DResolution->setValue(100);
    // 2D
    mControlWidget->gridTransX->setValue(0);
    mControlWidget->gridTransY->setValue(0);
    mControlWidget->gridRotate->setValue(0);
    mControlWidget->gridScale->setValue(100);

    ///
    /// recognition params
    ///
    mControlWidget->performRecognition->setCheckState(Qt::Unchecked);
    mControlWidget->recoStep->setValue(1);

    // region of interest
    mControlWidget->roiFix->setCheckState(Qt::Unchecked);
    mControlWidget->roiShow->setCheckState(Qt::Unchecked);
    getRecoRoiItem()->setRect(0, 0, 0, 0);
d.kilic's avatar
d.kilic committed

    // marker, default multicolor marker (until 11/2016 hermes marker)
    mControlWidget->recoMethod->setCurrentIndex(
        mControlWidget->recoMethod->findData(QVariant::fromValue(reco::RecognitionMethod::MultiColor)));
d.kilic's avatar
d.kilic committed
    mControlWidget->markerBrightness->setValue(100);
    mControlWidget->markerIgnoreWithout->setCheckState(Qt::Checked);

    // size and color
    mControlWidget->recoShowColor->setCheckState(Qt::Checked);
    mControlWidget->recoAutoWB->setCheckState(Qt::Checked);
    mControlWidget->recoColorX->setCurrentIndex(0);
    mControlWidget->recoColorY->setCurrentIndex(1);
    mControlWidget->recoColorZ->setValue(255);
    mControlWidget->recoGreyLevel->setValue(50);
    mControlWidget->recoSymbolSize->setValue(10);

    // map
    mControlWidget->recoColorModel->setCurrentIndex(0);
    mControlWidget->colorPlot->getMapItem()->delMaps();
    mControlWidget->mapNr->setValue(0);
    mControlWidget->mapNr->setMinimum(0);
    mControlWidget->mapNr->setMaximum(0);
    mControlWidget->mapX->setValue(0);
    mControlWidget->mapY->setValue(0);
    mControlWidget->mapW->setValue(0);
    mControlWidget->mapH->setValue(0);
    mControlWidget->mapColor->setCheckState(Qt::Checked);
    mControlWidget->mapHeight->setValue(180);
    mControlWidget->mapDefaultHeight->setValue(180);

    ///
    /// tracking params
    ///
    mControlWidget->trackOnlineCalc->setCheckState(Qt::Checked);
    mControlWidget->trackRepeat->setCheckState(Qt::Checked);
    mControlWidget->trackRepeatQual->setValue(50);
    mControlWidget->trackExtrapolation->setCheckState(Qt::Checked);
    mControlWidget->trackMerge->setCheckState(Qt::Unchecked);
    mControlWidget->trackOnlySelected->setCheckState(Qt::Checked);
    getTrackRoiItem()->setRect(0, 0, 0, 0);
d.kilic's avatar
d.kilic committed

    // export options
    mControlWidget->trackMissingFrames->setCheckState(Qt::Checked);
    mControlWidget->trackRecalcHeight->setCheckState(Qt::Checked);
    mControlWidget->trackAlternateHeight->setCheckState(Qt::Unchecked);
    mControlWidget->exportElimTp->setCheckState(Qt::Unchecked);
    mControlWidget->exportElimTrj->setCheckState(Qt::Unchecked);
    mControlWidget->exportSmooth->setCheckState(Qt::Checked);
    mControlWidget->exportViewDir->setCheckState(Qt::Unchecked);
    mControlWidget->exportAngleOfView->setCheckState(Qt::Unchecked);
    mControlWidget->exportUseM->setCheckState(Qt::Unchecked);
    mControlWidget->exportComment->setCheckState(Qt::Unchecked);
    mControlWidget->exportMarkerID->setCheckState(Qt::Unchecked);

    // test options
    mControlWidget->testEqual->setCheckState(Qt::Checked);
    mControlWidget->testVelocity->setCheckState(Qt::Checked);
    mControlWidget->testInside->setCheckState(Qt::Checked);
    mControlWidget->testLength->setCheckState(Qt::Checked);
    setTrackFileName(nullptr);
d.kilic's avatar
d.kilic committed

    // search region
    mControlWidget->trackRegionScale->setValue(16);
    mControlWidget->trackRegionLevels->setValue(3);
    mControlWidget->trackErrorExponent->setValue(0);
    mControlWidget->trackShowSearchSize->setCheckState(Qt::Unchecked);

    // path params
    mControlWidget->trackShow->setCheckState(Qt::Checked);
    mControlWidget->trackFix->setCheckState(Qt::Unchecked);

    mControlWidget->trackShowOnlyVisible->setCheckState(Qt::Unchecked);
    mControlWidget->trackShowOnly->setCheckState(Qt::Unchecked);
    mControlWidget->trackShowOnlyNr->setValue(1);
    mControlWidget->trackShowOnlyList->setCheckState(Qt::Unchecked);
    mControlWidget->trackShowOnlyNrList->setEnabled(false);
    mControlWidget->trackShowOnlyListButton->setEnabled(false);

    mControlWidget->trackShowCurrentPoint->setCheckState(Qt::Checked);
    mControlWidget->trackShowPoints->setCheckState(Qt::Unchecked);
    mControlWidget->trackShowPath->setCheckState(Qt::Checked);
    mControlWidget->trackShowColColor->setCheckState(Qt::Checked);
    mControlWidget->trackShowColorMarker->setCheckState(Qt::Checked);
    mControlWidget->trackShowNumber->setCheckState(Qt::Checked);
    mControlWidget->trackShowGroundPosition->setCheckState(Qt::Unchecked);
Loading
Loading full blame...