0-proposal-of-impl.md 26 KB

UI Layout Definition Draw Tool — Implementation Proposal

Version: 0.1.0 Platform: Android (APK), native C++ compiled with Clang in Termux Target Spec: UI Layout Definition Format v1.6


1. Project Overview

A lightweight Android application for visually designing UI layouts conforming to the ui-layout-def XML specification (v1.6). The tool enables selecting a control set, drawing wireframes by placing controls from a toolbox, creating windows with slot overrides, editing control properties, and saving/loading/validating XML files against the XSD schemas.

The app is built entirely in C++ using the Android NDK toolchain available in Termux, with no Java/Kotlin layer — pure NativeActivity + OpenGL ES or Skia for rendering.


2. Architecture

2.1 High-Level Component Diagram

┌─────────────────────────────────────────────────────┐
│                    Android APK                       │
│  ┌───────────────────────────────────────────────┐  │
│  │              NativeActivity (C++)              │  │
│  │  ┌─────────┐ ┌──────────┐ ┌───────────────┐  │  │
│  │  │ UI Core │ │ Renderer │ │ Input Handler │  │  │
│  │  │ (ImGui) │ │(GLES 2.0)│ │ (touch/keys)  │  │  │
│  │  └────┬────┘ └─────┬────┘ └───────┬───────┘  │  │
│  │       │            │              │           │  │
│  │  ┌────▼────────────▼──────────────▼───────┐   │  │
│  │  │           Application Core             │   │  │
│  │  │  ┌────────────┐  ┌──────────────────┐  │   │  │
│  │  │  │  Document   │  │  Control         │  │   │  │
│  │  │  │  Model      │  │  Registry        │  │   │  │
│  │  │  │  (DOM tree) │  │  (parsed XMLs)   │  │   │  │
│  │  │  └──────┬─────┘  └────────┬─────────┘  │   │  │
│  │  │         │                 │             │   │  │
│  │  │  ┌──────▼─────────────────▼──────────┐  │   │  │
│  │  │  │         XML Engine                │  │   │  │
│  │  │  │  ┌──────────┐  ┌──────────────┐   │  │   │  │
│  │  │  │  │ pugixml  │  │ libxml2 XSD  │   │  │   │  │
│  │  │  │  │ (R/W)    │  │ (validation) │   │  │   │  │
│  │  │  │  └──────────┘  └──────────────┘   │  │   │  │
│  │  │  └───────────────────────────────────┘  │   │  │
│  │  └─────────────────────────────────────────┘   │  │
│  └───────────────────────────────────────────────┘  │
│                  ┌───────────────┐                   │
│                  │  File System  │                   │
│                  │  (storage)    │                   │
│                  └───────────────┘                   │
└─────────────────────────────────────────────────────┘

2.2 Key Technology Choices

Component Library Rationale
UI Framework Dear ImGui (docking branch) Immediate-mode GUI, trivial to embed in NativeActivity, excellent for toolbox/property panels, zero Java dependency
Rendering OpenGL ES 2.0 via EGL Universal Android support, ImGui has a backend for it
XML Parsing/Writing pugixml Header-only C++, lightweight, DOM-based — perfect fit for ui-layout-def tree manipulation
XSD Validation libxml2 The only practical C library with XSD schema validation; available in Termux (pkg install libxml2)
Touch/Input android_native_app_glue Standard NDK input handling for NativeActivity
Build System CMake + NDK via Termux pkg install android-ndk cmake in Termux
File Dialogs Custom ImGui panel Browsing /sdcard/ for open/save since there's no native file picker in NativeActivity

2.3 Why Not SDL2 / Other Frameworks?

SDL2 is an option but adds an unnecessary abstraction layer. NativeActivity + android_native_app_glue + ImGui is more direct, smaller APK, and gives full control over the GL context lifecycle. If future versions need audio or gamepad input, SDL2 can be introduced later.


3. Data Model

3.1 Control Registry

On startup, the app parses the control definition XML files (abstract-controls.xml, avalonia-controls.xml, winform-controls.xml, webawesome-controls.xml) using pugixml. Each parsed control becomes an entry in a ControlRegistry:

struct ControlDef {
    std::string name;           // "TextBox", "Panel", "wa-button"
    std::string type;           // "input", "container", "display"
    std::string category;       // "basic", "avalonia-input", etc.
    std::string inherits;       // "CommonControl"
    std::string platform;       // "basic", "avalonia", "web"
    std::string description;
    bool is_container;
    std::vector<std::string> allowed_parents;
    std::vector<std::string> allowed_children;
    std::vector<AttributeDef> attributes;
    std::vector<EventDef> events;
};

struct AttributeDef {
    std::string name;
    std::string type;       // "string", "int", "bool", "enum"
    std::string default_val;
    bool required;
    int min, max;
    std::string values;     // comma-separated enum values
};

class ControlRegistry {
    std::unordered_map<std::string, ControlDef> controls_;
    // Grouped by control set for toolbox display
    std::map<std::string, std::vector<std::string>> by_category_;
public:
    void load_control_set(const std::string& xml_path);
    const ControlDef* find(const std::string& name) const;
    void resolve_inheritance();  // flatten inherited attributes
};

The registry resolves inherits chains so each ControlDef has the full merged attribute list from CommonControl down to the specific control.

3.2 Document Model

The working document is an in-memory tree mirroring the ui-layout-def XML structure:

// Represents a placed control instance on the canvas
struct ControlInstance {
    std::string id;             // unique within document
    std::string control_name;   // reference to ControlDef
    float x, y, w, h;          // canvas position/size
    std::map<std::string, std::string> properties;  // attribute overrides
    std::vector<ControlInstance*> children;
    ControlInstance* parent;
};

// A wireframe definition
struct WireframeDef {
    std::string name;
    std::string type;
    std::vector<SlotDef> slots;    // named regions
    ControlInstance* root_layout;  // the template tree
};

// A window definition
struct WindowDef {
    std::string name;
    std::string title;
    std::string wireframe_ref;     // optional wireframe name
    std::string view_ref;          // optional view name
    std::string target_platform;
    // Either template (free-form) or slot-overrides
    ControlInstance* template_root;
    std::map<std::string, ControlInstance*> slot_overrides;
};

// Root document
struct Document {
    std::string version = "1.6";
    std::string target_platform = "basic";
    std::vector<std::string> pattern_includes;
    std::vector<WireframeDef> wireframes;
    std::vector<WindowDef> windows;
    // views, validation-rules stored as raw pugixml nodes
    // (v0.1 focuses on patterns+windows)
    pugi::xml_document raw_doc;  // for round-tripping unsupported sections
    std::string file_path;
    bool modified = false;
};

3.3 Round-Trip XML Fidelity

Sections the tool doesn't visually edit (views, validation-rules, state-management, etc.) are preserved as raw XML nodes via pugixml's DOM. When saving, the tool:

  1. Serializes patterns (from registry selection)
  2. Serializes wireframes (from canvas)
  3. Serializes windows (from canvas)
  4. Preserves untouched sections verbatim

This guarantees no data loss when editing files created by hand or other tools.


4. Feature Implementation

4.1 Feature 1 — Create New UI Definition (Control Set Selection)

Flow:

  1. User taps "New" → modal dialog presents control set options:
    • Abstract only (basic controls)
    • Abstract + WinForms
    • Abstract + Avalonia
    • Abstract + Web Awesome
    • Custom combination (multi-select)
  2. User selects target platform (basic, winforms, avalonia, web, mixed)
  3. App creates a new Document with appropriate <pattern-include> entries
  4. Control registry loads/filters to the selected sets
  5. Toolbox panel populates with available controls grouped by category

Control set files bundled in APK assets:

File Control Set
abstract-controls.xml Always loaded — base controls
winform-controls.xml WinForms-specific controls
avalonia-controls.xml Avalonia-specific controls
webawesome-controls.xml Web Awesome components

The XSD schemas are also bundled for validation.

4.2 Feature 2 — Wireframe Drawing (Canvas + Toolbox)

Canvas:

  • OpenGL ES 2.0 rendered surface, ImGui draw-list overlay
  • Pan (two-finger drag) and zoom (pinch) with transform matrix
  • Grid snap (configurable: 4px, 8px, 16px, 32px)
  • Each control renders as a labeled rectangle with type icon
  • Container controls show dotted border and accept children via drag-drop
  • Selection: tap to select, long-press for context menu
  • Multi-select via lasso or Shift+tap (with external keyboard)

Toolbox panel (left sidebar, collapsible):

  • Accordion-style categories: Display, Input, Container, List, Navigation, etc.
  • Each entry shows control name + small icon
  • Tap a toolbox item → enters "placement mode" → tap canvas to place
  • Alternative: drag from toolbox to canvas (if touch precision allows)

Wireframe creation:

  • User defines a wireframe via menu: "New Wireframe" → name + type
  • Places container controls (Panel, SplitPanel, TabControl) as layout skeleton
  • Marks named slots within containers (right-click → "Mark as Slot" → enter slot name)
  • Slot regions render with distinct dashed border + slot label

Rendering style for v0.1:

  • Simple rectangles with rounded corners
  • Control type name rendered inside
  • Container nesting shown by indentation/border hierarchy
  • Color-coding by control type (blue=input, green=display, gray=container, orange=list)

4.3 Feature 3 — Window Creation (Wireframe Overrides + Standalone)

Two modes:

A) Window with wireframe reference:

  1. User creates window → selects an existing wireframe
  2. Canvas shows the wireframe layout with slot regions highlighted
  3. User drags controls into slot regions → creates <slot-overrides>
  4. Non-slot areas are read-only (inherited from wireframe)
  5. Slot content is freely editable

B) Standalone window (no wireframe):

  1. User creates window → skips wireframe selection
  2. Blank canvas → builds layout from scratch using <template> mode
  3. Can reference a <structure> pattern or build free-form

Window list panel (right sidebar):

  • Tree view: Document → Wireframes → Windows
  • Shows wireframe→window relationships
  • Double-click to open a window on the canvas
  • Multiple windows can be open as tabs

4.4 Feature 4 — Property Editor

When a control is selected on the canvas, the Properties panel shows:

  1. Identity section: name (editable), control type (read-only), category
  2. Layout section: x, y, width, height, dock, anchor, margin, padding
  3. Appearance section: background-color, foreground-color, font-*, visible, enabled
  4. Type-specific section: attributes from the ControlDef (e.g., max-length for TextBox, paging-enabled for Gallery)
  5. Data binding section: data-source, binding properties
  6. Raw XML: advanced toggle to see/edit raw XML attributes

Property editors by attribute type:

  • string → text input
  • int → numeric input with min/max clamp and slider
  • bool → checkbox
  • enum → dropdown (populated from values attribute)
  • color → color picker widget (ImGui has one built-in)

Validation feedback: red highlight on properties that fail constraints (min/max, required).

4.5 Feature 5 — Save to XML File

Serialization pipeline:

Document model → pugixml DOM tree → formatted XML string → file
  1. Build <ui-layout-def> root with version, schema-version, target-platform attributes
  2. Build <patterns> with <pattern-include> elements for selected control sets
  3. For each wireframe → build <wireframe> with <template> containing the layout tree
  4. For each window:
    • If wireframe-based → <window wireframe="..."> with <slot-overrides>
    • If standalone → <window> with <template> content
  5. Preserve raw sections (views, validation-rules) from original load
  6. Save to user-specified path (default: /sdcard/Documents/ui-layout/)

File naming: {document-name}.xml with .xml extension enforced.

Auto-save: optional, every 60 seconds to ~/.uidef-autosave/.

4.6 Feature 6 — Open Existing XML File

Loading pipeline:

File → pugixml parse → Document model population → Canvas render
  1. Parse XML with pugixml
  2. Read root attributes (version, platform, schema-version)
  3. Load <pattern-include> entries → resolve control registry
  4. Parse <wireframe> elements → build wireframe canvas objects
  5. Parse <window> elements → build window canvas objects with control instances
  6. Sections not visually editable → store as raw DOM nodes
  7. Handle parse errors gracefully with error dialog listing issues

Version compatibility: warn if schema-version != "1.6" but attempt to load anyway.

4.7 Feature 7 — XSD Validation

Using libxml2 for schema validation:

#include <libxml/xmlschemastypes.h>

bool validate_against_schema(const std::string& xml_path,
                             const std::string& xsd_path) {
    xmlSchemaParserCtxtPtr parser_ctx =
        xmlSchemaNewParserCtxt(xsd_path.c_str());
    xmlSchemaPtr schema = xmlSchemaParse(parser_ctx);
    xmlSchemaValidCtxtPtr valid_ctx =
        xmlSchemaNewValidCtxt(schema);

    // Collect errors via callback
    xmlSchemaSetValidErrors(valid_ctx, error_cb, warning_cb, &errors);

    int ret = xmlSchemaValidateFile(valid_ctx, xml_path.c_str(), 0);

    // cleanup...
    return ret == 0;
}

Validation workflow:

  1. User taps "Validate" toolbar button
  2. App serializes current document to temp file
  3. Runs libxml2 validation against ui-layout-def.xsd (which imports all sub-schemas)
  4. Results displayed in a scrollable error/warning panel at bottom
  5. Tapping an error highlights the relevant control on canvas
  6. Errors categorized: Schema errors, Constraint violations, Warnings

Bundled XSD files:

Schema Purpose
ui-layout-def.xsd Root document structure
ui-layout-patterns.xsd Controls, structures, wireframes
ui-layout-views.xsd View definitions
ui-layout-validation.xsd Validation rules, profiles
ui-layout-basic-controls.xsd Basic control types
ui-layout-winforms-controls.xsd WinForms controls
ui-layout-avalonia-controls.xsd Avalonia controls
ui-layout-webawesome-controls.xsd Web Awesome controls

5. UI Layout of the App Itself

┌──────────────────────────────────────┐
│ Toolbar: [☰] [New][Open][Save][✓Val] │
├──────────────────────────────────────┤
│                                      │
│         Canvas                       │
│         (wireframe/window            │
│          drawing area)               │
│                                      │
│    ┌──────────────────┐              │
│    │  Panel            │             │
│    │  ┌──────────────┐ │             │
│    │  │  TextBox      │ │             │
│    │  └──────────────┘ │             │
│    │  ┌──────────────┐ │             │
│    │  │  Button       │ │             │
│    │  └──────────────┘ │             │
│    └──────────────────┘              │
│                                      │
├──────────────────────────────────────┤
│  Doc Tree / Validation (collapsible) │
│  ▸ Wireframes                        │
│    ▸ MainLayout (3 slots)            │
│  ▸ Windows                           │
│    ▸ ProductListWindow               │
└──────────────────────────────────────┘

 ◄ Swipe from left        Swipe from right ►
┌────────────┐            ┌────────────────┐
│  Toolbox   │            │  Properties    │
│            │            │                │
│ [Label]    │            │ Name: ________ │
│ [TextBox]  │            │ X: ___  Y: ___ │
│ [Button]   │            │ W: ___  H: ___ │
│ [Panel]    │            │ dock: [none ▾] │
│ [SplitPnl] │            │ enabled: [☑]   │
│ [TabCtrl]  │            │ visible: [☑]   │
│ [ListBox]  │            │                │
│ [DataGrid] │            │ --- Type ---   │
│ [Tree]     │            │ maxLen: [255]  │
│  ...       │            │ placeholder: _ │
└────────────┘            └────────────────┘

Portrait layout behavior:

  • Canvas occupies the full width, maximizing vertical drawing space
  • Toolbox slides in from the left edge (swipe or hamburger menu)
  • Properties panel slides in from the right edge (swipe or tap selected control)
  • Bottom panel (document tree / validation output) is collapsible with a drag handle
  • Toolbar stays fixed at the top

6. Build System & Toolchain

6.1 Termux Setup

# Install required packages
pkg install clang cmake make ndk-sysroot android-ndk
pkg install libxml2 git

# Clone project
mkdir -p ~/uidef-tool && cd ~/uidef-tool

# External dependencies (header-only or source-included)
# pugixml: single header+source, copy into project
# imgui: clone docking branch
# imgui backends: imgui_impl_opengl3 + imgui_impl_android

6.2 CMake Structure

uidef-tool/
├── CMakeLists.txt
├── src/
│   ├── main.cpp                  # NativeActivity entry point
│   ├── app.h / app.cpp           # Application lifecycle
│   ├── canvas/
│   │   ├── canvas.h / .cpp       # Drawing surface + transform
│   │   ├── grid.h / .cpp         # Snap grid rendering
│   │   └── selection.h / .cpp    # Selection + multi-select
│   ├── model/
│   │   ├── document.h / .cpp     # Document root
│   │   ├── control_instance.h    # Placed control
│   │   ├── wireframe_def.h       # Wireframe
│   │   ├── window_def.h          # Window
│   │   └── control_registry.h    # Registry
│   ├── xml/
│   │   ├── xml_reader.h / .cpp   # Load from XML (pugixml)
│   │   ├── xml_writer.h / .cpp   # Save to XML (pugixml)
│   │   └── xsd_validator.h / .cpp# Validate (libxml2)
│   ├── ui/
│   │   ├── toolbox.h / .cpp      # Toolbox panel
│   │   ├── properties.h / .cpp   # Property editor
│   │   ├── doc_tree.h / .cpp     # Document tree panel
│   │   ├── toolbar.h / .cpp      # Top toolbar
│   │   ├── file_dialog.h / .cpp  # Open/save file browser
│   │   └── validation_panel.h    # Validation results
│   └── util/
│       ├── undo_redo.h / .cpp    # Undo/redo stack
│       └── platform.h / .cpp     # Android-specific helpers
├── assets/                        # Bundled into APK
│   ├── schemas/                   # All .xsd files
│   ├── controls/                  # Control definition .xml files
│   └── fonts/                     # ImGui font (e.g. Roboto)
├── third_party/
│   ├── pugixml/
│   ├── imgui/                     # docking branch
│   └── imgui_backends/
└── android/
    └── AndroidManifest.xml

6.3 Build & Package

# Configure
cmake -B build \
  -DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake \
  -DANDROID_ABI=arm64-v8a \
  -DANDROID_PLATFORM=android-26 \
  -DCMAKE_BUILD_TYPE=Release

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

# Package APK (using aapt2 + apksigner from build-tools)
# Script provided in android/build-apk.sh

7. Milestone Plan

Milestone 1 — Skeleton (weeks 1–2)

  • NativeActivity + OpenGL ES + ImGui rendering loop
  • Basic toolbar, empty canvas with pan/zoom
  • ImGui docking layout (toolbox, canvas, properties, bottom panel)

Milestone 2 — Control Registry + Toolbox (weeks 3–4)

  • Parse abstract-controls.xml with pugixml
  • Populate toolbox from registry
  • Control set selection dialog (new document flow)

Milestone 3 — Canvas Drawing (weeks 5–7)

  • Place controls on canvas from toolbox
  • Drag to move, resize handles
  • Container nesting (parent-child relationships)
  • Grid snap
  • Selection + multi-select
  • Undo/redo

Milestone 4 — Property Editor (week 8)

  • Display selected control's attributes
  • Editable fields by type (text, int, bool, enum, color)
  • Constraint validation (min/max, required)
  • Layout properties (x, y, w, h, dock, anchor)

Milestone 5 — Wireframes & Windows (weeks 9–11)

  • Wireframe definition: create, name, template editing
  • Slot marking within wireframes
  • Window creation: wireframe-based with slot overrides
  • Window creation: standalone with template
  • Document tree panel with window/wireframe hierarchy

Milestone 6 — XML I/O (weeks 12–13)

  • Save document to .xml (serialization with pugixml)
  • Open existing .xml files (deserialization)
  • File browser dialog
  • Round-trip preservation of non-visual sections
  • Auto-save

Milestone 7 — XSD Validation (week 14)

  • Integrate libxml2 schema validation
  • Validation results panel with error navigation
  • Error-to-canvas-element mapping

Milestone 8 — Polish & Package (weeks 15–16)

  • APK packaging script
  • Touch input refinement (long-press, gestures)
  • Performance optimization (large documents)
  • Responsive layout for phones vs tablets
  • Testing with sample documents

8. Risks & Mitigations

Risk Impact Mitigation
libxml2 XSD validation may not handle all schema features (imports, complex types) Validation incomplete Test early with all bundled XSDs; fallback to partial validation reporting
Touch precision for small controls Poor UX on phones Configurable zoom + snap grid; "precision mode" toggle; portrait orientation maximizes canvas width
ImGui text input on Android soft keyboard Keyboard may not work well Use ImGui's Android backend which handles IME; test early
Large documents (100+ controls) Performance Use ImGui viewport culling; lazy render off-screen controls
APK signing in Termux Can't install Use apksigner from Android SDK build-tools; document setup
NDK version compatibility Build failures Pin NDK version in CMakeLists.txt; document tested versions

9. Future Versions (Post 0.1)

  • v0.2: View definitions editor (state management, accessibility, performance sections); Gallery box-template visual editor
  • v0.3: Live preview — render actual platform-like controls instead of rectangles
  • v0.4: External includes resolution — load <pattern-include src="..."> from external files
  • v0.5: Multi-file project support — manage a collection of includes + main file
  • v0.6: Code generation — emit platform-specific code (XAML, HTML, WinForms designer)
  • v1.0: Collaboration — share/import control libraries; theming preview

10. Dependencies Summary

Dependency Version License Size Purpose
Dear ImGui 1.91+ (docking) MIT ~400KB src UI framework
pugixml 1.14+ MIT ~300KB src XML DOM read/write
libxml2 2.12+ MIT ~5MB .so XSD validation
Android NDK r26+ Apache 2.0 (system) Toolchain
Roboto Font Apache 2.0 ~150KB UI font

Total estimated APK size: ~8–12 MB (Release, arm64-v8a only).


11. Open Questions

  1. Gallery control editor — The Gallery box-template with visual element placement is complex. Should v0.1 support visual editing of <box-template> or defer to raw XML editing? Decision: Deferred to v0.2.0. In v0.1.0 the Gallery renders as a compact block on canvas; box-template content is not visually editable.

  2. Web Awesome controls — These have HTML-specific semantics (slots via <div slot="..."> pattern). How should the canvas represent HTML slot semantics? Decision: Show as named regions similar to wireframe slots; HTML-specific attributes editable in property editor.

  3. Undo granularity — Should undo be per-action (move, resize, property change) or group related actions? Decision: Per-action with optional grouping for drag sequences.

  4. Portrait orientation Decision: Portrait orientation. Toolbox and properties become slide-in drawers from left/right edges; canvas gets maximum vertical space. Bottom panel remains collapsible.