mirror of
https://github.com/storytold/figcraft.git
synced 2026-11-12 21:34:31 +00:00
M1: Set default properties gives new shapes and text the layer's properties (#2028)
Edit ▸ Set default properties put the selected layer's properties into the Paste properties
clipboard and did nothing else: a rectangle drawn afterwards was still the default grey, and what
Copy properties had copied was replaced.
The defaults are now kept apart (`Session::default_props`: one set for shapes, set from any layer
but text, and one for text). Rectangles, ellipses, polygons and stars drawn or clicked with their
tools take the shape defaults: fills, strokes and their settings, effects, opacity, blend and
corners (only where the shape has corners), through `apply_copied_props`, the rules Paste
properties already used (now shared). New text from the Text tool takes a text layer's fills and
font and is laid out at that size. Frames, sections, slices, lines, arrows, vectors and layers made
by commands keep their own look; the help center is silent on those. `edit.setDefaultProperties`
answers `{for: shapes|text, properties}`.
Tests: `default_props_tests::new_shapes_drawn_with_the_tools_take_the_default_properties`,
`setting_defaults_leaves_the_copied_properties_alone`,
`new_text_takes_a_text_layers_defaults_and_shapes_keep_theirs`. Docs: ui-parity.md, ROADMAP.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LvG6E2LxvJ6MuFmiLA6Zqm
This commit is contained in:
1 parent
8eb0b87646
commit
20f1219fbc
10 files changed
+200
-24
No files matched your search
@@ -17,6 +17,7 @@ mod clipboard;
|
||||
mod props;
|
||||
mod select;
|
||||
|
||||
pub(crate) use clipboard::apply_copied_props;
|
||||
pub use clipboard::{CLIP_CLOSE, CLIP_OPEN, copy_to_clipboard, design_clipboard_buffer, paste_into};
|
||||
use clipboard::{copy, copy_props, copy_props_of, cut, paste, paste_design_layers, paste_over, paste_props, paste_replace};
|
||||
use props::{
|
||||
@@ -142,12 +143,26 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
true,
|
||||
find_replace
|
||||
),
|
||||
spec!("edit.setDefaultProperties", "Set default properties", "{id?}", false, |s, p| {
|
||||
let id = targets(s, p).first().copied().ok_or_else(|| bad("edit.setDefaultProperties", "select a layer"))?;
|
||||
let v = copy_props_of(s.doc()?, id);
|
||||
s.clipboard.props = Some(v);
|
||||
ok()
|
||||
}),
|
||||
spec!(
|
||||
"edit.setDefaultProperties",
|
||||
"Set default properties",
|
||||
"{id?} the layer's fills, strokes, effects, opacity and corners (a text layer's: also its font) become what new rectangles, ellipses, polygons and stars (or, from a text layer, new text) drawn with the tools take → {for: shapes|text, properties}",
|
||||
false,
|
||||
|s, p| {
|
||||
let id = targets(s, p).first().copied().ok_or_else(|| bad("edit.setDefaultProperties", "select a layer"))?;
|
||||
let doc = s.doc()?;
|
||||
let text = matches!(doc.get(id)?.kind, NodeKind::Text(_));
|
||||
let v = copy_props_of(doc, id);
|
||||
let kind = if text {
|
||||
s.default_props.text = Some(v.clone());
|
||||
"text"
|
||||
} else {
|
||||
s.default_props.shape = Some(v.clone());
|
||||
"shapes"
|
||||
};
|
||||
Ok(json!({"for": kind, "properties": v}))
|
||||
}
|
||||
),
|
||||
spec!("select.set", "Select", "{ids: [..]} (replace the selection)", false, |s, p| {
|
||||
let ids = match get(p, "ids") {
|
||||
Some(Value::Array(a)) => a.iter().filter_map(id_of).collect(),
|
||||
|
||||
@@ -357,21 +357,27 @@ pub(super) fn copy_props(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
/// Give layer `id` the properties [`copy_props_of`] copied (`props`), those it can take: the text
|
||||
/// properties only to text, the corners only to a layer with corners.
|
||||
pub(crate) fn apply_copied_props(cmd: &str, doc: &mut Document, id: NodeId, props: &Value) -> Result<()> {
|
||||
let mut m = props.as_object().cloned().unwrap_or_default();
|
||||
let is_text = matches!(doc.get(id)?.kind, NodeKind::Text(_));
|
||||
if !is_text {
|
||||
m.retain(|k, _| !k.starts_with("font") && k != "lineHeight" && k != "letterSpacing");
|
||||
}
|
||||
if !doc.get(id)?.kind.has_corner_radius() {
|
||||
m.remove("cornerRadius");
|
||||
m.remove("cornerSmoothing");
|
||||
}
|
||||
crate::cmd::props::apply(cmd, doc, id, &m)
|
||||
}
|
||||
|
||||
pub(super) fn paste_props(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let props = s.clipboard.props.clone().ok_or_else(|| EngineError::Disabled("edit.pasteProperties".into(), "no copied properties".into()))?;
|
||||
let ids = req_targets("edit.pasteProperties", s, p)?;
|
||||
let doc = s.doc_mut()?;
|
||||
for i in ids {
|
||||
let mut m = props.as_object().cloned().unwrap_or_default();
|
||||
let is_text = matches!(doc.get(i)?.kind, NodeKind::Text(_));
|
||||
if !is_text {
|
||||
m.retain(|k, _| !k.starts_with("font") && k != "lineHeight" && k != "letterSpacing");
|
||||
}
|
||||
if !doc.get(i)?.kind.has_corner_radius() {
|
||||
m.remove("cornerRadius");
|
||||
m.remove("cornerSmoothing");
|
||||
}
|
||||
crate::cmd::props::apply("edit.pasteProperties", doc, i, &m)?;
|
||||
apply_copied_props("edit.pasteProperties", doc, i, &props)?;
|
||||
}
|
||||
ok()
|
||||
}
|
||||
Reference in new issue
Block a user