diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index a1009057..8cd58413 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -20,7 +20,7 @@ eframe = { git = "https://github.com/emilk/egui", branch = "master" } --> **Describe the bug** - + **To Reproduce** Steps to reproduce the behavior: diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 96db0602..eb595662 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -147,3 +147,9 @@ jobs: - run: sudo apt-get update && sudo apt-get install libspeechd-dev - run: rustup target add wasm32-unknown-unknown - run: cargo doc -p egui_web --target wasm32-unknown-unknown --lib --no-deps --all-features + + cargo-deny: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - uses: EmbarkStudios/cargo-deny-action@v1 diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 410b648c..994c5be2 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -42,7 +42,7 @@ Puts an egui app inside a native window on your laptop. Paints the triangles tha ### `eframe` A wrapper around `egui_web` + `egui_glium`, so you can compile the same app for either web or native. -The demo that you can see at is using `eframe` to host the `egui`. The demo code is found in: +The demo that you can see at is using `eframe` to host the `egui`. The demo code is found in: ### `egui_demo_lib` Depends on `egui` + `epi`. diff --git a/CHANGELOG.md b/CHANGELOG.md index be641726..81e84aad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,13 +8,51 @@ NOTE: [`epaint`](epaint/CHANGELOG.md), [`eframe`](eframe/CHANGELOG.md), [`egui_w ## Unreleased ### Added ⭐ +* Much improved font selection ([#1154](https://github.com/emilk/egui/pull/1154)): + * You can now select any font size and family using `RichText::size` amd `RichText::family` and the new `FontId`. + * Easily change text styles with `Style::text_styles`. + * Added `Ui::text_style_height`. + * Added `TextStyle::resolve`. +* `Context::load_texture` to convert an image into a texture which can be displayed using e.g. `ui.image(texture, size)` ([#1110](https://github.com/emilk/egui/pull/1110)). * Added `Ui::add_visible` and `Ui::add_visible_ui`. +* Opt-in dependency on `tracing` crate for logging warnings ([#1192](https://github.com/emilk/egui/pull/1192)). +* Added `CollapsingHeader::icon` to override the default open/close icon using a custom function. ([1147](https://github.com/emilk/egui/pull/1147)). +* Added `Plot::x_axis_formatter` and `Plot::y_axis_formatter` for custom axis labels ([#1130](https://github.com/emilk/egui/pull/1130)). +* Added `ui.data()`, `ctx.data()`, `ctx.options()` and `ctx.tessellation_options()` ([#1175](https://github.com/emilk/egui/pull/1175)). +* Added `Plot::allow_boxed_zoom()`, `Plot::boxed_zoom_pointer()` for boxed zooming on plots ([#1188](https://github.com/emilk/egui/pull/1188)). +* Added linked axis support for plots via `plot::LinkedAxisGroup` ([#1184](https://github.com/emilk/egui/pull/1184)). +* Added `Response::on_hover_text_at_pointer` as a convenience akin to `Response::on_hover_text`. ([1179](https://github.com/emilk/egui/pull/1179)) ### Changed 🔧 +* ⚠️ `Context::input` and `Ui::input` now locks a mutex. This can lead to a dead-lock is used in an `if let` binding! + * `if let Some(pos) = ui.input().pointer.latest_pos()` and similar must now be rewritten on two lines. + * Search for this problem in your code using the regex `if let .*input`. +* Renamed `CtxRef` to `Context` ([#1050](https://github.com/emilk/egui/pull/1050)). +* `Context` can now be cloned and stored between frames ([#1050](https://github.com/emilk/egui/pull/1050)). * Renamed `Ui::visible` to `Ui::is_visible`. +* Split `Event::Text` into `Event::Text` and `Event::Paste` ([#1058](https://github.com/emilk/egui/pull/1058)). +* For integrations: + * `FontImage` has been replaced by `TexturesDelta` (found in `Output`), describing what textures were loaded and freed each frame ([#1110](https://github.com/emilk/egui/pull/1110)). + * The painter must support partial texture updates ([#1149](https://github.com/emilk/egui/pull/1149)). + * Added `RawInput::max_texture_side` which should be filled in with e.g. `GL_MAX_TEXTURE_SIZE` ([#1154](https://github.com/emilk/egui/pull/1154)). +* Replaced `Style::body_text_style` with more generic `Style::text_styles` ([#1154](https://github.com/emilk/egui/pull/1154)). +* `TextStyle` is no longer `Copy` ([#1154](https://github.com/emilk/egui/pull/1154)). +* Replaced `TextEdit::text_style` with `TextEdit::font` ([#1154](https://github.com/emilk/egui/pull/1154)). +* Replaced `corner_radius: f32` with `rounding: Rounding`, allowing per-corner rounding settings ([#1206](https://github.com/emilk/egui/pull/1206)). +* `Plot::highlight` now takes a `bool` argument ([#1159](https://github.com/emilk/egui/pull/1159)). +* `ScrollArea::show` now returns a `ScrollAreaOutput`, so you might need to add `.inner` after the call to it ([#1166](https://github.com/emilk/egui/pull/1166)). ### Fixed 🐛 -* Context menu now respects the theme ([#1043](https://github.com/emilk/egui/pull/1043)) +* Context menus now respects the theme ([#1043](https://github.com/emilk/egui/pull/1043)) +* Plot `Orientation` was not public, although fields using this type were ([#1130](https://github.com/emilk/egui/pull/1130)) +* Fixed `enable_drag` for Windows ([#1108](https://github.com/emilk/egui/pull/1108)). +* Calling `Context::set_pixels_per_point` before the first frame will now work. + +### Contributors 🙏 +* [AlexxxRu](https://github.com/alexxxru): [#1108](https://github.com/emilk/egui/pull/1108). +* [danielkeller](https://github.com/danielkeller): [#1050](https://github.com/emilk/egui/pull/1050). +* [juancampa](https://github.com/juancampa): [#1147](https://github.com/emilk/egui/pull/1147). + ## 0.16.1 - 2021-12-31 - Add back `CtxRef::begin_frame,end_frame` @@ -334,7 +372,7 @@ NOTE: [`epaint`](epaint/CHANGELOG.md), [`eframe`](eframe/CHANGELOG.md), [`egui_w ### Changed 🔧 * Text will now wrap at newlines, spaces, dashes, punctuation or in the middle of a words if necessary, in that order of priority. * Widgets will now always line break at `\n` characters. -* Widgets will now more intelligently choose wether or not to wrap text. +* Widgets will now more intelligently choose whether or not to wrap text. * `mouse` has been renamed `pointer` everywhere (to make it clear it includes touches too). * Most parts of `Response` are now methods, so `if ui.button("…").clicked {` is now `if ui.button("…").clicked() {`. * `Response::active` is now gone. You can use `response.dragged()` or `response.clicked()` instead. @@ -517,6 +555,7 @@ NOTE: [`epaint`](epaint/CHANGELOG.md), [`eframe`](eframe/CHANGELOG.md), [`egui_w * Optimization: coarse culling in the tessellator * CHANGED: switch argument order of `ui.checkbox` and `ui.radio` + ## 0.1.4 - 2020-09-08 This is when I started the CHANGELOG.md, after almost two years of development. Better late than never. @@ -528,3 +567,13 @@ This is when I started the CHANGELOG.md, after almost two years of development. * Regions: resizing, vertical scrolling, collapsing headers (sections) * Rendering: Anti-aliased rendering of lines, circles, text and convex polygons. * Tooltips on hover + + +## Earlier: + +* 2020-08-10: renamed the project to "egui" +* 2020-05-30: first release on crates.io (0.1.0) +* 2020-05-01: serious work starts (pandemic project) +* 2019-03-12: gave a talk about what would later become egui: https://www.youtube.com/watch?v=-pmwLHw5Gbs +* 2018-12-23: [initial commit](https://github.com/emilk/egui/commit/856bbf4dae4a69693a0324da34e8b0dd3754dfdf) +* 2018-11-04: started tinkering on a train diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e6808d39..c3490a60 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,7 +16,7 @@ There is an `egui` discord at . ## Filing an issue -[Issues](https://github.com/emilk/egui/issues) are for bug reports and feature requests. Issues are not for asking questions (use [Discussions](https://github.com/emilk/egui/discussions) for that). +[Issues](https://github.com/emilk/egui/issues) are for bug reports and feature requests. Issues are not for asking questions (use [Discussions](https://github.com/emilk/egui/discussions) or [Discord](https://discord.gg/vbuv9Xan65) for that). Always make sure there is not already a similar issue to the one you are creating. @@ -36,6 +36,8 @@ When you feel the PR is ready to go, do a self-review of the code, and then open Please keep pull requests small and focused. +Don't worry about having many small commits in the PR - they will be squashed to one commit once merged. + Do not include the `.js` and `.wasm` build artifacts generated for building for web. `git` is not great at storing large files like these, so we only commit a new web demo after a new egui release. @@ -59,6 +61,8 @@ While using an immediate mode gui is simple, implementing one is a lot more tric * read some code before writing your own * follow the `egui` code style +* add blank lines around all `fn`, `struct`, `enum`, etc. +* `// Comment like this`, not `//like this` * write idiomatic rust * avoid `unsafe` * avoid code that can cause panics diff --git a/Cargo.lock b/Cargo.lock index 8ee67a10..34c91490 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "ab_glyph" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20b228f2c198f98d4337ceb560333fb12cbb2f4948a953bf8c57d09deb219603" +checksum = "61caed9aec6daeee1ea38ccf5fb225e4f96c1eeead1b4a5c267324a63cf02326" dependencies = [ "ab_glyph_rasterizer", "owned_ttf_parser", @@ -39,6 +39,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" +[[package]] +name = "ahash" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e" + [[package]] name = "ahash" version = "0.7.6" @@ -76,16 +82,116 @@ dependencies = [ ] [[package]] -name = "anyhow" -version = "1.0.52" +name = "ashpd" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3" +checksum = "7915e26e0786f91768d23de32afafa4ee5e2ea76be21c0ecd8e14441543c1655" +dependencies = [ + "enumflags2", + "futures", + "rand", + "serde", + "serde_repr", + "zbus", +] + +[[package]] +name = "async-broadcast" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90622698a1218e0b2fb846c97b5f19a0831f6baddee73d9454156365ccfa473b" +dependencies = [ + "easy-parallel", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-executor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "once_cell", + "slab", +] + +[[package]] +name = "async-io" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a811e6a479f2439f0c04038796b5cfb3d2ad56c230e0f2d3f7b04d68cfee607b" +dependencies = [ + "concurrent-queue", + "futures-lite", + "libc", + "log", + "once_cell", + "parking", + "polling", + "slab", + "socket2", + "waker-fn", + "winapi", +] + +[[package]] +name = "async-lock" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6a8ea61bf9947a1007c5cada31e647dbc77b103c679858150003ba697ea798b" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-recursion" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d78656ba01f1b93024b7c3a0467f1608e4be67d725749fdcd7d2c7678fd7a2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-task" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d306121baf53310a3fd342d88dc0824f6bbeace68347593658525565abee8" + +[[package]] +name = "async-trait" +version = "0.1.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "atk-sys" -version = "0.14.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "badcf670157c84bb8b1cf6b5f70b650fed78da2033c9eed84c4e49b11cbe83ea" +checksum = "58aeb089fb698e06db8089971c7ee317ab9644bade33383f63631437b03aafb6" dependencies = [ "glib-sys", "gobject-sys", @@ -118,15 +224,15 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "backtrace" -version = "0.3.63" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6" +checksum = "5e121dee8023ce33ab248d9ce1493df03c3b38a659b240096fcbd7048ff9c31f" dependencies = [ "addr2line", "cc", "cfg-if 1.0.0", "libc", - "miniz_oxide 0.4.4", + "miniz_oxide", "object", "rustc-demangle", ] @@ -210,9 +316,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.8.0" +version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" [[package]] name = "bytemuck" @@ -247,10 +353,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" [[package]] -name = "cairo-sys-rs" -version = "0.14.9" +name = "cache-padded" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b448b876970834fda82ba3aeaccadbd760206b75388fc5c1b02f1e343b697570" +checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" + +[[package]] +name = "cairo-sys-rs" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c55d429bef56ac9172d25fecb85dc8068307d17acd74b377866b7a1ef25d3c8" dependencies = [ "libc", "system-deps", @@ -263,7 +375,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf2eec61efe56aa1e813f5126959296933cf0700030e4314786c48779a66ab82" dependencies = [ "log", - "nix", + "nix 0.22.3", ] [[package]] @@ -298,9 +410,9 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.8.1" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b412e83326147c2bb881f8b40edfbf9905b9b8abaebd0e47ca190ba62fda8f0e" +checksum = "3431df59f28accaf4cb4eed4a9acc66bea3f3c3753aa6cdc2f024174ef232af7" dependencies = [ "smallvec", ] @@ -355,9 +467,9 @@ checksum = "5d83feae28854d73f33659f9018546157422ddf5b84264ce171a766d8547d77b" [[package]] name = "clang-sys" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa66045b9cb23c2e9c1520732030608b02ee07e5cfaa5a521ec15ded7fa24c90" +checksum = "4cc00842eed744b858222c4c9faf7243aafc6d33f92f96935263ef4d8a41ce21" dependencies = [ "glob", "libc", @@ -428,14 +540,33 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "combine" -version = "4.6.2" +version = "4.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b2f5d0ee456f3928812dfc8c6d9a1d592b98678f6d56db9b0cd2b7bc6c8db5" +checksum = "50b727aacc797f9fc28e355d21f34709ac4fc9adecfe470ad07b8f4464f53062" dependencies = [ "bytes", "memchr", ] +[[package]] +name = "concurrent-queue" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" +dependencies = [ + "cache-padded", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if 1.0.0", + "wasm-bindgen", +] + [[package]] name = "copypasta" version = "0.7.1" @@ -534,9 +665,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "738c290dfaea84fc1ca15ad9c168d083b05a714e1efddd8edaab678dc28d2836" +checksum = "a2209c310e29876f7f0b2721e7e26b84aff178aa3da5d091f9bfbf47669e60e3" dependencies = [ "cfg-if 1.0.0", ] @@ -579,9 +710,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -600,9 +731,9 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" +checksum = "97242a70df9b89a65d0b6df3c4bf5b9ce03c5b7309019777fbde37e7537f8762" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -613,9 +744,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +checksum = "cfcae03edb34f947e64acdb1c33ec169824e20657e9ecb61cef6c8c74dcb8120" dependencies = [ "cfg-if 1.0.0", "lazy_static", @@ -649,6 +780,22 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" +[[package]] +name = "dark-light" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a76de8354e3935082b341ac29aeff1d05dd14eab64d67ffce4c2f6af06cdb2b" +dependencies = [ + "dconf_rs", + "detect-desktop-environment", + "dirs", + "objc", + "rust-ini", + "winreg", + "zbus", + "zvariant", +] + [[package]] name = "darling" version = "0.13.1" @@ -685,13 +832,18 @@ dependencies = [ ] [[package]] -name = "deflate" -version = "0.8.6" +name = "dconf_rs" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174" +checksum = "7046468a81e6a002061c01e6a7c83139daf91b11c30e66795b13217c2d885c8b" + +[[package]] +name = "deflate" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f95bf05dffba6e6cce8dfbb30def788154949ccd9aed761b472119c21e01c70" dependencies = [ "adler32", - "byteorder", ] [[package]] @@ -705,6 +857,12 @@ dependencies = [ "syn", ] +[[package]] +name = "detect-desktop-environment" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21d8ad60dd5b13a4ee6bd8fa2d5d88965c597c67bce32b5fc49c94f55cb50810" + [[package]] name = "directories-next" version = "2.0.0" @@ -715,6 +873,26 @@ dependencies = [ "dirs-sys-next", ] +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "dirs-sys-next" version = "0.1.2" @@ -741,6 +919,15 @@ dependencies = [ "libloading", ] +[[package]] +name = "dlv-list" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68df3f2b690c1b86e65ef7830956aededf3cb0a16f898f79b9a6f421a7b6211b" +dependencies = [ + "rand", +] + [[package]] name = "downcast-rs" version = "1.2.0" @@ -774,6 +961,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee2626afccd7561a06cf1367e2950c4718ea04565e20fb5029b6c7d8ad09abcf" +[[package]] +name = "easy-parallel" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6907e25393cdcc1f4f3f513d9aac1e840eb1cc341a0fccb01171f7d14d10b946" + [[package]] name = "eframe" version = "0.16.0" @@ -783,8 +976,10 @@ dependencies = [ "egui_glium", "egui_glow", "egui_web", + "ehttp", "epi", "image", + "poll-promise", "rfd", ] @@ -792,11 +987,12 @@ dependencies = [ name = "egui" version = "0.16.1" dependencies = [ - "ahash", + "ahash 0.7.6", "epaint", "nohash-hasher", "ron", "serde", + "tracing", ] [[package]] @@ -804,10 +1000,12 @@ name = "egui-winit" version = "0.16.0" dependencies = [ "copypasta", + "dark-light", "egui", "epi", "instant", "serde", + "tracing", "tts", "webbrowser", "winit", @@ -819,6 +1017,7 @@ version = "0.16.0" dependencies = [ "eframe", "egui_demo_lib", + "tracing-subscriber", ] [[package]] @@ -833,6 +1032,7 @@ dependencies = [ "enum-map", "epi", "image", + "poll-promise", "serde", "syntect", "unicode_names2", @@ -851,6 +1051,8 @@ dependencies = [ name = "egui_glium" version = "0.16.0" dependencies = [ + "ahash 0.7.6", + "bytemuck", "egui", "egui-winit", "epi", @@ -862,6 +1064,7 @@ dependencies = [ name = "egui_glow" version = "0.16.0" dependencies = [ + "bytemuck", "egui", "egui-winit", "epi", @@ -869,6 +1072,7 @@ dependencies = [ "glutin", "image", "memoffset", + "tracing", "wasm-bindgen", "web-sys", ] @@ -877,12 +1081,16 @@ dependencies = [ name = "egui_web" version = "0.16.0" dependencies = [ + "bytemuck", + "console_error_panic_hook", "egui", "egui_glow", "epi", "js-sys", "ron", "serde", + "tracing", + "tracing-wasm", "tts", "wasm-bindgen", "wasm-bindgen-futures", @@ -891,9 +1099,9 @@ dependencies = [ [[package]] name = "ehttp" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b078e2305de4c998700ac152b3e7a358d7fbe77e15b3b1cd2c44a8b82176124f" +checksum = "80b69a6f9168b96c0ae04763bec27a8b06b34343c334dd2703a4ec21f0f5e110" dependencies = [ "js-sys", "ureq", @@ -918,10 +1126,74 @@ dependencies = [ ] [[package]] -name = "enum-map" -version = "1.1.1" +name = "encoding" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e893a7ba6116821058dec84a6fb14fb2a97cd8ce5fd0f85d5a4e760ecd7329d9" +checksum = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec" +dependencies = [ + "encoding-index-japanese", + "encoding-index-korean", + "encoding-index-simpchinese", + "encoding-index-singlebyte", + "encoding-index-tradchinese", +] + +[[package]] +name = "encoding-index-japanese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-korean" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-simpchinese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87a7194909b9118fc707194baa434a4e3b0fb6a5a757c73c3adb07aa25031f7" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-singlebyte" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-tradchinese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding_index_tests" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569" + +[[package]] +name = "enum-map" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4daa8ce58bdc96f86eb90b4b8eab8f1e051da02f8c564389ae2b8ce38932f758" dependencies = [ "enum-map-derive", "serde", @@ -929,9 +1201,30 @@ dependencies = [ [[package]] name = "enum-map-derive" -version = "0.6.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84278eae0af6e34ff6c1db44c11634a694aafac559ff3080e4db4e4ac35907aa" +checksum = "a63b7a0ddec6f38dcec5e36257750b7a8fcaf4227e12ceb306e341d63634da05" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "enumflags2" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a25c90b056b3f84111cf183cbeddef0d3a0bbe9a674f057e1a1533c315f24def" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "144ec79496cbab6f84fa125dc67be9264aef22eb8a28da8454d9c33f15108da4" dependencies = [ "proc-macro2", "quote", @@ -956,7 +1249,7 @@ name = "epaint" version = "0.16.0" dependencies = [ "ab_glyph", - "ahash", + "ahash 0.7.6", "atomic_refcell", "bytemuck", "cint", @@ -975,8 +1268,15 @@ dependencies = [ "egui", "ron", "serde", + "tracing", ] +[[package]] +name = "event-listener" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71" + [[package]] name = "fancy-regex" version = "0.7.1" @@ -987,6 +1287,15 @@ dependencies = [ "regex", ] +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + [[package]] name = "flate2" version = "1.0.22" @@ -996,7 +1305,7 @@ dependencies = [ "cfg-if 1.0.0", "crc32fast", "libc", - "miniz_oxide 0.4.4", + "miniz_oxide", ] [[package]] @@ -1031,16 +1340,114 @@ dependencies = [ ] [[package]] -name = "gcc" -version = "0.3.55" +name = "futures" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" +checksum = "28560757fe2bb34e79f907794bb6b22ae8b0e5c669b638a1132f2592b19035b4" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7" + +[[package]] +name = "futures-executor" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2" + +[[package]] +name = "futures-lite" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-macro" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbd947adfffb0efc70599b3ddcf7b5597bb5fa9e245eb99f62b3a5f7bb8bd3c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508" + +[[package]] +name = "futures-task" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72" + +[[package]] +name = "futures-util" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] [[package]] name = "gdk-pixbuf-sys" -version = "0.14.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f097c0704201fbc8f69c1762dc58c6947c8bb188b8ed0bc7e65259f1894fe590" +checksum = "413424d9818621fa3cfc8a3a915cdb89a7c3c507d56761b4ec83a9a98e587171" dependencies = [ "gio-sys", "glib-sys", @@ -1051,9 +1458,9 @@ dependencies = [ [[package]] name = "gdk-sys" -version = "0.14.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e091b3d3d6696949ac3b3fb3c62090e5bfd7bd6850bef5c3c5ea701de1b1f1e" +checksum = "32e7a08c1e8f06f4177fb7e51a777b8c1689f743a7bc11ea91d44d2226073a88" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", @@ -1068,9 +1475,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" dependencies = [ "cfg-if 1.0.0", "libc", @@ -1085,9 +1492,9 @@ checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" [[package]] name = "gio-sys" -version = "0.14.0" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0a41df66e57fcc287c4bcf74fc26b884f31901ea9792ec75607289b456f48fa" +checksum = "97225e1b9c7c48ed7fec4377fdc72702965bfbfd3a944b928ccbb5d8ed82ccc9" dependencies = [ "glib-sys", "gobject-sys", @@ -1109,9 +1516,9 @@ dependencies = [ [[package]] name = "glib-sys" -version = "0.14.0" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c1d60554a212445e2a858e42a0e48cece1bd57b311a19a9468f70376cf554ae" +checksum = "0c4f08dd67f74b223fedbbb30e73145b9acd444e67cc4d77d0598659b7eebe7e" dependencies = [ "libc", "system-deps", @@ -1225,9 +1632,9 @@ dependencies = [ [[package]] name = "gobject-sys" -version = "0.14.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa92cae29759dae34ab5921d73fff5ad54b3d794ab842c117e36cafc7994c3f5" +checksum = "6edb1f0b3e4c08e2a0a490d1082ba9e902cdff8ff07091e85c6caec60d17e2ab" dependencies = [ "glib-sys", "libc", @@ -1236,9 +1643,9 @@ dependencies = [ [[package]] name = "gtk-sys" -version = "0.14.0" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c14c8d3da0545785a7c5a120345b3abb534010fb8ae0f2ef3f47c027fba303e" +checksum = "d5bc2f0587cba247f60246a0ca11fe25fb733eabc3de12d1965fc07efab87c84" dependencies = [ "atk-sys", "cairo-sys-rs", @@ -1258,6 +1665,15 @@ version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +[[package]] +name = "hashbrown" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +dependencies = [ + "ahash 0.4.7", +] + [[package]] name = "hashbrown" version = "0.11.2" @@ -1266,12 +1682,9 @@ checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" [[package]] name = "heck" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" [[package]] name = "hermit-abi" @@ -1282,6 +1695,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "humantime" version = "2.1.0" @@ -1307,9 +1726,9 @@ dependencies = [ [[package]] name = "image" -version = "0.23.14" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1" +checksum = "e94ac3d41f882c624a82d7945952032388488681f45f9d4077999a6c85688d61" dependencies = [ "bytemuck", "byteorder", @@ -1323,12 +1742,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.11.2", ] [[package]] @@ -1386,15 +1805,15 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jpeg-decoder" -version = "0.1.22" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2" +checksum = "fbcf0244f6597be39ab8d9203f574cafb529ae8c698afa2182f7b3c3205a4a9c" [[package]] name = "js-sys" -version = "0.3.55" +version = "0.3.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" +checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" dependencies = [ "wasm-bindgen", ] @@ -1425,15 +1844,15 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.112" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" +checksum = "e74d72e0f9b65b5b4ca49a346af3976df0f9c61d550727f349ecd559f251a26c" [[package]] name = "libloading" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afe203d669ec979b7128619bae5a63b7b42e9203c1b29146079ee05e2f604b52" +checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" dependencies = [ "cfg-if 1.0.0", "winapi", @@ -1456,9 +1875,9 @@ checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" [[package]] name = "lock_api" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" dependencies = [ "scopeguard", ] @@ -1517,15 +1936,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" -dependencies = [ - "adler32", -] - [[package]] name = "miniz_oxide" version = "0.4.4" @@ -1538,9 +1948,9 @@ dependencies = [ [[package]] name = "mint" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162e591484b4b8fe9e1ca16ebf07ab584fdc3334508d76a788cd54d89cfc20dc" +checksum = "e53debba6bda7a793e5f99b8dacf19e626084f525f7829104ba9898f367d85ff" [[package]] name = "mio" @@ -1572,7 +1982,20 @@ checksum = "96d868f654c72e75f8687572699cdabe755f03effbb62542768e995d5b8d699d" dependencies = [ "bitflags", "jni-sys", - "ndk-sys", + "ndk-sys 0.2.2", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" +dependencies = [ + "bitflags", + "jni-sys", + "ndk-sys 0.3.0", "num_enum", "thiserror", ] @@ -1586,9 +2009,23 @@ dependencies = [ "lazy_static", "libc", "log", - "ndk", + "ndk 0.5.0", "ndk-macro", - "ndk-sys", + "ndk-sys 0.2.2", +] + +[[package]] +name = "ndk-glue" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04c0d14b0858eb9962a5dac30b809b19f19da7e4547d64af2b0bb051d2e55d79" +dependencies = [ + "lazy_static", + "libc", + "log", + "ndk 0.6.0", + "ndk-macro", + "ndk-sys 0.3.0", ] [[package]] @@ -1611,10 +2048,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121" [[package]] -name = "nix" -version = "0.22.0" +name = "ndk-sys" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1e25ee6b412c2a1e3fcb6a4499a5c1bfe7f43e014bdce9a6b6666e5aa2d187" +checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "nix" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf" +dependencies = [ + "bitflags", + "cc", + "cfg-if 1.0.0", + "libc", + "memoffset", +] + +[[package]] +name = "nix" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" dependencies = [ "bitflags", "cc", @@ -1672,9 +2131,9 @@ dependencies = [ [[package]] name = "num-rational" -version = "0.3.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" +checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a" dependencies = [ "autocfg", "num-integer", @@ -1702,19 +2161,18 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "085fe377a4b2805c0fbc09484415ec261174614b7f080b0e0d520456ac421a67" +checksum = "720d3ea1055e4e4574c0c0b0f8c3fd4f24c4cdaf465948206dea090b57b526ad" dependencies = [ - "derivative", "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5249369707a1e07b39f78d98c8f34e00aca7dcb053812fdbb5ad7be82c1bba38" +checksum = "0d992b768490d7fe0d8586d9b5745f6c49f557da6d81dc982b1d167ad4edbb21" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -1722,6 +2180,15 @@ dependencies = [ "syn", ] +[[package]] +name = "num_threads" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97ba99ba6393e2c3734791401b66902d981cb03bf190af674ca69949b6d5fb15" +dependencies = [ + "libc", +] + [[package]] name = "objc" version = "0.2.7" @@ -1782,6 +2249,32 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "ordered-multimap" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c672c7ad9ec066e428c00eb917124a06f08db19e2584de982cc34b1f4c12485" +dependencies = [ + "dlv-list", + "hashbrown 0.9.1", +] + +[[package]] +name = "ordered-stream" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44630c059eacfd6e08bdaa51b1db2ce33119caa4ddc1235e923109aa5f25ccb1" +dependencies = [ + "futures-core", + "pin-project-lite", +] + [[package]] name = "osmesa-sys" version = "0.1.2" @@ -1793,18 +2286,18 @@ dependencies = [ [[package]] name = "owned_ttf_parser" -version = "0.13.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65ee3f72636e6f164cc41c9f9057f4e58c4e13507699ea7f5e5242b64b8198ee" +checksum = "4ef05f2882a8b3e7acc10c153ade2631f7bfc8ce00d2bf3fb8f4e9d2ae6ea5c3" dependencies = [ "ttf-parser", ] [[package]] name = "pango-sys" -version = "0.14.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2367099ca5e761546ba1d501955079f097caa186bb53ce0f718dca99ac1942fe" +checksum = "7022c2fb88cd2d9d55e1a708a8c53a3ae8678234c4a54bf623400aeb7f31fac2" dependencies = [ "glib-sys", "gobject-sys", @@ -1812,6 +2305,12 @@ dependencies = [ "system-deps", ] +[[package]] +name = "parking" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" + [[package]] name = "parking_lot" version = "0.11.2" @@ -1849,6 +2348,18 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +[[package]] +name = "pin-project-lite" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "pkg-config" version = "0.3.24" @@ -1865,7 +2376,7 @@ dependencies = [ "indexmap", "line-wrap", "serde", - "time 0.3.5", + "time 0.3.7", "xml-rs", ] @@ -1899,16 +2410,51 @@ dependencies = [ [[package]] name = "png" -version = "0.16.8" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6" +checksum = "c845088517daa61e8a57eee40309347cea13f273694d1385c553e7a57127763b" dependencies = [ "bitflags", "crc32fast", "deflate", - "miniz_oxide 0.3.7", + "encoding", + "miniz_oxide", ] +[[package]] +name = "poll-promise" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "260817b339544e5b23d4bb66d4522d89dd64af88d16b6dcd7b2a2409ee2e095d" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "polling" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685404d509889fade3e86fe3a5803bca2ec09b0c0778d5ada6ec8bf7a8de5259" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "log", + "wepoll-ffi", + "winapi", +] + +[[package]] +name = "pollster" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5da3b0203fd7ee5720aa0b5e790b591aa5d3f41c3ed2c34a3a393382198af2f7" + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + [[package]] name = "proc-macro-crate" version = "1.1.0" @@ -1939,13 +2485,53 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d" +checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +dependencies = [ + "rand_core", +] + [[package]] name = "raw-window-handle" version = "0.4.2" @@ -2024,10 +2610,11 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "rfd" -version = "0.6.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b0c25b610bf37d9874ff224ab2791ff2272bedeb5638a2dca8b18e1270ed69b" +checksum = "2aaf1d71ccd44689f7c2c72da1117fd8db71f72a76fe9b5c5dbb17ab903007e0" dependencies = [ + "ashpd", "block", "dispatch", "glib-sys", @@ -2035,9 +2622,11 @@ dependencies = [ "gtk-sys", "js-sys", "lazy_static", + "log", "objc", "objc-foundation", "objc_id", + "pollster", "raw-window-handle", "wasm-bindgen", "wasm-bindgen-futures", @@ -2071,6 +2660,16 @@ dependencies = [ "serde", ] +[[package]] +name = "rust-ini" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63471c4aa97a1cf8332a5f97709a79a4234698de6a1f5087faf66f2dae810e22" +dependencies = [ + "cfg-if 1.0.0", + "ordered-multimap", +] + [[package]] name = "rustc-demangle" version = "0.1.21" @@ -2104,6 +2703,27 @@ dependencies = [ "webpki", ] +[[package]] +name = "rustls-native-certs" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca9ebdfa27d3fc180e42879037b5338ab1c040c06affd00d8338598e7800943" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" +dependencies = [ + "base64", +] + [[package]] name = "ryu" version = "1.0.9" @@ -2125,6 +2745,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" +dependencies = [ + "lazy_static", + "winapi", +] + [[package]] name = "scoped-tls" version = "1.0.0" @@ -2147,6 +2777,29 @@ dependencies = [ "untrusted", ] +[[package]] +name = "security-framework" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fed7948b6c68acbb6e20c334f55ad635dc0f75506963de4464289fbd3b051ac" +dependencies = [ + "bitflags", + "core-foundation 0.9.2", + "core-foundation-sys 0.8.3", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a57321bf8bc2362081b2599912d2961fe899c0efadf1b4b2f8d48b3e253bb96c" +dependencies = [ + "core-foundation-sys 0.8.3", + "libc", +] + [[package]] name = "semver" version = "1.0.4" @@ -2155,9 +2808,9 @@ checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" [[package]] name = "serde" -version = "1.0.132" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9875c23cf305cd1fd7eb77234cbb705f21ea6a72c637a5c6db5fe4b8e7f008" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" dependencies = [ "serde_derive", ] @@ -2174,9 +2827,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.132" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc0db5cb2556c0e558887d9bbdcf6ac4471e83ff66cf696e5419024d1606276" +checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" dependencies = [ "proc-macro2", "quote", @@ -2185,15 +2838,50 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.73" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcbd0344bc6533bc7ec56df11d42fb70f1b912351c0825ccb7211b59d8af7cf5" +checksum = "d23c1ba4cf0efd44be32017709280b32d1cea5c3f1275c3b6d9e8bc54f758085" dependencies = [ "itoa 1.0.1", "ryu", "serde", ] +[[package]] +name = "serde_repr" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98d0516900518c29efa217c298fa1f4e6c6ffc85ae29fd7f4ee48f176e1a9ed5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sha1" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +dependencies = [ + "sha1_smol", +] + +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + [[package]] name = "shared_library" version = "0.1.9" @@ -2210,6 +2898,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" +[[package]] +name = "slab" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" + [[package]] name = "slotmap" version = "1.0.6" @@ -2221,9 +2915,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" [[package]] name = "smithay-client-toolkit" @@ -2237,7 +2931,7 @@ dependencies = [ "lazy_static", "log", "memmap2", - "nix", + "nix 0.22.3", "pkg-config", "wayland-client", "wayland-cursor", @@ -2255,10 +2949,20 @@ dependencies = [ ] [[package]] -name = "speech-dispatcher" -version = "0.9.0" +name = "socket2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b684552615661fef2658506637989f8a8ead697c83c9a35a12d2a11bbd96955" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "speech-dispatcher" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbab517fe176eb95d9bcc23c5ba75500fc5157d13a6978cfe135395fa149e151" dependencies = [ "lazy_static", "speech-dispatcher-sys", @@ -2266,12 +2970,11 @@ dependencies = [ [[package]] name = "speech-dispatcher-sys" -version = "0.5.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b662a91fe7e39d3d11edcf0297c717a8c05683a6c6445df9aba83b034b2b2db5" +checksum = "6c3e8acdf2b1f4bb13f1813b40b52f3edf4cc94d8a55fe713a584f672a10388d" dependencies = [ "bindgen", - "gcc", ] [[package]] @@ -2280,6 +2983,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" version = "0.8.0" @@ -2292,35 +3001,23 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" -[[package]] -name = "strum" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2" - -[[package]] -name = "strum_macros" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "syn" -version = "1.0.84" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecb2e6da8ee5eb9a61068762a32fa9619cc591ceb055b3687f4cd4051ec2e06b" +checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] +[[package]] +name = "sync_wrapper" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" + [[package]] name = "syntect" version = "4.6.0" @@ -2345,18 +3042,13 @@ dependencies = [ [[package]] name = "system-deps" -version = "3.2.0" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "480c269f870722b3b08d2f13053ce0c2ab722839f472863c3e2d61ff3a1c2fa6" +checksum = "ad3a97fdef3daf935d929b3e97e5a6a680cd4622e40c2941ca0875d6566416f8" dependencies = [ - "anyhow", "cfg-expr", "heck", - "itertools", "pkg-config", - "strum", - "strum_macros", - "thiserror", "toml", "version-compare", ] @@ -2405,6 +3097,15 @@ dependencies = [ "syn", ] +[[package]] +name = "thread_local" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +dependencies = [ + "once_cell", +] + [[package]] name = "time" version = "0.1.43" @@ -2417,12 +3118,13 @@ dependencies = [ [[package]] name = "time" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41effe7cfa8af36f439fac33861b66b049edc6f9a32331e2312660529c1c24ad" +checksum = "004cbc98f30fa233c61a38bc77e96a9106e65c88f2d3bef182ae952027e5753d" dependencies = [ - "itoa 0.4.8", + "itoa 1.0.1", "libc", + "num_threads", ] [[package]] @@ -2460,16 +3162,85 @@ dependencies = [ ] [[package]] -name = "ttf-parser" -version = "0.13.4" +name = "tracing" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76dacc724328b3d5e2ed67f9e30cdb56893a34ab239032502cc8f19f8dae4bbc" +checksum = "2d8d93354fe2a8e50d5953f5ae2e47a3fc2ef03292e7ea46e3cc38f549525fb9" +dependencies = [ + "cfg-if 1.0.0", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8276d9a4a3a558d7b7ad5303ad50b53d58264641b82914b7ada36bd762e7a716" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23" +dependencies = [ + "lazy_static", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5312f325fe3588e277415f5a6cca1f4ccad0f248c4cd5a4bd33032d7286abc22" +dependencies = [ + "ansi_term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "tracing-wasm" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4575c663a174420fa2d78f4108ff68f65bf2fbb7dd89f33749b6e826b3626e07" +dependencies = [ + "tracing", + "tracing-subscriber", + "wasm-bindgen", +] + +[[package]] +name = "ttf-parser" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ccbe8381883510b6a2d8f1e32905bddd178c11caef8083086d0c0c9ab0ac281" [[package]] name = "tts" -version = "0.19.2" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38dcd7e0cdd94949f55b94c24ccbb7922437883ec268dbbac23480db32287016" +checksum = "5dd3cc4cfd63db314c5b82e8b60cba72869f048c4e6d26e7ec1645bf4de2ca2d" dependencies = [ "cocoa-foundation", "dyn-clonable", @@ -2477,7 +3248,7 @@ dependencies = [ "lazy_static", "libc", "log", - "ndk-glue", + "ndk-glue 0.6.0", "objc", "speech-dispatcher", "thiserror", @@ -2501,12 +3272,6 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-segmentation" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" - [[package]] name = "unicode-width" version = "0.1.9" @@ -2534,8 +3299,7 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "ureq" version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9399fa2f927a3d327187cbd201480cee55bee6ac5d3c77dd27f0c6814cff16d5" +source = "git+https://github.com/emilk/ureq/?branch=opt-in-webpki-roots#d4ca2ca620b65854c3428306b03ab7ef562bf796" dependencies = [ "base64", "chunked_transfer", @@ -2543,9 +3307,10 @@ dependencies = [ "log", "once_cell", "rustls", + "rustls-native-certs", + "sync_wrapper", "url", "webpki", - "webpki-roots", ] [[package]] @@ -2560,6 +3325,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vec_map" version = "0.8.2" @@ -2568,9 +3339,9 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version-compare" -version = "0.0.11" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c18c859eead79d8b95d09e4678566e8d70105c4e7b251f707a03df32442661b" +checksum = "fe88247b92c1df6b6de80ddc290f3976dbdf2f5f5d3fd049a9fb598c6dd5ca73" [[package]] name = "version_check" @@ -2578,6 +3349,12 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "waker-fn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" + [[package]] name = "walkdir" version = "2.3.2" @@ -2597,9 +3374,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasm-bindgen" -version = "0.2.78" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" +checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -2607,9 +3384,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.78" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" +checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" dependencies = [ "bumpalo", "lazy_static", @@ -2622,9 +3399,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.28" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d7523cb1f2a4c96c1317ca690031b714a51cc14e05f712446691f413f5d39" +checksum = "2eb6ec270a31b1d3c7e266b999739109abce8b6c87e4b31fcfcd788b65267395" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -2634,9 +3411,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.78" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" +checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2644,9 +3421,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.78" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" +checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" dependencies = [ "proc-macro2", "quote", @@ -2657,20 +3434,20 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.78" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" +checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" [[package]] name = "wayland-client" -version = "0.29.1" +version = "0.29.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9108ec1c37f4774d0c2937ba1a6c23d1786b2152c4a13bd9fdb20e42d16e8841" +checksum = "91223460e73257f697d9e23d401279123d36039a3f7a449e983f123292d4458f" dependencies = [ "bitflags", "downcast-rs", "libc", - "nix", + "nix 0.22.3", "scoped-tls", "wayland-commons", "wayland-scanner", @@ -2679,11 +3456,11 @@ dependencies = [ [[package]] name = "wayland-commons" -version = "0.29.1" +version = "0.29.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "265ef51b3b3e5c9ef098f10425c39624663f459c3821dcaacc4748be975f1beb" +checksum = "94f6e5e340d7c13490eca867898c4cec5af56c27a5ffe5c80c6fc4708e22d33e" dependencies = [ - "nix", + "nix 0.22.3", "once_cell", "smallvec", "wayland-sys", @@ -2691,20 +3468,20 @@ dependencies = [ [[package]] name = "wayland-cursor" -version = "0.29.1" +version = "0.29.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c19bb6628daf4097e58b7911481e8371e13318d5a60894779901bd3267407a7" +checksum = "c52758f13d5e7861fc83d942d3d99bf270c83269575e52ac29e5b73cb956a6bd" dependencies = [ - "nix", + "nix 0.22.3", "wayland-client", "xcursor", ] [[package]] name = "wayland-egl" -version = "0.29.1" +version = "0.29.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accf27d1e5e1f64ba30b683fd926c2c916cc1014bea3376fb258e80abf622e40" +checksum = "83281d69ee162b59031c666385e93bde4039ec553b90c4191cdb128ceea29a3a" dependencies = [ "wayland-client", "wayland-sys", @@ -2712,9 +3489,9 @@ dependencies = [ [[package]] name = "wayland-protocols" -version = "0.29.1" +version = "0.29.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b3b6f1dc0193072ef4eadcb144da30d58c1f2895516c063804d213310703c8e" +checksum = "60147ae23303402e41fe034f74fb2c35ad0780ee88a1c40ac09a3be1e7465741" dependencies = [ "bitflags", "wayland-client", @@ -2724,9 +3501,9 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.29.1" +version = "0.29.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaaf2bc85e7b9143159af96bd23d954a5abe391c4376db712320643280fdc6f4" +checksum = "39a1ed3143f7a143187156a2ab52742e89dac33245ba505c17224df48939f9e0" dependencies = [ "proc-macro2", "quote", @@ -2735,9 +3512,9 @@ dependencies = [ [[package]] name = "wayland-sys" -version = "0.29.1" +version = "0.29.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba9e06acb775b3007f8d3094438306979e572d1d3b844d7a71557a84b055d959" +checksum = "d9341df79a8975679188e37dab3889bfa57c44ac2cb6da166f519a81cbe452d4" dependencies = [ "dlib", "lazy_static", @@ -2746,9 +3523,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.55" +version = "0.3.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" +checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" dependencies = [ "js-sys", "wasm-bindgen", @@ -2776,19 +3553,19 @@ dependencies = [ ] [[package]] -name = "webpki-roots" -version = "0.22.1" +name = "wepoll-ffi" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c475786c6f47219345717a043a37ec04cb4bc185e28853adcc4fa0a947eba630" +checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" dependencies = [ - "webpki", + "cc", ] [[package]] name = "which" -version = "4.2.2" +version = "4.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea187a8ef279bc014ec368c27a920da2024d2a711109bfbe3440585d5cf27ad9" +checksum = "2a5a7e487e921cf220206864a94a89b6c6905bfc19f1057fa26a4cb360e5c1d2" dependencies = [ "either", "lazy_static", @@ -2834,9 +3611,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aac7fef12f4b59cd0a29339406cc9203ab44e440ddff6b3f5a41455349fa9cf3" +checksum = "b749ebd2304aa012c5992d11a25d07b406bdbe5f79d371cb7a918ce501a19eb0" dependencies = [ "windows_aarch64_msvc", "windows_i686_gnu", @@ -2847,42 +3624,41 @@ dependencies = [ [[package]] name = "windows_aarch64_msvc" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d027175d00b01e0cbeb97d6ab6ebe03b12330a35786cbaca5252b1c4bf5d9b" +checksum = "29277a4435d642f775f63c7d1faeb927adba532886ce0287bd985bffb16b6bca" [[package]] name = "windows_i686_gnu" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8793f59f7b8e8b01eda1a652b2697d87b93097198ae85f823b969ca5b89bba58" +checksum = "1145e1989da93956c68d1864f32fb97c8f561a8f89a5125f6a2b7ea75524e4b8" [[package]] name = "windows_i686_msvc" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8602f6c418b67024be2996c512f5f995de3ba417f4c75af68401ab8756796ae4" +checksum = "d4a09e3a0d4753b73019db171c1339cd4362c8c44baf1bcea336235e955954a6" [[package]] name = "windows_x86_64_gnu" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d615f419543e0bd7d2b3323af0d86ff19cbc4f816e6453f36a2c2ce889c354" +checksum = "8ca64fcb0220d58db4c119e050e7af03c69e6f4f415ef69ec1773d9aab422d5a" [[package]] name = "windows_x86_64_msvc" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d95421d9ed3672c280884da53201a5c46b7b2765ca6faf34b0d71cf34a3561" +checksum = "08cabc9f0066848fef4bc6a1c1668e6efce38b661d2aeec75d18d8617eebb5f1" [[package]] name = "winit" -version = "0.26.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70466a5f4825cc88c92963591b06dbc255420bffe19d847bfcda475e82d079c0" +checksum = "9b43cc931d58b99461188607efd7acb2a093e65fc621f54cad78517a6063e73a" dependencies = [ "bitflags", - "block", "cocoa", "core-foundation 0.9.2", "core-graphics 0.22.3", @@ -2893,9 +3669,9 @@ dependencies = [ "libc", "log", "mio", - "ndk", - "ndk-glue", - "ndk-sys", + "ndk 0.5.0", + "ndk-glue 0.5.0", + "ndk-sys 0.2.2", "objc", "parking_lot", "percent-encoding", @@ -2909,6 +3685,15 @@ dependencies = [ "x11-dl", ] +[[package]] +name = "winreg" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d107f8c6e916235c4c01cabb3e8acf7bea8ef6a63ca2e7fa0527c049badfc48c" +dependencies = [ + "winapi", +] + [[package]] name = "x11-clipboard" version = "0.5.3" @@ -2963,3 +3748,90 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" dependencies = [ "linked-hash-map", ] + +[[package]] +name = "zbus" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb86f3d4592e26a48b2719742aec94f8ae6238ebde20d98183ee185d1275e9a" +dependencies = [ + "async-broadcast", + "async-channel", + "async-executor", + "async-io", + "async-lock", + "async-recursion", + "async-task", + "async-trait", + "byteorder", + "derivative", + "enumflags2", + "event-listener", + "futures-core", + "futures-sink", + "futures-util", + "hex", + "lazy_static", + "nix 0.23.1", + "once_cell", + "ordered-stream", + "rand", + "serde", + "serde_repr", + "sha1", + "static_assertions", + "winapi", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36823cc10fddc3c6b19f048903262dacaf8274170e9a255784bdd8b4570a8040" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "syn", +] + +[[package]] +name = "zbus_names" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45dfcdcf87b71dad505d30cc27b1b7b88a64b6d1c435648f48f9dbc1fdc4b7e1" +dependencies = [ + "serde", + "static_assertions", + "zvariant", +] + +[[package]] +name = "zvariant" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49ea5dc38b2058fae6a5b79009388143dadce1e91c26a67f984a0fc0381c8033" +dependencies = [ + "byteorder", + "enumflags2", + "libc", + "serde", + "static_assertions", + "zvariant_derive", +] + +[[package]] +name = "zvariant_derive" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c2cecc5a61c2a053f7f653a24cd15b3b0195d7f7ddb5042c837fb32e161fb7a" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index a8113833..da9c7db1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,3 +25,6 @@ opt-level = 2 # fast and small wasm, basically same as `opt-level = 's'` # opt-level = 3 # unecessarily large wasm for no performance gain # debug = true # include debug symbols, useful when profiling wasm + +[patch.crates-io] +ureq = { git = "https://github.com/emilk/ureq/", branch = "opt-in-webpki-roots" } # See https://github.com/algesten/ureq/pull/479 / https://github.com/algesten/ureq/issues/478 diff --git a/README.md b/README.md index ab50bdd0..946e8cdc 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ ![Apache](https://img.shields.io/badge/license-Apache-blue.svg) [![Discord](https://img.shields.io/discord/900275882684477440?label=egui%20discord)](https://discord.gg/JFcEma9bJq) +👉 [Click to run the web demo](https://www.egui.rs/#demo) 👈 egui is a simple, fast, and highly portable immediate mode GUI library for Rust. egui runs on the web, natively, and [in your favorite game engine](#integrations) (or will soon). @@ -18,43 +19,19 @@ egui can be used anywhere you can draw textured triangles, which means you can e Sections: +* [Example](#example) * [Quick start](#quick-start) * [Demo](#demo) * [Goals](#goals) * [Who is egui for?](#who-is-egui-for) * [State / features](#state) -* [How it works](#how-it-works) * [Integrations](#integrations) * [Why immediate mode](#why-immediate-mode) * [FAQ](#faq) * [Other](#other) * [Credits](#credits) -## Quick start - -If you just want to write a GUI application in Rust (for the web or for native), go to and follow the instructions there! The official docs are at . For inspiration, check out the [the egui web demo](https://emilk.github.io/egui/index.html) and follow the links in it to its source code. There is also an excellent tutorial video at . - -If you want to integrate egui into an existing engine, go to the [Integrations](#integrations) section. - -If you have questions, use [GitHub Discussions](https://github.com/emilk/egui/discussions). There is also [an egui discord server](https://discord.gg/JFcEma9bJq). If you want to contribute to egui, please read the [Contributing Guidelines](https://github.com/emilk/egui/blob/master/CONTRIBUTING.md). - -## Demo - -[Click to run egui web demo](https://emilk.github.io/egui/index.html) (works in any browser with WASM and WebGL support). Uses [`egui_web`](https://github.com/emilk/egui/tree/master/egui_web). - -To test the demo app locally, run `cargo run --release -p egui_demo_app`. - -The native backend is [`egui_glow`](https://github.com/emilk/egui/tree/master/egui_glow) (using [`glow`](https://crates.io/crates/glow)) and should work out-of-the-box on Mac and Windows, but on Linux you need to first run: - -`sudo apt-get install libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev libspeechd-dev libxkbcommon-dev libssl-dev` - -On Fedora Rawhide you need to run: - -`dnf install clang clang-devel clang-tools-extra speech-dispatcher-devel libxkbcommon-devel pkg-config openssl-devel libxcb-devel` - -**NOTE**: This is just for the demo app - egui itself is completely platform agnostic! - -### Example +## Example ``` rust ui.heading("My egui Application"); @@ -71,6 +48,30 @@ ui.label(format!("Hello '{}', age {}", name, age)); +## Quick start + +If you just want to write a GUI application in Rust (for the web or for native), go to and follow the instructions there! The official docs are at . For inspiration, check out the [the egui web demo](https://www.egui.rs/#demo) and follow the links in it to its source code. There is also an excellent tutorial video at . + +If you want to integrate egui into an existing engine, go to the [Integrations](#integrations) section. + +If you have questions, use [GitHub Discussions](https://github.com/emilk/egui/discussions). There is also [an egui discord server](https://discord.gg/JFcEma9bJq). If you want to contribute to egui, please read the [Contributing Guidelines](https://github.com/emilk/egui/blob/master/CONTRIBUTING.md). + +## Demo + +[Click to run egui web demo](https://www.egui.rs/#demo) (works in any browser with WASM and WebGL support). Uses [`egui_web`](https://github.com/emilk/egui/tree/master/egui_web). + +To test the demo app locally, run `cargo run --release -p egui_demo_app`. + +The native backend is [`egui_glow`](https://github.com/emilk/egui/tree/master/egui_glow) (using [`glow`](https://crates.io/crates/glow)) and should work out-of-the-box on Mac and Windows, but on Linux you need to first run: + +`sudo apt-get install libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev libspeechd-dev libxkbcommon-dev libssl-dev` + +On Fedora Rawhide you need to run: + +`dnf install clang clang-devel clang-tools-extra speech-dispatcher-devel libxkbcommon-devel pkg-config openssl-devel libxcb-devel` + +**NOTE**: This is just for the demo app - egui itself is completely platform agnostic! + ## Goals * The easiest to use GUI library @@ -145,72 +146,75 @@ Light Theme: -## How it works - -Loop: - -* Gather input (mouse, touches, keyboard, screen size, etc) and give it to egui -* Run application code (Immediate Mode GUI) -* Tell egui to tessellate the frame graphics to a triangle mesh -* Render the triangle mesh with your favorite graphics API (see [OpenGL example](https://github.com/emilk/egui/blob/master/egui_glium/src/painter.rs)) or use `eframe`, the egui framework crate. - ## Integrations egui is build to be easy to integrate into any existing game engine or platform you are working on. egui itself doesn't know or care on what OS it is running or how to render things to the screen - that is the job of the egui integration. -The integration needs to do two things: -* **IO**: Supply egui with input (mouse position, keyboard presses, …) and handle egui output (cursor changes, copy-paste integration, …). -* **Painting**: Render the textured triangles that egui outputs. +An integration needs to do the following each frame: -### Official +* **Input**: Gather input (mouse, touches, keyboard, screen size, etc) and give it to egui +* Run the application code +* **Output**: Handle egui output (cursor changes, paste, texture allocations, …) +* **Painting**: Render the triangle mesh egui produces (see [OpenGL example](https://github.com/emilk/egui/blob/master/egui_glium/src/painter.rs)) -There are three official egui integrations made for apps: +### Official integrations + +If you making an app, your best bet is using [`eframe`](https://github.com/emilk/egui/tree/master/eframe), the official egui framework. It lets you write apps that works on both the web and native. `eframe` is just a thin wrapper over `egui_web` and `egui_glium` (see below). + +These are the official egui integrations: -* [`egui_web`](https://github.com/emilk/egui/tree/master/egui_web) for making a web app. Compiles to WASM, renders with WebGL. [Click to run the egui demo](https://emilk.github.io/egui/index.html). * [`egui_glium`](https://github.com/emilk/egui/tree/master/egui_glium) for compiling native apps with [Glium](https://github.com/glium/glium). * [`egui_glow`](https://github.com/emilk/egui/tree/master/egui_glow) for compiling native apps with [Glow](https://github.com/grovesNL/glow). -* [`egui-winit`](https://github.com/emilk/egui/tree/master/egui-winit) for integrating with [`winit`](https://github.com/rust-windowing/winit). `egui-winit` is used by `egui_glium` and `egui_glow`. +* [`egui_web`](https://github.com/emilk/egui/tree/master/egui_web) for making a web app. Compiles to WASM, renders with WebGL. [Click to run the egui demo](https://www.egui.rs/#demo). +* [`egui-winit`](https://github.com/emilk/egui/tree/master/egui-winit) for integrating with [winit](https://github.com/rust-windowing/winit). `egui-winit` is used by `egui_glium` and `egui_glow`. -If you making an app, consider using [`eframe`](https://github.com/emilk/egui/tree/master/eframe), a framework which allows you to write code that works on both the web (`egui_web`) and native (using `egui_glium`). - -### 3rd party +### 3rd party integrations * [`amethyst_egui`](https://github.com/jgraef/amethyst_egui) for [the Amethyst game engine](https://amethyst.rs/). * [`bevy_egui`](https://github.com/mvlabat/bevy_egui) for [the Bevy game engine](https://bevyengine.org/). * [`egui_glfw_gl`](https://github.com/cohaereo/egui_glfw_gl) for [GLFW](https://crates.io/crates/glfw). -* [`egui-miniquad`](https://github.com/not-fl3/egui-miniquad) for [Miniquad](https://github.com/not-fl3/miniquad). -* [`egui-macroquad`](https://github.com/optozorax/egui-macroquad) for [macroquad](https://github.com/not-fl3/macroquad). * [`egui_sdl2_gl`](https://crates.io/crates/egui_sdl2_gl) for [SDL2](https://crates.io/crates/sdl2). * [`egui_vulkano`](https://github.com/derivator/egui_vulkano) for [Vulkano](https://github.com/vulkano-rs/vulkano). -* [`egui-winit-ash-integration`](https://github.com/MatchaChoco010/egui-winit-ash-integration) for [winit](https://github.com/rust-windowing/winit) and [ash](https://github.com/MaikKlein/ash). +* [`egui_wgpu_backend`](https://crates.io/crates/egui_wgpu_backend) for [wgpu](https://crates.io/crates/wgpu) (WebGPU API). * [`egui_winit_vulkano`](https://github.com/hakolao/egui_winit_vulkano) for [Vulkano](https://github.com/vulkano-rs/vulkano). +* [`egui-macroquad`](https://github.com/optozorax/egui-macroquad) for [macroquad](https://github.com/not-fl3/macroquad). +* [`egui-miniquad`](https://github.com/not-fl3/egui-miniquad) for [Miniquad](https://github.com/not-fl3/miniquad). +* [`egui-tetra`](https://crates.io/crates/egui-tetra) for [Tetra](https://crates.io/crates/tetra), a 2D game framework. +* [`egui-winit-ash-integration`](https://github.com/MatchaChoco010/egui-winit-ash-integration) for [winit](https://github.com/rust-windowing/winit) and [ash](https://github.com/MaikKlein/ash). * [`fltk-egui`](https://crates.io/crates/fltk-egui) for [fltk-rs](https://github.com/fltk-rs/fltk-rs). * [`ggez-egui`](https://github.com/NemuiSen/ggez-egui) for the [ggez](https://ggez.rs/) game framework. -* [`godot-egui`](https://github.com/setzer22/godot-egui) for [`godot-rust`](https://github.com/godot-rust/godot-rust). +* [`godot-egui`](https://github.com/setzer22/godot-egui) for [godot-rust](https://github.com/godot-rust/godot-rust). * [`nannou_egui`](https://github.com/AlexEne/nannou_egui) for [nannou](https://nannou.cc). -* [`egui-tetra`](https://crates.io/crates/egui-tetra) for [Tetra](https://crates.io/crates/tetra), a 2D game framework. -* [`egui_wgpu_backend`](https://crates.io/crates/egui_wgpu_backend) for [`wgpu`](https://crates.io/crates/wgpu) (WebGPU API). +* [`smithay-egui`](https://github.com/Smithay/smithay-egui) for [smithay](https://github.com/Smithay/smithay/). -Missing an integration for the thing you're working on? Create one, it is easy! +Missing an integration for the thing you're working on? Create one, it's easy! ### Writing your own egui integration -You need to collect [`egui::RawInput`](https://docs.rs/egui/latest/egui/struct.RawInput.html), paint [`egui::ClippedMesh`](https://docs.rs/epaint/):es and handle [`egui::Output`](https://docs.rs/egui/latest/egui/struct.Output.html). The basic structure is this: +You need to collect [`egui::RawInput`](https://docs.rs/egui/latest/egui/struct.RawInput.html), paint [`egui::ClippedMesh`](https://docs.rs/epaint/latest/epaint/struct.ClippedMesh.html):es and handle [`egui::Output`](https://docs.rs/egui/latest/egui/struct.Output.html). The basic structure is this: ``` rust let mut egui_ctx = egui::CtxRef::default(); // Game loop: loop { + // Gather input (mouse, touches, keyboard, screen size, etc): let raw_input: egui::RawInput = my_integration.gather_input(); let (output, shapes) = egui_ctx.run(raw_input, |egui_ctx| { my_app.ui(egui_ctx); // add panels, windows and widgets to `egui_ctx` here }); - let clipped_meshes = egui_ctx.tessellate(shapes); // create triangles to paint + let clipped_meshes = egui_ctx.tessellate(shapes); // creates triangles to paint + + my_integration.set_egui_textures(&output.textures_delta.set); my_integration.paint(clipped_meshes); + my_integration.free_egui_textures(&output.textures_delta.free); + my_integration.set_cursor_icon(output.cursor_icon); - // Also see `egui::Output` for more + if !output.copied_text.is_empty() { + my_integration.set_clipboard_text(output.copied_text); + } + // See `egui::Output` for more } ``` @@ -231,11 +235,12 @@ For a reference OpenGL backend, see [the `egui_glium` painter](https://github.co * egui uses premultiplied alpha, so make sure your blending function is `(ONE, ONE_MINUS_SRC_ALPHA)`. * Make sure your texture sampler is clamped (`GL_CLAMP_TO_EDGE`). -* Use an sRGBA-aware texture if available (e.g. `GL_SRGB8_ALPHA8`). - * Otherwise: remember to decode gamma in the fragment shader. -* Decode the gamma of the incoming vertex colors in your vertex shader. -* Turn on sRGBA/linear framebuffer if available (`GL_FRAMEBUFFER_SRGB`). - * Otherwise: gamma-encode the colors before you write them again. +* egui prefers linear color spaces for all blending so: + * Use an sRGBA-aware texture if available (e.g. `GL_SRGB8_ALPHA8`). + * Otherwise: remember to decode gamma in the fragment shader. + * Decode the gamma of the incoming vertex colors in your vertex shader. + * Turn on sRGBA/linear framebuffer if available (`GL_FRAMEBUFFER_SRGB`). + * Otherwise: gamma-encode the colors before you write them again. ## Why immediate mode @@ -301,7 +306,7 @@ Yes! But you need to install your own font (`.ttf` or `.otf`) using `Context::se Yes! You can customize the colors, spacing and sizes of everything. By default egui comes with a dark and a light theme. ### What about accessibility, such as screen readers? -There is experimental support for a screen reader. In [the web demo](https://emilk.github.io/egui/index.html) you can enable it in the "Backend" tab. +There is experimental support for a screen reader. In [the web demo](https://www.egui.rs/#demo) you can enable it in the "Backend" tab. Read more at . @@ -365,10 +370,13 @@ Notable contributions by: * [@AlexApps99](https://github.com/AlexApps99): [`egui_glow`](https://github.com/emilk/egui/pull/685). * [@mankinskin](https://github.com/mankinskin): [Context menus](https://github.com/emilk/egui/pull/543). * [@t18b219k](https://github.com/t18b219k): [Port glow painter to web](https://github.com/emilk/egui/pull/868). +* [@danielkeller](https://github.com/danielkeller): [`Context` refactor](https://github.com/emilk/egui/pull/1050). * And [many more](https://github.com/emilk/egui/graphs/contributors?type=a). egui is licensed under [MIT](LICENSE-MIT) OR [Apache-2.0](LICENSE-APACHE). +* The flattening algorithm for the cubic bezier curve and quadratic bezier curve is from [lyon_geom](https://docs.rs/lyon_geom/latest/lyon_geom/) + Default fonts: * `emoji-icon-font.ttf`: [Copyright (c) 2014 John Slegers](https://github.com/jslegers/emoji-icon-font) , MIT License diff --git a/deny.toml b/deny.toml new file mode 100644 index 00000000..afd1bb45 --- /dev/null +++ b/deny.toml @@ -0,0 +1,68 @@ +# https://embarkstudios.github.io/cargo-deny/ + +targets = [ + { triple = "aarch64-apple-darwin" }, + { triple = "aarch64-linux-android" }, + { triple = "x86_64-apple-darwin" }, + { triple = "x86_64-pc-windows-msvc" }, + { triple = "x86_64-unknown-linux-gnu" }, + { triple = "x86_64-unknown-linux-musl" }, +] + +[advisories] +vulnerability = "deny" +unmaintained = "warn" +yanked = "deny" +ignore = [ + "RUSTSEC-2020-0071", # https://rustsec.org/advisories/RUSTSEC-2020-0071 - chrono/time: Potential segfault in the time crate + "RUSTSEC-2020-0159", # https://rustsec.org/advisories/RUSTSEC-2020-0159 - chrono/time: Potential segfault in localtime_r invocations + "RUSTSEC-2021-0019", # https://rustsec.org/advisories/RUSTSEC-2021-0019 - xcb - is being worked on: https://github.com/rust-x-bindings/rust-xcb/issues/107 +] + +[bans] +multiple-versions = "deny" +wildcards = "allow" # at least until https://github.com/EmbarkStudios/cargo-deny/issues/241 is fixed +deny = [ + { name = "openssl" }, # prefer rustls + { name = "openssl-sys" }, # prefer rustls +] + +skip = [ + { name = "time" }, # old version pulled in by unmaintianed crate 'chrono' +] +skip-tree = [ + { name = "eframe", version = "0.16.0" }, +] + + +[licenses] +unlicensed = "deny" +allow-osi-fsf-free = "neither" +confidence-threshold = 0.92 # We want really high confidence when inferring licenses from text +copyleft = "deny" +allow = [ + "Apache-2.0 WITH LLVM-exception", # https://spdx.org/licenses/LLVM-exception.html + "Apache-2.0", # https://tldrlegal.com/license/apache-license-2.0-(apache-2.0) + "BSD-2-Clause", # https://tldrlegal.com/license/bsd-2-clause-license-(freebsd) + "BSD-3-Clause", # https://tldrlegal.com/license/bsd-3-clause-license-(revised) + "BSL-1.0", # https://tldrlegal.com/license/boost-software-license-1.0-explained + "CC0-1.0", # https://creativecommons.org/publicdomain/zero/1.0/ + "ISC", # https://tldrlegal.com/license/-isc-license + "MIT", # https://tldrlegal.com/license/mit-license + "OpenSSL", # https://www.openssl.org/source/license.html + "Zlib", # https://tldrlegal.com/license/zlib-libpng-license-(zlib) +] + +[[licenses.clarify]] +name = "webpki" +expression = "ISC" +license-files = [ + { path = "LICENSE", hash = 0x001c7e6c } +] + +[[licenses.clarify]] +name = "ring" +expression = "MIT AND ISC AND OpenSSL" +license-files = [ + { path = "LICENSE", hash = 0xbd0eed23 } +] diff --git a/docs/CNAME b/docs/CNAME new file mode 100644 index 00000000..ce62e6b7 --- /dev/null +++ b/docs/CNAME @@ -0,0 +1 @@ +www.egui.rs \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 077fb745..7cc35cfc 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,3 +1,3 @@ -This folder contains the files required for the egui web demo hosted at . +This folder contains the files required for the egui web demo hosted at . The reason the folder is called "docs" is because that is the name that GitHub requires in order to host a web page from the `master` branch of a repository. diff --git a/docs/example.html b/docs/example.html index 45e2cc3b..9caf23db 100644 --- a/docs/example.html +++ b/docs/example.html @@ -3,7 +3,7 @@ - + diff --git a/docs/index.html b/docs/index.html index 47975923..6d3a5588 100644 --- a/docs/index.html +++ b/docs/index.html @@ -46,7 +46,7 @@ transform: translate(-50%, 0%); } - .loading { + .centered { margin-right: auto; margin-left: auto; display: block; @@ -54,9 +54,10 @@ top: 50%; left: 50%; transform: translate(-50%, -50%); - color: white; + color: #f0f0f0; font-size: 24px; font-family: Ubuntu-Light, Helvetica, sans-serif; + text-align: center; } /* ---------------------------------------------- */ @@ -94,8 +95,10 @@ -
- Loading…   +
+

+ Loading… +

@@ -119,18 +122,33 @@ // We'll defer our execution until the wasm is ready to go. // Here we tell bindgen the path to the wasm file so it can start // initialization and return to us a promise when it's done. + console.debug("loading wasm…"); wasm_bindgen("./egui_demo_app_bg.wasm") .then(on_wasm_loaded) - .catch(console.error); + .catch(on_wasm_error); function on_wasm_loaded() { - console.log("loaded wasm, starting egui app…"); + console.debug("wasm loaded. starting egui app…"); // This call installs a bunch of callbacks and then returns: wasm_bindgen.start("the_canvas_id"); - console.log("egui app started."); - document.getElementById("loading").remove(); + console.debug("egui app started."); + document.getElementById("center_text").remove(); + } + + function on_wasm_error(error) { + console.error("Failed to start egui: " + error); + document.getElementById("center_text").innerHTML = ` +

+ An error occurred loading egui +

+

+ ${error} +

+

+ Make sure you use a modern browser with WebGL and WASM enabled. +

`; } diff --git a/eframe/CHANGELOG.md b/eframe/CHANGELOG.md index a6480965..5b64eafa 100644 --- a/eframe/CHANGELOG.md +++ b/eframe/CHANGELOG.md @@ -1,12 +1,19 @@ # Changelog for eframe All notable changes to the `eframe` and `epi` crates. -NOTE: [`egui_web`](egui_web/CHANGELOG.md), [`egui-winit`](egui-winit/CHANGELOG.md), [`egui_glium`](egui_glium/CHANGELOG.md), and [`egui_glow`](egui_glow/CHANGELOG.md) have their own changelogs! +NOTE: [`egui_web`](../egui_web/CHANGELOG.md), [`egui-winit`](../egui-winit/CHANGELOG.md), [`egui_glium`](../egui_glium/CHANGELOG.md), and [`egui_glow`](../egui_glow/CHANGELOG.md) have their own changelogs! ## Unreleased +* Removed `Frame::alloc_texture`. Use `egui::Context::load_texture` instead ([#1110](https://github.com/emilk/egui/pull/1110)). * The default native backend is now `egui_glow` (instead of `egui_glium`) ([#1020](https://github.com/emilk/egui/pull/1020)). * The default web painter is now `egui_glow` (instead of WebGL) ([#1020](https://github.com/emilk/egui/pull/1020)). +* Automatically detect and apply dark or light mode from system ([#1045](https://github.com/emilk/egui/pull/1045)). +* Fix horizontal scrolling direction on Linux. +* Added `App::on_exit_event` ([#1038](https://github.com/emilk/egui/pull/1038)) +* Added `NativeOptions::initial_window_pos`. +* Shift-scroll will now result in horizontal scrolling on all platforms ([#1136](https://github.com/emilk/egui/pull/1136)). +* Log using the `tracing` crate. Log to stdout by adding `tracing_subscriber::fmt::init();` to your `main` ([#1192](https://github.com/emilk/egui/pull/1192)). ## 0.16.0 - 2021-12-29 diff --git a/eframe/Cargo.toml b/eframe/Cargo.toml index a01d380a..35265b99 100644 --- a/eframe/Cargo.toml +++ b/eframe/Cargo.toml @@ -23,23 +23,6 @@ all-features = true [lib] -[dependencies] -egui = { version = "0.16.0", path = "../egui", default-features = false } -epi = { version = "0.16.0", path = "../epi" } - -# native: -[target.'cfg(not(target_arch = "wasm32"))'.dependencies] -egui-winit = { version = "0.16.0", path = "../egui-winit", default-features = false } -egui_glium = { version = "0.16.0", path = "../egui_glium", default-features = false, features = ["clipboard", "epi", "links"], optional = true } -egui_glow = { version = "0.16.0", path = "../egui_glow", default-features = false, features = ["clipboard", "epi", "links", "winit"], optional = true } - -# web: -[target.'cfg(target_arch = "wasm32")'.dependencies] -egui_web = { version = "0.16.0", path = "../egui_web", default-features = false, features = ["glow"] } - -[dev-dependencies] -image = { version = "0.23", default-features = false, features = ["png"] } -rfd = "0.6" [features] default = ["default_fonts", "egui_glow"] @@ -57,9 +40,31 @@ persistence = [ "epi/persistence", ] -# experimental support for a screen reader +# enable screen reader support (requires `ctx.options().screen_reader = true;`) screen_reader = [ # we cannot touch egui_glium or egui_glow here due to https://github.com/rust-lang/cargo/issues/8832 "egui-winit/screen_reader", "egui_web/screen_reader", ] + + +[dependencies] +egui = { version = "0.16.0", path = "../egui", default-features = false } +epi = { version = "0.16.0", path = "../epi" } + +# native: +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +egui-winit = { version = "0.16.0", path = "../egui-winit", default-features = false } +egui_glium = { version = "0.16.0", path = "../egui_glium", default-features = false, features = ["clipboard", "epi", "links"], optional = true } +egui_glow = { version = "0.16.0", path = "../egui_glow", default-features = false, features = ["clipboard", "epi", "links", "winit"], optional = true } + +# web: +[target.'cfg(target_arch = "wasm32")'.dependencies] +egui_web = { version = "0.16.0", path = "../egui_web", default-features = false, features = ["glow"] } + +[dev-dependencies] +ehttp = "0.2" +image = { version = "0.24", default-features = false, features = ["jpeg", "png"] } +poll-promise = "0.1" +rfd = "0.7" + diff --git a/eframe/examples/confirm_exit.rs b/eframe/examples/confirm_exit.rs new file mode 100644 index 00000000..f1e8a359 --- /dev/null +++ b/eframe/examples/confirm_exit.rs @@ -0,0 +1,49 @@ +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release + +use eframe::{egui, epi}; + +#[derive(Default)] +struct MyApp { + can_exit: bool, + is_exiting: bool, +} + +impl epi::App for MyApp { + fn name(&self) -> &str { + "Confirm exit" + } + + fn on_exit_event(&mut self) -> bool { + self.is_exiting = true; + self.can_exit + } + + fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) { + egui::CentralPanel::default().show(ctx, |ui| { + ui.heading("Try to close the window"); + }); + + if self.is_exiting { + egui::Window::new("Do you want to quit?") + .collapsible(false) + .resizable(false) + .show(ctx, |ui| { + ui.horizontal(|ui| { + if ui.button("Yes!").clicked() { + self.can_exit = true; + frame.quit(); + } + + if ui.button("Not yet").clicked() { + self.is_exiting = false; + } + }); + }); + } + } +} + +fn main() { + let options = eframe::NativeOptions::default(); + eframe::run_native(Box::new(MyApp::default()), options); +} diff --git a/eframe/examples/custom_font.rs b/eframe/examples/custom_font.rs index 199521da..8ba2ced4 100644 --- a/eframe/examples/custom_font.rs +++ b/eframe/examples/custom_font.rs @@ -19,7 +19,7 @@ impl epi::App for MyApp { fn setup( &mut self, - ctx: &egui::CtxRef, + ctx: &egui::Context, _frame: &epi::Frame, _storage: Option<&dyn epi::Storage>, ) { @@ -35,14 +35,14 @@ impl epi::App for MyApp { // Put my font first (highest priority) for proportional text: fonts - .fonts_for_family + .families .entry(egui::FontFamily::Proportional) .or_default() .insert(0, "my_font".to_owned()); // Put my font as last fallback for monospace: fonts - .fonts_for_family + .families .entry(egui::FontFamily::Monospace) .or_default() .push("my_font".to_owned()); @@ -51,7 +51,7 @@ impl epi::App for MyApp { ctx.set_fonts(fonts); } - fn update(&mut self, ctx: &egui::CtxRef, _frame: &epi::Frame) { + fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) { egui::CentralPanel::default().show(ctx, |ui| { ui.heading("egui using custom fonts"); ui.text_edit_multiline(&mut self.text); diff --git a/eframe/examples/download_image.rs b/eframe/examples/download_image.rs new file mode 100644 index 00000000..e350ac56 --- /dev/null +++ b/eframe/examples/download_image.rs @@ -0,0 +1,81 @@ +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release + +use eframe::{egui, epi}; +use poll_promise::Promise; + +fn main() { + let options = eframe::NativeOptions::default(); + eframe::run_native(Box::new(MyApp::default()), options); +} + +#[derive(Default)] +struct MyApp { + /// `None` when download hasn't started yet. + promise: Option>>, +} + +impl epi::App for MyApp { + fn name(&self) -> &str { + "Download and show an image with eframe/egui" + } + + fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) { + let promise = self.promise.get_or_insert_with(|| { + // Begin download. + // We download the image using `ehttp`, a library that works both in WASM and on native. + // We use the `poll-promise` library to communicate with the UI thread. + let ctx = ctx.clone(); + let frame = frame.clone(); + let (sender, promise) = Promise::new(); + let request = ehttp::Request::get("https://picsum.photos/seed/1.759706314/1024"); + ehttp::fetch(request, move |response| { + frame.request_repaint(); // wake up UI thread + let texture = response.and_then(|response| parse_response(&ctx, response)); + sender.send(texture); // send the results back to the UI thread. + }); + promise + }); + + egui::CentralPanel::default().show(ctx, |ui| match promise.ready() { + None => { + ui.add(egui::Spinner::new()); // still loading + } + Some(Err(err)) => { + ui.colored_label(egui::Color32::RED, err); // something went wrong + } + Some(Ok(texture)) => { + let mut size = texture.size_vec2(); + size *= (ui.available_width() / size.x).min(1.0); + size *= (ui.available_height() / size.y).min(1.0); + ui.image(texture, size); + } + }); + } +} + +fn parse_response( + ctx: &egui::Context, + response: ehttp::Response, +) -> Result { + let content_type = response.content_type().unwrap_or_default(); + if content_type.starts_with("image/") { + let image = load_image(&response.bytes).map_err(|err| err.to_string())?; + Ok(ctx.load_texture("my-image", image)) + } else { + Err(format!( + "Expected image, found content-type {:?}", + content_type + )) + } +} + +fn load_image(image_data: &[u8]) -> Result { + let image = image::load_from_memory(image_data)?; + let size = [image.width() as _, image.height() as _]; + let image_buffer = image.to_rgba8(); + let pixels = image_buffer.as_flat_samples(); + Ok(egui::ColorImage::from_rgba_unmultiplied( + size, + pixels.as_slice(), + )) +} diff --git a/eframe/examples/file_dialog.rs b/eframe/examples/file_dialog.rs index b9767e3e..f4b2f5a9 100644 --- a/eframe/examples/file_dialog.rs +++ b/eframe/examples/file_dialog.rs @@ -13,7 +13,7 @@ impl epi::App for MyApp { "Native file dialogs and drag-and-drop files" } - fn update(&mut self, ctx: &egui::CtxRef, _frame: &epi::Frame) { + fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) { egui::CentralPanel::default().show(ctx, |ui| { ui.label("Drag-and-drop files onto the window!"); @@ -57,7 +57,7 @@ impl epi::App for MyApp { } impl MyApp { - fn detect_files_being_dropped(&mut self, ctx: &egui::CtxRef) { + fn detect_files_being_dropped(&mut self, ctx: &egui::Context) { use egui::*; // Preview hovering files: @@ -82,7 +82,7 @@ impl MyApp { screen_rect.center(), Align2::CENTER_CENTER, text, - TextStyle::Heading, + TextStyle::Heading.resolve(&ctx.style()), Color32::WHITE, ); } diff --git a/eframe/examples/hello_world.rs b/eframe/examples/hello_world.rs index 9a944929..7ec61fba 100644 --- a/eframe/examples/hello_world.rs +++ b/eframe/examples/hello_world.rs @@ -21,7 +21,7 @@ impl epi::App for MyApp { "My egui App" } - fn update(&mut self, ctx: &egui::CtxRef, frame: &epi::Frame) { + fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) { let Self { name, age } = self; egui::CentralPanel::default().show(ctx, |ui| { diff --git a/eframe/examples/image.rs b/eframe/examples/image.rs index 91e0f4f5..a47e6c5b 100644 --- a/eframe/examples/image.rs +++ b/eframe/examples/image.rs @@ -4,7 +4,7 @@ use eframe::{egui, epi}; #[derive(Default)] struct MyApp { - texture: Option<(egui::Vec2, egui::TextureId)>, + texture: Option, } impl epi::App for MyApp { @@ -12,31 +12,18 @@ impl epi::App for MyApp { "Show an image with eframe/egui" } - fn update(&mut self, ctx: &egui::CtxRef, frame: &epi::Frame) { - if self.texture.is_none() { - // Load the image: - let image_data = include_bytes!("rust-logo-256x256.png"); - use image::GenericImageView; - let image = image::load_from_memory(image_data).expect("Failed to load image"); - let image_buffer = image.to_rgba8(); - let size = [image.width() as usize, image.height() as usize]; - let pixels = image_buffer.into_vec(); - let image = epi::Image::from_rgba_unmultiplied(size, &pixels); - - // Allocate a texture: - let texture = frame.alloc_texture(image); - let size = egui::Vec2::new(size[0] as f32, size[1] as f32); - self.texture = Some((size, texture)); - } + fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) { + let texture: &egui::TextureHandle = self.texture.get_or_insert_with(|| { + let image = load_image(include_bytes!("rust-logo-256x256.png")).unwrap(); + ctx.load_texture("rust-logo", image) + }); egui::CentralPanel::default().show(ctx, |ui| { - if let Some((size, texture)) = self.texture { - ui.heading("This is an image:"); - ui.image(texture, size); + ui.heading("This is an image:"); + ui.image(texture, texture.size_vec2()); - ui.heading("This is an image you can click:"); - ui.add(egui::ImageButton::new(texture, size)); - } + ui.heading("This is an image you can click:"); + ui.add(egui::ImageButton::new(texture, texture.size_vec2())); }); } } @@ -45,3 +32,14 @@ fn main() { let options = eframe::NativeOptions::default(); eframe::run_native(Box::new(MyApp::default()), options); } + +fn load_image(image_data: &[u8]) -> Result { + let image = image::load_from_memory(image_data)?; + let size = [image.width() as _, image.height() as _]; + let image_buffer = image.to_rgba8(); + let pixels = image_buffer.as_flat_samples(); + Ok(egui::ColorImage::from_rgba_unmultiplied( + size, + pixels.as_slice(), + )) +} diff --git a/eframe/src/lib.rs b/eframe/src/lib.rs index 2fff7519..d0ba574d 100644 --- a/eframe/src/lib.rs +++ b/eframe/src/lib.rs @@ -26,7 +26,7 @@ //! "My egui App" //! } //! -//! fn update(&mut self, ctx: &egui::CtxRef, frame: &epi::Frame) { +//! fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) { //! egui::CentralPanel::default().show(ctx, |ui| { //! ui.heading("Hello World!"); //! }); @@ -129,7 +129,7 @@ pub fn start_web(canvas_id: &str, app: Box) -> Result<(), wasm_bin /// "My egui App" /// } /// -/// fn update(&mut self, ctx: &egui::CtxRef, frame: &epi::Frame) { +/// fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) { /// egui::CentralPanel::default().show(ctx, |ui| { /// ui.heading("Hello World!"); /// }); @@ -160,7 +160,7 @@ pub fn run_native(app: Box, native_options: epi::NativeOptions) -> /// "My egui App" /// } /// -/// fn update(&mut self, ctx: &egui::CtxRef, frame: &epi::Frame) { +/// fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) { /// egui::CentralPanel::default().show(ctx, |ui| { /// ui.heading("Hello World!"); /// }); diff --git a/egui-winit/CHANGELOG.md b/egui-winit/CHANGELOG.md index e2eb6621..80de1eaa 100644 --- a/egui-winit/CHANGELOG.md +++ b/egui-winit/CHANGELOG.md @@ -4,7 +4,12 @@ All notable changes to the `egui-winit` integration will be noted in this file. ## Unreleased +* Fixed horizontal scrolling direction on Linux. +* Automatically detect and apply dark or light mode from system ([#1045](https://github.com/emilk/egui/pull/1045)). * Replaced `std::time::Instant` with `instant::Instant` for WebAssembly compatability ([#1023](https://github.com/emilk/egui/pull/1023)) +* Shift-scroll will now result in horizontal scrolling on all platforms ([#1136](https://github.com/emilk/egui/pull/1136)). +* Require knowledge about max texture side (e.g. `GL_MAX_TEXTURE_SIZE`)) ([#1154](https://github.com/emilk/egui/pull/1154)). +* Fixed `enable_drag` for Windows. Now called only once just after left click ([#1108](https://github.com/emilk/egui/pull/1108)). ## 0.16.0 - 2021-12-29 diff --git a/egui-winit/Cargo.toml b/egui-winit/Cargo.toml index 917a3ae5..bbb0fbfa 100644 --- a/egui-winit/Cargo.toml +++ b/egui-winit/Cargo.toml @@ -21,22 +21,9 @@ include = [ [package.metadata.docs.rs] all-features = true -[dependencies] -egui = { version = "0.16.0", path = "../egui", default-features = false, features = ["single_threaded"] } -instant = { version = "0.1", features = ["wasm-bindgen"] } -winit = "0.26" - -epi = { version = "0.16.0", path = "../epi", optional = true } - -copypasta = { version = "0.7", optional = true } -serde = { version = "1.0", optional = true, features = ["derive"] } -webbrowser = { version = "0.5", optional = true } - -# feature screen_reader -tts = { version = "0.19", optional = true } [features] -default = ["clipboard", "links"] +default = ["clipboard", "dark-light", "links"] # enable cut/copy/paste to OS clipboard. # if disabled a clipboard will be simulated so you can still copy/paste within the egui app. @@ -48,8 +35,25 @@ links = ["webbrowser"] # experimental support for a screen reader screen_reader = ["tts"] -persistence = ["egui/serialize", "serde"] +persistence = ["egui/serialize", "serde"] # can't add epi/persistence here because of https://github.com/rust-lang/cargo/issues/8832 serialize = ["egui/serialize", "serde"] # implement bytemuck on most types. convert_bytemuck = ["egui/convert_bytemuck"] + + +[dependencies] +egui = { version = "0.16.0", path = "../egui", default-features = false, features = ["single_threaded", "tracing"] } +instant = { version = "0.1", features = ["wasm-bindgen"] } +tracing = "0.1" +winit = "0.26.1" + +epi = { version = "0.16.0", path = "../epi", optional = true } + +copypasta = { version = "0.7", optional = true } +dark-light = { version = "0.2.1", optional = true } # detect dark mode system preference +serde = { version = "1.0", optional = true, features = ["derive"] } +webbrowser = { version = "0.5", optional = true } + +# feature screen_reader +tts = { version = "0.20", optional = true } diff --git a/egui-winit/src/clipboard.rs b/egui-winit/src/clipboard.rs index 4a70d47f..d6e29e33 100644 --- a/egui-winit/src/clipboard.rs +++ b/egui-winit/src/clipboard.rs @@ -29,7 +29,7 @@ impl Clipboard { match clipboard.get_contents() { Ok(contents) => Some(contents), Err(err) => { - eprintln!("Paste error: {}", err); + tracing::error!("Paste error: {}", err); None } } @@ -46,7 +46,7 @@ impl Clipboard { if let Some(clipboard) = &mut self.copypasta { use copypasta::ClipboardProvider as _; if let Err(err) = clipboard.set_contents(text) { - eprintln!("Copy/Cut error: {}", err); + tracing::error!("Copy/Cut error: {}", err); } } @@ -62,7 +62,7 @@ fn init_copypasta() -> Option { match copypasta::ClipboardContext::new() { Ok(clipboard) => Some(clipboard), Err(err) => { - eprintln!("Failed to initialize clipboard: {}", err); + tracing::error!("Failed to initialize clipboard: {}", err); None } } diff --git a/egui-winit/src/epi.rs b/egui-winit/src/epi.rs index badea97a..70d13d32 100644 --- a/egui-winit/src/epi.rs +++ b/egui-winit/src/epi.rs @@ -1,29 +1,62 @@ +use egui::Vec2; +use winit::dpi::LogicalSize; + +pub fn points_to_size(points: Vec2) -> LogicalSize { + winit::dpi::LogicalSize { + width: points.x as f64, + height: points.y as f64, + } +} + pub fn window_builder( native_options: &epi::NativeOptions, window_settings: &Option, ) -> winit::window::WindowBuilder { - let window_icon = native_options.icon_data.clone().and_then(load_icon); + let epi::NativeOptions { + always_on_top, + maximized, + decorated, + drag_and_drop_support, + icon_data, + initial_window_pos, + initial_window_size, + min_window_size, + max_window_size, + resizable, + transparent, + } = native_options; + + let window_icon = icon_data.clone().and_then(load_icon); let mut window_builder = winit::window::WindowBuilder::new() - .with_always_on_top(native_options.always_on_top) - .with_maximized(native_options.maximized) - .with_decorations(native_options.decorated) - .with_resizable(native_options.resizable) - .with_transparent(native_options.transparent) + .with_always_on_top(*always_on_top) + .with_maximized(*maximized) + .with_decorations(*decorated) + .with_resizable(*resizable) + .with_transparent(*transparent) .with_window_icon(window_icon); - window_builder = - window_builder_drag_and_drop(window_builder, native_options.drag_and_drop_support); + if let Some(min_size) = *min_window_size { + window_builder = window_builder.with_min_inner_size(points_to_size(min_size)); + } + if let Some(max_size) = *max_window_size { + window_builder = window_builder.with_max_inner_size(points_to_size(max_size)); + } - let initial_size_points = native_options.initial_window_size; + window_builder = window_builder_drag_and_drop(window_builder, *drag_and_drop_support); if let Some(window_settings) = window_settings { window_builder = window_settings.initialize_window(window_builder); - } else if let Some(initial_size_points) = initial_size_points { - window_builder = window_builder.with_inner_size(winit::dpi::LogicalSize { - width: initial_size_points.x as f64, - height: initial_size_points.y as f64, - }); + } else { + if let Some(pos) = *initial_window_pos { + window_builder = window_builder.with_position(winit::dpi::PhysicalPosition { + x: pos.x as f64, + y: pos.y as f64, + }); + } + if let Some(initial_window_size) = *initial_window_size { + window_builder = window_builder.with_inner_size(points_to_size(initial_window_size)); + } } window_builder @@ -55,10 +88,9 @@ pub fn handle_app_output( window: &winit::window::Window, current_pixels_per_point: f32, app_output: epi::backend::AppOutput, -) -> epi::backend::TexAllocationData { +) { let epi::backend::AppOutput { quit: _, - tex_allocation_data, window_size, window_title, decorated, @@ -86,8 +118,6 @@ pub fn handle_app_output( if drag_window { let _ = window.drag_window(); } - - tex_allocation_data } // ---------------------------------------------------------------------------- @@ -191,30 +221,34 @@ impl Persistence { pub struct EpiIntegration { frame: epi::Frame, persistence: crate::epi::Persistence, - pub egui_ctx: egui::CtxRef, + pub egui_ctx: egui::Context, egui_winit: crate::State, pub app: Box, /// When set, it is time to quit quit: bool, + can_drag_window: bool, } impl EpiIntegration { pub fn new( integration_name: &'static str, + max_texture_side: usize, window: &winit::window::Window, repaint_signal: std::sync::Arc, persistence: crate::epi::Persistence, app: Box, ) -> Self { - let egui_ctx = egui::CtxRef::default(); + let egui_ctx = egui::Context::default(); *egui_ctx.memory() = persistence.load_memory().unwrap_or_default(); + let prefer_dark_mode = prefer_dark_mode(); + let frame = epi::Frame::new(epi::backend::FrameData { info: epi::IntegrationInfo { name: integration_name, web_info: None, - prefer_dark_mode: None, // TODO: figure out system default + prefer_dark_mode, cpu_usage: None, native_pixels_per_point: Some(crate::native_pixels_per_point(window)), }, @@ -222,13 +256,20 @@ impl EpiIntegration { repaint_signal, }); + if prefer_dark_mode == Some(true) { + egui_ctx.set_visuals(egui::Visuals::dark()); + } else { + egui_ctx.set_visuals(egui::Visuals::light()); + } + let mut slf = Self { frame, persistence, egui_ctx, - egui_winit: crate::State::new(window), + egui_winit: crate::State::new(max_texture_side, window), app, quit: false, + can_drag_window: false, }; slf.setup(window); @@ -243,17 +284,19 @@ impl EpiIntegration { self.app .setup(&self.egui_ctx, &self.frame, self.persistence.storage()); let app_output = self.frame.take_app_output(); - self.quit |= app_output.quit; - let tex_alloc_data = - crate::epi::handle_app_output(window, self.egui_ctx.pixels_per_point(), app_output); - self.frame.lock().output.tex_allocation_data = tex_alloc_data; // Do it later + + if app_output.quit { + self.quit = self.app.on_exit_event(); + } + + crate::epi::handle_app_output(window, self.egui_ctx.pixels_per_point(), app_output); } fn warm_up(&mut self, window: &winit::window::Window) { - let saved_memory = self.egui_ctx.memory().clone(); + let saved_memory: egui::Memory = self.egui_ctx.memory().clone(); self.egui_ctx.memory().set_everything_is_visible(true); - let (_, tex_alloc_data, _) = self.update(window); - self.frame.lock().output.tex_allocation_data = tex_alloc_data; // handle it next frame + let (_, textures_delta, _) = self.update(window); + self.egui_ctx.output().textures_delta = textures_delta; // Handle it next frame *self.egui_ctx.memory() = saved_memory; // We don't want to remember that windows were huge. self.egui_ctx.clear_animations(); } @@ -264,8 +307,19 @@ impl EpiIntegration { } pub fn on_event(&mut self, event: &winit::event::WindowEvent<'_>) { - use winit::event::WindowEvent; - self.quit |= matches!(event, WindowEvent::CloseRequested | WindowEvent::Destroyed); + use winit::event::{ElementState, MouseButton, WindowEvent}; + + match event { + WindowEvent::CloseRequested => self.quit = self.app.on_exit_event(), + WindowEvent::Destroyed => self.quit = true, + WindowEvent::MouseInput { + button: MouseButton::Left, + state: ElementState::Pressed, + .. + } => self.can_drag_window = true, + _ => {} + } + self.egui_winit.on_event(&self.egui_ctx, event); } @@ -273,11 +327,7 @@ impl EpiIntegration { pub fn update( &mut self, window: &winit::window::Window, - ) -> ( - bool, - epi::backend::TexAllocationData, - Vec, - ) { + ) -> (bool, egui::TexturesDelta, Vec) { let frame_start = instant::Instant::now(); let raw_input = self.egui_winit.take_egui_input(window); @@ -286,18 +336,24 @@ impl EpiIntegration { }); let needs_repaint = egui_output.needs_repaint; - self.egui_winit + let textures_delta = self + .egui_winit .handle_output(window, &self.egui_ctx, egui_output); - let app_output = self.frame.take_app_output(); - self.quit |= app_output.quit; - let tex_allocation_data = - crate::epi::handle_app_output(window, self.egui_ctx.pixels_per_point(), app_output); + let mut app_output = self.frame.take_app_output(); + app_output.drag_window &= self.can_drag_window; // Necessary on Windows; see https://github.com/emilk/egui/pull/1108 + self.can_drag_window = false; + + if app_output.quit { + self.quit = self.app.on_exit_event(); + } + + crate::epi::handle_app_output(window, self.egui_ctx.pixels_per_point(), app_output); let frame_time = (instant::Instant::now() - frame_start).as_secs_f64() as f32; self.frame.lock().info.cpu_usage = Some(frame_time); - (needs_repaint, tex_allocation_data, shapes) + (needs_repaint, textures_delta, shapes) } pub fn maybe_autosave(&mut self, window: &winit::window::Window) { @@ -311,3 +367,16 @@ impl EpiIntegration { .save(&mut *self.app, &self.egui_ctx, window); } } + +#[cfg(feature = "dark-light")] +fn prefer_dark_mode() -> Option { + match dark_light::detect() { + dark_light::Mode::Dark => Some(true), + dark_light::Mode::Light => Some(false), + } +} + +#[cfg(not(feature = "dark-light"))] +fn prefer_dark_mode() -> Option { + None +} diff --git a/egui-winit/src/lib.rs b/egui-winit/src/lib.rs index 1fa2d22d..6e19f435 100644 --- a/egui-winit/src/lib.rs +++ b/egui-winit/src/lib.rs @@ -129,17 +129,22 @@ pub struct State { } impl State { - /// Initialize with the native `pixels_per_point` (dpi scaling). - pub fn new(window: &winit::window::Window) -> Self { - Self::from_pixels_per_point(native_pixels_per_point(window)) + /// Initialize with: + /// * `max_texture_side`: e.g. `GL_MAX_TEXTURE_SIZE` + /// * the native `pixels_per_point` (dpi scaling). + pub fn new(max_texture_side: usize, window: &winit::window::Window) -> Self { + Self::from_pixels_per_point(max_texture_side, native_pixels_per_point(window)) } - /// Initialize with a given dpi scaling. - pub fn from_pixels_per_point(pixels_per_point: f32) -> Self { + /// Initialize with: + /// * `max_texture_side`: e.g. `GL_MAX_TEXTURE_SIZE` + /// * the given `pixels_per_point` (dpi scaling). + pub fn from_pixels_per_point(max_texture_side: usize, pixels_per_point: f32) -> Self { Self { start_time: instant::Instant::now(), egui_input: egui::RawInput { pixels_per_point: Some(pixels_per_point), + max_texture_side, ..Default::default() }, pointer_pos_in_points: None, @@ -453,17 +458,19 @@ impl State { egui::vec2(delta.x as f32, delta.y as f32) / self.pixels_per_point() } }; - if cfg!(target_os = "macos") { - delta.x *= -1.0; // until https://github.com/rust-windowing/winit/pull/2105 is merged and released - } - if cfg!(target_os = "windows") { - delta.x *= -1.0; // until https://github.com/rust-windowing/winit/pull/2101 is merged and released - } + + delta.x *= -1.0; // Winit has inverted hscroll. Remove this line when we update winit after https://github.com/rust-windowing/winit/pull/2105 is merged and released if self.egui_input.modifiers.ctrl || self.egui_input.modifiers.command { // Treat as zoom instead: let factor = (delta.y / 200.0).exp(); self.egui_input.events.push(egui::Event::Zoom(factor)); + } else if self.egui_input.modifiers.shift { + // Treat as horizontal scrolling. + // Note: one Mac we already get horizontal scroll events when shift is down. + self.egui_input + .events + .push(egui::Event::Scroll(egui::vec2(delta.x + delta.y, 0.0))); } else { self.egui_input.events.push(egui::Event::Scroll(delta)); } @@ -484,7 +491,7 @@ impl State { if let Some(contents) = self.clipboard.get() { self.egui_input .events - .push(egui::Event::Text(contents.replace("\r\n", "\n"))); + .push(egui::Event::Paste(contents.replace("\r\n", "\n"))); } } } @@ -512,26 +519,39 @@ impl State { window: &winit::window::Window, egui_ctx: &egui::Context, output: egui::Output, - ) { - self.current_pixels_per_point = egui_ctx.pixels_per_point(); // someone can have changed it to scale the UI - - if egui_ctx.memory().options.screen_reader { + ) -> egui::TexturesDelta { + if egui_ctx.options().screen_reader { self.screen_reader.speak(&output.events_description()); } - self.set_cursor_icon(window, output.cursor_icon); + let egui::Output { + cursor_icon, + open_url, + copied_text, + needs_repaint: _, // needs to be handled elsewhere + events: _, // handled above + mutable_text_under_cursor: _, // only used in egui_web + text_cursor_pos, + textures_delta, + } = output; - if let Some(open) = output.open_url { - open_url(&open.url); + self.current_pixels_per_point = egui_ctx.pixels_per_point(); // someone can have changed it to scale the UI + + self.set_cursor_icon(window, cursor_icon); + + if let Some(open_url) = open_url { + open_url_in_browser(&open_url.url); } - if !output.copied_text.is_empty() { - self.clipboard.set(output.copied_text); + if !copied_text.is_empty() { + self.clipboard.set(copied_text); } - if let Some(egui::Pos2 { x, y }) = output.text_cursor_pos { + if let Some(egui::Pos2 { x, y }) = text_cursor_pos { window.set_ime_position(winit::dpi::LogicalPosition { x, y }); } + + textures_delta } fn set_cursor_icon(&mut self, window: &winit::window::Window, cursor_icon: egui::CursorIcon) { @@ -554,15 +574,15 @@ impl State { } } -fn open_url(_url: &str) { +fn open_url_in_browser(_url: &str) { #[cfg(feature = "webbrowser")] if let Err(err) = webbrowser::open(_url) { - eprintln!("Failed to open url: {}", err); + tracing::warn!("Failed to open url: {}", err); } #[cfg(not(feature = "webbrowser"))] { - eprintln!("Cannot open url - feature \"links\" not enabled."); + tracing::warn!("Cannot open url - feature \"links\" not enabled."); } } diff --git a/egui-winit/src/screen_reader.rs b/egui-winit/src/screen_reader.rs index 9397d2ea..e3ac02b1 100644 --- a/egui-winit/src/screen_reader.rs +++ b/egui-winit/src/screen_reader.rs @@ -15,11 +15,11 @@ impl Default for ScreenReader { fn default() -> Self { let tts = match tts::Tts::default() { Ok(screen_reader) => { - eprintln!("Initialized screen reader."); + tracing::debug!("Initialized screen reader."); Some(screen_reader) } Err(err) => { - eprintln!("Failed to load screen reader: {}", err); + tracing::warn!("Failed to load screen reader: {}", err); None } }; @@ -38,10 +38,10 @@ impl ScreenReader { return; } if let Some(tts) = &mut self.tts { - eprintln!("Speaking: {:?}", text); + tracing::debug!("Speaking: {:?}", text); let interrupt = true; if let Err(err) = tts.speak(text, interrupt) { - eprintln!("Failed to read: {}", err); + tracing::warn!("Failed to read: {}", err); } } } diff --git a/egui/Cargo.toml b/egui/Cargo.toml index 6f9ed8b2..67591cf2 100644 --- a/egui/Cargo.toml +++ b/egui/Cargo.toml @@ -23,13 +23,6 @@ all-features = true [lib] -[dependencies] -epaint = { version = "0.16.0", path = "../epaint", default-features = false } - -ahash = "0.7" -nohash-hasher = "0.2" -ron = { version = "0.7", optional = true } -serde = { version = "1", features = ["derive", "rc"], optional = true } [features] default = ["default_fonts", "single_threaded"] @@ -37,6 +30,9 @@ default = ["default_fonts", "single_threaded"] # add compatibility with https://crates.io/crates/cint cint = ["epaint/cint"] +# implement bytemuck on most types. +convert_bytemuck = ["epaint/convert_bytemuck"] + # If set, egui will use `include_bytes!` to bundle some fonts. # If you plan on specifying your own fonts you may disable this feature. default_fonts = ["epaint/default_fonts"] @@ -55,10 +51,20 @@ persistence = ["serde", "epaint/serialize", "ron"] # implement serde on most types. serialize = ["serde", "epaint/serialize"] -# implement bytemuck on most types. -convert_bytemuck = ["epaint/convert_bytemuck"] - # multi_threaded is only needed if you plan to use the same egui::Context # from multiple threads. It comes with a minor performance impact. single_threaded = ["epaint/single_threaded"] multi_threaded = ["epaint/multi_threaded"] + + +[dependencies] +epaint = { version = "0.16.0", path = "../epaint", default-features = false } + +ahash = "0.7" +nohash-hasher = "0.2" + +# Optional: +ron = { version = "0.7", optional = true } +serde = { version = "1", features = ["derive", "rc"], optional = true } +# egui doesn't log much, but when it does, it uses `tracing` +tracing = { version = "0.1", optional = true } diff --git a/egui/examples/README.md b/egui/examples/README.md index 44a9fe08..33da866c 100644 --- a/egui/examples/README.md +++ b/egui/examples/README.md @@ -1,5 +1,5 @@ There are no stand-alone egui examples, because egui is not stand-alone! -There are plenty of examples in [the online demo](https://emilk.github.io/egui/). You can find the source code for it at . +There are plenty of examples in [the online demo](https://www.egui.rs/#demo). You can find the source code for it at . If you are using `eframe`, check out [the `eframe` examples](https://github.com/emilk/egui/tree/master/eframe/examples) and [the `eframe` template repository](https://github.com/emilk/eframe_template/). diff --git a/egui/src/animation_manager.rs b/egui/src/animation_manager.rs index 8a6795f5..3cc273bf 100644 --- a/egui/src/animation_manager.rs +++ b/egui/src/animation_manager.rs @@ -3,6 +3,7 @@ use crate::{emath::remap_clamp, Id, IdMap, InputState}; #[derive(Clone, Default)] pub(crate) struct AnimationManager { bools: IdMap, + values: IdMap, } #[derive(Clone, Debug)] @@ -12,6 +13,14 @@ struct BoolAnim { toggle_time: f64, } +#[derive(Clone, Debug)] +struct ValueAnim { + from_value: f32, + to_value: f32, + /// when did `value` last toggle? + toggle_time: f64, +} + impl AnimationManager { /// See `Context::animate_bool` for documentation pub fn animate_bool( @@ -56,4 +65,47 @@ impl AnimationManager { } } } + + pub fn animate_value( + &mut self, + input: &InputState, + animation_time: f32, + id: Id, + value: f32, + ) -> f32 { + match self.values.get_mut(&id) { + None => { + self.values.insert( + id, + ValueAnim { + from_value: value, + to_value: value, + toggle_time: -f64::INFINITY, // long time ago + }, + ); + value + } + Some(anim) => { + let time_since_toggle = (input.time - anim.toggle_time) as f32; + // On the frame we toggle we don't want to return the old value, + // so we extrapolate forwards: + let time_since_toggle = time_since_toggle + input.predicted_dt; + let current_value = remap_clamp( + time_since_toggle, + 0.0..=animation_time, + anim.from_value..=anim.to_value, + ); + if anim.to_value != value { + anim.from_value = current_value; //start new animation from current position of playing animation + anim.to_value = value; + anim.toggle_time = input.time; + } + if animation_time == 0.0 { + anim.from_value = value; + anim.to_value = value; + } + current_value + } + } + } } diff --git a/egui/src/containers/area.rs b/egui/src/containers/area.rs index cb5fc831..9ff25d5f 100644 --- a/egui/src/containers/area.rs +++ b/egui/src/containers/area.rs @@ -176,7 +176,7 @@ pub(crate) struct Prepared { impl Area { pub fn show( self, - ctx: &CtxRef, + ctx: &Context, add_contents: impl FnOnce(&mut Ui) -> R, ) -> InnerResponse { let prepared = self.begin(ctx); @@ -186,7 +186,7 @@ impl Area { InnerResponse { inner, response } } - pub(crate) fn begin(self, ctx: &CtxRef) -> Prepared { + pub(crate) fn begin(self, ctx: &Context) -> Prepared { let Area { id, movable, @@ -234,7 +234,7 @@ impl Area { } } - pub fn show_open_close_animation(&self, ctx: &CtxRef, frame: &Frame, is_open: bool) { + pub fn show_open_close_animation(&self, ctx: &Context, frame: &Frame, is_open: bool) { // must be called first so animation managers know the latest state let visibility_factor = ctx.animate_bool(self.id.with("close_animation"), is_open); @@ -276,7 +276,7 @@ impl Prepared { self.drag_bounds } - pub(crate) fn content_ui(&self, ctx: &CtxRef) -> Ui { + pub(crate) fn content_ui(&self, ctx: &Context) -> Ui { let screen_rect = ctx.input().screen_rect(); let bounds = if let Some(bounds) = self.drag_bounds { @@ -317,7 +317,7 @@ impl Prepared { } #[allow(clippy::needless_pass_by_value)] // intentional to swallow up `content_ui`. - pub(crate) fn end(self, ctx: &CtxRef, content_ui: Ui) -> Response { + pub(crate) fn end(self, ctx: &Context, content_ui: Ui) -> Response { let Prepared { layer_id, mut state, @@ -370,8 +370,9 @@ impl Prepared { } fn pointer_pressed_on_area(ctx: &Context, layer_id: LayerId) -> bool { - if let Some(pointer_pos) = ctx.input().pointer.interact_pos() { - ctx.input().pointer.any_pressed() && ctx.layer_id_at(pointer_pos) == Some(layer_id) + if let Some(pointer_pos) = ctx.pointer_interact_pos() { + let any_pressed = ctx.input().pointer.any_pressed(); + any_pressed && ctx.layer_id_at(pointer_pos) == Some(layer_id) } else { false } diff --git a/egui/src/containers/collapsing_header.rs b/egui/src/containers/collapsing_header.rs index 66c6b213..d0df0895 100644 --- a/egui/src/containers/collapsing_header.rs +++ b/egui/src/containers/collapsing_header.rs @@ -1,9 +1,9 @@ use std::hash::Hash; use crate::*; -use epaint::{Shape, TextStyle}; +use epaint::Shape; -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Default)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "serde", serde(default))] pub(crate) struct State { @@ -13,22 +13,13 @@ pub(crate) struct State { open_height: Option, } -impl Default for State { - fn default() -> Self { - Self { - open: false, - open_height: None, - } - } -} - impl State { pub fn load(ctx: &Context, id: Id) -> Option { - ctx.memory().data.get_persisted(id) + ctx.data().get_persisted(id) } pub fn store(self, ctx: &Context, id: Id) { - ctx.memory().data.insert_persisted(id, self); + ctx.data().insert_persisted(id, self); } pub fn from_memory_with_default_open(ctx: &Context, id: Id, default_open: bool) -> Self { @@ -107,7 +98,7 @@ impl State { } /// Paint the arrow icon that indicated if the region is open or not -pub(crate) fn paint_icon(ui: &mut Ui, openness: f32, response: &Response) { +pub(crate) fn paint_default_icon(ui: &mut Ui, openness: f32, response: &Response) { let visuals = ui.style().interact(response); let stroke = visuals.fg_stroke; @@ -126,6 +117,9 @@ pub(crate) fn paint_icon(ui: &mut Ui, openness: f32, response: &Response) { ui.painter().add(Shape::closed_line(points, stroke)); } +/// A function that paints an icon indicating if the region is open or not +pub type IconPainter = Box; + /// A header which can be collapsed/expanded, revealing a contained [`Ui`] region. /// /// @@ -150,6 +144,7 @@ pub struct CollapsingHeader { selectable: bool, selected: bool, show_background: bool, + icon: Option, } impl CollapsingHeader { @@ -171,6 +166,7 @@ impl CollapsingHeader { selectable: false, selected: false, show_background: false, + icon: None, } } @@ -245,6 +241,28 @@ impl CollapsingHeader { self.show_background = show_background; self } + + /// Use the provided function to render a different `CollapsingHeader` icon. + /// Defaults to a triangle that animates as the `CollapsingHeader` opens and closes. + /// + /// For example: + /// ``` + /// # egui::__run_test_ui(|ui| { + /// fn circle_icon(ui: &mut egui::Ui, openness: f32, response: &egui::Response) { + /// let stroke = ui.style().interact(&response).fg_stroke; + /// let radius = egui::lerp(2.0..=3.0, openness); + /// ui.painter().circle_filled(response.rect.center(), radius, stroke.color); + /// } + /// + /// egui::CollapsingHeader::new("Circles") + /// .icon(circle_icon) + /// .show(ui, |ui| { ui.label("Hi!"); }); + /// # }); + /// ``` + pub fn icon(mut self, icon_fn: impl FnOnce(&mut Ui, f32, &Response) + 'static) -> Self { + self.icon = Some(Box::new(icon_fn)); + self + } } struct Prepared { @@ -260,6 +278,7 @@ impl CollapsingHeader { "Horizontal collapsing is unimplemented" ); let Self { + icon, text, default_open, open, @@ -319,7 +338,7 @@ impl CollapsingHeader { if ui.visuals().collapsing_header_frame || self.show_background { ui.painter().add(epaint::RectShape { rect: header_response.rect.expand(visuals.expansion), - corner_radius: visuals.corner_radius, + rounding: visuals.rounding, fill: visuals.bg_fill, stroke: visuals.bg_stroke, // stroke: Default::default(), @@ -331,9 +350,8 @@ impl CollapsingHeader { { let rect = rect.expand(visuals.expansion); - let corner_radius = 2.0; ui.painter() - .rect(rect, corner_radius, visuals.bg_fill, visuals.bg_stroke); + .rect(rect, visuals.rounding, visuals.bg_fill, visuals.bg_stroke); } { @@ -347,7 +365,11 @@ impl CollapsingHeader { ..header_response.clone() }; let openness = state.openness(ui.ctx(), id); - paint_icon(ui, openness, &icon_response); + if let Some(icon) = icon { + icon(ui, openness, &icon_response); + } else { + paint_default_icon(ui, openness, &icon_response); + } } text.paint_with_visuals(ui.painter(), text_pos, &visuals); diff --git a/egui/src/containers/combo_box.rs b/egui/src/containers/combo_box.rs index 71c4f063..14feb02c 100644 --- a/egui/src/containers/combo_box.rs +++ b/egui/src/containers/combo_box.rs @@ -27,6 +27,16 @@ pub struct ComboBox { } impl ComboBox { + /// Create new `ComboBox` with id and label + pub fn new(id_source: impl std::hash::Hash, label: impl Into) -> Self { + Self { + id_source: Id::new(id_source), + label: Some(label.into()), + selected_text: Default::default(), + width: None, + } + } + /// Label shown next to the combo box pub fn from_label(label: impl Into) -> Self { let label = label.into(); @@ -196,6 +206,7 @@ fn combo_box_dyn<'c, R>( ScrollArea::vertical() .max_height(ui.spacing().combo_height) .show(ui, menu_contents) + .inner }); InnerResponse { @@ -239,7 +250,7 @@ fn button_frame( where_to_put_background, epaint::RectShape { rect: outer_rect.expand(visuals.expansion), - corner_radius: visuals.corner_radius, + rounding: visuals.rounding, fill: visuals.bg_fill, stroke: visuals.bg_stroke, }, diff --git a/egui/src/containers/frame.rs b/egui/src/containers/frame.rs index fd85819d..c5c5a61a 100644 --- a/egui/src/containers/frame.rs +++ b/egui/src/containers/frame.rs @@ -9,7 +9,7 @@ use epaint::*; pub struct Frame { /// On each side pub margin: Vec2, - pub corner_radius: f32, + pub rounding: Rounding, pub shadow: Shadow, pub fill: Color32, pub stroke: Stroke, @@ -24,7 +24,7 @@ impl Frame { pub fn group(style: &Style) -> Self { Self { margin: Vec2::splat(6.0), // symmetric looks best in corners when nesting - corner_radius: style.visuals.widgets.noninteractive.corner_radius, + rounding: style.visuals.widgets.noninteractive.rounding, stroke: style.visuals.widgets.noninteractive.bg_stroke, ..Default::default() } @@ -33,7 +33,7 @@ impl Frame { pub(crate) fn side_top_panel(style: &Style) -> Self { Self { margin: Vec2::new(8.0, 2.0), - corner_radius: 0.0, + rounding: Rounding::none(), fill: style.visuals.window_fill(), stroke: style.visuals.window_stroke(), ..Default::default() @@ -43,7 +43,7 @@ impl Frame { pub(crate) fn central_panel(style: &Style) -> Self { Self { margin: Vec2::new(8.0, 8.0), - corner_radius: 0.0, + rounding: Rounding::none(), fill: style.visuals.window_fill(), stroke: Default::default(), ..Default::default() @@ -53,7 +53,7 @@ impl Frame { pub fn window(style: &Style) -> Self { Self { margin: style.spacing.window_padding, - corner_radius: style.visuals.window_corner_radius, + rounding: style.visuals.window_rounding, shadow: style.visuals.window_shadow, fill: style.visuals.window_fill(), stroke: style.visuals.window_stroke(), @@ -63,7 +63,7 @@ impl Frame { pub fn menu(style: &Style) -> Self { Self { margin: Vec2::splat(1.0), - corner_radius: style.visuals.widgets.noninteractive.corner_radius, + rounding: style.visuals.widgets.noninteractive.rounding, shadow: style.visuals.popup_shadow, fill: style.visuals.window_fill(), stroke: style.visuals.window_stroke(), @@ -73,7 +73,7 @@ impl Frame { pub fn popup(style: &Style) -> Self { Self { margin: style.spacing.window_padding, - corner_radius: style.visuals.widgets.noninteractive.corner_radius, + rounding: style.visuals.widgets.noninteractive.rounding, shadow: style.visuals.popup_shadow, fill: style.visuals.window_fill(), stroke: style.visuals.window_stroke(), @@ -84,7 +84,7 @@ impl Frame { pub fn dark_canvas(style: &Style) -> Self { Self { margin: Vec2::new(10.0, 10.0), - corner_radius: style.visuals.widgets.noninteractive.corner_radius, + rounding: style.visuals.widgets.noninteractive.rounding, fill: Color32::from_black_alpha(250), stroke: style.visuals.window_stroke(), ..Default::default() @@ -103,8 +103,8 @@ impl Frame { self } - pub fn corner_radius(mut self, corner_radius: f32) -> Self { - self.corner_radius = corner_radius; + pub fn rounding(mut self, rounding: impl Into) -> Self { + self.rounding = rounding.into(); self } @@ -172,7 +172,7 @@ impl Frame { pub fn paint(&self, outer_rect: Rect) -> Shape { let Self { margin: _, - corner_radius, + rounding, shadow, fill, stroke, @@ -180,7 +180,7 @@ impl Frame { let frame_shape = Shape::Rect(epaint::RectShape { rect: outer_rect, - corner_radius, + rounding, fill, stroke, }); @@ -188,7 +188,7 @@ impl Frame { if shadow == Default::default() { frame_shape } else { - let shadow = shadow.tessellate(outer_rect, corner_radius); + let shadow = shadow.tessellate(outer_rect, rounding); let shadow = Shape::Mesh(shadow); Shape::Vec(vec![shadow, frame_shape]) } diff --git a/egui/src/containers/panel.rs b/egui/src/containers/panel.rs index 8bdea2a8..9fc6aae8 100644 --- a/egui/src/containers/panel.rs +++ b/egui/src/containers/panel.rs @@ -25,11 +25,11 @@ struct PanelState { impl PanelState { fn load(ctx: &Context, bar_id: Id) -> Option { - ctx.memory().data.get_persisted(bar_id) + ctx.data().get_persisted(bar_id) } fn store(self, ctx: &Context, bar_id: Id) { - ctx.memory().data.insert_persisted(bar_id, self); + ctx.data().insert_persisted(bar_id, self); } } @@ -199,7 +199,7 @@ impl SidePanel { let mut is_resizing = false; if resizable { let resize_id = id.with("__resize"); - if let Some(pointer) = ui.input().pointer.latest_pos() { + if let Some(pointer) = ui.ctx().latest_pointer_pos() { let we_are_on_top = ui .ctx() .layer_id_at(pointer) @@ -284,7 +284,7 @@ impl SidePanel { /// Show the panel at the top level. pub fn show( self, - ctx: &CtxRef, + ctx: &Context, add_contents: impl FnOnce(&mut Ui) -> R, ) -> InnerResponse { self.show_dyn(ctx, Box::new(add_contents)) @@ -293,7 +293,7 @@ impl SidePanel { /// Show the panel at the top level. fn show_dyn<'c, R>( self, - ctx: &CtxRef, + ctx: &Context, add_contents: Box R + 'c>, ) -> InnerResponse { let layer_id = LayerId::background(); @@ -485,7 +485,8 @@ impl TopBottomPanel { let mut is_resizing = false; if resizable { let resize_id = id.with("__resize"); - if let Some(pointer) = ui.input().pointer.latest_pos() { + let latest_pos = ui.input().pointer.latest_pos(); + if let Some(pointer) = latest_pos { let we_are_on_top = ui .ctx() .layer_id_at(pointer) @@ -570,7 +571,7 @@ impl TopBottomPanel { /// Show the panel at the top level. pub fn show( self, - ctx: &CtxRef, + ctx: &Context, add_contents: impl FnOnce(&mut Ui) -> R, ) -> InnerResponse { self.show_dyn(ctx, Box::new(add_contents)) @@ -579,7 +580,7 @@ impl TopBottomPanel { /// Show the panel at the top level. fn show_dyn<'c, R>( self, - ctx: &CtxRef, + ctx: &Context, add_contents: Box R + 'c>, ) -> InnerResponse { let layer_id = LayerId::background(); @@ -670,7 +671,7 @@ impl CentralPanel { /// Show the panel at the top level. pub fn show( self, - ctx: &CtxRef, + ctx: &Context, add_contents: impl FnOnce(&mut Ui) -> R, ) -> InnerResponse { self.show_dyn(ctx, Box::new(add_contents)) @@ -679,7 +680,7 @@ impl CentralPanel { /// Show the panel at the top level. fn show_dyn<'c, R>( self, - ctx: &CtxRef, + ctx: &Context, add_contents: Box R + 'c>, ) -> InnerResponse { let available_rect = ctx.available_rect(); diff --git a/egui/src/containers/popup.rs b/egui/src/containers/popup.rs index 1194f12b..ffe36672 100644 --- a/egui/src/containers/popup.rs +++ b/egui/src/containers/popup.rs @@ -13,11 +13,11 @@ pub(crate) struct MonoState { impl MonoState { fn load(ctx: &Context) -> Option { - ctx.memory().data.get_temp(Id::null()) + ctx.data().get_temp(Id::null()) } fn store(self, ctx: &Context) { - ctx.memory().data.insert_temp(Id::null(), self); + ctx.data().insert_temp(Id::null(), self); } fn tooltip_size(&self, id: Id, index: usize) -> Option { @@ -66,7 +66,11 @@ impl MonoState { /// } /// # }); /// ``` -pub fn show_tooltip(ctx: &CtxRef, id: Id, add_contents: impl FnOnce(&mut Ui) -> R) -> Option { +pub fn show_tooltip( + ctx: &Context, + id: Id, + add_contents: impl FnOnce(&mut Ui) -> R, +) -> Option { show_tooltip_at_pointer(ctx, id, add_contents) } @@ -88,7 +92,7 @@ pub fn show_tooltip(ctx: &CtxRef, id: Id, add_contents: impl FnOnce(&mut Ui) /// # }); /// ``` pub fn show_tooltip_at_pointer( - ctx: &CtxRef, + ctx: &Context, id: Id, add_contents: impl FnOnce(&mut Ui) -> R, ) -> Option { @@ -104,7 +108,7 @@ pub fn show_tooltip_at_pointer( /// /// If the tooltip does not fit under the area, it tries to place it above it instead. pub fn show_tooltip_for( - ctx: &CtxRef, + ctx: &Context, id: Id, rect: &Rect, add_contents: impl FnOnce(&mut Ui) -> R, @@ -129,7 +133,7 @@ pub fn show_tooltip_for( /// /// Returns `None` if the tooltip could not be placed. pub fn show_tooltip_at( - ctx: &CtxRef, + ctx: &Context, id: Id, suggested_position: Option, add_contents: impl FnOnce(&mut Ui) -> R, @@ -146,7 +150,7 @@ pub fn show_tooltip_at( } fn show_tooltip_at_avoid_dyn<'c, R>( - ctx: &CtxRef, + ctx: &Context, mut id: Id, suggested_position: Option, above: bool, @@ -229,7 +233,7 @@ fn show_tooltip_at_avoid_dyn<'c, R>( /// } /// # }); /// ``` -pub fn show_tooltip_text(ctx: &CtxRef, id: Id, text: impl Into) -> Option<()> { +pub fn show_tooltip_text(ctx: &Context, id: Id, text: impl Into) -> Option<()> { show_tooltip(ctx, id, |ui| { crate::widgets::Label::new(text).ui(ui); }) @@ -237,7 +241,7 @@ pub fn show_tooltip_text(ctx: &CtxRef, id: Id, text: impl Into) -> O /// Show a pop-over window. fn show_tooltip_area_dyn<'c, R>( - ctx: &CtxRef, + ctx: &Context, id: Id, window_pos: Pos2, add_contents: Box R + 'c>, diff --git a/egui/src/containers/resize.rs b/egui/src/containers/resize.rs index 903d669a..5dd46dbe 100644 --- a/egui/src/containers/resize.rs +++ b/egui/src/containers/resize.rs @@ -18,11 +18,11 @@ pub(crate) struct State { impl State { pub fn load(ctx: &Context, id: Id) -> Option { - ctx.memory().data.get_persisted(id) + ctx.data().get_persisted(id) } pub fn store(self, ctx: &Context, id: Id) { - ctx.memory().data.insert_persisted(id, self); + ctx.data().insert_persisted(id, self); } } diff --git a/egui/src/containers/scroll_area.rs b/egui/src/containers/scroll_area.rs index a79bf5df..d5c9e712 100644 --- a/egui/src/containers/scroll_area.rs +++ b/egui/src/containers/scroll_area.rs @@ -10,9 +10,9 @@ use crate::*; #[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "serde", serde(default))] -pub(crate) struct State { +pub struct State { /// Positive offset means scrolling down/right - offset: Vec2, + pub offset: Vec2, show_scroll: [bool; 2], @@ -43,14 +43,28 @@ impl Default for State { impl State { pub fn load(ctx: &Context, id: Id) -> Option { - ctx.memory().data.get_persisted(id) + ctx.data().get_persisted(id) } pub fn store(self, ctx: &Context, id: Id) { - ctx.memory().data.insert_persisted(id, self); + ctx.data().insert_persisted(id, self); } } +pub struct ScrollAreaOutput { + /// What the user closure returned. + pub inner: R, + + /// `Id` of the `ScrollArea`. + pub id: Id, + + /// The current state of the scroll area. + pub state: State, + + /// Where on the screen the content is (excludes scroll bars). + pub inner_rect: Rect, +} + /// Add vertical and/or horizontal scrolling to a contained [`Ui`]. /// /// ``` @@ -258,6 +272,7 @@ struct Prepared { /// width of the vertical bar, and the height of the horizontal bar? current_bar_use: Vec2, always_show_scroll: bool, + /// Where on the screen the content is (excludes scroll bars). inner_rect: Rect, content_ui: Ui, /// Relative coordinates: the offset and size of the view of the inner UI. @@ -365,7 +380,11 @@ impl ScrollArea { /// Show the `ScrollArea`, and add the contents to the viewport. /// /// If the inner area can be very long, consider using [`Self::show_rows`] instead. - pub fn show(self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> R { + pub fn show( + self, + ui: &mut Ui, + add_contents: impl FnOnce(&mut Ui) -> R, + ) -> ScrollAreaOutput { self.show_viewport_dyn(ui, Box::new(|ui, _viewport| add_contents(ui))) } @@ -374,7 +393,7 @@ impl ScrollArea { /// ``` /// # egui::__run_test_ui(|ui| { /// let text_style = egui::TextStyle::Body; - /// let row_height = ui.fonts()[text_style].row_height(); + /// let row_height = ui.text_style_height(&text_style); /// // let row_height = ui.spacing().interact_size.y; // if you are adding buttons instead of labels. /// let total_rows = 10_000; /// egui::ScrollArea::vertical().show_rows(ui, row_height, total_rows, |ui, row_range| { @@ -391,7 +410,7 @@ impl ScrollArea { row_height_sans_spacing: f32, total_rows: usize, add_contents: impl FnOnce(&mut Ui, std::ops::Range) -> R, - ) -> R { + ) -> ScrollAreaOutput { let spacing = ui.spacing().item_spacing; let row_height_with_spacing = row_height_sans_spacing + spacing.y; self.show_viewport(ui, |ui, viewport| { @@ -420,7 +439,11 @@ impl ScrollArea { /// /// `add_contents` is past the viewport, which is the relative view of the content. /// So if the passed rect has min = zero, then show the top left content (the user has not scrolled). - pub fn show_viewport(self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui, Rect) -> R) -> R { + pub fn show_viewport( + self, + ui: &mut Ui, + add_contents: impl FnOnce(&mut Ui, Rect) -> R, + ) -> ScrollAreaOutput { self.show_viewport_dyn(ui, Box::new(add_contents)) } @@ -428,16 +451,23 @@ impl ScrollArea { self, ui: &mut Ui, add_contents: Box R + 'c>, - ) -> R { + ) -> ScrollAreaOutput { let mut prepared = self.begin(ui); - let ret = add_contents(&mut prepared.content_ui, prepared.viewport); - prepared.end(ui); - ret + let id = prepared.id; + let inner_rect = prepared.inner_rect; + let inner = add_contents(&mut prepared.content_ui, prepared.viewport); + let state = prepared.end(ui); + ScrollAreaOutput { + inner, + id, + state, + inner_rect, + } } } impl Prepared { - fn end(self, ui: &mut Ui) { + fn end(self, ui: &mut Ui) -> State { let Prepared { id, mut state, @@ -523,12 +553,11 @@ impl Prepared { }; let content_response = ui.interact(inner_rect, id.with("area"), sense); - let input = ui.input(); if content_response.dragged() { for d in 0..2 { if has_bar[d] { - state.offset[d] -= input.pointer.delta()[d]; - state.vel[d] = input.pointer.velocity()[d]; + state.offset[d] -= ui.input().pointer.delta()[d]; + state.vel[d] = ui.input().pointer.velocity()[d]; state.scroll_stuck_to_end[d] = false; } else { state.vel[d] = 0.0; @@ -537,7 +566,7 @@ impl Prepared { } else { let stop_speed = 20.0; // Pixels per second. let friction_coeff = 1000.0; // Pixels per second squared. - let dt = input.unstable_dt; + let dt = ui.input().unstable_dt; let friction = friction_coeff * dt; if friction > state.vel.length() || state.vel.length() < stop_speed { @@ -711,13 +740,13 @@ impl Prepared { ui.painter().add(epaint::Shape::rect_filled( outer_scroll_rect, - visuals.corner_radius, + visuals.rounding, ui.visuals().extreme_bg_color, )); ui.painter().add(epaint::Shape::rect_filled( handle_rect, - visuals.corner_radius, + visuals.rounding, visuals.bg_fill, )); } @@ -748,6 +777,8 @@ impl Prepared { state.show_scroll = show_scroll_this_frame; state.store(ui.ctx(), id); + + state } } diff --git a/egui/src/containers/window.rs b/egui/src/containers/window.rs index 4eceac70..9c439b26 100644 --- a/egui/src/containers/window.rs +++ b/egui/src/containers/window.rs @@ -235,7 +235,7 @@ impl<'open> Window<'open> { #[inline] pub fn show( self, - ctx: &CtxRef, + ctx: &Context, add_contents: impl FnOnce(&mut Ui) -> R, ) -> Option>> { self.show_dyn(ctx, Box::new(add_contents)) @@ -243,7 +243,7 @@ impl<'open> Window<'open> { fn show_dyn<'c, R>( self, - ctx: &CtxRef, + ctx: &Context, add_contents: Box R + 'c>, ) -> Option>> { let Window { @@ -296,7 +296,8 @@ impl<'open> Window<'open> { .and_then(|window_interaction| { // Calculate roughly how much larger the window size is compared to the inner rect let title_bar_height = if with_title_bar { - title.font_height(ctx.fonts(), &ctx.style()) + title_content_spacing + let style = ctx.style(); + title.font_height(&ctx.fonts(), &style) + title_content_spacing } else { 0.0 }; @@ -353,7 +354,7 @@ impl<'open> Window<'open> { } if scroll.has_any_bar() { - scroll.show(ui, add_contents) + scroll.show(ui, add_contents).inner } else { add_contents(ui) } @@ -698,42 +699,62 @@ fn paint_frame_interaction( ) { use epaint::tessellator::path::add_circle_quadrant; - let cr = ui.visuals().window_corner_radius; + let rounding = ui.visuals().window_rounding; let Rect { min, max } = rect; let mut points = Vec::new(); if interaction.right && !interaction.bottom && !interaction.top { - points.push(pos2(max.x, min.y + cr)); - points.push(pos2(max.x, max.y - cr)); + points.push(pos2(max.x, min.y + rounding.ne)); + points.push(pos2(max.x, max.y - rounding.se)); } if interaction.right && interaction.bottom { - points.push(pos2(max.x, min.y + cr)); - points.push(pos2(max.x, max.y - cr)); - add_circle_quadrant(&mut points, pos2(max.x - cr, max.y - cr), cr, 0.0); + points.push(pos2(max.x, min.y + rounding.ne)); + points.push(pos2(max.x, max.y - rounding.se)); + add_circle_quadrant( + &mut points, + pos2(max.x - rounding.se, max.y - rounding.se), + rounding.se, + 0.0, + ); } if interaction.bottom { - points.push(pos2(max.x - cr, max.y)); - points.push(pos2(min.x + cr, max.y)); + points.push(pos2(max.x - rounding.se, max.y)); + points.push(pos2(min.x + rounding.sw, max.y)); } if interaction.left && interaction.bottom { - add_circle_quadrant(&mut points, pos2(min.x + cr, max.y - cr), cr, 1.0); + add_circle_quadrant( + &mut points, + pos2(min.x + rounding.sw, max.y - rounding.sw), + rounding.sw, + 1.0, + ); } if interaction.left { - points.push(pos2(min.x, max.y - cr)); - points.push(pos2(min.x, min.y + cr)); + points.push(pos2(min.x, max.y - rounding.sw)); + points.push(pos2(min.x, min.y + rounding.nw)); } if interaction.left && interaction.top { - add_circle_quadrant(&mut points, pos2(min.x + cr, min.y + cr), cr, 2.0); + add_circle_quadrant( + &mut points, + pos2(min.x + rounding.nw, min.y + rounding.nw), + rounding.nw, + 2.0, + ); } if interaction.top { - points.push(pos2(min.x + cr, min.y)); - points.push(pos2(max.x - cr, min.y)); + points.push(pos2(min.x + rounding.nw, min.y)); + points.push(pos2(max.x - rounding.ne, min.y)); } if interaction.right && interaction.top { - add_circle_quadrant(&mut points, pos2(max.x - cr, min.y + cr), cr, 3.0); - points.push(pos2(max.x, min.y + cr)); - points.push(pos2(max.x, max.y - cr)); + add_circle_quadrant( + &mut points, + pos2(max.x - rounding.ne, min.y + rounding.ne), + rounding.ne, + 3.0, + ); + points.push(pos2(max.x, min.y + rounding.ne)); + points.push(pos2(max.x, max.y - rounding.se)); } ui.painter().add(Shape::line(points, visuals.bg_stroke)); } @@ -741,9 +762,16 @@ fn paint_frame_interaction( // ---------------------------------------------------------------------------- struct TitleBar { + /// A title Id used for dragging windows id: Id, + /// Prepared text in the title title_galley: WidgetTextGalley, + /// Size of the title bar in a collapsed state (if window is collapsible), + /// which includes all necessary space for showing the expand button, the + /// title and the close button. min_rect: Rect, + /// Size of the title bar in an expanded state. This size become known only + /// after expanding window and painting its content rect: Rect, } @@ -757,7 +785,7 @@ fn show_title_bar( ) -> TitleBar { let inner_response = ui.horizontal(|ui| { let height = title - .font_height(ui.fonts(), ui.style()) + .font_height(&ui.fonts(), ui.style()) .max(ui.spacing().interact_size.y); ui.set_min_height(height); @@ -775,7 +803,7 @@ fn show_title_bar( collapsing.toggle(ui); } let openness = collapsing.openness(ui.ctx(), collapsing_id); - collapsing_header::paint_icon(ui, openness, &collapse_button_response); + collapsing_header::paint_default_icon(ui, openness, &collapse_button_response); } let title_galley = title.into_galley(ui, Some(false), f32::INFINITY, TextStyle::Heading); @@ -804,6 +832,20 @@ fn show_title_bar( } impl TitleBar { + /// Finishes painting of the title bar when the window content size already known. + /// + /// # Parameters + /// + /// - `ui`: + /// - `outer_rect`: + /// - `content_response`: if `None`, window is collapsed at this frame, otherwise contains + /// a result of rendering the window content + /// - `open`: if `None`, no "Close" button will be rendered, otherwise renders and processes + /// the "Close" button and writes a `false` if window was closed + /// - `collapsing`: holds the current expanding state. Can be changed by double click on the + /// title if `collapsible` is `true` + /// - `collapsible`: if `true`, double click on the title bar will be handled for a change + /// of `collapsing` state fn ui( mut self, ui: &mut Ui, @@ -857,6 +899,11 @@ impl TitleBar { } } + /// Paints the "Close" button at the right side of the title bar + /// and processes clicks on it. + /// + /// The button is square and its size is determined by the + /// [`crate::style::Spacing::icon_width`] setting. fn close_button_ui(&self, ui: &mut Ui) -> Response { let button_size = Vec2::splat(ui.spacing().icon_width); let pad = (self.rect.height() - button_size.y) / 2.0; // calculated so that the icon is on the diagonal (if window padding is symmetrical) @@ -872,6 +919,16 @@ impl TitleBar { } } +/// Paints the "Close" button of the window and processes clicks on it. +/// +/// The close button is just an `X` symbol painted by a current stroke +/// for foreground elements (such as a label text). +/// +/// # Parameters +/// - `ui`: +/// - `rect`: The rectangular area to fit the button in +/// +/// Returns the result of a click on a button if it was pressed fn close_button(ui: &mut Ui, rect: Rect) -> Response { let close_id = ui.auto_id_with("window_close_button"); let response = ui.interact(rect, close_id, Sense::click()); @@ -880,9 +937,9 @@ fn close_button(ui: &mut Ui, rect: Rect) -> Response { let visuals = ui.style().interact(&response); let rect = rect.shrink(2.0).expand(visuals.expansion); let stroke = visuals.fg_stroke; - ui.painter() + ui.painter() // paints \ .line_segment([rect.left_top(), rect.right_bottom()], stroke); - ui.painter() + ui.painter() // paints / .line_segment([rect.right_top(), rect.left_bottom()], stroke); response } diff --git a/egui/src/context.rs b/egui/src/context.rs index ad5c8482..3695b91c 100644 --- a/egui/src/context.rs +++ b/egui/src/context.rs @@ -1,40 +1,129 @@ // #![warn(missing_docs)] -use std::sync::{ - atomic::{AtomicU32, Ordering::SeqCst}, - Arc, -}; - use crate::{ - animation_manager::AnimationManager, - data::output::Output, - frame_state::FrameState, - input_state::*, - layers::GraphicLayers, - menu::ContextMenuSystem, - mutex::{Mutex, MutexGuard}, - *, + animation_manager::AnimationManager, data::output::Output, frame_state::FrameState, + input_state::*, layers::GraphicLayers, memory::Options, TextureHandle, *, }; -use epaint::{stats::*, text::Fonts, *}; +use epaint::{mutex::*, stats::*, text::Fonts, TessellationOptions, *}; // ---------------------------------------------------------------------------- -/// A wrapper around [`Arc`](std::sync::Arc)`<`[`Context`]`>`. -/// This is how you will normally create and access a [`Context`]. +struct WrappedTextureManager(Arc>); + +impl Default for WrappedTextureManager { + fn default() -> Self { + let mut tex_mngr = epaint::textures::TextureManager::default(); + + // Will be filled in later + let font_id = tex_mngr.alloc( + "egui_font_texture".into(), + epaint::AlphaImage::new([0, 0]).into(), + ); + assert_eq!(font_id, TextureId::default()); + + Self(Arc::new(RwLock::new(tex_mngr))) + } +} + +// ---------------------------------------------------------------------------- + +#[derive(Default)] +struct ContextImpl { + /// `None` until the start of the first frame. + fonts: Option, + memory: Memory, + animation_manager: AnimationManager, + tex_manager: WrappedTextureManager, + + input: InputState, + + /// State that is collected during a frame and then cleared + frame_state: FrameState, + + // The output of a frame: + graphics: GraphicLayers, + output: Output, + + paint_stats: PaintStats, + + /// While positive, keep requesting repaints. Decrement at the end of each frame. + repaint_requests: u32, +} + +impl ContextImpl { + fn begin_frame_mut(&mut self, new_raw_input: RawInput) { + self.memory.begin_frame(&self.input, &new_raw_input); + + self.input = std::mem::take(&mut self.input).begin_frame(new_raw_input); + + if let Some(new_pixels_per_point) = self.memory.new_pixels_per_point.take() { + self.input.pixels_per_point = new_pixels_per_point; + } + + self.frame_state.begin_frame(&self.input); + + self.update_fonts_mut(); + + // Ensure we register the background area so panels and background ui can catch clicks: + let screen_rect = self.input.screen_rect(); + self.memory.areas.set_state( + LayerId::background(), + containers::area::State { + pos: screen_rect.min, + size: screen_rect.size(), + interactable: true, + }, + ); + } + + /// Load fonts unless already loaded. + fn update_fonts_mut(&mut self) { + let pixels_per_point = self.input.pixels_per_point(); + let max_texture_side = self.input.raw.max_texture_side; + + if let Some(font_definitions) = self.memory.new_font_definitions.take() { + let fonts = Fonts::new(pixels_per_point, max_texture_side, font_definitions); + self.fonts = Some(fonts); + } + + let fonts = self.fonts.get_or_insert_with(|| { + let font_definitions = FontDefinitions::default(); + Fonts::new(pixels_per_point, max_texture_side, font_definitions) + }); + + fonts.begin_frame(pixels_per_point, max_texture_side); + + if self.memory.options.preload_font_glyphs { + // Preload the most common characters for the most common fonts. + // This is not very important to do, but may a few GPU operations. + for font_id in self.memory.options.style.text_styles.values() { + fonts.lock().fonts.font(font_id).preload_common_characters(); + } + } + } +} + +// ---------------------------------------------------------------------------- + +/// Your handle to egui. /// -/// Almost all methods are marked `&self`, `Context` has interior mutability (protected by mutexes). +/// This is the first thing you need when working with egui. +/// Contains the [`InputState`], [`Memory`], [`Output`], and more. /// -/// [`CtxRef`] is cheap to clone, and any clones refers to the same mutable data. +/// [`Context`] is cheap to clone, and any clones refers to the same mutable data +/// ([`Context`] uses refcounting internally). /// -/// A [`CtxRef`] is only valid for the duration of a frame, and so you should not store a [`CtxRef`] between frames. -/// A new [`CtxRef`] is created each frame by calling [`Self::run`]. +/// All methods are marked `&self`; `Context` has interior mutability (protected by a mutex). +/// +/// +/// You can store /// /// # Example: /// /// ``` no_run /// # fn handle_output(_: egui::Output) {} /// # fn paint(_: Vec) {} -/// let mut ctx = egui::CtxRef::default(); +/// let mut ctx = egui::Context::default(); /// /// // Game loop: /// loop { @@ -53,58 +142,46 @@ use epaint::{stats::*, text::Fonts, *}; /// } /// ``` #[derive(Clone)] -pub struct CtxRef(std::sync::Arc); +pub struct Context(Arc>); -impl std::ops::Deref for CtxRef { - type Target = Context; - - fn deref(&self) -> &Context { - &*self.0 - } -} - -impl AsRef for CtxRef { - fn as_ref(&self) -> &Context { - self.0.as_ref() - } -} - -impl std::borrow::Borrow for CtxRef { - fn borrow(&self) -> &Context { - self.0.borrow() - } -} - -impl std::cmp::PartialEq for CtxRef { - fn eq(&self, other: &CtxRef) -> bool { +impl std::cmp::PartialEq for Context { + fn eq(&self, other: &Context) -> bool { Arc::ptr_eq(&self.0, &other.0) } } -impl Default for CtxRef { +impl Default for Context { fn default() -> Self { - Self(Arc::new(Context { + Self(Arc::new(RwLock::new(ContextImpl { // Start with painting an extra frame to compensate for some widgets // that take two frames before they "settle": - repaint_requests: AtomicU32::new(1), - ..Context::default() - })) + repaint_requests: 1, + ..ContextImpl::default() + }))) } } -impl CtxRef { +impl Context { + fn read(&self) -> RwLockReadGuard<'_, ContextImpl> { + self.0.read() + } + + fn write(&self) -> RwLockWriteGuard<'_, ContextImpl> { + self.0.write() + } + /// Run the ui code for one frame. /// /// Put your widgets into a [`SidePanel`], [`TopBottomPanel`], [`CentralPanel`], [`Window`] or [`Area`]. /// /// This will modify the internal reference to point to a new generation of [`Context`]. - /// Any old clones of this [`CtxRef`] will refer to the old [`Context`], which will not get new input. + /// Any old clones of this [`Context`] will refer to the old [`Context`], which will not get new input. /// /// You can alternatively run [`Self::begin_frame`] and [`Context::end_frame`]. /// - /// ``` rust + /// ``` /// // One egui context that you keep reusing: - /// let mut ctx = egui::CtxRef::default(); + /// let mut ctx = egui::Context::default(); /// /// // Each frame: /// let input = egui::RawInput::default(); @@ -117,9 +194,9 @@ impl CtxRef { /// ``` #[must_use] pub fn run( - &mut self, + &self, new_input: RawInput, - run_ui: impl FnOnce(&CtxRef), + run_ui: impl FnOnce(&Context), ) -> (Output, Vec) { self.begin_frame(new_input); run_ui(self); @@ -128,9 +205,9 @@ impl CtxRef { /// An alternative to calling [`Self::run`]. /// - /// ``` rust + /// ``` /// // One egui context that you keep reusing: - /// let mut ctx = egui::CtxRef::default(); + /// let mut ctx = egui::Context::default(); /// /// // Each frame: /// let input = egui::RawInput::default(); @@ -143,10 +220,8 @@ impl CtxRef { /// let (output, shapes) = ctx.end_frame(); /// // handle output, paint shapes /// ``` - pub fn begin_frame(&mut self, new_input: RawInput) { - let mut self_: Context = (*self.0).clone(); - self_.begin_frame_mut(new_input); - *self = Self(Arc::new(self_)); + pub fn begin_frame(&self, new_input: RawInput) { + self.write().begin_frame_mut(new_input); } // --------------------------------------------------------------------- @@ -167,7 +242,7 @@ impl CtxRef { let show_error = |pos: Pos2, text: String| { let painter = self.debug_painter(); let rect = painter.error(pos, text); - if let Some(pointer_pos) = self.input.pointer.hover_pos() { + if let Some(pointer_pos) = self.pointer_hover_pos() { if rect.contains(pointer_pos) { painter.error( rect.left_bottom() + vec2(2.0, 4.0), @@ -244,14 +319,19 @@ impl CtxRef { changed: false, // must be set by the widget itself }; - let mut memory = self.memory(); - if !enabled || !sense.focusable || !layer_id.allow_interaction() { // Not interested or allowed input: - memory.surrender_focus(id); + self.memory().surrender_focus(id); return response; } + self.register_interaction_id(id, rect); + + let clicked_elsewhere = response.clicked_elsewhere(); + let ctx_impl = &mut *self.write(); + let memory = &mut ctx_impl.memory; + let input = &mut ctx_impl.input; + // We only want to focus labels if the screen reader is on. let interested_in_focus = sense.interactive() || sense.focusable && memory.options.screen_reader; @@ -262,14 +342,12 @@ impl CtxRef { if sense.click && memory.has_focus(response.id) - && (self.input().key_pressed(Key::Space) || self.input().key_pressed(Key::Enter)) + && (input.key_pressed(Key::Space) || input.key_pressed(Key::Enter)) { // Space/enter works like a primary click for e.g. selected buttons response.clicked[PointerButton::Primary as usize] = true; } - self.register_interaction_id(id, rect); - if sense.click || sense.drag { memory.interaction.click_interest |= hovered && sense.click; memory.interaction.drag_interest |= hovered && sense.drag; @@ -278,7 +356,7 @@ impl CtxRef { response.is_pointer_button_down_on = memory.interaction.click_id == Some(id) || response.dragged; - for pointer_event in &self.input.pointer.pointer_events { + for pointer_event in &input.pointer.pointer_events { match pointer_event { PointerEvent::Moved(_) => {} PointerEvent::Pressed(_) => { @@ -325,14 +403,14 @@ impl CtxRef { } if response.is_pointer_button_down_on { - response.interact_pointer_pos = self.input().pointer.interact_pos(); + response.interact_pointer_pos = input.pointer.interact_pos(); } - if self.input.pointer.any_down() { + if input.pointer.any_down() { response.hovered &= response.is_pointer_button_down_on; // we don't hover widgets while interacting with *other* widgets } - if memory.has_focus(response.id) && response.clicked_elsewhere() { + if memory.has_focus(response.id) && clicked_elsewhere { memory.surrender_focus(id); } @@ -346,134 +424,119 @@ impl CtxRef { /// Get a full-screen painter for a new or existing layer pub fn layer_painter(&self, layer_id: LayerId) -> Painter { - Painter::new(self.clone(), layer_id, self.input.screen_rect()) + let screen_rect = self.input().screen_rect(); + Painter::new(self.clone(), layer_id, screen_rect) } /// Paint on top of everything else pub fn debug_painter(&self) -> Painter { Self::layer_painter(self, LayerId::debug()) } -} -// ---------------------------------------------------------------------------- - -/// Your handle to egui. -/// -/// This is the first thing you need when working with egui. -/// Use [`CtxRef`] to create and refer to a [`Context`]. -/// -/// Contains the [`InputState`], [`Memory`], [`Output`], and more. -/// -/// Almost all methods are marked `&self`, [`Context`] has interior mutability (protected by mutexes). -/// Multi-threaded access to a [`Context`] is behind the feature flag `multi_threaded`. -/// Normally you'd always do all ui work on one thread, or perhaps use multiple contexts, -/// but if you really want to access the same [`Context`] from multiple threads, it *SHOULD* be fine, -/// but you are likely the first person to try it. -#[derive(Default)] -pub struct Context { - // We clone the Context each frame so we can set a new `input`. - // This is so we can avoid a mutex lock to access the `InputState`. - // This means everything else needs to be behind an Arc. - // We can probably come up with a nicer design. - // - /// `None` until the start of the first frame. - fonts: Option>, - memory: Arc>, - animation_manager: Arc>, - context_menu_system: Arc>, - - input: InputState, - - /// State that is collected during a frame and then cleared - frame_state: Arc>, - - // The output of a frame: - graphics: Arc>, - output: Arc>, - - paint_stats: Arc>, - - /// While positive, keep requesting repaints. Decrement at the end of each frame. - repaint_requests: AtomicU32, -} - -impl Clone for Context { - fn clone(&self) -> Self { - Context { - fonts: self.fonts.clone(), - memory: self.memory.clone(), - animation_manager: self.animation_manager.clone(), - input: self.input.clone(), - frame_state: self.frame_state.clone(), - graphics: self.graphics.clone(), - output: self.output.clone(), - paint_stats: self.paint_stats.clone(), - repaint_requests: self.repaint_requests.load(SeqCst).into(), - context_menu_system: self.context_menu_system.clone(), - } - } -} - -impl Context { /// How much space is still available after panels has been added. /// This is the "background" area, what egui doesn't cover with panels (but may cover with windows). /// This is also the area to which windows are constrained. pub fn available_rect(&self) -> Rect { - self.frame_state.lock().available_rect() + self.frame_state().available_rect() } +} +/// ## Borrows parts of [`Context`] +impl Context { /// Stores all the egui state. + /// /// If you want to store/restore egui, serialize this. - pub fn memory(&self) -> MutexGuard<'_, Memory> { - self.memory.lock() + #[inline] + pub fn memory(&self) -> RwLockWriteGuard<'_, Memory> { + RwLockWriteGuard::map(self.write(), |c| &mut c.memory) } - pub(crate) fn context_menu_system(&self) -> MutexGuard<'_, ContextMenuSystem> { - self.context_menu_system.lock() + /// Stores superficial widget state. + #[inline] + pub fn data(&self) -> RwLockWriteGuard<'_, crate::util::IdTypeMap> { + RwLockWriteGuard::map(self.write(), |c| &mut c.memory.data) } - pub(crate) fn graphics(&self) -> MutexGuard<'_, GraphicLayers> { - self.graphics.lock() + #[inline] + pub(crate) fn graphics(&self) -> RwLockWriteGuard<'_, GraphicLayers> { + RwLockWriteGuard::map(self.write(), |c| &mut c.graphics) } /// What egui outputs each frame. - pub fn output(&self) -> MutexGuard<'_, Output> { - self.output.lock() + #[inline] + pub fn output(&self) -> RwLockWriteGuard<'_, Output> { + RwLockWriteGuard::map(self.write(), |c| &mut c.output) } - pub(crate) fn frame_state(&self) -> MutexGuard<'_, FrameState> { - self.frame_state.lock() + #[inline] + pub(crate) fn frame_state(&self) -> RwLockWriteGuard<'_, FrameState> { + RwLockWriteGuard::map(self.write(), |c| &mut c.frame_state) } + /// Access the [`InputState`]. + /// + /// Note that this locks the [`Context`], so be careful with if-let bindings: + /// + /// ``` + /// # let mut ctx = egui::Context::default(); + /// if let Some(pos) = ctx.input().pointer.hover_pos() { + /// // ⚠️ Using `ctx` again here will lead to a dead-lock! + /// } + /// + /// if let Some(pos) = { ctx.input().pointer.hover_pos() } { + /// // This is fine! + /// } + /// + /// let pos = ctx.input().pointer.hover_pos(); + /// if let Some(pos) = pos { + /// // This is fine! + /// } + /// ``` + #[inline] + pub fn input(&self) -> RwLockReadGuard<'_, InputState> { + RwLockReadGuard::map(self.read(), |c| &c.input) + } + + #[inline] + pub fn input_mut(&self) -> RwLockWriteGuard<'_, InputState> { + RwLockWriteGuard::map(self.write(), |c| &mut c.input) + } + + /// Not valid until first call to [`Context::run()`]. + /// That's because since we don't know the proper `pixels_per_point` until then. + #[inline] + pub fn fonts(&self) -> RwLockReadGuard<'_, Fonts> { + RwLockReadGuard::map(self.read(), |c| { + c.fonts + .as_ref() + .expect("No fonts available until first call to Context::run()") + }) + } + + #[inline] + fn fonts_mut(&self) -> RwLockWriteGuard<'_, Option> { + RwLockWriteGuard::map(self.write(), |c| &mut c.fonts) + } + + #[inline] + pub fn options(&self) -> RwLockWriteGuard<'_, Options> { + RwLockWriteGuard::map(self.write(), |c| &mut c.memory.options) + } + + /// Change the options used by the tessellator. + #[inline] + pub fn tessellation_options(&self) -> RwLockWriteGuard<'_, TessellationOptions> { + RwLockWriteGuard::map(self.write(), |c| &mut c.memory.options.tessellation_options) + } +} + +impl Context { /// Call this if there is need to repaint the UI, i.e. if you are showing an animation. /// If this is called at least once in a frame, then there will be another frame right after this. /// Call as many times as you wish, only one repaint will be issued. pub fn request_repaint(&self) { // request two frames of repaint, just to cover some corner cases (frame delays): - let times_to_repaint = 2; - self.repaint_requests.store(times_to_repaint, SeqCst); - } - - #[inline(always)] - pub fn input(&self) -> &InputState { - &self.input - } - - /// Not valid until first call to [`CtxRef::run()`]. - /// That's because since we don't know the proper `pixels_per_point` until then. - pub fn fonts(&self) -> &Fonts { - &*self - .fonts - .as_ref() - .expect("No fonts available until first call to CtxRef::run()") - } - - /// The egui font image, containing font characters etc. - /// - /// Not valid until first call to [`CtxRef::run()`]. - /// That's because since we don't know the proper `pixels_per_point` until then. - pub fn font_image(&self) -> Arc { - self.fonts().font_image() + self.write().repaint_requests = 2; } /// Tell `egui` which fonts to use. @@ -483,9 +546,9 @@ impl Context { /// /// The new fonts will become active at the start of the next frame. pub fn set_fonts(&self, font_definitions: FontDefinitions) { - if let Some(current_fonts) = &self.fonts { + if let Some(current_fonts) = &*self.fonts_mut() { // NOTE: this comparison is expensive since it checks TTF data for equality - if current_fonts.definitions() == &font_definitions { + if current_fonts.lock().fonts.definitions() == &font_definitions { return; // no change - save us from reloading font textures } } @@ -495,7 +558,7 @@ impl Context { /// The [`Style`] used by all subsequent windows, panels etc. pub fn style(&self) -> Arc