def __init__(self, client, parent=None): QDialog.__init__(self, parent) decorateWindow(self, i18n('Choose')) self.setObjectName('ClientDialog') self.client = client self.layout = QGridLayout(self) self.progressBar = QProgressBar() self.progressBar.setMinimumHeight(25) self.timer = QTimer() if not client.game.autoPlay: self.timer.timeout.connect(self.timeout) self.deferred = None self.buttons = [] self.setWindowFlags(Qt.SubWindow | Qt.WindowStaysOnTopHint) self.setModal(False) self.btnHeight = 0 self.answered = False self.move = None self.sorry = None
def __init__(self, client, parent=None): QDialog.__init__(self, parent) decorateWindow(self, m18n('Choose')) self.setObjectName('ClientDialog') self.client = client self.layout = QGridLayout(self) self.progressBar = QProgressBar() self.timer = QTimer() if not client.game.autoPlay: self.timer.timeout.connect(self.timeout) self.deferred = None self.buttons = [] self.setWindowFlags(Qt.SubWindow | Qt.WindowStaysOnTopHint) self.setModal(False) self.btnHeight = 0 self.answered = False self.move = None self.sorry = None
class ClientDialog(QDialog): """a simple popup dialog for asking the player what he wants to do""" def __init__(self, client, parent=None): QDialog.__init__(self, parent) decorateWindow(self, m18n('Choose')) self.setObjectName('ClientDialog') self.client = client self.layout = QGridLayout(self) self.progressBar = QProgressBar() self.timer = QTimer() if not client.game.autoPlay: self.timer.timeout.connect(self.timeout) self.deferred = None self.buttons = [] self.setWindowFlags(Qt.SubWindow | Qt.WindowStaysOnTopHint) self.setModal(False) self.btnHeight = 0 self.answered = False self.move = None self.sorry = None def keyPressEvent(self, event): """ESC selects default answer""" if not self.client.game or self.client.game.autoPlay: return if event.key() in [Qt.Key_Escape, Qt.Key_Space]: self.selectButton() event.accept() else: for btn in self.buttons: if str(event.text()).upper() == btn.message.shortcut: self.selectButton(btn) event.accept() return QDialog.keyPressEvent(self, event) def __declareButton(self, message): """define a button""" maySay = self.client.game.myself.sayable[message] if Internal.Preferences.showOnlyPossibleActions and not maySay: return btn = DlgButton(message, self) btn.setAutoDefault(True) btn.clicked.connect(self.selectedAnswer) self.buttons.append(btn) def focusTileChanged(self): """update icon and tooltip for the discard button""" if not self.client.game: return for button in self.buttons: button.decorate(self.client.game.myself.handBoard.focusTile) for uiTile in self.client.game.myself.handBoard.lowerHalfTiles(): txt = [] for button in self.buttons: _, _, tileTxt = button.message.toolTip(button, uiTile.tile) if tileTxt: txt.append(tileTxt) uiTile.setToolTip('<br><br>'.join(txt)) if self.client.game.activePlayer == self.client.game.myself: Internal.scene.handSelectorChanged( self.client.game.myself.handBoard) def checkTiles(self): """does the logical state match the displayed tiles?""" for player in self.client.game.players: player.handBoard.checkTiles() def messages(self): """a list of all messages returned by the declared buttons""" return list(x.message for x in self.buttons) def proposeAction(self): """either intelligently or first button by default. May also focus a proposed tile depending on the action.""" result = self.buttons[0] game = self.client.game if game.autoPlay or Internal.Preferences.propose: answer, parameter = game.myself.intelligence.selectAnswer( self.messages()) result = [x for x in self.buttons if x.message == answer][0] result.setFocus() if answer in [Message.Discard, Message.OriginalCall]: for uiTile in game.myself.handBoard.uiTiles: if uiTile.tile is parameter: game.myself.handBoard.focusTile = uiTile return result def askHuman(self, move, answers, deferred): """make buttons specified by answers visible. The first answer is default. The default button only appears with blue border when this dialog has focus but we always want it to be recognizable. Hence setBackgroundRole.""" self.move = move self.deferred = deferred for answer in answers: self.__declareButton(answer) self.focusTileChanged() self.show() self.checkTiles() game = self.client.game myTurn = game.activePlayer == game.myself prefButton = self.proposeAction() if game.autoPlay: self.selectButton(prefButton) return prefButton.setFocus() self.progressBar.setVisible(not myTurn) if not myTurn: msecs = 50 self.progressBar.setMinimum(0) self.progressBar.setMaximum( game.ruleset.claimTimeout * 1000 // msecs) self.progressBar.reset() self.timer.start(msecs) def placeInField(self): """place the dialog at bottom or to the right depending on space.""" mainWindow = Internal.scene.mainWindow cwi = mainWindow.centralWidget() view = mainWindow.centralView geometry = self.geometry() if not self.btnHeight: self.btnHeight = self.buttons[0].height() vertical = view.width() > view.height() * 1.2 if vertical: height = (len(self.buttons) + 1) * self.btnHeight * 1.2 width = (cwi.width() - cwi.height()) // 2 geometry.setX(cwi.width() - width) geometry.setY(min(cwi.height() // 3, cwi.height() - height)) else: handBoard = self.client.game.myself.handBoard if not handBoard: # we are in the progress of logging out return hbLeftTop = view.mapFromScene( handBoard.mapToScene(handBoard.rect().topLeft())) hbRightBottom = view.mapFromScene( handBoard.mapToScene(handBoard.rect().bottomRight())) width = hbRightBottom.x() - hbLeftTop.x() height = self.btnHeight geometry.setY(cwi.height() - height) geometry.setX(hbLeftTop.x()) for idx, btn in enumerate(self.buttons + [self.progressBar]): self.layout.addWidget( btn, idx + 1 if vertical else 0, idx + 1 if not vertical else 0) idx = len(self.buttons) + 2 spacer = QSpacerItem( 20, 20, QSizePolicy.Expanding, QSizePolicy.Expanding) self.layout.addItem( spacer, idx if vertical else 0, idx if not vertical else 0) geometry.setWidth(width) geometry.setHeight(height) self.setGeometry(geometry) def showEvent(self, dummyEvent): """try to place the dialog such that it does not cover interesting information""" self.placeInField() def timeout(self): """the progressboard wants an update""" pBar = self.progressBar if isAlive(pBar): pBar.setValue(pBar.value() + 1) pBar.setVisible(True) if pBar.value() == pBar.maximum(): # timeout: we always return the original default answer, not # the one with focus self.selectButton() pBar.setVisible(False) def selectButton(self, button=None): """select default answer. button may also be of type Message.""" if self.answered: # sometimes we get this event twice return if button is None: button = self.focusWidget() if isinstance(button, Message): assert any(x.message == button for x in self.buttons) answer = button else: answer = button.message if not self.client.game.myself.sayable[answer]: self.proposeAction().setFocus() # go back to default action self.sorry = Sorry(m18n('You cannot say %1', answer.i18nName)) return self.timer.stop() self.answered = True if self.sorry: self.sorry.cancel() self.sorry = None Internal.scene.clientDialog = None self.deferred.callback(answer) def selectedAnswer(self, dummyChecked): """the user clicked one of the buttons""" game = self.client.game if game and not game.autoPlay: self.selectButton(self.sender())
class ClientDialog(QDialog): """a simple popup dialog for asking the player what he wants to do""" def __init__(self, client, parent=None): QDialog.__init__(self, parent) decorateWindow(self, i18n('Choose')) self.setObjectName('ClientDialog') self.client = client self.layout = QGridLayout(self) self.progressBar = QProgressBar() self.progressBar.setMinimumHeight(25) self.timer = QTimer() if not client.game.autoPlay: self.timer.timeout.connect(self.timeout) self.deferred = None self.buttons = [] self.setWindowFlags(Qt.SubWindow | Qt.WindowStaysOnTopHint) self.setModal(False) self.btnHeight = 0 self.answered = False self.move = None self.sorry = None def keyPressEvent(self, event): """ESC selects default answer""" if not self.client.game or self.client.game.autoPlay: return if event.key() in [Qt.Key_Escape, Qt.Key_Space]: self.selectButton() event.accept() else: for btn in self.buttons: if str(event.text()).upper() == btn.message.shortcut: self.selectButton(btn) event.accept() return QDialog.keyPressEvent(self, event) def __declareButton(self, message): """define a button""" maySay = self.client.game.myself.sayable[message] if Internal.Preferences.showOnlyPossibleActions and not maySay: return btn = DlgButton(message, self) btn.setAutoDefault(True) btn.clicked.connect(self.selectedAnswer) self.buttons.append(btn) def focusTileChanged(self): """update icon and tooltip for the discard button""" if not self.client.game: return for button in self.buttons: button.setMeaning(self.client.game.myself.handBoard.focusTile) for uiTile in self.client.game.myself.handBoard.lowerHalfTiles(): txt = [] for button in self.buttons: _, _, tileTxt = button.message.toolTip(button, uiTile.tile) if tileTxt: txt.append(tileTxt) uiTile.setToolTip('<br><br>'.join(txt)) if self.client.game.activePlayer == self.client.game.myself: Internal.scene.handSelectorChanged( self.client.game.myself.handBoard) def checkTiles(self): """does the logical state match the displayed tiles?""" for player in self.client.game.players: player.handBoard.checkTiles() def messages(self): """a list of all messages returned by the declared buttons""" return list(x.message for x in self.buttons) def proposeAction(self): """either intelligently or first button by default. May also focus a proposed tile depending on the action.""" result = self.buttons[0] game = self.client.game if game.autoPlay or Internal.Preferences.propose: answer, parameter = game.myself.intelligence.selectAnswer( self.messages()) result = [x for x in self.buttons if x.message == answer][0] result.setFocus() if answer in [Message.Discard, Message.OriginalCall]: for uiTile in game.myself.handBoard.uiTiles: if uiTile.tile is parameter: game.myself.handBoard.focusTile = uiTile return result def askHuman(self, move, answers, deferred): """make buttons specified by answers visible. The first answer is default. The default button only appears with blue border when this dialog has focus but we always want it to be recognizable. Hence setBackgroundRole.""" self.move = move self.deferred = deferred for answer in answers: self.__declareButton(answer) self.focusTileChanged() self.show() self.checkTiles() game = self.client.game myTurn = game.activePlayer == game.myself prefButton = self.proposeAction() if game.autoPlay: self.selectButton(prefButton) return prefButton.setFocus() self.progressBar.setVisible(not myTurn) if not myTurn: msecs = 50 self.progressBar.setMinimum(0) self.progressBar.setMaximum( game.ruleset.claimTimeout * 1000 // msecs) self.progressBar.reset() self.timer.start(msecs) def placeInField(self): """place the dialog at bottom or to the right depending on space.""" mainWindow = Internal.scene.mainWindow cwi = mainWindow.centralWidget() view = mainWindow.centralView geometry = self.geometry() if not self.btnHeight: self.btnHeight = self.buttons[0].height() vertical = view.width() > view.height() * 1.2 if vertical: height = (len(self.buttons) + 1) * self.btnHeight * 1.2 width = (cwi.width() - cwi.height()) // 2 geometry.setX(cwi.width() - width) geometry.setY(min(cwi.height() // 3, cwi.height() - height)) else: handBoard = self.client.game.myself.handBoard if not handBoard: # we are in the progress of logging out return hbLeftTop = view.mapFromScene( handBoard.mapToScene(handBoard.rect().topLeft())) hbRightBottom = view.mapFromScene( handBoard.mapToScene(handBoard.rect().bottomRight())) width = hbRightBottom.x() - hbLeftTop.x() height = self.btnHeight geometry.setY(cwi.height() - height) geometry.setX(hbLeftTop.x()) for idx, btn in enumerate(self.buttons + [self.progressBar]): self.layout.addWidget( btn, idx + 1 if vertical else 0, idx + 1 if not vertical else 0) idx = len(self.buttons) + 2 spacer = QSpacerItem( 20, 20, QSizePolicy.Expanding, QSizePolicy.Expanding) self.layout.addItem( spacer, idx if vertical else 0, idx if not vertical else 0) geometry.setWidth(width) geometry.setHeight(height) self.setGeometry(geometry) def showEvent(self, dummyEvent): """try to place the dialog such that it does not cover interesting information""" self.placeInField() def timeout(self): """the progressboard wants an update""" pBar = self.progressBar if isAlive(pBar): pBar.setValue(pBar.value() + 1) pBar.setVisible(True) if pBar.value() == pBar.maximum(): # timeout: we always return the original default answer, not # the one with focus self.selectButton() pBar.setVisible(False) def selectButton(self, button=None): """select default answer. button may also be of type Message.""" if self.answered: # sometimes we get this event twice return if button is None: button = self.focusWidget() if isinstance(button, Message): assert any(x.message == button for x in self.buttons) answer = button else: answer = button.message if not self.client.game.myself.sayable[answer]: self.proposeAction().setFocus() # go back to default action self.sorry = Sorry(i18n('You cannot say %1', answer.i18nName)) return self.timer.stop() self.answered = True if self.sorry: self.sorry.cancel() self.sorry = None Internal.scene.clientDialog = None self.deferred.callback(answer) def selectedAnswer(self, dummyChecked): """the user clicked one of the buttons""" game = self.client.game if game and not game.autoPlay: self.selectButton(self.sender())