[orca/introspection] Braille Monitor improvements:



commit 26761a0e257b97286c0553010ba4a9048960fa58
Author: Joanmarie Diggs <joanmarie diggs gmail com>
Date:   Tue Aug 23 11:07:45 2011 -0400

    Braille Monitor improvements:
    
    * Complete introspection
    * Use the new GtkGrid to replace the deprecated HBox
    * General code cleanup
    * Display dots 7 and dots 8 as dots 7 and dots 8 rather than use
      some semi-arbitrarily=chosen pango underline types
    * Make the cells clickable so that sighted developers without
      refreshable braille displays can simulate/test/work on cursor
      routing. (I'll do panning and other traditional display features
      post-introspection completion.)

 src/orca/brlmon.py |  250 +++++++++++++++++++++++++++++++++-------------------
 1 files changed, 160 insertions(+), 90 deletions(-)
---
diff --git a/src/orca/brlmon.py b/src/orca/brlmon.py
index ca621ee..3a15fae 100644
--- a/src/orca/brlmon.py
+++ b/src/orca/brlmon.py
@@ -1,6 +1,8 @@
+# -*- coding: utf-8 -*-
 # Orca
 #
 # Copyright 2006-2008 Sun Microsystems Inc.
+# Copyright 2011 The Orca Team.
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
@@ -17,84 +19,189 @@
 # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
 # Boston MA  02110-1301 USA.
 
-"""Provides a graphical braille display at the top of the screen.
-This is mainly for debugging and for demonstrations."""
+"""Provides a graphical braille display, mainly for development tasks."""
 
 __id__        = "$Id$"
 __version__   = "$Revision$"
 __date__      = "$Date$"
-__copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc."
+__copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc." \
+                "Copyright (c) 2011 The Orca Team."
 __license__   = "LGPL"
 
+import brlapi
 from gi.repository import Gtk
 
+import orca_state
+from input_event import BrailleEvent
+
 # Attribute/Selection mask strings:
 #
 DOT_7 =   '\x40' # 01000000
 DOT_8 =   '\x80' # 10000000
 DOTS_78 = '\xc0' # 11000000
-    
-# Markup strings:
-#
-NORMAL = " size='xx-large'"
 
-CURSOR_CELL_EMPTY =   " background='black'" \
-                    + " weight='ultrabold'" \
-                    + " style='italic'"
+class BrlDot(Gtk.Alignment):
+    """A single braille dot."""
 
-CURSOR_CELL =   " background='white'" \
-              + " weight='ultrabold'" \
-              + " style='italic'" \
+    MARKUP_NORMAL  = '<tt><small>%s</small></tt>'
+    SYMBOL_LOWERED = u'\u25CB' # 'â'
+    SYMBOL_RAISED  = u'\u25CF' # 'â'
 
-ATTRIBUTE_7 = " underline='low'"
+    def __init__(self, dotNumber, isRaised=False):
+        """Create a new BrlDot.
 
-ATTRIBUTE_8 = " underline='error'"
+        Arguments:
+        - dotNumber: an integer reflecting the location of the dot within
+          an 8-dot braille cell, using traditional braille dot values.
+        """
 
-ATTRIBUTE_78 = " underline='double'"
+        Gtk.Alignment.__init__(self)
+        if dotNumber in [1, 2, 3, 7]:
+            self.set(1.0, 0.5, 0.0, 0.0)
+            self.set_padding(0, 0, 3, 0)
+        else:
+            self.set(0.0, 0.5, 0.0, 0.0)
+            self.set_padding(0, 0, 0, 3)
 
-class BrlMon(Gtk.Window):
+        self.label = Gtk.Label()
+        self.add(self.label)
+        if isRaised:
+            self.raiseDot()
+        else:
+            self.lowerDot()
+
+    def raiseDot(self):
+        self.set(0.5, 0.5, 0, 0)
+        self.label.set_markup(self.MARKUP_NORMAL % self.SYMBOL_RAISED)
+
+    def lowerDot(self):
+        self.set(0.5, 0.5, 0, 0)
+        self.label.set_markup(self.MARKUP_NORMAL % self.SYMBOL_LOWERED)
+
+class BrlCell(Gtk.Grid):
+    """A single graphical braille cell with cursor routing capability."""
+
+    MARKUP_NORMAL      = '<tt><big>%s</big></tt>'
+    MARKUP_CURSOR_CELL = '<b><u>%s</u></b>'
+
+    def __init__(self, position):
+        """Create a new BrlCell.
+
+        Arguments:
+        - position: The location of the cell with respect to the monitor.
+        """
+
+        Gtk.Grid.__init__(self)
+        self._position = position
+
+        # For now, we display the char in print, like we always have. Use
+        # (merge) dots 1-6 for this purpose. Also make the button a means
+        # by which developers can work on cursor routing.
+        self._displayedChar = Gtk.Button()
+        self._displayedChar.set_size_request(30, 40)
+        self._displayedChar.add(Gtk.Label())
+        self.attach(self._displayedChar, 0, 0, 2, 3)
+        self._displayedChar.connect("clicked", self._onCellClicked)
+
+        # Create a more braille-like representation for dots 7-8 so that we
+        # do not have to remember/guess what pango underline type goes with
+        # what dot(s).
+        self.dot7 = BrlDot(7)
+        self.dot8 = BrlDot(8)
+        self.attach(self.dot7, 0, 3, 1, 1)
+        self.attach(self.dot8, 1, 3, 1, 1)
+
+    def _onCellClicked(self, widget):
+        """Callback for the 'clicked' signal on the push button. Synthesizes
+        a fake brlapi command to route the cursor to the current cell, similar
+        to what occurs when a user presses the cursor routing key on his/her
+        hardware braille display."""
+
+        if not orca_state.activeScript:
+            return
+
+        fakeKeyPress = {}
+        fakeKeyPress['command'] = brlapi.KEY_CMD_ROUTE
+        fakeKeyPress['argument'] = self._position
+        event = BrailleEvent(fakeKeyPress)
+        orca_state.activeScript.processRoutingKey(event)
+
+    def clear(self):
+        """Clears the braille cell."""
+
+        try:
+            label, = self._displayedChar.get_children()
+        except ValueError:
+            return
+
+        label.set_markup("")
+        self.dot7.lowerDot()
+        self.dot8.lowerDot()
 
-    """Displays a GUI braille monitor that mirrors what is being
-    shown on the braille display.  This currently needs a lot of
-    work, but it is a start.  TODO's include doing a better job of
-    docking it at the top of the display (e.g., make all other
-    windows move out from underneath it), doing better highlighting of
-    the cursor cell, allowing the font to be set, and perhaps allowing
-    clicks to simulate cursor routing keys."""
+    def display(self, char, mask=None, isCursorCell=False):
+        """Displays the specified character in the cell.
 
-    def __init__(self, numCells=32, cellWidth=25, cellHeight=50):
+        Arguments:
+        - char: The character to display in the cell.
+        - isCursorCell: If True, the cursor/caret is at this cell and this
+          should be indicated visually.
+        """
+
+        if char == '&':
+            char = '&amp;'
+        elif char == '<':
+            char = '&lt;'
+        elif char == '\t':
+            char = '$t'
+
+        markup = self.MARKUP_NORMAL
+        if isCursorCell:
+            markup = markup % self.MARKUP_CURSOR_CELL
+        label, = self._displayedChar.get_children()
+        label.set_markup(markup % char)
+
+        if mask in [DOT_7, DOTS_78]:
+            self.dot7.raiseDot()
+        if mask in [DOT_8, DOTS_78]:
+            self.dot8.raiseDot()
+
+class BrlMon(Gtk.Window):
+    """Displays a GUI braille monitor that mirrors what would be displayed
+    by Orca on a connected, configured, and enabled braille display. Cursor
+    routing functionality is emulated by each cell being a push button.
+    Panning and other functionality found on hardware braille displays will
+    be added."""
+
+    def __init__(self, numCells=32):
         """Create a new BrlMon.
 
         Arguments:
         - numCells: how many braille cells to make
-        - cellWidth: width of each cell in pixels
-        - cellHeight: height of each cell in pixels
         """
 
         Gtk.Window.__init__(self)
         self.set_title("Braille Monitor")
-        self.set_size_request(cellWidth * numCells, cellHeight)
-        hbox = Gtk.HBox(homogeneous=True)
-        self.add(hbox)
-        self.cellFrames = []
-        self.cellLabels = []
-        i = 0
-        while (i < numCells):
-            frame = Gtk.Frame()
-            frame.set_shadow_type(Gtk.ShadowType.OUT)
-            label = Gtk.Label(label=" ")
-            label.set_use_markup(True)
-            frame.add(label)
-            hbox.add(frame)
-            self.cellFrames.append(frame)
-            self.cellLabels.append(label)
-            i += 1
 
-        self.set_property("accept-focus", False)
+        grid = Gtk.Grid()
+        self.add(grid)
+
+        self.cells = []
+        for i in range(numCells):
+            cell = BrlCell(i)
+            grid.attach(cell, i, 0, 1, 1)
+            self.cells.append(cell)
+
         self.set_resizable(False)
+        self.set_property("accept-focus", False)
         self.set_skip_taskbar_hint(True)
         self.set_skip_pager_hint(True)
 
+    def clear(self):
+        """Clears the braille monitor display."""
+
+        for cell in self.cells:
+            cell.clear()
+
     def writeText(self, cursorCell, string, mask=None):
         """Display the given text and highlight the given
         cursor cell.  A cursorCell of 0 means no cell has
@@ -105,55 +212,18 @@ class BrlMon(Gtk.Window):
         - string: len must be <= num cells.
         """
 
-        # Fill out the cells from the string.
-        #
+        self.clear()
+
         try:
             string = string.decode("UTF-8")
         except:
             string = ""
 
-        for i in range(0, len(string)):
-
-            # Handle special chars so they are not interpreted by Pango.
-            #
-            if string[i] == "<":
-                char = "&lt;"
-            elif string[i] == "&":
-                char = "&amp;"
-            elif string[i] == "\t":
-                char = "$t"
-            else:
-                char = string[i]
-
-            markup = NORMAL
-            if i == (cursorCell - 1):
-                if string[i] == " ":
-                    markup += CURSOR_CELL_EMPTY
-                else:
-                    markup += CURSOR_CELL
-                self.cellFrames[i].set_shadow_type(
-                    Gtk.ShadowType.IN)
-            else:
-                self.cellFrames[i].set_shadow_type(
-                    Gtk.ShadowType.OUT)
-
+        length = min(len(string), len(self.cells))
+        for i in range(length):
+            isCursorCell = i == cursorCell - 1
             try:
-                if mask:
-                    if (mask[i] == DOTS_78):
-                        markup += ATTRIBUTE_78
-                    elif (mask[i] == DOT_7):
-                        markup += ATTRIBUTE_7
-                    elif (mask[i] == DOT_8):
-                        markup += ATTRIBUTE_8
-            except:
-                pass
-
-            self.cellLabels[i].set_markup(
-                "<span" + markup + ">%s</span>" % char)
-
-        # Pad the rest
-        #
-        for i in range(len(string), len(self.cellFrames)):
-            self.cellLabels[i].set_text(" ")
-            self.cellFrames[i].set_shadow_type(
-                Gtk.ShadowType.OUT)
+                cellMask = mask[i]
+            except IndexError:
+                cellMask = None
+            self.cells[i].display(string[i], cellMask, isCursorCell)



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