2021-01-25 19:43:41 +00:00
|
|
|
use egui::{color::*, *};
|
|
|
|
|
2021-09-29 06:45:13 +00:00
|
|
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
2021-06-03 16:48:45 +00:00
|
|
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
|
|
enum ScrollDemo {
|
|
|
|
ScrollTo,
|
|
|
|
ManyLines,
|
|
|
|
LargeCanvas,
|
2021-10-09 10:59:42 +00:00
|
|
|
StickToEnd,
|
2021-01-25 19:43:41 +00:00
|
|
|
}
|
|
|
|
|
2021-06-03 16:48:45 +00:00
|
|
|
impl Default for ScrollDemo {
|
2021-01-25 19:43:41 +00:00
|
|
|
fn default() -> Self {
|
2021-06-03 16:48:45 +00:00
|
|
|
Self::ScrollTo
|
2021-01-25 19:43:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-29 06:45:13 +00:00
|
|
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
|
|
|
#[cfg_attr(feature = "serde", serde(default))]
|
2021-06-03 16:48:45 +00:00
|
|
|
#[derive(Default, PartialEq)]
|
|
|
|
pub struct Scrolling {
|
|
|
|
demo: ScrollDemo,
|
|
|
|
scroll_to: ScrollTo,
|
2021-10-09 10:59:42 +00:00
|
|
|
scroll_stick_to: ScrollStickTo,
|
2021-06-03 16:48:45 +00:00
|
|
|
}
|
|
|
|
|
2021-01-25 19:43:41 +00:00
|
|
|
impl super::Demo for Scrolling {
|
2021-02-20 08:18:23 +00:00
|
|
|
fn name(&self) -> &'static str {
|
2021-01-25 19:43:41 +00:00
|
|
|
"↕ Scrolling"
|
|
|
|
}
|
|
|
|
|
2022-01-10 22:13:10 +00:00
|
|
|
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
2021-01-25 19:43:41 +00:00
|
|
|
egui::Window::new(self.name())
|
|
|
|
.open(open)
|
|
|
|
.resizable(false)
|
|
|
|
.show(ctx, |ui| {
|
2021-10-06 21:48:09 +00:00
|
|
|
use super::View as _;
|
2021-01-25 19:43:41 +00:00
|
|
|
self.ui(ui);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl super::View for Scrolling {
|
2021-06-03 16:48:45 +00:00
|
|
|
fn ui(&mut self, ui: &mut Ui) {
|
|
|
|
ui.horizontal(|ui| {
|
|
|
|
ui.selectable_value(&mut self.demo, ScrollDemo::ScrollTo, "Scroll to");
|
|
|
|
ui.selectable_value(
|
|
|
|
&mut self.demo,
|
|
|
|
ScrollDemo::ManyLines,
|
|
|
|
"Scroll a lot of lines",
|
|
|
|
);
|
|
|
|
ui.selectable_value(
|
|
|
|
&mut self.demo,
|
|
|
|
ScrollDemo::LargeCanvas,
|
|
|
|
"Scroll a large canvas",
|
|
|
|
);
|
2021-10-09 10:59:42 +00:00
|
|
|
ui.selectable_value(&mut self.demo, ScrollDemo::StickToEnd, "Stick to end");
|
2021-06-03 16:48:45 +00:00
|
|
|
});
|
|
|
|
ui.separator();
|
|
|
|
match self.demo {
|
|
|
|
ScrollDemo::ScrollTo => {
|
|
|
|
self.scroll_to.ui(ui);
|
|
|
|
}
|
|
|
|
ScrollDemo::ManyLines => {
|
|
|
|
huge_content_lines(ui);
|
|
|
|
}
|
|
|
|
ScrollDemo::LargeCanvas => {
|
|
|
|
huge_content_painter(ui);
|
|
|
|
}
|
2021-10-09 10:59:42 +00:00
|
|
|
ScrollDemo::StickToEnd => {
|
|
|
|
self.scroll_stick_to.ui(ui);
|
|
|
|
}
|
2021-06-03 16:48:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn huge_content_lines(ui: &mut egui::Ui) {
|
|
|
|
ui.label(
|
|
|
|
"A lot of rows, but only the visible ones are layed out, so performance is still good:",
|
|
|
|
);
|
|
|
|
ui.add_space(4.0);
|
|
|
|
|
|
|
|
let text_style = TextStyle::Body;
|
2022-01-24 13:32:36 +00:00
|
|
|
let row_height = ui.text_style_height(&text_style);
|
2021-06-03 16:48:45 +00:00
|
|
|
let num_rows = 10_000;
|
2021-10-06 21:48:09 +00:00
|
|
|
ScrollArea::vertical().auto_shrink([false; 2]).show_rows(
|
|
|
|
ui,
|
|
|
|
row_height,
|
|
|
|
num_rows,
|
|
|
|
|ui, row_range| {
|
|
|
|
for row in row_range {
|
|
|
|
let text = format!("This is row {}/{}", row + 1, num_rows);
|
|
|
|
ui.label(text);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
);
|
2021-06-03 16:48:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn huge_content_painter(ui: &mut egui::Ui) {
|
|
|
|
// This is similar to the other demo, but is fully manual, for when you want to do custom painting.
|
|
|
|
ui.label("A lot of rows, but only the visible ones are painted, so performance is still good:");
|
|
|
|
ui.add_space(4.0);
|
|
|
|
|
2022-01-24 13:32:36 +00:00
|
|
|
let font_id = TextStyle::Body.resolve(ui.style());
|
|
|
|
let row_height = ui.fonts().row_height(&font_id) + ui.spacing().item_spacing.y;
|
2021-06-03 16:48:45 +00:00
|
|
|
let num_rows = 10_000;
|
|
|
|
|
2021-10-06 21:48:09 +00:00
|
|
|
ScrollArea::vertical()
|
|
|
|
.auto_shrink([false; 2])
|
|
|
|
.show_viewport(ui, |ui, viewport| {
|
|
|
|
ui.set_height(row_height * num_rows as f32);
|
|
|
|
|
|
|
|
let first_item = (viewport.min.y / row_height).floor().at_least(0.0) as usize;
|
|
|
|
let last_item = (viewport.max.y / row_height).ceil() as usize + 1;
|
|
|
|
let last_item = last_item.at_most(num_rows);
|
|
|
|
|
|
|
|
let mut used_rect = Rect::NOTHING;
|
|
|
|
|
|
|
|
for i in first_item..last_item {
|
|
|
|
let indentation = (i % 100) as f32;
|
|
|
|
let x = ui.min_rect().left() + indentation;
|
|
|
|
let y = ui.min_rect().top() + i as f32 * row_height;
|
|
|
|
let text = format!(
|
|
|
|
"This is row {}/{}, indented by {} pixels",
|
|
|
|
i + 1,
|
|
|
|
num_rows,
|
|
|
|
indentation
|
|
|
|
);
|
|
|
|
let text_rect = ui.painter().text(
|
|
|
|
pos2(x, y),
|
|
|
|
Align2::LEFT_TOP,
|
|
|
|
text,
|
2022-01-24 13:32:36 +00:00
|
|
|
font_id.clone(),
|
2021-10-06 21:48:09 +00:00
|
|
|
ui.visuals().text_color(),
|
|
|
|
);
|
|
|
|
used_rect = used_rect.union(text_rect);
|
|
|
|
}
|
|
|
|
|
|
|
|
ui.allocate_rect(used_rect, Sense::hover()); // make sure it is visible!
|
|
|
|
});
|
2021-06-03 16:48:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
2021-09-29 06:45:13 +00:00
|
|
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
|
|
|
#[cfg_attr(feature = "serde", serde(default))]
|
2021-06-03 16:48:45 +00:00
|
|
|
#[derive(PartialEq)]
|
|
|
|
struct ScrollTo {
|
|
|
|
track_item: usize,
|
2022-02-15 15:52:29 +00:00
|
|
|
tack_item_align: Option<Align>,
|
2021-06-03 16:48:45 +00:00
|
|
|
offset: f32,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for ScrollTo {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
track_item: 25,
|
2022-02-15 15:52:29 +00:00
|
|
|
tack_item_align: Some(Align::Center),
|
2021-06-03 16:48:45 +00:00
|
|
|
offset: 0.0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl super::View for ScrollTo {
|
2021-01-25 19:43:41 +00:00
|
|
|
fn ui(&mut self, ui: &mut Ui) {
|
|
|
|
ui.label("This shows how you can scroll to a specific item or pixel offset");
|
|
|
|
|
|
|
|
let mut track_item = false;
|
|
|
|
let mut go_to_scroll_offset = false;
|
|
|
|
let mut scroll_top = false;
|
|
|
|
let mut scroll_bottom = false;
|
|
|
|
|
|
|
|
ui.horizontal(|ui| {
|
|
|
|
ui.label("Scroll to a specific item index:");
|
|
|
|
track_item |= ui
|
2021-03-27 15:07:18 +00:00
|
|
|
.add(Slider::new(&mut self.track_item, 1..=50).text("Track Item"))
|
2021-01-25 19:43:41 +00:00
|
|
|
.dragged();
|
|
|
|
});
|
|
|
|
|
|
|
|
ui.horizontal(|ui| {
|
|
|
|
ui.label("Item align:");
|
|
|
|
track_item |= ui
|
2022-02-15 15:52:29 +00:00
|
|
|
.radio_value(&mut self.tack_item_align, Some(Align::Min), "Top")
|
2021-01-25 19:43:41 +00:00
|
|
|
.clicked();
|
|
|
|
track_item |= ui
|
2022-02-15 15:52:29 +00:00
|
|
|
.radio_value(&mut self.tack_item_align, Some(Align::Center), "Center")
|
2021-01-25 19:43:41 +00:00
|
|
|
.clicked();
|
|
|
|
track_item |= ui
|
2022-02-15 15:52:29 +00:00
|
|
|
.radio_value(&mut self.tack_item_align, Some(Align::Max), "Bottom")
|
|
|
|
.clicked();
|
|
|
|
track_item |= ui
|
|
|
|
.radio_value(&mut self.tack_item_align, None, "None (Bring into view)")
|
2021-01-25 19:43:41 +00:00
|
|
|
.clicked();
|
|
|
|
});
|
|
|
|
|
|
|
|
ui.horizontal(|ui| {
|
|
|
|
ui.label("Scroll to a specific offset:");
|
|
|
|
go_to_scroll_offset |= ui
|
2021-03-27 15:09:09 +00:00
|
|
|
.add(DragValue::new(&mut self.offset).speed(1.0).suffix("px"))
|
2021-01-25 19:43:41 +00:00
|
|
|
.dragged();
|
|
|
|
});
|
|
|
|
|
|
|
|
ui.horizontal(|ui| {
|
|
|
|
scroll_top |= ui.button("Scroll to top").clicked();
|
|
|
|
scroll_bottom |= ui.button("Scroll to bottom").clicked();
|
|
|
|
});
|
|
|
|
|
2021-10-06 21:48:09 +00:00
|
|
|
let mut scroll_area = ScrollArea::vertical()
|
|
|
|
.max_height(200.0)
|
|
|
|
.auto_shrink([false; 2]);
|
2021-01-25 19:43:41 +00:00
|
|
|
if go_to_scroll_offset {
|
2021-11-01 18:43:27 +00:00
|
|
|
scroll_area = scroll_area.vertical_scroll_offset(self.offset);
|
2021-01-25 19:43:41 +00:00
|
|
|
}
|
|
|
|
|
2021-02-07 13:46:53 +00:00
|
|
|
ui.separator();
|
2022-01-26 21:19:32 +00:00
|
|
|
let (current_scroll, max_scroll) = scroll_area
|
|
|
|
.show(ui, |ui| {
|
|
|
|
if scroll_top {
|
2022-02-15 15:52:29 +00:00
|
|
|
ui.scroll_to_cursor(Some(Align::TOP));
|
2021-01-25 19:43:41 +00:00
|
|
|
}
|
2022-01-26 21:19:32 +00:00
|
|
|
ui.vertical(|ui| {
|
|
|
|
for item in 1..=50 {
|
|
|
|
if track_item && item == self.track_item {
|
|
|
|
let response =
|
|
|
|
ui.colored_label(Color32::YELLOW, format!("This is item {}", item));
|
|
|
|
response.scroll_to_me(self.tack_item_align);
|
|
|
|
} else {
|
|
|
|
ui.label(format!("This is item {}", item));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2021-01-25 19:43:41 +00:00
|
|
|
|
2022-01-26 21:19:32 +00:00
|
|
|
if scroll_bottom {
|
2022-02-15 15:52:29 +00:00
|
|
|
ui.scroll_to_cursor(Some(Align::BOTTOM));
|
2022-01-26 21:19:32 +00:00
|
|
|
}
|
2021-01-25 19:43:41 +00:00
|
|
|
|
2022-01-26 21:19:32 +00:00
|
|
|
let margin = ui.visuals().clip_rect_margin;
|
2021-01-25 19:43:41 +00:00
|
|
|
|
2022-01-26 21:19:32 +00:00
|
|
|
let current_scroll = ui.clip_rect().top() - ui.min_rect().top() + margin;
|
|
|
|
let max_scroll = ui.min_rect().height() - ui.clip_rect().height() + 2.0 * margin;
|
|
|
|
(current_scroll, max_scroll)
|
|
|
|
})
|
|
|
|
.inner;
|
2021-02-07 13:46:53 +00:00
|
|
|
ui.separator();
|
|
|
|
|
|
|
|
ui.label(format!(
|
|
|
|
"Scroll offset: {:.0}/{:.0} px",
|
|
|
|
current_scroll, max_scroll
|
|
|
|
));
|
2021-01-25 19:43:41 +00:00
|
|
|
|
2021-02-07 13:46:53 +00:00
|
|
|
ui.separator();
|
|
|
|
ui.vertical_centered(|ui| {
|
|
|
|
egui::reset_button(ui, self);
|
|
|
|
ui.add(crate::__egui_github_link_file!());
|
|
|
|
});
|
2021-01-25 19:43:41 +00:00
|
|
|
}
|
|
|
|
}
|
2021-10-09 10:59:42 +00:00
|
|
|
|
|
|
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
|
|
|
#[cfg_attr(feature = "serde", serde(default))]
|
2022-01-16 21:13:22 +00:00
|
|
|
#[derive(Default, PartialEq)]
|
2021-10-09 10:59:42 +00:00
|
|
|
struct ScrollStickTo {
|
|
|
|
n_items: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl super::View for ScrollStickTo {
|
|
|
|
fn ui(&mut self, ui: &mut Ui) {
|
|
|
|
ui.label("Rows enter from the bottom, we want the scroll handle to start and stay at bottom unless moved");
|
|
|
|
|
|
|
|
ui.add_space(4.0);
|
|
|
|
|
|
|
|
let text_style = TextStyle::Body;
|
2022-01-24 13:32:36 +00:00
|
|
|
let row_height = ui.text_style_height(&text_style);
|
2021-10-09 10:59:42 +00:00
|
|
|
ScrollArea::vertical().stick_to_bottom().show_rows(
|
|
|
|
ui,
|
|
|
|
row_height,
|
|
|
|
self.n_items,
|
|
|
|
|ui, row_range| {
|
|
|
|
for row in row_range {
|
|
|
|
let text = format!("This is row {}", row + 1);
|
|
|
|
ui.label(text);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
|
|
|
self.n_items += 1;
|
|
|
|
ui.ctx().request_repaint();
|
|
|
|
}
|
|
|
|
}
|