From 3aa48b1b78c9e8fdb9ef207377f4c0e399af850c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kav=C3=ADk?= Date: Sat, 14 Sep 2024 19:48:09 +0200 Subject: [PATCH] command_panel.rs --- frontend/src/command_panel.rs | 141 ++++++++++++++++++++++++++++++++++ frontend/src/header_panel.rs | 134 +------------------------------- frontend/src/main.rs | 4 + 3 files changed, 146 insertions(+), 133 deletions(-) create mode 100644 frontend/src/command_panel.rs diff --git a/frontend/src/command_panel.rs b/frontend/src/command_panel.rs new file mode 100644 index 0000000..5e61df7 --- /dev/null +++ b/frontend/src/command_panel.rs @@ -0,0 +1,141 @@ +use crate::{script_bridge, theme::*}; +use zoon::*; + +pub struct CommandPanel {} + +impl CommandPanel { + pub fn new() -> impl Element { + Self {}.root() + } + + fn root(&self) -> impl Element { + let command_result: Mutable>> = <_>::default(); + Row::new() + .s(Align::new().top()) + .s(Gap::both(30)) + .s(Scrollbars::both()) + .s(Width::fill()) + .item(self.command_editor_panel(command_result.clone())) + .item(self.command_result_panel(command_result.read_only())) + } + + fn command_editor_panel( + &self, + command_result: Mutable>>, + ) -> impl Element { + Column::new() + .s(Align::new().top()) + .s(Gap::new().y(10)) + .s(Width::growable()) + .item( + Row::new() + .s(Gap::new().x(15)) + .s(Padding::new().x(5)) + .item(El::new().child("Javascript commands")) + .item(El::new().s(Align::new().right()).child("Shift + Enter")), + ) + .item(self.command_editor(command_result)) + } + + fn command_editor( + &self, + command_result: Mutable>>, + ) -> impl Element { + let (script, script_signal) = Mutable::new_and_signal_cloned(String::new()); + // @TODO perhaps replace with an element with syntax highlighter like https://github.com/WebCoder49/code-input later + TextArea::new() + .s(Background::new().color(COLOR_SLATE_BLUE)) + .s(Padding::new().x(10).y(8)) + .s(RoundedCorners::all(15)) + .s(Height::default().min(50)) + .s(Width::fill().min(300)) + .s(Font::new() + .tracking(1) + .weight(FontWeight::Medium) + .color(COLOR_WHITE) + .family([FontFamily::new("Courier New"), FontFamily::Monospace])) + .s(Shadows::new([Shadow::new() + .inner() + .color(COLOR_DARK_SLATE_BLUE) + .blur(4)])) + // @TODO `spellcheck` and `resize` to MZ API? (together with autocomplete and others?) + .update_raw_el(|raw_el| { + raw_el + .attr("spellcheck", "false") + .style("resize", "vertical") + }) + .placeholder(Placeholder::new("FW.say_hello()").s(Font::new().color(COLOR_LIGHT_BLUE))) + .label_hidden("command editor panel") + .text_signal(script_signal) + .on_change(clone!((script, command_result) move |text| { + script.set_neq(text); + command_result.set_neq(None); + })) + .on_key_down_event_with_options(EventOptions::new().preventable(), move |event| { + if event.key() == &Key::Enter { + let RawKeyboardEvent::KeyDown(raw_event) = event.raw_event.clone(); + if raw_event.shift_key() { + // @TODO move `prevent_default` to MZ API (next to the `pass_to_parent` method?) + raw_event.prevent_default(); + Task::start(clone!((script, command_result) async move { + let result = script_bridge::strict_eval(&script.lock_ref()).await; + command_result.set(Some(result)); + })); + } + } + }) + } + + fn command_result_panel( + &self, + command_result: ReadOnlyMutable>>, + ) -> impl Element { + Column::new() + .s(Gap::new().y(10)) + .s(Align::new().top()) + .s(Scrollbars::both()) + .s(Padding::new().x(5)) + .s(Width::growable().max(750)) + .item(El::new().child("Command result")) + .item(self.command_result_el(command_result)) + } + + fn command_result_el( + &self, + command_result: ReadOnlyMutable>>, + ) -> impl Element { + El::new() + .s(Font::new() + .tracking(1) + .weight(FontWeight::Medium) + .color(COLOR_WHITE) + .family([FontFamily::new("Courier New"), FontFamily::Monospace])) + .s(Scrollbars::both()) + .s(Height::default().max(100)) + .child_signal(command_result.signal_ref(|result| { + fn format_complex_js_value(js_value: &JsValue) -> String { + let value = format!("{js_value:?}"); + let value = value.strip_prefix("JsValue(").unwrap_throw(); + let value = value.strip_suffix(')').unwrap_throw(); + value.to_owned() + } + match result { + Some(Ok(js_value)) => { + if let Some(string_value) = js_value.as_string() { + string_value + } else if let Some(number_value) = js_value.as_f64() { + number_value.to_string() + } else if let Some(bool_value) = js_value.as_bool() { + bool_value.to_string() + } else { + format_complex_js_value(js_value) + } + } + Some(Err(js_value)) => { + format!("ERROR: {}", format_complex_js_value(js_value)) + } + None => "-".to_owned(), + } + })) + } +} diff --git a/frontend/src/header_panel.rs b/frontend/src/header_panel.rs index cb534bc..5007d73 100644 --- a/frontend/src/header_panel.rs +++ b/frontend/src/header_panel.rs @@ -1,4 +1,4 @@ -use crate::{platform, script_bridge, theme::*, Filename, Layout}; +use crate::{platform, theme::*, Filename, Layout}; use std::sync::Arc; use zoon::*; @@ -34,7 +34,6 @@ impl HeaderPanel { .item(self.load_button()) .item(self.layout_switcher()), ) - .item(self.command_panel()) } #[cfg(FASTWAVE_PLATFORM = "TAURI")] @@ -168,135 +167,4 @@ impl HeaderPanel { }) }) } - - fn command_panel(&self) -> impl Element { - let command_result: Mutable>> = <_>::default(); - Row::new() - .s(Align::new().top()) - .s(Gap::both(30)) - .s(Scrollbars::both()) - .s(Width::fill()) - .item(self.command_editor_panel(command_result.clone())) - .item(self.command_result_panel(command_result.read_only())) - } - - fn command_editor_panel( - &self, - command_result: Mutable>>, - ) -> impl Element { - Column::new() - .s(Align::new().top()) - .s(Gap::new().y(10)) - .s(Width::growable()) - .item( - Row::new() - .s(Gap::new().x(15)) - .s(Padding::new().x(5)) - .item(El::new().child("Javascript commands")) - .item(El::new().s(Align::new().right()).child("Shift + Enter")), - ) - .item(self.command_editor(command_result)) - } - - fn command_editor( - &self, - command_result: Mutable>>, - ) -> impl Element { - let (script, script_signal) = Mutable::new_and_signal_cloned(String::new()); - // @TODO perhaps replace with an element with syntax highlighter like https://github.com/WebCoder49/code-input later - TextArea::new() - .s(Background::new().color(COLOR_SLATE_BLUE)) - .s(Padding::new().x(10).y(8)) - .s(RoundedCorners::all(15)) - .s(Height::default().min(50)) - .s(Width::fill().min(300)) - .s(Font::new() - .tracking(1) - .weight(FontWeight::Medium) - .color(COLOR_WHITE) - .family([FontFamily::new("Courier New"), FontFamily::Monospace])) - .s(Shadows::new([Shadow::new() - .inner() - .color(COLOR_DARK_SLATE_BLUE) - .blur(4)])) - // @TODO `spellcheck` and `resize` to MZ API? (together with autocomplete and others?) - .update_raw_el(|raw_el| { - raw_el - .attr("spellcheck", "false") - .style("resize", "vertical") - }) - .placeholder(Placeholder::new("FW.say_hello()").s(Font::new().color(COLOR_LIGHT_BLUE))) - .label_hidden("command editor panel") - .text_signal(script_signal) - .on_change(clone!((script, command_result) move |text| { - script.set_neq(text); - command_result.set_neq(None); - })) - .on_key_down_event_with_options(EventOptions::new().preventable(), move |event| { - if event.key() == &Key::Enter { - let RawKeyboardEvent::KeyDown(raw_event) = event.raw_event.clone(); - if raw_event.shift_key() { - // @TODO move `prevent_default` to MZ API (next to the `pass_to_parent` method?) - raw_event.prevent_default(); - Task::start(clone!((script, command_result) async move { - let result = script_bridge::strict_eval(&script.lock_ref()).await; - command_result.set(Some(result)); - })); - } - } - }) - } - - fn command_result_panel( - &self, - command_result: ReadOnlyMutable>>, - ) -> impl Element { - Column::new() - .s(Gap::new().y(10)) - .s(Align::new().top()) - .s(Scrollbars::both()) - .s(Padding::new().x(5)) - .s(Width::growable().max(750)) - .item(El::new().child("Command result")) - .item(self.command_result_el(command_result)) - } - - fn command_result_el( - &self, - command_result: ReadOnlyMutable>>, - ) -> impl Element { - El::new() - .s(Font::new() - .tracking(1) - .weight(FontWeight::Medium) - .color(COLOR_WHITE) - .family([FontFamily::new("Courier New"), FontFamily::Monospace])) - .s(Scrollbars::both()) - .s(Height::default().max(100)) - .child_signal(command_result.signal_ref(|result| { - fn format_complex_js_value(js_value: &JsValue) -> String { - let value = format!("{js_value:?}"); - let value = value.strip_prefix("JsValue(").unwrap_throw(); - let value = value.strip_suffix(')').unwrap_throw(); - value.to_owned() - } - match result { - Some(Ok(js_value)) => { - if let Some(string_value) = js_value.as_string() { - string_value - } else if let Some(number_value) = js_value.as_f64() { - number_value.to_string() - } else if let Some(bool_value) = js_value.as_bool() { - bool_value.to_string() - } else { - format_complex_js_value(js_value) - } - } - Some(Err(js_value)) => { - format!("ERROR: {}", format_complex_js_value(js_value)) - } - None => "-".to_owned(), - } - })) - } } diff --git a/frontend/src/main.rs b/frontend/src/main.rs index a398435..b25c417 100644 --- a/frontend/src/main.rs +++ b/frontend/src/main.rs @@ -13,6 +13,9 @@ use waveform_panel::{PixiController, WaveformPanel}; mod header_panel; use header_panel::HeaderPanel; +mod command_panel; +use command_panel::CommandPanel; + pub mod theme; use theme::*; @@ -101,4 +104,5 @@ fn root() -> impl Element { } } ) + .item(CommandPanel::new()) }