Theme Editor: added "Insert Color" action to "Edit" menu that opens a color chooser dialog and inserts/edits a color at caret position

This commit is contained in:
Karl Tauber
2021-08-23 13:43:14 +02:00
parent e1f30f24a8
commit 60322be22a
5 changed files with 176 additions and 28 deletions

View File

@@ -34,6 +34,7 @@ import org.fife.ui.rsyntaxtextarea.Token;
import org.fife.ui.rtextarea.RTextArea;
import org.fife.ui.rtextarea.RTextAreaUI;
import com.formdev.flatlaf.UIDefaultsLoaderAccessor;
import com.formdev.flatlaf.themeeditor.FlatSyntaxTextAreaActions.InsertColorAction;
import com.formdev.flatlaf.themeeditor.FlatSyntaxTextAreaActions.DuplicateLinesAction;
import com.formdev.flatlaf.themeeditor.FlatSyntaxTextAreaActions.IncrementNumberAction;
@@ -64,6 +65,7 @@ class FlatSyntaxTextArea
actionMap.put( FlatSyntaxTextAreaActions.duplicateLinesDownAction, new DuplicateLinesAction( FlatSyntaxTextAreaActions.duplicateLinesDownAction, false ) );
actionMap.put( FlatSyntaxTextAreaActions.incrementNumberAction, new IncrementNumberAction( FlatSyntaxTextAreaActions.incrementNumberAction, true ) );
actionMap.put( FlatSyntaxTextAreaActions.decrementNumberAction, new IncrementNumberAction( FlatSyntaxTextAreaActions.decrementNumberAction, false ) );
actionMap.put( FlatSyntaxTextAreaActions.insertColorAction, new InsertColorAction( FlatSyntaxTextAreaActions.insertColorAction ) );
// add editor key strokes
InputMap inputMap = getInputMap();

View File

@@ -16,10 +16,19 @@
package com.formdev.flatlaf.themeeditor;
import java.awt.Color;
import java.awt.Component;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.util.prefs.Preferences;
import javax.swing.JColorChooser;
import javax.swing.JDialog;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException;
import org.fife.ui.rtextarea.RTextArea;
import org.fife.ui.rtextarea.RecordableTextAction;
import com.formdev.flatlaf.UIDefaultsLoaderAccessor;
/**
* @author Karl Tauber
@@ -30,6 +39,70 @@ class FlatSyntaxTextAreaActions
static final String duplicateLinesDownAction = "FlatLaf.DuplicateLinesDownAction";
static final String incrementNumberAction = "FlatLaf.IncrementNumberAction";
static final String decrementNumberAction = "FlatLaf.DecrementNumberAction";
static final String insertColorAction = "FlatLaf.InsertColorAction";
static int[] findColorAt( RTextArea textArea, int position ) {
try {
int start = position;
int end = position;
// find first '#' or hex digit
for( int i = position - 1; i >= 0; i-- ) {
char ch = textArea.getText( i, 1 ).charAt( 0 );
if( ch != '#' && !isHexDigit( ch ) )
break;
start = i;
}
// find last hex digit
int length = textArea.getDocument().getLength();
for( int i = position; i < length; i++ ) {
if( !isHexDigit( textArea.getText( i, 1 ).charAt( 0 ) ) )
break;
end = i + 1;
}
// check for valid length (#RGB, #RGBA, #RRGGBB or #RRGGBBAA)
int len = end - start;
if( len != 4 && len != 5 && len != 7 && len != 9 )
return null;
// check whether starts with '#'
if( textArea.getText( start, 1 ).charAt( 0 ) != '#' )
return null;
return new int[] { start, end - start };
} catch( BadLocationException | IndexOutOfBoundsException | NumberFormatException ex ) {
ex.printStackTrace();
return null;
}
}
static boolean isHexDigit( char ch ) {
return Character.isDigit( ch ) || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F');
}
static String colorToString( Color color ) {
int rgb = color.getRGB();
int alpha = color.getAlpha();
String format;
if( (rgb & 0xf) == ((rgb >> 4) & 0xf) &&
((rgb >> 8) & 0xf) == ((rgb >> 12) & 0xf) &&
((rgb >> 16) & 0xf) == ((rgb >> 20) & 0xf) &&
((rgb >> 24) & 0xf) == ((rgb >> 28) & 0xf) )
{
// short format (#RGB or #RGBA)
format = (alpha != 255) ? "#%03x%01x" : "#%03x";
rgb = (rgb & 0xf) | ((rgb >> 4) & 0xf0) | ((rgb >> 8) & 0xf00);
alpha &= 0xf;
} else {
// long format (#RRGGBB or #RRGGBBAA)
format = (alpha != 255) ? "#%06x%02x" : "#%06x";
rgb &= 0xffffff;
}
return String.format( format, rgb, alpha );
}
//---- class DuplicateLinesAction -----------------------------------------
@@ -143,33 +216,12 @@ class FlatSyntaxTextAreaActions
private boolean incrementRGBColor( RTextArea textArea ) {
try {
int caretPosition = textArea.getCaretPosition();
int start = caretPosition;
int end = caretPosition;
// find first '#' or hex digit
for( int i = caretPosition - 1; i >= 0; i-- ) {
char ch = textArea.getText( i, 1 ).charAt( 0 );
if( ch != '#' && !isHexDigit( ch ) )
break;
start = i;
}
// find last hex digit
int length = textArea.getDocument().getLength();
for( int i = caretPosition; i < length; i++ ) {
if( !isHexDigit( textArea.getText( i, 1 ).charAt( 0 ) ) )
break;
end = i + 1;
}
// check for valid length (#RGB, #RGBA, #RRGGBB or #RRGGBBAA)
int len = end - start;
if( len != 4 && len != 5 && len != 7 && len != 9 )
int[] result = findColorAt( textArea, caretPosition );
if( result == null )
return false;
// check whether starts with '#'
if( textArea.getText( start, 1 ).charAt( 0 ) != '#' )
return false;
int start = result[0];
int len = result[1];
// find start of color part that should be changed (red, green, blue or alpha)
int start2;
@@ -212,8 +264,66 @@ class FlatSyntaxTextAreaActions
}
}
private boolean isHexDigit( char ch ) {
return Character.isDigit( ch ) || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F');
@Override
public String getMacroID() {
return getName();
}
}
//---- class InsertColorAction --------------------------------------------
static class InsertColorAction
extends RecordableTextAction
{
private static final String KEY_SELECTED_TAB = "colorchooser.selectedTab";
InsertColorAction( String name ) {
super( name );
}
@Override
public void actionPerformedImpl( ActionEvent e, RTextArea textArea ) {
try {
// find current color at caret
Color currentColor = Color.white;
int caretPosition = textArea.getCaretPosition();
int start;
int len;
int[] result = findColorAt( textArea, caretPosition );
if( result != null ) {
start = result[0];
len = result[1];
String str = textArea.getText( start, len );
int rgb = UIDefaultsLoaderAccessor.parseColorRGBA( str );
currentColor = new Color( rgb, true );
} else {
start = caretPosition;
len = 0;
}
// create color chooser
JColorChooser chooser = new JColorChooser( currentColor );
Component tabbedPane = chooser.getComponent( 0 );
Preferences state = Preferences.userRoot().node( FlatThemeFileEditor.PREFS_ROOT_PATH );
int selectedTab = state.getInt( KEY_SELECTED_TAB, -1 );
if( tabbedPane instanceof JTabbedPane && selectedTab >= 0 && selectedTab < ((JTabbedPane)tabbedPane).getTabCount() )
((JTabbedPane)tabbedPane).setSelectedIndex( selectedTab );
// show color chooser dialog
Window window = SwingUtilities.windowForComponent( textArea );
JDialog dialog = JColorChooser.createDialog( window, "Insert Color", true, chooser, e2 -> {
// update editor
textArea.replaceRange( colorToString( chooser.getColor() ), start, start + len );
// remember selected tab
if( tabbedPane instanceof JTabbedPane )
state.putInt( KEY_SELECTED_TAB, ((JTabbedPane)tabbedPane).getSelectedIndex() );
}, null );
dialog.setVisible( true );
} catch( BadLocationException | IndexOutOfBoundsException | NumberFormatException ex ) {
ex.printStackTrace();
}
}
@Override

View File

@@ -20,9 +20,11 @@ import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.InputMap;
import javax.swing.JComponent;
@@ -290,6 +292,12 @@ class FlatThemeEditorPane
revalidate();
}
void notifyTextAreaAction( String actionKey ) {
Action action = textArea.getActionMap().get( actionKey );
if( action != null && action.isEnabled() )
action.actionPerformed( new ActionEvent( textArea, ActionEvent.ACTION_PERFORMED, null ) );
}
//---- class FlatSyntaxScheme ---------------------------------------------
private static class FlatSyntaxScheme

View File

@@ -32,6 +32,7 @@ import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.function.Supplier;
import java.util.prefs.Preferences;
@@ -56,7 +57,7 @@ import com.formdev.flatlaf.util.UIScale;
public class FlatThemeFileEditor
extends JFrame
{
private static final String PREFS_ROOT_PATH = "/flatlaf-theme-editor";
static final String PREFS_ROOT_PATH = "/flatlaf-theme-editor";
private static final String KEY_DIRECTORIES = "directories";
private static final String KEY_RECENT_DIRECTORY = "recentDirectory";
private static final String KEY_RECENT_FILE = "recentFile";
@@ -78,6 +79,9 @@ public class FlatThemeFileEditor
? new File( args[0] )
: null;
Locale.setDefault( Locale.ENGLISH );
System.setProperty( "user.language", "en" );
SwingUtilities.invokeLater( () -> {
FlatLaf.registerCustomDefaultsSource( "com.formdev.flatlaf.themeeditor" );
@@ -375,6 +379,12 @@ public class FlatThemeFileEditor
themeEditorPane.showFindReplaceBar();
}
private void insertColor() {
FlatThemeEditorPane themeEditorPane = (FlatThemeEditorPane) tabbedPane.getSelectedComponent();
if( themeEditorPane != null )
themeEditorPane.notifyTextAreaAction( FlatSyntaxTextAreaActions.insertColorAction );
}
private void showHidePreview() {
boolean show = previewMenuItem.isSelected();
for( FlatThemeEditorPane themeEditorPane : getThemeEditorPanes() )
@@ -562,6 +572,7 @@ public class FlatThemeFileEditor
exitMenuItem = new JMenuItem();
editMenu = new JMenu();
findMenuItem = new JMenuItem();
insertColorMenuItem = new JMenuItem();
viewMenu = new JMenu();
previewMenuItem = new JCheckBoxMenuItem();
lightLafMenuItem = new JRadioButtonMenuItem();
@@ -643,6 +654,13 @@ public class FlatThemeFileEditor
findMenuItem.setMnemonic('F');
findMenuItem.addActionListener(e -> find());
editMenu.add(findMenuItem);
editMenu.addSeparator();
//---- insertColorMenuItem ----
insertColorMenuItem.setText("Insert Color");
insertColorMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_G, KeyEvent.CTRL_DOWN_MASK));
insertColorMenuItem.addActionListener(e -> insertColor());
editMenu.add(insertColorMenuItem);
}
menuBar.add(editMenu);
@@ -786,6 +804,7 @@ public class FlatThemeFileEditor
private JMenuItem exitMenuItem;
private JMenu editMenu;
private JMenuItem findMenuItem;
private JMenuItem insertColorMenuItem;
private JMenu viewMenu;
private JCheckBoxMenuItem previewMenuItem;
private JRadioButtonMenuItem lightLafMenuItem;

View File

@@ -94,6 +94,15 @@ new FormModel {
"mnemonic": 70
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "find", false ) )
} )
add( new FormComponent( "javax.swing.JPopupMenu$Separator" ) {
name: "separator5"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "insertColorMenuItem"
"text": "Insert Color"
"accelerator": static javax.swing.KeyStroke getKeyStroke( 71, 130, false )
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "insertColor", false ) )
} )
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "viewMenu"