use super::{
RETARGET_ASYNC,
apply::revert_ghost_to_live_design,
build_retarget_candidate,
material::{target_display_name, target_material_selection},
};
use crate::{
MainWindow, RetargetModel,
bridge::render_thread::RenderContext,
gui::{
editor::{retarget::RetargetProposal, state::EditorState, view},
solid_preview::preview_state::SolidPreviewState,
},
};
use indicatrix_cut_core::{Design, MaterialSelection};
use slint::ComponentHandle;
use std::sync::{Arc, Mutex, PoisonError, atomic::Ordering as AtomicOrdering};
#[derive(Debug, Clone, PartialEq)]
pub(in crate::gui::editor) struct RetargetKeepGuard {
proposal: RetargetProposal,
generation: u64,
material: MaterialSelection,
}
pub(in crate::gui::editor) struct RetargetCompareInputs {
pub(in crate::gui::editor) current: Design,
pub(in crate::gui::editor) candidate: Design,
pub(in crate::gui::editor) after_label: String,
pub(in crate::gui::editor) guard: RetargetKeepGuard,
}
fn pending_proposal(st: &EditorState) -> Option<(RetargetProposal, u64)> {
st.pending_retarget
.clone()
.or_else(|| RETARGET_ASYNC.with(|cell| cell.borrow().pending.clone()))
}
fn target_selection(
ui: &MainWindow,
render_ctx: &Arc<Mutex<RenderContext>>,
design: &Design,
) -> MaterialSelection {
let custom = render_ctx
.lock()
.unwrap_or_else(PoisonError::into_inner)
.custom_materials
.as_ref()
.clone();
let model = ui.global::<RetargetModel>();
target_material_selection(
design,
&custom,
model.get_target_material_index(),
&model.get_target_ri_override_text(),
)
}
#[must_use]
pub(in crate::gui::editor) fn current_retarget_guard(
ui: &MainWindow,
st: &EditorState,
render_ctx: &Arc<Mutex<RenderContext>>,
) -> Option<RetargetKeepGuard> {
let (proposal, generation) = pending_proposal(st)?;
let material = target_selection(ui, render_ctx, &st.design);
Some(RetargetKeepGuard {
proposal,
generation,
material,
})
}
pub(in crate::gui::editor) fn retarget_compare_inputs(
ui: &MainWindow,
st: &EditorState,
render_ctx: &Arc<Mutex<RenderContext>>,
) -> Result<RetargetCompareInputs, String> {
let guard = current_retarget_guard(ui, st, render_ctx)
.ok_or_else(|| "No retarget proposal to compare yet.".to_string())?;
if guard.generation != st.generation.load(AtomicOrdering::Relaxed) {
return Err(
"The design changed since this proposal was built -- click Recompute first."
.to_string(),
);
}
let mut candidate = build_retarget_candidate(&st.design, &guard.proposal).ok_or_else(|| {
"This proposal no longer applies to the current design -- click Recompute first."
.to_string()
})?;
candidate.material = guard.material.clone();
let mode = if ui.global::<RetargetModel>().get_mode_index() == 1 {
"Optimize"
} else {
"Shift"
};
let after_label = format!(
"Retarget to {} ({mode})",
target_display_name(&guard.material)
);
Ok(RetargetCompareInputs {
current: st.design.clone(),
candidate,
after_label,
guard,
})
}
pub(in crate::gui::editor) fn discard_retarget_preview(
ui: &MainWindow,
render_ctx: &Arc<Mutex<RenderContext>>,
preview_state: &Arc<SolidPreviewState>,
solid_last_solved: &view::SolidLastSolved,
st: &EditorState,
) {
let model = ui.global::<RetargetModel>();
if !model.get_preview_enabled() {
return;
}
model.set_preview_enabled(false);
revert_ghost_to_live_design(ui, render_ctx, preview_state, solid_last_solved, st);
}