From 71abedb3b3ef955f51742b5cccfe71e30fa8d1bc Mon Sep 17 00:00:00 2001 From: Sameer Puri Date: Mon, 15 Nov 2021 18:00:15 -0800 Subject: [PATCH] move import/export button to settings modal + reorg mods --- web/src/forms/editors.rs | 246 +++++++++++++++++++ web/src/forms/inputs.rs | 73 ++++++ web/src/{inputs.rs => forms/mod.rs} | 350 ++++------------------------ web/src/main.rs | 16 +- web/src/{spectre => ui}/mod.rs | 0 5 files changed, 364 insertions(+), 321 deletions(-) create mode 100644 web/src/forms/editors.rs create mode 100644 web/src/forms/inputs.rs rename web/src/{inputs.rs => forms/mod.rs} (54%) rename web/src/{spectre => ui}/mod.rs (100%) diff --git a/web/src/forms/editors.rs b/web/src/forms/editors.rs new file mode 100644 index 0000000..2595ef1 --- /dev/null +++ b/web/src/forms/editors.rs @@ -0,0 +1,246 @@ +use codespan_reporting::term::{emit, termcolor::NoColor, Config}; +use g_code::parse::{into_diagnostic, snippet_parser}; +use gloo_timers::callback::Timeout; +use paste::paste; +use yew::prelude::*; +use yewdux_functional::use_store; +use yewdux_input::*; + +use crate::{ + state::{AppState, AppStore, FormStore}, + ui::{FormGroup, TextArea}, +}; + +macro_rules! gcode_input { + ($($name: ident { + $label: literal, + $desc: literal, + $form_accessor: expr $(=> $form_idx: literal)?, + $app_accessor: expr $(=> $app_idx: literal)?, + })*) => { + $( + paste! { + #[function_component([<$name Input>])] + pub fn [<$name:snake:lower _input>]() -> Html { + const VALIDATION_TIMEOUT: u32 = 350; + let app = use_store::(); + let form = use_store::(); + + let timeout = use_state::, _>(|| None); + let oninput = { + let timeout = timeout.clone(); + form.dispatch().input(move |state, value| { + let res = Some(match snippet_parser(&value) { + Ok(_) => Ok(value), + Err(err) => { + let mut buf = NoColor::new(vec![]); + let config = Config::default(); + emit( + &mut buf, + &config, + &codespan_reporting::files::SimpleFile::new("", value), + &into_diagnostic(&err), + ) + .unwrap(); + Err(String::from_utf8_lossy(buf.get_ref().as_slice()).to_string()) + } + }).filter(|res| { + !res.as_ref().ok().map(|value| value.is_empty()).unwrap_or(false) + }); + + let timeout_inner = timeout.clone(); + timeout.set(Some(Timeout::new(VALIDATION_TIMEOUT, move || { + timeout_inner.set(None); + }))); + state.$form_accessor $([$form_idx])? = res; + }) + }; + html! { + + label=$label desc=$desc + default={app.state().map(|state| (state.$app_accessor $([$app_idx])?).clone()).unwrap_or_else(|| AppState::default().$app_accessor $([$app_idx])?)} + parsed={form.state().and_then(|state| (state.$form_accessor $([$form_idx])?).clone()).filter(|_| timeout.is_none())} + oninput={oninput} + /> + + } + } + } + )* + }; +} + +gcode_input! { + ToolOnSequence { + "Tool On Sequence", + "G-Code for turning on the tool", + tool_on_sequence, + settings.machine.tool_on_sequence, + } + ToolOffSequence { + "Tool Off Sequence", + "G-Code for turning off the tool", + tool_off_sequence, + settings.machine.tool_off_sequence, + } + BeginSequence { + "Program Begin Sequence", + "G-Code for initializing the machine at the beginning of the program", + begin_sequence, + settings.machine.begin_sequence, + } + EndSequence { + "Program End Sequence", + "G-Code for stopping/idling the machine at the end of the program", + end_sequence, + settings.machine.end_sequence, + } +} + +// TODO: make a nice, syntax highlighting editor for g-code. +// I started on this but it quickly got too complex. +// pub struct GCodeEditor { +// props: GCodeEditorProps, +// dispatch: AppDispatch, +// state: Rc, +// validation_task: Option, +// link: ComponentLink, +// parsed: Option>, +// node_ref: NodeRef, +// } + +// pub enum InputMessage { +// Validate(String), +// State(Rc), +// Change(InputData), +// } + +// impl Component for GCodeEditor { +// type Message = InputMessage; + +// type Properties = GCodeEditorProps; + +// fn create(props: Self::Properties, link: ComponentLink) -> Self { +// Self { +// props, +// dispatch: Dispatch::bridge_state(link.callback(InputMessage::State)), +// state: Default::default(), +// validation_task: None, +// link, +// parsed: None, +// node_ref: NodeRef::default(), +// } +// } + +// fn update(&mut self, msg: Self::Message) -> ShouldRender { +// match msg { +// InputMessage::State(state) => { +// self.state = state; +// true +// } +// InputMessage::Validate(value) => { +// self.parsed = Some(snippet_parser(&value).map(|snippet| { +// html! { +// <> +// { +// for snippet.iter_emit_tokens().flat_map(|token| { +// if let Token::Field(field) = &token { +// vec![ +// html! { +// {field.letters.to_string()} +// }, +// { +// let class = match &field.value { +// Value::Rational(_) | Value::Integer(_) | Value::Float(_) => "hljs-number", +// Value::String(_) => "hljs-string", +// }; +// html! { +// {field.value.to_string()} +// } +// } +// ] +// } else if let Token::Newline{..} = &token { +// vec![ +// html! { +// "\r\n" +// } +// ] +// } +// else { +// let class = match &token { +// Token::Comment{..} => "hljs-comment", +// Token::Checksum(..) => "hljs-number", +// Token::Whitespace(..) => "whitespace", +// Token::Newline{..} => "newline", +// Token::Percent => "hljs-keyword", +// _ => unreachable!(), +// }; +// vec![html!{ +// +// { token.to_string() } +// +// }] +// } +// }) +// } +// +// } +// }).map_err(|err| { +// let mut buf = Buffer::no_color(); +// let config = Config::default(); +// emit( +// &mut buf, +// &config, +// &codespan_reporting::files::SimpleFile::new("", value), +// &into_diagnostic(&err), +// ) +// .unwrap(); +// String::from_utf8_lossy(buf.as_slice()).to_string() +// })); +// true +// } +// InputMessage::Change(InputData { value, .. }) => { +// self.parsed = None; +// self.validation_task = None; +// self.validation_task = Some(TimeoutService::spawn( +// self.props.validation_timeout, +// self.link +// .callback(move |_| InputMessage::Validate(value.clone())), +// )); +// true +// } +// } +// } + +// fn change(&mut self, props: Self::Properties) -> ShouldRender { +// self.props.neq_assign(props) +// } + +// fn view(&self) -> Html { +// let oninput = self.link.callback(|x: InputData| InputMessage::Change(x)); + +// html! { +// <> +//
+//