use super::{
facet_selection::{
clear_clicked_facet, clicked_tier_row, select_clicked_facet, set_hovered_facet,
},
preview_state::{FacetOwners, PickBuffer, SolidPreviewState},
};
use crate::{
EditorModel, MainWindow, ManipulateModel, SolidPreviewModel, gui::tutorial_events::raise,
};
use indicatrix_editor::guide::viewing_events as events;
use indicatrix_solid::preview::{panel_kind_from_index, view::toggle_enlarged_panel};
use slint::ComponentHandle;
use std::{
cell::RefCell,
sync::{Arc, Mutex, PoisonError},
};
thread_local! {
static DIAGRAM_SELECTED_FACET_LABEL: RefCell<String> = const { RefCell::new(String::new()) };
}
pub type DiagramPick = Arc<Mutex<Option<PickBuffer>>>;
pub type DiagramHoverText = Arc<Mutex<Option<Vec<String>>>>;
pub type DiagramFacetOwners = Arc<Mutex<Option<FacetOwners>>>;
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_owners: &DiagramFacetOwners,
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);
let text = tooth.map_or_else(
|| DIAGRAM_SELECTED_FACET_LABEL.with(|cell| cell.borrow().clone()),
|t| format!("Index {t}"),
);
ui.global::<SolidPreviewModel>()
.set_diagram_hover_text(text.into());
set_hovered_facet(&preview_state, None);
return;
};
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());
set_hovered_facet(&preview_state, Some(facet_id));
});
}
{
let pick = Arc::clone(pick);
let tooth_pick = Arc::clone(tooth_pick);
let facet_owners = Arc::clone(facet_owners);
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_click(move |x: f32, y: f32| {
let Some(ui) = ui_weak.upgrade() else {
return;
};
handle_diagram_facet_click(
&ui,
x,
y,
DiagramPickBuffers {
pick: &pick,
tooth_pick: &tooth_pick,
facet_owners: &facet_owners,
hover_text: &hover_text,
},
&preview_state,
);
});
}
}
pub fn setup_diagram_double_click_callback(ui: &MainWindow, panel_pick: &DiagramPick) {
let panel_pick = Arc::clone(panel_pick);
let ui_weak = ui.as_weak();
ui.global::<SolidPreviewModel>()
.on_diagram_double_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 clicked = panel_pick
.lock()
.unwrap_or_else(PoisonError::into_inner)
.as_ref()
.and_then(|buffer| buffer.facet_at(px, py))
.and_then(|index| panel_kind_from_index(i32::try_from(index).ok()?));
let model = ui.global::<SolidPreviewModel>();
let next = toggle_enlarged_panel(model.get_diagram_enlarged_panel(), clicked);
model.set_diagram_enlarged_panel(next);
});
}
#[derive(Clone, Copy)]
struct DiagramPickBuffers<'a> {
pick: &'a DiagramPick,
tooth_pick: &'a DiagramPick,
facet_owners: &'a DiagramFacetOwners,
hover_text: &'a DiagramHoverText,
}
fn handle_diagram_facet_click(
ui: &MainWindow,
x: f32,
y: f32,
buffers: DiagramPickBuffers<'_>,
preview_state: &SolidPreviewState,
) {
let DiagramPickBuffers {
pick,
tooth_pick,
facet_owners,
hover_text,
} = buffers;
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 {
let tooth = tooth as i32;
ui.global::<SolidPreviewModel>()
.set_diagram_clicked_tooth(tooth);
ui.global::<EditorModel>().invoke_highlight_tooth(tooth);
return;
}
clear_clicked_facet(preview_state);
ui.global::<EditorModel>().set_selected_tier_index(-1);
ui.global::<SolidPreviewModel>()
.set_diagram_clicked_tooth(-1);
ui.global::<EditorModel>().invoke_highlight_tooth(-1);
DIAGRAM_SELECTED_FACET_LABEL.with(|cell| cell.borrow_mut().clear());
ui.global::<SolidPreviewModel>()
.set_diagram_hover_text("".into());
return;
};
let tier_row = if ui.global::<ManipulateModel>().get_provisional_active() {
None
} else {
facet_owners
.lock()
.unwrap_or_else(PoisonError::into_inner)
.as_ref()
.and_then(|owners| clicked_tier_row(ui, owners, facet_id))
};
select_clicked_facet(preview_state, facet_id);
if let Some(tier_row) = tier_row {
ui.global::<EditorModel>()
.set_selected_tier_index(tier_row as i32);
raise(ui, events::FACET_PICKED);
}
let label = hover_text
.lock()
.unwrap_or_else(PoisonError::into_inner)
.as_ref()
.and_then(|table| table.get(facet_id as usize))
.cloned()
.unwrap_or_default();
DIAGRAM_SELECTED_FACET_LABEL.with(|cell| cell.borrow_mut().clone_from(&label));
ui.global::<SolidPreviewModel>()
.set_diagram_hover_text(label.into());
}