Ticket #3772: 0001-Port-to-Cairo.2.patch
File 0001-Port-to-Cairo.2.patch, 20.8 KB (added by humitos, 12 years ago) |
---|
-
balloongame.py
From 15637e1a2b112ad5f67a498d837a97832b679887 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann <humitos@gmail.com> Date: Wed, 25 Jul 2012 10:54:15 -0300 Subject: [PATCH TypingTurtle 1/2] Port to Cairo This will ease the port to GTK+ 3 Signed-off-by: Manuel Kaufmann <humitos@gmail.com> --- balloongame.py | 151 ++++++++++++++++++++++++++++------------------ keyboard.py | 187 +++++++++++++++++++++++++++------------------------------ titlescene.py | 44 ++++++++------ 3 files changed, 206 insertions(+), 176 deletions(-) diff --git a/balloongame.py b/balloongame.py index 56a6a34..7224893 100644
a b 14 14 # You should have received a copy of the GNU General Public License 15 15 # along with Typing Turtle. If not, see <http://www.gnu.org/licenses/>. 16 16 17 import math 17 18 import random, datetime 19 import pangocairo 20 18 21 from gettext import gettext as _ 19 22 20 23 import gobject, pygtk, gtk, pango … … class BalloonGame(gtk.VBox): 192 195 193 196 return True 194 197 195 def draw_results(self, gc):198 def draw_results(self, cr): 196 199 # Draw background. 197 200 w = self.bounds.width - 400 198 201 h = self.bounds.height - 200 199 202 x = self.bounds.width/2 - w/2 200 203 y = self.bounds.height/2 - h/2 201 204 202 gc.foreground = self.area.get_colormap().alloc_color(50000,50000,50000) 203 self.area.window.draw_rectangle(gc, True, x, y, w, h) 204 gc.foreground = self.area.get_colormap().alloc_color(0,0,0) 205 self.area.window.draw_rectangle(gc, False, x, y, w, h) 205 cr.set_source_rgb(0.762, 0.762, 0.762) 206 cr.rectangle(x, y, w, h) 207 cr.fill() 206 208 207 # Draw text 208 gc.foreground = self.area.get_colormap().alloc_color(0,0,0) 209 cr.set_source_rgb(0, 0, 0) 210 cr.rectangle(x, y, w, h) 211 cr.stroke() 209 212 213 # Draw text 210 214 title = _('You finished!') + '\n' 211 layout = self.area.create_pango_layout(title) 212 layout.set_font_description(pango.FontDescription('Serif Bold 16')) 213 size = layout.get_size() 214 tx = x+w/2-(size[0]/pango.SCALE)/2 215 216 pango_cr = pangocairo.CairoContext(cr) 217 pango_cr.set_source_rgb(0, 0, 0) 218 pango_layout = cr.create_layout() 219 pango_layout.set_font_description(pango.FontDescription('Serif Bold 16')) 220 pango_layout.set_text(title) 221 size = pango_layout.get_size() 222 tx = x + (w / 2) - (size[0] / pango.SCALE) / 2 215 223 ty = y + 100 216 self.area.window.draw_layout(gc, tx, ty, layout) 224 pango_cr.move_to(tx, ty) 225 pango_cr.show_layout(pango_layout) 226 pango_cr.stroke() 217 227 218 228 report = '' 219 229 report += _('Your score was %(score)d.') % { 'score': self.score } + '\n' … … class BalloonGame(gtk.VBox): 222 232 report += '\n' 223 233 report += _('Press the ENTER key to continue.') 224 234 225 layout = self.area.create_pango_layout(report) 226 layout.set_font_description(pango.FontDescription('Times 12')) 227 size = layout.get_size() 228 tx = x+w/2-(size[0]/pango.SCALE)/2 229 ty = y + 200 230 self.area.window.draw_layout(gc, tx, ty, layout) 235 pango_cr = pangocairo.CairoContext(cr) 236 pango_cr.set_source_rgb(0, 0, 0) 237 pango_layout = cr.create_layout() 238 pango_layout.set_font_description(pango.FontDescription('Times 12')) 239 pango_layout.set_text(report) 240 size = pango_layout.get_size() 241 sx = x + w / 2 - (size[0] / pango.SCALE) / 2 242 sy = y + 200 243 pango_cr.move_to(sx, sy) 244 pango_cr.show_layout(pango_layout) 245 pango_cr.stroke() 246 231 247 232 248 def finish_game(self): 233 249 self.finished = True … … class BalloonGame(gtk.VBox): 290 306 h = int(b.size*1.5 + 10) 291 307 self.area.queue_draw_area(x, y, w, h) 292 308 293 def draw_balloon(self, gc, b):309 def draw_balloon(self, cr, b): 294 310 x = int(b.x) 295 311 y = int(b.y) 296 312 297 313 # Draw the string. 298 gc.foreground = self.area.get_colormap().alloc_color(0,0,0)299 self.area.window.draw_line(gc,300 int(b.x), int(b.y+b.size/2),301 int(b.x), int(b.y+b.size))302 314 cr.set_source_rgb(0, 0, 0) 315 cr.move_to(int(b.x), int(b.y + b.size / 2)) 316 cr.line_to(int(b.x), int(b.y + b.size)) 317 cr.stroke() 318 303 319 # Draw the balloon. 304 gc.foreground = self.area.get_colormap().alloc_color(b.color[0],b.color[1],b.color[2]) 305 self.area.window.draw_arc(gc, True, x-b.size/2, y-b.size/2, b.size, b.size, 0, 360*64) 306 307 # Draw the text. 308 gc.foreground = self.area.get_colormap().alloc_color(0,0,0) 309 layout = self.area.create_pango_layout(b.word) 310 layout.set_font_description(pango.FontDescription('Sans 12')) 311 size = layout.get_size() 312 tx = x-(size[0]/pango.SCALE)/2 313 ty = y-(size[1]/pango.SCALE)/2 314 self.area.window.draw_layout(gc, tx, ty, layout) 315 320 cr.save() 321 cr.set_source_rgb(b.color[0], b.color[1], b.color[2]) 322 cr.arc(b.x, b.y, b.size / 2, 0, 2 * math.pi) 323 cr.fill() 324 cr.restore() 325 326 pango_cr = pangocairo.CairoContext(cr) 327 pango_cr.set_source_rgb(0, 0, 0) 328 pango_layout = cr.create_layout() 329 pango_layout.set_font_description(pango.FontDescription('Sans 12')) 330 pango_layout.set_text(unicode(b.word)) 331 size = pango_layout.get_size() 332 x = x - (size[0] / pango.SCALE) / 2 333 y = y - (size[1] / pango.SCALE) / 2 334 pango_cr.move_to(x, y) 335 pango_cr.show_layout(pango_layout) 336 pango_cr.stroke() 337 316 338 def add_score(self, num): 317 339 self.score += num 318 340 self.queue_draw_score() … … class BalloonGame(gtk.VBox): 325 347 y = 20 326 348 self.queue_draw_area(x, y, x+size[0], y+size[1]) 327 349 328 def draw_score(self, gc): 329 layout = self.area.create_pango_layout(_('SCORE: %d') % self.score) 330 layout.set_font_description(pango.FontDescription('Times 14')) 331 size = layout.get_size() 332 x = self.bounds.width-20-size[0]/pango.SCALE 350 def draw_score(self, cr): 351 pango_cr = pangocairo.CairoContext(cr) 352 pango_cr.set_source_rgb(0, 0, 0) 353 pango_layout = cr.create_layout() 354 pango_layout.set_font_description(pango.FontDescription('Times 14')) 355 pango_layout.set_text(_('SCORE: %d') % self.score) 356 size = pango_layout.get_size() 357 x = self.bounds.width - 20 - size[0] / pango.SCALE 333 358 y = 20 334 self.area.window.draw_layout(gc, x, y, layout) 359 pango_cr.move_to(x, y) 360 pango_cr.show_layout(pango_layout) 361 pango_cr.stroke() 335 362 336 def draw_instructions(self, gc):363 def draw_instructions(self, cr): 337 364 # Draw instructions. 338 gc.foreground = self.area.get_colormap().alloc_color(0,0,0) 339 340 layout = self.area.create_pango_layout(_('Type the words to pop the balloons!')) 341 layout.set_font_description(pango.FontDescription('Times 14')) 342 size = layout.get_size() 343 x = (self.bounds.width - size[0]/pango.SCALE)/2 344 y = self.bounds.height-20 - size[1]/pango.SCALE 345 self.area.window.draw_layout(gc, x, y, layout) 365 pango_cr = pangocairo.CairoContext(cr) 366 pango_cr.set_source_rgb(0, 0, 0) 367 pango_layout = cr.create_layout() 368 pango_layout.set_font_description(pango.FontDescription('Times 14')) 369 pango_layout.set_text(_('Type the words to pop the balloons!')) 370 size = pango_layout.get_size() 371 x = (self.bounds.width - size[0] / pango.SCALE) / 2 372 y = self.bounds.height - 20 - size[1] / pango.SCALE 373 pango_cr.move_to(x, y) 374 pango_cr.show_layout(pango_layout) 375 pango_cr.stroke() 346 376 347 377 def draw(self): 348 378 self.bounds = self.area.get_allocation() 349 379 350 gc = self.area.window.new_gc()351 380 cr = self.area.window.cairo_create() 381 352 382 # Draw background. 353 gc.foreground = self.area.get_colormap().alloc_color(60000,60000,65535) 354 self.area.window.draw_rectangle(gc, True, 0, 0, self.bounds.width, self.bounds.height) 383 cr.set_source_rgb(0.915, 0.915, 1) 384 cr.rectangle(0, 0, self.bounds.width, self.bounds.height) 385 cr.fill() 355 386 356 387 # Draw the balloons. 357 388 for b in self.balloons: 358 self.draw_balloon( gc, b)389 self.draw_balloon(cr, b) 359 390 360 391 if self.finished: 361 self.draw_results( gc)392 self.draw_results(cr) 362 393 363 394 else: 364 self.draw_instructions( gc)395 self.draw_instructions(cr) 365 396 366 self.draw_score( gc)397 self.draw_score(cr) 367 398 368 399 def expose_cb(self, area, event): 369 400 self.draw() -
keyboard.py
diff --git a/keyboard.py b/keyboard.py index 35daeed..25e870e 100644
a b 16 16 #!/usr/bin/env python 17 17 # vi:sw=4 et 18 18 19 import pygtk20 pygtk.require('2.0')21 19 import gtk 20 import cairo 21 import copy 22 22 import rsvg 23 23 import os, glob, re 24 24 import pango 25 import pangocairo 26 import StringIO 25 27 from port import json 26 28 import subprocess 27 29 from layouts.olpc import OLPC_LAYOUT … … class KeyboardImages: 130 132 scale_width = int(scale_width * 1.1625) 131 133 132 134 for filename in glob.iglob('images/OLPC*.svg'): 133 image = gtk.gdk.pixbuf_new_from_file_at_scale(filename, scale_width, 134 self.height, False) 135 image = rsvg.Handle(file=filename) 135 136 name = os.path.basename(filename) 136 137 self.images[name] = image 137 138 … … class KeyboardWidget(KeyboardData, gtk.DrawingArea): 383 384 k['key-width'] = int(k['key-width'] * width_scale) 384 385 k['key-height'] = int(k['key-height'] * height_scale) 385 386 386 self._make_all_key_images() 387 388 def _make_key_images(self, key): 389 key['key-images'] = {} 390 for group in [0, 1]: 391 for state in [0, gtk.gdk.SHIFT_MASK, gtk.gdk.MOD5_MASK, gtk.gdk.SHIFT_MASK|gtk.gdk.MOD5_MASK]: 392 key['key-images'][(state, group)] = self.get_key_image(key, state, group) 387 def _draw_key(self, k, cr): 388 bounds = self.get_allocation() 393 389 394 def _make_all_key_images(self): 395 for key in self.keys: 396 self._make_key_images(key) 390 # HACK: this is a hack used when the widget is not shown yet, 391 # in that case bounds will be gtk.gdk.Rectangle(-1, -1, 1, 1) 392 # and the key will be outside the canvas. This is used only 393 # for the first key that appears below the instructions 394 if bounds.x == -1: 395 screen_x = screen_y = 0 396 else: 397 screen_x = int(bounds.width - self.image.width) / 2 398 screen_y = int(bounds.height - self.image.height) / 2 397 399 398 def _draw_key(self, k, draw, gc, for_pixmap, w=0, h=0): 399 x1 = 0 400 y1 = 0 401 x2 = w 402 y2 = h 400 x1 = k['key-x'] + screen_x 401 y1 = k['key-y'] + screen_y 402 x2 = x1 + k['key-width'] 403 y2 = y1 + k['key-height'] 403 404 404 # Outline rounded box.405 gc.foreground = self.get_colormap().alloc_color(int(0.4*65536),int(0.7*65536),int(0.4*65536))406 407 405 corner = 5 408 406 points = [ 409 (x1 + corner, y1), 407 (x1 + corner, y1), 410 408 (x2 - corner, y1), 411 409 (x2, y1 + corner), 412 410 (x2, y2 - corner), … … class KeyboardWidget(KeyboardData, gtk.DrawingArea): 414 412 (x1 + corner, y2), 415 413 (x1, y2 - corner), 416 414 (x1, y1 + corner) 417 ] 418 draw.draw_polygon(gc, True, points) 419 420 # Inner text. 421 gc.foreground = self.get_colormap().alloc_color(int(1.0*65536),int(1.0*65536),int(1.0*65536)) 415 ] 416 417 cr.save() 418 cr.new_path() 419 cr.set_source_rgb(0.396, 0.698, 0.392) 420 cr.set_line_width(2) 421 cr.move_to(*points[0]) 422 for point in points: 423 cr.line_to(*point) 424 cr.line_to(*points[0]) 425 cr.close_path() 426 cr.fill_preserve() 427 cr.stroke() 428 cr.restore() 422 429 423 430 text = '' 424 431 if k['key-label']: 425 432 text = k['key-label'] 426 433 else: 427 text = self.get_letter_for_key_state_group(k, self.active_state, self.active_group) 428 429 try: 430 layout = self.create_pango_layout(unicode(text)) 431 layout.set_font_description(pango.FontDescription('Monospace')) 432 draw.draw_layout(gc, x1+8, y2-23, layout) 433 except: 434 pass 435 436 def _expose_hands(self, gc): 434 text = self.get_letter_for_key_state_group( 435 k, self.active_state, self.active_group) 436 437 pango_context = pangocairo.CairoContext(cr) 438 pango_context.set_source_rgb(0, 0, 0) 439 440 pango_layout = pango_context.create_layout() 441 pango_layout.set_font_description(pango.FontDescription('Monospace')) 442 pango_layout.set_text(unicode(text)) 443 444 pango_context.move_to(x1 + 8, y2 - 23) 445 pango_context.show_layout(pango_layout) 446 cr.stroke() 447 448 def _expose_hands(self, cr): 437 449 lhand_image = self.image.images['OLPC_Lhand_HOMEROW.svg'] 438 450 rhand_image = self.image.images['OLPC_Rhand_HOMEROW.svg'] 439 451 … … class KeyboardWidget(KeyboardData, gtk.DrawingArea): 459 471 460 472 # TODO: Do something about ALTGR. 461 473 462 bounds = self.get_allocation() 463 screen_x = int(bounds.width-self.image.width)/2 464 screen_y = int(bounds.height-self.image.height)/2 474 # bounds = self.get_allocation() 475 # screen_x = int(bounds.width-self.image.width)/2 476 # screen_y = int(bounds.height-self.image.height)/2 477 478 # README: these values (cairo.Matrix) are taken seeing the image on the 479 # screen, I think we should find a way to calculate them 480 cr.save() 481 matrix = cairo.Matrix(xx=0.3, yy=0.2, x0=10, y0=-20) 482 cr.transform(matrix) 483 lhand_image.render_cairo(cr) 465 484 466 self.window.draw_pixbuf(gc, lhand_image, 0, 0, screen_x, screen_y + HAND_YOFFSET) 467 self.window.draw_pixbuf(gc, rhand_image, 0, 0, screen_x, screen_y + HAND_YOFFSET) 485 cr.restore() 486 matrix = cairo.Matrix(xx=0.325, yy=0.2, x0=-5, y0=-20) 487 cr.transform(matrix) 488 rhand_image.render_cairo(cr) 468 489 469 490 def _expose_cb(self, area, event): 470 gc = self.window.new_gc() 471 472 bounds = self.get_allocation() 473 screen_x = int(bounds.width-self.image.width)/2 474 screen_y = int(bounds.height-self.image.height)/2 491 cr = self.window.cairo_create() 475 492 476 493 # Draw the keys. 477 494 for k in self.keys: 478 x1 = k['key-x'] + screen_x 479 y1 = k['key-y'] + screen_y 480 x2 = x1 + k['key-width'] 481 y2 = y1 + k['key-height'] 482 483 # Index cached key images by state and group. 484 state = self.active_state & (gtk.gdk.SHIFT_MASK|gtk.gdk.MOD5_MASK) 485 index = (state, self.active_group) 486 image = k['key-images'].get(index) 487 488 if image: 489 self.window.draw_image(gc, image, 0, 0, x1, y1, x2-x1, y2-y1) 490 495 self._draw_key(k, cr) 496 491 497 # Draw overlay images. 492 498 if self.draw_hands: 493 self._expose_hands(gc) 494 499 self._expose_hands(cr) 495 500 return True 496 501 497 502 def key_press_release_cb(self, widget, event): … … class KeyboardWidget(KeyboardData, gtk.DrawingArea): 512 517 sig = self.format_key_sig(event.hardware_keycode, event.state, event.group) 513 518 if not self.letter_map.has_key(sig): 514 519 self.letter_map[sig] = event.string 515 self._make_key_images(key)516 520 self.queue_draw() 517 521 518 522 return False 519 523 520 def _keys_changed_cb(self, keymap):521 self._make_key_images()522 523 524 def clear_hilite(self): 524 525 self.hilite_letter = None 525 526 self.queue_draw() … … class KeyboardWidget(KeyboardData, gtk.DrawingArea): 535 536 def get_key_pixbuf(self, key, state=0, group=0, scale=1): 536 537 w = int(key['key-width'] * scale) 537 538 h = int(key['key-height'] * scale) 538 539 539 540 old_state, old_group = self.active_state, self.active_group 540 541 self.active_state, self.active_group = state, group 541 542 pixmap = gtk.gdk.Pixmap(self.root_window.window, w, h)543 gc = pixmap.new_gc()544 545 gc.foreground = self.get_colormap().alloc_color('#d0d0d0')546 pixmap.draw_rectangle(gc, True, 0, 0, w, h)547 542 548 self._draw_key(key, pixmap, gc, True, w, h) 549 550 pb = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, w, h) 551 pb.get_from_drawable(pixmap, self.root_window.window.get_colormap(), 0, 0, 0, 0,w, h) 552 553 self.active_state, self.active_group = old_state, old_group 543 surface = cairo.ImageSurface(cairo.FORMAT_RGB24, w, h) 544 cr = cairo.Context(surface) 545 cr.set_source_rgb(1, 1, 1) 546 cr.rectangle(0, 0, w, h) 547 cr.fill() 554 548 555 return pb 549 # Duplicate the Key to be able to change its position values 550 key = copy.deepcopy(key) 551 key['key-x'] = 0 552 key['key-y'] = 0 556 553 557 def get_key_image(self, key, state=0, group=0, scale=1): 558 w = int(key['key-width'] * scale) 559 h = int(key['key-height'] * scale) 560 561 old_state, old_group = self.active_state, self.active_group 562 self.active_state, self.active_group = state, group 563 564 pixmap = gtk.gdk.Pixmap(self.root_window.window, w, h) 565 gc = pixmap.new_gc() 566 567 gc.foreground = self.get_colormap().alloc_color('#d0d0d0') 568 pixmap.draw_rectangle(gc, True, 0, 0, w, h) 554 self._draw_key(key, cr) 555 556 # Convert cairo.Surface to Pixbuf 557 pixbuf_data = StringIO.StringIO() 558 surface.write_to_png(pixbuf_data) 559 pxb_loader = gtk.gdk.PixbufLoader(image_type='png') 560 pxb_loader.write(pixbuf_data.getvalue()) 561 temp_pix = pxb_loader.get_pixbuf() 562 pxb_loader.close() 569 563 570 self._draw_key(key, pixmap, gc, True, w, h)571 572 image = pixmap.get_image(0, 0, w, h)573 574 564 self.active_state, self.active_group = old_state, old_group 575 565 576 return image 577 566 return temp_pix -
titlescene.py
diff --git a/titlescene.py b/titlescene.py index 7cc2d68..4dc6ae4 100644
a b from gettext import gettext as _ 20 20 21 21 # Import PyGTK. 22 22 import gobject, pygtk, gtk, pango 23 import pangocairo 24 23 25 24 26 class TitleScene(gtk.DrawingArea): 25 27 # Maximum portion of the screen the background can fill vertically. 26 28 BACKGROUND_HEIGHT_RATIO = 0.6 27 29 28 30 # Border from top right of screen to draw title at. 29 TITLE_OFFSET = (20, 30)31 TITLE_OFFSET = (20, 50) 30 32 31 33 # Font used to display the title. 32 34 TITLE_FONT = 'Times 45' … … class TitleScene(gtk.DrawingArea): 52 54 53 55 def expose_cb(self, area, event): 54 56 bounds = self.get_allocation() 55 56 gc = self.get_style().fg_gc[gtk.STATE_NORMAL]57 58 cr = self.window.cairo_create() 57 59 58 60 # Background picture. 59 61 x = (bounds.width - self.backgroundpixbuf.get_width())/2 60 self.window.draw_pixbuf( 61 gc, self.backgroundpixbuf, 0, 0, 62 x, 0, self.backgroundpixbuf.get_width(), self.backgroundpixbuf.get_height()) 63 pc = self.create_pango_context() 64 65 self.layout = self.create_pango_layout('') 66 self.layout.set_font_description(pango.FontDescription(TitleScene.TITLE_FONT)) 67 68 self.layout.set_text(self.title_original) 69 original_size = self.layout.get_size() 70 self.x_text = (bounds.width-original_size[0]/pango.SCALE)-TitleScene.TITLE_OFFSET[0] 62 cr.set_source_pixbuf(self.backgroundpixbuf, 0, 0) 63 cr.rectangle(x, 0, self.backgroundpixbuf.get_width(), 64 self.backgroundpixbuf.get_height()) 65 cr.paint() 66 67 cr = pangocairo.CairoContext(cr) 68 cr.set_source_rgb(0, 0, 0) 69 self.pango_layout = cr.create_layout() 70 self.pango_layout.set_font_description( 71 pango.FontDescription(TitleScene.TITLE_FONT)) 72 self.pango_layout.set_text(unicode(self.title_original)) 73 74 original_size = self.pango_layout.get_size() 75 self.x_text = (bounds.width - original_size[0] / pango.SCALE) - \ 76 TitleScene.TITLE_OFFSET[0] 71 77 self.y_text = TitleScene.TITLE_OFFSET[1] 78 72 79 gobject.timeout_add(50, self.timer_cb) 73 80 74 81 def draw_text(self): 75 82 # Animated Typing Turtle title. 76 gc = self.get_style().fg_gc[gtk.STATE_NORMAL] 77 self.layout.set_text(self.title_text) 78 self.window.draw_layout(gc, self.x_text, self.y_text, self.layout) 83 cr = self.window.cairo_create() 84 85 cr.move_to(self.x_text, self.y_text) 86 self.pango_layout.set_text(unicode(self.title_text)) 87 cr.show_layout(self.pango_layout) 88 cr.stroke() 79 89 80 90 def timer_cb(self): 81 91 if len(self.title_src) > 0: