It is currently August 4th, 2021, 11:23 pm

[Suggestion] Assigning a number to a meter

Report bugs with the Rainmeter application and suggest features.
User avatar
Active Colors
Moderator
Posts: 821
Joined: February 16th, 2012, 3:32 am
Location: Berlin, Germany

Re: [Suggestion] Assigning a number to a meter

Post by Active Colors »

Yincognito wrote: April 21st, 2021, 3:17 pm Ok, I found the culprit, but not sure if I should be happy about it: it's Rainmeter's formula parser. For example, this:

X=([&ObjIcon[#CURRENTSECTIONINDEX]:XW])

will produce the stupid error on skin refresh, but this (notice the lack of round brackets):

X=[&ObjIcon[#CURRENTSECTIONINDEX]:XW]

will not. So, as long as you don't add, subtract, multiply, divide, etc. the thing, you can skip the round brackets and lo and behold, it's error free, LMAO. Obviously, on a superficial look (not dwelling into technicalities) this doesn't make any sense, but...

I remember talking a while ago with Brian about other slight (and somewhat related) inconveniences regarding Rainmeter's formula parser (possibly in conjunction with the nested syntax, but I'm not sure it was that too), and, as far as I recall, there wasn't what you'd call a nice solution then either, so I'm afraid we have to live with it. There is this small possibility that one of the developers will come up with a workaround that escaped us, but I wouldn't count on it... :confused:

P.S. This is unfortunate, because I too like to use round brackets in such options, even though there isn't any operation going on - just in case I need to insert one later on in the skin development process.

EDIT: I believe this behavior has something to do with the Important Final Note section from the Inline Lua Notes in the manual. Apart from the error appearing only in a formula, the fact that initial errors due to the order of operations in Rainmeter and Lua at skin refresh time is quite comprehensively alluded to. This is pretty much what happens here. All in all, it's just an initial error with 0 impact on the actual result and behavior, at least starting with the time the skin has finished running its refresh mechanism and is "completely" loaded.
Welp, I use basic math formulas everywhere in the skins as well. It looks that the most proper resolution would be disabling or hiding stuff until things get properly initialized. It just requires changing the construction design of a skin. For now I will live with a dummy meter but will find for it some task so it actually contributes to the skin ahaha.

I have seen your JSON reading and writing skin but I without a test skin I am quite unable to check it out. The other day I was thinking to make a desktop planner and JSON seemed to be a better solution for storing, reading and writing all the data.
User avatar
Active Colors
Moderator
Posts: 821
Joined: February 16th, 2012, 3:32 am
Location: Berlin, Germany

Re: [Suggestion] Assigning a number to a meter

Post by Active Colors »

While on this, any idea if there is a way to get (#CurrentSectionIndex# minus one) ? I have a bunch of these repeating guys:

Code: Select all

[CnsDockW3]
Measure=Calc
Formula=(([CnsDockW2])+([ObjIcon[#CURRENTSECTONINDEX]:W]))
DynamicVariables=1
Disabled=0

[CnsDockW4]
Measure=Calc
Formula=(([CnsDockW3])+([ObjIcon[#CURRENTSECTONINDEX]:W]))
DynamicVariables=1
Disabled=0
I was thinking how to optimize this so I don't change it manually all the time I copypaste it. The workaround might be creating new measures for each such measure where the calculation will be made (#CurrentSectionIndex#-1) and then inserting the result in those guys. But could there be more compact way of doing it?
User avatar
Yincognito
Rainmeter Sage
Posts: 3789
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [Suggestion] Assigning a number to a meter

Post by Yincognito »

Active Colors wrote: April 21st, 2021, 5:18 pmI have seen your JSON reading...
It's not a JSON reader. It reads a file that is similar in some ways to a JSON (like the use of curly brackets, or Field:Value pairs), but not an actual JSON. There is already a Lua JSON reader (hosted on GitHub) made by someone, and although I didn't test it (regexing the strings is in some cases more flexible, because you can do more than just strictly parsing the JSON), I had no intention of reinventing the wheel. What I did was just for my specific case.
Active Colors wrote: April 21st, 2021, 5:33 pmWhile on this, any idea if there is a way to get (#CurrentSectionIndex# minus one) ?
Yes. Not just one way, but more ways. And not just (#CURRENTSECTIONINDEX#-1), but also any Rainmeter formula involving the resulting initial index, "codified" below as <x> (I tried $x$ first, as it looked similar to a mouse variable, but got an error so I changed to something else - feel free to give other suggestions, if you deem it necessary, but be aware that the "separators"/"markers" enclosing the index reference must not be in conflict with characters used by Rainmeter in other cases): 8-)

Script.lua:

Code: Select all

function SectionIndex(section, occurrence, formula)
  local indexes = {}
  for index in section:gmatch('%d+') do table.insert(indexes, index) end
  if occurrence == 'first' then occurrence = 1 elseif occurrence == 'last' then occurrence = #indexes end
  return tostring(SKIN:ParseFormula(string.gsub(formula, '<x>', tostring(indexes[tonumber(occurrence)])))) or '0'
end
In your skin, simply add the new "formula" string parameter (in the form of '(SomeFormulaInvolving<x>AkaTheOriginalIndex)' - don't forget the apostrophes and round brackets) to the inline calling of my Lua function:

Code: Select all

CURRENTSECTIONINDEX=[&Script:SectionIndex('[#*CURRENTSECTION*]','last','(<x>-1)')]
This uses the ParseFormula function of the SKIN object, available to the Rainmeter-Lua system, and performs a substitution (i.e. gsub) of <x> with the original index in the formula string, returning the final result. Obviously, you can do any valid Rainmeter formula operation in the "formula" parameter, for example '(Clamp(<x>,1,13))', or '(Sqrt(<x>))', and so on (it probably works with other Rainmeter section variables as well, though I didn't test it). If you simply want the original index, use '(<x>)' for the 3rd (i.e. the "formula") function parameter - though it might work with '<x>' as well.

Cool, right? :sly:
Good request, by the way - but I was not happy to add only the (index-1) possibility, and since Rainmeter allowed for more... :great:

P.S. You misspelled CURRENTSECTIONINDEX in your sample code - had an error because of copy pasting from there, LOL. Thankfully I figured out quickly where was the issue.
P.S.S. I was too lazy to post my test skin for the above, but I guess it's not too hard to wrap your head around the (minor) changes needed in the code.

EDIT: Not sure if it's entirely possible, but you can try using the new "formula" parameter to workaround the initial harmless errors at skin refresh time, by using the equivalent of your X=([&ObjIcon[#CURRENTSECTIONINDEX]:XW]) formula in the Lua function itself, something like (just guessing here) CURRENTSECTIONINDEX=[&Script:SectionIndex('[#*CURRENTSECTION*]','last','([&ObjIcon<x>:XW])')] or something like that in the [Variables] section, and then use a plain X=#CURRENTSECTIONINDEX# where you need it instead. You know, passing/migrating the formula from one place to another. I have no idea if this will work and avoid those initial errors, but you never know until you try...
User avatar
Active Colors
Moderator
Posts: 821
Joined: February 16th, 2012, 3:32 am
Location: Berlin, Germany

Re: [Suggestion] Assigning a number to a meter

Post by Active Colors »

Yincognito wrote: April 21st, 2021, 10:27 pm Yes. Not just one way, but more ways. And not just (#CURRENTSECTIONINDEX#-1), but also any Rainmeter formula involving the resulting initial index, "codified" below as <x> (I tried $x$ first, as it looked similar to a mouse variable, but got an error so I changed to something else - feel free to give other suggestions, if you deem it necessary, but be aware that the "separators"/"markers" enclosing the index reference must not be in conflict with characters used by Rainmeter in other cases): 8-)

Script.lua:

Code: Select all

function SectionIndex(section, occurrence, formula)
  local indexes = {}
  for index in section:gmatch('%d+') do table.insert(indexes, index) end
  if occurrence == 'first' then occurrence = 1 elseif occurrence == 'last' then occurrence = #indexes end
  return tostring(SKIN:ParseFormula(string.gsub(formula, '<x>', tostring(indexes[tonumber(occurrence)])))) or '0'
end
In your skin, simply add the new "formula" string parameter (in the form of '(SomeFormulaInvolving<x>AkaTheOriginalIndex)' - don't forget the apostrophes and round brackets) to the inline calling of my Lua function:

Code: Select all

CURRENTSECTIONINDEX=[&Script:SectionIndex('[#*CURRENTSECTION*]','last','(<x>-1)')]
Damn this is gold. Works perfectly. Thanks again Yincogonito really really much, and for the detailed explanation and sharing your experiences.
I haven't checked what you described in the last EDIT paragraph but I don't see why it won't work. The only "problem" could be that formulas generally are not parsed in the section variables and nested variables by Rainmeter, however since you are utilizing inline lua it can work I guess.
Also, sorry for my misspelling. In my code it was actually correct but in my message I typed it manually and missed one letter...
About the JSON, I haven't worked with it before, and I referred to it as JSON since your topic is called JSON :d But no matter what it is called, your approach should work for my calendar/planner skin.
Thanks again, :bow:
User avatar
Yincognito
Rainmeter Sage
Posts: 3789
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [Suggestion] Assigning a number to a meter

Post by Yincognito »

Active Colors wrote: April 22nd, 2021, 9:43 am Damn this is gold. Works perfectly. Thanks again Yincogonito really really much, and for the detailed explanation and sharing your experiences.
I haven't checked what you described in the last EDIT paragraph but I don't see why it won't work. The only "problem" could be that formulas generally are not parsed in the section variables and nested variables by Rainmeter, however since you are utilizing inline lua it can work I guess.
Also, sorry for my misspelling. In my code it was actually correct but in my message I typed it manually and missed one letter...
About the JSON, I haven't worked with it before, and I referred to it as JSON since your topic is called JSON :d But no matter what it is called, your approach should work for my calendar/planner skin.
Thanks again, :bow:
Excellent! To conclude, this is the final (I hope) form of a test skin used to illustrate an arbitrarily chosen "current section index" feature...

[SkinFolder]\@Resources\Scripts\Script.lua:

Code: Select all

function SectionIndex(section, occurrence, formula)
  local indexes = {}
  for index in section:gmatch('%d+') do table.insert(indexes, index) end
  if occurrence == 'first' then occurrence = 1 elseif occurrence == 'last' then occurrence = #indexes end
  return tostring(SKIN:ParseFormula(string.gsub(formula, '<x>', tostring(indexes[tonumber(occurrence)] or '0')))) or '0'
end
[SkinFolder]\SectionIndex.ini:

Code: Select all

[Variables]
; Inline Lua Usage: [&Script:SectionIndex(SomeSection,SomeOccurrence,SomeFormula)]
; SomeSection     = the name of any section, enclosed by ' (apostrophes), like: 'Measure1' or 'Meter1'
; SomeOccurrence  = the desired occurrence of an index, like: 3 or '5' or 'first' or 'last'
; SomeFormula     = the Rainmeter formula applied to the original <x> index, like: '(<x>)' or '(<x>+1)' or '(Sqrt(<x>))'
; Section variables need to use their nested form, like: [&Script:SectionIndex('[#Section]',[#Occurrence],'[#Formula]')]

; Applicability In:
; - Simulation of a CURRENTSECTIONINDEX "built-in" variable, "last" index scenario, to avoid repeating inline Lua syntax
CURRENTSECTIONINDEX=[&Script:SectionIndex('[#*CURRENTSECTION*]','last','(<x>)')]
; - Alternative equivalent using inline Lua in the skin code: [&Script:SectionIndex('[#CURRENTSECTION]','last','(<x>)')]

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

---Measures---

[Script]
Measure=Script
ScriptFile=#@#Scripts\Script.lua
UpdateDivider=-1
DynamicVariables=1

[MeasureBlah7Blah15Blah3]
Measure=Calc
Formula=(#CURRENTSECTIONINDEX#)
UpdateDivider=-1
IfCondition=(#CURRENTSECTIONINDEX#=3)
IfTrueAction=[!Log "Last index of #CURRENTSECTION# (i.e. [&Script:SectionIndex('[#CURRENTSECTION]','last','(<x>)')]) equals 3"]
IfFalseAction=[!Log "Last index of #CURRENTSECTION# (i.e. [&Script:SectionIndex('[#CURRENTSECTION]','last','(<x>)')]) is not 3"]
IfConditionMode=1
DynamicVariables=1

---Meters---

[MeterResult]
Meter=String
FontFace=Consolas
FontColor=255,255,255,255
SolidColor=47,47,47,255
Padding=5,5,5,5
FontSize=16
AntiAlias=1
MeasureName=MeasureBlah7Blah15Blah3
Text="Result: %1"
DynamicVariables=1
Packed Version:
SectionIndex_1.0.0.rmskin

Make sure you make the last Lua script modifications as well, since they prevent other minor "errors" that might appear (especially when used in an IfCondition, like above). Also, bear in mind that in the bangs from an IfCondition options (possibly bangs in general), the "long" inline Lua syntax (e.g. [&Script:SectionIndex('[#CURRENTSECTION]','last','(<x>)')]) should be used instead of the "short" custom variable simulation (i.e. #CURRENTSECTIONINDEX# or its nested form [#CURRENTSECTIONINDEX]), because apparently Rainmeter doesn't properly replace the latter with the result in those cases, so, although the IfCondition test above happens correctly, the log message from:

Code: Select all

IfTrueAction=[!Log "Last index of #CURRENTSECTION# (i.e. #CURRENTSECTIONINDEX#) equals 3"]
IfFalseAction=[!Log "Last index of #CURRENTSECTION# (i.e. #CURRENTSECTIONINDEX#) is not 3"]
will incorrectly be Last index of MeasureBlah7Blah15Blah3 (i.e. 0) equals 3 (SectionIndex\SectionIndex.ini)
while the log message from:

Code: Select all

IfTrueAction=[!Log "Last index of #CURRENTSECTION# (i.e. [&Script:SectionIndex('[#CURRENTSECTION]','last','(<x>)')]) equals 3"]
IfFalseAction=[!Log "Last index of #CURRENTSECTION# (i.e. [&Script:SectionIndex('[#CURRENTSECTION]','last','(<x>)')]) is not 3"]
will correctly be Last index of MeasureBlah7Blah15Blah3 (i.e. 3) equals 3 (SectionIndex\SectionIndex.ini)

I'm not sure if I should post this as a bug for the developers to give their opinion on it, as I'm a bit tired to have to workaround every little such Rainmeter peculiarity... :Whistle
You do not have the required permissions to view the files attached to this post.
User avatar
Active Colors
Moderator
Posts: 821
Joined: February 16th, 2012, 3:32 am
Location: Berlin, Germany

Re: [Suggestion] Assigning a number to a meter

Post by Active Colors »

Yincognito wrote: April 22nd, 2021, 12:38 pm Make sure you make the last Lua script modifications as well, since they prevent other minor "errors" that might appear (especially when used in an IfCondition, like above).
It still shows errors related to 0 section names by the way. As before, throwing dummy sections with 0 doesn't populate such errors in the log.

Yincognito wrote: April 22nd, 2021, 12:38 pm Also, bear in mind that in the bangs from an IfCondition options (possibly bangs in general), the "long" inline Lua syntax (e.g. [&Script:SectionIndex('[#CURRENTSECTION]','last','(<x>)')]) should be used instead of the "short" custom variable simulation (i.e. #CURRENTSECTIONINDEX# or its nested form [#CURRENTSECTIONINDEX]), because apparently Rainmeter doesn't properly replace the latter with the result in those cases.
I suppose in case of bangs Rainmeter for some reason strips down [#*CURRENTSECTION*] before it retrieves the name of a section, hence the result is 0. In the rest of the places [#*CURRENTSECTION*] first retrieves the section name and after that strips the letters out leaving only numbers.
User avatar
Yincognito
Rainmeter Sage
Posts: 3789
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [Suggestion] Assigning a number to a meter

Post by Yincognito »

Active Colors wrote: April 22nd, 2021, 4:05 pmIt still shows errors related to 0 section names by the way. As before, throwing dummy sections with 0 doesn't populate such errors in the log.
You mean when migrating the formula as I proposed? Anyway, that wasn't the purpose of my last reply (I kind of made peace with those instances you mentioned and wasn't going to create dummy 0 sections anyway, as the initial error behavior was alluded to in the manual as well and besides the log didn't produce adverse effects at all) - I just wanted to finally see how the function works in an IfCondition, since I had some things to clear out regarding the string vs numeric return value of it, and making sure it works in both IfCondition and IfMatch. The results are good, it does, bar this problem with what happens in the associated bangs, where only the inline Lua syntax works properly.
Active Colors wrote: April 22nd, 2021, 4:05 pmI suppose in case of bangs Rainmeter for some reason strips down [#*CURRENTSECTION*] before it retrieves the name of a section, hence the result is 0. In the rest of the places [#*CURRENTSECTION*] first retrieves the section name and after that strips the letters out leaving only numbers.
Right. Thing is, Rainmeter shouldn't "strip down" anything at all (or pass the empty string to the section parameter of my function, like it does in certain cases, including this one). All it should do is simply replace the variable with its value accordingly, like explained in the manual. The difference as I understood (assuming I did understand something out of Rainmeter) is that the replacement, in the case of nested syntax, is done in bangs when they are executed, as opposed to everywhere else where the replacements are done when the skin code is parsed (excerpt from the manual):

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.
User avatar
Yincognito
Rainmeter Sage
Posts: 3789
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [Suggestion] Assigning a number to a meter

Post by Yincognito »

Active Colors wrote: April 22nd, 2021, 4:05 pmI suppose in case of bangs Rainmeter for some reason strips down [#*CURRENTSECTION*] before it retrieves the name of a section, hence the result is 0. In the rest of the places [#*CURRENTSECTION*] first retrieves the section name and after that strips the letters out leaving only numbers.
Check this out :jawdrop :
Test_1.0.0.rmskin
So, basically, I made a very simple script that gives the value of the #CURRENTSECTION# built-in variable in Rainmeter, but from Lua. While in the measures and meters themselves Lua provides current section's correct value, in the Log bangs of the IfTrueAction/IfFalseAction options from the IfCondition it provides ... NOTHING.

I can't work this way, really. I'll post this OVERLY simplified skin in the bug topic I created yesterday, in the hope that the developers would stop being scared of my "hideously complicated" code and address the matter...someday.
You do not have the required permissions to view the files attached to this post.
User avatar
Active Colors
Moderator
Posts: 821
Joined: February 16th, 2012, 3:32 am
Location: Berlin, Germany

Re: [Suggestion] Assigning a number to a meter

Post by Active Colors »

Temporary solution

Code: Select all

[Variables]
; Normal behavior
CURRENTSECTIONINDEX=[&CSI:SectionIndex('[#*CURRENTSECTION*]','last','(<x>)')]


;Special for bangs
CSI=
CSIspecial=[&CSIspecial:SectionIndex('[#*CSI*]','last','(<x>)')]



; Normal behavior
[CSI]
Measure=Script
ScriptFile=#@#CSI.lua
UpdateDivider=-1


; Special for bangs (notice you use the same script file)
[CSIspecial]
Measure=Script
ScriptFile=#@#CSI.lua
UpdateDivider=-1



[Meter10]
Meter=Image
MouseOverAction=[!SetVariable CSI #CURRENTSECTION#][!Log #CSIspecial#]
GIF.gif
You do not have the required permissions to view the files attached to this post.
User avatar
Active Colors
Moderator
Posts: 821
Joined: February 16th, 2012, 3:32 am
Location: Berlin, Germany

Re: [Suggestion] Assigning a number to a meter

Post by Active Colors »

Can you see if you can use GetMeter and GetMeasure for SKIN object, Measure object, and Meter object? All three are described here https://docs.rainmeter.net/manual/lua-scripting/