mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2025-12-07 14:30:56 +03:00
Tree: support rounded selection
This commit is contained in:
@@ -353,15 +353,9 @@ debug*/
|
||||
|
||||
/** @since 3 */
|
||||
protected void paintSelection( Graphics g, Color selectionBackground, Insets selectionInsets, int selectionArc ) {
|
||||
Rectangle r = FlatUIUtils.subtractInsets( new Rectangle( menuItem.getSize() ), scale( selectionInsets ) );
|
||||
|
||||
g.setColor( deriveBackground( selectionBackground ) );
|
||||
if( selectionArc > 0 ) {
|
||||
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
|
||||
FlatUIUtils.paintComponentBackground( (Graphics2D) g, r.x, r.y, r.width, r.height, 0, scale( selectionArc ) );
|
||||
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||
} else
|
||||
g.fillRect( r.x, r.y, r.width, r.height );
|
||||
FlatUIUtils.paintSelection( (Graphics2D) g, 0, 0, menuItem.getWidth(), menuItem.getHeight(),
|
||||
scale( selectionInsets ), scale( (float) selectionArc ), 0 );
|
||||
}
|
||||
|
||||
/** @since 3 */
|
||||
|
||||
@@ -21,6 +21,7 @@ import static com.formdev.flatlaf.FlatClientProperties.*;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.MouseEvent;
|
||||
@@ -36,6 +37,7 @@ import javax.swing.LookAndFeel;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.JTree.DropLocation;
|
||||
import javax.swing.event.TreeSelectionListener;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicTreeUI;
|
||||
import javax.swing.tree.DefaultTreeCellRenderer;
|
||||
@@ -96,6 +98,8 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault Tree.selectionForeground Color
|
||||
* @uiDefault Tree.selectionInactiveBackground Color
|
||||
* @uiDefault Tree.selectionInactiveForeground Color
|
||||
* @uiDefault Tree.selectionInsets Insets
|
||||
* @uiDefault Tree.selectionArc int
|
||||
* @uiDefault Tree.wideSelection boolean
|
||||
* @uiDefault Tree.showCellFocusIndicator boolean
|
||||
*
|
||||
@@ -132,6 +136,8 @@ public class FlatTreeUI
|
||||
@Styleable protected Color selectionInactiveBackground;
|
||||
@Styleable protected Color selectionInactiveForeground;
|
||||
@Styleable protected Color selectionBorderColor;
|
||||
/** @since 3 */ @Styleable protected Insets selectionInsets;
|
||||
/** @since 3 */ @Styleable protected int selectionArc;
|
||||
@Styleable protected boolean wideSelection;
|
||||
@Styleable protected boolean showCellFocusIndicator;
|
||||
|
||||
@@ -175,6 +181,8 @@ public class FlatTreeUI
|
||||
selectionInactiveBackground = UIManager.getColor( "Tree.selectionInactiveBackground" );
|
||||
selectionInactiveForeground = UIManager.getColor( "Tree.selectionInactiveForeground" );
|
||||
selectionBorderColor = UIManager.getColor( "Tree.selectionBorderColor" );
|
||||
selectionInsets = UIManager.getInsets( "Tree.selectionInsets" );
|
||||
selectionArc = UIManager.getInt( "Tree.selectionArc" );
|
||||
wideSelection = UIManager.getBoolean( "Tree.wideSelection" );
|
||||
showCellFocusIndicator = UIManager.getBoolean( "Tree.showCellFocusIndicator" );
|
||||
|
||||
@@ -295,6 +303,34 @@ public class FlatTreeUI
|
||||
tree.repaint( 0, r.y, tree.getWidth(), r.height );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TreeSelectionListener createTreeSelectionListener() {
|
||||
TreeSelectionListener superListener = super.createTreeSelectionListener();
|
||||
return e -> {
|
||||
superListener.valueChanged( e );
|
||||
|
||||
// for united rounded selection, repaint parts of the rows that adjoin to the changed rows
|
||||
TreePath[] changedPaths;
|
||||
if( useUnitedRoundedSelection() &&
|
||||
tree.getSelectionCount() > 1 &&
|
||||
(changedPaths = e.getPaths()) != null )
|
||||
{
|
||||
if( changedPaths.length > 4 ) {
|
||||
// same is done in BasicTreeUI.Handler.valueChanged()
|
||||
tree.repaint();
|
||||
} else {
|
||||
int arcHeight = (int) Math.ceil( UIScale.scale( (float) selectionArc ) );
|
||||
|
||||
for( TreePath path : changedPaths ) {
|
||||
Rectangle r = getPathBounds( tree, path );
|
||||
if( r != null )
|
||||
tree.repaint( r.x, r.y - arcHeight, r.width, r.height + (arcHeight * 2) );
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle getPathBounds( JTree tree, TreePath path ) {
|
||||
Rectangle bounds = super.getPathBounds( tree, path );
|
||||
@@ -491,7 +527,16 @@ public class FlatTreeUI
|
||||
private void paintWideSelection( Graphics g, Rectangle clipBounds, Insets insets, Rectangle bounds,
|
||||
TreePath path, int row, boolean isExpanded, boolean hasBeenExpanded, boolean isLeaf )
|
||||
{
|
||||
g.fillRect( 0, bounds.y, tree.getWidth(), bounds.height );
|
||||
int flags = 0;
|
||||
if( useUnitedRoundedSelection() ) {
|
||||
if( row > 0 && tree.isRowSelected( row - 1 ) )
|
||||
flags |= FlatUIUtils.FLAG_TOP_NOT_ROUNDED;
|
||||
if( row < tree.getRowCount() - 1 && tree.isRowSelected( row + 1 ) )
|
||||
flags |= FlatUIUtils.FLAG_BOTTOM_NOT_ROUNDED;
|
||||
}
|
||||
|
||||
FlatUIUtils.paintSelection( (Graphics2D) g, 0, bounds.y, tree.getWidth(), bounds.height,
|
||||
UIScale.scale( selectionInsets ), UIScale.scale( (float) selectionArc ), flags );
|
||||
|
||||
// paint expand/collapse icon
|
||||
// (was already painted before, but painted over with wide selection)
|
||||
@@ -501,6 +546,11 @@ public class FlatTreeUI
|
||||
}
|
||||
}
|
||||
|
||||
private boolean useUnitedRoundedSelection() {
|
||||
return selectionArc > 0 &&
|
||||
(selectionInsets == null || (selectionInsets.top == 0 && selectionInsets.bottom == 0));
|
||||
}
|
||||
|
||||
private void paintCellBackground( Graphics g, Component rendererComponent, Rectangle bounds ) {
|
||||
int xOffset = 0;
|
||||
int imageOffset = 0;
|
||||
@@ -514,7 +564,8 @@ public class FlatTreeUI
|
||||
xOffset = label.getComponentOrientation().isLeftToRight() ? imageOffset : 0;
|
||||
}
|
||||
|
||||
g.fillRect( bounds.x + xOffset, bounds.y, bounds.width - imageOffset, bounds.height );
|
||||
FlatUIUtils.paintSelection( (Graphics2D) g, bounds.x + xOffset, bounds.y, bounds.width - imageOffset, bounds.height,
|
||||
UIScale.scale( selectionInsets ), UIScale.scale( (float) selectionArc ), 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -393,9 +393,9 @@ public class FlatUIUtils
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the background of a component with a round rectangle.
|
||||
* Fills the background of a component with a rounded rectangle.
|
||||
* <p>
|
||||
* The bounds of the painted round rectangle are
|
||||
* The bounds of the painted rounded rectangle are
|
||||
* {@code x + focusWidth, y + focusWidth, width - (focusWidth * 2), height - (focusWidth * 2)}.
|
||||
* The given arc diameter refers to the painted rectangle (and not to {@code x,y,width,height}).
|
||||
*
|
||||
@@ -426,7 +426,7 @@ public class FlatUIUtils
|
||||
* <p>
|
||||
*
|
||||
* <strong>Background</strong>:
|
||||
* The bounds of the filled round rectangle are
|
||||
* The bounds of the filled rounded rectangle are
|
||||
* {@code [x + focusWidth, y + focusWidth, width - (focusWidth * 2), height - (focusWidth * 2)]}.
|
||||
* The focus border and the border may paint over the background.
|
||||
* <p>
|
||||
@@ -624,6 +624,67 @@ public class FlatUIUtils
|
||||
}
|
||||
}
|
||||
|
||||
// flags for paintSelection()
|
||||
public static final int
|
||||
FLAG_TOP_LEFT_NOT_ROUNDED = (1 << 0),
|
||||
FLAG_TOP_RIGHT_NOT_ROUNDED = (1 << 1),
|
||||
FLAG_BOTTOM_LEFT_NOT_ROUNDED = (1 << 2),
|
||||
FLAG_BOTTOM_RIGHT_NOT_ROUNDED = (1 << 3),
|
||||
FLAG_TOP_NOT_ROUNDED = FLAG_TOP_LEFT_NOT_ROUNDED | FLAG_TOP_RIGHT_NOT_ROUNDED,
|
||||
FLAG_BOTTOM_NOT_ROUNDED = FLAG_BOTTOM_LEFT_NOT_ROUNDED | FLAG_BOTTOM_RIGHT_NOT_ROUNDED;
|
||||
|
||||
/**
|
||||
* Paints a selection.
|
||||
* <p>
|
||||
* The bounds of the painted selection (rounded) rectangle are
|
||||
* {@code x + insets.left, y + insets.top, width - insets.left - insets.right, height - insets.top - insets.bottom}.
|
||||
* The given arc diameter refers to the painted rectangle (and not to {@code x,y,width,height}).
|
||||
*
|
||||
* @since 3
|
||||
*/
|
||||
public static void paintSelection( Graphics2D g, int x, int y, int width, int height,
|
||||
Insets insets, float arc, int flags )
|
||||
{
|
||||
if( insets != null ) {
|
||||
x += insets.left;
|
||||
y += insets.top;
|
||||
width -= insets.left + insets.right;
|
||||
height -= insets.top + insets.bottom;
|
||||
}
|
||||
|
||||
if( arc > 0 ) {
|
||||
// because createRoundRectanglePath() expects a radius
|
||||
float arcRadius = arc / 2;
|
||||
|
||||
float arcTopLeft = ((flags & FLAG_TOP_LEFT_NOT_ROUNDED) != 0) ? 0 : arcRadius;
|
||||
float arcTopRight = ((flags & FLAG_TOP_RIGHT_NOT_ROUNDED) != 0) ? 0 : arcRadius;
|
||||
float arcBottomLeft = ((flags & FLAG_BOTTOM_LEFT_NOT_ROUNDED) != 0) ? 0 : arcRadius;
|
||||
float arcBottomRight = ((flags & FLAG_BOTTOM_RIGHT_NOT_ROUNDED) != 0) ? 0 : arcRadius;
|
||||
|
||||
double systemScaleFactor = UIScale.getSystemScaleFactor( g );
|
||||
if( systemScaleFactor != 1 && systemScaleFactor != 2 ) {
|
||||
// paint at scale 1x to avoid clipping on right and bottom edges at 125%, 150% or 175%
|
||||
HiDPIUtils.paintAtScale1x( g, x, y, width, height,
|
||||
(g2d, x2, y2, width2, height2, scaleFactor) -> {
|
||||
paintRoundedSelectionImpl( g2d, x2, y2, width2, height2,
|
||||
(float) (arcTopLeft * scaleFactor), (float) (arcTopRight * scaleFactor),
|
||||
(float) (arcBottomLeft * scaleFactor), (float) (arcBottomRight * scaleFactor) );
|
||||
} );
|
||||
} else
|
||||
paintRoundedSelectionImpl( g, x, y, width, height, arcTopLeft, arcTopRight, arcBottomLeft, arcBottomRight );
|
||||
|
||||
} else
|
||||
g.fillRect( x, y, width, height );
|
||||
}
|
||||
|
||||
private static void paintRoundedSelectionImpl( Graphics2D g, int x, int y, int width, int height,
|
||||
float arcTopLeft, float arcTopRight, float arcBottomLeft, float arcBottomRight )
|
||||
{
|
||||
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
|
||||
g.fill( FlatUIUtils.createRoundRectanglePath( x, y, width, height, arcTopLeft, arcTopRight, arcBottomLeft, arcBottomRight ) );
|
||||
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||
}
|
||||
|
||||
public static void paintGrip( Graphics g, int x, int y, int width, int height,
|
||||
boolean horizontal, int dotCount, int dotSize, int gap, boolean centerPrecise )
|
||||
{
|
||||
|
||||
@@ -881,6 +881,8 @@ Tree.dropCellForeground = @dropCellForeground
|
||||
Tree.dropLineColor = @dropLineColor
|
||||
Tree.rendererFillBackground = false
|
||||
Tree.rendererMargins = 1,2,1,2
|
||||
Tree.selectionInsets = 0,0,0,0
|
||||
Tree.selectionArc = 0
|
||||
Tree.wideSelection = true
|
||||
Tree.repaintWholeRow = true
|
||||
Tree.paintLines = false
|
||||
|
||||
@@ -921,6 +921,8 @@ public class TestFlatStyleableInfo
|
||||
"selectionInactiveBackground", Color.class,
|
||||
"selectionInactiveForeground", Color.class,
|
||||
"selectionBorderColor", Color.class,
|
||||
"selectionInsets", Insets.class,
|
||||
"selectionArc", int.class,
|
||||
"wideSelection", boolean.class,
|
||||
"showCellFocusIndicator", boolean.class,
|
||||
|
||||
|
||||
@@ -1127,6 +1127,8 @@ public class TestFlatStyling
|
||||
ui.applyStyle( "selectionInactiveBackground: #fff" );
|
||||
ui.applyStyle( "selectionInactiveForeground: #fff" );
|
||||
ui.applyStyle( "selectionBorderColor: #fff" );
|
||||
ui.applyStyle( "selectionInsets: 1,2,3,4" );
|
||||
ui.applyStyle( "selectionArc: 8" );
|
||||
ui.applyStyle( "wideSelection: true" );
|
||||
ui.applyStyle( "showCellFocusIndicator: true" );
|
||||
|
||||
|
||||
@@ -1376,11 +1376,13 @@ Tree.repaintWholeRow true
|
||||
Tree.rightChildIndent 11
|
||||
Tree.rowHeight 0
|
||||
Tree.scrollsOnExpand true
|
||||
Tree.selectionArc 0
|
||||
Tree.selectionBackground #4b6eaf HSL 219 40 49 javax.swing.plaf.ColorUIResource [UI]
|
||||
Tree.selectionBorderColor #000000 HSL 0 0 0 javax.swing.plaf.ColorUIResource [UI]
|
||||
Tree.selectionForeground #bbbbbb HSL 0 0 73 javax.swing.plaf.ColorUIResource [UI]
|
||||
Tree.selectionInactiveBackground #0f2a3d HSL 205 61 15 javax.swing.plaf.ColorUIResource [UI]
|
||||
Tree.selectionInactiveForeground #bbbbbb HSL 0 0 73 javax.swing.plaf.ColorUIResource [UI]
|
||||
Tree.selectionInsets 0,0,0,0 javax.swing.plaf.InsetsUIResource [UI]
|
||||
Tree.showCellFocusIndicator false
|
||||
Tree.textBackground #46494b HSL 204 3 28 javax.swing.plaf.ColorUIResource [UI]
|
||||
Tree.textForeground #bbbbbb HSL 0 0 73 javax.swing.plaf.ColorUIResource [UI]
|
||||
|
||||
@@ -1381,11 +1381,13 @@ Tree.repaintWholeRow true
|
||||
Tree.rightChildIndent 11
|
||||
Tree.rowHeight 0
|
||||
Tree.scrollsOnExpand true
|
||||
Tree.selectionArc 0
|
||||
Tree.selectionBackground #2675bf HSL 209 67 45 javax.swing.plaf.ColorUIResource [UI]
|
||||
Tree.selectionBorderColor #000000 HSL 0 0 0 javax.swing.plaf.ColorUIResource [UI]
|
||||
Tree.selectionForeground #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
|
||||
Tree.selectionInactiveBackground #d3d3d3 HSL 0 0 83 javax.swing.plaf.ColorUIResource [UI]
|
||||
Tree.selectionInactiveForeground #000000 HSL 0 0 0 javax.swing.plaf.ColorUIResource [UI]
|
||||
Tree.selectionInsets 0,0,0,0 javax.swing.plaf.InsetsUIResource [UI]
|
||||
Tree.showCellFocusIndicator false
|
||||
Tree.textBackground #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
|
||||
Tree.textForeground #000000 HSL 0 0 0 javax.swing.plaf.ColorUIResource [UI]
|
||||
|
||||
@@ -1401,11 +1401,13 @@ Tree.repaintWholeRow true
|
||||
Tree.rightChildIndent 11
|
||||
Tree.rowHeight 0
|
||||
Tree.scrollsOnExpand true
|
||||
Tree.selectionArc 0
|
||||
Tree.selectionBackground #00aa00 HSL 120 100 33 javax.swing.plaf.ColorUIResource [UI]
|
||||
Tree.selectionBorderColor #ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI]
|
||||
Tree.selectionForeground #ffff00 HSL 60 100 50 javax.swing.plaf.ColorUIResource [UI]
|
||||
Tree.selectionInactiveBackground #888888 HSL 0 0 53 javax.swing.plaf.ColorUIResource [UI]
|
||||
Tree.selectionInactiveForeground #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
|
||||
Tree.selectionInsets 0,0,0,0 javax.swing.plaf.InsetsUIResource [UI]
|
||||
Tree.showCellFocusIndicator false
|
||||
Tree.textBackground #fff0ff HSL 300 100 97 javax.swing.plaf.ColorUIResource [UI]
|
||||
Tree.textForeground #ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI]
|
||||
|
||||
@@ -1099,11 +1099,13 @@ Tree.repaintWholeRow
|
||||
Tree.rightChildIndent
|
||||
Tree.rowHeight
|
||||
Tree.scrollsOnExpand
|
||||
Tree.selectionArc
|
||||
Tree.selectionBackground
|
||||
Tree.selectionBorderColor
|
||||
Tree.selectionForeground
|
||||
Tree.selectionInactiveBackground
|
||||
Tree.selectionInactiveForeground
|
||||
Tree.selectionInsets
|
||||
Tree.showCellFocusIndicator
|
||||
Tree.textBackground
|
||||
Tree.textForeground
|
||||
|
||||
Reference in New Issue
Block a user