diff --git a/sugar/activity/activity.py b/sugar/activity/activity.py index 146d8636..2c1eaaea 100644 --- a/sugar/activity/activity.py +++ b/sugar/activity/activity.py @@ -28,6 +28,7 @@ See the methods of the Activity class below for more information on what you will need for a real activity. """ # Copyright (C) 2006-2007 Red Hat, Inc. +# Copyright (C) 2007-2008 One Laptop Per Child # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -125,14 +126,14 @@ class ActivityToolbar(gtk.Toolbar): self._update_share() - self.keep = ToolButton('document-save') - self.keep.set_tooltip(_('Keep')) + self.keep = ToolButton('document-save', tooltip=_('Keep')) + self.keep.props.accelerator = 'S' self.keep.connect('clicked', self.__keep_clicked_cb) self.insert(self.keep, -1) self.keep.show() - self.stop = ToolButton('activity-stop') - self.stop.set_tooltip(_('Stop')) + self.stop = ToolButton('activity-stop', tooltip=_('Stop')) + self.stop.props.accelerator = 'Q' self.stop.connect('clicked', self.__stop_clicked_cb) self.insert(self.stop, -1) self.stop.show() @@ -418,7 +419,6 @@ class Activity(Window, gtk.Container): self.connect('realize', self.__realize_cb) self.connect('delete-event', self.__delete_event_cb) - self.connect("key_press_event", self.__key_press_event_cb) self._active = False self._activity_id = handle.activity_id @@ -433,6 +433,10 @@ class Activity(Window, gtk.Container): self._max_participants = 0 self._invites_queue = [] + accel_group = gtk.AccelGroup() + self.set_data('sugar-accel-group', accel_group) + self.add_accel_group(accel_group) + self._bus = ActivityService(self) self._owns_file = False @@ -905,13 +909,6 @@ class Activity(Window, gtk.Container): metadata = property(get_metadata, None) - def __key_press_event_cb(self, widget, event): - key = gtk.gdk.keyval_name(event.keyval) - if key == 's' and (event.state & gtk.gdk.CONTROL_MASK): - logging.debug('Keep requested') - self.copy() - return True - def get_bundle_name(): """Return the bundle name for the current process' bundle""" return os.environ['SUGAR_BUNDLE_NAME'] diff --git a/sugar/graphics/palette.py b/sugar/graphics/palette.py index e84cc51f..4430b96a 100644 --- a/sugar/graphics/palette.py +++ b/sugar/graphics/palette.py @@ -1,4 +1,5 @@ # Copyright (C) 2007, Eduardo Silva +# Copyright (C) 2008, One Laptop Per Child # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -176,9 +177,9 @@ class Palette(gtk.Window): vbox = gtk.VBox() - self._label = gtk.Label() - self._label.set_size_request(-1, style.zoom(style.GRID_CELL_SIZE) - - 2*self.get_border_width()) + self._label = gtk.AccelLabel('') + self._label.set_size_request(-1, style.zoom(style.GRID_CELL_SIZE) - + 2 * self.get_border_width()) self._label.set_alignment(0, 0.5) self._label.set_padding(style.DEFAULT_SPACING, 0) @@ -186,7 +187,7 @@ class Palette(gtk.Window): self._label.set_max_width_chars(text_maxlen) self._label.set_ellipsize(pango.ELLIPSIZE_MIDDLE) - vbox.pack_start(self._label, False) + vbox.pack_start(self._label) self._secondary_box = gtk.VBox() vbox.pack_start(self._secondary_box) @@ -220,7 +221,7 @@ class Palette(gtk.Window): self.connect('leave-notify-event', self._leave_notify_event_cb) - self.set_primary_text(label, accel_path) + self.set_primary_text(label) self.set_group_id('default') self._mouse_detector = MouseSpeedDetector(self, 200, 5) @@ -263,9 +264,9 @@ class Palette(gtk.Window): return gtk.gdk.Rectangle(x, y, width, height) - def set_primary_text(self, label, accel_path=None): + def set_primary_text(self, label): if label is not None: - self._label.set_markup(""+label+"") + self._label.set_markup('%s' % label) self._label.show() def set_content(self, widget): @@ -302,6 +303,8 @@ class Palette(gtk.Window): 'mouse-enter', self._invoker_mouse_enter_cb) self._leave_invoker_hid = self._invoker.connect( 'mouse-leave', self._invoker_mouse_leave_cb) + if hasattr(value.props, 'widget'): + self._label.props.accel_widget = value.props.widget else: raise AssertionError @@ -314,11 +317,15 @@ class Palette(gtk.Window): def do_size_request(self, requisition): gtk.Window.do_size_request(self, requisition) - requisition.width = max(requisition.width, self._full_request[0]) + # gtk.AccelLabel request doesn't include the accelerator. + label_width = self._label.size_request()[0] + \ + self._label.get_accel_width() + \ + 2 * self.get_border_width() - # Minimum width requisition.width = max(requisition.width, - style.zoom(style.GRID_CELL_SIZE*2)) + style.zoom(style.GRID_CELL_SIZE * 2), + label_width, + self._full_request[0]) def do_size_allocate(self, allocation): gtk.Window.do_size_allocate(self, allocation) @@ -819,6 +826,10 @@ class WidgetInvoker(Invoker): Invoker.notify_popdown(self) self._widget.queue_draw() + def _get_widget(self): + return self._widget + widget = gobject.property(type=object, getter=_get_widget, setter=None) + class CanvasInvoker(Invoker): def __init__(self, item): Invoker.__init__(self) diff --git a/sugar/graphics/radiotoolbutton.py b/sugar/graphics/radiotoolbutton.py index cb4ae255..8cccefc7 100644 --- a/sugar/graphics/radiotoolbutton.py +++ b/sugar/graphics/radiotoolbutton.py @@ -1,5 +1,5 @@ # Copyright (C) 2007, Red Hat, Inc. -# Copyright (C) 2007, One Laptop Per Child +# Copyright (C) 2007-2008, One Laptop Per Child # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -16,19 +16,58 @@ # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. +import logging + import gtk +import gobject from sugar.graphics.icon import Icon from sugar.graphics.palette import Palette, ToolInvoker +from sugar.graphics import toolbutton class RadioToolButton(gtk.RadioToolButton): __gtype_name__ = "SugarRadioToolButton" - def __init__(self, named_icon=None, group=None, xo_color=None): - gtk.RadioToolButton.__init__(self, group=group) + def __init__(self, named_icon=None, group=None, xo_color=None, **kwargs): + self._accelerator = None + self._tooltip = None self._palette = None self._xo_color = xo_color - self.set_named_icon(named_icon) + + gobject.GObject.__init__(self, **kwargs) + + if named_icon: + self.set_named_icon(named_icon) + if group: + self.props.group = group + + def set_tooltip(self, tooltip): + """ Set a simple palette with just a single label. + """ + if self.palette is None or self._tooltip is None: + self.palette = Palette(tooltip) + elif self.palette is not None: + self.palette.set_primary_text(tooltip) + + self._tooltip = tooltip + + # Set label, shows up when toolbar overflows + gtk.RadioToolButton.set_label(self, tooltip) + + def get_tooltip(self): + return self._tooltip + + tooltip = gobject.property(type=str, setter=set_tooltip, getter=get_tooltip) + + def set_accelerator(self, accelerator): + self._accelerator = accelerator + toolbutton.setup_accelerator(self) + + def get_accelerator(self): + return self._accelerator + + accelerator = gobject.property(type=str, setter=set_accelerator, + getter=get_accelerator) def set_named_icon(self, named_icon): icon = Icon(icon_name=named_icon, @@ -46,8 +85,7 @@ class RadioToolButton(gtk.RadioToolButton): self._palette = palette self._palette.props.invoker = ToolInvoker(self) - def set_tooltip(self, text): - self.set_palette(Palette(text)) + palette = gobject.property(type=object, setter=set_palette, getter=get_palette) def do_expose_event(self, event): if self._palette and self._palette.is_up(): @@ -63,5 +101,4 @@ class RadioToolButton(gtk.RadioToolButton): self.allocation.height) gtk.RadioToolButton.do_expose_event(self, event) - - palette = property(get_palette, set_palette) + diff --git a/sugar/graphics/toolbutton.py b/sugar/graphics/toolbutton.py index 26acc836..08bc1f3a 100644 --- a/sugar/graphics/toolbutton.py +++ b/sugar/graphics/toolbutton.py @@ -1,4 +1,5 @@ # Copyright (C) 2007, Red Hat, Inc. +# Copyright (C) 2008, One Laptop Per Child # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -15,22 +16,81 @@ # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. +import logging + import gtk import gobject -import time from sugar.graphics.icon import Icon from sugar.graphics.palette import Palette, ToolInvoker +def _add_accelerator(tool_button): + if not tool_button.props.accelerator or not tool_button.get_toplevel() or \ + not tool_button.child: + return + + # TODO: should we remove the accelerator from the prev top level? + + accel_group = tool_button.get_toplevel().get_data('sugar-accel-group') + if not accel_group: + logging.warning('No gtk.AccelGroup in the top level window.') + return + + keyval, mask = gtk.accelerator_parse(tool_button.props.accelerator) + # the accelerator needs to be set at the child, so the gtk.AccelLabel + # in the palette can pick it up. + tool_button.child.add_accelerator('clicked', accel_group, keyval, mask, + gtk.ACCEL_LOCKED | gtk.ACCEL_VISIBLE) + +def _hierarchy_changed_cb(tool_button, previous_toplevel): + _add_accelerator(tool_button) + +def setup_accelerator(tool_button): + _add_accelerator(tool_button) + tool_button.connect('hierarchy-changed', _hierarchy_changed_cb) + class ToolButton(gtk.ToolButton): __gtype_name__ = "SugarToolButton" - def __init__(self, icon_name=None): - gtk.ToolButton.__init__(self) + def __init__(self, icon_name=None, **kwargs): + self._accelerator = None + self._tooltip = None self._palette = None + + gobject.GObject.__init__(self, **kwargs) + if icon_name: self.set_icon(icon_name) - self.connect('clicked', self._button_clicked_cb) + + self.connect('clicked', self.__button_clicked_cb) + + def set_tooltip(self, tooltip): + """ Set a simple palette with just a single label. + """ + if self.palette is None or self._tooltip is None: + self.palette = Palette(tooltip) + elif self.palette is not None: + self.palette.set_primary_text(tooltip) + + self._tooltip = tooltip + + # Set label, shows up when toolbar overflows + gtk.ToolButton.set_label(self, tooltip) + + def get_tooltip(self): + return self._tooltip + + tooltip = gobject.property(type=str, setter=set_tooltip, getter=get_tooltip) + + def set_accelerator(self, accelerator): + self._accelerator = accelerator + setup_accelerator(self) + + def get_accelerator(self): + return self._accelerator + + accelerator = gobject.property(type=str, setter=set_accelerator, + getter=get_accelerator) def set_icon(self, icon_name): icon = Icon(icon_name=icon_name) @@ -46,11 +106,7 @@ class ToolButton(gtk.ToolButton): self._palette = palette self._palette.props.invoker = ToolInvoker(self) - def set_tooltip(self, text): - self.set_palette(Palette(text)) - - # Set label, shows up when toolbar overflows - self.set_label(text) + palette = gobject.property(type=object, setter=set_palette, getter=get_palette) def do_expose_event(self, event): if self._palette and self._palette.is_up(): @@ -67,8 +123,7 @@ class ToolButton(gtk.ToolButton): gtk.ToolButton.do_expose_event(self, event) - def _button_clicked_cb(self, widget): + def __button_clicked_cb(self, widget): if self._palette: self._palette.popdown(True) - palette = property(get_palette, set_palette)