It is currently May 26th, 2020, 8:31 pm

[Suggestion] Enhancements to Include

Report bugs with the Rainmeter application and suggest features.
buckb
Posts: 34
Joined: February 12th, 2018, 12:47 am

[Suggestion] Enhancements to Include

Post by buckb »

A couple of suggestions to kick around.

Include with Substitution

Rainmeter skins often have repeated sections of code corresponding to repeated instances of a given object. A "Disk Drive" skin will have one or more instances of a disk drive, while a "Stock Quote" skin will have one or more instances of a stock quote. Using the stock quote skin as an example, a skin I have developed has a series of measures and meters that looks something like this:

Code: Select all

[measureNameStock1]
...
[measurePriceStock1]
...
[measureChangeStock1]
...

[meterNameStock1]
...
[meterPriceStock1]
...
[meterChangeStock1]
...
This set of measures and meters is then repeated for Stock2, Stock3, etc. Making a change to these stock objects requires repeated edits to each of the objects individually. To ease development and maintenance, I split these groupings of measures and meters into a series of includes:

Code: Select all

@IncludeS1=stock1.inc
@IncludeS2=stock2.inc
@IncludeS3=stock3.inc
Further, I code each of these includes to be identical, except for an instance number. I then automatically generate them. I start with a "master" include that looks like this:

Code: Select all

[measureNameStock$num$]
...
[measurePriceStock$num$]
...
[measureChangeStock$num$]
...

[meterNameStock$num$]
...
[meterPriceStock$num$]
...
[meterChangeStock$num$]
...
I then run a small cmd/vbscript that makes copies of the master include, and substitutes occurances of "$num$" with "1", "2", "3", etc. So when a change to the stock measures or meters is needed, I just change the master include, then regenerate the individual includes.

It occured to me that the use of a master include could be formalized with an enhancement to the Include syntax. For example, since Rainmeter already has a "Substitute" capability, we might have:

Code: Select all

@IncludeS1=stock.inc Substitute="$num$":"1"
@IncludeS2=stock.inc Substitute="$num$":"2"
@IncludeS3=stock.inc Substitute="$num$":"3"

Conditional Include

A common feature of skins that make use of repeated measures and meters is the need to conditionally enable or disable them. For example, if the stock skin discussed above can support 9 stocks, but a given user only wants to display 3 stocks, a common technique seems to be to code for 9 stocks, then selectively disable or hide their measures and meters.

For a skin that changes the number of display objects dynamically, disable/hide seems like the way to go. But for other skins, a conditional include mechanism could simplify the code by dispensing with the disables/hides:

Code: Select all

[Variables]
stockCount=3
symbol1=AAPL
symbol2=GOOG
symbol3=MSFT

...

@IncludeS1=stock.inc IncludeIf=(#stockCount# >= 1) Substitute="$num$":"1"
@IncludeS2=stock.inc IncludeIf=(#stockCount# >= 2) Substitute="$num$":"2"
@IncludeS3=stock.inc IncludeIf=(#stockCount# >= 3) Substitute="$num$":"3"
@IncludeS4=stock.inc IncludeIf=(#stockCount# >= 4) Substitute="$num$":"4"
@IncludeS5=stock.inc IncludeIf=(#stockCount# >= 5) Substitute="$num$":"5"
@IncludeS6=stock.inc IncludeIf=(#stockCount# >= 6) Substitute="$num$":"6"
@IncludeS7=stock.inc IncludeIf=(#stockCount# >= 7) Substitute="$num$":"7"
@IncludeS8=stock.inc IncludeIf=(#stockCount# >= 8) Substitute="$num$":"8"
@IncludeS9=stock.inc IncludeIf=(#stockCount# >= 9) Substitute="$num$":"9"
I couldn't think of a good keyword, but you get the idea. Only the first three includes would actually be incorporated into the skin.


I am undecided about the sugguestions I have just made. I am wary of encumbering Rainmeter's syntax, and complex substitutions or overuse of includes could make understanding a skin much more difficult. For now, I lean toward suggesting the include enhancements described here. I'd be curious to know if other skin developers have found alternate solutions to the issues I have discussed.


--buckb
element
Posts: 25
Joined: April 24th, 2019, 1:29 am

Re: [Suggestion] Enhancements to Include

Post by element »

With regards to the above post, and also this thread:
https://forum.rainmeter.net/viewtopic.php?f=128&t=28455&p=148654#p148654

While copying several nearly-identical code sections for the 5 forecast days in the sample skin for the WeatherHub plugin, I thought that Rainmeter could use a simple "for" loop construct. This loop would iterate through an enclosed chunk of code, each time incrementing an iteration variable, and create the requested sets of measures. From this point on, all these measures would exist as if they had been written out verbatim, one-by-one, in the code. Below is a simplified example of what I mean (derived from that WeatherHub skin). This example would create 5 sets of labels, icons, temps, etc (one set for each forecast day) and place them all where they belong, without repeating any code.

#ITER# is the iterated variable increasing from 0 to 4, I capitalized #ITER# it to make it more distinct

Code: Select all

For 0..4

[mF#ITER#DayLabel]
Meter=String
X=(#sideL#+(#ITER#+0.5)*#forWid#)
Text=[&msWeatherHub:GetData("#feed#","(f#ITER#_dayW)")]
DynamicVariables=1

[mf#ITER#Icon]
Meter=Image
X=(#sideL#+(#ITER#+0.5)*#forWid#-#iconWid#/2)
ImageName=[&msWeatherHub:GetData("#feed#","(f#ITER#_iconL)")]
DynamicVariables=1

etc ...

End
Image
User avatar
jsmorley
Developer
Posts: 20637
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: [Suggestion] Enhancements to Include

Post by jsmorley »

It's just not how Rainmeter is engineered. Rainmeter is not a procedural programming language. There is only one "loop", the Update cycle. It's very simple. Inside the loop it pretty much just executes each Measure in turn, then updates each Meter in turn, then redraws the skin window.

So while I understand the charm of this, it's just not going to happen.

I could envision some external 3rd-party utility that offers some help of this type with "writing" skin files. Some tool that let's you create measures or meters that include some kind of "template" functionality, and when run the tool it would spit out a .ini file that automatically does all the duplication of the measures or meters for you. I'm not quite sure what this would look like, as it would need to be simple enough to use that it would be more attractive than just doing the relatively easy (If boring) copy and paste in a text editor. I'm a bit skeptical that it could gain any popularity, but you never know.

However, at the end of the day, a skin is a skin. We are just not going to go down the road of changing the architecture of Rainmeter, as that is a slippery-slope to a dark place.
User avatar
Yincognito
Posts: 1626
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [Suggestion] Enhancements to Include

Post by Yincognito »

buckb wrote:
May 7th, 2018, 9:22 pm
I then run a small cmd/vbscript that makes copies of the master include, and substitutes occurances of "$num$" with "1", "2", "3", etc. So when a change to the stock measures or meters is needed, I just change the master include, then regenerate the individual includes.
You probably know you can do this in Rainmeter as well, by using a "counter" measure that incremements itself, and then execute one or more !WriteKeyValue bangs to the .inc files on every update of the measure, taking care to either disable the measure once you reach the maximum "$num$" or execute the bangs in an IfCondition, instead of an OnUpdate. When finished, you can refresh the skin so that the includes are "up to date" for usage.

That being said, if you only display one "stock quote" / "disk drive" information at a time (as oposed to all of them at once), then you absolutely don't need to create hundreds of measures and meters for this. One set is enough, as you'd easily be able to use dynamic variables to "jump" to the previous / next set. Example: if I have a stock quote skin and I want to display the 5 stock quotes all at once, I'd have to create 5 times the number of measures / meters for this; however, if I want to display only 1 stock quote at a time and jump to the previous / next using, say, mouse scroll, then only one set of these measures / meters would be needed.

As for the conditional includes, disabling / hiding through bangs is not that much of an annoyance, but if you still want to avoid it, you could simply set Disabled=($num$>#stockCount#) and Hidden=($num$>#stockCount#) to all the measures / meters in your include files and be done with it. As soon as you modify the #stockCount# variable in your skin, the measures / meters whose "index" is greater than stockCount will automatically disable / hide themselves.
element
Posts: 25
Joined: April 24th, 2019, 1:29 am

Re: [Suggestion] Enhancements to Include

Post by element »

jsmorley wrote:
April 21st, 2020, 12:29 pm
Rainmeter is not a procedural programming language.
Nor am I proposing such a thing. The loop construct I suggested would be a simple parsing macro, like pre-processor directives in programming languages (#if DEBUG etc). They don't change how the compiler works. They modify the text presented to the compiler.
jsmorley wrote:
April 21st, 2020, 12:29 pm
There is only one "loop", the Update cycle
I'm not proposing any changes to Rainmeter's runtime. After creating the desired measures programmatically at parse time (as opposed to writing them all out manually), the macro has no bearing on Rainmeter's later runtime. A "for loop" is simply what I called it, it has nothing to do with any runtime loops. The macro could just as well be invoked with "Array 0..4" or "Set [0,4]" or "Copy 0 to 4" or any similar syntax
jsmorley wrote:
April 21st, 2020, 12:29 pm
Inside the loop it pretty much just executes each Measure in turn, then updates each Meter in turn, then redraws the skin window.
What prevents this mechanism from working with measures created programatically at parse time, as opposed to written out explictely as text by the user?
User avatar
Yincognito
Posts: 1626
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [Suggestion] Enhancements to Include

Post by Yincognito »

My impresion is that this would be a good place to use one or more Lua script measures, assuming Lua has the capabilities for it. Just saying...

That being said, I guess it's hard to maintain a balance between the relative simplicity of the Rainmeter's INI format (which already seems a bit complicated for the "regular" user) and the increased complexity of a procedural language (which, apart from requiring massive changes to Rainmeter, would be almost certainly a no-no for the said "regular" user). :confused:
element
Posts: 25
Joined: April 24th, 2019, 1:29 am

Re: [Suggestion] Enhancements to Include

Post by element »

Yincognito wrote:
April 21st, 2020, 7:09 pm
procedural language
Not what I proposed, nor did I use this phrase. The proper term for what I suggested is a preprocessing macro. Macros alter the input, they don't affect runtime behavior.

https://en.wikipedia.org/wiki/Macro_(computer_science)
Yincognito wrote:
April 21st, 2020, 7:09 pm
a no-no for the said "regular" user)
Nothing in what I proposed affects the "regular" users, because they're free to copy/paste repetitive code by hand, as before. The fact that beginners do it this way shouldn't prevent power users from doing things more efficiently. These approaches are not mutually exclusive.
Yincognito wrote:
April 21st, 2020, 7:09 pm
apart from requiring massive changes to Rainmeter
Not even remotely "massive". It took me a few hours to hack together my own version of Rainmeter which does this. Below is my WeatherHub skin with 5 forecast days. Left: forecast days defined explictly. Right: forecast days generated programmatically from "template" elements (no repetition in code). Both skins look identical. The .ini size dropped from 14K to 7K, the code looks much cleaner. The drop in size in this case isn't that dramatic since ~40% of the skin is non-repetitive code (current conditions)

Image

Here's a ridiculous 64-bar spectrum analyzer generated from a single template AudioLevel band and a single template bar meter (18 lines of code for both templates). Changes to templates propagate everywhere. 64 bars is just a ridiculous test, I actually use 14 bars.

Image
User avatar
Yincognito
Posts: 1626
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [Suggestion] Enhancements to Include

Post by Yincognito »

element wrote:
April 23rd, 2020, 4:16 am
Not what I proposed, nor did I use this phrase. The proper term for what I suggested is a preprocessing macro. Macros alter the input, they don't affect runtime behavior.

https://en.wikipedia.org/wiki/Macro_(computer_science)


Nothing in what I proposed affects the "regular" users, because they're free to copy/paste repetitive code by hand, as before. The fact that beginners do it this way shouldn't prevent power users from doing things more efficiently. These approaches are not mutually exclusive.
I know and I agree with you on this, but I meant it more like a general remark (given the usual type of requests in this area), not necessarily specific to what you had in mind. That's why I physically (by placing it in a different paragraph) and semantically (by using "that being said" construct) separated the phrase in my post. Sorry I hadn't been more clear in this - my bad.
element wrote:
April 23rd, 2020, 4:16 am
Not even remotely "massive". It took me a few hours to hack together my own version of Rainmeter which does this. Below is my WeatherHub skin with 5 forecast days. Left: forecast days defined explictly. Right: forecast days generated programmatically from "template" elements (no repetition in code). Both skins look identical. The .ini size dropped from 14K to 7K, the code looks much cleaner. The drop in size in this case isn't that dramatic since ~40% of the skin is non-repetitive code (current conditions)

Image

Here's a ridiculous 64-bar spectrum analyzer generated from a single template AudioLevel band and a single template bar meter (18 lines of code for both templates). Changes to templates propagate everywhere. 64 bars is just a ridiculous test, I actually use 14 bars.

Image
Excellent - then why not "push" this as an update or whatever this is called on Rainmeter's GitHub page? Sure, it doesn't guarantee that it will be accepted and such, but in my view it's a step in the right direction - correct me if I'm wrong. :confused:
User avatar
Brian
Developer
Posts: 1994
Joined: November 24th, 2011, 1:42 am
Location: Utah

Re: [Suggestion] Enhancements to Include

Post by Brian »

Suggestions similar to this have come up several times in the past.
https://forum.rainmeter.net/viewtopic.php?f=14&t=30136#p155080
https://forum.rainmeter.net/viewtopic.php?f=27&t=31193&p=158492#p158410
https://github.com/rainmeter/rainmeter/issues/214
https://github.com/rainmeter/rainmeter/issues/84 (sort of)
(probably more out there...)

At the end of the day, while most of these suggestions have some charm for skin authors/users that have a programming background - they offer very little to the average user that has no programming background. Some of these suggestions even break ini formatting rules, which we attempt to follow.

When adding new features, we attempt to keep the structure and syntax consistent with the rest of Rainmeter. Every object in a skin is defined by a [section] name, and subsequent key=value pairs. Nothing exists outside of that. This makes it really easy for users at any level to understand, modify, add, remove, and debug objects as they see fit. I can only imagine the support nightmare of users saying "I get an error from section XXX, but I cannot find it in the skin file" type of messages.

Incorporating any "procedural" non-ini formatted syntax is just going to confuse the bulk of our users.

I don't think any of the developers are against some sort of "dynamically created objects" or "repeating section creation" per se, I just think we haven't seen any idea that an average user can follow easily. We have added some fairly complicated items over the years such as measures: FileView, ActionTimer, and Lua scripts - and Container/Contained meters. A lot of users, even very experienced users, avoid these features alot of the time.

I agree with what jsmorley said, this seems like a better fit for a 3rd-party program/script that can "create" repeated sections from some sort of template and write to a ini skin file.

-Brian
User avatar
Yincognito
Posts: 1626
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: [Suggestion] Enhancements to Include

Post by Yincognito »

Since we're at it, I'll add my (possibly, less "intrusive") bit to the repetition "issue" that this post (and probably others) refer to, given that it's a thing acknowledged by the devs. Why not allow some measure and meter options, similar to the Repeat parameter in ActionTimer and the @N notation, that handles this, like:

Code: Select all

[SomeMeasureOrMeter]
...regular measure or meter code...
Iterations = IterationStartNumber, IterationStep, IterationCount
IterationTarget = IterationVariable
...regular measure or meter code...
A simple usage scenario for this, in the case of a Calc measure:

Code: Select all

[ComputeSomething]
Measure=Calc
Formula=(#Number#)
Iterations=1,1,3
IterationTarget=Number
This would translate "internally" as:

Code: Select all

[ComputeSomething1]
Measure=Calc
Formula=1

[ComputeSomething2]
Measure=Calc
Formula=2

[ComputeSomething3]
Measure=Calc
Formula=3
When referring to the measures as section variables, the [ComputeSomething@N] notation would be used, like [ComputeSomething@1], [ComputeSomething@2] or [ComputeSomething@3], for example.

Anyway, as I said, personally I'm not particularly bothered by the repetition "issue" (probably because most of my skins generally avoid that, where they can), since it's not that hard to copy paste stuff in a text editor after all - just thought of contributing with an "alternative way" of doing this. I'm sure this isn't perfect and that is probably similar to what element suggested in a way, but I'm well aware that such modifications might cause additional problems if not implemented carefully - that's why I mentioned the need to have a way of referring to those "duplicated" measures / meters as section variables.

EDIT: Huh. I was just speculating when mentioning that Lua can be used for such tasks, but apparently the script(s) are more or less available in one of the links posted by element...