]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/lib/splitter.py
Tweaks for demos on MacOSX
[wxWidgets.git] / wxPython / wx / lib / splitter.py
1 #----------------------------------------------------------------------
2 # Name: wx.lib.splitter
3 # Purpose: A class similar to wx.SplitterWindow but that allows more
4 # a single split
5 #
6 # Author: Robin Dunn
7 #
8 # Created: 9-June-2005
9 # RCS-ID: $Id$
10 # Copyright: (c) 2005 by Total Control Software
11 # Licence: wxWindows license
12 #----------------------------------------------------------------------
13 """
14 This module provides the `MultiSplitterWindow` class, which is very
15 similar to the standard `wx.SplitterWindow` except it can be split
16 more than once.
17 """
18
19 import wx
20 import sys
21
22 _RENDER_VER = (2,6,1,1)
23
24 #----------------------------------------------------------------------
25
26 class MultiSplitterWindow(wx.PyPanel):
27 """
28 This class is very similar to `wx.SplitterWindow` except that it
29 allows for more than two windows and more than one sash. Many of
30 the same styles, constants, and methods behave the same as in
31 wx.SplitterWindow. The key differences are seen in the methods
32 that deal with the child windows managed by the splitter, and also
33 those that deal with the sash positions. In most cases you will
34 need to pass an index value to tell the class which window or sash
35 you are refering to.
36
37 The concept of the sash position is also different than in
38 wx.SplitterWindow. Since the wx.Splitterwindow has only one sash
39 you can think of it's position as either relative to the whole
40 splitter window, or as relative to the first window pane managed
41 by the splitter. Once there is more than one sash then the
42 distinciton between the two concepts needs to be clairified. I've
43 chosen to use the second definition, and sash positions are the
44 distance (either horizontally or vertically) from the origin of
45 the window just before the sash in the splitter stack.
46
47 NOTE: These things are not yet supported:
48
49 * Using negative sash positions to indicate a position offset
50 from the end.
51
52 * User controlled unsplitting (with double clicks on the sash
53 or dragging a sash until the pane size is zero.)
54
55 * Sash gravity
56
57 """
58 def __init__(self, parent, id=-1,
59 pos = wx.DefaultPosition, size = wx.DefaultSize,
60 style = 0, name="multiSplitter"):
61
62 # always turn on tab traversal
63 style |= wx.TAB_TRAVERSAL
64
65 # and turn off any border styles
66 style &= ~wx.BORDER_MASK
67 style |= wx.BORDER_NONE
68
69 # initialize the base class
70 wx.PyPanel.__init__(self, parent, id, pos, size, style, name)
71 self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
72
73 # initialize data members
74 self._windows = []
75 self._sashes = []
76 self._pending = {}
77 self._permitUnsplitAlways = self.HasFlag(wx.SP_PERMIT_UNSPLIT)
78 self._orient = wx.HORIZONTAL
79 self._dragMode = wx.SPLIT_DRAG_NONE
80 self._activeSash = -1
81 self._oldX = 0
82 self._oldY = 0
83 self._checkRequestedSashPosition = False
84 self._minimumPaneSize = 0
85 self._sashCursorWE = wx.StockCursor(wx.CURSOR_SIZEWE)
86 self._sashCursorNS = wx.StockCursor(wx.CURSOR_SIZENS)
87 self._sashTrackerPen = wx.Pen(wx.BLACK, 2, wx.SOLID)
88 self._needUpdating = False
89 self._isHot = False
90
91 # Bind event handlers
92 self.Bind(wx.EVT_PAINT, self._OnPaint)
93 self.Bind(wx.EVT_IDLE, self._OnIdle)
94 self.Bind(wx.EVT_SIZE, self._OnSize)
95 self.Bind(wx.EVT_MOUSE_EVENTS, self._OnMouse)
96
97
98
99 def SetOrientation(self, orient):
100 """
101 Set whether the windows managed by the splitter will be
102 stacked vertically or horizontally. The default is
103 horizontal.
104 """
105 assert orient in [ wx.VERTICAL, wx.HORIZONTAL ]
106 self._orient = orient
107
108 def GetOrientation(self):
109 """
110 Returns the current orientation of the splitter, either
111 wx.VERTICAL or wx.HORIZONTAL.
112 """
113 return self._orient
114
115
116 def SetMinimumPaneSize(self, minSize):
117 """
118 Set the smallest size that any pane will be allowed to be
119 resized to.
120 """
121 self._minimumPaneSize = minSize
122
123 def GetMinimumPaneSize(self):
124 """
125 Returns the smallest allowed size for a window pane.
126 """
127 return self._minimumPaneSize
128
129
130
131 def AppendWindow(self, window, sashPos=-1):
132 """
133 Add a new window to the splitter at the right side or bottom
134 of the window stack. If sashPos is given then it is used to
135 size the new window.
136 """
137 self.InsertWindow(sys.maxint, window, sashPos)
138
139
140 def InsertWindow(self, idx, window, sashPos=-1):
141 """
142 Insert a new window into the splitter at the position given in
143 ``idx``.
144 """
145 assert window not in self._windows, "A window can only be in the splitter once!"
146 self._windows.insert(idx, window)
147 self._sashes.insert(idx, -1)
148 if not window.IsShown():
149 window.Show()
150 if sashPos != -1:
151 self._pending[window] = sashPos
152 self._checkRequestedSashPosition = False
153 self._SizeWindows()
154
155
156 def DetachWindow(self, window):
157 """
158 Removes the window from the stack of windows managed by the
159 splitter. The window will still exist so you should `Hide` or
160 `Destroy` it as needed.
161 """
162 assert window in self._windows, "Unknown window!"
163 idx = self._windows.index(window)
164 del self._windows[idx]
165 del self._sashes[idx]
166 self._SizeWindows()
167
168
169 def ReplaceWindow(self, oldWindow, newWindow):
170 """
171 Replaces oldWindow (which is currently being managed by the
172 splitter) with newWindow. The oldWindow window will still
173 exist so you should `Hide` or `Destroy` it as needed.
174 """
175 assert oldWindow in self._windows, "Unknown window!"
176 idx = self._windows.index(oldWindow)
177 self._windows[idx] = newWindow
178 if not newWindow.IsShown():
179 newWindow.Show()
180 self._SizeWindows()
181
182
183 def ExchangeWindows(self, window1, window2):
184 """
185 Trade the positions in the splitter of the two windows.
186 """
187 assert window1 in self._windows, "Unknown window!"
188 assert window2 in self._windows, "Unknown window!"
189 idx1 = self._windows.index(window1)
190 idx2 = self._windows.index(window2)
191 self._windows[idx1] = window2
192 self._windows[idx2] = window1
193 self._SizeWindows()
194
195
196 def GetWindow(self, idx):
197 """
198 Returns the idx'th window being managed by the splitter.
199 """
200 assert idx < len(self._windows)
201 return self._windows[idx]
202
203
204 def GetSashPosition(self, idx):
205 """
206 Returns the position of the idx'th sash, measured from the
207 left/top of the window preceding the sash.
208 """
209 assert idx < len(self._sashes)
210 return self._sashes[idx]
211
212
213 def SizeWindows(self):
214 """
215 Reposition and size the windows managed by the splitter.
216 Useful when windows have been added/removed or when styles
217 have been changed.
218 """
219 self._SizeWindows()
220
221
222 def DoGetBestSize(self):
223 """
224 Overridden base class virtual. Determines the best size of
225 the control based on the best sizes of the child windows.
226 """
227 best = wx.Size(0,0)
228 if not self._windows:
229 best = wx.Size(10,10)
230
231 sashsize = self._GetSashSize()
232 if self._orient == wx.HORIZONTAL:
233 for win in self._windows:
234 winbest = win.GetAdjustedBestSize()
235 best.width += max(self._minimumPaneSize, winbest.width)
236 best.height = max(best.height, winbest.height)
237 best.width += sashsize * (len(self._windows)-1)
238
239 else:
240 for win in self._windows:
241 winbest = win.GetAdjustedBestSize()
242 best.height += max(self._minimumPaneSize, winbest.height)
243 best.width = max(best.width, winbest.width)
244 best.height += sashsize * (len(self._windows)-1)
245
246 border = 2 * self._GetBorderSize()
247 best.width += border
248 best.height += border
249 return best
250
251 # -------------------------------------
252 # Event handlers
253
254 def _OnPaint(self, evt):
255 dc = wx.PaintDC(self)
256 self._DrawSash(dc)
257
258
259 def _OnSize(self, evt):
260 parent = wx.GetTopLevelParent(self)
261 if parent.IsIconized():
262 evt.Skip()
263 return
264 self._SizeWindows()
265
266
267 def _OnIdle(self, evt):
268 evt.Skip()
269 # if this is the first idle time after a sash position has
270 # potentially been set, allow _SizeWindows to check for a
271 # requested size.
272 if not self._checkRequestedSashPosition:
273 self._checkRequestedSashPosition = True
274 self._SizeWindows()
275
276 if self._needUpdating:
277 self._SizeWindows()
278
279
280
281 def _OnMouse(self, evt):
282 if self.HasFlag(wx.SP_NOSASH):
283 return
284
285 x, y = evt.GetPosition()
286 isLive = self.HasFlag(wx.SP_LIVE_UPDATE)
287 adjustNeighbor = evt.ShiftDown()
288
289 # LeftDown: set things up for dragging the sash
290 if evt.LeftDown() and self._SashHitTest(x, y) != -1:
291 self._activeSash = self._SashHitTest(x, y)
292 self._dragMode = wx.SPLIT_DRAG_DRAGGING
293
294 self.CaptureMouse()
295 self._SetResizeCursor()
296
297 if not isLive:
298 self._pendingPos = (self._sashes[self._activeSash],
299 self._sashes[self._activeSash+1])
300 self._DrawSashTracker(x, y)
301
302 self._oldX = x
303 self._oldY = y
304 return
305
306 # LeftUp: Finsish the drag
307 elif evt.LeftUp() and self._dragMode == wx.SPLIT_DRAG_DRAGGING:
308 self._dragMode = wx.SPLIT_DRAG_NONE
309 self.ReleaseMouse()
310 self.SetCursor(wx.STANDARD_CURSOR)
311
312 if not isLive:
313 # erase the old tracker
314 self._DrawSashTracker(self._oldX, self._oldY)
315
316 diff = self._GetMotionDiff(x, y)
317
318 # determine if we can change the position
319 if isLive:
320 oldPos1, oldPos2 = (self._sashes[self._activeSash],
321 self._sashes[self._activeSash+1])
322 else:
323 oldPos1, oldPos2 = self._pendingPos
324 newPos1, newPos2 = self._OnSashPositionChanging(self._activeSash,
325 oldPos1 + diff,
326 oldPos2 - diff,
327 adjustNeighbor)
328 if newPos1 == -1:
329 # the change was not allowed
330 return
331
332 # TODO: check for unsplit?
333
334 self._SetSashPositionAndNotify(self._activeSash, newPos1, newPos2, adjustNeighbor)
335 self._activeSash = -1
336 self._pendingPos = (-1, -1)
337 self._SizeWindows()
338
339 # Entering or Leaving a sash: Change the cursor
340 elif (evt.Moving() or evt.Leaving() or evt.Entering()) and self._dragMode == wx.SPLIT_DRAG_NONE:
341 if evt.Leaving() or self._SashHitTest(x, y) == -1:
342 self._OnLeaveSash()
343 else:
344 self._OnEnterSash()
345
346 # Dragging the sash
347 elif evt.Dragging() and self._dragMode == wx.SPLIT_DRAG_DRAGGING:
348 diff = self._GetMotionDiff(x, y)
349 if not diff:
350 return # mouse didn't move far enough
351
352 # determine if we can change the position
353 if isLive:
354 oldPos1, oldPos2 = (self._sashes[self._activeSash],
355 self._sashes[self._activeSash+1])
356 else:
357 oldPos1, oldPos2 = self._pendingPos
358 newPos1, newPos2 = self._OnSashPositionChanging(self._activeSash,
359 oldPos1 + diff,
360 oldPos2 - diff,
361 adjustNeighbor)
362 if newPos1 == -1:
363 # the change was not allowed
364 return
365
366 if newPos1 == self._sashes[self._activeSash]:
367 return # nothing was changed
368
369 if not isLive:
370 # erase the old tracker
371 self._DrawSashTracker(self._oldX, self._oldY)
372
373 if self._orient == wx.HORIZONTAL:
374 x = self._SashToCoord(self._activeSash, newPos1)
375 else:
376 y = self._SashToCoord(self._activeSash, newPos1)
377
378 # Remember old positions
379 self._oldX = x
380 self._oldY = y
381
382 if not isLive:
383 # draw a new tracker
384 self._pendingPos = (newPos1, newPos2)
385 self._DrawSashTracker(self._oldX, self._oldY)
386 else:
387 self._DoSetSashPosition(self._activeSash, newPos1, newPos2, adjustNeighbor)
388 self._needUpdating = True
389
390
391 # -------------------------------------
392 # Internal helpers
393
394 def _RedrawIfHotSensitive(self, isHot):
395 if not wx.VERSION >= _RENDER_VER:
396 return
397 if wx.RendererNative.Get().GetSplitterParams(self).isHotSensitive:
398 self._isHot = isHot
399 dc = wx.ClientDC(self)
400 self._DrawSash(dc)
401
402
403 def _OnEnterSash(self):
404 self._SetResizeCursor()
405 self._RedrawIfHotSensitive(True)
406
407
408 def _OnLeaveSash(self):
409 self.SetCursor(wx.STANDARD_CURSOR)
410 self._RedrawIfHotSensitive(False)
411
412
413 def _SetResizeCursor(self):
414 if self._orient == wx.HORIZONTAL:
415 self.SetCursor(self._sashCursorWE)
416 else:
417 self.SetCursor(self._sashCursorNS)
418
419
420 def _OnSashPositionChanging(self, idx, newPos1, newPos2, adjustNeighbor):
421 # TODO: check for possibility of unsplit (pane size becomes zero)
422
423 # make sure that minsizes are honored
424 newPos1, newPos2 = self._AdjustSashPosition(idx, newPos1, newPos2, adjustNeighbor)
425
426 # sanity check
427 if newPos1 <= 0:
428 newPos2 += newPos1
429 newPos1 = 0
430
431 # send the events
432 evt = MultiSplitterEvent(
433 wx.wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGING, self)
434 evt.SetSashIdx(idx)
435 evt.SetSashPosition(newPos1)
436 if not self._DoSendEvent(evt):
437 # the event handler vetoed the change
438 newPos1 = -1
439 else:
440 # or it might have changed the value
441 newPos1 = evt.GetSashPosition()
442
443 if adjustNeighbor and newPos1 != -1:
444 evt.SetSashIdx(idx+1)
445 evt.SetSashPosition(newPos2)
446 if not self._DoSendEvent(evt):
447 # the event handler vetoed the change
448 newPos2 = -1
449 else:
450 # or it might have changed the value
451 newPos2 = evt.GetSashPosition()
452 if newPos2 == -1:
453 newPos1 = -1
454
455 return (newPos1, newPos2)
456
457
458 def _AdjustSashPosition(self, idx, newPos1, newPos2=-1, adjustNeighbor=False):
459 total = newPos1 + newPos2
460
461 # these are the windows on either side of the sash
462 win1 = self._windows[idx]
463 win2 = self._windows[idx+1]
464
465 # make adjustments for window min sizes
466 minSize = self._GetWindowMin(win1)
467 if minSize == -1 or self._minimumPaneSize > minSize:
468 minSize = self._minimumPaneSize
469 minSize += self._GetBorderSize()
470 if newPos1 < minSize:
471 newPos1 = minSize
472 newPos2 = total - newPos1
473
474 if adjustNeighbor:
475 minSize = self._GetWindowMin(win2)
476 if minSize == -1 or self._minimumPaneSize > minSize:
477 minSize = self._minimumPaneSize
478 minSize += self._GetBorderSize()
479 if newPos2 < minSize:
480 newPos2 = minSize
481 newPos1 = total - newPos2
482
483 return (newPos1, newPos2)
484
485
486 def _DoSetSashPosition(self, idx, newPos1, newPos2=-1, adjustNeighbor=False):
487 newPos1, newPos2 = self._AdjustSashPosition(idx, newPos1, newPos2, adjustNeighbor)
488 if newPos1 == self._sashes[idx]:
489 return False
490 self._sashes[idx] = newPos1
491 if adjustNeighbor:
492 self._sashes[idx+1] = newPos2
493 return True
494
495
496 def _SetSashPositionAndNotify(self, idx, newPos1, newPos2=-1, adjustNeighbor=False):
497 # TODO: what is the thing about _requestedSashPosition for?
498
499 self._DoSetSashPosition(idx, newPos1, newPos2, adjustNeighbor)
500
501 evt = MultiSplitterEvent(
502 wx.wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGED, self)
503 evt.SetSashIdx(idx)
504 evt.SetSashPosition(newPos1)
505 self._DoSendEvent(evt)
506
507 if adjustNeighbor:
508 evt.SetSashIdx(idx+1)
509 evt.SetSashPosition(newPos2)
510 self._DoSendEvent(evt)
511
512
513 def _GetMotionDiff(self, x, y):
514 # find the diff from the old pos
515 if self._orient == wx.HORIZONTAL:
516 diff = x - self._oldX
517 else:
518 diff = y - self._oldY
519 return diff
520
521
522 def _SashToCoord(self, idx, sashPos):
523 coord = 0
524 for i in range(idx):
525 coord += self._sashes[i]
526 coord += self._GetSashSize()
527 coord += sashPos
528 return coord
529
530
531 def _GetWindowMin(self, window):
532 if self._orient == wx.HORIZONTAL:
533 return window.GetMinWidth()
534 else:
535 return window.GetMinHeight()
536
537
538 def _GetSashSize(self):
539 if self.HasFlag(wx.SP_NOSASH):
540 return 0
541 if wx.VERSION >= _RENDER_VER:
542 return wx.RendererNative.Get().GetSplitterParams(self).widthSash
543 else:
544 return 5
545
546
547 def _GetBorderSize(self):
548 if wx.VERSION >= _RENDER_VER:
549 return wx.RendererNative.Get().GetSplitterParams(self).border
550 else:
551 return 0
552
553
554 def _DrawSash(self, dc):
555 if wx.VERSION >= _RENDER_VER:
556 if self.HasFlag(wx.SP_3DBORDER):
557 wx.RendererNative.Get().DrawSplitterBorder(
558 self, dc, self.GetClientRect())
559
560 # if there are no splits then we're done.
561 if len(self._windows) < 2:
562 return
563
564 # if we are not supposed to use a sash then we're done.
565 if self.HasFlag(wx.SP_NOSASH):
566 return
567
568 # Reverse the sense of the orientation, in this case it refers
569 # to the direction to draw the sash not the direction that
570 # windows are stacked.
571 orient = { wx.HORIZONTAL : wx.VERTICAL,
572 wx.VERTICAL : wx.HORIZONTAL }[self._orient]
573
574 flag = 0
575 if self._isHot:
576 flag = wx.CONTROL_CURRENT
577
578 pos = 0
579 for sash in self._sashes[:-1]:
580 pos += sash
581 if wx.VERSION >= _RENDER_VER:
582 wx.RendererNative.Get().DrawSplitterSash(self, dc,
583 self.GetClientSize(),
584 pos, orient, flag)
585 else:
586 dc.SetPen(wx.TRANSPARENT_PEN)
587 dc.SetBrush(wx.Brush(self.GetBackgroundColour()))
588 sashsize = self._GetSashSize()
589 if orient == wx.VERTICAL:
590 x = pos
591 y = 0
592 w = sashsize
593 h = self.GetClientSize().height
594 else:
595 x = 0
596 y = pos
597 w = self.GetClientSize().width
598 h = sashsize
599 dc.DrawRectangle(x, y, w, h)
600
601 pos += self._GetSashSize()
602
603
604 def _DrawSashTracker(self, x, y):
605 # Draw a line to represent the dragging sash, for when not
606 # doing live updates
607 w, h = self.GetClientSize()
608 dc = wx.ScreenDC()
609
610 if self._orient == wx.HORIZONTAL:
611 x1 = x
612 y1 = 2
613 x2 = x
614 y2 = h-2
615 if x1 > w:
616 x1 = w
617 x2 = w
618 elif x1 < 0:
619 x1 = 0
620 x2 = 0
621 else:
622 x1 = 2
623 y1 = y
624 x2 = w-2
625 y2 = y
626 if y1 > h:
627 y1 = h
628 y2 = h
629 elif y1 < 0:
630 y1 = 0
631 y2 = 0
632
633 x1, y1 = self.ClientToScreenXY(x1, y1)
634 x2, y2 = self.ClientToScreenXY(x2, y2)
635
636 dc.SetLogicalFunction(wx.INVERT)
637 dc.SetPen(self._sashTrackerPen)
638 dc.SetBrush(wx.TRANSPARENT_BRUSH)
639 dc.DrawLine(x1, y1, x2, y2)
640 dc.SetLogicalFunction(wx.COPY)
641
642
643 def _SashHitTest(self, x, y, tolerance=5):
644 # if there are no splits then we're done.
645 if len(self._windows) < 2:
646 return -1
647
648 if self._orient == wx.HORIZONTAL:
649 z = x
650 else:
651 z = y
652
653 pos = 0
654 for idx, sash in enumerate(self._sashes[:-1]):
655 pos += sash
656 hitMin = pos - tolerance
657 hitMax = pos + self._GetSashSize() + tolerance
658
659 if z >= hitMin and z <= hitMax:
660 return idx
661
662 pos += self._GetSashSize()
663
664 return -1
665
666
667 def _SizeWindows(self):
668 # no windows yet?
669 if not self._windows:
670 return
671
672 # are there any pending size settings?
673 for window, spos in self._pending.items():
674 idx = self._windows.index(window)
675 # TODO: this may need adjusted to make sure they all fit
676 # in the current client size
677 self._sashes[idx] = spos
678 del self._pending[window]
679
680 # are there any that still have a -1?
681 for idx, spos in enumerate(self._sashes[:-1]):
682 if spos == -1:
683 # TODO: this should also be adjusted
684 self._sashes[idx] = 100
685
686 cw, ch = self.GetClientSize()
687 border = self._GetBorderSize()
688 sash = self._GetSashSize()
689
690 if len(self._windows) == 1:
691 # there's only one, it's an easy layout
692 self._windows[0].SetDimensions(border, border,
693 cw - 2*border, ch - 2*border)
694 else:
695 if 'wxMSW' in wx.PlatformInfo:
696 self.Freeze()
697 if self._orient == wx.HORIZONTAL:
698 x = y = border
699 h = ch - 2*border
700 for idx, spos in enumerate(self._sashes[:-1]):
701 self._windows[idx].SetDimensions(x, y, spos, h)
702 x += spos + sash
703 # last one takes the rest of the space. TODO make this configurable
704 last = cw - 2*border - x
705 self._windows[idx+1].SetDimensions(x, y, last, h)
706 if last > 0:
707 self._sashes[idx+1] = last
708 else:
709 x = y = border
710 w = cw - 2*border
711 for idx, spos in enumerate(self._sashes[:-1]):
712 self._windows[idx].SetDimensions(x, y, w, spos)
713 y += spos + sash
714 # last one takes the rest of the space. TODO make this configurable
715 last = ch - 2*border - y
716 self._windows[idx+1].SetDimensions(x, y, w, last)
717 if last > 0:
718 self._sashes[idx+1] = last
719 if 'wxMSW' in wx.PlatformInfo:
720 self.Thaw()
721
722 self._DrawSash(wx.ClientDC(self))
723 self._needUpdating = False
724
725
726 def _DoSendEvent(self, evt):
727 return not self.GetEventHandler().ProcessEvent(evt) or evt.IsAllowed()
728
729 #----------------------------------------------------------------------
730
731 class MultiSplitterEvent(wx.PyCommandEvent):
732 """
733 This event class is almost the same as `wx.SplitterEvent` except
734 it adds an accessor for the sash index that is being changed. The
735 same event type IDs and event binders are used as with
736 `wx.SplitterEvent`.
737 """
738 def __init__(self, type=wx.wxEVT_NULL, splitter=None):
739 wx.PyCommandEvent.__init__(self, type)
740 if splitter:
741 self.SetEventObject(splitter)
742 self.SetId(splitter.GetId())
743 self.sashIdx = -1
744 self.sashPos = -1
745 self.isAllowed = True
746
747 def SetSashIdx(self, idx):
748 self.sashIdx = idx
749
750 def SetSashPosition(self, pos):
751 self.sashPos = pos
752
753 def GetSashIdx(self):
754 return self.sashIdx
755
756 def GetSashPosition(self):
757 return self.sashPos
758
759 # methods from wx.NotifyEvent
760 def Veto(self):
761 self.isAllowed = False
762 def Allow(self):
763 self.isAllowed = True
764 def IsAllowed(self):
765 return self.isAllowed
766
767
768
769 #----------------------------------------------------------------------
770
771
772