UI direction and right-to-left layouts

eepp shapes and renders bidirectional text with HarfBuzz and SheenBidi. On top of that, every widget has a UI direction that decides how logical UI concepts resolve to physical sides. A layout authored with logical properties works unchanged in left-to-right (LTR) and right-to-left (RTL) applications.

The central rule:

Direction changes the meaning of logical UI concepts; it never changes the meaning of explicitly physical concepts.

Logical (direction-sensitive)

Physical (never mirrored)

Control RTL behavior ===================== ==================================================================================================================== CheckBox, RadioButton Indicator at the right, text before it PushButton Menu items Shortcut at the inline-end (left); icon gutter at the right Submenus Arrow at the left, mirrored; the submenu prefers opening to the left and still flips when it does not fit MenuBar First menu at the right; menus hang from the button’s right edge; Left/Right keys move to the visually adjacent menu TabWidget Tab 0 at the right; indexes, next/previous and drag reordering stay logical TreeView Indentation and expander at the right; expanders mirrored; cells default to TableView, ListView Cells default to Window chrome Title buttons mirrored to the left (custom eepp decorations only) ===================== ====================================================================================================================

The default themes use logical properties where spacing means “before” or “after”. Application themes should do the same for directional spacing.

Directional icons

Mirroring is opt-in: arbitrary images, media controls and code never mirror. Framework-owned affordances (submenu arrows, tree expanders) mirror automatically. Applications can opt in for back/forward style icons with setMirrorOnRTL( true ) or the mirror-on-rtl: true CSS property.

Current limitations

  • dir="auto" and unicode-bidi are not modeled; auto behaves as inherit.

  • Vertical writing modes and logical border/inset properties are not implemented.

  • Scrollbars keep their physical side and scroll offsets stay physical.

  • Table column order and native window decorations are not mirrored.

  • Inline box decorations (padding/borders of inline elements split across reordered RTL items) use their logical start/end only approximately.

  • Inline bidi placement operates at item granularity. Full paragraph bidi across mixed-direction styling boundaries and wrapped-line context is not yet modeled.

See src/examples/ui_rtl/ui_rtl.cpp for a runnable example that toggles the direction at runtime.