Freeze scroll area (#472)

* added ScrollArea::enable_scrolling

* also freeze dragging and scroll-bar

* fixed styling of inactive scrollbar

* fixed docs (backtick-quoted TextEdit)

Co-authored-by: edko99 <edko@jouzz.com>
This commit is contained in:
edko99 2021-06-12 05:30:14 -07:00 committed by GitHub
parent 02db9ee583
commit e007afc3c3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 36 additions and 4 deletions

View file

@ -21,6 +21,7 @@ NOTE: [`eframe`](eframe/CHANGELOG.md), [`egui_web`](egui_web/CHANGELOG.md) and [
* Add features `extra_asserts` and `extra_debug_asserts` to enable additional checks. * Add features `extra_asserts` and `extra_debug_asserts` to enable additional checks.
* `TextEdit` now supports edits on a generic buffer using `TextBuffer`. * `TextEdit` now supports edits on a generic buffer using `TextBuffer`.
* Add `Context::set_debug_on_hover` and `egui::trace!(ui)` * Add `Context::set_debug_on_hover` and `egui::trace!(ui)`
* Add `ScrollArea::enable_scrolling` to allow freezing scrolling when editing TextEdit widgets within it
### Changed 🔧 ### Changed 🔧
* Plot: Changed `Curve` to `Line`. * Plot: Changed `Curve` to `Line`.

View file

@ -36,6 +36,7 @@ pub struct ScrollArea {
always_show_scroll: bool, always_show_scroll: bool,
id_source: Option<Id>, id_source: Option<Id>,
offset: Option<Vec2>, offset: Option<Vec2>,
scrolling_enabled: bool,
} }
impl ScrollArea { impl ScrollArea {
@ -51,6 +52,7 @@ impl ScrollArea {
always_show_scroll: false, always_show_scroll: false,
id_source: None, id_source: None,
offset: None, offset: None,
scrolling_enabled: true,
} }
} }
@ -75,6 +77,17 @@ impl ScrollArea {
self.offset = Some(Vec2::new(0.0, offset)); self.offset = Some(Vec2::new(0.0, offset));
self self
} }
/// Control the scrolling behavior
/// If `true` (default), the scroll area will respond to user scrolling
/// If `false`, the scroll area will not respond to user scrolling
///
/// This can be used, for example, to optionally freeze scrolling while the user
/// is inputing text in a `TextEdit` widget contained within the scroll area
pub fn enable_scrolling(mut self, enable: bool) -> Self {
self.scrolling_enabled = enable;
self
}
} }
struct Prepared { struct Prepared {
@ -87,6 +100,7 @@ struct Prepared {
/// Relative coordinates: the offset and size of the view of the inner UI. /// Relative coordinates: the offset and size of the view of the inner UI.
/// `viewport.min == ZERO` means we scrolled to the top. /// `viewport.min == ZERO` means we scrolled to the top.
viewport: Rect, viewport: Rect,
scrolling_enabled: bool,
} }
impl ScrollArea { impl ScrollArea {
@ -96,6 +110,7 @@ impl ScrollArea {
always_show_scroll, always_show_scroll,
id_source, id_source,
offset, offset,
scrolling_enabled,
} = self; } = self;
let ctx = ui.ctx().clone(); let ctx = ui.ctx().clone();
@ -152,6 +167,7 @@ impl ScrollArea {
inner_rect, inner_rect,
content_ui, content_ui,
viewport, viewport,
scrolling_enabled,
} }
} }
@ -229,6 +245,7 @@ impl Prepared {
mut current_scroll_bar_width, mut current_scroll_bar_width,
content_ui, content_ui,
viewport: _, viewport: _,
scrolling_enabled,
} = self; } = self;
let content_size = content_ui.min_size(); let content_size = content_ui.min_size();
@ -268,7 +285,12 @@ impl Prepared {
if content_is_too_small { if content_is_too_small {
// Drag contents to scroll (for touch screens mostly): // Drag contents to scroll (for touch screens mostly):
let content_response = ui.interact(inner_rect, id.with("area"), Sense::drag()); let sense = if self.scrolling_enabled {
Sense::drag()
} else {
Sense::hover()
};
let content_response = ui.interact(inner_rect, id.with("area"), sense);
let input = ui.input(); let input = ui.input();
if content_response.dragged() { if content_response.dragged() {
@ -293,7 +315,7 @@ impl Prepared {
} }
let max_offset = content_size.y - inner_rect.height(); let max_offset = content_size.y - inner_rect.height();
if ui.rect_contains_pointer(outer_rect) { if scrolling_enabled && ui.rect_contains_pointer(outer_rect) {
let mut frame_state = ui.ctx().frame_state(); let mut frame_state = ui.ctx().frame_state();
let scroll_delta = frame_state.scroll_delta; let scroll_delta = frame_state.scroll_delta;
@ -340,7 +362,12 @@ impl Prepared {
); );
let interact_id = id.with("vertical"); let interact_id = id.with("vertical");
let response = ui.interact(outer_scroll_rect, interact_id, Sense::click_and_drag()); let sense = if self.scrolling_enabled {
Sense::click_and_drag()
} else {
Sense::hover()
};
let response = ui.interact(outer_scroll_rect, interact_id, sense);
if let Some(pointer_pos) = response.interact_pointer_pos() { if let Some(pointer_pos) = response.interact_pointer_pos() {
let scroll_start_offset_from_top = let scroll_start_offset_from_top =
@ -383,7 +410,11 @@ impl Prepared {
); );
} }
let visuals = ui.style().interact(&response); let visuals = if scrolling_enabled {
ui.style().interact(&response)
} else {
&ui.style().visuals.widgets.inactive
};
ui.painter().add(epaint::Shape::Rect { ui.painter().add(epaint::Shape::Rect {
rect: outer_scroll_rect, rect: outer_scroll_rect,