Skip to content

Commit

Permalink
feat(winit): client-side resize drag support
Browse files Browse the repository at this point in the history
  • Loading branch information
mmstick committed Aug 18, 2023
1 parent 2a3cb0f commit b673028
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/window/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ pub struct Settings {
/// The initial size of the window.
pub size: (u32, u32),

/// The border area for the drag resize handle.
pub resize_border: u32,

/// The initial position of the window.
pub position: Position,

Expand Down Expand Up @@ -43,6 +46,7 @@ impl Default for Settings {
fn default() -> Settings {
Settings {
size: (1024, 768),
resize_border: 8,
position: Position::default(),
min_size: None,
max_size: None,
Expand All @@ -61,6 +65,7 @@ impl From<Settings> for iced_winit::settings::Window {
fn from(settings: Settings) -> Self {
Self {
size: settings.size,
resize_border: settings.resize_border,
position: iced_winit::Position::from(settings.position),
min_size: settings.min_size,
max_size: settings.max_size,
Expand Down
18 changes: 18 additions & 0 deletions winit/src/application.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//! Create interactive, native cross-platform applications.
mod drag_resize;
#[cfg(feature = "trace")]
mod profiler;
mod state;
Expand Down Expand Up @@ -125,6 +126,8 @@ where
let mut debug = Debug::new();
debug.startup_started();

let resize_border = settings.window.resize_border;

#[cfg(feature = "trace")]
let _ = info_span!("Application", "RUN").entered();

Expand Down Expand Up @@ -212,6 +215,7 @@ where
window,
should_be_visible,
settings.exit_on_close_request,
resize_border,
);

#[cfg(feature = "trace")]
Expand Down Expand Up @@ -279,6 +283,7 @@ async fn run_instance<A, E, C>(
window: winit::window::Window,
should_be_visible: bool,
exit_on_close_request: bool,
resize_border: u32,
) where
A: Application + 'static,
E: Executor + 'static,
Expand Down Expand Up @@ -331,6 +336,12 @@ async fn run_instance<A, E, C>(
&mut debug,
));

// Creates closure for handling the window drag resize state with winit.
let mut drag_resize_window_func = drag_resize::event_func(
&window,
resize_border as f64 * window.scale_factor(),
);

let mut mouse_interaction = mouse::Interaction::default();
let mut events = Vec::new();
let mut messages = Vec::new();
Expand Down Expand Up @@ -562,6 +573,13 @@ async fn run_instance<A, E, C>(
event: window_event,
..
} => {
// Initiates a drag resize window state when found.
if let Some(func) = drag_resize_window_func.as_mut() {
if func(&window, &window_event) {
continue;
}
}

if requests_exit(&window_event, state.modifiers())
&& exit_on_close_request
{
Expand Down
132 changes: 132 additions & 0 deletions winit/src/application/drag_resize.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
use winit::window::{CursorIcon, ResizeDirection};

/// If supported by winit, returns a closure that implements cursor resize support.
pub fn event_func(
window: &winit::window::Window,
border_size: f64,
) -> Option<
impl FnMut(&winit::window::Window, &winit::event::WindowEvent<'_>) -> bool,
> {
if window.drag_resize_window(ResizeDirection::East).is_ok() {
// Keep track of cursor when it is within a resizeable border.
let mut cursor_prev_resize_direction = None;

Some(
move |window: &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::CursorMoved {
position, ..
} => {
if !window.is_decorated() {
let location = cursor_resize_direction(
window.inner_size(),
*position,
border_size,
);
if location != cursor_prev_resize_direction {
window.set_cursor_icon(
resize_direction_cursor_icon(location),
);
cursor_prev_resize_direction = location;
return true;
}
}
}
winit::event::WindowEvent::MouseInput {
state: winit::event::ElementState::Pressed,
button: winit::event::MouseButton::Left,
..
} => {
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,
},
})
}
5 changes: 5 additions & 0 deletions winit/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ pub struct Window {
/// The size of the window.
pub size: (u32, u32),

/// The border area for the drag resize handle.
pub resize_border: u32,

/// The position of the window.
pub position: Position,

Expand Down Expand Up @@ -100,6 +103,7 @@ impl fmt::Debug for Window {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Window")
.field("size", &self.size)
.field("resize_border", &self.resize_border)
.field("position", &self.position)
.field("min_size", &self.min_size)
.field("max_size", &self.max_size)
Expand Down Expand Up @@ -226,6 +230,7 @@ impl Default for Window {
fn default() -> Window {
Window {
size: (1024, 768),
resize_border: 8,
position: Position::default(),
min_size: None,
max_size: None,
Expand Down

0 comments on commit b673028

Please sign in to comment.