]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/lib/multisash.py
1 #----------------------------------------------------------------------
3 # Purpose: Multi Sash control
5 # Author: Gerrit van Dyk
10 # License: wxWindows license
11 #----------------------------------------------------------------------
12 # 12/09/2003 - Jeff Grimmett (grimmtooth@softhome.net)
14 # o 2.5 compatability update.
16 # 12/20/2003 - Jeff Grimmett (grimmtooth@softhome.net)
18 # o wxMultiSash -> MultiSash
19 # o wxMultiSplit -> MultiSplit wxMultiViewLeaf
20 # o wxMultiViewLeaf -> MultiViewLeaf
31 #----------------------------------------------------------------------
33 class MultiSash(wx
.Window
):
34 def __init__(self
, *_args
,**_kwargs
):
35 apply(wx
.Window
.__init
__,(self
,) + _args
,_kwargs
)
36 self
._defChild
= EmptyChild
37 self
.child
= MultiSplit(self
,self
,(0,0),self
.GetSize())
38 self
.Bind(wx
.EVT_SIZE
,self
.OnMultiSize
)
40 def SetDefaultChildClass(self
,childCls
):
41 self
._defChild
= childCls
42 self
.child
.DefaultChildChanged()
44 def OnMultiSize(self
,evt
):
45 self
.child
.SetSize(self
.GetSize())
52 self
.child
= MultiSplit(self
,self
,(0,0),self
.GetSize())
54 self
.child
.OnSize(None)
56 def GetSaveData(self
):
58 saveData
['_defChild'] = str(self
._defChild
)
59 saveData
['child'] = self
.child
.GetSaveData()
62 def SetSaveData(self
,data
):
63 dChild
= data
['_defChild']
64 mod
= dChild
.split('.')[0]
65 exec 'import %s' % mod
66 self
._defChild
= eval(dChild
)
68 self
.child
= MultiSplit(self
,self
,wxPoint(0,0),self
.GetSize())
69 self
.child
.SetSaveData(data
['child'])
71 self
.OnMultiSize(None)
72 self
.child
.OnSize(None)
75 #----------------------------------------------------------------------
78 class MultiSplit(wx
.Window
):
79 def __init__(self
,multiView
,parent
,pos
,size
,view1
= None):
80 wx
.Window
.__init
__(self
,id = -1,parent
= parent
,pos
= pos
,size
= size
,
81 style
= wx
.CLIP_CHILDREN
)
82 self
.multiView
= multiView
86 self
.view1
.Reparent(self
)
87 self
.view1
.MoveXY(0,0)
89 self
.view1
= MultiViewLeaf(self
.multiView
,self
,
93 self
.Bind(wx
.EVT_SIZE
,self
.OnSize
)
95 def GetSaveData(self
):
98 saveData
['view1'] = self
.view1
.GetSaveData()
99 if isinstance(self
.view1
,MultiSplit
):
100 saveData
['view1IsSplit'] = 1
102 saveData
['view2'] = self
.view2
.GetSaveData()
103 if isinstance(self
.view2
,MultiSplit
):
104 saveData
['view2IsSplit'] = 1
105 saveData
['direction'] = self
.direction
106 v1
,v2
= self
.GetPosition()
109 v1
,v2
= self
.GetSize()
114 def SetSaveData(self
,data
):
115 self
.direction
= data
['direction']
116 self
.SetDimensions(data
['x'],data
['y'],data
['w'],data
['h'])
117 v1Data
= data
.get('view1',None)
119 isSplit
= data
.get('view1IsSplit',None)
122 self
.view1
= MultiSplit(self
.multiView
,self
,
123 (0,0),self
.GetSize())
125 self
.view1
= MultiViewLeaf(self
.multiView
,self
,
126 (0,0),self
.GetSize())
127 self
.view1
.SetSaveData(v1Data
)
130 v2Data
= data
.get('view2',None)
132 isSplit
= data
.get('view2IsSplit',None)
135 self
.view2
= MultiSplit(self
.multiView
,self
,
136 (0,0),self
.GetSize())
138 self
.view2
= MultiViewLeaf(self
.multiView
,self
,
139 (0,0),self
.GetSize())
140 self
.view2
.SetSaveData(v2Data
)
144 self
.view1
.OnSize(None)
146 self
.view2
.OnSize(None)
150 self
.view1
.UnSelect()
152 self
.view2
.UnSelect()
154 def DefaultChildChanged(self
):
156 self
.view1
.DefaultChildChanged()
158 def AddLeaf(self
,direction
,caller
,pos
):
160 if caller
== self
.view1
:
161 self
.view1
= MultiSplit(self
.multiView
,self
,
162 caller
.GetPosition(),
165 self
.view1
.AddLeaf(direction
,caller
,pos
)
167 self
.view2
= MultiSplit(self
.multiView
,self
,
168 caller
.GetPosition(),
171 self
.view2
.AddLeaf(direction
,caller
,pos
)
173 self
.direction
= direction
175 if direction
== MV_HOR
:
183 self
.view2
= MultiViewLeaf(self
.multiView
, self
, (x
,y
), (w1
,h1
))
184 self
.view1
.SetSize((w2
,h2
))
185 self
.view2
.OnSize(None)
187 def DestroyLeaf(self
,caller
):
188 if not self
.view2
: # We will only have 2 windows if
189 return # we need to destroy any
190 parent
= self
.GetParent() # Another splitview
191 if parent
== self
.multiView
: # We'r at the root
192 if caller
== self
.view1
:
194 self
.view1
= self
.view2
200 self
.view1
.SetSize(self
.GetSize())
201 self
.view1
.Move(self
.GetPosition())
204 x
,y
= self
.GetPosition()
205 if caller
== self
.view1
:
206 if self
== parent
.view1
:
207 parent
.view1
= self
.view2
209 parent
.view2
= self
.view2
210 self
.view2
.Reparent(parent
)
211 self
.view2
.SetDimensions(x
,y
,w
,h
)
213 if self
== parent
.view1
:
214 parent
.view1
= self
.view1
216 parent
.view2
= self
.view1
217 self
.view1
.Reparent(parent
)
218 self
.view1
.SetDimensions(x
,y
,w
,h
)
223 def CanSize(self
,side
,view
):
224 if self
.SizeTarget(side
,view
):
228 def SizeTarget(self
,side
,view
):
229 if self
.direction
== side
and self
.view2
and view
== self
.view1
:
231 parent
= self
.GetParent()
232 if parent
!= self
.multiView
:
233 return parent
.SizeTarget(side
,self
)
236 def SizeLeaf(self
,leaf
,pos
,side
):
237 if self
.direction
!= side
:
239 if not (self
.view1
and self
.view2
):
244 if pos
> w
- 10: return
246 if pos
> h
- 10: return
248 self
.view1
.SetDimensions(0,0,pos
,h
)
249 self
.view2
.SetDimensions(pos
,0,w
-pos
,h
)
251 self
.view1
.SetDimensions(0,0,w
,pos
)
252 self
.view2
.SetDimensions(0,pos
,w
,h
-pos
)
254 def OnSize(self
,evt
):
256 self
.view1
.SetSize(self
.GetSize())
257 self
.view1
.OnSize(None)
259 v1w
,v1h
= self
.view1
.GetSize()
260 v2w
,v2h
= self
.view2
.GetSize()
261 v1x
,v1y
= self
.view1
.GetPosition()
262 v2x
,v2y
= self
.view2
.GetPosition()
266 ratio
= float(w
) / float((v1w
+ v2w
))
274 ratio
= float(h
) / float((v1h
+ v2h
))
281 self
.view1
.SetDimensions(v1x
,v1y
,v1w
,v1h
)
282 self
.view2
.SetDimensions(v2x
,v2y
,v2w
,v2h
)
283 self
.view1
.OnSize(None)
284 self
.view2
.OnSize(None)
287 #----------------------------------------------------------------------
290 class MultiViewLeaf(wx
.Window
):
291 def __init__(self
,multiView
,parent
,pos
,size
):
292 wx
.Window
.__init
__(self
,id = -1,parent
= parent
,pos
= pos
,size
= size
,
293 style
= wx
.CLIP_CHILDREN
)
294 self
.multiView
= multiView
296 self
.sizerHor
= MultiSizer(self
,MV_HOR
)
297 self
.sizerVer
= MultiSizer(self
,MV_VER
)
298 self
.creatorHor
= MultiCreator(self
,MV_HOR
)
299 self
.creatorVer
= MultiCreator(self
,MV_VER
)
300 self
.detail
= MultiClient(self
,multiView
._defChild
)
301 self
.closer
= MultiCloser(self
)
303 self
.Bind(wx
.EVT_SIZE
,self
.OnSize
)
305 def GetSaveData(self
):
307 saveData
['detailClass'] = str(self
.detail
.child
.__class
__)
308 if hasattr(self
.detail
.child
,'GetSaveData'):
309 attr
= getattr(self
.detail
.child
,'GetSaveData')
313 saveData
['detail'] = dData
314 v1
,v2
= self
.GetPosition()
317 v1
,v2
= self
.GetSize()
322 def SetSaveData(self
,data
):
323 dChild
= data
['detailClass']
324 mod
= dChild
.split('.')[0]
325 exec 'import %s' % mod
326 detClass
= eval(dChild
)
327 self
.SetDimensions(data
['x'],data
['y'],data
['w'],data
['h'])
329 self
.detail
= MultiClient(self
,detClass
)
330 dData
= data
.get('detail',None)
332 if hasattr(self
.detail
.child
,'SetSaveData'):
333 attr
= getattr(self
.detail
.child
,'SetSaveData')
337 self
.detail
.OnSize(None)
340 self
.detail
.UnSelect()
342 def DefaultChildChanged(self
):
343 self
.detail
.SetNewChildCls(self
.multiView
._defChild
)
345 def AddLeaf(self
,direction
,pos
):
348 if direction
== MV_VER
:
349 if pos
> h
- 10: return
351 if pos
> w
- 10: return
352 self
.GetParent().AddLeaf(direction
,self
,pos
)
354 def DestroyLeaf(self
):
355 self
.GetParent().DestroyLeaf(self
)
357 def SizeTarget(self
,side
):
358 return self
.GetParent().SizeTarget(side
,self
)
360 def CanSize(self
,side
):
361 return self
.GetParent().CanSize(side
,self
)
363 def OnSize(self
,evt
):
364 self
.sizerHor
.OnSize(evt
)
365 self
.sizerVer
.OnSize(evt
)
366 self
.creatorHor
.OnSize(evt
)
367 self
.creatorVer
.OnSize(evt
)
368 self
.detail
.OnSize(evt
)
369 self
.closer
.OnSize(evt
)
371 #----------------------------------------------------------------------
374 class MultiClient(wx
.Window
):
375 def __init__(self
,parent
,childCls
):
376 w
,h
= self
.CalcSize(parent
)
377 wx
.Window
.__init
__(self
,id = -1,parent
= parent
,
380 style
= wx
.CLIP_CHILDREN | wx
.SUNKEN_BORDER
)
381 self
.child
= childCls(self
)
382 self
.child
.MoveXY(2,2)
383 self
.normalColour
= self
.GetBackgroundColour()
384 self
.selected
= False
386 self
.Bind(wx
.EVT_SET_FOCUS
,self
.OnSetFocus
)
387 self
.Bind(wx
.EVT_CHILD_FOCUS
,self
.OnChildFocus
)
391 self
.selected
= False
392 self
.SetBackgroundColour(self
.normalColour
)
396 self
.GetParent().multiView
.UnSelect()
398 self
.SetBackgroundColour(wx
.Colour(255,255,0)) # Yellow
401 def CalcSize(self
,parent
):
402 w
,h
= parent
.GetSize()
407 def OnSize(self
,evt
):
408 w
,h
= self
.CalcSize(self
.GetParent())
409 self
.SetDimensions(0,0,w
,h
)
410 w
,h
= self
.GetClientSize()
411 self
.child
.SetSize((w
-4,h
-4))
413 def SetNewChildCls(self
,childCls
):
417 self
.child
= childCls(self
)
418 self
.child
.MoveXY(2,2)
420 def OnSetFocus(self
,evt
):
423 def OnChildFocus(self
,evt
):
425 ## from Funcs import FindFocusedChild
426 ## child = FindFocusedChild(self)
427 ## child.Bind(wx.EVT_KILL_FOCUS,self.OnChildKillFocus)
430 #----------------------------------------------------------------------
433 class MultiSizer(wx
.Window
):
434 def __init__(self
,parent
,side
):
436 x
,y
,w
,h
= self
.CalcSizePos(parent
)
437 wx
.Window
.__init
__(self
,id = -1,parent
= parent
,
440 style
= wx
.CLIP_CHILDREN
)
442 self
.px
= None # Previous X
443 self
.py
= None # Previous Y
444 self
.isDrag
= False # In Dragging
445 self
.dragTarget
= None # View being sized
447 self
.Bind(wx
.EVT_LEAVE_WINDOW
,self
.OnLeave
)
448 self
.Bind(wx
.EVT_ENTER_WINDOW
,self
.OnEnter
)
449 self
.Bind(wx
.EVT_MOTION
,self
.OnMouseMove
)
450 self
.Bind(wx
.EVT_LEFT_DOWN
,self
.OnPress
)
451 self
.Bind(wx
.EVT_LEFT_UP
,self
.OnRelease
)
453 def CalcSizePos(self
,parent
):
454 pw
,ph
= parent
.GetSize()
455 if self
.side
== MV_HOR
:
458 w
= pw
- CR_SIZE
- SH_SIZE
- 2
462 y
= CR_SIZE
+ 2 + SH_SIZE
464 h
= ph
- CR_SIZE
- SH_SIZE
- 4 - SH_SIZE
# For Closer
467 def OnSize(self
,evt
):
468 x
,y
,w
,h
= self
.CalcSizePos(self
.GetParent())
469 self
.SetDimensions(x
,y
,w
,h
)
471 def OnLeave(self
,evt
):
472 self
.SetCursor(wx
.StockCursor(wx
.CURSOR_ARROW
))
474 def OnEnter(self
,evt
):
475 if not self
.GetParent().CanSize(not self
.side
):
477 if self
.side
== MV_HOR
:
478 self
.SetCursor(wx
.StockCursor(wx
.CURSOR_SIZENS
))
480 self
.SetCursor(wx
.StockCursor(wx
.CURSOR_SIZEWE
))
482 def OnMouseMove(self
,evt
):
484 DrawSash(self
.dragTarget
,self
.px
,self
.py
,self
.side
)
485 self
.px
,self
.py
= self
.ClientToScreenXY(evt
.m_x
,evt
.m_y
)
486 self
.px
,self
.py
= self
.dragTarget
.ScreenToClientXY(self
.px
,self
.py
)
487 DrawSash(self
.dragTarget
,self
.px
,self
.py
,self
.side
)
491 def OnPress(self
,evt
):
492 self
.dragTarget
= self
.GetParent().SizeTarget(not self
.side
)
495 self
.px
,self
.py
= self
.ClientToScreenXY(evt
.m_x
,evt
.m_y
)
496 self
.px
,self
.py
= self
.dragTarget
.ScreenToClientXY(self
.px
,self
.py
)
497 DrawSash(self
.dragTarget
,self
.px
,self
.py
,self
.side
)
502 def OnRelease(self
,evt
):
504 DrawSash(self
.dragTarget
,self
.px
,self
.py
,self
.side
)
507 if self
.side
== MV_HOR
:
508 self
.dragTarget
.SizeLeaf(self
.GetParent(),
509 self
.py
,not self
.side
)
511 self
.dragTarget
.SizeLeaf(self
.GetParent(),
512 self
.px
,not self
.side
)
513 self
.dragTarget
= None
517 #----------------------------------------------------------------------
520 class MultiCreator(wx
.Window
):
521 def __init__(self
,parent
,side
):
523 x
,y
,w
,h
= self
.CalcSizePos(parent
)
524 wx
.Window
.__init
__(self
,id = -1,parent
= parent
,
527 style
= wx
.CLIP_CHILDREN
)
529 self
.px
= None # Previous X
530 self
.py
= None # Previous Y
531 self
.isDrag
= False # In Dragging
533 self
.Bind(wx
.EVT_LEAVE_WINDOW
,self
.OnLeave
)
534 self
.Bind(wx
.EVT_ENTER_WINDOW
,self
.OnEnter
)
535 self
.Bind(wx
.EVT_MOTION
,self
.OnMouseMove
)
536 self
.Bind(wx
.EVT_LEFT_DOWN
,self
.OnPress
)
537 self
.Bind(wx
.EVT_LEFT_UP
,self
.OnRelease
)
538 self
.Bind(wx
.EVT_PAINT
,self
.OnPaint
)
540 def CalcSizePos(self
,parent
):
541 pw
,ph
= parent
.GetSize()
542 if self
.side
== MV_HOR
:
549 y
= 4 + SH_SIZE
# Make provision for closer
554 def OnSize(self
,evt
):
555 x
,y
,w
,h
= self
.CalcSizePos(self
.GetParent())
556 self
.SetDimensions(x
,y
,w
,h
)
558 def OnLeave(self
,evt
):
559 self
.SetCursor(wx
.StockCursor(wx
.CURSOR_ARROW
))
561 def OnEnter(self
,evt
):
562 if self
.side
== MV_HOR
:
563 self
.SetCursor(wx
.StockCursor(wx
.CURSOR_HAND
))
565 self
.SetCursor(wx
.StockCursor(wx
.CURSOR_POINT_LEFT
))
567 def OnMouseMove(self
,evt
):
569 parent
= self
.GetParent()
570 DrawSash(parent
,self
.px
,self
.py
,self
.side
)
571 self
.px
,self
.py
= self
.ClientToScreenXY(evt
.m_x
,evt
.m_y
)
572 self
.px
,self
.py
= parent
.ScreenToClientXY(self
.px
,self
.py
)
573 DrawSash(parent
,self
.px
,self
.py
,self
.side
)
577 def OnPress(self
,evt
):
579 parent
= self
.GetParent()
580 self
.px
,self
.py
= self
.ClientToScreenXY(evt
.m_x
,evt
.m_y
)
581 self
.px
,self
.py
= parent
.ScreenToClientXY(self
.px
,self
.py
)
582 DrawSash(parent
,self
.px
,self
.py
,self
.side
)
585 def OnRelease(self
,evt
):
587 parent
= self
.GetParent()
588 DrawSash(parent
,self
.px
,self
.py
,self
.side
)
592 if self
.side
== MV_HOR
:
593 parent
.AddLeaf(MV_VER
,self
.py
)
595 parent
.AddLeaf(MV_HOR
,self
.px
)
599 def OnPaint(self
,evt
):
600 dc
= wx
.PaintDC(self
)
601 dc
.SetBackground(wx
.Brush(self
.GetBackgroundColour(),wx
.SOLID
))
604 highlight
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNHIGHLIGHT
), 1, wx
.SOLID
)
605 shadow
= wx
.Pen(wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_BTNSHADOW
), 1, wx
.SOLID
)
606 black
= wx
.Pen(wx
.BLACK
,1,wx
.SOLID
)
613 dc
.DrawLine((0,0), (0,h
))
614 dc
.DrawLine((0,0), (w
,0))
616 dc
.DrawLine((0,h
), (w
+1,h
))
617 dc
.DrawLine((w
,0), (w
,h
))
619 dc
.DrawLine((w
-1,2), (w
-1,h
))
621 #----------------------------------------------------------------------
624 class MultiCloser(wx
.Window
):
625 def __init__(self
,parent
):
626 x
,y
,w
,h
= self
.CalcSizePos(parent
)
627 wx
.Window
.__init
__(self
,id = -1,parent
= parent
,
630 style
= wx
.CLIP_CHILDREN
)
635 self
.Bind(wx
.EVT_LEFT_DOWN
,self
.OnPress
)
636 self
.Bind(wx
.EVT_LEFT_UP
,self
.OnRelease
)
637 self
.Bind(wx
.EVT_PAINT
,self
.OnPaint
)
638 self
.Bind(wx
.EVT_LEAVE_WINDOW
,self
.OnLeave
)
639 self
.Bind(wx
.EVT_ENTER_WINDOW
,self
.OnEnter
)
641 def OnLeave(self
,evt
):
642 self
.SetCursor(wx
.StockCursor(wx
.CURSOR_ARROW
))
645 def OnEnter(self
,evt
):
646 self
.SetCursor(wx
.StockCursor(wx
.CURSOR_BULLSEYE
))
649 def OnPress(self
,evt
):
653 def OnRelease(self
,evt
):
654 if self
.down
and self
.entered
:
655 self
.GetParent().DestroyLeaf()
660 def OnPaint(self
,evt
):
661 dc
= wx
.PaintDC(self
)
662 dc
.SetBackground(wx
.Brush(wx
.RED
,wx
.SOLID
))
665 def CalcSizePos(self
,parent
):
666 pw
,ph
= parent
.GetSize()
673 def OnSize(self
,evt
):
674 x
,y
,w
,h
= self
.CalcSizePos(self
.GetParent())
675 self
.SetDimensions(x
,y
,w
,h
)
678 #----------------------------------------------------------------------
681 class EmptyChild(wx
.Window
):
682 def __init__(self
,parent
):
683 wx
.Window
.__init
__(self
,parent
,-1, style
= wx
.CLIP_CHILDREN
)
686 #----------------------------------------------------------------------
689 def DrawSash(win
,x
,y
,direction
):
691 dc
.StartDrawingOnTopWin(win
)
692 bmp
= wx
.EmptyBitmap(8,8)
694 bdc
.SelectObject(bmp
)
695 bdc
.DrawRectangle((-1,-1), (10,10))
701 brush
= wx
.Brush(wx
.Colour(0,0,0))
702 brush
.SetStipple(bmp
)
705 dc
.SetLogicalFunction(wx
.XOR
)
707 body_w
,body_h
= win
.GetClientSize()
718 if direction
== MV_HOR
:
723 x
,y
= win
.ClientToScreenXY(x
,y
)
728 if direction
== MV_HOR
:
729 dc
.DrawRectangle((x
,y
-2), (w
,4))
731 dc
.DrawRectangle((x
-2,y
), (4,h
))