# DSL - easy Display Setup for Laptops
-# Copyright (C) 2012 Ralf Jung <post@ralfj.de>
+# Copyright (C) 2012-2015 Ralf Jung <post@ralfj.de>
#
# 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
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
-# along with this program (gpl.txt); if not, write to the Free Software
+# 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
-from PyQt4 import QtCore, QtGui
-
-def makeLayout(layout, members):
- for m in members:
- if isinstance(m, QtGui.QLayout):
- layout.addLayout(m)
- else:
- layout.addWidget(m)
- return layout
+import os
+from screen import RelativeScreenPosition, ScreenSetup
+from PyQt4 import QtCore, QtGui, uic
class PositionSelection(QtGui.QDialog):
- def __init__(self, externalName, internalResolutions, externalResolutions):
- # set up main window
- super(PositionSelection, self).__init__()
- self.setWindowTitle('External screen setup (connector: %s)' % externalName)
-
- # 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 = QtGui.QComboBox(resBox)
- for res in externalResolutions:
- self.extResolutions.addItem(res)
- self.extResolutions.setCurrentIndex(0) # select first resolution
- extRow = makeLayout(QtGui.QHBoxLayout(), [extResLabel, self.extResolutions])
- 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 = QtGui.QComboBox(resBox)
- for res in internalResolutions:
- self.intResolutions.addItem(res)
- self.intResolutions.setCurrentIndex(0) # select first resolution
- self.extOnly.toggled.connect(self.intResolutions.setDisabled) # disable the box if there's just one screen in use
- intRow = makeLayout(QtGui.QHBoxLayout(), [intResLabel, self.intResolutions])
- 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_()
- return True if self.result() else False
-
- def getRelativeScreenPosition(self):
- if self.posLeft.isChecked():
- return RelativeScreenPosition.LEFT
- elif self.posRight.isChecked():
- return RelativeScreenPosition.RIGHT
- else:
- return RelativeScreenPosition.EXTERNAL_ONLY
-
- def getIntResolutionIndex(self):
- return self.intResolutions.currentIndex()
-
- def getExtResolutionIndex(self):
- return self.extResolutions.currentIndex()
-
- def externalIsPrimary(self):
- return self.primExt.isChecked()
+ 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(pos.text, 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())