class ScoringDialog(QWidget): """a dialog for entering the scores""" # pylint: disable=too-many-instance-attributes def __init__(self, scene): QWidget.__init__(self) self.scene = scene decorateWindow(self, m18n("Scoring for this Hand")) self.nameLabels = [None] * 4 self.spValues = [None] * 4 self.windLabels = [None] * 4 self.wonBoxes = [None] * 4 self.detailsLayout = [None] * 4 self.details = [None] * 4 self.__tilePixMaps = [] self.__meldPixMaps = [] grid = QGridLayout(self) pGrid = QGridLayout() grid.addLayout(pGrid, 0, 0, 2, 1) pGrid.addWidget(QLabel(m18nc("kajongg", "Player")), 0, 0) pGrid.addWidget(QLabel(m18nc("kajongg", "Wind")), 0, 1) pGrid.addWidget(QLabel(m18nc("kajongg", "Score")), 0, 2) pGrid.addWidget(QLabel(m18n("Winner")), 0, 3) self.detailTabs = QTabWidget() self.detailTabs.setDocumentMode(True) pGrid.addWidget(self.detailTabs, 0, 4, 8, 1) for idx in range(4): self.setupUiForPlayer(pGrid, idx) self.draw = QCheckBox(m18nc("kajongg", "Draw")) self.draw.clicked.connect(self.wonChanged) btnPenalties = QPushButton(m18n("&Penalties")) btnPenalties.clicked.connect(self.penalty) self.btnSave = QPushButton(m18n("&Save Hand")) self.btnSave.clicked.connect(self.game.nextScoringHand) self.btnSave.setEnabled(False) self.setupUILastTileMeld(pGrid) pGrid.setRowStretch(87, 10) pGrid.addWidget(self.draw, 7, 3) self.cbLastTile.currentIndexChanged.connect(self.slotLastTile) self.cbLastMeld.currentIndexChanged.connect(self.slotInputChanged) btnBox = QHBoxLayout() btnBox.addWidget(btnPenalties) btnBox.addWidget(self.btnSave) pGrid.addLayout(btnBox, 8, 4) StateSaver(self) self.refresh() @property def game(self): """proxy""" return self.scene.game def setupUILastTileMeld(self, pGrid): """setup UI elements for last tile and last meld""" self.lblLastTile = QLabel(m18n("&Last Tile:")) self.cbLastTile = QComboBox() self.cbLastTile.setMinimumContentsLength(1) vpol = QSizePolicy() vpol.setHorizontalPolicy(QSizePolicy.Fixed) self.cbLastTile.setSizePolicy(vpol) self.cbLastTile.setSizeAdjustPolicy(QComboBox.AdjustToMinimumContentsLengthWithIcon) self.lblLastTile.setBuddy(self.cbLastTile) self.lblLastMeld = QLabel(m18n("L&ast Meld:")) self.prevLastTile = None self.cbLastMeld = QComboBox() self.cbLastMeld.setMinimumContentsLength(1) self.cbLastMeld.setSizePolicy(vpol) self.cbLastMeld.setSizeAdjustPolicy(QComboBox.AdjustToMinimumContentsLengthWithIcon) self.lblLastMeld.setBuddy(self.cbLastMeld) self.comboTilePairs = set() pGrid.setRowStretch(6, 5) pGrid.addWidget(self.lblLastTile, 7, 0, 1, 2) pGrid.addWidget(self.cbLastTile, 7, 2, 1, 1) pGrid.addWidget(self.lblLastMeld, 8, 0, 1, 2) pGrid.addWidget(self.cbLastMeld, 8, 2, 1, 2) def setupUiForPlayer(self, pGrid, idx): """setup UI elements for a player""" self.spValues[idx] = QSpinBox() self.nameLabels[idx] = QLabel() self.nameLabels[idx].setBuddy(self.spValues[idx]) self.windLabels[idx] = WindLabel() pGrid.addWidget(self.nameLabels[idx], idx + 2, 0) pGrid.addWidget(self.windLabels[idx], idx + 2, 1) pGrid.addWidget(self.spValues[idx], idx + 2, 2) self.wonBoxes[idx] = QCheckBox("") pGrid.addWidget(self.wonBoxes[idx], idx + 2, 3) self.wonBoxes[idx].clicked.connect(self.wonChanged) self.spValues[idx].valueChanged.connect(self.slotInputChanged) detailTab = QWidget() self.detailTabs.addTab(detailTab, "") self.details[idx] = QWidget() detailTabLayout = QVBoxLayout(detailTab) detailTabLayout.addWidget(self.details[idx]) detailTabLayout.addStretch() self.detailsLayout[idx] = QVBoxLayout(self.details[idx]) def refresh(self): """reload game""" self.clear() game = self.game self.setVisible(game is not None and not game.finished()) if game: for idx, player in enumerate(game.players): for child in self.details[idx].children(): if isinstance(child, RuleBox): child.hide() self.detailsLayout[idx].removeWidget(child) del child if game: self.spValues[idx].setRange(0, game.ruleset.limit or 99999) self.nameLabels[idx].setText(player.localName) self.windLabels[idx].wind = player.wind self.windLabels[idx].roundsFinished = game.roundsFinished self.detailTabs.setTabText(idx, player.localName) player.manualRuleBoxes = [RuleBox(x) for x in game.ruleset.allRules if x.hasSelectable] for ruleBox in player.manualRuleBoxes: self.detailsLayout[idx].addWidget(ruleBox) ruleBox.clicked.connect(self.slotInputChanged) player.refreshManualRules() def show(self): """only now compute content""" if self.game and not self.game.finished(): self.slotInputChanged() QWidget.show(self) def penalty(self): """penalty button clicked""" dlg = PenaltyDialog(self.game) dlg.exec_() def slotLastTile(self): """called when the last tile changes""" newLastTile = self.computeLastTile() if not newLastTile: return if self.prevLastTile and self.prevLastTile.isExposed != newLastTile.isExposed: # state of last tile (concealed/exposed) changed: # for all checked boxes check if they still are applicable winner = self.game.winner if winner: for box in winner.manualRuleBoxes: if box.isChecked(): box.setChecked(False) if winner.hand.manualRuleMayApply(box.rule): box.setChecked(True) self.prevLastTile = newLastTile self.fillLastMeldCombo() self.slotInputChanged() def computeLastTile(self): """returns the currently selected last tile""" idx = self.cbLastTile.currentIndex() if idx >= 0: return variantValue(self.cbLastTile.itemData(idx)) def clickedPlayerIdx(self, checkbox): """the player whose box has been clicked""" for idx in range(4): if checkbox == self.wonBoxes[idx]: return idx assert False def wonChanged(self): """if a new winner has been defined, uncheck any previous winner""" newWinner = None if self.sender() != self.draw: clicked = self.clickedPlayerIdx(self.sender()) if self.wonBoxes[clicked].isChecked(): newWinner = self.game.players[clicked] else: newWinner = None self.game.winner = newWinner for idx in range(4): if newWinner != self.game.players[idx]: self.wonBoxes[idx].setChecked(False) if newWinner: self.draw.setChecked(False) self.fillLastTileCombo() self.slotInputChanged() def updateManualRules(self): """enable/disable them""" # if an exclusive rule has been activated, deactivate it for # all other players ruleBox = self.sender() if isinstance(ruleBox, RuleBox) and ruleBox.isChecked() and ruleBox.rule.exclusive(): for idx, player in enumerate(self.game.players): if ruleBox.parentWidget() != self.details[idx]: for pBox in player.manualRuleBoxes: if pBox.rule.name == ruleBox.rule.name: pBox.setChecked(False) try: newState = bool(self.game.winner.handBoard.uiTiles) except AttributeError: newState = False self.lblLastTile.setEnabled(newState) self.cbLastTile.setEnabled(newState) self.lblLastMeld.setEnabled(newState) self.cbLastMeld.setEnabled(newState) if self.game: for player in self.game.players: player.refreshManualRules(self.sender()) def clear(self): """prepare for next hand""" if self.game: for idx, player in enumerate(self.game.players): self.spValues[idx].clear() self.spValues[idx].setValue(0) self.wonBoxes[idx].setChecked(False) player.payment = 0 player.invalidateHand() for box in self.wonBoxes: box.setVisible(False) self.draw.setChecked(False) self.updateManualRules() if self.game is None: self.hide() else: for idx, player in enumerate(self.game.players): self.windLabels[idx].setPixmap(WINDPIXMAPS[(player.wind, player.wind == self.game.roundWind)]) self.computeScores() self.spValues[0].setFocus() self.spValues[0].selectAll() def computeScores(self): """if tiles have been selected, compute their value""" # pylint: disable=too-many-branches # too many branches if not self.game: return if self.game.finished(): self.hide() return for nameLabel, wonBox, spValue, player in zip(self.nameLabels, self.wonBoxes, self.spValues, self.game.players): with BlockSignals([spValue, wonBox]): # we do not want that change to call computeScores again if player.handBoard and player.handBoard.uiTiles: spValue.setEnabled(False) nameLabel.setBuddy(wonBox) for _ in range(10): prevTotal = player.handTotal player.invalidateHand() wonBox.setVisible(player.hand.won) if not wonBox.isVisibleTo(self) and wonBox.isChecked(): wonBox.setChecked(False) self.game.winner = None elif prevTotal == player.handTotal: break player.refreshManualRules() spValue.setValue(player.handTotal) else: if not spValue.isEnabled(): spValue.clear() spValue.setValue(0) spValue.setEnabled(True) nameLabel.setBuddy(spValue) wonBox.setVisible(player.handTotal >= self.game.ruleset.minMJTotal()) if not wonBox.isVisibleTo(self) and wonBox.isChecked(): wonBox.setChecked(False) if not wonBox.isVisibleTo(self) and player is self.game.winner: self.game.winner = None if Internal.scene.explainView: Internal.scene.explainView.refresh() def __lastMeldContent(self): """prepare content for lastmeld combo""" lastTiles = set() winnerTiles = [] if self.game.winner and self.game.winner.handBoard: winnerTiles = self.game.winner.handBoard.uiTiles pairs = [] for meld in self.game.winner.hand.melds: if len(meld) < 4: pairs.extend(meld) for tile in winnerTiles: if tile.tile in pairs and not tile.isBonus: lastTiles.add(tile.tile) return lastTiles, winnerTiles def __fillLastTileComboWith(self, lastTiles, winnerTiles): """fill last meld combo with prepared content""" self.comboTilePairs = lastTiles idx = self.cbLastTile.currentIndex() if idx < 0: idx = 0 indexedTile = variantValue(self.cbLastTile.itemData(idx)) restoredIdx = None self.cbLastTile.clear() if not winnerTiles: return pmSize = winnerTiles[0].board.tileset.faceSize pmSize = QSize(pmSize.width() * 0.5, pmSize.height() * 0.5) self.cbLastTile.setIconSize(pmSize) QPixmapCache.clear() self.__tilePixMaps = [] shownTiles = set() for tile in winnerTiles: if tile.tile in lastTiles and tile.tile not in shownTiles: shownTiles.add(tile.tile) self.cbLastTile.addItem(QIcon(tile.pixmapFromSvg(pmSize, withBorders=False)), "", toQVariant(tile.tile)) if indexedTile is tile.tile: restoredIdx = self.cbLastTile.count() - 1 if not restoredIdx and indexedTile: # try again, maybe the tile changed between concealed and exposed indexedTile = indexedTile.exposed for idx in range(self.cbLastTile.count()): if indexedTile is variantValue(self.cbLastTile.itemData(idx)).exposed: restoredIdx = idx break if not restoredIdx: restoredIdx = 0 self.cbLastTile.setCurrentIndex(restoredIdx) self.prevLastTile = self.computeLastTile() def clearLastTileCombo(self): """as the name says""" self.comboTilePairs = None self.cbLastTile.clear() def fillLastTileCombo(self): """fill the drop down list with all possible tiles. If the drop down had content before try to preserve the current index. Even if the tile changed state meanwhile.""" if self.game is None: return lastTiles, winnerTiles = self.__lastMeldContent() if self.comboTilePairs == lastTiles: return with BlockSignals(self.cbLastTile): # we only want to emit the changed signal once self.__fillLastTileComboWith(lastTiles, winnerTiles) self.cbLastTile.currentIndexChanged.emit(0) def __fillLastMeldComboWith(self, winnerMelds, indexedMeld, lastTile): """fill last meld combo with prepared content""" winner = self.game.winner faceWidth = winner.handBoard.tileset.faceSize.width() * 0.5 faceHeight = winner.handBoard.tileset.faceSize.height() * 0.5 restoredIdx = None for meld in winnerMelds: pixMap = QPixmap(faceWidth * len(meld), faceHeight) pixMap.fill(Qt.transparent) self.__meldPixMaps.append(pixMap) painter = QPainter(pixMap) for element in meld: painter.drawPixmap( 0, 0, winner.handBoard.tilesByElement(element)[0].pixmapFromSvg( QSize(faceWidth, faceHeight), withBorders=False ), ) painter.translate(QPointF(faceWidth, 0.0)) self.cbLastMeld.addItem(QIcon(pixMap), "", toQVariant(str(meld))) if indexedMeld == str(meld): restoredIdx = self.cbLastMeld.count() - 1 if not restoredIdx and indexedMeld: # try again, maybe the meld changed between concealed and exposed indexedMeld = indexedMeld.lower() for idx in range(self.cbLastMeld.count()): meldContent = str(variantValue(self.cbLastMeld.itemData(idx))) if indexedMeld == meldContent.lower(): restoredIdx = idx if lastTile not in meldContent: lastTile = lastTile.swapped assert lastTile in meldContent with BlockSignals(self.cbLastTile): # we want to continue right here idx = self.cbLastTile.findData(toQVariant(lastTile)) self.cbLastTile.setCurrentIndex(idx) break if not restoredIdx: restoredIdx = 0 self.cbLastMeld.setCurrentIndex(restoredIdx) self.cbLastMeld.setIconSize(QSize(faceWidth * 3, faceHeight)) def fillLastMeldCombo(self): """fill the drop down list with all possible melds. If the drop down had content before try to preserve the current index. Even if the meld changed state meanwhile.""" with BlockSignals(self.cbLastMeld): # we only want to emit the changed signal once showCombo = False idx = self.cbLastMeld.currentIndex() if idx < 0: idx = 0 indexedMeld = str(variantValue(self.cbLastMeld.itemData(idx))) self.cbLastMeld.clear() self.__meldPixMaps = [] if not self.game.winner: return if self.cbLastTile.count() == 0: return lastTile = Internal.scene.computeLastTile() winnerMelds = [m for m in self.game.winner.hand.melds if len(m) < 4 and lastTile in m] assert len(winnerMelds), "lastTile %s missing in %s" % (lastTile, self.game.winner.hand.melds) if len(winnerMelds) == 1: self.cbLastMeld.addItem(QIcon(), "", toQVariant(str(winnerMelds[0]))) self.cbLastMeld.setCurrentIndex(0) return showCombo = True self.__fillLastMeldComboWith(winnerMelds, indexedMeld, lastTile) self.lblLastMeld.setVisible(showCombo) self.cbLastMeld.setVisible(showCombo) self.cbLastMeld.currentIndexChanged.emit(0) def slotInputChanged(self): """some input fields changed: update""" for player in self.game.players: player.invalidateHand() self.updateManualRules() self.computeScores() self.validate() for player in self.game.players: self.game.wall.decoratePlayer(player) Internal.mainWindow.updateGUI() def validate(self): """update the status of the OK button""" game = self.game if game: valid = True if game.winner and game.winner.handTotal < game.ruleset.minMJTotal(): valid = False elif not game.winner and not self.draw.isChecked(): valid = False self.btnSave.setEnabled(valid)
class ScoringDialog(QWidget): """a dialog for entering the scores""" # pylint: disable=too-many-instance-attributes def __init__(self, scene): QWidget.__init__(self) self.scene = scene decorateWindow(self, i18n('Scoring for this Hand')) self.nameLabels = [None] * 4 self.spValues = [None] * 4 self.windLabels = [None] * 4 self.wonBoxes = [None] * 4 self.detailsLayout = [None] * 4 self.details = [None] * 4 self.__tilePixMaps = [] self.__meldPixMaps = [] grid = QGridLayout(self) pGrid = QGridLayout() grid.addLayout(pGrid, 0, 0, 2, 1) pGrid.addWidget(QLabel(i18nc('kajongg', "Player")), 0, 0) pGrid.addWidget(QLabel(i18nc('kajongg', "Wind")), 0, 1) pGrid.addWidget(QLabel(i18nc('kajongg', 'Score')), 0, 2) pGrid.addWidget(QLabel(i18n("Winner")), 0, 3) self.detailTabs = QTabWidget() self.detailTabs.setDocumentMode(True) pGrid.addWidget(self.detailTabs, 0, 4, 8, 1) for idx in range(4): self.setupUiForPlayer(pGrid, idx) self.draw = QCheckBox(i18nc('kajongg', 'Draw')) self.draw.clicked.connect(self.wonChanged) btnPenalties = QPushButton(i18n("&Penalties")) btnPenalties.clicked.connect(self.penalty) self.btnSave = QPushButton(i18n('&Save Hand')) self.btnSave.clicked.connect(self.game.nextScoringHand) self.btnSave.setEnabled(False) self.setupUILastTileMeld(pGrid) pGrid.setRowStretch(87, 10) pGrid.addWidget(self.draw, 7, 3) self.cbLastTile.currentIndexChanged.connect(self.slotLastTile) self.cbLastMeld.currentIndexChanged.connect(self.slotInputChanged) btnBox = QHBoxLayout() btnBox.addWidget(btnPenalties) btnBox.addWidget(self.btnSave) pGrid.addLayout(btnBox, 8, 4) StateSaver(self) self.refresh() @property def game(self): """proxy""" return self.scene.game def setupUILastTileMeld(self, pGrid): """setup UI elements for last tile and last meld""" self.lblLastTile = QLabel(i18n('&Last Tile:')) self.cbLastTile = QComboBox() self.cbLastTile.setMinimumContentsLength(1) vpol = QSizePolicy() vpol.setHorizontalPolicy(QSizePolicy.Fixed) self.cbLastTile.setSizePolicy(vpol) self.cbLastTile.setSizeAdjustPolicy( QComboBox.AdjustToMinimumContentsLengthWithIcon) self.lblLastTile.setBuddy(self.cbLastTile) self.lblLastMeld = QLabel(i18n('L&ast Meld:')) self.prevLastTile = None self.cbLastMeld = QComboBox() self.cbLastMeld.setMinimumContentsLength(1) self.cbLastMeld.setSizePolicy(vpol) self.cbLastMeld.setSizeAdjustPolicy( QComboBox.AdjustToMinimumContentsLengthWithIcon) self.lblLastMeld.setBuddy(self.cbLastMeld) self.comboTilePairs = set() pGrid.setRowStretch(6, 5) pGrid.addWidget(self.lblLastTile, 7, 0, 1, 2) pGrid.addWidget(self.cbLastTile, 7, 2, 1, 1) pGrid.addWidget(self.lblLastMeld, 8, 0, 1, 2) pGrid.addWidget(self.cbLastMeld, 8, 2, 1, 2) def setupUiForPlayer(self, pGrid, idx): """setup UI elements for a player""" self.spValues[idx] = QSpinBox() self.nameLabels[idx] = QLabel() self.nameLabels[idx].setBuddy(self.spValues[idx]) self.windLabels[idx] = WindLabel() pGrid.addWidget(self.nameLabels[idx], idx + 2, 0) pGrid.addWidget(self.windLabels[idx], idx + 2, 1) pGrid.addWidget(self.spValues[idx], idx + 2, 2) self.wonBoxes[idx] = QCheckBox("") pGrid.addWidget(self.wonBoxes[idx], idx + 2, 3) self.wonBoxes[idx].clicked.connect(self.wonChanged) self.spValues[idx].valueChanged.connect(self.slotInputChanged) detailTab = QWidget() self.detailTabs.addTab(detailTab, '') self.details[idx] = QWidget() detailTabLayout = QVBoxLayout(detailTab) detailTabLayout.addWidget(self.details[idx]) detailTabLayout.addStretch() self.detailsLayout[idx] = QVBoxLayout(self.details[idx]) def refresh(self): """reload game""" self.clear() game = self.game self.setVisible(game is not None and not game.finished()) if game: for idx, player in enumerate(game.players): for child in self.details[idx].children(): if isinstance(child, RuleBox): child.hide() self.detailsLayout[idx].removeWidget(child) del child if game: self.spValues[idx].setRange(0, game.ruleset.limit or 99999) self.nameLabels[idx].setText(player.localName) self.refreshWindLabels() self.detailTabs.setTabText(idx, player.localName) player.manualRuleBoxes = [ RuleBox(x) for x in game.ruleset.allRules if x.hasSelectable ] for ruleBox in player.manualRuleBoxes: self.detailsLayout[idx].addWidget(ruleBox) ruleBox.clicked.connect(self.slotInputChanged) player.refreshManualRules() def show(self): """only now compute content""" if self.game and not self.game.finished(): self.slotInputChanged() QWidget.show(self) def penalty(self): """penalty button clicked""" dlg = PenaltyDialog(self.game) dlg.exec_() def slotLastTile(self): """called when the last tile changes""" newLastTile = self.computeLastTile() if not newLastTile: return if self.prevLastTile and self.prevLastTile.isExposed != newLastTile.isExposed: # state of last tile (concealed/exposed) changed: # for all checked boxes check if they still are applicable winner = self.game.winner if winner: for box in winner.manualRuleBoxes: if box.isChecked(): box.setChecked(False) if winner.hand.manualRuleMayApply(box.rule): box.setChecked(True) self.prevLastTile = newLastTile self.fillLastMeldCombo() self.slotInputChanged() def computeLastTile(self): """returns the currently selected last tile""" idx = self.cbLastTile.currentIndex() if idx >= 0: return self.cbLastTile.itemData(idx) def clickedPlayerIdx(self, checkbox): """the player whose box has been clicked""" for idx in range(4): if checkbox == self.wonBoxes[idx]: return idx assert False def wonChanged(self): """if a new winner has been defined, uncheck any previous winner""" newWinner = None if self.sender() != self.draw: clicked = self.clickedPlayerIdx(self.sender()) if self.wonBoxes[clicked].isChecked(): newWinner = self.game.players[clicked] else: newWinner = None self.game.winner = newWinner for idx in range(4): if newWinner != self.game.players[idx]: self.wonBoxes[idx].setChecked(False) if newWinner: self.draw.setChecked(False) self.fillLastTileCombo() self.slotInputChanged() def updateManualRules(self): """enable/disable them""" # if an exclusive rule has been activated, deactivate it for # all other players ruleBox = self.sender() if isinstance( ruleBox, RuleBox) and ruleBox.isChecked() and ruleBox.rule.exclusive(): for idx, player in enumerate(self.game.players): if ruleBox.parentWidget() != self.details[idx]: for pBox in player.manualRuleBoxes: if pBox.rule.name == ruleBox.rule.name: pBox.setChecked(False) try: newState = bool(self.game.winner.handBoard.uiTiles) except AttributeError: newState = False self.lblLastTile.setEnabled(newState) self.cbLastTile.setEnabled(newState) self.lblLastMeld.setEnabled(newState) self.cbLastMeld.setEnabled(newState) if self.game: for player in self.game.players: player.refreshManualRules(self.sender()) def clear(self): """prepare for next hand""" if self.game: for idx, player in enumerate(self.game.players): self.spValues[idx].clear() self.spValues[idx].setValue(0) self.wonBoxes[idx].setChecked(False) player.payment = 0 player.invalidateHand() for box in self.wonBoxes: box.setVisible(False) self.draw.setChecked(False) self.updateManualRules() if self.game is None: self.hide() else: self.refreshWindLabels() self.computeScores() self.spValues[0].setFocus() self.spValues[0].selectAll() def refreshWindLabels(self): """update their wind and prevailing""" for idx, player in enumerate(self.game.players): self.windLabels[idx].wind = player.wind self.windLabels[idx].roundsFinished = self.game.roundsFinished def computeScores(self): """if tiles have been selected, compute their value""" # pylint: disable=too-many-branches # too many branches if not self.game: return if self.game.finished(): self.hide() return for nameLabel, wonBox, spValue, player in zip(self.nameLabels, self.wonBoxes, self.spValues, self.game.players): with BlockSignals([spValue, wonBox]): # we do not want that change to call computeScores again if player.handBoard and player.handBoard.uiTiles: spValue.setEnabled(False) nameLabel.setBuddy(wonBox) for _ in range(10): prevTotal = player.handTotal player.invalidateHand() wonBox.setVisible(player.hand.won) if not wonBox.isVisibleTo(self) and wonBox.isChecked(): wonBox.setChecked(False) self.game.winner = None elif prevTotal == player.handTotal: break player.refreshManualRules() spValue.setValue(player.handTotal) else: if not spValue.isEnabled(): spValue.clear() spValue.setValue(0) spValue.setEnabled(True) nameLabel.setBuddy(spValue) wonBox.setVisible( player.handTotal >= self.game.ruleset.minMJTotal()) if not wonBox.isVisibleTo(self) and wonBox.isChecked(): wonBox.setChecked(False) if not wonBox.isVisibleTo(self) and player is self.game.winner: self.game.winner = None if Internal.scene.explainView: Internal.scene.explainView.refresh() def __lastMeldContent(self): """prepare content for lastmeld combo""" lastTiles = set() winnerTiles = [] if self.game.winner and self.game.winner.handBoard: winnerTiles = self.game.winner.handBoard.uiTiles pairs = [] for meld in self.game.winner.hand.melds: if len(meld) < 4: pairs.extend(meld) for tile in winnerTiles: if tile.tile in pairs and not tile.isBonus: lastTiles.add(tile.tile) return lastTiles, winnerTiles def __fillLastTileComboWith(self, lastTiles, winnerTiles): """fill last meld combo with prepared content""" self.comboTilePairs = lastTiles idx = self.cbLastTile.currentIndex() if idx < 0: idx = 0 indexedTile = self.cbLastTile.itemData(idx) restoredIdx = None self.cbLastTile.clear() if not winnerTiles: return pmSize = winnerTiles[0].board.tileset.faceSize pmSize = QSize(pmSize.width() * 0.5, pmSize.height() * 0.5) self.cbLastTile.setIconSize(pmSize) QPixmapCache.clear() self.__tilePixMaps = [] shownTiles = set() for tile in winnerTiles: if tile.tile in lastTiles and tile.tile not in shownTiles: shownTiles.add(tile.tile) self.cbLastTile.addItem( QIcon(tile.pixmapFromSvg(pmSize, withBorders=False)), '', tile.tile) if indexedTile is tile.tile: restoredIdx = self.cbLastTile.count() - 1 if not restoredIdx and indexedTile: # try again, maybe the tile changed between concealed and exposed indexedTile = indexedTile.exposed for idx in range(self.cbLastTile.count()): if indexedTile is self.cbLastTile.itemData(idx).exposed: restoredIdx = idx break if not restoredIdx: restoredIdx = 0 self.cbLastTile.setCurrentIndex(restoredIdx) self.prevLastTile = self.computeLastTile() def clearLastTileCombo(self): """as the name says""" self.comboTilePairs = None self.cbLastTile.clear() def fillLastTileCombo(self): """fill the drop down list with all possible tiles. If the drop down had content before try to preserve the current index. Even if the tile changed state meanwhile.""" if self.game is None: return lastTiles, winnerTiles = self.__lastMeldContent() if self.comboTilePairs == lastTiles: return with BlockSignals(self.cbLastTile): # we only want to emit the changed signal once self.__fillLastTileComboWith(lastTiles, winnerTiles) self.cbLastTile.currentIndexChanged.emit(0) def __fillLastMeldComboWith(self, winnerMelds, indexedMeld, lastTile): """fill last meld combo with prepared content""" winner = self.game.winner faceWidth = winner.handBoard.tileset.faceSize.width() * 0.5 faceHeight = winner.handBoard.tileset.faceSize.height() * 0.5 restoredIdx = None for meld in winnerMelds: pixMap = QPixmap(faceWidth * len(meld), faceHeight) pixMap.fill(Qt.transparent) self.__meldPixMaps.append(pixMap) painter = QPainter(pixMap) for element in meld: painter.drawPixmap( 0, 0, winner.handBoard.tilesByElement(element)[0].pixmapFromSvg( QSize(faceWidth, faceHeight), withBorders=False)) painter.translate(QPointF(faceWidth, 0.0)) self.cbLastMeld.addItem(QIcon(pixMap), '', str(meld)) if indexedMeld == str(meld): restoredIdx = self.cbLastMeld.count() - 1 if not restoredIdx and indexedMeld: # try again, maybe the meld changed between concealed and exposed indexedMeld = indexedMeld.lower() for idx in range(self.cbLastMeld.count()): meldContent = str(self.cbLastMeld.itemData(idx)) if indexedMeld == meldContent.lower(): restoredIdx = idx if lastTile not in meldContent: lastTile = lastTile.swapped assert lastTile in meldContent with BlockSignals(self.cbLastTile ): # we want to continue right here idx = self.cbLastTile.findData(lastTile) self.cbLastTile.setCurrentIndex(idx) break if not restoredIdx: restoredIdx = 0 self.cbLastMeld.setCurrentIndex(restoredIdx) self.cbLastMeld.setIconSize(QSize(faceWidth * 3, faceHeight)) def fillLastMeldCombo(self): """fill the drop down list with all possible melds. If the drop down had content before try to preserve the current index. Even if the meld changed state meanwhile.""" with BlockSignals(self.cbLastMeld ): # we only want to emit the changed signal once showCombo = False idx = self.cbLastMeld.currentIndex() if idx < 0: idx = 0 indexedMeld = str(self.cbLastMeld.itemData(idx)) self.cbLastMeld.clear() self.__meldPixMaps = [] if not self.game.winner: return if self.cbLastTile.count() == 0: return lastTile = Internal.scene.computeLastTile() winnerMelds = [ m for m in self.game.winner.hand.melds if len(m) < 4 and lastTile in m ] assert len(winnerMelds), 'lastTile %s missing in %s' % ( lastTile, self.game.winner.hand.melds) if len(winnerMelds) == 1: self.cbLastMeld.addItem(QIcon(), '', str(winnerMelds[0])) self.cbLastMeld.setCurrentIndex(0) return showCombo = True self.__fillLastMeldComboWith(winnerMelds, indexedMeld, lastTile) self.lblLastMeld.setVisible(showCombo) self.cbLastMeld.setVisible(showCombo) self.cbLastMeld.currentIndexChanged.emit(0) def slotInputChanged(self): """some input fields changed: update""" for player in self.game.players: player.invalidateHand() self.updateManualRules() self.computeScores() self.validate() for player in self.game.players: player.showInfo() Internal.mainWindow.updateGUI() def validate(self): """update the status of the OK button""" game = self.game if game: valid = True if game.winner and game.winner.handTotal < game.ruleset.minMJTotal( ): valid = False elif not game.winner and not self.draw.isChecked(): valid = False self.btnSave.setEnabled(valid)