tatane Posted June 6, 2019 Posted June 6, 2019 Hi, I'm playing with GDIPlus drawing for few days and I can't find a way to optimize my script. In the code below, you'll see 50 frames created by GDIPlus functions. You can move them separately and when the drag is initiate, all the graphic is clear and every frames are redrawn. But it's sloooow. Could you help me ? Thanks for your time. P.S : You will need the attached .jpg expandcollapse popup#include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <WinAPISysWin.au3> #include <WinAPIGdi.au3> #include <WinAPI.au3> AutoItSetOption("MouseCoordMode", 2) ;Register callback $hKey_Proc = DllCallbackRegister("_Mouse_Proc", "int", "int;ptr;ptr") $hM_Module = DllCall("kernel32.dll", "hwnd", "GetModuleHandle", "ptr", 0) $hM_Hook = DllCall("user32.dll", "hwnd", "SetWindowsHookEx", "int", $WH_MOUSE_LL, "ptr", DllCallbackGetPtr($hKey_Proc), "hwnd", $hM_Module[0], "dword", 0) Global Const $MSLLHOOKSTRUCT = $tagPOINT & ";dword mouseData;dword flags;dword time;ulong_ptr dwExtraInfo" Global $currentEvent[2] Global $iLBUTTONDOWN = 0 Global $iRBUTTONDOWN = 0 Global $iMBUTTONDOWN = 0 Global $LRClickStatus = 0 Global $RLClickStatus = 0 Global $LRDrag = 0 Global $RLDrag = 0 Global $LMDrag = 0 Global $RMDrag = 0 Global $doubleClickTime = 400 Global $tPoint Local Const $width = Int(@DesktopWidth * 0.8), $height = Int(@DesktopHeight * 0.8) Global $max_width = 1900 Global $max_height = 1000 ; Initialize GDI+ _GDIPlus_Startup() Local $GUI_title = "GDI+" Global $hGUI = GUICreate($GUI_title, $width, $height, -1, -1, BitOR($GUI_SS_DEFAULT_GUI,$WS_THICKFRAME,$WS_TABSTOP)) $aggrandissement = GUICtrlCreateButton("+", 10, 10, 20) $diminution = GUICtrlCreateButton("-", 40, 10, 20) GUISetState() ; main graphic and buffer Global $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI) Global $hBitmap = _GDIPlus_BitmapCreateFromGraphics($max_width, $max_height, $hGraphics) Global $hBackbuffer = _GDIPlus_ImageGetGraphicsContext($hBitmap) _GDIPlus_GraphicsSetSmoothingMode($hBackbuffer, 2) Global $hBitmap_switch = _GDIPlus_BitmapCreateFromFile(@ScriptDir & "\OS6250-24M.jpg") Global $iHeight_switch = _GDIPlus_ImageGetHeight($hBitmap_switch) ; exclude controls from GDI+ graphic region Local $hRegion = _GDIPlus_RegionCreateFromRect(0, 0, $width, $height) $aRect = ControlGetPos("", "", $aggrandissement) _GDIPlus_RegionCombineRect($hRegion, $aRect[0], $aRect[1], $aRect[2], $aRect[3], 3) $aRect = ControlGetPos("", "", $diminution) _GDIPlus_RegionCombineRect($hRegion, $aRect[0], $aRect[1], $aRect[2], $aRect[3], 3) _GDIPlus_GraphicsSetClipRegion($hGraphics, $hRegion) _GDIPlus_RegionDispose($hRegion) ; Text format Global $hBrush = _GDIPlus_BrushCreateSolid(0xFF000000) Global $hFormat = _GDIPlus_StringFormatCreate() _GDIPlus_StringFormatSetAlign($hFormat, 1) Global $hFamily = _GDIPlus_FontFamilyCreate("Arial") Global $hFont = _GDIPlus_FontCreate($hFamily, 10, 2) ; for the frames drawing Global $hPen = _GDIPlus_PenCreate(0xFF000000, 2) Global $hBrush_cadre_titre = _GDIPlus_BrushCreateSolid(0x55FF0000) Global $frame_width = 200 Global $frame_height = 200 Global $shift_X, $shift_Y Global $move_inprogress = False Global $index_stack Global $iScale = 1 ; creating array Global $array[51][4] $array[0][0] = 50 Local $startx = 50 Local $starty = 50 Local $guipos = WinGetPos($hGUI) Local $intervalle_x = $guipos[2] / 10 ; width Local $intervalle_y = $guipos[3] / 7 ; height For $i = 1 To $array[0][0] ; auto positionning If Mod($i, 10) = 0 Then $x = $startx $y = $array[$i - 1][1] + $intervalle_y Else If $i - 1 = 0 Then ; premier passage $x = $startx $y = $starty Else $x = $array[$i - 1][0] + $intervalle_x $y = $array[$i - 1][1] EndIf EndIf $array[$i][0] = $x $array[$i][1] = $y $array[$i][2] = "Hello world " & $i $array[$i][3] = "Bye world " & $i Next _DrawStack() GUIRegisterMsg($WM_PAINT, "WM_PAINT") GUIRegisterMsg($WM_SIZE, "WM_SIZE") While 1 $msg = GUIGetMsg() Switch $msg Case $GUI_EVENT_CLOSE _Exit() Case $GUI_EVENT_MAXIMIZE $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI) Case $aggrandissement $iScale = $iScale + 0.2 _DrawStack($iScale) Case $diminution $iScale = $iScale - 0.2 _DrawStack($iScale) EndSwitch WEnd Func _DrawStack($scale = 1, $index_en_cours = -1, $new_x = 0, $new_y = 0) Local $x, $y, $titre, $info, $tmp_cadre_largeur, $tmp_cadre_hauteur, $hauteur_cadre_titre _GDIPlus_GraphicsClear($hBackbuffer, 0xFFF0F0F0) For $i = 1 To $array[0][0] $x = $array[$i][0] $y = $array[$i][1] $titre = $array[$i][2] $info = $array[$i][3] $tmp_cadre_largeur = Int($frame_width * $scale) $tmp_cadre_hauteur = Int($frame_height * $scale) $hauteur_cadre_titre = Int(16 * $scale) ; 15 pixels de haut If $index_en_cours = $i Then ; le stack en cours de déplacement suit les mouvements de la souris, les autres ne bougent pas $x = $new_x $y = $new_y EndIf $hFont = _GDIPlus_FontCreate($hFamily, Int(10 * $scale), 2) Local $tLayout_titre = _GDIPlus_RectFCreate($x, $y, $tmp_cadre_largeur, $hauteur_cadre_titre) _GDIPlus_GraphicsDrawStringEx($hBackbuffer, $titre, $hFont, $tLayout_titre, $hFormat, $hBrush) Local $tLayout_info = _GDIPlus_RectFCreate($x, $y + $hauteur_cadre_titre, $tmp_cadre_largeur, $hauteur_cadre_titre) _GDIPlus_GraphicsDrawStringEx($hBackbuffer, $info, $hFont, $tLayout_info, $hFormat, $hBrush) _GDIPlus_GraphicsDrawRect($hBackbuffer, $x, $y, $tmp_cadre_largeur, $tmp_cadre_hauteur, $hPen) ; cadre _GDIPlus_GraphicsFillRect($hBackbuffer, $x, $y, $tmp_cadre_largeur, $hauteur_cadre_titre, $hBrush_cadre_titre) ; titre _GDIPlus_GraphicsDrawRect($hBackbuffer, $x, $y + $hauteur_cadre_titre, $tmp_cadre_largeur, $hauteur_cadre_titre, $hPen) ; info _GDIPlus_GraphicsDrawImageRect($hBackbuffer, $hBitmap_switch, $x + 2, $y + Int(50 * $scale), $tmp_cadre_largeur - 4, Int(($iHeight_switch / 2) * $scale)) ; affichage de l'image du switch Next _GDIPlus_GraphicsDrawImage($hGraphics, $hBitmap, 0, 0);, $max_width, $max_height) ; copy from backbuffer to visible graphic EndFunc Func _Mouse_Proc($nCode, $wParam, $lParam) Local $info, $mouseData, $time, $timeDiff If $nCode < 0 Then $ret = DllCall("user32.dll", "long", "CallNextHookEx", "hwnd", $hM_Hook[0], _ "int", $nCode, "ptr", $wParam, "ptr", $lParam) Return $ret[0] EndIf $info = DllStructCreate($MSLLHOOKSTRUCT, $lParam) $mouseData = DllStructGetData($info, 3) $time = DllStructGetData($info, 5) $timeDiff = $time - $currentEvent[1] Select Case $wParam = $WM_MOUSEMOVE ;Test for Drag in here If $currentEvent[0] <> "LDrag" Or $currentEvent[0] <> "LRDrag" Or $currentEvent[0] <> "LMDrag" Then If $iLBUTTONDOWN = 1 Then $currentEvent[0] = "LDrag" If $move_inprogress Then $mouseX = MouseGetPos(0) $mouseY = MouseGetPos(1) _DrawStack($iScale, $index_stack, $mouseX - $shift_X, $mouseY - $shift_Y) $array[$index_stack][0] = $mouseX - $shift_X $array[$index_stack][1] = $mouseY - $shift_Y EndIf If $iRBUTTONDOWN = 1 Then $currentEvent[0] = "LRDrag" $LRDrag = 2 EndIf EndIf EndIf If $currentEvent[0] <> "RDrag" Or $currentEvent[0] <> "RMDrag" Or $currentEvent[0] <> "LRDrag" Then If $iRBUTTONDOWN = 1 Then $currentEvent[0] = "RDrag" EndIf EndIf If $currentEvent[0] <> "MDrag" Then If $iMBUTTONDOWN = 1 Then $currentEvent[0] = "MDrag" $currentEvent[1] = $time EndIf EndIf If $iRBUTTONDOWN = 1 And $iMBUTTONDOWN = 1 And $currentEvent[0] <> "RMDrag" Then $RMDrag = 2 $currentEvent[0] = "RMDrag" $currentEvent[1] = $time EndIf If $iLBUTTONDOWN = 1 And $iMBUTTONDOWN = 1 And $currentEvent[0] <> "LMDrag" Then $LMDrag = 2 $currentEvent[0] = "LMDrag" $currentEvent[1] = $time EndIf Case $wParam = $WM_MOUSEWHEEL If _WinAPI_HiWord($mouseData) > 0 Then ;Wheel Up $currentEvent[0] = "WheelUp" $currentEvent[1] = $time Else ;Wheel Down $currentEvent[0] = "WheelDown" $currentEvent[1] = $time EndIf Case $wParam = $WM_LBUTTONDOWN $mouseX = MouseGetPos(0) $mouseY = MouseGetPos(1) For $i = 1 To $array[0][0] If $mouseX > $array[$i][0] And $mouseX < $array[$i][0] + $frame_width * $iScale And _ $mouseY > $array[$i][1] And $mouseY < $array[$i][1] + $frame_height * $iScale Then $shift_X = $mouseX - $array[$i][0] $shift_Y = $mouseY - $array[$i][1] ; ... we can move $move_inprogress = True $index_stack = $i EndIf Next ; Register Button Down, check for Right/Left If $currentEvent[0] = "RClick" Then $LRClickStatus = 1 EndIf $iLBUTTONDOWN = 1 Case $wParam = $WM_LBUTTONUP ;Update $iLBUTTONDOWN $iLBUTTONDOWN = 0 ;Test for Right/Left Click If $RLClickStatus = 1 And ($timeDiff) < $doubleClickTime Then $currentEvent[0] = "RLClick" $currentEvent[1] = $time EndIf If $currentEvent[0] = "LClick" And ($timeDiff) < $doubleClickTime Then $currentEvent[0] = "LDClick" $currentEvent[1] = $time EndIf ;Test for Drops If $currentEvent[0] = "LDrag" Then $currentEvent[0] = "LDrop" $currentEvent[1] = $time ; si un déplacement était en cours, on indique que c'est terminé puisqu'on vient de relacher le bouton de la souris If $move_inprogress Then $move_inprogress = False EndIf EndIf If $LRDrag = 2 And $iRBUTTONDOWN = 1 Then $LRDrag = 1 ; Denote $LRDrag as still having one button clicked, need to register the drop on RButton up EndIf If $LRDrag = 1 And $iRBUTTONDOWN = 0 Then $currentEvent[0] = "LRDrop" $currentEvent[1] = $time $LRDrag = 0 EndIf If $LMDrag = 2 And $iMBUTTONDOWN = 1 Then $LMDrag = 1 ; Denote $LMDrag as still having one button clicked, need to register the drop on MButton up EndIf If $LMDrag = 1 And $iMBUTTONDOWN = 0 Then $currentEvent[0] = "LMDrop" $currentEvent[1] = $time $LMDrag = 0 EndIf ;Set LClick if other events haven't fired If $currentEvent[1] <> $time Then $currentEvent[0] = "LClick" $currentEvent[1] = $time EndIf ;Negate $LRClickStatus $RLClickStatus = 0 Case $wParam = $WM_RBUTTONDOWN ;Register Button Down If $currentEvent[0] = "LClick" Then $RLClickStatus = 1 EndIf $iRBUTTONDOWN = 1 Case $wParam = $WM_RBUTTONUP ;Test for Left, Right, and Right Doubleclick here ;Update $iRBUTTONDOWN $iRBUTTONDOWN = 0 ;Test for Right/Left Click If $LRClickStatus = 1 And ($timeDiff) < $doubleClickTime Then $currentEvent[0] = "LRClick" $currentEvent[1] = $time EndIf If $currentEvent[0] = "RClick" And ($timeDiff) < $doubleClickTime Then $currentEvent[0] = "RDClick" $currentEvent[1] = $time EndIf ;Test for Drops If $currentEvent[0] = "RDrag" Then $currentEvent[0] = "RDrop" $currentEvent[1] = $time EndIf If $LRDrag = 2 And $iLBUTTONDOWN = 1 Then $LRDrag = 1 ; Denote $LRDrag as still having one button clicked, need to register the drop on RButton up EndIf If $LRDrag = 1 And $iLBUTTONDOWN = 0 Then $currentEvent[0] = "LRDrop" $currentEvent[1] = $time $LRDrag = 0 EndIf If $RMDrag = 2 And $iMBUTTONDOWN = 1 Then $RMDrag = 1 ; Denote $LMDrag as still having one button clicked, need to register the drop on MButton up EndIf If $RMDrag = 1 And $iMBUTTONDOWN = 0 Then $currentEvent[0] = "RMDrop" $currentEvent[1] = $time $RMDrag = 0 EndIf ;Set LClick if other events haven't fired If $currentEvent[1] <> $time Then $currentEvent[0] = "RClick" $currentEvent[1] = $time EndIf ;Negate $LRClickStatus $LRClickStatus = 0 Case $wParam = $WM_MBUTTONDOWN ;Register Button Down $iMBUTTONDOWN = 1 Case $wParam = $WM_MBUTTONUP ;Test for Middle Double Click here ;Update $iRBUTTONDOWN $iMBUTTONDOWN = 0 ;Test for Right/Left Click If $currentEvent[0] = "MClick" And ($timeDiff) < $doubleClickTime Then $currentEvent[0] = "MDClick" $currentEvent[1] = $time EndIf ;Test for Drops If $currentEvent[0] = "MDrag" Then $currentEvent[0] = "MDrop" $currentEvent[1] = $time EndIf If $LMDrag = 2 And $iLBUTTONDOWN = 1 Then $LMDrag = 1 ; Denote $LRDrag as still having one button clicked, need to register the drop on RButton up EndIf If $LMDrag = 1 And $iLBUTTONDOWN = 0 Then $currentEvent[0] = "LMDrop" $currentEvent[1] = $time $LMDrag = 0 EndIf If $RMDrag = 2 And $iRBUTTONDOWN = 1 Then $RMDrag = 1 ; Denote $LMDrag as still having one button clicked, need to register the drop on MButton up EndIf If $RMDrag = 1 And $iRBUTTONDOWN = 0 Then $currentEvent[0] = "RMDrop" $currentEvent[1] = $time $RMDrag = 0 EndIf ;Set MClick if other events haven't fired If $currentEvent[1] <> $time Then $currentEvent[0] = "MClick" $currentEvent[1] = $time EndIf EndSelect ;~ If $currentEvent[0] <> "" Then ConsoleWrite("event:"&$currentEvent[0] & @CRLF) $ret = DllCall("user32.dll", "long", "CallNextHookEx", "hwnd", $hM_Hook[0], _ "int", $nCode, "ptr", $wParam, "ptr", $lParam) Return $ret[0] EndFunc ;==>_Mouse_Proc Func WM_PAINT($hwnd, $iMsg, $wParam, $lParam) If $hwnd = $hGUI Then _GDIPlus_GraphicsDrawImage($hGraphics, $hBitmap, 0, 0) _WinAPI_RedrawWindow($hwnd, 0, 0, $RDW_VALIDATE) EndIf Return 'GUI_RUNDEFMSG' EndFunc ;==>WM_PAINT Func WM_SIZE($hwnd, $iMsg, $wParam, $lParam) If $hwnd = $hGUI Then $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI) EndIf Return 'GUI_RUNDEFMSG' EndFunc Func _Exit() DllCall("user32.dll", "int", "UnhookWindowsHookEx", "hwnd", $hM_Hook[0]) $hM_Hook[0] = 0 DllCallbackFree($hKey_Proc) $hKey_Proc = 0 ; Clean up _GDIPlus_PenDispose($hPen) _GDIPlus_GraphicsDispose($hBackbuffer) _GDIPlus_BitmapDispose($hBitmap) _GDIPlus_BitmapDispose($hBitmap_switch) _GDIPlus_GraphicsDispose($hGraphics) _GDIPlus_FontDispose($hFont) _GDIPlus_FontFamilyDispose($hFamily) _GDIPlus_StringFormatDispose($hFormat) _GDIPlus_BrushDispose($hBrush) _GDIPlus_BrushDispose($hBrush_cadre_titre) ; Uninitialize GDI+ _GDIPlus_Shutdown() Exit EndFunc
Sidley Posted June 6, 2019 Posted June 6, 2019 I'm far from an expert on this, but it's probably the fact that you're constantly drawing 50 boxes of x number of elements to the screen every program cycle. I don't know if there's a way to update only a graphics object that has changed position since the last cycle. This would be my first area of investigation.
tatane Posted June 6, 2019 Author Posted June 6, 2019 (edited) Indeed, I confirm your thoughts. That's why i'm asking for help Edited June 6, 2019 by tatane
tatane Posted June 12, 2019 Author Posted June 12, 2019 (edited) Ok I finally found a trick to do what I need. Instead of redraw everything each cycle, I created a transparent gui on top of the main gui. And I drawn the frame I'm dragging on it. This cloned gui is destroy when the drag is finished. Took me some time to understand the basic mecanics of gdiplus... Here is the code (not perfect) : expandcollapse popup#include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <WinAPISysWin.au3> #include <WinAPIGdi.au3> #include <WinAPI.au3> AutoItSetOption("MouseCoordMode", 2) ;Register callback $hKey_Proc = DllCallbackRegister("_Mouse_Proc", "int", "int;ptr;ptr") $hM_Module = DllCall("kernel32.dll", "hwnd", "GetModuleHandle", "ptr", 0) $hM_Hook = DllCall("user32.dll", "hwnd", "SetWindowsHookEx", "int", $WH_MOUSE_LL, "ptr", DllCallbackGetPtr($hKey_Proc), "hwnd", $hM_Module[0], "dword", 0) Global Const $MSLLHOOKSTRUCT = $tagPOINT & ";dword mouseData;dword flags;dword time;ulong_ptr dwExtraInfo" Global $currentEvent[2] Global $iLBUTTONDOWN = 0 Global $iRBUTTONDOWN = 0 Global $iMBUTTONDOWN = 0 Global $LRClickStatus = 0 Global $RLClickStatus = 0 Global $LRDrag = 0 Global $RLDrag = 0 Global $LMDrag = 0 Global $RMDrag = 0 Global $doubleClickTime = 400 Global $tPoint Local Const $width = Int(@DesktopWidth * 0.8), $height = Int(@DesktopHeight * 0.8) Global $max_width = 1900 Global $max_height = 1000 ; Initialize GDI+ _GDIPlus_Startup() Global $gui_clone = -1 Global $hGraphics_clone, $hBitmap_clone, $hBackbuffer_clone, $hHBitmap_clone, $hBrush_clone ; pour la gui clone Global $hGUI = GUICreate("", $width, $height, -1, -1, BitOR($GUI_SS_DEFAULT_GUI,$WS_THICKFRAME,$WS_TABSTOP)) $aggrandissement = GUICtrlCreateButton("+", 10, 10, 20) $diminution = GUICtrlCreateButton("-", 40, 10, 20) GUISetState() ; main graphic and buffer Global $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI) Global $hBitmap = _GDIPlus_BitmapCreateFromGraphics($max_width, $max_height, $hGraphics) Global $hBackbuffer = _GDIPlus_ImageGetGraphicsContext($hBitmap) _GDIPlus_GraphicsSetSmoothingMode($hBackbuffer, 1) _GDIPlus_GraphicsSetInterpolationMode($hBackbuffer, 1) _GDIPlus_GraphicsSetCompositingQuality($hBackbuffer, 1) _GDIPlus_GraphicsSetPixelOffsetMode($hBackbuffer, 1) Global $hBitmap_switch = _GDIPlus_BitmapCreateFromFile(@ScriptDir & "\OS6250-24M.jpg") Global $iHeight_switch = _GDIPlus_ImageGetHeight($hBitmap_switch) ; exclude controls from GDI+ graphic region Local $hRegion = _GDIPlus_RegionCreateFromRect(0, 0, $width, $height) $aRect = ControlGetPos("", "", $aggrandissement) _GDIPlus_RegionCombineRect($hRegion, $aRect[0], $aRect[1], $aRect[2], $aRect[3], 3) $aRect = ControlGetPos("", "", $diminution) _GDIPlus_RegionCombineRect($hRegion, $aRect[0], $aRect[1], $aRect[2], $aRect[3], 3) _GDIPlus_GraphicsSetClipRegion($hGraphics, $hRegion) _GDIPlus_RegionDispose($hRegion) ; Text format Global $hBrush = _GDIPlus_BrushCreateSolid(0xFF000000) Global $hFormat = _GDIPlus_StringFormatCreate() _GDIPlus_StringFormatSetAlign($hFormat, 1) Global $hFamily = _GDIPlus_FontFamilyCreate("Arial") Global $hFont = _GDIPlus_FontCreate($hFamily, 10, 2) ; for the frames drawing Global $hPen = _GDIPlus_PenCreate(0xFF000000, 2) Global $hBrush_cadre_titre = _GDIPlus_BrushCreateSolid(0x55FF0000) Global $frame_width = 200 Global $frame_height = 200 Global $shift_X, $shift_Y Global $move_inprogress = False Global $index_stack Global $iScale = 1 ; creating array Global $array[51][4] $array[0][0] = 50 Local $startx = 50 Local $starty = 50 Local $guipos = WinGetPos($hGUI) Local $intervalle_x = $guipos[2] / 10 ; width Local $intervalle_y = $guipos[3] / 7 ; height For $i = 1 To $array[0][0] ; auto positionning If Mod($i, 10) = 0 Then $x = $startx $y = $array[$i - 1][1] + $intervalle_y Else If $i - 1 = 0 Then ; first pass $x = $startx $y = $starty Else $x = $array[$i - 1][0] + $intervalle_x $y = $array[$i - 1][1] EndIf EndIf $array[$i][0] = $x $array[$i][1] = $y $array[$i][2] = "Hello world " & $i $array[$i][3] = "Bye world " & $i Next Global $fps = 0, $fps_maintimer, $fps_timer, $fps_diff $fps_maintimer = TimerInit() _DrawStack() GUIRegisterMsg($WM_PAINT, "WM_PAINT") GUIRegisterMsg($WM_SIZE, "WM_SIZE") While 1 $msg = GUIGetMsg() Switch $msg Case $GUI_EVENT_CLOSE _Exit() Case $GUI_EVENT_MAXIMIZE $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI) $winpos = WinGetPos($hGUI) ; exclude controls from GDI+ graphic region Local $hRegion = _GDIPlus_RegionCreateFromRect(0, 0, $winpos[2], $winpos[3]) $aRect = ControlGetPos("", "", $aggrandissement) _GDIPlus_RegionCombineRect($hRegion, $aRect[0], $aRect[1], $aRect[2], $aRect[3], 3) $aRect = ControlGetPos("", "", $diminution) _GDIPlus_RegionCombineRect($hRegion, $aRect[0], $aRect[1], $aRect[2], $aRect[3], 3) _GDIPlus_GraphicsSetClipRegion($hGraphics, $hRegion) _GDIPlus_RegionDispose($hRegion) Case $aggrandissement $iScale = $iScale + 0.2 _DrawStack($iScale) Case $diminution $iScale = $iScale - 0.2 _DrawStack($iScale) EndSwitch WEnd Func _Create_CloneGUI($clone, $x_frame = -1, $y_frame = -1) Local $winpos = WinGetPos($hGUI) Local $width_border = _WinAPI_GetSystemMetrics($SM_CXSIZEFRAME) Local $height_menu = _WinAPI_GetSystemMetrics($SM_CYCAPTION) If $clone Then If $gui_clone = -1 Then $gui_clone = GUICreate("clone", $width, $height, $winpos[0] + $width_border, $winpos[1] + $height_menu + $width_border, $WS_POPUP, BitOR($WS_EX_LAYERED, $WS_EX_TOPMOST)) GUISetState() ; delete previous dragging frame drawing on the main gui $hBrush_clone = _GDIPlus_BrushCreateSolid(0xFFF0F0F0) _GDIPlus_GraphicsFillRect($hBackbuffer, $x_frame, $y_frame, $frame_width * $iScale, $frame_height * $iScale, $hBrush_clone) _GDIPlus_GraphicsDrawImage($hGraphics, $hBitmap, 0, 0) ; new graphic for the cloned gui (with buffer) $hGraphics_clone = _GDIPlus_GraphicsCreateFromHWND($gui_clone) $hBitmap_clone = _GDIPlus_BitmapCreateFromGraphics($winpos[2] - 2 * $width_border, $winpos[3] - $height_menu - 2 * $width_border, $hGraphics_clone) $hBackbuffer_clone = _GDIPlus_ImageGetGraphicsContext($hBitmap_clone) EndIf Else If $gui_clone <> -1 Then _GDIPlus_BrushDispose($hBrush_clone) _GDIPlus_BitmapDispose($hBitmap_clone) _GDIPlus_GraphicsDispose($hGraphics_clone) _GDIPlus_GraphicsDispose($hBackbuffer_clone) _WinAPI_DeleteObject($hHBitmap_clone) GUIDelete($gui_clone) $gui_clone = -1 EndIf EndIf EndFunc ; Draw all the frames Func _DrawStack($scale = 1, $index_en_cours = -1, $new_x = 0, $new_y = 0) Local $x, $y, $titre, $info, $tmp_cadre_largeur, $tmp_cadre_hauteur, $hauteur_cadre_titre $fps_timer = TimerInit() _GDIPlus_GraphicsClear($hBackbuffer, 0xFFF0F0F0) ; fps Local $tLayout_fps = _GDIPlus_RectFCreate(100, 10, 200, 20) _GDIPlus_GraphicsDrawStringEx($hBackbuffer, "FPS: " & StringFormat("%.2f", $fps), $hFont, $tLayout_fps, $hFormat, $hBrush) If $index_en_cours = -1 Then For $i = 1 To $array[0][0] $x = $array[$i][0] $y = $array[$i][1] $titre = $array[$i][2] $info = $array[$i][3] $tmp_cadre_largeur = Int($frame_width * $scale) $tmp_cadre_hauteur = Int($frame_height * $scale) $hauteur_cadre_titre = Int(16 * $scale) ; 15 pixels de haut $hFont = _GDIPlus_FontCreate($hFamily, Int(10 * $scale), 2) Local $tLayout_titre = _GDIPlus_RectFCreate($x, $y, $tmp_cadre_largeur, $hauteur_cadre_titre) _GDIPlus_GraphicsDrawStringEx($hBackbuffer, $titre, $hFont, $tLayout_titre, $hFormat, $hBrush) Local $tLayout_info = _GDIPlus_RectFCreate($x, $y + $hauteur_cadre_titre, $tmp_cadre_largeur, $hauteur_cadre_titre) _GDIPlus_GraphicsDrawStringEx($hBackbuffer, $info, $hFont, $tLayout_info, $hFormat, $hBrush) _GDIPlus_GraphicsDrawRect($hBackbuffer, $x, $y, $tmp_cadre_largeur, $tmp_cadre_hauteur, $hPen) ; cadre _GDIPlus_GraphicsFillRect($hBackbuffer, $x, $y, $tmp_cadre_largeur, $hauteur_cadre_titre, $hBrush_cadre_titre) ; titre _GDIPlus_GraphicsDrawRect($hBackbuffer, $x, $y + $hauteur_cadre_titre, $tmp_cadre_largeur, $hauteur_cadre_titre, $hPen) ; info _GDIPlus_GraphicsDrawImageRect($hBackbuffer, $hBitmap_switch, $x + 2, $y + Int(50 * $scale), $tmp_cadre_largeur - 4, Int(($iHeight_switch / 2) * $scale)) ; affichage de l'image du switch _GDIPlus_GraphicsDrawImageRect($hBackbuffer, $hBitmap_switch, $x + 2, $y + Int(($iHeight_switch / 2) * $scale) + Int(50 * $scale), $tmp_cadre_largeur - 4, Int(($iHeight_switch / 2) * $scale)) ; affichage de l'image du switch Next Else For $i = 1 To $array[0][0] $x = $array[$i][0] $y = $array[$i][1] $titre = $array[$i][2] $info = $array[$i][3] $tmp_cadre_largeur = Int($frame_width * $scale) $tmp_cadre_hauteur = Int($frame_height * $scale) $hauteur_cadre_titre = Int(16 * $scale) ; 15 pixels de haut If $index_en_cours = $i Then ; le stack en cours de déplacement suit les mouvements de la souris, les autres ne bougent pas $x = $new_x $y = $new_y $hFont = _GDIPlus_FontCreate($hFamily, Int(10 * $scale), 2) Local $tLayout_titre = _GDIPlus_RectFCreate($x, $y, $tmp_cadre_largeur, $hauteur_cadre_titre) _GDIPlus_GraphicsDrawStringEx($hBackbuffer, $titre, $hFont, $tLayout_titre, $hFormat, $hBrush) Local $tLayout_info = _GDIPlus_RectFCreate($x, $y + $hauteur_cadre_titre, $tmp_cadre_largeur, $hauteur_cadre_titre) _GDIPlus_GraphicsDrawStringEx($hBackbuffer, $info, $hFont, $tLayout_info, $hFormat, $hBrush) _GDIPlus_GraphicsDrawRect($hBackbuffer, $x, $y, $tmp_cadre_largeur, $tmp_cadre_hauteur, $hPen) ; cadre _GDIPlus_GraphicsFillRect($hBackbuffer, $x, $y, $tmp_cadre_largeur, $hauteur_cadre_titre, $hBrush_cadre_titre) ; titre _GDIPlus_GraphicsDrawRect($hBackbuffer, $x, $y + $hauteur_cadre_titre, $tmp_cadre_largeur, $hauteur_cadre_titre, $hPen) ; info _GDIPlus_GraphicsDrawImageRect($hBackbuffer, $hBitmap_switch, $x + 2, $y + Int(50 * $scale), $tmp_cadre_largeur - 4, Int(($iHeight_switch / 2) * $scale)) ; affichage de l'image du switch _GDIPlus_GraphicsDrawImageRect($hBackbuffer, $hBitmap_switch, $x + 2, $y + Int(($iHeight_switch / 2) * $scale) + Int(50 * $scale), $tmp_cadre_largeur - 4, Int(($iHeight_switch / 2) * $scale)) ; affichage de l'image du switch EndIf Next EndIf _GDIPlus_GraphicsDrawImage($hGraphics, $hBitmap, 0, 0);, $max_width, $max_height) ; copy from backbuffer to visible graphic ; FPS $fps_diff = TimerDiff($fps_timer) If TimerDiff($fps_maintimer) > 999 Then ;calculate FPS $fps = Round(1000 / $fps_diff, 2) $fps_maintimer = TimerInit() EndIf EndFunc ; Draw the dragging frame on the cloned transparent gui Func _DrawStack_GUIClone($scale = 1, $index_en_cours = -1, $new_x = 0, $new_y = 0) Local $x, $y, $titre, $info, $tmp_cadre_largeur, $tmp_cadre_hauteur, $hauteur_cadre_titre $x = $new_x $y = $new_y $titre = $array[$index_en_cours][2] $info = $array[$index_en_cours][3] $tmp_cadre_largeur = Int($frame_width * $scale) $tmp_cadre_hauteur = Int($frame_height * $scale) $hauteur_cadre_titre = Int(16 * $scale) ; 16 pixels de haut _GDIPlus_GraphicsClear($hBackbuffer_clone, 0x00000000) Local $hFont = _GDIPlus_FontCreate($hFamily, Int(10 * $scale), 2) Local $tLayout_titre = _GDIPlus_RectFCreate($x, $y, $tmp_cadre_largeur, $hauteur_cadre_titre) _GDIPlus_GraphicsDrawStringEx($hBackbuffer_clone, $titre, $hFont, $tLayout_titre, $hFormat, $hBrush) Local $tLayout_info = _GDIPlus_RectFCreate($x, $y + $hauteur_cadre_titre, $tmp_cadre_largeur, $hauteur_cadre_titre) _GDIPlus_GraphicsDrawStringEx($hBackbuffer_clone, $info, $hFont, $tLayout_info, $hFormat, $hBrush) _GDIPlus_GraphicsDrawRect($hBackbuffer_clone, $x, $y, $tmp_cadre_largeur, $tmp_cadre_hauteur, $hPen) ; cadre _GDIPlus_GraphicsFillRect($hBackbuffer_clone, $x, $y, $tmp_cadre_largeur, $hauteur_cadre_titre, $hBrush_cadre_titre) ; titre _GDIPlus_GraphicsDrawRect($hBackbuffer_clone, $x, $y + $hauteur_cadre_titre, $tmp_cadre_largeur, $hauteur_cadre_titre, $hPen) ; info _GDIPlus_GraphicsDrawImageRect($hBackbuffer_clone, $hBitmap_switch, $x + 2, $y + Int(50 * $scale), $tmp_cadre_largeur - 4, Int(($iHeight_switch / 2) * $scale)) ; affichage de l'image du switch _GDIPlus_GraphicsDrawImageRect($hBackbuffer_clone, $hBitmap_switch, $x + 2, $y + Int(($iHeight_switch / 2) * $scale) + Int(50 * $scale), $tmp_cadre_largeur - 4, Int(($iHeight_switch / 2) * $scale)) ; affichage de l'image du switch _GDIPlus_GraphicsDrawImage($hGraphics_clone, $hBitmap_clone, 0, 0) ; copy from backbuffer to visible graphic ; change the cloned gui to transparent ; should be placed here to be done each time your refresh the drawing (why ?) $hHBitmap_clone = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap_clone) _WinAPI_BitmapDisplayTransparentInGUI($hHBitmap_clone, $gui_clone) _WinAPI_DeleteObject($hHBitmap_clone) EndFunc Func _Mouse_Proc($nCode, $wParam, $lParam) Local $info, $mouseData, $time, $timeDiff If $nCode < 0 Then $ret = DllCall("user32.dll", "long", "CallNextHookEx", "hwnd", $hM_Hook[0], _ "int", $nCode, "ptr", $wParam, "ptr", $lParam) Return $ret[0] EndIf $info = DllStructCreate($MSLLHOOKSTRUCT, $lParam) $mouseData = DllStructGetData($info, 3) $time = DllStructGetData($info, 5) $timeDiff = $time - $currentEvent[1] Select Case $wParam = $WM_MOUSEMOVE ;Test for Drag in here If $currentEvent[0] <> "LDrag" Or $currentEvent[0] <> "LRDrag" Or $currentEvent[0] <> "LMDrag" Then If $iLBUTTONDOWN = 1 Then $currentEvent[0] = "LDrag" If $move_inprogress Then $mouseX = MouseGetPos(0) $mouseY = MouseGetPos(1) ; draw only one frame, the one dragging _DrawStack_GUIClone($iScale, $index_stack, $mouseX - $shift_X, $mouseY - $shift_Y) $array[$index_stack][0] = $mouseX - $shift_X $array[$index_stack][1] = $mouseY - $shift_Y EndIf If $iRBUTTONDOWN = 1 Then $currentEvent[0] = "LRDrag" $LRDrag = 2 EndIf EndIf EndIf If $currentEvent[0] <> "RDrag" Or $currentEvent[0] <> "RMDrag" Or $currentEvent[0] <> "LRDrag" Then If $iRBUTTONDOWN = 1 Then $currentEvent[0] = "RDrag" EndIf EndIf If $currentEvent[0] <> "MDrag" Then If $iMBUTTONDOWN = 1 Then $currentEvent[0] = "MDrag" $currentEvent[1] = $time EndIf EndIf If $iRBUTTONDOWN = 1 And $iMBUTTONDOWN = 1 And $currentEvent[0] <> "RMDrag" Then $RMDrag = 2 $currentEvent[0] = "RMDrag" $currentEvent[1] = $time EndIf If $iLBUTTONDOWN = 1 And $iMBUTTONDOWN = 1 And $currentEvent[0] <> "LMDrag" Then $LMDrag = 2 $currentEvent[0] = "LMDrag" $currentEvent[1] = $time EndIf Case $wParam = $WM_MOUSEWHEEL If _WinAPI_HiWord($mouseData) > 0 Then ;Wheel Up $currentEvent[0] = "WheelUp" $currentEvent[1] = $time Else ;Wheel Down $currentEvent[0] = "WheelDown" $currentEvent[1] = $time EndIf Case $wParam = $WM_LBUTTONDOWN $mouseX = MouseGetPos(0) $mouseY = MouseGetPos(1) For $i = 1 To $array[0][0] If $mouseX > $array[$i][0] And $mouseX < $array[$i][0] + $frame_width * $iScale And _ $mouseY > $array[$i][1] And $mouseY < $array[$i][1] + $frame_height * $iScale Then $shift_X = $mouseX - $array[$i][0] $shift_Y = $mouseY - $array[$i][1] ; create cloned gui on top of main gui _Create_CloneGUI(True, $mouseX - $shift_X, $mouseY - $shift_Y) ; ... we can move $move_inprogress = True $index_stack = $i EndIf Next ; Register Button Down, check for Right/Left If $currentEvent[0] = "RClick" Then $LRClickStatus = 1 EndIf $iLBUTTONDOWN = 1 Case $wParam = $WM_LBUTTONUP ;Update $iLBUTTONDOWN $iLBUTTONDOWN = 0 ;Test for Right/Left Click If $RLClickStatus = 1 And ($timeDiff) < $doubleClickTime Then $currentEvent[0] = "RLClick" $currentEvent[1] = $time EndIf If $currentEvent[0] = "LClick" And ($timeDiff) < $doubleClickTime Then $currentEvent[0] = "LDClick" $currentEvent[1] = $time EndIf ;Test for Drops If $currentEvent[0] = "LDrag" Then $currentEvent[0] = "LDrop" $currentEvent[1] = $time ; If movement in progress, then it's finished, left click released If $move_inprogress Then $move_inprogress = False _DrawStack($iScale) ; draw everything in main gui _Create_CloneGUI(False) ; destroy cloned gui EndIf EndIf If $LRDrag = 2 And $iRBUTTONDOWN = 1 Then $LRDrag = 1 ; Denote $LRDrag as still having one button clicked, need to register the drop on RButton up EndIf If $LRDrag = 1 And $iRBUTTONDOWN = 0 Then $currentEvent[0] = "LRDrop" $currentEvent[1] = $time $LRDrag = 0 EndIf If $LMDrag = 2 And $iMBUTTONDOWN = 1 Then $LMDrag = 1 ; Denote $LMDrag as still having one button clicked, need to register the drop on MButton up EndIf If $LMDrag = 1 And $iMBUTTONDOWN = 0 Then $currentEvent[0] = "LMDrop" $currentEvent[1] = $time $LMDrag = 0 EndIf ;Set LClick if other events haven't fired If $currentEvent[1] <> $time Then $currentEvent[0] = "LClick" $currentEvent[1] = $time EndIf ;Negate $LRClickStatus $RLClickStatus = 0 Case $wParam = $WM_RBUTTONDOWN ;Register Button Down If $currentEvent[0] = "LClick" Then $RLClickStatus = 1 EndIf $iRBUTTONDOWN = 1 Case $wParam = $WM_RBUTTONUP ;Test for Left, Right, and Right Doubleclick here ;Update $iRBUTTONDOWN $iRBUTTONDOWN = 0 ;Test for Right/Left Click If $LRClickStatus = 1 And ($timeDiff) < $doubleClickTime Then $currentEvent[0] = "LRClick" $currentEvent[1] = $time EndIf If $currentEvent[0] = "RClick" And ($timeDiff) < $doubleClickTime Then $currentEvent[0] = "RDClick" $currentEvent[1] = $time EndIf ;Test for Drops If $currentEvent[0] = "RDrag" Then $currentEvent[0] = "RDrop" $currentEvent[1] = $time EndIf If $LRDrag = 2 And $iLBUTTONDOWN = 1 Then $LRDrag = 1 ; Denote $LRDrag as still having one button clicked, need to register the drop on RButton up EndIf If $LRDrag = 1 And $iLBUTTONDOWN = 0 Then $currentEvent[0] = "LRDrop" $currentEvent[1] = $time $LRDrag = 0 EndIf If $RMDrag = 2 And $iMBUTTONDOWN = 1 Then $RMDrag = 1 ; Denote $LMDrag as still having one button clicked, need to register the drop on MButton up EndIf If $RMDrag = 1 And $iMBUTTONDOWN = 0 Then $currentEvent[0] = "RMDrop" $currentEvent[1] = $time $RMDrag = 0 EndIf ;Set LClick if other events haven't fired If $currentEvent[1] <> $time Then $currentEvent[0] = "RClick" $currentEvent[1] = $time EndIf ;Negate $LRClickStatus $LRClickStatus = 0 Case $wParam = $WM_MBUTTONDOWN ;Register Button Down $iMBUTTONDOWN = 1 Case $wParam = $WM_MBUTTONUP ;Test for Middle Double Click here ;Update $iRBUTTONDOWN $iMBUTTONDOWN = 0 ;Test for Right/Left Click If $currentEvent[0] = "MClick" And ($timeDiff) < $doubleClickTime Then $currentEvent[0] = "MDClick" $currentEvent[1] = $time EndIf ;Test for Drops If $currentEvent[0] = "MDrag" Then $currentEvent[0] = "MDrop" $currentEvent[1] = $time EndIf If $LMDrag = 2 And $iLBUTTONDOWN = 1 Then $LMDrag = 1 ; Denote $LRDrag as still having one button clicked, need to register the drop on RButton up EndIf If $LMDrag = 1 And $iLBUTTONDOWN = 0 Then $currentEvent[0] = "LMDrop" $currentEvent[1] = $time $LMDrag = 0 EndIf If $RMDrag = 2 And $iRBUTTONDOWN = 1 Then $RMDrag = 1 ; Denote $LMDrag as still having one button clicked, need to register the drop on MButton up EndIf If $RMDrag = 1 And $iRBUTTONDOWN = 0 Then $currentEvent[0] = "RMDrop" $currentEvent[1] = $time $RMDrag = 0 EndIf ;Set MClick if other events haven't fired If $currentEvent[1] <> $time Then $currentEvent[0] = "MClick" $currentEvent[1] = $time EndIf EndSelect ;~ If $currentEvent[0] <> "" Then ConsoleWrite("event:"&$currentEvent[0] & @CRLF) $ret = DllCall("user32.dll", "long", "CallNextHookEx", "hwnd", $hM_Hook[0], _ "int", $nCode, "ptr", $wParam, "ptr", $lParam) Return $ret[0] EndFunc ;==>_Mouse_Proc Func WM_PAINT($hwnd, $iMsg, $wParam, $lParam) If $hwnd = $hGUI Then _GDIPlus_GraphicsDrawImage($hGraphics, $hBitmap, 0, 0) _WinAPI_RedrawWindow($hwnd, 0, 0, $RDW_VALIDATE) EndIf Return 'GUI_RUNDEFMSG' EndFunc ;==>WM_PAINT Func WM_SIZE($hwnd, $iMsg, $wParam, $lParam) If $hwnd = $hGUI Then $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI) EndIf Return 'GUI_RUNDEFMSG' EndFunc ; From UEZ ? Func _WinAPI_BitmapDisplayTransparentInGUI(ByRef $hHBitmap, ByRef $hGUI, $iOpacity = 0xFF, $bReleaseGDI = True) If Not BitAND(GUIGetStyle($hGUI)[1], $WS_EX_LAYERED) = $WS_EX_LAYERED Then Return SetError(1, 0, 0) Local $tDim = DllStructCreate($tagBITMAP) If Not _WinAPI_GetObject($hHBitmap, DllStructGetSize($tDim), DllStructGetPtr($tDim)) Then Return SetError(2, 0, 0) Local $tSize = DllStructCreate($tagSIZE), $tSource = DllStructCreate($tagPOINT), $tBlend = DllStructCreate($tagBLENDFUNCTION) Local Const $hScrDC = _WinAPI_GetDC(0), $hMemDC = _WinAPI_CreateCompatibleDC($hScrDC), $hOld = _WinAPI_SelectObject($hMemDC, $hHBitmap) $tSize.X = $tDim.bmWidth $tSize.Y = $tDim.bmHeight $tBlend.Alpha = $iOpacity $tBlend.Format = 1 _WinAPI_UpdateLayeredWindow($hGUI, $hScrDC, 0, DllStructGetPtr($tSize), $hMemDC, DllStructGetPtr($tSource), 0, DllStructGetPtr($tBlend), $ULW_ALPHA) _WinAPI_ReleaseDC(0, $hScrDC) _WinAPI_SelectObject($hMemDC, $hOld) _WinAPI_DeleteDC($hMemDC) If $bReleaseGDI Then _WinAPI_DeleteObject($hHBitmap) Return True EndFunc Func _Exit() DllCall("user32.dll", "int", "UnhookWindowsHookEx", "hwnd", $hM_Hook[0]) $hM_Hook[0] = 0 DllCallbackFree($hKey_Proc) $hKey_Proc = 0 ; Clean up _GDIPlus_PenDispose($hPen) _GDIPlus_GraphicsDispose($hBackbuffer) _GDIPlus_BitmapDispose($hBitmap) _GDIPlus_BitmapDispose($hBitmap_switch) _GDIPlus_GraphicsDispose($hGraphics) _GDIPlus_FontDispose($hFont) _GDIPlus_FontFamilyDispose($hFamily) _GDIPlus_StringFormatDispose($hFormat) _GDIPlus_BrushDispose($hBrush) _GDIPlus_BrushDispose($hBrush_cadre_titre) ; Uninitialize GDI+ _GDIPlus_Shutdown() Exit EndFunc If one of you have better ideas to make it work, I am obviously interested to read them Edited June 12, 2019 by tatane
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now