Skip to content

Commit

Permalink
Improve WebView<->bevy event communication
Browse files Browse the repository at this point in the history
BevyWry exposes 'register_out_webview_event' and 'register_in_webview_event' that are responsible for the setup of internal event processing.
- 'register_out_webview_event::<E>'
  - Calls 'app.add_event<E>'
  - Calls 'app.observe(out_event::<E>)'
  - 'out_event' observers are relying on 'trigger.entity()' to send the
    event to proper WebView
- 'register_in_webview_event::<E>'
  - Calls 'app.add_event<E>'
  - Calls 'app.add_system(Update, trigger_webview_event::<E>)
  - 'trigger_webview_event' is propagating the event via
    'command.trigger_targets'
  • Loading branch information
PawelBis committed Aug 14, 2024
1 parent 764d174 commit 7542221
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 153 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "bevy_wry"
version = "0.1.9"
version = "0.1.10"
edition = "2021"
categories = ["game-development"]
description = "A tauri-apps/wry integration with Bevy engine"
Expand Down
16 changes: 8 additions & 8 deletions examples/anchors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,18 @@ const BTN_SIZE: LogicalSize<f64> = LogicalSize {
#[derive(Event, Clone, serde::Serialize, serde::Deserialize)]
struct NextAnchor;

#[derive(Event, Clone, serde::Serialize, serde::Deserialize)]
struct InWrapper(pub NextAnchor);
fn init_bevy_wry(app: &mut App) {
BevyWryPlugin::reqister_in_webview_event::<NextAnchor>(app);
}

fn main() {
App::new()
.insert_resource(ClearColor(Color::Srgba(PURPLE)))
.add_event::<NextAnchor>()
.add_plugins(DefaultPlugins)
.add_plugins(BevyWryPlugin::<InWrapper>::default())
.add_plugins(BevyWryPlugin::new(init_bevy_wry))
.add_systems(Startup, setup)
.add_systems(Update, handle_events)
.observe(next_anchor)
.run();
}

Expand Down Expand Up @@ -70,16 +71,15 @@ fn setup(mut commands: Commands) {
);
}

fn handle_events(
mut event_reader: EventReader<InWrapper>,
fn next_anchor(
_: Trigger<NextAnchor>,
mut exit_writer: EventWriter<AppExit>,
mut webviews: Query<&mut Anchor, With<Initialized>>,
) {
if webviews.is_empty() || event_reader.is_empty() {
if webviews.is_empty() {
return;
}

event_reader.clear();
let mut anchor = webviews.single_mut();
let new_anchor = match *anchor {
Anchor::Top => Anchor::TopRight,
Expand Down
67 changes: 34 additions & 33 deletions examples/fullscreen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,38 +8,39 @@ use std::env;

const WEBVIEW_NAME: &str = "MAIN_WEBVIEW";

#[derive(Event, Clone, serde::Serialize, serde::Deserialize)]
enum Command {
/// Command arriving from WebView
#[derive(Event, Clone, serde::Deserialize)]
enum InCommand {
Rotate { angle: f32 },
ShowButton,
Exit,
}

#[derive(Event, Clone, serde::Serialize, serde::Deserialize)]
struct InWrapper(pub Command);

#[derive(Event, Clone, serde::Serialize, serde::Deserialize)]
struct OutWrapper(pub Command);
/// Command send to webview
#[derive(Event, Clone, serde::Serialize)]
enum OutCommand {
ShowButton,
}

impl OutWryEvent for OutWrapper {
impl OutWryEvent for OutCommand {
fn to_script(&self) -> String {
match self.0 {
// ShowButton is our only OutCommand
// Please note that 'showButton' is a method implemented in
// our UI code: examples/web/ui.html
Command::ShowButton => "showButton()".to_string(),
_ => unreachable!(),
match self {
OutCommand::ShowButton => "showButton()".to_string(),
}
}
}

fn init_bevy_wry(app: &mut App) {
BevyWryPlugin::reqister_in_webview_event::<InCommand>(app);
BevyWryPlugin::reqister_out_webview_event::<OutCommand>(app);
}

fn main() {
App::new()
.insert_resource(ClearColor(Color::Srgba(PURPLE)))
.add_plugins(DefaultPlugins)
.add_plugins(BevyWryPlugin::<InWrapper, OutWrapper>::default())
.add_plugins(BevyWryPlugin::new(init_bevy_wry))
.add_systems(Startup, setup)
.add_systems(Update, handle_events)
.observe(in_commands)
.run();
}

Expand All @@ -66,27 +67,27 @@ fn setup(mut commands: Commands) {
);
}

fn handle_events(
mut event_reader: EventReader<InWrapper>,
mut event_writer: EventWriter<OutWrapper>,
fn in_commands(
trigger: Trigger<InCommand>,
mut commands: Commands,
mut exit_writer: EventWriter<AppExit>,
mut sprite: Query<(&mut Transform, &Sprite)>,
) {
for event in event_reader.read() {
match event.0 {
Command::Rotate { angle } => {
let (mut transform, _) = sprite.single_mut();
transform.rotate_z(f32::to_radians(angle));
let event = trigger.event();
let webview_entity = trigger.entity();

let (_, z) = transform.rotation.to_axis_angle();
if z == f32::to_radians(180.0) {
event_writer.send(OutWrapper(Command::ShowButton));
}
}
Command::Exit => {
exit_writer.send(AppExit::Success);
match event {
InCommand::Rotate { angle } => {
let (mut transform, _) = sprite.single_mut();
transform.rotate_z(f32::to_radians(*angle));

let (_, z) = transform.rotation.to_axis_angle();
if z == f32::to_radians(180.0) {
commands.trigger_targets(OutCommand::ShowButton, webview_entity);
}
_ => (),
}
InCommand::Exit => {
exit_writer.send(AppExit::Success);
}
}
}
1 change: 1 addition & 0 deletions src/components/webview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ pub struct Initialized;

#[derive(Default)]
pub struct WebViews {
/// TODO: Use HashMap<Entity, WebView> instead
webviews: HashMap<String, WebView>,
}

Expand Down
53 changes: 32 additions & 21 deletions src/events/mod.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
pub mod error;
pub mod system;

use std::sync::{Arc, Mutex, MutexGuard};
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};

use bevy::prelude::{Deref, Event, Resource};
use bevy::prelude::*;
use serde::{Deserialize, Serialize};

pub trait OutWryEvent: Event + Serialize + Send {
fn to_script(&self) -> String;
fn target_webview(&self) -> Option<String> {
None
}
}

pub trait InWryEvent<'de>: Event + Deserialize<'de> + Send {}
Expand All @@ -19,32 +15,47 @@ impl<'de, T> InWryEvent<'de> for T where T: Event + Deserialize<'de> + Send {}
#[derive(Deserialize, Serialize, Event)]
pub struct EmptyOutEvent;

impl OutWryEvent for EmptyOutEvent {
fn to_script(&self) -> String {
"".to_string()
}
}

#[derive(Deserialize, Serialize, Event)]
pub struct EmptyInEvent;

#[derive(Deref, Resource)]
pub struct MessageBus<T: Send>(pub Arc<Mutex<Vec<T>>>);
/// MessageBus gathers all webview events.
#[derive(Deref)]
pub struct MessageBus {
messages: Arc<RwLock<Vec<String>>>,
}

impl<T: Send> MessageBus<T> {
pub fn lock(&self) -> MutexGuard<Vec<T>> {
self.0.lock().unwrap()
impl MessageBus {
pub fn write(&self) -> RwLockWriteGuard<Vec<String>> {
self.messages.write().unwrap()
}

pub fn read(&self) -> RwLockReadGuard<Vec<String>> {
self.messages.read().unwrap()
}

pub fn clear(&self) {
self.messages.write().unwrap().clear();
}
}

impl<T: Send> Default for MessageBus<T> {
impl Default for MessageBus {
fn default() -> Self {
Self(Arc::new(Mutex::new(Vec::<T>::new())))
Self {
messages: Arc::new(RwLock::new(Vec::new())),
}
}
}

impl<T: Send> Clone for MessageBus<T> {
impl Clone for MessageBus {
fn clone(&self) -> Self {
Self(self.0.clone())
Self {
messages: self.messages.clone(),
}
}
}

#[derive(Component, Deref, Default)]
pub struct InMessageBus(MessageBus);

#[derive(Component, Deref, Default)]
pub struct OutMessageBus(MessageBus);
39 changes: 0 additions & 39 deletions src/events/system.rs

This file was deleted.

68 changes: 27 additions & 41 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,11 @@ mod error;
pub mod events;
pub mod systems;

use std::marker::PhantomData;

use bevy::prelude::*;
use bevy::utils;
use components::webview::WebViews;
use events::system::{consume_in_events, send_out_events};
use events::{EmptyInEvent, EmptyOutEvent, InWryEvent, MessageBus, OutWryEvent};
use events::{InWryEvent, OutWryEvent};

use systems::{out_events, trigger_webview_event};
pub use wry;
pub use wry::dpi::{Position as WryPosition, Size as WrySize};

Expand All @@ -19,49 +16,35 @@ pub use wry::dpi::{Position as WryPosition, Size as WrySize};
#[derive(Resource, Deref, Clone, Default)]
pub struct UrlResource(pub String);

/// Creates a [WebView] window that can be used for both in game and editor UI rendering.
///
/// You can send events to webview via [EventWriter]<[OutEvent<Out>]> and read incoming
/// events with [EventReader]<[InEvent]>.
/// Out events are sent via webview.:evaluate_script.
pub struct BevyWryPlugin<I = EmptyInEvent, O = EmptyOutEvent>
where
for<'de> I: InWryEvent<'de>,
O: OutWryEvent,
{
_i: PhantomData<I>,
_o: PhantomData<O>,
pub struct BevyWryPlugin {
setup_callback: fn(&mut App),
}

impl<I, O> Default for BevyWryPlugin<I, O>
where
for<'de> I: InWryEvent<'de>,
O: OutWryEvent,
{
fn default() -> Self {
Self {
_i: PhantomData,
_o: PhantomData,
}
impl BevyWryPlugin {
pub fn new(setup_callback: fn(&mut App)) -> Self {
Self { setup_callback }
}

pub fn reqister_in_webview_event<E>(app: &mut App)
where
for<'de> E: InWryEvent<'de>,
{
app.add_event::<E>()
.add_systems(Update, trigger_webview_event::<E>);
}

pub fn reqister_out_webview_event<E: OutWryEvent>(app: &mut App) {
app.add_event::<E>().observe(out_events::<E>);
}
}

impl<I, O> Plugin for BevyWryPlugin<I, O>
where
for<'de> I: InWryEvent<'de>,
O: OutWryEvent,
{
impl Plugin for BevyWryPlugin {
fn build(&self, app: &mut App) {
let _app = app
.add_event::<I>()
.add_event::<O>()
let app = app
.insert_non_send_resource(WebViews::default())
.init_resource::<MessageBus<I>>()
.init_resource::<MessageBus<O>>()
.add_systems(Update, systems::create_webviews::<I>)
.add_systems(Update, systems::create_webviews)
.add_systems(Update, systems::keep_webviews_in_bounds)
.add_systems(Update, consume_in_events::<I>)
.add_systems(Update, send_out_events::<O>.map(utils::error));
.add_systems(PostUpdate, systems::clear_busses);

#[cfg(any(
target_os = "linux",
Expand All @@ -82,8 +65,11 @@ where
(unsafe { (*error).error_code }) == 170
}));

_app.add_systems(Update, gtk_iteration_do);
let app = app.add_systems(Update, gtk_iteration_do);
}

let setup = self.setup_callback;
setup(app);
}
}

Expand Down
Loading

0 comments on commit 7542221

Please sign in to comment.