+ layout working now BUT WIP
+ transform
+ fixed (virtual) paper size
+ size adjust
+ transparency adjust
+ step-adjust
This commit is contained in:
Patrick Haßel 2023-02-26 00:31:39 +01:00
parent d2c9efe9ea
commit 42db19b253
38 changed files with 988 additions and 625 deletions

4
.gitignore vendored
View File

@ -4,7 +4,7 @@
target/ target/
!.mvn/wrapper/maven-wrapper.jar !.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/ !**/src/window/**/target/
!**/src/test/**/target/ !**/src/test/**/target/
### IntelliJ IDEA ### ### IntelliJ IDEA ###
@ -32,7 +32,7 @@ target/
/nbdist/ /nbdist/
/.nb-gradle/ /.nb-gradle/
build/ build/
!**/src/main/**/build/ !**/src/window/**/build/
!**/src/test/**/build/ !**/src/test/**/build/
### VS Code ### ### VS Code ###

View File

@ -0,0 +1,17 @@
package de.ph87.kindermalen;
import java.awt.*;
public class CONFIG {
public static final boolean BORDERS = false;
public static final BasicStroke STROKE_BORDER = new BasicStroke(1f);
public static final int STROKE_HIGHLIGHT_WIDTH = 4;
public static final BasicStroke STROKE_HIGHLIGHT = new BasicStroke(STROKE_HIGHLIGHT_WIDTH);
public static final int STAMP_BUTTON_SIZE = 75;
}

View File

@ -1,47 +0,0 @@
package de.ph87.kindermalen;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.function.Consumer;
public class ClickListener implements MouseListener {
private final Consumer<MouseEvent> onPress;
private final Consumer<MouseEvent> onRelease;
public ClickListener(final Consumer<MouseEvent> onPress, final Consumer<MouseEvent> onRelease) {
this.onPress = onPress;
this.onRelease = onRelease;
}
@Override
public void mouseClicked(final MouseEvent e) {
}
@Override
public void mousePressed(final MouseEvent e) {
if (onPress != null) {
onPress.accept(e);
}
}
@Override
public void mouseReleased(final MouseEvent e) {
if (onRelease != null) {
onRelease.accept(e);
}
}
@Override
public void mouseEntered(final MouseEvent e) {
}
@Override
public void mouseExited(final MouseEvent e) {
}
}

View File

@ -1,40 +0,0 @@
package de.ph87.kindermalen;
import java.awt.event.KeyEvent;
import java.util.function.Consumer;
public class KeyListener implements java.awt.event.KeyListener {
private final boolean ctrl;
private final boolean shift;
private final int keycode;
private final Consumer<KeyEvent> next;
public KeyListener(final boolean ctrl, final boolean shift, final int keycode, final Consumer<KeyEvent> next) {
this.ctrl = ctrl;
this.shift = shift;
this.keycode = keycode;
this.next = next;
}
@Override
public void keyTyped(final KeyEvent e) {
}
@Override
public void keyPressed(final KeyEvent e) {
if (e.isControlDown() == ctrl && e.isShiftDown() == shift && e.getKeyCode() == keycode) {
next.accept(e);
}
}
@Override
public void keyReleased(final KeyEvent e) {
}
}

View File

@ -1,117 +0,0 @@
package de.ph87.kindermalen;
import de.ph87.kindermalen.drawing.Drawing;
import de.ph87.kindermalen.drawing.DrawingPanel;
import de.ph87.kindermalen.tool.Tool;
import de.ph87.kindermalen.tool.ToolPanel;
import de.ph87.kindermalen.tool.stamp.StampTool;
import de.ph87.kindermalen.tool.stamp.StampToolPanel;
import de.ph87.kindermalen.toolbox.ToolBox;
import de.ph87.kindermalen.toolbox.ToolBoxPanel;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
public class Main extends JFrame {
public static final int SCREEN = 1;
private static final double SIDEBAR_RATIO = 0.15;
public static final double TOOLBOX_RATIO = 0;
public static final double PROPERTIES_RATIO = 2;
private final ToolBox toolBox = new ToolBox();
private final Drawing drawing = new Drawing(1500, 1000);
private final DrawingPanel drawingPanel = new DrawingPanel(toolBox, drawing);
private final ToolBoxPanel toolBoxPanel = new ToolBoxPanel(toolBox);
private ToolPanel toolPanel = null;
public static void main(String[] args) {
final Main main = new Main();
main.setVisible(true);
}
public Main() {
setLayout(new GridBagLayout());
final GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
c.weightx = SIDEBAR_RATIO;
c.weighty = TOOLBOX_RATIO;
c.fill = GridBagConstraints.BOTH;
c.anchor = GridBagConstraints.FIRST_LINE_START;
add(toolBoxPanel, c);
c.gridx = 1;
c.gridy = 0;
c.weightx = 1 - SIDEBAR_RATIO;
c.weighty = 1;
c.fill = GridBagConstraints.BOTH;
c.gridheight = 3;
add(drawingPanel, c);
pack();
setFullscreen();
setDefaultCloseOperation(EXIT_ON_CLOSE);
addKeyListener(new KeyListener(true, false, KeyEvent.VK_Z, this::undo));
addKeyListener(new KeyListener(true, true, KeyEvent.VK_Z, this::redo));
toolBox.onToolChange(this::onToolChanged);
}
private void undo(final KeyEvent keyEvent) {
drawing.getCurrent().undo();
drawingPanel.repaint();
}
private void redo(final KeyEvent keyEvent) {
drawing.getCurrent().redo();
drawingPanel.repaint();
}
private void onToolChanged(final Tool tool) {
if (toolPanel != null) {
remove(toolPanel);
toolPanel = null;
}
if (tool instanceof StampTool) {
toolPanel = new StampToolPanel((StampTool) tool);
}
if (toolPanel != null) {
final GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 1;
c.weightx = SIDEBAR_RATIO;
c.weighty = PROPERTIES_RATIO;
c.fill = GridBagConstraints.BOTH;
c.anchor = GridBagConstraints.FIRST_LINE_START;
add(toolPanel, c);
pack();
}
}
private void setFullscreen() {
final GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
final GraphicsDevice[] graphicsDevices = graphicsEnvironment.getScreenDevices();
if (SCREEN < graphicsDevices.length) {
graphicsDevices[SCREEN].setFullScreenWindow(this);
} else if (graphicsDevices.length > 0) {
graphicsDevices[0].setFullScreenWindow(this);
} else {
throw new RuntimeException("No Screens Found");
}
}
}

View File

@ -1,32 +0,0 @@
package de.ph87.kindermalen;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.util.function.Consumer;
public class MotionListener implements MouseMotionListener {
private final Consumer<MouseEvent> onMove;
private final Consumer<MouseEvent> onDrag;
public MotionListener(final Consumer<MouseEvent> onMove, final Consumer<MouseEvent> onDrag) {
this.onMove = onMove;
this.onDrag = onDrag;
}
@Override
public void mouseDragged(final MouseEvent e) {
if (onDrag != null) {
onDrag.accept(e);
}
}
@Override
public void mouseMoved(final MouseEvent e) {
if (onMove != null) {
onMove.accept(e);
}
}
}

View File

@ -0,0 +1,53 @@
package de.ph87.kindermalen;
import de.ph87.kindermalen.tools.Tools;
import de.ph87.kindermalen.tools.ToolsPanel;
import de.ph87.kindermalen.tools.tool.Tool;
import de.ph87.kindermalen.tools.tool.ToolPanel;
import de.ph87.kindermalen.tools.tool.stamp.StampPanel;
import de.ph87.kindermalen.tools.tool.stamp.StampTool;
import javax.swing.*;
import java.awt.*;
import static de.ph87.kindermalen.CONFIG.BORDERS;
import static de.ph87.kindermalen.util.MyGridBagConstraints.C;
public class Sidebar extends JPanel {
private ToolPanel toolPanel = null;
public Sidebar(final Tools tools) {
setPreferredSize(new Dimension(300, 0));
setLayout(new GridBagLayout());
add(new ToolsPanel(tools), C(0, 0, 1, 0.1));
tools.onToolSelected(this::onToolSelected);
}
@Override
public void paint(final Graphics g) {
super.paint(g);
if (BORDERS) {
g.setColor(Color.red);
g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
}
}
private void onToolSelected(final Tool tool) {
if (toolPanel != null) {
remove(toolPanel);
toolPanel = null;
}
if (tool instanceof StampTool) {
toolPanel = new StampPanel((StampTool) tool);
}
if (toolPanel != null) {
add(toolPanel, C(0, 1, 1, 0.9));
}
repaint();
}
}

View File

@ -0,0 +1,73 @@
package de.ph87.kindermalen;
import de.ph87.kindermalen.drawing.Drawing;
import de.ph87.kindermalen.drawing.DrawingPanel;
import de.ph87.kindermalen.tools.Tools;
import javax.swing.*;
import java.awt.*;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import static de.ph87.kindermalen.util.MyGridBagConstraints.C;
public class Window extends JFrame {
public static final int SCREEN = 1;
private final Drawing drawing = new Drawing(1920, 1080);
public static void main(String[] args) {
final Tools tools = new Tools();
final Window window = new Window(tools);
window.setVisible(true);
}
public Window(final Tools tools) {
setLayout(new GridBagLayout());
final Sidebar sidebar = new Sidebar(tools);
add(sidebar, C(0, 0, 0, 1.0));
final DrawingPanel drawingPanel = new DrawingPanel(tools, drawing);
add(drawingPanel, C(1, 0, 1, 1.0));
pack();
setFullscreen();
setDefaultCloseOperation(EXIT_ON_CLOSE);
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.addKeyEventDispatcher(
keyEvent -> {
if (keyEvent.getID() == KeyEvent.KEY_PRESSED && keyEvent.getKeyCode() == KeyEvent.VK_Z) {
if (keyEvent.getModifiersEx() == InputEvent.CTRL_DOWN_MASK) {
drawing.undo();
return true;
}
if (keyEvent.getModifiersEx() == InputEvent.SHIFT_DOWN_MASK + InputEvent.CTRL_DOWN_MASK) {
drawing.redo();
return true;
}
}
return false;
}
);
}
private void setFullscreen() {
final GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
final GraphicsDevice[] graphicsDevices = graphicsEnvironment.getScreenDevices();
final GraphicsDevice graphicsDevice;
if (SCREEN < graphicsDevices.length) {
graphicsDevice = graphicsDevices[SCREEN];
} else if (graphicsDevices.length > 0) {
graphicsDevice = graphicsDevices[0];
} else {
throw new RuntimeException("No Screens Found");
}
graphicsDevice.setFullScreenWindow(this);
// setPreferredSize(new Dimension(graphicsDevice.getDisplayMode().getWidth(),graphicsDevice.getDisplayMode().getHeight()));
}
}

View File

@ -1,20 +1,74 @@
package de.ph87.kindermalen.drawing; package de.ph87.kindermalen.drawing;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
@Getter import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
@Slf4j
public class Drawing { public class Drawing {
@Getter
private final int width; private final int width;
@Getter
private final int height; private final int height;
private final Layer current; private final Layer current;
private final ZonedDateTime created = ZonedDateTime.now();
public Drawing(final int width, final int height) { public Drawing(final int width, final int height) {
this.width = width; this.width = width;
this.height = height; this.height = height;
current = new Layer(width, height); current = new Layer(width, height);
} }
public Graphics2D getGraphics() {
return (Graphics2D) current.getCurrent().getGraphics();
}
public void publish() {
current.publish();
}
public void undo() {
current.undo();
}
public void redo() {
current.redo();
}
public void newRevision() {
current.newRevision();
}
public void save(final File dir) throws IOException {
final int revision = current.getRevision();
final BufferedImage image = current.getCurrent();
final File subdir = new File(dir, created.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
final File file = new File(subdir, "%05d".formatted(revision) + ".png");
if (subdir.mkdirs()) {
log.debug("Directory created: {}", subdir);
}
new Thread(() -> {
try {
ImageIO.write(image, "PNG", file);
} catch (IOException e) {
log.error(e.toString());
}
}).start();
}
public Image getImage() {
return current.getCurrent();
}
} }

View File

@ -1,85 +1,168 @@
package de.ph87.kindermalen.drawing; package de.ph87.kindermalen.drawing;
import de.ph87.kindermalen.ClickListener; import de.ph87.kindermalen.tools.Tools;
import de.ph87.kindermalen.MotionListener; import de.ph87.kindermalen.tools.tool.Tool;
import de.ph87.kindermalen.toolbox.ToolBox; import de.ph87.kindermalen.util.MouseListener;
import de.ph87.kindermalen.util.Subscription;
import de.ph87.kindermalen.util.Vector;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import javax.imageio.ImageIO;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent; 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.awt.image.BufferedImage;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
@Slf4j @Slf4j
public class DrawingPanel extends JPanel { public class DrawingPanel extends JPanel {
private static final File SAVE_DIR = new File("./data/images"); private static final File SAVE_DIR = new File("./data/images");
private final ToolBox toolBox; private final Tools tools;
private final Drawing drawing; private final Drawing drawing;
private Subscription<Tool> toolSubscription = null;
private Vector lastPoint = null; private Vector lastPoint = null;
private Point cursor = null; private Vector cursor = null;
private final ZonedDateTime startup = ZonedDateTime.now(); private AffineTransform transform;
public DrawingPanel(final ToolBox toolBox, final Drawing drawing) { private AffineTransform inverseTransform;
this.toolBox = toolBox;
public DrawingPanel(final Tools tools, final Drawing drawing) {
this.tools = tools;
this.drawing = drawing; this.drawing = drawing;
this.addMouseListener(new ClickListener(this::onPress, this::onRelease)); MouseListener.onPress(this, this::onPress);
this.addMouseMotionListener(new MotionListener(this::onMove, this::onDrag)); MouseListener.onRelease(this, this::onRelease);
MouseListener.onMove(this, this::onMove);
MouseListener.onDrag(this, this::onDrag);
tools.onToolSelected(tool -> {
repaint();
if (toolSubscription != null) {
toolSubscription.unsubscribe();
}
toolSubscription = tool.onChange(ignore -> repaint());
});
addComponentListener(new ComponentListener() {
@Override
public void componentResized(final ComponentEvent e) {
calculateTransform();
}
@Override
public void componentMoved(final ComponentEvent e) {
calculateTransform();
}
@Override
public void componentShown(final ComponentEvent e) {
}
@Override
public void componentHidden(final ComponentEvent e) {
}
});
} }
private void onMove(final MouseEvent e) { private void calculateTransform() {
cursor = e.getPoint(); final Image image = drawing.getImage();
repaint(); final Rectangle box = fitInside(image.getWidth(null), image.getHeight(null), getWidth(), getHeight(), false);
} final double scale = (double) box.width / image.getWidth(null);
transform = new AffineTransform();
private void onPress(final MouseEvent e) { transform.translate(box.x, box.y);
drawing.getCurrent().newRevision(); transform.scale(scale, scale);
lastPoint = toolBox.getTool().apply(null, drawing.getCurrent().getCurrent(), new Vector(e.getPoint()));
repaint();
}
private void onDrag(final MouseEvent e) {
cursor = e.getPoint();
lastPoint = toolBox.getTool().apply(lastPoint, drawing.getCurrent().getCurrent(), new Vector(e.getPoint()));
repaint();
}
private void onRelease(final MouseEvent e) {
SAVE_DIR.mkdirs();
try { try {
ImageIO.write(drawing.getCurrent().getCurrent(), "PNG", new File(SAVE_DIR, startup.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) + ".png")); inverseTransform = transform.createInverse();
} catch (NoninvertibleTransformException ex) {
log.error(ex.toString());
}
System.out.printf("%.0f%%\n", 100.0 * scale);
}
private void onMove(final MouseEvent mouseEvent) {
cursor = transform(mouseEvent.getPoint());
repaint();
}
private void onPress(final MouseEvent mouseEvent) {
if (mouseEvent.getButton() == 3) {
drawing.undo();
return;
}
drawing.newRevision();
lastPoint = tools.getTool().apply(null, drawing, transform(mouseEvent.getPoint()));
repaint();
}
private void onDrag(final MouseEvent mouseEvent) {
cursor = transform(mouseEvent.getPoint());
lastPoint = tools.getTool().apply(lastPoint, drawing, transform(mouseEvent.getPoint()));
repaint();
}
private Vector transform(final Point point) {
final Point2D transformed = inverseTransform.transform(new Point2D.Double(point.x, point.y), null);
return new Vector(transformed);
}
private void onRelease(final MouseEvent mouseEvent) {
try {
drawing.save(SAVE_DIR);
} catch (IOException ex) { } catch (IOException ex) {
log.error(ex.toString()); log.error(ex.toString());
} }
} }
@Override @Override
public void paint(final Graphics g) { public void paint(final Graphics graphics) {
final Graphics2D g = (Graphics2D) graphics;
g.setColor(Color.gray); g.setColor(Color.gray);
g.fillRect(0, 0, getWidth(), getHeight()); g.fillRect(0, 0, getWidth(), getHeight());
g.setTransform(transform);
if (drawing == null) { if (drawing == null) {
return; return;
} }
g.setColor(Color.white); final Image image = drawing.getImage();
g.fillRect(0, 0, drawing.getWidth(), drawing.getHeight());
g.drawImage(drawing.getCurrent().getCurrent(), 0, 0, null);
final BufferedImage preview = toolBox.getTool().getPreview(); g.setColor(Color.white);
g.fillRect(0, 0, image.getWidth(null), image.getHeight(null));
g.drawImage(image, 0, 0, image.getWidth(null), image.getHeight(null), null);
final BufferedImage preview = tools.getTool().getPreview();
if (cursor != null && preview != null) { if (cursor != null && preview != null) {
g.drawImage(preview, cursor.x - preview.getWidth() / 2, cursor.y - preview.getHeight() / 2, 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);
}
} }

View File

@ -1,11 +1,16 @@
package de.ph87.kindermalen.drawing; package de.ph87.kindermalen.drawing;
import de.ph87.kindermalen.util.Publisher;
import de.ph87.kindermalen.util.Subscription;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Consumer;
import static de.ph87.kindermalen.util.ImageHelper.COPY;
@Slf4j @Slf4j
public class Layer { public class Layer {
@ -19,14 +24,19 @@ public class Layer {
private List<BufferedImage> history = new ArrayList<>(); private List<BufferedImage> history = new ArrayList<>();
private int index; @Getter
private int index = 0;
@Getter
private int revision = 0;
private final Publisher<BufferedImage> onChange = new Publisher<>();
public Layer(final int width, final int height) { public Layer(final int width, final int height) {
this.width = width; this.width = width;
this.height = height; this.height = height;
this.current = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); this.current = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
this.history.add(current); this.history.add(current);
this.index = 0;
} }
public void newRevision() { public void newRevision() {
@ -36,23 +46,19 @@ public class Layer {
history = history.subList(0, keep); history = history.subList(0, keep);
log.info("{} Revisions deleted", old - keep); log.info("{} Revisions deleted", old - keep);
} }
current = copy(); current = COPY(current);
index = history.size(); index = history.size();
revision++;
history.add(current); history.add(current);
log.info("Revision {} created", index); log.info("Revision {} created", index);
} }
private BufferedImage copy() {
final BufferedImage created = new BufferedImage(current.getWidth(), current.getHeight(), current.getType());
current.copyData(created.getRaster());
return created;
}
public void undo() { public void undo() {
if (index > 0) { if (index > 0) {
index--; index--;
current = history.get(index); current = history.get(index);
log.info("UNDO: Revision {} loaded", index); log.info("UNDO: Revision {} loaded", index);
publish();
} else { } else {
log.warn("No UNDO steps left."); log.warn("No UNDO steps left.");
} }
@ -63,6 +69,7 @@ public class Layer {
index++; index++;
current = history.get(index); current = history.get(index);
log.info("REDO: Revision {} loaded", index); log.info("REDO: Revision {} loaded", index);
publish();
} else { } else {
log.warn("No REDO steps left."); log.warn("No REDO steps left.");
} }
@ -72,4 +79,12 @@ public class Layer {
return index < history.size() - 1; return index < history.size() - 1;
} }
public void publish() {
onChange.publish(current);
}
public Subscription<BufferedImage> onChange(final Consumer<BufferedImage> next) {
return onChange.subscribe(next);
}
} }

View File

@ -1,21 +0,0 @@
package de.ph87.kindermalen.tool;
import de.ph87.kindermalen.drawing.Vector;
import lombok.Getter;
import java.awt.image.BufferedImage;
public abstract class Tool {
@Getter
private final String name;
protected Tool(final String name) {
this.name = name;
}
public abstract Vector apply(final Vector last, final BufferedImage image, final Vector point);
public abstract BufferedImage getPreview();
}

View File

@ -1,18 +0,0 @@
package de.ph87.kindermalen.tool;
import lombok.extern.slf4j.Slf4j;
import javax.swing.*;
import java.awt.*;
@Slf4j
public abstract class ToolPanel<T extends Tool> extends JPanel {
protected final T tool;
protected ToolPanel(final T tool) {
this.tool = tool;
setPreferredSize(new Dimension(100, 100));
}
}

View File

@ -1,118 +0,0 @@
package de.ph87.kindermalen.tool.stamp;
import de.ph87.kindermalen.drawing.Vector;
import de.ph87.kindermalen.tool.Tool;
import lombok.Getter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import static de.ph87.kindermalen.ImageHelper.*;
import static de.ph87.kindermalen.tool.stamp.ListHelper.SYNC;
@Slf4j
@ToString
public class StampTool extends Tool {
private static final File STAMPS_DIR = new File("./data/stamps");
@Getter
private List<Stamp> stamps = new ArrayList<>();
@Getter
private Stamp stamp;
@Getter
private int size = 100;
@Getter
private double alpha = 0.75;
private BufferedImage prepared;
@Getter
private BufferedImage preview;
public StampTool() {
super("Stempel");
final List<File> files = scan(STAMPS_DIR);
stamps = SYNC(files, stamps, Stamp::getFile, Stamp::new, Stamp::getName);
stamps.stream().filter(stamp -> stamp.getOriginal() == null).forEach(this::load);
}
private List<File> scan(final File dir) {
final List<File> files = new ArrayList<>();
for (final File child : Objects.requireNonNull(dir.listFiles())) {
if (child.isFile()) {
files.add(child.getAbsoluteFile());
} else if (child.isDirectory()) {
files.addAll(scan(child));
}
}
return files;
}
private void load(final Stamp stamp) {
try {
stamp.load();
if (this.stamp == stamp) {
prepare();
}
} catch (IOException e) {
log.error(e.toString());
}
}
public void setStamp(final Stamp stamp) {
this.stamp = stamp;
log.info("Stamp chosen: {}", stamp.getName());
prepare();
}
public void setSize(final int size) {
this.size = size;
prepare();
}
public void setAlpha(final double alpha) {
this.alpha = alpha;
prepare();
}
private void prepare() {
if (this.stamp == null || stamp.getOriginal() == null) {
return;
}
prepared = RESIZE(stamp.getOriginal(), size, size);
preview = COPY(prepared);
ALPHA(preview, 0.5);
ALPHA(prepared, alpha);
log.info("Stamp prepared: {}", stamp.getName());
}
@Override
public Vector apply(Vector last, final BufferedImage destination, final Vector current) {
if (last == null) {
apply(destination, current);
return current;
}
final Vector vector = new Vector(last, current);
for (int rest = (int) Math.floor(vector.length); rest >= 20; rest -= 20) {
final Vector point = last.plus(vector.withLength(20));
apply(destination, point);
last = point;
}
return last;
}
private void apply(final BufferedImage destination, final Vector point) {
destination.getGraphics().drawImage(prepared, point.intX() - prepared.getWidth() / 2, point.intY() - prepared.getHeight() / 2, null);
}
}

View File

@ -1,67 +0,0 @@
package de.ph87.kindermalen.tool.stamp;
import de.ph87.kindermalen.ClickListener;
import de.ph87.kindermalen.tool.ToolPanel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
@Slf4j
public class StampToolPanel extends ToolPanel<StampTool> {
private static final BasicStroke STROKE_BORDER = new BasicStroke(1f);
private static final int STROKE_HIGHLIGHT_WIDTH = 4;
private static final BasicStroke STROKE_HIGHLIGHT = new BasicStroke(STROKE_HIGHLIGHT_WIDTH);
private static final int SIZE = 50;
public StampToolPanel(final StampTool tool) {
super(tool);
setLayout(new FlowLayout(FlowLayout.LEADING, 0, 0));
tool.getStamps().forEach(stamp -> add(new StampPanel(stamp)));
}
private class StampPanel extends JPanel {
@Getter
private final Stamp stamp;
private final BufferedImage icon;
private final Point position;
public StampPanel(final Stamp stamp) {
this.stamp = stamp;
setPreferredSize(new Dimension(SIZE, SIZE));
addMouseListener(new ClickListener(null, e -> tool.setStamp(stamp)));
icon = stamp.getSize(SIZE - STROKE_HIGHLIGHT_WIDTH * 2);
position = new Point((SIZE - icon.getWidth()) / 2, (SIZE - icon.getHeight()) / 2);
}
@Override
public void paint(final Graphics g) {
super.paint(g);
final Graphics2D g2 = (Graphics2D) g;
if (tool.getStamp() == stamp) {
g2.setColor(Color.orange);
g2.setStroke(STROKE_HIGHLIGHT);
g2.fillRect(0, 0, getWidth(), getHeight());
} else {
g2.setColor(Color.white);
g2.setStroke(STROKE_BORDER);
}
g2.drawRect(0, 0, SIZE - 1, SIZE - 1);
g2.drawImage(icon, position.x, position.y, null);
}
}
}

View File

@ -1,7 +0,0 @@
package de.ph87.kindermalen.toolbox;
public interface Observer<T> {
void next(final T item);
}

View File

@ -1,38 +0,0 @@
package de.ph87.kindermalen.toolbox;
import de.ph87.kindermalen.Publisher;
import de.ph87.kindermalen.Subscription;
import de.ph87.kindermalen.tool.Tool;
import de.ph87.kindermalen.tool.stamp.StampTool;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
import java.util.function.Consumer;
@Slf4j
public class ToolBox {
@Getter
private final List<Tool> tools = List.of(new StampTool());
@Getter
private Tool tool;
private final Publisher<Tool> onToolChange = new Publisher<>();
public ToolBox() {
setTool(tools.get(0));
}
public void setTool(final Tool tool) {
this.tool = tool;
log.info("Tool selected: {}", tool.getName());
onToolChange.publish(tool);
}
public Subscription<Tool> onToolChange(final Consumer<Tool> next) {
return onToolChange.subscribe(next);
}
}

View File

@ -1,56 +0,0 @@
package de.ph87.kindermalen.toolbox;
import de.ph87.kindermalen.ClickListener;
import de.ph87.kindermalen.tool.Tool;
import lombok.extern.slf4j.Slf4j;
import javax.swing.*;
import java.awt.*;
@Slf4j
public class ToolBoxPanel extends JPanel {
private final ToolBox toolbox;
public ToolBoxPanel(final ToolBox toolbox) {
this.toolbox = toolbox;
setLayout(new FlowLayout(FlowLayout.LEADING, 0, 0));
for (final Tool tool : toolbox.getTools()) {
add(new ToolButton(tool));
}
}
@Override
public void paint(final Graphics g) {
super.paint(g);
// final Graphics2D g2 = (Graphics2D) g;
// g2.setColor(Color.red);
// g2.setStroke(new BasicStroke(1f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 0, new float[]{2f}, 0));
// g2.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
}
private class ToolButton extends Component {
private final Tool tool;
public ToolButton(final Tool tool) {
this.tool = tool;
setPreferredSize(new Dimension(50, 50));
addMouseListener(new ClickListener(null, e -> toolbox.setTool(tool)));
}
@Override
public void paint(final Graphics g) {
g.setColor(Color.magenta);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.black);
g.setFont(g.getFont().deriveFont(12.0f));
g.drawString(tool.getName(), 0, g.getFontMetrics().getHeight());
g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
}
}
}

View File

@ -0,0 +1,32 @@
package de.ph87.kindermalen.tools;
import de.ph87.kindermalen.tools.tool.Tool;
import de.ph87.kindermalen.util.MouseListener;
import java.awt.*;
import static de.ph87.kindermalen.CONFIG.STAMP_BUTTON_SIZE;
public class ToolButton extends Component {
private final Tool tool;
public ToolButton(final Tools tools, final Tool tool) {
this.tool = tool;
setPreferredSize(new Dimension(STAMP_BUTTON_SIZE, STAMP_BUTTON_SIZE));
MouseListener.onRelease(this, e -> tools.setTool(tool));
}
@Override
public void paint(final Graphics g) {
g.setColor(Color.magenta);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.black);
g.setFont(g.getFont().deriveFont(12.0f));
g.drawString(tool.getName(), 0, g.getFontMetrics().getHeight());
g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
}
}

View File

@ -0,0 +1,38 @@
package de.ph87.kindermalen.tools;
import de.ph87.kindermalen.tools.tool.Tool;
import de.ph87.kindermalen.tools.tool.stamp.StampTool;
import de.ph87.kindermalen.util.Publisher;
import de.ph87.kindermalen.util.Subscription;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
import java.util.function.Consumer;
@Slf4j
public class Tools {
@Getter
private final List<Tool> tools = List.of(new StampTool());
@Getter
private Tool tool;
private final Publisher<Tool> onToolSelected = new Publisher<>();
public Tools() {
setTool(tools.get(0));
}
public void setTool(final Tool tool) {
this.tool = tool;
log.info("Tool selected: {}", tool.getName());
onToolSelected.publish(tool);
}
public Subscription<Tool> onToolSelected(final Consumer<Tool> next) {
return onToolSelected.subscribe(next);
}
}

View File

@ -0,0 +1,30 @@
package de.ph87.kindermalen.tools;
import de.ph87.kindermalen.tools.tool.Tool;
import lombok.extern.slf4j.Slf4j;
import javax.swing.*;
import java.awt.*;
import static de.ph87.kindermalen.CONFIG.BORDERS;
@Slf4j
public class ToolsPanel extends JPanel {
public ToolsPanel(final Tools tools) {
setLayout(new FlowLayout(FlowLayout.LEADING, 0, 0));
for (final Tool tool : tools.getTools()) {
add(new ToolButton(tools, tool));
}
}
@Override
public void paint(final Graphics g) {
super.paint(g);
if (BORDERS) {
g.setColor(Color.magenta);
g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
}
}
}

View File

@ -0,0 +1,31 @@
package de.ph87.kindermalen.tools.tool;
import de.ph87.kindermalen.drawing.Drawing;
import de.ph87.kindermalen.util.Publisher;
import de.ph87.kindermalen.util.Subscription;
import de.ph87.kindermalen.util.Vector;
import lombok.Getter;
import java.awt.image.BufferedImage;
import java.util.function.Consumer;
public abstract class Tool {
protected final Publisher<Tool> onChange = new Publisher<>();
@Getter
private final String name;
protected Tool(final String name) {
this.name = name;
}
public abstract Vector apply(final Vector last, final Drawing drawing, final Vector point);
public abstract BufferedImage getPreview();
public Subscription<Tool> onChange(final Consumer<Tool> next) {
return onChange.subscribe(next);
}
}

View File

@ -0,0 +1,10 @@
package de.ph87.kindermalen.tools.tool;
import lombok.extern.slf4j.Slf4j;
import javax.swing.*;
@Slf4j
public abstract class ToolPanel extends JPanel {
}

View File

@ -1,4 +1,4 @@
package de.ph87.kindermalen.tool.stamp; package de.ph87.kindermalen.tools.tool.stamp;
import lombok.Getter; import lombok.Getter;
import lombok.ToString; import lombok.ToString;
@ -11,7 +11,7 @@ import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static de.ph87.kindermalen.ImageHelper.RESIZE; import static de.ph87.kindermalen.util.ImageHelper.RESIZE;
@Slf4j @Slf4j
@Getter @Getter
@ -22,17 +22,14 @@ public class Stamp {
private final File file; private final File file;
private BufferedImage original = null; private final BufferedImage original;
private final Map<Integer, BufferedImage> sizes = new HashMap<>(); private final Map<Integer, BufferedImage> sizes = new HashMap<>();
public Stamp(final File file) { public Stamp(final File file) throws IOException {
this.name = file.getName().substring(0, file.getName().lastIndexOf(".")); this.name = file.getName().substring(0, file.getName().lastIndexOf("."));
this.file = file; this.file = file;
} this.original = ImageIO.read(file);
public void load() throws IOException {
original = ImageIO.read(file);
log.info("Stamp loaded: {}", this); log.info("Stamp loaded: {}", this);
} }

View File

@ -0,0 +1,80 @@
package de.ph87.kindermalen.tools.tool.stamp;
import de.ph87.kindermalen.util.MouseListener;
import lombok.Getter;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import static de.ph87.kindermalen.CONFIG.*;
public class StampButton extends JPanel {
private final StampTool tool;
@Getter
private final Stamp stamp;
private final BufferedImage icon;
private final Point position;
private boolean hover = false;
public StampButton(final StampTool tool, final Stamp stamp) {
this.tool = tool;
this.stamp = stamp;
setPreferredSize(new Dimension(STAMP_BUTTON_SIZE, STAMP_BUTTON_SIZE));
MouseListener.onRelease(this, this::onRelease);
MouseListener.onEnter(this, this::onEnter);
MouseListener.onExit(this, this::onExit);
icon = stamp.getSize(STAMP_BUTTON_SIZE - STROKE_HIGHLIGHT_WIDTH * 2);
position = new Point((STAMP_BUTTON_SIZE - icon.getWidth()) / 2, (STAMP_BUTTON_SIZE - icon.getHeight()) / 2);
}
private void onRelease(final MouseEvent mouseEvent) {
this.tool.setStamp(stamp);
this.tool.prepare();
}
private void onEnter(final MouseEvent mouseEvent) {
hover = true;
repaint();
}
private void onExit(final MouseEvent mouseEvent) {
hover = false;
repaint();
}
@Override
public void paint(final Graphics g) {
super.paint(g);
final Graphics2D g2 = (Graphics2D) g;
boolean highlight = false;
if (hover) {
g2.setColor(Color.yellow);
highlight = true;
} else if (tool.getStamp() == stamp) {
g2.setColor(Color.magenta);
highlight = true;
} else {
g2.setColor(Color.black);
}
if (highlight) {
g2.setStroke(STROKE_HIGHLIGHT);
g2.fillRect(0, 0, getWidth(), getHeight());
} else {
g2.setStroke(STROKE_BORDER);
}
g2.drawImage(icon, position.x, position.y, null);
g2.drawRect(0, 0, STAMP_BUTTON_SIZE - 1, STAMP_BUTTON_SIZE - 1);
}
}

View File

@ -0,0 +1,23 @@
package de.ph87.kindermalen.tools.tool.stamp;
import lombok.extern.slf4j.Slf4j;
import javax.swing.*;
import java.awt.*;
import static de.ph87.kindermalen.CONFIG.BORDERS;
@Slf4j
public class StampListPanel extends JPanel {
public StampListPanel(final StampTool tool) {
setLayout(new FlowLayout(FlowLayout.LEADING, 0, 0));
tool.getStamps().forEach(stamp -> add(new StampButton(tool, stamp)));
tool.onChange(ignore -> repaint());
repaint();
if (BORDERS) {
setBackground(Color.green.brighter().brighter());
}
}
}

View File

@ -0,0 +1,62 @@
package de.ph87.kindermalen.tools.tool.stamp;
import javax.swing.*;
import java.awt.*;
import static de.ph87.kindermalen.CONFIG.BORDERS;
public class StampOptionsPanel extends JPanel {
private final JSlider sizeSlider = new JSlider(10, 1000, 100);
private final JSlider alphaSlider = new JSlider(1, 100, 100);
private final JSlider stepSlider = new JSlider(1, 1000, 25);
public StampOptionsPanel(final StampTool tool) {
setLayout(new GridLayout(6, 1));
final JLabel sizeLabel = new JLabel("Größe:");
add(sizeLabel);
sizeSlider.setAutoscrolls(false);
sizeSlider.addChangeListener(e -> {
sizeLabel.setText("Größe: " + sizeSlider.getValue());
tool.setSize(sizeSlider.getValue());
tool.prepare();
});
add(sizeSlider);
final JLabel alphaLabel = new JLabel("Transparenz:");
add(alphaLabel);
alphaSlider.setAutoscrolls(false);
alphaSlider.addChangeListener(e -> {
alphaLabel.setText("Transparenz: " + alphaSlider.getValue());
tool.setAlpha(alphaSlider.getValue() / 100.0);
tool.prepare();
});
add(alphaSlider);
final JLabel stepsLabel = new JLabel("Schrittweite:");
add(stepsLabel);
stepSlider.setAutoscrolls(false);
stepSlider.addChangeListener(e -> {
stepsLabel.setText("Schrittweite: " + stepSlider.getValue());
tool.setStep(stepSlider.getValue());
tool.prepare();
});
add(stepSlider);
sizeLabel.setText("Größe: " + sizeSlider.getValue());
tool.setSize(sizeSlider.getValue());
alphaLabel.setText("Transparenz: " + alphaSlider.getValue());
tool.setAlpha(alphaSlider.getValue() / 100.0);
stepsLabel.setText("Schrittweite: " + stepSlider.getValue());
tool.setStep(stepSlider.getValue());
tool.prepare();
if (BORDERS) {
setBackground(Color.blue.brighter().brighter());
}
}
}

View File

@ -0,0 +1,20 @@
package de.ph87.kindermalen.tools.tool.stamp;
import de.ph87.kindermalen.tools.tool.ToolPanel;
import lombok.extern.slf4j.Slf4j;
import java.awt.*;
import static de.ph87.kindermalen.util.MyGridBagConstraints.C;
import static java.awt.GridBagConstraints.HORIZONTAL;
@Slf4j
public class StampPanel extends ToolPanel {
public StampPanel(final StampTool tool) {
setLayout(new GridBagLayout());
add(new StampOptionsPanel(tool), C(0, 0, 1, 0, HORIZONTAL));
add(new StampListPanel(tool), C(0, 1, 1, 1));
}
}

View File

@ -0,0 +1,96 @@
package de.ph87.kindermalen.tools.tool.stamp;
import de.ph87.kindermalen.drawing.Drawing;
import de.ph87.kindermalen.tools.tool.Tool;
import de.ph87.kindermalen.util.Vector;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Objects;
import static de.ph87.kindermalen.util.FileHelper.SCAN_FILES;
import static de.ph87.kindermalen.util.ImageHelper.ALPHA;
import static de.ph87.kindermalen.util.ImageHelper.RESIZE;
@Slf4j
@Getter
@ToString
public class StampTool extends Tool {
private static final File STAMPS_DIR = new File("./data/stamps");
private final List<Stamp> stamps;
@Setter
private Stamp stamp = null;
@Setter
private int size = 100;
@Setter
private double alpha = 0.75;
@Setter
private int step = 25;
private BufferedImage prepared;
public StampTool() {
super("Stempel");
stamps = SCAN_FILES(STAMPS_DIR).stream().map(this::load).filter(Objects::nonNull).toList();
if (stamp == null && !stamps.isEmpty()) {
setStamp(stamps.get(0));
}
}
private Stamp load(final File file) {
try {
return new Stamp(file);
} catch (IOException e) {
log.error(e.toString());
return null;
}
}
public void prepare() {
if (this.stamp == null || stamp.getOriginal() == null) {
return;
}
prepared = RESIZE(stamp.getOriginal(), size, size);
ALPHA(prepared, alpha);
log.info("Stamp prepared: {}", stamp.getName());
onChange.publish(this);
}
@Override
public Vector apply(Vector last, final Drawing drawing, final Vector current) {
if (last == null) {
apply(drawing, current);
return current;
}
final Vector vector = new Vector(last, current);
for (int rest = (int) Math.floor(vector.length); rest >= step; rest -= step) {
final Vector point = last.plus(vector.withLength(step));
apply(drawing, point);
last = point;
}
return last;
}
private void apply(final Drawing drawing, final Vector point) {
drawing.getGraphics().drawImage(prepared, point.intX() - prepared.getWidth() / 2, point.intY() - prepared.getHeight() / 2, null);
drawing.publish();
}
@Override
public BufferedImage getPreview() {
return prepared;
}
}

View File

@ -0,0 +1,22 @@
package de.ph87.kindermalen.util;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class FileHelper {
public static List<File> SCAN_FILES(final File dir) {
final List<File> files = new ArrayList<>();
for (final File child : Objects.requireNonNull(dir.listFiles())) {
if (child.isFile()) {
files.add(child.getAbsoluteFile());
} else if (child.isDirectory()) {
files.addAll(SCAN_FILES(child));
}
}
return files;
}
}

View File

@ -1,4 +1,4 @@
package de.ph87.kindermalen; package de.ph87.kindermalen.util;
import com.mortennobel.imagescaling.ResampleFilters; import com.mortennobel.imagescaling.ResampleFilters;
import com.mortennobel.imagescaling.ResampleOp; import com.mortennobel.imagescaling.ResampleOp;

View File

@ -0,0 +1,39 @@
package de.ph87.kindermalen.util;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.util.function.Consumer;
public class KeyListener {
public static void onPress(final Component component, final boolean ctrl, final boolean shift, final int keycode, final Consumer<KeyEvent> onPress) {
component.addKeyListener(new KeyListenerImpl() {
@Override
public void keyPressed(final KeyEvent e) {
if (e.isControlDown() == ctrl && e.isShiftDown() == shift && e.getKeyCode() == keycode) {
onPress.accept(e);
}
}
});
}
private static class KeyListenerImpl implements java.awt.event.KeyListener {
@Override
public void keyTyped(final KeyEvent e) {
}
@Override
public void keyPressed(final KeyEvent e) {
}
@Override
public void keyReleased(final KeyEvent e) {
}
}
}

View File

@ -1,4 +1,4 @@
package de.ph87.kindermalen.tool.stamp; package de.ph87.kindermalen.util;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;

View File

@ -0,0 +1,109 @@
package de.ph87.kindermalen.util;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.util.function.Consumer;
public class MouseListener {
public static void onPress(final Component component, final Consumer<MouseEvent> onPress) {
component.addMouseListener(new MouseListenerImpl() {
@Override
public void mousePressed(final MouseEvent mouseEvent) {
onPress.accept(mouseEvent);
}
});
}
public static void onRelease(final Component component, final Consumer<MouseEvent> release) {
component.addMouseListener(new MouseListenerImpl() {
@Override
public void mouseReleased(final MouseEvent mouseEvent) {
if (release != null) {
release.accept(mouseEvent);
}
}
});
}
public static void onMove(final Component component, final Consumer<MouseEvent> onMove) {
component.addMouseMotionListener(new MouseMotionListenerImpl() {
@Override
public void mouseMoved(final MouseEvent mouseEvent) {
onMove.accept(mouseEvent);
}
});
}
public static void onDrag(final Component component, final Consumer<MouseEvent> onDrag) {
component.addMouseMotionListener(new MouseMotionListenerImpl() {
@Override
public void mouseDragged(final MouseEvent mouseEvent) {
onDrag.accept(mouseEvent);
}
});
}
public static void onEnter(final Component component, final Consumer<MouseEvent> onEnter) {
component.addMouseListener(new MouseListenerImpl() {
@Override
public void mouseEntered(final MouseEvent mouseEvent) {
onEnter.accept(mouseEvent);
}
});
}
public static void onExit(final Component component, final Consumer<MouseEvent> onExit) {
component.addMouseListener(new MouseListenerImpl() {
@Override
public void mouseExited(final MouseEvent mouseEvent) {
onExit.accept(mouseEvent);
}
});
}
private static class MouseListenerImpl implements java.awt.event.MouseListener {
@Override
public void mouseClicked(final MouseEvent mouseEvent) {
}
@Override
public void mousePressed(final MouseEvent mouseEvent) {
}
@Override
public void mouseReleased(final MouseEvent mouseEvent) {
}
@Override
public void mouseEntered(final MouseEvent mouseEvent) {
}
@Override
public void mouseExited(final MouseEvent mouseEvent) {
}
}
private static class MouseMotionListenerImpl implements MouseMotionListener {
@Override
public void mouseDragged(final MouseEvent mouseEvent) {
}
@Override
public void mouseMoved(final MouseEvent mouseEvent) {
}
}
}

View File

@ -0,0 +1,23 @@
package de.ph87.kindermalen.util;
import java.awt.*;
public class MyGridBagConstraints extends GridBagConstraints {
public MyGridBagConstraints(final int x, final int y, final int w, final int h, final double wX, final double wY, final int anchor, final int fill, final Insets insets, final int padX, final int padY) {
super(x, y, w, h, wX, wY, anchor, fill, insets, padX, padY);
}
public static MyGridBagConstraints C(final int x, final int y, final int w, final int h, final double wX, final double wY, final int anchor, final int fill) {
return new MyGridBagConstraints(x, y, w, h, wX, wY, anchor, fill, new Insets(0, 0, 0, 0), 0, 0);
}
public static MyGridBagConstraints C(final int x, final int y, final double wX, final double wY) {
return new MyGridBagConstraints(x, y, 1, 1, wX, wY, FIRST_LINE_START, BOTH, new Insets(0, 0, 0, 0), 0, 0);
}
public static MyGridBagConstraints C(final int x, final int y, final double wX, final double wY, final int fill) {
return new MyGridBagConstraints(x, y, 1, 1, wX, wY, FIRST_LINE_START, fill, new Insets(0, 0, 0, 0), 0, 0);
}
}

View File

@ -1,4 +1,4 @@
package de.ph87.kindermalen; package de.ph87.kindermalen.util;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;

View File

@ -1,4 +1,4 @@
package de.ph87.kindermalen; package de.ph87.kindermalen.util;
import java.util.function.Consumer; import java.util.function.Consumer;

View File

@ -1,6 +1,7 @@
package de.ph87.kindermalen.drawing; package de.ph87.kindermalen.util;
import java.awt.*; import java.awt.*;
import java.awt.geom.Point2D;
public class Vector { public class Vector {
@ -24,6 +25,10 @@ public class Vector {
this.length = Math.sqrt(x * x + y * y); this.length = Math.sqrt(x * x + y * y);
} }
public Vector(final Point2D point) {
this(point.getX(), point.getY());
}
public Vector withLength(final double newLength) { public Vector withLength(final double newLength) {
final double factor = newLength / length; final double factor = newLength / length;
return new Vector(x * factor, y * factor); return new Vector(x * factor, y * factor);
@ -41,4 +46,16 @@ public class Vector {
return (int) Math.round(x); return (int) Math.round(x);
} }
public Vector plus(final int x, final int y) {
return new Vector(this.x + x, this.y + y);
}
public Vector minus(final int x, final int y) {
return new Vector(this.x - x, this.y - y);
}
public Vector scale(final double factor) {
return new Vector(x * factor, y * factor);
}
} }