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

Made it possible to design in negative space #2559

Merged
merged 1 commit into from
Jun 27, 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 @@ -26,7 +26,14 @@ This file is part of Universal Gcode Sender (UGS).
import com.willwinder.ugs.nbp.designer.gui.Drawing;
import com.willwinder.ugs.nbp.designer.logic.Controller;

import java.awt.*;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.util.Optional;
Expand All @@ -36,69 +43,112 @@ This file is part of Universal Gcode Sender (UGS).
*/
public class GridControl extends AbstractEntity implements Control {

public static final int MINIMUM_SIZE = 300;
public static final int LARGE_GRID_SIZE = 50;
public static final int SMALL_GRID_SIZE = 10;
public static final int LARGE_GRID_SIZE = 100;
public static final int SMALL_GRID_SIZE = 20;
private final Controller controller;

public GridControl(Controller controller) {
this.controller = controller;
}

@Override
public void render(Graphics2D graphics, Drawing drawing) {
double gridSize = LARGE_GRID_SIZE;

Rectangle2D bounds = controller.getDrawing().getRootEntity().getBounds();
int calculatedMinimumWidth = (int) Math.round(Math.floor(bounds.getMaxX() / gridSize) * gridSize + (gridSize * 2));
int calculatedMinimumHeight = (int) Math.round(Math.floor(bounds.getMaxY() / gridSize) * gridSize + (gridSize * 2));

int width = Math.max(calculatedMinimumWidth, MINIMUM_SIZE);
int height = Math.max(calculatedMinimumHeight, MINIMUM_SIZE);

graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, width, height);
private static void drawZeroLines(Graphics2D graphics, Drawing drawing, int startPosX, int startPosY, int endPosX, int endPosY) {
// Draw zero lines
graphics.setStroke(new BasicStroke((float) (0.5 / drawing.getScale())));
graphics.setColor(Color.LIGHT_GRAY);
graphics.drawLine(0, startPosY, 0, endPosY);
graphics.drawLine(startPosX, 0, endPosX, 0);
}

graphics.setStroke(new BasicStroke(Double.valueOf(0.1 / drawing.getScale()).floatValue()));
private static void drawSmallGrid(Graphics2D graphics, Drawing drawing, int startPosX, int startPosY, int endPosX, int endPosY, int gridSize) {
graphics.setStroke(new BasicStroke((float) (0.2 / drawing.getScale())));
graphics.setColor(Color.LIGHT_GRAY);
for (int x = 0; x <= width; x += SMALL_GRID_SIZE) {
graphics.drawLine(x, 0, x, height);
for (int x = startPosX; x <= endPosX; x += gridSize) {
graphics.drawLine(x, startPosY, x, endPosY);
}

for (int y = 0; y <= height; y += SMALL_GRID_SIZE) {
graphics.drawLine(0, y, width, y);
for (int y = startPosY; y <= endPosY; y += gridSize) {
graphics.drawLine(startPosX, y, endPosX, y);
}
}



private static void drawLargeGridAndText(Graphics2D graphics, Drawing drawing, int startPosX, int startPosY, int endPosX, int endPosY, int gridSize) {
Rectangle2D clipBounds = graphics.getClipBounds();
AffineTransform affineTransform = AffineTransform.getScaleInstance(1 / drawing.getScale(), -1 / drawing.getScale());
affineTransform.rotate(Math.PI/2);
affineTransform.rotate(Math.PI / 2);
Font font = new Font(null, Font.PLAIN, 10).deriveFont(affineTransform);
graphics.setFont(font);
FontMetrics fontMetrics = graphics.getFontMetrics();

graphics.setStroke(new BasicStroke(Double.valueOf(0.2 / drawing.getScale()).floatValue()));
for (int x = 0; x <= width; x += LARGE_GRID_SIZE) {
graphics.drawLine(x, 0, x, height);
graphics.setStroke(new BasicStroke((float) (0.3 / drawing.getScale())));
graphics.setColor(Color.LIGHT_GRAY);

int fontOffset = (int) Math.round(6 / drawing.getScale());

for (int x = startPosX; x <= endPosX; x += gridSize) {
if (x < clipBounds.getMinX() || x > clipBounds.getMaxX()) {
continue;
}
graphics.drawLine(x, startPosY, x, endPosY);

String text = x + " mm";
int y = -fontMetrics.stringWidth(text);
graphics.drawString(text, x - (int) Math.round(3 / drawing.getScale()), y - (int) Math.round(8 / drawing.getScale()));
int y = -fontMetrics.stringWidth(text) - fontOffset;
graphics.drawString(text, x + fontOffset, y);
}


affineTransform = AffineTransform.getScaleInstance(1 / drawing.getScale(), -1 / drawing.getScale());
font = new Font(null, Font.PLAIN, 10).deriveFont(affineTransform);
graphics.setFont(font);
fontMetrics = graphics.getFontMetrics();

for (int y = 0; y <= height; y += LARGE_GRID_SIZE) {
graphics.drawLine(0, y, width, y);
for (int y = startPosY; y <= endPosY; y += gridSize) {
if (y < clipBounds.getMinY() || y > clipBounds.getMaxY()) {
continue;
}
graphics.drawLine(startPosX, y, endPosX, y);

String text = y + " mm";
int x = -fontMetrics.stringWidth(text);
graphics.drawString(text, x - (int) Math.round(8 / drawing.getScale()), y - (int) Math.round(3 / drawing.getScale()));
int x = -fontMetrics.stringWidth(text);
graphics.drawString(text, x - fontOffset, y + fontOffset);
}
}

@Override
public void render(Graphics2D graphics, Drawing drawing) {
double gridSize = LARGE_GRID_SIZE;


Rectangle2D bounds = controller.getDrawing().getRootEntity().getBounds();
double gridMargin = (gridSize * 100);


int startPosX = (int) Math.min(-gridMargin, (Math.floor(bounds.getMinX() / gridSize) * gridSize + gridMargin));
int startPosY = (int) Math.min(-gridMargin, (Math.floor(bounds.getMinY() / gridSize) * gridSize + gridMargin));
int endPosX = (int) Math.max(gridMargin, (Math.floor(bounds.getMaxX() / gridSize) * gridSize + gridMargin));
int endPosY = (int) Math.max(gridMargin, (Math.floor(bounds.getMaxY() / gridSize) * gridSize + gridMargin));

int width = endPosX - startPosX;
int height = endPosY - startPosY;
graphics.setColor(Color.WHITE);
graphics.fillRect(startPosX, startPosY, width, height);

int smallGridSize;
int largeGridSize;
if (drawing.getScale() < 1.3) {
smallGridSize = SMALL_GRID_SIZE;
largeGridSize = LARGE_GRID_SIZE;
} else if (drawing.getScale() < 4) {
smallGridSize = SMALL_GRID_SIZE / 2;
largeGridSize = LARGE_GRID_SIZE / 2;
} else if (drawing.getScale() < 12) {
smallGridSize = SMALL_GRID_SIZE / 4;
largeGridSize = LARGE_GRID_SIZE / 4;
} else {
smallGridSize = SMALL_GRID_SIZE / 10;
largeGridSize = LARGE_GRID_SIZE / 10;
}
drawSmallGrid(graphics, drawing, startPosX, startPosY, endPosX, endPosY, smallGridSize);
drawLargeGridAndText(graphics, drawing, startPosX, startPosY, endPosX, endPosY, largeGridSize);
drawZeroLines(graphics, drawing, startPosX, startPosY, endPosX, endPosY);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ This file is part of Universal Gcode Sender (UGS).
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
Expand All @@ -72,6 +73,9 @@ public class Drawing extends JPanel {
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);

public Drawing(Controller controller) {
refreshThrottler = new Throttler(this::refresh, 2000);
Expand Down Expand Up @@ -220,8 +224,10 @@ public void setScale(double scale) {

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

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

public AffineTransform getTransform() {
AffineTransform transform = AffineTransform.getScaleInstance(1, -1);
transform.translate(0, -getHeight());
transform.translate(MARGIN, MARGIN);
transform.scale(scale, scale);
// 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();
}

return transform;
}

Expand All @@ -263,4 +276,16 @@ public List<Control> getControls() {
public void clear() {
entitiesRoot.removeAll();
}


@Override
public Rectangle getBounds() {
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());
currentBounds.setRect(minX, minY, maxX - minX, maxY - minY);
return currentBounds.getBounds();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,22 @@ This file is part of Universal Gcode Sender (UGS).
import com.willwinder.ugs.nbp.lib.lookup.CentralLookup;
import com.willwinder.universalgcodesender.model.BackendAPI;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.Box;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.KeyboardFocusManager;
import java.awt.Rectangle;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;

/**
* A simple container that contains a Drawing instance and keeps it
Expand All @@ -37,6 +50,7 @@ This file is part of Universal Gcode Sender (UGS).
*/
public class DrawingContainer extends JPanel implements ComponentListener, MouseWheelListener {

public static final double CENTER_ZOOM_SCALE_FACTOR = 0.8;
private final transient Controller controller;
private JScrollPane scrollPane;
private JPanel buttonPanel;
Expand Down Expand Up @@ -82,6 +96,7 @@ protected void processMouseWheelEvent(MouseWheelEvent e) {
scrollPane.getHorizontalScrollBar().setUnitIncrement(5);
scrollPane.setPreferredSize(getSize());
scrollPane.setBounds(0, 0, getWidth(), getHeight());
scrollPane.setWheelScrollingEnabled(false);

buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
buttonPanel.setOpaque(false);
Expand Down Expand Up @@ -135,19 +150,22 @@ public void componentHidden(ComponentEvent e) {
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
BackendAPI backend = CentralLookup.getDefault().lookup(BackendAPI.class);
double scaleFactor = (e.getPreciseWheelRotation() * 0.1) * (backend.getSettings().isInvertMouseZoom() ? -1d : 1d);
controller.getDrawing().setScale(controller.getDrawing().getScale() + scaleFactor);
Rectangle viewRect = scrollPane.getViewport().getViewRect();
Dimension size = scrollPane.getViewport().getView().getSize();

double currentViewPortCenterX = (scrollPane.getHorizontalScrollBar().getValue() + (scrollPane.getWidth() / 2d)) / controller.getDrawing().getScale();
double currentViewPortCenterY = (scrollPane.getVerticalScrollBar().getValue() + (scrollPane.getHeight() / 2d)) / controller.getDrawing().getScale();
// Get the mouse position relative to the center
double mouseX = (e.getPoint().getX() - viewRect.getCenterX()) * CENTER_ZOOM_SCALE_FACTOR;
double mouseY = (e.getPoint().getY() - viewRect.getCenterY()) * CENTER_ZOOM_SCALE_FACTOR;

double mouseX = e.getPoint().getX() / controller.getDrawing().getScale();
double mouseY = e.getPoint().getY() / controller.getDrawing().getScale();
// Get the current view position in percent
double previousXScrollbarPercent = (viewRect.getX() + mouseX) / size.getWidth();
double previousYScrollbarPercent = (viewRect.getY() + mouseY) / size.getHeight();

double x = ((mouseX - currentViewPortCenterX) * controller.getDrawing().getScale()) * scaleFactor;
double y = ((mouseY - currentViewPortCenterY) * controller.getDrawing().getScale()) * scaleFactor;
// Apply the scaling
double scaleFactor = (e.getPreciseWheelRotation() * controller.getDrawing().getScale() * 0.1) * (backend.getSettings().isInvertMouseZoom() ? -1d : 1d);
controller.getDrawing().setScale(controller.getDrawing().getScale() + scaleFactor);

scrollPane.getHorizontalScrollBar().setValue(scrollPane.getHorizontalScrollBar().getValue() + (int) Math.round(x + 0.5));
scrollPane.getVerticalScrollBar().setValue(scrollPane.getVerticalScrollBar().getValue() + (int) Math.round(y + 0.5));
scrollPane.getHorizontalScrollBar().setValue((int) Math.round((controller.getDrawing().getMinimumSize().getWidth() * previousXScrollbarPercent)));
scrollPane.getVerticalScrollBar().setValue((int) Math.round((controller.getDrawing().getMinimumSize().getHeight() * previousYScrollbarPercent)));
}
}
Loading