tree view update + highlihgt hovered dot
This commit is contained in:
parent
db8657bb96
commit
c59621e43d
6 changed files with 184 additions and 32 deletions
17
README.md
17
README.md
|
@ -4,11 +4,12 @@ Eventually, this will be a level editor... But until then, I guess it's just fun
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
[ ] Items tree view showing all shapes with their child nodes and purposes(maybe location and such as well?)
|
- [x] Items tree view showing all shapes with their child nodes and purposes(maybe location and such as well?)
|
||||||
[ ] Delete shapes
|
- [ ] Change shape name in tree view
|
||||||
[ ] Import images
|
- [ ] Delete shapes in tree view
|
||||||
[ ] Drag camera around
|
- [ ] Import images
|
||||||
[ ] Zome in/out
|
- [ ] Drag camera around
|
||||||
[ ] Export
|
- [ ] Zome in/out
|
||||||
[ ] Import
|
- [ ] Export
|
||||||
[ ] Save? (maybe just import and export directly?)
|
- [ ] Import
|
||||||
|
- [ ] Save? (maybe just import and export directly?)
|
||||||
|
|
|
@ -163,6 +163,7 @@ fn add_center_point(
|
||||||
DrawMode::Fill(FillMode::color(Color::RED)),
|
DrawMode::Fill(FillMode::color(Color::RED)),
|
||||||
Transform::from_translation(Vec3::new(0.0, 0.0, 1.0))
|
Transform::from_translation(Vec3::new(0.0, 0.0, 1.0))
|
||||||
))
|
))
|
||||||
|
.insert(Visibility { is_visible: false })
|
||||||
.id();
|
.id();
|
||||||
sd.center = Some(np);
|
sd.center = Some(np);
|
||||||
|
|
||||||
|
@ -317,6 +318,7 @@ fn create_new_shape(coms: &mut Commands, pos: Vec2, create_shape: CreateShape, p
|
||||||
)).id()
|
)).id()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get center point(if exists)
|
// Get center point(if exists)
|
||||||
let center = match create_shape {
|
let center = match create_shape {
|
||||||
CreateShape::Circle => Some(fp),
|
CreateShape::Circle => Some(fp),
|
||||||
|
@ -324,5 +326,5 @@ fn create_new_shape(coms: &mut Commands, pos: Vec2, create_shape: CreateShape, p
|
||||||
};
|
};
|
||||||
let edges = if center.is_none() { Vec::from([fp]) } else { Vec::new() };
|
let edges = if center.is_none() { Vec::from([fp]) } else { Vec::new() };
|
||||||
|
|
||||||
ShapeData { shape: create_shape, main_shape, edges, center }
|
ShapeData { shape: create_shape, main_shape, edges, center, name: None }
|
||||||
}
|
}
|
14
src/lib.rs
14
src/lib.rs
|
@ -1,14 +1,13 @@
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
|
|
||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_egui::egui;
|
use bevy_egui::egui;
|
||||||
|
|
||||||
mod create;
|
pub mod create;
|
||||||
mod helpers;
|
pub mod helpers;
|
||||||
mod modify;
|
pub mod modify;
|
||||||
mod rotate;
|
pub mod rotate;
|
||||||
mod ui;
|
pub mod ui;
|
||||||
pub use ui::{action_bar_sys, shape_tree_sys};
|
pub use ui::{action_bar_sys, shape_tree_sys};
|
||||||
pub use modify::modify_sys;
|
pub use modify::modify_sys;
|
||||||
pub use create::create_sys;
|
pub use create::create_sys;
|
||||||
|
@ -21,6 +20,7 @@ pub struct PointSize(pub f32);
|
||||||
|
|
||||||
#[derive(Component, Debug)]
|
#[derive(Component, Debug)]
|
||||||
pub struct ShapeData {
|
pub struct ShapeData {
|
||||||
|
pub name: Option<String>,
|
||||||
pub shape: CreateShape,
|
pub shape: CreateShape,
|
||||||
pub main_shape: Entity,
|
pub main_shape: Entity,
|
||||||
pub edges: Vec<Entity>,
|
pub edges: Vec<Entity>,
|
||||||
|
@ -36,7 +36,7 @@ pub enum CreateShape {
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
Create, Modify, Delete, Rotate
|
Create, Modify, Rotate
|
||||||
}
|
}
|
||||||
pub struct UiState {
|
pub struct UiState {
|
||||||
pub current_action: Action,
|
pub current_action: Action,
|
||||||
|
|
98
src/main.rs
98
src/main.rs
|
@ -1,4 +1,5 @@
|
||||||
use bevy::ecs::schedule::ShouldRun;
|
use bevy::ecs::schedule::ShouldRun;
|
||||||
|
use bevy::math::Vec3Swizzles;
|
||||||
use bevy::{prelude::*, window::PresentMode, winit::WinitSettings};
|
use bevy::{prelude::*, window::PresentMode, winit::WinitSettings};
|
||||||
use bevy_egui::{egui, EguiContext, EguiPlugin};
|
use bevy_egui::{egui, EguiContext, EguiPlugin};
|
||||||
use bevy_prototype_lyon::prelude::*;
|
use bevy_prototype_lyon::prelude::*;
|
||||||
|
@ -20,7 +21,7 @@ fn main() {
|
||||||
})
|
})
|
||||||
.insert_resource(ButtonsColors::default())
|
.insert_resource(ButtonsColors::default())
|
||||||
.insert_resource(UiState::default())
|
.insert_resource(UiState::default())
|
||||||
.insert_resource(PointSize(5.0))
|
.insert_resource(PointSize(6.0))
|
||||||
;
|
;
|
||||||
|
|
||||||
app
|
app
|
||||||
|
@ -28,6 +29,7 @@ fn main() {
|
||||||
.add_plugin(EguiPlugin)
|
.add_plugin(EguiPlugin)
|
||||||
.add_plugin(ShapePlugin)
|
.add_plugin(ShapePlugin)
|
||||||
;
|
;
|
||||||
|
|
||||||
app
|
app
|
||||||
.add_startup_system(configure_visuals)
|
.add_startup_system(configure_visuals)
|
||||||
.add_startup_system(basic_setup_sys)
|
.add_startup_system(basic_setup_sys)
|
||||||
|
@ -42,6 +44,8 @@ fn main() {
|
||||||
))
|
))
|
||||||
.add_system(action_bar_sys)
|
.add_system(action_bar_sys)
|
||||||
.add_system(shape_tree_sys)
|
.add_system(shape_tree_sys)
|
||||||
|
.add_system(show_hide_points)
|
||||||
|
.add_system(color_points)
|
||||||
;
|
;
|
||||||
|
|
||||||
app.run();
|
app.run();
|
||||||
|
@ -59,4 +63,96 @@ fn configure_visuals(mut egui_ctx: ResMut<EguiContext>) {
|
||||||
window_rounding: 0.0.into(),
|
window_rounding: 0.0.into(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn show_hide_points(
|
||||||
|
state: Res<UiState>,
|
||||||
|
shapes: Query<&ShapeData>,
|
||||||
|
mut dots: Query<&mut Visibility, (With<Transform>, With<Path>)>,
|
||||||
|
) {
|
||||||
|
let (center, edge) = match state.current_action {
|
||||||
|
Action::Create => (false, false),
|
||||||
|
Action::Modify => (true, true),
|
||||||
|
Action::Rotate => (true, true),
|
||||||
|
};
|
||||||
|
|
||||||
|
for sd in shapes.iter() {
|
||||||
|
// center
|
||||||
|
if let Ok(mut v) = dots.get_mut(sd.center.unwrap()) {
|
||||||
|
if v.is_visible != center {
|
||||||
|
v.is_visible = center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for e in sd.edges.iter() {
|
||||||
|
if let Ok(mut v) = dots.get_mut(*e) {
|
||||||
|
if v.is_visible != edge {
|
||||||
|
v.is_visible = edge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn color_points(
|
||||||
|
mut current: Local<Option<Entity>>,
|
||||||
|
wnds: Res<Windows>,
|
||||||
|
p_size: Res<PointSize>,
|
||||||
|
q_cam: Query<(&Camera, &GlobalTransform), With<MainCamera>>,
|
||||||
|
shapes: Query<&ShapeData>,
|
||||||
|
global_transforms: Query<&GlobalTransform, With<Path>>,
|
||||||
|
mut dots: Query<&mut DrawMode, With<Path>>,
|
||||||
|
) {
|
||||||
|
let normal = DrawMode::Outlined { fill_mode: FillMode::color(Color::RED), outline_mode: StrokeMode::new(Color::rgb(0.9,0.0,0.0), 1.0) };
|
||||||
|
let hover = DrawMode::Outlined { fill_mode: FillMode::color(Color::RED), outline_mode: StrokeMode::new(Color::ORANGE, 3.0) };
|
||||||
|
|
||||||
|
let mouse_pos = get_mouse_pos(&q_cam, &wnds);
|
||||||
|
if let Some(mpos) = mouse_pos {
|
||||||
|
let mut hovering = false;
|
||||||
|
'shapes: for sd in shapes.iter() {
|
||||||
|
let e = sd.center.unwrap();
|
||||||
|
let p = global_transforms.get(e).unwrap().translation.xy();
|
||||||
|
if (mpos - p).length_squared() < p_size.0.powi(2) {
|
||||||
|
if Some(e) != *current {
|
||||||
|
if let Some(c) = &*current {
|
||||||
|
if let Ok(mut md) = dots.get_mut(*c) {
|
||||||
|
*md = normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*current = Some(e);
|
||||||
|
if let Ok(mut md) = dots.get_mut(e) {
|
||||||
|
*md = hover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hovering = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for edge in sd.edges.iter() {
|
||||||
|
let p = global_transforms.get(*edge).unwrap().translation.xy();
|
||||||
|
if (mpos - p).length_squared() < p_size.0.powi(2) {
|
||||||
|
if Some(*edge) != *current {
|
||||||
|
if let Some(c) = &*current {
|
||||||
|
if let Ok(mut md) = dots.get_mut(*c) {
|
||||||
|
*md = normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*current = Some(*edge);
|
||||||
|
if let Ok(mut md) = dots.get_mut(*edge) {
|
||||||
|
*md = hover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hovering = true;
|
||||||
|
break 'shapes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !hovering {
|
||||||
|
if let Some(c) = &*current {
|
||||||
|
if let Ok(mut md) = dots.get_mut(*c) {
|
||||||
|
*md = normal;
|
||||||
|
}
|
||||||
|
*current = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -9,7 +9,7 @@ pub fn modify_sys(
|
||||||
mouse: Res<Input<MouseButton>>,
|
mouse: Res<Input<MouseButton>>,
|
||||||
wnds: Res<Windows>,
|
wnds: Res<Windows>,
|
||||||
p_size: Res<PointSize>,
|
p_size: Res<PointSize>,
|
||||||
paths: Query<&mut Path>,
|
mut paths: Query<&mut Path>,
|
||||||
mut transforms: Query<&mut Transform>,
|
mut transforms: Query<&mut Transform>,
|
||||||
gtransforms: Query<&GlobalTransform>,
|
gtransforms: Query<&GlobalTransform>,
|
||||||
q_cam: Query<(&Camera, &GlobalTransform), With<MainCamera>>,
|
q_cam: Query<(&Camera, &GlobalTransform), With<MainCamera>>,
|
||||||
|
@ -71,14 +71,14 @@ pub fn modify_sys(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we need to update the shape itself
|
// Now we need to update the shape itself
|
||||||
update_main_shape(paths, transforms, sd);
|
update_main_shape(&mut paths, &transforms, sd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calc_shape_center_offset(transforms: &Query<&mut Transform>, sd: &ShapeData) -> Vec2 {
|
pub fn calc_shape_center_offset(transforms: &Query<&mut Transform>, sd: &ShapeData) -> Vec2 {
|
||||||
match sd.shape {
|
match sd.shape {
|
||||||
CreateShape::Triangle => {
|
CreateShape::Triangle => {
|
||||||
assert!(sd.edges.len() == 3);
|
assert!(sd.edges.len() == 3);
|
||||||
|
@ -109,7 +109,7 @@ fn calc_shape_center_offset(transforms: &Query<&mut Transform>, sd: &ShapeData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_main_shape(mut paths: Query<&mut Path>, transforms: Query<&mut Transform>, sd: &ShapeData) {
|
pub fn update_main_shape(paths: &mut Query<&mut Path>, transforms: &Query<&mut Transform>, sd: &ShapeData) {
|
||||||
let path = match sd.shape {
|
let path = match sd.shape {
|
||||||
CreateShape::Triangle => {
|
CreateShape::Triangle => {
|
||||||
assert!(sd.edges.len() == 3);
|
assert!(sd.edges.len() == 3);
|
||||||
|
|
75
src/ui.rs
75
src/ui.rs
|
@ -1,5 +1,7 @@
|
||||||
|
use bevy::math::{Vec3Swizzles, Mat2};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_egui::{egui, EguiContext};
|
use bevy_egui::{egui, EguiContext};
|
||||||
|
use bevy_prototype_lyon::prelude::Path;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
pub fn action_bar_sys(
|
pub fn action_bar_sys(
|
||||||
|
@ -28,11 +30,6 @@ pub fn action_bar_sys(
|
||||||
if c.clicked() {
|
if c.clicked() {
|
||||||
state.current_action = Action::Create;
|
state.current_action = Action::Create;
|
||||||
}
|
}
|
||||||
let d = hui.button(egui::RichText::new("D").color(state.current_action_color(&colors, Action::Delete)))
|
|
||||||
.on_hover_text("Delete");
|
|
||||||
if d.clicked() {
|
|
||||||
state.current_action = Action::Delete;
|
|
||||||
}
|
|
||||||
hui.label(" | ");
|
hui.label(" | ");
|
||||||
|
|
||||||
if hui.button(" I ").on_hover_text("Import Image").clicked() {
|
if hui.button(" I ").on_hover_text("Import Image").clicked() {
|
||||||
|
@ -70,9 +67,13 @@ pub fn action_bar_sys(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shape_tree_sys(
|
pub fn shape_tree_sys(
|
||||||
|
mut name_change: Local<Option<(Entity, String)>>,
|
||||||
|
mut coms: Commands,
|
||||||
mut egui_ctx: ResMut<EguiContext>,
|
mut egui_ctx: ResMut<EguiContext>,
|
||||||
shapes: Query<(Entity, &ShapeData)>,
|
mut shapes: Query<(Entity, &mut ShapeData)>,
|
||||||
mut transforms: Query<&mut Transform>,
|
mut transforms: Query<&mut Transform>,
|
||||||
|
global_transforms: Query<&GlobalTransform>,
|
||||||
|
mut paths: Query<&mut Path>,
|
||||||
) {
|
) {
|
||||||
if !shapes.is_empty() {
|
if !shapes.is_empty() {
|
||||||
egui::Window::new("Shape Tree")
|
egui::Window::new("Shape Tree")
|
||||||
|
@ -80,11 +81,9 @@ pub fn shape_tree_sys(
|
||||||
.title_bar(true)
|
.title_bar(true)
|
||||||
.resizable(false)
|
.resizable(false)
|
||||||
.show(egui_ctx.ctx_mut(), |ui| {
|
.show(egui_ctx.ctx_mut(), |ui| {
|
||||||
for (e, sd) in shapes.iter() {
|
for (e, mut sd) in shapes.iter_mut () {
|
||||||
ui.push_id(e.id(), |ui| {
|
ui.push_id(e.id(), |ui| {
|
||||||
|
let ui_func = |ui: &mut egui::Ui| {
|
||||||
ui.collapsing(format!("{:?}", sd.shape), |ui| {
|
|
||||||
|
|
||||||
if let Ok(mut t) = transforms.get_mut(sd.main_shape) {
|
if let Ok(mut t) = transforms.get_mut(sd.main_shape) {
|
||||||
ui.horizontal(|hui| {
|
ui.horizontal(|hui| {
|
||||||
hui.label("Translation:");
|
hui.label("Translation:");
|
||||||
|
@ -99,7 +98,61 @@ pub fn shape_tree_sys(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
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 ang = gt.rotation.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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Some((sde, name)) = &mut *name_change && *sde == e {
|
||||||
|
// Changing the current shape's name
|
||||||
|
let te = egui::TextEdit::singleline(name).desired_width(100.0);
|
||||||
|
|
||||||
|
if ui.add(te).lost_focus() {
|
||||||
|
let (_, name) = name_change.take().unwrap();
|
||||||
|
sd.name = Some(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let default_name = format!("{:?}", sd.shape);
|
||||||
|
ui.horizontal(|hui| {
|
||||||
|
let closed = hui.collapsing(sd.name.as_ref().unwrap_or(&default_name), ui_func).fully_closed();
|
||||||
|
if closed && hui.button("E").clicked() {
|
||||||
|
*name_change = Some((e, default_name));
|
||||||
|
}
|
||||||
|
if closed && hui.button("D").clicked() {
|
||||||
|
coms.entity(sd.main_shape).despawn_recursive();
|
||||||
|
coms.entity(e).despawn();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue