You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lxqt-config-packaging/lxqt-config-monitor/monitorwidget.cpp

348 lines
11 KiB

/*
Copyright (C) 2014 P.L. Lucas <selairi@gmail.com>
Copyright (C) 2014 Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
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) 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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "monitorwidget.h"
#include "monitor.h"
#include <QComboBox>
#include <QStringBuilder>
#include <QDialogButtonBox>
#include <KScreen/EDID>
QString modeToString(KScreen::ModePtr mode)
{
// mode->name() can be anything, not just widthxheight. eg if added with cvt.
return QString("%1x%2").arg(mode->size().width()).arg(mode->size().height());
}
KScreen::OutputPtr getOutputById(int id, KScreen::OutputList outputs)
{
for (const KScreen::OutputPtr &output : outputs)
if (output->id() == id)
return output;
return KScreen::OutputPtr(nullptr);
}
KScreen::ModePtr getModeById(QString id, KScreen::ModeList modes)
{
for (const KScreen::ModePtr &mode : modes)
if (mode->id() == id)
return mode;
return KScreen::ModePtr(NULL);
}
static bool sizeBiggerThan(const KScreen::ModePtr &modeA, const KScreen::ModePtr &modeB)
{
QSize sizeA = modeA->size();
QSize sizeB = modeB->size();
return sizeA.width() * sizeA.height() > sizeB.width() * sizeB.height();
}
MonitorWidget::MonitorWidget(KScreen::OutputPtr output, KScreen::ConfigPtr config, QWidget* parent) :
QGroupBox(parent)
{
this->output = output;
this->config = config;
ui.setupUi(this);
ui.enabledCheckbox->setChecked(output->isEnabled());
QList <KScreen::ModePtr> modeList = output->modes().values();
// Remove duplicate sizes
QMap<QString, KScreen::ModePtr> noDuplicateModes;
foreach(const KScreen::ModePtr &mode, modeList)
{
if( noDuplicateModes.keys().contains(modeToString(mode)) )
{
KScreen::ModePtr actual = noDuplicateModes[modeToString(mode)];
bool isActualPreferred = output->preferredModes().contains(actual->id());
bool isModePreferred = output->preferredModes().contains(mode->id());
if( ( mode->refreshRate() > actual->refreshRate() && !isActualPreferred ) || isModePreferred )
noDuplicateModes[modeToString(mode)] = mode;
}
else
noDuplicateModes[modeToString(mode)] = mode;
}
// Sort modes by size
modeList = noDuplicateModes.values();
qSort(modeList.begin(), modeList.end(), sizeBiggerThan);
// Add each mode to the list
foreach (const KScreen::ModePtr &mode, modeList)
{
ui.resolutionCombo->addItem(modeToString(mode), mode->id());
if(output->preferredModes().contains(mode->id()))
{
// Make bold preferredModes
QFont font = ui.resolutionCombo->font();
font.setBold(true);
ui.resolutionCombo->setItemData(ui.resolutionCombo->count()-1, font, Qt::FontRole);
}
}
connect(ui.resolutionCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onResolutionChanged(int)));
// Select actual mode in list
if (output->currentMode())
{
// Set the current mode in dropdown
int idx = ui.resolutionCombo->findData(output->currentMode()->id());
if (idx < 0)
{
// Select mode with same size
foreach (const KScreen::ModePtr &mode, modeList)
{
if( mode->size() == output->currentMode()->size() )
idx = ui.resolutionCombo->findData(output->currentMode()->id());
}
}
if(idx < 0)
idx = ui.resolutionCombo->findData(output->preferredMode()->id());
if (idx >= 0)
ui.resolutionCombo->setCurrentIndex(idx);
}
updateRefreshRates();
// Update EDID information
// KScreen doesn't make much public but that's ok...
KScreen::Edid* edid = output->edid();
if (edid && edid->isValid())
{
ui.outputInfoLabel->setText(
tr("Name: %1\n").arg(edid->name()) %
tr("Vendor: %1\n").arg(edid->vendor()) %
tr("Serial: %1\n").arg(edid->serial()) %
tr("Display size: %1cm x %2cm\n").arg(edid->width()).arg(edid->height()) %
tr("Serial number: %1\n").arg(edid->serial()) %
tr("EISA device ID: %1\n").arg(edid->eisaId())
);
}
if (config->connectedOutputs().count() == 1)
{
setOnlyMonitor(true);
// There isn't always a primary output. Gross.
output->setPrimary(true);
}
else
{
for (const KScreen::OutputPtr &other : config->connectedOutputs())
{
// We can't clone ourselves, or an output that already clones another
if (other == output)
continue;
ui.clonesCombo->addItem(other->name(), other->id());
ui.relativeScreensCombo->addItem(other->name(), other->id());
}
connect(ui.clonesCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onCloneChanged(int)));
}
ui.xPosSpinBox->setValue(output->pos().x());
ui.yPosSpinBox->setValue(output->pos().y());
// Behavior chooser
if (output->isPrimary())
ui.behaviorCombo->setCurrentIndex(PrimaryDisplay);
else if (!output->clone())
{
// Is this right?
ui.behaviorCombo->setCurrentIndex(CloneDisplay);
int idx = ui.resolutionCombo->findData(output->clone()->id());
ui.clonesCombo->setCurrentIndex(idx);
}
else
ui.behaviorCombo->setCurrentIndex(ExtendDisplay);
// Insert orientations
ui.orientationCombo->addItem(tr("None"), KScreen::Output::None);
ui.orientationCombo->addItem(tr("Left"), KScreen::Output::Left);
ui.orientationCombo->addItem(tr("Right"), KScreen::Output::Right);
ui.orientationCombo->addItem(tr("Inverted"), KScreen::Output::Inverted);
switch(output->rotation())
{
case KScreen::Output::None:
ui.orientationCombo->setCurrentIndex(0);
break;
case KScreen::Output::Left:
ui.orientationCombo->setCurrentIndex(1);
break;
case KScreen::Output::Right:
ui.orientationCombo->setCurrentIndex(2);
break;
case KScreen::Output::Inverted:
ui.orientationCombo->setCurrentIndex(3);
break;
}
connect(ui.enabledCheckbox, SIGNAL(toggled(bool)), this, SLOT(onEnabledChanged(bool)));
connect(ui.behaviorCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onBehaviorChanged(int)));
connect(ui.positioningCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onPositioningChanged(int)));
connect(ui.xPosSpinBox, SIGNAL(valueChanged(int)), this, SLOT(onPositionChanged(int)));
connect(ui.yPosSpinBox, SIGNAL(valueChanged(int)), this, SLOT(onPositionChanged(int)));
connect(ui.orientationCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onOrientationChanged(int)));
// Force update behavior visibility
onBehaviorChanged(ui.behaviorCombo->currentIndex());
}
MonitorWidget::~MonitorWidget()
{
}
void MonitorWidget::onEnabledChanged(bool enabled)
{
output->setEnabled(enabled);
// If we're enabling a disabled output for the first time
if (enabled && !output->currentMode())
{
// order here matters
onResolutionChanged(ui.resolutionCombo->currentIndex());
onOrientationChanged(ui.orientationCombo->currentIndex());
onPositioningChanged(ui.positioningCombo->currentIndex());
onBehaviorChanged(ui.behaviorCombo->currentIndex());
}
}
void MonitorWidget::onOrientationChanged(int idx)
{
output->setRotation((KScreen::Output::Rotation) ui.orientationCombo->currentData().toInt(0));
}
void MonitorWidget::onBehaviorChanged(int idx)
{
// Behavior should match the index of the selected element
ui.positioningCombo->setVisible(idx == ExtendDisplay);
ui.clonesCombo->setVisible(idx == CloneDisplay);
ui.relativeScreensCombo->setVisible(idx == ExtendDisplay);
ui.xPosSpinBox->setVisible(idx == ExtendDisplay);
ui.yPosSpinBox->setVisible(idx == ExtendDisplay);
ui.relativeScreensCombo->setEnabled(true);
if(idx == CloneDisplay)
onCloneChanged(ui.clonesCombo->currentIndex());
output->setPrimary(idx == PrimaryDisplay);
}
void MonitorWidget::onCloneChanged(int idx)
{
KScreen::OutputPtr other = getOutputById(ui.clonesCombo->currentData().toInt(),
config->outputs());
output->setPos( other->pos() );
}
void MonitorWidget::onPositioningChanged(int idx)
{
// Update the x/y spinboxes with the correct values
KScreen::OutputPtr other = getOutputById(ui.relativeScreensCombo->currentData().toInt(),
config->outputs());
// TODO: Figure out what to do here
if (!other->currentMode() || !output->currentMode())
return;
QSize otherSize = other->currentMode()->size();
QSize thisSize = output->currentMode()->size();
int x = other->pos().x();
int y = other->pos().y();
switch (idx) {
case RightOf:
x += otherSize.width();
break;
case LeftOf:
x += thisSize.width();
break;
case Above:
y += otherSize.height();
break;
case Below:
y += thisSize.height();
break;
case Manually:
default:
break;
}
ui.xPosSpinBox->setValue(x);
ui.yPosSpinBox->setValue(y);
// Disable the other screens combo box if we don't need it
ui.relativeScreensCombo->setEnabled(idx && idx != Manually);
}
void MonitorWidget::onPositionChanged(int value)
{
output->setPos(QPoint(ui.xPosSpinBox->value(), ui.yPosSpinBox->value()));
}
void MonitorWidget::onResolutionChanged(int index)
{
output->setCurrentModeId(ui.resolutionCombo->currentData().toString());
updateRefreshRates();
}
void MonitorWidget::onRateChanged(int index)
{
output->setCurrentModeId(ui.rateCombo->currentData().toString());
}
void MonitorWidget::updateRefreshRates()
{
disconnect(ui.rateCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onRateChanged(int)));
ui.rateCombo->clear();
if (output->modes().size() < 0)
return;
KScreen::ModePtr selectedMode = output->currentMode();
if (selectedMode)
{
for (const KScreen::ModePtr &mode : output->modes())
if (mode->size() == selectedMode->size())
ui.rateCombo->addItem(tr("%1 Hz").arg(mode->refreshRate()), mode->id());
int idx = ui.rateCombo->findData(selectedMode->id());
if (idx >= 0)
ui.rateCombo->setCurrentIndex(idx);
}
connect(ui.rateCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onRateChanged(int)));
}
void MonitorWidget::setOnlyMonitor(bool isOnlyMonitor)
{
ui.enabledCheckbox->setEnabled(!isOnlyMonitor);
ui.behaviorCombo->setEnabled(!isOnlyMonitor);
ui.xPosSpinBox->setVisible(!isOnlyMonitor);
ui.yPosSpinBox->setVisible(!isOnlyMonitor);
ui.relativeScreensCombo->setVisible(!isOnlyMonitor);
ui.clonesCombo->setVisible(!isOnlyMonitor);
}