[culling] full widget culling

This commit is contained in:
Emil Ernerfeldt 2020-10-10 07:23:02 +02:00
parent 7abb9a2814
commit 9112834f20
16 changed files with 179 additions and 109 deletions

View file

@ -180,6 +180,8 @@ impl CollapsingHeader {
let id = ui.make_persistent_id(id_source); let id = ui.make_persistent_id(id_source);
let mut state = State::from_memory_with_default_open(ui.ctx(), id, default_open);
let available = ui.available_finite(); let available = ui.available_finite();
let text_pos = available.min + vec2(ui.style().spacing.indent, 0.0); let text_pos = available.min + vec2(ui.style().spacing.indent, 0.0);
let galley = label.layout_width(ui, available.right() - text_pos.x); let galley = label.layout_width(ui, available.right() - text_pos.x);
@ -192,15 +194,16 @@ impl CollapsingHeader {
galley.size.y + 2.0 * ui.style().spacing.button_padding.y, galley.size.y + 2.0 * ui.style().spacing.button_padding.y,
); );
desired_size = desired_size.at_least(ui.style().spacing.interact_size); desired_size = desired_size.at_least(ui.style().spacing.interact_size);
let rect = ui.allocate_space(desired_size);
let header_response = ui.interact(rect, id, Sense::click()); let header_response;
if let Some(rect) = ui.request_space(desired_size) {
header_response = ui.interact(rect, id, Sense::click());
let text_pos = pos2( let text_pos = pos2(
text_pos.x, text_pos.x,
header_response.rect.center().y - galley.size.y / 2.0, header_response.rect.center().y - galley.size.y / 2.0,
); );
let mut state = State::from_memory_with_default_open(ui.ctx(), id, default_open);
if header_response.clicked { if header_response.clicked {
state.toggle(ui); state.toggle(ui);
} }
@ -238,6 +241,9 @@ impl CollapsingHeader {
stroke: Default::default(), stroke: Default::default(),
}, },
); );
} else {
header_response = Default::default();
}
Prepared { Prepared {
id, id,

View file

@ -38,7 +38,7 @@ pub fn combo_box(
let advance = full_minimum_width - icon_width - ui.min_rect().width(); let advance = full_minimum_width - icon_width - ui.min_rect().width();
ui.advance_cursor(advance.at_least(0.0)); ui.advance_cursor(advance.at_least(0.0));
let icon_rect = ui.allocate_space(Vec2::splat(icon_width)); let icon_rect = unwrap_or_return_default!(ui.request_space(Vec2::splat(icon_width)));
let button_rect = ui.min_rect().expand2(ui.style().spacing.button_padding); let button_rect = ui.min_rect().expand2(ui.style().spacing.button_padding);
let mut response = ui.interact(button_rect, button_id, Sense::click()); let mut response = ui.interact(button_rect, button_id, Sense::click());
response.active |= button_active; response.active |= button_active;
@ -91,6 +91,7 @@ fn button_frame(
add_contents(&mut content_ui); add_contents(&mut content_ui);
let outer_rect = Rect::from_min_max(outer_rect_bounds.min, content_ui.min_rect().max + margin); let outer_rect = Rect::from_min_max(outer_rect_bounds.min, content_ui.min_rect().max + margin);
ui.allocate_space(outer_rect.size());
let mut response = ui.interact(outer_rect, id, sense); let mut response = ui.interact(outer_rect, id, sense);
response.active |= button_active; response.active |= button_active;
@ -106,8 +107,6 @@ fn button_frame(
}, },
); );
ui.allocate_space(outer_rect.size());
response response
} }

View file

@ -436,7 +436,7 @@ impl Context {
if id.is_none() || sense == Sense::nothing() || !layer_id.allow_interaction() { if id.is_none() || sense == Sense::nothing() || !layer_id.allow_interaction() {
// Not interested or allowed input: // Not interested or allowed input:
return Response { return Response {
ctx: self.clone(), ctx: Some(self.clone()),
sense, sense,
rect, rect,
hovered, hovered,
@ -461,7 +461,7 @@ impl Context {
if self.input.mouse.pressed { if self.input.mouse.pressed {
if hovered { if hovered {
let mut response = Response { let mut response = Response {
ctx: self.clone(), ctx: Some(self.clone()),
sense, sense,
rect, rect,
hovered: true, hovered: true,
@ -491,7 +491,7 @@ impl Context {
} else { } else {
// miss // miss
Response { Response {
ctx: self.clone(), ctx: Some(self.clone()),
sense, sense,
rect, rect,
hovered, hovered,
@ -504,7 +504,7 @@ impl Context {
} else if self.input.mouse.released { } else if self.input.mouse.released {
let clicked = hovered && active && self.input.mouse.could_be_click; let clicked = hovered && active && self.input.mouse.could_be_click;
Response { Response {
ctx: self.clone(), ctx: Some(self.clone()),
sense, sense,
rect, rect,
hovered, hovered,
@ -515,7 +515,7 @@ impl Context {
} }
} else if self.input.mouse.down { } else if self.input.mouse.down {
Response { Response {
ctx: self.clone(), ctx: Some(self.clone()),
sense, sense,
rect, rect,
hovered: hovered && active, hovered: hovered && active,
@ -526,7 +526,7 @@ impl Context {
} }
} else { } else {
Response { Response {
ctx: self.clone(), ctx: Some(self.clone()),
sense, sense,
rect, rect,
hovered, hovered,

View file

@ -105,7 +105,9 @@ impl FrameHistory {
// TODO: we should not use `slider_width` as default graph width. // TODO: we should not use `slider_width` as default graph width.
let height = ui.style().spacing.slider_width; let height = ui.style().spacing.slider_width;
let rect = ui.allocate_space(vec2(ui.available_finite().width(), height)); let rect = unwrap_or_return_default!(
ui.request_space(vec2(ui.available_finite().width(), height))
);
let style = ui.style().noninteractive(); let style = ui.style().noninteractive();
let mut cmds = vec![PaintCmd::Rect { let mut cmds = vec![PaintCmd::Rect {

View file

@ -267,7 +267,7 @@ impl ColorTest {
fn vertex_gradient(ui: &mut Ui, bg_fill: Srgba, gradient: &Gradient) -> Response { fn vertex_gradient(ui: &mut Ui, bg_fill: Srgba, gradient: &Gradient) -> Response {
use crate::paint::*; use crate::paint::*;
let rect = ui.allocate_space(GRADIENT_SIZE); let rect = unwrap_or_return_default!(ui.request_space(GRADIENT_SIZE));
if bg_fill != Default::default() { if bg_fill != Default::default() {
let mut triangles = Triangles::default(); let mut triangles = Triangles::default();
triangles.add_colored_rect(rect, bg_fill); triangles.add_colored_rect(rect, bg_fill);

View file

@ -93,7 +93,7 @@ impl DemoWindow {
.show(ui, |ui| { .show(ui, |ui| {
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.label("You can pretty easily paint your own small icons:"); ui.label("You can pretty easily paint your own small icons:");
let rect = ui.allocate_space(Vec2::splat(16.0)); if let Some(rect) = ui.request_space(Vec2::splat(16.0)) {
let painter = ui.painter(); let painter = ui.painter();
let c = rect.center(); let c = rect.center();
let r = rect.width() / 2.0 - 1.0; let r = rect.width() / 2.0 - 1.0;
@ -103,6 +103,7 @@ impl DemoWindow {
painter.line_segment([c - vec2(0.0, r), c + vec2(0.0, r)], stroke); painter.line_segment([c - vec2(0.0, r), c + vec2(0.0, r)], stroke);
painter.line_segment([c, c + r * Vec2::angled(TAU * 1.0 / 8.0)], stroke); painter.line_segment([c, c + r * Vec2::angled(TAU * 1.0 / 8.0)], stroke);
painter.line_segment([c, c + r * Vec2::angled(TAU * 3.0 / 8.0)], stroke); painter.line_segment([c, c + r * Vec2::angled(TAU * 3.0 / 8.0)], stroke);
}
}); });
}); });
} }
@ -210,9 +211,9 @@ impl BoxPainting {
ui.add(Slider::f32(&mut self.stroke_width, 0.0..=10.0).text("stroke_width")); ui.add(Slider::f32(&mut self.stroke_width, 0.0..=10.0).text("stroke_width"));
ui.add(Slider::usize(&mut self.num_boxes, 0..=5).text("num_boxes")); ui.add(Slider::usize(&mut self.num_boxes, 0..=5).text("num_boxes"));
let pos = ui let rect = ui.request_space(vec2(self.size.x * (self.num_boxes as f32), self.size.y));
.allocate_space(vec2(self.size.x * (self.num_boxes as f32), self.size.y)) let rect = unwrap_or_return_default!(rect);
.min; let pos = rect.min;
let mut cmds = vec![]; let mut cmds = vec![];
for i in 0..self.num_boxes { for i in 0..self.num_boxes {
@ -265,7 +266,7 @@ impl Painting {
} }
fn content(&mut self, ui: &mut Ui) { fn content(&mut self, ui: &mut Ui) {
let rect = ui.allocate_space(ui.available_finite().size()); let rect = unwrap_or_return_default!(ui.request_space(ui.available_finite().size()));
let response = ui.interact(rect, ui.id(), Sense::drag()); let response = ui.interact(rect, ui.id(), Sense::drag());
let rect = response.rect; let rect = response.rect;
let clip_rect = ui.clip_rect().intersect(rect); // Make sure we don't paint out of bounds let clip_rect = ui.clip_rect().intersect(rect); // Make sure we don't paint out of bounds

View file

@ -13,7 +13,7 @@ use crate::*;
pub fn toggle(ui: &mut Ui, on: &mut bool) -> Response { pub fn toggle(ui: &mut Ui, on: &mut bool) -> Response {
// Widget code can be broken up in four steps: // Widget code can be broken up in four steps:
// 1. Decide a size for the widget // 1. Decide a size for the widget
// 2. Allocate space for it // 2. Request space for it
// 3. Handle interactions with the widget (if any) // 3. Handle interactions with the widget (if any)
// 4. Paint the widget // 4. Paint the widget
@ -22,9 +22,14 @@ pub fn toggle(ui: &mut Ui, on: &mut bool) -> Response {
// but in this example we have a fixed size widget of the default size for a button: // but in this example we have a fixed size widget of the default size for a button:
let desired_size = ui.style().spacing.interact_size; let desired_size = ui.style().spacing.interact_size;
// 2. Allocating space: // 2. Requesting space:
// This is where we get a region (`Rect`) of the screen assigned. // This is where we get a region (`Rect`) of the screen assigned.
let rect = ui.allocate_space(desired_size); let rect = ui.request_space(desired_size);
// If we get `None` back from `request_space`, it means this widgets isn't visible.
// In this case we shouldn't do anything else and just return early.
// Egui has a helper macro for this:
let rect = unwrap_or_return_default!(rect);
// 3. Interact: Time to check for clicks! // 3. Interact: Time to check for clicks!
// To do that we need an `Id` for the button. // To do that we need an `Id` for the button.

View file

@ -19,7 +19,7 @@ impl Texture {
if size.x > ui.available().width() { if size.x > ui.available().width() {
size *= ui.available().width() / size.x; size *= ui.available().width() / size.x;
} }
let rect = ui.allocate_space(size); let rect = unwrap_or_return_default!(ui.request_space(size));
let mut triangles = Triangles::default(); let mut triangles = Triangles::default();
triangles.add_rect_with_uv(rect, [pos2(0.0, 0.0), pos2(1.0, 1.0)].into(), WHITE); triangles.add_rect_with_uv(rect, [pos2(0.0, 0.0), pos2(1.0, 1.0)].into(), WHITE);
ui.painter().add(PaintCmd::triangles(triangles)); ui.painter().add(PaintCmd::triangles(triangles));
@ -34,7 +34,7 @@ impl Texture {
.mouse .mouse
.pos .pos
.unwrap_or_else(|| ui.min_rect().left_top()); .unwrap_or_else(|| ui.min_rect().left_top());
let zoom_rect = ui.allocate_space(vec2(128.0, 128.0)); let zoom_rect = unwrap_or_return_default!(ui.request_space(vec2(128.0, 128.0)));
let u = remap_clamp(pos.x, rect.x_range(), 0.0..=tex_w); let u = remap_clamp(pos.x, rect.x_range(), 0.0..=tex_w);
let v = remap_clamp(pos.y, rect.y_range(), 0.0..=tex_h); let v = remap_clamp(pos.y, rect.y_range(), 0.0..=tex_h);

View file

@ -120,3 +120,15 @@ pub fn text_egui_e2e() {
assert!(!paint_jobs.is_empty()); assert!(!paint_jobs.is_empty());
} }
} }
#[macro_export]
macro_rules! unwrap_or_return_default {
($option:expr) => {
match $option {
Some(value) => value,
None => {
return Default::default();
}
}
};
}

View file

@ -1,11 +1,6 @@
#![allow(clippy::if_same_then_else)] #![allow(clippy::if_same_then_else)]
use crate::{ use crate::{color::*, *};
color::*,
math::*,
paint::{Stroke, TextStyle},
types::*,
};
/// Specifies the look and feel of a `Ui`. /// Specifies the look and feel of a `Ui`.
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
@ -474,7 +469,8 @@ impl Stroke {
ui.label(text); ui.label(text);
// stroke preview: // stroke preview:
let stroke_rect = ui.allocate_space(ui.style().spacing.interact_size); let stroke_rect =
unwrap_or_return_default!(ui.request_space(ui.style().spacing.interact_size));
let left = stroke_rect.left_center(); let left = stroke_rect.left_center();
let right = stroke_rect.right_center(); let right = stroke_rect.right_center();
ui.painter().line_segment([left, right], (*width, *color)); ui.painter().line_segment([left, right], (*width, *color));

View file

@ -56,8 +56,10 @@ impl Default for CursorIcon {
#[derive(Clone)] #[derive(Clone)]
pub struct Response { pub struct Response {
// CONTEXT: // CONTEXT:
/// Used for optionally showing a tooltip /// Used for optionally showing a tooltip.
pub ctx: Arc<Context>, /// If `None`, we likely come from a cull widgets and shouldn't show any
/// tooltip.
pub ctx: Option<Arc<Context>>,
// IN: // IN:
/// The area of the screen we are talking about /// The area of the screen we are talking about
@ -83,17 +85,18 @@ pub struct Response {
pub has_kb_focus: bool, pub has_kb_focus: bool,
} }
impl std::fmt::Debug for Response { impl Default for Response {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn default() -> Self {
f.debug_struct("Response") Self {
.field("rect", &self.rect) ctx: None,
.field("sense", &self.sense) rect: Rect::nothing(),
.field("hovered", &self.hovered) sense: Sense::nothing(),
.field("clicked", &self.clicked) hovered: false,
.field("double_clicked", &self.double_clicked) clicked: false,
.field("active", &self.active) double_clicked: false,
.field("has_kb_focus", &self.has_kb_focus) active: false,
.finish() has_kb_focus: false,
}
} }
} }
@ -101,7 +104,11 @@ impl Response {
/// Show this UI if the item was hovered (i.e. a tooltip) /// Show this UI if the item was hovered (i.e. a tooltip)
pub fn on_hover_ui(self, add_contents: impl FnOnce(&mut Ui)) -> Self { pub fn on_hover_ui(self, add_contents: impl FnOnce(&mut Ui)) -> Self {
if self.hovered { if self.hovered {
crate::containers::show_tooltip(&self.ctx, add_contents); if let Some(ctx) = &self.ctx {
crate::containers::show_tooltip(ctx, add_contents);
} else {
panic!("We shouldn't be able to hover something without a Context");
}
} }
self self
} }
@ -123,9 +130,12 @@ impl Response {
/// A logical "or" operation. /// A logical "or" operation.
/// For instance `a.union(b).hovered` means "was either a or b hovered?". /// For instance `a.union(b).hovered` means "was either a or b hovered?".
pub fn union(&self, other: Self) -> Self { pub fn union(&self, other: Self) -> Self {
assert!(Arc::ptr_eq(&self.ctx, &other.ctx)); if let (Some(lc), Some(rc)) = (&self.ctx, &other.ctx) {
debug_assert!(Arc::ptr_eq(lc, rc));
}
Self { Self {
ctx: other.ctx, ctx: other.ctx.or_else(|| self.ctx.clone()),
rect: self.rect.union(other.rect), rect: self.rect.union(other.rect),
sense: self.sense.union(other.sense), sense: self.sense.union(other.sense),
hovered: self.hovered || other.hovered, hovered: self.hovered || other.hovered,
@ -137,6 +147,23 @@ impl Response {
} }
} }
impl std::fmt::Debug for Response {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Response")
.field("ctx", &self.ctx.is_some())
.field("rect", &self.rect)
.field("sense", &self.sense)
.field("hovered", &self.hovered)
.field("clicked", &self.clicked)
.field("double_clicked", &self.double_clicked)
.field("active", &self.active)
.field("has_kb_focus", &self.has_kb_focus)
.finish()
}
}
// ----------------------------------------------------------------------------
/// To summarize the response from many widgets you can use this pattern: /// To summarize the response from many widgets you can use this pattern:
/// ///
/// ``` /// ```

View file

@ -462,6 +462,26 @@ impl Ui {
rect rect
} }
/// Potential future of `allocate_space`.
/// Returns `None` if the allocated rectangle is outside the clip rect and is thus invisible.
/// Works well together with the `unwrap_or_return_default!` macro:
/// ```
/// # use egui::*;
/// # let mut ui = Ui::test();
/// let desired_size = vec2(100.0, 200.0);
/// let rect = unwrap_or_return_default!(ui.request_space(desired_size));
/// assert_eq!(rect, Rect::from_min_size(pos2(0.0, 0.0), desired_size));
/// ```
///
pub fn request_space(&mut self, desired_size: Vec2) -> Option<Rect> {
let rect = self.allocate_space(desired_size);
if self.clip_rect().intersects(rect) {
Some(rect)
} else {
None
}
}
/// Reserve this much space and move the cursor. /// Reserve this much space and move the cursor.
/// Returns where to put the widget. /// Returns where to put the widget.
fn reserve_space_impl(&mut self, child_size: Vec2) -> Rect { fn reserve_space_impl(&mut self, child_size: Vec2) -> Rect {

View file

@ -43,7 +43,7 @@ pub fn show_color(ui: &mut Ui, color: impl Into<Srgba>, desired_size: Vec2) -> R
} }
fn show_srgba(ui: &mut Ui, srgba: Srgba, desired_size: Vec2) -> Response { fn show_srgba(ui: &mut Ui, srgba: Srgba, desired_size: Vec2) -> Response {
let rect = ui.allocate_space(desired_size); let rect = unwrap_or_return_default!(ui.request_space(desired_size));
background_checkers(ui.painter(), rect); background_checkers(ui.painter(), rect);
ui.painter().add(PaintCmd::Rect { ui.painter().add(PaintCmd::Rect {
rect, rect,
@ -56,7 +56,7 @@ fn show_srgba(ui: &mut Ui, srgba: Srgba, desired_size: Vec2) -> Response {
fn color_button(ui: &mut Ui, color: Srgba) -> Response { fn color_button(ui: &mut Ui, color: Srgba) -> Response {
let desired_size = ui.style().spacing.interact_size; let desired_size = ui.style().spacing.interact_size;
let rect = ui.allocate_space(desired_size); let rect = unwrap_or_return_default!(ui.request_space(desired_size));
let id = ui.make_position_id(); let id = ui.make_position_id();
let response = ui.interact(rect, id, Sense::click()); let response = ui.interact(rect, id, Sense::click());
let visuals = ui.style().interact(&response); let visuals = ui.style().interact(&response);
@ -77,7 +77,7 @@ fn color_slider_1d(ui: &mut Ui, value: &mut f32, color_at: impl Fn(f32) -> Srgba
ui.style().spacing.slider_width, ui.style().spacing.slider_width,
ui.style().spacing.interact_size.y * 2.0, ui.style().spacing.interact_size.y * 2.0,
); );
let rect = ui.allocate_space(desired_size); let rect = unwrap_or_return_default!(ui.request_space(desired_size));
let id = ui.make_position_id(); let id = ui.make_position_id();
let response = ui.interact(rect, id, Sense::click_and_drag()); let response = ui.interact(rect, id, Sense::click_and_drag());
@ -136,7 +136,7 @@ fn color_slider_2d(
color_at: impl Fn(f32, f32) -> Srgba, color_at: impl Fn(f32, f32) -> Srgba,
) -> Response { ) -> Response {
let desired_size = Vec2::splat(ui.style().spacing.slider_width); let desired_size = Vec2::splat(ui.style().spacing.slider_width);
let rect = ui.allocate_space(desired_size); let rect = unwrap_or_return_default!(ui.request_space(desired_size));
let id = ui.make_position_id(); let id = ui.make_position_id();
let response = ui.interact(rect, id, Sense::click_and_drag()); let response = ui.interact(rect, id, Sense::click_and_drag());

View file

@ -49,7 +49,7 @@ impl Widget for Image {
bg_fill, bg_fill,
tint, tint,
} = self; } = self;
let rect = ui.allocate_space(desired_size); let rect = unwrap_or_return_default!(ui.request_space(desired_size));
if bg_fill != Default::default() { if bg_fill != Default::default() {
let mut triangles = Triangles::default(); let mut triangles = Triangles::default();
triangles.add_colored_rect(rect, bg_fill); triangles.add_colored_rect(rect, bg_fill);

View file

@ -135,7 +135,7 @@ macro_rules! label {
impl Widget for Label { impl Widget for Label {
fn ui(self, ui: &mut Ui) -> Response { fn ui(self, ui: &mut Ui) -> Response {
let galley = self.layout(ui); let galley = self.layout(ui);
let rect = ui.allocate_space(galley.size); let rect = unwrap_or_return_default!(ui.request_space(galley.size));
self.paint_galley(ui, rect.min, galley); self.paint_galley(ui, rect.min, galley);
ui.interact_hover(rect) ui.interact_hover(rect)
} }
@ -207,7 +207,7 @@ impl Widget for Hyperlink {
let text_style = text_style.unwrap_or_else(|| ui.style().body_text_style); let text_style = text_style.unwrap_or_else(|| ui.style().body_text_style);
let font = &ui.fonts()[text_style]; let font = &ui.fonts()[text_style];
let galley = font.layout_multiline(text, ui.available().width()); let galley = font.layout_multiline(text, ui.available().width());
let rect = ui.allocate_space(galley.size); let rect = unwrap_or_return_default!(ui.request_space(galley.size));
let id = ui.make_position_id(); let id = ui.make_position_id();
let response = ui.interact(rect, id, Sense::click()); let response = ui.interact(rect, id, Sense::click());
@ -318,7 +318,7 @@ impl Widget for Button {
let galley = font.layout_multiline(text, ui.available().width()); let galley = font.layout_multiline(text, ui.available().width());
let mut desired_size = galley.size + 2.0 * button_padding; let mut desired_size = galley.size + 2.0 * button_padding;
desired_size = desired_size.at_least(ui.style().spacing.interact_size); desired_size = desired_size.at_least(ui.style().spacing.interact_size);
let rect = ui.allocate_space(desired_size); let rect = unwrap_or_return_default!(ui.request_space(desired_size));
let id = ui.make_position_id(); let id = ui.make_position_id();
let response = ui.interact(rect, id, sense); let response = ui.interact(rect, id, sense);
@ -390,7 +390,7 @@ impl<'a> Widget for Checkbox<'a> {
button_padding + vec2(icon_width + icon_spacing, 0.0) + galley.size + button_padding; button_padding + vec2(icon_width + icon_spacing, 0.0) + galley.size + button_padding;
desired_size = desired_size.at_least(spacing.interact_size); desired_size = desired_size.at_least(spacing.interact_size);
desired_size.y = desired_size.y.max(icon_width); desired_size.y = desired_size.y.max(icon_width);
let rect = ui.allocate_space(desired_size); let rect = unwrap_or_return_default!(ui.request_space(desired_size));
let id = ui.make_position_id(); let id = ui.make_position_id();
let response = ui.interact(rect, id, Sense::click()); let response = ui.interact(rect, id, Sense::click());
@ -475,7 +475,7 @@ impl Widget for RadioButton {
button_padding + vec2(icon_width + icon_spacing, 0.0) + galley.size + button_padding; button_padding + vec2(icon_width + icon_spacing, 0.0) + galley.size + button_padding;
desired_size = desired_size.at_least(ui.style().spacing.interact_size); desired_size = desired_size.at_least(ui.style().spacing.interact_size);
desired_size.y = desired_size.y.max(icon_width); desired_size.y = desired_size.y.max(icon_width);
let rect = ui.allocate_space(desired_size); let rect = unwrap_or_return_default!(ui.request_space(desired_size));
let id = ui.make_position_id(); let id = ui.make_position_id();
let response = ui.interact(rect, id, Sense::click()); let response = ui.interact(rect, id, Sense::click());
@ -544,7 +544,8 @@ impl Widget for Separator {
let (points, rect) = match ui.layout().dir() { let (points, rect) = match ui.layout().dir() {
Direction::Horizontal => { Direction::Horizontal => {
let rect = ui.allocate_space(vec2(spacing, available_space.y)); let rect =
unwrap_or_return_default!(ui.request_space(vec2(spacing, available_space.y)));
( (
[ [
pos2(rect.center().x, rect.top()), pos2(rect.center().x, rect.top()),
@ -554,7 +555,8 @@ impl Widget for Separator {
) )
} }
Direction::Vertical => { Direction::Vertical => {
let rect = ui.allocate_space(vec2(available_space.x, spacing)); let rect =
unwrap_or_return_default!(ui.request_space(vec2(available_space.x, spacing)));
( (
[ [
pos2(rect.left(), rect.center().y), pos2(rect.left(), rect.center().y),

View file

@ -122,7 +122,7 @@ impl<'t> Widget for TextEdit<'t> {
galley.size.x.max(desired_width.min(available_width)), galley.size.x.max(desired_width.min(available_width)),
galley.size.y.max(line_spacing), galley.size.y.max(line_spacing),
); );
let rect = ui.allocate_space(desired_size); let rect = unwrap_or_return_default!(ui.request_space(desired_size));
let sense = if enabled { let sense = if enabled {
Sense::click_and_drag() Sense::click_and_drag()
} else { } else {