# UI Layout Definition Draw Tool — Implementation TODO **Version:** 0.1.0 **Derived from:** `0-proposal-of-impl.md` **Platform:** Android APK — native C++ / Clang in Termux **Schema Target:** ui-layout-def v1.6 --- ## How to Use This Document Each section corresponds to a milestone from the proposal. Tasks are ordered by dependency — complete them top-to-bottom within each milestone. Tasks marked `[CRITICAL]` are blockers for downstream work. Tasks marked `[RISK]` have an identified risk from the proposal and should be validated early. --- ## Milestone 1 — Project Skeleton (Weeks 1–2) ### 1.1 Termux Environment - [x] Install base packages: ```bash pkg install clang cmake make git patchelf pkg install aapt2 apksigner zipalign d8 javac ``` Note: libxml2 is built from source (in `third_party/libxml2/`), no system package needed. - [ ] Verify Clang targets arm64: `clang++ --print-target-triple` → expect `aarch64-linux-android*` - [ ] Locate NDK path: `echo $NDK` or find under `$PREFIX/lib/android-ndk/` - [ ] Create project root: `mkdir -p ~/uidef-tool && cd ~/uidef-tool` ### 1.2 Fetch Third-Party Sources - [ ] Download **pugixml** 1.14+ — copy `pugixml.hpp` + `pugixml.cpp` into `third_party/pugixml/` - [ ] Clone **Dear ImGui** docking branch: ```bash git clone --branch docking https://github.com/ocornut/imgui.git third_party/imgui ``` - [ ] Copy ImGui Android+OpenGL3 backends from `third_party/imgui/backends/`: - `imgui_impl_opengl3.h / .cpp` - `imgui_impl_android.h / .cpp` - [ ] Download **Roboto-Regular.ttf** into `assets/fonts/` ### 1.3 Create Directory Layout ``` uidef-tool/ ├── CMakeLists.txt ├── src/ │ ├── main.cpp # NativeActivity entry, EGL init, main loop │ ├── app.h / app.cpp # Application lifecycle + state machine │ ├── canvas/ │ │ ├── canvas.h / .cpp # Drawing surface + view transform │ │ ├── grid.h / .cpp # Snap grid rendering │ │ └── selection.h / .cpp # Click-select, multi-select, resize handles │ ├── model/ │ │ ├── document.h / .cpp # Document root (version, platform, includes) │ │ ├── control_instance.h/.cpp # Placed control with position + props │ │ ├── wireframe_def.h / .cpp # Wireframe with slots │ │ ├── window_def.h / .cpp # Window (template or slot-overrides) │ │ └── control_registry.h/.cpp # Parsed control definitions │ ├── xml/ │ │ ├── xml_reader.h / .cpp # Load XML → Document model (pugixml) │ │ ├── xml_writer.h / .cpp # Document model → XML file (pugixml) │ │ └── xsd_validator.h / .cpp # XSD validation wrapper (libxml2) │ ├── ui/ │ │ ├── toolbox.h / .cpp # Left slide-in: control palette │ │ ├── properties.h / .cpp # Right slide-in: property editor │ │ ├── doc_tree.h / .cpp # Bottom panel: document tree │ │ ├── toolbar.h / .cpp # Top bar: New/Open/Save/Validate │ │ ├── file_dialog.h / .cpp # ImGui file browser (/sdcard/) │ │ └── validation_panel.h/.cpp # Validation results list │ └── util/ │ ├── undo_redo.h / .cpp # Undo/redo command stack │ └── platform.h / .cpp # Android helpers (asset loading, paths) ├── assets/ │ ├── schemas/ # All 8 .xsd files │ ├── controls/ # abstract/avalonia/winform/web/webawesome .xml │ └── fonts/ # Roboto-Regular.ttf ├── third_party/ │ ├── pugixml/ │ └── imgui/ # docking branch + backends └── android/ └── AndroidManifest.xml ``` - [ ] Create all directories and placeholder `.h/.cpp` files with header guards - [ ] Copy all 8 XSD schema files from project into `assets/schemas/` - [ ] Copy all 5 control definition XMLs into `assets/controls/` ### 1.4 CMakeLists.txt `[CRITICAL]` - [ ] Write root `CMakeLists.txt`: - `cmake_minimum_required(VERSION 3.18)` - `set(CMAKE_CXX_STANDARD 17)` / `set(CMAKE_CXX_STANDARD_REQUIRED ON)` - Toolchain: `-DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake` - ABI: `set(ANDROID_ABI arm64-v8a)` - Platform: `set(ANDROID_PLATFORM android-26)` - Target: `add_library(uidef-tool SHARED ...)` (NativeActivity requires shared lib) - Sources: all `src/**/*.cpp` + pugixml + ImGui + backends - Include: `third_party/pugixml/`, `third_party/imgui/`, `third_party/imgui/backends/` - Link libraries: `android`, `log`, `EGL`, `GLESv2`, `xml2`, `z` - Find libxml2: `find_package(LibXml2 REQUIRED)` or manual `-lxml2` + include path - [ ] Write `android/AndroidManifest.xml`: - `android:hasCode="false"` (pure NativeActivity) - `` - Permissions: `WRITE_EXTERNAL_STORAGE`, `READ_EXTERNAL_STORAGE` (for `/sdcard/` access) - `android:screenOrientation="portrait"` ### 1.5 NativeActivity Entry Point `[CRITICAL]` Implement `src/main.cpp`: - [ ] `#include ` — use NDK glue - [ ] `android_main(struct android_app* app)` entry function - [ ] EGL initialization: create display → choose config (GLES2, RGBA8) → create surface → create context - [ ] Initialize ImGui: `ImGui::CreateContext()`, load Roboto font from APK assets via `AAssetManager` - [ ] Initialize ImGui backends: `ImGui_ImplAndroid_Init(app->window)`, `ImGui_ImplOpenGL3_Init("#version 100")` - [ ] Main loop: poll events → `ImGui_ImplAndroid_NewFrame()` → `ImGui_ImplOpenGL3_NewFrame()` → `ImGui::NewFrame()` → draw UI → `ImGui::Render()` → `ImGui_ImplOpenGL3_RenderDrawData()` → `eglSwapBuffers()` - [ ] Handle `APP_CMD_INIT_WINDOW` / `APP_CMD_TERM_WINDOW` for EGL surface lifecycle - [ ] Handle `APP_CMD_GAINED_FOCUS` / `APP_CMD_LOST_FOCUS` for render pause ### 1.6 Basic ImGui Docking Layout - [ ] Enable docking: `ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_DockingEnable` - [ ] Create fullscreen dockspace in main loop: `ImGui::DockSpaceOverViewport()` - [ ] Stub windows (empty, will be filled in later milestones): - `ImGui::Begin("Toolbar")` — top bar placeholder - `ImGui::Begin("Canvas")` — central area - `ImGui::Begin("Document Tree")` — bottom panel - [ ] **Do not** create persistent side panels yet — toolbox and properties are slide-in drawers (portrait layout per proposal §5) ### 1.7 Canvas: Pan & Zoom - [ ] In `canvas.h/cpp`: - `struct ViewTransform { float offset_x, offset_y, zoom; }` — default: offset(0,0), zoom(1.0) - Two-finger drag → update offset (pan) - Pinch gesture → update zoom (clamp to 0.25 – 4.0) - [ ] Apply transform to ImGui draw list via `ImDrawList::PushClipRect()` + coordinate mapping - [ ] Draw a faint grid background (respecting current snap size) - [ ] `[RISK]` Test touch input early — ImGui Android backend must correctly translate `AInputEvent` to ImGui IO. If not, implement manual `AMotionEvent` → ImGui mapping in `main.cpp` event handler. ### 1.8 Build & Smoke Test - [ ] Configure and build: ```bash cmake -B build \ -DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake \ -DANDROID_ABI=arm64-v8a \ -DANDROID_PLATFORM=android-26 \ -DCMAKE_BUILD_TYPE=Debug cmake --build build -j$(nproc) ``` - [ ] Package APK manually or via `android/build-apk.sh` (using `aapt2` + `apksigner`) - [ ] `[RISK]` Install and verify: ImGui renders, canvas pans/zooms, toolbar shows - [ ] If APK signing fails in Termux: install `apksigner` from Android SDK build-tools, document the path ### Milestone 1 — Done Criteria > App launches, shows ImGui docked layout with toolbar, empty canvas with grid, and bottom panel. Canvas supports touch pan and pinch zoom. No functionality yet. --- ## Milestone 2 — Control Registry + Toolbox (Weeks 3–4) ### 2.1 Control Definition Parser `[CRITICAL]` Implement `model/control_registry.h/.cpp`: - [ ] Define core data structures (per proposal §3.1): ```cpp struct AttributeDef { std::string name, type, default_val, values; // values = comma-separated for enum bool required = false; int min = 0, max = 0; }; struct EventDef { std::string name; bool required = false; }; struct ControlDef { std::string name, type, category, inherits, platform, description; bool is_container = false; std::vector allowed_parents, allowed_children; std::vector attributes; std::vector events; }; ``` - [ ] `ControlRegistry::load_control_set(const std::string& xml_path)`: - Open XML with pugixml: `pugi::xml_document doc; doc.load_buffer(data, size)` - Iterate `` elements under `` root - Parse `name`, `type`, `category`, `inherits`, `platform` attributes - Parse `` text - Parse ``: extract ``, ``, `` → split comma-separated values - Parse `` → vector of `AttributeDef` (name, type, default, required, min, max, values) - Parse `` → vector of `EventDef` - Also parse `` elements (same shape but include `