mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-11 22:47:13 -06:00
Theme Editor:
- support dark theme (menu "View > Dark Laf") - moved RSyntaxTextArea theme config from XML to properties files - bracket matching enabled - highlight selected tab background
This commit is contained in:
@@ -26,6 +26,7 @@ import java.util.Map;
|
||||
import javax.swing.ActionMap;
|
||||
import javax.swing.InputMap;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import org.fife.ui.rsyntaxtextarea.TextEditorPane;
|
||||
import org.fife.ui.rsyntaxtextarea.Token;
|
||||
@@ -47,14 +48,19 @@ class FlatSyntaxTextArea
|
||||
private final Map<String, Color> parsedColorsMap = new HashMap<>();
|
||||
|
||||
FlatSyntaxTextArea() {
|
||||
// this is necessary because RTextAreaBase.init() always sets foreground to black
|
||||
setForeground( UIManager.getColor( "TextArea.foreground" ) );
|
||||
|
||||
// remove Ctrl+Tab and Ctrl+Shift+Tab focus traversal keys to allow tabbed pane to process them
|
||||
setFocusTraversalKeys( KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, Collections.emptySet() );
|
||||
setFocusTraversalKeys( KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, Collections.emptySet() );
|
||||
|
||||
// add editor actions
|
||||
ActionMap actionMap = getActionMap();
|
||||
actionMap.put( FlatSyntaxTextAreaActions.duplicateLinesUpAction, new DuplicateLinesAction( FlatSyntaxTextAreaActions.duplicateLinesUpAction, true ) );
|
||||
actionMap.put( FlatSyntaxTextAreaActions.duplicateLinesDownAction, new DuplicateLinesAction( FlatSyntaxTextAreaActions.duplicateLinesDownAction, false ) );
|
||||
|
||||
// add editor key strokes
|
||||
InputMap inputMap = getInputMap();
|
||||
int defaultModifier = RTextArea.getDefaultModifier();
|
||||
int alt = InputEvent.ALT_DOWN_MASK;
|
||||
|
||||
@@ -22,9 +22,9 @@ import java.awt.Font;
|
||||
import java.awt.Window;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLayer;
|
||||
import javax.swing.JOptionPane;
|
||||
@@ -38,10 +38,13 @@ import org.fife.ui.autocomplete.CompletionProvider;
|
||||
import org.fife.ui.rsyntaxtextarea.AbstractTokenMakerFactory;
|
||||
import org.fife.ui.rsyntaxtextarea.ErrorStrip;
|
||||
import org.fife.ui.rsyntaxtextarea.FileLocation;
|
||||
import org.fife.ui.rsyntaxtextarea.Style;
|
||||
import org.fife.ui.rsyntaxtextarea.SyntaxScheme;
|
||||
import org.fife.ui.rsyntaxtextarea.TextEditorPane;
|
||||
import org.fife.ui.rsyntaxtextarea.Theme;
|
||||
import org.fife.ui.rsyntaxtextarea.TokenMakerFactory;
|
||||
import org.fife.ui.rsyntaxtextarea.TokenTypes;
|
||||
import org.fife.ui.rtextarea.Gutter;
|
||||
import org.fife.ui.rtextarea.RTextArea;
|
||||
import org.fife.ui.rtextarea.RTextScrollPane;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
@@ -60,6 +63,7 @@ class FlatThemeEditorPane
|
||||
private final CollapsibleSectionPanel collapsiblePanel;
|
||||
private final RTextScrollPane scrollPane;
|
||||
private final FlatSyntaxTextArea textArea;
|
||||
private final ErrorStrip errorStrip;
|
||||
private FlatFindReplaceBar findReplaceBar;
|
||||
|
||||
private File file;
|
||||
@@ -82,20 +86,6 @@ class FlatThemeEditorPane
|
||||
firePropertyChange( DIRTY_PROPERTY, e.getOldValue(), e.getNewValue() );
|
||||
} );
|
||||
|
||||
// theme
|
||||
try( InputStream in = getClass().getResourceAsStream( "light.xml" ) ) {
|
||||
Theme theme = Theme.load( in );
|
||||
theme.apply( textArea );
|
||||
} catch( IOException ex ) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
// use semitransparent token background because token background
|
||||
// is painted over mark occurrences background
|
||||
SyntaxScheme scheme = textArea.getSyntaxScheme();
|
||||
scheme.getStyle( FlatThemeTokenMaker.TOKEN_COLOR ).background = new Color( 0x0a000000, true );
|
||||
scheme.getStyle( FlatThemeTokenMaker.TOKEN_VARIABLE ).background = new Color( 0x1800cc00, true );
|
||||
|
||||
// autocomplete
|
||||
CompletionProvider provider = new FlatCompletionProvider();
|
||||
AutoCompletion ac = new AutoCompletion( provider );
|
||||
@@ -111,29 +101,49 @@ class FlatThemeEditorPane
|
||||
|
||||
// create scroll pane
|
||||
scrollPane = new RTextScrollPane( overlay );
|
||||
scrollPane.setBorder( null );
|
||||
scrollPane.setBorder( BorderFactory.createEmptyBorder() );
|
||||
scrollPane.setLineNumbersEnabled( true );
|
||||
|
||||
// scale fonts
|
||||
if( UIScale.getUserScaleFactor() != 1 )
|
||||
textArea.setFont( scaleFont( textArea.getFont() ) );
|
||||
|
||||
// use same font for line numbers as in editor
|
||||
scrollPane.getGutter().setLineNumberFont( textArea.getFont() );
|
||||
|
||||
// create error strip
|
||||
ErrorStrip errorStrip = new ErrorStrip( textArea );
|
||||
errorStrip = new ErrorStrip( textArea );
|
||||
|
||||
// create collapsible panel
|
||||
collapsiblePanel = new CollapsibleSectionPanel();
|
||||
collapsiblePanel.add( scrollPane );
|
||||
collapsiblePanel.add( errorStrip, BorderLayout.LINE_END );
|
||||
add( collapsiblePanel, BorderLayout.CENTER );
|
||||
|
||||
updateTheme();
|
||||
}
|
||||
|
||||
private static Font scaleFont( Font font ) {
|
||||
int newFontSize = UIScale.scale( font.getSize() );
|
||||
return font.deriveFont( (float) newFontSize );
|
||||
void updateTheme() {
|
||||
Font defaultFont = RTextArea.getDefaultFont();
|
||||
Font font = defaultFont.deriveFont( (float) UIManager.getFont( "defaultFont" ).getSize() );
|
||||
|
||||
textArea.setFont( font );
|
||||
textArea.setBackground( UIManager.getColor( "FlatThemeEditorPane.background" ) );
|
||||
textArea.setCaretColor( UIManager.getColor( "FlatThemeEditorPane.caretColor" ) );
|
||||
textArea.setSelectionColor( UIManager.getColor( "FlatThemeEditorPane.selectionBackground" ) );
|
||||
textArea.setCurrentLineHighlightColor( UIManager.getColor( "FlatThemeEditorPane.currentLineHighlight" ) );
|
||||
textArea.setMarkAllHighlightColor( UIManager.getColor( "FlatThemeEditorPane.markAllHighlightColor" ) );
|
||||
textArea.setMarkOccurrencesColor( UIManager.getColor( "FlatThemeEditorPane.markOccurrencesColor" ) );
|
||||
textArea.setMatchedBracketBGColor( UIManager.getColor( "FlatThemeEditorPane.matchedBracketBackground" ) );
|
||||
textArea.setMatchedBracketBorderColor( UIManager.getColor( "FlatThemeEditorPane.matchedBracketBorderColor" ) );
|
||||
textArea.setPaintMatchedBracketPair( true );
|
||||
textArea.setAnimateBracketMatching( false );
|
||||
|
||||
// syntax
|
||||
textArea.setSyntaxScheme( new FlatSyntaxScheme( font ) );
|
||||
|
||||
// gutter
|
||||
Gutter gutter = scrollPane.getGutter();
|
||||
gutter.setBackground( UIManager.getColor( "FlatThemeEditorPane.gutter.background" ) );
|
||||
gutter.setBorderColor( UIManager.getColor( "FlatThemeEditorPane.gutter.borderColor" ) );
|
||||
gutter.setLineNumberColor( UIManager.getColor( "FlatThemeEditorPane.gutter.lineNumberColor" ) );
|
||||
gutter.setLineNumberFont( font );
|
||||
|
||||
// error strip
|
||||
errorStrip.setCaretMarkerColor( UIManager.getColor( "FlatThemeEditorPane.errorstrip.caretMarkerColor" ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -233,4 +243,43 @@ class FlatThemeEditorPane
|
||||
|
||||
collapsiblePanel.showBottomComponent( findReplaceBar );
|
||||
}
|
||||
|
||||
//---- class FlatSyntaxScheme ---------------------------------------------
|
||||
|
||||
private static class FlatSyntaxScheme
|
||||
extends SyntaxScheme
|
||||
{
|
||||
FlatSyntaxScheme( Font baseFont ) {
|
||||
super( false );
|
||||
|
||||
Style[] styles = getStyles();
|
||||
for( int i = 0; i < styles.length; i++ )
|
||||
styles[i] = new Style( Color.red );
|
||||
|
||||
init( "property", FlatThemeTokenMaker.TOKEN_PROPERTY, baseFont );
|
||||
init( "variable", FlatThemeTokenMaker.TOKEN_VARIABLE, baseFont );
|
||||
init( "number", FlatThemeTokenMaker.TOKEN_NUMBER, baseFont );
|
||||
init( "color", FlatThemeTokenMaker.TOKEN_COLOR, baseFont );
|
||||
init( "string", FlatThemeTokenMaker.TOKEN_STRING, baseFont );
|
||||
init( "function", FlatThemeTokenMaker.TOKEN_FUNCTION, baseFont );
|
||||
init( "type", FlatThemeTokenMaker.TOKEN_TYPE, baseFont );
|
||||
init( "reservedWord", TokenTypes.RESERVED_WORD, baseFont );
|
||||
init( "literalBoolean", TokenTypes.LITERAL_BOOLEAN, baseFont );
|
||||
init( "operator", TokenTypes.OPERATOR, baseFont );
|
||||
init( "separator", TokenTypes.SEPARATOR, baseFont );
|
||||
init( "whitespace", TokenTypes.WHITESPACE, baseFont );
|
||||
init( "comment", TokenTypes.COMMENT_EOL, baseFont );
|
||||
}
|
||||
|
||||
private void init( String key, int token, Font baseFont ) {
|
||||
String prefix = "FlatThemeEditorPane.style.";
|
||||
Color fg = UIManager.getColor( prefix + key );
|
||||
Color bg = UIManager.getColor( prefix + key + ".background" );
|
||||
boolean italic = UIManager.getBoolean( prefix + key + ".italic" );
|
||||
Font font = Style.DEFAULT_FONT;
|
||||
if( italic )
|
||||
font = baseFont.deriveFont( Font.ITALIC );
|
||||
getStyles()[token] = new Style( fg, bg, font );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ import java.util.function.Supplier;
|
||||
import java.util.prefs.Preferences;
|
||||
import javax.swing.*;
|
||||
import net.miginfocom.swing.*;
|
||||
import com.formdev.flatlaf.FlatDarkLaf;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.FlatLightLaf;
|
||||
import com.formdev.flatlaf.extras.FlatInspector;
|
||||
import com.formdev.flatlaf.extras.FlatSVGIcon;
|
||||
@@ -59,6 +61,7 @@ public class FlatThemeFileEditor
|
||||
private static final String KEY_RECENT_DIRECTORY = "recentDirectory";
|
||||
private static final String KEY_RECENT_FILE = "recentFile";
|
||||
private static final String KEY_WINDOW_BOUNDS = "windowBounds";
|
||||
private static final String KEY_LAF = "laf";
|
||||
|
||||
private File dir;
|
||||
private Preferences state;
|
||||
@@ -70,7 +73,15 @@ public class FlatThemeFileEditor
|
||||
: null;
|
||||
|
||||
SwingUtilities.invokeLater( () -> {
|
||||
FlatLightLaf.setup();
|
||||
FlatLaf.registerCustomDefaultsSource( "com.formdev.flatlaf.themeeditor" );
|
||||
|
||||
try {
|
||||
String laf = Preferences.userRoot().node( PREFS_ROOT_PATH ).get( KEY_LAF, FlatLightLaf.class.getName() );
|
||||
UIManager.setLookAndFeel( laf );
|
||||
} catch( Exception ex ) {
|
||||
FlatLightLaf.setup();
|
||||
}
|
||||
|
||||
FlatInspector.install( "ctrl alt shift X" );
|
||||
FlatUIDefaultsInspector.install( "ctrl shift alt Y" );
|
||||
|
||||
@@ -83,6 +94,8 @@ public class FlatThemeFileEditor
|
||||
initComponents();
|
||||
|
||||
openDirectoryButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/themeeditor/icons/menu-open.svg" ) );
|
||||
if( UIManager.getLookAndFeel() instanceof FlatDarkLaf )
|
||||
darkLafMenuItem.setSelected( true );
|
||||
|
||||
restoreState();
|
||||
restoreWindowBounds();
|
||||
@@ -338,6 +351,29 @@ public class FlatThemeFileEditor
|
||||
themeEditorPane.showFindReplaceBar();
|
||||
}
|
||||
|
||||
private void lightLaf() {
|
||||
applyLookAndFeel( FlatLightLaf.class.getName() );
|
||||
}
|
||||
|
||||
private void darkLaf() {
|
||||
applyLookAndFeel( FlatDarkLaf.class.getName() );
|
||||
}
|
||||
|
||||
private void applyLookAndFeel( String lafClassName ) {
|
||||
if( UIManager.getLookAndFeel().getClass().getName().equals( lafClassName ) )
|
||||
return;
|
||||
|
||||
try {
|
||||
UIManager.setLookAndFeel( lafClassName );
|
||||
FlatLaf.updateUI();
|
||||
for( FlatThemeEditorPane themeEditorPane : getThemeEditorPanes() )
|
||||
themeEditorPane.updateTheme();
|
||||
state.put( KEY_LAF, lafClassName );
|
||||
} catch( Exception ex ) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void restoreState() {
|
||||
state = Preferences.userRoot().node( PREFS_ROOT_PATH );
|
||||
|
||||
@@ -438,6 +474,9 @@ public class FlatThemeFileEditor
|
||||
exitMenuItem = new JMenuItem();
|
||||
editMenu = new JMenu();
|
||||
findMenuItem = new JMenuItem();
|
||||
viewMenu = new JMenu();
|
||||
lightLafMenuItem = new JRadioButtonMenuItem();
|
||||
darkLafMenuItem = new JRadioButtonMenuItem();
|
||||
windowMenu = new JMenu();
|
||||
nextEditorMenuItem = new JMenuItem();
|
||||
previousEditorMenuItem = new JMenuItem();
|
||||
@@ -512,6 +551,28 @@ public class FlatThemeFileEditor
|
||||
}
|
||||
menuBar.add(editMenu);
|
||||
|
||||
//======== viewMenu ========
|
||||
{
|
||||
viewMenu.setText("View");
|
||||
viewMenu.setMnemonic('V');
|
||||
|
||||
//---- lightLafMenuItem ----
|
||||
lightLafMenuItem.setText("Light Laf");
|
||||
lightLafMenuItem.setMnemonic('L');
|
||||
lightLafMenuItem.setSelected(true);
|
||||
lightLafMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F11, 0));
|
||||
lightLafMenuItem.addActionListener(e -> lightLaf());
|
||||
viewMenu.add(lightLafMenuItem);
|
||||
|
||||
//---- darkLafMenuItem ----
|
||||
darkLafMenuItem.setText("Dark Laf");
|
||||
darkLafMenuItem.setMnemonic('D');
|
||||
darkLafMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F12, 0));
|
||||
darkLafMenuItem.addActionListener(e -> darkLaf());
|
||||
viewMenu.add(darkLafMenuItem);
|
||||
}
|
||||
menuBar.add(viewMenu);
|
||||
|
||||
//======== windowMenu ========
|
||||
{
|
||||
windowMenu.setText("Window");
|
||||
@@ -570,6 +631,11 @@ public class FlatThemeFileEditor
|
||||
tabbedPane.addChangeListener(e -> selectedTabChanged());
|
||||
}
|
||||
contentPane.add(tabbedPane, BorderLayout.CENTER);
|
||||
|
||||
//---- buttonGroup1 ----
|
||||
ButtonGroup buttonGroup1 = new ButtonGroup();
|
||||
buttonGroup1.add(lightLafMenuItem);
|
||||
buttonGroup1.add(darkLafMenuItem);
|
||||
// JFormDesigner - End of component initialization //GEN-END:initComponents
|
||||
}
|
||||
|
||||
@@ -581,6 +647,9 @@ public class FlatThemeFileEditor
|
||||
private JMenuItem exitMenuItem;
|
||||
private JMenu editMenu;
|
||||
private JMenuItem findMenuItem;
|
||||
private JMenu viewMenu;
|
||||
private JRadioButtonMenuItem lightLafMenuItem;
|
||||
private JRadioButtonMenuItem darkLafMenuItem;
|
||||
private JMenu windowMenu;
|
||||
private JMenuItem nextEditorMenuItem;
|
||||
private JMenuItem previousEditorMenuItem;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
JFDML JFormDesigner: "7.0.3.1.342" Java: "15" encoding: "UTF-8"
|
||||
JFDML JFormDesigner: "7.0.4.0.360" Java: "16" encoding: "UTF-8"
|
||||
|
||||
new FormModel {
|
||||
contentType: "form/swing"
|
||||
@@ -95,6 +95,28 @@ new FormModel {
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "find", false ) )
|
||||
} )
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
|
||||
name: "viewMenu"
|
||||
"text": "View"
|
||||
"mnemonic": 86
|
||||
add( new FormComponent( "javax.swing.JRadioButtonMenuItem" ) {
|
||||
name: "lightLafMenuItem"
|
||||
"text": "Light Laf"
|
||||
"$buttonGroup": new FormReference( "buttonGroup1" )
|
||||
"mnemonic": 76
|
||||
"selected": true
|
||||
"accelerator": static javax.swing.KeyStroke getKeyStroke( 122, 0, false )
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "lightLaf", false ) )
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JRadioButtonMenuItem" ) {
|
||||
name: "darkLafMenuItem"
|
||||
"text": "Dark Laf"
|
||||
"$buttonGroup": new FormReference( "buttonGroup1" )
|
||||
"mnemonic": 68
|
||||
"accelerator": static javax.swing.KeyStroke getKeyStroke( 123, 0, false )
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "darkLaf", false ) )
|
||||
} )
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
|
||||
name: "windowMenu"
|
||||
"text": "Window"
|
||||
@@ -119,5 +141,10 @@ new FormModel {
|
||||
"location": new java.awt.Point( 0, 0 )
|
||||
"size": new java.awt.Dimension( 535, 300 )
|
||||
} )
|
||||
add( new FormNonVisual( "javax.swing.ButtonGroup" ) {
|
||||
name: "buttonGroup1"
|
||||
}, new FormLayoutConstraints( null ) {
|
||||
"location": new java.awt.Point( 0, 310 )
|
||||
} )
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,8 +127,10 @@ public class FlatThemeTokenMaker
|
||||
newTokenType = TOKEN_VARIABLE;
|
||||
else if( currentTokenType != TOKEN_STRING && (RSyntaxUtilities.isDigit( ch ) || (currentTokenType == TOKEN_NUMBER && ch == '.')) )
|
||||
newTokenType = TOKEN_NUMBER;
|
||||
else if( ch == ',' || ch == '(' || ch == ')' || ch == '"' || ch == '%' )
|
||||
else if( ch == ',' || ch == '"' || ch == '%' )
|
||||
newTokenType = TokenTypes.OPERATOR;
|
||||
else if( ch == '(' || ch == ')' )
|
||||
newTokenType = TokenTypes.SEPARATOR; // necessary for bracket matching
|
||||
else
|
||||
newTokenType = TOKEN_STRING;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user