use crate::{
MainWindow, RetargetModel, RetargetRowItem,
gui::editor::retarget::{
self, CrownShift, RetargetError, RetargetMode, RetargetProposal, RetargetRow,
},
};
use indicatrix::{geometry::meet_solver::Block, optics::materials::GemMaterial};
use indicatrix_cut_core::{Design, MaterialSelection, ResolvedMaterial, Risk};
use slint::{Color, ComponentHandle, ModelRc, SharedString, VecModel};
pub(super) struct RetargetRowView {
tier_index: usize,
block: &'static str,
name: String,
old_angle: String,
new_angle: String,
margin: String,
risk_label: &'static str,
risk_rgb: (u8, u8, u8),
}
const fn risk_label_and_rgb(risk: Risk) -> (&'static str, (u8, u8, u8)) {
match risk {
Risk::Safe => ("Safe", (0x10, 0xb9, 0x81)),
Risk::Marginal => ("Marginal", (0xf5, 0x9e, 0x0b)),
Risk::Windows => ("Windows", (0xf4, 0x3f, 0x5e)),
}
}
pub(super) fn row_view(row: &RetargetRow) -> RetargetRowView {
let block = match row.block {
Block::Crown => "Crown",
Block::Pavilion => "Pavilion",
Block::Girdle => "Girdle",
};
let (risk_label, risk_rgb) = risk_label_and_rgb(row.risk);
RetargetRowView {
tier_index: row.tier_index,
block,
name: row.name.clone(),
old_angle: format!("{:.2}\u{b0}", row.old_angle),
new_angle: format!("{:.2}\u{b0}", row.new_angle),
margin: format!("{:+.2}\u{b0}", row.margin_deg),
risk_label,
risk_rgb,
}
}
pub(super) fn retarget_view(
design: &Design,
target: &ResolvedMaterial,
crown: CrownShift,
mode: RetargetMode,
custom_materials: &[GemMaterial],
) -> (RetargetView, Option<RetargetProposal>) {
match retarget::build_proposal(design, target, crown, mode, custom_materials) {
Ok(proposal) => {
let rows = proposal.rows.iter().map(row_view).collect();
let view = RetargetView {
rows,
notes: proposal.notes.clone(),
anchored_errors: Vec::new(),
solve_error: String::new(),
};
(view, Some(proposal))
}
Err(RetargetError::AnchoredTiers(tiers)) => {
let anchored_errors = tiers
.iter()
.map(|(index, name)| format!("#{index} \"{name}\""))
.collect();
let view = RetargetView {
rows: Vec::new(),
notes: Vec::new(),
anchored_errors,
solve_error: String::new(),
};
(view, None)
}
Err(RetargetError::Solve(err)) => {
let view = RetargetView {
rows: Vec::new(),
notes: Vec::new(),
anchored_errors: Vec::new(),
solve_error: err.to_string(),
};
(view, None)
}
}
}
pub(super) struct RetargetView {
pub(super) rows: Vec<RetargetRowView>,
pub(super) notes: Vec<String>,
pub(super) anchored_errors: Vec<String>,
pub(super) solve_error: String,
}
pub(super) fn push_retarget_view(ui: &MainWindow, view: RetargetView) {
let rows: Vec<RetargetRowItem> = view
.rows
.into_iter()
.map(|r| RetargetRowItem {
tier_index: r.tier_index as i32,
block: r.block.into(),
name: r.name.into(),
old_angle: r.old_angle.into(),
new_angle: r.new_angle.into(),
margin: r.margin.into(),
risk_label: r.risk_label.into(),
risk_color: Color::from_rgb_u8(r.risk_rgb.0, r.risk_rgb.1, r.risk_rgb.2),
})
.collect();
ui.global::<RetargetModel>()
.set_rows(ModelRc::new(VecModel::from(rows)));
ui.global::<RetargetModel>()
.set_notes(ModelRc::new(VecModel::from(
view.notes
.into_iter()
.map(SharedString::from)
.collect::<Vec<_>>(),
)));
ui.global::<RetargetModel>()
.set_anchored_tier_errors(ModelRc::new(VecModel::from(
view.anchored_errors
.into_iter()
.map(SharedString::from)
.collect::<Vec<_>>(),
)));
ui.global::<RetargetModel>()
.set_solve_error(view.solve_error.into());
}
pub(super) fn push_target_readout(
ui: &MainWindow,
selection: &MaterialSelection,
target: &ResolvedMaterial,
) {
ui.global::<RetargetModel>()
.set_target_material_name(super::material::target_display_name(selection).into());
ui.global::<RetargetModel>()
.set_target_material_ri(format!("{:.4}", target.n_d).into());
ui.global::<RetargetModel>()
.set_target_critical_angle(format!("{:.2}\u{b0}", target.critical_angle_deg).into());
ui.global::<RetargetModel>()
.set_target_material_error("".into());
}
pub(super) fn push_target_error(ui: &MainWindow, message: &str) {
ui.global::<RetargetModel>()
.set_target_material_error(message.into());
push_retarget_view(
ui,
RetargetView {
rows: Vec::new(),
notes: Vec::new(),
anchored_errors: Vec::new(),
solve_error: String::new(),
},
);
}