0xC0FFEE Posted June 13 Posted June 13 Hello @ioa747, Have you seen any crashing/runtime errors while developing this? I've been using MetroUDF 5.1 for my GUI builder and if there is any subscript error Metro will crash before writing the subscript error to the console. If there is a subscript error will uc_framework display it or will it have a "rc 0x00..." error. I think we are really close to replacing Koda with these modern frameworks! I've looked at your code a little bit, and it is very organized. I like how the controls are modular. What is detecting the hits and hovers, user32.dll? Thanks for everything, 0xC0ffee
ioa747 Posted June 15 Author Posted June 15 (edited) Hi 0xC0FFEE, thanks for your kind words! Regarding errors: The framework uses Maps for properties. If you try to access a non-existent map, AutoIt will crash, unless you provide error handling. I am trying to implement MapExists checks, and error checks in the main engine (__UC_Main_MsgHandler and _UC_Properties) to prevent these errors at runtime. (I'm sure I missed some, but I'll fix them as I find them) For critical operations, I use the Call() method with the documented error codes (0xDEAD / 0xBEEF). This way, if a function is missing or a parameter is invalid, the framework logs the specific error point to the console Hit Detection: You are right, it relies on user32.dll messages (WM_LBUTTONDOWN, WM_MOUSEMOVE, etc.). The framework essentially acts as a router. It listens for these messages via GUIRegisterMsg, checks which control is under the cursor using the properties stored in our Maps, and then triggers the appropriate _UC_[Type]_Draw or event function. The hovers for the time are managed by the function __UC_Main_MsgHandler Keeps track of $hLastChild (the previous control) and $hWnd (the current control). What I'm trying to achieve now is to avoid pointless redraw. for example with techniques like the one below. Func _UC_Toggle_WM_MOUSEMOVE($idDummy, $hWnd, $iX, $iY) #forceref $hWnd, $iX, $iY Static $sFlag = 0 Local $m = _UC_Properties($idDummy, Default, Default, "UC_Toggle.au3") __DW("_UC_Toggle_WM_MOUSEMOVE :: $idDummy=" & $idDummy & " :: $m.State=" & $m.State & " :: $sFlag=" & $sFlag & @CRLF, 1, ">> UC_Toggle.au3") If Not MapExists($m, "State") Then Return 1 = __DW("_UC_Toggle_WM_MOUSEMOVE :: Not Map Exists $m.State" & @CRLF, 1, "!! UC_Toggle.au3") ; 🚧 If $sFlag = $idDummy & "-" & $m.State Then ; 🚧 as new flag e.g. '4-2' __DW("_UC_Toggle_WM_MOUSEMOVE :: $sFlag=" & $sFlag & " => Return" & @CRLF, 1, "-> UC_Toggle.au3") Return EndIf If $m.State = 0 Then Return ; If is Disabled If $m.State = 1 Then ; If is normal $m.State = 2 ; Hover __DW('_UC_Toggle_WM_MOUSEMOVE :: -> New $sFlag from:' & $sFlag & " to:" & $idDummy & "-" & $m.State & @CRLF, 1, "--> UC_Toggle.au3") $sFlag = $idDummy & "-" & $m.State ; 🚧 _UC_Properties($idDummy, $m, Default, "UC_Toggle.au3") EndIf EndFunc ;==>_UC_Toggle_WM_MOUSEMOVE (I'll go to the early approach, and see how I can integrate it into __UC_Main_MsgHandler, directly) I have updated https://github.com/ioa747/UC_Framework and added the Example4.au3 with a 'chattery' debugging output, for a full recording of the program flow I'm a little pressed for time right now, as soon as I find some free time I'll work on it more extensively. Thank you for your understanding and support. Edited June 15 by ioa747 0xC0FFEE and argumentum 2 I know that I know nothing
0xC0FFEE Posted Saturday at 04:54 PM Posted Saturday at 04:54 PM Hi @ioa747, I took a look at Example4.au3 and the code was very clean! There was no messy GUIRegisterMsg or WM_NOTIFY code visible. I didn't see any flicker either. Heads-up for Maps because I am new to using them. Maybe this could help: I've found that MapExist is not as helpful as these other techniques. Check if a Map has anything in it Global $g_Settings[] If Not UBound($g_Settings) then Return ; Code Returns early if there are no Keys in the Map Check if a Key exists and has value ; Use IsMap or the next line might lead to a runtime error If Not IsMap($m) Then Return ; Keys that don't exist will return Null If $m.State = Null Then Return Do you know any way of drawing a fuzzy shadow with GDI+ under a button? The only way seems to have the window manager drop the shadow under GUI windows (like your buttons). ioa747 1
ioa747 Posted Saturday at 07:11 PM Author Posted Saturday at 07:11 PM Hi! Thanks for the feedback and the heads-up! You are totally right about IsMap(). It's a lifesaver against runtime crashes when passing variables around. I prefer MapExists() over checking for Null just to be formal, but your approach is definitely faster to write! As for the fuzzy shadow with GDI+, you hit a soft spot! Since GDI+ doesn't natively support Gaussian Blur filters, relying on the OS window manager drops shadows on the entire $hWnd rect, which ruins custom or rounded shapes. From my perspective , the correct approach is using a PathGradientBrush on a GraphicsPath around the button to fade a dark color to 0% alpha at the edges (creates a nice soft glow/shadow). I might experiment with the PathGradient approach in future updates! Thanks for interactive I know that I know nothing
genius257 Posted Saturday at 07:21 PM Posted Saturday at 07:21 PM 9 minutes ago, ioa747 said: Since GDI+ doesn't natively support Gaussian Blur filters, https://www.autoitscript.com/autoit3/docs/libfunctions/_GDIPlus_EffectCreateBlur.htm I think it does? ioa747 1 To show your appreciation My highlighted topics: AutoIt Package Manager, AutoItObject Pure AutoIt, AutoIt extension for Visual Studio Code Github: AutoIt HTTP Server, AutoIt HTML Parser
ioa747 Posted Saturday at 08:11 PM Author Posted Saturday at 08:11 PM 48 minutes ago, genius257 said: https://www.autoitscript.com/autoit3/docs/libfunctions/_GDIPlus_EffectCreateBlur.htm I think it does? Oops, thank you for pointing it out! I must study. What is your opinion on the topic of drawing a shadow under a button? I know that I know nothing
genius257 Posted Saturday at 08:17 PM Posted Saturday at 08:17 PM 2 minutes ago, ioa747 said: What is your opinion on the topic of drawing a shadow under a button? Oh i looked into it and it's complicated. I like the idea of shadows, but you can't really draw the shadow outside your control. Best way I've found so far, is padding your control size for the shadow, but that introduces unexpected problems, if the coder don't know this and tries to move or resize the control. I'm considering if I should try it for my own custom controls, but so far it's not a priority, because of the downsides 😅 ioa747 1 To show your appreciation My highlighted topics: AutoIt Package Manager, AutoItObject Pure AutoIt, AutoIt extension for Visual Studio Code Github: AutoIt HTTP Server, AutoIt HTML Parser
ioa747 Posted Saturday at 08:29 PM Author Posted Saturday at 08:29 PM (edited) You hit the nail on the head! Including the shadow completely breaks the predictability of the layout for the end user (alignment issues, inaccurate hit testing on the transparent shadow area, and resizing headaches). I can see why keeping it flat and clean is the smartest priority right now! Just thinking about how to code that padding logic makes me feel desperate 😅 Edited Saturday at 08:30 PM by ioa747 I know that I know nothing
ioa747 Posted Saturday at 08:49 PM Author Posted Saturday at 08:49 PM (edited) The best logic would be an independent function that wouldn't affect the control If we put it underneath, the child window's clipping rect/parent background would just cut the shadow off. The ultimate trick would be the exact opposite. Put the translucent layer right on top of the control, using $WS_EX_TRANSPARENT so it becomes a "ghost" window (zero mouse capture, clicks pass right through to the button). Then, using GDI+ Regions with an Exclude mode, we can punch a "hole" into that top layer exactly where the button is. We draw the fuzzy shadow only on the outside edges, leaving the button area untouched and perfectly crisp. A bit complex to orchestrate, but theoretically, it completely bypasses the clipping limitations! Edited Saturday at 08:53 PM by ioa747 WildByDesign 1 I know that I know nothing
ioa747 Posted 15 hours ago Author Posted 15 hours ago Hi everyone, Regarding drawing custom blur shadows under controls... genius257 rightly pointed out back then that padding the control itself to fit a shadow creates layout and sizing headaches for the developer. At that point, I shared a theoretical idea: What if we put a transparent "ghost" window over the control, punch a hole in it using GDI+ regions, and draw the shadow only on the outer edges? Well, that thought wouldn't let me rest. After a lot of experimentation with the Win32 API and GDI+, I finally added this "piece of wood" to 0xC0FFEE's fire! It's not perfect and can certainly be improved, as it's a first approach. The key is that it's universal and works automatically for all controls. How the architecture of _UC_Shadow_Overlay works internally ; #FUNCTION# ==================================================================================================================== ; Name...........: _UC_Shadow_Overlay ; Description ...: Creates and manages a layered window overlay to render a drop shadow effect for a UC_control. ; Syntax.........: _UC_Shadow_Overlay($idCtrl, $iDirection, $iDistance, $bOutline, $iInflate, $iOpacity, $iMethod) ; Parameters ....: $idCtrl - The ID of the control to apply the shadow to. ; $iDirection - [optional] The angle of the shadow in degrees (0-360). (Default = 150) ; $iDistance - [optional] The distance of the shadow from the control in pixels. (Default = 10) ; $bOutline - [optional] Boolean to toggle outline rendering logic. (Default = True) ; $iInflate - [optional] Pixel value to expand or shrink the shadow area. (Default = 0) ; $iOpacity - [optional] Shadow opacity percentage (0-100). ; Set to 0 for automatic adaptive opacity based on ; parent background brightness (Light=1%, Dark=7%). (Default = 0) ; $iMethod - [optional] Rendering method (1 = Multi-layer blur, 2 = Offset spread). (Default = 2) ; Return values .: Success - Returns the handle (HWND) of the created shadow overlay window. ; Failure - Returns False and sets @error if the control properties are not found. ; =============================================================================================================================== Func _UC_Shadow_Overlay($idCtrl, $iDirection = Default, $iDistance = Default, $bOutline = Default, $iInflate = Default, $iOpacity = Default, $iMethod = Default) The shadow window is actually created on top of the control in Z-Order. The ghost layer, by combining $WS_EX_LAYERED and $WS_EX_TRANSPARENT, makes this top layer completely invisible on mouseovers. Clicks go straight through it to the button below! The exception hole, using GDI+ regions with exception mode, a perfect "hole" is opened in this top layer exactly where the control is. This keeps the control rendering 100% clean. To implement this, I also had to deal with some deep Win32 timing issues. For example, changing the background theme in bulk caused a small rendering delay due to Alpha Blending calculations. Using _WinAPI_LockWindowUpdate() helped quite a bit Also, to avoid the "ghost shadows" that remain on the screen when a control is hidden programmatically (since hidden windows do not trigger WM_PAINT), I implemented a custom state manager _UC_SetState($idCtrl, $iState) so that this can be done internally by UC_Framework It was not a major breakthrough, just a small piece of code added to the collective knowledge, bypassing the typical cut and fill limitations of custom UI frameworks. Thanks to 0xC0FFEE for the initial inspiration and genius257 for pointing out the points of caution! I haven't integrated it into all the controls, I put it experimentally in UC_Toggle, UC_Slider, UC_Button the implementation of the idea, you can find it at https://github.com/ioa747/UC_Framework main.zip Please, every comment is appreciated! leave your comments and experiences here! Thank you very much WildByDesign and argumentum 2 I know that I know nothing
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