mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-07 15:51:56 +00:00
Merge pull request #5586 from dotCooCoo/fix/text-tweaker-range
Text Tweaker: align byte ranges to character boundaries
This commit is contained in:
@@ -46,7 +46,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
"Text Tweaker",
|
||||
["Object", "Plug-ins", "Type Tools"],
|
||||
None,
|
||||
"{attribute?: \"size\" (pt 0.1..1296) | \"baselineShift\" (pt −1296..1296) | \"rotation\" (° −360..360) | \"hScale\" (% 1..10000) | \"vScale\" (% 1..10000) | \"tracking\" (1/1000 em −1000..10000) | \"leading\" (pt 0.1..5000) | \"strokeWidth\" (pt 0..1000) (\"size\"), from?: the first character's value, to?: the last character's value (each in the attribute's units and range; defaults: size 12 → 36, baselineShift 0 → 12, rotation 0 → 30, hScale and vScale 100 → 150, tracking 0 → 200, leading 12 → 36, strokeWidth 0 → 2), shape?: \"straight\" (an even ramp) | \"ease\" (slow at both ends) | \"bow\" (from at both ends, rising smoothly to `to` in the middle) | \"spike\" (from at both ends, straight up to `to` in the middle) | \"random\" (each character anywhere from `from` to `to`) (\"straight\"), seed?: whole number (0; random: the same seed and text give the same values), skipSpaces?: true (spaces and line breaks keep their values and don't count), id?, start?: byte, end?: byte, ids?: [id…] (instead of id)} give the characters one character attribute letter by letter, from `from` to `to` along the shape, as the Character panel sets it, as one undo step; the text stays live and editable. The range of `id`, else the type objects in `ids`, else the text the Type tool has selected (at a caret: all its text), else every selected type object; each object gets its own ramp. Stroke weight only shows on characters with a stroke → {count (characters changed), ids}",
|
||||
"{attribute?: \"size\" (pt 0.1..1296) | \"baselineShift\" (pt −1296..1296) | \"rotation\" (° −360..360) | \"hScale\" (% 1..10000) | \"vScale\" (% 1..10000) | \"tracking\" (1/1000 em −1000..10000) | \"leading\" (pt 0.1..5000) | \"strokeWidth\" (pt 0..1000) (\"size\"), from?: the first character's value, to?: the last character's value (each in the attribute's units and range; defaults: size 12 → 36, baselineShift 0 → 12, rotation 0 → 30, hScale and vScale 100 → 150, tracking 0 → 200, leading 12 → 36, strokeWidth 0 → 2), shape?: \"straight\" (an even ramp) | \"ease\" (slow at both ends) | \"bow\" (from at both ends, rising smoothly to `to` in the middle) | \"spike\" (from at both ends, straight up to `to` in the middle) | \"random\" (each character anywhere from `from` to `to`) (\"straight\"), seed?: whole number (0; random: the same seed and text give the same values), skipSpaces?: true (spaces and line breaks keep their values and don't count), id?, start?: byte, end?: byte (range endpoints inside a character round down to its start), ids?: [id…] (instead of id)} give the characters one character attribute letter by letter, from `from` to `to` along the shape, as the Character panel sets it, as one undo step; the text stays live and editable. The range of `id`, else the type objects in `ids`, else the text the Type tool has selected (at a caret: all its text), else every selected type object; each object gets its own ramp. Stroke weight only shows on characters with a stroke → {count (characters changed), ids}",
|
||||
has_selection,
|
||||
text_tweaker
|
||||
)]
|
||||
@@ -97,6 +97,7 @@ fn text_tweaker(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
for (id, a, b, _) in ranges {
|
||||
let t = text_ref(s, id)?;
|
||||
let text = t.plain_text();
|
||||
let (a, b) = (edit::floor_char(&text, a), edit::floor_char(&text, b));
|
||||
let chars: Vec<usize> =
|
||||
text.char_indices().filter(|&(i, c)| (a..b).contains(&i) && !(skip && (c.is_whitespace() || c.is_control()))).map(|(i, _)| i).collect();
|
||||
seen += chars.len();
|
||||
|
||||
@@ -124,6 +124,16 @@ fn a_range_changes_only_its_characters() {
|
||||
assert_eq!(tracking, [0.0, 100.0, 200.0, 300.0, 0.0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_range_inside_a_multibyte_character_uses_character_boundaries() {
|
||||
let mut s = session();
|
||||
let id = text(&mut s, "éx");
|
||||
let out = s.execute(C, &json!({"id": id.0, "start": 1, "end": 2, "attribute": "tracking", "from": 100, "to": 300})).unwrap();
|
||||
assert_eq!(out["count"], 1);
|
||||
let tracking: Vec<f64> = styles(&s, id).iter().map(|(_, st)| st.tracking).collect();
|
||||
assert_eq!(tracking, [100.0, 0.0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_values_stay_in_range_and_repeat_with_the_seed() {
|
||||
let mut s = session();
|
||||
|
||||
@@ -6921,6 +6921,7 @@ type it is the size shown.
|
||||
It changes the range of `id` (`start`/`end` bytes), else all the text of the type objects in `ids`, else the text the
|
||||
Type tool has selected (at a caret: all of that object's text), else all the text of every selected type object; each
|
||||
object gets its own ramp, and at most 100000 characters change in one run. A run that changes nothing makes no step.
|
||||
A `start` or `end` byte inside a character rounds down to that character's start.
|
||||
|
||||
| Parameter | Values (default) |
|
||||
|---|---|
|
||||
|
||||
Reference in New Issue
Block a user