mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-25 02:07:09 -06:00
Draw from centre (Alt) now applies to the typed size of a rectangle or ellipse (#3309)
This commit is contained in:
committed by
bflatastic
parent
b0056a127d
commit
cde39698ff
@@ -201,7 +201,9 @@ impl Tool for ShapeTool {
|
||||
self.began = false;
|
||||
vec![Action::Commit]
|
||||
} else {
|
||||
vec![Action::Dialog(self.id.into(), json!({ "x": s.x, "y": s.y }))]
|
||||
// Alt (draw from centre) is passed on, so the size dialog can centre the shape on the click.
|
||||
let args = if ev.mods.alt { json!({ "x": s.x, "y": s.y, "alt": true }) } else { json!({ "x": s.x, "y": s.y }) };
|
||||
vec![Action::Dialog(self.id.into(), args)]
|
||||
}
|
||||
}
|
||||
_ => vec![],
|
||||
@@ -385,6 +387,21 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn alt_click_passes_draw_from_centre_to_the_dialog() {
|
||||
let (d, _) = doc_with_rect();
|
||||
let s = Selection::default();
|
||||
let p = paint();
|
||||
let cx = cx(&d, &s, &p);
|
||||
let alt = Mods { alt: true, ..Default::default() };
|
||||
let mut t = ShapeTool::new("rectangle");
|
||||
t.pointer(&cx, &PointerEvent::new(PointerKind::Down, 10.0, 10.0).with_mods(alt));
|
||||
assert_eq!(
|
||||
t.pointer(&cx, &PointerEvent::new(PointerKind::Up, 10.0, 10.0).with_mods(alt)),
|
||||
vec![Action::Dialog("rectangle".into(), json!({"x": 10.0, "y": 10.0, "alt": true}))]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn arrow_keys_change_sides() {
|
||||
let (d, _) = doc_with_rect();
|
||||
|
||||
@@ -93,6 +93,16 @@ fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// The top-left corner of a rectangle or ellipse: the click itself, or with Alt held (draw from centre) the click minus half the size.
|
||||
fn box_origin(d: &Dialog) -> (f64, f64) {
|
||||
let (x, y) = (d.f64("x", 0.0), d.f64("y", 0.0));
|
||||
if d.fields.get("alt").and_then(Value::as_bool).unwrap_or(false) {
|
||||
(x - d.f64("width", 100.0) / 2.0, y - d.f64("height", 100.0) / 2.0)
|
||||
} else {
|
||||
(x, y)
|
||||
}
|
||||
}
|
||||
|
||||
fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> Result<Value, String> {
|
||||
let count = match d.kind.as_str() {
|
||||
"polygon" => Some(("sides", 6.0, 3.0)),
|
||||
@@ -105,8 +115,9 @@ fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> Result<Value, String> {
|
||||
values
|
||||
});
|
||||
let (x, y) = (d.f64("x", 0.0), d.f64("y", 0.0));
|
||||
let (bx, by) = box_origin(d);
|
||||
let (id, params) = match d.kind.as_str() {
|
||||
"ellipse" => ("shape.ellipse", json!({"x": x, "y": y, "width": d.f64("width", 100.0), "height": d.f64("height", 100.0)})),
|
||||
"ellipse" => ("shape.ellipse", json!({"x": bx, "y": by, "width": d.f64("width", 100.0), "height": d.f64("height", 100.0)})),
|
||||
"polygon" => ("shape.polygon", json!({"cx": x, "cy": y, "radius": d.f64("radius", 50.0), "sides": d.f64("sides", 6.0) as u64})),
|
||||
"star" => (
|
||||
"shape.star",
|
||||
@@ -131,7 +142,7 @@ fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> Result<Value, String> {
|
||||
}
|
||||
_ => (
|
||||
"shape.rectangle",
|
||||
json!({"x": x, "y": y, "width": d.f64("width", 100.0), "height": d.f64("height", 100.0), "radius": d.f64("radius", 0.0)}),
|
||||
json!({"x": bx, "y": by, "width": d.f64("width", 100.0), "height": d.f64("height", 100.0), "radius": d.f64("radius", 0.0)}),
|
||||
),
|
||||
};
|
||||
// On the active plane while the perspective grid shows, sized in plane units from the click.
|
||||
@@ -145,3 +156,15 @@ fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> Result<Value, String> {
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn alt_click_centres_the_typed_size_on_the_click() {
|
||||
let fields = |alt: bool| Dialog::new("rectangle", json!({"x": 100.0, "y": 50.0, "alt": alt, "width": "40 pt", "height": "20 pt"}));
|
||||
assert_eq!(box_origin(&fields(false)), (100.0, 50.0));
|
||||
assert_eq!(box_origin(&fields(true)), (80.0, 40.0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,9 +11,10 @@ use crate::state::Dialog;
|
||||
pub fn open_tool_dialog(app: &mut VectorcraftApp, kind: &str, p: Value) {
|
||||
let x = p.get("x").and_then(Value::as_f64).unwrap_or(0.0);
|
||||
let y = p.get("y").and_then(Value::as_f64).unwrap_or(0.0);
|
||||
let alt = p.get("alt").and_then(Value::as_bool).unwrap_or(false);
|
||||
let d = match kind {
|
||||
"rectangle" | "ellipse" => Dialog::new(kind, json!({"x": x, "y": y, "width": "100 pt", "height": "100 pt"})),
|
||||
"roundedRectangle" => Dialog::new(kind, json!({"x": x, "y": y, "width": "100 pt", "height": "100 pt", "radius": "12 pt"})),
|
||||
"rectangle" | "ellipse" => Dialog::new(kind, json!({"x": x, "y": y, "alt": alt, "width": "100 pt", "height": "100 pt"})),
|
||||
"roundedRectangle" => Dialog::new(kind, json!({"x": x, "y": y, "alt": alt, "width": "100 pt", "height": "100 pt", "radius": "12 pt"})),
|
||||
"polygon" => Dialog::new(kind, json!({"x": x, "y": y, "radius": "50 pt", "sides": app.session.tool_options_of(kind)["sides"]})),
|
||||
"star" => {
|
||||
Dialog::new(kind, json!({"x": x, "y": y, "radius1": "50 pt", "radius2": "25 pt", "points": app.session.tool_options_of(kind)["points"]}))
|
||||
|
||||
Reference in New Issue
Block a user