use super::{
panel::{push_tier_list_and_undo_redo, push_yield_material_scratch},
solve_results::{deep_solve_hint, optimize_hint},
state::{
EditorState, ScratchDelta, design_label_text, manufacturability_warnings_tagged,
preform_y_offset_mm_text, result_is_stale, tier_items_stale_with_last_solved,
},
};
use crate::{
AngleItem, EditorModel,
bridge::render_thread::RenderContext,
gui::editor::{auto_solve, stale},
};
use indicatrix_cut_core::PreformShape;
use slint::{ComponentHandle, ModelRc, SharedString, VecModel};
use std::{
collections::BTreeSet,
sync::{Arc, Mutex, PoisonError, atomic::Ordering as AtomicOrdering},
};
pub(super) fn refresh_deep_solve_availability(ui: &crate::MainWindow, state: &EditorState) {
let (available, hint) = deep_solve_hint(state);
ui.global::<EditorModel>()
.set_deep_solve_available(available);
ui.global::<EditorModel>().set_deep_solve_hint(hint.into());
}
pub(super) fn refresh_optimize_availability(ui: &crate::MainWindow, state: &EditorState) {
let (available, hint) = optimize_hint(state, configured_optimize_max_evaluations(ui));
ui.global::<EditorModel>().set_optimize_available(available);
ui.global::<EditorModel>().set_optimize_hint(hint.into());
let current_generation = state.generation.load(AtomicOrdering::Relaxed);
let can_apply = state
.pending_optimize
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.as_ref()
.is_some_and(|(_, started_generation)| *started_generation == current_generation);
ui.global::<EditorModel>().set_optimize_can_apply(can_apply);
}
#[must_use]
pub(in crate::gui::editor) fn configured_optimize_max_evaluations(ui: &crate::MainWindow) -> usize {
ui.global::<EditorModel>()
.get_optimize_budget_text()
.parse::<usize>()
.ok()
.filter(|&v| v > 0)
.unwrap_or(200)
}
pub(in crate::gui::editor) fn refresh_editor_panel_stale(
ui: &crate::MainWindow,
render_ctx: &Arc<Mutex<RenderContext>>,
state: &EditorState,
dirty: &BTreeSet<usize>,
) {
push_stale_content(ui, render_ctx, state, dirty);
auto_solve::on_edit(ui, render_ctx, state);
crate::gui::editor::guide::check_progress(ui, state);
}
fn push_stale_generation_badges(
ui: &crate::MainWindow,
state: &EditorState,
current_generation: u64,
) {
ui.global::<EditorModel>()
.set_deep_solve_stale(result_is_stale(
state.deep_solve_result_generation,
current_generation,
));
let optimize_result_generation = state
.pending_optimize
.lock()
.unwrap_or_else(PoisonError::into_inner)
.as_ref()
.map(|(_, generation)| *generation);
ui.global::<EditorModel>()
.set_optimize_stale(result_is_stale(
optimize_result_generation,
current_generation,
));
stale::refresh_badges(ui, current_generation);
}
fn push_stale_warnings(ui: &crate::MainWindow, state: &EditorState) {
let tagged_warnings = manufacturability_warnings_tagged(&state.design, None);
let warning_tiers: Vec<i32> = tagged_warnings
.iter()
.map(|(index, _)| i32::try_from(*index).unwrap_or(i32::MAX))
.collect();
let warnings: Vec<SharedString> = tagged_warnings
.into_iter()
.map(|(_, text)| SharedString::from(text))
.collect();
super::state::push_rows(
&ui.global::<EditorModel>().get_manufacturability_warnings(),
warnings,
|model| {
ui.global::<EditorModel>()
.set_manufacturability_warnings(model);
},
);
super::state::push_rows(
&ui.global::<EditorModel>()
.get_manufacturability_warning_tiers(),
warning_tiers,
|model| {
ui.global::<EditorModel>()
.set_manufacturability_warning_tiers(model);
},
);
}
fn push_stale_preform_and_yield(ui: &crate::MainWindow, state: &EditorState, delta: &ScratchDelta) {
if delta.preform {
let preform = &state.design.preform;
ui.global::<EditorModel>()
.set_preform_shape_index(match preform.shape {
PreformShape::Block => 0,
PreformShape::Cylinder { .. } => 1,
});
ui.global::<EditorModel>()
.set_preform_half_width(format!("{:.4}", preform.half_width).into());
ui.global::<EditorModel>()
.set_preform_length_over_width(format!("{:.4}", preform.length_over_width).into());
ui.global::<EditorModel>()
.set_preform_depth(format!("{:.4}", preform.depth).into());
}
ui.global::<EditorModel>()
.set_preform_half_width_mm_text("".into());
ui.global::<EditorModel>()
.set_preform_depth_mm_text("".into());
ui.global::<EditorModel>().set_preform_y_offset_mm(
preform_y_offset_mm_text(state.design.preform_y_offset, None).into(),
);
push_yield_material_scratch(ui, state, delta);
ui.global::<EditorModel>()
.set_volumetric_yield_text("".into());
ui.global::<EditorModel>().set_carat_weight_text("".into());
ui.global::<EditorModel>()
.set_specific_gravity_used_text("".into());
ui.global::<EditorModel>()
.set_preform_fit_warning("".into());
}
fn push_stale_proportions_reset(ui: &crate::MainWindow) {
ui.global::<EditorModel>()
.set_proportions_table_pct("-".into());
ui.global::<EditorModel>()
.set_proportions_crown_height("-".into());
ui.global::<EditorModel>()
.set_proportions_pavilion_depth("-".into());
ui.global::<EditorModel>()
.set_proportions_total_depth("-".into());
ui.global::<EditorModel>()
.set_proportions_length_to_width("-".into());
ui.global::<EditorModel>()
.set_girdle_thickness_text("-".into());
ui.global::<EditorModel>()
.set_crown_to_width_text("-".into());
ui.global::<EditorModel>()
.set_pavilion_to_width_text("-".into());
ui.global::<EditorModel>()
.set_girdle_to_width_text("-".into());
ui.global::<EditorModel>()
.set_cutting_rows(ModelRc::new(VecModel::from(Vec::<AngleItem>::new())));
ui.global::<EditorModel>().set_facet_count(0);
}
pub(super) fn push_stale_content(
ui: &crate::MainWindow,
render_ctx: &Arc<Mutex<RenderContext>>,
state: &EditorState,
dirty: &BTreeSet<usize>,
) {
super::viewport::push_trace_staleness(ui, render_ctx, state);
let current_generation = state.generation.load(AtomicOrdering::Relaxed);
push_stale_generation_badges(ui, state, current_generation);
let delta = state.record_scratch_push();
let n_d = super::inspector::refresh_design_settings(ui, render_ctx, state, &delta);
let last_solved = auto_solve::solid_last_solved().and_then(|cache| {
cache
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.clone()
});
let tiers =
tier_items_stale_with_last_solved(&state.design, n_d, last_solved.as_deref(), dirty);
push_tier_list_and_undo_redo(ui, state, tiers);
ui.global::<EditorModel>().set_status_text(
"Not solved -- click Solve to compute masts and validate this design.".into(),
);
ui.global::<EditorModel>().set_status_is_problem(true);
ui.global::<EditorModel>().set_solve_state("stale".into());
push_stale_warnings(ui, state);
push_stale_preform_and_yield(ui, state, &delta);
push_stale_proportions_reset(ui);
ui.global::<EditorModel>()
.set_design_label(design_label_text(state.asc_filename.as_deref()).into());
refresh_deep_solve_availability(ui, state);
refresh_optimize_availability(ui, state);
}