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

File 0001-Port-to-Cairo.patch, 14.1 KB (added by humitos, 12 years ago)

New patch to make it applies in the latest git version

  • clock.py

    From 2c96f4dbdd858bf5ebf400ca5f2ec2a3efd8b64c Mon Sep 17 00:00:00 2001
    Message-Id: <2c96f4dbdd858bf5ebf400ca5f2ec2a3efd8b64c.1336393804.git.humitos@gmail.com>
    From: Manuel Kaufmann <humitos@gmail.com>
    Date: Mon, 7 May 2012 09:29:51 -0300
    Subject: [PATCH Clock] 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.
    
    Original Patch: Manuel Quiñones <manuq@laptop.org>
    
    I've just made some modification so it applies in the latest git version of Clock Activity.
    
    Signed-off-by: Manuel Kaufmann <humitos@gmail.com>
    ---
     clock.py |  183 ++++++++++++++++++++++++++++++++++----------------------------
     1 file changed, 100 insertions(+), 83 deletions(-)
    
    diff --git a/clock.py b/clock.py
    index 1219aee..9715f65 100755
    a b More about clocks and time in the World 
    6666import gobject
    6767gobject.threads_init()
    6868
    69 import pygtk
    7069import gtk
    7170from gtk import gdk
    7271import pango
     72import cairo
     73import pangocairo
     74import rsvg
    7375import gst
    7476
    7577OLD_TOOLBAR = False
    except ImportError: 
    8385import math
    8486from datetime import datetime
    8587import threading
    86 import gc
    8788import re
    8889
    8990from pgettext import pgettext as _
    from pgettext import pgettext as _ 
    9192from sugar.activity import activity
    9293from sugar.graphics.toggletoolbutton import ToggleToolButton
    9394from sugar.graphics.radiotoolbutton import RadioToolButton
     95from sugar.graphics import style
    9496
    9597from speaker import Speaker
    9698from timewriter import TimeWriter
    class ClockFace(gtk.DrawingArea): 
    491493        # The display mode of the clock
    492494        self._mode = _MODE_SIMPLE_CLOCK
    493495
    494         # SVG Background cache
    495         self._cache_pixbuf = None
    496         self._radius = -1
     496        # SVG Background handle
     497        self._svg_handle = None
    497498
    498         # The graphic context used for drawings
    499         self._gc = None
     499        self._radius = -1
    500500        self._line_width = 2
    501501
    502502        # Color codes (approved colors for XO screen:
    503503        # http://wiki.laptop.org/go/XO_colors)
    504         colormap = self.get_colormap()
    505504
    506505        # XO Medium Blue
    507         self._COLOR_HOURS = colormap.alloc_color("#005FE4")
     506        self._COLOR_HOURS = "#005FE4"
    508507
    509508        # XO Medium Green
    510         self._COLOR_MINUTES = colormap.alloc_color("#00B20D")
     509        self._COLOR_MINUTES = "#00B20D"
    511510
    512511        # XO Medium Red
    513         self._COLOR_SECONDS = colormap.alloc_color("#E6000A")
     512        self._COLOR_SECONDS = "#E6000A"
    514513
    515514        # White
    516         self._COLOR_WHITE = colormap.alloc_color("#FFFFFF")
     515        self._COLOR_WHITE = "#FFFFFF"
    517516
    518517        # Black
    519         self._COLOR_BLACK = colormap.alloc_color("#000000")
     518        self._COLOR_BLACK = "#000000"
    520519
    521520        # gtk.Widget signals
    522521        self.connect("expose-event", self._expose_cb)
    class ClockFace(gtk.DrawingArea): 
    552551        self._height = allocation.height
    553552        self._line_width = int(self._radius / 150)
    554553
    555         # Reload the cached pixbuf
    556         self._cache_pixbuf = gdk.pixbuf_new_from_file_at_size("clock.svg",
    557           2 * self._radius, 2 * self._radius)
    558         gc.collect()  # Reclaim memory from old pixbuf
     554        # Reload the svg handle
     555        self._svg_handle = rsvg.Handle(file="clock.svg")
    559556
    560557        self.initialized = True
    561558
    class ClockFace(gtk.DrawingArea): 
    572569            self.queue_resize()
    573570
    574571        if self._active:
    575             self._gc = self.window.new_gc()
    576 
    577572            if self._mode == _MODE_NICE_CLOCK:
    578573                self._draw_nice_clock()
    579574            elif self._mode == _MODE_SIMPLE_CLOCK:
    class ClockFace(gtk.DrawingArea): 
    622617        seconds_length = 2 * self._radius / 60 * self._time.second
    623618
    624619        # Fill background
    625         self._gc.set_line_attributes(self._line_width, gdk.LINE_SOLID, \
    626                 gdk.CAP_BUTT, gdk.JOIN_BEVEL)
    627         self._gc.set_foreground(self._COLOR_WHITE)
    628         self.window.draw_rectangle(self._gc, True, \
    629                 int(self._center_x - 1.1 * self._radius), \
    630                 int(self._center_y - 0.8 * self._radius), \
    631                 int(2.2 * self._radius), \
    632                 int(0.55 * self._radius))
     620        cr = self.window.cairo_create()
     621        cr.set_source_rgba(*style.Color(self._COLOR_WHITE).get_rgba())
     622        cr.rectangle(int(self._center_x - 1.1 * self._radius),
     623                     int(self._center_y - 0.8 * self._radius),
     624                     int(2.2 * self._radius),
     625                     int(0.55 * self._radius))
     626        cr.fill()
    633627
    634628        h = int(0.15 * self._radius)
    635629        x = int(self._center_x - self._radius)
    636630
    637631        # Hours scale
    638         self._gc.set_foreground(self._COLOR_HOURS)
     632        cr.set_source_rgba(*style.Color(self._COLOR_HOURS).get_rgba())
    639633        y = int(self._center_y - 0.75 * self._radius)
    640         self.window.draw_rectangle(self._gc, True, x, y, hours_length, h)
     634        cr.rectangle(x, y, hours_length, h)
     635        cr.fill()
    641636
    642637        # Minutes scale
    643         self._gc.set_foreground(self._COLOR_MINUTES)
     638        cr.set_source_rgba(*style.Color(self._COLOR_MINUTES).get_rgba())
    644639        y = int(self._center_y - 0.60 * self._radius)
    645         self.window.draw_rectangle(self._gc, True, x, y, minutes_length, h)
     640        cr.rectangle(x, y, minutes_length, h)
     641        cr.fill()
    646642
    647643        # Seconds scale
    648         self._gc.set_foreground(self._COLOR_SECONDS)
     644        cr.set_source_rgba(*style.Color(self._COLOR_SECONDS).get_rgba())
    649645        y = int(self._center_y - 0.45 * self._radius)
    650         self.window.draw_rectangle(self._gc, True, x, y, seconds_length, h)
     646        cr.rectangle(x, y, seconds_length, h)
     647        cr.fill()
    651648
    652649    def _draw_time(self):
    653650        """Draw the time in colors (digital display).
    class ClockFace(gtk.DrawingArea): 
    669666        markup_time = self._time.strftime(markup)
    670667        #markup_time = time.strftime(markup)
    671668
    672         self._gc.set_foreground(self._COLOR_BLACK)
     669        cr = self.window.cairo_create()
     670        cr = pangocairo.CairoContext(cr)
     671        cr.set_source_rgba(*style.Color(self._COLOR_BLACK).get_rgba())
     672        pango_layout = cr.create_layout()
    673673        d = int(self._center_y + 0.3 * self._radius)
    674         self._draw_markup(self._center_x, d, markup_time)
     674        pango_layout.set_markup(markup_time)
     675        dx, dy = pango_layout.get_pixel_size()
     676        pango_layout.set_alignment(pango.ALIGN_CENTER)
     677        cr.translate(self._center_x - dx / 2.0, d - dy / 2.0)
     678        cr.show_layout(pango_layout)
    675679
    676680    def _draw_simple_clock(self):
    677681        """Draw the simple clock variants.
    class ClockFace(gtk.DrawingArea): 
    685689        The simple clock background is a white disk, with hours and minutes
    686690        ticks, and the hour numbers.
    687691        """
     692        cr = self.window.cairo_create()
     693        cr.set_line_width(4 * self._line_width)
     694
    688695        # Simple clock background
    689         self._gc.set_foreground(self._COLOR_WHITE)
    690         x_delta = self._center_x - self._radius
    691         y_delta = self._center_y - self._radius
    692 
    693         self.window.draw_arc(self._gc, True, x_delta, y_delta,
    694           2 * self._radius, 2 * self._radius, 0, 360 * 64)
    695         self._gc.set_foreground(self.get_style().fg[gtk.STATE_NORMAL])
    696         self._gc.set_line_attributes(4 * self._line_width,
    697           gdk.LINE_SOLID, gdk.CAP_ROUND, gdk.JOIN_ROUND)
    698         self.window.draw_arc(self._gc, False, x_delta, y_delta,
    699           2 * self._radius, 2 * self._radius, 0, 360 * 64)
     696        cr.set_source_rgba(*style.Color(self._COLOR_WHITE).get_rgba())
     697        cr.arc(self._width / 2, self._height / 2, self._radius, 0, 2 * math.pi)
     698        cr.fill_preserve()
     699        cr.set_source_rgba(*style.Color(self._COLOR_BLACK).get_rgba())
     700        cr.stroke()
    700701
    701702        # Clock ticks
    702         self._gc.set_line_attributes(4 * self._line_width,
    703           gdk.LINE_SOLID, gdk.CAP_ROUND, gdk.JOIN_ROUND)
    704703        for i in xrange(60):
    705704            if i % 15 == 0:
    706705                inset = 0.175 * self._radius
    class ClockFace(gtk.DrawingArea): 
    711710
    712711            cos = math.cos(i * math.pi / 30.0)
    713712            sin = math.sin(i * math.pi / 30.0)
    714             self.window.draw_line(self._gc,
    715               int(self._center_x + (self._radius - inset) * cos),
    716               int(self._center_y + (self._radius - inset) * sin),
    717               int(self._center_x + self._radius * cos),
    718               int(self._center_y + self._radius * sin))
     713            cr.move_to(int(self._center_x + (self._radius - inset) * cos),
     714                       int(self._center_y + (self._radius - inset) * sin))
     715            cr.line_to(int(self._center_x + self._radius * cos),
     716                       int(self._center_y + self._radius * sin))
     717            cr.stroke()
    719718
    720719    def _draw_nice_background(self):
    721720        """Draw the nice clock background.
    722721
    723722        The background has been loaded from the clock.svg file to a
    724         pixbuf, and we just draw this pixbuf onto the pixmap where we
    725         will be drawing the hands.
    726         """
    727         # We draw the background from the SVG pixbuf
    728         self.window.draw_pixbuf(None, self._cache_pixbuf,
    729           0, 0, self._center_x - self._radius, self._center_y - self._radius)
     723        rsvg handle, and we just transform this handle and render it
     724        with cairo.
     725        """
     726        # We transform the background SVG
     727        cr = self.window.cairo_create()
     728        scale_x = self._radius * 2.0 / self._svg_handle.props.width
     729        scale_y = self._radius * 2.0 / self._svg_handle.props.height
     730        matrix = cairo.Matrix(xx=scale_x, yy=scale_y,
     731                              x0=self._center_x - self._radius,
     732                              y0=self._center_y - self._radius)
     733        cr.transform(matrix)
     734        self._svg_handle.render_cairo(cr)
    730735
    731736    def _draw_nice_clock(self):
    732737        """Draw the nice clock.
    class ClockFace(gtk.DrawingArea): 
    741746        minutes = self._time.minute
    742747        seconds = self._time.second
    743748
     749        cr = self.window.cairo_create()
     750        cr.set_line_cap(cairo.LINE_CAP_ROUND)
     751
    744752        # Hour hand:
    745753        # The hour hand is rotated 30 degrees (pi/6 r) per hour +
    746754        # 1/2 a degree (pi/360) per minute
    747         self._gc.set_foreground(self._COLOR_HOURS)
    748         self._gc.set_line_attributes(8 * self._line_width,
    749           gdk.LINE_SOLID, gdk.CAP_ROUND, gdk.JOIN_ROUND)
    750         self.window.draw_line(self._gc, self._center_x, self._center_y,
    751           int(self._center_x + self._radius * 0.5 *
    752           math.sin(math.pi / 6 * hours + math.pi / 360 * minutes)),
    753           int(self._center_y + self._radius * 0.5 *
    754           - math.cos(math.pi / 6 * hours + math.pi / 360 * minutes)))
     755        cr.set_source_rgba(*style.Color(self._COLOR_HOURS).get_rgba())
     756        cr.set_line_width(8 * self._line_width)
     757        cr.move_to(self._center_x, self._center_y)
     758        cr.line_to(int(self._center_x + self._radius * 0.5 *
     759            math.sin(math.pi / 6 * hours + math.pi / 360 * minutes)),
     760            int(self._center_y + self._radius * 0.5 *
     761            - math.cos(math.pi / 6 * hours + math.pi / 360 * minutes)))
     762        cr.stroke()
    755763
    756764        # Minute hand:
    757765        # The minute hand is rotated 6 degrees (pi/30 r) per minute
    758         self._gc.set_foreground(self._COLOR_MINUTES)
    759         self._gc.set_line_attributes(6 * self._line_width,
    760           gdk.LINE_SOLID, gdk.CAP_ROUND, gdk.JOIN_ROUND)
    761         self.window.draw_line(self._gc, self._center_x, self._center_y,
    762                 int(self._center_x + self._radius * 0.8 *
     766        cr.set_source_rgba(*style.Color(self._COLOR_MINUTES).get_rgba())
     767        cr.set_line_width(6 * self._line_width)
     768        cr.move_to(self._center_x, self._center_y)
     769        cr.line_to(int(self._center_x + self._radius * 0.8 *
    763770                math.sin(math.pi / 30 * minutes)),
    764                 int(self._center_y + self._radius * 0.8 *
     771                   int(self._center_y + self._radius * 0.8 *
    765772                - math.cos(math.pi / 30 * minutes)))
     773        cr.stroke()
    766774
    767775        # Seconds hand:
    768776        # Operates identically to the minute hand
    769         self._gc.set_foreground(self._COLOR_SECONDS)
    770         self._gc.set_line_attributes(2 * self._line_width,
    771           gdk.LINE_SOLID, gdk.CAP_ROUND, gdk.JOIN_ROUND)
    772         self.window.draw_line(self._gc, self._center_x, self._center_y,
    773                 int(self._center_x + self._radius * 0.7 *
     777        cr.set_source_rgba(*style.Color(self._COLOR_SECONDS).get_rgba())
     778        cr.set_line_width(2 * self._line_width)
     779        cr.move_to(self._center_x, self._center_y)
     780        cr.line_to(int(self._center_x + self._radius * 0.7 *
    774781                math.sin(math.pi / 30 * seconds)),
    775782                int(self._center_y + self._radius * 0.7 *
    776783                - math.cos(math.pi / 30 * seconds)))
     784        cr.stroke()
    777785
    778786    def _draw_numbers(self):
    779787        """Draw the numbers of the hours.
    780788        """
    781         self._gc.set_foreground(self._COLOR_HOURS)
     789        cr = self.window.cairo_create()
     790        cr = pangocairo.CairoContext(cr)
     791        cr.set_source_rgba(*style.Color(self._COLOR_HOURS).get_rgba())
     792        pango_layout = cr.create_layout()
    782793
    783794        for i in xrange(12):
    784795            # TRANS: The format of the font used to print hour
    class ClockFace(gtk.DrawingArea): 
    786797            hour_number = _("Hour Number",
    787798              '<markup><span lang="en" ' +
    788799              'font_desc="Sans Bold 20">%d</span></markup>') % (i + 1)
    789             self._draw_markup(self._center_x + 0.75 * \
    790             self._radius * math.cos((i - 2) * math.pi / 6.0), \
    791             self._center_y + 0.75 * self._radius * \
    792             math.sin((i - 2) * math.pi / 6.0), hour_number)
     800            cr.save()
     801            dx, dy = pango_layout.get_pixel_size()
     802            cr.translate(- dx / 2.0 + self._center_x + 0.75 *
     803                self._radius * math.cos((i - 2) * math.pi / 6.0),
     804                - dy / 2.0 + self._center_y + 0.75 * self._radius *
     805                math.sin((i - 2) * math.pi / 6.0))
     806            pango_layout.set_markup(hour_number)
     807            cr.update_layout(pango_layout)
     808            cr.show_layout(pango_layout)
     809            cr.restore()
    793810
    794811    def _redraw_canvas(self):
    795812        """Force a redraw of the clock on the screen.