Jump to content

transparent movable windows with drop shadow


Go to solution Solved by Nine,

Recommended Posts

Posted (edited)

@Nine if you had to add a Button with its image, would this way be recommended or do you have something else in mind ?

I'm posting below the reworked Example function from your script . Image "Ok 52-51.bmp" downloadable below the code

Func Example()

    _GDIPlus_Startup()

    $hGUI = GUICreateEx("main.png", 100, 100)
    $hGUI2 = GUICreateEx("item.png", 150, 400, $hGUI)
    $hGUI3 = GUICreateEx("item.png", 400, 400, $hGUI)

    Local $hGUI4 = GUICreate("", 52, 51, 100, 100, $WS_POPUP, $WS_EX_MDICHILD, $hGUI)
    Local $idButton_OK = GUICtrlCreateButton("", 0, 0, 52, 51, $BS_BITMAP)
    GUICtrlSetImage($idButton_OK, @ScriptDir & "\Ok 52-51.bmp")
    GUISetState()

    GUIRegisterMsg($WM_NCHITTEST, WM_NCHITTEST)
    GUIRegisterMsg($WM_MOUSELEAVE, WM_MOUSELEAVE)

    While True
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop
            Case $idButton_OK
                ConsoleWrite("Button OK pressed" & @crlf)
        EndSwitch
    WEnd

    _GDIPlus_Shutdown()
EndFunc   ;==>Example

Ok 52-51.bmp

Cancel 52-51.bmp

Edited by pixelsearch
Posted

@nine i created gui using your help, just make item creation dynamically, but i face another problem, i cant use scrollbar!

 i want to use _GUIScrollbars_Generate from GUIScrollbars_Ex udf but there are many Gui created!

For $i=0 to UBound($item)
    $aGui[$i] = GUICreateEx("item.png", 150*$i, 400, $hGUI)
    
Next
    
_GUIScrollbars_Generate($hGUI, 1000, 1000)

 

Posted
5 hours ago, rot3r said:

an you please recommend a method to change the picture on hover?

I'd do it using GUIGetCursorInfo() . Here  is a reworked function Example() from Nine's script. Both images (Ok 52-51.bmp & Cancel 52-51.bmp) downloadable at the end of... my preceding post :D

Func Example()

    _GDIPlus_Startup()

    $hGUI = GUICreateEx("main.png", 100, 100)
    $hGUI2 = GUICreateEx("item.png", 150, 400, $hGUI)
    $hGUI3 = GUICreateEx("item.png", 400, 400, $hGUI)

    Local $hGUI4 = GUICreate("", 52, 51, 100, 100, $WS_POPUP, $WS_EX_MDICHILD, $hGUI)
    Local $idButton = GUICtrlCreateButton("", 0, 0, 52, 51, $BS_BITMAP)
    GUICtrlSetImage($idButton, @ScriptDir & "\Ok 52-51.bmp")
    GUISetState()

    GUIRegisterMsg($WM_NCHITTEST, WM_NCHITTEST)
    GUIRegisterMsg($WM_MOUSELEAVE, WM_MOUSELEAVE)

    Local $aInfo, $iCounter, $hTimer = TimerInit()

    While True
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop
            Case $idButton
                ConsoleWrite("Button OK pressed" & @crlf)
        EndSwitch

        $aInfo = GUIGetCursorInfo($hGUI4)
        If Not @error And $aInfo[4] = $idButton Then
            If TimerDiff($hTimer) > 1000 Then ; 1s
                $iCounter += 1
                GUICtrlSetImage( $idButton, @ScriptDir & (Mod($iCounter, 2) ? "\Cancel 52-51.bmp" : "\Ok 52-51.bmp") )
                $hTimer = TimerInit()
            EndIf
        EndIf
    WEnd

    _GDIPlus_Shutdown()
EndFunc   ;==>Example

The added part (changing the picture) could (should ?) probably be done in a function and not in Main loop, especially you'll add your own code to all this. Well... now it seems you got everything you need.

Good luck

 

Posted

Another way to toggle the button (similar with secondary GUIs) :

Global $pOldBtnProc
...
  Local $hGUI4 = GUICreate("", 52, 51, 300, 300, $WS_POPUP, $WS_EX_MDICHILD, $hGUI)
  Local $idBtn = GUICtrlCreateButton("Test", 0, 0, 52, 51, $BS_BITMAP)
  GUICtrlSetImage($idBtn, "Cancel 52-51.bmp")
  Local $hBtnProc = DllCallbackRegister(WinBtnProc, "long", "hwnd;uint;wparam;lparam")
  $pOldBtnProc = _WinAPI_SetWindowLong(GUICtrlGetHandle($idBtn), $GWL_WNDPROC, DllCallbackGetPtr($hBtnProc))
...
Func WinBtnProc($hWnd, $iMsg, $wParam, $lParam)
  Local Static $bHover = False
  Switch $iMsg
    Case $WM_MOUSEMOVE
      If Not $bHover Then
        GUICtrlSetImage(_WinAPI_GetDlgCtrlID($hWnd), "OK 52-51.bmp")
        $bHover = True
      EndIf
    Case $WM_MOUSELEAVE
      GUICtrlSetImage(_WinAPI_GetDlgCtrlID($hWnd), "Cancel 52-51.bmp")
      $bHover = False
  EndSwitch
  Return DllCallAddress("long", $pOldBtnProc, "hwnd", $hWnd, "uint", $iMsg, "wparam", $wParam, "lparam", $lParam)[0]
EndFunc   ;==>WinBtnProc

 

Posted (edited)

@Nine do you have any idea why the script below outputs :
1) Correct results when registering WM_MOUSEMOVE and calling _WinAPI_TrackMouseEvent from there.
2) Wrong results when registering WM_NCHITTEST instead, then calling _WinAPI_TrackMouseEvent from there.

#include <WinAPISys.au3>
#include <GDIPlus.au3>
#include <GuiConstants.au3>

Opt("MustDeclareVars", True)

Global $hGUI, $hGUI2, $hGUI3
Example()

;==============================================
Func Example()

    _GDIPlus_Startup()

    $hGUI = GUICreateEx("main.png", 100, 100)
    $hGUI2 = GUICreateEx("item.png", 150, 400, $hGUI)
    $hGUI3 = GUICreateEx("item.png", 400, 400, $hGUI)

    GUIRegisterMsg($WM_MOUSEMOVE, WM_MOUSEMOVE) ; correct results for _WinAPI_TrackMouseEvent
    ; GUIRegisterMsg($WM_NCHITTEST, WM_NCHITTEST) ; wrong results for _WinAPI_TrackMouseEvent

    GUIRegisterMsg($WM_MOUSEHOVER, WM_MOUSEHOVER)
    GUIRegisterMsg($WM_MOUSELEAVE, WM_MOUSELEAVE)

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

    _GDIPlus_Shutdown()
EndFunc   ;==>Example

;==============================================
Func GUICreateEx($sImage, $iPosX = -1, $iPosY = -1, $hParent = 0)

    Local $hWnd = GUICreate("", -1, -1, $iPosX, $iPosY, $WS_POPUP, BitOR($WS_EX_LAYERED, $hParent ? $WS_EX_MDICHILD : 0), $hParent)
    GUIUpdate($hWnd, $sImage)
    GUISetState()
    Return $hWnd
EndFunc   ;==>GUICreateEx

;==============================================
Func GUIUpdate($hWnd, $sImage)

    Local $hImage = _GDIPlus_ImageLoadFromFile($sImage)
    Local $hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
    _WinAPI_UpdateLayeredWindowEx($hWnd, -1, -1, $hBitmap)
    _WinAPI_DeleteObject($hBitmap)
    _GDIPlus_ImageDispose($hImage)
EndFunc   ;==>GUIUpdate

;==============================================
Func WM_MOUSEMOVE($hWnd, $iMsg, $wParam, $lParam)

    _WinAPI_TrackMouseEvent($hWnd, $TME_HOVER + $TME_LEAVE, 10) ; 10ms
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_MOUSEMOVE

;==============================================
Func WM_NCHITTEST($hWnd, $iMsg, $wParam, $lParam)

    _WinAPI_TrackMouseEvent($hWnd, $TME_HOVER + $TME_LEAVE, 10) ; 10ms
    Return $GUI_RUNDEFMSG
    ; No Return keyword should be equivalent to Return 0 ($HTNOWHERE)
EndFunc   ;==>WM_NCHITTEST

;==============================================
Func WM_MOUSEHOVER($hWnd, $msg, $wParam, $lParam)

    Local Static $iWhichOne_Old
    Local $iWhichOne = ($hWnd = $hGUI) ? 1 : (($hWnd = $hGUI2) ? 2 : 3)

    If $iWhichOne <> $iWhichOne_Old Then
        ConsoleWrite("hovering " & $iWhichOne & @crlf)
        $iWhichOne_Old = $iWhichOne
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_MOUSEHOVER

;==============================================
Func WM_MOUSELEAVE($hWnd, $msg, $wParam, $lParam)

    Local Static $iWhichOne_Old
    Local $iWhichOne = ($hWnd = $hGUI) ? 1 : (($hWnd = $hGUI2) ? 2 : 3)

    If $iWhichOne <> $iWhichOne_Old Then
        ConsoleWrite("leaving " & $iWhichOne & @crlf)
        $iWhichOne_Old = $iWhichOne
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_MOUSELEAVE

Correct output when registering WM_MOUSEMOVE, after we hover over the main GUI, then GUI2, then main GUI (to reach GUI3) then GUI3 and back to main GUI, exiting the script (Esc) while the mouse is still hovering over the main GUI (which explains why there is no last "leaving 1")

hovering 1
leaving 1
hovering 2
leaving 2
hovering 1
leaving 1
hovering 3
leaving 3
hovering 1

Wrong output when registering WM_NCHITTEST instead, after we hover over them in the same way,

hovering 1
leaving 2   <== why ? we were slowly approaching GUI2 when this surprising message appeared
leaving 1
hovering 2
leaving 2
hovering 1
leaving 3   <== why ? we were slowly approaching GUI3 when this surprising message appeared
leaving 1
hovering 3
leaving 3
hovering 1

Thanks

Edited by pixelsearch
Posted (edited)

Thanks, it's a possible explanation, especially when I look at a test done this morning. With these 2 lines replaced in the script :

; ConsoleWrite("hovering " & $iWhichOne & @crlf)
ConsoleWrite("hovering " & $iWhichOne & "   X-MouseGetPos() = " & MouseGetPos()[0] & @crlf)

; ConsoleWrite("leaving " & $iWhichOne & @crlf)
ConsoleWrite("leaving " & $iWhichOne & "   X-MouseGetPos() = " & MouseGetPos()[0] & @crlf)

Console :

$WM_MOUSEMOVE, moving mouse horizontally VERY slowly from left to right through 3 GUI's, starting at (0,600)
hovering 1   X-MouseGetPos() = 104
leaving 1   X-MouseGetPos() = 250
hovering 2   X-MouseGetPos() = 250
leaving 2   X-MouseGetPos() = 414
hovering 1   X-MouseGetPos() = 414
leaving 1   X-MouseGetPos() = 500
hovering 3   X-MouseGetPos() = 500
leaving 3   X-MouseGetPos() = 664
hovering 1   X-MouseGetPos() = 664


WM_NCHITTEST, moving mouse horizontally etc...
leaving 1   X-MouseGetPos() = 104  ; why ? forgot that one in prec. post as mouse was already inside GUI
hovering 1   X-MouseGetPos() = 105
leaving 2   X-MouseGetPos() = 250  ; why ?
leaving 1   X-MouseGetPos() = 250
hovering 2   X-MouseGetPos() = 251
leaving 2   X-MouseGetPos() = 414
hovering 1   X-MouseGetPos() = 415
leaving 3   X-MouseGetPos() = 500  ; why ?
leaving 1   X-MouseGetPos() = 500
hovering 3   X-MouseGetPos() = 501
leaving 3   X-MouseGetPos() = 664
hovering 1   X-MouseGetPos() = 665

For what it's worth...

Edited by pixelsearch
removed unfinished new test
Posted

Thanks for testing.  One thing I dislike about MOUSEHOVER is that you need to stay put for a small amount of time (e.g. 10ms in your example).  When you move fast, it lacks responsiveness in my perspective.  Putting it in MOUSEMOVE or (NCHITTEST), you get faster response from the GUI.  No big deal though. 

Posted (edited)

"leaving" is a confusing word in all our preceding scripts, imho it should be read "leave" or "left" .  msdn link :

TME_LEAVE [...] If the mouse is not over the specified window or area, a leave notification is generated immediately [...]

On the other side "hovering" is a correct word. This script will output plenty of "left" lines ... and a few "hovering" ones too :D

#include <WinAPISys.au3>
#include <GDIPlus.au3>
#include <GuiConstants.au3>

Opt("MustDeclareVars", True)

Global $hGUI, $hGUI2, $hGUI3
Example()

;==============================================
Func Example()

    _GDIPlus_Startup()

    $hGUI = GUICreateEx("main.png", 100, 100)
    $hGUI2 = GUICreateEx("item.png", 150, 400, $hGUI)
    $hGUI3 = GUICreateEx("item.png", 400, 400, $hGUI)

    GUIRegisterMsg($WM_MOUSEHOVER, WM_MOUSEHOVER)
    GUIRegisterMsg($WM_MOUSELEAVE, WM_MOUSELEAVE)

    While True
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop

            Case $GUI_EVENT_MOUSEMOVE
                _WinAPI_TrackMouseEvent($hGUI, $TME_HOVER + $TME_LEAVE, 10) ; 10ms
                _WinAPI_TrackMouseEvent($hGUI2, $TME_HOVER + $TME_LEAVE, 10) ; 10ms
                _WinAPI_TrackMouseEvent($hGUI3, $TME_HOVER + $TME_LEAVE, 10) ; 10ms
        EndSwitch
    WEnd

    _GDIPlus_Shutdown()
EndFunc   ;==>Example

;==============================================
Func GUICreateEx($sImage, $iPosX = -1, $iPosY = -1, $hParent = 0)

    Local $hWnd = GUICreate("", -1, -1, $iPosX, $iPosY, $WS_POPUP, BitOR($WS_EX_LAYERED, $hParent ? $WS_EX_MDICHILD : 0), $hParent)
    GUIUpdate($hWnd, $sImage)
    GUISetState()
    Return $hWnd
EndFunc   ;==>GUICreateEx

;==============================================
Func GUIUpdate($hWnd, $sImage)

    Local $hImage = _GDIPlus_ImageLoadFromFile($sImage)
    Local $hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
    _WinAPI_UpdateLayeredWindowEx($hWnd, -1, -1, $hBitmap)
    _WinAPI_DeleteObject($hBitmap)
    _GDIPlus_ImageDispose($hImage)
EndFunc   ;==>GUIUpdate

;==============================================
Func WM_MOUSEHOVER($hWnd, $msg, $wParam, $lParam)

    Local $iWhichOne = ($hWnd = $hGUI) ? 1 : (($hWnd = $hGUI2) ? 2 : 3)
    ConsoleWrite("hovering " & $iWhichOne & "   X-MouseGetPos() = " & MouseGetPos()[0] & @crlf)
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_MOUSEHOVER

;==============================================
Func WM_MOUSELEAVE($hWnd, $msg, $wParam, $lParam)

    Local $iWhichOne = ($hWnd = $hGUI) ? 1 : (($hWnd = $hGUI2) ? 2 : 3)
    ConsoleWrite("left " & $iWhichOne & "   X-MouseGetPos() = " & MouseGetPos()[0] & @crlf)
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_MOUSELEAVE

Console output, when the mouse hot spot is about to reach horizontal X coord 250 (the transition from GUI to GUI2, e.g. 1 to 2) then reaches it (250) , then moves to the right of it (e.g. hover over GUI2 at X coords 250, 251 , 252 , etc...)

...
left 2   X-MouseGetPos() = 248
left 3   X-MouseGetPos() = 248
hovering 1   X-MouseGetPos() = 248

left 2   X-MouseGetPos() = 249
left 3   X-MouseGetPos() = 249
hovering 1   X-MouseGetPos() = 249

left 1   X-MouseGetPos() = 250
left 3   X-MouseGetPos() = 250
hovering 2   X-MouseGetPos() = 250

left 1   X-MouseGetPos() = 251
left 3   X-MouseGetPos() = 251
hovering 2   X-MouseGetPos() = 251

left 1   X-MouseGetPos() = 252
left 3   X-MouseGetPos() = 252
hovering 2   X-MouseGetPos() = 252
...
Edited by pixelsearch
Posted (edited)
3 hours ago, Nine said:

When you move fast, it lacks responsiveness in my perspective

It may have something to do with the mouse interface, some gamers still use old PS/2 mice because PS/2 communicates directly with the cpu whereas USB mice has to go through the USB interface first, old PS/2 is more responsive.

/edit

....though that doesnt explain why one method in the script is faster than the other. 😛 

Edited by Werty

Some guy's script + some other guy's script = my script!

Posted (edited)
2 hours ago, Werty said:

with the mouse interface

Nah, you do not understand.  It is about how Windows treats some events.  It requires that you do not move (or whatever you are doing) for a certain amount of time.  Even if it is as small as 10ms.  It is quite big if you move your mouse rapidly.  

Edited by Nine
Posted (edited)

@Nine I have an issue when you use the following line, for example in this script from preceding page, where no error is triggered in case of non pre-declared variables (AutoIt 3.3.16.1)

Opt("MustDeclareVars", True)

What only works correctly for me is this :

Opt("MustDeclareVars", 1)

Could you confirm / deny it ?
Thanks

Edited by pixelsearch
typo
Posted (edited)
54 minutes ago, pixelsearch said:
Opt("MustDeclareVars", True)

AU3Check fails but AutoIt behaves the same.

nonetheless the manual say:
0 = (default) Variables don't need to be pre-declared
1 = Variables must be pre-declared. See Dim / Global / Local / Const for details on declaring variables.

..so the "True" setting should not be used. If AU3Check don't recognize it, me coding it, would not think that anyone would state True instead of 1.

Edited by argumentum

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Posted

I tried to adapt Nine's idea (found in his post) to subclass the imaged button, not using...

_WinAPI_SetWindowLong() and its $GWL_WNDPROC parameter...

...but using the 2nd way for subclassing, e.g. the 3 functions :

_WinAPI_SetWindowSubclass
_WinAPI_DefSubclassProc
_WinAPI_RemoveWindowSubclass

LarsJ wrote a lot about the 2 ways of subclassing in different threads. Also here is a msdn link which explains and compares these 2 ways.

In case you don't already have them, the 4 pics used in the script can be found elsewhere in this thread, here (2 pics) and there (2 pics)

#include <GDIPlus.au3>
#include <GuiConstants.au3>
#include <WinAPIShellEx.au3>
#include <WinAPISys.au3>

Opt("MustDeclareVars", 1)

OnAutoItExitRegister('OnAutoItExit')

Global $g_hDll, $g_pDll, $g_hBtn
Example()

;==============================================
Func Example()

    _GDIPlus_Startup()

    Local $hGUI = GUICreateEx("main.png", 100, 100)
    _WinAPI_SetWindowLong($hGUI, $GWL_EXSTYLE , BitOR(_WinAPI_GetWindowLong($hGUI, $GWL_EXSTYLE), $WS_EX_CONTROLPARENT))

    Local $hGUI2 = GUICreateEx("item.png", 150, 400, $hGUI)
    Local $hGUI3 = GUICreateEx("item.png", 400, 400, $hGUI)

    Local $hGUI4 = GUICreate("", 52, 51, 100, 100, $WS_POPUP, $WS_EX_MDICHILD, $hGUI)
    Local $idBtn = GUICtrlCreateButton("", 0, 0, 52, 51, $BS_BITMAP)
    GUICtrlSetImage($idBtn, @ScriptDir & "\Cancel 52-51.bmp")
    $g_hBtn = GUICtrlGetHandle($idBtn)

    Global $g_hDll = DllCallbackRegister('_BtnProc', 'lresult', 'hwnd;uint;wparam;lparam;uint_ptr;dword_ptr')
    Global $g_pDll = DllCallbackGetPtr($g_hDll)

    _WinAPI_SetWindowSubclass($g_hBtn, $g_pDll, 1000, $idBtn) ; remember how the 4th param. is used in this script (+++)

    GUISetState(@SW_SHOW, $hGUI4)

    While True
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop
            Case $idBtn
                ConsoleWrite("Button pressed" & @crlf)
        EndSwitch
    WEnd

    _GDIPlus_Shutdown()
EndFunc   ;==>Example

;==============================================
Func _BtnProc($hWnd, $iMsg, $wParam, $lParam, $IdSubclass, $dwRefData)

    Local Static $bHover
    Switch $iMsg
        Case $WM_MOUSEMOVE
            If Not $bHover Then
                GUICtrlSetImage($dwRefData, @ScriptDir & "\OK 52-51.bmp")
                $bHover = True
            EndIf
        Case $WM_MOUSELEAVE
            GUICtrlSetImage($dwRefData, @ScriptDir & "\Cancel 52-51.bmp")
            $bHover = False
    EndSwitch
    Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>_BtnProc

;==============================================
Func OnAutoItExit()

    _WinAPI_RemoveWindowSubclass($g_hBtn, $g_pDll, 1000)
    DllCallbackFree($g_hDll)
EndFunc   ;==>OnAutoItExit

;==============================================
Func GUICreateEx($sImage, $iPosX = -1, $iPosY = -1, $hParent = 0)

    Local $hWnd = GUICreate("", -1, -1, $iPosX, $iPosY, $WS_POPUP, BitOR($WS_EX_LAYERED, $hParent ? $WS_EX_MDICHILD : 0), $hParent)
    GUIUpdate($hWnd, $sImage)
    GUISetState()
    Return $hWnd
EndFunc   ;==>GUICreateEx

;==============================================
Func GUIUpdate($hWnd, $sImage)

    Local $hImage = _GDIPlus_ImageLoadFromFile($sImage)
    Local $hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
    _WinAPI_UpdateLayeredWindowEx($hWnd, -1, -1, $hBitmap)
    _WinAPI_DeleteObject($hBitmap)
    _GDIPlus_ImageDispose($hImage)
EndFunc   ;==>GUIUpdate

Hope I scripted it correctly, fingers crossed :)
Please indicate if something needs to be modified, thanks !

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...