Accent color:

- Demo: added accent color switching to toolbar
- added `FlatLaf.setGlobalExtraDefaults()` for easy setting accent color at runtime

(issue #233)
This commit is contained in:
Karl Tauber
2021-08-31 14:06:41 +02:00
parent 7f9cf6f45c
commit d333d0c9e4
7 changed files with 220 additions and 19 deletions

View File

@@ -86,6 +86,7 @@ public abstract class FlatLaf
private static final String DESKTOPFONTHINTS = "awt.font.desktophints"; private static final String DESKTOPFONTHINTS = "awt.font.desktophints";
private static List<Object> customDefaultsSources; private static List<Object> customDefaultsSources;
private static Map<String, String> globalExtraDefaults;
private Map<String, String> extraDefaults; private Map<String, String> extraDefaults;
private String desktopPropertyName; private String desktopPropertyName;
@@ -465,10 +466,13 @@ public abstract class FlatLaf
} }
protected Properties getAdditionalDefaults() { protected Properties getAdditionalDefaults() {
if( extraDefaults == null ) if( globalExtraDefaults == null && extraDefaults == null )
return null; return null;
Properties properties = new Properties(); Properties properties = new Properties();
if( globalExtraDefaults != null )
properties.putAll( globalExtraDefaults );
if( extraDefaults != null )
properties.putAll( extraDefaults ); properties.putAll( extraDefaults );
return properties; return properties;
} }
@@ -785,6 +789,38 @@ public abstract class FlatLaf
customDefaultsSources.remove( folder ); customDefaultsSources.remove( folder );
} }
/**
* Gets global extra UI defaults; or {@code null}.
*
* @since 1.6
*/
public static Map<String, String> getGlobalExtraDefaults() {
return globalExtraDefaults;
}
/**
* Sets global extra UI defaults, which are only used when setting up the application look and feel.
* E.g. using {@link UIManager#setLookAndFeel(LookAndFeel)} or {@link #setup(LookAndFeel)}.
* <p>
* The global extra defaults are useful for smaller additional defaults that may change.
* E.g. accent color. Otherwise FlatLaf properties files should be used.
* See {@link #registerCustomDefaultsSource(String)}.
* <p>
* The keys and values are strings in same format as in FlatLaf properties files.
* <p>
* Sample that setups "FlatLaf Light" theme with red accent color:
* <pre>{@code
* FlatLaf.setGlobalExtraDefaults( Collections.singletonMap( "@accentColor", "#f00" ) );
* FlatLightLaf.setup();
* }</pre>
*
* @see #setExtraDefaults(Map)
* @since 1.6
*/
public static void setGlobalExtraDefaults( Map<String, String> globalExtraDefaults ) {
FlatLaf.globalExtraDefaults = globalExtraDefaults;
}
/** /**
* Gets extra UI defaults; or {@code null}. * Gets extra UI defaults; or {@code null}.
* *
@@ -811,6 +847,7 @@ public abstract class FlatLaf
* FlatLaf.setup( laf ); * FlatLaf.setup( laf );
* }</pre> * }</pre>
* *
* @see #setGlobalExtraDefaults(Map)
* @since 1.6 * @since 1.6
*/ */
public void setExtraDefaults( Map<String, String> extraDefaults ) { public void setExtraDefaults( Map<String, String> extraDefaults ) {

View File

@@ -49,6 +49,9 @@ public class ColorFunctions
/** /**
* Returns a color that is a mixture of two colors. * Returns a color that is a mixture of two colors.
* <p>
* This can be used to animate a color change from {@code color1} to {@code color2}
* by invoking this method multiple times with growing {@code weight} (from 0 to 1).
* *
* @param color1 first color * @param color1 first color
* @param color2 second color * @param color2 second color
@@ -79,6 +82,34 @@ public class ColorFunctions
Math.round( a2 + ((a1 - a2) * weight) ) ); Math.round( a2 + ((a1 - a2) * weight) ) );
} }
/**
* Mix color with white, which makes the color brighter.
* This is the same as {@link #mix}{@code (Color.white, color, weight)}.
*
* @param color second color
* @param weight the weight (in range 0-1) to mix the two colors.
* Larger weight uses more of first color, smaller weight more of second color.
* @return mixture of colors
* @since 1.6
*/
public static Color tint( Color color, float weight ) {
return mix( Color.white, color, weight );
}
/**
* Mix color with black, which makes the color darker.
* This is the same as {@link #mix}{@code (Color.black, color, weight)}.
*
* @param color second color
* @param weight the weight (in range 0-1) to mix the two colors.
* Larger weight uses more of first color, smaller weight more of second color.
* @return mixture of colors
* @since 1.6
*/
public static Color shade( Color color, float weight ) {
return mix( Color.black, color, weight );
}
/** /**
* Calculates the luma (perceptual brightness) of the given color. * Calculates the luma (perceptual brightness) of the given color.
* <p> * <p>

View File

@@ -41,7 +41,7 @@
Button.focusedBackground = null Button.focusedBackground = null
Button.default.background = @accentButtonDefaultBackground Button.default.background = @accentButtonDefaultBackground
Button.default.foreground = #fff Button.default.foreground = contrast($Button.default.background,lighten(@foreground,50%),#fff,50%)
Button.default.focusedBackground = null Button.default.focusedBackground = null
Button.default.borderColor = shade($Button.default.background,15%) Button.default.borderColor = shade($Button.default.background,15%)
Button.default.hoverBorderColor = tint($Button.default.background,50%) Button.default.hoverBorderColor = tint($Button.default.background,50%)

View File

@@ -24,11 +24,16 @@ import java.net.URISyntaxException;
import java.time.Year; import java.time.Year;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.prefs.Preferences; import java.util.prefs.Preferences;
import javax.swing.*; import javax.swing.*;
import javax.swing.text.DefaultEditorKit; import javax.swing.text.DefaultEditorKit;
import javax.swing.text.StyleContext; import javax.swing.text.StyleContext;
import com.formdev.flatlaf.FlatDarculaLaf;
import com.formdev.flatlaf.FlatDarkLaf;
import com.formdev.flatlaf.FlatIntelliJLaf;
import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.FlatLightLaf;
import com.formdev.flatlaf.demo.HintManager.Hint; import com.formdev.flatlaf.demo.HintManager.Hint;
import com.formdev.flatlaf.demo.extras.*; import com.formdev.flatlaf.demo.extras.*;
import com.formdev.flatlaf.demo.intellijthemes.*; import com.formdev.flatlaf.demo.intellijthemes.*;
@@ -37,9 +42,12 @@ import com.formdev.flatlaf.extras.FlatSVGIcon;
import com.formdev.flatlaf.extras.FlatUIDefaultsInspector; import com.formdev.flatlaf.extras.FlatUIDefaultsInspector;
import com.formdev.flatlaf.extras.components.FlatButton; import com.formdev.flatlaf.extras.components.FlatButton;
import com.formdev.flatlaf.extras.components.FlatButton.ButtonType; import com.formdev.flatlaf.extras.components.FlatButton.ButtonType;
import com.formdev.flatlaf.icons.FlatAbstractIcon;
import com.formdev.flatlaf.extras.FlatSVGUtils; import com.formdev.flatlaf.extras.FlatSVGUtils;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.ui.JBRCustomDecorations; import com.formdev.flatlaf.ui.JBRCustomDecorations;
import com.formdev.flatlaf.util.ColorFunctions;
import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
import net.miginfocom.layout.ConstraintParser; import net.miginfocom.layout.ConstraintParser;
@@ -65,6 +73,7 @@ class DemoFrame
initComponents(); initComponents();
updateFontMenuItems(); updateFontMenuItems();
initAccentColors();
controlBar.initialize( this, tabbedPane ); controlBar.initialize( this, tabbedPane );
setIconImages( FlatSVGUtils.createWindowIconImages( "/com/formdev/flatlaf/demo/FlatLaf.svg" ) ); setIconImages( FlatSVGUtils.createWindowIconImages( "/com/formdev/flatlaf/demo/FlatLaf.svg" ) );
@@ -323,6 +332,74 @@ class DemoFrame
item.setEnabled( enabled ); item.setEnabled( enabled );
} }
// the real colors are defined in
// flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/FlatLightLaf.properties and
// flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/FlatDarkLaf.properties
private static String[] accentColorKeys = {
"Demo.accent.blue", "Demo.accent.purple", "Demo.accent.red",
"Demo.accent.orange", "Demo.accent.yellow", "Demo.accent.green",
};
private final JToggleButton[] accentColorButtons = new JToggleButton[accentColorKeys.length];
private JLabel accentColorLabel;
private void initAccentColors() {
accentColorLabel = new JLabel( "Accent color:" );
toolBar.add( Box.createHorizontalGlue() );
toolBar.add( accentColorLabel );
ButtonGroup group = new ButtonGroup();
for( int i = 0; i < accentColorButtons.length; i++ ) {
accentColorButtons[i] = new JToggleButton( new AccentColorIcon( accentColorKeys[i] ) );
accentColorButtons[i].addActionListener( this::accentColorChanged );
toolBar.add( accentColorButtons[i] );
group.add( accentColorButtons[i] );
}
accentColorButtons[0].setSelected( true );
UIManager.addPropertyChangeListener( e -> {
if( "lookAndFeel".equals( e.getPropertyName() ) )
updateAccentColorButtons();
} );
updateAccentColorButtons();
}
private void accentColorChanged( ActionEvent e ) {
String accentColor = accentColorKeys[0];
for( int i = 0; i < accentColorButtons.length; i++ ) {
if( accentColorButtons[i].isSelected() ) {
accentColor = accentColorKeys[i];
break;
}
}
FlatLaf.setGlobalExtraDefaults( (accentColor != accentColorKeys[0])
? Collections.singletonMap( "@accentColor", "$" + accentColor )
: null );
Class<? extends LookAndFeel> lafClass = UIManager.getLookAndFeel().getClass();
try {
FlatLaf.setup( lafClass.newInstance() );
FlatLaf.updateUI();
} catch( InstantiationException | IllegalAccessException ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
}
}
private void updateAccentColorButtons() {
Class<? extends LookAndFeel> lafClass = UIManager.getLookAndFeel().getClass();
boolean isAccentColorSupported =
lafClass == FlatLightLaf.class ||
lafClass == FlatDarkLaf.class ||
lafClass == FlatIntelliJLaf.class ||
lafClass == FlatDarculaLaf.class;
accentColorLabel.setEnabled( isAccentColorSupported );
for( int i = 0; i < accentColorButtons.length; i++ )
accentColorButtons[i].setEnabled( isAccentColorSupported );
}
private void initComponents() { private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
JMenuBar menuBar1 = new JMenuBar(); JMenuBar menuBar1 = new JMenuBar();
@@ -369,7 +446,7 @@ class DemoFrame
JMenuItem showUIDefaultsInspectorMenuItem = new JMenuItem(); JMenuItem showUIDefaultsInspectorMenuItem = new JMenuItem();
JMenu helpMenu = new JMenu(); JMenu helpMenu = new JMenu();
JMenuItem aboutMenuItem = new JMenuItem(); JMenuItem aboutMenuItem = new JMenuItem();
JToolBar toolBar1 = new JToolBar(); toolBar = new JToolBar();
JButton backButton = new JButton(); JButton backButton = new JButton();
JButton forwardButton = new JButton(); JButton forwardButton = new JButton();
JButton cutButton = new JButton(); JButton cutButton = new JButton();
@@ -671,43 +748,43 @@ class DemoFrame
} }
setJMenuBar(menuBar1); setJMenuBar(menuBar1);
//======== toolBar1 ======== //======== toolBar ========
{ {
toolBar1.setMargin(new Insets(3, 3, 3, 3)); toolBar.setMargin(new Insets(3, 3, 3, 3));
//---- backButton ---- //---- backButton ----
backButton.setToolTipText("Back"); backButton.setToolTipText("Back");
toolBar1.add(backButton); toolBar.add(backButton);
//---- forwardButton ---- //---- forwardButton ----
forwardButton.setToolTipText("Forward"); forwardButton.setToolTipText("Forward");
toolBar1.add(forwardButton); toolBar.add(forwardButton);
toolBar1.addSeparator(); toolBar.addSeparator();
//---- cutButton ---- //---- cutButton ----
cutButton.setToolTipText("Cut"); cutButton.setToolTipText("Cut");
toolBar1.add(cutButton); toolBar.add(cutButton);
//---- copyButton ---- //---- copyButton ----
copyButton.setToolTipText("Copy"); copyButton.setToolTipText("Copy");
toolBar1.add(copyButton); toolBar.add(copyButton);
//---- pasteButton ---- //---- pasteButton ----
pasteButton.setToolTipText("Paste"); pasteButton.setToolTipText("Paste");
toolBar1.add(pasteButton); toolBar.add(pasteButton);
toolBar1.addSeparator(); toolBar.addSeparator();
//---- refreshButton ---- //---- refreshButton ----
refreshButton.setToolTipText("Refresh"); refreshButton.setToolTipText("Refresh");
toolBar1.add(refreshButton); toolBar.add(refreshButton);
toolBar1.addSeparator(); toolBar.addSeparator();
//---- showToggleButton ---- //---- showToggleButton ----
showToggleButton.setSelected(true); showToggleButton.setSelected(true);
showToggleButton.setToolTipText("Show Details"); showToggleButton.setToolTipText("Show Details");
toolBar1.add(showToggleButton); toolBar.add(showToggleButton);
} }
contentPane.add(toolBar1, BorderLayout.NORTH); contentPane.add(toolBar, BorderLayout.NORTH);
//======== contentPanel ======== //======== contentPanel ========
{ {
@@ -813,8 +890,37 @@ class DemoFrame
private JCheckBoxMenuItem underlineMenuSelectionMenuItem; private JCheckBoxMenuItem underlineMenuSelectionMenuItem;
private JCheckBoxMenuItem alwaysShowMnemonicsMenuItem; private JCheckBoxMenuItem alwaysShowMnemonicsMenuItem;
private JCheckBoxMenuItem animatedLafChangeMenuItem; private JCheckBoxMenuItem animatedLafChangeMenuItem;
private JToolBar toolBar;
private JTabbedPane tabbedPane; private JTabbedPane tabbedPane;
private ControlBar controlBar; private ControlBar controlBar;
IJThemesPanel themesPanel; IJThemesPanel themesPanel;
// JFormDesigner - End of variables declaration //GEN-END:variables // JFormDesigner - End of variables declaration //GEN-END:variables
//---- class AccentColorIcon ----------------------------------------------
private static class AccentColorIcon
extends FlatAbstractIcon
{
private final String colorKey;
AccentColorIcon( String colorKey ) {
super( 16, 16, null );
this.colorKey = colorKey;
}
@Override
protected void paintIcon( Component c, Graphics2D g ) {
Color color = UIManager.getColor( colorKey );
if( color == null )
color = Color.lightGray;
else if( !c.isEnabled() ) {
color = FlatLaf.isLafDark()
? ColorFunctions.shade( color, 0.5f )
: ColorFunctions.tint( color, 0.6f );
}
g.setColor( color );
g.fillRoundRect( 1, 1, width - 2, height - 2, 5, 5 );
}
}
} }

View File

@@ -1,4 +1,4 @@
JFDML JFormDesigner: "7.0.3.1.342" Java: "16" encoding: "UTF-8" JFDML JFormDesigner: "7.0.4.0.360" Java: "11.0.11" encoding: "UTF-8"
new FormModel { new FormModel {
contentType: "form/swing" contentType: "form/swing"
@@ -13,8 +13,11 @@ new FormModel {
"$locationPolicy": 2 "$locationPolicy": 2
"$sizePolicy": 2 "$sizePolicy": 2
add( new FormContainer( "javax.swing.JToolBar", new FormLayoutManager( class javax.swing.JToolBar ) ) { add( new FormContainer( "javax.swing.JToolBar", new FormLayoutManager( class javax.swing.JToolBar ) ) {
name: "toolBar1" name: "toolBar"
"margin": new java.awt.Insets( 3, 3, 3, 3 ) "margin": new java.awt.Insets( 3, 3, 3, 3 )
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
add( new FormComponent( "javax.swing.JButton" ) { add( new FormComponent( "javax.swing.JButton" ) {
name: "backButton" name: "backButton"
"toolTipText": "Back" "toolTipText": "Back"

View File

@@ -14,4 +14,16 @@
# limitations under the License. # limitations under the License.
# #
#---- Demo.accent ----
Demo.accent.blue = #4B6EAF
Demo.accent.purple = #BF5AF2
Demo.accent.red = #e81123
Demo.accent.orange = #FF9F0A
Demo.accent.yellow = #FFCC00
Demo.accent.green = #32D74B
#---- HintPanel ----
HintPanel.backgroundColor = darken(#ffffe1,80%) HintPanel.backgroundColor = darken(#ffffe1,80%)

View File

@@ -14,4 +14,16 @@
# limitations under the License. # limitations under the License.
# #
#---- Demo.accent ----
Demo.accent.blue = #2675BF
Demo.accent.purple = #BF5AF2
Demo.accent.red = #FF3B30
Demo.accent.orange = #FF9500
Demo.accent.yellow = #FFCC00
Demo.accent.green = #28CD41
#---- HintPanel ----
HintPanel.backgroundColor = #ffffe1 HintPanel.backgroundColor = #ffffe1