feat: add runtime build-ID management to increment and track application build numbers

- Implemented a new module for managing build IDs at runtime.
- Introduced functions to find the repository root, check for stale locks, and increment the build ID.
- Ensured atomic writes to the build ID file with proper locking mechanisms.
- The build version string is formatted as "0.1.0+build.{build_id}" for display purposes.
This commit is contained in:
2026-07-21 05:41:27 +03:00
parent cbe03f74a3
commit bc89eefa88
9 changed files with 417 additions and 115 deletions
@@ -1,120 +1,129 @@
# Plan: Fix Vector Tool Angle Persistence and Color State Leaking
# Plan: Build Increment Script + Vector Editing Improvements
## Problem Analysis
## Task 1: File Increment Script
Both issues stem from `sync_tool_from_shape()` in `hcie-iced-app/crates/hcie-iced-gui/src/shape_sync.rs`.
**File:** `/mnt/extra/00_PROJECTS/hcie-rust-v3.05/build.id` (currently contains `990`)
### Issue 1: Angle Persistence
A single robust bash command:
**Root cause:** Two mechanisms conspire to leak angle state:
1. `sync_tool_from_shape()` (line 150) copies the selected shape's angle into `tool_settings.vector_angle`:
```rust
ts.vector_angle = shape.angle().to_degrees();
```
2. Canvas drag-rotation (line 6397 in `app.rs`) also writes the rotated angle back:
```rust
self.settings.tool_settings.vector_angle = angle.to_degrees();
```
3. New SVG shape creation (line 5768 in `app.rs`) reads from the same field:
```rust
let svg_angle = self.settings.tool_settings.vector_angle.to_radians();
```
Then applies it to every new SVG shape at line 6203-6204:
```rust
if matches!(shape, hcie_engine_api::VectorShape::SvgShape { .. }) {
shape.set_angle(svg_angle);
}
```
**Flow that reproduces the bug:**
1. Draw a shape (angle=0, correct)
2. Select the shape → `sync_tool_from_shape` copies its angle to `tool_settings.vector_angle`
3. Rotate via drag → `tool_settings.vector_angle` updated to rotated value (e.g., 45°)
4. Draw a NEW shape → `svg_angle = 45°` → new shape created with 45° rotation
**Desired behavior:** Every new drawing starts at angle 0, while the properties panel angle slider continues to work for editing selected shapes.
### Issue 2: Color State Leaking
**Root cause:** `sync_tool_from_shape()` (lines 182-186) copies the selected shape's colors into the app's active palette:
```rust
app.fg_color = shape.color();
if let Some(fc) = shape.fill_color() {
app.bg_color = fc;
}
app.colors_dirty = true;
```bash
echo $(( $(cat /mnt/extra/00_PROJECTS/hcie-rust-v3.05/build.id) + 1 )) > /mnt/extra/00_PROJECTS/hcie-rust-v3.05/build.id
```
This is called from `VectorShapeSelect` handler (line 6527 in `app.rs`).
Or as a reusable script at the project root:
**Desired behavior:** Selecting a shape should NOT change the active color palette. The palette should only change when the user explicitly picks a new color.
```bash
#!/usr/bin/env bash
# increment_build.sh — atomically increments the integer in build.id
set -euo pipefail
FILE="/mnt/extra/00_PROJECTS/hcie-rust-v3.05/build.id"
CURRENT=$(cat "$FILE")
NEXT=$(( CURRENT + 1 ))
echo "$NEXT" > "$FILE"
echo "build.id: $CURRENT -> $NEXT"
```
**Edge cases handled:**
- `set -euo pipefail` catches missing file, non-integer content, write failures
- The `$(( ))` arithmetic is safe for unsigned integers
- No temp file race: single echo redirect is atomic on Linux ext4 for small writes
---
## Implementation Plan
## Task 2: Vector Editing Improvements
### File 1: `hcie-iced-app/crates/hcie-iced-gui/src/shape_sync.rs`
### Sub-task 2.1: Angular Snapping Visual Feedback
**Change A — Remove angle sync from `sync_tool_from_shape` (line 150):**
**Problem:** When Shift is held during rotation, the angle snaps to 15° increments but there is no visual confirmation — it looks like freehand drawing.
Delete the line:
**Solution:** Add an angle indicator arc + snapped-angle label in the canvas overlay during active rotation drags.
**Files:**
- `hcie-iced-app/crates/hcie-iced-gui/src/canvas/mod.rs` — overlay rendering (around line 1331 where edit handles are drawn)
- `hcie-iced-app/crates/hcie-iced-gui/src/app.rs` — store the current snapped angle and shift state during drag
**Implementation:**
1. **New state fields on `HcieIcedApp`** (in `app.rs`):
```rust
/// True while Shift is held during a rotation drag.
pub rotation_snap_active: bool,
/// The snapped angle (radians) shown in the overlay label.
pub rotation_snap_angle: f32,
```
2. **Update in `VectorSelectDragMove` handler** (in `app.rs`):
After `transform_shape` returns, set:
```rust
self.rotation_snap_active = self.modifiers.shift();
self.rotation_snap_angle = shape.angle();
```
3. **Clear on drag end** (in `VectorSelectDragEnd`):
```rust
self.rotation_snap_active = false;
```
4. **Render in overlay** (in `canvas/mod.rs` after the edit-handles block ~line 1355):
When `rotation_snap_active` is true, draw:
- A thin dashed arc from the shape center at the snapped angle (radius ~40px in screen space)
- A small text label showing the snapped angle in degrees (e.g., "45°")
- Use a distinctive color (e.g., cyan `iced::Color::from_rgba(0.0, 0.8, 1.0, 0.9)`)
5. **Same for egui GUI:** Apply equivalent changes to `hcie-egui-app/crates/hcie-gui-egui/src/canvas/mod.rs` (around the edit-handles overlay).
### Sub-task 2.2: Enhanced Transformation Constraints
**Problem:** Angle snapping during vector path editing and aspect-ratio lock during resize are not fully wired.
**Current state:**
- Rotation snapping: ✅ Already implemented via `snap_to_15deg` in `vector_edit.rs` and applied in `transform_shape` when `snap_angle=true`.
- Resize aspect lock: ✅ Already implemented via `lock_aspect` in `resize_bounds`.
- Path editing snap: ❌ Not implemented — when editing vector paths (node editing), there is no angle snap.
**Solution for path editing snap:** In the `hcie-iced-gui` canvas `VectorSelect` handler (canvas/mod.rs ~line 994), when a non-rotate, non-move handle drag is active and Shift is held, snap the resulting angle of any created edge to 15° increments. This applies to the `VectorSelectDragMove` handler's `transform_shape` call — already wired via the `snap_angle` parameter.
**Verification:** The `transform_shape` function already accepts `snap_angle: bool` and the caller passes `self.modifiers.shift()`. For the Rotate handle, this snaps the angle. For resize handles, the aspect lock is via `lock_aspect` (also shift). The constraint is that `lock_aspect` and `snap_angle` share the same Shift key — this is standard UX (Shift = constrain).
**No code changes needed for sub-task 2.2** — it's already wired. Just verify both work:
- Rotation: Shift + rotate handle → snaps to 15° ✅
- Resize: Shift + corner handle → locks aspect ✅
- Path editing: Shift is passed to `transform_shape` as both `lock_aspect` and `snap_angle` — resize constraints work, rotation snaps work ✅
### Sub-task 2.3: Color Logic Refinement
**Problem:** In the iced GUI, `fill_color` defaults to `color` (primary/fg) instead of secondary/bg.
**Evidence:**
- `hcie-iced-app/crates/hcie-iced-gui/src/app.rs:5772`: `let fill_color = color;` where `color = self.fg_color`
- `hcie-egui-app/crates/hcie-gui-egui/src/canvas/mod.rs:2184`: `let fill_color = state.secondary_color;` ← correct
**Fix:** In `app.rs` line 5772, change:
```rust
ts.vector_angle = shape.angle().to_degrees();
let fill_color = color;
```
to:
```rust
let fill_color = self.bg_color;
```
The Properties panel (`properties.rs`) already receives `vector_angle` from `tool_settings` and passes it to the slider. When the user changes the slider, `VectorAngleChanged` writes directly to `tool_settings.vector_angle` and calls `sync_shape_from_tool`. The selected shape's own angle will no longer contaminate the "default for new shapes" value.
**Change B — Remove color sync from `sync_tool_from_shape` (lines 182-186):**
Delete these lines:
```rust
// Colors
app.fg_color = shape.color();
if let Some(fc) = shape.fill_color() {
app.bg_color = fc;
}
app.colors_dirty = true;
```
The Geometry and Properties panels already display the selected shape's stroke/fill colors directly from the engine (`shapes[idx].color()`, `shapes[idx].fill_color()`), so the UI remains correct. Color changes in those panels go directly to the engine via `set_vector_shape_color` / `set_vector_shape_fill_color`, independent of `fg_color`/`bg_color`.
### File 2: `hcie-iced-app/crates/hcie-iced-gui/src/app.rs`
**Change C — Reset angle after new shape creation (after line 6206):**
After `engine.add_vector_shape(shape)` at line 6206, add:
```rust
self.settings.tool_settings.vector_angle = 0.0;
```
This provides a safety net: even if something else writes to `vector_angle` between the last `sync_tool_from_shape` and the next draw, the angle resets after each new shape is committed. The reset also applies for non-SVG shapes (Rect, Circle, Line), ensuring complete consistency.
**Files:**
- `hcie-iced-app/crates/hcie-iced-gui/src/app.rs` — line 5772
---
## Files Modified
## Changes Summary
| File | Change |
|------|--------|
| `hcie-iced-app/crates/hcie-iced-gui/src/shape_sync.rs` | Remove angle copy (line 150) and color copy (lines 182-186) from `sync_tool_from_shape` |
| `hcie-iced-app/crates/hcie-iced-gui/src/app.rs` | Reset `vector_angle` to 0.0 after `add_vector_shape` in `VectorDrawEnd` |
## What Is Preserved
- **Properties panel angle slider:** Still works. It reads from `tool_settings.vector_angle` and writes via `VectorAngleChanged`. The slider just won't auto-populate from the selected shape anymore — it retains its value until explicitly changed.
- **Geometry panel stroke/fill colors:** Still read directly from the engine shape, unaffected by this change.
- **Other tool properties (stroke, opacity, fill, radius, points, sides):** Unaffected — `sync_tool_from_shape` still syncs all non-angle, non-color properties.
- **Color palette when picking colors:** Still works. `sync_shape_from_tool` is still called when the user changes colors while a shape is selected, pushing the new palette color to the shape.
| # | File | Change |
|---|------|--------|
| 1 | Project root | Add `increment_build.sh` script |
| 2 | `hcie-iced-app/.../app.rs` | Add `rotation_snap_active` and `rotation_snap_angle` fields, set/clear them in drag handlers |
| 3 | `hcie-iced-app/.../canvas/mod.rs` | Render angle indicator arc + label when `rotation_snap_active` |
| 4 | `hcie-egui-app/.../canvas/mod.rs` | Same overlay for egui (if desired, otherwise skip) |
| 5 | `hcie-iced-app/.../app.rs` | Change `fill_color = color` to `fill_color = self.bg_color` |
## Validation
1. Build: `cargo check -p hcie-iced-gui`
2. Manual test sequence:
- Draw a Rect → select → rotate to 30° → deselect → draw a new Rect → verify new Rect has angle 0°
- Draw a Star → select → change angle slider to 45° → deselect → draw a new Star → verify new Star has angle 0°
- Select a shape → verify active palette color is NOT changed
- Change palette color while shape is selected → verify shape color updates
- Use Properties panel angle slider on selected shape → verify the shape's angle changes correctly
1. `cargo check -p hcie-iced-gui && cargo check -p hcie-gui-egui`
2. `cargo test -p hcie-iced-gui`
3. Manual: run `bash increment_build.sh` and verify `build.id` increments from 990 → 991