Merge pull request #180 from mrxiaozhuox/borderless-frame

Add support for desktop context, borderless frames, minimize, maximize, and other window-related goodies through the imperative `use_window` hook.
This commit is contained in:
Jonathan Kelley 2022-01-31 19:53:27 -05:00 committed by GitHub
commit 0c0f638c47
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 143 additions and 89 deletions

1
.gitignore vendored
View file

@ -1,4 +1,5 @@
/target /target
/dist
Cargo.lock Cargo.lock
.DS_Store .DS_Store

38
examples/borderless.rs Normal file
View file

@ -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"
}
}
}
))
}

View file

@ -1,100 +1,67 @@
use std::cell::RefCell; use std::rc::Rc;
use dioxus::prelude::Scope; use dioxus_core::ScopeState;
use dioxus_core as dioxus; use wry::application::event_loop::EventLoopProxy;
use dioxus_core::{Context, Element, LazyNodes, NodeFactory, Properties};
use dioxus_core_macro::Props;
/* use crate::UserWindowEvent;
This module provides a set of Dioxus components to easily manage windows, tabs, etc.
Windows can be created anywhere in the tree, making them very flexible for things like modals, etc. type ProxyType = EventLoopProxy<UserWindowEvent>;
*/ /// Desktop-Window handle api context
pub struct DesktopContext {} ///
/// you can use this context control some window event
///
/// you can use `cx.consume_context::<DesktopContext>` to get this context
///
/// ```rust
/// let desktop = cx.consume_context::<DesktopContext>().unwrap();
/// ```
#[derive(Clone)]
pub struct DesktopContext {
proxy: ProxyType,
}
impl DesktopContext { 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 { /// use this function can get the `DesktopContext` context.
Resized(Box<dyn Fn()>), pub fn use_window(cx: &ScopeState) -> &Rc<DesktopContext> {
Moved(Box<dyn Fn()>), cx.use_hook(|_| cx.consume_context::<DesktopContext>())
CloseRequested(Box<dyn Fn()>), .as_ref()
Destroyed(Box<dyn Fn()>), .unwrap()
DroppedFile(Box<dyn Fn()>),
HoveredFile(Box<dyn Fn()>),
HoverFileCancelled(Box<dyn Fn()>),
ReceivedTimeText(Box<dyn Fn()>),
Focused(Box<dyn Fn()>),
}
#[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<WebviewWindowProps>) -> Element {
let dtcx = cx.consume_state::<RefCell<DesktopContext>>()?;
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<WindowHandle> {
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 {
}
}
})
};
} }

View file

@ -51,10 +51,13 @@
//! Make sure to read the [Dioxus Guide](https://dioxuslabs.com/guide) if you already haven't! //! Make sure to read the [Dioxus Guide](https://dioxuslabs.com/guide) if you already haven't!
pub mod cfg; pub mod cfg;
pub mod desktop_context;
pub mod escape; pub mod escape;
pub mod events; pub mod events;
use cfg::DesktopConfig; use cfg::DesktopConfig;
pub use desktop_context::use_window;
use desktop_context::DesktopContext;
use dioxus_core::*; use dioxus_core::*;
use std::{ use std::{
collections::{HashMap, VecDeque}, collections::{HashMap, VecDeque},
@ -283,6 +286,41 @@ pub fn launch_with_props<P: 'static + Send>(
// //
match _evt { match _evt {
UserWindowEvent::Update => desktop.try_load_ready_webviews(), 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 => {} Event::MainEventsCleared => {}
@ -297,6 +335,11 @@ pub fn launch_with_props<P: 'static + Send>(
pub enum UserWindowEvent { pub enum UserWindowEvent {
Update, Update,
DragWindow,
CloseWindow,
FocusWindow,
Minimize(bool),
Maximize(bool),
} }
pub struct DesktopController { pub struct DesktopController {
@ -323,6 +366,7 @@ impl DesktopController {
let return_sender = sender.clone(); let return_sender = sender.clone();
let proxy = evt.clone(); let proxy = evt.clone();
let desktop_context_proxy = proxy.clone();
std::thread::spawn(move || { std::thread::spawn(move || {
// We create the runtime as multithreaded, so you can still "spawn" onto multiple threads // We create the runtime as multithreaded, so you can still "spawn" onto multiple threads
let runtime = tokio::runtime::Builder::new_multi_thread() let runtime = tokio::runtime::Builder::new_multi_thread()
@ -334,6 +378,10 @@ impl DesktopController {
let mut dom = let mut dom =
VirtualDom::new_with_props_and_scheduler(root, props, (sender, receiver)); 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(); let edits = dom.rebuild();
edit_queue edit_queue