Skip to content

Commit

Permalink
trait based event system
Browse files Browse the repository at this point in the history
  • Loading branch information
ealmloff committed Aug 25, 2023
1 parent a727181 commit 299b123
Show file tree
Hide file tree
Showing 28 changed files with 2,411 additions and 738 deletions.
4 changes: 2 additions & 2 deletions packages/desktop/src/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ impl DesktopElement {
}

impl RenderedElementBacking for DesktopElement {
fn get_raw_element(&self) -> dioxus_html::MountedResult<&dyn std::any::Any> {
Ok(self)
fn as_any(&self) -> &dyn std::any::Any {
self
}

fn get_client_rect(
Expand Down
24 changes: 18 additions & 6 deletions packages/desktop/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ pub use desktop_context::{
};
use desktop_context::{EventData, UserWindowEvent, WebviewQueue, WindowEventHandlers};
use dioxus_core::*;
use dioxus_html::MountedData;
use dioxus_html::{native_bind::NativeFileEngine, FormData, HtmlEvent};
use dioxus_html::{native_bind::NativeFileEngine, HtmlEvent};
use dioxus_html::{FileEngine, HasFormData, MountedData};
use element::DesktopElement;
use eval::init_eval;
use futures_util::{pin_mut, FutureExt};
Expand Down Expand Up @@ -340,14 +340,26 @@ pub fn launch_with_props<P: 'static>(root: Component<P>, props: P, cfg: Config)
if let Ok(file_diolog) =
serde_json::from_value::<file_upload::FileDialogRequest>(msg.params())
{
struct DesktopFileUploadForm {
files: Arc<NativeFileEngine>,
}

impl HasFormData for DesktopFileUploadForm {
fn files(&self) -> Option<Arc<dyn FileEngine>> {
Some(self.files.clone())
}

fn as_any(&self) -> &dyn std::any::Any {
self
}
}

let id = ElementId(file_diolog.target);
let event_name = &file_diolog.event;
let event_bubbles = file_diolog.bubbles;
let files = file_upload::get_file_event(&file_diolog);
let data = Rc::new(FormData {
value: Default::default(),
values: Default::default(),
files: Some(Arc::new(NativeFileEngine::new(files))),
let data = Rc::new(DesktopFileUploadForm {
files: Arc::new(NativeFileEngine::new(files)),
});

let view = webviews.get_mut(&event.1).unwrap();
Expand Down
3 changes: 2 additions & 1 deletion packages/html/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ features = [
"PointerEvent",
"FocusEvent",
"CompositionEvent",
"ClipboardEvent",
]

[dev-dependencies]
Expand All @@ -51,11 +50,13 @@ serde_json = "1"
default = ["serialize", "mounted"]
serialize = [
"serde",
"serde/rc",
"serde_repr",
"serde_json",
"euclid/serde",
"keyboard-types/serde",
"dioxus-core/serialize",
"enumset/serde",
]
mounted = [
"web-sys/Element",
Expand Down
4 changes: 1 addition & 3 deletions packages/html/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,6 @@ pub fn event_bubbles(evt: &str) -> bool {
}
}

use std::future::Future;

#[doc(hidden)]
pub trait EventReturn<P>: Sized {
fn spawn(self, _cx: &dioxus_core::ScopeState) {}
Expand All @@ -164,7 +162,7 @@ pub struct AsyncMarker;

impl<T> EventReturn<AsyncMarker> for T
where
T: Future<Output = ()> + 'static,
T: std::future::Future<Output = ()> + 'static,
{
#[inline]
fn spawn(self, cx: &dioxus_core::ScopeState) {
Expand Down
118 changes: 113 additions & 5 deletions packages/html/src/events/animation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,120 @@ use dioxus_core::Event;

pub type AnimationEvent = Event<AnimationData>;

#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, PartialEq)]
pub struct AnimationData {
pub animation_name: String,
pub pseudo_element: String,
pub elapsed_time: f32,
inner: Box<dyn HasAnimationData>,
}

impl AnimationData {
pub fn animation_name(&self) -> String {
self.inner.animation_name()
}

pub fn pseudo_element(&self) -> String {
self.inner.pseudo_element()
}

pub fn elapsed_time(&self) -> f32 {
self.inner.elapsed_time()
}

pub fn downcast<T: 'static>(&self) -> Option<&T> {
self.inner.as_ref().as_any().downcast_ref::<T>()
}
}

impl<E: HasAnimationData> From<E> for AnimationData {
fn from(e: E) -> Self {
Self { inner: Box::new(e) }
}
}

impl std::fmt::Debug for AnimationData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AnimationData")
.field("animation_name", &self.animation_name())
.field("pseudo_element", &self.pseudo_element())
.field("elapsed_time", &self.elapsed_time())
.finish()
}
}

impl PartialEq for AnimationData {
fn eq(&self, other: &Self) -> bool {
self.animation_name() == other.animation_name()
&& self.pseudo_element() == other.pseudo_element()
&& self.elapsed_time() == other.elapsed_time()
}
}

#[cfg(feature = "serialize")]
#[derive(serde::Serialize, serde::Deserialize)]
struct SerializedAnimationData {
animation_name: String,
pseudo_element: String,
elapsed_time: f32,
}

#[cfg(feature = "serialize")]
impl From<&AnimationData> for SerializedAnimationData {
fn from(data: &AnimationData) -> Self {
Self {
animation_name: data.animation_name(),
pseudo_element: data.pseudo_element(),
elapsed_time: data.elapsed_time(),
}
}
}

#[cfg(feature = "serialize")]
impl HasAnimationData for SerializedAnimationData {
fn animation_name(&self) -> String {
self.animation_name.clone()
}

fn pseudo_element(&self) -> String {
self.pseudo_element.clone()
}

fn elapsed_time(&self) -> f32 {
self.elapsed_time
}

fn as_any(&self) -> &dyn std::any::Any {
self
}
}

#[cfg(feature = "serialize")]
impl serde::Serialize for AnimationData {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
SerializedAnimationData::from(self).serialize(serializer)
}
}

#[cfg(feature = "serialize")]
impl<'de> serde::Deserialize<'de> for AnimationData {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let data = SerializedAnimationData::deserialize(deserializer)?;
Ok(Self {
inner: Box::new(data),
})
}
}

/// A trait for any object that has the data for an animation event
pub trait HasAnimationData: std::any::Any {
/// The name of the animation
fn animation_name(&self) -> String;

/// The name of the pseudo-element the animation runs on
fn pseudo_element(&self) -> String;

/// The amount of time the animation has been running
fn elapsed_time(&self) -> f32;

/// return self as Any
fn as_any(&self) -> &dyn std::any::Any;
}

impl_event! [
Expand Down
75 changes: 72 additions & 3 deletions packages/html/src/events/clipboard.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,79 @@
use dioxus_core::Event;

pub type ClipboardEvent = Event<ClipboardData>;
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq)]

pub struct ClipboardData {
// DOMDataTransfer clipboardData
inner: Box<dyn HasClipboardData>,
}

impl<E: HasClipboardData> From<E> for ClipboardData {
fn from(e: E) -> Self {
Self { inner: Box::new(e) }
}
}

impl std::fmt::Debug for ClipboardData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ClipboardData").finish()
}
}

impl PartialEq for ClipboardData {
fn eq(&self, _other: &Self) -> bool {
true
}
}

impl ClipboardData {
pub fn new(inner: impl HasClipboardData) -> Self {
Self {
inner: Box::new(inner),
}
}

pub fn downcast<T: 'static>(&self) -> Option<&T> {
self.inner.as_ref().as_any().downcast_ref::<T>()
}
}

#[cfg(feature = "serialize")]
#[derive(serde::Serialize, serde::Deserialize)]
struct SerializedClipboardData {}

#[cfg(feature = "serialize")]
impl From<&ClipboardData> for SerializedClipboardData {
fn from(_: &ClipboardData) -> Self {
Self {}
}
}

#[cfg(feature = "serialize")]
impl HasClipboardData for SerializedClipboardData {
fn as_any(&self) -> &dyn std::any::Any {
self
}
}

#[cfg(feature = "serialize")]
impl serde::Serialize for ClipboardData {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
SerializedClipboardData::from(self).serialize(serializer)
}
}

#[cfg(feature = "serialize")]
impl<'de> serde::Deserialize<'de> for ClipboardData {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let data = SerializedClipboardData::deserialize(deserializer)?;
Ok(Self {
inner: Box::new(data),
})
}
}

pub trait HasClipboardData: std::any::Any {
/// return self as Any
fn as_any(&self) -> &dyn std::any::Any;
}

impl_event![
Expand Down
85 changes: 82 additions & 3 deletions packages/html/src/events/composition.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,89 @@
use dioxus_core::Event;

pub type CompositionEvent = Event<CompositionData>;
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq)]

pub struct CompositionData {
pub data: String,
inner: Box<dyn HasCompositionData>,
}

impl std::fmt::Debug for CompositionData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CompositionData")
.field("data", &self.data())
.finish()
}
}

impl<E: HasCompositionData> From<E> for CompositionData {
fn from(e: E) -> Self {
Self { inner: Box::new(e) }
}
}

impl PartialEq for CompositionData {
fn eq(&self, other: &Self) -> bool {
self.data() == other.data()
}
}

impl CompositionData {
pub fn data(&self) -> String {
self.inner.data()
}

pub fn downcast<T: 'static>(&self) -> Option<&T> {
self.inner.as_any().downcast_ref()
}
}

#[cfg(feature = "serialize")]
#[derive(serde::Serialize, serde::Deserialize)]
struct SerializedCompositionData {
data: String,
}

#[cfg(feature = "serialize")]
impl From<&CompositionData> for SerializedCompositionData {
fn from(data: &CompositionData) -> Self {
Self { data: data.data() }
}
}

#[cfg(feature = "serialize")]
impl HasCompositionData for SerializedCompositionData {
fn data(&self) -> String {
self.data.clone()
}

fn as_any(&self) -> &dyn std::any::Any {
self
}
}

#[cfg(feature = "serialize")]
impl serde::Serialize for CompositionData {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
SerializedCompositionData::from(self).serialize(serializer)
}
}

#[cfg(feature = "serialize")]
impl<'de> serde::Deserialize<'de> for CompositionData {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let data = SerializedCompositionData::deserialize(deserializer)?;
Ok(Self {
inner: Box::new(data),
})
}
}

/// A trait for any object that has the data for a composition event
pub trait HasCompositionData: std::any::Any {
/// The characters generated by the input method that raised the event
fn data(&self) -> String;

/// return self as Any
fn as_any(&self) -> &dyn std::any::Any;
}

impl_event! [
Expand Down
Loading

0 comments on commit 299b123

Please sign in to comment.