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  try:
     21          import wxversion
     22          import wx
     23  except ImportError:
     24          from wxPython import wx
     25
     26  MV_HOR = 0
     27  MV_VER = not MV_HOR
     28
     29  SH_SIZE = 5
     30  CR_SIZE = SH_SIZE * 3
     31
     32  #----------------------------------------------------------------------
     33 -class cMultiSash(wx.Window):
     34          """
     35          Main multisash widget. Dynamically displays a stack of child widgets.
     36          """
     37 -        def __init__(self, *_args,**_kwargs):
     38                  apply(wx.Window.__init__,(self,) + _args,_kwargs)
     39                  #self._defChild = cEmptyChild
     40                  self.child = cMultiSashSplitter(self,self,wxPoint(0,0),self.GetSize())
     41
     42                  # Gnumed: focused and bottom leaf
     43                  self.focussed_leaf = self.child.leaf1
     44                  self.bottom_leaf = self.child.leaf1
     45                  self.displayed_leafs = []
     46
     47                  wx.EVT_SIZE(self,self._on_size)
     48          #---------------------------------------------
     49          # public API
     50          #---------------------------------------------
     51          # Gnumed:
     52 -        def get_focussed_leaf(self):
     53                  """
     54                  Retrieves the currently focused leaf. Typically, used to
     55                  process some action over the focused widget.
     56                  """
     57                  return self.focussed_leaf
     58          #---------------------------------------------
     59 -        def get_displayed_leafs(self):
     60                  """
     61                  Retrieves the currently displayed leafs.
     62                  """
     63                  return self.displayed_leafs
     64          #---------------------------------------------
     65 -        def add_content(self, content):
     66                  """
     67                  Adds he supplied content widget to the multisash, setting it as
     68                  child of the bottom leaf.
     69
     70                  @param content The new content widget to add.
     71                  @type content Any wx.Window derived object.
     72                  """
     73                  successful, errno = self.bottom_leaf.AddLeaf(direction = MV_VER, pos = 100)
     74                  if successful:
     75                          self.bottom_leaf.set_content(content)
     76                  return successful, errno
     77          #---------------------------------------------
     78 -        def Clear(self):
     79                  """
     80                  Clear all mulsisash leafs and restores initial values
     81                  """
     82                  # FIXME: keep an eye if strange behaviour
     83                  old = self.child
     84                  self.child = cMultiSashSplitter(self,self,wxPoint(0,0),self.GetSize())
     85                  old.Destroy()
     86                  self.child.OnSize(None)
     87
     88                  # Gnumed: focused and bottom leaf
     89                  self.focussed_leaf = self.child.leaf1
     90                  self.bottom_leaf = self.child.leaf1
     91                  self.bottom_leaf.Select()
     92                  self.displayed_leafs = []
     93          #---------------------------------------------
     94 -        def refresh_bottom_leaf(self, bottom_leaf = None):
     95                  """
     96                  Updates the field that keeps track of the bottom leaf. It is required
     97                  to ensure new leafs are created under the bottom one.
     98                  If the bottom leaf is supplied as parameter, it is set. Typically,
     99                  after a new leaf has been added/created.
    100                  If the bottom leaf ins not supplied ad parameter, it will be dinamically
    101                  obtained. Typically, after leaf destruction.
    102
    103                  @param bottom_leaf The leaf to be set as bottom one
    104                  @type bottom_leaf wx.MultiViewLeaf
    105                  """
    106                  if bottom_leaf is None:
    107                          self.bottom_leaf = self.__find_bottom_leaf(self.child)
    108                  else:
    109                          self.bottom_leaf = bottom_leaf
    110                  self.bottom_leaf.Select()
    111
    112          #---------------------------------------------
    113 -        def refresh_displayed_leafs(self, splitter):
    114                  """
    115                  Recursively find all displayed leafs.
    116                  @param splitter The multisash splitter to traverse its leafs for.
    117                  @type splitter cMultiSashSplitter
    118                  """
    119                  if id(splitter) == id(self.child):
    120                          self.displayed_leafs = []
    121  #               print "__refresh_displayed_leafs()"
    122  #               print "splitter: %s [%s]" % (splitter.__class__.__name__, id(splitter))
    123  #               print "- leaf 1: %s [%s]" % (splitter.leaf1.__class__.__name__, id(splitter.leaf1))
    124  #               print "- leaf 2: %s [%s]" % (splitter.leaf2.__class__.__name__, id(splitter.leaf2))
    125                  if isinstance(splitter.leaf1, cMultiSashSplitter):
    126  #                       print "leaf 1 is splitter, recurse down"
    127                          self.refresh_displayed_leafs(splitter.leaf1)
    128                  if isinstance(splitter.leaf2, cMultiSashSplitter):
    129  #                       print "leaf 2 is splitter, recurse down"
    130                          self.refresh_displayed_leafs(splitter.leaf2)
    131  #               print "found bottom split: %s [%s]" % (splitter.__class__.__name__, id(splitter))
    132                  if not splitter.leaf2 is None and not isinstance(splitter.leaf2, cMultiSashSplitter):
    133  #                       print "found leaf (leaf2): %s [%s]" % (splitter.leaf2.__class__.__name__, id(splitter.leaf2))
    134                          self.displayed_leafs.append(splitter.leaf2)
    135                  if not splitter.leaf1 is None and not isinstance(splitter.leaf1, cMultiSashSplitter):
    136  #                       print "found leaf (leaf1): %s [%s]" % (splitter.leaf1.__class__.__name__, id(splitter.leaf1))
    137                          self.displayed_leafs.append(splitter.leaf1)
    138          #---------------------------------------------
    139          # event handlers
    140          #---------------------------------------------
    141 -        def _on_size(self, evt):
    142                  self.child.SetSize(self.GetSize())
    143          #---------------------------------------------
    144          # internal API
    145          #---------------------------------------------
    146 -        def __find_bottom_leaf(self, splitter):
    147                  """
    148                  Recursively find and return the bottom leaf.
    149                  """
    150  #               print "__find_bottom_leaf()"
    151  #               print "splitter: %s [%s]" % (splitter.__class__.__name__, id(splitter))
    152  #               print "- leaf 1: %s [%s]" % (splitter.leaf1.__class__.__name__, id(splitter.leaf1))
    153  #               print "- leaf 2: %s [%s]" % (splitter.leaf2.__class__.__name__, id(splitter.leaf2))
    154                  if isinstance(splitter.leaf1, cMultiSashSplitter):
    155  #                       print "leaf 1 is splitter, recurse down"
    156                          return self.__find_bottom_leaf(splitter.leaf1)
    157                  if isinstance(splitter.leaf2, cMultiSashSplitter):
    158  #                       print "leaf 2 is splitter, recurse down"
    159                          return self.__find_bottom_leaf(splitter.leaf2)
    160  #               print "found bottom split: %s [%s]" % (splitter.__class__.__name__, id(splitter))
    161                  if not splitter.leaf2 is None:
    162  #                       print "bottom leaf (leaf2): %s [%s]" % (splitter.leaf2.__class__.__name__, id(splitter.leaf2))
    163                          return splitter.leaf2
    164                  else:
    165  #                       print "bottom leaf (leaf1): %s [%s]" % (splitter.leaf1.__class__.__name__, id(splitter.leaf1))
    166                          return splitter.leaf1
    167          #---------------------------------------------
    168 -        def _unselect(self):
    169                  self.child._unselect()
    170  #----------------------------------------------------------------------
    171 -class cMultiSashSplitter(wx.Window):
    172          """
    173          Basic split windows container of the multisash widget.
    174          Has references to two leafs or splitted windows (typically, first leaf
    175          is another cMultiSashSplitter and the second leaf is the displayed content
    176          widget).
    177          """
    178 -        def __init__(self, top_parent, parent, pos, size, leaf1 = None):
    179                  wx.Window.__init__ (
    180                          self,
    181                          id = -1,
    182                          parent = parent,
    183                          pos = pos,
    184                          size = size,
    185                          style = wx.CLIP_CHILDREN
    186                  )
    187                  self.top_parent = top_parent
    188                  self.leaf2 = None
    189                  if leaf1:
    190                          self.leaf1 = leaf1
    191                          self.leaf1.Reparent(self)
    192                          self.leaf1.MoveXY(0,0)
    193                  else:
    194                          self.leaf1 = cMultiSashLeaf (
    195                                  self.top_parent,
    196                                  self,
    197                                  wxPoint(0,0),
    198                                  self.GetSize()
    199                          )
    200                  self.direction = None
    201
    202                  wx.EVT_SIZE(self,self.OnSize)
    203          #---------------------------------------------
    204 -        def _unselect(self):
    205                  if self.leaf1:
    206                          self.leaf1._unselect()
    207                  if self.leaf2:
    208                          self.leaf2._unselect()
    209
    210          #---------------------------------------------
    211 -        def AddLeaf(self,direction,caller,pos):
    212  #               print '%s[%s].AddLeaf()' % (self.__class__.__name__, id(self))
    213  #               print "leaf 1: %s [%s]" % (self.leaf1.__class__.__name__, id(self.leaf1))
    214  #               print "leaf 2: %s [%s]" % (self.leaf2.__class__.__name__, id(self.leaf2))
    215                  if self.leaf2:
    216  #                       print "we have two leafs"
    217  #                       print "caller: %s [%s]" % (caller.__class__.__name__, id(caller))
    218                          if caller == self.leaf1:
    219  #                               print "caller was leaf 1, hence splitting leaf 1"
    220                                  self.leaf1 = cMultiSashSplitter(self.top_parent,self,
    221                                                                                    caller.GetPosition(),
    222                                                                                    caller.GetSize(),
    223                                                                                    caller)
    224                                  self.leaf1.AddLeaf(direction,caller,pos)
    225                          else:
    226  #                               print "caller was leaf 2, hence splitting leaf 2"
    227                                  self.leaf2 = cMultiSashSplitter(self.top_parent,self,
    228                                                                                    caller.GetPosition(),
    229                                                                                    caller.GetSize(),
    230                                                                                    caller)
    231                                  self.leaf2.AddLeaf(direction,caller,pos)
    232                  else:
    233  #                       print "we have only one leaf"
    234  #                       print "caller: %s [%s]" % (caller.__class__.__name__, id(caller))
    235  #                       print "hence caller must have been leaf 1 hence adding leaf 2 ..."
    236                          self.direction = direction
    237                          w,h = self.GetSizeTuple()
    238                          if direction == MV_HOR:
    239  #                               print "... next to leaf 1"
    240                                  x,y = (pos,0)
    241                                  w1,h1 = (w-pos,h)
    242                                  w2,h2 = (pos,h)
    243                          else:
    244  #                               print "... below leaf 1"
    245                                  x,y = (0,pos)
    246                                  w1,h1 = (w,h-pos)
    247                                  w2,h2 = (w,pos)
    248                          self.leaf2 = cMultiSashLeaf(self.top_parent,self,
    249                                                                                   wxPoint(x,y),wx.Size(w1,h1))
    250                          self.leaf1.SetSize(wx.Size(w2,h2))
    251                          self.leaf2.OnSize(None)
    252                          # Gnumed: register added leaf content
    253                          self.top_parent.displayed_leafs.append(self.leaf2)
    254                          # Gnumed: sets the newly created leaf as the bottom and focus it
    255                          self.top_parent.refresh_bottom_leaf(self.leaf2)
    256                          self.leaf2.set_focus()
    257
    258 -        def DestroyLeaf(self,caller):
    259  #               print '%s[%s].DestroyLeaf()' % (self.__class__.__name__, id(self))
    260                  top_parent = self.top_parent
    261                  if not self.leaf2:
    262                          self.leaf1.set_content(cEmptyChild(self))       # We will only have 2 windows if
    263                          return                                          # we need to destroy any
    264                  parent = self.GetParent()               # Another splitview
    265                  if parent == self.top_parent:   # We'r at the root
    266  #                       print "parent is root view"
    267  #                       print "caller: %s [%s]" % (caller.__class__.__name__, id(caller))
    268                          if caller == self.leaf1:
    269  #                               print "caller is leaf 1, hence destroying leaf 1 and copying leaf 2 to leaf 1"
    270                                  old = self.leaf1
    271                                  self.leaf1 = self.leaf2
    272                                  self.leaf2 = None
    273                                  # Gnumed: remove content from displayed leafs
    274                                  #print "Removing old: %s [%s]" % (old.__class__.__name__, id(old))
    275                                  #self.top_parent.displayed_leafs.remove(old)
    276                                  old.Destroy()
    277                          else:
    278  #                               print "caller is leaf 2, hence destroying leaf 2"
    279                                  # Gnumed: remove content from displayed leafs
    280                                  #print "Removing leaf2: %s [%s]" % (self.leaf2.__class__.__name__, id(self.leaf2))
    281                                  #self.top_parent.displayed_leafs.remove(self.leaf2)
    282                                  self.leaf2.Destroy()
    283                                  self.leaf2 = None
    284                          self.leaf1.SetSize(self.GetSize())
    285                          self.leaf1.Move(self.GetPosition())
    286                  else:
    287  #                       print "parent is NOT root view"
    288  #                       print "caller: %s [%s]" % (caller.__class__.__name__, id(caller))
    289  #                       print "Removing caller"
    290                          # Gnumed: remove content from displayed leafs
    291                          self.top_parent.displayed_leafs.remove(caller)
    292                          w,h = self.GetSizeTuple()
    293                          x,y = self.GetPositionTuple()
    294                          if caller == self.leaf1:
    295                                  if self == parent.leaf1:
    296  #                                       print "... leaf 1 ..."
    297                                          parent.leaf1 = self.leaf2
    298                                  else:
    299  #                                       print "... leaf 2 ..."
    300                                          parent.leaf2 = self.leaf2
    301  #                                       print "... so replacing ourselves in the parent with our leaf 2"
    302                                  self.leaf2.Reparent(parent)
    303                                  self.leaf2.SetDimensions(x,y,w,h)
    304  #                               print "caller is leaf 2"
    305  #                               print "in the parent we are ..."
    306                          else:
    307                                  if self == parent.leaf1:
    308  #                                       print "... leaf 1 ..."
    309                                          parent.leaf1 = self.leaf1
    310                                  else:
    311  #                                       print "... leaf 2 ..."
    312                                          parent.leaf2 = self.leaf1
    313  #                                       print "... so replacing ourselves in the parent with our leaf 1"
    314                                  self.leaf1.Reparent(parent)
    315                                  self.leaf1.SetDimensions(x,y,w,h)
    316
    317                          self.leaf1 = None
    318                          self.leaf2 = None
    319                          top_parent = self.top_parent
    320                          self.Destroy()
    321  #                       try:
    322  #                               print "leaf 1: %s [%s]" % (self.leaf1.__class__.__name__, id(self.leaf1))
    323  #                       except:
    324  #                               pass
    325  #                       try:
    326  #                               print "leaf 2: %s [%s]" % (self.leaf2.__class__.__name__, id(self.leaf2))
    327  #                       except:
    328  #                               pass
    329                  # Gnumed: find and update the bottom leaf
    330                  top_parent.refresh_bottom_leaf()
    331                  top_parent.refresh_displayed_leafs(top_parent.child)
    332  #               print "\nGuessed leafs:"
    333  #               cont = 0
    334  #               for a_leaf in top_parent.displayed_leafs:
    335  #                       cont +=1
    336  #                       print "leaf %d: %s [%s]" % (cont, a_leaf.__class__.__name__, id(a_leaf))
    337          #---------------------------------------------
    338 -        def CanSize(self,side,view):
    339                  if self.SizeTarget(side,view):
    340                          return True
    341                  return False
    342
    343 -        def SizeTarget(self,side,view):
    344                  if self.direction == side and self.leaf2 and view == self.leaf1:
    345                          return self
    346                  parent = self.GetParent()
    347                  if parent != self.top_parent:
    348                          return parent.SizeTarget(side,self)
    349                  return None
    350
    351 -        def SizeLeaf(self,leaf,pos,side):
    352                  if self.direction != side:
    353                          return
    354                  if not (self.leaf1 and self.leaf2):
    355                          return
    356                  if pos < 10: return
    357                  w,h = self.GetSizeTuple()
    358                  if side == MV_HOR:
    359                          if pos > w - 10: return
    360                  else:
    361                          if pos > h - 10: return
    362                  if side == MV_HOR:
    363                          self.leaf1.SetDimensions(0,0,pos,h)
    364                          self.leaf2.SetDimensions(pos,0,w-pos,h)
    365                  else:
    366                          self.leaf1.SetDimensions(0,0,w,pos)
    367                          self.leaf2.SetDimensions(0,pos,w,h-pos)
    368
    369 -        def OnSize(self,evt):
    370                  if not self.leaf2:
    371                          self.leaf1.SetSize(self.GetSize())
    372                          self.leaf1.OnSize(None)
    373                          return
    374                  v1w,v1h = self.leaf1.GetSizeTuple()
    375                  v2w,v2h = self.leaf2.GetSizeTuple()
    376                  v1x,v1y = self.leaf1.GetPositionTuple()
    377                  v2x,v2y = self.leaf2.GetPositionTuple()
    378                  w,h = self.GetSizeTuple()
    379
    380                  if v1x != v2x:
    381                          ratio = float(w) / float((v1w + v2w))
    382                          v1w *= ratio
    383                          v2w = w - v1w
    384                          v2x = v1w
    385                  else:
    386                          v1w = v2w = w
    387
    388                  if v1y != v2y:
    389                          ratio = float(h) / float((v1h + v2h))
    390                          v1h *= ratio
    391                          v2h = h - v1h
    392                          v2y = v1h
    393                  else:
    394                          v1h = v2h = h
    395
    396                  self.leaf1.SetDimensions(v1x,v1y,v1w,v1h)
    397                  self.leaf2.SetDimensions(v2x,v2y,v2w,v2h)
    398                  self.leaf1.OnSize(None)
    399                  self.leaf2.OnSize(None)
    400
    401  #----------------------------------------------------------------------
    402 -class cMultiSashLeaf(wx.Window):
    403          """
    404          A leaf represent a split window, one instance of the displayed content
    405          widget.
    406          """
    407 -        def __init__(self,top_parent,parent,pos,size):
    408                  wx.Window.__init__(self,id = -1,parent = parent,pos = pos,size = size,
    409                                                    style = wx.CLIP_CHILDREN)
    410                  self.top_parent = top_parent
    411
    412                  self.sizerHor = cMultiSizer(self,MV_HOR)
    413                  self.sizerVer = cMultiSizer(self,MV_VER)
    414                  # Gnumed: Disable creators until obvious solution
    415                  #self.creatorHor = cMultiCreator(self,MV_HOR)
    416                  #self.creatorVer = cMultiCreator(self,MV_VER)
    417                  self.content = cMultiSashLeafContent(self)
    418                  self.closer = cMultiCloser(self)
    419
    420                  wx.EVT_SIZE(self,self.OnSize)
    421          #-----------------------------------------------------
    422 -        def set_focus(self):
    423                  """
    424                  Set current leaf as focused leaf. Typically, the focused widget
    425                  will be required to further actions and processing.
    426                  """
    427                  self.top_parent.focussed_leaf = self
    428  #               print "focussed soap editor leaf:", self.__class__.__name__, id(self)
    429
    430 -        def _unselect(self):
    431                  self.content._unselect()
    432
    433          #-----------------------------------------------------
    434 -        def set_content(self, content):
    435                  """
    436                  Sets the as content child of this leaf.
    437
    438                  @param content The new content widget to set..
    439                  @type content Any wx.Window derived object.
    440                  """
    441                  self.content.set_new_content(content)
    442
    443          #-----------------------------------------------------
    444 -        def get_content(self):
    445                  """
    446                  Retrieves the content child of this leaf.
    447                  """
    448                  return self.content.child
    449
    450          #-----------------------------------------------------
    451 -        def Select(self):
    452                  """
    453                  Select the leaf
    454                  """
    455                  self.content.Select()
    456          #-----------------------------------------------------
    457 -        def AddLeaf(self,direction,pos):
    458                  """Add a leaf.
    459
    460                  returns (Status, error)
    461                  errors:
    462                          1: lacking space to add leaf
    463                  """
    464  #               print '%s[%s].AddLeaf()' % (self.__class__.__name__, id(self))
    465                  if pos < 10:
    466                          pos = 10
    467                  w,h = self.GetSizeTuple()
    468                  if direction == MV_VER:
    469                          if pos > h - 10:
    470  #                               print "pos", pos
    471  #                               print "w,h", w, h
    472                                  return (False, 1)
    473                  else:
    474                          if pos > w - 10: return (False, 1)
    475                  # Gnumed: when initial leaf, replace its content widget and focus it
    476                  #                else, add a new leaf
    477                  if not isinstance(self.content.child, cEmptyChild):
    478                          self.GetParent().AddLeaf(direction,self,pos)
    479                  else:
    480                          self.set_focus()
    481                          # Gnumed: register added leaf content
    482                          self.GetParent().top_parent.displayed_leafs.append(self)
    483                  return (True, None)
    484
    485          #---------------------------------------------
    486 -        def DestroyLeaf(self):
    487  #               print '%s[%s].DestroyLeaf()' % (self.__class__.__name__, id(self))
    488                  self.GetParent().DestroyLeaf(self)
    489
    490          #-----------------------------------------------------
    491 -        def SizeTarget(self,side):
    492                  return self.GetParent().SizeTarget(side,self)
    493
    494 -        def CanSize(self,side):
    495                  return self.GetParent().CanSize(side,self)
    496
    497 -        def OnSize(self,evt):
    498                  self.sizerHor.OnSize(evt)
    499                  self.sizerVer.OnSize(evt)
    500                  # Gnumed: creators disables until obvious solution
    501                  #self.creatorHor.OnSize(evt)
    502                  #self.creatorVer.OnSize(evt)
    503                  self.content.OnSize(evt)
    504                  self.closer.OnSize(evt)
    505
    506  #----------------------------------------------------------------------
    507 -class cMultiSashLeafContent(wx.Window):
    508          """
    509          Widget that encapsulate contents of a leaf or split window.
    510          """
    511 -        def __init__(self,parent):
    512                  w,h = self.CalcSize(parent)
    513                  wx.Window.__init__ (
    514                          self,
    515                          id = -1,
    516                          parent = parent,
    517                          pos = wxPoint(0,0),
    518                          size = wx.Size(w,h),
    519                          style = wx.CLIP_CHILDREN | wx.SUNKEN_BORDER
    520                  )
    521                  self.child = cEmptyChild(self)
    522                  self.child.MoveXY(2,2)
    523                  self.__normal_colour = self.GetBackgroundColour()
    524                  self.selected = False
    525
    526                  wx.EVT_SET_FOCUS(self, self._on_set_focus)
    527                  wx.EVT_CHILD_FOCUS(self, self._on_child_focus)
    528          #---------------------------------------------
    529 -        def set_new_content(self,content):
    530                  """
    531                  Sets the as content child of this widget.
    532
    533                  @param content The new content widget to set..
    534                  @type content Any wx.Window derived object.
    535                  """
    536                  # Gnumed: avoid yellow blinking during widget replacement
    537                  self.SetBackgroundColour(self.__normal_colour)
    538                  if self.child:
    539                          self.child.Destroy()
    540                  content.Reparent(self)
    541                  self.child = content
    542                  self.child.MoveXY(2,2)
    543                  # Gnumed: required to a proper layout of the child and parent widgets
    544                  self.Select()
    545                  self.OnSize(None)
    546          #---------------------------------------------
    547          # internal API
    548          #---------------------------------------------
    549 -        def _unselect(self):
    550                  if self.selected:
    551                          self.selected = False
    552                          self.SetBackgroundColour(self.__normal_colour)
    553                          self.Refresh()
    554          #---------------------------------------------
    555 -        def _on_set_focus(self,evt):
    556                  self.Select()
    557          #---------------------------------------------
    558 -        def _on_child_focus(self,evt):
    559                  self._on_set_focus(evt)
    560  ##                from Funcs import FindFocusedChild
    561  ##                child = FindFocusedChild(self)
    562  ##                wx.EVT_KILL_FOCUS(child,self.OnChildKillFocus)
    563
    564          #---------------------------------------------
    565 -        def Select(self):
    566                  """
    567                  May be invoked by user clicking on the leaf, or programmatically after
    568                  leaf creation. Highlight it and update focused leaf.
    569                  """
    570                  # Gnumed: when the leaf is selected, highlight and update selected focus
    571                  parent = self.GetParent()
    572                  parent.top_parent._unselect()
    573                  self.selected = True
    574                  if parent.top_parent.focussed_leaf != parent:
    575                          parent.set_focus()
    576                  self.SetBackgroundColour(wx.Colour(255,255,0)) # Yellow
    577                  self.Refresh()
    578
    579 -        def CalcSize(self,parent):
    580                  w,h = parent.GetSizeTuple()
    581                  w -= SH_SIZE
    582                  h -= SH_SIZE
    583                  return (w,h)
    584
    585 -        def OnSize(self,evt):
    586                  w,h = self.CalcSize(self.GetParent())
    587                  self.SetDimensions(0,0,w,h)
    588                  w,h = self.GetClientSizeTuple()
    589                  self.child.SetSize(wx.Size(w-4,h-4))
    590  #----------------------------------------------------------------------
    591 -class cMultiSizer(wx.Window):
    592          """
    593          Leaf's sash bar
    594          """
    595 -        def __init__(self,parent,side):
    596                  self.side = side
    597                  x,y,w,h = self.CalcSizePos(parent)
    598                  wx.Window.__init__(self,id = -1,parent = parent,
    599                                                    pos = wxPoint(x,y),
    600                                                    size = wx.Size(w,h),
    601                                                    style = wx.CLIP_CHILDREN)
    602
    603                  self.px = None                                  # Previous X
    604                  self.py = None                                  # Previous Y
    605                  self.isDrag = False                             # In Dragging
    606                  self.dragTarget = None                  # View being sized
    607
    608                  wx.EVT_LEAVE_WINDOW(self,self.OnLeave)
    609                  wx.EVT_ENTER_WINDOW(self,self.OnEnter)
    610                  wx.EVT_MOTION(self,self.OnMouseMove)
    611                  wx.EVT_LEFT_DOWN(self,self.OnPress)
    612                  wx.EVT_LEFT_UP(self,self.OnRelease)
    613
    614 -        def CalcSizePos(self,parent):
    615                  pw,ph = parent.GetSizeTuple()
    616                  if self.side == MV_HOR:
    617                          x = CR_SIZE + 2
    618                          y = ph - SH_SIZE
    619                          w = pw - CR_SIZE - SH_SIZE - 2
    620                          h = SH_SIZE
    621                  else:
    622                          x = pw - SH_SIZE
    623                          y = CR_SIZE + 2 + SH_SIZE
    624                          w = SH_SIZE
    625                          h = ph - CR_SIZE - SH_SIZE - 4 - SH_SIZE # For Closer
    626                  return (x,y,w,h)
    627
    628 -        def OnSize(self,evt):
    629                  x,y,w,h = self.CalcSizePos(self.GetParent())
    630                  self.SetDimensions(x,y,w,h)
    631
    632 -        def OnLeave(self,evt):
    633                  self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
    634
    635 -        def OnEnter(self,evt):
    636                  if not self.GetParent().CanSize(not self.side):
    637                          return
    638                  if self.side == MV_HOR:
    639                          self.SetCursor(wx.StockCursor(wx.CURSOR_SIZENS))
    640                  else:
    641                          self.SetCursor(wx.StockCursor(wx.CURSOR_SIZEWE))
    642
    643 -        def OnMouseMove(self,evt):
    644                  if self.isDrag:
    645                          DrawSash(self.dragTarget,self.px,self.py,self.side)
    646                          self.px,self.py = self.ClientToScreenXY(evt.m_x,evt.m_y)
    647                          self.px,self.py = self.dragTarget.ScreenToClientXY(self.px,self.py)
    648                          DrawSash(self.dragTarget,self.px,self.py,self.side)
    649                  else:
    650                          evt.Skip()
    651
    652 -        def OnPress(self,evt):
    653                  self.dragTarget = self.GetParent().SizeTarget(not self.side)
    654                  if self.dragTarget:
    655                          self.isDrag = True
    656                          self.px,self.py = self.ClientToScreenXY(evt.m_x,evt.m_y)
    657                          self.px,self.py = self.dragTarget.ScreenToClientXY(self.px,self.py)
    658                          DrawSash(self.dragTarget,self.px,self.py,self.side)
    659                          self.CaptureMouse()
    660                  else:
    661                          evt.Skip()
    662
    663 -        def OnRelease(self,evt):
    664                  if self.isDrag:
    665                          DrawSash(self.dragTarget,self.px,self.py,self.side)
    666                          self.ReleaseMouse()
    667                          self.isDrag = False
    668                          if self.side == MV_HOR:
    669                                  self.dragTarget.SizeLeaf(self.GetParent(),
    670                                                                                   self.py,not self.side)
    671                          else:
    672                                  self.dragTarget.SizeLeaf(self.GetParent(),
    673                                                                                   self.px,not self.side)
    674                          self.dragTarget = None
    675                  else:
    676                          evt.Skip()
    677
    678  #----------------------------------------------------------------------
    679 -class cMultiCreator(wx.Window):
    680          """
    681          Sash bar's creator element
    682          """
    683 -        def __init__(self,parent,side):
    684                  self.side = side
    685                  x,y,w,h = self.CalcSizePos(parent)
    686                  wx.Window.__init__(self,id = -1,parent = parent,
    687                                                    pos = wxPoint(x,y),
    688                                                    size = wx.Size(w,h),
    689                                                    style = wx.CLIP_CHILDREN)
    690
    691                  self.px = None                                  # Previous X
    692                  self.py = None                                  # Previous Y
    693                  self.isDrag = False                       # In Dragging
    694
    695                  wx.EVT_LEAVE_WINDOW(self,self.OnLeave)
    696                  wx.EVT_ENTER_WINDOW(self,self.OnEnter)
    697                  wx.EVT_MOTION(self,self.OnMouseMove)
    698                  wx.EVT_LEFT_DOWN(self,self.OnPress)
    699                  wx.EVT_LEFT_UP(self,self.OnRelease)
    700                  wx.EVT_PAINT(self,self.OnPaint)
    701
    702 -        def CalcSizePos(self,parent):
    703                  pw,ph = parent.GetSizeTuple()
    704                  if self.side == MV_HOR:
    705                          x = 2
    706                          y = ph - SH_SIZE
    707                          w = CR_SIZE
    708                          h = SH_SIZE
    709                  else:
    710                          x = pw - SH_SIZE
    711                          y = 4 + SH_SIZE                         # Make provision for closer
    712                          w = SH_SIZE
    713                          h = CR_SIZE
    714                  return (x,y,w,h)
    715
    716 -        def OnSize(self,evt):
    717                  x,y,w,h = self.CalcSizePos(self.GetParent())
    718                  self.SetDimensions(x,y,w,h)
    719
    720 -        def OnLeave(self,evt):
    721                  self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
    722
    723 -        def OnEnter(self,evt):
    724                  if self.side == MV_HOR:
    725                          self.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
    726                  else:
    727                          self.SetCursor(wx.StockCursor(wx.CURSOR_POINT_LEFT))
    728
    729 -        def OnMouseMove(self,evt):
    730                  if self.isDrag:
    731                          parent = self.GetParent()
    732                          DrawSash(parent,self.px,self.py,self.side)
    733                          self.px,self.py = self.ClientToScreenXY(evt.m_x,evt.m_y)
    734                          self.px,self.py = parent.ScreenToClientXY(self.px,self.py)
    735                          DrawSash(parent,self.px,self.py,self.side)
    736                  else:
    737                          evt.Skip()
    738
    739 -        def OnPress(self,evt):
    740                  self.isDrag = True
    741                  parent = self.GetParent()
    742                  self.px,self.py = self.ClientToScreenXY(evt.m_x,evt.m_y)
    743                  self.px,self.py = parent.ScreenToClientXY(self.px,self.py)
    744                  DrawSash(parent,self.px,self.py,self.side)
    745                  self.CaptureMouse()
    746
    747 -        def OnRelease(self,evt):
    748                  if self.isDrag:
    749                          parent = self.GetParent()
    750                          DrawSash(parent,self.px,self.py,self.side)
    751                          self.ReleaseMouse()
    752                          self.isDrag = False
    753
    754                          if self.side == MV_HOR:
    755                                  parent.AddLeaf(MV_VER,self.py)
    756                          else:
    757                                  parent.AddLeaf(MV_HOR,self.px)
    758                  else:
    759                          evt.Skip()
    760
    761 -        def OnPaint(self,evt):
    762                  dc = wxPaintDC(self)
    763                  dc.SetBackground(wx.Brush(self.GetBackgroundColour(),wx.SOLID))
    764                  dc.Clear()
    765
    766                  highlight = wxPen(wx.SystemSettings_GetSystemColour(
    767                          wx.SYS_COLOUR_BTNHIGHLIGHT),1,wx.SOLID)
    768                  shadow = wxPen(wx.SystemSettings_GetSystemColour(
    769                          wx.SYS_COLOUR_BTNSHADOW),1,wx.SOLID)
    770                  black = wxPen(wx.BLACK,1,wx.SOLID)
    771                  w,h = self.GetSizeTuple()
    772                  w -= 1
    773                  h -= 1
    774
    775                  # Draw outline
    776                  dc.SetPen(highlight)
    777                  dc.DrawLine(0,0,0,h)
    778                  dc.DrawLine(0,0,w,0)
    779                  dc.SetPen(black)
    780                  dc.DrawLine(0,h,w+1,h)
    781                  dc.DrawLine(w,0,w,h)
    782                  dc.SetPen(shadow)
    783                  dc.DrawLine(w-1,2,w-1,h)
    784
    785  #----------------------------------------------------------------------
    786 -class cMultiCloser(wx.Window):
    787          """
    788          Sash bar's destroyer element
    789          """
    790 -        def __init__(self,parent):
    791                  x,y,w,h = self.CalcSizePos(parent)
    792                  wx.Window.__init__(self,id = -1,parent = parent,
    793                                                    pos = wxPoint(x,y),
    794                                                    size = wx.Size(w,h),
    795                                                    style = wx.CLIP_CHILDREN)
    796
    797                  self.down = False
    798                  self.entered = False
    799
    800                  wx.EVT_LEFT_DOWN(self,self.OnPress)
    801                  wx.EVT_LEFT_UP(self,self.OnRelease)
    802                  wx.EVT_PAINT(self,self.OnPaint)
    803                  wx.EVT_LEAVE_WINDOW(self,self.OnLeave)
    804                  wx.EVT_ENTER_WINDOW(self,self.OnEnter)
    805
    806 -        def OnLeave(self,evt):
    807                  self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
    808                  self.entered = False
    809
    810 -        def OnEnter(self,evt):
    811                  self.SetCursor(wx.StockCursor(wx.CURSOR_BULLSEYE))
    812                  self.entered = True
    813
    814 -        def OnPress(self,evt):
    815                  self.down = True
    816                  evt.Skip()
    817
    818 -        def OnRelease(self,evt):
    819                  if self.down and self.entered:
    820                          self.GetParent().DestroyLeaf()
    821                  else:
    822                          evt.Skip()
    823                  self.down = False
    824
    825 -        def OnPaint(self,evt):
    826                  dc = wxPaintDC(self)
    827                  dc.SetBackground(wx.Brush(wx.RED,wx.SOLID))
    828                  dc.Clear()
    829
    830 -        def CalcSizePos(self,parent):
    831                  pw,ph = parent.GetSizeTuple()
    832                  x = pw - SH_SIZE
    833                  w = SH_SIZE
    834                  h = SH_SIZE + 2
    835                  y = 1
    836                  return (x,y,w,h)
    837
    838 -        def OnSize(self,evt):
    839                  x,y,w,h = self.CalcSizePos(self.GetParent())
    840                  self.SetDimensions(x,y,w,h)
    841
    842
    843  #----------------------------------------------------------------------
    844
    845
    846 -class cEmptyChild(wx.Window):
    847 -        def __init__(self,parent):
    848                  wx.Window.__init__(self,parent,-1, style = wx.CLIP_CHILDREN)
    849
    850
    851  #----------------------------------------------------------------------
    852
    853
    854 -def DrawSash(win,x,y,direction):
    855          dc = wx.ScreenDC()
    856          dc.StartDrawingOnTopWin(win)
    857          bmp = wx.EmptyBitmap(8,8)
    858          bdc = wx.MemoryDC()
    859          bdc.SelectObject(bmp)
    860          bdc.DrawRectangle(-1,-1,10,10)
    861          for i in range(8):
    862                  for j in range(8):
    863                          if ((i + j) & 1):
    864                                  bdc.DrawPoint(i,j)
    865
    866          brush = wx.Brush(wx.Colour(0,0,0))
    867          brush.SetStipple(bmp)
    868
    869          dc.SetBrush(brush)
    870          dc.SetLogicalFunction(wx.XOR)
    871
    872          body_w,body_h = win.GetClientSizeTuple()
    873
    874          if y < 0:
    875                  y = 0
    876          if y > body_h:
    877                  y = body_h
    878          if x < 0:
    879                  x = 0
    880          if x > body_w:
    881                  x = body_w
    882
    883          if direction == MV_HOR:
    884                  x = 0
    885          else:
    886                  y = 0
    887
    888          x,y = win.ClientToScreenXY(x,y)
    889
    890          w = body_w
    891          h = body_h
    892
    893          if direction == MV_HOR:
    894                  dc.DrawRectangle(x,y-2,w,4)
    895          else:
    896                  dc.DrawRectangle(x-2,y,4,h)
    897
    898          dc.EndDrawingOnTop()
    899  #----------------------------------------------------------------------
    900