summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2018-08-28 12:55:35 +0200
committerSimon Rettberg2018-08-28 12:55:35 +0200
commit74de0010bdf71e8f4cf7495c53853065b78462ec (patch)
treee13a637ef39cabfe364b325209164140f32bb11a
parentGetting there, slowly (diff)
downloadbeamergui-74de0010bdf71e8f4cf7495c53853065b78462ec.tar.gz
beamergui-74de0010bdf71e8f4cf7495c53853065b78462ec.tar.xz
beamergui-74de0010bdf71e8f4cf7495c53853065b78462ec.zip
UI improvements
-rw-r--r--LICENSE8
-rw-r--r--src/i18n/de.ts33
-rw-r--r--src/icons.qrc7
-rw-r--r--src/icons/checkmark.svg93
-rw-r--r--src/icons/projector_icon.svg65
-rw-r--r--src/icons/screen_icon.svg44
-rw-r--r--src/widget.cpp103
-rw-r--r--src/widget.h4
-rw-r--r--src/widget.ui77
-rw-r--r--src/x.cpp73
10 files changed, 405 insertions, 102 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..c56fa74
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,8 @@
+GPL blabla
+
+Icons:
+Projector:
+Icons made by "http://www.freepik.com" Freepik, from "https://www.flaticon.com/", "Creative Commons BY 3.0" (CC 3.0 BY)
+
+Screen:
+Icons made by "https://www.flaticon.com/authors/icon-works" Icon Works, from "https://www.flaticon.com/", "Creative Commons BY 3.0" (CC 3.0 BY)
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>&lt;- Swap -&gt;</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>
diff --git a/src/x.cpp b/src/x.cpp
index 73662c5..ef43f08 100644
--- a/src/x.cpp
+++ b/src/x.cpp
@@ -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) {