use crate::mosaic::WidgetContext;
use nightshade::prelude::serde::{Deserialize, Serialize};
use nightshade::prelude::*;
use crate::app_context::AppContext;
use crate::messages::EditorMessage;
#[derive(Clone, Default, Serialize, Deserialize)]
#[serde(crate = "nightshade::prelude::serde")]
pub struct CameraWidget {
pub camera_index: usize,
}
impl CameraWidget {
pub(crate) fn render(
&mut self,
ui: &mut egui::Ui,
context: &mut WidgetContext<AppContext, EditorMessage>,
) {
let rect = ui.available_rect_before_wrap();
let tile_id = context.current_tile_id;
let pixels_per_point = ui.ctx().pixels_per_point();
let cameras = context.cached_cameras;
if !cameras.is_empty() && self.camera_index >= cameras.len() {
self.camera_index = cameras.len() - 1;
}
let camera_entity = cameras.get(self.camera_index).copied();
let screen_rect = ui.ctx().content_rect();
let (viewport_width, viewport_height) = if let Some((physical_width, physical_height)) =
context.world().resources.window.cached_viewport_size
{
let scale_x = physical_width as f32 / screen_rect.width();
let scale_y = physical_height as f32 / screen_rect.height();
(
(rect.width() * scale_x).round() as u32,
(rect.height() * scale_y).round() as u32,
)
} else {
(
(rect.width() * pixels_per_point).round() as u32,
(rect.height() * pixels_per_point).round() as u32,
)
};
let texture_index = camera_entity.and_then(|cam| {
context
.world()
.resources
.user_interface
.required_cameras
.iter()
.position(|&entity| entity == cam)
});
if let Some(index) = texture_index {
context
.world_mut()
.resources
.user_interface
.required_camera_sizes[index] = (viewport_width, viewport_height);
}
let clicked = if let Some(index) = texture_index
&& let Some(texture_id) = context.viewport_textures.get(index)
{
let image = egui::Image::new(egui::load::SizedTexture::new(
*texture_id,
egui::vec2(rect.width(), rect.height()),
))
.fit_to_exact_size(egui::vec2(rect.width(), rect.height()))
.sense(egui::Sense::click());
let response = ui.put(rect, image);
response.clicked()
} else {
let response = ui.allocate_rect(rect, egui::Sense::click());
response.clicked()
};
let was_none = context.selected_viewport_tile.is_none();
if was_none {
*context.selected_viewport_tile = Some(tile_id);
}
if clicked {
*context.selected_viewport_tile = Some(tile_id);
}
let is_selected = *context.selected_viewport_tile == Some(tile_id);
let world = context.world_mut();
if (was_none || clicked || is_selected)
&& let Some(cam) = camera_entity
{
world.resources.active_camera = Some(cam);
}
if is_selected {
world.resources.window.active_viewport_rect = Some(nightshade::prelude::ViewportRect {
x: rect.min.x * pixels_per_point,
y: rect.min.y * pixels_per_point,
width: rect.width() * pixels_per_point,
height: rect.height() * pixels_per_point,
});
}
if is_selected {
ui.painter().rect_stroke(
rect,
egui::CornerRadius::ZERO,
egui::Stroke::new(3.0, egui::Color32::from_rgb(255, 165, 0)),
egui::StrokeKind::Inside,
);
}
if cameras.len() > 1 {
let selector_width = 120.0;
let selector_height = 24.0;
let margin = 8.0;
let selector_rect = egui::Rect::from_min_size(
egui::pos2(rect.min.x + margin, rect.min.y + margin),
egui::vec2(selector_width, selector_height),
);
let mut child_ui = ui.new_child(
egui::UiBuilder::new()
.max_rect(selector_rect)
.layout(egui::Layout::left_to_right(egui::Align::Center)),
);
let world = context.world();
let current_camera_name = camera_entity
.and_then(|entity| world.core.get_name(entity))
.map(|name| name.0.clone())
.unwrap_or_else(|| format!("Camera {}", self.camera_index + 1));
egui::ComboBox::from_id_salt(("camera_selector", tile_id))
.selected_text(¤t_camera_name)
.width(selector_width - 8.0)
.show_ui(&mut child_ui, |ui| {
for (index, &entity) in cameras.iter().enumerate() {
let name = world
.core
.get_name(entity)
.map(|name| name.0.clone())
.unwrap_or_else(|| format!("Camera {}", index + 1));
if ui
.selectable_label(self.camera_index == index, &name)
.clicked()
{
self.camera_index = index;
}
}
});
}
}
}