mirror of
https://github.com/emilk/egui.git
synced 2026-09-01 06:10:06 -04:00
Add screenshot support for eframe web (#5438)
This implements web support for taking screenshots in an eframe app (and adds a nice demo). It also updates the native screenshot implementation to work with the wgpu gl backend. The wgpu implementation is quite different than the native one because we can't block to wait for the screenshot result, so instead I use a channel to pass the result to a future frame asynchronously. * Closes <https://github.com/emilk/egui/issues/5425> * [x] I have followed the instructions in the PR template https://github.com/user-attachments/assets/67cad40b-0384-431d-96a3-075cc3cb98fb
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
use egui::TexturesDelta;
|
||||
use egui::{TexturesDelta, UserData, ViewportCommand};
|
||||
use std::mem;
|
||||
|
||||
use crate::{epi, App};
|
||||
|
||||
@@ -16,6 +17,9 @@ pub struct AppRunner {
|
||||
last_save_time: f64,
|
||||
pub(crate) text_agent: TextAgent,
|
||||
|
||||
// If not empty, the painter should capture the next frame
|
||||
screenshot_commands: Vec<UserData>,
|
||||
|
||||
// Output for the last run:
|
||||
textures_delta: TexturesDelta,
|
||||
clipped_primitives: Option<Vec<egui::ClippedPrimitive>>,
|
||||
@@ -36,7 +40,8 @@ impl AppRunner {
|
||||
app_creator: epi::AppCreator<'static>,
|
||||
text_agent: TextAgent,
|
||||
) -> Result<Self, String> {
|
||||
let painter = super::ActiveWebPainter::new(canvas, &web_options).await?;
|
||||
let egui_ctx = egui::Context::default();
|
||||
let painter = super::ActiveWebPainter::new(egui_ctx.clone(), canvas, &web_options).await?;
|
||||
|
||||
let info = epi::IntegrationInfo {
|
||||
web_info: epi::WebInfo {
|
||||
@@ -47,7 +52,6 @@ impl AppRunner {
|
||||
};
|
||||
let storage = LocalStorage::default();
|
||||
|
||||
let egui_ctx = egui::Context::default();
|
||||
egui_ctx.set_os(egui::os::OperatingSystem::from_user_agent(
|
||||
&super::user_agent().unwrap_or_default(),
|
||||
));
|
||||
@@ -110,6 +114,7 @@ impl AppRunner {
|
||||
needs_repaint,
|
||||
last_save_time: now_sec(),
|
||||
text_agent,
|
||||
screenshot_commands: vec![],
|
||||
textures_delta: Default::default(),
|
||||
clipped_primitives: None,
|
||||
};
|
||||
@@ -205,6 +210,8 @@ impl AppRunner {
|
||||
pub fn logic(&mut self) {
|
||||
// We sometimes miss blur/focus events due to the text agent, so let's just poll each frame:
|
||||
self.update_focus();
|
||||
// We might have received a screenshot
|
||||
self.painter.handle_screenshots(&mut self.input.raw.events);
|
||||
|
||||
let canvas_size = super::canvas_size_in_points(self.canvas(), self.egui_ctx());
|
||||
let mut raw_input = self.input.new_frame(canvas_size);
|
||||
@@ -225,12 +232,19 @@ impl AppRunner {
|
||||
if viewport_output.len() > 1 {
|
||||
log::warn!("Multiple viewports not yet supported on the web");
|
||||
}
|
||||
for viewport_output in viewport_output.values() {
|
||||
for command in &viewport_output.commands {
|
||||
// TODO(emilk): handle some of the commands
|
||||
log::warn!(
|
||||
"Unhandled egui viewport command: {command:?} - not implemented in web backend"
|
||||
);
|
||||
for (_viewport_id, viewport_output) in viewport_output {
|
||||
for command in viewport_output.commands {
|
||||
match command {
|
||||
ViewportCommand::Screenshot(user_data) => {
|
||||
self.screenshot_commands.push(user_data);
|
||||
}
|
||||
_ => {
|
||||
// TODO(emilk): handle some of the commands
|
||||
log::warn!(
|
||||
"Unhandled egui viewport command: {command:?} - not implemented in web backend"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,6 +264,7 @@ impl AppRunner {
|
||||
&clipped_primitives,
|
||||
self.egui_ctx.pixels_per_point(),
|
||||
&textures_delta,
|
||||
mem::take(&mut self.screenshot_commands),
|
||||
) {
|
||||
log::error!("Failed to paint: {}", super::string_from_js_value(&err));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user