diff --git a/examples/gtk/Cargo.toml b/examples/gtk/Cargo.toml index b5071de00f..efa88c841c 100644 --- a/examples/gtk/Cargo.toml +++ b/examples/gtk/Cargo.toml @@ -4,15 +4,15 @@ version = "0.1.0" edition = "2021" [dependencies] -leptos = { path = "../../leptos", features = ["csr"] } +leptos = { path = "../../leptos" } throw_error = { path = "../../any_error/" } -any_spawner = { path = "../../any_spawner/" } + +# these are used to build the integration +gtk = { version = "0.9.0", package = "gtk4" } next_tuple = { path = "../../next_tuple/" } -gtk = { version = "0.9.0", package = "gtk4", optional = true } paste = "1.0" -console_error_panic_hook = { version = "0.1.7", optional = true } - -[features] -gtk = ["dep:gtk", "any_spawner/glib"] -wasm = ["any_spawner/wasm-bindgen", "dep:console_error_panic_hook"] +# we want to support using glib for the reactive runtime event loop +any_spawner = { path = "../../any_spawner/", features = ["glib"] } +# yes, we want effects to run: this is a "frontend," not a backend +reactive_graph = { path = "../../reactive_graph", features = ["effects"] } diff --git a/examples/gtk/src/leptos_gtk.rs b/examples/gtk/src/leptos_gtk.rs index e8997355f7..0f0dca8d14 100644 --- a/examples/gtk/src/leptos_gtk.rs +++ b/examples/gtk/src/leptos_gtk.rs @@ -56,11 +56,12 @@ impl Mountable for Element { .insert_before(&parent.0, marker.as_ref().map(|m| &m.0)); } - fn insert_before_this(&self, - child: &mut dyn Mountable, - ) -> bool { - child.mount(parent, Some(self.as_ref())); - true + fn insert_before_this(&self, child: &mut dyn Mountable) -> bool { + if let Some(parent) = self.0.parent() { + child.mount(&Element(parent), Some(self)); + return true; + } + false } } @@ -79,11 +80,8 @@ impl Mountable for Text { .insert_before(&parent.0, marker.as_ref().map(|m| &m.0)); } - fn insert_before_this(&self, - child: &mut dyn Mountable, - ) -> bool { - child.mount(parent, Some(self.as_ref())); - true + fn insert_before_this(&self, child: &mut dyn Mountable) -> bool { + self.0.insert_before_this(child) } } @@ -332,16 +330,12 @@ where parent: &::Element, marker: Option<&::Node>, ) { - println!("mounting {}", std::any::type_name::()); self.children.mount(&self.widget, None); LeptosGtk::insert_node(parent, &self.widget, marker); } - fn insert_before_this(&self, - child: &mut dyn Mountable, - ) -> bool { - child.mount(parent, Some(self.widget.as_ref())); - true + fn insert_before_this(&self, child: &mut dyn Mountable) -> bool { + self.widget.insert_before_this(child) } } diff --git a/examples/gtk/src/main.rs b/examples/gtk/src/main.rs index d9238b7e76..49a09599a7 100644 --- a/examples/gtk/src/main.rs +++ b/examples/gtk/src/main.rs @@ -1,20 +1,8 @@ -#[cfg(feature = "gtk")] -use gtk::{ - glib::Value, prelude::*, Application, ApplicationWindow, Orientation, - Widget, -}; -#[cfg(feature = "wasm")] -use leptos::tachys::{dom::body, html::element, html::event as ev}; -use leptos::{ - logging, - prelude::*, - reactive_graph::{effect::Effect, owner::Owner, signal::RwSignal}, - Executor, For, ForProps, -}; -#[cfg(feature = "gtk")] -use leptos_gtk::{Element, LGtkWidget, LeptosGtk}; +use any_spawner::Executor; +use gtk::{prelude::*, Application, ApplicationWindow, Orientation}; +use leptos::prelude::*; +use leptos_gtk::LeptosGtk; use std::{mem, thread, time::Duration}; -#[cfg(feature = "gtk")] mod leptos_gtk; const APP_ID: &str = "dev.leptos.Counter"; @@ -22,59 +10,39 @@ const APP_ID: &str = "dev.leptos.Counter"; // Basic GTK app setup from https://gtk-rs.org/gtk4-rs/stable/latest/book/hello_world.html fn main() { // use the glib event loop to power the reactive system - #[cfg(feature = "gtk")] - { - _ = Executor::init_glib(); - let app = Application::builder().application_id(APP_ID).build(); - - app.connect_startup(|_| load_css()); - - app.connect_activate(|app| { - // Connect to "activate" signal of `app` - let owner = Owner::new(); - let view = owner.with(ui); - let (root, state) = leptos_gtk::root(view); - - let window = ApplicationWindow::builder() - .application(app) - .title("TachyGTK") - .child(&root) - .build(); - // Present window - window.present(); - mem::forget((owner, state)); - }); - - app.run(); - } - - #[cfg(all(feature = "wasm", not(feature = "gtk")))] - { - console_error_panic_hook::set_once(); - _ = Executor::init_wasm_bindgen(); + _ = Executor::init_glib(); + let app = Application::builder().application_id(APP_ID).build(); + + app.connect_startup(|_| load_css()); + + app.connect_activate(|app| { + // Connect to "activate" signal of `app` let owner = Owner::new(); let view = owner.with(ui); - let mut state = view.build(); - state.mount(&body().into(), None); + let (root, state) = leptos_gtk::root(view); + + let window = ApplicationWindow::builder() + .application(app) + .title("TachyGTK") + .child(&root) + .build(); + // Present window + window.present(); mem::forget((owner, state)); - } -} + }); -#[cfg(feature = "gtk")] -type Rndr = LeptosGtk; -#[cfg(all(feature = "wasm", not(feature = "gtk")))] -type Rndr = Dom; + app.run(); +} -fn ui() -> impl Render { +fn ui() -> impl Render { let value = RwSignal::new(0); let rows = RwSignal::new(vec![1, 2, 3, 4, 5]); Effect::new(move |_| { - logging::log!("value = {}", value.get()); + println!("value = {}", value.get()); }); // just an example of multithreaded reactivity - #[cfg(feature = "gtk")] thread::spawn(move || loop { thread::sleep(Duration::from_millis(250)); value.update(|n| *n += 1); @@ -82,7 +50,10 @@ fn ui() -> impl Render { vstack(( hstack(( - button("-1", move || value.update(|n| *n -= 1)), + button("-1", move || { + println!("clicked -1"); + value.update(|n| *n -= 1); + }), move || value.get().to_string(), button("+1", move || value.update(|n| *n += 1)), )), @@ -91,75 +62,36 @@ fn ui() -> impl Render { items.swap(1, 3); }) }), - hstack(For(ForProps::builder() - .each(move || rows.get()) - .key(|k| *k) - .children(|v| v) - .build())), + hstack(rows), )) } fn button( - label: impl Render, + label: impl Render, callback: impl Fn() + Send + Sync + 'static, -) -> impl Render { - #[cfg(feature = "gtk")] - { - leptos_gtk::button() - .child(label) - .connect("clicked", move |_| { - callback(); - None - }) - } - #[cfg(all(feature = "wasm", not(feature = "gtk")))] - { - element::button() - .on(ev::click, move |_| callback()) - .child(label) - } +) -> impl Render { + leptos_gtk::button() + .child(label) + .connect("clicked", move |_| { + callback(); + None + }) } -fn vstack(children: impl Render) -> impl Render { - #[cfg(feature = "gtk")] - { - leptos_gtk::r#box() - .orientation(Orientation::Vertical) - .spacing(12) - .child(children) - } - #[cfg(all(feature = "wasm", not(feature = "gtk")))] - { - element::div() - .style(("display", "flex")) - .style(("flex-direction", "column")) - .style(("align-items", "center")) - .style(("justify-content", "center")) - .style(("margin", "1rem")) - .child(children) - } +fn vstack(children: impl Render) -> impl Render { + leptos_gtk::r#box() + .orientation(Orientation::Vertical) + .spacing(12) + .child(children) } -fn hstack(children: impl Render) -> impl Render { - #[cfg(feature = "gtk")] - { - leptos_gtk::r#box() - .orientation(Orientation::Horizontal) - .spacing(12) - .child(children) - } - #[cfg(all(feature = "wasm", not(feature = "gtk")))] - { - element::div() - .style(("display", "flex")) - .style(("align-items", "center")) - .style(("justify-content", "center")) - .style(("margin", "1rem")) - .child(children) - } +fn hstack(children: impl Render) -> impl Render { + leptos_gtk::r#box() + .orientation(Orientation::Horizontal) + .spacing(12) + .child(children) } -#[cfg(feature = "gtk")] fn load_css() { use gtk::{gdk::Display, CssProvider};