From 4e0504febd931c46f0e2cb7f9fab1309d9831d90 Mon Sep 17 00:00:00 2001 From: Luc Fauvel Date: Sun, 7 Apr 2024 14:25:04 -0400 Subject: [PATCH 1/7] Implemented resizing for non-decorated winit windows --- internal/backends/winit/drag_resize_window.rs | 96 +++++++++++++++++++ internal/backends/winit/event_loop.rs | 8 ++ internal/backends/winit/lib.rs | 2 + 3 files changed, 106 insertions(+) create mode 100644 internal/backends/winit/drag_resize_window.rs diff --git a/internal/backends/winit/drag_resize_window.rs b/internal/backends/winit/drag_resize_window.rs new file mode 100644 index 00000000000..fea422fdc71 --- /dev/null +++ b/internal/backends/winit/drag_resize_window.rs @@ -0,0 +1,96 @@ +use winit::window::{CursorIcon, ResizeDirection}; + +pub fn handle_cursor_move_for_resize( + window: &winit::window::Window, + position: winit::dpi::PhysicalPosition, + current_direction: Option, +) -> Option { + if !window.is_decorated() { + let location = get_resize_direction(window.inner_size(), position, 8_f64); + + if current_direction != location { + window.set_cursor_icon(resize_direction_cursor_icon(location)); + } + + return location; + } + + None +} + +pub fn handle_resize(window: &winit::window::Window, direction: Option) { + if let Some(dir) = direction { + let _ = window.drag_resize_window(dir); + } +} + +/// Get the cursor icon that corresponds to the resize direction. +fn resize_direction_cursor_icon(resize_direction: Option) -> 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, + } +} + +fn get_resize_direction( + win_size: winit::dpi::PhysicalSize, + position: winit::dpi::PhysicalPosition, + border_size: f64, +) -> Option { + enum X { + West, + East, + Default, + } + + enum Y { + North, + South, + Default, + } + + let xdir = if position.x < border_size { + X::West + } else if position.x > (win_size.width as f64 - border_size) { + X::East + } else { + X::Default + }; + + let ydir = if position.y < border_size { + Y::North + } else if position.y > (win_size.height as f64 - border_size) { + Y::South + } else { + Y::Default + }; + + Some(match xdir { + X::West => match ydir { + Y::North => ResizeDirection::NorthWest, + Y::South => ResizeDirection::SouthWest, + Y::Default => ResizeDirection::West, + }, + + X::East => match ydir { + Y::North => ResizeDirection::NorthEast, + Y::South => ResizeDirection::SouthEast, + Y::Default => ResizeDirection::East, + }, + + X::Default => match ydir { + Y::North => ResizeDirection::North, + Y::South => ResizeDirection::South, + Y::Default => return None, + }, + }) +} diff --git a/internal/backends/winit/event_loop.rs b/internal/backends/winit/event_loop.rs index 7309a660649..aab11375861 100644 --- a/internal/backends/winit/event_loop.rs +++ b/internal/backends/winit/event_loop.rs @@ -24,6 +24,8 @@ use std::cell::{RefCell, RefMut}; use std::rc::{Rc, Weak}; use winit::event::{Event, WindowEvent}; use winit::event_loop::EventLoopWindowTarget; +use winit::window::ResizeDirection; +use crate::drag_resize_window::{handle_cursor_move_for_resize, handle_resize}; #[cfg(not(target_arch = "wasm32"))] /// The Default, and the selection clippoard @@ -247,6 +249,7 @@ pub struct EventLoopState { pressed: bool, loop_error: Option, + current_resize_direction: Option, } impl EventLoopState { @@ -342,6 +345,7 @@ impl EventLoopState { runtime_window.process_key_input(event); } WindowEvent::CursorMoved { position, .. } => { + self.current_resize_direction = handle_cursor_move_for_resize(window.winit_window().as_ref(), position, self.current_resize_direction); let position = position.to_logical(runtime_window.scale_factor() as f64); self.cursor_pos = euclid::point2(position.x, position.y); runtime_window.process_mouse_input(MouseEvent::Moved { position: self.cursor_pos }); @@ -378,6 +382,10 @@ impl EventLoopState { }; let ev = match state { winit::event::ElementState::Pressed => { + if button == PointerEventButton::Left && self.current_resize_direction.is_some() { + handle_resize(window.winit_window().as_ref(), self.current_resize_direction) + } + self.pressed = true; MouseEvent::Pressed { position: self.cursor_pos, button, click_count: 0 } } diff --git a/internal/backends/winit/lib.rs b/internal/backends/winit/lib.rs index b8a9173f8a5..67b0b3021fb 100644 --- a/internal/backends/winit/lib.rs +++ b/internal/backends/winit/lib.rs @@ -12,7 +12,9 @@ use i_slint_core::window::WindowAdapter; use renderer::WinitCompatibleRenderer; use std::rc::Rc; +mod drag_resize_window; mod winitwindowadapter; + use i_slint_core::platform::PlatformError; use winitwindowadapter::*; pub(crate) mod event_loop; From bcd64b2882611c1d13dbebc5f05b4acc39ce5659 Mon Sep 17 00:00:00 2001 From: Luc Fauvel Date: Sun, 7 Apr 2024 15:09:00 -0400 Subject: [PATCH 2/7] Fixed formatting --- internal/backends/winit/event_loop.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/internal/backends/winit/event_loop.rs b/internal/backends/winit/event_loop.rs index aab11375861..ecb638b21e2 100644 --- a/internal/backends/winit/event_loop.rs +++ b/internal/backends/winit/event_loop.rs @@ -7,6 +7,7 @@ [WindowAdapter] trait used by the generated code and the run-time to change aspects of windows on the screen. */ +use crate::drag_resize_window::{handle_cursor_move_for_resize, handle_resize}; use crate::winitwindowadapter::WinitWindowAdapter; use crate::SlintUserEvent; #[cfg(not(target_arch = "wasm32"))] @@ -25,7 +26,6 @@ use std::rc::{Rc, Weak}; use winit::event::{Event, WindowEvent}; use winit::event_loop::EventLoopWindowTarget; use winit::window::ResizeDirection; -use crate::drag_resize_window::{handle_cursor_move_for_resize, handle_resize}; #[cfg(not(target_arch = "wasm32"))] /// The Default, and the selection clippoard @@ -345,7 +345,11 @@ impl EventLoopState { runtime_window.process_key_input(event); } WindowEvent::CursorMoved { position, .. } => { - self.current_resize_direction = handle_cursor_move_for_resize(window.winit_window().as_ref(), position, self.current_resize_direction); + self.current_resize_direction = handle_cursor_move_for_resize( + window.winit_window().as_ref(), + position, + self.current_resize_direction, + ); let position = position.to_logical(runtime_window.scale_factor() as f64); self.cursor_pos = euclid::point2(position.x, position.y); runtime_window.process_mouse_input(MouseEvent::Moved { position: self.cursor_pos }); @@ -382,8 +386,13 @@ impl EventLoopState { }; let ev = match state { winit::event::ElementState::Pressed => { - if button == PointerEventButton::Left && self.current_resize_direction.is_some() { - handle_resize(window.winit_window().as_ref(), self.current_resize_direction) + if button == PointerEventButton::Left + && self.current_resize_direction.is_some() + { + handle_resize( + window.winit_window().as_ref(), + self.current_resize_direction, + ) } self.pressed = true; From 839fcb8de6d5184438b8715718f17659d2c0b3af Mon Sep 17 00:00:00 2001 From: Luc Fauvel Date: Sat, 13 Apr 2024 19:58:31 -0400 Subject: [PATCH 3/7] Changed direction match to use a tuple, reduced resize border size, returned after handling resize --- internal/backends/winit/drag_resize_window.rs | 28 ++++++++----------- internal/backends/winit/event_loop.rs | 3 +- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/internal/backends/winit/drag_resize_window.rs b/internal/backends/winit/drag_resize_window.rs index fea422fdc71..81e473e95e7 100644 --- a/internal/backends/winit/drag_resize_window.rs +++ b/internal/backends/winit/drag_resize_window.rs @@ -6,7 +6,7 @@ pub fn handle_cursor_move_for_resize( current_direction: Option, ) -> Option { if !window.is_decorated() { - let location = get_resize_direction(window.inner_size(), position, 8_f64); + let location = get_resize_direction(window.inner_size(), position, 3_f64); if current_direction != location { window.set_cursor_icon(resize_direction_cursor_icon(location)); @@ -74,23 +74,17 @@ fn get_resize_direction( Y::Default }; - Some(match xdir { - X::West => match ydir { - Y::North => ResizeDirection::NorthWest, - Y::South => ResizeDirection::SouthWest, - Y::Default => ResizeDirection::West, - }, + Some(match (xdir, ydir) { + (X::West, Y::North) => ResizeDirection::NorthWest, + (X::West, Y::South) => ResizeDirection::SouthWest, + (X::West, Y::Default) => ResizeDirection::West, - X::East => match ydir { - Y::North => ResizeDirection::NorthEast, - Y::South => ResizeDirection::SouthEast, - Y::Default => ResizeDirection::East, - }, + (X::East, Y::North) => ResizeDirection::NorthEast, + (X::East, Y::South) => ResizeDirection::SouthEast, + (X::East, Y::Default) => ResizeDirection::East, - X::Default => match ydir { - Y::North => ResizeDirection::North, - Y::South => ResizeDirection::South, - Y::Default => return None, - }, + (X::Default, Y::North) => ResizeDirection::North, + (X::Default, Y::South) => ResizeDirection::South, + (X::Default, Y::Default) => return None, }) } diff --git a/internal/backends/winit/event_loop.rs b/internal/backends/winit/event_loop.rs index ecb638b21e2..eb127526ecd 100644 --- a/internal/backends/winit/event_loop.rs +++ b/internal/backends/winit/event_loop.rs @@ -392,7 +392,8 @@ impl EventLoopState { handle_resize( window.winit_window().as_ref(), self.current_resize_direction, - ) + ); + return; } self.pressed = true; From e287d3920741b157e897ffdb00d4ac002a8815f8 Mon Sep 17 00:00:00 2001 From: Luc Fauvel Date: Sat, 13 Apr 2024 20:01:23 -0400 Subject: [PATCH 4/7] Added is resizable check for before resizing winit window --- internal/backends/winit/drag_resize_window.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/backends/winit/drag_resize_window.rs b/internal/backends/winit/drag_resize_window.rs index 81e473e95e7..412a67d9472 100644 --- a/internal/backends/winit/drag_resize_window.rs +++ b/internal/backends/winit/drag_resize_window.rs @@ -5,7 +5,7 @@ pub fn handle_cursor_move_for_resize( position: winit::dpi::PhysicalPosition, current_direction: Option, ) -> Option { - if !window.is_decorated() { + if !window.is_decorated() && window.is_resizable() { let location = get_resize_direction(window.inner_size(), position, 3_f64); if current_direction != location { From 52f68a2672d9674cf0dfc1576624aab30c9f7df8 Mon Sep 17 00:00:00 2001 From: Luc Fauvel Date: Tue, 16 Apr 2024 20:07:16 -0400 Subject: [PATCH 5/7] Added resize-border property to window --- docs/reference/src/language/builtins/elements.md | 1 + internal/backends/winit/drag_resize_window.rs | 3 ++- internal/backends/winit/event_loop.rs | 1 + internal/compiler/builtins.slint | 1 + internal/core/items.rs | 1 + 5 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/reference/src/language/builtins/elements.md b/docs/reference/src/language/builtins/elements.md index bbbea333f13..5a297a09e72 100644 --- a/docs/reference/src/language/builtins/elements.md +++ b/docs/reference/src/language/builtins/elements.md @@ -864,4 +864,5 @@ or smaller. The initial width can be controlled with the `preferred-width` prope - **`default-font-weight`** (_in_ _int_): The font weight to use as default in text elements inside this window, that don't have their `font-weight` property set. The values range from 100 (lightest) to 900 (thickest). 400 is the normal weight. - **`icon`** (_in_ _image_): The window icon shown in the title bar or the task bar on window managers supporting it. - **`no-frame`** (_in_ _bool_): Whether the window should be borderless/frameless or not. +- **`resize-border`** (_in_ _float_): Size of the resize border in borderless/frameless windows (winit only for now). - **`title`** (_in_ _string_): The window title that is shown in the title bar. diff --git a/internal/backends/winit/drag_resize_window.rs b/internal/backends/winit/drag_resize_window.rs index 412a67d9472..b7912c45808 100644 --- a/internal/backends/winit/drag_resize_window.rs +++ b/internal/backends/winit/drag_resize_window.rs @@ -4,9 +4,10 @@ pub fn handle_cursor_move_for_resize( window: &winit::window::Window, position: winit::dpi::PhysicalPosition, current_direction: Option, + border_size: f64, ) -> Option { if !window.is_decorated() && window.is_resizable() { - let location = get_resize_direction(window.inner_size(), position, 3_f64); + let location = get_resize_direction(window.inner_size(), position, border_size); if current_direction != location { window.set_cursor_icon(resize_direction_cursor_icon(location)); diff --git a/internal/backends/winit/event_loop.rs b/internal/backends/winit/event_loop.rs index eb127526ecd..dd0ef2c14a9 100644 --- a/internal/backends/winit/event_loop.rs +++ b/internal/backends/winit/event_loop.rs @@ -349,6 +349,7 @@ impl EventLoopState { window.winit_window().as_ref(), position, self.current_resize_direction, + runtime_window.window_item().map_or(0_f64, |w| w.as_pin_ref().resize_border().into()) ); let position = position.to_logical(runtime_window.scale_factor() as f64); self.cursor_pos = euclid::point2(position.x, position.y); diff --git a/internal/compiler/builtins.slint b/internal/compiler/builtins.slint index 2912c4adc3f..9452991825b 100644 --- a/internal/compiler/builtins.slint +++ b/internal/compiler/builtins.slint @@ -149,6 +149,7 @@ component WindowItem { in property color <=> background; in property title: "Slint Window"; in property no-frame; + in property resize-border; in property always-on-top; in property default-font-family; in-out property default-font-size; // <=> StyleMetrics.default-font-size set in apply_default_properties_from_style diff --git a/internal/core/items.rs b/internal/core/items.rs index 9c1276b0de0..dd20ec51f9f 100644 --- a/internal/core/items.rs +++ b/internal/core/items.rs @@ -1254,6 +1254,7 @@ pub struct WindowItem { pub background: Property, pub title: Property, pub no_frame: Property, + pub resize_border: Property, pub always_on_top: Property, pub icon: Property, pub default_font_family: Property, From 496ef1b277380816bc5bb06b664ef5905fc35a77 Mon Sep 17 00:00:00 2001 From: Luc Fauvel Date: Tue, 16 Apr 2024 20:32:24 -0400 Subject: [PATCH 6/7] Formatted code --- internal/backends/winit/drag_resize_window.rs | 2 +- internal/backends/winit/event_loop.rs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/internal/backends/winit/drag_resize_window.rs b/internal/backends/winit/drag_resize_window.rs index b7912c45808..dc6cd9b846e 100644 --- a/internal/backends/winit/drag_resize_window.rs +++ b/internal/backends/winit/drag_resize_window.rs @@ -76,7 +76,7 @@ fn get_resize_direction( }; Some(match (xdir, ydir) { - (X::West, Y::North) => ResizeDirection::NorthWest, + (X::West, Y::North) => ResizeDirection::NorthWest, (X::West, Y::South) => ResizeDirection::SouthWest, (X::West, Y::Default) => ResizeDirection::West, diff --git a/internal/backends/winit/event_loop.rs b/internal/backends/winit/event_loop.rs index dd0ef2c14a9..133d25ef1ea 100644 --- a/internal/backends/winit/event_loop.rs +++ b/internal/backends/winit/event_loop.rs @@ -349,7 +349,9 @@ impl EventLoopState { window.winit_window().as_ref(), position, self.current_resize_direction, - runtime_window.window_item().map_or(0_f64, |w| w.as_pin_ref().resize_border().into()) + runtime_window + .window_item() + .map_or(0_f64, |w| w.as_pin_ref().resize_border().into()), ); let position = position.to_logical(runtime_window.scale_factor() as f64); self.cursor_pos = euclid::point2(position.x, position.y); From 3a0fc1835a80fc9a6c43a5600c9880e21c5f1ae5 Mon Sep 17 00:00:00 2001 From: Luc Fauvel Date: Sat, 11 May 2024 21:16:45 -0400 Subject: [PATCH 7/7] Change resize-border from float to length --- docs/reference/src/language/builtins/elements.md | 2 +- internal/backends/winit/event_loop.rs | 2 +- internal/compiler/builtins.slint | 2 +- internal/core/items.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/reference/src/language/builtins/elements.md b/docs/reference/src/language/builtins/elements.md index 5a297a09e72..6feaf1564bc 100644 --- a/docs/reference/src/language/builtins/elements.md +++ b/docs/reference/src/language/builtins/elements.md @@ -864,5 +864,5 @@ or smaller. The initial width can be controlled with the `preferred-width` prope - **`default-font-weight`** (_in_ _int_): The font weight to use as default in text elements inside this window, that don't have their `font-weight` property set. The values range from 100 (lightest) to 900 (thickest). 400 is the normal weight. - **`icon`** (_in_ _image_): The window icon shown in the title bar or the task bar on window managers supporting it. - **`no-frame`** (_in_ _bool_): Whether the window should be borderless/frameless or not. -- **`resize-border`** (_in_ _float_): Size of the resize border in borderless/frameless windows (winit only for now). +- **`resize-border`** (_in_ _length_): Size of the resize border in borderless/frameless windows (winit only for now). - **`title`** (_in_ _string_): The window title that is shown in the title bar. diff --git a/internal/backends/winit/event_loop.rs b/internal/backends/winit/event_loop.rs index 133d25ef1ea..d9acb7aa221 100644 --- a/internal/backends/winit/event_loop.rs +++ b/internal/backends/winit/event_loop.rs @@ -351,7 +351,7 @@ impl EventLoopState { self.current_resize_direction, runtime_window .window_item() - .map_or(0_f64, |w| w.as_pin_ref().resize_border().into()), + .map_or(0_f64, |w| w.as_pin_ref().resize_border().0.into()), ); let position = position.to_logical(runtime_window.scale_factor() as f64); self.cursor_pos = euclid::point2(position.x, position.y); diff --git a/internal/compiler/builtins.slint b/internal/compiler/builtins.slint index 9452991825b..f17ba9be829 100644 --- a/internal/compiler/builtins.slint +++ b/internal/compiler/builtins.slint @@ -149,7 +149,7 @@ component WindowItem { in property color <=> background; in property title: "Slint Window"; in property no-frame; - in property resize-border; + in property resize-border; in property always-on-top; in property default-font-family; in-out property default-font-size; // <=> StyleMetrics.default-font-size set in apply_default_properties_from_style diff --git a/internal/core/items.rs b/internal/core/items.rs index dd20ec51f9f..10af80b69d0 100644 --- a/internal/core/items.rs +++ b/internal/core/items.rs @@ -1254,7 +1254,7 @@ pub struct WindowItem { pub background: Property, pub title: Property, pub no_frame: Property, - pub resize_border: Property, + pub resize_border: Property, pub always_on_top: Property, pub icon: Property, pub default_font_family: Property,