Skip to content

Bidirectional Layout#3303

Open
hojjatabdollahi wants to merge 6 commits intoiced-rs:masterfrom
hojjatabdollahi:hojjat/rtl-layout-root
Open

Bidirectional Layout#3303
hojjatabdollahi wants to merge 6 commits intoiced-rs:masterfrom
hojjatabdollahi:hojjat/rtl-layout-root

Conversation

@hojjatabdollahi
Copy link
Copy Markdown
Contributor

@hojjatabdollahi hojjatabdollahi commented Apr 9, 2026

I have completed implementing RTL layout in Iced. But I have extracted a smaller piece of it with a small example in this PR to make reviewing and feedback easier.

Design

A Direction primitive is defined and added to Settings. It is then passed down to all children via Limits.
The direction for a widget can be explicitly set, or it can inherit it from its parent. You may want a part of your app to always be drawn in the same direction as you're designing for example if you have two buttons that say "<west, east>".

There is no Auto in Direction, just LTR and RTL. The app developer can decide based on the translated language, or some other factor what the direction should be (whoever is doing i18n can decide). So, Iced doesn't need to automatically detect and change the direction.

Request

The process of updating all widgets to support the direction can be done over time and widget by widget. However, the main thing that I need your input on is the Direction primitive and how to pass it down the tree? Is this the best approach for Iced? Is the design sound? I will be working on integrating this into libcosmic, but before I do that I want to get your opinion and make sure the design is solid on you're onboard, or ideally get this merged into Iced first.

In this PR I have applied the direction to row and toggler and added a small example that shows how changing the direction in Settings would change the alignment and the order of the widgets.

Here's a screenshot of the small example:

image

Note that the direction of the toggler widget is also mirrored. more info

Note: if you don't set the direction in the settings, everything should render exactly as before. If this feature is done right, people who don't need RTL won't notice anything!

Here's our discussion in zulip.

Here's how you set this in GTK.

@hojjatabdollahi hojjatabdollahi force-pushed the hojjat/rtl-layout-root branch 2 times, most recently from a0c1275 to 89ec8ea Compare April 9, 2026 01:51
@hojjatabdollahi hojjatabdollahi force-pushed the hojjat/rtl-layout-root branch 3 times, most recently from e45bf37 to 42cff5f Compare April 16, 2026 22:12
Copy link
Copy Markdown
Member

@hecrj hecrj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure adding Direction to Limits makes sense conceptually.

Maybe it could be a new argument to Widget::layout and Overlay::layout instead? We are not afraid of breaking changes here.

@hojjatabdollahi hojjatabdollahi force-pushed the hojjat/rtl-layout-root branch from 42cff5f to dd5c7b8 Compare April 17, 2026 06:43
@hojjatabdollahi
Copy link
Copy Markdown
Contributor Author

hojjatabdollahi commented Apr 17, 2026

@hecrj Thank you for your feedback.

I agree, passing the direction as a separate field makes more sense. And the good thing about it being a breaking change is that more developers may actually handle it and make their widgets bidirectional.

Updated design

Direction is no longer stored on Limits. It is passed as an additional argument to layout().

Each widget has to choose whether to care about it (e.g. row, column, toggler) or simply forward it down to its children (e.g. button). UserInterface::build still takes the root Direction (coming from Settings).

Overriding the direction for a subtree

To avoid adding a .direction(...) setter everywhere, I introduced a new Directional widget. It is a thin wrapper that ignores the direction it receives from its parent and forwards its own to the wrapped content. We can still expose .direction() setters for some widgets if we want.

Example

I renamed my toy example to directional and now it shows both directions side by side using Directional widget. Even though I had to touch many files, currently still row and toggler are the only widgets that actually react to Direction.

image

Please let me know what you think of the new design. If you're OK with it, I can start working on adding RTL support to more widgets.

And I assume that you're OK with my decision to not include a Direction::Auto that automatically sets the direction based on system Locale, and leave that to the App developers or users of Iced (the person handling i18n down stream).

@hojjatabdollahi hojjatabdollahi force-pushed the hojjat/rtl-layout-root branch 2 times, most recently from 9d3e3a2 to 00e3993 Compare April 17, 2026 15:28
@hojjatabdollahi hojjatabdollahi changed the title (RFC) Bidirectional Layout Bidirectional Layout Apr 17, 2026
@hojjatabdollahi
Copy link
Copy Markdown
Contributor Author

hojjatabdollahi commented Apr 18, 2026

Since Direction is already pretty loaded (editor::Direction, window::Direction, scrollable::Direction, pane_grid::Direction), I'm thinking to rename the enum to LayoutDirection.

Here's what other toolkits call it:

  • GTK: GTKTextDirection
  • Qt: LayoutDirection
  • WPF/WinUI/...: FlowDirection
  • SwiftUI: layoutDirection

I think LayoutDirection is the cleanest option, and makes the most sense. Any suggestions?

@hecrj
Copy link
Copy Markdown
Member

hecrj commented Apr 20, 2026

Just Direction in the root should be fine. Worst case, we move it inside the layout module; but since we don't expose that module unless advanced is enabled, the root is fine.

@hojjatabdollahi hojjatabdollahi force-pushed the hojjat/rtl-layout-root branch 4 times, most recently from f19e578 to 5d026b2 Compare April 20, 2026 19:23
@hojjatabdollahi hojjatabdollahi force-pushed the hojjat/rtl-layout-root branch from 5d026b2 to a2e4be9 Compare April 20, 2026 19:49
@hojjatabdollahi
Copy link
Copy Markdown
Contributor Author

I implemented support for some more widgets. Should I try to do all widgets? Or should we do that over time in separate PRs for reviewing purposes?

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants