From bb2a21270b3ee7380d13e5f09b8922e88528e71a Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Mon, 4 Oct 2021 12:44:03 +0200 Subject: [PATCH] Theme Editor: added "Pick Color from Screen" action to "Edit" menu that allows picking a color from anywhere on screen and insert/change it at caret position --- .../flatlaf/themes/FlatOneDarkLaf.properties | 268 +++++++++++++++++ .../flatlaf/themeeditor/FlatColorPipette.java | 278 ++++++++++++++++++ .../themeeditor/FlatSyntaxTextArea.java | 2 + .../FlatSyntaxTextAreaActions.java | 74 +++++ .../themeeditor/FlatThemeFileEditor.java | 14 + .../themeeditor/FlatThemeFileEditor.jfd | 8 +- 6 files changed, 643 insertions(+), 1 deletion(-) create mode 100644 flatlaf-core/src/main/resources/com/formdev/flatlaf/themes/FlatOneDarkLaf.properties create mode 100644 flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatColorPipette.java diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/themes/FlatOneDarkLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/themes/FlatOneDarkLaf.properties new file mode 100644 index 00000000..df31f619 --- /dev/null +++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/themes/FlatOneDarkLaf.properties @@ -0,0 +1,268 @@ +# +# Copyright 2021 FormDev Software GmbH +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# base theme (light, dark, intellij or darcula); only used by theme editor +@baseTheme = dark + +#---- variables ---- + +# general background and foreground (text color) +@background = #21252b +@foreground = #abb2bf +@selectionBackground = #323844 +@selectionForeground = #d7dae0 +@selectionInactiveBackground = #2c313a +#@selectionInactiveForeground = @foreground +#@disabledText = #888 +@textComponentBackground = #282c34 +#@menuBackground = darken(@background,5%) +#@menuHoverBackground = lighten(@menuBackground,10%,derived) +#@menuCheckBackground = darken(@selectionBackground,10%,derived noAutoInverse) +#@menuAcceleratorForeground = darken(@foreground,15%) +#@menuAcceleratorSelectionForeground = @selectionForeground +#@cellFocusColor = #000 +#@icon = #adadad + +# accent colors (blueish) +@accentColor = #568AF2 +#@accentFocusColor = shade(spin(@accentColor,-8),20%) +#@accentLinkColor = lighten(saturate(spin(@accentColor,-5),50%),16%) +#@accentSelectionBackground = @accentColor +#@accentSliderColor = @accentUnderlineColor +#@accentUnderlineColor = lighten(saturate(spin(@accentColor,-8),13%),5%) +#@accentButtonDefaultBackground = darken(spin(@accentColor,-8),13%) +# +## for buttons within components (e.g. combobox or spinner) +#@buttonArrowColor = #9A9DA1 +#@buttonDisabledArrowColor = darken(@buttonArrowColor,25%) +#@buttonHoverArrowColor = lighten(@buttonArrowColor,10%,derived noAutoInverse) +#@buttonPressedArrowColor = lighten(@buttonArrowColor,20%,derived noAutoInverse) +# +## Drop (use lazy colors for IntelliJ platform themes, which usually do not specify these colors) +#@dropCellBackground = darken(List.selectionBackground,10%,lazy) +#@dropCellForeground = lazy(List.selectionForeground) +#@dropLineColor = lighten(List.selectionBackground,10%,lazy) +#@dropLineShortColor = lighten(List.selectionBackground,30%,lazy) + + +Button.borderColor = #464c55 +Button.disabledBorderColor = #2d3137 + +#---- CheckBox ---- + +CheckBox.icon.style = filled +#CheckBox.icon.checkmarkColor = @accentColor +#CheckBox.icon.background = @background + +CheckBox.icon[filled].selectedBorderColor = @accentColor +CheckBox.icon[filled].selectedBackground = @accentColor +CheckBox.icon[filled].checkmarkColor = #001133 +CheckBox.icon[filled].focusedBackground = #f00 + + +a=hsl(220,24%,20%) +#---- Component ---- + +Component.borderColor = #333841 + + "colors": { + "accentColor": "", + "backgroundColor": "", +# "borderColor": "#333841", + "infoForeground": "#7e8491" + }, + "ui": { + "*": { + + "infoForeground": "#5c6370", + + + "disabledBackground": "backgroundColor", + "inactiveBackground": "backgroundColor", + + "acceleratorForeground": "#E6E6E6", + "acceleratorSelectionForeground": "#E6E6E6", + + "errorForeground": "#cd3359", + + "focusColor": "backgroundColor", + "focusedBorderColor": "accentColor", + + "separatorColor": "#32363c" + }, + + "Button": { + "foreground": "#a0a7b4", + "startBackground": "#3d424b", + "endBackground": "#3d424b", + "shadowColor": "backgroundColor", + "focusedBorderColor": "#646a73", + + "default": { + "foreground": "#ffffff", + "startBackground": "accentColor", + "endBackground": "accentColor", + "startBorderColor": "accentColor", + "endBorderColor": "accentColor", + "focusedBorderColor": "#4269b9", + "focusColor": "#4269b9" + } + }, + + "ComboBox": { + "nonEditableBackground": "#333841", + "background": "#333841", + "selectionBackground": "#4d78cc", + "ArrowButton": { + "iconColor": "#abb2bf", + "disabledIconColor": "#2c313a", + "nonEditableBackground": "#333841" + } + }, + + "ComboPopup.border": "1,1,1,1,#2d3137", + + "CompletionPopup": { + "matchForeground": "accentColor" + }, + + "Component": { + "errorFocusColor": "#802d43", + "inactiveErrorFocusColor": "#522530", + "warningFocusColor": "#8c812b", + "inactiveWarningFocusColor": "#47441f" + }, + + "DefaultTabs": { + "underlineColor": "accentColor", + "inactiveUnderlineColor": "#4269b9", + "hoverBackground": "#323844" + }, + + "DragAndDrop": { + "areaForeground": "#abb2bf", + "areaBackground": "#323844", + "areaBorderColor": "#333841" + }, + + "EditorPane.inactiveBackground": "#282c34", + + "FileColor": { + "Yellow": "#3d3026", + "Green": "#293a24", + "Blue": "#24354f", + "Violet": "#2d1942", + "Orange": "#3d3026", + "Rose": "#3d1e2b" + }, + + "Label": { + "infoForeground": "infoForeground" + }, + + "Link": { + "activeForeground": "#6494ed", + "hoverForeground": "#6494ed", + "pressedForeground": "#6494ed", + "visitedForeground": "#6494ed" + }, + + "Popup": { + "paintBorder": false, + "Toolbar.borderColor": "#3d424b", + "Header.activeBackground": "#414855", + "Header.inactiveBackground": "#2c313a", + "Advertiser": { + "foreground": "#5c6370", + "borderColor": "#2d3137" + } + }, + + "ProgressBar": { + "trackColor": "#1D1D26", + "progressColor": "accentColor", + "indeterminateStartColor": "accentColor", + "indeterminateEndColor": "#313469", + "failedColor": "#bd3c5f", + "failedEndColor": "#472c33", + "passedColor": "#239E62", + "passedEndColor": "#2b4242" + }, + + + "TabbedPane": { + "underlineColor": "accentColor", + "contentAreaColor": "#323844", + "hoverColor": "#323844" + }, + + "Table": { + "selectionForeground": "#ffffff", + "dropLineColor": "#abb2bf", + "focusCellForeground": "#abb2bf", + "gridColor": "#5c6370", + "lightSelectionInactiveForeground": "#abb2bf", + "lightSelectionForeground": "#abb2bf", + "selectionBackground": "#3d424b", + "selectionInactiveForeground": "#abb2bf", + "lightSelectionBackground": "#414855", + "lightSelectionInactiveBackground": "#323844" + }, + + "TextArea": { + "selectionBackground": "#414855" + }, + + "TextField": { + "selectionBackground": "#414855" + }, + + "ToggleButton": { + "onForeground": "#ffffff", + "onBackground": "accentColor", + "offForeground": "#9f9fa6", + "offBackground": "#3d424b", + "borderColor": "#3d424b", + "buttonColor": "#5c6370" + }, + + "ToolTip": { + "background": "#3d424b" + }, + + + "Tree": { + "selectionBackground": "#4d78cc", + "modifiedItemForeground": "accentColor", + "rowHeight": 20 + }, + + }, + + "icons": { + "ColorPalette": { + "Checkbox.Background.Default.Dark": "#282c34", + "Checkbox.Border.Default.Dark": "#414855", + "Checkbox.Foreground.Selected.Dark": "#abb2bf", + "Checkbox.Focus.Wide.Dark": "#568AF2", + "Checkbox.Focus.Thin.Default.Dark": "#568AF2", + "Checkbox.Focus.Thin.Selected.Dark": "#568AF2", + "Checkbox.Background.Disabled.Dark": "#21252b", + "Checkbox.Border.Disabled.Dark": "#2c313a", + "Checkbox.Foreground.Disabled.Dark": "#5c6370" + } + } +} diff --git a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatColorPipette.java b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatColorPipette.java new file mode 100644 index 00000000..107ed632 --- /dev/null +++ b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatColorPipette.java @@ -0,0 +1,278 @@ +/* + * Copyright 2021 FormDev Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.formdev.flatlaf.themeeditor; + +import java.awt.AWTException; +import java.awt.BasicStroke; +import java.awt.BorderLayout; +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.Robot; +import java.awt.Window; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.image.BufferedImage; +import java.util.function.Consumer; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JWindow; +import javax.swing.SwingUtilities; +import com.formdev.flatlaf.icons.FlatAbstractIcon; +import com.formdev.flatlaf.ui.FlatEmptyBorder; +import com.formdev.flatlaf.ui.FlatLineBorder; +import com.formdev.flatlaf.util.HSLColor; +import com.formdev.flatlaf.util.UIScale; + +/** + * @author Karl Tauber + */ +class FlatColorPipette +{ + /** + * + * + * @throws AWTException if platform does not allow using robot (e.g. if headless) + * @throws UnsupportedOperationException if platform does not support translucent window + */ + static void pick( Window owner, boolean modal, + Consumer hoverCallback, Consumer pickCallback ) + throws AWTException, UnsupportedOperationException + { + InvisiblePickWindow pickWindow = new InvisiblePickWindow( owner, modal, hoverCallback, pickCallback ); + pickWindow.setVisible( true ); + } + + //---- class InvisiblePickWindow ------------------------------------------ + + /** + * An invisible window used to receive mouse and keyboard events for the whole screen. + */ + private static class InvisiblePickWindow + extends JDialog + { + private final Consumer hoverCallback; + private final Consumer pickCallback; + + private final Robot robot; + private final Magnifier magnifier; + + private int lastX; + private int lastY; + private Color lastHoverColor; + + InvisiblePickWindow( Window owner, boolean modal, + Consumer hoverCallback, Consumer pickCallback ) + throws AWTException, UnsupportedOperationException + { + super( owner, modal ? ModalityType.APPLICATION_MODAL : ModalityType.MODELESS ); + this.hoverCallback = hoverCallback; + this.pickCallback = pickCallback; + + setAlwaysOnTop( true ); + setUndecorated( true ); + setOpacity( 0.005f ); + setBounds( owner.getGraphicsConfiguration().getBounds() ); + + robot = new Robot( owner.getGraphicsConfiguration().getDevice() ); + magnifier = new Magnifier( this, robot ); + + MouseAdapter mouseListener = new MouseAdapter() { + @Override + public void mouseMoved( MouseEvent e ) { + lastX = e.getX(); + lastY = e.getY(); + + // get color at mouse location + // (temporary change opacity to zero to get correct color from robot) + float oldOpacity = getOpacity(); + setOpacity( 0 ); + Color color = robot.getPixelColor( lastX, lastY ); + setOpacity( oldOpacity ); + + hover( color ); + magnifier.update( lastX, lastY, color ); + } + + @Override + public void mouseClicked( MouseEvent e ) { + dispose(); + + if( SwingUtilities.isLeftMouseButton( e ) ) + pick( robot.getPixelColor( e.getX(), e.getY() ) ); + else + pick( null ); + } + }; + + KeyAdapter keyListener = new KeyAdapter() { + @Override + public void keyPressed( KeyEvent e ) { + switch( e.getKeyCode() ) { + case KeyEvent.VK_ESCAPE: dispose(); pick( null ); break; + + // move mouse one pixel using arrow keys + case KeyEvent.VK_LEFT: robot.mouseMove( lastX - 1, lastY ); break; + case KeyEvent.VK_RIGHT: robot.mouseMove( lastX + 1, lastY ); break; + case KeyEvent.VK_UP: robot.mouseMove( lastX, lastY - 1 ); break; + case KeyEvent.VK_DOWN: robot.mouseMove( lastX, lastY + 1 ); break; + } + } + }; + + addMouseListener( mouseListener ); + addMouseMotionListener( mouseListener ); + addKeyListener( keyListener ); + + magnifier.addMouseListener( mouseListener ); + magnifier.addMouseMotionListener( mouseListener ); + magnifier.addKeyListener( keyListener ); + + magnifier.pack(); + } + + private void hover( Color color ) { + if( hoverCallback == null || color == null || color.equals( lastHoverColor ) ) + return; + + lastHoverColor = color; + + EventQueue.invokeLater( () -> { + hoverCallback.accept( color ); + } ); + } + + private void pick( Color color ) { + EventQueue.invokeLater( () -> { + pickCallback.accept( color ); + } ); + } + } + + //---- class Magnifier ---------------------------------------------------- + + private static class Magnifier + extends JWindow + { + private final Window owner; + private final Robot robot; + + private final MagnifierView view; + private final JLabel infoLabel; + + private final int zoom; + private final int pixels = 16; + private Color colorAtMouse; + private BufferedImage image; + + public Magnifier( Window owner, Robot robot ) { + super( owner ); + this.owner = owner; + this.robot = robot; + + zoom = UIScale.scale( 16 ); + + getRootPane().setBorder( new FlatLineBorder( new Insets( 2, 2, 2, 2 ), Color.red, 2 ) ); + + view = new MagnifierView(); + view.setPreferredSize( new Dimension( pixels * zoom, pixels * zoom ) ); + + infoLabel = new JLabel( "#" ); + infoLabel.setIcon( new ColorIcon() ); + infoLabel.setBorder( new FlatEmptyBorder( 4, 4, 4, 4 ) ); + + add( view, BorderLayout.CENTER ); + add( infoLabel, BorderLayout.SOUTH ); + } + + void update( int x, int y, Color colorAtXY ) { + colorAtMouse = colorAtXY; + + // capture screen at mouse location + image = robot.createScreenCapture( new Rectangle( x - (pixels / 2), y - (pixels / 2), pixels, pixels ) ); + + // update color in info label + HSLColor hslColor = new HSLColor( colorAtMouse ); + int hue = Math.round( hslColor.getHue() ); + int saturation = Math.round( hslColor.getSaturation() ); + int luminance = Math.round( hslColor.getLuminance() ); + infoLabel.setText( String.format( "#%06x HSL %d %d %d", + colorAtMouse.getRGB() & 0xffffff, hue, saturation, luminance ) ); + + // place bottom-right to mouse location + int mx = x + UIScale.scale( 32 ); + int my = y + UIScale.scale( 32 ); + + // make sure that it is within screen + if( mx + getWidth() > owner.getX() + owner.getWidth() ) + mx = x - getWidth() - UIScale.scale( 32 ); + if( my + getHeight() > owner.getY() + owner.getHeight() ) + my = y - getHeight() - UIScale.scale( 32 ); + + setLocation( mx, my ); + setVisible( true ); + repaint(); + } + + //---- class MagnifierView ---- + + private class MagnifierView + extends JComponent + { + @Override + public void paint( Graphics g ) { + int width = getWidth(); + int height = getHeight(); + + if( image != null ) + g.drawImage( image, 0, 0, width, height, null ); + + int xy = (pixels / 2) * zoom; + g.setColor( Color.red ); + ((Graphics2D)g).setStroke( new BasicStroke( 2 ) ); + g.drawRect( xy - 1, xy - 1, zoom + 2, zoom + 2 ); + } + } + + //---- class ColorIcon ---- + + private class ColorIcon + extends FlatAbstractIcon + { + private static final int WIDTH = 64; + private static final int HEIGHT = 16; + + public ColorIcon() { + super( WIDTH, HEIGHT, null ); + } + + @Override + protected void paintIcon( Component c, Graphics2D g ) { + g.setColor( colorAtMouse ); + g.fillRect( 0, 0, WIDTH, HEIGHT ); + } + } + } +} diff --git a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatSyntaxTextArea.java b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatSyntaxTextArea.java index 6a15ad85..c06a8791 100644 --- a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatSyntaxTextArea.java +++ b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatSyntaxTextArea.java @@ -36,6 +36,7 @@ import org.fife.ui.rtextarea.RTextAreaUI; import org.fife.ui.rtextarea.RUndoManager; import com.formdev.flatlaf.UIDefaultsLoaderAccessor; import com.formdev.flatlaf.themeeditor.FlatSyntaxTextAreaActions.InsertColorAction; +import com.formdev.flatlaf.themeeditor.FlatSyntaxTextAreaActions.PickColorAction; import com.formdev.flatlaf.themeeditor.FlatSyntaxTextAreaActions.DuplicateLinesAction; import com.formdev.flatlaf.themeeditor.FlatSyntaxTextAreaActions.IncrementNumberAction; @@ -68,6 +69,7 @@ class FlatSyntaxTextArea 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 ) ); + actionMap.put( FlatSyntaxTextAreaActions.pickColorAction, new PickColorAction( FlatSyntaxTextAreaActions.pickColorAction ) ); // add editor key strokes InputMap inputMap = getInputMap(); diff --git a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatSyntaxTextAreaActions.java b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatSyntaxTextAreaActions.java index 30e5321b..2ce3829c 100644 --- a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatSyntaxTextAreaActions.java +++ b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatSyntaxTextAreaActions.java @@ -16,6 +16,7 @@ package com.formdev.flatlaf.themeeditor; +import java.awt.AWTException; import java.awt.Color; import java.awt.Component; import java.awt.Point; @@ -43,6 +44,7 @@ class FlatSyntaxTextAreaActions static final String incrementNumberAction = "FlatLaf.IncrementNumberAction"; static final String decrementNumberAction = "FlatLaf.DecrementNumberAction"; static final String insertColorAction = "FlatLaf.InsertColorAction"; + static final String pickColorAction = "FlatLaf.PickColorAction"; static int[] findColorAt( RTextArea textArea, int position ) { try { @@ -384,4 +386,76 @@ class FlatSyntaxTextAreaActions return getName(); } } + + //---- class PickColorAction ---------------------------------------------- + + static class PickColorAction + extends RecordableTextAction + { + PickColorAction( String name ) { + super( name ); + } + + @Override + public void actionPerformedImpl( ActionEvent e, RTextArea textArea ) { + try { + // find current color at caret + int caretPosition = textArea.getCaretPosition(); + int start; + int len = 0; + String oldStr; + int[] result = findColorAt( textArea, caretPosition ); + if( result != null ) { + start = result[0]; + len = result[1]; + + oldStr = textArea.getText( start, len ); + } else { + start = caretPosition; + oldStr = ""; + } + + AtomicInteger length = new AtomicInteger( len ); + AtomicBoolean changed = new AtomicBoolean(); + + // show pipette color picker + Window window = SwingUtilities.windowForComponent( textArea ); + FlatColorPipette.pick( window, true, + color -> { + // update editor immediately for live preview + String str = colorToString( color ); + ((FlatSyntaxTextArea)textArea).runWithoutUndo( () -> { + textArea.replaceRange( str, start, start + length.get() ); + } ); + length.set( str.length() ); + changed.set( true ); + }, + color -> { + // restore original string + ((FlatSyntaxTextArea)textArea).runWithoutUndo( () -> { + textArea.replaceRange( oldStr, start, start + length.get() ); + } ); + length.set( oldStr.length() ); + + // update editor + if( color != null ) { + String newStr = colorToString( color ); + try { + if( !newStr.equals( textArea.getText( start, length.get() ) ) ) + textArea.replaceRange( newStr, start, start + length.get() ); + } catch( BadLocationException ex ) { + ex.printStackTrace(); + } + } + } ); + } catch( BadLocationException | IndexOutOfBoundsException | NumberFormatException | UnsupportedOperationException | AWTException ex ) { + ex.printStackTrace(); + } + } + + @Override + public String getMacroID() { + return getName(); + } + } } diff --git a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeFileEditor.java b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeFileEditor.java index 69a23921..0e6cdf80 100644 --- a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeFileEditor.java +++ b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeFileEditor.java @@ -657,6 +657,12 @@ class FlatThemeFileEditor themeEditorPane.notifyTextAreaAction( FlatSyntaxTextAreaActions.insertColorAction ); } + private void pickColor() { + FlatThemeEditorPane themeEditorPane = (FlatThemeEditorPane) tabbedPane.getSelectedComponent(); + if( themeEditorPane != null ) + themeEditorPane.notifyTextAreaAction( FlatSyntaxTextAreaActions.pickColorAction ); + } + private void showHidePreview() { boolean show = previewMenuItem.isSelected(); for( FlatThemeEditorPane themeEditorPane : getThemeEditorPanes() ) @@ -888,6 +894,7 @@ class FlatThemeFileEditor editMenu = new JMenu(); findMenuItem = new JMenuItem(); insertColorMenuItem = new JMenuItem(); + pickColorMenuItem = new JMenuItem(); viewMenu = new JMenu(); previewMenuItem = new JCheckBoxMenuItem(); lightLafMenuItem = new JRadioButtonMenuItem(); @@ -986,6 +993,12 @@ class FlatThemeFileEditor insertColorMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_G, KeyEvent.CTRL_DOWN_MASK)); insertColorMenuItem.addActionListener(e -> insertColor()); editMenu.add(insertColorMenuItem); + + //---- pickColorMenuItem ---- + pickColorMenuItem.setText("Pick Color from Screen"); + pickColorMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_G, KeyEvent.CTRL_DOWN_MASK|KeyEvent.SHIFT_DOWN_MASK)); + pickColorMenuItem.addActionListener(e -> pickColor()); + editMenu.add(pickColorMenuItem); } menuBar.add(editMenu); @@ -1150,6 +1163,7 @@ class FlatThemeFileEditor private JMenu editMenu; private JMenuItem findMenuItem; private JMenuItem insertColorMenuItem; + private JMenuItem pickColorMenuItem; private JMenu viewMenu; private JCheckBoxMenuItem previewMenuItem; private JRadioButtonMenuItem lightLafMenuItem; diff --git a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeFileEditor.jfd b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeFileEditor.jfd index 1b080599..26f72b92 100644 --- a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeFileEditor.jfd +++ b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeFileEditor.jfd @@ -1,4 +1,4 @@ -JFDML JFormDesigner: "7.0.4.0.360" Java: "16" encoding: "UTF-8" +JFDML JFormDesigner: "7.0.5.0.382" Java: "16" encoding: "UTF-8" new FormModel { contentType: "form/swing" @@ -112,6 +112,12 @@ new FormModel { "accelerator": static javax.swing.KeyStroke getKeyStroke( 71, 130, false ) addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "insertColor", false ) ) } ) + add( new FormComponent( "javax.swing.JMenuItem" ) { + name: "pickColorMenuItem" + "text": "Pick Color from Screen" + "accelerator": &KeyStroke0 static javax.swing.KeyStroke getKeyStroke( 71, 195, false ) + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "pickColor", false ) ) + } ) } ) add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) { name: "viewMenu"