It is currently March 29th, 2024, 5:19 am

Creating a "counter" or "loop" in your code

Tips and Tricks from the Rainmeter Community
User avatar
jsmorley
Developer
Posts: 22628
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Creating a "counter" or "loop" in your code

Post by jsmorley »

One of the things that people often want to do is create a "loop" that counts up to a specific number, then starts over and repeats.

This is useful in any number of circumstances, like displaying a series of images, delaying some action for some number of skin updates, anything where you want to say "create a loop from 1 to XX".

In Rainmeter, this is done by using a mathematical formula, normally but not exclusively in a Calc measure. The formula will use the % modulo mathematical operator.

Modulus math can be complicated in its explanation, as it used different ways in different contexts, but in the sense that we use it in a counter in Rainmeter, it is really pretty simple.

The % modulo mathematical operator in Rainmeter simply means "the remainder" when two numbers are divided. For instance, 63 / 4 in long division is equal to 15 with a remainder of 3. (15 * 4 = 60 and 63 - 60 = 3) So 63 % 4 is equal to 3.

A counter in Rainmeter

To use it as a counter, we use the current value of the measure as the dividend, and the highest number we want to count to as the divisor. So it is [MeasureValue] / HighestValue.

When the skin is loaded or refreshed, the initial value of the measure will be 0.

[MeasureCounter]
Measure=Calc
Formula=(MeasureCounter % 10) + 1

The result on the first update is 0 / 10 which is equal to 0 with a remainder of 0. We add + 1 to that, and get 1.

On the second update, it is now 1 / 10 which is still 0, with a remainder of 1. We add + 1 to that, and it's now 2.

On the third update, it is now 2 / 10 which is still 0, with a remainder of 2. We add + 1 to that, and it's now 3.

....

On the tenth update, it is now 9 / 10 which is still 0, with a remainder of 9. We add + 1 to that, and it's now 10. The highest number we want to use.

On the next update, we are at 10, so we have 10 / 10, which is 1 with a remainder of 0, so we have "started over", and when we add + 1 to that we are back to 1.

It will just repeat that way, counting from 1 to whatever is after the % operator, forever.

An example

Let's assume we have 10 images, named MyImage1.png ... MyImage10.png in a folder called Images\ in our @Resources\ folder for our skin.

Code: Select all

[Rainmeter]
Update=1000

[Variables]
SecondsBetween=30

[MeasureCounter]
Measure=Calc
Formula=(MeasureCounter % 10) + 1
UpdateDivider=#SecondsBetween#

[MeterImage]
Meter=Image
ImagePath=#@#Images\
ImageName=MyImage[MeasureCounter].png
DynamicVariables=1
That will display the images, starting with MyImage1.png through MyImage10.png. It will then start over, and continue in that way.

You can control the speed of the change by simply setting UpdateDivider=XX (where XX is the number of seconds between changes, assuming that the setting of Update in [Rainmeter] is 1000).

More information

More details about how to use counters in Rainmeter can be found at Counters Guide.
User avatar
jsmorley
Developer
Posts: 22628
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Creating a "counter" or "loop" in your code

Post by jsmorley »

Additional credit

In the above explanation and example, we showed how to count from "1" to any number. That is probably the most common use of a counter in Rainmeter. However, it is certainly possible that you might want to count from "0" to some number instead.

In its most simple sense, this is really easy. Just change the formula up a bit:

Counting from "1"

Code: Select all

[Variables]
Highest=10

[MeasureCountFrom1]
Measure=Calc
Formula=(MeasureCountFrom1 % #Highest#) + 1
Counting from "0"

Code: Select all

[Variables]
Highest=10

[MeasureCountFrom0]
Measure=Calc
Formula=(MeasureCountFrom0 + 1) % (#Highest# + 1)
We use (#Highest# + 1) since it is really 11 numbers from 0 to 10, where when we count from 1 to 10 that is just 10 numbers.

While it may not be obvious, what this really does is count from "1" to #Highest# and then become "0" before starting over at "1". So really it is 1...2...3...4...5...6...7...8...9...10...0...1...

That should be all you need to do to count from "0" to any number, HOWEVER... This is one little "gotcha" we should show how to deal with.

You may have already noticed that the effect of this is that the count will start with "1" when the skin is first loaded or refreshed, then count to "10" and from then on count from "0" to "10". The problem is that the "0" is really at the end of the loop, not the beginning. That is transparent and not important, unless you really want the skin to start counting from "0" right out of the gate, when loaded or refreshed.

To accomplish that, you have to do a little trick to fool Rainmeter. Let's look at the code and then I will explain:

Code: Select all

[Variables]
Highest=10

[MeasureCountFrom0]
Measure=Calc
Formula=0
OnUpdateAction=[!SetOption MeasureCountFrom0 Formula "(MeasureCountFrom0 + 1) % (#Highest# + 1)"][!SetOption MeasureCountFrom0 OnUpdateAction ""]
What we are doing it setting the initial Formula to simply "0", so that is what is used by anything using the counter on the very first update. We are not incrementing the value with "+ 1", and simply "0" is used.

Then, on the next update, we change the Formula to our "counter" expression we used in [MeasureCountFrom0] earlier. Now, starting with the second update, it will count from 1 to 10 and then 0 as before. This will give us the behavior we want, starting from the time the skin is first loaded or refreshed. It is in a sense 0 for one update, then 1...2...3...4...5...6...7...8...9...10...0...1...

After we have changed the Formula, we simply use !SetOption to completely turn off that OnUpdateAction, as we don't need it anymore until the next time the skin is loaded or refreshed.

Full example

Code: Select all

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

[Variables]
Highest=10

[MeasureCountFrom1]
Measure=Calc
Formula=(MeasureCountFrom1 % #Highest#) + 1

[MeterCountFrom1]
Meter=String
MeasureName=MeasureCountFrom1
FontSize=13
FontColor=255,255,255,255
SolidColor=47,47,47,255
Padding=5,5,5,5
AntiAlias=1

[MeasureCountFrom0]
Measure=Calc
Formula=0
OnUpdateAction=[!SetOption MeasureCountFrom0 Formula "(MeasureCountFrom0 + 1) % (#Highest# + 1)"][!SetOption MeasureCountFrom0 OnUpdateAction ""]

[MeterCountFrom0]
Meter=String
MeasureName=MeasureCountFrom0
Y=2R
FontSize=13
FontColor=255,255,255,255
SolidColor=47,47,47,255
Padding=5,5,5,5
AntiAlias=1