332 lines
15 KiB
Rust
332 lines
15 KiB
Rust
use bevy::math::{Vec3Swizzles, Mat2};
|
|
use bevy::prelude::*;
|
|
use bevy_egui::{egui, EguiContext};
|
|
use bevy_prototype_lyon::prelude::{Path, DrawMode};
|
|
use crate::*;
|
|
|
|
#[derive(Default, Deref, DerefMut, Clone)]
|
|
pub struct SelectedItem(pub Option<Entity>);
|
|
|
|
pub fn action_bar_sys(
|
|
mut coms: Commands,
|
|
assets: Res<AssetServer>,
|
|
mut egui_ctx: ResMut<EguiContext>,
|
|
mut state: ResMut<UiState>,
|
|
colors: Res<ButtonsColors>,
|
|
) {
|
|
egui::Window::new("buttons_float")
|
|
.default_pos((20.0, 20.0))
|
|
.title_bar(false)
|
|
.resizable(false)
|
|
.show(egui_ctx.ctx_mut(), |ui| {
|
|
ui.horizontal(|hui| {
|
|
let m = hui.button(egui::RichText::new("M").color(state.current_action_color(&colors, Action::Modify)))
|
|
.on_hover_text("Modify");
|
|
if m.clicked() {
|
|
state.current_action = Action::Modify;
|
|
}
|
|
let c = hui.button(egui::RichText::new("C").color(state.current_action_color(&colors, Action::Create)))
|
|
.on_hover_text("Create");
|
|
if c.clicked() {
|
|
state.current_action = Action::Create;
|
|
}
|
|
hui.label(" | ");
|
|
|
|
if hui.button(" I ").on_hover_text("Import Image").clicked() {
|
|
let file = rfd::FileDialog::new()
|
|
.add_filter("Pngs", &["png"])
|
|
.set_directory("./")
|
|
.set_title("Please dont try to pick a cat instead of an image(although you can pick a cat image)")
|
|
.pick_file();
|
|
if let Some(file) = file {
|
|
let name = String::from(file.file_name().unwrap().to_str().unwrap_or("Image"));
|
|
let image: Handle<Image> = assets.load(file);
|
|
coms.spawn_bundle(SpriteBundle {
|
|
texture: image,
|
|
..Default::default()
|
|
})
|
|
.insert(ImageName(name));
|
|
}
|
|
}
|
|
|
|
hui.label(": :");
|
|
});
|
|
|
|
if state.current_action == Action::Create {
|
|
ui.horizontal(|hui| {
|
|
let tri = hui.button(egui::RichText::new("Tri").color(state.create_shape_color(&colors, CreateShape::Triangle)))
|
|
.on_hover_text("Triangle - from 3 edges");
|
|
if tri.clicked() {
|
|
state.create_shape = CreateShape::Triangle;
|
|
}
|
|
let squ = hui.button(egui::RichText::new("Squ").color(state.create_shape_color(&colors, CreateShape::Square)))
|
|
.on_hover_text("Square - from 2 opposing edges");
|
|
if squ.clicked() {
|
|
state.create_shape = CreateShape::Square;
|
|
}
|
|
let cir = hui.button(egui::RichText::new("Cir").color(state.create_shape_color(&colors, CreateShape::Circle)))
|
|
.on_hover_text("Circle - center point and radius");
|
|
if cir.clicked() {
|
|
state.create_shape = CreateShape::Circle;
|
|
}
|
|
// let cap = hui.button(egui::RichText::new("Cap").color(state.create_shape_color(&colors, CreateShape::Capsule)))
|
|
// .on_hover_text("Capsule - from 2 center points and a radius");
|
|
// if cap.clicked() {
|
|
// state.create_shape = CreateShape::Capsule;
|
|
// }
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
pub fn grid_window_sys(
|
|
mut grid: ResMut<SnapGrid>,
|
|
mut egui_ctx: ResMut<EguiContext>,
|
|
) {
|
|
egui::Window::new("Snap Grid")
|
|
.default_pos((500.0, 20.0))
|
|
.title_bar(true)
|
|
.resizable(false)
|
|
.show(egui_ctx.ctx_mut(), |ui| {
|
|
ui.horizontal(|hui| {
|
|
hui.checkbox(&mut grid.snap, "Snap Enabled");
|
|
hui.checkbox(&mut grid.visible, "Visible");
|
|
});
|
|
|
|
ui.label("Grid size:");
|
|
ui.horizontal(|hui| {
|
|
hui.label("Width:");
|
|
hui.add(egui::DragValue::new(&mut grid.width));
|
|
hui.label("Height:");
|
|
hui.add(egui::DragValue::new(&mut grid.height));
|
|
});
|
|
ui.horizontal(|hui| {
|
|
hui.label("Offset:");
|
|
hui.label("X:");
|
|
hui.add(egui::DragValue::new(&mut grid.offset.x));
|
|
hui.label("Y:");
|
|
hui.add(egui::DragValue::new(&mut grid.offset.y));
|
|
});
|
|
|
|
});
|
|
}
|
|
/// Items tree
|
|
///
|
|
/// Select items to edit in an inspector window/panel,
|
|
/// or just change the visibility of items
|
|
///
|
|
/// TODO: Allow drag and drop to re-order + reparent
|
|
pub fn items_tree_sys(
|
|
mut selected: ResMut<SelectedItem>,
|
|
mut egui_ctx: ResMut<EguiContext>,
|
|
shapes:Query<(Entity, &ShapeData)>,
|
|
images: Query<(Entity, &ImageName), With<Sprite>>,
|
|
mut draw_modes: Query<&mut DrawMode, With<ShapeData>>,
|
|
mut visible: Query<&mut Visibility, Or<(With<Path>, With<Sprite>)>>,
|
|
) {
|
|
egui::Window::new("Items")
|
|
.default_pos((10.0,100.0))
|
|
.title_bar(true)
|
|
.resizable(false)
|
|
.show(egui_ctx.ctx_mut(), |ui| {
|
|
for (e, sd) in shapes.iter() {
|
|
let entity_selected = if let Some(se) = **selected && se == e { true } else { false };
|
|
ui.horizontal(|hui| {
|
|
let color = if entity_selected { egui::Color32::GOLD } else { egui::Color32::WHITE };
|
|
let label = egui::Label::new(egui::RichText::new(&sd.name).color(color)).sense(egui::Sense::click());
|
|
if hui.add(label).clicked() {
|
|
if entity_selected {
|
|
**selected = None;
|
|
}
|
|
else {
|
|
**selected = Some(e);
|
|
}
|
|
}
|
|
|
|
if let Ok(mut v) = visible.get_mut(e) {
|
|
let rt = egui::RichText::new("V");
|
|
if hui.button(if v.is_visible { rt } else { rt.strikethrough() }).clicked() {
|
|
v.is_visible ^= true;
|
|
}
|
|
}
|
|
});
|
|
|
|
if let Ok(mut dm) = draw_modes.get_mut(e) {
|
|
if let DrawMode::Outlined { fill_mode: _ , outline_mode: o } = &mut *dm {
|
|
o.color = if entity_selected { Color::GOLD } else { Color::rgba(0.0, 0.5, 0.5, 0.6) };
|
|
}
|
|
}
|
|
}
|
|
for (e, n) in images.iter() {
|
|
let entity_selected = if let Some(se) = **selected && se == e { true } else { false };
|
|
|
|
ui.horizontal(|hui| {
|
|
let color = if entity_selected { egui::Color32::GOLD } else { egui::Color32::WHITE };
|
|
let label = egui::Label::new(egui::RichText::new(&**n).color(color)).sense(egui::Sense::click());
|
|
if hui.add(label).clicked() {
|
|
if entity_selected {
|
|
**selected = None;
|
|
}
|
|
else {
|
|
**selected = Some(e);
|
|
}
|
|
}
|
|
|
|
if let Ok(mut v) = visible.get_mut(e) {
|
|
let rt = egui::RichText::new("V");
|
|
if hui.button(if v.is_visible { rt } else { rt.strikethrough() }).clicked() {
|
|
v.is_visible ^= true;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
});
|
|
}
|
|
|
|
pub fn inspector_sys(
|
|
mut selected: ResMut<SelectedItem>, // Which item is currently selected
|
|
mut coms: Commands, // For deletion!
|
|
mut egui_ctx: ResMut<EguiContext>,
|
|
mut shapes: Query<&mut ShapeData>,
|
|
mut transforms: Query<&mut Transform>,
|
|
global_transforms: Query<&GlobalTransform>,
|
|
mut paths: Query<&mut Path>,
|
|
mut draw_modes: Query<&mut DrawMode, With<Path>>,
|
|
mut visible: Query<&mut Visibility, Or<(With<Path>, With<Sprite>)>>,
|
|
mut images: Query<&mut ImageName, With<Sprite>>,
|
|
) {
|
|
if let Some(e) = **selected {
|
|
let mut open = true;
|
|
|
|
egui::Window::new("Inspector")
|
|
.default_pos((350.0, 350.0))
|
|
.fixed_size((150.0, f32::INFINITY))
|
|
.title_bar(true)
|
|
.collapsible(false)
|
|
.open(&mut open)
|
|
.resizable(false)
|
|
.show(egui_ctx.ctx_mut(), |ui| {
|
|
if let Ok(mut sd) = shapes.get_mut(e) {
|
|
ui.horizontal(|hui| {
|
|
hui.label("Name:");
|
|
hui.text_edit_singleline(&mut sd.name);
|
|
});
|
|
ui.separator();
|
|
if let Ok(mut t) = transforms.get_mut(sd.main_shape) {
|
|
ui.horizontal(|hui| {
|
|
hui.label("Translation:");
|
|
hui.add(egui::DragValue::new(&mut t.translation.x));
|
|
hui.add(egui::DragValue::new(&mut t.translation.y));
|
|
|
|
});
|
|
ui.horizontal(|hui| {
|
|
hui.label("Rotation:");
|
|
let mut rot = t.rotation.to_euler(EulerRot::XYZ).2.to_degrees();
|
|
if hui.add(egui::DragValue::new(&mut rot).suffix("°")).changed() {
|
|
t.rotation = Quat::from_rotation_z(rot.to_radians());
|
|
}
|
|
hui.label("Z:");
|
|
hui.add(egui::DragValue::new(&mut t.translation.z).clamp_range(0..=i32::MAX));
|
|
});
|
|
}
|
|
ui.separator();
|
|
for (i, edge) in sd.edges.iter().enumerate() {
|
|
ui.horizontal(|hui| {
|
|
hui.label(format!("Edge {}", i));
|
|
let gt = global_transforms.get(*edge).unwrap();
|
|
let mut gt_x = gt.translation().x;
|
|
let mut gt_y = gt.translation().y;
|
|
let c1 = hui.add(egui::DragValue::new(&mut gt_x)).changed();
|
|
let c2 = hui.add(egui::DragValue::new(&mut gt_y)).changed();
|
|
|
|
if c1 || c2 {
|
|
let rot = gt.to_scale_rotation_translation().1;
|
|
let ang = rot.to_euler(EulerRot::XYZ).2;
|
|
let delta = Mat2::from_angle(-ang) * (Vec2::new(gt_x, gt_y) - gt.translation().xy());
|
|
if let Ok(mut t) = transforms.get_mut(*edge) {
|
|
t.translation += delta.extend(0.0);
|
|
}
|
|
// We need to recalculate the center, and update the points to be the new relevant point from the center
|
|
let center_offset = modify::calc_shape_center_offset(&transforms, &*sd);
|
|
// Update each edge's offset, and then move the main shape's translation
|
|
for edge in sd.edges.iter() {
|
|
if let Ok(mut t) = transforms.get_mut(*edge) {
|
|
t.translation -= center_offset.extend(0.0);
|
|
}
|
|
}
|
|
if let Ok(mut t) = transforms.get_mut(sd.main_shape) {
|
|
t.translation += (Mat2::from_angle(ang) * center_offset).extend(0.0);
|
|
}
|
|
|
|
// Now we need to update the shape itself
|
|
modify::update_main_shape(&mut paths, &transforms, &*sd);
|
|
}
|
|
});
|
|
}
|
|
ui.separator();
|
|
if let Ok(mut v) = visible.get_mut(e) {
|
|
ui.checkbox(&mut v.is_visible, "Visible");
|
|
}
|
|
if let Ok(mut dm) = draw_modes.get_mut(e) {
|
|
ui.separator();
|
|
if let DrawMode::Outlined { fill_mode: f, outline_mode: _ } = &mut *dm {
|
|
ui.horizontal(|hui| {
|
|
hui.label("Color: ");
|
|
let mut color = [f.color.r(), f.color.g(), f.color.b(), f.color.a()];
|
|
if hui.color_edit_button_rgba_unmultiplied(&mut color).changed() {
|
|
f.color = Color::from(color);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
ui.separator();
|
|
if ui.button("Delete").clicked() {
|
|
coms.entity(e).despawn_recursive();
|
|
**selected = None;
|
|
}
|
|
}
|
|
else if let Ok(mut name) = images.get_mut(e) {
|
|
ui.horizontal(|hui| {
|
|
hui.label("Name:");
|
|
hui.text_edit_singleline(&mut **name);
|
|
});
|
|
ui.separator();
|
|
|
|
if let Ok(mut t) = transforms.get_mut(e) {
|
|
ui.horizontal(|hui| {
|
|
hui.label("Translation:");
|
|
hui.add(egui::DragValue::new(&mut t.translation.x));
|
|
hui.add(egui::DragValue::new(&mut t.translation.y));
|
|
|
|
});
|
|
ui.horizontal(|hui| {
|
|
hui.label("Rotation:");
|
|
let mut rot = t.rotation.to_euler(EulerRot::XYZ).2.to_degrees();
|
|
if hui.add(egui::DragValue::new(&mut rot).suffix("°")).changed() {
|
|
t.rotation = Quat::from_rotation_z(rot.to_radians());
|
|
}
|
|
hui.label("Z:");
|
|
hui.add(egui::DragValue::new(&mut t.translation.z).clamp_range(0..=i32::MAX));
|
|
});
|
|
ui.horizontal(|hui| {
|
|
hui.label("Scale:");
|
|
hui.add(egui::DragValue::new(&mut t.scale.x).speed(0.01));
|
|
hui.add(egui::DragValue::new(&mut t.scale.y).speed(0.01));
|
|
});
|
|
}
|
|
|
|
ui.separator();
|
|
if ui.button("Delete").clicked() {
|
|
coms.entity(e).despawn_recursive();
|
|
**selected = None;
|
|
}
|
|
}
|
|
});
|
|
if !open {
|
|
**selected = None;
|
|
}
|
|
}
|
|
} |