It is currently March 28th, 2024, 8:58 am

[FEATURE REQUEST - Important] !UpdateVariables bang

Report bugs with the Rainmeter application and suggest features.
User avatar
Yincognito
Rainmeter Sage
Posts: 7017
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

[FEATURE REQUEST - Important] !UpdateVariables bang

Post by Yincognito »

This very annoying problem has been mentioned before (see here, and probably in a bunch of other places as well), so I'm not the only one affected - it's about the update of variables. See the code below, which no matter how you look at it, should in theory update (or modify, change, whatever) the String2 and String3 variables once String1 is changed, since it's a dependency chain between them:

Code: Select all

[Variables]
String1="string"
String2="A #String1# is made out of characters"
String3="#String2# and it has a length."

[Rainmeter]
Update=1000
DynamicWindowSize=1
AccurateText=1
BackgroundMode=2
SolidColor=47,47,47,255

---Measures---

[MeasureToggler]
Measure=Calc
Formula=(1-MeasureToggler)
UpdateDivider=-1
RegExpSubstitute=1
Substitute="^0$":"string","^1$":"text"
DynamicVariables=1

---Meters---

[MeterTest]
Meter=STRING
X=0
Y=0
FontFace=Consolas
FontColor=255,255,255,255
SolidColor=47,47,47,255
Padding=5,5,5,5
FontSize=16
AntiAlias=1
Text="String1 Format = either 'string' or 'text' (click based, dynamic)#CRLF#String2 Format = 'A #*String1*# is made out of characters'#CRLF#String3 Format = '#*String2*# and it has a length.'#CRLF##CRLF#String1 = #String1##CRLF#String2 = #String2##CRLF#String3 = #String3#"
LeftMouseUpAction=[!UpdateMeasure *][!SetVariable String1 "[MeasureToggler]"][!UpdateMeter *][!Redraw]
;LeftMouseUpAction=[!UpdateMeasure *][!SetVariable String1 "[MeasureToggler]"][!UpdateMeter *][!Redraw][!SetVariable String2 "A #String1# is made out of characters"][!UpdateMeter *][!Redraw][!SetVariable String3 "#String2# and it has a length."][!UpdateMeter *][!Redraw]
;LeftMouseUpAction=[!UpdateMeasure *][!WriteKeyValue Variables String1 "[MeasureToggler]"][!Refresh]
DynamicVariables=1
Neither of the mouse actions achieve what would be logical to happen, i.e. the variables internally becoming either

Code: Select all

String1="text"
String2="A text is made out of characters"
String3="A text is made out of characters and it has a length."
or

Code: Select all

String1="string"
String2="A string is made out of characters"
String3="A string is made out of characters and it has a length."
on left mouse click.

Apart from that, there is also the related problem of variables not updating within the option their change was made, so this leads to downright wrong and inconsistent behavior, not to mention requiring the user or skin designer to write a TON of !SetVariable bangs using hardcoded values (or even worse, having a TON of .inc files to handle that, or a TON of measures acting as "fake variables" because the damn variables just can't be actual variables like they're supposed to be) just to update dependent variables - and this becomes even worse if the number of variables increase.

That being said, I know and understand why this happens: the [Variables] section is not dynamic, thus can't do this automatically. You can't modify that without breaking backwards compatibilty, I get that. What I propose though is a simple !UpdateVariables bang that "updates" the value of variables manually at the time of calling, pretty much the way !UpdateMeasure does. I'm not sure this is possible directly or it needs some "coding hacks" to get it done, but for sure it would be tremendously useful. Basically do what !Refresh does but with the current values of the variables and without upating measures/meters/etc.

Hopefully my case for such an addition (or other workable solution) to Rainmeter is strong enough to warrant at least some thinking about it without the usual "it can't be done" prejudice. Now if that would be put in practice as well that would be really awesome, but I'm getting ahead of myself here with this wishful thinking... :D
Last edited by Yincognito on August 22nd, 2020, 5:50 pm, edited 1 time in total.
User avatar
eclectic-tech
Rainmeter Sage
Posts: 5380
Joined: April 12th, 2012, 9:40 pm
Location: Cedar Point, Ohio, USA
Contact:

Re: [FEATURE REQUEST - Important] !UpdateVariables bang

Post by eclectic-tech »

I agree that this would be a popular addition, but it definitely would break backward compatibility.

By changing how variables are defined, you can get the desired results, but this will get more complicated as you increase the number of variable-dependent variables.

Code: Select all

[Variables]
String1=string
String2=A [&MeasureToggler] is made out of characters
String3=[#String2] and it has a length.

[Rainmeter]
Update=1000
DynamicWindowSize=1
AccurateText=1
BackgroundMode=2
SolidColor=47,47,47,255
OnRefreshAction=[!EnableMeasure MeasureToggler]

---Measures---

[MeasureToggler]
Measure=Calc
Formula=(1-MeasureToggler)
UpdateDivider=-1
RegExpSubstitute=1
Substitute="^0$":"string","^1$":"text"
OnChangeAction=[!SetVariable String1 "[MeasureToggler]"][!Update]
DynamicVariables=1
Disabled=1

---Meters---

[MeterTest]
Meter=STRING
X=0
Y=0
FontFace=Consolas
FontColor=255,255,255,255
SolidColor=47,47,47,255
Padding=5,5,5,5
FontSize=16
AntiAlias=1
Text="String1 Format = either 'string' or 'text' (click based, dynamic)#CRLF#String2 Format = 'A [*&MeasureToggle*] is made out of characters'#CRLF#String3 Format = '#*String2*# and it has a length.'#CRLF##CRLF#String1 = [#String1]#CRLF#String2 = [#String2]#CRLF#String3 = [#String3]"
LeftMouseUpAction=[!UpdateMeasure *][!SetVariable String1 "[MeasureToggler]"][!UpdateMeter *][!Redraw]
;LeftMouseUpAction=[!UpdateMeasure *][!SetVariable String1 "[MeasureToggler]"][!UpdateMeter *][!Redraw][!SetVariable String2 "A #String1# is made out of characters"][!UpdateMeter *][!Redraw][!SetVariable String3 "#String2# and it has a length."][!UpdateMeter *][!Redraw]
;LeftMouseUpAction=[!UpdateMeasure *][!WriteKeyValue Variables String1 "[MeasureToggler]"][!Refresh]
DynamicVariables=1
{Click to animate Image}
variablevars.gif
This achieves this simple test you posted by updating 'String1' in the toggle measure and setting the value of 'String2' to the toggle measure rather than to another variable-dependent variable.

I will let the dev team look into the possibilities of having a new bang.
User avatar
Yincognito
Rainmeter Sage
Posts: 7017
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [FEATURE REQUEST - Important] !UpdateVariables bang

Post by Yincognito »

eclectic-tech wrote: August 22nd, 2020, 11:45 amBy changing how variables are defined, you can get the desired results, but this will get more complicated as you increase the number of variable-dependent variables.
Many thanks for pointing me in the right direction, as this code works without issues:

Code: Select all

[Variables]
String1="string"
String2="A [#String1] is made out of characters"
String3="[#String2] and it has a length."
String4="[#String3] Period."

[Rainmeter]
Update=1000
DynamicWindowSize=1
AccurateText=1
BackgroundMode=2
SolidColor=47,47,47,255

---Measures---

[MeasureToggler]
Measure=Calc
Formula=(1-MeasureToggler)
UpdateDivider=-1
RegExpSubstitute=1
Substitute="^0$":"string","^1$":"text"
DynamicVariables=1

---Meters---

[MeterTest]
Meter=STRING
X=0
Y=0
FontFace=Consolas
FontColor=255,255,255,255
SolidColor=47,47,47,255
Padding=5,5,5,5
FontSize=16
AntiAlias=1
Text="String1 Format = either 'string' or 'text' (click based, dynamic)#CRLF#String2 Format = 'A [#*String1*] is made out of characters'#CRLF#String3 Format = '[#*String2*] and it has a length.'#CRLF##CRLF#String1 = #String1##CRLF#String2 = #String2##CRLF#String3 = #String3##CRLF#String4 = #String4#"
LeftMouseUpAction=[!UpdateMeasure *][!SetVariable String1 "[MeasureToggler]"][!SetVariable String2 "A [#String1] is made out of characters"][!SetVariable String3 "[#String2] and it has a length."][!UpdateMeter *][!Redraw]
DynamicVariables=1
Of course, as you said, it becomes more complex and the number of bangs required increase once you increase the number of variable-dependent variables. Also, it requires you to set each variable again each time a change is made to the lowest level variable (i.e. String1), as it can be seen above, where String4 doesn't update unless a [!SetVariable String4 "[#String3] Period."] bang is added as well. Although the method works (lots of thanks for that!) it's quite a pain to apply it in a "real-life" scenario in a skin. For example, I have my weather variables (mainly regex patterns) set like this:

Code: Select all

; Site Mode: EscB=\\ <-> API Mode: EscB=
EscB=\\
Q=#EscB#"
EscQ=#EscB##EscB#\\"

Cleaner="(?:^[^[\x200B]].*|.*[^[\x200B]]$)":"","(?:^[\x200B]|[\x200B]$)":"","(?:^\\\d+|\\\d+$)":""
Decoder="[\\]+"":"""
; General Patterns
Flag=(?siU)
Lead=(?>.*#Q#[^"]*dailyforecast#Q#:\[|.*#Q#[^"]*data#Q#:|)
Stop=(?>,|\{|\[|\]|\}|$)
Data=(?:[^"\{\[\]\}]*|(?:(?>#EscQ#|[^"])*#Q#){2}+)
; Source Data
Weather=^(.*)$
; Weather
Location=#Q#[^"]*location[^"]*#Q#:[^\}]*([\{\[]{1}[^\}]*#Q#[^"]*city[^"]*#Q#:\s*#Q#[^"]+#Q#.*[\]\}]{2})
Observation=#Q#[^"]*observation[^"]*#Q#:[^\}]*([\{\[]{1}.*[\]\}]{1})
DateTime=#Q#[^"]*datetime[^"]*#Q#:[^\}]*([\{\[]{1}.*[\]\}]{1})
DailyForecast=#Q#(?=[^"]*daily)(?=[^"]*forecast)[^"]*#Q#:(?:(?=.*15day).*15day|)[^\}]*([\{\[]{1}.*[\]\}]{3,4}+)
; Weather -> Location
Latitude=#Q#[^"]*latitude[^"]*#Q#:
Longitude=#Q#[^"]*longitude[^"]*#Q#:
City=#Q#[^"]*city#Q#:
District=#Q#[^"]*district#Q#:
DistrictCode=#Q#[^"]*districtcode[^"]*#Q#:
Country=#Q#[^"]*country#Q#:
CountryCode=#Q#[^"]*countrycode[^"]*#Q#:
; Weather -> Observation
Units=[:;]units:
Pressure=#Q#[^"]*altimeter[^"]*#Q#:
PressureCode=#Q#[^"]*(?:barometer|pressure)[^"]*code[^"]*#Q#:
PressureChange=#Q#[^"]*(?:barometer|pressure)[^"]*change[^"]*#Q#:
DewPoint=#Q#[^"]*dewpoint[^"]*#Q#:
FeelsLike=#Q#[^"]*feelslike[^"]*#Q#:
WindGust=#Q#[^"]*gust[^"]*#Q#:
HumidityPercent=#Q#[^"]*humidity[^"]*#Q#:
Icon=#Q#[^"]*icon(?:code)?#Q#:
ObservationTime=#Q#(?:[^"]*(?:observation|valid)time[^"]*)(?<!utc)#Q#:
Phrase=#Q#(?:wx)?phrase(?:long)?#Q#:
Precipitation24Hours=#Q#[^"]*precip24h[^"]*#Q#:
Snow24Hours=#Q#[^"]*snow(?:depth|24h)[^"]*#Q#:
Temperature=#Q#[^"]*temperature#Q#:
UltravioletIndex=#Q#[^"]*uvindex[^"]*#Q#:
Visibility=#Q#[^"]*visibility[^"]*#Q#:
WindSpeed=#Q#[^"]*windspeed[^"]*#Q#:
WindDirection=#Q#[^"]*winddir[^"]*(?-i)C[^"]*#Q#:
; Weather -> DateTime
TimeZone=#Q#[^"]*timezoneabbr[^"]*#Q#:
; Weather -> DailyForecast
ValidDate=#Q#(?:[^"]*valid(?:date|time)[^"]*)(?<!utc)#Q#:
DayOfWeek=#Q#[^"]*dayofweek[^"]*#Q#:
Sunrise=#Q#(?:[^"]*sunrise[^"]*)(?<!utc)#Q#:
Sunset=#Q#(?:[^"]*sunset[^"]*)(?<!utc)#Q#:
MoonCode=#Q#[^"]*moon[^"]*(?:icon|code)#Q#:
Moonrise=#Q#(?:[^"]*moonrise[^"]*)(?<!utc)#Q#:
Moonset=#Q#(?:[^"]*moonset[^"]*)(?<!utc)#Q#:
; Weather -> DailyForecast -> DayPart
PrecipitationPercent=#Q#[^"]*precip(?:pct|chance)[^"]*#Q#:
PrecipitationAmount=#Q#[^"]*(?:precipamt[^"]*|qpf)#Q#:
PrecipitationType=#Q#[^"]*preciptype[^"]*#Q#:
; Note: the Temperature, Ultraviolet Index, Icon, Phrase are like in Weather -> Observation, thus skipped
CloudPercent=#Q#[^"]*cloud(?:pct|cover)[^"]*#Q#:
; Note: the Wind Speed / Direction, Humidity are like in Weather -> Observation, thus skipped
Qualifier=#Q#[^"]*qualifier(?:phrase)?#Q#:
SnowRange=#Q#[^"]*snowrange[^"]*#Q#:
I already automated the process of of switching from the Site mode to the API mode and back a while ago, by checking if an API Key has been added in a corresponding measure using an IfMatch, but I want to similarly automate the escaped (Site mode) vs unescaped (API mode) quote format as well, in the same measure, by "updating" all these variables when changing the EscB variable (which holds the escaped backslash, \\ for the Site mode and nothing aka empty string for the API mode) using a bang instead of having to modify it manually by editing the file. You can imagine the effort of writing a TON of bangs for such a thing to happen - and my skin is extremely light in terms of measures and meters, compared to other weather skins, due to how I built it...
eclectic-tech wrote: August 22nd, 2020, 11:45 amI agree that this would be a popular addition, but it definitely would break backward compatibility.
Hmm. What are you referring to, more specifically? To the fact that variables are strongly linked to updating measures, meters or options calling for their resolve? Or to the fact that they are read only on those updates and don't exist in Rainmeter's memory (where they could easily be updated and have those changes reflected in the skin)?

EDIT: You were right - I only had to turn EscB from a variable into a String measure, set:

Code: Select all

Q=[&EscB]"
EscQ=[&EscB][&EscB]\\"
in the [Variables] section and then instead of setting the variable, set the String option of the newly created [EscB] measure. It all works flawlessly now - many thanks again. :rosegift: I will not yet mark the thread as solved as I would be interested to find out what the devs think about these things, but I might mark it afterwards.
User avatar
eclectic-tech
Rainmeter Sage
Posts: 5380
Joined: April 12th, 2012, 9:40 pm
Location: Cedar Point, Ohio, USA
Contact:

Re: [FEATURE REQUEST - Important] !UpdateVariables bang

Post by eclectic-tech »

When thinking about backward compatibility, the one suite that comes to mind is Enigma by Kaelri.

Besides using an 'ungodly' number of @includes, he also takes advantage of the ability to re-assign variable values between multiple variables, before updating. He used this extensively in his configuration skin and in other skins that step through a list of options or pages, re-assigning their values one-to-another, and then updating.

There may be other methods available with today's Rainmeter, but dynamic variables would break many skins that rely on the fact the variable value does not change until it is updated.
User avatar
Yincognito
Rainmeter Sage
Posts: 7017
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [FEATURE REQUEST - Important] !UpdateVariables bang

Post by Yincognito »

eclectic-tech wrote: August 22nd, 2020, 4:22 pm When thinking about backward compatibility, the one suite that comes to mind is Enigma by Kaelri.

Besides using an 'ungodly' number of @includes, he also takes advantage of the ability to re-assign variable values between multiple variables, before updating. He used this extensively in his configuration skin and in other skins that step through a list of options or pages, re-assigning their values one-to-another, and then updating.

There may be other methods available with today's Rainmeter, but dynamic variables would break many skins that rely on the fact the variable value does not change until it is updated.
Yeah, but that's why I said it would be a bang - if you don't want to use it, no harm done, things will behave exactly as before. :confused:
Anyway, I think I know where you're heading with this: the introduction of this bang would possibly require to make the [Variables] section dynamic, and that would indeed be a blow to backward compatibility. I was just hoping that such an introduction could be made without altering the static nature of the [Variables] section - i.e. do this in memory only, or something like that.
Last edited by Yincognito on August 22nd, 2020, 4:43 pm, edited 1 time in total.
User avatar
jsmorley
Developer
Posts: 22628
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: [FEATURE REQUEST - Important] !UpdateVariables bang

Post by jsmorley »

I almost hesitate to weigh in on this, but I would point out one overriding principle that is important to keep in mind.

The things in [Variables] are just strings. Nothing more, nothing less. Variables are resolved when they are used, not in the context of the [Variables] section.

Code: Select all

[Variables]
myVar1=123
myVar2=(100 + 23)
myVar3=#myVar1#
myVar4=(#myVar1# + #myVar2#)
The value of myVar1 is "123"
The value of myVar2 is "(100 + 23)"
The value of MyVar3 is "#myVar1#
The value of myVar4 is "(#myVar1# + #myVar2#)"

myVar4 has NO idea what the value of #myVar1# is, nor that it is even a variable. It just doesn't care.

It is resolved when you "use" them in a context that resolves variables.

Code: Select all

[Rainmeter]
Update=1000
DynamicWindowSize=1
AccurateText=1

[Variables]
myVar1=123
myVar2=(100 + 23)
myVar3=#myVar1#
myVar4=(#myVar1# + #myVar2#)

[MeasureCalc]
Measure=Calc
Formula=#myVar4#

[MeterResult]
Meter=String
MeasureName=MeasureCalc
FontSize=11
FontWeight=400
FontColor=255,255,255,255
SolidColor=47,47,47,255
Padding=5,5,5,5
AntiAlias=1
Text=myVar1 is #myVar1# | myVar2 is #myVar2# | myVar3 is #myVar3# | myVar4 is #myVar4# | MeasureCalc is %1

1.jpg


Now, the Text option in a String meter doesn't resolve formulas, while obviously the Formula option in a Calc measure does. So this gives you a good sense of what is going on.

All [Variables] are resolved at the point, and in the context, of where they are used.

So I don't see any real point in discussions about making anything in the [Variables] section "dynamic". Some things in Rainmeter are the way they are because it makes the most sense that way. I would be entirely opposed to any change to the behavior of [Variables], and really to any Rube Goldberg approach that tries to make [Variables] be something it isn't. [Variables] is not a "measure". It has no capabilities, other than as a place to associate a string with a variable name. You can use !SetVariable to change the string value of a variable, but it's still just a string. No more, no less. Nothing, no #VarName#, (formula), or [SectionVariable] are in any way "resolved" in the context of the [Variables] section. It just doesn't know or care.
User avatar
Yincognito
Rainmeter Sage
Posts: 7017
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [FEATURE REQUEST - Important] !UpdateVariables bang

Post by Yincognito »

jsmorley wrote: August 22nd, 2020, 4:43 pm I almost hesitate to weigh in on this, but I would point out one overriding principle that is important to keep in mind.

The things in [Variables] are just strings. Nothing more, nothing less. Variables are resolved when they are used, not in the context of the [Variables] section.

Now, the Text option in a String meter doesn't resolve formulas, while obviously the formula option in a Calc measure does. So this gives you a good sense of what is going on.

All [Variables] are resolved at the point, and in the context, of where they are used.

So I don't see any real point in discussions about making anything in the [Variables] section "dynamic". Some things in Rainmeter are the way they are because it makes the most sense that way. I would be entirely opposed to any change to the behavior of [Variables], and really to any Rube Goldberg approach that tries to make [Variables] be something it isn't.
Yep, I figured out they are just strings in the [Variables] section, nothing to argue about that, it's logical. The things about resolving them only where / when / in the context they are used is also normal, in my view (so ok, they are not resolved when the !SetVariable bang happens either, so be it, although this one is a bit strange). The thing I don't really get is why they are not resolved when they are used to be displayed in the meter from my initial code - unless one writes them as [#SomeVariable] or [&SomeMeasure] in the [Variables] section, that is (I'm obviously talking about String2 and String3 here, String1 is fine). Isn't that "usage", in the eyes of Rainmeter? :???:

Also, related to this, am I right that when writing variables / section variables as [#SomeVariable] or [&SomeMeasure] in the [Variables] section, their resolving is in a sense "delayed" by being for a moment in a "literal" form?

P.S. Don't hesitate weighing on things, it never does harm. No progress is done if a man doesn't bother to think on "what if?" scenarios. Feel free to disagree though. :D
User avatar
jsmorley
Developer
Posts: 22628
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: [FEATURE REQUEST - Important] !UpdateVariables bang

Post by jsmorley »

Yincognito wrote: August 22nd, 2020, 5:08 pm Yep, I figured out they are just strings in the [Variables] section, nothing to argue about that, it's logical. The things about resolving them only where / when / in the context they are used is also normal, in my view (so ok, they are not resolved when the !SetVariable bang happens either, so be it, although this one is a bit strange). The thing I don't really get is why they are not resolved when they are used to be displayed in the meter from my initial code - unless one writes them as [#SomeVariable] or [&SomeMeasure] in the [Variables] section, that is. Isn't that "usage", in the eyes of Rainmeter? :???:

Also, related to this, am I right that when writing variables / section variables as [#SomeVariable] or [&SomeMeasure] in the [Variables] section, their resolving is in a sense "delayed" by being for a moment in a "literal" form?

P.S. Don't hesitate weighing on things, it never does harm. No progress is done if a man doesn't bother to think on "what if?" scenarios. Feel free to disagree though. :D
As I said, you are off down the rabbit hole the minute you think of [Variables] as anything more than ALWAYS just a literal string. [Variables] doesn't know or care a bit about the "dependency chain" you alluded to. There is just no such thing in [Variables].
User avatar
jsmorley
Developer
Posts: 22628
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: [FEATURE REQUEST - Important] !UpdateVariables bang

Post by jsmorley »

Yincognito wrote: August 22nd, 2020, 5:08 pm The thing I don't really get is why they are not resolved when they are used to be displayed in the meter from my initial code - unless one writes them as [#SomeVariable] or [&SomeMeasure] in the [Variables] section, that is (I'm obviously talking about String2 and String3 here, String1 is fine). Isn't that "usage", in the eyes of Rainmeter? :???:
I have not looked at your code closely, but I suspect the reason that you need nested versions of the variables and section variables is because they are in fact nested where they are "used".
User avatar
Yincognito
Rainmeter Sage
Posts: 7017
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [FEATURE REQUEST - Important] !UpdateVariables bang

Post by Yincognito »

jsmorley wrote: August 22nd, 2020, 5:17 pm I have not looked at your code closely, but I suspect the reason that you need nested versions of the variables and section variables is because they are in fact nested.
Hm, that's starting to make sense now, I guess. So I have to "tell" Rainmeter that it has to update on the line of dependency chain by using the nested form of referencing the nested elements? Sorry about asking about it, but while the escaping of variables is well documented in the manual and pretty clear, nesting variables is only documented at the level of nesting the names the variables, and not so much at the level of nesting their values...

I hope I make sense in the last phrase and you get where I'm going with this.

EDIT: Or maybe I didn't quite get the grasp of this paragraph properly - in this case it's my mistake:
One difference is that when the Nesting Variables syntax is used in bangs, the values are always dynamically resolved when they are used, including in the [Rainmeter] section of the skin. This is different than the standard #VarName# syntax, which will always require DynamicVariables=1 when the value changes, and can't be dynamic in [Rainmeter]. This difference only applies to use in bangs. When used in option values, DynamicVariables=1 must still be set on the measure or meter if the value changes.
Post Reply