It is currently March 28th, 2024, 7:08 pm

Best way to use MeasureNames efficiently for a skin with lots of string meters?

Get help with creating, editing & fixing problems with skins
MattNY177
Posts: 28
Joined: December 3rd, 2018, 1:15 am

Best way to use MeasureNames efficiently for a skin with lots of string meters?

Post by MattNY177 »

I'm trying to come up with the most efficient way to form Meter/Measure combinations, so that string meters can easily reference corresponding measures on a large scale WITHOUT having to type each individual meter's MeasureName option.

For example:

Code: Select all

[GetStringMeter0001]
Measure=WebParser
URL=https://...
RegExp=(?siU)...
StringIndex=1

[StringMeter0001]
Meter=String
MeasureName=Get#CURRENTSECTION#
The way the last line of this code is written, I could create any number of meters by simply copy/pasting this snippet and adjusting their names accordingly without having to worry about changing each individual MeasureName value.

Where this can get tricky is when you have hundreds of meters, each meter having multiple corresponding measures that can be toggled using !SetOption or !WriteKeyValue to update the MeasureName.

My question is, what is the best practice for setting up these types of relationships? Should I approach every skin as if the Meter name is always the starting point, and every measure name is derived from that by adding a prefix/postfix to the #CURRENTSECTION# variable?
User avatar
balala
Rainmeter Sage
Posts: 16110
Joined: October 11th, 2010, 6:27 pm
Location: Gheorgheni, Romania

Re: Best way to use MeasureNames efficiently for a skin with lots of string meters?

Post by balala »

MattNY177 wrote: March 27th, 2019, 4:16 pm Where this can get tricky is when you have hundreds of meters, each meter having multiple corresponding measures that can be toggled using !SetOption or !WriteKeyValue to update the MeasureName.

My question is, what is the best practice for setting up these types of relationships? Should I approach every skin as if the Meter name is always the starting point, and every measure name is derived from that by adding a prefix/postfix to the #CURRENTSECTION# variable?
Probably this is good, but you have to take care about a small detail: if you're writing the MeasureName options with some !WriteKeyValue bangs there is no such problem, but if you set them with !SetOption bangs, take care to escape the #CURRENTSECTION# variable name into the value set with the bangs.
To see you what am I talking about, here is an example. As I don't know exactly the measures used / wanted by you, I wrote two, a String and a Calc measures. A third measure ([Timer]) sets the measure shown by the [StringMeter0001] String meter, changing the MeasureName option:

Code: Select all

[GetStringMeter0001]
Measure=String
String=String One 

[NumStringMeter0001]
Measure=Calc
Formula=111

[Timer]
Measure=Calc
Formula=(( Timer + 1 ) % 2 )
IfCondition=(#CURRENTSECTION#=0)
IfTrueAction=[!SetOption StringMeter0001 MeasureName "Get#*CURRENTSECTION*#"][!UpdateMeter "StringMeter0001"][!Redraw]
IfFalseAction=[!SetOption StringMeter0001 MeasureName "Num#*CURRENTSECTION*#"][!UpdateMeter "StringMeter0001"][!Redraw]
UpdateDivider=3
 
[StringMeter0001]
Meter=STRING
X=0
Y=0
Padding=15,5,15,5
FontColor=220,220,220
FontEffectColor=0,0,0
StringEffect=Shadow
SolidColor=0,0,0,150
FontSize=8
FontFace=Segoe UI
StringStyle=BOLD
StringAlign=LEFT
AntiAlias=1
Text=%1
See how the MeasureNames were set with the !SetOption bangs: I didn't set Get#CURRENTSECTION# and Num#CURRENTSECTION#, but Get#*CURRENTSECTION*# and respectively Num#*CURRENTSECTION*#. This is required to get the set values to work.
User avatar
Yincognito
Rainmeter Sage
Posts: 7025
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: Best way to use MeasureNames efficiently for a skin with lots of string meters?

Post by Yincognito »

MattNY177 wrote: March 27th, 2019, 4:16 pm I'm trying to come up with the most efficient way to form Meter/Measure combinations, so that string meters can easily reference corresponding measures on a large scale WITHOUT having to type each individual meter's MeasureName option. Where this can get tricky is when you have hundreds of meters, each meter having multiple corresponding measures that can be toggled using !SetOption or !WriteKeyValue to update the MeasureName.

My question is, what is the best practice for setting up these types of relationships? Should I approach every skin as if the Meter name is always the starting point, and every measure name is derived from that by adding a prefix/postfix to the #CURRENTSECTION# variable?
I went down the road you have, and the best way to handle this is stop creating hundreds of measures/meters, and just reuse a single one (or a couple of them). Now, of course, I don't know the specifics in your case, but generally, if you have repetitive things measured/handled, then you should identify the things that are similar to all of them, create one or more base measure/meters containing the similarities, and then at runtime just adapt that/those measure/meters by tweaking the relevant index/bangs/variables that are subject to change.

Of course, sometimes such tricks are just not possible, as you'd want to get all things in one big measurement/parse because maybe you need all the values to calculate something else, but those are the exceptions. In all the other cases, you'd generally want to measure or display just a part of the whole at a given moment, and this is where the bangs changing the relevant indexes or variables come handy.

To illustrate this, take a look at this little excerpt from a skin I wrote:

Code: Select all

---Measures Rainmeter---

[MS_Rainmeter_Counter]
Group=DiskGroup
Measure=Calc
Formula=0
UpdateDivider=-1
RegExpSubstitute=1
Substitute="^0$":"Total","^1$":"C","^2$":"D","^3$":"E","^4$":"F","^5$":"G","^6$":"H","^7$":"I","^8$":"J","^9$":"K","^10$":"L","^11$":"M","^12$":"N","^13$":"O","^14$":"P","^15$":"Q","^16$":"R","^17$":"S","^18$":"T","^19$":"U","^20$":"V","^21$":"W","^22$":"X","^23$":"Y","^24$":"Z"
IfCondition=(MS_Rainmeter_Counter=0)
IfTrueAction=[!SetVariable DiskIDPrefix "_"][!SetVariable DiskID [MS_Rainmeter_Counter]][!SetVariable DiskIDPostfix ""]
IfFalseAction=[!SetVariable DiskIDPrefix ""][!SetVariable DiskID [MS_Rainmeter_Counter]][!SetVariable DiskIDPostfix ":"]
IfConditionMode=1
DynamicVariables=1

---Measures UsageMonitor---

[MS_UsageMonitor_DiskReadRate]
Group=DiskGroup
Measure=Plugin
Plugin=UsageMonitor
Category=LogicalDisk
Counter=Disk Read Bytes/sec
Name=#DiskIDPrefix##DiskID##DiskIDPostfix#
DynamicVariables=1

[MS_UsageMonitor_DiskReadRateValue]
Group=DiskGroup
Measure=Calc
Formula=MS_UsageMonitor_DiskReadRate

[MS_Rainmeter_SetMeters]
Group=DiskGroup
Measure=Calc
IfCondition=(MS_Rainmeter_Counter=0)
IfTrueAction=[!SetOption MT_Rainmeter_DiskReadUse Text "Disks Read"][!SetOption MT_Rainmeter_DiskReadUse ToolTipTitle "Disk #DiskID#: [MS_Rainmeter_#DiskID#Used]"][!SetOption MT_Rainmeter_DiskReadUse ToolTipText "Read [MS_Rainmeter_DiskReadRate]Bs"][!SetOption MT_Rainmeter_DiskReadUseValue MeasureName MS_UsageMonitor_DiskReadRateValue]
IfFalseAction=[!SetOption MT_Rainmeter_DiskReadUse Text "#DiskID# Read"][!SetOption MT_Rainmeter_DiskReadUse ToolTipTitle "Disk #DiskID#: [MS_Rainmeter_#DiskID#Used]"][!SetOption MT_Rainmeter_DiskReadUse ToolTipText "Read [MS_Rainmeter_DiskReadRate]Bs"][!SetOption MT_Rainmeter_DiskReadUseValue MeasureName MS_Rainmeter_DiskUsedValue]
IfConditionMode=1
DynamicVariables=1

---Meters---

[MT_Rainmeter_DiskReadUse]
Meter=STRING
MeterStyle=SCell | STitleColText
Text=
ToolTipTitle=
ToolTipText=
MouseScrollUpAction=[!SetOption MS_Rainmeter_Counter Formula ((MS_Rainmeter_Counter<=(0))?(24):(MS_Rainmeter_Counter-1))][!UpdateMeasureGroup "DiskGroup"][!UpdateMeter *][!Redraw]
MouseScrollDownAction=[!SetOption MS_Rainmeter_Counter Formula ((MS_Rainmeter_Counter>=(24))?(0):(MS_Rainmeter_Counter+1))][!UpdateMeasureGroup "DiskGroup"][!UpdateMeter *][!Redraw]
DynamicVariables=1

[MT_Rainmeter_DiskReadUseValue]
Meter=STRING
MeterStyle=SCell | SPrimaryColText
MeasureName=MS_UsageMonitor_DiskReadRateValue
AutoScale=1k
NumOfDecimals=1
Text="%1Bs"
DynamicVariables=1
This is adapted and cut off from the main skin, so it won't work, but what it does is reuse a single [MS_UsageMonitor_DiskReadRate] measure to measure the read rate of any of the 25 possible drives (i.e._Total, plus C:, D:, etc.), by using bangs to change variables like #DiskIDPrefix#, #DiskID# or #DiskIDPostfix# on mouse scroll, variables that are also used to set the relevant Name option of the [MS_UsageMonitor_DiskReadRate] measure in order to measure the previous or the next drive read rates. Bottom line, instead of creating 25 measures and meters to handle each drive individually, I only work with 2 or 3 that will dynamically change their "index-like" option on demand, to measure the desired drive.

This way of approaching things made my skins span on just a couple of pages instead of tens and tens of pages, simplified the process and the readability, probably improved performance a little bit (since I'm only measuring one thing instead of 25 things) and overall made it easier for me to work on my skins. Sure, there will be some long bang rows in the process, but it's just a row, not lots of pages.

One other thing you could do to make things easier is to use the regex search/replace function in Notepad++, on the whole document or just the selected text (if you're not doing it already, that is). That helps a lot in changing lots of text according to the desired pattern, and it only takes a couple of seconds, if you build your regexes properly.
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth
User avatar
qwerky
Posts: 182
Joined: April 10th, 2014, 12:31 am
Location: Canada

Re: Best way to use MeasureNames efficiently for a skin with lots of string meters?

Post by qwerky »

Yincognito wrote: March 27th, 2019, 11:07 pm I went down the road you have, and the best way to handle this is stop creating hundreds of measures/meters, and just reuse a single one (or a couple of them). Now, of course, I don't know the specifics in your case, but generally, if you have repetitive things measured/handled, then you should identify the things that are similar to all of them, create one or more base measure/meters containing the similarities, and then at runtime just adapt that/those measure/meters by tweaking the relevant index/bangs/variables that are subject to change.

Of course, sometimes such tricks are just not possible, as you'd want to get all things in one big measurement/parse because maybe you need all the values to calculate something else, but those are the exceptions. In all the other cases, you'd generally want to measure or display just a part of the whole at a given moment, and this is where the bangs changing the relevant indexes or variables come handy.

To illustrate this, take a look at this little excerpt from a skin I wrote:
This is adapted and cut off from the main skin, so it won't work, but what it does is reuse a single [MS_UsageMonitor_DiskReadRate] measure to measure the read rate of any of the 25 possible drives (i.e._Total, plus C:, D:, etc.), by using bangs to change variables like #DiskIDPrefix#, #DiskID# or #DiskIDPostfix# on mouse scroll, variables that are also used to set the relevant Name option of the [MS_UsageMonitor_DiskReadRate] measure in order to measure the previous or the next drive read rates. Bottom line, instead of creating 25 measures and meters to handle each drive individually, I only work with 2 or 3 that will dynamically change their "index-like" option on demand, to measure the desired drive.

This way of approaching things made my skins span on just a couple of pages instead of tens and tens of pages, simplified the process and the readability, probably improved performance a little bit (since I'm only measuring one thing instead of 25 things) and overall made it easier for me to work on my skins. Sure, there will be some long bang rows in the process, but it's just a row, not lots of pages.
Bang! Bang! You're right! (Couldn't resist.) :rofl:

Facing this same issue, I was leaning towards just using a multitude of meters, as it was simpler, though longer. The thought of using so many bangs to set so many options was distracting, to say the least. But after reading your post, I have given it some more thought, and I think that even the option setting bangs can be condensed by judicious use of variables, so I'm going to give this approach a try. Thanks for pointing it out. :welcome:

Of course, as you also said, there may be other considerations which cause the first approach to be more appropriate. The OP will need to decide for himself.
User avatar
Yincognito
Rainmeter Sage
Posts: 7025
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: Best way to use MeasureNames efficiently for a skin with lots of string meters?

Post by Yincognito »

qwerky wrote: March 28th, 2019, 5:32 pm Bang! Bang! You're right! (Couldn't resist.) :rofl:

Facing this same issue, I was leaning towards just using a multitude of meters, as it was simpler, though longer. The thought of using so many bangs to set so many options was distracting, to say the least. But after reading your post, I have given it some more thought, and I think that even the option setting bangs can be condensed by judicious use of variables, so I'm going to give this approach a try. Thanks for pointing it out. :welcome:

Of course, as you also said, there may be other considerations which cause the first approach to be more appropriate. The OP will need to decide for himself.
Exactly. It doesn't have to be that many options, if you correctly identify the things that change and, as you said, use variables properly. Most of the times it's just about one or two measure options that are different, with an extra one or two options for the meter (depending on its complexity).

You may want to start with something easy with this, to fully grasp the technique. Ideally, of course, the thing should be applied right from the start, to save you the time and effort to "rethink" the approach, but then, I didn't do it from the start either, LOL. I was literally creating hundreds of measures and meters in some cases, until it struck me that I could make it all much more compact. Once I completed my first skin using this approach though, applying the method to the others became much easier. The particularities of my skins made this even more logical, since I extensively use mouse scrolling to "walk through" the indexes or instances of a given measurement.

Lastly, this method has another benefit: you don't necessarily have to know the exact value of the last valid index, you only need to know the absolute maximum and "blank" the "out of bounds" measurements or texts. This is trickier to do for WebParser though, since a dynamic change of a child index requires a full update of the parent using the [!CommandMeasure WebParserParentMeasure "Update"] bang (which is why my Weather skin is still the biggest in my suite because of using the "classic" WebParser parent-children approach), but even there, if really needed, using String measures instead of WebParser children (like we discussed in another topic) is a valid workaround.
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth
MattNY177
Posts: 28
Joined: December 3rd, 2018, 1:15 am

Re: Best way to use MeasureNames efficiently for a skin with lots of string meters?

Post by MattNY177 »

Yincognito wrote: March 27th, 2019, 11:07 pm I went down the road you have, and the best way to handle this is stop creating hundreds of measures/meters, and just reuse a single one (or a couple of them).
Hey, I appreciate the reply and thanks for the insight. Unfortunately this doesn't work for me, because in my case each meter represents a different visual element, some or all of which may appear on screen simultaneously.

Think of each meter as a live tile in the Windows 10 start menu. Some can be modified manually with user input, others pull live data from dynamic URLs, etc. Each of these "parents" have multiple child components grouped together with a unique Group ID, and each child has multiple measures used to calculate their respective values.

Now, say I have 50 of these tiles, and I want to add 50 more. Each of them is unique in their visual appearance, data source, update rate, etc. But the overall structure of Meter(Parent) --> Meters(Children) --> Measures(WebParser/String/Calc/Plugin) is constant. For example:

METERS

Code: Select all

[Tile001] <-- Container (Parent)
  Hidden=#CURRENTSECTION#_isVisible
  
[Tile001_Background] <-- Shape/Image (Child)
  SolidColor=#CURRENTSECTION#_color
  Group=Tile001
[Tile001_Name] <-- String (Child)
  Measure=#CURRENTSECTION#_string
  Group=Tile001  
[Tile001_Thumbnail] <-- Image (Child)
  Measure=#CURRENTSECTION#_image
  Group=Tile001  
MEASURES

Code: Select all

[Variables]
  Tile001_isVisible=#SOMECALC#
  Tile001_Background_color=#SOMEOTHERCALC#
[Tile001_Name_string]
  Measure=Quote
[Tile001_Thumbnail_image]
  Measure=WebParser
Essentially I'm trying to find a way to copy/paste as little code as possible to create each new (100+) tiles. This is a good start because I can simply increment the Tile### and add whatever changes I need from there.

Where this runs into problems is when I need to have one Child reference another Child within the same Parent, since it can't use the #CURRENTSECTION# variable to do so. For example, what if I want to set the Thumbnail meter's SolidColor value to equal the chosen Background color?

Unless maybe there was some way to only reference the first 7 characters of the #CURRENTSECTION# variable? That would make cross-referencing between Children a lot easier.
User avatar
Yincognito
Rainmeter Sage
Posts: 7025
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: Best way to use MeasureNames efficiently for a skin with lots of string meters?

Post by Yincognito »

MattNY177 wrote: April 1st, 2019, 2:09 pmHey, I appreciate the reply and thanks for the insight. Unfortunately this doesn't work for me, because in my case each meter represents a different visual element, some or all of which may appear on screen simultaneously.
Well, that's why I said that sometimes such tricks are just not possible, as you'd want to get all things in one big measurement/parse because maybe you need all the values to calculate something else (or, in your case, to display them all simultaneously).
MattNY177 wrote: April 1st, 2019, 2:09 pmWhere this runs into problems is when I need to have one Child reference another Child within the same Parent, since it can't use the #CURRENTSECTION# variable to do so. For example, what if I want to set the Thumbnail meter's SolidColor value to equal the chosen Background color?

Unless maybe there was some way to only reference the first 7 characters of the #CURRENTSECTION# variable? That would make cross-referencing between Children a lot easier.
There are multiple solutions for this:
- set your variable names independently of the section names, or rather call those variables independently (e.g. you could have a variable named Tile001_Background_color, just don't use it as #CURRENTSECTION#_color, but literally, as Tile001_Background_color, in every place you might need it)
- pass the #CURRENTSECTION# you're working with to a String measure, where you can regex substitute it to its first 7 characters, and then use that measure name instead of #CURRENTSECTION# when "calling" it (pay attention to potentially escaping that measure name, if and when needed, and also make sure you correctly get the section name by either placing the String measure before the measures using it or updating it with a bang if possible)
- "modularize" the variables used when "calling" another variable (e.g. set variables like #ParentID#=Tile001 and #ChildID#=Background instead of #CURRENTSECTION#, then you could do a SolidColor=#ParentID#_#ChildID# when "calling"/actually using them)
- use the #CURRENTSECTION# value of the parent instead, as that is already set to the first 7 characters that you want, e.g. Tile001 (of course, that should be done inside the parent measure, for example you could attach an OnUpdateAction=[!SetVariable ParentName "#CURRENTSECTION#"] at the end of [Tile001], then use #ParentName# in its "children" - but pay attention that the parent has to update for the value of #ParentName# to change)
- another version of the above is to set the color from the parent, using a bang, like OnUpdateAction=[!SetOption Tile001_Thumbnail SolidColor #CURRENTSECTION#_Background_color] (this also needs the parent to update, of course)

So yeah, it can be done. It depends on you if you think it's worth the effort to change your current approach, or which one of the solutions you think it's more appropriate/easier to use in your case. None of them is complicated, but they all require a bit of attention to properly set values right whenever you deal with a particular set of parent-children pair (basically, don't forget to update things if needed).

Other than than, like I said, the regex Replace in Notepad++ does wonders when you have lots of related things to be modified (assuming you properly select the text and perform the replacement in the selection, of course).
Last edited by Yincognito on April 1st, 2019, 7:18 pm, edited 2 times in total.
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth
User avatar
balala
Rainmeter Sage
Posts: 16110
Joined: October 11th, 2010, 6:27 pm
Location: Gheorgheni, Romania

Re: Best way to use MeasureNames efficiently for a skin with lots of string meters?

Post by balala »

MattNY177 wrote: April 1st, 2019, 2:09 pm Unless maybe there was some way to only reference the first 7 characters of the #CURRENTSECTION# variable?
No, there is not. #CURRENTSECTION# refers always to the whole name of the section (no matter if that's a measure or meter).
User avatar
Yincognito
Rainmeter Sage
Posts: 7025
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: Best way to use MeasureNames efficiently for a skin with lots of string meters?

Post by Yincognito »

balala wrote: April 1st, 2019, 7:13 pm No, there is not. #CURRENTSECTION# refers always to the whole name of the section (no matter if that's a measure or meter).
Agreed, but this doesn't invalidate the possible solutions that I mentioned above. Right?
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth
User avatar
balala
Rainmeter Sage
Posts: 16110
Joined: October 11th, 2010, 6:27 pm
Location: Gheorgheni, Romania

Re: Best way to use MeasureNames efficiently for a skin with lots of string meters?

Post by balala »

Yincognito wrote: April 1st, 2019, 7:22 pm Agreed, but this doesn't invalidate the possible solutions that I mentioned above. Right?
No, probably not (if MattNY177 will be able to follow what you've described there).