diff --git a/src/action.rs b/src/action.rs index bfee1483..13529016 100644 --- a/src/action.rs +++ b/src/action.rs @@ -6,6 +6,7 @@ use std::{ use floem_reactive::Scope; use kurbo::{Point, Size, Vec2}; +use winit::window::ResizeDirection; use crate::{ app::{add_app_update_event, AppUpdateEvent}, @@ -39,6 +40,10 @@ pub fn drag_window() { add_update_message(UpdateMessage::DragWindow); } +pub fn drag_resize_window(direction: ResizeDirection) { + add_update_message(UpdateMessage::DragResizeWindow(direction)); +} + pub fn set_window_delta(delta: Vec2) { add_update_message(UpdateMessage::SetWindowDelta(delta)); } diff --git a/src/app_handle.rs b/src/app_handle.rs index c8f30a0b..69bca02b 100644 --- a/src/app_handle.rs +++ b/src/app_handle.rs @@ -150,7 +150,9 @@ impl ApplicationHandle { WindowEvent::ScaleFactorChanged { scale_factor, .. } => { window_handle.scale(scale_factor); } - WindowEvent::ThemeChanged(_) => {} + WindowEvent::ThemeChanged(theme) => { + window_handle.theme_changed(theme); + } WindowEvent::Occluded(_) => {} WindowEvent::MenuAction(id) => { window_handle.menu_action(id); diff --git a/src/event.rs b/src/event.rs index 97e71df1..a39b4326 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,5 +1,5 @@ use kurbo::{Point, Size}; -use winit::keyboard::KeyCode; +use winit::{keyboard::KeyCode, window::Theme}; use crate::{ keyboard::KeyEvent, @@ -31,6 +31,7 @@ pub enum EventListener { PointerWheel, FocusGained, FocusLost, + ThemeChanged, WindowClosed, WindowResized, WindowMoved, @@ -60,6 +61,7 @@ pub enum Event { WindowResized(Size), WindowMoved(Point), WindowMaximizeChanged(bool), + ThemeChanged(Theme), FocusGained, FocusLost, } @@ -77,6 +79,7 @@ impl Event { | Event::ImeDisabled | Event::ImePreedit { .. } | Event::ImeCommit(_) + | Event::ThemeChanged(_) | Event::WindowClosed | Event::WindowResized(_) | Event::WindowMoved(_) @@ -101,6 +104,7 @@ impl Event { | Event::ImeDisabled | Event::ImePreedit { .. } | Event::ImeCommit(_) + | Event::ThemeChanged(_) | Event::WindowClosed | Event::WindowResized(_) | Event::WindowMoved(_) @@ -137,6 +141,7 @@ impl Event { | Event::KeyDown(_) | Event::KeyUp(_) => false, Event::PointerMove(_) + | Event::ThemeChanged(_) | Event::WindowClosed | Event::WindowResized(_) | Event::WindowMoved(_) @@ -160,6 +165,7 @@ impl Event { | Event::ImeEnabled | Event::ImeDisabled | Event::ImePreedit { .. } + | Event::ThemeChanged(_) | Event::ImeCommit(_) | Event::WindowClosed | Event::WindowResized(_) @@ -191,6 +197,7 @@ impl Event { | Event::ImeEnabled | Event::ImeDisabled | Event::ImePreedit { .. } + | Event::ThemeChanged(_) | Event::ImeCommit(_) | Event::WindowClosed | Event::WindowResized(_) @@ -220,6 +227,7 @@ impl Event { | Event::ImeEnabled | Event::ImeDisabled | Event::ImePreedit { .. } + | Event::ThemeChanged(_) | Event::ImeCommit(_) | Event::WindowClosed | Event::WindowResized(_) @@ -251,6 +259,7 @@ impl Event { Event::WindowLostFocus => Some(EventListener::WindowLostFocus), Event::FocusLost => Some(EventListener::FocusLost), Event::FocusGained => Some(EventListener::FocusGained), + Event::ThemeChanged(_) => Some(EventListener::ThemeChanged), } } } diff --git a/src/style.rs b/src/style.rs index e80d01b6..431c97c5 100644 --- a/src/style.rs +++ b/src/style.rs @@ -60,6 +60,14 @@ pub enum CursorStyle { Text, ColResize, RowResize, + WResize, + EResize, + SResize, + NResize, + NwResize, + NeResize, + SwResize, + SeResize, } #[derive(Debug, Clone, Copy)] diff --git a/src/update.rs b/src/update.rs index a414b976..4d024e0e 100644 --- a/src/update.rs +++ b/src/update.rs @@ -1,6 +1,7 @@ use std::{any::Any, cell::RefCell, collections::HashMap}; use kurbo::{Point, Size, Vec2}; +use winit::window::ResizeDirection; use crate::{ animate::{AnimUpdateMsg, Animation}, @@ -89,6 +90,7 @@ pub(crate) enum UpdateMessage { SetWindowMaximized(bool), MinimizeWindow, DragWindow, + DragResizeWindow(ResizeDirection), SetWindowDelta(Vec2), Animation { id: Id, diff --git a/src/views/drag_resize_window_area.rs b/src/views/drag_resize_window_area.rs new file mode 100644 index 00000000..64773643 --- /dev/null +++ b/src/views/drag_resize_window_area.rs @@ -0,0 +1,105 @@ +use kurbo::Rect; +use winit::window::ResizeDirection; + +use crate::{ + action::drag_resize_window, + event::{Event, EventListener}, + id::Id, + style::CursorStyle, + view::View, +}; + +use super::Decorators; + +pub struct DragResizeWindowArea<V: View> { + id: Id, + child: V, +} + +pub fn drag_resize_window_area<V: View>( + direction: ResizeDirection, + child: V, +) -> DragResizeWindowArea<V> { + let id = Id::next(); + DragResizeWindowArea { id, child } + .on_event(EventListener::PointerDown, move |_| { + drag_resize_window(direction); + true + }) + .style(move |s| { + let cursor = match direction { + ResizeDirection::East => CursorStyle::EResize, + ResizeDirection::North => CursorStyle::NResize, + ResizeDirection::NorthEast => CursorStyle::NeResize, + ResizeDirection::NorthWest => CursorStyle::NwResize, + ResizeDirection::South => CursorStyle::SResize, + ResizeDirection::SouthEast => CursorStyle::SeResize, + ResizeDirection::SouthWest => CursorStyle::SwResize, + ResizeDirection::West => CursorStyle::WResize, + }; + s.cursor(cursor) + }) +} + +impl<V: View> View for DragResizeWindowArea<V> { + fn id(&self) -> Id { + self.id + } + + fn child(&self, id: Id) -> Option<&dyn View> { + if self.child.id() == id { + Some(&self.child) + } else { + None + } + } + + fn child_mut(&mut self, id: Id) -> Option<&mut dyn View> { + if self.child.id() == id { + Some(&mut self.child) + } else { + None + } + } + + fn children(&self) -> Vec<&dyn View> { + vec![&self.child] + } + + fn children_mut(&mut self) -> Vec<&mut dyn View> { + vec![&mut self.child] + } + + fn update( + &mut self, + _cx: &mut crate::context::UpdateCx, + _state: Box<dyn std::any::Any>, + ) -> crate::view::ChangeFlags { + crate::view::ChangeFlags::empty() + } + + fn layout(&mut self, cx: &mut crate::context::LayoutCx) -> taffy::prelude::Node { + cx.layout_node(self.id, true, |cx| vec![self.child.layout_main(cx)]) + } + + fn compute_layout(&mut self, cx: &mut crate::context::LayoutCx) -> Option<Rect> { + Some(self.child.compute_layout_main(cx)) + } + + fn event( + &mut self, + cx: &mut crate::context::EventCx, + id_path: Option<&[Id]>, + event: Event, + ) -> bool { + if cx.should_send(self.child.id(), &event) { + self.child.event_main(cx, id_path, event) + } else { + false + } + } + + fn paint(&mut self, cx: &mut crate::context::PaintCx) { + self.child.paint_main(cx); + } +} diff --git a/src/views/mod.rs b/src/views/mod.rs index 5f940044..7926baf3 100644 --- a/src/views/mod.rs +++ b/src/views/mod.rs @@ -50,3 +50,6 @@ pub use empty::*; mod drag_window_area; pub use drag_window_area::*; + +mod drag_resize_window_area; +pub use drag_resize_window_area::*; diff --git a/src/window.rs b/src/window.rs index ed611778..05a1c838 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1,4 +1,6 @@ use kurbo::{Point, Size}; +pub use winit::window::ResizeDirection; +pub use winit::window::Theme; pub use winit::window::WindowId; use crate::{ diff --git a/src/window_handle.rs b/src/window_handle.rs index 28e2dd55..34c6702b 100644 --- a/src/window_handle.rs +++ b/src/window_handle.rs @@ -10,7 +10,7 @@ use winit::{ dpi::{LogicalPosition, LogicalSize}, event::{ElementState, Ime, MouseButton, MouseScrollDelta}, keyboard::{Key, ModifiersState}, - window::CursorIcon, + window::{CursorIcon, Theme}, }; #[cfg(target_os = "linux")] @@ -49,6 +49,7 @@ pub(crate) struct WindowHandle { app_state: AppState, paint_state: PaintState, size: RwSignal<Size>, + theme: RwSignal<Option<Theme>>, is_maximized: bool, pub(crate) scale: f64, pub(crate) modifiers: ModifiersState, @@ -70,6 +71,7 @@ impl WindowHandle { let size: LogicalSize<f64> = window.inner_size().to_logical(scale); let size = Size::new(size.width, size.height); let size = scope.create_rw_signal(Size::new(size.width, size.height)); + let theme = scope.create_rw_signal(window.theme()); let is_maximized = window.is_maximized(); #[cfg(target_os = "linux")] @@ -104,6 +106,7 @@ impl WindowHandle { app_state: AppState::new(), paint_state, size, + theme, is_maximized, scale, modifiers: ModifiersState::default(), @@ -269,6 +272,10 @@ impl WindowHandle { self.request_paint(); } + pub(crate) fn theme_changed(&mut self, theme: Theme) { + self.theme.set(Some(theme)); + } + pub(crate) fn size(&mut self, size: Size) { self.size.set(size); self.app_state.update_screen_size_bp(size); @@ -599,6 +606,11 @@ impl WindowHandle { let _ = window.drag_window(); } } + UpdateMessage::DragResizeWindow(direction) => { + if let Some(window) = self.window.as_ref() { + let _ = window.drag_resize_window(direction); + } + } UpdateMessage::ToggleWindowMaximized => { if let Some(window) = self.window.as_ref() { window.set_maximized(!window.is_maximized()); @@ -880,6 +892,14 @@ impl WindowHandle { Some(CursorStyle::Text) => CursorIcon::Text, Some(CursorStyle::ColResize) => CursorIcon::ColResize, Some(CursorStyle::RowResize) => CursorIcon::RowResize, + Some(CursorStyle::WResize) => CursorIcon::WResize, + Some(CursorStyle::EResize) => CursorIcon::EResize, + Some(CursorStyle::NwResize) => CursorIcon::NwResize, + Some(CursorStyle::NeResize) => CursorIcon::NeResize, + Some(CursorStyle::SwResize) => CursorIcon::SwResize, + Some(CursorStyle::SeResize) => CursorIcon::SeResize, + Some(CursorStyle::SResize) => CursorIcon::SResize, + Some(CursorStyle::NResize) => CursorIcon::NResize, None => CursorIcon::Default, }; if cursor != self.app_state.last_cursor {