153 lines
4.7 KiB
Java
153 lines
4.7 KiB
Java
package de.ph87.kindermalen.drawing;
|
|
|
|
import de.ph87.kindermalen.ComponentListener;
|
|
import de.ph87.kindermalen.Environment;
|
|
import de.ph87.kindermalen.MyComponent;
|
|
import de.ph87.kindermalen.toolbox.tool.Tool;
|
|
import de.ph87.kindermalen.util.Subscription;
|
|
import de.ph87.kindermalen.util.Vector;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
import java.awt.*;
|
|
import java.awt.event.MouseEvent;
|
|
import java.awt.geom.AffineTransform;
|
|
import java.awt.geom.NoninvertibleTransformException;
|
|
import java.awt.geom.Point2D;
|
|
import java.awt.image.BufferedImage;
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
|
|
@Slf4j
|
|
public class DrawingPanel extends MyComponent {
|
|
|
|
private static final File SAVE_DIR = new File("./data/images");
|
|
|
|
private final Environment environment;
|
|
|
|
private Subscription<Tool> toolChangeSubscription = null;
|
|
|
|
private Vector lastPoint = null;
|
|
|
|
private Vector cursor = null;
|
|
|
|
private AffineTransform transform;
|
|
|
|
private AffineTransform inverseTransform;
|
|
|
|
public DrawingPanel(final Environment environment) {
|
|
this.environment = environment;
|
|
subscribe(environment.getToolbox().getOnSelect(), this::onToolSelect);
|
|
subscribe(environment.getOnDrawingChange(), drawing -> repaint());
|
|
ComponentListener.on(this)
|
|
.componentResized(this::calculateTransform)
|
|
.componentMoved(this::calculateTransform)
|
|
.componentShown(this::calculateTransform)
|
|
.mousePressed(this::mousePressed)
|
|
.mouseReleased(this::mouseReleased)
|
|
.mouseDragged(this::mouseDragged)
|
|
.mouseMoved(this::mouseMoved);
|
|
|
|
}
|
|
|
|
private void onToolSelect(final Tool tool) {
|
|
repaint();
|
|
if (toolChangeSubscription != null) {
|
|
unsubscribe(toolChangeSubscription);
|
|
}
|
|
toolChangeSubscription = subscribe(tool.getOnChange(), ignore -> repaint());
|
|
}
|
|
|
|
public void mousePressed(final MouseEvent mouseEvent) {
|
|
if (mouseEvent.getButton() == 3) {
|
|
environment.getDrawing().undo();
|
|
return;
|
|
}
|
|
environment.getDrawing().newRevision();
|
|
lastPoint = environment.getToolbox().getTool().apply(null, environment.getDrawing(), transform(mouseEvent.getPoint()));
|
|
repaint();
|
|
}
|
|
|
|
public void mouseReleased(final MouseEvent mouseEvent) {
|
|
try {
|
|
environment.getDrawing().save(SAVE_DIR);
|
|
} catch (IOException ex) {
|
|
log.error(ex.toString());
|
|
}
|
|
}
|
|
|
|
public void mouseDragged(final MouseEvent mouseEvent) {
|
|
cursor = transform(mouseEvent.getPoint());
|
|
lastPoint = environment.getToolbox().getTool().apply(lastPoint, environment.getDrawing(), transform(mouseEvent.getPoint()));
|
|
repaint();
|
|
}
|
|
|
|
public void mouseMoved(final MouseEvent mouseEvent) {
|
|
cursor = transform(mouseEvent.getPoint());
|
|
repaint();
|
|
}
|
|
|
|
private void calculateTransform() {
|
|
final Drawing drawing = environment.getDrawing();
|
|
final Rectangle box = fitInside(drawing.width, drawing.height, getWidth(), getHeight(), false);
|
|
final double scale = (double) box.width / drawing.width;
|
|
transform = new AffineTransform();
|
|
transform.translate(box.x, box.y);
|
|
transform.scale(scale, scale);
|
|
try {
|
|
inverseTransform = transform.createInverse();
|
|
} catch (NoninvertibleTransformException ex) {
|
|
log.error(ex.toString());
|
|
}
|
|
}
|
|
|
|
private Vector transform(final Point point) {
|
|
final Point2D transformed = inverseTransform.transform(new Point2D.Double(point.x, point.y), null);
|
|
return new Vector(transformed);
|
|
}
|
|
|
|
@Override
|
|
public void paint(final Graphics graphics) {
|
|
final Graphics2D g = (Graphics2D) graphics;
|
|
g.setColor(Color.gray);
|
|
g.fillRect(0, 0, getWidth(), getHeight());
|
|
|
|
if (transform == null || environment == null || environment.getDrawing() == null) {
|
|
return;
|
|
}
|
|
|
|
g.setTransform(transform);
|
|
draw(g, environment.getDrawing());
|
|
}
|
|
|
|
private void draw(final Graphics2D g, final Drawing drawing) {
|
|
g.setColor(Color.white);
|
|
g.fillRect(0, 0, drawing.width, drawing.height);
|
|
g.drawImage(drawing.getImage(), 0, 0, drawing.width, drawing.height, null);
|
|
|
|
final BufferedImage preview = environment.getToolbox().getTool().getPreview();
|
|
if (cursor != null && preview != null) {
|
|
g.drawImage(preview, cursor.intX() - preview.getWidth() / 2, cursor.intY() - preview.getHeight() / 2, null);
|
|
}
|
|
}
|
|
|
|
private Rectangle fitInside(int w, int h, final int width, final int height, final boolean grow) {
|
|
final double r = (double) w / h;
|
|
if (grow && h < height) {
|
|
h = height;
|
|
w = (int) Math.round(h * r);
|
|
}
|
|
if (w > width || (grow && w < width)) {
|
|
w = width;
|
|
h = (int) Math.round(w / r);
|
|
}
|
|
if (h > height) {
|
|
h = height;
|
|
w = (int) Math.round(h * r);
|
|
}
|
|
final int x = (int) Math.round((width - w) / 2.0);
|
|
final int y = (int) Math.round((height - h) / 2.0);
|
|
return new Rectangle(x, y, w, h);
|
|
}
|
|
|
|
}
|