diff --git a/Cargo.lock b/Cargo.lock index 2a93bc6..02fefa7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,15 +20,19 @@ checksum = "b2187590a23ab1e3df8681afdf0987c48504d80291f002fcdb651f0ef5e25169" [[package]] name = "accesskit" -version = "0.17.1" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3d3b8f9bae46a948369bc4a03e815d4ed6d616bd00de4051133a5019dc31c5a" +checksum = "e25ae84c0260bdf5df07796d7cc4882460de26a2b406ec0e6c42461a723b271b" +dependencies = [ + "enumn", + "serde", +] [[package]] name = "accesskit_atspi_common" -version = "0.10.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c5dd55e6e94949498698daf4d48fb5659e824d7abec0d394089656ceaf99d4f" +checksum = "29bd41de2e54451a8ca0dd95ebf45b54d349d29ebceb7f20be264eee14e3d477" dependencies = [ "accesskit", "accesskit_consumer", @@ -40,20 +44,19 @@ dependencies = [ [[package]] name = "accesskit_consumer" -version = "0.26.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f47983a1084940ba9a39c077a8c63e55c619388be5476ac04c804cfbd1e63459" +checksum = "8bfae7c152994a31dc7d99b8eeac7784a919f71d1b306f4b83217e110fd3824c" dependencies = [ "accesskit", "hashbrown", - "immutable-chunkmap", ] [[package]] name = "accesskit_macos" -version = "0.18.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7329821f3bd1101e03a7d2e03bd339e3ac0dc64c70b4c9f9ae1949e3ba8dece1" +checksum = "692dd318ff8a7a0ffda67271c4bd10cf32249656f4e49390db0b26ca92b095f2" dependencies = [ "accesskit", "accesskit_consumer", @@ -65,9 +68,9 @@ dependencies = [ [[package]] name = "accesskit_unix" -version = "0.13.1" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcee751cc20d88678c33edaf9c07e8b693cd02819fe89053776f5313492273f5" +checksum = "c5f7474c36606d0fe4f438291d667bae7042ea2760f506650ad2366926358fc8" dependencies = [ "accesskit", "accesskit_atspi_common", @@ -83,24 +86,23 @@ dependencies = [ [[package]] name = "accesskit_windows" -version = "0.24.1" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24fcd5d23d70670992b823e735e859374d694a3d12bfd8dd32bd3bd8bedb5d81" +checksum = "70a042b62c9c05bf7b616f015515c17d2813f3ba89978d6f4fc369735d60700a" dependencies = [ "accesskit", "accesskit_consumer", "hashbrown", - "paste", "static_assertions", "windows", - "windows-core 0.58.0", + "windows-core", ] [[package]] name = "accesskit_winit" -version = "0.23.1" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6a48dad5530b6deb9fc7a52cc6c3bf72cdd9eb8157ac9d32d69f2427a5e879" +checksum = "5c1f0d3d13113d8857542a4f8d1a1c24d1dc1527b77aee8426127f4901588708" dependencies = [ "accesskit", "accesskit_macos", @@ -125,6 +127,7 @@ dependencies = [ "cfg-if", "getrandom 0.3.3", "once_cell", + "serde", "version_check", "zerocopy", ] @@ -154,7 +157,7 @@ dependencies = [ "log", "ndk", "ndk-context", - "ndk-sys 0.6.0+11769913", + "ndk-sys", "num_enum", "thiserror 1.0.69", ] @@ -241,15 +244,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" -[[package]] -name = "ash" -version = "0.38.0+1.3.281" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" -dependencies = [ - "libloading", -] - [[package]] name = "async-broadcast" version = "0.7.2" @@ -288,17 +282,6 @@ dependencies = [ "slab", ] -[[package]] -name = "async-fs" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" -dependencies = [ - "async-lock", - "blocking", - "futures-lite", -] - [[package]] name = "async-io" version = "2.4.1" @@ -402,9 +385,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "atspi" -version = "0.22.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be534b16650e35237bb1ed189ba2aab86ce65e88cc84c66f4935ba38575cecbf" +checksum = "c83247582e7508838caf5f316c00791eee0e15c0bf743e6880585b867e16815c" dependencies = [ "atspi-common", "atspi-connection", @@ -413,9 +396,9 @@ dependencies = [ [[package]] name = "atspi-common" -version = "0.6.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1909ed2dc01d0a17505d89311d192518507e8a056a48148e3598fef5e7bb6ba7" +checksum = "33dfc05e7cdf90988a197803bf24f5788f94f7c94a69efa95683e8ffe76cfdfb" dependencies = [ "enumflags2", "serde", @@ -429,9 +412,9 @@ dependencies = [ [[package]] name = "atspi-connection" -version = "0.6.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "430c5960624a4baaa511c9c0fcc2218e3b58f5dbcc47e6190cafee344b873333" +checksum = "4193d51303d8332304056ae0004714256b46b6635a5c556109b319c0d3784938" dependencies = [ "atspi-common", "atspi-proxies", @@ -441,14 +424,13 @@ dependencies = [ [[package]] name = "atspi-proxies" -version = "0.6.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e6c5de3e524cf967569722446bcd458d5032348554d9a17d7d72b041ab7496" +checksum = "d2eebcb9e7e76f26d0bcfd6f0295e1cd1e6f33bedbc5698a971db8dc43d7751c" dependencies = [ "atspi-common", "serde", "zbus", - "zvariant", ] [[package]] @@ -522,21 +504,6 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" -[[package]] -name = "block" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - [[package]] name = "block2" version = "0.5.1" @@ -703,10 +670,11 @@ dependencies = [ [[package]] name = "codespan-reporting" -version = "0.11.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" dependencies = [ + "serde", "termcolor", "unicode-width", ] @@ -786,15 +754,6 @@ dependencies = [ "libc", ] -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - [[package]] name = "crc32fast" version = "1.4.2" @@ -835,16 +794,6 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - [[package]] name = "cursor-icon" version = "1.2.0" @@ -857,16 +806,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - [[package]] name = "dispatch" version = "0.2.0" @@ -932,12 +871,13 @@ checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" [[package]] name = "ecolor" -version = "0.31.1" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc4feb366740ded31a004a0e4452fbf84e80ef432ecf8314c485210229672fd1" +checksum = "4a631732d995184114016fab22fc7e3faf73d6841c2d7650395fe251fbcd9285" dependencies = [ "bytemuck", "emath", + "serde", ] [[package]] @@ -950,9 +890,9 @@ dependencies = [ [[package]] name = "eframe" -version = "0.31.1" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0dfe0859f3fb1bc6424c57d41e10e9093fe938f426b691e42272c2f336d915c" +checksum = "0c790ccfbb3dd556588342463454b2b2b13909e5fdce5bc2a1432a8aa69c8b7a" dependencies = [ "ahash", "bytemuck", @@ -986,9 +926,9 @@ dependencies = [ [[package]] name = "egui" -version = "0.31.1" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd34cec49ab55d85ebf70139cb1ccd29c977ef6b6ba4fe85489d6877ee9ef3" +checksum = "8470210c95a42cc985d9ffebfd5067eea55bdb1c3f7611484907db9639675e28" dependencies = [ "accesskit", "ahash", @@ -998,13 +938,16 @@ dependencies = [ "log", "nohash-hasher", "profiling", + "serde", + "smallvec", + "unicode-segmentation", ] [[package]] name = "egui-wgpu" -version = "0.31.1" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d319dfef570f699b6e9114e235e862a2ddcf75f0d1a061de9e1328d92146d820" +checksum = "14de9942d8b9e99e2d830403c208ab1a6e052e925a7456a4f6f66d567d90de1d" dependencies = [ "ahash", "bytemuck", @@ -1022,9 +965,9 @@ dependencies = [ [[package]] name = "egui-winit" -version = "0.31.1" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d9dfbb78fe4eb9c3a39ad528b90ee5915c252e77bbab9d4ebc576541ab67e13" +checksum = "c490804a035cec9c826082894a3e1ecf4198accd3817deb10f7919108ebafab0" dependencies = [ "accesskit_winit", "ahash", @@ -1042,9 +985,9 @@ dependencies = [ [[package]] name = "egui_commonmark" -version = "0.20.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1e5d9a91b1b7a320c9b7f56d1878416d7c9bab3eaf337b036e0ddfabf58623" +checksum = "26c9caff9c964af1e3d913acd85e86d2170e3169a43cf4ff84eea3106691c14d" dependencies = [ "egui", "egui_commonmark_backend", @@ -1054,9 +997,9 @@ dependencies = [ [[package]] name = "egui_commonmark_backend" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efb41b6833a6aaa99ca5c4f8e75b2410d69a7b3e30148d413f541147404a0dfa" +checksum = "6e317aa4031f27be77d4c1c33cb038cdf02d77790c28e5cf1283a66cceb88695" dependencies = [ "data-url", "egui", @@ -1066,9 +1009,9 @@ dependencies = [ [[package]] name = "egui_extras" -version = "0.31.1" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624659a2e972a46f4d5f646557906c55f1cd5a0836eddbe610fdf1afba1b4226" +checksum = "0f791a5937f518249016b276b3639ad2aa3824048b6f2161ec2b431ab325880a" dependencies = [ "ahash", "chrono", @@ -1082,9 +1025,9 @@ dependencies = [ [[package]] name = "egui_file" -version = "0.22.1" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e7289fecaa1af3f4944a7ac6e1c187d0700e32716c2a4c76d6bad7ffd255d72" +checksum = "cd34f5785805b134a7f7a739140cee3af03e36022639348952024b136a19790d" dependencies = [ "dyn-clone", "egui", @@ -1092,9 +1035,9 @@ dependencies = [ [[package]] name = "egui_glow" -version = "0.31.1" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "910906e3f042ea6d2378ec12a6fd07698e14ddae68aed2d819ffe944a73aab9e" +checksum = "d44f3fd4fdc5f960c9e9ef7327c26647edc3141abf96102980647129d49358e6" dependencies = [ "ahash", "bytemuck", @@ -1116,11 +1059,12 @@ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "emath" -version = "0.31.1" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e4cadcff7a5353ba72b7fea76bf2122b5ebdbc68e8155aa56dfdea90083fe1b" +checksum = "45f057b141e7e46340c321400be74b793543b1b213036f0f989c35d35957c32e" dependencies = [ "bytemuck", + "serde", ] [[package]] @@ -1136,7 +1080,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9" dependencies = [ "enum-map-derive", - "serde", ] [[package]] @@ -1172,10 +1115,21 @@ dependencies = [ ] [[package]] -name = "epaint" -version = "0.31.1" +name = "enumn" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fcc0f5a7c613afd2dee5e4b30c3e6acafb8ad6f0edb06068811f708a67c562" +checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "epaint" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94cca02195f0552c17cabdc02f39aa9ab6fbd815dac60ab1cd3d5b0aa6f9551c" dependencies = [ "ab_glyph", "ahash", @@ -1187,13 +1141,14 @@ dependencies = [ "nohash-hasher", "parking_lot", "profiling", + "serde", ] [[package]] name = "epaint_default_fonts" -version = "0.31.1" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7e7a64c02cf7a5b51e745a9e45f60660a286f151c238b9d397b3e923f5082f" +checksum = "e8495e11ed527dff39663b8c36b6c2b2799d7e4287fb90556e455d72eca0b4d3" [[package]] name = "equator" @@ -1376,12 +1331,6 @@ dependencies = [ "syn", ] -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - [[package]] name = "futures-task" version = "0.3.31" @@ -1395,26 +1344,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-core", - "futures-io", "futures-macro", - "futures-sink", "futures-task", - "memchr", "pin-project-lite", "pin-utils", "slab", ] -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - [[package]] name = "gethostname" version = "0.4.3" @@ -1547,45 +1483,6 @@ dependencies = [ "gl_generator", ] -[[package]] -name = "gpu-alloc" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" -dependencies = [ - "bitflags 2.9.1", - "gpu-alloc-types", -] - -[[package]] -name = "gpu-alloc-types" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" -dependencies = [ - "bitflags 2.9.1", -] - -[[package]] -name = "gpu-descriptor" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" -dependencies = [ - "bitflags 2.9.1", - "gpu-descriptor-types", - "hashbrown", -] - -[[package]] -name = "gpu-descriptor-types" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" -dependencies = [ - "bitflags 2.9.1", -] - [[package]] name = "half" version = "2.6.0" @@ -1594,6 +1491,7 @@ checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" dependencies = [ "cfg-if", "crunchy", + "num-traits", ] [[package]] @@ -1641,7 +1539,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.61.2", + "windows-core", ] [[package]] @@ -1799,15 +1697,6 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408" -[[package]] -name = "immutable-chunkmap" -version = "2.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f97096f508d54f8f8ab8957862eee2ccd628847b6217af1a335e1c44dee578" -dependencies = [ - "arrayvec", -] - [[package]] name = "indexmap" version = "2.10.0" @@ -1892,17 +1781,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "khronos-egl" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" -dependencies = [ - "libc", - "libloading", - "pkg-config", -] - [[package]] name = "khronos_api" version = "3.1.0" @@ -1941,6 +1819,12 @@ dependencies = [ "windows-targets 0.53.2", ] +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + [[package]] name = "libredox" version = "0.1.4" @@ -2001,15 +1885,6 @@ dependencies = [ "imgref", ] -[[package]] -name = "malloc_buf" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -dependencies = [ - "libc", -] - [[package]] name = "maybe-rayon" version = "0.1.1" @@ -2044,21 +1919,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "metal" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f569fb946490b5743ad69813cb19629130ce9374034abe31614a36402d18f99e" -dependencies = [ - "bitflags 2.9.1", - "block", - "core-graphics-types", - "foreign-types", - "log", - "objc", - "paste", -] - [[package]] name = "mime" version = "0.3.17" @@ -2095,24 +1955,26 @@ dependencies = [ [[package]] name = "naga" -version = "24.0.0" +version = "25.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e380993072e52eef724eddfcde0ed013b0c023c3f0417336ed041aa9f076994e" +checksum = "2b977c445f26e49757f9aca3631c3b8b836942cb278d69a92e7b80d3b24da632" dependencies = [ "arrayvec", "bit-set", "bitflags 2.9.1", "cfg_aliases", "codespan-reporting", + "half", + "hashbrown", "hexf-parse", "indexmap", "log", + "num-traits", + "once_cell", "rustc-hash 1.1.0", - "spirv", "strum", - "termcolor", "thiserror 2.0.12", - "unicode-xid", + "unicode-ident", ] [[package]] @@ -2124,7 +1986,7 @@ dependencies = [ "bitflags 2.9.1", "jni-sys", "log", - "ndk-sys 0.6.0+11769913", + "ndk-sys", "num_enum", "raw-window-handle", "thiserror 1.0.69", @@ -2136,15 +1998,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" -[[package]] -name = "ndk-sys" -version = "0.5.0+25.2.9519653" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" -dependencies = [ - "jni-sys", -] - [[package]] name = "ndk-sys" version = "0.6.0+11769913" @@ -2162,9 +2015,9 @@ checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "nix" -version = "0.29.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ "bitflags 2.9.1", "cfg-if", @@ -2243,6 +2096,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -2267,15 +2121,6 @@ dependencies = [ "syn", ] -[[package]] -name = "objc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" -dependencies = [ - "malloc_buf", -] - [[package]] name = "objc-sys" version = "0.3.5" @@ -2562,15 +2407,6 @@ dependencies = [ "libredox", ] -[[package]] -name = "ordered-float" -version = "4.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" -dependencies = [ - "num-traits", -] - [[package]] name = "ordered-stream" version = "0.2.0" @@ -2752,6 +2588,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "portable-atomic" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + [[package]] name = "potential_utf" version = "0.1.2" @@ -2809,9 +2651,9 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.12.2" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f86ba2052aebccc42cbbb3ed234b8b13ce76f75c3551a303cb2bcffcff12bb14" +checksum = "1e8bbe1a966bd2f362681a44f6edce3c2310ac21e4d5067a6e7ec396297a6ea0" dependencies = [ "bitflags 2.9.1", "memchr", @@ -2835,9 +2677,9 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quick-xml" -version = "0.30.0" +version = "0.36.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956" +checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" dependencies = [ "memchr", "serde", @@ -3139,17 +2981,6 @@ dependencies = [ "serde", ] -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - [[package]] name = "shlex" version = "1.3.0" @@ -3271,15 +3102,6 @@ dependencies = [ "walkdir", ] -[[package]] -name = "spirv" -version = "0.3.0+sdk-1.3.268.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" -dependencies = [ - "bitflags 2.9.1", -] - [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -3549,12 +3371,6 @@ dependencies = [ "rustc-hash 2.1.1", ] -[[package]] -name = "typenum" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" - [[package]] name = "uds_windows" version = "1.1.0" @@ -3590,12 +3406,6 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - [[package]] name = "url" version = "2.5.4" @@ -3896,23 +3706,24 @@ checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" [[package]] name = "wgpu" -version = "24.0.5" +version = "25.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b0b3436f0729f6cdf2e6e9201f3d39dc95813fad61d826c1ed07918b4539353" +checksum = "ec8fb398f119472be4d80bc3647339f56eb63b2a331f6a3d16e25d8144197dd9" dependencies = [ "arrayvec", "bitflags 2.9.1", "cfg_aliases", "document-features", + "hashbrown", "js-sys", "log", "parking_lot", + "portable-atomic", "profiling", "raw-window-handle", "smallvec", "static_assertions", "wasm-bindgen", - "wasm-bindgen-futures", "web-sys", "wgpu-core", "wgpu-hal", @@ -3921,79 +3732,72 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "24.0.5" +version = "25.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f0aa306497a238d169b9dc70659105b4a096859a34894544ca81719242e1499" +checksum = "f7b882196f8368511d613c6aeec80655160db6646aebddf8328879a88d54e500" dependencies = [ "arrayvec", + "bit-set", "bit-vec", "bitflags 2.9.1", "cfg_aliases", "document-features", + "hashbrown", "indexmap", "log", "naga", "once_cell", "parking_lot", + "portable-atomic", "profiling", "raw-window-handle", "rustc-hash 1.1.0", "smallvec", "thiserror 2.0.12", + "wgpu-core-deps-windows-linux-android", "wgpu-hal", "wgpu-types", ] [[package]] -name = "wgpu-hal" -version = "24.0.4" +name = "wgpu-core-deps-windows-linux-android" +version = "25.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f112f464674ca69f3533248508ee30cb84c67cf06c25ff6800685f5e0294e259" +checksum = "cba5fb5f7f9c98baa7c889d444f63ace25574833df56f5b817985f641af58e46" +dependencies = [ + "wgpu-hal", +] + +[[package]] +name = "wgpu-hal" +version = "25.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f968767fe4d3d33747bbd1473ccd55bf0f6451f55d733b5597e67b5deab4ad17" dependencies = [ - "android_system_properties", - "arrayvec", - "ash", "bitflags 2.9.1", - "bytemuck", "cfg_aliases", - "core-graphics-types", - "glow", - "glutin_wgl_sys", - "gpu-alloc", - "gpu-descriptor", - "js-sys", - "khronos-egl", - "libc", "libloading", "log", - "metal", "naga", - "ndk-sys 0.5.0+25.2.9519653", - "objc", - "once_cell", - "ordered-float", "parking_lot", - "profiling", + "portable-atomic", "raw-window-handle", "renderdoc-sys", - "rustc-hash 1.1.0", - "smallvec", "thiserror 2.0.12", - "wasm-bindgen", - "web-sys", "wgpu-types", - "windows", ] [[package]] name = "wgpu-types" -version = "24.0.0" +version = "25.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50ac044c0e76c03a0378e7786ac505d010a873665e2d51383dcff8dd227dc69c" +checksum = "2aa49460c2a8ee8edba3fca54325540d904dd85b2e086ada762767e17d06e8bc" dependencies = [ "bitflags 2.9.1", + "bytemuck", "js-sys", "log", + "thiserror 2.0.12", "web-sys", ] @@ -4030,25 +3834,24 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.58.0" +version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ - "windows-core 0.58.0", - "windows-targets 0.52.6", + "windows-collections", + "windows-core", + "windows-future", + "windows-link", + "windows-numerics", ] [[package]] -name = "windows-core" -version = "0.58.0" +name = "windows-collections" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" dependencies = [ - "windows-implement 0.58.0", - "windows-interface 0.58.0", - "windows-result 0.2.0", - "windows-strings 0.1.0", - "windows-targets 0.52.6", + "windows-core", ] [[package]] @@ -4057,22 +3860,22 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ - "windows-implement 0.60.0", - "windows-interface 0.59.1", + "windows-implement", + "windows-interface", "windows-link", - "windows-result 0.3.4", - "windows-strings 0.4.2", + "windows-result", + "windows-strings", ] [[package]] -name = "windows-implement" -version = "0.58.0" +name = "windows-future" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ - "proc-macro2", - "quote", - "syn", + "windows-core", + "windows-link", + "windows-threading", ] [[package]] @@ -4086,17 +3889,6 @@ dependencies = [ "syn", ] -[[package]] -name = "windows-interface" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "windows-interface" version = "0.59.1" @@ -4115,12 +3907,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] -name = "windows-result" +name = "windows-numerics" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" dependencies = [ - "windows-targets 0.52.6", + "windows-core", + "windows-link", ] [[package]] @@ -4132,16 +3925,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-strings" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" -dependencies = [ - "windows-result 0.2.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows-strings" version = "0.4.2" @@ -4249,6 +4032,15 @@ dependencies = [ "windows_x86_64_msvc 0.53.0", ] +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -4543,16 +4335,6 @@ version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b" -[[package]] -name = "xdg-home" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - [[package]] name = "xkbcommon-dl" version = "0.4.2" @@ -4604,13 +4386,12 @@ dependencies = [ [[package]] name = "zbus" -version = "4.4.0" +version = "5.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb97012beadd29e654708a0fdb4c84bc046f537aecfde2c3ee0a9e4b4d48c725" +checksum = "597f45e98bc7e6f0988276012797855613cd8269e23b5be62cc4e5d28b7e515d" dependencies = [ "async-broadcast", "async-executor", - "async-fs", "async-io", "async-lock", "async-process", @@ -4621,20 +4402,16 @@ dependencies = [ "enumflags2", "event-listener", "futures-core", - "futures-sink", - "futures-util", + "futures-lite", "hex", "nix", "ordered-stream", - "rand", "serde", "serde_repr", - "sha1", - "static_assertions", "tracing", "uds_windows", - "windows-sys 0.52.0", - "xdg-home", + "windows-sys 0.59.0", + "winnow", "zbus_macros", "zbus_names", "zvariant", @@ -4642,9 +4419,9 @@ dependencies = [ [[package]] name = "zbus-lockstep" -version = "0.4.4" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca2c5dceb099bddaade154055c926bb8ae507a18756ba1d8963fd7b51d8ed1d" +checksum = "29e96e38ded30eeab90b6ba88cb888d70aef4e7489b6cd212c5e5b5ec38045b6" dependencies = [ "zbus_xml", "zvariant", @@ -4652,9 +4429,9 @@ dependencies = [ [[package]] name = "zbus-lockstep-macros" -version = "0.4.4" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "709ab20fc57cb22af85be7b360239563209258430bccf38d8b979c5a2ae3ecce" +checksum = "dc6821851fa840b708b4cbbaf6241868cabc85a2dc22f426361b0292bfc0b836" dependencies = [ "proc-macro2", "quote", @@ -4666,35 +4443,38 @@ dependencies = [ [[package]] name = "zbus_macros" -version = "4.4.0" +version = "5.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267db9407081e90bbfa46d841d3cbc60f59c0351838c4bc65199ecd79ab1983e" +checksum = "e5c8e4e14dcdd9d97a98b189cd1220f30e8394ad271e8c987da84f73693862c2" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", "syn", + "zbus_names", + "zvariant", "zvariant_utils", ] [[package]] name = "zbus_names" -version = "3.0.0" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" +checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97" dependencies = [ "serde", "static_assertions", + "winnow", "zvariant", ] [[package]] name = "zbus_xml" -version = "4.0.0" +version = "5.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3f374552b954f6abb4bd6ce979e6c9b38fb9d0cd7cc68a7d796e70c9f3a233" +checksum = "589e9a02bfafb9754bb2340a9e3b38f389772684c63d9637e76b1870377bec29" dependencies = [ - "quick-xml 0.30.0", + "quick-xml 0.36.2", "serde", "static_assertions", "zbus_names", @@ -4801,22 +4581,23 @@ dependencies = [ [[package]] name = "zvariant" -version = "4.2.0" +version = "5.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2084290ab9a1c471c38fc524945837734fbf124487e105daec2bb57fd48c81fe" +checksum = "d91b3680bb339216abd84714172b5138a4edac677e641ef17e1d8cb1b3ca6e6f" dependencies = [ "endi", "enumflags2", "serde", - "static_assertions", + "winnow", "zvariant_derive", + "zvariant_utils", ] [[package]] name = "zvariant_derive" -version = "4.2.0" +version = "5.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73e2ba546bda683a90652bac4a279bc146adad1386f25379cf73200d2002c449" +checksum = "3a8c68501be459a8dbfffbe5d792acdd23b4959940fc87785fb013b32edbc208" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -4827,11 +4608,14 @@ dependencies = [ [[package]] name = "zvariant_utils" -version = "2.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340" +checksum = "e16edfee43e5d7b553b77872d99bc36afdda75c223ca7ad5e3fbecd82ca5fc34" dependencies = [ "proc-macro2", "quote", + "serde", + "static_assertions", "syn", + "winnow", ] diff --git a/Cargo.toml b/Cargo.toml index 5409042..2a47beb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,22 +4,22 @@ version = "0.1.0" edition = "2024" [dependencies] -eframe = "0.31.1" -egui = "0.31.1" +eframe = "0.32.0" +egui = { version = "0.32.0", features = ["serde"] } editor = { path = "./editor" } -egui_extras = { version = "0.31.1", features = [ +egui_extras = { version = "0.32.0", features = [ "chrono", "datepicker", "file", "image", ] } -egui_file = "0.22.1" +egui_file = "0.23.0" image = { version = "0.25.6", features = ["jpeg", "png"] } serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0.140" chrono = { version = "0.4.41", features = ["serde"] } thiserror = "2.0.12" -egui_commonmark = { version = "0.20.0", features = ["embedded_image"] } +egui_commonmark = { version = "0.21.1", features = ["embedded_image"] } walkdir = "2.5.0" uuid = { version = "1.17.0", features = ["v4"] } diff --git a/editor/Cargo.toml b/editor/Cargo.toml index 687d1b1..636badb 100644 --- a/editor/Cargo.toml +++ b/editor/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" description = "a basic text editor widget with line numbers" [dependencies] -egui = "0.31.1" +egui = "0.32.0" serde = "1" [lib] diff --git a/editor/src/lib.rs b/editor/src/lib.rs index b191250..eeeade4 100644 --- a/editor/src/lib.rs +++ b/editor/src/lib.rs @@ -1,7 +1,6 @@ - - -use egui::{text::LayoutJob, Color32}; +use egui::TextBuffer; use egui::widgets::text_edit::TextEditOutput; +use egui::{Color32, text::LayoutJob}; use std::hash::{Hash, Hasher}; @@ -137,9 +136,10 @@ impl CodeEditor { text.lines().count() } as isize; - let max_indent = total.to_string().len().max( - !self.numlines_only_natural as usize * self.numlines_shift.to_string().len(), - ); + let max_indent = total + .to_string() + .len() + .max(!self.numlines_only_natural as usize * self.numlines_shift.to_string().len()); let mut counter = (1..=total) .map(|i| { let num = i + self.numlines_shift; @@ -160,16 +160,12 @@ impl CodeEditor { let width = max_indent as f32 * self.fontsize * 0.5 - * !(total + self.numlines_shift <= 0 && self.numlines_only_natural) as u8 - as f32; + * !(total + self.numlines_shift <= 0 && self.numlines_only_natural) as u8 as f32; - let mut layouter = |ui: &egui::Ui, string: &str, _wrap_width: f32| { + let mut layouter = |ui: &egui::Ui, string: &dyn TextBuffer, _wrap_width: f32| { let layout_job = egui::text::LayoutJob::single_section( - string.to_string(), - egui::TextFormat::simple( - egui::FontId::monospace(self.fontsize), - Color32::WHITE, - ), + string.as_str().to_string(), // Convert TextBuffer to String + egui::TextFormat::simple(egui::FontId::monospace(self.fontsize), Color32::WHITE), ); ui.fonts(|f| f.layout_job(layout_job)) }; @@ -186,11 +182,7 @@ impl CodeEditor { } /// Show Code Editor - pub fn show( - &mut self, - ui: &mut egui::Ui, - text: &mut dyn egui::TextBuffer, - ) -> TextEditOutput { + pub fn show(&mut self, ui: &mut egui::Ui, text: &mut dyn egui::TextBuffer) -> TextEditOutput { let mut text_edit_output: Option = None; let code_editor = |ui: &mut egui::Ui| { ui.horizontal_top(|h| { diff --git a/project/assets/the prophet.png b/project/assets/the prophet.png new file mode 100644 index 0000000..f586eff Binary files /dev/null and b/project/assets/the prophet.png differ diff --git a/project/documents/09fb1e02-055b-4a02-b23e-5e5e9e0ca52d.json b/project/documents/09fb1e02-055b-4a02-b23e-5e5e9e0ca52d.json deleted file mode 100644 index 1eba827..0000000 --- a/project/documents/09fb1e02-055b-4a02-b23e-5e5e9e0ca52d.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "New Document", - "text": "# The effects of Whimsum dust:\nmore aggression, higher damage, higher rate of fire, lower accuracy" -} \ No newline at end of file diff --git a/project/notes/ee0fa255-9a71-44b1-9556-e7b3157f1f77.json b/project/notes/ee0fa255-9a71-44b1-9556-e7b3157f1f77.json deleted file mode 100644 index cd0118f..0000000 --- a/project/notes/ee0fa255-9a71-44b1-9556-e7b3157f1f77.json +++ /dev/null @@ -1 +0,0 @@ -{"name":"Note","content":"this is the note! gfjh gfdhgj fgfjhghfd iughuifghuifghuifghuifghuifdg"} \ No newline at end of file diff --git a/project/objects/0078bb24-2fb0-4ecb-b5cb-20d29c5f2f77.json b/project/objects/0078bb24-2fb0-4ecb-b5cb-20d29c5f2f77.json deleted file mode 100644 index f7a5ad4..0000000 --- a/project/objects/0078bb24-2fb0-4ecb-b5cb-20d29c5f2f77.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "id": "0078bb24-2fb0-4ecb-b5cb-20d29c5f2f77", - "template_id": "b5745688-3c1c-40de-bc3a-2a3e354dd19d", - "name": "The SPOONS!", - "fields": { - "description": { - "value": "full of smilers\n" - } - } -} \ No newline at end of file diff --git a/project/objects/20beeb2f-363c-49bf-9621-f156d7c7cdd7.json b/project/objects/20beeb2f-363c-49bf-9621-f156d7c7cdd7.json deleted file mode 100644 index 5f08197..0000000 --- a/project/objects/20beeb2f-363c-49bf-9621-f156d7c7cdd7.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "id": "20beeb2f-363c-49bf-9621-f156d7c7cdd7", - "template_id": "b5745688-3c1c-40de-bc3a-2a3e354dd19d", - "name": "the brewdog.", - "fields": { - "description": { - "value": "full of smilers\n" - } - } -} \ No newline at end of file diff --git a/project/objects/8d76fdcd-0c3e-41a9-abc4-66fe21c0cb73.json b/project/objects/8d76fdcd-0c3e-41a9-abc4-66fe21c0cb73.json new file mode 100644 index 0000000..4757219 --- /dev/null +++ b/project/objects/8d76fdcd-0c3e-41a9-abc4-66fe21c0cb73.json @@ -0,0 +1,23 @@ +{ + "id": "8d76fdcd-0c3e-41a9-abc4-66fe21c0cb73", + "template_id": "d1223e6b-ade0-405a-8c3b-657c743a21cc", + "name": "Prophet", + "fields": { + "Age": { + "value": "" + }, + "Appearance": { + "value": "" + }, + "Species": { + "value": "" + }, + "DOB": { + "value": "" + }, + "PFP": { + "value": "./project/assets/the prophet.png" + } + }, + "tags": [] +} \ No newline at end of file diff --git a/project/objects/bd13d252-3f19-4618-bb10-cc45e9f7d301.json b/project/objects/bd13d252-3f19-4618-bb10-cc45e9f7d301.json deleted file mode 100644 index 9d1850a..0000000 --- a/project/objects/bd13d252-3f19-4618-bb10-cc45e9f7d301.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "id": "bd13d252-3f19-4618-bb10-cc45e9f7d301", - "template_id": "c96f5e87-7517-44cc-a5ab-42ffd537801d", - "name": "Cast Iron Pan", - "fields": { - "durability": { - "value": "9999999" - }, - "Icon": { - "value": "" - }, - "description": { - "value": "An unburnt pan for bitchslapping, comes with a free punchcard." - } - } -} \ No newline at end of file diff --git a/project/templates/a24b3ab7-2572-4af4-8457-df26937fd773.json b/project/templates/a24b3ab7-2572-4af4-8457-df26937fd773.json deleted file mode 100644 index 74366b9..0000000 --- a/project/templates/a24b3ab7-2572-4af4-8457-df26937fd773.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "Character", - "id": "a24b3ab7-2572-4af4-8457-df26937fd773", - "description": "character", - "fields": [ - { - "name": "Portrait / Image", - "field_type": "Image", - "required": true, - "description": "image of character" - }, - { - "name": "Date of Birth", - "field_type": "Date", - "required": false, - "description": "date of birth" - }, - { - "name": "Age", - "field_type": "Number", - "required": false, - "description": "age" - }, - { - "name": "Appearance", - "field_type": "MultiLine", - "required": false, - "description": "character's appearance" - }, - { - "name": "Personality", - "field_type": "MultiLine", - "required": false, - "description": "character's personality" - } - ] -} \ No newline at end of file diff --git a/project/templates/b5745688-3c1c-40de-bc3a-2a3e354dd19d.json b/project/templates/b5745688-3c1c-40de-bc3a-2a3e354dd19d.json deleted file mode 100644 index 6a3b549..0000000 --- a/project/templates/b5745688-3c1c-40de-bc3a-2a3e354dd19d.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "Location", - "id": "b5745688-3c1c-40de-bc3a-2a3e354dd19d", - "description": "a place", - "fields": [ - { - "name": "description", - "field_type": "MultiLine", - "required": true, - "description": "what is it like?" - } - ] -} \ No newline at end of file diff --git a/project/templates/c96f5e87-7517-44cc-a5ab-42ffd537801d.json b/project/templates/c96f5e87-7517-44cc-a5ab-42ffd537801d.json deleted file mode 100644 index ebcd7bf..0000000 --- a/project/templates/c96f5e87-7517-44cc-a5ab-42ffd537801d.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "Item", - "id": "c96f5e87-7517-44cc-a5ab-42ffd537801d", - "description": "an in-game item", - "fields": [ - { - "name": "durability", - "field_type": "Number", - "required": false, - "description": "the item's durability" - }, - { - "name": "description", - "field_type": "MultiLine", - "required": true, - "description": "the item's description" - }, - { - "name": "Icon", - "field_type": "Image", - "required": false, - "description": "yes" - } - ] -} \ No newline at end of file diff --git a/project/templates/d1223e6b-ade0-405a-8c3b-657c743a21cc.json b/project/templates/d1223e6b-ade0-405a-8c3b-657c743a21cc.json new file mode 100644 index 0000000..c404cfe --- /dev/null +++ b/project/templates/d1223e6b-ade0-405a-8c3b-657c743a21cc.json @@ -0,0 +1,37 @@ +{ + "name": "Character", + "id": "d1223e6b-ade0-405a-8c3b-657c743a21cc", + "description": "desc", + "fields": [ + { + "name": "Appearance", + "field_type": "MultiLine", + "required": true, + "description": "app" + }, + { + "name": "Age", + "field_type": "Number", + "required": true, + "description": "age" + }, + { + "name": "DOB", + "field_type": "Date", + "required": false, + "description": "dob" + }, + { + "name": "PFP", + "field_type": "Image", + "required": true, + "description": "" + }, + { + "name": "Species", + "field_type": "Link", + "required": false, + "description": "" + } + ] +} \ No newline at end of file diff --git a/src/editors/asset_editor.rs b/src/editors/asset_editor.rs new file mode 100644 index 0000000..d6ce031 --- /dev/null +++ b/src/editors/asset_editor.rs @@ -0,0 +1,74 @@ +use egui::{TextEdit, vec2}; + +use crate::{PROJECT_FOLDER, util}; + +#[derive(Debug, Clone)] +pub struct Asset { + pub name: String, + pub old_name: String, + pub saved: bool, +} + +impl Asset { + pub fn open(name: String) -> Self { + Self { + old_name: name.clone(), + name, + saved: false, + } + } + + pub fn save(&mut self) { + let old_path = Self::path(&self.old_name); + let new_path = Self::path(&self.name); + + // move from src dir to name path + std::fs::rename(&old_path, &new_path).unwrap(); + self.saved = true; + self.old_name = self.name.clone(); + } + + pub fn path(name: &str) -> std::path::PathBuf { + PROJECT_FOLDER.join("assets").join(format!("{name}.png")) + } + + pub fn ui(&mut self, ui: &mut egui::Ui) { + ui.vertical(|ui| { + util::saved_status(ui, self.saved, &self.name, &self.name); + + if ui.input(|i| i.key_pressed(egui::Key::S) && i.modifiers.ctrl) + || ui.button("Save").clicked() + { + self.save(); + } + + ui.separator(); + + ui.horizontal(|ui| { + ui.strong("Filename:"); + if TextEdit::singleline(&mut self.name) + .desired_width(f32::INFINITY) + .frame(false) + .show(ui) + .response + .changed() + { + self.saved = false; + } + }); + + ui.separator(); + + if let Ok(bytes) = std::fs::read(Self::path(&self.name)) { + let image_source = egui::ImageSource::Bytes { + uri: std::borrow::Cow::Owned(self.name.clone()), + bytes: bytes.into(), + }; + ui.add( + egui::Image::new(image_source) + .max_size(vec2(ui.available_width(), f32::INFINITY)), + ); + } + }); + } +} diff --git a/src/editors/content_editor.rs b/src/editors/content_editor.rs new file mode 100644 index 0000000..9d9ffb2 --- /dev/null +++ b/src/editors/content_editor.rs @@ -0,0 +1,306 @@ +use egui::TextEdit; +use egui_commonmark::{CommonMarkCache, CommonMarkViewer}; +use serde::{self, Deserialize, Serialize}; + +use crate::{PROJECT_FOLDER, editors::tags::Tag, util}; + +pub struct MainEditor { + pub content: ContentSection, + pub show_editor: bool, + pub show_preview: bool, + preview_cache: CommonMarkCache, +} + +impl Clone for MainEditor { + fn clone(&self) -> Self { + Self { + content: self.content.clone(), + + show_editor: self.show_editor, + show_preview: self.show_preview, + preview_cache: CommonMarkCache::default(), + } + } +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct ContentSection { + #[serde(default)] + pub title: String, + + #[serde(default)] + pub id: String, + + #[serde(default)] + pub description: String, + + #[serde(default)] + pub tags: Vec, + + #[serde(default)] + pub content: String, + + // parent id + #[serde(default)] + pub parent: Option, + + #[serde(skip)] + pub saved: bool, +} + +impl ContentSection { + pub fn new() -> Self { + Self { + title: String::new(), + id: uuid::Uuid::new_v4().to_string(), + description: String::new(), + tags: Vec::new(), + content: String::new(), + parent: None, + saved: false, + } + } + + pub fn save(&mut self) -> Result<(), Box> { + let path = PROJECT_FOLDER + .join("documents") + .join(format!("{}.json", &self.id)); + + let content = serde_json::to_string_pretty(self)?; + std::fs::write(path, content)?; + self.saved = true; + Ok(()) + } + + pub fn load(id: &str) -> Result> { + let path = PROJECT_FOLDER.join("documents").join(format!("{id}.json")); + + let content = std::fs::read_to_string(&path)?; + let mut section: Self = serde_json::from_str(&content)?; + section.saved = true; + section.id = id.to_string(); + Ok(section) + } + + pub fn create_child(&self) -> Self { + let mut child = Self::new(); + child.title = format!("{} (Child)", self.title); + child.parent = Some(self.id.clone()); + child + } +} + +impl MainEditor { + pub fn new() -> Self { + Self { + content: ContentSection::new(), + show_editor: false, // Start with editor hidden + show_preview: true, + preview_cache: CommonMarkCache::default(), + } + } + + pub fn open(content: ContentSection) -> Self { + Self { + content, + show_editor: true, + show_preview: true, + preview_cache: CommonMarkCache::default(), + } + } + + pub fn ui(&mut self, ctx: &egui::Context) { + // Show the editor window if enabled + let mut show = self.show_editor; + if show { + egui::Window::new("Markdown Editor") + .resizable(true) + .default_width(1000.0) + .default_height(800.0) + .open(&mut show) + .show(ctx, |ui| { + ui.vertical(|ui| { + // check for Ctrl+S to save + if ui.input(|i| i.key_pressed(egui::Key::S) && i.modifiers.ctrl) { + if let Err(e) = self.content.save() { + eprintln!("Failed to save: {e}"); + } + } + + // display save state + util::saved_status( + ui, + self.content.saved, + &self.content.id, + &self.content.title, + ); + + // Save/Cancel buttons + ui.horizontal(|ui| { + // save button + if ui.button("Save").clicked() { + if let Err(e) = self.content.save() { + eprintln!("Failed to save: {e}"); + } + } + + // create copy button + if ui.button("Create Copy").clicked() { + let mut copy = self.clone(); + copy.content.id = uuid::Uuid::new_v4().to_string(); + copy.content.title = format!("{} (Copy)", self.content.title); + copy.content.save().unwrap(); + } + + // delete button + if ui.button("Delete").clicked() { + std::fs::remove_file( + PROJECT_FOLDER + .join("documents") + .join(format!("{}.json", self.content.id)), + ) + .unwrap(); + + *self = Self::new(); + } + + // revert changes button + if ui.button("Revert changes").clicked() { + self.content = ContentSection::load(&self.content.id).unwrap(); + } + + // preview toggle + ui.checkbox(&mut self.show_preview, "Preview"); + }); + }); + + ui.separator(); + + // Name and description grid + egui::Grid::new("top_grid") + .striped(true) + .num_columns(2) + .show(ui, |ui| { + ui.strong("Name"); + if ui + .add( + TextEdit::singleline(&mut self.content.title) + .desired_width(f32::INFINITY) + .frame(false), + ) + .changed() + { + self.content.saved = false; + } + ui.end_row(); + + ui.strong("Description"); + if ui + .add( + TextEdit::singleline(&mut self.content.description) + .desired_width(f32::INFINITY) + .frame(false), + ) + .changed() + { + self.content.saved = false; + } + ui.end_row(); + + ui.strong("Tags"); + Tag::selector_ui( + &mut self.content.tags, + ui, + Some(&mut self.content.saved), + ); + ui.end_row(); + }); + + ui.separator(); + + if self.show_preview { + self.preview_ui(ui); + } + + self.editor_ui(ui); + }); + } + + self.show_editor = show; + } + + fn preview_ui(&mut self, ui: &mut egui::Ui) { + // Preview area + egui::SidePanel::right("preview_panel") + .resizable(true) + .default_width(ui.available_width() / 2.0) + .show_inside(ui, |ui| { + // Preview area with centered content and max width + egui::ScrollArea::both() + .auto_shrink([false, false]) + .id_salt("preview_scroll") + .show(ui, |ui| { + let max_width = 600; + let available_width = ui.available_width(); + let content_width = (max_width as f32).min(available_width); + let padding = (available_width - content_width) / 2.0; + + ui.horizontal(|ui| { + ui.add_space(padding); + ui.vertical(|ui| { + ui.set_width(content_width); + ui.add_space(15.0); + + ui.set_min_width(max_width as f32); + + CommonMarkViewer::new() + .default_width(Some(max_width)) + .max_image_width(Some(512)) + .show(ui, &mut self.preview_cache, &self.content.content); + }); + }); + }); + }); + } + + fn editor_ui(&mut self, ui: &mut egui::Ui) { + egui::ScrollArea::both() + .auto_shrink([false, false]) + .id_salt("editor_scroll") + .show(ui, |ui| { + let max_width = 600; + let available_width = ui.available_width(); + let content_width = (max_width as f32).min(available_width); + let padding = (available_width - content_width).max(30.0) / 2.0; + + ui.horizontal(|ui| { + ui.add_space(padding); + ui.vertical(|ui| { + ui.set_width(content_width); + ui.add_space(15.0); + + ui.set_min_width(max_width as f32); + + let text_edit = TextEdit::multiline(&mut self.content.content) + .id_source("MainEditor_editor") + .font(egui::TextStyle::Monospace) + .interactive(true) + .frame(false) + .lock_focus(true) + .hint_text("Type here...") + .desired_width(max_width as f32); + + if ui + .add_sized( + egui::vec2(max_width as f32 - 30.0, ui.available_height()), + text_edit, + ) + .changed() + { + self.content.saved = false; + } + }); + }); + }); + } +} diff --git a/src/editors/mod.rs b/src/editors/mod.rs new file mode 100644 index 0000000..49d0d61 --- /dev/null +++ b/src/editors/mod.rs @@ -0,0 +1,6 @@ +pub mod asset_editor; +pub mod content_editor; +pub mod note_editor; +pub mod object_editor; +pub mod tags; +pub mod template_editor; diff --git a/src/editors/note_editor.rs b/src/editors/note_editor.rs new file mode 100644 index 0000000..7232b68 --- /dev/null +++ b/src/editors/note_editor.rs @@ -0,0 +1,152 @@ +use std::fs; + +use egui::TextEdit; +use serde::{Deserialize, Serialize}; + +use crate::{PROJECT_FOLDER, editors::tags::Tag, util}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct Note { + pub name: String, + #[serde(default)] + pub content: String, + #[serde(default)] + pub subject: String, + + #[serde(default)] + pub tags: Vec, + + #[serde(skip)] + pub id: String, + + #[serde(skip)] + pub saved: bool, +} + +impl Default for Note { + fn default() -> Self { + Self { + id: uuid::Uuid::new_v4().to_string(), + name: "New Note".to_string(), + subject: "".to_string(), + content: "".to_string(), + tags: Vec::new(), + saved: false, + } + } +} + +impl Note { + pub fn new() -> Self { + Self { + id: uuid::Uuid::new_v4().to_string(), + name: "New Note".to_string(), + subject: "".to_string(), + content: "".to_string(), + tags: Vec::new(), + saved: false, + } + } + + pub fn save(&mut self) -> std::io::Result<()> { + let id = &self.id; + let path = PROJECT_FOLDER.join("notes").join(format!("{id}.json")); + fs::write(path, serde_json::to_string(&self)?)?; + self.saved = true; + Ok(()) + } + + pub fn load(id: &str) -> std::io::Result { + let path = PROJECT_FOLDER.join("notes").join(format!("{id}.json")); + let content = fs::read_to_string(path)?; + let mut note: Note = serde_json::from_str(&content)?; + note.id = id.to_string(); + note.saved = true; + Ok(note) + } + + pub fn ui(&mut self, ui: &mut egui::Ui) { + if ui.input(|i| i.key_pressed(egui::Key::S) && i.modifiers.ctrl) { + if let Err(e) = self.save() { + eprintln!("Failed to save: {e}"); + } + } + + util::saved_status(ui, self.saved, &self.id, &self.name); + + if ui.button("Save").clicked() { + if let Err(e) = self.save() { + eprintln!("Failed to save: {e}"); + } + } + + let id = ui.make_persistent_id("note_name"); + egui::collapsing_header::CollapsingState::load_with_default_open(ui.ctx(), id, true) + .show_header(ui, |ui| { + ui.strong("Name"); + }) + .body(|ui| { + ui.separator(); + if TextEdit::singleline(&mut self.name) + .desired_width(f32::INFINITY) + .frame(false) + .show(ui) + .response + .changed() + { + self.saved = false; + } + ui.separator(); + }); + + let id = ui.make_persistent_id("note_tags"); + egui::collapsing_header::CollapsingState::load_with_default_open(ui.ctx(), id, true) + .show_header(ui, |ui| { + ui.strong("Tags"); + }) + .body(|ui| { + ui.separator(); + Tag::selector_ui(&mut self.tags, ui, Some(&mut self.saved)); + ui.separator(); + }); + + let id = ui.make_persistent_id("note_subject"); + egui::collapsing_header::CollapsingState::load_with_default_open(ui.ctx(), id, true) + .show_header(ui, |ui| { + ui.strong("Subject"); + }) + .body(|ui| { + ui.separator(); + if TextEdit::singleline(&mut self.subject) + .desired_width(f32::INFINITY) + .frame(false) + .show(ui) + .response + .changed() + { + self.saved = false; + } + ui.separator(); + }); + + let id = ui.make_persistent_id("note_content"); + egui::collapsing_header::CollapsingState::load_with_default_open(ui.ctx(), id, true) + .show_header(ui, |ui| { + ui.strong("Content"); + }) + .body(|ui| { + ui.separator(); + if TextEdit::multiline(&mut self.content) + .desired_width(f32::INFINITY) + .desired_rows(5) + .frame(false) + .show(ui) + .response + .changed() + { + self.saved = false; + } + ui.separator(); + }); + } +} diff --git a/src/editors/object_editor.rs b/src/editors/object_editor.rs new file mode 100644 index 0000000..ef9343c --- /dev/null +++ b/src/editors/object_editor.rs @@ -0,0 +1,364 @@ +use core::f32; +use std::path::Path; + +use chrono::NaiveDate; +use egui::{CollapsingHeader, Response, RichText, Sense, TextEdit, Ui, UiBuilder, vec2}; +use serde::{Deserialize, Serialize}; + +use crate::{ + PROJECT_FOLDER, RightPanelContent, + editors::{ + tags::Tag, + template_editor::{FieldDefinition, FieldType, FieldValue, Template}, + }, + util, +}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct ObjectInstance { + // template info + pub id: String, + pub template_id: String, + + // instance info + pub name: String, + pub fields: std::collections::HashMap, + + #[serde(default)] + pub tags: Vec, + + #[serde(skip)] + pub saved: bool, + + #[serde(skip)] + pub dialog: Option, +} + +impl Clone for ObjectInstance { + fn clone(&self) -> Self { + Self { + id: self.id.clone(), + template_id: self.template_id.clone(), + name: self.name.clone(), + fields: self.fields.clone(), + tags: self.tags.clone(), + saved: self.saved, + dialog: None, + } + } +} + +impl Default for ObjectInstance { + fn default() -> Self { + Self { + id: uuid::Uuid::new_v4().to_string(), + template_id: "new_template_instance".to_string(), + name: "new_object".to_string(), + fields: std::collections::HashMap::new(), + tags: Vec::new(), + saved: false, + dialog: None, + } + } +} + +impl ObjectInstance { + pub fn new(template: &Template) -> Self { + let mut fields = std::collections::HashMap::new(); + + for field in &template.fields { + fields.insert(field.name.clone(), FieldValue::default()); + } + + Self { + id: uuid::Uuid::new_v4().to_string(), + template_id: template.id.clone(), + name: "new_object".to_string(), + fields, + tags: Vec::new(), + saved: false, + dialog: None, + } + } + + pub fn save(&mut self) -> Result<(), Box> { + let path = PROJECT_FOLDER + .join("objects") + .join(format!("{}.json", &self.id)); + + let content = serde_json::to_string_pretty(self)?; + std::fs::write(&path, content)?; + self.saved = true; + Ok(()) + } + + pub fn load(id: &str) -> Result> { + let path = PROJECT_FOLDER.join("objects").join(format!("{id}.json")); + + let content = std::fs::read_to_string(&path)?; + let mut instance: ObjectInstance = serde_json::from_str(&content)?; + instance.saved = true; + Ok(instance) + } + + pub fn ui( + &mut self, + ui: &mut Ui, + template: &Template, + right_panel: &mut Option, + objects: &mut Vec, + ) { + let _ = right_panel; + if ui.input(|i| i.key_pressed(egui::Key::S) && i.modifiers.ctrl) { + if let Err(e) = self.save() { + eprintln!("Failed to save: {e}"); + } + } + + ui.vertical(|ui| { + // Show save status and button + + util::saved_status(ui, self.saved, &self.id, &self.name); + + ui.horizontal(|ui| { + if ui.button("Save").clicked() { + if let Err(e) = self.save() { + eprintln!("Failed to save: {e}"); + } + } + + if ui.button("Create Copy").clicked() { + let mut copy = self.clone(); + copy.id = uuid::Uuid::new_v4().to_string(); + copy.dialog = None; + copy.name = format!("{} (Copy)", self.name); + copy.save().unwrap(); + + *right_panel = Some(RightPanelContent::Object(Box::new(copy))); + } + + if ui.button("Delete").clicked() { + std::fs::remove_file( + PROJECT_FOLDER + .join("objects") + .join(format!("{}.json", self.id)), + ) + .unwrap(); + + *right_panel = Some(RightPanelContent::None); + } + }); + + ui.separator(); + + egui::ScrollArea::vertical().show(ui, |ui| { + // Render each field + + // allow name to be edited + CollapsingHeader::new("Name") + .default_open(true) + .show(ui, |ui| { + ui.separator(); + let _ = TextEdit::singleline(&mut self.name) + .desired_width(f32::INFINITY) + .frame(false) + .show(ui) + .response; + ui.separator(); + }); + + CollapsingHeader::new("Tags") + .default_open(true) + .show(ui, |ui| { + ui.separator(); + Tag::selector_ui(&mut self.tags, ui, Some(&mut self.saved)); + ui.separator(); + }); + + for field_def in &template.fields { + if let Some(field_value) = self.fields.get_mut(&field_def.name) { + let id = ui.make_persistent_id(format!("field_{}", field_def.name)); + egui::collapsing_header::CollapsingState::load_with_default_open( + ui.ctx(), + id, + true, + ) + .show_header(ui, |ui| { + ui.strong(&field_def.name); + }) + .body(|ui| { + if let Some(desc) = &field_def.description { + ui.label(RichText::new(desc).italics().weak()); + } + + ui.separator(); + + Self::render_field( + field_def, + field_value, + ui, + &mut self.saved, + objects, + ); + + ui.separator(); + }); + } + } + }); + }); + } + + fn render_field( + field_def: &FieldDefinition, + field_value: &mut FieldValue, + ui: &mut egui::Ui, + saved: &mut bool, + objects: &mut Vec, + ) { + match field_def.field_type { + FieldType::SingleLine => { + if TextEdit::singleline(&mut field_value.value) + .desired_width(f32::INFINITY) + .frame(false) + .show(ui) + .response + .changed() + { + field_value.modified = true; + *saved = false; + } + } + FieldType::MultiLine => { + if TextEdit::multiline(&mut field_value.value) + .desired_width(f32::INFINITY) + .desired_rows(5) + .frame(false) + .show(ui) + .response + .changed() + { + field_value.modified = true; + *saved = false; + } + } + FieldType::Date => { + let date_str = &field_value.value; + let mut date = NaiveDate::parse_from_str(date_str, "%Y-%m-%d") + .unwrap_or_else(|_| chrono::Local::now().date_naive()); + + let response = ui.add(egui_extras::DatePickerButton::new(&mut date)); + + if response.changed() { + field_value.value = date.format("%Y-%m-%d").to_string(); + field_value.modified = true; + *saved = false; + } + } + FieldType::Number => { + let mut num = field_value.value.parse::().unwrap_or(0.0); + let response = ui.add(egui::DragValue::new(&mut num).speed(0.1)); + + if response.changed() { + field_value.value = num.to_string(); + field_value.modified = true; + *saved = false; + } + } + FieldType::Image => { + ui.scope_builder(UiBuilder::new().sense(Sense::HOVER), |ui| { + let id = ui.make_persistent_id("is_hovered"); + let should_show = field_value.value.is_empty() + || ui.response().hovered() + || ui.memory(|mem| mem.data.get_temp(id).unwrap_or(false)); + + // Simple path input for now + if should_show { + let response = TextEdit::singleline(&mut field_value.value) + .hint_text("Path to image") + .desired_width(f32::INFINITY) + .frame(false) + .show(ui) + .response; + + if response.changed() { + field_value.modified = true; + *saved = false; + } + + ui.memory_mut(|mem| { + *mem.data.get_temp_mut_or_insert_with(id, || true) = response.hovered(); + }); + } + + // If we have a valid path, try to display a preview + if !field_value.value.is_empty() { + if let Ok(bytes) = std::fs::read(&field_value.value) { + let path = PROJECT_FOLDER.join(&field_value.value); + + let image_source = egui::ImageSource::Bytes { + uri: std::borrow::Cow::Owned(path.to_str().unwrap().to_string()), + bytes: bytes.into(), + }; + ui.add( + egui::Image::new(image_source).max_size(vec2(256.0, f32::INFINITY)), + ); + } + } + }); + } + FieldType::Link => ObjectInstance::selector_ui(field_value, objects, ui, saved), + FieldType::Links => { + if ui.text_edit_singleline(&mut field_value.value).changed() { + field_value.modified = true; + *saved = false; + } + } + }; + } + + fn selector_ui( + field_value: &mut FieldValue, + objects: &mut Vec, + ui: &mut egui::Ui, + saved: &mut bool, + ) { + if !field_value.value.is_empty() { + if let Ok(object) = ObjectInstance::load(&field_value.value) { + ui.strong(&object.name); + } + } + + ui.horizontal(|ui| { + let id = ui.make_persistent_id("new_object"); + + let ctx = ui.ctx(); + let mut object_selection: usize = + ctx.memory_mut(|mem| *mem.data.get_temp_mut_or_default::(id)); + + if objects.is_empty() { + ui.label("No objects available"); + } else { + egui::ComboBox::from_id_salt(id) + .selected_text(&objects[object_selection].name) + .show_ui(ui, |ui| { + for (i, obj) in objects.iter().enumerate() { + ui.selectable_value(&mut object_selection, i, &obj.name); + } + }); + } + + if ui.button("Set").clicked() && object_selection < objects.len() { + field_value.value = objects[object_selection].id.clone(); + field_value.modified = true; + *saved = false; + } + + if ui.button("Remove").clicked() { + field_value.value.clear(); + field_value.modified = true; + *saved = false; + } + }); + } +} diff --git a/src/editors/tags.rs b/src/editors/tags.rs new file mode 100644 index 0000000..5606e7a --- /dev/null +++ b/src/editors/tags.rs @@ -0,0 +1,244 @@ +use egui::{Response, RichText, TextEdit, UiBuilder}; +use serde::{Deserialize, Serialize}; + +use crate::{PROJECT_FOLDER, util}; + +#[derive(Serialize, Deserialize)] +pub struct Tag { + pub id: String, + pub name: String, + pub description: String, + pub color: egui::Color32, + + #[serde(skip)] + pub saved: bool, + + #[serde(skip)] + pub error: Option, +} + +impl Default for Tag { + fn default() -> Self { + Self { + id: uuid::Uuid::new_v4().to_string(), + name: String::new(), + description: String::new(), + color: egui::Color32::from_rgb(20, 20, 20), + saved: false, + error: None, + } + } +} + +impl Clone for Tag { + fn clone(&self) -> Self { + Self { + id: self.id.clone(), + name: self.name.clone(), + description: self.description.clone(), + color: self.color, + saved: self.saved, + error: None, + } + } +} + +impl Tag { + pub fn display_ui(&mut self, ui: &mut egui::Ui) -> bool { + let mut remove = false; + + egui::Frame::new() + .shadow(egui::Shadow { + offset: [2, 2], + blur: 16, + spread: 0, + color: egui::Color32::from_black_alpha(180), + }) + .stroke(egui::Stroke::new(2.0, self.color)) + .corner_radius(4.0) + .show(ui, |ui| { + ui.horizontal(|ui| { + if ui.add(egui::Button::new("").frame(false)).clicked() { + remove = true; + } + ui.strong(&self.name); + }); + }); + + remove + } + + pub fn list_ui(&mut self, ui: &mut egui::Ui) -> Response { + ui.add( + egui::Button::new(RichText::new(self.name.clone()).strong()) + .frame(false) + .stroke(egui::Stroke::new(2.0, self.color)) + .corner_radius(4.0), + ) + } + + pub fn ui(&mut self, ui: &mut egui::Ui) { + util::saved_status(ui, self.saved, &self.id, &self.name); + + if let Some(error) = &mut self.error { + error.show(ui); + } + + if ui.input(|i| i.key_pressed(egui::Key::S) && i.modifiers.ctrl) { + if let Err(e) = self.save() { + self.error = Some(util::Error::new(format!("Failed to save tag: {e}"))); + } + } + + egui::Grid::new("tag_grid") + .striped(true) + .num_columns(2) + .show(ui, |ui| { + ui.strong("Name"); + if ui + .add( + TextEdit::singleline(&mut self.name) + .desired_width(f32::INFINITY) + .frame(false), + ) + .changed() + { + self.saved = false; + } + ui.end_row(); + + ui.strong("Description"); + if ui + .add( + TextEdit::singleline(&mut self.description) + .desired_width(f32::INFINITY) + .frame(false), + ) + .changed() + { + self.saved = false; + } + ui.end_row(); + + ui.strong("Color"); + if ui.color_edit_button_srgba(&mut self.color).changed() { + self.saved = false; + } + ui.end_row(); + }); + } + + pub fn selector_ui(tag_ids: &mut Vec, ui: &mut egui::Ui, saved: Option<&mut bool>) { + // remove duplicate tag ids + tag_ids.sort(); + tag_ids.dedup(); + + let mut remove: Vec = Vec::new(); + let mut modified = false; + let id = ui.make_persistent_id("new_tag"); + let available_tags = Self::load_all(); + + ui.horizontal(|ui| { + let ctx = ui.ctx(); + let mut tag_selection: usize = + ctx.memory_mut(|mem| *mem.data.get_temp_mut_or_default::(id)); + + if available_tags.is_empty() { + ui.label("No tags available"); + } else { + egui::ComboBox::from_id_salt(id) + .selected_text(&available_tags[tag_selection].name) + .show_ui(ui, |ui| { + for (i, tag) in available_tags.iter().enumerate() { + if ui + .add( + egui::Button::new(RichText::new(tag.name.clone()).strong()) + .frame(false) + .stroke(egui::Stroke::new(2.0, tag.color)) + .corner_radius(4.0), + ) + .clicked() + { + tag_selection = i; + } + } + }); + } + + if ui.button("Add").clicked() && tag_selection < available_tags.len() { + tag_ids.push(available_tags[tag_selection].id.clone()); + tag_selection = 0; + modified = true; + } + + let ctx = ui.ctx(); + ctx.memory_mut(|mem| { + *mem.data.get_temp_mut_or_default::(id) = tag_selection; + }); + + for (i, tag_id) in tag_ids.iter().enumerate() { + if let Ok(mut tag) = Self::load(tag_id) { + if tag.display_ui(ui) { + remove.push(i) + } + } else { + // if the tag doesn't exist (AKA it's been deleted) + remove.push(i) + } + } + + if !remove.is_empty() { + modified = true; + for i in remove { + tag_ids.remove(i); + } + } + + if let Some(saved) = saved { + if modified { + *saved = false; + } + } + }); + } + + pub fn load(id: &str) -> Result> { + let path = PROJECT_FOLDER.join("tags").join(format!("{id}.json")); + Ok(serde_json::from_str(&std::fs::read_to_string(path)?)?) + } + + pub fn save(&mut self) -> Result<(), Box> { + if self.name.is_empty() { + self.error = Some(util::Error::new("Tag name cannot be empty".to_string())); + return Ok(()); + } + + self.error = None; + + let path = PROJECT_FOLDER + .join("tags") + .join(format!("{}.json", &self.id)); + let content = serde_json::to_string_pretty(self)?; + std::fs::write(path, content)?; + self.saved = true; + Ok(()) + } + + pub fn load_all() -> Vec { + let mut tags = Vec::new(); + + // scan tags folder. load tag json files + let tags_folder = PROJECT_FOLDER.join("tags"); + if tags_folder.exists() { + for entry in std::fs::read_dir(tags_folder).unwrap() { + let path = entry.unwrap().path(); + if path.is_file() && path.extension().unwrap() == "json" { + let tag = + serde_json::from_str(&std::fs::read_to_string(path).unwrap()).unwrap(); + tags.push(tag); + } + } + } + tags + } +} diff --git a/src/template.rs b/src/editors/template_editor.rs similarity index 75% rename from src/template.rs rename to src/editors/template_editor.rs index 6a7861e..eacfc89 100644 --- a/src/template.rs +++ b/src/editors/template_editor.rs @@ -1,9 +1,13 @@ use core::fmt; -use egui::{RichText, ScrollArea}; +use egui::ScrollArea; use serde::{Deserialize, Serialize}; -use crate::{PROJECT_FOLDER, RightPanelContent, error::Error, object::ObjectInstance}; +use crate::{ + PROJECT_FOLDER, RightPanelContent, + editors::object_editor::ObjectInstance, + util::{self, Error}, +}; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub enum FieldType { @@ -12,6 +16,28 @@ pub enum FieldType { MultiLine, Date, Number, + Link, + Links, +} + +impl Default for FieldType { + fn default() -> Self { + Self::SingleLine + } +} + +impl FieldType { + fn types() -> Vec { + vec![ + FieldType::Image, + FieldType::SingleLine, + FieldType::MultiLine, + FieldType::Date, + FieldType::Number, + FieldType::Link, + FieldType::Links, + ] + } } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -35,6 +61,18 @@ pub struct Template { #[serde(skip)] pub error: Option, + + #[serde(skip)] + pub new_field_name: String, + + #[serde(skip)] + pub new_field_type: FieldType, + + #[serde(skip)] + pub new_field_required: bool, + + #[serde(skip)] + pub new_field_description: String, } impl fmt::Debug for Template { @@ -45,6 +83,10 @@ impl fmt::Debug for Template { .field("description", &self.description) .field("fields", &self.fields) .field("saved", &self.saved) + .field("new_field_name", &self.new_field_name) + .field("new_field_type", &self.new_field_type) + .field("new_field_required", &self.new_field_required) + .field("new_field_description", &self.new_field_description) .finish() } } @@ -58,6 +100,11 @@ impl Clone for Template { fields: self.fields.clone(), saved: self.saved, error: None, + + new_field_name: "".to_string(), + new_field_type: FieldType::default(), + new_field_required: false, + new_field_description: "".to_string(), } } } @@ -71,6 +118,11 @@ impl Default for Template { fields: Vec::new(), saved: false, error: None, + + new_field_name: "".to_string(), + new_field_type: FieldType::default(), + new_field_required: false, + new_field_description: "".to_string(), } } } @@ -96,15 +148,7 @@ impl Template { Ok(()) } - pub fn ui( - &mut self, - ui: &mut egui::Ui, - new_instance: &mut Option, - new_field_name: &mut String, - new_field_type: &mut FieldType, - new_field_required: &mut bool, - new_field_description: &mut String, - ) { + pub fn ui(&mut self, ui: &mut egui::Ui, new_instance: &mut Option) { if let Some(error) = &mut self.error { error.show(ui); } @@ -117,16 +161,17 @@ impl Template { ScrollArea::vertical().show(ui, |ui| { ui.vertical(|ui| { - ui.group(|ui| { - ui.horizontal(|ui| { - if self.saved { - ui.label(RichText::new("✓ Saved").color(egui::Color32::GREEN)); - } else { - ui.label(RichText::new("* Unsaved").color(egui::Color32::YELLOW)); - } - ui.label(format!("id: {}", self.id)); - }); - }); + // ui.group(|ui| { + // ui.horizontal(|ui| { + // if self.saved { + // ui.label(RichText::new("✓ Saved").color(egui::Color32::GREEN)); + // } else { + // ui.label(RichText::new("* Unsaved").color(egui::Color32::YELLOW)); + // } + // ui.label(format!("id: {}", self.id)); + // }); + // }); + util::saved_status(ui, self.saved, &self.id, &self.name); // Save/Cancel buttons ui.horizontal(|ui| { @@ -161,9 +206,9 @@ impl Template { if ui.button("Use Template").clicked() { if self.saved { - *new_instance = Some(RightPanelContent::Object { - object: Box::new(ObjectInstance::new(self)), - }); + *new_instance = Some(RightPanelContent::Object(Box::new( + ObjectInstance::new(self), + ))); } else { self.error = Some(Error::new( "You must save the template before creating a new instance!" @@ -173,25 +218,12 @@ impl Template { } }); - self.editor_ui( - ui, - new_field_name, - new_field_type, - new_field_required, - new_field_description, - ); + self.editor_ui(ui); }); }); } - pub fn editor_ui( - &mut self, - ui: &mut egui::Ui, - new_field_name: &mut String, - new_field_type: &mut FieldType, - new_field_required: &mut bool, - new_field_description: &mut String, - ) { + pub fn editor_ui(&mut self, ui: &mut egui::Ui) { egui::Grid::new("template_grid") .num_columns(2) .striped(true) @@ -254,7 +286,7 @@ impl Template { if ui.button("❌").clicked() { to_remove = Some(i); } - ui.label(field.name.clone()); + ui.strong(field.name.clone()); }) .body(|ui| { ui.separator(); @@ -272,13 +304,7 @@ impl Template { egui::ComboBox::from_id_salt(format!("field_type_{i}")) .selected_text(format!("{:?}", field.field_type)) .show_ui(ui, |ui| { - for variant in [ - FieldType::SingleLine, - FieldType::MultiLine, - FieldType::Number, - FieldType::Date, - FieldType::Image, - ] { + for variant in FieldType::types() { if ui .selectable_value( &mut field.field_type, @@ -330,22 +356,16 @@ impl Template { .striped(true) .show(ui, |ui| { ui.label("Name:"); - ui.text_edit_singleline(new_field_name); + ui.text_edit_singleline(&mut self.new_field_name); ui.end_row(); ui.label("Type:"); egui::ComboBox::from_id_salt("new_field_type") - .selected_text(format!("{new_field_type:?}")) + .selected_text(format!("{:?}", self.new_field_type)) .show_ui(ui, |ui| { - for variant in [ - FieldType::SingleLine, - FieldType::MultiLine, - FieldType::Number, - FieldType::Date, - FieldType::Image, - ] { + for variant in FieldType::types() { ui.selectable_value( - new_field_type, + &mut self.new_field_type, variant.clone(), format!("{variant:?}"), ); @@ -354,31 +374,31 @@ impl Template { ui.end_row(); ui.label("Required:"); - ui.checkbox(new_field_required, ""); + ui.checkbox(&mut self.new_field_required, ""); ui.end_row(); ui.label("Description:"); - ui.text_edit_singleline(new_field_description); + ui.text_edit_singleline(&mut self.new_field_description); ui.end_row(); - if ui.button("Add Field").clicked() && !new_field_name.is_empty() { + if ui.button("Add Field").clicked() && !self.new_field_name.is_empty() { self.fields.push(FieldDefinition { - name: new_field_name.clone(), - field_type: new_field_type.clone(), - required: *new_field_required, - description: if new_field_description.is_empty() { + name: self.new_field_name.clone(), + field_type: self.new_field_type.clone(), + required: self.new_field_required, + description: if self.new_field_description.is_empty() { None } else { - Some(new_field_description.clone()) + Some(self.new_field_description.clone()) }, }); self.saved = false; // Reset new field form - new_field_name.clear(); - *new_field_required = false; - new_field_description.clear(); + self.new_field_name.clear(); + self.new_field_required = false; + self.new_field_description.clear(); } }); }); diff --git a/src/error.rs b/src/error.rs deleted file mode 100644 index 441e43c..0000000 --- a/src/error.rs +++ /dev/null @@ -1,22 +0,0 @@ -pub struct Error { - message: String, - visible: bool, -} - -impl Error { - pub fn new(message: String) -> Self { - Self { - message, - visible: true, - } - } - - pub fn show(&mut self, ui: &mut egui::Ui) { - egui::Window::new("Error") - .open(&mut self.visible) - .fixed_size([200.0, 100.0]) - .show(ui.ctx(), |ui| { - ui.label(self.message.clone()); - }); - } -} diff --git a/src/explorer.rs b/src/explorer.rs index 316772d..cb2f656 100644 --- a/src/explorer.rs +++ b/src/explorer.rs @@ -1,18 +1,36 @@ -use egui::RichText; - use crate::{ PROJECT_FOLDER, RightPanelContent, - main_editor::MainEditor, - note::Note, - object::ObjectInstance, - template::{FieldType, Template}, + content_editor::MainEditor, + editors::{ + asset_editor::Asset, content_editor::ContentSection, object_editor::ObjectInstance, + tags::Tag, template_editor::Template, + }, + note_editor::Note, }; -pub struct Explorer {} +pub struct Explorer { + templates: Vec