Files
bevy_cef/src/webview/webview_sprite.rs
elm edf9e064b9 Support Bevy 0.17 (#11)
* update: modify for 0.17

* update: enhance webview functionality and improve plugin implementation

* update: refactor webview system and improve binding group usage

* update: refactor command triggering for webview events and enhance Receive struct

* update: refactor command triggering for webview dev tools

* update: refactor render process handler and improve webview handling

* update: refactor webview browser handling and improve IME caret management

* clippy

* fmt

* update: improve README formatting and clarify version compatibility

* update: support Bevy 0.17 and enhance permissions in settings

* update: enhance CI configuration by adding Wayland and XKB dependencies

* delete: settings.json

* update: refactor shader imports and improve binding group definitions

* update: refactor devtool command triggers for improved clarity

* update: modify LibraryLoader initialization for improved path handling on macOS

* fmt

---------

Co-authored-by: not-elm <elmgameinfo@gmail.com>
2025-10-26 16:55:03 +09:00

147 lines
4.4 KiB
Rust

use crate::common::{CefWebviewUri, WebviewSize};
use crate::prelude::update_webview_image;
use bevy::input::mouse::MouseWheel;
use bevy::prelude::*;
use bevy_cef_core::prelude::{Browsers, RenderTextureMessage};
use std::fmt::Debug;
pub(in crate::webview) struct WebviewSpritePlugin;
impl Plugin for WebviewSpritePlugin {
fn build(&self, app: &mut App) {
if !app.is_plugin_added::<SpritePickingPlugin>() {
app.add_plugins(SpritePickingPlugin);
}
app.add_systems(
Update,
(
setup_observers,
on_mouse_wheel.run_if(on_message::<MouseWheel>),
),
)
.add_systems(
PostUpdate,
render.run_if(on_message::<RenderTextureMessage>),
);
}
}
fn render(
mut er: MessageReader<RenderTextureMessage>,
mut images: ResMut<Assets<bevy::prelude::Image>>,
webviews: Query<&Sprite, With<CefWebviewUri>>,
) {
for texture in er.read() {
if let Ok(sprite) = webviews.get(texture.webview)
&& let Some(image) = images.get_mut(sprite.image.id())
{
update_webview_image(texture.clone(), image);
}
}
}
fn setup_observers(
mut commands: Commands,
webviews: Query<Entity, (Added<CefWebviewUri>, With<Sprite>)>,
) {
for entity in webviews.iter() {
commands
.entity(entity)
.observe(apply_on_pointer_move)
.observe(apply_on_pointer_pressed)
.observe(apply_on_pointer_released);
}
}
fn apply_on_pointer_move(
trigger: On<Pointer<Move>>,
input: Res<ButtonInput<MouseButton>>,
browsers: NonSend<Browsers>,
cameras: Query<(&Camera, &GlobalTransform)>,
webviews: Query<(&Sprite, &WebviewSize, &GlobalTransform)>,
) {
let Some(pos) = obtain_relative_pos_from_trigger(&trigger, &webviews, &cameras) else {
return;
};
browsers.send_mouse_move(&trigger.entity, input.get_pressed(), pos, false);
}
fn apply_on_pointer_pressed(
trigger: On<Pointer<Press>>,
browsers: NonSend<Browsers>,
cameras: Query<(&Camera, &GlobalTransform)>,
webviews: Query<(&Sprite, &WebviewSize, &GlobalTransform)>,
) {
let Some(pos) = obtain_relative_pos_from_trigger(&trigger, &webviews, &cameras) else {
return;
};
browsers.send_mouse_click(&trigger.entity, pos, trigger.button, false);
}
fn apply_on_pointer_released(
trigger: On<Pointer<Release>>,
browsers: NonSend<Browsers>,
cameras: Query<(&Camera, &GlobalTransform)>,
webviews: Query<(&Sprite, &WebviewSize, &GlobalTransform)>,
) {
let Some(pos) = obtain_relative_pos_from_trigger(&trigger, &webviews, &cameras) else {
return;
};
browsers.send_mouse_click(&trigger.entity, pos, trigger.button, true);
}
fn on_mouse_wheel(
mut er: MessageReader<MouseWheel>,
browsers: NonSend<Browsers>,
webviews: Query<(Entity, &Sprite, &WebviewSize, &GlobalTransform)>,
cameras: Query<(&Camera, &GlobalTransform)>,
windows: Query<&Window>,
) {
let Some(cursor_pos) = windows.iter().find_map(|window| window.cursor_position()) else {
return;
};
for event in er.read() {
for (webview, sprite, webview_size, gtf) in webviews.iter() {
let Some(pos) = obtain_relative_pos(sprite, webview_size, gtf, &cameras, cursor_pos)
else {
continue;
};
browsers.send_mouse_wheel(&webview, pos, Vec2::new(event.x, event.y));
}
}
}
fn obtain_relative_pos_from_trigger<E: Debug + Clone + Reflect>(
trigger: &On<Pointer<E>>,
webviews: &Query<(&Sprite, &WebviewSize, &GlobalTransform)>,
cameras: &Query<(&Camera, &GlobalTransform)>,
) -> Option<Vec2> {
let (sprite, webview_size, gtf) = webviews.get(trigger.entity).ok()?;
obtain_relative_pos(
sprite,
webview_size,
gtf,
cameras,
trigger.pointer_location.position,
)
}
fn obtain_relative_pos(
sprite: &Sprite,
webview_size: &WebviewSize,
transform: &GlobalTransform,
cameras: &Query<(&Camera, &GlobalTransform)>,
cursor_pos: Vec2,
) -> Option<Vec2> {
let size = sprite.custom_size?;
let viewport_pos = cameras.iter().find_map(|(camera, camera_gtf)| {
camera
.world_to_viewport(camera_gtf, transform.translation())
.ok()
})?;
let relative_pos = (cursor_pos - viewport_pos + size / 2.0) / size;
Some(relative_pos * webview_size.0)
}