disabling gadgets (stealing clicks)

Share your advanced PureBasic knowledge/code with the community.
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

disabling gadgets (stealing clicks)

Post by blueznl »

Code updated For 5.20+

pb disablegadget() leaves the gadget, well, disabled :-)

all fine, but what if you want the gadget to look like the regular thing, but not operating? (let's just say you're into visual designers and you want to drag buttons :-))

here's a solution

Code: Select all

Structure x_dgwindow
  windownr.l
  mousehook_h.l
EndStructure
Structure x_dggadget
  gadgetnr.l
  gadget_h.l
  windownr.l
EndStructure
Global NewList x_dgwindow.x_dgwindow()
Global NewList x_dggadget.x_dggadget()

Procedure x_dg_mousehookhandler(ncode.l,wparam.l,lparam.l)
  Protected mx.l, my.l, rect.RECT
  ;
  If wparam = #WM_LBUTTONUP Or wparam = #WM_LBUTTONDOWN                       ; only rmb or lmb messages
    ResetList(x_dggadget())
    While NextElement(x_dggadget()) <> 0
      If EventWindow() = x_dggadget()\windownr
        mx = DesktopMouseX()
        my = DesktopMouseY()
        rect.RECT
        GetWindowRect_(x_dggadget()\gadget_h,@rect)
        If mx >= rect\left And mx <= rect\right And my >= rect\Top And my <= rect\bottom
          ProcedureReturn 1
        EndIf
      EndIf
    Wend
  EndIf
  ProcedureReturn 0
EndProcedure

Procedure.l x_enddisablegadgets(windownr.l)                            ; reenable all gadgets on specified window
  Protected found.l, endoflist.l
  ;
  ; *** remove the specified windownr and all gadgets on it from the list and enable these gadgets
  ;
  ; in:      windownr.l = -1    - reenable all gadgets and windows. remove all hooks
  ;                     = n     - reenable all gadgets on specified window, remove hook
  ; retval: -1                  - no window removed from list
  ;         0                   - removed window and hook
  ;
  x_retval = -1
  If windownr > 0
    ;
    ; delete all elements in the list of gadgets that belong to the specified window
    ;
    endoflist = 1
    If FirstElement(x_dggadget()) <> 0
      Repeat
        If x_dggadget()\windownr = windownr
          DeleteElement(x_dggadget(),1)
        Else
          endoflist = NextElement(x_dggadget())
        EndIf
      Until endoflist = 0
    EndIf
    ;
    ; now unhook the window and remove it from the list of windows
    ;
    found = #False
    If FirstElement(x_dgwindow())
      Repeat
        If x_dgwindow()\windownr = windownr
          found = #True
        EndIf
      Until found = #True Or NextElement(x_dgwindow()) = 0
      If found = #True
        UnhookWindowsHookEx_(x_dgwindow()\mousehook_h)
        DeleteElement(x_dgwindow())
        x_retval = 0
      EndIf
    EndIf
    ;
  Else
    ;
    ; window was specified as -1 so unhook all windows, enable all gadgets and clear both lists
    ;
    ResetList(x_dgwindow())
    While NextElement(x_dgwindow()) <> 0
      UnhookWindowsHookEx_(x_dgwindow()\mousehook_h)
    Wend
    ClearList(x_dgwindow())
    ClearList(x_dggadget())
    x_retval = 0
    ;
  EndIf
  ;
EndProcedure

Procedure.l x_disablegadget(gadgetnr,windownr,disable.l)               ; disable gadget by intercepting clicks
  Protected found.l, instance_h.l, thread_id.l
  Global x_retval.l
  ; Global x_dgwindow.l(), x_dggadget.l()
  ;
  ; *** disable or enable gadgets by intercepting clicks
  ;
  ; in:     with disable.l = #true:
  ;               gadgetnr = m  windownr = n          - disable gadget m on window n
  ;                             windownr = -1         - disable gadget rectangle on any window
  ;               gadgetnr = -1 windownr = n          - disable specified gadgets for window n
  ;                             windownr = -1         - error
  ;         with disable.l = #false:
  ;               gadgetnr = m                        - reenable specified gadget (windownr is ignored)
  ;               gadgetnr = -1 windownr = n          - reenable all gadgets on this window
  ;
  ; x_retval:   -1                                    - error
  ;             0                                     - no error
  ;
  ; note 1: do not close windows once a hook has been set up for them, make sure you call
  ; x_enddisablegadgets() with the proper windownumber, or x_disablegadget(-1,n,0)
  ;
  ; note 2: nothing stops people from tabbing to the gadget, this one's just for those that
  ; have (quiet :-)) aspirations to write a visual designer :-)
  ;
  x_retval = 0
  If disable = #True
    ;
    ; *** disabling gadgets
    ;
    If windownr > 0
      If IsWindow(windownr)
        ;
        ; first process window: does it exist, was it already in the list, if not add it to list for windows and hook it
        ;
        window_h = WindowID(windownr)                                  ; handle of window
        found = #False                                                 ; is the window already hooked?
        If FirstElement(x_dgwindow()) <> 0
          Repeat
            If x_dgwindow()\windownr = windownr
              found = #True
            EndIf
          Until found = #True Or NextElement(x_dgwindow()) = 0
        EndIf
        If found = #False                                              ; wasn't hooked yet
          AddElement(x_dgwindow())                                     ; new window to monitor
          x_dgwindow()\windownr = windownr
          instance_h = GetModuleHandle_(0)                             ; do the hooky thing
          thread_id = GetWindowThreadProcessId_(window_h, 0)
          x_dgwindow()\mousehook_h = SetWindowsHookEx_(#WH_MOUSE, @x_dg_mousehookhandler(), instance_h, thread_id)
        EndIf
      Else
        x_retval = -1                                                  ; specified window does not exist, error
      EndIf
    ElseIf gadgetnr < 0                                                ; neither gadget nor window were specified, error
      x_retval = -1
    EndIf
    ;
    ; now the gadget: does it exist, was it already in the list, if not add to list for gadgets
    ;
    If x_retval > -1
      If IsGadget(gadgetnr)
        found = #False
        If FirstElement(x_dggadget()) <> 0
          Repeat
            If x_dggadget()\gadgetnr = gadgetnr                        ; already existed
              found = #True
            EndIf
          Until found = #True Or NextElement(x_dggadget()) = 0
        EndIf
        If found = #False                                              ; didn't exist so add
          AddElement(x_dggadget())
          x_dggadget()\gadgetnr = gadgetnr
          x_dggadget()\gadget_h = GadgetID(gadgetnr)
          x_dggadget()\windownr = windownr
        EndIf
      Else                                                             ; gadget does not exist
        x_retval = -1
      EndIf
    EndIf
    ;
  Else
    ;
    ; *** reenabling gadgets or windows
    ;
    If gadgetnr > -1
      found = #False
      If FirstElement(x_dggadget()) <> 0                               ; begin of list of gadgets
        Repeat
          If x_dggadget()\gadgetnr = gadgetnr                          ; found the gadget
            found = #True
          EndIf
        Until found = #True Or NextElement(x_dggadget()) = 0
        If found = #True                                               ; found now delete
          windownr = x_dggadget()\windownr                             ; but first remember windownr
          DeleteElement(x_dggadget())                                  ; delete from list of gadgets
          found = #False
          If FirstElement(x_dggadget())                                ; now check if there were more gadgets on the same window
            Repeat
              If x_dggadget()\windownr = windownr
                found = #True
              EndIf
            Until found = #True Or NextElement(x_dggadget()) = 0       ; keep on going until found or end of list
          EndIf
          If found = #False                                          ; no more gadgets on this window
            x_retval = x_enddisablegadgets(windownr)
          EndIf
        EndIf
      EndIf
    ElseIf windownr > -1
      x_retval = x_enddisablegadgets(windownr)
    Else
      x_retval = -1
    EndIf
    ;
  EndIf
  ;
  ProcedureReturn x_retval
  ;
EndProcedure

h = OpenWindow(1,300,200,400,300,"test",#PB_Window_SystemMenu)

ButtonGadget(1,10,10,20,20,"1")
ButtonGadget(2,30,10,20,20,"2")
ButtonGadget(3,50,10,20,20,"3")
x_disablegadget(1,1,1)
Repeat
  event = WaitWindowEvent()
Until event = #PB_Event_CloseWindow
x_enddisablegadgets(-1)

( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )