Attachments you submit will be routed for moderation. If you have an account, please log in first.

Ticket #3454: 0001-Port-to-Cairo.patch

File 0001-Port-to-Cairo.patch, 13.8 KB (added by manuq, 14 months ago)
  • clock.py

    From 40ae77291c5de5dded5a89d87b5d2b645c3c86aa Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?Manuel=20Qui=C3=B1ones?= <manuq@laptop.org>
    Date: Tue, 27 Dec 2011 13:25:31 -0300
    Subject: [PATCH clock 1/2] Port to Cairo
    MIME-Version: 1.0
    Content-Type: text/plain; charset=UTF-8
    Content-Transfer-Encoding: 8bit
    
    This will ease the port to GTK+ 3, and it gains in nicer graphics,
    sharp edges now have antialiasing.
    
    Signed-off-by: Manuel Quiñones <manuq@laptop.org>
    ---
     clock.py |  182 ++++++++++++++++++++++++++++++++++----------------------------
     1 files changed, 100 insertions(+), 82 deletions(-)
    
    diff --git a/clock.py b/clock.py
    index 1893b77..7635b2e 100755
    a b  
    7070import gtk 
    7171from gtk import gdk 
    7272import pango 
     73import cairo 
     74import pangocairo 
     75import rsvg 
    7376 
    7477OLD_TOOLBAR = False 
    7578try: 
     
    8285import math 
    8386from datetime import datetime 
    8487import threading 
    85 import gc 
    8688import re 
    8789 
    8890from pgettext import pgettext as _ 
     
    9092from sugar.activity import activity 
    9193from sugar.graphics.toggletoolbutton import ToggleToolButton 
    9294from sugar.graphics.radiotoolbutton import RadioToolButton 
     95from sugar.graphics import style 
    9396 
    9497from speaker import Speaker 
    9598from timewriter import TimeWriter 
     
    477480        # The display mode of the clock 
    478481        self._mode = _MODE_SIMPLE_CLOCK 
    479482 
    480         # SVG Background cache 
    481         self._cache_pixbuf = None 
    482         self._radius = -1 
     483        # SVG Background handle 
     484        self._svg_handle = None 
    483485 
    484         # The graphic context used for drawings 
    485         self._gc = None 
     486        self._radius = -1 
    486487        self._line_width = 2 
    487488 
    488489        # Color codes (approved colors for XO screen: 
    489490        # http://wiki.laptop.org/go/XO_colors) 
    490         colormap = self.get_colormap() 
    491491 
    492492        # XO Medium Blue 
    493         self._COLOR_HOURS = colormap.alloc_color("#005FE4") 
     493        self._COLOR_HOURS = "#005FE4" 
    494494 
    495495        # XO Medium Green 
    496         self._COLOR_MINUTES = colormap.alloc_color("#00B20D") 
     496        self._COLOR_MINUTES = "#00B20D" 
    497497 
    498498        # XO Medium Red 
    499         self._COLOR_SECONDS = colormap.alloc_color("#E6000A") 
     499        self._COLOR_SECONDS = "#E6000A" 
    500500 
    501501        # White 
    502         self._COLOR_WHITE = colormap.alloc_color("#FFFFFF") 
     502        self._COLOR_WHITE = "#FFFFFF" 
    503503 
    504504        # Black 
    505         self._COLOR_BLACK = colormap.alloc_color("#000000") 
     505        self._COLOR_BLACK = "#000000" 
    506506 
    507507        # gtk.Widget signals 
    508508        self.connect("expose-event", self._expose_cb) 
     
    538538        self._height = allocation.height 
    539539        self._line_width = int(self._radius / 150) 
    540540 
    541         # Reload the cached pixbuf 
    542         self._cache_pixbuf = gdk.pixbuf_new_from_file_at_size("clock.svg", 
    543           2 * self._radius, 2 * self._radius) 
    544         gc.collect()  # Reclaim memory from old pixbuf 
     541        # Reload the svg handle 
     542        self._svg_handle = rsvg.Handle(file="clock.svg") 
    545543 
    546544        self.initialized = True 
    547545 
     
    558556            self.queue_resize() 
    559557 
    560558        if self._active: 
    561             self._gc = self.window.new_gc() 
    562  
    563559            if self._mode == _MODE_NICE_CLOCK: 
    564560                self._draw_nice_clock() 
    565561            elif self._mode == _MODE_SIMPLE_CLOCK: 
     
    608604        seconds_length = 2 * self._radius / 60 * self._time.second 
    609605 
    610606        # Fill background 
    611         self._gc.set_line_attributes(self._line_width, gdk.LINE_SOLID, \ 
    612                 gdk.CAP_BUTT, gdk.JOIN_BEVEL) 
    613         self._gc.set_foreground(self._COLOR_WHITE) 
    614         self.window.draw_rectangle(self._gc, True, \ 
    615                 int(self._center_x - 1.1 * self._radius), \ 
    616                 int(self._center_y - 0.8 * self._radius), \ 
    617                 int(2.2 * self._radius), \ 
    618                 int(0.55 * self._radius)) 
     607        cr = self.window.cairo_create() 
     608        cr.set_source_rgba(*style.Color(self._COLOR_WHITE).get_rgba()) 
     609        cr.rectangle(int(self._center_x - 1.1 * self._radius), 
     610                     int(self._center_y - 0.8 * self._radius), 
     611                     int(2.2 * self._radius), 
     612                     int(0.55 * self._radius)) 
     613        cr.fill() 
    619614 
    620615        h = int(0.15 * self._radius) 
    621616        x = int(self._center_x - self._radius) 
    622617 
    623618        # Hours scale 
    624         self._gc.set_foreground(self._COLOR_HOURS) 
     619        cr.set_source_rgba(*style.Color(self._COLOR_HOURS).get_rgba()) 
    625620        y = int(self._center_y - 0.75 * self._radius) 
    626         self.window.draw_rectangle(self._gc, True, x, y, hours_length, h) 
     621        cr.rectangle(x, y, hours_length, h) 
     622        cr.fill() 
    627623 
    628624        # Minutes scale 
    629         self._gc.set_foreground(self._COLOR_MINUTES) 
     625        cr.set_source_rgba(*style.Color(self._COLOR_MINUTES).get_rgba()) 
    630626        y = int(self._center_y - 0.60 * self._radius) 
    631         self.window.draw_rectangle(self._gc, True, x, y, minutes_length, h) 
     627        cr.rectangle(x, y, minutes_length, h) 
     628        cr.fill() 
    632629 
    633630        # Seconds scale 
    634         self._gc.set_foreground(self._COLOR_SECONDS) 
     631        cr.set_source_rgba(*style.Color(self._COLOR_SECONDS).get_rgba()) 
    635632        y = int(self._center_y - 0.45 * self._radius) 
    636         self.window.draw_rectangle(self._gc, True, x, y, seconds_length, h) 
     633        cr.rectangle(x, y, seconds_length, h) 
     634        cr.fill() 
    637635 
    638636    def _draw_time(self): 
    639637        """Draw the time in colors (digital display). 
     
    655653        markup_time = self._time.strftime(markup) 
    656654        #markup_time = time.strftime(markup) 
    657655 
    658         self._gc.set_foreground(self._COLOR_BLACK) 
     656        cr = self.window.cairo_create() 
     657        cr = pangocairo.CairoContext(cr) 
     658        cr.set_source_rgba(*style.Color(self._COLOR_BLACK).get_rgba()) 
     659        pango_layout = cr.create_layout() 
    659660        d = int(self._center_y + 0.3 * self._radius) 
    660         self._draw_markup(self._center_x, d, markup_time) 
     661        pango_layout.set_markup(markup_time) 
     662        dx, dy = pango_layout.get_pixel_size() 
     663        pango_layout.set_alignment(pango.ALIGN_CENTER) 
     664        cr.translate(self._center_x - dx / 2.0, d - dy / 2.0) 
     665        cr.show_layout(pango_layout) 
    661666 
    662667    def _draw_simple_clock(self): 
    663668        """Draw the simple clock variants. 
     
    671676        The simple clock background is a white disk, with hours and minutes 
    672677        ticks, and the hour numbers. 
    673678        """ 
     679        cr = self.window.cairo_create() 
     680        cr.set_line_width(4 * self._line_width) 
     681 
    674682        # Simple clock background 
    675         self._gc.set_foreground(self._COLOR_WHITE) 
    676         x_delta = self._center_x - self._radius 
    677         y_delta = self._center_y - self._radius 
    678  
    679         self.window.draw_arc(self._gc, True, x_delta, y_delta, 
    680           2 * self._radius, 2 * self._radius, 0, 360 * 64) 
    681         self._gc.set_foreground(self.get_style().fg[gtk.STATE_NORMAL]) 
    682         self._gc.set_line_attributes(4 * self._line_width, 
    683           gdk.LINE_SOLID, gdk.CAP_ROUND, gdk.JOIN_ROUND) 
    684         self.window.draw_arc(self._gc, False, x_delta, y_delta, 
    685           2 * self._radius, 2 * self._radius, 0, 360 * 64) 
     683        cr.set_source_rgba(*style.Color(self._COLOR_WHITE).get_rgba()) 
     684        cr.arc(self._width / 2, self._height / 2, self._radius, 0, 2 * math.pi) 
     685        cr.fill_preserve() 
     686        cr.set_source_rgba(*style.Color(self._COLOR_BLACK).get_rgba()) 
     687        cr.stroke() 
    686688 
    687689        # Clock ticks 
    688         self._gc.set_line_attributes(4 * self._line_width, 
    689           gdk.LINE_SOLID, gdk.CAP_ROUND, gdk.JOIN_ROUND) 
    690690        for i in xrange(60): 
    691691            if i % 15 == 0: 
    692692                inset = 0.175 * self._radius 
     
    697697 
    698698            cos = math.cos(i * math.pi / 30.0) 
    699699            sin = math.sin(i * math.pi / 30.0) 
    700             self.window.draw_line(self._gc, 
    701               int(self._center_x + (self._radius - inset) * cos), 
    702               int(self._center_y + (self._radius - inset) * sin), 
    703               int(self._center_x + self._radius * cos), 
    704               int(self._center_y + self._radius * sin)) 
     700            cr.move_to(int(self._center_x + (self._radius - inset) * cos), 
     701                       int(self._center_y + (self._radius - inset) * sin)) 
     702            cr.line_to(int(self._center_x + self._radius * cos), 
     703                       int(self._center_y + self._radius * sin)) 
     704            cr.stroke() 
    705705 
    706706    def _draw_nice_background(self): 
    707707        """Draw the nice clock background. 
    708708 
    709709        The background has been loaded from the clock.svg file to a 
    710         pixbuf, and we just draw this pixbuf onto the pixmap where we 
    711         will be drawing the hands. 
    712         """ 
    713         # We draw the background from the SVG pixbuf 
    714         self.window.draw_pixbuf(None, self._cache_pixbuf, 
    715           0, 0, self._center_x - self._radius, self._center_y - self._radius) 
     710        rsvg handle, and we just transform this handle and render it 
     711        with cairo. 
     712        """ 
     713        # We transform the background SVG 
     714        cr = self.window.cairo_create() 
     715        scale_x = self._radius * 2.0 / self._svg_handle.props.width 
     716        scale_y = self._radius * 2.0 / self._svg_handle.props.height 
     717        matrix = cairo.Matrix(xx=scale_x, yy=scale_y, 
     718                              x0=self._center_x - self._radius, 
     719                              y0=self._center_y - self._radius) 
     720        cr.transform(matrix) 
     721        self._svg_handle.render_cairo(cr) 
    716722 
    717723    def _draw_nice_clock(self): 
    718724        """Draw the nice clock. 
     
    727733        minutes = self._time.minute 
    728734        seconds = self._time.second 
    729735 
     736        cr = self.window.cairo_create() 
     737        cr.set_line_cap(cairo.LINE_CAP_ROUND) 
     738 
    730739        # Hour hand: 
    731740        # The hour hand is rotated 30 degrees (pi/6 r) per hour + 
    732741        # 1/2 a degree (pi/360) per minute 
    733         self._gc.set_foreground(self._COLOR_HOURS) 
    734         self._gc.set_line_attributes(8 * self._line_width, 
    735           gdk.LINE_SOLID, gdk.CAP_ROUND, gdk.JOIN_ROUND) 
    736         self.window.draw_line(self._gc, self._center_x, self._center_y, 
    737           int(self._center_x + self._radius * 0.5 * 
    738           math.sin(math.pi / 6 * hours + math.pi / 360 * minutes)), 
    739           int(self._center_y + self._radius * 0.5 * 
    740           - math.cos(math.pi / 6 * hours + math.pi / 360 * minutes))) 
     742        cr.set_source_rgba(*style.Color(self._COLOR_HOURS).get_rgba()) 
     743        cr.set_line_width(8 * self._line_width) 
     744        cr.move_to(self._center_x, self._center_y) 
     745        cr.line_to(int(self._center_x + self._radius * 0.5 * 
     746            math.sin(math.pi / 6 * hours + math.pi / 360 * minutes)), 
     747            int(self._center_y + self._radius * 0.5 * 
     748            - math.cos(math.pi / 6 * hours + math.pi / 360 * minutes))) 
     749        cr.stroke() 
    741750 
    742751        # Minute hand: 
    743752        # The minute hand is rotated 6 degrees (pi/30 r) per minute 
    744         self._gc.set_foreground(self._COLOR_MINUTES) 
    745         self._gc.set_line_attributes(6 * self._line_width, 
    746           gdk.LINE_SOLID, gdk.CAP_ROUND, gdk.JOIN_ROUND) 
    747         self.window.draw_line(self._gc, self._center_x, self._center_y, 
    748                 int(self._center_x + self._radius * 0.8 * 
     753        cr.set_source_rgba(*style.Color(self._COLOR_MINUTES).get_rgba()) 
     754        cr.set_line_width(6 * self._line_width) 
     755        cr.move_to(self._center_x, self._center_y) 
     756        cr.line_to(int(self._center_x + self._radius * 0.8 * 
    749757                math.sin(math.pi / 30 * minutes)), 
    750                 int(self._center_y + self._radius * 0.8 * 
     758                   int(self._center_y + self._radius * 0.8 * 
    751759                - math.cos(math.pi / 30 * minutes))) 
     760        cr.stroke() 
    752761 
    753762        # Seconds hand: 
    754763        # Operates identically to the minute hand 
    755         self._gc.set_foreground(self._COLOR_SECONDS) 
    756         self._gc.set_line_attributes(2 * self._line_width, 
    757           gdk.LINE_SOLID, gdk.CAP_ROUND, gdk.JOIN_ROUND) 
    758         self.window.draw_line(self._gc, self._center_x, self._center_y, 
    759                 int(self._center_x + self._radius * 0.7 * 
     764        cr.set_source_rgba(*style.Color(self._COLOR_SECONDS).get_rgba()) 
     765        cr.set_line_width(2 * self._line_width) 
     766        cr.move_to(self._center_x, self._center_y) 
     767        cr.line_to(int(self._center_x + self._radius * 0.7 * 
    760768                math.sin(math.pi / 30 * seconds)), 
    761769                int(self._center_y + self._radius * 0.7 * 
    762770                - math.cos(math.pi / 30 * seconds))) 
     771        cr.stroke() 
    763772 
    764773    def _draw_numbers(self): 
    765774        """Draw the numbers of the hours. 
    766775        """ 
    767         self._gc.set_foreground(self._COLOR_HOURS) 
     776        cr = self.window.cairo_create() 
     777        cr = pangocairo.CairoContext(cr) 
     778        cr.set_source_rgba(*style.Color(self._COLOR_HOURS).get_rgba()) 
     779        pango_layout = cr.create_layout() 
    768780 
    769781        for i in xrange(12): 
    770782            # TRANS: The format of the font used to print hour 
     
    772784            hour_number = _("Hour Number", 
    773785              '<markup><span lang="en" ' + 
    774786              'font_desc="Sans Bold 20">%d</span></markup>') % (i + 1) 
    775             self._draw_markup(self._center_x + 0.75 * \ 
    776             self._radius * math.cos((i - 2) * math.pi / 6.0), \ 
    777             self._center_y + 0.75 * self._radius * \ 
    778             math.sin((i - 2) * math.pi / 6.0), hour_number) 
     787            cr.save() 
     788            dx, dy = pango_layout.get_pixel_size() 
     789            cr.translate(- dx / 2.0 + self._center_x + 0.75 * 
     790                self._radius * math.cos((i - 2) * math.pi / 6.0), 
     791                - dy / 2.0 + self._center_y + 0.75 * self._radius * 
     792                math.sin((i - 2) * math.pi / 6.0)) 
     793            pango_layout.set_markup(hour_number) 
     794            cr.update_layout(pango_layout) 
     795            cr.show_layout(pango_layout) 
     796            cr.restore() 
    779797 
    780798    def _redraw_canvas(self): 
    781799        """Force a redraw of the clock on the screen.