MyComponent out of Destructible to handle Component-Events too

This commit is contained in:
Patrick Haßel 2023-02-27 09:33:42 +01:00
parent 16593e4fd5
commit cae3f0b2cf
11 changed files with 198 additions and 239 deletions

View File

@ -1,40 +0,0 @@
package de.ph87.kindermalen;
import de.ph87.kindermalen.util.Publisher;
import de.ph87.kindermalen.util.Subscription;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public abstract class Destructible extends JPanel {
private final List<Subscription<?>> subscriptions = new ArrayList<>();
public void destruct() {
subscriptions.forEach(this::unsubscribe);
synchronized (getTreeLock()) {
for (final Component component : getComponents()) {
if (component instanceof Destructible) {
((Destructible) component).destruct();
}
}
}
}
protected <T> Subscription<T> subscribe(final Publisher<T> publisher, final Consumer<T> next) {
final Subscription<T> subscription = publisher.subscribe(next);
subscriptions.add(subscription);
return subscription;
}
protected void unsubscribe(final Subscription<?> subscription) {
if (!subscriptions.remove(subscription)) {
throw new RuntimeException();
}
subscription.unsubscribe();
}
}

View File

@ -0,0 +1,102 @@
package de.ph87.kindermalen;
import de.ph87.kindermalen.util.Publisher;
import de.ph87.kindermalen.util.Subscription;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public abstract class MyComponent extends JPanel implements ComponentListener, MouseListener, MouseMotionListener {
private final List<Subscription<?>> subscriptions = new ArrayList<>();
public MyComponent() {
addComponentListener(this);
addMouseListener(this);
addMouseMotionListener(this);
}
public void destruct() {
subscriptions.forEach(this::unsubscribe);
synchronized (getTreeLock()) {
for (final Component component : getComponents()) {
if (component instanceof MyComponent) {
((MyComponent) component).destruct();
}
}
}
}
protected <T> Subscription<T> subscribe(final Publisher<T> publisher, final Consumer<T> next) {
final Subscription<T> subscription = publisher.subscribe(next);
subscriptions.add(subscription);
return subscription;
}
protected void unsubscribe(final Subscription<?> subscription) {
if (!subscriptions.remove(subscription)) {
throw new RuntimeException();
}
subscription.unsubscribe();
}
@Override
public void componentResized(final ComponentEvent e) {
// nothing
}
@Override
public void componentMoved(final ComponentEvent e) {
// nothing
}
@Override
public void componentShown(final ComponentEvent e) {
// nothing
}
@Override
public void componentHidden(final ComponentEvent e) {
// nothing
}
@Override
public void mouseClicked(final MouseEvent mouseEvent) {
// nothing
}
@Override
public void mousePressed(final MouseEvent mouseEvent) {
// nothing
}
@Override
public void mouseReleased(final MouseEvent mouseEvent) {
// nothing
}
@Override
public void mouseEntered(final MouseEvent mouseEvent) {
// nothing
}
@Override
public void mouseExited(final MouseEvent mouseEvent) {
// nothing
}
@Override
public void mouseDragged(final MouseEvent mouseEvent) {
// nothing
}
@Override
public void mouseMoved(final MouseEvent mouseEvent) {
// nothing
}
}

View File

@ -5,24 +5,27 @@ import de.ph87.kindermalen.tools.tool.Tool;
import de.ph87.kindermalen.tools.tool.ToolPanel; import de.ph87.kindermalen.tools.tool.ToolPanel;
import de.ph87.kindermalen.tools.tool.stamp.StampPanel; import de.ph87.kindermalen.tools.tool.stamp.StampPanel;
import de.ph87.kindermalen.tools.tool.stamp.StampTool; import de.ph87.kindermalen.tools.tool.stamp.StampTool;
import de.ph87.kindermalen.util.MouseListener;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.awt.event.MouseEvent;
import static de.ph87.kindermalen.CONFIG.BORDERS; import static de.ph87.kindermalen.CONFIG.BORDERS;
import static de.ph87.kindermalen.util.MyGridBagConstraints.C; import static de.ph87.kindermalen.util.MyGridBagConstraints.C;
public class Sidebar extends Destructible { public class Sidebar extends MyComponent {
private final Environment environment;
private ToolPanel toolPanel = null; private ToolPanel toolPanel = null;
public Sidebar(final Environment environment) { public Sidebar(final Environment environment) {
this.environment = environment;
setPreferredSize(new Dimension(300, 0)); setPreferredSize(new Dimension(300, 0));
setLayout(new GridBagLayout()); setLayout(new GridBagLayout());
final JButton newDrawing = new JButton("Neues Bild"); final JButton newDrawing = new JButton("Neues Bild");
MouseListener.onPress(newDrawing, e -> environment.newDrawing());
add(newDrawing, C(0, 0, 1, 0)); add(newDrawing, C(0, 0, 1, 0));
final ToolsPanel toolsPanel = new ToolsPanel(environment.getTools()); final ToolsPanel toolsPanel = new ToolsPanel(environment.getTools());
@ -31,6 +34,11 @@ public class Sidebar extends Destructible {
subscribe(environment.getTools().getOnSelect(), this::onToolSelected); subscribe(environment.getTools().getOnSelect(), this::onToolSelected);
} }
@Override
public void mousePressed(final MouseEvent mouseEvent) {
environment.newDrawing();
}
@Override @Override
public void paint(final Graphics g) { public void paint(final Graphics g) {
super.paint(g); super.paint(g);

View File

@ -1,6 +1,5 @@
package de.ph87.kindermalen.drawing; package de.ph87.kindermalen.drawing;
import lombok.Getter;
import lombok.ToString; import lombok.ToString;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -13,15 +12,14 @@ import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
@Slf4j @Slf4j
@Getter
@ToString @ToString
public class Drawing { public class Drawing {
private final int width; public final int width;
private final int height; public final int height;
private final ZonedDateTime created = ZonedDateTime.now(); public final ZonedDateTime created = ZonedDateTime.now();
@ToString.Exclude @ToString.Exclude
private final Layer current; private final Layer current;

View File

@ -1,16 +1,14 @@
package de.ph87.kindermalen.drawing; package de.ph87.kindermalen.drawing;
import de.ph87.kindermalen.Destructible;
import de.ph87.kindermalen.Environment; import de.ph87.kindermalen.Environment;
import de.ph87.kindermalen.MyComponent;
import de.ph87.kindermalen.tools.tool.Tool; import de.ph87.kindermalen.tools.tool.Tool;
import de.ph87.kindermalen.util.MouseListener;
import de.ph87.kindermalen.util.Subscription; import de.ph87.kindermalen.util.Subscription;
import de.ph87.kindermalen.util.Vector; import de.ph87.kindermalen.util.Vector;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.awt.*; import java.awt.*;
import java.awt.event.ComponentEvent; 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.AffineTransform;
import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.NoninvertibleTransformException;
@ -20,7 +18,7 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
@Slf4j @Slf4j
public class DrawingPanel extends Destructible { public class DrawingPanel extends MyComponent {
private static final File SAVE_DIR = new File("./data/images"); private static final File SAVE_DIR = new File("./data/images");
@ -38,14 +36,18 @@ public class DrawingPanel extends Destructible {
public DrawingPanel(final Environment environment) { public DrawingPanel(final Environment environment) {
this.environment = environment; this.environment = environment;
MouseListener.onPress(this, this::onPress);
MouseListener.onRelease(this, this::onRelease);
MouseListener.onMove(this, this::onMove);
MouseListener.onDrag(this, this::onDrag);
subscribe(environment.getTools().getOnSelect(), this::onToolSelect); subscribe(environment.getTools().getOnSelect(), this::onToolSelect);
subscribe(environment.getOnNewDrawing(), drawing -> repaint()); subscribe(environment.getOnNewDrawing(), drawing -> repaint());
}
private void onToolSelect(final Tool tool) {
repaint();
if (toolChangeSubscription != null) {
unsubscribe(toolChangeSubscription);
}
toolChangeSubscription = subscribe(tool.getOnChange(), ignore -> repaint());
}
addComponentListener(new ComponentListener() {
@Override @Override
public void componentResized(final ComponentEvent e) { public void componentResized(final ComponentEvent e) {
calculateTransform(); calculateTransform();
@ -58,26 +60,46 @@ public class DrawingPanel extends Destructible {
@Override @Override
public void componentShown(final ComponentEvent e) { public void componentShown(final ComponentEvent e) {
calculateTransform();
} }
@Override @Override
public void componentHidden(final ComponentEvent e) { public void mousePressed(final MouseEvent mouseEvent) {
if (mouseEvent.getButton() == 3) {
environment.getDrawing().undo();
return;
} }
}); environment.getDrawing().newRevision();
lastPoint = environment.getTools().getTool().apply(null, environment.getDrawing(), transform(mouseEvent.getPoint()));
repaint();
} }
private void onToolSelect(final Tool tool) { @Override
repaint(); public void mouseReleased(final MouseEvent mouseEvent) {
if (toolChangeSubscription != null) { try {
unsubscribe(toolChangeSubscription); environment.getDrawing().save(SAVE_DIR);
} catch (IOException ex) {
log.error(ex.toString());
} }
toolChangeSubscription = subscribe(tool.getOnChange(), ignore -> repaint()); }
@Override
public void mouseDragged(final MouseEvent mouseEvent) {
cursor = transform(mouseEvent.getPoint());
lastPoint = environment.getTools().getTool().apply(lastPoint, environment.getDrawing(), transform(mouseEvent.getPoint()));
repaint();
}
@Override
public void mouseMoved(final MouseEvent mouseEvent) {
cursor = transform(mouseEvent.getPoint());
repaint();
} }
private void calculateTransform() { private void calculateTransform() {
final Image image = environment.getDrawing().getImage(); final Drawing drawing = environment.getDrawing();
final Rectangle box = fitInside(image.getWidth(null), image.getHeight(null), getWidth(), getHeight(), false); final Rectangle box = fitInside(drawing.width, drawing.height, getWidth(), getHeight(), false);
final double scale = (double) box.width / image.getWidth(null); final double scale = (double) box.width / drawing.width;
transform = new AffineTransform(); transform = new AffineTransform();
transform.translate(box.x, box.y); transform.translate(box.x, box.y);
transform.scale(scale, scale); transform.scale(scale, scale);
@ -88,40 +110,11 @@ public class DrawingPanel extends Destructible {
} }
} }
private void onMove(final MouseEvent mouseEvent) {
cursor = transform(mouseEvent.getPoint());
repaint();
}
private void onPress(final MouseEvent mouseEvent) {
if (mouseEvent.getButton() == 3) {
environment.getDrawing().undo();
return;
}
environment.getDrawing().newRevision();
lastPoint = environment.getTools().getTool().apply(null, environment.getDrawing(), transform(mouseEvent.getPoint()));
repaint();
}
private void onDrag(final MouseEvent mouseEvent) {
cursor = transform(mouseEvent.getPoint());
lastPoint = environment.getTools().getTool().apply(lastPoint, environment.getDrawing(), transform(mouseEvent.getPoint()));
repaint();
}
private Vector transform(final Point point) { private Vector transform(final Point point) {
final Point2D transformed = inverseTransform.transform(new Point2D.Double(point.x, point.y), null); final Point2D transformed = inverseTransform.transform(new Point2D.Double(point.x, point.y), null);
return new Vector(transformed); return new Vector(transformed);
} }
private void onRelease(final MouseEvent mouseEvent) {
try {
environment.getDrawing().save(SAVE_DIR);
} catch (IOException ex) {
log.error(ex.toString());
}
}
@Override @Override
public void paint(final Graphics graphics) { public void paint(final Graphics graphics) {
final Graphics2D g = (Graphics2D) graphics; final Graphics2D g = (Graphics2D) graphics;
@ -129,15 +122,15 @@ public class DrawingPanel extends Destructible {
g.fillRect(0, 0, getWidth(), getHeight()); g.fillRect(0, 0, getWidth(), getHeight());
g.setTransform(transform); g.setTransform(transform);
if (environment == null) { if (environment == null || environment.getDrawing() == null) {
return; return;
} }
final Image image = environment.getDrawing().getImage(); final Drawing drawing = environment.getDrawing();
g.setColor(Color.white); g.setColor(Color.white);
g.fillRect(0, 0, image.getWidth(null), image.getHeight(null)); g.fillRect(0, 0, drawing.width, drawing.height);
g.drawImage(image, 0, 0, image.getWidth(null), image.getHeight(null), null); g.drawImage(drawing.getImage(), 0, 0, drawing.width, drawing.height, null);
final BufferedImage preview = environment.getTools().getTool().getPreview(); final BufferedImage preview = environment.getTools().getTool().getPreview();
if (cursor != null && preview != null) { if (cursor != null && preview != null) {

View File

@ -1,20 +1,28 @@
package de.ph87.kindermalen.tools; package de.ph87.kindermalen.tools;
import de.ph87.kindermalen.MyComponent;
import de.ph87.kindermalen.tools.tool.Tool; import de.ph87.kindermalen.tools.tool.Tool;
import de.ph87.kindermalen.util.MouseListener;
import java.awt.*; import java.awt.*;
import java.awt.event.MouseEvent;
import static de.ph87.kindermalen.CONFIG.STAMP_BUTTON_SIZE; import static de.ph87.kindermalen.CONFIG.STAMP_BUTTON_SIZE;
public class ToolButton extends Component { public class ToolButton extends MyComponent {
private final Tools tools;
private final Tool tool; private final Tool tool;
public ToolButton(final Tools tools, final Tool tool) { public ToolButton(final Tools tools, final Tool tool) {
this.tools = tools;
this.tool = tool; this.tool = tool;
setPreferredSize(new Dimension(STAMP_BUTTON_SIZE, STAMP_BUTTON_SIZE)); setPreferredSize(new Dimension(STAMP_BUTTON_SIZE, STAMP_BUTTON_SIZE));
MouseListener.onRelease(this, e -> tools.setTool(tool)); }
@Override
public void mouseReleased(final MouseEvent mouseEvent) {
tools.setTool(tool);
} }
@Override @Override

View File

@ -1,9 +1,9 @@
package de.ph87.kindermalen.tools.tool; package de.ph87.kindermalen.tools.tool;
import de.ph87.kindermalen.Destructible; import de.ph87.kindermalen.MyComponent;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
public abstract class ToolPanel extends Destructible { public abstract class ToolPanel extends MyComponent {
} }

View File

@ -1,16 +1,15 @@
package de.ph87.kindermalen.tools.tool.stamp; package de.ph87.kindermalen.tools.tool.stamp;
import de.ph87.kindermalen.util.MouseListener; import de.ph87.kindermalen.MyComponent;
import lombok.Getter; import lombok.Getter;
import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import static de.ph87.kindermalen.CONFIG.*; import static de.ph87.kindermalen.CONFIG.*;
public class StampButton extends JPanel { public class StampButton extends MyComponent {
private final StampTool tool; private final StampTool tool;
@ -27,24 +26,24 @@ public class StampButton extends JPanel {
this.tool = tool; this.tool = tool;
this.image = image; this.image = image;
setPreferredSize(new Dimension(STAMP_BUTTON_SIZE, STAMP_BUTTON_SIZE)); 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 = image.getSize(STAMP_BUTTON_ICON_REAL_SIZE); icon = image.getSize(STAMP_BUTTON_ICON_REAL_SIZE);
position = new Point((STAMP_BUTTON_SIZE - icon.getWidth()) / 2, (STAMP_BUTTON_SIZE - icon.getHeight()) / 2); position = new Point((STAMP_BUTTON_SIZE - icon.getWidth()) / 2, (STAMP_BUTTON_SIZE - icon.getHeight()) / 2);
} }
private void onRelease(final MouseEvent mouseEvent) { @Override
public void mouseReleased(final MouseEvent mouseEvent) {
this.tool.setImage(image); this.tool.setImage(image);
this.tool.prepare(); this.tool.prepare();
} }
private void onEnter(final MouseEvent mouseEvent) { @Override
public void mouseEntered(final MouseEvent mouseEvent) {
hover = true; hover = true;
repaint(); repaint();
} }
private void onExit(final MouseEvent mouseEvent) { @Override
public void mouseExited(final MouseEvent mouseEvent) {
hover = false; hover = false;
repaint(); repaint();
} }

View File

@ -1,6 +1,6 @@
package de.ph87.kindermalen.tools.tool.stamp; package de.ph87.kindermalen.tools.tool.stamp;
import de.ph87.kindermalen.Destructible; import de.ph87.kindermalen.MyComponent;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.awt.*; import java.awt.*;
@ -8,7 +8,7 @@ import java.util.Comparator;
import java.util.List; import java.util.List;
@Slf4j @Slf4j
public class StampButtonList extends Destructible { public class StampButtonList extends MyComponent {
public StampButtonList(final StampTool stampTool) { public StampButtonList(final StampTool stampTool) {
final FlowLayout flowLayout = new FlowLayout(FlowLayout.LEADING, 0, 0); final FlowLayout flowLayout = new FlowLayout(FlowLayout.LEADING, 0, 0);

View File

@ -1,13 +1,13 @@
package de.ph87.kindermalen.tools.tool.stamp; package de.ph87.kindermalen.tools.tool.stamp;
import de.ph87.kindermalen.Destructible; import de.ph87.kindermalen.MyComponent;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import static de.ph87.kindermalen.CONFIG.BORDERS; import static de.ph87.kindermalen.CONFIG.BORDERS;
public class StampOptions extends Destructible { public class StampOptions extends MyComponent {
private final JSlider sizeSlider = new JSlider(10, 1000, 100); private final JSlider sizeSlider = new JSlider(10, 1000, 100);

View File

@ -1,109 +0,0 @@
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) {
}
}
}