📄 splitter.py
字号:
# draw a new tracker
self._pendingPos = (newPos1, newPos2)
self._DrawSashTracker(self._oldX, self._oldY)
else:
self._DoSetSashPosition(self._activeSash, newPos1, newPos2, adjustNeighbor)
self._needUpdating = True
# -------------------------------------
# Internal helpers
def _RedrawIfHotSensitive(self, isHot):
if not wx.VERSION >= _RENDER_VER:
return
if wx.RendererNative.Get().GetSplitterParams(self).isHotSensitive:
self._isHot = isHot
dc = wx.ClientDC(self)
self._DrawSash(dc)
def _OnEnterSash(self):
self._SetResizeCursor()
self._RedrawIfHotSensitive(True)
def _OnLeaveSash(self):
self.SetCursor(wx.STANDARD_CURSOR)
self._RedrawIfHotSensitive(False)
def _SetResizeCursor(self):
if self._orient == wx.HORIZONTAL:
self.SetCursor(self._sashCursorWE)
else:
self.SetCursor(self._sashCursorNS)
def _OnSashPositionChanging(self, idx, newPos1, newPos2, adjustNeighbor):
# TODO: check for possibility of unsplit (pane size becomes zero)
# make sure that minsizes are honored
newPos1, newPos2 = self._AdjustSashPosition(idx, newPos1, newPos2, adjustNeighbor)
# sanity check
if newPos1 <= 0:
newPos2 += newPos1
newPos1 = 0
# send the events
evt = MultiSplitterEvent(
wx.wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGING, self)
evt.SetSashIdx(idx)
evt.SetSashPosition(newPos1)
if not self._DoSendEvent(evt):
# the event handler vetoed the change
newPos1 = -1
else:
# or it might have changed the value
newPos1 = evt.GetSashPosition()
if adjustNeighbor and newPos1 != -1:
evt.SetSashIdx(idx+1)
evt.SetSashPosition(newPos2)
if not self._DoSendEvent(evt):
# the event handler vetoed the change
newPos2 = -1
else:
# or it might have changed the value
newPos2 = evt.GetSashPosition()
if newPos2 == -1:
newPos1 = -1
return (newPos1, newPos2)
def _AdjustSashPosition(self, idx, newPos1, newPos2=-1, adjustNeighbor=False):
total = newPos1 + newPos2
# these are the windows on either side of the sash
win1 = self._windows[idx]
win2 = self._windows[idx+1]
# make adjustments for window min sizes
minSize = self._GetWindowMin(win1)
if minSize == -1 or self._minimumPaneSize > minSize:
minSize = self._minimumPaneSize
minSize += self._GetBorderSize()
if newPos1 < minSize:
newPos1 = minSize
newPos2 = total - newPos1
if adjustNeighbor:
minSize = self._GetWindowMin(win2)
if minSize == -1 or self._minimumPaneSize > minSize:
minSize = self._minimumPaneSize
minSize += self._GetBorderSize()
if newPos2 < minSize:
newPos2 = minSize
newPos1 = total - newPos2
return (newPos1, newPos2)
def _DoSetSashPosition(self, idx, newPos1, newPos2=-1, adjustNeighbor=False):
newPos1, newPos2 = self._AdjustSashPosition(idx, newPos1, newPos2, adjustNeighbor)
if newPos1 == self._sashes[idx]:
return False
self._sashes[idx] = newPos1
if adjustNeighbor:
self._sashes[idx+1] = newPos2
return True
def _SetSashPositionAndNotify(self, idx, newPos1, newPos2=-1, adjustNeighbor=False):
# TODO: what is the thing about _requestedSashPosition for?
self._DoSetSashPosition(idx, newPos1, newPos2, adjustNeighbor)
evt = MultiSplitterEvent(
wx.wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGED, self)
evt.SetSashIdx(idx)
evt.SetSashPosition(newPos1)
self._DoSendEvent(evt)
if adjustNeighbor:
evt.SetSashIdx(idx+1)
evt.SetSashPosition(newPos2)
self._DoSendEvent(evt)
def _GetMotionDiff(self, x, y):
# find the diff from the old pos
if self._orient == wx.HORIZONTAL:
diff = x - self._oldX
else:
diff = y - self._oldY
return diff
def _SashToCoord(self, idx, sashPos):
coord = 0
for i in range(idx):
coord += self._sashes[i]
coord += self._GetSashSize()
coord += sashPos
return coord
def _GetWindowMin(self, window):
if self._orient == wx.HORIZONTAL:
return window.GetMinWidth()
else:
return window.GetMinHeight()
def _GetSashSize(self):
if self.HasFlag(wx.SP_NOSASH):
return 0
if wx.VERSION >= _RENDER_VER:
return wx.RendererNative.Get().GetSplitterParams(self).widthSash
else:
return 5
def _GetBorderSize(self):
if wx.VERSION >= _RENDER_VER:
return wx.RendererNative.Get().GetSplitterParams(self).border
else:
return 0
def _DrawSash(self, dc):
if wx.VERSION >= _RENDER_VER:
if self.HasFlag(wx.SP_3DBORDER):
wx.RendererNative.Get().DrawSplitterBorder(
self, dc, self.GetClientRect())
# if there are no splits then we're done.
if len(self._windows) < 2:
return
# if we are not supposed to use a sash then we're done.
if self.HasFlag(wx.SP_NOSASH):
return
# Reverse the sense of the orientation, in this case it refers
# to the direction to draw the sash not the direction that
# windows are stacked.
orient = { wx.HORIZONTAL : wx.VERTICAL,
wx.VERTICAL : wx.HORIZONTAL }[self._orient]
flag = 0
if self._isHot:
flag = wx.CONTROL_CURRENT
pos = 0
for sash in self._sashes[:-1]:
pos += sash
if wx.VERSION >= _RENDER_VER:
wx.RendererNative.Get().DrawSplitterSash(self, dc,
self.GetClientSize(),
pos, orient, flag)
else:
dc.SetPen(wx.TRANSPARENT_PEN)
dc.SetBrush(wx.Brush(self.GetBackgroundColour()))
sashsize = self._GetSashSize()
if orient == wx.VERTICAL:
x = pos
y = 0
w = sashsize
h = self.GetClientSize().height
else:
x = 0
y = pos
w = self.GetClientSize().width
h = sashsize
dc.DrawRectangle(x, y, w, h)
pos += self._GetSashSize()
def _DrawSashTracker(self, x, y):
# Draw a line to represent the dragging sash, for when not
# doing live updates
w, h = self.GetClientSize()
dc = wx.ScreenDC()
if self._orient == wx.HORIZONTAL:
x1 = x
y1 = 2
x2 = x
y2 = h-2
if x1 > w:
x1 = w
x2 = w
elif x1 < 0:
x1 = 0
x2 = 0
else:
x1 = 2
y1 = y
x2 = w-2
y2 = y
if y1 > h:
y1 = h
y2 = h
elif y1 < 0:
y1 = 0
y2 = 0
x1, y1 = self.ClientToScreenXY(x1, y1)
x2, y2 = self.ClientToScreenXY(x2, y2)
dc.SetLogicalFunction(wx.INVERT)
dc.SetPen(self._sashTrackerPen)
dc.SetBrush(wx.TRANSPARENT_BRUSH)
dc.DrawLine(x1, y1, x2, y2)
dc.SetLogicalFunction(wx.COPY)
def _SashHitTest(self, x, y, tolerance=5):
# if there are no splits then we're done.
if len(self._windows) < 2:
return -1
if self._orient == wx.HORIZONTAL:
z = x
else:
z = y
pos = 0
for idx, sash in enumerate(self._sashes[:-1]):
pos += sash
hitMin = pos - tolerance
hitMax = pos + self._GetSashSize() + tolerance
if z >= hitMin and z <= hitMax:
return idx
pos += self._GetSashSize()
return -1
def _SizeWindows(self):
# no windows yet?
if not self._windows:
return
# are there any pending size settings?
for window, spos in self._pending.items():
idx = self._windows.index(window)
# TODO: this may need adjusted to make sure they all fit
# in the current client size
self._sashes[idx] = spos
del self._pending[window]
# are there any that still have a -1?
for idx, spos in enumerate(self._sashes[:-1]):
if spos == -1:
# TODO: this should also be adjusted
self._sashes[idx] = 100
cw, ch = self.GetClientSize()
border = self._GetBorderSize()
sash = self._GetSashSize()
if len(self._windows) == 1:
# there's only one, it's an easy layout
self._windows[0].SetDimensions(border, border,
cw - 2*border, ch - 2*border)
else:
if 'wxMSW' in wx.PlatformInfo:
self.Freeze()
if self._orient == wx.HORIZONTAL:
x = y = border
h = ch - 2*border
for idx, spos in enumerate(self._sashes[:-1]):
self._windows[idx].SetDimensions(x, y, spos, h)
x += spos + sash
# last one takes the rest of the space. TODO make this configurable
last = cw - 2*border - x
self._windows[idx+1].SetDimensions(x, y, last, h)
if last > 0:
self._sashes[idx+1] = last
else:
x = y = border
w = cw - 2*border
for idx, spos in enumerate(self._sashes[:-1]):
self._windows[idx].SetDimensions(x, y, w, spos)
y += spos + sash
# last one takes the rest of the space. TODO make this configurable
last = ch - 2*border - y
self._windows[idx+1].SetDimensions(x, y, w, last)
if last > 0:
self._sashes[idx+1] = last
if 'wxMSW' in wx.PlatformInfo:
self.Thaw()
self._DrawSash(wx.ClientDC(self))
self._needUpdating = False
def _DoSendEvent(self, evt):
return not self.GetEventHandler().ProcessEvent(evt) or evt.IsAllowed()
#----------------------------------------------------------------------
class MultiSplitterEvent(wx.PyCommandEvent):
"""
This event class is almost the same as `wx.SplitterEvent` except
it adds an accessor for the sash index that is being changed. The
same event type IDs and event binders are used as with
`wx.SplitterEvent`.
"""
def __init__(self, type=wx.wxEVT_NULL, splitter=None):
wx.PyCommandEvent.__init__(self, type)
if splitter:
self.SetEventObject(splitter)
self.SetId(splitter.GetId())
self.sashIdx = -1
self.sashPos = -1
self.isAllowed = True
def SetSashIdx(self, idx):
self.sashIdx = idx
def SetSashPosition(self, pos):
self.sashPos = pos
def GetSashIdx(self):
return self.sashIdx
def GetSashPosition(self):
return self.sashPos
# methods from wx.NotifyEvent
def Veto(self):
self.isAllowed = False
def Allow(self):
self.isAllowed = True
def IsAllowed(self):
return self.isAllowed
#----------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -