Sfoglia il codice sorgente

feat: desktop functioning well

Jonathan Kelley 3 anni fa
parent
commit
5502429626

+ 5 - 3
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<DomEdit>| {
             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);
                 }

+ 32 - 4
packages/core/src/events.rs

@@ -106,7 +106,7 @@ pub enum EventPriority {
 }
 
 #[derive(Debug)]
-pub struct DioxusEvent<T: Send> {
+pub struct DioxusEvent<T: Send + Sync> {
     inner: T,
     raw: Box<dyn Any + Send>,
 }
@@ -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,
+
+        /// Indicate if the `meta` modifier key was pressed during this keyboard event
+        pub meta_key: bool,
+
+        /// Indicate if the `shift` modifier key was pressed during this keyboard event
+        pub shift_key: bool,
+
         pub locale: String,
+
         pub location: usize,
-        pub meta_key: bool,
+
         pub repeat: bool,
-        pub shift_key: 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,

+ 3 - 3
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" }

+ 97 - 5
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<ImEvent> = serde_json::from_value(val).unwrap();
-    let data = data.drain(..).next().unwrap();
+    let mut ims: Vec<ImEvent> = 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 scope = ScopeId(data.scope as usize);
-    let mounted_dom_id = Some(ElementId(data.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",

+ 242 - 0
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();

+ 3 - 18
packages/desktop/src/lib.rs

@@ -95,11 +95,10 @@ pub fn run<T: Properties + 'static + Send + Sync>(
     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<T: Properties + 'static + Send + Sync>(
                     }
                 }
                 "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<C: Send + 'static>(
 
             let edits = vir.rebuild();
 
+            // the receiving end expects something along these lines
             #[derive(Serialize)]
             struct Evt<'a> {
                 edits: Vec<DomEdit<'a>>,
             }
 
-            // 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<C: Send + 'static>(
 
             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)) {