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.
vBulletin® v3.8.6, Copyright ©2000-2013, Jelsoft Enterprises Ltd.