From 078e0564d8a3b2c816c75a3d188a336cc6bf25e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sat, 28 Sep 2024 22:55:25 +0200 Subject: [PATCH] Added: #2305 Saving recent colors in the color selection dialog --- CHANGELOG.md | 2 + .../flash/configuration/Configuration.java | 4 + .../decompiler/flash/gui/ViewMessages.java | 8 + .../gui/colordialog/MyColorChooserDialog.java | 271 +++++++++ .../gui/colordialog/MyRecentSwatchPanel.java | 74 +++ .../gui/colordialog/MySwatchChooserPanel.java | 531 ++++++++++++++++++ .../flash/gui/colordialog/MySwatchPanel.java | 177 ++++++ .../gui/generictageditors/ColorEditor.java | 26 +- .../locales/AdvancedSettingsDialog.properties | 4 + .../gui/locales/ColorChooserDialog.properties | 16 + 10 files changed, 1110 insertions(+), 3 deletions(-) create mode 100644 src/com/jpexs/decompiler/flash/gui/colordialog/MyColorChooserDialog.java create mode 100644 src/com/jpexs/decompiler/flash/gui/colordialog/MyRecentSwatchPanel.java create mode 100644 src/com/jpexs/decompiler/flash/gui/colordialog/MySwatchChooserPanel.java create mode 100644 src/com/jpexs/decompiler/flash/gui/colordialog/MySwatchPanel.java create mode 100644 src/com/jpexs/decompiler/flash/gui/locales/ColorChooserDialog.properties diff --git a/CHANGELOG.md b/CHANGELOG.md index b99f736df..45c2e2dc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file. ### Added - [#2321] Commandline option to generate HTML docs for AS1/2 Actions - Chinese translation update +- [#2305] Saving recent colors in the color selection dialog ### Fixed - [#2319] AS3 Compound assignments problems in some cases @@ -3587,6 +3588,7 @@ Major version of SWF to XML export changed to 2. [alpha 8]: https://github.com/jindrapetrik/jpexs-decompiler/compare/alpha7...alpha8 [alpha 7]: https://github.com/jindrapetrik/jpexs-decompiler/releases/tag/alpha7 [#2321]: https://www.free-decompiler.com/flash/issues/2321 +[#2305]: https://www.free-decompiler.com/flash/issues/2305 [#2319]: https://www.free-decompiler.com/flash/issues/2319 [#2320]: https://www.free-decompiler.com/flash/issues/2320 [#2272]: https://www.free-decompiler.com/flash/issues/2272 diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java index a3ffdcb1d..cb9307942 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java @@ -1023,6 +1023,10 @@ public final class Configuration { @ConfigurationDefaultBoolean(false) @ConfigurationCategory("export") public static ConfigurationItem linkAllClasses = null; + + @ConfigurationDefaultString("") + @ConfigurationInternal + public static ConfigurationItem recentColors = null; private enum OSId { WINDOWS, OSX, UNIX diff --git a/src/com/jpexs/decompiler/flash/gui/ViewMessages.java b/src/com/jpexs/decompiler/flash/gui/ViewMessages.java index 49b83276e..7555c683c 100644 --- a/src/com/jpexs/decompiler/flash/gui/ViewMessages.java +++ b/src/com/jpexs/decompiler/flash/gui/ViewMessages.java @@ -16,8 +16,10 @@ */ package com.jpexs.decompiler.flash.gui; +import com.jpexs.decompiler.flash.gui.colordialog.MyColorChooserDialog; import com.jpexs.decompiler.flash.configuration.ConfigurationItem; import java.awt.BorderLayout; +import java.awt.Color; import java.awt.Component; import javax.swing.Icon; import javax.swing.JCheckBox; @@ -134,4 +136,10 @@ public class ViewMessages { }); return ret[0]; } + + public static Color showColorDialog(Component parentComponent, Color initialColor, boolean withTransparency) { + MyColorChooserDialog colorDialog = new MyColorChooserDialog(parentComponent, initialColor, withTransparency); + colorDialog.setVisible(true); + return colorDialog.getColor(); + } } diff --git a/src/com/jpexs/decompiler/flash/gui/colordialog/MyColorChooserDialog.java b/src/com/jpexs/decompiler/flash/gui/colordialog/MyColorChooserDialog.java new file mode 100644 index 000000000..2ef31afb4 --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/colordialog/MyColorChooserDialog.java @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2024 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.gui.colordialog; + +import com.jpexs.decompiler.flash.gui.AppStrings; +import com.jpexs.helpers.Helper; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.Serializable; +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.ActionMap; +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.InputMap; +import javax.swing.JButton; +import javax.swing.JColorChooser; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JRootPane; +import javax.swing.JSlider; +import javax.swing.JSpinner; +import javax.swing.KeyStroke; +import javax.swing.UIManager; +import javax.swing.colorchooser.AbstractColorChooserPanel; + +/** + * + * @author JPEXS + */ +public class MyColorChooserDialog extends JDialog { + + private JColorChooser chooserPane; + private MyRecentSwatchPanel recentSwatchPanel; + + private Color color = null; + + public MyColorChooserDialog(Component parentComponent, Color initialColor, boolean colorTransparencySelectionEnabled) { + setTitle(AppStrings.translate("com.jpexs.decompiler.flash.gui.locales.ColorChooserDialog", "dialog.title")); + JColorChooser chooser = new JColorChooser(initialColor); + List choosers = new ArrayList<>(Arrays.asList(chooser.getChooserPanels())); + choosers.set(0, new MySwatchChooserPanel()); + + if (!colorTransparencySelectionEnabled) { + if (Helper.getJavaVersion() >= 9) { + for (AbstractColorChooserPanel ccPanel : choosers) { + Method m; + try { + m = AbstractColorChooserPanel.class.getDeclaredMethod("setColorTransparencySelectionEnabled", boolean.class); + m.invoke(ccPanel, colorTransparencySelectionEnabled); + } catch (NoSuchMethodException | SecurityException | IllegalAccessException | InvocationTargetException ex) { + //ignore + } + } + } else { + for (int i = 1; i < choosers.size(); i++) { + AbstractColorChooserPanel cp = choosers.get(i); + + Field f; + try { + f = cp.getClass().getDeclaredField("panel"); + + f.setAccessible(true); + + Object colorPanel = f.get(cp); + Field f2 = colorPanel.getClass().getDeclaredField("spinners"); + f2.setAccessible(true); + Object spinners = f2.get(colorPanel); + + Object transpSlispinner = Array.get(spinners, 3); + if (i == choosers.size() - 1) { + transpSlispinner = Array.get(spinners, 4); + } + Field f3 = transpSlispinner.getClass().getDeclaredField("slider"); + f3.setAccessible(true); + JSlider slider = (JSlider) f3.get(transpSlispinner); + slider.setEnabled(false); + Field f4 = transpSlispinner.getClass().getDeclaredField("spinner"); + f4.setAccessible(true); + JSpinner spinner = (JSpinner) f4.get(transpSlispinner); + spinner.setEnabled(false); + } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex) { + //ignore + } + } + } + } + + chooser.setChooserPanels(choosers.toArray(new AbstractColorChooserPanel[0])); + + this.chooserPane = chooser; + Locale locale = getLocale(); + String okString = UIManager.getString("ColorChooser.okText", locale); + String cancelString = UIManager.getString("ColorChooser.cancelText", locale); + String resetString = UIManager.getString("ColorChooser.resetText", locale); + + Container contentPane = getContentPane(); + contentPane.setLayout(new BorderLayout()); + contentPane.add(chooserPane, BorderLayout.CENTER); + + recentSwatchPanel = new MyRecentSwatchPanel(); + RecentSwatchListener recentSwatchListener = new RecentSwatchListener(); + RecentSwatchKeyListener recentSwatchKeyListener = new RecentSwatchKeyListener(); + recentSwatchPanel.addMouseListener(recentSwatchListener); + recentSwatchPanel.addKeyListener(recentSwatchKeyListener); + + JLabel recentLabel = new JLabel(UIManager.getString("ColorChooser.swatchesRecentText", getLocale())); + + JButton recentAddButton = new JButton(AppStrings.translate("com.jpexs.decompiler.flash.gui.locales.ColorChooserDialog", "recent.add")); + recentAddButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + recentSwatchPanel.setMostRecentColor(chooserPane.getColor()); + } + }); + + recentSwatchPanel.setMaximumSize(recentSwatchPanel.getPreferredSize()); + + recentLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + recentSwatchPanel.setAlignmentX(Component.CENTER_ALIGNMENT); + recentAddButton.setAlignmentX(Component.CENTER_ALIGNMENT); + + JPanel recentPanel = new JPanel(); + recentPanel.setLayout(new BoxLayout(recentPanel, BoxLayout.Y_AXIS)); + recentPanel.add(Box.createVerticalStrut(20)); + recentPanel.add(recentLabel); + recentPanel.add(recentSwatchPanel); + recentPanel.add(Box.createVerticalStrut(5)); + recentPanel.add(recentAddButton); + recentPanel.add(Box.createVerticalGlue()); + + recentPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + + contentPane.add(recentPanel, BorderLayout.EAST); + + /* + * Create Lower button panel + */ + JPanel buttonPane = new JPanel(); + buttonPane.setLayout(new FlowLayout(FlowLayout.CENTER)); + JButton okButton = new JButton(okString); + getRootPane().setDefaultButton(okButton); + okButton.getAccessibleContext().setAccessibleDescription(okString); + okButton.setActionCommand("OK"); + okButton.addActionListener(new ActionListener() { + @SuppressWarnings("deprecation") + public void actionPerformed(ActionEvent e) { + color = chooserPane.getColor(); + recentSwatchPanel.setMostRecentColor(color); + setVisible(false); + } + }); + buttonPane.add(okButton); + + JButton cancelButton = new JButton(cancelString); + cancelButton.getAccessibleContext().setAccessibleDescription(cancelString); + + Action cancelKeyAction = new AbstractAction() { + public void actionPerformed(ActionEvent e) { + setVisible(false); + } + }; + KeyStroke cancelKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); + InputMap inputMap = cancelButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); + ActionMap actionMap = cancelButton.getActionMap(); + if (inputMap != null && actionMap != null) { + inputMap.put(cancelKeyStroke, "cancel"); + actionMap.put("cancel", cancelKeyAction); + } + + cancelButton.setActionCommand("cancel"); + cancelButton.addActionListener(new ActionListener() { + @SuppressWarnings("deprecation") + public void actionPerformed(ActionEvent e) { + setVisible(false); + } + }); + buttonPane.add(cancelButton); + + JButton resetButton = new JButton(resetString); + resetButton.getAccessibleContext().setAccessibleDescription(resetString); + resetButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + chooserPane.setColor(initialColor); + } + }); + Object mnemonic = UIManager.get("ColorChooser.resetMnemonic", locale); + if (mnemonic instanceof Integer) { + resetButton.setMnemonic((int) mnemonic); + } + buttonPane.add(resetButton); + contentPane.add(buttonPane, BorderLayout.SOUTH); + + if (JDialog.isDefaultLookAndFeelDecorated()) { + boolean supportsWindowDecorations + = UIManager.getLookAndFeel().getSupportsWindowDecorations(); + if (supportsWindowDecorations) { + getRootPane().setWindowDecorationStyle(JRootPane.COLOR_CHOOSER_DIALOG); + } + } + applyComponentOrientation(((parentComponent == null) ? getRootPane() : parentComponent).getComponentOrientation()); + + pack(); + setLocationRelativeTo(parentComponent); + + setDefaultCloseOperation(HIDE_ON_CLOSE); + setModal(true); + } + + public Color getColor() { + return color; + } + + private class RecentSwatchKeyListener extends KeyAdapter { + + public void keyPressed(KeyEvent e) { + if (KeyEvent.VK_SPACE == e.getKeyCode()) { + Color color = recentSwatchPanel.getSelectedColor(); + chooserPane.setColor(color); + //setSelectedColor(color); + } + } + } + + class RecentSwatchListener extends MouseAdapter implements Serializable { + + public void mousePressed(MouseEvent e) { + if (isEnabled()) { + Color color = recentSwatchPanel.getColorForLocation(e.getX(), e.getY()); + recentSwatchPanel.setSelectedColorFromLocation(e.getX(), e.getY()); + //setSelectedColor(color); + chooserPane.setColor(color); + recentSwatchPanel.requestFocusInWindow(); + } + } + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/colordialog/MyRecentSwatchPanel.java b/src/com/jpexs/decompiler/flash/gui/colordialog/MyRecentSwatchPanel.java new file mode 100644 index 000000000..3f8ca4e41 --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/colordialog/MyRecentSwatchPanel.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2024 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.gui.colordialog; + +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.types.RGBA; +import com.jpexs.helpers.Helper; +import java.awt.Color; +import java.awt.Dimension; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.swing.UIManager; + +/** + * + * @author JPEXS + */ +class MyRecentSwatchPanel extends MySwatchPanel { + protected void initValues() { + swatchSize = UIManager.getDimension("ColorChooser.swatchesRecentSwatchSize", getLocale()); + numSwatches = new Dimension( 5, 7 ); + gap = new Dimension(1, 1); + } + protected void initColors() { + Color defaultRecentColor = UIManager.getColor("ColorChooser.swatchesDefaultRecentColor", getLocale()); + int numColors = numSwatches.width * numSwatches.height; + colors = new Color[numColors]; + String recentColorsStr = Configuration.recentColors.get(); + for (int i = 0; i < numColors ; i++) { + colors[i] = defaultRecentColor; + } + Pattern hexColorPattern = Pattern.compile("^#(?[a-fA-F0-9]{2})(?[a-fA-F0-9]{2})(?[a-fA-F0-9]{2})(?[a-fA-F0-9]{2})$"); + if (!recentColorsStr.isEmpty()) { + String[] colorsHex = recentColorsStr.split(",", -1); + for (int i = 0; i < colorsHex.length; i++) { + Matcher m = hexColorPattern.matcher(colorsHex[i]); + if (m.matches()) { + colors[i] = new Color(Integer.parseInt(m.group("r"), 16),Integer.parseInt(m.group("g"), 16),Integer.parseInt(m.group("b"), 16), Integer.parseInt(m.group("a"), 16)); + } + } + } + } + public void setMostRecentColor(Color c) { + if (colors[0].equals(c)) { + return; + } + System.arraycopy( colors, 0, colors, 1, colors.length-1); + colors[0] = c; + + List colorsAsStr = new ArrayList<>(); + for (int i = 0; i < colors.length; i++) { + colorsAsStr.add(new RGBA(colors[i]).toHexARGB()); + } + Configuration.recentColors.set(String.join(",", colorsAsStr)); + + repaint(); + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/colordialog/MySwatchChooserPanel.java b/src/com/jpexs/decompiler/flash/gui/colordialog/MySwatchChooserPanel.java new file mode 100644 index 000000000..d993a776d --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/colordialog/MySwatchChooserPanel.java @@ -0,0 +1,531 @@ +/* + * Copyright (C) 2024 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.gui.colordialog; +import javax.swing.*; +import javax.swing.border.*; +import java.awt.*; +import java.awt.event.*; +import java.io.Serializable; +import javax.accessibility.*; +import javax.swing.colorchooser.AbstractColorChooserPanel; +import javax.swing.colorchooser.ColorSelectionModel; +/** + * The standard color swatch chooser. + * Modified Java version + */ +public class MySwatchChooserPanel extends AbstractColorChooserPanel { + MySwatchPanel swatchPanel; + //RecentSwatchPanel recentSwatchPanel; + MouseListener mainSwatchListener; + MouseListener recentSwatchListener; + private KeyListener mainSwatchKeyListener; + private KeyListener recentSwatchKeyListener; + public MySwatchChooserPanel() { + super(); + setInheritsPopupMenu(true); + } + + void setSelectedColor(Color color) { + ColorSelectionModel model = getColorSelectionModel(); + if (model != null) { + model.setSelectedColor(color); + } + } + + int getInt(Object key, int defaultValue) { + Object value = UIManager.get(key, getLocale()); + if (value instanceof Integer) { + return ((Integer)value).intValue(); + } + if (value instanceof String) { + try { + return Integer.parseInt((String)value); + } catch (NumberFormatException nfe) {} + } + return defaultValue; + } + + public String getDisplayName() { + return UIManager.getString("ColorChooser.swatchesNameText", getLocale()); + } + /** + * Provides a hint to the look and feel as to the + * KeyEvent.VK constant that can be used as a mnemonic to + * access the panel. A return value <= 0 indicates there is no mnemonic. + *

+ * The return value here is a hint, it is ultimately up to the look + * and feel to honor the return value in some meaningful way. + *

+ * This implementation looks up the value from the default + * ColorChooser.swatchesMnemonic, or if it + * isn't available (or not an Integer) returns -1. + * The lookup for the default is done through the UIManager: + * UIManager.get("ColorChooser.swatchesMnemonic");. + * + * @return KeyEvent.VK constant identifying the mnemonic; <= 0 for no + * mnemonic + * @see #getDisplayedMnemonicIndex + * @since 1.4 + */ + public int getMnemonic() { + return getInt("ColorChooser.swatchesMnemonic", -1); + } + /** + * Provides a hint to the look and feel as to the index of the character in + * getDisplayName that should be visually identified as the + * mnemonic. The look and feel should only use this if + * getMnemonic returns a value > 0. + *

+ * The return value here is a hint, it is ultimately up to the look + * and feel to honor the return value in some meaningful way. For example, + * a look and feel may wish to render each + * AbstractColorChooserPanel in a JTabbedPane, + * and further use this return value to underline a character in + * the getDisplayName. + *

+ * This implementation looks up the value from the default + * ColorChooser.rgbDisplayedMnemonicIndex, or if it + * isn't available (or not an Integer) returns -1. + * The lookup for the default is done through the UIManager: + * UIManager.get("ColorChooser.swatchesDisplayedMnemonicIndex");. + * + * @return Character index to render mnemonic for; -1 to provide no + * visual identifier for this panel. + * @see #getMnemonic + * @since 1.4 + */ + public int getDisplayedMnemonicIndex() { + return getInt("ColorChooser.swatchesDisplayedMnemonicIndex", -1); + } + public Icon getSmallDisplayIcon() { + return null; + } + public Icon getLargeDisplayIcon() { + return null; + } + /** + * The background color, foreground color, and font are already set to the + * defaults from the defaults table before this method is called. + */ + public void installChooserPanel(JColorChooser enclosingChooser) { + super.installChooserPanel(enclosingChooser); + } + protected void buildChooser() { + String recentStr = UIManager.getString("ColorChooser.swatchesRecentText", getLocale()); + GridBagLayout gb = new GridBagLayout(); + GridBagConstraints gbc = new GridBagConstraints(); + JPanel superHolder = new JPanel(gb); + swatchPanel = new MainSwatchPanel(); + swatchPanel.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, + getDisplayName()); + swatchPanel.setInheritsPopupMenu(true); + //recentSwatchPanel = new RecentSwatchPanel(); + /*recentSwatchPanel.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, + recentStr);*/ + mainSwatchKeyListener = new MainSwatchKeyListener(); + mainSwatchListener = new MainSwatchListener(); + swatchPanel.addMouseListener(mainSwatchListener); + swatchPanel.addKeyListener(mainSwatchKeyListener); + recentSwatchListener = new RecentSwatchListener(); + recentSwatchKeyListener = new RecentSwatchKeyListener(); + //recentSwatchPanel.addMouseListener(recentSwatchListener); + //recentSwatchPanel.addKeyListener(recentSwatchKeyListener); + JPanel mainHolder = new JPanel(new BorderLayout()); + Border border = new CompoundBorder( new LineBorder(Color.black), + new LineBorder(Color.white) ); + mainHolder.setBorder(border); + mainHolder.add(swatchPanel, BorderLayout.CENTER); + gbc.anchor = GridBagConstraints.LAST_LINE_START; + gbc.gridwidth = 1; + gbc.gridheight = 2; + Insets oldInsets = gbc.insets; + gbc.insets = new Insets(0, 0, 0, 10); + superHolder.add(mainHolder, gbc); + gbc.insets = oldInsets; + //recentSwatchPanel.setInheritsPopupMenu(true); + JPanel recentHolder = new JPanel( new BorderLayout() ); + recentHolder.setBorder(border); + recentHolder.setInheritsPopupMenu(true); + //recentHolder.add(recentSwatchPanel, BorderLayout.CENTER); + JLabel l = new JLabel(recentStr); + //l.setLabelFor(recentSwatchPanel); + gbc.gridwidth = GridBagConstraints.REMAINDER; + gbc.gridheight = 1; + gbc.weighty = 1.0; + //superHolder.add(l, gbc); + gbc.weighty = 0; + gbc.gridheight = GridBagConstraints.REMAINDER; + gbc.insets = new Insets(0, 0, 0, 2); + //superHolder.add(recentHolder, gbc); + superHolder.setInheritsPopupMenu(true); + add(superHolder); + } + public void uninstallChooserPanel(JColorChooser enclosingChooser) { + super.uninstallChooserPanel(enclosingChooser); + swatchPanel.removeMouseListener(mainSwatchListener); + swatchPanel.removeKeyListener(mainSwatchKeyListener); + //recentSwatchPanel.removeMouseListener(recentSwatchListener); + //recentSwatchPanel.removeKeyListener(recentSwatchKeyListener); + swatchPanel = null; + //recentSwatchPanel = null; + mainSwatchListener = null; + mainSwatchKeyListener = null; + recentSwatchListener = null; + recentSwatchKeyListener = null; + removeAll(); // strip out all the sub-components + } + public void updateChooser() { + } + private class RecentSwatchKeyListener extends KeyAdapter { + public void keyPressed(KeyEvent e) { + if (KeyEvent.VK_SPACE == e.getKeyCode()) { + /*Color color = recentSwatchPanel.getSelectedColor(); + setSelectedColor(color);*/ + } + } + } + private class MainSwatchKeyListener extends KeyAdapter { + public void keyPressed(KeyEvent e) { + if (KeyEvent.VK_SPACE == e.getKeyCode()) { + Color color = swatchPanel.getSelectedColor(); + setSelectedColor(color); + //recentSwatchPanel.setMostRecentColor(color); + } + } + } + class RecentSwatchListener extends MouseAdapter implements Serializable { + public void mousePressed(MouseEvent e) { + if (isEnabled()) { + /*Color color = recentSwatchPanel.getColorForLocation(e.getX(), e.getY()); + recentSwatchPanel.setSelectedColorFromLocation(e.getX(), e.getY()); + setSelectedColor(color); + recentSwatchPanel.requestFocusInWindow();*/ + } + } + } + class MainSwatchListener extends MouseAdapter implements Serializable { + public void mousePressed(MouseEvent e) { + if (isEnabled()) { + Color color = swatchPanel.getColorForLocation(e.getX(), e.getY()); + setSelectedColor(color); + swatchPanel.setSelectedColorFromLocation(e.getX(), e.getY()); + //recentSwatchPanel.setMostRecentColor(color); + swatchPanel.requestFocusInWindow(); + } + } + } +} + + +class MainSwatchPanel extends MySwatchPanel { + protected void initValues() { + swatchSize = UIManager.getDimension("ColorChooser.swatchesSwatchSize", getLocale()); + numSwatches = new Dimension( 31, 9 ); + gap = new Dimension(1, 1); + } + protected void initColors() { + int[] rawValues = initRawValues(); + int numColors = rawValues.length / 3; + colors = new Color[numColors]; + for (int i = 0; i < numColors ; i++) { + colors[i] = new Color( rawValues[(i*3)], rawValues[(i*3)+1], rawValues[(i*3)+2] ); + } + } + private int[] initRawValues() { + int[] rawValues = { +255, 255, 255, // first row. +204, 255, 255, +204, 204, 255, +204, 204, 255, +204, 204, 255, +204, 204, 255, +204, 204, 255, +204, 204, 255, +204, 204, 255, +204, 204, 255, +204, 204, 255, +255, 204, 255, +255, 204, 204, +255, 204, 204, +255, 204, 204, +255, 204, 204, +255, 204, 204, +255, 204, 204, +255, 204, 204, +255, 204, 204, +255, 204, 204, +255, 255, 204, +204, 255, 204, +204, 255, 204, +204, 255, 204, +204, 255, 204, +204, 255, 204, +204, 255, 204, +204, 255, 204, +204, 255, 204, +204, 255, 204, +204, 204, 204, // second row. +153, 255, 255, +153, 204, 255, +153, 153, 255, +153, 153, 255, +153, 153, 255, +153, 153, 255, +153, 153, 255, +153, 153, 255, +153, 153, 255, +204, 153, 255, +255, 153, 255, +255, 153, 204, +255, 153, 153, +255, 153, 153, +255, 153, 153, +255, 153, 153, +255, 153, 153, +255, 153, 153, +255, 153, 153, +255, 204, 153, +255, 255, 153, +204, 255, 153, +153, 255, 153, +153, 255, 153, +153, 255, 153, +153, 255, 153, +153, 255, 153, +153, 255, 153, +153, 255, 153, +153, 255, 204, +204, 204, 204, // third row +102, 255, 255, +102, 204, 255, +102, 153, 255, +102, 102, 255, +102, 102, 255, +102, 102, 255, +102, 102, 255, +102, 102, 255, +153, 102, 255, +204, 102, 255, +255, 102, 255, +255, 102, 204, +255, 102, 153, +255, 102, 102, +255, 102, 102, +255, 102, 102, +255, 102, 102, +255, 102, 102, +255, 153, 102, +255, 204, 102, +255, 255, 102, +204, 255, 102, +153, 255, 102, +102, 255, 102, +102, 255, 102, +102, 255, 102, +102, 255, 102, +102, 255, 102, +102, 255, 153, +102, 255, 204, +153, 153, 153, // fourth row +51, 255, 255, +51, 204, 255, +51, 153, 255, +51, 102, 255, +51, 51, 255, +51, 51, 255, +51, 51, 255, +102, 51, 255, +153, 51, 255, +204, 51, 255, +255, 51, 255, +255, 51, 204, +255, 51, 153, +255, 51, 102, +255, 51, 51, +255, 51, 51, +255, 51, 51, +255, 102, 51, +255, 153, 51, +255, 204, 51, +255, 255, 51, +204, 255, 51, +153, 255, 51, +102, 255, 51, +51, 255, 51, +51, 255, 51, +51, 255, 51, +51, 255, 102, +51, 255, 153, +51, 255, 204, +153, 153, 153, // Fifth row +0, 255, 255, +0, 204, 255, +0, 153, 255, +0, 102, 255, +0, 51, 255, +0, 0, 255, +51, 0, 255, +102, 0, 255, +153, 0, 255, +204, 0, 255, +255, 0, 255, +255, 0, 204, +255, 0, 153, +255, 0, 102, +255, 0, 51, +255, 0 , 0, +255, 51, 0, +255, 102, 0, +255, 153, 0, +255, 204, 0, +255, 255, 0, +204, 255, 0, +153, 255, 0, +102, 255, 0, +51, 255, 0, +0, 255, 0, +0, 255, 51, +0, 255, 102, +0, 255, 153, +0, 255, 204, +102, 102, 102, // sixth row +0, 204, 204, +0, 204, 204, +0, 153, 204, +0, 102, 204, +0, 51, 204, +0, 0, 204, +51, 0, 204, +102, 0, 204, +153, 0, 204, +204, 0, 204, +204, 0, 204, +204, 0, 204, +204, 0, 153, +204, 0, 102, +204, 0, 51, +204, 0, 0, +204, 51, 0, +204, 102, 0, +204, 153, 0, +204, 204, 0, +204, 204, 0, +204, 204, 0, +153, 204, 0, +102, 204, 0, +51, 204, 0, +0, 204, 0, +0, 204, 51, +0, 204, 102, +0, 204, 153, +0, 204, 204, +102, 102, 102, // seventh row +0, 153, 153, +0, 153, 153, +0, 153, 153, +0, 102, 153, +0, 51, 153, +0, 0, 153, +51, 0, 153, +102, 0, 153, +153, 0, 153, +153, 0, 153, +153, 0, 153, +153, 0, 153, +153, 0, 153, +153, 0, 102, +153, 0, 51, +153, 0, 0, +153, 51, 0, +153, 102, 0, +153, 153, 0, +153, 153, 0, +153, 153, 0, +153, 153, 0, +153, 153, 0, +102, 153, 0, +51, 153, 0, +0, 153, 0, +0, 153, 51, +0, 153, 102, +0, 153, 153, +0, 153, 153, +51, 51, 51, // eigth row +0, 102, 102, +0, 102, 102, +0, 102, 102, +0, 102, 102, +0, 51, 102, +0, 0, 102, +51, 0, 102, +102, 0, 102, +102, 0, 102, +102, 0, 102, +102, 0, 102, +102, 0, 102, +102, 0, 102, +102, 0, 102, +102, 0, 51, +102, 0, 0, +102, 51, 0, +102, 102, 0, +102, 102, 0, +102, 102, 0, +102, 102, 0, +102, 102, 0, +102, 102, 0, +102, 102, 0, +51, 102, 0, +0, 102, 0, +0, 102, 51, +0, 102, 102, +0, 102, 102, +0, 102, 102, +0, 0, 0, // ninth row +0, 51, 51, +0, 51, 51, +0, 51, 51, +0, 51, 51, +0, 51, 51, +0, 0, 51, +51, 0, 51, +51, 0, 51, +51, 0, 51, +51, 0, 51, +51, 0, 51, +51, 0, 51, +51, 0, 51, +51, 0, 51, +51, 0, 51, +51, 0, 0, +51, 51, 0, +51, 51, 0, +51, 51, 0, +51, 51, 0, +51, 51, 0, +51, 51, 0, +51, 51, 0, +51, 51, 0, +0, 51, 0, +0, 51, 51, +0, 51, 51, +0, 51, 51, +0, 51, 51, +51, 51, 51 }; + return rawValues; + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/colordialog/MySwatchPanel.java b/src/com/jpexs/decompiler/flash/gui/colordialog/MySwatchPanel.java new file mode 100644 index 000000000..ebc03dc1f --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/colordialog/MySwatchPanel.java @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2024 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.gui.colordialog; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import javax.swing.JPanel; + +/** + * + * @author JPEXS + */ +class MySwatchPanel extends JPanel { + protected Color[] colors; + protected Dimension swatchSize; + protected Dimension numSwatches; + protected Dimension gap; + private int selRow; + private int selCol; + public MySwatchPanel() { + initValues(); + initColors(); + setToolTipText(""); // register for events + setOpaque(true); + setBackground(Color.white); + setFocusable(true); + setInheritsPopupMenu(true); + addFocusListener(new FocusAdapter() { + public void focusGained(FocusEvent e) { + repaint(); + } + public void focusLost(FocusEvent e) { + repaint(); + } + }); + addKeyListener(new KeyAdapter() { + public void keyPressed(KeyEvent e) { + int typed = e.getKeyCode(); + switch (typed) { + case KeyEvent.VK_UP: + if (selRow > 0) { + selRow--; + repaint(); + } + break; + case KeyEvent.VK_DOWN: + if (selRow < numSwatches.height - 1) { + selRow++; + repaint(); + } + break; + case KeyEvent.VK_LEFT: + if (selCol > 0 && MySwatchPanel.this.getComponentOrientation().isLeftToRight()) { + selCol--; + repaint(); + } else if (selCol < numSwatches.width - 1 + && !MySwatchPanel.this.getComponentOrientation().isLeftToRight()) { + selCol++; + repaint(); + } + break; + case KeyEvent.VK_RIGHT: + if (selCol < numSwatches.width - 1 + && MySwatchPanel.this.getComponentOrientation().isLeftToRight()) { + selCol++; + repaint(); + } else if (selCol > 0 && !MySwatchPanel.this.getComponentOrientation().isLeftToRight()) { + selCol--; + repaint(); + } + break; + case KeyEvent.VK_HOME: + selCol = 0; + selRow = 0; + repaint(); + break; + case KeyEvent.VK_END: + selCol = numSwatches.width - 1; + selRow = numSwatches.height - 1; + repaint(); + break; + } + } + }); + } + public Color getSelectedColor() { + return getColorForCell(selCol, selRow); + } + protected void initValues() { + } + public void paintComponent(Graphics g) { + g.setColor(getBackground()); + g.fillRect(0,0,getWidth(), getHeight()); + for (int row = 0; row < numSwatches.height; row++) { + int y = row * (swatchSize.height + gap.height); + for (int column = 0; column < numSwatches.width; column++) { + Color c = getColorForCell(column, row); + g.setColor(c); + int x; + if (!this.getComponentOrientation().isLeftToRight()) { + x = (numSwatches.width - column - 1) * (swatchSize.width + gap.width); + } else { + x = column * (swatchSize.width + gap.width); + } + g.fillRect( x, y, swatchSize.width, swatchSize.height); + g.setColor(Color.black); + g.drawLine( x+swatchSize.width-1, y, x+swatchSize.width-1, y+swatchSize.height-1); + g.drawLine( x, y+swatchSize.height-1, x+swatchSize.width-1, y+swatchSize.height-1); + if (selRow == row && selCol == column && this.isFocusOwner()) { + Color c2 = new Color(c.getRed() < 125 ? 255 : 0, + c.getGreen() < 125 ? 255 : 0, + c.getBlue() < 125 ? 255 : 0); + g.setColor(c2); + g.drawLine(x, y, x + swatchSize.width - 1, y); + g.drawLine(x, y, x, y + swatchSize.height - 1); + g.drawLine(x + swatchSize.width - 1, y, x + swatchSize.width - 1, y + swatchSize.height - 1); + g.drawLine(x, y + swatchSize.height - 1, x + swatchSize.width - 1, y + swatchSize.height - 1); + g.drawLine(x, y, x + swatchSize.width - 1, y + swatchSize.height - 1); + g.drawLine(x, y + swatchSize.height - 1, x + swatchSize.width - 1, y); + } + } + } + } + public Dimension getPreferredSize() { + int x = numSwatches.width * (swatchSize.width + gap.width) - 1; + int y = numSwatches.height * (swatchSize.height + gap.height) - 1; + return new Dimension( x, y ); + } + protected void initColors() { + } + public String getToolTipText(MouseEvent e) { + Color color = getColorForLocation(e.getX(), e.getY()); + return color.getRed()+", "+ color.getGreen() + ", " + color.getBlue(); + } + public void setSelectedColorFromLocation(int x, int y) { + if (!this.getComponentOrientation().isLeftToRight()) { + selCol = numSwatches.width - x / (swatchSize.width + gap.width) - 1; + } else { + selCol = x / (swatchSize.width + gap.width); + } + selRow = y / (swatchSize.height + gap.height); + repaint(); + } + public Color getColorForLocation( int x, int y ) { + int column; + if (!this.getComponentOrientation().isLeftToRight()) { + column = numSwatches.width - x / (swatchSize.width + gap.width) - 1; + } else { + column = x / (swatchSize.width + gap.width); + } + int row = y / (swatchSize.height + gap.height); + return getColorForCell(column, row); + } + private Color getColorForCell( int column, int row) { + return colors[ (row * numSwatches.width) + column ]; // (STEVE) - change data orientation here + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/generictageditors/ColorEditor.java b/src/com/jpexs/decompiler/flash/gui/generictageditors/ColorEditor.java index 9bfd5d280..5ec7869be 100644 --- a/src/com/jpexs/decompiler/flash/gui/generictageditors/ColorEditor.java +++ b/src/com/jpexs/decompiler/flash/gui/generictageditors/ColorEditor.java @@ -17,6 +17,8 @@ package com.jpexs.decompiler.flash.gui.generictageditors; import com.jpexs.decompiler.flash.gui.AppStrings; +import com.jpexs.decompiler.flash.gui.Main; +import com.jpexs.decompiler.flash.gui.View; import com.jpexs.decompiler.flash.types.ARGB; import com.jpexs.decompiler.flash.types.RGB; import com.jpexs.decompiler.flash.types.RGBA; @@ -34,17 +36,24 @@ import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.lang.reflect.Array; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.Objects; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JColorChooser; import javax.swing.JDialog; +import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JSlider; import javax.swing.JSpinner; import javax.swing.border.BevelBorder; import javax.swing.colorchooser.AbstractColorChooserPanel; +import com.jpexs.decompiler.flash.gui.colordialog.MySwatchChooserPanel; +import com.jpexs.decompiler.flash.gui.ViewMessages; /** * @author JPEXS @@ -254,11 +263,22 @@ public class ColorEditor extends JPanel implements GenericTagEditor, ActionListe return col[0]; } + JDialog chooserDialog = null; + + private void colorCancelPerformed(ActionEvent e) { + chooserDialog.setVisible(false); + } + + private void colorOkPerformed(ActionEvent e) { + chooserDialog.setVisible(false); + } + @Override public void actionPerformed(ActionEvent e) { - Color newColor; - if (colorType == COLOR_TYPE_RGB) { + Color newColor = ViewMessages.showColorDialog(this, color, colorType == COLOR_TYPE_RGBA); + + /*if (colorType == COLOR_TYPE_RGB) { try { newColor = noTransparencyColorChooser(null, AppStrings.translate("dialog.selectcolor.title"), color); } catch (Exception ex) { @@ -266,7 +286,7 @@ public class ColorEditor extends JPanel implements GenericTagEditor, ActionListe } } else { newColor = JColorChooser.showDialog(null, AppStrings.translate("dialog.selectcolor.title"), color); - } + }*/ if (newColor != null) { color = newColor; buttonChange.setBackground(color); diff --git a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties index b3b7dc36d..b4070d4a0 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties @@ -531,3 +531,7 @@ config.description.warningAddFunction = Show warning before creating new functio #after 21.0.2 config.name.linkAllClasses = Add link to all classes (sound, font, image) config.description.linkAllClasses = Add special script that links all (sound, font, image) classes in the SWF. This is useful when no other script links them, to be still available in compiled file. + +#after 21.1.0 +config.name.recentColors = Recent colors +config.description.recentColors = Recent colors in the color dialog diff --git a/src/com/jpexs/decompiler/flash/gui/locales/ColorChooserDialog.properties b/src/com/jpexs/decompiler/flash/gui/locales/ColorChooserDialog.properties new file mode 100644 index 000000000..fd63fa7a3 --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/locales/ColorChooserDialog.properties @@ -0,0 +1,16 @@ +# Copyright (C) 2024 JPEXS +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +dialog.title = Choose color +recent.add = Add \ No newline at end of file