It is currently March 28th, 2024, 9:51 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

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

Post by MattNY177 »

Yincognito wrote: April 1st, 2019, 6:57 pm 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).
Thanks for these suggestions, I will certainly experiment with some of them and see what can be done. I know I can always fall back to regex replacements, but my goal is to make it as user friendly as possible (i.e. lots of $UserInput$ measures and less manual code editing) since I'd like to eventually be able to share it with others who are not as tech savvy.

One question regarding OnUpdateAction for meters... say I was to add that line OnUpdateAction=[!SetVariable ParentName "#CURRENTSECTION#"] to each parent meter, then change the children to reference that variable instead of #CURRENTSECTION# when calling their individual options. When the skin is refreshed, will all of the calculations be executed in the proper order?

For example, Tile001 sets #ParentName# to "Tile001"... then each Tile001 child meter assigns values based on that #ParentName#... then Tile002 changes the value to "Tile002" and so on. Will each child meter update in the correct order before the next parent tile changes the #ParentName# value?
User avatar
Yincognito
Rainmeter Sage
Posts: 7029
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 3rd, 2019, 12:06 amI know I can always fall back to regex replacements, but my goal is to make it as user friendly as possible (i.e. lots of $UserInput$ measures and less manual code editing) since I'd like to eventually be able to share it with others who are not as tech savvy.
I don't know the specifics of your skin, but regex replacements shouldn't negatively interfere with the $UserInput$ measures, assuming you have the appropriate order of measures/meters in your skin. After all, the regex replacements will, in this case, act on the names of the variables that you use, while $UserInput$ will generally act on their values, so, in theory, they shouldn't be in a conflict. By the way, I'm talking about regex substitutions here, not regex replacements in Notepad++ (where you are right in what you said).
MattNY177 wrote: April 3rd, 2019, 12:06 amOne question regarding OnUpdateAction for meters... say I was to add that line OnUpdateAction=[!SetVariable ParentName "#CURRENTSECTION#"] to each parent meter, then change the children to reference that variable instead of #CURRENTSECTION# when calling their individual options. When the skin is refreshed, will all of the calculations be executed in the proper order?

For example, Tile001 sets #ParentName# to "Tile001"... then each Tile001 child meter assigns values based on that #ParentName#... then Tile002 changes the value to "Tile002" and so on. Will each child meter update in the correct order before the next parent tile changes the #ParentName# value?
Again, I don't know the specifics, but if you have them in the correct order for the things you want to accomplish, there shouldn't be a problem. For example, if you have:

Code: Select all

[Tile001]
...
[Tile001_Child001]
...
[Tile001_Child002]
...
[Tile001_Child003]
...
[Tile002]
...
[Tile002_Child001]
...
[Tile002_Child002]
...
[Tile002_Child003]
...
then everything will work just fine, assuming you update each parent before updating its children.
However, if you have something like:

Code: Select all

[Tile001]
...
[Tile001_Child001]
...
[Tile001_Child002]
...
[Tile002]
...
[Tile002_Child001]
...
[Tile002_Child002]
...
[Tile002_Child003]
...
[Tile001_Child003]
...
meaning that [Tile002]'s stuff is "intertwined" among [Tile001]'s stuff, then you'll have problems, since [Tile001_Child003] will use [Tile002]'s (and not the correct [Tile001]'s) #ParentName#, simply because [Tile002] was the last updated parent.

Of course, the order I was talking above must be consistent with what you want to achieve in the skin. No point in putting them in this order if a calculation you make or anything else you might need the skin to do requires a different order.

NOTE: Setting things directly using bangs from the parents (like the OnUpdateAction=[!SetOption Tile001_Thumbnail SolidColor #CURRENTSECTION#_Background_color] bang I mentioned as the last solution) doesn't require such a specific order, since it acts directly on those particular children, wherever they are in the code - it only requires that each parent is updated before its children (of course, you'd have very long bang rows for hundreds of children, but that's another story). That's why I said you'd have to choose the solution that is the most suitable for your case. The good thing is that you have alternatives.
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth
User avatar
Yincognito
Rainmeter Sage
Posts: 7029
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 »

Another solution for this:
- use multiple parent names, one for each parent, like OnUpdateAction=[!SetVariable ParentName001 "#CURRENTSECTION#"] in [Tile001], OnUpdateAction=[!SetVariable ParentName002 "#CURRENTSECTION#"] in [Tile002], and so on, then using #ParentName001#, #ParentName002#, etc. This also doesn't require a specific order of your measures/meters where you do this (since they will be different variables), other than, as always, updating each parent before its children.
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: April 3rd, 2019, 3:47 pm Another solution for this:
- use multiple parent names, one for each parent, like OnUpdateAction=[!SetVariable ParentName001 "#CURRENTSECTION#"] in [Tile001], OnUpdateAction=[!SetVariable ParentName002 "#CURRENTSECTION#"] in [Tile002], and so on, then using #ParentName001#, #ParentName002#, etc. This also doesn't require a specific order of your measures/meters where you do this (since they will be different variables), other than, as always, updating each parent before its children.
Yes, I know I can always create new variable(s) for each new meter/value, but my goal is to be able to create any number of new tiles dynamically with as little effort/code as possible.

So just to clarify, assuming everything is in correct numerical order (with all parents above their children), what happens if some measures have not finished calculating their values when the time comes to update their meters via its parent's OnUpdateAction?
User avatar
Yincognito
Rainmeter Sage
Posts: 7029
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 3rd, 2019, 11:25 pmSo just to clarify, assuming everything is in correct numerical order (with all parents above their children), what happens if some measures have not finished calculating their values when the time comes to update their meters via its parent's OnUpdateAction?
My turn to clarify: I didn't say they have to be in the correct numerical order (e.g. Tile001, Tile002, etc.), I only said the children shouldn't be intertwined/mixed up between the parents, that's all. Basically, a parent should follow only after all the children of the previous parent have been written/exhausted before it. So, you can have Tile003 followed by all its children, then Tile001 followed by all its children (as long as they are followed by all their children before moving to the next parent).

I doubt the measures won't finish calculating before their asociated meters are displayed, since if you work with variables, they are resolved at the moment of usage, as far as I know. However, if the meters corresponding to those measures update before the measures finish getting the needed values (for example, if the meters update once a second and the measures only update once every two seconds), then the meters will use the last values of the associated measures in any action attached to the meters. In this case, speaking in general terms, it's better to instruct the meters to update from the associated measures using bangs, once the measures finish calculating, maybe even using UpdateDivider=-1 on the meter so that it will only update when triggered by the measure, if you think it's critical to do so. Setting DynamicVariables=1 on the measures/meters where you use section variables might also help to update stuff as soon as values change.

Just to be clear, if by any chance you're talking about WebParser measures (that don't get their values instantly, but only after parsing the associated URL), then it's better to perform the actions in the FinishAction of the WebParser parent measure, instead of performing them in the OnUpdateAction of the meter associated with that WebParser parent measure results.
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: April 4th, 2019, 1:38 am Just to be clear, if by any chance you're talking about WebParser measures (that don't get their values instantly, but only after parsing the associated URL), then it's better to perform the actions in the FinishAction of the WebParser parent measure, instead of performing them in the OnUpdateAction of the meter associated with that WebParser parent measure results.
Yes, this is exactly what I'm referring to. Say there's a measure that parses and downloads multiple large images from a dynamic URL to display in a photo slideshow. Now, let's say multiple Tiles use this measure by passing different URLs to gather those images.

For example, reloading the skin (or clicking a Refresh button) each slideshow tile would update the #ParentName# variable, then use !CommandMeasure to retrieve the latest images. The measure would reference the #ParentName#_URL to update the #ParentName#_slideshow meter(s) accordingly.

However, when the measure completes its parsing, if the #ParentName# has already been changed by subsequent tiles, there will be a mismatch when it goes to assign the values back to the meter. Is this assumption correct? If so, is there a better way to handle this process?
User avatar
Yincognito
Rainmeter Sage
Posts: 7029
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 5th, 2019, 12:37 am Yes, this is exactly what I'm referring to. Say there's a measure that parses and downloads multiple large images from a dynamic URL to display in a photo slideshow. Now, let's say multiple Tiles use this measure by passing different URLs to gather those images.

For example, reloading the skin (or clicking a Refresh button) each slideshow tile would update the #ParentName# variable, then use !CommandMeasure to retrieve the latest images. The measure would reference the #ParentName#_URL to update the #ParentName#_slideshow meter(s) accordingly.

However, when the measure completes its parsing, if the #ParentName# has already been changed by subsequent tiles, there will be a mismatch when it goes to assign the values back to the meter. Is this assumption correct? If so, is there a better way to handle this process?
I see what you mean. Yes, there will be a mismatch, but only if you update multiple tiles at once. If you update them synchronously/sequentially (meaning the next tile or meter is updated only after the previous one completed its update), then I think it will solve the issue. I don't know if this suits your case, since they're large images and it would take a little bit to finish the process for each one of them, but if you use a single WebParser measure dynamically to achieve this, then going sequentially about it might be one of the few solutions available (apart from using multiple #ParentNameNNN# variables or multiple WebParser measures along with their associated measures and meters).

Incidentally, I had a similar issue to yours in my Feeds skin, where I use a single WebParser measure to get a theoretically unlimited number of feeds and aggregate them to present them to the user, ticker style. I don't know if the way I approached this is of any help to you or if it suits exactly to your case, but what I did was create a "loop" of:
1. "update" the URL (if the URL was empty, exit the "loop", if not !CommandMeasure the WebParser in step 2. using the updated URL)
2. use it to get the data in the WebParser measure
3. parse the data, process it and add it to the aggregator
4. go back to step 1. until the URLs were exhausted (i.e. encountered an "empty" URL)
This could be adapted to your workflow like this (if I correctly understood your process, that is):
1. slideshow tile 001 updates the #ParentName# variable (if the tile number is "out of bounds", exit the "loop", if not !CommandMeasure to 2.)
2. use #ParentName#_URL to get the data in the WebParser measure
3. update the #ParentName#_slideshow meter corresponding (or equal to) tile 001 with the corresponding image
4. go back to step 1. but for the next slideshow tile (i.e. tile 002, in this case), until the tile number is "out of bounds", aka the last one

So basically, you'd update tiles one by one, in the FinishAction of the WebParser measure, taking care to "move" to the next tile after updating the current one, also in the FinishAction of the WebParser. Of course, you should be careful not to create an "infinite loop", since at 1. you trigger the WebParser and at 4. you go back at 1. with a new value, from inside the WebParser's FinishAction.

This is something a bit tricky to properly explain in words, so if you think this can be applied in your case and want to see exactly how I did it, I could link to my skin suite to have a "sample framework" that you can adapt to your needs.
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: April 5th, 2019, 2:00 am This is something a bit tricky to properly explain in words, so if you think this can be applied in your case and want to see exactly how I did it, I could link to my skin suite to have a "sample framework" that you can adapt to your needs.
Thanks again for the feedback, and sure I could check out your skin as a frame of reference.

After some consideration, I don't think I want to make each Tile wait until the previous one is done loading since that adds a lot of unnecessary time to each update. Therefore I think I've narrowed it down to two possible solutions, one which you suggested and another I just thought of after reading your last post:

1. As per your suggestion, I could use multiple WebParser measures instead of a single measure for each Tile that requires downloading multiple files or other complex function that takes time to complete. The only problem is figuring out how many to create in advance, without knowing how many tiles will actually need to use them in the future.

2. What if instead of using the #ParentName# variable directly in the measure, an extra step was added to assign the #ParentName# to a #TempName# variable at the time the !CommandMeasure action is run? Then the measure could reference the #TempName# variable for all of its calculations, which would not change and therefore return the correct Tile### when assigning values back to the meter, correct?

This brings up another question though, what happens when two separate !CommandMeasure actions are sent to the same measure? Does the measure wait to finish the first command cycle before starting the second one (i.e. consecutively)? Or are they run as two separate instances of the same measure (i.e. concurrently)?
User avatar
Yincognito
Rainmeter Sage
Posts: 7029
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 5th, 2019, 5:03 am1. As per your suggestion, I could use multiple WebParser measures instead of a single measure for each Tile that requires downloading multiple files or other complex function that takes time to complete. The only problem is figuring out how many to create in advance, without knowing how many tiles will actually need to use them in the future.
Which is precisely why reusing a single WebParser is useful, like I said in my first reply in this topic. Of course, creating more WebParser measures than necessary isn't a problem, only creating less than necessary. Logically though, you should have a "limit" to the number of tiles too, so if you correlate those maximums with one another, this would be a valid solution.
MattNY177 wrote: April 5th, 2019, 5:03 am2. What if instead of using the #ParentName# variable directly in the measure, an extra step was added to assign the #ParentName# to a #TempName# variable at the time the !CommandMeasure action is run? Then the measure could reference the #TempName# variable for all of its calculations, which would not change and therefore return the correct Tile### when assigning values back to the meter, correct?

This brings up another question though, what happens when two separate !CommandMeasure actions are sent to the same measure? Does the measure wait to finish the first command cycle before starting the second one (i.e. consecutively)? Or are they run as two separate instances of the same measure (i.e. concurrently)?
You'd have to try and see if 2. works out for you, although I see no reason why it wouldn't, if made properly and my understanding of the process is correct. I don't quite understand why you'd !CommandMeasure a single WebParser measure twice though - isn't simpler and more logical to wait the first parsing to complete before you get to the next one, like I explained before (if you're using a single WebParser, that is)? Anyway, although I didn't test it myself, I'm pretty sure sending a second !CommandMeasure before the first had the time to complete would override the first and start the second right away, effectively cancelling the first.
MattNY177 wrote: April 5th, 2019, 5:03 amThanks again for the feedback, and sure I could check out your skin as a frame of reference.
I think it's better to present you a cropped and simplified version of the measures involved in that "loop" - you'd probably find it easier to understand:

Code: Select all

[Variables]
FeedURLMaxIndex=0
FeedURLIndex=-1
Feed="<(?:channel|feed)(?:\s.*)?>.*</(?:channel|feed)>"

---Measures Rainmeter---

[MS_WebParser_ResetIndexes]
Measure=Calc
UpdateDivider=(#DetectionUpdateDivider#*#UpdateInterval#/#FeedSlidingUpdate#)
OnUpdateAction=[!SetOption MS_Rainmeter_FeedAggregator String ""][!SetVariable FeedURLMaxIndex 0][!SetVariable FeedURLIndex -1]
DynamicVariables=1

[MS_Rainmeter_FeedAggregator]
Group=FeedDerivativeGroup
Measure=String
String=
UpdateDivider=(#DetectionUpdateDivider#*#UpdateInterval#/#FeedSlidingUpdate#)
OnUpdateAction=[!SetVariable FeedURLIndex (#FeedURLIndex#+1)]
DynamicVariables=1

[MS_Rainmeter_FeedURL]
Group=FeedDerivativeGroup
Measure=String
String="#FeedURLs#"
UpdateDivider=(#DetectionUpdateDivider#*#UpdateInterval#/#FeedSlidingUpdate#)
RegExpSubstitute=1
Substitute=" ":"","^(.*)$":"\1,",",+":",","^,":"","(?siU)^(?:.*,){0,#FeedURLIndex#}+(.*?)$":"\1","(?siU)(?<=,).*?":"","(?:^\\1|\\2$)":"",",$":"","^.*,.*$":""
IfMatch=^.{1,}$
IfMatchAction=[!SetOption MS_WebParser_Feeds Url "[MS_Rainmeter_FeedURL]"][!CommandMeasure MS_WebParser_Feeds "Update"]
IfNotMatchAction=[!SetVariable FeedURLMaxIndex (#FeedURLIndex#)][!SetVariable FeedURLIndex 0][...][!CommandMeasure MS_WebParser_Feeds "Reset"]
IfMatchMode=1
DynamicVariables=1

---Measures WebParser---

[MS_WebParser_Feeds]
Measure=WebParser
RegExp="(?siU)(#Feed#)"
UpdateRate=(#DetectionUpdateDivider#*#UpdateInterval#/#FeedSlidingUpdate#)
FinishAction=[!UpdateMeasureGroup "FeedGroup"][!UpdateMeasureGroup "FeedDerivativeGroup"]
OnConnectErrorAction=[!UpdateMeasureGroup "FeedGroup"][!UpdateMeasureGroup "FeedDerivativeGroup"]
OnRegExpErrorAction=[!UpdateMeasureGroup "FeedGroup"][!UpdateMeasureGroup "FeedDerivativeGroup"]
DynamicVariables=1

[MS_WebParser_Feed]
Group=FeedGroup
Measure=WebParser
Url=[MS_WebParser_Feeds]
StringIndex=1
UpdateDivider=-1
OnUpdateAction=[!SetOption MS_Rainmeter_FeedAggregator String "[MS_Rainmeter_FeedAggregator][MS_WebParser_Feed]"]
DynamicVariables=1
[MS_WebParser_ResetIndexes] is not technically involved in the loop, but it updates right before the loop measures do in order to reset the indexes I work with and clear the aggregator (the equivalent of a skin refresh for the variables involved, that is). Other than that, [MS_Rainmeter_FeedURL] gets the "next" URL from a comma separated list of URLs (the [...] part in the IfNotMatchAction is where I update meters, because I do this after iterating through all the URLs - but you can do it in the OnUpdateAction of [MS_WebParser_Feed] or in the FinishAction of the measure that gets the image, right before moving to the next tile, aka incrementing the index). As you can see, the code for the process is relatively simple and short.

And the link is here (the Feeds skin).
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 »

Thanks, I'll test it out and see if I can adapt it somehow.
Yincognito wrote: April 5th, 2019, 6:24 am I don't quite understand why you'd !CommandMeasure a single WebParser measure twice though - isn't simpler and more logical to wait the first parsing to complete before you get to the next one, like I explained before (if you're using a single WebParser, that is)? Anyway, although I didn't test it myself, I'm pretty sure sending a second !CommandMeasure before the first had the time to complete would override the first and start the second right away, effectively cancelling the first.
This is based on your original suggestion to add OnUpdateAction=[!SetVariable #ParentName# #CURRENTSECTION#] to all parent Tiles, then OnUpdateAction=[!CommandMeasure Measure_WebParser "Run"] to each child meter. The measure(s) would then use the #ParentName# variable to gather and return the relevant values to each respective child meter.

Using this method, every time the skin is loaded or refreshed, it would fire off dozens of !CommandMeasures in rapid succession with different #ParentName# values. The resulting actions would be something like this:
  • #ParentName# = Tile001
  • !CommandMeasure WebParser "Run"
  • #ParentName# = Tile002
  • !CommandMeasure WebParser "Run"
    ...
  • #ParentName# = Tile007
  • !CommandMeasure WebParser "Run"
    ... etc.
After assigning the #ParentName# to a #TempName# variable, the WebParser would have something like FinishAction=[!SetOption #TempName#_image1 ImageName [webparser_index1] ] to pass the value back to the meter.

In this scenario, doesn't it seem like there would be many overlapping commands being sent to each measure? If what you say is true, then only the last command would actually resolve rendering all the previous ones cancelled before completion, is that correct?

If so, it sounds like the only solution is to create multiple measures to perform the same function (#1 above). I just want to clarify this is the case before I pursue that option.