From b887e504eb789550cd07290c524637b3f6a4e1c1 Mon Sep 17 00:00:00 2001
From: Simon Schampijer <simon@laptop.org>
Date: Thu, 15 Nov 2012 18:09:00 +0100
Subject: [PATCH toolkit-gtk3] Add support for locking Palettes
This adds a property that indicates that a Palette should
behave in a locking manner. The behaviour is the same
as with the secondary Toolbars: when you hover over the invoking
widget the Palette will popdown and react to mouse movements,
leaving the invoker area or the Palette itself will popdown
the Palette again. When you click the invoking widget
the Palette will be locked. You have to unlock it again
to pop it down.
The DescriptionPalette can be seen as a good example, also
the Colorbutton will work that way.
When a secondary toolbar is unlocked we do force that the
open Palettes are closed.
---
src/sugar3/activity/widgets.py | 1 +
src/sugar3/graphics/colorbutton.py | 11 ++------
src/sugar3/graphics/palettewindow.py | 55 +++++++++++++++++++++++++++++++++---
src/sugar3/graphics/toolbarbox.py | 1 +
4 files changed, 55 insertions(+), 13 deletions(-)
diff --git a/src/sugar3/activity/widgets.py b/src/sugar3/activity/widgets.py
index 03b2415..54b64a4 100644
a
|
b
|
class DescriptionItem(Gtk.ToolItem): |
228 | 228 | description_button.show() |
229 | 229 | description_button.set_tooltip(_('Description')) |
230 | 230 | description_button.palette_invoker.props.toggle_palette = True |
| 231 | description_button.palette_invoker.props.lock_palette = True |
231 | 232 | description_button.props.hide_tooltip_on_click = False |
232 | 233 | self._palette = description_button.get_palette() |
233 | 234 | |
diff --git a/src/sugar3/graphics/colorbutton.py b/src/sugar3/graphics/colorbutton.py
index 823fd61..e85157c 100644
a
|
b
|
class _ColorButton(Gtk.Button): |
112 | 112 | return '#%.2X%.2X%.2X' % (fg_color.red * 255, fg_color.green * 255, |
113 | 113 | fg_color.blue * 255) |
114 | 114 | |
115 | | def do_clicked(self): |
116 | | if self._palette: |
117 | | if not self._palette.is_up(): |
118 | | self._palette.popup(immediate=True, |
119 | | state=self._palette.SECONDARY) |
120 | | else: |
121 | | self._palette.popdown(immediate=True) |
122 | | return True |
123 | | |
124 | 115 | def set_color(self, color): |
125 | 116 | assert isinstance(color, Gdk.Color) |
126 | 117 | |
… |
… |
class ColorToolButton(Gtk.ToolItem): |
451 | 442 | color_button.icon_size = Gtk.IconSize.LARGE_TOOLBAR |
452 | 443 | |
453 | 444 | self._palette_invoker.attach_tool(self) |
| 445 | self._palette_invoker.props.toggle_palette = True |
| 446 | self._palette_invoker.props.lock_palette = True |
454 | 447 | |
455 | 448 | # This widget just proxies the following properties to the colorbutton |
456 | 449 | color_button.connect('notify::color', self.__notify_change) |
diff --git a/src/sugar3/graphics/palettewindow.py b/src/sugar3/graphics/palettewindow.py
index 0283551..05873b9 100644
a
|
b
|
STABLE. |
24 | 24 | """ |
25 | 25 | |
26 | 26 | import logging |
| 27 | import math |
27 | 28 | |
28 | 29 | from gi.repository import Gdk |
29 | 30 | from gi.repository import Gtk |
… |
… |
class PaletteWindow(GObject.GObject): |
655 | 656 | self.popdown() |
656 | 657 | |
657 | 658 | def _invoker_mouse_enter_cb(self, invoker): |
658 | | self.on_invoker_enter() |
| 659 | if not self._invoker.locked: |
| 660 | self.on_invoker_enter() |
659 | 661 | |
660 | 662 | def _invoker_mouse_leave_cb(self, invoker): |
661 | | self.on_invoker_leave() |
| 663 | if not self._invoker.locked: |
| 664 | self.on_invoker_leave() |
662 | 665 | |
663 | 666 | def _invoker_right_click_cb(self, invoker): |
664 | 667 | self.popup(immediate=True, state=self.SECONDARY) |
… |
… |
class PaletteWindow(GObject.GObject): |
670 | 673 | self.popup(immediate=True, state=self.SECONDARY) |
671 | 674 | |
672 | 675 | def __enter_notify_cb(self, widget): |
673 | | self.on_enter() |
| 676 | if not self._invoker.locked: |
| 677 | self.on_enter() |
674 | 678 | |
675 | 679 | def __leave_notify_cb(self, widget): |
676 | | self.on_leave() |
| 680 | if not self._invoker.locked: |
| 681 | self.on_leave() |
677 | 682 | |
678 | 683 | def __show_cb(self, widget): |
679 | 684 | if self._invoker is not None: |
… |
… |
class Invoker(GObject.GObject): |
774 | 779 | self._palette = None |
775 | 780 | self._cache_palette = True |
776 | 781 | self._toggle_palette = False |
| 782 | self._lock_palette = False |
| 783 | self.locked = False |
777 | 784 | |
778 | 785 | def attach(self, parent): |
779 | 786 | self.parent = parent |
… |
… |
class Invoker(GObject.GObject): |
1012 | 1019 | button left click/touch tap. Defaults to False. |
1013 | 1020 | """ |
1014 | 1021 | |
| 1022 | def get_lock_palette(self): |
| 1023 | return self._lock_palette |
| 1024 | |
| 1025 | def set_lock_palette(self, lock_palette): |
| 1026 | self._lock_palette = lock_palette |
| 1027 | |
| 1028 | lock_palette = GObject.property(type=object, setter=set_lock_palette, |
| 1029 | getter=get_lock_palette) |
| 1030 | """Whether the invoker will lock the Palette and |
| 1031 | ignore mouse events. Defaults to False. |
| 1032 | """ |
| 1033 | |
1015 | 1034 | def __palette_popdown_cb(self, palette): |
1016 | 1035 | if not self.props.cache_palette: |
1017 | 1036 | self.set_palette(None) |
… |
… |
class WidgetInvoker(Invoker): |
1023 | 1042 | Invoker.__init__(self) |
1024 | 1043 | |
1025 | 1044 | self._widget = None |
| 1045 | self._expanded = False |
1026 | 1046 | self._enter_hid = None |
1027 | 1047 | self._leave_hid = None |
1028 | 1048 | self._release_hid = None |
1029 | 1049 | self._click_hid = None |
1030 | 1050 | self._touch_hid = None |
| 1051 | self._draw_hid = None |
1031 | 1052 | self._long_pressed_recognized = False |
1032 | 1053 | self._long_pressed_hid = None |
1033 | 1054 | self._long_pressed_controller = SugarGestures.LongPressController() |
… |
… |
class WidgetInvoker(Invoker): |
1054 | 1075 | self.__touch_event_cb) |
1055 | 1076 | self._release_hid = self._widget.connect('button-release-event', |
1056 | 1077 | self.__button_release_event_cb) |
| 1078 | self._draw_hid = self._widget.connect_after('draw', self.__drawing_cb) |
1057 | 1079 | |
1058 | 1080 | self._long_pressed_hid = self._long_pressed_controller.connect( |
1059 | 1081 | 'pressed', self.__long_pressed_event_cb, self._widget) |
… |
… |
class WidgetInvoker(Invoker): |
1066 | 1088 | self._widget.disconnect(self._enter_hid) |
1067 | 1089 | self._widget.disconnect(self._leave_hid) |
1068 | 1090 | self._widget.disconnect(self._release_hid) |
| 1091 | self._widget.disconnect(self._draw_hid) |
1069 | 1092 | if self._click_hid: |
1070 | 1093 | self._widget.disconnect(self._click_hid) |
1071 | 1094 | self._widget.disconnect(self._touch_hid) |
… |
… |
class WidgetInvoker(Invoker): |
1127 | 1150 | |
1128 | 1151 | def __click_event_cb(self, button): |
1129 | 1152 | if self.props.toggle_palette: |
| 1153 | if self.locked == False: |
| 1154 | self.locked = True |
| 1155 | else: |
| 1156 | self.locked = False |
1130 | 1157 | self.notify_toggle_state() |
1131 | 1158 | |
1132 | 1159 | def __button_release_event_cb(self, widget, event): |
1133 | 1160 | if event.button == 1 and not self._click_hid: |
1134 | 1161 | if self.props.toggle_palette: |
| 1162 | if self.locked == False: |
| 1163 | self.locked = True |
| 1164 | else: |
| 1165 | self.locked = False |
1135 | 1166 | self.notify_toggle_state() |
1136 | 1167 | elif event.button == 3: |
1137 | 1168 | self.notify_right_click() |
… |
… |
class WidgetInvoker(Invoker): |
1148 | 1179 | |
1149 | 1180 | def notify_popup(self): |
1150 | 1181 | Invoker.notify_popup(self) |
| 1182 | self._expanded = True |
1151 | 1183 | self._widget.queue_draw() |
1152 | 1184 | |
1153 | 1185 | def notify_popdown(self): |
1154 | 1186 | Invoker.notify_popdown(self) |
| 1187 | self._expanded = False |
1155 | 1188 | self._widget.queue_draw() |
1156 | 1189 | |
1157 | 1190 | def _get_widget(self): |
1158 | 1191 | return self._widget |
1159 | 1192 | widget = GObject.property(type=object, getter=_get_widget, setter=None) |
1160 | 1193 | |
| 1194 | def __drawing_cb(self, widget, cr): |
| 1195 | if not self.props.lock_palette: |
| 1196 | return False |
| 1197 | alloc = widget.get_allocation() |
| 1198 | arrow_size = style.TOOLBAR_ARROW_SIZE / 2 |
| 1199 | y = alloc.height - arrow_size |
| 1200 | x = (alloc.width - arrow_size) / 2 |
| 1201 | context = widget.get_style_context() |
| 1202 | context.add_class('toolitem') |
| 1203 | if self._expanded: |
| 1204 | Gtk.render_arrow(context, cr, 0, x, y, arrow_size) |
| 1205 | else: |
| 1206 | Gtk.render_arrow(context, cr, math.pi, x, y, arrow_size) |
| 1207 | |
1161 | 1208 | |
1162 | 1209 | class CursorInvoker(Invoker): |
1163 | 1210 | |
diff --git a/src/sugar3/graphics/toolbarbox.py b/src/sugar3/graphics/toolbarbox.py
index 1683403..8c4e644 100644
a
|
b
|
class ToolbarButton(ToolButton): |
89 | 89 | |
90 | 90 | def set_expanded(self, expanded): |
91 | 91 | self.popdown() |
| 92 | palettegroup.popdown_all() |
92 | 93 | |
93 | 94 | if self.page is None or self.is_expanded() == expanded: |
94 | 95 | return |