use super::preview_state::{FacetOverlay, PickBuffer, SolidPreviewState};
use crate::{EditorModel, MainWindow, SolidPreviewModel};
use slint::ComponentHandle;
use std::sync::{Arc, Mutex, PoisonError};
pub type DiagramPick = Arc<Mutex<Option<PickBuffer>>>;
pub type DiagramHoverText = Arc<Mutex<Option<Vec<String>>>>;
pub type DiagramFacetTier = Arc<Mutex<Option<Vec<Option<usize>>>>>;
fn tooth_at(tooth_pick: &DiagramPick, px: u32, py: u32) -> Option<u32> {
tooth_pick
.lock()
.unwrap_or_else(PoisonError::into_inner)
.as_ref()
.and_then(|tooth_pick| tooth_pick.facet_at(px, py))
}
pub fn setup_diagram_hover_and_click_callbacks(
ui: &MainWindow,
pick: &DiagramPick,
tooth_pick: &DiagramPick,
hover_text: &DiagramHoverText,
facet_tier: &DiagramFacetTier,
preview_state: &Arc<SolidPreviewState>,
) {
{
let pick = Arc::clone(pick);
let tooth_pick = Arc::clone(tooth_pick);
let hover_text = Arc::clone(hover_text);
let preview_state = Arc::clone(preview_state);
let ui_weak = ui.as_weak();
ui.global::<SolidPreviewModel>()
.on_diagram_facet_hover(move |x: f32, y: f32| {
let Some(ui) = ui_weak.upgrade() else {
return;
};
let scale = ui.window().scale_factor();
let px = (x * scale).max(0.0) as u32;
let py = (y * scale).max(0.0) as u32;
let Some(facet_id) = pick
.lock()
.unwrap_or_else(PoisonError::into_inner)
.as_ref()
.and_then(|pick| pick.facet_at(px, py))
else {
let tooth = tooth_at(&tooth_pick, px, py);
ui.global::<SolidPreviewModel>()
.set_diagram_hovered_tooth(tooth.map_or(-1, |t| t as i32));
ui.global::<SolidPreviewModel>().set_diagram_hover_text(
tooth
.map_or_else(String::new, |t| format!("Index {t}"))
.into(),
);
preview_state.request_facet_overlay(FacetOverlay::default());
return;
};
ui.global::<SolidPreviewModel>()
.set_diagram_hovered_tooth(-1);
let text = hover_text
.lock()
.unwrap_or_else(PoisonError::into_inner)
.as_ref()
.and_then(|table| table.get(facet_id as usize))
.cloned()
.unwrap_or_default();
ui.global::<SolidPreviewModel>()
.set_diagram_hover_text(text.into());
preview_state.request_facet_overlay(FacetOverlay {
hovered: Some(facet_id),
..FacetOverlay::default()
});
});
}
{
let pick = Arc::clone(pick);
let tooth_pick = Arc::clone(tooth_pick);
let facet_tier = Arc::clone(facet_tier);
let preview_state = Arc::clone(preview_state);
let ui_weak = ui.as_weak();
ui.global::<SolidPreviewModel>()
.on_diagram_facet_click(move |x: f32, y: f32| {
let Some(ui) = ui_weak.upgrade() else {
return;
};
let scale = ui.window().scale_factor();
let px = (x * scale).max(0.0) as u32;
let py = (y * scale).max(0.0) as u32;
let Some(facet_id) = pick
.lock()
.unwrap_or_else(PoisonError::into_inner)
.as_ref()
.and_then(|pick| pick.facet_at(px, py))
else {
let tooth = tooth_at(&tooth_pick, px, py);
if let Some(tooth) = tooth {
ui.global::<SolidPreviewModel>()
.set_diagram_clicked_tooth(tooth as i32);
return;
}
preview_state.request_facet_overlay(FacetOverlay::default());
ui.global::<EditorModel>().set_selected_tier_index(-1);
return;
};
let tier_index = facet_tier
.lock()
.unwrap_or_else(PoisonError::into_inner)
.as_ref()
.and_then(|table| table.get(facet_id as usize).copied())
.flatten();
preview_state.request_facet_overlay(FacetOverlay {
selected_facet: Some(facet_id),
..FacetOverlay::default()
});
if let Some(tier_index) = tier_index {
ui.global::<EditorModel>()
.set_selected_tier_index(tier_index as i32);
}
});
}
}