Files
marathon/crates/libmarathon/src/debug_ui/output.rs
2026-02-07 14:11:12 +00:00

126 lines
5.0 KiB
Rust

// 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 <vladyslav.batyrenko@gmail.com>
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<crate::EguiClipboard>,
// NOTE: RequestRedraw not used since we own winit and run unbounded (continuous redraws)
// mut request_redraw_writer: MessageWriter<RequestRedraw>,
mut last_cursor_icon: Local<HashMap<Entity, egui::CursorIcon>>,
egui_global_settings: Res<EguiGlobalSettings>,
window_to_egui_context_map: Res<WindowToEguiContextMap>,
) {
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);
// }
}