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.
131 lines
3.8 KiB
MQL5
131 lines
3.8 KiB
MQL5
//+------------------------------------------------------------------+
| |
//| UState.mqh |
| |
//| Copyright 2026, DearMQL5 GUI Engine |
| |
//| https://www.mql5.com |
| |
//+------------------------------------------------------------------+
| |
#property copyright "Copyright 2026, DearMQL5 GUI Engine"
| |
#property link "https://www.mql5.com"
| |
#property strict
| |
| |
/// Retained state entry for a single widget or window instance.
| |
struct SUStateEntry
| |
{
| |
ulong id; ///< Unique FNV-1a hash key
| |
double float_val; ///< Floating point value (sliders, scroll)
| |
long int_val; ///< Integer / boolean flag value (toggles, collapses)
| |
string str_val; ///< String content (edit boxes)
| |
ulong last_frame; ///< Frame counter when last touched (for garbage collection)
| |
};
| |
| |
/// High-performance retained state map in pure MQL5 (zero external dependencies).
| |
class UState
| |
{
| |
private:
| |
static SUStateEntry s_entries[];
| |
static int s_count;
| |
static ulong s_frame_counter;
| |
| |
/// Binary search or linear scan for state key.
| |
static int FindIndex(const ulong id)
| |
{
| |
for(int i = 0; i < s_count; i++)
| |
{
| |
if(s_entries[i].id == id)
| |
return(i);
| |
}
| |
return(-1);
| |
}
| |
| |
/// Inserts or gets a state entry index for the given key.
| |
static int GetOrCreate(const ulong id)
| |
{
| |
int idx = FindIndex(id);
| |
if(idx >= 0)
| |
{
| |
s_entries[idx].last_frame = s_frame_counter;
| |
return(idx);
| |
}
| |
| |
if(s_count >= ArraySize(s_entries))
| |
ArrayResize(s_entries, (s_count == 0) ? 64 : s_count * 2);
| |
| |
int new_idx = s_count++;
| |
s_entries[new_idx].id = id;
| |
s_entries[new_idx].float_val = 0.0;
| |
s_entries[new_idx].int_val = 0;
| |
s_entries[new_idx].str_val = "";
| |
s_entries[new_idx].last_frame = s_frame_counter;
| |
return(new_idx);
| |
}
| |
| |
public:
| |
/// Increments the global frame counter.
| |
static void NextFrame(void)
| |
{
| |
s_frame_counter++;
| |
}
| |
| |
/// Gets or initializes an integer/boolean state value.
| |
static long GetInt(const ulong id, const long default_val = 0)
| |
{
| |
int idx = FindIndex(id);
| |
if(idx < 0)
| |
{
| |
idx = GetOrCreate(id);
| |
s_entries[idx].int_val = default_val;
| |
return(default_val);
| |
}
| |
return(s_entries[idx].int_val);
| |
}
| |
| |
/// Sets an integer/boolean state value.
| |
static void SetInt(const ulong id, const long val)
| |
{
| |
int idx = GetOrCreate(id);
| |
s_entries[idx].int_val = val;
| |
}
| |
| |
/// Gets or initializes a floating point state value.
| |
static double GetFloat(const ulong id, const double default_val = 0.0)
| |
{
| |
int idx = FindIndex(id);
| |
if(idx < 0)
| |
{
| |
idx = GetOrCreate(id);
| |
s_entries[idx].float_val = default_val;
| |
return(default_val);
| |
}
| |
return(s_entries[idx].float_val);
| |
}
| |
| |
/// Sets a floating point state value.
| |
static void SetFloat(const ulong id, const double val)
| |
{
| |
int idx = GetOrCreate(id);
| |
s_entries[idx].float_val = val;
| |
}
| |
| |
/// Gets or initializes a string state value.
| |
static string GetString(const ulong id, const string default_val = "")
| |
{
| |
int idx = FindIndex(id);
| |
if(idx < 0)
| |
{
| |
idx = GetOrCreate(id);
| |
s_entries[idx].str_val = default_val;
| |
return(default_val);
| |
}
| |
return(s_entries[idx].str_val);
| |
}
| |
| |
/// Sets a string state value.
| |
static void SetString(const ulong id, const string val)
| |
{
| |
int idx = GetOrCreate(id);
| |
s_entries[idx].str_val = val;
| |
}
| |
};
| |
| |
SUStateEntry UState::s_entries[];
| |
int UState::s_count = 0;
| |
ulong UState::s_frame_counter = 0;
|