diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs index e29b5e18e..7cb4303cc 100644 --- a/packages/core/src/diff.rs +++ b/packages/core/src/diff.rs @@ -456,12 +456,16 @@ impl<'bump> DiffMachine<'bump> { new.dom_id.set(root); + // todo: attributes currently rely on the element on top of the stack, but in theory, we only need the id of the + // element to modify its attributes. + // it would result in fewer instructions if we just set the id directly. + // it would also clean up this code some, but that's not very important anyways + // Don't push the root if we don't have to let mut has_comitted = false; let mut please_commit = |edits: &mut Vec| { if !has_comitted { has_comitted = true; - log::info!("planning on committing... {:#?}, {:#?}", old, new); edits.push(PushRoot { id: root.unwrap().as_u64(), }); @@ -476,12 +480,10 @@ impl<'bump> DiffMachine<'bump> { // TODO: take a more efficient path than this if old.attributes.len() == new.attributes.len() { for (old_attr, new_attr) in old.attributes.iter().zip(new.attributes.iter()) { - log::info!("checking attribute"); if old_attr.value != new_attr.value { please_commit(&mut self.mutations.edits); self.mutations.set_attribute(new_attr); } else if new_attr.is_volatile { - log::debug!("setting due to volatile atttributes"); please_commit(&mut self.mutations.edits); self.mutations.set_attribute(new_attr); } diff --git a/packages/core/src/events.rs b/packages/core/src/events.rs index b0ff08ea3..042884c68 100644 --- a/packages/core/src/events.rs +++ b/packages/core/src/events.rs @@ -106,7 +106,7 @@ pub enum EventPriority { } #[derive(Debug)] -pub struct DioxusEvent { +pub struct DioxusEvent { inner: T, raw: Box, } @@ -595,19 +595,21 @@ pub mod on { ]; } + #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug)] pub struct ClipboardEventInner( // DOMDataTransfer clipboardData ); + #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug)] pub struct CompositionEventInner { pub data: String, } + #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug)] pub struct KeyboardEventInner { - pub alt_key: bool, pub char_code: u32, /// Identify which "key" was entered. @@ -650,25 +652,41 @@ pub mod on { /// ``` /// pub key_code: KeyCode, + + /// Indicate if the `alt` modifier key was pressed during this keyboard event + pub alt_key: bool, + + /// Indicate if the `ctrl` modifier key was pressed during this keyboard event pub ctrl_key: bool, - pub locale: String, - pub location: usize, + + /// Indicate if the `meta` modifier key was pressed during this keyboard event pub meta_key: bool, - pub repeat: bool, + + /// Indicate if the `shift` modifier key was pressed during this keyboard event pub shift_key: bool, + + pub locale: String, + + pub location: usize, + + pub repeat: bool, + pub which: usize, // get_modifier_state: bool, } + #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug)] pub struct FocusEventInner {/* DOMEventInner: Send + SyncTarget relatedTarget */} + #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug)] pub struct FormEventInner { /* DOMEventInner: Send + SyncTarget relatedTarget */ pub value: String, } + #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug)] pub struct MouseEventInner { pub alt_key: bool, @@ -686,6 +704,7 @@ pub mod on { // fn get_modifier_state(&self, key_code: &str) -> bool; } + #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug)] pub struct PointerEventInner { // Mouse only @@ -714,9 +733,11 @@ pub mod on { // pub get_modifier_state: bool, } + #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug)] pub struct SelectionEventInner {} + #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug)] pub struct TouchEventInner { pub alt_key: bool, @@ -729,6 +750,7 @@ pub mod on { // touches: DOMTouchList, } + #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug)] pub struct WheelEventInner { pub delta_mode: u32, @@ -737,15 +759,18 @@ pub mod on { pub delta_z: f64, } + #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug)] pub struct MediaEventInner {} + #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug)] pub struct ImageEventInner { // load error pub load_error: bool, } + #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug)] pub struct AnimationEventInner { pub animation_name: String, @@ -753,6 +778,7 @@ pub mod on { pub elapsed_time: f32, } + #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug)] pub struct TransitionEventInner { pub property_name: String, @@ -760,10 +786,12 @@ pub mod on { pub elapsed_time: f32, } + #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug)] pub struct ToggleEventInner {} } +#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[derive(Clone, Copy, Debug)] pub enum KeyCode { Backspace = 8, diff --git a/packages/desktop/examples/crm.rs b/packages/desktop/examples/crm.rs index 14a299313..14ac2d1ca 100644 --- a/packages/desktop/examples/crm.rs +++ b/packages/desktop/examples/crm.rs @@ -63,13 +63,13 @@ static App: FC<()> = |cx, _| { h2 {"Add new client" margin_bottom: "10px" } form { class: "pure-form" input { class: "new-client firstname" placeholder: "First name" value: "{firstname}" - oninput: move |evt| firstname.set(evt.value()) + oninput: move |evt| firstname.set(evt.value.clone()) } input { class: "new-client lastname" placeholder: "Last name" value: "{lastname}" - oninput: move |evt| lastname.set(evt.value()) + oninput: move |evt| lastname.set(evt.value.clone()) } textarea { class: "new-client description" placeholder: "Description" value: "{description}" - oninput: move |evt| description.set(evt.value()) + oninput: move |evt| description.set(evt.value.clone()) } } button { class: "pure-button pure-button-primary", onclick: {add_new}, "Add New" } diff --git a/packages/desktop/src/events.rs b/packages/desktop/src/events.rs index 75c7f3cfb..a7b69187a 100644 --- a/packages/desktop/src/events.rs +++ b/packages/desktop/src/events.rs @@ -17,22 +17,114 @@ struct ImEvent { event: String, mounted_dom_id: u64, scope: u64, + contents: serde_json::Value, } -pub fn trigger_from_serialized(val: serde_json::Value) -> UserEvent { - let mut data: Vec = serde_json::from_value(val).unwrap(); - let data = data.drain(..).next().unwrap(); - let scope = ScopeId(data.scope as usize); - let mounted_dom_id = Some(ElementId(data.mounted_dom_id as usize)); +pub fn trigger_from_serialized(val: serde_json::Value) -> UserEvent { + let mut ims: Vec = serde_json::from_value(val).unwrap(); + let ImEvent { + event, + mounted_dom_id, + scope, + contents, + } = ims.into_iter().next().unwrap(); + + let scope = ScopeId(scope as usize); + let mounted_dom_id = Some(ElementId(mounted_dom_id as usize)); + + let name = event_name_from_typ(&event); + let event = make_synthetic_event(&event, contents); UserEvent { - name: "click", + name, event, scope, mounted_dom_id, } } +fn make_synthetic_event(name: &str, val: serde_json::Value) -> SyntheticEvent { + use dioxus_core::events::on::*; + use dioxus_core::events::DioxusEvent; + + match name { + "copy" | "cut" | "paste" => SyntheticEvent::ClipboardEvent(ClipboardEvent( + DioxusEvent::new(ClipboardEventInner(), ()), + )), + "compositionend" | "compositionstart" | "compositionupdate" => { + SyntheticEvent::CompositionEvent(CompositionEvent(DioxusEvent::new( + serde_json::from_value(val).unwrap(), + (), + ))) + } + "keydown" | "keypress" | "keyup" => SyntheticEvent::KeyboardEvent(KeyboardEvent( + DioxusEvent::new(serde_json::from_value(val).unwrap(), ()), + )), + "focus" | "blur" => { + SyntheticEvent::FocusEvent(FocusEvent(DioxusEvent::new(FocusEventInner {}, ()))) + } + "change" => SyntheticEvent::GenericEvent(DioxusEvent::new((), ())), + + // todo: these handlers might get really slow if the input box gets large and allocation pressure is heavy + // don't have a good solution with the serialized event problem + "input" | "invalid" | "reset" | "submit" => SyntheticEvent::FormEvent(FormEvent( + DioxusEvent::new(serde_json::from_value(val).unwrap(), ()), + )), + "click" | "contextmenu" | "doubleclick" | "drag" | "dragend" | "dragenter" | "dragexit" + | "dragleave" | "dragover" | "dragstart" | "drop" | "mousedown" | "mouseenter" + | "mouseleave" | "mousemove" | "mouseout" | "mouseover" | "mouseup" => { + SyntheticEvent::MouseEvent(MouseEvent(DioxusEvent::new( + serde_json::from_value(val).unwrap(), + (), + ))) + } + "pointerdown" | "pointermove" | "pointerup" | "pointercancel" | "gotpointercapture" + | "lostpointercapture" | "pointerenter" | "pointerleave" | "pointerover" | "pointerout" => { + SyntheticEvent::PointerEvent(PointerEvent(DioxusEvent::new( + serde_json::from_value(val).unwrap(), + (), + ))) + } + "select" => SyntheticEvent::SelectionEvent(SelectionEvent(DioxusEvent::new( + SelectionEventInner {}, + (), + ))), + + "touchcancel" | "touchend" | "touchmove" | "touchstart" => SyntheticEvent::TouchEvent( + TouchEvent(DioxusEvent::new(serde_json::from_value(val).unwrap(), ())), + ), + + "scroll" => SyntheticEvent::GenericEvent(DioxusEvent::new((), ())), + + "wheel" => SyntheticEvent::WheelEvent(WheelEvent(DioxusEvent::new( + serde_json::from_value(val).unwrap(), + (), + ))), + + "animationstart" | "animationend" | "animationiteration" => SyntheticEvent::AnimationEvent( + AnimationEvent(DioxusEvent::new(serde_json::from_value(val).unwrap(), ())), + ), + + "transitionend" => SyntheticEvent::TransitionEvent(TransitionEvent(DioxusEvent::new( + serde_json::from_value(val).unwrap(), + (), + ))), + + "abort" | "canplay" | "canplaythrough" | "durationchange" | "emptied" | "encrypted" + | "ended" | "error" | "loadeddata" | "loadedmetadata" | "loadstart" | "pause" | "play" + | "playing" | "progress" | "ratechange" | "seeked" | "seeking" | "stalled" | "suspend" + | "timeupdate" | "volumechange" | "waiting" => { + SyntheticEvent::MediaEvent(MediaEvent(DioxusEvent::new(MediaEventInner {}, ()))) + } + + "toggle" => { + SyntheticEvent::ToggleEvent(ToggleEvent(DioxusEvent::new(ToggleEventInner {}, ()))) + } + + _ => SyntheticEvent::GenericEvent(DioxusEvent::new((), ())), + } +} + fn event_name_from_typ(typ: &str) -> &'static str { match typ { "copy" => "copy", diff --git a/packages/desktop/src/index.js b/packages/desktop/src/index.js index c62b6d4cf..04a315fde 100644 --- a/packages/desktop/src/index.js +++ b/packages/desktop/src/index.js @@ -159,10 +159,12 @@ class Interpreter { console.log(`parsed event with scope_id ${scope_id} and real_id ${real_id}`); + let contents = serialize_event(event); rpc.call('user_event', { event: event_name, scope: scope_id, mounted_dom_id: real_id, + contents: contents, }).then((reply) => { console.log(reply); this.stack.push(this.root); @@ -213,4 +215,244 @@ function apply_edits(edits, interpreter) { console.log("stack completed: ", interpreter.stack); } +function serialize_event(event) { + let serializer = SerializeMap[event.type]; + if (serializer === undefined) { + return {}; + } else { + return serializer(event); + } +} + +const SerializeMap = { + "copy": serialize_clipboard, + "cut": serialize_clipboard, + "paste": serialize_clipboard, + + "compositionend": serialize_composition, + "compositionstart": serialize_composition, + "compositionupdate": serialize_composition, + + "keydown": serialize_keyboard, + "keypress": serialize_keyboard, + "keyup": serialize_keyboard, + + "focus": serialize_focus, + "blur": serialize_focus, + + "change": serialize_change, + + "input": serialize_form, + "invalid": serialize_form, + "reset": serialize_form, + "submit": serialize_form, + + "click": serialize_mouse, + "contextmenu": serialize_mouse, + "doubleclick": serialize_mouse, + "drag": serialize_mouse, + "dragend": serialize_mouse, + "dragenter": serialize_mouse, + "dragexit": serialize_mouse, + "dragleave": serialize_mouse, + "dragover": serialize_mouse, + "dragstart": serialize_mouse, + "drop": serialize_mouse, + "mousedown": serialize_mouse, + "mouseenter": serialize_mouse, + "mouseleave": serialize_mouse, + "mousemove": serialize_mouse, + "mouseout": serialize_mouse, + "mouseover": serialize_mouse, + "mouseup": serialize_mouse, + + "pointerdown": serialize_pointer, + "pointermove": serialize_pointer, + "pointerup": serialize_pointer, + "pointercancel": serialize_pointer, + "gotpointercapture": serialize_pointer, + "lostpointercapture": serialize_pointer, + "pointerenter": serialize_pointer, + "pointerleave": serialize_pointer, + "pointerover": serialize_pointer, + "pointerout": serialize_pointer, + + "select": serialize_selection, + + "touchcancel": serialize_touch, + "touchend": serialize_touch, + "touchmove": serialize_touch, + "touchstart": serialize_touch, + + "scroll": serialize_scroll, + + "wheel": serialize_wheel, + + "animationstart": serialize_animation, + "animationend": serialize_animation, + "animationiteration": serialize_animation, + + "transitionend": serialize_transition, + + "abort": serialize_media, + "canplay": serialize_media, + "canplaythrough": serialize_media, + "durationchange": serialize_media, + "emptied": serialize_media, + "encrypted": serialize_media, + "ended": serialize_media, + "error": serialize_media, + "loadeddata": serialize_media, + "loadedmetadata": serialize_media, + "loadstart": serialize_media, + "pause": serialize_media, + "play": serialize_media, + "playing": serialize_media, + "progress": serialize_media, + "ratechange": serialize_media, + "seeked": serialize_media, + "seeking": serialize_media, + "stalled": serialize_media, + "suspend": serialize_media, + "timeupdate": serialize_media, + "volumechange": serialize_media, + "waiting": serialize_media, + + "toggle": serialize_toggle +} + +function serialize_clipboard(_event) { + return {}; +} +function serialize_composition(event) { + return { + data: event.data + } +} +function serialize_keyboard(event) { + return { + alt_key: event.altKey, + char_code: event.charCode, + key: event.key, + key_code: event.keyCode, + ctrl_key: event.ctrlKey, + locale: event.locale, + location: event.location, + meta_key: event.metaKey, + repeat: event.repeat, + shift_key: event.shiftKey, + which: event.which, + } +} +function serialize_focus(_event) { + return {} +} +function serialize_change(_event) { + return {} +} +function serialize_form(event) { + let target = event.target; + let value = target.value ?? target.textContent; + return { + value: value + } +} +function serialize_mouse(event) { + return { + alt_key: event.altKey, + button: event.button, + buttons: event.buttons, + client_x: event.clientX, + client_y: event.clientY, + ctrl_key: event.ctrlKey, + meta_key: event.metaKey, + page_x: event.pageX, + page_y: event.pageY, + screen_x: event.screenX, + screen_y: event.screenY, + shift_key: event.shiftKey, + } +} + +function serialize_pointer(event) { + return { + alt_key: event.altKey, + button: event.button, + buttons: event.buttons, + client_x: event.clientX, + client_y: event.clientY, + ctrl_key: event.ctrlKey, + meta_key: event.metaKey, + page_x: event.pageX, + page_y: event.pageY, + screen_x: event.screenX, + screen_y: event.screenY, + shift_key: event.shiftKey, + pointer_id: event.pointerId, + width: event.width, + height: event.height, + pressure: event.pressure, + tangential_pressure: event.tangentialPressure, + tilt_x: event.tiltX, + tilt_y: event.tiltY, + twist: event.twist, + pointer_type: event.pointerType, + is_primary: event.isPrimary, + } +} + +function serialize_selection(event) { + return {} +} + +function serialize_touch(event) { + return { + alt_key: event.altKey, + ctrl_key: event.ctrlKey, + meta_key: event.metaKey, + shift_key: event.shiftKey, + + // changed_touches: event.changedTouches, + // target_touches: event.targetTouches, + // touches: event.touches, + } +} +function serialize_scroll(event) { + return {} +} + +function serialize_wheel(event) { + return { + delta_x: event.deltaX, + delta_y: event.deltaY, + delta_z: event.deltaZ, + delta_mode: event.deltaMode, + } +} + +function serialize_animation(event) { + return { + animation_name: event.animationName, + elapsed_time: event.elapsedTime, + pseudo_element: event.pseudoElement, + } +} + +function serialize_transition(event) { + return { + property_name: event.propertyName, + elapsed_time: event.elapsedTime, + pseudo_element: event.pseudoElement, + } +} + +function serialize_media(event) { + return {} +} + +function serialize_toggle(event) { + return {} +} + + initialize(); diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs index b93854442..9deda3bc9 100644 --- a/packages/desktop/src/lib.rs +++ b/packages/desktop/src/lib.rs @@ -95,11 +95,10 @@ pub fn run( let webview = WebViewBuilder::new(window)? .with_url("wry://src/index.html")? .with_rpc_handler(move |_window: &Window, mut req: RpcRequest| { + // match req.method.as_str() { "initiate" => { - // let mut rx = (*locked_receiver).borrow_mut(); - match rx.try_recv() { Ok(BridgeEvent::Initialize(edits)) => { Some(RpcResponse::new_result(req.id.take(), Some(edits))) @@ -108,27 +107,16 @@ pub fn run( } } "user_event" => { - // let data = req.params.unwrap(); - log::debug!("Data: {:#?}", data); let event = events::trigger_from_serialized(data); sender.unbounded_send(SchedulerMsg::UiEvent(event)).unwrap(); let mut rx = (*locked_receiver).borrow_mut(); - match rx.blocking_recv() { Some(BridgeEvent::Update(edits)) => { - log::info!("Passing response back"); Some(RpcResponse::new_result(req.id.take(), Some(edits))) } - None => { - log::error!("Sender half is gone"); - None - } - _ => { - log::error!("No update event received"); - None - } + _ => None, } } _ => todo!("this message failed"), @@ -200,12 +188,12 @@ fn launch_vdom_with_tokio( let edits = vir.rebuild(); + // the receiving end expects something along these lines #[derive(Serialize)] struct Evt<'a> { edits: Vec>, } - // let msg = RpcEvent::Initialize { edits: edits.edits }; let edit_string = serde_json::to_value(Evt { edits: edits.edits }).unwrap(); match event_tx.send(BridgeEvent::Initialize(edit_string)) { Ok(_) => {} @@ -214,10 +202,7 @@ fn launch_vdom_with_tokio( loop { vir.wait_for_work().await; - log::info!("{}", vir); - let mut muts = vir.run_with_deadline(|| false); - log::info!("muts {:#?}", muts); while let Some(edit) = muts.pop() { let edit_string = serde_json::to_value(Evt { edits: edit.edits }).unwrap(); match event_tx.send(BridgeEvent::Update(edit_string)) {