Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/kmcaster.git

Refactor autofit label creation, pass modifier name as its label value

Author DaveJarvis <email>
Date 2020-07-23 19:32:51 GMT-0700
Commit 60b35796349e2e757ba170d9ef5f84ead6955b83
Parent f9402e1
src/main/com/whitemagicsoftware/kmcaster/EventHandler.java
hwSwitch, hwState, switchValue );
- // Clear the text before redrawing to prevent discord between the
- // label colour and the hardware switch's background.
- if( switchState.isSwitchState( SWITCH_RELEASED ) ) {
- getHardwareComponent( switchState ).removeAll();
- }
-
updateSwitchState( switchState );
if( state.isModifier() ) {
- final var hwSwitch = state.getHardwareSwitch();
- final var switchName = hwSwitch.toTitleCase();
-
- final var label = new AutofitLabel( switchName, LABEL_FONT, keyColour );
- label.setVisible( false );
- label.setHorizontalAlignment( CENTER );
- label.setVerticalAlignment( CENTER );
- container.removeAll();
- container.add( label );
- label.setVisible( true );
+ updateLabel( state, keyColour );
}
else if( state.isSwitchState( SWITCH_PRESSED ) ) {
// Label for "Num", "Back", "Tab", and other dual-labelled keys.
- final var sup = new AutofitLabel( s[ 0 ], LABEL_FONT, keyColour );
+ final var sup = new AutofitLabel( s[ 0 ], LABEL_FONT );
sup.setVisible( false );
+ sup.setForeground( keyColour );
sup.setVerticalAlignment( TOP );
// Label for number pad keys or icon glyphs.
- final var main = new AutofitLabel( s[ 1 ], LABEL_FONT, keyColour );
+ final var main = new AutofitLabel( s[ 1 ], LABEL_FONT );
main.setVisible( false );
+ main.setForeground( keyColour );
main.setHorizontalAlignment( CENTER );
main.setVerticalAlignment( CENTER );
}
else {
- // Single keys need no tweaking and can be added to the container
- // directly. The horizontal and vertical alignments
- final var label = new AutofitLabel( keyValue, LABEL_FONT, keyColour );
- label.setVisible( false );
- label.setHorizontalAlignment( CENTER );
- label.setVerticalAlignment( CENTER );
container.removeAll();
- container.add( label );
- label.setVisible( true );
+ updateLabel( state, keyColour );
}
+ }
+ else {
+ container.removeAll();
+ }
+ }
+
+ /**
+ * Creates the label if it does not already exist.
+ *
+ * @param state The state of the hardware switch to look up.
+ */
+ private void updateLabel(
+ final HardwareSwitchState state,
+ final Color keyColour ) {
+ final var container = getHardwareComponent( state );
+ final var value = state.getValue();
+ final AutofitLabel label;
+
+ if( container.getComponentCount() == 0 ) {
+ // Regular keys will have labels recreated each time to auto-fit the text.
+ label = new AutofitLabel( value, LABEL_FONT );
+ label.setHorizontalAlignment( CENTER );
+ label.setVerticalAlignment( CENTER );
+ label.setForeground( keyColour );
+ container.add( label );
+ }
+ else {
+ // Modifier keys can reuse labels.
+ label = (AutofitLabel) container.getComponent( 0 );
+ label.setForeground( keyColour );
+ label.setText( value );
}
}
private HardwareComponent<HardwareSwitchState, Image> getHardwareComponent(
final HardwareSwitchState state ) {
return mHardwareImages.get( state.getHardwareSwitch() );
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getName() + "{" +
+ "mHardwareImages=" + mHardwareImages +
+ '}';
}
}
src/main/com/whitemagicsoftware/kmcaster/HardwareComponent.java
import static com.whitemagicsoftware.kmcaster.ui.Constants.INSETS_EMPTY;
-import static com.whitemagicsoftware.kmcaster.ui.Constants.TRANSPARENT;
/**
public HardwareComponent() {
this( INSETS_EMPTY );
- setBackground( TRANSPARENT );
- setOpaque( false );
}
@Override
protected void paintComponent( final Graphics graphics ) {
- super.paintComponent( graphics );
-
- final var g = (Graphics2D) graphics.create();
+ final var g = graphics.create();
g.drawImage( getActiveImage(), 0, 0, this );
+ g.dispose();
}
getStateImages().put( state, image );
- // No need to issue a repaint request, change the state directly.
+ // Change the state variable directly, no need to issue a repaint request.
mState = state;
}
src/main/com/whitemagicsoftware/kmcaster/HardwareState.java
SWITCH_RELEASED;
- private final static String BOOLEAN_FALSE = FALSE.toString();
+ /**
+ * Convenience constant.
+ */
+ public final static String BOOLEAN_FALSE = FALSE.toString();
/**
src/main/com/whitemagicsoftware/kmcaster/HardwareSwitchState.java
* was pressed.
*
- * @param hardwareSwitch A {@link HardwareSwitch} that represents the type of
- * switch having the given status.
- * @param hardwareState Defines whether the switch is pressed or released.
- * @param value The value associated with the switch in the given
- * state. For example, this could be human-readable
- * text representing a pressed key code.
+ * @param hwSwitch A {@link HardwareSwitch} that represents the type of
+ * switch having the given status.
+ * @param hwState Defines whether the switch is pressed or released.
+ * @param value The value associated with the switch in the given
+ * state. For example, this could be human-readable
+ * text representing a pressed key code.
*/
public HardwareSwitchState(
- final HardwareSwitch hardwareSwitch,
- final HardwareState hardwareState,
+ final HardwareSwitch hwSwitch,
+ final HardwareState hwState,
final String value ) {
- assert hardwareSwitch != null;
- assert hardwareState != null;
+ assert hwSwitch != null;
+ assert hwState != null;
assert value != null;
- mHardwareSwitch = hardwareSwitch;
- mHardwareState = hardwareState;
- mValue = value;
+ mHardwareSwitch = hwSwitch;
+ mHardwareState = hwState;
+ mValue = hwSwitch.isModifier() ? hwSwitch.toTitleCase() : value;
}
result = 31 * result + mHardwareState.hashCode();
return result;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getName() + "{" +
+ "mHardwareSwitch=" + mHardwareSwitch +
+ ", mHardwareState=" + mHardwareState +
+ ", mValue='" + mValue + '\'' +
+ '}';
}
}
src/main/com/whitemagicsoftware/kmcaster/SvgRasterizer.java
import com.kitfox.svg.SVGException;
import com.kitfox.svg.SVGUniverse;
-import com.whitemagicsoftware.kmcaster.ui.ScalableDimension;
import com.whitemagicsoftware.kmcaster.ui.DimensionTuple;
+import com.whitemagicsoftware.kmcaster.ui.ScalableDimension;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.Map;
import static java.awt.RenderingHints.*;
-import static java.awt.image.BufferedImage.TYPE_INT_ARGB;
+import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR;
/**
final var wScaled = (int) scaled.getWidth();
final var hScaled = (int) scaled.getHeight();
- final var image = new BufferedImage( wScaled, hScaled, TYPE_INT_ARGB );
+ final var image = new BufferedImage( wScaled, hScaled, TYPE_4BYTE_ABGR );
final var graphics = image.createGraphics();
graphics.setRenderingHints( RENDERING_HINTS );
src/main/com/whitemagicsoftware/kmcaster/listeners/FrameDragListener.java
public void mouseDragged( final MouseEvent e ) {
- final Point dragCoordinates = e.getLocationOnScreen();
- mFrame.setLocation( dragCoordinates.x - mCoordinates.x,
- dragCoordinates.y - mCoordinates.y );
+ // Race-condition guards.
+ final var frame = mFrame;
+ final var coordinates = mCoordinates;
+
+ // Used to calculate delta between current and previous mouse position.
+ final var dragCoordinates = e.getLocationOnScreen();
+
+ if( frame != null && coordinates != null ) {
+ frame.setLocation( dragCoordinates.x - coordinates.x,
+ dragCoordinates.y - coordinates.y );
+ }
}
}
src/main/com/whitemagicsoftware/kmcaster/listeners/KeyboardListener.java
import java.util.Map;
+import static com.whitemagicsoftware.kmcaster.HardwareState.BOOLEAN_FALSE;
import static com.whitemagicsoftware.kmcaster.HardwareSwitch.*;
-import static java.lang.Boolean.FALSE;
import static java.util.Map.entry;
import static org.jnativehook.keyboard.NativeKeyEvent.getKeyText;
@Override
public void nativeKeyReleased( final NativeKeyEvent e ) {
- updateRegular( getDisplayText( e ), FALSE.toString() );
+ updateRegular( getDisplayText( e ), BOOLEAN_FALSE );
updateModifiers( e );
}
final var state = mSwitches.get( key );
- // By default, the keys are all "false", so fire fake events indicating
- // that has one has just transitioned to "false". This will cause the
- // GUI to repaint with the text label affixed to each key, drawn in the
- // released state. This happens before the frame is set to visible.
+ // All modifiers keys are "false" by default, so firing fake transition
+ // events from "true" to "false" will cause the GUI to repaint with the
+ // text label affixed to each key, drawn in the released state. This
+ // happens before the frame is set to visible.
tryFire( key, !state, state );
}
src/main/com/whitemagicsoftware/kmcaster/ui/AutofitLabel.java
* </p>
*
- * @param text The text to write on the container's graphics context.
- * @param font The font to use when writing the text.
- * @param color The colour to use when writing hte text.
+ * @param text The text to write on the container's graphics context.
+ * @param font The font to use when writing the text.
*/
- public AutofitLabel( final String text, final Font font, final Color color ) {
+ public AutofitLabel( final String text, final Font font ) {
super( text );
setDoubleBuffered( true );
setFont( font );
- setForeground( color );
addHierarchyListener( e -> {
float scaledPt = scaledFont.getSize();
- while( maxSizePt - minSizePt > 1f ) {
- scaledFont = scaledFont.deriveFont( scaledPt );
+ // TextLayout cannot suffer null or empty values, so return the default
+ // font size if the label is cleared out.
+ if( text != null && !text.isEmpty() ) {
+ while( maxSizePt - minSizePt > 1f ) {
+ scaledFont = scaledFont.deriveFont( scaledPt );
- final var layout = new TextLayout( text, scaledFont, frc );
- final var metrics = scaledFont.getLineMetrics( text, frc );
- final var fontWidthPx = layout.getVisibleAdvance();
- final var fontHeightPx = metrics.getHeight();
+ final var layout = new TextLayout( text, scaledFont, frc );
+ final var metrics = scaledFont.getLineMetrics( text, frc );
+ final var fontWidthPx = layout.getVisibleAdvance();
+ final var fontHeightPx = metrics.getHeight();
- if( (fontWidthPx > dstWidthPx) || (fontHeightPx > dstHeightPx) ) {
- maxSizePt = scaledPt;
- }
- else {
- minSizePt = scaledPt;
- }
+ if( (fontWidthPx > dstWidthPx) || (fontHeightPx > dstHeightPx) ) {
+ maxSizePt = scaledPt;
+ }
+ else {
+ minSizePt = scaledPt;
+ }
- scaledPt = (minSizePt + maxSizePt) / 2;
+ scaledPt = (minSizePt + maxSizePt) / 2;
+ }
}
src/main/com/whitemagicsoftware/kmcaster/ui/Constants.java
* Application dimensions in pixels. Images are scaled to these dimensions,
* maintaining aspect ratio. The height constrains the width, so as long as
- * the width is sufficiently large, the application's window will adjust to
- * fit.
+ * the width is large enough, the application's window will adjust to fit.
*/
public static final Dimension APP_DIMENSIONS = new Dimension( 1024, 90 );
Delta 114 lines added, 79 lines removed, 35-line increase