From 58a6536ef1efdc55e200ca0d6981dec41979804b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Br=C3=B6tzmann?= Date: Mon, 19 Aug 2019 09:22:57 +0200 Subject: [PATCH] [tictactoe] Code cleanup, new config dialog --- tictactoe/config_dialog.py | 55 ++++++++++ tictactoe/config_dialog.ui | 63 ----------- tictactoe/plugin.py | 212 +++++++++++++++++++------------------ 3 files changed, 162 insertions(+), 168 deletions(-) create mode 100644 tictactoe/config_dialog.py delete mode 100644 tictactoe/config_dialog.ui diff --git a/tictactoe/config_dialog.py b/tictactoe/config_dialog.py new file mode 100644 index 0000000..1c0617a --- /dev/null +++ b/tictactoe/config_dialog.py @@ -0,0 +1,55 @@ +# +# This file is part of the TicTacToe plugin for Gajim. +# +# Gajim is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Gajim is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Gajim. If not, see . + +from gi.repository import GObject +from gi.repository import Gtk + +from gajim.gtk.settings import SettingsDialog +from gajim.gtk.settings import SpinSetting +from gajim.gtk.const import Setting +from gajim.gtk.const import SettingType + +from gajim.plugins.plugins_i18n import _ + + +class TicTacToeConfigDialog(SettingsDialog): + def __init__(self, plugin, parent): + + self.plugin = plugin + settings = [ + Setting('BoardSizeSpinSetting', _('Board Size'), + SettingType.VALUE, self.plugin.config['board_size'], + callback=self.on_setting, data='board_size', + desc=_('Size of the board'), + props={'range_': (3, 10)})] + + SettingsDialog.__init__(self, parent, _('TicTacToe Configuration'), + Gtk.DialogFlags.MODAL, settings, None, + extend=[ + ('BoardSizeSpinSetting', SizeSpinSetting)]) + + def on_setting(self, value, data): + self.plugin.config[data] = value + + +class SizeSpinSetting(SpinSetting): + + __gproperties__ = { + "setting-value": (int, 'Size', '', 3, 10, 3, + GObject.ParamFlags.READWRITE), } + + def __init__(self, *args, **kwargs): + SpinSetting.__init__(self, *args, **kwargs) diff --git a/tictactoe/config_dialog.ui b/tictactoe/config_dialog.ui deleted file mode 100644 index 5a2a5dc..0000000 --- a/tictactoe/config_dialog.ui +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - False - - - True - False - vertical - - - True - False - - - 133 - True - False - Board size - start - True - False - - - True - True - 0 - - - - - True - True - True - Preview size(10-512) - - 6 - True - True - - - - False - False - 1 - - - - - True - True - 0 - - - - - - - - - diff --git a/tictactoe/plugin.py b/tictactoe/plugin.py index 8c7afff..79e3a04 100644 --- a/tictactoe/plugin.py +++ b/tictactoe/plugin.py @@ -1,21 +1,20 @@ -## plugins/tictactoe/plugin.py -## -## Copyright (C) 2011 Yann Leboulanger -## -## This file is part of Gajim. -## -## Gajim is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published -## by the Free Software Foundation; version 3 only. -## -## Gajim is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Gajim. If not, see . -## +# +# Copyright (C) 2011 Yann Leboulanger +# +# This file is part of the TicTacToe plugin for Gajim. +# +# Gajim is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation; version 3 only. +# +# Gajim is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Gajim. If not, see . +# ''' Tictactoe plugin. @@ -30,36 +29,53 @@ import string import itertools import random -import nbxmpp +from functools import partial + from gi.repository import Gtk from gi.repository import Gdk from gi.repository import Gio from gi.repository import GLib -import gi -gi.require_version('PangoCairo', '1.0') -from gi.repository import PangoCairo -from gajim.common import helpers -from gajim.common import app -from gajim.plugins import GajimPlugin -from gajim.plugins.helpers import log_calls, log -from gajim.plugins.gui import GajimPluginConfigDialog +import nbxmpp + from gajim import chat_control + +from gajim.common import app from gajim.common import ged +from gajim.common import helpers from gajim.common.connection_handlers_events import InformationEvent -from gajim.plugins.plugins_i18n import _ from gajim.gtk.dialogs import DialogButton from gajim.gtk.dialogs import NewConfirmationDialog +from gajim.plugins import GajimPlugin +from gajim.plugins.helpers import log +from gajim.plugins.helpers import log_calls +from gajim.plugins.plugins_i18n import _ + +from tictactoe.config_dialog import TicTacToeConfigDialog + +try: + import gi + gi.require_version('PangoCairo', '1.0') + from gi.repository import PangoCairo + HAS_PANGOCAIRO = True +except ImportError: + HAS_PANGOCAIRO = False + NS_GAMES = 'http://jabber.org/protocol/games' NS_GAMES_TICTACTOE = NS_GAMES + '/tictactoe' + class TictactoePlugin(GajimPlugin): @log_calls('TictactoePlugin') def init(self): + if not HAS_PANGOCAIRO: + self.activatable = False + self.config_dialog = None + self.available_text = _('TicTacToe requires PangoCairo to run') self.description = _('Play Tictactoe.') - self.config_dialog = TictactoePluginConfigDialog(self) + self.config_dialog = partial(TicTacToeConfigDialog, self) self.events_handlers = { 'decrypted-message-received': ( ged.PREGUI, self._nec_decrypted_message_received), @@ -109,8 +125,8 @@ class TictactoePlugin(GajimPlugin): # Already existing session? conn = app.connections[control.account] sessions = conn.get_sessions(control.contact.jid) - tictactoes = [s for s in sessions if isinstance(s, - TicTacToeSession)] + tictactoes = [s for s in sessions if isinstance( + s, TicTacToeSession)] if tictactoes: base.tictactoe = tictactoes[0] base.enable_action(True) @@ -125,8 +141,8 @@ class TictactoePlugin(GajimPlugin): def update_button_state(self, control): for base in self.controls: if base.chat_control == control: - if control.contact.supports(NS_GAMES) and \ - control.contact.supports(NS_GAMES_TICTACTOE): + if (control.contact.supports(NS_GAMES) and + control.contact.supports(NS_GAMES_TICTACTOE)): base.enable_action(True) else: base.enable_action(False) @@ -166,13 +182,13 @@ class TictactoePlugin(GajimPlugin): obj.session.received(obj.stanza) game_invite = obj.stanza.getTag('invite', namespace=NS_GAMES) if game_invite: - account = obj.conn.name game = game_invite.getTag('game') if game and game.getAttr('var') == NS_GAMES_TICTACTOE: session = obj.conn.make_new_session(obj.fjid, obj.thread_id, - cls=TicTacToeSession) + cls=TicTacToeSession) self.show_request_dialog(obj, session) + class Base(object): def __init__(self, plugin, chat_control): self.plugin = plugin @@ -230,9 +246,11 @@ class Base(object): menu.remove(i) break + class InvalidMove(Exception): pass + class TicTacToeSession(object): def __init__(self, conn, jid, thread_id, type_): self.conn = conn @@ -266,7 +284,10 @@ class TicTacToeSession(object): def get_to(self): to = str(self.jid) - return app.get_jid_without_resource(to) + '/' + self.resource + jid = app.get_jid_without_resource(to) + if self.resource: + jid += '/' + self.resource + return jid def generate_thread_id(self): return ''.join( @@ -274,7 +295,7 @@ class TicTacToeSession(object): random.choice, 32)] ) - # initiate a session + # Initiate a session def begin(self, role_s='x'): self.rows = self.base.plugin.config['board_size'] self.cols = self.base.plugin.config['board_size'] @@ -343,23 +364,23 @@ class TicTacToeSession(object): else: self.cols = 3 - # number in a row needed to win + # Number in a row needed to win if form.getField('strike'): self.strike = int(form.getField('strike').getValues()[0]) else: self.strike = 3 - # received an invitation + # Received an invitation def invited(self, msg): self.read_invitation(msg) - # the number of the move about to be made + # The number of the move about to be made self.next_move_id = 1 - # display the board + # Display the board self.board = TicTacToeBoard(self, self.rows, self.cols) - # accept the invitation, join the game + # Accept the invitation, join the game response = nbxmpp.Message() join = response.NT.join @@ -377,7 +398,7 @@ class TicTacToeSession(object): self.our_turn() - # just sent an invitation, expecting a reply + # Just sent an invitation, expecting a reply def wait_for_invite_response(self, msg): if msg.getTag('join', namespace=NS_GAMES): self.board = TicTacToeBoard(self, self.rows, self.cols) @@ -388,13 +409,15 @@ class TicTacToeSession(object): self.their_turn() elif msg.getTag('decline', namespace=NS_GAMES): - app.nec.push_incoming_event(InformationEvent(None, conn=self.conn, - level='info', pri_txt=_('Invitation refused'), - sec_txt=_('%(name)s refused your invitation to play tic tac ' - 'toe.') % {'name': self.name})) + app.nec.push_incoming_event( + InformationEvent( + None, + conn=self.conn, + level='info', + pri_txt=_('Invitation refused'), + sec_txt=_('%(name)s refused your invitation to play tic ' + 'tac toe.') % {'name': self.name})) self.conn.delete_session(str(self.jid), self.thread_id) - if self.base: - self.base.button.set_active(False) def decline_invitation(self): msg = nbxmpp.Message() @@ -413,14 +436,14 @@ class TicTacToeSession(object): self.received = self.game_over return True - # silently ignores any received messages + # Silently ignores any received messages def ignore(self, msg): self.treat_terminate(msg) def game_over(self, msg): invite = msg.getTag('invite', namespace=NS_GAMES) - # ignore messages unless they're renewing the game + # Ignore messages unless they're renewing the game if invite and invite.getAttr('type') == 'renew': self.invited(msg) @@ -440,14 +463,14 @@ class TicTacToeSession(object): try: self.board.mark(row, col, self.role_o) - except InvalidMove as e: - # received an invalid move, end the game. + except InvalidMove: + # Received an invalid move, end the game. self.board.cheated() self.end_game('cheating') self.received = self.game_over return - # check win conditions + # Check win conditions if self.board.check_for_strike(self.role_o, row, col, self.strike): self.lost() elif self.board.full(): @@ -461,7 +484,7 @@ class TicTacToeSession(object): return self.received == self.ignore def our_turn(self): - # ignore messages until we've made our move + # Ignore messages until we've made our move self.received = self.ignore self.board.set_title('your turn') @@ -473,13 +496,13 @@ class TicTacToeSession(object): def move(self, row, col): try: self.board.mark(row, col, self.role_s) - except InvalidMove as e: - log.warn('you made an invalid move') + except InvalidMove: + log.warn('You made an invalid move') return self.send_move(row, col) - # check win conditions + # Check win conditions if self.board.check_for_strike(self.role_s, row, col, self.strike): self.won() elif self.board.full(): @@ -489,7 +512,7 @@ class TicTacToeSession(object): self.their_turn() - # sends a move message + # Sends a move message def send_move(self, row, column): msg = nbxmpp.Message() msg.setType('chat') @@ -506,7 +529,7 @@ class TicTacToeSession(object): self.send(msg) - # sends a termination message and ends the game + # Sends a termination message and ends the game def end_game(self, reason): msg = nbxmpp.Message() @@ -547,22 +570,22 @@ class TicTacToeBoard: self.rows = rows self.cols = cols - self.board = [ [None] * self.cols for r in range(self.rows) ] + self.board = [[None] * self.cols for r in range(self.rows)] self.setup_window() - # check if the last move (at row r and column c) won the game + # Check if the last move (at row r and column c) won the game def check_for_strike(self, p, r, c, strike): - # number in a row: up and down, left and right + # Number in a row: up and down, left and right tallyI = 0 tally_ = 0 - # number in a row: diagonal + # Number in a row: diagonal # (imagine L or F as two sides of a right triangle: L\ or F/) tallyL = 0 tallyF = 0 - # convert real columns to internal columns + # Convert real columns to internal columns r -= 1 c -= 1 @@ -570,19 +593,19 @@ class TicTacToeBoard: r_in_range = 0 <= r+d < self.rows c_in_range = 0 <= c+d < self.cols - # vertical check + # Vertical check if r_in_range: tallyI = tallyI + 1 if self.board[r+d][c] != p: tallyI = 0 - # horizontal check + # Horizontal check if c_in_range: tally_ = tally_ + 1 if self.board[r][c+d] != p: tally_ = 0 - # diagonal checks + # Diagonal checks if r_in_range and c_in_range: tallyL = tallyL + 1 if self.board[r+d][c+d] != p: @@ -598,11 +621,11 @@ class TicTacToeBoard: return False - # is the board full? + # Is the board full? def full(self): for r in range(self.rows): for c in range(self.cols): - if self.board[r][c] == None: + if self.board[r][c] is None: return False return True @@ -628,16 +651,16 @@ class TicTacToeBoard: (width, height) = widget.get_size() - # convert click co-ordinates to row and column - row_height = height // self.rows - col_width = width // self.cols + # Convert click co-ordinates to row and column + row_height = height // self.rows + col_width = width // self.cols - row = int(event.y // row_height) + 1 + row = int(event.y // row_height) + 1 column = int(event.x // col_width) + 1 self.session.move(row, column) - # this actually draws the board + # This actually draws the board def do_draw(self, widget, cr): cr.set_source_rgb(1.0, 1.0, 1.0) @@ -647,7 +670,7 @@ class TicTacToeBoard: (width, height) = self.win.get_size() row_height = (height - text_height) // self.rows - col_width = width // self.cols + col_width = width // self.cols cr.set_source_rgb(0, 0, 0) cr.set_line_width(2) @@ -669,11 +692,11 @@ class TicTacToeBoard: txt = _('You won !') elif self.state == 'lost': txt = _('You lost !') - elif self.state == 'resign': # other part resigned + elif self.state == 'resign': # Other part resigned txt = _('%(name)s capitulated') % {'name': self.session.name} - elif self.state == 'cheated': # other part cheated + elif self.state == 'cheated': # Other part cheated txt = _('%(name)s cheated') % {'name': self.session.name} - else: #draw + else: # Draw txt = _('It\'s a draw') layout.set_text(txt, -1) # Inform Pango to re-layout the text with the new transformation @@ -689,9 +712,9 @@ class TicTacToeBoard: def draw_x(self, cr, row, col, row_height, col_width): if self.session.role_s == 'x': - color = '#3d79fb' # out + color = '#3d79fb' # Out else: - color = '#f03838' # red + color = '#f03838' # Red rgba = Gdk.RGBA() rgba.parse(color) cr.set_source_rgba(rgba.red, rgba.green, rgba.blue, rgba.alpha) @@ -724,12 +747,12 @@ class TicTacToeBoard: x = col_width * (col + 0.5) y = row_height * (row + 0.5) - cr.arc(x, y, row_height/4, 0, 2.0*3.2) # slightly further than 2*pi + cr.arc(x, y, row_height/4, 0, 2.0*3.2) # Slightly further than 2*pi cr.set_line_width(row_height / 5) cr.stroke() - # mark a move on the board + # Mark a move on the board def mark(self, row, column, player): if self.board[row-1][column-1]: raise InvalidMove @@ -738,7 +761,7 @@ class TicTacToeBoard: self.win.queue_draw() - def set_title(self, suffix = None): + def set_title(self, suffix=None): str_ = self.title_prefix if suffix: @@ -764,24 +787,3 @@ class TicTacToeBoard: def cheated(self): self.state == 'cheated' self.win.queue_draw() - - -class TictactoePluginConfigDialog(GajimPluginConfigDialog): - def init(self): - self.GTK_BUILDER_FILE_PATH = self.plugin.local_file_path( - 'config_dialog.ui') - self.xml = Gtk.Builder() - self.xml.set_translation_domain('gajim_plugins') - self.xml.add_objects_from_file(self.GTK_BUILDER_FILE_PATH, ['vbox1']) - self.board_size_spinbutton = self.xml.get_object('board_size') - self.board_size_spinbutton.get_adjustment().configure(3, 3, 10, 1, 1, 0) - vbox = self.xml.get_object('vbox1') - self.get_child().pack_start(vbox, True, True, 0) - - self.xml.connect_signals(self) - - def on_run(self): - self.board_size_spinbutton.set_value(self.plugin.config['board_size']) - - def board_size_value_changed(self, spinbutton): - self.plugin.config['board_size'] = int(spinbutton.get_value())