]> git.saurik.com Git - wxWidgets.git/blob - wxPython/samples/ide/activegrid/tool/AbstractEditor.py
Tweaks for demos on MacOSX
[wxWidgets.git] / wxPython / samples / ide / activegrid / tool / AbstractEditor.py
1 #----------------------------------------------------------------------------
2 # Name: AbstractEditor.py
3 # Purpose: Non-text editor for DataModel and Process
4 #
5 # Author: Peter Yared, Morgan Hua
6 #
7 # Created: 7/28/04
8 # CVS-ID: $Id$
9 # Copyright: (c) 2004-2005 ActiveGrid, Inc.
10 # License: wxWindows License
11 #----------------------------------------------------------------------------
12
13
14 import wx
15 import wx.lib.docview
16 import wx.lib.ogl as ogl
17 import PropertyService
18 _ = wx.GetTranslation
19
20
21 SELECT_BRUSH = wx.Brush("BLUE", wx.SOLID)
22 SHAPE_BRUSH = wx.Brush("WHEAT", wx.SOLID)
23 LINE_BRUSH = wx.BLACK_BRUSH
24 INACTIVE_SELECT_BRUSH = wx.Brush("LIGHT BLUE", wx.SOLID)
25
26 NORMALFONT = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
27 SLANTFONT = wx.Font(NORMALFONT.GetPointSize(), NORMALFONT.GetFamily(), wx.SLANT, NORMALFONT.GetWeight())
28 BOLDFONT = wx.Font(NORMALFONT.GetPointSize(), NORMALFONT.GetFamily(), NORMALFONT.GetStyle(), wx.BOLD)
29
30 DEFAULT_BACKGROUND_COLOR = wx.Colour(0xEE, 0xEE, 0xEE)
31 HEADER_BRUSH = wx.Brush(wx.Colour(0xDB, 0xEB, 0xFF), wx.SOLID)
32 BODY_BRUSH = wx.Brush(wx.WHITE, wx.SOLID)
33
34
35 PARKING_VERTICAL = 1
36 PARKING_HORIZONTAL = 2
37 PARKING_OFFSET = 30 # space between shapes
38
39
40 def GetRawModel(model):
41 if hasattr(model, "GetRawModel"):
42 rawModel = model.GetRawModel()
43 else:
44 rawModel = model
45 return rawModel
46
47
48 def GetLabel(model):
49 model = GetRawModel(model)
50 if hasattr(model, "__xmlname__"):
51 label = model.__xmlname__
52 try:
53 if (len(label) > 0):
54 label = label[0].upper() + label[1:]
55 if (hasattr(model, "complexType")):
56 label += ': %s/%s' % (model.complexType.name, model.name)
57 else:
58 if model.name:
59 label += ': %s' % model.name
60 elif model.ref:
61 label += ': %s' % model.ref
62 except AttributeError:
63 pass
64 else:
65 label = str(model)
66 return label
67
68
69 class CanvasView(wx.lib.docview.View):
70
71
72 #----------------------------------------------------------------------------
73 # Overridden methods
74 #----------------------------------------------------------------------------
75
76
77 def __init__(self, brush=SHAPE_BRUSH, background=DEFAULT_BACKGROUND_COLOR):
78 wx.lib.docview.View.__init__(self)
79 self._brush = brush
80 self._backgroundColor = background
81 self._canvas = None
82 self._pt1 = None
83 self._pt2 = None
84 self._needEraseLasso = False
85 self._propShape = None
86 self._maxWidth = 2000
87 self._maxHeight = 16000
88
89
90 def OnDraw(self, dc):
91 """ for Print Preview and Print """
92 dc.BeginDrawing()
93 self._canvas.Redraw(dc)
94 dc.EndDrawing()
95
96
97 def OnCreate(self, doc, flags):
98 frame = wx.GetApp().CreateDocumentFrame(self, doc, flags)
99 frame.Show()
100 sizer = wx.BoxSizer()
101 self._CreateCanvas(frame)
102 sizer.Add(self._canvas, 1, wx.EXPAND, 0)
103 frame.SetSizer(sizer)
104 frame.Layout()
105 self.Activate()
106 wx.EVT_RIGHT_DOWN(self._canvas, self.OnRightClick)
107 return True
108
109
110 def OnActivateView(self, activate, activeView, deactiveView):
111 if activate and self._canvas:
112 # In MDI mode just calling set focus doesn't work and in SDI mode using CallAfter causes an endless loop
113 if self.GetDocumentManager().GetFlags() & wx.lib.docview.DOC_SDI:
114 self.SetFocus()
115 else:
116 wx.CallAfter(self.SetFocus)
117
118
119 def SetFocus(self):
120 if self._canvas:
121 self._canvas.SetFocus()
122
123
124 def OnFocus(self, event):
125 self.FocusColorPropertyShape(True)
126 event.Skip()
127
128
129 def FocusOnClick(self, event):
130 self.SetFocus()
131 event.Skip()
132
133
134 def OnKillFocus(self, event):
135 self.FocusColorPropertyShape(False)
136 event.Skip()
137
138
139 def HasFocus(self):
140 winWithFocus = wx.Window.FindFocus()
141 if not winWithFocus:
142 return False
143 while winWithFocus:
144 if winWithFocus == self._canvas:
145 return True
146 winWithFocus = winWithFocus.GetParent()
147 return False
148
149
150 def OnClose(self, deleteWindow = True):
151 statusC = wx.GetApp().CloseChildDocuments(self.GetDocument())
152 statusP = wx.lib.docview.View.OnClose(self, deleteWindow = deleteWindow)
153 if hasattr(self, "ClearOutline"):
154 wx.CallAfter(self.ClearOutline) # need CallAfter because when closing the document, it is Activated and then Close, so need to match OnActivateView's CallAfter
155 if not (statusC and statusP):
156 return False
157 self.Activate(False)
158 if deleteWindow and self.GetFrame():
159 self.GetFrame().Destroy()
160 return True
161
162
163 def _CreateCanvas(self, parent):
164 self._canvas = ogl.ShapeCanvas(parent)
165 wx.EVT_LEFT_DOWN(self._canvas, self.OnLeftClick)
166 wx.EVT_LEFT_UP(self._canvas, self.OnLeftUp)
167 wx.EVT_MOTION(self._canvas, self.OnLeftDrag)
168 wx.EVT_LEFT_DCLICK(self._canvas, self.OnLeftDoubleClick)
169 wx.EVT_KEY_DOWN(self._canvas, self.OnKeyPressed)
170
171 # need this otherwise mouse clicks don't set focus to this view
172 wx.EVT_LEFT_DOWN(self._canvas, self.FocusOnClick)
173 wx.EVT_LEFT_DCLICK(self._canvas, self.FocusOnClick)
174 wx.EVT_RIGHT_DOWN(self._canvas, self.FocusOnClick)
175 wx.EVT_RIGHT_DCLICK(self._canvas, self.FocusOnClick)
176 wx.EVT_MIDDLE_DOWN(self._canvas, self.FocusOnClick)
177 wx.EVT_MIDDLE_DCLICK(self._canvas, self.FocusOnClick)
178
179 wx.EVT_KILL_FOCUS(self._canvas, self.OnKillFocus)
180 wx.EVT_SET_FOCUS(self._canvas, self.OnFocus)
181
182 self._canvas.SetScrollbars(20, 20, self._maxWidth / 20, self._maxHeight / 20)
183
184 self._canvas.SetBackgroundColour(self._backgroundColor)
185 self._diagram = ogl.Diagram()
186 self._canvas.SetDiagram(self._diagram)
187 self._diagram.SetCanvas(self._canvas)
188 self._canvas.SetFont(NORMALFONT)
189
190
191 def OnClear(self, event):
192 """ Deletion of selected objects from view.
193 *Must Override*
194 """
195 self.SetPropertyModel(None)
196
197
198 def OnKeyPressed(self, event):
199 key = event.KeyCode()
200 if key == wx.WXK_DELETE:
201 self.OnClear(event)
202 else:
203 event.Skip()
204
205
206 def OnRightClick(self, event):
207 """ force selection underneath right click position. """
208 self.Activate()
209 self._canvas.SetFocus()
210
211 dc = wx.ClientDC(self._canvas)
212 self._canvas.PrepareDC(dc)
213 x, y = event.GetLogicalPosition(dc) # this takes into account scrollbar offset
214 shape = self._canvas.FindShape(x, y)[0]
215
216 model = None
217 if not shape:
218 self.SetSelection(None)
219 self.SetPropertyShape(None)
220 elif hasattr(shape, "GetModel"):
221 self.BringToFront(shape)
222 self.SetPropertyShape(shape)
223 self.SetSelection(shape)
224 shape.Select(True, dc)
225 model = shape.GetModel()
226 elif shape.GetParent() and isinstance(shape.GetParent(), ogl.CompositeShape): # ComplexTypeHeader for ComplexTypeShape
227 self.BringToFront(shape)
228 self.SetPropertyShape(shape.GetParent())
229 self.SetSelection(shape.GetParent())
230 shape.GetParent().Select(True, dc)
231 model = shape.GetParent().GetModel()
232
233 self.SetPropertyModel(model)
234
235 return (shape, model)
236
237
238 def OnLeftClick(self, event):
239 self.Activate()
240 self._canvas.SetFocus()
241
242 self.EraseRubberBand()
243
244 dc = wx.ClientDC(self._canvas)
245 self._canvas.PrepareDC(dc)
246
247 # keep track of mouse down for group select
248 self._pt1 = event.GetLogicalPosition(dc) # this takes into account scrollbar offset
249 self._pt2 = None
250
251 shape = self._canvas.FindShape(self._pt1[0], self._pt1[1])[0]
252 if shape:
253 self.BringToFront(shape)
254
255 self._pt1 = None
256 event.Skip() # pass on event to shape handler to take care of selection
257
258 return
259 elif event.ControlDown() or event.ShiftDown(): # extend select, don't deselect
260 pass
261 else:
262 # click on empty part of canvas, deselect everything
263 needRefresh = False
264 for shape in self._diagram.GetShapeList():
265 if hasattr(shape, "GetModel"):
266 if shape.Selected():
267 needRefresh = True
268 shape.Select(False, dc)
269 if needRefresh:
270 self._canvas.Redraw(dc)
271
272 self.SetPropertyModel(None)
273
274 if len(self.GetSelection()) == 0:
275 self.SetPropertyShape(None)
276
277
278
279 def OnLeftDoubleClick(self, event):
280 propertyService = wx.GetApp().GetService(PropertyService.PropertyService)
281 if propertyService:
282 propertyService.ShowWindow()
283
284
285 def OnLeftDrag(self, event):
286 # draw lasso for group select
287 if self._pt1 and event.LeftIsDown(): # we are in middle of lasso selection
288 self.EraseRubberBand()
289
290 dc = wx.ClientDC(self._canvas)
291 self._canvas.PrepareDC(dc)
292 self._pt2 = event.GetLogicalPosition(dc) # this takes into account scrollbar offset
293 self.DrawRubberBand()
294 else:
295 event.Skip()
296
297
298 def OnLeftUp(self, event):
299 # do group select
300 if self._needEraseLasso:
301 self.EraseRubberBand()
302
303 dc = wx.ClientDC(self._canvas)
304 self._canvas.PrepareDC(dc)
305 x1, y1 = self._pt1
306 x2, y2 = event.GetLogicalPosition(dc) # this takes into account scrollbar offset
307
308 tol = self._diagram.GetMouseTolerance()
309 if abs(x1 - x2) > tol or abs(y1 - y2) > tol:
310 # make sure x1 < x2 and y1 < y2 to make comparison test easier
311 if x1 > x2:
312 temp = x1
313 x1 = x2
314 x2 = temp
315 if y1 > y2:
316 temp = y1
317 y1 = y2
318 y2 = temp
319
320 for shape in self._diagram.GetShapeList():
321 if not shape.GetParent() and hasattr(shape, "GetModel"): # if part of a composite, don't select it
322 x, y = shape.GetX(), shape.GetY()
323 width, height = shape.GetBoundingBoxMax()
324 selected = x1 < x - width/2 and x2 > x + width/2 and y1 < y - height/2 and y2 > y + height/2
325 if event.ControlDown() or event.ShiftDown(): # extend select, don't deselect
326 if selected:
327 shape.Select(selected, dc)
328 else: # select items in lasso and deselect items out of lasso
329 shape.Select(selected, dc)
330 self._canvas.Redraw(dc)
331 else:
332 event.Skip()
333 else:
334 event.Skip()
335
336
337 def EraseRubberBand(self):
338 if self._needEraseLasso:
339 self._needEraseLasso = False
340
341 dc = wx.ClientDC(self._canvas)
342 self._canvas.PrepareDC(dc)
343 dc.SetLogicalFunction(wx.XOR)
344 pen = wx.Pen(wx.Colour(200, 200, 200), 1, wx.SHORT_DASH)
345 dc.SetPen(pen)
346 brush = wx.Brush(wx.Colour(255, 255, 255), wx.TRANSPARENT)
347 dc.SetBrush(brush)
348 dc.ResetBoundingBox()
349 dc.BeginDrawing()
350
351 x1, y1 = self._pt1
352 x2, y2 = self._pt2
353
354 # make sure x1 < x2 and y1 < y2
355 # this will make (x1, y1) = upper left corner
356 if x1 > x2:
357 temp = x1
358 x1 = x2
359 x2 = temp
360 if y1 > y2:
361 temp = y1
362 y1 = y2
363 y2 = temp
364
365 # erase previous outline
366 dc.SetClippingRegion(x1, y1, x2 - x1, y2 - y1)
367 dc.DrawRectangle(x1, y1, x2 - x1, y2 - y1)
368 dc.EndDrawing()
369
370
371 def DrawRubberBand(self):
372 self._needEraseLasso = True
373
374 dc = wx.ClientDC(self._canvas)
375 self._canvas.PrepareDC(dc)
376 dc.SetLogicalFunction(wx.XOR)
377 pen = wx.Pen(wx.Colour(200, 200, 200), 1, wx.SHORT_DASH)
378 dc.SetPen(pen)
379 brush = wx.Brush(wx.Colour(255, 255, 255), wx.TRANSPARENT)
380 dc.SetBrush(brush)
381 dc.ResetBoundingBox()
382 dc.BeginDrawing()
383
384 x1, y1 = self._pt1
385 x2, y2 = self._pt2
386
387 # make sure x1 < x2 and y1 < y2
388 # this will make (x1, y1) = upper left corner
389 if x1 > x2:
390 temp = x1
391 x1 = x2
392 x2 = temp
393 if y1 > y2:
394 temp = y1
395 y1 = y2
396 y2 = temp
397
398 # draw outline
399 dc.SetClippingRegion(x1, y1, x2 - x1, y2 - y1)
400 dc.DrawRectangle(x1, y1, x2 - x1, y2 - y1)
401 dc.EndDrawing()
402
403
404 def FindParkingSpot(self, width, height, parking=PARKING_HORIZONTAL, x=PARKING_OFFSET, y=PARKING_OFFSET):
405 """ given a width and height, find a upper left corner where shape can be parked without overlapping other shape """
406 max = 700 # max distance to the right where we'll place tables
407 noParkingSpot = True
408
409 while noParkingSpot:
410 point = self.isSpotOccupied(x, y, width, height)
411 if point:
412 if parking == PARKING_HORIZONTAL:
413 x = point[0] + PARKING_OFFSET
414 if x > max:
415 x = PARKING_OFFSET
416 y = point[1] + PARKING_OFFSET
417 else: # parking == PARKING_VERTICAL:
418 y = point[1] + PARKING_OFFSET
419 if y > max:
420 y = PARKING_OFFSET
421 x = point[0] + PARKING_OFFSET
422 else:
423 noParkingSpot = False
424
425 return x, y
426
427
428 def isSpotOccupied(self, x, y, width, height):
429 """ returns None if at x,y,width,height no object occupies that rectangle,
430 otherwise returns lower right corner of object that occupies given x,y position
431 """
432 x2 = x + width
433 y2 = y + height
434
435 for shape in self._diagram.GetShapeList():
436 if isinstance(shape, ogl.RectangleShape) or isinstance(shape, ogl.EllipseShape) or isinstance(shape, ogl.PolygonShape):
437 if shape.GetParent() and isinstance(shape.GetParent(), ogl.CompositeShape):
438 # skip, part of a composite shape
439 continue
440
441 if hasattr(shape, "GetModel"):
442 other_x, other_y, other_width, other_height = shape.GetModel().getEditorBounds()
443 other_x2 = other_x + other_width
444 other_y2 = other_y + other_height
445 else:
446 # shapes x,y are at the center of the shape, need to transform to upper left coordinate
447 other_width, other_height = shape.GetBoundingBoxMax()
448 other_x = shape.GetX() - other_width/2
449 other_y = shape.GetY() - other_height/2
450
451 other_x2 = other_x + other_width
452 other_y2 = other_y + other_height
453 # intersection check
454 if ((other_x2 < other_x or other_x2 > x) and
455 (other_y2 < other_y or other_y2 > y) and
456 (x2 < x or x2 > other_x) and
457 (y2 < y or y2 > other_y)):
458 return (other_x2, other_y2)
459 return None
460
461
462 #----------------------------------------------------------------------------
463 # Canvas methods
464 #----------------------------------------------------------------------------
465
466 def AddShape(self, shape, x = None, y = None, pen = None, brush = None, text = None, eventHandler = None, shown=True):
467 if isinstance(shape, ogl.CompositeShape):
468 dc = wx.ClientDC(self._canvas)
469 self._canvas.PrepareDC(dc)
470 shape.Move(dc, x, y)
471 else:
472 shape.SetDraggable(True, True)
473 shape.SetCanvas(self._canvas)
474
475 if x:
476 shape.SetX(x)
477 if y:
478 shape.SetY(y)
479 shape.SetCentreResize(False)
480 if pen:
481 shape.SetPen(pen)
482 if brush:
483 shape.SetBrush(brush)
484 if text:
485 shape.AddText(text)
486 shape.SetShadowMode(ogl.SHADOW_NONE)
487 self._diagram.AddShape(shape)
488 shape.Show(shown)
489 if not eventHandler:
490 eventHandler = EditorCanvasShapeEvtHandler(self)
491 eventHandler.SetShape(shape)
492 eventHandler.SetPreviousHandler(shape.GetEventHandler())
493 shape.SetEventHandler(eventHandler)
494 return shape
495
496
497 def RemoveShape(self, model = None, shape = None):
498 if not model and not shape:
499 return
500
501 if not shape:
502 shape = self.GetShape(model)
503
504 if shape:
505 shape.Select(False)
506 for line in shape.GetLines():
507 shape.RemoveLine(line)
508 self._diagram.RemoveShape(line)
509 line.Delete()
510 for obj in self._diagram.GetShapeList():
511 for line in obj.GetLines():
512 if self.IsShapeContained(shape, line.GetTo()) or self.IsShapeContained(shape, line.GetFrom()):
513 obj.RemoveLine(line)
514 self._diagram.RemoveShape(line)
515 line.Delete()
516 if line == shape:
517 obj.RemoveLine(line)
518 self._diagram.RemoveShape(line)
519 line.Delete()
520
521 shape.RemoveFromCanvas(self._canvas)
522 self._diagram.RemoveShape(shape)
523 shape.Delete()
524
525
526 def IsShapeContained(self, parent, shape):
527 if parent == shape:
528 return True
529 elif shape.GetParent():
530 return self.IsShapeContained(parent, shape.GetParent())
531
532 return False
533
534
535 def UpdateShape(self, model):
536 for shape in self._diagram.GetShapeList():
537 if hasattr(shape, "GetModel") and shape.GetModel() == model:
538 oldw, oldh = shape.GetBoundingBoxMax()
539 oldx = shape.GetX()
540 oldy = shape.GetY()
541
542 x, y, w, h = model.getEditorBounds()
543 newX = x + w / 2
544 newY = y + h / 2
545
546 if oldw != w or oldh != h or oldx != newX or oldy != newY:
547 dc = wx.ClientDC(self._canvas)
548 self._canvas.PrepareDC(dc)
549 shape.SetSize(w, h, True) # wxBug: SetSize must be before Move because links won't go to the right place
550 shape.Move(dc, newX, newY) # wxBug: Move must be after SetSize because links won't go to the right place
551 shape.ResetControlPoints()
552 self._canvas.Refresh()
553
554 break
555
556
557 def GetShape(self, model):
558 for shape in self._diagram.GetShapeList():
559 if hasattr(shape, "GetModel") and shape.GetModel() == model:
560 return shape
561 return None
562
563
564 def GetShapeCount(self):
565 return self._diagram.GetCount()
566
567
568 def GetSelection(self):
569 return filter(lambda shape: shape.Selected(), self._diagram.GetShapeList())
570
571
572 def SetSelection(self, models, extendSelect = False):
573 dc = wx.ClientDC(self._canvas)
574 self._canvas.PrepareDC(dc)
575 update = False
576 if not isinstance(models, type([])) and not isinstance(models, type(())):
577 models = [models]
578 for shape in self._diagram.GetShapeList():
579 if hasattr(shape, "GetModel"):
580 if shape.Selected() and not shape.GetModel() in models: # was selected, but not in new list, so deselect, unless extend select
581 if not extendSelect:
582 shape.Select(False, dc)
583 update = True
584 elif not shape.Selected() and shape.GetModel() in models: # was not selected and in new list, so select
585 shape.Select(True, dc)
586 update = True
587 elif extendSelect and shape.Selected() and shape.GetModel() in models: # was selected, but extend select means to deselect
588 shape.Select(False, dc)
589 update = True
590 if update:
591 self._canvas.Redraw(dc)
592
593
594 def BringToFront(self, shape):
595 if shape.GetParent() and isinstance(shape.GetParent(), ogl.CompositeShape):
596 self._diagram.RemoveShape(shape.GetParent())
597 self._diagram.AddShape(shape.GetParent())
598 else:
599 self._diagram.RemoveShape(shape)
600 self._diagram.AddShape(shape)
601
602
603 def SendToBack(self, shape):
604 if shape.GetParent() and isinstance(shape.GetParent(), ogl.CompositeShape):
605 self._diagram.RemoveShape(shape.GetParent())
606 self._diagram.InsertShape(shape.GetParent())
607 else:
608 self._diagram.RemoveShape(shape)
609 self._diagram.InsertShape(shape)
610
611
612 def ScrollVisible(self, shape):
613 if not shape:
614 return
615
616 xUnit, yUnit = self._canvas.GetScrollPixelsPerUnit()
617 scrollX, scrollY = self._canvas.GetViewStart() # in scroll units
618 scrollW, scrollH = self._canvas.GetSize() # in pixels
619 w, h = shape.GetBoundingBoxMax() # in pixels
620 x = shape.GetX() - w/2 # convert to upper left coordinate from center
621 y = shape.GetY() - h/2 # convert to upper left coordinate from center
622
623 if x >= scrollX*xUnit and x <= scrollX*xUnit + scrollW: # don't scroll if already visible
624 x = -1
625 else:
626 x = x/xUnit
627
628 if y >= scrollY*yUnit and y <= scrollY*yUnit + scrollH: # don't scroll if already visible
629 y = -1
630 else:
631 y = y/yUnit
632
633 self._canvas.Scroll(x, y) # in scroll units
634
635
636 def SetPropertyShape(self, shape):
637 # no need to highlight if no PropertyService is running
638 propertyService = wx.GetApp().GetService(PropertyService.PropertyService)
639 if not propertyService:
640 return
641
642 if shape == self._propShape:
643 return
644
645 if hasattr(shape, "GetPropertyShape"):
646 shape = shape.GetPropertyShape()
647
648 dc = wx.ClientDC(self._canvas)
649 self._canvas.PrepareDC(dc)
650 dc.BeginDrawing()
651
652 # erase old selection if it still exists
653 if self._propShape and self._propShape in self._diagram.GetShapeList():
654 if hasattr(self._propShape, "DEFAULT_BRUSH"):
655 self._propShape.SetBrush(self._propShape.DEFAULT_BRUSH)
656 else:
657 self._propShape.SetBrush(self._brush)
658 if (self._propShape._textColourName in ["BLACK", "WHITE"]): # Would use GetTextColour() but it is broken
659 self._propShape.SetTextColour("BLACK", 0)
660 self._propShape.Draw(dc)
661
662 # set new selection
663 self._propShape = shape
664
665 # draw new selection
666 if self._propShape and self._propShape in self._diagram.GetShapeList():
667 if self.HasFocus():
668 self._propShape.SetBrush(SELECT_BRUSH)
669 else:
670 self._propShape.SetBrush(INACTIVE_SELECT_BRUSH)
671 if (self._propShape._textColourName in ["BLACK", "WHITE"]): # Would use GetTextColour() but it is broken
672 self._propShape.SetTextColour("WHITE", 0)
673 self._propShape.Draw(dc)
674
675 dc.EndDrawing()
676
677
678 def FocusColorPropertyShape(self, gotFocus=False):
679 # no need to change highlight if no PropertyService is running
680 propertyService = wx.GetApp().GetService(PropertyService.PropertyService)
681 if not propertyService:
682 return
683
684 if not self._propShape:
685 return
686
687 dc = wx.ClientDC(self._canvas)
688 self._canvas.PrepareDC(dc)
689 dc.BeginDrawing()
690
691 # draw deactivated selection
692 if self._propShape and self._propShape in self._diagram.GetShapeList():
693 if gotFocus:
694 self._propShape.SetBrush(SELECT_BRUSH)
695 else:
696 self._propShape.SetBrush(INACTIVE_SELECT_BRUSH)
697 if (self._propShape._textColourName in ["BLACK", "WHITE"]): # Would use GetTextColour() but it is broken
698 self._propShape.SetTextColour("WHITE", 0)
699 self._propShape.Draw(dc)
700
701 dc.EndDrawing()
702
703
704 #----------------------------------------------------------------------------
705 # Property Service methods
706 #----------------------------------------------------------------------------
707
708 def GetPropertyModel(self):
709 if hasattr(self, "_propModel"):
710 return self._propModel
711 return None
712
713
714 def SetPropertyModel(self, model):
715 # no need to set the model if no PropertyService is running
716 propertyService = wx.GetApp().GetService(PropertyService.PropertyService)
717 if not propertyService:
718 return
719
720 if hasattr(self, "_propModel") and model == self._propModel:
721 return
722
723 self._propModel = model
724 propertyService.LoadProperties(self._propModel, self.GetDocument())
725
726
727 class EditorCanvasShapeMixin:
728
729 def GetModel(self):
730 return self._model
731
732
733 def SetModel(self, model):
734 self._model = model
735
736
737 class EditorCanvasShapeEvtHandler(ogl.ShapeEvtHandler):
738
739 """ wxBug: Bug in OLG package. With wxShape.SetShadowMode() turned on, when we set the size,
740 the width/height is larger by 6 pixels. Need to subtract this value from width and height when we
741 resize the object.
742 """
743 SHIFT_KEY = 1
744 CONTROL_KEY = 2
745
746 def __init__(self, view):
747 ogl.ShapeEvtHandler.__init__(self)
748 self._view = view
749
750
751 def OnLeftClick(self, x, y, keys = 0, attachment = 0):
752 shape = self.GetShape()
753 if hasattr(shape, "GetModel"): # Workaround, on drag, we should deselect all other objects and select the clicked on object
754 model = shape.GetModel()
755 else:
756 shape = shape.GetParent()
757 if shape:
758 model = shape.GetModel()
759
760 if model:
761 self._view.SetSelection(model, keys == self.SHIFT_KEY or keys == self.CONTROL_KEY)
762 self._view.SetPropertyShape(shape)
763 self._view.SetPropertyModel(model)
764
765
766 def OnEndDragLeft(self, x, y, keys = 0, attachment = 0):
767 ogl.ShapeEvtHandler.OnEndDragLeft(self, x, y, keys, attachment)
768 shape = self.GetShape()
769 if hasattr(shape, "GetModel"): # Workaround, on drag, we should deselect all other objects and select the clicked on object
770 model = shape.GetModel()
771 else:
772 parentShape = shape.GetParent()
773 if parentShape:
774 model = parentShape.GetModel()
775 self._view.SetSelection(model, keys == self.SHIFT_KEY or keys == self.CONTROL_KEY)
776
777
778 def OnMovePre(self, dc, x, y, oldX, oldY, display):
779 """ Prevent objects from being dragged outside of viewable area """
780 if (x < 0) or (y < 0) or (x > self._view._maxWidth) or (y > self._view._maxHeight):
781 return False
782
783 return ogl.ShapeEvtHandler.OnMovePre(self, dc, x, y, oldX, oldY, display)
784
785
786 def OnMovePost(self, dc, x, y, oldX, oldY, display):
787 """ Update the model's record of where the shape should be. Also enable redo/undo. """
788 if x == oldX and y == oldY:
789 return
790 if not self._view.GetDocument():
791 return
792 shape = self.GetShape()
793 if isinstance(shape, EditorCanvasShapeMixin) and shape.Draggable():
794 model = shape.GetModel()
795 if hasattr(model, "getEditorBounds") and model.getEditorBounds():
796 x, y, w, h = model.getEditorBounds()
797 newX = shape.GetX() - shape.GetBoundingBoxMax()[0] / 2
798 newY = shape.GetY() - shape.GetBoundingBoxMax()[1] / 2
799 newWidth = shape.GetBoundingBoxMax()[0]
800 newHeight = shape.GetBoundingBoxMax()[1]
801 if shape._shadowMode != ogl.SHADOW_NONE:
802 newWidth -= shape._shadowOffsetX
803 newHeight -= shape._shadowOffsetY
804 newbounds = (newX, newY, newWidth, newHeight)
805
806 if x != newX or y != newY or w != newWidth or h != newHeight:
807 self._view.GetDocument().GetCommandProcessor().Submit(EditorCanvasUpdateShapeBoundariesCommand(self._view.GetDocument(), model, newbounds))
808
809
810 def Draw(self, dc):
811 pass
812
813
814 class EditorCanvasUpdateShapeBoundariesCommand(wx.lib.docview.Command):
815
816
817 def __init__(self, canvasDocument, model, newbounds):
818 wx.lib.docview.Command.__init__(self, canUndo = True)
819 self._canvasDocument = canvasDocument
820 self._model = model
821 self._oldbounds = model.getEditorBounds()
822 self._newbounds = newbounds
823
824
825 def GetName(self):
826 name = self._canvasDocument.GetNameForObject(self._model)
827 if not name:
828 name = ""
829 print "ERROR: AbstractEditor.EditorCanvasUpdateShapeBoundariesCommand.GetName: unable to get name for ", self._model
830 return _("Move/Resize %s") % name
831
832
833 def Do(self):
834 return self._canvasDocument.UpdateEditorBoundaries(self._model, self._newbounds)
835
836
837 def Undo(self):
838 return self._canvasDocument.UpdateEditorBoundaries(self._model, self._oldbounds)
839