]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/wx/lib/multisash.py
Give PlotCanvas the full compliment of constructor parameters again.
[wxWidgets.git] / wxPython / wx / lib / multisash.py
index b586275f73c45a0578310fdc7860769daa6360da..6be5e730aaba69358ca4a0477e8b2940167e2eea 100644 (file)
+#----------------------------------------------------------------------
+# 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
+#
 
-"""Renamer stub: provides a way to drop the wx prefix from wxPython objects."""
+import wx
 
-__cvsid__ = "$Id$"
-__revision__ = "$Revision$"[11:-2]
+MV_HOR = 0
+MV_VER = not MV_HOR
 
-from wx import _rename
-from wxPython.lib import multisash
-_rename(globals(), multisash.__dict__, modulename='lib.multisash')
-del multisash
-del _rename
+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()