From 0a912e214a815717be270a4ae49becc8721a26dc Mon Sep 17 00:00:00 2001 From: Marco Pesenti Gritti Date: Mon, 2 Oct 2006 01:50:43 +0200 Subject: [PATCH] Start moving to hippo canvas. (Friends presence in the activity regressed) --- configure.ac | 1 + .../{BottomPanel.py => ActivitiesBox.py} | 47 ++++---- shell/view/frame/Frame.py | 84 ++++++------- shell/view/frame/PanelWindow.py | 33 +++-- shell/view/frame/RightPanel.py | 12 +- shell/view/frame/{TopPanel.py => ZoomBox.py} | 58 ++++----- sugar/Makefile.am | 2 +- sugar/graphics/__init__.py | 20 ++++ sugar/graphics/canvasicon.py | 5 + sugar/graphics/grid.py | 2 +- sugar/graphics/menuicon.py | 113 ++++++++++++++++++ sugar/graphics/style.py | 15 +-- tests/test-icons.py | 27 ++--- 13 files changed, 267 insertions(+), 152 deletions(-) rename shell/view/frame/{BottomPanel.py => ActivitiesBox.py} (54%) rename shell/view/frame/{TopPanel.py => ZoomBox.py} (63%) create mode 100644 sugar/graphics/menuicon.py diff --git a/configure.ac b/configure.ac index 4d8a2f98..9a5b0581 100644 --- a/configure.ac +++ b/configure.ac @@ -66,6 +66,7 @@ sugar/activity/Makefile sugar/canvas/Makefile sugar/chat/Makefile sugar/chat/sketchpad/Makefile +sugar/graphics/Makefile sugar/p2p/Makefile sugar/p2p/model/Makefile sugar/presence/Makefile diff --git a/shell/view/frame/BottomPanel.py b/shell/view/frame/ActivitiesBox.py similarity index 54% rename from shell/view/frame/BottomPanel.py rename to shell/view/frame/ActivitiesBox.py index 7509576f..d46f3bed 100644 --- a/shell/view/frame/BottomPanel.py +++ b/shell/view/frame/ActivitiesBox.py @@ -1,26 +1,25 @@ -import gtk -import goocanvas +import hippo import logging import conf -from sugar.canvas.IconItem import IconItem -from sugar.canvas.IconColor import IconColor +from sugar.graphics.canvasicon import CanvasIcon from sugar.presence import PresenceService -from sugar.canvas.CanvasBox import CanvasBox +from sugar.graphics import style -class ActivityItem(IconItem): +class ActivityItem(CanvasIcon): def __init__(self, activity): icon_name = activity.get_icon() - IconItem.__init__(self, icon_name=icon_name, color=IconColor('white')) + CanvasIcon.__init__(self, icon_name=icon_name) + style.apply_stylesheet(self, 'frame-activity-icon') self._activity = activity def get_bundle_id(self): return self._activity.get_id() -class InviteItem(IconItem): +class InviteItem(CanvasIcon): def __init__(self, invite): - IconItem.__init__(self, icon_name=invite.get_icon(), - color=invite.get_color()) + CanvasIcon.__init__(self, icon_name=invite.get_icon(), + color=invite.get_color()) self._invite = invite def get_activity_id(self): @@ -32,9 +31,9 @@ class InviteItem(IconItem): def get_invite(self): return self._invite -class BottomPanel(CanvasBox): +class ActivitiesBox(hippo.CanvasBox): def __init__(self, shell): - CanvasBox.__init__(self, shell.get_grid(), CanvasBox.HORIZONTAL) + hippo.CanvasBox.__init__(self, orientation=hippo.ORIENTATION_HORIZONTAL) self._shell = shell self._invite_to_item = {} @@ -47,37 +46,35 @@ class BottomPanel(CanvasBox): for invite in self._invites: self.add_invite(invite) - self._invites.connect('invite-added', self.__invite_added_cb) - self._invites.connect('invite-removed', self.__invite_removed_cb) + self._invites.connect('invite-added', self._invite_added_cb) + self._invites.connect('invite-removed', self._invite_removed_cb) - def __activity_clicked_cb(self, icon): + def _activity_clicked_cb(self, icon): self._shell.start_activity(icon.get_bundle_id()) - def __invite_clicked_cb(self, icon): + def _invite_clicked_cb(self, icon): self._invites.remove_invite(icon.get_invite()) self._shell.join_activity(icon.get_bundle_id(), icon.get_activity_id()) - def __invite_added_cb(self, invites, invite): + def _invite_added_cb(self, invites, invite): self.add_invite(invite) - def __invite_removed_cb(self, invites, invite): + def _invite_removed_cb(self, invites, invite): self.remove_invite(invite) def add_activity(self, activity): item = ActivityItem(activity) - item.connect('clicked', self.__activity_clicked_cb) - self.set_constraints(item, 5, 5) - self.add_child(item) + item.connect('activated', self._activity_clicked_cb) + self.append(item, 0) def add_invite(self, invite): item = InviteItem(invite) - item.connect('clicked', self.__invite_clicked_cb) - self.set_constraints(item, 5, 5) - self.add_child(item, 0) + item.connect('activated', self._invite_clicked_cb) + self.append(item, 0) self._invite_to_item[invite] = item def remove_invite(self, invite): - self.remove_child(self._invite_to_item[invite]) + self.remove(self._invite_to_item[invite]) del self._invite_to_item[invite] diff --git a/shell/view/frame/Frame.py b/shell/view/frame/Frame.py index 0206080b..bd7e51f4 100644 --- a/shell/view/frame/Frame.py +++ b/shell/view/frame/Frame.py @@ -1,15 +1,14 @@ import gtk import gobject -import goocanvas +import hippo import wnck -from view.frame.BottomPanel import BottomPanel -from view.frame.RightPanel import RightPanel -from view.frame.TopPanel import TopPanel +from view.frame.ActivitiesBox import ActivitiesBox +from view.frame.ZoomBox import ZoomBox from view.frame.PanelWindow import PanelWindow -from sugar.canvas.Grid import Grid from sugar.canvas.Timeline import Timeline from sugar.canvas.MenuShell import MenuShell +from sugar.graphics.grid import Grid class EventFrame(gobject.GObject): __gsignals__ = { @@ -116,51 +115,52 @@ class Frame: self._timeline.add_tag('before_slide_out', 36, 36) self._timeline.add_tag('slide_out', 37, 42) - model = goocanvas.CanvasModelSimple() - root = model.get_root_item() - - grid = shell.get_grid() - self._menu_shell = MenuShell(grid) - self._menu_shell.connect('activated', self._menu_shell_activated_cb) - self._menu_shell.connect('deactivated', self._menu_shell_deactivated_cb) - - bg = goocanvas.Rect(fill_color="#4f4f4f", line_width=0) - grid.set_constraints(bg, 0, 0, 80, 60) - root.add_child(bg) - - panel = BottomPanel(shell) - grid.set_constraints(panel, 5, 55) - root.add_child(panel) - - self._add_panel(model, 0, 55, 80, 5) - - panel = TopPanel(shell, self._menu_shell) - root.add_child(panel) - - self._add_panel(model, 0, 0, 80, 5) - - panel = RightPanel(shell, self._menu_shell) - grid.set_constraints(panel, 75, 5) - root.add_child(panel) - - self._add_panel(model, 75, 5, 5, 50) - - self._add_panel(model, 0, 5, 5, 50) - self._event_frame = EventFrame() self._event_frame.connect('enter-edge', self._enter_edge_cb) self._event_frame.connect('enter-corner', self._enter_corner_cb) self._event_frame.connect('leave', self._event_frame_leave_cb) self._event_frame.show() - def _add_panel(self, model, x, y, width, height): - grid = self._shell.get_grid() + grid = Grid() - panel_window = PanelWindow(grid, model, x, y, width, height) - panel_window.connect('enter-notify-event', self._enter_notify_cb) - panel_window.connect('leave-notify-event', self._leave_notify_cb) + self._menu_shell = MenuShell(grid) + self._menu_shell.connect('activated', self._menu_shell_activated_cb) + self._menu_shell.connect('deactivated', self._menu_shell_deactivated_cb) - self._windows.append(panel_window) + top_panel = self._create_panel(grid, 0, 0, 16, 1) + + box = ZoomBox(self._shell, self._menu_shell) + top_panel.append(box, hippo.PACK_FIXED) + + [x, y] = grid.point(1, 0) + top_panel.move(box, x, y) + + bottom_panel = self._create_panel(grid, 0, 11, 16, 1) + + box = ActivitiesBox(self._shell) + bottom_panel.append(box, hippo.PACK_FIXED) + + [x, y] = grid.point(1, 0) + bottom_panel.move(box, x, y) + + left_panel = self._create_panel(grid, 0, 1, 1, 10) + + right_panel = self._create_panel(grid, 15, 1, 1, 10) + + def _create_panel(self, grid, x, y, width, height): + panel = PanelWindow() + + panel.connect('enter-notify-event', self._enter_notify_cb) + panel.connect('leave-notify-event', self._leave_notify_cb) + + [x, y, width, height] = grid.rectangle(x, y, width, height) + + panel.move(x, y) + panel.resize(width, height) + + self._windows.append(panel) + + return panel.get_root() def _menu_shell_activated_cb(self, menu_shell): self._timeline.goto('slide_in', True) diff --git a/shell/view/frame/PanelWindow.py b/shell/view/frame/PanelWindow.py index 549776f5..0c2930cd 100644 --- a/shell/view/frame/PanelWindow.py +++ b/shell/view/frame/PanelWindow.py @@ -1,27 +1,24 @@ import gtk -import goocanvas - -from sugar.canvas.CanvasView import CanvasView +import hippo class PanelWindow(gtk.Window): - def __init__(self, grid, model, x, y, width, height): + def __init__(self): gtk.Window.__init__(self) - self._grid = grid - self.set_decorated(False) + self.connect('realize', self._realize_cb) - self.realize() + canvas = hippo.Canvas() + + self._bg = hippo.CanvasBox(background_color=0x4f4f4fff) + canvas.set_root(self._bg) + + self.add(canvas) + canvas.show() + + def get_root(self): + return self._bg + + def _realize_cb(self, widget): self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) self.window.set_accept_focus(False) - - screen = gtk.gdk.screen_get_default() - self.window.set_transient_for(screen.get_root_window()) - - view = CanvasView() - view.show() - self.add(view) - view.set_model(model) - - self._grid.set_constraints(self, x, y, width, height) - self._grid.set_constraints(view, x, y, width, height) diff --git a/shell/view/frame/RightPanel.py b/shell/view/frame/RightPanel.py index 28c81b3a..9c164020 100644 --- a/shell/view/frame/RightPanel.py +++ b/shell/view/frame/RightPanel.py @@ -1,16 +1,15 @@ -import goocanvas +import hippo -from sugar.canvas.IconItem import IconItem +from sugar.graphics.CanvasIcon import CanvasIcon from sugar.canvas.IconColor import IconColor -from sugar.canvas.CanvasBox import CanvasBox from sugar.presence import PresenceService from view.BuddyIcon import BuddyIcon from model.BuddyModel import BuddyModel from view.frame.MenuStrategy import MenuStrategy -class RightPanel(CanvasBox): +class RightPanel(hippo.CanvasBox): def __init__(self, shell, menu_shell): - CanvasBox.__init__(self, shell.get_grid(), CanvasBox.VERTICAL) + CanvasBox.__init__(self) self._shell = shell self._menu_shell = menu_shell self._activity_ps = None @@ -28,8 +27,7 @@ class RightPanel(CanvasBox): model = BuddyModel(buddy=buddy) icon = BuddyIcon(self._shell, self._menu_shell, model) icon.set_menu_strategy(MenuStrategy()) - self.set_constraints(icon, 5, 5) - self.add_child(icon) + self.append(icon, 0) self._buddies[buddy.get_name()] = icon diff --git a/shell/view/frame/TopPanel.py b/shell/view/frame/ZoomBox.py similarity index 63% rename from shell/view/frame/TopPanel.py rename to shell/view/frame/ZoomBox.py index e0aec2ea..8e78979e 100644 --- a/shell/view/frame/TopPanel.py +++ b/shell/view/frame/ZoomBox.py @@ -1,9 +1,11 @@ import goocanvas +import hippo -from sugar.canvas.CanvasBox import CanvasBox -from sugar.canvas.IconItem import IconItem -from sugar.canvas.MenuIcon import MenuIcon +from sugar.graphics.canvasicon import CanvasIcon +from sugar.graphics.menuicon import MenuIcon +from sugar.graphics import style from sugar.canvas.Menu import Menu +from sugar.canvas.IconItem import IconItem from view.frame.MenuStrategy import MenuStrategy import sugar @@ -51,53 +53,45 @@ class ActivityIcon(MenuIcon): if action == ActivityMenu.ACTION_CLOSE: activity.close() -class TopPanel(goocanvas.Group): +class ZoomBox(hippo.CanvasBox): def __init__(self, shell, menu_shell): - goocanvas.Group.__init__(self) + hippo.CanvasBox.__init__(self, orientation=hippo.ORIENTATION_HORIZONTAL) self._shell = shell self._menu_shell = menu_shell self._activity_icon = None - grid = shell.get_grid() + icon = CanvasIcon(icon_name='stock-zoom-mesh') + style.apply_stylesheet(icon, 'frame-zoom-icon') + icon.connect('activated', self._level_clicked_cb, sugar.ZOOM_MESH) + self.append(icon, 0) - box = CanvasBox(grid, CanvasBox.HORIZONTAL) - grid.set_constraints(box, 5, 0) - self.add_child(box) + icon = CanvasIcon(icon_name='stock-zoom-friends') + style.apply_stylesheet(icon, 'frame-zoom-icon') + icon.connect('activated', self._level_clicked_cb, sugar.ZOOM_FRIENDS) + self.append(icon, 0) - icon = IconItem(icon_name='stock-zoom-mesh') - icon.connect('clicked', self._level_clicked_cb, sugar.ZOOM_MESH) - box.set_constraints(icon, 5, 5) - box.add_child(icon) + icon = CanvasIcon(icon_name='stock-zoom-home') + style.apply_stylesheet(icon, 'frame-zoom-icon') + icon.connect('activated', self._level_clicked_cb, sugar.ZOOM_HOME) + self.append(icon, 0) - icon = IconItem(icon_name='stock-zoom-friends') - icon.connect('clicked', self._level_clicked_cb, sugar.ZOOM_FRIENDS) - box.set_constraints(icon, 5, 5) - box.add_child(icon) - - icon = IconItem(icon_name='stock-zoom-home') - icon.connect('clicked', self._level_clicked_cb, sugar.ZOOM_HOME) - box.set_constraints(icon, 5, 5) - box.add_child(icon) - - icon = IconItem(icon_name='stock-zoom-activity') - icon.connect('clicked', self._level_clicked_cb, sugar.ZOOM_ACTIVITY) - box.set_constraints(icon, 5, 5) - box.add_child(icon) - - self._box = box + icon = CanvasIcon(icon_name='stock-zoom-activity') + style.apply_stylesheet(icon, 'frame-zoom-icon') + icon.connect('activated', self._level_clicked_cb, sugar.ZOOM_ACTIVITY) + self.append(icon, 0) shell.connect('activity-changed', self._activity_changed_cb) self._set_current_activity(shell.get_current_activity()) def _set_current_activity(self, activity): if self._activity_icon: - self._box.remove_child(self._activity_icon) + self.remove(self._activity_icon) if activity: icon = ActivityIcon(self._shell, self._menu_shell, activity) - self._box.set_constraints(icon, 5, 5) - self._box.add_child(icon) + style.apply_stylesheet(icon, 'frame-zoom-icon') + self.append(icon, 0) self._activity_icon = icon else: self._activity_icon = None diff --git a/sugar/Makefile.am b/sugar/Makefile.am index 2cee687d..0e653511 100644 --- a/sugar/Makefile.am +++ b/sugar/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = activity canvas chat p2p presence session +SUBDIRS = activity canvas chat graphics p2p presence session sugardir = $(pythondir)/sugar sugar_PYTHON = \ diff --git a/sugar/graphics/__init__.py b/sugar/graphics/__init__.py index e69de29b..8bfa7eb5 100644 --- a/sugar/graphics/__init__.py +++ b/sugar/graphics/__init__.py @@ -0,0 +1,20 @@ +import gtk + +from sugar.graphics import style +from sugar.canvas.IconColor import IconColor + +if gtk.gdk.screen_width() == 1200: + _medium_icon_size = 75 +else: + _medium_icon_size = 50 + +_stylesheet = { + 'color' : IconColor('white'), + 'size' : _medium_icon_size +} +style.register_stylesheet('frame-activity-icon', _stylesheet) + +_stylesheet = { + 'size' : _medium_icon_size +} +style.register_stylesheet('frame-zoom-icon', _stylesheet) diff --git a/sugar/graphics/canvasicon.py b/sugar/graphics/canvasicon.py index e8d8ea41..17a0193d 100644 --- a/sugar/graphics/canvasicon.py +++ b/sugar/graphics/canvasicon.py @@ -73,6 +73,8 @@ class CanvasIcon(hippo.CanvasBox, hippo.CanvasItem): self._buffer = None self._buffer_size = 0.0 + self.connect('button-press-event', self._button_press_event_cb) + def do_set_property(self, pspec, value): if pspec.name == 'icon-name': self._icon_name = value @@ -132,3 +134,6 @@ class CanvasIcon(hippo.CanvasBox, hippo.CanvasItem): def do_get_height_request(self, for_width): return self._size + + def _button_press_event_cb(self, item, event): + item.emit_activated() diff --git a/sugar/graphics/grid.py b/sugar/graphics/grid.py index be44f43a..8ee124a3 100644 --- a/sugar/graphics/grid.py +++ b/sugar/graphics/grid.py @@ -7,7 +7,7 @@ class Grid(object): def __init__(self): self._factor = gtk.gdk.screen_width() / COLS - def position(self, x, y): + def point(self, x, y): return [x * self._factor, y * self._factor] def rectangle(self, x, y, width, height): diff --git a/sugar/graphics/menuicon.py b/sugar/graphics/menuicon.py new file mode 100644 index 00000000..88a8d561 --- /dev/null +++ b/sugar/graphics/menuicon.py @@ -0,0 +1,113 @@ +import hippo +import gobject + +from sugar.graphics.canvasicon import CanvasIcon + +class _MenuStrategy: + def get_menu_position(self, menu, grid_x1, grid_y1, grid_x2, grid_y2): + grid_x = grid_x2 + if grid_x + menu.get_width() > Grid.COLS: + grid_x = grid_x1 - menu.get_width() + 1 + + grid_y = grid_y1 + + if grid_y < 0: + grid_y = 0 + if grid_y + menu.get_width() > Grid.ROWS: + grid_y = Grid.ROWS - menu.get_width() + + return [grid_x, grid_y] + +class MenuIcon(CanvasIcon): + def __init__(self, menu_shell, **kwargs): + CanvasIcon.__init__(self, **kwargs) + + self._menu_shell = menu_shell + self._grid = menu_shell.get_grid() + self._menu = None + self._hover_menu = False + self._popdown_on_leave = False + self._popdown_sid = 0 + self._menu_strategy = _MenuStrategy() + + self.connect('motion-notify-event', self._motion_notify_event_cb) + + def popdown(self): + if self._menu: + self._menu.destroy() + self._menu = None + self._menu_shell.set_active(None) + + def set_menu_strategy(self, strategy): + self._menu_strategy = strategy + + def _popup(self, x1, y1, x2, y2): + self.popdown() + + self._menu_shell.set_active(None) + + grid = self._shell.get_grid() + self._menu = self.create_menu() + self._menu.connect('enter-notify-event', + self._menu_enter_notify_event_cb) + self._menu.connect('leave-notify-event', + self._menu_leave_notify_event_cb) + + [grid_x1, grid_y1] = grid.convert_from_screen(x1, y1) + [grid_x2, grid_y2] = grid.convert_from_screen(x2, y2) + + strategy = self._menu_strategy + [grid_x, grid_y] = strategy.get_menu_position(self._menu, + grid_x1, grid_y1, + grid_x2, grid_y2) + + grid.set_constraints(self._menu, grid_x, grid_y, + self._menu.get_width(), self._menu.get_height()) + + self._menu.show() + + self._menu_shell.set_active(self) + + def _menu_enter_notify_event_cb(self, widget, event): + self._hover_menu = True + + def _menu_leave_notify_event_cb(self, widget, event): + self._hover_menu = False + if self._popdown_on_leave: + self.popdown() + + def _start_popdown_timeout(self): + self._stop_popdown_timeout() + self._popdown_sid = gobject.timeout_add(1000, self._popdown_timeout_cb) + + def _stop_popdown_timeout(self): + if self._popdown_sid > 0: + gobject.source_remove(self._popdown_sid) + self._popdown_sid = 0 + + def _motion_notify_event_cb(self, item, event): + if event.detail == hippo.MOTION_DETAIL_ENTER: + self._motion_notify_enter() + elif event.detail == hippo.MOTION_DETAIL_LEAVE: + self._motion_notify_leave() + + def _motion_notify_enter(self): + self._stop_popdown_timeout() + + [x, y] = self.get_context().translate_to_widget(self) + [width, height] = self.get_allocation() + + self._popup(x, y, width, height) + + def _motion_notify_leave(self): + self._start_popdown_timeout() + + def _popdown_timeout_cb(self): + self._popdown_sid = 0 + + if not self._hover_menu: + self.popdown() + else: + self._popdown_on_leave = True + + return False diff --git a/sugar/graphics/style.py b/sugar/graphics/style.py index f8a08988..4b1bc536 100644 --- a/sugar/graphics/style.py +++ b/sugar/graphics/style.py @@ -1,13 +1,10 @@ _styles = {} -def register_style(name, style): +def register_stylesheet(name, style): _styles[name] = style -def apply_style(name, item): - if _styles.has_key(name): - for name in _styles.keys(): - item.set_property(name, _styles[name] - -def Style(dict): - def set_property(self, name, value): - self._properties[name] = value +def apply_stylesheet(item, stylesheet_name): + if _styles.has_key(stylesheet_name): + style_sheet = _styles[stylesheet_name] + for name in style_sheet.keys(): + item.set_property(name, style_sheet[name]) diff --git a/tests/test-icons.py b/tests/test-icons.py index ff578e0c..c4247060 100755 --- a/tests/test-icons.py +++ b/tests/test-icons.py @@ -11,42 +11,35 @@ import sys import random import gtk -import goocanvas +import hippo from sugar.canvas import IconColor -from sugar.canvas.IconItem import IconItem +from sugar.canvas.CanvasIcon import CanvasIcon from sugar.canvas.CanvasView import CanvasView window = gtk.Window() window.connect("destroy", lambda w: gtk.main_quit()) window.show() -canvas = CanvasView() +canvas = hippo.Canvas() canvas.show() window.add(canvas) -canvas_model = goocanvas.CanvasModelSimple() -root = canvas_model.get_root_item() - -item = goocanvas.Rect(x=0, y=0, width=1200, height=900, - line_width=0.0, fill_color="#4f4f4f") -root.add_child(item) +box = hippo.CanvasBox(background_color=0x4f4f4fff) +canvas.set_root(box) icon_names = [ 'stock-buddy', 'activity-groupchat', 'activity-web'] k = 0 -while k < 12: +while k < 1: i = 0 - while i < 16: + while i < 10: color = IconColor.IconColor() icon_name_n = int(random.random() * len(icon_names)) - icon = IconItem(x=i * 75, y=k * 75, - size=75, color=color, - icon_name=icon_names[icon_name_n]) - root.add_child(icon) + icon = CanvasIcon(icon_name=icon_names[icon_name_n], + size=75, color=color) + box.append(icon, 0) i += 1 k += 1 -canvas.set_model(canvas_model) - gtk.main()