Skip to content

Add Pagination widget.#1706

Merged
xStrom merged 2 commits intolinebender:mainfrom
xStrom:pagination
Apr 2, 2026
Merged

Add Pagination widget.#1706
xStrom merged 2 commits intolinebender:mainfrom
xStrom:pagination

Conversation

@xStrom
Copy link
Copy Markdown
Member

@xStrom xStrom commented Mar 31, 2026

The Pagination widget is technically new ground for Masonry, as it composes multiple other widgets (Button in this case) and then captures and translates their actions (ButtonPress) into its own actions (PageChanged). This builds on top of the new action pass added in #1677.

In addition to being able to set the total page count and currently active page index, it's also possible to configure how many pagination buttons should be shown in total and at each of the extremes. Changes to any of these values or any user input that triggers a button press will then execute sync_buttons which is a mini-reactivity engine inside of Pagination that makes sure that there is a correct number of child Button widgets and that they all have correct page numbers on them. These child widgets are lazily created and when no longer needed, stashing is preferred. So in the case where there are 10 buttons max but only 3 pages exist, only 3 button widgets will be created. Then, let's say a search filter is modified and now there are suddenly 30 pages. The remaining 7 buttons will be created, reaching the total max of 10 buttons. If the filter is modified again and there's only 1 page of results now, 9 of the buttons will be stashed. Only when the maximum number of buttons is reduced to say 5 will Pagination remove the excess buttons.

Styling is intentionally postponed until the properties system gains more features, e.g. #1691. Until then, it's just a concated list of buttons with their default style.


You can try it out in the gallery via cargo run --example gallery.

pagination

@xStrom xStrom added masonry Issues relating to the Masonry widget layer needs review Needs review before proceeding. labels Mar 31, 2026
Copy link
Copy Markdown
Contributor

@jaredoconnell jaredoconnell left a comment

Choose a reason for hiding this comment

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

I haven't reviewed it deeply enough to approve it, but from my once-over and testing, the behavior looks pretty good quality already. The only oddity due to how it's implemented is that the button you press is the one that stays active, despite the number changing. The pro of this behavior is you can hit enter again to skip ahead the same amount again, until it stops shifting because it gets to the end of the range. But this behavior isn't consistent, and is therefore less intuitive.

@xStrom
Copy link
Copy Markdown
Member Author

xStrom commented Mar 31, 2026

Yes, I also noticed that focus behavior during my testing. The problem is that Masonry currently only allows changing the focus target from the widget's own event handling. So the host Pagination widget can't change the focus to a specific button. Limitation of Masonry that I think should probably be changed.

Comment on lines +402 to +412
/// Collections of context methods required to sync buttons.
trait SyncCtx {
fn children_changed(&mut self);
fn set_stashed(&mut self, child: &mut WidgetPod<impl Widget + ?Sized>, stashed: bool);
fn remove_child(&mut self, child: WidgetPod<impl Widget + ?Sized>);
fn mutate_child_later<W: Widget + FromDynWidget + ?Sized>(
&mut self,
child: &mut WidgetPod<W>,
f: impl FnOnce(WidgetMut<'_, W>) + Send + 'static,
);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm really cautious of adding more traits to Masonry, though this one is at least private.

An alternative I'd recommend is using MutateCtx::update_mut instead and have sync_buttons take &mut UpdateCtx. You'd have to add a similar method to ActionCtx.

Currently MutateCtx::update_mut is private, and I think the reason is because making public would mean we'd commit to having MutateCtx (and ActionCtx, and probably EventCtx) be a superset of UpdateCtx, basically locking in "you can do everything during the mutate pass".

This is probably worth a Zulip discussion, and in the meantime this solution is fine.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yeah I only added the trait out of necessity, but the alternative you mention could work as well. As would having official traits for the context methods. It's a bigger issue than this PR here though and not high priority, so I'll open a Zulip thread for it.

@xStrom xStrom removed the needs review Needs review before proceeding. label Apr 2, 2026
@xStrom xStrom added this pull request to the merge queue Apr 2, 2026
Merged via the queue into linebender:main with commit 0f5878d Apr 2, 2026
17 checks passed
@xStrom xStrom deleted the pagination branch April 2, 2026 15:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

masonry Issues relating to the Masonry widget layer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants