vbAccelerator - Contents of code file: vbalDockContainer.ctl

VERSION 5.00
Begin VB.UserControl vbalDockContainer 
   Alignable       =   -1  'True
   AutoRedraw      =   -1  'True
   ClientHeight    =   3600
   ClientLeft      =   0
   ClientTop       =   0
   ClientWidth     =   4800
   ControlContainer=   -1  'True
   ScaleHeight     =   3600
   ScaleWidth      =   4800
   ToolboxBitmap   =   "vbalDockContainer.ctx":0000
   Begin VB.PictureBox picBar 
      AutoRedraw      =   -1  'True
      BorderStyle     =   0  'None
      Height          =   375
      Index           =   0
      Left            =   60
      ScaleHeight     =   375
      ScaleWidth      =   3075
      TabIndex        =   0
      Top             =   120
      Visible         =   0   'False
      Width           =   3075
   End
End
Attribute VB_Name = "vbalDockContainer"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = True
Option Explicit

Implements ISubclass

Private Const WM_ERASEBKGND = &H14
Private Const WM_DESTROY = &H2
Private Declare Function GetClientRect Lib "user32" (ByVal hwnd As Long, lpRect
 As RECT) As Long
Private Declare Function MapWindowPoints Lib "user32" (ByVal hwndFrom As Long,
 ByVal hWndTo As Long, lppt As Any, ByVal cPoints As Long) As Long
Private Declare Function SetCapture Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function SetParent Lib "user32" (ByVal hWndChild As Long, ByVal
 hWndNewParent As Long) As Long
Private Declare Function MoveWindow Lib "user32" (ByVal hwnd As Long, ByVal x
 As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal
 bRepaint As Long) As Long
Private Declare Function ShowWindow Lib "user32" (ByVal hwnd As Long, ByVal
 nCmdShow As Long) As Long
Private Declare Function IsWindow Lib "user32" (ByVal hwnd As Long) As Long
Private Const SW_HIDE = 0
Private Const SW_NORMAL = 1
Private Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd
 As Long) As Long
Private Const GW_OWNER = 4
Private Const GW_HWNDNEXT = 2
Private Const GW_CHILD = 5
Private Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function CreatePen Lib "gdi32" (ByVal nPenStyle As Long, ByVal
 nWidth As Long, ByVal crColor As Long) As Long
Private Declare Function LineTo Lib "gdi32" (ByVal hdc As Long, ByVal x As
 Long, ByVal y As Long) As Long
Private Declare Function MoveToEx Lib "gdi32" (ByVal hdc As Long, ByVal x As
 Long, ByVal y As Long, lpPoint As POINTAPI) As Long
Private Declare Function DrawEdge Lib "user32" (ByVal hdc As Long, qrc As RECT,
 ByVal edge As Long, ByVal grfFlags As Long) As Long
Private Const BDR_RAISED = &H5
Private Const BDR_RAISEDINNER = &H4
Private Const BDR_RAISEDOUTER = &H1
Private Const BDR_SUNKENOUTER = 2
Private Const BDR_SUNKENINNER = 8
Private Const EDGE_RAISED = (BDR_RAISEDOUTER Or BDR_RAISEDINNER)
Private Const BF_BOTTOM = &H8
Private Const BF_LEFT = &H1
Private Const BF_RIGHT = &H4
Private Const BF_SOFT = &H1000     ' Use for softer buttons.
Private Const BF_FLAT = &H4000          '/* For flat rather than 3D borders */
Private Const BF_MONO = &H8000&          '/* For monochrome borders */
Private Const BF_TOP = &H2
Private Const BF_RECT = (BF_LEFT Or BF_TOP Or BF_RIGHT Or BF_BOTTOM)
Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal
 hObject As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As
 Long
Private Declare Function GetSysColor Lib "user32" (ByVal nIndex As Long) As Long
Private Declare Function GetSysColorBrush Lib "user32" (ByVal nIndex As Long)
 As Long
Private Declare Function CreateSolidBrush Lib "gdi32" (ByVal crColor As Long)
 As Long
Private Declare Function InflateRect Lib "user32" (lpRect As RECT, ByVal x As
 Long, ByVal y As Long) As Long
Private Declare Function OffsetRect Lib "user32" (lpRect As RECT, ByVal x As
 Long, ByVal y As Long) As Long
Private Declare Function UnionRect Lib "user32" (lpDestRect As RECT, lpSrc1Rect
 As RECT, lpSrc2Rect As RECT) As Long
Private Declare Function FillRect Lib "user32" (ByVal hdc As Long, lpRect As
 RECT, ByVal hBrush As Long) As Long
Private Const PS_SOLID = 0
Private Const HWND_DESKTOP = 0
Private Declare Function GetSystemMetrics Lib "user32" (ByVal nIndex As Long)
 As Long
Private Const SM_CXFRAME = 32
Private Const SM_CYFRAME = 33
Private Const SM_CYBORDER = 6
Private Const SM_CXBORDER = 5
Private Const SM_CYCAPTION = 4
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal
 hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function SendMessageLong Lib "user32" Alias "SendMessageA"
 (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As
 Long) As Long
Private Const WM_USER = &H400
Private Const TB_BUTTONCOUNT = (WM_USER + 24)
Private Const TB_GETBUTTON = (WM_USER + 23)
Private Const TB_GETRECT = (WM_USER + 51)             '// wParam is the Cmd
 instead of index
Private Type TBBUTTON
   iBitmap As Long
   idCommand As Long
   fsState As Byte
   fsStyle As Byte
   bReserved1 As Byte
   bReserved2 As Byte
   dwData As Long
   iString As Long
End Type

Private Enum eDTBCLastAction
   eNewAction
   eNewRowUp
   eNewRowDown
   eShareRowDown
   eShareRowUp
End Enum

Private Type tDockedBar
   
   lX As Long
   cx As Long
   
   cXA As Long
   cYA As Long
   
   cXAHorz As Long
   cYAHorz As Long
   cXAVert As Long
   cYAVert As Long
   
   lIdx As Long
   sKey As String
   sTitle As String
   bFillRow As Boolean
   
   lThisX As Long
   lThisY As Long
   
   lLastX As Long
   lLastY As Long
   
   lOffsetX As Long
   
   bActiveBar As Boolean
   eAction As Long
   
   bRowLastChosenBar As Boolean
   lXSingleRow As Long
   
   bCanDockHorizontal As Boolean
   bCanDockVertical As Boolean
   bCanClose As Boolean
   bShowChevron As Boolean
   
End Type

Private Type tDockedRow
   lCount As Long
   lHeight As Long
   tBar() As tDockedBar
End Type

Private Type tChevron
   bShow As Boolean
   bMouseOver As Boolean
   bMouseDown As Boolean
   tR As RECT
End Type

Private Type tVerticalHiddenButtons
   hwnd As Long
   cKeys As Collection
End Type

Private m_tHiddenItems() As tVerticalHiddenButtons
Private m_iHiddenItemCount As Long

Private m_lCount As Long
Private m_pic() As Long
Private m_lRows As Long
Private m_tRow() As tDockedRow
Private m_tChevron() As tChevron
Private m_hWndCtl As Long
Private m_bXPStyle As Boolean

Private m_iActiveBar As Long
Private m_lIndexActiveBar As Long

Private m_lMinBarSize As Long
Private m_lMinBestBarSize As Long

Private m_bAllowDragOff As Boolean
Private m_bLockToolbars As Boolean

Private m_bResizeInterlock As Boolean

Private m_bNonDockingArea As Boolean
Private m_lNonDockingAreaSize As Long

Private m_hWndParent As Long

Private m_tPtDock As POINTAPI

Private m_iDragOffCount As Long
Private m_lDragOff() As Long
Private m_sDragOff() As String

Private WithEvents m_tmr As CTimer
Attribute m_tmr.VB_VarHelpID = -1

Public Event ChevronPress(ByVal key As String, ByVal x As Long, ByVal y As Long)
Attribute ChevronPress.VB_Description = "Raised when the chevron at the end of
 the bar is clicked."
Public Event SizeChanged()
Attribute SizeChanged.VB_Description = "Raised when the size of this dock
 changes (e.g. due to rearrangement of bands or docking/undocking)."
Public Event Docked(ByVal key As String)
Attribute Docked.VB_Description = "Raised when the specified bar is docked."
Public Event Undocked(ByVal key As String)
Attribute Undocked.VB_Description = "Raised when the specified bar is undocked."
Public Event BarClose(ByVal sKey As String, ByRef bCancel As Boolean)
Attribute BarClose.VB_Description = "Raised when the user clicks the close
 button on an undocked toolbar owned by this container."

Public Property Get OfficeXpStyle() As Boolean
Attribute OfficeXpStyle.VB_Description = "Gets/sets whether the control draws
 using Office XP Style or not."
   OfficeXpStyle = m_bXPStyle
End Property
Public Property Let OfficeXpStyle(ByVal bState As Boolean)
Dim i As Long
   m_bXPStyle = bState
   On Error Resume Next
   For i = picBar.LBound To picBar.UBound
      If (m_bXPStyle) Then
         picBar(i).BackColor = VSNetControlColor
      Else
         picBar(i).BackColor = vbButtonFace
      End If
   Next i
   PropertyChanged "OfficeXpStyle"
End Property

Friend Function fJustDocked(ByVal sKey As String)
   ' we have to make it look like there was a mouse down
   ' on the bar added at sKey, then trap mouse events into
   ' this control:
Dim lIndex As Long
Dim tP As POINTAPI
   If getBarForKey(sKey, lIndex) Then
      GetCursorPos tP
      ScreenToClient picBar(lIndex).hwnd, tP
      mouseDown lIndex, tP.x * Screen.TwipsPerPixelX, tP.y *
       Screen.TwipsPerPixelY
      UserControl.SetFocus
   End If
End Function

Public Function SaveLayout() As String
Attribute SaveLayout.VB_Description = "Saves the current layout to an XML
 string for use later with the RestoreLayout method."
   '
   Dim i As Long
   Dim j As Long
   Dim attr As IXMLDOMAttribute
   Dim nodWork As IXMLDOMNode
   Dim lPtr As Long
   
   Dim dom As New DOMDocument
   Dim nodTop As IXMLDOMNode
   
   Set nodTop = dom.createElement("Dock")
   Set attr = dom.createAttribute("name")
   attr.Value = UserControl.Extender.Name
   nodTop.Attributes.setNamedItem attr
   Set attr = dom.createAttribute("version")
   attr.Value = "1.0"
   nodTop.Attributes.setNamedItem attr
   
   ' Save the general configuration:
   Set nodWork = dom.createElement("Configuration")
   Set attr = dom.createAttribute("allowDragOff")
   attr.Value = IIf(m_bAllowDragOff, "y", "n")
   nodWork.Attributes.setNamedItem attr
   Set attr = dom.createAttribute("lockToolbars")
   attr.Value = IIf(m_bLockToolbars, "y", "n")
   nodWork.Attributes.setNamedItem attr
   Set attr = dom.createAttribute("officeXpStyle")
   attr.Value = IIf(m_bXPStyle, "y", "n")
   nodWork.Attributes.setNamedItem attr
   Set attr = dom.createAttribute("nonDockingArea")
   attr.Value = IIf(m_bNonDockingArea, "y", "n")
   nodWork.Attributes.setNamedItem attr
   Set attr = dom.createAttribute("nonDockingAreaSize")
   attr.Value = m_lNonDockingAreaSize
   nodWork.Attributes.setNamedItem attr
   nodTop.appendChild nodWork
   
   ' Save the rows:
   Dim nodRows As IXMLDOMNode
   Set nodRows = dom.createElement("Rows")
   Set attr = dom.createAttribute("count")
   attr.Value = m_lRows
   nodRows.Attributes.setNamedItem attr
   For i = 1 To m_lRows
      Set nodWork = dom.createElement("Row")
      Set attr = dom.createAttribute("index")
      attr.Value = i
      nodWork.Attributes.setNamedItem attr
      
      Set attr = dom.createAttribute("barCount")
      attr.Value = m_tRow(i).lCount
      nodWork.Attributes.setNamedItem attr
      Set attr = dom.createAttribute("height")
      attr.Value = m_tRow(i).lHeight
      nodWork.Attributes.setNamedItem attr
      
      Dim nodBars As IXMLDOMNode
      Set nodBars = dom.createElement("Bars")
      Dim nodBar As IXMLDOMNode
      For j = 1 To m_tRow(i).lCount
         Set nodBar = dom.createElement("Bar")
         Set attr = dom.createAttribute("index")
         attr.Value = j
         nodBar.Attributes.setNamedItem attr
         
         saveBarLayout dom, nodBar, m_tRow(i).tBar(j)
         
         saveHiddenItems dom, nodBar, m_tRow(i).tBar(j)
         
         nodBars.appendChild nodBar
      Next j
      nodWork.appendChild nodBars
      
      nodRows.appendChild nodWork
   Next i
   nodTop.appendChild nodRows

   ' Save the pic index data;
   Dim nodPicIndexes As IXMLDOMNode
   Set nodPicIndexes = dom.createElement("PicIndexes")
   Set attr = dom.createAttribute("count")
   attr.Value = m_lCount
   nodPicIndexes.Attributes.setNamedItem attr
   Dim nodPicIndex As IXMLDOMNode
   For i = 1 To m_lCount
      Set nodPicIndex = dom.createElement("PicIndex")
      Set attr = dom.createAttribute("index")
      attr.Value = i
      nodPicIndex.Attributes.setNamedItem attr
      Set attr = dom.createAttribute("value")
      attr.Value = m_pic(i)
      nodPicIndex.Attributes.setNamedItem attr
      nodPicIndexes.appendChild nodPicIndex
   Next i
   nodTop.appendChild nodPicIndexes
   
   ' Save the undocked items:
   Dim nodUndocked As IXMLDOMNode
   Set nodUndocked = dom.createElement("UndockedBars")
   Set attr = dom.createAttribute("count")
   attr.Value = m_iDragOffCount
   nodUndocked.Attributes.setNamedItem attr
   Dim nodUndockedBar As IXMLDOMNode
   For i = 1 To m_iDragOffCount
      Set nodUndockedBar = dom.createElement("UndockedBar")
      saveUndockedBarLayout dom, nodUndockedBar, i
      nodUndocked.appendChild nodUndockedBar
   Next i
   nodTop.appendChild nodUndocked
   
   ' Add to the top node:
   dom.appendChild nodTop
   
   ' Return the XML:
   SaveLayout = dom.xml
      
End Function

Private Sub saveHiddenItems(dom As DOMDocument, nodBar As IXMLDOMNode, tBar As
 tDockedBar)
Dim i As Long
Dim key As Variant
   For i = 1 To m_iHiddenItemCount
      If (IsNumeric(picBar(m_pic(tBar.lIdx)).Tag)) Then
         If (m_tHiddenItems(i).hwnd = CLng(picBar(m_pic(tBar.lIdx)).Tag)) Then
            Dim nodHiddenItems As IXMLDOMNode
            Set nodHiddenItems = dom.createElement("HiddenItems")
            Dim nodHidden As IXMLDOMNode
            Dim attr As IXMLDOMAttribute
            For Each key In m_tHiddenItems(i).cKeys
               Set nodHidden = dom.createElement("Hidden")
               Set attr = dom.createAttribute("key")
               attr.Value = key
               nodHidden.Attributes.setNamedItem attr
               nodHiddenItems.appendChild nodHidden
            Next
            nodBar.appendChild nodHiddenItems
         End If
      End If
   Next i
End Sub

Private Sub saveUndockedBarLayout(dom As DOMDocument, nodBar As IXMLDOMNode,
 lIndex As Long)
Dim lPtr As Long
Dim attr As IXMLDOMAttribute

   lPtr = GetProp(m_lDragOff(lIndex), UNDOCKEDCONTAINERID)
   If Not (lPtr = 0) Then
      Dim tBar As tDockedBar
      Dim x As Long
      Dim y As Long
      Dim width As Long
      Dim height As Long
      Dim f As frmToolbar
      Set f = objectFromPtr(lPtr)
      f.getDetails tBar.sKey, tBar.cXAHorz, tBar.cYAHorz, tBar.cXAVert,
       tBar.cYAVert, _
         tBar.bFillRow, tBar.sTitle, tBar.bCanDockHorizontal,
          tBar.bCanDockVertical, _
         tBar.bCanClose, x, y, width, height
      saveBarLayout dom, nodBar, tBar
      
      Set attr = dom.createAttribute("xPos")
      attr.Value = x
      nodBar.Attributes.setNamedItem attr
      Set attr = dom.createAttribute("yPos")
      attr.Value = y
      nodBar.Attributes.setNamedItem attr
      Set attr = dom.createAttribute("width")
      attr.Value = width
      nodBar.Attributes.setNamedItem attr
      Set attr = dom.createAttribute("height")
      attr.Value = height
      nodBar.Attributes.setNamedItem attr
      
   End If
End Sub

Private Sub saveBarLayout(dom As DOMDocument, nodBar As IXMLDOMNode, tBar As
 tDockedBar)
Dim attr As IXMLDOMAttribute

   Set attr = dom.createAttribute("lx")
   attr.Value = tBar.lX
   nodBar.Attributes.setNamedItem attr
   Set attr = dom.createAttribute("cx")
   attr.Value = tBar.cx
   nodBar.Attributes.setNamedItem attr
   
   Set attr = dom.createAttribute("cXA")
   attr.Value = tBar.cXA
   nodBar.Attributes.setNamedItem attr
   Set attr = dom.createAttribute("cYA")
   attr.Value = tBar.cYA
   nodBar.Attributes.setNamedItem attr
   
   Set attr = dom.createAttribute("cXAHorz")
   attr.Value = tBar.cXAHorz
   nodBar.Attributes.setNamedItem attr
   Set attr = dom.createAttribute("cYAHorz")
   attr.Value = tBar.cYAHorz
   nodBar.Attributes.setNamedItem attr
   Set attr = dom.createAttribute("cXAVert")
   attr.Value = tBar.cXAVert
   nodBar.Attributes.setNamedItem attr
   Set attr = dom.createAttribute("cYAVert")
   attr.Value = tBar.cYAVert
   nodBar.Attributes.setNamedItem attr
   
   Set attr = dom.createAttribute("lIdx")
   attr.Value = tBar.lIdx
   nodBar.Attributes.setNamedItem attr
   Set attr = dom.createAttribute("sKey")
   attr.Value = tBar.sKey
   nodBar.Attributes.setNamedItem attr
   Set attr = dom.createAttribute("sTitle")
   attr.Value = tBar.sTitle
   nodBar.Attributes.setNamedItem attr
   Set attr = dom.createAttribute("bFillRow")
   attr.Value = IIf(tBar.bFillRow, "y", "n")
   nodBar.Attributes.setNamedItem attr
   
   Set attr = dom.createAttribute("lThisX")
   attr.Value = tBar.lThisX
   nodBar.Attributes.setNamedItem attr
   Set attr = dom.createAttribute("lThisY")
   attr.Value = tBar.lThisY
   nodBar.Attributes.setNamedItem attr
   Set attr = dom.createAttribute("lLastX")
   attr.Value = tBar.lLastX
   nodBar.Attributes.setNamedItem attr
   Set attr = dom.createAttribute("lLastY")
   attr.Value = tBar.lLastY
   nodBar.Attributes.setNamedItem attr
   
   Set attr = dom.createAttribute("lOffsetX")
   attr.Value = tBar.lOffsetX
   nodBar.Attributes.setNamedItem attr
   
   Set attr = dom.createAttribute("bActiveBar")
   attr.Value = IIf(tBar.bActiveBar, "y", "n")
   nodBar.Attributes.setNamedItem attr
   Set attr = dom.createAttribute("eAction")
   attr.Value = tBar.eAction
   nodBar.Attributes.setNamedItem attr
   
   Set attr = dom.createAttribute("bRowLastChosenBar")
   attr.Value = IIf(tBar.bRowLastChosenBar, "y", "n")
   nodBar.Attributes.setNamedItem attr
   Set attr = dom.createAttribute("lXSingleRow")
   attr.Value = tBar.lXSingleRow
   nodBar.Attributes.setNamedItem attr
   
   Set attr = dom.createAttribute("bCanDockHorizontal")
   attr.Value = IIf(tBar.bCanDockHorizontal, "y", "n")
   nodBar.Attributes.setNamedItem attr
   Set attr = dom.createAttribute("bCanDockVertical")
   attr.Value = IIf(tBar.bCanDockVertical, "y", "n")
   nodBar.Attributes.setNamedItem attr
   Set attr = dom.createAttribute("bCanClose")
   attr.Value = IIf(tBar.bCanClose, "y", "n")
   nodBar.Attributes.setNamedItem attr
   Set attr = dom.createAttribute("bShowChevron")
   attr.Value = IIf(tBar.bShowChevron, "y", "n")
   nodBar.Attributes.setNamedItem attr
   
End Sub

Public Sub RestoreLayout(ByVal sLayoutXml As String, ByRef sKey() As String,
 ByRef hwnd() As Long)
Attribute RestoreLayout.VB_Description = "Restores a layout from XML previously
 generated using the SaveLayout function."
   '
   
   ' Clear everything internally:
   Dim lPtr As Long
   Dim i As Long
   Dim f As frmToolbar
   Dim lhWnd As Long
   Dim key As Variant
   
   m_tmr.Interval = 0
   For i = 1 To m_iHiddenItemCount
      lPtr = GetProp(m_tHiddenItems(i).hwnd, "vbalTbar:ControlPtr")
      If Not (lPtr = 0) Then
         Dim ctl As Object
         Set ctl = objectFromPtr(lPtr)
         For Each key In m_tHiddenItems(i).cKeys
            ctl.ButtonVisible(i) = True
         Next
      End If
   Next i
   m_iHiddenItemCount = 0
   Erase m_tHiddenItems
   m_lCount = 0
   Erase m_pic
   m_lRows = 0
   Erase m_tRow
   Erase m_tChevron
   m_bXPStyle = True
   m_iActiveBar = 0
   m_lIndexActiveBar = 0
   m_lMinBarSize = 0
   m_lMinBestBarSize = 0
   m_bAllowDragOff = True
   m_bLockToolbars = False
   m_bResizeInterlock = False
   m_bNonDockingArea = False
   m_lNonDockingAreaSize = 24
   For i = 1 To m_iDragOffCount
      lPtr = GetProp(m_lDragOff(i), UNDOCKEDCONTAINERID)
      If Not (lPtr = 0) Then
         Set f = objectFromPtr(lPtr)
         lhWnd = f.DockedhWnd
         If Not (lhWnd = 0) Then
            ShowWindow lhWnd, SW_HIDE
            SetParent lhWnd, m_hWndCtl
         End If
         Unload f
         Set f = Nothing
      End If
   Next i
   m_iDragOffCount = 0
   Erase m_lDragOff
   Erase m_sDragOff
   If (picBar.UBound > 0) Then
      For i = 1 To picBar.UBound
         On Error Resume Next
         If IsNumeric(picBar(i).Tag) Then
            DetachMessage Me, picBar(i).hwnd, WM_ERASEBKGND
            DetachMessage Me, picBar(i).hwnd, WM_DESTROY
            ShowWindow picBar(i).Tag, SW_HIDE
            SetParent picBar(i).Tag, m_hWndCtl
         End If
         Unload picBar(i)
         picBar(i).Tag = ""
         On Error GoTo 0
      Next i
      If IsNumeric(picBar(0).Tag) Then
         DetachMessage Me, picBar(0).hwnd, WM_ERASEBKGND
         DetachMessage Me, picBar(0).hwnd, WM_DESTROY
         ShowWindow picBar(0).Tag, SW_HIDE
         SetParent picBar(0).Tag, m_hWndCtl
         picBar(0).Tag = ""
      End If
   End If
   
   ' Now read the layout information:
   Dim dom As New DOMDocument
   dom.loadXML sLayoutXml
   
   Dim nodTop As IXMLDOMNode
   Set nodTop = dom.selectSingleNode("//Dock[@name='" +
    UserControl.Extender.Name + "']")
   If Not nodTop Is Nothing Then
      
      Dim nodWork As IXMLDOMNode
      For Each nodWork In nodTop.childNodes
         Select Case nodWork.nodeName
         Case "Configuration"
            restoreConfiguration nodWork
         Case "Rows"
            restoreRows nodWork
         Case "PicIndexes"
            restorePicIndexes nodWork
         Case "UndockedBars"
            restoreUndockedBars nodWork, sKey(), hwnd()
         End Select
      Next
      
      ' Ensure we have enough chevrons:
      ReDim m_tChevron(0 To picBar.UBound) As tChevron
      
      ' Fix up the docked items & the picBars
      ' using the passed in array of keys/hWnds:
      Dim cXA As Long
      Dim cYA As Long
      Dim lIndex As Long
      Dim lRow As Long
      Dim lBar As Long
      
      For i = LBound(sKey) To UBound(sKey)
         For lRow = 1 To m_lRows
            For lBar = 1 To m_tRow(lRow).lCount
               If (m_tRow(lRow).tBar(lBar).sKey = sKey(i)) Then
                  lIndex = m_pic(m_tRow(lRow).tBar(lBar).lIdx)
                  cXA = m_tRow(lRow).tBar(lBar).cXA
                  cYA = m_tRow(lRow).tBar(lBar).cYA
                  Debug.Print "Setting "; Hex(hwnd(i)); " into picBar(" &
                   lIndex & ")", Hex(picBar(lIndex).hwnd), sKey(i)
                  If Not (Horizontal) Then
                     hideControlsInToolbar hwnd(i), True
                  End If
                  SetParent hwnd(i), picBar(lIndex).hwnd
                  If UserControl.Extender.Align = vbAlignTop Or
                   UserControl.Extender.Align = vbAlignBottom Then
                     MoveWindow hwnd(i), 10, 1, cXA - 22, cYA - 2, 1
                  Else
                     MoveWindow hwnd(i), 1, 10, cYA - 2, cXA - 22, 1
                  End If
                  picBar(lIndex).Tag = hwnd(i)
                  picBar(lIndex).Visible = True
                  ShowWindow hwnd(i), 1
                  On Error Resume Next
                  AttachMessage Me, picBar(lIndex).hwnd, WM_ERASEBKGND
                  AttachMessage Me, picBar(lIndex).hwnd, WM_DESTROY
               End If
            Next lBar
         Next lRow
      Next i
      
      Resize
   End If
   
   '
End Sub

Private Sub restoreConfiguration(nodConfiguration As IXMLDOMNode)
Dim attr As IXMLDOMAttribute
   For Each attr In nodConfiguration.Attributes
      Select Case attr.Name
      Case "allowDragOff"
         m_bAllowDragOff = IIf(attr.Value = "n", False, True)
      Case "lockToolbars"
         m_bLockToolbars = IIf(attr.Value = "y", True, False)
      Case "officeXpStyle"
         m_bXPStyle = IIf(attr.Value = "n", False, True)
      Case "nonDockingArea"
         m_bNonDockingArea = IIf(attr.Value = "y", True, False)
      Case "nonDockingAreaSize"
         m_lNonDockingAreaSize = CLng(attr.Value)
      End Select
   Next
End Sub

Private Sub restoreRows(nodRows As IXMLDOMNode)
Dim attr As IXMLDOMAttribute
Dim lRow As Long
Dim lBar As Long
Dim lTotalBarCount As Long

   Set attr = nodRows.Attributes.getNamedItem("count")
   m_lRows = CLng(attr.Value)
   If (m_lRows > 0) Then
      ReDim m_tRow(1 To m_lRows) As tDockedRow
      Dim nodRow As IXMLDOMNode
      For Each nodRow In nodRows.childNodes
         Set attr = nodRow.Attributes.getNamedItem("index")
         lRow = CLng(attr.Value)
         Set attr = nodRow.Attributes.getNamedItem("barCount")
         m_tRow(lRow).lCount = CLng(attr.Value)
         Set attr = nodRow.Attributes.getNamedItem("height")
         m_tRow(lRow).lHeight = CLng(attr.Value)
         If (m_tRow(lRow).lCount > 0) Then
            ReDim m_tRow(lRow).tBar(1 To m_tRow(lRow).lCount) As tDockedBar
            Dim nodBars As IXMLDOMNode
            Set nodBars = nodRow.firstChild
            Dim nodBar As IXMLDOMNode
            For Each nodBar In nodBars.childNodes
               lTotalBarCount = lTotalBarCount + 1
               Set attr = nodBar.Attributes.getNamedItem("index")
               lBar = CLng(attr.Value)
               For Each attr In nodBar.Attributes
                  With m_tRow(lRow).tBar(lBar)
                     Select Case attr.Name
                     Case "lx"
                        .lX = CLng(attr.Value)
                     Case "cx"
                        .cx = CLng(attr.Value)
                     Case "cXA"
                        .cXA = CLng(attr.Value)
                     Case "cYA"
                        .cYA = CLng(attr.Value)
                     Case "cXAHorz"
                        .cXAHorz = CLng(attr.Value)
                     Case "cYAHorz"
                        .cYAHorz = CLng(attr.Value)
                     Case "cXAVert"
                        .cXAVert = CLng(attr.Value)
                     Case "cYAVert"
                        .cYAVert = CLng(attr.Value)
                     Case "lIdx"
                        .lIdx = CLng(attr.Value)
                     Case "sKey"
                        .sKey = attr.Value
                     Case "sTitle"
                        .sTitle = attr.Value
                     Case "bFillRow"
                        .bFillRow = IIf(attr.Value = "y", True, False)
                     Case "lThisX"
                        .lThisX = CLng(attr.Value)
                     Case "lThisY"
                        .lThisY = CLng(attr.Value)
                     Case "lLastX"
                        .lLastX = CLng(attr.Value)
                     Case "lLastY"
                        .lLastY = CLng(attr.Value)
                     Case "lOffsetX"
                        .lOffsetX = CLng(attr.Value)
                     Case "bActiveBar"
                        .bActiveBar = IIf(attr.Value = "y", True, False)
                     Case "eAction"
                        .eAction = CLng(attr.Value)
                     Case "bRowLastChosenBar"
                        .bRowLastChosenBar = IIf(attr.Value = "y", True, False)
                     Case "lXSingleRow"
                        .lXSingleRow = CLng(attr.Value)
                     Case "bCanDockHorizontal"
                        .bCanDockHorizontal = IIf(attr.Value = "n", False, True)
                     Case "bCanDockVertical"
                        .bCanDockVertical = IIf(attr.Value = "n", False, True)
                     Case "bCanClose"
                        .bCanClose = IIf(attr.Value = "n", False, True)
                     Case "bShowChevron"
                        .bShowChevron = IIf(attr.Value = "n", False, True)
                     End Select
                  End With
               Next
            Next
         End If
      Next
      ' Ensure we have enough rows available to accommodate all bars:
      If (lTotalBarCount > m_lRows) Then
         ReDim Preserve m_tRow(1 To lTotalBarCount) As tDockedRow
      End If
      For lRow = 1 To lTotalBarCount
         ReDim Preserve m_tRow(lRow).tBar(1 To lTotalBarCount) As tDockedBar
      Next lRow
   End If
End Sub

Private Sub restorePicIndexes(nodPicIndexes As IXMLDOMNode)
Dim nodPicIndex As IXMLDOMNode
Dim attr As IXMLDOMAttribute
Dim lIndex As Long
Dim lValue As Long
Dim i As Long

   Set attr = nodPicIndexes.Attributes.getNamedItem("count")
   m_lCount = CLng(attr.Value)
   If (m_lCount > 0) Then
      ReDim m_pic(1 To m_lCount) As Long
      For Each nodPicIndex In nodPicIndexes.childNodes
         Set attr = nodPicIndex.Attributes.getNamedItem("index")
         lIndex = CLng(attr.Value)
         Set attr = nodPicIndex.Attributes.getNamedItem("value")
         lValue = CLng(attr.Value)
         m_pic(lIndex) = lValue
         If (lValue > picBar.UBound) Then
            For i = picBar.UBound + 1 To lValue
               Load picBar(i)
               picBar(i).Tag = ""
            Next i
         End If
      Next
   End If
End Sub

Private Sub restoreUndockedBars(nodUndockedBars As IXMLDOMNode, sKey() As
 String, hwnd() As Long)
Dim nodUndocked As IXMLDOMNode
Dim attr As IXMLDOMAttribute
Dim tBarBlank As tDockedBar
Dim tBar As tDockedBar
Dim x As Long
Dim y As Long
Dim width As Long
Dim height As Long
Dim i As Long
Dim hWndA As Long

   For Each nodUndocked In nodUndockedBars.childNodes
      LSet tBar = tBarBlank
      For Each attr In nodUndocked.Attributes
         Select Case attr.Name
         Case "cXAHorz"
            tBar.cXAHorz = CLng(attr.Value)
         Case "cYAHorz"
            tBar.cYAHorz = CLng(attr.Value)
         Case "cXAVert"
            tBar.cXAVert = CLng(attr.Value)
         Case "cYAVert"
            tBar.cYAVert = CLng(attr.Value)
         Case "sKey"
            tBar.sKey = attr.Value
         Case "sTitle"
            tBar.sTitle = attr.Value
         Case "bFillRow"
            tBar.bFillRow = IIf(attr.Value = "y", True, False)
         Case "bCanDockHorizontal"
            tBar.bCanDockHorizontal = IIf(attr.Value = "n", False, True)
         Case "bCanDockVertical"
            tBar.bCanDockVertical = IIf(attr.Value = "n", False, True)
         Case "bCanClose"
            tBar.bCanClose = IIf(attr.Value = "n", False, True)
         Case "bShowChevron"
            tBar.bShowChevron = IIf(attr.Value = "n", False, True)
         Case "xPos"
            x = CLng(attr.Value)
         Case "yPos"
            y = CLng(attr.Value)
         Case "width"
            width = CLng(attr.Value)
         Case "height"
            height = CLng(attr.Value)
         End Select
      Next
      
      ' create new toolbar
      Dim f As New frmToolbar
      f.width = width * Screen.TwipsPerPixelX
      f.height = height * Screen.TwipsPerPixelY
   
      ' eval position to show
      f.Move x * Screen.TwipsPerPixelX, y * Screen.TwipsPerPixelY
      With tBar
         f.init .sKey, _
            m_hWndCtl, _
            m_hWndParent, _
            .cXAHorz, .cYAHorz, .cXAVert, .cYAVert, _
            .bFillRow, _
            .sTitle, _
            .bCanDockHorizontal, .bCanDockVertical, _
            .bCanClose, _
            m_bXPStyle, _
            True
      End With
   
      ' remove the bar from the control so it can be seen
      ' floating instead:
      For i = LBound(sKey) To UBound(sKey)
         If (sKey(i) = tBar.sKey) Then
            hWndA = hwnd(i)
            Exit For
         End If
      Next i
      If Not (hWndA = 0) Then
         ShowWindow hWndA, 0
         SetParent hWndA, 0
      End If
   
      ' show in position & redirect mouse messages
      f.Show , UserControl.Parent
   
      ' ensure any captured window moves correctly:
      f.Capture hWndA
   
      ' now store a reference that we've dragged this item off:
      m_iDragOffCount = m_iDragOffCount + 1
      ReDim Preserve m_lDragOff(1 To m_iDragOffCount) As Long
      ReDim Preserve m_sDragOff(1 To m_iDragOffCount) As String
      m_lDragOff(m_iDragOffCount) = f.hwnd
      m_sDragOff(m_iDragOffCount) = tBar.sKey
   Next
End Sub

Public Property Get NonDockingArea() As Boolean
Attribute NonDockingArea.VB_Description = "Gets/sets whether a space is left at
 the edge of this dock closed to the window.  This space can be used for status
 bars or other non-dockable objects."
   NonDockingArea = m_bNonDockingArea
End Property
Public Property Let NonDockingArea(ByVal bState As Boolean)
   m_bNonDockingArea = bState
   Resize
   PropertyChanged "NonDockingArea"
End Property

Public Property Get NonDockingAreaSize() As Long
Attribute NonDockingAreaSize.VB_Description = "Gets/sets the size of the
 non-dockable area when the NonDockingArea flag is set."
   NonDockingAreaSize = m_lNonDockingAreaSize
End Property
Public Property Let NonDockingAreaSize(ByVal lSize As Long)
   m_lNonDockingAreaSize = lSize
   Resize
   PropertyChanged "NonDockingAreaSize"
End Property

Public Property Get AllowUndock() As Boolean
Attribute AllowUndock.VB_Description = "Gets/sets whether items added to this
 container can be undocked.  Defaults to True."
   AllowUndock = m_bAllowDragOff
End Property
Public Property Let AllowUndock(ByVal bState As Boolean)
   m_bAllowDragOff = bState
   PropertyChanged "AllowUndock"
End Property

Public Property Get LockToolBars() As Boolean
Attribute LockToolBars.VB_Description = "Prevents re-arrangement or resizing of
 the toolbars within this dock."
   LockToolBars = m_bLockToolbars
End Property
Public Property Let LockToolBars(ByVal bState As Boolean)
   m_bLockToolbars = bState
   Resize
   PropertyChanged "LockToolbars"
End Property

Public Property Get ContainerForKey(ByVal sKey As String) As vbalDockContainer
Attribute ContainerForKey.VB_Description = "Gets the control which owns the bar
 with the specified key."
Dim i As Long
Dim ctl As vbalDockContainer
Dim lPtr As Long
   findDockTargets m_hWndParent
   For i = 1 To DockTargetCount
      lPtr = GetProp(DockTarget(i), DOCKCONTAINERID)
      If Not (lPtr = 0) Then
         Set ctl = objectFromPtr(lPtr)
         If (ctl.OwnsKey(sKey)) Then
            Set ContainerForKey = ctl
            Exit Property
         End If
      End If
   Next i
End Property

Public Property Get OwnsKey(ByVal sKey As String) As Boolean
Attribute OwnsKey.VB_Description = "Gets whether this container owns the bar
 with the specified key (docked or undocked)"
Dim i As Long
Dim j As Long
   For i = 1 To m_lRows
      For j = 1 To m_tRow(i).lCount
         If (m_tRow(i).tBar(j).sKey = sKey) Then
            OwnsKey = True
            Exit Property
         End If
      Next j
   Next i
   For i = 1 To m_iDragOffCount
      If (m_sDragOff(i) = sKey) Then
         OwnsKey = True
         Exit Property
      End If
   Next i
End Property

Public Property Get IsDocked(ByVal sKey As String) As Boolean
Attribute IsDocked.VB_Description = "Gets/sets whether the bar with the
 specified key is docked or not."
Dim i As Long
Dim j As Long
   If (OwnsKey(sKey)) Then
      For i = 1 To m_lRows
         For j = 1 To m_tRow(i).lCount
            If (m_tRow(i).tBar(j).sKey = sKey) Then
               IsDocked = True
               Exit Property
            End If
         Next j
      Next i
   End If
End Property

Public Property Let IsDocked(ByVal sKey As String, ByVal bState As Boolean)
Dim i As Long
Dim j As Long
Dim lPtr As Long

   If (OwnsKey(sKey)) Then
      If (bState) Then
         ' Check all of the owned items:
         For i = 1 To m_iDragOffCount
            If (m_sDragOff(i) = sKey) Then
               ' dock the item
               lPtr = GetProp(m_lDragOff(i), UNDOCKEDCONTAINERID)
               If Not (lPtr = 0) Then
                  Dim f As frmToolbar
                  f.performDock m_hWndCtl, 0, -1, False
               End If
               Exit For
            End If
         Next i
      Else
         For i = 1 To m_lRows
            For j = 1 To m_tRow(i).lCount
               If (m_tRow(i).tBar(j).sKey = sKey) Then
                  ' undock the item
                  Dim x As Long
                  Dim y As Long
                  Dim tR As RECT
                  GetWindowRect m_hWndParent, tR
                  x = tR.Left + (tR.Right - tR.Left) \ 2
                  y = tR.Top + (tR.Bottom - tR.Top) \ 2
                  undock i, j, x, y
                  Exit Property
               End If
            Next j
         Next i
      End If
   Else
      Err.Raise 9, App.EXEName, "This container does not own the item with the
       key " & sKey
   End If

End Property


Friend Sub RemoveUndocked(ByVal sKey As String)
Dim i As Long
Dim lIndex As Long
   For i = 1 To m_iDragOffCount
      If (m_sDragOff(i) = sKey) Then
         lIndex = i
      End If
   Next i
   If (lIndex > 0) Then
      If (m_iDragOffCount > 1) Then
         For i = lIndex To m_iDragOffCount - 1
            m_lDragOff(i + 1) = m_lDragOff(i)
            m_sDragOff(i + 1) = m_sDragOff(i)
         Next i
         m_iDragOffCount = m_iDragOffCount - 1
         ReDim Preserve m_lDragOff(1 To m_iDragOffCount) As Long
         ReDim Preserve m_sDragOff(1 To m_iDragOffCount) As String
      Else
         m_iDragOffCount = 0
         Erase m_lDragOff
         Erase m_sDragOff
      End If
   End If
End Sub

Public Property Get BarCount() As Long
Attribute BarCount.VB_Description = "Gets the number of bars docked in this
 control."
   BarCount = m_lCount + m_iDragOffCount
End Property

Public Property Get BarKey(ByVal index As Long) As String
Attribute BarKey.VB_Description = "Gets the Key for the bar with the specified
 index within the control."
Dim i As Long
Dim j As Long
Dim lIdx As Long
   lIdx = 0
   For i = 1 To m_lRows
      For j = 1 To m_tRow(i).lCount
         lIdx = lIdx + 1
         If (lIdx = index) Then
            BarKey = m_tRow(i).tBar(j).sKey
            Exit Property
         End If
      Next j
   Next i
   For i = 1 To m_iDragOffCount
      lIdx = lIdx + 1
      If (lIdx = index) Then
         BarKey = m_sDragOff(i)
         Exit For
      End If
   Next i
End Property

Public Property Get RowCount() As Long
Attribute RowCount.VB_Description = "Gets the number of rows in this dock."
   RowCount = m_lRows
End Property

Public Sub BandSizeChange( _
      key As Variant, _
      ByVal cXAHorz As Long, _
      ByVal cYAHorz As Long, _
      ByVal cXAVert As Long, _
      ByVal cYAVert As Long _
   )
Attribute BandSizeChange.VB_Description = "Call when you change the size of an
 object which is docked into the control."
Dim lRow As Long, lBar As Long
Dim lIndex As Long
Dim bFound As Boolean
Dim i As Long
Dim lPtr As Long

   If getBarForKey(key, lIndex) Then
      For lRow = 1 To m_lRows
         For lBar = 1 To m_tRow(lRow).lCount
            If m_pic(m_tRow(lRow).tBar(lBar).lIdx) = lIndex Then
               With m_tRow(lRow).tBar(lBar)
                  .cXAHorz = cXAHorz + 10 + 12
                  .cYAHorz = cYAHorz + 2
                  .cXAVert = cXAVert + 10 + 12
                  .cYAVert = cYAVert + 2
                  If Horizontal Then
                     .cXA = .cXAHorz
                     .cYA = .cYAHorz
                  Else
                     .cXA = .cXAVert
                     .cYA = .cYAVert
                  End If
                  rowSize lRow
                  Resize
               End With
               Exit Sub
            End If
         Next lBar
      Next lRow
   Else
      For i = 1 To m_iDragOffCount
         If (m_sDragOff(i) = key) Then
            lPtr = GetProp(m_lDragOff(i), UNDOCKEDCONTAINERID)
            If Not (lPtr = 0) Then
               Dim f As frmToolbar
               Set f = objectFromPtr(lPtr)
               f.BandSizeChange _
                  cXAHorz, cYAHorz, _
                  cXAVert, cYAVert
            End If
            bFound = True
            Exit For
         End If
      Next i
      
      If Not bFound Then
         ' is an error
         Err.Raise 9, App.EXEName & ".vbalDockContainer", "The key '" & key &
          "' is not associated with this bar"
      End If
   End If
End Sub

Private Function getBarForKey( _
      ByVal key As Variant, _
      ByRef lIndex As Long _
   ) As Boolean
Dim lRow As Long
Dim lBar As Long
Dim i As Long
Dim iJunk As Long
Dim iCount As Long
   
   If IsNumeric(key) Then
      On Error Resume Next
      For i = picBar.LBound To picBar.UBound
         Err.Clear
         iJunk = picBar(i).index
         If Err.Number = 0 Then
            iCount = iCount + 1
            If iCount = key Then
               lIndex = i
               getBarForKey = True
               Exit Function
            End If
         End If
      Next i
   Else
      For lRow = 1 To m_lRows
         With m_tRow(lRow)
            For lBar = 1 To .lCount
               If .tBar(lBar).sKey = key Then
                  lIndex = m_pic(.tBar(lBar).lIdx)
                  getBarForKey = True
                  Exit Function
               End If
            Next lBar
         End With
      Next lRow
   End If
   
End Function

Public Sub Remove( _
      ByVal key As Variant _
   )
Attribute Remove.VB_Description = "Removes the specified bar from this dock."
Dim lRow As Long, lBar As Long
Dim lTheRow As Long, lTheBar As Long
Dim lIdx As Long
Dim lIndex As Long
   
   If getBarForKey(key, lIndex) Then

      ' Remove the bar lPtr from the thing:
      For lRow = 1 To m_lRows
         With m_tRow(lRow)
            For lBar = 1 To .lCount
               If m_pic(.tBar(lBar).lIdx) = lIndex Then
                  lIdx = .tBar(lBar).lIdx
                  lTheRow = lRow
                  lTheBar = lBar
                  Exit For
               End If
            Next lBar
         End With
         If lTheBar > 0 Then
            Exit For
         End If
      Next lRow
      
      Dim lhWndCapture As Long
      lhWndCapture = getCapturehWndForBar(lIndex)
      If Not (lhWndCapture = 0) Then
         hideControlsInToolbar lhWndCapture, False
         
         DetachMessage Me, picBar(lIndex).hwnd, WM_ERASEBKGND
         DetachMessage Me, picBar(lIndex).hwnd, WM_DESTROY
      End If
      RemoveProp hwnd, DOCKCONTAINERBARINDEX
      If lIndex > 0 Then
         Unload picBar(lIndex)
      Else
         picBar(0).Visible = False
         picBar(0).Tag = ""
      End If
      If lTheBar > 0 And lTheRow > 0 Then
         If m_lCount <= 1 Then
            ' no bars left
            m_lCount = 0
            'Erase m_tRow
            Erase m_pic
            m_lRows = 0
         Else
            ' Some bars left:
            ' ? Only one bar on this row?
            If m_tRow(lTheRow).lCount = 1 Then
               ' all subsequent rows move up
               For lRow = lTheRow To m_lRows - 1
                  m_tRow(lRow).lCount = m_tRow(lRow + 1).lCount
                  For lBar = 1 To m_tRow(lRow + 1).lCount
                     LSet m_tRow(lRow).tBar(lBar) = m_tRow(lRow + 1).tBar(lBar)
                  Next lBar
               Next lRow
               m_tRow(m_lRows).lCount = 0
               ' One row less
               m_lRows = m_lRows - 1
            Else
               ' We need to remove this bar &
               ' then AutoSize the row:
               For lBar = lTheBar To m_tRow(lTheRow).lCount - 1
                  LSet m_tRow(lTheRow).tBar(lBar) = m_tRow(lTheRow).tBar(lBar +
                   1)
               Next lBar
               m_tRow(lTheRow).lCount = m_tRow(lTheRow).lCount - 1
               rowSize lTheRow
               Resize
            End If
                                    
            ' Remove from m_pic:
            For lRow = lIdx To m_lCount - 1
               m_pic(lRow) = m_pic(lRow + 1)
            Next lRow
            ' One less item:
            m_lCount = m_lCount - 1
         
            For lRow = 1 To m_lRows
               For lBar = 1 To m_tRow(lRow).lCount
                  If m_tRow(lRow).tBar(lBar).lIdx >= lIdx Then
                     m_tRow(lRow).tBar(lBar).lIdx =
                      m_tRow(lRow).tBar(lBar).lIdx - 1
                  End If
               Next lBar
            Next lRow
         
         End If
         
         ' Redraw:
         Resize
         
      End If
   
   End If
   
End Sub

Private Function findPictureBox() As Long

Dim i As Long
Dim j As Long
Dim l As Long
Dim bUsed As Boolean
Dim bLowestSet As Boolean
Dim iLowestIndex As Long

   For i = picBar.LBound To picBar.UBound
      On Error Resume Next
      l = picBar(i).index
      If Err.Number = 0 Then
         ' this exists
         bUsed = False
         For j = 1 To m_lCount
            If m_pic(j) = i Then
               bUsed = True
               Exit For
            End If
         Next j
         If Not bUsed Then
            findPictureBox = i
            Exit Function
         End If
      Else
         If Not bLowestSet Then
            bLowestSet = True
            iLowestIndex = i
         End If
      End If
      Err.Clear
   Next i
   
   If bLowestSet Then
      On Error Resume Next
      Load picBar(iLowestIndex)
      picBar(iLowestIndex).Tag = ""
      On Error GoTo 0
      findPictureBox = iLowestIndex
   Else
      Load picBar(picBar.UBound + 1)
      picBar(picBar.UBound).Tag = ""
      findPictureBox = picBar.UBound
      ReDim Preserve m_tChevron(0 To picBar.UBound) As tChevron
   End If
   
End Function

Public Sub Add( _
      ByVal key As String, _
      ByVal cXAHorz As Long, _
      ByVal cYAHorz As Long, _
      ByVal cXAVert As Long, _
      ByVal cYAVert As Long, _
      Optional ByVal sTitle As String = "", _
      Optional ByVal lRow As Long = -1, _
      Optional ByVal lX As Long = 0, _
      Optional ByVal cx As Long = -1, _
      Optional ByVal bFillRow As Boolean = False, _
      Optional ByVal bCanDockHorizontal As Boolean = True, _
      Optional ByVal bCanDockVertical As Boolean = True, _
      Optional ByVal bCanClose As Boolean = True _
   )
Attribute Add.VB_Description = "Adds a new dockable bar to the control. 
 cXAHorz and cYAHorz specify the size of the control when docked horizontally,
 cXAVert and cYAVert when it is docked vertically.  Note the Key must be unique
 across all docks if the control can be dragged to other "
Dim o As Object
Dim i As Long
Dim lBarY As Long
Dim lIndex As Long
Dim lPicIndex As Long
Dim lBar As Long
Dim lXOffset As Long
Dim lYOffset As Long

   GetCursorPos m_tPtDock
   
   ' Find a picture box for this item:
   lPicIndex = findPictureBox()
   cXAHorz = cXAHorz + 10 + 12
   cYAHorz = cYAHorz + 2
   cXAVert = cXAVert + 10 + 12
   cYAVert = cYAVert + 2
   'Debug.Print Key, cXAHorz, cYAHorz, cXAVert, cYAVert
   
   If (m_bNonDockingArea) Then
      If (UserControl.Extender.Align = vbAlignTop) Then
         lYOffset = m_lNonDockingAreaSize
      ElseIf (UserControl.Extender.Align = vbAlignLeft) Then
         lXOffset = m_lNonDockingAreaSize
      End If
   End If
   
   If (UserControl.Extender.Align = vbAlignTop) Or (UserControl.Extender.Align
    = vbAlignBottom) Then
      picBar(lPicIndex).Move (lX + lXOffset) * Screen.TwipsPerPixelX, lYOffset
       * Screen.TwipsPerPixelY, cXAHorz * Screen.TwipsPerPixelX, cYAHorz *
       Screen.TwipsPerPixelX
   Else
      picBar(lPicIndex).Move lXOffset * Screen.TwipsPerPixelX, (lX + lYOffset)
       * Screen.TwipsPerPixelY, cYAVert * Screen.TwipsPerPixelX, cXAVert *
       Screen.TwipsPerPixelY
   End If
   If (m_bXPStyle) Then
      picBar(lPicIndex).BackColor = VSNetControlColor
   Else
      picBar(lPicIndex).BackColor = vbButtonFace
   End If
   picBar(lPicIndex).Visible = True
   SetProp picBar(lPicIndex).hwnd, DOCKCONTAINERBARINDEX, lPicIndex
   
   ' Resize the internal array which holds the information
   m_lCount = m_lCount + 1
   ReDim Preserve m_tRow(1 To m_lCount) As tDockedRow
   For i = 1 To m_lCount
      ReDim Preserve m_tRow(i).tBar(1 To m_lCount) As tDockedBar
   Next i
   ReDim Preserve m_pic(1 To m_lCount) As Long
   m_pic(m_lCount) = lPicIndex
   
   If lRow = -1 Then
      
      ' Add a new bar & row:
      m_lRows = m_lRows + 1
      lRow = m_lRows
      With m_tRow(lRow)
         .lCount = 1
         With .tBar(1)
            .lX = lX
            .lXSingleRow = lX
            If Horizontal Then
               .cXA = cXAHorz
               .cYA = cYAHorz
            Else
               .cXA = cXAVert
               .cYA = cYAVert
            End If
            .cXAHorz = cXAHorz
            .cYAHorz = cYAHorz
            .cXAVert = cXAVert
            .cYAVert = cYAVert
            .cx = .cXA
            .sKey = key
            .sTitle = sTitle
            .lIdx = m_lCount
            .bFillRow = bFillRow
            .lOffsetX = 0
            .bCanDockHorizontal = bCanDockHorizontal
            .bCanDockVertical = bCanDockVertical
            .bCanClose = bCanClose
         End With
         If Horizontal Then
            If cYAHorz > .lHeight Then
               .lHeight = cYAHorz
            End If
         Else
            If cYAVert > .lHeight Then
               .lHeight = cYAVert
            End If
         End If
      End With
   
   ElseIf lRow = 0 Then
   
      ' Insert before
      For i = m_lRows To 1 Step -1
         LSet m_tRow(i + 1) = m_tRow(i)
         For lBar = 1 To m_tRow(i).lCount
            LSet m_tRow(i + 1).tBar(lBar) = m_tRow(i).tBar(lBar)
         Next lBar
      Next i
      m_lRows = m_lRows + 1
      With m_tRow(1)
         .lCount = 1
         With .tBar(1)
            .lX = lX
            .lXSingleRow = lX
            If Horizontal Then
               .cXA = cXAHorz 'tR.right - tR.left
               .cYA = cYAHorz 'tR.bottom - tR.top
            Else
               .cXA = cXAVert 'tR.bottom - tR.top
               .cYA = cYAVert 'tR.right - tR.left
            End If
            .cXAHorz = cXAHorz
            .cYAHorz = cYAHorz
            .cXAVert = cXAVert
            .cYAVert = cYAVert
            .cx = .cXA
            .sKey = key
            .sTitle = sTitle
            .lIdx = m_lCount
            .bFillRow = bFillRow
            .lOffsetX = 0
            .bCanDockHorizontal = bCanDockHorizontal
            .bCanDockVertical = bCanDockVertical
            .bCanClose = bCanClose
         End With
         If Horizontal Then
            If cYAHorz + 2 > .lHeight Then
               .lHeight = cYAHorz + 2
            End If
         Else
            If cYAVert + 2 > .lHeight Then
               .lHeight = cYAVert + 2
            End If
         End If
      End With
   
   Else
      ' Adding to an existing row
      ' Check if we've got a row with the fill setting here:
      If (m_tRow(lRow).lCount > 0) Then
         If (m_tRow(lRow).tBar(1).bFillRow) Then
            ' can't do it
            Err.Raise 23067, App.EXEName & ".vbalDockContainer", "Can't add to
             a row which contains a bar with the bFillRow property"
            Exit Sub
         End If
      End If
      
      With m_tRow(lRow)
         .lCount = .lCount + 1
         With .tBar(.lCount)
            .lX = lX
            If Horizontal Then
               .cXA = cXAHorz 'tR.right - tR.left
               .cYA = cYAHorz 'tR.bottom - tR.top
            Else
               .cXA = cXAVert 'tR.bottom - tR.top
               .cYA = cYAVert 'tR.right - tR.left
            End If
            .cXAHorz = cXAHorz
            .cYAHorz = cYAHorz
            .cXAVert = cXAVert
            .cYAVert = cYAVert
            .cx = .cXA
            .sKey = key
            .sTitle = sTitle
            .lIdx = m_lCount
            .bFillRow = bFillRow
            .lOffsetX = 0
            .bCanDockHorizontal = bCanDockHorizontal
            .bCanDockVertical = bCanDockVertical
            .bCanClose = bCanClose
         End With
         If Horizontal Then
            If cYAHorz + 2 > .lHeight Then
               .lHeight = cYAHorz + 2
            End If
         Else
            If cYAVert + 2 > .lHeight Then
               .lHeight = cYAVert + 2
            End If
         End If
      End With
      AutoSize
   End If
   
   Resize
   drawBar lPicIndex
   UserControl.Refresh
   
   ' Event
   RaiseEvent Docked(key)

End Sub

Private Property Get Horizontal() As Boolean
   If (UserControl.Extender.Align = vbAlignTop) Or (UserControl.Extender.Align
    = vbAlignBottom) Then
      Horizontal = True
   End If
End Property

Private Sub hideControlsInToolbar(ByVal lhWnd As Long, ByVal bState As Boolean)
Dim lPtr As Long
Dim i As Long
Dim iIndex As Long
Dim bMustHide As Boolean
Dim vKey As Variant

   lPtr = GetProp(lhWnd, "vbalTbar:ControlPtr")
   If Not (lPtr = 0) Then
      Dim ctl As Object
      Set ctl = objectFromPtr(lPtr)
      If (bState) Then
         For i = 0 To ctl.ButtonCount - 1
            If Not (ctl.ButtonControl(i) = 0) Then
               bMustHide = True
               Exit For
            End If
         Next i
         If (bMustHide) Then
            m_iHiddenItemCount = m_iHiddenItemCount + 1
            ReDim Preserve m_tHiddenItems(1 To m_iHiddenItemCount) As
             tVerticalHiddenButtons
            m_tHiddenItems(m_iHiddenItemCount).hwnd = lhWnd
            Set m_tHiddenItems(m_iHiddenItemCount).cKeys = New Collection
            For i = 0 To ctl.ButtonCount - 1
               If Not (ctl.ButtonControl(i) = 0) Then
                  m_tHiddenItems(m_iHiddenItemCount).cKeys.Add
                   ctl.ButtonKey(i), ctl.ButtonKey(i)
                  ctl.ButtonVisible(i) = False
               End If
            Next i
         End If
      Else
         For i = 1 To m_iHiddenItemCount
            If (m_tHiddenItems(i).hwnd = lhWnd) Then
               iIndex = i
               Exit For
            End If
         Next i
         If (iIndex > 0) Then
            For Each vKey In m_tHiddenItems(iIndex).cKeys
               ctl.ButtonVisible(vKey) = True
            Next
            If (m_iHiddenItemCount > 1) Then
               For i = iIndex To m_iHiddenItemCount + 1
                  LSet m_tHiddenItems(i) = m_tHiddenItems(i + 1)
               Next i
               m_iHiddenItemCount = m_iHiddenItemCount - 1
            Else
               m_iHiddenItemCount = 0
               Erase m_tHiddenItems
            End If
         End If
      End If
   End If
End Sub

Public Sub Capture( _
      ByVal key As String, _
      ByVal hWndA As Long _
   )
Attribute Capture.VB_Description = "Captures a window into the bar with the
 specified key.  The bar must be docked."
Dim lIndex As Long
Dim lRow As Long
Dim lBar As Long
Dim lTheRow As Long
Dim lTheBar As Long
Dim tR As RECT
Dim cXA As Long
Dim cYA As Long
   
   If hWndA <> 0 Then
      If getBarForKey(key, lIndex) Then
         For lRow = 1 To m_lRows
            For lBar = 1 To m_tRow(lRow).lCount
               If m_tRow(lRow).tBar(lBar).sKey = key Then
                  lTheRow = lRow
                  lTheBar = lBar
                  cXA = m_tRow(lRow).tBar(lBar).cXA
                  cYA = m_tRow(lRow).tBar(lBar).cYA
                  Exit For
               End If
            Next lBar
         Next lRow
         If Not (Horizontal) Then
            hideControlsInToolbar hWndA, True
         End If
         SetParent hWndA, picBar(lIndex).hwnd
         If UserControl.Extender.Align = vbAlignTop Or
          UserControl.Extender.Align = vbAlignBottom Then
            MoveWindow hWndA, 10, 1, cXA - 22, cYA - 2, 1
         Else
            MoveWindow hWndA, 1, 10, cYA - 2, cXA - 22, 1
         End If
         'Debug.Print "Capture:", hWndA
         picBar(lIndex).Tag = hWndA
         
         ' It is possible but unlikely these messages are already attached:
         On Error Resume Next
         AttachMessage Me, picBar(lIndex).hwnd, WM_ERASEBKGND
         AttachMessage Me, picBar(lIndex).hwnd, WM_DESTROY
      Else
         ' is an error
         Err.Raise 9, App.EXEName & ".vbalDockContainer", "The key '" & key &
          "' is not associated with this bar"
      End If
   End If
End Sub

Private Sub Create( _
      Optional ByVal lMinBarSize As Long = 48, _
      Optional ByVal lMinBestBarSize As Long = 48 _
   )
      
   m_hWndCtl = UserControl.hwnd
   SetProp m_hWndCtl, DOCKCONTAINERID, ObjPtr(Me)
   m_lMinBarSize = lMinBarSize
   m_lMinBestBarSize = lMinBestBarSize
   
   On Error Resume Next
   m_hWndParent = UserControl.Parent.hwnd
   SetProp m_hWndCtl, DOCKCONTAINERPARENTHWND, m_hWndParent
   SetProp m_hWndCtl, DOCKCONTAINERVERTICAL, Not (Horizontal)
   On Error GoTo 0
   'If mdiChildhWnd(m_hWndParent) <> 0 Then
   '   ' check if we need to do anything:
   '   If GetProp(m_hWndParent, MDITOOLBARMENUID) = 0 Then
   '      Set m_cMDIToolbarMenu = New pcMDIToolbarMenu
   '      m_cMDIToolbarMenu.Attach m_hWndParent
   '      SetProp m_hWndParent, MDITOOLBARMENUID, ObjPtr(m_cMDIToolbarMenu)
   '   End If
   'End If
   
   
End Sub
Public Sub AutoSize()
Attribute AutoSize.VB_Description = "Attempts to best size all the bars within
 each current row of the dock control."
Dim i As Long
   For i = 1 To m_lRows
      rowSize i
   Next i
   Resize
End Sub
Public Sub Resize()
Attribute Resize.VB_Description = "Raised when this dock control is resized."
Dim i As Long
Dim j As Long
Dim o As Object
Dim ctlCont As Object
Dim lY As Long
Dim tR As RECT
Dim tWR As RECT
Dim lhWnd As Long
Dim lSize As Long
Dim lXOffset As Long
Dim lYOffset As Long
Dim lStart As Long

   If m_lCount > 0 Then
      If (m_bNonDockingArea) Then
         If (Horizontal) Then
            lYOffset = m_lNonDockingAreaSize * Abs(UserControl.Extender.Align =
             vbAlignTop)
         Else
            lXOffset = m_lNonDockingAreaSize * Abs(UserControl.Extender.Align =
             vbAlignLeft)
         End If
      End If
      
      ' We have at least one bar
      If (m_bLockToolbars) Then
         lStart = 1
      Else
         lStart = 10
      End If
      lY = 0
      For i = 1 To m_lRows
         With m_tRow(i)
            For j = 1 To .lCount
               GetWindowRect picBar(m_pic(.tBar(j).lIdx)).hwnd, tR
               If .tBar(j).bFillRow Then
                  GetClientRect m_hWndCtl, tWR
                  If Horizontal Then
                     .tBar(j).lX = tWR.Left
                     .tBar(j).cx = tWR.Right - tWR.Left
                  Else
                     .tBar(j).lX = tWR.Top
                     .tBar(j).cx = tWR.Bottom - tWR.Top
                  End If
               End If
               lhWnd = 0
               If Horizontal Then
                  On Error Resume Next
                  picBar(m_pic(.tBar(j).lIdx)).Move (.tBar(j).lX + lXOffset) *
                   Screen.TwipsPerPixelX, (lY + lYOffset) *
                   Screen.TwipsPerPixelY, .tBar(j).cx * Screen.TwipsPerPixelX,
                   .lHeight * Screen.TwipsPerPixelY
                  lhWnd = getCapturehWndForBar(m_pic(.tBar(j).lIdx))
                  If Not (lhWnd = 0) Then
                     If .tBar(j).cx < .tBar(j).cXA Then
                        ' too small:
                        MoveWindow lhWnd, lStart, 1 + (.lHeight - .tBar(j).cYA)
                         / 2, .tBar(j).cx - 22, .tBar(j).cYA - 2, 1
                     Else
                        ' ok
                        MoveWindow lhWnd, lStart, 1 + (.lHeight - .tBar(j).cYA)
                         / 2, .tBar(j).cXA - 22, .tBar(j).cYA - 2, 1
                     End If
                  End If
                  picBar(m_pic(.tBar(j).lIdx)).Refresh
                  On Error GoTo 0
               Else
                  On Error Resume Next
                  picBar(m_pic(.tBar(j).lIdx)).Move (lY + lXOffset) *
                   Screen.TwipsPerPixelY, (.tBar(j).lX + lYOffset) *
                   Screen.TwipsPerPixelX, .lHeight * Screen.TwipsPerPixelX,
                   .tBar(j).cx * Screen.TwipsPerPixelY
                  lhWnd = getCapturehWndForBar(m_pic(.tBar(j).lIdx))
                  If lhWnd <> 0 Then
                     If .tBar(j).cx < .tBar(j).cXA Then
                        ' too small:
                        MoveWindow lhWnd, 1, lStart, .tBar(j).cYA - 2,
                         .tBar(j).cx - 22, 1
                     Else
                        ' ok
                        MoveWindow lhWnd, 1, lStart, .tBar(j).cYA - 2,
                         .tBar(j).cXA - 22, 1
                     End If
                  End If
                  picBar(m_pic(.tBar(j).lIdx)).Refresh
                  On Error GoTo 0
               End If
               setChevron m_pic(.tBar(j).lIdx), (.tBar(j).cx < .tBar(j).cXA)

            Next j
            lY = lY + .lHeight
         End With
      Next i
      
      GetWindowRect m_hWndCtl, tR
      lhWnd = GetParent(m_hWndCtl)
      MapWindowPoints HWND_DESKTOP, lhWnd, tR, 2
      lSize = 0
      If m_bNonDockingArea Then
         lSize = lSize + m_lNonDockingAreaSize
      End If
      If Horizontal Then
         'UserControl.Extender.Move tR.Left * Screen.TwipsPerPixelX, tR.Top *
          Screen.TwipsPerPixelY, (tR.Right - tR.Left) * Screen.TwipsPerPixelX,
          (lY + lSize) * Screen.TwipsPerPixelY
         If Not (UserControl.Extender.height = (lY + lSize) *
          Screen.TwipsPerPixelY) Then
            UserControl.Extender.height = (lY + lSize) * Screen.TwipsPerPixelY
         End If
      Else
         'UserControl.Extender.Move tR.Left * Screen.TwipsPerPixelX, tR.Top *
          Screen.TwipsPerPixelY, (lY + lSize) * Screen.TwipsPerPixelX,
          (tR.Bottom - tR.Top) * Screen.TwipsPerPixelY
         If Not (UserControl.Extender.width = (lY + lSize) *
          Screen.TwipsPerPixelX) Then
            UserControl.Extender.width = (lY + lSize) * Screen.TwipsPerPixelX
         End If
      End If
      If Not lY = (tR.Bottom - tR.Top) Then
         RaiseEvent SizeChanged
      End If
      
   Else
      ' No Bars:
      GetWindowRect m_hWndCtl, tR
      lSize = 0
      If m_bNonDockingArea Then
         lSize = lSize + m_lNonDockingAreaSize
      End If
      If Horizontal Then
         UserControl.Extender.Move tR.Left * Screen.TwipsPerPixelX, tR.Top *
          Screen.TwipsPerPixelY, (tR.Right - tR.Left) * Screen.TwipsPerPixelX,
          lSize * Screen.TwipsPerPixelY
      Else
         UserControl.Extender.Move tR.Left * Screen.TwipsPerPixelX, tR.Top *
          Screen.TwipsPerPixelY, lSize * Screen.TwipsPerPixelY, (tR.Bottom -
          tR.Top) * Screen.TwipsPerPixelY
      End If
      If Not lY = (tR.Bottom - tR.Top) Then
         RaiseEvent SizeChanged
      End If
      
   End If
   
   UserControl.Refresh
   
End Sub
Private Function setChevron(ByVal lIndex As Long, ByVal bState As Boolean)
   If Not (m_tChevron(lIndex).bShow = bState) Then
      m_tChevron(lIndex).bShow = bState
      drawBar lIndex
   End If
End Function
Private Function performChevron(ByVal lIndex As Long) As Long
Dim sKey As String
Dim lX As Long
Dim lY As Long
Dim lRow As Long
Dim lBar As Long
Dim tP As POINTAPI
   '
   For lRow = 1 To m_lRows
      With m_tRow(lRow)
         For lBar = 1 To .lCount
            If m_pic(.tBar(lBar).lIdx) = lIndex Then
               sKey = .tBar(lBar).sKey
               Exit For
            End If
         Next lBar
      End With
   Next lRow
      
   If (Horizontal) Then
      tP.x = m_tChevron(lIndex).tR.Left
      tP.y = m_tChevron(lIndex).tR.Bottom
      MapWindowPoints picBar(lIndex).hwnd, 0, tP, 1
      tP.y = tP.y - 1
   Else
      tP.x = m_tChevron(lIndex).tR.Right
      tP.y = m_tChevron(lIndex).tR.Top
      MapWindowPoints picBar(lIndex).hwnd, 0, tP, 1
      tP.x = tP.x - 1
   End If
   OnChevronPress sKey, tP.x, tP.y
   
   Debug.Print "redraw chevron"
   m_tChevron(lIndex).bMouseOver = False
   m_tChevron(lIndex).bMouseDown = False
   m_tmr.Item = ""
   m_tmr.Interval = 0
   drawBar lIndex
   
   '
End Function
Friend Sub OnChevronPress(ByVal sKey As String, x As Long, y As Long)
   RaiseEvent ChevronPress(sKey, x, y)
End Sub
Friend Function OnCloseClick(ByVal sKey As String) As Boolean
Dim bCancel As Boolean
   RaiseEvent BarClose(sKey, bCancel)
   OnCloseClick = Not (bCancel)
End Function
Private Function mouseDown( _
      ByVal lIndex As Long, _
      ByVal x As Single, _
      ByVal y As Single _
   ) As Boolean

Dim lX As Long, lY As Long
Dim i As Long, j As Long
Dim lRow As Long, lBar As Long
Dim tP As POINTAPI
Dim o As Object
Dim ctl As Object
   
   ' ---------------------------------------------------------------------------
   ' In Chevron?
   ' ---------------------------------------------------------------------------
   lX = x \ Screen.TwipsPerPixelX
   lY = y \ Screen.TwipsPerPixelY
   With m_tChevron(lIndex)
      If lX >= .tR.Left And lX <= .tR.Right Then
         If lY >= .tR.Top And lY <= .tR.Bottom Then
            .bMouseOver = True
            .bMouseDown = True
            drawBar lIndex
            performChevron lIndex
            Exit Function
         End If
      End If
   End With

   
   ' ---------------------------------------------------------------------------
   ' Dragging a docking bar?
   ' ---------------------------------------------------------------------------
   If Not m_bLockToolbars Then
      m_iActiveBar = 0
      
      For i = 1 To m_lRows
         With m_tRow(i)
            For j = 1 To .lCount
               .tBar(j).bActiveBar = (lIndex = m_pic(.tBar(j).lIdx))
               
               If (.tBar(j).bActiveBar) Then
                  m_iActiveBar = .tBar(j).lIdx
                  'Debug.Print "ActiveBar:", m_iActiveBar
                  ' Store x,y:
                  tP.x = x \ Screen.TwipsPerPixelX
                  tP.y = y \ Screen.TwipsPerPixelY
                  Set o = picBar(lIndex)
                  MapWindowPoints o.hwnd, m_hWndCtl, tP, 1
                  If Horizontal Then
                     .tBar(j).lOffsetX = -x \ Screen.TwipsPerPixelX
                     .tBar(j).lThisX = tP.x - .tBar(j).lOffsetX
                     .tBar(j).lThisY = tP.y
                  Else
                     .tBar(j).lOffsetX = -y \ Screen.TwipsPerPixelY
                     .tBar(j).lThisX = tP.y - .tBar(j).lOffsetX
                     .tBar(j).lThisY = tP.x
                  End If
                  .tBar(j).lLastX = .tBar(j).lThisX
                  .tBar(j).lLastY = .tBar(j).lThisY
                  .tBar(j).eAction = eNewAction
                  
                  m_lIndexActiveBar = m_pic(.tBar(j).lIdx)
                  
                  ' redirect all mouse messages to the usercontrol:
                  picBar(lIndex).MousePointer = vbSizeAll
                  
                  SetCapture m_hWndCtl
                  mouseDown = True
               End If
            Next j
         End With
      Next i
   End If
   
End Function

Private Sub getActiveBarLocation( _
      ByRef lRow As Long, _
      ByRef lBar As Long _
   )
   'Debug.Assert (m_iActiveBar <> 0)
   lRow = 0
   lBar = 0
   For lRow = 1 To m_lRows
      'Debug.Print "(" & m_iActiveBar; ") Row:"; lRow; "-";
      With m_tRow(lRow)
         For lBar = 1 To .lCount
            'Debug.Print lBar; "="; .tBar(lBar).lIdx; ",";
            If m_iActiveBar = .tBar(lBar).lIdx Then
               ' Found it
               'Debug.Print "Found"
               Exit Sub
            End If
         Next lBar
      End With
   Next lRow
   'Debug.Print "Not found"
   'Debug.Print
   lRow = 0
   lBar = 0
   
End Sub
Private Sub getLocationOfBar( _
      ByRef lRow As Long, _
      ByRef lBar As Long _
   )
   
   lRow = 0
   lBar = 0
   For lRow = 1 To m_lRows
      With m_tRow(lRow)
         For lBar = 1 To .lCount
            If m_iActiveBar = .tBar(lBar).lIdx Then
               Exit Sub
            End If
         Next lBar
      End With
   Next lRow
   lRow = 0
   lBar = 0
   
End Sub

Private Sub mouseMove( _
      x As Single, y As Single _
   )
Dim lRow As Long, lBar As Long
Dim lX As Long, lY As Long
Dim cx As Long, cy As Long
Dim pic As PictureBox
Dim tR As RECT
Dim tS As RECT
Dim tP As POINTAPI
Dim bNextIsRowDown As Boolean
Dim bNextIsRowUp As Boolean

   If m_iActiveBar > 0 Then
   
      getActiveBarLocation lRow, lBar
      
      ' Bands on row: m_tRow(lRow).lCount
      ' Rows < Bars:
   
      With m_tRow(lRow).tBar(lBar)
      
         ' Get the control which is  being moved
         Set pic = picBar(m_pic(.lIdx))
         GetWindowRect pic.hwnd, tR
         MapWindowPoints HWND_DESKTOP, m_hWndCtl, tR, 2
         
         If Horizontal Then
            tP.x = x \ Screen.TwipsPerPixelX
            tP.y = y \ Screen.TwipsPerPixelY
         Else
            ' Swap around x,y coords:
            tP.x = y \ Screen.TwipsPerPixelY
            tP.y = x \ Screen.TwipsPerPixelX
            tS.Left = tR.Top
            tS.Top = tR.Left
            tS.Right = tR.Bottom
            tS.Bottom = tR.Right
            LSet tR = tS
         End If
         
         '
         lX = tP.x + .lOffsetX
         lY = tP.y
         .lThisX = lX
         .lThisY = lY
               
      
         ' ======================================================
         ' START: Y DIRECTION
         ' ======================================================
         cy = .lThisY - .lLastY
         If Abs(cy) > 8 Then
            ' We can make a move:
            If Sgn(cy) = 1 Then
               ' ------------------------------------------------
               ' DOWN MOVEMENT
               ' ------------------------------------------------
               If lRow = m_lRows Then
                  ' Last row
                  If m_tRow(lRow).lCount = 1 Then
                     If dragOff(lRow, lBar, False, 1) Then
                        '
                     End If
                     Exit Sub
                  End If
               End If
                                                         
               If .eAction = eNewAction Then
                  If (m_tRow(lRow).lCount > 1) Or _
                     (m_tRow(lRow).tBar(lBar).bFillRow) Then
                     bNextIsRowDown = True
                  Else
                     If lRow < m_lRows Then
                        If m_tRow(lRow + 1).tBar(1).bFillRow Then
                           bNextIsRowDown = True
                        End If
                     End If
                  End If

                  If bNextIsRowDown Then
                     .eAction = eShareRowDown
                  Else
                     .eAction = eNewRowDown
                  End If
               End If
               
               Select Case .eAction
               Case eShareRowUp
                  ' Last action was share up, next action
                  ' will be to new row down
                  If .lThisY > tR.Top + (tR.Bottom - tR.Top) \ 2 Then
                     ' new down
                     rearrangeNewRowDown
                  End If
                  
               Case eShareRowDown
                  ' Last action was share down, next action
                  ' will be new row down:
                  If .lThisY > tR.Bottom Then
                     ' New down
                     rearrangeNewRowDown
                  End If
                  
               Case eNewRowUp
                  ' Last action was new row up, next action
                  ' will be to share row down:
                  If .lThisY > tR.Top + (tR.Bottom - tR.Top) \ 2 Then
                     rearrangeShareRowUp
                  End If
                  
               Case eNewRowDown
                  ' Last action was new row down, next action
                  ' will be to share row down:
                  If .lThisY > tR.Bottom Then
                     rearrangeShareRowDown
                  End If
                              
               End Select
                        
            Else
               
               ' ------------------------------------------------
               ' UP MOVEMENT
               ' ------------------------------------------------
               If lRow = 1 Then
                  ' First row
                  If m_tRow(lRow).lCount = 1 Then
                     ' check for dragging off:
                     If dragOff(lRow, lBar, False, -1) Then
                        '
                     End If
                     Exit Sub
                  End If
               End If
               
               If .eAction = eNewAction Then
                  If (m_tRow(lRow).lCount > 1) Or
                   (m_tRow(lRow).tBar(lBar).bFillRow) Then
                     bNextIsRowUp = True
                  Else
                     If lRow > 1 Then
                        If m_tRow(lRow - 1).tBar(1).bFillRow Then
                           bNextIsRowUp = True
                        End If
                     End If
                  End If
                  
                  If bNextIsRowUp Then
                     .eAction = eShareRowUp
                  Else
                     .eAction = eNewRowUp
                  End If
               End If
               
               Select Case .eAction
               Case eShareRowUp
                  ' Last action was share up, next action
                  ' will be to new row down
                  If .lThisY < tR.Top + (tR.Bottom - tR.Top) \ 2 Then
                     ' new up
                     rearrangeNewRowUp
                  End If
                  
               Case eShareRowDown
                  ' Last action was share down, next action
                  ' will be new row down:
                  If .lThisY < tR.Top Then
                     ' New up
                     rearrangeNewRowUp
                  End If
                  
               Case eNewRowUp
                  ' Last action was new row up, next action
                  ' will be to share row down:
                  If .lThisY < tR.Top + (tR.Bottom - tR.Top) \ 2 Then
                     rearrangeShareRowUp
                  End If
                  
               Case eNewRowDown
                  ' Last action was new row down, next action
                  ' will be to share row down:
                  If .lThisY < tR.Top Then
                     rearrangeShareRowUp
                  End If
                              
               End Select
               
               
            End If
         
         Else
            ' insufficient movement to do anything
         End If
         ' ======================================================
         ' END: Y DIRECTION
         ' ======================================================
         
         
         ' ======================================================
         ' START: X DIRECTION
         ' ======================================================
         cx = .lThisX - .lLastX
         If Abs(cx) > 8 Then
            ' Fundamentally here we check if the x coord is
            ' moved outside the boundary of the item to the
            ' sgn(cX) of the current bar.  If so then we
            ' swap them.
            
            If Sgn(cx) = -1 Then
               ' Moving left.
               checkMoveLeft
               
            Else
               ' Moving right
               checkMoveRight
               
            End If
         Else
            ' insufficient movement to do anything
         End If
         ' ======================================================
         ' END: X DIRECTION
         ' ======================================================
         
      End With
   End If
End Sub

Private Function getCapturehWndForBar(ByVal lIndex As Long) As Long
   If IsNumeric(picBar(lIndex).Tag) Then
      getCapturehWndForBar = picBar(lIndex).Tag
   End If
End Function


Private Function dragOff(ByVal lRow As Long, ByVal lBar As Long, ByVal
 bHorizontal As Boolean, ByVal iDir As Long) As Boolean
Dim tP As POINTAPI
Dim tR As RECT
   
   If m_bAllowDragOff Then
   
      GetCursorPos tP
      If Abs(tP.x - m_tPtDock.x) > 8 Or Abs(tP.y - m_tPtDock.y) > 8 Then
         m_tPtDock.x = -20000
         m_tPtDock.y = -20000
      Else
         Exit Function
      End If
      
      ' check for hysteresis (i.e. > 6 pixels from control edge)
      GetWindowRect m_hWndCtl, tR
      If Not Horizontal Then
         bHorizontal = Not (bHorizontal)
      End If
      If bHorizontal Then
         If iDir > 0 Then
            If tP.x < tR.Right + 12 Then
               Exit Function
            End If
         Else
            If tP.x > tR.Left - 12 Then
               Exit Function
            End If
         End If
      Else
         If iDir > 0 Then
            If tP.y < tR.Bottom + 12 Then
               Exit Function
            End If
         Else
            If tP.y > tR.Top - 12 Then
               Exit Function
            End If
         End If
      End If
      GetCursorPos tP
      tP.x = (tP.x - 4) * Screen.TwipsPerPixelX
      tP.y = (tP.y - 4) * Screen.TwipsPerPixelY
      If tP.x < 0 Then tP.x = 0
      If tP.y < 0 Then tP.y = 0
      
      dragOff = undock(lRow, lBar, tP.x, tP.y)
      
   End If
End Function

Private Function undock( _
      ByVal lRow As Long, ByVal lBar As Long, _
      ByVal x As Long, ByVal y As Long _
   ) As Boolean
Dim hWndA As Long
Dim sKey As String
Dim lIndex As Long
Dim cXAHorz As Long
Dim cYAHorz As Long
Dim cXAVert As Long
Dim cYAVert As Long
   
   ' get any captured bar:
   getBarForKey m_tRow(lRow).tBar(lBar).sKey, lIndex
   'Debug.Print "Undock", lIndex, m_tRow(lRow).tBar(lBar).sKey
   If (lIndex > -1) Then
      hWndA = getCapturehWndForBar(lIndex)
   Else
      'Debug.Print ""
   End If
   
   ' work out size of undocked toolbar:
   Dim f As New frmToolbar
   f.width = (m_tRow(lRow).tBar(lBar).cXA + GetSystemMetrics(SM_CXFRAME) * 2 +
    GetSystemMetrics(SM_CXBORDER) * 2) * Screen.TwipsPerPixelX
   f.height = (m_tRow(lRow).tBar(lBar).cYA + GetSystemMetrics(SM_CYFRAME) * 2 +
    GetSystemMetrics(SM_CYBORDER) * 2 + GetSystemMetrics(SM_CYCAPTION) - 4) *
    Screen.TwipsPerPixelY
   
   ' eval position to show
   f.Move x, y
   With m_tRow(lRow).tBar(lBar)
      f.init .sKey, _
         m_hWndCtl, _
         m_hWndParent, _
         .cXAHorz, .cYAHorz, .cXAVert, .cYAVert, _
         .bFillRow, _
         .sTitle, _
         .bCanDockHorizontal, .bCanDockVertical, _
         .bCanClose, _
         m_bXPStyle
   End With
   
   ' remove the bar from the control so it can be seen
   ' floating instead:
   If Not (hWndA = 0) Then
      ShowWindow hWndA, 0
      SetParent hWndA, 0
   End If
   With m_tRow(lRow).tBar(lBar)
      sKey = .sKey
      cXAHorz = .cXAHorz - 22
      cYAHorz = .cYAHorz - 2
      cXAVert = .cXAVert - 22
      cYAVert = .cYAVert - 2
   End With
   Remove sKey
   
   ' show in position & redirect mouse messages
   f.Show , UserControl.Parent
   f.SetFocus
   SetCapture f.hwnd
   
   ' ensure any captured window moves correctly:
   f.Capture hWndA
   
   f.BandSizeChange _
      cXAHorz, cYAHorz, _
      cXAVert, cYAVert

   ' now store a reference that we've dragged this item off:
   m_iDragOffCount = m_iDragOffCount + 1
   ReDim Preserve m_lDragOff(1 To m_iDragOffCount) As Long
   ReDim Preserve m_sDragOff(1 To m_iDragOffCount) As String
   m_lDragOff(m_iDragOffCount) = f.hwnd
   m_sDragOff(m_iDragOffCount) = sKey
   
   undock = True
   
   ' Event:
   RaiseEvent Undocked(sKey)
   
   m_iActiveBar = 0

End Function

Private Sub checkMoveLeft()
Dim lRow As Long, lBar As Long
Dim i As Long, j As Long
Dim tB As tDockedBar
Dim lX As Long
Dim tR As RECT
Dim lSize As Long
Dim lWPrior As Long
Dim lXPrior As Long
Dim lW As Long, lAW As Long
   
   getActiveBarLocation lRow, lBar
   
   ' have we moved off?
   If lBar = 1 Then
      If m_tRow(lRow).tBar(1).lThisX - m_tRow(lRow).tBar(1).lOffsetX < 0 Then
         If dragOff(lRow, lBar, True, -1) Then
            Exit Sub
         End If
      End If
   End If
   
   If lRow > 0 Then
      If m_tRow(lRow).tBar(lBar).bFillRow Then
         ' don't move
         Exit Sub
      End If
   
      
      If m_tRow(lRow).lCount = 1 Then
         
         ' 1 item on row
         
         GetWindowRect m_hWndCtl, tR
         If Horizontal Then
            lSize = tR.Right - tR.Left
         Else
            lSize = tR.Bottom - tR.Top
         End If
         ' constrained by dimension:
         lX = m_tRow(lRow).tBar(lBar).lThisX
         If m_tRow(lRow).tBar(lBar).lThisX < 0 Then
            lX = 0
         Else
            If m_tRow(lRow).tBar(lBar).lThisX + m_tRow(lRow).tBar(lBar).cx >
             lSize Then
               lX = lSize - m_tRow(lRow).tBar(lBar).cx
            End If
         End If
         m_tRow(lRow).tBar(lBar).lX = lX
         m_tRow(lRow).tBar(lBar).lXSingleRow = lX
         Resize
      
      Else
         
         ' more than one item on row:
      
         If lBar > 1 Then
   
            ' check against midpoint of prior bar:
            lX = m_tRow(lRow).tBar(lBar - 1).lX + m_tRow(lRow).tBar(lBar -
             1).cx \ 2
            If m_tRow(lRow).tBar(lBar).lThisX -
             m_tRow(lRow).tBar(lBar).lOffsetX < lX Then
               ' time to move. Swap lBar with lBar -1 and then autosize:
               LSet tB = m_tRow(lRow).tBar(lBar - 1)
               LSet m_tRow(lRow).tBar(lBar - 1) = m_tRow(lRow).tBar(lBar)
               m_tRow(lRow).tBar(lBar - 1).lX = tB.lX
               LSet m_tRow(lRow).tBar(lBar) = tB
               m_tRow(lRow).tBar(lBar).lX = m_tRow(lRow).tBar(lBar - 1).lX +
                m_tRow(lRow).tBar(lBar - 1).cx
               
               m_tRow(lRow).tBar(lBar).lLastX = m_tRow(lRow).tBar(lBar).lThisX
               m_tRow(lRow).tBar(lBar).lLastY = m_tRow(lRow).tBar(lBar).lThisY
               rowSize lRow
               Resize
            Else
            
               ' is there any movement possible in the bars?
               For j = 1 To m_tRow(lRow).lCount
                  lW = lW + m_tRow(lRow).tBar(j).cx
                  lAW = lAW + m_tRow(lRow).tBar(j).cXA
               Next j
               
               If lAW > lW Then
                  ' move the split point provided it won't make any bar smaller
                  ' than min width:
                  lWPrior = m_tRow(lRow).tBar(lBar - 1).cx
                  lXPrior = m_tRow(lRow).tBar(lBar - 1).lX
                  lX = m_tRow(lRow).tBar(lBar).lThisX
                  
                  If lX - lXPrior + 1 > m_lMinBarSize Then
                     ' First check whether our bar is maxwidth or not
                     If m_tRow(lRow).tBar(lBar).cx =
                      m_tRow(lRow).tBar(lBar).cXA Then
                        'Debug.Print "isMaxWidth"
                     Else
                        'Debug.Print "notMaxWidth"
                     End If
                  End If
               End If
            End If
         Else
            ' At leftmost position already.  The code currently prevents
            ' you from shifting the left most bar away from the 0 position
            ' when there is more than one bar on the row
            
         End If
      End If
   End If
End Sub

Private Sub checkMoveRight()
Dim lRow As Long, lBar As Long
Dim i As Long, j As Long
Dim tB As tDockedBar
Dim lX As Long
Dim tR As RECT
Dim lSize As Long
      
   getActiveBarLocation lRow, lBar
   
   ' have we moved off?
   If lBar = m_tRow(lRow).lCount Then
      GetWindowRect m_hWndCtl, tR
      If Horizontal Then
         lSize = tR.Right - tR.Left
      Else
         lSize = tR.Bottom - tR.Top
      End If
      If m_tRow(lRow).tBar(lBar).lThisX - m_tRow(lRow).tBar(lBar).lOffsetX >
       lSize Then
         If dragOff(lRow, lBar, True, 1) Then
            Exit Sub
         End If
      End If
   End If
   
   If m_tRow(lRow).tBar(lBar).bFillRow Then
      ' don't move
      Exit Sub
   End If
   
   If m_tRow(lRow).lCount = 1 Then
      GetWindowRect m_hWndCtl, tR
      If Horizontal Then
         lSize = tR.Right - tR.Left
      Else
         lSize = tR.Bottom - tR.Top
      End If
      ' constrained by dimension:
      If m_tRow(lRow).tBar(lBar).lThisX < 0 Then
         lX = 0
      ElseIf m_tRow(lRow).tBar(lBar).lThisX + m_tRow(lRow).tBar(lBar).cx >
       lSize Then
         lX = lSize - m_tRow(lRow).tBar(lBar).cx
      Else
         lX = m_tRow(lRow).tBar(lBar).lThisX
      End If
      m_tRow(lRow).tBar(lBar).lX = lX
      m_tRow(lRow).tBar(lBar).lXSingleRow = lX
      
      Resize
   Else
      If lBar < m_tRow(lRow).lCount Then
         ' left x of Leftmost subsequent bar:
         lX = m_tRow(lRow).tBar(lBar + 1).lX
         If m_tRow(lRow).tBar(lBar).lThisX + m_tRow(lRow).tBar(lBar).lOffsetX >
          lX Then
            ' time to move. Swap lBar with lBar + 1 and then autosize:
            LSet tB = m_tRow(lRow).tBar(lBar)
            LSet m_tRow(lRow).tBar(lBar) = m_tRow(lRow).tBar(lBar + 1)
            m_tRow(lRow).tBar(lBar).lX = tB.lX
            LSet m_tRow(lRow).tBar(lBar + 1) = tB
            m_tRow(lRow).tBar(lBar + 1).lX = m_tRow(lRow).tBar(lBar).lX +
             m_tRow(lRow).tBar(lBar).cx
   
            m_tRow(lRow).tBar(lBar).lLastX = m_tRow(lRow).tBar(lBar).lThisX
            m_tRow(lRow).tBar(lBar).lLastY = m_tRow(lRow).tBar(lBar).lThisY
            
            rowSize lRow
            Resize
         End If
      Else
         ' At rightmost position already
      End If
   End If
   
End Sub
Private Function sanity(ByVal sProcName As String) As Boolean
Dim lRow As Long
Dim lR As Boolean
   'Debug.Print sProcName
   lR = True
   For lRow = 1 To m_lRows
      'Debug.Print lRow, m_tRow(lRow).lCount
      If m_tRow(lRow).lCount = 0 Then
         Debug.Assert "!!!!!!FAILED!!!!!!" = ""
         lR = False
      End If
   Next lRow
   sanity = lR
End Function
Private Sub rearrangeShareRowUp()
Dim lRow As Long, lBar As Long
Dim i As Long, j As Long
Dim tB() As tDockedBar
Dim tBS As tDockedBar
Dim iC As Long

   Debug.Assert sanity("rearrangeShareRowUp:START")
   m_tPtDock.x = -20000
   m_tPtDock.y = -20000


   getActiveBarLocation lRow, lBar
   
   ' We shift the active bar onto the next row up, and shift
   ' up everything on subsequent rows up on.
   
   m_tRow(lRow).tBar(lBar).lLastX = m_tRow(lRow).tBar(lBar).lThisX
   m_tRow(lRow).tBar(lBar).lLastY = m_tRow(lRow).tBar(lBar).lThisY
   m_tRow(lRow).tBar(lBar).eAction = eNewAction
   
   ' Can we share the row?
   If m_tRow(lRow).tBar(lBar).bFillRow Then
      ' NO
      Exit Sub
   End If
   
   For i = lRow - 1 To m_lRows - 1
      If i = lRow - 1 Then
         ' Shifting onto the row:
         iC = m_tRow(i).lCount
         ReDim tB(1 To iC) As tDockedBar
         For j = 1 To iC
            LSet tB(j) = m_tRow(i).tBar(j)
         Next j
         
         m_tRow(i).lCount = iC + 1
         
         If m_tRow(lRow).tBar(lBar).lThisX - m_tRow(lRow).tBar(lBar).lOffsetX >
          m_lMinBarSize Then
            LSet m_tRow(i).tBar(m_tRow(i).lCount) = m_tRow(lRow).tBar(lBar)
            For j = 1 To iC
               LSet m_tRow(i).tBar(j) = tB(j)
            Next j
         Else
            LSet m_tRow(i).tBar(1) = m_tRow(lRow).tBar(lBar)
            For j = 2 To iC + 1
               LSet m_tRow(i).tBar(j) = tB(j - 1)
            Next j
         End If
      Else
         ' Moving up a row:
         m_tRow(i).lCount = m_tRow(i + 1).lCount
         For j = 1 To m_tRow(i + 1).lCount
            LSet m_tRow(i).tBar(j) = m_tRow(i + 1).tBar(j)
         Next j
      End If
   Next i
   m_lRows = m_lRows - 1
      
   AutoSize
   
   Debug.Assert sanity("rearrangeShareRowUp:END")
   
End Sub

Private Sub rearrangeShareRowDown()
Dim lRow As Long, lBar As Long
Dim i As Long, j As Long
Dim tB() As tDockedBar
Dim tBS As tDockedBar
Dim iC As Long
   
   Debug.Assert (sanity("rearrangeShareRowDown:START"))
   m_tPtDock.x = -20000
   m_tPtDock.y = -20000
      
   getActiveBarLocation lRow, lBar
   
   ' this is needed because when the dock is aligned bottom or right,
   ' the act of creating a new row in an up direction causes the
   ' share row action to occur, leading to a flickery loop
   If m_bResizeInterlock Then
      m_tRow(lRow).tBar(lBar).lLastX = m_tRow(lRow).tBar(lBar).lThisX
      m_tRow(lRow).tBar(lBar).lLastY = m_tRow(lRow).tBar(lBar).lThisY
      m_bResizeInterlock = False
      Exit Sub
   End If
   
   ' In effect we shift all the rows below this
   ' one up one, correspondingly adjusting the x
   ' position on our own row across to the right
   
   m_tRow(lRow).tBar(lBar).lLastX = m_tRow(lRow).tBar(lBar).lThisX
   m_tRow(lRow).tBar(lBar).lLastY = m_tRow(lRow).tBar(lBar).lThisY
   m_tRow(lRow).tBar(lBar).eAction = eNewAction
   
   ' Can we share the row?
   If m_tRow(lRow).tBar(lBar).bFillRow Then
      ' NO
      Exit Sub
   End If
   
   For i = lRow To m_lRows - 1
      If i = lRow Then
         ' Shifting onto the row:
         iC = m_tRow(i + 1).lCount
         ReDim tB(1 To iC) As tDockedBar
         For j = 1 To iC
            LSet tB(j) = m_tRow(i + 1).tBar(j)
         Next j
         
         m_tRow(i).lCount = iC + 1
         
         If m_tRow(lRow).tBar(lBar).lThisX - m_tRow(lRow).tBar(lBar).lOffsetX >
          m_lMinBarSize Then
            LSet m_tRow(i).tBar(m_tRow(i).lCount) = m_tRow(lRow).tBar(lBar)
            For j = 1 To iC
               LSet m_tRow(i).tBar(j) = tB(j)
            Next j
         Else
            LSet m_tRow(i).tBar(1) = m_tRow(lRow).tBar(lBar)
            For j = 2 To iC + 1
               LSet m_tRow(i).tBar(j) = tB(j - 1)
            Next j
         End If
      Else
         ' Moving up a row:
         m_tRow(i).lCount = m_tRow(i + 1).lCount
         For j = 1 To m_tRow(i + 1).lCount
            LSet m_tRow(i).tBar(j) = m_tRow(i + 1).tBar(j)
         Next j
      End If
   Next i
   m_lRows = m_lRows - 1
   
   AutoSize
   
   Debug.Assert (sanity("rearrangeShareRowDown:END"))
   
End Sub

Private Sub rearrangeNewRowUp()
Dim lRow As Long, lBar As Long
Dim i As Long, j As Long
Dim tB As tDockedBar
Dim iC As Long
Dim tR As RECT
Dim lSize As Long
Dim lX As Long
Dim lH As Long
Dim lAlign As Long
Dim bSwap As Boolean

   Debug.Assert sanity("rearrangeNewRowUp:START")
   m_tPtDock.x = -20000
   m_tPtDock.y = -20000

   ' Keep only me on the current row
   ' and shift everything else down by one
   getActiveBarLocation lRow, lBar
   m_tRow(lRow).tBar(lBar).lLastX = m_tRow(lRow).tBar(lBar).lThisX
   m_tRow(lRow).tBar(lBar).lLastY = m_tRow(lRow).tBar(lBar).lThisY
   m_tRow(lRow).tBar(lBar).eAction = eNewAction
   
   LSet tB = m_tRow(lRow).tBar(lBar)
   lH = m_tRow(lRow).lHeight
   
   If (m_tRow(lRow).tBar(lBar).bFillRow) Then
      bSwap = True
   ElseIf (lRow > 1) Then
      If (m_tRow(lRow - 1).tBar(1).bFillRow) And (m_tRow(lRow).lCount = 1) Then
         bSwap = True
      End If
   End If
   
   ' Full row bar situation?
   If m_lRows = m_lCount Then
      If lRow > 1 Then
         LSet m_tRow(lRow).tBar(1) = m_tRow(lRow - 1).tBar(1)
         m_tRow(lRow).lHeight = m_tRow(lRow - 1).lHeight
         LSet m_tRow(lRow - 1).tBar(1) = tB
         m_tRow(lRow - 1).lHeight = lH
      End If
   ElseIf bSwap Then
      ' swp:
      If lRow > 1 Then
         For j = 1 To m_tRow(lRow - 1).lCount
            LSet m_tRow(lRow).tBar(j) = m_tRow(lRow - 1).tBar(j)
         Next j
         LSet m_tRow(lRow) = m_tRow(lRow - 1)
         LSet m_tRow(lRow - 1).tBar(1) = tB
         m_tRow(lRow - 1).lCount = 1
         m_tRow(lRow - 1).lHeight = lH
      End If
   Else
      ' First shift everything across on this row
      ' now that the active bar has left:
      For j = lBar + 1 To m_tRow(lRow).lCount
         LSet m_tRow(lRow).tBar(j - 1) = m_tRow(lRow).tBar(j)
      Next j
      m_tRow(lRow).lCount = m_tRow(lRow).lCount - 1
      
      ' Now shift everything down by 1:
      For i = m_lRows To lRow Step -1
         m_tRow(i + 1).lCount = m_tRow(i).lCount
         For j = 1 To m_tRow(i).lCount
            LSet m_tRow(i + 1).tBar(j) = m_tRow(i).tBar(j)
         Next j
      Next i
      m_lRows = m_lRows + 1
      
      ' Fix up the current row:
      m_tRow(lRow).lCount = 1
      LSet m_tRow(lRow).tBar(1) = tB
      m_tRow(lRow).tBar(1).lX = 0
      
      For i = 1 To m_lRows
         rowSize i
      Next i
      Resize
      getActiveBarLocation lRow, lBar
      GetWindowRect m_hWndCtl, tR
      If Horizontal Then
         lSize = tR.Right - tR.Left
      Else
         lSize = tR.Bottom - tR.Top
      End If
      If m_tRow(lRow).tBar(lBar).lThisX < 0 Then
         lX = 0
      ElseIf m_tRow(lRow).tBar(lBar).lThisX + m_tRow(lRow).tBar(lBar).cx >
       lSize Then
         lX = lSize - m_tRow(lRow).tBar(lBar).cx
      Else
         lX = m_tRow(lRow).tBar(lBar).lThisX
      End If
      m_tRow(lRow).tBar(lBar).lX = lX
      m_tRow(lRow).tBar(lBar).lXSingleRow = lX
   End If
   
   On Error Resume Next
   lAlign = UserControl.Extender.Align
   On Error GoTo 0
   
   If lAlign = 2 Or lAlign = 4 Then ' bottom, right
      m_bResizeInterlock = True
   End If
   
   Resize
   
   Debug.Assert sanity("rearrangeNewRowUp:END")
   
End Sub

Private Sub rearrangeNewRowDown()
Dim lRow As Long, lBar As Long
Dim i As Long, j As Long
Dim tB As tDockedBar
Dim iC As Long
Dim tR As RECT
Dim lX As Long
Dim lSize As Long
Dim lH As Long
Dim bSwap As Boolean

   Debug.Assert sanity("rearrangeNewRowDown:START")
   m_tPtDock.x = -20000
   m_tPtDock.y = -20000

   ' We make space for a new row on the next row, shift
   ' everything else down and then put this in the new row
   getActiveBarLocation lRow, lBar
   m_tRow(lRow).tBar(lBar).lLastX = m_tRow(lRow).tBar(lBar).lThisX
   m_tRow(lRow).tBar(lBar).lLastY = m_tRow(lRow).tBar(lBar).lThisY
   m_tRow(lRow).tBar(lBar).eAction = eNewAction
      
   LSet tB = m_tRow(lRow).tBar(lBar)
   lH = m_tRow(lRow).lHeight
   
   If (m_tRow(lRow).tBar(lBar).bFillRow) Then
      bSwap = True
   ElseIf (lRow < m_lCount) Then
      If (m_tRow(lRow + 1).tBar(1).bFillRow) And (m_tRow(lRow).lCount = 1) Then
         bSwap = True
      End If
   End If
   
   ' Full row bar situation?
   If (m_lRows = m_lCount) Then
      LSet m_tRow(lRow).tBar(1) = m_tRow(lRow + 1).tBar(1)
      m_tRow(lRow).lHeight = m_tRow(lRow + 1).lHeight
      LSet m_tRow(lRow + 1).tBar(1) = tB
      m_tRow(lRow + 1).lHeight = lH
   ElseIf bSwap Then
      ' must swap this with the next row:
      For j = 1 To m_tRow(lRow + 1).lCount
         LSet m_tRow(lRow).tBar(j) = m_tRow(lRow + 1).tBar(j)
      Next j
      LSet m_tRow(lRow) = m_tRow(lRow + 1)
      m_tRow(lRow + 1).tBar(1) = tB
      m_tRow(lRow + 1).lCount = 1
      m_tRow(lRow + 1).lHeight = lH
   Else
      ' Shuffle up this row:
      For j = lBar + 1 To m_tRow(lRow).lCount
         LSet m_tRow(lRow).tBar(j - 1) = m_tRow(lRow).tBar(j)
      Next j
      m_tRow(lRow).lCount = m_tRow(lRow).lCount - 1
      
      If lRow = m_lRows Then
         ' Moving onto the last row; simply
         ' add the new bar onto the last row:
         m_lRows = m_lRows + 1
         m_tRow(m_lRows).lCount = 1
         LSet m_tRow(m_lRows).tBar(1) = tB
         m_tRow(m_lRows).tBar(1).lX = 0
      Else
         ' Now move all bars from bar lBar+1 to m_lROws down one:
         For i = m_lRows To lRow + 1 Step -1
            m_tRow(i + 1).lCount = m_tRow(i).lCount
            For j = 1 To m_tRow(i).lCount
               LSet m_tRow(i + 1).tBar(j) = m_tRow(i).tBar(j)
            Next j
         Next i
         m_lRows = m_lRows + 1
         
         ' Finally, the new row will be set to contain the active
         ' bar;
         m_tRow(lRow + 1).lCount = 1
         LSet m_tRow(lRow + 1).tBar(1) = tB
         m_tRow(lRow + 1).tBar(1).lX = 0
      End If
      
      For i = 1 To m_lRows
         rowSize i
      Next i
      Resize
      getActiveBarLocation lRow, lBar
      GetWindowRect m_hWndCtl, tR
      If Horizontal Then
         lSize = tR.Right - tR.Left
      Else
         lSize = tR.Bottom - tR.Top
      End If
      If m_tRow(lRow).tBar(lBar).lThisX < 0 Then
         lX = 0
      ElseIf m_tRow(lRow).tBar(lBar).lThisX + m_tRow(lRow).tBar(lBar).cx >
       lSize Then
         lX = lSize - m_tRow(lRow).tBar(lBar).cx
      Else
         lX = m_tRow(lRow).tBar(lBar).lThisX
      End If
      m_tRow(lRow).tBar(lBar).lX = lX
      m_tRow(lRow).tBar(lBar).lXSingleRow = lX
      
   End If
   Resize
   
   Debug.Assert sanity("rearrangeNewRowDown:END")
   
End Sub

Private Sub rowSize(ByVal lRow As Long)
Dim lW As Long, lX As Long
Dim tR As RECT
Dim lBar As Long
Dim lR2 As Long, lB2 As Long
Dim lcxA As Long
Dim i As Long, j As Long
Dim lSize As Long
      
   getActiveBarLocation lR2, lB2
   'Debug.Print "rowSize:ABR:", lR2, "ABB"; lB2
   
   GetWindowRect m_hWndCtl, tR
   If Horizontal Then
      lSize = tR.Right - tR.Left
   Else
      lSize = tR.Bottom - tR.Top
   End If
   
   ' cYA evaluation:
   With m_tRow(lRow)
      .lHeight = 0
      For lBar = 1 To .lCount
         If .tBar(lBar).cYA > .lHeight Then
            .lHeight = .tBar(lBar).cYA
         End If
      Next lBar
   End With
   
   ' cXA evaluation:
   If m_tRow(lRow).lCount = 1 Then
      
      ' one item on this row:
      lX = 0
      If m_tRow(lRow).tBar(1).lXSingleRow > 0 Then
         If m_tRow(lRow).tBar(1).lXSingleRow + m_tRow(lRow).tBar(1).cXA < lSize
          Then
            lX = m_tRow(lRow).tBar(1).lXSingleRow
         Else
            lX = lSize - m_tRow(lRow).tBar(1).cXA
            If lX < 0 Then lX = 0
         End If
      End If
      m_tRow(lRow).tBar(1).lX = lX
      m_tRow(lRow).tBar(1).cx = m_tRow(lRow).tBar(1).cXA
      If m_tRow(lRow).tBar(1).lX + m_tRow(lRow).tBar(1).cx > lSize Then
         m_tRow(lRow).tBar(1).cx = lSize - m_tRow(lRow).tBar(1).lX
      End If
      
   Else
   
      ' multiple items on this row:
      For j = 1 To m_tRow(lRow).lCount
         lW = lW + m_tRow(lRow).tBar(j).cXA
      Next j
      
      If lW < lSize Then
         ' We can fit everything in:
         lX = 0
         For j = 1 To m_tRow(lRow).lCount
            m_tRow(lRow).tBar(j).lX = lX
            m_tRow(lRow).tBar(j).cx = m_tRow(lRow).tBar(j).cXA
            lX = lX + m_tRow(lRow).tBar(j).cx
         Next j
      Else
         
         ' We can't fit everything in.  If the activebar is on this
         ' row then give that full size and divide the rest by the
         ' remaining count, unless that doesn't fit in which case
         ' give the rest the minimum width & the activebar the
         ' remainder.
         ' If the activebar isn't on the row, then check for the
         ' last chosen bar and attempt to give that priority.
         ' If there isn't a last chosen bar then just resize
         ' equally
            
         If Not (lR2 = lRow) Then
            For j = 1 To m_tRow(lRow).lCount
               If m_tRow(lRow).tBar(j).bRowLastChosenBar Then
                  lR2 = lRow
                  lB2 = j
               End If
            Next j
         End If
         
         If lR2 = lRow Then
            lcxA = m_tRow(lRow).tBar(lB2).cXA
            
            If (lcxA + (m_tRow(lRow).lCount - 1) * m_lMinBarSize) > lSize Then
               lcxA = lSize - (m_tRow(lRow).lCount - 1) * m_lMinBarSize
               If lcxA < m_lMinBestBarSize Then
                  lcxA = m_lMinBestBarSize
               End If
            End If
            
            lW = (lSize - lcxA) \ (m_tRow(lRow).lCount - 1)
            
            For j = 1 To m_tRow(lRow).lCount
               If j = lB2 Then
                  m_tRow(lRow).tBar(j).cx = lcxA
               Else
                  m_tRow(lRow).tBar(j).cx = lW
               End If
               m_tRow(lRow).tBar(j).lX = lX
               lX = lX + m_tRow(lRow).tBar(j).cx
            Next j
            
         Else
            lW = lSize \ m_tRow(lRow).lCount
            For j = 1 To m_tRow(lRow).lCount
               m_tRow(lRow).tBar(j).lX = lX
               m_tRow(lRow).tBar(j).cx = lW
               lX = lX + lW
            Next j
         End If
         
      End If
      
   End If
   
   
End Sub

Private Sub mouseUp( _
      x As Single, y As Single _
   )
Dim lRow As Long, lBar As Long
Dim j As Long
Dim ctl As Object
   If m_iActiveBar > 0 Then
      ' set the row last chosen bar:
      getActiveBarLocation lRow, lBar
      For j = 1 To m_tRow(lRow).lCount
         m_tRow(lRow).tBar(j).bRowLastChosenBar = (j = lBar)
      Next j
   End If
   m_iActiveBar = 0
End Sub

Private Sub drawBar( _
      ByVal lIndex As Long _
   )
Dim hBrBack As Long
Dim hPen As Long
Dim hPenOld As Long
Dim tJunk As POINTAPI
Dim tR As RECT
Dim tTR As RECT
Dim lHDC As Long
   
   lHDC = picBar(lIndex).hdc
   
   If (m_bXPStyle) Then
      hBrBack = CreateSolidBrush(VSNetControlColor)
   Else
      If (picBar(lIndex).BackColor And &H80000000) Then
         hBrBack = GetSysColorBrush(picBar(lIndex).BackColor And &H1F&)
      Else
         hBrBack = CreateSolidBrush(picBar(lIndex).BackColor)
      End If
   End If
   
   ' -------------------------------------------------------------------
   ' Background to client area:
   GetClientRect picBar(lIndex).hwnd, tR
   FillRect lHDC, tR, hBrBack
   ' -------------------------------------------------------------------
   
   ' -------------------------------------------------------------------
   ' Background to gripper:
   If Not (LockToolBars) Then
      LSet tTR = tR
      If Horizontal Then
         tTR.Right = tTR.Left + 10
      Else
         tTR.Bottom = tTR.Top + 10
      End If
      FillRect lHDC, tTR, hBrBack
   End If
   ' -------------------------------------------------------------------
   ' Background to chevron:
   LSet tTR = tR
   If Horizontal Then
      tTR.Left = tTR.Right - 12
   Else
      tTR.Top = tTR.Bottom - 12
   End If
   If (m_bXPStyle) Then
      If (m_tChevron(lIndex).bMouseDown) Then
         DeleteObject hBrBack
         hBrBack = GetSysColorBrush(vbButtonFace)
      ElseIf (m_tChevron(lIndex).bMouseOver) Then
         DeleteObject hBrBack
         hBrBack = CreateSolidBrush(VSNetSelectionColor)
      End If
   End If
   FillRect lHDC, tTR, hBrBack
   ' -------------------------------------------------------------------
   
   DeleteObject hBrBack
         
   ' -------------------------------------------------------------------
   ' Chevron/Customiser
   hPen = CreatePen(PS_SOLID, 1, GetSysColor(vbMenuText))
   hPenOld = SelectObject(lHDC, hPen)
   
   LSet tTR = tR
   If Horizontal Then
      tTR.Left = tTR.Right - 12
      tTR.Right = tTR.Right - 1
      tTR.Top = tTR.Top + 1
      tTR.Bottom = tTR.Bottom - 1
   Else
      tTR.Left = tTR.Left + 1
      tTR.Right = tTR.Right - 1
      tTR.Top = tTR.Bottom - 12
      tTR.Bottom = tTR.Bottom - 1
   End If
   LSet m_tChevron(lIndex).tR = tTR
      
   ' The Chevron:
   LSet tTR = tR
   If m_tChevron(lIndex).bShow Then
      If Horizontal Then
         
         tTR.Left = tTR.Right - 10
         tTR.Top = tTR.Top + 3
         MoveToEx lHDC, tTR.Left, tTR.Top, tJunk
         LineTo lHDC, tTR.Left + 2, tTR.Top
         MoveToEx lHDC, tTR.Left + 1, tTR.Top + 1, tJunk
         LineTo lHDC, tTR.Left + 3, tTR.Top + 1
         MoveToEx lHDC, tTR.Left + 2, tTR.Top + 2, tJunk
         LineTo lHDC, tTR.Left + 4, tTR.Top + 2
         MoveToEx lHDC, tTR.Left + 1, tTR.Top + 3, tJunk
         LineTo lHDC, tTR.Left + 3, tTR.Top + 3
         MoveToEx lHDC, tTR.Left, tTR.Top + 4, tJunk
         LineTo lHDC, tTR.Left + 2, tTR.Top + 4
         
         tTR.Left = tTR.Right - 6
         MoveToEx lHDC, tTR.Left, tTR.Top, tJunk
         LineTo lHDC, tTR.Left + 2, tTR.Top
         MoveToEx lHDC, tTR.Left + 1, tTR.Top + 1, tJunk
         LineTo lHDC, tTR.Left + 3, tTR.Top + 1
         MoveToEx lHDC, tTR.Left + 2, tTR.Top + 2, tJunk
         LineTo lHDC, tTR.Left + 4, tTR.Top + 2
         MoveToEx lHDC, tTR.Left + 1, tTR.Top + 3, tJunk
         LineTo lHDC, tTR.Left + 3, tTR.Top + 3
         MoveToEx lHDC, tTR.Left, tTR.Top + 4, tJunk
         LineTo lHDC, tTR.Left + 2, tTR.Top + 4
         
      Else
         
         tTR.Left = tTR.Right - 8
         tTR.Top = tTR.Bottom - 10
         MoveToEx lHDC, tTR.Left, tTR.Top, tJunk
         LineTo lHDC, tTR.Left, tTR.Top + 2
         MoveToEx lHDC, tTR.Left + 1, tTR.Top + 1, tJunk
         LineTo lHDC, tTR.Left + 1, tTR.Top + 3
         MoveToEx lHDC, tTR.Left + 2, tTR.Top + 2, tJunk
         LineTo lHDC, tTR.Left + 2, tTR.Top + 4
         MoveToEx lHDC, tTR.Left + 3, tTR.Top + 1, tJunk
         LineTo lHDC, tTR.Left + 3, tTR.Top + 3
         MoveToEx lHDC, tTR.Left + 4, tTR.Top, tJunk
         LineTo lHDC, tTR.Left + 4, tTR.Top + 2
         
         tTR.Top = tTR.Bottom - 6
         MoveToEx lHDC, tTR.Left, tTR.Top, tJunk
         LineTo lHDC, tTR.Left, tTR.Top + 2
         MoveToEx lHDC, tTR.Left + 1, tTR.Top + 1, tJunk
         LineTo lHDC, tTR.Left + 1, tTR.Top + 3
         MoveToEx lHDC, tTR.Left + 2, tTR.Top + 2, tJunk
         LineTo lHDC, tTR.Left + 2, tTR.Top + 4
         MoveToEx lHDC, tTR.Left + 3, tTR.Top + 1, tJunk
         LineTo lHDC, tTR.Left + 3, tTR.Top + 3
         MoveToEx lHDC, tTR.Left + 4, tTR.Top, tJunk
         LineTo lHDC, tTR.Left + 4, tTR.Top + 2
      
      End If
      
   End If
   
   ' The customiser:
   LSet tTR = tR
   If Horizontal Then
      tTR.Left = tTR.Right - 8
      tTR.Top = tTR.Bottom - 6
      MoveToEx lHDC, tTR.Left, tTR.Top, tJunk
      LineTo lHDC, tTR.Left + 5, tTR.Top
      MoveToEx lHDC, tTR.Left + 1, tTR.Top + 1, tJunk
      LineTo lHDC, tTR.Left + 4, tTR.Top + 1
      MoveToEx lHDC, tTR.Left + 2, tTR.Top, tJunk
      LineTo lHDC, tTR.Left + 2, tTR.Top + 3
   Else
      tTR.Left = tTR.Left + 6
      tTR.Top = tTR.Bottom - 8
      MoveToEx lHDC, tTR.Left, tTR.Top, tJunk
      LineTo lHDC, tTR.Left, tTR.Top + 5
      MoveToEx lHDC, tTR.Left - 1, tTR.Top + 1, tJunk
      LineTo lHDC, tTR.Left - 1, tTR.Top + 4
      MoveToEx lHDC, tTR.Left, tTR.Top + 2, tJunk
      LineTo lHDC, tTR.Left - 3, tTR.Top + 2
   End If
   
   SelectObject lHDC, hPenOld
   DeleteObject hPen
      
   If m_tChevron(lIndex).bMouseOver Or m_tChevron(lIndex).bMouseDown Then
      If m_tChevron(lIndex).bMouseDown Then
         If (m_bXPStyle) Then
            If Horizontal Then
               DrawEdge lHDC, m_tChevron(lIndex).tR, BDR_RAISED, BF_RECT Or
                BF_FLAT
            Else
               DrawEdge lHDC, m_tChevron(lIndex).tR, BDR_RAISED, BF_RECT Or
                BF_FLAT
            End If
         Else
            DrawEdge lHDC, m_tChevron(lIndex).tR, BDR_SUNKENOUTER, BF_RECT
         End If
      Else
         If (m_bXPStyle) Then
            hPen = CreatePen(PS_SOLID, 1, TranslateColor(vbHighlight))
            hPenOld = SelectObject(lHDC, hPen)
            MoveToEx lHDC, m_tChevron(lIndex).tR.Left,
             m_tChevron(lIndex).tR.Top, tJunk
            LineTo lHDC, m_tChevron(lIndex).tR.Right - 1,
             m_tChevron(lIndex).tR.Top
            LineTo lHDC, m_tChevron(lIndex).tR.Right - 1,
             m_tChevron(lIndex).tR.Bottom - 1
            LineTo lHDC, m_tChevron(lIndex).tR.Left,
             m_tChevron(lIndex).tR.Bottom - 1
            LineTo lHDC, m_tChevron(lIndex).tR.Left, m_tChevron(lIndex).tR.Top
            SelectObject lHDC, hPen
            DeleteObject hPen
         Else
            DrawEdge lHDC, m_tChevron(lIndex).tR, BDR_RAISEDINNER, BF_RECT
         End If
      End If
   End If
   
   ' -------------------------------------------------------------------
            
   ' -------------------------------------------------------------------
   ' The Gripper & borders
   If m_bXPStyle Then
      ' Gripper:
      hPen = CreatePen(PS_SOLID, 1, GetSysColor(vb3DShadow And &H1F))
      hPenOld = SelectObject(lHDC, hPen)
      Dim i As Long
      If Not (LockToolBars) Then
         If Horizontal Then
            For i = tR.Top + 4 To tR.Bottom - 4 Step 2
               MoveToEx lHDC, tR.Left + 3, i, tJunk
               LineTo lHDC, tR.Left + 6, i
            Next i
         Else
            For i = tR.Left + 4 To tR.Right - 4 Step 2
               MoveToEx lHDC, i, tR.Top + 3, tJunk
               LineTo lHDC, i, tR.Top + 6
            Next i
         End If
      End If
      SelectObject lHDC, hPenOld
      DeleteObject hPen
            
      ' Borders
      hPen = CreatePen(PS_SOLID, 1, GetSysColor(vbButtonFace And &H1F&))
      hPenOld = SelectObject(lHDC, hPen)
      If Horizontal Then
         MoveToEx lHDC, tR.Left, tR.Top, tJunk
         LineTo lHDC, tR.Right - 1, tR.Top
         MoveToEx lHDC, tR.Left, tR.Bottom - 1, tJunk
         LineTo lHDC, tR.Right - 1, tR.Bottom - 1
      Else
         MoveToEx lHDC, tR.Left, tR.Top, tJunk
         LineTo lHDC, tR.Left, tR.Bottom - 1
         MoveToEx lHDC, tR.Right - 1, tR.Top, tJunk
         LineTo lHDC, tR.Right - 1, tR.Bottom - 1
      End If
      SelectObject lHDC, hPenOld
      DeleteObject hPen
   
   Else
      hPen = CreatePen(PS_SOLID, 1, GetSysColor(vb3DHighlight And &H1F&))
      hPenOld = SelectObject(lHDC, hPen)
      ' Draw border left/top
      MoveToEx lHDC, tR.Left, tR.Bottom, tJunk
      LineTo lHDC, tR.Left, tR.Top
      LineTo lHDC, tR.Right, tR.Top
      
      If Not (LockToolBars) Then
         If Horizontal Then
            MoveToEx lHDC, tR.Left + 4, tR.Bottom - 2 - 1, tJunk
            LineTo lHDC, tR.Left + 4, tR.Top + 2
            LineTo lHDC, tR.Left + 4 + 2, tR.Top + 2
         Else
            MoveToEx lHDC, tR.Right - 2 - 1, tR.Top + 4, tJunk
            LineTo lHDC, tR.Left + 2, tR.Top + 4
            LineTo lHDC, tR.Left + 2, tR.Top + 4 + 2
         End If
      End If
      SelectObject lHDC, hPenOld
      DeleteObject hPen
      
      hPen = CreatePen(PS_SOLID, 1, GetSysColor(vbButtonShadow And &H1F&))
      hPenOld = SelectObject(lHDC, hPen)
      ' Draw border right/bottom
      MoveToEx lHDC, tR.Right - 1, tR.Top, tJunk
      LineTo lHDC, tR.Right - 1, tR.Bottom - 1
      LineTo lHDC, tR.Left - 1, tR.Bottom - 1
   
      If Not (LockToolBars) Then
         If Horizontal Then
            MoveToEx lHDC, tR.Left + 4 + 2, tR.Top + 2, tJunk
            LineTo lHDC, tR.Left + 4 + 2, tR.Bottom - 2 - 1
            LineTo lHDC, tR.Left + 4, tR.Bottom - 2 - 1
         Else
            MoveToEx lHDC, tR.Left + 2, tR.Top + 4 + 2, tJunk
            LineTo lHDC, tR.Right - 2 - 1, tR.Top + 4 + 2
            LineTo lHDC, tR.Right - 2 - 1, tR.Top + 4
         End If
      End If
      SelectObject lHDC, hPenOld
      DeleteObject hPen
   End If
   ' -------------------------------------------------------------------
      
   picBar(lIndex).Refresh
      
End Sub

Private Property Let ISubclass_MsgResponse(ByVal RHS As EMsgResponse)
   '
End Property

Private Property Get ISubclass_MsgResponse() As EMsgResponse
   '
   Select Case CurrentMessage
   Case WM_ERASEBKGND
      ISubclass_MsgResponse = emrConsume
   Case WM_DESTROY
      ISubclass_MsgResponse = emrPreprocess
   End Select
   '
End Property

Private Function ISubclass_WindowProc(ByVal hwnd As Long, ByVal iMsg As Long,
 ByVal wParam As Long, ByVal lParam As Long) As Long
Dim hBr As Long
Dim lhWnd As Long
Dim lBtns As Long
Dim iBtn As Long
Dim tB As TBBUTTON
Dim tR As RECT
Dim tP As POINTAPI
Dim lIndex As Long

   Select Case iMsg
   Case WM_ERASEBKGND
      lIndex = GetProp(hwnd, DOCKCONTAINERBARINDEX)
      lhWnd = GetWindow(hwnd, GW_CHILD)
      If lhWnd <> 0 Then
         hBr = CreateSolidBrush(TranslateColor(picBar(lIndex).BackColor))
         GetClientRect lhWnd, tR
         MapWindowPoints lhWnd, hwnd, tR, 2
         FillRect wParam, tR, hBr
         DeleteObject hBr
      End If
      ISubclass_WindowProc = 1
      
   Case WM_DESTROY
      DetachMessage Me, hwnd, WM_ERASEBKGND
      DetachMessage Me, hwnd, WM_DESTROY
      
   End Select

End Function

Private Sub m_tmr_ThatTime()
Dim tP As POINTAPI
Dim lIndex As Long
Dim bOk As Boolean
   '
   If IsNumeric(m_tmr.Item) Then
      lIndex = m_tmr.Item
      If m_tChevron(lIndex).bMouseOver Then
         GetCursorPos tP
         MapWindowPoints 0, picBar(lIndex).hwnd, tP, 1
         With m_tChevron(lIndex)
            If tP.x >= .tR.Left And tP.x <= .tR.Right Then
               If tP.y >= .tR.Top And tP.y <= .tR.Bottom Then
                  bOk = True
               End If
            End If
            If Not bOk Then
               .bMouseOver = False
               drawBar lIndex
               m_tmr.Item = ""
               m_tmr.Interval = 0
            End If
         End With
      Else
         m_tmr.Interval = 0
      End If
   End If
   '
End Sub

Private Sub picBar_MouseDown(index As Integer, Button As Integer, Shift As
 Integer, x As Single, y As Single)
   If (Button = vbLeftButton) Then
      mouseDown index, x, y
   End If
End Sub

Private Sub picBar_MouseMove(index As Integer, Button As Integer, Shift As
 Integer, x As Single, y As Single)
   '
   Dim lX As Long, lY As Long
   Dim lIndex As Long
   
   lX = x \ Screen.TwipsPerPixelX
   lY = y \ Screen.TwipsPerPixelY
   With m_tChevron(index)
      If lX >= .tR.Left And lX <= .tR.Right Then
         If lY >= .tR.Top And lY <= .tR.Bottom Then
            If IsNumeric(m_tmr.Item) Then
               lIndex = m_tmr.Item
               If lIndex = index Then
                  ' nothing to do
               Else
                  m_tmr.Interval = 0
                  m_tmr_ThatTime
               End If
            End If
            .bMouseOver = True
            drawBar index
            m_tmr.Item = index
            m_tmr.Interval = 50
         End If
      End If
   End With
   '
End Sub

Private Sub picBar_MouseUp(index As Integer, Button As Integer, Shift As
 Integer, x As Single, y As Single)
   If (Button = vbLeftButton) Then
      If (m_tChevron(index).bMouseDown Or m_tChevron(index).bMouseOver) Then
         m_tChevron(index).bMouseDown = False
         m_tChevron(index).bMouseOver = False
         drawBar index
      End If
   End If
   picBar(index).MousePointer = vbDefault
End Sub

Private Sub picBar_Resize(index As Integer)
   drawBar index
End Sub

Private Sub UserControl_Initialize()
   m_bXPStyle = True
   m_bAllowDragOff = True
   m_lNonDockingAreaSize = 24
   ReDim m_tChevron(0 To 0) As tChevron
   Set m_tmr = New CTimer
End Sub

Private Sub UserControl_InitProperties()
   '
   Create
   '
End Sub

Private Sub UserControl_MouseMove(Button As Integer, Shift As Integer, x As
 Single, y As Single)
   '
   If m_iActiveBar > 0 Then
      If (Button = 0) Then
         mouseUp x, y
      Else
         mouseMove x, y
      End If
   End If
   '
End Sub

Private Sub UserControl_MouseUp(Button As Integer, Shift As Integer, x As
 Single, y As Single)
   '
   mouseUp x, y
   On Error Resume Next
   Dim i As Long
   For i = picBar.LBound To picBar.UBound
      picBar(i).MousePointer = vbDefault
   Next i
   '
End Sub

Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
   '
   NonDockingArea = PropBag.ReadProperty("NonDockingArea", False)
   NonDockingAreaSize = PropBag.ReadProperty("NonDockingAreaSize", 24)
   AllowUndock = PropBag.ReadProperty("AllowUndock", True)
   LockToolBars = PropBag.ReadProperty("LockToolbars", False)
   OfficeXpStyle = PropBag.ReadProperty("OfficeXpStyle", True)
   Create
   '
End Sub

Private Sub UserControl_Resize()
   '
   AutoSize
   UserControl.Refresh
   '
End Sub

Private Sub UserControl_Show()
   '
   AutoSize
   '
End Sub

Private Sub UserControl_Terminate()
   '
   RemoveProp m_hWndCtl, DOCKCONTAINERID
   RemoveProp m_hWndCtl, DOCKCONTAINERVERTICAL
   RemoveProp m_hWndCtl, DOCKCONTAINERPARENTHWND
   m_hWndCtl = 0
   'If Not m_cMDIToolbarMenu Is Nothing Then
   '   m_cMDIToolbarMenu.Detach
   '   m_hWndParent = 0
   '   Set m_cMDIToolbarMenu = Nothing
   '   RemoveProp m_hWndParent, MDITOOLBARMENUID
   'End If
   '
End Sub

Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
   '
   PropBag.WriteProperty "NonDockingArea", NonDockingArea, False
   PropBag.WriteProperty "NonDockingAreaSize", NonDockingAreaSize, 24
   PropBag.WriteProperty "AllowUndock", AllowUndock, True
   PropBag.WriteProperty "LockToolbars", LockToolBars, False
   PropBag.WriteProperty "OfficeXpStyle", OfficeXpStyle, True
   '
End Sub