1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 __version__ = "$Revision: 1.7 $"
17 __author__ = "Gerrit van Dyk, Carlos, Karsten"
18
19
20 import wx
21
22 MV_HOR = 0
23 MV_VER = not MV_HOR
24
25 SH_SIZE = 5
26 CR_SIZE = SH_SIZE * 3
27
28
30 """
31 Main multisash widget. Dynamically displays a stack of child widgets.
32 """
34 apply(wx.Window.__init__,(self,) + _args,_kwargs)
35
36 self.child = cMultiSashSplitter(self,self,wxPoint(0,0),self.GetSize())
37
38
39 self.focussed_leaf = self.child.leaf1
40 self.bottom_leaf = self.child.leaf1
41 self.displayed_leafs = []
42
43 wx.EVT_SIZE(self,self._on_size)
44
45
46
47
49 """
50 Retrieves the currently focused leaf. Typically, used to
51 process some action over the focused widget.
52 """
53 return self.focussed_leaf
54
56 """
57 Retrieves the currently displayed leafs.
58 """
59 return self.displayed_leafs
60
61 - def add_content(self, content):
62 """
63 Adds he supplied content widget to the multisash, setting it as
64 child of the bottom leaf.
65
66 @param content The new content widget to add.
67 @type content Any wx.Window derived object.
68 """
69 successful, errno = self.bottom_leaf.AddLeaf(direction = MV_VER, pos = 100)
70 if successful:
71 self.bottom_leaf.set_content(content)
72 return successful, errno
73
75 """
76 Clear all mulsisash leafs and restores initial values
77 """
78
79 old = self.child
80 self.child = cMultiSashSplitter(self,self,wxPoint(0,0),self.GetSize())
81 old.DestroyLater()
82 self.child.OnSize(None)
83
84
85 self.focussed_leaf = self.child.leaf1
86 self.bottom_leaf = self.child.leaf1
87 self.bottom_leaf.Select()
88 self.displayed_leafs = []
89
91 """
92 Updates the field that keeps track of the bottom leaf. It is required
93 to ensure new leafs are created under the bottom one.
94 If the bottom leaf is supplied as parameter, it is set. Typically,
95 after a new leaf has been added/created.
96 If the bottom leaf ins not supplied ad parameter, it will be dinamically
97 obtained. Typically, after leaf destruction.
98
99 @param bottom_leaf The leaf to be set as bottom one
100 @type bottom_leaf wx.MultiViewLeaf
101 """
102 if bottom_leaf is None:
103 self.bottom_leaf = self.__find_bottom_leaf(self.child)
104 else:
105 self.bottom_leaf = bottom_leaf
106 self.bottom_leaf.Select()
107
108
110 """
111 Recursively find all displayed leafs.
112 @param splitter The multisash splitter to traverse its leafs for.
113 @type splitter cMultiSashSplitter
114 """
115 if id(splitter) == id(self.child):
116 self.displayed_leafs = []
117
118
119
120
121 if isinstance(splitter.leaf1, cMultiSashSplitter):
122
123 self.refresh_displayed_leafs(splitter.leaf1)
124 if isinstance(splitter.leaf2, cMultiSashSplitter):
125
126 self.refresh_displayed_leafs(splitter.leaf2)
127
128 if not splitter.leaf2 is None and not isinstance(splitter.leaf2, cMultiSashSplitter):
129
130 self.displayed_leafs.append(splitter.leaf2)
131 if not splitter.leaf1 is None and not isinstance(splitter.leaf1, cMultiSashSplitter):
132
133 self.displayed_leafs.append(splitter.leaf1)
134
135
136
139
140
141
143 """
144 Recursively find and return the bottom leaf.
145 """
146
147
148
149
150 if isinstance(splitter.leaf1, cMultiSashSplitter):
151
152 return self.__find_bottom_leaf(splitter.leaf1)
153 if isinstance(splitter.leaf2, cMultiSashSplitter):
154
155 return self.__find_bottom_leaf(splitter.leaf2)
156
157 if not splitter.leaf2 is None:
158
159 return splitter.leaf2
160 else:
161
162 return splitter.leaf1
163
165 self.child._unselect()
166
168 """
169 Basic split windows container of the multisash widget.
170 Has references to two leafs or splitted windows (typically, first leaf
171 is another cMultiSashSplitter and the second leaf is the displayed content
172 widget).
173 """
174 - def __init__(self, top_parent, parent, pos, size, leaf1 = None):
175 wx.Window.__init__ (
176 self,
177 id = -1,
178 parent = parent,
179 pos = pos,
180 size = size,
181 style = wx.CLIP_CHILDREN
182 )
183 self.top_parent = top_parent
184 self.leaf2 = None
185 if leaf1:
186 self.leaf1 = leaf1
187 self.leaf1.Reparent(self)
188 self.leaf1.Move(0,0)
189 else:
190 self.leaf1 = cMultiSashLeaf (
191 self.top_parent,
192 self,
193 wxPoint(0,0),
194 self.GetSize()
195 )
196 self.direction = None
197
198 wx.EVT_SIZE(self,self.OnSize)
199
201 if self.leaf1:
202 self.leaf1._unselect()
203 if self.leaf2:
204 self.leaf2._unselect()
205
206
207 - def AddLeaf(self,direction,caller,pos):
208
209
210
211 if self.leaf2:
212
213
214 if caller == self.leaf1:
215
216 self.leaf1 = cMultiSashSplitter(self.top_parent,self,
217 caller.GetPosition(),
218 caller.GetSize(),
219 caller)
220 self.leaf1.AddLeaf(direction,caller,pos)
221 else:
222
223 self.leaf2 = cMultiSashSplitter(self.top_parent,self,
224 caller.GetPosition(),
225 caller.GetSize(),
226 caller)
227 self.leaf2.AddLeaf(direction,caller,pos)
228 else:
229
230
231
232 self.direction = direction
233 w,h = self.GetSize()
234 if direction == MV_HOR:
235
236 x,y = (pos,0)
237 w1,h1 = (w-pos,h)
238 w2,h2 = (pos,h)
239 else:
240
241 x,y = (0,pos)
242 w1,h1 = (w,h-pos)
243 w2,h2 = (w,pos)
244 self.leaf2 = cMultiSashLeaf(self.top_parent,self,
245 wxPoint(x,y),wx.Size(w1,h1))
246 self.leaf1.SetSize(wx.Size(w2,h2))
247 self.leaf2.OnSize(None)
248
249 self.top_parent.displayed_leafs.append(self.leaf2)
250
251 self.top_parent.refresh_bottom_leaf(self.leaf2)
252 self.leaf2.set_focus()
253
255
256 top_parent = self.top_parent
257 if not self.leaf2:
258 self.leaf1.set_content(cEmptyChild(self))
259 return
260 parent = self.GetParent()
261 if parent == self.top_parent:
262
263
264 if caller == self.leaf1:
265
266 old = self.leaf1
267 self.leaf1 = self.leaf2
268 self.leaf2 = None
269
270
271
272 old.DestroyLater()
273 else:
274
275
276
277
278 self.leaf2.DestroyLater()
279 self.leaf2 = None
280 self.leaf1.SetSize(self.GetSize())
281 self.leaf1.Move(self.GetPosition())
282 else:
283
284
285
286
287 self.top_parent.displayed_leafs.remove(caller)
288 w,h = self.GetSize()
289 x,y = self.GetPosition()
290 if caller == self.leaf1:
291 if self == parent.leaf1:
292
293 parent.leaf1 = self.leaf2
294 else:
295
296 parent.leaf2 = self.leaf2
297
298 self.leaf2.Reparent(parent)
299 self.leaf2.SetDimensions(x,y,w,h)
300
301
302 else:
303 if self == parent.leaf1:
304
305 parent.leaf1 = self.leaf1
306 else:
307
308 parent.leaf2 = self.leaf1
309
310 self.leaf1.Reparent(parent)
311 self.leaf1.SetDimensions(x,y,w,h)
312
313 self.leaf1 = None
314 self.leaf2 = None
315 top_parent = self.top_parent
316 self.DestroyLater()
317
318
319
320
321
322
323
324
325
326 top_parent.refresh_bottom_leaf()
327 top_parent.refresh_displayed_leafs(top_parent.child)
328
329
330
331
332
333
338
346
348 if self.direction != side:
349 return
350 if not (self.leaf1 and self.leaf2):
351 return
352 if pos < 10: return
353 w,h = self.GetSize()
354 if side == MV_HOR:
355 if pos > w - 10: return
356 else:
357 if pos > h - 10: return
358 if side == MV_HOR:
359 self.leaf1.SetDimensions(0,0,pos,h)
360 self.leaf2.SetDimensions(pos,0,w-pos,h)
361 else:
362 self.leaf1.SetDimensions(0,0,w,pos)
363 self.leaf2.SetDimensions(0,pos,w,h-pos)
364
366 if not self.leaf2:
367 self.leaf1.SetSize(self.GetSize())
368 self.leaf1.OnSize(None)
369 return
370 v1w,v1h = self.leaf1.GetSize()
371 v2w,v2h = self.leaf2.GetSize()
372 v1x,v1y = self.leaf1.GetPosition()
373 v2x,v2y = self.leaf2.GetPosition()
374 w,h = self.GetSize()
375
376 if v1x != v2x:
377 ratio = float(w) / float((v1w + v2w))
378 v1w *= ratio
379 v2w = w - v1w
380 v2x = v1w
381 else:
382 v1w = v2w = w
383
384 if v1y != v2y:
385 ratio = float(h) / float((v1h + v2h))
386 v1h *= ratio
387 v2h = h - v1h
388 v2y = v1h
389 else:
390 v1h = v2h = h
391
392 self.leaf1.SetDimensions(v1x,v1y,v1w,v1h)
393 self.leaf2.SetDimensions(v2x,v2y,v2w,v2h)
394 self.leaf1.OnSize(None)
395 self.leaf2.OnSize(None)
396
397
399 """
400 A leaf represent a split window, one instance of the displayed content
401 widget.
402 """
403 - def __init__(self,top_parent,parent,pos,size):
417
419 """
420 Set current leaf as focused leaf. Typically, the focused widget
421 will be required to further actions and processing.
422 """
423 self.top_parent.focussed_leaf = self
424
425
427 self.content._unselect()
428
429
430 - def set_content(self, content):
431 """
432 Sets the as content child of this leaf.
433
434 @param content The new content widget to set..
435 @type content Any wx.Window derived object.
436 """
437 self.content.set_new_content(content)
438
439
440 - def get_content(self):
441 """
442 Retrieves the content child of this leaf.
443 """
444 return self.content.child
445
446
448 """
449 Select the leaf
450 """
451 self.content.Select()
452
454 """Add a leaf.
455
456 returns (Status, error)
457 errors:
458 1: lacking space to add leaf
459 """
460
461 if pos < 10:
462 pos = 10
463 w,h = self.GetSize()
464 if direction == MV_VER:
465 if pos > h - 10:
466
467
468 return (False, 1)
469 else:
470 if pos > w - 10: return (False, 1)
471
472
473 if not isinstance(self.content.child, cEmptyChild):
474 self.GetParent().AddLeaf(direction,self,pos)
475 else:
476 self.set_focus()
477
478 self.GetParent().top_parent.displayed_leafs.append(self)
479 return (True, None)
480
481
485
486
489
492
494 self.sizerHor.OnSize(evt)
495 self.sizerVer.OnSize(evt)
496
497
498
499 self.content.OnSize(evt)
500 self.closer.OnSize(evt)
501
502
503 -class cMultiSashLeafContent(wx.Window):
504 """
505 Widget that encapsulate contents of a leaf or split window.
506 """
507 - def __init__(self,parent):
508 w,h = self.CalcSize(parent)
509 wx.Window.__init__ (
510 self,
511 id = -1,
512 parent = parent,
513 pos = wxPoint(0,0),
514 size = wx.Size(w,h),
515 style = wx.CLIP_CHILDREN | wx.SUNKEN_BORDER
516 )
517 self.child = cEmptyChild(self)
518 self.child.Move(2,2)
519 self.__normal_colour = self.GetBackgroundColour()
520 self.selected = False
521
522 wx.EVT_SET_FOCUS(self, self._on_set_focus)
523 wx.EVT_CHILD_FOCUS(self, self._on_child_focus)
524
525 - def set_new_content(self,content):
526 """
527 Sets the as content child of this widget.
528
529 @param content The new content widget to set..
530 @type content Any wx.Window derived object.
531 """
532
533 self.SetBackgroundColour(self.__normal_colour)
534 if self.child:
535 self.child.DestroyLater()
536 content.Reparent(self)
537 self.child = content
538 self.child.Move(2,2)
539
540 self.Select()
541 self.OnSize(None)
542
543
544
545 - def _unselect(self):
546 if self.selected:
547 self.selected = False
548 self.SetBackgroundColour(self.__normal_colour)
549 self.Refresh()
550
551 - def _on_set_focus(self,evt):
553
554 - def _on_child_focus(self,evt):
555 self._on_set_focus(evt)
556
557
558
559
560
562 """
563 May be invoked by user clicking on the leaf, or programmatically after
564 leaf creation. Highlight it and update focused leaf.
565 """
566
567 parent = self.GetParent()
568 parent.top_parent._unselect()
569 self.selected = True
570 if parent.top_parent.focussed_leaf != parent:
571 parent.set_focus()
572 self.SetBackgroundColour(wx.Colour(255,255,0))
573 self.Refresh()
574
575 - def CalcSize(self,parent):
576 w,h = parent.GetSize()
577 w -= SH_SIZE
578 h -= SH_SIZE
579 return (w,h)
580
581 - def OnSize(self,evt):
582 w,h = self.CalcSize(self.GetParent())
583 self.SetDimensions(0,0,w,h)
584 w,h = self.GetClientSize()
585 self.child.SetSize(wx.Size(w-4,h-4))
586
587
589 """
590 Leaf's sash bar
591 """
593 self.side = side
594 x,y,w,h = self.CalcSizePos(parent)
595 wx.Window.__init__(self,id = -1,parent = parent,
596 pos = wxPoint(x,y),
597 size = wx.Size(w,h),
598 style = wx.CLIP_CHILDREN)
599
600 self.px = None
601 self.py = None
602 self.isDrag = False
603 self.dragTarget = None
604
605 wx.EVT_LEAVE_WINDOW(self,self.OnLeave)
606 wx.EVT_ENTER_WINDOW(self,self.OnEnter)
607 wx.EVT_MOTION(self,self.OnMouseMove)
608 wx.EVT_LEFT_DOWN(self,self.OnPress)
609 wx.EVT_LEFT_UP(self,self.OnRelease)
610
624
628
630 self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
631
633 if not self.GetParent().CanSize(not self.side):
634 return
635 if self.side == MV_HOR:
636 self.SetCursor(wx.StockCursor(wx.CURSOR_SIZENS))
637 else:
638 self.SetCursor(wx.StockCursor(wx.CURSOR_SIZEWE))
639
641 if self.isDrag:
642 DrawSash(self.dragTarget,self.px,self.py,self.side)
643 self.px,self.py = self.ClientToScreen(evt.x,evt.y)
644 self.px,self.py = self.dragTarget.ScreenToClientXY(self.px,self.py)
645 DrawSash(self.dragTarget,self.px,self.py,self.side)
646 else:
647 evt.Skip()
648
650 self.dragTarget = self.GetParent().SizeTarget(not self.side)
651 if self.dragTarget:
652 self.isDrag = True
653 self.px,self.py = self.ClientToScreen(evt.x,evt.y)
654 self.px,self.py = self.dragTarget.ScreenToClientXY(self.px,self.py)
655 DrawSash(self.dragTarget,self.px,self.py,self.side)
656 self.CaptureMouse()
657 else:
658 evt.Skip()
659
661 if self.isDrag:
662 DrawSash(self.dragTarget,self.px,self.py,self.side)
663 self.ReleaseMouse()
664 self.isDrag = False
665 if self.side == MV_HOR:
666 self.dragTarget.SizeLeaf(self.GetParent(),
667 self.py,not self.side)
668 else:
669 self.dragTarget.SizeLeaf(self.GetParent(),
670 self.px,not self.side)
671 self.dragTarget = None
672 else:
673 evt.Skip()
674
675
677 """
678 Sash bar's creator element
679 """
681 self.side = side
682 x,y,w,h = self.CalcSizePos(parent)
683 wx.Window.__init__(self,id = -1,parent = parent,
684 pos = wxPoint(x,y),
685 size = wx.Size(w,h),
686 style = wx.CLIP_CHILDREN)
687
688 self.px = None
689 self.py = None
690 self.isDrag = False
691
692 wx.EVT_LEAVE_WINDOW(self,self.OnLeave)
693 wx.EVT_ENTER_WINDOW(self,self.OnEnter)
694 wx.EVT_MOTION(self,self.OnMouseMove)
695 wx.EVT_LEFT_DOWN(self,self.OnPress)
696 wx.EVT_LEFT_UP(self,self.OnRelease)
697 wx.EVT_PAINT(self,self.OnPaint)
698
712
716
718 self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
719
721 if self.side == MV_HOR:
722 self.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
723 else:
724 self.SetCursor(wx.StockCursor(wx.CURSOR_POINT_LEFT))
725
727 if self.isDrag:
728 parent = self.GetParent()
729 DrawSash(parent,self.px,self.py,self.side)
730 self.px,self.py = self.ClientToScreen(evt.x,evt.y)
731 self.px,self.py = parent.ScreenToClientXY(self.px,self.py)
732 DrawSash(parent,self.px,self.py,self.side)
733 else:
734 evt.Skip()
735
737 self.isDrag = True
738 parent = self.GetParent()
739 self.px,self.py = self.ClientToScreen(evt.x,evt.y)
740 self.px,self.py = parent.ScreenToClientXY(self.px,self.py)
741 DrawSash(parent,self.px,self.py,self.side)
742 self.CaptureMouse()
743
757
759 dc = wxPaintDC(self)
760 dc.SetBackground(wx.Brush(self.GetBackgroundColour(),wx.SOLID))
761 dc.Clear()
762
763 highlight = wxPen(wx.SystemSettings.GetSystemColour(
764 wx.SYS_COLOUR_BTNHIGHLIGHT),1,wx.SOLID)
765 shadow = wxPen(wx.SystemSettings.GetSystemColour(
766 wx.SYS_COLOUR_BTNSHADOW),1,wx.SOLID)
767 black = wxPen(wx.BLACK,1,wx.SOLID)
768 w,h = self.GetSize()
769 w -= 1
770 h -= 1
771
772
773 dc.SetPen(highlight)
774 dc.DrawLine(0,0,0,h)
775 dc.DrawLine(0,0,w,0)
776 dc.SetPen(black)
777 dc.DrawLine(0,h,w+1,h)
778 dc.DrawLine(w,0,w,h)
779 dc.SetPen(shadow)
780 dc.DrawLine(w-1,2,w-1,h)
781
782
784 """
785 Sash bar's destroyer element
786 """
788 x,y,w,h = self.CalcSizePos(parent)
789 wx.Window.__init__(self,id = -1,parent = parent,
790 pos = wxPoint(x,y),
791 size = wx.Size(w,h),
792 style = wx.CLIP_CHILDREN)
793
794 self.down = False
795 self.entered = False
796
797 wx.EVT_LEFT_DOWN(self,self.OnPress)
798 wx.EVT_LEFT_UP(self,self.OnRelease)
799 wx.EVT_PAINT(self,self.OnPaint)
800 wx.EVT_LEAVE_WINDOW(self,self.OnLeave)
801 wx.EVT_ENTER_WINDOW(self,self.OnEnter)
802
804 self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
805 self.entered = False
806
808 self.SetCursor(wx.StockCursor(wx.CURSOR_BULLSEYE))
809 self.entered = True
810
812 self.down = True
813 evt.Skip()
814
816 if self.down and self.entered:
817 self.GetParent().DestroyLeaf()
818 else:
819 evt.Skip()
820 self.down = False
821
823 dc = wxPaintDC(self)
824 dc.SetBackground(wx.Brush(wx.RED,wx.SOLID))
825 dc.Clear()
826
834
838
839
840
841
842
846
847
848
849
850
852 dc = wx.ScreenDC()
853 dc.StartDrawingOnTopWin(win)
854 bmp = wx.Bitmap(8,8)
855 bdc = wx.MemoryDC()
856 bdc.SelectObject(bmp)
857 bdc.DrawRectangle(-1,-1,10,10)
858 for i in range(8):
859 for j in range(8):
860 if ((i + j) & 1):
861 bdc.DrawPoint(i,j)
862
863 brush = wx.Brush(wx.Colour(0,0,0))
864 brush.SetStipple(bmp)
865
866 dc.SetBrush(brush)
867 dc.SetLogicalFunction(wx.XOR)
868
869 body_w,body_h = win.GetClientSize()
870
871 if y < 0:
872 y = 0
873 if y > body_h:
874 y = body_h
875 if x < 0:
876 x = 0
877 if x > body_w:
878 x = body_w
879
880 if direction == MV_HOR:
881 x = 0
882 else:
883 y = 0
884
885 x,y = win.ClientToScreen(x,y)
886
887 w = body_w
888 h = body_h
889
890 if direction == MV_HOR:
891 dc.DrawRectangle(x,y-2,w,4)
892 else:
893 dc.DrawRectangle(x-2,y,4,h)
894
895 dc.EndDrawingOnTop()
896
897