Skip to content

Latest commit

 

History

History
1413 lines (1106 loc) · 39.2 KB

File metadata and controls

1413 lines (1106 loc) · 39.2 KB

Luma Native GUI Framework - Implementation Plan

Version: 0.0.1 (very early stage)
License: MIT OR Apache-2.0 (dual)
Target Platform: Windows-first, architecture supports future Linux/macOS
Last Updated: January 8, 2026


Executive Decision: Win32 Backend (Not WinUI 3)

After thorough research (see Appendix A: WinUI 3 Research), Luma will use Win32 (user32 + GDI) as the Windows backend, not WinUI 3 or Windows App SDK.

Rationale:

  • ✅ Win32 fully supported in windows crate with complete Rust bindings
  • ✅ In-box on every Windows version (minimal memory footprint)
  • ✅ Battle-tested, stable, well-documented API
  • ❌ WinUI 3/XAML explicitly removed from windows crate (June 2022)
  • ❌ Microsoft states: "XAML only truly supports MSBuild+C#"
  • windows-app crate experimental, undocumented behavior, unsustainable

Dark Mode Strategy:

  • Phase 1-3: Dark title bars via DwmSetWindowAttribute (optional), light window contents (acceptable limitation)
  • Phase 4+: Custom control rendering for full dark mode support
  • Future: DirectComposition-based rendering layer (as suggested by Microsoft)

See full research findings in Appendix A.


Table of Contents

  1. Project Overview
  2. Architecture
  3. Dependencies
  4. Project Structure
  5. Core Design Principles
  6. Layout System
  7. Widget System
  8. Serialization Format
  9. Implementation Phases
  10. API Examples
  11. Testing Strategy
  12. Future Enhancements

Project Overview

Luma (Latin for "light") is a native GUI framework for Rust that provides:

  • Native UI: Uses OS-native UI components (Win32 API on Windows)
  • Safe Abstractions: Wraps unsafe platform APIs in safe Rust interfaces
  • Layout-Based: Grid/box layout system (similar to Swing, wxWidgets)
  • Visual Editor: GUI editor application built with Luma itself (dogfooding)
  • JSON Definitions: Define UIs in JSON, load at runtime
  • Type-Safe Builders: All widgets use builder pattern with Result-based validation
  • Cross-Platform Ready: Architecture supports Windows, macOS, Linux

Key Features

  • ✓ Automatic layout calculation (recalculates on window resize by default)
  • ✓ Nested layout support (containers can hold layouts)
  • ✓ Builder pattern for all widgets
  • ✓ Comprehensive error handling with thiserror
  • ✓ Multi-select support for ListBox widget
  • ✓ Future: Visual GUI editor
  • ✓ Future: Code generation from visual designs

Architecture

Crate Organization

luma/
├── crates/
│   ├── luma-core/         # Platform-agnostic core + layout engine
│   ├── luma-windows/      # Win32 backend implementation
│   ├── luma-serde/        # JSON serialization for UI definitions
│   ├── luma-gui/          # Main public API (platform selection)
│   └── luma-editor/       # Visual GUI editor (future)
└── examples/              # Example applications

Separation of Concerns

  1. luma-core: Platform-agnostic types, traits, and layout engine
  2. luma-windows: Win32-specific implementations
  3. luma-serde: Serialization/deserialization of UI definitions
  4. luma-gui: Public API that selects platform backend at compile time
  5. luma-editor: Visual editor application (future)

Platform Selection

Uses cfg-if crate for clean platform selection:

cfg_if! {
    if #[cfg(windows)] {
        use luma_windows::*;
    } else if #[cfg(target_os = "macos")] {
        compile_error!("macOS support not yet implemented");
    } else {
        compile_error!("Unsupported platform");
    }
}

Dependencies

Workspace Dependencies

All approved and locked in:

[workspace.dependencies]
# Error handling & serialization
thiserror = "1.0"           # Error types with derive macros
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"          # JSON for UI definitions

# Utilities
bitflags = "2.4"            # Widget/layout flags and styles
cfg-if = "1.0"              # Clean platform conditional compilation
tracing = "0.1"             # Logging/debugging (dev only)
once_cell = "1.19"          # Lazy static initialization

# Internal workspace crates
luma-core = { path = "crates/luma-core", version = "0.0.1" }
luma-windows = { path = "crates/luma-windows", version = "0.0.1" }
luma-serde = { path = "crates/luma-serde", version = "0.0.1" }
luma-gui = { path = "crates/luma-gui", version = "0.0.1" }

# Windows-specific
[workspace.dependencies.windows]
version = "0.52"
features = [
    "Win32_Foundation",
    "Win32_UI_WindowsAndMessaging",
    "Win32_Graphics_Gdi",
    "Win32_System_LibraryLoader",
]

Dependency Rationale

  • thiserror: Industry-standard error handling with derive macros
  • serde/serde_json: De facto standard for serialization in Rust
  • bitflags: Clean, type-safe flag definitions
  • cfg-if: More readable than nested #[cfg] attributes
  • tracing: Structured logging for debugging (development only)
  • once_cell: Lazy statics for global state initialization
  • windows: Official Microsoft crate for Win32 APIs

Project Structure

Complete File Structure

luma/
├── Cargo.toml                          # Workspace root
├── PLAN.md                             # This file
├── README.md                           # Project overview
├── LICENSE-MIT
├── LICENSE-APACHE
├── .gitignore
│
├── crates/
│   ├── luma-core/                      # Platform-agnostic core
│   │   ├── Cargo.toml
│   │   └── src/
│   │       ├── lib.rs                  # Public exports
│   │       ├── error.rs                # Error types (thiserror)
│   │       ├── geometry.rs             # Point, Size, Rect
│   │       ├── ids.rs                  # WidgetId, WindowId
│   │       ├── handle.rs               # Safe Handle<T> wrapper
│   │       ├── traits.rs               # Backend traits
│   │       ├── flags.rs                # bitflags for widgets/windows
│   │       │
│   │       └── layout/                 # Layout system
│   │           ├── mod.rs
│   │           ├── container.rs        # Container trait
│   │           ├── constraints.rs      # LayoutConstraints, Alignment, Padding
│   │           ├── box_layout.rs       # BoxLayout (horizontal/vertical)
│   │           ├── grid_layout.rs      # GridLayout (Phase 5)
│   │           └── engine.rs           # Layout calculation engine
│   │
│   ├── luma-windows/                   # Win32 backend
│   │   ├── Cargo.toml
│   │   └── src/
│   │       ├── lib.rs
│   │       ├── application.rs          # Win32 message loop
│   │       ├── window.rs               # HWND window wrapper
│   │       ├── button.rs               # Button control
│   │       ├── label.rs                # Static text (Phase 2)
│   │       ├── textinput.rs            # Edit control (Phase 2)
│   │       ├── checkbox.rs             # Checkbox (Phase 2)
│   │       ├── listbox.rs              # Listbox (Phase 2)
│   │       ├── panel.rs                # Container widget
│   │       ├── utils.rs                # Win32 helpers
│   │       └── error.rs                # Win32 error conversion
│   │
│   ├── luma-serde/                     # Serialization (Phase 3)
│   │   ├── Cargo.toml
│   │   └── src/
│   │       ├── lib.rs
│   │       ├── ui_def.rs               # UiDefinition structs
│   │       ├── loader.rs               # Runtime UI loader
│   │       └── saver.rs                # Save UI definitions
│   │
│   ├── luma-gui/                       # Main public API
│   │   ├── Cargo.toml
│   │   └── src/
│   │       ├── lib.rs                  # Platform selection (cfg-if)
│   │       ├── prelude.rs              # Convenience re-exports
│   │       ├── application.rs          # Application API
│   │       ├── window.rs               # Window + WindowBuilder
│   │       ├── panel.rs                # Panel container widget
│   │       │
│   │       ├── widgets/                # Widget APIs
│   │       │   ├── mod.rs
│   │       │   ├── button.rs           # Button + ButtonBuilder
│   │       │   ├── label.rs            # Label + LabelBuilder (Phase 2)
│   │       │   ├── textinput.rs        # TextInput + Builder (Phase 2)
│   │       │   ├── checkbox.rs         # CheckBox + Builder (Phase 2)
│   │       │   └── listbox.rs          # ListBox + Builder (Phase 2)
│   │       │
│   │       └── layout/                 # Public layout API
│   │           ├── mod.rs
│   │           ├── box_layout.rs       # Public BoxLayout wrapper
│   │           └── grid_layout.rs      # Public GridLayout (Phase 5)
│   │
│   └── luma-editor/                    # GUI editor (Phase 4)
│       ├── Cargo.toml
│       └── src/
│           ├── lib.rs
│           ├── main.rs                 # Editor application entry
│           ├── editor.rs               # Main editor window
│           ├── canvas.rs               # Visual design canvas
│           ├── toolbox.rs              # Widget palette
│           ├── properties.rs           # Property inspector
│           └── codegen.rs              # Generate Rust code (future)
│
└── examples/
    ├── hello_window.rs                 # Basic empty window
    ├── button_demo.rs                  # Button in BoxLayout
    ├── layout_demo.rs                  # BoxLayout examples
    ├── nested_layout.rs                # Nested layouts
    ├── ui_from_json.rs                 # Load UI from JSON (Phase 3)
    └── form_demo.rs                    # Form with multiple widgets (Phase 2)

Core Design Principles

1. Layout-Based Only (No Absolute Positioning)

Unlike VCL or WinForms, Luma uses layout managers exclusively:

  • BoxLayout: Arranges widgets horizontally or vertically
  • GridLayout: Arranges widgets in a grid (Phase 5)
  • Nested Layouts: Containers can hold layouts containing more containers

Rationale: Better for responsive UIs, visual editors, and window resizing.

2. Widgets as Layout Containers

Any widget can potentially contain a layout:

pub trait Widget {
    fn set_layout(&mut self, layout: Box<dyn Container>) -> Result<()>;
    fn get_layout(&self) -> Option<&dyn Container>;
    fn set_bounds(&mut self, bounds: Rect) -> Result<()>;
    fn get_bounds(&self) -> Rect;
}
  • Window: Top-level container with layout
  • Panel: Container widget for grouping
  • Button/Label: Leaf widgets (don't contain layouts)

3. Auto-Recalculating Layouts

By default, layouts automatically recalculate when:

  • Window is resized
  • Widgets are added/removed
  • Widget constraints change

Opt-out available for performance-critical scenarios.

4. Builder Pattern with Result Validation

All widgets use builders that validate at build time:

let button = Button::builder()
    .label("Click Me")
    .on_click(|| println!("Clicked!"))
    .build(&window)?;  // Returns Result<Button, Error>

5. Type-Safe Error Handling

Using thiserror, all errors are strongly typed:

#[derive(Error, Debug)]
pub enum Error {
    #[error("Failed to create window: {0}")]
    WindowCreation(String),
    
    #[error("Failed to create widget: {0}")]
    WidgetCreation(String),
    
    #[error("Invalid parameter: {0}")]
    InvalidParameter(String),
    
    #[cfg(windows)]
    #[error("Windows API error: {0}")]
    Windows(#[from] windows::core::Error),
}

6. Safe Wrappers Around Unsafe Code

Platform-specific handles are wrapped safely:

pub struct Handle<T> {
    raw: *mut std::ffi::c_void,
    _marker: PhantomData<T>,
}

impl<T> Drop for Handle<T> {
    fn drop(&mut self) {
        // Platform-specific cleanup
    }
}

7. Concurrency Model

Phase 1: Single-threaded event loop (matches native platform model) Phase 2 (future): Thread-safe messaging with window.invoke() for background thread updates


Layout System

Container Trait

pub trait Container {
    fn add(&mut self, widget: Box<dyn Widget>, constraints: LayoutConstraints);
    fn remove(&mut self, widget: &dyn Widget);
    fn layout(&mut self, available_space: Size) -> Result<()>;
}

LayoutConstraints

#[derive(Debug, Clone, Copy)]
pub struct LayoutConstraints {
    pub min_width: Option<u32>,
    pub max_width: Option<u32>,
    pub min_height: Option<u32>,
    pub max_height: Option<u32>,
    pub preferred_width: Option<u32>,
    pub preferred_height: Option<u32>,
    pub expand_horizontal: bool,
    pub expand_vertical: bool,
    pub alignment: Alignment,
    pub padding: Padding,
}

impl LayoutConstraints {
    pub fn preferred_width(mut self, width: u32) -> Self { ... }
    pub fn preferred_height(mut self, height: u32) -> Self { ... }
    pub fn expand_horizontal(mut self, expand: bool) -> Self { ... }
    pub fn expand_vertical(mut self, expand: bool) -> Self { ... }
    pub fn expand_both(mut self, expand: bool) -> Self { ... }
    pub fn padding(mut self, padding: Padding) -> Self { ... }
    pub fn alignment(mut self, alignment: Alignment) -> Self { ... }
}

Alignment

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Alignment {
    Start,      // Left or Top
    Center,     // Centered
    End,        // Right or Bottom
    Fill,       // Stretch to fill available space
}

Padding

#[derive(Debug, Clone, Copy)]
pub struct Padding {
    pub top: u32,
    pub right: u32,
    pub bottom: u32,
    pub left: u32,
}

impl Padding {
    pub fn zero() -> Self { ... }
    pub fn all(value: u32) -> Self { ... }
    pub fn symmetric(vertical: u32, horizontal: u32) -> Self { ... }
}

BoxLayout

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LayoutDirection {
    Horizontal,
    Vertical,
}

pub struct BoxLayout {
    direction: LayoutDirection,
    gap: u32,  // Space between children
    children: Vec<(Box<dyn Widget>, LayoutConstraints)>,
}

impl BoxLayout {
    pub fn horizontal() -> Self { ... }
    pub fn vertical() -> Self { ... }
    pub fn with_gap(mut self, gap: u32) -> Self { ... }
    pub fn add(&mut self, widget: impl Widget + 'static, constraints: LayoutConstraints) { ... }
}

Layout Algorithm (Vertical):

  1. Calculate total fixed height (non-expanding widgets)
  2. Calculate remaining space for expanding widgets
  3. Distribute remaining space equally among expanding widgets
  4. Position each widget with padding applied
  5. If widget has child layout, recursively trigger layout

GridLayout (Phase 5)

pub struct GridLayout {
    rows: u32,
    columns: u32,
    horizontal_gap: u32,
    vertical_gap: u32,
    children: Vec<(Box<dyn Widget>, LayoutConstraints)>,
}

impl GridLayout {
    pub fn new(rows: u32, columns: u32) -> Self { ... }
    pub fn with_gaps(mut self, h_gap: u32, v_gap: u32) -> Self { ... }
}

Widget System

Essential Widgets (Phase 1-2)

  1. Window: Top-level container
  2. Panel: Container for grouping widgets with layouts
  3. Button: Clickable button with text label
  4. Label: Static text display
  5. TextInput: Single-line editable text field
  6. CheckBox: Boolean toggle
  7. ListBox: List selection (single or multi-select)

Widget Flags

bitflags! {
    pub struct WindowFlags: u32 {
        const RESIZABLE = 0b0001;
        const MINIMIZABLE = 0b0010;
        const MAXIMIZABLE = 0b0100;
        const CLOSABLE = 0b1000;
        const TITLED = 0b10000;
    }
}

bitflags! {
    pub struct ButtonFlags: u32 {
        const DEFAULT = 0b0001;      // Activated by Enter key
        const TOGGLE = 0b0010;       // Toggle button (on/off)
    }
}

bitflags! {
    pub struct ListBoxFlags: u32 {
        const MULTI_SELECT = 0b0001; // Allow multiple selection
        const SORTED = 0b0010;       // Sort items alphabetically
        const VSCROLL = 0b0100;      // Vertical scrollbar
        const HSCROLL = 0b1000;      // Horizontal scrollbar
    }
}

ListBox Multi-Select API

Type-safe approach with separate callbacks:

pub struct ListBoxBuilder {
    // ...
}

impl ListBoxBuilder {
    // Single-select mode
    pub fn on_select_single<F>(mut self, callback: F) -> Self
    where F: FnMut(usize) + 'static
    { ... }
    
    // Multi-select mode (automatically sets MULTI_SELECT flag)
    pub fn on_select_multi<F>(mut self, callback: F) -> Self
    where F: FnMut(Vec<usize>) + 'static
    { ... }
    
    // Cannot specify both - validated at build() time
    pub fn build(self, parent: &Window) -> Result<ListBox> { ... }
}

Serialization Format

JSON UI Definition (Phase 3)

{
  "version": "0.0.1",
  "window": {
    "title": "My Application",
    "width": 500,
    "height": 400,
    "resizable": true,
    "layout": {
      "type": "BoxLayout",
      "direction": "vertical",
      "gap": 10,
      "children": [
        {
          "id": "header_panel",
          "widget_type": "Panel",
          "properties": {},
          "constraints": {
            "preferred_height": 60
          },
          "layout": {
            "type": "BoxLayout",
            "direction": "horizontal",
            "gap": 5,
            "children": [
              {
                "id": "btn_new",
                "widget_type": "Button",
                "properties": {
                  "label": "New"
                },
                "constraints": {
                  "preferred_width": 80,
                  "expand_vertical": true
                }
              },
              {
                "id": "btn_open",
                "widget_type": "Button",
                "properties": {
                  "label": "Open"
                },
                "constraints": {
                  "preferred_width": 80,
                  "expand_vertical": true
                }
              }
            ]
          }
        },
        {
          "id": "content_label",
          "widget_type": "Label",
          "properties": {
            "text": "Content goes here"
          },
          "constraints": {
            "expand_horizontal": true,
            "expand_vertical": true,
            "alignment": "center"
          }
        }
      ]
    }
  }
}

Runtime Loading (Phase 3)

use luma_serde::UiLoader;

let window = UiLoader::load_from_file("ui/main_window.json")?;
window.show()?;

Code Generation (Future)

use luma_editor::codegen;

let ui_def = UiDefinition::load("ui/main_window.json")?;
let rust_code = codegen::generate_rust_code(&ui_def);
std::fs::write("src/generated_ui.rs", rust_code)?;

Implementation Phases

Phase 1: Foundation (2-3 weeks) ← START HERE

Goal: Basic window + button with BoxLayout working on Windows

Tasks

  1. Workspace Setup

    • Create root Cargo.toml with workspace configuration
    • Create README.md, LICENSE-MIT, LICENSE-APACHE
    • Create .gitignore for Rust projects
    • Set up crate directory structure
  2. luma-core Implementation

    • error.rs: Error types with thiserror
    • geometry.rs: Point, Size, Rect structs
    • ids.rs: WidgetId, WindowId newtypes
    • handle.rs: Safe Handle wrapper
    • traits.rs: Backend traits (ApplicationBackend, WindowBackend, ButtonBackend)
    • flags.rs: WindowFlags, ButtonFlags with bitflags
    • layout/constraints.rs: LayoutConstraints, Alignment, Padding
    • layout/container.rs: Container trait
    • layout/box_layout.rs: BoxLayout implementation
  3. luma-windows Implementation

    • application.rs: Win32 message loop (GetMessage, DispatchMessage)
    • window.rs: HWND wrapper with CreateWindowExW
    • button.rs: Button control (CreateWindowExW with "BUTTON" class)
    • panel.rs: Panel container widget
    • utils.rs: String conversion helpers (UTF-8 ↔ UTF-16)
    • error.rs: Win32 error conversion
  4. luma-gui Implementation

    • lib.rs: Platform selection with cfg-if
    • prelude.rs: Convenience re-exports
    • application.rs: Cross-platform Application wrapper
    • window.rs: Window + WindowBuilder
    • panel.rs: Panel wrapper
    • widgets/button.rs: Button + ButtonBuilder
    • layout/box_layout.rs: Public BoxLayout API
  5. Examples

    • hello_window.rs: Empty window
    • button_demo.rs: Window with button in vertical layout
    • nested_layout.rs: Panel with nested horizontal layout
  6. Testing

    • Unit tests for geometry types
    • Unit tests for layout constraints
    • Unit tests for builder patterns
    • Manual testing: Run examples and verify behavior

Success Criteria

  • ✓ Window displays on Windows
  • ✓ Button renders and responds to clicks
  • ✓ BoxLayout arranges widgets correctly
  • ✓ Layout recalculates on window resize
  • ✓ Nested layouts work correctly
  • ✓ All examples compile and run
  • ✓ No panics or crashes during normal operation

Phase 2: Complete Widget Set (2-3 weeks)

Goal: Implement all essential widgets with layout support

Tasks

  1. Label Widget

    • Win32: STATIC control
    • API: Label + LabelBuilder
    • Properties: text, alignment
  2. TextInput Widget

    • Win32: EDIT control (single-line)
    • API: TextInput + TextInputBuilder
    • Properties: text, placeholder, read-only
    • Events: on_text_changed
  3. CheckBox Widget

    • Win32: BUTTON with BS_CHECKBOX style
    • API: CheckBox + CheckBoxBuilder
    • Properties: label, checked
    • Events: on_checked_changed
  4. ListBox Widget

    • Win32: LISTBOX control
    • API: ListBox + ListBoxBuilder
    • Properties: items, flags (MULTI_SELECT, SORTED)
    • Events: on_select_single, on_select_multi
  5. Examples

    • form_demo.rs: Complete form with all widget types
    • listbox_demo.rs: Single and multi-select demos
  6. Testing

    • Unit tests for each widget builder
    • Integration test: Form with all widgets
    • Manual testing: Verify native look and feel

Success Criteria

  • ✓ All 7 essential widgets implemented
  • ✓ Each widget integrates properly with layout system
  • ✓ Native Windows appearance maintained
  • ✓ Events fire correctly
  • ✓ ListBox multi-select works as designed

Phase 3: Serialization & UI Loading (1-2 weeks)

Goal: Define UIs in JSON and load at runtime

Tasks

  1. luma-serde Crate

    • ui_def.rs: UiDefinition, WindowDef, LayoutDef, WidgetDef structs
    • loader.rs: Runtime UI loader
    • saver.rs: Save UI definitions to JSON
  2. UiLoader Implementation

    • Parse JSON into UiDefinition
    • Build Window from WindowDef
    • Build layouts recursively
    • Build widgets with properties
    • Connect to parent window
  3. Examples

    • ui_from_json.rs: Load and display UI from JSON
    • Create sample JSON files for various UIs
  4. Testing

    • Unit tests for JSON parsing
    • Integration test: Load complex nested layout
    • Verify all widget types load correctly
    • Test error handling for invalid JSON

Success Criteria

  • ✓ Can define complete UI in JSON
  • ✓ Runtime loader creates functional UI
  • ✓ Nested layouts load correctly
  • ✓ Widget properties apply correctly
  • ✓ Error messages helpful for invalid JSON

Phase 4: GUI Editor (3-4 weeks)

Goal: Visual editor for designing UIs (built with Luma itself)

Tasks

  1. Editor Window Structure

    • Main window with three-panel BoxLayout
    • Left panel: Toolbox (widget palette)
    • Center panel: Canvas (design area)
    • Right panel: Properties inspector
  2. Toolbox Implementation

    • List of available widget types
    • Click to select widget type
    • Simple UI: ListBox with widget names
  3. Canvas Implementation

    • Display current UI being edited
    • Click to select widgets
    • Highlight selected widget
    • Show layout boundaries (debug visualization)
  4. Properties Inspector

    • Display selected widget properties
    • Editable fields for text, size, etc.
    • Layout constraint editors
  5. Core Editor Features

    • New project
    • Add widget to layout
    • Remove widget
    • Edit widget properties
    • Save to JSON
    • Load from JSON
    • Preview UI
  6. Testing

    • Manual testing: Design sample UIs
    • Verify saved JSON loads correctly
    • Test round-trip: Save → Load → Save

Success Criteria

  • ✓ Editor runs and is stable
  • ✓ Can create simple UIs visually
  • ✓ Saved JSON files are valid
  • ✓ Loaded UIs match the design
  • ✓ Editor itself demonstrates Luma capabilities

Note: Code generation deferred to future phase


Phase 5: GridLayout (1-2 weeks)

Goal: Add grid layout support

Tasks

  1. GridLayout Implementation

    • luma-core/layout/grid_layout.rs
    • Row/column-based positioning
    • Gap support (horizontal and vertical)
    • Cell spanning (future enhancement)
  2. API Integration

    • Public GridLayout in luma-gui
    • GridLayout in JSON format
    • Update UI loader
  3. Editor Support

    • Add GridLayout to editor
    • Layout type selector
    • Grid configuration UI
  4. Examples

    • grid_demo.rs: GridLayout examples

Success Criteria

  • ✓ GridLayout works alongside BoxLayout
  • ✓ JSON format supports GridLayout
  • ✓ Editor can create grid-based UIs
  • ✓ Proper resize behavior

Phase 6: Polish & Documentation (1-2 weeks)

Goal: Production-ready 0.1.0 release

Tasks

  1. Documentation

    • Comprehensive rustdoc comments for all public APIs
    • User guide (getting started, tutorials)
    • Architecture documentation
    • Contributing guide
  2. Examples Gallery

    • Polished examples for each feature
    • Screenshot/demo for each example
    • Example descriptions
  3. Performance

    • Profile layout calculation
    • Optimize Win32 message handling
    • Reduce allocations where possible
  4. Bug Fixes

    • Edge cases in layout system
    • Window resize glitches
    • Memory leaks (verify Drop impls)
  5. Release Preparation

    • Update version to 0.1.0
    • Finalize README
    • Prepare release notes
    • Publish to crates.io (optional)

Success Criteria

  • ✓ All public APIs documented
  • ✓ User guide complete
  • ✓ No known critical bugs
  • ✓ Examples are polished
  • ✓ Ready for 0.1.0 release

API Examples

Basic Window with Button

use luma_gui::prelude::*;

fn main() -> Result<()> {
    let app = Application::new()?;
    
    let mut window = Window::builder()
        .title("Hello, Luma!")
        .size(400, 300)
        .build()?;
    
    let mut layout = BoxLayout::vertical().with_gap(10);
    
    let button = Button::builder()
        .label("Click Me!")
        .on_click(|| println!("Button clicked!"))
        .build(&window)?;
    
    layout.add(button, LayoutConstraints::default()
        .preferred_height(40)
        .expand_horizontal(true));
    
    window.set_layout(layout)?;
    window.show()?;
    
    app.run()
}

Nested Layouts

use luma_gui::prelude::*;

fn main() -> Result<()> {
    let app = Application::new()?;
    
    let mut window = Window::builder()
        .title("Nested Layout Demo")
        .size(500, 400)
        .build()?;
    
    let mut main_layout = BoxLayout::vertical().with_gap(10);
    
    // Top panel with horizontal button row
    let mut top_panel = Panel::new(&window)?;
    let mut button_layout = BoxLayout::horizontal().with_gap(5);
    
    button_layout.add(
        Button::builder().label("New").build(&top_panel)?,
        LayoutConstraints::default().expand_horizontal(true)
    );
    button_layout.add(
        Button::builder().label("Open").build(&top_panel)?,
        LayoutConstraints::default().expand_horizontal(true)
    );
    button_layout.add(
        Button::builder().label("Save").build(&top_panel)?,
        LayoutConstraints::default().expand_horizontal(true)
    );
    
    top_panel.set_layout(button_layout)?;
    main_layout.add(top_panel, LayoutConstraints::default().preferred_height(50));
    
    // Content area
    let label = Label::builder()
        .text("Content Area")
        .build(&window)?;
    main_layout.add(label, LayoutConstraints::default().expand_both(true));
    
    window.set_layout(main_layout)?;
    window.show()?;
    
    app.run()
}

Form with Multiple Widgets

use luma_gui::prelude::*;

fn main() -> Result<()> {
    let app = Application::new()?;
    
    let mut window = Window::builder()
        .title("Form Demo")
        .size(400, 300)
        .build()?;
    
    let mut layout = BoxLayout::vertical().with_gap(10);
    
    // Name field
    layout.add(
        Label::builder().text("Name:").build(&window)?,
        LayoutConstraints::default().preferred_height(20)
    );
    layout.add(
        TextInput::builder().build(&window)?,
        LayoutConstraints::default().preferred_height(30).expand_horizontal(true)
    );
    
    // Options
    layout.add(
        CheckBox::builder().label("Subscribe to newsletter").build(&window)?,
        LayoutConstraints::default().preferred_height(25)
    );
    
    // Submit button
    layout.add(
        Button::builder()
            .label("Submit")
            .on_click(|| println!("Form submitted!"))
            .build(&window)?,
        LayoutConstraints::default().preferred_height(40)
    );
    
    window.set_layout(layout)?;
    window.show()?;
    
    app.run()
}

ListBox Multi-Select

use luma_gui::prelude::*;

fn main() -> Result<()> {
    let app = Application::new()?;
    
    let mut window = Window::builder()
        .title("ListBox Demo")
        .size(300, 400)
        .build()?;
    
    let mut layout = BoxLayout::vertical().with_gap(10);
    
    // Multi-select listbox
    let listbox = ListBox::builder()
        .items(vec!["Item 1", "Item 2", "Item 3", "Item 4"])
        .on_select_multi(|indices| {
            println!("Selected items: {:?}", indices);
        })
        .sorted(true)
        .build(&window)?;
    
    layout.add(listbox, LayoutConstraints::default().expand_both(true));
    
    window.set_layout(layout)?;
    window.show()?;
    
    app.run()
}

Load UI from JSON

use luma_gui::prelude::*;
use luma_serde::UiLoader;

fn main() -> Result<()> {
    let app = Application::new()?;
    
    // Load UI from JSON file
    let mut window = UiLoader::load_from_file("ui/main_window.json")?;
    
    window.show()?;
    
    app.run()
}

Testing Strategy

Unit Tests

All tests in #[cfg(test)] mod tests blocks:

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_point_creation() {
        let p = Point { x: 10, y: 20 };
        assert_eq!(p.x, 10);
        assert_eq!(p.y, 20);
    }
    
    #[test]
    fn test_layout_constraints_builder() {
        let constraints = LayoutConstraints::default()
            .preferred_width(100)
            .expand_horizontal(true);
        
        assert_eq!(constraints.preferred_width, Some(100));
        assert!(constraints.expand_horizontal);
    }
}

Integration Tests

In tests/ directory at workspace root:

// tests/window_creation.rs
use luma_gui::prelude::*;

#[test]
fn test_window_creation() {
    let _app = Application::new().unwrap();
    let window = Window::builder()
        .title("Test")
        .size(400, 300)
        .build();
    
    assert!(window.is_ok());
}

Manual Testing

For each phase:

  1. Run all examples
  2. Verify visual appearance matches expectations
  3. Test window resize behavior
  4. Test widget interactions (clicks, typing, etc.)
  5. Check for memory leaks (long-running tests)
  6. Verify error messages are helpful

Tracing/Logging

Use tracing for debugging (development only):

tracing::info!("Creating Win32 window: title='{}', size={}x{}", title, width, height);
tracing::debug!("Layout calculated: {} widgets positioned", child_count);
tracing::error!("Failed to create window: {}", error);

Enable with environment variable:

RUST_LOG=luma=debug cargo run --example hello_window

Future Enhancements

Post-0.1.0 Features

  1. Platform Support

    • macOS support (Cocoa/AppKit)
    • Linux support (GTK)
  2. More Widgets

    • TreeView (hierarchical data)
    • TabControl (tabbed interface)
    • ProgressBar (progress indication)
    • Slider (numeric input)
    • ComboBox/DropDown (selection)
    • TextArea (multi-line text)
    • Toolbar (button groups)
    • StatusBar (status information)
  3. Advanced Layout

    • Cell spanning in GridLayout
    • FlowLayout (wrapping layout)
    • Custom layout managers
    • Layout animations
  4. Styling & Theming

    • Custom colors
    • Custom fonts
    • Theme support
    • Dark mode (via DwmSetWindowAttribute for title bars, custom rendering for controls)
  5. Code Generation

    • Generate Rust code from JSON
    • Hot reload during development
    • Visual Studio Code extension
  6. Advanced Editor Features

    • Undo/redo
    • Copy/paste widgets
    • Alignment guides
    • Snapping to grid
    • Component/template system
    • Drag-and-drop on canvas
  7. Accessibility

    • Screen reader support
    • Keyboard navigation
    • High contrast themes
    • Accessibility hints
  8. Graphics & Drawing

    • Custom painting API
    • Canvas widget
    • Image display
    • SVG support
  9. Dialogs

    • File picker (open/save)
    • Message boxes
    • Color picker
    • Font picker
  10. Performance

    • Virtual scrolling for large lists
    • Layout caching
    • Partial redraws
    • GPU acceleration (future)
  11. Developer Tools

    • Layout inspector
    • Performance profiler
    • Widget hierarchy viewer
    • Live property editing

Success Metrics

Phase 1 Success

  • Window displays on Windows
  • Button responds to clicks
  • BoxLayout positions widgets correctly
  • Layout recalculates on resize
  • All examples run without errors
  • No crashes or panics

Phase 2 Success

  • All 7 widgets implemented
  • Form example works completely
  • ListBox multi-select functions correctly
  • Native Windows look maintained

Phase 3 Success

  • JSON format defined and documented
  • Runtime loader works for all widget types
  • Nested layouts load correctly
  • Error messages are helpful

Phase 4 Success

  • Editor launches and runs stably
  • Can design simple UIs visually
  • Save/load cycle preserves designs
  • Editor demonstrates Luma's power

Phase 5 Success

  • GridLayout works correctly
  • Editor supports GridLayout
  • Examples demonstrate grid usage

Phase 6 Success

  • All APIs documented
  • User guide complete
  • Ready for 0.1.0 release
  • Community feedback positive

Development Guidelines

Code Style

  • Follow Rust API guidelines
  • Use rustfmt for formatting
  • Use clippy for lints
  • Comprehensive documentation comments
  • Meaningful variable names
  • Clear error messages

Git Workflow

  • Feature branches for each task
  • Descriptive commit messages
  • Squash commits before merging
  • Keep main branch stable

Documentation

  • Rustdoc comments for all public APIs
  • Examples in doc comments
  • Architecture decisions documented
  • Update PLAN.md as design evolves

Performance

  • Profile before optimizing
  • Minimize allocations in hot paths
  • Lazy initialization where appropriate
  • Cache layout calculations when possible

Contact & Support

For questions, issues, or contributions, please refer to:

  • Repository: (add GitHub URL when available)
  • Documentation: (add docs URL when available)
  • Issues: (add issue tracker URL when available)

Appendix A: WinUI 3 Research

Research Date: January 8, 2026

Question: Should Luma use WinUI 3 / Windows App SDK for native Windows 11 dark mode support?

Answer: No. Win32 is the correct choice.

Findings

1. XAML Removed from windows Crate

In June 2022, Microsoft explicitly removed all XAML APIs from the windows crate:

  • PR #1836: "Remove Xaml from windows crate"
  • Reason: "Xaml is designed squarely for C# developers"
  • Kenny Kerr (maintainer): "there are currently no plans to provide a Rust-friendly version of Xaml"

2. WinUI 3 Status

Separate crate exists: windows-app (experimental, not recommended)

Major Issues Identified:

  • WinUI has undocumented behavior and undocumented assumptions about host processes
  • Only truly supports MSBuild + C#
  • Implementing IXamlMetadataProvider alone is insufficient
  • Controls appear to work but crash unpredictably in WinUI stack
  • No source code access makes debugging nearly impossible
  • Incomplete fusion manifests cause crashes
  • Quirks change between WinUI 3 releases

Microsoft's Official Position (Rivera, Windows team):

"WinUI has undocumented behavior and makes undocumented assumptions about its host process. (XAML only truly supports MSBuild+C#.) Finding and adjusting for those quirks--that changed between WinUI 3 releases--through trial and error was wasting everyone's time."

"I think the sustainable way forward is to throw away XAML and build on top of DirectComposition. That's a gargantuan effort and not something folks are working on at this time."

3. Current UI Framework Usage (per Microsoft)

  • Top 2: WinForms and WPF (both require .NET)
  • Very low usage: WinRT XAML (in-box XAML)
  • Zero usage in Rust: WinRT XAML

4. What DOES Work

  • Win32 (user32 + GDI): Fully supported, stable, in-box, complete Rust bindings
  • Windows.UI.WindowManagement.AppWindow (UWP): Available but deprecated for new development

Decision: Continue with Win32

Pros:

  1. Battle-tested with complete Rust bindings via windows crate
  2. In-box on every Windows version (minimal memory footprint)
  3. No experimental/unsupported territory
  4. Stable API that won't change unexpectedly

Dark Mode Limitation (Acceptable for MVP):

  • Can implement dark title bars via DwmSetWindowAttribute(DWMWA_USE_IMMERSIVE_DARK_MODE)
  • Window contents (buttons, panels) remain light themed (standard Win32 controls)
  • This is consistent with many existing Win32 applications
  • Documented limitation, not a blocker

Future Dark Mode Strategy:

  • Phase 1-3 (MVP): Dark title bars optional, light controls (acceptable)
  • Phase 4+: Custom control rendering (owner-drawn controls) for full dark mode
  • Phase 5+: DirectComposition-based rendering layer (hardware-accelerated)
  • Alternative: WebView2 backend for Electron-like experience

References


Last Updated: January 8, 2026
Status: Phase 1 implementation complete (luma-core, luma-windows, luma-gui)
Next Step: Begin Phase 2 - Complete widget set (Label, TextInput, CheckBox, ListBox)