### Define and Initialize VirtualList in Rust Source: https://docs.rs/egui_virtual_list/0.9.0/egui_virtual_list/struct.VirtualList_search=std%3A%3Avec This snippet shows how to declare the `VirtualList` struct and create a new instance of it. It's the starting point for using the virtual list functionality. ```Rust pub struct VirtualList { /* private fields */ } // Create a new VirtualList let mut virtual_list = VirtualList::new(); ``` -------------------------------- ### VirtualListResponse TryFrom Implementation Example Source: https://docs.rs/egui_virtual_list/0.9.0/egui_virtual_list/struct.VirtualListResponse_search=u32+-%3E+bool Illustrates a potential usage or issue with the `try_from` method for `VirtualListResponse` (or a related type) where a `bool` type is expected but a `u32` might be provided, leading to a type mismatch. This highlights generic type handling in Rust conversions. ```rust // Example illustrating potential type mismatch in try_from // This is a conceptual representation based on the summary text. // Actual implementation would be within the egui_virtual_list crate. // Assuming a context where T is bool and U is u32 for try_from // let u32_value: u32 = 10; // let bool_result: Result = TryFrom::::try_from(u32_value); // Similarly for VirtualList::try_from // let list_result: Result = egui_virtual_list::VirtualList::try_from(u32_value); ``` -------------------------------- ### VirtualList Item Insertion Handling (Rust) Source: https://docs.rs/egui_virtual_list/0.9.0/egui_virtual_list/struct.VirtualList_search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Provides methods to inform the VirtualList about changes in item order, specifically when items are inserted at the start. This helps maintain the user's scroll position. ```rust impl VirtualList { /// Call this when you insert items at the start of the list. The list will offset the scroll position by the height of these items, so that for the user, the scroll position stays the same. pub fn items_inserted_at_start(&mut self, scroll_top_items: usize) { // ... implementation ... } } ``` -------------------------------- ### Initialize Rendering State for Virtual List in egui Source: https://docs.rs/egui_virtual_list/0.9.0/src/egui_virtual_list/lib.rs_search= This Rust code initializes the state required for rendering a virtualized list in egui. It calculates the starting item index based on the first visible row and any offset from items inserted at the start. It also sets up a loop counter and a mechanism to request repaints if too many items are calculated in a single frame, preventing performance degradation. ```rust let item_start_index = self .rows .get(row_start_index) .map_or(0, |row| row.range.start) + index_offset; let mut current_item_index = item_start_index; let mut iterations = 0; ui.skip_ahead_auto_ids(item_start_index); loop { if iterations > self.max_rows_calculated_per_frame { ui.ctx().request_repaint(); break; } iterations += 1; if current_item_index < length { let pos = ui.next_widget_position() - min; // ... rest of rendering logic ``` -------------------------------- ### Find First Visible Row and Initialize Item Index Source: https://docs.rs/egui_virtual_list/0.9.0/src/egui_virtual_list/lib.rs_search=std%3A%3Avec This code block efficiently determines the starting row index that is visible within the current viewport. It iterates backward from the last known row until it finds a row whose top is at or above the visible area's top edge. It then calculates the initial item index based on this visible row, accounting for any items added at the start. ```rust // Find the first row that is visible loop { if row_start_index == 0 { break; } if let Some(row) = self.rows.get(row_start_index) { let skip = if let Some((idx, _)) = scroll_to_item_index_visibility { row.range.start >= idx } else { false }; if row.pos.y <= visible_rect.min.y && !skip { ui.add_space(row.pos.y); break; } } row_start_index -= 1; } let mut current_row = row_start_index; let item_start_index = self .rows .get(row_start_index) .map_or(0, |row| row.range.start) + index_offset; let mut current_item_index = item_start_index; let mut iterations = 0; let mut first_visible_item_index = None; let mut first_visible_item_visibility = None; let mut did_scroll = false; ui.skip_ahead_auto_ids(item_start_index); loop { // Bail out if we're recalculating too many items if iterations > self.max_rows_calculated_per_frame { ui.ctx().request_repaint(); break; } iterations += 1; // let item = self.items.get_mut(current_row); if current_item_index < length { let pos = ui.next_widget_position() - min; let count = ui ``` -------------------------------- ### Notify VirtualList of Items Inserted at Start Source: https://docs.rs/egui_virtual_list/0.9.0/src/egui_virtual_list/lib.rs Informs the VirtualList when new items have been added to the beginning of the list. This is crucial for maintaining the user's scroll position by adjusting the scroll offset to compensate for the added items' height. ```rust /// Call this when you insert items at the start of the list. /// The list will offset the scroll position by the height of these items, so that for the user, /// the scroll position stays the same. pub fn items_inserted_at_start(&mut self, scroll_top_items: usize) { self.items_inserted_at_start = Some(scroll_top_items); } ``` -------------------------------- ### Find First Visible Row for Rendering in egui Source: https://docs.rs/egui_virtual_list/0.9.0/src/egui_virtual_list/lib.rs_search= This Rust code determines the starting row index for rendering a virtualized list in egui. It iterates backward from a previous known row index, checking if the row's position is above the visible area's top edge. This optimization ensures that rendering only begins for items that are actually visible on the screen, improving performance. ```rust loop { if row_start_index == 0 { break; } if let Some(row) = self.rows.get(row_start_index) { let skip = if let Some((idx, _)) = scroll_to_item_index_visibility { row.range.start >= idx } else { false }; if row.pos.y <= visible_rect.min.y && !skip { ui.add_space(row.pos.y); break; } } row_start_index -= 1; } ``` -------------------------------- ### Custom Layout for VirtualList UI (Rust) Source: https://docs.rs/egui_virtual_list/0.9.0/egui_virtual_list/struct.VirtualList Allows for a custom layout function to define how rows are rendered within the VirtualList. The provided closure receives the UI context and the starting item index for a row, returning the number of items displayed in that row. This enables flexible row generation. ```rust use egui::Ui; // Assuming VirtualListResponse is defined elsewhere // pub struct VirtualListResponse { ... } impl VirtualList { /// The layout closure gets called for each row with the index of the first item that should be displayed. It should return the number of items that were displayed in the row. pub fn ui_custom_layout( &mut self, ui: &mut Ui, length: usize, layout: impl FnMut(&mut Ui, usize) -> usize, ) -> VirtualListResponse { // ... implementation details ... } } ``` -------------------------------- ### Initialize VirtualList Widget Source: https://docs.rs/egui_virtual_list/0.9.0/src/egui_virtual_list/lib.rs Creates a new instance of the VirtualList widget with default settings. This includes default overscan, resize checking, and scroll position synchronization on resize. ```rust impl Default for VirtualList { fn default() -> Self { Self::new() } } impl VirtualList { /// Create a new `VirtualList` pub fn new() -> Self { Self { previous_item_range: usize::MAX..usize::MAX, last_known_row_index: None, last_width: None, average_row_size: None, rows: vec![], average_items_per_row: None, max_rows_calculated_per_frame: 1000, over_scan: 200.0, items_inserted_at_start: None, check_for_resize: true, scroll_position_sync_on_resize: true, hide_on_resize: Some(Duration::from_millis(100)), last_top_most_item: None, last_resize: SystemTime::now(), } } // ... other methods ``` -------------------------------- ### Calculate Visible Rect and Manage Scroll Offset in egui Source: https://docs.rs/egui_virtual_list/0.9.0/src/egui_virtual_list/lib.rs_search=u32+-%3E+bool This Rust code calculates the visible rectangular area within a scrollable egui widget, considering overscan. It determines the starting position for row rendering and handles items inserted at the start of the list by adjusting the scroll position and repaint requests. Dependencies include egui's UI context and layout functions. ```Rust // Start of the scroll area (basically scroll_offset + whatever is above the scroll area) let min = ui.next_widget_position().to_vec2(); let mut row_start_index = self.last_known_row_index.unwrap_or(0); // This calculates the visible rect inside the scroll area // Should be equivalent to to viewport from ScrollArea::show_viewport(), offset by whatever is above the scroll area let visible_rect = ui.clip_rect().translate(-min); let visible_rect = visible_rect.expand2(Vec2::new(0.0, self.over_scan)); let mut index_offset = 0; // Calculate the added_height for items that were added at the top and scroll by that amount // to maintain the scroll position let scroll_items_top_step_2 = if let Some(scroll_top_items) = self.items_inserted_at_start.take() { let mut measure_ui = ui.new_child(UiBuilder::new().max_rect(ui.max_rect())); measure_ui.set_invisible(); let start_height = measure_ui.next_widget_position(); for i in 0..scroll_top_items { measure_ui.scope_builder(UiBuilder::new().id_salt(i), |ui| { layout(ui, i); }); } let end_height = measure_ui.next_widget_position(); let added_height = end_height.y - start_height.y + ui.spacing().item_spacing.y; // TODO: Ideally we should be able to use scroll_with_delta here but that doesn't work // until https://github.com/emilk/egui/issues/2783 is fixed. Before, scroll_to_rect // only works when the mouse is over the scroll area. // ui.scroll_with_delta(Vec2::new(0.0, -added_height)); ui.scroll_to_rect(ui.clip_rect().translate(Vec2::new(0.0, added_height)), None); index_offset = scroll_top_items; ui.ctx().request_repaint(); Some(added_height) } else { None }; // Find the first row that is visible loop { if row_start_index == 0 { break; } if let Some(row) = self.rows.get(row_start_index) { let skip = if let Some((idx, _)) = scroll_to_item_index_visibility { row.range.start >= idx } else { false }; if row.pos.y <= visible_rect.min.y && !skip { ui.add_space(row.pos.y); break; } } row_start_index -= 1; } let mut current_row = row_start_index; let item_start_index = self .rows .get(row_start_index) .map_or(0, |row| row.range.start) + index_offset; let mut current_item_index = item_start_index; let mut iterations = 0; let mut first_visible_item_index = None; let mut first_visible_item_visibility = None; let mut did_scroll = false; ui.skip_ahead_auto_ids(item_start_index); loop { // Bail out if we're recalculating too many items if iterations > self.max_rows_calculated_per_frame { ui.ctx().request_repaint(); break; } iterations += 1; // let item = self.items.get_mut(current_row); if current_item_index < length { let pos = ui.next_widget_position() - min; let count = ui } ``` -------------------------------- ### Create new VirtualList Source: https://docs.rs/egui_virtual_list/0.9.0/egui_virtual_list/struct.VirtualList_search= Initializes a new instance of the `VirtualList` struct. This is the entry point for creating a virtual list widget. ```rust pub fn new() -> Self ``` -------------------------------- ### VirtualList Initialization and Configuration Source: https://docs.rs/egui_virtual_list/0.9.0/src/egui_virtual_list/lib.rs_search= Demonstrates how to create a new VirtualList instance and configure its behavior, such as overscan, resize handling, and scroll synchronization. ```rust #![doc = include_str!("../README.md")] #![forbid(unsafe_code)] #![warn(missing_docs)] use std::ops::Range; use egui::{Align, Pos2, Rect, Ui, UiBuilder, Vec2}; use web_time::{Duration, SystemTime}; /// The response from a call to [`VirtualList::ui_custom_layout`] pub struct VirtualListResponse { /// The range of items that was displayed pub item_range: Range, /// Any items in this range are now visible pub newly_visible_items: Range, /// Any items in this range are no longer visible pub hidden_items: Range, } #[derive(Debug)] struct RowData { range: Range, pos: Pos2, } /// Virtual list widget for egui. #[derive(Debug)] pub struct VirtualList { rows: Vec, previous_item_range: Range, // The index of the first item that has an unknown rect last_known_row_index: Option, average_row_size: Option, average_items_per_row: Option, // We will recalculate every item's rect if the scroll area's width changes last_width: Option, max_rows_calculated_per_frame: usize, over_scan: f32, // If set, the list will scroll by this many items from the top. // Useful when items at the top are added, and the scroll position should be maintained. // The value should be the number of items that were added at the top. items_inserted_at_start: Option, check_for_resize: bool, scroll_position_sync_on_resize: bool, hide_on_resize: Option, /// Stores the index and visibility percentage of the last item that was at the top of the list last_top_most_item: Option<(usize, f32)>, last_resize: SystemTime, } impl Default for VirtualList { fn default() -> Self { Self::new() } } impl VirtualList { /// Create a new `VirtualList` pub fn new() -> Self { Self { previous_item_range: usize::MAX..usize::MAX, last_known_row_index: None, last_width: None, average_row_size: None, rows: vec![], average_items_per_row: None, max_rows_calculated_per_frame: 1000, over_scan: 200.0, items_inserted_at_start: None, check_for_resize: true, scroll_position_sync_on_resize: true, hide_on_resize: Some(Duration::from_millis(100)), last_top_most_item: None, last_resize: SystemTime::now(), } } /// Call this when you insert items at the start of the list. /// The list will offset the scroll position by the height of these items, so that for the user, /// the scroll position stays the same. pub fn items_inserted_at_start(&mut self, scroll_top_items: usize) { self.items_inserted_at_start = Some(scroll_top_items); } /// Set the overscan, or how much the list should render outside of the visible area. /// The default is 200.0. pub fn over_scan(&mut self, over_scan: f32) { self.over_scan = over_scan; } /// Checks if the list was resized and resets the cached sizes if it was. /// If you are certain that the item heights won't change on resize, you can disable this. /// The default is true. pub fn check_for_resize(&mut self, check_for_resize: bool) { self.check_for_resize = check_for_resize; } /// Tries to keep the first visible item at the top of the screen when the window is resized. /// Depending on the contents, this may cause some flicker. /// The default is true. pub fn scroll_position_sync_on_resize(&mut self, scroll_position_sync_on_resize: bool) { self.scroll_position_sync_on_resize = scroll_position_sync_on_resize; } /// Prevent flickering while resizing by hiding the list until the resize is done. /// The default is true. pub fn hide_on_resize(&mut self, hide_on_resize: impl Into>) { self.hide_on_resize = hide_on_resize.into(); } /// The layout closure gets called for each row with the index of the first item that should /// be displayed. /// It should return the number of items that were displayed in the row. #[allow(clippy::too_many_lines)] // TODO: refactor this to reduce the number of lines pub fn ui_custom_layout( &mut self, ui: &mut Ui, length: usize, mut layout: impl FnMut(&mut Ui, usize) -> usize, ) -> VirtualListResponse { let mut scroll_to_item_index_visibility = None; { let available_width_rounded = (ui.available_width() * 10.0).round() / 10.0; ``` -------------------------------- ### Build and Render UI Rows with egui Source: https://docs.rs/egui_virtual_list/0.9.0/src/egui_virtual_list/lib.rs_search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E This snippet demonstrates how to build and render individual rows within a virtual list using the egui library. It calculates the position and size of each row, handles scrolling logic, and updates the UI accordingly. Dependencies include egui and associated utilities for layout and UI building. ```Rust .scope_builder(UiBuilder::new().id_salt(current_item_index), |ui| { layout(ui, current_item_index) }) .inner; let size = ui.next_widget_position() - min - pos; let rect = Rect::from_min_size(pos, size); let range = current_item_index..current_item_index + count; if let Some((scroll_to, visibility)) = scroll_to_item_index_visibility { if range.contains(&scroll_to) { // TODO: Somehow correct for overscan here ui.scroll_to_rect( Rect::from_min_size( pos + min + Vec2::new(0.0, size.y * visibility), Vec2::ZERO, ), Some(Align::Min), ); scroll_to_item_index_visibility = None; did_scroll = true; } } if first_visible_item_index.is_none() && rect.max.y >= visible_rect.min.y { first_visible_item_index = Some(current_item_index); first_visible_item_visibility = Some((visible_rect.min.y - rect.min.y) / (rect.max.y - rect.min.y)); } let mut discard_following_rows = false; if let Some(row) = self.rows.get_mut(current_row) { if row.range != range || row.pos != pos { // Our row changed, so the following rows are no longer valid discard_following_rows = true; } row.range = range; row.pos = pos; } else { self.rows.push(RowData { range, pos }); let size_with_space = size; self.average_row_size = Some(self.average_row_size.map_or(size, |size| { (current_row as f32 * size + size_with_space) / (current_row as f32 + 1.0) })); self.average_items_per_row = Some(self.average_items_per_row.map_or( count as f32, |avg_count| { (current_row as f32 * avg_count + count as f32) / (current_row as f32 + 1.0) }, )); self.last_known_row_index = Some(current_row); } if discard_following_rows { self.rows.truncate(current_row + 1); } current_item_index += count; if rect.max.y > visible_rect.max.y && scroll_to_item_index_visibility.is_none() { break; } } else { break; } current_row += 1; } ``` -------------------------------- ### VirtualList::new Constructor Source: https://docs.rs/egui_virtual_list/0.9.0/src/egui_virtual_list/lib.rs_search=u32+-%3E+bool Creates a new `VirtualList` instance with default configuration values. This includes setting initial ranges, sizes, and control flags. ```Rust impl VirtualList { /// Create a new `VirtualList` pub fn new() -> Self { Self { previous_item_range: usize::MAX..usize::MAX, last_known_row_index: None, last_width: None, average_row_size: None, rows: vec![], average_items_per_row: None, max_rows_calculated_per_frame: 1000, over_scan: 200.0, items_inserted_at_start: None, check_for_resize: true, scroll_position_sync_on_resize: true, hide_on_resize: Some(Duration::from_millis(100)), last_top_most_item: None, last_resize: SystemTime::now(), } } ``` -------------------------------- ### Manage VirtualList Resize and Visibility in Rust Source: https://docs.rs/egui_virtual_list/0.9.0/egui_virtual_list/struct.VirtualList_search=std%3A%3Avec Shows how to control the `VirtualList`'s behavior during window resizing. This includes enabling/disabling resize checks and hiding the list to prevent flickering. ```Rust pub fn check_for_resize(&mut self, check_for_resize: bool) pub fn hide_on_resize(&mut self, hide_on_resize: impl Into>) ``` -------------------------------- ### Managing List Items and Scrolling (Rust) Source: https://docs.rs/egui_virtual_list/0.9.0/egui_virtual_list/struct.VirtualList Provides methods to handle dynamic list content. `items_inserted_at_start` adjusts scroll position when new items are added at the beginning. `reset` clears cached data when item sizes or content change. ```rust impl VirtualList { /// Call this when you insert items at the start of the list. The list will offset the scroll position by the height of these items, so that for the user, the scroll position stays the same. pub fn items_inserted_at_start(&mut self, scroll_top_items: usize) { // ... implementation details ... } /// Resets the list, clearing all cached data. Call this if items changed size, items were replaced, etc. The heights will be recalculated on the next frame. pub fn reset(&mut self) { // ... implementation details ... } } ``` -------------------------------- ### Calculate Visible Rect and Handle Item Insertion in egui Virtual List Source: https://docs.rs/egui_virtual_list/0.9.0/src/egui_virtual_list/lib.rs_search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E This Rust code calculates the visible rectangular area for a scrollable list, accounting for overscan to improve perceived performance. It also handles the insertion of new items at the start of the list, adjusting the scroll position to maintain continuity. ```rust 157 // Start of the scroll area (basically scroll_offset + whatever is above the scroll area) 158 let min = ui.next_widget_position().to_vec2(); 159 160 let mut row_start_index = self.last_known_row_index.unwrap_or(0); 161 162 // This calculates the visible rect inside the scroll area 163 // Should be equivalent to to viewport from ScrollArea::show_viewport(), offset by whatever is above the scroll area 164 let visible_rect = ui.clip_rect().translate(-min); 165 166 let visible_rect = visible_rect.expand2(Vec2::new(0.0, self.over_scan)); 167 168 let mut index_offset = 0; 169 170 // Calculate the added_height for items that were added at the top and scroll by that amount 171 // to maintain the scroll position 172 let scroll_items_top_step_2 = 173 if let Some(scroll_top_items) = self.items_inserted_at_start.take() { 174 let mut measure_ui = ui.new_child(UiBuilder::new().max_rect(ui.max_rect())); 175 measure_ui.set_invisible(); 176 177 let start_height = measure_ui.next_widget_position(); 178 for i in 0..scroll_top_items { 179 measure_ui.scope_builder(UiBuilder::new().id_salt(i), |ui| { 180 layout(ui, i); 181 }); 182 } 183 let end_height = measure_ui.next_widget_position(); 184 185 let added_height = end_height.y - start_height.y + ui.spacing().item_spacing.y; 186 187 // TODO: Ideally we should be able to use scroll_with_delta here but that doesn't work 188 // until https://github.com/emilk/egui/issues/2783 is fixed. Before, scroll_to_rect 189 // only works when the mouse is over the scroll area. 190 // ui.scroll_with_delta(Vec2::new(0.0, -added_height)); 191 ui.scroll_to_rect(ui.clip_rect().translate(Vec2::new(0.0, added_height)), None); 192 193 index_offset = scroll_top_items; 194 195 ui.ctx().request_repaint(); 196 197 Some(added_height) 198 } else { 199 None 200 }; 201 202 // Find the first row that is visible 203 loop { 204 if row_start_index == 0 { 205 break; 206 } 207 208 if let Some(row) = self.rows.get(row_start_index) { 209 let skip = if let Some((idx, _)) = scroll_to_item_index_visibility { 210 row.range.start >= idx 211 } else { 212 false 213 }; 214 215 if row.pos.y <= visible_rect.min.y && !skip { 216 ui.add_space(row.pos.y); 217 break; 218 } 219 } 220 row_start_index -= 1; 221 } ``` -------------------------------- ### Configuring VirtualList Rendering and Behavior (Rust) Source: https://docs.rs/egui_virtual_list/0.9.0/egui_virtual_list/struct.VirtualList Methods to customize how the VirtualList renders and behaves. `over_scan` controls the rendering buffer outside the visible area. `check_for_resize` and `scroll_position_sync_on_resize` manage adjustments during window resizing. `hide_on_resize` temporarily hides the list during resizing to prevent flicker. ```rust use std::time::Duration; impl VirtualList { /// Set the overscan, or how much the list should render outside of the visible area. The default is 200.0. pub fn over_scan(&mut self, over_scan: f32) { // ... implementation details ... } /// Checks if the list was resized and resets the cached sizes if it was. If you are certain that the item heights won’t change on resize, you can disable this. The default is true. pub fn check_for_resize(&mut self, check_for_resize: bool) { // ... implementation details ... } /// Tries to keep the first visible item at the top of the screen when the window is resized. Depending on the contents, this may cause some flicker. The default is true. pub fn scroll_position_sync_on_resize( &mut self, scroll_position_sync_on_resize: bool, ) { // ... implementation details ... } /// Prevent flickering while resizing by hiding the list until the resize is done. The default is true. pub fn hide_on_resize(&mut self, hide_on_resize: impl Into>) { // ... implementation details ... } } ``` -------------------------------- ### Calculate Visible Rect and Scroll Offset in egui Virtual List Source: https://docs.rs/egui_virtual_list/0.9.0/src/egui_virtual_list/lib.rs This Rust code calculates the visible rectangular area within the scrollable content of an egui virtual list. It determines the minimum position of the scroll area, accounts for any content above it, and expands the visible rectangle with over-scan for smoother scrolling. It also handles logic for items inserted at the start, adjusting the scroll position to maintain continuity. ```rust // Start of the scroll area (basically scroll_offset + whatever is above the scroll area) let min = ui.next_widget_position().to_vec2(); let mut row_start_index = self.last_known_row_index.unwrap_or(0); // This calculates the visible rect inside the scroll area // Should be equivalent to to viewport from ScrollArea::show_viewport(), offset by whatever is above the scroll area let visible_rect = ui.clip_rect().translate(-min); let visible_rect = visible_rect.expand2(Vec2::new(0.0, self.over_scan)); let mut index_offset = 0; // Calculate the added_height for items that were added at the top and scroll by that amount // to maintain the scroll position let scroll_items_top_step_2 = if let Some(scroll_top_items) = self.items_inserted_at_start.take() { let mut measure_ui = ui.new_child(UiBuilder::new().max_rect(ui.max_rect())); measure_ui.set_invisible(); let start_height = measure_ui.next_widget_position(); for i in 0..scroll_top_items { measure_ui.scope_builder(UiBuilder::new().id_salt(i), |ui| { layout(ui, i); }); } let end_height = measure_ui.next_widget_position(); let added_height = end_height.y - start_height.y + ui.spacing().item_spacing.y; // TODO: Ideally we should be able to use scroll_with_delta here but that doesn't work // until https://github.com/emilk/egui/issues/2783 is fixed. Before, scroll_to_rect // only works when the mouse is over the scroll area. // ui.scroll_with_delta(Vec2::new(0.0, -added_height)); ui.scroll_to_rect(ui.clip_rect().translate(Vec2::new(0.0, added_height)), None); index_offset = scroll_top_items; ui.ctx().request_repaint(); Some(added_height) } else { None }; // Find the first row that is visible loop { if row_start_index == 0 { break; } if let Some(row) = self.rows.get(row_start_index) { let skip = if let Some((idx, _)) = scroll_to_item_index_visibility { row.range.start >= idx } else { false }; if row.pos.y <= visible_rect.min.y && !skip { ui.add_space(row.pos.y); break; } } row_start_index -= 1; } let mut current_row = row_start_index; let item_start_index = self .rows .get(row_start_index) .map_or(0, |row| row.range.start) + index_offset; let mut current_item_index = item_start_index; let mut iterations = 0; let mut first_visible_item_index = None; let mut first_visible_item_visibility = None; let mut did_scroll = false; ui.skip_ahead_auto_ids(item_start_index); loop { // Bail out if we're recalculating too many items if iterations > self.max_rows_calculated_per_frame { ui.ctx().request_repaint(); break; } iterations += 1; // let item = self.items.get_mut(current_row); if current_item_index < length { let pos = ui.next_widget_position() - min; let count = ui ``` -------------------------------- ### Implement Custom Layout for VirtualList in Rust Source: https://docs.rs/egui_virtual_list/0.9.0/egui_virtual_list/struct.VirtualList_search=std%3A%3Avec Illustrates how to provide a custom layout function for the `VirtualList`. This allows for flexible row rendering based on specific logic and item indices. ```Rust pub fn ui_custom_layout( &mut self, ui: &mut Ui, length: usize, layout: impl FnMut(&mut Ui, usize) -> usize, ) -> VirtualListResponse ``` -------------------------------- ### Calculate Visible Rect and Handle Inserted Items Source: https://docs.rs/egui_virtual_list/0.9.0/src/egui_virtual_list/lib.rs_search=std%3A%3Avec This section calculates the visible rectangular area within the scrollable content, accounting for any UI elements above the scroll area. It also manages the insertion of new items at the start of the list, adjusting the scroll position to maintain the user's view and updating the index offset accordingly. This ensures that newly added items at the top do not disrupt the perceived scroll position. ```rust // Start of the scroll area (basically scroll_offset + whatever is above the scroll area) let min = ui.next_widget_position().to_vec2(); let mut row_start_index = self.last_known_row_index.unwrap_or(0); // This calculates the visible rect inside the scroll area // Should be equivalent to to viewport from ScrollArea::show_viewport(), offset by whatever is above the scroll area let visible_rect = ui.clip_rect().translate(-min); let visible_rect = visible_rect.expand2(Vec2::new(0.0, self.over_scan)); let mut index_offset = 0; // Calculate the added_height for items that were added at the top and scroll by that amount // to maintain the scroll position let scroll_items_top_step_2 = if let Some(scroll_top_items) = self.items_inserted_at_start.take() { let mut measure_ui = ui.new_child(UiBuilder::new().max_rect(ui.max_rect())); measure_ui.set_invisible(); let start_height = measure_ui.next_widget_position(); for i in 0..scroll_top_items { measure_ui.scope_builder(UiBuilder::new().id_salt(i), |ui| { layout(ui, i); // Assuming 'layout' is a function to render an item }); } let end_height = measure_ui.next_widget_position(); let added_height = end_height.y - start_height.y + ui.spacing().item_spacing.y; // TODO: Ideally we should be able to use scroll_with_delta here but that doesn't work // until https://github.com/emilk/egui/issues/2783 is fixed. Before, scroll_to_rect // only works when the mouse is over the scroll area. // ui.scroll_with_delta(Vec2::new(0.0, -added_height)); ui.scroll_to_rect(ui.clip_rect().translate(Vec2::new(0.0, added_height)), None); index_offset = scroll_top_items; ui.ctx().request_repaint(); Some(added_height) } else { None }; ``` -------------------------------- ### VirtualList Configuration Methods Source: https://docs.rs/egui_virtual_list/0.9.0/src/egui_virtual_list/lib.rs_search=u32+-%3E+bool Provides methods to configure the behavior of the `VirtualList`. These include setting overscan, enabling/disabling resize checks, controlling scroll position synchronization, and managing hiding during resize. ```Rust /// Call this when you insert items at the start of the list. /// The list will offset the scroll position by the height of these items, so that for the user, /// the scroll position stays the same. pub fn items_inserted_at_start(&mut self, scroll_top_items: usize) { self.items_inserted_at_start = Some(scroll_top_items); } /// Set the overscan, or how much the list should render outside of the visible area. /// The default is 200.0. pub fn over_scan(&mut self, over_scan: f32) { self.over_scan = over_scan; } /// Checks if the list was resized and resets the cached sizes if it was. /// If you are certain that the item heights won't change on resize, you can disable this. /// The default is true. pub fn check_for_resize(&mut self, check_for_resize: bool) { self.check_for_resize = check_for_resize; } /// Tries to keep the first visible item at the top of the screen when the window is resized. /// Depending on the contents, this may cause some flicker. /// The default is true. pub fn scroll_position_sync_on_resize(&mut self, scroll_position_sync_on_resize: bool) { self.scroll_position_sync_on_resize = scroll_position_sync_on_resize; } /// Prevent flickering while resizing by hiding the list until the resize is done. /// The default is true. pub fn hide_on_resize(&mut self, hide_on_resize: impl Into>) { self.hide_on_resize = hide_on_resize.into(); } ``` -------------------------------- ### VirtualList Structure and Initialization (Rust) Source: https://docs.rs/egui_virtual_list/0.9.0/egui_virtual_list/struct.VirtualList Defines the VirtualList struct and provides a constructor to create a new instance. The struct itself has private fields, and its behavior is controlled through its methods. ```rust pub struct VirtualList { /* private fields */ } impl VirtualList { /// Create a new `VirtualList` pub fn new() -> Self { // ... implementation details ... } } ``` -------------------------------- ### Rust Trait Implementations for VirtualList Source: https://docs.rs/egui_virtual_list/0.9.0/egui_virtual_list/struct.VirtualList Demonstrates various standard Rust trait implementations for the `VirtualList` struct, including `Debug`, `Default`, `Freeze`, `RefUnwindSafe`, `Send`, `Sync`, `Unpin`, `UnwindSafe`, `Any`, `Borrow`, `BorrowMut`, `From`, `Into`, `TryFrom`, and `TryInto`. These enable standard Rust practices and interoperability. ```rust use std::any::TypeId; use std::convert::Infallible; use std::fmt::Formatter; // Debug implementation impl Debug for VirtualList { fn fmt(&self, f: &mut Formatter<'_>) -> Result { // ... implementation details ... } } // Default implementation impl Default for VirtualList { fn default() -> Self { // ... implementation details ... } } // Blanket implementations (examples) impl Any for T where T: 'static + ?Sized { fn type_id(&self) -> TypeId { // ... implementation details ... } } impl TryFrom for T where U: Into { type Error = Infallible; fn try_from(value: U) -> Result { // ... implementation details ... } } ``` -------------------------------- ### Configure VirtualList Scroll Behavior in Rust Source: https://docs.rs/egui_virtual_list/0.9.0/egui_virtual_list/struct.VirtualList_search=std%3A%3Avec Demonstrates methods to manage scroll behavior and item visibility within the `VirtualList`. These include offsetting scroll on insertion, setting overscan, and synchronizing scroll on resize. ```Rust pub fn items_inserted_at_start(&mut self, scroll_top_items: usize) pub fn over_scan(&mut self, over_scan: f32) pub fn scroll_position_sync_on_resize( &mut self, scroll_position_sync_on_resize: bool, ) ``` -------------------------------- ### VirtualList Widget API Source: https://docs.rs/egui_virtual_list/0.9.0/egui_virtual_list/struct.VirtualList_search=std%3A%3Avec Provides methods for creating and configuring the VirtualList widget for egui applications. ```APIDOC ## VirtualList Widget API ### Description Documentation for the `VirtualList` struct, which is a virtual list widget for egui. It allows for efficient rendering of large lists by only drawing the items currently visible in the viewport. ### Methods #### `new()` **Description**: Creates a new `VirtualList` instance. **Method**: `pub fn new() -> Self` **Endpoint**: N/A (Constructor) **Request Body**: None **Success Response**: A new `VirtualList` instance. **Response Example**: N/A #### `items_inserted_at_start()` **Description**: Call this method when items are inserted at the beginning of the list. It adjusts the scroll position to maintain the user's current view. **Method**: `pub fn items_inserted_at_start(&mut self, scroll_top_items: usize)` **Endpoint**: N/A **Parameters**: * `scroll_top_items` (usize) - The number of items inserted at the start. **Request Body**: None **Success Response**: The `VirtualList` state is updated. **Response Example**: N/A #### `over_scan()` **Description**: Sets the overscan value, which determines how many pixels beyond the visible area the list should render. This helps in creating a smoother scrolling experience. **Method**: `pub fn over_scan(&mut self, over_scan: f32)` **Endpoint**: N/A **Parameters**: * `over_scan` (f32) - The amount of overscan in pixels. Default is 200.0. **Request Body**: None **Success Response**: The `over_scan` value is updated. **Response Example**: N/A #### `check_for_resize()` **Description**: Enables or disables checking for list resizing. If enabled (default is true), the widget checks if its size has changed and resets cached item sizes accordingly. Disabling can be useful if item heights are guaranteed not to change on resize. **Method**: `pub fn check_for_resize(&mut self, check_for_resize: bool)` **Endpoint**: N/A **Parameters**: * `check_for_resize` (bool) - `true` to enable resize checking, `false` to disable. **Request Body**: None **Success Response**: The resize checking behavior is updated. **Response Example**: N/A #### `scroll_position_sync_on_resize()` **Description**: Configures whether the list attempts to keep the first visible item at the top of the screen when the window is resized. Enabling this can sometimes cause minor flickering depending on content. **Method**: `pub fn scroll_position_sync_on_resize(&mut self, scroll_position_sync_on_resize: bool)` **Endpoint**: N/A **Parameters**: * `scroll_position_sync_on_resize` (bool) - `true` to enable scroll position synchronization on resize, `false` to disable. Default is true. **Request Body**: None **Success Response**: The scroll position synchronization behavior is updated. **Response Example**: N/A #### `hide_on_resize()` **Description**: Configures whether the list should be hidden during window resizing to prevent flickering. The list will be hidden for a specified duration after the resize event stops. **Method**: `pub fn hide_on_resize(&mut self, hide_on_resize: impl Into>)` **Endpoint**: N/A **Parameters**: * `hide_on_resize` (impl Into>) - A duration after which the list will be shown again. `None` disables this feature. Default is true (interpreted as a default duration). **Request Body**: None **Success Response**: The hide-on-resize behavior is updated. **Response Example**: N/A #### `ui_custom_layout()` **Description**: Renders the `VirtualList` with a custom layout function. This is the primary method for drawing the list content within a given `Ui` context. **Method**: `pub fn ui_custom_layout(&mut self, ui: &mut Ui, length: usize, layout: impl FnMut(&mut Ui, usize) -> usize) -> VirtualListResponse` **Endpoint**: N/A **Parameters**: * `ui` (&mut Ui) - The egui UI context. * `length` (usize) - The total number of items in the list. * `layout` (impl FnMut(&mut Ui, usize) -> usize) - A closure that defines how items are laid out. It receives the `Ui` context and the index of the first item to display, and should return the number of items rendered in that row. **Request Body**: None **Success Response**: Returns a `VirtualListResponse` indicating interaction details. **Response Example**: ```json { "response": "VirtualListResponse details" } ``` #### `reset()` **Description**: Resets the internal state of the `VirtualList`, clearing all cached data. This should be called when the list's items change in size or are replaced, as it forces recalculation of item heights on the next frame. **Method**: `pub fn reset(&mut self)` **Endpoint**: N/A **Request Body**: None **Success Response**: The `VirtualList` is reset. **Response Example**: N/A ```