diff options
author | Simon Rettberg | 2018-08-28 12:55:35 +0200 |
---|---|---|
committer | Simon Rettberg | 2018-08-28 12:55:35 +0200 |
commit | 74de0010bdf71e8f4cf7495c53853065b78462ec (patch) | |
tree | e13a637ef39cabfe364b325209164140f32bb11a /src | |
parent | Getting there, slowly (diff) | |
download | beamergui-74de0010bdf71e8f4cf7495c53853065b78462ec.tar.gz beamergui-74de0010bdf71e8f4cf7495c53853065b78462ec.tar.xz beamergui-74de0010bdf71e8f4cf7495c53853065b78462ec.zip |
UI improvements
Diffstat (limited to 'src')
-rw-r--r-- | src/i18n/de.ts | 33 | ||||
-rw-r--r-- | src/icons.qrc | 7 | ||||
-rw-r--r-- | src/icons/checkmark.svg | 93 | ||||
-rw-r--r-- | src/icons/projector_icon.svg | 65 | ||||
-rw-r--r-- | src/icons/screen_icon.svg | 44 | ||||
-rw-r--r-- | src/widget.cpp | 103 | ||||
-rw-r--r-- | src/widget.h | 4 | ||||
-rw-r--r-- | src/widget.ui | 77 | ||||
-rw-r--r-- | src/x.cpp | 73 |
9 files changed, 397 insertions, 102 deletions
diff --git a/src/i18n/de.ts b/src/i18n/de.ts index 6fbd9c4..a9ade8d 100644 --- a/src/i18n/de.ts +++ b/src/i18n/de.ts @@ -4,7 +4,7 @@ <context> <name>QCoreApplication</name> <message> - <location filename="../widget.cpp" line="171"/> + <location filename="../widget.cpp" line="152"/> <source>%1x%2</source> <translation type="unfinished"></translation> </message> @@ -12,7 +12,7 @@ <context> <name>TimeOutDialog</name> <message> - <location filename="../timeoutdialog.cpp" line="16"/> + <location filename="../timeoutdialog.cpp" line="17"/> <source>%v seconds</source> <translation type="unfinished"></translation> </message> @@ -20,65 +20,64 @@ <context> <name>Widget</name> <message> - <location filename="../widget.ui" line="29"/> + <location filename="../widget.ui" line="33"/> <source>Clone</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../widget.ui" line="35"/> + <location filename="../widget.ui" line="39"/> <source>In this mode, all connected outputs will display the same image. This is most useful if there is one monitor and one projector currently connected to the computer.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../widget.ui" line="58"/> + <location filename="../widget.ui" line="62"/> <source>Please select the mode you want to apply. The mode that has been detected as the potentially best mode is highlighted.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../widget.ui" line="86"/> - <location filename="../widget.ui" line="174"/> - <location filename="../widget.ui" line="211"/> + <location filename="../widget.ui" line="90"/> + <location filename="../widget.ui" line="210"/> + <location filename="../widget.ui" line="250"/> <source>Apply</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../widget.ui" line="102"/> - <location filename="../widget.cpp" line="141"/> + <location filename="../widget.ui" line="106"/> <source>Dual Screen</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../widget.ui" line="127"/> + <location filename="../widget.ui" line="147"/> <source><- Swap -></source> <translation type="unfinished"></translation> </message> <message> - <location filename="../widget.ui" line="184"/> + <location filename="../widget.ui" line="223"/> <source>Advanced Setup</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../widget.cpp" line="274"/> + <location filename="../widget.cpp" line="288"/> <source>(off)</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../widget.cpp" line="306"/> + <location filename="../widget.cpp" line="320"/> <source>Output</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../widget.cpp" line="307"/> + <location filename="../widget.cpp" line="321"/> <source>Position</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../widget.cpp" line="387"/> + <location filename="../widget.cpp" line="432"/> <source>Do you want to keep this resolution?</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../widget.cpp" line="388"/> + <location filename="../widget.cpp" line="433"/> <source>Keep</source> <translation type="unfinished"></translation> </message> diff --git a/src/icons.qrc b/src/icons.qrc new file mode 100644 index 0000000..3a700e5 --- /dev/null +++ b/src/icons.qrc @@ -0,0 +1,7 @@ +<RCC> + <qresource> + <file alias="projector">icons/projector_icon.svg</file> + <file alias="screen">icons/screen_icon.svg</file> + <file alias="check">icons/checkmark.svg</file> + </qresource> +</RCC> diff --git a/src/icons/checkmark.svg b/src/icons/checkmark.svg new file mode 100644 index 0000000..db50cb9 --- /dev/null +++ b/src/icons/checkmark.svg @@ -0,0 +1,93 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://web.resource.org/cc/" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="417.20389" + height="361.62466" + id="svg2" + sodipodi:version="0.32" + inkscape:version="0.45" + inkscape:export-filename="C:\Documents and Settings\Staff\Desktop\checkmark.png" + inkscape:export-xdpi="72.839996" + inkscape:export-ydpi="72.839996" + sodipodi:docname="checkmark.svg" + inkscape:output_extension="org.inkscape.output.svg.inkscape" + sodipodi:docbase="C:\Documents and Settings\Staff\Desktop\photos\SVG" + version="1.0" + sodipodi:modified="true"> + <defs + id="defs4" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="0.7" + inkscape:cx="427.74596" + inkscape:cy="114.40134" + inkscape:document-units="px" + inkscape:current-layer="layer1" + inkscape:window-width="1024" + inkscape:window-height="712" + inkscape:window-x="0" + inkscape:window-y="22" /> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-101.54091,-163.59563)"> + <path + style="fill:#5fd35f;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="M 508.74477,226.99015 C 459.42189,193.17234 436.08559,163.59563 436.08559,163.59563 C 344.99984,217.26626 248.26757,407.83719 248.26757,407.83719 C 202.93454,344.01939 157.35384,326.21932 157.35384,326.21932 C 136.86236,353.60112 101.54091,390.09316 101.54091,390.09316 C 183.924,412.28062 253.07323,493.70015 253.07323,493.70015 C 402.5571,259.01322 508.74477,226.99015 508.74477,226.99015 z " + id="path5075" + sodipodi:nodetypes="ccccccc" + inkscape:export-filename="C:\Documents and Settings\Staff\Desktop\photos\SVG\path2161.png" + inkscape:export-xdpi="72.839996" + inkscape:export-ydpi="72.839996" /> + <path + sodipodi:type="arc" + style="opacity:0.2;fill:#999999;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0" + id="path3131" + sodipodi:cx="238.57143" + sodipodi:cy="529.50507" + sodipodi:rx="64.285713" + sodipodi:ry="7.1428571" + d="M 302.03011,528.36301 A 64.285713,7.1428571 0 1 1 301.97855,528.32818" + sodipodi:start="6.1226078" + sodipodi:end="12.400852" + sodipodi:open="true" + transform="translate(8.5714285,-11.428571)" + inkscape:export-filename="C:\Documents and Settings\Staff\Desktop\photos\SVG\path2161.png" + inkscape:export-xdpi="72.839996" + inkscape:export-ydpi="72.839996" /> + <path + style="opacity:0.27777782;fill:#5fd35f;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="M 518.74479,227.27587 C 469.42191,193.45806 446.08561,163.88135 446.08561,163.88135 C 354.99986,217.55198 258.26759,408.12291 258.26759,408.12291 C 212.93456,344.30511 167.35386,326.50504 167.35386,326.50504 C 146.86238,353.88684 111.54093,390.37888 111.54093,390.37888 C 193.92402,412.56634 263.07325,493.98587 263.07325,493.98587 C 412.55712,259.29894 518.74479,227.27587 518.74479,227.27587 z " + id="path2161" + sodipodi:nodetypes="ccccccc" + inkscape:export-xdpi="72.839996" + inkscape:export-ydpi="72.839996" /> + </g> +</svg> diff --git a/src/icons/projector_icon.svg b/src/icons/projector_icon.svg new file mode 100644 index 0000000..a22f105 --- /dev/null +++ b/src/icons/projector_icon.svg @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 494.516 494.516" style="enable-background:new 0 0 494.516 494.516;" xml:space="preserve">
+<g>
+ <path d="M264.787,220.756c1.088,0,2.176-0.415,3.004-1.245l23.453-23.454c1.66-1.66,1.66-4.351,0-6.011
+ c-1.658-1.659-4.352-1.659-6.01,0l-23.453,23.454c-1.66,1.66-1.66,4.351,0,6.011C262.611,220.341,263.699,220.756,264.787,220.756z
+ "/>
+ <path d="M316.324,190.047l-54.543,54.544c-1.66,1.66-1.66,4.351,0,6.011c0.83,0.83,1.918,1.245,3.006,1.245
+ c1.088,0,2.176-0.415,3.004-1.245l54.543-54.544c1.66-1.66,1.66-4.351,0-6.011C320.674,188.388,317.982,188.388,316.324,190.047z"
+ />
+ <path d="M308.49,167.516c-39.314,0-71.301,31.985-71.301,71.299c0,39.315,31.986,71.3,71.301,71.3
+ c39.314,0,71.299-31.985,71.299-71.3C379.789,199.501,347.805,167.516,308.49,167.516z M308.49,301.615
+ c-34.629,0-62.801-28.172-62.801-62.8c0-34.627,28.172-62.799,62.801-62.799c34.627,0,62.799,28.172,62.799,62.799
+ C371.289,273.443,343.117,301.615,308.49,301.615z"/>
+ <path d="M421.185,151.672H352.9c-13.334-6.823-28.43-10.676-44.41-10.676c-15.979,0-31.076,3.853-44.41,10.676H73.33
+ C32.896,151.672,0,184.568,0,225.003v27.626c0,37.031,27.598,67.72,63.303,72.626v7.565c0,11.413,9.285,20.699,20.699,20.699
+ h16.447c11.414,0,20.699-9.286,20.699-20.699v-6.861H264.08c13.334,6.823,28.432,10.676,44.41,10.676h0.002
+ c15.979,0,31.074-3.853,44.41-10.676h20.465v6.861c0,11.413,9.285,20.699,20.699,20.699h16.447
+ c11.414,0,20.699-9.286,20.699-20.699v-7.565c35.705-4.906,63.303-35.595,63.303-72.626v-27.626
+ C494.516,184.568,461.621,151.672,421.185,151.672z M112.648,332.82c0,6.727-5.473,12.199-12.199,12.199H84.002
+ c-6.727,0-12.199-5.472-12.199-12.199v-6.9c0.51,0.01,1.016,0.039,1.527,0.039h39.318V332.82z M73.33,317.459
+ c-21.209,0-40.072-10.238-51.908-26.032h51.223c2.348,0,4.25-1.903,4.25-4.25c0-2.347-1.902-4.25-4.25-4.25H16.039
+ c-4.805-9.049-7.539-19.358-7.539-30.298v-9.564h188.621c2.348,0,4.25-1.903,4.25-4.25s-1.902-4.25-4.25-4.25H8.5v-9.562
+ c0-6.332,0.928-12.448,2.629-18.237h101.617c2.348,0,4.25-1.903,4.25-4.25s-1.902-4.25-4.25-4.25H14.293
+ c10.205-22.442,32.82-38.094,59.037-38.094h177.057c-24.076,17.836-39.717,46.446-39.717,78.643
+ c0,32.197,15.641,60.808,39.717,78.644H73.33z M308.49,328.135c-49.25,0-89.32-40.068-89.32-89.319
+ c0-49.251,40.07-89.319,89.32-89.319c49.252,0,89.32,40.068,89.32,89.319c0,49.251-40.068,89.319-89.318,89.319H308.49z
+ M422.713,332.82c0,6.727-5.473,12.199-12.199,12.199h-16.447c-6.727,0-12.199-5.472-12.199-12.199v-6.861h39.318
+ c0.512,0,1.018-0.028,1.527-0.039V332.82z M421.185,317.459h-54.592c24.078-17.836,39.717-46.446,39.717-78.644
+ c0-32.197-15.641-60.807-39.719-78.643h54.594c35.748,0,64.83,29.083,64.83,64.831v11.137h-21.688c-2.348,0-4.25,1.903-4.25,4.25
+ s1.902,4.25,4.25,4.25h21.688v7.989C486.016,288.376,456.934,317.459,421.185,317.459z"/>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>
diff --git a/src/icons/screen_icon.svg b/src/icons/screen_icon.svg new file mode 100644 index 0000000..f2ca511 --- /dev/null +++ b/src/icons/screen_icon.svg @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ width="612px" height="612px" viewBox="0 0 612 612" style="enable-background:new 0 0 612 612;" xml:space="preserve">
+<g>
+ <path d="M578.766,51.487v-0.895h-2.996H35.93h-2.996v0.895C15.272,52.701,2.095,66.753,0,83.808v3.002v355.724
+ c0,6.898,1.795,12.712,4.791,17.949c6.893,12.137,17.068,18.269,31.14,18.269h197.012v49.695h-37.425
+ c-9.281,0-16.467,7.218-16.467,16.48c0,9.262,7.186,16.479,16.467,16.479h220.666c9.281,0,16.768-7.218,16.768-16.479
+ c0-9.263-7.486-16.48-16.768-16.48h-37.425v-49.695H575.77c14.078,0,24.343-6.132,31.14-18.269
+ c3.085-5.493,5.091-11.37,5.091-17.949V86.811v-3.002C609.905,66.753,595.833,52.701,578.766,51.487z M578.766,86.811v355.724
+ c0,2.108-0.895,3.002-2.996,3.002H35.93c-2.095,0-2.996-0.894-2.996-3.002V86.811v-3.002h545.831V86.811z"/>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>
diff --git a/src/widget.cpp b/src/widget.cpp index 34684b5..d0f0312 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -66,10 +66,12 @@ static void addBoldListener(QComboBox *combo) Widget::Widget(QWidget *parent) : QWidget(parent), _ui(new Ui::Widget), - _popupCount(0) + _popupCount(0), + _iProjector(QIcon(":projector")), + _iScreen(QIcon(":screen")) { _ui->setupUi(this); - setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); + setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint); QTimer *top = new QTimer(this); connect(top, &QTimer::timeout, [=]() { // Move window to current screen @@ -136,29 +138,7 @@ Widget::~Widget() { void Widget::showEvent(QShowEvent *event) { QWidget::showEvent(event); - ScreenMode mode = ScreenSetup::inst()->getCurrentMode(); - if (ScreenSetup::inst()->getOutputCount() >= 2 || mode == ScreenMode::Dual) { - if (_ui->tabWidget->widget(1) != _ui->tabDual) { - _ui->tabWidget->insertTab(1, _ui->tabDual, tr("Dual Screen")); - } - } else { - if (_ui->tabWidget->widget(1) == _ui->tabDual) { - _ui->tabWidget->removeTab(1); - } - } - switch (mode) { - case ScreenMode::Single: - case ScreenMode::Clone: - _ui->tabWidget->setCurrentWidget(_ui->tabClone); - break; - case ScreenMode::Dual: - _ui->tabWidget->setCurrentWidget(_ui->tabDual); - break; - case ScreenMode::Advanced: - _ui->tabWidget->setCurrentWidget(_ui->tabAdvanced); - break; - } - initControls(); + initControls(true); } static void fillCombo(QComboBox *combo, const ResolutionVector &resolutions, const QSize &preselected, const QSize &preferred = QSize()) @@ -202,8 +182,38 @@ void Widget::comboBold(int index) } } -void Widget::initControls() +void Widget::initControls(bool jumpToTab) { + // + ScreenMode currentOpMode = ScreenSetup::inst()->getCurrentMode(); + _ui->tabWidget->setTabEnabled(1, CommandLine::testMode() || ScreenSetup::inst()->getOutputCount() == 2 || currentOpMode == ScreenMode::Dual); + QWidget *current = nullptr; + switch (currentOpMode) { + case ScreenMode::Single: + case ScreenMode::Clone: + current = _ui->tabClone; + break; + case ScreenMode::Dual: + current = _ui->tabDual; + break; + case ScreenMode::Advanced: + current = _ui->tabAdvanced; + break; + } + if (current != nullptr) { + if (jumpToTab) { + _ui->tabWidget->setCurrentWidget(current); + } + for (int i = 0; i < _ui->tabWidget->count(); ++i) { + auto w = _ui->tabWidget->widget(i); + if (w == current) { + _ui->tabWidget->setTabIcon(i, QIcon(":check")); + } else { + _ui->tabWidget->setTabIcon(i, QIcon()); + } + } + } + // if (_ui->btnDualSwap->isChecked()) { _ui->btnDualSwap->toggle(); } @@ -228,7 +238,7 @@ void Widget::initControls() int j = 0; for (int i = 0; i < screenList.size() && j < 2; ++i) { QSize selected; - if (ScreenSetup::inst()->getCurrentMode() == ScreenMode::Dual) { + if (currentOpMode == ScreenMode::Dual) { // When we're not in dualhead mode, pre-select the preferred solution, so in case the user wants // to switch to dualhead, they just need to switch to the "dual" tab and hit apply to get // each screen configured to its preferred resolution. @@ -236,8 +246,11 @@ void Widget::initControls() } fillCombo(lists[j], screenList[i].modes, selected, screenList[i].preferredResolution); lists[j]->setProperty("output", screenList[i].output); - QLabel *sl = ( j == 0 ? _ui->lblDualLeft : _ui->lblDualRight ); - sl->setText(screenList[i].output + "\n" + screenList[i].name); + QWidget *sl = ( j == 0 ? _ui->wDualLeft : _ui->wDualRight ); + const QIcon &icon = screenList[i].isProjector ? _iProjector : _iScreen; + auto labels = sl->findChildren<QLabel*>(); + labels[0]->setPixmap(icon.pixmap(QSize(32, 32))); + labels[1]->setText(screenList[i].output + "\n" + screenList[i].name); if (screenList[i].currentResolution.isEmpty()) continue; ++j; @@ -304,22 +317,27 @@ void Widget::initControls() }); } // Header - _ui->advancedCombos->addWidget(new QLabel(tr("Output")), 0, 0); - _ui->advancedCombos->addWidget(new QLabel(tr("Position")), 0, 2); + _ui->advancedCombos->addWidget(new QLabel(tr("Output")), 0, 0, 1, 2); + _ui->advancedCombos->addWidget(new QLabel(tr("Position")), 0, 3); // List int row = 1; for (auto it = screenMap.begin(); it != screenMap.end(); ++it) { + int col = 0; AdvancedOutput *a = new AdvancedOutput(it.value()); a->assignmentLabel = new QLabel(it.key(), this); a->assignmentLabel->hide(); a->rowLabel = new QLabel(it.key()); - _ui->advancedCombos->addWidget(a->rowLabel, row, 0); - _ui->advancedCombos->addWidget(new QLabel(a->info.name), row, 1); + auto ico = new QLabel(); + const QIcon &icon = (a->info.isProjector ? _iProjector : _iScreen); + auto h = a->assignmentLabel->fontMetrics().height(); + ico->setPixmap(icon.pixmap(QSize(h + 3, h))); + _ui->advancedCombos->addWidget(ico, row, col++); + _ui->advancedCombos->addWidget(a->rowLabel, row, col++); + _ui->advancedCombos->addWidget(new QLabel(a->info.name), row, col++); QComboBox *cbo = new QComboBox(); a->cboPosition = cbo; - cbo->setProperty("output", QVariant::fromValue(a)); - _ui->advancedCombos->addWidget(cbo, row, 2); - _ui->advancedCombos->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum), row, 3); + _ui->advancedCombos->addWidget(cbo, row, col++); + _ui->advancedCombos->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum), row, col++); _advancedOutput.append(a); row++; // Logic @@ -327,9 +345,6 @@ void Widget::initControls() // TODO Signal connect(cbo, QOverload<int>::of(&QComboBox::currentIndexChanged), [a, this](int index) { a->info.position = index - 1; - if (a->assignmentLabel->layout() != nullptr) { - a->assignmentLabel->layout()->removeWidget(a->cboPosition); - } if (index > 0) { _advancedScreens[index - 1]->screen->layout()->addWidget(a->assignmentLabel); a->assignmentLabel->show(); @@ -377,6 +392,14 @@ void Widget::initControls() }); cbo->setCurrentIndex(a->info.position + 1); } + // Apply Spacing + QLayoutItem *control; + int i = 0; + while ((control = _ui->advancedCombos->itemAt(i++)) != nullptr) { + if (control->widget() != nullptr) { + control->widget()->setStyleSheet(".QLabel {padding: 1px 7px;}"); + } + } } bool Widget::keepResolution() @@ -484,7 +507,7 @@ void Widget::connectButtons() { int index = e->cboPosition->currentIndex() - 1; if (index < 0 || index >= list.size()) continue; - list[index].second.append(e->cboPosition->property("output").toString()); + list[index].second.append(e->info.output); } if (!ScreenSetup::inst()->setCustom(list) || !keepResolution()) { qDebug() << "reverting custom"; diff --git a/src/widget.h b/src/widget.h index 4e3c932..f784ce9 100644 --- a/src/widget.h +++ b/src/widget.h @@ -3,6 +3,7 @@ #include <QWidget> // for Qt5 #include <QDebug> +#include <QIcon> namespace Ui { class Widget; @@ -32,8 +33,9 @@ private: QVector<AdvancedOutput*> _advancedOutput; QList<const QScreen *> _qtScreens; bool _popupCount; + QIcon _iProjector, _iScreen; - void initControls(); + void initControls(bool jumpToTab = false); void connectButtons(); bool keepResolution(); }; diff --git a/src/widget.ui b/src/widget.ui index 5836a42..7a09c4c 100644 --- a/src/widget.ui +++ b/src/widget.ui @@ -16,13 +16,17 @@ <verstretch>0</verstretch> </sizepolicy> </property> + <property name="windowIcon"> + <iconset resource="icons.qrc"> + <normaloff>:/projector</normaloff>:/projector</iconset> + </property> <layout class="QHBoxLayout" name="horizontalLayout_2"> <item> <layout class="QHBoxLayout" name="horizontalLayout"> <item> <widget class="QTabWidget" name="tabWidget"> <property name="currentIndex"> - <number>1</number> + <number>2</number> </property> <widget class="QWidget" name="tabClone"> <attribute name="title"> @@ -93,7 +97,7 @@ </widget> <widget class="QWidget" name="tabDual"> <property name="styleSheet"> - <string notr="true">#lblDualLeft, #lblDualRight { + <string notr="true">#wDualLeft, #wDualRight { border-radius: 3px; border: 2px solid black; }</string> @@ -107,13 +111,29 @@ border: 2px solid black; <item> <layout class="QVBoxLayout" name="verticalLayout_2"> <item> - <widget class="QLabel" name="lblDualLeft"> - <property name="text"> - <string/> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> + <widget class="QWidget" name="wDualLeft" native="true"> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <item> + <widget class="QLabel" name="lblDualLeftIcon"> + <property name="text"> + <string notr="true"/> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="lblDualLeftText"> + <property name="text"> + <string notr="true"/> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + </layout> </widget> </item> <item> @@ -134,16 +154,32 @@ border: 2px solid black; <item> <layout class="QVBoxLayout" name="verticalLayout_3"> <item> - <widget class="QLabel" name="lblDualRight"> - <property name="text"> - <string/> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - <property name="margin"> + <widget class="QWidget" name="wDualRight" native="true"> + <property name="margin" stdset="0"> <number>0</number> </property> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <item> + <widget class="QLabel" name="lblDualRightIcon"> + <property name="text"> + <string notr="true"/> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="lblDualRightText"> + <property name="text"> + <string notr="true"/> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + </layout> </widget> </item> <item> @@ -180,6 +216,9 @@ border: 2px solid black; </layout> </widget> <widget class="QWidget" name="tabAdvanced"> + <property name="styleSheet"> + <string notr="true"/> + </property> <attribute name="title"> <string>Advanced Setup</string> </attribute> @@ -223,6 +262,8 @@ border: 2px solid black; </layout> </widget> <layoutdefault spacing="6" margin="11"/> - <resources/> + <resources> + <include location="icons.qrc"/> + </resources> <connections/> </ui> @@ -15,7 +15,7 @@ enum class Projector { struct OutputInfo { OutputInfo(RROutput id, XRROutputInfo *output, XRRCrtcInfo *crtc, XRRModeInfo *mode) - : output(output), crtc(crtc), mode(mode), id(id), position(-1), isProjector(Projector::No) {} + : output(output), crtc(crtc), mode(mode), id(id), position(-1), outputType(Projector::No) {} ~OutputInfo() { XRRFreeOutputInfo(output); } @@ -26,12 +26,12 @@ struct OutputInfo { QString modelName; QString outputName; int position; - Projector isProjector; + Projector outputType; }; ScreenInfo::ScreenInfo(const OutputInfo *oi, const ModeMap &om) : position(oi->position), name(oi->modelName), output(oi->outputName), - isProjector(oi->isProjector == Projector::Yes) + isProjector(oi->outputType == Projector::Yes) { if (oi->mode != nullptr) { currentResolution = QSize(QSize(int(oi->mode->width), int(oi->mode->height))); @@ -180,12 +180,15 @@ void ScreenSetup::updateScreenResources() } const QString outputName = QString::fromLocal8Bit(info->name, info->nameLen); tempMap.insert(_screenResources->outputs[i], outputName); - if (info->connection != RR_Connected) { + if (info->connection == RR_Disconnected) { qDebug() << "Ignoring disconnected output" << outputName; XRRFreeOutputInfo(info); continue; } + bool disconnected = false; if (info->crtc == None) { + disconnected = true; + qDebug() << "Connected output" << outputName << "has no CRTC -- trying to find free one"; info->crtc = getFreeCrtc(info); } if (!_crtcMap.contains(info->crtc)) { @@ -195,23 +198,25 @@ void ScreenSetup::updateScreenResources() } XRRCrtcInfo *crtc = _crtcMap.value(info->crtc); XRRModeInfo *mode = nullptr; - if (!_modeMap.contains(crtc->mode)) { - qDebug() << "Have output" << outputName << " with crtc with no known mode -- offline?"; - } else { - mode = _modeMap.value(crtc->mode); + if (!disconnected) { + if (!_modeMap.contains(crtc->mode)) { + qDebug() << "Have output" << outputName << " with crtc with no known mode -- offline?"; + } else { + mode = _modeMap.value(crtc->mode); + } } OutputInfo *oi = new OutputInfo(_screenResources->outputs[i], info, crtc, mode); oi->outputName = outputName; if (!this->readEdid(oi)) { // We have no EDID - take it as an indicator that there's a dumb output split/switch box - oi->isProjector = Projector::Maybe; + oi->outputType = Projector::Maybe; } else if ((info->mm_height == 0 && info->mm_width == 0) || isProjectorName(oi->modelName)) { - oi->isProjector = Projector::Yes; // Screens with size 0x0 are projectors by convention + oi->outputType = Projector::Yes; // Screens with size 0x0 are projectors by convention } else if (info->mm_width > 500 && info->mm_height > 500) { // Big screen - probably should be handled like a projector - oi->isProjector = Projector::Yes; + oi->outputType = Projector::Yes; } else if (info->mm_width > 350 && info->mm_height > 350) { // Somewhere in-between - oi->isProjector = Projector::Maybe; + oi->outputType = Projector::Maybe; } - typeCount[oi->isProjector]++; + typeCount[oi->outputType]++; _outputMap.insert(_screenResources->outputs[i], oi); qDebug() << "Connected" << outputName << "-- Clones:" << info->nclone << "Modes:" << info->nmode << "Crtcs:" << info->ncrtc << "Preferred:" << info->npreferred; } @@ -221,8 +226,8 @@ void ScreenSetup::updateScreenResources() if (typeCount[Projector::Maybe] > 0 && typeCount[Projector::No] > 0) { // Potential projector(s) and normal screen, promote for (OutputInfo *info : _outputMap) { - if (info->isProjector == Projector::Maybe) { - info->isProjector = Projector::Yes; + if (info->outputType == Projector::Maybe) { + info->outputType = Projector::Yes; break; } } @@ -244,6 +249,9 @@ void ScreenSetup::updateScreenResources() int endX = -0xffff; qDebug() << "From left to right"; for (OutputInfo* output : screens) { + if (output->mode == nullptr) { + qDebug() << "(Ignoring" << output->outputName << "since it's disconnected)"; + } if (output->crtc->x >= endX) { QSize res(0, 0); if (_modeMap.contains(output->crtc->mode)) { @@ -355,7 +363,7 @@ void ScreenSetup::initModes() // Finally copy all those the projector supports to other outputs for (auto key : _outputMap.keys()) { OutputInfo *oi = _outputMap[key]; - if (oi->isProjector == Projector::Yes) { + if (oi->outputType == Projector::Yes) { copyModesToAll(key, oi->output->nmode); } } @@ -421,9 +429,10 @@ bool ScreenSetup::setOutputResolution(OutputInfo *oi, int x, int y, const QSize { RRMode mode = getOutputModeForResolution(oi->output, size); if (mode == None) { + qDebug() << "Cannot set" << oi->outputName << "to" << size << " since it's not supported"; if (oi->output->nmode == 0) return false; - qDebug() << oi->outputName << "doesn't support" << size << "- falling back to its default"; + qDebug() << "falling back to its default"; mode = oi->output->modes[0]; } if (!dryRun) { @@ -441,19 +450,17 @@ bool ScreenSetup::setOutputResolution(OutputInfo *oi, int x, int y, const QSize ScreenMode ScreenSetup::getCurrentMode() { - int numConnected = 0; bool notAtOrigin = false; for (auto oi : _outputMap) { if (oi->mode != nullptr) { - ++numConnected; if (oi->crtc->x != 0 || oi->crtc->y != 0) { notAtOrigin = true; } } } - if (numConnected == 1) + if (_outputMap.size() == 1) return ScreenMode::Single; - if (numConnected > 2) + if (_outputMap.size() > 2) return ScreenMode::Advanced; if (notAtOrigin) return ScreenMode::Dual; @@ -467,8 +474,8 @@ ScreenMode ScreenSetup::setDefaultMode(bool dryRun) QMap<QString, OutputInfo*> screenMap; QMap<QString, OutputInfo*> projectorMap; for (auto o : _outputMap) { - qDebug() << o->outputName << quint32(o->isProjector); - if (o->isProjector == Projector::Yes) { + qDebug() << o->outputName << quint32(o->outputType); + if (o->outputType == Projector::Yes) { projectorMap.insert(o->outputName, o); } else { screenMap.insert(o->outputName, o); @@ -572,8 +579,16 @@ RRCrtc ScreenSetup::getFreeCrtc(const XRROutputInfo* output) const { for (int i = 0; i < output->ncrtc; ++i) { RRCrtc c = output->crtcs[i]; - for (auto oi : _outputMap) { - if (oi->output->crtc == c) + if (!_crtcMap.contains(c)) { + // Unknown CRTC!? Scan already known outputs + qDebug() << "BUG: Output has unknown possible CRTC"; + for (auto oi : _outputMap) { + if (oi->output->crtc == c) + goto next; + } + } else { + // Known CRTC -- see if free + if (_crtcMap[c]->noutput > 0) goto next; } return c; @@ -690,11 +705,15 @@ bool ScreenSetup::setClone(const QSize &resolution) bool ScreenSetup::setCustom(const QList<QPair<QSize, QList<QString>>> &list) { - createCrtcBackup(); QList<QSize> sizes; for (auto e : list) { + if (e.second.isEmpty()) + continue; sizes.append(e.first); } + if (sizes.isEmpty()) + return false; + createCrtcBackup(); auto screenSize = getTotalSizeHorz(sizes); if (screenSize.isEmpty()) return false; @@ -704,6 +723,8 @@ bool ScreenSetup::setCustom(const QList<QPair<QSize, QList<QString>>> &list) int x = 0; bool ok = false; for (auto e : list) { + if (e.second.isEmpty()) + continue; const QSize &res = e.first; for (auto outputName : e.second) { for (auto oi : _outputMap) { |