Implement copy action
This commit is contained in:
parent
b4eac668c8
commit
aea90f5a93
@ -3,7 +3,6 @@ package ovh.gasser.newshapes;
|
|||||||
import ovh.gasser.newshapes.shapes.SCircle;
|
import ovh.gasser.newshapes.shapes.SCircle;
|
||||||
import ovh.gasser.newshapes.shapes.SCollection;
|
import ovh.gasser.newshapes.shapes.SCollection;
|
||||||
import ovh.gasser.newshapes.shapes.SRectangle;
|
import ovh.gasser.newshapes.shapes.SRectangle;
|
||||||
import ovh.gasser.newshapes.shapes.Shape;
|
|
||||||
import ovh.gasser.newshapes.ui.ShapesView;
|
import ovh.gasser.newshapes.ui.ShapesView;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
@ -12,7 +11,7 @@ import java.awt.*;
|
|||||||
public class App {
|
public class App {
|
||||||
|
|
||||||
public static final Dimension WIN_SIZE = new Dimension(800, 600);
|
public static final Dimension WIN_SIZE = new Dimension(800, 600);
|
||||||
private Shape model;
|
private SCollection model;
|
||||||
|
|
||||||
private App() throws HeadlessException {
|
private App() throws HeadlessException {
|
||||||
final JFrame frame = new JFrame("Reactive shapes");
|
final JFrame frame = new JFrame("Reactive shapes");
|
||||||
|
@ -48,4 +48,7 @@ public abstract class AbstractShape implements Shape {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("x=%d, y=%d, width=%d, height=%d", bounds.x, bounds.y, bounds.width, bounds.height);
|
return String.format("x=%d, y=%d, width=%d, height=%d", bounds.x, bounds.y, bounds.width, bounds.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract Shape clone();
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package ovh.gasser.newshapes.shapes;
|
package ovh.gasser.newshapes.shapes;
|
||||||
|
|
||||||
import ovh.gasser.newshapes.ShapeVisitor;
|
import ovh.gasser.newshapes.ShapeVisitor;
|
||||||
|
import ovh.gasser.newshapes.attributes.ColorAttributes;
|
||||||
import ovh.gasser.newshapes.attributes.SelectionAttributes;
|
import ovh.gasser.newshapes.attributes.SelectionAttributes;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
@ -19,13 +20,24 @@ public class SCircle extends AbstractShape {
|
|||||||
visitor.visitCircle(this);
|
visitor.visitCircle(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Shape clone() {
|
||||||
|
var color = (ColorAttributes) getAttributes(ColorAttributes.ID);
|
||||||
|
return SCircle.create(super.getBounds().x, super.getBounds().y, this.radius, color.strokedColor);
|
||||||
|
}
|
||||||
|
|
||||||
public int getRadius() {
|
public int getRadius() {
|
||||||
return radius;
|
return radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SCircle create(int x, int y, int radius) {
|
public static SCircle create(int x, int y, int radius) {
|
||||||
|
return create(x, y, radius, Color.BLACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SCircle create(int x, int y, int radius, Color color) {
|
||||||
var circle = new SCircle(x, y, radius);
|
var circle = new SCircle(x, y, radius);
|
||||||
circle.addAttributes(new SelectionAttributes());
|
circle.addAttributes(new SelectionAttributes());
|
||||||
|
circle.addAttributes(new ColorAttributes(false, true, Color.BLACK, color));
|
||||||
return circle;
|
return circle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Spliterator;
|
import java.util.Spliterator;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class SCollection extends AbstractShape implements Streamable<Shape> {
|
public class SCollection extends AbstractShape implements Streamable<Shape> {
|
||||||
private final static Logger logger = LoggerFactory.getLogger(SCollection.class);
|
private final static Logger logger = LoggerFactory.getLogger(SCollection.class);
|
||||||
@ -43,6 +44,14 @@ public class SCollection extends AbstractShape implements Streamable<Shape> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Shape clone() {
|
||||||
|
var clonedChildren = children.stream().map(Shape::clone).toArray(Shape[]::new);
|
||||||
|
var collection = new SCollection(clonedChildren);
|
||||||
|
collection.addAttributes(new SelectionAttributes());
|
||||||
|
return collection;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setLoc(Point newLoc) {
|
public void setLoc(Point newLoc) {
|
||||||
final Point loc = getBounds().getLocation();
|
final Point loc = getBounds().getLocation();
|
||||||
@ -59,6 +68,10 @@ public class SCollection extends AbstractShape implements Streamable<Shape> {
|
|||||||
return children.spliterator();
|
return children.spliterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void add(Shape s) {
|
||||||
|
children.add(s);
|
||||||
|
}
|
||||||
|
|
||||||
public void remove(Shape s) {
|
public void remove(Shape s) {
|
||||||
if (!children.remove(s)) {
|
if (!children.remove(s)) {
|
||||||
logger.error("Unable to delete shape: {}", s);
|
logger.error("Unable to delete shape: {}", s);
|
||||||
|
@ -24,14 +24,19 @@ public class SRectangle extends AbstractShape {
|
|||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Shape clone() {
|
||||||
|
var color = (ColorAttributes) this.getAttributes(ColorAttributes.ID);
|
||||||
|
return SRectangle.create(super.getBounds().x, super.getBounds().y, getBounds().width, getBounds().height, color.strokedColor);
|
||||||
|
}
|
||||||
|
|
||||||
public static SRectangle create(int x, int y, int width, int height) {
|
public static SRectangle create(int x, int y, int width, int height) {
|
||||||
SRectangle rect = new SRectangle(new Rectangle(x, y, width, height));
|
return create(x, y, width, height, Color.BLACK);
|
||||||
rect.addAttributes(new SelectionAttributes());
|
|
||||||
return rect;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SRectangle create(int x, int y, int width, int height, Color color) {
|
public static SRectangle create(int x, int y, int width, int height, Color color) {
|
||||||
final SRectangle rect = create(x, y, width, height);
|
SRectangle rect = new SRectangle(new Rectangle(x, y, width, height));
|
||||||
|
rect.addAttributes(new SelectionAttributes());
|
||||||
rect.addAttributes(new ColorAttributes(false, true, Color.BLACK, color));
|
rect.addAttributes(new ColorAttributes(false, true, Color.BLACK, color));
|
||||||
return rect;
|
return rect;
|
||||||
}
|
}
|
||||||
|
@ -12,4 +12,5 @@ public interface Shape {
|
|||||||
Attributes getAttributes(String key);
|
Attributes getAttributes(String key);
|
||||||
void addAttributes(Attributes attr);
|
void addAttributes(Attributes attr);
|
||||||
Rectangle getBounds();
|
Rectangle getBounds();
|
||||||
|
Shape clone();
|
||||||
}
|
}
|
||||||
|
@ -15,10 +15,10 @@ import java.util.Optional;
|
|||||||
public class Controller {
|
public class Controller {
|
||||||
private final static Logger logger = LoggerFactory.getLogger(Controller.class);
|
private final static Logger logger = LoggerFactory.getLogger(Controller.class);
|
||||||
private final ShapesView view;
|
private final ShapesView view;
|
||||||
private final Shape model;
|
private final SCollection model;
|
||||||
private Selection selection;
|
private Selection selection;
|
||||||
|
|
||||||
Controller(ShapesView view, Shape model) {
|
Controller(ShapesView view, SCollection model) {
|
||||||
this.view = view;
|
this.view = view;
|
||||||
this.model = model;
|
this.model = model;
|
||||||
|
|
||||||
@ -53,8 +53,7 @@ public class Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleMousePressed(MouseEvent evt) {
|
private void handleMousePressed(MouseEvent evt) {
|
||||||
var sc = (SCollection) this.model;
|
getTarget(evt, this.model)
|
||||||
getTarget(evt, sc)
|
|
||||||
.ifPresentOrElse(
|
.ifPresentOrElse(
|
||||||
s -> {
|
s -> {
|
||||||
if (selection != null) resetSelection();
|
if (selection != null) resetSelection();
|
||||||
@ -73,18 +72,29 @@ public class Controller {
|
|||||||
case KeyEvent.VK_DELETE:
|
case KeyEvent.VK_DELETE:
|
||||||
deleteSelected();
|
deleteSelected();
|
||||||
break;
|
break;
|
||||||
|
case KeyEvent.VK_C:
|
||||||
|
copySelection();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
logger.warn("Pressed unhandled key: {}", evt.getKeyChar());
|
logger.warn("Pressed unhandled key: {}", evt.getKeyChar());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void copySelection() {
|
||||||
|
if (selection == null) {
|
||||||
|
logger.debug("No selection to copy");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.model.add(selection.shape.clone());
|
||||||
|
view.repaint();
|
||||||
|
}
|
||||||
|
|
||||||
private void deleteSelected() {
|
private void deleteSelected() {
|
||||||
if (selection == null) return;
|
if (selection == null) return;
|
||||||
logger.debug("Deleting selected shape(s)");
|
logger.debug("Deleting selected shape(s)");
|
||||||
var sc = (SCollection) this.model;
|
this.model.remove(selection.shape);
|
||||||
sc.remove(selection.shape);
|
resetSelection();
|
||||||
selection = null;
|
|
||||||
view.repaint();
|
view.repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ package ovh.gasser.newshapes.ui;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import ovh.gasser.newshapes.ShapeVisitor;
|
import ovh.gasser.newshapes.ShapeVisitor;
|
||||||
|
import ovh.gasser.newshapes.shapes.SCollection;
|
||||||
import ovh.gasser.newshapes.shapes.Shape;
|
import ovh.gasser.newshapes.shapes.Shape;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
@ -15,7 +16,7 @@ public class ShapesView extends JPanel {
|
|||||||
private final Controller controller;
|
private final Controller controller;
|
||||||
private ShapeVisitor draftman;
|
private ShapeVisitor draftman;
|
||||||
|
|
||||||
public ShapesView(Shape model) {
|
public ShapesView(SCollection model) {
|
||||||
this.model = model;
|
this.model = model;
|
||||||
this.controller = new Controller(this, model);
|
this.controller = new Controller(this, model);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user