Skip to content

Commit c1925ca

Browse files
gajopclaude
andcommitted
Group panels/ toolkit into controls/dialogs/cursor; cleanse refactor plan
panels/ subfolders for the reusable pieces that were sitting flat: - controls/ grid, color_picker, asset_picker (field-adjacent components) - dialogs/ file_dialog (reusable modal) - cursor/ cursortip, drag_cursor (map cursor overlays) Import sites updated across the crate. The editor-hosting machinery (manager, view, input, editor_slot, field_session, modal_stack, action_dispatcher, brush_sync, editor, registry) stays flat for now. brush.rs stays in the UI layer: it is the action-strip renderer, not a brush, and moving it out would reintroduce the states -> panel dependency. Delete the spent ui-architecture.md design doc; rewrite the WIP refactor plan to record what is done and keep only the remaining structural work. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent c0a2725 commit c1925ca

24 files changed

Lines changed: 92 additions & 133 deletions

File tree

Lines changed: 54 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,131 +1,80 @@
11
---
22
name: Rust WIP refactor plan
3-
description: Structural work to complete in rust-wip before selectively moving domains into rust-stable
3+
description: Remaining structural work in rust-wip before selectively moving domains into rust-stable
44
---
55

66
# Rust WIP refactor plan
77

8-
## Purpose
9-
108
`rust-wip` is functionally broad but developed as a fast, exploratory workspace.
11-
Before work is transferred into `rust-stable`, make its ownership boundaries and
12-
module structure match [conventions.md](conventions.md). The stable branch should
13-
then receive small, reviewable domain slices rather than architectural cleanup.
14-
15-
This is a plan, not a license to cherry-pick the existing WIP history. The
16-
current 87 WIP-only commits are archaeological evidence; WIP is the source
17-
snapshot and stable receives deliberate file-level transfers.
18-
19-
## Assessment baseline
20-
21-
On 2026-07-18, `rust-stable` was the merge base of `rust-wip`. The committed
22-
delta was 463 files, +44,043 / -2,642 lines. The largest native additions were
23-
the panel UI (+13,421 lines), Chonsole (+3,729), editing states (+2,999), and
24-
developer console (+1,944).
25-
26-
The backend is already mostly feature-first: commands, models, and tests are
27-
generally co-located under their feature directories. The main exception is the
28-
native UI, which is organized by rendering technology under `panels/editors`.
29-
30-
## Refactors required before stable transfers
31-
32-
### 1. Make feature UI feature-owned
9+
Before work transfers into `rust-stable`, its ownership boundaries and module
10+
structure must match [conventions.md](conventions.md), so the stable branch
11+
receives small, reviewable domain slices rather than architectural cleanup.
3312

34-
`panels/` must retain only reusable RmlUi infrastructure: host/document
35-
lifecycle, fields, modal primitives, grid, input, and shared theme. Move actual
36-
editor behaviour beside the feature it represents:
13+
## Done
3714

38-
```text
39-
objects/ui/{definitions,properties,collision}/
40-
heightmap/ui/
41-
grass/ui/
42-
metal/ui/
43-
textures/ui/
44-
map_settings/ui/
45-
teams/ui/
46-
project/ui/
47-
```
15+
- Feature UI is feature-owned (`<feature>/ui/`, each editor split into
16+
`model` / `layout` / `behavior`); the old `panels/editors/` is gone.
17+
- `ModelShader` extracted to `sbc/render/`; `states` no longer imports panel UI.
18+
- `PanelManager` decomposed into `EditorSlot` / `FieldSession` / `ModalStack` /
19+
`ActionDispatcher` / `BrushSync`; the wide `Editor` trait is implemented once
20+
by the generic `Runtime<B>`.
21+
- Shared theme split into `panels/theme/*.rcss`.
22+
- Concrete UI moved out of `panels/`: the dev editor → `dev/`, the new-project
23+
dialog → `project/`, def thumbnails → `objects/`. Reusable pieces grouped
24+
under `panels/{controls,dialogs,cursor,fields,runtime,theme}`.
4825

49-
The generic panel registry can remain shared, but each feature must register its
50-
own editor. This is the highest-value refactor: an Objects or Textures transfer
51-
then becomes a coherent domain copy rather than surgery inside a generic folder.
26+
## Remaining
5227

53-
### 2. Remove the state → panel dependency
28+
### Objects boundary
5429

55-
Editing states currently depend on `panels::ModelShader` for ghost previews,
56-
selection highlights, movement, and rotation. Extract world rendering to
57-
`states` or a neutral renderer module. Map interaction must not depend on the
58-
right-hand panel implementation.
30+
Properties and Collision still duplicate selection projection and object-field
31+
mapping. Extract a shared `objects/ui/selection.rs` both project through. Also
32+
TODO #1: replace the generic JSON Area/Feature/Unit object commands with
33+
concrete typed commands, and cache static object-field descriptors.
5934

60-
### 3. Shrink the panel coordinator and editor contract
35+
### Split project IO from the Project feature
6136

62-
`PanelManager` currently owns document lifecycle, editor lifecycle, actions,
63-
field commits/drags, modal coordination, state synchronisation, and cursor tips.
64-
Keep a small composition point, but extract active-editor lifecycle, modal
65-
coordination, toolbar actions, and field commits into focused components.
37+
Finish extracting project paths + save/load/export registrations into a neutral
38+
project-IO/workspace module (`io_registries`, `paths` exist but still sit inside
39+
`project/`). Scenario metadata, archive export, reload, map info, and the
40+
project editor stay in `project/`. This is TODO #16; it stops each saving
41+
feature depending on the whole Project feature.
6642

67-
Likewise split the broad `Editor` trait into explicit capabilities around
68-
lifecycle/rendering, field hosting, brush/state binding, and optional modal
69-
ownership. Do not introduce a general event bus or UI framework: retain the
70-
explicit update/input order, just give each concern a narrow owner.
43+
### Texture material ownership
7144

72-
### 4. Finish the Objects boundary
45+
`list_materials` / `material_of` still live in `textures/ui/model.rs`. Move
46+
material discovery/parsing into the `textures` feature proper; the editor
47+
consumes it. Texture/material ownership must not be trapped in a panel editor
48+
before the Textures domain transfers.
7349

74-
Refactor the Objects UI into definitions/catalog/filtering/placement/thumbnails,
75-
properties, and collision submodules. Properties and collision must share
76-
selection projection and object-field mapping rather than duplicate conversion
77-
logic.
50+
### Split the E2ERun monolith
7851

79-
At the same time, complete TODO #1 in [todo.md](todo.md): replace generic
80-
JSON-based Area/Feature/Unit object commands with concrete typed commands, and
81-
cache static object-field descriptors. This makes Objects safer and smaller to
82-
review in stable.
52+
`tools/e2e/runner.py` (~1150 lines) into engine-session lifecycle, input,
53+
assertions + command-log reading, screenshots/artifacts, and reporting. Semantic
54+
UI coordinates already live in `scenarios/geometry.py`.
8355

84-
### 5. Split project persistence from the Project feature
56+
### Finish the panels/ toolkit
8557

86-
Extract project paths plus save/load/export registrations into a neutral
87-
project-IO/workspace module. Leave scenario metadata, archive export, reload,
88-
map info, and project-editor functionality in `project/`. This is TODO #16 and
89-
prevents each saving feature from depending on the whole Project feature.
58+
- `brush.rs` is misnamed: it is the brush-editor action-strip UI plus a couple
59+
of asset-field helpers, not "a brush". Rename to reflect that it is UI (e.g. an
60+
action-strip control) — it must stay in the UI layer, because it renders RML
61+
and moving it out reintroduces the `states → panel` dependency.
62+
- `modal_stack` enumerates concrete dialogs as fields
63+
(`new_project: NewProjectDialog`). If it is meant to be the app-wide modal
64+
concept, dialogs should self-register (inventory, like editors) rather than be
65+
listed. Also review what `modal_stack` actually does.
66+
- `tokens.rcss`: a single source for colours/spacing/sizes needs build-time
67+
substitution, because RmlUi's RCSS has no variables.
9068

91-
### 6. Split the texture editor by ownership
69+
### Loud duplicate registration
9270

93-
Move material discovery/parsing into `textures`, separate saved-brush state, and
94-
leave a thin UI composition layer. Texture/material ownership must not be
95-
trapped in one large panel editor before the Textures domain is transferred.
71+
Duplicate model-factory registration should fail loudly, as duplicate command
72+
registration already does.
9673

97-
### 7. Establish a shared native RmlUi theme
74+
## Do not rewrite first
9875

99-
Centralize common text, color, border, opacity, button, toggle, dropdown, and
100-
tooltip rules. Keep only document-specific layout in panel, Chonsole, and
101-
developer-console stylesheets. This prevents future stable slices from changing
102-
three visual systems for one control correction.
103-
104-
### 8. Separate E2E runner responsibilities
105-
106-
Split the `E2ERun` monolith into engine session lifecycle, input, assertions and
107-
command-log reading, screenshots/artifacts, and reporting. Keep semantic UI
108-
coordinates centralized in `scenarios/geometry.py`; that file already fixes the
109-
previous scattered-coordinate problem.
110-
111-
## Do not rewrite these first
112-
113-
- Chonsole is already sensibly divided into catalog, completion, input, history,
114-
model, and views. Transfer it as one domain after shared RmlUi lifecycle work.
115-
- Developer console has a useful actions/log/metrics/manager/view split. Limit
116-
restructuring to common lifecycle and theme extraction.
76+
- Chonsole (catalog/completion/input/history/model/views) and the developer
77+
console (actions/log/metrics/manager/view) are already sensibly divided;
78+
transfer each as one domain after shared RmlUi lifecycle work.
11779
- Do not replace the command system wholesale; reconcile only its required WIP
11880
delta against stable.
119-
120-
## Completion criteria
121-
122-
Before the first stable transfer:
123-
124-
1. Feature UI no longer lives in `panels/editors`.
125-
2. `states` no longer imports panel UI/rendering.
126-
3. Project IO is independent of the Project feature.
127-
4. The shared native theme has a single source of truth.
128-
5. The E2E harness and verification ledger identify a feature's tests without
129-
relying on obsolete phase documents.
130-
6. Duplicate model-factory registration fails loudly, as duplicate command
131-
registration already does.

docs/porting/verification.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ python3 tools/e2e/ui_driver.py <target> --tag ui:rust
4242
| 3 | Objects → Properties | VERIFIED | Selection-driven fields, complete vector/table commits, map movement, and collision-field propagation. E2E `props_panel`. |
4343
| 4 | Objects → Collision | VERIFIED | Visibility, type/axis, scale/offset/center/aim, radius/height, linked cylinder scale, and blocking fields. E2E `props_panel` and `collision`. |
4444
| 5 | Map → Terrain | VERIFIED | Pattern, size, rotation, strength, height, direction, Add/Set/Smooth, textured preview, and a stationary held stroke. E2E `heightmap`, `map-editors`, `pattern-preview`, `terrain-stationary-hold`. |
45-
| 6 | Map → Texture | VERIFIED | Saved brushes, material dialog, Paint/Filter/DNTS/Void, and splat controls. Rust is the sole owner of texture paint, cache, stroke close, undo, and redo; native GL and Lua command-bridge tests cover that ownership contract. E2E `map-paint`, `map-editors`, `texture-panel`. |
46-
| 7 | Map → Metal | VERIFIED | Pattern, size, rotation, amount, and painting. E2E `map-editors`. |
47-
| 8 | Map → Grass | VERIFIED | Pattern, detail, size, rotation, and painting. E2E `map-editors`. |
45+
| 6 | Map → Texture | VERIFIED | Saved brushes, material dialog, Paint/Filter/DNTS/Void, and splat controls. Rust is the sole owner of texture paint, cache, stroke close, undo, and redo; native GL and Lua command-bridge tests cover that ownership contract. E2E `texture-paint`, `map-editors`. |
46+
| 7 | Map → Metal | VERIFIED | Pattern, size, rotation, amount, and painting. E2E `map-editors`, `metal-paint`. |
47+
| 8 | Map → Grass | VERIFIED | Pattern, detail, size, rotation, and painting. E2E `map-editors`, `grass-paint`. |
4848
| 9 | Map → Settings | VERIFIED | Rendering flags, splat fields, detail texture, and New/Existing texture paths. E2E `map-editors`, `settings-panel`. |
4949
| 10 | Env → Lighting | VERIFIED | Shadow mode, direction, six colours, and densities. E2E `lighting-panel`. |
5050
| 11 | Env → Sky | VERIFIED | Atmosphere colours, fog bounds, and skybox picker. E2E `sky-panel`. |

native/src/sbc/map_settings/ui/settings/layout.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use spring_native::prelude::{Error, NativeInterfaceRef};
22

3-
use crate::sbc::panels::grid::{list_assets, GridItem};
3+
use crate::sbc::panels::controls::grid::{list_assets, GridItem};
44
use crate::sbc::panels::runtime::Item;
55
use crate::sbc::rml::{element_by_id, escape_rml};
66

native/src/sbc/map_settings/ui/settings/model.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ use std::cell::RefCell;
22
use std::collections::BTreeMap;
33
use std::rc::Rc;
44

5+
use crate::sbc::panels::controls::grid::GridView;
56
use crate::sbc::panels::field::FieldValue;
67
use crate::sbc::panels::fields::{AssetField, BooleanField, NumericField};
7-
use crate::sbc::panels::grid::GridView;
88
use crate::sbc::panels::runtime::{EditorModel, FieldMut, FieldRef, TableEntry, TableModel};
99

1010
#[derive(Debug, Clone, Copy, PartialEq, Eq)]

native/src/sbc/objects/ui/definitions/behavior.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use spring_native::prelude::{Error, NativeInterfaceRef};
33
use crate::sbc::command_system::model::Models;
44
use crate::sbc::objects::thumbnails::ThumbKind;
55
use crate::sbc::objects::ui::filters::DefTraits;
6+
use crate::sbc::panels::controls::grid::GridItem;
67
use crate::sbc::panels::field::{escape_rml, ChangeQueue, CommitRequest, InteractionQueue};
7-
use crate::sbc::panels::grid::GridItem;
88
use crate::sbc::panels::runtime::{Behavior, Event, Item, Outcome, Phase, Watch};
99
use crate::sbc::rml::element_by_id;
1010
use crate::sbc::states::StateRequest;

native/src/sbc/objects/ui/definitions/model.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use spring_native::prelude::{Error, NativeInterfaceRef};
77
use crate::sbc::command_system::model::Models;
88
use crate::sbc::objects::thumbnails::ThumbnailRenderer;
99
use crate::sbc::objects::ui::filters::{DefTraits, FEATURE_TYPES, TERRAINS, UNIT_TYPES};
10-
use crate::sbc::panels::grid::{GridItem, GridView};
10+
use crate::sbc::panels::controls::grid::{GridItem, GridView};
1111
use crate::sbc::panels::runtime::{
1212
Brush, DynChoice, DynChoiceDef, EditorModel, FieldMut, FieldRef, Num, NumDef, StrChoice,
1313
StrChoiceDef,

native/src/sbc/panels/asset_picker.rs renamed to native/src/sbc/panels/controls/asset_picker.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ use std::rc::Rc;
88

99
use spring_native::prelude::{Error, NativeInterfaceRef};
1010

11+
use crate::sbc::panels::controls::grid::{list_asset_tree, parent_dir, GridView};
1112
use crate::sbc::panels::field::{element_by_id, escape_rml};
12-
use crate::sbc::panels::grid::{list_asset_tree, parent_dir, GridView};
1313

1414
#[derive(Debug, Clone, Copy)]
1515
pub(crate) enum PickerEvent {
File renamed without changes.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
//! Interactive components fields and dialogs are built from — grid views and
2+
//! the colour/asset pickers. Field-like, but not `Field` value controls.
3+
4+
pub(crate) mod asset_picker;
5+
pub(crate) mod color_picker;
6+
pub(crate) mod grid;

0 commit comments

Comments
 (0)