Mar 20 2012
WebLookAndFeel and Nine-patch
Library got a large bunch of updates and upgrades since last version and i today i will tell about the main one – new Nine-patch editor and styling hidden within the library.
First of all i will tell a bit about nine-patch format for those who still don’t know anything…
Nine-patch
Nine-patch is an image format that holds some additional information inside png-format image meta-data or inside the picture itself.
Here you can see a simple example of nine-patch image (it is also set as default image in editor):
As you can see there are four black-colored lines on the image sides – that is additional data that nine-patch format provides.
Each line on the left and top sides presents stretchable image areas – those parts of image will be sized with the component they are used on.
Each line on the right and bottom sides presents content areas (they might also be empty) – in those parts of image component content will be placed (for example – button text and icon).
That is basically all you need to know about that format to make it useful inside you application with WebLookAndFeel library!
If you want to know more – you might find this post and official Android dev guide useful.
I will tell you about nine-patch files usage a bit later – let’s check the format editor first…
Nine-patch editor
It was already announced on HabraHabr, but it changed a lot since than and i will tell some more technical info today.
First of all – this is how visual editor looks like:
There three main areas:
– system disks tree on the left side that allows you to browse through system files and open them quickly
– visual editor area in the middle on which you can add, drag and delete “patches”
– preview area on the right side that always represents last changes made to image
On the top left toolbar you will find main control buttons used to open/save image, copy patch info and undo/redo changes.
On the top right toolbar you will find preview settings – text (you can use “;” or “\n” to separate lines), its color and icon.
On the bottom toolbar there are editor view settings buttons and zoom slider.
On the code side this dialog (NinePatchEditorDialog) is just a small shell for NinePatchEditorPanel class that contains areas and base editor logic.
You can easily use either NinePatchEditorDialog, NinePatchEditorPanel or NinePatchEditor (visual editor itself) inside your own application if needed.
For example if you want to display nine-patch editor (without any controls) inside your application with some image you can simply add it like this:
NinePatchEditor editor = new NinePatchEditor (); editor.setNinePatchImage ( ImageUtils.loadImage ( "C:\\image.png" ) ); myPanel.add ( editor );
where “myPanel” could be any Swing Container.
You can set and retrieve image from the editor anytime you like:
NinePatchIcon icon = editor.getNinePatchIcon (); BufferedImage image = editor.getNinePatchImage ();
From NinePatchIcon you can get any edited data and 2nd method quickly assembles complete image from that data.
Also you can easily tweak editor settings:
editor.setFillContentArea ( true ); editor.setFillStretchAreas ( true ); editor.setShowGuideSpacing ( true ); editor.setShowRuler ( true ); editor.setZoom ( 1 );
Zoom can be any value from 1 to 32.
Still, editor is not the most interesting thing here but the nine-patch parser – NinePatchIcon class to be exact. Let’s look closer at it…
NinePatchIcon
This class is based on javax.swing.Icon interface that is used by a great amount of Swing components.
It provides basic information about icon – size and how it should be painted on one or another component.
NinePatchIcon extends that basic information and also provides icon preferred size (remember, the nine-patch icons are stretchable), margin and patches information which are determined from the image itself. All that additional information is used to correctly paint icon over different components.
So nine-patch icons could be used to style a component of any size unlike (as an example) the static ImageIcon.
But most of the components have lots of different parts or states they might switch between during the execution – how could they be styled with single image (even stretchable one)?
This is when WebLookAndFeel time comes…
BackgroundPainter and styleable UI’s
I already told you about BackgroundPainter concept in previous post so i will go straight and show how it can be used in action.
Let’s try something easy first – we will style a button with a few states through nine-patch icons which i will take from android platform resources:
These are different button states – normal, focused, disabled, pressed and selected (this one is for toggle button).
So, first of all we need a BackgroundPainter instance to style button with.
There are plenty already available and supported by Web-components like NinePatchBackgroundPainter, AlphaBackgroundPainter, TextureBackgroundPainter and others.
At the moment we are interested in StateBackgroundPainter which is an extended version of NinePatchBackgroundPainter and can keep different state images and decides how to use them in one or another component.
So this is how our StateBackgroundPainter will look like:
StateBackgroundPainter bg = new StateBackgroundPainter (); bg.addStateIcon ( ComponentState.normal, new NinePatchIcon ( NinePatch.class.getResource ( "icons/n.png" ) ) ); bg.addStateIcon ( ComponentState.focused, new NinePatchIcon ( NinePatch.class.getResource ( "icons/f.png" ) ) ); bg.addStateIcon ( ComponentState.disabled, new NinePatchIcon ( NinePatch.class.getResource ( "icons/d.png" ) ) ); bg.addStateIcon ( ComponentState.pressed, new NinePatchIcon ( NinePatch.class.getResource ( "icons/p.png" ) ) ); bg.addStateIcon ( ComponentState.selected, new NinePatchIcon ( NinePatch.class.getResource ( "icons/s.png" ) ) );
We will use it for both – normal and toggle buttons since it doesn’t really matter if there is a useless state inside – it will just be ignored when painting occurs.
Also notice that “focused” state is a special state since it might cover other icons when painted if the component is focused – that allows you to draw focus border separately from the other parts.
So next we add it into our buttons and run a test frame (TestFrame is also a new feature that allows you to display any component in a frame quickly):
WebButton button = new WebButton ( "Simple button" ); button.setBackgroundPainter ( bg ); WebToggleButton toggleButton = new WebToggleButton ( "Simple toggle button" ); toggleButton.setBackgroundPainter ( bg ); new TestFrame ( new GroupPanel ( 15, button, toggleButton ), new Insets ( 15, 15, 15, 15 ) );
And here we go – two Android-styled buttons in our demo-frame:
Try clicking them – they will act like normal buttons.
This approach already works for a list of Swing-based Web-components:
– WebLabel
– WebPanel
– WebButton & WebToggleButton
– WebTextField, WebPasswordField & WebFormattedTextField
– WebTextArea
You can easily style any of them, usign different background painters (including nine-patch ones).
Actual style (BackgroundPainter) support is hidden within the component UI classes (for example WebLabelUI).
In next version there will be much more components styling support added like check-boxes, radio-buttons, sliders, spinners and many others.
Xml and styling
Components styling through background painters (and by nine-patch background painters in the particular case) takes much less effort than creating new or extending existing one.
Still there is a room for even more simple and compact code. So the next step of simplification was moving all graphics and styling out from code into properties-like xml files.
You might have noticed that in library showcase Futurico and Android styling examples does not use background painters directly, but load them from predefined xml files which are contained in demo jar.
This is how Android button background painter creation code looks like in showcase:
StateBackgroundPainter npbbp = XmlUtils.loadStateBackgroundPainter ( AndroidButtonsExample.class.getResource ( "resources/button.xml" ) );
This replaces 6 lines of code we used before. Let’s see what is in the xml file:
<ResourceMap> <states> <entry> <string>selected</string> <ResourceFile> <location>nearClass</location> <source>icons/button/s.png</source> <className>com.alee.examples.groups.android.AndroidButtonsExample</className> </ResourceFile> </entry> <entry> <string>pressed</string> <ResourceFile> <location>nearClass</location> <source>icons/button/p.png</source> <className>com.alee.examples.groups.android.AndroidButtonsExample</className> </ResourceFile> </entry> <entry> <string>normal</string> <ResourceFile> <location>nearClass</location> <source>icons/button/n.png</source> <className>com.alee.examples.groups.android.AndroidButtonsExample</className> </ResourceFile> </entry> <entry> <string>focused</string> <ResourceFile> <location>nearClass</location> <source>icons/button/f.png</source> <className>com.alee.examples.groups.android.AndroidButtonsExample</className> </ResourceFile> </entry> <entry> <string>disabled</string> <ResourceFile> <location>nearClass</location> <source>icons/button/d.png</source> <className>com.alee.examples.groups.android.AndroidButtonsExample</className> </ResourceFile> </entry> </states> </ResourceMap>
Basically this is an xml representation of ResourceMap class filled with button state resources.
Single resource (ResourceFile) represents a file location (it could be url, local file or resource near some class).
Since we used files from the showcase jar – all resources have “nearClass” enumeration value and also have class name field filled in.
Actually xml file is not perfect yet and will be simplified with next release to remove lots of useless information, but it is still a good way to simplify your code.
Plus you can always change the resources location without affecting the code (you can do it even after all the classes are compiled and deployed).
For now there are three types of resources that could be serialized to xml – ResourceFile (single file), ResourceList (list of ResourceFile), ResourceMap (map of ResourceFile behind String keys).
All of them can be used to simplify any massive resource files loading (for example styling graphics in our particular case).
Stay tuned!
This is all for today, but i will keep telling you much more about the library with each post, so stay tuned for updates!