From 4f9708870cdf554d57530fe118b085b30213b5f8 Mon Sep 17 00:00:00 2001 From: doctorguile Date: Sat, 22 Mar 2014 18:41:50 -0700 Subject: [PATCH] #Version 0.08 - Option to show country flags in chat - Allow double click on player names to challenge/cancel/spectate - Show Ping and Country for incoming challenge - Remove challenge/decline table column --- VERSION | 2 +- WHATSNEW.md | 8 ++++++- ggpo/common/controller.py | 18 ++++++++++++++ ggpo/common/copyright.py | 2 +- ggpo/common/settings.py | 1 + ggpo/gui/ggpowindow.py | 44 +++++++++++++++++++++++----------- ggpo/gui/playermodel.py | 46 +++++++++++++++++------------------- ggpo/gui/ui/ggpowindow.ui | 11 ++++++++- ggpo/gui/ui/ggpowindow_ui.py | 9 +++++-- 9 files changed, 97 insertions(+), 44 deletions(-) diff --git a/VERSION b/VERSION index 7f8f011..45a4fb7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7 +8 diff --git a/WHATSNEW.md b/WHATSNEW.md index e62bf6d..6fbf344 100644 --- a/WHATSNEW.md +++ b/WHATSNEW.md @@ -60,4 +60,10 @@ Type `/help` to see a list of commands available - Add smooth networking settings like in official client - Add a custom scheme url for accept decline challenge. - Support custom emoticons -- Use green color for links \ No newline at end of file +- Use green color for links + +#Version 0.08 +- Option to show country flags in chat +- Allow double click on player names to challenge/cancel/spectate +- Show Ping and Country for incoming challenge +- Remove challenge/decline table column diff --git a/ggpo/common/controller.py b/ggpo/common/controller.py index 8fdb2d2..644e359 100644 --- a/ggpo/common/controller.py +++ b/ggpo/common/controller.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +import cgi import os import re import socket @@ -256,6 +257,23 @@ def getPlayerColor(self, name): return ColorTheme.getPlayerColor(self.players[name].id) return '#808080' + def getPlayerFlag(self, name): + if name in self.players: + p = self.players[name] + if p.cc: + return " ".format(p.cc) + + def getPlayerPrefix(self, name, useFlag): + c = self.getPlayerColor(name) + icon = '' + if useFlag: + icon = self.getPlayerFlag(name) + if useFlag: + return '{}{} '.format(icon, c, cgi.escape(name)) + else: + return '{} '.format(c, cgi.escape('<{}>'.format(name))) + + def ggpoPathJoin(self, *args): if self.fba: return os.path.join(os.path.dirname(self.fba), *args) diff --git a/ggpo/common/copyright.py b/ggpo/common/copyright.py index 505af86..63fc11d 100644 --- a/ggpo/common/copyright.py +++ b/ggpo/common/copyright.py @@ -16,7 +16,7 @@ # define version information __requires__ = ['PyQt4'] -__version__ = 7 +__version__ = 8 def versionString(): diff --git a/ggpo/common/settings.py b/ggpo/common/settings.py index 62ebcac..025d522 100644 --- a/ggpo/common/settings.py +++ b/ggpo/common/settings.py @@ -14,6 +14,7 @@ class Settings: SMOOTHING = 'smoothing' MUTE_CHALLENGE_SOUND = 'mute' NOTIFY_PLAYER_STATE_CHANGE = 'notifyPlayerStateChange' + SHOW_COUNTRY_FLAG_IN_CHAT = 'showCountryFlagInChat' WINDOW_GEOMETRY = 'mainWindowGeometry' WINDOW_STATE = 'mainWindowState' SPLITTER_STATE = 'splitterState' diff --git a/ggpo/gui/ggpowindow.py b/ggpo/gui/ggpowindow.py index e52cf8b..61bd956 100644 --- a/ggpo/gui/ggpowindow.py +++ b/ggpo/gui/ggpowindow.py @@ -62,6 +62,7 @@ def onAnchorClicked(self, qurl): if name in self.controller.challengers: self.controller.sendDeclineChallenge(name) self.controller.sigStatusMessage.emit("Declined {}'s challenge".format(name)) + self.updateStatusBar() def onRemoteHasUpdates(self, added, updated, nochange): totalchanged = added + updated @@ -165,10 +166,12 @@ def locateWine(self): if fname: Settings.setValue(Settings.WINE_LOCATION, fname) - def notifyStateChange(self, msg): + def notifyStateChange(self, name, msg): + msg = name + msg if self.lastStateChangeMsg != msg: self.lastStateChangeMsg = msg - self.uiChatHistoryTxtB.append(ColorTheme.statusHtml(msg)) + flag = self.controller.getPlayerFlag(name) or '' + self.uiChatHistoryTxtB.append(flag + ColorTheme.statusHtml(msg)) def onActionFailed(self, txt): self.uiChatHistoryTxtB.append(ColorTheme.statusHtml(txt)) @@ -182,8 +185,18 @@ def onChallengeDeclined(self, name): self.updateStatusBar() def onChallengeReceived(self, name): - c = self.controller.getPlayerColor(name) - chat = '' + cgi.escape(name) + " challenged you - " + extrainfo = [] + if name in self.controller.players: + p = self.controller.players[name] + if p.ping: + extrainfo.append('{}ms'.format(p.ping)) + if p.country: + extrainfo.append(p.country.decode('utf-8', 'ignore')) + extrainfo = ', '.join(extrainfo) + if extrainfo: + extrainfo = '({}) '.format(extrainfo) + chat = self.controller.getPlayerPrefix(name, True) + chat += " challenged you - " + extrainfo chat += "accept" chat += " / decline" self.uiChatHistoryTxtB.append(chat) @@ -191,9 +204,8 @@ def onChallengeReceived(self, name): self.updateStatusBar() def onChatReceived(self, name, txt): - c = self.controller.getPlayerColor(name) - chat = '' + cgi.escape('<' + name + '>') + " " + cgi.escape( - txt.strip()) + chat = self.controller.getPlayerPrefix(name, Settings.value(Settings.SHOW_COUNTRY_FLAG_IN_CHAT)) + \ + cgi.escape(txt.strip()) urls = findURLs(txt) if urls: for url in urls: @@ -231,11 +243,11 @@ def onMOTDReceived(self, channel, topic, msg): def onPlayerStateChange(self, name, state): if Settings.value(Settings.NOTIFY_PLAYER_STATE_CHANGE): if state == PlayerStates.QUIT: - self.notifyStateChange(name + " left") + self.notifyStateChange(name, " left") elif state == PlayerStates.AVAILABLE: - self.notifyStateChange(name + " becomes available") + self.notifyStateChange(name, " becomes available") elif state == PlayerStates.PLAYING: - self.notifyStateChange(name + " is in a game") + self.notifyStateChange(name, " is in a game") self.updateStatusBar() def onStatusMessage(self, msg): @@ -297,6 +309,8 @@ def restorePreference(self): self.uiMuteChallengeSoundAct.setChecked(True) if Settings.value(Settings.NOTIFY_PLAYER_STATE_CHANGE): self.uiNotifyPlayerStateChangeAct.setChecked(True) + if Settings.value(Settings.SHOW_COUNTRY_FLAG_IN_CHAT): + self.uiShowCountryFlagInChatAct.setChecked(True) fontsetting = Settings.pythonValue(Settings.CHAT_HISTORY_FONT) if fontsetting: self.uiChatHistoryTxtB.setFont(QtGui.QFont(*fontsetting)) @@ -469,6 +483,7 @@ def setupMenuSettings(self): else: self.uiLocateGeommdbAct.setVisible(False) self.uiNotifyPlayerStateChangeAct.toggled.connect(self.__class__.toggleNotifyPlayerStateChange) + self.uiShowCountryFlagInChatAct.toggled.connect(self.__class__.toggleShowCountryFlagInChat) if Settings.value(Settings.DEBUG_LOG): self.uiDebugLogAct.setChecked(True) self.uiDebugLogAct.triggered.connect(self.__class__.debuglogTriggered) @@ -526,6 +541,7 @@ def setupUserTable(self): model = PlayerModel(self.controller) self.uiPlayersTableV.setModel(model) self.uiPlayersTableV.clicked.connect(model.onCellClicked) + self.uiPlayersTableV.doubleClicked.connect(model.onCellDoubleClicked) self.uiPlayersTableV.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) self.uiPlayersTableV.verticalHeader().setVisible(False) hh = self.uiPlayersTableV.horizontalHeader() @@ -540,13 +556,9 @@ def setupUserTable(self): hh.resizeSection(PlayerModel.IGNORE, 25) hh.resizeSection(PlayerModel.PLAYER, 165) hh.resizeSection(PlayerModel.OPPONENT, 165) - hh.resizeSection(PlayerModel.ACCEPT_CHALLENGE, 25) - hh.resizeSection(PlayerModel.DECLINE_CHALLENGE, 25) hh.setResizeMode(PlayerModel.STATE, QtGui.QHeaderView.Fixed) hh.setResizeMode(PlayerModel.PING, QtGui.QHeaderView.Fixed) hh.setResizeMode(PlayerModel.IGNORE, QtGui.QHeaderView.Fixed) - hh.setResizeMode(PlayerModel.ACCEPT_CHALLENGE, QtGui.QHeaderView.Fixed) - hh.setResizeMode(PlayerModel.DECLINE_CHALLENGE, QtGui.QHeaderView.Fixed) self.uiPlayersTableV.setSortingEnabled(True) self.uiPlayersTableV.sortByColumn(PlayerModel.DEFAULT_SORT, Qt.AscendingOrder) hh.sortIndicatorChanged.connect(self.sortIndicatorChanged) @@ -563,6 +575,10 @@ def toggleAFK(self, state): def toggleNotifyPlayerStateChange(state): Settings.setBoolean(Settings.NOTIFY_PLAYER_STATE_CHANGE, state) + @staticmethod + def toggleShowCountryFlagInChat(state): + Settings.setBoolean(Settings.SHOW_COUNTRY_FLAG_IN_CHAT, state) + @staticmethod def toggleSound(state): Settings.setBoolean(Settings.MUTE_CHALLENGE_SOUND, state) diff --git a/ggpo/gui/playermodel.py b/ggpo/gui/playermodel.py index 1a8aae5..88e68a9 100644 --- a/ggpo/gui/playermodel.py +++ b/ggpo/gui/playermodel.py @@ -25,10 +25,8 @@ class PlayerModel(QtCore.QAbstractTableModel): DEFAULT_SORT = PLAYER - # state, player, ping, opponent, ignore, accept challenge, decline challenge - displayColumns = ["", "Player", "Ping", "Opponent", "", "", ""] - ACCEPT_CHALLENGE = 5 - DECLINE_CHALLENGE = 6 + # state, player, ping, opponent, ignore + displayColumns = ["", "Player", "Ping", "Opponent", ""] N_DISPLAY_COLS = len(displayColumns) sortableColumns = [PLAYER, PING, OPPONENT] @@ -44,8 +42,6 @@ def __init__(self, controller): controller.sigPlayersLoaded.connect(self.reloadPlayers) # TODO: optimize to only update challenge column? controller.sigChallengeDeclined.connect(self.reloadPlayers) - controller.sigChallengeReceived.connect(self.reloadPlayers) - controller.sigChallengeCancelled.connect(self.reloadPlayers) # This is very heavy-handed for handling the CLI add/remove changes controller.sigIgnoreAdded.connect(self.reloadPlayers) controller.sigIgnoreRemoved.connect(self.reloadPlayers) @@ -71,7 +67,6 @@ def data(self, modelIndex, role=None): return self.controller.players[name].country + ', ' + self.controller.players[name].city else: return self.controller.players[name].country - elif role == Qt.CheckStateRole and col == PlayerModel.IGNORE: return self.players[row][col] elif role == Qt.DecorationRole: @@ -91,12 +86,6 @@ def dataIcon(self, row, col): icon_path = ':/flags/' + self.players[row][PlayerModel.COUNTRY] + '.png' elif col == PlayerModel.OPPONENT: icon_path = ':/flags/' + self.players[row][PlayerModel.OPPONENT_COUNTRY] + '.png' - elif col == PlayerModel.ACCEPT_CHALLENGE: - if self.players[row][PlayerModel.PLAYER] in self.controller.challengers: - icon_path = ':/images/sword-yes.png' - elif col == PlayerModel.DECLINE_CHALLENGE: - if self.players[row][PlayerModel.PLAYER] in self.controller.challengers: - icon_path = ':/images/sword-no.png' elif col == PlayerModel.STATE: val = self.players[row][col] if self.controller.challenged: @@ -137,8 +126,6 @@ def headerData(self, section, Qt_Orientation, role=None): if role == Qt.DecorationRole and Qt_Orientation == Qt.Horizontal: if section == PlayerModel.IGNORE: return QtGui.QIcon(':/assets/face-ignore.png') - elif section == PlayerModel.ACCEPT_CHALLENGE: - return QtGui.QIcon(':/images/swords.png') def onCellClicked(self, index): col = index.column() @@ -159,15 +146,26 @@ def onCellClicked(self, index): idx2 = self.createIndex(len(self.players) - 1, PlayerModel.STATE) # noinspection PyUnresolvedReferences self.dataChanged.emit(idx1, idx2) - if col in [PlayerModel.ACCEPT_CHALLENGE, PlayerModel.DECLINE_CHALLENGE]: - if col == PlayerModel.ACCEPT_CHALLENGE: - self.controller.sendAcceptChallenge(self.players[row][PlayerModel.PLAYER]) - elif col == PlayerModel.DECLINE_CHALLENGE: - self.controller.sendDeclineChallenge(self.players[row][PlayerModel.PLAYER]) - idx1 = self.createIndex(0, PlayerModel.ACCEPT_CHALLENGE) - idx2 = self.createIndex(len(self.players) - 1, PlayerModel.DECLINE_CHALLENGE) - # noinspection PyUnresolvedReferences - self.dataChanged.emit(idx1, idx2) + + def onCellDoubleClicked(self, index): + col = index.column() + row = index.row() + if col == PlayerModel.PLAYER: + modified = False + if self.controller.challenged == self.players[row][PlayerModel.PLAYER]: + self.controller.sendCancelChallenge() + modified = True + elif self.players[row][PlayerModel.STATE] == PlayerModelState.AVAILABLE: + self.controller.sendChallenge(self.players[row][PlayerModel.PLAYER]) + modified = True + elif self.players[row][PlayerModel.STATE] == PlayerModelState.PLAYING: + self.controller.sendSpectateRequest(self.players[row][PlayerModel.PLAYER]) + modified = True + if modified: + idx1 = self.createIndex(0, PlayerModel.STATE) + idx2 = self.createIndex(len(self.players) - 1, PlayerModel.STATE) + # noinspection PyUnresolvedReferences + self.dataChanged.emit(idx1, idx2) # noinspection PyUnusedLocal def reloadPlayers(self, *args): diff --git a/ggpo/gui/ui/ggpowindow.ui b/ggpo/gui/ui/ggpowindow.ui index 2e71fce..203f985 100644 --- a/ggpo/gui/ui/ggpowindow.ui +++ b/ggpo/gui/ui/ggpowindow.ui @@ -131,9 +131,9 @@ - + @@ -142,6 +142,7 @@ + @@ -394,6 +395,14 @@ Custom &Emoticons + + + true + + + Show &country flag in chat + + diff --git a/ggpo/gui/ui/ggpowindow_ui.py b/ggpo/gui/ui/ggpowindow_ui.py index c783af0..58f5c82 100644 --- a/ggpo/gui/ui/ggpowindow_ui.py +++ b/ggpo/gui/ui/ggpowindow_ui.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'ggpo/gui/ui/ggpowindow.ui' # -# Created: Sat Mar 22 15:59:28 2014 +# Created: Sat Mar 22 18:35:35 2014 # by: PyQt4 UI code generator 4.9.1 # # WARNING! All changes made in this file will be lost! @@ -152,6 +152,9 @@ def setupUi(self, MainWindow): self.action0.setObjectName(_fromUtf8("action0")) self.uiCustomEmoticonsAct = QtGui.QAction(MainWindow) self.uiCustomEmoticonsAct.setObjectName(_fromUtf8("uiCustomEmoticonsAct")) + self.uiShowCountryFlagInChatAct = QtGui.QAction(MainWindow) + self.uiShowCountryFlagInChatAct.setCheckable(True) + self.uiShowCountryFlagInChatAct.setObjectName(_fromUtf8("uiShowCountryFlagInChatAct")) self.menuAction.addAction(self.uiAwayAct) self.menuAction.addAction(self.uiFocusOnChatAct) self.menuAction.addAction(self.uiEmoticonAct) @@ -169,9 +172,9 @@ def setupUi(self, MainWindow): self.menuAction.addSeparator() self.menuAction.addAction(self.uiQuitAct) self.menuSetting.addAction(self.uiMuteChallengeSoundAct) - self.menuSetting.addAction(self.uiFontAct) self.menuSetting.addAction(self.uiThemeMenu.menuAction()) self.menuSetting.addAction(self.uiSmoothingMenu.menuAction()) + self.menuSetting.addAction(self.uiFontAct) self.menuSetting.addAction(self.uiCustomEmoticonsAct) self.menuSetting.addSeparator() self.menuSetting.addAction(self.uiLocateGgpofbaAct) @@ -180,6 +183,7 @@ def setupUi(self, MainWindow): self.menuSetting.addAction(self.uiLocateGeommdbAct) self.menuSetting.addSeparator() self.menuSetting.addAction(self.uiNotifyPlayerStateChangeAct) + self.menuSetting.addAction(self.uiShowCountryFlagInChatAct) self.menuSetting.addAction(self.uiDebugLogAct) self.menuAbout.addAction(self.uiSRKForumAct) self.menuAbout.addAction(self.uiSRKWikiAct) @@ -258,5 +262,6 @@ def retranslateUi(self, MainWindow): self.uiNormalThemeAct.setText(QtGui.QApplication.translate("MainWindow", "&Normal", None, QtGui.QApplication.UnicodeUTF8)) self.action0.setText(QtGui.QApplication.translate("MainWindow", "0", None, QtGui.QApplication.UnicodeUTF8)) self.uiCustomEmoticonsAct.setText(QtGui.QApplication.translate("MainWindow", "Custom &Emoticons", None, QtGui.QApplication.UnicodeUTF8)) + self.uiShowCountryFlagInChatAct.setText(QtGui.QApplication.translate("MainWindow", "Show &country flag in chat", None, QtGui.QApplication.UnicodeUTF8)) from ggpo.gui.completionlineedit import CompletionLineEdit