diff options
Diffstat (limited to 'sugar-toolkit/src/sugar/tutorius/dragbox.py')
-rw-r--r-- | sugar-toolkit/src/sugar/tutorius/dragbox.py | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/sugar-toolkit/src/sugar/tutorius/dragbox.py b/sugar-toolkit/src/sugar/tutorius/dragbox.py new file mode 100644 index 0000000..d84e4ee --- /dev/null +++ b/sugar-toolkit/src/sugar/tutorius/dragbox.py @@ -0,0 +1,120 @@ +# Copyright (C) 2009, Tutorius.org +# +# 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 +""" +This module defines the DragBox class, representing a gtk.Layout like container +which supports a "children dragging mode". +""" + +import gtk + +class DragBox(gtk.EventBox): + """ + A DragBox represents a gtk container whose child object can be arbitrarily + placed, like for a gtk.Layout. However DragBox implements a child "dragging" + mode which allows the user to freely move immediate children of the DragBox. + + This can be toggled by the dragMode property (default to False) + + Default behavior is to keep children at minimal size, as returned by + a call to gtk.Widget.get_size(). + + """ + def __init__(self): + gtk.EventBox.__init__(self) + + self.set_above_child(False) + self.connect("motion-notify-event", self._on_mouse_evt) + self.connect("button-press-event", self._on_mouse_evt) + self.connect("button-release-event", self._on_mouse_evt) + + self._drag_mode = False + self._dragging = None # the object being dragged, or None + self._last_mouse_pos = None # last known mouse position (win. relative) + + self._layout = gtk.Layout() + self.add(self._layout) + + def attach(self, widget, xPos=0, yPos=0, size=None, resizable=False): + """ + Adds the child to the EventBox hierarchy. + widget is expected to be a displayable gtk.Widget and will respond + to the dragMode by being dragable. + """ + # TODO handle child and set size + self._layout.put(child_widget=widget, x=xPos, y=yPos) + + def show(self): + gtk.EventBox.show(self) + self._layout.show() + + def hide(self): + gtk.EventBox.hide(self) + self._layout.hide() + + def _on_mouse_evt(self, widget, event, data=None): + """ + Callback registered on mouse events. + _on_mouse_evt does the actual child selection and moving + """ + if not self._drag_mode: + return + + x, y = event.get_coords() + + if self._dragging is not None and event.type is gtk.gdk.MOTION_NOTIFY: + child = self._dragging.get_allocation() + self._layout.move(self._dragging, + int(child.x+x-self._last_mouse_pos[0]), + int(child.y+y-self._last_mouse_pos[1])) + self._last_mouse_pos = event.get_coords() + # FIXME scale layout or constraint dragging to DragBox + + elif self._dragging is None and event.type is gtk.gdk.BUTTON_PRESS: + # iterate in revese as last drawn child is over the others + for child in reversed(self._layout.get_children()): + rect = child.get_allocation() + if x >= rect.x and x < rect.x+rect.width \ + and y >= rect.y and y < rect.y+rect.height: + self._dragging = child + # Common interface paradigm is that selecting an item + # goes to top of stack it so we do just that. + self._layout.remove(child) + self._layout.put(child, rect.x, rect.y) + break + self._last_mouse_pos = event.get_coords() + # TODO add conditional restack child + + elif self._dragging is not None \ + and event.type is gtk.gdk.BUTTON_RELEASE: + self._dragging = None + + def _set_drag_mode(self, value): + if (not self._drag_mode) and value: + self.set_above_child(True) + elif self._drag_mode and (not value): + self.set_above_child(False) + + self._drag_mode = value + + def _get_drag_mode(self): + return self._drag_mode + + dragMode = property(fset=_set_drag_mode, fget=_get_drag_mode, + doc="Defines whether widgets in DragBox can be mouse dragged.") + + # TODO set child properties (list_child_properties) + + |