mirror of
https://github.com/emilk/egui.git
synced 2026-09-02 14:50:03 -04:00
Make sure scroll bars are always visible (#2371)
* Nicer debug rectangles * Move scrollbars into the clip-rect so they are always visible * Improve table demo * Add options for controlling inner and outer margin of the scroll bars * Add line to changelog * Update egui_extras changelog with recent Table improvements * Refactor Table:s scroll options * Add Table::auto_size * Rename it auto_shrink
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
//! | fixed size | all available space/minimum | 30% of available width | fixed size |
|
||||
//! Takes all available height, so if you want something below the table, put it in a strip.
|
||||
|
||||
use egui::{Align, NumExt as _, Rect, Response, Ui, Vec2};
|
||||
use egui::{Align, NumExt as _, Rect, Response, ScrollArea, Ui, Vec2};
|
||||
|
||||
use crate::{
|
||||
layout::{CellDirection, CellSize},
|
||||
@@ -155,6 +155,32 @@ fn to_sizing(columns: &[Column]) -> crate::sizing::Sizing {
|
||||
|
||||
// -----------------------------------------------------------------=----------
|
||||
|
||||
struct TableScrollOptions {
|
||||
vscroll: bool,
|
||||
stick_to_bottom: bool,
|
||||
scroll_to_row: Option<(usize, Option<Align>)>,
|
||||
scroll_offset_y: Option<f32>,
|
||||
min_scrolled_height: f32,
|
||||
max_scroll_height: f32,
|
||||
auto_shrink: [bool; 2],
|
||||
}
|
||||
|
||||
impl Default for TableScrollOptions {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
vscroll: true,
|
||||
stick_to_bottom: false,
|
||||
scroll_to_row: None,
|
||||
scroll_offset_y: None,
|
||||
min_scrolled_height: 200.0,
|
||||
max_scroll_height: 800.0,
|
||||
auto_shrink: [true; 2],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------=----------
|
||||
|
||||
/// Builder for a [`Table`] with (optional) fixed header and scrolling body.
|
||||
///
|
||||
/// You must pre-allocate all columns with [`Self::column`]/[`Self::columns`].
|
||||
@@ -195,14 +221,7 @@ pub struct TableBuilder<'a> {
|
||||
striped: bool,
|
||||
resizable: bool,
|
||||
cell_layout: egui::Layout,
|
||||
|
||||
// Scroll stuff:
|
||||
vscroll: bool,
|
||||
stick_to_bottom: bool,
|
||||
scroll_to_row: Option<(usize, Option<Align>)>,
|
||||
scroll_offset_y: Option<f32>,
|
||||
min_scrolled_height: f32,
|
||||
max_scroll_height: f32,
|
||||
scroll_options: TableScrollOptions,
|
||||
}
|
||||
|
||||
impl<'a> TableBuilder<'a> {
|
||||
@@ -214,13 +233,7 @@ impl<'a> TableBuilder<'a> {
|
||||
striped: false,
|
||||
resizable: false,
|
||||
cell_layout,
|
||||
|
||||
vscroll: true,
|
||||
stick_to_bottom: false,
|
||||
scroll_to_row: None,
|
||||
scroll_offset_y: None,
|
||||
min_scrolled_height: 200.0,
|
||||
max_scroll_height: 800.0,
|
||||
scroll_options: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,7 +260,7 @@ impl<'a> TableBuilder<'a> {
|
||||
|
||||
/// Enable vertical scrolling in body (default: `true`)
|
||||
pub fn vscroll(mut self, vscroll: bool) -> Self {
|
||||
self.vscroll = vscroll;
|
||||
self.scroll_options.vscroll = vscroll;
|
||||
self
|
||||
}
|
||||
|
||||
@@ -260,7 +273,7 @@ impl<'a> TableBuilder<'a> {
|
||||
/// dynamically? The scroll handle remains stuck until manually changed, and will become stuck
|
||||
/// once again when repositioned to the bottom. Default: `false`.
|
||||
pub fn stick_to_bottom(mut self, stick: bool) -> Self {
|
||||
self.stick_to_bottom = stick;
|
||||
self.scroll_options.stick_to_bottom = stick;
|
||||
self
|
||||
}
|
||||
|
||||
@@ -272,7 +285,7 @@ impl<'a> TableBuilder<'a> {
|
||||
///
|
||||
/// See also: [`Self::vertical_scroll_offset`].
|
||||
pub fn scroll_to_row(mut self, row: usize, align: Option<Align>) -> Self {
|
||||
self.scroll_to_row = Some((row, align));
|
||||
self.scroll_options.scroll_to_row = Some((row, align));
|
||||
self
|
||||
}
|
||||
|
||||
@@ -280,7 +293,7 @@ impl<'a> TableBuilder<'a> {
|
||||
///
|
||||
/// See also: [`Self::scroll_to_row`].
|
||||
pub fn vertical_scroll_offset(mut self, offset: f32) -> Self {
|
||||
self.scroll_offset_y = Some(offset);
|
||||
self.scroll_options.scroll_offset_y = Some(offset);
|
||||
self
|
||||
}
|
||||
|
||||
@@ -291,7 +304,7 @@ impl<'a> TableBuilder<'a> {
|
||||
///
|
||||
/// Default: `200.0`.
|
||||
pub fn min_scrolled_height(mut self, min_scrolled_height: f32) -> Self {
|
||||
self.min_scrolled_height = min_scrolled_height;
|
||||
self.scroll_options.min_scrolled_height = min_scrolled_height;
|
||||
self
|
||||
}
|
||||
|
||||
@@ -300,7 +313,19 @@ impl<'a> TableBuilder<'a> {
|
||||
/// In other words: add scroll-bars when this height is reached.
|
||||
/// Default: `800.0`.
|
||||
pub fn max_scroll_height(mut self, max_scroll_height: f32) -> Self {
|
||||
self.max_scroll_height = max_scroll_height;
|
||||
self.scroll_options.max_scroll_height = max_scroll_height;
|
||||
self
|
||||
}
|
||||
|
||||
/// For each axis (x,y):
|
||||
/// * If true, add blank space outside the table, keeping the table small.
|
||||
/// * If false, add blank space inside the table, expanding the table to fit the containing ui.
|
||||
///
|
||||
/// Default: `[true; 2]`.
|
||||
///
|
||||
/// See [`ScrollArea::auto_shrink`] for more.
|
||||
pub fn auto_shrink(mut self, auto_shrink: [bool; 2]) -> Self {
|
||||
self.scroll_options.auto_shrink = auto_shrink;
|
||||
self
|
||||
}
|
||||
|
||||
@@ -326,8 +351,10 @@ impl<'a> TableBuilder<'a> {
|
||||
|
||||
fn available_width(&self) -> f32 {
|
||||
self.ui.available_rect_before_wrap().width()
|
||||
- if self.vscroll {
|
||||
self.ui.spacing().item_spacing.x + self.ui.spacing().scroll_bar_width
|
||||
- if self.scroll_options.vscroll {
|
||||
self.ui.spacing().scroll_bar_inner_margin
|
||||
+ self.ui.spacing().scroll_bar_width
|
||||
+ self.ui.spacing().scroll_bar_outer_margin
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
@@ -343,13 +370,7 @@ impl<'a> TableBuilder<'a> {
|
||||
striped,
|
||||
resizable,
|
||||
cell_layout,
|
||||
|
||||
vscroll,
|
||||
stick_to_bottom,
|
||||
scroll_to_row,
|
||||
scroll_offset_y,
|
||||
min_scrolled_height,
|
||||
max_scroll_height,
|
||||
scroll_options,
|
||||
} = self;
|
||||
|
||||
let state_id = ui.id().with("__table_state");
|
||||
@@ -390,13 +411,7 @@ impl<'a> TableBuilder<'a> {
|
||||
resizable,
|
||||
striped,
|
||||
cell_layout,
|
||||
|
||||
vscroll,
|
||||
stick_to_bottom,
|
||||
scroll_to_row,
|
||||
scroll_offset_y,
|
||||
min_scrolled_height,
|
||||
max_scroll_height,
|
||||
scroll_options,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,13 +428,7 @@ impl<'a> TableBuilder<'a> {
|
||||
striped,
|
||||
resizable,
|
||||
cell_layout,
|
||||
|
||||
vscroll,
|
||||
stick_to_bottom,
|
||||
scroll_to_row,
|
||||
scroll_offset_y,
|
||||
min_scrolled_height,
|
||||
max_scroll_height,
|
||||
scroll_options,
|
||||
} = self;
|
||||
|
||||
let state_id = ui.id().with("__table_state");
|
||||
@@ -445,13 +454,7 @@ impl<'a> TableBuilder<'a> {
|
||||
resizable,
|
||||
striped,
|
||||
cell_layout,
|
||||
|
||||
vscroll,
|
||||
stick_to_bottom,
|
||||
scroll_to_row,
|
||||
scroll_offset_y,
|
||||
min_scrolled_height,
|
||||
max_scroll_height,
|
||||
scroll_options,
|
||||
}
|
||||
.body(add_body_contents);
|
||||
}
|
||||
@@ -509,13 +512,7 @@ pub struct Table<'a> {
|
||||
striped: bool,
|
||||
cell_layout: egui::Layout,
|
||||
|
||||
// Scroll stuff:
|
||||
vscroll: bool,
|
||||
stick_to_bottom: bool,
|
||||
scroll_to_row: Option<(usize, Option<Align>)>,
|
||||
scroll_offset_y: Option<f32>,
|
||||
min_scrolled_height: f32,
|
||||
max_scroll_height: f32,
|
||||
scroll_options: TableScrollOptions,
|
||||
}
|
||||
|
||||
impl<'a> Table<'a> {
|
||||
@@ -534,24 +531,29 @@ impl<'a> Table<'a> {
|
||||
mut state,
|
||||
mut max_used_widths,
|
||||
first_frame_auto_size_columns,
|
||||
vscroll,
|
||||
striped,
|
||||
cell_layout,
|
||||
scroll_options,
|
||||
} = self;
|
||||
|
||||
let TableScrollOptions {
|
||||
vscroll,
|
||||
stick_to_bottom,
|
||||
scroll_to_row,
|
||||
scroll_offset_y,
|
||||
min_scrolled_height,
|
||||
max_scroll_height,
|
||||
} = self;
|
||||
auto_shrink,
|
||||
} = scroll_options;
|
||||
|
||||
let avail_rect = ui.available_rect_before_wrap();
|
||||
|
||||
let mut scroll_area = egui::ScrollArea::new([false, vscroll])
|
||||
let mut scroll_area = ScrollArea::new([false, vscroll])
|
||||
.auto_shrink([true; 2])
|
||||
.stick_to_bottom(stick_to_bottom)
|
||||
.min_scrolled_height(min_scrolled_height)
|
||||
.max_height(max_scroll_height);
|
||||
.max_height(max_scroll_height)
|
||||
.auto_shrink(auto_shrink);
|
||||
|
||||
if let Some(scroll_offset_y) = scroll_offset_y {
|
||||
scroll_area = scroll_area.vertical_scroll_offset(scroll_offset_y);
|
||||
|
||||
Reference in New Issue
Block a user