Dave Jarvis' Repositories

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

Introduce tuple concepts to bind image and its scale factor

Author DaveJarvis <email>
Date 2020-07-19 20:25:57 GMT-0700
Commit 897e2e5ffb05a8555e8da41227633b6fbcab76bb
Parent 0cc89ce
src/main/com/whitemagicsoftware/kmcaster/HardwareComponent.java
*/
public class HardwareComponent<S, I extends Image> extends JComponent {
- private final static Insets INSET_PROJECTED =
- new Insets( 3, 7, 6, 7 );
+ /**
+ * Default insets, has no padding.
+ */
+ private final static Insets INSETS_EMPTY =
+ new Insets( 0, 0, 0, 0 );
private final Map<S, I> mStateImages = new HashMap<>();
/**
- * Active state.
+ * State that corresponds with the {@link Image} to paint.
*/
private S mState;
+
+ /**
+ * Available space on the image for drawing. This
+ */
+ private final Insets mInsets;
/**
* Constructs a new {@link HardwareComponent} without an initial state. The
* initial state must be set by calling {@link #setState(Object)} before
* drawing the image.
*/
public HardwareComponent() {
+ this( INSETS_EMPTY );
}
- /**
- * Associates a new (or existing) state with the given image. If the
- * state already exists for the image, the image is updated for that
- * state. After calling this method, the active state changes to the
- * given state as a convenience.
- *
- * @param state The state to associate with an image.
- * @param image The image to paint when the given state is selected.
- */
- public void put( final S state, final I image ) {
- getStateImages().put( state, image );
- setState( state );
+ public HardwareComponent( final Insets insets ) {
+ mInsets = insets;
}
@Override
public Insets getInsets() {
- return INSET_PROJECTED;
+ return mInsets;
}
@Override
protected void paintComponent( final Graphics graphics ) {
super.paintComponent( graphics );
final var g = (Graphics2D) graphics.create();
g.drawImage( getActiveImage(), 0, 0, this );
+ }
+
+ /**
+ * Associates a new (or existing) state with the given image. If the
+ * state already exists for the image, the image is updated for that
+ * state. After calling this method, the active state changes to the
+ * given state as a convenience.
+ *
+ * @param state The state to associate with an image.
+ * @param image The image to paint when the given state is selected.
+ */
+ public void put( final S state, final I image ) {
+ getStateImages().put( state, image );
+ setState( state );
}
src/main/com/whitemagicsoftware/kmcaster/HardwareImages.java
package com.whitemagicsoftware.kmcaster;
+import com.whitemagicsoftware.kmcaster.ui.DimensionTuple;
+import com.whitemagicsoftware.kmcaster.util.Pair;
+
import java.awt.*;
import java.util.HashMap;
import java.util.Map;
import static com.whitemagicsoftware.kmcaster.HardwareState.ANY_KEY;
import static com.whitemagicsoftware.kmcaster.HardwareSwitch.*;
import static com.whitemagicsoftware.kmcaster.exceptions.Rethrowable.rethrow;
+import static java.lang.Boolean.FALSE;
+import static java.lang.Boolean.TRUE;
import static java.lang.String.format;
* large, the application's window will adjust to fit.
*/
- private final Dimension mDimension = new Dimension( 1024, 60 );
+ private final Dimension mDimension = new Dimension( 1024, 120 );
- /**
- * Constructs an enumerated type that represents the different types of
- * images shown when keyboard and mouse events are triggered.
- */
public HardwareImages() {
- final var mouseStates = new HardwareComponent<HardwareState, Image>();
+ final var mouseStates = createHardwareComponent();
for( int i = 1; i <= 3; i++ ) {
final var s = Integer.toString( i );
mouseStates.put( state( MOUSE, s ), mouseImage( s ) );
}
mouseStates.put( state( MOUSE, "1-3" ), mouseImage( "1-3" ) );
- mouseStates.put( state( MOUSE, false ), mouseImage( "0" ) );
+ mouseStates.put( state( MOUSE, FALSE.toString() ), mouseImage( "0" ) );
mSwitches.put( MOUSE, mouseStates );
- final var altStates = new HardwareComponent<HardwareState, Image>();
- altStates.put( state( KEY_ALT, true ), keyDnImage( "medium" ) );
- altStates.put( state( KEY_ALT, false ), keyUpImage( "medium" ) );
- mSwitches.put( KEY_ALT, altStates );
+ final var fileNamePrefixes = Map.of(
+ KEY_ALT, "medium",
+ KEY_CTRL, "medium",
+ KEY_SHIFT, "long",
+ KEY_REGULAR, "short"
+ );
- final var ctrlStates = new HardwareComponent<HardwareState, Image>();
- ctrlStates.put( state( KEY_CTRL, true ), keyDnImage( "medium" ) );
- ctrlStates.put( state( KEY_CTRL, false ), keyUpImage( "medium" ) );
- mSwitches.put( KEY_CTRL, ctrlStates );
+ for( final var key : HardwareSwitch.keyboardKeys() ) {
+ final var hardwareComponent = createHardwareComponent();
+ final var stateNameOn = key == KEY_REGULAR ? ANY_KEY : TRUE.toString();
- final var shiftStates = new HardwareComponent<HardwareState, Image>();
- shiftStates.put( state( KEY_SHIFT, true ), keyDnImage( "long" ) );
- shiftStates.put( state( KEY_SHIFT, false ), keyUpImage( "long" ) );
- mSwitches.put( KEY_SHIFT, shiftStates );
+ final var stateOn = state( key, stateNameOn );
+ final var stateOff = state( key, FALSE.toString() );
+ final var imageDn = keyDnImage( fileNamePrefixes.get( key ) );
+ final var imageUp = keyUpImage( fileNamePrefixes.get( key ) );
- final var regularStates = new HardwareComponent<HardwareState, Image>();
- regularStates.put( state( KEY_REGULAR, ANY_KEY ), keyDnImage( "short" ) );
- regularStates.put( state( KEY_REGULAR, false ), keyUpImage( "short" ) );
- mSwitches.put( KEY_REGULAR, regularStates );
+ hardwareComponent.put( stateOn, imageDn.getKey() );
+ hardwareComponent.put( stateOff, imageUp.getKey() );
+
+ mSwitches.put( key, hardwareComponent );
+ }
+ }
+
+ private HardwareComponent<HardwareState, Image> createHardwareComponent() {
+ return new HardwareComponent<>();
}
public HardwareComponent<HardwareState, Image> get(
final HardwareSwitch hwSwitch ) {
return mSwitches.get( hwSwitch );
- }
-
- private HardwareState state(
- final HardwareSwitch name, final boolean state ) {
- return state( name, Boolean.toString( state ) );
}
private HardwareState state(
final HardwareSwitch name, final String state ) {
return new HardwareState( name, state );
}
private Image mouseImage( final String prefix ) {
- return createImage( format( "%s/%s", DIR_IMAGES_MOUSE, prefix ) );
+ final var imagePair =
+ createImage( format( "%s/%s", DIR_IMAGES_MOUSE, prefix ) );
+
+ return imagePair.getKey();
}
- private Image keyImage(
+ private Pair<Image, DimensionTuple> keyImage(
final String state, final String prefix ) {
return createImage(
format( "%s/%s/%s", DIR_IMAGES_KEYBOARD, state, prefix )
);
}
- private Image keyUpImage( final String prefix ) {
+ private Pair<Image, DimensionTuple> keyUpImage( final String prefix ) {
return keyImage( "up", prefix );
}
- private Image keyDnImage( final String prefix ) {
+ private Pair<Image, DimensionTuple> keyDnImage( final String prefix ) {
return keyImage( "dn", prefix );
}
- private Image createImage( final String path ) {
+ private Pair<Image, DimensionTuple> createImage( final String path ) {
final var resource = format( "%s.svg", path );
try {
final var diagram = sRasterizer.loadDiagram( resource );
final var scale = sRasterizer.calculateScale( diagram, mDimension );
final var image = sRasterizer.rasterize( diagram, mDimension );
-
- // TODO: Scale insets.
- return image;
+ return new Pair<>( image, scale );
} catch( final Exception ex ) {
rethrow( ex );
src/main/com/whitemagicsoftware/kmcaster/HardwareSwitch.java
* given {@code modifiers} value.
*/
- public boolean isPressed( final int modifiers ) {
+ public boolean isModifierPressed( final int modifiers ) {
assert isModifier();
return KEY_REGULAR;
+ }
+
+ /**
+ * Returns a list of all keyboard keys.
+ *
+ * @return The complete list of keyboard keys.
+ */
+ public static HardwareSwitch[] keyboardKeys() {
+ return new HardwareSwitch[]{KEY_ALT, KEY_CTRL, KEY_SHIFT, KEY_REGULAR};
}
src/main/com/whitemagicsoftware/kmcaster/SvgRasterizer.java
import com.kitfox.svg.SVGException;
import com.kitfox.svg.SVGUniverse;
-import com.whitemagicsoftware.kmcaster.ui.KmDimension;
+import com.whitemagicsoftware.kmcaster.ui.ScalableDimension;
+import com.whitemagicsoftware.kmcaster.ui.DimensionTuple;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.net.URL;
-import java.util.AbstractMap;
import java.util.Map;
* @param diagram A 2-dimensional vector graphic having a width and height.
* @param dstDim The image's target dimensions.
- * @return A key-value pair of the source image dimensions with the
- * scaled image dimensions.
+ * @return A key-value pair of the source image dimensions (key) and the
+ * scaled image dimensions (value).
*/
- public Map.Entry<Dimension, Dimension> calculateScale(
+ public DimensionTuple calculateScale(
final SVGDiagram diagram, final Dimension dstDim ) {
- final var srcDim = new KmDimension(
+ final var srcDim = new ScalableDimension(
(int) diagram.getWidth(), (int) diagram.getHeight()
);
- final var scaled = srcDim.scaleTo( dstDim );
+ final var scaled = srcDim.scale( dstDim );
- return new AbstractMap.SimpleEntry<>( srcDim, scaled );
+ return new DimensionTuple( srcDim, scaled );
}
/**
* Rasterizes a vector graphic to a given size using a {@link BufferedImage}.
* The rendering hints are set to produce high quality output.
*
- * @param diagram The diagram to rasterize.
- * @param dimensions The output image dimensions.
+ * @param diagram The diagram to rasterize.
+ * @param tuple The source and destination image dimensions.
* @return The rasterized {@link Image}.
* @throws SVGException Could not open, read, parse, or render SVG data.
*/
public BufferedImage rasterize(
- final SVGDiagram diagram,
- final Map.Entry<Dimension, Dimension> dimensions ) throws SVGException {
- final var scaled = dimensions.getValue();
+ final SVGDiagram diagram, final DimensionTuple tuple )
+ throws SVGException {
+ final var scaled = tuple.getValue();
final var wScaled = (int) scaled.getWidth();
final var hScaled = (int) scaled.getHeight();
final var image = new BufferedImage( wScaled, hScaled, TYPE_INT_ARGB );
final var graphics = image.createGraphics();
graphics.setRenderingHints( RENDERING_HINTS );
- final var srcDim = dimensions.getKey();
final var transform = graphics.getTransform();
- transform.setToScale( wScaled / srcDim.getWidth(),
- hScaled / srcDim.getHeight() );
+ transform.setToScale( tuple.getWidthRatio(), tuple.getHeightRatio() );
graphics.setTransform( transform );
src/main/com/whitemagicsoftware/kmcaster/listeners/KeyboardListener.java
private void updateModifiers( final NativeKeyEvent e ) {
for( final var key : mModifiers.keySet() ) {
- final boolean down = key.isPressed( e.getModifiers() );
+ final boolean down = key.isModifierPressed( e.getModifiers() );
tryFire( key, mModifiers.get( key ), down );
mModifiers.put( key, down );
src/main/com/whitemagicsoftware/kmcaster/ui/DimensionTuple.java
+/*
+ * Copyright 2020 White Magic Software, Ltd.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.whitemagicsoftware.kmcaster.ui;
+
+import com.whitemagicsoftware.kmcaster.util.Pair;
+
+import java.awt.*;
+
+/**
+ * Convenience class for pairing two dimensions together.
+ */
+public class DimensionTuple extends Pair<Dimension, Dimension> {
+ /**
+ * Associates a new {@link Dimension} tuple.
+ *
+ * @param key The key for this key-value pairing.
+ * @param value The value for this key-value pairing.
+ */
+ public DimensionTuple( final Dimension key, final Dimension value ) {
+ super( key, value );
+ }
+
+ /**
+ * Returns the ratio of the value width to the key width.
+ *
+ * @return A unit-less ratio between the value and key widths.
+ */
+ public double getWidthRatio() {
+ return getValue().getWidth() / getKey().getWidth();
+ }
+
+ /**
+ * Returns the ratio of the value height to the key height.
+ *
+ * @return A unit-less ratio between the value and key heights.
+ */
+ public double getHeightRatio() {
+ return getValue().getHeight() / getKey().getHeight();
+ }
+}
src/main/com/whitemagicsoftware/kmcaster/ui/KmDimension.java
-/*
- * Copyright 2020 White Magic Software, Ltd.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * o Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * o Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.whitemagicsoftware.kmcaster.ui;
-
-import java.awt.*;
-
-/**
- * Provides the ability to scale a dimension in relation to another
- * dimension. The dimensions are unit-less.
- */
-public final class KmDimension extends Dimension {
-
- /**
- * Delegates construction to the superclass.
- *
- * @param w The dimension's width.
- * @param h The dimension's height.
- */
- public KmDimension( final int w, final int h ) {
- super( w, h );
- }
-
- /**
- * Delegates construction to this class.
- *
- * @param w The width, cast to an integer.
- * @param h The height, cast to an integer.
- */
- @SuppressWarnings("unused")
- public KmDimension( final double w, final double h ) {
- this( (int) w, (int) h );
- }
-
- /**
- * Scales the given source {@link Dimension} to the destination
- * {@link Dimension}, maintaining the aspect ratio with respect to
- * the best fit.
- *
- * @param dst The desired image dimensions to scale.
- * @return The given source dimensions scaled to the destination dimensions,
- * maintaining the aspect ratio.
- */
- public Dimension scaleTo( final Dimension dst ) {
- final var srcWidth = getWidth();
- final var srcHeight = getHeight();
-
- // Determine the ratio that will have the best fit.
- final var ratio = Math.min(
- dst.getWidth() / srcWidth, dst.getHeight() / srcHeight
- );
-
- // Scale both dimensions with respect to the best fit ratio.
- return new KmDimension( (int) (srcWidth * ratio),
- (int) (srcHeight * ratio) );
- }
-}
src/main/com/whitemagicsoftware/kmcaster/ui/ScalableDimension.java
+/*
+ * Copyright 2020 White Magic Software, Ltd.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.whitemagicsoftware.kmcaster.ui;
+
+import java.awt.*;
+
+/**
+ * Provides the ability to scale a dimension in relation to another
+ * dimension. The dimensions are unit-less.
+ */
+public final class ScalableDimension extends Dimension {
+
+ /**
+ * Delegates construction to the superclass.
+ *
+ * @param w The dimension's width.
+ * @param h The dimension's height.
+ */
+ public ScalableDimension( final int w, final int h ) {
+ super( w, h );
+ }
+
+ /**
+ * Delegates construction to this class.
+ *
+ * @param w The width, cast to an integer.
+ * @param h The height, cast to an integer.
+ */
+ @SuppressWarnings("unused")
+ public ScalableDimension( final double w, final double h ) {
+ this( (int) w, (int) h );
+ }
+
+ /**
+ * Scales the given source {@link Dimension} to the destination
+ * {@link Dimension}, maintaining the aspect ratio with respect to
+ * the best fit.
+ *
+ * @param dst The desired image dimensions to scale.
+ * @return The given source dimensions scaled to the destination dimensions,
+ * maintaining the aspect ratio.
+ */
+ public Dimension scale( final Dimension dst ) {
+ final var srcWidth = getWidth();
+ final var srcHeight = getHeight();
+
+ // Determine the ratio that will have the best fit.
+ final var ratio = Math.min(
+ dst.getWidth() / srcWidth, dst.getHeight() / srcHeight
+ );
+
+ // Scale both dimensions with respect to the best fit ratio.
+ return new ScalableDimension( (int) (srcWidth * ratio),
+ (int) (srcHeight * ratio) );
+ }
+}
src/main/com/whitemagicsoftware/kmcaster/util/Pair.java
+/*
+ * Copyright 2020 White Magic Software, Ltd.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.whitemagicsoftware.kmcaster.util;
+
+import java.util.AbstractMap;
+import java.util.Map;
+
+/**
+ * Convenience class for pairing two objects together; this is a synonym for
+ * {@link Map.Entry}.
+ *
+ * @param <K> The type of key to store in this pair.
+ * @param <V> The type of value to store in this pair.
+ */
+public class Pair<K, V> extends AbstractMap.SimpleImmutableEntry<K, V> {
+ /**
+ * Associates a new key-value pair.
+ *
+ * @param key The key for this key-value pairing.
+ * @param value The value for this key-value pairing.
+ */
+ public Pair( final K key, final V value ) {
+ super( key, value );
+ }
+}
Delta 289 lines added, 151 lines removed, 138-line increase