Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adjusted how scrolling and zooming works in the designer #2566

Merged
merged 1 commit into from
Jul 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

import com.willwinder.ugs.nbp.designer.actions.UndoManager;
import com.willwinder.ugs.nbp.designer.entities.selection.SelectionManager;
import com.willwinder.ugs.nbp.designer.gui.DrawingContainer;
import com.willwinder.ugs.nbp.designer.gui.MainMenu;
import com.willwinder.ugs.nbp.designer.gui.DrawingScrollContainer;
import com.willwinder.ugs.nbp.designer.gui.DrawingOverlayContainer;
import com.willwinder.ugs.nbp.designer.gui.PopupMenuFactory;
import com.willwinder.ugs.nbp.designer.gui.ToolBox;
import com.willwinder.ugs.nbp.designer.gui.selectionsettings.SelectionSettingsPanel;
Expand Down Expand Up @@ -53,13 +54,14 @@ public DesignerMain() {
SelectionManager selectionManager = ControllerFactory.getSelectionManager();
CentralLookup.getDefault().add(selectionManager);

DrawingContainer drawingContainer = new DrawingContainer(controller);
DrawingScrollContainer drawingContainer = new DrawingScrollContainer(controller);
selectionManager.addSelectionListener(e -> drawingContainer.repaint());

JSplitPane toolsSplit = createRightPanel(controller);
DrawingOverlayContainer overlayToolContainer = new DrawingOverlayContainer(controller, drawingContainer);

JSplitPane toolsSplit = createRightPanel(controller);
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
drawingContainer, toolsSplit);
overlayToolContainer, toolsSplit);
splitPane.setResizeWeight(0.95);

getContentPane().add(splitPane, BorderLayout.CENTER);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public void addChild(Entity entity, int index) {
invalidateBounds();
}

private void invalidateBounds() {
public void invalidateBounds() {
cachedBounds = null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@ public void render(Graphics2D graphics, Drawing drawing) {
}

// Draw the bounds
double margin = ResizeControl.MARGIN / drawing.getScale();
graphics.setColor(Colors.CONTROL_BORDER);
graphics.setStroke(new BasicStroke(Double.valueOf(0.8 / drawing.getScale()).floatValue()));
graphics.setStroke(new BasicStroke((float) (0.8f / drawing.getScale())));
Rectangle2D bounds = getRelativeShape().getBounds2D();
bounds.setFrame(bounds.getX() - margin, bounds.getY() - margin, bounds.getWidth() + (margin * 2), bounds.getHeight() + (margin * 2));
bounds.setFrame(bounds.getX() , bounds.getY() , bounds.getWidth(), bounds.getHeight());
graphics.draw(getSelectionManager().getTransform().createTransformedShape(bounds));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2021 Will Winder
Copyright 2021-2024 Will Winder

This file is part of Universal Gcode Sender (UGS).

Expand Down Expand Up @@ -54,6 +54,7 @@ This file is part of Universal Gcode Sender (UGS).
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.Serial;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
Expand All @@ -65,20 +66,20 @@ This file is part of Universal Gcode Sender (UGS).
public class Drawing extends JPanel {

public static final double MIN_SCALE = 0.05;
@Serial
private static final long serialVersionUID = 1298712398723987873L;
private static final int MARGIN = 100;
private final transient EntityGroup globalRoot;
private final transient EntityGroup entitiesRoot;
private final transient EntityGroup controlsRoot;
private final transient Set<DrawingListener> listeners = Sets.newConcurrentHashSet();
private final transient Throttler refreshThrottler;
private double scale;
private AffineTransform transform;
private long lastUpdate;
private final transient Rectangle2D currentBounds = new Rectangle(0, 0, 8, 8);
private double scale;
private Point2D.Double position = new Point2D.Double();
private Dimension oldMinimumSize;

public Drawing(Controller controller) {
refreshThrottler = new Throttler(this::refresh, 2000);
refreshThrottler = new Throttler(this::refresh, 1000);

globalRoot = new EntityGroup();
globalRoot.addChild(new GridControl(controller));
Expand Down Expand Up @@ -219,14 +220,14 @@ public void setScale(double scale) {
if (this.scale != newScale) {
this.scale = newScale;
notifyListeners(DrawingEvent.SCALE_CHANGED);
refresh();
}
}

@Override
public Dimension getMinimumSize() {
int margin = (int) (MARGIN * 2 * scale);
int width = (int) (currentBounds.getWidth() * scale) + margin;
int height = (int) (currentBounds.getHeight() * scale) + margin;
int width = (int) (currentBounds.getWidth() );
int height = (int) (currentBounds.getHeight());
return new Dimension(width, height);
}

Expand All @@ -235,11 +236,14 @@ public Dimension getPreferredSize() {
return getMinimumSize();
}

private void refresh() {
public void refresh() {
repaint();
globalRoot.invalidateBounds();
updateBounds();
Dimension minimumSize = getMinimumSize();
firePropertyChange("minimumSize", minimumSize.width, minimumSize.height);
firePropertyChange("preferredSize", minimumSize.width, minimumSize.height);
firePropertyChange("minimumSize", oldMinimumSize, minimumSize);
firePropertyChange("preferredSize", oldMinimumSize, minimumSize);
oldMinimumSize = minimumSize;
revalidate();
}

Expand All @@ -248,17 +252,10 @@ public void addListener(DrawingListener listener) {
}

public AffineTransform getTransform() {
// Don't update this every time or else it will be hard to move entites outside the canvas
if (System.currentTimeMillis() > lastUpdate + 50) {

transform = AffineTransform.getScaleInstance(1, -1);
transform.translate(0, -getHeight());
transform.scale(scale, scale);
transform.translate(MARGIN / 4d, MARGIN / 4d);
transform.translate(-getBounds().getMinX(), -getBounds().getMinY());
lastUpdate = System.currentTimeMillis();
}

AffineTransform transform = AffineTransform.getScaleInstance(1, -1);
transform.translate(0, -getHeight());
transform.scale(scale, scale);
transform.translate(-position.x, -position.y);
return transform;
}

Expand All @@ -277,15 +274,27 @@ public void clear() {
entitiesRoot.removeAll();
}


@Override
public Rectangle getBounds() {
updateBounds();
return currentBounds.getBounds();
}

private void updateBounds() {
Rectangle2D bounds = globalRoot.getBounds();
double minX = Math.min(currentBounds.getMinX(), bounds.getMinX());
double minY = Math.min(currentBounds.getMinY(), bounds.getMinY());
double maxX = Math.max(currentBounds.getMaxX(), bounds.getMaxX());
double maxY = Math.max(currentBounds.getMaxY(), bounds.getMaxY());
double minX = (bounds.getMinX()) * scale;
double minY = (bounds.getMinY()) * scale;
double maxX = (bounds.getMaxX()) * scale;
double maxY = (bounds.getMaxY()) * scale;
currentBounds.setRect(minX, minY, maxX - minX, maxY - minY);
return currentBounds.getBounds();
}

public void setPosition(double x, double y) {
position = new Point2D.Double(x / scale, y / scale);
refresh();
}

public Point2D.Double getPosition() {
return new Point2D.Double(position.x * scale, position.y * scale);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
Copyright 2024 Will Winder

This file is part of Universal Gcode Sender (UGS).

UGS is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

UGS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with UGS. If not, see <http://www.gnu.org/licenses/>.
*/
package com.willwinder.ugs.nbp.designer.gui;

import com.willwinder.ugs.nbp.designer.actions.OpenStockSettingsAction;
import com.willwinder.ugs.nbp.designer.actions.OpenToolSettingsAction;
import com.willwinder.ugs.nbp.designer.logic.Controller;

import javax.swing.Box;
import javax.swing.JComponent;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Rectangle;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;

/**
* A container that will add button overlays
*
* @author Joacim Breiler
*/
public class DrawingOverlayContainer extends JPanel implements ComponentListener {
private final JPanel buttonPanel;
private final JComponent component;

public DrawingOverlayContainer(Controller controller, JComponent component) {
setLayout(new BorderLayout());

this.component = component;
buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
buttonPanel.setOpaque(false);

ToolButton toolButton = new ToolButton(controller);
toolButton.setMinimumSize(new Dimension(60, 40));
toolButton.setMaximumSize(new Dimension(100, 40));
toolButton.addActionListener(new OpenToolSettingsAction(controller));
buttonPanel.add(toolButton);

add(Box.createHorizontalStrut(6));
PanelButton stockButton = new PanelButton("Stock", controller.getSettings().getStockSizeDescription());
stockButton.setMinimumSize(new Dimension(60, 40));
stockButton.setMaximumSize(new Dimension(100, 40));
controller.getSettings().addListener(() -> stockButton.setText(controller.getSettings().getStockSizeDescription()));
stockButton.addActionListener(new OpenStockSettingsAction(controller));
buttonPanel.add(stockButton);

JLayeredPane layeredPane = new JLayeredPane();

layeredPane.add(component, JLayeredPane.DEFAULT_LAYER, 0);
layeredPane.add(buttonPanel, JLayeredPane.PALETTE_LAYER, 0);
add(layeredPane, BorderLayout.CENTER);
revalidate();

// This is a workaround to be able to resize the layered pane
addComponentListener(this);
}

@Override
public void componentResized(ComponentEvent e) {
// Needed to properly resize the layered pane
SwingUtilities.invokeLater(() -> {
Rectangle bounds = getBounds();
component.setBounds(0, 0, bounds.width, bounds.height);
buttonPanel.setBounds(0, bounds.height - 80, bounds.width - 30, 80);
revalidate();
});
}

@Override
public void componentMoved(ComponentEvent e) {
// Not used
}

@Override
public void componentShown(ComponentEvent e) {
// Not used
}

@Override
public void componentHidden(ComponentEvent e) {
// Not used
}
}
Loading
Loading