/****************************************************************************** QtAV Player Demo: this file is part of QtAV examples Copyright (C) 2012-2015 Wang Bin * This file is part of QtAV 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 . ******************************************************************************/ // scroll area code is from Xuno: https://github.com/Xuno/Xuno-QtAV/blob/master/examples/player/config/DecoderConfigPage.cpp #include "DecoderConfigPage.h" #include "common/Config.h" #include "PropertyEditor.h" #include #include #include #include #include #include #include #include #include #include #include using namespace QtAV; // shared static QVector sDecodersUi; static QVector sPriorityUi; QStringList idsToNames(QVector ids) { QStringList decs; foreach (int id, ids) { decs.append(QString::fromLatin1(VideoDecoder::name(id))); } return decs; } QVector idsFromNames(const QStringList& names) { QVector decs; foreach (QString name, names) { if (name.isEmpty()) continue; VideoDecoderId id = VideoDecoder::id(name.toLatin1().constData()); if (id == 0) continue; decs.append(id); } return decs; } using namespace QtAV; class DecoderConfigPage::DecoderItemWidget : public QFrame { Q_OBJECT public: DecoderItemWidget(QWidget* parent = 0) : QFrame(parent) { mpEditorWidget = 0; // why no frame? setFrameStyle(QFrame::Panel|QFrame::Raised); setLineWidth(2); mpEditor = new PropertyEditor(this); mSelected = false; QVBoxLayout *vb = new QVBoxLayout; setLayout(vb); QFrame *frame = new QFrame(); frame->setFrameShape(QFrame::HLine); vb->addWidget(frame); mpCheck = new QCheckBox(); QHBoxLayout *hb = new QHBoxLayout(); hb->addWidget(mpCheck); QToolButton *expandBtn = new QToolButton(); expandBtn->setText(QString::fromLatin1("+")); hb->addWidget(expandBtn); connect(expandBtn, SIGNAL(clicked()), SLOT(toggleEditorVisible())); mpDesc = new QLabel(); vb->addLayout(hb); vb->addWidget(mpDesc); connect(mpCheck, SIGNAL(pressed()), SLOT(checkPressed())); // no this->mousePressEvent connect(mpCheck, SIGNAL(toggled(bool)), this, SIGNAL(enableChanged())); } void buildUiFor(QObject *obj) { mpEditor->getProperties(obj); //mpEditor->set() QWidget *w = mpEditor->buildUi(obj); if (!w) return; mpEditorWidget = w; w->setEnabled(true); layout()->addWidget(w); w->setVisible(false); } QVariantHash getOptions() const { return mpEditor->exportAsHash(); } void select(bool s) { mSelected = s; update(); } void setChecked(bool c) { mpCheck->setChecked(c); } bool isChecked() const { return mpCheck->isChecked(); } void setName(const QString& name) { mpCheck->setText(name);} QString name() const { return mpCheck->text();} void setDescription(const QString& desc) { mpDesc->setText(desc); } QString description() const { return mpDesc->text();} signals: void enableChanged(); void selected(DecoderItemWidget*); private slots: void checkPressed() { select(true); emit selected(this); } void toggleEditorVisible() { if (!mpEditorWidget) return; mpEditorWidget->setVisible(!mpEditorWidget->isVisible()); QToolButton *b = qobject_cast(sender()); if (b) { b->setText(mpEditorWidget->isVisible()?QString::fromLatin1("-"):QString::fromLatin1("+")); } parentWidget()->adjustSize(); } protected: virtual void mousePressEvent(QMouseEvent *) { select(true); emit selected(this); } virtual void paintEvent(QPaintEvent *e) { if (mSelected) { QPainter p(this); p.fillRect(rect(), QColor(0, 100, 200, 100)); } QWidget::paintEvent(e); } private: bool mSelected; QCheckBox *mpCheck; QLabel *mpDesc; PropertyEditor *mpEditor; QWidget *mpEditorWidget; }; DecoderConfigPage::DecoderConfigPage(QWidget *parent) : ConfigPageBase(parent) { mpSelectedDec = 0; setWindowTitle(tr("Video decoder config page")); QVBoxLayout *vbs = new QVBoxLayout(this); QSpacerItem *horizontalSpacer = new QSpacerItem(320, 0, QSizePolicy::Minimum, QSizePolicy::Minimum); vbs->addItem(horizontalSpacer); QScrollArea *scrollArea = new QScrollArea(this); scrollArea->setWidgetResizable(true); QWidget *scrollAreaWidgetContents = new QWidget(this); QVBoxLayout *vlsroll = new QVBoxLayout(scrollAreaWidgetContents); vlsroll->setSpacing(0); QVBoxLayout *vb = new QVBoxLayout; vb->setSpacing(0); vb->addWidget(new QLabel(QString::fromLatin1("%1 %2 (%3)").arg(tr("Decoder")).arg(tr("Priorities")).arg(tr("reopen is required")))); sPriorityUi = idsFromNames(Config::instance().decoderPriorityNames()); QStringList vds = Config::instance().decoderPriorityNames(); QVector vids = idsFromNames(vds); QVector vds_all = VideoDecoder::registered(); QVector all = vids; foreach (QtAV::VideoDecoderId vid, vds_all) { if (!vids.contains(vid)) all.push_back(vid); } mpDecLayout = new QVBoxLayout; foreach (QtAV::VideoDecoderId vid, all) { VideoDecoder *vd = VideoDecoder::create(vid); DecoderItemWidget *iw = new DecoderItemWidget(scrollAreaWidgetContents); iw->buildUiFor(vd); mDecItems.append(iw); iw->setName(vd->name()); iw->setDescription(vd->description()); iw->setChecked(vids.contains(vid)); connect(iw, SIGNAL(enableChanged()), SLOT(videoDecoderEnableChanged())); connect(iw, SIGNAL(selected(DecoderItemWidget*)), SLOT(onDecSelected(DecoderItemWidget*))); mpDecLayout->addWidget(iw); delete vd; }/* for (int i = 0; i < vds_all.size(); ++i) { VideoDecoder *vd = VideoDecoder::create(vds_all.at(i)); DecoderItemWidget *iw = new DecoderItemWidget(); iw->buildUiFor(vd); mDecItems.append(iw); iw->setName(vd->name()); iw->setDescription(vd->description()); iw->setChecked(vds.contains(vd->name())); connect(iw, SIGNAL(enableChanged()), SLOT(videoDecoderEnableChanged())); connect(iw, SIGNAL(selected(DecoderItemWidget*)), SLOT(onDecSelected(DecoderItemWidget*))); mpDecLayout->addWidget(iw); delete vd; }*/ vb->addLayout(mpDecLayout); vb->addSpacerItem(new QSpacerItem(width(), 10, QSizePolicy::Ignored, QSizePolicy::Expanding)); mpUp = new QToolButton(scrollAreaWidgetContents); mpUp->setText(tr("Up")); connect(mpUp, SIGNAL(clicked()), SLOT(priorityUp())); mpDown = new QToolButton(scrollAreaWidgetContents); mpDown->setText(tr("Down")); connect(mpDown, SIGNAL(clicked()), SLOT(priorityDown())); QHBoxLayout *hb = new QHBoxLayout; hb->addWidget(mpUp); hb->addWidget(mpDown); vb->addLayout(hb); vb->addSpacerItem(new QSpacerItem(width(), 10, QSizePolicy::Ignored, QSizePolicy::Expanding)); vlsroll->addLayout(vb); scrollArea->setWidget(scrollAreaWidgetContents); vbs->addWidget(scrollArea); connect(&Config::instance(), SIGNAL(decoderPriorityNamesChanged()), SLOT(onConfigChanged())); applyToUi(); } QString DecoderConfigPage::name() const { return tr("Decoder"); } QVariantHash DecoderConfigPage::audioDecoderOptions() const { return QVariantHash(); } QVariantHash DecoderConfigPage::videoDecoderOptions() const { QVariantHash options; foreach (DecoderItemWidget* diw, mDecItems) { options[diw->name()] = diw->getOptions(); } return options; } void DecoderConfigPage::applyFromUi() { QStringList decs_all; QStringList decs; foreach (DecoderItemWidget *w, mDecItems) { decs_all.append(w->name()); if (w->isChecked()) decs.append(w->name()); } sPriorityUi = idsFromNames(decs); Config::instance().setDecoderPriorityNames(decs); } void DecoderConfigPage::applyToUi() { updateDecodersUi(); } void DecoderConfigPage::videoDecoderEnableChanged() { QStringList names; foreach (DecoderItemWidget *iw, mDecItems) { if (iw->isChecked()) names.append(iw->name()); } sPriorityUi = idsFromNames(names); if (applyOnUiChange()) { Config::instance().setDecoderPriorityNames(names); } else { // emit Config::instance().decoderPriorityChanged(sPriorityUi); } } void DecoderConfigPage::priorityUp() { if (!mpSelectedDec) return; int i = mDecItems.indexOf(mpSelectedDec); if (i == 0) return; DecoderItemWidget *iw = mDecItems.takeAt(i-1); mDecItems.insert(i, iw); mpDecLayout->removeWidget(iw); mpDecLayout->insertWidget(i, iw); QStringList decs_all; QStringList decs_p = Config::instance().decoderPriorityNames(); QStringList decs; foreach (DecoderItemWidget *w, mDecItems) { decs_all.append(w->name()); if (decs_p.contains(w->name())) decs.append(w->name()); } sDecodersUi = idsFromNames(decs_all); sPriorityUi = idsFromNames(decs); if (applyOnUiChange()) { Config::instance().setDecoderPriorityNames(decs); } else { //emit Config::instance().decoderPriorityChanged(idsFromNames(decs)); } } void DecoderConfigPage::priorityDown() { if (!mpSelectedDec) return; int i = mDecItems.indexOf(mpSelectedDec); if (i == mDecItems.size()-1) return; DecoderItemWidget *iw = mDecItems.takeAt(i+1); mDecItems.insert(i, iw); // why takeItemAt then insertItem does not work? mpDecLayout->removeWidget(iw); mpDecLayout->insertWidget(i, iw); QStringList decs_all; QStringList decs_p = Config::instance().decoderPriorityNames(); QStringList decs; foreach (DecoderItemWidget *w, mDecItems) { decs_all.append(w->name()); if (decs_p.contains(w->name())) decs.append(w->name()); } sDecodersUi = idsFromNames(decs_all); sPriorityUi = idsFromNames(decs); if (applyOnUiChange()) { Config::instance().setDecoderPriorityNames(decs); } else { //emit Config::instance().decoderPriorityChanged(idsFromNames(decs)); //emit Config::instance().registeredDecodersChanged(idsFromNames(decs)); } } void DecoderConfigPage::onDecSelected(DecoderItemWidget *iw) { if (mpSelectedDec == iw) return; if (mpSelectedDec) { mpSelectedDec->select(false); } mpSelectedDec = iw; } void DecoderConfigPage::updateDecodersUi() { QStringList names = idsToNames(sPriorityUi); QStringList all_names = idsToNames(sDecodersUi); //qDebug() << "updateDecodersUi " << this << " " << names << " all: " << all_names; int idx = 0; foreach (const QString& name, all_names) { DecoderItemWidget * iw = 0; for (int i = idx; i < mDecItems.size(); ++i) { if (mDecItems.at(i)->name() != name) continue; iw = mDecItems.at(i); break; } if (!iw) break; iw->setChecked(names.contains(iw->name())); int i = mDecItems.indexOf(iw); if (i != idx) { mDecItems.removeAll(iw); mDecItems.insert(idx, iw); } // why takeItemAt then insertItem does not work? if (mpDecLayout->indexOf(iw) != idx) { mpDecLayout->removeWidget(iw); mpDecLayout->insertWidget(idx, iw); } ++idx; } } void DecoderConfigPage::onConfigChanged() { sPriorityUi = idsFromNames(Config::instance().decoderPriorityNames()); sDecodersUi = VideoDecoder::registered(); updateDecodersUi(); } #include "DecoderConfigPage.moc"