| Author | DaveJarvis <email> |
|---|---|
| Date | 2020-07-26 01:29:31 GMT-0700 |
| Commit | 77d0366113dec18f052ea3480f91c82807a11535 |
| Parent | 30d2436 |
| Delta | 51 lines added, 64 lines removed, 13-line decrease |
|---|
| protected void updateSwitchLabel( final HardwareSwitchState state ) { | ||
| final var keyColour = KEY_COLOURS.get( state.getHardwareState() ); | ||
| - final var pressed = state.isHardwareState( SWITCH_PRESSED ); | ||
| if( state.isModifier() ) { | ||
| updateLabel( state, keyColour ); | ||
| - if( pressed ) { | ||
| - mKeyCounter.reset(); | ||
| - } | ||
| + mKeyCounter.reset(); | ||
| } | ||
| else { | ||
| final var component = getHardwareComponent( state ); | ||
| final var keyValue = state.getValue(); | ||
| // A non-modifier key has been pressed. | ||
| - if( pressed ) { | ||
| + if( state.isHardwareState( SWITCH_PRESSED ) ) { | ||
| // Determine whether there are separate parts for the key label. | ||
| final var index = keyValue.indexOf( ' ' ); | ||
| final var supSize = compDimen.scale( .6f ); | ||
| final var mainSize = compDimen.scale( .9f ); | ||
| - | ||
| - final var s = new String[]{ | ||
| - keyValue.substring( 0, index ), | ||
| - keyValue.substring( index + 1 ) | ||
| - }; | ||
| // Label for "Num", "Back", "Tab", and other dual-labelled keys. | ||
| - final var sup = new AutofitLabel( s[ 0 ], LABEL_FONT ); | ||
| + final var sup = new AutofitLabel( | ||
| + keyValue.substring( 0, index ), 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 ); | ||
| + final var main = new AutofitLabel( | ||
| + keyValue.substring( index + 1 ), LABEL_FONT ); | ||
| main.setVisible( false ); | ||
| main.setForeground( keyColour ); | ||
| main.setHorizontalAlignment( CENTER ); | ||
| - main.setVerticalAlignment( CENTER ); | ||
| // Keep removeAll/add operations close together to minimize flicker. | ||
| private final Insets mInsets; | ||
| + private Dimension mPreferredSize; | ||
| + | ||
| /** | ||
| * Constructs a new {@link HardwareComponent} without an initial state. The | ||
| @Override | ||
| public Dimension getPreferredSize() { | ||
| - // Race-condition guard. | ||
| - final var image = getActiveImage(); | ||
| - | ||
| - return new Dimension( | ||
| - image.getWidth( null ), image.getHeight( null ) | ||
| - ); | ||
| + return mPreferredSize == null | ||
| + ? mPreferredSize = calcPreferredSize() | ||
| + : mPreferredSize; | ||
| } | ||
| repaint(); | ||
| } | ||
| - } | ||
| - | ||
| - private Image getActiveImage() { | ||
| - return getStateImages().get( getState() ); | ||
| } | ||
| public S getState() { | ||
| return mState; | ||
| + } | ||
| + | ||
| + private Dimension calcPreferredSize() { | ||
| + // Race-condition guard. | ||
| + final var image = getActiveImage(); | ||
| + | ||
| + return new Dimension( | ||
| + image.getWidth( null ), image.getHeight( null ) | ||
| + ); | ||
| + } | ||
| + | ||
| + private Image getActiveImage() { | ||
| + return getStateImages().get( getState() ); | ||
| } | ||
| import static java.util.Map.entry; | ||
| import static java.util.Optional.ofNullable; | ||
| +import static javax.swing.SwingUtilities.invokeLater; | ||
| import static org.jnativehook.keyboard.NativeKeyEvent.getKeyText; | ||
| } | ||
| - updateRegular( mRegularHeld, getDisplayText( e ) ); | ||
| + invokeLater( | ||
| + () -> updateRegular( mRegularHeld, getDisplayText( e ) ) | ||
| + ); | ||
| } ); | ||
| } | ||
| () -> { | ||
| final var timer = delayedAction( mDelayRegular, ( action ) -> | ||
| - updateRegular( getDisplayText( e ), "" ) | ||
| + invokeLater( | ||
| + () -> updateRegular( getDisplayText( e ), "" ) | ||
| + ) | ||
| ); | ||
| import javax.swing.*; | ||
| import java.awt.*; | ||
| -import java.awt.font.FontRenderContext; | ||
| -import java.awt.font.TextLayout; | ||
| import static java.awt.event.HierarchyEvent.PARENT_CHANGED; | ||
| */ | ||
| private Font computeScaledFont() { | ||
| - final var frc = getFontRenderContext(); | ||
| final var text = getText(); | ||
| + final var graphics = getGraphics(); | ||
| final var dstWidthPx = getWidth(); | ||
| final var dstHeightPx = getHeight(); | ||
| - var minSizePt = 1f; | ||
| - var maxSizePt = 100f; | ||
| + var minSizePt = 1; | ||
| + var maxSizePt = 100; | ||
| var scaledFont = getFont(); | ||
| - float scaledPt = scaledFont.getSize(); | ||
| - | ||
| - // 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 ); | ||
| + var scaledPt = scaledFont.getSize(); | ||
| - 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(); | ||
| + while( maxSizePt - minSizePt > 1 ) { | ||
| + scaledFont = scaledFont.deriveFont( (float) scaledPt ); | ||
| - if( (fontWidthPx > dstWidthPx) || (fontHeightPx > dstHeightPx) ) { | ||
| - maxSizePt = scaledPt; | ||
| - } | ||
| - else { | ||
| - minSizePt = scaledPt; | ||
| - } | ||
| + final var fm = getFontMetrics( scaledFont ); | ||
| + final var bounds = fm.getStringBounds( text, graphics ); | ||
| + final var fontWidthPx = (int) bounds.getWidth(); | ||
| + final var fontHeightPx = (int) bounds.getHeight(); | ||
| - scaledPt = (minSizePt + maxSizePt) / 2; | ||
| + if( (fontWidthPx > dstWidthPx) || (fontHeightPx > dstHeightPx) ) { | ||
| + maxSizePt = scaledPt; | ||
| + } | ||
| + else { | ||
| + minSizePt = scaledPt; | ||
| } | ||
| + | ||
| + scaledPt = (minSizePt + maxSizePt) / 2; | ||
| } | ||
| // Round down to guarantee fit. | ||
| return scaledFont.deriveFont( (float) floor( scaledPt ) ); | ||
| - } | ||
| - | ||
| - /** | ||
| - * Gets the {@link FontRenderContext} for the parent {@link Container}'s | ||
| - * {@link Graphics} context, casting it to a {@link Graphics2D} context. | ||
| - * | ||
| - * @return The parent's {@link Graphics2D} context. | ||
| - */ | ||
| - private FontRenderContext getFontRenderContext() { | ||
| - return ((Graphics2D) getGraphics()).getFontRenderContext(); | ||
| } | ||
| } | ||
| /** | ||
| - * Returns the total width and height of an area that is safe for | ||
| - * writing on the {@link Container} parameter provided during construction. | ||
| + * Returns the safe area for writing on the {@link Container} parameter | ||
| + * provided during construction. | ||
| * | ||
| * @return The {@link Container}'s safe area, based on the |
| */ | ||
| public Dimension scale( final Dimension dst ) { | ||
| - assert dst != null; | ||
| - | ||
| // Determine the ratio that has the best fit, then scale both dimensions | ||
| // with respect to said ratio. | ||
| */ | ||
| public Dimension scale( final double factor ) { | ||
| - assert factor >= 0; | ||
| - | ||
| return new ScalableDimension( | ||
| getWidth() * factor, getHeight() * factor | ||
| public void reset() { | ||
| mCount = 1; | ||
| + mPrevious = null; | ||
| } | ||