]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/lib/ogl/_canvas.py
1 # -*- coding: iso-8859-1 -*-
2 #----------------------------------------------------------------------------
4 # Purpose: The canvas class
6 # Author: Pierre Hjälm (from C++ original by Julian Smart)
10 # Copyright: (c) 2004 Pierre Hjälm - 1998 Julian Smart
11 # Licence: wxWindows license
12 #----------------------------------------------------------------------------
15 from _lines
import LineShape
16 from _composit
import *
18 NoDragging
, StartDraggingLeft
, ContinueDraggingLeft
, StartDraggingRight
, ContinueDraggingRight
= 0, 1, 2, 3, 4
20 KEY_SHIFT
, KEY_CTRL
= 1, 2
24 # Helper function: True if 'contains' wholly contains 'contained'.
25 def WhollyContains(contains
, contained
):
26 xp1
, yp1
= contains
.GetX(), contains
.GetY()
27 xp2
, yp2
= contained
.GetX(), contained
.GetY()
29 w1
, h1
= contains
.GetBoundingBoxMax()
30 w2
, h2
= contained
.GetBoundingBoxMax()
32 left1
= xp1
- w1
/ 2.0
34 right1
= xp1
+ w1
/ 2.0
35 bottom1
= yp1
+ h1
/ 2.0
37 left2
= xp2
- w2
/ 2.0
39 right2
= xp2
+ w2
/ 2.0
40 bottom2
= yp2
+ h2
/ 2.0
42 return ((left1
<= left2
) and (top1
<= top2
) and (right1
>= right2
) and (bottom1
>= bottom2
))
46 class ShapeCanvas(wx
.ScrolledWindow
):
47 def __init__(self
, parent
= None, id = -1, pos
= wx
.DefaultPosition
, size
= wx
.DefaultSize
, style
= wx
.BORDER
, name
= "ShapeCanvas"):
48 wx
.ScrolledWindow
.__init
__(self
, parent
, id, pos
, size
, style
, name
)
50 self
._shapeDiagram
= None
51 self
._dragState
= NoDragging
52 self
._draggedShape
= None
57 self
._checkTolerance
= True
59 wx
.EVT_PAINT(self
, self
.OnPaint
)
60 wx
.EVT_MOUSE_EVENTS(self
, self
.OnMouseEvent
)
62 def SetDiagram(self
, diag
):
63 self
._shapeDiagram
= diag
66 return self
._shapeDiagram
68 def OnPaint(self
, evt
):
72 dc
.SetBackground(wx
.Brush(self
.GetBackgroundColour(), wx
.SOLID
))
76 self
.GetDiagram().Redraw(dc
)
78 def OnMouseEvent(self
, evt
):
79 dc
= wx
.ClientDC(self
)
82 x
, y
= evt
.GetLogicalPosition(dc
)
90 dragging
= evt
.Dragging()
92 # Check if we're within the tolerance for mouse movements.
93 # If we're very close to the position we started dragging
94 # from, this may not be an intentional drag at all.
96 if self
._checkTolerance
:
97 # the difference between two logical coordinates is a logical coordinate
98 dx
= abs(x
- self
._firstDragX
)
99 dy
= abs(y
- self
._firstDragY
)
100 toler
= self
.GetDiagram().GetMouseTolerance()
101 if (dx
<= toler
) and (dy
<= toler
):
103 # If we've ignored the tolerance once, then ALWAYS ignore
104 # tolerance in this drag, even if we come back within
105 # the tolerance range.
106 self
._checkTolerance
= False
108 # Dragging - note that the effect of dragging is left entirely up
109 # to the object, so no movement is done unless explicitly done by
111 if dragging
and self
._draggedShape
and self
._dragState
== StartDraggingLeft
:
112 self
._dragState
= ContinueDraggingLeft
114 # If the object isn't m_draggable, transfer message to canvas
115 if self
._draggedShape
.Draggable():
116 self
._draggedShape
.GetEventHandler().OnBeginDragLeft(x
, y
, keys
, self
._draggedAttachment
)
118 self
._draggedShape
= None
119 self
.OnBeginDragLeft(x
, y
, keys
)
121 self
._oldDragX
, self
._oldDragY
= x
, y
123 elif dragging
and self
._draggedShape
and self
._dragState
== ContinueDraggingLeft
:
125 self
._draggedShape
.GetEventHandler().OnDragLeft(False, self
._oldDragX
, self
._oldDragY
, keys
, self
._draggedAttachment
)
126 self
._draggedShape
.GetEventHandler().OnDragLeft(True, x
, y
, keys
, self
._draggedAttachment
)
127 self
._oldDragX
, self
._oldDragY
= x
, y
129 elif evt
.LeftUp() and self
._draggedShape
and self
._dragState
== ContinueDraggingLeft
:
130 self
._dragState
= NoDragging
131 self
._checkTolerance
= True
133 self
._draggedShape
.GetEventHandler().OnDragLeft(False, self
._oldDragX
, self
._oldDragY
, keys
, self
._draggedAttachment
)
134 self
._draggedShape
.GetEventHandler().OnEndDragLeft(x
, y
, keys
, self
._draggedAttachment
)
135 self
._draggedShape
= None
137 elif dragging
and self
._draggedShape
and self
._dragState
== StartDraggingRight
:
138 self
._dragState
= ContinueDraggingRight
139 if self
._draggedShape
.Draggable
:
140 self
._draggedShape
.GetEventHandler().OnBeginDragRight(x
, y
, keys
, self
._draggedAttachment
)
142 self
._draggedShape
= None
143 self
.OnBeginDragRight(x
, y
, keys
)
144 self
._oldDragX
, self
._oldDragY
= x
, y
146 elif dragging
and self
._draggedShape
and self
._dragState
== ContinueDraggingRight
:
148 self
._draggedShape
.GetEventHandler().OnDragRight(False, self
._oldDragX
, self
._oldDragY
, keys
, self
._draggedAttachment
)
149 self
._draggedShape
.GetEventHandler().OnDragRight(True, x
, y
, keys
, self
._draggedAttachment
)
150 self
._oldDragX
, self
._oldDragY
= x
, y
152 elif evt
.RightUp() and self
._draggedShape
and self
._dragState
== ContinueDraggingRight
:
153 self
._dragState
= NoDragging
154 self
._checkTolerance
= True
156 self
._draggedShape
.GetEventHandler().OnDragRight(False, self
._oldDragX
, self
._oldDragY
, keys
, self
._draggedAttachment
)
157 self
._draggedShape
.GetEventHandler().OnEndDragRight(x
, y
, keys
, self
._draggedAttachment
)
158 self
._draggedShape
= None
160 # All following events sent to canvas, not object
161 elif dragging
and not self
._draggedShape
and self
._dragState
== StartDraggingLeft
:
162 self
._dragState
= ContinueDraggingLeft
163 self
.OnBeginDragLeft(x
, y
, keys
)
164 self
._oldDragX
, self
._oldDragY
= x
, y
166 elif dragging
and not self
._draggedShape
and self
._dragState
== ContinueDraggingLeft
:
168 self
.OnDragLeft(False, self
._oldDragX
, self
._oldDragY
, keys
)
169 self
.OnDragLeft(True, x
, y
, keys
)
170 self
._oldDragX
, self
._oldDragY
= x
, y
172 elif evt
.LeftUp() and not self
._draggedShape
and self
._dragState
== ContinueDraggingLeft
:
173 self
._dragState
= NoDragging
174 self
._checkTolerance
= True
176 self
.OnDragLeft(False, self
._oldDragX
, self
._oldDragY
, keys
)
177 self
.OnEndDragLeft(x
, y
, keys
)
178 self
._draggedShape
= None
180 elif dragging
and not self
._draggedShape
and self
._dragState
== StartDraggingRight
:
181 self
._dragState
= ContinueDraggingRight
182 self
.OnBeginDragRight(x
, y
, keys
)
183 self
._oldDragX
, self
._oldDragY
= x
, y
185 elif dragging
and not self
._draggedShape
and self
._dragState
== ContinueDraggingRight
:
187 self
.OnDragRight(False, self
._oldDragX
, self
._oldDragY
, keys
)
188 self
.OnDragRight(True, x
, y
, keys
)
189 self
._oldDragX
, self
._oldDragY
= x
, y
191 elif evt
.RightUp() and not self
._draggedShape
and self
._dragState
== ContinueDraggingRight
:
192 self
._dragState
= NoDragging
193 self
._checkTolerance
= True
195 self
.OnDragRight(False, self
._oldDragX
, self
._oldDragY
, keys
)
196 self
.OnEndDragRight(x
, y
, keys
)
197 self
._draggedShape
= None
199 # Non-dragging events
201 self
._checkTolerance
= True
203 # Find the nearest object
206 nearest_object
, attachment
= self
.FindShape(x
, y
)
207 if nearest_object
: # Object event
209 self
._draggedShape
= nearest_object
210 self
._draggedAttachment
= attachment
211 self
._dragState
= StartDraggingLeft
216 # N.B. Only register a click if the same object was
217 # identified for down *and* up.
218 if nearest_object
== self
._draggedShape
:
219 nearest_object
.GetEventHandler().OnLeftClick(x
, y
, keys
, attachment
)
220 self
._draggedShape
= None
221 self
._dragState
= NoDragging
223 elif evt
.LeftDClick():
224 nearest_object
.GetEventHandler().OnLeftDoubleClick(x
, y
, keys
, attachment
)
225 self
._draggedShape
= None
226 self
._dragState
= NoDragging
228 elif evt
.RightDown():
229 self
._draggedShape
= nearest_object
230 self
._draggedAttachment
= attachment
231 self
._dragState
= StartDraggingRight
236 if nearest_object
== self
._draggedShape
:
237 nearest_object
.GetEventHandler().OnRightClick(x
, y
, keys
, attachment
)
238 self
._draggedShape
= None
239 self
._dragState
= NoDragging
243 self
._draggedShape
= None
244 self
._dragState
= StartDraggingLeft
249 self
.OnLeftClick(x
, y
, keys
)
250 self
._draggedShape
= None
251 self
._dragState
= NoDragging
253 elif evt
.RightDown():
254 self
._draggedShape
= None
255 self
._dragState
= StartDraggingRight
260 self
.OnRightClick(x
, y
, keys
)
261 self
._draggedShape
= None
262 self
._dragState
= NoDragging
264 def FindShape(self
, x
, y
, info
= None, notObject
= None):
266 nearest_attachment
= 0
267 nearest_object
= None
269 # Go backward through the object list, since we want:
270 # (a) to have the control points drawn LAST to overlay
272 # (b) to find the control points FIRST if they exist
274 rl
= self
.GetDiagram().GetShapeList()[:]
277 # First pass for lines, which might be inside a container, so we
278 # want lines to take priority over containers. This first loop
279 # could fail if we clickout side a line, so then we'll
281 if object.IsShown() and \
282 isinstance(object, LineShape
) and \
283 object.HitTest(x
, y
) and \
284 ((info
== None) or isinstance(object, info
)) and \
285 (not notObject
or not notObject
.HasDescendant(object)):
286 temp_attachment
, dist
= object.HitTest(x
, y
)
287 # A line is trickier to spot than a normal object.
288 # For a line, since it's the diagonal of the box
289 # we use for the hit test, we may have several
290 # lines in the box and therefore we need to be able
291 # to specify the nearest point to the centre of the line
292 # as our hit criterion, to give the user some room for
296 nearest_object
= object
297 nearest_attachment
= temp_attachment
300 # On second pass, only ever consider non-composites or
301 # divisions. If children want to pass up control to
302 # the composite, that's up to them.
303 if (object.IsShown() and
304 (isinstance(object, DivisionShape
) or
305 not isinstance(object, CompositeShape
)) and
306 object.HitTest(x
, y
) and
307 (info
== None or isinstance(object, info
)) and
308 (not notObject
or not notObject
.HasDescendant(object))):
309 temp_attachment
, dist
= object.HitTest(x
, y
)
310 if not isinstance(object, LineShape
):
311 # If we've hit a container, and we have already
312 # found a line in the first pass, then ignore
313 # the container in case the line is in the container.
314 # Check for division in case line straddles divisions
315 # (i.e. is not wholly contained).
316 if not nearest_object
or not (isinstance(object, DivisionShape
) or WhollyContains(object, nearest_object
)):
317 nearest_object
= object
318 nearest_attachment
= temp_attachment
321 return nearest_object
, nearest_attachment
323 def AddShape(self
, object, addAfter
= None):
324 self
.GetDiagram().AddShape(object, addAfter
)
326 def InsertShape(self
, object):
327 self
.GetDiagram().InsertShape(object)
329 def RemoveShape(self
, object):
330 self
.GetDiagram().RemoveShape(object)
332 def GetQuickEditMode(self
):
333 return self
.GetDiagram().GetQuickEditMode()
335 def Redraw(self
, dc
):
336 self
.GetDiagram().Redraw(dc
)
338 def Snap(self
, x
, y
):
339 return self
.GetDiagram().Snap(x
, y
)
341 def OnLeftClick(self
, x
, y
, keys
= 0):
344 def OnRightClick(self
, x
, y
, keys
= 0):
347 def OnDragLeft(self
, draw
, x
, y
, keys
= 0):
350 def OnBeginDragLeft(self
, x
, y
, keys
= 0):
353 def OnEndDragLeft(self
, x
, y
, keys
= 0):
356 def OnDragRight(self
, draw
, x
, y
, keys
= 0):
359 def OnBeginDragRight(self
, x
, y
, keys
= 0):
362 def OnEndDragRight(self
, x
, y
, keys
= 0):