Page 1 of 2

Drag to Move/Resize Gadgets

Posted: Thu Feb 20, 2014 5:15 am
by IdeasVacuum
The following code allows gadgets to be dragged around the client area of the parent Window. I need to restrict that movement so that the gadgets only move along X. That works fine.

However, I also need to restrict the resize of the gadgets such that they can only be stretched along X. The code adds the #WS_SIZEBOX flag, and this gives the ability to resize the sample gadget (does not work with all gadget types, but StringGadget is a good one for my project). It has two issues though:

1) It adds an ugly border - I need to keep the gadget as-is, no border.
2) It allows the gadget to be resized in Y, I need to restrict resize to X only.

So, I think this is basically the wrong way to go about it, although it gets really close to what is needed.......

Code: Select all

Enumeration
#Win
#Gdt
EndEnumeration

Structure SubClassGadget
        hWnd.i
  oldWndProc.i
   mouseDown.i
   mouseOffX.i
   mouseOffY.i
EndStructure

Global NewList gadgets.SubClassGadget()

Procedure GadgetCallback(hWnd,Msg,wParam,lParam)
;----------------------------------------------

  Select Msg

             Case #WM_LBUTTONDOWN

                      ForEach gadgets()

                            If gadgets()\hWnd = hWnd

                                     gadgets()\mouseOffX = lParam & $FFFF
                                     gadgets()\mouseOffY = (lParam>>16) & $FFFF
                                     gadgets()\mouseDown = 1
                                     SetFocus_(hWnd)

                                     SetCursor_(LoadCursor_(0,#IDC_SIZEALL))

                                     ProcedureReturn 0
                            EndIf
                      Next

             Case #WM_SIZING

                      If wParam & #MK_LBUTTON

                              ForEach gadgets()

                                    If gadgets()\hWnd = hWnd And gadgets()\mouseDown

                                                SetCursor_(LoadCursor_(0,#IDC_SIZEWE))

                                              ResizeGadget(GetWindowLongPtr_(hWnd,#GWL_ID), #PB_Ignore, #PB_Ignore, #PB_Ignore, 30)

                                               SetCursor_(LoadCursor_(0,#IDC_SIZEALL))
                                              SetCapture_(hWnd)

                                              ProcedureReturn 0
                                    EndIf
                              Next

                      ElseIf wParam = 0

                              SetCursor_(LoadCursor_(0,#IDC_SIZEALL))
                      EndIf

             Case #WM_MOUSEMOVE

                      If wParam & #MK_LBUTTON

                              ForEach gadgets()

                                    If gadgets()\hWnd = hWnd And gadgets()\mouseDown

                                              GetCursorPos_(p.POINT)
                                              MapWindowPoints_(0,WindowID(#Win),@p,1)
                                              x = p\x - gadgets()\mouseOffX
                                              y = p\y - gadgets()\mouseOffY
                                              If x < 0 : x = 0 : EndIf
                                              If y < 0 : y = 0 : EndIf
                                              GetClientRect_(hWnd,rect.RECT)
                                              GetClientRect_(WindowID(#Win),rect2.RECT)
                                              If x > rect2\right  - rect\right  : x = rect2\right  - rect\right  : EndIf
                                              If y > rect2\bottom - rect\bottom : y = rect2\bottom - rect\bottom : EndIf
                                              ResizeGadget(GetWindowLongPtr_(hWnd,#GWL_ID), x, #PB_Ignore, #PB_Ignore, #PB_Ignore)

                                               SetCursor_(LoadCursor_(0,#IDC_SIZEALL))
                                              SetCapture_(hWnd)

                                              ProcedureReturn 0
                                    EndIf
                              Next

                      ElseIf wParam = 0

                              SetCursor_(LoadCursor_(0,#IDC_SIZEALL))
                      EndIf

             Case #WM_LBUTTONUP

                      ForEach gadgets()

                             If gadgets()\hWnd = hWnd

                                      gadgets()\mouseDown = 0
                             EndIf
                      Next

                       SetCursor_(LoadCursor_(0,#IDC_SIZEALL))
                      SetCapture_(0)

                      ProcedureReturn 0

             Case #WM_LBUTTONDBLCLK

                      ForEach gadgets()

                             If gadgets()\hWnd = hWnd

                                      FreeGadget(GetWindowLongPtr_(hWnd,#GWL_ID))
                             EndIf
                      Next

                      ProcedureReturn 0

  EndSelect

  ForEach gadgets()

           If gadgets()\hWnd = hWnd

                     ProcedureReturn CallWindowProc_(gadgets()\oldWndProc,hWnd,Msg,wParam,lParam)
           EndIf
  Next

EndProcedure

Procedure AddGadget(hGadget)
;---------------------------

          If IsGadget(hGadget)

                    hWnd = GadgetID(hGadget) ; for #PB_Any
          Else
                    hWnd = hGadget
          EndIf

          If hWnd

                    LastElement(gadgets())
                     AddElement(gadgets())

                       gadgets()\hWnd = hWnd
                 gadgets()\oldWndProc = SetWindowLongPtr_(hWnd,#GWL_WNDPROC,@GadgetCallback())
          EndIf

          ProcedureReturn hGadget

EndProcedure

If OpenWindow(#Win, 0, 0, 500, 300, "Test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

    SetWindowColor(#Win, RGB(100,60,60))


     AddGadget(StringGadget(#Gdt, 20, 20, 100, 30, "Test", #PB_String_BorderLess|#PB_String_ReadOnly|#PB_Text_Center|#WS_SIZEBOX))
    ;AddGadget(ContainerGadget(#Gdt, 20, 20, 100, 30, #WS_SIZEBOX))
    ;AddGadget(CanvasGadget(#Gdt, 20, 20, 100, 30, #WS_SIZEBOX))
             SetGadgetColor(#Gdt,#PB_Gadget_BackColor,RGB(175,255,175))


             Repeat

                   iEvent = WaitWindowEvent(1)

             Until iEvent = #PB_Event_CloseWindow
EndIf

End

Re: Drag to Move/Resize Gadgets

Posted: Fri Feb 21, 2014 2:16 pm
by chi
No ugly border and horizontal resize only (change #HTBOTTOMRIGHT to #HTRIGHT) ;)

Code: Select all

Procedure Resize()
  ResizeImage(0, GadgetWidth(3), GadgetHeight(3))
  StartDrawing(ImageOutput(0))
    Box(0,0,OutputWidth(), OutputHeight(), RGB(64,64,64))
    Circle(150,150,100, RGB(255,0,0))
    DrawingMode(#PB_2DDrawing_Transparent)
    DrawText(10,10, "ImageGadget inside Container")
  StopDrawing()
  SetGadgetState(4, ImageID(0))
EndProcedure

OpenWindow(0, 0, 0, 420, 300, "designer", #PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
SetWindowColor(0, RGB(37,37,38))

ButtonGadget(0, 140, 90, 140, 30, "move = LMB down")
SetWindowLongPtr_(GadgetID(0), #GWL_STYLE, GetWindowLongPtr_(GadgetID(0), #GWL_STYLE) | #WS_CLIPSIBLINGS)

StringGadget(1, 40, 70, 140, 30, "resize = Shift + LMB down")
SetWindowLongPtr_(GadgetID(1), #GWL_STYLE, GetWindowLongPtr_(GadgetID(1), #GWL_STYLE) | #WS_CLIPSIBLINGS)

ContainerGadget(3, 40, 115, 210, 100, #PB_Container_BorderLess)
  SetWindowLongPtr_(GadgetID(3), #GWL_STYLE, GetWindowLongPtr_(GadgetID(3), #GWL_STYLE) | #WS_CLIPSIBLINGS)
  CreateImage(0, GadgetWidth(3), GadgetHeight(3), 24, RGB(64,64,64))
  ImageGadget(4, 0, 0, GadgetWidth(3), GadgetHeight(3), 0)
  DisableGadget(4, #True)
  Resize()
  BindGadgetEvent(3, @Resize())  
CloseGadgetList()

Repeat
  event = WaitWindowEvent()
  Select event
      
    Case #WM_LBUTTONDOWN
      ReleaseCapture_()
      GetCursorPos_(cursorpos.POINT)
      gadget = WindowFromPoint_(PeekQ(cursorpos))
      If GetAsyncKeyState_(#VK_SHIFT) & 32768
        SendMessage_(gadget, #WM_NCLBUTTONDOWN, #HTBOTTOMRIGHT, 0) ; #HTRIGHT = stretch width only
      Else
        SendMessage_(gadget, #WM_NCLBUTTONDOWN, #HTCAPTION, 0)
      EndIf
      
  EndSelect
Until event = #PB_Event_CloseWindow

Re: Drag to Move/Resize Gadgets

Posted: Fri Feb 21, 2014 2:26 pm
by IdeasVacuum
Hi Chi ~ erm, code crashes on launch? :?

Re: Drag to Move/Resize Gadgets

Posted: Fri Feb 21, 2014 2:30 pm
by Thunder93
Resize() command is in the wrong place. At least needs to be moved one down.

Re: Drag to Move/Resize Gadgets

Posted: Fri Feb 21, 2014 2:37 pm
by chi
Strange! No problems with PB 5.21 LTS (x64 + x86). Code was written pretty fast, so there might be some other oddities ;)

Edit: code updated

Re: Drag to Move/Resize Gadgets

Posted: Fri Feb 21, 2014 2:52 pm
by Thunder93
chi wrote:Strange! No problems with PB 5.21 LTS (x64 + x86). Code was written pretty fast, so there might be some other oddities ;)
Might be a cache thing... Because the code that you originally posted wouldn't of worked in any version of PB. Resize() has dependencies. ImageGadget(4, is one of them. So doing the Resize() before that gadget creation, Resize() can't go very far in the process.

Re: Drag to Move/Resize Gadgets

Posted: Fri Feb 21, 2014 2:55 pm
by IdeasVacuum
Ah, that's better :)

Resize is not restricted to X only though, and I have to find a better input than Shift + LMB (it should just work, resize if mouse cursor is near the edge of the gadget, as per my example). I'm trying to workout how Falsam's code works for MindMap.

Re: Drag to Move/Resize Gadgets

Posted: Fri Feb 21, 2014 3:01 pm
by Thunder93
You had the following top-most in the Resize() function

Code: Select all

ResizeGadget(4, #PB_Ignore, #PB_Ignore, GadgetWidth(3), GadgetHeight(3))
So having the Resize() command before

Code: Select all

ImageGadget(4, 0, 0, GadgetWidth(3), GadgetHeight(3), ImageID(0))
would cause issues.

Re: Drag to Move/Resize Gadgets

Posted: Fri Feb 21, 2014 3:12 pm
by chi
Resize is not restricted to X only though
Just change SendMessage_(gadget, #WM_NCLBUTTONDOWN, #HTBOTTOMRIGHT, 0) to #HTRIGHT, #HTLEFT or whatever #HT? you like ^^
Might be a cache thing...
Never heard of that ;). But i have a problem with autocompletion (with-endwith) too, since last setup... who knows

Edit: After a restart my old code throws an error on ResizeGadget(4... WTF? :oops:

Re: Drag to Move/Resize Gadgets

Posted: Fri Feb 21, 2014 3:20 pm
by Thunder93
lol

Re: Drag to Move/Resize Gadgets

Posted: Fri Feb 21, 2014 3:54 pm
by IdeasVacuum
Actually, having removed half the code (it handles image gadget/button gadget, which I do not need) and using the #HTRIGHT flag as noted in the code, things look very encouraging! I think I should be able to use the gadget rect to determine whether the User is moving the gadget or stretching it. Thanks for the help :wink:

Re: Drag to Move/Resize Gadgets

Posted: Fri Feb 21, 2014 4:13 pm
by chi
np :D

Re: Drag to Move/Resize Gadgets

Posted: Sat Feb 22, 2014 3:28 am
by electrochrisso
Great stuff Chi. :)

Re: Drag to Move/Resize Gadgets

Posted: Mon Feb 24, 2014 9:51 am
by Kwai chang caine
Cool !!!
Thanks CHI 8)

Re: Drag to Move/Resize Gadgets

Posted: Mon Feb 24, 2014 2:37 pm
by chi
You're welcome :)