diff --git a/src/sugar3/activity/widgets.py b/src/sugar3/activity/widgets.py index 03b24157..b60fc669 100644 --- a/src/sugar3/activity/widgets.py +++ b/src/sugar3/activity/widgets.py @@ -219,17 +219,15 @@ class TitleEntry(Gtk.ToolItem): shared_activity.props.name = title -class DescriptionItem(Gtk.ToolItem): +class DescriptionItem(ToolButton): def __init__(self, activity, **kwargs): - Gtk.ToolItem.__init__(self) - - description_button = ToolButton('edit-description') - description_button.show() - description_button.set_tooltip(_('Description')) - description_button.palette_invoker.props.toggle_palette = True - description_button.props.hide_tooltip_on_click = False - self._palette = description_button.get_palette() + ToolButton.__init__(self, 'edit-description', **kwargs) + self.set_tooltip(_('Description')) + self.palette_invoker.props.toggle_palette = True + self.palette_invoker.props.lock_palette = True + self.props.hide_tooltip_on_click = False + self._palette = self.get_palette() description_box = PaletteMenuBox() sw = Gtk.ScrolledWindow() @@ -251,10 +249,31 @@ class DescriptionItem(Gtk.ToolItem): self._palette.set_content(description_box) description_box.show_all() - self.add(description_button) - activity.metadata.connect('updated', self.__jobject_updated_cb) + def set_expanded(self, expanded): + box = self.toolbar_box + if not box: + return + + if not expanded: + self.palette_invoker.notify_popdown() + return + + if box.expanded_button is not None: + box.expanded_button.queue_draw() + if box.expanded_button != self: + box.expanded_button.set_expanded(False) + box.expanded_button = self + + def get_toolbar_box(self): + parent = self.get_parent() + if not hasattr(parent, 'owner'): + return None + return parent.owner + + toolbar_box = property(get_toolbar_box) + def _get_text_from_buffer(self): buf = self._text_view.get_buffer() start_iter = buf.get_start_iter() diff --git a/src/sugar3/graphics/colorbutton.py b/src/sugar3/graphics/colorbutton.py index 823fd610..065a55e6 100644 --- a/src/sugar3/graphics/colorbutton.py +++ b/src/sugar3/graphics/colorbutton.py @@ -112,15 +112,6 @@ class _ColorButton(Gtk.Button): return '#%.2X%.2X%.2X' % (fg_color.red * 255, fg_color.green * 255, fg_color.blue * 255) - def do_clicked(self): - if self._palette: - if not self._palette.is_up(): - self._palette.popup(immediate=True, - state=self._palette.SECONDARY) - else: - self._palette.popdown(immediate=True) - return True - def set_color(self, color): assert isinstance(color, Gdk.Color) @@ -451,6 +442,8 @@ class ColorToolButton(Gtk.ToolItem): color_button.icon_size = Gtk.IconSize.LARGE_TOOLBAR self._palette_invoker.attach_tool(self) + self._palette_invoker.props.toggle_palette = True + self._palette_invoker.props.lock_palette = True # This widget just proxies the following properties to the colorbutton color_button.connect('notify::color', self.__notify_change) @@ -489,6 +482,29 @@ class ColorToolButton(Gtk.ToolItem): palette_invoker = GObject.property( type=object, setter=set_palette_invoker, getter=get_palette_invoker) + def set_expanded(self, expanded): + box = self.toolbar_box + if not box: + return + + if not expanded: + self._palette_invoker.notify_popdown() + return + + if box.expanded_button is not None: + box.expanded_button.queue_draw() + if box.expanded_button != self: + box.expanded_button.set_expanded(False) + box.expanded_button = self + + def get_toolbar_box(self): + parent = self.get_parent() + if not hasattr(parent, 'owner'): + return None + return parent.owner + + toolbar_box = property(get_toolbar_box) + def set_color(self, color): self.get_child().props.color = color diff --git a/src/sugar3/graphics/palettewindow.py b/src/sugar3/graphics/palettewindow.py index 0283551e..cadb4fee 100644 --- a/src/sugar3/graphics/palettewindow.py +++ b/src/sugar3/graphics/palettewindow.py @@ -24,6 +24,7 @@ STABLE. """ import logging +import math from gi.repository import Gdk from gi.repository import Gtk @@ -655,25 +656,29 @@ class PaletteWindow(GObject.GObject): self.popdown() def _invoker_mouse_enter_cb(self, invoker): - self.on_invoker_enter() + if not self._invoker.locked: + self.on_invoker_enter() def _invoker_mouse_leave_cb(self, invoker): - self.on_invoker_leave() + if not self._invoker.locked: + self.on_invoker_leave() def _invoker_right_click_cb(self, invoker): self.popup(immediate=True, state=self.SECONDARY) def _invoker_toggle_state_cb(self, invoker): - if self.is_up(): + if self.is_up() and self._palette_state == self.SECONDARY: self.popdown(immediate=True) else: self.popup(immediate=True, state=self.SECONDARY) def __enter_notify_cb(self, widget): - self.on_enter() + if not self._invoker.locked: + self.on_enter() def __leave_notify_cb(self, widget): - self.on_leave() + if not self._invoker.locked: + self.on_leave() def __show_cb(self, widget): if self._invoker is not None: @@ -774,6 +779,8 @@ class Invoker(GObject.GObject): self._palette = None self._cache_palette = True self._toggle_palette = False + self._lock_palette = False + self.locked = False def attach(self, parent): self.parent = parent @@ -1012,6 +1019,18 @@ class Invoker(GObject.GObject): button left click/touch tap. Defaults to False. """ + def get_lock_palette(self): + return self._lock_palette + + def set_lock_palette(self, lock_palette): + self._lock_palette = lock_palette + + lock_palette = GObject.property(type=object, setter=set_lock_palette, + getter=get_lock_palette) + """Whether the invoker will lock the Palette and + ignore mouse events. Defaults to False. + """ + def __palette_popdown_cb(self, palette): if not self.props.cache_palette: self.set_palette(None) @@ -1023,11 +1042,13 @@ class WidgetInvoker(Invoker): Invoker.__init__(self) self._widget = None + self._expanded = False self._enter_hid = None self._leave_hid = None self._release_hid = None self._click_hid = None self._touch_hid = None + self._draw_hid = None self._long_pressed_recognized = False self._long_pressed_hid = None self._long_pressed_controller = SugarGestures.LongPressController() @@ -1054,11 +1075,13 @@ class WidgetInvoker(Invoker): self.__touch_event_cb) self._release_hid = self._widget.connect('button-release-event', self.__button_release_event_cb) + self._draw_hid = self._widget.connect_after('draw', self.__drawing_cb) self._long_pressed_hid = self._long_pressed_controller.connect( 'pressed', self.__long_pressed_event_cb, self._widget) self._long_pressed_controller.attach(self._widget, SugarGestures.EventControllerFlags.NONE) + self.attach(parent) def detach(self): @@ -1066,6 +1089,7 @@ class WidgetInvoker(Invoker): self._widget.disconnect(self._enter_hid) self._widget.disconnect(self._leave_hid) self._widget.disconnect(self._release_hid) + self._widget.disconnect(self._draw_hid) if self._click_hid: self._widget.disconnect(self._click_hid) self._widget.disconnect(self._touch_hid) @@ -1126,6 +1150,11 @@ class WidgetInvoker(Invoker): return False def __click_event_cb(self, button): + if self.props.lock_palette: + if not self.locked: + self.locked = True + self.parent.set_expanded(True) + if self.props.toggle_palette: self.notify_toggle_state() @@ -1151,6 +1180,7 @@ class WidgetInvoker(Invoker): self._widget.queue_draw() def notify_popdown(self): + self.locked = False Invoker.notify_popdown(self) self._widget.queue_draw() @@ -1158,6 +1188,20 @@ class WidgetInvoker(Invoker): return self._widget widget = GObject.property(type=object, getter=_get_widget, setter=None) + def __drawing_cb(self, widget, cr): + if not self.props.lock_palette: + return False + alloc = widget.get_allocation() + arrow_size = style.TOOLBAR_ARROW_SIZE / 2 + y = alloc.height - arrow_size + x = (alloc.width - arrow_size) / 2 + context = widget.get_style_context() + context.add_class('toolitem') + if self.locked: + Gtk.render_arrow(context, cr, 0, x, y, arrow_size) + else: + Gtk.render_arrow(context, cr, math.pi, x, y, arrow_size) + class CursorInvoker(Invoker): diff --git a/src/sugar3/graphics/toolbarbox.py b/src/sugar3/graphics/toolbarbox.py index 16834032..8c4e644b 100644 --- a/src/sugar3/graphics/toolbarbox.py +++ b/src/sugar3/graphics/toolbarbox.py @@ -89,6 +89,7 @@ class ToolbarButton(ToolButton): def set_expanded(self, expanded): self.popdown() + palettegroup.popdown_all() if self.page is None or self.is_expanded() == expanded: return