X-Git-Url: https://git.ralfj.de/lilass.git/blobdiff_plain/4dd0918b62956f292f8448c32d8c61fbbeacfeb4..ffc98865eecc0de34e0a33d7d83461ed9d4ee29b:/qt_dialogue.py diff --git a/qt_dialogue.py b/qt_dialogue.py index c82b8f9..96c04a7 100644 --- a/qt_dialogue.py +++ b/qt_dialogue.py @@ -1,5 +1,5 @@ # DSL - easy Display Setup for Laptops -# Copyright (C) 2012 Ralf Jung +# Copyright (C) 2012-2015 Ralf Jung # # 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 @@ -14,112 +14,98 @@ # 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. -from dsl import RelativeScreenPosition, ScreenSetup, res2user -from PyQt4 import QtCore, QtGui +import os +from screen import RelativeScreenPosition, ScreenSetup +from PyQt4 import QtCore, QtGui, uic + +relPosNames = { + RelativeScreenPosition.LEFT: "left of", + RelativeScreenPosition.RIGHT: "right of", + RelativeScreenPosition.ABOVE: "above", + RelativeScreenPosition.BELOW: "below", + RelativeScreenPosition.MIRROR: "same as", +} -def makeLayout(layout, members): - for m in members: - if isinstance(m, QtGui.QLayout): - layout.addLayout(m) - else: - layout.addWidget(m) - return layout class PositionSelection(QtGui.QDialog): - def __init__(self, internalResolutions, externalResolutions, commonResolutions): + def __init__(self, situation): # set up main window super(PositionSelection, self).__init__() - self.setWindowTitle('DSL - easy Display Setup for Laptops') - - ## position selection - posBox = QtGui.QGroupBox('Position of external screen', self) - self.posLeft = QtGui.QRadioButton('Left of internal screen', posBox) - self.posRight = QtGui.QRadioButton('Right of internal screen', posBox) - self.posRight.setChecked(True) - self.posRight.setFocus() - self.extOnly = QtGui.QRadioButton('Use external screen exclusively', posBox) - self.mirror = QtGui.QRadioButton('Mirror internal screen', posBox) - positions = [self.posLeft, self.posRight, self.extOnly, self.mirror] - posBox.setLayout(makeLayout(QtGui.QVBoxLayout(), positions)) - for pos in positions: - pos.toggled.connect(self.updateForm) - - ## primary screen - self.primBox = QtGui.QGroupBox('Which should be the primary screen?', self) - self.primExt = QtGui.QRadioButton('The external screen', self.primBox) - self.primInt = QtGui.QRadioButton('The internal screen', self.primBox) - self.primInt.setChecked(True) - self.primBox.setLayout(makeLayout(QtGui.QVBoxLayout(), [self.primExt, self.primInt])) + self._situation = situation + uifile = os.path.join(os.path.dirname(__file__), 'qt_dialogue.ui') + uic.loadUi(uifile, self) - ## resolution selection - resBox = QtGui.QGroupBox('Screen resolutions', self) - # external screen - self.extResLabel = QtGui.QLabel('Resolution of external screen:', resBox) - self.extResolutions = externalResolutions - self.extResolutionsBox = QtGui.QComboBox(resBox) - for res in externalResolutions: - self.extResolutionsBox.addItem(res2user(res)) - self.extResolutionsBox.setCurrentIndex(0) # select first resolution - self.extRow = makeLayout(QtGui.QHBoxLayout(), [self.extResLabel, self.extResolutionsBox]) - # internal screen - self.intResLabel = QtGui.QLabel('Resolution of internal screen:', resBox) - self.intResolutions = internalResolutions - self.intResolutionsBox = QtGui.QComboBox(resBox) - for res in internalResolutions: - self.intResolutionsBox.addItem(res2user(res)) - self.intResolutionsBox.setCurrentIndex(0) # select first resolution - self.intRow = makeLayout(QtGui.QHBoxLayout(), [self.intResLabel, self.intResolutionsBox]) - # both screens - self.mirrorResLabel = QtGui.QLabel('Resolution of both screens:', resBox) - self.mirrorResolutions = commonResolutions - self.mirrorResolutionsBox = QtGui.QComboBox(resBox) - for res in commonResolutions: - self.mirrorResolutionsBox.addItem(res2user(res)) - self.mirrorResolutionsBox.setCurrentIndex(0) # select first resolution - self.mirrorRow = makeLayout(QtGui.QHBoxLayout(), [self.mirrorResLabel, self.mirrorResolutionsBox]) - # show them all - resBox.setLayout(makeLayout(QtGui.QVBoxLayout(), [self.extRow, self.intRow, self.mirrorRow])) + # fill relative position box + for pos in RelativeScreenPosition: + self.relPos.addItem(relPosNames[pos], pos) - # last row: buttons - buttons = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel, QtCore.Qt.Horizontal, self) - buttons.accepted.connect(self.accept) - buttons.rejected.connect(self.reject) - - # add them all to the window - self.setLayout(makeLayout(QtGui.QVBoxLayout(), [posBox, self.primBox, resBox, buttons])) - - # make sure we are consistent - self.updateForm() + # keep resolutions in sync when in mirror mode + def syncIfMirror(source, target): + def _slot(idx): + if self.isMirror: + target.setCurrentIndex(idx) + source.currentIndexChanged.connect(_slot) + syncIfMirror(self.intRes, self.extRes) + syncIfMirror(self.extRes, self.intRes) + + # connect the update function, and make sure we are in a correct state + self.intEnabled.toggled.connect(self.updateEnabledControls) + self.extEnabled.toggled.connect(self.updateEnabledControls) + self.relPos.currentIndexChanged.connect(self.updateEnabledControls) + self.updateEnabledControls() + + def getRelativeScreenPosition(self): + idx = self.relPos.currentIndex() + return self.relPos.itemData(idx) + + def fillResolutionBox(self, box, resolutions): + # if the count did not change, update in-place (this avoids flicker) + if box.count() == len(resolutions): + for idx, res in enumerate(resolutions): + box.setItemText(idx, str(res)) + box.setItemData(idx, res) + else: + # first clear it + while box.count() > 0: + box.removeItem(0) + # then fill it + for res in resolutions: + box.addItem(str(res), res) - def updateForm(self): - self.primBox.setEnabled(self.posLeft.isChecked() or self.posRight.isChecked()) - self.extResolutionsBox.setEnabled(not self.mirror.isChecked()) - self.extResLabel.setEnabled(not self.mirror.isChecked()) - self.intResolutionsBox.setEnabled(self.posLeft.isChecked() or self.posRight.isChecked()) - self.intResLabel.setEnabled(self.posLeft.isChecked() or self.posRight.isChecked()) - self.mirrorResolutionsBox.setEnabled(self.mirror.isChecked()) - self.mirrorResLabel.setEnabled(self.mirror.isChecked()) + def updateEnabledControls(self): + intEnabled = self.intEnabled.isChecked() + extEnabled = self.extEnabled.isChecked() + bothEnabled = intEnabled and extEnabled + self.isMirror = bothEnabled and self.getRelativeScreenPosition() == RelativeScreenPosition.MIRROR # only if both are enabled, we can really mirror + # configure screen controls + self.intRes.setEnabled(intEnabled) + self.intPrimary.setEnabled(intEnabled and not self.isMirror) + self.extRes.setEnabled(extEnabled) + self.extPrimary.setEnabled(extEnabled and not self.isMirror) + if not intEnabled and extEnabled: + self.extPrimary.setChecked(True) + elif not extEnabled and intEnabled: + self.intPrimary.setChecked(True) + # which resolutions do we offer? + if self.isMirror: + commonRes = self._situation.commonResolutions() + self.fillResolutionBox(self.intRes, commonRes) + self.fillResolutionBox(self.extRes, commonRes) + self.intRes.setCurrentIndex(self.extRes.currentIndex()) + else: + self.fillResolutionBox(self.intRes, self._situation.internalResolutions()) + self.fillResolutionBox(self.extRes, self._situation.externalResolutions()) + # configure position control + self.posGroup.setEnabled(bothEnabled) + self.posLabel1.setEnabled(bothEnabled) + self.posLabel2.setEnabled(bothEnabled) + self.relPos.setEnabled(bothEnabled) + # avoid having no screen + self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(intEnabled or extEnabled) def run(self): self.exec_() if not self.result(): return None - if self.mirror.isChecked(): - return ScreenSetup(RelativeScreenPosition.MIRROR, - self.mirrorResolutions[self.mirrorResolutionsBox.currentIndex()], - self.mirrorResolutions[self.mirrorResolutionsBox.currentIndex()], - extIsPrimary = True) - else: - return ScreenSetup(self.getRelativeScreenPosition(), - self.intResolutions[self.intResolutionsBox.currentIndex()], - self.extResolutions[self.extResolutionsBox.currentIndex()], - self.primExt.isChecked()) - - def getRelativeScreenPosition(self): - if self.posLeft.isChecked(): - return RelativeScreenPosition.LEFT - elif self.posRight.isChecked(): - return RelativeScreenPosition.RIGHT - elif self.extOnly.isChecked(): - return RelativeScreenPosition.EXTERNAL_ONLY - else: - raise Exception("Nothing is checked?") + intRes = self.intRes.itemData(self.intRes.currentIndex()) if self.intEnabled.isChecked() else None + extRes = self.extRes.itemData(self.extRes.currentIndex()) if self.extEnabled.isChecked() else None + return ScreenSetup(intRes, extRes, self.getRelativeScreenPosition(), self.extPrimary.isChecked())