DockingBar.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. # DockingBar.py
  2. # Ported directly (comments and all) from the samples at www.codeguru.com
  3. # WARNING: Use at your own risk, as this interface is highly likely to change.
  4. # Currently we support only one child per DockingBar. Later we need to add
  5. # support for multiple children.
  6. import win32api, win32con, win32ui
  7. from pywin.mfc import afxres, window
  8. import struct
  9. clrBtnHilight = win32api.GetSysColor(win32con.COLOR_BTNHILIGHT)
  10. clrBtnShadow = win32api.GetSysColor(win32con.COLOR_BTNSHADOW)
  11. def CenterPoint(rect):
  12. width = rect[2]-rect[0]
  13. height = rect[3]-rect[1]
  14. return rect[0] + width//2, rect[1] + height//2
  15. def OffsetRect(rect, point):
  16. (x, y) = point
  17. return rect[0]+x, rect[1]+y, rect[2]+x, rect[3]+y
  18. def DeflateRect(rect, point):
  19. (x, y) = point
  20. return rect[0]+x, rect[1]+y, rect[2]-x, rect[3]-y
  21. def PtInRect(rect, pt):
  22. return rect[0] <= pt[0] < rect[2] and rect[1] <= pt[1] < rect[3]
  23. class DockingBar(window.Wnd):
  24. def __init__(self, obj=None):
  25. if obj is None:
  26. obj = win32ui.CreateControlBar()
  27. window.Wnd.__init__(self, obj)
  28. self.dialog = None
  29. self.nDockBarID = 0
  30. self.sizeMin = 32, 32
  31. self.sizeHorz = 200, 200
  32. self.sizeVert = 200, 200
  33. self.sizeFloat = 200, 200
  34. self.bTracking = 0
  35. self.bInRecalcNC = 0
  36. self.cxEdge = 6
  37. self.cxBorder = 3
  38. self.cxGripper = 20
  39. self.brushBkgd = win32ui.CreateBrush()
  40. self.brushBkgd.CreateSolidBrush(win32api.GetSysColor(win32con.COLOR_BTNFACE))
  41. # Support for diagonal resizing
  42. self.cyBorder = 3
  43. self.cCaptionSize = win32api.GetSystemMetrics(win32con.SM_CYSMCAPTION)
  44. self.cMinWidth = win32api.GetSystemMetrics(win32con.SM_CXMIN)
  45. self.cMinHeight = win32api.GetSystemMetrics(win32con.SM_CYMIN)
  46. self.rectUndock = (0,0,0,0)
  47. def OnUpdateCmdUI(self, target, bDisableIfNoHndler):
  48. return self.UpdateDialogControls(target, bDisableIfNoHndler)
  49. def CreateWindow(self, parent, childCreator, title, id, style=win32con.WS_CHILD | win32con.WS_VISIBLE | afxres.CBRS_LEFT, childCreatorArgs=()):
  50. assert not ((style & afxres.CBRS_SIZE_FIXED) and (style & afxres.CBRS_SIZE_DYNAMIC)), "Invalid style"
  51. self.rectClose = self.rectBorder = self.rectGripper = self.rectTracker = 0,0,0,0
  52. # save the style
  53. self._obj_.dwStyle = style & afxres.CBRS_ALL
  54. cursor = win32api.LoadCursor(0, win32con.IDC_ARROW)
  55. wndClass = win32ui.RegisterWndClass(win32con.CS_DBLCLKS, cursor, self.brushBkgd.GetSafeHandle(), 0)
  56. self._obj_.CreateWindow(wndClass, title, style, (0,0,0,0), parent, id)
  57. # Create the child dialog
  58. self.dialog = childCreator(*(self,) + childCreatorArgs)
  59. # use the dialog dimensions as default base dimensions
  60. assert self.dialog.IsWindow(), "The childCreator function %s did not create a window!" % childCreator
  61. rect = self.dialog.GetWindowRect()
  62. self.sizeHorz = self.sizeVert = self.sizeFloat = rect[2]-rect[0], rect[3]-rect[1]
  63. self.sizeHorz = self.sizeHorz[0], self.sizeHorz[1] + self.cxEdge + self.cxBorder
  64. self.sizeVert = self.sizeVert[0] + self.cxEdge + self.cxBorder, self.sizeVert[1]
  65. self.HookMessages()
  66. def CalcFixedLayout(self, bStretch, bHorz):
  67. rectTop = self.dockSite.GetControlBar(afxres.AFX_IDW_DOCKBAR_TOP).GetWindowRect()
  68. rectLeft = self.dockSite.GetControlBar(afxres.AFX_IDW_DOCKBAR_LEFT).GetWindowRect()
  69. if bStretch:
  70. nHorzDockBarWidth = 32767
  71. nVertDockBarHeight = 32767
  72. else:
  73. nHorzDockBarWidth = rectTop[2]-rectTop[0] + 4
  74. nVertDockBarHeight = rectLeft[3]-rectLeft[1] + 4
  75. if self.IsFloating():
  76. return self.sizeFloat
  77. if bHorz:
  78. return nHorzDockBarWidth, self.sizeHorz[1]
  79. return self.sizeVert[0], nVertDockBarHeight
  80. def CalcDynamicLayout(self, length, mode):
  81. # Support for diagonal sizing.
  82. if self.IsFloating():
  83. self.GetParent().GetParent().ModifyStyle(win32ui.MFS_4THICKFRAME, 0)
  84. if mode & (win32ui.LM_HORZDOCK | win32ui.LM_VERTDOCK):
  85. flags = win32con.SWP_NOSIZE | win32con.SWP_NOMOVE | win32con.SWP_NOZORDER |\
  86. win32con.SWP_NOACTIVATE | win32con.SWP_FRAMECHANGED
  87. self.SetWindowPos(0, (0, 0, 0, 0,), flags)
  88. self.dockSite.RecalcLayout()
  89. return self._obj_.CalcDynamicLayout(length, mode)
  90. if mode & win32ui.LM_MRUWIDTH:
  91. return self.sizeFloat
  92. if mode & win32ui.LM_COMMIT:
  93. self.sizeFloat = length, self.sizeFloat[1]
  94. return self.sizeFloat
  95. # More diagonal sizing.
  96. if self.IsFloating():
  97. dc = self.dockContext
  98. pt = win32api.GetCursorPos()
  99. windowRect = self.GetParent().GetParent().GetWindowRect()
  100. hittest = dc.nHitTest
  101. if hittest==win32con.HTTOPLEFT:
  102. cx = max(windowRect[2] - pt[0], self.cMinWidth) - self.cxBorder
  103. cy = max(windowRect[3] - self.cCaptionSize - pt[1],self.cMinHeight) - 1
  104. self.sizeFloat = cx, cy
  105. top = min(pt[1], windowRect[3] - self.cCaptionSize - self.cMinHeight) - self.cyBorder
  106. left = min(pt[0], windowRect[2] - self.cMinWidth) - 1
  107. dc.rectFrameDragHorz = left, top, dc.rectFrameDragHorz[2], dc.rectFrameDragHorz[3]
  108. return self.sizeFloat
  109. if hittest==win32con.HTTOPRIGHT:
  110. cx = max(pt[0] - windowRect[0], self.cMinWidth)
  111. cy = max(windowRect[3] - self.cCaptionSize - pt[1], self.cMinHeight) - 1
  112. self.sizeFloat = cx, cy
  113. top = min(pt[1], windowRect[3] - self.cCaptionSize - self.cMinHeight) - self.cyBorder
  114. dc.rectFrameDragHorz = dc.rectFrameDragHorz[0], top, dc.rectFrameDragHorz[2], dc.rectFrameDragHorz[3]
  115. return self.sizeFloat
  116. if hittest==win32con.HTBOTTOMLEFT:
  117. cx = max(windowRect[2] - pt[0], self.cMinWidth) - self.cxBorder
  118. cy = max(pt[1] - windowRect[1] - self.cCaptionSize, self.cMinHeight)
  119. self.sizeFloat = cx, cy
  120. left = min(pt[0], windowRect[2] -self.cMinWidth) - 1
  121. dc.rectFrameDragHorz = left, dc.rectFrameDragHorz[1], dc.rectFrameDragHorz[2], dc.rectFrameDragHorz[3]
  122. return self.sizeFloat
  123. if hittest==win32con.HTBOTTOMRIGHT:
  124. cx = max(pt[0] - windowRect[0], self.cMinWidth)
  125. cy = max(pt[1] - windowRect[1] - self.cCaptionSize, self.cMinHeight)
  126. self.sizeFloat = cx, cy
  127. return self.sizeFloat
  128. if mode & win32ui.LM_LENGTHY:
  129. self.sizeFloat = self.sizeFloat[0], max(self.sizeMin[1], length)
  130. return self.sizeFloat
  131. else:
  132. return max(self.sizeMin[0], length), self.sizeFloat[1]
  133. def OnWindowPosChanged(self, msg):
  134. if self.GetSafeHwnd()==0 or self.dialog is None:
  135. return 0
  136. lparam = msg[3]
  137. """ LPARAM used with WM_WINDOWPOSCHANGED:
  138. typedef struct {
  139. HWND hwnd;
  140. HWND hwndInsertAfter;
  141. int x;
  142. int y;
  143. int cx;
  144. int cy;
  145. UINT flags;} WINDOWPOS;
  146. """
  147. format = "PPiiiii"
  148. bytes = win32ui.GetBytes( lparam, struct.calcsize(format) )
  149. hwnd, hwndAfter, x, y, cx, cy, flags = struct.unpack(format, bytes)
  150. if self.bInRecalcNC:
  151. rc = self.GetClientRect()
  152. self.dialog.MoveWindow(rc)
  153. return 0
  154. # Find on which side are we docked
  155. nDockBarID = self.GetParent().GetDlgCtrlID()
  156. # Return if dropped at same location
  157. # no docking side change and no size change
  158. if (nDockBarID == self.nDockBarID) and \
  159. (flags & win32con.SWP_NOSIZE) and \
  160. ((self._obj_.dwStyle & afxres.CBRS_BORDER_ANY) != afxres.CBRS_BORDER_ANY):
  161. return
  162. self.nDockBarID = nDockBarID
  163. # Force recalc the non-client area
  164. self.bInRecalcNC = 1
  165. try:
  166. swpflags = win32con.SWP_NOSIZE | win32con.SWP_NOMOVE | win32con.SWP_NOZORDER | win32con.SWP_FRAMECHANGED
  167. self.SetWindowPos(0, (0,0,0,0), swpflags)
  168. finally:
  169. self.bInRecalcNC = 0
  170. return 0
  171. # This is a virtual and not a message hook.
  172. def OnSetCursor(self, window, nHitTest, wMouseMsg):
  173. if nHitTest != win32con.HTSIZE or self.bTracking:
  174. return self._obj_.OnSetCursor(window, nHitTest, wMouseMsg)
  175. if self.IsHorz():
  176. win32api.SetCursor(win32api.LoadCursor(0, win32con.IDC_SIZENS))
  177. else:
  178. win32api.SetCursor(win32api.LoadCursor(0, win32con.IDC_SIZEWE))
  179. return 1
  180. # Mouse Handling
  181. def OnLButtonUp(self, msg):
  182. if not self.bTracking:
  183. return 1 # pass it on.
  184. self.StopTracking(1)
  185. return 0 # Dont pass on
  186. def OnLButtonDown(self, msg):
  187. # UINT nFlags, CPoint point)
  188. # only start dragging if clicked in "void" space
  189. if self.dockBar is not None:
  190. # start the drag
  191. pt = msg[5]
  192. pt = self.ClientToScreen(pt)
  193. self.dockContext.StartDrag(pt)
  194. return 0
  195. return 1
  196. def OnNcLButtonDown(self, msg):
  197. if self.bTracking: return 0
  198. nHitTest = wparam = msg[2]
  199. pt = msg[5]
  200. if nHitTest==win32con.HTSYSMENU and not self.IsFloating():
  201. self.GetDockingFrame().ShowControlBar(self, 0, 0)
  202. elif nHitTest == win32con.HTMINBUTTON and not self.IsFloating():
  203. self.dockContext.ToggleDocking()
  204. elif nHitTest == win32con.HTCAPTION and not self.IsFloating() and self.dockBar is not None:
  205. self.dockContext.StartDrag(pt)
  206. elif nHitTest == win32con.HTSIZE and not self.IsFloating():
  207. self.StartTracking()
  208. else:
  209. return 1
  210. return 0
  211. def OnLButtonDblClk(self, msg):
  212. # only toggle docking if clicked in "void" space
  213. if self.dockBar is not None:
  214. # toggle docking
  215. self.dockContext.ToggleDocking()
  216. return 0
  217. return 1
  218. def OnNcLButtonDblClk(self, msg):
  219. nHitTest = wparam = msg[2]
  220. # UINT nHitTest, CPoint point)
  221. if self.dockBar is not None and nHitTest == win32con.HTCAPTION:
  222. # toggle docking
  223. self.dockContext.ToggleDocking()
  224. return 0
  225. return 1
  226. def OnMouseMove(self, msg):
  227. flags = wparam = msg[2]
  228. lparam = msg[3]
  229. if self.IsFloating() or not self.bTracking:
  230. return 1
  231. # Convert unsigned 16 bit to signed 32 bit.
  232. x=win32api.LOWORD(lparam)
  233. if x & 32768: x = x | -65536
  234. y = win32api.HIWORD(lparam)
  235. if y & 32768: y = y | -65536
  236. pt = x, y
  237. cpt = CenterPoint(self.rectTracker)
  238. pt = self.ClientToWnd(pt)
  239. if self.IsHorz():
  240. if cpt[1] != pt[1]:
  241. self.OnInvertTracker(self.rectTracker)
  242. self.rectTracker = OffsetRect(self.rectTracker, (0, pt[1] - cpt[1]))
  243. self.OnInvertTracker(self.rectTracker)
  244. else:
  245. if cpt[0] != pt[0]:
  246. self.OnInvertTracker(self.rectTracker)
  247. self.rectTracker = OffsetRect(self.rectTracker, (pt[0]-cpt[0], 0))
  248. self.OnInvertTracker(self.rectTracker)
  249. return 0 # Dont pass it on.
  250. # def OnBarStyleChange(self, old, new):
  251. def OnNcCalcSize(self, bCalcValid, size_info):
  252. (rc0, rc1, rc2, pos) = size_info
  253. self.rectBorder = self.GetWindowRect()
  254. self.rectBorder = OffsetRect( self.rectBorder, (-self.rectBorder[0], -self.rectBorder[1]) )
  255. dwBorderStyle = self._obj_.dwStyle | afxres.CBRS_BORDER_ANY
  256. if self.nDockBarID==afxres.AFX_IDW_DOCKBAR_TOP:
  257. dwBorderStyle = dwBorderStyle & ~afxres.CBRS_BORDER_BOTTOM;
  258. rc0.left = rc0.left + self.cxGripper
  259. rc0.bottom = rc0.bottom-self.cxEdge
  260. rc0.top = rc0.top + self.cxBorder
  261. rc0.right = rc0.right - self.cxBorder
  262. self.rectBorder = self.rectBorder[0], self.rectBorder[3]-self.cxEdge, self.rectBorder[2], self.rectBorder[3]
  263. elif self.nDockBarID==afxres.AFX_IDW_DOCKBAR_BOTTOM:
  264. dwBorderStyle = dwBorderStyle & ~afxres.CBRS_BORDER_TOP
  265. rc0.left = rc0.left + self.cxGripper
  266. rc0.top = rc0.top + self.cxEdge
  267. rc0.bottom = rc0.bottom - self.cxBorder
  268. rc0.right = rc0.right - self.cxBorder
  269. self.rectBorder = self.rectBorder[0], self.rectBorder[1], self.rectBorder[2], self.rectBorder[1]+self.cxEdge
  270. elif self.nDockBarID==afxres.AFX_IDW_DOCKBAR_LEFT:
  271. dwBorderStyle = dwBorderStyle & ~afxres.CBRS_BORDER_RIGHT
  272. rc0.right = rc0.right - self.cxEdge
  273. rc0.left = rc0.left + self.cxBorder
  274. rc0.bottom = rc0.bottom - self.cxBorder
  275. rc0.top = rc0.top + self.cxGripper
  276. self.rectBorder = self.rectBorder[2] - self.cxEdge, self.rectBorder[1], self.rectBorder[2], self.rectBorder[3]
  277. elif self.nDockBarID==afxres.AFX_IDW_DOCKBAR_RIGHT:
  278. dwBorderStyle = dwBorderStyle & ~afxres.CBRS_BORDER_LEFT
  279. rc0.left = rc0.left + self.cxEdge
  280. rc0.right = rc0.right - self.cxBorder
  281. rc0.bottom = rc0.bottom - self.cxBorder
  282. rc0.top = rc0.top + self.cxGripper
  283. self.rectBorder = self.rectBorder[0], self.rectBorder[1], self.rectBorder[0]+self.cxEdge, self.rectBorder[3]
  284. else:
  285. self.rectBorder = 0,0,0,0
  286. self.SetBarStyle(dwBorderStyle)
  287. return 0
  288. def OnNcPaint(self, msg):
  289. self.EraseNonClient()
  290. dc = self.GetWindowDC()
  291. ctl = win32api.GetSysColor(win32con.COLOR_BTNHIGHLIGHT)
  292. cbr = win32api.GetSysColor(win32con.COLOR_BTNSHADOW)
  293. dc.Draw3dRect(self.rectBorder, ctl, cbr)
  294. self.DrawGripper(dc)
  295. rect = self.GetClientRect()
  296. self.InvalidateRect( rect, 1)
  297. return 0
  298. def OnNcHitTest(self, pt): # A virtual, not a hooked message.
  299. if self.IsFloating():
  300. return 1
  301. ptOrig = pt
  302. rect = self.GetWindowRect()
  303. pt = pt[0] - rect[0], pt[1] - rect[1]
  304. if PtInRect(self.rectClose, pt):
  305. return win32con.HTSYSMENU
  306. elif PtInRect(self.rectUndock, pt):
  307. return win32con.HTMINBUTTON
  308. elif PtInRect(self.rectGripper, pt):
  309. return win32con.HTCAPTION
  310. elif PtInRect(self.rectBorder, pt):
  311. return win32con.HTSIZE
  312. else:
  313. return self._obj_.OnNcHitTest(ptOrig)
  314. def StartTracking(self):
  315. self.SetCapture()
  316. # make sure no updates are pending
  317. self.RedrawWindow(None, None, win32con.RDW_ALLCHILDREN | win32con.RDW_UPDATENOW)
  318. self.dockSite.LockWindowUpdate()
  319. self.ptOld = CenterPoint(self.rectBorder)
  320. self.bTracking = 1
  321. self.rectTracker = self.rectBorder;
  322. if not self.IsHorz():
  323. l, t, r, b = self.rectTracker
  324. b = b - 4
  325. self.rectTracker = l, t, r, b
  326. self.OnInvertTracker(self.rectTracker);
  327. def OnCaptureChanged(self, msg):
  328. hwnd = lparam = msg[3]
  329. if self.bTracking and hwnd != self.GetSafeHwnd():
  330. self.StopTracking(0) # cancel tracking
  331. return 1
  332. def StopTracking(self, bAccept):
  333. self.OnInvertTracker(self.rectTracker)
  334. self.dockSite.UnlockWindowUpdate()
  335. self.bTracking = 0
  336. self.ReleaseCapture()
  337. if not bAccept: return
  338. rcc = self.dockSite.GetWindowRect()
  339. if self.IsHorz():
  340. newsize = self.sizeHorz[1]
  341. maxsize = newsize + (rcc[3]-rcc[1])
  342. minsize = self.sizeMin[1]
  343. else:
  344. newsize = self.sizeVert[0]
  345. maxsize = newsize + (rcc[2]-rcc[0])
  346. minsize = self.sizeMin[0]
  347. pt = CenterPoint(self.rectTracker)
  348. if self.nDockBarID== afxres.AFX_IDW_DOCKBAR_TOP:
  349. newsize = newsize + (pt[1] - self.ptOld[1])
  350. elif self.nDockBarID== afxres.AFX_IDW_DOCKBAR_BOTTOM:
  351. newsize = newsize + (- pt[1] + self.ptOld[1])
  352. elif self.nDockBarID== afxres.AFX_IDW_DOCKBAR_LEFT:
  353. newsize = newsize + (pt[0] - self.ptOld[0])
  354. elif self.nDockBarID== afxres.AFX_IDW_DOCKBAR_RIGHT:
  355. newsize = newsize + (- pt[0] + self.ptOld[0])
  356. newsize = max(minsize, min(maxsize, newsize))
  357. if self.IsHorz():
  358. self.sizeHorz = self.sizeHorz[0], newsize
  359. else:
  360. self.sizeVert = newsize, self.sizeVert[1]
  361. self.dockSite.RecalcLayout()
  362. return 0
  363. def OnInvertTracker(self, rect):
  364. assert rect[2]-rect[0]>0 and rect[3]-rect[1]>0, "rect is empty"
  365. assert self.bTracking
  366. rcc = self.GetWindowRect()
  367. rcf = self.dockSite.GetWindowRect()
  368. rect = OffsetRect(rect, (rcc[0] - rcf[0], rcc[1] - rcf[1]))
  369. rect = DeflateRect(rect, (1, 1));
  370. flags = win32con.DCX_WINDOW|win32con.DCX_CACHE|win32con.DCX_LOCKWINDOWUPDATE
  371. dc = self.dockSite.GetDCEx(None, flags)
  372. try:
  373. brush = win32ui.GetHalftoneBrush()
  374. oldBrush = dc.SelectObject(brush)
  375. dc.PatBlt((rect[0], rect[1]), (rect[2]-rect[0], rect[3]-rect[1]), win32con.PATINVERT)
  376. dc.SelectObject(oldBrush)
  377. finally:
  378. self.dockSite.ReleaseDC(dc)
  379. def IsHorz(self):
  380. return self.nDockBarID == afxres.AFX_IDW_DOCKBAR_TOP or \
  381. self.nDockBarID == afxres.AFX_IDW_DOCKBAR_BOTTOM
  382. def ClientToWnd(self, pt):
  383. x, y=pt
  384. if self.nDockBarID == afxres.AFX_IDW_DOCKBAR_BOTTOM:
  385. y = y + self.cxEdge
  386. elif self.nDockBarID == afxres.AFX_IDW_DOCKBAR_RIGHT:
  387. x = x + self.cxEdge
  388. return x,y
  389. def DrawGripper(self, dc):
  390. # no gripper if floating
  391. if self._obj_.dwStyle & afxres.CBRS_FLOATING:
  392. return
  393. # -==HACK==-
  394. # in order to calculate the client area properly after docking,
  395. # the client area must be recalculated twice (I have no idea why)
  396. self.dockSite.RecalcLayout()
  397. # -==END HACK==-
  398. gripper = self.GetWindowRect()
  399. gripper = self.ScreenToClient( gripper )
  400. gripper = OffsetRect( gripper, (-gripper[0], -gripper[1]) )
  401. gl, gt, gr, gb = gripper
  402. if self._obj_.dwStyle & afxres.CBRS_ORIENT_HORZ:
  403. # gripper at left
  404. self.rectGripper = gl, gt + 40, gl+20, gb
  405. # draw close box
  406. self.rectClose = gl+7, gt + 10, gl+19, gt+22
  407. dc.DrawFrameControl(self.rectClose, win32con.DFC_CAPTION, win32con.DFCS_CAPTIONCLOSE)
  408. # draw docking toggle box
  409. self.rectUndock = OffsetRect(self.rectClose, (0,13))
  410. dc.DrawFrameControl(self.rectUndock, win32con.DFC_CAPTION, win32con.DFCS_CAPTIONMAX);
  411. gt = gt + 38
  412. gb = gb - 10
  413. gl = gl + 10
  414. gr = gl + 3
  415. gripper = gl, gt, gr, gb
  416. dc.Draw3dRect( gripper, clrBtnHilight, clrBtnShadow )
  417. dc.Draw3dRect( OffsetRect(gripper, (4,0)), clrBtnHilight, clrBtnShadow )
  418. else:
  419. # gripper at top
  420. self.rectGripper = gl, gt, gr-40, gt+20
  421. # draw close box
  422. self.rectClose = gr-21, gt+7, gr-10, gt+18
  423. dc.DrawFrameControl(self.rectClose, win32con.DFC_CAPTION, win32con.DFCS_CAPTIONCLOSE)
  424. # draw docking toggle box
  425. self.rectUndock = OffsetRect( self.rectClose, (-13,0) )
  426. dc.DrawFrameControl(self.rectUndock, win32con.DFC_CAPTION, win32con.DFCS_CAPTIONMAX)
  427. gr = gr - 38;
  428. gl = gl + 10
  429. gt = gt + 10
  430. gb = gt + 3
  431. gripper = gl, gt, gr, gb
  432. dc.Draw3dRect( gripper, clrBtnHilight, clrBtnShadow )
  433. dc.Draw3dRect( OffsetRect(gripper, (0,4) ), clrBtnHilight, clrBtnShadow )
  434. def HookMessages(self):
  435. self.HookMessage(self.OnLButtonUp, win32con.WM_LBUTTONUP)
  436. self.HookMessage(self.OnLButtonDown, win32con.WM_LBUTTONDOWN)
  437. self.HookMessage(self.OnLButtonDblClk, win32con.WM_LBUTTONDBLCLK)
  438. self.HookMessage(self.OnNcLButtonDown, win32con.WM_NCLBUTTONDOWN)
  439. self.HookMessage(self.OnNcLButtonDblClk, win32con.WM_NCLBUTTONDBLCLK)
  440. self.HookMessage(self.OnMouseMove, win32con.WM_MOUSEMOVE)
  441. self.HookMessage(self.OnNcPaint, win32con.WM_NCPAINT)
  442. self.HookMessage(self.OnCaptureChanged, win32con.WM_CAPTURECHANGED)
  443. self.HookMessage(self.OnWindowPosChanged, win32con.WM_WINDOWPOSCHANGED)
  444. # self.HookMessage(self.OnSize, win32con.WM_SIZE)
  445. def EditCreator(parent):
  446. d = win32ui.CreateEdit()
  447. es = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_BORDER | win32con.ES_MULTILINE | win32con.ES_WANTRETURN
  448. d.CreateWindow( es, (0,0,150,150), parent, 1000)
  449. return d
  450. def test():
  451. import pywin.mfc.dialog
  452. global bar
  453. bar = DockingBar()
  454. creator = EditCreator
  455. bar.CreateWindow(win32ui.GetMainFrame(), creator, "Coolbar Demo",0xfffff)
  456. # win32ui.GetMainFrame().ShowControlBar(bar, 1, 0)
  457. bar.SetBarStyle( bar.GetBarStyle()|afxres.CBRS_TOOLTIPS|afxres.CBRS_FLYBY|afxres.CBRS_SIZE_DYNAMIC)
  458. bar.EnableDocking(afxres.CBRS_ALIGN_ANY)
  459. win32ui.GetMainFrame().DockControlBar(bar, afxres.AFX_IDW_DOCKBAR_BOTTOM)
  460. if __name__=='__main__':
  461. test()