home *** CD-ROM | disk | FTP | other *** search
/ CD Shareware Magazine 1999 April / CD_Shareware_Magazine_31.iso / Free / Prg / csplitdc.exe / cSplitDC.cls next >
Encoding:
Visual Basic class definition  |  1998-07-14  |  11.7 KB  |  323 lines

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4. END
  5. Attribute VB_Name = "cSplitDDC"
  6. Attribute VB_GlobalNameSpace = False
  7. Attribute VB_Creatable = True
  8. Attribute VB_PredeclaredId = False
  9. Attribute VB_Exposed = False
  10. Option Explicit
  11.  
  12. ' ======================================================================
  13. ' Class:    cSplitDDC
  14. ' Filename: cSplitDC.cls
  15. ' Author:   SP McMahon
  16. ' Date:     07 July 1998
  17. '
  18. ' A splitter class using the Desktop window to draw a
  19. ' splitter bar, therefore allowing splitting of MDI forms
  20. ' as well as standard forms.
  21. ' ======================================================================
  22.  
  23. '// some global declarations
  24. Private bDraw As Boolean
  25. Private rcCurrent As RECT
  26. Private rcNew As RECT
  27. Private rcWindow As RECT
  28.  
  29. Private Type POINTAPI
  30.     X As Long
  31.     Y As Long
  32. End Type
  33. Private Type RECT
  34.    Left As Long
  35.    Top As Long
  36.    Right As Long
  37.    Bottom As Long
  38. End Type
  39. Private Declare Function Rectangle Lib "gdi32" (ByVal hDC As Long, ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
  40. Private Declare Function SetCapture Lib "user32" (ByVal hwnd As Long) As Long
  41. Private Declare Function ReleaseCapture Lib "user32" () As Long
  42. Private Declare Function ClientToScreen Lib "user32" (ByVal hwnd As Long, lpPoint As POINTAPI) As Long
  43. Private Declare Function ScreenToClient Lib "user32" (ByVal hwnd As Long, lpPoint As POINTAPI) As Long
  44. Private Declare Function DeleteDC Lib "gdi32" (ByVal hDC As Long) As Long
  45. Private Declare Function CreateDCAsNull Lib "gdi32" Alias "CreateDCA" (ByVal lpDriverName As String, lpDeviceName As Any, lpOutput As Any, lpInitData As Any) As Long
  46. Private Declare Function SetROP2 Lib "gdi32" (ByVal hDC As Long, ByVal nDrawMode As Long) As Long
  47. Private Const R2_BLACK = 1       '   0
  48. Private Const R2_COPYPEN = 13    '  P
  49. Private Const R2_LAST = 16
  50. Private Const R2_MASKNOTPEN = 3  '  DPna
  51. Private Const R2_MASKPEN = 9     '  DPa
  52. Private Const R2_MASKPENNOT = 5  '  PDna
  53. Private Const R2_MERGENOTPEN = 12        '  DPno
  54. Private Const R2_MERGEPEN = 15   '  DPo
  55. Private Const R2_MERGEPENNOT = 14        '  PDno
  56. Private Const R2_NOP = 11        '  D
  57. Private Const R2_NOT = 6 '  Dn
  58. Private Const R2_NOTCOPYPEN = 4  '  PN
  59. Private Const R2_NOTMASKPEN = 8  '  DPan
  60. Private Const R2_NOTMERGEPEN = 2 '  DPon
  61. Private Const R2_NOTXORPEN = 10  '  DPxn
  62. Private Const R2_WHITE = 16      '   1
  63. Private Const R2_XORPEN = 7      '  DPx
  64. Private Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
  65. Private Declare Function GetClientRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
  66. Private Declare Sub ClipCursorRect Lib "user32" Alias "ClipCursor" (lpRect As RECT)
  67. Private Declare Sub ClipCursorClear Lib "user32" Alias "ClipCursor" (ByVal lpRect As Long)
  68. Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
  69. Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
  70. Private Declare Function GetSystemMetrics Lib "user32" (ByVal nIndex As Long) As Long
  71. Private Const SM_CXBORDER = 5
  72. Private Const SM_CYBORDER = 6
  73. Private Const SM_CYCAPTION = 4
  74. Private Const SM_CYMENU = 15
  75.  
  76. Public Enum eOrientationConstants
  77.     espVertical = 1
  78.     espHorizontal = 2
  79. End Enum
  80. Private m_hWnd As Long
  81. Private m_eOrientation As eOrientationConstants
  82. Private m_lBorder(1 To 4) As Long
  83. Private m_oSplit As Object
  84. Public Enum ESplitBorderTypes
  85.    espbLeft = 1
  86.    espbTop = 2
  87.    espbRight = 3
  88.    espbBottom = 4
  89. End Enum
  90. Private m_bIsMDI As Boolean
  91. Private m_bSplitting As Boolean
  92.  
  93. Public Property Get SplitObject() As Object
  94.     Set SplitObject = m_oSplit
  95. End Property
  96. Public Property Let SplitObject(ByRef oThis As Object)
  97.     Set m_oSplit = oThis
  98.     On Error Resume Next
  99.     oThis.BorderStyle = 0
  100.     If (m_eOrientation = espHorizontal) Then
  101.         oThis.MousePointer = vbSizeNS
  102.     Else
  103.         oThis.MousePointer = vbSizeWE
  104.     End If
  105. End Property
  106. Public Property Let Border(ByVal eBorderType As ESplitBorderTypes, ByVal lSize As Long)
  107.    m_lBorder(eBorderType) = lSize
  108. End Property
  109. Public Property Get Border(ByVal eBorderType As ESplitBorderTypes) As Long
  110.    Border = m_lBorder(eBorderType)
  111. End Property
  112. Public Property Get Orientation() As eOrientationConstants
  113.     Orientation = m_eOrientation
  114. End Property
  115. Public Property Let Orientation(ByVal eOrientation As eOrientationConstants)
  116.     m_eOrientation = eOrientation
  117.     If Not (m_oSplit Is Nothing) Then
  118.         If (m_eOrientation = espHorizontal) Then
  119.             m_oSplit.MousePointer = vbSizeNS
  120.             m_lBorder(espbTop) = 64
  121.             m_lBorder(espbBottom) = 64
  122.             m_lBorder(espbLeft) = 0
  123.             m_lBorder(espbRight) = 0
  124.         Else
  125.             m_oSplit.MousePointer = vbSizeWE
  126.             m_lBorder(espbTop) = 0
  127.             m_lBorder(espbBottom) = 0
  128.             m_lBorder(espbLeft) = 64
  129.             m_lBorder(espbRight) = 64
  130.         End If
  131.     End If
  132. End Property
  133.  
  134. Public Sub SplitterMouseDown( _
  135.         ByVal hwnd As Long, _
  136.         ByVal X As Long, _
  137.         ByVal Y As Long _
  138.     )
  139. Dim tP As POINTAPI
  140.  
  141.     m_hWnd = hwnd
  142.  
  143.     ' Send subsequent mouse messages to the owner window
  144.     SetCapture m_hWnd
  145.     ' Get the window rectangle on the desktop of the owner window:
  146.     GetWindowRect m_hWnd, rcWindow
  147.     ' Clip the cursor so it can't move outside the window:
  148.     ClipCursorRect rcWindow
  149.     
  150.     ' Check if this is an MDI form:
  151.     If (ClassName(m_hWnd) = "ThunderMDIForm") Then
  152.         ' Get the inside portion of the MDI form:
  153.         ' I'm assuming you have a caption,menu and border in your MDI here
  154.         rcWindow.Left = rcWindow.Left + GetSystemMetrics(SM_CXBORDER)
  155.         rcWindow.Right = rcWindow.Right - GetSystemMetrics(SM_CXBORDER)
  156.         rcWindow.Bottom = rcWindow.Bottom - GetSystemMetrics(SM_CYBORDER)
  157.         rcWindow.Top = rcWindow.Top + GetSystemMetrics(SM_CYBORDER) * 3 + GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYMENU)
  158.         m_bIsMDI = True
  159.     Else
  160.         ' Get the client rectangle of the window in screen coordinates:
  161.         GetClientRect m_hWnd, rcWindow
  162.         tP.X = rcWindow.Left
  163.         tP.Y = rcWindow.Top
  164.         ClientToScreen m_hWnd, tP
  165.         rcWindow.Left = tP.X
  166.         rcWindow.Top = tP.Y
  167.         tP.X = rcWindow.Right
  168.         tP.Y = rcWindow.Bottom
  169.         ClientToScreen m_hWnd, tP
  170.         rcWindow.Right = tP.X
  171.         rcWindow.Bottom = tP.Y
  172.         m_bIsMDI = False
  173.     End If
  174.     bDraw = True  '// start actual drawing from next move message
  175.     
  176.     rcCurrent.Left = 0: rcCurrent.Top = 0: rcCurrent.Right = 0: rcCurrent.Bottom = 0
  177.     
  178.     X = (m_oSplit.Left + X) \ Screen.TwipsPerPixelX
  179.     Y = (m_oSplit.Top + Y) \ Screen.TwipsPerPixelY
  180.     SplitterFormMouseMove X, Y
  181.     
  182. End Sub
  183.  
  184. Public Sub SplitterFormMouseMove( _
  185.       ByVal X As Long, _
  186.       ByVal Y As Long)
  187. Dim hDC As Long
  188. Dim tP As POINTAPI
  189. Dim hWndClient As Long
  190.     If (bDraw) Then
  191.         '// Draw two rectangles in the screen DC to cause splitting:
  192.         
  193.         ' First get the Desktop DC:
  194.         hDC = CreateDCAsNull("DISPLAY", ByVal 0&, ByVal 0&, ByVal 0&)
  195.         ' Set the draw mode to XOR:
  196.         SetROP2 hDC, R2_NOTXORPEN
  197.     
  198.         '// Draw over and erase the old rectangle
  199.         ' (if this is the first time, all the coords will be 0 and nothing will get drawn):
  200.         Rectangle hDC, rcCurrent.Left, rcCurrent.Top, rcCurrent.Right, rcCurrent.Bottom
  201.                 
  202.         ' It is simpler to use the mouse cursor position than try to translate
  203.         ' X,Y to screen coordinates!
  204.         GetCursorPos tP
  205.         
  206.         ' Determine where to draw the splitter:
  207.         If (m_eOrientation = espHorizontal) Then
  208.             rcNew.Left = rcWindow.Left + m_lBorder(espbLeft)
  209.             rcNew.Right = rcWindow.Right - m_lBorder(espbRight)
  210.             If (tP.Y >= rcWindow.Top + m_lBorder(espbTop)) And (tP.Y < rcWindow.Bottom - m_lBorder(espbBottom)) Then
  211.                 rcNew.Top = tP.Y - 2
  212.                 rcNew.Bottom = tP.Y + 2
  213.             Else
  214.                 If (tP.Y < rcWindow.Top + m_lBorder(espbTop)) Then
  215.                     rcNew.Top = rcWindow.Top + m_lBorder(espbTop) - 2
  216.                     rcNew.Bottom = rcNew.Top + 5
  217.                 Else
  218.                     rcNew.Top = rcWindow.Bottom - m_lBorder(espbBottom) - 2
  219.                     rcNew.Bottom = rcNew.Top + 5
  220.                 End If
  221.             End If
  222.         Else
  223.             rcNew.Top = rcWindow.Top + m_lBorder(espbTop)
  224.             rcNew.Bottom = rcWindow.Bottom - m_lBorder(espbBottom)
  225.             If (tP.X >= rcWindow.Left + m_lBorder(espbLeft)) And (tP.X <= rcWindow.Right - m_lBorder(espbRight)) Then
  226.                 rcNew.Left = tP.X - 2
  227.                 rcNew.Right = tP.X + 2
  228.             Else
  229.                 If (tP.X < rcWindow.Left + m_lBorder(espbLeft)) Then
  230.                     rcNew.Left = rcWindow.Left + m_lBorder(espbLeft) - 2
  231.                     rcNew.Right = rcNew.Left + 5
  232.                 Else
  233.                     rcNew.Left = rcWindow.Right - m_lBorder(espbRight) - 2
  234.                     rcNew.Right = rcNew.Left + 5
  235.                 End If
  236.             End If
  237.         End If
  238.         
  239.         '// Draw the new rectangle
  240.         Rectangle hDC, rcNew.Left, rcNew.Top, rcNew.Right, rcNew.Bottom
  241.         
  242.         ' Store this position so we can erase it next time:
  243.         LSet rcCurrent = rcNew
  244.         
  245.         ' Free the reference to the Desktop DC we got (make sure you do this!)
  246.         DeleteDC hDC
  247.     End If
  248.     
  249. End Sub
  250.  
  251. Public Function SplitterFormMouseUp( _
  252.       ByVal X As Long, _
  253.       ByVal Y As Long _
  254.    ) As Boolean
  255. Dim hDC As Long
  256. Dim tP As POINTAPI
  257. Dim hWndClient As Long
  258.  
  259.       '// Don't leave orphaned rectangle on desktop; erase last rectangle.
  260.    If (bDraw) Then
  261.        bDraw = False
  262.        
  263.        ' Release mouse capture:
  264.        ReleaseCapture
  265.        ' Release the cursor clipping region (must do this!):
  266.        ClipCursorClear 0&
  267.        
  268.        ' Get the Desktop DC:
  269.        hDC = CreateDCAsNull("DISPLAY", 0, 0, 0)
  270.        ' Set to XOR drawing mode:
  271.        SetROP2 hDC, R2_NOTXORPEN
  272.        ' Erase the last rectangle:
  273.        Rectangle hDC, rcCurrent.Left, rcCurrent.Top, rcCurrent.Right, rcCurrent.Bottom
  274.        ' Clear up the desktop DC:
  275.        DeleteDC hDC
  276.        
  277.        ' Here we ensure the splitter is within bounds before releasing:
  278.        GetCursorPos tP
  279.  
  280.        If (tP.X < rcWindow.Left + m_lBorder(espbLeft)) Then
  281.            tP.X = rcWindow.Left + m_lBorder(espbLeft)
  282.        End If
  283.        If (tP.X > rcWindow.Right - m_lBorder(espbRight)) Then
  284.            tP.X = rcWindow.Right - m_lBorder(espbRight)
  285.        End If
  286.        If (tP.Y < rcWindow.Top + m_lBorder(espbTop)) Then
  287.            tP.Y = rcWindow.Top + m_lBorder(espbTop)
  288.        End If
  289.        If (tP.Y > rcWindow.Bottom - m_lBorder(espbBottom)) Then
  290.            tP.Y = rcWindow.Bottom - m_lBorder(espbBottom)
  291.        End If
  292.        ScreenToClient m_hWnd, tP
  293.        
  294.        ' Move the splitter to the validated final position:
  295.        If (m_eOrientation = espHorizontal) Then
  296.            m_oSplit.Top = (tP.Y - 2) * Screen.TwipsPerPixelY
  297.        Else
  298.            m_oSplit.Left = (tP.X - 2) * Screen.TwipsPerPixelX
  299.        End If
  300.        
  301.        ' Return true to tell the owner we have completed splitting:
  302.        SplitterFormMouseUp = True
  303.    End If
  304.    
  305. End Function
  306.  
  307. Private Sub Class_Initialize()
  308.    m_eOrientation = espVertical
  309.    m_lBorder(espbLeft) = 64
  310.    m_lBorder(espbRight) = 64
  311. End Sub
  312. Private Function ClassName(ByVal lHwnd As Long) As String
  313. Dim lLen As Long
  314. Dim sBuf As String
  315.     lLen = 260
  316.     sBuf = String$(lLen, 0)
  317.     lLen = GetClassName(lHwnd, sBuf, lLen)
  318.     If (lLen <> 0) Then
  319.         ClassName = Left$(sBuf, lLen)
  320.     End If
  321. End Function
  322.  
  323.