WildByDesign Posted Sunday at 11:47 AM Posted Sunday at 11:47 AM Recently, I have been experimenting with enabling a random color border coloring transitions (rainbow) effect in external processes with my Immersive UX (DwmColorBlurMica) project. The idea (and code) comes from the great @argumentum's Win11myOwnBorderColor project. Since my project would color the borders of whichever happens to be the active window at the time and therefore working with separate processes, I don't believe that I can use _Timer_SetTimer() and related functions because "This window must be owned by the calling thread", unfortunately. Therefore in my example, I have had to resort to using AdlibRegister. expandcollapse popup#include <GUIConstantsEx.au3> Global $hGUI Example() Func Example() ; Create a GUI with various controls. $hGUI = GUICreate("Example", 400, 400) Local $idBtn_OK = GUICtrlCreateButton("OK", 310, 370, 85, 25) ; dark titlebar _WinAPI_DwmSetWindowAttribute__($hGUI, 20, 1) ; Display the GUI. GUISetState(@SW_SHOW, $hGUI) AdlibRegister("BorderMeRandomColorViaTimer", 300) ; Loop until the user exits. While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $idBtn_OK ExitLoop EndSwitch WEnd ; Delete the previous GUI and all controls. AdlibUnRegister("BorderMeRandomColorViaTimer") GUIDelete($hGUI) EndFunc ;==>Example Func BorderMeRandomColorViaTimer() Local $color = '0x' & Hex(Random(2, 13, 1), 1) & Hex(Random(2, 13, 1), 1) & Hex(Random(2, 13, 1), 1) & Hex(Random(2, 13, 1), 1) & Hex(Random(2, 13, 1), 1) & Hex(Random(2, 13, 1), 1) DllCall('dwmapi.dll', 'long', 'DwmSetWindowAttribute', 'hwnd', $hGUI, 'dword', 34, 'dword*', $color, 'dword', 4) ; border ;DllCall('dwmapi.dll', 'long', 'DwmSetWindowAttribute', 'hwnd', $g_hForm, 'dword', 35, 'dword*', $color, 'dword', 4) ; caption EndFunc ;==>BorderMeRandomColorViaTimer Func _WinAPI_DwmSetWindowAttribute__($hwnd, $attribute = 34, $value = 0x00FF00, $valLen = 4) Local $aCall = DllCall('dwmapi.dll', 'long', 'DwmSetWindowAttribute', 'hwnd', $hWnd, 'dword', $attribute, 'dword*', $value, 'dword', $valLen) If @error Then Return SetError(@error, @extended, 0) If $aCall[0] Then Return SetError(10, $aCall[0], 0) Return 1 EndFunc ;==>_WinAPI_DwmSetWindowAttribute__ Now the question that I have and what I am asking for help with is making those color transitions smoother. There is a recent example in a program that I follow that is in C# that has achieved a very smooth transition of colors. But since I am not very familiar with C#, I don't understand exactly how it is being done. Particularly, the transition of one color to the next. Link: https://github.com/HotCakeX/Harden-Windows-Security/blob/4966307bc06257b37307d0660e3d821b9944d67b/AppControl Manager/CustomUIElements/AppWindowBorderCustomization.cs#L211-L264 private static void TickUpdate() { long currentTimestamp = Stopwatch.GetTimestamp(); long deltaTicks = currentTimestamp - LastTimestamp; LastTimestamp = currentTimestamp; // Convert ticks to seconds. float deltaSeconds = deltaTicks * TickToSeconds; // Increment hue based on elapsed time and speed. Hue += deltaSeconds * InverseSpeed; // Wrap hue to [0,1) without using modulo. if (Hue >= 1f) { // (int)Hue removes the integer portion (if a long pause made it exceed by more than 1). Hue -= (int)Hue; } #region Convert hue to RGB border color. float t = Hue * 6f; float r = MathF.Abs(t - 3f) - 1f; float g = 2f - MathF.Abs(t - 2f); float b = 2f - MathF.Abs(t - 4f); r = r < 0f ? 0f : (r > 1f ? 1f : r); g = g < 0f ? 0f : (g > 1f ? 1f : g); b = b < 0f ? 0f : (b > 1f ? 1f : b); byte rr = (byte)(r * 255f); byte gg = (byte)(g * 255f); byte bb = (byte)(b * 255f); // https://learn.microsoft.com/windows/win32/gdi/colorref // COLORREF format expected: 0x00BBGGRR uint computedBorderColor = (uint)((bb << 16) | (gg << 8) | rr); #endregion // Main Apply int result = NativeMethods.DwmSetWindowAttribute(GlobalVars.hWnd, DWMWA_BORDER_COLOR, ref computedBorderColor, sizeof(uint)); if (result != 0) { // If setting the border color failed, stop the timer to avoid further errors. if (Timer is not null && Timer.IsRunning) { Timer.Stop(); } Logger.Write($"Failed to set window border color. DwmSetWindowAttribute returned error code: {result}", LogTypeIntel.Error); } } The app is in the Microsoft Store in case anyone wants to see the smooth transitions. It's called AppControl Manager and the rainbow border effect is in the Settings for it. Although many of you will probably understand better what is happening in the C# code. Does anybody have any ideas on what can be done to make the color transition appear smoother? I may be somewhat limited since I don't think I can use timers in external processes. Thank you for your time. argumentum 1
argumentum Posted Sunday at 12:02 PM Posted Sunday at 12:02 PM 8:00 here. Working on a Sunday Anywayz, .. float t = Hue * 6f; is the same in AutoIt, $t = $Hue * 0x6f .. float r = MathF.Abs(t - 3f) - 1f; would be $r = Abs($t - 0x3f) if nobody does it, I'll do it ... next week ? 😅 PS: you should be able to do it by throwing code at it. I have faith in you WildByDesign 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
WildByDesign Posted Sunday at 12:34 PM Author Posted Sunday at 12:34 PM I'm sorry to hear that you got stuck working early on a Sunday of all days. Thank you, I appreciate it. I will see what I can figure out with the color transitions. But I also don't really understand the timing of it either. Other users requested this feature, so it's not something I have thought much about. I did not even think that it could potentially look nice. But after seeing how smooth it is in that C# program, I can understand it can look nice if done right. It's really quite beautiful, surprisingly.
Werty Posted Sunday at 01:34 PM Posted Sunday at 01:34 PM 1 hour ago, argumentum said: .. float t = Hue * 6f; is the same in AutoIt, $t = $Hue * 0x6f .. float r = MathF.Abs(t - 3f) - 1f; would be $r = Abs($t - 0x3f) f in C# means float, but you are treating them as Hex. So it's just $t =$Hue * 6 in AU3, removing the f. argumentum and WildByDesign 2 Some guy's script + some other guy's script = my script!
WildByDesign Posted Monday at 12:25 PM Author Posted Monday at 12:25 PM So I talked to the developer of that program to get an understanding of what is happening in that code since I don't understand C# at all. Even though I somehow magically committed a bunch of C# code to Microsoft which Microsoft has actually shipped. Yeah they shipped my C# code and I had no idea what I was doing. 😆 Anyway, she said that when it colors the border with a main color, let's say blue, it will then hit every shade of blue on the way to the next color, let's say green. And then it will hit every shade of green on the way to the next color and so on. So that is how the border color transitions appear so smooth. And somehow she manages to do it very efficiently as well which is nice. I'm still not 100% sure that I can do this properly with only AdlibRegister() and not have access to _Timer_*() functions.
argumentum Posted Monday at 02:07 PM Posted Monday at 02:07 PM (edited) 1 hour ago, WildByDesign said: I'm still not 100% sure that I can do this properly with only AdlibRegister() and not have access to _Timer_*() functions. ..what are the options: run in same process or span another process. Make faster small updates or make longer taking jump from color to color. I would span another process as the rainbow feature is independent of the main script. IPC seems like OMG !. About this IPC: expandcollapse popup#include <GUIConstantsEx.au3> Exit main() Func main() If StringInStr($CmdLineRaw, "/rainbowThing") Then Return rainbow() Opt("GUIOnEventMode", 1) GUICreate(@ScriptName & " - main", 300, 200) GUISetOnEvent($GUI_EVENT_CLOSE, "SpecialEvents") GUICtrlCreateButton(" stop the other process ", 10, 10) GUICtrlSetOnEvent(-1, main_BttnStop) GUICtrlCreateInput(" something from the other process ", 10, 40, 280) GUISetState() ShellExecute(@AutoItExe, '"' & @ScriptFullPath & '" /rainbowThing') While Sleep(300) WEnd EndFunc ;==>main Func main_BttnStop() ConsoleWrite('+ Func main_BttnStop()' & @CRLF) WinClose(@ScriptName & " - rainbow") EndFunc ;==>main_BttnStop Func SpecialEvents() Switch @GUI_CtrlId Case $GUI_EVENT_CLOSE ControlSetText(@ScriptName & " - main", "", "[CLASS:Edit; INSTANCE:1]", "good bye world @" & @HOUR & ":" & @MIN & ":" & @SEC & "." & @MSEC) GUIDelete() Exit EndSwitch EndFunc ;==>SpecialEvents Func rainbow() Opt("GUIOnEventMode", 1) GUICreate(@ScriptName & " - rainbow", 300, 100) GUISetOnEvent($GUI_EVENT_CLOSE, "SpecialEvents") Local $idBttn = GUICtrlCreateButton(" my rainbow process ", 10, 10) ;~ GUISetState() ; or not. Is not needed While Sleep(300) GUICtrlSetData($idBttn, @HOUR & ":" & @MIN & ":" & @SEC & "." & @MSEC) WEnd EndFunc ;==>rainbow it does Interprocess communication via something else but the use is the same. You'll do fancy IPC when you get more experience Edited Monday at 02:19 PM by argumentum better WildByDesign 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
WildByDesign Posted Monday at 10:57 PM Author Posted Monday at 10:57 PM 8 hours ago, argumentum said: ..what are the options: run in same process or span another process. Make faster small updates or make longer taking jump from color to color. I would span another process as the rainbow feature is independent of the main script. I think that you are right about keeping the rainbow thing independent from the main script. Thanks for this example script of passing information between scripts. It's definitely an area that I need to learn more about. And your example script is a perfect starting point.
Solution MattyD Posted Tuesday at 12:09 AM Solution Posted Tuesday at 12:09 AM (edited) This is quite a clever bit of code! The internal timer is a reference, so doesn't matter when you call the function - it'll always calculate the "correct" colour based on when it was called. The function was being called periodically based on a second external timer. But adlib should happily work for us, or we can just call it in a loop. A hue value is then calculated based on that internal timer. It is a value between 0 and 1, then the RGB values are based on that. We can see this in action... For $i = 0 To 9 WriteVals($i/10) Next Func WriteVals($fHue) ;T = presumably "transition" value. So RGB values are all based on this. Local $fT = 6 * $fHue Local $nR = Abs($fT - 3) - 1 Local $nG = 2 - Abs($fT - 2) Local $nB = 2 - Abs($fT - 4) ;Max out at 0 and 1. $nR = ($nR < 0) ? 0 : ($nR > 1) ? 1 : $nR $nG = ($nG < 0) ? 0 : ($nG > 1) ? 1 : $nG $nB = ($nB < 0) ? 0 : ($nB > 1) ? 1 : $nB ConsoleWrite(StringFormat("Hue: %1.2f", $fHue, $nR, $nG, $nB)& @CRLF) ConsoleWrite(StringFormat("R:%1.2f G:%1.2f B:%1.2f", $nR, $nG, $nB)& @CRLF) ;make percentage of max values! $nR *= 255 $nG *= 255 $nB *= 255 ConsoleWrite(StringFormat("R:%4d G:%4d B:%4d" , $nR, $nG, $nB)& @CRLF & @CRLF) EndFunc And here's that implemented based on time: expandcollapse popup#include <GUIConstantsEx.au3> Global $hGUI, $fSpeed = 4 Example() Func Example() ; Create a GUI with various controls. $hGUI = GUICreate("Example", 400, 400) Local $idBtn_OK = GUICtrlCreateButton("OK", 310, 370, 85, 25) ; dark titlebar _WinAPI_DwmSetWindowAttribute__($hGUI, 20, 1) ; Display the GUI. GUISetState(@SW_SHOW, $hGUI) ; Loop until the user exits. While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $idBtn_OK ExitLoop EndSwitch DoBorder($hGUI) WEnd GUIDelete($hGUI) EndFunc ;==>Example Func DoBorder($hWnd) Local Const $fInverseSpeed = 1/$fSpeed Local Static $fHue ;the border col will be calculated based on the time elapsed from a single timer. Local Static $hTimer = TimerInit() Local Static $fLastTime Local $fCurTime = TimerDiff($hTimer) Local $fTimerSec = ($fCurTime - $fLastTime)/1000 If $fTimerSec < 1/25 Then Return ;Slow down processing (do not needlessly refresh faster than 25hz) $fLastTime = $fCurTime ;Hue is a value between 0 and 1. ;Its value is based on the internal timer.. $fHue += ($fTimerSec * $fInverseSpeed) If $fHue >= 1 Then $fHue -= Int($fHue) ;T = transition value. So RGB values are all based on this. ;We want RGB values to be between 0 and 1. Local $fT = 6 * $fHue Local $fR = Abs($fT - 3) - 1 Local $fG = 2 - Abs($fT - 2) Local $fB = 2 - Abs($fT - 4) ;Max values out at 0 and 1. $fR = ($fR < 0) ? 0 : ($fR > 1) ? 1 : $fR $fG = ($fG < 0) ? 0 : ($fG > 1) ? 1 : $fG $fB = ($fB < 0) ? 0 : ($fB > 1) ? 1 : $fB ;RGB is now a percentage of max values $fR *= 255 $fG *= 255 $fB *= 255 ;Construct RGB Value. (reverse order due to endianness!) Local $iRGB = BitOr(BitShift(Int($fB), -16), BitShift(Int($fG), -8), Int($fR)) DllCall('dwmapi.dll', 'long', 'DwmSetWindowAttribute', 'hwnd', $hWnd, 'dword', 34, 'dword*', $iRGB, 'dword', 4) EndFunc ;==>BorderMeRandomColorViaTimer Func _WinAPI_DwmSetWindowAttribute__($hwnd, $attribute = 34, $value = 0x00FF00, $valLen = 4) Local $aCall = DllCall('dwmapi.dll', 'long', 'DwmSetWindowAttribute', 'hwnd', $hWnd, 'dword', $attribute, 'dword*', $value, 'dword', $valLen) If @error Then Return SetError(@error, @extended, 0) If $aCall[0] Then Return SetError(10, $aCall[0], 0) Return 1 EndFunc ;==>_WinAPI_DwmSetWindowAttribute__ Edit: I'm a bit confused as to why we're jumping into IPC stuff? - was the problem with adlib that you can't supply the window handle as a param? I'd just store the target window handle as a global var to do it that way... - anyway FWIW I've updated the example so you can specify a target window. Edited Tuesday at 12:50 AM by MattyD ioa747 and WildByDesign 2
argumentum Posted Tuesday at 01:26 AM Posted Tuesday at 01:26 AM 1 hour ago, MattyD said: Edit: I'm a bit confused as to why we're jumping into IPC stuff? I think that, if the rainbow effect is too fast and/or free the menus and what not, from freezing the effect, forking would work. It it was my toy to play with, given the extent of the features, I'd make a script just for menus and option, and IPC everything to other concurrent scripts. But is a trial and error thing. If it all works fine within the same instance, keep it simple, and use just one instance. WildByDesign 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
WildByDesign Posted Tuesday at 02:32 AM Author Posted Tuesday at 02:32 AM 2 hours ago, MattyD said: The internal timer is a reference, so doesn't matter when you call the function - it'll always calculate the "correct" colour based on when it was called. The function was being called periodically based on a second external timer. But adlib should happily work for us, or we can just call it in a loop. Matty, this is the second time this month that you have left me speechless. I can't thank you enough. The smoothness of the color transition really is a beautiful thing. It kind of reminds of those LED lights around some TVs these days. Very smooth. 2 hours ago, MattyD said: Edit: I'm a bit confused as to why we're jumping into IPC stuff? - was the problem with adlib that you can't supply the window handle as a param? I'd just store the target window handle as a global var to do it that way... - anyway FWIW I've updated the example so you can specify a target window. Thank you for the update. Being able to supply the window handle is definitely a bonus. So I did end up having some trouble with the smoothness of the transitions in the project that I am aiming to place it in which is Immersive UX. Since it uses a SetWinEventHook and therefore hooking all processes on the machine, it is really a fine-tuned project. It has to be, of course. I tried using AdlibRegister and even matched approx. 15ms timing for the adlib which I measured from your While loop. The problem is not with your code, it's just that there is way too much going on in Immersive UX that the hook gets in the way of the timing needed for the code that you shared. @argumentum was right and predicted (before I even realized it) that I would likely need to run this border color transition functionality in a separate process. Therefore, tomorrow I will spend some time creating a separate process with a mini version of the hook that only deals with the border color transition stuff. It only has to target whatever the current Active process is. I can probably do that without a hook in the second process as well. I'll try a few things tomorrow and see which is the most efficient. Anyway, I will follow up tomorrow. Thank you so much. I really could not comprehend that C# code and you ported it over to AutoIt and it works exquisitely.
MattyD Posted Tuesday at 03:06 AM Posted Tuesday at 03:06 AM (edited) My pleasure mate 1 hour ago, argumentum said: I think that, if the rainbow effect is too fast and/or free the menus and what not, from freezing the effect, forking would work. Ok fair enough. Just as an eye test, we probably on need to refresh this every 100ms or so to keep the animation relatively smooth. At that pace I wouldn't think we'd run into responsiveness issues caused by too much border-ing. But yes, if the process is too busy to call DoBorder() then the animation would obviously pause. 35 minutes ago, WildByDesign said: tried using AdlibRegister and even matched approx. 15ms timing for the adlib which I measured from your While loop That function shouldn't really do anything until that "1/25" seconds has elapsed.. so would adlib a bit slower and save some resources Try 100ms to start, and if it looks janky you can speed it up a little bit from there. Adlibing super fast can also cause issues, this is because the adlib gap could be smaller than the available idle time.. In that case you'll just endup with a backlog of adlib tasks that can't be processed, and you'll probably ramp the cpu. To give you an idea, even doing a Sleep(1) will take around 10 - 15ms by the time the process goes to sleep and wakes up again. Edited Tuesday at 03:08 AM by MattyD WildByDesign and argumentum 2
WildByDesign Posted Tuesday at 12:02 PM Author Posted Tuesday at 12:02 PM 8 hours ago, MattyD said: Just as an eye test, we probably on need to refresh this every 100ms or so to keep the animation relatively smooth. At that pace I wouldn't think we'd run into responsiveness issues caused by too much border-ing. But yes, if the process is too busy to call DoBorder() then the animation would obviously pause. I ended up getting it working smoothly in a separate process (that works together with the main process) without ending up needing to use the event hook or adlib which is nice, less overhead that way. I just ended up using a 50ms loop which was smoother than a 100ms loop that I also tested. It basically just checks for the handle of the active window and keeps track of the previous window handle as well. So when a new window becomes the active window, it will remove the border color from the previous window that is no longer active and the border coloring continues on the newly active window. Can I have your permission to use that function in my Immersive UX project? I assume that you likely don't mind, but I prefer to ask anyway. MattyD 1
MattyD Posted Tuesday at 12:41 PM Posted Tuesday at 12:41 PM sure thing. To be fair, I can't really take the credit - the core logic is from that c# example. But yeah, from my end go nuts. WildByDesign 1
ioa747 Posted Tuesday at 12:46 PM Posted Tuesday at 12:46 PM (edited) experimentally: expandcollapse popup#include <GUIConstantsEx.au3> #include <WinAPIGdi.au3> #include <WindowsConstants.au3> #include <WinAPIEx.au3> #include <Timers.au3> Global $hGUI, $idColor1, $idColor2, $idColor3 Example() Func Example() ; Create a GUI. $hGUI = GUICreate("HLS Rainbow Controls Example", 500, 300, -1, -1, $WS_POPUP) $idColor1 = GUICtrlCreateLabel("", 0, 0, 500, 30, -1, $GUI_WS_EX_PARENTDRAG) $idColor2 = GUICtrlCreateLabel("", 0, 100, 500, 30) $idColor3 = GUICtrlCreateLabel("", 0, 200, 500, 30) Local $idBtn = GUICtrlCreateButton("CLOSE", 400, 250, 85, 30) ; Display the GUI. GUISetState(@SW_SHOW, $hGUI) ; set timer to check every nnn Local $i_TimerInterval = 40 _Timer_SetTimer($hGUI, $i_TimerInterval, "_TimerCheck") ; Register the time-based color update function. AdlibRegister("RandomColorViaTimer", 40) ; Loop until the user exits. While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $idBtn ExitLoop EndSwitch DoBorder() WEnd ; Cleanup ConsoleWrite("Killed All Timers? " & _Timer_KillAllTimers($hGUI) & @CRLF) AdlibUnRegister("RandomColorViaTimer") GUIDelete($hGUI) EndFunc ;==>Example Func RandomColorViaTimer() Local Const $iHueSpeed = 3 Local Const $iMaxHLS = 240 Local Const $iLuminance = 120 Local Const $iSaturation = 240 Local Static $iHue = 0 Local Static $hTimer = TimerInit() ; Calculate Hue $iHue = Mod($iHue + $iHueSpeed, $iMaxHLS) ; Time for a full Hue cycle If $iHue = 0 Then ConsoleWrite("<< << << Adlib: Time for a full Hue cycle: " & Round(TimerDiff($hTimer) / 1000, 3) & " seconds >> >> >>" & @LF) $hTimer = TimerInit() EndIf ; Convert HLS (0-240) to RGB Local $iColorRef = _WinAPI_ColorHLSToRGB($iHue, $iLuminance, $iSaturation) Local $sRGB = '0x' & Hex(_WinAPI_ColorHLSToRGB($iHue, $iLuminance, $iSaturation), 6) ; Apply Colors GUICtrlSetBkColor($idColor1, $sRGB) Local $sRef = _ColorRef($sRGB) ConsoleWrite("Adlib: " & $sRef & @CRLF) EndFunc ;==>RandomColorViaTimer ; Timer call back function Func _TimerCheck($hWnd, $iMsg, $iIDTimer, $iTime) #forceref $hWnd, $iMsg, $iIDTimer, $iTime Local Const $iHueSpeed = 3 Local Const $iMaxHLS = 240 Local Const $iLuminance = 120 Local Const $iSaturation = 240 Local Static $iHue = 160 Local Static $hTimer = TimerInit() ; Calculate Hue (reverse to fit with DoBorder) $iHue -= $iHueSpeed If $iHue < 0 Then $iHue = $iMaxHLS ; Time for a full Hue cycle If $iHue = $iMaxHLS Then ConsoleWrite("<< << << Timer: Time for a full Hue cycle: " & Round(TimerDiff($hTimer) / 1000, 3) & " seconds >> >> >>" & @LF) $hTimer = TimerInit() EndIf ; Convert HLS (0-240) to RGB Local $iColorRef = _WinAPI_ColorHLSToRGB($iHue, $iLuminance, $iSaturation) Local $sRGB = '0x' & Hex(_WinAPI_ColorHLSToRGB($iHue, $iLuminance, $iSaturation), 6) ; Apply Colors GUICtrlSetBkColor($idColor2, $sRGB) Local $sRef = _ColorRef($sRGB) ConsoleWrite("Timer: " & $sRef & @CRLF) EndFunc ;==>_TimerCheck Func DoBorder() Local Const $fSpeed = 4 Local Const $fInverseSpeed = 1 / $fSpeed Local Static $fHue ;the border col will be calculated based on the time elapsed from a single timer. Local Static $hTimer = TimerInit() Local Static $hTimer1 = TimerInit() Local Static $fLastTime Local $fCurTime = TimerDiff($hTimer) Local $fTimerSec = ($fCurTime - $fLastTime) / 1000 If $fTimerSec < 1 / 25 Then Return ;Slow down processing (do not needlessly refresh faster than 25hz) $fLastTime = $fCurTime ;Hue is a value between 0 and 1. ;Its value is based on the internal timer.. $fHue += ($fTimerSec * $fInverseSpeed) If $fHue >= 1 Then $fHue -= Int($fHue) ConsoleWrite("<< << << Bordr: Time for a full Hue cycle: " & Round(TimerDiff($hTimer1) / 1000, 3) & " seconds >> >> >>" & @LF) $hTimer1 = TimerInit() EndIf ;T = transition value. So RGB values are all based on this. ;We want RGB values to be between 0 and 1. Local $fT = 6 * $fHue Local $fR = Abs($fT - 3) - 1 Local $fG = 2 - Abs($fT - 2) Local $fB = 2 - Abs($fT - 4) ;Max values out at 0 and 1. $fR = ($fR < 0) ? 0 : ($fR > 1) ? 1 : $fR $fG = ($fG < 0) ? 0 : ($fG > 1) ? 1 : $fG $fB = ($fB < 0) ? 0 : ($fB > 1) ? 1 : $fB ;RGB is now a percentage of max values $fR *= 255 $fG *= 255 $fB *= 255 ;Construct RGB Value. (reverse order due to endianness!) Local $iRGB = BitOR(BitShift(Int($fB), -16), BitShift(Int($fG), -8), Int($fR)) GUICtrlSetBkColor($idColor3, $iRGB) Local $sRef = _ColorRef($iRGB) ConsoleWrite("Bordr: " & $sRef & @CRLF) EndFunc ;==>DoBorder Func _ColorRef($sRGB) ; Optionaly RGB analysis Local $iHue, $iLuminance, $iSaturation _WinAPI_ColorRGBToHLS($sRGB, $iHue, $iLuminance, $iSaturation) Local $R = _WinAPI_GetRValue($sRGB) Local $G = _WinAPI_GetGValue($sRGB) Local $B = _WinAPI_GetBValue($sRGB) Local $iAutoItColor = _WinAPI_RGB($R, $G, $B) Local $sHexColor = "0x" & Hex($iAutoItColor, 6) Local $sRef = "HLS(" & $iHue & "," & $iLuminance & "," & $iSaturation & ") => RGB(" & $R & "," & $G & "," & $B & ") => " & $sHexColor Return $sRef EndFunc ;==>_ColorRef Edited Tuesday at 01:09 PM by ioa747 WildByDesign and argumentum 2 I know that I know nothing
WildByDesign Posted Tuesday at 01:02 PM Author Posted Tuesday at 01:02 PM 16 minutes ago, ioa747 said: experimentally: You Sir... you know how to bring the party! 😃 That was fun. ioa747 1
WildByDesign Posted Wednesday at 05:38 PM Author Posted Wednesday at 05:38 PM (edited) Here is a fun example that does the smooth color animation for the border and for the blur behind blend color as well. Mesmerizing! 🤩 Spoiler expandcollapse popup#include <GUIConstantsEx.au3> #include <WinAPIHObj.au3> #include <WinAPIGdi.au3> Global $hGUI, $fSpeed = 4 Global $hDwmapi = DllOpen('dwmapi.dll') Global $hUser32 = DllOpen('user32.dll') Global $hGdi = DllOpen('gdi32.dll') Global $WCA_ACCENT_POLICY = 19 Global $ACCENT_DISABLED = 0 Global $ACCENT_ENABLE_GRADIENT = 1 Global $ACCENT_ENABLE_TRANSPARENTGRADIENT = 2 Global $ACCENT_ENABLE_BLURBEHIND = 3 Global $ACCENT_ENABLE_ACRYLICBLURBEHIND = 4 Global $ACCENT_ENABLE_HOSTBACKDROP = 5 Global $ACCENT_INVALID_STATE = 6 DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext" , "HWND", "DPI_AWARENESS_CONTEXT" -4) Example() Func Example() ; Create a GUI with various controls. $hGUI = GUICreate("Example", 400, 400) Local $idBtn_OK = GUICtrlCreateButton("OK", 310, 370, 85, 25) ; dark titlebar _WinAPI_DwmSetWindowAttribute__($hGUI, 20, 1) $hRgn = _WinAPI_CreateEllipticRgn(_WinAPI_CreateRectEx(0, 0, 0, 0)) _WinAPI_DwmEnableBlurBehindWindow_mod($hGUI, 1, 0, $hRgn) _WinAPI_DwmEnableBlurBehindWindow_mod($hGUI, 1, 0, 0) If $hRgn Then _WinAPI_DeleteObject($hRgn) EndIf _WinAPI_DwmExtendFrameIntoClientArea_mod($hGUI, _WinAPI_CreateMargins(-1, -1, -1, -1)) ; Display the GUI. GUISetState(@SW_SHOW, $hGUI) ; Loop until the user exits. While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $idBtn_OK ExitLoop EndSwitch DoBorder($hGUI) WEnd GUIDelete($hGUI) EndFunc ;==>Example Func DoBorder($hWnd) Local Const $fInverseSpeed = 1/$fSpeed Local Static $fHue ;the border col will be calculated based on the time elapsed from a single timer. Local Static $hTimer = TimerInit() Local Static $fLastTime Local $fCurTime = TimerDiff($hTimer) Local $fTimerSec = ($fCurTime - $fLastTime)/1000 If $fTimerSec < 1/25 Then Return ;Slow down processing (do not needlessly refresh faster than 25hz) $fLastTime = $fCurTime ;Hue is a value between 0 and 1. ;Its value is based on the internal timer.. $fHue += ($fTimerSec * $fInverseSpeed) If $fHue >= 1 Then $fHue -= Int($fHue) ;T = transition value. So RGB values are all based on this. ;We want RGB values to be between 0 and 1. Local $fT = 6 * $fHue Local $fR = Abs($fT - 3) - 1 Local $fG = 2 - Abs($fT - 2) Local $fB = 2 - Abs($fT - 4) ;Max values out at 0 and 1. $fR = ($fR < 0) ? 0 : ($fR > 1) ? 1 : $fR $fG = ($fG < 0) ? 0 : ($fG > 1) ? 1 : $fG $fB = ($fB < 0) ? 0 : ($fB > 1) ? 1 : $fB ;RGB is now a percentage of max values $fR *= 255 $fG *= 255 $fB *= 255 ;Construct RGB Value. (reverse order due to endianness!) Local $iRGB = BitOr(BitShift(Int($fB), -16), BitShift(Int($fG), -8), Int($fR)) DllCall($hDwmapi, 'long', 'DwmSetWindowAttribute', 'hwnd', $hWnd, 'dword', 34, 'dword*', $iRGB, 'dword', 4) _WinAPI_DwmEnableBlurBehindWindow11($hWnd, $ACCENT_ENABLE_ACRYLICBLURBEHIND, True, $iRGB, 50) EndFunc ;==>BorderMeRandomColorViaTimer Func _WinAPI_DwmSetWindowAttribute__($hwnd, $attribute = 34, $value = 0x00FF00, $valLen = 4) Local $aCall = DllCall($hDwmapi, 'long', 'DwmSetWindowAttribute', 'hwnd', $hWnd, 'dword', $attribute, 'dword*', $value, 'dword', $valLen) If @error Then Return SetError(@error, @extended, 0) If $aCall[0] Then Return SetError(10, $aCall[0], 0) Return 1 EndFunc ;==>_WinAPI_DwmSetWindowAttribute__ Func _WinAPI_DwmEnableBlurBehindWindow_mod($hWnd, $bEnable = True, $bTransition = False, $hRgn = 0) Local $tBLURBEHIND = DllStructCreate('dword;bool;handle;bool') Local $iFlags = 0 If $hRgn Then $iFlags += 2 DllStructSetData($tBLURBEHIND, 3, $hRgn) EndIf DllStructSetData($tBLURBEHIND, 1, BitOR($iFlags, 0x05)) DllStructSetData($tBLURBEHIND, 2, $bEnable) DllStructSetData($tBLURBEHIND, 4, $bTransition) Local $aCall = DllCall($hDwmapi, 'long', 'DwmEnableBlurBehindWindow', 'hwnd', $hWnd, 'struct*', $tBLURBEHIND) If @error Then Return SetError(@error, @extended, 0) If $aCall[0] Then Return SetError(10, $aCall[0], 0) Return 1 EndFunc ;==>_WinAPI_DwmEnableBlurBehindWindow_mod Func _WinAPI_DwmExtendFrameIntoClientArea_mod($hWnd, $tMARGINS = 0) DllCall($hDwmapi, 'long', 'DwmExtendFrameIntoClientArea', 'hwnd', $hWnd, 'struct*', $tMARGINS) EndFunc ;==>_WinAPI_DwmExtendFrameIntoClientArea_mod ; Function by argumentum Func _percentageOfHex($iVal) $iVal = Int($iVal > 99 ? 100 : ($iVal < 1 ? 0 : $iVal)) ; no more than 100% or less than 0% Return Hex(Ceiling(($iVal * 100) * (2.55 * 100) / (100 * 100)), 2) ; calculate in integers, as floating point numbers suck in a CPU EndFunc ; #FUNCTION# ==================================================================================================================== ; Name ..........: _WinAPI_DwmEnableBlurBehindWindow11 ; Description ...: Enables Aero-like blurred background in Windows 11. ; Syntax ........: _WinAPI_DwmEnableBlurBehindWindow11($hWnd[, $AccentState, $BlendColor, $ColorOpacity, $AccentFlags, $AnimationId]) ; Parameters ....: $hWnd - Window handle ; $AccentState - [optional] Enable or disable the blur effect ; $IncludeCaption - [optional] Extend effects to the titlebar ; $BlendColor - [optional] Sets GradientColor ; $ColorOpacity - [optional] Sets blending color opacity value ; $AccentFlags - [optional] Sets AccentFlags value ; $AnimationId - [optional] Sets AnimationId value ; Return values .: 1 on success, 0 otherwise. Call _WinAPI_GetLastError on failure for more information. ; Author ........: scintilla4evr ; Modified ......: WildByDesign - added $AccentState, $BlendColor, $ColorOpacity, $AccentFlags and $AnimationId ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: Yes ; ACCENT_DISABLED = 0 ; ACCENT_ENABLE_GRADIENT = 1 ; ACCENT_ENABLE_TRANSPARENTGRADIENT = 2 ; ACCENT_ENABLE_BLURBEHIND = 3 ; ACCENT_ENABLE_ACRYLICBLURBEHIND = 4 ; ACCENT_ENABLE_HOSTBACKDROP = 5 ; ACCENT_INVALID_STATE = 6 ; =============================================================================================================================== Func _WinAPI_DwmEnableBlurBehindWindow11($hWnd, $AccentState = $ACCENT_ENABLE_ACRYLICBLURBEHIND, $IncludeCaption = True, $BlendColor = "", $ColorOpacity = "", $AccentFlags = 0, $AnimationId = 0) If $AccentState And $IncludeCaption Then Local $hRgn = _WinAPI_CreateEllipticRgn_mod(_WinAPI_CreateRectEx(0, 0, 0, 0)) _WinAPI_DwmEnableBlurBehindWindow_mod($hWnd, 1, 0, $hRgn) If $hRgn Then _WinAPI_DeleteObject($hRgn) EndIf If Not $AccentState Then _WinAPI_DwmEnableBlurBehindWindow_mod($hWnd, 0) Local $tAccentPolicy = DllStructCreate("int AccentState; int AccentFlags; int GradientColor; int AnimationId") Local $tAttrData = DllStructCreate("dword Attribute; ptr DataBuffer; ulong Size") $tAccentPolicy.AccentState = $AccentState If $AccentState = $ACCENT_ENABLE_TRANSPARENTGRADIENT And $AccentFlags = 0 Then $AccentFlags = 2 $tAccentPolicy.AccentFlags = $AccentFlags If $BlendColor Then Local $iVal = Int($ColorOpacity > 99 ? 100 : ($ColorOpacity < 1 ? 0 : $ColorOpacity)) ; no more than 100% or less than 0% Local $sTransparencyHex = Hex(Ceiling(($iVal * 100) * (2.55 * 100) / (100 * 100)), 2) $tAccentPolicy.GradientColor = '0x' & $sTransparencyHex & Hex($BlendColor, 6) EndIf $tAccentPolicy.AnimationId = $AnimationId $tAttrData.Attribute = $WCA_ACCENT_POLICY $tAttrData.DataBuffer = DllStructGetPtr($tAccentPolicy) $tAttrData.Size = DllStructGetSize($tAccentPolicy) Local $aResult = DllCall($hUser32, "bool", "SetWindowCompositionAttribute", "hwnd", $hWnd, "ptr", DllStructGetPtr($tAttrData)) If @error Then Return SetError(@error, @extended, 0) If $AccentState And $IncludeCaption Then _WinAPI_DwmExtendFrameIntoClientArea_mod($hWnd, _WinAPI_CreateMargins(-1, -1, -1, -1)) If Not $AccentState And $IncludeCaption Then Local $sClassName = _WinAPI_GetClassName_mod($hWnd) If $sClassName <> "CabinetWClass" Then _WinAPI_DwmExtendFrameIntoClientArea_mod($hWnd, _WinAPI_CreateMargins(0, 0, 0, 0)) If $sClassName = "CabinetWClass" Then _WinAPI_DwmExtendFrameIntoClientArea_mod($hWnd, _WinAPI_CreateMargins(-1, -1, -1, -1)) EndIf Return $aResult[0] EndFunc ;==>_WinAPI_DwmEnableBlurBehindWindow11 Func _WinAPI_GetClassName_mod($hWnd) If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd) Local $aCall = DllCall($hUser32, "int", "GetClassNameW", "hwnd", $hWnd, "wstr", "", "int", 4096) If @error Or Not $aCall[0] Then Return SetError(@error, @extended, '') Return SetExtended($aCall[0], $aCall[2]) EndFunc ;==>_WinAPI_GetClassName_mod Func _WinAPI_CreateEllipticRgn_mod($tRECT) Local $aCall = DllCall($hGdi, 'handle', 'CreateEllipticRgnIndirect', 'struct*', $tRECT) If @error Then Return SetError(@error, @extended, False) ; If Not $aCall[0] Then Return SetError(1000, 0, 0) Return $aCall[0] EndFunc ;==>_WinAPI_CreateEllipticRgn_mod Func _WinAPI_SwitchColor_mod($iColor) Return BitOR(BitAND($iColor, 0x00FF00), BitShift(BitAND($iColor, 0x0000FF), -16), BitShift(BitAND($iColor, 0xFF0000), 16)) EndFunc Edited Wednesday at 05:39 PM by WildByDesign ioa747 and argumentum 2
argumentum Posted Wednesday at 07:43 PM Posted Wednesday at 07:43 PM 2 hours ago, WildByDesign said: Mesmerizing! 🤩 ... #include <WindowsConstants.au3> ; $WS_* ... $hGUI = GUICreate("Example", 400, 400, -1, -1, BitOR($GUI_SS_DEFAULT_GUI,$WS_MAXIMIZEBOX,$WS_SIZEBOX,$WS_THICKFRAME,$WS_TABSTOP)) ... should try it in full screen 😍 WildByDesign 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
argumentum Posted 11 hours ago Posted 11 hours ago (edited) Spoiler .. a bit off-topic. Did you try "My fine tuned High Contrast theme editor" ? Bet you'll enjoy it . Edit: a full screen. I think I can get used to this Win95 theme. Spoiler Edited 6 hours ago by argumentum more Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
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