[Nifty] Creating a new Style

Anyone knows of a primer or some examples on how to create a style either from scratch or from an already existing control? Not something too simple as I’m ok with simple stuff.



My goal is to create a totally different style for the Window control but so far, not very successful. There are things you can do with styles that are really great without having to reinvent a brand new control. I’d like to achieve that but help on styles is pretty scarce except for the files taken from the source jars. Although those are nice to have, they won’t explain the intricacies of styles and their proper usage.



Any help/input/suggestion would be appreciated.



Thanks!

Well, the 1.2 interactive tutorial demo thing had a couple of pages explaining styles. besides that there is no black magic involved, I swear :slight_smile:



Actually it depends on what you mean by “style” because you could mean:



a. the Nifty style tag that defines attributes (and effects) once and that you can apply to several elements

b. the “style” of a default control, like a button or a window or so



I think you understand the first kind of styles?



To define a new style for a default control you’ll need to understand how the default control is being build. Since Nifty controls are build out of elements (panel, image, text) there is no black magic there either. A button for instance consists of the background image and a text element centered on that image. So all what the “styles” for the button does is to define the image to use, the font of the text and so on. The basic structure of the control (a image with a centered text element) stays the same and the style simply changes the images, fonts and so on.



It’s the same for the window.



The only thing that might be the cause of some confusion is the substyle mechanism. Here is an example:



[xml]<controlDefinition name=“window” style=“nifty-window” …> <!-- main style called nifty-window -->

<panel style="#frame"> <!-- sub style called #frame -->

<panel id="#window-bar" style="#bar"> <!-- sub style called #bar … and so on -->

<text id="#window-title" style="#title" text="$title" />

<panel id="#window-close-button" style="#close-button" />

</panel>

<panel id="#window-content" style="#content" />

</panel>

</controlDefinition>

</nifty-controls>[/xml]



This is the actual window control (I’ve removed some of the interact stuff and some of the attributes for the sake of the example and I’ve added additional XML comments).



When Nifty finds a control tag, like that one:



[xml]<control name=“window” …/>[/xml]



and you specify no style attribute for the control tag, then Nifty will simply add the one from the controlDefinition. So what you end up is actually:



[xml]<control name=“window” style=“nifty-window” …/>[/xml]



When Nifty sees a control like that it will simply replace the control name=“window” with all of the elements from the controldefinition and it will automatically resolve styles using the main style name “nifty-window” and adds the substyle things.



So for instance the element with the id="#window-content" will get the resolved style = “nifty-window#content” (see the controlDefinition above).



And when you look at the nifty-style-black style definition for the window you’ll find exactly that:



[xml] <style id=“nifty-window#content”>

<attributes width=“100%” height="" padding=“8px” backgroundColor="#9996" childLayout=“center” />

</style>

[/xml]



So this line:



[xml]<panel id="#window-content" style="#content" />[/xml]



will be resolved to that line when the controlDefinition is resolved using the default style:



[xml]<panel id="#window-content" style=“nifty-window#content” />[/xml]



and finally when that styleDefinition “nifty-window#content” is applied you’ll get this:



[xml]<panel id="#window-content" width=“100%” height="
" padding=“8px” backgroundColor="#9996" childLayout=“center” />[/xml]



Done! :slight_smile: Oh, wait … one more thing :wink:



With the correct styles in place you can overwrite that “nifty-window” style when you use the control:



[xml]<control name=“window” style=“ueber-awesome-new-madjack-window-style” …/>[/xml]



and with your style definition in place



[xml] <style id=“ueber-awesome-new-madjack-window-style#content”>

<attributes … your attributes />

</style>

[/xml]



Nifty will automatically apply your style as well!



So creating your own style for a existing control means:



a. understand how that control is being build out of nifty elements inside the controlDefintion

b. define all the substyle the control asks for with your own version



This might look quite a bit challenging at first (or over complicated maybe too?) but it’s really not as hard as it might look because it’s just applying the same mechanism of resolving things. In the end it comes down to a nifty element, like a panel, image or text and a set of attribute derived from the style definition.

2 Likes

Thanks a lot for that great post void.



Unfortunately I figured it all out since I posted it, but I’m sure it’ll be appreciated by the other jME3 users. It’s not all bad though, I’ll definitively use that to make a new entry in the Nifty wiki and also here as a basis for a complete tutorial.



But I’ve noted some discrepancies. Discrepancies might be too big a word. More like confusing behavior. Here’s what I mean.

If, in your basic control definition (either the .xml file or the “custom controlDefinition” at the start of a wholeScreen.xml), you define a panel to be childLayout=“vertical”, but your new-spiffy-style.xml redefines that same panel with childLayout=“horizontal” and finally the panel itself on the page uses childLayout=“center”, nifty will simply complain and “crash”. Shouldn’t the last childLayout override the others specifications of childLayout? Or override any tag for that matter? And by last, I mean the one declaring the childLayout like so:

[xml]

<screen … >

<control name=“revisitedControl” … >

<panel id="#specialStyle" childLayout=“center” … /> <!-- This one should override all others right? -->

</control>

</screen>

[/xml]



Here’s the example of the style redefinition for the window control I made. It’s not entirely finished but it’s getting very close. I hope you like it. :wink:

Here’s the link to the control redefinition… Forgot to paste it and don’t want to reformat the whole message because of editing. :stuck_out_tongue:



http://hub.jmonkeyengine.org/groups/gui/forum/topic/an-invitation-to-contribute-to-niftys-documentation/#post-129668

nifty will simply complain and “crash”


Complain and "crash" with what kind of a message? Can you please be a bit more specific? Especially when it "crashes" I'd like to know with what message :)

For some reason - and I really can't remember right now - styles don't necessarily override attributes. When an attribute is already set by someone else you can't overwrite it with a new value. This might be odd but at the moment it just works this way.

Controldefinitions should take this into account and should probably move all attributes to the style definition. A properly written control should only define the elements that the control consists of and let the style handle all of the attributes (so that someone can define a completly new style for the control).

And before you notice and complain about the 'childLayout="vertical" valign="top"' attributes that still exists in the nifty-window.xml (controldefinition) I've just moved it to the style (where it belongs) and commited that change to svn. :P

Aha! I knew I had it wrong!



The real crash happens when you have a “missing” childLayout tag in a stylized panel. That will happen even if the style definition has the childLayout defined AND/OR the controlDefinition also has the childLayout defined. It does not matter if childLayout are identical or not.



Here’s what I mean.



[xml]

<layer id=“topPanel” childLayout=“absolute” width=“225px” visibleToMouse=“false”>

<control id=“infoPanelDraggable” name=“draggablePanel” width=“225px” height=“303px” x="${CALL.infoPanelX()}" y=“5” valign=“top”>

<panel id="#content" childLayout=“vertical” backgroundImage=“Textures/GUI/panelTop.png” />

</control>

</layer>

[/xml]



If I use:

[xml]

<panel id="#content" backgroundImage=“Textures/GUI/panelTop.png” />

[/xml]

I get a crash when the screen loads EVEN if those are true:



[xml]

<controlDefinition name=“draggablePanel” style=“drag-panel-style” childRootId="#content" controller=“com.madjack.games.sc.gui.nifty.GameWindow” revert=“false” drop=“false” handle="#frame">

<interact onClick=“dragStart()” onClickMouseMove=“drag()” onRelease=“dragStop()” />

<panel style="#frame" childLayout=“vertical” valign=“top”>

<panel id="#bar" style="#bar" childLayout=“horizontal” align=“right”>

<panel id="#minimize-button" style="#minimize-button" align=“right”>

<interact onClick=“minimizeWindow()” />

</panel>

</panel>

<!-- notice the childLayout IS there -->

<panel id="#content" style="#content" childLayout=“vertical” />

</panel>

</controlDefinition>

[/xml]



and even if the style is like this:

[xml]

<style id=“drag-panel-style#content”>

<attributes align=“center” valign=“center” childLayout=“vertical” />

</style>

[/xml]



No matter what the style or control definition says, if the panel doesn’t have the childLayout, it will crash with the following

[java]

java.lang.RuntimeException: missing childLayout attribute for an element with [1] child elements. Attributes of error element [backgroundImage => Textures/GUI/panelTop.png, id => infoPanelDraggable#content#content]

at de.lessvoid.nifty.loaderv2.types.ElementType.enforceChildLayout(ElementType.java:186)

at de.lessvoid.nifty.loaderv2.types.ElementType.applyStandard(ElementType.java:175)

at de.lessvoid.nifty.loaderv2.types.ElementType.create(ElementType.java:143)

at de.lessvoid.nifty.loaderv2.types.ElementType.applyChildren(ElementType.java:250)

[/java]



Moreover, it seems Nifty doesn’t recognize the #content id. I guess because it doesn’t have the same params?

It seems, after rereading void’s post and comparing to the behavior I was getting, I was wrong in certain of my assumptions. The results were working (almost 100%), but it was wrong, thus I have to make it the right way so it’s consistent.



Because of that the tutorials will have to wait until I fully grasp what’s going on and fix it accordingly.