[caribou] Separate window placement code from the keyboard code



commit 6b9c16c10aaedea38ec1d9fb8e74aae3311acd12
Author: Ben Konrath <ben bagu org>
Date:   Thu Dec 3 15:43:13 2009 -0500

    Separate window placement code from the keyboard code
    
    This leaves the door open for the CaribouWindow to host things besides
    keyboards - so dasher, namon or any other text entry mechanism.

 src/caribou.py  |   56 ++++++++---------
 src/keyboard.py |  169 +-------------------------------------------------
 src/window.py   |  183 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 213 insertions(+), 195 deletions(-)
---
diff --git a/src/caribou.py b/src/caribou.py
index b8ebf98..4db0e28 100644
--- a/src/caribou.py
+++ b/src/caribou.py
@@ -20,7 +20,8 @@
 
 import pyatspi
 import gtk
-import keyboard
+import gtk.gdk as gdk
+import window
 import gettext
 import getopt
 import sys
@@ -29,7 +30,7 @@ _ = gettext.gettext
 
 debug = False
 
-class Test:
+class Caribou:
     def __init__(self):
         self.__current_acc = None 
 
@@ -37,34 +38,35 @@ class Test:
         if self.__current_acc == event.source:
             self.__set_location(event.source)
             if debug == True:
-                print "object:text-caret-moved in", event.host_application.name, event.detail1, event.source.description
+                print "object:text-caret-moved in", event.host_application.name,
+                print event.detail1, event.source.description
     
     def __set_text_location(self, acc):
         text = acc.queryText() 
         [x, y, width, height] = text.getCharacterExtents(text.caretOffset, pyatspi.DESKTOP_COORDS)
-        cp.set_cursor_location(gtk.gdk.Rectangle(x, y, width, height))
+        caribouwindow.set_cursor_location(gdk.Rectangle(x, y, width, height))
         
         component = acc.queryComponent()
         entry_bb = component.getExtents(pyatspi.DESKTOP_COORDS)
-        cp.set_entry_location(entry_bb)
-        cp.show_all()
+        caribouwindow.set_entry_location(entry_bb)
+        caribouwindow.show_all()
        
     def __set_entry_location(self, acc):
         text = acc.queryText()
-        cursor_bb = gtk.gdk.Rectangle(
-            *text.getCharacterExtents(text.caretOffset, 
+        cursor_bb = gdk.Rectangle(
+            *text.getCharacterExtents(text.caretOffset,
                                       pyatspi.DESKTOP_COORDS))
 
         component = acc.queryComponent()
         entry_bb = component.getExtents(pyatspi.DESKTOP_COORDS)
 
-        if cursor_bb == gtk.gdk.Rectangle(0, 0, 0, 0):
+        if cursor_bb == gdk.Rectangle(0, 0, 0, 0):
             cursor_bb = entry_bb
 
-        cp.set_cursor_location(cursor_bb)
-        cp.set_entry_location(entry_bb)
+        caribouwindow.set_cursor_location(cursor_bb)
+        caribouwindow.set_entry_location(entry_bb)
 
-        cp.show_all()
+        caribouwindow.show_all()
        
     def on_state_changed_focused(self, event):
         acc = event.source
@@ -77,7 +79,7 @@ class Test:
                     if debug == True:
                         print "enter text widget in", event.host_application.name
                 elif event.detail1 == 0:
-                    cp.hide_all()
+                    caribouwindow.hide_all()
                     self.__current_acc = None 
                     self.__set_location = None
                     if debug == True:
@@ -91,7 +93,7 @@ class Test:
                     if debug == True:
                         print "enter entry widget in", event.host_application.name
                 elif event.detail1 == 0:
-                    cp.hide_all()
+                    caribouwindow.hide_all()
                     self.__current_acc = None 
                     self.__set_location = None
                     if debug == True:
@@ -103,18 +105,17 @@ class Test:
         # This could be a way to get the entry widget leave events.
         #else:
         #    if event.detail1 == 1:
-        #        cp.hide_all()
+        #        caribouwindow.hide_all()
         #        print "--> LEAVE EDITABLE TEXT <--"
 
     def on_key_down(self, event):
         # key binding for controling the row column scanning
-        # TODO: needs implementing
         if event.event_string == "Shift_R":
+            # TODO: implement keyboard scanning
             pass 
         elif event.event_string == "Control_R":
             if debug == True:
                 print "quitting ..."
-            # TODO: use for loop here? see below
             result = pyatspi.Registry.deregisterEventListener(self.on_text_caret_moved, "object:text-caret-moved")
             if debug == True:
                 print "deregisterEventListener - object:text-caret-moved ...",
@@ -129,7 +130,7 @@ class Test:
                     print "OK"
                 else:
                     print "FAIL"
-            result = pyatspi.Registry.deregisterKeystrokeListener(self.on_key_down, mask = None, kind = (pyatspi.KEY_PRESSED_EVENT,))
+            result = pyatspi.Registry.deregisterKeystrokeListener(self.on_key_down, mask=None, kind=(pyatspi.KEY_PRESSED_EVENT,))
             if debug == True:
                 print "deregisterKeystrokeListener"
             gtk.main_quit()
@@ -148,7 +149,8 @@ def usage():
 if __name__ == "__main__":
 
     try:
-        options, xargs = getopt.getopt(sys.argv[1:], "dhv", ["debug", "help", "version"])
+        options, xargs = getopt.getopt(sys.argv[1:], "dhv",
+            ["debug", "help", "version"])
     except getopt.GetoptError, e:
         print "Error: " + e.__str__() + "\n"
         usage()
@@ -166,18 +168,14 @@ if __name__ == "__main__":
             print "caribou @VERSION@"
             sys.exit(0)
 
-    test = Test()
-    # TODO: make a for loop
-    #EVENTS = ["object:state-changed:focused", "object:text-caret-moved"]
-    #for f in dir(test):
-    #    print f, isinstance(f, str)
-    pyatspi.Registry.registerEventListener(test.on_state_changed_focused, "object:state-changed:focused")
-    pyatspi.Registry.registerEventListener(test.on_text_caret_moved, "object:text-caret-moved")
-    pyatspi.Registry.registerKeystrokeListener(test.on_key_down, mask = None, kind = (pyatspi.KEY_PRESSED_EVENT,))
+    caribou = Caribou()
+    pyatspi.Registry.registerEventListener(caribou.on_state_changed_focused, "object:state-changed:focused")
+    pyatspi.Registry.registerEventListener(caribou.on_text_caret_moved, "object:text-caret-moved")
+    pyatspi.Registry.registerKeystrokeListener(caribou.on_key_down, mask=None, kind=(pyatspi.KEY_PRESSED_EVENT,))
 
     # TODO: move text entry detection to its own file
 
-    cp = keyboard.CaribouWindowEntry()
-    cp.hide_all()
+    caribouwindow = window.CaribouWindowEntry()
+    caribouwindow.hide_all()
  
     gtk.main()
diff --git a/src/keyboard.py b/src/keyboard.py
index dd55ec0..eb25335 100644
--- a/src/keyboard.py
+++ b/src/keyboard.py
@@ -20,13 +20,8 @@
 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 
 import gtk
-import gobject
-import gtk.gdk as gdk
-import pango
 import virtkey
-from keyboards import qwerty
-import rsvg
-import cairo
+import window
 
 class CaribouPredicitionArea(gtk.HBox):
     pass
@@ -133,167 +128,9 @@ class CaribouKeyboard(gtk.Frame):
         self.add(data)
         self.show_all()
 
-class CaribouWindow(gtk.Window):
-    __gtype_name__ = "CaribouWindow"
-
-    def __init__(self, default_placement=None):
-        super(CaribouWindow, self).__init__(gtk.WINDOW_POPUP)
-        self.set_name("CaribouWindow")
-
-        self._vbox = gtk.VBox()
-        self.add(self._vbox)
-
-        self._vbox.pack_start(CaribouKeyboard(qwerty))    
-
-        self.connect("size-allocate", lambda w, a: self._update_position())
-
-        self._cursor_location = gtk.gdk.Rectangle()
-        self._entry_location = gtk.gdk.Rectangle()
-        self._default_placement = default_placement or \
-            CaribouKeyboardPlacement()
-
-    def set_cursor_location(self, cursor_location):
-        self._cursor_location = cursor_location
-        self._update_position()
-
-    def set_entry_location(self, entry_location):
-        self._entry_location = entry_location
-        self._update_position()
-
-    def set_default_placement(self, default_placement):
-        self._default_placement = default_placement
-        self._update_position()
-
-    def _get_root_bbox(self):
-        root_window = gdk.get_default_root_window()
-        args = root_window.get_position() + root_window.get_size()
-        return gdk.Rectangle(*args)
-            
-    def _calculate_position(self, placement=None):
-        root_bbox = self._get_root_bbox()
-        placement = placement or self._default_placement
-
-        x = self._calculate_axis(placement.x, root_bbox)
-        y = self._calculate_axis(placement.y, root_bbox)
-
-        
-        return x, y
-
-    def _update_position(self):
-        x, y = self._calculate_position()
-        root_bbox = self._get_root_bbox()
-        proposed_position = \
-            gdk.Rectangle(x, y, self.allocation.width, self.allocation.height)
-
-        x += self._default_placement.x.adjust_to_bounds(root_bbox, proposed_position)
-        y += self._default_placement.y.adjust_to_bounds(root_bbox, proposed_position)
-        self.move(x, y)
-
-    def _calculate_axis(self, axis_placement, root_bbox):
-        bbox = root_bbox
-
-        if axis_placement.stickto == CaribouKeyboardPlacement.CURSOR:
-            bbox = self._cursor_location
-        elif axis_placement.stickto == CaribouKeyboardPlacement.ENTRY:
-            bbox = self._entry_location
-
-        offset = axis_placement.get_offset(bbox)
-
-        if axis_placement.align == CaribouKeyboardPlacement.END:
-            offset += axis_placement.get_length(bbox)
-            if axis_placement.gravitate == CaribouKeyboardPlacement.INSIDE:
-                offset -= axis_placement.get_length(self.allocation)
-        elif axis_placement.align == CaribouKeyboardPlacement.START:
-            if axis_placement.gravitate == CaribouKeyboardPlacement.OUTSIDE:
-                offset -= axis_placement.get_length(self.allocation)
-        elif axis_placement.align == CaribouKeyboardPlacement.CENTER:
-            offset += axis_placement.get_length(bbox)/2
-
-        return offset
-
-class CaribouWindowEntry(CaribouWindow):
-    __gtype_name__ = "CaribouWindowEntry"
-
-    def __init__(self):
-        placement = CaribouKeyboardPlacement(
-            xalign=CaribouKeyboardPlacement.START,
-            xstickto=CaribouKeyboardPlacement.ENTRY,
-            ystickto=CaribouKeyboardPlacement.ENTRY,
-            xgravitate=CaribouKeyboardPlacement.INSIDE,
-            ygravitate=CaribouKeyboardPlacement.OUTSIDE)
-
-        CaribouWindow.__init__(self, placement)
-
-    def _calculate_axis(self, axis_placement, root_bbox):
-        offset = CaribouWindow._calculate_axis(self, axis_placement, root_bbox)
-
-        if axis_placement.axis == 'y':
-            if offset + self.allocation.height > root_bbox.height + root_bbox.y:
-                new_axis_placement = axis_placement.copy(align=CaribouKeyboardPlacement.START)
-                offset = CaribouWindow._calculate_axis(self, new_axis_placement, root_bbox)
-
-        return offset
-
-class CaribouKeyboardPlacement(object):
-    START = 'start'
-    END = 'end'
-    CENTER = 'center'
-    
-    SCREEN = 'screen'
-    ENTRY = 'entry'
-    CURSOR = 'cursor'
-    
-    INSIDE = 'inside'
-    OUTSIDE = 'outside'
-    
-    class _AxisPlacement(object):
-        def __init__(self, axis, align, stickto, gravitate):
-            self.axis = axis
-            self.align = align
-            self.stickto = stickto
-            self.gravitate = gravitate
-
-        def copy(self, align=None, stickto=None, gravitate=None):
-            return self.__class__(self.axis,
-                                  align or self.align, 
-                                  stickto or self.stickto, 
-                                  gravitate or self.gravitate)
-
-        def get_offset(self, bbox):
-            return bbox.x if self.axis == 'x' else bbox.y
-        
-        def get_length(self, bbox):
-            return bbox.width if self.axis == 'x' else bbox.height
-
-        def adjust_to_bounds(self, root_bbox, child_bbox):
-            child_vector_start = self.get_offset(child_bbox)
-            child_vector_end = self.get_length(child_bbox) + child_vector_start
-            root_vector_start = self.get_offset(root_bbox)
-            root_vector_end = self.get_length(root_bbox) + root_vector_start
-
-            if root_vector_end < child_vector_end:
-                return root_vector_end - child_vector_end
-
-            if root_vector_start > child_vector_start:
-                return root_vector_start - child_vector_start
-
-            return 0
-            
-
-    def __init__(self, 
-                 xalign=None, xstickto=None, xgravitate=None,
-                 yalign=None, ystickto=None, ygravitate=None):
-        self.x = self._AxisPlacement('x',
-                                     xalign or self.END,
-                                     xstickto or self.CURSOR,
-                                     xgravitate or self.OUTSIDE)
-        self.y = self._AxisPlacement('y',
-                                     yalign or self.END,
-                                     ystickto or self.CURSOR,
-                                     ygravitate or self.OUTSIDE)
 
 if __name__ == "__main__":
-    ckbd = CaribouWindow()
-    ckbd.show_all()
+    window = window.CaribouWindow()
+    window.show_all()
     gtk.main()
 
diff --git a/src/window.py b/src/window.py
new file mode 100644
index 0000000..cb0dbef
--- /dev/null
+++ b/src/window.py
@@ -0,0 +1,183 @@
+# -*- coding: utf-8 -*-
+#
+# Carbou - text entry and UI navigation application
+#
+# Copyright (C) 2009 Eitan Isaacson <eitan monotonous org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by the
+# Free Software Foundation; either version 2.1 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+# for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+import gtk
+import gtk.gdk as gdk
+import keyboard
+from keyboards import qwerty
+
+class CaribouWindow(gtk.Window):
+    __gtype_name__ = "CaribouWindow"
+
+    def __init__(self, default_placement=None):
+        super(CaribouWindow, self).__init__(gtk.WINDOW_POPUP)
+        self.set_name("CaribouWindow")
+
+        self._vbox = gtk.VBox()
+        self.add(self._vbox)
+
+        self._vbox.pack_start(keyboard.CaribouKeyboard(qwerty))
+
+        self.connect("size-allocate", lambda w, a: self._update_position())
+
+        self._cursor_location = gdk.Rectangle()
+        self._entry_location = gdk.Rectangle()
+        self._default_placement = default_placement or \
+            CaribouWindowPlacement()
+
+    def set_cursor_location(self, cursor_location):
+        self._cursor_location = cursor_location
+        self._update_position()
+
+    def set_entry_location(self, entry_location):
+        self._entry_location = entry_location
+        self._update_position()
+
+    def set_default_placement(self, default_placement):
+        self._default_placement = default_placement
+        self._update_position()
+
+    def _get_root_bbox(self):
+        root_window = gdk.get_default_root_window()
+        args = root_window.get_position() + root_window.get_size()
+        return gdk.Rectangle(*args)
+
+    def _calculate_position(self, placement=None):
+        root_bbox = self._get_root_bbox()
+        placement = placement or self._default_placement
+
+        x = self._calculate_axis(placement.x, root_bbox)
+        y = self._calculate_axis(placement.y, root_bbox)
+
+        return x, y
+
+    def _update_position(self):
+        x, y = self._calculate_position()
+        root_bbox = self._get_root_bbox()
+        proposed_position = \
+            gdk.Rectangle(x, y, self.allocation.width, self.allocation.height)
+
+        x += self._default_placement.x.adjust_to_bounds(root_bbox, proposed_position)
+        y += self._default_placement.y.adjust_to_bounds(root_bbox, proposed_position)
+        self.move(x, y)
+
+    def _calculate_axis(self, axis_placement, root_bbox):
+        bbox = root_bbox
+
+        if axis_placement.stickto == CaribouWindowPlacement.CURSOR:
+            bbox = self._cursor_location
+        elif axis_placement.stickto == CaribouWindowPlacement.ENTRY:
+            bbox = self._entry_location
+
+        offset = axis_placement.get_offset(bbox)
+
+        if axis_placement.align == CaribouWindowPlacement.END:
+            offset += axis_placement.get_length(bbox)
+            if axis_placement.gravitate == CaribouWindowPlacement.INSIDE:
+                offset -= axis_placement.get_length(self.allocation)
+        elif axis_placement.align == CaribouWindowPlacement.START:
+            if axis_placement.gravitate == CaribouWindowPlacement.OUTSIDE:
+                offset -= axis_placement.get_length(self.allocation)
+        elif axis_placement.align == CaribouWindowPlacement.CENTER:
+            offset += axis_placement.get_length(bbox)/2
+
+        return offset
+
+class CaribouWindowEntry(CaribouWindow):
+    __gtype_name__ = "CaribouWindowEntry"
+
+    def __init__(self):
+        placement = CaribouWindowPlacement(
+            xalign=CaribouWindowPlacement.START,
+            xstickto=CaribouWindowPlacement.ENTRY,
+            ystickto=CaribouWindowPlacement.ENTRY,
+            xgravitate=CaribouWindowPlacement.INSIDE,
+            ygravitate=CaribouWindowPlacement.OUTSIDE)
+
+        CaribouWindow.__init__(self, placement)
+
+    def _calculate_axis(self, axis_placement, root_bbox):
+        offset = CaribouWindow._calculate_axis(self, axis_placement, root_bbox)
+
+        if axis_placement.axis == 'y':
+            if offset + self.allocation.height > root_bbox.height + root_bbox.y:
+                new_axis_placement = axis_placement.copy(align=CaribouWindowPlacement.START)
+                offset = CaribouWindow._calculate_axis(self, new_axis_placement, root_bbox)
+
+        return offset
+
+class CaribouWindowPlacement(object):
+    START = 'start'
+    END = 'end'
+    CENTER = 'center'
+
+    SCREEN = 'screen'
+    ENTRY = 'entry'
+    CURSOR = 'cursor'
+
+    INSIDE = 'inside'
+    OUTSIDE = 'outside'
+
+    class _AxisPlacement(object):
+        def __init__(self, axis, align, stickto, gravitate):
+            self.axis = axis
+            self.align = align
+            self.stickto = stickto
+            self.gravitate = gravitate
+
+        def copy(self, align=None, stickto=None, gravitate=None):
+            return self.__class__(self.axis,
+                                  align or self.align,
+                                  stickto or self.stickto,
+                                  gravitate or self.gravitate)
+
+        def get_offset(self, bbox):
+            return bbox.x if self.axis == 'x' else bbox.y
+
+        def get_length(self, bbox):
+            return bbox.width if self.axis == 'x' else bbox.height
+
+        def adjust_to_bounds(self, root_bbox, child_bbox):
+            child_vector_start = self.get_offset(child_bbox)
+            child_vector_end = self.get_length(child_bbox) + child_vector_start
+            root_vector_start = self.get_offset(root_bbox)
+            root_vector_end = self.get_length(root_bbox) + root_vector_start
+
+            if root_vector_end < child_vector_end:
+                return root_vector_end - child_vector_end
+
+            if root_vector_start > child_vector_start:
+                return root_vector_start - child_vector_start
+
+            return 0
+
+
+    def __init__(self,
+                 xalign=None, xstickto=None, xgravitate=None,
+                 yalign=None, ystickto=None, ygravitate=None):
+        self.x = self._AxisPlacement('x',
+                                     xalign or self.END,
+                                     xstickto or self.CURSOR,
+                                     xgravitate or self.OUTSIDE)
+        self.y = self._AxisPlacement('y',
+                                     yalign or self.END,
+                                     ystickto or self.CURSOR,
+                                     ygravitate or self.OUTSIDE)
+



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]