orca r4190 - in trunk: . src/orca



Author: wwalker
Date: Thu Sep 11 15:28:56 2008
New Revision: 4190
URL: http://svn.gnome.org/viewvc/orca?rev=4190&view=rev

Log:
Fix for bug  363793 - Add the ability to change the color of the flat review rectangle


Added:
   trunk/src/orca/outline.py
Modified:
   trunk/ChangeLog
   trunk/src/orca/Makefile.am
   trunk/src/orca/default.py
   trunk/src/orca/settings.py

Modified: trunk/src/orca/Makefile.am
==============================================================================
--- trunk/src/orca/Makefile.am	(original)
+++ trunk/src/orca/Makefile.am	Thu Sep 11 15:28:56 2008
@@ -43,6 +43,7 @@
 	orca_prefs.py \
 	orca_quit.py \
 	orca_state.py \
+	outline.py \
 	outloud.py \
 	phonnames.py \
 	platform.py \

Modified: trunk/src/orca/default.py
==============================================================================
--- trunk/src/orca/default.py	(original)
+++ trunk/src/orca/default.py	Thu Sep 11 15:28:56 2008
@@ -28,16 +28,6 @@
 __copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc."
 __license__   = "LGPL"
 
-try:
-    # This can fail due to gtk not being available.  We want to
-    # be able to recover from that if possible.  The main driver
-    # for this is to allow "orca --text-setup" to work even if
-    # the desktop is not running.
-    #
-    import gtk
-except:
-    pass
-
 import locale
 import math
 import sys
@@ -52,6 +42,7 @@
 import input_event
 import keybindings
 import mag
+import outline
 import orca
 import orca_prefs
 import orca_state
@@ -115,11 +106,6 @@
         #
         self._unicodeCurrencySymbols = []
 
-        # Used by the drawOutline routine.
-        #
-        self._display = None
-        self._visibleRectangle = None
-
         # Used by the visualAppearanceChanged routine for updating whether
         # progress bars are spoken.
         #
@@ -3925,7 +3911,8 @@
                     and (orca_state.lastNonModifierKeyEvent.event_string \
                                                                   == "F1"):
                     self.updateBraille(orca_state.locusOfFocus)
-                    utterances = self.speechGenerator.getSpeech(orca_state.locusOfFocus,
+                    utterances = self.speechGenerator.getSpeech(\
+                        orca_state.locusOfFocus,
                         False)
                     utterances.extend(self.tutorialGenerator.getTutorial(
                                       orca_state.locusOfFocus, False))
@@ -4178,6 +4165,11 @@
             #
             braille.clear()
 
+            # Hide the flat review window and reset it so that it will be
+            # recreated.
+            #
+            self.drawOutline(-1, 0, 0, 0)
+
         # Because window activated and deactivated events may be
         # received in any order when switching from one application to
         # another, locusOfFocus and activeWindow, we really only change
@@ -5313,8 +5305,6 @@
             for zone in line.zones:
                 lineString += " '%s' [%s]" % \
                           (zone.string, zone.accessible.getRoleName())
-                self.drawOutline(zone.x, zone.y, zone.width, zone.height,
-                                 False)
             debug.println(debug.LEVEL_OFF, lineString)
         self.flatReviewContext = None
 
@@ -7167,77 +7157,30 @@
     #                                                                      #
     ########################################################################
 
-    def drawOutline(self, x, y, width, height, erasePrevious=True):
-        """Draws a rectangular outline around the accessible, erasing the
-        last drawn rectangle in the process."""
-
-        if not self._display:
-            try:
-                self._display = gtk.gdk.display_get_default()
-            except:
-                debug.printException(debug.LEVEL_FINEST)
-                self._display = gtk.gdk.display(":0")
-
-            if not self._display:
-                debug.println(debug.LEVEL_SEVERE,
-                              "Script.drawOutline could not open display.")
-                return
-
-        screen = self._display.get_default_screen()
-        root_window = screen.get_root_window()
-        graphics_context = root_window.new_gc()
-        graphics_context.set_subwindow(gtk.gdk.INCLUDE_INFERIORS)
-        graphics_context.set_function(gtk.gdk.INVERT)
-        graphics_context.set_line_attributes(3,                  # width
-                                             gtk.gdk.LINE_SOLID, # style
-                                             gtk.gdk.CAP_BUTT,   # end style
-                                             gtk.gdk.JOIN_MITER) # join style
-
-        # Erase the old rectangle.
-        #
-        if self._visibleRectangle and erasePrevious:
-            self.drawOutline(self._visibleRectangle[0],
-                             self._visibleRectangle[1],
-                             self._visibleRectangle[2],
-                             self._visibleRectangle[3],
-                             False)
-            self._visibleRectangle = None
-
-        # We'll use an invalid x value to indicate nothing should be
-        # drawn.
-        #
-        if x < 0:
-            self._visibleRectangle = None
-            return
-
-        # The +1 and -2 stuff here is an attempt to stay within the
-        # bounding box of the object.
-        #
-        root_window.draw_rectangle(graphics_context,
-                                   False, # Fill
-                                   x + 1,
-                                   y + 1,
-                                   max(1, width - 2),
-                                   max(1, height - 2))
+    def drawOutline(self, x, y, width, height):
+        """Draws an outline around the accessible, erasing the
+        last drawn outline in the process."""
 
-        self._visibleRectangle = [x, y, width, height]
+        if (x == -1) and (y == 0) and (width == 0) and (height == 0):
+            outline.erase()
+        else:
+            outline.draw(x, y, width, height)
 
-    def outlineAccessible(self, accessible, erasePrevious=True):
+    def outlineAccessible(self, accessible):
         """Draws a rectangular outline around the accessible, erasing the
         last drawn rectangle in the process."""
 
         try:
             component = accessible.queryComponent()
         except AttributeError:
-            self.drawOutline(-1, 0, 0, 0, erasePrevious)
+            self.drawOutline(-1, 0, 0, 0)
         except NotImplementedError:
             pass
         else:
             visibleRectangle = \
                 component.getExtents(pyatspi.DESKTOP_COORDS)
             self.drawOutline(visibleRectangle.x, visibleRectangle.y,
-                             visibleRectangle.width, visibleRectangle.height,
-                             erasePrevious)
+                             visibleRectangle.width, visibleRectangle.height)
 
     def isTextSelected(self, obj, startOffset, endOffset):
         """Returns an indication of whether the text is selected by

Added: trunk/src/orca/outline.py
==============================================================================
--- (empty file)
+++ trunk/src/orca/outline.py	Thu Sep 11 15:28:56 2008
@@ -0,0 +1,264 @@
+#
+# Copyright 2008 Sun Microsystems Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library 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
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
+# Boston MA  02110-1301 USA.
+
+"""Provides a simple utility to draw outlines on the screen.
+[[[TODO: WDW - The Wedge support is experimental and not perfect.]]]"""
+
+__id__        = "$Id: $"
+__version__   = "$Revision: $"
+__date__      = "$Date: $"
+__copyright__ = "Copyright (c) 2008 Sun Microsystems Inc."
+__license__   = "LGPL"
+
+import cairo
+
+try:
+    # This can fail due to gtk not being available.  We want to
+    # be able to recover from that if possible.  The main driver
+    # for this is to allow "orca --text-setup" to work even if
+    # the desktop is not running.
+    #
+    import gtk
+    display = gtk.gdk.display_get_default()
+    screen = display.get_default_screen()
+    screen_width = screen.get_width()
+    screen_height = screen.get_height()
+except:
+    pass
+
+import orca_state
+import settings
+
+def _adjustToScreen(x, y, width, height):
+    if x < 0:
+        width = width + x
+        x = 0
+    elif x >= screen_width:
+        width -= (x - screen_width)
+        x = screen_width
+    if y < 0:
+        height = height + y
+        y = 0
+    elif y >= screen_height:
+        height -= (y - screen_height)
+        y = screen_height
+    if (x + width) >= screen_width:
+        width = screen_width - x
+    if (y + height) >= screen_height:
+        height = max(1, screen_height - y)
+    width = max(1, width)
+    height = max(1, height)
+    return [x, y, width, height]
+
+# Our known windows that we've put on the screen.
+#
+_outlineWindows = []
+
+class Line(gtk.Window):
+    """Draws a simple filled box on the display using
+    settings.outlineColor for the color.
+
+    Arguments:
+    - x, y, width, height: the dimensions of the box
+    """
+    def __init__(self, x, y, width, height):
+        gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
+
+        self.modify_bg(gtk.STATE_NORMAL,
+                       gtk.gdk.Color(settings.outlineColor[0],
+                                     settings.outlineColor[1],
+                                     settings.outlineColor[2]))
+
+        self.set_property("accept-focus", False)
+        self.set_decorated(False)
+        self.set_keep_above(True)
+        self.set_skip_taskbar_hint(True)
+
+        self.move(x, y)
+        self.set_default_size(width, height)
+        self.resize(width, height)
+        self.realize()
+
+class Wedge(Line):
+    """Draws a filled isosceles triangle on the display
+    using settings.outlineColor for the color.
+
+    Arguments:
+    - x, y, width, height - the bounding box of the triangle
+    - top - if true, the triangle is flat on the bottom,
+            if false, the triangle is pointy on the bottom
+    """
+    def __init__(self, x, y, width, height, top):
+        self.top = top
+        Line.__init__(self, x, y, width, height)
+        self.connect('size-allocate', self._on_size_allocate)
+
+    def _on_size_allocate(self, win, allocation):
+        """Sets the shape of the window to a triangle."""
+        # Create a bitmap to draw into.  This will be the mask
+        # for the shape of the window.
+        #
+        width, height = allocation.width, allocation.height
+        bitmap = gtk.gdk.Pixmap(None, width, height, 1)
+        cr = bitmap.cairo_create()
+
+        # Clear the bitmap
+        #
+        cr.set_source_rgb(0, 0, 0)
+        cr.set_operator(cairo.OPERATOR_DEST_OUT)
+        cr.paint()
+
+        # Draw our shape into the bitmap using cairo
+        #
+        cr.set_operator(cairo.OPERATOR_OVER)
+        if self.top:
+            # In this case, height is the same as thickness
+            #
+            cr.move_to(width/2.0, 0.0)
+            cr.line_to(width/2.0 + height/2.0, height)
+            cr.line_to(width/2.0 - height/2.0, height)
+        else:
+            cr.move_to(width/2.0, height)
+            cr.line_to(width/2.0 + height/2.0, 0.0)
+            cr.line_to(width/2.0 - height/2.0, 0.0)
+        cr.close_path()
+        cr.fill()
+
+        # Set the window shape
+        #
+        win.shape_combine_mask(bitmap, 0, 0)
+
+class Box(Line):
+    """Draws the outline of a rectangle on the display
+    using settings.outlineColor for the color.
+
+    Arguments:
+    - x, y, width, height - the bounding box of the rectangle
+    - thickness - the thickness of the border
+    """
+    def __init__(self, x, y, width, height, thickness):
+        self.thickness = thickness
+        Line.__init__(self, x, y, width, height)
+        self.connect('size-allocate', self._on_size_allocate)
+
+    def _on_size_allocate(self, win, allocation):
+        """Sets the shape of the window to a hollow rectangle."""
+        # Create a bitmap to draw into.  This will be the mask
+        # for the shape of the window.
+        #
+        width, height = allocation.width, allocation.height
+        bitmap = gtk.gdk.Pixmap(None, width, height, 1)
+        cr = bitmap.cairo_create()
+
+        # Clear the bitmap
+        #
+        cr.set_source_rgb(0, 0, 0)
+        cr.set_operator(cairo.OPERATOR_DEST_OUT)
+        cr.paint()
+
+        # Draw our shape into the bitmap using cairo
+        #
+        cr.set_line_width(self.thickness)
+        cr.set_operator(cairo.OPERATOR_OVER)
+        offset = self.thickness / 2.0
+        cr.rectangle(0.0 + offset, 0.0 + offset,
+                     width - self.thickness, height - self.thickness)
+        cr.stroke()
+
+        # Set the window shape
+        #
+        win.shape_combine_mask(bitmap, 0, 0)
+
+def reset():
+    """Destroys all windows we have put on the screen."""
+    global _outlineWindows
+    for window in _outlineWindows:
+        window.destroy()
+    _outlineWindows = []
+   
+def erase():
+    """Erases all windows we have put on the screen."""
+    for window in _outlineWindows:
+        window.hide()
+
+def draw(x, y, width, height):
+    """Draws an outline for the given rectangle.  This might
+    be composed of multiple windows depending upon the
+    settings.outlineStyle."""
+
+    if settings.outlineStyle == settings.OUTLINE_NONE:
+        pass
+    elif settings.outlineStyle == settings.OUTLINE_LINE:
+        y = y + height + settings.outlineMargin
+        height = settings.outlineThickness
+        [x, y, width, height] = _adjustToScreen(x, y, width, height)
+        if not _outlineWindows:
+            line = \
+                Line(x, y, width, height)
+            _outlineWindows.append(line)
+        else:
+            _outlineWindows[0].resize(width, height)
+            _outlineWindows[0].move(x, y)
+    elif settings.outlineStyle == settings.OUTLINE_BOX:
+        extra = settings.outlineThickness + settings.outlineMargin
+        x = x - extra
+        y = y - extra
+        width = width + (2 * extra)
+        height = height + (2 * extra)
+        [x, y, width, height] = _adjustToScreen(x, y, width, height)
+        if not _outlineWindows:
+            box = \
+                Box(x, y, width, height,
+                    settings.outlineThickness)
+            _outlineWindows.append(box)
+        else:
+            _outlineWindows[0].resize(width, height)
+            _outlineWindows[0].move(x, y)
+    elif settings.outlineStyle == settings.OUTLINE_WEDGES:
+        wedgeSize = 4 * settings.outlineThickness
+        if width < wedgeSize:
+            diff = wedgeSize - width
+            width = wedgeSize
+            x -= (diff/2)
+        topy = y - (4 * settings.outlineThickness)
+        bottomy = y + height + settings.outlineMargin
+        [topx, topy, topwidth, topheight] = \
+           _adjustToScreen(x, topy, width, wedgeSize)
+        [bottomx, bottomy, bottomwidth, bottomheight] = \
+           _adjustToScreen(x, bottomy, width, wedgeSize)
+        if not _outlineWindows:
+            top = \
+                Wedge(topx, topy, topwidth, topheight, True)
+            _outlineWindows.append(top)
+            bottom = \
+                Wedge(bottomx, bottomy, bottomwidth, bottomheight, False)
+            _outlineWindows.append(bottom)
+        else:
+            _outlineWindows[0].resize(topwidth, topheight)
+            _outlineWindows[0].move(topx, topy)
+            _outlineWindows[1].resize(bottomwidth, bottomheight)
+            _outlineWindows[1].move(bottomx, bottomy)
+
+    for window in _outlineWindows:
+        window.present()
+        # Make sure the windows stay on top.
+        #
+        try:
+            window.window.set_user_time(orca_state.lastInputEventTimestamp)
+        except:
+            pass

Modified: trunk/src/orca/settings.py
==============================================================================
--- trunk/src/orca/settings.py	(original)
+++ trunk/src/orca/settings.py	Thu Sep 11 15:28:56 2008
@@ -592,6 +592,29 @@
 GENERAL_KEYBOARD_LAYOUT_LAPTOP  = 2
 keyboardLayout                  = GENERAL_KEYBOARD_LAYOUT_DESKTOP
 
+# The red, green, blue values to use to outline the current item in
+# flat review mode. They are values between 0 and 65535 (0xFFFF), with
+# 65535 (0xFFFF) indicating full intensitiy
+#
+outlineColor = [ 0xFFFF, 0x0000, 0x0000 ]
+
+# Thickness in pixels of the outline around the the current item in flat 
+# review mode.
+#
+outlineThickness = 4
+
+# Margin between the object being outlined and the actual outline
+#
+outlineMargin = 1
+
+# The kind of outlining to do for flat review mode.
+#
+OUTLINE_NONE = 0
+OUTLINE_BOX = 1
+OUTLINE_LINE = 2
+OUTLINE_WEDGES = 3
+outlineStyle = OUTLINE_BOX
+
 # If True, speak blank lines.
 #
 speakBlankLines         = True



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