diff --git a/src/main/java/pixelitor/Canvas.java b/src/main/java/pixelitor/Canvas.java index d44732f8f..3e1a68749 100644 --- a/src/main/java/pixelitor/Canvas.java +++ b/src/main/java/pixelitor/Canvas.java @@ -68,12 +68,12 @@ public Canvas(Canvas orig) { /** * Changes the size with values given in image space */ - public void changeSize(int newWidth, int newHeight, View view) { + public void changeSize(int newWidth, int newHeight, View view, boolean notify) { width = newWidth; height = newHeight; // also update the component space values - recalcCoSize(view); + recalcCoSize(view, notify); activeCanvasSizeChanged(this); } @@ -81,12 +81,18 @@ public void changeSize(int newWidth, int newHeight, View view) { /** * Recalculates the component-space (zoomed) size */ - public void recalcCoSize(View view) { + public void recalcCoSize(View view, boolean notify) { double viewScale = view.getScaling(); + + int oldZoomedWidth = zoomedWidth; + int oldZoomedHeight = zoomedHeight; + zoomedWidth = (int) (viewScale * width); zoomedHeight = (int) (viewScale * height); - view.canvasCoSizeChanged(); + if (notify && (zoomedWidth != oldZoomedWidth || zoomedHeight != oldZoomedHeight)) { + view.canvasCoSizeChanged(); + } } /** diff --git a/src/main/java/pixelitor/Composition.java b/src/main/java/pixelitor/Composition.java index f54e21f15..9b41d9a60 100644 --- a/src/main/java/pixelitor/Composition.java +++ b/src/main/java/pixelitor/Composition.java @@ -22,6 +22,7 @@ import pixelitor.gui.PixelitorWindow; import pixelitor.gui.View; import pixelitor.gui.utils.Dialogs; +import pixelitor.gui.utils.ImagePreviewPanel; import pixelitor.guides.Guides; import pixelitor.guides.GuidesChangeEdit; import pixelitor.history.*; @@ -74,6 +75,8 @@ public class Composition implements Serializable { @Serial private static final long serialVersionUID = 1L; + private static long debugCounter = 0; + private String name; private final List layerList = new ArrayList<>(); @@ -90,6 +93,10 @@ public class Composition implements Serializable { // // transient variables from here // + + // useful for distinguishing between versions with the same name + private transient String debugName; + private transient File file; private transient boolean dirty = false; @@ -140,6 +147,7 @@ public static Composition fromImage(BufferedImage img, File file, String name) { // one of the file and name arguments must be given throw new IllegalArgumentException("no name could be set"); } + comp.createDebugName(); assert comp.getName() != null; return comp; } @@ -194,6 +202,7 @@ public Composition copy(boolean forUndo, boolean copySelection) { compCopy.guides = guides.copyForNewComp(view); } } + compCopy.createDebugName(); assert compCopy.checkInvariant(); @@ -211,6 +220,7 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE // init transient variables compositeImage = null; // will be set when needed file = null; // will be set later + debugName = null; // will be set later dirty = false; view = null; // will be set later selection = null; // the selection is not saved @@ -226,7 +236,7 @@ public View getView() { public void setView(View view) { this.view = view; if (view != null) { - canvas.recalcCoSize(view); + canvas.recalcCoSize(view, true); } if (selection != null) { // can happen when duplicating @@ -283,6 +293,15 @@ public void setName(String name) { } } + public String getDebugName() { + return debugName; + } + + public void createDebugName() { + assert name != null; + this.debugName = name + " " + debugCounter++; + } + public String generateNewLayerName() { return "layer " + newLayerCount++; } @@ -1045,7 +1064,7 @@ public void createSelectionFrom(Shape shape) { public void setSelectionRef(Selection selection) { this.selection = selection; if (isActive()) { - SelectionActions.setEnabled(selection != null, this); + SelectionActions.update(this); SelectionActions.getShowHide().updateTextFrom(selection); } } @@ -1357,6 +1376,7 @@ public void afterSuccessfulSaveActions(File file, boolean addToRecentMenus) { if (addToRecentMenus) { RecentFilesMenu.getInstance().addFile(file); } + ImagePreviewPanel.removeThumbFromCache(file); Messages.showFileSavedMessage(file); } diff --git a/src/main/java/pixelitor/OpenImages.java b/src/main/java/pixelitor/OpenImages.java index 9d7c464b8..4d52c9c35 100644 --- a/src/main/java/pixelitor/OpenImages.java +++ b/src/main/java/pixelitor/OpenImages.java @@ -113,8 +113,7 @@ private static void onAllImagesClosed() { setActiveView(null, false); activationListeners.forEach(ViewActivationListener::allViewsClosed); History.onAllImagesClosed(); - SelectionActions.setEnabled(false, null); - + SelectionActions.update(null); PixelitorWindow.get().updateTitle(null); FramesUI.resetCascadeIndex(); } @@ -172,7 +171,7 @@ public static void viewActivated(View view) { var comp = view.getComp(); setActiveView(view, false); - SelectionActions.setEnabled(comp.hasSelection(), comp); + SelectionActions.update(comp); view.activateUI(true); for (ViewActivationListener listener : activationListeners) { diff --git a/src/main/java/pixelitor/Pixelitor.java b/src/main/java/pixelitor/Pixelitor.java index fe54b6270..c7891fd81 100644 --- a/src/main/java/pixelitor/Pixelitor.java +++ b/src/main/java/pixelitor/Pixelitor.java @@ -73,11 +73,12 @@ public static void main(String[] args) { if (!Language.isCodeSupported(sysLangCode)) { // except if supported Locale.setDefault(Locale.US); } - Language.load(); System.setProperty("com.apple.mrj.application.apple.menu.about.name", "Pixelitor"); +// System.setProperty("sun.java2d.uiScale", "2.0"); + if (JVM.isLinux) { // doesn't seem to pick up good defaults System.setProperty("awt.useSystemAAFontSettings", "lcd"); @@ -225,14 +226,14 @@ private static void afterStartTestActions() { // SplashImageCreator.saveManySplashImages(); -// Debug.addTestPath(); - // Debug.keepSwitchingToolsRandomly(); // Debug.startFilter(new Marble()); // Navigator.showInDialog(pw); // Tools.PEN.activate(); +// Debug.addTestPath(); +// Tools.PEN.startRestrictedMode(PenToolMode.TRANSFORM, false); // Debug.addMaskAndShowIt(); // Debug.showAddTextLayerDialog(); diff --git a/src/main/java/pixelitor/colors/FgBgColorSelector.java b/src/main/java/pixelitor/colors/FgBgColorSelector.java index 69671cc1d..787aa2cbf 100644 --- a/src/main/java/pixelitor/colors/FgBgColorSelector.java +++ b/src/main/java/pixelitor/colors/FgBgColorSelector.java @@ -32,7 +32,6 @@ import javax.swing.*; import java.awt.Color; import java.awt.Dimension; -import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import static java.awt.Color.BLACK; @@ -180,9 +179,9 @@ public void onClick() { } private void initResetDefaultsButton() { - resetToDefaultAction = new AbstractAction() { + resetToDefaultAction = new PAction() { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { setDefaultColors(); } }; @@ -199,9 +198,9 @@ public void setDefaultColors() { } private void initSwapColorsButton() { - swapColorsAction = new AbstractAction() { + swapColorsAction = new PAction() { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { swapColors(); } }; @@ -224,9 +223,9 @@ private void swapColors() { } private void initRandomizeButton() { - randomizeColorsAction = new AbstractAction() { + randomizeColorsAction = new PAction() { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { setFgColor(Rnd.createRandomColor(), false); setBgColor(Rnd.createRandomColor(), true); } diff --git a/src/main/java/pixelitor/compactions/Crop.java b/src/main/java/pixelitor/compactions/Crop.java index a78036cac..d711e2f87 100644 --- a/src/main/java/pixelitor/compactions/Crop.java +++ b/src/main/java/pixelitor/compactions/Crop.java @@ -109,7 +109,7 @@ public CompletableFuture process(Composition oldComp) { } }); - newCanvas.changeSize(cropRect.width, cropRect.height, view); + newCanvas.changeSize(cropRect.width, cropRect.height, view, false); // The intersected selection, tool widgets etc. have to be moved // into the coordinate system of the new, cropped image. @@ -138,7 +138,7 @@ public CompletableFuture process(Composition oldComp) { view.replaceComp(newComp); newComp.updateAllIconImages(); - SelectionActions.setEnabled(newComp.hasSelection(), newComp); + SelectionActions.update(newComp); newComp.imageChanged(FULL, true); diff --git a/src/main/java/pixelitor/compactions/EnlargeCanvas.java b/src/main/java/pixelitor/compactions/EnlargeCanvas.java index d29186fd1..da6fda13a 100644 --- a/src/main/java/pixelitor/compactions/EnlargeCanvas.java +++ b/src/main/java/pixelitor/compactions/EnlargeCanvas.java @@ -85,7 +85,7 @@ public boolean doesNothing() { protected void changeCanvasSize(Canvas newCanvas, View view) { newCanvasWidth = newCanvas.getWidth() + east + west; newCanvasHeight = newCanvas.getHeight() + north + south; - newCanvas.changeSize(newCanvasWidth, newCanvasHeight, view); + newCanvas.changeSize(newCanvasWidth, newCanvasHeight, view, false); } @Override diff --git a/src/main/java/pixelitor/compactions/Resize.java b/src/main/java/pixelitor/compactions/Resize.java index a336d0e22..39002a46e 100644 --- a/src/main/java/pixelitor/compactions/Resize.java +++ b/src/main/java/pixelitor/compactions/Resize.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Laszlo Balazs-Csiki and Contributors + * Copyright 2021 Laszlo Balazs-Csiki and Contributors * * This file is part of Pixelitor. Pixelitor is free software: you * can redistribute it and/or modify it under the terms of the GNU @@ -108,7 +108,7 @@ private static Composition afterResizeActions(Composition oldComp, newComp.imCoordsChanged(canvasTransform, false); View view = newComp.getView(); - newCanvas.changeSize(newCanvasSize.width, newCanvasSize.height, view); + newCanvas.changeSize(newCanvasSize.width, newCanvasSize.height, view, false); History.add(new CompositionReplacedEdit("Resize", view, oldComp, newComp, canvasTransform, false)); @@ -117,7 +117,7 @@ private static Composition afterResizeActions(Composition oldComp, // the view was active when the resize started, but since the // resize was asynchronous, this could have changed if (view.isActive()) { - SelectionActions.setEnabled(newComp.hasSelection(), newComp); + SelectionActions.update(newComp); } Guides oldGuides = oldComp.getGuides(); diff --git a/src/main/java/pixelitor/compactions/Rotate.java b/src/main/java/pixelitor/compactions/Rotate.java index 51ae484ab..d17b990f4 100644 --- a/src/main/java/pixelitor/compactions/Rotate.java +++ b/src/main/java/pixelitor/compactions/Rotate.java @@ -74,7 +74,7 @@ public void changeCanvasSize(Canvas canvas, View view) { // switch width and height int newWidth = canvas.getHeight(); int newHeight = canvas.getWidth(); - canvas.changeSize(newWidth, newHeight, view); + canvas.changeSize(newWidth, newHeight, view, false); } @Override diff --git a/src/main/java/pixelitor/compactions/SimpleCompAction.java b/src/main/java/pixelitor/compactions/SimpleCompAction.java index 5baf15da0..7a3193efb 100644 --- a/src/main/java/pixelitor/compactions/SimpleCompAction.java +++ b/src/main/java/pixelitor/compactions/SimpleCompAction.java @@ -73,7 +73,7 @@ public CompletableFuture process(Composition oldComp) { History.add(new CompositionReplacedEdit( getEditName(), view, oldComp, newComp, canvasAT, false)); view.replaceComp(newComp); - SelectionActions.setEnabled(newComp.hasSelection(), newComp); + SelectionActions.update(newComp); Guides guides = oldComp.getGuides(); if (guides != null) { diff --git a/src/main/java/pixelitor/filters/ChannelMixer.java b/src/main/java/pixelitor/filters/ChannelMixer.java index 1bf741626..f236fbea6 100644 --- a/src/main/java/pixelitor/filters/ChannelMixer.java +++ b/src/main/java/pixelitor/filters/ChannelMixer.java @@ -19,11 +19,11 @@ import com.jhlabs.image.PixelUtils; import pixelitor.filters.gui.*; +import pixelitor.gui.utils.PAction; import pixelitor.layers.Drawable; import pixelitor.utils.ImageUtils; import javax.swing.*; -import java.awt.event.ActionEvent; import java.awt.image.BandCombineOp; import java.awt.image.BufferedImage; import java.util.function.BooleanSupplier; @@ -66,9 +66,9 @@ public class ChannelMixer extends ParametrizedFilter { // DO require explicit triggering because they are simple JButtons }; - private final Action swapRedGreen = new AbstractAction("Swap Red-Green") { + private final Action swapRedGreen = new PAction("Swap Red-Green") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { redFromRed.setValueNoTrigger(0); redFromGreen.setValueNoTrigger(100); redFromBlue.setValueNoTrigger(0); @@ -85,9 +85,9 @@ public void actionPerformed(ActionEvent e) { } }; - private final Action swapRedBlue = new AbstractAction("Swap Red-Blue") { + private final Action swapRedBlue = new PAction("Swap Red-Blue") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { redFromRed.setValueNoTrigger(0); redFromGreen.setValueNoTrigger(0); redFromBlue.setValueNoTrigger(100); @@ -104,9 +104,9 @@ public void actionPerformed(ActionEvent e) { } }; - private final Action swapGreenBlue = new AbstractAction("Swap Green-Blue") { + private final Action swapGreenBlue = new PAction("Swap Green-Blue") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { redFromRed.setValueNoTrigger(100); redFromGreen.setValueNoTrigger(0); redFromBlue.setValueNoTrigger(0); @@ -123,9 +123,9 @@ public void actionPerformed(ActionEvent e) { } }; - private final Action shiftRGBR = new AbstractAction("R -> G -> B -> R") { + private final Action shiftRGBR = new PAction("R -> G -> B -> R") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { redFromRed.setValueNoTrigger(0); redFromGreen.setValueNoTrigger(0); redFromBlue.setValueNoTrigger(100); @@ -142,9 +142,9 @@ public void actionPerformed(ActionEvent e) { } }; - private final Action shiftRBGR = new AbstractAction("R -> B -> G -> R") { + private final Action shiftRBGR = new PAction("R -> B -> G -> R") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { redFromRed.setValueNoTrigger(0); redFromGreen.setValueNoTrigger(100); redFromBlue.setValueNoTrigger(0); @@ -161,9 +161,9 @@ public void actionPerformed(ActionEvent e) { } }; - private final Action removeRed = new AbstractAction("Remove Red") { + private final Action removeRed = new PAction("Remove Red") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { redFromRed.setValueNoTrigger(0); redFromGreen.setValueNoTrigger(0); redFromBlue.setValueNoTrigger(0); @@ -180,9 +180,9 @@ public void actionPerformed(ActionEvent e) { } }; - private final Action removeGreen = new AbstractAction("Remove Green") { + private final Action removeGreen = new PAction("Remove Green") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { redFromRed.setValueNoTrigger(100); redFromGreen.setValueNoTrigger(0); redFromBlue.setValueNoTrigger(0); @@ -199,9 +199,9 @@ public void actionPerformed(ActionEvent e) { } }; - private final Action removeBlue = new AbstractAction("Remove Blue") { + private final Action removeBlue = new PAction("Remove Blue") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { redFromRed.setValueNoTrigger(100); redFromGreen.setValueNoTrigger(0); redFromBlue.setValueNoTrigger(0); @@ -218,9 +218,9 @@ public void actionPerformed(ActionEvent e) { } }; - private final Action averageBW = new AbstractAction("Average BW") { + private final Action averageBW = new PAction("Average BW") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { redFromRed.setValueNoTrigger(33); redFromGreen.setValueNoTrigger(33); redFromBlue.setValueNoTrigger(33); @@ -237,9 +237,9 @@ public void actionPerformed(ActionEvent e) { } }; - private final Action luminosityBW = new AbstractAction("Luminosity BW") { + private final Action luminosityBW = new PAction("Luminosity BW") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { redFromRed.setValueNoTrigger(22); redFromGreen.setValueNoTrigger(71); redFromBlue.setValueNoTrigger(7); @@ -256,9 +256,9 @@ public void actionPerformed(ActionEvent e) { } }; - private final Action sepia = new AbstractAction("Sepia") { + private final Action sepia = new PAction("Sepia") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { redFromRed.setValueNoTrigger(39); redFromGreen.setValueNoTrigger(77); redFromBlue.setValueNoTrigger(19); diff --git a/src/main/java/pixelitor/filters/gui/DialogMenuBar.java b/src/main/java/pixelitor/filters/gui/DialogMenuBar.java index 7c1d967ec..d87489afd 100644 --- a/src/main/java/pixelitor/filters/gui/DialogMenuBar.java +++ b/src/main/java/pixelitor/filters/gui/DialogMenuBar.java @@ -19,13 +19,13 @@ import pixelitor.filters.ParametrizedFilter; import pixelitor.gui.utils.Dialogs; +import pixelitor.gui.utils.PAction; import pixelitor.utils.OpenInBrowserAction; import pixelitor.utils.Texts; import pixelitor.utils.Utils; import javax.swing.*; import java.awt.Desktop; -import java.awt.event.ActionEvent; import java.io.File; import java.io.IOException; import java.util.List; @@ -80,9 +80,9 @@ private void addPresetsMenu() { if (owner.hasBuiltinPresets()) { presetsMenu.addSeparator(); } - Action savePresetAction = new AbstractAction("Save Preset...") { + Action savePresetAction = new PAction("Save Preset...") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { String presetName = Dialogs.getTextDialog( DialogMenuBar.this, "Preset Name", "Preset Name:"); if (presetName == null || presetName.isBlank()) { @@ -116,9 +116,9 @@ private void addManagePresetsMenu() { if (!CAN_USE_FILE_MANAGER) { return; } - presetsMenu.add(new AbstractAction("Manage Presets...") { + presetsMenu.add(new PAction("Manage Presets...") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { try { String dirPath = PRESETS_DIR + FILE_SEPARATOR + owner.getPresetDirName(); Desktop.getDesktop().open(new File(dirPath)); diff --git a/src/main/java/pixelitor/filters/gui/FilterState.java b/src/main/java/pixelitor/filters/gui/FilterState.java index 0b331eaa5..6d29617d9 100644 --- a/src/main/java/pixelitor/filters/gui/FilterState.java +++ b/src/main/java/pixelitor/filters/gui/FilterState.java @@ -17,8 +17,9 @@ package pixelitor.filters.gui; +import pixelitor.gui.utils.PAction; + import javax.swing.*; -import java.awt.event.ActionEvent; import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -98,9 +99,9 @@ public void setName(String name) { } public Action asAction(ParamSet paramSet) { - return new AbstractAction(name) { + return new PAction(name) { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { paramSet.applyState(FilterState.this); } }; diff --git a/src/main/java/pixelitor/filters/gui/UserPreset.java b/src/main/java/pixelitor/filters/gui/UserPreset.java index 482d4ecd9..527329ae2 100644 --- a/src/main/java/pixelitor/filters/gui/UserPreset.java +++ b/src/main/java/pixelitor/filters/gui/UserPreset.java @@ -18,12 +18,12 @@ package pixelitor.filters.gui; import pixelitor.colors.Colors; +import pixelitor.gui.utils.PAction; import pixelitor.io.FileUtils; import pixelitor.utils.Messages; import javax.swing.*; import java.awt.Color; -import java.awt.event.ActionEvent; import java.io.*; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -157,9 +157,9 @@ public void save() { } public Action asAction(DialogMenuOwner owner) { - return new AbstractAction(name) { + return new PAction(name) { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { if (!loaded) { try { load(); diff --git a/src/main/java/pixelitor/gui/GlobalEvents.java b/src/main/java/pixelitor/gui/GlobalEvents.java index 627762a3c..c611704e6 100644 --- a/src/main/java/pixelitor/gui/GlobalEvents.java +++ b/src/main/java/pixelitor/gui/GlobalEvents.java @@ -17,6 +17,7 @@ package pixelitor.gui; +import pixelitor.gui.utils.PAction; import pixelitor.tools.Tools; import pixelitor.tools.gui.ToolButton; import pixelitor.tools.util.ArrowKey; @@ -28,7 +29,6 @@ import javax.swing.*; import java.awt.*; -import java.awt.event.ActionEvent; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; @@ -57,16 +57,16 @@ public class GlobalEvents { private static KeyListener keyListener; - private static final Action INCREASE_ACTIVE_BRUSH_SIZE_ACTION = new AbstractAction() { + private static final Action INCREASE_ACTIVE_BRUSH_SIZE_ACTION = new PAction() { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { Tools.increaseActiveBrushSize(); } }; - private static final Action DECREASE_ACTIVE_BRUSH_SIZE_ACTION = new AbstractAction() { + private static final Action DECREASE_ACTIVE_BRUSH_SIZE_ACTION = new PAction() { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { Tools.decreaseActiveBrushSize(); } }; diff --git a/src/main/java/pixelitor/gui/Navigator.java b/src/main/java/pixelitor/gui/Navigator.java index 1e94cb397..734639a53 100644 --- a/src/main/java/pixelitor/gui/Navigator.java +++ b/src/main/java/pixelitor/gui/Navigator.java @@ -23,6 +23,7 @@ import pixelitor.colors.Colors; import pixelitor.gui.utils.DialogBuilder; import pixelitor.gui.utils.GUIUtils; +import pixelitor.gui.utils.PAction; import pixelitor.menus.view.ZoomLevel; import pixelitor.menus.view.ZoomMenu; import pixelitor.utils.Cursors; @@ -96,17 +97,17 @@ private void addPopupMenu() { popup = new JPopupMenu(); ZoomLevel[] levels = {ZoomLevel.Z100, ZoomLevel.Z50, ZoomLevel.Z25, ZoomLevel.Z12}; for (ZoomLevel level : levels) { - popup.add(new AbstractAction("Navigator Zoom: " + level) { + popup.add(new PAction("Navigator Zoom: " + level) { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { setNavigatorSizeFromZoom(level); } }); } popup.addSeparator(); - popup.add(new AbstractAction("View Box Color...") { + popup.add(new PAction("View Box Color...") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { Colors.selectColorWithDialog(Navigator.this, "View Box Color", viewBoxColor, true, Navigator.this::setNewViewBoxColor); diff --git a/src/main/java/pixelitor/gui/PixelitorWindow.java b/src/main/java/pixelitor/gui/PixelitorWindow.java index 7d4e7fa42..e1f911be7 100644 --- a/src/main/java/pixelitor/gui/PixelitorWindow.java +++ b/src/main/java/pixelitor/gui/PixelitorWindow.java @@ -38,6 +38,7 @@ import java.awt.event.ComponentEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; +import java.awt.geom.AffineTransform; import java.net.URL; import java.util.ArrayList; import java.util.List; @@ -372,5 +373,9 @@ private void setupFirstUnMaximization() { } }); } + + public AffineTransform getHiDPIScaling() { + return getGraphicsConfiguration().getDefaultTransform(); + } } diff --git a/src/main/java/pixelitor/gui/TabViewContainer.java b/src/main/java/pixelitor/gui/TabViewContainer.java index 3e83ee615..83a420cd5 100644 --- a/src/main/java/pixelitor/gui/TabViewContainer.java +++ b/src/main/java/pixelitor/gui/TabViewContainer.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Laszlo Balazs-Csiki and Contributors + * Copyright 2021 Laszlo Balazs-Csiki and Contributors * * This file is part of Pixelitor. Pixelitor is free software: you * can redistribute it and/or modify it under the terms of the GNU @@ -19,11 +19,11 @@ import pixelitor.OpenImages; import pixelitor.gui.utils.GUIUtils; +import pixelitor.gui.utils.PAction; import javax.swing.*; import java.awt.BorderLayout; import java.awt.Desktop; -import java.awt.event.ActionEvent; import java.awt.event.MouseEvent; import java.io.File; @@ -104,15 +104,15 @@ private void showPopup(MouseEvent mouse) { JPopupMenu popup = new JPopupMenu(); // close the clicked one, even if it is not the active! - popup.add(new AbstractAction(i18n("close")) { + popup.add(new PAction(i18n("close")) { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { OpenImages.warnAndClose(view); } }); - popup.add(new AbstractAction("Close Others") { + popup.add(new PAction("Close Others") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { OpenImages.warnAndCloseAllBut(view); } }); diff --git a/src/main/java/pixelitor/gui/TabsUI.java b/src/main/java/pixelitor/gui/TabsUI.java index 581961073..d8e8931af 100644 --- a/src/main/java/pixelitor/gui/TabsUI.java +++ b/src/main/java/pixelitor/gui/TabsUI.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Laszlo Balazs-Csiki and Contributors + * Copyright 2021 Laszlo Balazs-Csiki and Contributors * * This file is part of Pixelitor. Pixelitor is free software: you * can redistribute it and/or modify it under the terms of the GNU @@ -18,10 +18,10 @@ package pixelitor.gui; import pixelitor.OpenImages; +import pixelitor.gui.utils.PAction; import pixelitor.utils.Lazy; import javax.swing.*; -import java.awt.event.ActionEvent; import static pixelitor.utils.Keys.CTRL_SHIFT_TAB; import static pixelitor.utils.Keys.CTRL_TAB; @@ -127,9 +127,9 @@ private JMenu createTabPlacementMenu() { } private JRadioButtonMenuItem createTabPlacementMenuItem(String name, int pos) { - return new JRadioButtonMenuItem(new AbstractAction(name) { + return new JRadioButtonMenuItem(new PAction(name) { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { setTabPlacement(pos); ImageArea.setTabPlacement(pos); } diff --git a/src/main/java/pixelitor/gui/View.java b/src/main/java/pixelitor/gui/View.java index 27cdcb3b6..ccb60143b 100644 --- a/src/main/java/pixelitor/gui/View.java +++ b/src/main/java/pixelitor/gui/View.java @@ -99,6 +99,7 @@ public View(Composition comp) { public void replaceJustReloadedComp(Composition newComp) { assert calledOnEDT() : threadInfo(); assert newComp != comp; + assert !newComp.hasSelection(); // do this before actually replacing so that the old comp is // deselected before its view is set to null @@ -109,7 +110,7 @@ public void replaceJustReloadedComp(Composition newComp) { // the view was active when the reload started, but since the // reload was asynchronous, this could have changed if (isActive()) { - SelectionActions.setEnabled(false, newComp); + SelectionActions.update(newComp); } String msg = format("The image %s was reloaded from the file %s.", @@ -147,9 +148,9 @@ public void replaceComp(Composition newComp, HistogramsPanel.updateFrom(newComp); } - Tools.currentTool.compReplaced(oldComp, newComp, reloaded); + Tools.currentTool.compReplaced(newComp, reloaded); - revalidate(); // make sure the scrollbars are OK if the new comp has a different size + revalidate(); // update the scrollbars if the new comp has a different size canvasCoSizeChanged(); repaint(); } @@ -530,7 +531,7 @@ public void setZoom(ZoomLevel newZoom, Point mousePos) { this.zoomLevel = newZoom; scaling = newZoom.getViewScale(); - canvas.recalcCoSize(this); + canvas.recalcCoSize(this, true); if (ImageArea.currentModeIs(ImageArea.Mode.FRAMES)) { updateTitle(); diff --git a/src/main/java/pixelitor/gui/utils/DialogBuilder.java b/src/main/java/pixelitor/gui/utils/DialogBuilder.java index 5a0c9af30..e1269fda0 100644 --- a/src/main/java/pixelitor/gui/utils/DialogBuilder.java +++ b/src/main/java/pixelitor/gui/utils/DialogBuilder.java @@ -54,6 +54,7 @@ public class DialogBuilder { private boolean modal = true; private boolean disposeWhenClosing = true; private Screens.Align align = SCREEN_CENTER; + private JComponent parent; private Runnable okAction; private Runnable cancelAction; @@ -203,6 +204,11 @@ public DialogBuilder menuBar(JMenuBar m) { return this; } + public DialogBuilder parentComponent(JComponent c) { + parent = c; + return this; + } + public JButton getOkButton() { return okButton; } @@ -216,7 +222,12 @@ public JDialog show() { } JDialog d = build(); - GUIUtils.showDialog(d, align); + if (parent != null) { + GUIUtils.showDialog(d, parent); + } else { + GUIUtils.showDialog(d, align); + } + return d; } diff --git a/src/main/java/pixelitor/gui/utils/Dialogs.java b/src/main/java/pixelitor/gui/utils/Dialogs.java index 5bc4941e7..9c65a76b8 100644 --- a/src/main/java/pixelitor/gui/utils/Dialogs.java +++ b/src/main/java/pixelitor/gui/utils/Dialogs.java @@ -251,8 +251,8 @@ public static void showExceptionDialog(Throwable e, Thread srcThread) { String basicErrorMessage = """ A program error occurred. - Please consider reporting this error to the developers by creating a new issue on GitHub (see "Help/Report an Issue..." in the menus). - If you do, then open "Details", click "Copy to Clipboard", and paste the details into the new issue."""; + Please consider reporting this error to the developers by creating a new issue on github (see "Help/Report an Issue..." in the menus). + If you do, then open "Details", click "Copy to Clipboard", and paste the details into the issue."""; var errorInfo = new ErrorInfo("Program Error", basicErrorMessage, null, null, e, Level.SEVERE, null); @@ -278,8 +278,10 @@ private static void showMoreDevelopmentInfo(Throwable e) { } } - boolean autoTest = randomGUITest || assertJSwingTest; - if (!autoTest) { + // the following should happen only for the GUI tests, + // which are running for a long time + boolean guiTest = randomGUITest || assertJSwingTest; + if (!guiTest) { return; } @@ -288,7 +290,7 @@ private static void showMoreDevelopmentInfo(Throwable e) { Utils.sleep(2, TimeUnit.SECONDS); if (randomGUITest) { - Events.dumpForActiveComp(); + Events.dumpAll(); } Toolkit.getDefaultToolkit().beep(); playWarningSound(); diff --git a/src/main/java/pixelitor/gui/utils/GUIUtils.java b/src/main/java/pixelitor/gui/utils/GUIUtils.java index 442431bc4..9b09153af 100644 --- a/src/main/java/pixelitor/gui/utils/GUIUtils.java +++ b/src/main/java/pixelitor/gui/utils/GUIUtils.java @@ -126,6 +126,16 @@ public static JDialog getDialogAncestor(Component c) { return (JDialog) SwingUtilities.getWindowAncestor(c); } + public static void showDialog(JDialog d, JComponent parent) { + Point loc = lastDialogLocationsByTitle.get(d.getTitle()); + if (loc != null) { + d.setLocation(loc); + } else { + d.setLocationRelativeTo(parent); + } + d.setVisible(true); + } + public static void showDialog(JDialog d) { showDialog(d, SCREEN_CENTER); } @@ -313,9 +323,9 @@ private static void openFileInFolder(File file) throws IOException { } public static AbstractAction createPrintFileAction(Composition comp, File file) { - return new AbstractAction("Print...") { + return new PAction("Print...") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { if (comp.isDirty()) { String msg = "The file " + file.getName() + " contains unsaved changes.
" + diff --git a/src/main/java/pixelitor/gui/utils/ImagePreviewPanel.java b/src/main/java/pixelitor/gui/utils/ImagePreviewPanel.java index 47938ae2b..8a9071f3f 100644 --- a/src/main/java/pixelitor/gui/utils/ImagePreviewPanel.java +++ b/src/main/java/pixelitor/gui/utils/ImagePreviewPanel.java @@ -41,9 +41,9 @@ public class ImagePreviewPanel extends JPanel implements PropertyChangeListener { private static final int SIZE = 200; public static final int EMPTY_SPACE_AT_LEFT = 5; + private static final Map> thumbsCache = new HashMap<>(); private final Color backgroundColor; - private final Map> thumbsCache; private ThumbInfo thumbInfo; private final ProgressPanel progressPanel; @@ -51,7 +51,6 @@ public ImagePreviewPanel(ProgressPanel progressPanel) { this.progressPanel = progressPanel; setPreferredSize(new Dimension(SIZE, SIZE)); backgroundColor = getBackground(); - thumbsCache = new HashMap<>(); this.progressPanel.setVisible(true); } @@ -62,8 +61,7 @@ public void propertyChange(PropertyChangeEvent e) { if (JFileChooser.SELECTED_FILE_CHANGED_PROPERTY.equals(e.getPropertyName())) { File file = (File) e.getNewValue(); if (file != null && FileUtils.hasSupportedInputExt(file)) { - String filePath = file.getAbsolutePath(); - thumbInfo = getOrCreateThumb(file, filePath); + thumbInfo = getOrCreateThumb(file); } else { thumbInfo = null; } @@ -74,7 +72,8 @@ public void propertyChange(PropertyChangeEvent e) { repaint(); } - private ThumbInfo getOrCreateThumb(File file, String filePath) { + private ThumbInfo getOrCreateThumb(File file) { + String filePath = file.getAbsolutePath(); if (thumbsCache.containsKey(filePath)) { SoftReference thumbRef = thumbsCache.get(filePath); ThumbInfo cachedInfo = thumbRef.get(); @@ -106,6 +105,10 @@ private ThumbInfo getOrCreateThumb(File file, String filePath) { } } + public static void removeThumbFromCache(File file) { + thumbsCache.remove(file.getAbsolutePath()); + } + @Override public void paintComponent(Graphics g) { g.setColor(backgroundColor); diff --git a/src/main/java/pixelitor/history/CompositionReplacedEdit.java b/src/main/java/pixelitor/history/CompositionReplacedEdit.java index 06da6b5e6..cd2337c29 100644 --- a/src/main/java/pixelitor/history/CompositionReplacedEdit.java +++ b/src/main/java/pixelitor/history/CompositionReplacedEdit.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Laszlo Balazs-Csiki and Contributors + * Copyright 2021 Laszlo Balazs-Csiki and Contributors * * This file is part of Pixelitor. Pixelitor is free software: you * can redistribute it and/or modify it under the terms of the GNU @@ -21,6 +21,8 @@ import pixelitor.gui.View; import pixelitor.layers.MaskViewMode; import pixelitor.tools.Tools; +import pixelitor.utils.debug.CompositionNode; +import pixelitor.utils.debug.DebugNode; import javax.swing.undo.CannotRedoException; import javax.swing.undo.CannotUndoException; @@ -161,4 +163,14 @@ public void die() { backupCompRef = null; view = null; } + + @Override + public DebugNode createDebugNode() { + DebugNode node = super.createDebugNode(); + Composition backupComp = backupCompRef.get(); + if (backupComp != null) { + node.add(new CompositionNode("backup comp", backupComp)); + } + return node; + } } diff --git a/src/main/java/pixelitor/history/PartialImageEdit.java b/src/main/java/pixelitor/history/PartialImageEdit.java index 7083f93ae..b4efd31c7 100644 --- a/src/main/java/pixelitor/history/PartialImageEdit.java +++ b/src/main/java/pixelitor/history/PartialImageEdit.java @@ -116,7 +116,7 @@ private static void debugRaster(String name, Raster raster) { String className = raster.getClass().getSimpleName(); DataBuffer dataBuffer = raster.getDataBuffer(); int dataType = dataBuffer.getDataType(); - String typeAsString = Debug.dateBufferTypeAsString(dataType); + String typeAsString = Debug.dataBufferTypeAsString(dataType); int numBanks = dataBuffer.getNumBanks(); int numBands = raster.getNumBands(); int numDataElements = raster.getNumDataElements(); diff --git a/src/main/java/pixelitor/history/PixelitorEdit.java b/src/main/java/pixelitor/history/PixelitorEdit.java index 684736854..a3a32c37a 100644 --- a/src/main/java/pixelitor/history/PixelitorEdit.java +++ b/src/main/java/pixelitor/history/PixelitorEdit.java @@ -156,7 +156,7 @@ public DebugNode createDebugNode() { var node = new DebugNode(nodeName, this); node.addClass(); - node.addQuotedString("comp", comp.getName()); + node.addQuotedString("comp debug name", comp.getDebugName()); node.addBoolean("embedded", embedded); return node; } diff --git a/src/main/java/pixelitor/io/OpenRaster.java b/src/main/java/pixelitor/io/OpenRaster.java index d2dec070e..c7d2e2374 100644 --- a/src/main/java/pixelitor/io/OpenRaster.java +++ b/src/main/java/pixelitor/io/OpenRaster.java @@ -182,6 +182,7 @@ public static Composition read(File file) throws IOException, ParserConfiguratio var comp = Composition.createEmpty(compWidth, compHeight, ImageMode.RGB); comp.setFile(file); + comp.createDebugName(); NodeList layers = doc.getElementsByTagName("layer"); for (int i = layers.getLength() - 1; i >= 0; i--) { // stack.xml contains layers in reverse order diff --git a/src/main/java/pixelitor/layers/LayerMaskActions.java b/src/main/java/pixelitor/layers/LayerMaskActions.java index 4555b7611..c40a76747 100644 --- a/src/main/java/pixelitor/layers/LayerMaskActions.java +++ b/src/main/java/pixelitor/layers/LayerMaskActions.java @@ -21,7 +21,6 @@ import pixelitor.utils.Messages; import javax.swing.*; -import java.awt.event.ActionEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; @@ -84,7 +83,7 @@ private void popup(MouseEvent e) { } } - private static class DeleteMaskAction extends AbstractAction { + private static class DeleteMaskAction extends PAction { private final Layer layer; public DeleteMaskAction(Layer layer) { @@ -93,12 +92,12 @@ public DeleteMaskAction(Layer layer) { } @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { layer.deleteMask(true); } } - private static class ApplyMaskAction extends AbstractAction { + private static class ApplyMaskAction extends PAction { private final Layer layer; public ApplyMaskAction(Layer layer) { @@ -107,7 +106,7 @@ public ApplyMaskAction(Layer layer) { } @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { if (!(layer instanceof ImageLayer)) { // actually we should never get here because the popup menu // is enabled only for image layers diff --git a/src/main/java/pixelitor/layers/LayerMaskAddType.java b/src/main/java/pixelitor/layers/LayerMaskAddType.java index 501bceed1..ef89d9f63 100644 --- a/src/main/java/pixelitor/layers/LayerMaskAddType.java +++ b/src/main/java/pixelitor/layers/LayerMaskAddType.java @@ -17,8 +17,10 @@ package pixelitor.layers; +import com.jhlabs.image.PointFilter; import pixelitor.Canvas; import pixelitor.colors.Colors; +import pixelitor.utils.ProgressTracker; import java.awt.*; import java.awt.image.BufferedImage; @@ -139,15 +141,22 @@ private static BufferedImage createMaskFromImage(BufferedImage image, image.getWidth(), image.getHeight(), TYPE_BYTE_GRAY); Graphics2D g = bwImage.createGraphics(); - // fill the background with white so that transparent parts become white - Colors.fillWith(Color.WHITE, g, image.getWidth(), image.getHeight()); - if (onlyTransparency) { - // with DstOut only the source alpha will matter - g.setComposite(AlphaComposite.DstOut); + PointFilter transparencyToBWFilter = new PointFilter("") { + @Override + public int filterRGB(int x, int y, int rgb) { + int a = (rgb >>> 24) & 0xFF; + return 0xFF_00_00_00 | a << 16 | a << 8 | a; + } + }; + transparencyToBWFilter.setProgressTracker(ProgressTracker.NULL_TRACKER); + BufferedImage argbBWImage = transparencyToBWFilter.filter(image, null); + g.drawImage(argbBWImage, 0, 0, null); + } else { + // fill the background with white so that transparent parts become white + Colors.fillWith(Color.WHITE, g, image.getWidth(), image.getHeight()); + g.drawImage(image, 0, 0, null); } - - g.drawImage(image, 0, 0, null); g.dispose(); return bwImage; } diff --git a/src/main/java/pixelitor/layers/MaskViewMode.java b/src/main/java/pixelitor/layers/MaskViewMode.java index 111b0a149..51c2d1783 100644 --- a/src/main/java/pixelitor/layers/MaskViewMode.java +++ b/src/main/java/pixelitor/layers/MaskViewMode.java @@ -22,6 +22,7 @@ import pixelitor.ConsistencyChecks; import pixelitor.colors.FgBgColors; import pixelitor.gui.View; +import pixelitor.gui.utils.PAction; import pixelitor.gui.utils.RestrictedLayerAction; import pixelitor.gui.utils.RestrictedLayerAction.Condition; import pixelitor.history.History; @@ -31,7 +32,6 @@ import pixelitor.utils.test.Events; import javax.swing.*; -import java.awt.event.ActionEvent; import static pixelitor.utils.Keys.*; @@ -84,9 +84,9 @@ public void onActiveLayer(Layer layer) { * Adds a menu item that acts on the given layer and its image */ public void addToPopupMenu(JMenu menu, Layer layer) { - var action = new AbstractAction(guiName) { + var action = new PAction(guiName) { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { activate(layer); } }; diff --git a/src/main/java/pixelitor/layers/TextLayer.java b/src/main/java/pixelitor/layers/TextLayer.java index 95fb04bf4..07b445060 100644 --- a/src/main/java/pixelitor/layers/TextLayer.java +++ b/src/main/java/pixelitor/layers/TextLayer.java @@ -33,6 +33,7 @@ import pixelitor.filters.painters.TransformedTextPainter; import pixelitor.gui.PixelitorWindow; import pixelitor.gui.utils.DialogBuilder; +import pixelitor.gui.utils.PAction; import pixelitor.history.*; import pixelitor.tools.Tools; import pixelitor.utils.Messages; @@ -40,7 +41,6 @@ import javax.swing.*; import java.awt.*; -import java.awt.event.ActionEvent; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.IOException; @@ -376,16 +376,16 @@ public JPopupMenu createLayerIconPopupMenu() { editMenuItem.setAccelerator(CTRL_T); popup.add(editMenuItem); - popup.add(new AbstractAction("Rasterize") { + popup.add(new PAction("Rasterize") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { replaceWithRasterized(); } }); - popup.add(new AbstractAction("Selection from Text") { + popup.add(new PAction("Selection from Text") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { createSelectionFromText(); } }); diff --git a/src/main/java/pixelitor/menus/file/MetaDataPanel.java b/src/main/java/pixelitor/menus/file/MetaDataPanel.java index 57ea7cb28..eb88e2e62 100644 --- a/src/main/java/pixelitor/menus/file/MetaDataPanel.java +++ b/src/main/java/pixelitor/menus/file/MetaDataPanel.java @@ -25,6 +25,7 @@ import pixelitor.gui.PixelitorWindow; import pixelitor.gui.utils.DialogBuilder; import pixelitor.gui.utils.Dialogs; +import pixelitor.gui.utils.PAction; import pixelitor.io.FileUtils; import pixelitor.utils.Messages; @@ -35,7 +36,6 @@ import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.dnd.*; -import java.awt.event.ActionEvent; import java.io.File; import java.io.IOException; import java.util.List; @@ -61,15 +61,15 @@ public MetaDataPanel(MetaDataTreeTableModel model) { JPanel northPanel = new JPanel(new BorderLayout()); JPanel northLeftPanel = new JPanel(new FlowLayout(LEFT)); - JButton expandButton = new JButton(new AbstractAction("Expand All") { + JButton expandButton = new JButton(new PAction("Expand All") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { treeTable.expandAll(); } }); - JButton collapseButton = new JButton(new AbstractAction("Collapse All") { + JButton collapseButton = new JButton(new PAction("Collapse All") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { treeTable.collapseAll(); } }); @@ -78,9 +78,9 @@ public void actionPerformed(ActionEvent e) { northLeftPanel.add(expandButton); northLeftPanel.add(collapseButton); northPanel.add(northLeftPanel, WEST); - JButton helpButton = new JButton(new AbstractAction("Help") { + JButton helpButton = new JButton(new PAction("Help") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { showHelp(); } }); diff --git a/src/main/java/pixelitor/menus/file/ScreenCaptureAction.java b/src/main/java/pixelitor/menus/file/ScreenCaptureAction.java index af74f4bec..b0167fabd 100644 --- a/src/main/java/pixelitor/menus/file/ScreenCaptureAction.java +++ b/src/main/java/pixelitor/menus/file/ScreenCaptureAction.java @@ -22,12 +22,12 @@ import pixelitor.gui.PixelitorWindow; import pixelitor.gui.utils.DialogBuilder; import pixelitor.gui.utils.GridBagHelper; +import pixelitor.gui.utils.PAction; import pixelitor.utils.Messages; import pixelitor.utils.Utils; import javax.swing.*; import java.awt.*; -import java.awt.event.ActionEvent; import java.awt.image.BufferedImage; import java.util.concurrent.TimeUnit; @@ -36,7 +36,7 @@ /** * The {@link Action} for creating a screen capture. */ -public class ScreenCaptureAction extends AbstractAction { +public class ScreenCaptureAction extends PAction { private static final String SCREEN_CAPTURE_STRING = i18n("screen_capture"); private JCheckBox hidePixelitorCB; private static int captureCount = 1; @@ -46,7 +46,7 @@ public ScreenCaptureAction() { } @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { new DialogBuilder() .content(getSettingsPanel()) .title(SCREEN_CAPTURE_STRING) diff --git a/src/main/java/pixelitor/menus/help/SystemInfoPanel.java b/src/main/java/pixelitor/menus/help/SystemInfoPanel.java index d147066e6..6914535ad 100644 --- a/src/main/java/pixelitor/menus/help/SystemInfoPanel.java +++ b/src/main/java/pixelitor/menus/help/SystemInfoPanel.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Laszlo Balazs-Csiki and Contributors + * Copyright 2021 Laszlo Balazs-Csiki and Contributors * * This file is part of Pixelitor. Pixelitor is free software: you * can redistribute it and/or modify it under the terms of the GNU @@ -17,12 +17,15 @@ package pixelitor.menus.help; +import pixelitor.gui.PixelitorWindow; import pixelitor.gui.utils.GridBagHelper; import pixelitor.utils.MemoryInfo; import javax.swing.*; import java.awt.GridBagLayout; +import static java.lang.String.format; + class SystemInfoPanel extends JPanel { private final GridBagHelper gbh; @@ -39,6 +42,9 @@ private void addSystemProperties() { gbh.addTwoLabels("Java VM:", System.getProperty("java.vm.name")); gbh.addTwoLabels("Java vendor:", System.getProperty("java.vendor")); gbh.addTwoLabels("OS:", System.getProperty("os.name")); + + gbh.addTwoLabels("UI scaling:", format("%.2f", + PixelitorWindow.get().getHiDPIScaling().getScaleY())); } private void addMemoryProperties() { diff --git a/src/main/java/pixelitor/selection/SelectionActions.java b/src/main/java/pixelitor/selection/SelectionActions.java index 0c2890f0a..20f69852f 100644 --- a/src/main/java/pixelitor/selection/SelectionActions.java +++ b/src/main/java/pixelitor/selection/SelectionActions.java @@ -38,7 +38,6 @@ import javax.swing.*; import java.awt.GridBagLayout; import java.awt.Shape; -import java.awt.event.ActionEvent; import static pixelitor.OpenImages.getActiveComp; import static pixelitor.OpenImages.getActiveSelection; @@ -52,9 +51,9 @@ public final class SelectionActions { private static Shape copiedSelShape = null; - private static final Action crop = new AbstractAction("Crop Selection") { + private static final Action crop = new PAction("Crop Selection") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { Crop.selectionCropActiveImage(); } }; @@ -75,9 +74,9 @@ public void onClick() { private static final ShowHideSelectionAction showHide = new ShowHideSelectionAction(); - private static final Action convertToPath = new AbstractAction("Convert to Path") { + private static final Action convertToPath = new PAction("Convert to Path") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { var comp = getActiveComp(); selectionToPath(comp, true); } @@ -168,7 +167,7 @@ private static void modifySelection(EnumParam type, } static { - setEnabled(false, null); + update(null); } private SelectionActions() { @@ -178,18 +177,22 @@ private SelectionActions() { * Selection actions must be enabled only if * the active composition has a selection */ - public static void setEnabled(boolean b, Composition comp) { - assert comp == null || getActiveComp() == comp - : "comp = " + (comp == null ? "null" : comp.getName()) - + ", active comp = " + (getActiveComp() == null ? "null" : getActiveComp().getName()); - - crop.setEnabled(b); - deselect.setEnabled(b); - invert.setEnabled(b); - showHide.setEnabled(b); - modify.setEnabled(b); - convertToPath.setEnabled(b); - copySel.setEnabled(b); + public static void update(Composition comp) { + boolean enabled; + if (comp == null) { + enabled = false; + } else { + assert comp.isActive(); + enabled = comp.hasSelection(); + } + + crop.setEnabled(enabled); + deselect.setEnabled(enabled); + invert.setEnabled(enabled); + showHide.setEnabled(enabled); + modify.setEnabled(enabled); + convertToPath.setEnabled(enabled); + copySel.setEnabled(enabled); } public static boolean areEnabled() { diff --git a/src/main/java/pixelitor/tools/AbstractBrushTool.java b/src/main/java/pixelitor/tools/AbstractBrushTool.java index 090d34b42..8362a292b 100644 --- a/src/main/java/pixelitor/tools/AbstractBrushTool.java +++ b/src/main/java/pixelitor/tools/AbstractBrushTool.java @@ -38,7 +38,6 @@ import javax.swing.*; import java.awt.*; -import java.awt.event.ActionEvent; import java.awt.event.MouseEvent; import java.awt.geom.Ellipse2D; import java.awt.geom.FlatteningPathIterator; @@ -80,16 +79,17 @@ public abstract class AbstractBrushTool extends Tool { private SymmetryBrush symmetryBrush; protected AffectedArea affectedArea; + private JButton brushSettingsDialogButton; private Action brushSettingsAction; private JDialog settingsDialog; protected DrawDestination drawDestination; private RangeParam lazyMouseDist; - private RangeParam lazyMouseSpacing; protected boolean lazyMouse; protected LazyMouseBrush lazyMouseBrush; private static final String UNICODE_MOUSE_SYMBOL = new String(Character.toChars(0x1F42D)); + private JButton showLazyMouseDialogButton; private int outlineCoX; private int outlineCoY; @@ -165,13 +165,13 @@ protected void addSymmetryCombo() { } protected void addBrushSettingsButton() { - brushSettingsAction = new AbstractAction("Settings...") { + brushSettingsAction = new PAction("Settings...") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { brushSettingsButtonPressed(); } }; - settingsPanel.addButton(brushSettingsAction, + brushSettingsDialogButton = settingsPanel.addButton(brushSettingsAction, "brushSettingsDialogButton", "Configure the selected brush"); brushSettingsAction.setEnabled(false); @@ -186,18 +186,19 @@ private void brushSettingsButtonPressed() { .withScrollbars() .okText(CLOSE_DIALOG) .noCancelButton() + .parentComponent(brushSettingsDialogButton) .show(); } protected void addLazyMouseDialogButton() { - settingsPanel.addButton("Lazy Mouse...", + showLazyMouseDialogButton = settingsPanel.addButton("Lazy Mouse...", e -> showLazyMouseDialog(), "lazyMouseDialogButton", "Configure brush smoothing"); } private void showLazyMouseDialog() { if (lazyMouseDialog != null) { - GUIUtils.showDialog(lazyMouseDialog); + GUIUtils.showDialog(lazyMouseDialog, showLazyMouseDialogButton); return; } var p = new JPanel(new GridBagLayout()); @@ -205,7 +206,8 @@ private void showLazyMouseDialog() { var gbh = new GridBagHelper(p); lazyMouseCB = new JCheckBox("", false); - lazyMouseCB.addActionListener(e -> setLazyBrush()); + // actionListener doesn't react to programmatic setSelected calls + lazyMouseCB.addItemListener(e -> setLazyBrush()); gbh.addLabelAndControlNoStretch("Enabled:", lazyMouseCB); lazyMouseDist = LazyMouseBrush.createDistParam(); @@ -214,17 +216,8 @@ private void showLazyMouseDialog() { distSlider.setEnabled(false); gbh.addLabelAndControl(lazyMouseDist.getName() + ":", distSlider); - lazyMouseSpacing = LazyMouseBrush.createSpacingParam(); - var spacingSlider = SliderSpinner.from(lazyMouseSpacing); - spacingSlider.setEnabled(false); - spacingSlider.setName("spacingSlider"); - gbh.addLabelAndControl(lazyMouseSpacing.getName() + ":", spacingSlider); - - lazyMouseCB.addActionListener(e -> { - boolean enable = lazyMouseCB.isSelected(); - distSlider.setEnabled(enable); - spacingSlider.setEnabled(enable); - }); + lazyMouseCB.addActionListener(e -> + distSlider.setEnabled(lazyMouseCB.isSelected())); lazyMouseDialog = new DialogBuilder() .content(p) @@ -233,6 +226,7 @@ private void showLazyMouseDialog() { .willBeShownAgain() .okText(CLOSE_DIALOG) .noCancelButton() + .parentComponent(showLazyMouseDialogButton) .show(); } @@ -563,11 +557,17 @@ public void firstModalDialogHidden() { * Traces the given shape with the current brush tool */ public void trace(Drawable dr, Shape shape) { + boolean wasLazy = lazyMouse; try { + if (wasLazy) { + lazyMouseCB.setSelected(false); + } doTrace(dr, shape); finishBrushStroke(dr); } finally { - resetInitialState(); + if (wasLazy) { + lazyMouseCB.setSelected(true); + } } } @@ -715,8 +715,6 @@ public String getStateInfo() { if (lazyMouse) { sb.append(", (lazy " + UNICODE_MOUSE_SYMBOL + " d=") .append(lazyMouseDist.getValue()) - .append(", sp=") - .append(lazyMouseSpacing.getValue()) .append(")"); } else { sb.append(", eager "); diff --git a/src/main/java/pixelitor/tools/BrushTool.java b/src/main/java/pixelitor/tools/BrushTool.java index 07ac345ba..3770e0d12 100644 --- a/src/main/java/pixelitor/tools/BrushTool.java +++ b/src/main/java/pixelitor/tools/BrushTool.java @@ -38,7 +38,7 @@ public class BrushTool extends BlendingModeBrushTool { private Color drawingColor; public BrushTool() { - super(NAME, 'B', "brush_tool_icon.png", + super(NAME, 'B', "brush_tool.png", "click or drag to draw with the current brush, " + "Shift-click to draw lines, " + "right-click or right-drag to draw with the background color.", diff --git a/src/main/java/pixelitor/tools/CloneTool.java b/src/main/java/pixelitor/tools/CloneTool.java index 039b947a4..fc3f46aeb 100644 --- a/src/main/java/pixelitor/tools/CloneTool.java +++ b/src/main/java/pixelitor/tools/CloneTool.java @@ -53,6 +53,8 @@ enum State { private State state = NO_SOURCE; private boolean sampleAllLayers = false; + + private JButton showTransformDialogButton; private JDialog transformDialog; private CloneBrush cloneBrush; @@ -65,7 +67,7 @@ enum State { "Mirror", Mirror.class); protected CloneTool() { - super("Clone Stamp", 'S', "clone_tool_icon.png", + super("Clone Stamp", 'S', "clone_tool.png", "Alt-click (or right-click) to select the source, " + "then drag to paint. Shift-click to clone along a line.", Cursors.CROSSHAIR, false); @@ -87,7 +89,8 @@ public void initSettingsPanel() { "sampleAllLayersCB", selected -> sampleAllLayers = selected); settingsPanel.addSeparator(); - settingsPanel.addButton("Transform...", e -> transformButtonPressed(), + showTransformDialogButton = settingsPanel.addButton("Transform...", + e -> transformButtonPressed(), "transformButton", "Transform while cloning"); addLazyMouseDialogButton(); } @@ -100,6 +103,7 @@ private void transformButtonPressed() { .notModal() .okText(CLOSE_DIALOG) .noCancelButton() + .parentComponent(showTransformDialogButton) .show(); } diff --git a/src/main/java/pixelitor/tools/ColorPickerTool.java b/src/main/java/pixelitor/tools/ColorPickerTool.java index 0b563d9d5..6fd5b35f9 100644 --- a/src/main/java/pixelitor/tools/ColorPickerTool.java +++ b/src/main/java/pixelitor/tools/ColorPickerTool.java @@ -46,7 +46,7 @@ public class ColorPickerTool extends Tool { private final JCheckBox sampleLayerOnly = new JCheckBox(SAMPLE_LABEL_TEXT); public ColorPickerTool() { - super("Color Picker", 'I', "color_picker_tool_icon.png", + super("Color Picker", 'I', "color_picker_tool.png", HELP_TEXT, Cursors.CROSSHAIR); } diff --git a/src/main/java/pixelitor/tools/EraserTool.java b/src/main/java/pixelitor/tools/EraserTool.java index f8911cf77..41532a275 100644 --- a/src/main/java/pixelitor/tools/EraserTool.java +++ b/src/main/java/pixelitor/tools/EraserTool.java @@ -29,7 +29,7 @@ */ public class EraserTool extends AbstractBrushTool { public EraserTool() { - super("Eraser", 'E', "erase_tool_icon.png", + super("Eraser", 'E', "eraser_tool.png", "click and drag to erase pixels. Shift-click to erase lines.", Cursors.CROSSHAIR, true); drawDestination = DrawDestination.DIRECT; diff --git a/src/main/java/pixelitor/tools/HandTool.java b/src/main/java/pixelitor/tools/HandTool.java index fc1f0a26f..f9fd1c98a 100644 --- a/src/main/java/pixelitor/tools/HandTool.java +++ b/src/main/java/pixelitor/tools/HandTool.java @@ -27,7 +27,7 @@ public class HandTool extends Tool { private final HandToolSupport handToolSupport = new HandToolSupport(); HandTool() { - super("Hand", 'H', "hand_tool_icon.png", + super("Hand", 'H', "hand_tool.png", "drag to move the view (if there are scrollbars).", Cursors.HAND); } diff --git a/src/main/java/pixelitor/tools/PaintBucketTool.java b/src/main/java/pixelitor/tools/PaintBucketTool.java index 6bacdbdbd..93d770b24 100644 --- a/src/main/java/pixelitor/tools/PaintBucketTool.java +++ b/src/main/java/pixelitor/tools/PaintBucketTool.java @@ -63,7 +63,7 @@ public class PaintBucketTool extends Tool { public PaintBucketTool() { super("Paint Bucket", 'N', - "paint_bucket_tool_icon.png", + "paint_bucket_tool.png", "click to fill with the selected color.", Cursors.DEFAULT); } diff --git a/src/main/java/pixelitor/tools/SelectionTool.java b/src/main/java/pixelitor/tools/SelectionTool.java index c53213585..32a44c01a 100644 --- a/src/main/java/pixelitor/tools/SelectionTool.java +++ b/src/main/java/pixelitor/tools/SelectionTool.java @@ -68,7 +68,7 @@ public class SelectionTool extends DragTool { = new EnumComboBoxModel<>(ShapeCombination.class); SelectionTool() { - super("Selection", 'M', "selection_tool_icon.png", + super("Selection", 'M', "selection_tool.png", HELP_TEXT, Cursors.DEFAULT, false); spaceDragStartPoint = true; } diff --git a/src/main/java/pixelitor/tools/SmudgeTool.java b/src/main/java/pixelitor/tools/SmudgeTool.java index 898b70cd4..067f0f218 100644 --- a/src/main/java/pixelitor/tools/SmudgeTool.java +++ b/src/main/java/pixelitor/tools/SmudgeTool.java @@ -35,7 +35,7 @@ */ public class SmudgeTool extends AbstractBrushTool { public SmudgeTool() { - super("Smudge", 'K', "smudge_tool_icon.png", + super("Smudge", 'K', "smudge_tool.png", "click and drag to smudge. " + "Click and Shift-click to smudge along a line.", Cursors.HAND, false); diff --git a/src/main/java/pixelitor/tools/Tool.java b/src/main/java/pixelitor/tools/Tool.java index 7d78dc47d..d81da9d96 100644 --- a/src/main/java/pixelitor/tools/Tool.java +++ b/src/main/java/pixelitor/tools/Tool.java @@ -240,7 +240,7 @@ public void viewActivated(View oldCV, View newCV) { } } - public void compReplaced(Composition oldComp, Composition newComp, boolean reloaded) { + public void compReplaced(Composition newComp, boolean reloaded) { // empty by default } @@ -310,7 +310,7 @@ public void activate() { toolButton.doClick(); } else { assert AppContext.isUnitTesting(); - Tools.changeTo(this); + Tools.start(this); } } diff --git a/src/main/java/pixelitor/tools/Tools.java b/src/main/java/pixelitor/tools/Tools.java index 8fe21b432..3b7ae1169 100644 --- a/src/main/java/pixelitor/tools/Tools.java +++ b/src/main/java/pixelitor/tools/Tools.java @@ -24,7 +24,6 @@ import pixelitor.layers.Layer; import pixelitor.tools.crop.CropTool; import pixelitor.tools.gradient.GradientTool; -import pixelitor.tools.gui.ToolButton; import pixelitor.tools.gui.ToolSettingsPanelContainer; import pixelitor.tools.move.MoveTool; import pixelitor.tools.pen.PenTool; @@ -85,30 +84,29 @@ public static void setDefaultTool() { for (Tool tool : allTools) { if (tool.getName().equals(lastToolName)) { found = true; - changeToProgrammatically(tool); + startAndSelect(tool); break; } } if (!found) { // ui language changed - changeToProgrammatically(BRUSH); + startAndSelect(BRUSH); } } @VisibleForTesting - public static void setCurrentTool(Tool currentTool) { - Tools.currentTool = currentTool; + public static void setCurrentTool(Tool newTool) { + currentTool = newTool; } - private static void changeToProgrammatically(Tool tool) { - changeTo(tool); + private static void startAndSelect(Tool newTool) { + start(newTool); - // changeTo doesn't select the button, because it is + // start doesn't select the button, because it is // either called by the button event handler or by testing code - ToolButton button = currentTool.getButton(); - button.setSelected(true); + currentTool.getButton().setSelected(true); } - public static void changeTo(Tool newTool) { + public static void start(Tool newTool) { // showing the message could be useful even if the tool didn't change Messages.showInStatusBar(newTool.getStatusBarMessage()); @@ -122,7 +120,7 @@ public static void changeTo(Tool newTool) { EventDispatcher.toolChanged(previousTool, newTool); } - currentTool = newTool; + setCurrentTool(newTool); newTool.toolStarted(); ToolSettingsPanelContainer.get().showSettingsFor(newTool); } diff --git a/src/main/java/pixelitor/tools/ZoomTool.java b/src/main/java/pixelitor/tools/ZoomTool.java index 52b1757a6..52561c9b6 100644 --- a/src/main/java/pixelitor/tools/ZoomTool.java +++ b/src/main/java/pixelitor/tools/ZoomTool.java @@ -30,7 +30,7 @@ */ public class ZoomTool extends Tool { ZoomTool() { - super(ZOOM, 'Z', "zoom_tool_icon.png", + super(ZOOM, 'Z', "zoom_tool.png", "click to zoom in, " + "right-click (or Alt-click) to zoom out.", Cursors.HAND); diff --git a/src/main/java/pixelitor/tools/brushes/LazyMouseBrush.java b/src/main/java/pixelitor/tools/brushes/LazyMouseBrush.java index 736ad6204..5482f637b 100644 --- a/src/main/java/pixelitor/tools/brushes/LazyMouseBrush.java +++ b/src/main/java/pixelitor/tools/brushes/LazyMouseBrush.java @@ -33,9 +33,7 @@ public class LazyMouseBrush extends BrushDecorator { private static final int DEFAULT_DIST = 30; private static final int MAX_DIST = 200; - private static final int MIN_SPACING = 1; private static final int DEFAULT_SPACING = 3; - private static final int MAX_SPACING = 20; private double mouseX; private double mouseY; @@ -43,7 +41,6 @@ public class LazyMouseBrush extends BrushDecorator { private double drawY; private View view; private double spacing; - private static int defaultSpacing = DEFAULT_SPACING; // the lazy mouse distance is shared between the tools private static int dist = DEFAULT_DIST; @@ -69,14 +66,10 @@ private static void setDist(int value) { dist2 = value * value; } - private static void setDefaultSpacing(int value) { - defaultSpacing = value; - } - private void calcSpacing() { spacing = delegate.getPreferredSpacing(); if (spacing == 0) { - spacing = defaultSpacing; + spacing = DEFAULT_SPACING; } } @@ -152,13 +145,6 @@ public static RangeParam createDistParam() { return param; } - public static RangeParam createSpacingParam() { - RangeParam param = new RangeParam( - "Spacing (px)", MIN_SPACING, defaultSpacing, MAX_SPACING); - param.setAdjustmentListener(() -> setDefaultSpacing(param.getValue())); - return param; - } - public PPoint getDrawPoint() { return PPoint.eagerFromIm(drawX, drawY, view); } diff --git a/src/main/java/pixelitor/tools/crop/CropTool.java b/src/main/java/pixelitor/tools/crop/CropTool.java index f882f62d7..d2a482adc 100644 --- a/src/main/java/pixelitor/tools/crop/CropTool.java +++ b/src/main/java/pixelitor/tools/crop/CropTool.java @@ -78,7 +78,7 @@ public class CropTool extends DragTool { private final CompositionGuide compositionGuide; public CropTool() { - super("Crop", 'C', "crop_tool_icon.png", + super("Crop", 'C', "crop_tool.png", "drag to start or Alt-drag to start form the center. " + "After the handles appear: " + "Shift-drag keeps the aspect ratio, " + @@ -423,7 +423,7 @@ private void setState(DragToolState newState) { } @Override - public void compReplaced(Composition oldComp, Composition newComp, boolean reloaded) { + public void compReplaced(Composition newComp, boolean reloaded) { if (reloaded) { resetInitialState(); } diff --git a/src/main/java/pixelitor/tools/gradient/GradientTool.java b/src/main/java/pixelitor/tools/gradient/GradientTool.java index de9e9cd78..bedc43742 100644 --- a/src/main/java/pixelitor/tools/gradient/GradientTool.java +++ b/src/main/java/pixelitor/tools/gradient/GradientTool.java @@ -68,7 +68,7 @@ public class GradientTool extends DragTool { private boolean ignoreRegenerate = false; public GradientTool() { - super("Gradient", 'G', "gradient_tool_icon.png", + super("Gradient", 'G', "gradient_tool.png", "click and drag to draw a gradient, " + "Shift-drag to constrain the direction. " + "Press Esc or click outside to hide the handles.", @@ -287,7 +287,7 @@ public void resetInitialState() { } @Override - public void compReplaced(Composition oldComp, Composition newComp, boolean reloaded) { + public void compReplaced(Composition newComp, boolean reloaded) { if (reloaded && handles != null) { hideHandles(newComp, false); } diff --git a/src/main/java/pixelitor/tools/gui/ToolButton.java b/src/main/java/pixelitor/tools/gui/ToolButton.java index 633413385..cf56657ab 100644 --- a/src/main/java/pixelitor/tools/gui/ToolButton.java +++ b/src/main/java/pixelitor/tools/gui/ToolButton.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Laszlo Balazs-Csiki and Contributors + * Copyright 2021 Laszlo Balazs-Csiki and Contributors * * This file is part of Pixelitor. Pixelitor is free software: you * can redistribute it and/or modify it under the terms of the GNU @@ -41,7 +41,13 @@ public ToolButton(Tool tool, Dimension preferredSize) { putClientProperty("JComponent.sizeVariant", "mini"); - Icon icon = Icons.load(tool.getIconFileName()); + Icon icon; + if (tool == Tools.SMUDGE) { + icon = Icons.load("smudge_tool.png", + "smudge_tool_2x.png"); + } else { + icon = Icons.load(tool.getIconFileName()); + } setIcon(icon); assert icon.getIconWidth() == 30; @@ -53,7 +59,7 @@ public ToolButton(Tool tool, Dimension preferredSize) { setMargin(new Insets(0, 0, 0, 0)); setBorderPainted(true); setRolloverEnabled(false); - addActionListener(e -> Tools.changeTo(tool)); + addActionListener(e -> Tools.start(tool)); setPreferredSize(preferredSize); } diff --git a/src/main/java/pixelitor/tools/gui/ToolSettingsPanel.java b/src/main/java/pixelitor/tools/gui/ToolSettingsPanel.java index 2ef893266..c51dd76ae 100644 --- a/src/main/java/pixelitor/tools/gui/ToolSettingsPanel.java +++ b/src/main/java/pixelitor/tools/gui/ToolSettingsPanel.java @@ -59,20 +59,22 @@ public void addComboBox(String text, JComboBox box, String name) { addWithLabel(text, box, name); } - public void addButton(Action action, String name, String toolTip) { + public JButton addButton(Action action, String name, String toolTip) { JButton button = new JButton(action); button.setName(name); button.setToolTipText(toolTip); add(button); + return button; } - public void addButton(String text, ActionListener listener, - String name, String toolTip) { + public JButton addButton(String text, ActionListener listener, + String name, String toolTip) { JButton button = new JButton(text); button.setName(name); button.setToolTipText(toolTip); button.addActionListener(listener); add(button); + return button; } public void addCheckBox(String text, boolean selected, String name, diff --git a/src/main/java/pixelitor/tools/gui/ToolsPanel.java b/src/main/java/pixelitor/tools/gui/ToolsPanel.java index 93ee067f7..0cd7601b2 100644 --- a/src/main/java/pixelitor/tools/gui/ToolsPanel.java +++ b/src/main/java/pixelitor/tools/gui/ToolsPanel.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Laszlo Balazs-Csiki and Contributors + * Copyright 2021 Laszlo Balazs-Csiki and Contributors * * This file is part of Pixelitor. Pixelitor is free software: you * can redistribute it and/or modify it under the terms of the GNU @@ -21,13 +21,13 @@ import pixelitor.colors.FgBgColors; import pixelitor.gui.GlobalEvents; import pixelitor.gui.PixelitorWindow; +import pixelitor.gui.utils.PAction; import pixelitor.layers.AddTextLayerAction; import pixelitor.tools.Tool; import pixelitor.tools.Tools; import javax.swing.*; import java.awt.Dimension; -import java.awt.event.ActionEvent; import static javax.swing.BoxLayout.Y_AXIS; @@ -38,16 +38,16 @@ public class ToolsPanel extends JPanel { public ToolsPanel(PixelitorWindow pw, Dimension screenSize) { setLayout(new BoxLayout(this, Y_AXIS)); - addToolButtons(screenSize); + addToolButtons(screenSize, pw); add(Box.createVerticalGlue()); addColorSelector(pw); setupTShortCut(); } - private void addToolButtons(Dimension screenSize) { + private void addToolButtons(Dimension screenSize, PixelitorWindow pw) { ButtonGroup group = new ButtonGroup(); - Dimension buttonSize = calcToolButtonSize(screenSize); + Dimension buttonSize = calcToolButtonSize(screenSize, pw); Tool[] tools = Tools.getAll(); for (Tool tool : tools) { ToolButton toolButton = new ToolButton(tool, buttonSize); @@ -71,10 +71,11 @@ private static void setupTShortCut() { GlobalEvents.addHotKey('T', AddTextLayerAction.INSTANCE); } - private static Dimension calcToolButtonSize(Dimension screen) { + private static Dimension calcToolButtonSize(Dimension screen, PixelitorWindow pw) { // the icons are 30x30 Dimension buttonSize; - if (screen.height <= 768) { // many laptops have 1366x768, minus the taskbar + int threshold = (int) (768 * pw.getHiDPIScaling().getScaleY()); + if (screen.height <= threshold) { // many laptops have 1366x768, minus the taskbar buttonSize = new Dimension(44, 38); // compromise } else { buttonSize = new Dimension(44, 44); // ideal @@ -83,9 +84,9 @@ private static Dimension calcToolButtonSize(Dimension screen) { } private static void setupKeyboardShortcut(Tool tool) { - Action activateAction = new AbstractAction() { + Action activateAction = new PAction() { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { if (Tools.currentTool != tool) { tool.activate(); } diff --git a/src/main/java/pixelitor/tools/move/MoveTool.java b/src/main/java/pixelitor/tools/move/MoveTool.java index 6e1c25fa5..77f4ae6f7 100644 --- a/src/main/java/pixelitor/tools/move/MoveTool.java +++ b/src/main/java/pixelitor/tools/move/MoveTool.java @@ -43,7 +43,7 @@ public class MoveTool extends DragTool { private final JCheckBox autoSelectCheckBox = new JCheckBox(); public MoveTool() { - super("Move", 'V', "move_tool_icon.png", + super("Move", 'V', "move_tool.png", "drag to move the active layer, " + "Alt-drag (or right-mouse-drag) to move a duplicate of the active layer. " + "Shift-drag to constrain the movement.", diff --git a/src/main/java/pixelitor/tools/pen/AnchorPoint.java b/src/main/java/pixelitor/tools/pen/AnchorPoint.java index af3459cd5..3a044cd84 100644 --- a/src/main/java/pixelitor/tools/pen/AnchorPoint.java +++ b/src/main/java/pixelitor/tools/pen/AnchorPoint.java @@ -19,6 +19,7 @@ import pixelitor.AppContext; import pixelitor.gui.View; +import pixelitor.gui.utils.PAction; import pixelitor.history.History; import pixelitor.tools.pen.history.AnchorPointChangeEdit; import pixelitor.tools.pen.history.SubPathEdit; @@ -31,7 +32,6 @@ import java.awt.Color; import java.awt.Graphics2D; import java.awt.IllegalComponentStateException; -import java.awt.event.ActionEvent; import java.awt.geom.AffineTransform; import java.awt.geom.Line2D; @@ -230,9 +230,9 @@ public void showPopup(int x, int y) { popup.addSeparator(); - popup.add(new AbstractAction("Retract Handles") { + popup.add(new PAction("Retract Handles") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { retractHandles(); } }); @@ -240,9 +240,9 @@ public void actionPerformed(ActionEvent e) { popup.addSeparator(); if (AppContext.isDevelopment()) { - popup.add(new AbstractAction("Dump") { + popup.add(new PAction("Dump") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { dump(); } }); @@ -252,26 +252,26 @@ public void actionPerformed(ActionEvent e) { boolean isLastPoint = singleSubPath && subPath.getNumAnchors() == 1; if (!isLastPoint) { - popup.add(new AbstractAction("Delete Point") { + popup.add(new PAction("Delete Point") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { delete(); } }); } if (!singleSubPath) { - popup.add(new AbstractAction("Delete Subpath") { + popup.add(new PAction("Delete Subpath") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { subPath.delete(); } }); } - popup.add(new AbstractAction("Delete Path") { + popup.add(new PAction("Delete Path") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { subPath.deletePath(); } }); diff --git a/src/main/java/pixelitor/tools/pen/AnchorPointType.java b/src/main/java/pixelitor/tools/pen/AnchorPointType.java index c4ec0a44e..70741feda 100644 --- a/src/main/java/pixelitor/tools/pen/AnchorPointType.java +++ b/src/main/java/pixelitor/tools/pen/AnchorPointType.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Laszlo Balazs-Csiki and Contributors + * Copyright 2021 Laszlo Balazs-Csiki and Contributors * * This file is part of Pixelitor. Pixelitor is free software: you * can redistribute it and/or modify it under the terms of the GNU @@ -17,8 +17,9 @@ package pixelitor.tools.pen; +import pixelitor.gui.utils.PAction; + import javax.swing.*; -import java.awt.event.ActionEvent; /** * The type of an anchor point determines how its control @@ -95,9 +96,9 @@ public String toString() { static class AnchorPointTypeMenuItem extends JRadioButtonMenuItem { public AnchorPointTypeMenuItem(AnchorPoint ap, AnchorPointType type) { - super(new AbstractAction(type.toString()) { + super(new PAction(type.toString()) { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { ap.setType(type); } }); diff --git a/src/main/java/pixelitor/tools/pen/Path.java b/src/main/java/pixelitor/tools/pen/Path.java index 8ce4038a2..9bf661fab 100644 --- a/src/main/java/pixelitor/tools/pen/Path.java +++ b/src/main/java/pixelitor/tools/pen/Path.java @@ -88,11 +88,13 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE public Path deepCopy(Composition newComp) { Path copy = new Path(newComp, false); for (SubPath sp : subPaths) { - copy.subPaths.add(sp.deepCopy(copy, newComp)); + SubPath spCopy = sp.deepCopy(copy, newComp); + copy.subPaths.add(spCopy); + + if (sp == activeSubPath) { + copy.activeSubPath = spCopy; + } } - int activeIndex = subPaths.indexOf(activeSubPath); - assert activeIndex != -1 : "Index of " + activeSubPath + " is -1 in " + this; - copy.activeSubPath = copy.subPaths.get(activeIndex); return copy; } diff --git a/src/main/java/pixelitor/tools/pen/PathTransformer.java b/src/main/java/pixelitor/tools/pen/PathTransformer.java index 2f3ac206a..9aefba9cc 100644 --- a/src/main/java/pixelitor/tools/pen/PathTransformer.java +++ b/src/main/java/pixelitor/tools/pen/PathTransformer.java @@ -46,7 +46,11 @@ public class PathTransformer implements PenToolMode { private static final String HELP_MESSAGE = "Pen Tool Transform Mode."; private List boxes; + + // Null if no box is being dragged. private TransformBox draggedBox; + + // The receiver of keyboard nudges. Never null. private TransformBox lastActiveBox; private PathTransformer() { @@ -87,16 +91,7 @@ public void imCoordsChanged(AffineTransform at, Composition comp) { @Override public void compReplaced(Composition newComp) { - // the transform boxes store references to - // the old subpaths, they need to be updated - assert path.getNumSubpaths() == boxes.size(); - for (int i = 0; i < boxes.size(); i++) { - SubPath subPath = path.getSubPath(i); - TransformBox box = boxes.get(i); - box.replaceOwner(subPath); - - subPath.storeTransformRefPoints(); - } + initBoxes(); } @Override @@ -168,7 +163,6 @@ public boolean mouseMoved(MouseEvent e, View view) { boolean contained = false; for (TransformBox box : boxes) { if (box.contains(x, y)) { - view.setCursor(MOVE); contained = true; break; } @@ -198,10 +192,13 @@ public void start() { } @Override - public void modeStarted(PenToolMode prevMode, Path path) { - PenToolMode.super.modeStarted(prevMode, path); - boxes = path.createTransformBoxes(); + public void modeStarted(PenToolMode prevMode) { + PenToolMode.super.modeStarted(prevMode); + initBoxes(); + } + private void initBoxes() { + boxes = path.createTransformBoxes(); if (!boxes.isEmpty()) { lastActiveBox = boxes.get(0); } else { diff --git a/src/main/java/pixelitor/tools/pen/PenTool.java b/src/main/java/pixelitor/tools/pen/PenTool.java index f7ab957f9..9fe638760 100644 --- a/src/main/java/pixelitor/tools/pen/PenTool.java +++ b/src/main/java/pixelitor/tools/pen/PenTool.java @@ -22,6 +22,7 @@ import pixelitor.OpenImages; import pixelitor.gui.View; import pixelitor.gui.utils.Dialogs; +import pixelitor.gui.utils.PAction; import pixelitor.history.History; import pixelitor.history.PixelitorEdit; import pixelitor.tools.Tool; @@ -39,7 +40,6 @@ import java.awt.EventQueue; import java.awt.Graphics2D; import java.awt.Shape; -import java.awt.event.ActionEvent; import java.awt.event.MouseEvent; import java.awt.geom.AffineTransform; @@ -54,9 +54,8 @@ public class PenTool extends Tool { private final ComboBoxModel modeModel = new DefaultComboBoxModel<>(new PenToolMode[]{BUILD, EDIT, TRANSFORM}); - private final AbstractAction toSelectionAction; - // private final AbstractAction traceAction; - private final AbstractAction dumpPathAction; + private final Action toSelectionAction; + private final Action dumpPathAction; private final JLabel rubberBandLabel = new JLabel("Show Rubber Band:"); private final JCheckBox rubberBandCB = new JCheckBox("", true); @@ -68,38 +67,39 @@ public class PenTool extends Tool { private boolean rubberBand = true; - private static final Action traceWithBrush = new TraceAction( + private static final Action traceWithBrushAction = new TraceAction( "Stroke with Current Brush", Tools.BRUSH); - private static final Action traceWithEraser = new TraceAction( + private static final Action traceWithEraserAction = new TraceAction( "Stroke with Current Eraser", Tools.ERASER); - private static final Action traceWithSmudge = new TraceAction( + private static final Action traceWithSmudgeAction = new TraceAction( "Stroke with Current Smudge", Tools.SMUDGE); + private static final Action deletePath = new PAction("Delete Path") { + @Override + public void onClick() { + path.delete(); + } + }; + public PenTool() { - super("Pen", 'P', "pen_tool_icon.png", + super("Pen", 'P', "pen_tool.png", "", // getStatusBarMessage() is overridden Cursors.DEFAULT); - toSelectionAction = new AbstractAction("Convert to Selection") { + toSelectionAction = new PAction("Convert to Selection") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { convertToSelection(); } }; -// traceAction = new AbstractAction("Trace...") { -// @Override -// public void actionPerformed(ActionEvent e) { -// TracePathPanel.showInDialog(path); -// } -// }; - dumpPathAction = new AbstractAction("Dump") { + dumpPathAction = new PAction("Dump") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { assert hasPath(); path.dump(); } }; - enableActionsBasedOnFinishedPath(false); + enableActions(false); } @Override @@ -121,12 +121,14 @@ public void initSettingsPanel() { // settingsPanel.addButton(traceAction, "traceAction", // "Trace the path with a stroke or with a tool"); - settingsPanel.addButton(traceWithBrush, "traceWithBrush", + settingsPanel.addButton(traceWithBrushAction, "traceWithBrush", "Stroke the path using the current settings of the Brush Tool"); - settingsPanel.addButton(traceWithEraser, "traceWithEraser", + settingsPanel.addButton(traceWithEraserAction, "traceWithEraser", "Stroke the path using the current settings of the Eraser Tool"); - settingsPanel.addButton(traceWithSmudge, "traceWithSmudge", + settingsPanel.addButton(traceWithSmudgeAction, "traceWithSmudge", "Stroke the path using the current settings of the Smudge Tool"); + settingsPanel.addButton(deletePath, "deletePath", + "Delete the path"); if (AppContext.isDevelopment()) { settingsPanel.addButton(dumpPathAction, "dumpPathAction", ""); @@ -160,7 +162,7 @@ public void startBuilding(boolean calledFromModeChooser) { ignoreModeChooser = false; } changeMode(BUILD, path); - enableActionsBasedOnFinishedPath(hasPath()); + enableActions(hasPath()); OpenImages.repaintActive(); assert checkPathConsistency(); @@ -196,7 +198,7 @@ public void startRestrictedMode(PenToolMode mode, boolean calledFromModeChooser) } changeMode(mode, path); - enableActionsBasedOnFinishedPath(true); + enableActions(true); OpenImages.repaintActive(); assert checkPathConsistency(); @@ -207,7 +209,7 @@ public void startRestrictedMode(PenToolMode mode, boolean calledFromModeChooser) private void changeMode(PenToolMode mode, Path path) { if (this.mode != mode) { this.mode.modeEnded(); - mode.modeStarted(this.mode, path); + mode.modeStarted(this.mode); } this.mode = mode; @@ -327,7 +329,7 @@ public void viewActivated(View oldCV, View newCV) { } @Override - public void compReplaced(Composition oldComp, Composition newComp, boolean reloaded) { + public void compReplaced(Composition newComp, boolean reloaded) { if (newComp.isActive()) { // reloading is asynchronous, the view might not be active anymore setPathFromComp(newComp); @@ -358,7 +360,7 @@ protected void toolStarted() { assert path == null; } - mode.modeStarted(null, path); + mode.modeStarted(null); assert checkPathConsistency(); } @@ -399,7 +401,7 @@ private void setPathFromComp(Composition comp) { } comp.repaint(); } - enableActionsBasedOnFinishedPath(path != null); + enableActions(path != null); } private void setNullPath() { @@ -426,7 +428,7 @@ public void setPath(Path path) { public void removePath() { OpenImages.setActivePath(null); setNullPath(); - enableActionsBasedOnFinishedPath(false); + enableActions(false); } @Override @@ -438,14 +440,15 @@ protected void toolEnded() { } // TODO enable them while building, as soon as the path != null - public void enableActionsBasedOnFinishedPath(boolean b) { + public void enableActions(boolean b) { toSelectionAction.setEnabled(b); - traceWithBrush.setEnabled(b); - traceWithEraser.setEnabled(b); - traceWithSmudge.setEnabled(b); + traceWithBrushAction.setEnabled(b); + traceWithEraserAction.setEnabled(b); + traceWithSmudgeAction.setEnabled(b); // traceAction.setEnabled(b); + deletePath.setEnabled(b); dumpPathAction.setEnabled(b); } @@ -462,16 +465,16 @@ public static boolean hasPath() { return path != null; } - public static Action getTraceWithBrush() { - return traceWithBrush; + public static Action getTraceWithBrushAction() { + return traceWithBrushAction; } - public static Action getTraceWithEraser() { - return traceWithEraser; + public static Action getTraceWithEraserAction() { + return traceWithEraserAction; } - public static Action getTraceWithSmudge() { - return traceWithSmudge; + public static Action getTraceWithSmudgeAction() { + return traceWithSmudgeAction; } @Override diff --git a/src/main/java/pixelitor/tools/pen/PenToolMode.java b/src/main/java/pixelitor/tools/pen/PenToolMode.java index 3befcbeb4..826ba2143 100644 --- a/src/main/java/pixelitor/tools/pen/PenToolMode.java +++ b/src/main/java/pixelitor/tools/pen/PenToolMode.java @@ -60,7 +60,7 @@ default void compReplaced(Composition newComp) { boolean requiresExistingPath(); - default void modeStarted(PenToolMode prevMode, Path path) { + default void modeStarted(PenToolMode prevMode) { if (path != null) { path.setPreferredPenToolMode(this); } diff --git a/src/main/java/pixelitor/tools/pen/SubPath.java b/src/main/java/pixelitor/tools/pen/SubPath.java index a6cc36173..0d2efb1c7 100644 --- a/src/main/java/pixelitor/tools/pen/SubPath.java +++ b/src/main/java/pixelitor/tools/pen/SubPath.java @@ -31,8 +31,10 @@ import pixelitor.tools.util.DraggablePoint; import pixelitor.utils.VisibleForTesting; import pixelitor.utils.debug.Ansi; +import pixelitor.utils.debug.DebugNode; import java.awt.Graphics2D; +import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.geom.Rectangle2D; @@ -73,6 +75,10 @@ public class SubPath implements Serializable, Transformable { private boolean closed = false; private boolean finished = false; + // caching the transform box ensures that its + // image-space coordinates are correct after undo + private transient TransformBox box; + public SubPath(Path path, Composition comp) { assert path != null; assert comp != null; @@ -159,6 +165,12 @@ public void addToComponentSpaceShape(GeneralPath path) { addToShape(path, p -> p.x, p1 -> p1.y); } + public Shape toComponentSpaceShape() { + GeneralPath gp = new GeneralPath(); + addToComponentSpaceShape(gp); + return gp; + } + public void addToImageSpaceShape(GeneralPath path) { addToShape(path, p -> p.imX, p1 -> p1.imY); } @@ -595,7 +607,7 @@ public void finish(Composition comp, boolean addToHistory) { setFinished(true); path.setBuildState(NO_INTERACTION); comp.setActivePath(path); - Tools.PEN.enableActionsBasedOnFinishedPath(true); + Tools.PEN.enableActions(true); if (addToHistory) { History.add(new FinishSubPathEdit(comp, this)); @@ -669,21 +681,30 @@ public void addQuadCurve(double cx, double cy, } public TransformBox createTransformBox() { + if (box != null) { + return box; + } + if (isEmpty()) { + return null; + } storeTransformRefPoints(); - GeneralPath gp = new GeneralPath(); - addToComponentSpaceShape(gp); - - assert ShapeUtils.isValid(gp) : "invalid shape for " + toDetailedString(); + Shape coShape = toComponentSpaceShape(); - Rectangle2D coBoundingBox = gp.getBounds2D(); + assert ShapeUtils.isValid(coShape) : "invalid shape for " + toDetailedString(); + Rectangle2D coBoundingBox = coShape.getBounds2D(); if (coBoundingBox.isEmpty()) { - // it can happen that a subpath consists of a single point + // it can still be empty if all x or y coordinates are the same return null; } - return new TransformBox(coBoundingBox, comp.getView(), this); + box = new TransformBox(coBoundingBox, comp.getView(), this); + return box; + } + + public boolean isEmpty() { + return getNumAnchors() < 2; } @Override @@ -695,7 +716,9 @@ public void transform(AffineTransform at) { @Override public void updateUI(View view) { - assert view.getComp() == comp; + assert view.getComp() == comp : + "subpath comp = " + comp.getDebugName() + + ", view comp = " + view.getComp().getDebugName(); comp.repaint(); } @@ -722,6 +745,30 @@ public int hashCode() { return Objects.hash(id); } + public boolean isActive() { + return path.getActiveSubpath() == this; + } + + @Override + public DebugNode createDebugNode() { + String name = isActive() ? "active " : ""; + name += "subpath " + getId(); + + var node = new DebugNode(name, this); + + node.addString("comp debug name", comp.getDebugName()); + node.addString("name", getId()); + node.addBoolean("closed", isClosed()); + node.addBoolean("finished", isFinished()); + node.addBoolean("has moving point", hasMovingPoint()); + + for (AnchorPoint point : anchorPoints) { + node.add(point.createDebugNode()); + } + + return node; + } + @VisibleForTesting public String getId() { return id; diff --git a/src/main/java/pixelitor/tools/shapes/ShapesTool.java b/src/main/java/pixelitor/tools/shapes/ShapesTool.java index a065bc648..5582fab4a 100644 --- a/src/main/java/pixelitor/tools/shapes/ShapesTool.java +++ b/src/main/java/pixelitor/tools/shapes/ShapesTool.java @@ -29,6 +29,7 @@ import pixelitor.gui.utils.DialogBuilder; import pixelitor.gui.utils.Dialogs; import pixelitor.gui.utils.GUIUtils; +import pixelitor.gui.utils.PAction; import pixelitor.history.History; import pixelitor.history.PixelitorEdit; import pixelitor.layers.Drawable; @@ -51,7 +52,6 @@ import java.awt.Graphics2D; import java.awt.Shape; import java.awt.Stroke; -import java.awt.event.ActionEvent; import java.awt.event.MouseEvent; import java.awt.geom.AffineTransform; import java.util.EnumMap; @@ -89,9 +89,10 @@ public class ShapesTool extends DragTool { private final StrokeParam strokeParam = new StrokeParam(""); - private final AbstractAction shapeSettingsAction = new AbstractAction("Settings...") { + private JButton showShapeSettingsButton; + private final Action shapeSettingsAction = new PAction("Settings...") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { showShapeSettingsDialog(); } }; @@ -106,9 +107,11 @@ public void actionPerformed(ActionEvent e) { private final JComboBox strokePaintCombo = createStrokePaintCombo(); + private JButton showStrokeDialogButton; private Action strokeSettingsAction; private JDialog strokeSettingsDialog; + private JButton showEffectsDialogButton; private JDialog effectsDialog; private StyledShape styledShape; @@ -116,15 +119,15 @@ public void actionPerformed(ActionEvent e) { private DragToolState state = NO_INTERACTION; - private final Action convertToSelectionAction = new AbstractAction("Convert to Selection") { + private final Action convertToSelectionAction = new PAction("Convert to Selection") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { convertToSelection(); } }; public ShapesTool() { - super("Shapes", 'U', "shapes_tool_icon.png", + super("Shapes", 'U', "shapes_tool.png", "drag to draw a shape. " + "Hold Alt down to drag from the center. " + "Hold SPACE down while drawing to move the shape. ", @@ -141,24 +144,25 @@ public void initSettingsPanel() { JComboBox shapeTypeCB = createShapeTypeCombo(); settingsPanel.addComboBox("Shape:", shapeTypeCB, "shapeTypeCB"); - settingsPanel.addButton(shapeSettingsAction, "shapeSettingsButton", + showShapeSettingsButton = settingsPanel.addButton(shapeSettingsAction, "shapeSettingsButton", "Configure the selected shape"); settingsPanel.addSeparator(); settingsPanel.addComboBox("Fill:", fillPaintCombo, "fillPaintCB"); settingsPanel.addComboBox("Stroke:", strokePaintCombo, "strokePaintCB"); - strokeSettingsAction = new AbstractAction("Stroke Settings...") { + strokeSettingsAction = new PAction("Stroke Settings...") { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { initAndShowStrokeSettingsDialog(); } }; - settingsPanel.addButton(strokeSettingsAction, + showStrokeDialogButton = settingsPanel.addButton(strokeSettingsAction, "strokeSettingsButton", "Configure the stroke"); - settingsPanel.addButton("Effects...", e -> showEffectsDialog(), + showEffectsDialogButton = settingsPanel.addButton("Effects...", + e -> showEffectsDialog(), "effectsButton", "Configure the effects"); settingsPanel.addButton(convertToSelectionAction, "convertToSelection", @@ -270,12 +274,13 @@ private void showShapeSettingsDialog() { .content(configPanel) .noCancelButton() .okText(GUIText.CLOSE_DIALOG) + .parentComponent(showShapeSettingsButton) .show(); } private void showEffectsDialog() { effectsDialog = effectsParam.buildDialog(null, false); - GUIUtils.showDialog(effectsDialog); + GUIUtils.showDialog(effectsDialog, showEffectsDialogButton); } @Override @@ -466,7 +471,7 @@ private void updateStrokeEnabledState() { private void initAndShowStrokeSettingsDialog() { strokeSettingsDialog = createStrokeSettingsDialog(); - GUIUtils.showDialog(strokeSettingsDialog); + GUIUtils.showDialog(strokeSettingsDialog, showStrokeDialogButton); } private void closeEffectsDialog() { @@ -586,7 +591,7 @@ public void resetInitialState() { } @Override - public void compReplaced(Composition oldComp, Composition newComp, boolean reloaded) { + public void compReplaced(Composition newComp, boolean reloaded) { if (reloaded) { resetInitialState(); } diff --git a/src/main/java/pixelitor/tools/shapes/StyledShape.java b/src/main/java/pixelitor/tools/shapes/StyledShape.java index 4413f9731..a56c623f8 100644 --- a/src/main/java/pixelitor/tools/shapes/StyledShape.java +++ b/src/main/java/pixelitor/tools/shapes/StyledShape.java @@ -545,6 +545,7 @@ public Shape getShapeForSelection() { } } + @Override public DebugNode createDebugNode() { var node = new DebugNode("styled shape", this); node.addString("type", shapeType.toString()); diff --git a/src/main/java/pixelitor/tools/transform/TransformBox.java b/src/main/java/pixelitor/tools/transform/TransformBox.java index 5e3e841dc..52974291c 100644 --- a/src/main/java/pixelitor/tools/transform/TransformBox.java +++ b/src/main/java/pixelitor/tools/transform/TransformBox.java @@ -605,6 +605,7 @@ public RotationHandle getRot() { public DebugNode createDebugNode() { var node = new DebugNode("transform box", this); + node.add(owner.createDebugNode()); node.add(nw.createDebugNode()); node.add(ne.createDebugNode()); node.add(se.createDebugNode()); diff --git a/src/main/java/pixelitor/tools/transform/Transformable.java b/src/main/java/pixelitor/tools/transform/Transformable.java index 28edd5aed..a4284fd4c 100644 --- a/src/main/java/pixelitor/tools/transform/Transformable.java +++ b/src/main/java/pixelitor/tools/transform/Transformable.java @@ -18,6 +18,7 @@ package pixelitor.tools.transform; import pixelitor.gui.View; +import pixelitor.utils.debug.DebugNode; import java.awt.geom.AffineTransform; @@ -37,4 +38,6 @@ public interface Transformable { * shapes tool, because the image has to be recalculated. */ void updateUI(View view); + + DebugNode createDebugNode(); } diff --git a/src/main/java/pixelitor/tools/util/DraggablePoint.java b/src/main/java/pixelitor/tools/util/DraggablePoint.java index 455b812a4..e459d4dc9 100644 --- a/src/main/java/pixelitor/tools/util/DraggablePoint.java +++ b/src/main/java/pixelitor/tools/util/DraggablePoint.java @@ -403,16 +403,22 @@ public String toColoredString() { name, x, y, imX, imY); } + private String toCoordsString() { + return format("co: (%.1f, %.1f) im:(%.1f, %.1f)", x, y, imX, imY); + } + @Override public String toString() { - return format("%s {x = %.2f, y = %.2f}{imX = %.1f, imY = %.1f}", - name, x, y, imX, imY); + return format("%s {%s}", name, toCoordsString()); } public DebugNode createDebugNode() { var node = new DebugNode(name, this); - node.addDouble("x", getX()); - node.addDouble("y", getY()); + node.addString("coords", toCoordsString()); + if (imTransformRefPoint != null) { + node.addDouble("ref X", imTransformRefPoint.getX()); + node.addDouble("ref Y", imTransformRefPoint.getY()); + } return node; } } diff --git a/src/main/java/pixelitor/utils/Icons.java b/src/main/java/pixelitor/utils/Icons.java index 2d45f0bf5..1a429f7b5 100644 --- a/src/main/java/pixelitor/utils/Icons.java +++ b/src/main/java/pixelitor/utils/Icons.java @@ -16,7 +16,13 @@ */ package pixelitor.utils; +import pixelitor.gui.utils.Dialogs; + +import javax.imageio.ImageIO; import javax.swing.*; +import java.awt.image.BaseMultiResolutionImage; +import java.awt.image.BufferedImage; +import java.io.IOException; import java.net.URL; /** @@ -28,8 +34,8 @@ public final class Icons { private static final Icon dice2Icon = load("dice2.png"); private static final Icon northArrowIcon = load("north_arrow.gif"); private static final Icon southArrowIcon = load("south_arrow.gif"); - private static final Icon textLayerIcon = load("text_layer_icon.png"); - private static final Icon adjLayerIcon = load("adj_layer_icon.png"); + private static final Icon textLayerIcon = load("text_layer.png"); + private static final Icon adjLayerIcon = load("adj_layer.png"); private static final Icon undoIcon = load("undo.png"); private static final Icon redoIcon = load("redo.png"); private static final Icon searchIcon = load("search.png"); @@ -57,6 +63,21 @@ public static Icon load(String iconFileName) { return new ImageIcon(imgURL); } + public static Icon load(String baseIconFileName, String bigIconFileName) { + try { + URL imgURL1 = ImageUtils.imagePathToURL(baseIconFileName); + BufferedImage img1 = ImageIO.read(imgURL1); + + URL imgURL2 = ImageUtils.imagePathToURL(bigIconFileName); + BufferedImage img2 = ImageIO.read(imgURL2); + + return new ImageIcon(new BaseMultiResolutionImage(img1, img2)); + } catch (IOException e) { + Dialogs.showExceptionDialog(e); + return null; + } + } + public static Icon getNorthArrowIcon() { return northArrowIcon; } diff --git a/src/main/java/pixelitor/utils/debug/CompositionNode.java b/src/main/java/pixelitor/utils/debug/CompositionNode.java index 880d85673..b6820559a 100644 --- a/src/main/java/pixelitor/utils/debug/CompositionNode.java +++ b/src/main/java/pixelitor/utils/debug/CompositionNode.java @@ -34,7 +34,11 @@ */ public class CompositionNode extends DebugNode { public CompositionNode(Composition comp) { - super("composition", comp); + this("composition", comp); + } + + public CompositionNode(String name, Composition comp) { + super(name, comp); comp.forEachLayer(this::addLayerNode); @@ -57,6 +61,7 @@ public CompositionNode(Composition comp) { addInt("num layers", comp.getNumLayers()); addQuotedString("name", comp.getName()); + addQuotedString("debug name", comp.getDebugName()); String filePath = ""; File file = comp.getFile(); diff --git a/src/main/java/pixelitor/utils/debug/Debug.java b/src/main/java/pixelitor/utils/debug/Debug.java index 30b204205..1fd681415 100644 --- a/src/main/java/pixelitor/utils/debug/Debug.java +++ b/src/main/java/pixelitor/utils/debug/Debug.java @@ -65,7 +65,7 @@ private Debug() { // shouldn't be instantiated } - public static String dateBufferTypeAsString(int type) { + public static String dataBufferTypeAsString(int type) { return switch (type) { case DataBuffer.TYPE_BYTE -> "BYTE"; case DataBuffer.TYPE_USHORT -> "USHORT"; @@ -263,7 +263,7 @@ private static void replaceImageInDebugComp(Composition comp, BufferedImage copy comp.getActiveDrawableOrThrow().setImage(copy); if (canvas.hasDifferentSizeThan(copy)) { - canvas.changeSize(copy.getWidth(), copy.getHeight(), comp.getView()); + canvas.changeSize(copy.getWidth(), copy.getHeight(), comp.getView(), true); } comp.repaint(); diff --git a/src/main/java/pixelitor/utils/debug/DebugNodes.java b/src/main/java/pixelitor/utils/debug/DebugNodes.java index 70036774d..5d3ed2d1f 100644 --- a/src/main/java/pixelitor/utils/debug/DebugNodes.java +++ b/src/main/java/pixelitor/utils/debug/DebugNodes.java @@ -24,7 +24,6 @@ import pixelitor.guides.Guides; import pixelitor.tools.pen.Path; import pixelitor.tools.pen.Paths; -import pixelitor.tools.pen.SubPath; import pixelitor.utils.Utils; import java.awt.GraphicsEnvironment; @@ -51,13 +50,9 @@ public static DebugNode createSystemNode() { node.addString("OS name", System.getProperty("os.name")); var displayMode = device.getDisplayMode(); - - int width = displayMode.getWidth(); - int height = displayMode.getHeight(); - int bitDepth = displayMode.getBitDepth(); - node.addInt("display width", width); - node.addInt("display height", height); - node.addInt("display bit depth", bitDepth); + node.addInt("display width", displayMode.getWidth()); + node.addInt("display height", displayMode.getHeight()); + node.addInt("display bit depth", displayMode.getBitDepth()); var pw = PixelitorWindow.get(); node.addInt("app window width", pw.getWidth()); @@ -66,11 +61,8 @@ public static DebugNode createSystemNode() { node.addString("max memory", Utils.getMaxHeapInMegabytes() + " Mb"); node.addString("used memory", Utils.getUsedMemoryInMegabytes() + " Mb"); - var configuration = device.getDefaultConfiguration(); - var defaultColorModel = configuration.getColorModel(); - - var colorModelNode = createColorModelNode("default color model", defaultColorModel); - node.add(colorModelNode); + node.add(createColorModelNode("default color model", + device.getDefaultConfiguration().getColorModel())); return node; } @@ -82,29 +74,22 @@ public static DebugNode createViewNode(String name, View view) { node.add(new CompositionNode(comp)); node.addQuotedString("name", comp.getName()); - node.addQuotedString("mask view mode", view.getMaskViewMode().toString()); - int width = view.getWidth(); - node.addInt("view width", width); - int height = view.getHeight(); - node.addInt("view height", height); + node.addInt("view width", view.getWidth()); + node.addInt("view height", view.getHeight()); var viewContainer = view.getViewContainer(); if (viewContainer instanceof ImageFrame) { var frame = (ImageFrame) viewContainer; - int frameWidth = frame.getWidth(); - node.addInt("frame width", frameWidth); - int frameHeight = frame.getHeight(); - node.addInt("frame height", frameHeight); + node.addInt("frame width", frame.getWidth()); + node.addInt("frame height", frame.getHeight()); } node.addString("zoom level", view.getZoomLevel().toString()); Canvas canvas = view.getCanvas(); - int zoomedCanvasWidth = canvas.getCoWidth(); - node.addInt("zoomed canvas width", zoomedCanvasWidth); - int zoomedCanvasHeight = canvas.getCoHeight(); - node.addInt("zoomed canvas height", zoomedCanvasHeight); + node.addInt("zoomed canvas width", canvas.getCoWidth()); + node.addInt("zoomed canvas height", canvas.getCoHeight()); return node; } @@ -126,12 +111,8 @@ private static DebugNode createRasterNode(WritableRaster raster) { var node = new DebugNode("writable raster", raster); node.addClass(); - - var sampleModel = raster.getSampleModel(); - node.add(createSampleModelNode(sampleModel)); - - var dataBuffer = raster.getDataBuffer(); - node.add(createDataBufferNode(dataBuffer)); + node.add(createSampleModelNode(raster.getSampleModel())); + node.add(createDataBufferNode(raster.getDataBuffer())); return node; } @@ -140,24 +121,14 @@ private static DebugNode createSampleModelNode(SampleModel sampleModel) { var node = new DebugNode("sample model", sampleModel); node.addClass(); - - int width = sampleModel.getWidth(); - node.addInt("width", width); - - int height = sampleModel.getHeight(); - node.addInt("height", height); - - int dataType = sampleModel.getDataType(); - node.addString("data type", Debug.dateBufferTypeAsString(dataType)); - - int numBands = sampleModel.getNumBands(); - node.addInt("num bands", numBands); - - int transferType = sampleModel.getTransferType(); - node.addString("transfer type", Debug.dateBufferTypeAsString(transferType)); - - int numDataElements = sampleModel.getNumDataElements(); - node.addInt("num data elements", numDataElements); + node.addInt("width", sampleModel.getWidth()); + node.addInt("height", sampleModel.getHeight()); + node.addString("data type", + Debug.dataBufferTypeAsString(sampleModel.getDataType())); + node.addInt("num bands", sampleModel.getNumBands()); + node.addString("transfer type", + Debug.dataBufferTypeAsString(sampleModel.getTransferType())); + node.addInt("num data elements", sampleModel.getNumDataElements()); return node; } @@ -166,36 +137,26 @@ private static DebugNode createDataBufferNode(DataBuffer dataBuffer) { var node = new DebugNode("data buffer", dataBuffer); node.addClass(); - - int numBanks = dataBuffer.getNumBanks(); - node.addInt("num banks", numBanks); - - int type = dataBuffer.getDataType(); - node.addString("type", Debug.dateBufferTypeAsString(type)); - - int size = dataBuffer.getSize(); - node.addInt("size", size); + node.addInt("num banks", dataBuffer.getNumBanks()); + node.addString("type", Debug.dataBufferTypeAsString(dataBuffer.getDataType())); + node.addInt("size", dataBuffer.getSize()); return node; } private static DebugNode createColorModelNode(String name, ColorModel colorModel) { var node = new DebugNode(name, colorModel); - node.addClass(); + node.addClass(); node.add(createColorSpaceNode(colorModel.getColorSpace())); - node.addInt("num color components", colorModel.getNumColorComponents()); node.addInt("num components", colorModel.getNumComponents()); node.addBoolean("has alpha", colorModel.hasAlpha()); node.addInt("pixel size", colorModel.getPixelSize()); - node.addString("transfer type", - Debug.dateBufferTypeAsString(colorModel.getTransferType())); - + Debug.dataBufferTypeAsString(colorModel.getTransferType())); node.addString("transparency", Debug.transparencyAsString(colorModel.getTransparency())); - node.addBoolean("is RGB", Debug.isRgbColorModel(colorModel)); node.addBoolean("is BGR", Debug.isBgrColorModel(colorModel)); @@ -206,15 +167,9 @@ private static DebugNode createColorSpaceNode(ColorSpace colorSpace) { var node = new DebugNode("color space", colorSpace); node.addClass(); - - int numComponents = colorSpace.getNumComponents(); - node.addInt("num components", numComponents); - - int type = colorSpace.getType(); - node.addString("type", Debug.colorSpaceTypeAsString(type)); - - boolean sRGB = colorSpace.isCS_sRGB(); - node.addBoolean("sRGB", sRGB); + node.addInt("num components", colorSpace.getNumComponents()); + node.addString("type", Debug.colorSpaceTypeAsString(colorSpace.getType())); + node.addBoolean("sRGB", colorSpace.isCS_sRGB()); return node; } @@ -254,33 +209,11 @@ public static DebugNode createPathNode(Path path) { node.addInt("number of subpaths", numSubpaths); node.addString("build state", path.getBuildState().toString()); - var activeSubpath = path.getActiveSubpath(); for (int i = 0; i < numSubpaths; i++) { var subPath = path.getSubPath(i); - if (subPath == activeSubpath) { - node.add(createSubpathNode( - "active subpath " + subPath.getId(), - subPath)); - } else { - node.add(createSubpathNode(subPath)); - } + node.add(subPath.createDebugNode()); } return node; } - - private static DebugNode createSubpathNode(SubPath subPath) { - return createSubpathNode("subpath " + subPath.getId(), subPath); - } - - private static DebugNode createSubpathNode(String name, SubPath subPath) { - var node = new DebugNode(name, subPath); - - node.addString("name", subPath.getId()); - node.addBoolean("closed", subPath.isClosed()); - node.addBoolean("finished", subPath.isFinished()); - node.addBoolean("has moving point", subPath.hasMovingPoint()); - - return node; - } } diff --git a/src/main/java/pixelitor/utils/test/Events.java b/src/main/java/pixelitor/utils/test/Events.java index e097fa478..e9c0b967a 100644 --- a/src/main/java/pixelitor/utils/test/Events.java +++ b/src/main/java/pixelitor/utils/test/Events.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 Laszlo Balazs-Csiki and Contributors + * Copyright 2021 Laszlo Balazs-Csiki and Contributors * * This file is part of Pixelitor. Pixelitor is free software: you * can redistribute it and/or modify it under the terms of the GNU @@ -18,7 +18,6 @@ package pixelitor.utils.test; import pixelitor.Composition; -import pixelitor.OpenImages; import pixelitor.gui.View; import pixelitor.history.PixelitorEdit; import pixelitor.layers.Layer; @@ -105,16 +104,6 @@ public static void postProgramError(String s, Composition comp, Layer layer) { post(new PixelitorEvent("[PROGRAM ERROR: " + s + "]", comp, layer)); } - /** - * Dumps the last events for the active Composition. - */ - public static void dumpForActiveComp() { - var comp = OpenImages.getActiveComp(); - events.stream() - .filter(e -> e.isComp(comp)) - .forEach(System.out::println); - } - public static void dumpMouse() { events.stream() .filter(e -> e.toString().startsWith("[MOUSE]")) diff --git a/src/main/java/pixelitor/utils/test/PixelitorEvent.java b/src/main/java/pixelitor/utils/test/PixelitorEvent.java index 7572b9111..943cad40b 100644 --- a/src/main/java/pixelitor/utils/test/PixelitorEvent.java +++ b/src/main/java/pixelitor/utils/test/PixelitorEvent.java @@ -22,6 +22,7 @@ import pixelitor.OpenImages; import pixelitor.layers.Layer; import pixelitor.utils.Threads; +import pixelitor.utils.debug.Ansi; import java.awt.geom.Rectangle2D; import java.time.LocalTime; @@ -81,18 +82,18 @@ private String stateAsString(String type) { return format("%s (%s) no composition", type, threadName); } - String layerType = layer.getClass().getSimpleName(); - String formattedDate = dateFormatter.format(now); return format("%s (%s) on \"%s/%s\" (%s, %s, %s) at %s", - type, threadName, comp.getName(), layer.getName(), - layerType, getSelectionInfo(), getMaskInfo(), formattedDate); + type, Ansi.yellow(threadName), Ansi.red(comp.getName()), layer.getName(), + layer.getClass().getSimpleName(), getSelectionInfo(), getMaskInfo(), + dateFormatter.format(now)); } private String getSelectionInfo() { String selectionInfo = "no selection"; if (comp.hasSelection()) { - Rectangle2D rect = comp.getSelection().getShapeBounds2D(); - selectionInfo = format("sel. bounds = '%s'", rect); + Rectangle2D bounds = comp.getSelection().getShapeBounds2D(); + selectionInfo = format("sel. bounds = ['x=%.1f, y=%.1f, w=%.1f, h=%.1f']", + bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight()); } return selectionInfo; } @@ -106,13 +107,6 @@ private String getMaskInfo() { return maskInfo; } - public boolean isComp(Composition c) { - if (c == null) { - return true; - } - return comp == c; - } - @Override public String toString() { return message; diff --git a/src/main/java/pixelitor/utils/test/RandomGUITest.java b/src/main/java/pixelitor/utils/test/RandomGUITest.java index d68f5729b..9d8055db5 100644 --- a/src/main/java/pixelitor/utils/test/RandomGUITest.java +++ b/src/main/java/pixelitor/utils/test/RandomGUITest.java @@ -36,6 +36,7 @@ import pixelitor.filters.util.FilterUtils; import pixelitor.gui.*; import pixelitor.gui.utils.GUIUtils; +import pixelitor.gui.utils.PAction; import pixelitor.guides.Guides; import pixelitor.history.History; import pixelitor.layers.*; @@ -141,9 +142,9 @@ public static void start() { numPastedImages = 0; // make sure it can be stopped by pressing a key - GlobalEvents.addHotKey(PAUSE_KEY_CHAR, new AbstractAction() { + GlobalEvents.addHotKey(PAUSE_KEY_CHAR, new PAction() { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { System.err.printf("%nRandomGUITest: '%s' pressed.%n", PAUSE_KEY_CHAR); stopRunning = true; } @@ -152,9 +153,9 @@ public void actionPerformed(ActionEvent e) { stopRunning = false; // This key not only stops the testing, but also exits the app - GlobalEvents.addHotKey(EXIT_KEY_CHAR, new AbstractAction() { + GlobalEvents.addHotKey(EXIT_KEY_CHAR, new PAction() { @Override - public void actionPerformed(ActionEvent e) { + public void onClick() { System.err.printf("%nRandomGUITest: exiting app because '%s' was pressed.%n", EXIT_KEY_CHAR); System.exit(1); @@ -766,19 +767,19 @@ private static void invertSelection() { private static void traceWithCurrentBrush() { if (canTrace()) { - runAction(PenTool.getTraceWithBrush()); + runAction(PenTool.getTraceWithBrushAction()); } } private static void traceWithCurrentEraser() { if (canTrace()) { - runAction(PenTool.getTraceWithEraser()); + runAction(PenTool.getTraceWithEraserAction()); } } private static void traceWithCurrentSmudge() { if (canTrace()) { - runAction(PenTool.getTraceWithSmudge()); + runAction(PenTool.getTraceWithSmudgeAction()); } } diff --git a/src/main/resources/images/adj_layer_icon.png b/src/main/resources/images/adj_layer.png similarity index 100% rename from src/main/resources/images/adj_layer_icon.png rename to src/main/resources/images/adj_layer.png diff --git a/src/main/resources/images/brush_tool_icon.png b/src/main/resources/images/brush_tool.png similarity index 100% rename from src/main/resources/images/brush_tool_icon.png rename to src/main/resources/images/brush_tool.png diff --git a/src/main/resources/images/clone_tool_icon.png b/src/main/resources/images/clone_tool.png similarity index 100% rename from src/main/resources/images/clone_tool_icon.png rename to src/main/resources/images/clone_tool.png diff --git a/src/main/resources/images/color_picker_tool_icon.png b/src/main/resources/images/color_picker_tool.png similarity index 100% rename from src/main/resources/images/color_picker_tool_icon.png rename to src/main/resources/images/color_picker_tool.png diff --git a/src/main/resources/images/crop_tool.png b/src/main/resources/images/crop_tool.png new file mode 100644 index 000000000..9632aef2e Binary files /dev/null and b/src/main/resources/images/crop_tool.png differ diff --git a/src/main/resources/images/crop_tool_icon.png b/src/main/resources/images/crop_tool_icon.png deleted file mode 100644 index 22a756525..000000000 Binary files a/src/main/resources/images/crop_tool_icon.png and /dev/null differ diff --git a/src/main/resources/images/erase_tool_icon.png b/src/main/resources/images/eraser_tool.png similarity index 100% rename from src/main/resources/images/erase_tool_icon.png rename to src/main/resources/images/eraser_tool.png diff --git a/src/main/resources/images/gradient_tool.png b/src/main/resources/images/gradient_tool.png new file mode 100644 index 000000000..6453c38b6 Binary files /dev/null and b/src/main/resources/images/gradient_tool.png differ diff --git a/src/main/resources/images/gradient_tool_icon.png b/src/main/resources/images/gradient_tool_icon.png deleted file mode 100644 index 05c0da9ff..000000000 Binary files a/src/main/resources/images/gradient_tool_icon.png and /dev/null differ diff --git a/src/main/resources/images/hand_tool_icon.png b/src/main/resources/images/hand_tool.png similarity index 100% rename from src/main/resources/images/hand_tool_icon.png rename to src/main/resources/images/hand_tool.png diff --git a/src/main/resources/images/move_tool.png b/src/main/resources/images/move_tool.png new file mode 100644 index 000000000..44f701710 Binary files /dev/null and b/src/main/resources/images/move_tool.png differ diff --git a/src/main/resources/images/move_tool_icon.png b/src/main/resources/images/move_tool_icon.png deleted file mode 100644 index 0aa77293f..000000000 Binary files a/src/main/resources/images/move_tool_icon.png and /dev/null differ diff --git a/src/main/resources/images/paint_bucket_tool_icon.png b/src/main/resources/images/paint_bucket_tool.png similarity index 100% rename from src/main/resources/images/paint_bucket_tool_icon.png rename to src/main/resources/images/paint_bucket_tool.png diff --git a/src/main/resources/images/pen_tool_icon.png b/src/main/resources/images/pen_tool.png similarity index 100% rename from src/main/resources/images/pen_tool_icon.png rename to src/main/resources/images/pen_tool.png diff --git a/src/main/resources/images/selection_tool_icon.png b/src/main/resources/images/selection_tool.png similarity index 100% rename from src/main/resources/images/selection_tool_icon.png rename to src/main/resources/images/selection_tool.png diff --git a/src/main/resources/images/shapes_tool_icon.png b/src/main/resources/images/shapes_tool.png similarity index 100% rename from src/main/resources/images/shapes_tool_icon.png rename to src/main/resources/images/shapes_tool.png diff --git a/src/main/resources/images/smudge_tool_icon.png b/src/main/resources/images/smudge_tool.png similarity index 100% rename from src/main/resources/images/smudge_tool_icon.png rename to src/main/resources/images/smudge_tool.png diff --git a/src/main/resources/images/smudge_tool_2x.png b/src/main/resources/images/smudge_tool_2x.png new file mode 100644 index 000000000..1a5bec086 Binary files /dev/null and b/src/main/resources/images/smudge_tool_2x.png differ diff --git a/src/main/resources/images/text_layer_icon.png b/src/main/resources/images/text_layer.png similarity index 100% rename from src/main/resources/images/text_layer_icon.png rename to src/main/resources/images/text_layer.png diff --git a/src/main/resources/images/zoom_tool_icon.png b/src/main/resources/images/zoom_tool.png similarity index 100% rename from src/main/resources/images/zoom_tool_icon.png rename to src/main/resources/images/zoom_tool.png diff --git a/src/test/java/pixelitor/TestHelper.java b/src/test/java/pixelitor/TestHelper.java index f580354cc..27e6beef2 100755 --- a/src/test/java/pixelitor/TestHelper.java +++ b/src/test/java/pixelitor/TestHelper.java @@ -74,6 +74,8 @@ public static Composition createEmptyComp() { public static Composition createEmptyComp(int width, int height) { var comp = Composition.createEmpty(width, height, ImageMode.RGB); comp.setName("Test"); + comp.createDebugName(); + setupMockViewFor(comp); return comp; diff --git a/src/test/java/pixelitor/guitest/AssertJSwingTest.java b/src/test/java/pixelitor/guitest/AssertJSwingTest.java index 0f89ecd18..a39b74119 100644 --- a/src/test/java/pixelitor/guitest/AssertJSwingTest.java +++ b/src/test/java/pixelitor/guitest/AssertJSwingTest.java @@ -2333,11 +2333,9 @@ private void enableLazyMouse(boolean b) { dialog.slider("distSlider") .requireEnabled() .slideToMinimum(); - dialog.slider("spacingSlider").requireEnabled(); } else { dialog.checkBox().uncheck(); dialog.slider("distSlider").requireDisabled(); - dialog.slider("spacingSlider").requireDisabled(); } findButtonByText(dialog, "Close").click(); dialog.requireNotVisible(); diff --git a/src/test/java/pixelitor/guitest/RandomToolTest.java b/src/test/java/pixelitor/guitest/RandomToolTest.java index d176ffed1..b020f5133 100644 --- a/src/test/java/pixelitor/guitest/RandomToolTest.java +++ b/src/test/java/pixelitor/guitest/RandomToolTest.java @@ -784,7 +784,6 @@ private void changeLazyMouseSetting() { enabledCB.click(); if (enabledCB.target().isSelected()) { slideRandomly(dialog.slider("distSlider")); - slideRandomly(dialog.slider("spacingSlider")); } Utils.sleep(200, MILLISECONDS); diff --git a/src/test/java/pixelitor/layers/ImageLayerTest.java b/src/test/java/pixelitor/layers/ImageLayerTest.java index 00492ca65..a5c94670b 100755 --- a/src/test/java/pixelitor/layers/ImageLayerTest.java +++ b/src/test/java/pixelitor/layers/ImageLayerTest.java @@ -507,7 +507,7 @@ private void checkLayerAfterCrop(int expectedTx, int expectedTy, comp.getCanvas().changeSize( (int) expectedNewCanvas.getWidth(), - (int) expectedNewCanvas.getHeight(), comp.getView()); + (int) expectedNewCanvas.getHeight(), comp.getView(), true); ConsistencyChecks.imageCoversCanvas(layer); } diff --git a/src/test/java/pixelitor/tools/transform/TransformBoxTest.java b/src/test/java/pixelitor/tools/transform/TransformBoxTest.java index 1ae490be6..35a89b393 100644 --- a/src/test/java/pixelitor/tools/transform/TransformBoxTest.java +++ b/src/test/java/pixelitor/tools/transform/TransformBoxTest.java @@ -20,6 +20,7 @@ import org.junit.jupiter.api.*; import pixelitor.TestHelper; import pixelitor.gui.View; +import pixelitor.utils.debug.DebugNode; import java.awt.Rectangle; import java.awt.geom.AffineTransform; @@ -45,6 +46,11 @@ public void transform(AffineTransform transform) { public void updateUI(View view) { // do nothing } + + @Override + public DebugNode createDebugNode() { + return new DebugNode("test", null); + } }; @BeforeAll