From 9823fd774fbd6bb0a1e9dc89337b33e3ca5ef534 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Fri, 27 Dec 2024 14:49:03 +0100 Subject: [PATCH 1/3] Tweak window resize handles This makes it easier to hit the corners. Previously the corner response-area was covered by the response-areas of the edges. --- crates/egui/src/containers/window.rs | 32 +++++++++++++++++----------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/crates/egui/src/containers/window.rs b/crates/egui/src/containers/window.rs index 414c58cfae7..c4cc0501591 100644 --- a/crates/egui/src/containers/window.rs +++ b/crates/egui/src/containers/window.rs @@ -849,7 +849,7 @@ fn resize_interaction( }; } - let is_dragging = |rect, id| { + let side_response = |rect, id| { let response = ctx.create_widget( WidgetRect { layer_id, @@ -872,6 +872,12 @@ fn resize_interaction( let side_grab_radius = ctx.style().interaction.resize_grab_radius_side; let corner_grab_radius = ctx.style().interaction.resize_grab_radius_corner; + let vetrtical_rect = |a: Pos2, b: Pos2| { + Rect::from_min_max(a, b).expand2(vec2(side_grab_radius, -corner_grab_radius)) + }; + let horizontal_rect = |a: Pos2, b: Pos2| { + Rect::from_min_max(a, b).expand2(vec2(-corner_grab_radius, side_grab_radius)) + }; let corner_rect = |center: Pos2| Rect::from_center_size(center, Vec2::splat(2.0 * corner_grab_radius)); @@ -882,29 +888,29 @@ fn resize_interaction( // Check sides first, so that corners are on top, covering the sides (i.e. corners have priority) if possible.resize_right { - let response = is_dragging( - Rect::from_min_max(rect.right_top(), rect.right_bottom()).expand(side_grab_radius), + let response = side_response( + vetrtical_rect(rect.right_top(), rect.right_bottom()), id.with("right"), ); right |= response; } if possible.resize_left { - let response = is_dragging( - Rect::from_min_max(rect.left_top(), rect.left_bottom()).expand(side_grab_radius), + let response = side_response( + vetrtical_rect(rect.left_top(), rect.left_bottom()), id.with("left"), ); left |= response; } if possible.resize_bottom { - let response = is_dragging( - Rect::from_min_max(rect.left_bottom(), rect.right_bottom()).expand(side_grab_radius), + let response = side_response( + horizontal_rect(rect.left_bottom(), rect.right_bottom()), id.with("bottom"), ); bottom |= response; } if possible.resize_top { - let response = is_dragging( - Rect::from_min_max(rect.left_top(), rect.right_top()).expand(side_grab_radius), + let response = side_response( + horizontal_rect(rect.left_top(), rect.right_top()), id.with("top"), ); top |= response; @@ -914,25 +920,25 @@ fn resize_interaction( // Now check corners: if possible.resize_right && possible.resize_bottom { - let response = is_dragging(corner_rect(rect.right_bottom()), id.with("right_bottom")); + let response = side_response(corner_rect(rect.right_bottom()), id.with("right_bottom")); right |= response; bottom |= response; } if possible.resize_right && possible.resize_top { - let response = is_dragging(corner_rect(rect.right_top()), id.with("right_top")); + let response = side_response(corner_rect(rect.right_top()), id.with("right_top")); right |= response; top |= response; } if possible.resize_left && possible.resize_bottom { - let response = is_dragging(corner_rect(rect.left_bottom()), id.with("left_bottom")); + let response = side_response(corner_rect(rect.left_bottom()), id.with("left_bottom")); left |= response; bottom |= response; } if possible.resize_left && possible.resize_top { - let response = is_dragging(corner_rect(rect.left_top()), id.with("left_top")); + let response = side_response(corner_rect(rect.left_top()), id.with("left_top")); left |= response; top |= response; } From 127acd0b6c5a7d32f3f6330a6155246da1f6c093 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Fri, 27 Dec 2024 15:19:14 +0100 Subject: [PATCH 2/3] Make it easy to hit corners, even on windows that only expand one way --- crates/egui/src/containers/window.rs | 33 +++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/crates/egui/src/containers/window.rs b/crates/egui/src/containers/window.rs index c4cc0501591..601e69d1ab9 100644 --- a/crates/egui/src/containers/window.rs +++ b/crates/egui/src/containers/window.rs @@ -917,31 +917,52 @@ fn resize_interaction( } // ---------------------------------------- - // Now check corners: - - if possible.resize_right && possible.resize_bottom { + // Now check corners. + // We check any corner that has either side resizable, + // because we shrink the side resize handled by the corner width. + // Also, even if we can only change the width (or height) of a window, + // we show one of the corners as a grab-handle, so it makes sense that + // the whole corner is grabbable: + + if possible.resize_right || possible.resize_bottom { let response = side_response(corner_rect(rect.right_bottom()), id.with("right_bottom")); + if possible.resize_right { right |= response; + } + if possible.resize_bottom { bottom |= response; } + } - if possible.resize_right && possible.resize_top { + if possible.resize_right || possible.resize_top { let response = side_response(corner_rect(rect.right_top()), id.with("right_top")); + if possible.resize_right { right |= response; + } + if possible.resize_top { top |= response; } + } - if possible.resize_left && possible.resize_bottom { + if possible.resize_left || possible.resize_bottom { let response = side_response(corner_rect(rect.left_bottom()), id.with("left_bottom")); + if possible.resize_left { left |= response; + } + if possible.resize_bottom { bottom |= response; } + } - if possible.resize_left && possible.resize_top { + if possible.resize_left || possible.resize_top { let response = side_response(corner_rect(rect.left_top()), id.with("left_top")); + if possible.resize_left { left |= response; + } + if possible.resize_top { top |= response; } + } let interaction = ResizeInteraction { start_rect: rect, From b9cd31b7bc3dac2c11c0d908537750fc279adee4 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Fri, 27 Dec 2024 15:19:30 +0100 Subject: [PATCH 3/3] Highlight resize-corner when hovered --- crates/egui/src/containers/window.rs | 65 ++++++++++++++++++---------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/crates/egui/src/containers/window.rs b/crates/egui/src/containers/window.rs index 601e69d1ab9..c48f6009915 100644 --- a/crates/egui/src/containers/window.rs +++ b/crates/egui/src/containers/window.rs @@ -583,6 +583,7 @@ impl<'open> Window<'open> { outer_rect, frame_stroke, window_frame.rounding, + resize_interaction, ); // END FRAME -------------------------------- @@ -651,29 +652,30 @@ fn paint_resize_corner( outer_rect: Rect, stroke: impl Into, rounding: impl Into, + i: ResizeInteraction, ) { - let stroke = stroke.into(); + let inactive_stroke = stroke.into(); let rounding = rounding.into(); - let (corner, radius) = if possible.resize_right && possible.resize_bottom { - (Align2::RIGHT_BOTTOM, rounding.se) + let (corner, radius, corner_response) = if possible.resize_right && possible.resize_bottom { + (Align2::RIGHT_BOTTOM, rounding.se, i.right & i.bottom) } else if possible.resize_left && possible.resize_bottom { - (Align2::LEFT_BOTTOM, rounding.sw) + (Align2::LEFT_BOTTOM, rounding.sw, i.left & i.bottom) } else if possible.resize_left && possible.resize_top { - (Align2::LEFT_TOP, rounding.nw) + (Align2::LEFT_TOP, rounding.nw, i.left & i.top) } else if possible.resize_right && possible.resize_top { - (Align2::RIGHT_TOP, rounding.ne) + (Align2::RIGHT_TOP, rounding.ne, i.right & i.top) } else { // 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) + (Align2::RIGHT_BOTTOM, rounding.se, i.right & i.bottom) } else if possible.resize_left || possible.resize_bottom { - (Align2::LEFT_BOTTOM, rounding.sw) + (Align2::LEFT_BOTTOM, rounding.sw, i.left & i.bottom) } else if possible.resize_left || possible.resize_top { - (Align2::LEFT_TOP, rounding.nw) + (Align2::LEFT_TOP, rounding.nw, i.left & i.top) } else if possible.resize_right || possible.resize_top { - (Align2::RIGHT_TOP, rounding.ne) + (Align2::RIGHT_TOP, rounding.ne, i.right & i.top) } else { return; } @@ -683,6 +685,14 @@ fn paint_resize_corner( let offset = ((2.0_f32.sqrt() * (1.0 + radius) - radius) * 45.0_f32.to_radians().cos()).max(2.0); + let stroke = if corner_response.drag { + ui.visuals().widgets.active.fg_stroke + } else if corner_response.hover { + ui.visuals().widgets.hovered.fg_stroke + } else { + inactive_stroke + }; + let corner_size = Vec2::splat(ui.visuals().resize_corner_size); let corner_rect = corner.align_size_within_rect(corner_size, outer_rect); let corner_rect = corner_rect.translate(-offset * corner.to_sign()); // move away from corner @@ -744,6 +754,17 @@ impl SideResponse { } } +impl std::ops::BitAnd for SideResponse { + type Output = Self; + + fn bitand(self, rhs: Self) -> Self::Output { + Self { + hover: self.hover && rhs.hover, + drag: self.drag && rhs.drag, + } + } +} + impl std::ops::BitOrAssign for SideResponse { fn bitor_assign(&mut self, rhs: Self) { *self = Self { @@ -927,41 +948,41 @@ fn resize_interaction( if possible.resize_right || possible.resize_bottom { let response = side_response(corner_rect(rect.right_bottom()), id.with("right_bottom")); if possible.resize_right { - right |= response; + right |= response; } if possible.resize_bottom { - bottom |= response; - } + bottom |= response; + } } if possible.resize_right || possible.resize_top { let response = side_response(corner_rect(rect.right_top()), id.with("right_top")); if possible.resize_right { - right |= response; + right |= response; } if possible.resize_top { - top |= response; - } + top |= response; + } } if possible.resize_left || possible.resize_bottom { let response = side_response(corner_rect(rect.left_bottom()), id.with("left_bottom")); if possible.resize_left { - left |= response; + left |= response; } if possible.resize_bottom { - bottom |= response; - } + bottom |= response; + } } if possible.resize_left || possible.resize_top { let response = side_response(corner_rect(rect.left_top()), id.with("left_top")); if possible.resize_left { - left |= response; + left |= response; } if possible.resize_top { - top |= response; - } + top |= response; + } } let interaction = ResizeInteraction {