It is currently May 17th, 2024, 1:28 am

Ending A Loop?

Get help with creating, editing & fixing problems with skins
Riving
Posts: 2
Joined: September 22nd, 2010, 9:32 am

Ending A Loop?

Post by Riving »

Hey everybody! This is my first post and I'm a newbie so please be nice if I ask a pretty stupid question, I'm assuming I will :D

I recently have gotten into Rainmeter and it is definitely an awesome tool. I have been experimenting with implementing animation into some of my skins, however I'm having some trouble with the converted gif files. I was able to get them running and they loop on a constant basis, however what I would like is to have them only activate when I hover over them or activate them manually, as well as have the animation stop once the process has finished, meaning once the animation runs through beginning to end I don't want it to loop over and over again.

I've been previously able to get hoverover, leaveaction, and clickactions all working fine but it seems to be different with a looping animation and would as it looks require a conditional operator (I'm guessing? :cry: )

Can anybody help me out with how my coding should look if I want my animation to stop once It gets to a certain frame as well as only activate once I hover over the skin?

Here's what my coding looks like so far (This is just my experimentation at work)(Anything I'm putting into quotes is just explanation of what I was trying to do in my coding)

[Rainmeter]
Author=Josh
Update=100

[BlankSquare]
(This was just to try and help out with the hoverover and leaveaction executes as this was how I got my other executes working how I wanted)
Meter=Image
SolidColor=0,100,0,255
W=150
H=150

[ImageMeter]
Meter=Image
ImageName=ImagesFrames\Frame[ImageNumberCalc].png
DynamicVariables=1

[ImageNumberCalc]
Measure=Calc
Formula=Counter%12 > 11 ? 1 : 2 (This is where I tried implementing my conditional operator although it doesn't work)
Substitute=".00000":""
IfAboveValue=1
IfAboveAction=ImageName=ImagesFrames\Frame11.png
(Frame11 is my last frame of the animation so I want it to stop here on this image with this image as the new permanent of the meter)
IfBelowValue=2
IfBelowValue=ImageName=ImagesFrames\Frame[ImageNumberCalc].png
(This is where I wanted my conditional operator to continue until the "abovevalue" is true)
DynamicVariables=1

Anyway this is what I have come up with so far although to no avail. Can anybody help me out here as to how the coding should actually look to get what I would like done? I would really appreciate it! Thanks!!

Oh and P.S. can anybody explain what the Substitute=".00000":"" value means? I couldnt' find it in any of the manuals i just know that if it isn't there my animation won't work..Thanks again!
User avatar
Chewtoy
Moderator
Posts: 995
Joined: June 10th, 2009, 12:44 pm
Location: Sweden

Re: Ending A Loop?

Post by Chewtoy »

Riving wrote:[ImageNumberCalc]
Measure=Calc
Formula=Counter%12 > 11 ? 1 : 2 (This is where I tried implementing my conditional operator although it doesn't work)
Substitute=".00000":""
IfAboveValue=1
IfAboveAction=ImageName=ImagesFrames\Frame11.png
(Frame11 is my last frame of the animation so I want it to stop here on this image with this image as the new permanent of the meter)
IfBelowValue=2
IfBelowValue=ImageName=ImagesFrames\Frame[ImageNumberCalc].png
(This is where I wanted my conditional operator to continue until the "abovevalue" is true)
DynamicVariables=1
The substitute is to remove the .00000 that is added to a value that goes thru a calc. It's fixed in the beta.
You've done everything great until you reach IfAboveAction. In that part you can only use bangs, and that's not a bang.
http://rainmeter.net/cms/Bangs_beta <-- These are the bangs you can use (needs 1.3beta to use them all).

The way I would go about this is probably something like this:

Code: Select all

[variables]
Image=1

;--

[ImageNumberCalc]
Measure=Calc
Formula=Counter %12
IfEqualValue=12
IfEqualAction=!Execute [!RainmeterSetVariable Image "11"][!RainmeterDisableMeasure ImageNumberCalc]

[SetImage]
Measure=Calc
Formula=Counter%1
IfBelowValue=1
IfBelowAction=!Execute [!RainmeterSetVariable Image [ImageNumberCalc][!RainmeterRedraw]
IfEqualValue=1
IfEqualAction=!Execute [!RainmeterSetVariable Image [ImageNumberCalc][!RainmeterRedraw]

[ImageMeter]
Meter=Image
ImageName=ImagesFrames\Frame#Image#.png
DynamicVariables=1
MouseOverAction=!Execute [!RainmeterEnableMeasure ImageNumberCalc]
Haven't tried it, but think that would work.
But anyway, what you did worng was that you didn't have a !Bang in the If****Action.
I don't think, therefore I'm not.
User avatar
Alex2539
Rainmeter Sage
Posts: 642
Joined: July 19th, 2009, 5:59 am
Location: Montreal, QC, Canada

Re: Ending A Loop?

Post by Alex2539 »

Pretty much everything in this bit of code is wrong:

Code: Select all

[ImageNumberCalc]
Measure=Calc
Formula=Counter%12 > 11 ? 1 : 2 (This is where I tried implementing my conditional operator although it doesn't work)
Substitute=".00000":""
IfAboveValue=1
IfAboveAction=ImageName=ImagesFrames\Frame11.png
(Frame11 is my last frame of the animation so I want it to stop here on this image with this image as the new permanent of the meter)
IfBelowValue=2
IfBelowValue=ImageName=ImagesFrames\Frame[ImageNumberCalc].png
(This is where I wanted my conditional operator to continue until the "abovevalue" is true)
DynamicVariables=1
I'll go through it line by line with you.

First, the formula will not do what you expect it to do. The % operator (called the modulus operator) returns the remainder of the first number divided by the second number. That means that if you have X%N, the values will range from 0 to N-1. In your statement, you are checking for when Counter%12 will be greater than 11. This will never happen. The only values you will get are from 0 to 11. You can see this yourself if you just write out the first few values that Counter%12 will return:

Code: Select all

0 % 12 = 0
1 % 12 = 1
2 % 12 = 2
3 % 12 = 3
4 % 12 = 4
5 % 12 = 5
6 % 12 = 6
7 % 12 = 7
8 % 12 = 8
9 % 12 = 9
10 % 12 = 10
11 % 12 = 11
12 % 12 = 0
13 % 12 = 1
etc...
In the end, all of this means that your conditional is always going to be false, and thus your measure will always return a value of 2.

Next, IfAboveAction is being completely misused. That assignment syntax you have invented there is completely meaningless. The action here must take the form of a Rainmeter Bang. If you want to perform more than one bang, use the !Execute bang first, then encase the following bangs in [square brackets]. Even if you did use bangs, what you are trying to do there is impossible. You cannot directly assign a value to some meter's parameter like that. The main reason is that ImageName is not unique to your [ImageMeter] meter. Every image meter will have an ImageName parameter, and there is no external distinction between them. For that matter, there is not even a way to refer to any of a meter's parameters. Not only that, but even if it did work the way you thought it did, you would still not get the result you expected. You are trying to use the value of [ImageNumberCalc] as the number of the frame to show when that is not at all what the measure is calculating. Because of the conditional statement, you will only ever get 1 or 2 as a result. The counter is just part of the formula, not the result.

Your next error is that you miswrote IfBelowAction as a second IfBelowValue. That's a pretty minor issue, I do it myself sometimes as well. That's just a matter of being careful. Of course even if you had spelled it properly, you would still run into the exact issue you had with IfAboveAction, but I won't slam you twice for that.

As for how to get this working, Chewtoy's method would almost work, but he fell into one of the same traps that you did. In his Calc measures he is first checking for when Counter % 12 will equal 12, which it never will, and then expecting Counter % 1 to oscillate between 0 and 1 whereas it will always return 0. Changing the IfEqualValue to 11 in the first case and Counter % 1 to Counter % 2 in the second case will fix that.

While Chewtoy's method will work pretty well, there are some issues I have with it. First of all, when trying to get the timing on something down, I try to avoid the built-in Counter function. Counter does not reset when a skin is refreshed, only when it is closed and restarted or when Rainmeter is restarted; otherwise the Counter will continue from where it last left off. If you wanted the animation to loop it wouldn't be a problem, but since you need it to start 0 you need a way to guarantee that, which Counter cannot easily do.

Instead I prefer to make my own counters. It's pretty simple. Calc measures can read the values of other measures and use them in their formulas simply by specifying the measure's name. You can also use dynamic variables by encasing the name in [square brackets] and adding DynamicVariables=1 to the Calc. Each method has its own benefits depending on what you want to do, but in this case it doesn't matter so I won't get into it. Now, not only can a Calc refer to other measures, but also to itself. So, by adding the Calc's name to its own formula, you can read the last value it held and then perform some operation. In this case since we want to make a counter, just add one to that value.

The second issue I have with Chewtoy's method is that you need an extra variable that needs to be set by an extra Calc measure in order to properly use the value of that first measure that cycles through the frames. To me both the extra variable and measure seem excessive, but are necessary because of the way he is doing it. I would rather find a way to stop the measure that is counting the frames so that it is the only value you need rather than relying on extra code.

Anyway, here is how I would do it:

Code: Select all

[Rainmeter]
Update=100
OnRefreshAction=!RainmeterEnableMeasure Frame

[Frame]
Measure=Calc
Formula=Frame<11?Frame+1:11
Disabled=1
Substitute=".00000":""


[ImageMeter]
Meter=Image
ImageName=ImagesFrames\Frames[Frame].png
DynamicVariables=1
The [Frame] measure first checks its own value. If it is less than 11, it returns its own value, plus one (ie: it is like a counter). Otherwise the value is simply 11. This will make it count from 0 to 11 and then stop. The benefit of doing it this way is that if ever you want to play the animation again, all you need to do is disable the measure and then reneable it. When a measure is disabled, its value is read as 0, so when you reenable it and it checks its previous value, it will once again be less than 11 and the measure will count up again. I've made it so that the measure starts off disabled and is enabled at the very start using OnRefreshAction in the [Rainmeter] section. It's not strictly necessary, but without it the animation would always start at frame 2 instead of frame 0 when the skin is refreshed. Finally, all you need to do is use the value of the [Frame] measure wherever you need it. I based the path in ImageName off of what you posted, so if it is incorrect, it's up to you to fix it.
ImageImageImageImage
Riving
Posts: 2
Joined: September 22nd, 2010, 9:32 am

Re: Ending A Loop?

Post by Riving »

Hey I really appreciate it guys.
I was having trouble finding anything about the subsititue value so that helped alot, thanks Chewtoy :)
And that coding worked like a charm Alex. (Just had to fix the image location you put in ;) )
But that was awesome explanation it really helped me out. I'm starting to get a feel for the tools rainmeter has. To be honest I like your way of calculating values much better than the built-in one, so kudos for coming up with that, I'll be using that quite a bit more now ha. I was able to get both your codings working, with a quick tweak to Chewtoy's, and rewriting both of them actually let me understand what each part of the coding meant.

What I am still having trouble with, Alex, is how the last part of what you wrote works.

"When a measure is disabled, its value is read as 0, so when you reenable it and it checks its previous value, it will once again be less than 11 and the measure will count up again. I've made it so that the measure starts off disabled and is enabled at the very start using OnRefreshAction in the [Rainmeter] section. It's not strictly necessary, but without it the animation would always start at frame 2 instead of frame 0 when the skin is refreshed. Finally, all you need to do is use the value of the [Frame] measure wherever you need it. I based the path in ImageName off of what you posted, so if it is incorrect, it's up to you to fix it."

When I put your code in as is, it didn't work until I removed the Disabled=1 part of the coding, although I thought this might work considering you had placed in the onrefreshaction part of the code. Maybe it didn't work because the code is read downwards so what's written last is done first or something? I tried refreshing rainmeter and it still wouldn't work, but when I removed that part of the coding (the disabled=1 part) it worked fine starting at what looks like frame0 and ending on the final frame.

I'm also guessing that the way this type of code is written I can enable a !RainmeterDisableMeasure [Measure] (Config) and a !RainmeterEnableMeasure [Measure] (Config) bang to allow the animation to only run on say a mouseover or mouseclick action? So something like this would work?:
MouseOverAction=!execute [!RainmeterEnableMeasure ImageMeter]
MouseLeaveAction=!execute [!RainmeterDisableMeasure ImageMeter]

Again guys I really appreciate all of the help. I'm doing my best to learn everything, but it's a little overwhelming for me as of right now :)
User avatar
Alex2539
Rainmeter Sage
Posts: 642
Joined: July 19th, 2009, 5:59 am
Location: Montreal, QC, Canada

Re: Ending A Loop?

Post by Alex2539 »

Disabling the measure will make it return 0, so it would show the first frame of the animation. Once you reenable it, it will start up the animation again. If you add the Enable/Disable bangs to the MouseOver/Leave actions like that, what will happen is when you put your mouse over the meter in question, the animation will begin to play. As soon as the mouse leaves, the animation will snap back to the first frame. If that's what you want, then you're good to go.
ImageImageImageImage