mirror of
https://github.com/emilk/egui.git
synced 2026-09-02 06:40:06 -04:00
Implement full bleed scrollarea
This commit is contained in:
@@ -361,6 +361,8 @@ pub struct ScrollArea {
|
|||||||
content_margin: Option<Margin>,
|
content_margin: Option<Margin>,
|
||||||
overflow_margin: Option<Margin>,
|
overflow_margin: Option<Margin>,
|
||||||
|
|
||||||
|
extend_into_parent_margin: bool,
|
||||||
|
|
||||||
/// If true for vertical or horizontal the scroll wheel will stick to the
|
/// If true for vertical or horizontal the scroll wheel will stick to the
|
||||||
/// end position until user manually changes position. It will become true
|
/// end position until user manually changes position. It will become true
|
||||||
/// again once scroll handle makes contact with end.
|
/// again once scroll handle makes contact with end.
|
||||||
@@ -415,6 +417,7 @@ impl ScrollArea {
|
|||||||
wheel_scroll_multiplier: Vec2::splat(1.0),
|
wheel_scroll_multiplier: Vec2::splat(1.0),
|
||||||
content_margin: None,
|
content_margin: None,
|
||||||
overflow_margin: None,
|
overflow_margin: None,
|
||||||
|
extend_into_parent_margin: false,
|
||||||
stick_to_end: Vec2b::FALSE,
|
stick_to_end: Vec2b::FALSE,
|
||||||
animated: true,
|
animated: true,
|
||||||
}
|
}
|
||||||
@@ -654,6 +657,29 @@ impl ScrollArea {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Grow into the inner margin of the closest parent [`crate::Frame`], e.g. a
|
||||||
|
/// [`crate::Popup`] or a [`crate::containers::menu::MenuButton`] menu.
|
||||||
|
///
|
||||||
|
/// The viewport, the clip rect and the scroll bar then reach all the way to the
|
||||||
|
/// edge of the frame, while the margin is added to [`Self::content_margin`],
|
||||||
|
/// so the contents keep the same padding as before.
|
||||||
|
///
|
||||||
|
/// The scroll area paints into the margin, but does not allocate it: the frame
|
||||||
|
/// adds its margin back around the rect the scroll area painted into, so the
|
||||||
|
/// frame ends up the same size as it would be without this.
|
||||||
|
///
|
||||||
|
/// Only the sides where the scroll area is flush with the frame are used, so a
|
||||||
|
/// widget added _before_ the scroll area keeps its normal padding. A widget added
|
||||||
|
/// _after_ the scroll area would be overlapped by it, so reserve the space for it
|
||||||
|
/// first, e.g. with [`Layout::bottom_up`](crate::Layout::bottom_up).
|
||||||
|
///
|
||||||
|
/// Default: `false`.
|
||||||
|
#[inline]
|
||||||
|
pub fn extend_into_parent_margin(mut self, extend: bool) -> Self {
|
||||||
|
self.extend_into_parent_margin = extend;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// The scroll handle will stick to the rightmost position even while the content size
|
/// The scroll handle will stick to the rightmost position even while the content size
|
||||||
/// changes dynamically. This can be useful to simulate text scrollers coming in from right
|
/// changes dynamically. This can be useful to simulate text scrollers coming in from right
|
||||||
/// hand side. The scroll handle remains stuck until user manually changes position. Once "unstuck"
|
/// hand side. The scroll handle remains stuck until user manually changes position. Once "unstuck"
|
||||||
@@ -708,6 +734,11 @@ struct Prepared {
|
|||||||
/// Where on the screen the content is (excludes scroll bars; includes `content_margin`).
|
/// Where on the screen the content is (excludes scroll bars; includes `content_margin`).
|
||||||
inner_rect: Rect,
|
inner_rect: Rect,
|
||||||
|
|
||||||
|
/// The part of the parent frame's inner margin that we paint into, but do not allocate.
|
||||||
|
///
|
||||||
|
/// See [`ScrollArea::extend_into_parent_margin`].
|
||||||
|
claimed_margin: Margin,
|
||||||
|
|
||||||
content_ui: Ui,
|
content_ui: Ui,
|
||||||
|
|
||||||
/// 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.
|
||||||
@@ -746,6 +777,7 @@ impl ScrollArea {
|
|||||||
wheel_scroll_multiplier,
|
wheel_scroll_multiplier,
|
||||||
content_margin: _, // Used elsewhere
|
content_margin: _, // Used elsewhere
|
||||||
overflow_margin,
|
overflow_margin,
|
||||||
|
extend_into_parent_margin,
|
||||||
stick_to_end,
|
stick_to_end,
|
||||||
animated,
|
animated,
|
||||||
} = self;
|
} = self;
|
||||||
@@ -782,7 +814,16 @@ impl ScrollArea {
|
|||||||
show_bars_factor.yx() * scroll_style.allocated_width()
|
show_bars_factor.yx() * scroll_style.allocated_width()
|
||||||
};
|
};
|
||||||
|
|
||||||
let available_outer = ui.available_rect_before_wrap();
|
// We paint into the margin of the parent frame, but we don't _allocate_ it.
|
||||||
|
// The frame will then add its margin around the rect we paint into, so it ends up
|
||||||
|
// exactly where the contents already are. See `Self::extend_into_parent_margin`.
|
||||||
|
let claimed_margin = if extend_into_parent_margin {
|
||||||
|
claimable_parent_margin(ui)
|
||||||
|
} else {
|
||||||
|
Margin::ZERO
|
||||||
|
};
|
||||||
|
|
||||||
|
let available_outer = ui.available_rect_before_wrap() + claimed_margin;
|
||||||
|
|
||||||
let outer_size = available_outer.size().at_most(max_size);
|
let outer_size = available_outer.size().at_most(max_size);
|
||||||
|
|
||||||
@@ -979,6 +1020,7 @@ impl ScrollArea {
|
|||||||
scroll_bar_visibility,
|
scroll_bar_visibility,
|
||||||
scroll_bar_rect,
|
scroll_bar_rect,
|
||||||
inner_rect,
|
inner_rect,
|
||||||
|
claimed_margin,
|
||||||
content_ui,
|
content_ui,
|
||||||
viewport,
|
viewport,
|
||||||
scroll_source,
|
scroll_source,
|
||||||
@@ -1067,14 +1109,17 @@ impl ScrollArea {
|
|||||||
ui: &mut Ui,
|
ui: &mut Ui,
|
||||||
add_contents: Box<dyn FnOnce(&mut Ui, Rect) -> R + 'c>,
|
add_contents: Box<dyn FnOnce(&mut Ui, Rect) -> R + 'c>,
|
||||||
) -> ScrollAreaOutput<R> {
|
) -> ScrollAreaOutput<R> {
|
||||||
let margin = self
|
let content_margin = self.content_margin;
|
||||||
.content_margin
|
|
||||||
.unwrap_or_else(|| ui.spacing().scroll.content_margin);
|
|
||||||
|
|
||||||
let mut prepared = self.begin(ui);
|
let mut prepared = self.begin(ui);
|
||||||
let id = prepared.id;
|
let id = prepared.id;
|
||||||
let inner_rect = prepared.inner_rect;
|
let inner_rect = prepared.inner_rect;
|
||||||
|
|
||||||
|
// The margin we took over from the parent frame is applied to the contents instead,
|
||||||
|
// so they keep the same padding:
|
||||||
|
let margin = content_margin.unwrap_or_else(|| ui.spacing().scroll.content_margin)
|
||||||
|
+ prepared.claimed_margin;
|
||||||
|
|
||||||
let inner = crate::Frame::NONE
|
let inner = crate::Frame::NONE
|
||||||
.inner_margin(margin)
|
.inner_margin(margin)
|
||||||
.show(&mut prepared.content_ui, |ui| {
|
.show(&mut prepared.content_ui, |ui| {
|
||||||
@@ -1106,6 +1151,7 @@ impl Prepared {
|
|||||||
current_bar_use,
|
current_bar_use,
|
||||||
scroll_bar_visibility,
|
scroll_bar_visibility,
|
||||||
scroll_bar_rect,
|
scroll_bar_rect,
|
||||||
|
claimed_margin,
|
||||||
content_ui,
|
content_ui,
|
||||||
viewport: _,
|
viewport: _,
|
||||||
scroll_source,
|
scroll_source,
|
||||||
@@ -1306,10 +1352,11 @@ impl Prepared {
|
|||||||
|
|
||||||
let scroll_style = ui.spacing().scroll;
|
let scroll_style = ui.spacing().scroll;
|
||||||
|
|
||||||
// Reserve the scroll area before painting fades, because fade painting uses ui.min_rect().
|
// We paint into the margin of the parent frame, but we allocate only the rect we would
|
||||||
ui.advance_cursor_after_rect(outer_rect);
|
// have used without it. The frame then adds that margin back around what we painted.
|
||||||
|
ui.advance_cursor_after_rect(shrink_at_least_to_nothing(outer_rect, claimed_margin));
|
||||||
|
|
||||||
paint_fade_areas_impl(ui, inner_rect, content_size, state.offset);
|
paint_fade_areas_impl(ui, inner_rect, claimed_margin, content_size, state.offset);
|
||||||
|
|
||||||
// Paint the bars:
|
// Paint the bars:
|
||||||
let scroll_bar_rect = scroll_bar_rect.unwrap_or(inner_rect);
|
let scroll_bar_rect = scroll_bar_rect.unwrap_or(inner_rect);
|
||||||
@@ -1599,7 +1646,13 @@ impl Prepared {
|
|||||||
|
|
||||||
/// Paint fade-out gradients at the top and/or bottom of a scroll area to
|
/// Paint fade-out gradients at the top and/or bottom of a scroll area to
|
||||||
/// indicate that more content is available beyond the visible region.
|
/// indicate that more content is available beyond the visible region.
|
||||||
fn paint_fade_areas_impl(ui: &Ui, inner_rect: Rect, content_size: Vec2, offset: Vec2) {
|
fn paint_fade_areas_impl(
|
||||||
|
ui: &Ui,
|
||||||
|
inner_rect: Rect,
|
||||||
|
corner_inset: Margin,
|
||||||
|
content_size: Vec2,
|
||||||
|
offset: Vec2,
|
||||||
|
) {
|
||||||
let crate::style::ScrollFadeStyle {
|
let crate::style::ScrollFadeStyle {
|
||||||
strength,
|
strength,
|
||||||
size: fade_size,
|
size: fade_size,
|
||||||
@@ -1613,15 +1666,31 @@ fn paint_fade_areas_impl(ui: &Ui, inner_rect: Rect, content_size: Vec2, offset:
|
|||||||
|
|
||||||
let overflow = content_size - inner_rect.size();
|
let overflow = content_size - inner_rect.size();
|
||||||
|
|
||||||
let paint_rect = inner_rect.intersect(ui.min_rect());
|
let paint_rect = inner_rect.intersect(ui.min_rect().union(inner_rect));
|
||||||
|
|
||||||
|
// A fade runs along one edge. We keep it clear of the corners of the parent frame by
|
||||||
|
// insetting it _across_ its direction, so it cannot paint over a rounded corner.
|
||||||
|
// No content can be there anyway, because it is inset by the same margin.
|
||||||
|
let horizontal_fade_rect = paint_rect
|
||||||
|
- Margin {
|
||||||
|
left: corner_inset.left,
|
||||||
|
right: corner_inset.right,
|
||||||
|
..Margin::ZERO
|
||||||
|
};
|
||||||
|
let vertical_fade_rect = paint_rect
|
||||||
|
- Margin {
|
||||||
|
top: corner_inset.top,
|
||||||
|
bottom: corner_inset.bottom,
|
||||||
|
..Margin::ZERO
|
||||||
|
};
|
||||||
|
|
||||||
// Top fade: animate opacity based on how far we've scrolled down.
|
// Top fade: animate opacity based on how far we've scrolled down.
|
||||||
if 0.0 < offset.y {
|
if 0.0 < offset.y {
|
||||||
let t = (offset.y / fade_size).clamp(0.0, 1.0) * strength;
|
let t = (offset.y / fade_size).clamp(0.0, 1.0) * strength;
|
||||||
let bg_faded = bg.gamma_multiply(t);
|
let bg_faded = bg.gamma_multiply(t);
|
||||||
let rect = Rect::from_min_max(
|
let rect = Rect::from_min_max(
|
||||||
paint_rect.left_top(),
|
horizontal_fade_rect.left_top(),
|
||||||
pos2(paint_rect.right(), paint_rect.top() + fade_size),
|
pos2(horizontal_fade_rect.right(), paint_rect.top() + fade_size),
|
||||||
);
|
);
|
||||||
ui.painter().add(Shape::gradient_rect(
|
ui.painter().add(Shape::gradient_rect(
|
||||||
rect,
|
rect,
|
||||||
@@ -1636,8 +1705,8 @@ fn paint_fade_areas_impl(ui: &Ui, inner_rect: Rect, content_size: Vec2, offset:
|
|||||||
let t = (distance_from_bottom / fade_size).clamp(0.0, 1.0) * strength;
|
let t = (distance_from_bottom / fade_size).clamp(0.0, 1.0) * strength;
|
||||||
let bg_faded = bg.gamma_multiply(t);
|
let bg_faded = bg.gamma_multiply(t);
|
||||||
let rect = Rect::from_min_max(
|
let rect = Rect::from_min_max(
|
||||||
pos2(paint_rect.left(), paint_rect.bottom() - fade_size),
|
pos2(horizontal_fade_rect.left(), paint_rect.bottom() - fade_size),
|
||||||
paint_rect.right_bottom(),
|
horizontal_fade_rect.right_bottom(),
|
||||||
);
|
);
|
||||||
ui.painter().add(Shape::gradient_rect(
|
ui.painter().add(Shape::gradient_rect(
|
||||||
rect,
|
rect,
|
||||||
@@ -1651,8 +1720,8 @@ fn paint_fade_areas_impl(ui: &Ui, inner_rect: Rect, content_size: Vec2, offset:
|
|||||||
let t = (offset.x / fade_size).clamp(0.0, 1.0) * strength;
|
let t = (offset.x / fade_size).clamp(0.0, 1.0) * strength;
|
||||||
let bg_faded = bg.gamma_multiply(t);
|
let bg_faded = bg.gamma_multiply(t);
|
||||||
let rect = Rect::from_min_max(
|
let rect = Rect::from_min_max(
|
||||||
paint_rect.left_top(),
|
vertical_fade_rect.left_top(),
|
||||||
pos2(paint_rect.left() + fade_size, paint_rect.bottom()),
|
pos2(paint_rect.left() + fade_size, vertical_fade_rect.bottom()),
|
||||||
);
|
);
|
||||||
ui.painter().add(Shape::gradient_rect(
|
ui.painter().add(Shape::gradient_rect(
|
||||||
rect,
|
rect,
|
||||||
@@ -1667,8 +1736,8 @@ fn paint_fade_areas_impl(ui: &Ui, inner_rect: Rect, content_size: Vec2, offset:
|
|||||||
let t = (distance_from_right / fade_size).clamp(0.0, 1.0) * strength;
|
let t = (distance_from_right / fade_size).clamp(0.0, 1.0) * strength;
|
||||||
let bg_faded = bg.gamma_multiply(t);
|
let bg_faded = bg.gamma_multiply(t);
|
||||||
let rect = Rect::from_min_max(
|
let rect = Rect::from_min_max(
|
||||||
pos2(paint_rect.right() - fade_size, paint_rect.top()),
|
pos2(paint_rect.right() - fade_size, vertical_fade_rect.top()),
|
||||||
paint_rect.right_bottom(),
|
vertical_fade_rect.right_bottom(),
|
||||||
);
|
);
|
||||||
ui.painter().add(Shape::gradient_rect(
|
ui.painter().add(Shape::gradient_rect(
|
||||||
rect,
|
rect,
|
||||||
@@ -1677,3 +1746,61 @@ fn paint_fade_areas_impl(ui: &Ui, inner_rect: Rect, content_size: Vec2, offset:
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The inner margin of the closest parent [`crate::Frame`] that a [`ScrollArea`] may paint into.
|
||||||
|
///
|
||||||
|
/// Only the sides that the scroll area is flush with are returned; the others are zero, so that
|
||||||
|
/// e.g. a widget above the scroll area keeps its normal padding.
|
||||||
|
///
|
||||||
|
/// See [`ScrollArea::extend_into_parent_margin`].
|
||||||
|
fn claimable_parent_margin(ui: &Ui) -> Margin {
|
||||||
|
let mut frame_node = None;
|
||||||
|
for node in ui.stack().iter() {
|
||||||
|
if node.frame().inner_margin != Margin::ZERO {
|
||||||
|
frame_node = Some(node);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if node.is_area_ui() || node.kind() == Some(UiKind::ScrollArea) {
|
||||||
|
// Don't reach outside of the closest container.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let Some(frame_node) = frame_node else {
|
||||||
|
return Margin::ZERO;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The rect the frame gave its contents, i.e. the frame rect minus the inner margin.
|
||||||
|
// If we are the content `Ui` of the frame we use its current `max_rect`, which honors
|
||||||
|
// e.g. `Ui::set_width`. The rect in the stack is a snapshot from when the `Ui` was created.
|
||||||
|
let frame_rect = if frame_node.id == ui.unique_id() {
|
||||||
|
ui.max_rect()
|
||||||
|
} else {
|
||||||
|
frame_node.max_rect
|
||||||
|
};
|
||||||
|
let full_margin = frame_node.frame().inner_margin;
|
||||||
|
let available = ui.available_rect_before_wrap();
|
||||||
|
|
||||||
|
// Only take over the sides we are flush with:
|
||||||
|
let tolerance = 0.1;
|
||||||
|
let mut margin = Margin::ZERO;
|
||||||
|
if available.left() <= frame_rect.left() + tolerance {
|
||||||
|
margin.left = full_margin.left;
|
||||||
|
}
|
||||||
|
if available.top() <= frame_rect.top() + tolerance {
|
||||||
|
margin.top = full_margin.top;
|
||||||
|
}
|
||||||
|
if frame_rect.right() - tolerance <= available.right() {
|
||||||
|
margin.right = full_margin.right;
|
||||||
|
}
|
||||||
|
if frame_rect.bottom() - tolerance <= available.bottom() {
|
||||||
|
margin.bottom = full_margin.bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
margin
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shrink the rect by the margin, but never past nothing.
|
||||||
|
fn shrink_at_least_to_nothing(rect: Rect, margin: Margin) -> Rect {
|
||||||
|
let shrunk = rect - margin;
|
||||||
|
Rect::from_min_max(shrunk.min, shrunk.max.max(shrunk.min))
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use egui::color_picker::{Alpha, color_picker_color32};
|
|||||||
use egui::containers::menu::{MenuConfig, SubMenuButton};
|
use egui::containers::menu::{MenuConfig, SubMenuButton};
|
||||||
use egui::{
|
use egui::{
|
||||||
Align, Align2, Atom, Button, ComboBox, Frame, Id, Layout, Popup, PopupCloseBehavior, RectAlign,
|
Align, Align2, Atom, Button, ComboBox, Frame, Id, Layout, Popup, PopupCloseBehavior, RectAlign,
|
||||||
RichText, Tooltip, Ui, UiBuilder, include_image,
|
RichText, ScrollArea, Tooltip, Ui, UiBuilder, include_image,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Showcase [`Popup`].
|
/// Showcase [`Popup`].
|
||||||
@@ -66,6 +66,57 @@ impl PopupsDemo {
|
|||||||
ui.close();
|
ui.close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
ui.menu_button("Full-bleed ScrollArea", |ui| {
|
||||||
|
ui.menu_button("…with a header", |ui| {
|
||||||
|
ui.set_width(180.0);
|
||||||
|
|
||||||
|
// The header is added before the scroll area, so it keeps the padding
|
||||||
|
// of the menu frame:
|
||||||
|
ui.label(RichText::new("Pick a number").strong());
|
||||||
|
|
||||||
|
ScrollArea::vertical()
|
||||||
|
.max_height(150.0)
|
||||||
|
.auto_shrink([false, true])
|
||||||
|
// The scroll area is flush with the left, right and bottom of the
|
||||||
|
// menu frame, so it grows into the padding on those sides. The scroll
|
||||||
|
// bar ends up at the very edge of the menu:
|
||||||
|
.extend_into_parent_margin(true)
|
||||||
|
.show(ui, |ui| {
|
||||||
|
for i in 0..30 {
|
||||||
|
if ui.button(format!("Item {i}")).clicked() {
|
||||||
|
ui.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ui.menu_button("…with a footer", |ui| {
|
||||||
|
ui.set_width(180.0);
|
||||||
|
ui.set_height(200.0);
|
||||||
|
|
||||||
|
// A widget _after_ the scroll area would be overlapped by it, so we
|
||||||
|
// reserve the space for the footer first, from the bottom up:
|
||||||
|
ui.with_layout(Layout::bottom_up(Align::Min), |ui| {
|
||||||
|
if ui.button("Footers keep their padding").clicked() {
|
||||||
|
ui.close();
|
||||||
|
}
|
||||||
|
ui.separator();
|
||||||
|
|
||||||
|
ui.with_layout(Layout::top_down(Align::Min), |ui| {
|
||||||
|
ScrollArea::vertical()
|
||||||
|
.auto_shrink(false)
|
||||||
|
.extend_into_parent_margin(true)
|
||||||
|
.show(ui, |ui| {
|
||||||
|
for i in 0..30 {
|
||||||
|
if ui.button(format!("Item {i}")).clicked() {
|
||||||
|
ui.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
ui.add_enabled_ui(false, |ui| {
|
ui.add_enabled_ui(false, |ui| {
|
||||||
ui.menu_button("SubMenus can be disabled", |_| {});
|
ui.menu_button("SubMenus can be disabled", |_| {});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -175,3 +175,56 @@ fn test_interactive_tooltip() {
|
|||||||
|
|
||||||
assert!(harness.state().link_clicked);
|
assert!(harness.state().link_clicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "snapshot", feature = "wgpu"))]
|
||||||
|
#[test]
|
||||||
|
fn scroll_area_extends_into_popup_margin() {
|
||||||
|
fn scroll_area(ui: &mut egui::Ui, extend: bool) {
|
||||||
|
egui::ScrollArea::vertical()
|
||||||
|
.max_height(110.0)
|
||||||
|
.auto_shrink([false, true])
|
||||||
|
.extend_into_parent_margin(extend)
|
||||||
|
.show(ui, |ui| {
|
||||||
|
for i in 0..20 {
|
||||||
|
_ = ui.selectable_label(i == 2, format!("Item {i}"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn popup_with_scroll_area(ui: &mut egui::Ui, label: &str, extend: bool, nested: bool) {
|
||||||
|
let response = ui.button(label);
|
||||||
|
Popup::from_response(&response).open(true).show(|ui| {
|
||||||
|
ui.set_width(120.0);
|
||||||
|
if nested {
|
||||||
|
// The scroll area is not a direct child of the popup frame here,
|
||||||
|
// so we must find the frame by walking up the `UiStack`:
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
ui.label("Header");
|
||||||
|
scroll_area(ui, extend);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
ui.label("Header");
|
||||||
|
scroll_area(ui, extend);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut harness = Harness::builder()
|
||||||
|
.with_size(egui::Vec2::new(600.0, 220.0))
|
||||||
|
.with_pixels_per_point(2.0)
|
||||||
|
.build_ui(|ui| {
|
||||||
|
// Solid scroll bars make it easy to see where the scroll area ends:
|
||||||
|
ui.ctx()
|
||||||
|
.all_styles_mut(|style| style.spacing.scroll = egui::style::ScrollStyle::solid());
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
popup_with_scroll_area(ui, "normal", false, false);
|
||||||
|
ui.add_space(140.0);
|
||||||
|
popup_with_scroll_area(ui, "full bleed", true, false);
|
||||||
|
ui.add_space(140.0);
|
||||||
|
popup_with_scroll_area(ui, "full bleed, nested", true, true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
harness.run();
|
||||||
|
harness.snapshot("popup_full_bleed_scroll_area");
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:d817452786ded288a2e62a1c45066e8b23b1582880fded27a434aabd8298bd3e
|
||||||
|
size 54764
|
||||||
Reference in New Issue
Block a user