Simple editor - filters (editing only existing, without gradients)

This commit is contained in:
Jindra Petřík
2025-05-10 13:13:17 +02:00
parent c1007fae70
commit 3133d7b6d0
21 changed files with 605 additions and 134 deletions

View File

@@ -22,7 +22,7 @@ All notable changes to this project will be documented in this file.
- Option to enter custom zoom level by clicking on zoom percentage label
- Show in Simple editor context menu item for timelined items (sprites, buttons, swfs)
- Simple editor - change background color
- Simple editor - filters (read only yet)
- Simple editor - filters (editing only existing, without gradients)
### Fixed
- [#2424] DefineEditText handling of letterSpacing, font size on incorrect values

View File

@@ -727,22 +727,36 @@ public class PlaceObject3Tag extends PlaceObjectTypeTag implements ASMSourceCont
this.placeFlagHasBlendMode = value;
}
@Override
public void setBitmapCache(int value) {
this.bitmapCache = value;
this.placeFlagHasCacheAsBitmap = true;
}
@Override
public void setPlaceFlagHasCacheAsBitmap(boolean value) {
this.placeFlagHasCacheAsBitmap = value;
}
@Override
public void setBackgroundColor(RGBA value) {
this.backgroundColor = value;
this.placeFlagOpaqueBackground = true;
}
@Override
public void setPlaceFlagOpaqueBackground(boolean value) {
this.placeFlagOpaqueBackground = value;
}
@Override
public void setPlaceFlagHasFilterList(boolean placeFlagHasFilterList) {
this.placeFlagHasFilterList = placeFlagHasFilterList;
}
@Override
public void setFilters(List<FILTER> filters) {
this.surfaceFilterList = new ArrayList<>(filters);
this.placeFlagHasFilterList = true;
}
}

View File

@@ -748,21 +748,36 @@ public class PlaceObject4Tag extends PlaceObjectTypeTag implements ASMSourceCont
this.placeFlagHasBlendMode = value;
}
@Override
public void setBitmapCache(int value) {
this.bitmapCache = value;
this.placeFlagHasCacheAsBitmap = true;
}
@Override
public void setPlaceFlagHasCacheAsBitmap(boolean value) {
this.placeFlagHasCacheAsBitmap = value;
}
@Override
public void setBackgroundColor(RGBA value) {
this.backgroundColor = value;
this.placeFlagOpaqueBackground = true;
}
@Override
public void setPlaceFlagOpaqueBackground(boolean value) {
this.placeFlagOpaqueBackground = value;
}
@Override
public void setPlaceFlagHasFilterList(boolean placeFlagHasFilterList) {
this.placeFlagHasFilterList = placeFlagHasFilterList;
}
@Override
public void setFilters(List<FILTER> filters) {
this.surfaceFilterList = new ArrayList<>(filters);
this.placeFlagHasFilterList = true;
}
}

View File

@@ -247,6 +247,14 @@ public abstract class PlaceObjectTypeTag extends Tag implements CharacterIdTag,
throw new UnsupportedOperationException();
}
public void setPlaceFlagHasFilterList(boolean value) {
throw new UnsupportedOperationException();
}
public void setFilters(List<FILTER> filters) {
throw new UnsupportedOperationException();
}
/**
* Checks if place equals.
* @param other Other place object type tag
@@ -292,6 +300,9 @@ public abstract class PlaceObjectTypeTag extends Tag implements CharacterIdTag,
if (!Objects.equals(getAmfData(), other.getAmfData())) { //?
return false;
}
if (!Objects.equals(getFilters(), other.getFilters())) {
return false;
}
return true;
}

View File

@@ -17,31 +17,58 @@
package com.jpexs.decompiler.flash.easygui;
import com.jpexs.decompiler.flash.ecma.EcmaNumberToString;
import com.jpexs.decompiler.flash.gui.AppStrings;
import com.jpexs.decompiler.flash.gui.View;
import com.jpexs.decompiler.flash.gui.generictageditors.BooleanEditor;
import com.jpexs.decompiler.flash.gui.generictageditors.ChangeListener;
import com.jpexs.decompiler.flash.gui.generictageditors.ColorEditor;
import com.jpexs.decompiler.flash.gui.generictageditors.FloatEditor;
import com.jpexs.decompiler.flash.gui.generictageditors.GenericTagEditor;
import com.jpexs.decompiler.flash.gui.generictageditors.NumberEditor;
import com.jpexs.decompiler.flash.gui.generictageditors.ValueNormalizer;
import com.jpexs.decompiler.flash.types.RGB;
import com.jpexs.decompiler.flash.types.RGBA;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.decompiler.flash.types.filters.FILTER;
import de.javagl.treetable.JTreeTable;
import de.javagl.treetable.TreeTableModel;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
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.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.EventObject;
import java.util.List;
import java.util.Objects;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.BevelBorder;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.plaf.basic.BasicTableUI;
import javax.swing.table.TableColumn;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellEditor;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
/**
@@ -50,6 +77,8 @@ import javax.swing.tree.TreePath;
*/
public class FiltersTreeTable extends JTreeTable {
private List<ActionListener> filterChangedListeners = new ArrayList<>();
public FiltersTreeTable() {
super(new FiltersTreeTableModel(null));
getTree().setCellRenderer(new FiltersTreeCellRenderer());
@@ -106,7 +135,7 @@ public class FiltersTreeTable extends JTreeTable {
getTree().setBackground(Color.WHITE);
}
addMouseListener(new MouseAdapter() {
/*addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2) {
@@ -119,18 +148,278 @@ public class FiltersTreeTable extends JTreeTable {
}
}
});
});*/
getTableHeader().setReorderingAllowed(false);
/*getTree().addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (isEditing()) {
getCellEditor().stopCellEditing();
}
}
});*/
}
public void addFilterChangedListener(ActionListener l) {
filterChangedListeners.add(l);
}
public void removeFilterChangedListener(ActionListener l) {
filterChangedListeners.remove(l);
}
private void fireFilterChanged() {
List<ActionListener> listeners2 = new ArrayList<>(filterChangedListeners);
for (ActionListener l : listeners2) {
l.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "filterChanged"));
}
}
public List<FILTER> getFilters() {
TreeModel model = getTree().getModel();
if (model instanceof FiltersTreeTableModel) {
FiltersTreeTableModel treeTableModel = (FiltersTreeTableModel) model;
return treeTableModel.filters;
}
return new ArrayList<>();
}
public void setFilters(List<FILTER> filters) {
if (Objects.equals(getFilters(), filters)) {
return;
}
setTreeTableModel(new FiltersTreeTableModel(filters));
getColumnModel().getColumn(0).setMinWidth(200);
getColumnModel().getColumn(0).setWidth(200);
getColumnModel().getColumn(0).setPreferredWidth(200);
getColumnModel().getColumn(1).setPreferredWidth(Integer.MAX_VALUE);
getColumnModel().getColumn(1).setCellEditor(new FiltersValueCellEditor(this));
getColumnModel().getColumn(1).setCellRenderer(new FiltersTableCellRenderer());
TreeModel ttm = getTree().getModel();
Object root = ttm.getRoot();
int childCount = ttm.getChildCount(root);
for (int i = 0; i < childCount; i++) {
getTree().expandPath(new TreePath(new Object[]{root, ttm.getChild(root, i)}));
}
}
private static class FiltersValueCellEditor implements TableCellEditor {
private Object value;
private GenericTagEditor editor;
private List<CellEditorListener> listeners = new ArrayList<>();
private final FiltersTreeTable filtersTable;
public FiltersValueCellEditor(FiltersTreeTable filtersTable) {
this.filtersTable = filtersTable;
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
if (value == null) {
return null;
}
if (!(value instanceof FilterValue)) {
return null;
}
FilterValue filterValue = (FilterValue) value;
Object realValue = filterValue.getValue();
this.value = value;
FilterField filterField = filterValue.filterField;
if (editor != null) {
//((Component) editor).setVisible(false);
}
editor = null;
if (realValue.getClass() == Boolean.class) {
editor = new BooleanEditor(filterField.toString(), filterField.filter, filterField.field, -1, Boolean.class);
/*editor.addChangeListener(new ChangeListener() {
@Override
public void change(GenericTagEditor editor) {
editor.save();
}
});*/
//((BooleanEditor) editor).setRequestFocusEnabled(false);
} else if (realValue.getClass() == Double.class || realValue.getClass() == Float.class) {
editor = new FloatEditor(filterField.toString(), filterField.filter, filterField.field, -1, realValue.getClass());
//editor = new NumberEditor(filterField.toString(), filterField.filter, filterField.field, -1, realValue.getClass(), filterField.field.getAnnotation(SWFType.class));
if ("angle".equals(filterField.field.getName())) {
editor.setValueNormalizer(new ValueNormalizer() {
@Override
public Object toFieldValue(Object viewValue) {
return Math.toRadians((double) viewValue);
}
@Override
public Object toViewValue(Object fieldValue) {
return Math.round(Math.toDegrees((double) fieldValue) * 100) / 100.0;
}
});
}
} else if (realValue.getClass() == int.class || realValue.getClass() == Integer.class) {
editor = new NumberEditor(filterField.toString(), filterField.filter, filterField.field, -1, realValue.getClass(), filterField.field.getAnnotation(SWFType.class));
} else if (realValue.getClass() == RGBA.class) {
editor = new ColorEditor(filterField.toString(), filterField.filter, filterField.field, -1, RGBA.class);
}
if (editor != null) {
editor.addChangeListener(new ChangeListener() {
@Override
public void change(GenericTagEditor editor) {
editor.save();
filtersTable.fireFilterChanged();
}
});
if (table instanceof JTreeTable) {
JTreeTable treeTable = (JTreeTable) table;
if (treeTable.isRowSelected(row)) {
((JComponent) editor).setForeground(new Color(UIManager.getColor("Table.selectionForeground").getRGB(), true));
((JComponent) editor).setBackground(new Color(UIManager.getColor("Table.selectionBackground").getRGB(), true));
((JComponent) editor).setOpaque(true);
} else {
((JComponent) editor).setOpaque(false);
}
}
}
return (Component) editor;
}
@Override
public Object getCellEditorValue() {
return value;
}
@Override
public boolean isCellEditable(EventObject anEvent) {
return true;
}
@Override
public boolean shouldSelectCell(EventObject anEvent) {
if (value == null) {
return true;
}
if (!(value instanceof FilterValue)) {
return false;
}
FilterValue filterValue = (FilterValue) value;
Object realValue = filterValue.getValue();
if (realValue.getClass() == Double.class || realValue.getClass() == Float.class) {
return true;
}
if (realValue.getClass() == Boolean.class) {
return false;
}
return false;
}
@Override
public boolean stopCellEditing() {
editor.save();
List<CellEditorListener> listeners2 = new ArrayList<>(listeners);
for (CellEditorListener l : listeners2) {
l.editingStopped(new ChangeEvent(editor));
}
return true;
}
@Override
public void cancelCellEditing() {
List<CellEditorListener> listeners2 = new ArrayList<>(listeners);
for (CellEditorListener l : listeners2) {
l.editingCanceled(new ChangeEvent(editor));
}
editor.reset();
}
@Override
public void addCellEditorListener(CellEditorListener l) {
listeners.add(l);
}
@Override
public void removeCellEditorListener(CellEditorListener l) {
listeners.remove(l);
}
}
private static class FiltersTableCellRenderer extends DefaultTableCellRenderer {
JLabel label = new JLabel();
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
label.setText(value.toString());
if (table instanceof JTreeTable) {
JTreeTable treeTable = (JTreeTable) table;
isSelected = treeTable.isRowSelected(row);
}
JComponent component = label;
if (value instanceof FilterValue) {
FilterValue filterValue = (FilterValue) value;
Object fieldValue = filterValue.getValue();
if (fieldValue != null) {
if (fieldValue.getClass() == Boolean.class) {
JPanel panel = new JPanel(new BorderLayout());
JCheckBox checkBox = new JCheckBox();
//checkBox.setHorizontalAlignment(CENTER);
checkBox.setSelected((Boolean) fieldValue);
checkBox.setOpaque(false);
panel.add(checkBox, BorderLayout.CENTER);
panel.setOpaque(false);
component = panel;
}
if (fieldValue.getClass() == RGBA.class) {
JPanel panel = new JPanel(new BorderLayout());
JButton buttonChange = new JButton("") {
@Override
protected void paintComponent(Graphics g) {
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
super.paintBorder(g);
}
};
buttonChange.setToolTipText(AppStrings.translate("button.selectcolor.hint"));
buttonChange.setCursor(new Cursor(Cursor.HAND_CURSOR));
buttonChange.setBorderPainted(true);
buttonChange.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
Dimension colorDim = new Dimension(16, 16);
buttonChange.setSize(colorDim);
buttonChange.setPreferredSize(colorDim);
buttonChange.setBackground(((RGBA) fieldValue).toColor());
panel.add(buttonChange, BorderLayout.WEST);
component = panel;
}
}
}
if (isSelected) {
component.setForeground(new Color(UIManager.getColor("Table.selectionForeground").getRGB(), true));
component.setBackground(new Color(UIManager.getColor("Table.selectionBackground").getRGB(), true));
component.setOpaque(true);
} else {
component.setOpaque(false);
}
return component;
}
}
private static class FiltersTreeCellRenderer extends DefaultTreeCellRenderer {
@@ -155,24 +444,6 @@ public class FiltersTreeTable extends JTreeTable {
}
}
private static class LibraryFolder {
private String name;
public LibraryFolder(String name) {
this.name = name;
}
@Override
public String toString() {
return EasyStrings.translate("library.folder." + name);
}
public String getName() {
return name;
}
}
private static class FilterField {
private final FILTER filter;
@@ -206,15 +477,76 @@ public class FiltersTreeTable extends JTreeTable {
}
private static class FilterValue {
private final FilterField filterField;
public FilterValue(FilterField filterField) {
this.filterField = filterField;
}
public Object getValue() {
return filterField.getValue();
}
@Override
public String toString() {
return valueToString(filterField.getField().getName(), filterField.getValue());
}
}
private static String valueToString(String fieldName, Object value) {
if (value == null) {
return "null";
}
if (value.getClass().isArray()) {
StringBuilder sb = new StringBuilder();
sb.append("[");
int length = Array.getLength(value);
for (int i = 0; i < length; i++) {
Object element = Array.get(value, i);
sb.append(valueToString(fieldName, element));
if (i < length - 1) {
sb.append(", ");
}
}
sb.append("]");
return sb.toString();
}
if (value.getClass() == RGBA.class) {
RGBA rgb = (RGBA) value;
return rgb.toHexARGB();
}
if (value.getClass() == RGB.class) {
RGB rgb = (RGB) value;
return rgb.toHexRGB();
}
if (fieldName.equals("angle")) {
return "" + EcmaNumberToString.stringFor(Math.round(Math.toDegrees((double) value) * 100) / 100.0);
}
if (value.getClass() == Double.class) {
return EcmaNumberToString.stringFor((Double) value);
}
if (value.getClass() == Float.class) {
return EcmaNumberToString.stringFor((Float) value);
}
return "" + value;
}
private static class FiltersTreeTableModel implements TreeTableModel {
private final DefaultMutableTreeNode root;
private List<FILTER> filters;
public FiltersTreeTableModel(List<FILTER> filters) {
root = new DefaultMutableTreeNode("root");
this.filters = filters;
if (filters == null) {
DefaultMutableTreeNode indeterminate = new DefaultMutableTreeNode(EasyStrings.translate("properties.instance.filters.indeterminate"));
DefaultMutableTreeNode indeterminate = new DefaultMutableTreeNode(EasyStrings.translate("property.instance.filters.indeterminate"));
root.add(indeterminate);
return;
}
@@ -243,9 +575,9 @@ public class FiltersTreeTable extends JTreeTable {
public String getColumnName(int column) {
switch (column) {
case 0:
return EasyStrings.translate("properties.instance.filters.header.property");
return EasyStrings.translate("property.instance.filters.header.property");
case 1:
return EasyStrings.translate("properties.instance.filters.header.value");
return EasyStrings.translate("property.instance.filters.header.value");
default:
return null;
}
@@ -262,46 +594,6 @@ public class FiltersTreeTable extends JTreeTable {
}
private String valueToString(String fieldName, Object value) {
if (value == null) {
return "null";
}
if (value.getClass().isArray()) {
StringBuilder sb = new StringBuilder();
sb.append("[");
int length = Array.getLength(value);
for (int i = 0; i < length; i++) {
Object element = Array.get(value, i);
sb.append(valueToString(fieldName, element));
if (i < length - 1) {
sb.append(", ");
}
}
sb.append("]");
return sb.toString();
}
if (value.getClass() == RGBA.class) {
RGBA rgb = (RGBA) value;
return rgb.toHexARGB();
}
if (value.getClass() == RGB.class) {
RGB rgb = (RGB) value;
return rgb.toHexRGB();
}
if (fieldName.equals("angle")) {
return "" + EcmaNumberToString.stringFor(Math.round(Math.toDegrees((double) value) * 100) / 100.0);
}
if (value.getClass() == Double.class) {
return EcmaNumberToString.stringFor((Double) value);
}
if (value.getClass() == Float.class) {
return EcmaNumberToString.stringFor((Float) value);
}
return "" + value;
}
@Override
public Object getValueAt(Object node, int column) {
DefaultMutableTreeNode n = (DefaultMutableTreeNode) node;
@@ -312,7 +604,7 @@ public class FiltersTreeTable extends JTreeTable {
case 1:
if (o instanceof FilterField) {
FilterField filterField = (FilterField) o;
return valueToString(filterField.field.getName(), filterField.getValue());
return new FilterValue(filterField);
} else {
return "";
}
@@ -326,6 +618,10 @@ public class FiltersTreeTable extends JTreeTable {
if (column == 0) {
return true;
}
DefaultMutableTreeNode n = (DefaultMutableTreeNode) node;
if (column == 1 && n.getUserObject() instanceof FilterField) {
return true;
}
return false;
}

View File

@@ -38,6 +38,7 @@ import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA;
import com.jpexs.decompiler.flash.types.ColorTransform;
import com.jpexs.decompiler.flash.types.RGBA;
import com.jpexs.decompiler.flash.types.filters.FILTER;
import com.jpexs.helpers.Helper;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
@@ -337,35 +338,35 @@ public class InstancePropertiesPanel extends AbstractPropertiesPanel {
JScrollPane sp = new JScrollPane(filtersTable);
filtersPanel.add(sp, BorderLayout.CENTER);
sp.getViewport().setBackground(filtersTable.getBackground());
//filtersPanel.setBorder(BorderFactory.createLineBorder(Color.red, 5));
//sp.setMaximumSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
filtersTable.addFilterChangedListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
List<FILTER> newFilters = filtersTable.getFilters();
if (newFilters != null) {
undoManager.doOperation(new PlaceChangeDoableOperation("instance.filters", 3) {
List<FILTER> applyFilters = Helper.deepCopy(newFilters);
@Override
public void doPlaceOperation(PlaceObjectTypeTag placeObject, DepthState depthState) {
placeObject.setFilters(applyFilters);
}
}, swfPanel.getSwf());
}
}
});
propertiesPanel = new JPanel();
//propertiesPanel.setLayout(new BoxLayout(propertiesPanel, BoxLayout.Y_AXIS));
//propertiesPanel.setBorder(BorderFactory.createLineBorder(Color.GREEN, 5));
propertiesPanel.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
propertiesPanel.setLayout(new GridBagLayout());
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = -1;
/*gbc.anchor = GridBagConstraints.FIRST_LINE_START;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridx = 0;
gbc.gridy = 0;
gbcc.weightx = 1;*/
addCard(propertiesPanel, "positionSize", null, positionSizePanel, gbc, false);
//gbc.gridy++;
addCard(propertiesPanel, "colorEffect", null, colorEffectPanel, gbc, false);
//gbc.gridy++;
addCard(propertiesPanel, "display", null, displayPanel, gbc, false);
//gbc.gridy++;
//gbc.fill = GridBagConstraints.BOTH; //GridBagConstraints.BOTH;
//gbc.weighty = 1;
addCard(propertiesPanel, "filters", null, filtersPanel, gbc, true);
setCardOpened("positionSize", true);
@@ -825,12 +826,13 @@ public class InstancePropertiesPanel extends AbstractPropertiesPanel {
}
}
if (filters.size() == 1) {
List<FILTER> oneFilters = filters.iterator().next();
if (oneFilters == null) {
filtersTable.setFilters(new ArrayList<>());
} else {
filtersTable.setFilters(oneFilters);
filtersTable.setFilters(Helper.deepCopy(oneFilters));
}
} else if (filters.isEmpty()) {
filtersTable.setFilters(new ArrayList<>());

View File

@@ -5262,7 +5262,11 @@ public final class ImagePanel extends JPanel implements MediaDisplay {
Reference<Rectangle2D> boundsRef = new Reference<>(null);
RECT rect = getTopTimelined().getRect();
Timelined t = getTopTimelined();
if (t == null) {
return;
}
RECT rect = t.getRect();
synchronized (ImagePanel.this) {
synchronized (lock) {

View File

@@ -276,6 +276,9 @@ public class MainFrameClassicMenu extends MainFrameMenu {
if (selected != null) {
selected = mapping(selected);
}
if (menuGroups == null) {
return;
}
for (String path : menuGroups.get(group)) {
setMenuChecked(path, selected == null ? false : path.equals(selected));
}

View File

@@ -264,4 +264,9 @@ public class Amf3ValueEditor extends JPanel implements GenericTagEditor, FullSiz
public Object getObject() {
return obj;
}
@Override
public void setValueNormalizer(ValueNormalizer normalizer) {
}
}

View File

@@ -199,4 +199,9 @@ public class BinaryDataEditor extends JPanel implements GenericTagEditor {
public Object getObject() {
return obj;
}
@Override
public void setValueNormalizer(ValueNormalizer normalizer) {
}
}

View File

@@ -17,15 +17,18 @@
package com.jpexs.decompiler.flash.gui.generictageditors;
import com.jpexs.helpers.ReflectionTools;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Field;
import javax.swing.JCheckBox;
import javax.swing.JPanel;
/**
* @author JPEXS
*/
public class BooleanEditor extends JCheckBox implements GenericTagEditor {
public class BooleanEditor extends JPanel implements GenericTagEditor {
private final Object obj;
@@ -36,6 +39,8 @@ public class BooleanEditor extends JCheckBox implements GenericTagEditor {
private final Class<?> type;
private final String fieldName;
private final JCheckBox checkBox;
@Override
public void added() {
@@ -49,7 +54,13 @@ public class BooleanEditor extends JCheckBox implements GenericTagEditor {
this.index = index;
this.type = type;
this.fieldName = fieldName;
reset();
checkBox = new JCheckBox();
checkBox.setOpaque(false);
checkBox.setRequestFocusEnabled(false);
setLayout(new BorderLayout());
add(checkBox, BorderLayout.CENTER);
setOpaque(false);
reset();
}
@Override
@@ -59,7 +70,7 @@ public class BooleanEditor extends JCheckBox implements GenericTagEditor {
@Override
public void reset() {
try {
setSelected((boolean) ReflectionTools.getValue(obj, field, index));
checkBox.setSelected((boolean) ReflectionTools.getValue(obj, field, index));
} catch (IllegalArgumentException | IllegalAccessException ex) {
// ignore
}
@@ -69,13 +80,13 @@ public class BooleanEditor extends JCheckBox implements GenericTagEditor {
public boolean save() {
try {
boolean oldValue = (boolean) ReflectionTools.getValue(obj, field, index);
boolean newValue = isSelected();
boolean newValue = checkBox.isSelected();
if (oldValue == newValue) {
return false;
}
ReflectionTools.setValue(obj, field, index, isSelected());
ReflectionTools.setValue(obj, field, index, checkBox.isSelected());
} catch (IllegalArgumentException | IllegalAccessException ex) {
// ignore
}
@@ -85,7 +96,7 @@ public class BooleanEditor extends JCheckBox implements GenericTagEditor {
@Override
public void addChangeListener(final ChangeListener l) {
final GenericTagEditor t = this;
addActionListener(new ActionListener() {
checkBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
@@ -96,7 +107,7 @@ public class BooleanEditor extends JCheckBox implements GenericTagEditor {
@Override
public Object getChangedValue() {
return isSelected();
return checkBox.isSelected();
}
@Override
@@ -118,4 +129,9 @@ public class BooleanEditor extends JCheckBox implements GenericTagEditor {
public Object getObject() {
return obj;
}
@Override
public void setValueNormalizer(ValueNormalizer normalizer) {
}
}

View File

@@ -17,12 +17,14 @@
package com.jpexs.decompiler.flash.gui.generictageditors;
import com.jpexs.decompiler.flash.gui.AppStrings;
import com.jpexs.decompiler.flash.gui.FocusablePanel;
import com.jpexs.decompiler.flash.gui.ViewMessages;
import com.jpexs.decompiler.flash.types.ARGB;
import com.jpexs.decompiler.flash.types.RGB;
import com.jpexs.decompiler.flash.types.RGBA;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.ReflectionTools;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
@@ -36,6 +38,8 @@ import java.awt.event.FocusEvent;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import javax.swing.BorderFactory;
import javax.swing.JButton;
@@ -50,7 +54,7 @@ import javax.swing.colorchooser.AbstractColorChooserPanel;
/**
* @author JPEXS
*/
public class ColorEditor extends JPanel implements GenericTagEditor, ActionListener {
public class ColorEditor extends FocusablePanel implements GenericTagEditor, ActionListener {
private final Object obj;
@@ -74,6 +78,8 @@ public class ColorEditor extends JPanel implements GenericTagEditor, ActionListe
private final JButton buttonChange;
private final List<ChangeListener> changeListeners = new ArrayList<>();
public int getColorType() {
return colorType;
}
@@ -90,7 +96,7 @@ public class ColorEditor extends JPanel implements GenericTagEditor, ActionListe
this.type = type;
this.fieldName = fieldName;
setLayout(new FlowLayout());
setLayout(new BorderLayout());
buttonChange = new JButton("") {
@@ -111,7 +117,7 @@ public class ColorEditor extends JPanel implements GenericTagEditor, ActionListe
Dimension colorDim = new Dimension(16, 16);
buttonChange.setSize(colorDim);
buttonChange.setPreferredSize(colorDim);
add(buttonChange);
add(buttonChange, BorderLayout.WEST);
reset();
}
@@ -163,15 +169,7 @@ public class ColorEditor extends JPanel implements GenericTagEditor, ActionListe
@Override
public void addChangeListener(final ChangeListener l) {
final GenericTagEditor t = this;
addFocusListener(new FocusAdapter() {
@Override
public void focusLost(FocusEvent e) {
l.change(t);
}
});
changeListeners.add(l);
}
@Override
@@ -256,15 +254,15 @@ public class ColorEditor extends JPanel implements GenericTagEditor, ActionListe
}
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) {
@@ -283,6 +281,10 @@ public class ColorEditor extends JPanel implements GenericTagEditor, ActionListe
color = newColor;
buttonChange.setBackground(color);
repaint();
List<ChangeListener> listeners2 = new ArrayList<>(changeListeners);
for (ChangeListener l : listeners2) {
l.change(this);
}
}
}
@@ -296,4 +298,9 @@ public class ColorEditor extends JPanel implements GenericTagEditor, ActionListe
public Object getObject() {
return obj;
}
@Override
public void setValueNormalizer(ValueNormalizer normalizer) {
}
}

View File

@@ -159,4 +159,9 @@ public class EnumEditor extends JComboBox<ComboBoxItem<Integer>> implements Gene
public Object getObject() {
return obj;
}
@Override
public void setValueNormalizer(ValueNormalizer normalizer) {
}
}

View File

@@ -24,6 +24,8 @@ import java.awt.Dimension;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import javax.swing.JTextField;
@@ -41,7 +43,9 @@ public class FloatEditor extends JTextField implements GenericTagEditor {
private final Class<?> type;
private String fieldName;
private ValueNormalizer normalizer;
@Override
public boolean getScrollableTracksViewportWidth() {
return true;
@@ -77,7 +81,10 @@ public class FloatEditor extends JTextField implements GenericTagEditor {
public void reset() {
try {
Object val = ReflectionTools.getValue(obj, field, index);
setText(val == null ? "" : val.toString());
if (normalizer != null) {
val = normalizer.toViewValue(val);
}
setText(val == null ? "" : EcmaScript.toString(val));
} catch (IllegalArgumentException | IllegalAccessException ex) {
// ignore
}
@@ -86,7 +93,11 @@ public class FloatEditor extends JTextField implements GenericTagEditor {
@Override
public boolean save() {
try {
String oldValue = (String) EcmaScript.toString(ReflectionTools.getValue(obj, field, index));
Object oldFieldValue = ReflectionTools.getValue(obj, field, index);
if (normalizer != null) {
oldFieldValue = normalizer.toViewValue(oldFieldValue);
}
String oldValue = (String) EcmaScript.toString(oldFieldValue);
String newValue = getText();
if (Objects.equals(oldValue, newValue)) {
return false;
@@ -97,6 +108,9 @@ public class FloatEditor extends JTextField implements GenericTagEditor {
} else {
val = Float.valueOf(getText());
}
if (normalizer != null) {
val = normalizer.toFieldValue(val);
}
ReflectionTools.setValue(obj, field, index, val);
} catch (IllegalArgumentException | IllegalAccessException ex) {
// ignore
@@ -150,4 +164,10 @@ public class FloatEditor extends JTextField implements GenericTagEditor {
public Object getObject() {
return obj;
}
@Override
public void setValueNormalizer(ValueNormalizer normalizer) {
this.normalizer = normalizer;
reset();
}
}

View File

@@ -42,4 +42,6 @@ public interface GenericTagEditor {
public void validateValue();
public Object getObject();
public void setValueNormalizer(ValueNormalizer normalizer);
}

View File

@@ -19,12 +19,14 @@ package com.jpexs.decompiler.flash.gui.generictageditors;
import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.helpers.ReflectionTools;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.lang.reflect.Field;
import java.util.Objects;
import javax.swing.JFormattedTextField;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
@@ -33,7 +35,7 @@ import javax.swing.text.DefaultFormatter;
/**
* @author JPEXS
*/
public class NumberEditor extends JSpinner implements GenericTagEditor {
public class NumberEditor extends JPanel implements GenericTagEditor {
private final Object obj;
@@ -46,6 +48,10 @@ public class NumberEditor extends JSpinner implements GenericTagEditor {
private final SWFType swfType;
private String fieldName;
private ValueNormalizer normalizer;
private JSpinner spinner;
@Override
public BaselineResizeBehavior getBaselineResizeBehavior() {
@@ -71,20 +77,28 @@ public class NumberEditor extends JSpinner implements GenericTagEditor {
this.type = type;
this.swfType = swfType;
this.fieldName = fieldName;
spinner = new JSpinner();
setLayout(new BorderLayout());
add(spinner, BorderLayout.WEST);
setOpaque(false);
reset();
((JSpinner.NumberEditor) getEditor()).getFormat().setGroupingUsed(false);
JFormattedTextField jtf = ((JSpinner.NumberEditor) getEditor()).getTextField();
reset();
((JSpinner.NumberEditor) spinner.getEditor()).getFormat().setGroupingUsed(false);
JFormattedTextField jtf = ((JSpinner.NumberEditor) spinner.getEditor()).getTextField();
DefaultFormatter formatter = (DefaultFormatter) jtf.getFormatter();
formatter.setCommitsOnValidEdit(true);
}
@Override
public void reset() {
try {
Object value = ReflectionTools.getValue(obj, field, index);
setModel(getModel(swfType, value));
if (normalizer != null) {
value = normalizer.toViewValue(value);
}
spinner.setModel(getModel(swfType, value));
} catch (IllegalArgumentException | IllegalAccessException ex) {
// ignore
}
@@ -93,14 +107,22 @@ public class NumberEditor extends JSpinner implements GenericTagEditor {
@Override
public boolean save() {
try {
Object oldValue = ReflectionTools.getValue(obj, field, index);
Object newValue = getChangedValue();
if (newValue == null) {
Object oldValue = ReflectionTools.getValue(obj, field, index);
Object oldViewValue = oldValue;
if (normalizer != null) {
oldViewValue = normalizer.toViewValue(oldValue);
}
Object newViewValue = getChangedValue();
if (newViewValue == null) {
return false;
}
if (Objects.equals(oldValue, newValue)) {
if (Objects.equals(oldViewValue, newViewValue)) {
return false;
}
Object newValue = newViewValue;
if (normalizer != null) {
newValue = normalizer.toFieldValue(newViewValue);
}
ReflectionTools.setValue(obj, field, index, newValue);
} catch (IllegalArgumentException | IllegalAccessException ex) {
// ignore
@@ -210,15 +232,15 @@ public class NumberEditor extends JSpinner implements GenericTagEditor {
public Object getChangedValue() {
Object value = null;
if (type.equals(int.class) || type.equals(Integer.class)) {
value = Integer.parseInt(getValue().toString());
value = Integer.parseInt(spinner.getValue().toString());
} else if (type.equals(short.class) || type.equals(Short.class)) {
value = Short.parseShort(getValue().toString());
value = Short.parseShort(spinner.getValue().toString());
} else if (type.equals(long.class) || type.equals(Long.class)) {
value = Long.parseLong(getValue().toString());
value = Long.parseLong(spinner.getValue().toString());
} else if (type.equals(double.class) || type.equals(Double.class)) {
value = Double.parseDouble(getValue().toString());
value = Double.parseDouble(spinner.getValue().toString());
} else if (type.equals(float.class) || type.equals(Float.class)) {
value = Float.parseFloat(getValue().toString());
value = Float.parseFloat(spinner.getValue().toString());
}
return value;
}
@@ -242,4 +264,9 @@ public class NumberEditor extends JSpinner implements GenericTagEditor {
public Object getObject() {
return obj;
}
@Override
public void setValueNormalizer(ValueNormalizer normalizer) {
this.normalizer = normalizer;
}
}

View File

@@ -151,4 +151,9 @@ public class StringEditor extends JTextArea implements GenericTagEditor {
public Object getObject() {
return obj;
}
@Override
public void setValueNormalizer(ValueNormalizer normalizer) {
}
}

View File

@@ -165,4 +165,9 @@ public class UUIDEditor extends JTextField implements GenericTagEditor {
public Object getObject() {
return obj;
}
@Override
public void setValueNormalizer(ValueNormalizer normalizer) {
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) 2025 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 <http://www.gnu.org/licenses/>.
*/
package com.jpexs.decompiler.flash.gui.generictageditors;
/**
*
* @author JPEXS
*/
public interface ValueNormalizer {
public Object toFieldValue(Object viewValue);
public Object toViewValue(Object fieldValue);
}

View File

@@ -121,7 +121,9 @@ property.document.backgroundColor = Background color
properties.instance.header.filters = Filters
properties.instance.filters.header.property = Property
properties.instance.filters.header.value = Value
property.instance.filters.header.property = Property
property.instance.filters.header.value = Value
properties.instance.filters.indeterminate = Indeterminate
property.instance.filters.indeterminate = Indeterminate
property.instance.filters = Filters

View File

@@ -99,7 +99,7 @@ public class JTreeTable extends JTable
// Install the tree editor renderer and editor.
setDefaultRenderer(TreeTableModel.class, tree);
setDefaultEditor(TreeTableModel.class, new TreeTableCellEditor());
// No grid.
setShowGrid(false);