Skip to content

Commit

Permalink
Fixing handle drag selection priorities
Browse files Browse the repository at this point in the history
  • Loading branch information
ecton committed Aug 31, 2024
1 parent 09b32c2 commit 7af6ed6
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 35 deletions.
57 changes: 35 additions & 22 deletions src/cushy/skeleton_canvas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use crate::{Angle, BoneEnd, BoneId, Coordinate, JointId, Skeleton, Vector};
use cushy::{
context::{EventContext, GraphicsContext, LayoutContext},
figures::{
units::{Px, UPx},
FloatConversion, IntoComponents, Point, Round, Size,
units::{Lp, Px, UPx},
FloatConversion, IntoComponents, Point, Round, ScreenScale, Size,
},
kludgine::{
app::winit::{event::MouseButton, window::CursorIcon},
Expand All @@ -25,6 +25,7 @@ pub struct SkeletonCanvas {
skeleton: Dynamic<Skeleton>,
hovering: Option<Target>,
scale: f32,
handle_size: f32,
maximum_scale: f32,
offset: Point<Px>,
drag: Option<DragInfo>,
Expand All @@ -37,6 +38,7 @@ impl SkeletonCanvas {
Self {
skeleton,
hovering: None,
handle_size: 0.1,
scale: f32::MAX,
maximum_scale: 0.,
offset: Point::default(),
Expand Down Expand Up @@ -108,6 +110,9 @@ impl Widget for SkeletonCanvas {
if self.scale > self.maximum_scale {
self.scale = self.maximum_scale;
}
let handle_size = Lp::mm(2).into_px(context.gfx.scale()).ceil();
self.handle_size = handle_size.into_float() / self.scale;

let root = root_start * self.scale;

self.offset = (middle - root).to_vec::<Point<f32>>().map(Px::from).floor();
Expand All @@ -118,7 +123,7 @@ impl Widget for SkeletonCanvas {
let path = if let Some(joint) = bone.solved_joint() {
let joint = self.vector_position(joint);
context.gfx.draw_shape(
Shape::filled_circle(Px::new(4), Color::WHITE, Origin::Center)
Shape::filled_circle(handle_size / 2, Color::WHITE, Origin::Center)
.translate_by(joint),
);
PathBuilder::new(self.vector_position(bone.start()))
Expand All @@ -131,15 +136,18 @@ impl Widget for SkeletonCanvas {
.build()
};
let (selected, stroke) = match selected {
Some(Target::DesiredEnd(id)) if id == bone.id() => {
(true, StrokeOptions::px_wide(2).colored(Color::RED))
}
Some(Target::Joint(joint)) if skeleton[joint].bone_b == bone.id().axis_a() => {
(true, StrokeOptions::px_wide(2).colored(Color::RED))
}
Some(Target::Joint(joint)) if skeleton[joint].bone_a.bone == bone.id() => {
(false, StrokeOptions::px_wide(2).colored(Color::BLUE))
}
Some(Target::DesiredEnd(id)) if id == bone.id() => (
true,
StrokeOptions::px_wide(handle_size / 2).colored(Color::RED),
),
Some(Target::Joint(joint)) if skeleton[joint].bone_b == bone.id().axis_a() => (
true,
StrokeOptions::px_wide(handle_size / 2).colored(Color::RED),
),
Some(Target::Joint(joint)) if skeleton[joint].bone_a.bone == bone.id() => (
false,
StrokeOptions::px_wide(handle_size / 2).colored(Color::BLUE),
),
_ => (false, StrokeOptions::px_wide(1).colored(Color::WHITE)),
};
context.gfx.draw_shape(&path.stroke(stroke));
Expand All @@ -155,7 +163,7 @@ impl Widget for SkeletonCanvas {
let end = self.vector_position(end);

context.gfx.draw_shape(
Shape::filled_circle(Px::new(10), stroke.color, Origin::Center)
Shape::filled_circle(handle_size, stroke.color, Origin::Center)
.translate_by(end),
);
}
Expand All @@ -173,21 +181,22 @@ impl Widget for SkeletonCanvas {
fn hover(&mut self, location: Point<Px>, context: &mut EventContext<'_>) -> Option<CursorIcon> {
let location = self.position_to_vector(location);
let skeleton = self.skeleton.read();
let mut closest_match = 0.1;
let mut closest_match = self.handle_size;
let current_hover = self.hovering.take();
for bone in skeleton.bones() {
let mut distance = (location - bone.end()).magnitude() / 10.;
let mut distance = (location - bone.end()).magnitude();
if let Some(mid) = bone.solved_joint() {
// This can have its desired_end set
distance = distance.min(
distance_to_line(location, bone.start(), mid).min(distance_to_line(
location,
mid,
bone.end(),
)),
distance_to_line(location, bone.start(), mid)
.min(distance_to_line(location, mid, bone.end()))
.max(self.handle_size / 10.)
* 5.0,
);
if let Some(desired_end) = bone.desired_end() {
distance = distance.min((location - desired_end).magnitude());
distance = distance.min(
(location - bone.start() - (desired_end + bone.entry_angle())).magnitude(),
);
}

if distance < closest_match {
Expand All @@ -196,7 +205,11 @@ impl Widget for SkeletonCanvas {
}
} else if !bone.is_root() {
// Single line segment
let distance = distance_to_line(location, bone.start(), bone.end());
distance = distance.min(
distance_to_line(location, bone.start(), bone.end())
.max(self.handle_size / 10.)
* 5.0,
);
if distance < closest_match {
closest_match = distance;
// For a non-jointed bone, interacting with it adjusts the
Expand Down
12 changes: 0 additions & 12 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -542,13 +542,6 @@ impl Skeleton {
continue;
};

println!(
"Solving {axis:?} - {}",
self.bones[axis.bone.index()]
.label
.as_ref()
.map_or("", |s| s)
);
for joint_id in connections {
let joint = &mut self.joints[joint_id.index()];
let other_axis = joint.other_axis(axis);
Expand All @@ -559,11 +552,6 @@ impl Skeleton {
// each bone a single time.
continue;
}
println!(
"{joint_id:?}{} -> {other_axis:?}{} at {current_rotation}",
joint.label.as_ref().map_or("", |s| s),
bone.label.as_ref().map_or("", |s| s)
);
bone.generation = self.generation;
bone.entry_angle = current_rotation;
bone.start = current_position;
Expand Down
2 changes: 1 addition & 1 deletion src/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ fn roundtrip() {
other.axis_b(),
));
let serialized = pot::to_vec(&s).unwrap();
let deserialized: Skeleton = dbg!(pot::from_slice(&serialized).unwrap());
let deserialized: Skeleton = pot::from_slice(&serialized).unwrap();
assert_eq!(deserialized[spine].label(), "spine");
assert_eq!(deserialized[other].label(), "");
assert_eq!(deserialized[joint].angle(), Angle::radians(0.));
Expand Down

0 comments on commit 7af6ed6

Please sign in to comment.