use std::{
cell::RefCell,
collections::BTreeSet,
rc::Rc,
sync::{Arc, Mutex},
};
use slint::ComponentHandle;
use super::facet_overlay::{facet_map_from_aligned_solve, resubmit_facet_overlay};
use crate::{
EditorModel, MainWindow,
bridge::render_thread::RenderContext,
gui::{
editor::{
auto_solve,
state::EditorState,
view::{SolidLastSolved, refresh_editor_panel_stale, submit_preview_replan},
},
show_toast,
solid_preview::preview_state::SolidPreviewState,
},
};
pub(super) fn setup_highlight_tooth_callback(ui: &MainWindow, state: &Rc<RefCell<EditorState>>) {
let state = Rc::clone(state);
ui.global::<EditorModel>()
.on_highlight_tooth(move |tooth: i32| {
let Some(preview_state) = auto_solve::preview_state() else {
return;
};
if tooth < 0 {
resubmit_facet_overlay(&preview_state, |overlay| overlay.multi_selected.clear());
return;
}
let st = state.borrow();
let facet_map = facet_map_from_aligned_solve(&st.design);
let tooth = tooth as u32;
let facet_ids: Vec<u32> = (0..facet_map.facet_count() as u32)
.filter(|&facet_id| facet_map.index_on_gear(facet_id as usize) == tooth)
.collect();
resubmit_facet_overlay(&preview_state, |overlay| {
overlay.multi_selected = facet_ids;
});
});
}
pub(super) fn setup_facet_remove_callback(
ui: &MainWindow,
state: &Rc<RefCell<EditorState>>,
render_ctx: &Arc<Mutex<RenderContext>>,
preview_state: &Arc<SolidPreviewState>,
solid_last_solved: &SolidLastSolved,
) {
let state = Rc::clone(state);
let render_ctx = Arc::clone(render_ctx);
let preview_state = Arc::clone(preview_state);
let solid_last_solved = Arc::clone(solid_last_solved);
let ui_weak = ui.as_weak();
ui.global::<EditorModel>()
.on_facet_remove(move |tier_index: i32, position: f32| {
let Some(ui) = ui_weak.upgrade() else {
return;
};
let Ok(tier_index) = usize::try_from(tier_index) else {
return;
};
let mut st = state.borrow_mut();
match st
.design
.remove_orbit_member(tier_index, f64::from(position))
.and_then(|edit| st.apply(edit))
{
Ok(()) => {
refresh_editor_panel_stale(
&ui,
&render_ctx,
&st,
&BTreeSet::from([tier_index]),
);
submit_preview_replan(
&ui,
&render_ctx,
&preview_state,
&solid_last_solved,
&st,
BTreeSet::from([tier_index]),
false,
);
}
Err(e) => show_toast(&ui, &e.to_string(), "error"),
}
});
}
pub(super) fn setup_facet_toggle_detach_callback(
ui: &MainWindow,
state: &Rc<RefCell<EditorState>>,
render_ctx: &Arc<Mutex<RenderContext>>,
preview_state: &Arc<SolidPreviewState>,
solid_last_solved: &SolidLastSolved,
) {
let state = Rc::clone(state);
let render_ctx = Arc::clone(render_ctx);
let preview_state = Arc::clone(preview_state);
let solid_last_solved = Arc::clone(solid_last_solved);
let ui_weak = ui.as_weak();
ui.global::<EditorModel>()
.on_facet_toggle_detach(move |tier_index: i32, position: f32| {
let Some(ui) = ui_weak.upgrade() else {
return;
};
let Ok(tier_index) = usize::try_from(tier_index) else {
return;
};
let position = f64::from(position);
let mut st = state.borrow_mut();
let Some(tier) = st.design.tiers.get(tier_index) else {
return;
};
let edit_result = if tier.detached.contains(&position) {
st.design.reattach_orbit_member(tier_index, position)
} else {
st.design.detach_orbit_member(tier_index, position)
};
match edit_result.and_then(|edit| st.apply(edit)) {
Ok(()) => {
refresh_editor_panel_stale(
&ui,
&render_ctx,
&st,
&BTreeSet::from([tier_index]),
);
submit_preview_replan(
&ui,
&render_ctx,
&preview_state,
&solid_last_solved,
&st,
BTreeSet::from([tier_index]),
false,
);
}
Err(e) => show_toast(&ui, &e.to_string(), "error"),
}
});
}
pub(super) fn setup_facet_add_callback(
ui: &MainWindow,
state: &Rc<RefCell<EditorState>>,
render_ctx: &Arc<Mutex<RenderContext>>,
preview_state: &Arc<SolidPreviewState>,
solid_last_solved: &SolidLastSolved,
) {
let state = Rc::clone(state);
let render_ctx = Arc::clone(render_ctx);
let preview_state = Arc::clone(preview_state);
let solid_last_solved = Arc::clone(solid_last_solved);
let ui_weak = ui.as_weak();
ui.global::<EditorModel>()
.on_facet_add(move |tier_index: i32, position: f32| {
let Some(ui) = ui_weak.upgrade() else {
return;
};
let Ok(tier_index) = usize::try_from(tier_index) else {
return;
};
let mut st = state.borrow_mut();
match st
.design
.add_orbit_member(tier_index, f64::from(position))
.and_then(|edit| st.apply(edit))
{
Ok(()) => {
refresh_editor_panel_stale(
&ui,
&render_ctx,
&st,
&BTreeSet::from([tier_index]),
);
submit_preview_replan(
&ui,
&render_ctx,
&preview_state,
&solid_last_solved,
&st,
BTreeSet::from([tier_index]),
false,
);
}
Err(e) => show_toast(&ui, &e.to_string(), "error"),
}
});
}
pub(super) fn setup_tier_rotate_indices_callback(
ui: &MainWindow,
state: &Rc<RefCell<EditorState>>,
render_ctx: &Arc<Mutex<RenderContext>>,
preview_state: &Arc<SolidPreviewState>,
solid_last_solved: &SolidLastSolved,
) {
let state = Rc::clone(state);
let render_ctx = Arc::clone(render_ctx);
let preview_state = Arc::clone(preview_state);
let solid_last_solved = Arc::clone(solid_last_solved);
let ui_weak = ui.as_weak();
ui.global::<EditorModel>()
.on_tier_rotate_indices(move |tier_index: i32, k_teeth: f32| {
let Some(ui) = ui_weak.upgrade() else {
return;
};
let Ok(tier_index) = usize::try_from(tier_index) else {
return;
};
let mut st = state.borrow_mut();
match st
.design
.rotate_indices(tier_index, f64::from(k_teeth))
.and_then(|edit| st.apply(edit))
{
Ok(()) => {
refresh_editor_panel_stale(
&ui,
&render_ctx,
&st,
&BTreeSet::from([tier_index]),
);
submit_preview_replan(
&ui,
&render_ctx,
&preview_state,
&solid_last_solved,
&st,
BTreeSet::from([tier_index]),
false,
);
}
Err(e) => show_toast(&ui, &e.to_string(), "error"),
}
});
}
pub(super) fn setup_tier_mirror_indices_callback(
ui: &MainWindow,
state: &Rc<RefCell<EditorState>>,
render_ctx: &Arc<Mutex<RenderContext>>,
preview_state: &Arc<SolidPreviewState>,
solid_last_solved: &SolidLastSolved,
) {
let state = Rc::clone(state);
let render_ctx = Arc::clone(render_ctx);
let preview_state = Arc::clone(preview_state);
let solid_last_solved = Arc::clone(solid_last_solved);
let ui_weak = ui.as_weak();
ui.global::<EditorModel>()
.on_tier_mirror_indices(move |tier_index: i32| {
let Some(ui) = ui_weak.upgrade() else {
return;
};
let Ok(tier_index) = usize::try_from(tier_index) else {
return;
};
let mut st = state.borrow_mut();
match st.mirror_indices(tier_index) {
Ok(_) => {
refresh_editor_panel_stale(
&ui,
&render_ctx,
&st,
&BTreeSet::from([tier_index]),
);
submit_preview_replan(
&ui,
&render_ctx,
&preview_state,
&solid_last_solved,
&st,
BTreeSet::from([tier_index]),
false,
);
}
Err(e) => show_toast(&ui, &e.to_string(), "error"),
}
});
}