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

How to add the resize handle button to the main window? #2548

Closed
apoorv569 opened this issue Jan 6, 2023 · 5 comments
Closed

How to add the resize handle button to the main window? #2548

apoorv569 opened this issue Jan 6, 2023 · 5 comments
Labels
bug Something is broken

Comments

@apoorv569
Copy link
Contributor

apoorv569 commented Jan 6, 2023

How do I add this resize button or handle to the main window?

2023-01-06_20-01

as a window with no decorations or custom decorations doesn't seems to be resizable unless there is a shortcut like Super + Right click and drag.

@apoorv569 apoorv569 added the bug Something is broken label Jan 6, 2023
@parasyte
Copy link
Contributor

parasyte commented Jan 6, 2023

There isn't a component for it, and all of the types used to draw and check for interactions are private. You can reimplement the basics by copying code or ideas. This is the "entry-point" for the resize handle on windows:

/// Returns `Some` if there is a move or resize
fn window_interaction(
ctx: &Context,
possible: PossibleInteractions,
area_layer_id: LayerId,
id: Id,
rect: Rect,
) -> Option<WindowInteraction> {
{
let drag_id = ctx.memory().interaction.drag_id;
if drag_id.is_some() && drag_id != Some(id) {
return None;
}
}
let mut window_interaction = { ctx.memory().window_interaction };
if window_interaction.is_none() {
if let Some(hover_window_interaction) = resize_hover(ctx, possible, area_layer_id, rect) {
hover_window_interaction.set_cursor(ctx);
let any_pressed = ctx.input().pointer.any_pressed(); // avoid deadlocks
if any_pressed && ctx.input().pointer.primary_down() {
ctx.memory().interaction.drag_id = Some(id);
ctx.memory().interaction.drag_is_window = true;
window_interaction = Some(hover_window_interaction);
ctx.memory().window_interaction = window_interaction;
}
}
}
if let Some(window_interaction) = window_interaction {
let is_active = ctx.memory().interaction.drag_id == Some(id);
if is_active && window_interaction.area_layer_id == area_layer_id {
return Some(window_interaction);
}
}
None
}

FWIW, I would probably label this a feature (make resize-handle a public widget) instead of a bug.

@apoorv569
Copy link
Contributor Author

There isn't a component for it, and all of the types used to draw and check for interactions are private. You can reimplement the basics by copying code or ideas. This is the "entry-point" for the resize handle on windows:

/// Returns `Some` if there is a move or resize
fn window_interaction(
ctx: &Context,
possible: PossibleInteractions,
area_layer_id: LayerId,
id: Id,
rect: Rect,
) -> Option<WindowInteraction> {
{
let drag_id = ctx.memory().interaction.drag_id;
if drag_id.is_some() && drag_id != Some(id) {
return None;
}
}
let mut window_interaction = { ctx.memory().window_interaction };
if window_interaction.is_none() {
if let Some(hover_window_interaction) = resize_hover(ctx, possible, area_layer_id, rect) {
hover_window_interaction.set_cursor(ctx);
let any_pressed = ctx.input().pointer.any_pressed(); // avoid deadlocks
if any_pressed && ctx.input().pointer.primary_down() {
ctx.memory().interaction.drag_id = Some(id);
ctx.memory().interaction.drag_is_window = true;
window_interaction = Some(hover_window_interaction);
ctx.memory().window_interaction = window_interaction;
}
}
}
if let Some(window_interaction) = window_interaction {
let is_active = ctx.memory().interaction.drag_id == Some(id);
if is_active && window_interaction.area_layer_id == area_layer_id {
return Some(window_interaction);
}
}
None
}

FWIW, I would probably label this a feature (make resize-handle a public widget) instead of a bug.

I was mostly just asking a question so it didn't made sense to use the feature template as I didn't know this is a internal only widget and the bug label automatically applies to all issues created using bug template.

But yea I will re-post this using feature template.

Thanks!

@j-n-f
Copy link

j-n-f commented May 30, 2024

For any one else looking for a quick and dirty way to do this

// offset from bottom right of window to trigger resize handle
let resize_area_size = 16.0;
// position of bottom right of window
let bottom_right = ui.max_rect().right_bottom();
// Easier to use a vector for the following math
let offset_vec = vec2(resize_area_size, resize_area_size);
// rect giving a square area at the bottom right of the window where the resize can be triggered
let bottom_right_resize_rect = bottom_right - offset_vec;
// set up the interaction so that the cursor changes and we can sense click/drag
let bottom_right_drag = ui.interact(bottom_right_resize_rect, "bottom-right-resize".into(), Sense::click_and_drag())
    .on_hover_cursor(egui::CursorIcon::ResizeNwSe);
// if the rect gets dragged, just resize the window according to the current cursor position
if bottom_right_drag.dragged() {
    let current_pos = bottom_right_drag.interact_pointer_pos();
    if let Some(pos) = current_pos {
        // + `offset_vec` so that the interaction never falls outside of the window area
        ui.ctx().send_viewport_cmd(egui::ViewportCommand::InnerSize(pos.to_vec2() + offset_vec));
    }
}

// Follow this basic idea for all the other corners you want the interaction for ...

Only issue I ran into is that without the offset_vec sometimes the current drag interaction will fall outside the window (and interact_pointer_pos() will continually return None after that). Right now the interaction has to happen a little inset from the corner. If there was a sort of transparent area around the window you could get the interaction to occur right at the corner (rather than inset from it).

If anyone has thoughts on how to improve on this maybe it can be added to the demo code.

edit: you probably also want to add some logic to ensure that you maintain some minimum size. It's 100% possible to make the window too small to interact with.

Something like:

let effective_size = pos.to_vec2() + offset_vec;
ui.ctx().send_viewport_cmd(egui::ViewportComand::InnerSize(effective_size.max(640., 480.).into()));

Other considerations: if you're in fullscreen you probably want to disable this (though it does seem to work anyways).

@j-n-f
Copy link

j-n-f commented May 30, 2024

Another thing to look into, there's also egui::ViewportCommand::BeginResize. In the previous code you can re-write it like:

if bottom_right_drag.dragged() {
    ui.ctx().send_viewport_cmd(egui::ViewportCommand::BeginResize(egui::ResizeDirection::SouthEast));
}

It seems to resolve all the issues relating to the interaction position falling outside the window.

@ardocrat
Copy link

We have a problem with app window resize as we as with dragging, egui is not receiving event on mouse button release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something is broken
Projects
None yet
Development

No branches or pull requests

4 participants