- Selection: add addAll() method for bulk shape addition - Controller: box selection with mouse drag on empty space - ShapeDraftman: drawSelectionBox() for rubber-band rendering - ShapesView: currentSelectionBox field and setter
163 lines
6.2 KiB
Java
163 lines
6.2 KiB
Java
package ovh.gasser.newshapes.ui;
|
|
|
|
import ovh.gasser.newshapes.ShapeVisitor;
|
|
import ovh.gasser.newshapes.attributes.ColorAttributes;
|
|
import ovh.gasser.newshapes.attributes.SelectionAttributes;
|
|
import ovh.gasser.newshapes.shapes.*;
|
|
import ovh.gasser.newshapes.shapes.Shape;
|
|
|
|
import java.awt.*;
|
|
|
|
public class ShapeDraftman implements ShapeVisitor {
|
|
|
|
private static final ColorAttributes DEFAULT_COLOR_ATTRIBUTES =
|
|
new ColorAttributes(false, true, Color.BLACK, Color.BLACK);
|
|
private final Graphics2D g2d;
|
|
private boolean resizeMode;
|
|
|
|
public ShapeDraftman(Graphics graph) {
|
|
this.g2d = (Graphics2D) graph;
|
|
}
|
|
|
|
public void setResizeMode(boolean resizeMode) {
|
|
this.resizeMode = resizeMode;
|
|
}
|
|
|
|
@Override
|
|
public void visitRectangle(SRectangle rect) {
|
|
Rectangle r = rect.getBounds();
|
|
ColorAttributes colAttrs = (ColorAttributes) rect.getAttributes(ColorAttributes.ID);
|
|
if (colAttrs == null){
|
|
colAttrs = DEFAULT_COLOR_ATTRIBUTES;
|
|
}
|
|
if (colAttrs.filled) {
|
|
this.g2d.setColor(colAttrs.filledColor);
|
|
this.g2d.fillRect(r.x, r.y, r.width, r.height);
|
|
}
|
|
if (colAttrs.stroked) {
|
|
this.g2d.setColor(colAttrs.strokedColor);
|
|
this.g2d.drawRect(r.x, r.y, r.width, r.height);
|
|
}
|
|
drawHandlerIfSelected(rect);
|
|
}
|
|
|
|
@Override
|
|
public void visitCollection(SCollection collection) {
|
|
for (Shape s: collection) {
|
|
s.accept(this);
|
|
}
|
|
drawHandlerIfSelected(collection);
|
|
}
|
|
|
|
@Override
|
|
public void visitCircle(SCircle circle) {
|
|
ColorAttributes colAttrs = (ColorAttributes) circle.getAttributes(ColorAttributes.ID);
|
|
final Rectangle bounds = circle.getBounds();
|
|
if (colAttrs == null) {
|
|
colAttrs = DEFAULT_COLOR_ATTRIBUTES;
|
|
}
|
|
if (colAttrs.filled) {
|
|
this.g2d.setColor(colAttrs.filledColor);
|
|
this.g2d.fillOval(bounds.x, bounds.y, 2 * circle.getRadius(), 2 * circle.getRadius());
|
|
}
|
|
if (colAttrs.stroked) {
|
|
this.g2d.setColor(colAttrs.strokedColor);
|
|
this.g2d.drawOval(bounds.x, bounds.y, 2 * circle.getRadius(), 2 * circle.getRadius());
|
|
}
|
|
|
|
drawHandlerIfSelected(circle);
|
|
}
|
|
|
|
@Override
|
|
public void visitTriangle(STriangle tri) {
|
|
ColorAttributes colAttrs = (ColorAttributes) tri.getAttributes(ColorAttributes.ID);
|
|
var bounds = tri.getBounds();
|
|
var size = Math.min(bounds.width, bounds.height); // Should be the same because we only support equilateral triangles
|
|
if (colAttrs == null){
|
|
colAttrs = DEFAULT_COLOR_ATTRIBUTES;
|
|
}
|
|
if (colAttrs.filled) {
|
|
this.g2d.setColor(colAttrs.filledColor);
|
|
this.g2d.fillPolygon(
|
|
new int[]{ bounds.x, bounds.x + (size/2), bounds.x + size },
|
|
new int[]{ bounds.y + size, bounds.y, bounds.y + size },
|
|
3);
|
|
}
|
|
if (colAttrs.stroked) {
|
|
this.g2d.setColor(colAttrs.strokedColor);
|
|
this.g2d.drawPolygon(
|
|
new int[]{bounds.x, bounds.x + (size / 2), bounds.x + size},
|
|
new int[]{bounds.y + size, bounds.y, bounds.y + size},
|
|
3);
|
|
}
|
|
|
|
drawHandlerIfSelected(tri);
|
|
}
|
|
|
|
@Override
|
|
public void visitText(SText text) {
|
|
ColorAttributes colAttrs = (ColorAttributes) text.getAttributes(ColorAttributes.ID);
|
|
|
|
Font previousFont = g2d.getFont();
|
|
Color previousColor = g2d.getColor();
|
|
Font textFont = new Font(text.getFontName(), Font.PLAIN, text.getFontSize());
|
|
g2d.setFont(textFont);
|
|
g2d.setColor(resolveTextColor(colAttrs));
|
|
|
|
FontMetrics metrics = g2d.getFontMetrics(textFont);
|
|
int width = metrics.stringWidth(text.getText());
|
|
int height = metrics.getHeight();
|
|
text.updateMeasuredBounds(width, height);
|
|
|
|
Rectangle bounds = text.getBounds();
|
|
g2d.drawString(text.getText(), bounds.x, bounds.y + metrics.getAscent());
|
|
|
|
g2d.setFont(previousFont);
|
|
g2d.setColor(previousColor);
|
|
drawHandlerIfSelected(text);
|
|
}
|
|
|
|
private Color resolveTextColor(ColorAttributes attrs) {
|
|
if (attrs == null) {
|
|
return Color.BLACK;
|
|
}
|
|
if (attrs.filledColor != null) {
|
|
return attrs.filledColor;
|
|
}
|
|
if (attrs.strokedColor != null) {
|
|
return attrs.strokedColor;
|
|
}
|
|
return Color.BLACK;
|
|
}
|
|
|
|
private void drawHandlerIfSelected(Shape s) {
|
|
SelectionAttributes selAttrs = (SelectionAttributes) s.getAttributes(SelectionAttributes.ID);
|
|
if ((selAttrs != null) && (selAttrs.selected)){
|
|
Rectangle bounds = s.getBounds();
|
|
this.g2d.setColor(Color.RED);
|
|
int handleSize = 10;
|
|
this.g2d.drawRect(bounds.x - handleSize, bounds.y - handleSize, handleSize, handleSize);
|
|
this.g2d.drawRect(bounds.x + bounds.width, bounds.y + bounds.height, handleSize, handleSize);
|
|
if (resizeMode) {
|
|
this.g2d.drawRect(bounds.x + bounds.width, bounds.y - handleSize, handleSize, handleSize);
|
|
this.g2d.drawRect(bounds.x - handleSize, bounds.y + bounds.height, handleSize, handleSize);
|
|
this.g2d.drawRect(bounds.x + bounds.width / 2 - handleSize / 2, bounds.y - handleSize, handleSize, handleSize);
|
|
this.g2d.drawRect(bounds.x + bounds.width / 2 - handleSize / 2, bounds.y + bounds.height, handleSize, handleSize);
|
|
this.g2d.drawRect(bounds.x - handleSize, bounds.y + bounds.height / 2 - handleSize / 2, handleSize, handleSize);
|
|
this.g2d.drawRect(bounds.x + bounds.width, bounds.y + bounds.height / 2 - handleSize / 2, handleSize, handleSize);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void drawSelectionBox(Rectangle box) {
|
|
if (box == null) return;
|
|
g2d.setXORMode(Color.WHITE);
|
|
g2d.setColor(Color.BLUE);
|
|
g2d.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT,
|
|
BasicStroke.JOIN_MITER, 1, new float[]{4, 4}, 0));
|
|
g2d.drawRect(box.x, box.y, box.width, box.height);
|
|
g2d.setPaintMode();
|
|
}
|
|
|
|
}
|