Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/auto_reload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub struct AutoReload {
pub reload_after: Option<u32>,
pub reload_count: u32,
}

impl AutoReload {
/// Increase the current reload count and return bool based on if it is equal or above the count it is
/// supposed to reload at
Expand Down Expand Up @@ -55,6 +56,13 @@ where
/// occur at a rate of 1000 rows per second, a `count` between 500 and 1000 may offer the best balance between
/// performance and up-to-date display.
///
/// # When to use:
/// This can be useful when streaming table data from a source and it gets updated
/// frequently. If for example 1k rows are added/modified per second, it might be a good idea
/// to set the count at 5k so it auto reloads the table every 5 seconds. This
/// allows not having to keep track of when to reload the table and reloading once at the end
/// of stream can result in the table showing the latest data.
///
/// # Example:
/// ```rust,ignore
/// let table = SelectableTable::new(vec![col1, col2, col3])
Expand Down
1 change: 0 additions & 1 deletion src/auto_scroll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ impl AutoScroll {
if let Some(loc) = pointer {
let pointer_y = loc.y;

// Min gets a bit more space as the header is along the way
let min_y = max_rect.min.y + self.distance_from_min;
let max_y = max_rect.max.y - self.distance_from_max;

Expand Down
37 changes: 31 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,9 @@ where
add_serial_column: bool,
/// The row height for the table, defaults to 25.0
row_height: f32,
/// The header height for the table, defaults to 20.0
header_height: f32,

/// The matcher used for fuzzy searching
#[cfg(feature = "fuzzy-matching")]
matcher: Matcher,
Expand Down Expand Up @@ -309,6 +312,7 @@ where
config: Conf::default(),
add_serial_column: false,
row_height: 25.0,
header_height: 20.0,
#[cfg(feature = "fuzzy-matching")]
matcher: Matcher::default(),
no_ctrl_a_capture: false,
Expand Down Expand Up @@ -347,7 +351,8 @@ where
self
}

/// Clears all rows from the table, including the displayed ones
/// Clears all rows from the table, including the displayed ones. No need for any additional
/// call to update the UI.
///
/// # Example:
/// ```rust,ignore
Expand All @@ -365,7 +370,8 @@ where
///
/// # Parameters:
/// - `ui`: The UI context where the table will be rendered.
/// - `table_builder`: A closure that receives and modifies the `TableBuilder`.
/// - A closure that provides and allows modification of `TableBuilder`. Build your own table
/// and return it.
///
/// # Example:
/// ```rust,ignore
Expand Down Expand Up @@ -408,7 +414,7 @@ where
}

let output = table
.header(20.0, |header| {
.header(self.header_height, |header| {
self.build_head(header);
})
.body(|body| {
Expand Down Expand Up @@ -437,7 +443,7 @@ where
}

let output = table
.header(20.0, |header| {
.header(self.header_height, |header| {
self.build_head(header);
})
.body(|body| {
Expand Down Expand Up @@ -701,9 +707,9 @@ where
&self.rows
}

/// Adds a serial column to the table.
/// Adds a serial column UI to the table.
///
/// The serial column is automatically generated and displayed at the very left of the table.
/// The serial column UI is automatically generated and displayed at the very left of the table.
/// It shows the row number (starting from 1) for each row.
///
/// # Returns:
Expand Down Expand Up @@ -755,6 +761,25 @@ where
self
}

/// Sets the height of the header in the table. Defaults to 20.0.
///
/// # Parameters:
/// - `height`: The desired height for the header
///
/// # Returns:
/// - `Self`: The modified table with the specified header height applied.
///
/// # Example:
/// ```rust,ignore
/// let table = SelectableTable::new(vec![col1, col2, col3])
/// .header_height(24.0);
/// ```
#[must_use]
pub const fn header_height(mut self, height: f32) -> Self {
self.header_height = height;
self
}

/// Disables Ctrl+A keyboard shortcut capturing for selecting all rows
///
/// # Returns:
Expand Down
38 changes: 33 additions & 5 deletions src/row_modification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,15 @@ where
/// Modify or add rows to the table. Changes are not immediately reflected in the UI.
/// You must call [`recreate_rows`](#method.recreate_rows) or [`recreate_rows_no_unselect`](#method.recreate_rows_no_unselect) to apply these changes visually.
///
/// If modifying existing and visible row, consider using [`modify_shown_row`](#method.modify_shown_row)
/// alongside modifying through this function which will effectively mirror [`recreate_rows`](#method.recreate_rows)
/// without doing an expensive call.
///
/// Bulk additions of rows is possible through this function with a single call to
/// [`add_modify_row`](#method.add_modify_row) at the end.
///
/// # Parameters:
/// - `table`: A closure that takes a mutable reference to the rows and optionally returns a new row.
/// - A closure that provides a mutable reference to the rows and optionally returns a new row.
/// If a row is returned, it will be added to the table.
///
/// # Auto Reload:
Expand Down Expand Up @@ -77,15 +84,31 @@ where
/// This provides direct access to the currently formatted rows for lightweight updates.
///
/// # Important:
/// - This does **not** require calling `recreate_rows` to reflect changes in the UI.
/// - This does **not** require calling [`recreate_rows`](#method.recreate_rows) to reflect changes in the UI.
/// - **Do not delete rows** from inside this closure — doing so will **cause a panic** and break internal assumptions.
/// To safely delete a row, use [`add_modify_row`](#method.add_modify_row) and then call [`recreate_rows`](#method.recreate_rows) or [`recreate_rows_no_unselect`](#method.recreate_rows_no_unselect).
/// - Can be used alongside [`add_modify_row`](#method.add_modify_row) to show updated data immediately.
/// When row recreation happens, the modified data will be preserved as long as it's updated via [`add_modify_row`](#method.add_modify_row).
/// - Can be used to update a row and show it immediately without having to do an expensive [`recreate_rows`](#method.recreate_rows).
/// You can then immediately call [`add_modify_row`](#method.add_modify_row) to do the same
/// update so later calls to [`recreate_rows`](#method.recreate_rows) or
/// [`recreate_rows_no_unselect`](#method.recreate_rows_no_unselect) does not revert the changes.
/// - Does not contribute toward [`auto_reload`](#method.auto_reload) count.
///
/// # Parameters:
/// - `table`: A closure that takes a mutable reference to the currently formatted rows and an index map.
/// - A closure that provides a mutable reference to the currently formatted rows and an index map.
///
/// # When to use:
/// - Use when you need to modify a data that is currently displayed without having to call
/// [`recreate_rows`](#method.recreate_rows).
/// - When you need to make a temporary change to the data displayed in the UI. To persist any
/// changes, use [`add_modify_row`](#method.add_modify_row).
///
/// # How to use:
/// 1. Get the row ID you want to modify.
/// 2. Use the index map to get the index of the row in the formatted rows.
/// 3. Use the index to get a mutable reference to the row.
/// 4. Safely modify the row contents.
/// 5. In the next frame load, the modified data is visible immediately without any additional
/// calls.
///
/// # Example:
/// ```rust,ignore
Expand All @@ -109,6 +132,11 @@ where
/// returns it as a `SelectableRow`. This does **not**
/// require calling [`recreate_rows`](#method.recreate_rows) for the row to appear in the UI.
///
/// # Important:
/// - This method does not contribute toward [`auto_reload`](#method.auto_reload) count.
/// - Later calls to [`recreate_rows`](#method.recreate_rows) or
/// [`recreate_rows_no_unselect`](#method.recreate_rows_no_unselect) will sort the row again.
///
/// # Parameters:
/// - `row`: The data to insert into the table.
///
Expand Down
45 changes: 42 additions & 3 deletions src/row_selection.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use egui::Ui;
use egui::ahash::{HashMap, HashMapExt, HashSet, HashSetExt};
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
use std::fmt::Write as _;
use std::hash::Hash;

Expand Down Expand Up @@ -100,7 +101,7 @@ where

let drag_start = self.drag_started_on.clone().expect("Drag start not found");

// number of the column of drag starting point and the current cell that we are trying to select
// Number of the column of drag starting point and the current cell that we are trying to select
let drag_start_num = self.column_to_num(&drag_start.1);
let ongoing_column_num = self.column_to_num(column_name);

Expand Down Expand Up @@ -363,7 +364,7 @@ where

/// Selects all rows and columns in the table.
///
/// After calling this method, all rows will have all columns selected.
/// After calling this method, all rows will have all columns selected and visible immediately.
///
/// # Example:
/// ```rust,ignore
Expand Down Expand Up @@ -418,6 +419,44 @@ where
selected_rows
}

/// Retrieves the currently selected rows but in no particular order. Can be faster than
/// [`get_selected_rows`](#method.get_selected_rows) as it uses rayon for parallel processing
/// and only checks the active rows instead of every single row.
///
/// This method returns a vector of the rows that have one or more columns selected.
///
/// If the `select_full_row` flag is enabled, it will ensure that all columns are selected for
/// each active row.
///
/// # Returns:
/// A `Vec` of `SelectableRow` instances that are currently selected.
///
/// # Example:
/// ```rust,ignore
/// let selected_rows = table.get_selected_rows();
/// ```
pub fn get_selected_rows_unsorted(&mut self) -> Vec<SelectableRow<Row, F>> {
if self.select_full_row {
self.active_columns.extend(self.all_columns.clone());
}

self.active_rows
.par_iter()
.map(|row_id| {
let row_index = self
.indexed_ids
.get(row_id)
.expect("Could not get id index");
let target_row = self
.formatted_rows
.get(*row_index)
.expect("Could not get row");

target_row.clone()
})
.collect()
}

/// Copies selected cells to the system clipboard in a tabular format.
///
/// This method copies only the selected cells from each row to the clipboard, and ensures
Expand All @@ -441,7 +480,7 @@ where
// Iter through all the rows and find the rows that have at least one column as selected.
// Keep track of the biggest length of a value of a column
// active rows cannot be used here because hashset does not maintain an order.
// So itering will give the rows in a different order than what is shown in the ui
// So iterating will give the rows in a different order than what is shown in the ui
for row in &self.formatted_rows {
if row.selected_columns.is_empty() {
continue;
Expand Down
Loading