From 72f6733bde67ccb3aef4b027dd922ff69b89125b Mon Sep 17 00:00:00 2001 From: Walter Bender Date: Mon, 29 Oct 2012 14:24:44 +0000 Subject: gtk3 port --- diff --git a/YupanaActivity.py b/YupanaActivity.py index 5df63d9..9718230 100644 --- a/YupanaActivity.py +++ b/YupanaActivity.py @@ -1,4 +1,4 @@ -#Copyright (c) 2011 Walter Bender +#Copyright (c) 2011,12 Walter Bender #Copyright (c) 2012 Ignacio Rodriguez # This program is free software; you can redistribute it and/or modify @@ -14,16 +14,10 @@ from gi.repository import Gtk, Gdk, GObject from sugar3.activity import activity from sugar3 import profile -try: - from sugar3.graphics.toolbarbox import ToolbarBox - _have_toolbox = True -except ImportError: - _have_toolbox = False - -if _have_toolbox: - from sugar3.activity.widgets import ActivityToolbarButton - from sugar3.activity.widgets import StopButton - from sugar3.graphics.toolbarbox import ToolbarButton +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 toolbar_utils import button_factory, label_factory, separator_factory, \ radio_factory, entry_factory @@ -66,7 +60,7 @@ class YupanaActivity(activity.Activity): else: self.colors = ['#A0FFA0', '#FF8080'] - self._setup_toolbars(_have_toolbox) + self._setup_toolbars() self._setup_dispatch_table() # Create a canvas @@ -89,56 +83,44 @@ class YupanaActivity(activity.Activity): if self._reload_custom: self._custom_cb() - def _setup_toolbars(self, have_toolbox): + def _setup_toolbars(self): """ Setup the toolbars. """ self.max_participants = 4 yupana_toolbar = Gtk.Toolbar() self.custom_toolbar = Gtk.Toolbar() - if have_toolbox: - toolbox = ToolbarBox() - - # Activity toolbar - activity_button = ActivityToolbarButton(self) + toolbox = ToolbarBox() - toolbox.toolbar.insert(activity_button, 0) - activity_button.show() + # Activity toolbar + activity_button = ActivityToolbarButton(self) - yupana_toolbar_button = ToolbarButton( - label=_("Mode"), page=yupana_toolbar, - icon_name='preferences-system') - yupana_toolbar.show() - toolbox.toolbar.insert(yupana_toolbar_button, -1) - yupana_toolbar_button.show() + toolbox.toolbar.insert(activity_button, 0) + activity_button.show() - custom_toolbar_button = ToolbarButton( - label=_("Custom"), page=self.custom_toolbar, - icon_name='view-source') - self.custom_toolbar.show() - toolbox.toolbar.insert(custom_toolbar_button, -1) - custom_toolbar_button.show() + yupana_toolbar_button = ToolbarButton( + label=_("Mode"), page=yupana_toolbar, + icon_name='preferences-system') + yupana_toolbar.show() + toolbox.toolbar.insert(yupana_toolbar_button, -1) + yupana_toolbar_button.show() - self.set_toolbar_box(toolbox) - toolbox.show() - self.toolbar = toolbox.toolbar + custom_toolbar_button = ToolbarButton( + label=_("Custom"), page=self.custom_toolbar, + icon_name='view-source') + self.custom_toolbar.show() + toolbox.toolbar.insert(custom_toolbar_button, -1) + custom_toolbar_button.show() - else: - # Use pre-0.86 toolbar design - toolbox = activity.ActivityToolbox(self) - self.set_toolbox(toolbox) - toolbox.add_toolbar(_('Yupana'), yupana_toolbar) - toolbox.add_toolbar(_('Custom'), self.custom_toolbar) - toolbox.show() - toolbox.set_current_toolbar(1) - self.toolbar = yupana_toolbar + self.set_toolbar_box(toolbox) + toolbox.show() + self.toolbar = toolbox.toolbar self._new_yupana_button = button_factory( 'edit-delete', self.toolbar, self._new_yupana_cb, tooltip=_('Clear the yupana.')) - if not _have_toolbox: - separator_factory(yupana_toolbar, False, True) + separator_factory(yupana_toolbar, False, True) self.ten_button = radio_factory( 'ten', yupana_toolbar, self._ten_cb, tooltip=_('decimal mode'), @@ -161,17 +143,15 @@ class YupanaActivity(activity.Activity): group=self.ten_button) separator_factory(self.toolbar, False, False) - self.status = label_factory(self.toolbar, '') + self.status = label_factory(self.toolbar, '', width=200) self.status.set_label(_('decimal mode')) - if _have_toolbox: - separator_factory(toolbox.toolbar, True, False) + separator_factory(toolbox.toolbar, True, False) - if _have_toolbox: - stop_button = StopButton(self) - stop_button.props.accelerator = 'q' - toolbox.toolbar.insert(stop_button, -1) - stop_button.show() + stop_button = StopButton(self) + stop_button.props.accelerator = 'q' + toolbox.toolbar.insert(stop_button, -1) + stop_button.show() def _make_custom_toolbar(self): self._ones = entry_factory(str(self._yupana.custom[0]), diff --git a/setup.py b/setup.py index 468572c..bdeaed6 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,5 @@ #!/usr/bin/env python from sugar3.activity import bundlebuilder if __name__ == "__main__": - bundlebuilder.start() + bundlebuilder.start() + diff --git a/sprites.py b/sprites.py index 0ef8dca..d1a4562 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,401 +68,14 @@ 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() return pixbuf -''' -## <-----------GTK2---------------->## - -''' - - -import pygtk -pygtk.require('2.0') -import gtk -import pango -import pangocairo -import cairo - -class Sprites: - # A class for the list of sprites and everything they share in common # - - def __init__(self, widget): - # Initialize an empty array of sprites # - self.widget = widget - self.list = [] - self.cr = None - - def set_cairo_context(self, cr): - # Cairo context may be set or reset after __init__ # - self.cr = cr - - def get_sprite(self, i): - # Return a sprint from the array # - if i < 0 or i > len(self.list) - 1: - return(None) - else: - return(self.list[i]) - - def length_of_list(self): - # How many sprites are there? # - return(len(self.list)) - - def append_to_list(self, spr): - # Append a new sprite to the end of the list. # - self.list.append(spr) - - def insert_in_list(self, spr, i): - # Insert a sprite at position i. # - if i < 0: - self.list.insert(0, spr) - elif i > len(self.list) - 1: - self.list.append(spr) - else: - self.list.insert(i, spr) - - 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, inverse=False): - # Search based on (x, y) position. Return the 'top/first' one. # - list = self.list[:] - if not inverse: - list.reverse() - for spr in list: - if spr.hit(pos): - return spr - return None - - def redraw_sprites(self, area=None, cr=None): - # Redraw the sprites that intersect area. # - # I think I need to do this to save Cairo some work - if cr is None: - cr = self.cr - else: - self.cr = cr - if cr is None: - print 'sprites.redraw_sprites: no Cairo context' - return - for spr in self.list: - if area == None: - spr.draw(cr=cr) - else: - intersection = spr.rect.intersect(area) - if intersection.width > 0 or intersection.height > 0: - spr.draw(cr=cr) - - -class Sprite: - # A class for the individual sprites # - - 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._scale = [12] - self._rescale = [True] - self._horiz_align = ["center"] - self._vert_align = ["middle"] - self._fd = None - self._bold = False - self._italic = False - self._color = None - self._margins = [0, 0, 0, 0] - self.layer = 100 - self.labels = [] - self.cached_surfaces = [] - self._dx = [] # image offsets - self._dy = [] - self.type = None - self.set_image(image) - self._sprites.append_to_list(self) - - 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) - self._dx.append(0) - self._dy.append(0) - 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() - else: - w, h = image.get_size() - if i == 0: # Always reset width and height when base image changes. - self.rect.width = w + dx - self.rect.height = 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 - - 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.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.inval() - - def get_xy(self): - # Return current (x, y) position # - return (self.rect.x, self.rect.y) - - def get_dimensions(self): - # Return current size # - return (self.rect.width, self.rect.height) - - def get_layer(self): - # Return current layer # - return self.layer - - def set_shape(self, image, i=0): - # Set the current image associated with the sprite # - self.inval() - self.set_image(image, i) - self.inval() - - def set_layer(self, layer=None): - # Set the layer for a sprite # - self._sprites.remove_from_list(self) - if layer is not None: - 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) - self.inval() - return - self._sprites.append_to_list(self) - self.inval() - - def set_label(self, new_label, i=0): - # Set the label drawn on the sprite # - self._extend_labels_array(i) - if type(new_label) is str or type(new_label) is unicode: - # pango doesn't like nulls - self.labels[i] = new_label.replace("\0", " ") - else: - self.labels[i] = str(new_label) - self.inval() - - def set_margins(self, l=0, t=0, r=0, b=0): - # Set the margins for drawing the label # - self._margins = [l, t, r, b] - - def _extend_labels_array(self, i): - # Append to the labels attribute list # - if self._fd is None: - self.set_font('Sans') - if self._color is None: - self._color = (0., 0., 0.) - while len(self.labels) < i + 1: - self.labels.append(" ") - self._scale.append(self._scale[0]) - self._rescale.append(self._rescale[0]) - self._horiz_align.append(self._horiz_align[0]) - self._vert_align.append(self._vert_align[0]) - - def set_font(self, font): - # Set the font for a label # - self._fd = pango.FontDescription(font) - - def set_label_color(self, rgb): - # Set the font color for a label # - COLORTABLE = {'black': '#000000', 'white': '#FFFFFF', - 'red': '#FF0000', 'yellow': '#FFFF00', - 'green': '#00FF00', 'cyan': '#00FFFF', - 'blue': '#0000FF', 'purple': '#FF00FF', - 'gray': '#808080'} - if rgb.lower() in COLORTABLE: - rgb = COLORTABLE[rgb.lower()] - # Convert from '#RRGGBB' to floats - self._color = (int('0x' + rgb[1:3], 16) / 256., - int('0x' + rgb[3:5], 16) / 256., - int('0x' + rgb[5:7], 16) / 256.) - return - - def set_label_attributes(self, scale, rescale=True, horiz_align="center", - vert_align="middle", i=0): - # Set the various label attributes # - self._extend_labels_array(i) - self._scale[i] = scale - self._rescale[i] = rescale - self._horiz_align[i] = horiz_align - self._vert_align[i] = vert_align - - def hide(self): - # Hide a 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) - - def draw(self, cr=None): - # Draw the sprite (and label) # - 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() - if len(self.labels) > 0: - self.draw_label(cr) - - def hit(self, pos): - # Is (x, y) on top of the sprite? # - x, y = pos - if x < self.rect.x: - return False - if x > self.rect.x + self.rect.width: - return False - if y < self.rect.y: - return False - if y > self.rect.y + self.rect.height: - return False - 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] - if my_width < 0: - my_width = 0 - my_height = self.rect.height - 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.set_font_description(self._fd) - 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)) - pl.set_font_description(self._fd) - 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)) - pl.set_font_description(self._fd) - 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) - 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 - if self._vert_align[i] == "middle": - y = int(self.rect.y + 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]) - 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) - 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 - - def label_safe_width(self): - # Return maximum width for a label # - return self.rect.width - 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] - - 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(-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 writing is done - # Read the pixel - pixels = cs.get_data() - return (ord(pixels[2]), ord(pixels[1]), ord(pixels[0]), 0) ''' -#<-----------------------GTK3-----------># import gi from gi.repository import Gtk, GdkPixbuf, Gdk from gi.repository import Pango, PangoCairo @@ -528,7 +141,6 @@ class Sprites: else: self.cr = cr if cr is None: - print 'sprites.redraw_sprites: no Cairo context' return for spr in self.list: if area == None: @@ -715,7 +327,6 @@ class Sprite: if cr is None: cr = self._sprites.cr if cr is None: - print 'sprite.draw: no Cairo context.' return for i, img in enumerate(self.images): if isinstance(img, GdkPixbuf.Pixbuf): diff --git a/toolbar_utils.py b/toolbar_utils.py index 03f5461..72f7100 100644 --- a/toolbar_utils.py +++ b/toolbar_utils.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Copyright (c) 2011, Walter Bender -# Copyright (c) 2012, Ignacio Rodriguez +# Port To GTK3: +# Ignacio Rodriguez # This program 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 @@ -10,6 +11,7 @@ # along with this library; if not, write to the Free Software # Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA + from gi.repository import Gtk from sugar3.graphics.radiotoolbutton import RadioToolButton diff --git a/utils.py b/utils.py index ffab831..81a76f8 100644 --- a/utils.py +++ b/utils.py @@ -1,4 +1,4 @@ -#Copyright (c) 2011 Walter Bender +#Copyright (c) 2011,12 Walter Bender # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -11,43 +11,28 @@ from StringIO import StringIO -try: - OLD_SUGAR_SYSTEM = False - import json - json.dumps - 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: - OLD_SUGAR_SYSTEM = True +import json +json.dumps +from json import load as jload +from json import dump as jdump def json_load(text): """ Load JSON data using what ever resources are available. """ - if OLD_SUGAR_SYSTEM is True: - listdata = json.read(text) - else: - # strip out leading and trailing whitespace, nulls, and newlines - io = StringIO(text) - try: - listdata = jload(io) - except ValueError: - # assume that text is ascii list - listdata = text.split() - for i, value in enumerate(listdata): - listdata[i] = int(value) + # strip out leading and trailing whitespace, nulls, and newlines + io = StringIO(text) + try: + listdata = jload(io) + except ValueError: + # assume that text is ascii list + listdata = text.split() + for i, value in enumerate(listdata): + listdata[i] = int(value) return listdata def json_dump(data): """ Save data using available JSON tools. """ - if OLD_SUGAR_SYSTEM is True: - return json.write(data) - else: - _io = StringIO() - jdump(data, _io) - return _io.getvalue() + _io = StringIO() + jdump(data, _io) + return _io.getvalue() diff --git a/yupana.py b/yupana.py index 8a0bfbf..56fa51d 100644 --- a/yupana.py +++ b/yupana.py @@ -80,7 +80,7 @@ class Yupana(): Sprite(self._sprites, x, y, self._new_dot(self._colors[0]))) self._dots[-1].type = 0 # not set - self._dots[-1].set_label_color('black') + self._dots[-1].set_label_color('white') x += self._dot_size + self._space x = int((p * self._width / 6.) + self._dot_size / 2.) + self._space y -= self._dot_size + self._space @@ -89,7 +89,7 @@ class Yupana(): Sprite(self._sprites, x, y, self._new_dot(self._colors[0]))) self._dots[-1].type = 0 # not set - self._dots[-1].set_label_color('black') + self._dots[-1].set_label_color('white') x += self._dot_size + self._space y -= self._dot_size @@ -102,7 +102,7 @@ class Yupana(): Sprite(self._sprites, x, y, self._new_dot(self._colors[0]))) self._dots[-1].type = 0 # not set - self._dots[-1].set_label_color('black') + self._dots[-1].set_label_color('white') x += self._dot_size + self._space x = int((p * self._width / 6.) + self._dot_size) + self._space y -= self._dot_size + self._space @@ -111,7 +111,7 @@ class Yupana(): Sprite(self._sprites, x, y, self._new_dot(self._colors[0]))) self._dots[-1].type = 0 # not set - self._dots[-1].set_label_color('black') + self._dots[-1].set_label_color('white') x += self._dot_size + self._space y -= self._dot_size @@ -124,7 +124,7 @@ class Yupana(): Sprite(self._sprites, x, y, self._new_dot(self._colors[0]))) self._dots[-1].type = 0 # not set - self._dots[-1].set_label_color('black') + self._dots[-1].set_label_color('white') x += self._dot_size + self._space y -= self._dot_size @@ -137,7 +137,7 @@ class Yupana(): Sprite(self._sprites, x, y, self._new_dot(self._colors[0]))) self._dots[-1].type = 0 # not set - self._dots[-1].set_label_color('black') + self._dots[-1].set_label_color('white') x += self._dot_size + self._space y -= self._dot_size @@ -174,7 +174,7 @@ class Yupana(): if mode is not None: self._mode = mode - o = (SIX - 1) * (TEN + 1) # only label units + o = (SIX - 1) * (TEN + 1) # only label units if mode == 'ten': for i in range(TEN + 1): self._dots[o + i].set_label('1') @@ -311,6 +311,7 @@ class Yupana(): else: return (self.custom[4] ** e) * self.custom[3] + def remote_button_press(self, dot, color): ''' Receive a button press from a sharer ''' self._dots[dot].type = color @@ -371,6 +372,7 @@ class Yupana(): else: pixbuf = svg_str_to_pixbuf( self._header() + \ + self._def(self._dot_size) + \ self._gradient(self._dot_size / 2., self._dot_size / 2., self._dot_size / 2.) + \ self._footer()) @@ -402,7 +404,7 @@ class Yupana(): self._rect(self._width, 3, 0, 0) + \ self._footer()) - def _box(self, w, h, color='black'): + def _box(self, w, h, color='white'): ''' Generate a box ''' self._svg_width = w self._svg_height = h @@ -436,56 +438,39 @@ class Yupana(): return svg_string def _circle(self, r, cx, cy): - scale = (DOT_SIZE * self._scale) / 55. - return '\ - \ - \ -' % ( - scale, scale, self._colors[1]) + return '\n' def _gradient(self, r, cx, cy): - ''' return '\n' - ''' - scale = (DOT_SIZE * self._scale) / 55. - return '\ - \ + + def _def(self, r): + return ' \ \ + id="linearGradient3755">\ \ \ \ - \ + \ \ - \ - \ - \ - ' % ( - scale, scale) +' % (self._fill, self._fill_dark, r, r / 3, r / 3) def _footer(self): return '\n' -- cgit v0.9.1