diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatArrowButton.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatArrowButton.java index 795b220d..26916d89 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatArrowButton.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatArrowButton.java @@ -17,16 +17,13 @@ package com.formdev.flatlaf.ui; import static com.formdev.flatlaf.util.UIScale.scale; -import java.awt.BasicStroke; import java.awt.Color; import java.awt.Container; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; -import java.awt.Shape; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.awt.geom.Path2D; import javax.swing.JComponent; import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicArrowButton; @@ -190,73 +187,14 @@ public class FlatArrowButton } protected void paintArrow( Graphics2D g ) { - int direction = getDirection(); boolean vert = (direction == NORTH || direction == SOUTH); - - // compute width/height - int w = scale( arrowWidth + (chevron ? 0 : 1) ); - int h = scale( (arrowWidth / 2) + (chevron ? 0 : 1) ); - - // rotate width/height - int rw = vert ? w : h; - int rh = vert ? h : w; - - // chevron lines end 1px outside of width/height - if( chevron ) { - // add 1px to width/height for position calculation only - rw++; - rh++; - } - - int x = Math.round( (getWidth() - rw) / 2f + scale( (float) xOffset ) ); - int y = Math.round( (getHeight() - rh) / 2f + scale( (float) yOffset ) ); + int x = 0; // move arrow for round borders Container parent = getParent(); if( vert && parent instanceof JComponent && FlatUIUtils.hasRoundBorder( (JComponent) parent ) ) x -= scale( parent.getComponentOrientation().isLeftToRight() ? 1 : -1 ); - // paint arrow - g.translate( x, y ); -/*debug - debugPaint( g, vert, rw, rh ); -debug*/ - Shape arrowShape = createArrowShape( direction, chevron, w, h ); - if( chevron ) { - g.setStroke( new BasicStroke( scale( 1f ) ) ); - g.draw( arrowShape ); - } else { - // triangle - g.fill( arrowShape ); - } - g.translate( -x, -y ); + FlatUIUtils.paintArrow( g, x, 0, getWidth(), getHeight(), getDirection(), chevron, arrowWidth, xOffset, yOffset ); } - - public static Shape createArrowShape( int direction, boolean chevron, float w, float h ) { - switch( direction ) { - case NORTH: return FlatUIUtils.createPath( !chevron, 0,h, (w / 2f),0, w,h ); - case SOUTH: return FlatUIUtils.createPath( !chevron, 0,0, (w / 2f),h, w,0 ); - case WEST: return FlatUIUtils.createPath( !chevron, h,0, 0,(w / 2f), h,w ); - case EAST: return FlatUIUtils.createPath( !chevron, 0,0, h,(w / 2f), 0,w ); - default: return new Path2D.Float(); - } - } - -/*debug - private void debugPaint( Graphics g, boolean vert, int w, int h ) { - Color oldColor = g.getColor(); - g.setColor( Color.red ); - g.drawRect( 0, 0, w - 1, h - 1 ); - - int xy1 = -2; - int xy2 = h + 1; - for( int i = 0; i < 20; i++ ) { - g.drawRect( vert ? 0 : xy1, vert ? xy1 : 0, 0, 0 ); - g.drawRect( vert ? 0 : xy2, vert ? xy2 : 0, 0, 0 ); - xy1 -= 2; - xy2 += 2; - } - g.setColor( oldColor ); - } -debug*/ } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java index 5e0eb5f8..7694389a 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java @@ -16,6 +16,7 @@ package com.formdev.flatlaf.ui; +import java.awt.BasicStroke; import java.awt.Color; import java.awt.Component; import java.awt.Container; @@ -30,6 +31,7 @@ import java.awt.KeyboardFocusManager; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.Shape; +import java.awt.Stroke; import java.awt.Window; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; @@ -44,6 +46,7 @@ import java.util.function.Supplier; import javax.swing.JComponent; import javax.swing.JTable; import javax.swing.LookAndFeel; +import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.border.Border; @@ -609,6 +612,111 @@ public class FlatUIUtils return rect; } + /** + * Paints a chevron or triangle arrow in the center of the given rectangle. + * + * @param g the graphics context used for painting + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param width the width of the rectangle + * @param height the height of the rectangle + * @param direction the arrow direction ({@link SwingConstants#NORTH}, {@link SwingConstants#SOUTH} + * {@link SwingConstants#WEST} or {@link SwingConstants#EAST}) + * @param chevron {@code true} for chevron arrow, {@code false} for triangle arrow + * @param arrowSize the width of the painted arrow (for vertical direction) (will be scaled) + * @param xOffset a offset added to the x coordinate of the arrow to paint it out-of-center. Usually zero. (will be scaled) + * @param yOffset a offset added to the y coordinate of the arrow to paint it out-of-center. Usually zero. (will be scaled) + * + * @since 1.1 + */ + public static void paintArrow( Graphics2D g, int x, int y, int width, int height, + int direction, boolean chevron, int arrowSize, int xOffset, int yOffset ) + { + // compute arrow width/height + int aw = UIScale.scale( arrowSize + (chevron ? 0 : 1) ); + int ah = UIScale.scale( (arrowSize / 2) + (chevron ? 0 : 1) ); + + // rotate arrow width/height for horizontal directions + boolean vert = (direction == SwingConstants.NORTH || direction == SwingConstants.SOUTH); + if( !vert ) { + int temp = aw; + aw = ah; + ah = temp; + } + + // chevron lines end 1px outside of width/height + // --> add 1px to arrow width/height for position calculation + int extra = chevron ? 1 : 0; + + // compute arrow location + int ax = x + Math.round( ((width - (aw + extra)) / 2f) + UIScale.scale( (float) xOffset ) ); + int ay = y + Math.round( ((height - (ah + extra)) / 2f) + UIScale.scale( (float) yOffset ) ); + + // paint arrow + g.translate( ax, ay ); +/*debug + debugPaintArrow( g, Color.red, vert, aw + extra, ah + extra ); +debug*/ + Shape arrowShape = createArrowShape( direction, chevron, aw, ah ); + if( chevron ) { + Stroke oldStroke = g.getStroke(); + g.setStroke( new BasicStroke( UIScale.scale( 1f ) ) ); + g.draw( arrowShape ); + g.setStroke( oldStroke ); + } else { + // triangle + g.fill( arrowShape ); + } + g.translate( -ax, -ay ); + } + + /** + * Creates a chevron or triangle arrow shape for the given direction and size. + *
+ * The chevron shape is a open path that can be painted with {@link Graphics2D#draw(Shape)}. + * The triangle shape is a close path that can be painted with {@link Graphics2D#fill(Shape)}. + * + * @param direction the arrow direction ({@link SwingConstants#NORTH}, {@link SwingConstants#SOUTH} + * {@link SwingConstants#WEST} or {@link SwingConstants#EAST}) + * @param chevron {@code true} for chevron arrow, {@code false} for triangle arrow + * @param w the width of the returned shape + * @param h the height of the returned shape + * + * @since 1.1 + */ + public static Shape createArrowShape( int direction, boolean chevron, float w, float h ) { + switch( direction ) { + case SwingConstants.NORTH: return createPath( !chevron, 0,h, (w / 2f),0, w,h ); + case SwingConstants.SOUTH: return createPath( !chevron, 0,0, (w / 2f),h, w,0 ); + case SwingConstants.WEST: return createPath( !chevron, w,0, 0,(h / 2f), w,h ); + case SwingConstants.EAST: return createPath( !chevron, 0,0, w,(h / 2f), 0,h ); + default: return new Path2D.Float(); + } + } + +/*debug + private static void debugPaintArrow( Graphics2D g, Color color, boolean vert, int w, int h ) { + Color oldColor = g.getColor(); + g.setColor( color ); + g.fill( createRectangle( 0, 0, w, h, 1 ) ); + + int xy1 = -2; + int x2 = w + 1; + int y2 = h + 1; + for( int i = 0; i < 20; i++ ) { + g.fillRect( 0, xy1, 1, 1 ); + g.fillRect( 0, y2, 1, 1 ); + g.fillRect( xy1, 0, 1, 1 ); + g.fillRect( x2, 0, 1, 1 ); + xy1 -= 2; + x2 += 2; + y2 += 2; + } + + g.setColor( oldColor ); + } +debug*/ + /** * Creates a closed path for the given points. */ diff --git a/flatlaf-swingx/src/main/java/com/formdev/flatlaf/swingx/ui/FlatMonthDownIcon.java b/flatlaf-swingx/src/main/java/com/formdev/flatlaf/swingx/ui/FlatMonthDownIcon.java index c28b5205..a84c469b 100644 --- a/flatlaf-swingx/src/main/java/com/formdev/flatlaf/swingx/ui/FlatMonthDownIcon.java +++ b/flatlaf-swingx/src/main/java/com/formdev/flatlaf/swingx/ui/FlatMonthDownIcon.java @@ -24,7 +24,6 @@ import java.awt.Shape; import javax.swing.SwingConstants; import javax.swing.UIManager; import com.formdev.flatlaf.icons.FlatAbstractIcon; -import com.formdev.flatlaf.ui.FlatArrowButton; import com.formdev.flatlaf.ui.FlatUIUtils; /** @@ -56,14 +55,14 @@ public class FlatMonthDownIcon @Override protected void paintIcon( Component c, Graphics2D g ) { - int h = chevron ? 4 : 5; - int w = chevron ? 8 : 9; - int x = Math.round( (width - h) / 2f ); - int y = Math.round( (height - w) / 2f ); + int w = chevron ? 4 : 5; + int h = chevron ? 8 : 9; + int x = Math.round( (width - w) / 2f ); + int y = Math.round( (height - h) / 2f ); g.setColor( c.isEnabled() ? arrowColor : disabledArrowColor ); g.translate( x, y ); - Shape arrowShape = FlatArrowButton.createArrowShape( direction, chevron, w, h ); + Shape arrowShape = FlatUIUtils.createArrowShape( direction, chevron, w, h ); if( chevron ) { // chevron arrow g.setStroke( new BasicStroke( 1f ) ); diff --git a/flatlaf-swingx/src/main/java/com/formdev/flatlaf/swingx/ui/FlatTaskPaneUI.java b/flatlaf-swingx/src/main/java/com/formdev/flatlaf/swingx/ui/FlatTaskPaneUI.java index e71ac7ca..f336a370 100644 --- a/flatlaf-swingx/src/main/java/com/formdev/flatlaf/swingx/ui/FlatTaskPaneUI.java +++ b/flatlaf-swingx/src/main/java/com/formdev/flatlaf/swingx/ui/FlatTaskPaneUI.java @@ -36,7 +36,6 @@ import javax.swing.plaf.ComponentUI; import javax.swing.plaf.UIResource; import org.jdesktop.swingx.JXTaskPane; import org.jdesktop.swingx.plaf.basic.BasicTaskPaneUI; -import com.formdev.flatlaf.ui.FlatArrowButton; import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.util.UIScale; @@ -223,7 +222,7 @@ public class FlatTaskPaneUI // create arrow shape int direction = group.isCollapsed() ? SwingConstants.SOUTH : SwingConstants.NORTH; - Shape arrowShape = FlatArrowButton.createArrowShape( direction, true, cw, ch ); + Shape arrowShape = FlatUIUtils.createArrowShape( direction, true, cw, ch ); // fix position of controls x = group.getComponentOrientation().isLeftToRight() ? (group.getWidth() - width - y) : y; diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatPaintingTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatPaintingTest.java index ae9642b2..d0cb244f 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatPaintingTest.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatPaintingTest.java @@ -17,10 +17,14 @@ package com.formdev.flatlaf.testing; import java.awt.Color; +import java.awt.Container; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.image.BufferedImage; import javax.swing.*; +import javax.swing.border.*; +import com.formdev.flatlaf.ui.FlatArrowButton; import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.util.HiDPIUtils; import com.formdev.flatlaf.util.UIScale; @@ -43,6 +47,54 @@ public class FlatPaintingTest initComponents(); } + @Override + public void updateUI() { + super.updateUI(); + + getHorizontalScrollBar().setUnitIncrement( UIScale.scale( 25 ) ); + getVerticalScrollBar().setUnitIncrement( UIScale.scale( 25 ) ); + } + + private void arrowSizeChanged() { + int width = (int) arrowWidthSpinner.getValue(); + int height = (int) arrowHeightSpinner.getValue(); + int arrowSize = (int) arrowSizeSpinner.getValue(); + + FlatTestFrame.updateComponentsRecur( (Container) getViewport().getView(), (c, type) -> { + if( c instanceof ArrowPainter ) { + ArrowPainter painter = (ArrowPainter) c; + painter.setW( painter.isHalfWidth() ? width / 2 : width ); + painter.setH( painter.isHalfHeight() ? height / 2 : height ); + painter.setArrowSize( arrowSize ); + } + } ); + + revalidate(); + repaint(); + } + + private void vectorChanged() { + boolean vector = vectorCheckBox.isSelected(); + + FlatTestFrame.updateComponentsRecur( (Container) getViewport().getView(), (c, type) -> { + if( c instanceof ArrowPainter ) + ((ArrowPainter) c).vector = vector; + } ); + + repaint(); + } + + private void checkBox1ActionPerformed() { + boolean button = buttonCheckBox.isSelected(); + + FlatTestFrame.updateComponentsRecur( (Container) getViewport().getView(), (c, type) -> { + if( c instanceof ArrowPainter ) + ((ArrowPainter)c).button = button; + } ); + + repaint(); + } + private void initComponents() { // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents FlatTestPanel flatTestPanel1 = new FlatTestPanel(); @@ -86,6 +138,35 @@ public class FlatPaintingTest JLabel label5 = new JLabel(); JLabel label6 = new JLabel(); JLabel label7 = new JLabel(); + FlatPaintingTest.ArrowPainter arrowPainter1 = new FlatPaintingTest.ArrowPainter(); + FlatPaintingTest.ArrowPainter arrowPainter2 = new FlatPaintingTest.ArrowPainter(); + FlatPaintingTest.ArrowPainter arrowPainter3 = new FlatPaintingTest.ArrowPainter(); + FlatPaintingTest.ArrowPainter arrowPainter4 = new FlatPaintingTest.ArrowPainter(); + JPanel panel1 = new JPanel(); + FlatPaintingTest.ArrowPainter arrowPainter5 = new FlatPaintingTest.ArrowPainter(); + FlatPaintingTest.ArrowPainter arrowPainter6 = new FlatPaintingTest.ArrowPainter(); + JPanel panel2 = new JPanel(); + FlatPaintingTest.ArrowPainter arrowPainter7 = new FlatPaintingTest.ArrowPainter(); + FlatPaintingTest.ArrowPainter arrowPainter8 = new FlatPaintingTest.ArrowPainter(); + JPanel panel5 = new JPanel(); + JLabel arrowWidthLabel = new JLabel(); + arrowWidthSpinner = new JSpinner(); + JLabel arrowHeightLabel = new JLabel(); + arrowHeightSpinner = new JSpinner(); + JLabel arrowSizeLabel = new JLabel(); + arrowSizeSpinner = new JSpinner(); + vectorCheckBox = new JCheckBox(); + buttonCheckBox = new JCheckBox(); + FlatPaintingTest.ArrowPainter arrowPainter9 = new FlatPaintingTest.ArrowPainter(); + FlatPaintingTest.ArrowPainter arrowPainter10 = new FlatPaintingTest.ArrowPainter(); + FlatPaintingTest.ArrowPainter arrowPainter11 = new FlatPaintingTest.ArrowPainter(); + FlatPaintingTest.ArrowPainter arrowPainter12 = new FlatPaintingTest.ArrowPainter(); + JPanel panel3 = new JPanel(); + FlatPaintingTest.ArrowPainter arrowPainter13 = new FlatPaintingTest.ArrowPainter(); + FlatPaintingTest.ArrowPainter arrowPainter14 = new FlatPaintingTest.ArrowPainter(); + JPanel panel4 = new JPanel(); + FlatPaintingTest.ArrowPainter arrowPainter15 = new FlatPaintingTest.ArrowPainter(); + FlatPaintingTest.ArrowPainter arrowPainter16 = new FlatPaintingTest.ArrowPainter(); //======== this ======== setBorder(null); @@ -109,6 +190,8 @@ public class FlatPaintingTest "[top]" + "[top]" + "[top]" + + "[]para" + + "[]" + "[]")); //---- borderPainter9 ---- @@ -360,15 +443,206 @@ public class FlatPaintingTest //---- label7 ---- label7.setText("fw 1, lw 3, arc 3,2,1,0"); flatTestPanel1.add(label7, "cell 8 4"); + + //---- arrowPainter1 ---- + arrowPainter1.setScale(8.0F); + flatTestPanel1.add(arrowPainter1, "cell 0 5,align left top,grow 0 0"); + + //---- arrowPainter2 ---- + arrowPainter2.setScale(8.0F); + arrowPainter2.setDirection(1); + flatTestPanel1.add(arrowPainter2, "cell 1 5,align left top,grow 0 0"); + + //---- arrowPainter3 ---- + arrowPainter3.setScale(8.0F); + arrowPainter3.setDirection(7); + flatTestPanel1.add(arrowPainter3, "cell 2 5,align left top,grow 0 0"); + + //---- arrowPainter4 ---- + arrowPainter4.setScale(8.0F); + arrowPainter4.setDirection(3); + flatTestPanel1.add(arrowPainter4, "cell 3 5,align left top,grow 0 0"); + + //======== panel1 ======== + { + panel1.setLayout(new BoxLayout(panel1, BoxLayout.Y_AXIS)); + + //---- arrowPainter5 ---- + arrowPainter5.setScale(8.0F); + arrowPainter5.setDirection(1); + arrowPainter5.setH(10); + arrowPainter5.setHalfHeight(true); + arrowPainter5.setYOffset(1); + panel1.add(arrowPainter5); + + //---- arrowPainter6 ---- + arrowPainter6.setScale(8.0F); + arrowPainter6.setH(10); + arrowPainter6.setHalfHeight(true); + arrowPainter6.setYOffset(-1); + panel1.add(arrowPainter6); + } + flatTestPanel1.add(panel1, "cell 4 5,align left top,grow 0 0"); + + //======== panel2 ======== + { + panel2.setLayout(new BoxLayout(panel2, BoxLayout.X_AXIS)); + + //---- arrowPainter7 ---- + arrowPainter7.setScale(8.0F); + arrowPainter7.setDirection(7); + arrowPainter7.setW(10); + arrowPainter7.setHalfWidth(true); + arrowPainter7.setXOffset(1); + panel2.add(arrowPainter7); + + //---- arrowPainter8 ---- + arrowPainter8.setScale(8.0F); + arrowPainter8.setDirection(3); + arrowPainter8.setW(10); + arrowPainter8.setHalfWidth(true); + arrowPainter8.setXOffset(-1); + panel2.add(arrowPainter8); + } + flatTestPanel1.add(panel2, "cell 5 5,align left top,grow 0 0"); + + //======== panel5 ======== + { + panel5.setBorder(new TitledBorder("Arrow Control")); + panel5.setLayout(new MigLayout( + "hidemode 3", + // columns + "[fill]" + + "[fill]", + // rows + "[]" + + "[]" + + "[]" + + "[]" + + "[]")); + + //---- arrowWidthLabel ---- + arrowWidthLabel.setText("Width:"); + panel5.add(arrowWidthLabel, "cell 0 0"); + + //---- arrowWidthSpinner ---- + arrowWidthSpinner.setModel(new SpinnerNumberModel(20, 0, null, 1)); + arrowWidthSpinner.addChangeListener(e -> arrowSizeChanged()); + panel5.add(arrowWidthSpinner, "cell 1 0"); + + //---- arrowHeightLabel ---- + arrowHeightLabel.setText("Height:"); + panel5.add(arrowHeightLabel, "cell 0 1"); + + //---- arrowHeightSpinner ---- + arrowHeightSpinner.setModel(new SpinnerNumberModel(20, 0, null, 1)); + arrowHeightSpinner.addChangeListener(e -> arrowSizeChanged()); + panel5.add(arrowHeightSpinner, "cell 1 1"); + + //---- arrowSizeLabel ---- + arrowSizeLabel.setText("Arrow Size:"); + panel5.add(arrowSizeLabel, "cell 0 2"); + + //---- arrowSizeSpinner ---- + arrowSizeSpinner.setModel(new SpinnerNumberModel(8, 2, null, 1)); + arrowSizeSpinner.addChangeListener(e -> arrowSizeChanged()); + panel5.add(arrowSizeSpinner, "cell 1 2"); + + //---- vectorCheckBox ---- + vectorCheckBox.setText("vector"); + vectorCheckBox.addActionListener(e -> vectorChanged()); + panel5.add(vectorCheckBox, "cell 0 3 2 1,alignx left,growx 0"); + + //---- buttonCheckBox ---- + buttonCheckBox.setText("FlatArrowButton"); + buttonCheckBox.addActionListener(e -> checkBox1ActionPerformed()); + panel5.add(buttonCheckBox, "cell 0 4 2 1,alignx left,growx 0"); + } + flatTestPanel1.add(panel5, "cell 6 5,aligny top,growy 0"); + + //---- arrowPainter9 ---- + arrowPainter9.setScale(8.0F); + arrowPainter9.setChevron(false); + flatTestPanel1.add(arrowPainter9, "cell 0 6,align left top,grow 0 0"); + + //---- arrowPainter10 ---- + arrowPainter10.setScale(8.0F); + arrowPainter10.setDirection(1); + arrowPainter10.setChevron(false); + flatTestPanel1.add(arrowPainter10, "cell 1 6,align left top,grow 0 0"); + + //---- arrowPainter11 ---- + arrowPainter11.setScale(8.0F); + arrowPainter11.setDirection(7); + arrowPainter11.setChevron(false); + flatTestPanel1.add(arrowPainter11, "cell 2 6,align left top,grow 0 0"); + + //---- arrowPainter12 ---- + arrowPainter12.setScale(8.0F); + arrowPainter12.setDirection(3); + arrowPainter12.setChevron(false); + flatTestPanel1.add(arrowPainter12, "cell 3 6,align left top,grow 0 0"); + + //======== panel3 ======== + { + panel3.setLayout(new BoxLayout(panel3, BoxLayout.Y_AXIS)); + + //---- arrowPainter13 ---- + arrowPainter13.setScale(8.0F); + arrowPainter13.setDirection(1); + arrowPainter13.setH(10); + arrowPainter13.setChevron(false); + arrowPainter13.setHalfHeight(true); + arrowPainter13.setYOffset(1); + panel3.add(arrowPainter13); + + //---- arrowPainter14 ---- + arrowPainter14.setScale(8.0F); + arrowPainter14.setH(10); + arrowPainter14.setChevron(false); + arrowPainter14.setHalfHeight(true); + arrowPainter14.setYOffset(-1); + panel3.add(arrowPainter14); + } + flatTestPanel1.add(panel3, "cell 4 6,align left top,grow 0 0"); + + //======== panel4 ======== + { + panel4.setLayout(new BoxLayout(panel4, BoxLayout.X_AXIS)); + + //---- arrowPainter15 ---- + arrowPainter15.setScale(8.0F); + arrowPainter15.setDirection(7); + arrowPainter15.setW(10); + arrowPainter15.setChevron(false); + arrowPainter15.setHalfWidth(true); + arrowPainter15.setXOffset(1); + panel4.add(arrowPainter15); + + //---- arrowPainter16 ---- + arrowPainter16.setScale(8.0F); + arrowPainter16.setDirection(3); + arrowPainter16.setW(10); + arrowPainter16.setChevron(false); + arrowPainter16.setHalfWidth(true); + arrowPainter16.setXOffset(-1); + panel4.add(arrowPainter16); + } + flatTestPanel1.add(panel4, "cell 5 6,align left top,grow 0 0"); } setViewportView(flatTestPanel1); // JFormDesigner - End of component initialization //GEN-END:initComponents } // JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables + private JSpinner arrowWidthSpinner; + private JSpinner arrowHeightSpinner; + private JSpinner arrowSizeSpinner; + private JCheckBox vectorCheckBox; + private JCheckBox buttonCheckBox; // JFormDesigner - End of variables declaration //GEN-END:variables - //---- class Preview ---- + //---- class BorderPainter ------------------------------------------------ public static class BorderPainter extends JComponent @@ -507,4 +781,170 @@ public class FlatPaintingTest FlatUIUtils.resetRenderingHints( g2, oldRenderingHints ); } } + + //---- class ArrowPainter ------------------------------------------------- + + public static class ArrowPainter + extends JComponent + { + private int w = 20; + private int h = 20; + private int direction = SwingConstants.SOUTH; + private boolean chevron = true; + private int arrowSize = FlatArrowButton.DEFAULT_ARROW_WIDTH; + private int xOffset = 0; + private int yOffset = 0; + private float scale = 1; + private boolean halfWidth; + private boolean halfHeight; + public boolean vector; + public boolean button; + + public ArrowPainter() { + } + + public int getW() { + return w; + } + + public void setW( int w ) { + this.w = w; + invalidate(); + } + + public int getH() { + return h; + } + + public void setH( int h ) { + this.h = h; + invalidate(); + } + + public int getDirection() { + return direction; + } + + public void setDirection( int direction ) { + this.direction = direction; + } + + public boolean isChevron() { + return chevron; + } + + public void setChevron( boolean chevron ) { + this.chevron = chevron; + } + + public int getArrowSize() { + return arrowSize; + } + + public void setArrowSize( int arrowSize ) { + this.arrowSize = arrowSize; + } + + public int getXOffset() { + return xOffset; + } + + public void setXOffset( int xOffset ) { + this.xOffset = xOffset; + } + + public int getYOffset() { + return yOffset; + } + + public void setYOffset( int yOffset ) { + this.yOffset = yOffset; + } + + public float getScale() { + return scale; + } + + public void setScale( float scale ) { + this.scale = scale; + } + + public boolean isHalfWidth() { + return halfWidth; + } + + public void setHalfWidth( boolean halfWidth ) { + this.halfWidth = halfWidth; + } + + public boolean isHalfHeight() { + return halfHeight; + } + + public void setHalfHeight( boolean halfHeight ) { + this.halfHeight = halfHeight; + } + + @Override + public Dimension getPreferredSize() { + return UIScale.scale( new Dimension( (int) (w * scale), (int) (h * scale) ) ); + } + + @Override + public Dimension getMinimumSize() { + return getPreferredSize(); + } + + @Override + protected void paintComponent( Graphics g ) { + Graphics2D g2 = (Graphics2D) g; + Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g2 ); + + g2.scale( scale, scale ); + + int width = UIScale.scale( w ); + int height = UIScale.scale( h ); + + if( vector ) { + g.setColor( Color.blue ); + paintArrow( g2, width, height ); + } else { + BufferedImage bi = new BufferedImage( width, height, BufferedImage.TYPE_INT_ARGB ); + Graphics bg = bi.createGraphics(); + try { + FlatUIUtils.setRenderingHints( bg ); + + bg.setColor( Color.blue ); + paintArrow( (Graphics2D) bg, width, height ); + } finally { + bg.dispose(); + } + + g.drawImage( bi, 0, 0, width, height, null ); + } + + HiDPIUtils.paintAtScale1x( g2, 0, 0, width, height, + (g2d, x2, y2, width2, height2, scaleFactor) -> { + g2d.setColor( Color.magenta ); + g2d.drawRect( x2, y2, width2 - 1, height2 - 1 ); + } ); + + FlatUIUtils.resetRenderingHints( g2, oldRenderingHints ); + } + + private void paintArrow( Graphics2D g, int width, int height ) { + FlatUIUtils.paintArrow( g, 0, 0, width, height, + direction, chevron, arrowSize, xOffset, yOffset ); + + if( button ) { + FlatArrowButton arrowButton = new FlatArrowButton( direction, + chevron ? null : "triangle", Color.black, null, null, null, null, null ); + arrowButton.setArrowWidth( arrowSize ); + arrowButton.setXOffset( xOffset ); + arrowButton.setYOffset( yOffset ); + arrowButton.setSize( width, height ); + arrowButton.paint( g ); + } + } + } } diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatPaintingTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatPaintingTest.jfd index 38abfc3f..0d6c21c2 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatPaintingTest.jfd +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatPaintingTest.jfd @@ -1,4 +1,4 @@ -JFDML JFormDesigner: "7.0.2.0.298" Java: "15" encoding: "UTF-8" +JFDML JFormDesigner: "7.0.3.1.342" Java: "15" encoding: "UTF-8" new FormModel { contentType: "form/swing" @@ -12,7 +12,7 @@ new FormModel { add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { "$layoutConstraints": "ltr,insets dialog,hidemode 3" "$columnConstraints": "[fill][fill][fill][fill][fill][fill][fill][fill][fill]" - "$rowConstraints": "[top][top][top][top][]" + "$rowConstraints": "[top][top][top][top][]para[][]" } ) { name: "flatTestPanel1" add( new FormComponent( "com.formdev.flatlaf.testing.FlatPaintingTest$BorderPainter" ) { @@ -345,10 +345,245 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 8 4" } ) + add( new FormComponent( "com.formdev.flatlaf.testing.FlatPaintingTest$ArrowPainter" ) { + name: "arrowPainter1" + "scale": 8.0f + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 5,align left top,grow 0 0" + } ) + add( new FormComponent( "com.formdev.flatlaf.testing.FlatPaintingTest$ArrowPainter" ) { + name: "arrowPainter2" + "scale": 8.0f + "direction": 1 + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 5,align left top,grow 0 0" + } ) + add( new FormComponent( "com.formdev.flatlaf.testing.FlatPaintingTest$ArrowPainter" ) { + name: "arrowPainter3" + "scale": 8.0f + "direction": 7 + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 2 5,align left top,grow 0 0" + } ) + add( new FormComponent( "com.formdev.flatlaf.testing.FlatPaintingTest$ArrowPainter" ) { + name: "arrowPainter4" + "scale": 8.0f + "direction": 3 + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 3 5,align left top,grow 0 0" + } ) + add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class javax.swing.BoxLayout ) { + "axis": 1 + } ) { + name: "panel1" + add( new FormComponent( "com.formdev.flatlaf.testing.FlatPaintingTest$ArrowPainter" ) { + name: "arrowPainter5" + "scale": 8.0f + "direction": 1 + "h": 10 + "halfHeight": true + "YOffset": 1 + } ) + add( new FormComponent( "com.formdev.flatlaf.testing.FlatPaintingTest$ArrowPainter" ) { + name: "arrowPainter6" + "scale": 8.0f + "h": 10 + "halfHeight": true + "YOffset": -1 + } ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 4 5,align left top,grow 0 0" + } ) + add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class javax.swing.BoxLayout ) ) { + name: "panel2" + add( new FormComponent( "com.formdev.flatlaf.testing.FlatPaintingTest$ArrowPainter" ) { + name: "arrowPainter7" + "scale": 8.0f + "direction": 7 + "w": 10 + "halfWidth": true + "XOffset": 1 + } ) + add( new FormComponent( "com.formdev.flatlaf.testing.FlatPaintingTest$ArrowPainter" ) { + name: "arrowPainter8" + "scale": 8.0f + "direction": 3 + "w": 10 + "halfWidth": true + "XOffset": -1 + } ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 5 5,align left top,grow 0 0" + } ) + add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { + "$layoutConstraints": "hidemode 3" + "$columnConstraints": "[fill][fill]" + "$rowConstraints": "[][][][][]" + } ) { + name: "panel5" + "border": new javax.swing.border.TitledBorder( "Arrow Control" ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "arrowWidthLabel" + "text": "Width:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 0" + } ) + add( new FormComponent( "javax.swing.JSpinner" ) { + name: "arrowWidthSpinner" + "model": new javax.swing.SpinnerNumberModel { + minimum: 0 + value: 20 + } + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "arrowSizeChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 0" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "arrowHeightLabel" + "text": "Height:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 1" + } ) + add( new FormComponent( "javax.swing.JSpinner" ) { + name: "arrowHeightSpinner" + "model": new javax.swing.SpinnerNumberModel { + minimum: 0 + value: 20 + } + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "arrowSizeChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 1" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "arrowSizeLabel" + "text": "Arrow Size:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 2" + } ) + add( new FormComponent( "javax.swing.JSpinner" ) { + name: "arrowSizeSpinner" + "model": new javax.swing.SpinnerNumberModel { + minimum: 2 + value: 8 + } + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "arrowSizeChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 2" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "vectorCheckBox" + "text": "vector" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "vectorChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 3 2 1,alignx left,growx 0" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "buttonCheckBox" + "text": "FlatArrowButton" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "checkBox1ActionPerformed", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 4 2 1,alignx left,growx 0" + } ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 6 5,aligny top,growy 0" + } ) + add( new FormComponent( "com.formdev.flatlaf.testing.FlatPaintingTest$ArrowPainter" ) { + name: "arrowPainter9" + "scale": 8.0f + "chevron": false + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 6,align left top,grow 0 0" + } ) + add( new FormComponent( "com.formdev.flatlaf.testing.FlatPaintingTest$ArrowPainter" ) { + name: "arrowPainter10" + "scale": 8.0f + "direction": 1 + "chevron": false + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 6,align left top,grow 0 0" + } ) + add( new FormComponent( "com.formdev.flatlaf.testing.FlatPaintingTest$ArrowPainter" ) { + name: "arrowPainter11" + "scale": 8.0f + "direction": 7 + "chevron": false + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 2 6,align left top,grow 0 0" + } ) + add( new FormComponent( "com.formdev.flatlaf.testing.FlatPaintingTest$ArrowPainter" ) { + name: "arrowPainter12" + "scale": 8.0f + "direction": 3 + "chevron": false + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 3 6,align left top,grow 0 0" + } ) + add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class javax.swing.BoxLayout ) { + "axis": 1 + } ) { + name: "panel3" + add( new FormComponent( "com.formdev.flatlaf.testing.FlatPaintingTest$ArrowPainter" ) { + name: "arrowPainter13" + "scale": 8.0f + "direction": 1 + "h": 10 + "chevron": false + "halfHeight": true + "YOffset": 1 + } ) + add( new FormComponent( "com.formdev.flatlaf.testing.FlatPaintingTest$ArrowPainter" ) { + name: "arrowPainter14" + "scale": 8.0f + "h": 10 + "chevron": false + "halfHeight": true + "YOffset": -1 + } ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 4 6,align left top,grow 0 0" + } ) + add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class javax.swing.BoxLayout ) ) { + name: "panel4" + add( new FormComponent( "com.formdev.flatlaf.testing.FlatPaintingTest$ArrowPainter" ) { + name: "arrowPainter15" + "scale": 8.0f + "direction": 7 + "w": 10 + "chevron": false + "halfWidth": true + "XOffset": 1 + } ) + add( new FormComponent( "com.formdev.flatlaf.testing.FlatPaintingTest$ArrowPainter" ) { + name: "arrowPainter16" + "scale": 8.0f + "direction": 3 + "w": 10 + "chevron": false + "halfWidth": true + "XOffset": -1 + } ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 5 6,align left top,grow 0 0" + } ) } ) }, new FormLayoutConstraints( null ) { "location": new java.awt.Point( 0, 0 ) - "size": new java.awt.Dimension( 1610, 880 ) + "size": new java.awt.Dimension( 1610, 1160 ) } ) } }