// Copyright (c) 2021 Vladyslav Batyrenko // SPDX-License-Identifier: MIT // // This code is vendored from bevy_egui: https://github.com/vladbat00/bevy_egui // Original author: Vladyslav Batyrenko use super::{ EguiContext, EguiContextSettings, EguiFullOutput, EguiGlobalSettings, EguiOutput, EguiRenderOutput, helpers, input::WindowToEguiContextMap, }; use bevy::ecs::{ entity::Entity, system::{Commands, Local, Query, Res}, }; use bevy::platform::collections::HashMap; use bevy::window::CursorIcon; /// Reads Egui output. #[allow(clippy::too_many_arguments)] pub fn process_output_system( mut commands: Commands, mut context_query: Query<( Entity, &mut EguiContext, &mut EguiFullOutput, &mut EguiRenderOutput, &mut EguiOutput, &EguiContextSettings, )>, #[cfg(all(feature = "manage_clipboard", not(target_os = "android")))] mut egui_clipboard: bevy::ecs::system::ResMut, // NOTE: RequestRedraw not used since we own winit and run unbounded (continuous redraws) // mut request_redraw_writer: MessageWriter, mut last_cursor_icon: Local>, egui_global_settings: Res, window_to_egui_context_map: Res, ) { let mut should_request_redraw = false; for (entity, mut context, mut full_output, mut render_output, mut egui_output, settings) in context_query.iter_mut() { let ctx = context.get_mut(); let Some(full_output) = full_output.0.take() else { bevy::log::error!( "bevy_egui pass output has not been prepared (if EguiSettings::run_manually is set to true, make sure to call egui::Context::run or egui::Context::begin_pass and egui::Context::end_pass)" ); continue; }; let egui::FullOutput { platform_output, shapes, textures_delta, pixels_per_point, viewport_output: _, } = full_output; let paint_jobs = ctx.tessellate(shapes, pixels_per_point); render_output.paint_jobs = paint_jobs; render_output.textures_delta = textures_delta; egui_output.platform_output = platform_output; for command in &egui_output.platform_output.commands { match command { egui::OutputCommand::CopyText(_text) => { #[cfg(all(feature = "manage_clipboard", not(target_os = "android")))] if !_text.is_empty() { egui_clipboard.set_text(_text); } } egui::OutputCommand::CopyImage(_image) => { #[cfg(all(feature = "manage_clipboard", not(target_os = "android")))] egui_clipboard.set_image(_image); } egui::OutputCommand::OpenUrl(_url) => { #[cfg(feature = "open_url")] { let egui::output::OpenUrl { url, new_tab } = _url; let target = if *new_tab { "_blank" } else { settings .default_open_url_target .as_deref() .unwrap_or("_self") }; if let Err(err) = webbrowser::open_browser_with_options( webbrowser::Browser::Default, url, webbrowser::BrowserOptions::new().with_target_hint(target), ) { bevy::log::error!("Failed to open '{}': {:?}", url, err); } } } } } if egui_global_settings.enable_cursor_icon_updates && settings.enable_cursor_icon_updates && let Some(window_entity) = window_to_egui_context_map.context_to_window.get(&entity) { let last_cursor_icon = last_cursor_icon.entry(entity).or_default(); if *last_cursor_icon != egui_output.platform_output.cursor_icon { commands .entity(*window_entity) .try_insert(CursorIcon::System( helpers::egui_to_winit_cursor_icon(egui_output.platform_output.cursor_icon) .unwrap_or(bevy::window::SystemCursorIcon::Default), )); *last_cursor_icon = egui_output.platform_output.cursor_icon; } } let needs_repaint = !render_output.is_empty(); should_request_redraw |= ctx.has_requested_repaint() && needs_repaint; } // NOTE: RequestRedraw not needed - we own winit and run unbounded (continuous redraws) // if should_request_redraw { // request_redraw_writer.write(RequestRedraw); // } }