Refresh, Layout and Rendering
ModernUI repaints through a CCanvas-backed chart surface.
The root tracks what needs to be repainted. Some changes redraw the whole logical canvas. Other changes can redraw only a smaller area.
Main refresh calls (prefer these)
| Call | Meaning |
|---|---|
MuiRoot::RefreshAll() |
Redraw the whole UI |
MuiRoot::RefreshArea(MuiRect) |
Redraw a specific logical rectangle only |
MuiElement::Refresh() |
Redraw one control after its visual state changed |
MuiElement::Relayout() |
Recalculate layout for one control (already includes redraw) |
The existing names below still work and are kept for compatibility:
| Existing/internal name | Friendly alias |
|---|---|
MuiRoot::Invalidate() |
RefreshAll() |
MuiRoot::InvalidateRect(MuiRect) |
RefreshArea(MuiRect) |
MuiElement::InvalidateSelf() |
Refresh() |
MuiElement::RequestLayoutSelf() |
Relayout() |
Refresh the whole UI
Use a full refresh when a broad area changed or you do not know the exact area that needs to update.
g_ui.RefreshAll();
A full refresh is simple and safe, but it can redraw more than needed.
Refresh a known area only
When you know exactly which rectangle changed, ask ModernUI to redraw only that area:
MuiRect r;
r.x=20.0;
r.y=40.0;
r.w=160.0;
r.h=40.0;
g_ui.RefreshArea(r);
Multiple RefreshArea calls in the same frame are combined into one redraw region for that frame. Internally this is sometimes called a dirty rectangle: it is just the area marked as needing redraw.
Skipping controls that did not change
During a partial refresh, ModernUI can skip drawing controls whose paint area does not overlap the area you asked to redraw.
This means:
- controls completely outside the refresh area are skipped
- invisible controls are skipped
- a full refresh still walks the entire tree
- if the refresh area is unknown, ModernUI plays it safe and redraws everything
Advanced controls describe their drawing area using PaintBounds() (the layout rectangle plus a small allowance for effects such as focus rings, glow, or shadows). Internally this is sometimes called partial paint culling. You only need to think about it when writing a custom control that draws outside its normal rectangle.
Helper functions (advanced)
For custom controls, Root.mqh exposes a few helpers:
MuiInvalidateElementBounds(MuiRoot*,MuiElement*,inflateLogical);
MuiInvalidateElementsBounds(MuiRoot*,MuiElement*,MuiElement*,inflate);
MuiShouldSkipPartialChildPaint(MuiRoot &root,MuiElement *child);
These are mostly useful inside controls and advanced custom elements.
What still causes a full redraw
A full redraw is still expected for:
- first frame
- explicit
g_ui.RefreshAll()(formerlyInvalidate()) - layout changes
Relayout()(formerlyRequestLayout())- theme changes
- scale changes
- canvas resize
SetRoot- unknown or empty refresh area
- modal overlay changes that cover large chart areas
A full redraw is not always bad. It is the safe path when geometry or broad visual state changes.
Layout vs paint
Not all changes are equal.
| Change | Use |
|---|---|
| Text value changes without geometry impact | Refresh() on the control, or g_ui.RefreshArea(...) |
| Colour change | Refresh() |
| Hover/press visual change | targeted refresh where possible |
| Child added/removed | Relayout() |
| Font size, padding or row height changes | Relayout() |
| Theme/scale changes | full layout/paint path |
Do not refresh twice after a layout
If you call Relayout(), do not also call RefreshAll() unless you have a specific reason.
Relayout() already schedules the redraw it needs.
panel.Relayout();
g_ui.RefreshAll();
Prefer:
panel.Relayout();
Pixel snapping and chrome
ModernUI performs final paint snapping for common chrome so borders, fills, separators, slider thumbs, and tab segment dividers map to consistent physical pixel rectangles. Layout and generic hit testing remain in logical coordinates.
This split avoids changing control behaviour while reducing one-pixel gaps that can appear at non-integer scale factors.
Selective anti-aliasing
Small rounded chrome can use selective anti-aliasing when a radius is set. Square controls keep the fast square path. Large panels, tables, and broad containers are not globally anti-aliased by default.
This keeps rounded buttons, sliders, badges, inputs, and similar small elements smoother without turning every repaint into an expensive full-surface smoothing pass.
Custom controls and PaintBounds
If a custom control draws outside its layout rectangle, override or adjust PaintBounds().
Examples where this matters:
- large shadows
- glow effects
- popups painted outside normal bounds
- chart strokes outside
m_rect
If PaintBounds() is too small, a partial refresh can leave stale pixels until the next full refresh.
Common mistakes
Calling RefreshAll() for every small change
A full refresh is safe, but a targeted refresh is better for frequent small visual changes.
Calling Relayout() for value-only changes
Only relayout when geometry, child count, or preferred size changed.
Forgetting that the first frame is full
The first frame is expected to redraw the full tree.
Related pages
- Performance counters
- Best practices
- ModernUI showcase demo — large scrollable UI surface