[Sugar-devel] [PATCH v2] Remove hippo from the frame

Daniel Drake dsd at laptop.org
Tue Sep 27 13:41:32 EDT 2011


Based on earlier work by Raul Gutierrez and Walter Bender.

The tricky part here is not placing frame elements in the corners of the
screen, where grid-cell-sized squares are reserved, and also drawing
the little grey border around the inner edges of the frame.

Both of these issues are tackled with a custom container (FrameContainer)
class which provides the frame's child elements with a precisely defined
box to work in (which leaves the screen corners blank), and (like hippo)
uses cairo to draw the border on the appropriate edge.
---
 src/jarabe/frame/clipboardpanelwindow.py |    5 +-
 src/jarabe/frame/frame.py                |   16 +--
 src/jarabe/frame/framewindow.py          |  168 +++++++++++++++++++----------
 src/jarabe/frame/zoomtoolbar.py          |    4 +
 4 files changed, 120 insertions(+), 73 deletions(-)

v2: Sascha pointed out that FrameContainer does not need to be windowed

diff --git a/src/jarabe/frame/clipboardpanelwindow.py b/src/jarabe/frame/clipboardpanelwindow.py
index f5d537c..aefec7b 100644
--- a/src/jarabe/frame/clipboardpanelwindow.py
+++ b/src/jarabe/frame/clipboardpanelwindow.py
@@ -18,7 +18,6 @@ import logging
 from urlparse import urlparse
 
 import gtk
-import hippo
 
 from jarabe.frame.framewindow import FrameWindow
 from jarabe.frame.clipboardtray import ClipboardTray
@@ -39,8 +38,8 @@ class ClipboardPanelWindow(FrameWindow):
         self._clipboard.connect('owner-change', self._owner_change_cb)
 
         self._clipboard_tray = ClipboardTray()
-        canvas_widget = hippo.CanvasWidget(widget=self._clipboard_tray)
-        self.append(canvas_widget, hippo.PACK_EXPAND)
+        self._clipboard_tray.show()
+        self.append(self._clipboard_tray)
 
         # Receiving dnd drops
         self.drag_dest_set(0, [], 0)
diff --git a/src/jarabe/frame/frame.py b/src/jarabe/frame/frame.py
index 079eeeb..7407e18 100644
--- a/src/jarabe/frame/frame.py
+++ b/src/jarabe/frame/frame.py
@@ -18,7 +18,6 @@ import logging
 
 import gtk
 import gobject
-import hippo
 
 from sugar.graphics import animator
 from sugar.graphics import style
@@ -178,17 +177,12 @@ class Frame(object):
     def _create_top_panel(self):
         panel = self._create_panel(gtk.POS_TOP)
 
-        # TODO: setting box_width and hippo.PACK_EXPAND looks like a hack to
-        # me. Why hippo isn't respecting the request size of these controls?
-
         zoom_toolbar = ZoomToolbar()
-        panel.append(hippo.CanvasWidget(widget=zoom_toolbar,
-                box_width=4 * style.GRID_CELL_SIZE))
+        panel.append(zoom_toolbar, expand=False)
         zoom_toolbar.show()
 
         activities_tray = ActivitiesTray()
-        panel.append(hippo.CanvasWidget(widget=activities_tray),
-                hippo.PACK_EXPAND)
+        panel.append(activities_tray)
         activities_tray.show()
 
         return panel
@@ -196,10 +190,8 @@ class Frame(object):
     def _create_bottom_panel(self):
         panel = self._create_panel(gtk.POS_BOTTOM)
 
-        # TODO: same issue as in _create_top_panel()
         devices_tray = DevicesTray()
-        panel.append(hippo.CanvasWidget(widget=devices_tray),
-                     hippo.PACK_EXPAND)
+        panel.append(devices_tray)
         devices_tray.show()
 
         return panel
@@ -208,7 +200,7 @@ class Frame(object):
         panel = self._create_panel(gtk.POS_RIGHT)
 
         tray = FriendsTray()
-        panel.append(hippo.CanvasWidget(widget=tray), hippo.PACK_EXPAND)
+        panel.append(tray)
         tray.show()
 
         return panel
diff --git a/src/jarabe/frame/framewindow.py b/src/jarabe/frame/framewindow.py
index c77e76c..e0256eb 100644
--- a/src/jarabe/frame/framewindow.py
+++ b/src/jarabe/frame/framewindow.py
@@ -15,11 +15,109 @@
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 import gtk
-import hippo
+from gtk import gdk
+import gobject
 
 from sugar.graphics import style
 
 
+class FrameContainer(gtk.Container):
+    """A container class for frame panel rendering. Hosts a child 'box' where
+    frame elements can be added. Excludes grid-sized squares at each end
+    of the frame panel, and a space alongside the inside of the screen where
+    a border is drawn."""
+
+    __gtype_name__ = 'SugarFrameContainer'
+
+    def __init__(self, position):
+        gtk.Container.__init__(self)
+        self.set_has_window(False)
+        self._position = position
+
+        if self.is_vertical():
+            self._box = gtk.VBox()
+        else:
+            self._box = gtk.HBox()
+        self._box.set_parent(self)
+        self._box.show()
+
+    def is_vertical(self):
+        return self._position in (gtk.POS_LEFT, gtk.POS_RIGHT)
+
+    @gobject.property
+    def box(self):
+        return self._box
+
+    def do_realize(self):
+        self.set_flags(gtk.REALIZED)
+        self.set_window(self.get_parent_window())
+        self._box.set_parent_window(self.get_parent_window())
+        self.queue_resize()
+
+    def do_expose_event(self, event):
+        gtk.Container.do_expose_event(self, event)
+
+        # Draw the inner border as a rectangle
+        cr = self.get_parent_window().cairo_create()
+        r, g, b, a = style.COLOR_BUTTON_GREY.get_rgba()
+        cr.set_source_rgba (r, g, b, a)
+
+        if self.is_vertical():
+            x = style.GRID_CELL_SIZE if self._position == gtk.POS_LEFT else 0
+            y = style.GRID_CELL_SIZE
+            width = style.LINE_WIDTH
+            height = self.allocation.height - (style.GRID_CELL_SIZE * 2)
+        else:
+            x = style.GRID_CELL_SIZE
+            y = style.GRID_CELL_SIZE if self._position == gtk.POS_TOP else 0
+            height = style.LINE_WIDTH
+            width = self.allocation.width - (style.GRID_CELL_SIZE * 2)
+
+        cr.rectangle(x, y, width, height)
+        cr.fill()
+        return False
+
+    def do_size_request(self, req):
+        if self.is_vertical():
+            req.height = gdk.screen_height()
+            req.width = style.GRID_CELL_SIZE + style.LINE_WIDTH
+        else:
+            req.width = gdk.screen_width()
+            req.height = style.GRID_CELL_SIZE + style.LINE_WIDTH
+
+        self._box.size_request()
+
+    def do_size_allocate(self, allocation):
+        self.allocation = allocation
+
+        # exclude grid squares at two ends of the frame
+        # allocate remaining space to child box, minus the space needed for
+        # drawing the border
+        allocation = gdk.Rectangle()
+        if self.is_vertical():
+            allocation.x = 0 if self._position == gtk.POS_LEFT \
+                else style.LINE_WIDTH
+            allocation.y = style.GRID_CELL_SIZE
+            allocation.width = self.allocation.width - style.LINE_WIDTH
+            allocation.height = self.allocation.height \
+                - (style.GRID_CELL_SIZE * 2)
+        else:
+            allocation.x = style.GRID_CELL_SIZE
+            allocation.y = 0 if self._position == gtk.POS_TOP \
+                else style.LINE_WIDTH
+            allocation.width = self.allocation.width \
+                - (style.GRID_CELL_SIZE * 2)
+            allocation.height = self.allocation.height - style.LINE_WIDTH
+
+        self._box.size_allocate(allocation)
+
+    def do_forall(self, include_internals, callback, data):
+        callback(self._box, data)
+
+    def do_remove(self, child):
+        child.unparent()
+
+
 class FrameWindow(gtk.Window):
     __gtype_name__ = 'SugarFrameWindow'
 
@@ -39,79 +137,33 @@ class FrameWindow(gtk.Window):
         self.connect('enter-notify-event', self._enter_notify_cb)
         self.connect('leave-notify-event', self._leave_notify_cb)
 
-        self._canvas = hippo.Canvas()
-        self.add(self._canvas)
-        self._canvas.show()
-
-        box = hippo.CanvasBox()
-        self._canvas.set_root(box)
-
-        bg_box = hippo.CanvasBox(
-                border_color=style.COLOR_BUTTON_GREY.get_int())
-        box.append(bg_box, hippo.PACK_EXPAND)
-
-        self._bg = hippo.CanvasBox()
-        bg_box.append(self._bg, hippo.PACK_EXPAND)
-
-        padding = style.GRID_CELL_SIZE
-        border = style.LINE_WIDTH
-
-        if position == gtk.POS_TOP or position == gtk.POS_BOTTOM:
-            box.props.orientation = hippo.ORIENTATION_HORIZONTAL
-            box.props.padding_left = padding
-            box.props.padding_right = padding
-            box.props.padding_top = 0
-            box.props.padding_bottom = 0
-            self._bg.props.orientation = hippo.ORIENTATION_HORIZONTAL
-            self._bg.props.padding_left = border * 2
-            self._bg.props.padding_right = border * 2
-        else:
-            box.props.orientation = hippo.ORIENTATION_VERTICAL
-            box.props.padding_left = 0
-            box.props.padding_right = 0
-            box.props.padding_top = padding
-            box.props.padding_bottom = padding
-            self._bg.props.orientation = hippo.ORIENTATION_VERTICAL
-            self._bg.props.padding_top = border * 2
-            self._bg.props.padding_bottom = border * 2
-
-        if position == gtk.POS_TOP:
-            bg_box.props.orientation = hippo.ORIENTATION_HORIZONTAL
-            bg_box.props.border_bottom = border
-        elif position == gtk.POS_BOTTOM:
-            bg_box.props.orientation = hippo.ORIENTATION_HORIZONTAL
-            bg_box.props.border_top = border
-        elif position == gtk.POS_LEFT:
-            bg_box.props.orientation = hippo.ORIENTATION_VERTICAL
-            bg_box.props.border_right = border
-        elif position == gtk.POS_RIGHT:
-            bg_box.props.orientation = hippo.ORIENTATION_VERTICAL
-            bg_box.props.border_left = border
-
+        self._container = FrameContainer(position)
+        self.add(self._container)
+        self._container.show()
         self._update_size()
 
-        screen = gtk.gdk.screen_get_default()
+        screen = gdk.screen_get_default()
         screen.connect('size-changed', self._size_changed_cb)
 
-    def append(self, child, flags=0):
-        self._bg.append(child, flags)
+    def append(self, child, expand=True, fill=True):
+        self._container.box.pack_start(child, expand=expand, fill=fill)
 
     def _update_size(self):
         if self._position == gtk.POS_TOP or self._position == gtk.POS_BOTTOM:
-            self.resize(gtk.gdk.screen_width(), self.size)
+            self.resize(gdk.screen_width(), self.size)
         else:
-            self.resize(self.size, gtk.gdk.screen_height())
+            self.resize(self.size, gdk.screen_height())
 
     def _realize_cb(self, widget):
-        self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DOCK)
+        self.window.set_type_hint(gdk.WINDOW_TYPE_HINT_DOCK)
         self.window.set_accept_focus(False)
 
     def _enter_notify_cb(self, window, event):
-        if event.detail != gtk.gdk.NOTIFY_INFERIOR:
+        if event.detail != gdk.NOTIFY_INFERIOR:
             self.hover = True
 
     def _leave_notify_cb(self, window, event):
-        if event.detail != gtk.gdk.NOTIFY_INFERIOR:
+        if event.detail != gdk.NOTIFY_INFERIOR:
             self.hover = False
 
     def _size_changed_cb(self, screen):
diff --git a/src/jarabe/frame/zoomtoolbar.py b/src/jarabe/frame/zoomtoolbar.py
index 2effea2..c28fe1c 100644
--- a/src/jarabe/frame/zoomtoolbar.py
+++ b/src/jarabe/frame/zoomtoolbar.py
@@ -21,6 +21,7 @@ import logging
 import glib
 import gtk
 
+from sugar.graphics import style
 from sugar.graphics.palette import Palette
 from sugar.graphics.radiotoolbutton import RadioToolButton
 
@@ -35,6 +36,9 @@ class ZoomToolbar(gtk.Toolbar):
         # we shouldn't be mirrored in RTL locales
         self.set_direction(gtk.TEXT_DIR_LTR)
 
+        # ask not to be collapsed if possible
+        self.set_size_request(4 * style.GRID_CELL_SIZE, -1)
+
         self._mesh_button = self._add_button('zoom-neighborhood',
                 _('Neighborhood'), _('F1'), shell.ShellModel.ZOOM_MESH)
         self._groups_button = self._add_button('zoom-groups',
-- 
1.7.6.2



More information about the Sugar-devel mailing list