digal
A customizable, scalable JavaFX rotary dial.
Features
- CSS-styleable rotary dials
- Scalable to any size
- OSGi-ready
- JPMS-ready
- High coverage automated test suite
- ISC license
Maven
<dependency>
<groupId>com.io7m.digal</groupId>
<artifactId>com.io7m.digal.core</artifactId>
<version>${latest}</version>
</dependency>
Dials
A dial is a rotary knob seen on hardware such as guitar amplifiers, mixing desks, and etc.
In digal
, a dial carries a real value in the range [0, 1]
where 0
means "
turned fully anti-clockwise" and 1
means "turned fully clockwise". Each dial
can be provided with a value converter that converts this internal value to
something else for display purposes.
Dials are constrained to a 270°
range in order to unambiguously indicate the
current value at a glance.
Visually, a dial consists of the following components:
- The indicator is a small notch on the dial that shows which direction the dial is pointing.
- The radial gauge is a filled-in arc segment showing how far away the current dial setting is from the minimum.
- The tick marks are small marks around the dial that can be used to indicate discrete values. The number of tick marks can be customized.
- The shade emulates the way dials are often recessed into hardware. The shade can be disabled.
- The body is the actual physical dial.
The text field below the dial is not part of the dial itself, and is a plain text field bound the dial value for demonstration purposes.
Dials are manipulated by clicking the body and dragging upwards and downwards on the Y axis. Dragging upwards turns the dial clockwise, and dragging downwards turns the dial anti-clockwise.
Value Converters
As mentioned, dials use real values in the range [0,1]
. A dial instance
can be provided with a value converter that allows for converting internal
values to something else for use externally. The package comes with a number
of built-in converters, organized into real and discrete converters. A
real converter maps dial values in the range [0, 1]
to a user-defined
range of real numbers. A discrete converter maps dial values in the range
[0, 1]
to a user-defined range of integers.
dial0.setValueConverter(
new DialValueConverterRealType()
{
@Override
public double convertToDial(
final double x)
{
return x / 12.0;
}
@Override
public double convertFromDial(
final double x)
{
return (double) Math.round(x * 12.0);
}
@Override
public double convertedNext(
final double x)
{
return x + 0.5;
}
@Override
public double convertedPrevious(
final double x)
{
return x - 0.5;
}
});
Note that it would probably also be a good idea to set the number of tick
marks to 12
:
dial0.setTickCount(12);
Data Flow
Some applications may choose to use dials both as a data display and a data
input. For example, a user interface that controls an external audio device
might want dials to always match the state of the external device, but also
need to be adjustable by the user turning the dial onscreen. The dials are
typically configured with a ChangeListener
that is invoked when the user
turns the dial that submits commands to update the external device. Additionally,
the dials are usually set to particular values when state updates are received
from the external device. This can cause a problem due to a circular data
dependency:
- The user turns a dial.
- The
ChangeListener
on the dial sees the dial value change and submits a command to update the value on the external device. - The external device returns the newly set value.
- The dial is updated with the new value.
- The
ChangeListener
on the dial sees the dial value change and submits a command to update the value on the external device. - The external device returns the newly set value...
This problem is sometimes mitigated by the fact that setting a JavaFX property
to a value to which it is already set doesn't result in observers of the
property being called. This isn't always reliable, however, and so the
digal
API provides "quiet" versions of the commands to update dials that
break the cycle of observer updates.
The setRawValueQuietly
and setConvertedValueQuietly
commands will set
the value of a dial and update the dial's UI, but will not call any observers
of the dial's value property.
In the scenario described above, state updates that come from the external
audio device should set dial values using set*Quietly
so that the state
updates do not cause more commands to be submitted to the device.
CSS
The dial components can be customized to some extent with CSS. Assuming
a dial with id #dial0
, the following CSS will produce an ugly looking dial:
#dial0
{
dial-body-color: #30a030;
dial-body-stroke-color: #0000ff;
dial-emboss-color: #00000030;
dial-emboss-size: 4.0;
dial-indicator-color: #00ffff;
dial-indicator-size: 3.0;
dial-radial-gauge-color: #ff00ff;
dial-radial-gauge-size: 12.0;
dial-shade-color: #ff000050;
dial-tick-color: #ff0000;
dial-tick-size: 1.0;
}
Releases & Development Snapshots
Releases
You can subscribe to the atom feed to be notified of project releases.
The most recently released version of the package is 1.0.0.
1.0.0 Release (2024-05-16Z)
- Initial public release.
The compiled artifacts for the release (and all previous releases) are available on Maven Central.
Maven Modules
<dependency> <group>com.io7m.digal</group> <artifactId>com.io7m.digal.core</artifactId> <version>1.0.0</version> </dependency><dependency> <group>com.io7m.digal</group> <artifactId>com.io7m.digal.tests</artifactId> <version>1.0.0</version> </dependency>
Development Snapshots
At the time of writing, the current unstable development version of the package is 1.0.1-SNAPSHOT.
Development snapshots may be available in the Central Portal Snapshots repository. Snapshots are published to this repository every time the project is built by the project's continuous integration system, but snapshots do expire after around ninety days and so may or may not be available depending on when a build of the package was last triggered.
Manual
This project does not have any user manuals or other documentation beyond what might be present on the page above.
Sources
This project uses Git to manage source code.
Repository: https://www.github.com/io7m-com/digal
$ git clone --recursive https://www.github.com/io7m-com/digal
Issues
This project uses GitHub Issues to track issues.
License
Copyright © 2023 Mark Raynsford <code@io7m.com> https://www.io7m.com Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.