use super::{
planes::{ReconstructedPlanesInput, apply_reconstructed_planes},
shared::{catalogue_material_guess, format_optional_proportion, sides_from_angle_sequence},
};
use crate::{
AngleItem, DiagramDetailData, FileItem, LibraryModel, MainWindow, TiltModel,
bridge::render_thread::RenderContext,
};
use indicatrix::geometry::plane::GpuFacetPlane;
use indicatrix_vault::{db::sqlite::Database, model::entry::FullDiagramRecord};
use slint::{ComponentHandle, ModelRc, VecModel};
use std::sync::{Arc, Mutex};
use tracing::error;
fn note_derived_from_if_any(ui: &MainWindow, db: &Database, entry_id: i64) {
if let Some((_, title)) = db.get_derived_from_title(entry_id).ok().flatten() {
ui.global::<LibraryModel>()
.set_status_message(format!("Derived from: {title}").into());
}
}
fn push_shape_picker_and_cached_material(
ui: &MainWindow,
db: &Database,
entry_id: i64,
shape: Option<&str>,
) -> Option<String> {
let (shape_options, shape_index) =
crate::gui::library::local::build_shape_picker_options(db, shape);
ui.global::<LibraryModel>()
.set_shape_picker_options(ModelRc::new(VecModel::from(shape_options)));
ui.global::<LibraryModel>()
.set_shape_picker_current_index(shape_index);
let cached_curve_material = db
.get_preview_images(entry_id)
.ok()
.and_then(|p| p.material);
ui.global::<TiltModel>()
.set_cached_curve_material(cached_curve_material.clone().unwrap_or_default().into());
note_derived_from_if_any(ui, db, entry_id);
cached_curve_material
}
fn resolve_catalogue_planes_for_entry(
full: &FullDiagramRecord,
) -> Option<(Vec<GpuFacetPlane>, u32, f32)> {
crate::gui::editor::resolve_catalogue_planes(full)
.ok()
.flatten()
}
pub(super) fn load_diagram_detail(
ui: &MainWindow,
db_mutex: &Arc<Mutex<Database>>,
render_ctx: &Arc<Mutex<RenderContext>>,
entry_id: i64,
) {
let db = match db_mutex.lock() {
Ok(guard) => guard,
Err(poisoned) => poisoned.into_inner(),
};
match db.get_diagram_full(entry_id) {
Ok(Some(full)) => {
let is_local = full.url.starts_with("local://");
let ri_text = full.refractive_index.clone();
let catalogue_planes = resolve_catalogue_planes_for_entry(&full);
let detail_data = DiagramDetailData {
id: full.entry_id as i32,
title: full.title.into(),
url: full.url.into(),
designer: full.designer_info.clone().unwrap_or_default().into(),
shape: full.shape.clone().unwrap_or_default().into(),
gear: full.index_gear.clone().unwrap_or_default().into(),
facets: full.facets_count.unwrap_or_default().into(),
lw_ratio: format_optional_proportion(full.lw_ratio.as_deref()).into(),
material_guess: catalogue_material_guess(full.refractive_index.as_deref()).into(),
ri: full.refractive_index.unwrap_or_default().into(),
volume: format_optional_proportion(full.volume.as_deref()).into(),
competition: full.competition_diagram.unwrap_or_default().into(),
image_name: full.diagram_image_name.unwrap_or_default().into(),
has_image: full.diagram_image_data.is_some(),
is_local,
hw_ratio: format_optional_proportion(full.hw_ratio.as_deref()).into(),
cw_ratio: format_optional_proportion(full.cw_ratio.as_deref()).into(),
pw_ratio: format_optional_proportion(full.pw_ratio.as_deref()).into(),
symmetry_order: full.symmetry_order.unwrap_or_default().into(),
mirror_symmetry: full.mirror_symmetry.unwrap_or(false),
};
ui.global::<LibraryModel>().set_current_detail(detail_data);
let sides =
sides_from_angle_sequence(full.angle_settings.iter().map(|a| a.angle.as_str()));
let angle_items: Vec<AngleItem> = full
.angle_settings
.into_iter()
.zip(sides)
.map(|(a, side)| AngleItem {
order_idx: a.order_index as i32,
side,
facet: a.facet.into(),
angle: a.angle.into(),
index_val: a.index.into(),
notes: a.notes.into(),
})
.collect();
ui.global::<LibraryModel>()
.set_current_angles(ModelRc::new(VecModel::from(angle_items.clone())));
let file_items: Vec<FileItem> = full
.attached_files
.into_iter()
.map(|f| {
let size_kb = f.content.len() as f64 / 1024.0;
FileItem {
name: f.name.into(),
url: f.url.into(),
size_str: format!("{size_kb:.1} KB").into(),
}
})
.collect();
ui.global::<LibraryModel>()
.set_current_files(ModelRc::new(VecModel::from(file_items)));
ui.global::<LibraryModel>()
.set_selected_entry_id(entry_id as i32);
let cached_curve_material =
push_shape_picker_and_cached_material(ui, &db, entry_id, full.shape.as_deref());
drop(db);
apply_reconstructed_planes(
ui,
render_ctx,
entry_id,
ReconstructedPlanesInput {
shape: full.shape.as_deref(),
index_gear: full.index_gear.as_deref(),
angle_items: &angle_items,
refractive_index: ri_text.as_deref(),
preview_material: cached_curve_material.as_deref(),
real_design: catalogue_planes,
},
);
}
Ok(None) => {
ui.global::<LibraryModel>()
.set_status_message("Diagram detail not found.".into());
}
Err(e) => {
error!("Failed to fetch diagram full detail: {:?}", e);
ui.global::<LibraryModel>()
.set_status_message(format!("Error loading detail: {e}").into());
}
}
}