diff --git a/diylc/diylc-core/src/org/diylc/presenter/update.xml b/diylc/diylc-core/src/org/diylc/presenter/update.xml index 9a2ef701..f6e45d5b 100644 --- a/diylc/diylc-core/src/org/diylc/presenter/update.xml +++ b/diylc/diylc-core/src/org/diylc/presenter/update.xml @@ -3269,5 +3269,25 @@ https://github.com/bancika/diy-layout-creator/releases + + + 4 + 12 + 0 + + 2020-11-19 00:00:00.000 CET + + + + NEW_FEATURE + macOS: added pinch zooming functionality + + + IMPROVEMENT + macOS: added meta +/- (minus and equal keys) keyboard shortcuts for zooming + + + https://github.com/bancika/diy-layout-creator/releases + diff --git a/diylc/diylc-swing/.classpath b/diylc/diylc-swing/.classpath index 8159a3ea..c9ca94d3 100644 --- a/diylc/diylc-swing/.classpath +++ b/diylc/diylc-swing/.classpath @@ -15,6 +15,7 @@ + diff --git a/diylc/diylc-swing/build.xml b/diylc/diylc-swing/build.xml index 6fefedc7..52338685 100644 --- a/diylc/diylc-swing/build.xml +++ b/diylc/diylc-swing/build.xml @@ -10,7 +10,7 @@ - + diff --git a/diylc/diylc-swing/lib/diylc-core.jar b/diylc/diylc-swing/lib/diylc-core.jar index b9185f38..459b2fbf 100644 Binary files a/diylc/diylc-swing/lib/diylc-core.jar and b/diylc/diylc-swing/lib/diylc-core.jar differ diff --git a/diylc/diylc-swing/lib/gestures-wrapper-0.2.jar b/diylc/diylc-swing/lib/gestures-wrapper-0.2.jar new file mode 100644 index 00000000..d72ddc8a Binary files /dev/null and b/diylc/diylc-swing/lib/gestures-wrapper-0.2.jar differ diff --git a/diylc/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasGestureListener.java b/diylc/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasDragGestureListener.java similarity index 87% rename from diylc/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasGestureListener.java rename to diylc/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasDragGestureListener.java index 5906bcb7..409d6248 100644 --- a/diylc/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasGestureListener.java +++ b/diylc/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasDragGestureListener.java @@ -29,15 +29,15 @@ import java.awt.event.MouseEvent; import org.diylc.common.IPlugInPort; /** - * {@link DragGestureListener} for {@link CanvasPanel}. + * {@link DragGestureListener} implementation for {@link CanvasPanel}. * * @author Branislav Stojkovic */ -class CanvasGestureListener implements DragGestureListener { +class CanvasDragGestureListener implements DragGestureListener { private IPlugInPort presenter; - public CanvasGestureListener(IPlugInPort presenter) { + public CanvasDragGestureListener(IPlugInPort presenter) { super(); this.presenter = presenter; } diff --git a/diylc/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasPanel.java b/diylc/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasPanel.java index a1c4166d..2417e0eb 100644 --- a/diylc/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasPanel.java +++ b/diylc/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasPanel.java @@ -124,7 +124,7 @@ public class CanvasPanel extends JComponent implements Autoscroll { // Initialize drag source recognizer. DragSource.getDefaultDragSource().createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY_OR_MOVE | DnDConstants.ACTION_LINK, - new CanvasGestureListener(plugInPort)); + new CanvasDragGestureListener(plugInPort)); // Initialize drop target. new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, new CanvasTargetListener(plugInPort), true); @@ -143,8 +143,12 @@ public class CanvasPanel extends JComponent implements Autoscroll { .put(KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, KeyEvent.CTRL_DOWN_MASK), "zoomOut"); getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke(KeyEvent.VK_ADD, KeyEvent.META_DOWN_MASK), "zoomIn"); + getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) + .put(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, KeyEvent.META_DOWN_MASK), "zoomIn"); getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, KeyEvent.META_DOWN_MASK), "zoomOut"); + getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) + .put(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, KeyEvent.META_DOWN_MASK), "zoomOut"); getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke(KeyEvent.VK_0, KeyEvent.CTRL_DOWN_MASK), "resetZoom"); getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) @@ -169,35 +173,35 @@ public class CanvasPanel extends JComponent implements Autoscroll { }); } - getActionMap().put("zoomIn", new AbstractAction() { - - private static final long serialVersionUID = 1L; - - @Override - public void actionPerformed(ActionEvent e) { - LOG.debug("Keyboard zoom-in triggered"); - double oldZoom = CanvasPanel.this.plugInPort.getZoomLevel(); - Double[] availableZoomLevels = CanvasPanel.this.plugInPort.getAvailableZoomLevels(); - int index = Arrays.binarySearch(availableZoomLevels, oldZoom); - if (index < availableZoomLevels.length - 1) - CanvasPanel.this.plugInPort.setZoomLevel(availableZoomLevels[index + 1]); - } - }); - - getActionMap().put("zoomOut", new AbstractAction() { - - private static final long serialVersionUID = 1L; - - @Override - public void actionPerformed(ActionEvent e) { - LOG.debug("Keyboard zoom-out triggered"); - double oldZoom = CanvasPanel.this.plugInPort.getZoomLevel(); - Double[] availableZoomLevels = CanvasPanel.this.plugInPort.getAvailableZoomLevels(); - int index = Arrays.binarySearch(availableZoomLevels, oldZoom); - if (index > 0) - CanvasPanel.this.plugInPort.setZoomLevel(availableZoomLevels[index - 1]); - } - }); +// getActionMap().put("zoomIn", new AbstractAction() { +// +// private static final long serialVersionUID = 1L; +// +// @Override +// public void actionPerformed(ActionEvent e) { +// LOG.debug("Keyboard zoom-in triggered"); +// double oldZoom = CanvasPanel.this.plugInPort.getZoomLevel(); +// Double[] availableZoomLevels = CanvasPanel.this.plugInPort.getAvailableZoomLevels(); +// int index = Arrays.binarySearch(availableZoomLevels, oldZoom); +// if (index < availableZoomLevels.length - 1) +// CanvasPanel.this.plugInPort.setZoomLevel(availableZoomLevels[index + 1]); +// } +// }); +// +// getActionMap().put("zoomOut", new AbstractAction() { +// +// private static final long serialVersionUID = 1L; +// +// @Override +// public void actionPerformed(ActionEvent e) { +// LOG.debug("Keyboard zoom-out triggered"); +// double oldZoom = CanvasPanel.this.plugInPort.getZoomLevel(); +// Double[] availableZoomLevels = CanvasPanel.this.plugInPort.getAvailableZoomLevels(); +// int index = Arrays.binarySearch(availableZoomLevels, oldZoom); +// if (index > 0) +// CanvasPanel.this.plugInPort.setZoomLevel(availableZoomLevels[index - 1]); +// } +// }); getActionMap().put("resetZoom", new AbstractAction() { diff --git a/diylc/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasPlugin.java b/diylc/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasPlugin.java index 7de953d8..e6a08e6d 100644 --- a/diylc/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasPlugin.java +++ b/diylc/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasPlugin.java @@ -61,19 +61,24 @@ import org.diylc.common.IPlugInPort; import org.diylc.core.ExpansionMode; import org.diylc.core.IDIYComponent; import org.diylc.core.Template; -import org.diylc.swing.images.IconLoader; import org.diylc.core.measures.Size; import org.diylc.core.measures.SizeUnit; import org.diylc.swing.ActionFactory; import org.diylc.swing.ISwingUI; import org.diylc.swing.gui.TranslatedMenu; import org.diylc.swing.gui.TranslatedPopupMenu; +import org.diylc.swing.images.IconLoader; import org.diylc.swing.plugins.edit.ComponentTransferable; import org.diylc.swing.plugins.file.ProjectDrawingProvider; import org.diylc.swingframework.ruler.IRulerListener; import org.diylc.swingframework.ruler.Ruler.InchSubdivision; import org.diylc.swingframework.ruler.RulerScrollPane; +import com.guigarage.gestures.GestureMagnificationEvent; +import com.guigarage.gestures.GestureMagnificationListener; +import com.guigarage.gestures.GestureUtilities; +import com.guigarage.gestures.GesturesNotSupportedException; + public class CanvasPlugin implements IPlugIn, ClipboardOwner { private static final Logger LOG = Logger.getLogger(CanvasPlugin.class); @@ -343,6 +348,55 @@ public class CanvasPlugin implements IPlugIn, ClipboardOwner { e.isShiftDown(), e.isAltDown()); } }); + + canvasPanel.getActionMap().put("zoomIn", new AbstractAction() { + + private static final long serialVersionUID = 1L; + + @Override + public void actionPerformed(ActionEvent e) { + LOG.debug("Keyboard zoom-in triggered"); + zoom(-1); + } + }); + + canvasPanel.getActionMap().put("zoomOut", new AbstractAction() { + + private static final long serialVersionUID = 1L; + + @Override + public void actionPerformed(ActionEvent e) { + LOG.debug("Keyboard zoom-out triggered"); + zoom(1); + } + }); + + if (!GestureUtilities.isSupported()) { + LOG.info("Gestures are not supported, skipping initialization"); + } + try { + GestureUtilities.registerListener(canvasPanel, new GestureMagnificationListener() { + + private long prevEventTime = 0; + private static final int DELAY = 100; + + @Override + public void magnify(GestureMagnificationEvent e) { + if (System.currentTimeMillis() - this.prevEventTime < DELAY) + return; + + if (e.getMagnification() > 0) + CanvasPlugin.this.zoom(-1); + else if (e.getMagnification() < 0) + CanvasPlugin.this.zoom(1); + + prevEventTime = System.currentTimeMillis(); + } + }); + LOG.info("Magnification gesture listener initialized."); + } catch (GesturesNotSupportedException e) { + LOG.error("Error registering gesture listener", e); + } } return canvasPanel; } @@ -390,48 +444,7 @@ public class CanvasPlugin implements IPlugIn, ClipboardOwner { configManager.readBoolean(IPlugInPort.WHEEL_ZOOM_KEY, false); if (wheelZoom || (Utils.isMac() ? e.isMetaDown() : e.isControlDown())) { - - Point mousePos = getCanvasPanel().getMousePosition(true); - - // change zoom level - double oldZoom = plugInPort.getZoomLevel(); - double newZoom; - Double[] availableZoomLevels = plugInPort.getAvailableZoomLevels(); - if (e.getWheelRotation() > 0) { - int i = availableZoomLevels.length - 1; - while (i > 0 && availableZoomLevels[i] >= oldZoom) { - i--; - } - plugInPort.setZoomLevel(newZoom = availableZoomLevels[i]); - } else { - int i = 0; - while (i < availableZoomLevels.length - 1 && availableZoomLevels[i] <= oldZoom) { - i++; - } - plugInPort.setZoomLevel(newZoom = availableZoomLevels[i]); - } - - Rectangle2D selectionBounds = plugInPort.getSelectionBounds(true); - Rectangle visibleRect = scrollPane.getVisibleRect(); - - JScrollBar horizontal = scrollPane.getHorizontalScrollBar(); - JScrollBar vertical = scrollPane.getVerticalScrollBar(); - - if (selectionBounds == null) { - // center to cursor - Point desiredPos = new Point((int) (1d * mousePos.x / oldZoom * newZoom), - (int) (1d * mousePos.y / oldZoom * newZoom)); - int dx = desiredPos.x - mousePos.x; - int dy = desiredPos.y - mousePos.y; - horizontal.setValue(horizontal.getValue() + dx); - vertical.setValue(vertical.getValue() + dy); - } else { - // center to selection - horizontal.setValue((int) (selectionBounds.getX() + selectionBounds.getWidth() / 2 - - visibleRect.getWidth() / 2)); - vertical.setValue((int) (selectionBounds.getY() + selectionBounds.getHeight() / 2 - - visibleRect.getHeight() / 2)); - } + CanvasPlugin.this.zoom(e.getWheelRotation()); } if (e.isShiftDown()) { int iScrollAmount = e.getScrollAmount(); @@ -451,6 +464,50 @@ public class CanvasPlugin implements IPlugIn, ClipboardOwner { } return scrollPane; } + + public void zoom(int direction) { + Point mousePos = canvasPanel.getMousePosition(true); + + // change zoom level + double oldZoom = plugInPort.getZoomLevel(); + double newZoom; + Double[] availableZoomLevels = plugInPort.getAvailableZoomLevels(); + if (direction > 0) { + int i = availableZoomLevels.length - 1; + while (i > 0 && availableZoomLevels[i] >= oldZoom) { + i--; + } + plugInPort.setZoomLevel(newZoom = availableZoomLevels[i]); + } else { + int i = 0; + while (i < availableZoomLevels.length - 1 && availableZoomLevels[i] <= oldZoom) { + i++; + } + plugInPort.setZoomLevel(newZoom = availableZoomLevels[i]); + } + + Rectangle2D selectionBounds = plugInPort.getSelectionBounds(true); + Rectangle visibleRect = scrollPane.getVisibleRect(); + + JScrollBar horizontal = scrollPane.getHorizontalScrollBar(); + JScrollBar vertical = scrollPane.getVerticalScrollBar(); + + if (selectionBounds == null) { + // center to cursor + Point desiredPos = new Point((int) (1d * mousePos.x / oldZoom * newZoom), + (int) (1d * mousePos.y / oldZoom * newZoom)); + int dx = desiredPos.x - mousePos.x; + int dy = desiredPos.y - mousePos.y; + horizontal.setValue(horizontal.getValue() + dx); + vertical.setValue(vertical.getValue() + dy); + } else { + // center to selection + horizontal.setValue((int) (selectionBounds.getX() + selectionBounds.getWidth() / 2 + - visibleRect.getWidth() / 2)); + vertical.setValue((int) (selectionBounds.getY() + selectionBounds.getHeight() / 2 + - visibleRect.getHeight() / 2)); + } + } private void showPopupAt(int x, int y) { updateSelectionMenu(x, y);