use super::*;
#[component]
pub fn euv_transfer(node: VirtualNode<EuvTransferProps>) -> VirtualNode {
let EuvTransferProps {
source,
target,
selected,
source_title,
target_title,
on_move_to_target,
on_move_to_source,
}: EuvTransferProps = node.try_get_props().unwrap_or_default();
let marked: Vec<String> = selected.get();
let source_count: usize = source.len();
let target_count: usize = target.len();
let source_values: Vec<&'static str> = source
.iter()
.map(|item: &EuvTransferItem| item.value)
.collect();
let target_values: Vec<&'static str> = target
.iter()
.map(|item: &EuvTransferItem| item.value)
.collect();
let source_rows: Vec<VirtualNode> = source
.into_iter()
.map(|item: EuvTransferItem| {
transfer_row(item, transfer_is_marked(&marked, item.value), selected)
})
.collect();
let target_rows: Vec<VirtualNode> = target
.into_iter()
.map(|item: EuvTransferItem| {
transfer_row(item, transfer_is_marked(&marked, item.value), selected)
})
.collect();
let move_to_target: Rc<dyn Fn(Event)> =
transfer_move_to_target(selected, source_values, on_move_to_target);
let move_to_source: Rc<dyn Fn(Event)> =
transfer_move_to_source(selected, target_values, on_move_to_source);
html! {
div {
class: c_euv_transfer()
div {
class: c_euv_transfer_panel()
div {
class: c_euv_transfer_header()
span {
source_title
}
span {
source_count
}
}
div {
class: c_euv_transfer_list()
source_rows
}
}
div {
class: c_euv_transfer_actions()
euv_button {
variant: EuvButtonVariant::Outline
label: ">"
onclick: Some(move_to_target)
}
euv_button {
variant: EuvButtonVariant::Outline
label: "<"
onclick: Some(move_to_source)
}
}
div {
class: c_euv_transfer_panel()
div {
class: c_euv_transfer_header()
span {
target_title
}
span {
target_count
}
}
div {
class: c_euv_transfer_list()
target_rows
}
}
}
}
}
fn transfer_row(
item: EuvTransferItem,
is_marked: bool,
selected: Signal<Vec<String>>,
) -> VirtualNode {
let disabled: bool = item.disabled;
let handler: Option<Rc<dyn Fn(Event)>> = if disabled {
None
} else {
transfer_toggle_handler(selected, item.value)
};
html! {
div {
class: transfer_row_class(is_marked)
onclick: handler
span {
class: if is_marked {
c_euv_transfer_box_active()
} else {
c_euv_transfer_box()
}
if is_marked {
"✓"
}
}
span {
item.label
}
}
}
}
fn transfer_row_class(is_marked: bool) -> String {
let base: &str = c_euv_transfer_item().get_name();
if !is_marked {
return String::from(base);
}
let active: &str = c_euv_transfer_item_active().get_name();
let mut class_name: String = String::with_capacity(base.len() + 1 + active.len());
class_name.push_str(base);
class_name.push(' ');
class_name.push_str(active);
class_name
}
pub fn transfer_is_marked(marked: &[String], value: &str) -> bool {
marked.iter().any(|entry: &String| entry.as_str() == value)
}
fn transfer_toggle_handler(
selected: Signal<Vec<String>>,
value: &'static str,
) -> Option<Rc<dyn Fn(Event)>> {
Some(Rc::new(move |_: Event| {
transfer_toggle_value(selected, value);
}))
}
pub fn transfer_toggle_value(selected: Signal<Vec<String>>, value: &'static str) {
let mut marked: Vec<String> = selected.get();
if let Some(index) = marked.iter().position(|entry: &String| entry == value) {
marked.remove(index);
} else {
marked.push(String::from(value));
}
selected.set(marked);
}
pub fn transfer_move_to_target<E: 'static>(
selected: Signal<Vec<String>>,
source_values: Vec<&'static str>,
on_move: Option<Rc<dyn Fn(&'static str)>>,
) -> Rc<dyn Fn(E)> {
Rc::new(move |_: E| {
transfer_report_moves(selected, &source_values, &on_move);
})
}
pub fn transfer_move_to_source<E: 'static>(
selected: Signal<Vec<String>>,
target_values: Vec<&'static str>,
on_move: Option<Rc<dyn Fn(&'static str)>>,
) -> Rc<dyn Fn(E)> {
Rc::new(move |_: E| {
transfer_report_moves(selected, &target_values, &on_move);
})
}
pub fn transfer_report_moves(
selected: Signal<Vec<String>>,
values: &[&'static str],
on_move: &Option<Rc<dyn Fn(&'static str)>>,
) {
let marked: Vec<String> = selected.get();
for value in values.iter() {
if transfer_is_marked(&marked, value)
&& let Some(callback) = on_move
{
callback(value);
}
}
}