diff --git a/src/components/callbacks/mod.rs b/src/components/callbacks/mod.rs index 4141163..dacd723 100644 --- a/src/components/callbacks/mod.rs +++ b/src/components/callbacks/mod.rs @@ -1,2 +1,3 @@ pub mod main_window_callbacks; pub mod new_plate_dialog_callbacks; +pub mod transfer_menu_callbacks; diff --git a/src/components/callbacks/transfer_menu_callbacks.rs b/src/components/callbacks/transfer_menu_callbacks.rs new file mode 100644 index 0000000..885ee22 --- /dev/null +++ b/src/components/callbacks/transfer_menu_callbacks.rs @@ -0,0 +1,242 @@ +use lazy_static::lazy_static; +use regex::Regex; +use serde::{Deserialize, Serialize}; +use std::rc::Rc; +use uuid::Uuid; +use wasm_bindgen::JsCast; +use web_sys::{EventTarget, HtmlInputElement}; +use yew::prelude::*; +use yewdux::prelude::*; + +use crate::components::transfer_menu::RegionDisplay; +use crate::data::{transfer::Transfer, transfer_region::Region}; + +use crate::components::states::{CurrentTransfer, MainState}; + +pub fn on_name_change_callback(ct_dispatch: Dispatch) -> Callback { + Callback::from(move |e: Event| { + let target: Option = e.target(); + let input = target.and_then(|t| t.dyn_into::().ok()); + if let Some(input) = input { + if input.value() == "" { + return; + } // We do not want empty inputs! + ct_dispatch.reduce_mut(|state| { + state.transfer.name = input.value(); + }); + } + }) +} + +pub fn on_src_region_change_callback(ct_dispatch: Dispatch) -> Callback { + Callback::from(move |e: Event| { + if matches!( + ct_dispatch.get().transfer.transfer_region.source_region, + Region::Custom(_) + ) { + return; // Do nothing here! + } + let target: Option = e.target(); + let input = target.and_then(|t| t.dyn_into::().ok()); + if let Some(input) = input { + if let Ok(rd) = RegionDisplay::try_from(input.value().to_uppercase()) { + ct_dispatch.reduce_mut(|state| { + state.transfer.transfer_region.source_region = Region::from(&rd); + }); + input.set_custom_validity(""); + } else { + input.set_custom_validity("Invalid region.") + } + } + }) +} + +pub fn on_dest_region_change_callback(ct_dispatch: Dispatch) -> Callback { + Callback::from(move |e: Event| { + let target: Option = e.target(); + let input = target.and_then(|t| t.dyn_into::().ok()); + if let Some(input) = input { + if let Ok(rd) = RegionDisplay::try_from(input.value().to_uppercase()) { + ct_dispatch.reduce_mut(|state| { + state.transfer.transfer_region.dest_region = Region::from(&rd); + }); + input.set_custom_validity(""); + } else { + input.set_custom_validity("Invalid region.") + } + } + }) +} + +pub fn on_source_interleave_x_change_callback( + ct_dispatch: Dispatch, +) -> Callback { + Callback::from(move |e: Event| { + let target: Option = e.target(); + let input = target.and_then(|t| t.dyn_into::().ok()); + if let Some(input) = input { + if let Ok(num) = input.value().parse::() { + ct_dispatch.reduce_mut(|state| { + state.transfer.transfer_region.interleave_source = + (num, state.transfer.transfer_region.interleave_source.1); + }); + } + } + }) +} + +pub fn on_source_interleave_y_change_callback( + ct_dispatch: Dispatch, +) -> Callback { + Callback::from(move |e: Event| { + let target: Option = e.target(); + let input = target.and_then(|t| t.dyn_into::().ok()); + if let Some(input) = input { + if let Ok(num) = input.value().parse::() { + ct_dispatch.reduce_mut(|state| { + state.transfer.transfer_region.interleave_source = + (state.transfer.transfer_region.interleave_source.0, num); + }); + } + } + }) +} + +pub fn on_dest_interleave_x_change_callback( + ct_dispatch: Dispatch, +) -> Callback { + Callback::from(move |e: Event| { + let target: Option = e.target(); + let input = target.and_then(|t| t.dyn_into::().ok()); + if let Some(input) = input { + if let Ok(num) = input.value().parse::() { + ct_dispatch.reduce_mut(|state| { + state.transfer.transfer_region.interleave_dest = + (num, state.transfer.transfer_region.interleave_dest.1); + }); + } + } + }) +} + +pub fn on_dest_interleave_y_change_callback( + ct_dispatch: Dispatch, +) -> Callback { + Callback::from(move |e: Event| { + let target: Option = e.target(); + let input = target.and_then(|t| t.dyn_into::().ok()); + if let Some(input) = input { + if let Ok(num) = input.value().parse::() { + ct_dispatch.reduce_mut(|state| { + state.transfer.transfer_region.interleave_dest = + (state.transfer.transfer_region.interleave_dest.0, num); + }); + } + } + }) +} + +pub fn on_volume_change_callback(ct_dispatch: Dispatch) -> Callback { + Callback::from(move |e: Event| { + let input = e + .target() + .expect("Event must have target") + .dyn_into::() + .expect("Must have been emitted by input"); + if let Ok(num) = input.value().parse::() { + ct_dispatch.reduce_mut(|state| { + state.transfer.volume = num; + }); + } + }) +} + +pub fn new_transfer_button_callback_callback( + main_dispatch: Dispatch, + main_state: Rc, + ct_dispatch: Dispatch, +) -> Callback { + Callback::from(move |_: MouseEvent| { + main_dispatch.reduce_mut(|state| { + state.selected_transfer = Uuid::nil(); + }); + ct_dispatch.reduce_mut(|state| { + state.transfer = Transfer::default(); + state.transfer.source_id = main_state.selected_source_plate; + state.transfer.dest_id = main_state.selected_dest_plate; + }); + }) +} + +pub fn save_transfer_button_callback_callback( + main_dispatch: Dispatch, + main_state: Rc, + ct_state: Rc, + new_transfer_button_callback: Callback) + -> Callback { + Callback::from(move |e: MouseEvent| { + log::debug!("Button pressed"); + if main_state.selected_transfer.is_nil() { + if let Some(spi) = main_state + .source_plates + .iter() + .find(|spi| spi.get_uuid() == main_state.selected_source_plate) + { + if let Some(dpi) = main_state + .destination_plates + .iter() + .find(|dpi| dpi.get_uuid() == main_state.selected_dest_plate) + { + let new_transfer = Transfer::new( + spi.clone(), + dpi.clone(), + ct_state.transfer.transfer_region.clone(), + ct_state.transfer.name.clone(), + ); + main_dispatch.reduce_mut(|state| { + state.transfers.push(new_transfer); + state.selected_transfer = state + .transfers + .last() + .expect("An element should have just been added") + .get_uuid(); + }); + new_transfer_button_callback.emit(e); // If we just made a new transfer, + // then we should make another on + // save. + } + } + } else if let Some(index) = main_state + .transfers + .iter() + .position(|t| t.get_uuid() == main_state.selected_transfer) + { + main_dispatch.reduce_mut(|state| { + state.transfers[index] = ct_state.transfer.clone(); + }); + } + }) +} + +pub fn delete_transfer_button_callback( + main_state: Rc, + main_dispatch: Dispatch, + ct_state: Rc, + new_transfer_button_callback: Callback +) -> Callback { + Callback::from(move |e: MouseEvent| { + if main_state.selected_transfer.is_nil() { + // Maybe reset transfer? + } else if let Some(index) = main_state + .transfers + .iter() + .position(|t| t.get_uuid() == ct_state.transfer.get_uuid()) + { + main_dispatch.reduce_mut(|state| { + state.transfers.remove(index); + state.selected_transfer = Uuid::nil(); + }); + new_transfer_button_callback.emit(e); // We need a new transfer now + } + }) +} diff --git a/src/components/transfer_menu.rs b/src/components/transfer_menu.rs index fa9f343..052f53f 100644 --- a/src/components/transfer_menu.rs +++ b/src/components/transfer_menu.rs @@ -9,6 +9,7 @@ use web_sys::{EventTarget, HtmlInputElement}; use yew::prelude::*; use yewdux::prelude::*; +use crate::components::callbacks::transfer_menu_callbacks; use crate::data::{transfer::Transfer, transfer_region::Region}; use super::states::{CurrentTransfer, MainState}; @@ -20,157 +21,52 @@ pub fn TransferMenu() -> Html { let on_name_change = { let ct_dispatch = ct_dispatch.clone(); - - Callback::from(move |e: Event| { - let target: Option = e.target(); - let input = target.and_then(|t| t.dyn_into::().ok()); - if let Some(input) = input { - if input.value() == "" { - return; - } // We do not want empty inputs! - ct_dispatch.reduce_mut(|state| { - state.transfer.name = input.value(); - }); - } - }) + transfer_menu_callbacks::on_name_change_callback(ct_dispatch) }; let on_src_region_change = { let ct_dispatch = ct_dispatch.clone(); - - Callback::from(move |e: Event| { - if matches!(ct_dispatch.get().transfer.transfer_region.source_region, Region::Custom(_)) { - return; // Do nothing here! - } - let target: Option = e.target(); - let input = target.and_then(|t| t.dyn_into::().ok()); - if let Some(input) = input { - if let Ok(rd) = RegionDisplay::try_from(input.value().to_uppercase()) { - ct_dispatch.reduce_mut(|state| { - state.transfer.transfer_region.source_region = Region::from(&rd); - }); - input.set_custom_validity(""); - } else { - input.set_custom_validity("Invalid region.") - } - } - }) + transfer_menu_callbacks::on_src_region_change_callback(ct_dispatch) }; + let on_dest_region_change = { let ct_dispatch = ct_dispatch.clone(); - - Callback::from(move |e: Event| { - let target: Option = e.target(); - let input = target.and_then(|t| t.dyn_into::().ok()); - if let Some(input) = input { - if let Ok(rd) = RegionDisplay::try_from(input.value().to_uppercase()) { - ct_dispatch.reduce_mut(|state| { - state.transfer.transfer_region.dest_region = Region::from(&rd); - }); - input.set_custom_validity(""); - } else { - input.set_custom_validity("Invalid region.") - } - } - }) + transfer_menu_callbacks::on_dest_region_change_callback(ct_dispatch) }; let on_source_interleave_x_change = { let ct_dispatch = ct_dispatch.clone(); - - Callback::from(move |e: Event| { - let target: Option = e.target(); - let input = target.and_then(|t| t.dyn_into::().ok()); - if let Some(input) = input { - if let Ok(num) = input.value().parse::() { - ct_dispatch.reduce_mut(|state| { - state.transfer.transfer_region.interleave_source = - (num, state.transfer.transfer_region.interleave_source.1); - }); - } - } - }) + transfer_menu_callbacks::on_source_interleave_x_change_callback(ct_dispatch) }; + let on_source_interleave_y_change = { let ct_dispatch = ct_dispatch.clone(); - - Callback::from(move |e: Event| { - let target: Option = e.target(); - let input = target.and_then(|t| t.dyn_into::().ok()); - if let Some(input) = input { - if let Ok(num) = input.value().parse::() { - ct_dispatch.reduce_mut(|state| { - state.transfer.transfer_region.interleave_source = - (state.transfer.transfer_region.interleave_source.0, num); - }); - } - } - }) + transfer_menu_callbacks::on_source_interleave_y_change_callback(ct_dispatch) }; let on_dest_interleave_x_change = { let ct_dispatch = ct_dispatch.clone(); - - Callback::from(move |e: Event| { - let target: Option = e.target(); - let input = target.and_then(|t| t.dyn_into::().ok()); - if let Some(input) = input { - if let Ok(num) = input.value().parse::() { - ct_dispatch.reduce_mut(|state| { - state.transfer.transfer_region.interleave_dest = - (num, state.transfer.transfer_region.interleave_dest.1); - }); - } - } - }) + transfer_menu_callbacks::on_dest_interleave_x_change_callback(ct_dispatch) }; + let on_dest_interleave_y_change = { let ct_dispatch = ct_dispatch.clone(); - - Callback::from(move |e: Event| { - let target: Option = e.target(); - let input = target.and_then(|t| t.dyn_into::().ok()); - if let Some(input) = input { - if let Ok(num) = input.value().parse::() { - ct_dispatch.reduce_mut(|state| { - state.transfer.transfer_region.interleave_dest = - (state.transfer.transfer_region.interleave_dest.0, num); - }); - } - } - }) + transfer_menu_callbacks::on_dest_interleave_y_change_callback(ct_dispatch) }; let on_volume_change = { let ct_dispatch = ct_dispatch.clone(); - - Callback::from(move |e: Event| { - let input = e - .target() - .expect("Event must have target") - .dyn_into::() - .expect("Must have been emitted by input"); - if let Ok(num) = input.value().parse::() { - ct_dispatch.reduce_mut(|state| { - state.transfer.volume = num; - }); - } - }) + transfer_menu_callbacks::on_volume_change_callback(ct_dispatch) }; let new_transfer_button_callback = { let main_dispatch = main_dispatch.clone(); let main_state = main_state.clone(); - - Callback::from(move |_: MouseEvent| { - main_dispatch.reduce_mut(|state| { - state.selected_transfer = Uuid::nil(); - }); - ct_dispatch.reduce_mut(|state| { - state.transfer = Transfer::default(); - state.transfer.source_id = main_state.selected_source_plate; - state.transfer.dest_id = main_state.selected_dest_plate; - }); - }) + let ct_dispatch = ct_dispatch.clone(); + transfer_menu_callbacks::new_transfer_button_callback_callback( + main_dispatch, + main_state, + ct_dispatch, + ) }; let save_transfer_button_callback = { @@ -178,70 +74,25 @@ pub fn TransferMenu() -> Html { let main_state = main_state.clone(); let ct_state = ct_state.clone(); let new_transfer_button_callback = new_transfer_button_callback.clone(); - - Callback::from(move |e: MouseEvent| { - log::debug!("Button pressed"); - if main_state.selected_transfer.is_nil() { - if let Some(spi) = main_state - .source_plates - .iter() - .find(|spi| spi.get_uuid() == main_state.selected_source_plate) - { - if let Some(dpi) = main_state - .destination_plates - .iter() - .find(|dpi| dpi.get_uuid() == main_state.selected_dest_plate) - { - let new_transfer = Transfer::new( - spi.clone(), - dpi.clone(), - ct_state.transfer.transfer_region.clone(), - ct_state.transfer.name.clone(), - ); - main_dispatch.reduce_mut(|state| { - state.transfers.push(new_transfer); - state.selected_transfer = state - .transfers - .last() - .expect("An element should have just been added") - .get_uuid(); - }); - new_transfer_button_callback.emit(e); // If we just made a new transfer, - // then we should make another on - // save. - } - } - } else if let Some(index) = main_state - .transfers - .iter() - .position(|t| t.get_uuid() == main_state.selected_transfer) - { - main_dispatch.reduce_mut(|state| { - state.transfers[index] = ct_state.transfer.clone(); - }); - } - }) + transfer_menu_callbacks::save_transfer_button_callback_callback( + main_dispatch, + main_state, + ct_state, + new_transfer_button_callback, + ) }; let delete_transfer_button_callback = { + let main_state = main_state.clone(); + let main_dispatch = main_dispatch.clone(); let ct_state = ct_state.clone(); - let new_callback = new_transfer_button_callback.clone(); - - Callback::from(move |e: MouseEvent| { - if main_state.selected_transfer.is_nil() { - // Maybe reset transfer? - } else if let Some(index) = main_state - .transfers - .iter() - .position(|t| t.get_uuid() == ct_state.transfer.get_uuid()) - { - main_dispatch.reduce_mut(|state| { - state.transfers.remove(index); - state.selected_transfer = Uuid::nil(); - }); - new_callback.emit(e); // We need a new transfer now - } - }) + let new_transfer_button_callback = new_transfer_button_callback.clone(); + transfer_menu_callbacks::delete_transfer_button_callback( + main_state, + main_dispatch, + ct_state, + new_transfer_button_callback, + ) }; html! { @@ -390,7 +241,13 @@ impl From<&Region> for RegionDisplay { Region::Rect(c1, c2) => RegionDisplay::try_from((c1.0, c1.1, c2.0, c2.1)) .ok() .unwrap(), - Region::Custom(_) => RegionDisplay { text: "CUSTOM".to_string(), col_start: 0, row_start: 0, col_end: 0, row_end: 0 } + Region::Custom(_) => RegionDisplay { + text: "CUSTOM".to_string(), + col_start: 0, + row_start: 0, + col_end: 0, + row_end: 0, + }, } } }