Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/sugar-toolkit/src/sugar/tutorius/dragbox.py
diff options
context:
space:
mode:
Diffstat (limited to 'sugar-toolkit/src/sugar/tutorius/dragbox.py')
-rw-r--r--sugar-toolkit/src/sugar/tutorius/dragbox.py120
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)
+
+