mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-09 09:29:44 -06:00
Merge pull request #5224 from dotCooCoo/feat/select-same-link-block-series
Select: Same › Link Block Series selects every frame of a text thread
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
//! brush strokes, Save/recall selections), View → Guides, and File → Close All / Document Color
|
||||
//! Mode / File Info.
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
use std::collections::{BTreeSet, HashMap, HashSet};
|
||||
use std::sync::Arc;
|
||||
|
||||
use serde_json::{Value, json};
|
||||
@@ -11,7 +11,7 @@ use vectorcraft_geom::Vec2;
|
||||
|
||||
use super::edit::selected_roots;
|
||||
use super::pathops::Beside;
|
||||
use super::select::{selectable_ids, walk_selectable};
|
||||
use super::select::{is_selectable, selectable_ids, walk_selectable};
|
||||
use super::{
|
||||
CommandSpec, EngineError, Point, Result, Session, bad, bool_or, checked_ids_param, cmd, f64_or, f64_req, has_doc, has_selection, id_param, ok,
|
||||
str_param,
|
||||
@@ -27,6 +27,15 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
_ => false,
|
||||
}
|
||||
)),
|
||||
cmd!(
|
||||
"select.same.linkBlockSeries",
|
||||
"Link Block Series",
|
||||
["Select", "Same"],
|
||||
None,
|
||||
"{} select every frame of the threads of the selected type objects (and of the type inside selected groups); type in no thread selects itself; type and frames that are hidden or locked, inside a hidden or locked object or layer, on a template layer, or outside the isolated group or layer neither count as selected nor are selected → {count}",
|
||||
has_text_selection,
|
||||
same_link_block_series
|
||||
),
|
||||
cmd!("select.same.fontFamily", "Font Family", ["Select", "Same"], None, "{} → {count}", has_selection, |s, _| same_text(
|
||||
s,
|
||||
"select.same.fontFamily",
|
||||
@@ -313,6 +322,84 @@ fn same_text(s: &mut Session, cmd: &str, eq: fn(&CharStyle, &CharStyle) -> bool)
|
||||
finish_same(s, cmd, ids)
|
||||
}
|
||||
|
||||
/// Call `f` with each type object among the selected objects and inside them, in selection order,
|
||||
/// keeping only those [`walk_selectable`] visits: none that is hidden, locked, on a hidden, locked
|
||||
/// or template layer, or outside the isolated group. A type object inside two selected objects is
|
||||
/// given twice. The walk stops when `f` returns false.
|
||||
fn each_selected_text(s: &Session, mut f: impl FnMut(NodeId) -> bool) {
|
||||
fn inside(n: &Node, f: &mut impl FnMut(NodeId) -> bool) -> bool {
|
||||
if !n.visible || n.locked {
|
||||
return true;
|
||||
}
|
||||
if matches!(n.kind, NodeKind::Text(_)) && !f(n.id) {
|
||||
return false;
|
||||
}
|
||||
n.children().into_iter().flatten().all(|c| inside(c, f))
|
||||
}
|
||||
let Some(st) = s.active() else { return };
|
||||
let locks = st.doc.locked_artboards();
|
||||
for id in &st.selection.objects {
|
||||
if is_selectable(&st.doc, st.isolation, &locks, *id)
|
||||
&& let Some(n) = st.doc.node(*id)
|
||||
&& !inside(n, &mut f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The type objects [`each_selected_text`] gives, each once, in selection order.
|
||||
fn selected_text(s: &Session) -> Vec<NodeId> {
|
||||
let (mut out, mut seen) = (vec![], HashSet::new());
|
||||
each_selected_text(s, |id| {
|
||||
if seen.insert(id) {
|
||||
out.push(id);
|
||||
}
|
||||
true
|
||||
});
|
||||
out
|
||||
}
|
||||
|
||||
/// A type object is selected, or is inside a selected object.
|
||||
fn has_text_selection(s: &Session) -> std::result::Result<(), String> {
|
||||
has_selection(s)?;
|
||||
let mut any = false;
|
||||
each_selected_text(s, |_| {
|
||||
any = true;
|
||||
false
|
||||
});
|
||||
if any { Ok(()) } else { Err("select a text object".into()) }
|
||||
}
|
||||
|
||||
/// Select › Same › Link Block Series: the frames of the threads the selected type objects are
|
||||
/// in, in thread order; a type object in no thread is its own series.
|
||||
fn same_link_block_series(s: &mut Session, _: &Value) -> Result<Value> {
|
||||
const C: &str = "select.same.linkBlockSeries";
|
||||
let seeds = selected_text(s);
|
||||
if seeds.is_empty() {
|
||||
return Err(bad(C, "select a text object"));
|
||||
}
|
||||
let st = s.doc()?;
|
||||
let can = selectable_ids(&st.doc, st.isolation);
|
||||
// Each frame's thread: the first thread that lists it.
|
||||
let mut threads: HashMap<NodeId, &[NodeId]> = HashMap::new();
|
||||
for t in &st.doc.text_threads {
|
||||
for id in t {
|
||||
threads.entry(*id).or_insert(t.as_slice());
|
||||
}
|
||||
}
|
||||
let (mut ids, mut seen): (Vec<NodeId>, HashSet<NodeId>) = (vec![], HashSet::new());
|
||||
for seed in &seeds {
|
||||
let series = threads.get(seed).copied().unwrap_or(std::slice::from_ref(seed));
|
||||
for id in series {
|
||||
if can.contains(id) && seen.insert(*id) {
|
||||
ids.push(*id);
|
||||
}
|
||||
}
|
||||
}
|
||||
finish_same(s, C, ids)
|
||||
}
|
||||
|
||||
fn by_kind(s: &mut Session, f: impl Fn(&Node) -> bool) -> Result<Value> {
|
||||
let ids = candidates(s, f)?;
|
||||
s.select(|_, sel| sel.set(ids))?;
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::collections::BTreeSet;
|
||||
|
||||
use serde_json::{Value, json};
|
||||
use vectorcraft_color::Paint;
|
||||
use vectorcraft_doc::{Document, Node, NodeId, NodeKind};
|
||||
use vectorcraft_doc::{Document, LockedArtboards, Node, NodeId, NodeKind};
|
||||
use vectorcraft_tools::builder::is_live_paint;
|
||||
|
||||
use super::wand::{fill_of, stroke_of};
|
||||
@@ -249,6 +249,24 @@ pub(crate) fn selectable_ids(d: &Document, iso: Option<NodeId>) -> BTreeSet<Node
|
||||
ids
|
||||
}
|
||||
|
||||
/// Whether [`walk_selectable`] visits `id`, read from the objects that hold it instead of a walk of
|
||||
/// the document. `locks` is the document's [`Document::locked_artboards`].
|
||||
pub(crate) fn is_selectable(d: &Document, iso: Option<NodeId>, locks: &LockedArtboards, id: NodeId) -> bool {
|
||||
let Some(a) = d.ancestry(id) else { return false };
|
||||
if !a.iter().all(|i| d.node(*i).is_some_and(|n| n.visible && !n.locked && !n.is_template())) {
|
||||
return false;
|
||||
}
|
||||
match iso.and_then(|i| d.node(i)) {
|
||||
// Inside the isolated container, or the single object isolated.
|
||||
Some(c) => a.iter().position(|i| *i == c.id).is_some_and(|p| p + 1 < a.len() || !c.is_container()),
|
||||
None => {
|
||||
// The object Select All takes: the outermost one that is not a layer.
|
||||
let top = a.iter().filter_map(|i| d.node(*i)).find(|n| !n.is_layer());
|
||||
top.is_some_and(|t| locks.is_empty() || !locks.holds(t))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn all(s: &mut Session, _: &Value) -> Result<Value> {
|
||||
// While the Type tool edits text, Select All takes all of that text and leaves the art
|
||||
// selection as it is (Illustrator: text cursor in a text object).
|
||||
|
||||
@@ -1948,6 +1948,69 @@ fn select_same_font_size_and_fill() {
|
||||
assert!(s.execute("select.same.fontSize", &json!({})).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn select_same_link_block_series_selects_the_frames_of_a_thread() {
|
||||
let mut s = session();
|
||||
let frame = |s: &mut Session, x: f64, y: f64| {
|
||||
id_of(&s.execute("text.create", &json!({"x": x, "y": y, "text": "words ".repeat(40), "area": {"width": 80, "height": 30}})).unwrap())
|
||||
};
|
||||
let (a, b, c) = (frame(&mut s, 10.0, 10.0), frame(&mut s, 110.0, 10.0), frame(&mut s, 210.0, 10.0));
|
||||
sel(&mut s, &[a, b, c]);
|
||||
s.execute("text.thread.create", &json!({})).unwrap();
|
||||
let (d, e) = (frame(&mut s, 10.0, 200.0), frame(&mut s, 110.0, 200.0));
|
||||
sel(&mut s, &[d, e]);
|
||||
s.execute("text.thread.create", &json!({})).unwrap();
|
||||
let lone = text(&mut s, "alone");
|
||||
let r = rect(&mut s, 300.0, 300.0, 10.0, 10.0);
|
||||
let undo = s.doc().unwrap().history.undo.len();
|
||||
// The middle frame of the first thread selects that thread's three frames, in thread order.
|
||||
sel(&mut s, &[b]);
|
||||
assert_eq!(s.execute("select.same.linkBlockSeries", &json!({})).unwrap()["count"], 3);
|
||||
assert_eq!(selected(&s), vec![a, b, c]);
|
||||
// Frames of two threads select both threads.
|
||||
sel(&mut s, &[c, e]);
|
||||
assert_eq!(s.execute("select.same.linkBlockSeries", &json!({})).unwrap()["count"], 5);
|
||||
// Type in no thread selects itself; a path beside it is left out.
|
||||
sel(&mut s, &[lone, r]);
|
||||
assert_eq!(s.execute("select.same.linkBlockSeries", &json!({})).unwrap()["count"], 1);
|
||||
assert_eq!(selected(&s), vec![lone]);
|
||||
assert_eq!(s.doc().unwrap().history.undo.len(), undo, "selecting adds no undo step");
|
||||
// With no type selected the command is not available.
|
||||
sel(&mut s, &[r]);
|
||||
assert!(s.execute("select.same.linkBlockSeries", &json!({})).is_err());
|
||||
// A selected group counts the type inside it, but not hidden or locked type.
|
||||
let box_ = rect(&mut s, 400.0, 400.0, 10.0, 10.0);
|
||||
sel(&mut s, &[d, box_]);
|
||||
let g = id_of(&s.execute("object.group", &json!({})).unwrap());
|
||||
sel(&mut s, &[g]);
|
||||
assert!(find_command("select.same.linkBlockSeries").unwrap().info(&s).enabled);
|
||||
assert_eq!(s.execute("select.same.linkBlockSeries", &json!({})).unwrap()["count"], 2);
|
||||
assert_eq!(selected(&s), vec![d, e]);
|
||||
for props in [json!({"id": d.0, "visible": false}), json!({"id": d.0, "visible": true, "locked": true})] {
|
||||
s.execute("layer.setProps", &props).unwrap();
|
||||
sel(&mut s, &[g]);
|
||||
assert!(!find_command("select.same.linkBlockSeries").unwrap().info(&s).enabled, "{props}");
|
||||
assert!(s.execute("select.same.linkBlockSeries", &json!({})).is_err(), "{props}");
|
||||
assert_eq!(selected(&s), vec![g], "{props}");
|
||||
}
|
||||
s.execute("layer.setProps", &json!({"id": d.0, "locked": false})).unwrap();
|
||||
// A frame on a hidden layer, selected by id, is not type to start from.
|
||||
let l1 = s.doc().unwrap().doc.layers[0].id;
|
||||
s.execute("layer.setProps", &json!({"id": l1.0, "visible": false})).unwrap();
|
||||
sel(&mut s, &[a]);
|
||||
assert!(!find_command("select.same.linkBlockSeries").unwrap().info(&s).enabled);
|
||||
assert!(s.execute("select.same.linkBlockSeries", &json!({})).is_err());
|
||||
s.execute("layer.setProps", &json!({"id": l1.0, "visible": true})).unwrap();
|
||||
// In an isolated group, only the frames inside it count and are selected.
|
||||
s.execute("object.isolate", &json!({"id": g.0})).unwrap();
|
||||
sel(&mut s, &[d]);
|
||||
assert_eq!(s.execute("select.same.linkBlockSeries", &json!({})).unwrap()["count"], 1);
|
||||
assert_eq!(selected(&s), vec![d]);
|
||||
sel(&mut s, &[a]);
|
||||
assert!(!find_command("select.same.linkBlockSeries").unwrap().info(&s).enabled);
|
||||
assert!(s.execute("select.same.linkBlockSeries", &json!({})).is_err());
|
||||
}
|
||||
|
||||
/// #1737: Select > Same reads type's fill and stroke from its characters (the first run), so type
|
||||
/// matches type and paths both ways.
|
||||
#[test]
|
||||
|
||||
@@ -3270,6 +3270,7 @@ digits Malayalam Малаялам
|
||||
Graphic Графика
|
||||
Show all open documents Показване на всички отворени документи
|
||||
Symbol Instance Екземпляр на символ
|
||||
Link Block Series Серия свързани блокове
|
||||
Symbol Libraries Библиотеки със символи
|
||||
Symbol Screener Tool Инструмент „Филтър на символи“
|
||||
Symbol Scruncher Tool Инструмент „Свиване на символи“
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -418,6 +418,7 @@
|
||||
Stroke Weight Debljina poteza
|
||||
Graphic Style Grafički stil
|
||||
Symbol Instance Instanca simbola
|
||||
Link Block Series Niz povezanih blokova
|
||||
Font Family Porodica fonta
|
||||
Font Family & Style Porodica i stil fonta
|
||||
Font Family, Style & Size Porodica, stil i veličina fonta
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4156,6 +4156,7 @@ digits Malayalam Malaiàlam
|
||||
Switch x/y Intercanvia x/y
|
||||
Symbol Símbol
|
||||
Symbol Instance Instància de símbol
|
||||
Link Block Series Sèrie de blocs enllaçats
|
||||
Symbol Libraries Biblioteques de símbols
|
||||
Symbol Libraries Menu Menú de biblioteques de símbols
|
||||
Symbol Library Biblioteca de símbols
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -426,6 +426,7 @@
|
||||
Stroke Weight Tloušťka tahu
|
||||
Graphic Style Grafický styl
|
||||
Symbol Instance Instance symbolu
|
||||
Link Block Series Řada propojených bloků
|
||||
Font Family Rodina písma
|
||||
Font Family & Style Rodina a řez písma
|
||||
Font Family, Style & Size Rodina, řez a velikost písma
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -385,6 +385,7 @@
|
||||
Stroke Weight Stregtykkelse
|
||||
Graphic Style Grafisk stil
|
||||
Symbol Instance Symbolforekomst
|
||||
Link Block Series Serie af sammenkædede blokke
|
||||
Font Family Skrifttypefamilie
|
||||
Font Family & Style Skrifttypefamilie og -stil
|
||||
Font Family, Style & Size Skrifttypefamilie, stil og størrelse
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3298,6 +3298,7 @@ effect Points Punkte
|
||||
Graphic Grafik
|
||||
Show all open documents Alle geöffneten Dokumente anzeigen
|
||||
Symbol Instance Symbolinstanz
|
||||
Link Block Series Reihe verketteter Blöcke
|
||||
Symbol Libraries Symbol-Bibliotheken
|
||||
Symbol Screener Tool Symbol-transparent-gestalten-Werkzeug
|
||||
Symbol Scruncher Tool Symbol-stauchen-Werkzeug
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3697,6 +3697,7 @@ digits Malayalam Μαλαγιάλαμ
|
||||
Graphic Γραφικό
|
||||
Show all open documents Εμφάνιση όλων των ανοιχτών εγγράφων
|
||||
Symbol Instance Στιγμιότυπο συμβόλου
|
||||
Link Block Series Σειρά συνδεδεμένων μπλοκ
|
||||
Symbol Libraries Βιβλιοθήκες συμβόλων
|
||||
Symbol Screener Tool Αραίωση συμβόλων (Symbol Screener Tool)
|
||||
Symbol Scruncher Tool Σύμπτυξη συμβόλων (Symbol Scruncher Tool)
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 163 and column 5.
|
@@ -3354,6 +3354,7 @@ digits Malayalam Malayálam
|
||||
Graphic Gráfico
|
||||
Show all open documents Mostrar todos los documentos abiertos
|
||||
Symbol Instance Instancia de símbolo
|
||||
Link Block Series Serie de bloques enlazados
|
||||
Symbol Libraries Bibliotecas de símbolos
|
||||
Symbol Screener Tool Herramienta Transparencia de símbolos
|
||||
Symbol Scruncher Tool Herramienta Concentración de símbolos
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -423,6 +423,7 @@
|
||||
Stroke Weight Viivan paksuus
|
||||
Graphic Style Grafiikkatyyli
|
||||
Symbol Instance Symbolin ilmentymä
|
||||
Link Block Series Linkitettyjen lohkojen sarja
|
||||
Font Family Fonttiperhe
|
||||
Font Family & Style Fonttiperhe ja tyyli
|
||||
Font Family, Style & Size Fonttiperhe, tyyli ja koko
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3346,6 +3346,7 @@ digits Malayalam Malayalam
|
||||
Graphic Graphique
|
||||
Show all open documents Afficher tous les documents ouverts
|
||||
Symbol Instance Instance de symbole
|
||||
Link Block Series Série de blocs liés
|
||||
Symbol Libraries Bibliothèques de symboles
|
||||
Symbol Screener Tool Outil Transparence de symboles
|
||||
Symbol Scruncher Tool Outil Espacement de symboles
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3988,6 +3988,7 @@ mark-style Japanese Japán
|
||||
Switch workspace Munkaterület váltása
|
||||
Symbol Szimbólum
|
||||
Symbol Instance Szimbólumpéldány
|
||||
Link Block Series Csatolt blokkok sorozata
|
||||
Symbol Libraries Szimbólumkönyvtárak
|
||||
Symbol Screener Tool Szimbólumhalványító
|
||||
Symbol Scruncher Tool Szimbólumtömörítő
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -385,6 +385,7 @@
|
||||
Stroke Weight Ketebalan stroke
|
||||
Graphic Style Gaya grafis
|
||||
Symbol Instance Instans simbol
|
||||
Link Block Series Rangkaian blok tertaut
|
||||
Font Family Keluarga font
|
||||
Font Family & Style Keluarga & gaya font
|
||||
Font Family, Style & Size Keluarga, gaya & ukuran font
|
||||
|
||||
|
@@ -3390,6 +3390,7 @@ digits Malayalam Malayalam
|
||||
Graphic Grafica
|
||||
Show all open documents Mostra tutti i documenti aperti
|
||||
Symbol Instance Istanza di simbolo
|
||||
Link Block Series Serie di blocchi collegati
|
||||
Symbol Libraries Librerie simboli
|
||||
Symbol Screener Tool Strumento Trasparenza simboli
|
||||
Symbol Scruncher Tool Strumento Addensamento simboli
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -455,6 +455,7 @@ digits Malayalam マラヤーラム数字
|
||||
Stroke Weight 線幅
|
||||
Graphic Style グラフィックスタイル
|
||||
Symbol Instance シンボルインスタンス
|
||||
Link Block Series 連結ブロックの系列
|
||||
Font Family フォントファミリー
|
||||
Font Family & Style フォントファミリー (スタイル)
|
||||
Font Family, Style & Size フォントファミリー (スタイルとサイズ)
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -343,6 +343,7 @@
|
||||
Stroke Weight კონტურის სისქე
|
||||
Graphic Style გრაფიკული სტილი
|
||||
Symbol Instance სიმბოლოს ეგზემპლარი
|
||||
Link Block Series დაკავშირებული ბლოკების სერია
|
||||
Font Family შრიფტის ოჯახი
|
||||
Font Family & Style შრიფტის ოჯახი და სტილი
|
||||
Font Family, Style & Size შრიფტის ოჯახი, სტილი და ზომა
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -448,6 +448,7 @@ digits Malayalam 말라얄람어
|
||||
Stroke Weight 선 두께
|
||||
Graphic Style 그래픽 스타일
|
||||
Symbol Instance 심볼 인스턴스
|
||||
Link Block Series 연결된 블록 시리즈
|
||||
Font Family 글꼴 패밀리
|
||||
Font Family & Style 글꼴 패밀리 및 스타일
|
||||
Font Family, Style & Size 글꼴 패밀리, 스타일 및 크기
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -399,6 +399,7 @@
|
||||
Stroke Weight Contourdikte
|
||||
Graphic Style Grafische stijl
|
||||
Symbol Instance Symboolinstantie
|
||||
Link Block Series Reeks gekoppelde blokken
|
||||
Font Family Lettertypefamilie
|
||||
Font Family & Style Lettertypefamilie en -stijl
|
||||
Font Family, Style & Size Lettertypefamilie, -stijl en -grootte
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -386,6 +386,7 @@
|
||||
Stroke Weight Grubość obrysu
|
||||
Graphic Style Styl graficzny
|
||||
Symbol Instance Wystąpienie symbolu
|
||||
Link Block Series Seria połączonych bloków
|
||||
Font Family Rodzina czcionek
|
||||
Font Family & Style Rodzina i styl czcionki
|
||||
Font Family, Style & Size Rodzina, styl i rozmiar czcionki
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2757,6 +2757,7 @@ digits Malayalam Malaiala
|
||||
Switch Units Trocar Unidades
|
||||
Switch workspace Trocar espaço de trabalho
|
||||
Symbol Instance Instância de Símbolo
|
||||
Link Block Series Série de Blocos Vinculados
|
||||
Symbol Libraries Bibliotecas de Símbolos
|
||||
Symbol Screener Tool Ferramenta Peneira de Símbolos
|
||||
Symbol Scruncher Tool Ferramenta Amontoar Símbolos
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -3385,6 +3385,7 @@ digits Malayalam Малаялам
|
||||
Graphic Графика
|
||||
Show all open documents Показать все открытые документы
|
||||
Symbol Instance Экземпляр символа
|
||||
Link Block Series Серия связанных блоков
|
||||
Symbol Libraries Библиотеки символов
|
||||
Symbol Screener Tool Инструмент «Прозрачность символов»
|
||||
Symbol Scruncher Tool Инструмент «Сжатие символов»
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3276,6 +3276,7 @@ digits Malayalam Malayalam
|
||||
Graphic Grafik
|
||||
Show all open documents Visa alla öppna dokument
|
||||
Symbol Instance Symbolinstans
|
||||
Link Block Series Serie av länkade block
|
||||
Symbol Libraries Symbolbibliotek
|
||||
Symbol Screener Tool Verktyg för symbolopacitet
|
||||
Symbol Scruncher Tool Verktyg för att dra ihop symboler
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -3169,6 +3169,7 @@ digits Malayalam Malayalam
|
||||
Graphic Grafik
|
||||
Show all open documents Tüm açık belgeleri göster
|
||||
Symbol Instance Sembol Örneği
|
||||
Link Block Series Bağlantılı Blok Serisi
|
||||
Symbol Libraries Sembol Kitaplıkları
|
||||
Symbol Screener Tool Sembol Perdeleyici Aracı
|
||||
Symbol Scruncher Tool Sembol Ezici Aracı
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -3383,6 +3383,7 @@ effect Points Точки
|
||||
Graphic Графіка
|
||||
Show all open documents Показати всі відкриті документи
|
||||
Symbol Instance Екземпляр символу
|
||||
Link Block Series Серія пов’язаних блоків
|
||||
Symbol Libraries Бібліотеки символів
|
||||
Symbol Screener Tool Інструмент «Прозорість символів»
|
||||
Symbol Scruncher Tool Інструмент «Стиск символів»
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 177 and column 5.
|
@@ -3706,6 +3706,7 @@ mark-style Japanese Kiểu Nhật
|
||||
Switch workspace Chuyển không gian làm việc
|
||||
Switch x/y Đổi x/y
|
||||
Symbol Instance Thực thể ký hiệu
|
||||
Link Block Series Chuỗi khối liên kết
|
||||
Symbol Libraries Thư viện ký hiệu
|
||||
Symbol Screener Tool Công cụ Lọc ký hiệu
|
||||
Symbol Scruncher Tool Công cụ Thu gọn ký hiệu
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 199 and column 5.
|
@@ -3222,6 +3222,7 @@ digits Malayalam 马拉雅拉姆数字
|
||||
Graphic 图形
|
||||
Show all open documents 显示所有打开的文档
|
||||
Symbol Instance 符号实例
|
||||
Link Block Series 链接块系列
|
||||
Symbol Libraries 符号库
|
||||
Symbol Screener Tool 符号透明度工具
|
||||
Symbol Scruncher Tool 符号紧缩工具
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4234,6 +4234,7 @@ digits Malayalam 馬來亞拉姆數字
|
||||
Graphic 圖形
|
||||
Show all open documents 顯示所有開啟的文件
|
||||
Symbol Instance 符號範例
|
||||
Link Block Series 連結區塊系列
|
||||
Symbol Libraries 符號資料庫
|
||||
Symbol Screener Tool 符號濾色器工具
|
||||
Symbol Scruncher Tool 符號緊縮器工具
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -507,6 +507,26 @@ fn update_selection_follows_save_selection_and_needs_a_recall() {
|
||||
assert_eq!(app.run("select.recall1", json!({})).unwrap()["count"], 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn select_same_link_block_series_selects_a_thread_from_the_menu() {
|
||||
let mut app = app_with_a_rectangle();
|
||||
let entry = menu_entries(&app).into_iter().find(|e| e.command.as_deref() == Some("select.same.linkBlockSeries")).expect("menu entry");
|
||||
assert_eq!((entry.path, entry.label.as_str()), (vec!["Select".to_string(), "Same".to_string()], "Link Block Series"));
|
||||
// A rectangle selected: no type, so the item is off.
|
||||
assert!(!enabled(&app, "select.same.linkBlockSeries"));
|
||||
let frame = |app: &mut VectorcraftApp, x: i32| {
|
||||
app.run("text.create", json!({"x": x, "y": 40, "text": "words ".repeat(40), "area": {"width": 60, "height": 30}})).unwrap()["id"].clone()
|
||||
};
|
||||
let (a, b) = (frame(&mut app, 0), frame(&mut app, 100));
|
||||
app.run("select.set", json!({"ids": [a.clone(), b.clone()]})).unwrap();
|
||||
app.run("text.thread.create", json!({})).unwrap();
|
||||
app.run("select.set", json!({"ids": [b.clone()]})).unwrap();
|
||||
assert!(enabled(&app, "select.same.linkBlockSeries"));
|
||||
invoke(&mut app, "select.same.linkBlockSeries", json!({}));
|
||||
let ids: Vec<u64> = app.session.active().unwrap().selection.objects.iter().map(|i| i.0).collect();
|
||||
assert_eq!(json!(ids), json!([a, b]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn edit_selection_opens_its_dialog_on_the_saved_selections() {
|
||||
let mut app = app_with_a_rectangle();
|
||||
|
||||
@@ -462,6 +462,7 @@ pub fn menu_tree_named(english_names: bool) -> Vec<(&'static str, Vec<Item>)> {
|
||||
c("Graphic Style", "select.same.graphicStyle"),
|
||||
c("Shape", "select.same.shapeType"),
|
||||
c("Symbol Instance", "select.same.symbolInstance"),
|
||||
c("Link Block Series", "select.same.linkBlockSeries"),
|
||||
Sep,
|
||||
c("Font Family", "select.same.fontFamily"),
|
||||
c("Font Family & Style", "select.same.fontFamilyStyle"),
|
||||
|
||||
@@ -4883,6 +4883,13 @@ after it (`out`). The whole story flows into the frames before the break; the fr
|
||||
threaded with each other when two or more remain, and the first of them starts a paragraph. It refuses an `id` that
|
||||
doesn't exist, a `port` other than `in` or `out`, and a side where no frame of a thread comes before or after `id`.
|
||||
|
||||
`select.same.linkBlockSeries` (Select › Same › Link Block Series) selects every frame of the threads that the selected
|
||||
type objects, and the type inside selected groups, are in, in thread order, and returns `{count}`. Type in no thread
|
||||
selects itself, and other selected objects are left out. With frames of several threads selected, it selects the frames
|
||||
of all of them. Type that is hidden or locked, inside a hidden or locked group or layer, on a template layer, or outside
|
||||
the isolated group does not count as selected, and such frames of a thread are left out. It is off while no other type
|
||||
is selected, and records no undo step.
|
||||
|
||||
In every thread, a paragraph that continues from one frame into the next has its first line, first-line indent and
|
||||
bullet or number in the frame where it starts. In the next frame its first line starts where its wrapped lines start,
|
||||
and it has no bullet or number. In a frame that is no longer threaded (after `text.thread.releaseSelection` or
|
||||
|
||||
@@ -888,6 +888,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
|
||||
Type › Convert To Point Type on a frame of threaded text makes point type of the text that frame holds and takes it out of the thread; the story flows through the other frames without that text, so each character is in the document once.
|
||||
Object › Rasterize on a frame of threaded text takes it out of the thread with the text it shows, which the image draws, and the other frames keep the text they hold. When the last frame is rasterized, the text it has no room for goes after the text of the last frame that stays.
|
||||
Type › Create Outlines, Object › Expand and Object › Expand Appearance on a frame of threaded text take it out of the thread with the text it shows, which the outlines draw, and the other frames keep the text they hold. When the last frame is outlined, the text it has no room for goes after the text of the last frame that stays. When Expand Appearance keeps the frame as type in a group with its shadow, outer glow or Crop Marks, the type stays in the thread. The public help on threads ([Create text threads between objects](https://helpx.adobe.com/illustrator/desktop/design-with-text/add-manage-text/create-text-threads-between-objects.html), [Remove or break text threads between objects](https://helpx.adobe.com/illustrator/desktop/design-with-text/add-manage-text/remove-or-break-text-threads-between-objects.html)) does not describe outlining a threaded frame; this handling is VectorCraft's own behavior.
|
||||
Select › Same › Link Block Series selects every frame of the threads of the selected type; type in no thread selects itself (`select.same.linkBlockSeries`). The menu entry is listed in [Select objects by characteristics](https://helpx.adobe.com/illustrator/desktop/manage-objects/select-objects/select-objects-by-characteristics.html); selecting several threads at once and type in no thread selecting itself are VectorCraft's own behavior.
|
||||
Object › Flatten Transparency takes a frame of threaded text out of the thread in the same way when Convert All Text to Outlines outlines it or when the frame becomes flat regions or an image, and the other frames keep the text they hold.
|
||||
New Symbol and Redefine Symbol on a frame of threaded text take it out of the thread with the text it shows, which the symbol's art holds, and the other frames keep the text they hold. When the last frame goes into the symbol, the text it has no room for goes after the text of the last frame that stays. When every frame of a thread goes into the symbol, the copy of the last frame keeps all its text.
|
||||
With Optical Margin Alignment on, or Roman Hanging Punctuation on in the first paragraph, the glyphs at the ends of left-to-right type on a path hang outside its brackets, measured along the path. The type hangs at the start bracket when its line is placed there, hangs at the end bracket when the line is placed there, and hangs at both when it is centered. Glyphs that hang past the end bracket do not make the type overflow, and a hang stops at an open path's end. SVG export writes such type as outlines.
|
||||
|
||||
Reference in New Issue
Block a user