Accessing variables from a form.
@dialogInputString "Caption" [scope.]name [default("Some Text")] [min(length)] [margintop("10px")] [marginbottom("5px")] [max(length)] [readonly(1)]
Add an input element for string values. When the form gets submitted, the value gets stored in scope.name
. If you omit scope. part, form is used as scope. To store it for access outside the form, use global
or perm
as scope. The form scope can only be used in the dialog button commands. min
and max
limit the allowed length of the string. default
sets a default value. readonly
makes the entry read only if value is not 0. margintop
offset to upper element. marginbottom
offset to lower element.
But when I use
@dialogInputString "Offset" global.Offset max(5) default({{global.probeOffset}})
It creates a variable form.globalOffset with no value instead of global.Offset with a value.
Second question: Is there any way to change the value programmatically in the form based on a button? For example, if the default value is 1.36 then whn a button is pressed, needs to add 0.01 to make it 1.37.
I was able to make it work by closing the form and recreating it. But that seems like a little overkill.
Comments
With
@set global.Offset 2
@dialogInputString "Offset" global.Offset max(5) default({{global.Offset}})
it was working for me as expected.
For setting/deleting variables see these server commands:
@set scope.name value
Sets the variable to a given value. Value is normally a computed expression. scope must be a writeable scope. Currently, these scopes are writeable: global, local, perm.
Examples:
@unset scope.name
Deletes an existing variable. Only allowed for scopes global, local and perm!
@reportVariables [scope]
Prints a list with all defined variables with their values in the given scope. If no scope parameter was set all available variables will be printed. Scopes available: local, global, deeplocal, perm.
With deeplocal it is possible so see all local variables in different level of stacks. Therefore you can access every local variable, which currently exists.
If I leave out the @dialogblocking, I only get the form.globalz and not the global.z.
I would also like to know if there is a way to add a button to the form that when clicked can change the value of another control such as changing the value of the @dialogInputString?
@dialogInputDouble "Caption" [scope.]name [min(0.0)] [max(9.9)] [default(0.4)] [margintop("10px")] [marginbottom("5px")] [readonly(1)]
Add an input element for floating numbers. You can add constraints to prevent illegal values. When the form gets submitted, the value gets stored in
scope.name
. If you omit scope. part, form is used as scope. To store it for access outside the form, useglobal
orperm
as scope. The form scope can only be used in the dialog button commands.default
sets a default value.readonly
makes the entry read only if value is not 0.margintop
offset to upper element.marginbottom
offset to lower element.Default values:
- min: -inf - the smallest allowed value
- max: inf - the largest allowed value
- default: 0- start value
- readonly: 0
- margintop: 10px
- marginbottom: 5px
The blocking is not necessary except due to your test. Func displays the dialog and without blocking it returns with dialog visible. Then you run @reportVariables before user has closed the dialog so new value is not set.What you want is adding a Button that calls a func with new value when dialog gets closed with new variables closed
@dialogButton "Button Text" "G-Code"
Adds a button to the dialog being created. The second argument is the g-code to execute when the button gets pressed.
@func setZOffset dist
@echo New offset {{local.dist}}
@endfunc
gets calles with
@dialogButton "Set Offset" "@call setZOffset {{global.z}}"
In this case no blocking is required and you have a place to implement the logic for operating on input data. This is also how you would export form.xy values. With global you of course do not need to make it a parameter, but global should be avoided for temporary values.
I see that the same. Actually you do it in deed since you have the @dialogBlocking which is unneeded in adjust. The visibility of a dialog is not bound to function creating it. It gets created and stays visible until a button is pressed. And only when a button is pressed the function of button gets executed. It actually bad practice to have dialog blocking in wizards. The only place you should really need it when you add it to a printing gcode as without blocking the print will continue while you show the dialogs and that might be unwanted.
Also having your continue flag is unneeded. You only need it because of the blocking nature you are thinking in for dialogs. I know it needs to get used to, but blocking blocks printer communication so nothing you should have.
Think about this logic:
Send monitor and on hit init start variables and call first dialog non blocking. It show and on cancel you do nothing in button command and on succeed you call a function that homes, heat extruders and calls adjust with value 0.
adjust shows z change buttons calling adjust again and on exit a function to disable heaters, store Z.
No blocking since button decide on logic triggered for next step. That is the way I was thinking for them to make easy wizards. adjust might look with this like this:
@call adjust 0
which is not moving z but shows dialog and exits function. So actually it is no recursive call to adjust since old adjust is already finished. So Call stack is also not increasing adjust as with blocking version.
Hope you understand the subtile difference and how it makes things easier.
I guess I'm used to programming where the code calls a screen. But here the screen should call the code. Different mind set.
More over code runs on server and dialog boxes are on ui in browser so even different computers. So this is in deed more ui sending changes without blocking any other viewers ideally. Of course blocking dialog does not stop other ui but they can not execute wizards or anything g-code related.
In end you have
but if firmware really waits for 0 you are bust. Better use M104 and M140 for off.
I see why you need global.exitCalled but don't like it. Should better have something like a @callAtTemperature command to trigger actions on reaching a temperature. Issue I see is that some might change temperature so it never gets reaches temperature so maybe like monitor with miss function if target gets set lower/off. Or wait for target temperature regardless of value plus minus a few degrees. A bit like
@waitForAllTemperatures maxDiff
but also working for manual commands.
I thought about a download page for user created wizards, but due to lack of wizards getting send to us there is none. Guess most wizards are just used in private or created by manufactuars so already installed on their images. After all they are normally very specific for certain firmwares or even printers.
I could also use a dialog telling the user to wait and if they don't want to, then that's their call. I can also make it quicker by heating the bed and nozzle at the same time, but that causes issues on some printers.
I will use links from now on for code.
https://1drv.ms/f/s!An1x6MEtLv87grZxFSTktA9avQiJZw?e=dzQemY
I used @timedCall in a repeating 5 second loop to watch for the temperature to reach the set value. The user can cancel out at any time and can even change the temperature. I also added a settings dialog to allow the user to set the temperatures they want with the temperatures saved as permanent. They can also set the temperatures to 0 if they don't want to wait.
https://1drv.ms/f/s!An1x6MEtLv87grZxFSTktA9avQiJZw?e=dzQemY
I used timedCall in a 5 second continuous loop to watch for the temperatures. The user can cancel out anytime and can even change the temperatures. I also added a dialog for setting the desired temperatures which they can set to 0 if they don't want to wait. The only thing I'm missing now is an icon.
Thank you for your assistance. This was a good learning exercise. I should be good in the future.