219 lines
9.1 KiB
Rust
219 lines
9.1 KiB
Rust
use bevy::math::{Vec3Swizzles, Mat2};
|
|
use bevy::prelude::*;
|
|
use crate::*;
|
|
use bevy_prototype_lyon::prelude::*;
|
|
|
|
#[derive(Default, PartialEq)]
|
|
pub enum Holding {
|
|
/// (ShapeData, Path)
|
|
Shape(Entity, Entity),
|
|
/// (Sprite, Offset)
|
|
Image(Entity, Vec2),
|
|
#[default]
|
|
None,
|
|
}
|
|
|
|
pub fn modify_sys(
|
|
// Which entity the user currently drags, and which specific part of it(ShapeData entity, path entity)
|
|
mut holding: Local<Holding>,
|
|
mut held_from: Local<Vec2>,
|
|
mut undo: ResMut<undo::UndoStack>,
|
|
mouse: Res<Input<MouseButton>>,
|
|
wnds: Res<Windows>,
|
|
scale: Query<&OrthographicProjection, With<MainCamera>>,
|
|
p_size: Res<PointSize>,
|
|
assets: Res<Assets<Image>>,
|
|
mut paths: Query<&mut Path>,
|
|
mut transforms: Query<&mut Transform>,
|
|
gtransforms: Query<&GlobalTransform>,
|
|
q_cam: Query<(&Camera, &GlobalTransform), With<MainCamera>>,
|
|
shapes: Query<(Entity, &ShapeData)>,
|
|
images: Query<(Entity, &Handle<Image>)>,
|
|
snap: Res<SnapGrid>,
|
|
) {
|
|
let scale = scale.get_single().map(|s| s.scale).unwrap_or(1.0);
|
|
let mouse_pos = get_mouse_pos(&q_cam, &wnds);
|
|
|
|
if let Some(mouse_pos) = mouse_pos {
|
|
if mouse.just_pressed(MouseButton::Left) && *holding == Holding::None {
|
|
// Grab attempt - search if we are holding a shape or something
|
|
for (e, sd) in shapes.iter() {
|
|
if let Ok(t) = gtransforms.get(sd.center.unwrap()) {
|
|
let t = t.translation().xy();
|
|
if (mouse_pos - t).length_squared() < (p_size.0 * scale).powi(2) {
|
|
*held_from = t;
|
|
*holding = Holding::Shape(e, sd.center.unwrap());
|
|
break;
|
|
}
|
|
}
|
|
for edge in sd.edges.iter() {
|
|
if let Ok(t) = gtransforms.get(*edge) {
|
|
let t = t.translation().xy();
|
|
|
|
if (mouse_pos - t).length_squared() < (p_size.0 * scale).powi(2) {
|
|
*held_from = t;
|
|
*holding = Holding::Shape(e, *edge);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Only proceed if holding is still None
|
|
if *holding == Holding::None {
|
|
for (e, h) in images.iter() {
|
|
if let Some(size) = assets.get(h).map(|x| x.size()) {
|
|
let size = size * 0.5;
|
|
let t = gtransforms.get(e).unwrap();
|
|
let scale = t.to_scale_rotation_translation().0;
|
|
// Disregard rotations for now plz
|
|
let diff = (mouse_pos - t.translation().xy()).abs();
|
|
if diff.x < size.x * scale.x && diff.y < size.y * scale.y {
|
|
*held_from = t.translation().xy();
|
|
*holding = Holding::Image(e, mouse_pos - t.translation().xy());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if mouse.just_released(MouseButton::Left) && *holding != Holding::None {
|
|
match *holding {
|
|
Holding::Shape(shape_data, dot) => {
|
|
if let Ok(sd) = shapes.get_component::<ShapeData>(shape_data) {
|
|
if sd.center == Some(dot) {
|
|
undo.push(UndoItem::MoveItem { shape: shape_data, from: *held_from, to: snap.snap_to_grid(mouse_pos) });
|
|
}
|
|
else {
|
|
undo.push(UndoItem::MoveDot {
|
|
shape_data,
|
|
dot: sd.edges.iter().position(|e| *e == dot).unwrap_or(0),
|
|
from: *held_from,
|
|
to: snap.snap_to_grid(mouse_pos),
|
|
});
|
|
}
|
|
}
|
|
},
|
|
Holding::Image(e, off) => {
|
|
// ye i know it says MoVeShaPe but really it doesnt matter that much here!
|
|
undo.push(UndoItem::MoveItem { shape: e, from: *held_from, to: snap.snap_to_grid(mouse_pos - off) });
|
|
},
|
|
Holding::None => {},
|
|
}
|
|
*holding = Holding::None; // We just released our sad little dot/shape
|
|
}
|
|
else if let Holding::Shape(se, pe) = *holding {
|
|
if let Ok(sd) = shapes.get_component::<ShapeData>(se) {
|
|
// Middle of a drag :D
|
|
if let Some(ce) = sd.center && ce == pe {
|
|
if let Ok(mut t) = transforms.get_mut(sd.main_shape) {
|
|
t.translation = snap.snap_to_grid(mouse_pos).extend(t.translation.z);
|
|
}
|
|
}
|
|
else if let Ok(mut t) = transforms.get_mut(pe) {
|
|
// Update the dot position
|
|
let gt = gtransforms.get(pe).unwrap();
|
|
let rot = gt.to_scale_rotation_translation().1;
|
|
let ang = rot.to_euler(EulerRot::XYZ).2;
|
|
let delta = Mat2::from_angle(-ang) * (snap.snap_to_grid(mouse_pos) - gt.translation().xy());
|
|
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 = 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
|
|
update_main_shape(&mut paths, &transforms, sd);
|
|
}
|
|
}
|
|
}
|
|
else if let Holding::Image(e, offset) = *holding {
|
|
if let Ok(mut t) = transforms.get_mut(e) {
|
|
t.translation = snap.snap_to_grid(mouse_pos - offset).extend(t.translation.z);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn calc_shape_center_offset(transforms: &Query<&mut Transform>, sd: &ShapeData) -> Vec2 {
|
|
match sd.shape {
|
|
CreateShape::Triangle => {
|
|
assert!(sd.edges.len() == 3);
|
|
|
|
let e1 = transforms.get(sd.edges[0]).unwrap().translation.xy();
|
|
let e2 = transforms.get(sd.edges[1]).unwrap().translation.xy();
|
|
let e3 = transforms.get(sd.edges[2]).unwrap().translation.xy();
|
|
|
|
(e1 + e2 + e3) / 3.0
|
|
},
|
|
CreateShape::Square => {
|
|
assert!(sd.edges.len() == 2);
|
|
|
|
let e1 = transforms.get(sd.edges[0]).unwrap().translation.xy();
|
|
let e2 = transforms.get(sd.edges[1]).unwrap().translation.xy();
|
|
|
|
(e1 + e2) * 0.5
|
|
},
|
|
CreateShape::Circle => {
|
|
if let Ok(gt) = transforms.get(sd.center.unwrap()) {
|
|
gt.translation.xy()
|
|
}
|
|
else {
|
|
Vec2::ZERO
|
|
}
|
|
},
|
|
CreateShape::Capsule => unimplemented!("Capsule is disabled for now"),
|
|
}
|
|
}
|
|
|
|
pub fn update_main_shape(paths: &mut Query<&mut Path>, transforms: &Query<&mut Transform>, sd: &ShapeData) {
|
|
let path = match sd.shape {
|
|
CreateShape::Triangle => {
|
|
assert!(sd.edges.len() == 3);
|
|
assert!(sd.center.is_some());
|
|
|
|
let fp = transforms.get(sd.edges[0]).unwrap().translation.xy();
|
|
let sp = transforms.get(sd.edges[1]).unwrap().translation.xy();
|
|
let tp = transforms.get(sd.edges[2]).unwrap().translation.xy();
|
|
|
|
let shape = shapes::Polygon {
|
|
points: Vec::from([fp, sp, tp]),
|
|
closed: true,
|
|
};
|
|
ShapePath::build_as(&shape)
|
|
},
|
|
CreateShape::Square => {
|
|
assert!(sd.edges.len() == 2);
|
|
assert!(sd.center.is_some());
|
|
|
|
let e1 = transforms.get(sd.edges[0]).unwrap().translation.xy();
|
|
let e2 = transforms.get(sd.edges[1]).unwrap().translation.xy();
|
|
let ext = (e2 - e1).abs();
|
|
|
|
let shape = shapes::Rectangle { extents: ext, origin: RectangleOrigin::Center };
|
|
ShapePath::build_as(&shape)
|
|
},
|
|
CreateShape::Circle => {
|
|
assert!(sd.center.is_some());
|
|
assert!(sd.edges.len() == 1);
|
|
|
|
let center= transforms.get(sd.center.unwrap()).unwrap().translation.xy();
|
|
let edge = transforms.get(sd.edges[0]).unwrap().translation.xy();
|
|
|
|
let shape = shapes::Circle { radius: (edge - center).length(), center: Vec2::ZERO };
|
|
ShapePath::build_as(&shape)
|
|
},
|
|
CreateShape::Capsule => {
|
|
panic!("Capsule creation not implemented yet!");
|
|
},
|
|
};
|
|
if let Ok(mut p) = paths.get_mut(sd.main_shape) {
|
|
*p = path;
|
|
}
|
|
} |