Tuesday, May 31, 2011

Brothers from other mothers...

"Write once run anywhere"...everybody remembers these words from Sun to promote the cross-platform functionality of Java. Today, more than 10 years later this is only true in different areas (but i think Java still is the platform which gives you the best cross-platform functionality on the market). Now we have tablet devices like the iPad, Android based devices and WebOS based devices. 
The problem with this devices is that your desktop java application won't run on them. The solution to this problem could be HTML5 Canvas which makes it possible to get the same graphical experience that you knew from Java Swing in your HTML5 capable browser. 
The Canvas 2D api is in fact very similar to the Java 2D api which makes it possible to create nearly the same graphics with it.
So to get the gauges from my steelseries Java library i first thought about porting them to Android and maybe iOS too. After i started porting a gauge to Android i felt that this was the wrong approach because it meant platform dependend code.
So i took a closer look to HTML5 Canvas and figured out that porting the code to JavaScript was easier than i thought and the idea of a SteelSeries JavaScript edition was born.
I started porting single gauges to Canvas but did not find the time to combine the components into one lib.
Fortunately i'v found some time last week to get some work done on the library and migrated all available components (which means the radials, the radialbargraphs, the compass and the level component) in the steelseries.js file. In addition i've also added a led component to the lib. 
I'm quite happy with the progress but you should judge by yourself.
Therfore i created two demo's to give you the chance to compare the Java Swing version to the HTML5 Canvas version.


Attention: Switching between different designs may take some time on mobile devices because right now i completely reinitialize the complete component (improvements will follow in the near future).


Here's a little screenshot of the website...

Click me for a live demo...


and of the Java Swing version too...


Click me for a live demo...


To start the applications just click on the link below the images.

So now you have the chance to compare and judge yourself but i'm sure you will agree that HTML5 Canvas gives you the chance to create real cross-platform applications (even if i also have to say that not everything is so easy to port to Canvas...but we are just at the beginning of the new HTML5 era).

Well that's all i have to say for today...so keep coding...

Friday, May 27, 2011

Friday Fun Component VIII

And it's friday again...yippeah...
This week i was on a trip to a customer in Grenoble (which is by the way a really nice place to be). It was related to my job and i did an installation and training for a customer.
The really best part of that trip was not the installation but my visit at the Canoo headquarter in Basel (CH). This company created a real nice product named Canoo RIA Suite which is based on ULC (UltraLightClient). If you never heard of it you should definitly take a look at it, it's worth the time.
I was there to visit Andres Almiray (Blog, Twitter) and gave a little presentation (which was a little chaotic because i was not really good prepared). During this presentation i figured out that people are interested in a little application that i wrote nearly 2 years ago for a talk at our local JUG.


Here is a little screenshot of the application...




The application itself should not demonstrate how to create a good looking user interface but more it should show the possibilities that you have with good old legacy Java Swing. The icing on the cake was the panel with the bubbles on top of the window because i used this panel as a validator for the whole form.
Well there's not much to explain...just 2 simple questions...

  • Do a form always have to look ugly and boring ??? 
  • And do have validators always have to look ugly too ???

I think you will be smart enough to give yourself the right answer...


After leaving Canoo i thought it might be interesting for others too and decided to split the BubblePanel of the old project and create a little component out of it that you could now download and use for yourself.
But before i will give you the link to the file i will show you a screenshot of what you will get...




And to get an even better impression of it you might want to see it live before you download the source...right...


So here is as a webstart app...and here is the source...as always a Netbeans project. The interesting part of the source is the BubblePanel, which simply extends a JPanel and produces bubbles in the background until you call setValidated(true). That means you could use it as a normal Swing container.


The main idea behind this bubble thing was to find other ways of visualization. In the original app the panel stays just on top of the form and does nothing but producing bubbles until one completes the form. So don't take the bubbles too serious but i hope i opened a door so you just have to make the next step and think different...


That's it for today, i hope you got the idea...and as always...keep coding...

Thursday, May 19, 2011

Varying gradients...

Just a short post about varying gradients. If you take a bar for example that has a linear gradient from top to bottom and you would like to adjust the gradient with the horizontal size of the bar you have to calculate the colors for the gradient from the size of horizontal size of the bar.
I created a little drawing to visualize what i mean (i hope you could understand it)...

The horizontal bar in the center should vary it's gradient by it's horizontal size. To achieve this you need to calculate two gradients, one over the three colors on the top of the box (the dark colors) and one over the three colors on the bottom of the box (the bright colors).
I faced the problem when i created the battery component of the SteelSeries lib yesterday which looks like this...


Exactly for this kind of problem i created the LinearGradientPaint wrapper last week. For the example with the horizontal box you have to create two instances of the LinearGradient2 class that is also part of the SteelSeries lib. One for the three dark colors and the other for the three bright colors.
Then you create a LinearGradientPaint that fills the horizontal box from top to bottom with the colors that you get from the getColorAt(float fraction) method of the LinearGradientPaint2 class. Hmm...hard to put into words...maybe some code will help here...

public class TestPanel extends javax.swing.JPanel
{
    public TestPanel()
    {
        super();
    }
    
    @Override
    protected void paintComponent(java.awt.Graphics g)
    {
        super.paintComponent(g);
        
        java.awt.Graphics2D G2 = (java.awt.Graphics2D) g;
        
        G2.setRenderingHint(java.awt.RenderingHints.KEY_ANTIALIASING, java.awt.RenderingHints.VALUE_ANTIALIAS_ON);
        
        // Define three boxes with the size of 100%, 66% and 33%
        final Rectangle2D BOX100 = new Rectangle2D.Double(0, 0, 300, 50);
        final Rectangle2D BOX66 = new Rectangle2D.Double(0, 100, 200, 50);
        final Rectangle2D BOX33 = new Rectangle2D.Double(0, 200, 100, 50);
        final Point2D START = new Point2D.Double();
        final Point2D STOP = new Point2D.Double();
        
        // Define the fractions for the dark and bright gradient
        final float[] FRACTIONS =
        {
            0.0f,
            0.5f,
            1.0f
        };        
        
        // Define the dark colors (from top to top)
        final Color[] DARK_COLORS =
        {
            Color.GREEN.darker(),
            Color.YELLOW.darker(),
            Color.RED.darker()
        };
        
        // Define the bright colors (from bottom to bottom)
        final Color[] BRIGHT_COLORS =
        {
            Color.GREEN.brighter(),
            Color.YELLOW.brighter(),
            Color.RED.brighter()
        };
        
        // Define the two LinearGradientPaint2 instances
        LinearGradientPaint2 DARK_GRADIENT = new LinearGradientPaint2(new Point2D.Double(0,0), new Point2D.Double(100,0), FRACTIONS, DARK_COLORS);
        LinearGradientPaint2 BRIGHT_GRADIENT = new LinearGradientPaint2(new Point2D.Double(0,0), new Point2D.Double(100,0), FRACTIONS, BRIGHT_COLORS);
                
        // Define the fractions for the linear gradient of the horizontal box
        final float[] BOX_FRACTIONS =
        {
            0.0f,
            1.0f
        };
        
        // Define the gradient for the 100% box and fill it with the right colors
        START.setLocation(0, BOX100.getMinY());
        STOP.setLocation(0, BOX100.getMaxY());                
        Color[] boxColors =
        {
            DARK_GRADIENT.getColorAt((float) BOX100.getWidth() / 300f),
            BRIGHT_GRADIENT.getColorAt((float) BOX100.getWidth() / 300f)
        };        
        LinearGradientPaint boxGradient = new LinearGradientPaint(START, STOP, BOX_FRACTIONS, boxColors);
        G2.setPaint(boxGradient);
        G2.fill(BOX100);
        
        // Define the gradient for the 66% box and fill it with the right colors
        START.setLocation(0, BOX66.getMinY());
        STOP.setLocation(0, BOX66.getMaxY());
        boxColors = new Color[]
        {
            DARK_GRADIENT.getColorAt((float) BOX66.getWidth() / 300f),
            BRIGHT_GRADIENT.getColorAt((float) BOX66.getWidth() / 300f)
        };        
        boxGradient = new LinearGradientPaint(START, STOP, BOX_FRACTIONS, boxColors);
        G2.setPaint(boxGradient);
        G2.fill(BOX66);

        // Define the gradient for the 33% box and fill it with the right colors
        START.setLocation(0, BOX33.getMinY());
        STOP.setLocation(0, BOX33.getMaxY());
        boxColors = new Color[]
        {
            DARK_GRADIENT.getColorAt((float) BOX33.getWidth() / 300f),
            BRIGHT_GRADIENT.getColorAt((float) BOX33.getWidth() / 300f)
        };        
        boxGradient = new LinearGradientPaint(START, STOP, BOX_FRACTIONS, boxColors);
        G2.setPaint(boxGradient);
        G2.fill(BOX33);
        
        G2.dispose();
    }
}  

This is a JPanel which you could put into a JFrame and it will look like this...




Hopefully this post will explain better why something like the getColorAt(float fraction) method is really usefull and why i created the LinearGradientPaint2 class.
It safes you a lot of code and gives you a lot of new ways to explore...


Here's another example where i vary the colors of a linear gradient. If you click the link below the image the application will start via webstart...


Webstart link




So enjoy the upcoming weekend and keep coding...




Sunday, May 15, 2011

SteelSeries 3.9.2 update...

This is just a small update of the steelseries library where i added four new backgrounds.

  • PUNCHED_SHEET
  • CARBON
  • MUD
  • ANTHRACITE

Here is a screenshot that shows the new backgrounds...




In addition i made some modifications that make it possible to use the library also on headless systems.


Well...that's all, just would like to let you know...


Enjoy the rest of the weekend...

Wednesday, May 11, 2011

LinearGradientPaint wrapper...

This is just a short post about a little wrapper around the java.awt.LinearGradientPaint class that i created as a helper for the SteelSeries library.
Well my problem was that i would like to create a gradient and after creating it i would like to get a color at a specific fraction. I might be wrong but as far as i know there's no method implemented in the LinearGradientPaint class that could help me here. So i created a little wrapper that wraps the LinearGradientPaint and also contains two additional methods, named getColorAt(float fraction) and getGradient().
The getColorAt(float fraction) method returns the color of the given gradient at the given fraction.
The getGradient() method simply returns the wrapped LinearGradientPaint so that you could set the paint in the Graphics content like: g.setPaint(LGP2.getGradient());


UPDATE:
I implemented the java.awt.Paint interface so that you could use the wrapper like an gradient paint (thx for the comment).


The class contains all constructor methods from the original LinearGradientPaint so that you could create it in the same way as the original.


To give you an idea of what i'm talking about here, a little screenshot might help:




On the screenshot you could see a gradient that i created and i picked the color at the fraction = 0.61.


There might be better solution like this but for me it does the job and if you could use it somewhere...here is the source...
public class LinearGradientPaint2 implements java.awt.Paint
{
    private final java.awt.LinearGradientPaint GRADIENT;
    private float[] fractions;
    private java.awt.Color[] colors;
    
    public LinearGradientPaint2(float startX, float startY, float endX, float endY, float[] fractions, java.awt.Color[] colors)
    {
        GRADIENT = new java.awt.LinearGradientPaint(new java.awt.geom.Point2D.Float(startX, startY), new java.awt.geom.Point2D.Float(endX, endY), fractions, colors, java.awt.MultipleGradientPaint.CycleMethod.NO_CYCLE);
        copyArrays(fractions, colors);
    }
    
    public LinearGradientPaint2(float startX, float startY, float endX, float endY, float[] fractions, java.awt.Color[] colors, java.awt.MultipleGradientPaint.CycleMethod cycleMethod)
    {
        GRADIENT = new java.awt.LinearGradientPaint(new java.awt.geom.Point2D.Float(startX, startY), new java.awt.geom.Point2D.Float(endX, endY), fractions, colors, cycleMethod);
        copyArrays(fractions, colors);
    }

    public LinearGradientPaint2(java.awt.geom.Point2D start, java.awt.geom.Point2D end, float[] fractions, java.awt.Color[] colors)
    {
        GRADIENT = new java.awt.LinearGradientPaint(start, end, fractions, colors, java.awt.MultipleGradientPaint.CycleMethod.NO_CYCLE);
        copyArrays(fractions, colors);
    }
    
    public LinearGradientPaint2(java.awt.geom.Point2D start, java.awt.geom.Point2D end, float[] fractions, java.awt.Color[] colors, java.awt.MultipleGradientPaint.CycleMethod cycleMethod)
    {
        GRADIENT = new java.awt.LinearGradientPaint(start, end, fractions, colors, cycleMethod, java.awt.MultipleGradientPaint.ColorSpaceType.SRGB, new java.awt.geom.AffineTransform());
        copyArrays(fractions, colors);
    }
       
    public LinearGradientPaint2(java.awt.geom.Point2D start, java.awt.geom.Point2D end, float[] fractions, java.awt.Color[] colors, java.awt.MultipleGradientPaint.CycleMethod cycleMethod,  java.awt.MultipleGradientPaint.ColorSpaceType colorSpace, java.awt.geom.AffineTransform gradientTransform)
    {
        GRADIENT = new java.awt.LinearGradientPaint(start, end, fractions, colors, cycleMethod, colorSpace, gradientTransform);
        copyArrays(fractions, colors);
    }
        
    /**
     * Returns the point where the wrapped java.awt.LinearGradientPaint will start
     * @return the point where the wrapped java.awt.LinearGradientPaint will start
     */
    public java.awt.geom.Point2D getStartPoint()
    {
        return GRADIENT.getStartPoint();
    }
    
    /**
     * Returns the point where the wrapped java.awt.LinearGradientPaint will stop
     * @return the point where the wrapped java.awt.LinearGradientPaint will stop
     */
    public java.awt.geom.Point2D getEndPoint()
    {
        return GRADIENT.getEndPoint();
    }
            
    /**
     * Returns the color that is defined by the given fraction in the linear gradient paint
     * @param FRACTION
     * @return the color that is defined by the given fraction in the linear gradient paint
     */
    public java.awt.Color getColorAt(final float FRACTION)
    {
        float fraction = FRACTION > 1 ? 1f : FRACTION;
        fraction = FRACTION < 0 ? 0f : fraction;
        float lowerLimit = 0f;        
        int lowerIndex = 0;
        float upperLimit = 1f;
        int upperIndex = 1;
        int index = 0;
        
        for (float currentFraction : fractions)
        {
            if (Float.compare(currentFraction, fraction) < 0)
            {
                lowerLimit = currentFraction;
                lowerIndex = index;
            }
            if (Float.compare(currentFraction, fraction) == 0)
            {
                return colors[index];
            }
            if (Float.compare(currentFraction, fraction) > 0)
            {
                upperLimit = currentFraction;
                upperIndex = index;
                break;
            }
            index++;
        }
        
        float interpolationFraction = (fraction - lowerLimit) / (upperLimit - lowerLimit);
        
        return interpolateColor(colors[lowerIndex], colors[upperIndex], interpolationFraction);
    }
    
    /**
     * Returns the wrapped java.awt.LinearGradientPaint
     * @return the wrapped java.awt.LinearGradientPaint
     */
    public java.awt.LinearGradientPaint getGradient()
    {
        return GRADIENT;
    }
    
    @Override
    public java.awt.PaintContext createContext(final java.awt.image.ColorModel COLOR_MODEL, final java.awt.Rectangle DEVICE_BOUNDS, java.awt.geom.Rectangle2D USER_BOUNDS, java.awt.geom.AffineTransform X_FORM, java.awt.RenderingHints HINTS)
    {
        return GRADIENT.createContext(COLOR_MODEL, DEVICE_BOUNDS, USER_BOUNDS, X_FORM, HINTS);
    }
 
    @Override
    public int getTransparency()
    {
        return GRADIENT.getTransparency();
    }

    /**
     * Just create a local copy of the fractions and colors array
     * @param fractions
     * @param colors 
     */
    private void copyArrays(final float[] fractions, final java.awt.Color[] colors)
    {
        this.fractions = new float[fractions.length]; 
        System.arraycopy( fractions, 0, this.fractions, 0, fractions.length );
        this.colors = colors.clone();
    }
    
    /**
     * Returns the interpolated color that you get if you multiply the delta between
     * color2 and color1 with the given fraction (for each channel) and interpolation. The fraction should
     * be a value between 0 and 1.
     * @param COLOR1 The first color as integer in the hex format 0xALPHA RED GREEN BLUE, e.g. 0xFF00FF00 for a pure green
     * @param COLOR2 The second color as integer in the hex format 0xALPHA RED GREEN BLUE e.g. 0xFFFF0000 for a pure red
     * @param FRACTION The fraction between those two colors that we would like to get e.g. 0.5f will result in the color 0xFF808000     
     * @return the interpolated color between color1 and color2 calculated by the given fraction and interpolation
     */
    private java.awt.Color interpolateColor(final java.awt.Color COLOR1, final java.awt.Color COLOR2, final float FRACTION)
    {
        assert(Float.compare(FRACTION, 0f) >= 0 && Float.compare(FRACTION, 1f) <= 0);
        
        final float INT_TO_FLOAT_CONST = 1f / 255f;
        
        final float RED1 = COLOR1.getRed() * INT_TO_FLOAT_CONST;
        final float GREEN1 = COLOR1.getGreen() * INT_TO_FLOAT_CONST;
        final float BLUE1 = COLOR1.getBlue() * INT_TO_FLOAT_CONST;
        final float ALPHA1 = COLOR1.getAlpha() * INT_TO_FLOAT_CONST;
        
        final float RED2 = COLOR2.getRed() * INT_TO_FLOAT_CONST;
        final float GREEN2 = COLOR2.getGreen() * INT_TO_FLOAT_CONST;
        final float BLUE2 = COLOR2.getBlue() * INT_TO_FLOAT_CONST;
        final float ALPHA2 = COLOR2.getAlpha() * INT_TO_FLOAT_CONST;
        
        final float DELTA_RED = RED2 - RED1;
        final float DELTA_GREEN = GREEN2 - GREEN1;
        final float DELTA_BLUE = BLUE2 - BLUE1;
        final float DELTA_ALPHA = ALPHA2 - ALPHA1;
        
        float red = RED1 + (DELTA_RED * FRACTION);
        float green = GREEN1 + (DELTA_GREEN * FRACTION);
        float blue = BLUE1 + (DELTA_BLUE * FRACTION);
        float alpha = ALPHA1 + (DELTA_ALPHA * FRACTION);
        
        red = red < 0f ? 0f : red;
        red = red > 1f ? 1f : red;
        green = green < 0f ? 0f : green;
        green = green > 1f ? 1f : green;
        blue = blue < 0f ? 0f : blue;
        blue = blue > 1f ? 1f : blue;
        alpha = alpha < 0f ? 0f : alpha;
        alpha = alpha > 1f ? 1f : alpha;
        
        return new java.awt.Color(red, green, blue, alpha);        
    }
}
     
To give you an idea on where i will use this helper class, let me explain an example.
If i have a linear gauge and the color of the column (which represents the current value of the gauge) should fade through different colors from the minimum to the maximum value it would be nice if i could create the underlying linear gradient once and pick the current color of the column dependent on the current value of the linear gauge.


That's all for today (to be honest it was more a little reminder that i have to implement the feature i described above to the linear gauge).


So keep coding...



Friday, May 6, 2011

Grinded steel plate effect

On my way back from the JAX conference in Mainz last tuesday i saw a stainless steel plate on the train that looked like on this image here. In german this treatment of metal has the name "Zapfenschliff" and is used to give the metal a nice design and a more robust surface.
Taking a closer look to the plate it reminds me on the conical gradient that i created a while ago and in fact it's just a simple pattern made out of many conical gradients.
Well you know me...i have to reproduce it in swing and voila here's a little tutorial on how i realized it. So the principle approach is to create a texture and use this texture to fill some shape with it.
Now you could argue that i simply could take an exsting texture and use it to fill the shape but i like to create the stuff completely in 100% pure Java right...

So first of all we need to create a conical gradient like the following:


And here is the code you need to create a gradient like this...

double diameter = 50;
Ellipse2D circle = new Ellipse2D.Double(0, 0, diameter, diameter);
Point2D center = new Point2D.Double(circle.getCenterX(), circle.getCenterY());
float[] fractions =  
{
    0f,
    0.03f,
    0.10f,
    0.14f,
    0.24f,
    0.33f,
    0.38f,
    0.5f,
    0.62f,
    0.67f,
    0.76f,
    0.81f,
    0.85f,
    0.97f,
    1.0f 
};

Color[] colors = 
{ 
    new Color(0xFDFDFD),
    new Color(0xFDFDFD),
    new Color(0xB2B2B4),
    new Color(0xACACAE),
    new Color(0xFDFDFD),
    new Color(0x6E6E70),
    new Color(0x6E6E70),
    new Color(0xFDFDFD),
    new Color(0x6E6E70),
    new Color(0x6E6E70),
    new Color(0xFDFDFD),
    new Color(0xACACAE),
    new Color(0xB2B2B4),
    new Color(0xFDFDFD),
    new Color(0xFDFDFD) 
};    
ConicalGradientPaint gradient = new ConicalGradientPaint(false, center, -0.45f, fractions, colors);
G2.setPaint(gradient);
G2.fill(circle);

After this we need to create a texture that contains a repeatable pattern of the conical gradient. I created a little drawing to make it easier to understand...



The texture (which will be represented by a BufferedImage object) should be a square rectangle with the given SIZE. In this case i used 2x the diameter of the conical gradient. As you can see we need 13 circles that have to be placed in a pattern where we place 3 circles in the first row, 2 circles in the second row, 3 circles in the third row and so on. The stepsize in x- and y-direction is half the size of the diameter and we start on the upper left corner at x=-stepsize, y=-stepsize.
Here is the code for the creation of the texture...


int amount = 3;
double stepsize = diameter / 2.0;
G2.translate(-stepsize, -stepsize);
AffineTransform oldTransform = G2.getTransform();
for (int y = 0 ; y < 5 ; y++)
{            
    if (y%2 == 0)
    {
        amount = 3;
        G2.translate(0, stepsize * y);
    }
    else
    {
        amount = 2;
        G2.translate(stepsize, stepsize * y);
    }
                                                
    for (int x = 0 ; x < amount ; x++)
    {
        G2.setPaint(gradient);
        G2.fill(circle);
        G2.translate(diameter, 0);                
    }                                    
    G2.setTransform(oldTransform);            
}         


After we have create the BufferedImage object we can use it as a texture in the java.awt.TexturePaint class to fill a shape. And the result could look like this...




On this image we filled a square with four textures but the image was created in Adobe Fireworks, the Java Swing version would look like this...




Fun isn't it ? Well the only problem with this texture is that it looks too perfect right but this is something i'll leave to you...   :-)


As always you will find the sourcecode for this little fun project as a Netbeans project...


SteelPaint.zip


Enjoy your weekend and keep coding...just for the fun of it...

Wednesday, May 4, 2011

SteelSeries 3.9

It's time again for another release of the SteelSeries library. 


This release will break the compatibility to older versions !


First of all i switched the version of the animation library trident from version 1.2 (which was created by Kirill Grouchnikov) to trident 6.2 which is based on a fork of Danno Ferrin. I did this because Kirill stopped supporting the original files and Danno created an updated version which is also available on maven central. So this should lead to no problems but maybe some new features in the future...who knows.
The second modification which is the one that breaks the downwards compatibility is related the the tickmarks of the gauges. Right after starting the SteelSeries project i figured out that the method that created to draw the tickmarks of the gauges was not very flexible which leads to some strange effects sometimes. If the range of values was very small (0 - 1) or if you have fractional labels like 0.0, 0.25, 0.5, 0.75... or also very large values you could see what i mean. With the help of Thomas Steinbach i tweaked the method in a way that it was able to do the job (as good as possible). But at some point the whole method looked so ugly to me that i decided to create a new algorithm to solve the problems. 
Fortunately there was already an algorithm that looked much better and is much more flexible so that i implemented it to the library. Steffen L. Norgren already converted this algorithm into Java code which made the transition much easier. Steffen also linked to two articles where you will find a more detailed explanation of the problems that you face when creating scale bars.


To give you an idea what i'm talking about here i made some screenshots:


Left: min = 0, max = 1.5   Center: min = 0, max = 12000   Right: min = 0, max = 12000


Left: min = 0, max = 1.5   Center: min = 0, max = 12000   Right: min = 0, max = 12000


As you can see on the images above the old version (prior 3.9) was not able to handle small ranges and with large ranges you had the problem with large tickmark labels.
Well the new version uses a complete different approach, now one could define how many major tickmarks and how many minor tickmarks one would like to use and a little routine will calculate nice values for the minimum, maximum and the ticklabels. 
Another thing which i added to the 3.9 release is the possibility to use different formats for the tickmark labels.

  • AUTO
  • STANDARD
  • FRACTIONAL
  • SCIENTIFIC
  • PERCENTAGE

This makes it possible to also handle large numbers tickmark labels. The automatic mode tries to figure out the best number format but you could also select one manualy. Here is a screenshot of some examples:




Due to a lack of time i was not able to add logarithmic scaling to this release but i'm definitly working on it.


Another minor feature that i have added to this release is a new background named "STAINLESS". The idea was born when i blogged about custom backgrounds in october 2010 and used a ConicalGradient to visualize a stainless background. In the meantime JIDE Software released a copy of that idea with their latest release of their components and so i thought fair to add it to the library too. 
It might not be very useful but looks impressive doesn't it...




There are two other modifications that i made to existing components.
The Linear and LinearBargraph component does now support TickmarkSections which looks like this...


In addition the Linear component is now also able to handle Sections. If one defines sections with different colors for each section the color of the bar will switch to the color that is defined in the active section. 


But that's old stuff, let's talk about something new...


Fabian David Carmargo asked me for some components and could not withstand to implement them into the library, so here we go.


The first thing he asked me for was a rectangular LED and so i created one...




The LED component in the package eu.hansolo.steelseries.extras now has a property named "ledType" which could be ROUND, RECT_VERTICAL or RECT_HORIZONTAL. If you ask yourself why i named it RECT_VERTICAL and RECT_HORIZONTAL.....there might be more geometric shapes of led's in the future... :-)


The other thing Fabian asked me for was a set of components that he needs to visualize a cockpit of a car...which means lot's of symbols...
First i was not sure if i really should add all this stuff to the library but after all...why not having some fun...so here it is the INDICATOR component with all it's different symbols...




Doesn't look very spectacular right...but believe me it was a lot of work to create all these symbols. As you might have noticed the component uses the same background, frame, foreground property as the radial components and this is because it's derived from AbstractRadial. This means you could use the same design for the INDICATOR component as you use for the gauges. You could also use the given colors to visualize the symbols, here is an example of all available colors...




As always you could also use CUSTOM as onColor and define your own customOnColor. The same is possible for the offColor property of the INDICATOR component.


For this release that's all i have to say but i have also created a little step-by-step-guide on how to add the SteelSeries components to your Netbeans IDE component palette because i've got questions about how to do that.


Well...that's it for today...keep coding and enjoy the upcoming summer...