X-Git-Url: https://git.ralfj.de/lilass.git/blobdiff_plain/1b0001147e5d8209a2a2a209edaa93264a143473..ffc98865eecc0de34e0a33d7d83461ed9d4ee29b:/qt_dialogue.py diff --git a/qt_dialogue.py b/qt_dialogue.py index 0986106..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,80 +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): - # 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) - posBox.setLayout(makeLayout(QtGui.QVBoxLayout(), [self.posLeft, self.posRight, self.extOnly])) - - # primary screen - primBox = QtGui.QGroupBox('Which should be the primary screen?', self) - self.extOnly.toggled.connect(primBox.setDisabled) # disable the box if there's just one screen in use - self.primExt = QtGui.QRadioButton('The external screen', primBox) - self.primInt = QtGui.QRadioButton('The internal screen', primBox) - self.primInt.setChecked(True) - primBox.setLayout(makeLayout(QtGui.QVBoxLayout(), [self.primExt, self.primInt])) - - # resolution selection - resBox = QtGui.QGroupBox('Screen resolutions', 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 - extRow = makeLayout(QtGui.QHBoxLayout(), [extResLabel, self.extResolutionsBox]) - intResLabel = QtGui.QLabel('Resolution of internal screen:', resBox) - self.extOnly.toggled.connect(intResLabel.setDisabled) # disable the label if there's just one screen in use - 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.extOnly.toggled.connect(self.intResolutionsBox.setDisabled) # disable the box if there's just one screen in use - intRow = makeLayout(QtGui.QHBoxLayout(), [intResLabel, self.intResolutionsBox]) - resBox.setLayout(makeLayout(QtGui.QVBoxLayout(), [extRow, intRow])) - - # 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, primBox, resBox, buttons])) - - def run(self): - self.exec_() - if not self.result(): return None - 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 - else: - return RelativeScreenPosition.EXTERNAL_ONLY + def __init__(self, situation): + # set up main window + super(PositionSelection, self).__init__() + self._situation = situation + uifile = os.path.join(os.path.dirname(__file__), 'qt_dialogue.ui') + uic.loadUi(uifile, self) + + # fill relative position box + for pos in RelativeScreenPosition: + self.relPos.addItem(relPosNames[pos], pos) + + # 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 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 + 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())