PDA

View Full Version : How to create a <NStatesButton> like the one from the Modern skin?


avegav2
30th September 2007, 18:45
I looked at the XML code of the Modern skin included with Winamp and noticed that the Repeat togglebutton is implemented via a <NStatesButton> instead of a <ToggleButton>, the following way;


<NStatesButton
id="Repeat"
x="-40" y="22"
nstates="3"
relatx="1"
image="player.button.repeat"
downImage="player.button.repeat.pressed"
hoverImage="player.button.repeat.hover"
activeImage="player.button.repeat"
tooltip="Toggle Playlist/Song Repeating"
cfgattrib="{45F3F7C1-A6F3-4EE6-A15E-125E92FC3F8D};Repeat"
cfgvals="0;1;-1"
rectrgn="1"
/>


I wanted to make use of this characteristic to build a Repeat button that would allow to change between the states REPEAT_DISABLED, REPEAT_TRACK and REPEAT_ALL. But when I modify the skin I am making to use this <NStatesButton>, the Repeat togglebutton simply vanishes from the skin.

Is there any parameter, any header file, any MAKI script that I must include in the beginning of the code so Winamp could recognize this element? My examination of the Modern skin did not help me to find an answer by myself. I have not found this element in the std.mi file either. How should I refer to this element in a MAKI script? For a Button, I would write

Global Button BtnPlay;

and for a ToggleButton, the code would look like this:

Global ToggleButton TglRepeat;

The MAKI references that I read do not mention the class NStatesButton.

Besides, I thought that the cfgvals for the Repeat atribute were 0, 1 and 2. But in this case, the developer is using -1, 0 and 1. Dou you know what the meaning of the -1 atribute is?

Any help would be very appreciated.

DigiMike
1st October 2007, 03:20
This code is essentially riped out of the modern skin. Hopefully some of the explinations will help.

A nstates button is a special type of togglebutton, that way it can cycle more than 2 states. In the case we want a 3 state repeat button. "Repeat off" "repeat all" "repeat track". Nstatebuttons need a graphics for all 3 states the button will be in, unlike the togglebutton which will work with one with the active image optional.

Here is example xml for the button itself.

<NStatesButton
id="Repeat"
nstates="3"
image="repeat"
downImage="repeat"
hoverImage="repeat.o"
activeImage="repeat"
x="0" y="0"
tooltip="Cycle Repeat Modes"
cfgattrib="{45F3F7C1-A6F3-4EE6-A15E-125E92FC3F8D};Repeat"
cfgvals="0;1;-1"
/>

The cfgattrib with the listed GUID handles just about everything on its own. No crazy voodoo magic required. From what I gather the vals are what is returned to winamp in a similar manner to what is processed in the ACTION="blah" part you see in most buttons.

Others here probably know more about the particulars than I do.

Now we need to reference the images for the button. Notice the 0,1,2 in each bitmap id. Winamp uses a separate bitmap id for each state the button is in and looks for the number at the end of each id. For a 3 state button you need 3 images referenced for normal, hover, and hit. You can reference the same bitmap id in the xml over and over though. IE if you want a stagnant button with no hover or hit graphic you could reference only 3 id's like so in your xml.


downImage="repeat"
hoverImage="repeat"
activeImage="repeat"


This one in particular uses the same graphics for "normal" and "hit" states. With a separate graphic for "hover"

<bitmap id="repeat0" file="player/repeat.png" gammagroup="Text Elements"/>
<bitmap id="repeat1" file="player/repeat.png" gammagroup="Text Elements"/>
<bitmap id="repeat2" file="player/repeat.png" gammagroup="Text Elements"/>
<bitmap id="repeat.o0" file="player/repeat_o.png" gammagroup="Text Elements"/>
<bitmap id="repeat.o1" file="player/repeat_o.png" gammagroup="Text Elements"/>
<bitmap id="repeat.o2" file="player/repeat_o.png" gammagroup="Text Elements"/>


With just that the button will function, but the user won't know what state the button is in.

This is the Maki from the modern skin that sends a text message to the song display called "SongTicker" so the user gets a view of what repeat state the player is currently in.

Notice the script is referencing onToggle(). A NStatesButton is after all a special type of toggle button.


Global Togglebutton Repeat; // Define a variable for the button
Global text Songticker; // Define the song display


//Here we reference the layers in the xml file and assign them to the variables.

System.onScriptLoaded(){
Layout mainLayout = getContainer("main").getLayout("Normal");
Songticker = mainLayout.findObject("Songticker");
Repeat = mainLayout.findObject("Repeat");

}

//This is the button script.

Repeat.onToggle(boolean on) {
int v = getCurCfgVal();
if (v == 0) SongTicker.setAlternateText("Repeat: OFF");
else if (v > 0) SongTicker.setAlternateText("Repeat: ALL");
else if (v < 0) SongTicker.setAlternateText("Repeat: ONE");
}


I hope this helps.

TheElusiveMelon
1st October 2007, 09:38
Yeah, you probably named your images wrongly. For the NStatesButton, they have to be named in a specific way, as DigiMike showed. Also, that maki script isn't neccesary to make the button work, it just adds a nice feature

avegav2
3rd October 2007, 02:44
Thanks very much for your comprehensive answer. I didn't know that the images' names for a NStatesButton had to follow such a specific pattern. It seems to be another undocumented feature of Winamp \(^o^)/.

I renamed the images for the three states and everything seems to work fine, except for the following bug: if I turn off Winamp when the state of the toggle is -1 (REPEAT: TRACK), next time I start Winamp, the image of the toggle corresponds to the REPEAT: ALL state (1), but the real state of the Repeat function is REPEAT: TRACK.

In case of a normal toggle, I usually initialize it in my scripts (section onScriptLoading()) with a function like this:

ToggleShuffle.setActivated(act);

where act is a variable that reads the current state of the toggle. In this case, act=0 for SHUFFLE: DISABLED and act=1 for SHUFFLE: ENABLED.

I wonder if there exists another similar function that can be applied over a NStatesButton, because the argument for setActivated() must be only a boolean (0 or 1), and our Repeat button has an additional state of -1. That would solve my problem completely.

By the way, the code for my NStatesButton (nothing marvelous here):


<nstatesbutton
id="player_normal_toggle_repeat"
cfgattrib="{45F3F7C1-A6F3-4EE6-A15E-125E92FC3F8D};Repeat"
nstates="3"
cfgvals="0;1;-1"
image="player.normal.toggle.repeat.enabled."
hoverImage="player.normal.toggle.repeat.hover."
downImage="player.normal.toggle.repeat.pressed."
activeImage="player.normal.toggle.repeat.enabled."
x="32" y="25"
/>

TheElusiveMelon
3rd October 2007, 07:49
Actually, i only knew because someone posted a link to a document where it said. That was on my old pc though, so i can't remember the link. You can probably find it by searching the forums though.

Found the link:
http://docs.wasabidev.org/wasabi_developer_manual/using_xml_reference.php

avegav2
4th October 2007, 01:56
Well, I see that the NStatesButton is well documented, only that I did not know about this document. (^_^)' Thanks for the link; this is the kind of rich documentation that we skinners need in order to polish our works.

Despite this, my Repeat NStatesButton still behaves buggy; I finally happened to convert it into a normal button (not a togglebutton) and performed the image changes with the help of a MAKI script.