diff --git a/src/jarabe/desktop/Makefile.am b/src/jarabe/desktop/Makefile.am index 25fb0b42e9..b36404e048 100644 --- a/src/jarabe/desktop/Makefile.am +++ b/src/jarabe/desktop/Makefile.am @@ -14,5 +14,5 @@ sugar_PYTHON = \ networkviews.py \ schoolserver.py \ snowflakelayout.py \ - spreadlayout.py \ - transitionbox.py + transitionbox.py \ + viewcontainer.py diff --git a/src/jarabe/desktop/favoriteslayout.py b/src/jarabe/desktop/favoriteslayout.py index 360c147dd9..0f63f95264 100644 --- a/src/jarabe/desktop/favoriteslayout.py +++ b/src/jarabe/desktop/favoriteslayout.py @@ -20,9 +20,7 @@ import hashlib from gettext import gettext as _ -import gobject import gtk -import hippo from sugar.graphics import style @@ -42,77 +40,134 @@ style.SMALL_ICON_SIZE] -class FavoritesLayout(gobject.GObject, hippo.CanvasLayout): - """Base class of the different layout types.""" - - __gtype_name__ = 'FavoritesLayout' - +class Layout(object): def __init__(self): - gobject.GObject.__init__(self) - self.box = None - self.fixed_positions = {} + pass - def do_set_box(self, box): - self.box = box + def remove(self, child): + pass - def do_get_height_request(self, for_width): - return 0, gtk.gdk.screen_height() - style.GRID_CELL_SIZE + def allocate_children(self, allocation, children): + pass - def do_get_width_request(self): - return 0, gtk.gdk.screen_width() - def compare_activities(self, icon_a, icon_b): - return 0 +class ViewLayout(Layout): + def __init__(self): + self._grid = None - def append(self, icon, locked=False): - if not hasattr(type(icon), 'fixed_position'): - logging.debug('Icon without fixed_position: %r', icon) + def setup(self, allocation, owner_icon, activity_icon=None): + if self._grid is not None: return - - icon.props.size = max(icon.props.size, style.STANDARD_ICON_SIZE) - - relative_x, relative_y = icon.fixed_position - if relative_x < 0 or relative_y < 0: - logging.debug('Icon out of bounds: %r', icon) + self._grid = Grid(int(allocation.width / _CELL_SIZE), + int(allocation.height / _CELL_SIZE)) + self._grid.connect('child-changed', self.__grid_child_changed_cb) + self._allocate_owner_icon(allocation, owner_icon, activity_icon) + + def _allocate_owner_icon(self, allocation, owner_icon, activity_icon): + # add owner icon to the grid, precisely centered on the screen + # if not None, add an activity icon directly below the owner icon + owner_width, owner_height = owner_icon.size_request() + height = allocation.height + allocation.y + width = allocation.width + + # Find vertical center point of screen + y = height / 2 + + # This container may be offset from the top by a certain amount + # (e.g. for a toolbar at the top of the screen). Adjust the + # center-point for that + y -= allocation.y + + # Now subtract half of the owner height. This gives us the y + # coordinate for the top of the owner icon. + y -= owner_height / 2 + + # calculate x coordinate and create allocation + x = (width - owner_width) / 2 + owner_icon_allocation = gtk.gdk.Rectangle(x, allocation.y + y, + owner_width, owner_height) + owner_icon.size_allocate(owner_icon_allocation) + + # Determine grid coordinates and add to grid + owner_grid_width, owner_grid_height = \ + self._get_child_grid_size(owner_icon) + x = int(x / float(_CELL_SIZE)) + y = int(y / float(_CELL_SIZE)) + self._grid.add(owner_icon, owner_grid_width, owner_grid_height, + x, y, locked=True) + + if activity_icon is None: return - min_width_, width = self.box.get_width_request() - min_height_, height = self.box.get_height_request(width) - self.fixed_positions[icon] = \ - (int(relative_x * _BASE_SCALE / float(width)), - int(relative_y * _BASE_SCALE / float(height))) + # Position the current activity below the XO icon + # FIXME must ensure we cross into next grid cell here.. + activity_width, activity_height = activity_icon.size_request() + x = (width - activity_width) / 2 + y = owner_icon_allocation.y + owner_height + activity_icon_allocation = gtk.gdk.Rectangle(x, y, activity_width, + activity_height) + activity_icon.size_allocate(activity_icon_allocation) + + # Determine grid coordinates and add to grid + activity_grid_width, activity_grid_height = \ + self._get_child_grid_size(activity_icon) + x = int(x / float(_CELL_SIZE)) + y = int(y / float(_CELL_SIZE)) + self._grid.add(activity_icon, activity_grid_width, + activity_grid_height, x, y, locked=True) + + def allocate_children(self, allocation, children): + pass + + def move(self, child, x, y, allocation=None): + self._grid.move(child, x / _CELL_SIZE, y / _CELL_SIZE, locked=True) + width, height = child.size_request() + rect = self._grid.get_child_rect(child) + child_allocation = gtk.gdk.Rectangle(int(round(rect.x * _CELL_SIZE)), + int(round(rect.y * _CELL_SIZE)), + width, + height) + child.size_allocate(child_allocation) + + def _get_child_grid_size(self, child): + width, height = child.size_request() + width = math.ceil(width / _CELL_SIZE) + height = math.ceil(height / _CELL_SIZE) + return int(width), int(height) - def remove(self, icon): - if icon in self.fixed_positions: - del self.fixed_positions[icon] + def __grid_child_changed_cb(self, grid, child): + width, height = child.size_request() + rect = self._grid.get_child_rect(child) + child_allocation = gtk.gdk.Rectangle(int(round(rect.x * _CELL_SIZE)), + int(round(rect.y * _CELL_SIZE)), + width, + height) + child.size_allocate(child_allocation) - def move_icon(self, icon, x, y, locked=False): - if icon not in self.box.get_children(): - raise ValueError('Child not in box.') - if not (hasattr(icon, 'get_bundle_id') and - hasattr(icon, 'get_version')): - logging.debug('Not an activity icon %r', icon) - return +class SpreadLayout(ViewLayout): + def __init__(self): + ViewLayout.__init__(self) - min_width_, width = self.box.get_width_request() - min_height_, height = self.box.get_height_request(width) - registry = bundleregistry.get_registry() - registry.set_bundle_position( - icon.get_bundle_id(), icon.get_version(), - x * width / float(_BASE_SCALE), - y * height / float(_BASE_SCALE)) - self.fixed_positions[icon] = (x, y) + def remove(self, child): + if self._grid.is_in_grid(child): + self._grid.remove(child) - def do_allocate(self, x, y, width, height, req_width, req_height, - origin_changed): - raise NotImplementedError() + def allocate_children(self, allocation, children): + for child in children: + if not self._grid.is_in_grid(child): + width, height = self._get_child_grid_size(child) + self._grid.add(child, width, height, None, None, locked=False) - def allow_dnd(self): - return False + width, height = child.size_request() + rect = self._grid.get_child_rect(child) + x = int(round(rect.x * _CELL_SIZE)) + y = int(round(rect.y * _CELL_SIZE)) + allocation.y + child_allocation = gtk.gdk.Rectangle(x, y, width, height) + child.size_allocate(child_allocation) -class RandomLayout(FavoritesLayout): +class RandomLayout(SpreadLayout): """Lay out icons randomly; try to nudge them around to resolve overlaps.""" __gtype_name__ = 'RandomLayout' @@ -128,69 +183,75 @@ class RandomLayout(FavoritesLayout): """String used to identify this layout in home view dropdown palette.""" def __init__(self): - FavoritesLayout.__init__(self) - - min_width_, width = self.do_get_width_request() - min_height_, height = self.do_get_height_request(width) - - self._grid = Grid(width / _CELL_SIZE, height / _CELL_SIZE) - self._grid.connect('child-changed', self.__grid_child_changed_cb) - - def __grid_child_changed_cb(self, grid, child): - child.emit_request_changed() - - def append(self, icon, locked=False): - FavoritesLayout.append(self, icon, locked) - - min_width_, child_width = icon.get_width_request() - min_height_, child_height = icon.get_height_request(child_width) - min_width_, width = self.box.get_width_request() - min_height_, height = self.box.get_height_request(width) - - if icon in self.fixed_positions: - x, y = self.fixed_positions[icon] - x = min(x, width - child_width) - y = min(y, height - child_height) - elif hasattr(icon, 'get_bundle_id'): - name_hash = hashlib.md5(icon.get_bundle_id()) - x = int(name_hash.hexdigest()[:5], 16) % (width - child_width) - y = int(name_hash.hexdigest()[-5:], 16) % (height - child_height) - else: - x = None - y = None - - if x is None or y is None: - self._grid.add(icon, - child_width / _CELL_SIZE, child_height / _CELL_SIZE) - else: - self._grid.add(icon, - child_width / _CELL_SIZE, child_height / _CELL_SIZE, - x / _CELL_SIZE, y / _CELL_SIZE) + SpreadLayout.__init__(self) + self.fixed_positions = {} - def remove(self, icon): - self._grid.remove(icon) - FavoritesLayout.remove(self, icon) + def _add_fixed_position(self, icon, allocation, locked=False): + if not hasattr(type(icon), 'fixed_position'): + logging.debug('Icon without fixed_position: %r', icon) + return - def move_icon(self, icon, x, y, locked=False): - self._grid.move(icon, x / _CELL_SIZE, y / _CELL_SIZE, locked) - FavoritesLayout.move_icon(self, icon, x, y, locked) + icon.props.pixel_size = max(icon.props.pixel_size, + style.STANDARD_ICON_SIZE) - def do_allocate(self, x, y, width, height, req_width, req_height, - origin_changed): - for child in self.box.get_layout_children(): - # We need to always get requests to not confuse hippo - min_w_, child_width = child.get_width_request() - min_h_, child_height = child.get_height_request(child_width) + relative_x, relative_y = icon.fixed_position + if relative_x < 0 or relative_y < 0: + logging.debug('Icon out of bounds: %r', icon) + return - rect = self._grid.get_child_rect(child.item) - child.allocate(rect.x * _CELL_SIZE, - rect.y * _CELL_SIZE, - child_width, - child_height, - origin_changed) + self.fixed_positions[icon] = \ + (int(relative_x * _BASE_SCALE / float(allocation.width)), + int(relative_y * _BASE_SCALE / float(allocation.height))) + + def allocate_children(self, allocation, children): + for child in children: + child_width, child_height = child.size_request() + if not self._grid.is_in_grid(child): + self._add_fixed_position(child, allocation) + + if child in self.fixed_positions: + x, y = self.fixed_positions[child] + x = min(x, allocation.width - child_width) + y = min(y, allocation.height - child_height) + elif hasattr(child, 'get_bundle_id'): + name_hash = hashlib.md5(child.get_bundle_id()) + x = int(name_hash.hexdigest()[:5], 16) % \ + (allocation.width - child_width) + y = int(name_hash.hexdigest()[-5:], 16) % \ + (allocation.height - child_height) + else: + x = None + y = None + + if x is None or y is None: + self._grid.add(child, child_width / _CELL_SIZE, + child_height / _CELL_SIZE) + else: + self._grid.add(child, child_width / _CELL_SIZE, + child_height / _CELL_SIZE, + x / _CELL_SIZE, y / _CELL_SIZE) + + rect = self._grid.get_child_rect(child) + x = int(round(rect.x * _CELL_SIZE)) + y = int(round(rect.y * _CELL_SIZE)) + allocation.y + child_allocation = gtk.gdk.Rectangle(x, y, + child_width, child_height) + child.size_allocate(child_allocation) + + def move_icon(self, child, x, y, allocation): + ViewLayout.move(self, child, x, y) + + if not (hasattr(child, 'get_bundle_id') and + hasattr(child, 'get_version')): + logging.debug('Not an activity icon %r', child) + return - def allow_dnd(self): - return True + registry = bundleregistry.get_registry() + registry.set_bundle_position( + child.get_bundle_id(), child.get_version(), + x * allocation.width / float(_BASE_SCALE), + y * allocation.height / float(_BASE_SCALE)) + self.fixed_positions[child] = (x, y) _MINIMUM_RADIUS = style.XLARGE_ICON_SIZE / 2 + style.DEFAULT_SPACING + \ @@ -203,7 +264,7 @@ def allow_dnd(self): _INITIAL_ANGLE = math.pi -class RingLayout(FavoritesLayout): +class RingLayout(ViewLayout): """Lay out icons in a ring or spiral around the XO man.""" __gtype_name__ = 'RingLayout' @@ -216,28 +277,9 @@ class RingLayout(FavoritesLayout): """String used to identify this layout in home view dropdown palette.""" def __init__(self): - FavoritesLayout.__init__(self) - self._locked_children = {} + ViewLayout.__init__(self) self._spiral_mode = False - def append(self, icon, locked=False): - FavoritesLayout.append(self, icon, locked) - if locked: - child = self.box.find_box_child(icon) - self._locked_children[child] = (0, 0) - - def remove(self, icon): - child = self.box.find_box_child(icon) - if child in self._locked_children: - del self._locked_children[child] - FavoritesLayout.remove(self, icon) - - def move_icon(self, icon, x, y, locked=False): - FavoritesLayout.move_icon(self, icon, x, y, locked) - if locked: - child = self.box.find_box_child(icon) - self._locked_children[child] = (x, y) - def _calculate_radius_and_icon_size(self, children_count): """ Adjust the ring or spiral radius and icon size as needed. """ self._spiral_mode = False @@ -270,12 +312,10 @@ def _calculate_radius_and_icon_size(self, children_count): return radius, icon_size def _calculate_position(self, radius, icon_size, icon_index, - children_count, sin=math.sin, cos=math.cos): + children_count, width, height, + sin=math.sin, cos=math.cos): """ Calculate an icon position on a circle or a spiral. """ - width, height = self.box.get_allocation() if self._spiral_mode: - min_width_, box_width = self.box.get_width_request() - min_height_, box_height = self.box.get_height_request(box_width) angle, radius = self._calculate_angle_and_radius(icon_index, icon_size) x, y = self._convert_from_polar_to_cartesian(angle, radius, @@ -286,7 +326,7 @@ def _calculate_position(self, radius, icon_size, icon_index, x = radius * cos(angle) + (width - icon_size) / 2 y = radius * sin(angle) + (height - icon_size - \ (style.GRID_CELL_SIZE / 2)) / 2 - return x, y + return int(x), int(y) def _convert_from_polar_to_cartesian(self, angle, radius, icon_size, width, height): @@ -311,49 +351,27 @@ def _calculate_angle_and_radius(self, icon_count, icon_size): radius += (float(icon_spacing) * spiral_spacing / n) return angle, radius - def _get_children_in_ring(self): - children_in_ring = [child for child in self.box.get_layout_children() \ - if child not in self._locked_children] - return children_in_ring - - def do_allocate(self, x, y, width, height, req_width, req_height, - origin_changed): - children_in_ring = self._get_children_in_ring() - if children_in_ring: - radius, icon_size = \ - self._calculate_radius_and_icon_size(len(children_in_ring)) - - for n in range(len(children_in_ring)): - child = children_in_ring[n] - - x, y = self._calculate_position(radius, icon_size, n, - len(children_in_ring)) - - # We need to always get requests to not confuse hippo - min_w_, child_width = child.get_width_request() - min_h_, child_height = child.get_height_request(child_width) + def allocate_children(self, allocation, children): + radius, icon_size = self._calculate_radius_and_icon_size(len(children)) - child.allocate(int(x), int(y), child_width, child_height, - origin_changed) - child.item.props.size = icon_size + children.sort(self.compare_activities) + for n in range(len(children)): + child = children[n] - for child in self._locked_children.keys(): - x, y = self._locked_children[child] - - # We need to always get requests to not confuse hippo - min_w_, child_width = child.get_width_request() - min_h_, child_height = child.get_height_request(child_width) - - if child_width <= 0 or child_height <= 0: - return - - child.allocate(int(x), int(y), child_width, child_height, - origin_changed) + x, y = self._calculate_position(radius, icon_size, n, + len(children), allocation.width, + allocation.height) + child.size_request() + child.set_size(icon_size) + child_allocation = gtk.gdk.Rectangle(allocation.x + x, + allocation.y + y, + icon_size, icon_size) + child.size_allocate(child_allocation) def compare_activities(self, icon_a, icon_b): if hasattr(icon_a, 'installation_time') and \ hasattr(icon_b, 'installation_time'): - return icon_b.installation_time - icon_a.installation_time + return int(icon_b.installation_time - icon_a.installation_time) else: return 0 @@ -420,13 +438,11 @@ def adjust_index(self, i): return i def _calculate_position(self, radius, icon_size, oindex, children_count, - sin=math.sin, cos=math.cos): + width, height, sin=math.sin, cos=math.cos): """Calculate the position of sunflower floret number 'oindex'. If the result is outside the bounding box, use the next index which is inside the bounding box.""" - width, height = self.box.get_allocation() - while True: index = self.adjust_index(oindex) @@ -454,7 +470,7 @@ def _calculate_position(self, radius, icon_size, oindex, children_count, # try again continue - return x, y + return int(x), int(y) class BoxLayout(RingLayout): @@ -476,7 +492,7 @@ def __init__(self): RingLayout.__init__(self) def _calculate_position(self, radius, icon_size, index, children_count, - sin=None, cos=None): + width, height, sin=None, cos=None): # use "orthogonal" versions of cos and sin in order to square the # circle and turn the 'ring view' into a 'box view' @@ -496,8 +512,8 @@ def cos_d(d): sin = lambda r: cos_d(math.degrees(r) - 90) return RingLayout._calculate_position(self, radius, icon_size, index, - children_count, sin=sin, - cos=cos) + children_count, width, height, + sin=sin, cos=cos) class TriangleLayout(RingLayout): @@ -526,7 +542,7 @@ def _calculate_radius_and_icon_size(self, children_count): return max(radius, _MINIMUM_RADIUS + style.MEDIUM_ICON_SIZE), icon_size def _calculate_position(self, radius, icon_size, index, children_count, - sin=math.sin, cos=math.cos): + width, height, sin=math.sin, cos=math.cos): # tweak cos and sin in order to make the 'ring' into an equilateral # triangle. @@ -556,5 +572,5 @@ def sin_d(d): sin = lambda r: sin_d(math.degrees(r)) return RingLayout._calculate_position(self, radius, icon_size, index, - children_count, sin=sin, - cos=cos) + children_count, width, height, + sin=sin, cos=cos) diff --git a/src/jarabe/desktop/favoritesview.py b/src/jarabe/desktop/favoritesview.py index 654f4002b5..35c4053c19 100644 --- a/src/jarabe/desktop/favoritesview.py +++ b/src/jarabe/desktop/favoritesview.py @@ -23,10 +23,9 @@ import gconf import glib import gtk -import hippo from sugar.graphics import style -from sugar.graphics.icon import Icon, CanvasIcon +from sugar.graphics.icon import Icon from sugar.graphics.menuitem import MenuItem from sugar.graphics.alert import Alert from sugar.graphics.xocolor import XoColor @@ -35,9 +34,11 @@ from sugar.datastore import datastore from jarabe.view.palettes import JournalPalette -from jarabe.view.palettes import CurrentActivityPalette, ActivityPalette +from jarabe.view.palettes import CurrentActivityPalette +from jarabe.view.palettes import ActivityPalette from jarabe.view.buddyicon import BuddyIcon from jarabe.view.buddymenu import BuddyMenu +from jarabe.view.eventicon import EventIcon from jarabe.model.buddy import get_owner_instance from jarabe.model import shell from jarabe.model import bundleregistry @@ -46,6 +47,7 @@ from jarabe.desktop import schoolserver from jarabe.desktop.schoolserver import RegisterError from jarabe.desktop import favoriteslayout +from jarabe.desktop.viewcontainer import ViewContainer _logger = logging.getLogger('FavoritesView') @@ -64,169 +66,127 @@ _favorites_settings = None -class FavoritesView(hippo.Canvas): - __gtype_name__ = 'SugarFavoritesView' +class FavoritesBox(gtk.VBox): + __gtype_name__ = 'SugarFavoritesBox' - def __init__(self, **kwargs): - logging.debug('STARTUP: Loading the favorites view') + def __init__(self): + gtk.VBox.__init__(self) - gobject.GObject.__init__(self, **kwargs) + self._view = FavoritesView(self) + self.pack_start(self._view) + self._view.show() - # DND stuff - self._pressed_button = None - self._press_start_x = None - self._press_start_y = None - self._hot_x = None - self._hot_y = None - self._last_clicked_icon = None + self._alert = None - self._box = hippo.CanvasBox() - self._box.props.background_color = style.COLOR_WHITE.get_int() - self.set_root(self._box) + def set_filter(self, query): + self._view.set_filter(query) - self._my_icon = OwnerIcon(style.XLARGE_ICON_SIZE) - self._my_icon.connect('register-activate', self.__register_activate_cb) - self._box.append(self._my_icon) + def set_resume_mode(self, resume_mode): + self._view.set_resume_mode(resume_mode) - self._current_activity = CurrentActivityIcon() - self._box.append(self._current_activity) + def add_alert(self, alert): + if self._alert is not None: + self.remove_alert() + self._alert = alert + self.pack_start(alert, False) + self.reorder_child(alert, 0) - self._layout = None + def remove_alert(self): + self.remove(self._alert) self._alert = None - self._resume_mode = True - # More DND stuff - self.add_events(gtk.gdk.BUTTON_PRESS_MASK | - gtk.gdk.POINTER_MOTION_HINT_MASK) - self.connect('motion-notify-event', self.__motion_notify_event_cb) - self.connect('button-press-event', self.__button_press_event_cb) - self.connect('drag-begin', self.__drag_begin_cb) - self.connect('drag-motion', self.__drag_motion_cb) - self.connect('drag-drop', self.__drag_drop_cb) - self.connect('drag-data-received', self.__drag_data_received_cb) - gobject.idle_add(self.__connect_to_bundle_registry_cb) +class FavoritesView(ViewContainer): + __gtype_name__ = 'SugarFavoritesView' + + def __init__(self, box): + self._box = box + self._layout = None favorites_settings = get_settings() favorites_settings.changed.connect(self.__settings_changed_cb) self._set_layout(favorites_settings.layout) - def set_filter(self, query): - query = query.strip() - for icon in self._box.get_children(): - if icon not in [self._my_icon, self._current_activity]: - activity_name = icon.get_activity_name().lower() - if activity_name.find(query) > -1: - icon.alpha = 1.0 - else: - icon.alpha = 0.33 + owner_icon = OwnerIcon(style.XLARGE_ICON_SIZE) + owner_icon.connect('register-activate', self.__register_activate_cb) - def __settings_changed_cb(self, **kwargs): - favorites_settings = get_settings() - self._set_layout(favorites_settings.layout) + current_activity = CurrentActivityIcon() - def __connect_to_bundle_registry_cb(self): - registry = bundleregistry.get_registry() + ViewContainer.__init__(self, layout=self._layout, + owner_icon=owner_icon, + activity_icon=current_activity) - for info in registry: - if registry.is_bundle_favorite(info.get_bundle_id(), - info.get_activity_version()): - self._add_activity(info) + self.add_events(gtk.gdk.BUTTON_PRESS_MASK | + gtk.gdk.POINTER_MOTION_HINT_MASK) + self.drag_dest_set(0, [], 0) + self.connect('drag-motion', self.__drag_motion_cb) + self.connect('drag-drop', self.__drag_drop_cb) + self.connect('drag-data-received', self.__drag_data_received_cb) - registry.connect('bundle-added', self.__activity_added_cb) - registry.connect('bundle-removed', self.__activity_removed_cb) - registry.connect('bundle-changed', self.__activity_changed_cb) + self._dragging = False + self._pressed_button = None + self._press_start_x = 0 + self._press_start_y = 0 + self._hot_x = None + self._hot_y = None + self._last_clicked_icon = None - def _add_activity(self, activity_info): - if activity_info.get_bundle_id() == 'org.laptop.JournalActivity': - return - icon = ActivityIcon(activity_info) - icon.props.size = style.STANDARD_ICON_SIZE - icon.set_resume_mode(self._resume_mode) - self._box.insert_sorted(icon, 0, self._layout.compare_activities) - self._layout.append(icon) + self._alert = None + self._resume_mode = True - def __activity_added_cb(self, activity_registry, activity_info): - registry = bundleregistry.get_registry() - if registry.is_bundle_favorite(activity_info.get_bundle_id(), - activity_info.get_activity_version()): - self._add_activity(activity_info) + gobject.idle_add(self.__connect_to_bundle_registry_cb) - def _find_activity_icon(self, bundle_id, version): - for icon in self._box.get_children(): - if isinstance(icon, ActivityIcon) and \ - icon.bundle_id == bundle_id and icon.version == version: - return icon - return None + def __settings_changed_cb(self, **kwargs): + favorites_settings = get_settings() + layout_set = self._set_layout(favorites_settings.layout) + if layout_set: + self.set_layout(self._layout) + registry = bundleregistry.get_registry() + for info in registry: + if registry.is_bundle_favorite(info.get_bundle_id(), + info.get_activity_version()): + self._add_activity(info) - def __activity_removed_cb(self, activity_registry, activity_info): - icon = self._find_activity_icon(activity_info.get_bundle_id(), - activity_info.get_activity_version()) - if icon is not None: - self._layout.remove(icon) - self._box.remove(icon) + def _set_layout(self, layout): + if layout not in LAYOUT_MAP: + logging.warn('Unknown favorites layout: %r', layout) + layout = favoriteslayout.RingLayout.key + assert layout in LAYOUT_MAP - def __activity_changed_cb(self, activity_registry, activity_info): - if activity_info.get_bundle_id() == 'org.laptop.JournalActivity': - return - icon = self._find_activity_icon(activity_info.get_bundle_id(), - activity_info.get_activity_version()) - if icon is not None: - self._box.remove(icon) + if type(self._layout) == LAYOUT_MAP[layout]: + return False - registry = bundleregistry.get_registry() - if registry.is_bundle_favorite(activity_info.get_bundle_id(), - activity_info.get_activity_version()): - self._add_activity(activity_info) + self._layout = LAYOUT_MAP[layout]() + return True - def do_size_allocate(self, allocation): - width = allocation.width - height = allocation.height + layout = property(None, _set_layout) - min_w_, my_icon_width = self._my_icon.get_width_request() - min_h_, my_icon_height = self._my_icon.get_height_request( - my_icon_width) - x = (width - my_icon_width) / 2 - y = (height - my_icon_height - style.GRID_CELL_SIZE) / 2 - self._layout.move_icon(self._my_icon, x, y, locked=True) - - min_w_, icon_width = self._current_activity.get_width_request() - min_h_, icon_height = \ - self._current_activity.get_height_request(icon_width) - x = (width - icon_width) / 2 - y = (height - my_icon_height - style.GRID_CELL_SIZE) / 2 + \ - my_icon_height + style.DEFAULT_PADDING - self._layout.move_icon(self._current_activity, x, y, locked=True) - - hippo.Canvas.do_size_allocate(self, allocation) - - # TODO: Dnd methods. This should be merged somehow inside hippo-canvas. - def __button_press_event_cb(self, widget, event): - if event.button == 1 and event.type == gtk.gdk.BUTTON_PRESS: - self._last_clicked_icon = self._get_icon_at_coords(event.x, - event.y) - if self._last_clicked_icon is not None: - self._pressed_button = event.button - self._press_start_x = event.x - self._press_start_y = event.y + def do_add(self, child): + if child != self._owner_icon and child != self._activity_icon: + self._children.append(child) + child.connect('button-press-event', self.__button_press_cb) + child.connect('button-release-event', self.__button_release_cb) + child.connect('motion-notify-event', self.__motion_notify_event_cb) + child.connect('drag-begin', self.__drag_begin_cb) + if child.flags() & gtk.REALIZED: + child.set_parent_window(self.get_parent_window()) + child.set_parent(self) + + def __button_release_cb(self, widget, event): + if self._dragging: + return True + else: + return False + def __button_press_cb(self, widget, event): + if event.button == 1 and event.type == gtk.gdk.BUTTON_PRESS: + self._last_clicked_icon = widget + self._pressed_button = event.button + self._press_start_x = event.x + self._press_start_y = event.y return False - def _get_icon_at_coords(self, x, y): - for icon in self._box.get_children(): - icon_x, icon_y = icon.get_context().translate_to_widget(icon) - icon_width, icon_height = icon.get_allocation() - - if (x >= icon_x) and (x <= icon_x + icon_width) and \ - (y >= icon_y) and (y <= icon_y + icon_height) and \ - isinstance(icon, ActivityIcon): - return icon - return None - def __motion_notify_event_cb(self, widget, event): - if not self._pressed_button: - return False - # if the mouse button is not pressed, no drag should occurr if not event.state & gtk.gdk.BUTTON1_MASK: self._pressed_button = None @@ -242,6 +202,7 @@ def __motion_notify_event_cb(self, widget, event): int(self._press_start_y), int(x), int(y)): + self._dragging = True context_ = widget.drag_begin([_ICON_DND_TARGET], gtk.gdk.ACTION_MOVE, 1, @@ -249,9 +210,7 @@ def __motion_notify_event_cb(self, widget, event): return False def __drag_begin_cb(self, widget, context): - icon_file_name = self._last_clicked_icon.props.file_name - # TODO: we should get the pixbuf from the widget, so it has colors, etc - pixbuf = gtk.gdk.pixbuf_new_from_file(icon_file_name) + pixbuf = gtk.gdk.pixbuf_new_from_file(widget.props.file_name) self._hot_x = pixbuf.props.width / 2 self._hot_y = pixbuf.props.height / 2 @@ -267,9 +226,9 @@ def __drag_motion_cb(self, widget, context, x, y, time): def __drag_drop_cb(self, widget, context, x, y, time): if self._last_clicked_icon is not None: self.drag_get_data(context, _ICON_DND_TARGET[0]) - self._layout.move_icon(self._last_clicked_icon, - x - self._hot_x, y - self._hot_y) + x - self._hot_x, y - self._hot_y, + self.get_allocation()) self._pressed_button = None self._press_start_x = None @@ -277,6 +236,7 @@ def __drag_drop_cb(self, widget, context, x, y, time): self._hot_x = None self._hot_y = None self._last_clicked_icon = None + self._dragging = False return True else: @@ -286,49 +246,68 @@ def __drag_data_received_cb(self, widget, context, x, y, selection_data, info, time): context.drop_finish(success=True, time=time) - def _set_layout(self, layout): - if layout not in LAYOUT_MAP: - logging.warn('Unknown favorites layout: %r', layout) - layout = favoriteslayout.RingLayout.key - assert layout in LAYOUT_MAP + def __connect_to_bundle_registry_cb(self): + registry = bundleregistry.get_registry() - if type(self._layout) == LAYOUT_MAP[layout]: - return + for info in registry: + if registry.is_bundle_favorite(info.get_bundle_id(), + info.get_activity_version()): + self._add_activity(info) - self._layout = LAYOUT_MAP[layout]() - self._box.set_layout(self._layout) + registry.connect('bundle-added', self.__activity_added_cb) + registry.connect('bundle-removed', self.__activity_removed_cb) + registry.connect('bundle-changed', self.__activity_changed_cb) - #TODO: compatibility hack while sort() gets added to the hippo python - # bindings - if hasattr(self._box, 'sort'): - self._box.sort(self._layout.compare_activities) + def _add_activity(self, activity_info): + if activity_info.get_bundle_id() == 'org.laptop.JournalActivity': + return + icon = ActivityIcon(activity_info) + icon.props.pixel_size = style.STANDARD_ICON_SIZE + #icon.set_resume_mode(self._resume_mode) + self.add(icon) + icon.show() - for icon in self._box.get_children(): - if icon not in [self._my_icon, self._current_activity]: - self._layout.append(icon) + def __activity_added_cb(self, activity_registry, activity_info): + registry = bundleregistry.get_registry() + if registry.is_bundle_favorite(activity_info.get_bundle_id(), + activity_info.get_activity_version()): + self._add_activity(activity_info) - self._layout.append(self._my_icon, locked=True) - self._layout.append(self._current_activity, locked=True) + def __activity_removed_cb(self, activity_registry, activity_info): + icon = self._find_activity_icon(activity_info.get_bundle_id(), + activity_info.get_activity_version()) + if icon is not None: + self.remove(icon) - if self._layout.allow_dnd(): - self.drag_source_set(0, [], 0) - self.drag_dest_set(0, [], 0) - else: - self.drag_source_unset() - self.drag_dest_unset() + def _find_activity_icon(self, bundle_id, version): + for icon in self.get_children(): + if isinstance(icon, ActivityIcon) and \ + icon.bundle_id == bundle_id and icon.version == version: + return icon + return None - layout = property(None, _set_layout) + def __activity_changed_cb(self, activity_registry, activity_info): + if activity_info.get_bundle_id() == 'org.laptop.JournalActivity': + return + icon = self._find_activity_icon(activity_info.get_bundle_id(), + activity_info.get_activity_version()) + if icon is not None: + self.remove(icon) - def add_alert(self, alert): - if self._alert is not None: - self.remove_alert() - alert.set_size_request(gtk.gdk.screen_width(), -1) - self._alert = hippo.CanvasWidget(widget=alert) - self._box.append(self._alert, hippo.PACK_FIXED) + registry = bundleregistry.get_registry() + if registry.is_bundle_favorite(activity_info.get_bundle_id(), + activity_info.get_activity_version()): + self._add_activity(activity_info) - def remove_alert(self): - self._box.remove(self._alert) - self._alert = None + def set_filter(self, query): + query = query.strip() + for icon in self.get_children(): + if icon not in [self._owner_icon, self._activity_icon]: + activity_name = icon.get_activity_name().lower() + if activity_name.find(query) > -1: + icon.alpha = 1.0 + else: + icon.alpha = 0.33 def __register_activate_cb(self, icon): alert = Alert() @@ -341,41 +320,43 @@ def __register_activate_cb(self, icon): alert.props.title = _('Registration Successful') alert.props.msg = _('You are now registered ' \ 'with your school server.') - self._my_icon.set_registered() + self._owner_icon.set_registered() ok_icon = Icon(icon_name='dialog-ok') alert.add_button(gtk.RESPONSE_OK, _('Ok'), ok_icon) - self.add_alert(alert) + self._box.add_alert(alert) alert.connect('response', self.__register_alert_response_cb) def __register_alert_response_cb(self, alert, response_id): - self.remove_alert() + self._box.remove_alert() def set_resume_mode(self, resume_mode): self._resume_mode = resume_mode - for icon in self._box.get_children(): + for icon in self.get_children(): if hasattr(icon, 'set_resume_mode'): icon.set_resume_mode(self._resume_mode) -class ActivityIcon(CanvasIcon): +class ActivityIcon(EventIcon): __gtype_name__ = 'SugarFavoriteActivityIcon' _BORDER_WIDTH = style.zoom(3) _MAX_RESUME_ENTRIES = 5 def __init__(self, activity_info): - CanvasIcon.__init__(self, cache=True, - file_name=activity_info.get_icon()) + EventIcon.__init__(self, cache=True, + file_name=activity_info.get_icon()) self._activity_info = activity_info self._journal_entries = [] self._hovering = False self._resume_mode = True - self.connect('hovering-changed', self.__hovering_changed_event_cb) - self.connect('button-release-event', self.__button_release_event_cb) + self.connect('enter-notify-event', self.__enter_notify_event_cb) + self.connect('leave-notify-event', self.__leave_notify_event_cb) + self.connect_after('button-release-event', + self.__button_release_event_cb) datastore.updated.connect(self.__datastore_listener_updated_cb) datastore.deleted.connect(self.__datastore_listener_deleted_cb) @@ -443,45 +424,47 @@ def __palette_activate_cb(self, palette): def __palette_entry_activate_cb(self, palette, metadata): self._resume(metadata) - def __hovering_changed_event_cb(self, icon, hovering): - self._hovering = hovering - self.emit_paint_needed(0, 0, -1, -1) + def __enter_notify_event_cb(self, icon, event): + self._hovering = True + self.queue_draw() + + def __leave_notify_event_cb(self, icon, event): + self._hovering = False + self.queue_draw() + + def do_expose_event(self, event): + EventIcon.do_expose_event(self, event) - def do_paint_above_children(self, cr, damaged_box): if not self._hovering: return - width, height = self.get_allocation() + allocation = self.get_allocation() + width = allocation.width + height = allocation.height - x = ActivityIcon._BORDER_WIDTH / 2.0 - y = ActivityIcon._BORDER_WIDTH / 2.0 + x = allocation.x + ActivityIcon._BORDER_WIDTH / 2.0 + y = allocation.y + ActivityIcon._BORDER_WIDTH / 2.0 width -= ActivityIcon._BORDER_WIDTH height -= ActivityIcon._BORDER_WIDTH radius = width / 10.0 + cr = self.window.cairo_create() cr.move_to(x + radius, y) cr.arc(x + width - radius, y + radius, radius, math.pi * 1.5, math.pi * 2.0) - cr.arc(x + width - radius, x + height - radius, radius, 0, + cr.arc(x + width - radius, y + height - radius, radius, 0, math.pi * 0.5) cr.arc(x + radius, y + height - radius, radius, math.pi * 0.5, math.pi) cr.arc(x + radius, y + radius, radius, math.pi, math.pi * 1.5) - color = style.COLOR_SELECTION_GREY.get_int() - hippo.cairo_set_source_rgba32(cr, color) + cr.set_source_color(style.COLOR_SELECTION_GREY.get_gdk_color()) cr.set_line_width(ActivityIcon._BORDER_WIDTH) cr.stroke() - def do_get_content_height_request(self, for_width): - height, height = CanvasIcon.do_get_content_height_request(self, - for_width) - height += ActivityIcon._BORDER_WIDTH * 2 - return height, height - - def do_get_content_width_request(self): - width, width = CanvasIcon.do_get_content_width_request(self) - width += ActivityIcon._BORDER_WIDTH * 2 - return width, width + def do_size_request(self, req): + EventIcon.do_size_request(self, req) + req.height += ActivityIcon._BORDER_WIDTH * 2 + req.width += ActivityIcon._BORDER_WIDTH * 2 def __button_release_event_cb(self, icon, event): self._activate() @@ -575,9 +558,10 @@ def __resume_entry_cb(self, menu_item, entry): self.emit('entry-activate', entry) -class CurrentActivityIcon(CanvasIcon, hippo.CanvasItem): +class CurrentActivityIcon(EventIcon): def __init__(self): - CanvasIcon.__init__(self, cache=True) + EventIcon.__init__(self, icon_name='activity-journal', + pixel_size=style.STANDARD_ICON_SIZE, cache=True) self._home_model = shell.get_model() self._home_activity = self._home_model.get_active_activity() @@ -587,7 +571,8 @@ def __init__(self): self._home_model.connect('active-activity-changed', self.__active_activity_changed_cb) - self.connect('button-release-event', self.__button_release_event_cb) + self.connect_after('button-release-event', + self.__button_release_event_cb) def __button_release_event_cb(self, icon, event): window = self._home_model.get_active_activity().get_window() @@ -596,7 +581,7 @@ def __button_release_event_cb(self, icon, event): def _update(self): self.props.file_name = self._home_activity.get_icon_path() self.props.xo_color = self._home_activity.get_icon_color() - self.props.size = style.STANDARD_ICON_SIZE + self.props.pixel_size = style.STANDARD_ICON_SIZE if self.palette is not None: self.palette.destroy() @@ -623,7 +608,7 @@ class OwnerIcon(BuddyIcon): } def __init__(self, size): - BuddyIcon.__init__(self, buddy=get_owner_instance(), size=size) + BuddyIcon.__init__(self, buddy=get_owner_instance(), pixel_size=size) self.palette_invoker.cache_palette = True @@ -652,9 +637,6 @@ def create_palette(self): return palette - def get_toplevel(self): - return hippo.get_canvas_for_item(self).get_toplevel() - def __register_activate_cb(self, menuitem): self.emit('register-activate') diff --git a/src/jarabe/desktop/friendview.py b/src/jarabe/desktop/friendview.py index 8dab35f519..01c2b71202 100644 --- a/src/jarabe/desktop/friendview.py +++ b/src/jarabe/desktop/friendview.py @@ -15,27 +15,30 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -import hippo +import gtk -from sugar.graphics.icon import CanvasIcon from sugar.graphics import style from jarabe.view.buddyicon import BuddyIcon +from jarabe.view.eventicon import EventIcon from jarabe.model import bundleregistry -class FriendView(hippo.CanvasBox): +class FriendView(gtk.VBox): def __init__(self, buddy, **kwargs): - hippo.CanvasBox.__init__(self, **kwargs) + gtk.VBox.__init__(self) + + # round icon sizes to an even number so that it can be accurately + # centered in a larger bounding box also of even dimensions + size = style.LARGE_ICON_SIZE & ~1 self._buddy = buddy self._buddy_icon = BuddyIcon(buddy) - self._buddy_icon.props.size = style.LARGE_ICON_SIZE - self.append(self._buddy_icon) - - self._activity_icon = CanvasIcon(size=style.LARGE_ICON_SIZE) - self._activity_icon_visible = False + self._buddy_icon.props.pixel_size = size + self.add(self._buddy_icon) + self._buddy_icon.show() + self._activity_icon = EventIcon(pixel_size=size) self._update_activity() self._buddy.connect('notify::current-activity', @@ -51,9 +54,9 @@ def _get_new_icon_name(self, ps_activity): return None def _remove_activity_icon(self): - if self._activity_icon_visible: + if self._activity_icon.get_visible(): + self._activity_icon.hide() self.remove(self._activity_icon) - self._activity_icon_visible = False def __buddy_notify_current_activity_cb(self, buddy, pspec): self._update_activity() @@ -70,9 +73,9 @@ def _update_activity(self): if name: self._activity_icon.props.file_name = name self._activity_icon.props.xo_color = self._buddy.props.color - if not self._activity_icon_visible: - self.append(self._activity_icon, hippo.PACK_EXPAND) - self._activity_icon_visible = True + if not self._activity_icon.get_visible(): + self.add(self._activity_icon) + self._activity_icon.show() else: self._remove_activity_icon() diff --git a/src/jarabe/desktop/grid.py b/src/jarabe/desktop/grid.py index eab403335c..65b33b230a 100644 --- a/src/jarabe/desktop/grid.py +++ b/src/jarabe/desktop/grid.py @@ -75,6 +75,9 @@ def add(self, child, width, height, x=None, y=None, locked=False): if weight > 0: self._detect_collisions(child) + def is_in_grid(self, child): + return child in self._children + def remove(self, child): self._children.remove(child) self.remove_weight(self._child_rects[child]) diff --git a/src/jarabe/desktop/groupbox.py b/src/jarabe/desktop/groupbox.py index ed8f8ae79a..4fcd6c22ba 100644 --- a/src/jarabe/desktop/groupbox.py +++ b/src/jarabe/desktop/groupbox.py @@ -16,47 +16,40 @@ import logging -import gobject -import hippo import gconf from sugar.graphics import style -from sugar.graphics.icon import CanvasIcon from sugar.graphics.xocolor import XoColor from jarabe.view.buddymenu import BuddyMenu +from jarabe.view.eventicon import EventIcon from jarabe.model.buddy import get_owner_instance from jarabe.model import friends from jarabe.desktop.friendview import FriendView -from jarabe.desktop.spreadlayout import SpreadLayout +from jarabe.desktop.viewcontainer import ViewContainer +from jarabe.desktop.favoriteslayout import SpreadLayout -class GroupBox(hippo.Canvas): +class GroupBox(ViewContainer): __gtype_name__ = 'SugarGroupBox' def __init__(self): logging.debug('STARTUP: Loading the group view') - gobject.GObject.__init__(self) - - self._box = hippo.CanvasBox() - self._box.props.background_color = style.COLOR_WHITE.get_int() - self.set_root(self._box) - - self._friends = {} - - self._layout = SpreadLayout() - self._box.set_layout(self._layout) + layout = SpreadLayout() client = gconf.client_get_default() color = XoColor(client.get_string('/desktop/sugar/user/color')) + owner_icon = EventIcon(icon_name='computer-xo', cache=True, + xo_color=color) + # Round off icon size to an even number to ensure that the icon + # is placed evenly in the grid + owner_icon.props.pixel_size = style.LARGE_ICON_SIZE & ~1 + owner_icon.set_palette(BuddyMenu(get_owner_instance())) - self._owner_icon = CanvasIcon(icon_name='computer-xo', cache=True, - xo_color=color) - self._owner_icon.props.size = style.LARGE_ICON_SIZE + ViewContainer.__init__(self, layout, owner_icon) - self._owner_icon.set_palette(BuddyMenu(get_owner_instance())) - self._layout.add(self._owner_icon) + self._friends = {} friends_model = friends.get_model() @@ -68,27 +61,15 @@ def __init__(self): def add_friend(self, buddy_info): icon = FriendView(buddy_info) - self._layout.add(icon) - + self.add(icon) self._friends[buddy_info.get_key()] = icon + icon.show() def _friend_added_cb(self, data_model, buddy_info): self.add_friend(buddy_info) def _friend_removed_cb(self, data_model, key): icon = self._friends[key] - self._layout.remove(icon) + self.remove(icon) del self._friends[key] icon.destroy() - - def do_size_allocate(self, allocation): - width = allocation.width - height = allocation.height - - min_w_, icon_width = self._owner_icon.get_width_request() - min_h_, icon_height = self._owner_icon.get_height_request(icon_width) - x = (width - icon_width) / 2 - y = (height - icon_height) / 2 - self._layout.move(self._owner_icon, x, y) - - hippo.Canvas.do_size_allocate(self, allocation) diff --git a/src/jarabe/desktop/homebox.py b/src/jarabe/desktop/homebox.py index 2ee6ae7d30..33c69658d7 100644 --- a/src/jarabe/desktop/homebox.py +++ b/src/jarabe/desktop/homebox.py @@ -45,7 +45,7 @@ def __init__(self): gobject.GObject.__init__(self) - self._favorites_view = favoritesview.FavoritesView() + self._favorites_box = favoritesview.FavoritesBox() self._list_view = ActivitiesList() self._toolbar = HomeToolbar() @@ -78,14 +78,14 @@ def show_software_updates_alert(self): if self._list_view in self.get_children(): self._list_view.add_alert(alert) else: - self._favorites_view.add_alert(alert) + self._favorites_box.add_alert(alert) alert.connect('response', self.__software_update_response_cb) def __software_update_response_cb(self, alert, response_id): if self._list_view in self.get_children(): self._list_view.remove_alert() else: - self._favorites_view.remove_alert() + self._favorites_box.remove_alert() if response_id != gtk.RESPONSE_REJECT: update_trigger_file = os.path.expanduser('~/.sugar-update') @@ -106,7 +106,7 @@ def __software_update_response_cb(self, alert, response_id): def __toolbar_query_changed_cb(self, toolbar, query): self._query = query.lower() self._list_view.set_filter(self._query) - self._favorites_view.set_filter(self._query) + self._favorites_box.set_filter(self._query) def __toolbar_view_changed_cb(self, toolbar, view): self._set_view(view) @@ -116,12 +116,12 @@ def _set_view(self, view): if self._list_view in self.get_children(): self.remove(self._list_view) - if self._favorites_view not in self.get_children(): - self.add(self._favorites_view) - self._favorites_view.show() + if self._favorites_box not in self.get_children(): + self.add(self._favorites_box) + self._favorites_box.show() elif view == _LIST_VIEW: - if self._favorites_view in self.get_children(): - self.remove(self._favorites_view) + if self._favorites_box in self.get_children(): + self.remove(self._favorites_box) if self._list_view not in self.get_children(): self.add(self._list_view) @@ -146,10 +146,10 @@ def focus_search_entry(self): self._toolbar.search_entry.grab_focus() def set_resume_mode(self, resume_mode): - self._favorites_view.set_resume_mode(resume_mode) + self._favorites_box.set_resume_mode(resume_mode) if resume_mode and self._query != '': self._list_view.set_filter(self._query) - self._favorites_view.set_filter(self._query) + self._favorites_box.set_filter(self._query) class HomeToolbar(gtk.Toolbar): diff --git a/src/jarabe/desktop/homewindow.py b/src/jarabe/desktop/homewindow.py index 07deff7937..a5536c0e4e 100644 --- a/src/jarabe/desktop/homewindow.py +++ b/src/jarabe/desktop/homewindow.py @@ -57,6 +57,8 @@ def __init__(self): self.realize() self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DESKTOP) + self.modify_bg(gtk.STATE_NORMAL, + style.COLOR_WHITE.get_gdk_color()) self.add_events(gtk.gdk.VISIBILITY_NOTIFY_MASK) self.connect('visibility-notify-event', diff --git a/src/jarabe/desktop/meshbox.py b/src/jarabe/desktop/meshbox.py index 20dc4138d2..1de37796df 100644 --- a/src/jarabe/desktop/meshbox.py +++ b/src/jarabe/desktop/meshbox.py @@ -21,26 +21,29 @@ import logging import dbus -import hippo import glib import gobject import gtk import gconf -from sugar.graphics.icon import CanvasIcon, Icon +from sugar.graphics.icon import Icon from sugar.graphics import style from sugar.graphics import palette from sugar.graphics import iconentry from sugar.graphics.menuitem import MenuItem +from sugar.graphics.xocolor import XoColor +from jarabe.desktop.snowflakelayout import SnowflakeLayout from jarabe.model import neighborhood from jarabe.model.buddy import get_owner_instance from jarabe.view.buddyicon import BuddyIcon -from jarabe.desktop.snowflakelayout import SnowflakeLayout -from jarabe.desktop.spreadlayout import SpreadLayout +from jarabe.view.buddymenu import BuddyMenu +from jarabe.view.eventicon import EventIcon from jarabe.desktop.networkviews import WirelessNetworkView from jarabe.desktop.networkviews import OlpcMeshView from jarabe.desktop.networkviews import SugarAdhocView +from jarabe.desktop.viewcontainer import ViewContainer +from jarabe.desktop.favoriteslayout import SpreadLayout from jarabe.model import network from jarabe.model.network import AccessPoint from jarabe.model.olpcmesh import OlpcMeshManager @@ -55,14 +58,13 @@ _FILTERED_ALPHA = 0.33 -class _ActivityIcon(CanvasIcon): +class _ActivityIcon(EventIcon): def __init__(self, model, file_name, xo_color, size=style.STANDARD_ICON_SIZE): - CanvasIcon.__init__(self, file_name=file_name, - xo_color=xo_color, - size=size) + EventIcon.__init__(self, file_name=file_name, + xo_color=xo_color, pixel_size=size) self._model = model - self.connect('activated', self._clicked_cb) + self.connect('button-release-event', self._button_release_cb) def create_palette(self): primary_text = glib.markup_escape_text(self._model.bundle.get_name()) @@ -91,15 +93,18 @@ def create_palette(self): return p + def _button_release_cb(self, widget, event): + return self._clicked_cb(item=None) + def _clicked_cb(self, item): bundle = self._model.get_bundle() misc.launch(bundle, activity_id=self._model.activity_id, color=self._model.get_color()) -class ActivityView(hippo.CanvasBox): +class ActivityView(SnowflakeLayout): def __init__(self, model): - hippo.CanvasBox.__init__(self) + SnowflakeLayout.__init__(self) self._model = model self._model.connect('current-buddy-added', self.__buddy_added_cb) @@ -107,11 +112,9 @@ def __init__(self, model): self._icons = {} - self._layout = SnowflakeLayout() - self.set_layout(self._layout) - self._icon = self._create_icon() - self._layout.add(self._icon, center=True) + self._icon.show() + self.add_icon(self._icon, center=True) self._icon.palette_invoker.cache_palette = False @@ -134,11 +137,13 @@ def __buddy_added_cb(self, activity, buddy): def _add_buddy(self, buddy): icon = BuddyIcon(buddy, style.STANDARD_ICON_SIZE) self._icons[buddy.props.key] = icon - self._layout.add(icon) + self.add_icon(icon) + icon.show() def __buddy_removed_cb(self, activity, buddy): icon = self._icons[buddy.props.key] del self._icons[buddy.props.key] + self.remove(icon) icon.destroy() def set_filter(self, query): @@ -401,13 +406,32 @@ def __properties_changed_cb(self, properties): self._box.add_adhoc_networks(device) +class MeshContainer(ViewContainer): + __gtype_name__ = 'SugarMeshContainer' + + def __init__(self): + + layout = SpreadLayout() + + client = gconf.client_get_default() + color = XoColor(client.get_string('/desktop/sugar/user/color')) + owner_icon = EventIcon(icon_name='computer-xo', cache=True, + xo_color=color) + # Round off icon size to an even number to ensure that the icon + # is placed evenly in the grid + owner_icon.props.pixel_size = style.STANDARD_ICON_SIZE & ~1 + owner_icon.set_palette(BuddyMenu(get_owner_instance())) + + ViewContainer.__init__(self, layout, owner_icon) + + class MeshBox(gtk.VBox): __gtype_name__ = 'SugarMeshBox' def __init__(self): logging.debug('STARTUP: Loading the mesh view') - gobject.GObject.__init__(self) + gtk.VBox.__init__(self) self.wireless_networks = {} self._adhoc_manager = None @@ -420,23 +444,15 @@ def __init__(self): self._buddy_to_activity = {} self._suspended = True self._query = '' - self._owner_icon = None self._toolbar = MeshToolbar() self._toolbar.connect('query-changed', self._toolbar_query_changed_cb) self.pack_start(self._toolbar, expand=False) self._toolbar.show() - canvas = hippo.Canvas() - self.add(canvas) - canvas.show() - - self._layout_box = hippo.CanvasBox( \ - background_color=style.COLOR_WHITE.get_int()) - canvas.set_root(self._layout_box) - - self._layout = SpreadLayout() - self._layout_box.set_layout(self._layout) + self._mesh_container = MeshContainer() + self.add(self._mesh_container) + self._mesh_container.show() for buddy_model in self._model.get_buddies(): self._add_buddy(buddy_model) @@ -453,18 +469,6 @@ def __init__(self): netmgr_observer = NetworkManagerObserver(self) netmgr_observer.listen() - def do_size_allocate(self, allocation): - width = allocation.width - height = allocation.height - - min_w_, icon_width = self._owner_icon.get_width_request() - min_h_, icon_height = self._owner_icon.get_height_request(icon_width) - x = (width - icon_width) / 2 - y = (height - icon_height) / 2 - style.GRID_CELL_SIZE - self._layout.move(self._owner_icon, x, y) - - gtk.VBox.do_size_allocate(self, allocation) - def _buddy_added_cb(self, model, buddy_model): self._add_buddy(buddy_model) @@ -482,10 +486,11 @@ def _add_buddy(self, buddy_model): self.__buddy_notify_current_activity_cb) if buddy_model.props.current_activity is not None: return - icon = BuddyIcon(buddy_model) if buddy_model.is_owner(): - self._owner_icon = icon - self._layout.add(icon) + return + icon = BuddyIcon(buddy_model) + self._mesh_container.add(icon) + icon.show() if hasattr(icon, 'set_filter'): icon.set_filter(self._query) @@ -495,9 +500,8 @@ def _add_buddy(self, buddy_model): def _remove_buddy(self, buddy_model): logging.debug('MeshBox._remove_buddy') icon = self._buddies[buddy_model.props.key] - self._layout.remove(icon) + self._mesh_container.remove(icon) del self._buddies[buddy_model.props.key] - icon.destroy() def __buddy_notify_current_activity_cb(self, buddy_model, pspec): logging.debug('MeshBox.__buddy_notify_current_activity_cb %s', @@ -510,7 +514,8 @@ def __buddy_notify_current_activity_cb(self, buddy_model, pspec): def _add_activity(self, activity_model): icon = ActivityView(activity_model) - self._layout.add(icon) + self._mesh_container.add(icon) + icon.show() if hasattr(icon, 'set_filter'): icon.set_filter(self._query) @@ -519,9 +524,8 @@ def _add_activity(self, activity_model): def _remove_activity(self, activity_model): icon = self._activities[activity_model.activity_id] - self._layout.remove(icon) + self._mesh_container.remove(icon) del self._activities[activity_model.activity_id] - icon.destroy() # add AP to its corresponding network icon on the desktop, # creating one if it doesn't already exist @@ -533,7 +537,8 @@ def _add_ap_to_network(self, ap): # this is a new network icon = WirelessNetworkView(ap) self.wireless_networks[hash_value] = icon - self._layout.add(icon) + self._mesh_container.add(icon) + icon.show() if hasattr(icon, 'set_filter'): icon.set_filter(self._query) @@ -541,7 +546,7 @@ def _remove_net_if_empty(self, net, hash_value): # remove a network if it has no APs left if net.num_aps() == 0: net.disconnect() - self._layout.remove(net) + self._mesh_container.remove(net) del self.wireless_networks[hash_value] def _ap_props_changed_cb(self, ap, old_hash_value): @@ -619,18 +624,20 @@ def add_adhoc_networks(self, device): def remove_adhoc_networks(self): for icon in self._adhoc_networks: - self._layout.remove(icon) + self._mesh_container.remove(icon) self._adhoc_networks = [] self._adhoc_manager.stop_listening() def _add_adhoc_network_icon(self, channel): icon = SugarAdhocView(channel) - self._layout.add(icon) + self._mesh_container.add(icon) + icon.show() self._adhoc_networks.append(icon) def _add_olpc_mesh_icon(self, mesh_mgr, channel): icon = OlpcMeshView(mesh_mgr, channel) - self._layout.add(icon) + self._mesh_container.add(icon) + icon.show() self._mesh.append(icon) def enable_olpc_mesh(self, mesh_device): @@ -648,13 +655,13 @@ def enable_olpc_mesh(self, mesh_device): logging.debug('removing OLPC mesh IBSS') net.remove_all_aps() net.disconnect() - self._layout.remove(net) + self._mesh_container.remove(net) del self.wireless_networks[hash_value] def disable_olpc_mesh(self, mesh_device): for icon in self._mesh: icon.disconnect() - self._layout.remove(icon) + self._mesh_container.remove(icon) self._mesh = [] def suspend(self): @@ -671,7 +678,7 @@ def resume(self): def _toolbar_query_changed_cb(self, toolbar, query): self._query = query.lower() - for icon in self._layout_box.get_children(): + for icon in self._mesh_container.get_children(): if hasattr(icon, 'set_filter'): icon.set_filter(self._query) diff --git a/src/jarabe/desktop/networkviews.py b/src/jarabe/desktop/networkviews.py index f42bfed839..d2531bf567 100644 --- a/src/jarabe/desktop/networkviews.py +++ b/src/jarabe/desktop/networkviews.py @@ -33,7 +33,7 @@ from sugar.util import unique_id from sugar import profile -from jarabe.view.pulsingicon import CanvasPulsingIcon +from jarabe.view.pulsingicon import EventPulsingIcon from jarabe.desktop import keydialog from jarabe.model import network from jarabe.model.network import Settings @@ -48,10 +48,10 @@ _FILTERED_ALPHA = 0.33 -class WirelessNetworkView(CanvasPulsingIcon): +class WirelessNetworkView(EventPulsingIcon): def __init__(self, initial_ap): - CanvasPulsingIcon.__init__(self, size=style.STANDARD_ICON_SIZE, - cache=True) + EventPulsingIcon.__init__(self, pixel_size=style.STANDARD_ICON_SIZE, + cache=True) self._bus = dbus.SystemBus() self._access_points = {initial_ap.model.object_path: initial_ap} self._active_ap = None @@ -255,9 +255,9 @@ def _update_color(self): self.props.base_color = self._color if self._filtered: self.props.pulsing = False - self.alpha = _FILTERED_ALPHA + self.props.alpha = _FILTERED_ALPHA else: - self.alpha = 1.0 + self.props.alpha = 1.0 def _disconnect_activate_cb(self, item): ap_paths = self._access_points.keys() @@ -436,7 +436,7 @@ def disconnect(self): dbus_interface=network.NM_WIRELESS_IFACE) -class SugarAdhocView(CanvasPulsingIcon): +class SugarAdhocView(EventPulsingIcon): """To mimic the mesh behavior on devices where mesh hardware is not available we support the creation of an Ad-hoc network on three channels 1, 6, 11. This is the class for an icon @@ -448,9 +448,10 @@ class SugarAdhocView(CanvasPulsingIcon): _NAME = 'Ad-hoc Network ' def __init__(self, channel): - CanvasPulsingIcon.__init__(self, - icon_name=self._ICON_NAME + str(channel), - size=style.STANDARD_ICON_SIZE, cache=True) + EventPulsingIcon.__init__(self, + icon_name=self._ICON_NAME + str(channel), + pixel_size=style.STANDARD_ICON_SIZE, + cache=True) self._bus = dbus.SystemBus() self._channel = channel self._disconnect_item = None @@ -572,10 +573,11 @@ def set_filter(self, query): self._update_color() -class OlpcMeshView(CanvasPulsingIcon): +class OlpcMeshView(EventPulsingIcon): def __init__(self, mesh_mgr, channel): - CanvasPulsingIcon.__init__(self, icon_name=_OLPC_MESH_ICON_NAME, - size=style.STANDARD_ICON_SIZE, cache=True) + EventPulsingIcon.__init__(self, icon_name=_OLPC_MESH_ICON_NAME, + pixel_size=style.STANDARD_ICON_SIZE, + cache=True) self._bus = dbus.SystemBus() self._channel = channel self._mesh_mgr = mesh_mgr diff --git a/src/jarabe/desktop/snowflakelayout.py b/src/jarabe/desktop/snowflakelayout.py index e4963ba9f8..25cae76586 100644 --- a/src/jarabe/desktop/snowflakelayout.py +++ b/src/jarabe/desktop/snowflakelayout.py @@ -16,8 +16,7 @@ import math -import gobject -import hippo +import gtk from sugar.graphics import style @@ -26,54 +25,71 @@ _CHILDREN_FACTOR = style.zoom(3) -class SnowflakeLayout(gobject.GObject, hippo.CanvasLayout): +class SnowflakeLayout(gtk.Container): __gtype_name__ = 'SugarSnowflakeLayout' def __init__(self): - gobject.GObject.__init__(self) + gtk.Container.__init__(self) + self.set_has_window(False) self._nflakes = 0 - self._box = None - - def add(self, child, center=False): + self._children = {} + + def do_realize(self): + # FIXME what is this for? + self.set_flags(gtk.REALIZED) + self.set_window(self.get_parent_window()) + self.style.attach(self.window) + for child in self._children.keys(): + child.set_parent_window(self.get_parent_window()) + self.queue_resize() + + def do_add(self, child): + if child.flags() & gtk.REALIZED: + child.set_parent_window(self.get_parent_window()) + child.set_parent(self) + + def do_forall(self, include_internals, callback, data): + for child in self._children.keys(): + callback(child, data) + + def do_remove(self, child): + child.unparent() + + def add_icon(self, child, center=False): if not center: self._nflakes += 1 - self._box.append(child) - - box_child = self._box.find_box_child(child) - box_child.is_center = center + self._children[child] = center + self.add(child) def remove(self, child): - box_child = self._box.find_box_child(child) - if not box_child.is_center: - self._nflakes -= 1 - - self._box.remove(child) + if not child in self._children: + return - def do_set_box(self, box): - self._box = box + if not self._children[child]: # not centered + self._nflakes -= 1 - def do_get_height_request(self, for_width): - size = self._calculate_size() - return (size, size) + del self._children[child] + self.remove(child) - def do_get_width_request(self): + def do_size_request(self, requisition): size = self._calculate_size() - return (size, size) + requisition.width = size + requisition.height = size - def do_allocate(self, x, y, width, height, - req_width, req_height, origin_changed): + def do_size_allocate(self, allocation): r = self._get_radius() index = 0 - for child in self._box.get_layout_children(): - min_width, child_width = child.get_width_request() - min_height, child_height = child.get_height_request(child_width) + for child, centered in self._children.items(): + child_width, child_height = child.size_request() + rect = gtk.gdk.Rectangle(0, 0, child_width, child_height) - if child.is_center: - child.allocate(x + (width - child_width) / 2, - y + (height - child_height) / 2, - child_width, child_height, origin_changed) + width = allocation.width - child_width + height = allocation.height - child_height + if centered: + rect.x = allocation.x + width / 2 + rect.y = allocation.y + height / 2 else: angle = 2 * math.pi * index / self._nflakes @@ -83,29 +99,26 @@ def do_allocate(self, x, y, width, height, dx = math.cos(angle) * r dy = math.sin(angle) * r - child_x = int(x + (width - child_width) / 2 + dx) - child_y = int(y + (height - child_height) / 2 + dy) - - child.allocate(child_x, child_y, child_width, - child_height, origin_changed) + rect.x = int(allocation.x + width / 2 + dx) + rect.y = int(allocation.y + height / 2 + dy) index += 1 + child.size_allocate(rect) + def _get_radius(self): radius = int(_BASE_DISTANCE + _CHILDREN_FACTOR * self._nflakes) - for child in self._box.get_layout_children(): - if child.is_center: - [min_w, child_w] = child.get_width_request() - [min_h, child_h] = child.get_height_request(child_w) + for child, centered in self._children.items(): + if centered: + child_w, child_h = child.size_request() radius += max(child_w, child_h) / 2 return radius def _calculate_size(self): thickness = 0 - for child in self._box.get_layout_children(): - [min_width, child_width] = child.get_width_request() - [min_height, child_height] = child.get_height_request(child_width) - thickness = max(thickness, max(child_width, child_height)) + for child in self._children.keys(): + width, height = child.size_request() + thickness = max(thickness, max(width, height)) return self._get_radius() * 2 + thickness diff --git a/src/jarabe/desktop/spreadlayout.py b/src/jarabe/desktop/spreadlayout.py deleted file mode 100644 index b5c623e492..0000000000 --- a/src/jarabe/desktop/spreadlayout.py +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright (C) 2007 Red Hat, Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -import math - -import hippo -import gobject -import gtk - -from sugar.graphics import style - -from jarabe.desktop.grid import Grid - - -_CELL_SIZE = 4.0 - - -class SpreadLayout(gobject.GObject, hippo.CanvasLayout): - __gtype_name__ = 'SugarSpreadLayout' - - def __init__(self): - gobject.GObject.__init__(self) - self._box = None - - min_width, width = self.do_get_width_request() - min_height, height = self.do_get_height_request(width) - - self._grid = Grid(int(width / _CELL_SIZE), int(height / _CELL_SIZE)) - self._grid.connect('child-changed', self._grid_child_changed_cb) - - def add(self, child): - self._box.append(child) - - width, height = self._get_child_grid_size(child) - self._grid.add(child, width, height) - - def remove(self, child): - self._grid.remove(child) - self._box.remove(child) - - def move(self, child, x, y): - self._grid.move(child, x / _CELL_SIZE, y / _CELL_SIZE, locked=True) - - def do_set_box(self, box): - self._box = box - - def do_get_height_request(self, for_width): - return 0, gtk.gdk.screen_height() - style.GRID_CELL_SIZE - - def do_get_width_request(self): - return 0, gtk.gdk.screen_width() - - def do_allocate(self, x, y, width, height, - req_width, req_height, origin_changed): - for child in self._box.get_layout_children(): - # We need to always get requests to not confuse hippo - min_w, child_width = child.get_width_request() - min_h, child_height = child.get_height_request(child_width) - - rect = self._grid.get_child_rect(child.item) - child.allocate(int(round(rect.x * _CELL_SIZE)), - int(round(rect.y * _CELL_SIZE)), - child_width, - child_height, - origin_changed) - - def _get_child_grid_size(self, child): - min_width, width = child.get_width_request() - min_height, height = child.get_height_request(width) - width = math.ceil(width / _CELL_SIZE) - height = math.ceil(height / _CELL_SIZE) - - return int(width), int(height) - - def _grid_child_changed_cb(self, grid, child): - child.emit_request_changed() diff --git a/src/jarabe/desktop/transitionbox.py b/src/jarabe/desktop/transitionbox.py index fd2112c90c..54a70de088 100644 --- a/src/jarabe/desktop/transitionbox.py +++ b/src/jarabe/desktop/transitionbox.py @@ -14,7 +14,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -import hippo import gobject from sugar.graphics import style @@ -34,37 +33,10 @@ def __init__(self, icon, start_size, end_size): def next_frame(self, current): d = (self.end_size - self.start_size) * current - self._icon.props.size = int(self.start_size + d) + self._icon.props.pixel_size = int(self.start_size + d) -class _Layout(gobject.GObject, hippo.CanvasLayout): - __gtype_name__ = 'SugarTransitionBoxLayout' - - def __init__(self): - gobject.GObject.__init__(self) - self._box = None - - def do_set_box(self, box): - self._box = box - - def do_get_height_request(self, for_width): - return 0, 0 - - def do_get_width_request(self): - return 0, 0 - - def do_allocate(self, x, y, width, height, - req_width, req_height, origin_changed): - for child in self._box.get_layout_children(): - min_width, child_width = child.get_width_request() - min_height, child_height = child.get_height_request(child_width) - - child.allocate(x + (width - child_width) / 2, - y + (height - child_height) / 2, - child_width, child_height, origin_changed) - - -class TransitionBox(hippo.Canvas): +class TransitionBox(BuddyIcon): __gtype_name__ = 'SugarTransitionBox' __gsignals__ = { @@ -72,18 +44,8 @@ class TransitionBox(hippo.Canvas): } def __init__(self): - gobject.GObject.__init__(self) - - self._box = hippo.CanvasBox() - self._box.props.background_color = style.COLOR_WHITE.get_int() - self.set_root(self._box) - - self._layout = _Layout() - self._box.set_layout(self._layout) - - self._my_icon = BuddyIcon(buddy=get_owner_instance(), - size=style.XLARGE_ICON_SIZE) - self._box.append(self._my_icon) + BuddyIcon.__init__(self, buddy=get_owner_instance(), + pixel_size=style.XLARGE_ICON_SIZE) self._animator = animator.Animator(0.3) self._animator.connect('completed', self._animation_completed_cb) @@ -92,8 +54,6 @@ def _animation_completed_cb(self, anim): self.emit('completed') def start_transition(self, start_size, end_size): - self._my_icon.props.size = start_size - self._animator.remove_all() - self._animator.add(_Animation(self._my_icon, start_size, end_size)) + self._animator.add(_Animation(self, start_size, end_size)) self._animator.start() diff --git a/src/jarabe/desktop/viewcontainer.py b/src/jarabe/desktop/viewcontainer.py new file mode 100644 index 0000000000..1c76fb1a73 --- /dev/null +++ b/src/jarabe/desktop/viewcontainer.py @@ -0,0 +1,82 @@ +# Copyright (C) 2011-2012 One Laptop Per Child +# Copyright (C) 2010 Tomeu Vizoso +# Copyright (C) 2011 Walter Bender +# Copyright (C) 2011 Raul Gutierrez Segales +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import gtk + + +class ViewContainer(gtk.Container): + __gtype_name__ = 'SugarViewContainer' + + def __init__(self, layout, owner_icon, activity_icon=None, **kwargs): + gtk.Container.__init__(self, **kwargs) + self.set_has_window(False) + + self._activity_icon = None + self._owner_icon = None + self._layout = None + + self._children = [] + self.set_layout(layout) + + if owner_icon: + self._owner_icon = owner_icon + self.add(self._owner_icon) + self._owner_icon.show() + + if activity_icon: + self._activity_icon = activity_icon + self.add(self._activity_icon) + self._activity_icon.show() + + def do_add(self, child): + if child != self._owner_icon and child != self._activity_icon: + self._children.append(child) + if child.flags() & gtk.REALIZED: + child.set_parent_window(self.get_parent_window()) + child.set_parent(self) + + def do_remove(self, child): + was_visible = child.get_visible() + if child in self._children: + self._children.remove(child) + child.unparent() + self._layout.remove(child) + if was_visible and self.get_visible(): + self.queue_resize() + + def do_size_allocate(self, allocation): + self.allocation = allocation + if self._owner_icon: + self._layout.setup(allocation, self._owner_icon, + self._activity_icon) + + self._layout.allocate_children(allocation, self._children) + + def do_forall(self, include_internals, callback, callback_data): + for child in self._children: + callback(child, callback_data) + if self._owner_icon: + callback(self._owner_icon, callback_data) + if self._activity_icon: + callback(self._activity_icon, callback_data) + + def set_layout(self, layout): + for child in self.get_children(): + self.remove(child) + self._layout = layout diff --git a/src/jarabe/journal/detailview.py b/src/jarabe/journal/detailview.py index aa8c039812..628af015ad 100644 --- a/src/jarabe/journal/detailview.py +++ b/src/jarabe/journal/detailview.py @@ -19,10 +19,9 @@ import gobject import gtk -import hippo from sugar.graphics import style -from sugar.graphics.icon import CanvasIcon +from sugar.graphics.icon import Icon from jarabe.journal.expandedentry import ExpandedEntry from jarabe.journal import model @@ -39,21 +38,15 @@ def __init__(self, **kwargs): self._metadata = None self._expanded_entry = None - canvas = hippo.Canvas() - - self._root = hippo.CanvasBox() - self._root.props.background_color = style.COLOR_PANEL_GREY.get_int() - canvas.set_root(self._root) + gobject.GObject.__init__(self, **kwargs) + gtk.VBox.__init__(self) back_bar = BackBar() back_bar.connect('button-release-event', self.__back_bar_release_event_cb) - self._root.append(back_bar) - - gobject.GObject.__init__(self, **kwargs) + self.pack_start(back_bar, expand=False) - self.pack_start(canvas) - canvas.show() + self.show_all() def _fav_icon_activated_cb(self, fav_icon): keep = not self._expanded_entry.get_keep() @@ -67,8 +60,9 @@ def __back_bar_release_event_cb(self, back_bar, event): def _update_view(self): if self._expanded_entry is None: self._expanded_entry = ExpandedEntry() - self._root.append(self._expanded_entry, hippo.PACK_EXPAND) + self.pack_start(self._expanded_entry) self._expanded_entry.set_metadata(self._metadata) + self.show_all() def refresh(self): logging.debug('DetailView.refresh') @@ -86,34 +80,37 @@ def set_metadata(self, metadata): type=object, getter=get_metadata, setter=set_metadata) -class BackBar(hippo.CanvasBox): +class BackBar(gtk.EventBox): def __init__(self): - hippo.CanvasBox.__init__(self, - orientation=hippo.ORIENTATION_HORIZONTAL, - border=style.LINE_WIDTH, - background_color=style.COLOR_PANEL_GREY.get_int(), - border_color=style.COLOR_SELECTION_GREY.get_int(), - padding=style.DEFAULT_PADDING, - padding_left=style.DEFAULT_SPACING, - spacing=style.DEFAULT_SPACING) - - icon = CanvasIcon(icon_name='go-previous', - size=style.SMALL_ICON_SIZE, - fill_color=style.COLOR_TOOLBAR_GREY.get_svg()) - self.append(icon) - - label = hippo.CanvasText(text=_('Back'), - font_desc=style.FONT_NORMAL.get_pango_desc()) - self.append(label) + gtk.EventBox.__init__(self) + self.modify_bg(gtk.STATE_NORMAL, + style.COLOR_PANEL_GREY.get_gdk_color()) + hbox = gtk.HBox(spacing=style.DEFAULT_PADDING) + hbox.set_border_width(style.DEFAULT_PADDING) + icon = Icon(icon_name='go-previous', icon_size=gtk.ICON_SIZE_MENU, + fill_color=style.COLOR_TOOLBAR_GREY.get_svg()) + hbox.pack_start(icon, False, False) + + label = gtk.Label() + label.set_text(_('Back')) + halign = gtk.Alignment(0, 0.5, 0, 1) + halign.add(label) + hbox.pack_start(halign, True, True) + hbox.show() + self.add(hbox) if gtk.widget_get_default_direction() == gtk.TEXT_DIR_RTL: - self.reverse() + hbox.reverse() + + self.connect('enter-notify-event', self.__enter_notify_event_cb) + self.connect('leave-notify-event', self.__leave_notify_event_cb) - self.connect('motion-notify-event', self.__motion_notify_event_cb) + def __enter_notify_event_cb(self, box, event): + box.modify_bg(gtk.STATE_NORMAL, + style.COLOR_SELECTION_GREY.get_gdk_color()) + return False - def __motion_notify_event_cb(self, box, event): - if event.detail == hippo.MOTION_DETAIL_ENTER: - box.props.background_color = style.COLOR_SELECTION_GREY.get_int() - elif event.detail == hippo.MOTION_DETAIL_LEAVE: - box.props.background_color = style.COLOR_PANEL_GREY.get_int() + def __leave_notify_event_cb(self, box, event): + box.modify_bg(gtk.STATE_NORMAL, + style.COLOR_PANEL_GREY.get_gdk_color()) return False diff --git a/src/jarabe/journal/expandedentry.py b/src/jarabe/journal/expandedentry.py index 03f8cd13a4..e0c603fd31 100644 --- a/src/jarabe/journal/expandedentry.py +++ b/src/jarabe/journal/expandedentry.py @@ -20,7 +20,6 @@ import time import os -import hippo import cairo import gobject import glib @@ -28,158 +27,144 @@ import simplejson from sugar.graphics import style -from sugar.graphics.icon import CanvasIcon from sugar.graphics.xocolor import XoColor -from sugar.graphics.canvastextview import CanvasTextView from sugar.util import format_size from jarabe.journal.keepicon import KeepIcon from jarabe.journal.palettes import ObjectPalette, BuddyPalette from jarabe.journal import misc from jarabe.journal import model +from jarabe.view.eventicon import EventIcon -class Separator(hippo.CanvasBox, hippo.CanvasItem): +class Separator(gtk.VBox): def __init__(self, orientation): - hippo.CanvasBox.__init__(self, - background_color=style.COLOR_PANEL_GREY.get_int()) - - if orientation == hippo.ORIENTATION_VERTICAL: - self.props.box_width = style.LINE_WIDTH - else: - self.props.box_height = style.LINE_WIDTH + gtk.VBox.__init__(self, + background_color=style.COLOR_PANEL_GREY.get_gdk_color()) -class BuddyList(hippo.CanvasBox): +class BuddyList(gtk.Alignment): def __init__(self, buddies): - hippo.CanvasBox.__init__(self, xalign=hippo.ALIGNMENT_START, - orientation=hippo.ORIENTATION_HORIZONTAL) + gtk.Alignment.__init__(self, 0, 0, 0, 0) + hbox = gtk.HBox() for buddy in buddies: nick_, color = buddy - hbox = hippo.CanvasBox(orientation=hippo.ORIENTATION_HORIZONTAL) - icon = CanvasIcon(icon_name='computer-xo', - xo_color=XoColor(color), - size=style.STANDARD_ICON_SIZE) + icon = EventIcon(icon_name='computer-xo', + xo_color=XoColor(color), + pixel_size=style.STANDARD_ICON_SIZE) icon.set_palette(BuddyPalette(buddy)) - hbox.append(icon) - self.append(hbox) + hbox.pack_start(icon) + self.add(hbox) -class ExpandedEntry(hippo.CanvasBox): +class ExpandedEntry(gtk.EventBox): def __init__(self): - hippo.CanvasBox.__init__(self) - self.props.orientation = hippo.ORIENTATION_VERTICAL - self.props.background_color = style.COLOR_WHITE.get_int() - self.props.padding_top = style.DEFAULT_SPACING * 3 + gtk.EventBox.__init__(self) + self._vbox = gtk.VBox() + self.add(self._vbox) self._metadata = None self._update_title_sid = None - # Create header - header = hippo.CanvasBox(orientation=hippo.ORIENTATION_HORIZONTAL, - padding=style.DEFAULT_PADDING, - padding_right=style.GRID_CELL_SIZE, - spacing=style.DEFAULT_SPACING) - self.append(header) - - # Create two column body + self.modify_bg(gtk.STATE_NORMAL, style.COLOR_WHITE.get_gdk_color()) - body = hippo.CanvasBox(orientation=hippo.ORIENTATION_HORIZONTAL, - spacing=style.DEFAULT_SPACING * 3, - padding_left=style.GRID_CELL_SIZE, - padding_right=style.GRID_CELL_SIZE, - padding_top=style.DEFAULT_SPACING * 3) + # Create a header + header = gtk.HBox() + self._vbox.pack_start(header, False, False, style.DEFAULT_SPACING * 2) - self.append(body, hippo.PACK_EXPAND) + # Create a two-column body + body_box = gtk.EventBox() + body_box.set_border_width(style.DEFAULT_SPACING) + body_box.modify_bg(gtk.STATE_NORMAL, style.COLOR_WHITE.get_gdk_color()) + self._vbox.pack_start(body_box) + body = gtk.HBox() + body_box.add(body) - first_column = hippo.CanvasBox(orientation=hippo.ORIENTATION_VERTICAL, - spacing=style.DEFAULT_SPACING) - body.append(first_column) + first_column = gtk.VBox() + body.pack_start(first_column, False, False, style.DEFAULT_SPACING) - second_column = hippo.CanvasBox(orientation=hippo.ORIENTATION_VERTICAL, - spacing=style.DEFAULT_SPACING) - body.append(second_column, hippo.PACK_EXPAND) + second_column = gtk.VBox() + body.pack_start(second_column) # Header - self._keep_icon = self._create_keep_icon() - header.append(self._keep_icon) + header.pack_start(self._keep_icon, False, False, style.DEFAULT_SPACING) self._icon = None - self._icon_box = hippo.CanvasBox() - header.append(self._icon_box) + self._icon_box = gtk.HBox() + header.pack_start(self._icon_box, False, False, style.DEFAULT_SPACING) self._title = self._create_title() - header.append(self._title, hippo.PACK_EXPAND) + header.pack_start(self._title) # TODO: create a version list popup instead of a date label self._date = self._create_date() - header.append(self._date) + header.pack_start(self._date, False, False, style.DEFAULT_SPACING) if gtk.widget_get_default_direction() == gtk.TEXT_DIR_RTL: header.reverse() - # First column - - self._preview_box = hippo.CanvasBox() - first_column.append(self._preview_box) + # First body column + self._preview_box = gtk.Frame() + first_column.pack_start(self._preview_box, expand=False) - self._technical_box = hippo.CanvasBox() - first_column.append(self._technical_box) - - # Second column + self._technical_box = gtk.VBox() + first_column.pack_start(self._technical_box) + # Second body column description_box, self._description = self._create_description() - second_column.append(description_box) + second_column.pack_start(description_box, True, True, + style.DEFAULT_SPACING) tags_box, self._tags = self._create_tags() - second_column.append(tags_box) + second_column.pack_start(tags_box, True, True, + style.DEFAULT_SPACING) + + self._buddy_list = gtk.VBox() + second_column.pack_start(self._buddy_list) - self._buddy_list = hippo.CanvasBox() - second_column.append(self._buddy_list) + self.show_all() def set_metadata(self, metadata): if self._metadata == metadata: return self._metadata = metadata - self._keep_icon.keep = (str(metadata.get('keep', 0)) == '1') + self._keep_icon.set_active(int(metadata.get('keep', 0)) == 1) self._icon = self._create_icon() - self._icon_box.clear() - self._icon_box.append(self._icon) - - self._date.props.text = misc.get_date(metadata) + self._icon_box.foreach(self._icon_box.remove) + self._icon_box.pack_start(self._icon, False, False) - title = self._title.props.widget - title.props.text = metadata.get('title', _('Untitled')) - title.props.editable = model.is_editable(metadata) + self._date.set_text(misc.get_date(metadata)) - self._preview_box.clear() - self._preview_box.append(self._create_preview()) + self._title.set_text(metadata.get('title', _('Untitled'))) - self._technical_box.clear() - self._technical_box.append(self._create_technical()) + if self._preview_box.get_child(): + self._preview_box.remove(self._preview_box.get_child()) + self._preview_box.add(self._create_preview()) - self._buddy_list.clear() - self._buddy_list.append(self._create_buddy_list()) + self._technical_box.foreach(self._technical_box.remove) + self._technical_box.pack_start(self._create_technical(), + False, False, style.DEFAULT_SPACING) - description = self._description.text_view_widget - description.props.buffer.props.text = metadata.get('description', '') - description.props.editable = model.is_editable(metadata) + self._buddy_list.foreach(self._buddy_list.remove) + self._buddy_list.pack_start(self._create_buddy_list(), False, False, + style.DEFAULT_SPACING) - tags = self._tags.text_view_widget - tags.props.buffer.props.text = metadata.get('tags', '') - tags.props.editable = model.is_editable(metadata) + description = metadata.get('description', '') + self._description.get_buffer().set_text(description) + tags = metadata.get('tags', '') + self._tags.get_buffer().set_text(tags) def _create_keep_icon(self): - keep_icon = KeepIcon(False) - keep_icon.connect('activated', self._keep_icon_activated_cb) + keep_icon = KeepIcon() + keep_icon.connect('toggled', self._keep_icon_toggled_cb) return keep_icon def _create_icon(self): - icon = CanvasIcon(file_name=misc.get_icon_name(self._metadata)) + icon = EventIcon(file_name=misc.get_icon_name(self._metadata)) icon.connect_after('button-release-event', self._icon_button_release_event_cb) @@ -202,17 +187,17 @@ def _create_title(self): entry.modify_bg(gtk.STATE_INSENSITIVE, bg_color) entry.modify_base(gtk.STATE_INSENSITIVE, bg_color) - return hippo.CanvasWidget(widget=entry) + return entry def _create_date(self): - date = hippo.CanvasText(xalign=hippo.ALIGNMENT_START, - font_desc=style.FONT_NORMAL.get_pango_desc()) + date = gtk.Label() return date def _create_preview(self): width = style.zoom(320) height = style.zoom(240) - box = hippo.CanvasBox() + box = gtk.EventBox() + box.modify_bg(gtk.STATE_NORMAL, style.COLOR_WHITE.get_gdk_color()) if len(self._metadata.get('preview', '')) > 4: if self._metadata['preview'][1:4] == 'PNG': @@ -225,7 +210,17 @@ def _create_preview(self): png_file = StringIO.StringIO(preview_data) try: + # Load image and scale to dimensions surface = cairo.ImageSurface.create_from_png(png_file) + png_width = surface.get_width() + png_height = surface.get_height() + pixmap = gtk.gdk.Pixmap(None, png_width, png_height, 24) + cr = pixmap.cairo_create() + cr.set_source_surface(surface, 0, 0) + cr.scale(width / png_width, height / png_height) + cr.paint() + + im = gtk.image_new_from_pixmap(pixmap, None) has_preview = True except Exception: logging.exception('Error while loading the preview') @@ -234,50 +229,35 @@ def _create_preview(self): has_preview = False if has_preview: - preview_box = hippo.CanvasImage(image=surface, - border=style.LINE_WIDTH, - border_color=style.COLOR_BUTTON_GREY.get_int(), - xalign=hippo.ALIGNMENT_CENTER, - yalign=hippo.ALIGNMENT_CENTER, - scale_width=width, - scale_height=height) + box.add(im) else: - preview_box = hippo.CanvasText(text=_('No preview'), - font_desc=style.FONT_NORMAL.get_pango_desc(), - xalign=hippo.ALIGNMENT_CENTER, - yalign=hippo.ALIGNMENT_CENTER, - border=style.LINE_WIDTH, - border_color=style.COLOR_BUTTON_GREY.get_int(), - color=style.COLOR_BUTTON_GREY.get_int(), - box_width=width, - box_height=height) - preview_box.connect_after('button-release-event', - self._preview_box_button_release_event_cb) - box.append(preview_box) + label = gtk.Label() + label.set_text(_('No preview')) + label.set_size_request(width, height) + box.add(label) + + box.connect_after('button-release-event', + self._preview_box_button_release_event_cb) return box def _create_technical(self): - vbox = hippo.CanvasBox() + vbox = gtk.VBox() vbox.props.spacing = style.DEFAULT_SPACING - lines = [ - _('Kind: %s') % (self._metadata.get('mime_type') or _('Unknown'),), - _('Date: %s') % (self._format_date(),), - _('Size: %s') % (format_size(int(self._metadata.get('filesize', - model.get_file_size(self._metadata['uid']))))), - ] - - for line in lines: - text = hippo.CanvasText(text=line, - font_desc=style.FONT_NORMAL.get_pango_desc()) - text.props.color = style.COLOR_BUTTON_GREY.get_int() - - if gtk.widget_get_default_direction() == gtk.TEXT_DIR_RTL: - text.props.xalign = hippo.ALIGNMENT_END - else: - text.props.xalign = hippo.ALIGNMENT_START - - vbox.append(text) + label = \ + _('Kind: %s') % (self._metadata.get('mime_type') or \ + _('Unknown'),) + '\n' + \ + _('Date: %s') % (self._format_date(),) + '\n' + \ + _('Size: %s') % (format_size(int(self._metadata.get( + 'filesize', + model.get_file_size(self._metadata['uid']))))) + + text = gtk.Label() + text.set_markup('%s' % ( + style.COLOR_BUTTON_GREY.get_html(), label)) + halign = gtk.Alignment(0, 0, 0, 0) + halign.add(text) + vbox.pack_start(halign, False, False, 0) return vbox @@ -295,76 +275,55 @@ def _format_date(self): def _create_buddy_list(self): - vbox = hippo.CanvasBox() + vbox = gtk.VBox() vbox.props.spacing = style.DEFAULT_SPACING - text = hippo.CanvasText(text=_('Participants:'), - font_desc=style.FONT_NORMAL.get_pango_desc()) - text.props.color = style.COLOR_BUTTON_GREY.get_int() - - if gtk.widget_get_default_direction() == gtk.TEXT_DIR_RTL: - text.props.xalign = hippo.ALIGNMENT_END - else: - text.props.xalign = hippo.ALIGNMENT_START - - vbox.append(text) + text = gtk.Label() + text.set_markup('%s' % ( + style.COLOR_BUTTON_GREY.get_html(), _('Participants:'))) + halign = gtk.Alignment(0, 0, 0, 0) + halign.add(text) + vbox.pack_start(halign, False, False, 0) if self._metadata.get('buddies'): buddies = simplejson.loads(self._metadata['buddies']).values() - vbox.append(BuddyList(buddies)) + vbox.pack_start(BuddyList(buddies), False, False, 0) return vbox else: return vbox - def _create_description(self): - vbox = hippo.CanvasBox() + def _create_scrollable(self, label): + vbox = gtk.VBox() vbox.props.spacing = style.DEFAULT_SPACING - text = hippo.CanvasText(text=_('Description:'), - font_desc=style.FONT_NORMAL.get_pango_desc()) - text.props.color = style.COLOR_BUTTON_GREY.get_int() + text = gtk.Label() + text.set_markup('%s' % ( + style.COLOR_BUTTON_GREY.get_html(), label)) - if gtk.widget_get_default_direction() == gtk.TEXT_DIR_RTL: - text.props.xalign = hippo.ALIGNMENT_END - else: - text.props.xalign = hippo.ALIGNMENT_START + halign = gtk.Alignment(0, 0, 0, 0) + halign.add(text) + vbox.pack_start(halign, False, False, 0) - vbox.append(text) + scrolled_window = gtk.ScrolledWindow() + scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) + scrolled_window.set_border_width(style.LINE_WIDTH) + text_buffer = gtk.TextBuffer() + text_view = gtk.TextView(text_buffer) + text_view.set_left_margin(style.DEFAULT_PADDING) + text_view.set_wrap_mode(gtk.WRAP_WORD_CHAR) + scrolled_window.add_with_viewport(text_view) + vbox.pack_start(scrolled_window) - text_view = CanvasTextView('', - box_height=style.GRID_CELL_SIZE * 2) - vbox.append(text_view, hippo.PACK_EXPAND) - - text_view.text_view_widget.props.accepts_tab = False - text_view.text_view_widget.connect('focus-out-event', - self._description_focus_out_event_cb) + # text_view.text_view_widget.connect('focus-out-event', + # self._description_focus_out_event_cb) return vbox, text_view - def _create_tags(self): - vbox = hippo.CanvasBox() - vbox.props.spacing = style.DEFAULT_SPACING - - text = hippo.CanvasText(text=_('Tags:'), - font_desc=style.FONT_NORMAL.get_pango_desc()) - text.props.color = style.COLOR_BUTTON_GREY.get_int() - - if gtk.widget_get_default_direction() == gtk.TEXT_DIR_RTL: - text.props.xalign = hippo.ALIGNMENT_END - else: - text.props.xalign = hippo.ALIGNMENT_START - - vbox.append(text) - - text_view = CanvasTextView('', - box_height=style.GRID_CELL_SIZE * 2) - vbox.append(text_view, hippo.PACK_EXPAND) - - text_view.text_view_widget.props.accepts_tab = False - text_view.text_view_widget.connect('focus-out-event', - self._tags_focus_out_event_cb) + def _create_description(self): + return self._create_scrollable(_('Description:')) - return vbox, text_view + def _create_tags(self): + return self._create_scrollable(_('Tags:')) def _title_notify_text_cb(self, entry, pspec): if not self._update_title_sid: @@ -385,7 +344,7 @@ def _update_entry(self, needs_update=False): return old_title = self._metadata.get('title', None) - new_title = self._title.props.widget.props.text + new_title = self._title.get_text() if old_title != new_title: label = glib.markup_escape_text(new_title) self._icon.palette.props.primary_text = label @@ -393,15 +352,18 @@ def _update_entry(self, needs_update=False): self._metadata['title_set_by_user'] = '1' needs_update = True + bounds = self._tags.get_buffer().get_bounds() old_tags = self._metadata.get('tags', None) - new_tags = self._tags.text_view_widget.props.buffer.props.text + new_tags = self._tags.get_buffer().get_text(bounds[0], bounds[1]) + if old_tags != new_tags: self._metadata['tags'] = new_tags needs_update = True + bounds = self._description.get_buffer().get_bounds() old_description = self._metadata.get('description', None) - new_description = \ - self._description.text_view_widget.props.buffer.props.text + new_description = self._description.get_buffer().get_text( + bounds[0], bounds[1]) if old_description != new_description: self._metadata['description'] = new_description needs_update = True @@ -418,16 +380,12 @@ def _update_entry(self, needs_update=False): self._update_title_sid = None - def get_keep(self): - return (str(self._metadata.get('keep', 0)) == '1') - - def _keep_icon_activated_cb(self, keep_icon): - if self.get_keep(): - self._metadata['keep'] = 0 - else: + def _keep_icon_toggled_cb(self, keep_icon): + if keep_icon.get_active(): self._metadata['keep'] = 1 + else: + self._metadata['keep'] = 0 self._update_entry(needs_update=True) - keep_icon.props.keep = self.get_keep() def _icon_button_release_event_cb(self, button, event): logging.debug('_icon_button_release_event_cb') diff --git a/src/jarabe/journal/keepicon.py b/src/jarabe/journal/keepicon.py index 5bc299bca9..85b1728de7 100644 --- a/src/jarabe/journal/keepicon.py +++ b/src/jarabe/journal/keepicon.py @@ -14,51 +14,42 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -import gobject -import hippo +import gtk import gconf +import logging -from sugar.graphics.icon import CanvasIcon +from sugar.graphics.icon import Icon from sugar.graphics import style from sugar.graphics.xocolor import XoColor -class KeepIcon(CanvasIcon): - def __init__(self, keep): - CanvasIcon.__init__(self, icon_name='emblem-favorite', - box_width=style.GRID_CELL_SIZE * 3 / 5, - size=style.SMALL_ICON_SIZE) - self.connect('motion-notify-event', self.__motion_notify_event_cb) +class KeepIcon(gtk.ToggleButton): + def __init__(self): + gtk.ToggleButton.__init__(self) + self.set_relief(gtk.RELIEF_NONE) + self.set_focus_on_click(False) - self._keep = None - self.set_keep(keep) + self._icon = Icon(icon_name='emblem-favorite', + pixel_size=style.SMALL_ICON_SIZE) + self.set_image(self._icon) + self.connect('toggled', self.__toggled_cb) + self.connect('leave-notify-event', self.__leave_notify_event_cb) + self.connect('enter-notify-event', self.__enter_notify_event_cb) - def set_keep(self, keep): - if keep == self._keep: - return - - self._keep = keep - if keep: + def __toggled_cb(self, widget): + if self.get_active(): client = gconf.client_get_default() color = XoColor(client.get_string('/desktop/sugar/user/color')) - self.props.xo_color = color + self._icon.props.xo_color = color + logging.debug('KEEPICON: setting xo_color') else: - self.props.stroke_color = style.COLOR_BUTTON_GREY.get_svg() - self.props.fill_color = style.COLOR_TRANSPARENT.get_svg() - - def get_keep(self): - return self._keep + self._icon.props.stroke_color = style.COLOR_BUTTON_GREY.get_svg() + self._icon.props.fill_color = style.COLOR_TRANSPARENT.get_svg() - keep = gobject.property(type=int, default=0, getter=get_keep, - setter=set_keep) + def __enter_notify_event_cb(self, icon, event): + if not self.get_active(): + self._icon.props.fill_color = style.COLOR_BUTTON_GREY.get_svg() - def __motion_notify_event_cb(self, icon, event): - if not self._keep: - if event.detail == hippo.MOTION_DETAIL_ENTER: - client = gconf.client_get_default() - prelit_color = XoColor(client.get_string('/desktop/sugar/user/color')) - icon.props.stroke_color = prelit_color.get_stroke_color() - icon.props.fill_color = prelit_color.get_fill_color() - elif event.detail == hippo.MOTION_DETAIL_LEAVE: - icon.props.stroke_color = style.COLOR_BUTTON_GREY.get_svg() - icon.props.fill_color = style.COLOR_TRANSPARENT.get_svg() + def __leave_notify_event_cb(self, icon, event): + if not self.get_active(): + self._icon.props.fill_color = style.COLOR_TRANSPARENT.get_svg() diff --git a/src/jarabe/journal/listview.py b/src/jarabe/journal/listview.py index 57836f250d..f6a867f0ec 100644 --- a/src/jarabe/journal/listview.py +++ b/src/jarabe/journal/listview.py @@ -18,14 +18,14 @@ from gettext import gettext as _ import time +import glib import gobject import gtk -import hippo import gconf import pango from sugar.graphics import style -from sugar.graphics.icon import CanvasIcon, Icon, CellRendererIcon +from sugar.graphics.icon import Icon, CellRendererIcon from sugar.graphics.xocolor import XoColor from sugar import util @@ -33,6 +33,7 @@ from jarabe.journal.palettes import ObjectPalette, BuddyPalette from jarabe.journal import model from jarabe.journal import misc +from jarabe.view.eventicon import EventIcon UPDATE_INTERVAL = 300 @@ -370,38 +371,33 @@ def _stop_progress_bar(self): self._progress_bar = None def _show_message(self, message, show_clear_query=False): - canvas = hippo.Canvas() + box = gtk.VBox() self.remove(self.child) - self.add(canvas) - canvas.show() - - box = hippo.CanvasBox(orientation=hippo.ORIENTATION_VERTICAL, - background_color=style.COLOR_WHITE.get_int(), - yalign=hippo.ALIGNMENT_CENTER, - spacing=style.DEFAULT_SPACING, - padding_bottom=style.GRID_CELL_SIZE) - canvas.set_root(box) - - icon = CanvasIcon(size=style.LARGE_ICON_SIZE, - icon_name='activity-journal', - stroke_color=style.COLOR_BUTTON_GREY.get_svg(), - fill_color=style.COLOR_TRANSPARENT.get_svg()) - box.append(icon) - - text = hippo.CanvasText(text=message, - xalign=hippo.ALIGNMENT_CENTER, - font_desc=style.FONT_BOLD.get_pango_desc(), - color=style.COLOR_BUTTON_GREY.get_int()) - box.append(text) + + alignment = gtk.Alignment(0.5, 0.5, 0.1, 0.1) + self.add(alignment) + + icon = EventIcon(pixel_size=style.LARGE_ICON_SIZE, + icon_name='activity-journal', + stroke_color=style.COLOR_BUTTON_GREY.get_svg(), + fill_color=style.COLOR_TRANSPARENT.get_svg()) + box.pack_start(icon, expand=True, fill=False) + + label = gtk.Label() + color = style.COLOR_BUTTON_GREY.get_html() + label.set_markup('%s' % ( \ + color, glib.markup_escape_text(message))) + box.pack_start(label, expand=True, fill=False) if show_clear_query: button = gtk.Button(label=_('Clear search')) button.connect('clicked', self.__clear_button_clicked_cb) button.props.image = Icon(icon_name='dialog-cancel', icon_size=gtk.ICON_SIZE_BUTTON) - canvas_button = hippo.CanvasWidget(widget=button, - xalign=hippo.ALIGNMENT_CENTER) - box.append(canvas_button) + box.pack_start(button, expand=True, fill=False) + + alignment.add(box) + alignment.show_all() def __clear_button_clicked_cb(self, button): self.emit('clear-clicked') diff --git a/src/jarabe/view/buddyicon.py b/src/jarabe/view/buddyicon.py index e0e8b3fea3..663bd9221c 100644 --- a/src/jarabe/view/buddyicon.py +++ b/src/jarabe/view/buddyicon.py @@ -14,17 +14,19 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -from sugar.graphics.icon import CanvasIcon from sugar.graphics import style from jarabe.view.buddymenu import BuddyMenu +from jarabe.view.eventicon import EventIcon + _FILTERED_ALPHA = 0.33 -class BuddyIcon(CanvasIcon): - def __init__(self, buddy, size=style.STANDARD_ICON_SIZE): - CanvasIcon.__init__(self, icon_name='computer-xo', size=size) +class BuddyIcon(EventIcon): + def __init__(self, buddy, pixel_size=style.STANDARD_ICON_SIZE): + EventIcon.__init__(self, icon_name='computer-xo', + pixel_size=pixel_size) self._filtered = False self._buddy = buddy diff --git a/src/jarabe/view/pulsingicon.py b/src/jarabe/view/pulsingicon.py index 9a98a80e41..39e0babd76 100644 --- a/src/jarabe/view/pulsingicon.py +++ b/src/jarabe/view/pulsingicon.py @@ -18,9 +18,12 @@ import gobject -from sugar.graphics.icon import Icon, CanvasIcon +from sugar.graphics.icon import Icon from sugar.graphics import style +from jarabe.view.eventicon import EventIcon + + _INTERVAL = 100 _STEP = math.pi / 10 # must be a fraction of pi, for clean caching _MINIMAL_ALPHA_VALUE = 0.33 @@ -169,8 +172,8 @@ def __destroy_cb(self, icon): self._palette.destroy() -class CanvasPulsingIcon(CanvasIcon): - __gtype_name__ = 'SugarCanvasPulsingIcon' +class EventPulsingIcon(EventIcon): + __gtype_name__ = 'SugarEventPulsingIcon' def __init__(self, **kwargs): self._pulser = Pulser(self) @@ -179,7 +182,7 @@ def __init__(self, **kwargs): self._paused = False self._pulsing = False - CanvasIcon.__init__(self, **kwargs) + EventIcon.__init__(self, **kwargs) self.connect('destroy', self.__destroy_cb)