diff --git a/.gitignore b/.gitignore index 9534dc207..9df7e9f93 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /target +/dist Cargo.lock .DS_Store diff --git a/examples/borderless.rs b/examples/borderless.rs new file mode 100644 index 000000000..d52e9fb5a --- /dev/null +++ b/examples/borderless.rs @@ -0,0 +1,38 @@ +use dioxus::prelude::*; + +fn main() { + dioxus::desktop::launch_cfg(app, |cfg| { + cfg.with_window(|w| w.with_title("BorderLess Demo").with_decorations(false)) + }); +} + +fn app(cx: Scope) -> Element { + let window = dioxus::desktop::use_window(&cx); + + cx.render(rsx!( + link { href:"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css", rel:"stylesheet" } + header { + class: "text-gray-400 bg-gray-900 body-font", + onmousedown: move |_| window.drag(), + div { + class: "container mx-auto flex flex-wrap p-5 flex-col md:flex-row items-center", + a { class: "flex title-font font-medium items-center text-white mb-4 md:mb-0", + span { class: "ml-3 text-xl", "Dioxus"} + } + nav { class: "md:ml-auto flex flex-wrap items-center text-base justify-center" } + button { + class: "inline-flex items-center bg-gray-800 border-0 py-1 px-3 focus:outline-none hover:bg-gray-700 rounded text-base mt-4 md:mt-0", + onmousedown: |evt| evt.cancel_bubble(), + onclick: move |_| window.minimize(true), + "Minimize" + } + button { + class: "inline-flex items-center bg-gray-800 border-0 py-1 px-3 focus:outline-none hover:bg-gray-700 rounded text-base mt-4 md:mt-0", + onmousedown: |evt| evt.cancel_bubble(), + onclick: move |_| window.close(), + "Close" + } + } + } + )) +} diff --git a/packages/desktop/src/desktop_context.rs b/packages/desktop/src/desktop_context.rs index 48c82f5a8..9c0404477 100644 --- a/packages/desktop/src/desktop_context.rs +++ b/packages/desktop/src/desktop_context.rs @@ -1,100 +1,67 @@ -use std::cell::RefCell; +use std::rc::Rc; -use dioxus::prelude::Scope; -use dioxus_core as dioxus; -use dioxus_core::{Context, Element, LazyNodes, NodeFactory, Properties}; -use dioxus_core_macro::Props; +use dioxus_core::ScopeState; +use wry::application::event_loop::EventLoopProxy; -/* -This module provides a set of Dioxus components to easily manage windows, tabs, etc. +use crate::UserWindowEvent; -Windows can be created anywhere in the tree, making them very flexible for things like modals, etc. +type ProxyType = EventLoopProxy; -*/ -pub struct DesktopContext {} +/// Desktop-Window handle api context +/// +/// you can use this context control some window event +/// +/// you can use `cx.consume_context::` to get this context +/// +/// ```rust +/// let desktop = cx.consume_context::().unwrap(); +/// ``` +#[derive(Clone)] +pub struct DesktopContext { + proxy: ProxyType, +} impl DesktopContext { - fn add_window(&mut self) { - // + pub(crate) fn new(proxy: ProxyType) -> Self { + Self { proxy } } - fn close_window(&mut self) { - // + + /// trigger the drag-window event + /// + /// Moves the window with the left mouse button until the button is released. + /// + /// you need use it in `onmousedown` event: + /// ```rust + /// onmousedown: move |_| { desktop.drag_window(); } + /// ``` + pub fn drag(&self) { + let _ = self.proxy.send_event(UserWindowEvent::DragWindow); + } + + /// set window minimize state + pub fn minimize(&self, minimized: bool) { + let _ = self.proxy.send_event(UserWindowEvent::Minimize(minimized)); + } + + /// set window maximize state + pub fn maximize(&self, maximized: bool) { + let _ = self.proxy.send_event(UserWindowEvent::Maximize(maximized)); + } + + /// close window + pub fn close(&self) { + let _ = self.proxy.send_event(UserWindowEvent::CloseWindow); + } + + /// set window to focus + pub fn focus(&self) { + let _ = self.proxy.send_event(UserWindowEvent::FocusWindow); } } -enum WindowHandlers { - Resized(Box), - Moved(Box), - CloseRequested(Box), - Destroyed(Box), - DroppedFile(Box), - HoveredFile(Box), - HoverFileCancelled(Box), - ReceivedTimeText(Box), - Focused(Box), -} - -#[derive(Props)] -pub struct WebviewWindowProps<'a> { - onclose: &'a dyn FnMut(()), - - onopen: &'a dyn FnMut(()), - - /// focuse me - onfocused: &'a dyn FnMut(()), - - children: Element, -} - -/// A handle to a -/// -/// -/// -/// -/// -/// -/// -/// -/// -pub fn WebviewWindow(cx: Scope) -> Element { - let dtcx = cx.consume_state::>()?; - - cx.use_hook(|_| {}); - - // render the children directly - todo!() - // cx.render(LazyNodes::new(move |f: NodeFactory| { - // f.fragment_from_iter(cx.children()) - // })) -} - -pub struct WindowHandle {} - -/// Get a handle to the current window from inside a component -pub fn use_current_window(cx: Scope) -> Option { - todo!() -} - -#[test] -fn syntax_works() { - use dioxus_core as dioxus; - use dioxus_core::prelude::*; - use dioxus_core_macro::*; - use dioxus_hooks::*; - use dioxus_html as dioxus_elements; - - static App: Component = |cx| { - cx.render(rsx! { - // left window - WebviewWindow { - onclose: move |evt| {} - onopen: move |evt| {} - onfocused: move |evt| {} - - div { - - } - } - }) - }; +/// use this function can get the `DesktopContext` context. +pub fn use_window(cx: &ScopeState) -> &Rc { + cx.use_hook(|_| cx.consume_context::()) + .as_ref() + .unwrap() } diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs index 86928ef24..eb4657c52 100644 --- a/packages/desktop/src/lib.rs +++ b/packages/desktop/src/lib.rs @@ -51,10 +51,13 @@ //! Make sure to read the [Dioxus Guide](https://dioxuslabs.com/guide) if you already haven't! pub mod cfg; +pub mod desktop_context; pub mod escape; pub mod events; use cfg::DesktopConfig; +pub use desktop_context::use_window; +use desktop_context::DesktopContext; use dioxus_core::*; use std::{ collections::{HashMap, VecDeque}, @@ -283,6 +286,41 @@ pub fn launch_with_props( // match _evt { UserWindowEvent::Update => desktop.try_load_ready_webviews(), + UserWindowEvent::DragWindow => { + // this loop just run once, because dioxus-desktop is unsupport multi-window. + for webview in desktop.webviews.values() { + let window = webview.window(); + // start to drag the window. + // if the drag_window have any err. we don't do anything. + let _ = window.drag_window(); + } + } + UserWindowEvent::CloseWindow => { + // close window + *control_flow = ControlFlow::Exit; + } + UserWindowEvent::Minimize(state) => { + // this loop just run once, because dioxus-desktop is unsupport multi-window. + for webview in desktop.webviews.values() { + let window = webview.window(); + // change window minimized state. + window.set_minimized(state); + } + } + UserWindowEvent::Maximize(state) => { + // this loop just run once, because dioxus-desktop is unsupport multi-window. + for webview in desktop.webviews.values() { + let window = webview.window(); + // change window maximized state. + window.set_maximized(state); + } + } + UserWindowEvent::FocusWindow => { + for webview in desktop.webviews.values() { + let window = webview.window(); + window.set_focus(); + } + } } } Event::MainEventsCleared => {} @@ -297,6 +335,11 @@ pub fn launch_with_props( pub enum UserWindowEvent { Update, + DragWindow, + CloseWindow, + FocusWindow, + Minimize(bool), + Maximize(bool), } pub struct DesktopController { @@ -323,6 +366,7 @@ impl DesktopController { let return_sender = sender.clone(); let proxy = evt.clone(); + let desktop_context_proxy = proxy.clone(); std::thread::spawn(move || { // We create the runtime as multithreaded, so you can still "spawn" onto multiple threads let runtime = tokio::runtime::Builder::new_multi_thread() @@ -334,6 +378,10 @@ impl DesktopController { let mut dom = VirtualDom::new_with_props_and_scheduler(root, props, (sender, receiver)); + let window_context = DesktopContext::new(desktop_context_proxy); + + dom.base_scope().provide_context(window_context); + let edits = dom.rebuild(); edit_queue