DearMQL5/Docs/ARCHITECTURE.md
Alex David Hernandez Maturrano 78e7ae5145 feat: initial release of DearMQL5 v1.0.0 - Immediate-Mode GUI Engine for MetaTrader 5
DearMQL5 is an institutional-grade, immediate-mode graphical user interface
(GUI) engine designed from the ground up for MetaTrader 5 (MQL5), inspired by
the ergonomics and performance of Dear ImGui.

### Core Architecture & Execution Pipeline
- Immediate-Mode Paradigm: Declarative frame-based rendering pipeline with zero
  memory allocation churn during render loops and deterministic execution.
- Modular Per-Hub Canvas Surfaces (CUWindowSurface): Replaces full-screen canvas
  overlays with isolated, window-bounded CCanvas bitmaps, reducing memory usage
  by up to 93% (~570 KB vs 8.3 MB for 1080p) and preventing click-swallowing.
- 0-Cost Hardware Texture Drag Engine: Absolute-anchor drag mechanics update
  native MT5 OBJPROP_XDISTANCE and OBJPROP_YDISTANCE properties directly on
  the compositor, bypassing CPU rasterization completely (0.00% CPU usage).
- Chart Scroll Protection: Automatically suppresses chart history sliding
  (CHART_MOUSE_SCROLL) during active HUD dragging and safely restores it on release.
- Two-Phase Hit-Testing: Interactive controls (buttons, sliders, toggles) receive
  first-priority click focus, cleanly separating widget actions from window drags.

### Subsystems & Components
- Core State & Input (Core/):
  * UInputState: Mouse/keyboard tracking, deltas, and chart scroll lock.
  * UState: Retained state hash map in pure MQL5 with 64-bit FNV-1a hashing.
  * UIdStack: Hierarchical identifier scoping preventing widget ID collisions.
  * ULayout: Automatic cursor placement supporting SameLine, Indent, and Unindent.
  * UEventQueue: Non-blocking circular UI event queue for decoupled handling.
  * UTheme: Institutional OneDark/Nord dark color palette and typography metrics.
- Rendering Backends (Render/):
  * URendererCanvas: Isolated per-hub surfaces with 32-bit ARGB alpha transparency.
  * URendererNative: Native MT5 object pool (OBJ_RECTANGLE_LABEL) with diff caching.
  * UFont: Anti-aliased font metrics and width cache.
- Complete Widget Suite (Widgets/):
  * UButton: Click-on-release standard, accent, and emergency panic buttons.
  * UToggle: Smooth draggable/clickable iOS-style toggle switches.
  * USlider: Draggable horizontal float and integer sliders.
  * UProgressBar: Adaptive progress bars with dynamic green->amber->red color ramps.
  * UHeader: Collapsible section headers with immediate-mode state retention.
  * ULabel & USeparator: Formatted text, colored metrics, and horizontal dividers.
- Window Management (Windows/):
  * UWindow: Window container with titlebar, collapse toggle, and coordinate clipping.
  * UWindowManager: Multi-window coordinator with GlobalVariable persistence across
    chart timeframe changes and backward-compatible key resolution.

### Tooling, Documentation & Reference Implementation
- Examples/EA_DearMQL5_Demo.mq5: Complete reference Prop-Firm cockpit HUD.
- README.md: Comprehensive institutional English documentation for GitHub and Algo Forge.
- Docs/ARCHITECTURE.md: Technical architecture specification with Mermaid lifecycle.
2026-10-12 08:35:18 -03:00

7.2 KiB

DearMQL5 Technical Architecture Specification

This document provides a technical deep-dive into the internal subsystems of DearMQL5, including its immediate-mode execution pipeline, input state machine, retained state management, and the per-hub canvas rendering backend.


1. Subsystem Architecture

DearMQL5 is partitioned into decoupled layers with strict separation of concerns:

┌────────────────────────────────────────────────────────┐
│                   Public API Facade                    │
│                        (UI.mqh)                        │
└───────────┬────────────────────────────────┬───────────┘
            │                                │
            ▼                                ▼
┌───────────────────────┐        ┌───────────────────────┐
│   Window Containers   │        │     Widget Suite      │
│ (UWindow, ULayout)    │        │ (UButton, USlider...) │
└───────────┬───────────┘        └───────────┬───────────┘
            │                                │
            └────────────────┬───────────────┘
                             ▼
┌────────────────────────────────────────────────────────┐
│                  Core State & Layout                   │
│   - UInputState (Mouse, Keyboard, Dragging, Scroll)    │
│   - UState (Retained State Hash Map)                   │
│   - UIdStack (FNV-1a Hierarchical Hashing)             │
│   - UTheme (Color Palette & Styling)                   │
└────────────────────────────┬───────────────────────────┘
                             ▼
┌────────────────────────────────────────────────────────┐
│                   Rendering Backend                    │
│   - URendererCanvas (Isolated CUWindowSurface Pool)    │
│   - URendererNative (OBJ_RECTANGLE_LABEL Pool)         │
│   - UFont (Font Metrics & Text Width Cache)            │
└────────────────────────────────────────────────────────┘

2. The Frame Lifecycle Pipeline

Every execution cycle in an Expert Advisor or Indicator follows a three-stage pipeline:

sequenceDiagram
    participant EA as Expert Advisor
    participant UI as UI Facade
    participant Input as UInputState
    participant Win as UWindow
    participant Surf as CUWindowSurface
    participant MT5 as MT5 Compositor

    EA->>UI: OnChartEvent(id, lparam, dparam, sparam)
    UI->>Input: OnMouseMove(x, y, flags)
    
    EA->>UI: NewFrame()
    UI->>Input: NewFrame() (Compute Deltas, Retain Active)
    
    EA->>UI: Begin("Cockpit", open, x, y, w, h)
    UI->>Win: Begin(...) (Resolve Anchor Drag & Collapses)
    UI->>Surf: BeginWindowSurface(win_id, x, y, w, h)
    
    EA->>UI: Button / Slider / Text Widgets
    UI->>Surf: DrawRect / DrawText (Local Coordinates)
    
    EA->>UI: End()
    UI->>Win: End() (Promote Drag Candidates)
    
    EA->>UI: Render()
    UI->>Surf: Update() (Commit Dirty Bitmaps)
    UI->>MT5: ChartRedraw()

Stage 1: Input Aggregation (NewFrame)

  1. Receives mouse position (x, y) and button flags from MT5's CHARTEVENT_MOUSE_MOVE.
  2. Computes movement delta: delta_x = mouse_x - prev_mouse_x before updating previous coordinates.
  3. Retains previous frame's s_active_id into s_prev_active_id so that release events (s_mouse_released) are properly recognized by widgets.
  4. Resets s_hot_id = 0 to prepare for the frame's hit-testing pass.

Stage 2: Widget Evaluation & Layout (Begin ... End)

  1. UI::Begin:
    • Retrieves persistent coordinates (x, y, w, h) from UState or UWindowManager.
    • Tests collapse button first to eliminate drag collision.
    • Evaluates window drag engine using absolute anchors.
    • Binds the active window surface in URendererCanvas and initializes ULayout.
  2. Widgets evaluate their bounding boxes and hit-testing in UWidget::Behavior.
    • If mouse is within bounding box, registers widget as Hot.
    • If clicked, claims Active and keyboard focus.
    • If released while Active and Hot, returns clicked = true.
  3. UI::End:
    • If the window was clicked and no child widget claimed active interaction, the window promotes candidate drag to active drag.
    • Restores layout and pops ID stack.

Stage 3: Rendering & Compositing (Render)

  1. Only surfaces marked with is_dirty = true execute CCanvas::Update().
  2. UInputState::EndFrame() cleans up any residual active captures.
  3. UDiagnostics records frame duration and total draw calls.

3. Retained State Engine (UState)

Although DearMQL5's API is immediate-mode, state must persist between frames (e.g., whether a header is open, current slider value, or window positions).

  • 64-bit FNV-1a Hash: Each widget ID is hashed:
    \text{hash} = (\text{hash} \oplus \text{byte}) \times 1099511628211
  • Pre-Allocated Entry Array: Stored in a contiguous array of SUStateEntry with geometric resizing (64 \to 128 \to 256), avoiding heap allocations after initial warm-up.
  • Frame Tracking: Each entry logs last_frame for automatic garbage collection of dead widgets.

4. Per-Hub Canvas Architecture (CUWindowSurface)

Unlike traditional full-chart canvas models:

  1. Each window owns a dedicated CCanvas instance mapped to a uniquely named chart bitmap: DearMQL5_Hub_<win_id>_<chart_id>.
  2. Local Coordinate Translation: Widgets submit global coordinates (gx, gy). URendererCanvas automatically translates:
    lx = gx - \text{surface.GetX()}
    ly = gy - \text{surface.GetY()}
  3. Zero-Cost Drag: When a window moves from (x_1, y_1) to (x_2, y_2), the canvas pixels are untouched. DearMQL5 only calls:
    ObjectSetInteger(chart_id, obj_name, OBJPROP_XDISTANCE, x2);
    ObjectSetInteger(chart_id, obj_name, OBJPROP_YDISTANCE, y2);
    
    MT5's internal DirectX compositor shifts the bitmap directly on the screen at zero CPU rasterization cost.

5. Chart Scroll Suppression & Interaction Guard

When dragging standard graphical objects on MetaTrader charts, MT5's default handler attempts to scroll price history horizontally.

DearMQL5 mitigates this using automatic scroll locking:

// On Drag Start:
ChartSetInteger(chart_id, CHART_MOUSE_SCROLL, false);

// On Drag Release:
ChartSetInteger(chart_id, CHART_MOUSE_SCROLL, true);

This guarantees smooth HUD movement without disrupting chart viewports.