voxel-zone/app/src/systems/ui/properties.rs

169 lines
7.0 KiB
Rust

use core::fmt;
use std::rc::Rc;
use bevy::{
prelude::{Camera, Commands, Component, Entity, GlobalTransform, Query, ResMut, Transform},
render::camera::Projection,
};
use bevy_egui::EguiContext;
use block_mesh::Voxel;
use common::space::{
level_tile::LevelTile,
three_dimensional::{
hash_map_container::VoxelHashMapLayer,
traits::{DefaultVoxel, VoxelContainer},
},
two_dimensional::depth_tiles::Direction,
};
use egui::{mutex::Mutex, Button, CollapsingHeader, Ui};
use smooth_bevy_cameras::LookTransform;
use common::strum::IntoEnumIterator;
use crate::{
components::{mutable_mesh::MutableMesh, named::Named, property_pane::PropertyPane},
systems::{layer_spawner::{LayerSpawnerCommand}, generic_command_queue::CommandQueue},
voxels::layers::traits::VoxelLayer,
};
use super::util::{bevy_quat_controls, bevy_vec3_controls};
pub fn properties_ui(
commands: Commands,
layer_spawner_commands: ResMut<CommandQueue<LayerSpawnerCommand>>,
mut egui_context: ResMut<EguiContext>,
mut property_pane_query: Query<(&mut PropertyPane, Entity)>,
mut camera_query: Query<(&mut Camera, &mut Projection, &mut LookTransform)>,
mut transform_query: Query<(&mut Transform, &mut GlobalTransform)>,
mut tile_hashmap_layer_query: Query<(
&mut VoxelHashMapLayer<LevelTile>,
&mut Named,
&mut MutableMesh,
)>,
) {
// in case we want to send commands from multiple places in the ui
let _commands = Rc::new(Mutex::new(commands));
let layer_spawner_commands = Rc::new(Mutex::new(layer_spawner_commands));
for (mut property_pane, entity) in property_pane_query.iter_mut() {
egui::Window::new(&property_pane.title)
.open(&mut property_pane.is_open)
.min_width(400.0)
.resizable(true)
.vscroll(true)
.show(egui_context.ctx_mut(), |ui| {
voxel_layer_properties(
layer_spawner_commands.clone(),
ui,
entity,
&mut tile_hashmap_layer_query,
);
if let Ok((_camera, projection, mut look_transform)) = camera_query.get_mut(entity)
{
let _heading =
CollapsingHeader::new("Camera")
.default_open(true)
.show(ui, |ui| {
match projection.into_inner() {
Projection::Perspective(_perspective) => {}
Projection::Orthographic(orthographic) => {
ui.add(
egui::DragValue::new(&mut orthographic.scale)
.speed(1)
.prefix("orthographic scale:"),
);
}
}
ui.add(
egui::DragValue::new(&mut look_transform.eye.x)
.speed(0.2)
.prefix("eye x:"),
);
ui.add(
egui::DragValue::new(&mut look_transform.eye.y)
.speed(0.2)
.prefix("eye y:"),
);
ui.add(
egui::DragValue::new(&mut look_transform.eye.z)
.speed(0.2)
.prefix("eye z:"),
);
});
}
if let Ok((mut transform, global_transform)) = transform_query.get_mut(entity) {
let _heading =
CollapsingHeader::new("Transform")
.default_open(true)
.show(ui, |ui| {
bevy_vec3_controls(ui, &mut transform.translation, "pos");
bevy_quat_controls(ui, &mut transform.rotation, "rot");
bevy_vec3_controls(ui, &mut transform.scale, "scale");
});
let _heading = CollapsingHeader::new("GlobalTransform")
.default_open(true)
.show(ui, |ui| {
let (mut scale, mut rotation, mut translation) =
global_transform.to_scale_rotation_translation();
bevy_vec3_controls(ui, &mut translation, "pos");
bevy_quat_controls(ui, &mut rotation, "rot");
bevy_vec3_controls(ui, &mut scale, "scale");
});
}
});
}
}
fn voxel_layer_properties<TLayer, TVoxel>(
layer_spawner_commands: Rc<Mutex<ResMut<CommandQueue<LayerSpawnerCommand>>>>,
ui: &mut Ui,
entity: Entity,
layer_query: &mut Query<(&mut TLayer, &mut Named, &mut MutableMesh)>,
) where
TLayer: VoxelLayer<TVoxel> + VoxelContainer<TVoxel> + Component,
TVoxel: Voxel + DefaultVoxel + Copy + Send + Sync + fmt::Debug,
{
if let Ok((layer, named, _mutable_mesh)) = layer_query.get_mut(entity) {
let _layer = layer.into_inner();
CollapsingHeader::new("Generic Voxel Layer")
.default_open(true)
.show(ui, |ui| {
ui.horizontal(|ui| {
for dir in Direction::iter() {
if ui.add(Button::new(format!("project {:?}", dir))).clicked() {
layer_spawner_commands.lock().add(
LayerSpawnerCommand::FromTileProjectedLayer {
name: format!("{} - {:?} proj", named.name, dir),
source_layer: entity,
direction: dir,
},
)
};
}
});
ui.separator();
if ui.button("Export projected tiles").clicked() {
layer_spawner_commands.lock().add(
LayerSpawnerCommand::ExportProjectedTilesToml { name: named.name.to_string(), source_layer: entity }
);
}
});
}
}
pub fn clean_up_closed_panes(
mut commands: Commands,
mut property_pane_query: Query<(&mut PropertyPane, Entity)>,
) {
for (mut pane, entity) in property_pane_query.iter_mut() {
if pane.closable && !pane.is_open {
commands.entity(entity).remove::<PropertyPane>();
} else if !pane.closable && !pane.is_open {
// reopen it. don't allow closing this one
pane.is_open = true;
}
}
}