Gnumed.wxpython.gmMultiSash

Package Gnumed :: Package wxpython :: Module gmMultiSash |
[frames] | no frames]

# Source Code for Module Gnumed.wxpython.gmMultiSash

      1  #----------------------------------------------------------------------
      2  # ORIGINAL HEADER:
      3  #
      4  # Name:                 multisash
      5  # Purpose:              Multi Sash control
      6  #
      7  # Author:               Gerrit van Dyk
      8  #
      9  # Created:              2002/11/20
     10  # Version:              0.1
     11  # RCS-ID:               $Id: gmMultiSash.py,v 1.7 2005-09-28 21:27:30 ncq Exp $
     12  # License:              wxWindows licensie
     13  #----------------------------------------------------------------------
     14  # $Source: /home/ncq/Projekte/cvs2git/vcs-mirror/gnumed/gnumed/client/wxpython/gmMultiSash.py,v $
     15  # $Id: gmMultiSash.py,v 1.7 2005-09-28 21:27:30 ncq Exp $
     16  __version__ = "$Revision: 1.7 $"
     17  __author__ = "Gerrit van Dyk, Carlos, Karsten"
     18  #__license__ = "GPL"
     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  #----------------------------------------------------------------------
     29 -class cMultiSash(wx.Window):
     30          """
     31          Main multisash widget. Dynamically displays a stack of child widgets.
     32          """
     33 -        def __init__(self, *_args,**_kwargs):
     34                  apply(wx.Window.__init__,(self,) + _args,_kwargs)
     35                  #self._defChild = cEmptyChild
     36                  self.child = cMultiSashSplitter(self,self,wxPoint(0,0),self.GetSize())
     37
     38                  # Gnumed: focused and bottom leaf
     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          # public API
     46          #---------------------------------------------
     47          # Gnumed:
     48 -        def get_focussed_leaf(self):
     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          #---------------------------------------------
     55 -        def get_displayed_leafs(self):
     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          #---------------------------------------------
     74 -        def Clear(self):
     75                  """
     76                  Clear all mulsisash leafs and restores initial values
     77                  """
     78                  # FIXME: keep an eye if strange behaviour
     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                  # Gnumed: focused and bottom leaf
     85                  self.focussed_leaf = self.child.leaf1
     86                  self.bottom_leaf = self.child.leaf1
     87                  self.bottom_leaf.Select()
     88                  self.displayed_leafs = []
     89          #---------------------------------------------
     90 -        def refresh_bottom_leaf(self, bottom_leaf = None):
     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          #---------------------------------------------
    109 -        def refresh_displayed_leafs(self, splitter):
    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  #               print "__refresh_displayed_leafs()"
    118  #               print "splitter: %s [%s]" % (splitter.__class__.__name__, id(splitter))
    119  #               print "- leaf 1: %s [%s]" % (splitter.leaf1.__class__.__name__, id(splitter.leaf1))
    120  #               print "- leaf 2: %s [%s]" % (splitter.leaf2.__class__.__name__, id(splitter.leaf2))
    121                  if isinstance(splitter.leaf1, cMultiSashSplitter):
    122  #                       print "leaf 1 is splitter, recurse down"
    123                          self.refresh_displayed_leafs(splitter.leaf1)
    124                  if isinstance(splitter.leaf2, cMultiSashSplitter):
    125  #                       print "leaf 2 is splitter, recurse down"
    126                          self.refresh_displayed_leafs(splitter.leaf2)
    127  #               print "found bottom split: %s [%s]" % (splitter.__class__.__name__, id(splitter))
    128                  if not splitter.leaf2 is None and not isinstance(splitter.leaf2, cMultiSashSplitter):
    129  #                       print "found leaf (leaf2): %s [%s]" % (splitter.leaf2.__class__.__name__, id(splitter.leaf2))
    130                          self.displayed_leafs.append(splitter.leaf2)
    131                  if not splitter.leaf1 is None and not isinstance(splitter.leaf1, cMultiSashSplitter):
    132  #                       print "found leaf (leaf1): %s [%s]" % (splitter.leaf1.__class__.__name__, id(splitter.leaf1))
    133                          self.displayed_leafs.append(splitter.leaf1)
    134          #---------------------------------------------
    135          # event handlers
    136          #---------------------------------------------
    137 -        def _on_size(self, evt):
    138                  self.child.SetSize(self.GetSize())
    139          #---------------------------------------------
    140          # internal API
    141          #---------------------------------------------
    142 -        def __find_bottom_leaf(self, splitter):
    143                  """
    144                  Recursively find and return the bottom leaf.
    145                  """
    146  #               print "__find_bottom_leaf()"
    147  #               print "splitter: %s [%s]" % (splitter.__class__.__name__, id(splitter))
    148  #               print "- leaf 1: %s [%s]" % (splitter.leaf1.__class__.__name__, id(splitter.leaf1))
    149  #               print "- leaf 2: %s [%s]" % (splitter.leaf2.__class__.__name__, id(splitter.leaf2))
    150                  if isinstance(splitter.leaf1, cMultiSashSplitter):
    151  #                       print "leaf 1 is splitter, recurse down"
    152                          return self.__find_bottom_leaf(splitter.leaf1)
    153                  if isinstance(splitter.leaf2, cMultiSashSplitter):
    154  #                       print "leaf 2 is splitter, recurse down"
    155                          return self.__find_bottom_leaf(splitter.leaf2)
    156  #               print "found bottom split: %s [%s]" % (splitter.__class__.__name__, id(splitter))
    157                  if not splitter.leaf2 is None:
    158  #                       print "bottom leaf (leaf2): %s [%s]" % (splitter.leaf2.__class__.__name__, id(splitter.leaf2))
    159                          return splitter.leaf2
    160                  else:
    161  #                       print "bottom leaf (leaf1): %s [%s]" % (splitter.leaf1.__class__.__name__, id(splitter.leaf1))
    162                          return splitter.leaf1
    163          #---------------------------------------------
    164 -        def _unselect(self):
    165                  self.child._unselect()
    166  #----------------------------------------------------------------------
    167 -class cMultiSashSplitter(wx.Window):
    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          #---------------------------------------------
    200 -        def _unselect(self):
    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  #               print '%s[%s].AddLeaf()' % (self.__class__.__name__, id(self))
    209  #               print "leaf 1: %s [%s]" % (self.leaf1.__class__.__name__, id(self.leaf1))
    210  #               print "leaf 2: %s [%s]" % (self.leaf2.__class__.__name__, id(self.leaf2))
    211                  if self.leaf2:
    212  #                       print "we have two leafs"
    213  #                       print "caller: %s [%s]" % (caller.__class__.__name__, id(caller))
    214                          if caller == self.leaf1:
    215  #                               print "caller was leaf 1, hence splitting leaf 1"
    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  #                               print "caller was leaf 2, hence splitting leaf 2"
    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  #                       print "we have only one leaf"
    230  #                       print "caller: %s [%s]" % (caller.__class__.__name__, id(caller))
    231  #                       print "hence caller must have been leaf 1 hence adding leaf 2 ..."
    232                          self.direction = direction
    233                          w,h = self.GetSize()
    234                          if direction == MV_HOR:
    235  #                               print "... next to leaf 1"
    236                                  x,y = (pos,0)
    237                                  w1,h1 = (w-pos,h)
    238                                  w2,h2 = (pos,h)
    239                          else:
    240  #                               print "... below leaf 1"
    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                          # Gnumed: register added leaf content
    249                          self.top_parent.displayed_leafs.append(self.leaf2)
    250                          # Gnumed: sets the newly created leaf as the bottom and focus it
    251                          self.top_parent.refresh_bottom_leaf(self.leaf2)
    252                          self.leaf2.set_focus()
    253
    254 -        def DestroyLeaf(self,caller):
    255  #               print '%s[%s].DestroyLeaf()' % (self.__class__.__name__, id(self))
    256                  top_parent = self.top_parent
    257                  if not self.leaf2:
    258                          self.leaf1.set_content(cEmptyChild(self))       # We will only have 2 windows if
    259                          return                                          # we need to destroy any
    260                  parent = self.GetParent()               # Another splitview
    261                  if parent == self.top_parent:   # We'r at the root
    262  #                       print "parent is root view"
    263  #                       print "caller: %s [%s]" % (caller.__class__.__name__, id(caller))
    264                          if caller == self.leaf1:
    265  #                               print "caller is leaf 1, hence destroying leaf 1 and copying leaf 2 to leaf 1"
    266                                  old = self.leaf1
    267                                  self.leaf1 = self.leaf2
    268                                  self.leaf2 = None
    269                                  # Gnumed: remove content from displayed leafs
    270                                  #print "Removing old: %s [%s]" % (old.__class__.__name__, id(old))
    271                                  #self.top_parent.displayed_leafs.remove(old)
    272                                  old.DestroyLater()
    273                          else:
    274  #                               print "caller is leaf 2, hence destroying leaf 2"
    275                                  # Gnumed: remove content from displayed leafs
    276                                  #print "Removing leaf2: %s [%s]" % (self.leaf2.__class__.__name__, id(self.leaf2))
    277                                  #self.top_parent.displayed_leafs.remove(self.leaf2)
    278                                  self.leaf2.DestroyLater()
    279                                  self.leaf2 = None
    280                          self.leaf1.SetSize(self.GetSize())
    281                          self.leaf1.Move(self.GetPosition())
    282                  else:
    283  #                       print "parent is NOT root view"
    284  #                       print "caller: %s [%s]" % (caller.__class__.__name__, id(caller))
    285  #                       print "Removing caller"
    286                          # Gnumed: remove content from displayed leafs
    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  #                                       print "... leaf 1 ..."
    293                                          parent.leaf1 = self.leaf2
    294                                  else:
    295  #                                       print "... leaf 2 ..."
    296                                          parent.leaf2 = self.leaf2
    297  #                                       print "... so replacing ourselves in the parent with our leaf 2"
    298                                  self.leaf2.Reparent(parent)
    299                                  self.leaf2.SetDimensions(x,y,w,h)
    300  #                               print "caller is leaf 2"
    301  #                               print "in the parent we are ..."
    302                          else:
    303                                  if self == parent.leaf1:
    304  #                                       print "... leaf 1 ..."
    305                                          parent.leaf1 = self.leaf1
    306                                  else:
    307  #                                       print "... leaf 2 ..."
    308                                          parent.leaf2 = self.leaf1
    309  #                                       print "... so replacing ourselves in the parent with our leaf 1"
    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  #                       try:
    318  #                               print "leaf 1: %s [%s]" % (self.leaf1.__class__.__name__, id(self.leaf1))
    319  #                       except Exception:
    320  #                               pass
    321  #                       try:
    322  #                               print "leaf 2: %s [%s]" % (self.leaf2.__class__.__name__, id(self.leaf2))
    323  #                       except Exception:
    324  #                               pass
    325                  # Gnumed: find and update the bottom leaf
    326                  top_parent.refresh_bottom_leaf()
    327                  top_parent.refresh_displayed_leafs(top_parent.child)
    328  #               print "\nGuessed leafs:"
    329  #               cont = 0
    330  #               for a_leaf in top_parent.displayed_leafs:
    331  #                       cont +=1
    332  #                       print "leaf %d: %s [%s]" % (cont, a_leaf.__class__.__name__, id(a_leaf))
    333          #---------------------------------------------
    334 -        def CanSize(self,side,view):
    335                  if self.SizeTarget(side,view):
    336                          return True
    337                  return False
    338
    339 -        def SizeTarget(self,side,view):
    340                  if self.direction == side and self.leaf2 and view == self.leaf1:
    341                          return self
    342                  parent = self.GetParent()
    343                  if parent != self.top_parent:
    344                          return parent.SizeTarget(side,self)
    345                  return None
    346
    347 -        def SizeLeaf(self,leaf,pos,side):
    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
    365 -        def OnSize(self,evt):
    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  #----------------------------------------------------------------------
    398 -class cMultiSashLeaf(wx.Window):
    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):
    404                  wx.Window.__init__(self,id = -1,parent = parent,pos = pos,size = size,
    405                                                    style = wx.CLIP_CHILDREN)
    406                  self.top_parent = top_parent
    407
    408                  self.sizerHor = cMultiSizer(self,MV_HOR)
    409                  self.sizerVer = cMultiSizer(self,MV_VER)
    410                  # Gnumed: Disable creators until obvious solution
    411                  #self.creatorHor = cMultiCreator(self,MV_HOR)
    412                  #self.creatorVer = cMultiCreator(self,MV_VER)
    413                  self.content = cMultiSashLeafContent(self)
    414                  self.closer = cMultiCloser(self)
    415
    416                  wx.EVT_SIZE(self,self.OnSize)
    417          #-----------------------------------------------------
    418 -        def set_focus(self):
    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  #               print "focussed soap editor leaf:", self.__class__.__name__, id(self)
    425
    426 -        def _unselect(self):
    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          #-----------------------------------------------------
    447 -        def Select(self):
    448                  """
    449                  Select the leaf
    450                  """
    451                  self.content.Select()
    452          #-----------------------------------------------------
    453 -        def AddLeaf(self,direction,pos):
    454                  """Add a leaf.
    455
    456                  returns (Status, error)
    457                  errors:
    458                          1: lacking space to add leaf
    459                  """
    460  #               print '%s[%s].AddLeaf()' % (self.__class__.__name__, id(self))
    461                  if pos < 10:
    462                          pos = 10
    463                  w,h = self.GetSize()
    464                  if direction == MV_VER:
    465                          if pos > h - 10:
    466  #                               print "pos", pos
    467  #                               print "w,h", w, h
    468                                  return (False, 1)
    469                  else:
    470                          if pos > w - 10: return (False, 1)
    471                  # Gnumed: when initial leaf, replace its content widget and focus it
    472                  #                else, add a new leaf
    473                  if not isinstance(self.content.child, cEmptyChild):
    474                          self.GetParent().AddLeaf(direction,self,pos)
    475                  else:
    476                          self.set_focus()
    477                          # Gnumed: register added leaf content
    478                          self.GetParent().top_parent.displayed_leafs.append(self)
    479                  return (True, None)
    480
    481          #---------------------------------------------
    482 -        def DestroyLeaf(self):
    483  #               print '%s[%s].DestroyLeaf()' % (self.__class__.__name__, id(self))
    484                  self.GetParent().DestroyLeaf(self)
    485
    486          #-----------------------------------------------------
    487 -        def SizeTarget(self,side):
    488                  return self.GetParent().SizeTarget(side,self)
    489
    490 -        def CanSize(self,side):
    491                  return self.GetParent().CanSize(side,self)
    492
    493 -        def OnSize(self,evt):
    494                  self.sizerHor.OnSize(evt)
    495                  self.sizerVer.OnSize(evt)
    496                  # Gnumed: creators disables until obvious solution
    497                  #self.creatorHor.OnSize(evt)
    498                  #self.creatorVer.OnSize(evt)
    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                  # Gnumed: avoid yellow blinking during widget replacement
    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                  # Gnumed: required to a proper layout of the child and parent widgets
    540                  self.Select()
    541                  self.OnSize(None)
    542          #---------------------------------------------
    543          # internal API
    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):
    552                  self.Select()
    553          #---------------------------------------------
    554 -        def _on_child_focus(self,evt):
    555                  self._on_set_focus(evt)
    556  ##                from Funcs import FindFocusedChild
    557  ##                child = FindFocusedChild(self)
    558  ##                wx.EVT_KILL_FOCUS(child,self.OnChildKillFocus)
    559
    560          #---------------------------------------------
    561 -        def Select(self):
    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                  # Gnumed: when the leaf is selected, highlight and update selected focus
    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)) # Yellow
    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  #----------------------------------------------------------------------
    588 -class cMultiSizer(wx.Window):
    589          """
    590          Leaf's sash bar
    591          """
    592 -        def __init__(self,parent,side):
    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                                  # Previous X
    601                  self.py = None                                  # Previous Y
    602                  self.isDrag = False                             # In Dragging
    603                  self.dragTarget = None                  # View being sized
    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
    611 -        def CalcSizePos(self,parent):
    612                  pw,ph = parent.GetSize()
    613                  if self.side == MV_HOR:
    614                          x = CR_SIZE + 2
    615                          y = ph - SH_SIZE
    616                          w = pw - CR_SIZE - SH_SIZE - 2
    617                          h = SH_SIZE
    618                  else:
    619                          x = pw - SH_SIZE
    620                          y = CR_SIZE + 2 + SH_SIZE
    621                          w = SH_SIZE
    622                          h = ph - CR_SIZE - SH_SIZE - 4 - SH_SIZE # For Closer
    623                  return (x,y,w,h)
    624
    625 -        def OnSize(self,evt):
    626                  x,y,w,h = self.CalcSizePos(self.GetParent())
    627                  self.SetDimensions(x,y,w,h)
    628
    629 -        def OnLeave(self,evt):
    630                  self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
    631
    632 -        def OnEnter(self,evt):
    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
    640 -        def OnMouseMove(self,evt):
    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
    649 -        def OnPress(self,evt):
    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
    660 -        def OnRelease(self,evt):
    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  #----------------------------------------------------------------------
    676 -class cMultiCreator(wx.Window):
    677          """
    678          Sash bar's creator element
    679          """
    680 -        def __init__(self,parent,side):
    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                                  # Previous X
    689                  self.py = None                                  # Previous Y
    690                  self.isDrag = False                       # In Dragging
    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
    699 -        def CalcSizePos(self,parent):
    700                  pw,ph = parent.GetSize()
    701                  if self.side == MV_HOR:
    702                          x = 2
    703                          y = ph - SH_SIZE
    704                          w = CR_SIZE
    705                          h = SH_SIZE
    706                  else:
    707                          x = pw - SH_SIZE
    708                          y = 4 + SH_SIZE                         # Make provision for closer
    709                          w = SH_SIZE
    710                          h = CR_SIZE
    711                  return (x,y,w,h)
    712
    713 -        def OnSize(self,evt):
    714                  x,y,w,h = self.CalcSizePos(self.GetParent())
    715                  self.SetDimensions(x,y,w,h)
    716
    717 -        def OnLeave(self,evt):
    718                  self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
    719
    720 -        def OnEnter(self,evt):
    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
    726 -        def OnMouseMove(self,evt):
    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
    736 -        def OnPress(self,evt):
    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
    744 -        def OnRelease(self,evt):
    745                  if self.isDrag:
    746                          parent = self.GetParent()
    747                          DrawSash(parent,self.px,self.py,self.side)
    748                          self.ReleaseMouse()
    749                          self.isDrag = False
    750
    751                          if self.side == MV_HOR:
    752                                  parent.AddLeaf(MV_VER,self.py)
    753                          else:
    754                                  parent.AddLeaf(MV_HOR,self.px)
    755                  else:
    756                          evt.Skip()
    757
    758 -        def OnPaint(self,evt):
    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                  # Draw outline
    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  #----------------------------------------------------------------------
    783 -class cMultiCloser(wx.Window):
    784          """
    785          Sash bar's destroyer element
    786          """
    787 -        def __init__(self,parent):
    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
    803 -        def OnLeave(self,evt):
    804                  self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
    805                  self.entered = False
    806
    807 -        def OnEnter(self,evt):
    808                  self.SetCursor(wx.StockCursor(wx.CURSOR_BULLSEYE))
    809                  self.entered = True
    810
    811 -        def OnPress(self,evt):
    812                  self.down = True
    813                  evt.Skip()
    814
    815 -        def OnRelease(self,evt):
    816                  if self.down and self.entered:
    817                          self.GetParent().DestroyLeaf()
    818                  else:
    819                          evt.Skip()
    820                  self.down = False
    821
    822 -        def OnPaint(self,evt):
    823                  dc = wxPaintDC(self)
    824                  dc.SetBackground(wx.Brush(wx.RED,wx.SOLID))
    825                  dc.Clear()
    826
    827 -        def CalcSizePos(self,parent):
    828                  pw,ph = parent.GetSize()
    829                  x = pw - SH_SIZE
    830                  w = SH_SIZE
    831                  h = SH_SIZE + 2
    832                  y = 1
    833                  return (x,y,w,h)
    834
    835 -        def OnSize(self,evt):
    836                  x,y,w,h = self.CalcSizePos(self.GetParent())
    837                  self.SetDimensions(x,y,w,h)
    838
    839
    840  #----------------------------------------------------------------------
    841
    842
    843 -class cEmptyChild(wx.Window):
    844 -        def __init__(self,parent):
    845                  wx.Window.__init__(self,parent,-1, style = wx.CLIP_CHILDREN)
    846
    847
    848  #----------------------------------------------------------------------
    849
    850
    851 -def DrawSash(win,x,y,direction):
    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