diff --git a/kcm/src/CMakeLists.txt b/kcm/src/CMakeLists.txt index 1edf523..6d4f91b 100644 --- a/kcm/src/CMakeLists.txt +++ b/kcm/src/CMakeLists.txt @@ -1,51 +1,50 @@ add_definitions(-DTRANSLATION_DOMAIN=\"kcm_displayconfiguration\") include_directories("${CMAKE_CURRENT_SOURCE_DIR}/declarative") set(kcm_kscreen_SRCS declarative/qmloutput.cpp declarative/qmloutputcomponent.cpp declarative/qmlscreen.cpp - collapsablebutton.cpp controlpanel.cpp outputconfig.cpp unifiedoutputconfig.cpp resolutionslider.cpp utils.cpp widget.cpp previewwidget.cpp scalingconfig.cpp ) ecm_qt_declare_logging_category(kcm_kscreen_SRCS HEADER kcm_screen_debug.h IDENTIFIER KSCREEN_KCM CATEGORY_NAME kscreen.kcm) ki18n_wrap_ui(kcm_kscreen_SRCS kscreen_widget.ui stylepreview.ui scaling.ui) add_library(kcm_kscreen MODULE kcm_kscreen.cpp ${kcm_kscreen_SRCS}) target_link_libraries(kcm_kscreen Qt5::QuickWidgets Qt5::Widgets KF5::Screen KF5::I18n KF5::ConfigCore KF5::ConfigWidgets KF5::WidgetsAddons ) install(TARGETS kcm_kscreen DESTINATION ${KDE_INSTALL_PLUGINDIR} ) add_executable(kcm_testapp kcm_testapp.cpp ${kcm_kscreen_SRCS}) set_target_properties(kcm_testapp PROPERTIES COMPILE_FLAGS "-DQT_DECLARATIVE_DEBUG") target_link_libraries(kcm_testapp Qt5::QuickWidgets Qt5::Widgets KF5::CoreAddons KF5::I18n KF5::ConfigCore KF5::Screen KF5::WidgetsAddons ) diff --git a/kcm/src/collapsablebutton.cpp b/kcm/src/collapsablebutton.cpp deleted file mode 100644 index f4a3b2b..0000000 --- a/kcm/src/collapsablebutton.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2013 Daniel Vrátil - * - * 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 2 of - * the License or (at your option) version 3 or any later version - * accepted by the membership of KDE e.V. (or its successor approved - * by the membership of KDE e.V.), which shall act as a proxy - * defined in Section 14 of version 3 of the license. - * - * 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 . - * - */ - -#include "collapsablebutton.h" - -#include -#include -#include -#include -#include - -CollapsableButton::CollapsableButton(const QString &text, QWidget *parent) - : QWidget(parent) - , mCollapsed(false) - , mWidget(nullptr) -{ - QHBoxLayout *layout = new QHBoxLayout(this); - mLabel = new QLabel(text, this); - layout->addWidget(mLabel); - QFont f = mLabel->font(); - f.setBold(true); - mLabel->setFont(f); - - mLabel->setIndent(20); -} - -CollapsableButton::~CollapsableButton() -{ -} - -void CollapsableButton::mouseReleaseEvent(QMouseEvent *ev) -{ - if (ev->button() == Qt::LeftButton) { - toggle(); - Q_EMIT toggled(); - } - - QWidget::mouseReleaseEvent(ev); -} - -void CollapsableButton::paintEvent(QPaintEvent *ev) -{ - QPainter painter(this); - - QStyleOption opt; - const int h = 20; - opt.rect = QRect(0, (height() - h) / 2, h, h); - opt.palette = palette(); - QStyle::PrimitiveElement pe = mCollapsed ? QStyle::PE_IndicatorArrowRight : QStyle::PE_IndicatorArrowDown; - - style()->drawPrimitive(pe, &opt, &painter); - painter.end(); - - QWidget::paintEvent(ev); -} - -bool CollapsableButton::isCollapsed() const -{ - return mCollapsed; -} - -void CollapsableButton::setCollapsed(bool collapsed) -{ - if (mCollapsed == collapsed) { - return; - } - - mCollapsed = collapsed; - if (mWidget) { - mWidget->setHidden(collapsed); - } - - update(); -} - -QLabel* CollapsableButton::label() const -{ - return mLabel; -} - -void CollapsableButton::setWidget(QWidget *widget) -{ - mWidget = widget; - if (mWidget) { - mWidget->setHidden(isCollapsed()); - } -} - -QWidget *CollapsableButton::widget() const -{ - return mWidget; -} - -void CollapsableButton::toggle() -{ - setCollapsed(!isCollapsed()); - Q_EMIT toggled(); -} diff --git a/kcm/src/collapsablebutton.h b/kcm/src/collapsablebutton.h deleted file mode 100644 index 63653c7..0000000 --- a/kcm/src/collapsablebutton.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2013 Daniel Vrátil - * - * 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 2 of - * the License or (at your option) version 3 or any later version - * accepted by the membership of KDE e.V. (or its successor approved - * by the membership of KDE e.V.), which shall act as a proxy - * defined in Section 14 of version 3 of the license. - * - * 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 . - * - */ - -#ifndef COLLAPSABLE_BUTTON_H -#define COLLAPSABLE_BUTTON_H - -#include - -class CollapsableButton : public QWidget -{ - Q_OBJECT - - public: - explicit CollapsableButton(const QString &text, QWidget *parent = nullptr); - ~CollapsableButton() override; - - void setCollapsed(bool collapsed); - bool isCollapsed() const; - - void setWidget(QWidget *widget); - QWidget* widget() const; - - QLabel* label() const; - - public Q_SLOTS: - void toggle(); - - Q_SIGNALS: - void toggled(); - - protected: - void paintEvent(QPaintEvent *ev) override; - void mouseReleaseEvent(QMouseEvent *ev) override; - - private: - bool mCollapsed; - QLabel *mLabel; - QWidget *mWidget; -}; - -#endif // COLLAPSABLE_BUTTON_H diff --git a/kcm/src/outputconfig.cpp b/kcm/src/outputconfig.cpp index 6d29336..a3bf86c 100644 --- a/kcm/src/outputconfig.cpp +++ b/kcm/src/outputconfig.cpp @@ -1,261 +1,246 @@ /* * Copyright 2013 Daniel Vrátil * * 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 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * 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 . * */ #include "outputconfig.h" #include "resolutionslider.h" -#include "collapsablebutton.h" #include "utils.h" #include "kcm_screen_debug.h" #include #include #include #include #include #include #include #include #include #include #include #include OutputConfig::OutputConfig(QWidget *parent) : QWidget(parent) , mOutput(nullptr) { } OutputConfig::OutputConfig(const KScreen::OutputPtr &output, QWidget *parent) : QWidget(parent) { setOutput(output); } OutputConfig::~OutputConfig() { } void OutputConfig::setTitle(const QString& title) { mTitle->setText(title); } void OutputConfig::initUi() { connect(mOutput.data(), &KScreen::Output::isConnectedChanged, this, [=]() { if (!mOutput->isConnected()) { setVisible(false); } }); connect(mOutput.data(), &KScreen::Output::isEnabledChanged, this, [=]() { mEnabled->setChecked(mOutput->isEnabled()); }); connect(mOutput.data(), &KScreen::Output::rotationChanged, this, [=]() { const int index = mRotation->findData(mOutput->rotation()); mRotation->setCurrentIndex(index); }); connect(mOutput.data(), &KScreen::Output::scaleChanged, this, [=]() { const int index = mScale->findData(mOutput->scale()); mScale->setCurrentIndex(index); }); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); QVBoxLayout *vbox = new QVBoxLayout(this); mTitle = new QLabel(this); mTitle->setAlignment(Qt::AlignHCenter); vbox->addWidget(mTitle); setTitle(Utils::outputName(mOutput)); QFormLayout *formLayout = new QFormLayout(); vbox->addLayout(formLayout); mEnabled = new QCheckBox(i18n("Enabled"), this); mEnabled->setChecked(mOutput->isEnabled()); connect(mEnabled, &QCheckBox::clicked, this, [=](bool checked) { mOutput->setEnabled(checked); qCDebug(KSCREEN_KCM) << mOutput.data() << mOutput->name() << mOutput->isEnabled(); Q_EMIT changed(); }); formLayout->addRow(i18n("Display:"), mEnabled); mResolution = new ResolutionSlider(mOutput, this); connect(mResolution, &ResolutionSlider::resolutionChanged, this, &OutputConfig::slotResolutionChanged); formLayout->addRow(i18n("Resolution:"), mResolution); mRotation = new QComboBox(this); mRotation->addItem(QIcon::fromTheme(QStringLiteral("arrow-up")), i18n("Normal"), KScreen::Output::None); mRotation->addItem(QIcon::fromTheme(QStringLiteral("arrow-right")), i18n("90° Clockwise"), KScreen::Output::Right); mRotation->addItem(QIcon::fromTheme(QStringLiteral("arrow-down")), i18n("Upside Down"), KScreen::Output::Inverted); mRotation->addItem(QIcon::fromTheme(QStringLiteral("arrow-left")), i18n("90° Counterclockwise"), KScreen::Output::Left); connect(mRotation, static_cast(&QComboBox::activated), this, &OutputConfig::slotRotationChanged); mRotation->setCurrentIndex(mRotation->findData(mOutput->rotation())); formLayout->addRow(i18n("Orientation:"), mRotation); if (mShowScaleOption) { mScale = new QComboBox(this); mScale->addItem(i18nc("Scale multiplier, show everything at 1 times normal scale", "1x"), 1); mScale->addItem(i18nc("Scale multiplier, show everything at 2 times normal scale", "2x"), 2); connect(mScale, static_cast(&QComboBox::activated), this, &OutputConfig::slotScaleChanged); mScale->setCurrentIndex(mScale->findData(mOutput->scale())); formLayout->addRow(i18n("Scale:"), mScale); formLayout->addItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum)); } - CollapsableButton *advancedButton = new CollapsableButton(i18n("Advanced Settings"), this); - advancedButton->setCollapsed(true); - vbox->addWidget(advancedButton); - - QWidget *advancedWidget = new QWidget(this); - int leftMargin, topMargin, rightMargin, bottomMargin; - advancedWidget->getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin); - advancedWidget->setContentsMargins(25, topMargin, rightMargin, bottomMargin); - vbox->addWidget(advancedWidget); - advancedButton->setWidget(advancedWidget); - - formLayout = new QFormLayout(advancedWidget); - advancedWidget->setLayout(formLayout); - - mRefreshRate = new QComboBox(advancedWidget); + mRefreshRate = new QComboBox(this); mRefreshRate->addItem(i18n("Auto"), -1); formLayout->addRow(i18n("Refresh rate:"), mRefreshRate); slotResolutionChanged(mResolution->currentResolution()); connect(mRefreshRate, static_cast(&QComboBox::activated), this, &OutputConfig::slotRefreshRateChanged); } void OutputConfig::setOutput(const KScreen::OutputPtr &output) { mOutput = output; initUi(); } KScreen::OutputPtr OutputConfig::output() const { return mOutput; } void OutputConfig::slotResolutionChanged(const QSize &size) { // Ignore disconnected outputs if (!size.isValid()) { return; } KScreen::ModePtr selectedMode; QList modes; Q_FOREACH (const KScreen::ModePtr &mode, mOutput->modes()) { if (mode->size() == size) { modes << mode; if (!selectedMode || selectedMode->refreshRate() < mode->refreshRate()) { selectedMode = mode; } } } Q_ASSERT(selectedMode); mOutput->setCurrentModeId(selectedMode->id()); // Don't remove the first "Auto" item - prevents ugly flicker of the combobox // when changing resolution for (int i = 1; i < mRefreshRate->count(); ++i) { mRefreshRate->removeItem(i); } for (int i = 0, total = modes.count(); i < total; ++i) { const KScreen::ModePtr mode = modes.at(i); mRefreshRate->addItem(i18n("%1 Hz", QLocale().toString(mode->refreshRate(), 'f', 2)), mode->id()); // If selected refresh rate is other then what we consider the "Auto" value // - that is it's not the highest resolution - then select it, otherwise // we stick with "Auto" if (mode == selectedMode && i > 1) { // i + 1 since 0 is auto mRefreshRate->setCurrentIndex(i + 1); } } Q_EMIT changed(); } void OutputConfig::slotRotationChanged(int index) { KScreen::Output::Rotation rotation = static_cast(mRotation->itemData(index).toInt()); mOutput->setRotation(rotation); Q_EMIT changed(); } void OutputConfig::slotRefreshRateChanged(int index) { QString modeId; if (index == 0) { // Item 0 is "Auto" - "Auto" is equal to highest refresh rate (at least // that's how I understand it, and since the combobox is sorted in descending // order, we just pick the second item from top modeId = mRefreshRate->itemData(1).toString(); } else { modeId = mRefreshRate->itemData(index).toString(); } mOutput->setCurrentModeId(modeId); Q_EMIT changed(); } void OutputConfig::slotScaleChanged(int index) { auto scale = mScale->itemData(index).toInt(); mOutput->setScale(scale); Q_EMIT changed(); } void OutputConfig::setShowScaleOption(bool showScaleOption) { mShowScaleOption = showScaleOption; if (mOutput) { initUi(); } } bool OutputConfig::showScaleOption() const { return mShowScaleOption; } diff --git a/kcm/src/outputconfig.h b/kcm/src/outputconfig.h index bcea8b9..9017a71 100644 --- a/kcm/src/outputconfig.h +++ b/kcm/src/outputconfig.h @@ -1,76 +1,75 @@ /* * Copyright 2013 Daniel Vrátil * * 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 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * 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 . * */ #ifndef OUTPUTCONFIG_H #define OUTPUTCONFIG_H #include #include #include #include -class CollapsableButton; class QCheckBox; class ResolutionSlider; class QLabel; class OutputConfig : public QWidget { Q_OBJECT public: explicit OutputConfig(QWidget *parent); explicit OutputConfig(const KScreen::OutputPtr &output, QWidget *parent = nullptr); ~OutputConfig() override; virtual void setOutput(const KScreen::OutputPtr &output); KScreen::OutputPtr output() const; void setTitle(const QString &title); void setShowScaleOption(bool showScaleOption); bool showScaleOption() const; protected Q_SLOTS: void slotResolutionChanged(const QSize &size); void slotRotationChanged(int index); void slotRefreshRateChanged(int index); void slotScaleChanged(int index); Q_SIGNALS: void changed(); protected: virtual void initUi(); protected: QLabel *mTitle = nullptr; KScreen::OutputPtr mOutput; QCheckBox *mEnabled = nullptr; ResolutionSlider *mResolution = nullptr; QComboBox *mRotation = nullptr; QComboBox *mScale = nullptr; QComboBox *mRefreshRate = nullptr; bool mShowScaleOption = false; }; #endif // OUTPUTCONFIG_H diff --git a/kcm/src/unifiedoutputconfig.cpp b/kcm/src/unifiedoutputconfig.cpp index 4661fd5..63cb966 100644 --- a/kcm/src/unifiedoutputconfig.cpp +++ b/kcm/src/unifiedoutputconfig.cpp @@ -1,197 +1,197 @@ /* * Copyright 2013 Daniel Vrátil * * 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 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * 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 . * */ #include "unifiedoutputconfig.h" -#include "collapsablebutton.h" #include "resolutionslider.h" #include "utils.h" #include "kcm_screen_debug.h" #include #include #include +#include #include #include #include #include #include #include #include bool operator<(const QSize &s1, const QSize &s2) { return s1.width() * s1.height() < s2.width() * s2.height(); } template<> bool qMapLessThanKey(const QSize &s1, const QSize &s2) { return s1 < s2; } UnifiedOutputConfig::UnifiedOutputConfig(const KScreen::ConfigPtr &config, QWidget *parent) : OutputConfig(parent) , mConfig(config) { } UnifiedOutputConfig::~UnifiedOutputConfig() { } void UnifiedOutputConfig::setOutput(const KScreen::OutputPtr &output) { mOutput = output; mClones.clear(); mClones.reserve(mOutput->clones().count()); Q_FOREACH (int id, mOutput->clones()) { mClones << mConfig->output(id); } mClones << mOutput; OutputConfig::setOutput(output); } void UnifiedOutputConfig::initUi() { QVBoxLayout *vbox = new QVBoxLayout(this); mTitle = new QLabel(this); mTitle->setAlignment(Qt::AlignHCenter); vbox->addWidget(mTitle); setTitle(i18n("Unified Outputs")); QGridLayout *formLayout = new QGridLayout(); vbox->addLayout(formLayout); vbox->addStretch(2); KScreen::OutputPtr fakeOutput = createFakeOutput(); mResolution = new ResolutionSlider(fakeOutput, this); connect(mResolution, &ResolutionSlider::resolutionChanged, this, &UnifiedOutputConfig::slotResolutionChanged); formLayout->addWidget(new QLabel(i18n("Resolution:"), this), 1, 0); formLayout->addWidget(mResolution, 1, 1); slotResolutionChanged(mResolution->currentResolution()); mRotation = new QComboBox(this); connect(mRotation, static_cast(&QComboBox::currentIndexChanged), this, &UnifiedOutputConfig::slotRotationChanged); mRotation->addItem(QIcon::fromTheme(QStringLiteral("arrow-up")), i18n("Normal"), KScreen::Output::None); mRotation->addItem(QIcon::fromTheme(QStringLiteral("arrow-right")), i18n("90° Clockwise"), KScreen::Output::Right); mRotation->addItem(QIcon::fromTheme(QStringLiteral("arrow-down")), i18n("Upside Down"), KScreen::Output::Inverted); mRotation->addItem(QIcon::fromTheme(QStringLiteral("arrow-left")), i18n("90° Counterclockwise"), KScreen::Output::Left); formLayout->addWidget(new QLabel(i18n("Orientation:"), this), 2, 0); formLayout->addWidget(mRotation, 2, 1); formLayout->addItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum), 0, 2, 3, 1); } KScreen::OutputPtr UnifiedOutputConfig::createFakeOutput() { // Find set of common resolutions QMap commonSizes; Q_FOREACH (const KScreen::OutputPtr &clone, mClones) { QList processedSizes; Q_FOREACH (const KScreen::ModePtr &mode, clone->modes()) { // Make sure we don't count some modes multiple times because of different // refresh rates if (processedSizes.contains(mode->size())) { continue; } processedSizes << mode->size(); if (commonSizes.contains(mode->size())) { commonSizes[mode->size()]++; } else { commonSizes.insert(mode->size(), 1); } } } KScreen::OutputPtr fakeOutput(new KScreen::Output); // This will give us list of resolution that are shared by all outputs QList commonResults = commonSizes.keys(mClones.count()); // If there are no common resolution, fallback to smallest preferred mode if (commonResults.isEmpty()) { QSize smallestMode; Q_FOREACH (const KScreen::OutputPtr &clone, mClones) { qCDebug(KSCREEN_KCM) << smallestMode << clone->preferredMode()->size(); if (!smallestMode.isValid() || clone->preferredMode()->size() < smallestMode) { smallestMode = clone->preferredMode()->size(); } } commonResults << smallestMode; } qSort(commonResults); KScreen::ModeList modes; Q_FOREACH (const QSize &size, commonResults) { KScreen::ModePtr mode(new KScreen::Mode); mode->setSize(size); mode->setId(Utils::sizeToString(size)); mode->setName(mode->id()); modes.insert(mode->id(), mode); } fakeOutput->setModes(modes); fakeOutput->setCurrentModeId(Utils::sizeToString(commonResults.last())); return fakeOutput; } void UnifiedOutputConfig::slotResolutionChanged(const QSize &size) { // Ignore disconnected outputs if (!size.isValid()) { return; } Q_FOREACH (const KScreen::OutputPtr &clone, mClones) { const QString &id = findBestMode(clone, size); if (id.isEmpty()) { // FIXME: Error? return; } clone->setCurrentModeId(id); } Q_EMIT changed(); } QString UnifiedOutputConfig::findBestMode(const KScreen::OutputPtr &output, const QSize &size) { float refreshRate = 0; QString id; Q_FOREACH (const KScreen::ModePtr &mode, output->modes()) { if (mode->size() == size && mode->refreshRate() > refreshRate) { refreshRate = mode->refreshRate(); id = mode->id(); } } return id; }