From f9b76032723899505fd8a7067451fa734459e29f Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Wed, 25 Jul 2012 13:54:15 +0000 Subject: Port to Cairo This will ease the port to GTK+ 3 Signed-off-by: Manuel Kaufmann --- diff --git a/balloongame.py b/balloongame.py index 56a6a34..7224893 100644 --- a/balloongame.py +++ b/balloongame.py @@ -14,7 +14,10 @@ # You should have received a copy of the GNU General Public License # along with Typing Turtle. If not, see . +import math import random, datetime +import pangocairo + from gettext import gettext as _ import gobject, pygtk, gtk, pango @@ -192,28 +195,35 @@ class BalloonGame(gtk.VBox): return True - def draw_results(self, gc): + def draw_results(self, cr): # Draw background. w = self.bounds.width - 400 h = self.bounds.height - 200 x = self.bounds.width/2 - w/2 y = self.bounds.height/2 - h/2 - gc.foreground = self.area.get_colormap().alloc_color(50000,50000,50000) - self.area.window.draw_rectangle(gc, True, x, y, w, h) - gc.foreground = self.area.get_colormap().alloc_color(0,0,0) - self.area.window.draw_rectangle(gc, False, x, y, w, h) + cr.set_source_rgb(0.762, 0.762, 0.762) + cr.rectangle(x, y, w, h) + cr.fill() - # Draw text - gc.foreground = self.area.get_colormap().alloc_color(0,0,0) + cr.set_source_rgb(0, 0, 0) + cr.rectangle(x, y, w, h) + cr.stroke() + # Draw text title = _('You finished!') + '\n' - layout = self.area.create_pango_layout(title) - layout.set_font_description(pango.FontDescription('Serif Bold 16')) - size = layout.get_size() - tx = x+w/2-(size[0]/pango.SCALE)/2 + + pango_cr = pangocairo.CairoContext(cr) + pango_cr.set_source_rgb(0, 0, 0) + pango_layout = cr.create_layout() + pango_layout.set_font_description(pango.FontDescription('Serif Bold 16')) + pango_layout.set_text(title) + size = pango_layout.get_size() + tx = x + (w / 2) - (size[0] / pango.SCALE) / 2 ty = y + 100 - self.area.window.draw_layout(gc, tx, ty, layout) + pango_cr.move_to(tx, ty) + pango_cr.show_layout(pango_layout) + pango_cr.stroke() report = '' report += _('Your score was %(score)d.') % { 'score': self.score } + '\n' @@ -222,12 +232,18 @@ class BalloonGame(gtk.VBox): report += '\n' report += _('Press the ENTER key to continue.') - layout = self.area.create_pango_layout(report) - layout.set_font_description(pango.FontDescription('Times 12')) - size = layout.get_size() - tx = x+w/2-(size[0]/pango.SCALE)/2 - ty = y + 200 - self.area.window.draw_layout(gc, tx, ty, layout) + pango_cr = pangocairo.CairoContext(cr) + pango_cr.set_source_rgb(0, 0, 0) + pango_layout = cr.create_layout() + pango_layout.set_font_description(pango.FontDescription('Times 12')) + pango_layout.set_text(report) + size = pango_layout.get_size() + sx = x + w / 2 - (size[0] / pango.SCALE) / 2 + sy = y + 200 + pango_cr.move_to(sx, sy) + pango_cr.show_layout(pango_layout) + pango_cr.stroke() + def finish_game(self): self.finished = True @@ -290,29 +306,35 @@ class BalloonGame(gtk.VBox): h = int(b.size*1.5 + 10) self.area.queue_draw_area(x, y, w, h) - def draw_balloon(self, gc, b): + def draw_balloon(self, cr, b): x = int(b.x) y = int(b.y) - + # Draw the string. - gc.foreground = self.area.get_colormap().alloc_color(0,0,0) - self.area.window.draw_line(gc, - int(b.x), int(b.y+b.size/2), - int(b.x), int(b.y+b.size)) - + cr.set_source_rgb(0, 0, 0) + cr.move_to(int(b.x), int(b.y + b.size / 2)) + cr.line_to(int(b.x), int(b.y + b.size)) + cr.stroke() + # Draw the balloon. - gc.foreground = self.area.get_colormap().alloc_color(b.color[0],b.color[1],b.color[2]) - self.area.window.draw_arc(gc, True, x-b.size/2, y-b.size/2, b.size, b.size, 0, 360*64) - - # Draw the text. - gc.foreground = self.area.get_colormap().alloc_color(0,0,0) - layout = self.area.create_pango_layout(b.word) - layout.set_font_description(pango.FontDescription('Sans 12')) - size = layout.get_size() - tx = x-(size[0]/pango.SCALE)/2 - ty = y-(size[1]/pango.SCALE)/2 - self.area.window.draw_layout(gc, tx, ty, layout) - + cr.save() + cr.set_source_rgb(b.color[0], b.color[1], b.color[2]) + cr.arc(b.x, b.y, b.size / 2, 0, 2 * math.pi) + cr.fill() + cr.restore() + + pango_cr = pangocairo.CairoContext(cr) + pango_cr.set_source_rgb(0, 0, 0) + pango_layout = cr.create_layout() + pango_layout.set_font_description(pango.FontDescription('Sans 12')) + pango_layout.set_text(unicode(b.word)) + size = pango_layout.get_size() + x = x - (size[0] / pango.SCALE) / 2 + y = y - (size[1] / pango.SCALE) / 2 + pango_cr.move_to(x, y) + pango_cr.show_layout(pango_layout) + pango_cr.stroke() + def add_score(self, num): self.score += num self.queue_draw_score() @@ -325,45 +347,54 @@ class BalloonGame(gtk.VBox): y = 20 self.queue_draw_area(x, y, x+size[0], y+size[1]) - def draw_score(self, gc): - layout = self.area.create_pango_layout(_('SCORE: %d') % self.score) - layout.set_font_description(pango.FontDescription('Times 14')) - size = layout.get_size() - x = self.bounds.width-20-size[0]/pango.SCALE + def draw_score(self, cr): + pango_cr = pangocairo.CairoContext(cr) + pango_cr.set_source_rgb(0, 0, 0) + pango_layout = cr.create_layout() + pango_layout.set_font_description(pango.FontDescription('Times 14')) + pango_layout.set_text(_('SCORE: %d') % self.score) + size = pango_layout.get_size() + x = self.bounds.width - 20 - size[0] / pango.SCALE y = 20 - self.area.window.draw_layout(gc, x, y, layout) + pango_cr.move_to(x, y) + pango_cr.show_layout(pango_layout) + pango_cr.stroke() - def draw_instructions(self, gc): + def draw_instructions(self, cr): # Draw instructions. - gc.foreground = self.area.get_colormap().alloc_color(0,0,0) - - layout = self.area.create_pango_layout(_('Type the words to pop the balloons!')) - layout.set_font_description(pango.FontDescription('Times 14')) - size = layout.get_size() - x = (self.bounds.width - size[0]/pango.SCALE)/2 - y = self.bounds.height-20 - size[1]/pango.SCALE - self.area.window.draw_layout(gc, x, y, layout) + pango_cr = pangocairo.CairoContext(cr) + pango_cr.set_source_rgb(0, 0, 0) + pango_layout = cr.create_layout() + pango_layout.set_font_description(pango.FontDescription('Times 14')) + pango_layout.set_text(_('Type the words to pop the balloons!')) + size = pango_layout.get_size() + x = (self.bounds.width - size[0] / pango.SCALE) / 2 + y = self.bounds.height - 20 - size[1] / pango.SCALE + pango_cr.move_to(x, y) + pango_cr.show_layout(pango_layout) + pango_cr.stroke() def draw(self): self.bounds = self.area.get_allocation() - gc = self.area.window.new_gc() - + cr = self.area.window.cairo_create() + # Draw background. - gc.foreground = self.area.get_colormap().alloc_color(60000,60000,65535) - self.area.window.draw_rectangle(gc, True, 0, 0, self.bounds.width, self.bounds.height) + cr.set_source_rgb(0.915, 0.915, 1) + cr.rectangle(0, 0, self.bounds.width, self.bounds.height) + cr.fill() # Draw the balloons. for b in self.balloons: - self.draw_balloon(gc, b) + self.draw_balloon(cr, b) if self.finished: - self.draw_results(gc) + self.draw_results(cr) else: - self.draw_instructions(gc) + self.draw_instructions(cr) - self.draw_score(gc) + self.draw_score(cr) def expose_cb(self, area, event): self.draw() diff --git a/keyboard.py b/keyboard.py index 35daeed..25e870e 100644 --- a/keyboard.py +++ b/keyboard.py @@ -16,12 +16,14 @@ #!/usr/bin/env python # vi:sw=4 et -import pygtk -pygtk.require('2.0') import gtk +import cairo +import copy import rsvg import os, glob, re import pango +import pangocairo +import StringIO from port import json import subprocess from layouts.olpc import OLPC_LAYOUT @@ -130,8 +132,7 @@ class KeyboardImages: scale_width = int(scale_width * 1.1625) for filename in glob.iglob('images/OLPC*.svg'): - image = gtk.gdk.pixbuf_new_from_file_at_scale(filename, scale_width, - self.height, False) + image = rsvg.Handle(file=filename) name = os.path.basename(filename) self.images[name] = image @@ -383,30 +384,27 @@ class KeyboardWidget(KeyboardData, gtk.DrawingArea): k['key-width'] = int(k['key-width'] * width_scale) k['key-height'] = int(k['key-height'] * height_scale) - self._make_all_key_images() - - def _make_key_images(self, key): - key['key-images'] = {} - for group in [0, 1]: - for state in [0, gtk.gdk.SHIFT_MASK, gtk.gdk.MOD5_MASK, gtk.gdk.SHIFT_MASK|gtk.gdk.MOD5_MASK]: - key['key-images'][(state, group)] = self.get_key_image(key, state, group) + def _draw_key(self, k, cr): + bounds = self.get_allocation() - def _make_all_key_images(self): - for key in self.keys: - self._make_key_images(key) + # HACK: this is a hack used when the widget is not shown yet, + # in that case bounds will be gtk.gdk.Rectangle(-1, -1, 1, 1) + # and the key will be outside the canvas. This is used only + # for the first key that appears below the instructions + if bounds.x == -1: + screen_x = screen_y = 0 + else: + screen_x = int(bounds.width - self.image.width) / 2 + screen_y = int(bounds.height - self.image.height) / 2 - def _draw_key(self, k, draw, gc, for_pixmap, w=0, h=0): - x1 = 0 - y1 = 0 - x2 = w - y2 = h + x1 = k['key-x'] + screen_x + y1 = k['key-y'] + screen_y + x2 = x1 + k['key-width'] + y2 = y1 + k['key-height'] - # Outline rounded box. - gc.foreground = self.get_colormap().alloc_color(int(0.4*65536),int(0.7*65536),int(0.4*65536)) - corner = 5 points = [ - (x1 + corner, y1), + (x1 + corner, y1), (x2 - corner, y1), (x2, y1 + corner), (x2, y2 - corner), @@ -414,26 +412,40 @@ class KeyboardWidget(KeyboardData, gtk.DrawingArea): (x1 + corner, y2), (x1, y2 - corner), (x1, y1 + corner) - ] - draw.draw_polygon(gc, True, points) - - # Inner text. - gc.foreground = self.get_colormap().alloc_color(int(1.0*65536),int(1.0*65536),int(1.0*65536)) + ] + + cr.save() + cr.new_path() + cr.set_source_rgb(0.396, 0.698, 0.392) + cr.set_line_width(2) + cr.move_to(*points[0]) + for point in points: + cr.line_to(*point) + cr.line_to(*points[0]) + cr.close_path() + cr.fill_preserve() + cr.stroke() + cr.restore() text = '' if k['key-label']: text = k['key-label'] else: - text = self.get_letter_for_key_state_group(k, self.active_state, self.active_group) - - try: - layout = self.create_pango_layout(unicode(text)) - layout.set_font_description(pango.FontDescription('Monospace')) - draw.draw_layout(gc, x1+8, y2-23, layout) - except: - pass - - def _expose_hands(self, gc): + text = self.get_letter_for_key_state_group( + k, self.active_state, self.active_group) + + pango_context = pangocairo.CairoContext(cr) + pango_context.set_source_rgb(0, 0, 0) + + pango_layout = pango_context.create_layout() + pango_layout.set_font_description(pango.FontDescription('Monospace')) + pango_layout.set_text(unicode(text)) + + pango_context.move_to(x1 + 8, y2 - 23) + pango_context.show_layout(pango_layout) + cr.stroke() + + def _expose_hands(self, cr): lhand_image = self.image.images['OLPC_Lhand_HOMEROW.svg'] rhand_image = self.image.images['OLPC_Rhand_HOMEROW.svg'] @@ -459,39 +471,32 @@ class KeyboardWidget(KeyboardData, gtk.DrawingArea): # TODO: Do something about ALTGR. - bounds = self.get_allocation() - screen_x = int(bounds.width-self.image.width)/2 - screen_y = int(bounds.height-self.image.height)/2 + # bounds = self.get_allocation() + # screen_x = int(bounds.width-self.image.width)/2 + # screen_y = int(bounds.height-self.image.height)/2 + + # README: these values (cairo.Matrix) are taken seeing the image on the + # screen, I think we should find a way to calculate them + cr.save() + matrix = cairo.Matrix(xx=0.3, yy=0.2, x0=10, y0=-20) + cr.transform(matrix) + lhand_image.render_cairo(cr) - self.window.draw_pixbuf(gc, lhand_image, 0, 0, screen_x, screen_y + HAND_YOFFSET) - self.window.draw_pixbuf(gc, rhand_image, 0, 0, screen_x, screen_y + HAND_YOFFSET) + cr.restore() + matrix = cairo.Matrix(xx=0.325, yy=0.2, x0=-5, y0=-20) + cr.transform(matrix) + rhand_image.render_cairo(cr) def _expose_cb(self, area, event): - gc = self.window.new_gc() - - bounds = self.get_allocation() - screen_x = int(bounds.width-self.image.width)/2 - screen_y = int(bounds.height-self.image.height)/2 + cr = self.window.cairo_create() # Draw the keys. for k in self.keys: - x1 = k['key-x'] + screen_x - y1 = k['key-y'] + screen_y - x2 = x1 + k['key-width'] - y2 = y1 + k['key-height'] - - # Index cached key images by state and group. - state = self.active_state & (gtk.gdk.SHIFT_MASK|gtk.gdk.MOD5_MASK) - index = (state, self.active_group) - image = k['key-images'].get(index) - - if image: - self.window.draw_image(gc, image, 0, 0, x1, y1, x2-x1, y2-y1) - + self._draw_key(k, cr) + # Draw overlay images. if self.draw_hands: - self._expose_hands(gc) - + self._expose_hands(cr) return True def key_press_release_cb(self, widget, event): @@ -512,14 +517,10 @@ class KeyboardWidget(KeyboardData, gtk.DrawingArea): sig = self.format_key_sig(event.hardware_keycode, event.state, event.group) if not self.letter_map.has_key(sig): self.letter_map[sig] = event.string - self._make_key_images(key) self.queue_draw() return False - def _keys_changed_cb(self, keymap): - self._make_key_images() - def clear_hilite(self): self.hilite_letter = None self.queue_draw() @@ -535,43 +536,31 @@ class KeyboardWidget(KeyboardData, gtk.DrawingArea): def get_key_pixbuf(self, key, state=0, group=0, scale=1): w = int(key['key-width'] * scale) h = int(key['key-height'] * scale) - + old_state, old_group = self.active_state, self.active_group self.active_state, self.active_group = state, group - - pixmap = gtk.gdk.Pixmap(self.root_window.window, w, h) - gc = pixmap.new_gc() - - gc.foreground = self.get_colormap().alloc_color('#d0d0d0') - pixmap.draw_rectangle(gc, True, 0, 0, w, h) - self._draw_key(key, pixmap, gc, True, w, h) - - pb = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, w, h) - pb.get_from_drawable(pixmap, self.root_window.window.get_colormap(), 0, 0, 0, 0,w, h) - - self.active_state, self.active_group = old_state, old_group + surface = cairo.ImageSurface(cairo.FORMAT_RGB24, w, h) + cr = cairo.Context(surface) + cr.set_source_rgb(1, 1, 1) + cr.rectangle(0, 0, w, h) + cr.fill() - return pb + # Duplicate the Key to be able to change its position values + key = copy.deepcopy(key) + key['key-x'] = 0 + key['key-y'] = 0 - def get_key_image(self, key, state=0, group=0, scale=1): - w = int(key['key-width'] * scale) - h = int(key['key-height'] * scale) - - old_state, old_group = self.active_state, self.active_group - self.active_state, self.active_group = state, group - - pixmap = gtk.gdk.Pixmap(self.root_window.window, w, h) - gc = pixmap.new_gc() - - gc.foreground = self.get_colormap().alloc_color('#d0d0d0') - pixmap.draw_rectangle(gc, True, 0, 0, w, h) + self._draw_key(key, cr) + + # Convert cairo.Surface to Pixbuf + pixbuf_data = StringIO.StringIO() + surface.write_to_png(pixbuf_data) + pxb_loader = gtk.gdk.PixbufLoader(image_type='png') + pxb_loader.write(pixbuf_data.getvalue()) + temp_pix = pxb_loader.get_pixbuf() + pxb_loader.close() - self._draw_key(key, pixmap, gc, True, w, h) - - image = pixmap.get_image(0, 0, w, h) - self.active_state, self.active_group = old_state, old_group - return image - + return temp_pix diff --git a/titlescene.py b/titlescene.py index 7cc2d68..4dc6ae4 100644 --- a/titlescene.py +++ b/titlescene.py @@ -20,13 +20,15 @@ from gettext import gettext as _ # Import PyGTK. import gobject, pygtk, gtk, pango +import pangocairo + class TitleScene(gtk.DrawingArea): # Maximum portion of the screen the background can fill vertically. BACKGROUND_HEIGHT_RATIO = 0.6 # Border from top right of screen to draw title at. - TITLE_OFFSET = (20, 30) + TITLE_OFFSET = (20, 50) # Font used to display the title. TITLE_FONT = 'Times 45' @@ -52,30 +54,38 @@ class TitleScene(gtk.DrawingArea): def expose_cb(self, area, event): bounds = self.get_allocation() - - gc = self.get_style().fg_gc[gtk.STATE_NORMAL] + + cr = self.window.cairo_create() # Background picture. x = (bounds.width - self.backgroundpixbuf.get_width())/2 - self.window.draw_pixbuf( - gc, self.backgroundpixbuf, 0, 0, - x, 0, self.backgroundpixbuf.get_width(), self.backgroundpixbuf.get_height()) - pc = self.create_pango_context() - - self.layout = self.create_pango_layout('') - self.layout.set_font_description(pango.FontDescription(TitleScene.TITLE_FONT)) - - self.layout.set_text(self.title_original) - original_size = self.layout.get_size() - self.x_text = (bounds.width-original_size[0]/pango.SCALE)-TitleScene.TITLE_OFFSET[0] + cr.set_source_pixbuf(self.backgroundpixbuf, 0, 0) + cr.rectangle(x, 0, self.backgroundpixbuf.get_width(), + self.backgroundpixbuf.get_height()) + cr.paint() + + cr = pangocairo.CairoContext(cr) + cr.set_source_rgb(0, 0, 0) + self.pango_layout = cr.create_layout() + self.pango_layout.set_font_description( + pango.FontDescription(TitleScene.TITLE_FONT)) + self.pango_layout.set_text(unicode(self.title_original)) + + original_size = self.pango_layout.get_size() + self.x_text = (bounds.width - original_size[0] / pango.SCALE) - \ + TitleScene.TITLE_OFFSET[0] self.y_text = TitleScene.TITLE_OFFSET[1] + gobject.timeout_add(50, self.timer_cb) def draw_text(self): # Animated Typing Turtle title. - gc = self.get_style().fg_gc[gtk.STATE_NORMAL] - self.layout.set_text(self.title_text) - self.window.draw_layout(gc, self.x_text, self.y_text, self.layout) + cr = self.window.cairo_create() + + cr.move_to(self.x_text, self.y_text) + self.pango_layout.set_text(unicode(self.title_text)) + cr.show_layout(self.pango_layout) + cr.stroke() def timer_cb(self): if len(self.title_src) > 0: -- cgit v0.9.1