Skip to content

Commit

Permalink
feat: add drag_resize_window (#829)
Browse files Browse the repository at this point in the history
* feat: add `drag_resize_window`

* fix android
  • Loading branch information
amrbashir authored Oct 29, 2023
1 parent 43c94f0 commit f497b5d
Show file tree
Hide file tree
Showing 14 changed files with 308 additions and 189 deletions.
5 changes: 5 additions & 0 deletions .changes/drag_resize_window.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tao": "patch"
---

Add `Window::drag_resize_window` and `ResizeDirection` enum to initialize window resizing. Supported on Windows and Linux only.
2 changes: 1 addition & 1 deletion src/platform/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use std::{os::raw::c_int, sync::Arc};
#[doc(hidden)]
pub use crate::platform_impl::x11;

pub use crate::platform_impl::{hit_test, EventLoop as UnixEventLoop};
pub use crate::platform_impl::EventLoop as UnixEventLoop;
use crate::{
event_loop::{EventLoopBuilder, EventLoopWindowTarget},
platform_impl::{x11::xdisplay::XError, Parent},
Expand Down
1 change: 0 additions & 1 deletion src/platform/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

use std::path::Path;

pub use crate::platform_impl::hit_test;
use crate::{
dpi::PhysicalSize,
event::DeviceId,
Expand Down
11 changes: 10 additions & 1 deletion src/platform_impl/android/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{
event_loop::{self, ControlFlow},
keyboard::{Key, KeyCode, KeyLocation, NativeKeyCode},
monitor,
window::{self, Theme, WindowSizeConstraints},
window::{self, ResizeDirection, Theme, WindowSizeConstraints},
};
use crossbeam_channel::{Receiver, Sender};
use ndk::{
Expand Down Expand Up @@ -677,6 +677,15 @@ impl Window {
))
}

pub fn drag_resize_window(
&self,
_direction: ResizeDirection,
) -> Result<(), error::ExternalError> {
Err(error::ExternalError::NotSupported(
error::NotSupportedError::new(),
))
}

pub fn set_ignore_cursor_events(&self, _ignore: bool) -> Result<(), error::ExternalError> {
Err(error::ExternalError::NotSupported(
error::NotSupportedError::new(),
Expand Down
8 changes: 6 additions & 2 deletions src/platform_impl/ios/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ use crate::{
monitor, view, EventLoopWindowTarget, MonitorHandle,
},
window::{
CursorIcon, Fullscreen, Theme, UserAttentionType, WindowAttributes, WindowId as RootWindowId,
WindowSizeConstraints,
CursorIcon, Fullscreen, ResizeDirection, Theme, UserAttentionType, WindowAttributes,
WindowId as RootWindowId, WindowSizeConstraints,
},
};

Expand Down Expand Up @@ -222,6 +222,10 @@ impl Inner {
Err(ExternalError::NotSupported(NotSupportedError::new()))
}

pub fn drag_resize_window(&self, _direction: ResizeDirection) -> Result<(), ExternalError> {
Err(ExternalError::NotSupported(NotSupportedError::new()))
}

pub fn set_ignore_cursor_events(&self, _ignore: bool) -> Result<(), ExternalError> {
Err(ExternalError::NotSupported(NotSupportedError::new()))
}
Expand Down
203 changes: 134 additions & 69 deletions src/platform_impl/linux/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ use crate::{
event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW},
keyboard::ModifiersState,
monitor::MonitorHandle as RootMonitorHandle,
platform_impl::platform::{device, window::hit_test, DEVICE_ID},
window::{CursorIcon, Fullscreen, ProgressBarState, WindowId as RootWindowId},
platform_impl::platform::{device, DEVICE_ID},
window::{CursorIcon, Fullscreen, ProgressBarState, ResizeDirection, WindowId as RootWindowId},
};

use super::{
Expand Down Expand Up @@ -290,6 +290,22 @@ impl<T: 'static> EventLoop<T> {
window.begin_move_drag(1, x, y, 0);
}
}
WindowRequest::DragResizeWindow(direction) => {
if let Some(cursor) = window
.display()
.default_seat()
.and_then(|seat| seat.pointer())
{
let (_, x, y) = cursor.position();
window.begin_resize_drag(
direction.to_gtk_edge(),
1,
x,
y,
gtk::gdk::ffi::GDK_CURRENT_TIME as _,
);
}
}
WindowRequest::Fullscreen(fullscreen) => match fullscreen {
Some(f) => {
if let Fullscreen::Borderless(m) = f {
Expand Down Expand Up @@ -339,49 +355,9 @@ impl<T: 'static> EventLoop<T> {
if let Some(gdk_window) = window.window() {
let display = window.display();
match cursor {
Some(cr) => gdk_window.set_cursor(
Cursor::from_name(
&display,
match cr {
CursorIcon::Crosshair => "crosshair",
CursorIcon::Hand => "pointer",
CursorIcon::Arrow => "arrow",
CursorIcon::Move => "move",
CursorIcon::Text => "text",
CursorIcon::Wait => "wait",
CursorIcon::Help => "help",
CursorIcon::Progress => "progress",
CursorIcon::NotAllowed => "not-allowed",
CursorIcon::ContextMenu => "context-menu",
CursorIcon::Cell => "cell",
CursorIcon::VerticalText => "vertical-text",
CursorIcon::Alias => "alias",
CursorIcon::Copy => "copy",
CursorIcon::NoDrop => "no-drop",
CursorIcon::Grab => "grab",
CursorIcon::Grabbing => "grabbing",
CursorIcon::AllScroll => "all-scroll",
CursorIcon::ZoomIn => "zoom-in",
CursorIcon::ZoomOut => "zoom-out",
CursorIcon::EResize => "e-resize",
CursorIcon::NResize => "n-resize",
CursorIcon::NeResize => "ne-resize",
CursorIcon::NwResize => "nw-resize",
CursorIcon::SResize => "s-resize",
CursorIcon::SeResize => "se-resize",
CursorIcon::SwResize => "sw-resize",
CursorIcon::WResize => "w-resize",
CursorIcon::EwResize => "ew-resize",
CursorIcon::NsResize => "ns-resize",
CursorIcon::NeswResize => "nesw-resize",
CursorIcon::NwseResize => "nwse-resize",
CursorIcon::ColResize => "col-resize",
CursorIcon::RowResize => "row-resize",
CursorIcon::Default => "default",
},
)
.as_ref(),
),
Some(cr) => {
gdk_window.set_cursor(Cursor::from_name(&display, cr.to_str()).as_ref())
}
None => gdk_window
.set_cursor(Cursor::for_display(&display, CursorType::BlankCursor).as_ref()),
}
Expand Down Expand Up @@ -429,24 +405,20 @@ impl<T: 'static> EventLoop<T> {
if !window.is_decorated() && window.is_resizable() && !window.is_maximized() {
if let Some(window) = window.window() {
let (cx, cy) = event.root();
let edge = hit_test(&window, cx, cy);
window.set_cursor(
Cursor::from_name(
&window.display(),
match edge {
WindowEdge::North => "n-resize",
WindowEdge::South => "s-resize",
WindowEdge::East => "e-resize",
WindowEdge::West => "w-resize",
WindowEdge::NorthWest => "nw-resize",
WindowEdge::NorthEast => "ne-resize",
WindowEdge::SouthEast => "se-resize",
WindowEdge::SouthWest => "sw-resize",
_ => "default",
},
)
.as_ref(),
let (left, top) = window.position();
let (w, h) = (window.width(), window.height());
let (right, bottom) = (left + w, top + h);
let edge = crate::window::hit_test(
(left, top, right, bottom),
cx as _,
cy as _,
window.scale_factor() as _,
);
let edge = match &edge {
Some(e) => e.to_cursor_str(),
None => "default",
};
window.set_cursor(Cursor::from_name(&window.display(), edge).as_ref());
}
}
glib::Propagation::Proceed
Expand All @@ -455,14 +427,25 @@ impl<T: 'static> EventLoop<T> {
if !window.is_decorated() && window.is_resizable() && event.button() == 1 {
if let Some(window) = window.window() {
let (cx, cy) = event.root();
let result = hit_test(&window, cx, cy);

let (left, top) = window.position();
let (w, h) = (window.width(), window.height());
let (right, bottom) = (left + w, top + h);
let edge = crate::window::hit_test(
(left, top, right, bottom),
cx as _,
cy as _,
window.scale_factor() as _,
)
.map(|d| d.to_gtk_edge())
// we return `WindowEdge::__Unknown` to be ignored later.
// we must return 8 or bigger, otherwise it will be the same as one of the other 7 variants of `WindowEdge` enum.
.unwrap_or(WindowEdge::__Unknown(8));
// Ignore the `__Unknown` variant so the window receives the click correctly if it is not on the edges.
match result {
match edge {
WindowEdge::__Unknown(_) => (),
_ => {
// FIXME: calling `window.begin_resize_drag` uses the default cursor, it should show a resizing cursor instead
window.begin_resize_drag(result, 1, cx as i32, cy as i32, event.time())
window.begin_resize_drag(edge, 1, cx as i32, cy as i32, event.time())
}
}
}
Expand All @@ -475,13 +458,25 @@ impl<T: 'static> EventLoop<T> {
if let Some(window) = window.window() {
if let Some((cx, cy)) = event.root_coords() {
if let Some(device) = event.device() {
let result = hit_test(&window, cx, cy);
let (left, top) = window.position();
let (w, h) = (window.width(), window.height());
let (right, bottom) = (left + w, top + h);
let edge = crate::window::hit_test(
(left, top, right, bottom),
cx as _,
cy as _,
window.scale_factor() as _,
)
.map(|d| d.to_gtk_edge())
// we return `WindowEdge::__Unknown` to be ignored later.
// we must return 8 or bigger, otherwise it will be the same as one of the other 7 variants of `WindowEdge` enum.
.unwrap_or(WindowEdge::__Unknown(8));

// Ignore the `__Unknown` variant so the window receives the click correctly if it is not on the edges.
match result {
match edge {
WindowEdge::__Unknown(_) => (),
_ => window.begin_resize_drag_for_device(
result,
edge,
&device,
0,
cx as i32,
Expand Down Expand Up @@ -1106,3 +1101,73 @@ fn is_main_thread() -> bool {
fn is_main_thread() -> bool {
std::thread::current().name() == Some("main")
}

impl CursorIcon {
fn to_str(&self) -> &str {
match self {
CursorIcon::Crosshair => "crosshair",
CursorIcon::Hand => "pointer",
CursorIcon::Arrow => "arrow",
CursorIcon::Move => "move",
CursorIcon::Text => "text",
CursorIcon::Wait => "wait",
CursorIcon::Help => "help",
CursorIcon::Progress => "progress",
CursorIcon::NotAllowed => "not-allowed",
CursorIcon::ContextMenu => "context-menu",
CursorIcon::Cell => "cell",
CursorIcon::VerticalText => "vertical-text",
CursorIcon::Alias => "alias",
CursorIcon::Copy => "copy",
CursorIcon::NoDrop => "no-drop",
CursorIcon::Grab => "grab",
CursorIcon::Grabbing => "grabbing",
CursorIcon::AllScroll => "all-scroll",
CursorIcon::ZoomIn => "zoom-in",
CursorIcon::ZoomOut => "zoom-out",
CursorIcon::EResize => "e-resize",
CursorIcon::NResize => "n-resize",
CursorIcon::NeResize => "ne-resize",
CursorIcon::NwResize => "nw-resize",
CursorIcon::SResize => "s-resize",
CursorIcon::SeResize => "se-resize",
CursorIcon::SwResize => "sw-resize",
CursorIcon::WResize => "w-resize",
CursorIcon::EwResize => "ew-resize",
CursorIcon::NsResize => "ns-resize",
CursorIcon::NeswResize => "nesw-resize",
CursorIcon::NwseResize => "nwse-resize",
CursorIcon::ColResize => "col-resize",
CursorIcon::RowResize => "row-resize",
CursorIcon::Default => "default",
}
}
}

impl ResizeDirection {
fn to_cursor_str(&self) -> &str {
match self {
ResizeDirection::East => "e-resize",
ResizeDirection::North => "n-resize",
ResizeDirection::NorthEast => "ne-resize",
ResizeDirection::NorthWest => "nw-resize",
ResizeDirection::South => "s-resize",
ResizeDirection::SouthEast => "se-resize",
ResizeDirection::SouthWest => "sw-resize",
ResizeDirection::West => "w-resize",
}
}

fn to_gtk_edge(&self) -> WindowEdge {
match self {
ResizeDirection::East => WindowEdge::East,
ResizeDirection::North => WindowEdge::North,
ResizeDirection::NorthEast => WindowEdge::NorthEast,
ResizeDirection::NorthWest => WindowEdge::NorthWest,
ResizeDirection::South => WindowEdge::South,
ResizeDirection::SouthEast => WindowEdge::SouthEast,
ResizeDirection::SouthWest => WindowEdge::SouthWest,
ResizeDirection::West => WindowEdge::West,
}
}
}
2 changes: 1 addition & 1 deletion src/platform_impl/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub(crate) use event_loop::PlatformSpecificEventLoopAttributes;
pub use event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget};
pub use icon::PlatformIcon;
pub use monitor::{MonitorHandle, VideoMode};
pub use window::{hit_test, Window, WindowId};
pub use window::{Window, WindowId};

use crate::{event::DeviceId as RootDeviceId, keyboard::Key};

Expand Down
Loading

0 comments on commit f497b5d

Please sign in to comment.