vbAccelerator - Contents of code file: cSplitter.cls

VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
END
Attribute VB_Name = "cSplitter"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit

Private Type POINTAPI
   X As Long
   Y As Long
End Type
Private Type RECT
   Left As Long
   Top As Long
   Right As Long
   Bottom As Long
End Type
Private Type BITMAP '24 bytes
   bmType As Long
   bmWidth As Long
   bmHeight As Long
   bmWidthBytes As Long
   bmPlanes As Integer
   bmBitsPixel As Integer
   bmBits As Long
End Type

Private Const IDC_SIZENS = 32645&
Private Const IDC_SIZEWE = 32644&
Private Const IDC_NO = 32648&

Private Const R2_NOTXORPEN = 10  '  DPxn

Private Const PATINVERT = &H5A0049       ' (DWORD) dest = pattern XOR dest
Private Const DSTINVERT = &H550009       ' (DWORD) dest = (NOT dest)

Private Declare Function GetClientRect Lib "user32" (ByVal hWnd As Long, lpRect
 As RECT) As Long
Private Declare Function ScreenToClient Lib "user32" (ByVal hWnd As Long,
 lpPoint As POINTAPI) As Long
Private Declare Function GetWindowRect Lib "user32" (ByVal hWnd As Long, lpRect
 As RECT) As Long
Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Private Declare Sub ClipCursorRect Lib "user32" Alias "ClipCursor" (lpRect As
 RECT)
Private Declare Sub ClipCursorClear Lib "user32" Alias "ClipCursor" (ByVal
 lpRect As Long)
Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function CreateDCAsNull Lib "gdi32" Alias "CreateDCA" (ByVal
 lpDriverName As String, lpDeviceName As Any, lpOutput As Any, lpInitData As
 Any) As Long
Private Declare Function SetROP2 Lib "gdi32" (ByVal hdc As Long, ByVal
 nDrawMode As Long) As Long
Private Declare Function CreateBitmapIndirect Lib "gdi32" (lpBitmap As BITMAP)
 As Long
Private Declare Function CreatePatternBrush Lib "gdi32" (ByVal hBitmap As Long)
 As Long
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 FillRect Lib "user32" (ByVal hdc As Long, lpRect As
 RECT, ByVal hBrush As Long) As Long
Private Declare Function PatBlt Lib "gdi32" (ByVal hdc As Long, ByVal X As
 Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal
 dwRop As Long) As Long
Private Declare Function LoadCursorLong Lib "user32" Alias "LoadCursorA" (ByVal
 hInstance As Long, ByVal lpCursorName As Long) As Long
Private Declare Function DestroyCursor Lib "user32" (ByVal hCursor As Long) As
 Long
Private Declare Function SetCursor Lib "user32" (ByVal hCursor As Long) As Long

Public Enum ESPLTOrientationConstants
    cSPLTOrientationHorizontal = 1
    cSPLTOrientationVertical = 2
End Enum

Public Enum ESPLTPanelConstants
   cSPLTLeftOrTopPanel = 1
   cSPLTRightOrBottomPanel = 2
End Enum

Private m_bKeepProportionsWhenResizing As Boolean
Private m_fProportion As Single
Private m_lSplitPos As Long
Private m_lSplitSize As Long
Private m_lMinSize(1 To 2) As Long
Private m_lMaxSize(1 To 2) As Long
Private m_bFullDrag As Boolean
Private m_bInDrag As Boolean
Private m_tPInitial As POINTAPI
Private m_lSplitInitial  As Long
Private m_hBrush As Long
Private m_lPattern(0 To 3) As Long
Private m_tSplitR As RECT
Private m_hCursor As Long

Private m_oContainer As Object
Private m_oLeftTop As Object
Private m_oRightBottom As Object

Private m_eOrientation As ESPLTOrientationConstants

Public Event Split(X As Single, Y As Single, bCancel As Boolean)

Public Property Get FullDrag() As Boolean
   FullDrag = m_bFullDrag
End Property
Public Property Let FullDrag(ByVal bState As Boolean)
   If Not (m_bFullDrag = bState) Then
      m_bFullDrag = bState
      If Not m_bFullDrag Then
         CreateBrush
      Else
         DestroyBrush
      End If
   End If
End Property

Public Property Get Orientation() As ESPLTOrientationConstants
   Orientation = m_eOrientation
End Property
Public Property Let Orientation(ByVal eOrientation As ESPLTOrientationConstants)
   If Not (m_eOrientation = eOrientation) Then
      m_eOrientation = eOrientation
      If Not (m_hCursor = 0) Then
         DestroyCursor m_hCursor
      End If
      If (m_eOrientation = cSPLTOrientationHorizontal) Then
         m_hCursor = LoadCursorLong(0, IDC_SIZENS)
      Else
         m_hCursor = LoadCursorLong(0, IDC_SIZEWE)
      End If
      Resize
   End If
End Property

Public Property Get Proportion() As Single
   If (m_fProportion > 1) Then
      m_fProportion = 1
   End If
   Proportion = m_fProportion * 100
End Property
Public Property Let Proportion(ByVal fProportion As Single)
   If (fProportion > 100#) Or (fProportion < 0#) Then
      Err.Raise 380, App.EXEName & ".cSplitter"
   Else
      m_fProportion = fProportion / 100#
      Resize
   End If
End Property

Public Property Get Position() As Long
   Position = m_lSplitPos
End Property
Public Property Let Position(ByVal lPosition As Long)
   If (lPosition <> m_lSplitPos) Then
      m_lSplitPos = lPosition
      pValidatePosition
      pSetProportion
      Resize
   End If
End Property

Public Property Get KeepProportion() As Boolean
   KeepProportion = m_bKeepProportionsWhenResizing
End Property
Public Property Let KeepProportion(ByVal bState As Boolean)
   m_bKeepProportionsWhenResizing = bState
End Property

Public Property Let Container(oContainer As Object)
   Set m_oContainer = oContainer
End Property
Public Property Get Container() As Object
   Set Container = m_oContainer
End Property

Public Property Get SplitterSize() As Long
   SplitterSize = m_lSplitSize
End Property
Public Property Let SplitterSize(ByVal lSize As Long)
   If Not (m_lSplitSize = lSize) Then
      If (lSize < 0) Then
         Err.Raise 380, App.EXEName & ".cSplitter"
      Else
         m_lSplitSize = lSize
         Resize
      End If
   End If
End Property

Public Property Get MinimumSize( _
      ByVal ePanel As ESPLTPanelConstants _
   ) As Long
   MinimumSize = m_lMinSize(ePanel)
End Property
Public Property Let MinimumSize( _
      ByVal ePanel As ESPLTPanelConstants, _
      ByVal lSize As Long _
   )
   If Not (m_lMinSize(ePanel) = lSize) Then
      m_lMinSize(ePanel) = lSize
      Resize
   End If
End Property

Public Property Get MaximumSize( _
      ByVal ePanel As ESPLTPanelConstants _
   ) As Long
   MaximumSize = m_lMaxSize(ePanel)
End Property
Public Property Let MaximumSize( _
      ByVal ePanel As ESPLTPanelConstants, _
      ByVal lSize As Long _
   )
   If Not (m_lMaxSize(ePanel) = lSize) Then
      m_lMaxSize(ePanel) = lSize
   End If
End Property


Public Sub Bind(oLeftTop As Object, oRightBottom As Object)
   
   If (m_oContainer Is Nothing) Then
      Set m_oContainer = oLeftTop.Container
   End If
   
   Set m_oLeftTop = oLeftTop
   Set m_oLeftTop.Container = m_oContainer
   Set m_oRightBottom = oRightBottom
   Set m_oRightBottom.Container = m_oContainer
      
   Resize
   
End Sub

Private Function pbConfigured() As Boolean
   If Not m_oContainer Is Nothing Then
      If Not m_oLeftTop Is Nothing Then
         If Not m_oRightBottom Is Nothing Then
            pbConfigured = True
         End If
      End If
   End If
End Function

Public Sub MouseDown(Button As Integer, Shift As Integer, X As Single, Y As
 Single)
   If (Button = vbLeftButton) Then
      Dim bCancel As Boolean
      RaiseEvent Split(X, Y, bCancel)
      If Not bCancel Then
         m_bInDrag = True
      
         Dim tP As POINTAPI
         GetCursorPos tP
         LSet m_tPInitial = tP
         m_lSplitInitial = m_lSplitPos
            
         Dim tR As RECT
         GetWindowRect m_oContainer.hWnd, tR
         ClipCursorRect tR
         
         If Not (m_bFullDrag) Then
            If (m_eOrientation = cSPLTOrientationVertical) Then
               m_tSplitR.Left = tR.Left + m_lSplitPos
               m_tSplitR.Right = m_tSplitR.Left + m_lSplitSize
               m_tSplitR.Top = tR.Top
               m_tSplitR.Bottom = tR.Bottom
            Else
               m_tSplitR.Left = tR.Left
               m_tSplitR.Right = tR.Right
               m_tSplitR.Top = tR.Top + m_lSplitPos
               m_tSplitR.Bottom = m_tSplitR.Top + m_lSplitSize
            End If
            
            pDrawSplitter
            
         End If
         
      End If
   End If
End Sub
Public Sub MouseMove(Button As Integer, Shift As Integer, X As Single, Y As
 Single)
      
   If (pbConfigured) Then
      SetCursor m_hCursor
   
      If (m_bInDrag) Then
         
         Dim tP As POINTAPI
         GetCursorPos tP
         
         If Not (m_bFullDrag) Then
            pDrawSplitter
         End If
         
         If (m_eOrientation = cSPLTOrientationVertical) Then
            m_lSplitPos = m_lSplitInitial + (tP.X - m_tPInitial.X)
         Else
            m_lSplitPos = m_lSplitInitial + (tP.Y - m_tPInitial.Y)
         End If
         pValidatePosition
         
         If (m_bFullDrag) Then
            ResizePanels
         Else
            Dim tR As RECT
            GetWindowRect m_oContainer.hWnd, tR
            
            If (m_eOrientation = cSPLTOrientationVertical) Then
               m_tSplitR.Left = tR.Left + m_lSplitPos
               m_tSplitR.Right = m_tSplitR.Left + m_lSplitSize
               m_tSplitR.Top = tR.Top
               m_tSplitR.Bottom = tR.Bottom
            Else
               m_tSplitR.Left = tR.Left
               m_tSplitR.Right = tR.Right
               m_tSplitR.Top = tR.Top + m_lSplitPos
               m_tSplitR.Bottom = m_tSplitR.Top + m_lSplitSize
            End If
               
            pDrawSplitter
   
         End If
         
      End If
   End If
End Sub
Public Sub MouseUp(Button As Integer, Shift As Integer, X As Single, Y As
 Single)
   If (pbConfigured()) Then
      If (m_bInDrag) Then
         ClipCursorClear 0&
         
         Dim tP As POINTAPI
         GetCursorPos tP
         
         If Not m_bFullDrag Then
            pDrawSplitter
         End If
         
         If (m_eOrientation = cSPLTOrientationVertical) Then
            m_lSplitPos = m_lSplitInitial + (tP.X - m_tPInitial.X)
         Else
            m_lSplitPos = m_lSplitInitial + (tP.Y - m_tPInitial.Y)
         End If
         pValidatePosition
            
         ResizePanels
         
         pSetProportion
         m_bInDrag = False
      End If
   End If
End Sub

Private Sub pDrawSplitter()
Dim lhDC As Long
Dim hOldBrush As Long
   lhDC = CreateDCAsNull("DISPLAY", ByVal 0&, ByVal 0&, ByVal 0&)
   hOldBrush = SelectObject(lhDC, m_hBrush)
   PatBlt lhDC, m_tSplitR.Left, m_tSplitR.Top, m_tSplitR.Right -
    m_tSplitR.Left, m_tSplitR.Bottom - m_tSplitR.Top, PATINVERT
   SelectObject lhDC, hOldBrush
   DeleteDC lhDC
End Sub

Private Sub pSetProportion()
   If (m_eOrientation = cSPLTOrientationVertical) Then
      m_fProportion = (m_lSplitPos * 1#) /
       m_oContainer.ScaleX(m_oContainer.ScaleWidth, m_oContainer.ScaleMode,
       vbPixels)
   Else
      m_fProportion = (m_lSplitPos * 1#) /
       m_oContainer.ScaleY(m_oContainer.ScaleHeight, m_oContainer.ScaleMode,
       vbPixels)
   End If
End Sub

Private Sub pValidatePosition()
   
   Dim tR As RECT
   GetClientRect m_oContainer.hWnd, tR
   
   If (m_eOrientation = cSPLTOrientationVertical) Then
      ' Check right too big:
      If (m_lMaxSize(2) > 0) Then
         If ((tR.Right - m_lSplitPos - m_lSplitSize) > m_lMaxSize(2)) Then
            m_lSplitPos = tR.Right - m_lMaxSize(2) - m_lSplitSize
         End If
      End If
      ' Check left too big:
      If (m_lMaxSize(1) > 0) Then
         If (m_lSplitPos > m_lMaxSize(1)) Then
            m_lSplitPos = m_lMaxSize(1)
         End If
      End If
      ' Check right too small:
      If (m_lMinSize(2) > 0) Then
         If ((tR.Right - m_lSplitPos - m_lSplitSize) < m_lMinSize(2)) Then
            m_lSplitPos = tR.Right - m_lMinSize(2) - m_lSplitSize
         End If
      End If
      ' Check left too small:
      If (m_lMinSize(1) > 0) Then
         If (m_lSplitPos < m_lMinSize(1)) Then
            m_lSplitPos = m_lMinSize(1)
         End If
      End If
   Else
      ' Check bottom too big:
      If (m_lMaxSize(2) > 0) Then
         If ((tR.Bottom - m_lSplitPos - m_lSplitSize) > m_lMaxSize(2)) Then
            m_lSplitPos = tR.Bottom - m_lMaxSize(2) - m_lSplitSize
         End If
      End If
      ' Check top too big:
      If (m_lMaxSize(1) > 0) Then
         If (m_lSplitPos > m_lMaxSize(1)) Then
            m_lSplitPos = m_lMaxSize(1)
         End If
      End If
      ' Bottom too small:
      If (m_lMinSize(2) > 0) Then
         If ((tR.Bottom - m_lSplitPos - m_lSplitSize) < m_lMinSize(2)) Then
            m_lSplitPos = tR.Bottom - m_lMinSize(2) - m_lSplitSize
         End If
      End If
      ' Top too small:
      If (m_lMinSize(1) > 0) Then
         If (m_lSplitPos < m_lMinSize(1)) Then
            m_lSplitPos = m_lMinSize(1)
         End If
      End If
   End If
End Sub

Public Sub Resize()
   If pbConfigured() Then
            
      ' Get the container's size:
      Dim tR As RECT
      GetClientRect m_oContainer.hWnd, tR
      
      If (m_bKeepProportionsWhenResizing) Then
         ' attempt to keep the proportions of the two parts:
         If (m_eOrientation = cSPLTOrientationVertical) Then
            m_lSplitPos = (tR.Right - tR.Left) * m_fProportion
         Else
            m_lSplitPos = (tR.Bottom - tR.Top) * m_fProportion
         End If
         pValidatePosition
      End If
            
      ResizePanels
      
   End If
End Sub

Public Sub ResizePanels()
   Dim f As Single
   On Error Resume Next
   If (m_eOrientation = cSPLTOrientationHorizontal) Then
      f = m_oContainer.ScaleY(m_lSplitPos, vbPixels, m_oContainer.ScaleMode)
      m_oLeftTop.Move 0, 0, m_oContainer.ScaleWidth, f
      f = f + m_oContainer.ScaleY(m_lSplitSize, vbPixels,
       m_oContainer.ScaleMode)
      m_oRightBottom.Move 0, f, m_oContainer.ScaleWidth,
       m_oContainer.ScaleHeight - f
   Else
      f = m_oContainer.ScaleX(m_lSplitPos, vbPixels, m_oContainer.ScaleMode)
      m_oLeftTop.Move 0, 0, f, m_oContainer.ScaleHeight
      f = f + m_oContainer.ScaleX(m_lSplitSize, vbPixels,
       m_oContainer.ScaleMode)
      m_oRightBottom.Move f, 0, m_oContainer.ScaleWidth - f, m_oContainer.Height
   End If

End Sub

Private Function CreateBrush() As Boolean
Dim tbm As BITMAP
Dim hBm As Long

   DestroyBrush
      
   ' Create a monochrome bitmap containing the desired pattern:
   tbm.bmType = 0
   tbm.bmWidth = 16
   tbm.bmHeight = 8
   tbm.bmWidthBytes = 2
   tbm.bmPlanes = 1
   tbm.bmBitsPixel = 1
   tbm.bmBits = VarPtr(m_lPattern(0))
   hBm = CreateBitmapIndirect(tbm)

   ' Make a brush from the bitmap bits
   m_hBrush = CreatePatternBrush(hBm)

   '// Delete the useless bitmap
   DeleteObject hBm

End Function
Private Sub DestroyBrush()
   If Not (m_hBrush = 0) Then
      DeleteObject m_hBrush
      m_hBrush = 0
   End If
End Sub

Private Sub Class_Initialize()
   
   m_fProportion = 0.5
   m_eOrientation = cSPLTOrientationHorizontal
      m_hCursor = LoadCursorLong(0, IDC_SIZENS)
   m_lSplitSize = 4
   m_lMinSize(1) = 8
   m_lMaxSize(1) = -1
   m_lMinSize(2) = 8
   m_lMaxSize(2) = -1
   m_bFullDrag = True
   m_lSplitPos = 128
   
   Dim i As Long
   For i = 0 To 3
      m_lPattern(i) = &HAAAA5555
   Next i
   
End Sub

Private Sub Class_Terminate()
   DestroyBrush
   If Not (m_hCursor = 0) Then
      DestroyCursor m_hCursor
   End If
End Sub