iced-yoda/winit/src/application/drag_resize.rs

172 lines
5.6 KiB
Rust

use cursor_icon::CursorIcon;
use winit::window::ResizeDirection;
#[cfg(any(
all(
unix,
not(target_vendor = "apple"),
not(target_os = "android"),
not(target_os = "emscripten"),
),
target_os = "windows",
))]
const DRAG_RESIZE_SUPPORTED: bool = true;
#[cfg(not(any(
all(
unix,
not(target_vendor = "apple"),
not(target_os = "android"),
not(target_os = "emscripten"),
),
target_os = "windows",
)))]
const DRAG_RESIZE_SUPPORTED: bool = false;
/// If supported by winit, returns a closure that implements cursor resize support.
pub fn event_func(
window: &dyn winit::window::Window,
border_size: f64,
) -> Option<
Box<
dyn FnMut(
&dyn winit::window::Window,
&winit::event::WindowEvent,
) -> bool,
>,
> {
if DRAG_RESIZE_SUPPORTED {
// Keep track of cursor when it is within a resizeable border.
let mut cursor_prev_resize_direction = None;
Some(Box::new(
move |window: &dyn winit::window::Window,
window_event: &winit::event::WindowEvent|
-> bool {
// Keep track of border resize state and set cursor icon when in range
match window_event {
winit::event::WindowEvent::PointerMoved {
position,
..
} => {
let resizable = !window.is_decorated()
&& !window.is_maximized()
&& window.fullscreen().is_none();
if resizable {
let location = cursor_resize_direction(
window.surface_size(),
*position,
border_size,
);
if location != cursor_prev_resize_direction {
window.set_cursor(
resize_direction_cursor_icon(location)
.into(),
);
cursor_prev_resize_direction = location;
return true;
}
}
}
winit::event::WindowEvent::PointerButton {
state: winit::event::ElementState::Pressed,
button:
winit::event::ButtonSource::Mouse(
winit::event::MouseButton::Left,
)
| winit::event::ButtonSource::Touch {
finger_id: _, ..
},
primary: true,
..
} => {
if let Some(direction) = cursor_prev_resize_direction {
let _res = window.drag_resize_window(direction);
return true;
}
}
_ => (),
}
false
},
))
} else {
None
}
}
/// Get the cursor icon that corresponds to the resize direction.
fn resize_direction_cursor_icon(
resize_direction: Option<ResizeDirection>,
) -> CursorIcon {
match resize_direction {
Some(resize_direction) => match resize_direction {
ResizeDirection::East => CursorIcon::EResize,
ResizeDirection::North => CursorIcon::NResize,
ResizeDirection::NorthEast => CursorIcon::NeResize,
ResizeDirection::NorthWest => CursorIcon::NwResize,
ResizeDirection::South => CursorIcon::SResize,
ResizeDirection::SouthEast => CursorIcon::SeResize,
ResizeDirection::SouthWest => CursorIcon::SwResize,
ResizeDirection::West => CursorIcon::WResize,
},
None => CursorIcon::Default,
}
}
/// Identifies resize direction based on cursor position and window dimensions.
#[allow(clippy::similar_names)]
fn cursor_resize_direction(
win_size: winit::dpi::PhysicalSize<u32>,
position: winit::dpi::PhysicalPosition<f64>,
border_size: f64,
) -> Option<ResizeDirection> {
enum XDirection {
West,
East,
Default,
}
enum YDirection {
North,
South,
Default,
}
let xdir = if position.x < border_size {
XDirection::West
} else if position.x > (win_size.width as f64 - border_size) {
XDirection::East
} else {
XDirection::Default
};
let ydir = if position.y < border_size {
YDirection::North
} else if position.y > (win_size.height as f64 - border_size) {
YDirection::South
} else {
YDirection::Default
};
Some(match xdir {
XDirection::West => match ydir {
YDirection::North => ResizeDirection::NorthWest,
YDirection::South => ResizeDirection::SouthWest,
YDirection::Default => ResizeDirection::West,
},
XDirection::East => match ydir {
YDirection::North => ResizeDirection::NorthEast,
YDirection::South => ResizeDirection::SouthEast,
YDirection::Default => ResizeDirection::East,
},
XDirection::Default => match ydir {
YDirection::North => ResizeDirection::North,
YDirection::South => ResizeDirection::South,
YDirection::Default => return None,
},
})
}