pub struct Model {
pub paginator_type: Type,
pub page: usize,
pub per_page: usize,
pub total_pages: usize,
pub active_dot: String,
pub inactive_dot: String,
pub arabic_format: String,
pub keymap: PaginatorKeyMap,
}Expand description
A paginator model for handling pagination state and rendering.
This component manages pagination state including current page, total pages, and pagination display style. It can render pagination in two modes:
- Arabic: Shows page numbers (e.g., “3/10”)
- Dots: Shows dots representing pages (e.g., “○ ○ ● ○ ○”)
The paginator handles key bindings for navigation and provides helper methods for calculating slice bounds and page information.
§Examples
§Basic Usage
use bubbletea_widgets::paginator::{Model, Type};
let mut paginator = Model::new()
.with_per_page(10)
.with_total_items(150); // Creates 15 pages
assert_eq!(paginator.total_pages, 15);
assert!(paginator.on_first_page());
paginator.next_page();
assert_eq!(paginator.page, 1);§Different Display Types
use bubbletea_widgets::paginator::{Model, Type};
let mut paginator = Model::new()
.with_total_items(50)
.with_per_page(10);
// Arabic mode (default): "1/5"
paginator.paginator_type = Type::Arabic;
let arabic_view = paginator.view();
// Dots mode: "● ○ ○ ○ ○"
paginator.paginator_type = Type::Dots;
let dots_view = paginator.view();§Integration with bubbletea-rs
use bubbletea_widgets::paginator::Model as Paginator;
use bubbletea_rs::{Model, Cmd, Msg};
struct App {
paginator: Paginator,
items: Vec<String>,
}
impl Model for App {
fn init() -> (Self, Option<Cmd>) {
let items: Vec<String> = (1..=100).map(|i| format!("Item {}", i)).collect();
let paginator = Paginator::new()
.with_per_page(10)
.with_total_items(items.len());
(Self { paginator, items }, None)
}
fn update(&mut self, msg: Msg) -> Option<Cmd> {
self.paginator.update(&msg);
None
}
fn view(&self) -> String {
let (start, end) = self.paginator.get_slice_bounds(self.items.len());
let page_items: Vec<String> = self.items[start..end].to_vec();
format!(
"Items:\n{}\n\nPage: {}",
page_items.join("\n"),
self.paginator.view()
)
}
}Fields§
§paginator_type: TypeThe type of pagination to display (Dots or Arabic).
page: usizeThe current page.
per_page: usizeThe number of items per page.
total_pages: usizeThe total number of pages.
active_dot: StringThe character to use for the active page in Dots mode.
inactive_dot: StringThe character to use for inactive pages in Dots mode.
arabic_format: StringThe format string for Arabic mode (e.g., “%d/%d”).
keymap: PaginatorKeyMapKey bindings.
Implementations§
Source§impl Model
impl Model
Sourcepub fn new() -> Self
pub fn new() -> Self
Creates a new paginator model with default settings.
This is equivalent to calling Model::default() but provides a more
conventional constructor-style API.
§Examples
use bubbletea_widgets::paginator::Model;
let paginator = Model::new();
assert_eq!(paginator.page, 0);
assert_eq!(paginator.total_pages, 1);Sourcepub fn with_total_items(self, items: usize) -> Self
pub fn with_total_items(self, items: usize) -> Self
Sets the total number of items and calculates total pages (builder pattern).
This method automatically calculates the total number of pages based on
the total items and the current per_page setting. If the current page
becomes out of bounds, it will be adjusted to the last valid page.
§Arguments
items- The total number of items to paginate
§Examples
use bubbletea_widgets::paginator::Model;
let paginator = Model::new()
.with_per_page(10)
.with_total_items(95); // Will create 10 pages (95/10 = 9.5 -> 10)
assert_eq!(paginator.total_pages, 10);Sourcepub fn with_per_page(self, per_page: usize) -> Self
pub fn with_per_page(self, per_page: usize) -> Self
Sets the number of items per page (builder pattern).
The minimum value is 1; any value less than 1 will be clamped to 1.
This setting affects how total pages are calculated when using
set_total_items() or with_total_items().
§Arguments
per_page- Number of items to display per page (minimum 1)
§Examples
use bubbletea_widgets::paginator::Model;
let paginator = Model::new()
.with_per_page(25)
.with_total_items(100); // Will create 4 pages
assert_eq!(paginator.per_page, 25);
assert_eq!(paginator.total_pages, 4);
// Values less than 1 are clamped to 1
let clamped = Model::new().with_per_page(0);
assert_eq!(clamped.per_page, 1);Sourcepub fn set_per_page(&mut self, per_page: usize)
pub fn set_per_page(&mut self, per_page: usize)
Sets the number of items per page (mutable version).
The minimum value is 1; any value less than 1 will be clamped to 1. This method modifies the paginator in place.
§Arguments
per_page- Number of items to display per page (minimum 1)
§Examples
use bubbletea_widgets::paginator::Model;
let mut paginator = Model::new();
paginator.set_per_page(15);
assert_eq!(paginator.per_page, 15);
// Values less than 1 are clamped to 1
paginator.set_per_page(0);
assert_eq!(paginator.per_page, 1);Sourcepub fn with_active_dot(self, dot: &str) -> Self
pub fn with_active_dot(self, dot: &str) -> Self
Sourcepub fn with_inactive_dot(self, dot: &str) -> Self
pub fn with_inactive_dot(self, dot: &str) -> Self
Sourcepub fn set_active_dot(&mut self, dot: &str)
pub fn set_active_dot(&mut self, dot: &str)
Sourcepub fn set_inactive_dot(&mut self, dot: &str)
pub fn set_inactive_dot(&mut self, dot: &str)
Sourcepub fn set_total_pages(&mut self, pages: usize)
pub fn set_total_pages(&mut self, pages: usize)
Sets the total number of pages directly.
The minimum value is 1; any value less than 1 will be clamped to 1. If the current page becomes out of bounds after setting the total pages, it will be adjusted to the last valid page.
Note: This method sets pages directly. If you want to calculate pages
based on total items, use set_total_items() instead.
§Arguments
pages- The total number of pages (minimum 1)
§Examples
use bubbletea_widgets::paginator::Model;
let mut paginator = Model::new();
paginator.set_total_pages(10);
assert_eq!(paginator.total_pages, 10);
// If current page is out of bounds, it gets adjusted
paginator.page = 15; // Out of bounds
paginator.set_total_pages(5);
assert_eq!(paginator.page, 4); // Adjusted to last page (0-indexed)Sourcepub fn set_total_items(&mut self, items: usize)
pub fn set_total_items(&mut self, items: usize)
Calculates and sets the total number of pages based on the total items.
This method divides the total number of items by the current per_page
setting to calculate the total pages. The result is always at least 1,
even for 0 items. If the current page becomes out of bounds after
recalculation, it will be adjusted to the last valid page.
§Arguments
items- The total number of items to paginate
§Examples
use bubbletea_widgets::paginator::Model;
let mut paginator = Model::new().with_per_page(10);
// 95 items with 10 per page = 10 pages (95/10 = 9.5 -> 10)
paginator.set_total_items(95);
assert_eq!(paginator.total_pages, 10);
// 0 items still results in 1 page minimum
paginator.set_total_items(0);
assert_eq!(paginator.total_pages, 1);
// Exact division
paginator.set_total_items(100);
assert_eq!(paginator.total_pages, 10);Sourcepub fn items_on_page(&self, total_items: usize) -> usize
pub fn items_on_page(&self, total_items: usize) -> usize
Returns the number of items on the current page.
This method calculates how many items are actually present on the
current page, which may be less than per_page on the last page
or when there are fewer total items than per_page.
§Arguments
total_items- The total number of items being paginated
§Returns
The number of items on the current page, or 0 if there are no items.
§Examples
use bubbletea_widgets::paginator::Model;
let mut paginator = Model::new().with_per_page(10);
// Full page
assert_eq!(paginator.items_on_page(100), 10);
// Partial last page
paginator.page = 9; // Last page (0-indexed)
assert_eq!(paginator.items_on_page(95), 5); // Only 5 items on page 10
// No items
assert_eq!(paginator.items_on_page(0), 0);Sourcepub fn get_slice_bounds(&self, length: usize) -> (usize, usize)
pub fn get_slice_bounds(&self, length: usize) -> (usize, usize)
Calculates slice bounds for the current page.
This is a helper function for paginating slices. Given the total length of your data, it returns the start and end indices for the current page. The returned bounds can be used directly with slice notation.
§Arguments
length- The total length of the data being paginated
§Returns
A tuple (start, end) where:
startis the inclusive start index for the current pageendis the exclusive end index for the current page
§Examples
use bubbletea_widgets::paginator::Model;
let items: Vec<i32> = (1..=100).collect();
let mut paginator = Model::new().with_per_page(10);
// First page (0)
let (start, end) = paginator.get_slice_bounds(items.len());
assert_eq!((start, end), (0, 10));
let page_items = &items[start..end]; // Items 1-10
// Third page (2)
paginator.page = 2;
let (start, end) = paginator.get_slice_bounds(items.len());
assert_eq!((start, end), (20, 30));
let page_items = &items[start..end]; // Items 21-30Sourcepub fn start_index_end_index(&self) -> (usize, usize)
pub fn start_index_end_index(&self) -> (usize, usize)
Returns slice bounds assuming maximum possible data length.
This is a convenience method that calls get_slice_bounds() with
the maximum possible data length (per_page * total_pages). It’s
useful when you know your data exactly fills the pagination structure.
§Returns
A tuple (start, end) representing slice bounds for the current page.
§Examples
use bubbletea_widgets::paginator::Model;
let mut paginator = Model::new()
.with_per_page(10)
.with_total_items(100); // Exactly 10 pages
paginator.page = 3;
let (start, end) = paginator.start_index_end_index();
assert_eq!((start, end), (30, 40));Sourcepub fn prev_page(&mut self)
pub fn prev_page(&mut self)
Navigates to the previous page.
If the paginator is already on the first page (page 0), this method has no effect. The page number will not go below 0.
§Examples
use bubbletea_widgets::paginator::Model;
let mut paginator = Model::new().with_per_page(10).with_total_items(100);
paginator.page = 5;
paginator.prev_page();
assert_eq!(paginator.page, 4);
// Won't go below 0
paginator.page = 0;
paginator.prev_page();
assert_eq!(paginator.page, 0);Sourcepub fn next_page(&mut self)
pub fn next_page(&mut self)
Navigates to the next page.
If the paginator is already on the last page, this method has no effect.
The page number will not exceed total_pages - 1.
§Examples
use bubbletea_widgets::paginator::Model;
let mut paginator = Model::new().with_per_page(10).with_total_items(100);
// total_pages = 10, so last page is 9 (0-indexed)
paginator.page = 5;
paginator.next_page();
assert_eq!(paginator.page, 6);
// Won't go beyond last page
paginator.page = 8; // Second to last page
paginator.next_page();
assert_eq!(paginator.page, 9); // Should go to last page (9 is the last valid page)
paginator.next_page();
assert_eq!(paginator.page, 9); // Should stay at last pageSourcepub fn on_first_page(&self) -> bool
pub fn on_first_page(&self) -> bool
Returns true if the paginator is on the first page.
The first page is always page 0 in the 0-indexed pagination system.
§Examples
use bubbletea_widgets::paginator::Model;
let mut paginator = Model::new().with_per_page(10).with_total_items(100);
assert!(paginator.on_first_page());
paginator.next_page();
assert!(!paginator.on_first_page());Sourcepub fn on_last_page(&self) -> bool
pub fn on_last_page(&self) -> bool
Returns true if the paginator is on the last page.
The last page is total_pages - 1 in the 0-indexed pagination system.
§Examples
use bubbletea_widgets::paginator::Model;
let mut paginator = Model::new().with_per_page(10).with_total_items(90);
// Creates 9 pages (0-8), so last page is 8
assert!(!paginator.on_last_page());
paginator.page = 8; // Last page
assert!(paginator.on_last_page());Sourcepub fn update(&mut self, msg: &Msg)
pub fn update(&mut self, msg: &Msg)
Updates the paginator based on received messages.
This method should be called from your application’s update() method
to handle pagination key presses. It automatically responds to the
configured key bindings for next/previous page navigation.
§Arguments
msg- The message to process, typically containing key press events
§Examples
use bubbletea_widgets::paginator::Model as Paginator;
use bubbletea_rs::{Model, Msg};
struct App {
paginator: Paginator,
}
impl Model for App {
fn update(&mut self, msg: Msg) -> Option<bubbletea_rs::Cmd> {
// Forward messages to paginator
self.paginator.update(&msg);
None
}
// ... other methods
}Sourcepub fn view(&self) -> String
pub fn view(&self) -> String
Renders the paginator as a string.
The output format depends on the paginator_type setting:
- Arabic: Shows “current/total” (e.g., “3/10”)
- Dots: Shows dots with active page highlighted (e.g., “○ ○ ● ○ ○”)
§Returns
A string representation of the current pagination state.
§Examples
use bubbletea_widgets::paginator::{Model, Type};
let mut paginator = Model::new().with_per_page(10).with_total_items(50);
// Creates 5 pages, currently on page 0
// Arabic mode (default)
paginator.paginator_type = Type::Arabic;
assert_eq!(paginator.view(), "1/5"); // 1-indexed for display
// Dots mode
paginator.paginator_type = Type::Dots;
assert_eq!(paginator.view(), "•○○○○"); // Active page shows filled bullet, others are hollow
// Move to page 2
paginator.page = 2;
assert_eq!(paginator.view(), "○○•○○"); // Third bullet filled (active page), others hollowTrait Implementations§
Source§impl Default for Model
impl Default for Model
Source§fn default() -> Self
fn default() -> Self
Creates a paginator with default settings.
Default configuration:
- Type: Arabic (“1/5” style)
- Current page: 0 (first page)
- Items per page: 1
- Total pages: 1
- Active dot: “•” (for dots mode)
- Inactive dot: “○” (for dots mode)
- Arabic format: “%d/%d” (current/total)
- Default key bindings
§Examples
use bubbletea_widgets::paginator::{Model, Type};
let paginator = Model::default();
assert_eq!(paginator.paginator_type, Type::Arabic);
assert_eq!(paginator.page, 0);
assert_eq!(paginator.per_page, 1);
assert_eq!(paginator.total_pages, 1);Auto Trait Implementations§
impl Freeze for Model
impl RefUnwindSafe for Model
impl Send for Model
impl Sync for Model
impl Unpin for Model
impl UnwindSafe for Model
Blanket Implementations§
Source§impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for Swhere
T: Real + Zero + Arithmetics + Clone,
Swp: WhitePoint<T>,
Dwp: WhitePoint<T>,
D: AdaptFrom<S, Swp, Dwp, T>,
impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for Swhere
T: Real + Zero + Arithmetics + Clone,
Swp: WhitePoint<T>,
Dwp: WhitePoint<T>,
D: AdaptFrom<S, Swp, Dwp, T>,
Source§fn adapt_into_using<M>(self, method: M) -> Dwhere
M: TransformMatrix<T>,
fn adapt_into_using<M>(self, method: M) -> Dwhere
M: TransformMatrix<T>,
Source§fn adapt_into(self) -> D
fn adapt_into(self) -> D
Source§impl<T, C> ArraysFrom<C> for Twhere
C: IntoArrays<T>,
impl<T, C> ArraysFrom<C> for Twhere
C: IntoArrays<T>,
Source§fn arrays_from(colors: C) -> T
fn arrays_from(colors: C) -> T
Source§impl<T, C> ArraysInto<C> for Twhere
C: FromArrays<T>,
impl<T, C> ArraysInto<C> for Twhere
C: FromArrays<T>,
Source§fn arrays_into(self) -> C
fn arrays_into(self) -> C
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<WpParam, T, U> Cam16IntoUnclamped<WpParam, T> for Uwhere
T: FromCam16Unclamped<WpParam, U>,
impl<WpParam, T, U> Cam16IntoUnclamped<WpParam, T> for Uwhere
T: FromCam16Unclamped<WpParam, U>,
Source§type Scalar = <T as FromCam16Unclamped<WpParam, U>>::Scalar
type Scalar = <T as FromCam16Unclamped<WpParam, U>>::Scalar
parameters when converting.Source§fn cam16_into_unclamped(
self,
parameters: BakedParameters<WpParam, <U as Cam16IntoUnclamped<WpParam, T>>::Scalar>,
) -> T
fn cam16_into_unclamped( self, parameters: BakedParameters<WpParam, <U as Cam16IntoUnclamped<WpParam, T>>::Scalar>, ) -> T
self into C, using the provided parameters.Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T, C> ComponentsFrom<C> for Twhere
C: IntoComponents<T>,
impl<T, C> ComponentsFrom<C> for Twhere
C: IntoComponents<T>,
Source§fn components_from(colors: C) -> T
fn components_from(colors: C) -> T
Source§impl<T> FromAngle<T> for T
impl<T> FromAngle<T> for T
Source§fn from_angle(angle: T) -> T
fn from_angle(angle: T) -> T
angle.Source§impl<T, U> FromStimulus<U> for Twhere
U: IntoStimulus<T>,
impl<T, U> FromStimulus<U> for Twhere
U: IntoStimulus<T>,
Source§fn from_stimulus(other: U) -> T
fn from_stimulus(other: U) -> T
other into Self, while performing the appropriate scaling,
rounding and clamping.Source§impl<T, U> IntoAngle<U> for Twhere
U: FromAngle<T>,
impl<T, U> IntoAngle<U> for Twhere
U: FromAngle<T>,
Source§fn into_angle(self) -> U
fn into_angle(self) -> U
T.Source§impl<WpParam, T, U> IntoCam16Unclamped<WpParam, T> for Uwhere
T: Cam16FromUnclamped<WpParam, U>,
impl<WpParam, T, U> IntoCam16Unclamped<WpParam, T> for Uwhere
T: Cam16FromUnclamped<WpParam, U>,
Source§type Scalar = <T as Cam16FromUnclamped<WpParam, U>>::Scalar
type Scalar = <T as Cam16FromUnclamped<WpParam, U>>::Scalar
parameters when converting.Source§fn into_cam16_unclamped(
self,
parameters: BakedParameters<WpParam, <U as IntoCam16Unclamped<WpParam, T>>::Scalar>,
) -> T
fn into_cam16_unclamped( self, parameters: BakedParameters<WpParam, <U as IntoCam16Unclamped<WpParam, T>>::Scalar>, ) -> T
self into C, using the provided parameters.Source§impl<T, U> IntoColor<U> for Twhere
U: FromColor<T>,
impl<T, U> IntoColor<U> for Twhere
U: FromColor<T>,
Source§fn into_color(self) -> U
fn into_color(self) -> U
Source§impl<T, U> IntoColorUnclamped<U> for Twhere
U: FromColorUnclamped<T>,
impl<T, U> IntoColorUnclamped<U> for Twhere
U: FromColorUnclamped<T>,
Source§fn into_color_unclamped(self) -> U
fn into_color_unclamped(self) -> U
Source§impl<T> IntoStimulus<T> for T
impl<T> IntoStimulus<T> for T
Source§fn into_stimulus(self) -> T
fn into_stimulus(self) -> T
self into T, while performing the appropriate scaling,
rounding and clamping.Source§impl<T, C> TryComponentsInto<C> for Twhere
C: TryFromComponents<T>,
impl<T, C> TryComponentsInto<C> for Twhere
C: TryFromComponents<T>,
Source§type Error = <C as TryFromComponents<T>>::Error
type Error = <C as TryFromComponents<T>>::Error
try_into_colors fails to cast.Source§fn try_components_into(self) -> Result<C, <T as TryComponentsInto<C>>::Error>
fn try_components_into(self) -> Result<C, <T as TryComponentsInto<C>>::Error>
Source§impl<T, U> TryIntoColor<U> for Twhere
U: TryFromColor<T>,
impl<T, U> TryIntoColor<U> for Twhere
U: TryFromColor<T>,
Source§fn try_into_color(self) -> Result<U, OutOfBounds<U>>
fn try_into_color(self) -> Result<U, OutOfBounds<U>>
OutOfBounds error is returned which contains
the unclamped color. Read more