Popular Post MattyD Posted February 3 Popular Post Share Posted February 3 (edited) hi all This one is nowhere near finished - I'd probably call it a proof of concept for now - "GDIControls.au3" needs to be included, then there's a couple of control types that you should be able to create. _GUICtrlGDI_CreateHFader($hGUI, $iX, $iY, $iWidth, $iHeight [, $Colour [, $iStyle [, $iExStyle ]]]) _GUICtrlGDI_CreateVFader($hGUI, $iX, $iY, $iWidth, $iHeight [, $Colour [, $iStyle [, $iExStyle ]]]) _GUICtrlGDI_CreateKnob($hGUI, $iX, $iY, $iWidth, $iHeight [, $Colour [, $iStyle [, $iExStyle ]]]) _GUICtrlGDI_CreateLRKnob($hGUI, $iX, $iY, $iWidth, $iHeight [, $Colour [, $iStyle [, $iExStyle ]]]) _GUICtrlGDI_CreateVMeter($hWnd, $iX, $iY, $iWidth, $iHeight [, $iStyle [, $iExStyle]]) _GUICtrlGDI_CreateHMeter($hWnd, $iX, $iY, $iWidth, $iHeight [, $iStyle [, $iExStyle]]) _GUICtrlGDI_Create7SegDisplay($hGUI, $iX, $iY, $iWidth, $iHeight [, $Colour [, $iStyle [, $iExStyle ]]]) _GUICtrlGDI_Create14SegDisplay($hGUI, $iX, $iY, $iWidth, $iHeight [, $Colour [, $iStyle [, $iExStyle ]]]) The above functions return a controlID which can be read with GuiCtrlRead() via the usual methods. The controls can also be manipulated with GuiCtrlSetData() Valid values can be from 0 through to 127. That's about the long and short of it! ---------- Theres a bit going on with the mechanics of it here, and I'm sure theres probably a better way of going about things... But for anyone who' s interested this is what's going on: I take the requested dimentions of the control, If there's already bitmaps available for the requested type/dimentions/colour we use those. Otherwise, we dynamically generate a set of 128 bitmaps for the control. The next step is to create a "static" control, which is basically the same as a label. With the right style we can push images to these however. At this stage those optional $iStyle and $iExStyle flags come into play. There are some forced style values to make things work, but hey, if you want to add $WS_BORDER or something I'm not gonna stop ya! Static controls are pretty dumb, but they do know when they're clicked on ($STN_CLICKED). This is enough to let me know that a control needs updating. Next we need to track the mouse. We need to know when and where the mouse in released. I can't really utillise the $GUI_EVENT_* method for this. I'd either have to force OnEvent() mode, or we'd have to ask the user to call some function in the Main GuiGetMsg() Loop. So then I thought of handling $WM_MOUSEMOVE. This works great until you move over a control in the client area! It seems the message gets gobbled up. So now I'm using a low-level mouse hook. With this I can find where we are relative to the control and update it accordingly. The next peice of the puzzle is to let the user know that something has been done. I can easily provide a "getter" function that retrieves the control's values. I'd rather not have a bespoke function for this though. So I thought its better to associate dummy controls, which I use as a delivery mechanism. Lastly we need have a method of updating the control from outsige the GUI. For ease of use we probably want to leverage GuiCtrlSetData(). Setting the dummy control this way puts us in the same predicament as earlier however - we can't really use GuiGetMsg() to monitor it. but we can periodically check the value of the dummy control with an adlib function. If the value of the dummy is not where the GDI control was set with the GUI, we know we need to update it! GDICtrls_1-9.zip Edited April 4 by MattyD Danyfirex, genius257, Dan_555 and 5 others 6 2 Link to comment Share on other sites More sharing options...
Andreik Posted February 3 Share Posted February 3 I like their design but the knobs aren't working as expected. If you click a knob and move the mouse to the left side of the control, the indicator goes the other way. Or you can replicate the behavior by just clicking the indicator of a know and the indicator will immediately shift position to the other side of the control. Is this how it's intended to work? Link to comment Share on other sites More sharing options...
MattyD Posted February 3 Author Share Posted February 3 Hey, thanks Andreik, So the knobs are controlled by the Y Axis of the mouse, which by memory should be the norm? but happy to be corrected! I agree they can be a little smarter - at present the knobs will snap to a value on mouse down. I was going to get it to only react only once you start dragging, but meh, good enough for this time of night! Link to comment Share on other sites More sharing options...
argumentum Posted February 3 Share Posted February 3 18 minutes ago, MattyD said: So the knobs are controlled by the Y Axis of the mouse Could on mouse over be controlled by the wheel mouse ? < request Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting. Link to comment Share on other sites More sharing options...
Andreik Posted February 3 Share Posted February 3 7 hours ago, MattyD said: Hey, thanks Andreik, So the knobs are controlled by the Y Axis of the mouse, which by memory should be the norm? but happy to be corrected! I agree they can be a little smarter - at present the knobs will snap to a value on mouse down. I was going to get it to only react only once you start dragging, but meh, good enough for this time of night! It's fine, just wanted to be sure it's the intended behavior. MattyD 1 Link to comment Share on other sites More sharing options...
MattyD Posted February 4 Author Share Posted February 4 10 hours ago, argumentum said: Could on mouse over be controlled by the wheel mouse ? < request Yeah, that sounds like a good idea! The mouse wheel should be easy enough to implement - the hit-testing could be more difficult... The static control won't notify when a mouse moves over it, so I think I'd need to store the locations of every control. Then we'd check if anything matches when the wheel moves. I'm not really sold on this approach though - just feels horribly inefficient. If anyone has had a crack at hit-testing controls in the past I'm all ears! But as a semi-solution we can totally do a: click on the control to select, then wheel to change though. argumentum 1 Link to comment Share on other sites More sharing options...
argumentum Posted February 4 Share Posted February 4 also, attend to HiDpi Scaling Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting. Link to comment Share on other sites More sharing options...
MattyD Posted February 4 Author Share Posted February 4 (edited) 2 hours ago, argumentum said: also, attend to HiDpi Scaling Ah, yep - looks like thats a problem. Thanks! For those playing at home, the control should more or less only react while the mouse is within its bounds... So if you drag a fader, the thumb should sit nicely under the mouse pointer. Something is getting thrown when the scaling is not set at %100, so this obviously needs fixing. Edited February 4 by MattyD argumentum 1 Link to comment Share on other sites More sharing options...
MattyD Posted February 4 Author Share Posted February 4 So a new file to address the issues previously mentioned - The scaling issue is hopefully now fixed! Knob controls will no longer snap to an absolute value on mouse down. They'll only start moving when you begin dragging on the Y-Axis The mouse wheel can now manupulate controls. - Click to select the control, then wheel to change the value. Clicking away from a control should de-select it. argumentum 1 Link to comment Share on other sites More sharing options...
ioa747 Posted February 4 Share Posted February 4 (edited) Thank you for sharing with us. That's very nice work, congratulations. It's nice to have more graphical elements, as an option to enrich the GUI. The responsiveness of the knobs has improved a lot compared to the previous one . suggestions: Spoiler suggestion for more realistic movement: Switch $iCurCtrlType Case $GDICTL_TYPE_KNOB If $aiMousePos[$X] > $__g_aiSelCtrlPos[$X] + ($__g_aiSelCtrlPos[$WIDTH] / 2) Then $iNewValue = $__g_bSelCtrlInitVal + ($aiTgtImg[$Y] - $__g_aiSelCtrlOffset[$Y]) Else $iNewValue = $__g_bSelCtrlInitVal - ($aiTgtImg[$Y] - $__g_aiSelCtrlOffset[$Y]) EndIf Case $GDICTL_TYPE_HFADER $iNewValue = $aiTgtImg[$X] Case $GDICTL_TYPE_VFADER $iNewValue = 127 - $aiTgtImg[$Y] EndSwitch and a function for the outside world to update the element: Func _GUICtrlGDI_SetData($ControlID, $iValue) Local $aBmps, $iBmpIdx, $hWnd $iValue = Int($iValue) If $iValue > 127 Then $iValue = 127 If $iValue < 0 Then $iValue = 0 For $i = 0 To UBound($__g_avCtrls) - 1 If $ControlID = $__g_avCtrls[$i][$GDICTL_DUMMY] Then $hWnd = $__g_avCtrls[$i][$GDICTL_HWND] ExitLoop EndIf Next If $i = UBound($__g_avCtrls) Then Return SetError(1, 0, False) If $__g_avCtrls[$i][$GDICTL_VALUE] = $iValue Then Return $__g_avCtrls[$i][$GDICTL_VALUE] = $iValue $iBmpIdx = $__g_avCtrls[$i][$GDICTL_BMPIDX] $aBmps = $__g_avCtrlBmps[$iBmpIdx][$GDICTL_BMPS] _SendMessage($hWnd, $STM_SETIMAGE, $IMAGE_BITMAP, $aBmps[$iValue]) GUICtrlSendToDummy($__g_avCtrls[$i][$GDICTL_DUMMY], $iValue) EndFunc Edited February 5 by ioa747 I know that I know nothing Link to comment Share on other sites More sharing options...
MattyD Posted February 5 Author Share Posted February 5 (edited) Thanks heaps ioa - really appreaciate it Yeah, certainly we need a way to set a value from outside the GUI. I was going to try and see if I can get GuiCtrlSetData() to trigger something similar to what you've written, but I still need to do the groundwork to see if that's viable. As for the other suggestion, I appreaciate where you're coming from. Pushing the left side of the control up works the same pulling the right side down... I think we do need to choose a direction though and stick with it - just from a usability standpoint. If I cross the centre line while pulling upwards I probably don't want the control to reverse.. Or if I'm using a touch screen my finger might cover the entire control - each time i grab something it could seemingly behave differently (depending on if I'm a little bit left or right of center) . Edited February 5 by MattyD ioa747 1 Link to comment Share on other sites More sharing options...
ioa747 Posted February 5 Share Posted February 5 (edited) 7 hours ago, MattyD said: If I cross the centre line while pulling upwards I probably don't want the control to reverse.. this was the first approach ... after that I went a little further Spoiler expandcollapse popupFunc WH_MOUSE_LL($iNotifCode, $wParam, $lParam) Local $tLLHook, $aiMousePos[2], $iWheelDelta Local $bReleaseCtrl, $iNewValue, $aiTgtImg[2] If $iNotifCode < 0 Then Return _WinAPI_CallNextHookEx($__g_pMouseHook, $iNotifCode, $wParam, $lParam) If $__g_iSelCtrl < 0 Then Return _WinAPI_CallNextHookEx($__g_pMouseHook, $iNotifCode, $wParam, $lParam) Local $iCurCtrlHwnd, $iCurCtrlType, $iCurCtrlValue Local Static $iMouseX = MouseGetPos(0) $iCurCtrlHwnd = $__g_avCtrls[$__g_iSelCtrl][$GDICTL_HWND] $iCurCtrlType = $__g_avCtrls[$__g_iSelCtrl][$GDICTL_TYPE] $iCurCtrlValue = $__g_avCtrls[$__g_iSelCtrl][$GDICTL_VALUE] Switch $wParam Case $WM_LBUTTONDOWN $iMouseX = MouseGetPos(0) $__g_iSelCtrl = -1 Return _WinAPI_CallNextHookEx($__g_pMouseHook, $iNotifCode, $wParam, $lParam) Case $WM_LBUTTONUP $bReleaseCtrl = True ContinueCase Case $WM_MOUSEMOVE If Not $__g_bSelCtrlHeld Then Return _WinAPI_CallNextHookEx($__g_pMouseHook, $iNotifCode, $wParam, $lParam) $tLLHook = DllStructCreate($tagMSLLHOOKSTRUCT, $lParam) $aiMousePos[$X] = DllStructGetData($tLLHook, "pt", 1) ConsoleWrite("$aiMousePos[$X]=" & $aiMousePos[$X] & @CRLF) $aiMousePos[$Y] = DllStructGetData($tLLHook, "pt", 2) $aiTgtImg[$X] = Round(127 * ($aiMousePos[$X] - $__g_aiSelCtrlPos[$X]) / $__g_aiSelCtrlPos[$WIDTH]) $aiTgtImg[$Y] = Round(127 * ($aiMousePos[$Y] - $__g_aiSelCtrlPos[$Y]) / $__g_aiSelCtrlPos[$HEIGHT]) Switch $iCurCtrlType Case $GDICTL_TYPE_KNOB If $iMouseX > $__g_aiSelCtrlPos[$X] + ($__g_aiSelCtrlPos[$WIDTH] / 2) Then $iNewValue = $__g_bSelCtrlInitVal + ($aiTgtImg[$Y] - $__g_aiSelCtrlOffset[$Y]) Else $iNewValue = $__g_bSelCtrlInitVal - ($aiTgtImg[$Y] - $__g_aiSelCtrlOffset[$Y]) EndIf Case $GDICTL_TYPE_HFADER $iNewValue = $aiTgtImg[$X] Case $GDICTL_TYPE_VFADER $iNewValue = 127 - $aiTgtImg[$Y] EndSwitch Case $WM_MOUSEWHEEL $tLLHook = DllStructCreate($tagMSLLHOOKSTRUCT, $lParam) $iWheelDelta = BitShift(DllStructGetData($tLLHook, "mouseData"), 16) / 120 $iNewValue = $iCurCtrlValue + $iWheelDelta Case Else Return _WinAPI_CallNextHookEx($__g_pMouseHook, $iNotifCode, $wParam, $lParam) EndSwitch __GUICtrlGDI_SetData($iCurCtrlHwnd, $iNewValue) If $bReleaseCtrl Then $__g_bSelCtrlHeld = False Return _WinAPI_CallNextHookEx($__g_pMouseHook, $iNotifCode, $wParam, $lParam) EndFunc ;==>WH_MOUSE_LL more is to share the idea Edited February 5 by ioa747 MattyD 1 I know that I know nothing Link to comment Share on other sites More sharing options...
MattyD Posted February 7 Author Share Posted February 7 (edited) Ok so take 3... there is little to no QA happening here so heads up!! Reversed the dragging diretion for the knob controls (so up is more, down is less). GuiCtrlSetData() now should work - Its not the most elegant solution, but hey, this whole project is kindof hacky anyway! added a _GUICtrlGDI_Destroy($iCtrlID) funtion for those crazy people who like to clean up after themselves. added _GUICtrlGDI_FwdMsg($iType, $sFunc) - Basically we're already handling $WM_COMMAND when we include the file. So if this is needed elsewhere, call _GUICtrlGDI_FwdMsg($WM_COMMAND, "myFunc"). Edit - I'm second guessing myself now... Does anyone have any strong opinions as to which way the mouse wheel should work on the faders? Edited February 7 by MattyD Link to comment Share on other sites More sharing options...
Jardz Posted February 8 Share Posted February 8 Hi MattyD, Love the approach, you've traded memory for low CPU making it smooth. One note! I believe you may have a memory leak, you need to release the old bitmap object when you replace it with sendmessage(). Something like: Local $vRet = _SendMessage($hWnd, $STM_SETIMAGE, $IMAGE_BITMAP, $aBmps[$iValue]) If $vRet Then _WinAPI_DeleteObject($vRet) Many thanks for sharing 👍 MattyD 1 Link to comment Share on other sites More sharing options...
MattyD Posted February 8 Author Share Posted February 8 1 hour ago, Jardz said: Hi MattyD, Love the approach, you've traded memory for low CPU making it smooth. One note! I believe you may have a memory leak, you need to release the old bitmap object when you replace it with sendmessage(). Something like: Local $vRet = _SendMessage($hWnd, $STM_SETIMAGE, $IMAGE_BITMAP, $aBmps[$iValue]) If $vRet Then _WinAPI_DeleteObject($vRet) Many thanks for sharing 👍 My pleasure - and thankyou kindly, you are indeed correct. Link to comment Share on other sites More sharing options...
ptrex Posted February 8 Share Posted February 8 Hi, Really nice job... Could be used to start building a music mixing app. Something like this 🤪 argumentum 1 Contributions :Firewall Log Analyzer for XP - Creating COM objects without a need of DLL's - UPnP support in AU3Crystal Reports Viewer - PDFCreator in AutoIT - Duplicate File FinderSQLite3 Database functionality - USB Monitoring - Reading Excel using SQLRun Au3 as a Windows Service - File Monitor - Embedded Flash PlayerDynamic Functions - Control Panel Applets - Digital Signing Code - Excel Grid In AutoIT - Constants for Special Folders in WindowsRead data from Any Windows Edit Control - SOAP and Web Services in AutoIT - Barcode Printing Using PS - AU3 on LightTD WebserverMS LogParser SQL Engine in AutoIT - ImageMagick Image Processing - Converter @ Dec - Hex - Bin -Email Address Encoder - MSI Editor - SNMP - MIB ProtocolFinancial Functions UDF - Set ACL Permissions - Syntax HighLighter for AU3ADOR.RecordSet approach - Real OCR - HTTP Disk - PDF Reader Personal Worldclock - MS Indexing Engine - Printing ControlsGuiListView - Navigation (break the 4000 Limit barrier) - Registration Free COM DLL Distribution - Update - WinRM SMART Analysis - COM Object Browser - Excel PivotTable Object - VLC Media Player - Windows LogOnOff Gui -Extract Data from Outlook to Word & Excel - Analyze Event ID 4226 - DotNet Compiler Wrapper - Powershell_COM - New Link to comment Share on other sites More sharing options...
MattyD Posted February 9 Author Share Posted February 9 Thanks heaps ptrex, yeah why not! As you may have guessed, this has actually sprung from working with that midi project - Basically I had this vision mixer, but the audio controls were all tucked behind some menus on the device. So I "fixed" it by writing my own audio interface This was going to be part of that project, but then I sortof got sidetracked... In all honesty dB meters are probably not a bad idea too 👍 - We probably couldn't use GuiCtrlSetData() on them the way I've implemented it though. I've got an adlib function to check the dummy control's values, then update the associated static control if need be. I would say this method would be too slow for the meters to show anything meaningful. If you set the static control directly I'd imagine it could be workable though. Link to comment Share on other sites More sharing options...
argumentum Posted February 9 Share Posted February 9 @MattyD, it would be good to have your 2 files in a ZIP file with a version or date in the name Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting. Link to comment Share on other sites More sharing options...
MattyD Posted February 9 Author Share Posted February 9 (edited) 6 hours ago, argumentum said: @MattyD, it would be good to have your 2 files in a ZIP file with a version or date in the name Ask and thou shall recieve! Just be aware the "versioning" should be treated very loosely. I'm still treating this all as early development; so its just the same file that has been updated and re-uploaded on my side... That being said, changes since last time: We've now plugged that memory leak previously mentioned. We're now disposing sets of bitmaps if we've destroyed all controls that reference them. Reduced the adlib interval for updating controls. (GUICtrlSetData() should be more responsinve) Edited February 9 by MattyD Link to comment Share on other sites More sharing options...
MattyD Posted February 9 Author Share Posted February 9 hmm, new issue... when you move a control fast there may be a problem, Say we do a quick sweep of a fader from 0 to 127: We check mousemove messages to see if theres a new value send, and if need be fire a SendToDummy. This doesn't nessecarily trigger on every vlaue between 0 & 127, but it can be pretty granular. So this becomes an issue with GuiGetMessage() in a loop, there's that built-in delay to prevent CPU ramping. In the space of one loop, you could've had, say, 10 mousemoves fire. If we're only reading values with GuiCtrlRead() when we process the GGM message, theres a good chance we're too late for the party. In practice, you end up reading a few values along the way during a sweep, but then a bunch of "127"s as we process the backlog of messages. I'm starting to think these dummy controls may be more trouble than they're worth! Link to comment Share on other sites More sharing options...
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