From 634b9568fbd262aec7f99b4c28f34aa1db6468e6 Mon Sep 17 00:00:00 2001 From: Bryan Van de Ven Date: Wed, 10 Jan 2024 14:49:11 -0800 Subject: [PATCH] Add option to take screenshot --- Cargo.lock | 268 +++++++++++++++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 3 + src/app.rs | 43 ++++++++- 3 files changed, 303 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d6834d4..cb1146a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -517,6 +517,18 @@ dependencies = [ "syn 2.0.18", ] +[[package]] +name = "atk-sys" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ad703eb64dc058024f0e57ccfa069e15a413b98dbd50a1a950e743b7f11148" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + [[package]] name = "atomic-waker" version = "1.1.1" @@ -697,6 +709,16 @@ dependencies = [ "bytes", ] +[[package]] +name = "cairo-sys-rs" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c48f4af05fabdcfa9658178e1326efa061853f040ce7d72e33af6885196f421" +dependencies = [ + "libc", + "system-deps", +] + [[package]] name = "calloop" version = "0.10.6" @@ -726,6 +748,16 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" +[[package]] +name = "cfg-expr" +version = "0.15.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6100bc57b6209840798d95cb2775684849d332f7bd788db2a8c8caf7ef82a41a" +dependencies = [ + "smallvec", + "target-lexicon", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -1233,6 +1265,12 @@ dependencies = [ "serde", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" version = "0.3.1" @@ -1392,6 +1430,36 @@ dependencies = [ "slab", ] +[[package]] +name = "gdk-pixbuf-sys" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3092cf797a5f1210479ea38070d9ae8a5b8e9f8f1be9f32f4643c529c7d70016" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gdk-sys" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76354f97a913e55b984759a997b693aa7dc71068c9e98bcce51aa167a0a5c5a" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "pkg-config", + "system-deps", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -1425,6 +1493,19 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gio-sys" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9b693b8e39d042a95547fc258a7b07349b1f0b48f4b2fa3108ba3c51c0b5229" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "winapi", +] + [[package]] name = "gl_generator" version = "0.14.0" @@ -1436,6 +1517,16 @@ dependencies = [ "xml-rs", ] +[[package]] +name = "glib-sys" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61a4f46316d06bfa33a7ac22df6f0524c8be58e3db2d9ca99ccb1f357b62a65" +dependencies = [ + "libc", + "system-deps", +] + [[package]] name = "glow" version = "0.12.2" @@ -1512,6 +1603,35 @@ dependencies = [ "gl_generator", ] +[[package]] +name = "gobject-sys" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3520bb9c07ae2a12c7f2fbb24d4efc11231c8146a86956413fb1a79bb760a0f1" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gtk-sys" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b5f8946685d5fe44497007786600c2f368ff6b1e61a16251c89f72a97520a3" +dependencies = [ + "atk-sys", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "system-deps", +] + [[package]] name = "h2" version = "0.3.19" @@ -1524,7 +1644,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.3", "slab", "tokio", "tokio-util", @@ -1543,6 +1663,18 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.2.6" @@ -1681,7 +1813,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", ] [[package]] @@ -1811,6 +1953,7 @@ dependencies = [ "egui_extras", "env_logger", "getrandom", + "image", "itertools", "log", "percentage", @@ -1818,6 +1961,7 @@ dependencies = [ "rayon", "regex", "reqwest", + "rfd", "serde", "url", "wasm-bindgen", @@ -2330,6 +2474,18 @@ dependencies = [ "ttf-parser", ] +[[package]] +name = "pango-sys" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e134909a9a293e04d2cc31928aa95679c5e4df954d0b85483159bd20d8f047f" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + [[package]] name = "parking" version = "2.1.0" @@ -2440,7 +2596,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", - "toml_edit", + "toml_edit 0.19.8", ] [[package]] @@ -2614,6 +2770,31 @@ dependencies = [ "winreg", ] +[[package]] +name = "rfd" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fe664af397d2b6a13a8ba1d172a2b5c87c6c5149039edbf8fa122b98c9ed96f" +dependencies = [ + "async-io", + "block", + "dispatch", + "futures-util", + "glib-sys", + "gobject-sys", + "gtk-sys", + "js-sys", + "log", + "objc", + "objc-foundation", + "objc_id", + "raw-window-handle", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows", +] + [[package]] name = "ron" version = "0.8.0" @@ -2768,6 +2949,15 @@ dependencies = [ "syn 2.0.18", ] +[[package]] +name = "serde_spanned" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -2919,6 +3109,25 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "system-deps" +version = "6.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2d580ff6a20c55dfb86be5f9c238f67835d0e81cbdea8bf5680e0897320331" +dependencies = [ + "cfg-expr", + "heck", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "target-lexicon" +version = "0.12.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69758bda2e78f098e4ccb393021a0963bb3442eac05f135c30f61b7370bbafae" + [[package]] name = "tempfile" version = "3.6.0" @@ -3071,11 +3280,26 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.21.0", +] + [[package]] name = "toml_datetime" -version = "0.6.2" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] [[package]] name = "toml_edit" @@ -3083,9 +3307,22 @@ version = "0.19.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" dependencies = [ - "indexmap", + "indexmap 1.9.3", "toml_datetime", - "winnow", + "winnow 0.4.1", +] + +[[package]] +name = "toml_edit" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +dependencies = [ + "indexmap 2.1.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.5.34", ] [[package]] @@ -3199,6 +3436,12 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +[[package]] +name = "version-compare" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" + [[package]] name = "version_check" version = "0.9.4" @@ -3679,6 +3922,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.5.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.10.1" @@ -3797,7 +4049,7 @@ dependencies = [ "quote", "regex", "syn 1.0.109", - "winnow", + "winnow 0.4.1", "zvariant_utils", ] diff --git a/Cargo.toml b/Cargo.toml index 3795f0c..06592ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,8 +18,11 @@ eframe = { version = "0.22.0", default-features = false, features = [ "default_fonts", # Embed the default egui fonts. "glow", # Use the glow rendering backend. Alternative: "wgpu". "persistence", # Enable restoring app state when restarting the app. + "__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO ] } +image = { version = "0.24", default-features = false, features = ["png"] } log = "0.4" +rfd = "0.11.0" serde = { version = "1", features = ["derive"] } ciborium = { version = "0.2" } diff --git a/src/app.rs b/src/app.rs index d4c453a..290c0c5 100644 --- a/src/app.rs +++ b/src/app.rs @@ -5,7 +5,7 @@ use std::time::Duration; use std::time::Instant; use egui::{ - Align2, Color32, NumExt, Pos2, Rect, RichText, ScrollArea, Slider, Stroke, TextStyle, Vec2, + Align2, ColorImage, Color32, NumExt, Pos2, Rect, RichText, ScrollArea, Slider, Stroke, TextStyle, Vec2, }; use egui_extras::{Column, TableBuilder}; #[cfg(not(target_arch = "wasm32"))] @@ -252,6 +252,9 @@ struct Context { #[serde(skip)] slot_rect: Option, + #[serde(skip)] + take_screenshot: bool, + toggle_dark_mode: bool, debug: bool, @@ -277,6 +280,8 @@ struct ProfApp { cx: Context, + screenshot: Option, + #[cfg(not(target_arch = "wasm32"))] #[serde(skip)] last_update: Option, @@ -1854,6 +1859,7 @@ impl ProfApp { fn reset_ui(cx: &mut Context, windows: &mut [Window]) { cx.show_controls = false; + cx.take_screenshot = false; for window in windows.iter_mut() { window.config.items_selected.clear(); } @@ -1876,6 +1882,7 @@ impl ProfApp { ExpandVertical, ShrinkVertical, ResetVertical, + TakeScreenShot, ToggleControls, ResetUI, NoAction, @@ -1902,6 +1909,8 @@ impl ProfApp { Actions::RedoZoom } else if i.key_pressed(egui::Key::Num0) { Actions::ResetZoom + } else if i.key_pressed(egui::Key::Space) { + Actions::TakeScreenShot } else { Actions::NoAction } @@ -1944,6 +1953,7 @@ impl ProfApp { Actions::ExpandVertical => ProfApp::multiply_scale_factor(cx, 2.0), Actions::ShrinkVertical => ProfApp::multiply_scale_factor(cx, 0.5), Actions::ResetVertical => ProfApp::reset_scale_factor(cx), + Actions::TakeScreenShot => cx.take_screenshot = true, Actions::ToggleControls => cx.show_controls = !cx.show_controls, Actions::ResetUI => ProfApp::reset_ui(cx, windows), Actions::NoAction => {} @@ -2082,6 +2092,7 @@ impl ProfApp { }); }; show_row("Zoom to Interval", "Click and Drag"); + show_row("Take Screenshot", "Ctrl + Space"); show_row("Pan 5%", "Left/Right Arrow"); show_row("Pan 1%", "Shift + Left/Right Arrow"); show_row("Vertical Scroll", "Up/Down Arrow"); @@ -2250,8 +2261,15 @@ impl eframe::App for ProfApp { eframe::set_value(storage, eframe::APP_KEY, self); } + fn post_rendering(&mut self, _screen_size_px: [u32; 2], frame: &eframe::Frame) { + // this is inspired by the Egui screenshot example + if let Some(screenshot) = frame.screenshot() { + self.screenshot = Some(screenshot); + } + } + /// Called each time the UI needs repainting. - fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { + fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { let Self { pending_data_sources, windows, @@ -2261,6 +2279,25 @@ impl eframe::App for ProfApp { .. } = self; + if cx.take_screenshot { + frame.request_screenshot(); + cx.take_screenshot = false; + } + + if let Some(screenshot) = self.screenshot.take() { + if let Some(mut path) = rfd::FileDialog::new().save_file() { + path.set_extension("png"); + image::save_buffer( + &path, + screenshot.as_raw(), + screenshot.width() as u32, + screenshot.height() as u32, + image::ColorType::Rgba8, + ) + .unwrap(); + } + } + if let Some(mut source) = pending_data_sources.pop_front() { // We made one request, so we know there is always zero or one // elements in this list. @@ -2328,7 +2365,7 @@ impl eframe::App for ProfApp { egui::menu::bar(ui, |ui| { ui.menu_button("File", |ui| { if ui.button("Quit").clicked() { - _frame.close(); + frame.close(); } }); });