SplitterExt Module (Windows XP+)

Share your advanced PureBasic knowledge/code with the community.
User avatar
chi
Addict
Addict
Posts: 1028
Joined: Sat May 05, 2007 5:31 pm
Location: Linz, Austria

SplitterExt Module (Windows XP+)

Post by chi »

Image

Code: Select all

;;; SplitterExt Module (by chi)

CompilerIf #PB_Compiler_OS <> #PB_OS_Windows
  MessageRequester("SplitterExt", "Your OS is not supported...", #PB_MessageRequester_Error)
  End
CompilerEndIf

DeclareModule Splitter
  Declare SplitterExt(Gadget)
EndDeclareModule

Module Splitter
  EnableExplicit
  
  #UseUxGripper = 0 ;;; 0 = custom, 1 = uxtheme
  Global Gripper = #UseUxGripper
  Global SplitterColor = GetSysColor_(#COLOR_BTNFACE) - RGB(Random(130), Random(130), Random(130)) ;;; comment -RGB(...) for native bg color
  
  Procedure SplitterCalc(hWnd, *rc.RECT)
    Protected hWnd1, hWnd2, r1.RECT, r2.RECT
    hWnd1 = GadgetID(GetGadgetAttribute(GetDlgCtrlID_(hWnd), #PB_Splitter_FirstGadget))
    hWnd2 = GadgetID(GetGadgetAttribute(GetDlgCtrlID_(hWnd), #PB_Splitter_SecondGadget))
    GetWindowRect_(hWnd1, r1)
    OffsetRect_(r1, -r1\left, -r1\top)
    If IsRectEmpty_(r1) = 0
      MapWindowPoints_(hWnd1, hWnd, r1, 2)
      SubtractRect_(*rc, *rc, r1)
    EndIf
    GetWindowRect_(hWnd2, r2)
    OffsetRect_(r2, -r2\left, -r2\top)
    If IsRectEmpty_(r2) = 0
      MapWindowPoints_(hWnd2, hWnd, r2, 2)
      SubtractRect_(*rc, *rc, r2)
    EndIf
  EndProcedure
  
  Procedure SplitterPaint(hWnd, hdc, *rc.RECT, rgb)
    SetDCBrushColor_(hdc, rgb - RGB(25, 25, 25))
    FrameRect_(hdc, *rc, GetStockObject_(#DC_BRUSH))
    InflateRect_(*rc, -1, -1)
    SetDCBrushColor_(hdc, rgb)
    FillRect_(hdc, *rc, GetStockObject_(#DC_BRUSH))
    CompilerIf #UseUxGripper
      Protected htheme = OpenThemeData_(hWnd, "Rebar")
      If htheme
        If *rc\right-*rc\left < *rc\bottom-*rc\top
          InflateRect_(*rc, Bool(*rc\right-*rc\left < 5), -(*rc\bottom-*rc\top-1)/2 + 9)
          DrawThemeBackground_(htheme, hdc, 1, 0, *rc, 0)
        Else
          InflateRect_(*rc, -(*rc\right-*rc\left-1)/2 + 9, Bool(*rc\bottom-*rc\top < 5))
          DrawThemeBackground_(htheme, hdc, 2, 0, *rc, 0)
        EndIf
        CloseThemeData_(htheme)
      EndIf
    CompilerElse
      If *rc\right-*rc\left < *rc\bottom-*rc\top
        InflateRect_(*rc, Bool(*rc\right-*rc\left < 5), -(*rc\bottom-*rc\top-1)/2 + 9)
      Else
        InflateRect_(*rc, -(*rc\right-*rc\left-1)/2 + 9, Bool(*rc\bottom-*rc\top < 5))
      EndIf
      SetBrushOrgEx_(hdc, *rc\left, *rc\top, 0)
      FillRect_(hdc, *rc, Gripper)
      SetBrushOrgEx_(hdc, 0, 0, 0)
    CompilerEndIf
  EndProcedure
  
  Procedure SplitterExtCB(hWnd, msg, wParam, lParam)
    Select msg
      Case #WM_PAINT
        Protected ps.PAINTSTRUCT
        BeginPaint_(hWnd, ps)
          SplitterCalc(hWnd, ps\rcPaint)
          SplitterPaint(hWnd, ps\hdc, ps\rcPaint, SplitterColor)
        EndPaint_(hWnd, ps)
        ProcedureReturn 0
      Case #WM_ERASEBKGND
        ProcedureReturn 1
      Case #WM_LBUTTONDBLCLK
        PostEvent(#PB_Event_Gadget, EventWindow(), GetDlgCtrlID_(hWnd), #PB_EventType_LeftDoubleClick)
      Case #WM_NCDESTROY
        SetWindowLongPtr_(hWnd, #GWL_WNDPROC, RemoveProp_(hWnd, "SplitterExt"))
        If Gripper : DeleteObject_(Gripper) : Gripper = 0 : EndIf
        ProcedureReturn 0
    EndSelect
    ProcedureReturn CallWindowProc_(GetProp_(hWnd, "SplitterExt"), hWnd, msg, wParam, lParam)
  EndProcedure
  
  Procedure SplitterExt(Gadget)
    Gadget = GadgetID(Gadget)
    SetClassLongPtr_(Gadget, #GCL_STYLE, GetClassLongPtr_(Gadget, #GCL_STYLE)|#CS_DBLCLKS)
    SetProp_(Gadget, "SplitterExt", SetWindowLongPtr_(Gadget, #GWL_WNDPROC, @SplitterExtCB()))
    SetWindowLongPtr_(Gadget, #GWL_STYLE, GetWindowLongPtr_(Gadget, #GWL_STYLE)|#WS_CLIPCHILDREN)
    CompilerIf #UseUxGripper = 0
      If Gripper = 0
        Gadget = CreateImage(#PB_Any, 5, 5, 24, SplitterColor - RGB(10, 10, 10))
        StartDrawing(ImageOutput(Gadget))
          DrawingMode(#PB_2DDrawing_AlphaBlend)
          Box(2, 2, 2, 2, RGBA(0, 0, 0, 60))
          Box(1, 1, 2, 2, RGBA(255, 255, 255, 178))
        StopDrawing()
        Gripper = CreatePatternBrush_(ImageID(Gadget))
        FreeImage(Gadget)
      EndIf
    CompilerEndIf
  EndProcedure
  
EndModule

CompilerIf #PB_Compiler_IsMainFile
  
  Procedure SizeWindow()
    ResizeGadget(6, #PB_Ignore, #PB_Ignore, WindowWidth(0)-14, WindowHeight(0)-14)
  EndProcedure
  
  w = 800
  h = 520
  OpenWindow(0, 0, 0, w, h, "SplitterExt", #PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget|#PB_Window_SizeGadget|#PB_Window_ScreenCentered|#PB_Window_Invisible)
  
  CompilerIf 1
    ExplorerTreeGadget(0, 0, 0, 0, 0, "c:\")
    ExplorerListGadget(1, 0, 0, 0, 0, "c:\windows\")
    ExplorerTreeGadget(2, 0, 0, 0, 0, "c:\")
  CompilerElse
    ButtonGadget(0, 0, 0, 0, 0, "Button 1")
    EditorGadget(1, 0, 0, 0, 0)
    ButtonGadget(2, 0, 0, 0, 0, "Button 3")
  CompilerEndIf
  
  SplitterGadget(3, 7, 7, w-14, h-14, 0, 1, #PB_Splitter_Separator|#PB_Splitter_Vertical)
  SetGadgetState(3, 240)
  Splitter::SplitterExt(3)
  
  SplitterGadget(4, 7, 7, w-14, h-14, 3, 2, #PB_Splitter_Separator)
  SetGadgetState(4, h/1.7)
  Splitter::SplitterExt(4)
  
  TextGadget(5, 0, 0, 0, 0, "SplitterExt (by chi)", #PB_Text_Center)
  SplitterGadget(6, 7, 7, w-14, h-14, 4, 5, #PB_Splitter_Separator)
  SetGadgetState(6, h/1.075)
  Splitter::SplitterExt(6)
  
  BindEvent(#PB_Event_SizeWindow, @SizeWindow())
  HideWindow(0, #False)
  
  Repeat
    event = WaitWindowEvent()
    Select event
      Case #PB_Event_Gadget
        Select EventGadget()
          Case 3
            If EventType() = #PB_EventType_LeftDoubleClick : SetGadgetState(3, 280) : EndIf
          Case 4
            If EventType() = #PB_EventType_LeftDoubleClick : SetGadgetState(4, 160) : EndIf
          Case 6
            If EventType() = #PB_EventType_LeftDoubleClick : SetGadgetState(6, h/1.075) : EndIf
        EndSelect
    EndSelect
  Until event = #PB_Event_CloseWindow
  
CompilerEndIf

Last edited by chi on Tue Dec 14, 2021 3:18 pm, edited 3 times in total.
Et cetera is my worst enemy
User avatar
chi
Addict
Addict
Posts: 1028
Joined: Sat May 05, 2007 5:31 pm
Location: Linz, Austria

Re: SplitterExt Module (Windows XP+)

Post by chi »

update: Fixed misalignment of the gripper image without using #PB_Splitter_Separator
Et cetera is my worst enemy
User avatar
ChrisR
Addict
Addict
Posts: 1127
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: SplitterExt Module (Windows XP+)

Post by ChrisR »

Very nice chi :)
I would need to learn to understand these APIs.
With the DPIAware compiler flag is there a way to also paint the splitter wider based on DesktopScaledX(Y) ?
User avatar
chi
Addict
Addict
Posts: 1028
Joined: Sat May 05, 2007 5:31 pm
Location: Linz, Austria

Re: SplitterExt Module (Windows XP+)

Post by chi »

update: Added #PB_EventType_LeftDoubleClick
ChrisR wrote: Mon Nov 22, 2021 4:29 pm Very nice chi :)
I would need to learn to understand these APIs.
With the DPIAware compiler flag is there a way to also paint the splitter wider based on DesktopScaledX(Y) ?
Thx, glad you like it. About making the splitter wider... I'm afraid that's something Fred needs to tackle. Should be pretty easy tho :lol:
Et cetera is my worst enemy
User avatar
ChrisR
Addict
Addict
Posts: 1127
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: SplitterExt Module (Windows XP+)

Post by ChrisR »

I hope gcc leaves enough time to address this kind of thing too for v6.00
And SetGadgetColor(#Splitter, #PB_Gadget_BackColor, Color) in native would be a bonus.
User avatar
chi
Addict
Addict
Posts: 1028
Joined: Sat May 05, 2007 5:31 pm
Location: Linz, Austria

Re: SplitterExt Module (Windows XP+)

Post by chi »

update: Added custom gripper drawing
ChrisR wrote: Mon Nov 22, 2021 6:12 pm I hope gcc leaves enough time to address this kind of thing too for v6.00
And SetGadgetColor(#Splitter, #PB_Gadget_BackColor, Color) in native would be a bonus.
We'll see...
Et cetera is my worst enemy
User avatar
chi
Addict
Addict
Posts: 1028
Joined: Sat May 05, 2007 5:31 pm
Location: Linz, Austria

Re: SplitterExt Module (Windows XP+)

Post by chi »

ChrisR wrote: Mon Nov 22, 2021 4:29 pm With the DPIAware compiler flag is there a way to also paint the splitter wider based on DesktopScaledX(Y) ?
I found a way to trick the splitter by using #WM_NCCALCSIZE on the gadgets inside to show a larger area. However, to make it fully functional, you have to extend the hittest to the NC rect of the gadgets and painting a nice splitter image would require some fiddling since you have to deal with 3 separate parts (GadgetNC_Right|Splitter|GadgetNC_Left). But it would be so much easier and more performant to just adjust the splitter size in the PB source code that I don't think it's worth the time :twisted:
Et cetera is my worst enemy
Post Reply