Skip to main content

i_slint_backend_winit/
drag_resize_window.rs

1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4// cSpell: ignore xdir ydir
5use i_slint_core::lengths::LogicalLength;
6use winit::window::{CursorIcon, ResizeDirection};
7
8pub fn handle_cursor_move_for_resize(
9    window: &winit::window::Window,
10    position: winit::dpi::PhysicalPosition<f64>,
11    current_direction: Option<ResizeDirection>,
12    border_width: LogicalLength,
13) -> Option<ResizeDirection> {
14    if !window.is_decorated() && window.is_resizable() {
15        let border_size = f64::from(border_width.get()) * window.scale_factor();
16        let location = get_resize_direction(window.inner_size(), position, border_size);
17
18        if current_direction != location {
19            window.set_cursor(resize_direction_cursor_icon(location));
20        }
21
22        return location;
23    }
24
25    None
26}
27
28pub fn handle_resize(window: &winit::window::Window, direction: Option<ResizeDirection>) {
29    if let Some(dir) = direction {
30        let _ = window.drag_resize_window(dir);
31    }
32}
33
34/// Get the cursor icon that corresponds to the resize direction.
35fn resize_direction_cursor_icon(resize_direction: Option<ResizeDirection>) -> CursorIcon {
36    match resize_direction {
37        Some(resize_direction) => match resize_direction {
38            ResizeDirection::East => CursorIcon::EResize,
39            ResizeDirection::North => CursorIcon::NResize,
40            ResizeDirection::NorthEast => CursorIcon::NeResize,
41            ResizeDirection::NorthWest => CursorIcon::NwResize,
42            ResizeDirection::South => CursorIcon::SResize,
43            ResizeDirection::SouthEast => CursorIcon::SeResize,
44            ResizeDirection::SouthWest => CursorIcon::SwResize,
45            ResizeDirection::West => CursorIcon::WResize,
46        },
47        None => CursorIcon::Default,
48    }
49}
50
51fn get_resize_direction(
52    win_size: winit::dpi::PhysicalSize<u32>,
53    position: winit::dpi::PhysicalPosition<f64>,
54    border_size: f64,
55) -> Option<ResizeDirection> {
56    enum X {
57        West,
58        East,
59        Default,
60    }
61
62    enum Y {
63        North,
64        South,
65        Default,
66    }
67
68    let xdir = if position.x < border_size {
69        X::West
70    } else if position.x > (win_size.width as f64 - border_size) {
71        X::East
72    } else {
73        X::Default
74    };
75
76    let ydir = if position.y < border_size {
77        Y::North
78    } else if position.y > (win_size.height as f64 - border_size) {
79        Y::South
80    } else {
81        Y::Default
82    };
83
84    Some(match (xdir, ydir) {
85        (X::West, Y::North) => ResizeDirection::NorthWest,
86        (X::West, Y::South) => ResizeDirection::SouthWest,
87        (X::West, Y::Default) => ResizeDirection::West,
88
89        (X::East, Y::North) => ResizeDirection::NorthEast,
90        (X::East, Y::South) => ResizeDirection::SouthEast,
91        (X::East, Y::Default) => ResizeDirection::East,
92
93        (X::Default, Y::North) => ResizeDirection::North,
94        (X::Default, Y::South) => ResizeDirection::South,
95        (X::Default, Y::Default) => return None,
96    })
97}