]>
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 dx
= abs(dc
.LogicalToDeviceX(x
- self
._firstDragX
))
97 dy
= abs(dc
.LogicalToDeviceY(y
- self
._firstDragY
))
98 if self
._checkTolerance
and (dx
<= self
.GetDiagram().GetMouseTolerance()) and (dy
<= self
.GetDiagram().GetMouseTolerance()):
100 # If we've ignored the tolerance once, then ALWAYS ignore
101 # tolerance in this drag, even if we come back within
102 # the tolerance range.
103 self
._checkTolerance
= False
105 # Dragging - note that the effect of dragging is left entirely up
106 # to the object, so no movement is done unless explicitly done by
108 if dragging
and self
._draggedShape
and self
._dragState
== StartDraggingLeft
:
109 self
._dragState
= ContinueDraggingLeft
111 # If the object isn't m_draggable, transfer message to canvas
112 if self
._draggedShape
.Draggable():
113 self
._draggedShape
.GetEventHandler().OnBeginDragLeft(x
, y
, keys
, self
._draggedAttachment
)
115 self
._draggedShape
= None
116 self
.OnBeginDragLeft(x
, y
, keys
)
118 self
._oldDragX
, self
._oldDragY
= x
, y
120 elif dragging
and self
._draggedShape
and self
._dragState
== ContinueDraggingLeft
:
122 self
._draggedShape
.GetEventHandler().OnDragLeft(False, self
._oldDragX
, self
._oldDragY
, keys
, self
._draggedAttachment
)
123 self
._draggedShape
.GetEventHandler().OnDragLeft(True, x
, y
, keys
, self
._draggedAttachment
)
124 self
._oldDragX
, self
._oldDragY
= x
, y
126 elif evt
.LeftUp() and self
._draggedShape
and self
._dragState
== ContinueDraggingLeft
:
127 self
._dragState
= NoDragging
128 self
._checkTolerance
= True
130 self
._draggedShape
.GetEventHandler().OnDragLeft(False, self
._oldDragX
, self
._oldDragY
, keys
, self
._draggedAttachment
)
131 self
._draggedShape
.GetEventHandler().OnEndDragLeft(x
, y
, keys
, self
._draggedAttachment
)
132 self
._draggedShape
= None
134 elif dragging
and self
._draggedShape
and self
._dragState
== StartDraggingRight
:
135 self
._dragState
= ContinueDraggingRight
136 if self
._draggedShape
.Draggable
:
137 self
._draggedShape
.GetEventHandler().OnBeginDragRight(x
, y
, keys
, self
._draggedAttachment
)
139 self
._draggedShape
= None
140 self
.OnBeginDragRight(x
, y
, keys
)
141 self
._oldDragX
, self
._oldDragY
= x
, y
143 elif dragging
and self
._draggedShape
and self
._dragState
== ContinueDraggingRight
:
145 self
._draggedShape
.GetEventHandler().OnDragRight(False, self
._oldDragX
, self
._oldDragY
, keys
, self
._draggedAttachment
)
146 self
._draggedShape
.GetEventHandler().OnDragRight(True, x
, y
, keys
, self
._draggedAttachment
)
147 self
._oldDragX
, self
._oldDragY
= x
, y
149 elif evt
.RightUp() and self
._draggedShape
and self
._dragState
== ContinueDraggingRight
:
150 self
._dragState
= NoDragging
151 self
._checkTolerance
= True
153 self
._draggedShape
.GetEventHandler().OnDragRight(False, self
._oldDragX
, self
._oldDragY
, keys
, self
._draggedAttachment
)
154 self
._draggedShape
.GetEventHandler().OnEndDragRight(x
, y
, keys
, self
._draggedAttachment
)
155 self
._draggedShape
= None
157 # All following events sent to canvas, not object
158 elif dragging
and not self
._draggedShape
and self
._dragState
== StartDraggingLeft
:
159 self
._dragState
= ContinueDraggingLeft
160 self
.OnBeginDragLeft(x
, y
, keys
)
161 self
._oldDragX
, self
._oldDragY
= x
, y
163 elif dragging
and not self
._draggedShape
and self
._dragState
== ContinueDraggingLeft
:
165 self
.OnDragLeft(False, self
._oldDragX
, self
._oldDragY
, keys
)
166 self
.OnDragLeft(True, x
, y
, keys
)
167 self
._oldDragX
, self
._oldDragY
= x
, y
169 elif evt
.LeftUp() and not self
._draggedShape
and self
._dragState
== ContinueDraggingLeft
:
170 self
._dragState
= NoDragging
171 self
._checkTolerance
= True
173 self
.OnDragLeft(False, self
._oldDragX
, self
._oldDragY
, keys
)
174 self
.OnEndDragLeft(x
, y
, keys
)
175 self
._draggedShape
= None
177 elif dragging
and not self
._draggedShape
and self
._dragState
== StartDraggingRight
:
178 self
._dragState
= ContinueDraggingRight
179 self
.OnBeginDragRight(x
, y
, keys
)
180 self
._oldDragX
, self
._oldDragY
= x
, y
182 elif dragging
and not self
._draggedShape
and self
._dragState
== ContinueDraggingRight
:
184 self
.OnDragRight(False, self
._oldDragX
, self
._oldDragY
, keys
)
185 self
.OnDragRight(True, x
, y
, keys
)
186 self
._oldDragX
, self
._oldDragY
= x
, y
188 elif evt
.RightUp() and not self
._draggedShape
and self
._dragState
== ContinueDraggingRight
:
189 self
._dragState
= NoDragging
190 self
._checkTolerance
= True
192 self
.OnDragRight(False, self
._oldDragX
, self
._oldDragY
, keys
)
193 self
.OnEndDragRight(x
, y
, keys
)
194 self
._draggedShape
= None
196 # Non-dragging events
198 self
._checkTolerance
= True
200 # Find the nearest object
203 nearest_object
, attachment
= self
.FindShape(x
, y
)
204 if nearest_object
: # Object event
206 self
._draggedShape
= nearest_object
207 self
._draggedAttachment
= attachment
208 self
._dragState
= StartDraggingLeft
213 # N.B. Only register a click if the same object was
214 # identified for down *and* up.
215 if nearest_object
== self
._draggedShape
:
216 nearest_object
.GetEventHandler().OnLeftClick(x
, y
, keys
, attachment
)
217 self
._draggedShape
= None
218 self
._dragState
= NoDragging
220 elif evt
.LeftDClick():
221 nearest_object
.GetEventHandler().OnLeftDoubleClick(x
, y
, keys
, attachment
)
222 self
._draggedShape
= None
223 self
._dragState
= NoDragging
225 elif evt
.RightDown():
226 self
._draggedShape
= nearest_object
227 self
._draggedAttachment
= attachment
228 self
._dragState
= StartDraggingRight
233 if nearest_object
== self
._draggedShape
:
234 nearest_object
.GetEventHandler().OnRightClick(x
, y
, keys
, attachment
)
235 self
._draggedShape
= None
236 self
._dragState
= NoDragging
240 self
._draggedShape
= None
241 self
._dragState
= StartDraggingLeft
246 self
.OnLeftClick(x
, y
, keys
)
247 self
._draggedShape
= None
248 self
._dragState
= NoDragging
250 elif evt
.RightDown():
251 self
._draggedShape
= None
252 self
._dragState
= StartDraggingRight
257 self
.OnRightClick(x
, y
, keys
)
258 self
._draggedShape
= None
259 self
._dragState
= NoDragging
261 def FindShape(self
, x
, y
, info
= None, notObject
= None):
263 nearest_attachment
= 0
264 nearest_object
= None
266 # Go backward through the object list, since we want:
267 # (a) to have the control points drawn LAST to overlay
269 # (b) to find the control points FIRST if they exist
271 rl
= self
.GetDiagram().GetShapeList()[:]
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
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):