//! Shared material UV-transform authoring used by Materials and Material Instances. use bevy::prelude::Vec2; use bevy_egui::egui; use egui_phosphor_icons::icons; use shared::{MaterialInputSet, MaterialParameter, MaterialParameterValue}; use crate::ui::design_system; use crate::ui::design_system::typography::TypeRole; pub(super) fn uv_transform_section( ui: &mut egui::Ui, offset: &mut Vec2, tiling: &mut Vec2, reset_offset: Vec2, reset_tiling: Vec2, ) { let palette = design_system::palette(ui); let width = ui.available_width().max(1.0); let height = match super::layout::ResponsiveMaterialLayout::for_width(width) { super::layout::ResponsiveMaterialLayout::Reference => { crate::ui::design_system::UV_SECTION_HEIGHT } super::layout::ResponsiveMaterialLayout::Compact => { crate::ui::design_system::COMPACT_UV_SECTION_HEIGHT } super::layout::ResponsiveMaterialLayout::Transient => 100.0, }; let (rect, _) = ui.allocate_exact_size(egui::vec2(width, height), egui::Sense::hover()); ui.painter().rect( rect, 5.0, palette.section, egui::Stroke::new(1.0_f32, palette.border), egui::StrokeKind::Inside, ); let mut child = ui.new_child(egui::UiBuilder::new().max_rect(rect)); child.set_clip_rect(rect.intersect(ui.clip_rect())); let geometry = super::layout::UvSectionGeometry::for_rect(rect); child.painter().text( geometry.title.left_center(), egui::Align2::LEFT_CENTER, "UV", TypeRole::Section.font(), palette.text_primary, ); vec2_group( &mut child, geometry.offset, "Offset", offset, reset_offset, "Reset UV offset", ); vec2_group( &mut child, geometry.tiling, "Tiling", tiling, reset_tiling, "Reset UV tiling", ); } fn vec2_group( ui: &mut egui::Ui, geometry: super::layout::UvGroupGeometry, label: &str, value: &mut Vec2, reset: Vec2, tooltip: &str, ) { let palette = design_system::palette(ui); ui.painter().text( geometry.label.left_center(), egui::Align2::LEFT_CENTER, label, TypeRole::Small.font(), palette.text_muted, ); ui.put( geometry.x, egui::DragValue::new(&mut value.x).speed(0.01).prefix("X "), ); ui.put( geometry.y, egui::DragValue::new(&mut value.y).speed(0.01).prefix("Y "), ); if let Some(reset_rect) = geometry.reset { let enabled = *value != reset; let response = ui.put( reset_rect, egui::Button::new( egui::RichText::new(icons::ARROW_COUNTER_CLOCKWISE.as_str()).font( egui::FontId::new(14.0, egui::FontFamily::Name("phosphor-bold".into())), ), ), ); if enabled && response.clicked() { *value = reset; } response.on_hover_text(tooltip); } } pub(super) fn material_vec2_value(inputs: &MaterialInputSet, name: &str, default: Vec2) -> Vec2 { inputs .values .iter() .find(|parameter| parameter.name == name) .and_then(|parameter| match parameter.value { MaterialParameterValue::Vec2(value) => Some(value), _ => None, }) .unwrap_or(default) } pub(super) fn set_material_vec2_value(inputs: &mut MaterialInputSet, name: &str, value: Vec2) { if let Some(parameter) = inputs .values .iter_mut() .find(|parameter| parameter.name == name) { parameter.value = MaterialParameterValue::Vec2(value); } else { inputs.values.push(MaterialParameter { name: name.into(), value: MaterialParameterValue::Vec2(value), }); } }