+++ /dev/null
-#----------------------------------------------------------------------
-# Name: multisash
-# Purpose: Multi Sash control
-#
-# Author: Gerrit van Dyk
-#
-# Created: 2002/11/20
-# Version: 0.1
-# RCS-ID: $Id$
-# License: wxWindows license
-#----------------------------------------------------------------------
-# 12/09/2003 - Jeff Grimmett (grimmtooth@softhome.net)
-#
-# o 2.5 compatability update.
-#
-# 12/20/2003 - Jeff Grimmett (grimmtooth@softhome.net)
-#
-# o wxMultiSash -> MultiSash
-# o wxMultiSplit -> MultiSplit
-# o wxMultiViewLeaf -> MultiViewLeaf
-#
-
-import wx
-
-MV_HOR = 0
-MV_VER = not MV_HOR
-
-SH_SIZE = 5
-CR_SIZE = SH_SIZE * 3
-
-#----------------------------------------------------------------------
-
-class MultiSash(wx.Window):
- def __init__(self, *_args,**_kwargs):
- apply(wx.Window.__init__,(self,) + _args,_kwargs)
- self._defChild = EmptyChild
- self.child = MultiSplit(self,self,(0,0),self.GetSize())
- self.Bind(wx.EVT_SIZE,self.OnMultiSize)
-
- def SetDefaultChildClass(self,childCls):
- self._defChild = childCls
- self.child.DefaultChildChanged()
-
- def OnMultiSize(self,evt):
- self.child.SetSize(self.GetSize())
-
- def UnSelect(self):
- self.child.UnSelect()
-
- def Clear(self):
- old = self.child
- self.child = MultiSplit(self,self,(0,0),self.GetSize())
- old.Destroy()
- self.child.OnSize(None)
-
- def GetSaveData(self):
- saveData = {}
- saveData['_defChild_class'] = self._defChild.__name__
- saveData['_defChild_mod'] = self._defChild.__module__
- saveData['child'] = self.child.GetSaveData()
- return saveData
-
- def SetSaveData(self,data):
- mod = data['_defChild_mod']
- dChild = mod + '.' + data['_defChild_class']
- exec 'import %s' % mod
- self._defChild = eval(dChild)
- old = self.child
- self.child = MultiSplit(self,self,wx.Point(0,0),self.GetSize())
- self.child.SetSaveData(data['child'])
- old.Destroy()
- self.OnMultiSize(None)
- self.child.OnSize(None)
-
-
-#----------------------------------------------------------------------
-
-
-class MultiSplit(wx.Window):
- def __init__(self,multiView,parent,pos,size,view1 = None):
- wx.Window.__init__(self,id = -1,parent = parent,pos = pos,size = size,
- style = wx.CLIP_CHILDREN)
- self.multiView = multiView
- self.view2 = None
- if view1:
- self.view1 = view1
- self.view1.Reparent(self)
- self.view1.MoveXY(0,0)
- else:
- self.view1 = MultiViewLeaf(self.multiView,self,
- (0,0),self.GetSize())
- self.direction = None
-
- self.Bind(wx.EVT_SIZE,self.OnSize)
-
- def GetSaveData(self):
- saveData = {}
- if self.view1:
- saveData['view1'] = self.view1.GetSaveData()
- if isinstance(self.view1,MultiSplit):
- saveData['view1IsSplit'] = 1
- if self.view2:
- saveData['view2'] = self.view2.GetSaveData()
- if isinstance(self.view2,MultiSplit):
- saveData['view2IsSplit'] = 1
- saveData['direction'] = self.direction
- v1,v2 = self.GetPosition()
- saveData['x'] = v1
- saveData['y'] = v2
- v1,v2 = self.GetSize()
- saveData['w'] = v1
- saveData['h'] = v2
- return saveData
-
- def SetSaveData(self,data):
- self.direction = data['direction']
- self.SetDimensions(int(data['x']), int(data['y']), int(data['w']), int(data['h']))
- v1Data = data.get('view1',None)
- if v1Data:
- isSplit = data.get('view1IsSplit',None)
- old = self.view1
- if isSplit:
- self.view1 = MultiSplit(self.multiView,self,
- (0,0),self.GetSize())
- else:
- self.view1 = MultiViewLeaf(self.multiView,self,
- (0,0),self.GetSize())
- self.view1.SetSaveData(v1Data)
- if old:
- old.Destroy()
- v2Data = data.get('view2',None)
- if v2Data:
- isSplit = data.get('view2IsSplit',None)
- old = self.view2
- if isSplit:
- self.view2 = MultiSplit(self.multiView,self,
- (0,0),self.GetSize())
- else:
- self.view2 = MultiViewLeaf(self.multiView,self,
- (0,0),self.GetSize())
- self.view2.SetSaveData(v2Data)
- if old:
- old.Destroy()
- if self.view1:
- self.view1.OnSize(None)
- if self.view2:
- self.view2.OnSize(None)
-
- def UnSelect(self):
- if self.view1:
- self.view1.UnSelect()
- if self.view2:
- self.view2.UnSelect()
-
- def DefaultChildChanged(self):
- if not self.view2:
- self.view1.DefaultChildChanged()
-
- def AddLeaf(self,direction,caller,pos):
- if self.view2:
- if caller == self.view1:
- self.view1 = MultiSplit(self.multiView,self,
- caller.GetPosition(),
- caller.GetSize(),
- caller)
- self.view1.AddLeaf(direction,caller,pos)
- else:
- self.view2 = MultiSplit(self.multiView,self,
- caller.GetPosition(),
- caller.GetSize(),
- caller)
- self.view2.AddLeaf(direction,caller,pos)
- else:
- self.direction = direction
- w,h = self.GetSize()
- if direction == MV_HOR:
- x,y = (pos,0)
- w1,h1 = (w-pos,h)
- w2,h2 = (pos,h)
- else:
- x,y = (0,pos)
- w1,h1 = (w,h-pos)
- w2,h2 = (w,pos)
- self.view2 = MultiViewLeaf(self.multiView, self, (x,y), (w1,h1))
- self.view1.SetSize((w2,h2))
- self.view2.OnSize(None)
-
- def DestroyLeaf(self,caller):
- if not self.view2: # We will only have 2 windows if
- return # we need to destroy any
- parent = self.GetParent() # Another splitview
- if parent == self.multiView: # We'r at the root
- if caller == self.view1:
- old = self.view1
- self.view1 = self.view2
- self.view2 = None
- old.Destroy()
- else:
- self.view2.Destroy()
- self.view2 = None
- self.view1.SetSize(self.GetSize())
- self.view1.Move(self.GetPosition())
- else:
- w,h = self.GetSize()
- x,y = self.GetPosition()
- if caller == self.view1:
- if self == parent.view1:
- parent.view1 = self.view2
- else:
- parent.view2 = self.view2
- self.view2.Reparent(parent)
- self.view2.SetDimensions(x,y,w,h)
- else:
- if self == parent.view1:
- parent.view1 = self.view1
- else:
- parent.view2 = self.view1
- self.view1.Reparent(parent)
- self.view1.SetDimensions(x,y,w,h)
- self.view1 = None
- self.view2 = None
- self.Destroy()
-
- def CanSize(self,side,view):
- if self.SizeTarget(side,view):
- return True
- return False
-
- def SizeTarget(self,side,view):
- if self.direction == side and self.view2 and view == self.view1:
- return self
- parent = self.GetParent()
- if parent != self.multiView:
- return parent.SizeTarget(side,self)
- return None
-
- def SizeLeaf(self,leaf,pos,side):
- if self.direction != side:
- return
- if not (self.view1 and self.view2):
- return
- if pos < 10: return
- w,h = self.GetSize()
- if side == MV_HOR:
- if pos > w - 10: return
- else:
- if pos > h - 10: return
- if side == MV_HOR:
- self.view1.SetDimensions(0,0,pos,h)
- self.view2.SetDimensions(pos,0,w-pos,h)
- else:
- self.view1.SetDimensions(0,0,w,pos)
- self.view2.SetDimensions(0,pos,w,h-pos)
-
- def OnSize(self,evt):
- if not self.view2:
- self.view1.SetSize(self.GetSize())
- self.view1.OnSize(None)
- return
- v1w,v1h = self.view1.GetSize()
- v2w,v2h = self.view2.GetSize()
- v1x,v1y = self.view1.GetPosition()
- v2x,v2y = self.view2.GetPosition()
- w,h = self.GetSize()
-
- if v1x != v2x:
- ratio = float(w) / float((v1w + v2w))
- v1w *= ratio
- v2w = w - v1w
- v2x = v1w
- else:
- v1w = v2w = w
-
- if v1y != v2y:
- ratio = float(h) / float((v1h + v2h))
- v1h *= ratio
- v2h = h - v1h
- v2y = v1h
- else:
- v1h = v2h = h
-
- self.view1.SetDimensions(int(v1x), int(v1y), int(v1w), int(v1h))
- self.view2.SetDimensions(int(v2x), int(v2y), int(v2w), int(v2h))
- self.view1.OnSize(None)
- self.view2.OnSize(None)
-
-
-#----------------------------------------------------------------------
-
-
-class MultiViewLeaf(wx.Window):
- def __init__(self,multiView,parent,pos,size):
- wx.Window.__init__(self,id = -1,parent = parent,pos = pos,size = size,
- style = wx.CLIP_CHILDREN)
- self.multiView = multiView
-
- self.sizerHor = MultiSizer(self,MV_HOR)
- self.sizerVer = MultiSizer(self,MV_VER)
- self.creatorHor = MultiCreator(self,MV_HOR)
- self.creatorVer = MultiCreator(self,MV_VER)
- self.detail = MultiClient(self,multiView._defChild)
- self.closer = MultiCloser(self)
-
- self.Bind(wx.EVT_SIZE,self.OnSize)
-
- self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE))
-
-
- def GetSaveData(self):
- saveData = {}
- saveData['detailClass_class'] = self.detail.child.__class__.__name__
- saveData['detailClass_mod'] = self.detail.child.__module__
- if hasattr(self.detail.child,'GetSaveData'):
- attr = getattr(self.detail.child,'GetSaveData')
- if callable(attr):
- dData = attr()
- if dData:
- saveData['detail'] = dData
- v1,v2 = self.GetPosition()
- saveData['x'] = v1
- saveData['y'] = v2
- v1,v2 = self.GetSize()
- saveData['w'] = v1
- saveData['h'] = v2
- return saveData
-
- def SetSaveData(self,data):
- mod = data['detailClass_mod']
- dChild = mod + '.' + data['detailClass_class']
- exec 'import %s' % mod
- detClass = eval(dChild)
- self.SetDimensions(data['x'],data['y'],data['w'],data['h'])
- old = self.detail
- self.detail = MultiClient(self,detClass)
- dData = data.get('detail',None)
- if dData:
- if hasattr(self.detail.child,'SetSaveData'):
- attr = getattr(self.detail.child,'SetSaveData')
- if callable(attr):
- attr(dData)
- old.Destroy()
- self.detail.OnSize(None)
-
- def UnSelect(self):
- self.detail.UnSelect()
-
- def DefaultChildChanged(self):
- self.detail.SetNewChildCls(self.multiView._defChild)
-
- def AddLeaf(self,direction,pos):
- if pos < 10: return
- w,h = self.GetSize()
- if direction == MV_VER:
- if pos > h - 10: return
- else:
- if pos > w - 10: return
- self.GetParent().AddLeaf(direction,self,pos)
-
- def DestroyLeaf(self):
- self.GetParent().DestroyLeaf(self)
-
- def SizeTarget(self,side):
- return self.GetParent().SizeTarget(side,self)
-
- def CanSize(self,side):
- return self.GetParent().CanSize(side,self)
-
- def OnSize(self,evt):
- def doresize():
- try:
- self.sizerHor.OnSize(evt)
- self.sizerVer.OnSize(evt)
- self.creatorHor.OnSize(evt)
- self.creatorVer.OnSize(evt)
- self.detail.OnSize(evt)
- self.closer.OnSize(evt)
- except:
- pass
- wx.CallAfter(doresize)
-
-#----------------------------------------------------------------------
-
-
-class MultiClient(wx.Window):
- def __init__(self,parent,childCls):
- w,h = self.CalcSize(parent)
- wx.Window.__init__(self,id = -1,parent = parent,
- pos = (0,0),
- size = (w,h),
- style = wx.CLIP_CHILDREN | wx.SUNKEN_BORDER)
- self.child = childCls(self)
- self.child.MoveXY(2,2)
- self.normalColour = self.GetBackgroundColour()
- self.selected = False
-
- self.Bind(wx.EVT_SET_FOCUS,self.OnSetFocus)
- self.Bind(wx.EVT_CHILD_FOCUS,self.OnChildFocus)
-
- def UnSelect(self):
- if self.selected:
- self.selected = False
- self.SetBackgroundColour(self.normalColour)
- self.Refresh()
-
- def Select(self):
- self.GetParent().multiView.UnSelect()
- self.selected = True
- self.SetBackgroundColour(wx.Colour(255,255,0)) # Yellow
- self.Refresh()
-
- def CalcSize(self,parent):
- w,h = parent.GetSize()
- w -= SH_SIZE
- h -= SH_SIZE
- return (w,h)
-
- def OnSize(self,evt):
- w,h = self.CalcSize(self.GetParent())
- self.SetDimensions(0,0,w,h)
- w,h = self.GetClientSize()
- self.child.SetSize((w-4,h-4))
-
- def SetNewChildCls(self,childCls):
- if self.child:
- self.child.Destroy()
- self.child = None
- self.child = childCls(self)
- self.child.MoveXY(2,2)
-
- def OnSetFocus(self,evt):
- self.Select()
-
- def OnChildFocus(self,evt):
- self.OnSetFocus(evt)
-## from Funcs import FindFocusedChild
-## child = FindFocusedChild(self)
-## child.Bind(wx.EVT_KILL_FOCUS,self.OnChildKillFocus)
-
-
-#----------------------------------------------------------------------
-
-
-class MultiSizer(wx.Window):
- def __init__(self,parent,side):
- self.side = side
- x,y,w,h = self.CalcSizePos(parent)
- wx.Window.__init__(self,id = -1,parent = parent,
- pos = (x,y),
- size = (w,h),
- style = wx.CLIP_CHILDREN)
-
- self.px = None # Previous X
- self.py = None # Previous Y
- self.isDrag = False # In Dragging
- self.dragTarget = None # View being sized
-
- self.Bind(wx.EVT_LEAVE_WINDOW,self.OnLeave)
- self.Bind(wx.EVT_ENTER_WINDOW,self.OnEnter)
- self.Bind(wx.EVT_MOTION,self.OnMouseMove)
- self.Bind(wx.EVT_LEFT_DOWN,self.OnPress)
- self.Bind(wx.EVT_LEFT_UP,self.OnRelease)
-
- self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE))
-
-
- def CalcSizePos(self,parent):
- pw,ph = parent.GetSize()
- if self.side == MV_HOR:
- x = CR_SIZE + 2
- y = ph - SH_SIZE
- w = pw - CR_SIZE - SH_SIZE - 2
- h = SH_SIZE
- else:
- x = pw - SH_SIZE
- y = CR_SIZE + 2 + SH_SIZE
- w = SH_SIZE
- h = ph - CR_SIZE - SH_SIZE - 4 - SH_SIZE # For Closer
- return (x,y,w,h)
-
- def OnSize(self,evt):
- x,y,w,h = self.CalcSizePos(self.GetParent())
- self.SetDimensions(x,y,w,h)
-
- def OnLeave(self,evt):
- self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
-
- def OnEnter(self,evt):
- if not self.GetParent().CanSize(not self.side):
- return
- if self.side == MV_HOR:
- self.SetCursor(wx.StockCursor(wx.CURSOR_SIZENS))
- else:
- self.SetCursor(wx.StockCursor(wx.CURSOR_SIZEWE))
-
- def OnMouseMove(self,evt):
- if self.isDrag:
- DrawSash(self.dragTarget,self.px,self.py,self.side)
- self.px,self.py = self.ClientToScreenXY(evt.m_x,evt.m_y)
- self.px,self.py = self.dragTarget.ScreenToClientXY(self.px,self.py)
- DrawSash(self.dragTarget,self.px,self.py,self.side)
- else:
- evt.Skip()
-
- def OnPress(self,evt):
- self.dragTarget = self.GetParent().SizeTarget(not self.side)
- if self.dragTarget:
- self.isDrag = True
- self.px,self.py = self.ClientToScreenXY(evt.m_x,evt.m_y)
- self.px,self.py = self.dragTarget.ScreenToClientXY(self.px,self.py)
- DrawSash(self.dragTarget,self.px,self.py,self.side)
- self.CaptureMouse()
- else:
- evt.Skip()
-
- def OnRelease(self,evt):
- if self.isDrag:
- DrawSash(self.dragTarget,self.px,self.py,self.side)
- self.ReleaseMouse()
- self.isDrag = False
- if self.side == MV_HOR:
- self.dragTarget.SizeLeaf(self.GetParent(),
- self.py,not self.side)
- else:
- self.dragTarget.SizeLeaf(self.GetParent(),
- self.px,not self.side)
- self.dragTarget = None
- else:
- evt.Skip()
-
-#----------------------------------------------------------------------
-
-
-class MultiCreator(wx.Window):
- def __init__(self,parent,side):
- self.side = side
- x,y,w,h = self.CalcSizePos(parent)
- wx.Window.__init__(self,id = -1,parent = parent,
- pos = (x,y),
- size = (w,h),
- style = wx.CLIP_CHILDREN)
-
- self.px = None # Previous X
- self.py = None # Previous Y
- self.isDrag = False # In Dragging
-
- self.Bind(wx.EVT_LEAVE_WINDOW,self.OnLeave)
- self.Bind(wx.EVT_ENTER_WINDOW,self.OnEnter)
- self.Bind(wx.EVT_MOTION,self.OnMouseMove)
- self.Bind(wx.EVT_LEFT_DOWN,self.OnPress)
- self.Bind(wx.EVT_LEFT_UP,self.OnRelease)
- self.Bind(wx.EVT_PAINT,self.OnPaint)
-
- def CalcSizePos(self,parent):
- pw,ph = parent.GetSize()
- if self.side == MV_HOR:
- x = 2
- y = ph - SH_SIZE
- w = CR_SIZE
- h = SH_SIZE
- else:
- x = pw - SH_SIZE
- y = 4 + SH_SIZE # Make provision for closer
- w = SH_SIZE
- h = CR_SIZE
- return (x,y,w,h)
-
- def OnSize(self,evt):
- x,y,w,h = self.CalcSizePos(self.GetParent())
- self.SetDimensions(x,y,w,h)
-
- def OnLeave(self,evt):
- self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
-
- def OnEnter(self,evt):
- if self.side == MV_HOR:
- self.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
- else:
- self.SetCursor(wx.StockCursor(wx.CURSOR_POINT_LEFT))
-
- def OnMouseMove(self,evt):
- if self.isDrag:
- parent = self.GetParent()
- DrawSash(parent,self.px,self.py,self.side)
- self.px,self.py = self.ClientToScreenXY(evt.m_x,evt.m_y)
- self.px,self.py = parent.ScreenToClientXY(self.px,self.py)
- DrawSash(parent,self.px,self.py,self.side)
- else:
- evt.Skip()
-
- def OnPress(self,evt):
- self.isDrag = True
- parent = self.GetParent()
- self.px,self.py = self.ClientToScreenXY(evt.m_x,evt.m_y)
- self.px,self.py = parent.ScreenToClientXY(self.px,self.py)
- DrawSash(parent,self.px,self.py,self.side)
- self.CaptureMouse()
-
- def OnRelease(self,evt):
- if self.isDrag:
- parent = self.GetParent()
- DrawSash(parent,self.px,self.py,self.side)
- self.ReleaseMouse()
- self.isDrag = False
-
- if self.side == MV_HOR:
- parent.AddLeaf(MV_VER,self.py)
- else:
- parent.AddLeaf(MV_HOR,self.px)
- else:
- evt.Skip()
-
- def OnPaint(self,evt):
- dc = wx.PaintDC(self)
- dc.SetBackground(wx.Brush(self.GetBackgroundColour(),wx.SOLID))
- dc.Clear()
-
- highlight = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNHIGHLIGHT), 1, wx.SOLID)
- shadow = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW), 1, wx.SOLID)
- black = wx.Pen(wx.BLACK,1,wx.SOLID)
- w,h = self.GetSize()
- w -= 1
- h -= 1
-
- # Draw outline
- dc.SetPen(highlight)
- dc.DrawLine(0,0, 0,h)
- dc.DrawLine(0,0, w,0)
- dc.SetPen(black)
- dc.DrawLine(0,h, w+1,h)
- dc.DrawLine(w,0, w,h)
- dc.SetPen(shadow)
- dc.DrawLine(w-1,2, w-1,h)
-
-#----------------------------------------------------------------------
-
-
-class MultiCloser(wx.Window):
- def __init__(self,parent):
- x,y,w,h = self.CalcSizePos(parent)
- wx.Window.__init__(self,id = -1,parent = parent,
- pos = (x,y),
- size = (w,h),
- style = wx.CLIP_CHILDREN)
-
- self.down = False
- self.entered = False
-
- self.Bind(wx.EVT_LEFT_DOWN,self.OnPress)
- self.Bind(wx.EVT_LEFT_UP,self.OnRelease)
- self.Bind(wx.EVT_PAINT,self.OnPaint)
- self.Bind(wx.EVT_LEAVE_WINDOW,self.OnLeave)
- self.Bind(wx.EVT_ENTER_WINDOW,self.OnEnter)
-
- def OnLeave(self,evt):
- self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
- self.entered = False
-
- def OnEnter(self,evt):
- self.SetCursor(wx.StockCursor(wx.CURSOR_BULLSEYE))
- self.entered = True
-
- def OnPress(self,evt):
- self.down = True
- evt.Skip()
-
- def OnRelease(self,evt):
- if self.down and self.entered:
- self.GetParent().DestroyLeaf()
- else:
- evt.Skip()
- self.down = False
-
- def OnPaint(self,evt):
- dc = wx.PaintDC(self)
- dc.SetBackground(wx.Brush(wx.RED,wx.SOLID))
- dc.Clear()
-
- def CalcSizePos(self,parent):
- pw,ph = parent.GetSize()
- x = pw - SH_SIZE
- w = SH_SIZE
- h = SH_SIZE + 2
- y = 1
- return (x,y,w,h)
-
- def OnSize(self,evt):
- x,y,w,h = self.CalcSizePos(self.GetParent())
- self.SetDimensions(x,y,w,h)
-
-
-#----------------------------------------------------------------------
-
-
-class EmptyChild(wx.Window):
- def __init__(self,parent):
- wx.Window.__init__(self,parent,-1, style = wx.CLIP_CHILDREN)
-
-
-#----------------------------------------------------------------------
-
-
-def DrawSash(win,x,y,direction):
- dc = wx.ScreenDC()
- dc.StartDrawingOnTopWin(win)
- bmp = wx.EmptyBitmap(8,8)
- bdc = wx.MemoryDC()
- bdc.SelectObject(bmp)
- bdc.DrawRectangle(-1,-1, 10,10)
- for i in range(8):
- for j in range(8):
- if ((i + j) & 1):
- bdc.DrawPoint(i,j)
-
- brush = wx.Brush(wx.Colour(0,0,0))
- brush.SetStipple(bmp)
-
- dc.SetBrush(brush)
- dc.SetLogicalFunction(wx.XOR)
-
- body_w,body_h = win.GetClientSize()
-
- if y < 0:
- y = 0
- if y > body_h:
- y = body_h
- if x < 0:
- x = 0
- if x > body_w:
- x = body_w
-
- if direction == MV_HOR:
- x = 0
- else:
- y = 0
-
- x,y = win.ClientToScreenXY(x,y)
-
- w = body_w
- h = body_h
-
- if direction == MV_HOR:
- dc.DrawRectangle(x,y-2, w,4)
- else:
- dc.DrawRectangle(x-2,y, 4,h)
-
- dc.EndDrawingOnTop()