# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Build Commands ```bash # Activate the conda environment (required before any build/run) export MAMBA_EXE="/home/share/micromamba/bin/micromamba" export MAMBA_ROOT_PREFIX="/home/share/micromamba" eval "$(/home/share/micromamba/bin/micromamba shell hook --shell bash)" micromamba activate uLib # Configure (from repo root, using Conan preset — uses Ninja + ccache) cmake --preset conan-release # Build everything cmake --build build -j$(nproc) # Build a specific target cmake --build build --target gcompose -j$(nproc) # Run tests cmake --build build --target test # or ctest --test-dir build # Run a single test binary (example) ./build/src/Core/testing/CoreTest # Run the gcompose GUI app ./build/app/gcompose/gcompose ``` First-time setup (if `build/` does not exist): ```bash conan profile detect conan install . --output-folder=build --build=missing cmake --preset conan-release ``` ### Build acceleration (already configured) - **Ninja** generator — used automatically via the conan default profile (`~/.conan2/profiles/default`) - **ccache** — enabled via `CMAKE_CXX_COMPILER_LAUNCHER=ccache`; cached rebuilds are nearly instant (~0.3s vs ~25s cold) - **Clang 22 + lld** profile available (`~/.conan2/profiles/fast`) but blocked by template overload ambiguities in `src/Core/Archives.h` that need fixing for full compatibility To reconfigure with the fast profile once Archives.h is fixed: ```bash conan install . --output-folder=build --build=missing --profile=fast cmake -B build -G Ninja -DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release cmake --build build -j$(nproc) ``` ## Architecture **uLib** is a C++ framework for Cosmic Muon Tomography (CMT), structured as layered shared libraries: ``` mutomCore → mutomMath → mutomDetectors → mutomGeant ↘ mutomVtk → gcompose (Qt6 GUI app) mutomRoot ``` ### Core Object Model (`src/Core/`) - All framework objects inherit from `uLib::Object` - **Property system**: `Property` wraps member pointers with change notification via `PropertyChanged` signal - **Signal/slot**: `uLib::Object::connect(sender, &Sender::Signal, callback)` — resembles Qt but works for non-QObject classes - **Serialization**: Boost archives (`xml_oarchive`, `text_oarchive`, `hrt_oarchive`); `hrp` marks fields as "human-readable properties" - `ObjectsContext` is a container owning a list of `Object*` pointers; signals `ObjectAdded`/`ObjectRemoved` ### VTK Layer (`src/Vtk/`) - `Puppet` (inherits `uLib::Object`): wraps a VTK `vtkProp` for rendering. Has `GetContent()` returning the underlying domain object. Display-only properties are registered via `ULIB_ACTIVATE_DISPLAY_PROPERTIES` macro. - `Viewport`: base class managing the VTK renderer, picking, selection logic. Maintains `m_Puppets` vector and `m_ObjectToPuppet` map. - `QViewport` (inherits `QWidget` + `Viewport`): Qt-embedded VTK widget. Emits Qt signal `puppetSelected(Puppet*)` on click-selection via `OnSelectionChanged`. - `vtkObjectsContext`: wraps `ObjectsContext`, creating/destroying `Puppet`s as objects come/go. Emits `PuppetAdded`/`PuppetRemoved`. - Display properties: `serialize_display()` + `display_properties_archive` registers selected `hrp` fields as `PropertyBase*` in the puppet's `m_DisplayProperties`. `PropertyEditor::setObject(obj, displayOnly=true)` shows only those. ### gcompose GUI App (`app/gcompose/src/`) - `MainPanel`: top-level widget. Owns `ContextPanel` (left) and `ViewportPane` (right). Wires together viewport↔context selection via signals. - `ContextPanel`: tree view of `ObjectsContext`. Emits `objectSelected(Object*)`. Contains an embedded `PropertiesPanel`. - `PropertiesPanel`: shows `uLib::Object` properties via `PropertyEditor`. - `ViewportPane`: embeds `QViewport` + a slide-out "Display Properties" panel (`PropertyEditor` in display-only mode). - `PropertyEditor`: populates widgets from `Object::GetProperties()` (all) or `Puppet::GetDisplayProperties()` (display-only mode). ### Selection Sync Flow ``` Viewport click → Viewport::SelectPuppet() → QViewport::OnSelectionChanged() → emit puppetSelected(p) → MainPanel: contextPanel->selectObject(p->GetContent()) [updates tree + PropertiesPanel] → MainPanel: firstPane->setObject(p) [updates Display Properties panel] ContextPanel tree click → emit objectSelected(obj) → MainPanel: viewport->SelectPuppet(puppet) [visual selection in VTK] → MainPanel: firstPane->setObject(puppet) [updates Display Properties panel] ``` ### Key Patterns - **Two signal systems coexist**: Qt signals (`Q_OBJECT`, `connect(...)`) for GUI; `uLib::Object::connect(...)` for domain signals. - **Display properties** flow: `Puppet::serialize_display()` → `display_properties_archive` → `RegisterDisplayProperty()` → `PropertyEditor(displayOnly=true)`. Must call `ULIB_ACTIVATE_DISPLAY_PROPERTIES` in the puppet constructor. - **Puppet ↔ Object map**: `Viewport::m_ObjectToPuppet` allows lookup by domain object; `vtkObjectsContext::GetPuppet(obj)` does the same.