diff --git a/CHANGELOG.md b/CHANGELOG.md index c3451c7f4..368632ab3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file. - [#2448] Simple editor - Option to turn off half transparent parent layers - Localized "Open with FFDec" context menu (switch association off/on to apply if already installed) - [#2370] Objects display - Option to show horizontal and vertical rulers +- [#2370] Objects display - Create guides by dragging from a ruler ### Fixed - [#2424] DefineEditText handling of letterSpacing, font size on incorrect values diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/CustomConfigurationKeys.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/CustomConfigurationKeys.java index d3fb6bac5..6e91b926e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/CustomConfigurationKeys.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/CustomConfigurationKeys.java @@ -31,4 +31,5 @@ public class CustomConfigurationKeys { public static final String KEY_ABC_DEPENDENCIES = "abcDependencies"; public static final String KEY_BREAKPOINTS = "breakpoints"; public static final String KEY_PATH_RESOLVING = "pathResolving"; + public static final String KEY_GUIDES = "guides"; } diff --git a/src/com/jpexs/decompiler/flash/easygui/EasySwfPanel.java b/src/com/jpexs/decompiler/flash/easygui/EasySwfPanel.java index 64371ee7e..146ffe35e 100644 --- a/src/com/jpexs/decompiler/flash/easygui/EasySwfPanel.java +++ b/src/com/jpexs/decompiler/flash/easygui/EasySwfPanel.java @@ -580,6 +580,11 @@ public class EasySwfPanel extends JPanel { libraryPreviewPanel.clearAll(); if (updateStage) { stagePanel.setTimelined(timelined, swf, 0, true, true, true, true, true, false, true, true, true); + if (timelined instanceof CharacterTag) { + stagePanel.setGuidesCharacter(swf, ((CharacterTag) timelined).getCharacterId()); + } else { + stagePanel.setGuidesCharacter(swf, -1); + } stagePanel.pause(); stagePanel.gotoFrame(0); } diff --git a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java index e6a6521dd..e929bae70 100644 --- a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java +++ b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java @@ -23,6 +23,8 @@ import com.jpexs.decompiler.flash.action.LocalDataArea; import com.jpexs.decompiler.flash.action.Stage; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.configuration.ConfigurationItemChangeListener; +import com.jpexs.decompiler.flash.configuration.CustomConfigurationKeys; +import com.jpexs.decompiler.flash.configuration.SwfSpecificCustomConfiguration; import com.jpexs.decompiler.flash.ecma.Undefined; import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle; import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; @@ -62,6 +64,7 @@ import java.awt.AlphaComposite; import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; +import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; import java.awt.FlowLayout; @@ -95,6 +98,7 @@ import java.awt.event.MouseListener; import java.awt.event.MouseMotionAdapter; import java.awt.event.MouseMotionListener; import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; import java.awt.geom.GeneralPath; @@ -106,6 +110,7 @@ import java.io.IOException; import java.text.DecimalFormat; import java.text.ParseException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.Map; @@ -338,8 +343,32 @@ public final class ImagePanel extends JPanel implements MediaDisplay { private JPanel leftRuler; + private boolean draggingYGuide = false; + + private boolean draggingXGuide = false; + + private int guideDragX = -1; + + private int guideDragY = -1; + private boolean contentCanHaveRuler = false; + private List guidesX = new ArrayList<>(); + + private List guidesY = new ArrayList<>(); + + private static final Color GUIDES_COLOR = Color.green; + + private static final int GUIDE_THICKNESS = 20; + + private static final int GUIDE_FONT_HEIGHT = 11; + + private static final int GUIDE_TEXT_OFFSET = 10; + + private SWF guidesSwf = null; + + private int guidesCharacterId = -1; + public void setFrozenButtons(boolean frozenButtons) { this.frozenButtons = frozenButtons; } @@ -1100,6 +1129,40 @@ public final class ImagePanel extends JPanel implements MediaDisplay { private boolean shiftDown = false; + private List mouseMotionListeners = new ArrayList<>(); + private List mouseListeners = new ArrayList<>(); + private List mouseWheelListeners = new ArrayList<>(); + + @Override + public synchronized void addMouseMotionListener(MouseMotionListener l) { + mouseMotionListeners.add(l); + } + + @Override + public synchronized void removeMouseMotionListener(MouseMotionListener l) { + mouseMotionListeners.remove(l); + } + + @Override + public synchronized void addMouseListener(MouseListener l) { + mouseListeners.add(l); + } + + @Override + public synchronized void removeMouseListener(MouseListener l) { + mouseListeners.remove(l); + } + + @Override + public synchronized void addMouseWheelListener(MouseWheelListener l) { + mouseWheelListeners.add(l); + } + + @Override + public synchronized void removeMouseWheelListener(MouseWheelListener l) { + mouseWheelListeners.remove(l); + } + public boolean isAltDown() { return altDown; } @@ -1286,7 +1349,34 @@ public final class ImagePanel extends JPanel implements MediaDisplay { } } - mouseMoved(e); //to correctly calculate mode, because mouseMoved event is not called during dragging + int guideTolerance = 2; + + Point mousePoint = e.getPoint(); + for (int d = 0; d < guidesX.size(); d++) { + Double guide = guidesX.get(d); + int guideInPanel = (int) Math.round(guide * getRealZoom() + offsetPoint.getX()); + if (mousePoint.x >= guideInPanel - guideTolerance && mousePoint.x <= guideInPanel + guideTolerance) { + guidesX.remove(d); + guideDragX = guideInPanel; + draggingXGuide = true; + saveGuides(); + return; + } + } + + for (int d = 0; d < guidesY.size(); d++) { + Double guide = guidesY.get(d); + int guideInPanel = (int) Math.round(guide * getRealZoom() + offsetPoint.getY()); + if (mousePoint.y >= guideInPanel - guideTolerance && mousePoint.y <= guideInPanel + guideTolerance) { + guidesY.remove(d); + guideDragY = guideInPanel; + draggingYGuide = true; + saveGuides(); + return; + } + } + + mouseMoved(e); //to correctly calculate mode, because mouseMoved event is not called during dragging setDragStart(e.getPoint()); if (!shiftDown) { @@ -1323,6 +1413,11 @@ public final class ImagePanel extends JPanel implements MediaDisplay { public void mouseReleased(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e)) { + if (draggingXGuide || draggingYGuide) { + draggingXGuide = false; + draggingYGuide = false; + } + if (hilightedPoints != null) { Rectangle2D selectionRect = getSelectionRect(); if (selectionRect != null) { @@ -2379,6 +2474,25 @@ public final class ImagePanel extends JPanel implements MediaDisplay { } } + g2d.setColor(GUIDES_COLOR); + if (draggingXGuide && lastMouseEvent != null) { + g2d.drawLine(guideDragX, 0, guideDragX, getHeight()); + } + + if (draggingYGuide && lastMouseEvent != null) { + g2d.drawLine(0, guideDragY, getWidth(), guideDragY); + } + + for (Double guide : guidesX) { + int guideRealPx = (int) Math.round(offsetPoint.getX() + guide * getRealZoom()); + g2d.drawLine(guideRealPx, 0, guideRealPx, getHeight()); + } + + for (Double guide : guidesY) { + int guideRealPx = (int) Math.round(offsetPoint.getY() + guide * getRealZoom()); + g2d.drawLine(0, guideRealPx, getWidth(), guideRealPx); + } + if (Configuration._debugMode.get()) { g2d.setColor(Color.red); DecimalFormat df = new DecimalFormat(); @@ -2507,13 +2621,176 @@ public final class ImagePanel extends JPanel implements MediaDisplay { public ImagePanel() { super(new BorderLayout()); - //iconPanel.setHorizontalAlignment(JLabel.CENTER); + JPanel p = new JPanel(); + add(p, BorderLayout.CENTER); + + //This is a bit hack so we can drag guides from rulers to iconPanel + MouseInputAdapter mouseInputAdapter = new MouseInputAdapter() { + + private MouseEvent convertMouseEvent(MouseEvent originalEvent, Component newSourceComponent) { + Point newPoint = SwingUtilities.convertPoint( + originalEvent.getComponent(), + originalEvent.getPoint(), + newSourceComponent + ); + + return new MouseEvent( + newSourceComponent, + originalEvent.getID(), + originalEvent.getWhen(), + originalEvent.getModifiersEx(), + newPoint.x, + newPoint.y, + originalEvent.getClickCount(), + originalEvent.isPopupTrigger(), + originalEvent.getButton() + ); + } + + private MouseWheelEvent convertMouseWheelEvent(MouseWheelEvent originalEvent, Component newSourceComponent) { + Point newPoint = SwingUtilities.convertPoint( + originalEvent.getComponent(), + originalEvent.getPoint(), + newSourceComponent + ); + + return new MouseWheelEvent( + newSourceComponent, + originalEvent.getID(), + originalEvent.getWhen(), + originalEvent.getModifiersEx(), + newPoint.x, + newPoint.y, + originalEvent.getClickCount(), + originalEvent.isPopupTrigger(), + originalEvent.getScrollType(), + originalEvent.getScrollAmount(), + originalEvent.getWheelRotation() + ); + } + + @Override + public void mouseClicked(MouseEvent e) { + Component c = SwingUtilities.getDeepestComponentAt(ImagePanel.this, e.getX(), e.getY()); + if (c != iconPanel) { + return; + } + for (MouseListener l : iconPanel.mouseListeners) { + l.mouseClicked(convertMouseEvent(e, iconPanel)); + } + } + + @Override + public void mouseDragged(MouseEvent e) { + Component c = SwingUtilities.getDeepestComponentAt(ImagePanel.this, e.getX(), e.getY()); + if (c != iconPanel) { + return; + } + for (MouseMotionListener l : iconPanel.mouseMotionListeners) { + l.mouseDragged(convertMouseEvent(e, iconPanel)); + } + } + + @Override + public void mouseEntered(MouseEvent e) { + Component c = SwingUtilities.getDeepestComponentAt(ImagePanel.this, e.getX(), e.getY()); + if (c != iconPanel) { + return; + } + for (MouseListener l : iconPanel.mouseListeners) { + l.mouseEntered(convertMouseEvent(e, iconPanel)); + } + } + + @Override + public void mouseExited(MouseEvent e) { + Component c = SwingUtilities.getDeepestComponentAt(ImagePanel.this, e.getX(), e.getY()); + if (c != iconPanel) { + return; + } + for (MouseListener l : iconPanel.mouseListeners) { + l.mouseExited(convertMouseEvent(e, iconPanel)); + } + } + + @Override + public void mouseMoved(MouseEvent e) { + Component c = SwingUtilities.getDeepestComponentAt(ImagePanel.this, e.getX(), e.getY()); + if (c != iconPanel) { + return; + } + for (MouseMotionListener l : iconPanel.mouseMotionListeners) { + l.mouseMoved(convertMouseEvent(e, iconPanel)); + } + } + + @Override + public void mousePressed(MouseEvent e) { + Component c = SwingUtilities.getDeepestComponentAt(ImagePanel.this, e.getX(), e.getY()); + if (c == topRuler) { + draggingYGuide = true; + guideDragY = -1; + } else if (c == leftRuler) { + draggingXGuide = true; + guideDragX = -1; + } else if (c == iconPanel) { + for (MouseListener l : iconPanel.mouseListeners) { + l.mousePressed(convertMouseEvent(e, iconPanel)); + } + } + } + + @Override + public void mouseReleased(MouseEvent e) { + + Component c = SwingUtilities.getDeepestComponentAt(ImagePanel.this, e.getX(), e.getY()); + + if (c == iconPanel) { + if (draggingXGuide && guideDragX > 0) { + double guide = (guideDragX - offsetPoint.getX()) / getRealZoom(); + guidesX.add(guide); + saveGuides(); + } + if (draggingYGuide && guideDragY > 0) { + double guide = (guideDragY - offsetPoint.getY()) / getRealZoom(); + guidesY.add(guide); + saveGuides(); + } + } + + draggingXGuide = false; + draggingYGuide = false; + guideDragX = -1; + guideDragY = -1; + + if (c != iconPanel) { + return; + } + for (MouseListener l : iconPanel.mouseListeners) { + l.mouseReleased(convertMouseEvent(e, iconPanel)); + } + } + + @Override + public void mouseWheelMoved(MouseWheelEvent e) { + Component c = SwingUtilities.getDeepestComponentAt(ImagePanel.this, e.getX(), e.getY()); + if (c != iconPanel) { + return; + } + for (MouseWheelListener l : iconPanel.mouseWheelListeners) { + l.mouseWheelMoved(convertMouseWheelEvent(e, iconPanel)); + } + } + }; + super.addMouseListener(mouseInputAdapter); + super.addMouseMotionListener(mouseInputAdapter); + super.addMouseWheelListener(mouseInputAdapter); + setOpaque(true); setBackground(View.getDefaultBackgroundColor()); loop = true; iconPanel = new IconPanel(); - //labelPan.add(label, new GridBagConstraints()); add(iconPanel, BorderLayout.CENTER); topPanel = new JPanel(); @@ -2564,9 +2841,9 @@ public final class ImagePanel extends JPanel implements MediaDisplay { } double fullLineDistance = fullLinePixels * z; - double leftOffset = 25; + double leftOffset = GUIDE_THICKNESS; Graphics2D g2 = (Graphics2D) g; - g2.setFont(new Font("Monospaced", Font.PLAIN, 12)); + g2.setFont(new Font("Monospaced", Font.PLAIN, GUIDE_FONT_HEIGHT)); GeneralPath gp = new GeneralPath(); double minX = leftOffset + offsetPoint.getX(); @@ -2583,34 +2860,40 @@ public final class ImagePanel extends JPanel implements MediaDisplay { int smallerLineLength = 2; int k = 0; for (double i = 0; i < fullLineDistance; i += fullLineDistance / 10.0, k++) { - gp.moveTo(x + i, 25); - gp.lineTo(x + i, 25 - (k % 2 == 0 ? smallLineLength : smallerLineLength)); + gp.moveTo(x + i, GUIDE_THICKNESS); + gp.lineTo(x + i, GUIDE_THICKNESS - (k % 2 == 0 ? smallLineLength : smallerLineLength)); } - g2.drawString("" + px, (int) x + 5, 15); + g2.drawString("" + px, (int) x + 5, GUIDE_THICKNESS - GUIDE_TEXT_OFFSET); } g2.setStroke(new BasicStroke(1, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL)); g2.draw(gp); - if (lastMouseEvent != null) { - int triangleX = lastMouseEvent.getX() + 25; + if (guideDragX == -1 && lastMouseEvent != null) { + int triangleX = lastMouseEvent.getX() + GUIDE_THICKNESS; int triangleHalfWidth = 3; int triangleHeight = 3; int triangleYOffset = 3; Polygon triangle = new Polygon( new int[]{triangleX - triangleHalfWidth, triangleX + triangleHalfWidth, triangleX}, - new int[]{25 - triangleHeight - triangleYOffset, 25 - triangleHeight - triangleYOffset, 25 - triangleYOffset}, + new int[]{GUIDE_THICKNESS - triangleHeight - triangleYOffset, GUIDE_THICKNESS - triangleHeight - triangleYOffset, GUIDE_THICKNESS - triangleYOffset}, 3); g2.setPaint(getForeground()); g2.fill(triangle); } g2.setPaint(getBackground()); - g2.fillRect(0, 0, 25, 25); + g2.fillRect(0, 0, GUIDE_THICKNESS, GUIDE_THICKNESS); + + if (guideDragX > -1) { + g2.setColor(GUIDES_COLOR); + g2.drawLine(GUIDE_THICKNESS + guideDragX, 0, GUIDE_THICKNESS + guideDragX, GUIDE_THICKNESS); + } + } }; - topRuler.setPreferredSize(new Dimension(1, 25)); + topRuler.setPreferredSize(new Dimension(1, GUIDE_THICKNESS)); topPanel.add(topRuler); leftRuler = new JPanel() { @@ -2627,7 +2910,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay { double fullLineDistance = fullLinePixels * z; double topOffset = 0; Graphics2D g2 = (Graphics2D) g; - g2.setFont(new Font("Monospaced", Font.PLAIN, 12)); + g2.setFont(new Font("Monospaced", Font.PLAIN, GUIDE_FONT_HEIGHT)); GeneralPath gp = new GeneralPath(); double minY = topOffset + offsetPoint.getY(); @@ -2646,28 +2929,28 @@ public final class ImagePanel extends JPanel implements MediaDisplay { int smallerLineLength = 2; int k = 0; for (double i = 0; i < fullLineDistance; i += fullLineDistance / 10.0, k++) { - gp.moveTo(25, y + i); - gp.lineTo(25 - (k % 2 == 0 ? smallLineLength : smallerLineLength), y + i); + gp.moveTo(GUIDE_THICKNESS, y + i); + gp.lineTo(GUIDE_THICKNESS - (k % 2 == 0 ? smallLineLength : smallerLineLength), y + i); } g2.setTransform(origTransform); String drawnString = "" + py; int stringWidth = g2.getFontMetrics().stringWidth(drawnString); AffineTransform fontTrans = new AffineTransform(); - fontTrans.rotate(-Math.PI / 2, 15, 15); + fontTrans.rotate(-Math.PI / 2, GUIDE_THICKNESS - GUIDE_TEXT_OFFSET, GUIDE_THICKNESS - GUIDE_TEXT_OFFSET); g2.transform(fontTrans); - g2.drawString(drawnString, 15 - stringWidth + 15 - 5 - Math.round(y), 15); + g2.drawString(drawnString, GUIDE_THICKNESS - stringWidth - Math.round(y) - 5, GUIDE_THICKNESS - GUIDE_TEXT_OFFSET); } g2.setTransform(origTransform); - if (lastMouseEvent != null) { + if (guideDragY == -1 && lastMouseEvent != null) { int triangleY = lastMouseEvent.getY(); int triangleHalfHeight = 3; int triangleWidth = 3; int triangleXOffset = 3; Polygon triangle = new Polygon( - new int[]{25 - triangleWidth - triangleXOffset, 25 - triangleWidth - triangleXOffset, 25 - triangleXOffset}, + new int[]{GUIDE_THICKNESS - triangleWidth - triangleXOffset, GUIDE_THICKNESS - triangleWidth - triangleXOffset, GUIDE_THICKNESS - triangleXOffset}, new int[]{triangleY - triangleHalfHeight, triangleY + triangleHalfHeight, triangleY}, 3); g2.setPaint(getForeground()); @@ -2676,11 +2959,37 @@ public final class ImagePanel extends JPanel implements MediaDisplay { g2.setStroke(new BasicStroke(1, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL)); g2.draw(gp); + + if (guideDragY > -1) { + g2.setColor(GUIDES_COLOR); + g2.drawLine(0, guideDragY, GUIDE_THICKNESS, guideDragY); + } } }; - leftRuler.setPreferredSize(new Dimension(25, 1)); + leftRuler.setPreferredSize(new Dimension(GUIDE_THICKNESS, 1)); add(leftRuler, BorderLayout.WEST); + super.addMouseMotionListener(new MouseAdapter() { + @Override + public void mouseDragged(MouseEvent e) { + if (SwingUtilities.isLeftMouseButton(e)) { + if (!draggingXGuide && !draggingYGuide) { + return; + } + if (iconPanel == SwingUtilities.getDeepestComponentAt(ImagePanel.this, e.getX(), e.getY())) { + Point p = SwingUtilities.convertPoint(ImagePanel.this, e.getX(), e.getY(), iconPanel); + if (draggingXGuide) { + guideDragX = p.x; + } + if (draggingYGuide) { + guideDragY = p.y; + } + iconPanel.repaint(); + } + } + } + }); + pointEditPanel.setVisible(false); add(topPanel, BorderLayout.NORTH); @@ -2838,6 +3147,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay { } } }); + //*/ } private synchronized void redraw() { @@ -3213,6 +3523,9 @@ public final class ImagePanel extends JPanel implements MediaDisplay { this.registrationPointPosition = RegistrationPointPosition.CENTER; iconPanel.calcRect(); + clearGuides(); + setNoGuidesCharacter(); + contentCanHaveRuler = canHaveRuler; updateRulerVisibility(); redraw(); @@ -3238,6 +3551,136 @@ public final class ImagePanel extends JPanel implements MediaDisplay { fireMediaDisplayStateChanged(); } + public synchronized void clearGuides() { + draggingXGuide = false; + draggingYGuide = false; + guideDragX = -1; + guideDragY = -1; + guidesX.clear(); + guidesY.clear(); + } + + public synchronized void addGuideX(double guidePixels) { + guidesX.add(guidePixels); + repaint(); + } + + public synchronized void addGuideY(double guidePixels) { + guidesY.add(guidePixels); + repaint(); + } + + public synchronized void setNoGuidesCharacter() { + guidesSwf = null; + guidesCharacterId = -1; + } + + public synchronized void setGuidesCharacter(SWF swf, int characterId) { + guidesSwf = swf; + guidesCharacterId = characterId; + loadGuidesCharacter(); + } + + private synchronized void loadGuidesCharacter() { + clearGuides(); + if (guidesSwf == null) { + return; + } + SwfSpecificCustomConfiguration conf = Configuration.getSwfSpecificCustomConfiguration(guidesSwf.getShortPathTitle()); + if (conf == null) { + return; + } + String guides = conf.getCustomData(CustomConfigurationKeys.KEY_GUIDES, ""); + if (guides.isEmpty()) { + return; + } + List parts = new ArrayList<>(); + if (!guides.isEmpty()) { + String[] partsArr = guides.split("\\|", -1); + parts = new ArrayList<>(Arrays.asList(partsArr)); + } + for (String part : parts) { + if (part.startsWith("" + guidesCharacterId + ":")) { + part = part.substring(part.indexOf(":") + 1); + String[] xy = part.split(";", -1); + String[] xArr = xy[0].split(",", -1); + String[] yArr = xy[1].split(",", -1); + + try { + if (!xy[0].isEmpty()) { + for (String x : xArr) { + guidesX.add(Double.parseDouble(x)); + } + } + if (!xy[1].isEmpty()) { + for (String y : yArr) { + guidesY.add(Double.parseDouble(y)); + } + } + } catch (NumberFormatException nfe) { + Logger.getLogger(ImagePanel.class.getName()).warning("Invalid configuration of guides. Cannot load."); + } + return; + } + } + } + + private synchronized void saveGuides() { + if (guidesSwf == null) { + return; + } + SwfSpecificCustomConfiguration conf = Configuration.getOrCreateSwfSpecificCustomConfiguration(guidesSwf.getShortPathTitle()); + String previous = conf.getCustomData(CustomConfigurationKeys.KEY_GUIDES, ""); + + //Format: character1:x1,x2,x3,x4;y1,y2|character2:... + List parts = new ArrayList<>(); + if (!previous.isEmpty()) { + String[] partsArr = previous.split("\\|", -1); + parts = new ArrayList<>(Arrays.asList(partsArr)); + } + + StringBuilder sb = new StringBuilder(); + sb.append(guidesCharacterId); + sb.append(":"); + boolean first = true; + for (Double guide : guidesX) { + if (!first) { + sb.append(","); + } + sb.append(guide); + first = false; + } + sb.append(";"); + first = true; + for (Double guide : guidesY) { + if (!first) { + sb.append(","); + } + sb.append(guide); + first = false; + } + String guidesStr = sb.toString(); + + for (int i = 0; i < parts.size(); i++) { + if (parts.get(i).startsWith("" + guidesCharacterId + ":")) { + parts.remove(i); + i--; + continue; + } + String part = parts.get(0); + String noChar = part.substring(part.indexOf(":") + 1); + if (";".equals(noChar)) { + parts.remove(i); + i--; + } + } + if (!("" + guidesCharacterId + ":;").equals(guidesStr)) { + parts.add(guidesStr); + } + + conf.setCustomData(CustomConfigurationKeys.KEY_GUIDES, String.join("|", parts)); + } + public synchronized void setImage(SerializableImage image) { lda = null; setBackground(View.getSwfBackgroundColor()); @@ -3256,6 +3699,9 @@ public final class ImagePanel extends JPanel implements MediaDisplay { horizontalScrollBar.setVisible(false); verticalScrollBar.setVisible(false); + clearGuides(); + setNoGuidesCharacter(); + contentCanHaveRuler = false; updateRulerVisibility(); fireMediaDisplayStateChanged(); @@ -4156,6 +4602,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay { clearImagePanel(); timelined = null; swf = null; + guidesSwf = null; lda = null; showObjectsUnderCursor = false; fireMediaDisplayStateChanged(); diff --git a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java index 6865ef637..56caa9634 100644 --- a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java @@ -344,7 +344,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel private JPersistentSplitPane displayEditTransformSplitPane; private JPersistentSplitPane imageTransformSplitPane; - + private DocumentListener cookieDocumentListener; public void setReadOnly(boolean readOnly) { @@ -753,7 +753,6 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel cookieFilenameField = new JTextField(30); amfVersionLabel = new JLabel(); cookieEditor = new LineMarkedEditorPane(); - JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); topPanel.add(new JLabel(AppStrings.translate(SolEditorFrame.class, "filename"))); @@ -764,7 +763,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel cookieCard.add(topPanel, BorderLayout.NORTH); cookieCard.add(new FasterScrollPane(cookieEditor), BorderLayout.CENTER); cookieCard.add(createCookieButtonsPanel(), BorderLayout.SOUTH); - + cookieEditor.setContentType("text/javascript"); cookieDocumentListener = new DocumentListener() { @@ -782,8 +781,8 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel public void changedUpdate(DocumentEvent e) { setCookieModified(true); } - - }; + + }; return cookieCard; } @@ -1700,6 +1699,13 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel imageTransformSaveButton.setVisible(false); imageTransformCancelButton.setVisible(false); imagePanel.setTimelined(timelined, swf, frame, showObjectsUnderCursor, autoPlay, frozen, alwaysDisplay, muted, mutable, allowZoom, frozenButtons, canHaveRuler); + if (canHaveRuler) { + if (timelined instanceof Tag) { + imagePanel.setGuidesCharacter(swf, ((CharacterTag) timelined).getCharacterId()); + } else { + imagePanel.setGuidesCharacter(swf, -1); + } + } } public void showImagePanel(SerializableImage image) { @@ -2029,15 +2035,24 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel if (tag instanceof ShapeTag) { Timelined tim = TimelinedMaker.makeTimelined(tag); displayEditImagePanel.setTimelined(tim, ((Tag) tag).getSwf(), 0, true, Configuration.autoPlayPreviews.get(), !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), false, true, true, true); + displayEditImagePanel.setGuidesCharacter(tag.getSwf(), ((CharacterTag) tag).getCharacterId()); } if (tag instanceof MorphShapeTag) { Timelined tim = TimelinedMaker.makeTimelined(tag); displayEditImagePanel.setTimelined(tim, ((Tag) tag).getSwf(), -1, true, Configuration.autoPlayPreviews.get(), !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), false, true, true, true); + displayEditImagePanel.setGuidesCharacter(tag.getSwf(), ((CharacterTag) tag).getCharacterId()); morphDisplayMode = MORPH_ANIMATE; displayEditShowAnimationButton.setSelected(true); } if (tag instanceof PlaceObjectTypeTag) { displayEditImagePanel.setTimelined(((Tag) tag).getTimelined(), ((Tag) tag).getSwf(), frame, true, Configuration.autoPlayPreviews.get(), !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), true, true, true, true); + Timelined tim = ((Tag) tag).getTimelined(); + if (tim instanceof Tag) { + displayEditImagePanel.setGuidesCharacter(tag.getSwf(), ((CharacterTag) tim).getCharacterId()); + } else { + displayEditImagePanel.setGuidesCharacter(tag.getSwf(), -1); + } + PlaceObjectTypeTag place = (PlaceObjectTypeTag) tag; displayEditImagePanel.selectDepth(place.getDepth()); } @@ -2719,18 +2734,21 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel morphDisplayMode = MORPH_ANIMATE; Timelined tim = TimelinedMaker.makeTimelined(displayEditTag); displayEditImagePanel.setTimelined(tim, displayEditTag.getSwf(), -1, true, Configuration.autoPlayPreviews.get(), !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), false, true, true, true); + displayEditImagePanel.setGuidesCharacter(displayEditTag.getSwf(), ((CharacterTag) displayEditTag).getCharacterId()); } private void showStartDisplayEditTagButtonActionPerformed(ActionEvent evt) { morphDisplayMode = MORPH_START; Timelined tim = TimelinedMaker.makeTimelined(displayEditTag); displayEditImagePanel.setTimelined(tim, displayEditTag.getSwf(), 0, true, Configuration.autoPlayPreviews.get(), !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), false, true, true, true); + displayEditImagePanel.setGuidesCharacter(displayEditTag.getSwf(), ((CharacterTag) displayEditTag).getCharacterId()); } private void showEndDisplayEditTagButtonActionPerformed(ActionEvent evt) { morphDisplayMode = MORPH_END; Timelined tim = TimelinedMaker.makeTimelined(displayEditTag); displayEditImagePanel.setTimelined(tim, displayEditTag.getSwf(), tim.getFrameCount() - 1, true, Configuration.autoPlayPreviews.get(), !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), false, true, true, true); + displayEditImagePanel.setGuidesCharacter(displayEditTag.getSwf(), ((CharacterTag) displayEditTag).getCharacterId()); } private void editPointsDisplayEditTagButtonActionPerformed(ActionEvent evt) { @@ -2745,7 +2763,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel replaceShapeUpdateBoundsButton.setVisible(false); replaceMorphShapeUpdateBoundsButton.setVisible(false); displayEditEditPointsButton.setVisible(false); - + displayEditSaveButton.setEnabled(true); displayEditCancelButton.setEnabled(true); @@ -3076,6 +3094,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel }; imagePanel.setTimelined(tim, origSwf, 0, true, true, true, true, true, false, true, true, true); + imagePanel.setGuidesCharacter(displayedCharacter.getSwf(), ((CharacterTag) displayedCharacter).getCharacterId()); imagePanel.selectDepth(-1); replaceSpriteButton.setVisible(false);