541 lines
18 KiB
Python
541 lines
18 KiB
Python
# DockingBar.py
|
|
|
|
# Ported directly (comments and all) from the samples at www.codeguru.com
|
|
|
|
# WARNING: Use at your own risk, as this interface is highly likely to change.
|
|
# Currently we support only one child per DockingBar. Later we need to add
|
|
# support for multiple children.
|
|
|
|
import win32api, win32con, win32ui
|
|
from pywin.mfc import afxres, window
|
|
import struct
|
|
|
|
clrBtnHilight = win32api.GetSysColor(win32con.COLOR_BTNHILIGHT)
|
|
clrBtnShadow = win32api.GetSysColor(win32con.COLOR_BTNSHADOW)
|
|
|
|
def CenterPoint(rect):
|
|
width = rect[2]-rect[0]
|
|
height = rect[3]-rect[1]
|
|
return rect[0] + width//2, rect[1] + height//2
|
|
|
|
def OffsetRect(rect, point):
|
|
(x, y) = point
|
|
return rect[0]+x, rect[1]+y, rect[2]+x, rect[3]+y
|
|
|
|
def DeflateRect(rect, point):
|
|
(x, y) = point
|
|
return rect[0]+x, rect[1]+y, rect[2]-x, rect[3]-y
|
|
|
|
def PtInRect(rect, pt):
|
|
return rect[0] <= pt[0] < rect[2] and rect[1] <= pt[1] < rect[3]
|
|
|
|
class DockingBar(window.Wnd):
|
|
def __init__(self, obj=None):
|
|
if obj is None:
|
|
obj = win32ui.CreateControlBar()
|
|
window.Wnd.__init__(self, obj)
|
|
self.dialog = None
|
|
self.nDockBarID = 0
|
|
self.sizeMin = 32, 32
|
|
self.sizeHorz = 200, 200
|
|
self.sizeVert = 200, 200
|
|
self.sizeFloat = 200, 200
|
|
self.bTracking = 0
|
|
self.bInRecalcNC = 0
|
|
self.cxEdge = 6
|
|
self.cxBorder = 3
|
|
self.cxGripper = 20
|
|
self.brushBkgd = win32ui.CreateBrush()
|
|
self.brushBkgd.CreateSolidBrush(win32api.GetSysColor(win32con.COLOR_BTNFACE))
|
|
|
|
# Support for diagonal resizing
|
|
self.cyBorder = 3
|
|
self.cCaptionSize = win32api.GetSystemMetrics(win32con.SM_CYSMCAPTION)
|
|
self.cMinWidth = win32api.GetSystemMetrics(win32con.SM_CXMIN)
|
|
self.cMinHeight = win32api.GetSystemMetrics(win32con.SM_CYMIN)
|
|
self.rectUndock = (0,0,0,0)
|
|
|
|
def OnUpdateCmdUI(self, target, bDisableIfNoHndler):
|
|
return self.UpdateDialogControls(target, bDisableIfNoHndler)
|
|
|
|
def CreateWindow(self, parent, childCreator, title, id, style=win32con.WS_CHILD | win32con.WS_VISIBLE | afxres.CBRS_LEFT, childCreatorArgs=()):
|
|
assert not ((style & afxres.CBRS_SIZE_FIXED) and (style & afxres.CBRS_SIZE_DYNAMIC)), "Invalid style"
|
|
self.rectClose = self.rectBorder = self.rectGripper = self.rectTracker = 0,0,0,0
|
|
|
|
# save the style
|
|
self._obj_.dwStyle = style & afxres.CBRS_ALL
|
|
|
|
cursor = win32api.LoadCursor(0, win32con.IDC_ARROW)
|
|
wndClass = win32ui.RegisterWndClass(win32con.CS_DBLCLKS, cursor, self.brushBkgd.GetSafeHandle(), 0)
|
|
|
|
self._obj_.CreateWindow(wndClass, title, style, (0,0,0,0), parent, id)
|
|
|
|
# Create the child dialog
|
|
self.dialog = childCreator(*(self,) + childCreatorArgs)
|
|
|
|
# use the dialog dimensions as default base dimensions
|
|
assert self.dialog.IsWindow(), "The childCreator function %s did not create a window!" % childCreator
|
|
rect = self.dialog.GetWindowRect()
|
|
self.sizeHorz = self.sizeVert = self.sizeFloat = rect[2]-rect[0], rect[3]-rect[1]
|
|
|
|
self.sizeHorz = self.sizeHorz[0], self.sizeHorz[1] + self.cxEdge + self.cxBorder
|
|
self.sizeVert = self.sizeVert[0] + self.cxEdge + self.cxBorder, self.sizeVert[1]
|
|
self.HookMessages()
|
|
|
|
def CalcFixedLayout(self, bStretch, bHorz):
|
|
rectTop = self.dockSite.GetControlBar(afxres.AFX_IDW_DOCKBAR_TOP).GetWindowRect()
|
|
rectLeft = self.dockSite.GetControlBar(afxres.AFX_IDW_DOCKBAR_LEFT).GetWindowRect()
|
|
if bStretch:
|
|
nHorzDockBarWidth = 32767
|
|
nVertDockBarHeight = 32767
|
|
else:
|
|
nHorzDockBarWidth = rectTop[2]-rectTop[0] + 4
|
|
nVertDockBarHeight = rectLeft[3]-rectLeft[1] + 4
|
|
|
|
if self.IsFloating():
|
|
return self.sizeFloat
|
|
if bHorz:
|
|
return nHorzDockBarWidth, self.sizeHorz[1]
|
|
return self.sizeVert[0], nVertDockBarHeight
|
|
|
|
def CalcDynamicLayout(self, length, mode):
|
|
# Support for diagonal sizing.
|
|
if self.IsFloating():
|
|
self.GetParent().GetParent().ModifyStyle(win32ui.MFS_4THICKFRAME, 0)
|
|
if mode & (win32ui.LM_HORZDOCK | win32ui.LM_VERTDOCK):
|
|
flags = win32con.SWP_NOSIZE | win32con.SWP_NOMOVE | win32con.SWP_NOZORDER |\
|
|
win32con.SWP_NOACTIVATE | win32con.SWP_FRAMECHANGED
|
|
self.SetWindowPos(0, (0, 0, 0, 0,), flags)
|
|
self.dockSite.RecalcLayout()
|
|
return self._obj_.CalcDynamicLayout(length, mode)
|
|
|
|
if mode & win32ui.LM_MRUWIDTH:
|
|
return self.sizeFloat
|
|
if mode & win32ui.LM_COMMIT:
|
|
self.sizeFloat = length, self.sizeFloat[1]
|
|
return self.sizeFloat
|
|
# More diagonal sizing.
|
|
if self.IsFloating():
|
|
dc = self.dockContext
|
|
pt = win32api.GetCursorPos()
|
|
windowRect = self.GetParent().GetParent().GetWindowRect()
|
|
|
|
hittest = dc.nHitTest
|
|
if hittest==win32con.HTTOPLEFT:
|
|
cx = max(windowRect[2] - pt[0], self.cMinWidth) - self.cxBorder
|
|
cy = max(windowRect[3] - self.cCaptionSize - pt[1],self.cMinHeight) - 1
|
|
self.sizeFloat = cx, cy
|
|
|
|
top = min(pt[1], windowRect[3] - self.cCaptionSize - self.cMinHeight) - self.cyBorder
|
|
left = min(pt[0], windowRect[2] - self.cMinWidth) - 1
|
|
dc.rectFrameDragHorz = left, top, dc.rectFrameDragHorz[2], dc.rectFrameDragHorz[3]
|
|
return self.sizeFloat
|
|
if hittest==win32con.HTTOPRIGHT:
|
|
cx = max(pt[0] - windowRect[0], self.cMinWidth)
|
|
cy = max(windowRect[3] - self.cCaptionSize - pt[1], self.cMinHeight) - 1
|
|
self.sizeFloat = cx, cy
|
|
|
|
top = min(pt[1], windowRect[3] - self.cCaptionSize - self.cMinHeight) - self.cyBorder
|
|
dc.rectFrameDragHorz = dc.rectFrameDragHorz[0], top, dc.rectFrameDragHorz[2], dc.rectFrameDragHorz[3]
|
|
return self.sizeFloat
|
|
|
|
if hittest==win32con.HTBOTTOMLEFT:
|
|
cx = max(windowRect[2] - pt[0], self.cMinWidth) - self.cxBorder
|
|
cy = max(pt[1] - windowRect[1] - self.cCaptionSize, self.cMinHeight)
|
|
self.sizeFloat = cx, cy
|
|
|
|
left = min(pt[0], windowRect[2] -self.cMinWidth) - 1
|
|
dc.rectFrameDragHorz = left, dc.rectFrameDragHorz[1], dc.rectFrameDragHorz[2], dc.rectFrameDragHorz[3]
|
|
return self.sizeFloat
|
|
|
|
if hittest==win32con.HTBOTTOMRIGHT:
|
|
cx = max(pt[0] - windowRect[0], self.cMinWidth)
|
|
cy = max(pt[1] - windowRect[1] - self.cCaptionSize, self.cMinHeight)
|
|
self.sizeFloat = cx, cy
|
|
return self.sizeFloat
|
|
|
|
if mode & win32ui.LM_LENGTHY:
|
|
self.sizeFloat = self.sizeFloat[0], max(self.sizeMin[1], length)
|
|
return self.sizeFloat
|
|
else:
|
|
return max(self.sizeMin[0], length), self.sizeFloat[1]
|
|
|
|
def OnWindowPosChanged(self, msg):
|
|
if self.GetSafeHwnd()==0 or self.dialog is None:
|
|
return 0
|
|
lparam = msg[3]
|
|
""" LPARAM used with WM_WINDOWPOSCHANGED:
|
|
typedef struct {
|
|
HWND hwnd;
|
|
HWND hwndInsertAfter;
|
|
int x;
|
|
int y;
|
|
int cx;
|
|
int cy;
|
|
UINT flags;} WINDOWPOS;
|
|
"""
|
|
format = "PPiiiii"
|
|
bytes = win32ui.GetBytes( lparam, struct.calcsize(format) )
|
|
hwnd, hwndAfter, x, y, cx, cy, flags = struct.unpack(format, bytes)
|
|
|
|
if self.bInRecalcNC:
|
|
rc = self.GetClientRect()
|
|
self.dialog.MoveWindow(rc)
|
|
return 0
|
|
# Find on which side are we docked
|
|
nDockBarID = self.GetParent().GetDlgCtrlID()
|
|
# Return if dropped at same location
|
|
# no docking side change and no size change
|
|
if (nDockBarID == self.nDockBarID) and \
|
|
(flags & win32con.SWP_NOSIZE) and \
|
|
((self._obj_.dwStyle & afxres.CBRS_BORDER_ANY) != afxres.CBRS_BORDER_ANY):
|
|
return
|
|
self.nDockBarID = nDockBarID
|
|
|
|
# Force recalc the non-client area
|
|
self.bInRecalcNC = 1
|
|
try:
|
|
swpflags = win32con.SWP_NOSIZE | win32con.SWP_NOMOVE | win32con.SWP_NOZORDER | win32con.SWP_FRAMECHANGED
|
|
self.SetWindowPos(0, (0,0,0,0), swpflags)
|
|
finally:
|
|
self.bInRecalcNC = 0
|
|
return 0
|
|
|
|
# This is a virtual and not a message hook.
|
|
def OnSetCursor(self, window, nHitTest, wMouseMsg):
|
|
if nHitTest != win32con.HTSIZE or self.bTracking:
|
|
return self._obj_.OnSetCursor(window, nHitTest, wMouseMsg)
|
|
|
|
if self.IsHorz():
|
|
win32api.SetCursor(win32api.LoadCursor(0, win32con.IDC_SIZENS))
|
|
else:
|
|
win32api.SetCursor(win32api.LoadCursor(0, win32con.IDC_SIZEWE))
|
|
return 1
|
|
|
|
# Mouse Handling
|
|
def OnLButtonUp(self, msg):
|
|
if not self.bTracking:
|
|
return 1 # pass it on.
|
|
self.StopTracking(1)
|
|
return 0 # Dont pass on
|
|
|
|
def OnLButtonDown(self, msg):
|
|
# UINT nFlags, CPoint point)
|
|
# only start dragging if clicked in "void" space
|
|
if self.dockBar is not None:
|
|
# start the drag
|
|
pt = msg[5]
|
|
pt = self.ClientToScreen(pt)
|
|
self.dockContext.StartDrag(pt)
|
|
return 0
|
|
return 1
|
|
|
|
def OnNcLButtonDown(self, msg):
|
|
if self.bTracking: return 0
|
|
nHitTest = wparam = msg[2]
|
|
pt = msg[5]
|
|
|
|
if nHitTest==win32con.HTSYSMENU and not self.IsFloating():
|
|
self.GetDockingFrame().ShowControlBar(self, 0, 0)
|
|
elif nHitTest == win32con.HTMINBUTTON and not self.IsFloating():
|
|
self.dockContext.ToggleDocking()
|
|
elif nHitTest == win32con.HTCAPTION and not self.IsFloating() and self.dockBar is not None:
|
|
self.dockContext.StartDrag(pt)
|
|
elif nHitTest == win32con.HTSIZE and not self.IsFloating():
|
|
self.StartTracking()
|
|
else:
|
|
return 1
|
|
return 0
|
|
|
|
def OnLButtonDblClk(self, msg):
|
|
# only toggle docking if clicked in "void" space
|
|
if self.dockBar is not None:
|
|
# toggle docking
|
|
self.dockContext.ToggleDocking()
|
|
return 0
|
|
return 1
|
|
|
|
def OnNcLButtonDblClk(self, msg):
|
|
nHitTest = wparam = msg[2]
|
|
# UINT nHitTest, CPoint point)
|
|
if self.dockBar is not None and nHitTest == win32con.HTCAPTION:
|
|
# toggle docking
|
|
self.dockContext.ToggleDocking()
|
|
return 0
|
|
return 1
|
|
|
|
def OnMouseMove(self, msg):
|
|
flags = wparam = msg[2]
|
|
lparam = msg[3]
|
|
if self.IsFloating() or not self.bTracking:
|
|
return 1
|
|
|
|
# Convert unsigned 16 bit to signed 32 bit.
|
|
x=win32api.LOWORD(lparam)
|
|
if x & 32768: x = x | -65536
|
|
y = win32api.HIWORD(lparam)
|
|
if y & 32768: y = y | -65536
|
|
pt = x, y
|
|
cpt = CenterPoint(self.rectTracker)
|
|
pt = self.ClientToWnd(pt)
|
|
if self.IsHorz():
|
|
if cpt[1] != pt[1]:
|
|
self.OnInvertTracker(self.rectTracker)
|
|
self.rectTracker = OffsetRect(self.rectTracker, (0, pt[1] - cpt[1]))
|
|
self.OnInvertTracker(self.rectTracker)
|
|
else:
|
|
if cpt[0] != pt[0]:
|
|
self.OnInvertTracker(self.rectTracker)
|
|
self.rectTracker = OffsetRect(self.rectTracker, (pt[0]-cpt[0], 0))
|
|
self.OnInvertTracker(self.rectTracker)
|
|
|
|
return 0 # Dont pass it on.
|
|
|
|
# def OnBarStyleChange(self, old, new):
|
|
|
|
def OnNcCalcSize(self, bCalcValid, size_info):
|
|
(rc0, rc1, rc2, pos) = size_info
|
|
self.rectBorder = self.GetWindowRect()
|
|
self.rectBorder = OffsetRect( self.rectBorder, (-self.rectBorder[0], -self.rectBorder[1]) )
|
|
|
|
dwBorderStyle = self._obj_.dwStyle | afxres.CBRS_BORDER_ANY
|
|
|
|
if self.nDockBarID==afxres.AFX_IDW_DOCKBAR_TOP:
|
|
dwBorderStyle = dwBorderStyle & ~afxres.CBRS_BORDER_BOTTOM;
|
|
rc0.left = rc0.left + self.cxGripper
|
|
rc0.bottom = rc0.bottom-self.cxEdge
|
|
rc0.top = rc0.top + self.cxBorder
|
|
rc0.right = rc0.right - self.cxBorder
|
|
self.rectBorder = self.rectBorder[0], self.rectBorder[3]-self.cxEdge, self.rectBorder[2], self.rectBorder[3]
|
|
elif self.nDockBarID==afxres.AFX_IDW_DOCKBAR_BOTTOM:
|
|
dwBorderStyle = dwBorderStyle & ~afxres.CBRS_BORDER_TOP
|
|
rc0.left = rc0.left + self.cxGripper
|
|
rc0.top = rc0.top + self.cxEdge
|
|
rc0.bottom = rc0.bottom - self.cxBorder
|
|
rc0.right = rc0.right - self.cxBorder
|
|
self.rectBorder = self.rectBorder[0], self.rectBorder[1], self.rectBorder[2], self.rectBorder[1]+self.cxEdge
|
|
elif self.nDockBarID==afxres.AFX_IDW_DOCKBAR_LEFT:
|
|
dwBorderStyle = dwBorderStyle & ~afxres.CBRS_BORDER_RIGHT
|
|
rc0.right = rc0.right - self.cxEdge
|
|
rc0.left = rc0.left + self.cxBorder
|
|
rc0.bottom = rc0.bottom - self.cxBorder
|
|
rc0.top = rc0.top + self.cxGripper
|
|
self.rectBorder = self.rectBorder[2] - self.cxEdge, self.rectBorder[1], self.rectBorder[2], self.rectBorder[3]
|
|
elif self.nDockBarID==afxres.AFX_IDW_DOCKBAR_RIGHT:
|
|
dwBorderStyle = dwBorderStyle & ~afxres.CBRS_BORDER_LEFT
|
|
rc0.left = rc0.left + self.cxEdge
|
|
rc0.right = rc0.right - self.cxBorder
|
|
rc0.bottom = rc0.bottom - self.cxBorder
|
|
rc0.top = rc0.top + self.cxGripper
|
|
self.rectBorder = self.rectBorder[0], self.rectBorder[1], self.rectBorder[0]+self.cxEdge, self.rectBorder[3]
|
|
else:
|
|
self.rectBorder = 0,0,0,0
|
|
|
|
self.SetBarStyle(dwBorderStyle)
|
|
return 0
|
|
|
|
def OnNcPaint(self, msg):
|
|
self.EraseNonClient()
|
|
dc = self.GetWindowDC()
|
|
ctl = win32api.GetSysColor(win32con.COLOR_BTNHIGHLIGHT)
|
|
cbr = win32api.GetSysColor(win32con.COLOR_BTNSHADOW)
|
|
dc.Draw3dRect(self.rectBorder, ctl, cbr)
|
|
|
|
self.DrawGripper(dc)
|
|
|
|
rect = self.GetClientRect()
|
|
self.InvalidateRect( rect, 1)
|
|
return 0
|
|
|
|
def OnNcHitTest(self, pt): # A virtual, not a hooked message.
|
|
if self.IsFloating():
|
|
return 1
|
|
|
|
ptOrig = pt
|
|
rect = self.GetWindowRect()
|
|
pt = pt[0] - rect[0], pt[1] - rect[1]
|
|
|
|
if PtInRect(self.rectClose, pt):
|
|
return win32con.HTSYSMENU
|
|
elif PtInRect(self.rectUndock, pt):
|
|
return win32con.HTMINBUTTON
|
|
elif PtInRect(self.rectGripper, pt):
|
|
return win32con.HTCAPTION
|
|
elif PtInRect(self.rectBorder, pt):
|
|
return win32con.HTSIZE
|
|
else:
|
|
return self._obj_.OnNcHitTest(ptOrig)
|
|
|
|
def StartTracking(self):
|
|
self.SetCapture()
|
|
|
|
# make sure no updates are pending
|
|
self.RedrawWindow(None, None, win32con.RDW_ALLCHILDREN | win32con.RDW_UPDATENOW)
|
|
self.dockSite.LockWindowUpdate()
|
|
|
|
self.ptOld = CenterPoint(self.rectBorder)
|
|
self.bTracking = 1
|
|
|
|
self.rectTracker = self.rectBorder;
|
|
if not self.IsHorz():
|
|
l, t, r, b = self.rectTracker
|
|
b = b - 4
|
|
self.rectTracker = l, t, r, b
|
|
|
|
self.OnInvertTracker(self.rectTracker);
|
|
|
|
def OnCaptureChanged(self, msg):
|
|
hwnd = lparam = msg[3]
|
|
if self.bTracking and hwnd != self.GetSafeHwnd():
|
|
self.StopTracking(0) # cancel tracking
|
|
return 1
|
|
|
|
def StopTracking(self, bAccept):
|
|
self.OnInvertTracker(self.rectTracker)
|
|
self.dockSite.UnlockWindowUpdate()
|
|
self.bTracking = 0
|
|
self.ReleaseCapture()
|
|
if not bAccept: return
|
|
|
|
rcc = self.dockSite.GetWindowRect()
|
|
if self.IsHorz():
|
|
newsize = self.sizeHorz[1]
|
|
maxsize = newsize + (rcc[3]-rcc[1])
|
|
minsize = self.sizeMin[1]
|
|
else:
|
|
newsize = self.sizeVert[0]
|
|
maxsize = newsize + (rcc[2]-rcc[0])
|
|
minsize = self.sizeMin[0]
|
|
|
|
pt = CenterPoint(self.rectTracker)
|
|
if self.nDockBarID== afxres.AFX_IDW_DOCKBAR_TOP:
|
|
newsize = newsize + (pt[1] - self.ptOld[1])
|
|
elif self.nDockBarID== afxres.AFX_IDW_DOCKBAR_BOTTOM:
|
|
newsize = newsize + (- pt[1] + self.ptOld[1])
|
|
elif self.nDockBarID== afxres.AFX_IDW_DOCKBAR_LEFT:
|
|
newsize = newsize + (pt[0] - self.ptOld[0])
|
|
elif self.nDockBarID== afxres.AFX_IDW_DOCKBAR_RIGHT:
|
|
newsize = newsize + (- pt[0] + self.ptOld[0])
|
|
newsize = max(minsize, min(maxsize, newsize))
|
|
if self.IsHorz():
|
|
self.sizeHorz = self.sizeHorz[0], newsize
|
|
else:
|
|
self.sizeVert = newsize, self.sizeVert[1]
|
|
self.dockSite.RecalcLayout()
|
|
return 0
|
|
|
|
def OnInvertTracker(self, rect):
|
|
assert rect[2]-rect[0]>0 and rect[3]-rect[1]>0, "rect is empty"
|
|
assert self.bTracking
|
|
rcc = self.GetWindowRect()
|
|
rcf = self.dockSite.GetWindowRect()
|
|
|
|
rect = OffsetRect(rect, (rcc[0] - rcf[0], rcc[1] - rcf[1]))
|
|
rect = DeflateRect(rect, (1, 1));
|
|
|
|
flags = win32con.DCX_WINDOW|win32con.DCX_CACHE|win32con.DCX_LOCKWINDOWUPDATE
|
|
dc = self.dockSite.GetDCEx(None, flags)
|
|
try:
|
|
brush = win32ui.GetHalftoneBrush()
|
|
oldBrush = dc.SelectObject(brush)
|
|
|
|
dc.PatBlt((rect[0], rect[1]), (rect[2]-rect[0], rect[3]-rect[1]), win32con.PATINVERT)
|
|
dc.SelectObject(oldBrush)
|
|
finally:
|
|
self.dockSite.ReleaseDC(dc)
|
|
|
|
def IsHorz(self):
|
|
return self.nDockBarID == afxres.AFX_IDW_DOCKBAR_TOP or \
|
|
self.nDockBarID == afxres.AFX_IDW_DOCKBAR_BOTTOM
|
|
|
|
def ClientToWnd(self, pt):
|
|
x, y=pt
|
|
if self.nDockBarID == afxres.AFX_IDW_DOCKBAR_BOTTOM:
|
|
y = y + self.cxEdge
|
|
elif self.nDockBarID == afxres.AFX_IDW_DOCKBAR_RIGHT:
|
|
x = x + self.cxEdge
|
|
return x,y
|
|
|
|
def DrawGripper(self, dc):
|
|
# no gripper if floating
|
|
if self._obj_.dwStyle & afxres.CBRS_FLOATING:
|
|
return
|
|
|
|
# -==HACK==-
|
|
# in order to calculate the client area properly after docking,
|
|
# the client area must be recalculated twice (I have no idea why)
|
|
self.dockSite.RecalcLayout()
|
|
# -==END HACK==-
|
|
|
|
gripper = self.GetWindowRect()
|
|
gripper = self.ScreenToClient( gripper )
|
|
gripper = OffsetRect( gripper, (-gripper[0], -gripper[1]) )
|
|
gl, gt, gr, gb = gripper
|
|
|
|
if self._obj_.dwStyle & afxres.CBRS_ORIENT_HORZ:
|
|
# gripper at left
|
|
self.rectGripper = gl, gt + 40, gl+20, gb
|
|
# draw close box
|
|
self.rectClose = gl+7, gt + 10, gl+19, gt+22
|
|
dc.DrawFrameControl(self.rectClose, win32con.DFC_CAPTION, win32con.DFCS_CAPTIONCLOSE)
|
|
# draw docking toggle box
|
|
self.rectUndock = OffsetRect(self.rectClose, (0,13))
|
|
dc.DrawFrameControl(self.rectUndock, win32con.DFC_CAPTION, win32con.DFCS_CAPTIONMAX);
|
|
|
|
gt = gt + 38
|
|
gb = gb - 10
|
|
gl = gl + 10
|
|
gr = gl + 3
|
|
gripper = gl, gt, gr, gb
|
|
dc.Draw3dRect( gripper, clrBtnHilight, clrBtnShadow )
|
|
dc.Draw3dRect( OffsetRect(gripper, (4,0)), clrBtnHilight, clrBtnShadow )
|
|
else:
|
|
# gripper at top
|
|
self.rectGripper = gl, gt, gr-40, gt+20
|
|
# draw close box
|
|
self.rectClose = gr-21, gt+7, gr-10, gt+18
|
|
dc.DrawFrameControl(self.rectClose, win32con.DFC_CAPTION, win32con.DFCS_CAPTIONCLOSE)
|
|
# draw docking toggle box
|
|
self.rectUndock = OffsetRect( self.rectClose, (-13,0) )
|
|
dc.DrawFrameControl(self.rectUndock, win32con.DFC_CAPTION, win32con.DFCS_CAPTIONMAX)
|
|
gr = gr - 38;
|
|
gl = gl + 10
|
|
gt = gt + 10
|
|
gb = gt + 3
|
|
|
|
gripper = gl, gt, gr, gb
|
|
dc.Draw3dRect( gripper, clrBtnHilight, clrBtnShadow )
|
|
dc.Draw3dRect( OffsetRect(gripper, (0,4) ), clrBtnHilight, clrBtnShadow )
|
|
|
|
def HookMessages(self):
|
|
self.HookMessage(self.OnLButtonUp, win32con.WM_LBUTTONUP)
|
|
self.HookMessage(self.OnLButtonDown, win32con.WM_LBUTTONDOWN)
|
|
self.HookMessage(self.OnLButtonDblClk, win32con.WM_LBUTTONDBLCLK)
|
|
self.HookMessage(self.OnNcLButtonDown, win32con.WM_NCLBUTTONDOWN)
|
|
self.HookMessage(self.OnNcLButtonDblClk, win32con.WM_NCLBUTTONDBLCLK)
|
|
self.HookMessage(self.OnMouseMove, win32con.WM_MOUSEMOVE)
|
|
self.HookMessage(self.OnNcPaint, win32con.WM_NCPAINT)
|
|
self.HookMessage(self.OnCaptureChanged, win32con.WM_CAPTURECHANGED)
|
|
self.HookMessage(self.OnWindowPosChanged, win32con.WM_WINDOWPOSCHANGED)
|
|
# self.HookMessage(self.OnSize, win32con.WM_SIZE)
|
|
|
|
def EditCreator(parent):
|
|
d = win32ui.CreateEdit()
|
|
es = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_BORDER | win32con.ES_MULTILINE | win32con.ES_WANTRETURN
|
|
d.CreateWindow( es, (0,0,150,150), parent, 1000)
|
|
return d
|
|
|
|
def test():
|
|
import pywin.mfc.dialog
|
|
global bar
|
|
bar = DockingBar()
|
|
creator = EditCreator
|
|
bar.CreateWindow(win32ui.GetMainFrame(), creator, "Coolbar Demo",0xfffff)
|
|
# win32ui.GetMainFrame().ShowControlBar(bar, 1, 0)
|
|
bar.SetBarStyle( bar.GetBarStyle()|afxres.CBRS_TOOLTIPS|afxres.CBRS_FLYBY|afxres.CBRS_SIZE_DYNAMIC)
|
|
bar.EnableDocking(afxres.CBRS_ALIGN_ANY)
|
|
win32ui.GetMainFrame().DockControlBar(bar, afxres.AFX_IDW_DOCKBAR_BOTTOM)
|
|
|
|
|
|
if __name__=='__main__':
|
|
test()
|