From 24c0e24d5fc865b8e28a1eea02f69afc70f2d318 Mon Sep 17 00:00:00 2001 From: Patrick Cleavelin Date: Sat, 24 Feb 2024 18:03:02 -0600 Subject: [PATCH] support window resizing, get started on UI lib --- editor/Cargo.lock | 561 ++++++++++++++++++++++++++++++- editor/Cargo.toml | 3 + editor/src/editor_core/mod.rs | 1 + editor/src/editor_core/ui/mod.rs | 200 +++++++++++ editor/src/main.rs | 286 +++++++++++----- 5 files changed, 969 insertions(+), 82 deletions(-) create mode 100644 editor/src/editor_core/mod.rs create mode 100644 editor/src/editor_core/ui/mod.rs diff --git a/editor/Cargo.lock b/editor/Cargo.lock index 3b3d71c..175f706 100644 --- a/editor/Cargo.lock +++ b/editor/Cargo.lock @@ -73,6 +73,12 @@ dependencies = [ "libc", ] +[[package]] +name = "anyhow" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" + [[package]] name = "arrayref" version = "0.3.7" @@ -100,6 +106,12 @@ dependencies = [ "libloading 0.7.4", ] +[[package]] +name = "associative-cache" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46016233fc1bb55c23b856fe556b7db6ccd05119a0a392e04f0b3b7c79058f16" + [[package]] name = "atomic-waker" version = "1.1.2" @@ -182,6 +194,31 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +[[package]] +name = "cairo-rs" +version = "0.16.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3125b15ec28b84c238f6f476c6034016a5f6cc0221cb514ca46c532139fc97d" +dependencies = [ + "bitflags 1.3.2", + "cairo-sys-rs", + "glib", + "libc", + "once_cell", + "thiserror", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c48f4af05fabdcfa9658178e1326efa061853f040ce7d72e33af6885196f421" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + [[package]] name = "calloop" version = "0.12.4" @@ -223,6 +260,16 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" +[[package]] +name = "cfg-expr" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa50868b64a9a6fda9d593ce778849ea8715cd2a3d2cc17ffdb4a2f2f2f1961d" +dependencies = [ + "smallvec", + "target-lexicon", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -311,6 +358,19 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +[[package]] +name = "core-graphics" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types 0.3.2", + "libc", +] + [[package]] name = "core-graphics" version = "0.23.1" @@ -320,7 +380,7 @@ dependencies = [ "bitflags 1.3.2", "core-foundation", "core-graphics-types", - "foreign-types", + "foreign-types 0.5.0", "libc", ] @@ -335,6 +395,18 @@ dependencies = [ "libc", ] +[[package]] +name = "core-text" +version = "19.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d74ada66e07c1cefa18f8abfba765b486f250de2e4a999e5727fc0dd4b4a25" +dependencies = [ + "core-foundation", + "core-graphics 0.22.3", + "foreign-types 0.3.2", + "libc", +] + [[package]] name = "crossbeam-utils" version = "0.8.19" @@ -379,11 +451,26 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" +[[package]] +name = "dwrote" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439a1c2ba5611ad3ed731280541d36d2e9c4ac5e7fb818a27b604bdc5a6aa65b" +dependencies = [ + "lazy_static", + "libc", + "winapi", + "wio", +] + [[package]] name = "editor" version = "0.1.0" dependencies = [ + "core-graphics 0.22.3", "futures", + "piet-common", + "piet-coregraphics", "wgpu", "winit", ] @@ -404,6 +491,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared 0.1.1", +] + [[package]] name = "foreign-types" version = "0.5.0" @@ -411,7 +507,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" dependencies = [ "foreign-types-macros", - "foreign-types-shared", + "foreign-types-shared 0.3.1", ] [[package]] @@ -425,6 +521,12 @@ dependencies = [ "syn 2.0.50", ] +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "foreign-types-shared" version = "0.3.1" @@ -541,6 +643,39 @@ dependencies = [ "wasi", ] +[[package]] +name = "gio" +version = "0.16.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a1c84b4534a290a29160ef5c6eff2a9c95833111472e824fc5cb78b513dd092" +dependencies = [ + "bitflags 1.3.2", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "gio-sys", + "glib", + "libc", + "once_cell", + "pin-project-lite", + "smallvec", + "thiserror", +] + +[[package]] +name = "gio-sys" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9b693b8e39d042a95547fc258a7b07349b1f0b48f4b2fa3108ba3c51c0b5229" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "winapi", +] + [[package]] name = "gl_generator" version = "0.14.0" @@ -552,6 +687,53 @@ dependencies = [ "xml-rs", ] +[[package]] +name = "glib" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16aa2475c9debed5a32832cb5ff2af5a3f9e1ab9e69df58eaadc1ab2004d6eba" +dependencies = [ + "bitflags 1.3.2", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "once_cell", + "smallvec", + "thiserror", +] + +[[package]] +name = "glib-macros" +version = "0.16.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb1a9325847aa46f1e96ffea37611b9d51fc4827e67f79e7de502a297560a67b" +dependencies = [ + "anyhow", + "heck", + "proc-macro-crate 1.3.1", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "glib-sys" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61a4f46316d06bfa33a7ac22df6f0524c8be58e3db2d9ca99ccb1f357b62a65" +dependencies = [ + "libc", + "system-deps", +] + [[package]] name = "glow" version = "0.13.1" @@ -573,6 +755,17 @@ dependencies = [ "gl_generator", ] +[[package]] +name = "gobject-sys" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3520bb9c07ae2a12c7f2fbb24d4efc11231c8146a86956413fb1a79bb760a0f1" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + [[package]] name = "gpu-alloc" version = "0.6.0" @@ -650,6 +843,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hexf-parse" version = "0.2.1" @@ -725,6 +924,21 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" +[[package]] +name = "kurbo" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd85a5776cd9500c2e2059c8c76c3b01528566b7fcbaf8098b55a33fc298849b" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" version = "0.2.153" @@ -793,6 +1007,12 @@ dependencies = [ "libc", ] +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + [[package]] name = "memchr" version = "2.7.1" @@ -817,7 +1037,7 @@ dependencies = [ "bitflags 2.4.2", "block", "core-graphics-types", - "foreign-types", + "foreign-types 0.5.0", "log", "objc", "paste", @@ -897,7 +1117,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 3.1.0", "proc-macro2", "quote", "syn 2.0.50", @@ -968,6 +1188,59 @@ dependencies = [ "ttf-parser", ] +[[package]] +name = "pango" +version = "0.16.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdff66b271861037b89d028656184059e03b0b6ccb36003820be19f7200b1e94" +dependencies = [ + "bitflags 1.3.2", + "gio", + "glib", + "libc", + "once_cell", + "pango-sys", +] + +[[package]] +name = "pango-sys" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e134909a9a293e04d2cc31928aa95679c5e4df954d0b85483159bd20d8f047f" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "pangocairo" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16ad2ec87789371b551fd2367c10aa37060412ffd3e60abd99491b21b93a3f9b" +dependencies = [ + "bitflags 1.3.2", + "cairo-rs", + "glib", + "libc", + "pango", + "pangocairo-sys", +] + +[[package]] +name = "pangocairo-sys" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "848d2df9b7f1a8c7a19d994de443bcbe5d4382610ccb8e64247f932be74fcf76" +dependencies = [ + "cairo-sys-rs", + "glib-sys", + "libc", + "pango-sys", + "system-deps", +] + [[package]] name = "parking_lot" version = "0.12.1" @@ -1003,6 +1276,92 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "piet" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e381186490a3e2017a506d62b759ea8eaf4be14666b13ed53973e8ae193451b1" +dependencies = [ + "kurbo", + "unic-bidi", +] + +[[package]] +name = "piet-cairo" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12dc0b38ac300c79deb9bfc8c7f91a08f2b080338648f7202981094b22321bb9" +dependencies = [ + "cairo-rs", + "pango", + "pangocairo", + "piet", + "unicode-segmentation", + "xi-unicode", +] + +[[package]] +name = "piet-common" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd8497cc0bcfecb1e14e027428c5e3eaf9af6e14761176e1212006d8bdba387" +dependencies = [ + "cairo-rs", + "cairo-sys-rs", + "cfg-if", + "core-graphics 0.22.3", + "piet", + "piet-cairo", + "piet-coregraphics", + "piet-direct2d", + "piet-web", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "piet-coregraphics" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a819b41d2ddb1d8abf3e45e49422f866cba281b4abb5e2fb948bba06e2c3d3f7" +dependencies = [ + "associative-cache", + "core-foundation", + "core-foundation-sys", + "core-graphics 0.22.3", + "core-text", + "foreign-types 0.3.2", + "piet", +] + +[[package]] +name = "piet-direct2d" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd00e91df4f987be40eb13042afe6ee9e54468466bdb7486390b40d4fef0993e" +dependencies = [ + "associative-cache", + "dwrote", + "piet", + "utf16_lit", + "winapi", + "wio", +] + +[[package]] +name = "piet-web" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a560232a94e535979923d49062d1c6d5407b3804bcd0d0b4cb9e25a9b41db1e" +dependencies = [ + "js-sys", + "piet", + "unicode-segmentation", + "wasm-bindgen", + "web-sys", + "xi-unicode", +] + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -1041,13 +1400,47 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + [[package]] name = "proc-macro-crate" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" dependencies = [ - "toml_edit", + "toml_edit 0.21.1", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", ] [[package]] @@ -1192,6 +1585,15 @@ dependencies = [ "syn 2.0.50", ] +[[package]] +name = "serde_spanned" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ + "serde", +] + [[package]] name = "slab" version = "0.4.9" @@ -1293,6 +1695,25 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "system-deps" +version = "6.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2d580ff6a20c55dfb86be5f9c238f67835d0e81cbdea8bf5680e0897320331" +dependencies = [ + "cfg-expr", + "heck", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "target-lexicon" +version = "0.12.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" + [[package]] name = "termcolor" version = "1.4.1" @@ -1347,11 +1768,37 @@ dependencies = [ "strict-num", ] +[[package]] +name = "toml" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a9aad4a3066010876e8dcf5a8a06e70a558751117a145c6ce2b82c2e2054290" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.6", +] + [[package]] name = "toml_datetime" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow 0.5.40", +] [[package]] name = "toml_edit" @@ -1361,7 +1808,20 @@ checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ "indexmap", "toml_datetime", - "winnow", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.6.2", ] [[package]] @@ -1386,6 +1846,57 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4" +[[package]] +name = "unic-bidi" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1356b759fb6a82050666f11dce4b6fe3571781f1449f3ef78074e408d468ec09" +dependencies = [ + "matches", + "unic-ucd-bidi", +] + +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-ucd-bidi" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1d568b51222484e1f8209ce48caa6b430bf352962b877d592c29ab31fb53d8c" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + [[package]] name = "unicode-ident" version = "1.0.12" @@ -1410,6 +1921,18 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "utf16_lit" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14706d2a800ee8ff38c1d3edb873cd616971ea59eb7c0d046bb44ef59b06a1ae" + +[[package]] +name = "version-compare" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" + [[package]] name = "version_check" version = "0.9.4" @@ -2001,7 +2524,7 @@ dependencies = [ "calloop", "cfg_aliases", "core-foundation", - "core-graphics", + "core-graphics 0.23.1", "cursor-icon", "icrate", "js-sys", @@ -2044,6 +2567,24 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a4191c47f15cc3ec71fcb4913cb83d58def65dd3787610213c649283b5ce178" +dependencies = [ + "memchr", +] + +[[package]] +name = "wio" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5" +dependencies = [ + "winapi", +] + [[package]] name = "x11-dl" version = "2.21.0" @@ -2082,6 +2623,12 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a0ccd7b4a5345edfcd0c3535718a4e9ff7798ffc536bb5b5a0e26ff84732911" +[[package]] +name = "xi-unicode" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a" + [[package]] name = "xkbcommon-dl" version = "0.4.2" diff --git a/editor/Cargo.toml b/editor/Cargo.toml index 60c1e07..062492b 100644 --- a/editor/Cargo.toml +++ b/editor/Cargo.toml @@ -6,6 +6,9 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +core-graphics = "0.22.3" futures = "0.3.30" +piet-common = "0.6.2" +piet-coregraphics = "0.6.2" wgpu = "0.19.1" winit = "0.29.10" diff --git a/editor/src/editor_core/mod.rs b/editor/src/editor_core/mod.rs new file mode 100644 index 0000000..6bae95d --- /dev/null +++ b/editor/src/editor_core/mod.rs @@ -0,0 +1 @@ +pub mod ui; diff --git a/editor/src/editor_core/ui/mod.rs b/editor/src/editor_core/ui/mod.rs new file mode 100644 index 0000000..37acaa3 --- /dev/null +++ b/editor/src/editor_core/ui/mod.rs @@ -0,0 +1,200 @@ +use std::collections::HashMap; + +const ROOT_NODE: &str = "root"; + +#[derive(Clone, Hash, Eq, PartialEq)] +pub struct NodeKey(String); +impl std::fmt::Display for NodeKey { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl std::fmt::Debug for NodeKey { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{self}") + } +} + +impl NodeKey { + fn root() -> Self { + Self(ROOT_NODE.to_string()) + } + + pub fn new(cx: &Context, label: &str) -> Self { + NodeKey(format!("{}:{label}", cx.current_parent)) + } +} + +#[derive(Debug)] +struct Node { + first: Option, + last: Option, + next: Option, + prev: Option, + + parent: Option, + + label: String, +} + +pub struct Context { + persistent_nodes: HashMap, + + current_parent: NodeKey, + root_node: NodeKey, +} + +impl Context { + pub fn new() -> Self { + let mut nodes = HashMap::new(); + nodes.insert( + NodeKey::root(), + Node { + first: None, + last: None, + next: None, + prev: None, + parent: None, + label: "root".to_string(), + }, + ); + + Self { + persistent_nodes: nodes, + current_parent: NodeKey::root(), + root_node: NodeKey::root(), + } + } + + fn parent_key(&self, key: &NodeKey) -> Option { + self.persistent_nodes + .get(key) + .and_then(|n| n.parent.clone()) + } + fn first_key(&self, key: &NodeKey) -> Option { + self.first_key_ref(key).cloned() + } + fn last_key(&self, key: &NodeKey) -> Option { + self.persistent_nodes.get(key).and_then(|n| n.last.clone()) + } + fn next_key(&self, key: &NodeKey) -> Option { + self.next_key_ref(key).cloned() + } + fn prev_key(&self, key: &NodeKey) -> Option { + self.persistent_nodes.get(key).and_then(|n| n.prev.clone()) + } + + fn first_key_ref(&self, key: &NodeKey) -> Option<&NodeKey> { + self.persistent_nodes + .get(key) + .and_then(|n| n.first.as_ref()) + } + fn next_key_ref(&self, key: &NodeKey) -> Option<&NodeKey> { + self.persistent_nodes.get(key).and_then(|n| n.next.as_ref()) + } + + pub fn make_node(&mut self, label: impl ToString) -> NodeKey { + let label = label.to_string(); + let key = NodeKey::new(self, &label); + + if let Some(_node) = self.persistent_nodes.get(&key) { + // TODO: check for last_interacted_index + } else { + let node = Node { + first: None, + last: None, + next: None, + prev: self.last_key(&self.current_parent), + parent: Some(self.current_parent.clone()), + + label, + }; + self.persistent_nodes.insert(key.clone(), node); + } + + // Update tree references + if let Some(parent_node) = self.persistent_nodes.get_mut(&self.current_parent) { + if parent_node.first.is_none() { + parent_node.first = Some(key.clone()); + } + + // NOTE(pcleavelin): `parent_node.last` must be updated before the below mutable + // borrow so the mutable reference above is un-borrowed by then + let last_before_update = parent_node.last.clone(); + parent_node.last = Some(key.clone()); + + if let Some(parent_node_last) = last_before_update { + if let Some(last_node) = self.persistent_nodes.get_mut(&parent_node_last) { + last_node.next = Some(key.clone()); + } + } + } + + key + } + + pub fn push_parent(&mut self, key: NodeKey) { + self.current_parent = key; + } + pub fn pop_parent(&mut self) { + self.current_parent = self + .parent_key(&self.current_parent) + .unwrap_or(NodeKey::root()); + } + + pub fn debug_print(&self) { + let root_node = NodeKey::root(); + let iter = NodeIter::from_key(self, self.first_key_ref(&root_node).unwrap()); + + for node in iter { + eprintln!("{node:?}"); + } + } +} + +struct NodeIter<'a> { + cx: &'a Context, + current_key: &'a NodeKey, + reached_end: bool, +} + +impl<'a> NodeIter<'a> { + fn from_key(cx: &'a Context, key: &'a NodeKey) -> Self { + Self { + cx, + current_key: key, + reached_end: false, + } + } +} + +impl<'a> Iterator for NodeIter<'a> { + type Item = &'a Node; + + fn next(&mut self) -> Option { + if self.reached_end { + return None; + } + + if let Some(node) = self.cx.persistent_nodes.get(self.current_key) { + if let Some(first) = node.first.as_ref() { + self.current_key = first; + } else if let Some(next) = node.next.as_ref() { + self.current_key = next; + } else if let Some(parent) = node.parent.as_ref() { + if let Some(parent_next) = self.cx.next_key_ref(parent) { + self.current_key = parent_next; + } else { + self.reached_end = true; + } + } else { + self.reached_end = true; + } + + return Some(node); + } + + None + } +} diff --git a/editor/src/main.rs b/editor/src/main.rs index 5f6c685..9aa4391 100644 --- a/editor/src/main.rs +++ b/editor/src/main.rs @@ -1,4 +1,10 @@ +mod editor_core; + +use core_graphics::{color_space::CGColorSpace, context::CGContext}; +use editor_core::ui; use futures::executor::block_on; +use piet_common::{kurbo::Rect, RenderContext}; +use piet_coregraphics::CoreGraphicsContext; use wgpu::util::DeviceExt; use winit::{ dpi::LogicalSize, @@ -64,6 +70,116 @@ const FULL_QUAD_VERTS: &[Vertex] = &[ }, ]; +struct Texture<'a> { + texture: wgpu::Texture, + view: wgpu::TextureView, + sampler: &'a wgpu::Sampler, + layout: &'a wgpu::BindGroupLayout, + bind_group: wgpu::BindGroup, + + width: u32, + height: u32, +} + +impl<'a> Texture<'a> { + const fn desc() -> wgpu::BindGroupLayoutDescriptor<'static> { + wgpu::BindGroupLayoutDescriptor { + label: None, + entries: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + view_dimension: wgpu::TextureViewDimension::D2, + multisampled: false, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), + count: None, + }, + ], + } + } + + fn create_wgpu_texture( + device: &wgpu::Device, + layout: &wgpu::BindGroupLayout, + sampler: &'a wgpu::Sampler, + width: u32, + height: u32, + ) -> (wgpu::Texture, wgpu::TextureView, wgpu::BindGroup) { + let texture_size = wgpu::Extent3d { + width, + height, + depth_or_array_layers: 1, + }; + let texture = device.create_texture(&wgpu::TextureDescriptor { + label: None, + size: texture_size, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8UnormSrgb, + usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, + view_formats: &[], + }); + let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default()); + + let texture_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: None, + layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(&texture_view), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::Sampler(sampler), + }, + ], + }); + + (texture, texture_view, texture_bind_group) + } + fn new( + device: &wgpu::Device, + layout: &'a wgpu::BindGroupLayout, + sampler: &'a wgpu::Sampler, + width: u32, + height: u32, + ) -> Self { + let (texture, view, bind_group) = + Self::create_wgpu_texture(device, layout, sampler, width, height); + + Self { + texture, + view, + layout, + bind_group, + sampler, + + width, + height, + } + } + + fn resize(&mut self, device: &wgpu::Device, width: u32, height: u32) { + self.texture.destroy(); + + (self.texture, self.view, self.bind_group) = + Self::create_wgpu_texture(device, self.layout, self.sampler, width, height); + + self.width = width; + self.height = height; + } +} + fn main() -> Result<(), Box> { let event_loop = EventLoop::new()?; let logical_size = LogicalSize::new(800.0, 600.0); @@ -112,62 +228,19 @@ fn main() -> Result<(), Box> { }, usage: wgpu::BufferUsages::VERTEX, }); - let texture_size = wgpu::Extent3d { - width: 2, - height: 2, - depth_or_array_layers: 1, - }; - let texture = device.create_texture(&wgpu::TextureDescriptor { - label: None, - size: texture_size, - mip_level_count: 1, - sample_count: 1, - dimension: wgpu::TextureDimension::D2, - format: wgpu::TextureFormat::Rgba8UnormSrgb, - usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, - view_formats: &[], - }); - let texture_bind_group_layout = - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - label: None, - entries: &[ - wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Texture { - sample_type: wgpu::TextureSampleType::Float { filterable: true }, - view_dimension: wgpu::TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 1, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), - count: None, - }, - ], - }); - let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default()); - let texture_sampler = device.create_sampler(&wgpu::SamplerDescriptor::default()); - let texture_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - label: None, - layout: &texture_bind_group_layout, - entries: &[ - wgpu::BindGroupEntry { - binding: 0, - resource: wgpu::BindingResource::TextureView(&texture_view), - }, - wgpu::BindGroupEntry { - binding: 1, - resource: wgpu::BindingResource::Sampler(&texture_sampler), - }, - ], - }); + + let sampler = device.create_sampler(&wgpu::SamplerDescriptor::default()); + let texture_layout = device.create_bind_group_layout(&Texture::desc()); + let mut texture = Texture::new( + &device, + &texture_layout, + &sampler, + window_size.width, + window_size.height, + ); let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: None, - bind_group_layouts: &[&texture_bind_group_layout], + bind_group_layouts: &[&texture_layout], push_constant_ranges: &[], }); let swapchain_capabilities = surface.get_capabilities(&adapter); @@ -199,6 +272,35 @@ fn main() -> Result<(), Box> { let window = &window; event_loop.set_control_flow(ControlFlow::Wait); + let mut cg_context = CGContext::create_bitmap_context( + None, + texture.width as usize, + texture.height as usize, + 8, + 4 * texture.width as usize, + &CGColorSpace::create_device_rgb(), + core_graphics::base::kCGImageAlphaPremultipliedLast, + ); + + /*************************/ + + let mut cx = ui::Context::new(); + cx.make_node("first child"); + cx.make_node("second child"); + let key = cx.make_node("third child with children"); + cx.push_parent(key); + { + cx.make_node("first nested child"); + cx.make_node("second nested child"); + cx.make_node("third nested child"); + } + cx.pop_parent(); + cx.make_node("fourth child"); + + cx.debug_print(); + + /*************************/ + #[allow(clippy::single_match)] event_loop.run(move |event, elwt| match event { Event::WindowEvent { event, .. } => match event { @@ -211,7 +313,16 @@ fn main() -> Result<(), Box> { config.height = size.height; surface.configure(&device, &config); - + texture.resize(&device, config.width, config.height); + cg_context = CGContext::create_bitmap_context( + None, + texture.width as usize, + texture.height as usize, + 8, + 4 * texture.width as usize, + &CGColorSpace::create_device_rgb(), + core_graphics::base::kCGImageAlphaPremultipliedLast, + ); window.request_redraw(); } WindowEvent::MouseInput { .. } => window.request_redraw(), @@ -243,33 +354,58 @@ fn main() -> Result<(), Box> { occlusion_query_set: None, }); rpass.set_pipeline(&render_pipeline); - rpass.set_bind_group(0, &texture_bind_group, &[]); + rpass.set_bind_group(0, &texture.bind_group, &[]); rpass.set_vertex_buffer(0, vertex_buffer.slice(..)); rpass.draw(0..FULL_QUAD_VERTS.len() as u32, 0..1); } - queue.write_texture( - wgpu::ImageCopyTexture { - texture: &texture, - mip_level: 0, - origin: wgpu::Origin3d::ZERO, - aspect: wgpu::TextureAspect::All, - }, - &[ - 255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255, 255, 0, 255, 255, - ], - wgpu::ImageDataLayout { - offset: 0, - bytes_per_row: Some(4 * texture_size.width), - rows_per_image: Some(texture_size.height), - }, - texture_size, - ); + let piet_render = || -> Result<(), Box> { + { + let mut piet_context = CoreGraphicsContext::new_y_up( + &mut cg_context, + texture.height as f64, + None, + ); + + piet_context.clear(None, piet_common::Color::BLACK); + piet_context.fill( + Rect::new(16.0, 16.0, 256.0, 256.0), + &piet_common::Color::WHITE, + ); + + piet_context.finish()?; + } + + queue.write_texture( + wgpu::ImageCopyTexture { + texture: &texture.texture, + mip_level: 0, + origin: wgpu::Origin3d::ZERO, + aspect: wgpu::TextureAspect::All, + }, + cg_context.data(), + wgpu::ImageDataLayout { + offset: 0, + bytes_per_row: Some(4 * texture.width), + rows_per_image: Some(texture.height), + }, + wgpu::Extent3d { + width: texture.width, + height: texture.height, + depth_or_array_layers: 1, + }, + ); + + Ok(()) + }(); + + if let Err(err) = piet_render { + eprintln!("failed to render with piet: {err}"); + elwt.exit(); + } queue.submit(Some(encoder.finish())); frame.present(); - - eprintln!("redraw"); } _ => (), },