mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-10 06:34:20 +00:00
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:
commit
0c0f638c47
4 changed files with 143 additions and 89 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
||||||
/target
|
/target
|
||||||
|
/dist
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
|
38
examples/borderless.rs
Normal file
38
examples/borderless.rs
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
|
@ -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 {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue