CLAUDE.md 9.0 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

UIDefEdit is a native Android C++ application for visually designing UI layouts conforming to the ui-layout-def XML specification (v1.6). It runs as a NativeActivity built with Clang in Termux. A minimal Java wrapper (DebugActivity extends NativeActivity) provides the entry point and soft keyboard support.

Status: All 8 milestones complete. The app is fully functional: create documents, place controls, edit properties, save/load XML, validate against XSD schemas, and package as APK.

Sync

# Push changes to remote (from home directory)
bash ~/uidefedit-sync.sh push

# Pull changes from remote
bash ~/uidefedit-sync.sh pull

Build Commands

# Termux prerequisites (libxml2 is built from source, not needed as system pkg)
pkg install clang cmake make git patchelf
pkg install aapt2 apksigner zipalign d8 javac

# Configure (only needed once)
cmake -B build -DCMAKE_BUILD_TYPE=Debug

# Build
cmake --build build -j$(nproc)

# Package APK
bash android/build-apk.sh

# Install (use termux-open, not pm install — SELinux blocks pm)
termux-open build/uidef-edit.apk

The CMake build uses Termux's native Clang targeting aarch64-unknown-linux-android24. No NDK toolchain file needed. The target is a shared library (add_library(uidef-tool SHARED ...)). C++17 standard. AndroidManifest uses targetSdkVersion=34 (required for modern Android installs).

An android.jar (API 28+) is required at $HOME/android.jar for APK resource linking.

Architecture

ANativeActivity_onCreate (main.cpp)
  │  Direct callbacks on main UI thread (no android_native_app_glue)
  │  timerfd + ALooper for ~60fps rendering
  │  EGL/GLES3 context
  │  Multi-touch: pinch zoom, double-tap zoom, three-finger undo
  │
  ├── App (app.cpp — lifecycle, docking layout, frame orchestration)
  │
  ├── UI layer (Dear ImGui, docking branch)
  │   ├── toolbar          — top bar: New/Open/Save/Validate + undo/redo + marquee select toggle
  │   ├── toolbox          — left slide-in: control palette by category
  │   ├── canvas           — central: pan/zoom surface with viewport culling
  │   ├── Bottom tab area (docked together):
  │   │   ├── doc_tree         — wireframe/window hierarchy with inline action buttons
  │   │   ├── properties       — attribute editor + slot properties (labels above fields)
  │   │   └── validation_panel — XSD error/warning list
  │   └── file_dialog      — custom /sdcard/ browser (single-tap select + Open button)
  │
  ├── Model layer
  │   ├── Document       — root: version, platform, pattern_includes, wireframes, windows
  │   ├── ControlRegistry — parsed control definitions with resolved inheritance
  │   ├── ControlInstance — placed control: id, position, properties, parent/children tree
  │   ├── WireframeDef   — template layout with named SlotDefs
  │   └── WindowDef      — wireframe-based (slot overrides) or standalone (template)
  │
  ├── XML engine
  │   ├── xml_reader/writer — pugixml DOM (round-trips non-visual sections verbatim)
  │   └── xsd_validator    — libxml2 (statically linked, built from source)
  │
  └── Utilities
      ├── undo_redo      — command pattern stack (100 action cap, drag grouping)
      └── platform       — AAssetManager helpers, path resolution

Rendering: OpenGL ES 3.0 via EGL. ImGui draws all UI. Controls render as color-coded rounded rectangles (blue=input, green=display, gray=container, orange=list). Viewport culling skips off-screen controls.

Portrait orientation is locked. Toolbox is a left slide-in drawer; Properties, Document Tree, and Validation are docked as tabs in a bottom panel area. Canvas gets maximum vertical space. UI scale derived from screen width (width / 540dp).

Dual font system: Main font (21sp scaled) for toolbar/buttons/headers. Smaller content font (15sp scaled, Fonts[1]) for bottom panel content text. Access via io.Fonts->Fonts[1] and ImGui::PushFont()/PopFont().

Key Libraries

Library Purpose Integration
Dear ImGui (docking branch) All UI rendering Source in third_party/imgui/, backends: imgui_impl_android + imgui_impl_opengl3
pugixml 1.14+ XML read/write, DOM manipulation Source in third_party/pugixml/ (2 files)
libxml2 2.12.9 XSD schema validation only Built from source in third_party/libxml2/, statically linked (no ICU/iconv)

Critical Patterns

  • Static libxml2 without ICU/iconv. libxml2 2.12.9 is built from source in third_party/libxml2/ as a static library with heavy dependencies disabled (LIBXML2_WITH_ICONV=OFF, LIBXML2_WITH_ICU=OFF, LIBXML2_WITH_LZMA=OFF, LIBXML2_WITH_ZLIB=OFF). This avoids the 32MB+ ICU dependency that Termux's system libxml2 requires. Schema validation (LIBXML2_WITH_SCHEMAS=ON) works fully. Added ~1.4MB to APK size.
  • No android_native_app_glue. The NDK's app_glue creates a background pthread that causes ANR with Termux's Clang. Use direct ANativeActivity callbacks + timerfd on the main ALooper.
  • RPATH stripping. Termux's Clang embeds RPATH to its lib dir. The APK build script must strip it with patchelf --remove-rpath or the .so won't load in the installed app.
  • Ownership: std::unique_ptr for parent→child control trees; raw pointers for child→parent back-references. Document owns all wireframes/windows.
  • Round-trip fidelity: Sections the tool doesn't edit (views, validation-rules, state-management) are preserved as raw pugixml DOM nodes and merged back on save in XSD document order.
  • v1.6 XML structure: Wireframes belong inside <patterns>, not at root. Root element has xmlns="http://quadarax.com/ui-layout-definition". Pattern-includes have src and platform attributes (PatternInclude struct in document.h).
  • Control inheritance: ControlRegistry::resolve_inheritance() flattens inherits chains (topological sort) so each ControlDef has a complete standalone attribute list.
  • Asset loading: APK assets aren't filesystem paths — use AAssetManager + load_buffer() for pugixml. For libxml2 XSD validation, extract schemas to cache directory first (libxml2 needs filesystem paths for <xs:import schemaLocation>).
  • Undo/redo: Per-action with begin_group()/end_group() for drag sequences. Actions: Place, Move, Resize, Delete, PropertyChange.
  • Marquee multi-selection: Toggle via View > Marquee Select. In select mode, drag on empty canvas draws rectangle to select multiple controls. Group move and group delete supported. Group move uses begin_group()/end_group() for single undo step.
  • Touch-friendly UI: Resize handles are 12px visual / 28px hit area (kHandleSize/kHandleHitSize in selection.h). Scrollbars are 24dp wide. Doc tree uses inline [Edit] [Props] [Rename] [Del] buttons instead of hidden popup menus. Bottom panels have 80px padding to clear Android nav bar.
  • Properties labels above fields. In the narrow bottom tab layout, ImGui widget labels (normally to the right) go off-screen. All property labels use ImGui::TextDisabled("Label:") on a separate line above the widget, with ##hidden_id for the widget label.
  • Slot property editing. When a control marked as a slot is selected in wireframe editing mode, the Properties panel shows a "Slot" section with editable name, allowed controls, required checkbox, and read-only region ID. The active wireframe is passed to Properties::render() to look up slot data.
  • File dialog single-tap selection. The file dialog tracks a selected_index_ for highlighted files. Single-tap highlights a file, enabling the Open button. Double-tap still works as a shortcut to open immediately. Previous behavior (Open button always disabled, double-tap only) was unreliable on touch screens.
  • Custom app icon. Generated by android/gen_icon.py (pure Python PNG, no Pillow). Teal rounded square with UI wireframe layout design. 5 density variants (mdpi through xxxhdpi) in android/res/mipmap-*/ic_launcher.png.
  • Install via termux-open. Direct pm install is blocked by SELinux. Always copy to /sdcard/Download/ then termux-open to trigger the system package installer.

Control Set Files

Bundled in assets/controls/: abstract-controls.xml (always loaded), winform-controls.xml, avalonia-controls.xml, webawesome-controls.xml. XSD schemas in assets/schemas/ (8 files).

Test Documents

Sample XML files in test/ for verifying open/save/validate:

  • test-basic.xml — Abstract controls, 1 wireframe, 1 window
  • test-avalonia.xml — Avalonia controls, 2 wireframes, 2 windows
  • test-webawesome.xml — Web Awesome controls, form layout
  • test-complex.xml — WinForms, 3 wireframes, 3 windows, 50+ controls
  • test-invalid.xml — Intentionally invalid for validation error testing