mirror of
https://github.com/danbulant/cushy
synced 2026-06-19 14:31:04 +00:00
Multi-window support
Closes #91 There's some details to still figure out, which are in new issues: - #109: When opening a window, no handle is returned that gives access to the window from the opener. Technically this can all be wired up manually, with exception of requeesting the window close. - #107: How can a window close itself? Once we have a handle type, we still need a mechanism to allow a button on a window request that the window closes gracefully. The examples that currently close the window call exit instad.
This commit is contained in:
parent
4c9e2d5989
commit
f1a2a711ff
12 changed files with 431 additions and 102 deletions
22
CHANGELOG.md
22
CHANGELOG.md
|
|
@ -11,6 +11,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
- Many bounds required `UnwindSafe` due to a misunderstanding on how to handle
|
||||
this trait in `appit`. All requirements for `UnwindSafe` have been removed.
|
||||
- `Gooey` no longer implements default. To gain access to a `Gooey` instance,
|
||||
create a `PendingApp` or get a reference to the running `App`.
|
||||
- `Window::new` no longer accepts a `Gooey` parameter. The window now adopts the
|
||||
`Gooey` from the application it is opened within.
|
||||
- `MakeWidget::into_window()` no longer takes any parameters.
|
||||
|
||||
### Changed
|
||||
|
||||
|
|
@ -30,6 +35,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
validations. This was already available on `when` conditioned validations.
|
||||
- `Dynamic::[try_]compare_swap` allows swapping the contents of a dynamic after
|
||||
verifying the current contents.
|
||||
- [#91][91]: Multi-window support has been implemented. `PendingApp` allows
|
||||
opening one or more windows before starting the program. `App` is a handle to
|
||||
the running application that can be used to open additional windows at
|
||||
runtime.
|
||||
|
||||
`Open` is a new trait that allows various types to open as a window given a
|
||||
reference to an application. This trait is implemented for all types that
|
||||
implemented `Run`, which means any type that was previously able to be run as
|
||||
a standalone executable can now be opened as a window within a multi-window
|
||||
application.
|
||||
|
||||
The `multi-window` example demonstates using this feature to open multiple
|
||||
windows before starting Gooey as well as dynamically opening windows at
|
||||
runtime.
|
||||
- `Window::on_close` sets a callback to be invoked when the window has closed.
|
||||
|
||||
[91]: https://github.com/khonsulabs/gooey/issues/91
|
||||
|
||||
## v0.1.3 (2023-12-19)
|
||||
|
||||
|
|
|
|||
164
Cargo.lock
generated
164
Cargo.lock
generated
|
|
@ -2,6 +2,22 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "ab_glyph"
|
||||
version = "0.2.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80179d7dd5d7e8c285d67c4a1e652972a92de7475beddfb92028c76463b13225"
|
||||
dependencies = [
|
||||
"ab_glyph_rasterizer",
|
||||
"owned_ttf_parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ab_glyph_rasterizer"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046"
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.21.0"
|
||||
|
|
@ -53,9 +69,9 @@ checksum = "b072fc284b73a3e4154e2decdbaad711daca0e8fedfceb0d7b1cbe2dffb00e2b"
|
|||
|
||||
[[package]]
|
||||
name = "android-activity"
|
||||
version = "0.5.0"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "052ad56e336bcc615a214bffbeca6c181ee9550acec193f0327e0b103b033a4d"
|
||||
checksum = "39b801912a977c3fd52d80511fe1c0c8480c6f957f21ae2ce1b92ffe970cf4b9"
|
||||
dependencies = [
|
||||
"android-properties",
|
||||
"bitflags 2.4.1",
|
||||
|
|
@ -90,7 +106,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "appit"
|
||||
version = "0.1.1"
|
||||
source = "git+https://github.com/khonsulabs/appit#36a413865b6ac93e04b8a32023397714a165304d"
|
||||
source = "git+https://github.com/khonsulabs/appit#1e162ed8df4470522d6dbfb1567b54df74ba911f"
|
||||
dependencies = [
|
||||
"winit",
|
||||
]
|
||||
|
|
@ -120,9 +136,15 @@ dependencies = [
|
|||
"parking_lot",
|
||||
"thiserror",
|
||||
"winapi",
|
||||
"x11rb",
|
||||
"x11rb 0.12.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.4"
|
||||
|
|
@ -805,6 +827,16 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gethostname"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.11"
|
||||
|
|
@ -1147,7 +1179,7 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
|
|||
[[package]]
|
||||
name = "kludgine"
|
||||
version = "0.6.1"
|
||||
source = "git+https://github.com/khonsulabs/kludgine#bb1a2cc237b353ebd91bef62109b9bb8e3cf32e7"
|
||||
source = "git+https://github.com/khonsulabs/kludgine#76a378ca124b2f965049e65aada1b0e839b37aff"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"alot",
|
||||
|
|
@ -1452,8 +1484,7 @@ dependencies = [
|
|||
"log",
|
||||
"ndk-sys",
|
||||
"num_enum",
|
||||
"raw-window-handle 0.5.2",
|
||||
"raw-window-handle 0.6.0",
|
||||
"raw-window-handle",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
|
|
@ -1637,6 +1668,15 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||
|
||||
[[package]]
|
||||
name = "owned_ttf_parser"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4586edfe4c648c71797a74c84bacb32b52b212eff5dfe2bb9f2c599844023e7"
|
||||
dependencies = [
|
||||
"ttf-parser 0.20.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "palette"
|
||||
version = "0.7.3"
|
||||
|
|
@ -1827,9 +1867,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.70"
|
||||
version = "1.0.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||
checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
|
@ -1961,12 +2001,6 @@ version = "0.5.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9"
|
||||
|
||||
[[package]]
|
||||
name = "raw-window-handle"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42a9830a0e1b9fb145ebb365b8bc4ccd75f290f98c0247deafbbe2c75cefb544"
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.8.0"
|
||||
|
|
@ -2127,6 +2161,19 @@ version = "1.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "sctk-adwaita"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82b2eaf3a5b264a521b988b2e73042e742df700c4f962cde845d1541adb46550"
|
||||
dependencies = [
|
||||
"ab_glyph",
|
||||
"log",
|
||||
"memmap2 0.9.3",
|
||||
"smithay-client-toolkit",
|
||||
"tiny-skia",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "self_cell"
|
||||
version = "1.0.3"
|
||||
|
|
@ -2269,6 +2316,12 @@ version = "1.0.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0"
|
||||
|
||||
[[package]]
|
||||
name = "strict-num"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
|
||||
|
||||
[[package]]
|
||||
name = "svg_fmt"
|
||||
version = "0.4.1"
|
||||
|
|
@ -2287,9 +2340,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.41"
|
||||
version = "2.0.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269"
|
||||
checksum = "5b7d0a2c048d661a1a59fcd7355baa232f7ed34e0ee4df2eef3c1c1c0d3852d8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -2355,6 +2408,31 @@ dependencies = [
|
|||
"weezl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-skia"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6a067b809476893fce6a254cf285850ff69c847e6cfbade6a20b655b6c7e80d"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
"bytemuck",
|
||||
"cfg-if",
|
||||
"log",
|
||||
"tiny-skia-path",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-skia-path"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5de35e8a90052baaaf61f171680ac2f8e925a1e43ea9d2e3a00514772250e541"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"bytemuck",
|
||||
"strict-num",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.6.0"
|
||||
|
|
@ -2763,7 +2841,7 @@ dependencies = [
|
|||
"naga",
|
||||
"parking_lot",
|
||||
"profiling",
|
||||
"raw-window-handle 0.5.2",
|
||||
"raw-window-handle",
|
||||
"smallvec",
|
||||
"static_assertions",
|
||||
"wasm-bindgen",
|
||||
|
|
@ -2788,7 +2866,7 @@ dependencies = [
|
|||
"naga",
|
||||
"parking_lot",
|
||||
"profiling",
|
||||
"raw-window-handle 0.5.2",
|
||||
"raw-window-handle",
|
||||
"rustc-hash",
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
|
|
@ -2829,7 +2907,7 @@ dependencies = [
|
|||
"parking_lot",
|
||||
"profiling",
|
||||
"range-alloc",
|
||||
"raw-window-handle 0.5.2",
|
||||
"raw-window-handle",
|
||||
"renderdoc-sys",
|
||||
"rustc-hash",
|
||||
"smallvec",
|
||||
|
|
@ -3116,9 +3194,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
|||
|
||||
[[package]]
|
||||
name = "winit"
|
||||
version = "0.29.4"
|
||||
version = "0.29.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d25d662bb83b511acd839534bb2d88521b0bbc81440969cb077d23c4db9e62c7"
|
||||
checksum = "2cc935117ef48caed8822a893efef723e07ad868f668dfc4d244aea8873b07f9"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"android-activity",
|
||||
|
|
@ -3141,9 +3219,10 @@ dependencies = [
|
|||
"once_cell",
|
||||
"orbclient",
|
||||
"percent-encoding",
|
||||
"raw-window-handle 0.5.2",
|
||||
"raw-window-handle",
|
||||
"redox_syscall 0.3.5",
|
||||
"rustix",
|
||||
"sctk-adwaita",
|
||||
"smithay-client-toolkit",
|
||||
"smol_str",
|
||||
"unicode-segmentation",
|
||||
|
|
@ -3157,7 +3236,7 @@ dependencies = [
|
|||
"web-time",
|
||||
"windows-sys 0.48.0",
|
||||
"x11-dl",
|
||||
"x11rb",
|
||||
"x11rb 0.13.0",
|
||||
"xkbcommon-dl",
|
||||
]
|
||||
|
||||
|
|
@ -3187,15 +3266,26 @@ version = "0.12.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1641b26d4dec61337c35a1b1aaf9e3cba8f46f0b43636c609ab0291a648040a"
|
||||
dependencies = [
|
||||
"as-raw-xcb-connection",
|
||||
"gethostname",
|
||||
"libc",
|
||||
"libloading 0.7.4",
|
||||
"gethostname 0.3.0",
|
||||
"nix",
|
||||
"once_cell",
|
||||
"winapi",
|
||||
"winapi-wsapoll",
|
||||
"x11rb-protocol",
|
||||
"x11rb-protocol 0.12.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x11rb"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8f25ead8c7e4cba123243a6367da5d3990e0d3affa708ea19dce96356bd9f1a"
|
||||
dependencies = [
|
||||
"as-raw-xcb-connection",
|
||||
"gethostname 0.4.3",
|
||||
"libc",
|
||||
"libloading 0.8.1",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"x11rb-protocol 0.13.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3207,6 +3297,12 @@ dependencies = [
|
|||
"nix",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x11rb-protocol"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e63e71c4b8bd9ffec2c963173a4dc4cbde9ee96961d4fcb4429db9929b606c34"
|
||||
|
||||
[[package]]
|
||||
name = "xcursor"
|
||||
version = "0.3.5"
|
||||
|
|
@ -3267,18 +3363,18 @@ checksum = "dd15f8e0dbb966fd9245e7498c7e9e5055d9e5c8b676b95bd67091cd11a1e697"
|
|||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.31"
|
||||
version = "0.7.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c4061bedbb353041c12f413700357bec76df2c7e2ca8e4df8bac24c6bf68e3d"
|
||||
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.31"
|
||||
version = "0.7.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3c129550b3e6de3fd0ba67ba5c81818f9805e58b8d7fee80a3a59d2c9fc601a"
|
||||
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
|
|||
|
|
@ -46,6 +46,11 @@ unicode-segmentation = "1.10.1"
|
|||
# alot = { git = "https://github.com/khonsulabs/alot" }
|
||||
# kempt = { path = "../objectmap" }
|
||||
|
||||
# [patch."https://github.com/khonsulabs/kludgine"]
|
||||
# kludgine = { path = "../kludgine" }
|
||||
# [patch."https://github.com/khonsulabs/appit"]
|
||||
# appit = { path = "../appit" }
|
||||
|
||||
[profile.dev.package."*"]
|
||||
opt-level = 2
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use gooey::value::Dynamic;
|
|||
use gooey::widget::{MakeWidget, WidgetInstance};
|
||||
use gooey::widgets::container::ContainerShadow;
|
||||
use gooey::window::ThemeMode;
|
||||
use gooey::{Gooey, Run};
|
||||
use gooey::Run;
|
||||
use kludgine::figures::units::Lp;
|
||||
use kludgine::figures::Point;
|
||||
|
||||
|
|
@ -10,7 +10,7 @@ fn main() -> gooey::Result {
|
|||
let theme_mode = Dynamic::default();
|
||||
set_of_containers(3, theme_mode.clone())
|
||||
.centered()
|
||||
.into_window(Gooey::default())
|
||||
.into_window()
|
||||
.themed_mode(theme_mode)
|
||||
.run()
|
||||
}
|
||||
|
|
|
|||
57
examples/multi-window.rs
Normal file
57
examples/multi-window.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
use gooey::value::{Dynamic, MapEach};
|
||||
use gooey::widget::MakeWidget;
|
||||
use gooey::{Application, Open, PendingApp, Run};
|
||||
|
||||
fn main() -> gooey::Result {
|
||||
let app = PendingApp::default();
|
||||
|
||||
let open_windows = Dynamic::new(0_usize);
|
||||
let counter = Dynamic::new(0_usize);
|
||||
|
||||
(&open_windows, &counter)
|
||||
.map_each(|(open, counter)| {
|
||||
format!(
|
||||
"There are {open} other window(s) open. {counter} total windows have been opened"
|
||||
)
|
||||
})
|
||||
.and(open_window_button(&app, &open_windows, &counter))
|
||||
.into_rows()
|
||||
.centered()
|
||||
.open(&app)?;
|
||||
|
||||
app.run()
|
||||
}
|
||||
|
||||
fn open_window_button(
|
||||
app: &impl Application,
|
||||
open_windows: &Dynamic<usize>,
|
||||
counter: &Dynamic<usize>,
|
||||
) -> impl MakeWidget {
|
||||
let app = app.as_app();
|
||||
let open_windows = open_windows.clone();
|
||||
let counter = counter.clone();
|
||||
"Open Another Window".into_button().on_click(move |()| {
|
||||
open_another_window(&app, &open_windows, &counter);
|
||||
})
|
||||
}
|
||||
|
||||
fn open_another_window(
|
||||
app: &impl Application,
|
||||
open_windows: &Dynamic<usize>,
|
||||
counter: &Dynamic<usize>,
|
||||
) {
|
||||
let my_number = counter.map_mut(|count| {
|
||||
*count += 1;
|
||||
*count
|
||||
});
|
||||
let open_windows = open_windows.clone();
|
||||
open_windows.map_mut(|open_windows| *open_windows += 1);
|
||||
format!("This is window {my_number}")
|
||||
.and(open_window_button(app, &open_windows, counter))
|
||||
.into_rows()
|
||||
.centered()
|
||||
.into_window()
|
||||
.on_close(move || open_windows.map_mut(|open_windows| *open_windows -= 1))
|
||||
.open(app)
|
||||
.expect("error opening another window");
|
||||
}
|
||||
|
|
@ -13,13 +13,13 @@ use gooey::widgets::input::InputValue;
|
|||
use gooey::widgets::slider::Slidable;
|
||||
use gooey::widgets::Space;
|
||||
use gooey::window::ThemeMode;
|
||||
use gooey::{Gooey, Run};
|
||||
use gooey::{Open, PendingApp};
|
||||
use kludgine::figures::units::Lp;
|
||||
use kludgine::Color;
|
||||
use palette::OklabHue;
|
||||
|
||||
fn main() -> gooey::Result {
|
||||
let gooey = Gooey::default();
|
||||
let app = PendingApp::default();
|
||||
|
||||
let (theme_mode, theme_switcher) = dark_mode_picker();
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ fn main() -> gooey::Result {
|
|||
.and(editors.neutral.1)
|
||||
.and(editors.neutral_variant.1)
|
||||
.and("Copy to Clipboard".into_button().on_click({
|
||||
let gooey = gooey.clone();
|
||||
let gooey = app.gooey().clone();
|
||||
move |()| {
|
||||
if let Some(mut clipboard) = gooey.clipboard_guard() {
|
||||
let builder = color_scheme_builder.get();
|
||||
|
|
@ -115,9 +115,9 @@ fn main() -> gooey::Result {
|
|||
.themed(theme)
|
||||
.pad()
|
||||
.expand()
|
||||
.into_window(gooey)
|
||||
.into_window()
|
||||
.themed_mode(theme_mode)
|
||||
.run()
|
||||
.run_in(app)
|
||||
}
|
||||
|
||||
struct Scheme<Primary, Other = Primary> {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ fn main() -> gooey::Result {
|
|||
let occluded = Dynamic::new(false);
|
||||
let inner_size = Dynamic::new(Size::default());
|
||||
|
||||
let widgets = focused.map_each(|v| format!("focused: {:?}", v))
|
||||
let widgets = focused
|
||||
.map_each(|v| format!("focused: {:?}", v))
|
||||
.and(occluded.map_each(|v| format!("occluded: {:?}", v)))
|
||||
.and(inner_size.map_each(|v| format!("inner_size: {:?}", v)))
|
||||
.into_rows()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# gooey-macros
|
||||
|
||||
This crate contains procedural macros that [`Gooey`][gooey] exposes.
|
||||
This crate contains procedural macros that [Gooey][gooey] exposes.
|
||||
|
||||
[gooey]: https://github.com/khonsulabs/gooey
|
||||
|
|
|
|||
116
src/app.rs
116
src/app.rs
|
|
@ -1,24 +1,55 @@
|
|||
use std::sync::{Arc, Mutex, MutexGuard};
|
||||
|
||||
use arboard::Clipboard;
|
||||
use kludgine::app::{AppEvent, AsApplication};
|
||||
|
||||
use crate::utils::IgnorePoison;
|
||||
use crate::window::sealed::WindowCommand;
|
||||
|
||||
/// A GUI application.
|
||||
/// A Gooey application that has not started running yet.
|
||||
pub struct PendingApp {
|
||||
app: kludgine::app::PendingApp<WindowCommand>,
|
||||
gooey: Gooey,
|
||||
}
|
||||
|
||||
impl PendingApp {
|
||||
/// The shared resources this application utilizes.
|
||||
pub const fn gooey(&self) -> &Gooey {
|
||||
&self.gooey
|
||||
}
|
||||
}
|
||||
|
||||
impl Run for PendingApp {
|
||||
fn run(self) -> crate::Result {
|
||||
self.app.run()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for PendingApp {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
app: kludgine::app::PendingApp::default(),
|
||||
gooey: Gooey {
|
||||
clipboard: Clipboard::new()
|
||||
.ok()
|
||||
.map(|clipboard| Arc::new(Mutex::new(clipboard))),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsApplication<AppEvent<WindowCommand>> for PendingApp {
|
||||
fn as_application(&self) -> &dyn kludgine::app::Application<AppEvent<WindowCommand>> {
|
||||
self.app.as_application()
|
||||
}
|
||||
}
|
||||
|
||||
/// Shared resources for a GUI application.
|
||||
#[derive(Clone)]
|
||||
pub struct Gooey {
|
||||
pub(crate) clipboard: Option<Arc<Mutex<Clipboard>>>,
|
||||
}
|
||||
|
||||
impl Default for Gooey {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
clipboard: Clipboard::new()
|
||||
.ok()
|
||||
.map(|clipboard| Arc::new(Mutex::new(clipboard))),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Gooey {
|
||||
/// Returns a locked mutex guard to the OS's clipboard, if one was able to be
|
||||
/// initialized when the window opened.
|
||||
|
|
@ -29,3 +60,68 @@ impl Gooey {
|
|||
.map(|mutex| mutex.lock().ignore_poison())
|
||||
}
|
||||
}
|
||||
|
||||
/// A type that is a Gooey application.
|
||||
pub trait Application: AsApplication<AppEvent<WindowCommand>> {
|
||||
/// Returns the shared resources for the application.
|
||||
fn gooey(&self) -> &Gooey;
|
||||
/// Returns this type as an [`App`] handle.
|
||||
fn as_app(&self) -> App;
|
||||
}
|
||||
|
||||
impl Application for PendingApp {
|
||||
fn gooey(&self) -> &Gooey {
|
||||
&self.gooey
|
||||
}
|
||||
|
||||
fn as_app(&self) -> App {
|
||||
App {
|
||||
app: self.app.as_app(),
|
||||
gooey: self.gooey.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A handle to a Gooey application.
|
||||
#[derive(Clone)]
|
||||
pub struct App {
|
||||
app: kludgine::app::App<WindowCommand>,
|
||||
gooey: Gooey,
|
||||
}
|
||||
|
||||
impl Application for App {
|
||||
fn gooey(&self) -> &Gooey {
|
||||
&self.gooey
|
||||
}
|
||||
|
||||
fn as_app(&self) -> App {
|
||||
self.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsApplication<AppEvent<WindowCommand>> for App {
|
||||
fn as_application(&self) -> &dyn kludgine::app::Application<AppEvent<WindowCommand>> {
|
||||
self.app.as_application()
|
||||
}
|
||||
}
|
||||
|
||||
/// A type that can be run as an application.
|
||||
pub trait Run: Sized {
|
||||
/// Runs the provided type, returning `Ok(())` upon successful execution and
|
||||
/// program exit. Note that this function may not ever return on some
|
||||
/// platforms.
|
||||
fn run(self) -> crate::Result;
|
||||
}
|
||||
|
||||
/// A type that can be opened as a window in an application.
|
||||
pub trait Open: Sized {
|
||||
/// Opens the provided type as a window inside of `app`.
|
||||
fn open<App>(self, app: &App) -> crate::Result
|
||||
where
|
||||
App: Application;
|
||||
|
||||
/// Runs the provided type inside of the pending `app`, returning `Ok(())`
|
||||
/// upon successful execution and program exit. Note that this function may
|
||||
/// not ever return on some platforms.
|
||||
fn run_in(self, app: PendingApp) -> crate::Result;
|
||||
}
|
||||
|
|
|
|||
10
src/lib.rs
10
src/lib.rs
|
|
@ -23,7 +23,7 @@ pub mod widgets;
|
|||
pub mod window;
|
||||
use std::ops::Sub;
|
||||
|
||||
pub use app::Gooey;
|
||||
pub use app::{App, Application, Gooey, Open, PendingApp, Run};
|
||||
pub use kludgine;
|
||||
use kludgine::app::winit::error::EventLoopError;
|
||||
use kludgine::figures::units::UPx;
|
||||
|
|
@ -117,14 +117,6 @@ impl Sub<UPx> for ConstraintLimit {
|
|||
/// this crate.
|
||||
pub type Result<T = (), E = EventLoopError> = std::result::Result<T, E>;
|
||||
|
||||
/// A type that can be run as an application.
|
||||
pub trait Run: Sized {
|
||||
/// Runs the provided type, returning `Ok(())` upon successful execution and
|
||||
/// program exit. Note that this function may not ever return on some
|
||||
/// platforms.
|
||||
fn run(self) -> crate::Result;
|
||||
}
|
||||
|
||||
/// Counts the number of expressions passed to it.
|
||||
///
|
||||
/// This is used inside of Gooey macros to preallocate collections.
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use kludgine::figures::units::{Px, UPx};
|
|||
use kludgine::figures::{IntoSigned, IntoUnsigned, Point, Rect, Size};
|
||||
use kludgine::Color;
|
||||
|
||||
use crate::app::Gooey;
|
||||
use crate::app::{Application, Open, PendingApp, Run};
|
||||
use crate::context::sealed::WindowHandle;
|
||||
use crate::context::{AsEventContext, EventContext, GraphicsContext, LayoutContext, WidgetContext};
|
||||
use crate::styles::components::{
|
||||
|
|
@ -44,7 +44,7 @@ use crate::widgets::{
|
|||
Style, Themed, ThemedMode, Validated, Wrap,
|
||||
};
|
||||
use crate::window::{RunningWindow, ThemeMode, Window, WindowBehavior};
|
||||
use crate::{ConstraintLimit, Run};
|
||||
use crate::ConstraintLimit;
|
||||
|
||||
/// A type that makes up a graphical user interface.
|
||||
///
|
||||
|
|
@ -459,7 +459,24 @@ where
|
|||
T: MakeWidget,
|
||||
{
|
||||
fn run(self) -> crate::Result {
|
||||
self.make_widget().run()
|
||||
Window::<WidgetInstance>::new(self.make_widget()).run()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Open for T
|
||||
where
|
||||
T: MakeWidget,
|
||||
{
|
||||
fn open<App>(self, app: &App) -> crate::Result
|
||||
where
|
||||
App: Application,
|
||||
{
|
||||
Window::<WidgetInstance>::new(self.make_widget()).open(app)
|
||||
}
|
||||
|
||||
fn run_in(self, app: PendingApp) -> crate::Result {
|
||||
Window::<WidgetInstance>::new(self.make_widget()).open(&app)?;
|
||||
app.run()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -900,8 +917,8 @@ pub trait MakeWidget: Sized {
|
|||
fn make_widget(self) -> WidgetInstance;
|
||||
|
||||
/// Returns a new window containing `self` as the root widget.
|
||||
fn into_window(self, gooey: Gooey) -> Window<WidgetInstance> {
|
||||
Window::new(self.make_widget(), gooey.clone())
|
||||
fn into_window(self) -> Window<WidgetInstance> {
|
||||
Window::new(self.make_widget())
|
||||
}
|
||||
|
||||
/// Associates `styles` with this widget.
|
||||
|
|
@ -1512,11 +1529,6 @@ impl WidgetInstance {
|
|||
WidgetGuard(self.data.widget.lock().ignore_poison())
|
||||
}
|
||||
|
||||
/// Runs this widget instance as an application.
|
||||
pub fn run(self) -> crate::Result {
|
||||
Window::<WidgetInstance>::new(self, Gooey::default()).run()
|
||||
}
|
||||
|
||||
/// Returns the id of the widget that should receive focus after this
|
||||
/// widget.
|
||||
///
|
||||
|
|
|
|||
108
src/window.rs
108
src/window.rs
|
|
@ -26,7 +26,7 @@ use kludgine::Kludgine;
|
|||
use tracing::Level;
|
||||
|
||||
use crate::animation::{LinearInterpolate, PercentBetween, ZeroToOne};
|
||||
use crate::app::Gooey;
|
||||
use crate::app::{Application, Gooey, Open, PendingApp, Run};
|
||||
use crate::context::{
|
||||
AsEventContext, EventContext, Exclusive, GraphicsContext, InvalidationStatus, LayoutContext,
|
||||
WidgetContext,
|
||||
|
|
@ -37,10 +37,11 @@ use crate::tree::Tree;
|
|||
use crate::utils::ModifiersExt;
|
||||
use crate::value::{Dynamic, DynamicReader, Generation, IntoDynamic, IntoValue, Value};
|
||||
use crate::widget::{
|
||||
EventHandling, MountedWidget, RootBehavior, Widget, WidgetId, WidgetInstance, HANDLED, IGNORED,
|
||||
EventHandling, MountedWidget, OnceCallback, RootBehavior, Widget, WidgetId, WidgetInstance,
|
||||
HANDLED, IGNORED,
|
||||
};
|
||||
use crate::window::sealed::WindowCommand;
|
||||
use crate::{initialize_tracing, ConstraintLimit, Run};
|
||||
use crate::{initialize_tracing, ConstraintLimit};
|
||||
|
||||
/// A currently running Gooey window.
|
||||
pub struct RunningWindow<'window> {
|
||||
|
|
@ -125,7 +126,6 @@ where
|
|||
Behavior: WindowBehavior,
|
||||
{
|
||||
context: Behavior::Context,
|
||||
gooey: Gooey,
|
||||
/// The attributes of this window.
|
||||
pub attributes: WindowAttributes,
|
||||
/// The colors to use to theme the user interface.
|
||||
|
|
@ -152,6 +152,7 @@ where
|
|||
/// during drawing operations.
|
||||
pub font_data_to_load: Vec<Vec<u8>>,
|
||||
|
||||
on_closed: Option<OnceCallback>,
|
||||
inner_size: Option<Dynamic<Size<UPx>>>,
|
||||
occluded: Option<Dynamic<bool>>,
|
||||
focused: Option<Dynamic<bool>>,
|
||||
|
|
@ -164,8 +165,7 @@ where
|
|||
Behavior::Context: Default,
|
||||
{
|
||||
fn default() -> Self {
|
||||
let context = Behavior::Context::default();
|
||||
Self::new(context, Gooey::default())
|
||||
Self::new(Behavior::Context::default())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -175,7 +175,7 @@ impl Window<WidgetInstance> {
|
|||
where
|
||||
W: Widget,
|
||||
{
|
||||
Self::new(WidgetInstance::new(widget), Gooey::default())
|
||||
Self::new(WidgetInstance::new(widget))
|
||||
}
|
||||
|
||||
/// Sets `focused` to be the dynamic updated when this window's focus status
|
||||
|
|
@ -252,6 +252,15 @@ impl Window<WidgetInstance> {
|
|||
self.font_data_to_load.push(font_data);
|
||||
self
|
||||
}
|
||||
|
||||
/// Invokes `on_close` when this window is closed.
|
||||
pub fn on_close<Function>(mut self, on_close: Function) -> Self
|
||||
where
|
||||
Function: FnOnce() + Send + 'static,
|
||||
{
|
||||
self.on_closed = Some(OnceCallback::new(|()| on_close()));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<Behavior> Window<Behavior>
|
||||
|
|
@ -260,7 +269,7 @@ where
|
|||
{
|
||||
/// Returns a new instance using `context` to initialize the window upon
|
||||
/// opening.
|
||||
pub fn new(context: Behavior::Context, gooey: Gooey) -> Self {
|
||||
pub fn new(context: Behavior::Context) -> Self {
|
||||
static EXECUTABLE_NAME: OnceLock<String> = OnceLock::new();
|
||||
|
||||
let title = EXECUTABLE_NAME
|
||||
|
|
@ -281,7 +290,7 @@ where
|
|||
title,
|
||||
..WindowAttributes::default()
|
||||
},
|
||||
gooey,
|
||||
on_closed: None,
|
||||
context,
|
||||
load_system_fonts: true,
|
||||
theme: Value::default(),
|
||||
|
|
@ -308,25 +317,51 @@ where
|
|||
{
|
||||
fn run(self) -> crate::Result {
|
||||
initialize_tracing();
|
||||
GooeyWindow::<Behavior>::run_with(sealed::Context {
|
||||
user: self.context,
|
||||
settings: RefCell::new(sealed::WindowSettings {
|
||||
gooey: self.gooey,
|
||||
transparent: self.attributes.transparent,
|
||||
attributes: Some(self.attributes),
|
||||
occluded: self.occluded,
|
||||
focused: self.focused,
|
||||
inner_size: self.inner_size,
|
||||
theme: Some(self.theme),
|
||||
theme_mode: self.theme_mode,
|
||||
font_data_to_load: self.font_data_to_load,
|
||||
serif_font_family: self.serif_font_family,
|
||||
sans_serif_font_family: self.sans_serif_font_family,
|
||||
fantasy_font_family: self.fantasy_font_family,
|
||||
monospace_font_family: self.monospace_font_family,
|
||||
cursive_font_family: self.cursive_font_family,
|
||||
}),
|
||||
})
|
||||
let app = PendingApp::default();
|
||||
self.open(&app)?;
|
||||
app.run()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Behavior> Open for Window<Behavior>
|
||||
where
|
||||
Behavior: WindowBehavior,
|
||||
{
|
||||
fn open<App>(self, app: &App) -> crate::Result
|
||||
where
|
||||
App: Application,
|
||||
{
|
||||
let gooey = app.gooey().clone();
|
||||
let _handle = GooeyWindow::<Behavior>::open_with(
|
||||
app,
|
||||
sealed::Context {
|
||||
user: self.context,
|
||||
settings: RefCell::new(sealed::WindowSettings {
|
||||
gooey,
|
||||
on_closed: self.on_closed,
|
||||
transparent: self.attributes.transparent,
|
||||
attributes: Some(self.attributes),
|
||||
occluded: self.occluded,
|
||||
focused: self.focused,
|
||||
inner_size: self.inner_size,
|
||||
theme: Some(self.theme),
|
||||
theme_mode: self.theme_mode,
|
||||
font_data_to_load: self.font_data_to_load,
|
||||
serif_font_family: self.serif_font_family,
|
||||
sans_serif_font_family: self.sans_serif_font_family,
|
||||
fantasy_font_family: self.fantasy_font_family,
|
||||
monospace_font_family: self.monospace_font_family,
|
||||
cursive_font_family: self.cursive_font_family,
|
||||
}),
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_in(self, app: PendingApp) -> crate::Result {
|
||||
self.open(&app)?;
|
||||
app.run()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -359,7 +394,7 @@ pub trait WindowBehavior: Sized + 'static {
|
|||
|
||||
/// Runs this behavior as an application, initialized with `context`.
|
||||
fn run_with(context: Self::Context) -> crate::Result {
|
||||
Window::<Self>::new(context, Gooey::default()).run()
|
||||
Window::<Self>::new(context).run()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -385,6 +420,7 @@ struct GooeyWindow<T> {
|
|||
transparent: bool,
|
||||
fonts: FontState,
|
||||
gooey: Gooey,
|
||||
on_closed: Option<OnceCallback>,
|
||||
}
|
||||
|
||||
impl<T> GooeyWindow<T>
|
||||
|
|
@ -580,6 +616,7 @@ where
|
|||
let focused = settings.focused.take().unwrap_or_default();
|
||||
let theme = settings.theme.take().expect("theme always present");
|
||||
let inner_size = settings.inner_size.take().unwrap_or_default();
|
||||
let on_closed = settings.on_closed.take();
|
||||
|
||||
inner_size.set(window.inner_size());
|
||||
|
||||
|
|
@ -676,6 +713,7 @@ where
|
|||
transparent,
|
||||
fonts,
|
||||
gooey,
|
||||
on_closed,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1298,6 +1336,14 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<Behavior> Drop for GooeyWindow<Behavior> {
|
||||
fn drop(&mut self) {
|
||||
if let Some(on_closed) = self.on_closed.take() {
|
||||
on_closed.invoke(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn recursively_handle_event(
|
||||
context: &mut EventContext<'_, '_>,
|
||||
mut each_widget: impl FnMut(&mut EventContext<'_, '_>) -> EventHandling,
|
||||
|
|
@ -1322,10 +1368,11 @@ pub(crate) mod sealed {
|
|||
use kludgine::figures::units::UPx;
|
||||
use kludgine::figures::Size;
|
||||
|
||||
use crate::app::Gooey;
|
||||
use crate::styles::{FontFamilyList, ThemePair};
|
||||
use crate::value::{Dynamic, Value};
|
||||
use crate::widget::OnceCallback;
|
||||
use crate::window::{ThemeMode, WindowAttributes};
|
||||
use crate::Gooey;
|
||||
|
||||
pub struct Context<C> {
|
||||
pub user: C,
|
||||
|
|
@ -1347,6 +1394,7 @@ pub(crate) mod sealed {
|
|||
pub monospace_font_family: FontFamilyList,
|
||||
pub cursive_font_family: FontFamilyList,
|
||||
pub font_data_to_load: Vec<Vec<u8>>,
|
||||
pub on_closed: Option<OnceCallback>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
|
|||
Loading…
Reference in a new issue