8000 A `Window` can now be resizable in only one direction by emilk · Pull Request #4155 · emilk/egui · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

A Window can now be resizable in only one direction #4155

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 0 additions & 17 deletions crates/egui/src/containers/area.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@ pub(crate) struct State {
/// If false, clicks goes straight through to what is behind us.
/// Good for tooltips etc.
pub interactable: bool,

/// When `true`, this `Area` belongs to a resizable window, so it needs to
/// receive mouse input which occurs a short distance beyond its bounding rect.
pub edges_padded_for_resize: bool,
}

impl State {
Expand Down Expand Up @@ -75,7 +71,6 @@ pub struct Area {
pivot: Align2,
anchor: Option<(Align2, Vec2)>,
new_pos: Option<Pos2>,
edges_padded_for_resize: bool,
}

impl Area {
Expand All @@ -93,7 +88,6 @@ impl Area {
new_pos: None,
pivot: Align2::LEFT_TOP,
anchor: None,
edges_padded_for_resize: false,
}
}

Expand Down Expand Up @@ -227,14 +221,6 @@ impl Area {
Align2::LEFT_TOP
}
}

/// When `true`, this `Area` belongs to a resizable window, so it needs to
/// receive mouse input which occurs a short distance beyond its bounding rect.
#[inline]
pub(crate) fn edges_padded_for_resize(mut self, edges_padded_for_resize: bool) -> Self {
self.edges_padded_for_resize = edges_padded_for_resize;
self
}
}

pub(crate) struct Prepared {
Expand Down Expand Up @@ -279,7 +265,6 @@ impl Area {
anchor,
constrain,
constrain_rect,
edges_padded_for_resize,
} = self;

let layer_id = LayerId::new(order, id);
Expand All @@ -300,11 +285,9 @@ impl Area {
pivot,
size: Vec2::ZERO,
interactable,
edges_padded_for_resize,
});
state.pivot_pos = new_pos.unwrap_or(state.pivot_pos);
state.interactable = interactable;
state.edges_padded_for_resize = edges_padded_for_resize;

if let Some((anchor, offset)) = anchor {
let screen = ctx.available_rect();
Expand Down
38 changes: 21 additions & 17 deletions crates/egui/src/containers/resize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pub struct Resize {
id_source: Option<Id>,

/// If false, we are no enabled
resizable: bool,
resizable: Vec2b,

pub(crate) min_size: Vec2,
pub(crate) max_size: Vec2,
Expand All @@ -49,7 +49,7 @@ impl Default for Resize {
Self {
id: None,
id_source: None,
resizable: true,
resizable: Vec2b::TRUE,
min_size: Vec2::splat(16.0),
max_size: Vec2::splat(f32::INFINITY),
default_size: vec2(320.0, 128.0), // TODO(emilk): preferred size of [`Resize`] area.
Expand Down Expand Up @@ -152,12 +152,13 @@ impl Resize {
///
/// Default is `true`.
#[inline]
pub fn resizable(mut self, resizable: bool) -> Self {
self.resizable = resizable;
pub fn resizable(mut self, resizable: impl Into<Vec2b>) -> Self {
self.resizable = resizable.into();
self
}

pub fn is_resizable(&self) -> bool {
#[inline]
pub fn is_resizable(&self) -> Vec2b {
self.resizable
}

Expand All @@ -175,7 +176,7 @@ impl Resize {
self.default_size = size;
self.min_size = size;
self.max_size = size;
self.resizable = false;
self.resizable = Vec2b::FALSE;
self
}

Expand Down Expand Up @@ -226,7 +227,7 @@ impl Resize {

let mut user_requested_size = state.requested_size.take();

let corner_id = self.resizable.then(|| id.with("__resize_corner"));
let corner_id = self.resizable.any().then(|| id.with("__resize_corner"));

if let Some(corner_id) = corner_id {
if let Some(corner_response) = ui.ctx().read_response(corner_id) {
Expand Down Expand Up @@ -299,18 +300,21 @@ impl Resize {

// ------------------------------

let size = if self.with_stroke || self.resizable {
// We show how large we are,
// so we must follow the contents:
let mut size = state.last_content_size;
for d in 0..2 {
if self.with_stroke || self.resizable[d] {
// We show how large we are,
// so we must follow the contents:

state.desired_size = state.desired_size.max(state.last_content_size);
state.desired_size[d] = state.desired_size[d].max(state.last_content_size[d]);

// We are as large as we look
state.desired_size
} else {
// Probably a window.
state.last_content_size
};
// We are as large as we look
size[d] = state.desired_size[d];
} else {
// Probably a window.
size[d] = state.last_content_size[d];
}
}
ui.advance_cursor_after_rect(Rect::from_min_size(content_ui.min_rect().min, size));

// ------------------------------
Expand Down
44 changes: 28 additions & 16 deletions crates/egui/src/containers/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,7 @@ impl<'open> Window<'open> {
/// If you need a changing title, you must call `window.id(…)` with a fixed id.
pub fn new(title: impl Into<WidgetText>) -> Self {
let title = title.into().fallback_text_style(TextStyle::Heading);
let area = Area::new(Id::new(title.text()))
.constrain(true)
.edges_padded_for_resize(true);
let area = Area::new(Id::new(title.text())).constrain(true);
Self {
title,
open: None,
Expand Down Expand Up @@ -119,9 +117,6 @@ impl<'open> Window<'open> {
#[inline]
pub fn resize(mut self, mutate: impl Fn(Resize) -> Resize) -> Self {
self.resize = mutate(self.resize);
self.area = self
.area
.edges_padded_for_resize(self.resize.is_resizable());
self
}

Expand Down Expand Up @@ -278,7 +273,6 @@ impl<'open> Window<'open> {
#[inline]
pub fn fixed_size(mut self, size: impl Into<Vec2>) -> Self {
self.resize = self.resize.fixed_size(size);
self.area = self.area.edges_padded_for_resize(false);
self
}

Expand All @@ -296,11 +290,15 @@ impl<'open> Window<'open> {
///
/// Note that even if you set this to `false` the window may still auto-resize.
///
/// You can set the window to only be resizable in one direction by using
/// e.g. `[true, false]` as the argument,
/// making the window only resizable in the x-direction.
///
/// Default is `true`.
#[inline]
pub fn resizable(mut self, resizable: bool) -> Self {
pub fn resizable(mut self, resizable: impl Into<Vec2b>) -> Self {
let resizable = resizable.into();
self.resize = self.resize.resizable(resizable);
self.area = self.area.edges_padded_for_resize(resizable);
self
}

Expand All @@ -326,7 +324,6 @@ impl<'open> Window<'open> {
pub fn auto_sized(mut self) -> Self {
self.resize = self.resize.auto_sized();
self.scroll = ScrollArea::neither();
self.area = self.area.edges_padded_for_resize(false);
self
}

Expand Down Expand Up @@ -589,7 +586,20 @@ fn paint_resize_corner(
} else if possible.resize_right && possible.resize_top {
(Align2::RIGHT_TOP, rounding.ne)
} else {
return;
// We're not in two directions, but it is still nice to tell the user
// we're resizable by painting the resize corner in the expected place
// (i.e. for windows only resizable in one direction):
if possible.resize_right || possible.resize_bottom {
(Align2::RIGHT_BOTTOM, rounding.se)
} else if possible.resize_left || possible.resize_bottom {
(Align2::LEFT_BOTTOM, rounding.sw)
} else if possible.resize_left || possible.resize_top {
(Align2::LEFT_TOP, rounding.nw)
} else if possible.resize_right || possible.resize_top {
(Align2::RIGHT_TOP, rounding.ne)
} else {
return;
}
};

// Adjust the corner offset to accommodate the stroke width and window rounding
Expand Down Expand Up @@ -621,13 +631,15 @@ struct PossibleInteractions {
impl PossibleInteractions {
fn new(area: &Area, resize: &Resize, is_collapsed: bool) -> Self {
let movable = area.is_enabled() && area.is_movable();
let resizable = area.is_enabled() && resize.is_resizable() && !is_collapsed;
let resizable = resize
.is_resizable()
.and(area.is_enabled() && !is_collapsed);
let pivot = area.get_pivot();
Self {
resize_left: resizable && (movable || pivot.x() != Align::LEFT),
resize_right: resizable && (movable || pivot.x() != Align::RIGHT),
resize_top: resizable && (movable || pivot.y() != Align::TOP),
resize_bottom: resizable && (movable || pivot.y() != Align::BOTTOM),
resize_left: resizable.x && (movable || pivot.x() != Align::LEFT),
resize_right: resizable.x && (movable || pivot.x() != Align::RIGHT),
resize_top: resizable.y && (movable || pivot.y() != Align::TOP),
resize_bottom: resizable.y && (movable || pivot.y() != Align::BOTTOM),
}
}

Expand Down
5 changes: 1 addition & 4 deletions crates/egui/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,6 @@ impl ContextImpl {
pivot: Align2::LEFT_TOP,
size: screen_rect.size(),
interactable: true,
edges_padded_for_resize: false,
},
);

Expand Down Expand Up @@ -2331,9 +2330,7 @@ impl Context {

/// Top-most layer at the given position.
pub fn layer_id_at(&self, pos: Pos2) -> Option<LayerId> {
self.memory(|mem| {
mem.layer_id_at(pos, mem.options.style.interaction.resize_grab_radius_side)
})
self.memory(|mem| mem.layer_id_at(pos))
}

/// Moves the given area to the top in its [`Order`].
Expand Down
11 changes: 2 additions & 9 deletions crates/egui/src/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -646,9 +646,8 @@ impl Memory {
}

/// Top-most layer at the given position.
pub fn layer_id_at(&self, pos: Pos2, resize_interact_radius_side: f32) -> Option<LayerId> {
self.areas()
.layer_id_at(pos, resize_interact_radius_side, &self.layer_transforms)
pub fn layer_id_at(&self, pos: Pos2) -> Option<LayerId> {
self.areas().layer_id_at(pos, &self.layer_transforms)
}

/// An iterator over all layers. Back-to-front. Top is last.
Expand Down Expand Up @@ -921,19 +920,13 @@ impl Areas {
pub fn layer_id_at(
&self,
pos: Pos2,
resize_interact_radius_side: f32,
layer_transforms: &HashMap<LayerId, TSTransform>,
) -> Option<LayerId> {
for layer in self.order.iter().rev() {
if self.is_visible(layer) {
if let Some(state) = self.areas.get(&layer.id) {
let mut rect = state.rect();
if state.interactable {
if state.edges_padded_for_resize {
// Allow us to resize by dragging just outside the window:
rect = rect.expand(resize_interact_radius_side);
}

if let Some(transform) = layer_transforms.get(layer) {
rect = *transform * rect;
}
Expand Down
1 change: 1 addition & 0 deletions crates/egui_demo_lib/src/demo/about.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ impl super::Demo for About {
.default_width(320.0)
.default_height(480.0)
.open(open)
.resizable([true, false])
.show(ctx, |ui| {
use super::View as _;
self.ui(ui);
Expand Down
1 change: 1 addition & 0 deletions crates/egui_demo_lib/src/demo/code_example.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ impl super::Demo for CodeExample {
.default_size([800.0, 400.0])
.vscroll(false)
.hscroll(true)
.resizable([true, false])
.show(ctx, |ui| self.ui(ui));
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/egui_demo_lib/src/demo/widget_gallery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ impl super::Demo for WidgetGallery {
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
egui::Window::new(self.name())
.open(open)
.resizable(true)
.resizable([true, false])
.default_width(280.0)
.show(ctx, |ui| {
use super::View as _;
Expand Down
12 changes: 12 additions & 0 deletions crates/emath/src/vec2.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};

use crate::Vec2b;

/// A vector has a direction and length.
/// A [`Vec2`] is often used to represent a size.
///
Expand Down Expand Up @@ -86,6 +88,16 @@ impl From<&Vec2> for (f32, f32) {
}
}

impl From<Vec2b> for Vec2 {
#[inline(always)]
fn from(v: Vec2b) -> Self {
Self {
x: v.x as i32 as f32,
y: v.y as i32 as f32,
}
}
}

// ----------------------------------------------------------------------------
// Mint compatibility and convenience conversions

Expand Down
24 changes: 24 additions & 0 deletions crates/emath/src/vec2b.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,30 @@ impl Vec2b {
pub fn any(&self) -> bool {
self.x || self.y
}

/// Are both `x` and `y` true?
#[inline]
pub fn all(&self) -> bool {
self.x && self.y
}

#[inline]
pub fn and(&self, other: impl Into<Self>) -> Self {
let other = other.into();
Self {
x: self.x && other.x,
y: self.y && other.y,
}
}

#[inline]
pub fn or(&self, other: impl Into<Self>) -> Self {
let other = other.into();
Self {
x: self.x || other.x,
y: self.y || other.y,
}
}
}

impl From<bool> for Vec2b {
Expand Down
0