use crate::canvas::model_textures::{aspect_bucket, svg_hash};
use crate::fixture_definition_editor::edit::{DefinitionEdit, Edit};
use crate::fixture_definition_editor::picked_file::DefinitionFile;
use crate::fixture_definition_editor::state::EditorState;
use crate::fixture_definition_editor::units::millimetres;
use crate::ui::file_pick;
use egui::{Button, Frame, Image, Ui, vec2};
use gled_model::patching::definition::Model;
const THUMBNAIL: f32 = 36.0;
pub(crate) fn show(
ui: &mut Ui,
asset_id: uuid::Uuid,
edit: &mut Edit<'_>,
state: &mut EditorState,
) {
for index in 0..edit.value.models.len() {
Frame::group(ui.style()).show(ui, |ui| {
ui.set_width(ui.available_width());
model_row(ui, asset_id, index, edit, state);
});
}
if edit.value.models.is_empty() {
ui.weak("No models yet. Pixels need one to be drawn.");
}
ui.horizontal(|ui| {
ui.menu_button("Add model", |ui| {
let size = edit.value.size_m;
let presets = [
("LED, round 10 mm", Model::circle("led", 0.01)),
(
"LED, square 5 mm",
Model::rounded_rect("led", [0.005, 0.005]),
),
(
"Tube segment 14 × 90 mm",
Model::rounded_rect("segment", [0.014, 0.09]),
),
(
"Outline of the fixture",
Model::frame("body", [size[0].max(0.05), size[1].max(0.05)]),
),
];
for (label, model) in presets {
if ui.button(label).clicked() {
edit.change(state, |definition| definition.models.push(model));
ui.close();
}
}
});
load_svg_button(ui, state);
});
}
fn model_row(
ui: &mut Ui,
asset_id: uuid::Uuid,
index: usize,
edit: &mut Edit<'_>,
state: &mut EditorState,
) {
let Some(model) = edit.value.models.get(index).cloned() else {
return;
};
ui.horizontal(|ui| {
let aspect = model.size_m[0] / model.size_m[1].max(f32::EPSILON);
let key = (
Some(asset_id),
index,
aspect_bucket(aspect),
svg_hash(&model),
);
match state.caches.models.texture(ui.ctx(), key, &model) {
Some(texture) => {
ui.add(Image::new(&texture).fit_to_exact_size(vec2(THUMBNAIL, THUMBNAIL)));
}
None => {
ui.add_sized(vec2(THUMBNAIL, THUMBNAIL), egui::Label::new("?"))
.on_hover_text("This SVG cannot be drawn");
}
}
ui.vertical(|ui| {
let mut name = model.name.clone();
let response = ui.text_edit_singleline(&mut name);
edit.tracked(&response, |definition| {
if let Some(model) = definition.models.get_mut(index) {
model.name = name;
}
});
ui.horizontal(|ui| {
for axis in 0..2 {
let mut metres = model.size_m[axis];
let response =
ui.add(millimetres(&mut metres).speed(0.0005).range(0.0001..=10.0));
edit.tracked(&response, |definition| {
if let Some(model) = definition.models.get_mut(index) {
model.size_m[axis] = metres;
}
});
}
});
});
});
ui.horizontal_wrapped(|ui| {
ui.radio_value(&mut state.current_model, index, "new pixels")
.on_hover_text("Pixels added from now on are drawn with this model");
let mut outline = edit.value.outline == Some(index);
if ui.checkbox(&mut outline, "outline").changed() {
edit.change(state, |definition| {
definition.outline = outline.then_some(index);
});
}
let selection = state.selection.clone();
if ui
.add_enabled(!selection.is_empty(), Button::new("Use for selection"))
.clicked()
{
edit.try_change(state, |definition| {
definition.set_model_of(&selection, index)
});
}
if ui.button("Remove").clicked() {
edit.try_change(state, |definition| definition.remove_model(index));
}
});
}
fn load_svg_button(ui: &mut Ui, state: &mut EditorState) {
if ui
.add_enabled(!state.file_pick.is_open(), Button::new("Load SVG…"))
.clicked()
{
state.ask_file(ui.ctx(), file_pick::SVG, DefinitionFile::model);
}
}