diff --git a/CHANGELOG.md b/CHANGELOG.md index cf8ee8bd..e35ef26d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. * `TextEdit` now supports edits on a generic buffer using `TextBuffer`. * 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 🔧 * Plot: Changed `Curve` to `Line`. diff --git a/egui/src/containers/scroll_area.rs b/egui/src/containers/scroll_area.rs index 286670b9..4cdc2db2 100644 --- a/egui/src/containers/scroll_area.rs +++ b/egui/src/containers/scroll_area.rs @@ -36,6 +36,7 @@ pub struct ScrollArea { always_show_scroll: bool, id_source: Option, offset: Option, + scrolling_enabled: bool, } impl ScrollArea { @@ -51,6 +52,7 @@ impl ScrollArea { always_show_scroll: false, id_source: None, offset: None, + scrolling_enabled: true, } } @@ -75,6 +77,17 @@ impl ScrollArea { self.offset = Some(Vec2::new(0.0, offset)); 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 { @@ -87,6 +100,7 @@ struct Prepared { /// Relative coordinates: the offset and size of the view of the inner UI. /// `viewport.min == ZERO` means we scrolled to the top. viewport: Rect, + scrolling_enabled: bool, } impl ScrollArea { @@ -96,6 +110,7 @@ impl ScrollArea { always_show_scroll, id_source, offset, + scrolling_enabled, } = self; let ctx = ui.ctx().clone(); @@ -152,6 +167,7 @@ impl ScrollArea { inner_rect, content_ui, viewport, + scrolling_enabled, } } @@ -229,6 +245,7 @@ impl Prepared { mut current_scroll_bar_width, content_ui, viewport: _, + scrolling_enabled, } = self; let content_size = content_ui.min_size(); @@ -268,7 +285,12 @@ impl Prepared { if content_is_too_small { // 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(); if content_response.dragged() { @@ -293,7 +315,7 @@ impl Prepared { } 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 scroll_delta = frame_state.scroll_delta; @@ -340,7 +362,12 @@ impl Prepared { ); 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() { 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 { rect: outer_scroll_rect,