I want to have up to 3 numbers displayed on screen as typed which will scroll in the 3 numeric places from right to left ( like a 3 character calculator). The enter key will end the input stage and trigger the end macro/end display timer, with an auto end timer if no enter key hit within a certain time. Keys hit after enter will wipe the previous display. This seems to require a Few methods I'm not familiar with. Can you help me with this?
I realize I don't know how to do any of this - now I have a starting example. Thanks for the code.
This works well. A few points though; I'm building a display for buttons which aren't labeled (on a MIDI device), sending Ctr+Alt+Win+(1-0 and Enter), simply adding visual feedback for the keys hit (ie 1-9 and 0). - I have no Back/Delete key, so the numbers continually scroll/accept inuput, with the value not sent until the Enter key is hit. I use 0's to fill the digits with "empty" when I've made a mistake or don't know exactly what numbers were hit.
-How to make the numbers scroll/replace from right to left => once 3 digits are displayed, with each new digit added move existing to left?
-This is built with a dialog, but I was hoping to have it as a floating OnScreenDisplay (cleaner aesthetic), is this possible?
-After Enter, another timer instead of immediately killing the display?
With OnScreenDisplay, keys would be sent to the active window, therefore I used dialog. We can make dialog transparent.
Function dialog_three_numbers_osd
[removed]
Hhmm... This is mind boggling... Transparent is cool. It's challenging for me to incorporate this, but it's basically what I sought. - Thanks again.
I'm going to refrain from asking you for more (at least for the time being) -until I get a handle on this.....
;The above code is created by the Dialog Editor. Don't change it. ;First time hDlg is 0, and we show dialog. Later hDlg is dialog handle, and we go to the dialog procedure. ;_____________________________________________________________________
;THIS CODE SHOWS DIALOG ;Basic code is created by the Dialog Editor. We add more code. ;This code can be in other macro. I usually put everything in the same macro to avoid multiple macros.
;Declare dialog variables. Optionally you can assign initial values. str controls ="3" str e3 ;Show dialog. ;This code waits until the dialog is closed. ;If closed using OK button or Enter or by calling DT_Ok(), it returns 1, else it returns 0 and we exit (then macro ends). if(!ShowDialog("dialog_three_numbers_osd"&dialog_three_numbers_osd&controls))ret ;Now we have dialog variables and can do whatever we want. out e3 ;...
;This is dialog definition, craeted by the Dialog Editor. ;In Dialog Editor we can set certain styles for dialog and edit control. ;For example, remove dialog caption, and make edit control text right-to left.
;THIS CODE IS DIALOG PROCEDURE ;Basic code is created by the Dialog Editor. We add more code. ;It runs while the above code is waiting in ShowDialog. ;It runs many times. It runs whenever the dialog receives a message (WM_INITDIALOG, WM_TIMER, etc). ;Messages are used to notify dialog about various events. Windows messages are documented in MSDN library. ;We add case for each message that we need. Then code below the case is executed whenever the dialog receives the message.
;messages __Font-- t_f sel message ,caseWM_INITDIALOG;;we receive this message when dialog is just created, but still invisible ,;set font for the edit control ,t_f.Create("Veranda"401) ,t_f.SetDialogFont(hDlg "3") ,t_f.SetDialogFontColor(hDlg 0xff0080"3") , ,Transparent hDlg 2550xffffff;;make dialog transparent, using white as transparent color ,SetTimer hDlg 1100000;;close after 10 s , ,caseWM_TIMER;;we repeatedly receive this message if we called SetTimer; wParam is argument 2 of SetTimer; period is argument 3 of SetTimer ,sel wParam ,,case1 ,,DT_Cancel hDlg ;;close dialog; let ShowDialog return 0 ,,case2 ,,DT_Ok hDlg ;;close dialog; let ShowDialog return 1; also populates dialog variables , ,caseWM_COMMANDgoto messages2 ;;we receive this message when some controls want to notify parent dialog about some events ret ;messages2 sel wParam ,caseEN_CHANGE<<16|3;;text changed in edit control ,_s.getwintext(lParam);if(_s.len>3) _s.remove(0 _s.len-3);EditReplaceSel(lParam 0 _s 1);;if text length > 3, remove characters from beginning (then text will scroll) ,SetTimer hDlg 1100000;;close after 10 s , ,caseIDOK;;OK button or Enter ,SetTimer hDlg 210000;;close after 1 s ,ret;;prevent closing dialog now , ,caseIDCANCEL;;Cancel button or Esc ret1 ;_____________________________________________________________________
;MORE HELP ;1. This function allows you to execute code while the dialog is open and this way change dialog behavior. ;2. It is implicitly called whenever the dialog receives a message. ;3. It is called multiple times. Values of local variables are not preserved. Instead you can use thread variables or SetProp/GetProp. ;4. To execute code when the dialog is just created but still invisible, place the code under case WM_INITDIALOG. Add tabs at the beginning, as well as under other case's. ;5. To execute code when the dialog is being destroyed, place it under WM_DESTROY. ;6. To execute code when the user clicks OK, place the code under case IDOK. When Cancel - under IDCANCEL. ;7. To prevent closing the dialog on OK/Cancel, return 0 under case IDOK/IDCANCEL. ;8. To insert code that must be executed on other events (messages), use the Events button in the dialog editor. ;,;For example, to execute code when button 3 (3 is its id) clicked, in the dialog editor click the button, click Events, OK. ;,;It inserts 'case 3' line. Add your code below. ;9. To generate code that shows the dialog, click Apply in the dialog editor. Copy the code from the QM output. ;,;You can insert code that shows the dialog in other macro(s) or functions(s), or in this function. ;,;If you insert it in this function, insert it below 'if(hDlg) goto messages'. ;,;To run the dialog instead of edit when you click the Run button, right click the selection bar by the '\Dialog_Editor' line. To edit again, right click there again. ;10. While the dialog is open, dialog variables cannot be used. Instead use window/control functions to get/set values of controls. ;,;To set/get text, use something like _s.getwintext(id(3 hDlg)). ;,;To see if a checkbox checked, use something like if(but(id(3 hDlg))) ... . ;,;To get selected listbox item, use something like _i=LB_SelectedItem(id(3 hDlg)). Use CB_SelectedItem for combobox. ;,;In control messages, lParam usually is control handle, and can be used instead of id(n hDlg). ;11. While the dialog is open, dialog variables can be used if you use an user-defined type for them. You can set it in dialog editor options. ;,;But you must explicitly populate the variables using DT_GetControls. Example: ;,;DIALOGVARTYPE& dv=+DT_GetControls(hDlg) ;,;out dv.e3 ;,;if(val(dv.c4Che)) out "checked" ;12. To return a value can be used SetWindowLong or DT_Ret. Example: ret DT_Ret(hDlg 1000). ;13. The dialog procedure used in QM is similar to the dialog box procedure that is documented in the MSDN Library on the Internet. ;,;All the messages (events) are documented there. ;,;The dialog editor's Events dialog contains some mostly used messages but you can use any messages. ;,;Don't use EndDialog and similar functions. QM dialogs are managed by QM extensions.
Wow...that's the dialog bible right there! What a great resource for folks just coming into QM! I really wish I had had that sitting around when I build my first dialogs!
Well, this Bible looks like it's still in Hebrew :?
I'm getting somewhere, but I'm getting frustration too.
-How to give the dialog set coordinates? I've been searching/trying, but all I can do is stretch the dialog or make it appear soemwhere not visible. I want to use 3 huge dialogs at the top of the screen - for MIDI Bank Select MSB, LSB, and Program change. I did discover DS_Center, but I can't define x y.
-How to trigger the code/run dialog - then populate with the triggering key (digit 1)? I'm presently using delays when converting MIDI to numeric to wait for the dialog to exist to send initial key but perhaps it can be simpler? I probably need the delay anyway to wait for the dialog to be enable. Do I need unique dialogs for each number?
-How to kill existing display before (re)opening another to prevent overlap? I'm using a font called LCD (11 segment calculator like). I didn't mention it but I've also got previous/next buttons to step throught the values, which can happen very rapidly. This is working, as the MIDI value is static [dialog(display -key 24- enter)] instead of dynamic [dialog(display -key 2- display -key 4- enter)]. When a program change occurs, the static value is converted into text, the dialog is opened, a delay, the text is inserted then enter. This works fine but the display looks "sluggish" as I have it set for a 2 second delay after IDOK. Killing existing dialog is actually necessary, as this MIDI translation method will open the dialog when Any Program Change is executed. I do realize I could use 2 dialogs, one dynamic and one static (dynamic IDOK no delay, static IDOK delay=(2) second). That way the dynamic would display numbers as typed, enter would immediately end that display, and instantly the static display would appear with the delayed close. Prv/Nxt would only trigger static display.
I Am learning something in all this... I realize you've given me bundles of info, I'm really in new territory and don't know how to understand a lot of it (yet).
My initial idea was to use OSD with Ctr+Alt+Win+(1-9 and 0), whcih wouldn't cause any active window confilicts. I wonder if that would simplify anything? In translating MIDI to QWERTY I try to avoid standard keystorkes, instead using special multikey keystrokes and letting QM send the standard key so I can have arguments, and to avoid any keystroke 'slipping through'. Either way, you've given me much essential info, It's just a slow process comprehending it all for my specific purposes... Many thanks.
I moved ShowDialog etc to a separate function DTN_Show.
You can create many functions, like DTN_1, with different triggers, and call DTN_Show with different values.
This code does all that you asked (sets x y, initial value, closes previous OSD). But maybe this is not the best way to do what you need.
;OsdId - any string that identifies the OSD. This function kills this OSD if exists. ;trigger - initial value to display. ;x, y - coordinates. If 0 - center. If negative - from right. ;color - text color in format 0xBBGGRR. ;size - font size.
;THIS CODE SHOWS DIALOG ;Basic code is created by the Dialog Editor. We add more code.
;Declare dialog variables. Optionally you can assign initial values. str controls ="0 3" str d0 e3
d0=F"dialog_three_numbers_osd_{OsdId}"
e3=trigger
clowin(d0 "#32770");err;;kill existing dialog
typeDTN_DATA color size ;;define type to pass more info to the dialog procedure DTN_DATA z; z.color=color; z.size=size ;;create and set variable of that type
;Show dialog. ;This code waits until the dialog is closed. ;If closed using OK button or Enter or by calling DT_Ok(), it returns 1, else it returns 0 and we exit (then macro ends). if(!ShowDialog("dialog_three_numbers_osd"&dialog_three_numbers_osd&controls 0000&z x y))ret ;Now we have dialog variables and can do whatever we want. out e3 ;...
;I use " /DTN_1" at the beginning for easier testing. When you run this function, instead runs DTH_1. To open dialog editor instead, move the second line to the beginning. ;_____________________________________________________________________
;This is dialog definition, craeted by the Dialog Editor. ;In Dialog Editor we can set certain styles for dialog and edit control. ;For example, remove dialog caption, and make edit control text right-to left.
;THIS CODE IS DIALOG PROCEDURE ;Basic code is created by the Dialog Editor. We add more code. ;It runs while the above code is waiting in ShowDialog. ;It runs many times. It runs whenever the dialog receives a message (WM_INITDIALOG, WM_TIMER, etc). ;Messages are used to notify dialog about various events. Windows messages are documented in MSDN library. ;We add case for each message that we need. Then code below the case is executed whenever the dialog receives the message.
;messages __Font-- t_f sel message ,caseWM_INITDIALOG;;we receive this message when dialog is just created, but still invisible ,;get data passed through ShowDialog's param ,DTN_DATA& z=+DT_GetParam(hDlg) , ,;set font for the edit control ,t_f.Create("LCD" z.size 1) ,t_f.SetDialogFont(hDlg "3") ,t_f.SetDialogFontColor(hDlg z.color "3") , ,Transparent hDlg 2550xffffff;;make dialog transparent, using white as transparent color ,SetTimer hDlg 1100000;;close after 10 s , ,caseWM_TIMER;;we repeatedly receive this message if we called SetTimer; wParam is argument 2 of SetTimer; period is argument 3 of SetTimer ,sel wParam ,,case1 ,,DT_Cancel hDlg ;;close dialog; let ShowDialog return 0 ,,case2 ,,DT_Ok hDlg ;;close dialog; let ShowDialog return 1; also populates dialog variables , ,caseWM_COMMANDgoto messages2 ;;we receive this message when some controls want to notify parent dialog about some events ret ;messages2 sel wParam ,caseEN_CHANGE<<16|3;;text changed in edit control ,_s.getwintext(lParam);if(_s.len>3) _s.remove(0 _s.len-3);EditReplaceSel(lParam 0 _s 1);;if text length > 3, remove characters from beginning (then text will scroll) ,SetTimer hDlg 1100000;;close after 10 s , ,caseEN_SETFOCUS<<16|3;;edit control focused ,SendMessage lParam EM_SETSEL-1-1;;remove selection and move caret to the end of text , ,caseIDOK;;OK button or Enter ,SetTimer hDlg 210000;;close after 1 s ,ret;;prevent closing dialog now , ,caseIDCANCEL;;Cancel button or Esc ret1 ;_____________________________________________________________________
;MORE HELP ;1. This function allows you to execute code while the dialog is open and this way change dialog behavior. ;2. It is implicitly called whenever the dialog receives a message. ;3. It is called multiple times. Values of local variables are not preserved. Instead you can use thread variables or SetProp/GetProp. ;4. To execute code when the dialog is just created but still invisible, place the code under case WM_INITDIALOG. Add tabs at the beginning, as well as under other case's. ;5. To execute code when the dialog is being destroyed, place it under WM_DESTROY. ;6. To execute code when the user clicks OK, place the code under case IDOK. When Cancel - under IDCANCEL. ;7. To prevent closing the dialog on OK/Cancel, return 0 under case IDOK/IDCANCEL. ;8. To insert code that must be executed on other events (messages), use the Events button in the dialog editor. ;,;For example, to execute code when button 3 (3 is its id) clicked, in the dialog editor click the button, click Events, OK. ;,;It inserts 'case 3' line. Add your code below. ;9. To generate code that shows the dialog, click Apply in the dialog editor. Copy the code from the QM output. ;,;You can insert code that shows the dialog in other macro(s) or functions(s), or in this function. ;,;If you insert it in this function, insert it below 'if(hDlg) goto messages'. ;,;To run the dialog instead of edit when you click the Run button, right click the selection bar by the '\Dialog_Editor' line. To edit again, right click there again. ;10. While the dialog is open, dialog variables cannot be used. Instead use window/control functions to get/set values of controls. ;,;To set/get text, use something like _s.getwintext(id(3 hDlg)). ;,;To see if a checkbox checked, use something like if(but(id(3 hDlg))) ... . ;,;To get selected listbox item, use something like _i=LB_SelectedItem(id(3 hDlg)). Use CB_SelectedItem for combobox. ;,;In control messages, lParam usually is control handle, and can be used instead of id(n hDlg). ;11. While the dialog is open, dialog variables can be used if you use an user-defined type for them. You can set it in dialog editor options. ;,;But you must explicitly populate the variables using DT_GetControls. Example: ;,;DIALOGVARTYPE& dv=+DT_GetControls(hDlg) ;,;out dv.e3 ;,;if(val(dv.c4Che)) out "checked" ;12. To return a value can be used SetWindowLong or DT_Ret. Example: ret DT_Ret(hDlg 1000). ;13. The dialog procedure used in QM is similar to the dialog box procedure that is documented in the MSDN Library on the Internet. ;,;All the messages (events) are documented there. ;,;The dialog editor's Events dialog contains some mostly used messages but you can use any messages. ;,;Don't use EndDialog and similar functions. QM dialogs are managed by QM extensions.
I'd hoped to come back with flying colors, but no so yet...
The (DTN_Show) functionality is great. Dynamic entry is working properly as requested with a one caveat - the Enter key doesn't end the input stage/reactivate previous window. That may ease the difficulty I'm having (re)allocating static entry which isn't coeexisting with dynamic now. I've been poking around attempting a fix with varied results. I think Enter ending input will help as a type of footer message - I'm deactivating the dialog effectively as below, but it seems Enter should have a more discreet action. Canceling the dialog returns to previously active window as expected.
ifa(win("dialog_PRG_PRG""#32770")) ,key Y ,act ,end
ifa(win("dialog_LSB_LSB""#32770")) ,key Y ,act ,end
ifa(win("dialog_MSB_MSB""#32770")) ,key Y ,act ,end
elseend
The above method works well enough for dynamic entry, but my previous method for static entry is unreliable - after Enter new numbers are often appended to an existing dialog before it's timer closes. I'm dealing more with the triggering process now, which is nearly a different matter, but it should be the final stage.
Just to note, an MSB message will 'bang/display' LSB and PRG, and an LSB message will 'bang/display' PRG, which are static input functions. I also need to build a trigger to bang/display MSB LSB PRG to see all present values, all static mechanisms (but not exactly what I asked for originally.) I originally expected I'd be able to "easily" adapt code for all this, but I overestimated.
Below is an example of a digit trigger for reference. I'm open to any suggestion.
I apologize for all the requests, and I really thank you for all the efforts. I ended up reverting to the last Dialog method, as that was far easier to allocate than the OSD way, only to realize that the Dialog system is nearly perfect. The problems I'd been having all stemmed from the timing of the auto static keys input execution from the MIDI to text conversion. I haven't perfected it all quite yet, but It's just a matter of - time.
Again, thanks for all you've done, your coding is immaculate, I'm always impressed.