1 #----------------------------------------------------------------------
3 # Purpose: Multi Sash control
5 # Author: Gerrit van Dyk
10 # License: wxWindows licensie
11 #----------------------------------------------------------------------
13 from wxPython
.wx
import *
21 #----------------------------------------------------------------------
23 class wxMultiSash(wxWindow
):
24 def __init__(self
, *_args
,**_kwargs
):
25 apply(wxWindow
.__init
__,(self
,) + _args
,_kwargs
)
26 self
._defChild
= EmptyChild
27 self
.child
= wxMultiSplit(self
,self
,wxPoint(0,0),self
.GetSize())
28 EVT_SIZE(self
,self
.OnMultiSize
)
30 def SetDefaultChildClass(self
,childCls
):
31 self
._defChild
= childCls
32 self
.child
.DefaultChildChanged()
34 def OnMultiSize(self
,evt
):
35 self
.child
.SetSize(self
.GetSize())
42 self
.child
= wxMultiSplit(self
,self
,wxPoint(0,0),self
.GetSize())
44 self
.child
.OnSize(None)
46 def GetSaveData(self
):
48 saveData
['_defChild'] = str(self
._defChild
)
49 saveData
['child'] = self
.child
.GetSaveData()
52 def SetSaveData(self
,data
):
53 dChild
= data
['_defChild']
54 mod
= dChild
.split('.')[0]
55 exec 'import %s' % mod
56 self
._defChild
= eval(dChild
)
58 self
.child
= wxMultiSplit(self
,self
,wxPoint(0,0),self
.GetSize())
59 self
.child
.SetSaveData(data
['child'])
61 self
.OnMultiSize(None)
62 self
.child
.OnSize(None)
65 #----------------------------------------------------------------------
68 class wxMultiSplit(wxWindow
):
69 def __init__(self
,multiView
,parent
,pos
,size
,view1
= None):
70 wxWindow
.__init
__(self
,id = -1,parent
= parent
,pos
= pos
,size
= size
,
71 style
= wxCLIP_CHILDREN
)
72 self
.multiView
= multiView
76 self
.view1
.Reparent(self
)
77 self
.view1
.MoveXY(0,0)
79 self
.view1
= wxMultiViewLeaf(self
.multiView
,self
,
80 wxPoint(0,0),self
.GetSize())
83 EVT_SIZE(self
,self
.OnSize
)
85 def GetSaveData(self
):
88 saveData
['view1'] = self
.view1
.GetSaveData()
89 if isinstance(self
.view1
,wxMultiSplit
):
90 saveData
['view1IsSplit'] = 1
92 saveData
['view2'] = self
.view2
.GetSaveData()
93 if isinstance(self
.view2
,wxMultiSplit
):
94 saveData
['view2IsSplit'] = 1
95 saveData
['direction'] = self
.direction
96 v1
,v2
= self
.GetPositionTuple()
99 v1
,v2
= self
.GetSizeTuple()
104 def SetSaveData(self
,data
):
105 self
.direction
= data
['direction']
106 self
.SetDimensions(data
['x'],data
['y'],data
['w'],data
['h'])
107 v1Data
= data
.get('view1',None)
109 isSplit
= data
.get('view1IsSplit',None)
112 self
.view1
= wxMultiSplit(self
.multiView
,self
,
113 wxPoint(0,0),self
.GetSize())
115 self
.view1
= wxMultiViewLeaf(self
.multiView
,self
,
116 wxPoint(0,0),self
.GetSize())
117 self
.view1
.SetSaveData(v1Data
)
120 v2Data
= data
.get('view2',None)
122 isSplit
= data
.get('view2IsSplit',None)
125 self
.view2
= wxMultiSplit(self
.multiView
,self
,
126 wxPoint(0,0),self
.GetSize())
128 self
.view2
= wxMultiViewLeaf(self
.multiView
,self
,
129 wxPoint(0,0),self
.GetSize())
130 self
.view2
.SetSaveData(v2Data
)
134 self
.view1
.OnSize(None)
136 self
.view2
.OnSize(None)
140 self
.view1
.UnSelect()
142 self
.view2
.UnSelect()
144 def DefaultChildChanged(self
):
146 self
.view1
.DefaultChildChanged()
148 def AddLeaf(self
,direction
,caller
,pos
):
150 if caller
== self
.view1
:
151 self
.view1
= wxMultiSplit(self
.multiView
,self
,
152 caller
.GetPosition(),
155 self
.view1
.AddLeaf(direction
,caller
,pos
)
157 self
.view2
= wxMultiSplit(self
.multiView
,self
,
158 caller
.GetPosition(),
161 self
.view2
.AddLeaf(direction
,caller
,pos
)
163 self
.direction
= direction
164 w
,h
= self
.GetSizeTuple()
165 if direction
== MV_HOR
:
173 self
.view2
= wxMultiViewLeaf(self
.multiView
,self
,
174 wxPoint(x
,y
),wxSize(w1
,h1
))
175 self
.view1
.SetSize(wxSize(w2
,h2
))
176 self
.view2
.OnSize(None)
178 def DestroyLeaf(self
,caller
):
179 if not self
.view2
: # We will only have 2 windows if
180 return # we need to destroy any
181 parent
= self
.GetParent() # Another splitview
182 if parent
== self
.multiView
: # We'r at the root
183 if caller
== self
.view1
:
185 self
.view1
= self
.view2
191 self
.view1
.SetSize(self
.GetSize())
192 self
.view1
.Move(self
.GetPosition())
194 w
,h
= self
.GetSizeTuple()
195 x
,y
= self
.GetPositionTuple()
196 if caller
== self
.view1
:
197 if self
== parent
.view1
:
198 parent
.view1
= self
.view2
200 parent
.view2
= self
.view2
201 self
.view2
.Reparent(parent
)
202 self
.view2
.SetDimensions(x
,y
,w
,h
)
204 if self
== parent
.view1
:
205 parent
.view1
= self
.view1
207 parent
.view2
= self
.view1
208 self
.view1
.Reparent(parent
)
209 self
.view1
.SetDimensions(x
,y
,w
,h
)
214 def CanSize(self
,side
,view
):
215 if self
.SizeTarget(side
,view
):
219 def SizeTarget(self
,side
,view
):
220 if self
.direction
== side
and self
.view2
and view
== self
.view1
:
222 parent
= self
.GetParent()
223 if parent
!= self
.multiView
:
224 return parent
.SizeTarget(side
,self
)
227 def SizeLeaf(self
,leaf
,pos
,side
):
228 if self
.direction
!= side
:
230 if not (self
.view1
and self
.view2
):
233 w
,h
= self
.GetSizeTuple()
235 if pos
> w
- 10: return
237 if pos
> h
- 10: return
239 self
.view1
.SetDimensions(0,0,pos
,h
)
240 self
.view2
.SetDimensions(pos
,0,w
-pos
,h
)
242 self
.view1
.SetDimensions(0,0,w
,pos
)
243 self
.view2
.SetDimensions(0,pos
,w
,h
-pos
)
245 def OnSize(self
,evt
):
247 self
.view1
.SetSize(self
.GetSize())
248 self
.view1
.OnSize(None)
250 v1w
,v1h
= self
.view1
.GetSizeTuple()
251 v2w
,v2h
= self
.view2
.GetSizeTuple()
252 v1x
,v1y
= self
.view1
.GetPositionTuple()
253 v2x
,v2y
= self
.view2
.GetPositionTuple()
254 w
,h
= self
.GetSizeTuple()
257 ratio
= float(w
) / float((v1w
+ v2w
))
265 ratio
= float(h
) / float((v1h
+ v2h
))
272 self
.view1
.SetDimensions(v1x
,v1y
,v1w
,v1h
)
273 self
.view2
.SetDimensions(v2x
,v2y
,v2w
,v2h
)
274 self
.view1
.OnSize(None)
275 self
.view2
.OnSize(None)
278 #----------------------------------------------------------------------
281 class wxMultiViewLeaf(wxWindow
):
282 def __init__(self
,multiView
,parent
,pos
,size
):
283 wxWindow
.__init
__(self
,id = -1,parent
= parent
,pos
= pos
,size
= size
,
284 style
= wxCLIP_CHILDREN
)
285 self
.multiView
= multiView
287 self
.sizerHor
= MultiSizer(self
,MV_HOR
)
288 self
.sizerVer
= MultiSizer(self
,MV_VER
)
289 self
.creatorHor
= MultiCreator(self
,MV_HOR
)
290 self
.creatorVer
= MultiCreator(self
,MV_VER
)
291 self
.detail
= MultiClient(self
,multiView
._defChild
)
292 self
.closer
= MultiCloser(self
)
294 EVT_SIZE(self
,self
.OnSize
)
296 def GetSaveData(self
):
298 saveData
['detailClass'] = str(self
.detail
.child
.__class
__)
299 if hasattr(self
.detail
.child
,'GetSaveData'):
300 attr
= getattr(self
.detail
.child
,'GetSaveData')
304 saveData
['detail'] = dData
305 v1
,v2
= self
.GetPositionTuple()
308 v1
,v2
= self
.GetSizeTuple()
313 def SetSaveData(self
,data
):
314 dChild
= data
['detailClass']
315 mod
= dChild
.split('.')[0]
316 exec 'import %s' % mod
317 detClass
= eval(dChild
)
318 self
.SetDimensions(data
['x'],data
['y'],data
['w'],data
['h'])
320 self
.detail
= MultiClient(self
,detClass
)
321 dData
= data
.get('detail',None)
323 if hasattr(self
.detail
.child
,'SetSaveData'):
324 attr
= getattr(self
.detail
.child
,'SetSaveData')
328 self
.detail
.OnSize(None)
331 self
.detail
.UnSelect()
333 def DefaultChildChanged(self
):
334 self
.detail
.SetNewChildCls(self
.multiView
._defChild
)
336 def AddLeaf(self
,direction
,pos
):
338 w
,h
= self
.GetSizeTuple()
339 if direction
== MV_VER
:
340 if pos
> h
- 10: return
342 if pos
> w
- 10: return
343 self
.GetParent().AddLeaf(direction
,self
,pos
)
345 def DestroyLeaf(self
):
346 self
.GetParent().DestroyLeaf(self
)
348 def SizeTarget(self
,side
):
349 return self
.GetParent().SizeTarget(side
,self
)
351 def CanSize(self
,side
):
352 return self
.GetParent().CanSize(side
,self
)
354 def OnSize(self
,evt
):
355 self
.sizerHor
.OnSize(evt
)
356 self
.sizerVer
.OnSize(evt
)
357 self
.creatorHor
.OnSize(evt
)
358 self
.creatorVer
.OnSize(evt
)
359 self
.detail
.OnSize(evt
)
360 self
.closer
.OnSize(evt
)
362 #----------------------------------------------------------------------
365 class MultiClient(wxWindow
):
366 def __init__(self
,parent
,childCls
):
367 w
,h
= self
.CalcSize(parent
)
368 wxWindow
.__init
__(self
,id = -1,parent
= parent
,
371 style
= wxCLIP_CHILDREN | wxSUNKEN_BORDER
)
372 self
.child
= childCls(self
)
373 self
.child
.MoveXY(2,2)
374 self
.normalColour
= self
.GetBackgroundColour()
375 self
.selected
= False
377 EVT_SET_FOCUS(self
,self
.OnSetFocus
)
378 EVT_CHILD_FOCUS(self
,self
.OnChildFocus
)
382 self
.selected
= False
383 self
.SetBackgroundColour(self
.normalColour
)
387 self
.GetParent().multiView
.UnSelect()
389 self
.SetBackgroundColour(wxColour(255,255,0)) # Yellow
392 def CalcSize(self
,parent
):
393 w
,h
= parent
.GetSizeTuple()
398 def OnSize(self
,evt
):
399 w
,h
= self
.CalcSize(self
.GetParent())
400 self
.SetDimensions(0,0,w
,h
)
401 w
,h
= self
.GetClientSizeTuple()
402 self
.child
.SetSize(wxSize(w
-4,h
-4))
404 def SetNewChildCls(self
,childCls
):
408 self
.child
= childCls(self
)
409 self
.child
.MoveXY(2,2)
411 def OnSetFocus(self
,evt
):
414 def OnChildFocus(self
,evt
):
416 ## from Funcs import FindFocusedChild
417 ## child = FindFocusedChild(self)
418 ## EVT_KILL_FOCUS(child,self.OnChildKillFocus)
421 #----------------------------------------------------------------------
424 class MultiSizer(wxWindow
):
425 def __init__(self
,parent
,side
):
427 x
,y
,w
,h
= self
.CalcSizePos(parent
)
428 wxWindow
.__init
__(self
,id = -1,parent
= parent
,
431 style
= wxCLIP_CHILDREN
)
433 self
.px
= None # Previous X
434 self
.py
= None # Previous Y
435 self
.isDrag
= False # In Dragging
436 self
.dragTarget
= None # View being sized
438 EVT_LEAVE_WINDOW(self
,self
.OnLeave
)
439 EVT_ENTER_WINDOW(self
,self
.OnEnter
)
440 EVT_MOTION(self
,self
.OnMouseMove
)
441 EVT_LEFT_DOWN(self
,self
.OnPress
)
442 EVT_LEFT_UP(self
,self
.OnRelease
)
444 def CalcSizePos(self
,parent
):
445 pw
,ph
= parent
.GetSizeTuple()
446 if self
.side
== MV_HOR
:
449 w
= pw
- CR_SIZE
- SH_SIZE
- 2
453 y
= CR_SIZE
+ 2 + SH_SIZE
455 h
= ph
- CR_SIZE
- SH_SIZE
- 4 - SH_SIZE
# For Closer
458 def OnSize(self
,evt
):
459 x
,y
,w
,h
= self
.CalcSizePos(self
.GetParent())
460 self
.SetDimensions(x
,y
,w
,h
)
462 def OnLeave(self
,evt
):
463 self
.SetCursor(wxStockCursor(wxCURSOR_ARROW
))
465 def OnEnter(self
,evt
):
466 if not self
.GetParent().CanSize(not self
.side
):
468 if self
.side
== MV_HOR
:
469 self
.SetCursor(wxStockCursor(wxCURSOR_SIZENS
))
471 self
.SetCursor(wxStockCursor(wxCURSOR_SIZEWE
))
473 def OnMouseMove(self
,evt
):
475 DrawSash(self
.dragTarget
,self
.px
,self
.py
,self
.side
)
476 self
.px
,self
.py
= self
.ClientToScreenXY(evt
.m_x
,evt
.m_y
)
477 self
.px
,self
.py
= self
.dragTarget
.ScreenToClientXY(self
.px
,self
.py
)
478 DrawSash(self
.dragTarget
,self
.px
,self
.py
,self
.side
)
482 def OnPress(self
,evt
):
483 self
.dragTarget
= self
.GetParent().SizeTarget(not self
.side
)
486 self
.px
,self
.py
= self
.ClientToScreenXY(evt
.m_x
,evt
.m_y
)
487 self
.px
,self
.py
= self
.dragTarget
.ScreenToClientXY(self
.px
,self
.py
)
488 DrawSash(self
.dragTarget
,self
.px
,self
.py
,self
.side
)
493 def OnRelease(self
,evt
):
495 DrawSash(self
.dragTarget
,self
.px
,self
.py
,self
.side
)
498 if self
.side
== MV_HOR
:
499 self
.dragTarget
.SizeLeaf(self
.GetParent(),
500 self
.py
,not self
.side
)
502 self
.dragTarget
.SizeLeaf(self
.GetParent(),
503 self
.px
,not self
.side
)
504 self
.dragTarget
= None
508 #----------------------------------------------------------------------
511 class MultiCreator(wxWindow
):
512 def __init__(self
,parent
,side
):
514 x
,y
,w
,h
= self
.CalcSizePos(parent
)
515 wxWindow
.__init
__(self
,id = -1,parent
= parent
,
518 style
= wxCLIP_CHILDREN
)
520 self
.px
= None # Previous X
521 self
.py
= None # Previous Y
522 self
.isDrag
= False # In Dragging
524 EVT_LEAVE_WINDOW(self
,self
.OnLeave
)
525 EVT_ENTER_WINDOW(self
,self
.OnEnter
)
526 EVT_MOTION(self
,self
.OnMouseMove
)
527 EVT_LEFT_DOWN(self
,self
.OnPress
)
528 EVT_LEFT_UP(self
,self
.OnRelease
)
529 EVT_PAINT(self
,self
.OnPaint
)
531 def CalcSizePos(self
,parent
):
532 pw
,ph
= parent
.GetSizeTuple()
533 if self
.side
== MV_HOR
:
540 y
= 4 + SH_SIZE
# Make provision for closer
545 def OnSize(self
,evt
):
546 x
,y
,w
,h
= self
.CalcSizePos(self
.GetParent())
547 self
.SetDimensions(x
,y
,w
,h
)
549 def OnLeave(self
,evt
):
550 self
.SetCursor(wxStockCursor(wxCURSOR_ARROW
))
552 def OnEnter(self
,evt
):
553 if self
.side
== MV_HOR
:
554 self
.SetCursor(wxStockCursor(wxCURSOR_HAND
))
556 self
.SetCursor(wxStockCursor(wxCURSOR_POINT_LEFT
))
558 def OnMouseMove(self
,evt
):
560 parent
= self
.GetParent()
561 DrawSash(parent
,self
.px
,self
.py
,self
.side
)
562 self
.px
,self
.py
= self
.ClientToScreenXY(evt
.m_x
,evt
.m_y
)
563 self
.px
,self
.py
= parent
.ScreenToClientXY(self
.px
,self
.py
)
564 DrawSash(parent
,self
.px
,self
.py
,self
.side
)
568 def OnPress(self
,evt
):
570 parent
= self
.GetParent()
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
)
576 def OnRelease(self
,evt
):
578 parent
= self
.GetParent()
579 DrawSash(parent
,self
.px
,self
.py
,self
.side
)
583 if self
.side
== MV_HOR
:
584 parent
.AddLeaf(MV_VER
,self
.py
)
586 parent
.AddLeaf(MV_HOR
,self
.px
)
590 def OnPaint(self
,evt
):
592 dc
.SetBackground(wxBrush(self
.GetBackgroundColour(),wxSOLID
))
595 highlight
= wxPen(wxSystemSettings_GetSystemColour(
596 wxSYS_COLOUR_BTNHIGHLIGHT
),1,wxSOLID
)
597 shadow
= wxPen(wxSystemSettings_GetSystemColour(
598 wxSYS_COLOUR_BTNSHADOW
),1,wxSOLID
)
599 black
= wxPen(wxBLACK
,1,wxSOLID
)
600 w
,h
= self
.GetSizeTuple()
609 dc
.DrawLine(0,h
,w
+1,h
)
612 dc
.DrawLine(w
-1,2,w
-1,h
)
614 #----------------------------------------------------------------------
617 class MultiCloser(wxWindow
):
618 def __init__(self
,parent
):
619 x
,y
,w
,h
= self
.CalcSizePos(parent
)
620 wxWindow
.__init
__(self
,id = -1,parent
= parent
,
623 style
= wxCLIP_CHILDREN
)
628 EVT_LEFT_DOWN(self
,self
.OnPress
)
629 EVT_LEFT_UP(self
,self
.OnRelease
)
630 EVT_PAINT(self
,self
.OnPaint
)
631 EVT_LEAVE_WINDOW(self
,self
.OnLeave
)
632 EVT_ENTER_WINDOW(self
,self
.OnEnter
)
634 def OnLeave(self
,evt
):
635 self
.SetCursor(wxStockCursor(wxCURSOR_ARROW
))
638 def OnEnter(self
,evt
):
639 self
.SetCursor(wxStockCursor(wxCURSOR_BULLSEYE
))
642 def OnPress(self
,evt
):
646 def OnRelease(self
,evt
):
647 if self
.down
and self
.entered
:
648 self
.GetParent().DestroyLeaf()
653 def OnPaint(self
,evt
):
655 dc
.SetBackground(wxBrush(wxRED
,wxSOLID
))
658 def CalcSizePos(self
,parent
):
659 pw
,ph
= parent
.GetSizeTuple()
666 def OnSize(self
,evt
):
667 x
,y
,w
,h
= self
.CalcSizePos(self
.GetParent())
668 self
.SetDimensions(x
,y
,w
,h
)
671 #----------------------------------------------------------------------
674 class EmptyChild(wxWindow
):
675 def __init__(self
,parent
):
676 wxWindow
.__init
__(self
,parent
,-1, style
= wxCLIP_CHILDREN
)
679 #----------------------------------------------------------------------
682 def DrawSash(win
,x
,y
,direction
):
684 dc
.StartDrawingOnTopWin(win
)
685 bmp
= wxEmptyBitmap(8,8)
687 bdc
.SelectObject(bmp
)
688 bdc
.DrawRectangle(-1,-1,10,10)
694 brush
= wxBrush(wxColour(0,0,0))
695 brush
.SetStipple(bmp
)
698 dc
.SetLogicalFunction(wxXOR
)
700 body_w
,body_h
= win
.GetClientSizeTuple()
711 if direction
== MV_HOR
:
716 x
,y
= win
.ClientToScreenXY(x
,y
)
721 if direction
== MV_HOR
:
722 dc
.DrawRectangle(x
,y
-2,w
,4)
724 dc
.DrawRectangle(x
-2,y
,4,h
)