feat: implement keyboard and mouse input, pattern placement, and HiDPI scaling
Add configurable key bindings (TOML), modifier-aware dispatch, mouse-driven pattern placement with preview and rotation, cell grid storage/rendering, and fractional/integer HiDPI scaling. Archive the input-and-placement change and sync its specs to main specs. Tests: Hashtable, Config, Grid, Pattern (4/4 pass).
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
# Spec Delta
|
||||
|
||||
## Purpose
|
||||
|
||||
Stores and renders the Game of Life cell grid with a fixed cell size and wall boundaries, independent of future simulation rules.
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Grid stores alive and dead cells
|
||||
The system SHALL maintain a grid of cells, each either alive or dead, addressable by column and row.
|
||||
|
||||
#### Scenario: Cell access
|
||||
- **WHEN** a cell is set to alive
|
||||
- **THEN** reading that cell returns alive
|
||||
- **AND** cells never set remain dead
|
||||
|
||||
### Requirement: Boundary cells are treated as dead
|
||||
The system SHALL treat any cell outside the grid bounds as dead and shall not store state outside the grid.
|
||||
|
||||
#### Scenario: Out of bounds read
|
||||
- **WHEN** a cell position outside the grid is queried
|
||||
- **THEN** the result is dead
|
||||
|
||||
### Requirement: Grid resizes while preserving overlapping cells
|
||||
The system SHALL preserve cells that remain within bounds when the grid dimensions change, clearing only cells that fall outside the new bounds.
|
||||
|
||||
#### Scenario: Enlarge grid
|
||||
- **WHEN** the grid grows in either dimension
|
||||
- **THEN** previously alive cells within the old bounds remain alive
|
||||
|
||||
#### Scenario: Shrink grid
|
||||
- **WHEN** the grid shrinks in either dimension
|
||||
- **THEN** cells outside the new bounds are discarded
|
||||
- **AND** remaining cells keep their state
|
||||
|
||||
### Requirement: Cell size is fixed in logical pixels
|
||||
The system SHALL use a cell size of 8 logical pixels, so grid dimensions derive from the logical surface size.
|
||||
|
||||
#### Scenario: Dimension calculation
|
||||
- **WHEN** the logical surface is 400 pixels wide
|
||||
- **THEN** the grid has 50 columns
|
||||
|
||||
### Requirement: Alive cells are rendered
|
||||
The system SHALL render alive cells distinctly from dead cells.
|
||||
|
||||
#### Scenario: Render alive cell
|
||||
- **WHEN** a cell is alive
|
||||
- **THEN** it is drawn with the alive cell color
|
||||
|
||||
### Requirement: Grid can be cleared
|
||||
The system SHALL set all cells to dead when the clear action is triggered.
|
||||
|
||||
#### Scenario: Clear grid
|
||||
- **WHEN** the user triggers the clear action
|
||||
- **THEN** all cells become dead
|
||||
|
||||
### Requirement: Grid lines can be toggled
|
||||
The system SHALL show or hide grid lines when the toggle_grid action is triggered.
|
||||
|
||||
#### Scenario: Toggle lines
|
||||
- **WHEN** the user triggers the toggle_grid action
|
||||
- **THEN** grid line visibility flips
|
||||
@@ -0,0 +1,45 @@
|
||||
# Spec Delta
|
||||
|
||||
## Purpose
|
||||
|
||||
Keeps the application rendering crisp on displays with integer or fractional scaling by converting between logical and physical coordinates.
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Fractional scale is applied when available
|
||||
The system SHALL use the compositor-provided fractional preferred scale for rendering when the fractional scale protocol is available.
|
||||
|
||||
#### Scenario: Fractional display
|
||||
- **WHEN** the compositor sends a preferred scale of 1.5
|
||||
- **THEN** the render buffer is created at 1.5 times the logical size
|
||||
- **AND** the buffer is displayed at the logical size
|
||||
|
||||
### Requirement: Integer scale is used as fallback
|
||||
The system SHALL use the output's integer scale when fractional scale is unavailable.
|
||||
|
||||
#### Scenario: No fractional protocol
|
||||
- **WHEN** the compositor does not support fractional scaling
|
||||
- **THEN** the render buffer uses the output integer scale
|
||||
- **AND** the buffer is displayed at the logical size
|
||||
|
||||
### Requirement: Input coordinates remain logical
|
||||
The system SHALL report mouse positions and grid cells in logical coordinates regardless of the active scale.
|
||||
|
||||
#### Scenario: Scaled click
|
||||
- **WHEN** the user clicks on a scaled display
|
||||
- **THEN** the selected grid cell matches the visual location of the cursor
|
||||
|
||||
### Requirement: Rendering uses physical resolution
|
||||
The system SHALL render all content at physical resolution so that lines and cells stay sharp at the active scale.
|
||||
|
||||
#### Scenario: Sharp cells
|
||||
- **WHEN** the application runs on a 2x scaled display
|
||||
- **THEN** cells are drawn with 2 physical pixels per logical pixel
|
||||
|
||||
### Requirement: Scale changes trigger re-render
|
||||
The system SHALL recreate buffers and re-render when the active scale changes.
|
||||
|
||||
#### Scenario: Scale change
|
||||
- **WHEN** the compositor changes the preferred scale
|
||||
- **THEN** the application updates its buffers
|
||||
- **AND** subsequent frames use the new scale
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
# Spec Delta
|
||||
|
||||
## Purpose
|
||||
|
||||
Allows users to configure keyboard shortcuts that map key combinations to application actions, with sensible built-in defaults when no configuration file exists.
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Default bindings are available without configuration
|
||||
The system SHALL provide built-in default bindings for all documented actions, including digits 1-4 selecting the Glider, Blinker, Block, and Toad patterns, Space rotating, Escape cancelling, and Ctrl+Q quitting.
|
||||
|
||||
#### Scenario: No config file present
|
||||
- **WHEN** the application starts and `~/.config/wlgol/keys.conf` does not exist
|
||||
- **THEN** the application uses the built-in default bindings
|
||||
- **AND** creates the config file with the default contents
|
||||
|
||||
### Requirement: Configuration file overrides defaults by merge
|
||||
The system SHALL read `~/.config/wlgol/keys.conf` as TOML when it exists and merge its entries over the built-in defaults, so only specified keys change.
|
||||
|
||||
#### Scenario: Partial override
|
||||
- **WHEN** the config file defines a binding for key "1" only
|
||||
- **THEN** key "1" uses the configured action
|
||||
- **AND** all other keys keep their default bindings
|
||||
|
||||
#### Scenario: Full replacement of a key
|
||||
- **WHEN** the config file defines a binding for a key that has a default
|
||||
- **THEN** the configured action replaces the default for that key
|
||||
|
||||
### Requirement: Key combinations are modifier-aware
|
||||
The system SHALL match a binding only when the modifiers required by the binding are active, supporting Ctrl, Shift, Alt, and Super.
|
||||
|
||||
#### Scenario: Modifier required
|
||||
- **WHEN** the user presses Q while Ctrl is held and a `ctrl+q = quit` binding exists
|
||||
- **THEN** the quit action is triggered
|
||||
|
||||
#### Scenario: Modifier not held
|
||||
- **WHEN** the user presses Q without Ctrl while a `ctrl+q = quit` binding exists
|
||||
- **THEN** the quit action is not triggered by that binding
|
||||
|
||||
### Requirement: Readable key aliases are supported
|
||||
The system SHALL accept human-readable key names such as space, escape, enter, and arrow names in binding keys.
|
||||
|
||||
#### Scenario: Alias binding
|
||||
- **WHEN** the config file contains `space = rotate`
|
||||
- **THEN** pressing the space bar triggers the rotate action
|
||||
|
||||
### Requirement: Malformed entries are ignored
|
||||
The system SHALL ignore malformed or unrecognized binding entries and continue using defaults for the affected keys.
|
||||
|
||||
#### Scenario: Invalid entry
|
||||
- **WHEN** the config file contains an entry with an unknown action
|
||||
- **THEN** that entry is ignored
|
||||
- **AND** the application still starts successfully
|
||||
|
||||
### Requirement: Actions trigger on key press
|
||||
The system SHALL dispatch a bound action when the corresponding key is pressed, not on release.
|
||||
|
||||
#### Scenario: Press triggers action
|
||||
- **WHEN** the user presses a key with a valid binding
|
||||
- **THEN** the bound action is invoked once for that press
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
# Spec Delta
|
||||
|
||||
## Purpose
|
||||
|
||||
Lets users select a Game of Life pattern, preview it under the mouse cursor, rotate it, and place copies on the grid with a click.
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Selecting a pattern arms a placement tool
|
||||
The system SHALL activate a placement tool for the selected pattern when a `select:<pattern>` action is triggered, and show a preview following the cursor.
|
||||
|
||||
#### Scenario: Tool activation
|
||||
- **WHEN** the user triggers `select:glider`
|
||||
- **THEN** a glider preview appears at the current cursor position
|
||||
- **AND** the placement tool remains active
|
||||
|
||||
### Requirement: Preview follows cursor motion
|
||||
The system SHALL update the preview position to track the current mouse cursor cell while a tool is active.
|
||||
|
||||
#### Scenario: Mouse moves
|
||||
- **WHEN** the user moves the mouse while a tool is active
|
||||
- **THEN** the preview moves to the cell under the cursor
|
||||
|
||||
### Requirement: Tool can be rotated in 90-degree steps
|
||||
The system SHALL rotate the active preview by 90 degrees each time the rotate action is triggered.
|
||||
|
||||
#### Scenario: Rotate preview
|
||||
- **WHEN** the user triggers the rotate action while a tool is active
|
||||
- **THEN** the preview rotates 90 degrees clockwise
|
||||
- **AND** remains at the same anchor cell
|
||||
|
||||
### Requirement: Left click places the pattern when valid
|
||||
The system SHALL write the active pattern's alive cells into the grid at the preview position when the user left-clicks and the pattern fits entirely within the grid.
|
||||
|
||||
#### Scenario: Valid placement
|
||||
- **WHEN** the user left-clicks while a tool is active and the preview fits in the grid
|
||||
- **THEN** the pattern's cells become alive in the grid
|
||||
- **AND** the tool remains active for further placement
|
||||
|
||||
### Requirement: Invalid placement is rejected
|
||||
The system SHALL not modify the grid when a left click occurs while the preview extends outside the grid.
|
||||
|
||||
#### Scenario: Out of bounds
|
||||
- **WHEN** the user left-clicks while the preview extends outside the grid
|
||||
- **THEN** no cells are changed
|
||||
- **AND** the tool remains active
|
||||
|
||||
### Requirement: Escape cancels the active tool
|
||||
The system SHALL deactivate the placement tool and remove the preview when the cancel action is triggered.
|
||||
|
||||
#### Scenario: Cancel placement
|
||||
- **WHEN** the user triggers the cancel action while a tool is active
|
||||
- **THEN** the preview disappears
|
||||
- **AND** no further clicks place a pattern until a tool is selected again
|
||||
|
||||
### Requirement: Click without active tool does nothing
|
||||
The system SHALL ignore left clicks when no placement tool is active.
|
||||
|
||||
#### Scenario: No tool
|
||||
- **WHEN** the user left-clicks while no tool is active
|
||||
- **THEN** the grid is unchanged
|
||||
Reference in New Issue
Block a user