]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/lib/splitter.py
fixed wxVsnprintf() to write as much as it can if the output buffer is too short
[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 SetSashPosition(self, idx, pos):
213 """
214 Set the psition of the idx'th sash, measured from the left/top
215 of the window preceding the sash.
216 """
217 assert idx < len(self._sashes)
218 self._sashes[idx] = pos
219 self._SizeWindows()
220
221
222 def SizeWindows(self):
223 """
224 Reposition and size the windows managed by the splitter.
225 Useful when windows have been added/removed or when styles
226 have been changed.
227 """
228 self._SizeWindows()
229
230
231 def DoGetBestSize(self):
232 """
233 Overridden base class virtual. Determines the best size of
234 the control based on the best sizes of the child windows.
235 """
236 best = wx.Size(0,0)
237 if not self._windows:
238 best = wx.Size(10,10)
239
240 sashsize = self._GetSashSize()
241 if self._orient == wx.HORIZONTAL:
242 for win in self._windows:
243 winbest = win.GetEffectiveMinSize()
244 best.width += max(self._minimumPaneSize, winbest.width)
245 best.height = max(best.height, winbest.height)
246 best.width += sashsize * (len(self._windows)-1)
247
248 else:
249 for win in self._windows:
250 winbest = win.GetEffectiveMinSize()
251 best.height += max(self._minimumPaneSize, winbest.height)
252 best.width = max(best.width, winbest.width)
253 best.height += sashsize * (len(self._windows)-1)
254
255 border = 2 * self._GetBorderSize()
256 best.width += border
257 best.height += border
258 return best
259
260 # -------------------------------------
261 # Event handlers
262
263 def _OnPaint(self, evt):
264 dc = wx.PaintDC(self)
265 self._DrawSash(dc)
266
267
268 def _OnSize(self, evt):
269 parent = wx.GetTopLevelParent(self)
270 if parent.IsIconized():
271 evt.Skip()
272 return
273 self._SizeWindows()
274
275
276 def _OnIdle(self, evt):
277 evt.Skip()
278 # if this is the first idle time after a sash position has
279 # potentially been set, allow _SizeWindows to check for a
280 # requested size.
281 if not self._checkRequestedSashPosition:
282 self._checkRequestedSashPosition = True
283 self._SizeWindows()
284
285 if self._needUpdating:
286 self._SizeWindows()
287
288
289
290 def _OnMouse(self, evt):
291 if self.HasFlag(wx.SP_NOSASH):
292 return
293
294 x, y = evt.GetPosition()
295 isLive = self.HasFlag(wx.SP_LIVE_UPDATE)
296 adjustNeighbor = evt.ShiftDown()
297
298 # LeftDown: set things up for dragging the sash
299 if evt.LeftDown() and self._SashHitTest(x, y) != -1:
300 self._activeSash = self._SashHitTest(x, y)
301 self._dragMode = wx.SPLIT_DRAG_DRAGGING
302
303 self.CaptureMouse()
304 self._SetResizeCursor()
305
306 if not isLive:
307 self._pendingPos = (self._sashes[self._activeSash],
308 self._sashes[self._activeSash+1])
309 self._DrawSashTracker(x, y)
310
311 self._oldX = x
312 self._oldY = y
313 return
314
315 # LeftUp: Finsish the drag
316 elif evt.LeftUp() and self._dragMode == wx.SPLIT_DRAG_DRAGGING:
317 self._dragMode = wx.SPLIT_DRAG_NONE
318 self.ReleaseMouse()
319 self.SetCursor(wx.STANDARD_CURSOR)
320
321 if not isLive:
322 # erase the old tracker
323 self._DrawSashTracker(self._oldX, self._oldY)
324
325 diff = self._GetMotionDiff(x, y)
326
327 # determine if we can change the position
328 if isLive:
329 oldPos1, oldPos2 = (self._sashes[self._activeSash],
330 self._sashes[self._activeSash+1])
331 else:
332 oldPos1, oldPos2 = self._pendingPos
333 newPos1, newPos2 = self._OnSashPositionChanging(self._activeSash,
334 oldPos1 + diff,
335 oldPos2 - diff,
336 adjustNeighbor)
337 if newPos1 == -1:
338 # the change was not allowed
339 return
340
341 # TODO: check for unsplit?
342
343 self._SetSashPositionAndNotify(self._activeSash, newPos1, newPos2, adjustNeighbor)
344 self._activeSash = -1
345 self._pendingPos = (-1, -1)
346 self._SizeWindows()
347
348 # Entering or Leaving a sash: Change the cursor
349 elif (evt.Moving() or evt.Leaving() or evt.Entering()) and self._dragMode == wx.SPLIT_DRAG_NONE:
350 if evt.Leaving() or self._SashHitTest(x, y) == -1:
351 self._OnLeaveSash()
352 else:
353 self._OnEnterSash()
354
355 # Dragging the sash
356 elif evt.Dragging() and self._dragMode == wx.SPLIT_DRAG_DRAGGING:
357 diff = self._GetMotionDiff(x, y)
358 if not diff:
359 return # mouse didn't move far enough
360
361 # determine if we can change the position
362 if isLive:
363 oldPos1, oldPos2 = (self._sashes[self._activeSash],
364 self._sashes[self._activeSash+1])
365 else:
366 oldPos1, oldPos2 = self._pendingPos
367 newPos1, newPos2 = self._OnSashPositionChanging(self._activeSash,
368 oldPos1 + diff,
369 oldPos2 - diff,
370 adjustNeighbor)
371 if newPos1 == -1:
372 # the change was not allowed
373 return
374
375 if newPos1 == self._sashes[self._activeSash]:
376 return # nothing was changed
377
378 if not isLive:
379 # erase the old tracker
380 self._DrawSashTracker(self._oldX, self._oldY)
381
382 if self._orient == wx.HORIZONTAL:
383 x = self._SashToCoord(self._activeSash, newPos1)
384 else:
385 y = self._SashToCoord(self._activeSash, newPos1)
386
387 # Remember old positions
388 self._oldX = x
389 self._oldY = y
390
391 if not isLive:
392 # draw a new tracker
393 self._pendingPos = (newPos1, newPos2)
394 self._DrawSashTracker(self._oldX, self._oldY)
395 else:
396 self._DoSetSashPosition(self._activeSash, newPos1, newPos2, adjustNeighbor)
397 self._needUpdating = True
398
399
400 # -------------------------------------
401 # Internal helpers
402
403 def _RedrawIfHotSensitive(self, isHot):
404 if not wx.VERSION >= _RENDER_VER:
405 return
406 if wx.RendererNative.Get().GetSplitterParams(self).isHotSensitive:
407 self._isHot = isHot
408 dc = wx.ClientDC(self)
409 self._DrawSash(dc)
410
411
412 def _OnEnterSash(self):
413 self._SetResizeCursor()
414 self._RedrawIfHotSensitive(True)
415
416
417 def _OnLeaveSash(self):
418 self.SetCursor(wx.STANDARD_CURSOR)
419 self._RedrawIfHotSensitive(False)
420
421
422 def _SetResizeCursor(self):
423 if self._orient == wx.HORIZONTAL:
424 self.SetCursor(self._sashCursorWE)
425 else:
426 self.SetCursor(self._sashCursorNS)
427
428
429 def _OnSashPositionChanging(self, idx, newPos1, newPos2, adjustNeighbor):
430 # TODO: check for possibility of unsplit (pane size becomes zero)
431
432 # make sure that minsizes are honored
433 newPos1, newPos2 = self._AdjustSashPosition(idx, newPos1, newPos2, adjustNeighbor)
434
435 # sanity check
436 if newPos1 <= 0:
437 newPos2 += newPos1
438 newPos1 = 0
439
440 # send the events
441 evt = MultiSplitterEvent(
442 wx.wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGING, self)
443 evt.SetSashIdx(idx)
444 evt.SetSashPosition(newPos1)
445 if not self._DoSendEvent(evt):
446 # the event handler vetoed the change
447 newPos1 = -1
448 else:
449 # or it might have changed the value
450 newPos1 = evt.GetSashPosition()
451
452 if adjustNeighbor and newPos1 != -1:
453 evt.SetSashIdx(idx+1)
454 evt.SetSashPosition(newPos2)
455 if not self._DoSendEvent(evt):
456 # the event handler vetoed the change
457 newPos2 = -1
458 else:
459 # or it might have changed the value
460 newPos2 = evt.GetSashPosition()
461 if newPos2 == -1:
462 newPos1 = -1
463
464 return (newPos1, newPos2)
465
466
467 def _AdjustSashPosition(self, idx, newPos1, newPos2=-1, adjustNeighbor=False):
468 total = newPos1 + newPos2
469
470 # these are the windows on either side of the sash
471 win1 = self._windows[idx]
472 win2 = self._windows[idx+1]
473
474 # make adjustments for window min sizes
475 minSize = self._GetWindowMin(win1)
476 if minSize == -1 or self._minimumPaneSize > minSize:
477 minSize = self._minimumPaneSize
478 minSize += self._GetBorderSize()
479 if newPos1 < minSize:
480 newPos1 = minSize
481 newPos2 = total - newPos1
482
483 if adjustNeighbor:
484 minSize = self._GetWindowMin(win2)
485 if minSize == -1 or self._minimumPaneSize > minSize:
486 minSize = self._minimumPaneSize
487 minSize += self._GetBorderSize()
488 if newPos2 < minSize:
489 newPos2 = minSize
490 newPos1 = total - newPos2
491
492 return (newPos1, newPos2)
493
494
495 def _DoSetSashPosition(self, idx, newPos1, newPos2=-1, adjustNeighbor=False):
496 newPos1, newPos2 = self._AdjustSashPosition(idx, newPos1, newPos2, adjustNeighbor)
497 if newPos1 == self._sashes[idx]:
498 return False
499 self._sashes[idx] = newPos1
500 if adjustNeighbor:
501 self._sashes[idx+1] = newPos2
502 return True
503
504
505 def _SetSashPositionAndNotify(self, idx, newPos1, newPos2=-1, adjustNeighbor=False):
506 # TODO: what is the thing about _requestedSashPosition for?
507
508 self._DoSetSashPosition(idx, newPos1, newPos2, adjustNeighbor)
509
510 evt = MultiSplitterEvent(
511 wx.wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGED, self)
512 evt.SetSashIdx(idx)
513 evt.SetSashPosition(newPos1)
514 self._DoSendEvent(evt)
515
516 if adjustNeighbor:
517 evt.SetSashIdx(idx+1)
518 evt.SetSashPosition(newPos2)
519 self._DoSendEvent(evt)
520
521
522 def _GetMotionDiff(self, x, y):
523 # find the diff from the old pos
524 if self._orient == wx.HORIZONTAL:
525 diff = x - self._oldX
526 else:
527 diff = y - self._oldY
528 return diff
529
530
531 def _SashToCoord(self, idx, sashPos):
532 coord = 0
533 for i in range(idx):
534 coord += self._sashes[i]
535 coord += self._GetSashSize()
536 coord += sashPos
537 return coord
538
539
540 def _GetWindowMin(self, window):
541 if self._orient == wx.HORIZONTAL:
542 return window.GetMinWidth()
543 else:
544 return window.GetMinHeight()
545
546
547 def _GetSashSize(self):
548 if self.HasFlag(wx.SP_NOSASH):
549 return 0
550 if wx.VERSION >= _RENDER_VER:
551 return wx.RendererNative.Get().GetSplitterParams(self).widthSash
552 else:
553 return 5
554
555
556 def _GetBorderSize(self):
557 if wx.VERSION >= _RENDER_VER:
558 return wx.RendererNative.Get().GetSplitterParams(self).border
559 else:
560 return 0
561
562
563 def _DrawSash(self, dc):
564 if wx.VERSION >= _RENDER_VER:
565 if self.HasFlag(wx.SP_3DBORDER):
566 wx.RendererNative.Get().DrawSplitterBorder(
567 self, dc, self.GetClientRect())
568
569 # if there are no splits then we're done.
570 if len(self._windows) < 2:
571 return
572
573 # if we are not supposed to use a sash then we're done.
574 if self.HasFlag(wx.SP_NOSASH):
575 return
576
577 # Reverse the sense of the orientation, in this case it refers
578 # to the direction to draw the sash not the direction that
579 # windows are stacked.
580 orient = { wx.HORIZONTAL : wx.VERTICAL,
581 wx.VERTICAL : wx.HORIZONTAL }[self._orient]
582
583 flag = 0
584 if self._isHot:
585 flag = wx.CONTROL_CURRENT
586
587 pos = 0
588 for sash in self._sashes[:-1]:
589 pos += sash
590 if wx.VERSION >= _RENDER_VER:
591 wx.RendererNative.Get().DrawSplitterSash(self, dc,
592 self.GetClientSize(),
593 pos, orient, flag)
594 else:
595 dc.SetPen(wx.TRANSPARENT_PEN)
596 dc.SetBrush(wx.Brush(self.GetBackgroundColour()))
597 sashsize = self._GetSashSize()
598 if orient == wx.VERTICAL:
599 x = pos
600 y = 0
601 w = sashsize
602 h = self.GetClientSize().height
603 else:
604 x = 0
605 y = pos
606 w = self.GetClientSize().width
607 h = sashsize
608 dc.DrawRectangle(x, y, w, h)
609
610 pos += self._GetSashSize()
611
612
613 def _DrawSashTracker(self, x, y):
614 # Draw a line to represent the dragging sash, for when not
615 # doing live updates
616 w, h = self.GetClientSize()
617 dc = wx.ScreenDC()
618
619 if self._orient == wx.HORIZONTAL:
620 x1 = x
621 y1 = 2
622 x2 = x
623 y2 = h-2
624 if x1 > w:
625 x1 = w
626 x2 = w
627 elif x1 < 0:
628 x1 = 0
629 x2 = 0
630 else:
631 x1 = 2
632 y1 = y
633 x2 = w-2
634 y2 = y
635 if y1 > h:
636 y1 = h
637 y2 = h
638 elif y1 < 0:
639 y1 = 0
640 y2 = 0
641
642 x1, y1 = self.ClientToScreenXY(x1, y1)
643 x2, y2 = self.ClientToScreenXY(x2, y2)
644
645 dc.SetLogicalFunction(wx.INVERT)
646 dc.SetPen(self._sashTrackerPen)
647 dc.SetBrush(wx.TRANSPARENT_BRUSH)
648 dc.DrawLine(x1, y1, x2, y2)
649 dc.SetLogicalFunction(wx.COPY)
650
651
652 def _SashHitTest(self, x, y, tolerance=5):
653 # if there are no splits then we're done.
654 if len(self._windows) < 2:
655 return -1
656
657 if self._orient == wx.HORIZONTAL:
658 z = x
659 else:
660 z = y
661
662 pos = 0
663 for idx, sash in enumerate(self._sashes[:-1]):
664 pos += sash
665 hitMin = pos - tolerance
666 hitMax = pos + self._GetSashSize() + tolerance
667
668 if z >= hitMin and z <= hitMax:
669 return idx
670
671 pos += self._GetSashSize()
672
673 return -1
674
675
676 def _SizeWindows(self):
677 # no windows yet?
678 if not self._windows:
679 return
680
681 # are there any pending size settings?
682 for window, spos in self._pending.items():
683 idx = self._windows.index(window)
684 # TODO: this may need adjusted to make sure they all fit
685 # in the current client size
686 self._sashes[idx] = spos
687 del self._pending[window]
688
689 # are there any that still have a -1?
690 for idx, spos in enumerate(self._sashes[:-1]):
691 if spos == -1:
692 # TODO: this should also be adjusted
693 self._sashes[idx] = 100
694
695 cw, ch = self.GetClientSize()
696 border = self._GetBorderSize()
697 sash = self._GetSashSize()
698
699 if len(self._windows) == 1:
700 # there's only one, it's an easy layout
701 self._windows[0].SetDimensions(border, border,
702 cw - 2*border, ch - 2*border)
703 else:
704 if 'wxMSW' in wx.PlatformInfo:
705 self.Freeze()
706 if self._orient == wx.HORIZONTAL:
707 x = y = border
708 h = ch - 2*border
709 for idx, spos in enumerate(self._sashes[:-1]):
710 self._windows[idx].SetDimensions(x, y, spos, h)
711 x += spos + sash
712 # last one takes the rest of the space. TODO make this configurable
713 last = cw - 2*border - x
714 self._windows[idx+1].SetDimensions(x, y, last, h)
715 if last > 0:
716 self._sashes[idx+1] = last
717 else:
718 x = y = border
719 w = cw - 2*border
720 for idx, spos in enumerate(self._sashes[:-1]):
721 self._windows[idx].SetDimensions(x, y, w, spos)
722 y += spos + sash
723 # last one takes the rest of the space. TODO make this configurable
724 last = ch - 2*border - y
725 self._windows[idx+1].SetDimensions(x, y, w, last)
726 if last > 0:
727 self._sashes[idx+1] = last
728 if 'wxMSW' in wx.PlatformInfo:
729 self.Thaw()
730
731 self._DrawSash(wx.ClientDC(self))
732 self._needUpdating = False
733
734
735 def _DoSendEvent(self, evt):
736 return not self.GetEventHandler().ProcessEvent(evt) or evt.IsAllowed()
737
738 #----------------------------------------------------------------------
739
740 class MultiSplitterEvent(wx.PyCommandEvent):
741 """
742 This event class is almost the same as `wx.SplitterEvent` except
743 it adds an accessor for the sash index that is being changed. The
744 same event type IDs and event binders are used as with
745 `wx.SplitterEvent`.
746 """
747 def __init__(self, type=wx.wxEVT_NULL, splitter=None):
748 wx.PyCommandEvent.__init__(self, type)
749 if splitter:
750 self.SetEventObject(splitter)
751 self.SetId(splitter.GetId())
752 self.sashIdx = -1
753 self.sashPos = -1
754 self.isAllowed = True
755
756 def SetSashIdx(self, idx):
757 self.sashIdx = idx
758
759 def SetSashPosition(self, pos):
760 self.sashPos = pos
761
762 def GetSashIdx(self):
763 return self.sashIdx
764
765 def GetSashPosition(self):
766 return self.sashPos
767
768 # methods from wx.NotifyEvent
769 def Veto(self):
770 self.isAllowed = False
771 def Allow(self):
772 self.isAllowed = True
773 def IsAllowed(self):
774 return self.isAllowed
775
776
777
778 #----------------------------------------------------------------------
779
780
781