]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/lib/ogl/_canvas.py
105cfa22ab3bdbe1bcbf77a21bd89fbeeafcb72b
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 #----------------------------------------------------------------------------
14 from __future__
import division
17 from _lines
import LineShape
18 from _composit
import *
20 NoDragging
, StartDraggingLeft
, ContinueDraggingLeft
, StartDraggingRight
, ContinueDraggingRight
= 0, 1, 2, 3, 4
22 KEY_SHIFT
, KEY_CTRL
= 1, 2
26 # Helper function: True if 'contains' wholly contains 'contained'.
27 def WhollyContains(contains
, contained
):
28 xp1
, yp1
= contains
.GetX(), contains
.GetY()
29 xp2
, yp2
= contained
.GetX(), contained
.GetY()
31 w1
, h1
= contains
.GetBoundingBoxMax()
32 w2
, h2
= contained
.GetBoundingBoxMax()
36 right1
= xp1
+ w1
/ 2.0
37 bottom1
= yp1
+ h1
/ 2.0
41 right2
= xp2
+ w2
/ 2.0
42 bottom2
= yp2
+ h2
/ 2.0
44 return ((left1
<= left2
) and (top1
<= top2
) and (right1
>= right2
) and (bottom1
>= bottom2
))
48 class ShapeCanvas(wx
.ScrolledWindow
):
49 def __init__(self
, parent
= None, id=-1, pos
= wx
.DefaultPosition
, size
= wx
.DefaultSize
, style
= wx
.BORDER
, name
="ShapeCanvas"):
50 wx
.ScrolledWindow
.__init
__(self
, parent
, id, pos
, size
, style
, name
)
52 self
._shapeDiagram
= None
53 self
._dragState
= NoDragging
54 self
._draggedShape
= None
59 self
._checkTolerance
= True
61 wx
.EVT_PAINT(self
, self
.OnPaint
)
62 wx
.EVT_MOUSE_EVENTS(self
, self
.OnMouseEvent
)
64 def SetDiagram(self
, diag
):
65 self
._shapeDiagram
= diag
68 return self
._shapeDiagram
70 def OnPaint(self
, evt
):
74 dc
.SetBackground(wx
.Brush(self
.GetBackgroundColour(), wx
.SOLID
))
78 self
.GetDiagram().Redraw(dc
)
80 def OnMouseEvent(self
, evt
):
81 dc
= wx
.ClientDC(self
)
84 x
, y
= evt
.GetLogicalPosition(dc
)
92 dragging
= evt
.Dragging()
94 # Check if we're within the tolerance for mouse movements.
95 # If we're very close to the position we started dragging
96 # from, this may not be an intentional drag at all.
98 dx
= abs(dc
.LogicalToDeviceX(x
-self
._firstDragX
))
99 dy
= abs(dc
.LogicalToDeviceY(y
-self
._firstDragY
))
100 if self
._checkTolerance
and (dx
<= self
.GetDiagram().GetMouseTolerance()) and (dy
<= self
.GetDiagram().GetMouseTolerance()):
102 # If we've ignored the tolerance once, then ALWAYS ignore
103 # tolerance in this drag, even if we come back within
104 # the tolerance range.
105 self
._checkTolerance
= False
107 # Dragging - note that the effect of dragging is left entirely up
108 # to the object, so no movement is done unless explicitly done by
110 if dragging
and self
._draggedShape
and self
._dragState
== StartDraggingLeft
:
111 self
._dragState
= ContinueDraggingLeft
113 # If the object isn't m_draggable, transfer message to canvas
114 if self
._draggedShape
.Draggable():
115 self
._draggedShape
.GetEventHandler().OnBeginDragLeft(x
, y
, keys
, self
._draggedAttachment
)
117 self
._draggedShape
= None
118 self
.OnBeginDragLeft(x
, y
, keys
)
120 self
._oldDragX
, self
._oldDragY
= x
, y
122 elif dragging
and self
._draggedShape
and self
._dragState
== ContinueDraggingLeft
:
124 self
._draggedShape
.GetEventHandler().OnDragLeft(False, self
._oldDragX
, self
._oldDragY
, keys
, self
._draggedAttachment
)
125 self
._draggedShape
.GetEventHandler().OnDragLeft(True, x
, y
, keys
, self
._draggedAttachment
)
126 self
._oldDragX
, self
._oldDragY
= x
, y
128 elif evt
.LeftUp
and self
._draggedShape
and self
._dragState
== ContinueDraggingLeft
:
129 self
._dragState
= NoDragging
130 self
._checkTolerance
= True
132 self
._draggedShape
.GetEventHandler().OnDragLeft(False, self
._oldDragX
, self
._oldDragY
, keys
, self
._draggedAttachment
)
133 self
._draggedShape
.GetEventHandler().OnEndDragLeft(x
, y
, keys
, self
._draggedAttachment
)
134 self
._draggedShape
= None
136 elif dragging
and self
._draggedShape
and self
._dragState
== StartDraggingRight
:
137 self
._dragState
= ContinueDraggingRight
138 if self
._draggedShape
.Draggable
:
139 self
._draggedShape
.GetEventHandler().OnBeginDragRight(x
, y
, keys
, self
._draggedAttachment
)
141 self
._draggedShape
= None
142 self
.OnBeginDragRight(x
, y
, keys
)
143 self
._oldDragX
, self
._oldDragY
= x
, y
145 elif dragging
and self
._draggedShape
and self
._dragState
== ContinueDraggingRight
:
147 self
._draggedShape
.GetEventHandler().OnDragRight(False, self
._oldDragX
, self
._oldDragY
, keys
, self
._draggedAttachment
)
148 self
._draggedShape
.GetEventHandler().OnDragRight(True, x
, y
, keys
, self
._draggedAttachment
)
149 self
._oldDragX
, self
._oldDragY
= x
, y
151 elif evt
.RightUp() and self
._draggedShape
and self
._dragState
== ContinueDraggingRight
:
152 self
._dragState
= NoDragging
153 self
._checkTolerance
= True
155 self
._draggedShape
.GetEventHandler().OnDragRight(False, self
._oldDragX
, self
._oldDragY
, keys
, self
._draggedAttachment
)
156 self
._draggedShape
.GetEventHandler().OnEndDragRight(x
, y
, keys
, self
._draggedAttachment
)
157 self
._draggedShape
= None
159 # All following events sent to canvas, not object
160 elif dragging
and not self
._draggedShape
and self
._dragState
== StartDraggingLeft
:
161 self
._dragState
= ContinueDraggingLeft
162 self
.OnBeginDragLeft(x
, y
, keys
)
163 self
._oldDragX
, self
._oldDragY
= x
, y
165 elif dragging
and not self
._draggedShape
and self
._dragState
== ContinueDraggingLeft
:
167 self
.OnDragLeft(False, self
._oldDragX
, self
._oldDragY
, keys
)
168 self
.OnDragLeft(True, x
, y
, keys
)
169 self
._oldDragX
, self
._oldDragY
= x
, y
171 elif evt
.LeftUp() and not self
._draggedShape
and self
._dragState
== ContinueDraggingLeft
:
172 self
._dragState
= NoDragging
173 self
._checkTolerance
= True
175 self
.OnDragLeft(False, self
._oldDragX
, self
._oldDragY
, keys
)
176 self
.OnEndDragLeft(x
, y
, keys
)
177 self
._draggedShape
= None
179 elif dragging
and not self
._draggedShape
and self
._dragState
== StartDraggingRight
:
180 self
._dragState
= ContinueDraggingRight
181 self
.OnBeginDragRight(x
, y
, keys
)
182 self
._oldDragX
, self
._oldDragY
= x
, y
184 elif dragging
and not self
._draggedShape
and self
._dragState
== ContinueDraggingRight
:
186 self
.OnDragRight(False, self
._oldDragX
, self
._oldDragY
, keys
)
187 self
.OnDragRight(True, x
, y
, keys
)
188 self
._oldDragX
, self
._oldDragY
= x
, y
190 elif evt
.RightUp() and not self
._draggedShape
and self
._dragState
== ContinueDraggingRight
:
191 self
._dragState
= NoDragging
192 self
._checkTolerance
= True
194 self
.OnDragRight(False, self
._oldDragX
, self
._oldDragY
, keys
)
195 self
.OnEndDragRight(x
, y
, keys
)
196 self
._draggedShape
= None
198 # Non-dragging events
200 self
._checkTolerance
= True
202 # Find the nearest object
205 nearest_object
, attachment
= self
.FindShape(x
, y
)
206 if nearest_object
: # Object event
208 self
._draggedShape
= nearest_object
209 self
._draggedAttachment
= attachment
210 self
._dragState
= StartDraggingLeft
215 # N.B. Only register a click if the same object was
216 # identified for down *and* up.
217 if nearest_object
== self
._draggedShape
:
218 nearest_object
.GetEventHandler().OnLeftClick(x
, y
, keys
, attachment
)
219 self
._draggedShape
= None
220 self
._dragState
= NoDragging
222 elif evt
.LeftDClick():
223 nearest_object
.GetEventHandler().OnLeftDoubleClick(x
, y
, keys
, attachment
)
224 self
._draggedShape
= None
225 self
._dragState
= NoDragging
227 elif evt
.RightDown():
228 self
._draggedShape
= nearest_object
229 self
._draggedAttachment
= attachment
230 self
._dragState
= StartDraggingRight
235 if nearest_object
== self
._draggedShape
:
236 nearest_object
.GetEventHandler().OnRightClick(x
, y
, keys
, attachment
)
237 self
._draggedShape
= None
238 self
._dragState
= NoDragging
242 self
._draggedShape
= None
243 self
._dragState
= StartDraggingLeft
248 self
.OnLeftClick(x
, y
, keys
)
249 self
._draggedShape
= None
250 self
._dragState
= NoDragging
252 elif evt
.RightDown():
253 self
._draggedShape
= None
254 self
._dragState
= StartDraggingRight
259 self
.OnRightClick(x
, y
, keys
)
260 self
._draggedShape
= None
261 self
._dragState
= NoDragging
263 def FindShape(self
, x
, y
, info
= None, notObject
= None):
265 nearest_attachment
= 0
266 nearest_object
= None
268 # Go backward through the object list, since we want:
269 # (a) to have the control points drawn LAST to overlay
271 # (b) to find the control points FIRST if they exist
273 for object in self
.GetDiagram().GetShapeList()[::-1]:
274 # First pass for lines, which might be inside a container, so we
275 # want lines to take priority over containers. This first loop
276 # could fail if we clickout side a line, so then we'll
278 if object.IsShown() and \
279 isinstance(object, LineShape
) and \
280 object.HitTest(x
, y
) and \
281 ((info
== None) or isinstance(object, info
)) and \
282 (not notObject
or not notObject
.HasDescendant(object)):
283 temp_attachment
, dist
= object.HitTest(x
, y
)
284 # A line is trickier to spot than a normal object.
285 # For a line, since it's the diagonal of the box
286 # we use for the hit test, we may have several
287 # lines in the box and therefore we need to be able
288 # to specify the nearest point to the centre of the line
289 # as our hit criterion, to give the user some room for
293 nearest_object
= object
294 nearest_attachment
= temp_attachment
296 for object in self
.GetDiagram().GetShapeList()[::-1]:
297 # On second pass, only ever consider non-composites or
298 # divisions. If children want to pass up control to
299 # the composite, that's up to them.
300 if (object.IsShown() and
301 (isinstance(object, DivisionShape
) or
302 not isinstance(object, CompositeShape
)) and
303 object.HitTest(x
, y
) and
304 (info
== None or isinstance(object, info
)) and
305 (not notObject
or not notObject
.HasDescendant(object))):
306 temp_attachment
, dist
= object.HitTest(x
, y
)
307 if not isinstance(object, LineShape
):
308 # If we've hit a container, and we have already
309 # found a line in the first pass, then ignore
310 # the container in case the line is in the container.
311 # Check for division in case line straddles divisions
312 # (i.e. is not wholly contained).
313 if not nearest_object
or not (isinstance(object, DivisionShape
) or WhollyContains(object, nearest_object
)):
314 nearest_object
= object
315 nearest_attachment
= temp_attachment
318 return nearest_object
, nearest_attachment
320 def AddShape(self
, object, addAfter
= None):
321 self
.GetDiagram().AddShape(object, addAfter
)
323 def InsertShape(self
, object):
324 self
.GetDiagram().InsertShape(object)
326 def RemoveShape(self
, object):
327 self
.GetDiagram().RemoveShape(object)
329 def GetQuickEditMode(self
):
330 return self
.GetDiagram().GetQuickEditMode()
332 def Redraw(self
, dc
):
333 self
.GetDiagram().Redraw(dc
)
335 def Snap(self
, x
, y
):
336 return self
.GetDiagram().Snap(x
, y
)
338 def OnLeftClick(self
, x
, y
, keys
= 0):
341 def OnRightClick(self
, x
, y
, keys
= 0):
344 def OnDragLeft(self
, draw
, x
, y
, keys
= 0):
347 def OnBeginDragLeft(self
, x
, y
, keys
= 0):
350 def OnEndDragLeft(self
, x
, y
, keys
= 0):
353 def OnDragRight(self
, draw
, x
, y
, keys
= 0):
356 def OnBeginDragRight(self
, x
, y
, keys
= 0):
359 def OnEndDragRight(self
, x
, y
, keys
= 0):