From 94cee3bdd2db050345f042658bdb99097402e7f1 Mon Sep 17 00:00:00 2001 From: Walter Bender Date: Mon, 29 Oct 2012 12:42:09 +0000 Subject: Merge git.sugarlabs.org:~walter/visualmatch/walter-gtk3 --- diff --git a/NEWS b/NEWS index 708f52d..caf1b2d 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,15 @@ +43 + +BUG FIX: +* Fixed name change in radio button (#4028) + +41 + +ENHANCEMENTS: +* GTK-3 version +* Added summary to activity.info +* Added support for touch + 39 BUG FIX: diff --git a/VisualMatchActivity.py b/VisualMatchActivity.py index 6557b68..9c249a1 100644 --- a/VisualMatchActivity.py +++ b/VisualMatchActivity.py @@ -11,47 +11,33 @@ # Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA -import pygtk -pygtk.require('2.0') -import gtk -import gobject - -from sugar.activity import activity -try: - from sugar.graphics.toolbarbox import ToolbarBox - _NEW_SUGAR_SYSTEM = True -except ImportError: - _NEW_SUGAR_SYSTEM = False -if _NEW_SUGAR_SYSTEM: - from sugar.activity.widgets import ActivityToolbarButton - from sugar.activity.widgets import StopButton - from sugar.graphics.toolbarbox import ToolbarButton -from sugar.graphics.alert import NotifyAlert -from sugar.datastore import datastore +from gi.repository import Gtk +from gi.repository import Gdk +from gi.repository import GObject + +from sugar3.activity import activity +from sugar3 import profile +from sugar3.graphics.toolbarbox import ToolbarBox +from sugar3.activity.widgets import ActivityToolbarButton +from sugar3.activity.widgets import StopButton +from sugar3.graphics.toolbarbox import ToolbarButton +from sugar3.graphics.alert import NotifyAlert +from sugar3.graphics import style +from sugar3.datastore import datastore import telepathy from dbus.service import signal from dbus.gobject_service import ExportedGObject -from sugar.presence import presenceservice -from sugar.presence.tubeconn import TubeConnection -from sugar.graphics import style +from sugar3.presence import presenceservice +from sugar3.presence.tubeconn import TubeConnection from gettext import gettext as _ import os.path import logging _logger = logging.getLogger('visualmatch-activity') -try: - _OLD_SUGAR_SYSTEM = False - import json - from json import load as jload - from json import dump as jdump -except(ImportError, AttributeError): - try: - import simplejson as json - from simplejson import load as jload - from simplejson import dump as jdump - except ImportError: - _OLD_SUGAR_SYSTEM = True +import json +from json import load as jload +from json import dump as jdump from StringIO import StringIO @@ -95,7 +81,7 @@ class VisualMatchActivity(activity.Activity): self.ready_to_play = False self._prompt = '' self._read_journal_data() - self._setup_toolbars(_NEW_SUGAR_SYSTEM) + self._setup_toolbars() canvas = self._setup_canvas() self._setup_presence_service() @@ -127,7 +113,7 @@ class VisualMatchActivity(activity.Activity): return self._notify_new_game(self._prompt) # a brief pause to give alert time to load - timeout = gobject.timeout_add(200, self._new_game, card_type) + timeout = GObject.timeout_add(200, self._new_game, card_type) def _new_game(self, card_type): if card_type == 'custom' and self.vmw.custom_paths[0] is None: @@ -255,73 +241,64 @@ class VisualMatchActivity(activity.Activity): jscores = '' for i, s in enumerate(self.vmw.all_scores): jscores += '%s: %s\n' % (str(i + 1), s) - gtk.Clipboard().set_text(jscores) + Gtk.Clipboard().set_text(jscores) - def _setup_toolbars(self, new_sugar_system): + def _setup_toolbars(self): ''' Setup the toolbars.. ''' - games_toolbar = gtk.Toolbar() - tools_toolbar = gtk.Toolbar() - numbers_toolbar = gtk.Toolbar() - if new_sugar_system: - toolbox = ToolbarBox() - - self.activity_toolbar_button = ActivityToolbarButton(self) - - toolbox.toolbar.insert(self.activity_toolbar_button, 0) - self.activity_toolbar_button.show() - - self.game_toolbar_button = ToolbarButton( - page=games_toolbar, - icon_name='new-game') - games_toolbar.show() - toolbox.toolbar.insert(self.game_toolbar_button, -1) - self.game_toolbar_button.show() - - self.numbers_toolbar_button = ToolbarButton( - page=numbers_toolbar, - icon_name='number-tools') - numbers_toolbar.show() - toolbox.toolbar.insert(self.numbers_toolbar_button, -1) - self.numbers_toolbar_button.show() - - self.tools_toolbar_button = ToolbarButton( - page=tools_toolbar, - icon_name='view-source') - tools_toolbar.show() - toolbox.toolbar.insert(self.tools_toolbar_button, -1) - self.tools_toolbar_button.show() - - self._set_labels(toolbox.toolbar) - separator_factory(toolbox.toolbar, True, False) - - help_button = HelpButton(self) - toolbox.toolbar.insert(help_button, -1) - help_button.show() - self._setup_toolbar_help() - - stop_button = StopButton(self) - stop_button.props.accelerator = 'q' - toolbox.toolbar.insert(stop_button, -1) - stop_button.show() - - export_scores = button_factory( - 'score-copy', self.activity_toolbar_button, - self._write_scores_to_clipboard, - tooltip=_('Export scores to clipboard')) - - self.set_toolbar_box(toolbox) - toolbox.show() - - self.game_toolbar_button.set_expanded(True) - else: - toolbox = activity.ActivityToolbox(self) - self.set_toolbox(toolbox) - toolbox.add_toolbar(_('Game'), games_toolbar) - toolbox.add_toolbar(_('Numbers'), numbers_toolbar) - toolbox.add_toolbar(_('Tools'), tools_toolbar) - toolbox.show() - toolbox.set_current_toolbar(1) + games_toolbar = Gtk.Toolbar() + tools_toolbar = Gtk.Toolbar() + numbers_toolbar = Gtk.Toolbar() + toolbox = ToolbarBox() + + self.activity_toolbar_button = ActivityToolbarButton(self) + + toolbox.toolbar.insert(self.activity_toolbar_button, 0) + self.activity_toolbar_button.show() + + self.game_toolbar_button = ToolbarButton( + page=games_toolbar, + icon_name='new-game') + games_toolbar.show() + toolbox.toolbar.insert(self.game_toolbar_button, -1) + self.game_toolbar_button.show() + + self.numbers_toolbar_button = ToolbarButton( + page=numbers_toolbar, + icon_name='number-tools') + numbers_toolbar.show() + toolbox.toolbar.insert(self.numbers_toolbar_button, -1) + self.numbers_toolbar_button.show() + + self.tools_toolbar_button = ToolbarButton( + page=tools_toolbar, + icon_name='view-source') + tools_toolbar.show() + toolbox.toolbar.insert(self.tools_toolbar_button, -1) + self.tools_toolbar_button.show() + + self._set_labels(toolbox.toolbar) + separator_factory(toolbox.toolbar, True, False) + + help_button = HelpButton(self) + toolbox.toolbar.insert(help_button, -1) + help_button.show() + self._setup_toolbar_help() + + stop_button = StopButton(self) + stop_button.props.accelerator = 'q' + toolbox.toolbar.insert(stop_button, -1) + stop_button.show() + + export_scores = button_factory( + 'score-copy', self.activity_toolbar_button, + self._write_scores_to_clipboard, + tooltip=_('Export scores to clipboard')) + + self.set_toolbar_box(toolbox) + toolbox.show() + + self.game_toolbar_button.set_expanded(True) self.button_pattern = button_factory( 'new-pattern-game', games_toolbar, self._select_game_cb, @@ -336,11 +313,7 @@ class VisualMatchActivity(activity.Activity): 'no-custom-game', games_toolbar, self._select_game_cb, cb_arg='custom', tooltip=PROMPT_DICT['custom']) - if new_sugar_system: - self._set_extras(games_toolbar, games_toolbar=True) - else: - self._set_labels(games_toolbar) - self._set_extras(tools_toolbar, games_toolbar=False) + self._set_extras(games_toolbar) self.words_tool_button = button_factory( 'word-tools', tools_toolbar, self._edit_words_cb, @@ -442,9 +415,8 @@ class VisualMatchActivity(activity.Activity): group=self.hash_button) NUMBER_C_BUTTONS[LINES] = self.lines_button - def _set_extras(self, toolbar, games_toolbar=True): - if games_toolbar: - separator_factory(toolbar, False, True) + def _set_extras(self, toolbar): + separator_factory(toolbar, False, True) self.robot_button = button_factory( 'robot-off', toolbar, self._robot_cb, tooltip=_('Play with the computer')) @@ -479,29 +451,25 @@ class VisualMatchActivity(activity.Activity): group=self.beginner_button) LEVEL_BUTTONS[EXPERT] = self.expert_button - self.level_label = label_factory(toolbar, self.calc_level_label( - self._low_score, self._play_level)) - - if not games_toolbar: - separator_factory(toolbar, False, True) + self.level_label = label_factory(self.calc_level_label( + self._low_score, self._play_level), toolbar) def _set_labels(self, toolbar): ''' Add labels to toolbar toolbar ''' - self.status_label = label_factory(toolbar, _('Find a match.')) + self.status_label = label_factory(_('Find a match.'), toolbar) separator_factory(toolbar, False, True) self.deck_label = label_factory( - toolbar, '%d %s' % (LEVEL_DECKSIZE[self._play_level] - DEAL, - _('cards'))) + '%d %s' % (LEVEL_DECKSIZE[self._play_level] - DEAL, _('cards')), + toolbar) separator_factory(toolbar, False, True) - self.match_label = label_factory(toolbar, '%d %s' % (0, _('matches'))) + self.match_label = label_factory('%d %s' % (0, _('matches')), toolbar) separator_factory(toolbar, False, True) - self.clock_label = label_factory(toolbar, '-') + self.clock_label = label_factory('-', toolbar) def _setup_canvas(self): ''' Create a canvas.. ''' - canvas = gtk.DrawingArea() - canvas.set_size_request(gtk.gdk.screen_width(), - gtk.gdk.screen_height()) + canvas = Gtk.DrawingArea() + canvas.set_size_request(Gdk.Screen.width(), Gdk.Screen.height()) self.set_canvas(canvas) canvas.show() self.show_all() @@ -596,12 +564,9 @@ class VisualMatchActivity(activity.Activity): return self._data_dumper(data) def _data_dumper(self, data): - if _OLD_SUGAR_SYSTEM: - return json.write(data) - else: - io = StringIO() - jdump(data, io) - return io.getvalue() + io = StringIO() + jdump(data, io) + return io.getvalue() def read_file(self, file_path): ''' Read data from the Journal. ''' @@ -616,11 +581,8 @@ class VisualMatchActivity(activity.Activity): self._saved_state = saved_state def _data_loader(self, data): - if _OLD_SUGAR_SYSTEM: - return json.read(data) - else: - io = StringIO(data) - return jload(io) + io = StringIO(data) + return jload(io) def _notify_new_game(self, prompt): ''' Called from New Game button since loading a new game can @@ -637,16 +599,17 @@ class VisualMatchActivity(activity.Activity): alert.show() def _new_help_box(self, name, button=None): - help_box = gtk.VBox() + help_box = Gtk.VBox() help_box.set_homogeneous(False) help_palettes[name] = help_box if button is not None: help_buttons[name] = button - help_windows[name] = gtk.ScrolledWindow() + help_windows[name] = Gtk.ScrolledWindow() help_windows[name].set_size_request( - int(gtk.gdk.screen_width() / 3), - gtk.gdk.screen_height() - style.GRID_CELL_SIZE * 3) - help_windows[name].set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) + int(Gdk.Screen.width() / 3), + Gdk.Screen.height() - style.GRID_CELL_SIZE * 3) + help_windows[name].set_policy(Gtk.PolicyType.NEVER, + Gtk.PolicyType.AUTOMATIC) help_windows[name].add_with_viewport(help_palettes[name]) help_palettes[name].show() return help_box diff --git a/activity/activity.info b/activity/activity.info index 99db48a..85b61ef 100644 --- a/activity/activity.info +++ b/activity/activity.info @@ -1,9 +1,10 @@ [Activity] #TRANS: Please translate Visual Match as Dimensions name = Visual Match -activity_version = 39 +activity_version = 43 license = GPLv3 bundle_id = org.sugarlabs.VisualMatchActivity exec = sugar-activity VisualMatchActivity.VisualMatchActivity icon = activity-visualmatch show_launcher = yes +summary = a pattern-matching game diff --git a/card.py b/card.py index 69f7f31..c6b4cb6 100644 --- a/card.py +++ b/card.py @@ -10,10 +10,7 @@ # along with this library; if not, write to the Free Software # Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA - -import pygtk -pygtk.require('2.0') -import gtk +from gi.repository import Gdk, GdkPixbuf import logging _logger = logging.getLogger('visualmatch-activity') @@ -74,7 +71,7 @@ class Card: def svg_str_to_pixbuf(string): ''' Load pixbuf from SVG string ''' - pl = gtk.gdk.PixbufLoader('svg') + pl = GdkPixbuf.PixbufLoader.new_with_type('svg') pl.write(string) pl.close() pixbuf = pl.get_pixbuf() @@ -83,6 +80,6 @@ def svg_str_to_pixbuf(string): def load_image(object, scale): ''' Load pixbuf from file ''' - return gtk.gdk.pixbuf_new_from_file_at_size(object.file_path, - int(scale * CARD_WIDTH * .75), - int(scale * CARD_HEIGHT * .75)) + return GdkPixbuf.Pixbuf.new_from_file_at_size( + object.file_path, int(scale * CARD_WIDTH * .75), + int(scale * CARD_HEIGHT * .75)) diff --git a/deck.py b/deck.py index ca145f3..47573e1 100644 --- a/deck.py +++ b/deck.py @@ -10,9 +10,6 @@ # Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA -import pygtk -pygtk.require('2.0') -import gtk from random import randrange from constants import HIGH, MEDIUM, LOW, FILLS, SHAPES, NUMBER, COLORS, \ diff --git a/game.py b/game.py index 21b6693..0760ca9 100644 --- a/game.py +++ b/game.py @@ -13,30 +13,27 @@ # Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA -import pygtk -pygtk.require('2.0') -import gtk -import gobject - +import gi +from gi.repository import Gtk +from gi.repository import Gdk +from gi.repository import GdkPixbuf +from gi.repository import GObject import os from gettext import gettext as _ from math import sqrt -from sugar.graphics.objectchooser import ObjectChooser -from sugar.datastore import datastore -from sugar import mime -from sugar.activity import activity +from sugar3.graphics.objectchooser import ObjectChooser +from sugar3.datastore import datastore +from sugar3 import mime +from sugar3.activity import activity import logging _logger = logging.getLogger('visualmatch-activity') -try: - from sugar.graphics import style - GRID_CELL_SIZE = style.GRID_CELL_SIZE -except ImportError: - GRID_CELL_SIZE = 0 +from sugar3.graphics import style +GRID_CELL_SIZE = style.GRID_CELL_SIZE from constants import LOW, MEDIUM, HIGH, MATCHMASK, ROW, COL, \ WORD_CARD_INDICIES, DEAD_DICTS, DEAD_KEYS, WHITE_SPACE, \ @@ -117,17 +114,19 @@ class Game(): self._canvas = canvas parent.show_all() - self._canvas.set_flags(gtk.CAN_FOCUS) - self._canvas.connect('expose-event', self._expose_cb) - self._canvas.add_events(gtk.gdk.BUTTON_PRESS_MASK) - self._canvas.connect('button-press-event', self._button_press_cb) - self._canvas.add_events(gtk.gdk.BUTTON_RELEASE_MASK) - self._canvas.connect('button-release-event', self._button_release_cb) - self._canvas.add_events(gtk.gdk.POINTER_MOTION_MASK) - self._canvas.connect("motion-notify-event", self._mouse_move_cb) - self._canvas.connect('key_press_event', self._keypress_cb) - self._width = gtk.gdk.screen_width() - self._height = gtk.gdk.screen_height() - GRID_CELL_SIZE + self._canvas.set_can_focus(True) + + self._canvas.add_events(Gdk.EventMask.TOUCH_MASK) + self._canvas.add_events(Gdk.EventMask.BUTTON_PRESS_MASK) + self._canvas.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK) + self._canvas.add_events(Gdk.EventMask.BUTTON_MOTION_MASK) + self._canvas.add_events(Gdk.EventMask.KEY_PRESS_MASK) + + self._canvas.connect('event', self.__event_cb) + self._canvas.connect('draw', self.__draw_cb) + + self._width = Gdk.Screen.width() + self._height = Gdk.Screen.height() - GRID_CELL_SIZE self._scale = 0.8 * self._height / (CARD_HEIGHT * 5.5) self._card_width = CARD_WIDTH * self._scale self._card_height = CARD_HEIGHT * self._scale @@ -222,7 +221,7 @@ class Game(): self._saved_state = saved_state self._deck_index = deck_index # Wait for any animations to stop before starting new game - timeout = gobject.timeout_add(200, self._prepare_new_game) + timeout = GObject.timeout_add(200, self._prepare_new_game) def _prepare_new_game(self): # If there is already a deck, hide it. @@ -294,11 +293,11 @@ class Game(): if self._game_over(): if hasattr(self, 'timeout_id') and self.timeout_id is not None: - gobject.source_remove(self.timeout_id) + GObject.source_remove(self.timeout_id) else: if hasattr(self, 'match_timeout_id') and \ self.match_timeout_id is not None: - gobject.source_remove(self.match_timeout_id) + GObject.source_remove(self.match_timeout_id) self._timer_reset() for i in range((ROW - 1) * COL): @@ -347,7 +346,7 @@ class Game(): self._edit_card = None self._dead_key = None if hasattr(self, 'timeout_id') and self.timeout_id is not None: - gobject.source_remove(self.timeout_id) + GObject.source_remove(self.timeout_id) # Fill the grid with custom cards. self.grid.restore(self.deck, CUSTOM_CARD_INDICIES) @@ -376,7 +375,7 @@ class Game(): self._edit_card = None self._dead_key = None if hasattr(self, 'timeout_id') and self.timeout_id is not None: - gobject.source_remove(self.timeout_id) + GObject.source_remove(self.timeout_id) # Fill the grid with word cards. self.grid.restore(self.deck, WORD_CARD_INDICIES) self.set_label('deck', '') @@ -384,10 +383,39 @@ class Game(): self.set_label('clock', '') self.set_label('status', _('Edit the word cards.')) + def __event_cb(self, widget, event): + ''' Handle touch events ''' + if event.type in (Gdk.EventType.TOUCH_BEGIN, + Gdk.EventType.TOUCH_END, + Gdk.EventType.TOUCH_UPDATE, + Gdk.EventType.BUTTON_PRESS, + Gdk.EventType.BUTTON_RELEASE, + Gdk.EventType.MOTION_NOTIFY): + x = event.get_coords()[1] + y = event.get_coords()[2] + if event.type == Gdk.EventType.TOUCH_BEGIN or \ + event.type == Gdk.EventType.BUTTON_PRESS: + self._button_press(x, y) + elif event.type == Gdk.EventType.TOUCH_UPDATE or \ + event.type == Gdk.EventType.MOTION_NOTIFY: + self._drag_event(x, y) + elif event.type == Gdk.EventType.TOUCH_END or \ + event.type == Gdk.EventType.BUTTON_RELEASE: + self._button_release(x, y) + elif event.type == Gdk.EventType.KEY_PRESS: + k = Gdk.keyval_name(event.keyval) + u = Gdk.keyval_to_unicode(event.keyval) + self._keypress(k, u) + def _button_press_cb(self, win, event): ''' Look for a card under the button press and save its position. ''' win.grab_focus() + x, y = map(int, event.get_coords()) + self._button_press(x, y) + + def _button_press(self, x, y): + # Turn off help animation if not self._stop_help: self._stop_help = True @@ -402,7 +430,6 @@ class Game(): return True # Find the sprite under the mouse. - x, y = map(int, event.get_coords()) spr = self._sprites.find_sprite((x, y)) # If there is a match showing, hide it. @@ -470,13 +497,16 @@ class Game(): def _mouse_move_cb(self, win, event): ''' Drag the card with the mouse. ''' + win.grab_focus() + x, y = map(int, event.get_coords()) + self._drag_event(x, y) + + def _drag_event(self, x, y): if self._press is None or \ self.editing_word_list or \ self.editing_custom_cards: self._drag_pos = [0, 0] return True - win.grab_focus() - x, y = map(int, event.get_coords()) dx = x - self._drag_pos[0] dy = y - self._drag_pos[1] self._press.set_layer(5000) @@ -486,7 +516,10 @@ class Game(): def _button_release_cb(self, win, event): ''' Lots of possibilities here between clicks and drags ''' win.grab_focus() + x, y = map(int, event.get_coords()) + self._button_release(x, y) + def _button_release(self, x, y): # Maybe there is nothing to do. if self._press is None: self._drag_pos = [0, 0] @@ -495,7 +528,6 @@ class Game(): self._press.set_layer(2000) # Determine if it was a click, a drag, or an aborted drag - x, y = map(int, event.get_coords()) d = _distance((x, y), (self._start_pos[0], self._start_pos[1])) if d < self._card_width / 10: # click move = 'click' @@ -722,7 +754,7 @@ match area (%d)' % (i)) for i in range((ROW - 1) * COL): if self.grid.grid[i] == None: self._smiley[i].show_card() - self.match_timeout_id = gobject.timeout_add( + self.match_timeout_id = GObject.timeout_add( 2000, self._show_matches, 0) self._the_game_is_over = True elif self.grid.cards_in_grid() == DEAL + 3 \ @@ -743,8 +775,8 @@ match area (%d)' % (i)) # Stop the timer. if hasattr(self, 'timeout_id'): if self.timeout_id is not None: - gobject.source_remove(self.timeout_id) - self.total_time += gobject.get_current_time() - self.start_time + GObject.source_remove(self.timeout_id) + self.total_time += GObject.get_current_time() - self.start_time # Increment the match counter and add the match to the match list. self.matches += 1 @@ -755,7 +787,7 @@ match area (%d)' % (i)) # Test to see if the game is over. if self._game_over(): if hasattr(self, 'timeout_id'): - gobject.source_remove(self.timeout_id) + GObject.source_remove(self.timeout_id) if self.low_score[self.level] == -1: self.low_score[self.level] = self.total_time elif self.total_time < self.low_score[self.level]: @@ -773,7 +805,7 @@ match area (%d)' % (i)) else: # Wait a few seconds before dealing new cards. self._dealing = True - gobject.timeout_add(2000, self._deal_new_cards) + GObject.timeout_add(2000, self._deal_new_cards) # Keep playing. self._update_labels() @@ -813,8 +845,11 @@ match area (%d)' % (i)) def _keypress_cb(self, area, event): ''' Keypress: editing word cards or selecting cards to play ''' - k = gtk.gdk.keyval_name(event.keyval) - u = gtk.gdk.keyval_to_unicode(event.keyval) + k = Gdk.keyval_name(event.keyval) + u = Gdk.keyval_to_unicode(event.keyval) + self._keypress(k, u) + + def _keypress(self, k, u): if self.editing_word_list and self._edit_card is not None: if k in NOISE_KEYS: self._dead_key = None @@ -884,6 +919,9 @@ match area (%d)' % (i)) self.process_selection(self.grid.grid_to_spr(KEYMAP.index(k))) return True + def __draw_cb(self, canvas, cr): + self._sprites.redraw_sprites(cr=cr) + def _expose_cb(self, win, event): ''' Callback to handle window expose events ''' self.do_expose_event(event) @@ -906,7 +944,7 @@ match area (%d)' % (i)) def _destroy_cb(self, win, event): ''' This is the end ''' - gtk.main_quit() + Gtk.main_quit() def _update_labels(self): ''' Write strings to a label in the toolbar. ''' @@ -979,16 +1017,16 @@ match area (%d)' % (i)) def _counter(self): ''' Display of seconds since start_time. ''' - seconds = int(gobject.get_current_time() - self.start_time) + seconds = int(GObject.get_current_time() - self.start_time) self.set_label('clock', str(seconds)) if self.robot and self.robot_time < seconds: self._find_a_match(robot_match=True) else: - self.timeout_id = gobject.timeout_add(1000, self._counter) + self.timeout_id = GObject.timeout_add(1000, self._counter) def _timer_reset(self): ''' Reset the timer for the robot ''' - self.start_time = gobject.get_current_time() + self.start_time = GObject.get_current_time() self.timeout_id = None self._counter() @@ -999,7 +1037,7 @@ match area (%d)' % (i)) for j in range(CARDS_IN_A_MATCH): self.grid.display_match( self.match_list[i * CARDS_IN_A_MATCH + j], j) - self.match_timeout_id = gobject.timeout_add( + self.match_timeout_id = GObject.timeout_add( 2000, self._show_matches, i + 1) def _find_a_match(self, robot_match=False): @@ -1008,7 +1046,7 @@ match area (%d)' % (i)) if self._matches_on_display: if not self.deck.empty(): self._matches_on_display = False - gobject.timeout_add(1000, self.clean_up_match) + GObject.timeout_add(1000, self.clean_up_match) else: for c in self.clicked: if c.spr is not None: @@ -1096,13 +1134,14 @@ match area (%d)' % (i)) try: chooser = ObjectChooser(parent=self, what_filter=None) except TypeError: - chooser = ObjectChooser(None, self.activity, - gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) + chooser = ObjectChooser( + None, self.activity, + Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT) if chooser is not None: try: result = chooser.run() - if result == gtk.RESPONSE_ACCEPT: + if result == Gtk.ResponseType.ACCEPT: jobject = chooser.get_selected_object() if jobject and jobject.file_path: name = jobject.metadata['title'] @@ -1188,7 +1227,7 @@ match area (%d)' % (i)) self._help_index = 0 self._stop_help = False self._help[self._help_index].set_layer(5000) - self._help_timeout_id = gobject.timeout_add(2000, self._help_next) + self._help_timeout_id = GObject.timeout_add(2000, self._help_next) def _help_next(self): ''' Load the next frame in the animation ''' @@ -1200,9 +1239,9 @@ match area (%d)' % (i)) self._help_index %= len(self._help) self._help[self._help_index].set_layer(5000) if self._help_index in [0, 9, 10, 20, 21]: - self._help_timeout_id = gobject.timeout_add(2000, self._help_next) + self._help_timeout_id = GObject.timeout_add(2000, self._help_next) else: - self._help_timeout_id = gobject.timeout_add(1000, self._help_next) + self._help_timeout_id = GObject.timeout_add(1000, self._help_next) class Permutation: @@ -1229,7 +1268,7 @@ class Permutation: def svg_str_to_pixbuf(svg_string, w, h): """ Load pixbuf from SVG string """ - pl = gtk.gdk.PixbufLoader('svg') + pl = GdkPixbuf.PixbufLoader.new_with_type('svg') pl.set_size(w, h) pl.write(svg_string) pl.close() diff --git a/grid.py b/grid.py index f9b0900..03e2078 100644 --- a/grid.py +++ b/grid.py @@ -10,10 +10,7 @@ # Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA -import pygtk -pygtk.require('2.0') -import gtk -import gobject +from gi.repository import GObject import random @@ -105,7 +102,7 @@ class Grid: i = self.find_an_empty_slot() # Put new card in grid position of card we are replacing. self.grid[i] = deck.deal_next_card() - timeout_id = gobject.timeout_add( + timeout_id = GObject.timeout_add( 1200, self.place_a_card, self.grid[i], self.grid_to_xy(i)[0], self.grid_to_xy(i)[1], j) @@ -119,7 +116,7 @@ class Grid: self.sy[i] = spr.get_xy()[1] self.dx[i] = int((self.ex[i] - self.sx[i]) / 10) self.dy[i] = int((self.ey[i] - self.sy[i]) / 10) - timeout_id = gobject.timeout_add( + timeout_id = GObject.timeout_add( 100, self._move_to_position, spr, i) def return_to_grid(self, spr, i, j): @@ -133,7 +130,7 @@ class Grid: self.sy[j] = spr.get_xy()[1] self.dx[j] = int((self.ex[j] - self.sx[j]) / 10) self.dy[j] = int((self.ey[j] - self.sy[j]) / 10) - timeout_id = gobject.timeout_add( + timeout_id = GObject.timeout_add( 100, self._move_to_position, spr, j) def _move_to_position(self, spr, i): @@ -146,7 +143,7 @@ class Grid: spr.move((self.ex[i], self.ey[i])) self.animation_lock[i] = False else: - timeout_id = gobject.timeout_add( + timeout_id = GObject.timeout_add( 100, self._move_to_position, spr, i) def consolidate(self): @@ -180,7 +177,7 @@ class Grid: self.dy[animate + 3] = int( (self.ey[animate + 3] - c.spr.get_xy()[1]) / 10) self.animation_lock[animate + 3] = True - timeout_id = gobject.timeout_add(100, self._move_to_position, + timeout_id = GObject.timeout_add(100, self._move_to_position, c.spr, animate + 3) def xy_to_match(self, pos): diff --git a/helpbutton.py b/helpbutton.py index 6c4540b..cea6110 100644 --- a/helpbutton.py +++ b/helpbutton.py @@ -21,11 +21,12 @@ from gettext import gettext as _ -import gtk +from gi.repository import Gtk +from gi.repository import Gdk -from sugar.graphics.toolbutton import ToolButton -from sugar.graphics.icon import Icon -from sugar.graphics import style +from sugar3.graphics.toolbutton import ToolButton +from sugar3.graphics.icon import Icon +from sugar3.graphics import style help_windows = {} help_buttons = {} @@ -34,13 +35,13 @@ import logging _logger = logging.getLogger('visualmatch-activity') -class HelpButton(gtk.ToolItem): +class HelpButton(Gtk.ToolItem): def __init__(self, activity): self._activity = activity self._current_palette = 'game' - gtk.ToolItem.__init__(self) + Gtk.ToolItem.__init__(self) help_button = ToolButton('help-toolbar') help_button.set_tooltip(_('Help')) @@ -85,9 +86,9 @@ class HelpButton(gtk.ToolItem): def add_section(help_box, section_text, icon=None): ''' Add a section to the help palette. From helpbutton.py by Gonzalo Odiard ''' - max_text_width = int(gtk.gdk.screen_width() / 3) - 20 - hbox = gtk.HBox() - label = gtk.Label() + max_text_width = int(Gdk.Screen.width() / 3) - 20 + hbox = Gtk.HBox() + label = Gtk.Label() label.set_use_markup(True) label.set_markup('%s' % section_text) label.set_line_wrap(True) @@ -107,10 +108,10 @@ def add_section(help_box, section_text, icon=None): def add_paragraph(help_box, text, icon=None): ''' Add an entry to the help palette. From helpbutton.py by Gonzalo Odiard ''' - max_text_width = int(gtk.gdk.screen_width() / 3) - 20 - hbox = gtk.HBox() - label = gtk.Label(text) - label.set_justify(gtk.JUSTIFY_LEFT) + max_text_width = int(Gdk.Screen.width() / 3) - 20 + hbox = Gtk.HBox() + label = Gtk.Label(label=text) + label.set_justify(Gtk.Justification.LEFT) label.set_line_wrap(True) hbox.add(label) if icon is not None: diff --git a/setup.py b/setup.py index bd1e319..bdeaed6 100755 --- a/setup.py +++ b/setup.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -from sugar.activity import bundlebuilder +from sugar3.activity import bundlebuilder if __name__ == "__main__": bundlebuilder.start() diff --git a/sprites.py b/sprites.py index 8e4c8c5..e128369 100644 --- a/sprites.py +++ b/sprites.py @@ -24,7 +24,7 @@ ''' sprites.py is a simple sprites library for managing graphics objects, -'sprites', on a gtk.DrawingArea. It manages multiple sprites with +'sprites', on a Gtk.DrawingArea. It manages multiple sprites with methods such as move, hide, set_layer, etc. There are two classes: @@ -68,7 +68,7 @@ Example usage: # method for converting SVG to a gtk pixbuf def svg_str_to_pixbuf(svg_string): - pl = gtk.gdk.PixbufLoader('svg') + pl = GdkPixbuf.PixbufLoader('svg') pl.write(svg_string) pl.close() pixbuf = pl.get_pixbuf() @@ -76,12 +76,9 @@ def svg_str_to_pixbuf(svg_string): ''' -import pygtk -pygtk.require('2.0') -import gtk -import pango -import pangocairo -import cairo +import gi +from gi.repository import Gtk, GdkPixbuf, Gdk +from gi.repository import Pango, PangoCairo class Sprites: @@ -89,9 +86,9 @@ class Sprites: def __init__(self, widget): ''' Initialize an empty array of sprites ''' + self.cr = None self.widget = widget self.list = [] - self.cr = None def set_cairo_context(self, cr): ''' Cairo context may be set or reset after __init__ ''' @@ -99,7 +96,7 @@ class Sprites: def get_sprite(self, i): ''' Return a sprint from the array ''' - if i < 0 or i > len(self.list) - 1: + if i < 0 or i > len(self.list)-1: return(None) else: return(self.list[i]) @@ -121,23 +118,17 @@ class Sprites: else: self.list.insert(i, spr) - def find_in_list(self, spr): - if spr in self.list: - return True - return False - def remove_from_list(self, spr): ''' Remove a sprite from the list. ''' if spr in self.list: self.list.remove(spr) - def find_sprite(self, pos, region=False, reverse=False): + def find_sprite(self, pos): ''' Search based on (x, y) position. Return the 'top/first' one. ''' list = self.list[:] - if not reverse: - list.reverse() + list.reverse() for spr in list: - if spr.hit(pos, readpixel=not region): + if spr.hit(pos): return spr return None @@ -149,7 +140,7 @@ class Sprites: else: self.cr = cr if cr is None: - # print 'sprites.redraw_sprites: no Cairo context' + print 'sprites.redraw_sprites: no Cairo context' return for spr in self.list: if area == None: @@ -166,8 +157,7 @@ class Sprite: def __init__(self, sprites, x, y, image): ''' Initialize an individual sprite ''' self._sprites = sprites - self.save_xy = (x, y) # remember initial (x, y) position - self.rect = gtk.gdk.Rectangle(int(x), int(y), 0, 0) + self.rect = [int(x), int(y), 0, 0] self._scale = [12] self._rescale = [True] self._horiz_align = ["center"] @@ -179,7 +169,7 @@ class Sprite: self._margins = [0, 0, 0, 0] self.layer = 100 self.labels = [] - self.cached_surfaces = [] + self.images = [] self._dx = [] # image offsets self._dy = [] self.type = None @@ -188,58 +178,47 @@ class Sprite: def set_image(self, image, i=0, dx=0, dy=0): ''' Add an image to the sprite. ''' - while len(self.cached_surfaces) < i + 1: - self.cached_surfaces.append(None) + while len(self.images) < i + 1: + self.images.append(None) self._dx.append(0) self._dy.append(0) + self.images[i] = image self._dx[i] = dx self._dy[i] = dy - if isinstance(image, gtk.gdk.Pixbuf) or \ - isinstance(image, cairo.ImageSurface): - w = image.get_width() - h = image.get_height() + if isinstance(self.images[i], GdkPixbuf.Pixbuf): + w = self.images[i].get_width() + h = self.images[i].get_height() else: - w, h = image.get_size() + w, h = self.images[i].get_size() if i == 0: # Always reset width and height when base image changes. - self.rect.width = w + dx - self.rect.height = h + dy + self.rect[2] = w + dx + self.rect[3] = h + dy else: - if w + dx > self.rect.width: - self.rect.width = w + dx - if h + dy > self.rect.height: - self.rect.height = h + dy - if isinstance(image, cairo.ImageSurface): - self.cached_surfaces[i] = image - else: # Convert to Cairo surface - surface = cairo.ImageSurface( - cairo.FORMAT_ARGB32, self.rect.width, self.rect.height) - context = cairo.Context(surface) - context = gtk.gdk.CairoContext(context) - context.set_source_pixbuf(image, 0, 0) - context.rectangle(0, 0, self.rect.width, self.rect.height) - context.fill() - self.cached_surfaces[i] = surface + if w + dx > self.rect[2]: + self.rect[2] = w + dx + if h + dy > self.rect[3]: + self.rect[3] = h + dy def move(self, pos): ''' Move to new (x, y) position ''' self.inval() - self.rect.x, self.rect.y = int(pos[0]), int(pos[1]) + self.rect[0], self.rect[1] = int(pos[0]), int(pos[1]) self.inval() def move_relative(self, pos): ''' Move to new (x+dx, y+dy) position ''' self.inval() - self.rect.x += int(pos[0]) - self.rect.y += int(pos[1]) + self.rect[0] += int(pos[0]) + self.rect[1] += int(pos[1]) self.inval() def get_xy(self): ''' Return current (x, y) position ''' - return (self.rect.x, self.rect.y) + return (self.rect[0], self.rect[1]) def get_dimensions(self): ''' Return current size ''' - return (self.rect.width, self.rect.height) + return (self.rect[2], self.rect[3]) def get_layer(self): ''' Return current layer ''' @@ -251,11 +230,10 @@ class Sprite: self.set_image(image, i) self.inval() - def set_layer(self, layer=None): + def set_layer(self, layer): ''' Set the layer for a sprite ''' self._sprites.remove_from_list(self) - if layer is not None: - self.layer = layer + self.layer = layer for i in range(self._sprites.length_of_list()): if layer < self._sprites.get_sprite(i).layer: self._sprites.insert_in_list(self, i) @@ -283,7 +261,7 @@ class Sprite: if self._fd is None: self.set_font('Sans') if self._color is None: - self._color = (0., 0., 0.) + self._color = (0.5, 0.5, 0.5) while len(self.labels) < i + 1: self.labels.append(" ") self._scale.append(self._scale[0]) @@ -293,7 +271,7 @@ class Sprite: def set_font(self, font): ''' Set the font for a label ''' - self._fd = pango.FontDescription(font) + self._fd = Pango.FontDescription(font) def set_label_color(self, rgb): ''' Set the font color for a label ''' @@ -324,145 +302,136 @@ class Sprite: self.inval() self._sprites.remove_from_list(self) - def restore(self): - ''' Restore a hidden sprite ''' - self.set_layer() - def inval(self): ''' Invalidate a region for gtk ''' - self._sprites.widget.queue_draw_area(self.rect.x, - self.rect.y, - self.rect.width, - self.rect.height) + # self._sprites.window.invalidate_rect(self.rect, False) + self._sprites.widget.queue_draw_area(self.rect[0], + self.rect[1], + self.rect[2], + self.rect[3]) def draw(self, cr=None): ''' Draw the sprite (and label) ''' if cr is None: - # print 'sprite.draw: no Cairo context.' + cr = self._sprites.cr + if cr is None: + print 'sprite.draw: no Cairo context.' return - for i, surface in enumerate(self.cached_surfaces): - cr.set_source_surface(surface, - self.rect.x + self._dx[i], - self.rect.y + self._dy[i]) - cr.rectangle(self.rect.x + self._dx[i], - self.rect.y + self._dy[i], - self.rect.width, - self.rect.height) - cr.fill() + for i, img in enumerate(self.images): + if isinstance(img, GdkPixbuf.Pixbuf): + Gdk.cairo_set_source_pixbuf(cr, img, + self.rect[0] + self._dx[i], + self.rect[1] + self._dy[i]) + cr.rectangle(self.rect[0] + self._dx[i], + self.rect[1] + self._dy[i], + self.rect[2], + self.rect[3]) + cr.fill() + else: + print 'sprite.draw: source not a pixbuf (%s)' % (type(img)) if len(self.labels) > 0: self.draw_label(cr) - def hit(self, pos, readpixel=False): + def hit(self, pos): ''' Is (x, y) on top of the sprite? ''' x, y = pos - if x < self.rect.x: + if x < self.rect[0]: return False - if x > self.rect.x + self.rect.width: + if x > self.rect[0] + self.rect[2]: return False - if y < self.rect.y: + if y < self.rect[1]: return False - if y > self.rect.y + self.rect.height: + if y > self.rect[1] + self.rect[3]: return False - if readpixel: - r, g, b, a = self.get_pixel(pos) - if r == g == b == a == 0: - return False - if a == -1: - return False - return self._sprites.find_in_list(self) + return True def draw_label(self, cr): ''' Draw the label based on its attributes ''' - # Create a pangocairo context - cr = pangocairo.CairoContext(cr) - my_width = self.rect.width - self._margins[0] - self._margins[2] + my_width = self.rect[2] - self._margins[0] - self._margins[2] if my_width < 0: my_width = 0 - my_height = self.rect.height - self._margins[1] - self._margins[3] + my_height = self.rect[3] - self._margins[1] - self._margins[3] for i in range(len(self.labels)): - pl = cr.create_layout() - pl.set_text(str(self.labels[i])) - self._fd.set_size(int(self._scale[i] * pango.SCALE)) + pl = PangoCairo.create_layout(cr) + pl.set_text(str(self.labels[i]), -1) + self._fd.set_size(int(self._scale[i] * Pango.SCALE)) pl.set_font_description(self._fd) - w = pl.get_size()[0] / pango.SCALE + w = pl.get_size()[0] / Pango.SCALE if w > my_width: if self._rescale[i]: self._fd.set_size( - int(self._scale[i] * pango.SCALE * my_width / w)) + int(self._scale[i] * Pango.SCALE * my_width / w)) pl.set_font_description(self._fd) - w = pl.get_size()[0] / pango.SCALE + w = pl.get_size()[0] / Pango.SCALE else: j = len(self.labels[i]) - 1 while(w > my_width and j > 0): pl.set_text( - "…" + self.labels[i][len(self.labels[i]) - j:]) - self._fd.set_size(int(self._scale[i] * pango.SCALE)) + "…" + self.labels[i][len(self.labels[i]) - j:], -1) + self._fd.set_size(int(self._scale[i] * Pango.SCALE)) pl.set_font_description(self._fd) - w = pl.get_size()[0] / pango.SCALE + w = pl.get_size()[0] / Pango.SCALE j -= 1 if self._horiz_align[i] == "center": - x = int(self.rect.x + self._margins[0] + (my_width - w) / 2) + x = int(self.rect[0] + self._margins[0] + (my_width - w) / 2) elif self._horiz_align[i] == 'left': - x = int(self.rect.x + self._margins[0]) - else: # right - x = int(self.rect.x + self.rect.width - w - self._margins[2]) - h = pl.get_size()[1] / pango.SCALE + x = int(self.rect[0] + self._margins[0]) + else: # right + x = int(self.rect[0] + self.rect[2] - w - self._margins[2]) + h = pl.get_size()[1] / Pango.SCALE if self._vert_align[i] == "middle": - y = int(self.rect.y + self._margins[1] + (my_height - h) / 2) + y = int(self.rect[1] + self._margins[1] + (my_height - h) / 2) elif self._vert_align[i] == "top": - y = int(self.rect.y + self._margins[1]) - else: # bottom - y = int(self.rect.y + self.rect.height - h - self._margins[3]) + y = int(self.rect[1] + self._margins[1]) + else: # bottom + y = int(self.rect[1] + self.rect[3] - h - self._margins[3]) cr.save() cr.translate(x, y) cr.set_source_rgb(self._color[0], self._color[1], self._color[2]) - cr.update_layout(pl) - cr.show_layout(pl) + PangoCairo.update_layout(cr, pl) + PangoCairo.show_layout(cr, pl) cr.restore() def label_width(self): ''' Calculate the width of a label ''' - cr = pangocairo.CairoContext(self._sprites.cr) - if cr is not None: - max = 0 - for i in range(len(self.labels)): - pl = cr.create_layout() - pl.set_text(self.labels[i]) - self._fd.set_size(int(self._scale[i] * pango.SCALE)) - pl.set_font_description(self._fd) - w = pl.get_size()[0] / pango.SCALE - if w > max: - max = w - return max - else: - return self.rect.width + max = 0 + for i in range(len(self.labels)): + pl = self._sprites.canvas.create_pango_layout(self.labels[i]) + self._fd.set_size(int(self._scale[i] * Pango.SCALE)) + pl.set_font_description(self._fd) + w = pl.get_size()[0] / Pango.SCALE + if w > max: + max = w + return max def label_safe_width(self): ''' Return maximum width for a label ''' - return self.rect.width - self._margins[0] - self._margins[2] + return self.rect[2] - self._margins[0] - self._margins[2] def label_safe_height(self): ''' Return maximum height for a label ''' - return self.rect.height - self._margins[1] - self._margins[3] + return self.rect[3] - self._margins[1] - self._margins[3] def label_left_top(self): ''' Return the upper-left corner of the label safe zone ''' return(self._margins[0], self._margins[1]) def get_pixel(self, pos, i=0): - ''' Return the pixel at (x, y) ''' - x = int(pos[0] - self.rect.x) - y = int(pos[1] - self.rect.y) - if x < 0 or x > (self.rect.width - 1) or \ - y < 0 or y > (self.rect.height - 1): + ''' Return the pixl at (x, y) ''' + x, y = pos + x = x - self.rect[0] + y = y - self.rect[1] + if y > self.images[i].get_height() - 1: + return(-1, -1, -1, -1) + try: + array = self.images[i].get_pixels() + if array is not None: + offset = (y * self.images[i].get_width() + x) * 4 + r, g, b, a = ord(array[offset]), ord(array[offset + 1]),\ + ord(array[offset + 2]), ord(array[offset + 3]) + return(r, g, b, a) + else: + return(-1, -1, -1, -1) + except IndexError: + print "Index Error: %d %d" % (len(array), offset) return(-1, -1, -1, -1) - # Create a new 1x1 cairo surface. - cs = cairo.ImageSurface(cairo.FORMAT_RGB24, 1, 1) - cr = cairo.Context(cs) - cr.set_source_surface(self.cached_surfaces[i], -x, -y) - cr.rectangle(0, 0, 1, 1) - cr.set_operator(cairo.OPERATOR_SOURCE) - cr.fill() - cs.flush() # Ensure all the writing is done. - pixels = cs.get_data() # Read the pixel. - return (ord(pixels[2]), ord(pixels[1]), ord(pixels[0]), 0) diff --git a/toolbar_utils.py b/toolbar_utils.py index 94e6883..607bf22 100644 --- a/toolbar_utils.py +++ b/toolbar_utils.py @@ -11,70 +11,25 @@ # Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA -import gtk +from gi.repository import Gtk -from sugar.graphics.radiotoolbutton import RadioToolButton -from sugar.graphics.toolbutton import ToolButton -from sugar.graphics.combobox import ComboBox -from sugar.graphics.toolcombobox import ToolComboBox - - -def combo_factory(combo_array, toolbar, callback, cb_arg=None, - tooltip=None, default=None): - '''Factory for making a toolbar combo box''' - combo = ComboBox() - if tooltip is not None and hasattr(combo, 'set_tooltip_text'): - combo.set_tooltip_text(tooltip) - if cb_arg is not None: - combo.connect('changed', callback, cb_arg) - else: - combo.connect('changed', callback) - for i, selection in enumerate(combo_array): - combo.append_item(i, selection, None) - combo.show() - toolitem = gtk.ToolItem() - toolitem.add(combo) - if hasattr(toolbar, 'insert'): # the main toolbar - toolbar.insert(toolitem, -1) - else: # or a secondary toolbar - toolbar.props.page.insert(toolitem, -1) - toolitem.show() - if default is not None: - combo.set_active(combo_array.index(default)) - return combo - - -def entry_factory(default_string, toolbar, tooltip=None, max=3): - ''' Factory for adding a text box to a toolbar ''' - entry = gtk.Entry() - entry.set_text(default_string) - if tooltip is not None and hasattr(entry, 'set_tooltip_text'): - entry.set_tooltip_text(tooltip) - entry.set_width_chars(max) - entry.show() - toolitem = gtk.ToolItem() - toolitem.add(entry) - if hasattr(toolbar, 'insert'): # the main toolbar - toolbar.insert(toolitem, -1) - else: # or a secondary toolbar - toolbar.props.page.insert(toolitem, -1) - toolitem.show() - return entry +from sugar3.graphics.toolbutton import ToolButton +from sugar3.graphics.radiotoolbutton import RadioToolButton def button_factory(icon_name, toolbar, callback, cb_arg=None, tooltip=None, - accelerator=None): - '''Factory for making tooplbar buttons''' + accelerator=None): + ''' Factory for making toolbar buttons ''' button = ToolButton(icon_name) if tooltip is not None: button.set_tooltip(tooltip) button.props.sensitive = True if accelerator is not None: button.props.accelerator = accelerator - if cb_arg is not None: - button.connect('clicked', callback, cb_arg) - else: + if cb_arg is None: button.connect('clicked', callback) + else: + button.connect('clicked', callback, cb_arg) if hasattr(toolbar, 'insert'): # the main toolbar toolbar.insert(button, -1) else: # or a secondary toolbar @@ -83,82 +38,60 @@ def button_factory(icon_name, toolbar, callback, cb_arg=None, tooltip=None, return button -def radio_factory(name, toolbar, callback, cb_arg=None, tooltip=None, - group=None): +def radio_factory(icon_name, toolbar, callback, cb_arg=None, + tooltip=None, group=None): ''' Add a radio button to a toolbar ''' button = RadioToolButton(group=group) - button.set_named_icon(name) - if callback is not None: - if cb_arg is None: - button.connect('clicked', callback) - else: - button.connect('clicked', callback, cb_arg) - if hasattr(toolbar, 'insert'): # Add button to the main toolbar... + button.set_icon_name(icon_name) + if tooltip is not None: + button.set_tooltip(tooltip) + if cb_arg is None: + button.connect('clicked', callback) + else: + button.connect('clicked', callback, cb_arg) + if hasattr(toolbar, 'insert'): # the main toolbar toolbar.insert(button, -1) - else: # ...or a secondary toolbar. + else: # or a secondary toolbar toolbar.props.page.insert(button, -1) button.show() - if tooltip is not None: - button.set_tooltip(tooltip) return button -def label_factory(toolbar, label_text, width=None): +def label_factory(label_text, toolbar): ''' Factory for adding a label to a toolbar ''' - label = gtk.Label(label_text) + label = Gtk.Label(label=label_text) label.set_line_wrap(True) - if width is not None: - label.set_size_request(width, -1) # doesn't work on XOs label.show() - toolitem = gtk.ToolItem() + toolitem = Gtk.ToolItem() toolitem.add(label) - if hasattr(toolbar, 'insert'): # the main toolbar - toolbar.insert(toolitem, -1) - else: # or a secondary toolbar - toolbar.props.page.insert(toolitem, -1) + toolbar.insert(toolitem, -1) toolitem.show() return label -def separator_factory(toolbar, expand=False, visible=True): - ''' add a separator to a toolbar ''' - separator = gtk.SeparatorToolItem() - separator.props.draw = visible - separator.set_expand(expand) - if hasattr(toolbar, 'insert'): # the main toolbar - toolbar.insert(separator, -1) - else: # or a secondary toolbar - toolbar.props.page.insert(separator, -1) - separator.show() - - -def image_factory(image, toolbar, tooltip=None): - ''' Add an image to the toolbar ''' - img = gtk.Image() - img.set_from_pixbuf(image) - img_tool = gtk.ToolItem() - img_tool.add(img) - if tooltip is not None: - img.set_tooltip_text(tooltip) - if hasattr(toolbar, 'insert'): # the main toolbar - toolbar.insert(img_tool, -1) - else: # or a secondary toolbar - toolbar.props.page.insert(img_tool, -1) - img_tool.show() - return img - - -def spin_factory(default, min, max, callback, toolbar): - spin_adj = gtk.Adjustment(default, min, max, 1, 32, 0) - spin = gtk.SpinButton(spin_adj, 0, 0) - spin_id = spin.connect('value-changed', callback) +def spin_factory(default, min_value, max_value, callback, toolbar): + ''' Factory for making toolbar value spinners ''' + spin_adj = Gtk.Adjustment(default, min_value, max_value, 1, 32, 0) + spin = Gtk.SpinButton() + spin.set_adjustment(spin_adj) + spin.connect('value-changed', callback) spin.set_numeric(True) spin.show() - toolitem = gtk.ToolItem() + toolitem = Gtk.ToolItem() toolitem.add(spin) - if hasattr(toolbar, 'insert'): # the main toolbar + if toolbar is not None: toolbar.insert(toolitem, -1) + toolitem.show() + return spin else: - toolbar.props.page.insert(toolitem, -1) - toolitem.show() - return spin + toolitem.show() + return spin, toolitem + + +def separator_factory(toolbar, expand=False, visible=True): + ''' Add a separator to a toolbar ''' + separator = Gtk.SeparatorToolItem() + separator.props.draw = visible + separator.set_expand(expand) + toolbar.insert(separator, -1) + separator.show() diff --git a/visualmatch.py b/visualmatch.py index 809f556..3fa1211 100755 --- a/visualmatch.py +++ b/visualmatch.py @@ -12,9 +12,9 @@ # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. -import pygtk -pygtk.require('2.0') -import gtk +import gi +from gi.repository import Gtk +from gi.repository import Gdk from gettext import gettext as _ import os @@ -27,130 +27,128 @@ from constants import PRODUCT, HASH, ROMAN, WORD, CHINESE, MAYAN, DICE, DOTS, \ class VisualMatchMain: def __init__(self): - self.r = 0 - self.tw = None # create a new window - self.win = gtk.Window(gtk.WINDOW_TOPLEVEL) + self.win = Gtk.Window(type=Gtk.WindowType.TOPLEVEL) self.win.maximize() self.win.set_title("%s: %s" % (_("Visual Match"), _("Click on cards to create sets of three."))) - self.win.connect("delete_event", lambda w, e: gtk.main_quit()) + self.win.connect("delete_event", lambda w, e: Gtk.main_quit()) - menu0 = gtk.Menu() - menu_items = gtk.MenuItem(_("Toggle level")) + menu0 = Gtk.Menu() + menu_items = Gtk.MenuItem(_("Toggle level")) menu0.append(menu_items) menu_items.connect("activate", self._level_cb) menu_items.show() - level_menu = gtk.MenuItem("Level") + level_menu = Gtk.MenuItem("Level") level_menu.show() level_menu.set_submenu(menu0) - menu1 = gtk.Menu() - menu_items = gtk.MenuItem(_("New pattern game")) + menu1 = Gtk.Menu() + menu_items = Gtk.MenuItem(_("New pattern game")) menu1.append(menu_items) menu_items.connect("activate", self._new_game_cb, 'pattern') menu_items.show() - menu_items = gtk.MenuItem(_("New number game")) + menu_items = Gtk.MenuItem(_("New number game")) menu1.append(menu_items) menu_items.connect("activate", self._new_game_cb, 'number') menu_items.show() - menu_items = gtk.MenuItem(_("New word game")) + menu_items = Gtk.MenuItem(_("New word game")) menu1.append(menu_items) menu_items.connect("activate", self._new_game_cb, 'word') menu_items.show() - game_menu = gtk.MenuItem("Games") + game_menu = Gtk.MenuItem("Games") game_menu.show() game_menu.set_submenu(menu1) - menu2 = gtk.Menu() - menu_items = gtk.MenuItem(_("Robot on/off")) + menu2 = Gtk.Menu() + menu_items = Gtk.MenuItem(_("Robot on/off")) menu2.append(menu_items) menu_items.connect("activate", self._robot_cb) menu_items.show() - menu_items = gtk.MenuItem(_("90 sec.")) + menu_items = Gtk.MenuItem(_("90 sec.")) menu2.append(menu_items) menu_items.connect("activate", self._robot_time_cb, 90) menu_items.show() - menu_items = gtk.MenuItem(_("60 sec.")) + menu_items = Gtk.MenuItem(_("60 sec.")) menu2.append(menu_items) menu_items.connect("activate", self._robot_time_cb, 60) menu_items.show() - menu_items = gtk.MenuItem(_("45 sec.")) + menu_items = Gtk.MenuItem(_("45 sec.")) menu2.append(menu_items) menu_items.connect("activate", self._robot_time_cb, 45) menu_items.show() - menu_items = gtk.MenuItem(_("30 sec.")) + menu_items = Gtk.MenuItem(_("30 sec.")) menu2.append(menu_items) menu_items.connect("activate", self._robot_time_cb, 30) menu_items.show() - menu_items = gtk.MenuItem(_("15 sec.")) + menu_items = Gtk.MenuItem(_("15 sec.")) menu2.append(menu_items) menu_items.connect("activate", self._robot_time_cb, 15) menu_items.show() - tool_menu = gtk.MenuItem("Robot") + tool_menu = Gtk.MenuItem("Robot") tool_menu.show() tool_menu.set_submenu(menu2) - menu3 = gtk.Menu() - menu_items = gtk.MenuItem(_("Product")) + menu3 = Gtk.Menu() + menu_items = Gtk.MenuItem(_("Product")) menu3.append(menu_items) menu_items.connect("activate", self._number_card_O_cb, PRODUCT) menu_items.show() - menu_items = gtk.MenuItem(_("Roman")) + menu_items = Gtk.MenuItem(_("Roman")) menu3.append(menu_items) menu_items.connect("activate", self._number_card_O_cb, ROMAN) menu_items.show() - menu_items = gtk.MenuItem(_("Word")) + menu_items = Gtk.MenuItem(_("Word")) menu3.append(menu_items) menu_items.connect("activate", self._number_card_O_cb, WORD) menu_items.show() - menu_items = gtk.MenuItem(_("Chinese")) + menu_items = Gtk.MenuItem(_("Chinese")) menu3.append(menu_items) menu_items.connect("activate", self._number_card_O_cb, CHINESE) menu_items.show() - menu_items = gtk.MenuItem(_("Mayan")) + menu_items = Gtk.MenuItem(_("Mayan")) menu3.append(menu_items) menu_items.connect("activate", self._number_card_O_cb, MAYAN) menu_items.show() - menu_items = gtk.MenuItem(_("Quipu")) + menu_items = Gtk.MenuItem(_("Quipu")) menu3.append(menu_items) menu_items.connect("activate", self._number_card_O_cb, INCAN) menu_items.show() - menu_items = gtk.MenuItem(_("Hash")) + menu_items = Gtk.MenuItem(_("Hash")) menu3.append(menu_items) menu_items.connect("activate", self._number_card_C_cb, HASH) menu_items.show() - menu_items = gtk.MenuItem(_("Dice")) + menu_items = Gtk.MenuItem(_("Dice")) menu3.append(menu_items) menu_items.connect("activate", self._number_card_C_cb, DICE) menu_items.show() - menu_items = gtk.MenuItem(_("Dots")) + menu_items = Gtk.MenuItem(_("Dots")) menu3.append(menu_items) menu_items.connect("activate", self._number_card_C_cb, DOTS) menu_items.show() - menu_items = gtk.MenuItem(_("Star")) + menu_items = Gtk.MenuItem(_("Star")) menu3.append(menu_items) menu_items.connect("activate", self._number_card_C_cb, STAR) menu_items.show() - menu_items = gtk.MenuItem(_("Lines")) + menu_items = Gtk.MenuItem(_("Lines")) menu3.append(menu_items) menu_items.connect("activate", self._number_card_C_cb, LINES) menu_items.show() - num_menu = gtk.MenuItem("Numbers") + num_menu = Gtk.MenuItem("Numbers") num_menu.show() num_menu.set_submenu(menu3) # A vbox to put a menu and the canvas in: - vbox = gtk.VBox(False, 0) + vbox = Gtk.VBox(False, 0) self.win.add(vbox) vbox.show() - menu_bar = gtk.MenuBar() + menu_bar = Gtk.MenuBar() vbox.pack_start(menu_bar, False, False, 2) menu_bar.show() - canvas = gtk.DrawingArea() - vbox.pack_end(canvas, True, True) + canvas = Gtk.DrawingArea() + vbox.pack_end(canvas, True, True, 0) canvas.show() menu_bar.append(game_menu) @@ -229,7 +227,7 @@ class VisualMatchMain: def main(): - gtk.main() + Gtk.main() return 0 -- cgit v0.9.1