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