Skip to content
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

Tweak window resize handles #5524

Merged
merged 3 commits into from
Dec 27, 2024
Merged
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
122 changes: 85 additions & 37 deletions crates/egui/src/containers/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,7 @@ impl<'open> Window<'open> {
outer_rect,
frame_stroke,
window_frame.rounding,
resize_interaction,
);

// END FRAME --------------------------------
Expand Down Expand Up @@ -651,29 +652,30 @@ fn paint_resize_corner(
outer_rect: Rect,
stroke: impl Into<Stroke>,
rounding: impl Into<Rounding>,
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;
}
Expand All @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -849,7 +870,7 @@ fn resize_interaction(
};
}

let is_dragging = |rect, id| {
let side_response = |rect, id| {
let response = ctx.create_widget(
WidgetRect {
layer_id,
Expand All @@ -872,6 +893,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));

Expand All @@ -882,59 +909,80 @@ 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;
}

// ----------------------------------------
// Now check corners:

if possible.resize_right && possible.resize_bottom {
let response = is_dragging(corner_rect(rect.right_bottom()), id.with("right_bottom"));
right |= response;
bottom |= response;
// 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 {
let response = is_dragging(corner_rect(rect.right_top()), id.with("right_top"));
right |= response;
top |= 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;
}
if possible.resize_top {
top |= response;
}
}

if possible.resize_left && possible.resize_bottom {
let response = is_dragging(corner_rect(rect.left_bottom()), id.with("left_bottom"));
left |= response;
bottom |= 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;
}
if possible.resize_bottom {
bottom |= response;
}
}

if possible.resize_left && possible.resize_top {
let response = is_dragging(corner_rect(rect.left_top()), id.with("left_top"));
left |= response;
top |= 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;
}
if possible.resize_top {
top |= response;
}
}

let interaction = ResizeInteraction {
Expand Down
Loading