Thursday, March 10, 2016

Friday Fun XXV

And Friday again...means time for some fun... :)
This time I have two three (I've recently added a ColorRegulator) controls for you. When I was working on my mood light I stumbled upon some nice images on the web and one of those image was the following that I've found on Dribbble...

The temperature control on the right side of the image looked nice to me and I thought it might be worth creating a JavaFX control of it.
The control above only acts as some kind of slider which shows the target value but I thought by myself it would be nice it would also show the current value. Because then one can use it also as a display of the current temperature. So here is what I came up with...

As you can see it's really similar to the original image except some additional features...
  • Target value will be shown on top
  • Icon to visualize the property
  • An overlay on the color bar that shows the current value
The target value and the overlay will disappear as soon as the (int) current value == (in) target value.
When I've started this control I only thought about a temperature control but you can use it for whatever you like. Therefore I've added the possibility to set a custom color gradient for the bar and you could also define your own icon. 
The control will fire three different events
  • RegulatorEvent.TARGET_SET  fired when target value was set (Mouse released)
  • RegulatorEvent.ADJUSTING    in case the (int) current value != (int) target value
  • RegulatorEvent.ADJUSTED      in case the (int) current value == (int) target value
With this you could also use the control to define a point on the scale by using the rotation ring and as soon as the current value will reach the selected value it will fire an event on which you can could think about a battery charger control that informs you if the battery is charged to 80%.
If we take the charger example let's have a look how to configure the control in this case...
FeedbackRegulator feedbackRegulator = 
                            .prefSize(400, 400)
                            .gradientStops(new Stop(0.0, Color.RED),
                                     new Stop(0.5, Color.YELLOW),
                                     new Stop(0.75, Color.GREEN),
                                     new Stop(1.0, Color.LIME))
                            .symbolPath(1, 0.71428571, "M 11.7829 11.7647 L 9.3333 20 L 17.5 8.2353 L 12.7171 " +
                                                       "8.2353 L 15.1667 0 L 7 11.7647 L 11.7829 11.7647 ZM 1.1667 " +
                                                       "17.6471 L 8.8138 17.6471 L 9.5156 15.2941 L 2.3333 15.2941 " +
                                                       "L 2.3333 4.7059 L 10.4749 4.7059 L 12.1087 2.3529 L 1.1667 " +
                                                       "2.3529 C 0.5218 2.3529 0 2.8791 0 3.5294 L 0 16.4706 C 0 " +
                                                       "17.1209 0.5218 17.6471 1.1667 17.6471 ZM 26.8333 5.8824 L " +
                                                       "24.5 5.8824 L 24.5 3.5294 C 24.5 2.8791 23.9782 2.3529 23.3333" +
                                                       " 2.3529 L 15.6839 2.3529 L 14.9844 4.7059 L 22.1667 4.7059 " +
                                                       "L 22.1667 15.2941 L 14.0228 15.2941 L 12.3913 17.6471 " +
                                                       "L 23.3333 17.6471 C 23.9782 17.6471 24.5 17.1209 24.5 16.4706 " +
                                                       "L 24.5 14.1176 L 26.8333 14.1176 C 27.4782 14.1176 28 13.5915 " +
                                                       "28 12.9412 L 28 7.0588 C 28 6.4085 27.4782 5.8824 26.8333 5.8824 Z")

As you can see we can define the min- and maxValue of the control, the unit and the stops for the gradient bar. In addition we can define the symbolPath which is a SVG path and to get the scaling right we also have to define the scaleX and scaleY values for this path.
To get this path you usually use a vector drawing program like Inkscape, Adobe Illustrator etc. and export the vector drawing of the icon as SVG file. Usually you will find a <path> tag in the SVG file that should look similar to the above string. Simply copy that string that normally starts with a M for MoveTo and ends with a Z for ClosePath. To get the scaling right you simply have to calculate the scaling factor from the size of the image, e.g. the charging battery icon that I used here has the following size...

width : 28px
height: 20px

Divide the smaller value by the bigger value and set the bigger value to 1.0. This will give us the following values...

scaleY: 20 / 28 = 0.71428571
scaleX: 1.0

That's all you need to set your customized icon in the control and the result of the code above will look like this...

In this case we could also hook up an EventHandler to the FeedbackEvent.ADJUSTED EventType that will be fired as soon as the battery will be charged by 80%. To realize that you can simply add one line to the builder like follows...
.onAdjusted(e -> System.out.println("Battery charge is 80%"))
But you could also attach the handler later on in your code like follows
feedbackRegulator.addEventHandler(RegulatorEvent.ADJUSTED, event -> System.out.println("Battery charge is 80%"));
So far so good but now that I had a control with a ring to set values I thought it might also be useful to have a similar control that really only acts as some kind of a slider.
Long story it is...

As you can see it's very similar to the other control except it can't visualize a current value but only the target value. So you can use it to control for example the brightness of a light etc.
In principle it comes with the same features as the FeedbackRegulator control except the gradient stops and the current value. But it has an additional property which is the barColor. So to create a control with the custom icon you can simply use the same approach as for the FeedbackRegulator. Here is a little example with a different bar color and a unit...
Regulator regulator = RegulatorBuilder.create()
                                      .prefSize(400, 400)
                                      .barColor(Color.rgb(255, 222, 102))
And the result will look like this...

I did not implement properties for different colors of the ring, background etc. but if you are interested in changing it I (in the meantime I've added features to change the control color, text color and symbol color.)...fork it on github :)

Here is a screenshot of the currently available regulator controls...

As you can see on the right I've also added another color selector :)

That's it for keep coding...