This commit is contained in:
not-elm
2025-08-10 21:28:45 +09:00
commit 23bdc65da3
91 changed files with 20122 additions and 0 deletions

View File

@@ -0,0 +1,143 @@
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, RenderTexture};
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_event::<MouseWheel>),
),
)
.add_systems(PostUpdate, render.run_if(on_event::<RenderTexture>));
}
}
fn render(
mut er: EventReader<RenderTexture>,
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: Trigger<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.target, input.get_pressed(), pos, false);
}
fn apply_on_pointer_pressed(
trigger: Trigger<Pointer<Pressed>>,
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.target, pos, trigger.button, false);
}
fn apply_on_pointer_released(
trigger: Trigger<Pointer<Released>>,
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.target, pos, trigger.button, true);
}
fn on_mouse_wheel(
mut er: EventReader<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: &Trigger<Pointer<E>>,
webviews: &Query<(&Sprite, &WebviewSize, &GlobalTransform)>,
cameras: &Query<(&Camera, &GlobalTransform)>,
) -> Option<Vec2> {
let (sprite, webview_size, gtf) = webviews.get(trigger.target()).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)
}