From a648956f7df33d0a359ed90a83cc01f08919f6b8 Mon Sep 17 00:00:00 2001 From: Aleksey Lim Date: Thu, 29 Jul 2010 17:53:50 +0000 Subject: Embody toolkit dependency --- (limited to 'toolkit/toolbarbox.py') diff --git a/toolkit/toolbarbox.py b/toolkit/toolbarbox.py new file mode 100644 index 0000000..7172b8b --- /dev/null +++ b/toolkit/toolbarbox.py @@ -0,0 +1,333 @@ +# Copyright (C) 2009, Aleksey Lim +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +import gtk +import gobject + +from sugar.graphics import style +from sugar.graphics.toolbutton import ToolButton +from sugar.graphics import palettegroup + +from toolkit.internals.palettewindow import PaletteWindow +from toolkit.internals.palettewindow import ToolInvoker + + +_ARROW_SIZE = style.zoom(24) +_LINE_WIDTH = 2 + +class ToolbarButton(ToolButton): + + def __init__(self, page=None, **kwargs): + ToolButton.__init__(self, **kwargs) + + self.page_widget = None + + self.set_page(page) + + self.connect('clicked', + lambda widget: self.set_expanded(not self.is_expanded())) + self.connect('size-allocate', self.__size_allocate_cb) + + def get_toolbar_box(self): + if not hasattr(self.parent, 'owner'): + return None + return self.parent.owner + + toolbar_box = property(get_toolbar_box) + + def get_page(self): + if self.page_widget is None: + return None + return _get_embedded_page(self.page_widget) + + def set_page(self, page): + if page is None: + self.page_widget = None + return + + self.page_widget, alignment_ = _embed_page(_Box, page) + w_, h = gtk.icon_size_lookup(gtk.ICON_SIZE_LARGE_TOOLBAR) + page.show() + + if self.props.palette is None: + self.props.palette = _ToolbarPalette(invoker=ToolInvoker(self)) + self._move_page_to_palette() + + page = gobject.property(type=object, getter=get_page, setter=set_page) + + def is_in_palette(self): + return self.page is not None and \ + self.page_widget.parent == self.props.palette + + def is_expanded(self): + return self.page is not None and \ + not self.is_in_palette() + + def popdown(self): + if self.props.palette is not None: + self.props.palette.popdown(immediate=True) + + def set_expanded(self, expanded): + self.popdown() + + if self.page is None or self.is_expanded() == expanded: + return + + if not expanded: + self._move_page_to_palette() + return + + box = self.toolbar_box + + if box.expanded_button is not None: + if box.expanded_button.window is not None: + # need to redraw it to erase arrow + box.expanded_button.window.invalidate_rect(None, True) + box.expanded_button.set_expanded(False) + box.expanded_button = self + + self._unparent() + + self.modify_bg(gtk.STATE_NORMAL, box.background) + _setup_page(self.page_widget, box.background, box.props.padding) + box.pack_start(self.page_widget) + + def _move_page_to_palette(self): + if self.is_in_palette(): + return + + self._unparent() + + if isinstance(self.props.palette, _ToolbarPalette): + self.props.palette.add(self.page_widget) + + def _unparent(self): + if self.page_widget.parent is None: + return + self.page_widget.parent.remove(self.page_widget) + + def do_expose_event(self, event): + if not self.is_expanded() or self.props.palette is not None and \ + self.props.palette.is_up(): + ToolButton.do_expose_event(self, event) + _paint_arrow(self, event, gtk.ARROW_DOWN) + return + + alloc = self.allocation + + self.get_style().paint_box(event.window, + gtk.STATE_NORMAL, gtk.SHADOW_IN, event.area, self, + 'palette-invoker', alloc.x, 0, + alloc.width, alloc.height + _LINE_WIDTH) + + if self.child.state != gtk.STATE_PRELIGHT: + self.get_style().paint_box(event.window, + gtk.STATE_NORMAL, gtk.SHADOW_NONE, event.area, self, None, + alloc.x + _LINE_WIDTH, _LINE_WIDTH, + alloc.width - _LINE_WIDTH * 2, alloc.height) + + gtk.ToolButton.do_expose_event(self, event) + _paint_arrow(self, event, gtk.ARROW_UP) + + def __size_allocate_cb(self, button, allocation): + if self.page_widget is not None: + self.page_widget.set_size_request(-1, allocation.height) + + +class ToolbarBox(gtk.VBox): + + def __init__(self, padding=style.TOOLBOX_HORIZONTAL_PADDING): + gtk.VBox.__init__(self) + self._expanded_button_index = -1 + self.background = None + + self._toolbar = gtk.Toolbar() + self._toolbar.owner = self + self._toolbar.connect('remove', self.__remove_cb) + + self._toolbar_widget, self._toolbar_alignment = \ + _embed_page(gtk.EventBox, self._toolbar) + self.pack_start(self._toolbar_widget) + + self.props.padding = padding + self.modify_bg(gtk.STATE_NORMAL, + style.COLOR_TOOLBAR_GREY.get_gdk_color()) + + def get_toolbar(self): + return self._toolbar + + toolbar = property(get_toolbar) + + def get_expanded_button(self): + if self._expanded_button_index == -1: + return None + return self.toolbar.get_nth_item(self._expanded_button_index) + + def set_expanded_button(self, button): + if not button in self.toolbar: + self._expanded_button_index = -1 + return + self._expanded_button_index = self.toolbar.get_item_index(button) + + expanded_button = property(get_expanded_button, set_expanded_button) + + def get_padding(self): + return self._toolbar_alignment.props.left_padding + + def set_padding(self, pad): + self._toolbar_alignment.set_padding(0, 0, pad, pad) + + padding = gobject.property(type=object, + getter=get_padding, setter=set_padding) + + def modify_bg(self, state, color): + if state == gtk.STATE_NORMAL: + self.background = color + self._toolbar_widget.modify_bg(state, color) + self.toolbar.modify_bg(state, color) + + def __remove_cb(self, sender, button): + if not isinstance(button, ToolbarButton): + return + button.popdown() + if button == self.expanded_button: + self.remove(button.page_widget) + self._expanded_button_index = -1 + + +class _ToolbarPalette(PaletteWindow): + + def __init__(self, **kwargs): + PaletteWindow.__init__(self, **kwargs) + self.set_border_width(0) + self._has_focus = False + + group = palettegroup.get_group('default') + group.connect('popdown', self.__group_popdown_cb) + self.set_group_id('toolbarbox') + + def get_expanded_button(self): + return self.invoker.parent + + expanded_button = property(get_expanded_button) + + def on_invoker_enter(self): + PaletteWindow.on_invoker_enter(self) + self._set_focus(True) + + def on_invoker_leave(self): + PaletteWindow.on_invoker_leave(self) + self._set_focus(False) + + def on_enter(self, event): + PaletteWindow.on_enter(self, event) + self._set_focus(True) + + def on_leave(self, event): + PaletteWindow.on_enter(self, event) + self._set_focus(False) + + def _set_focus(self, new_focus): + self._has_focus = new_focus + if not self._has_focus: + group = palettegroup.get_group('default') + if not group.is_up(): + self.popdown() + + def do_size_request(self, requisition): + gtk.Window.do_size_request(self, requisition) + requisition.width = max(requisition.width, + gtk.gdk.screen_width()) + + def popup(self, immediate=False): + button = self.expanded_button + if button.is_expanded(): + return + box = button.toolbar_box + _setup_page(button.page_widget, style.COLOR_BLACK.get_gdk_color(), + box.props.padding) + PaletteWindow.popup(self, immediate) + + def __group_popdown_cb(self, group): + if not self._has_focus: + self.popdown(immediate=True) + + +class _Box(gtk.EventBox): + + def __init__(self): + gtk.EventBox.__init__(self) + self.connect('expose-event', self.do_expose_event) + self.set_app_paintable(True) + + def do_expose_event(self, widget, event): + if self.parent.expanded_button is None: + return + alloc = self.parent.expanded_button.allocation + self.get_style().paint_box(event.window, + gtk.STATE_NORMAL, gtk.SHADOW_IN, event.area, self, + 'palette-invoker', -_LINE_WIDTH, 0, + self.allocation.width + _LINE_WIDTH * 2, + self.allocation.height + _LINE_WIDTH) + self.get_style().paint_box(event.window, + gtk.STATE_NORMAL, gtk.SHADOW_NONE, event.area, self, None, + alloc.x + _LINE_WIDTH, 0, + alloc.width - _LINE_WIDTH * 2, _LINE_WIDTH) + + +def _setup_page(page_widget, color, hpad): + vpad = _LINE_WIDTH + page_widget.child.set_padding(vpad, vpad, hpad, hpad) + + page = _get_embedded_page(page_widget) + page.modify_bg(gtk.STATE_NORMAL, color) + if isinstance(page, gtk.Container): + for i in page.get_children(): + i.modify_bg(gtk.STATE_INSENSITIVE, color) + + page_widget.modify_bg(gtk.STATE_NORMAL, color) + page_widget.modify_bg(gtk.STATE_PRELIGHT, color) + + +def _embed_page(box_class, page): + page.show() + + alignment = gtk.Alignment(0.0, 0.0, 1.0, 1.0) + alignment.add(page) + alignment.show() + + page_widget = box_class() + page_widget.modify_bg(gtk.STATE_ACTIVE, + style.COLOR_BUTTON_GREY.get_gdk_color()) + page_widget.add(alignment) + page_widget.show() + + return (page_widget, alignment) + + +def _get_embedded_page(page_widget): + return page_widget.child.child + + +def _paint_arrow(widget, event, arrow_type): + alloc = widget.allocation + x = alloc.x + alloc.width / 2 - _ARROW_SIZE / 2 + y = alloc.y + alloc.height - int(_ARROW_SIZE * .85) + + widget.get_style().paint_arrow(event.window, + gtk.STATE_NORMAL, gtk.SHADOW_NONE, event.area, widget, + None, arrow_type, True, x, y, _ARROW_SIZE, _ARROW_SIZE) -- cgit v0.9.1