3 Module that holds the GUI modes used by FloatCanvas
6 Note that this can only be imported after a wx.App() has been created.
8 This approach was inpired by Christian Blouin, who also wrote the initial
14 ## fixme: events should live in their own module, so all of FloatCanvas
15 ## wouldn't have to be imported here.
16 import FloatCanvas
, Resources
19 ## create all the Cursors, so they don't need to be created each time.
20 if "wxMac" in wx
.PlatformInfo
: # use 16X16 cursors for wxMac
21 HandCursor
= wx
.CursorFromImage(Resources
.getHand16Image())
22 GrabHandCursor
= wx
.CursorFromImage(Resources
.getGrabHand16Image())
24 img
= Resources
.getMagPlus16Image()
25 img
.SetOptionInt(wx
.IMAGE_OPTION_CUR_HOTSPOT_X
, 6)
26 img
.SetOptionInt(wx
.IMAGE_OPTION_CUR_HOTSPOT_Y
, 6)
27 MagPlusCursor
= wx
.CursorFromImage(img
)
29 img
= Resources
.getMagMinus16Image()
30 img
.SetOptionInt(wx
.IMAGE_OPTION_CUR_HOTSPOT_X
, 6)
31 img
.SetOptionInt(wx
.IMAGE_OPTION_CUR_HOTSPOT_Y
, 6)
32 MagMinusCursor
= wx
.CursorFromImage(img
)
33 else: # use 24X24 cursors for GTK and Windows
34 HandCursor
= wx
.CursorFromImage(Resources
.getHandImage())
35 GrabHandCursor
= wx
.CursorFromImage(Resources
.getGrabHandImage())
37 img
= Resources
.getMagPlusImage()
38 img
.SetOptionInt(wx
.IMAGE_OPTION_CUR_HOTSPOT_X
, 9)
39 img
.SetOptionInt(wx
.IMAGE_OPTION_CUR_HOTSPOT_Y
, 9)
40 MagPlusCursor
= wx
.CursorFromImage(img
)
42 img
= Resources
.getMagMinusImage()
43 img
.SetOptionInt(wx
.IMAGE_OPTION_CUR_HOTSPOT_X
, 9)
44 img
.SetOptionInt(wx
.IMAGE_OPTION_CUR_HOTSPOT_Y
, 9)
45 MagMinusCursor
= wx
.CursorFromImage(img
)
50 Basic Mouse mode and baseclass for other GUImode.
52 This one does nothing with any event
55 def __init__(self
, parent
):
58 Cursor
= wx
.NullCursor
61 def OnLeftDown(self
, event
):
63 def OnLeftUp(self
, event
):
65 def OnLeftDouble(self
, event
):
67 def OnRightDown(self
, event
):
69 def OnRightUp(self
, event
):
71 def OnRightDouble(self
, event
):
73 def OnMiddleDown(self
, event
):
75 def OnMiddleUp(self
, event
):
77 def OnMiddleDouble(self
, event
):
79 def OnWheel(self
, event
):
81 def OnMove(self
, event
):
84 def UpdateScreen(self
):
86 Update gets called if the screen has been repainted in the middle of a zoom in
87 so the Rubber Band Box can get updated
91 class GUIMouse(GUIBase
):
94 Mouse mode checks for a hit test, and if nothing is hit,
95 raises a FloatCanvas mouse event for each event.
99 Cursor
= wx
.NullCursor
102 def OnLeftDown(self
, event
):
103 EventType
= FloatCanvas
.EVT_FC_LEFT_DOWN
104 if not self
.parent
.HitTest(event
, EventType
):
105 self
.parent
._RaiseMouseEvent
(event
, EventType
)
107 def OnLeftUp(self
, event
):
108 EventType
= FloatCanvas
.EVT_FC_LEFT_UP
109 if not self
.parent
.HitTest(event
, EventType
):
110 self
.parent
._RaiseMouseEvent
(event
, EventType
)
112 def OnLeftDouble(self
, event
):
113 EventType
= FloatCanvas
.EVT_FC_LEFT_DCLICK
114 if not self
.parent
.HitTest(event
, EventType
):
115 self
.parent
._RaiseMouseEvent
(event
, EventType
)
117 def OnMiddleDown(self
, event
):
118 EventType
= FloatCanvas
.EVT_FC_MIDDLE_DOWN
119 if not self
.parent
.HitTest(event
, EventType
):
120 self
.parent
._RaiseMouseEvent
(event
, EventType
)
122 def OnMiddleUp(self
, event
):
123 EventType
= FloatCanvas
.EVT_FC_MIDDLE_UP
124 if not self
.parent
.HitTest(event
, EventType
):
125 self
.parent
._RaiseMouseEvent
(event
, EventType
)
127 def OnMiddleDouble(self
, event
):
128 EventType
= FloatCanvas
.EVT_FC_MIDDLE_DCLICK
129 if not self
.parent
.HitTest(event
, EventType
):
130 self
.parent
._RaiseMouseEvent
(event
, EventType
)
132 def OnRightDown(self
, event
):
133 EventType
= FloatCanvas
.EVT_FC_RIGHT_DOWN
134 if not self
.parent
.HitTest(event
, EventType
):
135 self
.parent
._RaiseMouseEvent
(event
, EventType
)
137 def OnRightUp(self
, event
):
138 EventType
= FloatCanvas
.EVT_FC_RIGHT_UP
139 if not self
.parent
.HitTest(event
, EventType
):
140 self
.parent
._RaiseMouseEvent
(event
, EventType
)
142 def OnRightDouble(self
, event
):
143 EventType
= FloatCanvas
.EVT_FC_RIGHT_DCLICK
144 if not self
.parent
.HitTest(event
, EventType
):
145 self
.parent
._RaiseMouseEvent
(event
, EventType
)
147 def OnWheel(self
, event
):
148 EventType
= FloatCanvas
.EVT_FC_MOUSEWHEEL
149 self
.parent
._RaiseMouseEvent
(event
, EventType
)
151 def OnMove(self
, event
):
152 ## The Move event always gets raised, even if there is a hit-test
153 self
.parent
.MouseOverTest(event
)
154 self
.parent
._RaiseMouseEvent
(event
,FloatCanvas
.EVT_FC_MOTION
)
157 class GUIMove(GUIBase
):
160 GrabCursor
= GrabHandCursor
161 def __init__(self
, parent
):
162 GUIBase
.__init
__(self
, parent
)
163 self
.StartMove
= None
164 self
.PrevMoveXY
= None
166 def OnLeftDown(self
, event
):
167 self
.parent
.SetCursor(self
.GrabCursor
)
168 self
.parent
.CaptureMouse()
169 self
.StartMove
= N
.array( event
.GetPosition() )
170 self
.PrevMoveXY
= (0,0)
172 def OnLeftUp(self
, event
):
173 if self
.StartMove
is not None:
174 StartMove
= self
.StartMove
175 EndMove
= N
.array(event
.GetPosition())
176 DiffMove
= StartMove
-EndMove
177 if N
.sum(DiffMove
**2) > 16:
178 self
.parent
.MoveImage(DiffMove
, 'Pixel')
179 self
.StartMove
= None
180 self
.parent
.SetCursor(self
.Cursor
)
182 def OnMove(self
, event
):
183 # Allways raise the Move event.
184 self
.parent
._RaiseMouseEvent
(event
,FloatCanvas
.EVT_FC_MOTION
)
185 if event
.Dragging() and event
.LeftIsDown() and not self
.StartMove
is None:
186 xy1
= N
.array( event
.GetPosition() )
187 wh
= self
.parent
.PanelSize
188 xy_tl
= xy1
- self
.StartMove
189 dc
= wx
.ClientDC(self
.parent
)
191 x1
,y1
= self
.PrevMoveXY
193 w
,h
= self
.parent
.PanelSize
194 ##fixme: This sure could be cleaner!
195 if x2
> x1
and y2
> y1
:
202 elif x2
> x1
and y2
<= y1
:
211 elif x2
<= x1
and y2
> y1
:
220 elif x2
<= x1
and y2
<= y1
:
230 dc
.SetPen(wx
.TRANSPARENT_PEN
)
231 dc
.SetBrush(self
.parent
.BackgroundBrush
)
232 dc
.DrawRectangle(xa
, ya
, wa
, ha
)
233 dc
.DrawRectangle(xb
, yb
, wb
, hb
)
234 self
.PrevMoveXY
= xy_tl
235 if self
.parent
._ForeDrawList
:
236 dc
.DrawBitmapPoint(self
.parent
._ForegroundBuffer
,xy_tl
)
238 dc
.DrawBitmapPoint(self
.parent
._Buffer
,xy_tl
)
241 def OnWheel(self
, event
):
243 By default, zoom in/out by a 0.1 factor per Wheel event.
245 if event
.GetWheelRotation() < 0:
246 self
.parent
.Zoom(0.9)
248 self
.parent
.Zoom(1.1)
250 class GUIZoomIn(GUIBase
):
252 Cursor
= MagPlusCursor
254 def __init__(self
, parent
):
255 GUIBase
.__init
__(self
, parent
)
256 self
.StartRBBox
= None
257 self
.PrevRBBox
= None
259 def OnLeftDown(self
, event
):
260 self
.StartRBBox
= N
.array( event
.GetPosition() )
261 self
.PrevRBBox
= None
262 self
.parent
.CaptureMouse()
264 def OnLeftUp(self
, event
):
265 #if self.parent.HasCapture():
266 # self.parent.ReleaseMouse()
267 if event
.LeftUp() and not self
.StartRBBox
is None:
268 self
.PrevRBBox
= None
269 EndRBBox
= event
.GetPosition()
270 StartRBBox
= self
.StartRBBox
271 # if mouse has moved less that ten pixels, don't use the box.
272 if ( abs(StartRBBox
[0] - EndRBBox
[0]) > 10
273 and abs(StartRBBox
[1] - EndRBBox
[1]) > 10 ):
274 EndRBBox
= self
.parent
.PixelToWorld(EndRBBox
)
275 StartRBBox
= self
.parent
.PixelToWorld(StartRBBox
)
276 BB
= N
.array(((min(EndRBBox
[0],StartRBBox
[0]),
277 min(EndRBBox
[1],StartRBBox
[1])),
278 (max(EndRBBox
[0],StartRBBox
[0]),
279 max(EndRBBox
[1],StartRBBox
[1]))),N
.float_
)
280 self
.parent
.ZoomToBB(BB
)
282 Center
= self
.parent
.PixelToWorld(StartRBBox
)
283 self
.parent
.Zoom(1.5,Center
)
284 self
.StartRBBox
= None
286 def OnMove(self
, event
):
287 # Allways raise the Move event.
288 self
.parent
._RaiseMouseEvent
(event
,FloatCanvas
.EVT_FC_MOTION
)
289 if event
.Dragging() and event
.LeftIsDown() and not (self
.StartRBBox
is None):
290 xy0
= self
.StartRBBox
291 xy1
= N
.array( event
.GetPosition() )
293 wh
[0] = max(wh
[0], int(wh
[1]*self
.parent
.AspectRatio
))
294 wh
[1] = int(wh
[0] / self
.parent
.AspectRatio
)
295 xy_c
= (xy0
+ xy1
) / 2
296 dc
= wx
.ClientDC(self
.parent
)
298 dc
.SetPen(wx
.Pen('WHITE', 2, wx
.SHORT_DASH
))
299 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
300 dc
.SetLogicalFunction(wx
.XOR
)
302 dc
.DrawRectanglePointSize(*self
.PrevRBBox
)
303 self
.PrevRBBox
= ( xy_c
- wh
/2, wh
)
304 dc
.DrawRectanglePointSize( *self
.PrevRBBox
)
307 def UpdateScreen(self
):
309 Update gets called if the screen has been repainted in the middle of a zoom in
310 so the Rubber Band Box can get updated
312 if self
.PrevRBBox
is not None:
313 dc
= wx
.ClientDC(self
.parent
)
314 dc
.SetPen(wx
.Pen('WHITE', 2, wx
.SHORT_DASH
))
315 dc
.SetBrush(wx
.TRANSPARENT_BRUSH
)
316 dc
.SetLogicalFunction(wx
.XOR
)
317 dc
.DrawRectanglePointSize(*self
.PrevRBBox
)
319 def OnRightDown(self
, event
):
320 self
.parent
.Zoom(1/1.5, event
.GetPosition(), centerCoords
="pixel")
322 def OnWheel(self
, event
):
323 if event
.GetWheelRotation() < 0:
324 self
.parent
.Zoom(0.9)
326 self
.parent
.Zoom(1.1)
328 class GUIZoomOut(GUIBase
):
330 Cursor
= MagMinusCursor
332 def OnLeftDown(self
, event
):
333 self
.parent
.Zoom(1/1.5, event
.GetPosition(), centerCoords
="pixel")
335 def OnRightDown(self
, event
):
336 self
.parent
.Zoom(1.5, event
.GetPosition(), centerCoords
="pixel")
338 def OnWheel(self
, event
):
339 if event
.GetWheelRotation() < 0:
340 self
.parent
.Zoom(0.9)
342 self
.parent
.Zoom(1.1)
344 def OnMove(self
, event
):
345 # Allways raise the Move event.
346 self
.parent
._RaiseMouseEvent
(event
,FloatCanvas
.EVT_FC_MOTION
)