# 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 struct

import win32api
import win32con
import win32ui
from pywin.mfc import afxres, window

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  # Don't 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 |= -65536
        y = win32api.HIWORD(lparam)
        if y & 32768:
            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  # Don't 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 &= ~afxres.CBRS_BORDER_BOTTOM
            rc0.left += self.cxGripper
            rc0.bottom -= self.cxEdge
            rc0.top += self.cxBorder
            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 &= ~afxres.CBRS_BORDER_TOP
            rc0.left += self.cxGripper
            rc0.top += self.cxEdge
            rc0.bottom -= self.cxBorder
            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 &= ~afxres.CBRS_BORDER_RIGHT
            rc0.right -= self.cxEdge
            rc0.left += self.cxBorder
            rc0.bottom -= self.cxBorder
            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 &= ~afxres.CBRS_BORDER_LEFT
            rc0.left += self.cxEdge
            rc0.right -= self.cxBorder
            rc0.bottom -= self.cxBorder
            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 -= 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 += pt[1] - self.ptOld[1]
        elif self.nDockBarID == afxres.AFX_IDW_DOCKBAR_BOTTOM:
            newsize += -pt[1] + self.ptOld[1]
        elif self.nDockBarID == afxres.AFX_IDW_DOCKBAR_LEFT:
            newsize += pt[0] - self.ptOld[0]
        elif self.nDockBarID == afxres.AFX_IDW_DOCKBAR_RIGHT:
            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 += self.cxEdge
        elif self.nDockBarID == afxres.AFX_IDW_DOCKBAR_RIGHT:
            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 += 38
            gb -= 10
            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 -= 38
            gl += 10
            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():
    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()
