Module Structure
The application state lives on NullCadApp, split across several app_*
files by concern (canvas, dialogs, menus, tools, properties, layers, status
bar, input, I/O), backed by a set of focused subsystem modules.
| Module | Purpose |
|---|---|
app.rs | Main application state and egui integration |
app_canvas_ui.rs, app_dialogs_ui.rs, app_menu_ui.rs, app_tool_ui.rs, app_properties_ui.rs, app_layer_ui.rs, app_statusbar_ui.rs, app_input.rs, app_io.rs | UI and input, split by concern |
document/ | Document model, geometry objects, spatial index, comparisons, selection sets |
operations/ | Operation types, history, executor, snapshots — see Operation System |
commands/ | Legacy command system (superseded by operations/, still present, being migrated out) |
geometry/ | Geometry primitives (Point, Line, Polyline, Polygon, Rectangle, Circle, Arc, Text, PlanImage, TIN surface, page proxy, viewport) |
renderer/ | wgpu renderer, camera, auto-contrast, line types, PDF/image underlays, tile rendering — see Precision Handling |
tools/ | Interactive tool modules (point, edit, trim, offset, text/callout annotation, TIN, page proxy, viewport) |
annotations/ | Text and callout annotations with anchoring, styling, and leaders |
labels/ | Point label generation with collision detection |
selection/, select_similar.rs | Selection set management, hit testing, select-by-attribute |
snapping/ | Snap point detection and configuration |
layers/, codelist/ | Layer/group management and code→layer import mapping |
gis_io/native/ | Pure-Rust import/export: Shapefile, GeoJSON, DXF, CSV, .ncweb web bundle |
gis_io/gdal/ | Optional GDAL formats: KML, GeoPackage, MapInfo TAB, FileGDB |
pdf_export/, pdf_viewer.rs | Vector PDF export (page proxies → pages) and in-app PDF plan viewer |
mcp/ | In-process MCP server exposing the document to AI agents |
plugins/ | Lua plugin system: commands, tools, panels/dialogs, event hooks |
console/ | Application message log |
settings/, autosave.rs, template.rs | Persistent settings, autosave/crash recovery, document templates |
ui/ | Reusable UI components (operation log, phase tabs, resource panel, color/codelist pickers) |
archive/ | ZIP-based .nullcad file reading/writing with resource management |
utils/ | DMS parsing, unit conversions |
Document model (src/document/)
Document— the central store; geometry in aHashMapkeyed byGeometryId.GeometryId— UUID v4, for global uniqueness (collaboration-ready).GeometryObject— wraps aGeometrywith metadata (created_by, timestamps, phase, layer, name/code, tombstone).- Spatial index — an
rstarR-tree, auto-maintained on create/delete/modify and rebuilt on load; powers O(log n) hit testing and range queries.
Geometry (src/geometry/)
The Geometry enum covers Point, Line, Polyline, Polygon, Text,
Circle, Arc, Rectangle, PlanImage (a PDF page placed in world
space), TinSurface, PageProxy, Viewport, and ViewportView. All
coordinates are f64; the crate integrates with the geo crate’s types.
Modular tool development
Interactive tools are self-contained modules in src/tools/, each
encapsulating its own state and behavior, which keeps the app_* files
thin and lets tools be unit-tested in isolation.
A tool module typically provides:
- A state struct (
new(),reset()). - A tool struct holding that state, with
name(),instructions(),handle_click(...) -> (Option<OperationType>, bool)(the bool = should-exit),render_ui(...), andreset().
To add a new tool:
- Add
pub mod my_tool;insrc/tools/mod.rsand a variant to theToolenum (plus itsname()/instructions()arms). - Add a tool instance field to
NullCadAppand initialize it. - Dispatch clicks and UI rendering from the
app_*files based on the active tool. - Add a toolbar button that sets the active tool and calls
reset().
src/tools/point_tool.rs is the reference implementation. Best practices:
keep all tool logic in the module, route every mutation through
DocumentState::apply_operation(), reset tool state on activation, provide
clear instructions() text, handle edge cases (invalid input, no snap
point), and unit-test the module.
Adding a new geometry type
- Add the type in
src/geometry/using f64 coordinates. - Add a variant to the
Geometryenum ingeometry/mod.rs. - Handle it in the renderer’s vertex generation.
- Handle it everywhere else the
Geometryenum is matched (hit testing, serialization, export paths, MCPtools.rs, etc.) — the compiler will point these out.
Camera controls (renderer/camera.rs)
- Pan: middle mouse drag (
PAN_SENSITIVITY, default 0.005), zoom-scaled. - Zoom: scroll wheel toward cursor; clamp range ~0.001–10000.
- Position lives in f64; the view-projection matrix handles only zoom/aspect, never translation (see Precision Handling).