diff --git a/Box-Selection.md b/Box-Selection.md new file mode 100644 index 0000000..0b52e24 --- /dev/null +++ b/Box-Selection.md @@ -0,0 +1,53 @@ +# Plan: Box Selection + +## Overview +Add drag-to-select functionality for selecting multiple shapes within a rectangle. + +## Current State +- Click selects single shape (in Controller.mousePressed) +- Shift+click adds to selection +- Selection uses SelectionAttributes + +## Implementation Plan + +### 1. Controller changes +- Add state: `boxSelectOrigin` (Point), `boxSelectActive` (boolean) +- Add `boxSelectionRectangle` (Rectangle) for current drag area + +### 2. Mouse handling +- `mousePressed`: + - If click on empty area (no shape), start box selection + - Store origin point + - Clear current selection unless Shift is held +- `mouseDragged`: + - If boxSelectActive, update rectangle from origin to current point + - Repaint to show selection box +- `mouseReleased`: + - Calculate final box rectangle + - Find all shapes whose bounds intersect with box + - Add to selection (or replace if no Shift) + - Clear box selection state, repaint + +### 3. Visual feedback +- Draw semi-transparent rectangle during drag in ShapesView +- Use XOR mode or overlay for drawing +- Box outline: dashed line, gray color + +### 4. Selection behavior +- Default: box replaces current selection +- Shift+drag: box adds to current selection +- Box entirely within shape = shape selected +- Partial overlap: select shape (standard behavior) + +### 5. Intersection check +- Use `shape.getBounds().intersects(boxRect)` +- Handle composite shapes (SCollection) - check children + +## Files to modify +- `ui/Controller.java` - mouse handling +- `ui/ShapesView.java` - draw box overlay in paintComponent + +## Edge cases +- Drag on existing selection: allow move instead of box select +- Very small drag (< 5px): treat as click, select shape under point +- Empty box: clear selection diff --git a/Home.md b/Home.md index 1f576c2..303d60a 100644 --- a/Home.md +++ b/Home.md @@ -1 +1,8 @@ -Bienvenue sur le Wiki. \ No newline at end of file +# Home + +## Project Plans + +1. [Resize Shapes](Resize-Shapes.md) - Add ability to resize shapes by dragging corner handles +2. [Text Shapes](Text-Shapes.md) - Add support for creating text shapes +3. [Undo/Redo Stack](Undo-Redo-Stack.md) - Implement undo/redo functionality +4. [Box Selection](Box-Selection.md) - Add drag-to-select for multiple shapes diff --git a/Resize-Shapes.md b/Resize-Shapes.md new file mode 100644 index 0000000..a042315 --- /dev/null +++ b/Resize-Shapes.md @@ -0,0 +1,45 @@ +# Plan: Resize Shapes + +## Overview +Add the ability to resize shapes by dragging corner handles on selected shapes. + +## Current State +- Selection already draws red corner handles via `ShapeDraftman.drawHandlerIfSelected()` +- `Controller` handles mouse events for selection and moving +- Selection uses `SelectionAttributes` on shapes + +## Implementation Plan + +### 1. ResizeHandle enum +- Create `ResizeHandle` enum in `shapes/` package with positions: NW, N, NE, E, SE, S, SW, W +- Each handle knows its cursor type + +### 2. Controller changes +- Add mouse state: `resizing` (boolean), `activeHandle` (ResizeHandle), `resizeOrigin` (Point) +- Add `getHandleAt(Point)` method to find which handle is clicked +- Modify mouse handlers: + - `mousePressed`: If click is on a handle, enter resize mode + - `mouseDragged`: If resizing, calculate delta and call shape's resize method + - `mouseReleased`: Exit resize mode +- Add cursor changes based on handle position + +### 3. Shape interface changes +- Add `resize(ResizeHandle handle, int dx, int dy)` method to `Shape` interface +- Implement in `AbstractShape` or each concrete shape +- For basic shapes (rectangle, circle, triangle): + - Rectangle: adjust width/height based on handle + - Circle: adjust radius (maintain aspect ratio or allow ellipse) + - Triangle: adjust vertices + +### 4. Visual feedback +- Update `ShapeDraftman` to use different handle positions (not just corners) +- Consider showing resize preview during drag + +## Files to modify +- `shapes/Shape.java` - add resize method +- `ui/Controller.java` - mouse handling for resize +- `shapes/SRectangle.java`, `SCircle.java`, `STriangle.java` - implement resize logic + +## Alternative consideration +- Could use a separate `Resizer` class to keep Controller clean +- Could implement resize in `AbstractShape` for common logic diff --git a/Text-Shapes.md b/Text-Shapes.md new file mode 100644 index 0000000..cc85bcd --- /dev/null +++ b/Text-Shapes.md @@ -0,0 +1,62 @@ +# Plan: Text Shapes + +## Overview +Add support for creating text shapes in the canvas. + +## Current State +- Available shapes: SRectangle, SCircle, STriangle +- Uses visitor pattern for rendering +- Menu system in App.java for adding shapes + +## Implementation Plan + +### 1. Create SText class +- New class `shapes/SText` extending `AbstractShape` +- Fields: `text` (String), `fontSize` (int, default 16), `fontName` (String, default "SansSerif"), `fontStyle` (int, default Font.PLAIN) +- Empty or cancelled input falls back to placeholder `"Text"` +- Override `resize(ResizeHandle, int, int)` as no-op (text not resizable) +- Implement `accept(ShapeVisitor)` calling `visitor.visitText(this)` +- Bounds are stored as a Rectangle at construction time (position only, zero size); updated and cached by ShapeDraftman on each paint via FontMetrics for accurate hit-test and selection + +### 2. ShapeVisitor interface change +- Add `visitText(SText text)` to the `ShapeVisitor` interface +- All implementations must implement this method + +### 3. ShapeDraftman changes +- Implement `visitText(SText)`: render with `Graphics2D.drawString()` +- After drawing, measure text via `g2d.getFontMetrics()` and update the cached bounds on the SText object +- Selection visuals reuse existing `drawHandlerIfSelected()` with measured bounds + +### 4. SVGDraftman / HTMLDraftman changes +- Implement `visitText(SText)` in both visitors +- Escape special characters in text content for safe export (& < > " ') + +### 5. Controller changes +- Add lightweight text-placement mode (boolean `addingText`) +- When active, next canvas click prompts via `JOptionPane.showInputDialog()` +- If input is null (cancelled): do not create shape, exit text-placement mode +- If input is empty: use placeholder `"Text"` +- Create `SText` at click position, add to model, exit text-placement mode + +### 6. App.java changes +- Add "Add Text" menu item that calls `controller.enterTextMode()` +- Single-line, no wrapping; bounds expand horizontally with text length + +## Files to create/modify +- Create: `shapes/SText.java` +- Modify: `ShapeVisitor.java` — add `visitText(SText)` +- Modify: `ui/ShapeDraftman.java` — implement visitText, update bounds via FontMetrics +- Modify: `ui/visitors/SVGDraftman.java` — implement visitText +- Modify: `ui/visitors/HTMLDraftman.java` — implement visitText +- Modify: `ui/Controller.java` — add text-placement mode +- Modify: `App.java` — add "Add Text" menu item + +## Defaults +- Font: SansSerif, plain, size 16 +- Placeholder: "Text" +- Text is single-line, no wrapping + +## Out of scope (first version) +- Double-click to edit existing text +- Font size/style configuration via UI +- Text resize (no-op for now) diff --git a/Undo-Redo-Stack.md b/Undo-Redo-Stack.md new file mode 100644 index 0000000..3cf5a67 --- /dev/null +++ b/Undo-Redo-Stack.md @@ -0,0 +1,51 @@ +# Plan: Undo/Redo Stack + +## Overview +Implement undo/redo functionality with a command history stack. + +## Current State +- Controller handles shape operations (add, delete, move, color change) +- No command history exists +- Selection system tracks selected shapes + +## Implementation Plan + +### 1. Command pattern +- Create `Command` interface with `execute()` and `undo()` methods +- Create concrete commands: + - `AddShapeCommand` - stores shape reference, removes on undo + - `DeleteShapesCommand` - stores shapes list, re-adds on undo + - `MoveShapeCommand` - stores shape, original pos, new pos + - `ChangeColorCommand` - stores shape, old/new colors + - `ResizeCommand` - stores shape, old/new bounds + - `GroupCommand` - composite for batch operations + +### 2. CommandManager class +- Maintains two stacks: `undoStack`, `redoStack` +- `execute(Command)`: push to undoStack, clear redoStack +- `undo()`: pop from undoStack, call undo(), push to redoStack +- `redo()`: pop from redoStack, call execute(), push to undoStack +- Limit stack size (e.g., 50 commands) + +### 3. Controller integration +- Replace direct shape operations with commands +- Example: instead of `collection.add(shape)`, do `commandManager.execute(new AddShapeCommand(shape, collection))` + +### 4. Keyboard shortcuts +- Ctrl+Z: undo +- Ctrl+Y: redo (or Ctrl+Shift+Z) +- Update menu with these shortcuts + +### 5. Menu additions +- Add Edit menu items: Undo, Redo +- Enable/disable based on stack state + +## Files to create/modify +- Create: `commands/Command.java`, `commands/CommandManager.java` +- Create: `commands/AddShapeCommand.java`, `commands/DeleteShapesCommand.java`, `commands/MoveShapeCommand.java`, etc. +- Modify: `ui/Controller.java`, `App.java` (menu) + +## Edge cases +- Copy/paste after undo: clear redo stack +- Multi-select delete: single compound command +- Application close: no persistence needed (in-memory only)