It is currently July 18th, 2024, 10:29 pm

If / Then / Else with Conditional Operators in Rainmeter

Our most popular Tips and Tricks from the Rainmeter Team and others
User avatar
jsmorley
Developer
Posts: 22646
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

If / Then / Else with Conditional Operators in Rainmeter

Post by jsmorley »

One of the things folks run into when creating skins is that the IfActions functionality, while powerful, has some limitations.

Code: Select all

[MeasureCond]
Measure=Calc
Formula=50
IfAboveValue=50
IfAboveAction=[!SetOption MeterCond Text "I'm above 50"]
IfBelowValue=50
IfBelowAction=[!SetOption MeterCond Text "I'm below 50"]
IfEqualValue=50
IfEqualAction=[!SetOption MeterCond Text "I'm exactly 50"]
The limitation is that there can only be one of each of the three IfActions, (IFBelow, IfEqual, IfAbove) so it is not possible to say "if I am above 50 do A, if I am above 60 do B". Since there can only be one IfAboveValue option, the answer to this will have to be "A", even if the value being compared is 70.

The solution to this is to explore the use of conditional operations in a formula in Rainmeter. We will focus on using them in Calc measures for purposes of this guide.

The conditional operation in Rainmeter is a way to have a more complex "If / Then / ElseIf / Then / Else" comparison, allowing you to set the value of the measure based on a broad range of comparisons. You can then use IfActions on the measure to take actions, or Substitute to change the number value into some text you might use in a meter later.

The form of the conditional operation is condition ? expression if true : expression if false. When the "condition" is evaluated, it is either "true" or "false". When it is "true", the expression after the "?" is evaluated. If it is "false", the expression after the ":" is done. This is equivalent to a block like this in a programming language:

Code: Select all

 if (condition)
     then
       expr. if true
     else
       expr. if false
   end if


Let's start with a simple example:

Code: Select all

[Val]
Measure=Calc
Formula=50

[MeasureCond]
Measure=Calc
Formula=Val > 49 ? 1 : -1
[MeasureCond] will be 1

What this is doing is asking "is [Val] greater than 49?". If it is, the the condition is "true", and the value of this Calc measure is set to "1" (the "then" part of the formula). If it is not true, then the value is set to "-1" (the "else" part of the formula).

I'm just using a simple Calc measure [Val] to set a value we can use for our comparison. Normally you are going to be comparing with some measure that is returning some value based on a measurement.

It should be noted as we get started that there must always be all three parts of the formula. This whole thing is known in programming languages as a "Ternary Operation", which comes from the Latin for "three operations". You must always have an "if" a "then" and an "else" or an error will result.

Now this isn't much different than just using an IfAction right on the [Val] measure like "IfAboveValue=49", but I wanted to start simple and work up to more complex examples that go beyond what an IfAction is capable of.

You can use formulas in the condition part of the formula as well:

Code: Select all

[MeasureCond]
Measure=Calc
Formula=Val * 2 = 100 ? 1 : -1
With [Val] still set to 50, [MeasureCond] will be 1

You can use Section Variables as well. Just be sure to set DynamicVariables=1 on the measure to use the current value:

Code: Select all

[Val]
Measure=Calc
Formula=50

[Val2]
Measure=Calc
Formula=40

[MeasureCond]
Measure=Calc
Formula=Val > [Val2] ? 1 : -1
DynamicVariables=1
Since the value of [Val] is larger than the value of [Val2], [MeasureCond] will be 1

Or you can use formulas or Section Variables in the "then" or "else" parts as well:

Code: Select all

[MeasureCond]
Measure=Calc
Formula=Val > 50 ? 1 : [Val]
DynamicVariables=1
Since the value of [Val] is 50, the condition is "false" and [MeasureCond] is set to the value of [Val] instead of "1"

You can also use compound conditions using things like AND and OR.

Code: Select all

[Val]
Measure=Calc
Formula=50

[MeasureCond]
Measure=Calc
Formula=(Val > 49) && (Val < 60) ? 1 : -1

[MeasureCond2]
Measure=Calc
Formula=(Val = 50) || (Val = 100) ? 1 : -1
These are using the "logical AND" and "logical OR". Note that you must enclose the components of the condition in parentheses. In both cases, [MeasureCond] and [MeasureCond2], the result is "1"

We should stop for one second and touch on terminology.

(parentheses)
[brackets]
{braces}

Don't confuse parentheses with brackets or braces, or I will just send you to visit Grammar Girl ;-)

Ok, that should touch on most of the simple uses, things that you can also logically get to with IfActions in most cases. Now let's look at how we can use "nesting" of "If / Then / ElseIf / Then / Else" to get the full benefit of conditional operations.

Code: Select all

[Val]
Measure=Calc
Formula=50

[MeasureCond]
Measure=Calc
Formula=Val > 74 ? 4 : (Val > 49 ? 3 : (Val > 24 ? 2 : 1))
Let's look at what this is saying. It is in effect walking through a series of "If / Then" statements, stopping when the result is "true" and continuing to evaluate the next "Else" when the result is "false". At the very end is the last "Else", in this example : 1, which will be the value if the entire expression is never "true".

"Is Val greater than 74? No. Well then, is Val greater than 49? Yes!" So the value of [MeasureCond] will be "3".

Important Notes: You must use parentheses to "nest" the conditional operations within the whole of the expression. So each of the "If" conditions after the initial one would start with an open parentheses, and you would put as many end parentheses at the very end of the entire option as there are "If" conditions after the first one. Look carefully at the Formula above to see how this should be done. Also, there is a limit of 30 nested operations in a single formula in Rainmeter.

If the Formula was more complex, with more "ElseIf" comparisons, it might look like this:

Code: Select all

Formula=Val > 90 ? 9 : (Val > 80 ? 8 : (Val > 70 ? 7 : (Val > 60 ? 6 : (Val > 50 ? 5 : (Val > 40 ? 4 : (Val > 30 ? 3 : (Val > 20 ? 2 : (Val > 10 ? 1 : 0))))))))
Eight starting parentheses to begin each "If", and eight ending parentheses at the very end to "close" them all.

Using the result:

You can certainly directly use the value of [MeasureCond] (in our examples) directly as MeasureName in a meter or as a Section Variable in other measures or meters.

You can also use IfActions on the measure to take actions as long as the result lends itself to the limitations of IfActions:

Code: Select all

[Val]
Measure=Calc
Formula=50

[MeasureCond]
Measure=Calc
Formula=Val * 2 = 100 ? 1 : -1
IfEqualValue=1
IfEqualAction=[!SetOption MeterCond Text "I'm One"]
IfBelowValue=0
IfBelowAction=[!SetOption MeterCond Text "I'm Negative"]
Or use a Substitute to turn the numeric value into some text you can use in a meter:

Code: Select all

[Val]
Measure=Calc
Formula=50

[MeasureCond]
Measure=Calc
Formula=Val > 74 ? 4 : (Val > 49 ? 3 : (Val > 24 ? 2 : 1))
Substitute="4":"Last Quarter","3":"Third Quarter","2":"Second Quarter","1":"First Quarter"
Remember our example of the limitations of IfAction from the very beginning of this guide?

Code: Select all

[Val]
Measure=Calc
Formula=70
The limitation is that there can only be one of each of the three IfActions, (IFBelow, IfEqual, IfAbove) so it is not possible to say "if I am above 50 do A, if I am above 60 do B". Since there can only be one IfAboveValue option, the answer to this will have to be "A", even if the value being compared is 70.

Using a Calc measure with a nested conditional operation, we can in fact bend the IfAction to our will:

Code: Select all

[MeasureCond]
Measure=Calc
Formula=Val > 60 ? 2 : (Val > 50 ? 1 : -1)
IfEqualValue=1
IfEqualAction=[!SetOption MeterCond Text "I'm above 50"]
IfAboveValue=1
IfAboveAction=[!SetOption MeterCond Text "I'm above 60"]
IfBelowValue=0
IfBelowAction=[!SetOption MeterCond Text "I'm below 50"]
Extra credit:

I mentioned that I would be using Calc measures to demonstrate how conditional operations work, but it should be noted that they will work anywhere a formula is allowed!

Code: Select all

[MeterImage]
Meter=Image
W=10
H=10
SolidColor=0,0,0,255
X=(#SCREENAREAWIDTH# = 1680 ? 160 : (#SCREENAREAWIDTH# = 1280 ? 128 : 0))
Y=0
Just remember that outside of a Calc measure, formulas must be totally enclosed in starting and ending parentheses, aside from any you might need for "nesting".


Hope this is of some help with understanding this feature of Rainmeter.
User avatar
jumper77
Posts: 132
Joined: October 13th, 2016, 2:07 am

Re: If / Then / Else with Conditional Operators in Rainmeter

Post by jumper77 »

What a wealth of information!! These examples are great. Being new to Rainmeter, I have looked for a way to do all the things you presented. This will help a lot.

Thank you for this guide.
USING: Rainmeter 4.0 Beta Release
User avatar
Mor3bane
Posts: 943
Joined: May 7th, 2016, 7:32 am

Re: If / Then / Else with Conditional Operators in Rainmeter

Post by Mor3bane »

I Finally understand the nesting and the syntax for inline if then tests!

Thanks!
:17good
My DevArt Gallery

There are many ways to be different - there is only one way to be yourself - be amazing at it

The law of averages says what it means; even if you get everything right, you will get something wrong. Therefore; self managing error trapping initiates another set of averages - amongst the errors, some of them will not be errors, instead those instances will appear to be "luck". One cannot complain of the 'appearance' of 'infinite regress of causation', even if it does not have a predictable pattern, only that it requires luck to achieve.
RicardoTM
Posts: 295
Joined: December 28th, 2022, 9:30 pm
Location: México

Re: If / Then / Else with Conditional Operators in Rainmeter

Post by RicardoTM »

I got a question, I got a measure that measures the temperature of the GPU, then I got another measure that takes the temperature of the GPU measure and gives me a value between 0 and 16, that is taken into a meter that selects an image according to the value (0.png - 16.png) the problem is that sometimes that value can go over 16, so I want to condition it so the value never exceeds 16 and never goes below 0. But if it doesn't exceed 16 nor is below 0, then do nothing (leave the result of the formula alone).

I tried formula= (all my formula) < 0 ? 0 : (> 16 ? 16) but the value turns out to be either 0 or 16.. but never 1-2-3-4..etc.

How can I fix it? I want it to evaluate the formula and say, is it more than 16? No? Well, is it below 0? Noup? Well, I'll do nothing and I'll leave the result as is. E.g. 12.

Another question, I also want those numbers to be variable (so maybe I can use more images) so the variables would be MinValue=0 and MaxValue=16. The formula would look like this Formula= (all my formula) < #MinValue# ? #MinValue# : ( > #MaxValue# ? #MaxValue#). Is it possible?

Thank you, and Happy New Year!
User avatar
eclectic-tech
Rainmeter Sage
Posts: 5453
Joined: April 12th, 2012, 9:40 pm
Location: Cedar Point, Ohio, USA

Re: If / Then / Else with Conditional Operators in Rainmeter

Post by eclectic-tech »

RicardoTM wrote: January 2nd, 2023, 2:49 am I got a question, I got a measure that measures the temperature of the GPU, then I got another measure that takes the temperature of the GPU measure and gives me a value between 0 and 16, that is taken into a meter that selects an image according to the value (0.png - 16.png) the problem is that sometimes that value can go over 16, so I want to condition it so the value never exceeds 16 and never goes below 0. But if it doesn't exceed 16 nor is below 0, then do nothing (leave the result of the formula alone).

I tried formula= (all my formula) < 0 ? 0 : (> 16 ? 16) but the value turns out to be either 0 or 16.. but never 1-2-3-4..etc.

How can I fix it? I want it to evaluate the formula and say, is it more than 16? No? Well, is it below 0? Noup? Well, I'll do nothing and I'll leave the result as is. E.g. 12.

Another question, I also want those numbers to be variable (so maybe I can use more images) so the variables would be MinValue=0 and MaxValue=16. The formula would look like this Formula= (all my formula) < #MinValue# ? #MinValue# : ( > #MaxValue# ? #MaxValue#). Is it possible?

Thank you, and Happy New Year!
IfCondition is a better choice rather than using IfActions or Conditional statements. Those methods will work, but IfCondition is my preferred choice because it is more versatile.

However, for this case, I would be tempted to use the Clamp function in the Formula of your measure to restrict the result between 0 and 15.
From your earlier code:

Code: Select all

[MeasureGPUTempValueRaw]
Measure=Registry
RegHKey=HKEY_CURRENT_USER
RegKey=SOFTWARE\HWINFO64\VSB
RegValue=ValueRaw#GPUTempIndex#

[MeasureGPUTempValueOf15]
Measure=Calc
Formula=(Clamp(MeasureGPUTempValueRaw/(100/16)),0,15)
DynamicVariables=1
User avatar
SilverAzide
Rainmeter Sage
Posts: 2687
Joined: March 23rd, 2015, 5:26 pm

Re: If / Then / Else with Conditional Operators in Rainmeter

Post by SilverAzide »

RicardoTM wrote: January 2nd, 2023, 2:49 am I tried formula= (all my formula) < 0 ? 0 : (> 16 ? 16) but the value turns out to be either 0 or 16.. but never 1-2-3-4..etc.

How can I fix it?
Aside from Eclectic-Tech's very good advice, the reason your value is acting as it is, is because your syntax is invalid. Specifically, (> 16 ? 16) is a syntax error, and the entire expression is also invalid since it is missing a chunk of logic. You might want to read up on the ternary operator ("?"), and especially how to nest ternary expressions.

The correct syntax would be: Formula=((all my formula) < 0) ? 0 : ((all my formula) > 16 ? 16 : (all my formula)).
But... :vomit:

E-T's suggestion is much better: Formula=Clamp((all my formula),0,16)
Gadgets Wiki GitHub More Gadgets...
RicardoTM
Posts: 295
Joined: December 28th, 2022, 9:30 pm
Location: México

Re: If / Then / Else with Conditional Operators in Rainmeter

Post by RicardoTM »

Thank you guys!

SilverAzide wrote: January 2nd, 2023, 4:09 am
The correct syntax would be: Formula=((all my formula) < 0) ? 0 : ((all my formula) > 16 ? 16 : (all my formula)).
But... :vomit:

E-T's suggestion is much better: Formula=Clamp((all my formula),0,16)
Thank you! I went back and fixed it but the log threw [Stage]: Calc: Unmatched brackets, then I fixed it again and I ended up with
[Stage]: Calc: Invalid function parameter count.
So yeah, I went and tried Tech's way. I will check it out later and do some testing with it again though. I really want to understand it.
eclectic-tech wrote: January 2nd, 2023, 3:53 am IfCondition is a better choice rather than using IfActions or Conditional statements. Those methods will work.
Nice, I'll do some testing with IfCondition, IfActions and Conditional statements too.
eclectic-tech wrote: January 2nd, 2023, 3:53 am for this case, I would be tempted to use the Clamp function in the Formula of your measure to restrict the result between 0 and 15.
From your earlier code:

Code: Select all

[MeasureGPUTempValueRaw]
Measure=Registry
RegHKey=HKEY_CURRENT_USER
RegKey=SOFTWARE\HWINFO64\VSB
RegValue=ValueRaw#GPUTempIndex#

[MeasureGPUTempValueOf15]
Measure=Calc
Formula=(Clamp(MeasureGPUTempValueRaw/(100/16)),0,15)
DynamicVariables=1
Yeah, this worked like a charm, I played with it for a little while and I ended up with this:

Code: Select all

[MGPUTempVR]
Measure=Registry
RegHKey=HKEY_CURRENT_USER
RegKey=SOFTWARE\HWINFO64\VSB
RegValue=ValueRaw#GPUTempIndex#

[State]
Measure=Calc
Formula=Clamp((((((MGPUTempVR-#MinTemp#) /(#MaxTemp#-#MinTemp#))*#NStatesMax#))), #NStatesMin#, #NStatesMax#)
DynamicVariables=1
It gives me exactly all the control I want for this skin from the variables section, without needing to go back to check anything into the code if I want to make some changes. Thank you again Tech!