mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2025-12-06 14:00:55 +03:00
Merge PR #612: macOS themes: make spinner look like macOS stepper
This commit is contained in:
@@ -17,7 +17,10 @@
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import javax.swing.JSpinner;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.SpinnerUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
|
||||
/**
|
||||
@@ -35,6 +38,19 @@ public class FlatRoundBorder
|
||||
// only used via styling (not in UI defaults, but has likewise client properties)
|
||||
/** @since 2 */ @Styleable protected Boolean roundRect;
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
// make mac style spinner border smaller (border does not surround arrow buttons)
|
||||
if( isMacStyleSpinner( c ) ) {
|
||||
int macStyleButtonsWidth = ((FlatSpinnerUI)((JSpinner)c).getUI()).getMacStyleButtonsWidth();
|
||||
width -= macStyleButtonsWidth;
|
||||
if( !c.getComponentOrientation().isLeftToRight() )
|
||||
x += macStyleButtonsWidth;
|
||||
}
|
||||
|
||||
super.paintBorder( c, g, x, y, width, height );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getArc( Component c ) {
|
||||
if( isCellEditor( c ) )
|
||||
@@ -43,6 +59,17 @@ public class FlatRoundBorder
|
||||
Boolean roundRect = FlatUIUtils.isRoundRect( c );
|
||||
if( roundRect == null )
|
||||
roundRect = this.roundRect;
|
||||
return roundRect != null ? (roundRect ? Short.MAX_VALUE : 0) : arc;
|
||||
return roundRect != null
|
||||
? (roundRect ? Short.MAX_VALUE : 0)
|
||||
: (isMacStyleSpinner( c ) ? 0 : arc);
|
||||
}
|
||||
|
||||
private boolean isMacStyleSpinner( Component c ) {
|
||||
if( c instanceof JSpinner ) {
|
||||
SpinnerUI ui = ((JSpinner)c).getUI();
|
||||
if( ui instanceof FlatSpinnerUI )
|
||||
return ((FlatSpinnerUI)ui).isMacStyle();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,20 +340,31 @@ public class FlatSpinnerUI
|
||||
|
||||
private Component createArrowButton( int direction, String name ) {
|
||||
FlatArrowButton button = new FlatArrowButton( direction, arrowType, buttonArrowColor,
|
||||
buttonDisabledArrowColor, buttonHoverArrowColor, null, buttonPressedArrowColor, null );
|
||||
buttonDisabledArrowColor, buttonHoverArrowColor, null, buttonPressedArrowColor, null )
|
||||
{
|
||||
@Override
|
||||
public int getArrowWidth() {
|
||||
return isMacStyle() ? 7 : super.getArrowWidth();
|
||||
}
|
||||
@Override
|
||||
public float getArrowThickness() {
|
||||
return isMacStyle() ? 1.5f : super.getArrowThickness();
|
||||
}
|
||||
@Override
|
||||
public float getYOffset() {
|
||||
return isMacStyle() ? 0 : super.getYOffset();
|
||||
}
|
||||
@Override
|
||||
public boolean isRoundBorderAutoXOffset() {
|
||||
return isMacStyle() ? false : super.isRoundBorderAutoXOffset();
|
||||
}
|
||||
};
|
||||
button.setName( name );
|
||||
button.setYOffset( (direction == SwingConstants.NORTH) ? 1.25f : -1.25f );
|
||||
if( direction == SwingConstants.NORTH )
|
||||
installNextButtonListeners( button );
|
||||
else
|
||||
installPreviousButtonListeners( button );
|
||||
|
||||
if( "mac".equals( buttonStyle ) ) {
|
||||
button.setArrowWidth( 7 );
|
||||
button.setArrowThickness( 1.5f );
|
||||
button.setYOffset( (direction == SwingConstants.NORTH) ? 0.75f : -0.75f );
|
||||
button.setRoundBorderAutoXOffset( false );
|
||||
}
|
||||
return button;
|
||||
}
|
||||
|
||||
@@ -381,10 +392,13 @@ public class FlatSpinnerUI
|
||||
int width = c.getWidth();
|
||||
int height = c.getHeight();
|
||||
boolean enabled = spinner.isEnabled();
|
||||
boolean ltr = spinner.getComponentOrientation().isLeftToRight();
|
||||
boolean isMacStyle = isMacStyle();
|
||||
int macStyleButtonsWidth = isMacStyle ? getMacStyleButtonsWidth() : 0;
|
||||
|
||||
// paint background
|
||||
g2.setColor( getBackground( enabled ) );
|
||||
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
|
||||
FlatUIUtils.paintComponentBackground( g2, ltr ? 0 : macStyleButtonsWidth, 0, width - macStyleButtonsWidth, height, focusWidth, arc );
|
||||
|
||||
// paint button background and separator
|
||||
boolean paintButton = !"none".equals( buttonStyle );
|
||||
@@ -393,22 +407,20 @@ public class FlatSpinnerUI
|
||||
Component button = (handler.nextButton != null) ? handler.nextButton : handler.previousButton;
|
||||
int arrowX = button.getX();
|
||||
int arrowWidth = button.getWidth();
|
||||
boolean isLeftToRight = spinner.getComponentOrientation().isLeftToRight();
|
||||
Color separatorColor = enabled ? buttonSeparatorColor : buttonDisabledSeparatorColor;
|
||||
|
||||
if( "mac".equals( buttonStyle ) ) {
|
||||
if( isMacStyle ) {
|
||||
Insets insets = spinner.getInsets();
|
||||
int gapX = scale( 3 );
|
||||
int gapY = scale( 1 );
|
||||
int bx = arrowX + gapX;
|
||||
int by = insets.top + gapY;
|
||||
int bw = arrowWidth - (gapX * 2);
|
||||
int bh = height - insets.top - insets.bottom - (gapY * 2);
|
||||
int lineWidth = Math.round( FlatUIUtils.getBorderLineWidth( spinner ) );
|
||||
int bx = arrowX;
|
||||
int by = insets.top - lineWidth;
|
||||
int bw = arrowWidth;
|
||||
int bh = height - insets.top - insets.bottom + (lineWidth * 2);
|
||||
float lw = scale( buttonSeparatorWidth );
|
||||
|
||||
// buttons border
|
||||
FlatUIUtils.paintOutlinedComponent( g2, bx, by, bw, bh,
|
||||
0, 0, 0, lw, arc - focusWidth,
|
||||
0, 0, 0, lw, scale( 12 ),
|
||||
null, separatorColor, buttonBackground );
|
||||
|
||||
// separator between buttons
|
||||
@@ -423,7 +435,7 @@ public class FlatSpinnerUI
|
||||
if( enabled && buttonBackground != null ) {
|
||||
g2.setColor( buttonBackground );
|
||||
Shape oldClip = g2.getClip();
|
||||
if( isLeftToRight )
|
||||
if( ltr )
|
||||
g2.clipRect( arrowX, 0, width - arrowX, height );
|
||||
else
|
||||
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
|
||||
@@ -435,7 +447,7 @@ public class FlatSpinnerUI
|
||||
if( separatorColor != null && buttonSeparatorWidth > 0 ) {
|
||||
g2.setColor( separatorColor );
|
||||
float lw = scale( buttonSeparatorWidth );
|
||||
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
|
||||
float lx = ltr ? arrowX : arrowX + arrowWidth - lw;
|
||||
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - 1 - (focusWidth * 2) ) );
|
||||
}
|
||||
}
|
||||
@@ -446,6 +458,19 @@ public class FlatSpinnerUI
|
||||
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||
}
|
||||
|
||||
boolean isMacStyle() {
|
||||
return "mac".equals( buttonStyle );
|
||||
}
|
||||
|
||||
int getMacStyleButtonsWidth() {
|
||||
return (handler.nextButton != null || handler.previousButton != null)
|
||||
? scale( MAC_STEPPER_GAP ) + scale( MAC_STEPPER_WIDTH )
|
||||
: 0;
|
||||
}
|
||||
|
||||
private static final int MAC_STEPPER_WIDTH = 15;
|
||||
private static final int MAC_STEPPER_GAP = 3;
|
||||
|
||||
//---- class Handler ------------------------------------------------------
|
||||
|
||||
private class Handler
|
||||
@@ -502,6 +527,7 @@ public class FlatSpinnerUI
|
||||
Insets insets = parent.getInsets();
|
||||
Rectangle r = FlatUIUtils.subtractInsets( new Rectangle( size ), insets );
|
||||
|
||||
// editor gets all space if there are no buttons
|
||||
if( nextButton == null && previousButton == null ) {
|
||||
if( editor != null )
|
||||
editor.setBounds( r );
|
||||
@@ -517,20 +543,36 @@ public class FlatSpinnerUI
|
||||
int minButtonWidth = (maxButtonWidth * 3) / 4;
|
||||
|
||||
// make button area square (except if width is limited)
|
||||
int buttonsWidth = Math.min( Math.max( buttonsRect.height, minButtonWidth ), maxButtonWidth );
|
||||
buttonsRect.width = buttonsWidth;
|
||||
boolean isMacStyle = isMacStyle();
|
||||
int buttonsGap = isMacStyle ? scale( MAC_STEPPER_GAP ) : 0;
|
||||
int prefButtonWidth = isMacStyle ? scale( MAC_STEPPER_WIDTH ) : buttonsRect.height;
|
||||
int buttonsWidth = Math.min( Math.max( prefButtonWidth, minButtonWidth ), maxButtonWidth );
|
||||
|
||||
if( parent.getComponentOrientation().isLeftToRight() ) {
|
||||
editorRect.width -= buttonsWidth;
|
||||
buttonsRect.x += editorRect.width;
|
||||
} else {
|
||||
editorRect.x += buttonsWidth;
|
||||
editorRect.width -= buttonsWidth;
|
||||
// update editor and buttons bounds
|
||||
buttonsRect.width = buttonsWidth;
|
||||
editorRect.width -= buttonsWidth + buttonsGap;
|
||||
boolean ltr = parent.getComponentOrientation().isLeftToRight();
|
||||
if( ltr )
|
||||
buttonsRect.x += editorRect.width + buttonsGap;
|
||||
else
|
||||
editorRect.x += buttonsWidth + buttonsGap;
|
||||
|
||||
// in mac button style increase buttons height and move to the right
|
||||
// for exact alignment with border
|
||||
if( isMacStyle ) {
|
||||
int lineWidth = Math.round( FlatUIUtils.getBorderLineWidth( spinner ) );
|
||||
if( lineWidth > 0 ) {
|
||||
buttonsRect.x += ltr ? lineWidth : -lineWidth;
|
||||
buttonsRect.y -= lineWidth;
|
||||
buttonsRect.height += lineWidth * 2;
|
||||
}
|
||||
}
|
||||
|
||||
// set editor bounds
|
||||
if( editor != null )
|
||||
editor.setBounds( editorRect );
|
||||
|
||||
// set buttons bounds
|
||||
int nextHeight = (buttonsRect.height / 2) + (buttonsRect.height % 2); // round up
|
||||
if( nextButton != null )
|
||||
nextButton.setBounds( buttonsRect.x, buttonsRect.y, buttonsRect.width, nextHeight );
|
||||
|
||||
@@ -253,6 +253,9 @@ Slider.focusedColor = $Component.focusColor
|
||||
Spinner.buttonStyle = mac
|
||||
Spinner.disabledBackground = @disabledComponentBackground
|
||||
Spinner.buttonBackground = @buttonBackground
|
||||
Spinner.buttonArrowColor = @foreground
|
||||
Spinner.buttonHoverArrowColor = lighten($Spinner.buttonArrowColor,10%,derived noAutoInverse)
|
||||
Spinner.buttonPressedArrowColor = lighten($Spinner.buttonArrowColor,20%,derived noAutoInverse)
|
||||
Spinner.buttonSeparatorWidth = 0
|
||||
|
||||
|
||||
|
||||
@@ -982,12 +982,12 @@ SliderUI com.formdev.flatlaf.ui.FlatSliderUI
|
||||
Spinner.arrowButtonSize 16,5 java.awt.Dimension
|
||||
Spinner.background #282828 HSL 0 0 16 javax.swing.plaf.ColorUIResource [UI]
|
||||
Spinner.border [lazy] 3,3,3,3 false com.formdev.flatlaf.ui.FlatRoundBorder [UI]
|
||||
Spinner.buttonArrowColor #b7b7b7 HSL 0 0 72 javax.swing.plaf.ColorUIResource [UI]
|
||||
Spinner.buttonArrowColor #dddddd HSL 0 0 87 javax.swing.plaf.ColorUIResource [UI]
|
||||
Spinner.buttonBackground #565656 HSL 0 0 34 javax.swing.plaf.ColorUIResource [UI]
|
||||
Spinner.buttonDisabledArrowColor #777777 HSL 0 0 47 javax.swing.plaf.ColorUIResource [UI]
|
||||
Spinner.buttonDisabledSeparatorColor #ffffff0c 5% HSLA 0 0 100 5 javax.swing.plaf.ColorUIResource [UI]
|
||||
Spinner.buttonHoverArrowColor #d1d1d1 HSL 0 0 82 com.formdev.flatlaf.util.DerivedColor [UI] lighten(10%)
|
||||
Spinner.buttonPressedArrowColor #eaeaea HSL 0 0 92 com.formdev.flatlaf.util.DerivedColor [UI] lighten(20%)
|
||||
Spinner.buttonHoverArrowColor #f7f7f7 HSL 0 0 97 com.formdev.flatlaf.util.DerivedColor [UI] lighten(10%)
|
||||
Spinner.buttonPressedArrowColor #ffffff HSL 0 0 100 com.formdev.flatlaf.util.DerivedColor [UI] lighten(20%)
|
||||
Spinner.buttonSeparatorColor #ffffff19 10% HSLA 0 0 100 10 javax.swing.plaf.ColorUIResource [UI]
|
||||
Spinner.buttonSeparatorWidth 0
|
||||
Spinner.buttonStyle mac
|
||||
|
||||
@@ -45,6 +45,27 @@ public class FlatTextComponentsTest
|
||||
|
||||
FlatTextComponentsTest() {
|
||||
initComponents();
|
||||
updatePreferredSizes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateUI() {
|
||||
super.updateUI();
|
||||
|
||||
if( comboBox5 != null )
|
||||
updatePreferredSizes();
|
||||
}
|
||||
|
||||
private void updatePreferredSizes() {
|
||||
Dimension size40 = UIScale.scale( new Dimension( 60, 40 ) );
|
||||
comboBox5.setPreferredSize( size40 );
|
||||
spinner4.setPreferredSize( size40 );
|
||||
|
||||
Dimension size14 = UIScale.scale( new Dimension( 60, 14 ) );
|
||||
comboBox6.setPreferredSize( size14 );
|
||||
comboBox6.setMinimumSize( size14 );
|
||||
spinner5.setPreferredSize( size14 );
|
||||
spinner5.setMinimumSize( size14 );
|
||||
}
|
||||
|
||||
private void editableChanged() {
|
||||
@@ -216,18 +237,19 @@ public class FlatTextComponentsTest
|
||||
JComboBox<String> comboBox3 = new JComboBox<>();
|
||||
JLabel spinnerLabel = new JLabel();
|
||||
JSpinner spinner1 = new JSpinner();
|
||||
JSpinner spinner6 = new JSpinner();
|
||||
JLabel label2 = new JLabel();
|
||||
JComboBox<String> comboBox2 = new JComboBox<>();
|
||||
JSpinner spinner2 = new JSpinner();
|
||||
JLabel label1 = new JLabel();
|
||||
JComboBox<String> comboBox5 = new JComboBox<>();
|
||||
JSpinner spinner4 = new JSpinner();
|
||||
comboBox5 = new JComboBox<>();
|
||||
spinner4 = new JSpinner();
|
||||
JLabel label3 = new JLabel();
|
||||
JComboBox<String> comboBox4 = new JComboBox<>();
|
||||
JSpinner spinner3 = new JSpinner();
|
||||
JLabel label4 = new JLabel();
|
||||
JComboBox<String> comboBox6 = new JComboBox<>();
|
||||
JSpinner spinner5 = new JSpinner();
|
||||
comboBox6 = new JComboBox<>();
|
||||
spinner5 = new JSpinner();
|
||||
JLabel label5 = new JLabel();
|
||||
textField = new JTextField();
|
||||
dragEnabledCheckBox = new JCheckBox();
|
||||
@@ -563,6 +585,10 @@ public class FlatTextComponentsTest
|
||||
spinner1.setComponentPopupMenu(popupMenu1);
|
||||
add(spinner1, "cell 1 7,growx");
|
||||
|
||||
//---- spinner6 ----
|
||||
spinner6.setBorder(BorderFactory.createEmptyBorder());
|
||||
add(spinner6, "cell 2 7,growx");
|
||||
|
||||
//---- label2 ----
|
||||
label2.setText("<html>Large row height:<br>(default pref height)</html>");
|
||||
add(label2, "cell 0 8,aligny top,growy 0");
|
||||
@@ -690,6 +716,10 @@ public class FlatTextComponentsTest
|
||||
private JCheckBox trailingComponentVisibleCheckBox;
|
||||
private JCheckBox showClearButtonCheckBox;
|
||||
private JCheckBox showRevealButtonCheckBox;
|
||||
private JComboBox<String> comboBox5;
|
||||
private JSpinner spinner4;
|
||||
private JComboBox<String> comboBox6;
|
||||
private JSpinner spinner5;
|
||||
private JTextField textField;
|
||||
private JCheckBox dragEnabledCheckBox;
|
||||
private JTextArea textArea;
|
||||
|
||||
@@ -403,6 +403,12 @@ new FormModel {
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 7,growx"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JSpinner" ) {
|
||||
name: "spinner6"
|
||||
"border": new javax.swing.border.EmptyBorder( 0, 0, 0, 0 )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 2 7,growx"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label2"
|
||||
"text": "<html>Large row height:<br>(default pref height)</html>"
|
||||
@@ -435,6 +441,7 @@ new FormModel {
|
||||
"editable": true
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.typeParameters": "String"
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 10,growx"
|
||||
@@ -442,6 +449,9 @@ new FormModel {
|
||||
add( new FormComponent( "javax.swing.JSpinner" ) {
|
||||
name: "spinner4"
|
||||
"preferredSize": new java.awt.Dimension( 60, 40 )
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 11,growx"
|
||||
} )
|
||||
@@ -478,6 +488,7 @@ new FormModel {
|
||||
"minimumSize": new java.awt.Dimension( 60, 14 )
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.typeParameters": "String"
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 14,growx"
|
||||
@@ -486,6 +497,9 @@ new FormModel {
|
||||
name: "spinner5"
|
||||
"minimumSize": new java.awt.Dimension( 60, 14 )
|
||||
"preferredSize": new java.awt.Dimension( 60, 14 )
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 15,growx,hmax 14"
|
||||
} )
|
||||
|
||||
Reference in New Issue
Block a user