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

Implemented resizing for non-decorated winit windows #5026

Merged
merged 7 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/reference/src/language/builtins/elements.md
Original file line number Diff line number Diff line change
Expand Up @@ -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_ _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.
91 changes: 91 additions & 0 deletions internal/backends/winit/drag_resize_window.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use winit::window::{CursorIcon, ResizeDirection};

pub fn handle_cursor_move_for_resize(
window: &winit::window::Window,
position: winit::dpi::PhysicalPosition<f64>,
current_direction: Option<ResizeDirection>,
border_size: f64,
) -> Option<ResizeDirection> {
if !window.is_decorated() && window.is_resizable() {
let location = get_resize_direction(window.inner_size(), position, border_size);

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<ResizeDirection>) {
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<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,
}
}

fn get_resize_direction(
win_size: winit::dpi::PhysicalSize<u32>,
position: winit::dpi::PhysicalPosition<f64>,
border_size: f64,
) -> Option<ResizeDirection> {
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, ydir) {
(X::West, Y::North) => ResizeDirection::NorthWest,
(X::West, Y::South) => ResizeDirection::SouthWest,
(X::West, Y::Default) => ResizeDirection::West,

(X::East, Y::North) => ResizeDirection::NorthEast,
(X::East, Y::South) => ResizeDirection::SouthEast,
(X::East, Y::Default) => ResizeDirection::East,

(X::Default, Y::North) => ResizeDirection::North,
(X::Default, Y::South) => ResizeDirection::South,
(X::Default, Y::Default) => return None,
})
}
21 changes: 21 additions & 0 deletions internal/backends/winit/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"))]
Expand All @@ -24,6 +25,7 @@ use std::cell::{RefCell, RefMut};
use std::rc::{Rc, Weak};
use winit::event::{Event, WindowEvent};
use winit::event_loop::EventLoopWindowTarget;
use winit::window::ResizeDirection;

#[cfg(not(target_arch = "wasm32"))]
/// The Default, and the selection clippoard
Expand Down Expand Up @@ -247,6 +249,7 @@ pub struct EventLoopState {
pressed: bool,

loop_error: Option<PlatformError>,
current_resize_direction: Option<ResizeDirection>,
}

impl EventLoopState {
Expand Down Expand Up @@ -342,6 +345,14 @@ 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,
runtime_window
.window_item()
.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);
runtime_window.process_mouse_input(MouseEvent::Moved { position: self.cursor_pos });
Expand Down Expand Up @@ -378,6 +389,16 @@ 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,
);
return;
}

self.pressed = true;
MouseEvent::Pressed { position: self.cursor_pos, button, click_count: 0 }
}
Expand Down
2 changes: 2 additions & 0 deletions internal/backends/winit/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions internal/compiler/builtins.slint
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ component WindowItem {
in property <brush> color <=> background;
in property <string> title: "Slint Window";
in property <bool> no-frame;
in property <length> resize-border;
in property <bool> always-on-top;
in property <string> default-font-family;
in-out property <length> default-font-size; // <=> StyleMetrics.default-font-size set in apply_default_properties_from_style
Expand Down
1 change: 1 addition & 0 deletions internal/core/items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1254,6 +1254,7 @@ pub struct WindowItem {
pub background: Property<Brush>,
pub title: Property<SharedString>,
pub no_frame: Property<bool>,
pub resize_border: Property<LogicalLength>,
pub always_on_top: Property<bool>,
pub icon: Property<crate::graphics::Image>,
pub default_font_family: Property<SharedString>,
Expand Down
Loading