1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
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)
|