Jump to content

Recommended Posts

Posted (edited)

@MattyD  Sorry if we've been hijacking your thread, but in a sense it is all your fault.  Making such an innovative example will certainly attract some members of the community, right ?

Anyway, here my take to solve the minimize issue :

#include <guiConstants.au3>
#include <winapi.au3>

Opt("MustDeclareVars", True)

Global Const $tagMOUSEHOOKSTRUCT = "dword X;dword Y;hwnd hwnd;uint wHitTestCode;ulong_ptr dwExtraInfo;"

Global $hGUI, $idBtn, $idBtn2, $hHook

Example()

Func Example()
  $hGUI = GUICreate("WM_NCHITTEST", 300, 200, -1, -1, $WS_OVERLAPPEDWINDOW)
  $idBtn = GUICtrlCreateButton("Button 1", 4, 4, 80, 80, $WS_CLIPSIBLINGS)
  $idBtn2 = GUICtrlCreateButton("Button 2", 90, 4, 80, 80, $WS_CLIPSIBLINGS)
  Local $idLockButtons = GUICtrlCreateCheckbox("Lock Buttons", 200, 20, 80, 20)

  Local $hDll = DllCallbackRegister(ButtonMoveProc, 'lresult', 'hwnd;uint;wparam;lparam;uint_ptr;dword_ptr')
  _WinAPI_SetWindowSubclass(GUICtrlGetHandle($idBtn), DllCallbackGetPtr($hDll), $idBtn)
  _WinAPI_SetWindowSubclass(GUICtrlGetHandle($idBtn2), DllCallbackGetPtr($hDll), $idBtn2)

  Local $hStub = DllCallbackRegister(WM_MOUSE, "LRESULT", "int;wparam;lparam")
  $hHook = _WinAPI_SetWindowsHookEx($WH_MOUSE, DllCallbackGetPtr($hStub), 0, _WinAPI_GetCurrentThreadId())

  GUISetState()

  Local $iMsg

  While True
    $iMsg = GUIGetMsg()
    Switch $iMsg
      Case $GUI_EVENT_CLOSE
        ExitLoop
      Case $idLockButtons
        If GUICtrlRead($iMsg) = $GUI_CHECKED Then
          _WinAPI_RemoveWindowSubclass(GUICtrlGetHandle($idBtn), DllCallbackGetPtr($hDll), $idBtn)
          _WinAPI_RemoveWindowSubclass(GUICtrlGetHandle($idBtn2), DllCallbackGetPtr($hDll), $idBtn2)
          _WinAPI_UnhookWindowsHookEx($hHook)
        Else
          _WinAPI_SetWindowSubclass(GUICtrlGetHandle($idBtn), DllCallbackGetPtr($hDll), $idBtn, 0)
          _WinAPI_SetWindowSubclass(GUICtrlGetHandle($idBtn2), DllCallbackGetPtr($hDll), $idBtn2, 0)
          $hHook = _WinAPI_SetWindowsHookEx($WH_MOUSE, DllCallbackGetPtr($hStub), 0, _WinAPI_GetCurrentThreadId())
        EndIf
      Case $idBtn, $idBtn2
        ConsoleWrite("Click " & GUICtrlRead($iMsg) & @CRLF)
    EndSwitch
  WEnd

  GUIDelete()
  _WinAPI_RemoveWindowSubclass(GUICtrlGetHandle($idBtn), DllCallbackGetPtr($hDll), $idBtn)
  _WinAPI_RemoveWindowSubclass(GUICtrlGetHandle($idBtn2), DllCallbackGetPtr($hDll), $idBtn2)
  DllCallbackFree($hDll)
  _WinAPI_UnhookWindowsHookEx($hHook)
  DllCallbackFree($hStub)
EndFunc   ;==>Example

Func ButtonMoveProc($hWnd, $iMsg, $wParam, $lParam, $iID, $iData)
  Local $aPos, $iRet, $aPoint[2], $iSrc, $iEvent, $hCursor

  Switch $iMsg
    Case $WM_NCHITTEST
      $aPos = WinGetPos($hWnd)

      $aPoint[0] = BitAND($lParam, 0xFFFF)
      $aPoint[1] = BitShift($lParam, 16)

      $iRet = $HTCAPTION
      If $aPoint[0] - $aPos[0] < 10 Then $iRet = $HTLEFT
      If $aPoint[0] - $aPos[0] > ($aPos[2] - 10) Then $iRet = $HTRIGHT

      If $aPoint[1] - $aPos[1] < 10 Then
        Switch $iRet
          Case $HTLEFT
            $iRet = $HTTOPLEFT
          Case $HTRIGHT
            $iRet = $HTTOPRIGHT
          Case Else
            $iRet = $HTTOP
        EndSwitch
      ElseIf $aPoint[1] - $aPos[1] > ($aPos[3] - 10) Then
        Switch $iRet
          Case $HTLEFT
            $iRet = $HTBOTTOMLEFT
          Case $HTRIGHT
            $iRet = $HTBOTTOMRIGHT
          Case Else
            $iRet = $HTBOTTOM
        EndSwitch
      EndIf
      Return $iRet

    Case $WM_SETCURSOR
      $iSrc = BitAND($lParam, 0xFFFF)
      $iEvent = BitShift($lParam, 16)
      If $iSrc = $HTCAPTION And $iEvent = $WM_LBUTTONDOWN Then
        _WinAPI_RedrawWindow($hWnd, 0, 0, $RDW_INVALIDATE + $RDW_FRAME)
        $hCursor = _WinAPI_LoadCursor(0, $OCR_SIZEALL)
        _WinAPI_SetCursor($hCursor)
        Return True
      EndIf
  EndSwitch
  Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>ButtonMoveProc

Func WM_MOUSE($iMsg, $wParam, $lParam)
  If $iMsg < 0 Then Return _WinAPI_CallNextHookEx($hHook, $iMsg, $wParam, $lParam)
  If $wParam = $WM_LBUTTONUP Then
    Local $tMouse = DllStructCreate($tagMOUSEHOOKSTRUCT, $lParam)
    If $tMouse.hwnd = GUICtrlGetHandle($idBtn) Or $tMouse.hwnd = GUICtrlGetHandle($idBtn2) Then
      Local $idCtrl = _WinAPI_GetDlgCtrlID($tMouse.hwnd)
      Local $aPos = ControlGetPos($hGUI, "", $idCtrl)
      GUICtrlSetPos($idCtrl, $aPos[0], $aPos[1])
    EndIf
  EndIf
  Return _WinAPI_CallNextHookEx($hHook, $iMsg, $wParam, $lParam)
EndFunc   ;==>WM_MOUSE

ps. I converted it to subclassing :ermm:

Edited by Nine
Posted

Nah all good :) Its all very interesting.

I might experiment some more to see if I can discover what ControlSetPos is actually doing behind the scenes :think:. I mean calling it works a treat - but surely we shouldn't need to move everything twice.

 

 

Posted
8 hours ago, MattyD said:

what ControlSetPos is actually doing behind the scenes

Do you mean ControlMove or GUICtrlSetPos ?  In any case, I tend to believe that there is an underlying bug behind all this minimize issue. 

8 hours ago, MattyD said:

but surely we shouldn't need to move everything twice

Totally agree.  

Posted
2 hours ago, ptrex said:

When the  windows is resized the mouse control to release the button to the new position doesn't work anymore ?

Only when the window is not resized all is OK

You mean with @pixelsearch base code ?  It is working alright, just the flickers is quite annoying after resize.  But with the snippet I provided, it makes it very tolerable.

With @MattyD base code there is no is issue (no flickers) before or after resize. 

However, both codes have the same problem on minimize/restore, the controls get restored to their original places.  But solutions was found in both cases.

Posted (edited)
39 minutes ago, Nine said:

However, both codes have the same problem on minimize/restore, the controls get restored to their original places.  But solutions was found in both cases.

So in my case (and with your help) there is no Minimize/Restore bug when using GUICtrlSetPos() instead of ControlMove

Now if we refer to this post from @Melba23 this is not a bug, here is an excerpt of his post :

The 2 types of commands do not have the same "prefix" as they are used differently:

    Any command that begins GUICtrl* is to be used on an AutoIt GUI created by the script itself - hence the use of a ControlID only to identify the control to be actioned.
    
    Commands that begin Control* can be used on any GUI - hence the requirement to define the GUI by title and text as well as providing a ControlID.

So we should have in mind to always use the GUICtrl* commands when the GUI is created by our own script (my case) and everything should be fine, fingers crossed :)

Edited by pixelsearch
typo

"I think you are searching a bug where there is no bug... don't listen to bad advice."

Posted (edited)

I understand what you are saying.  But in the original code from @MattyD there is no Control* function used at all.  And the minimize/restore problem is still there.  I had to set position again with GUICtrlSetPos to make it work (I do not think it is normal). 

Edit Here an interesting test I just made.

Local $hWnd = WinGetHandle("Express")
WinActivate($hWnd)
Local $hCtrl = ControlGetHandle($hWnd, "", "Button6")
Local $aPos = ControlGetPos($hWnd, "", $hCtrl)
ControlMove($hWnd, "", $hCtrl, $aPos[0] + 50, $aPos[1])

Using an outside window (Express Burn), when I move a button and I minimize/restore the window..... well, control returns to its original place.  Just like what AutoIt GUI does.  Seems it is a Windows behavior not a bug like I said.

ReEdit : tried with _WinAPI_SetWindowPos.  Same behavior, same result.

Edited by Nine
Posted (edited)

I tried the traditional method of applying resize
... but it overflowed a little :lol:

#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <EditConstants.au3>
#include <WinAPI.au3>

Example()

Func Example()
    Local $hGui = GUICreate("", 300, 200, -1, -1, $WS_OVERLAPPEDWINDOW)
    Local $idBtn1 = GUICtrlCreateButton("Button 1", 10, 40, 80, 80, $WS_CLIPSIBLINGS)
    Local $idBtn2 = GUICtrlCreateButton("Button 2", 100, 40, 80, 80, $WS_CLIPSIBLINGS)
    Local $idInput = GUICtrlCreateInput("Test 123 Text", 10, 10, 170, 20, BitOR($ES_CENTER, $WS_CLIPSIBLINGS))
    Local $idLockButtons = GUICtrlCreateCheckbox("Lock Buttons", 200, 20, 80, 20, $WS_CLIPSIBLINGS)
    Local $bLock = False
    GUISetState()

    Local $iMsg, $aInfo

    While 1
        $iMsg = GUIGetMsg()
        Switch $iMsg
            Case $GUI_EVENT_CLOSE
                Exit
            Case $idLockButtons
                $bLock = (GUICtrlRead($iMsg) = $GUI_CHECKED)
                ConsoleWrite("- Lock Buttons is " & _
                        (GUICtrlRead($iMsg) = 1 ? "Checked" : "Un-Checked") & @CRLF)
            Case $idBtn1
                If Not $bLock Then ContinueLoop
                ConsoleWrite("- Button 1 is pressed" & @CRLF)
            Case $idBtn2
                If Not $bLock Then ContinueLoop
                ConsoleWrite("- Button 2 is pressed" & @CRLF)
            Case $GUI_EVENT_PRIMARYDOWN
                If $bLock Then ContinueLoop
                $aInfo = GUIGetCursorInfo($hGui)
                If (Not @error) And ($aInfo[4] = $idBtn1 Or $aInfo[4] = $idBtn2 Or $aInfo[4] = $idInput) Then
                    _Resize($hGui)
                EndIf
        EndSwitch
    WEnd
EndFunc   ;==>Example

Func _Resize($hWnd, $iGrid = 5)
    If Not WinActive($hWnd) Then Return
    Local $aInfo = GUIGetCursorInfo($hWnd)
    Local $idControl = $aInfo[4]
    If $idControl = 0 Then Return

    If $iGrid < 1 Then $iGrid = 1

    Local $iEdge = 5
    Local $CtrlPos = ControlGetPos($hWnd, "", $idControl)
    Local $CtrlX = $CtrlPos[0]
    Local $CtrlY = $CtrlPos[1]
    Local $CtrlW = $CtrlPos[2]
    Local $CtrlH = $CtrlPos[3]

    Local $MouseX = $aInfo[0]
    Local $MouseY = $aInfo[1]

    Local $LeftEdge = Abs($MouseX - $CtrlX) < $iEdge
    Local $RightEdge = Abs($MouseX - ($CtrlX + $CtrlW)) < $iEdge
    Local $TopEdge = Abs($MouseY - $CtrlY) < $iEdge
    Local $BottomEdge = Abs($MouseY - ($CtrlY + $CtrlH)) < $iEdge

    _WinAPI_SetWindowPos(GUICtrlGetHandle($idControl), $HWND_TOP, 0, 0, 0, 0, $SWP_NOMOVE + $SWP_NOSIZE)

    Local $iCursorId = MouseGetCursor()
    Local $aInfoNew = $aInfo

    If $LeftEdge Or $RightEdge Or $TopEdge Or $BottomEdge Then
        ; ## Resizing ##
        Local $resizeMode = 0
        If $LeftEdge Then $resizeMode += 1
        If $RightEdge Then $resizeMode += 2
        If $TopEdge Then $resizeMode += 4
        If $BottomEdge Then $resizeMode += 8

        ; Set cursor for resizing
        Switch $resizeMode
            Case 1, 2  ; Left, Right edge
                GUISetCursor(13, 1, $hWnd)
            Case 4, 8  ; Top, Bottom edge
                GUISetCursor(11, 1, $hWnd)
            Case 5, 10 ; Top-left, Bottom-right corner
                GUISetCursor(12, 1, $hWnd)
            Case 6, 9  ; Top-right, Bottom-left corner
                GUISetCursor(10, 1, $hWnd)
        EndSwitch

        Do
            $aInfo = GUIGetCursorInfo($hWnd)
            If $aInfoNew[0] <> $aInfo[0] Or $aInfoNew[1] <> $aInfo[1] Then
                $MouseX = $aInfo[0]
                $MouseY = $aInfo[1]

                Switch $resizeMode
                    Case 1 ; Left edge
                        $CtrlW += $CtrlX - $MouseX
                        $CtrlX = $MouseX
                    Case 2 ; Right edge
                        $CtrlW = $MouseX - $CtrlX
                    Case 4 ; Top edge
                        $CtrlH += $CtrlY - $MouseY
                        $CtrlY = $MouseY
                    Case 8 ; Bottom edge
                        $CtrlH = $MouseY - $CtrlY
                    Case 5 ; Top-left corner
                        $CtrlW += $CtrlX - $MouseX
                        $CtrlX = $MouseX
                        $CtrlH += $CtrlY - $MouseY
                        $CtrlY = $MouseY
                    Case 6 ; Top-right corner
                        $CtrlW = $MouseX - $CtrlX
                        $CtrlH += $CtrlY - $MouseY
                        $CtrlY = $MouseY
                    Case 9 ; Bottom-left corner
                        $CtrlW += $CtrlX - $MouseX
                        $CtrlX = $MouseX
                        $CtrlH = $MouseY - $CtrlY
                    Case 10 ; Bottom-right corner
                        $CtrlW = $MouseX - $CtrlX
                        $CtrlH = $MouseY - $CtrlY
                EndSwitch

                ; Snap to grid
                $CtrlX = Round($CtrlX / $iGrid) * $iGrid
                $CtrlY = Round($CtrlY / $iGrid) * $iGrid
                $CtrlW = Round($CtrlW / $iGrid) * $iGrid
                $CtrlH = Round($CtrlH / $iGrid) * $iGrid

                ; minimum size
                If $CtrlW < 15 Then $CtrlW = 15
                If $CtrlH < 15 Then $CtrlH = 15

                GUICtrlSetPos($idControl, $CtrlX, $CtrlY, $CtrlW, $CtrlH)
            EndIf

            Sleep(10)
        Until Not $aInfo[2]

    ElseIf $MouseX > $CtrlX + $iEdge And $MouseX < ($CtrlX + $CtrlW - $iEdge) And _
            $MouseY > $CtrlY + $iEdge And $MouseY < ($CtrlY + $CtrlH - $iEdge) Then
        ; ## Moving ##
        GUISetCursor(0, 1, $hWnd)
        Local $OffsetX = $MouseX - $CtrlX
        Local $OffsetY = $MouseY - $CtrlY

        Do
            $aInfo = GUIGetCursorInfo($hWnd)
            If $aInfoNew[0] <> $aInfo[0] Or $aInfoNew[1] <> $aInfo[1] Then
                Local $NewX = Round(($aInfo[0] - $OffsetX) / $iGrid) * $iGrid
                Local $NewY = Round(($aInfo[1] - $OffsetY) / $iGrid) * $iGrid
                GUICtrlSetPos($idControl, $NewX, $NewY, $CtrlW, $CtrlH)
            EndIf

            Sleep(10)
        Until Not $aInfo[2]
    EndIf
    GUISetCursor($iCursorId, 0, $hWnd)
EndFunc   ;==>_Resize

... and since I did it, I want to share it

 

Edit:
I entered the grid parameter.

 

Edited by ioa747
I entered the grid parameter.

I know that I know nothing

Posted (edited)

Ok so here's a test to see whats going on with GUICtrlSetPos. I tried inspecting whats being sent to the button - Bear with me...

Spoiler
#include <guiConstants.au3>
#include <winapi.au3>
#include <GUIButton.au3>

Opt("MustDeclareVars", 1)

Global Const $SC_MINIMIZE = 0xF020
Global Const $SC_RESTORE = 0xF120

Global $tagMSG = "hwnd hwnd;uint Message;wparam wParam;lparam lParam;dword time;" & $tagPoint & ";dword private"
Global $tagNCCALCSIZE_PARAMS = "int rect1[4];int rect2[4];int rect3[4];ptr WinPos"


Global $hGui = GUICreate("", 300, 200)

;~ Global $hBtn = _GUICtrlButton_Create($hGUI, "Button 1", 4, 4, 80, 80)
;~ Global $idBtn = _WinAPI_GetDlgCtrlID($hBtn)

Global $idBtn = GUICtrlCreateButton("Button 1", 4, 4, 80, 80)
Global $hBtn = GUICtrlGetHandle($idBtn)

Global $hBtnMoveProc = DllCallbackRegister("ButtonInspect", "long", "hwnd;uint;wparam;lparam")
Global $pBtnMoveProc = DllCallbackGetPtr($hBtnMoveProc)

Global $pOrigBtnProc = _WinAPI_SetWindowLong($hBtn, $GWL_WNDPROC, $pBtnMoveProc)

GUISetState()
GUIRegisterMsg($WM_SYSCOMMAND, "WM_SYSCOMMAND")

While 1
    Local $iMsg = GUIGetMsg()
    Switch $iMsg
        Case $GUI_EVENT_CLOSE
            Exit

        Case $GUI_EVENT_MINIMIZE
            ConsoleWrite("---End Min---" & @CRLF)

        Case $GUI_EVENT_RESTORE
            ConsoleWrite("---End Restore---" & @CRLF)

    EndSwitch

WEnd

Func ButtonInspect($hWnd, $uMsg, $wParam, $lParam)

    Local $iRet, $aRes, $tNCCALCSIZE

    Switch $uMsg
        Case $WM_NCHITTEST
            $iRet = _WinAPI_DefWindowProcW($hWnd, $uMsg, $wParam, $lParam)
            ConsoleWrite("WM_NCHITTEST" & @CRLF)
            ConsoleWrite(StringFormat("\tMouse[%d, %d]", BitShift($lParam, 16), BitAND($lParam, 0xFFFF)) & @CRLF)
            ConsoleWrite(StringFormat("\tRET (Area)[%d]", $iRet) & @CRLF)

            ConsoleWrite("----Set Pos----" & @CRLF)
            GUICtrlSetPos($idBtn, 80, 80, 100, 100)
;~          _WinAPI_SetWindowPos($hWnd, $HWND_TOP, 80, 80, 100, 100, $SWP_FRAMECHANGED)
            ConsoleWrite("---End Set Pos---" & @CRLF)

            Return $iRet

        Case $WM_GETDLGCODE
            $iRet = _WinAPI_DefWindowProcW($hWnd, $uMsg, $wParam, $lParam)
            ConsoleWrite("WM_GETDLGCODE" & @CRLF)
            ConsoleWrite(StringFormat("\tvKey[0x%02x]", $wParam) & @CRLF)
            If $lParam Then
                Local $tMsg = DllStructCreate($tagMSG, $lParam)
                ConsoleWrite(StringFormat("\tMsg[0x%08x]", $tMsg.Message) & @CRLF)
                ConsoleWrite(StringFormat("\twParam[0x%08x]", $tMsg.wParam) & @CRLF)
                ConsoleWrite(StringFormat("\tlParam[0x%08x]", $tMsg.lParam) & @CRLF)
                ConsoleWrite(StringFormat("\tTime[0x%08x]", $tMsg.time) & @CRLF)
                ConsoleWrite(StringFormat("\tPoint[%d, %d]", $tMsg.X, $tMsg.Y) & @CRLF)
            EndIf
            ConsoleWrite(StringFormat("\tRET[0x%08x]", $iRet) & @CRLF)
            Return $iRet

        Case $WM_IME_SETCONTEXT
            $iRet = _WinAPI_DefWindowProcW($hWnd, $uMsg, $wParam, $lParam)
            ConsoleWrite("WM_IME_SETCONTEXT" & @CRLF)
            ConsoleWrite(StringFormat("\tWinActive[%d]", $wParam) & @CRLF)
            ConsoleWrite(StringFormat("\tOptions[0x%08x]", $lParam) & @CRLF)
            ConsoleWrite(StringFormat("\tRET[0x%08x]", $iRet) & @CRLF)
            Return $iRet

        Case $WM_IME_NOTIFY
            $iRet = _WinAPI_DefWindowProcW($hWnd, $uMsg, $wParam, $lParam)
            ConsoleWrite("WM_IME_NOTIFY" & @CRLF)
            ConsoleWrite(StringFormat("\tCommand[0x%08x]", $wParam) & @CRLF)
            ConsoleWrite(StringFormat("\tData[0x%08x]", $lParam) & @CRLF)
            ConsoleWrite(StringFormat("\tRET[0x%08x]", $iRet) & @CRLF)
            Return $iRet

        Case $WM_KILLFOCUS
            $iRet = _WinAPI_DefWindowProcW($hWnd, $uMsg, $wParam, $lParam)
            ConsoleWrite("WM_KILLFOCUS" & @CRLF)
            ConsoleWrite(StringFormat("\tKBFocusHWND[0x%08x]", $wParam) & @CRLF)
            Return $iRet

        Case $WM_CHILDACTIVATE
            $iRet = _WinAPI_DefWindowProcW($hWnd, $uMsg, $wParam, $lParam)
            ConsoleWrite("WM_CHILDACTIVATE" & @CRLF)
            Return $iRet

        Case $WM_SETCURSOR
            $iRet = _WinAPI_DefWindowProcW($hWnd, $uMsg, $wParam, $lParam)
            ConsoleWrite("WM_SETCURSOR" & @CRLF)
            ConsoleWrite(StringFormat("\tCursorHwnd[0x%08x]", $wParam) & @CRLF)
            ConsoleWrite(StringFormat("\tCauseMsg[0x%04x]", BitShift($lParam, 16)) & @CRLF)
            ConsoleWrite(StringFormat("\tHitTest[%d]", BitAND($lParam, 0xFFFF)) & @CRLF)
            ConsoleWrite(StringFormat("\tRET[0x%08x]", $iRet) & @CRLF)
            Return $iRet

        Case $WM_WINDOWPOSCHANGING
            $iRet = _WinAPI_DefWindowProcW($hWnd, $uMsg, $wParam, $lParam)
            ConsoleWrite("WM_WINDOWPOSCHANGING" & @CRLF)
            _DispWinPos($lParam)
            Return $iRet

        Case $WM_NCCALCSIZE
            $iRet = _WinAPI_DefWindowProcW($hWnd, $uMsg, $wParam, $lParam)

            Local $tNCCALCSIZE
            ConsoleWrite("WM_NCCALCSIZE" & @CRLF)
            ConsoleWrite(StringFormat("\twParam[%d]", $wParam) & @CRLF)
            If $wParam Then
                $tNCCALCSIZE = DllStructCreate($tagNCCALCSIZE_PARAMS, $lParam)
                ConsoleWrite(StringFormat("\tNewPos[%d %d %d %d]", $tNCCALCSIZE.rect1(1), $tNCCALCSIZE.rect1(2), $tNCCALCSIZE.rect1(3), $tNCCALCSIZE.rect1(4)) & @CRLF)
                ConsoleWrite(StringFormat("\tOldPos[%d %d %d %d]", $tNCCALCSIZE.rect2(1), $tNCCALCSIZE.rect2(2), $tNCCALCSIZE.rect2(3), $tNCCALCSIZE.rect2(4)) & @CRLF)
                ConsoleWrite(StringFormat("\tOldClientPos[%d %d %d %d]", $tNCCALCSIZE.rect3(1), $tNCCALCSIZE.rect3(2), $tNCCALCSIZE.rect3(3), $tNCCALCSIZE.rect3(4)) & @CRLF)
                _DispWinPos($tNCCALCSIZE.WinPos)
            Else
                $tNCCALCSIZE = DllStructCreate($tagRect, $lParam)
                ;proc may change rect data.
                ConsoleWrite(StringFormat("\tProposed[%d %d %d %d]", $tNCCALCSIZE.Left, $tNCCALCSIZE.Top, $tNCCALCSIZE.Right, $tNCCALCSIZE.Bottom) & @CRLF)
            EndIf

            ConsoleWrite(StringFormat("\tRET[0x%08x]", $iRet) & @CRLF)
            Return $iRet

        Case $WM_MOVE
            $iRet = _WinAPI_DefWindowProcW($hWnd, $uMsg, $wParam, $lParam)
            ConsoleWrite("WM_MOVE" & @CRLF)
            ConsoleWrite(StringFormat("\tPos[%d, %d]", BitShift($lParam, 16), BitAND($lParam, 0xFFFF)) & @CRLF)
            Return $iRet

        Case $WM_SIZE
            $iRet = _WinAPI_DefWindowProcW($hWnd, $uMsg, $wParam, $lParam)
            ConsoleWrite("WM_SIZE" & @CRLF)
            ConsoleWrite(StringFormat("\tType[%d]", $wParam) & @CRLF)
            ConsoleWrite(StringFormat("\tDims[%d, %d]", BitShift($lParam, 16), BitAND($lParam, 0xFFFF)) & @CRLF)
            Return $iRet

        Case $WM_WINDOWPOSCHANGED
            $iRet = _WinAPI_DefWindowProcW($hWnd, $uMsg, $wParam, $lParam)
            ConsoleWrite("WM_WINDOWPOSCHANGED" & @CRLF)
            _DispWinPos($lParam)
            Return $iRet

        Case $WM_GETOBJECT
            $iRet = _WinAPI_DefWindowProcW($hWnd, $uMsg, $wParam, $lParam)
            ConsoleWrite("WM_GETOBJECT" & @CRLF)
            ConsoleWrite(StringFormat("\tFlags[0x%08x]", $wParam) & @CRLF)
            ConsoleWrite(StringFormat("\tObjId[0x%08x]", $lParam) & @CRLF)
            ConsoleWrite(StringFormat("\tRET[0x%08x]", $iRet) & @CRLF)
            Return $iRet

        Case $WM_MOUSEMOVE
            $iRet = _WinAPI_DefWindowProcW($hWnd, $uMsg, $wParam, $lParam)
            ConsoleWrite("WM_MOUSEMOVE" & @CRLF)
            ConsoleWrite(StringFormat("\tvKey[0x%08x]", $wParam) & @CRLF)
            ConsoleWrite(StringFormat("\tPos[%d, %d]", BitShift($lParam, 16), BitAND($lParam, 0xFFFF)) & @CRLF)
            Return $iRet

        Case $WM_GETTEXTLENGTH
            $iRet = _WinAPI_DefWindowProcW($hWnd, $uMsg, $wParam, $lParam)
            ConsoleWrite("WM_GETTEXTLENGTH" & @CRLF)
            ConsoleWrite(StringFormat("\tRET[%d]", $iRet) & @CRLF)
            Return $iRet

        Case $WM_GETTEXT
            $iRet = _WinAPI_DefWindowProcW($hWnd, $uMsg, $wParam, $lParam)
            ConsoleWrite("WM_GETTEXT" & @CRLF)
            ConsoleWrite(StringFormat("\tLenInclNull[%d]", $wParam) & @CRLF)
            ConsoleWrite(StringFormat("\tpBuff[0x%08x]", $lParam) & @CRLF)
            ConsoleWrite(StringFormat("\tRET[%d]", $iRet) & @CRLF)
            Return $iRet

            ;;;; Below affects the painting process - need Autoit proc to handle these.

        Case $WM_SETFOCUS
            $aRes = DllCallAddress("long", $pOrigBtnProc, "hwnd", $hWnd, "uint", $uMsg, "wparam", $wParam, "lparam", $lParam)
            $iRet = $aRes[0]
            ConsoleWrite("WM_SETFOCUS" & @CRLF)
            ConsoleWrite(StringFormat("\tPrevWin[0x%08x]", $wParam) & @CRLF)
            Return $iRet

        Case $WM_ERASEBKGND
            $aRes = DllCallAddress("long", $pOrigBtnProc, "hwnd", $hWnd, "uint", $uMsg, "wparam", $wParam, "lparam", $lParam)
            $iRet = $aRes[0]
            ConsoleWrite("WM_ERASEBKGND" & @CRLF)
            ConsoleWrite(StringFormat("\thDC[0x%08x]", $wParam) & @CRLF)
            ConsoleWrite(StringFormat("\tRET[%d]", $iRet) & @CRLF)
            Return $iRet

        Case $WM_NCPAINT
            $aRes = DllCallAddress("long", $pOrigBtnProc, "hwnd", $hWnd, "uint", $uMsg, "wparam", $wParam, "lparam", $lParam)
            $iRet = $aRes[0]
            ConsoleWrite("WM_NCPAINT" & @CRLF)
            ConsoleWrite(StringFormat("\tUpdateRegion[0x%08x]", $wParam) & @CRLF)
            Return $iRet

        Case $WM_PAINT
            $aRes = DllCallAddress("long", $pOrigBtnProc, "hwnd", $hWnd, "uint", $uMsg, "wparam", $wParam, "lparam", $lParam)
            $iRet = $aRes[0]
            ConsoleWrite("WM_PAINT" & @CRLF)
            Return $iRet

        Case $BM_SETSTATE
            $aRes = DllCallAddress("long", $pOrigBtnProc, "hwnd", $hWnd, "uint", $uMsg, "wparam", $wParam, "lparam", $lParam)
            $iRet = $aRes[0]
            ConsoleWrite("BM_SETSTATE" & @CRLF)
            ConsoleWrite(StringFormat("\tHilighted[%d]", $wParam) & @CRLF)
            Return $iRet

        Case Else
            $iRet = _WinAPI_DefWindowProcW($hWnd, $uMsg, $wParam, $lParam)
;~          $aRes = DllCallAddress("long", $pOrigBtnProc, "hwnd", $hWnd, "uint", $uMsg, "wparam", $wParam, "lparam", $lParam)
;~          $iRet = $aRes[0]
            ConsoleWrite(StringFormat("msg: 0x%04x %-5s ret(%d) wparam( 0x%08x ) lparam( 0x%08x )", $uMsg, "(" & $uMsg & ")", $iRet, $wParam, $lParam) & @CRLF)
            Return $iRet

    EndSwitch
EndFunc   ;==>ButtonInspect

Func _DispWinPos($pPos)
    Local $tPos = DllStructCreate($tagWINDOWPOS, $pPos)
    ConsoleWrite(StringFormat("\tInsertAfter [0x%0x8]", $tPos.InsertAfter) & @CRLF)
    ConsoleWrite(StringFormat("\tpos [%d %d %d %d]", $tPos.X, $tPos.Y, $tPos.CX, $tPos.CY) & @CRLF)
    ConsoleWrite(StringFormat("\tFlags [0x%0x8]", $tPos.InsertAfter) & @CRLF)
EndFunc   ;==>_DispWinPos

Func WM_SYSCOMMAND($hWnd, $uMsg, $wParam, $lParam)
    If $wParam = $SC_MINIMIZE Then
        ConsoleWrite("---Start MIN---" & @CRLF)
    ElseIf $wParam = $SC_RESTORE Then
        ConsoleWrite("---Start Restore---" & @CRLF)
    EndIf
EndFunc   ;==>WM_SYSCOMMAND

 

 

So run this > mouse over the control (it will jump) > then minimise > restore > esc (Exit).
Next on line 58, uncomment _WinAPI_SetWindowPos & comment out GUICtrlSetPos

I found the end result is near identical - except

    _WinAPI_SetWindowPos  sends a WM_CHILDACTIVATE when moving the control (I doubt this matters)
    and WM_WINDOWPOSCHANGING has different coordinates after restoring.

OK next uncomment 16 & 17, Comment out 19 & 20. Repeat the experiment.
_WinAPI_SetWindowPos now works properly for minimize/restore (buttons now created with _GUICtrlButton_Create),  and GUICtrlSetPos breaks totally.

So I'm guessing Auitoit is keeping track of the controls that it creates, and is manually telling them where to go during the restore procedure.
And I figure if we wanted to go deeper we could probably just wite our own restore func to test this... But I haven't got around to that just yet!

Edit: Then again this seems inconsistent with what @Nine found with the external window - so maybe I'm still missing something....

Edited by MattyD
clarity
Posted (edited)

Here's a simpler test. This time we're defining the main gui proc.

When $bBypassAutoItHdlr = False then we're letting Autoit's message handler do its thing, otherwise we're bypassing it (That's my understanding anyway!).

So we can see _WinAPI_SetWindowsPos() does indeed work with a minimize/restore when $bBypassAutoItHdlr = True.  So I guess the next task is to find which messages introduce the behavior.

#include <guiConstants.au3>
#include <winapi.au3>

Opt("MustDeclareVars", 1)

Global Const $SC_MINIMIZE = 0xF020
Global Const $SC_RESTORE = 0xF120
Global Const $SC_CLOSE = 0xF060

Global $hGui = GUICreate("", 300, 200, 100, 100)

Global $idBtn = GUICtrlCreateButton("Button 1", 4, 4, 80, 80)
Global $hBtn = GUICtrlGetHandle($idBtn)

Global $hGUIProc = DllCallbackRegister("GUIProc", "long", "hwnd;uint;wparam;lparam")
Global $pGUIProc = DllCallbackGetPtr($hGUIProc)
Global $pOrigGUIProc = _WinAPI_SetWindowLong($hGUI, $GWL_WNDPROC, $pGUIProc)

Global $bBypassAutoItHdlr = False
GUISetState()

_WinAPI_SetWindowPos($hBtn, $HWND_TOP, 80, 80, 100, 100, 0)
;~ GUICtrlSetPos($idBtn, 80, 80, 100, 100)

While WinExists($hGUI)
    Sleep(10)
WEnd

Func guiProc($hWnd, $uMsg, $wParam, $lParam)

    Local $iRet, $aRes

    Switch $uMsg
        Case $WM_SYSCOMMAND

            Switch $wParam
                Case $SC_CLOSE
                    $iRet = _WinAPI_DefWindowProcW($hWnd, $uMsg, $wParam, $lParam)
                    GUIDelete($hGUI)

                Case Else
                    If $bBypassAutoItHdlr Then
                        $iRet = _WinAPI_DefWindowProcW($hWnd, $uMsg, $wParam, $lParam)
                    Else
                        $aRes = DllCallAddress("long", $pOrigGuiProc, "hwnd", $hWnd, "uint", $uMsg, "wparam", $wParam, "lparam", $lParam)
                        $iRet = $aRes[0]
                    EndIf
            EndSwitch

        Case $WM_DESTROY
            $aRes = DllCallAddress("long", $pOrigGuiProc, "hwnd", $hWnd, "uint", $uMsg, "wparam", $wParam, "lparam", $lParam)
            $iRet = $aRes[0]

        Case Else
            If $bBypassAutoItHdlr Then
                $iRet = _WinAPI_DefWindowProcW($hWnd, $uMsg, $wParam, $lParam)
            Else
                $aRes = DllCallAddress("long", $pOrigGuiProc, "hwnd", $hWnd, "uint", $uMsg, "wparam", $wParam, "lparam", $lParam)
                $iRet = $aRes[0]
            EndIf

    EndSwitch

    Return $iRet
EndFunc

 

 

Edited by MattyD
Posted (edited)

Great investigations.  Seems we can force the position of the button inside $WM_WINDOWPOSCHANGING message (by setting X, Y, CX and CY).  I still haven't found the elegant way to set the right position at the right time, though.  Got to go for now...

Edit : this is what I got best so far...

#include <guiConstants.au3>
#include <winapi.au3>
#include <MenuConstants.au3>

Opt("MustDeclareVars", True)

Global $hGUI, $bRestore

Example()

Func Example()
  $hGUI = GUICreate("WM_NCHITTEST", 300, 200, -1, -1, $WS_OVERLAPPEDWINDOW)
  Local $idBtn = GUICtrlCreateButton("Button 1", 4, 4, 80, 80, $WS_CLIPSIBLINGS)
  Local $idBtn2 = GUICtrlCreateButton("Button 2", 90, 4, 80, 80, $WS_CLIPSIBLINGS)
  Local $idLockButtons = GUICtrlCreateCheckbox("Lock Buttons", 200, 20, 80, 20)

  Local $hDll = DllCallbackRegister(ButtonMoveProc, 'lresult', 'hwnd;uint;wparam;lparam;uint_ptr;dword_ptr')
  _WinAPI_SetWindowSubclass(GUICtrlGetHandle($idBtn), DllCallbackGetPtr($hDll), $idBtn)
  _WinAPI_SetWindowSubclass(GUICtrlGetHandle($idBtn2), DllCallbackGetPtr($hDll), $idBtn2)

  GUIRegisterMsg($WM_SYSCOMMAND, WM_SYSCOMMAND)
  GUISetState()

  Local $iMsg

  While True
    $iMsg = GUIGetMsg()
    Switch $iMsg
      Case $GUI_EVENT_CLOSE
        ExitLoop
      Case $idLockButtons
        If GUICtrlRead($iMsg) = $GUI_CHECKED Then
          _WinAPI_RemoveWindowSubclass(GUICtrlGetHandle($idBtn), DllCallbackGetPtr($hDll), $idBtn)
          _WinAPI_RemoveWindowSubclass(GUICtrlGetHandle($idBtn2), DllCallbackGetPtr($hDll), $idBtn2)
        Else
          _WinAPI_SetWindowSubclass(GUICtrlGetHandle($idBtn), DllCallbackGetPtr($hDll), $idBtn, 0)
          _WinAPI_SetWindowSubclass(GUICtrlGetHandle($idBtn2), DllCallbackGetPtr($hDll), $idBtn2, 0)
        EndIf
      Case $idBtn, $idBtn2
        ConsoleWrite("Click " & GUICtrlRead($iMsg) & @CRLF)
      Case $GUI_EVENT_RESTORE
        $bRestore = False
    EndSwitch
  WEnd

  GUIDelete()
  _WinAPI_RemoveWindowSubclass(GUICtrlGetHandle($idBtn), DllCallbackGetPtr($hDll), $idBtn)
  _WinAPI_RemoveWindowSubclass(GUICtrlGetHandle($idBtn2), DllCallbackGetPtr($hDll), $idBtn2)
  DllCallbackFree($hDll)
EndFunc   ;==>Example

Func ButtonMoveProc($hWnd, $iMsg, $wParam, $lParam, $iID, $iData)
  Local $tPos, $aPos, $iRet, $aPoint[2], $iSrc, $iEvent, $hCursor

  Switch $iMsg
    Case $WM_NCHITTEST
      $aPos = WinGetPos($hWnd)
      $aPoint[0] = BitAND($lParam, 0xFFFF)
      $aPoint[1] = BitShift($lParam, 16)

      $iRet = $HTCAPTION
      If $aPoint[0] - $aPos[0] < 10 Then $iRet = $HTLEFT
      If $aPoint[0] - $aPos[0] > ($aPos[2] - 10) Then $iRet = $HTRIGHT

      If $aPoint[1] - $aPos[1] < 10 Then
        Switch $iRet
          Case $HTLEFT
            $iRet = $HTTOPLEFT
          Case $HTRIGHT
            $iRet = $HTTOPRIGHT
          Case Else
            $iRet = $HTTOP
        EndSwitch
      ElseIf $aPoint[1] - $aPos[1] > ($aPos[3] - 10) Then
        Switch $iRet
          Case $HTLEFT
            $iRet = $HTBOTTOMLEFT
          Case $HTRIGHT
            $iRet = $HTBOTTOMRIGHT
          Case Else
            $iRet = $HTBOTTOM
        EndSwitch
      EndIf
      Return $iRet

    Case $WM_SETCURSOR
      $iSrc = BitAND($lParam, 0xFFFF)
      $iEvent = BitShift($lParam, 16)
      If $iSrc = $HTCAPTION And $iEvent = $WM_LBUTTONDOWN Then
        _WinAPI_RedrawWindow($hWnd, 0, 0, $RDW_INVALIDATE + $RDW_FRAME)
        $hCursor = _WinAPI_LoadCursor(0, $OCR_SIZEALL)
        _WinAPI_SetCursor($hCursor)
        Return True
      EndIf

    Case $WM_WINDOWPOSCHANGING
      If $bRestore Then
        ConsoleWrite("WM_WINDOWPOSCHANGING" & @CRLF)
        $tPos = DllStructCreate($tagWINDOWPOS, $lParam)
        $aPos = ControlGetPos($hGUI, "", $hWnd)
        ConsoleWrite($aPos[0] & "/" & $aPos[1] & "/" & $aPos[2] & "/" & $aPos[3] & @CRLF)
        $tPos.X = $aPos[0]
        $tPos.Y = $aPos[1]
        $tPos.CX = $aPos[2]
        $tPos.CY = $aPos[3]
        Return 0
      EndIf

  EndSwitch
  Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>ButtonMoveProc

Func WM_SYSCOMMAND($hWnd, $uMsg, $wParam, $lParam)
  If $wParam = $SC_RESTORE Then
    ConsoleWrite("---Start Restore---" & @CRLF)
    $bRestore = True
  EndIf
  Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_SYSCOMMAND

 

Edited by Nine
Posted (edited)

Nice Nine, but I'll do you one better -

The trigger looks to be WM_SIZE, which makes sense. I'd say we've been fighting the mechanism behind control docking.

We can ignore it though by using GuiRegisterMsg and returning anything but $GUI_RUNDEFMSG.

Edit: or maybe its technically better to return _WinAPI_DefWindowProcW($hWnd, $uMsg, $wParam, $lParam)
I've also changed the Main GUI style so you can resize the window. If you don't register $WM_SIZE you can see autoit's "default" behavior is  that the button moves when you resize the window.

#AutoIt3Wrapper_UseX64=N

#include <guiConstants.au3>
#include <winapi.au3>

Opt("MustDeclareVars", 1)

Global $hGui = GUICreate("", 300, 200, 100, 100, BitOR($WS_SIZEBOX, $WS_MINIMIZEBOX))

Global $idBtn = GUICtrlCreateButton("Button 1", 4, 4, 80, 80)
Global $hBtn = GUICtrlGetHandle($idBtn)

Global $hBtnProc = DllCallbackRegister("btnProc", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr")
Global $pBtnProc = DllCallbackGetPtr($hBtnProc)
_WinAPI_SetWindowSubclass($hBtn, $pBtnProc, $idBtn)

GUIRegisterMsg($WM_SIZE, "WM_SIZE")
GUISetState()

Local $iMsg
While 1
    $iMsg = GUIGetMsg()
    switch $iMsg
        Case $GUI_EVENT_CLOSE
            Exit
    EndSwitch
WEnd

Func btnProc($hWnd, $uMsg, $wParam, $lParam, $uIdSubclasss, $dwRefData)
    local $iRet

    Switch $uMsg
        Case $WM_NCHITTEST
            $iRet = $HTCAPTION

        Case Else
            $iRet = _WinAPI_DefSubclassProc($hWnd, $uMsg, $wParam, $lParam)

    EndSwitch

    Return $iRet
EndFunc


Func WM_SIZE($hWnd, $uMsg, $wParam, $lParam)
    Return _WinAPI_DefWindowProcW($hWnd, $uMsg, $wParam, $lParam)
EndFunc#include <guiConstants.au3>
#include <winapi.au3>

Opt("MustDeclareVars", 1)

Global $hGui = GUICreate("", 300, 200, 100, 100, BitOR($WS_SIZEBOX, $WS_MINIMIZEBOX))

Global $idBtn = GUICtrlCreateButton("Button 1", 4, 4, 80, 80)
Global $hBtn = GUICtrlGetHandle($idBtn)

Global $hBtnProc = DllCallbackRegister("BtnProc", "long", "hwnd;uint;wparam;lparam")
Global $pBtnProc = DllCallbackGetPtr($hBtnProc)
_WinAPI_SetWindowSubclass($hBtn,$pBtnProc, $idBtn)

GUIRegisterMsg($WM_SIZE, "WM_SIZE")
GUISetState()

Local $iMsg
While 1
    $iMsg = GUIGetMsg()
    switch $iMsg
        Case $GUI_EVENT_CLOSE
            Exit
    EndSwitch
WEnd

Func btnProc($hWnd, $uMsg, $wParam, $lParam)
    local $iRet

    Switch $uMsg
        Case $WM_NCHITTEST
            $iRet = $HTCAPTION

        Case Else
            $iRet = _WinAPI_DefSubclassProc($hWnd, $uMsg, $wParam, $lParam)

    EndSwitch

    Return $iRet
EndFunc


Func WM_SIZE($hWnd, $uMsg, $wParam, $lParam)
    Return _WinAPI_DefWindowProcW($hWnd, $uMsg, $wParam, $lParam)
EndFunc

 

Edited by MattyD
Posted (edited)

Oops it was broken for Autoit x86 - I didn't register the callback correctly when I've moved from WindowSetLong to setwindowssubclass.

I've updated the example.

And here's one for @argumentum  if I've done things correctly :) Hold shift to move/resize the controls.

#include <guiConstants.au3>
#include <winapi.au3>
#include <misc.au3>

Opt("MustDeclareVars", 1)

Global $hGui = GUICreate("", 300, 200, 100, 100, BitOR($WS_SIZEBOX, $WS_MINIMIZEBOX))

Global $idBtn = GUICtrlCreateButton("Button 1", 4, 4, 80, 80)
Global $idBtn2 = GUICtrlCreateButton("Button 2", 90, 4, 80, 80)

Global $hCursor = _WinAPI_CopyCursor(_WinAPI_LoadCursor(0, $OCR_CROSS))
Global $hBtn = GUICtrlGetHandle($idBtn)
Global $hBtn2 = GUICtrlGetHandle($idBtn2)

Global $hBtnProc = DllCallbackRegister("btnProc", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr")
Global $pBtnProc = DllCallbackGetPtr($hBtnProc)
_WinAPI_SetWindowSubclass($hBtn, $pBtnProc, $idBtn)
_WinAPI_SetWindowSubclass($hBtn2, $pBtnProc, $idBtn2)

GUIRegisterMsg($WM_SIZE, "WM_SIZE")
GUISetState()

Local $iMsg
While 1
    $iMsg = GUIGetMsg()
    Switch $iMsg
        Case $GUI_EVENT_CLOSE
            Exit

        Case $idBtn, $idBtn2
            ConsoleWrite(GUICtrlRead($iMsg) & @CRLF)

    EndSwitch
WEnd

Func btnProc($hWnd, $uMsg, $wParam, $lParam, $uIdSubclasss, $dwRefData)
    Local $iRet

    Switch $uMsg
        Case $WM_NCHITTEST

            Local $aPoint[2] = [BitAND($lParam, 0xFFFF),  BitShift($lParam, 16)]
            ;Mouse coords can be negative on edge cases!
            If BitAND($aPoint[0], 0x8000) Then $aPoint[0] = BitOR(0xFFFF0000, $aPoint[0])
            If BitAND($aPoint[1], 0x8000) Then $aPoint[1] = BitOR(0xFFFF0000, $aPoint[1])

            Local $aPos = WinGetPos($hWnd), $iMar = 10

            If Not _IsPressed("10") Then
                $iRet = _WinAPI_DefSubclassProc($hWnd, $uMsg, $wParam, $lParam)
            Else
                $iRet = $HTCAPTION
                If $aPoint[0] - $aPos[0] < $iMar Then $iRet = $HTLEFT
                If $aPoint[0] - $aPos[0] > ($aPos[2] - $iMar) Then $iRet = $HTRIGHT

                If $aPoint[1] - $aPos[1] < $iMar Then
                    Switch $iRet
                        Case $HTLEFT
                            $iRet = $HTTOPLEFT
                        Case $HTRIGHT
                            $iRet = $HTTOPRIGHT
                        Case Else
                            $iRet = $HTTOP
                    EndSwitch

                ElseIf $aPoint[1] - $aPos[1] > ($aPos[3] - $iMar) Then
                    Switch $iRet
                        Case $HTLEFT
                            $iRet = $HTBOTTOMLEFT
                        Case $HTRIGHT
                            $iRet = $HTBOTTOMRIGHT
                        Case Else
                            $iRet = $HTBOTTOM
                    EndSwitch
                EndIf

                If $aPoint[0] < 0 Then $iRet = _WinAPI_DefSubclassProc($hWnd, $uMsg, $wParam, $lParam)
                If $aPoint[1] < 0 Then $iRet = _WinAPI_DefSubclassProc($hWnd, $uMsg, $wParam, $lParam)
                _WinAPI_RedrawWindow($hWnd)
            EndIf

        Case $WM_SETCURSOR
            Local $iSrc = BitAND($lParam, 0xFFFF), $iEvent = BitShift($lParam, 16)
            If $iSrc = $HTCAPTION And $iEvent = $WM_LBUTTONDOWN Then
                _WinAPI_SetCursor($hCursor)
                $iRet = 1
            Else
                $iRet = _WinAPI_DefSubclassProc($hWnd, $uMsg, $wParam, $lParam)
            EndIf

        Case Else
            $iRet = _WinAPI_DefSubclassProc($hWnd, $uMsg, $wParam, $lParam)

    EndSwitch

    Return $iRet
EndFunc   ;==>btnProc


Func WM_SIZE($hWnd, $uMsg, $wParam, $lParam)
    Return _WinAPI_DefWindowProcW($hWnd, $uMsg, $wParam, $lParam)
EndFunc   ;==>WM_SIZE

 

Edited by MattyD
  • 5 months later...
Posted

hi guys.
I want to code a program, that is like a gantt chart with a time line.
There for I want to use a resizable button as the timeline, where the user can drag and resize it.

Can you show how to lock vertical resizing? allow the vertical resizing of the button only.
Also allow the horizontal movement of the button only, block vertically...

Hope you can help me. Thanks

Posted (edited)

@atvaxn  I would go some other way.  Try this :

#include <guiConstants.au3>
#include <Misc.au3>
#include <WinAPIShellEx.au3>
#include <WinAPIRes.au3>
#include <WinAPISysWin.au3>

Opt("MustDeclareVars", True)
Opt("MouseCoordMode", 2)

Example()

Func Example()
  Local $hGUI = GUICreate("Gantt Chart", 300, 200, -1, -1, -1, $WS_EX_COMPOSITED)
  Local $idBar1 = GUICtrlCreateLabel("", 5, 50, 80, 20)
  GUICtrlSetBkColor(-1, 0xf00000)
  Local $idBar2 = GUICtrlCreateLabel("", 25, 80, 80, 20)
  GUICtrlSetBkColor(-1, 0xf0)

  Local $hDll = DllCallbackRegister(MoveProc, 'lresult', 'hwnd;uint;wparam;lparam;uint_ptr;dword_ptr')
  _WinAPI_SetWindowSubclass(GUICtrlGetHandle($idBar1), DllCallbackGetPtr($hDll), $idBar1)
  _WinAPI_SetWindowSubclass(GUICtrlGetHandle($idBar2), DllCallbackGetPtr($hDll), $idBar2)

  GUISetState()

  While True
    Switch GUIGetMsg()
      Case $GUI_EVENT_CLOSE
        ExitLoop
    EndSwitch
  WEnd

  _WinAPI_RemoveWindowSubclass(GUICtrlGetHandle($idBar1), DllCallbackGetPtr($hDll), $idBar1)
  _WinAPI_RemoveWindowSubclass(GUICtrlGetHandle($idBar2), DllCallbackGetPtr($hDll), $idBar2)
  DllCallbackFree($hDll)
EndFunc   ;==>Example

Func MoveProc($hWnd, $iMsg, $wParam, $lParam, $iID, $iData)
  If $iMsg <> $WM_LBUTTONDOWN Then Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam)
  Local $aPosID = ControlGetPos(_WinAPI_GetParent($hWnd), "", $hWnd)
  Local $iPosX = MouseGetPos(0), $iPosXN, $hCursor
  Select
    Case $iPosX - $aPosID[0] <= 3   ; left
      $hCursor = _WinAPI_LoadCursor(0, $OCR_SIZEWE)
      While _IsPressed("01")
        _WinAPI_SetCursor($hCursor)
        If $iPosX <> MouseGetPos(0) Then
          $iPosXN = MouseGetPos(0)
          GUICtrlSetPos($iID, $aPosID[0] + ($iPosXN - $iPosX), $aPosID[1], $aPosID[2] + $iPosX - $iPosXN)
          $iPosX = $iPosXN
          $aPosID = ControlGetPos(_WinAPI_GetParent($hWnd), "", $hWnd)
        EndIf
      WEnd

    Case $aPosID[0] + $aPosID[2] - $iPosX <= 3    ; right
      $hCursor = _WinAPI_LoadCursor(0, $OCR_SIZEWE)
      While _IsPressed("01")
        _WinAPI_SetCursor($hCursor)
        If $iPosX <> MouseGetPos(0) Then
          $iPosXN = MouseGetPos(0)
          GUICtrlSetPos($iID, $aPosID[0], $aPosID[1], $aPosID[2] + $iPosXN - $iPosX)
          $iPosX = $iPosXN
          $aPosID = ControlGetPos(_WinAPI_GetParent($hWnd), "", $hWnd)
        EndIf
      WEnd

    Case Else   ; center
      $hCursor = _WinAPI_LoadCursor(0, $OCR_HAND)
      While _IsPressed("01")
        _WinAPI_SetCursor($hCursor)
        If $iPosX <> MouseGetPos(0) Then
          $iPosXN = MouseGetPos(0)
          GUICtrlSetPos($iID, $aPosID[0] + $iPosXN - $iPosX)
          $iPosX = $iPosXN
          $aPosID = ControlGetPos(_WinAPI_GetParent($hWnd), "", $hWnd)
        EndIf
      WEnd
  EndSelect
  Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>MoveProc

 

Edited by Nine

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...