[Commits] typing-turtle branch master updated.

olpc olpc at xo-05-26-CC.localdomain
Mon Dec 8 22:13:50 EST 2008


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "/home/olpc-code/git/activities/typing-turtle".

The branch, master has been updated
       via  7ec25f9180d948dad7839c4f7187d83960e987fd (commit)
      from  103e65924809d04a1446774346ecfcc03379d556 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

 keyboard.py     |  167 +++++++++++++++++++++++++++++++-----------------------
 lessonscreen.py |    5 +-
 2 files changed, 99 insertions(+), 73 deletions(-)

- Log -----------------------------------------------------------------
commit 7ec25f9180d948dad7839c4f7187d83960e987fd
Author: olpc <olpc at xo-05-26-CC.localdomain>
Date:   Tue Dec 9 03:13:02 2008 +0000

    Optimize keyboard rendering using Cairo.  Only draw the keys as they change, instead of drawing the entire keyboard.

diff --git a/keyboard.py b/keyboard.py
index 1243f77..2ace05d 100644
--- a/keyboard.py
+++ b/keyboard.py
@@ -14,6 +14,7 @@
 # You should have received a copy of the GNU General Public License
 # along with Typing Turtle.  If not, see <http://www.gnu.org/licenses/>.
 #!/usr/bin/env python
+# vi:sw=4 et 
 
 import pygtk
 pygtk.require('2.0')
@@ -232,9 +233,6 @@ class Key:
         self.pressed = False
         self.hilite = False
 
-    def set_hilite(self, enabled):
-        self.hilite = enabled
-
 class Keyboard(gtk.EventBox):
     """A GTK widget which implements an interactive visual keyboard, with support
        for custom data driven layouts."""
@@ -248,6 +246,9 @@ class Keyboard(gtk.EventBox):
         self.area = gtk.DrawingArea()
         self.area.connect("expose-event", self._expose_cb)
         self.add(self.area)
+
+        # Initialize the default cairo context to None. 
+        cr = None
         
         # Access the current GTK keymap.
         self.keymap = gtk.gdk.keymap_get_default()
@@ -265,15 +266,15 @@ class Keyboard(gtk.EventBox):
         self.shift_down = False
         
         # Connect keyboard grabbing and releasing callbacks.        
-        self.connect('realize', self._realize_cb)
-        self.connect('unrealize', self._unrealize_cb)
+        self.area.connect('realize', self._realize_cb)
+        self.area.connect('unrealize', self._unrealize_cb)
 
     def _realize_cb(self, widget):
         # Setup keyboard event snooping in the root window.
         self.root_window.add_events(gtk.gdk.KEY_PRESS_MASK | gtk.gdk.KEY_RELEASE_MASK)
         self.key_press_cb_id = self.root_window.connect('key-press-event', self._key_press_cb)
         self.key_release_cb_id = self.root_window.connect('key-release-event', self._key_release_cb)
-        
+
     def _unrealize_cb(self, widget):
         self.root_window.disconnect(self.key_press_cb_id)
         self.root_window.disconnect(self.key_release_cb_id)
@@ -390,69 +391,79 @@ class Keyboard(gtk.EventBox):
             k.screen_width = int(k.width * ratio_x / 100)
             k.screen_height = int(k.height * ratio_y / 100)
 
+    def _expose_key(self, k, cr=None):
+        # Create cairo context if need be.
+        if not cr:
+            if not self.area.window:
+                return
+            cr = self.area.window.cairo_create()
+
+        cr.save()
+
+        x1 = k.screen_x
+        y1 = k.screen_y
+        x2 = k.screen_x + k.screen_width
+        y2 = k.screen_y + k.screen_height
+
+        # Outline rounded box.
+        corner = 5
+        cr.move_to(x1 + corner, y1)
+        cr.line_to(x2 - corner, y1)
+        cr.line_to(x2, y1 + corner)
+        cr.line_to(x2, y2 - corner)
+        cr.line_to(x2 - corner, y2)
+        cr.line_to(x1 + corner, y2)
+        cr.line_to(x1, y2 - corner)
+        cr.line_to(x1, y1 + corner)
+        cr.close_path()
+
+        if k.pressed:
+            cr.set_source_rgb(1.0, 0.6, 0.6)
+        elif k.hilite:
+            cr.set_source_rgb(0.6, 1.0, 0.6)
+        else:
+            cr.set_source_rgb(1.0, 1.0, 1.0)
+        cr.fill_preserve()
+
+        cr.set_source_rgb(0.1, 0.1, 0.1)
+        cr.stroke_preserve()
+
+        cr.clip()
+
+        # Inner text.
+        text = ''
+        if k.props['key-label']:
+            text = k.props['key-label']
+        else:
+            info = self.keymap.translate_keyboard_state(
+                k.props['key-scan'], self.active_state, self.active_group)
+            if info:
+                key = gtk.gdk.keyval_to_unicode(info[0])
+                try:
+                    text = unichr(key).encode('utf-8')
+                except:
+                    pass
+
+        cr.set_font_size(16)
+        x_bearing, y_bearing, width, height = cr.text_extents(text)[:4]
+
+        cr.move_to(x1+8 - x_bearing, y2-8 - height - y_bearing)
+        cr.show_text(text)
+
+        cr.restore()
+
     def _expose_cb(self, area, event):
         # Update layout given screen size.
         self._update_screen_layout()
 
         # Draw the keys.
         cr = self.area.window.cairo_create()
+
         cr.rectangle(event.area.x, event.area.y, event.area.width, event.area.height)
         cr.clip()
 
         for k in self.keys:
-            cr.save()
-
-            x1 = k.screen_x
-            y1 = k.screen_y
-            x2 = k.screen_x + k.screen_width
-            y2 = k.screen_y + k.screen_height
-
-            # Outline rounded box.
-            corner = 5
-            cr.move_to(x1 + corner, y1)
-            cr.line_to(x2 - corner, y1)
-            cr.line_to(x2, y1 + corner)
-            cr.line_to(x2, y2 - corner)
-            cr.line_to(x2 - corner, y2)
-            cr.line_to(x1 + corner, y2)
-            cr.line_to(x1, y2 - corner)
-            cr.line_to(x1, y1 + corner)
-            cr.close_path()
-
-            if k.pressed:
-                cr.set_source_rgb(1.0, 0.6, 0.6)
-            elif k.hilite:
-                cr.set_source_rgb(0.6, 1.0, 0.6)
-            else:
-                cr.set_source_rgb(1.0, 1.0, 1.0)
-            cr.fill_preserve()
-
-            cr.set_source_rgb(0.1, 0.1, 0.1)
-            cr.stroke_preserve()
-
-            cr.clip()
-
-            # Inner text.
-            text = ''
-            if k.props['key-label']:
-                text = k.props['key-label']
-            else:
-                info = self.keymap.translate_keyboard_state(
-                    k.props['key-scan'], self.active_state, self.active_group)
-                if info:
-                    key = gtk.gdk.keyval_to_unicode(info[0])
-                    try:
-                        text = unichr(key).encode('utf-8')
-                    except:
-                        pass
-
-            cr.set_font_size(16)
-            x_bearing, y_bearing, width, height = cr.text_extents(text)[:4]
-    
-            cr.move_to(x1+8 - x_bearing, y2-8 - height - y_bearing)
-            cr.show_text(text)
-
-            cr.restore()
+            self._expose_key(k, cr)
 
         return True
 
@@ -460,35 +471,48 @@ class Keyboard(gtk.EventBox):
         key = self.key_scan_map.get(event.hardware_keycode)
         if key:
             key.pressed = True
-        
-        self.active_group = event.group
-        self.active_state = event.state
-        
+            self._expose_key(key)
+
         # Hack to get the current modifier state - which will not be represented by the event.
-        self.active_state = gtk.gdk.device_get_core_pointer().get_state(self.window)[1]
+        state = gtk.gdk.device_get_core_pointer().get_state(self.window)[1]
+
+        if self.active_group != event.group or self.active_state != state:
+            self.active_group = event.group
+            self.active_state = event.state
+            self.queue_draw()
+        
         #print "press %d state=%x group=%d" % (event.hardware_keycode, self.active_state, event.group)
         
-        self.queue_draw()
         return False
 
     def _key_release_cb(self, widget, event):
         key = self.key_scan_map.get(event.hardware_keycode)
         if key:
             key.pressed = False 
-        
-        self.active_group = event.group
-        self.active_state = event.state
+            self._expose_key(key)
         
         # Hack to get the current modifier state - which will not be represented by the event.
-        self.active_state = gtk.gdk.device_get_core_pointer().get_state(self.window)[1]
+        state = gtk.gdk.device_get_core_pointer().get_state(self.window)[1]
+
+        if self.active_group != event.group or self.active_state != state:
+            self.active_group = event.group
+            self.active_state = event.state
+            self.queue_draw()
+
         #print "release %d state=%x group=%d" % (event.hardware_keycode, self.active_state, event.group)
         
-        self.queue_draw()
         return False
 
     def clear_hilite(self):
         for k in self.keys:
-            k.hilite = False
+            if k.hilite:
+                k.hilite = False
+                self._expose_key(k)
+
+    def hilite_key(self, key):
+        if not key.hilite:
+            key.hilite = True
+            self._expose_key(key)
 
     def find_key_by_letter(self, letter):
         # Convert unicode to GDK keyval.
@@ -516,3 +540,4 @@ if __name__ == "__main__":
     window.show()
 
     gtk.main()
+
diff --git a/lessonscreen.py b/lessonscreen.py
index 25328dc..13f49c9 100644
--- a/lessonscreen.py
+++ b/lessonscreen.py
@@ -13,6 +13,7 @@
 # 
 # You should have received a copy of the GNU General Public License
 # along with Typing Turtle.  If not, see <http://www.gnu.org/licenses/>.
+# vi:sw=4 et 
 
 # Import standard Python modules.
 import logging, os, math, time, copy, json, locale, datetime, random, re
@@ -279,7 +280,7 @@ class LessonScreen(gtk.VBox):
         if key_name == 'Return':
             key = PARAGRAPH_CODE
         
-        print "key_press_cb: key=%s key_name=%s event.keyval=%d" % (key, key_name, event.keyval)
+        #print "key_press_cb: key=%s key_name=%s event.keyval=%d" % (key, key_name, event.keyval)
         
         # Timer starts with first keypress.
         if not self.start_time:
@@ -352,7 +353,7 @@ class LessonScreen(gtk.VBox):
         if len(self.line) > 0:
             key = self.keyboard.find_key_by_letter(self.line[self.char_idx])
             if key:
-                key.set_hilite(True)
+                self.keyboard.hilite_key(key)
 
         # Move the cursor to the insert location.
         iter = self.lessonbuffer.get_iter_at_mark(self.line_mark)
-----------------------------------------------------------------------


--
/home/olpc-code/git/activities/typing-turtle


More information about the Commits mailing list