andre@25: /* Copyright (C) 2015 by ETH Zürich andre@25: * Software engineering by Intevation GmbH andre@2: * andre@2: * This file is Free Software under the GNU GPL (v>=2) andre@2: * and comes with ABSOLUTELY NO WARRANTY! andre@2: * See LICENSE.txt for details. andre@2: */ andre@2: #include "pngplayer.h" andre@3: #include "constants.h" andre@3: #include "imagelabel.h" andre@2: #include andre@2: #include andre@2: #include andre@3: #include andre@3: #include andre@3: #include andre@5: #include andre@10: #include andre@10: #include andre@3: andre@3: #include andre@2: andre@2: PNGPlayer::PNGPlayer(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f) { andre@2: setupGUI(); andre@5: QSettings settings; andre@34: double settingsSecs = settings.value(REPLAY_SPEED_KEY, REPLAY_SPEED_DEFAULT).toDouble(); andre@34: if (settingsSecs != 0) { andre@34: mSpeedSlider->setValue(settingsSecs * 1000 / REPLAY_SPEED_STEP_MS); andre@34: } andre@5: speedChanged(); andre@2: } andre@2: andre@2: void PNGPlayer::setupGUI() { andre@2: QVBoxLayout *baseLayout = new QVBoxLayout; andre@3: mPNGLabel = new ImageLabel; andre@3: mPNGLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); andre@38: connect(mPNGLabel, &ImageLabel::doubleClicked, this, &PNGPlayer::togglePicFullscreen); andre@38: connect(mPNGLabel, &ImageLabel::closeRequested, this, &PNGPlayer::togglePicFullscreen); andre@3: andre@3: QHBoxLayout *controlArea = new QHBoxLayout; andre@3: QHBoxLayout *controlBtns = new QHBoxLayout; andre@3: controlArea->addLayout(controlBtns); andre@10: controlArea->addStretch(-1); andre@3: andre@10: QPushButton *firstBtn = new QPushButton; andre@10: firstBtn->setIcon(QApplication::style()->standardIcon(QStyle::SP_MediaSkipBackward)); andre@3: controlBtns->addWidget(firstBtn); andre@3: connect(firstBtn, &QPushButton::clicked, this, &PNGPlayer::firstClicked); andre@3: andre@10: QPushButton *prevBtn = new QPushButton; andre@10: prevBtn->setIcon(QApplication::style()->standardIcon(QStyle::SP_MediaSeekBackward)); andre@3: controlBtns->addWidget(prevBtn); andre@3: connect(prevBtn, &QPushButton::clicked, this, &PNGPlayer::back); andre@3: andre@10: mPlayBtn = new QPushButton; andre@3: mPlayBtn->setCheckable(true); andre@10: mPlayBtn->setIcon(QApplication::style()->standardIcon(QStyle::SP_MediaPlay)); andre@3: controlBtns->addWidget(mPlayBtn); andre@3: connect(mPlayBtn, &QPushButton::clicked, this, &PNGPlayer::togglePlay); andre@3: andre@10: QPushButton *nextBtn = new QPushButton; andre@10: nextBtn->setIcon(QApplication::style()->standardIcon(QStyle::SP_MediaSeekForward)); andre@3: connect(nextBtn, &QPushButton::clicked, this, &PNGPlayer::advance); andre@3: controlBtns->addWidget(nextBtn); andre@3: andre@10: QPushButton *lastBtn = new QPushButton; andre@10: lastBtn->setIcon(QApplication::style()->standardIcon(QStyle::SP_MediaSkipForward)); andre@3: controlBtns->addWidget(lastBtn); andre@3: connect(lastBtn, &QPushButton::clicked, this, &PNGPlayer::lastClicked); andre@3: andre@3: mSlider = new QSlider(Qt::Horizontal); andre@3: mSlider->setTickPosition(QSlider::TicksBelow); andre@3: connect(mSlider, &QSlider::valueChanged, this, &PNGPlayer::sliderChanged); andre@3: connect(mSlider, &QSlider::sliderPressed, this, &PNGPlayer::sliderPressed); andre@3: connect(mSlider, &QSlider::sliderReleased, this, &PNGPlayer::sliderReleased); andre@3: andre@3: QVBoxLayout *speedInfoArea = new QVBoxLayout; andre@3: QHBoxLayout *speedArea = new QHBoxLayout; andre@3: speedInfoArea->addLayout(speedArea); andre@3: andre@3: QLabel *speedLabel = new QLabel(tr("Speed:")); andre@3: speedArea->addWidget(speedLabel); andre@3: andre@3: mSpeedSlider = new QSlider(Qt::Horizontal); andre@5: mSpeedSlider->setMaximum(10); andre@5: mSpeedSlider->setTickInterval(1); andre@3: mSpeedSlider->setTickPosition(QSlider::TicksBelow); andre@5: mSpeedSlider->setTracking(false); andre@5: mSpeedSlider->setInvertedAppearance(true); andre@43: mSpeedSlider->setSingleStep(1); andre@43: mSpeedSlider->setPageStep(1); andre@5: andre@3: speedArea->addWidget(mSpeedSlider); andre@5: connect(mSpeedSlider, &QSlider::valueChanged, this, &PNGPlayer::speedChanged); andre@3: andre@3: mCurSpeedLabel = new QLabel; andre@3: speedArea->addWidget(mCurSpeedLabel); andre@3: speedArea->addStretch(-1); andre@3: andre@3: mPositionLabel = new QLabel; andre@3: speedInfoArea->addWidget(mPositionLabel); andre@3: andre@3: controlArea->addLayout(speedInfoArea); andre@3: andre@2: baseLayout->addWidget(mPNGLabel); andre@3: baseLayout->addLayout(controlArea); andre@3: baseLayout->addWidget(mSlider); andre@3: andre@2: connect(&mAdvanceTimer, SIGNAL(timeout()), this, SIGNAL(advance())); andre@2: setLayout(baseLayout); andre@2: } andre@2: andre@3: void PNGPlayer::showPicture(const QString& fileName, int current, int max, andre@44: const QString& timestamp, int number) { andre@2: QPixmap pic(mBaseDir.filePath(fileName)); andre@2: /* If this is too slow we could use a pixmap cache here and do andre@2: * some intelligent preloading */ andre@2: if (pic.isNull()) { andre@20: qWarning() << "Failed to load picture: " << fileName; andre@7: // emit error(tr("Failed to load picture: '%1'").arg(fileName)); andre@37: QIcon errIcon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical); andre@37: mPNGLabel->setPixmap(errIcon.pixmap(QSize(128, 128))); andre@37: } else { andre@37: mPNGLabel->setPixmap(pic); andre@2: } andre@37: updatePositions(current, max, timestamp, number); andre@2: } andre@3: andre@44: void PNGPlayer::updatePositions(int current, int max, const QString& timestamp, andre@37: int number) { andre@3: mMax = max; andre@3: mSlider->blockSignals(true); /* We only want user generated changes */ andre@3: mSlider->setValue(current); andre@3: mSlider->blockSignals(false); andre@3: mSlider->setMaximum(max); andre@3: mPositionLabel->setText("" + tr("Screenshot Nr.:") + " " + andre@37: QString("%1 (%2)").arg(current + 1).arg(max + 1) + andre@44: "/ " + tr("Index Nr.:") + " " + QString::number(number) + " / " + andre@44: tr("Timestamp:") + " " + timestamp); andre@3: andre@3: if (mMax == current && mAdvanceTimer.isActive()) { andre@3: togglePlay(); andre@3: } andre@3: } andre@3: andre@3: void PNGPlayer::setSpeed(int mSecsPerPicture) { andre@3: if (mSecsPerPicture == 1000) { andre@3: mCurSpeedLabel->setText(tr("%1 second per Picture"). andre@5: arg(mSecsPerPicture / 1000.)); andre@3: } else { andre@3: mCurSpeedLabel->setText(tr("%1 seconds per Picture"). andre@5: arg(mSecsPerPicture / 1000.)); andre@3: } andre@3: mAdvanceTimer.setInterval(mSecsPerPicture); andre@3: } andre@3: andre@3: void PNGPlayer::togglePlay() { andre@3: if (mAdvanceTimer.isActive()) { andre@3: mAdvanceTimer.stop(); andre@3: mPlayBtn->setChecked(false); andre@10: mPlayBtn->setIcon(QApplication::style()->standardIcon(QStyle::SP_MediaPlay)); andre@3: } else { andre@3: mAdvanceTimer.start(); andre@3: mPlayBtn->setChecked(true); andre@10: mPlayBtn->setIcon(QApplication::style()->standardIcon(QStyle::SP_MediaPause)); andre@3: emit advance(); andre@3: } andre@3: } andre@3: andre@3: void PNGPlayer::sliderChanged() { andre@3: qDebug() << "Slider moved. "; andre@3: emit jumpToFrame(mSlider->value()); andre@3: } andre@3: andre@3: void PNGPlayer::sliderPressed() { andre@3: qDebug() << "Slider pressed. Deactivating timer. "; andre@3: mAdvanceTimer.stop(); andre@3: } andre@3: andre@3: void PNGPlayer::sliderReleased() { andre@3: if (mPlayBtn->isChecked()) { andre@3: mAdvanceTimer.start(); andre@3: } andre@3: } andre@3: andre@3: void PNGPlayer::firstClicked() { andre@3: emit jumpToFrame(0); andre@3: } andre@3: andre@3: void PNGPlayer::lastClicked() { andre@3: emit jumpToFrame(mMax); andre@3: } andre@5: andre@5: void PNGPlayer::speedChanged() { andre@5: if (mSpeedSlider->value()) { andre@5: setSpeed(mSpeedSlider->value() * REPLAY_SPEED_STEP_MS); andre@5: } else { andre@5: setSpeed(REPLAY_SPEED_STEP_MS / 2); andre@5: } andre@5: QSettings settings; andre@34: settings.setValue(REPLAY_SPEED_KEY, (mSpeedSlider->value() * REPLAY_SPEED_STEP_MS) / 1000.0); andre@5: } andre@38: andre@38: void PNGPlayer::togglePicFullscreen() { andre@44: QSettings settings; andre@44: bool enabled = settings.value(DETACHABLE_IMAGE_KEY, DETACHABLE_IMAGE_DEFAULT).toBool(); andre@44: settings.setValue(DETACHABLE_IMAGE_KEY, enabled); andre@44: andre@44: if (!enabled) { andre@44: return; andre@44: } andre@44: andre@38: QVBoxLayout *baseLayout = qobject_cast(layout()); andre@38: if (!baseLayout) { andre@38: qWarning() << "Wrong layout!"; andre@38: return; andre@38: } andre@38: if (baseLayout->indexOf(mPNGLabel) == -1) { andre@38: baseLayout->insertWidget(0, mPNGLabel); andre@38: } else { andre@38: baseLayout->removeWidget(mPNGLabel); andre@38: mPNGLabel->setParent(NULL, Qt::Tool); andre@38: mPNGLabel->showMaximized(); andre@38: } andre@38: } andre@38: andre@38: void PNGPlayer::close() { andre@38: QVBoxLayout *baseLayout = qobject_cast(layout()); andre@38: if (!baseLayout) { andre@38: qWarning() << "Wrong layout!"; andre@38: return; andre@38: } andre@38: if (baseLayout->indexOf(mPNGLabel) == -1) { andre@38: delete mPNGLabel; andre@38: } andre@38: }