use crate::prelude::*;
use super::widget::WidgetContext;
#[derive(Clone, Default, serde::Serialize, serde::Deserialize)]
pub struct ViewportWidget {
pub camera_index: usize,
}
impl ViewportWidget {
pub fn title(&self) -> String {
format!("Viewport {}", self.camera_index + 1)
}
pub fn required_camera(&self, cameras: &[Entity]) -> Option<Entity> {
cameras.get(self.camera_index).copied()
}
pub fn ui<C, M>(&mut self, ui: &mut egui::Ui, context: &mut WidgetContext<C, M>) {
let rect = ui.available_rect_before_wrap();
let tile_id = context.current_tile_id;
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 pixels_per_point = ui.ctx().pixels_per_point();
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(|camera| {
context
.world()
.resources
.user_interface
.required_cameras
.iter()
.position(|&entity| entity == camera)
});
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());
ui.put(rect, image).clicked()
} else {
ui.allocate_rect(rect, egui::Sense::click()).clicked()
};
if context.selected_viewport_tile.is_none() {
*context.selected_viewport_tile = Some(tile_id);
if let Some(camera) = camera_entity {
context.world_mut().resources.active_camera = Some(camera);
}
}
if clicked {
*context.selected_viewport_tile = Some(tile_id);
if let Some(camera) = camera_entity {
context.world_mut().resources.active_camera = Some(camera);
}
}
let is_selected = *context.selected_viewport_tile == Some(tile_id);
if is_selected {
if context.is_active_window {
context.world_mut().resources.window.active_viewport_rect = Some(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 let Some(camera) = camera_entity {
context.world_mut().resources.active_camera = Some(camera);
}
}
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 current_camera_name = camera_entity
.and_then(|entity| context.world().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 = context
.world()
.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;
}
}
});
}
}
}