Skip to content
ModernUI A DaneTrades developer library

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.

UI build fragment
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:

UI build fragment
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:

Reference excerpt
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() (formerly Invalidate())
  • layout changes
  • Relayout() (formerly RequestLayout())
  • 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.

Incorrect
panel.Relayout();
g_ui.RefreshAll();

Prefer:

Correct
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