Added: AS1/2 - hilight variables and errors on scrollbar

This commit is contained in:
Jindra Petřík
2025-05-28 20:41:46 +02:00
parent 479b61a7f1
commit bbeeef4fc5
5 changed files with 204 additions and 9 deletions

View File

@@ -21,6 +21,7 @@ All notable changes to this project will be documented in this file.
- AS1/2 - highlight variable definition and all its instances on cursor place
(also in edit mode)
- AS1/2 - underline errors in the code (also in edit mode)
- AS1/2 - highlight variables and errors on scrollbar
### Changed
- AS1/2 - Single DoAction tag inside frame is now displayed directly as frame node

View File

@@ -57,7 +57,6 @@ import com.jpexs.decompiler.flash.gui.ViewMessages;
import com.jpexs.decompiler.flash.gui.controls.JPersistentSplitPane;
import com.jpexs.decompiler.flash.gui.controls.NoneSelectedButtonGroup;
import com.jpexs.decompiler.flash.gui.editor.DebuggableEditorPane;
import com.jpexs.decompiler.flash.gui.editor.LinkHandler;
import com.jpexs.decompiler.flash.gui.tagtree.AbstractTagTreeModel;
import com.jpexs.decompiler.flash.helpers.HighlightedText;
import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter;
@@ -96,7 +95,6 @@ import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
@@ -111,7 +109,6 @@ import javax.swing.border.EmptyBorder;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Highlighter;
import javax.swing.text.JTextComponent;
import javax.swing.text.Utilities;
import javax.swing.tree.TreePath;
@@ -947,8 +944,11 @@ public class ActionPanel extends JPanel implements SearchListener<ScriptSearchRe
brokenHintPanel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED), new EmptyBorder(5, 5, 5, 5)));
panelWithHint.add(brokenHintPanel, BorderLayout.NORTH);
panelWithHint.add(new FasterScrollPane(decompiledEditor), BorderLayout.CENTER);
JPanel panelDecompiled = new JPanel(new BorderLayout(0, 0));
panelDecompiled.add(new FasterScrollPane(decompiledEditor), BorderLayout.CENTER);
panelWithHint.add(panelDecompiled, BorderLayout.CENTER);
brokenHintPanel.setVisible(false);
JPanel iconsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));

View File

@@ -23,7 +23,10 @@ import com.jpexs.decompiler.flash.action.parser.script.variables.ActionVariableP
import com.jpexs.decompiler.flash.gui.editor.DebuggableEditorPane;
import com.jpexs.decompiler.flash.gui.editor.LineMarkedEditorPane;
import com.jpexs.decompiler.flash.gui.editor.LinkHandler;
import com.jpexs.decompiler.flash.gui.editor.ScrollbarOverlay;
import com.jpexs.decompiler.flash.gui.editor.TrackRectSubstanceScrollbarUI;
import com.jpexs.decompiler.flash.gui.editor.WavyUnderLinePainter;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
@@ -38,12 +41,22 @@ import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JEditorPane;
import javax.swing.JLayer;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.plaf.ScrollBarUI;
import javax.swing.plaf.ScrollPaneUI;
import javax.swing.plaf.basic.BasicScrollPaneUI;
import javax.swing.text.BadLocationException;
import javax.swing.text.Highlighter;
import jsyntaxpane.SyntaxDocument;
@@ -53,6 +66,7 @@ import jsyntaxpane.actions.ActionUtils;
import jsyntaxpane.components.Markers;
import jsyntaxpane.components.SyntaxComponent;
import jsyntaxpane.util.Configuration;
import org.pushingpixels.substance.internal.ui.SubstanceScrollBarUI;
/**
* This class highlights Variable tokens of ActionScript 1/2
@@ -64,7 +78,10 @@ public class ActionVariableMarker implements SyntaxComponent, CaretListener, Pro
public static final String PROPERTY_ERRORCOLOR = "ActionVariableMarker.ErrorColor";
public static final String PROPERTY_TOKENTYPES = "ActionVariableMarker.TokenTypes";
private static final Color DEFAULT_COLOR = new Color(0xffeedd);
private static final Color DEFAULT_ERRORCOLOR = new Color(0xffaaaa);
private static final Color DEFAULT_ERRORCOLOR = new Color(0xff0000);
private static final Color SCROLLBAR_VARIABLE_COLOR = new Color(0xb59070);
private static final Color SCROLLBAR_ERROR_COLOR = new Color(0xff0000);
private JEditorPane pane;
private final Set<TokenType> tokenTypes = new HashSet<>();
private Markers.SimpleMarker marker;
@@ -81,6 +98,14 @@ public class ActionVariableMarker implements SyntaxComponent, CaretListener, Pro
private MouseMotionAdapter mouseMotionAdapter;
private JLayer<JScrollBar> layer;
private ScrollbarOverlay scrollbarOverlay;
private ScrollPaneUI originalScrollPaneUI;
private ScrollBarUI originalScrollBarUI;
/**
* Constructs a new Token highlighter
*/
@@ -106,6 +131,7 @@ public class ActionVariableMarker implements SyntaxComponent, CaretListener, Pro
if (token != null && tokenTypes.contains(token.type)) {
addMarkers(token);
}
layer.repaint();
}
}
@@ -114,11 +140,13 @@ public class ActionVariableMarker implements SyntaxComponent, CaretListener, Pro
*/
public void removeMarkers() {
Markers.removeMarkers(pane, marker);
scrollbarOverlay.removeMarkers(SCROLLBAR_VARIABLE_COLOR);
}
public void removeErrorMarkers() {
Markers.removeMarkers(pane, errorMarker);
errorsShown = false;
scrollbarOverlay.removeMarkers(SCROLLBAR_ERROR_COLOR);
}
private Token getIdentifierTokenAt(SyntaxDocument sDoc, int pos) {
@@ -173,8 +201,10 @@ public class ActionVariableMarker implements SyntaxComponent, CaretListener, Pro
Token token = getNearestTokenAt(doc, position);
if (token != null) {
Markers.markToken(pane, token, errorMarker);
markPositionOnScrollbar(position, SCROLLBAR_ERROR_COLOR);
}
}
layer.repaint();
doc.readUnlock();
errorsShown = true;
}
@@ -195,10 +225,12 @@ public class ActionVariableMarker implements SyntaxComponent, CaretListener, Pro
if (definitionToken != null) {
if (definitionPosToReferences.containsKey(definitionPos)) {
Markers.markToken(pane, definitionToken, marker);
markPositionOnScrollbar(definitionToken.start, SCROLLBAR_VARIABLE_COLOR);
for (int i : definitionPosToReferences.get(definitionPos)) {
Token referenceToken = getIdentifierTokenAt(sDoc, i);
if (referenceToken != null) {
Markers.markToken(pane, referenceToken, marker);
markPositionOnScrollbar(referenceToken.start, SCROLLBAR_VARIABLE_COLOR);
}
}
}
@@ -206,12 +238,20 @@ public class ActionVariableMarker implements SyntaxComponent, CaretListener, Pro
sDoc.readUnlock();
}
private void markPositionOnScrollbar(int position, Color color) {
try {
scrollbarOverlay.addMarker(ActionUtils.getLineNumber(pane, position), color);
} catch (BadLocationException ex) {
//ignore
}
}
@Override
public void config(Configuration config) {
Color markerColor = config.getColor(PROPERTY_COLOR, DEFAULT_COLOR);
Color errorColor = config.getColor(PROPERTY_ERRORCOLOR, DEFAULT_ERRORCOLOR);
this.marker = new Markers.SimpleMarker(markerColor);
this.errorMarker = new WavyUnderLinePainter(Color.red); //Markers.SimpleMarker(errorColor);
this.errorMarker = new WavyUnderLinePainter(errorColor); //Markers.SimpleMarker(errorColor);
String types = config.getString(
PROPERTY_TOKENTYPES, DEFAULT_TOKENTYPES);
@@ -236,8 +276,6 @@ public class ActionVariableMarker implements SyntaxComponent, CaretListener, Pro
if (editor instanceof LineMarkedEditorPane) {
((LineMarkedEditorPane) editor).setLinkHandler(this);
}
documentUpdated();
markTokenAt(editor.getCaretPosition());
mouseMotionAdapter = new MouseMotionAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
@@ -245,6 +283,28 @@ public class ActionVariableMarker implements SyntaxComponent, CaretListener, Pro
}
};
editor.addMouseMotionListener(mouseMotionAdapter);
JScrollPane scrollPane = (JScrollPane) SwingUtilities.getAncestorOfClass(JScrollPane.class, editor);
originalScrollPaneUI = scrollPane.getUI();
scrollPane.setUI(new BasicScrollPaneUI());
JScrollBar verticalScrollBar = scrollPane.getVerticalScrollBar();
originalScrollBarUI = verticalScrollBar.getUI();
if (originalScrollBarUI instanceof SubstanceScrollBarUI) {
verticalScrollBar.setUI(new TrackRectSubstanceScrollbarUI(verticalScrollBar));
}
scrollbarOverlay = new ScrollbarOverlay((LineMarkedEditorPane) pane);
layer = new JLayer<>(verticalScrollBar, scrollbarOverlay);
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
JPanel panel = (JPanel) SwingUtilities.getAncestorOfClass(JPanel.class, scrollPane);
panel.add(layer, BorderLayout.EAST);
documentUpdated();
markTokenAt(editor.getCaretPosition());
status = Status.INSTALLING;
}
@@ -278,6 +338,14 @@ public class ActionVariableMarker implements SyntaxComponent, CaretListener, Pro
if (editor instanceof LineMarkedEditorPane) {
((LineMarkedEditorPane) editor).setLinkHandler(null);
}
JScrollPane scrollPane = (JScrollPane) SwingUtilities.getAncestorOfClass(JScrollPane.class, editor);
JPanel panel = (JPanel) SwingUtilities.getAncestorOfClass(JPanel.class, scrollPane);
panel.remove(layer);
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
panel.revalidate();
panel.repaint();
scrollPane.setUI(originalScrollPaneUI);
scrollPane.getVerticalScrollBar().setUI(originalScrollBarUI);
}
private static final Logger LOG = Logger.getLogger(ActionVariableMarker.class.getName());
@@ -299,6 +367,7 @@ public class ActionVariableMarker implements SyntaxComponent, CaretListener, Pro
private void documentUpdated() {
errors.clear();
removeErrorMarkers();
layer.repaint();
try {
SyntaxDocument sDoc = (SyntaxDocument) pane.getDocument();

View File

@@ -0,0 +1,89 @@
/*
* 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.editor;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import javax.swing.JComponent;
import javax.swing.JLayer;
import javax.swing.JScrollBar;
import javax.swing.plaf.LayerUI;
import javax.swing.plaf.ScrollBarUI;
import jsyntaxpane.actions.ActionUtils;
/**
*
* @author JPEXS
*/
public class ScrollbarOverlay extends LayerUI<JScrollBar> {
private final LineMarkedEditorPane editorPane;
private final Map<Integer, Color> markedLines = new LinkedHashMap<>();
public ScrollbarOverlay(LineMarkedEditorPane editorPane) {
this.editorPane = editorPane;
}
public void removeMarkers(Color color) {
Set<Integer> lines = new HashSet<>(markedLines.keySet());
for (int key : lines) {
if (markedLines.get(key).equals(color)) {
markedLines.remove(key);
}
}
}
public void clearMarkers() {
markedLines.clear();
}
public void addMarker(int line, Color color) {
markedLines.put(line, color);
}
public void setMarkedLines(Map<Integer, Color> markedLines) {
this.markedLines.clear();
this.markedLines.putAll(markedLines);
}
@Override
public void paint(Graphics g, JComponent c) {
super.paint(g, c);
JScrollBar bar = (JScrollBar) ((JLayer<?>) c).getView();
ScrollBarUI ui = bar.getUI();
Rectangle r;
if (ui instanceof TrackRectSubstanceScrollbarUI) {
r = ((TrackRectSubstanceScrollbarUI) ui).getTrackBounds();
} else {
r = new Rectangle(0, 16, 16, bar.getHeight() - 32);
}
int totalLineCount = ActionUtils.getLineCount(editorPane);
for (Map.Entry<Integer, Color> entry : markedLines.entrySet()) {
g.setColor(entry.getValue());
float ratio = (float) entry.getKey() / totalLineCount;
int y = r.y + (int) (ratio * r.height);
g.drawLine(0, y, bar.getWidth(), y);
}
}
}

View File

@@ -0,0 +1,36 @@
/*
* 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.editor;
import java.awt.Rectangle;
import javax.swing.JComponent;
import org.pushingpixels.substance.internal.ui.SubstanceScrollBarUI;
/**
*
* @author JPEXS
*/
public class TrackRectSubstanceScrollbarUI extends SubstanceScrollBarUI {
public TrackRectSubstanceScrollbarUI(JComponent b) {
super(b);
}
@Override
public Rectangle getTrackBounds() {
return super.getTrackBounds();
}
}