mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-07 16:52:47 +00:00
Merge pull request #5847 from ZIDAN44/fix/5372-control-bar-paragraph
Control bar: Paragraph options while type is selected (#5372)
This commit is contained in:
@@ -172,13 +172,95 @@ fn inline_label(t: &Tokens, lbl: &str) -> egui::RichText {
|
||||
/// language, the four fields, the W/H link and the item spacing ahead of each of them. With less,
|
||||
/// only the Transform link shows.
|
||||
fn inline_transform_width(ui: &Ui, t: &Tokens) -> f32 {
|
||||
let measure = |text: egui::WidgetText| text.into_galley(ui, Some(egui::TextWrapMode::Extend), f32::INFINITY, egui::TextStyle::Body).size().x;
|
||||
let labels: f32 = INLINE_FIELDS.iter().map(|(_, lbl)| measure(inline_label(t, lbl).into())).sum();
|
||||
let labels: f32 = INLINE_FIELDS.iter().map(|(_, lbl)| widgets::text_width(ui, inline_label(t, lbl))).sum();
|
||||
let fields = INLINE_FIELD_WIDTH * INLINE_FIELDS.len() as f32;
|
||||
let items = 2 * INLINE_FIELDS.len() + 1;
|
||||
labels + fields + crate::panels::transform::CONSTRAIN_LINK_SIZE + ui.spacing().item_spacing.x * items as f32
|
||||
}
|
||||
|
||||
/// The size of the Control bar's Align, Distribute and area type vertical alignment buttons.
|
||||
const BUTTON: f32 = 24.0;
|
||||
|
||||
/// The space ahead of the separator that ends a group of the Control bar's controls.
|
||||
const GROUP_GAP: f32 = 4.0;
|
||||
|
||||
/// The width of the separators of the Control bar's [`group_end`] and ahead of the Transform link.
|
||||
const SEPARATOR: f32 = 6.0;
|
||||
|
||||
/// The widths of the Document Setup and Preferences buttons, shown with nothing selected.
|
||||
const DOCUMENT_SETUP_WIDTH: f32 = 112.0;
|
||||
const PREFERENCES_WIDTH: f32 = 90.0;
|
||||
|
||||
/// The room `n` of the bar's buttons take, with the spacing after each.
|
||||
fn buttons_width(ui: &Ui, n: usize) -> f32 {
|
||||
(BUTTON + ui.spacing().item_spacing.x) * n as f32
|
||||
}
|
||||
|
||||
/// The separator that ends a group of the Control bar's controls, as [`group_end_width`] measures it.
|
||||
fn group_end(ui: &mut Ui) {
|
||||
ui.add_space(GROUP_GAP);
|
||||
separator(ui);
|
||||
}
|
||||
|
||||
fn group_end_width(ui: &Ui) -> f32 {
|
||||
GROUP_GAP + separator_width(ui)
|
||||
}
|
||||
|
||||
/// A separator [`SEPARATOR`] wide.
|
||||
fn separator(ui: &mut Ui) {
|
||||
ui.add(egui::Separator::default().spacing(SEPARATOR));
|
||||
}
|
||||
|
||||
fn separator_width(ui: &Ui) -> f32 {
|
||||
SEPARATOR + ui.spacing().item_spacing.x
|
||||
}
|
||||
|
||||
/// The room the controls at the end of the Control bar need: the Transform link, or Document Setup
|
||||
/// and Preferences with nothing selected. The groups ahead of them (the Paragraph section, area
|
||||
/// type's vertical alignment, the Align and Distribute buttons) show only while it is left, so
|
||||
/// the bar trims them from its right end (#5372), after the inline X/Y/W/H fields.
|
||||
fn end_width(ui: &Ui, nothing_selected: bool) -> f32 {
|
||||
if nothing_selected { DOCUMENT_SETUP_WIDTH + ui.spacing().item_spacing.x + PREFERENCES_WIDTH } else { crate::panels::transform::link_width(ui) }
|
||||
}
|
||||
|
||||
/// Draws the Control bar's groups between its Character controls and the Transform link, and
|
||||
/// returns whether the Transform link and X/Y/W/H follow (false: nothing is selected, and Document
|
||||
/// Setup and Preferences, drawn here, end the bar). The groups are the Paragraph section and area
|
||||
/// type's vertical alignment (#3759), then the Align buttons and, for two or more objects, the
|
||||
/// Distribute buttons (a single object keeps the bar as it was); each shows only while the end of
|
||||
/// the bar keeps its room.
|
||||
fn groups_before_transform(app: &mut VectorcraftApp, ui: &mut Ui, objects: usize) -> bool {
|
||||
let nothing = objects == 0;
|
||||
if crate::panels::paragraph::control_bar(app, ui, BUTTON, |ui| group_end_width(ui) + end_width(ui, nothing)) {
|
||||
group_end(ui);
|
||||
}
|
||||
if crate::panels::properties::vertical_align::shown(app).is_some()
|
||||
&& ui.available_width() >= buttons_width(ui, 4) + group_end_width(ui) + end_width(ui, nothing)
|
||||
&& crate::panels::properties::vertical_align::buttons(app, ui, BUTTON)
|
||||
{
|
||||
group_end(ui);
|
||||
}
|
||||
if nothing {
|
||||
if widgets::flat_button(ui, tl!("Document Setup"), DOCUMENT_SETUP_WIDTH).clicked() {
|
||||
app.run("file.documentSetup", json!({})).ok();
|
||||
}
|
||||
if widgets::flat_button(ui, tl!("Preferences"), PREFERENCES_WIDTH).clicked() {
|
||||
app.run("edit.preferences", json!({})).ok();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
let end = separator_width(ui) + end_width(ui, false);
|
||||
if ui.available_width() >= buttons_width(ui, 7) + end {
|
||||
crate::panels::align::align_buttons(app, ui, BUTTON);
|
||||
if objects > 1 && ui.available_width() >= GROUP_GAP + buttons_width(ui, 6) + end {
|
||||
ui.add_space(GROUP_GAP);
|
||||
crate::panels::align::distribute_buttons(app, ui, BUTTON);
|
||||
}
|
||||
separator(ui);
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// The Control bar (Window → Control), context-sensitive like Illustrator's.
|
||||
pub fn control_bar(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
let t = Tokens::get(ui.ctx());
|
||||
@@ -283,28 +365,9 @@ pub fn control_bar(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
}
|
||||
ui.separator();
|
||||
crate::panels::character::control_bar(app, ui);
|
||||
// Area type: its vertical alignment in the frame (#3759).
|
||||
if crate::panels::properties::vertical_align::buttons(app, ui, 24.0) {
|
||||
ui.add_space(4.0);
|
||||
ui.separator();
|
||||
}
|
||||
if sel.is_empty() {
|
||||
if widgets::flat_button(ui, tl!("Document Setup"), 112.0).clicked() {
|
||||
app.run("file.documentSetup", json!({})).ok();
|
||||
}
|
||||
if widgets::flat_button(ui, tl!("Preferences"), 90.0).clicked() {
|
||||
app.run("edit.preferences", json!({})).ok();
|
||||
}
|
||||
if !groups_before_transform(app, ui, sel.len()) {
|
||||
return;
|
||||
}
|
||||
crate::panels::align::align_buttons(app, ui, 24.0);
|
||||
// Two or more objects get the six Distribute Objects buttons too; a single
|
||||
// object keeps the bar as it was.
|
||||
if sel.len() > 1 {
|
||||
ui.add_space(4.0);
|
||||
crate::panels::align::distribute_buttons(app, ui, 24.0);
|
||||
}
|
||||
ui.separator();
|
||||
// The Transform link opens the whole Transform panel (reference point, rotate,
|
||||
// shear, options) in a popover; X/Y/W/H follow inline while the bar has room.
|
||||
crate::panels::transform::link(app, ui);
|
||||
|
||||
@@ -1939,7 +1939,8 @@ fn the_control_bar_shows_the_global_edit_options() {
|
||||
|
||||
/// At any width the Control bar shows the inline X, Y, W and H fields whole inside its right margin,
|
||||
/// or leaves all four out and keeps the Transform link; a wider bar never leaves them out once a
|
||||
/// narrower one showed them.
|
||||
/// narrower one showed them. The Align buttons, and for two objects the Distribute buttons, are
|
||||
/// trimmed the same way ahead of the Transform link (#5372).
|
||||
#[test]
|
||||
fn the_control_bar_shows_the_inline_transform_fields_only_when_they_fit() {
|
||||
crate::i18n::set_current(crate::i18n::Lang::EN);
|
||||
@@ -1954,6 +1955,33 @@ fn the_control_bar_shows_the_inline_transform_fields_only_when_they_fit() {
|
||||
ctx.enable_accesskit();
|
||||
crate::theme::install_fonts(&ctx);
|
||||
let mut seen = false;
|
||||
// The Align group, then for two objects the Distribute group (#5372): each by its controls.
|
||||
let mut groups: Vec<(&str, Vec<&str>)> = vec![(
|
||||
"Align",
|
||||
vec![
|
||||
"Horizontal Align Left",
|
||||
"Horizontal Align Center",
|
||||
"Horizontal Align Right",
|
||||
"Horizontal & Vertical Align Center",
|
||||
"Vertical Align Top",
|
||||
"Vertical Align Center",
|
||||
"Vertical Align Bottom",
|
||||
],
|
||||
)];
|
||||
if count == 2 {
|
||||
groups.push((
|
||||
"Distribute",
|
||||
vec![
|
||||
"Vertical Distribute Top",
|
||||
"Vertical Distribute Center",
|
||||
"Vertical Distribute Bottom",
|
||||
"Horizontal Distribute Left",
|
||||
"Horizontal Distribute Center",
|
||||
"Horizontal Distribute Right",
|
||||
],
|
||||
));
|
||||
}
|
||||
let mut groups_seen = vec![false; groups.len()];
|
||||
for width in (600..=2400).step_by(10) {
|
||||
let screen = egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(width as f32, 300.0));
|
||||
let mut nodes = Vec::new();
|
||||
@@ -1980,7 +2008,24 @@ fn the_control_bar_shows_the_inline_transform_fields_only_when_they_fit() {
|
||||
}
|
||||
assert!(!seen || fields[3].is_some(), "{count} objects, {width}: left out after a narrower bar showed them");
|
||||
seen |= fields[3].is_some();
|
||||
// The Align and Distribute buttons show whole inside the margin, with the Transform
|
||||
// link after them, or are left out; once shown, a wider bar keeps them.
|
||||
let end = |name: &str| nodes.iter().find(|(_, n)| n.label() == Some(name)).and_then(|(_, n)| n.bounds()).map(|b| b.x1);
|
||||
let inside = |x: f64| x <= f64::from(width) - 10.0;
|
||||
for ((group, names), was) in groups.iter().zip(groups_seen.iter_mut()) {
|
||||
let ends: Vec<Option<f64>> = names.iter().map(|n| end(n)).collect();
|
||||
let shown = ends.iter().all(Option::is_some);
|
||||
assert!(shown || ends.iter().all(Option::is_none), "{count} objects, {width}: {group} {ends:?}");
|
||||
if let Some(Some(last)) = ends.last() {
|
||||
assert!(inside(*last), "{count} objects, {width}: {group} ends at {last}");
|
||||
let transform = end("Transform");
|
||||
assert!(transform.is_some_and(inside), "{count} objects, {width}: Transform after {group} ends at {transform:?}");
|
||||
}
|
||||
assert!(!*was || shown, "{count} objects, {width}: {group} left out after a narrower bar showed it");
|
||||
*was |= shown;
|
||||
}
|
||||
}
|
||||
assert!(seen, "{count} objects: a wide bar has room for the fields");
|
||||
assert!(groups_seen.iter().all(|s| *s), "{count} objects: a wide bar shows every group: {groups_seen:?}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3207,7 +3207,9 @@ digits Malayalam Малаялам
|
||||
Patterns Мостри
|
||||
Stroke Options Опции на щриха
|
||||
Character: Знак:
|
||||
Paragraph: Абзац:
|
||||
Character options Опции на знака
|
||||
Paragraph options Опции за абзац
|
||||
Stroke options Опции на щриха
|
||||
Transform options Опции за трансформации
|
||||
Stroke Weight Дебелина на щриха
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1469,7 +1469,9 @@ digits Malayalam Malajalam
|
||||
Standard Vertical Roman Alignment Standardno okomito latinično poravnanje
|
||||
Strikethrough Precrtano
|
||||
Character: Znak:
|
||||
Paragraph: Pasus:
|
||||
Character options Opcije znakova
|
||||
Paragraph options Opcije pasusa
|
||||
Subscript Indeks
|
||||
Subscript (on the roadmap) Indeks (u planu)
|
||||
Superscript Eksponent
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -615,12 +615,14 @@
|
||||
Character Alignment Alineació de caràcters
|
||||
Character Direction Direcció de caràcters
|
||||
Character options Opcions de caràcter
|
||||
Paragraph options Opcions de paràgraf
|
||||
Character Rotation Rotació de caràcters
|
||||
Character Set: Joc de caràcters:
|
||||
Character Style Estil de caràcter
|
||||
Character Style Options Opcions de l’estil de caràcter
|
||||
Character Styles Estils de caràcter
|
||||
Character: Caràcter:
|
||||
Paragraph: Paràgraf:
|
||||
Charcoal Carbó
|
||||
Charcoal… Carbó…
|
||||
Check an artboard to save. Marca un tauler per desar.
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1493,7 +1493,9 @@ digits Malayalam Malajálamské
|
||||
Standard Vertical Roman Alignment Standardní svislé zarovnání latinky
|
||||
Strikethrough Přeškrtnutí
|
||||
Character: Znak:
|
||||
Paragraph: Odstavec:
|
||||
Character options Možnosti znaků
|
||||
Paragraph options Možnosti odstavce
|
||||
Subscript Dolní index
|
||||
Subscript (on the roadmap) Dolní index (v plánu)
|
||||
Superscript Horní index
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1403,7 +1403,9 @@ digits Malayalam Malayalam
|
||||
Standard Vertical Roman Alignment Standard lodret romersk justering
|
||||
Strikethrough Gennemstreget
|
||||
Character: Tegn:
|
||||
Paragraph: Afsnit:
|
||||
Character options Tegnindstillinger
|
||||
Paragraph options Afsnitsindstillinger
|
||||
Subscript Sænket skrift
|
||||
Subscript (on the roadmap) Sænket skrift (på vejkortet)
|
||||
Superscript Hævet skrift
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3252,7 +3252,9 @@ effect Points Punkte
|
||||
Patterns Muster
|
||||
Stroke Options Konturoptionen
|
||||
Character: Zeichen:
|
||||
Paragraph: Absatz:
|
||||
Character options Zeichenoptionen
|
||||
Paragraph options Absatzoptionen
|
||||
Stroke options Konturoptionen
|
||||
Transform options Transformationsoptionen
|
||||
Stroke Weight Konturstärke
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1991,6 +1991,7 @@ font-technology Variable Μεταβλητές
|
||||
Patterns Μοτίβα
|
||||
Stroke Options Επιλογές περιγράμματος
|
||||
Character: Χαρακτήρας:
|
||||
Paragraph: Παράγραφος:
|
||||
Stroke: Περίγραμμα:
|
||||
Style Στυλ
|
||||
Style: Στυλ:
|
||||
@@ -3655,6 +3656,7 @@ digits Malayalam Μαλαγιάλαμ
|
||||
Stray Points Μεμονωμένα σημεία
|
||||
Stroke (X), double-click for the Color Picker Περίγραμμα (X), διπλό κλικ για επιλογέα χρώματος
|
||||
Character options Επιλογές χαρακτήρων
|
||||
Paragraph options Επιλογές παραγράφου
|
||||
Stroke options Επιλογές περιγράμματος
|
||||
Transform options Επιλογές μετασχηματισμού
|
||||
Stroke Weight Πάχος περιγράμματος
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 163 and column 5.
|
@@ -3291,7 +3291,9 @@ digits Malayalam Malayálam
|
||||
Patterns Motivos
|
||||
Stroke Options Opciones de trazo
|
||||
Character: Carácter:
|
||||
Paragraph: Párrafo:
|
||||
Character options Opciones de carácter
|
||||
Paragraph options Opciones de párrafo
|
||||
Stroke options Opciones de trazo
|
||||
Transform options Opciones de transformación
|
||||
Stroke Weight Grosor de trazo
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1466,7 +1466,9 @@ digits Malayalam Malajalam
|
||||
Standard Vertical Roman Alignment Tavallinen pystysuuntainen latinalainen tasaus
|
||||
Strikethrough Yliviivaus
|
||||
Character: Merkki:
|
||||
Paragraph: Kappale:
|
||||
Character options Merkkiasetukset
|
||||
Paragraph options Kappaleasetukset
|
||||
Subscript Alaindeksi
|
||||
Subscript (on the roadmap) Alaindeksi (suunnitteilla)
|
||||
Superscript Yläindeksi
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3283,7 +3283,9 @@ digits Malayalam Malayalam
|
||||
Patterns Motifs
|
||||
Stroke Options Options de contour
|
||||
Character: Caractère :
|
||||
Paragraph: Paragraphe :
|
||||
Character options Options de caractère
|
||||
Paragraph options Options de paragraphe
|
||||
Stroke options Options de contour
|
||||
Transform options Options de transformation
|
||||
Stroke Weight Épaisseur du contour
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -554,12 +554,14 @@ font-technology Variable Változó
|
||||
Character / Paragraph Karakter / bekezdés
|
||||
Character Alignment Karakterigazítás
|
||||
Character options Karakterbeállítások
|
||||
Paragraph options Bekezdésbeállítások
|
||||
Character Rotation Karakterforgatás
|
||||
Character Set: Karakterkészlet:
|
||||
Character Style Karakterstílus
|
||||
Character Style Options Karakterstílus beállításai
|
||||
Character Styles Karakterstílusok
|
||||
Character: Karakter:
|
||||
Paragraph: Bekezdés:
|
||||
Check Links Csatolások ellenőrzése
|
||||
# Check Script (File › Scripts) and the report it shows on a script written for the reference app.
|
||||
Check Script Szkript ellenőrzése
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1403,7 +1403,9 @@ digits Malayalam Malayalam
|
||||
Standard Vertical Roman Alignment Perataan Romawi vertikal standar
|
||||
Strikethrough Coret
|
||||
Character: Karakter:
|
||||
Paragraph: Paragraf:
|
||||
Character options Opsi karakter
|
||||
Paragraph options Opsi paragraf
|
||||
Subscript Subskrip
|
||||
Subscript (on the roadmap) Subskrip (masih dalam roadmap)
|
||||
Superscript Superskrip
|
||||
|
||||
|
@@ -3327,7 +3327,9 @@ digits Malayalam Malayalam
|
||||
Patterns Motivi
|
||||
Stroke Options Opzioni traccia
|
||||
Character: Carattere:
|
||||
Paragraph: Paragrafo:
|
||||
Character options Opzioni carattere
|
||||
Paragraph options Opzioni di paragrafo
|
||||
Stroke options Opzioni traccia
|
||||
Transform options Opzioni di trasformazione
|
||||
Stroke Weight Spessore traccia
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3090,7 +3090,9 @@ mark-style Japanese 日本式
|
||||
Strikethrough 打ち消し線
|
||||
Stroke Options 線オプション
|
||||
Character: 文字:
|
||||
Paragraph: 段落:
|
||||
Character options 文字オプション
|
||||
Paragraph options 段落オプション
|
||||
Stroke options 線オプション
|
||||
Transform options 変形オプション
|
||||
Stroke: 線:
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1329,7 +1329,9 @@ digits Malayalam მალაიალამური
|
||||
Standard Vertical Roman Alignment სტანდარტული ვერტიკალური ლათინური სწორება
|
||||
Strikethrough გადახაზული
|
||||
Character: სიმბოლო:
|
||||
Paragraph: აბზაცი:
|
||||
Character options სიმბოლოს პარამეტრები
|
||||
Paragraph options აბზაცის პარამეტრები
|
||||
Subscript ქვედა ინდექსი
|
||||
Subscript (on the roadmap) ქვედა ინდექსი (სამომავლო გეგმაშია)
|
||||
Superscript ზედა ინდექსი
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -3079,7 +3079,9 @@ mark-style Japanese 일본식
|
||||
Strikethrough 취소선
|
||||
Stroke Options 선 옵션
|
||||
Character: 문자:
|
||||
Paragraph: 단락:
|
||||
Character options 문자 옵션
|
||||
Paragraph options 단락 옵션
|
||||
Stroke options 선 옵션
|
||||
Transform options 변형 옵션
|
||||
Stroke: 선:
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1417,7 +1417,9 @@ digits Malayalam Malayalam
|
||||
Standard Vertical Roman Alignment Standaard verticale Romeinse uitlijning
|
||||
Strikethrough Doorhalen
|
||||
Character: Teken:
|
||||
Paragraph: Alinea:
|
||||
Character options Tekenopties
|
||||
Paragraph options Alineaopties
|
||||
Subscript Subscript
|
||||
Subscript (on the roadmap) Subscript (op de roadmap)
|
||||
Superscript Superscript
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1406,7 +1406,9 @@ digits Malayalam Malajalam
|
||||
Standard Vertical Roman Alignment Standardowe pionowe wyrównanie łacińskie
|
||||
Strikethrough Przekreślenie
|
||||
Character: Znak:
|
||||
Paragraph: Akapit:
|
||||
Character options Opcje znaków
|
||||
Paragraph options Opcje akapitu
|
||||
Subscript Indeks dolny
|
||||
Subscript (on the roadmap) Indeks dolny (w planach)
|
||||
Superscript Indeks górny
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2748,7 +2748,9 @@ digits Malayalam Malaiala
|
||||
Stroke Options Opções de Traçado
|
||||
Stroke Weight Peso do Traçado
|
||||
Character: Caractere:
|
||||
Paragraph: Parágrafo:
|
||||
Character options Opções de caractere
|
||||
Paragraph options Opções de parágrafo
|
||||
Stroke options Opções de traçado
|
||||
Transform options Opções de transformação
|
||||
Stroke: Traçado:
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -3322,7 +3322,9 @@ digits Malayalam Малаялам
|
||||
Patterns Узоры
|
||||
Stroke Options Параметры обводки
|
||||
Character: Символ:
|
||||
Paragraph: Абзац:
|
||||
Character options Параметры символа
|
||||
Paragraph options Параметры абзаца
|
||||
Stroke options Параметры обводки
|
||||
Transform options Параметры трансформирования
|
||||
Stroke Weight Толщина обводки
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3213,7 +3213,9 @@ digits Malayalam Malayalam
|
||||
Patterns Mönster
|
||||
Stroke Options Konturalternativ
|
||||
Character: Tecken:
|
||||
Paragraph: Stycke:
|
||||
Character options Teckenalternativ
|
||||
Paragraph options Styckealternativ
|
||||
Stroke options Konturalternativ
|
||||
Transform options Transformeringsalternativ
|
||||
Stroke Weight Konturtjocklek
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -3115,7 +3115,9 @@ digits Malayalam Malayalam
|
||||
Patterns Desenler
|
||||
Stroke Options Kontur Seçenekleri
|
||||
Character: Karakter:
|
||||
Paragraph: Paragraf:
|
||||
Character options Karakter seçenekleri
|
||||
Paragraph options Paragraf seçenekleri
|
||||
Stroke options Kontur seçenekleri
|
||||
Transform options Dönüştürme seçenekleri
|
||||
Stroke Weight Kontur Kalınlığı
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -3320,7 +3320,9 @@ effect Points Точки
|
||||
Patterns Візерунки
|
||||
Stroke Options Параметри обведення
|
||||
Character: Символ:
|
||||
Paragraph: Абзац:
|
||||
Character options Параметри символу
|
||||
Paragraph options Параметри абзацу
|
||||
Stroke options Параметри обведення
|
||||
Transform options Параметри трансформування
|
||||
Stroke Weight Товщина обведення
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 177 and column 5.
|
@@ -468,12 +468,14 @@ font-technology Variable Biến thiên
|
||||
Character / Paragraph Ký tự / Đoạn văn
|
||||
Character Alignment Căn chỉnh ký tự
|
||||
Character options Tùy chọn ký tự
|
||||
Paragraph options Tùy chọn đoạn văn
|
||||
Character Rotation Xoay ký tự
|
||||
Character Set: Bộ ký tự:
|
||||
Character Style Kiểu ký tự
|
||||
Character Style Options Tùy chọn kiểu ký tự
|
||||
Character Styles Các kiểu ký tự
|
||||
Character: Ký tự:
|
||||
Paragraph: Đoạn văn:
|
||||
Check Links Kiểm tra liên kết
|
||||
# Check Script (File › Scripts) and the report it shows on a script written for the reference app.
|
||||
Check Script Kiểm tra script
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 199 and column 5.
|
@@ -3158,7 +3158,9 @@ digits Malayalam 马拉雅拉姆数字
|
||||
Patterns 图案
|
||||
Stroke Options 描边选项
|
||||
Character: 字符:
|
||||
Paragraph: 段落:
|
||||
Character options 字符选项
|
||||
Paragraph options 段落选项
|
||||
Stroke options 描边选项
|
||||
Transform options 变换选项
|
||||
Stroke Weight 描边粗细
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4185,7 +4185,9 @@ digits Malayalam 馬來亞拉姆數字
|
||||
Patterns 圖樣
|
||||
Stroke Options 筆畫選項
|
||||
Character: 字元:
|
||||
Paragraph: 段落:
|
||||
Character options 字元選項
|
||||
Paragraph options 段落選項
|
||||
Stroke options 筆畫選項
|
||||
Transform options 變形選項
|
||||
Stroke Weight 筆畫寬度
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -380,14 +380,66 @@ fn selected_alignment(app: &VectorcraftApp, fallback: &ParaStyle) -> Option<Just
|
||||
/// The seven alignment buttons shared by Paragraph and Properties; no button is selected
|
||||
/// when the paragraphs they act on have differing displayed alignments.
|
||||
pub fn alignment_buttons(app: &mut VectorcraftApp, ui: &mut Ui, para: &ParaStyle, size: f32) {
|
||||
first_alignment_buttons(app, ui, para, size, ALIGNMENTS.len());
|
||||
}
|
||||
|
||||
/// The first `count` of the [`ALIGNMENTS`] buttons.
|
||||
fn first_alignment_buttons(app: &mut VectorcraftApp, ui: &mut Ui, para: &ParaStyle, size: f32, count: usize) {
|
||||
let shown = selected_alignment(app, para);
|
||||
for (j, icon, tip, id) in ALIGNMENTS {
|
||||
for (j, icon, tip, id) in ALIGNMENTS.into_iter().take(count) {
|
||||
if widgets::icon_button(ui, icon, tip, shown == Some(j), size).clicked() {
|
||||
para_cmd(app, "text.setStyle", json!({"justify": id}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The Control bar's alignment buttons: Align left, Align center and Align right. The public
|
||||
/// documentation has the Control panel format paragraphs while type is selected, with a way to the
|
||||
/// Paragraph panel (<https://helpx.adobe.com/illustrator/using/formatting-paragraphs.html>), and
|
||||
/// its alignment buttons align text as the Paragraph panel's do
|
||||
/// (<https://helpx.adobe.com/illustrator/using/align-text.html>). The bar keeps to the three that
|
||||
/// don't justify, for its room; all seven are in the Paragraph options the link opens.
|
||||
const CONTROL_BAR_ALIGNMENTS: usize = 3;
|
||||
|
||||
/// The spacing between the Control bar's alignment buttons, as in the Paragraph panel's row.
|
||||
const CONTROL_BAR_BUTTON_SPACING: f32 = 3.0;
|
||||
|
||||
/// The width of the Paragraph panel in the Control bar's popover, as the Character panel's.
|
||||
const CONTROL_BAR_POPOVER_WIDTH: f32 = 260.0;
|
||||
|
||||
/// The Control bar's Paragraph link, as it is drawn and measured.
|
||||
fn control_bar_link_text(ui: &Ui) -> egui::RichText {
|
||||
egui::RichText::new(tl!("Paragraph:")).size(12.0).color(Tokens::get(ui.ctx()).text).underline()
|
||||
}
|
||||
|
||||
/// The Control bar's paragraph controls while type is selected or edited (#5372), after its
|
||||
/// Character controls: the Paragraph link, which opens the Paragraph panel in a popover under it,
|
||||
/// and the Align left, Align center and Align right buttons, `size` points square as the bar's others. `reserve` gives the room the controls
|
||||
/// after them keep, asked only when type is selected: short of room, the buttons are left out,
|
||||
/// then the link too. Returns whether the link shows.
|
||||
pub(crate) fn control_bar(app: &mut VectorcraftApp, ui: &mut Ui, size: f32, reserve: impl FnOnce(&Ui) -> f32) -> bool {
|
||||
let Some((_, para)) = text_style(app) else { return false };
|
||||
let text = control_bar_link_text(ui);
|
||||
let link_width = widgets::text_width(ui, text.clone());
|
||||
let room = ui.available_width() - reserve(ui);
|
||||
let link_room = link_width + ui.spacing().item_spacing.x;
|
||||
if room < link_room {
|
||||
return false;
|
||||
}
|
||||
let link = ui.link(text).on_hover_text(tl!("Paragraph options"));
|
||||
widgets::popover(&link, link.clicked(), |ui| {
|
||||
ui.set_width(CONTROL_BAR_POPOVER_WIDTH);
|
||||
show(app, ui);
|
||||
});
|
||||
if room >= link_room + (size + CONTROL_BAR_BUTTON_SPACING) * CONTROL_BAR_ALIGNMENTS as f32 {
|
||||
let spacing = ui.spacing().item_spacing.x;
|
||||
ui.spacing_mut().item_spacing.x = CONTROL_BAR_BUTTON_SPACING;
|
||||
first_alignment_buttons(app, ui, ¶, size, CONTROL_BAR_ALIGNMENTS);
|
||||
ui.spacing_mut().item_spacing.x = spacing;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// Type › Bullets and Numbering › Apply Bullets (`type.applyBullets {bullet?}`): the paragraphs of
|
||||
/// the selected type, or those the Type tool's selection touches, become a bulleted list with
|
||||
/// `bullet`; without it, a list keeps its bullet and other paragraphs take the dot.
|
||||
|
||||
@@ -543,3 +543,150 @@ fn reset_panel_resets_the_hyphenation_options() {
|
||||
assert_eq!(serde_json::to_value(¶).unwrap().get("justification"), None, "saves no justification options");
|
||||
}
|
||||
}
|
||||
|
||||
type Nodes = Vec<(egui::accesskit::NodeId, egui::accesskit::Node)>;
|
||||
|
||||
/// An English context for headless Control bar frames, with AccessKit on to find its controls.
|
||||
fn control_bar_ctx() -> egui::Context {
|
||||
crate::i18n::set_current(crate::i18n::Lang::EN);
|
||||
let ctx = egui::Context::default();
|
||||
ctx.enable_accesskit();
|
||||
crate::theme::install_fonts(&ctx);
|
||||
ctx
|
||||
}
|
||||
|
||||
/// A document with the type `texts` (`text.create` params) makes, all of it selected.
|
||||
fn control_bar_app(texts: &[Value]) -> VectorcraftApp {
|
||||
let mut app = VectorcraftApp::new(Session::new(), Default::default());
|
||||
app.run("file.new", json!({"width": 800, "height": 400})).unwrap();
|
||||
let ids: Vec<Value> = texts.iter().map(|p| app.run("text.create", p.clone()).unwrap()["id"].clone()).collect();
|
||||
app.run("select.set", json!({ "ids": ids })).unwrap();
|
||||
app
|
||||
}
|
||||
|
||||
/// The second of two headless frames of the whole Control bar, `width` wide (the first lays it out).
|
||||
fn control_bar_nodes(ctx: &egui::Context, app: &mut VectorcraftApp, width: f32, events: Vec<egui::Event>) -> Nodes {
|
||||
let screen = egui::Rect::from_min_size(egui::Pos2::ZERO, vec2(width, 300.0));
|
||||
let mut nodes = Vec::new();
|
||||
for events in [events, vec![]] {
|
||||
let mut out =
|
||||
ctx.run_ui(egui::RawInput { events, screen_rect: Some(screen), ..Default::default() }, |ui| crate::chrome::control_bar(app, ui));
|
||||
out.textures_delta.clear();
|
||||
nodes = out.platform_output.accesskit_update.map(|u| u.nodes).unwrap_or_default();
|
||||
}
|
||||
nodes
|
||||
}
|
||||
|
||||
/// The control named `name` (a button's or link's label, a label's text).
|
||||
fn control_bar_node(nodes: &Nodes, name: &str) -> Option<egui::accesskit::Node> {
|
||||
nodes.iter().find(|(_, n)| n.label() == Some(name) || n.value() == Some(name)).map(|(_, n)| n.clone())
|
||||
}
|
||||
|
||||
/// Where the control named `name` ends, if it shows.
|
||||
fn control_bar_end(nodes: &Nodes, name: &str) -> Option<f64> {
|
||||
control_bar_node(nodes, name).and_then(|n| n.bounds()).map(|b| b.x1)
|
||||
}
|
||||
|
||||
/// The Control bar's Paragraph alignment buttons.
|
||||
const BAR_ALIGNMENTS: [&str; 3] = ["Align left", "Align center", "Align right"];
|
||||
|
||||
/// #5372: with type selected, the Control bar shows a Paragraph section after the Character one, as
|
||||
/// the public documentation's Control panel does: a Paragraph: link that opens the Paragraph panel
|
||||
/// in a popover under it, and the Align left, Align center and Align right buttons. A click aligns
|
||||
/// the selected type, and the button of its alignment shows selected. The buttons show on a bar of
|
||||
/// common window widths.
|
||||
#[test]
|
||||
fn the_control_bar_shows_the_paragraph_alignment_of_the_selected_type() {
|
||||
let ctx = control_bar_ctx();
|
||||
let mut app = control_bar_app(&[json!({"x": 20, "y": 50, "text": "Point"})]);
|
||||
// Pinned, so that the room the buttons need can't creep up past common window widths.
|
||||
for width in [1440.0, 1920.0] {
|
||||
let nodes = control_bar_nodes(&ctx, &mut app, width, vec![]);
|
||||
let ends = BAR_ALIGNMENTS.map(|n| control_bar_end(&nodes, n));
|
||||
assert!(ends.iter().all(|e| e.is_some_and(|x| x <= f64::from(width) - 10.0)), "pinned: the buttons show on a {width} pt window: {ends:?}");
|
||||
}
|
||||
let width = 1920.0;
|
||||
let nodes = control_bar_nodes(&ctx, &mut app, width, vec![]);
|
||||
let center = |n: &egui::accesskit::Node| {
|
||||
let b = n.bounds().unwrap_or_else(|| panic!("{n:?}"));
|
||||
egui::pos2(((b.x0 + b.x1) / 2.0) as f32, ((b.y0 + b.y1) / 2.0) as f32)
|
||||
};
|
||||
let click = |app: &mut VectorcraftApp, at: egui::Pos2| {
|
||||
let press = |pressed| egui::Event::PointerButton { pos: at, button: egui::PointerButton::Primary, pressed, modifiers: Default::default() };
|
||||
control_bar_nodes(&ctx, app, width, vec![egui::Event::PointerMoved(at), press(true)]);
|
||||
control_bar_nodes(&ctx, app, width, vec![press(false)]);
|
||||
control_bar_nodes(&ctx, app, width, vec![])
|
||||
};
|
||||
// A selected button shows pressed.
|
||||
let on = |n: &egui::accesskit::Node| n.toggled() == Some(egui::accesskit::Toggled::True);
|
||||
let button = control_bar_node(&nodes, "Align center").unwrap_or_else(|| panic!("the Control bar has Align center"));
|
||||
assert!(!on(&button), "left-aligned type: Align center is not selected");
|
||||
assert!(control_bar_node(&nodes, "Align left").is_some_and(|n| on(&n)), "Align left shows selected");
|
||||
let undo = app.session.active().unwrap().history.undo.len();
|
||||
let nodes = click(&mut app, center(&button));
|
||||
assert_eq!(text_style(&app).unwrap().1.justify, Justify::Center, "{}", app.ui.status);
|
||||
assert_eq!(app.session.active().unwrap().history.undo.len(), undo + 1, "one undo step");
|
||||
assert!(control_bar_node(&nodes, "Align center").is_some_and(|n| on(&n)), "Align center shows selected");
|
||||
assert!(!control_bar_node(&nodes, "Align left").is_some_and(|n| on(&n)), "Align left no longer selected");
|
||||
// The Paragraph: link opens the Paragraph panel in a popover: its justifications show there,
|
||||
// no panel docks, and a second click closes it.
|
||||
let link = control_bar_node(&nodes, "Paragraph:").unwrap_or_else(|| panic!("the Paragraph: link"));
|
||||
assert_eq!(link.description(), Some("Paragraph options"));
|
||||
assert!(control_bar_node(&nodes, "Justify all lines").is_none(), "closed");
|
||||
let nodes = click(&mut app, center(&link));
|
||||
assert!(control_bar_node(&nodes, "Justify all lines").is_some(), "the popover shows the Paragraph panel");
|
||||
assert_eq!(app.ui.open_panel, None, "no panel docks");
|
||||
let nodes = click(&mut app, center(&link));
|
||||
assert!(control_bar_node(&nodes, "Justify all lines").is_none(), "a second click closes it");
|
||||
}
|
||||
|
||||
/// #5372: at any width the Control bar trims itself from its right end, ending inside its margin.
|
||||
/// With type selected the inline X/Y/W/H fields go first, then the Distribute and Align buttons,
|
||||
/// area type's vertical alignment, the Paragraph buttons and last the Paragraph: link, while the
|
||||
/// Transform link keeps its room; a wider bar never leaves out what a narrower one showed. For one point
|
||||
/// type object, area type (its vertical alignment) and two objects (the Distribute buttons).
|
||||
#[test]
|
||||
fn the_control_bar_trims_its_paragraph_section_after_the_controls_to_its_right() {
|
||||
let ctx = control_bar_ctx();
|
||||
let point = |x: i32| json!({"x": x, "y": 50, "text": "Point"});
|
||||
let area = json!({"x": 20, "y": 20, "text": "Area", "area": {"width": 100, "height": 120}});
|
||||
const VERTICAL: [&str; 4] = ["Align Top", "Align Center", "Align Bottom", "Justify Vertically"];
|
||||
for (case, texts) in [("point type", vec![point(20)]), ("area type", vec![area]), ("two objects", vec![point(20), point(300)])] {
|
||||
let mut app = control_bar_app(&texts);
|
||||
// Each group of controls in the bar's order, by its first and last control.
|
||||
let mut groups: Vec<(&str, Vec<&str>)> = vec![("link", vec!["Paragraph:"]), ("buttons", BAR_ALIGNMENTS.to_vec())];
|
||||
if case == "area type" {
|
||||
groups.push(("vertical alignment", VERTICAL.to_vec()));
|
||||
}
|
||||
groups.push(("Align", vec!["Horizontal Align Left", "Vertical Align Bottom"]));
|
||||
if case == "two objects" {
|
||||
groups.push(("Distribute", vec!["Vertical Distribute Top", "Horizontal Distribute Right"]));
|
||||
}
|
||||
groups.push(("X/Y/W/H", vec!["X:", "H:"]));
|
||||
let mut seen = vec![false; groups.len()];
|
||||
for width in (600..=2400).step_by(10) {
|
||||
let nodes = control_bar_nodes(&ctx, &mut app, width as f32, vec![]);
|
||||
let inside = |x: f64| x <= f64::from(width) - 10.0;
|
||||
let shown: Vec<bool> = groups
|
||||
.iter()
|
||||
.map(|(group, names)| {
|
||||
let ends: Vec<Option<f64>> = names.iter().map(|n| control_bar_end(&nodes, n)).collect();
|
||||
assert!(ends.iter().all(Option::is_some) || ends.iter().all(Option::is_none), "{case}, {width}: {group} {ends:?}");
|
||||
if let Some(Some(end)) = ends.last() {
|
||||
assert!(inside(*end), "{case}, {width}: {group} ends at {end}");
|
||||
}
|
||||
ends.iter().all(Option::is_some)
|
||||
})
|
||||
.collect();
|
||||
// Narrower bars are already full before the section (the Character controls).
|
||||
let transform = control_bar_end(&nodes, "Transform");
|
||||
assert!(!shown[0] || transform.is_some_and(inside), "{case}, {width}: Transform ends at {transform:?}");
|
||||
for (i, ((group, _), on)) in groups.iter().zip(&shown).enumerate() {
|
||||
assert!(!seen[i] || *on, "{case}, {width}: {group} left out after a narrower bar showed it");
|
||||
assert!(!*on || shown[..i].iter().all(|s| *s), "{case}, {width}: {group} shows while a group before it is left out");
|
||||
seen[i] |= on;
|
||||
}
|
||||
}
|
||||
assert!(seen.iter().all(|s| *s), "{case}: a wide bar shows every group: {seen:?}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -461,14 +461,23 @@ pub(crate) fn polygon_rows(app: &mut VectorcraftApp, ui: &mut Ui, n: &Node, live
|
||||
/// The Control bar's underlined "Transform" link: a click toggles the Transform panel in a
|
||||
/// popover under it, as the Stroke link does with the Stroke panel.
|
||||
pub fn link(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
let t = Tokens::get(ui.ctx());
|
||||
let resp = ui.link(egui::RichText::new(tl!("Transform")).size(12.0).color(t.text).underline()).on_hover_text(tl!("Transform options"));
|
||||
let resp = ui.link(link_text(ui)).on_hover_text(tl!("Transform options"));
|
||||
widgets::popover(&resp, resp.clicked(), |ui| {
|
||||
ui.set_width(300.0);
|
||||
show(app, ui);
|
||||
});
|
||||
}
|
||||
|
||||
/// The Transform link's text, as [`link`] draws it and [`link_width`] measures it.
|
||||
fn link_text(ui: &Ui) -> egui::RichText {
|
||||
egui::RichText::new(tl!("Transform")).size(12.0).color(Tokens::get(ui.ctx()).text).underline()
|
||||
}
|
||||
|
||||
/// The width of the Transform [`link`] in `ui`.
|
||||
pub fn link_width(ui: &Ui) -> f32 {
|
||||
widgets::text_width(ui, link_text(ui))
|
||||
}
|
||||
|
||||
/// The width and height of [`constrain_link`]'s button.
|
||||
pub const CONSTRAIN_LINK_SIZE: f32 = 22.0;
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ pub use dropdowns::{
|
||||
panel_scroll, popover, set_menu_floor, strip_scroll,
|
||||
};
|
||||
pub use labels::{dim_label, dim_name, divider, field_label, label_row, link_label, section_header, section_toggle, section_toggle_name, subheader};
|
||||
pub(crate) use labels::{label_field, take_previous_label};
|
||||
pub(crate) use labels::{label_field, take_previous_label, text_width};
|
||||
pub(crate) use numeric::{ANY, round_to, set_bare_numbers_are_points, typed_unit};
|
||||
pub use numeric::{
|
||||
SpinPick, mixed_field, mixed_field_named, num_field, num_field_live, num_field_named, num_field_within, num_field_within_empty, opt_field,
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
use super::{Pos2, Rect, Response, Sense, Stroke, Tokens, Ui, icons, pos2, scrub, theme, vec2};
|
||||
|
||||
/// The width `text` takes on one line, as a label or link in `ui` draws it: its galley, which has
|
||||
/// no padding around it.
|
||||
pub(crate) fn text_width(ui: &Ui, text: egui::RichText) -> f32 {
|
||||
egui::WidgetText::from(text).into_galley(ui, Some(egui::TextWrapMode::Extend), f32::INFINITY, egui::TextStyle::Body).size().x
|
||||
}
|
||||
|
||||
/// Bold section header (Properties panel).
|
||||
pub fn section_header(ui: &mut Ui, text: &str) {
|
||||
let t = Tokens::get(ui.ctx());
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Parity with Adobe Illustrator
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-05 · **Change:** minor (large images in CMYK documents are shrunk before they are separated into ink planes (#4155); scores and estimates unchanged; Libraries panel colours keep their spot ink in every document, #5812; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x; public release notes through 30.7, August 2026)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-06 · **Change:** minor (Control bar Paragraph section with type selected, #5372; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x; public release notes through 30.7, August 2026)
|
||||
|
||||
## Feature submission evidence
|
||||
|
||||
@@ -1672,6 +1672,10 @@ While a corner widget is pressed or dragged with the Selection or Direct Selecti
|
||||
|
||||
A double-click on a Repeat (Radial, Grid or Mirror) with the Selection tool enters isolation mode on it ([isolate objects](https://helpx.adobe.com/illustrator/desktop/manage-objects/select-objects/isolate-objects.html): a double-click with the Selection tool isolates an object; [repeat patterns overview](https://helpx.adobe.com/illustrator/desktop/paint-and-fill/create-and-edit-patterns/repeat-patterns-overview.html): every instance follows edits to the original object); there the source art is selected and edited as usual (a double-click on type in it switches to the Type tool on that text) and every copy follows, with the repeat's settings kept (#5054). Test: `tests::repeat_edit::a_double_click_on_a_repeat_isolates_it_to_edit_its_text`.
|
||||
|
||||
## Control bar: Paragraph section while type is selected (2026-11-06)
|
||||
|
||||
With type selected, the Control bar shows a Paragraph: link and the Align left, Align center and Align right buttons after its Character controls, as the public documentation has the Control panel format paragraphs while the Type tool is in use, with a way to the Paragraph panel ([Paragraph panel overview](https://helpx.adobe.com/illustrator/using/formatting-paragraphs.html)), and its alignment buttons align text as the Paragraph panel's do ([Align text](https://helpx.adobe.com/illustrator/using/align-text.html)). A button aligns the selected type (`text.setStyle {justify}`, one undo step) and the shared alignment shows selected; the link opens the Paragraph panel in a popover under it, as Character: opens the Character panel. Keeping to the three alignments that don't justify is our choice, for the bar's room; the popover has all seven. Short of room the bar leaves controls out from its right end: the inline X/Y/W/H fields, the Distribute and Align buttons, area type's vertical alignment, then these buttons and last the link, keeping room for the Transform link; on a 1440 pt bar with one point type object, the buttons show (pinned by a headless test, #5372).
|
||||
|
||||
## Area type: vertical alignment in the Properties and Control panels (2026-11-04)
|
||||
|
||||
With area type selected, the Properties panel's Paragraph section and the Control panel show Align Top, Align Center, Align Bottom and Justify Vertically buttons, as the public documentation places them ([Align text](https://helpx.adobe.com/illustrator/desktop/design-with-text/edit-format-text/align-text.html)). They set the type's vertical alignment in its frame (`text.areaOptions {verticalAlign}`, as Area Type Options does) on every selected frame in one undo step, each frame keeping its other options; the shared alignment shows selected, none when the frames differ (#3759). As that page limits vertical alignment to area type without rows, columns or threads, the buttons are turned off while a selected frame has rows or columns or is threaded; Area Type Options and `text.areaOptions` still align each row/column cell (a VectorCraft extension, unchanged here). Tests: `panels::properties::tests::vertical_alignment_buttons_align_the_selected_area_type`.
|
||||
@@ -1684,6 +1688,7 @@ Edit › Copy and Cut put the selected ruler guides on the clipboard, with the s
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-11-06 | minor | Control bar: Paragraph: link and Align left/center/right while type is selected, trimmed from the bar's right end after X/Y/W/H and the Align buttons (#5372); evidence added; scores unchanged. |
|
||||
| 2026-11-04 | minor | Contour add-on (beyond Illustrator): drag away from a selected shape's edge to grow a live copy of it, or toward the inside to shrink it; the copy carries a live Offset Path effect, so it stays editable until Bake (Expand Appearance), a second drag changes the same Contour instead of nesting one, and a floating bar sets the distance and the Sharp, Round or Square corners. `addon.contour.set` is the command behind it. It is a built-in add-on: Object › Plug-ins › Contour, and its own heading in All Tools, with no default shortcut or toolbar slot. A VectorCraft design built on Offset Path; no other application was inspected. Scores and estimates unchanged. |
|
||||
| 2026-11-04 | minor | Contour tool (beyond Illustrator): drag away from a selected shape's edge to grow a live copy of it, or toward the inside to shrink it; the copy carries a live Offset Path effect, so it stays editable until Bake (Expand Appearance), a second drag changes the same Contour instead of nesting one, and a floating bar sets the distance and the Sharp, Round or Square corners. `object.contour` is the command behind it. A VectorCraft design built on Offset Path; no other application was inspected. Scores and estimates unchanged. |
|
||||
| 2026-11-05 | minor | View & navigation: document tabs are reordered by dragging them along the tab strip (`document.move`, #5663); evidence added; scores unchanged. |
|
||||
|
||||
+3
-1
@@ -1,6 +1,6 @@
|
||||
# UI and interaction parity
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-05 · **Change:** minor (Effect dialogs: a colour swatch beside a hex colour opens the Color Picker, #5365; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x; Units › East Asian Type acts, with Q and Ha units; scores unchanged)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-06 · **Change:** minor (Control bar: Paragraph: link and Align left/center/right while type is selected, #5372; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x; Units › East Asian Type acts, with Q and Ha units; scores unchanged)
|
||||
|
||||
## Feature submission evidence
|
||||
|
||||
@@ -359,6 +359,7 @@ next unit in the order a right-click on a ruler lists them, from Feet back to Po
|
||||
| Select › Start Global Edit / Stop Global Edit; Properties › Quick Actions with the Global Edit Options popover (Match: Appearance, Size; On Artboards: All Artboards or a range, Include Objects On Canvas; Result(s)); Escape stops it; the matched objects are highlighted in their layer colour while it runs; a Shift-click on a highlighted match leaves it out | partial | #3521, `select.globalEdit` / `select.globalEditOptions` / `select.globalEditExclude`, `crates/engine/src/tests/globaledit.rs`; paths, compound paths, symbol instances and groups of them (similar groups, #4939: edits inside one group reach the same object in the others; [public source](https://helpx.adobe.com/illustrator/desktop/manage-objects/edit-objects/edit-groups-with-similar-objects.html)); Shift-click to leave a match out ([public source](https://helpx.adobe.com/ph_fil/illustrator/how-to/global-editing-sensei.html)); the Control bar's Global Edit Options dropdown opens the same options; rotated copies and highlighting matches before the start remain ([public source](https://helpx.adobe.com/illustrator/desktop/manage-objects/edit-objects/edit-similar-objects.html)) |
|
||||
| Contextual task bar | done | |
|
||||
| Control bar with Transform and Stroke popovers | done | |
|
||||
| Control bar: Paragraph: link and Align left/center/right while type is selected (#5372) | done | After the Character controls, as the public documentation has the Control panel format paragraphs ([Paragraph panel overview](https://helpx.adobe.com/illustrator/using/formatting-paragraphs.html), [Align text](https://helpx.adobe.com/illustrator/using/align-text.html)); the link opens the Paragraph panel in a popover, as Character: does with the Character panel. The bar trims from its right end: X/Y/W/H, Distribute, Align, area type vertical alignment, then these buttons, then the link. The three-button set is our choice for room; all seven alignments are in the popover. `panels/paragraph/tests.rs` headless tests (`the_control_bar_shows_the_paragraph_alignment_of_the_selected_type`, `the_control_bar_trims_its_paragraph_section_after_the_controls_to_its_right`) |
|
||||
| Pathfinder shape results keep their source names and SVG IDs | done | #1293; Minus Front keeps the back name, Minus Back the front name; Unite/Intersect/Exclude use the backmost named input; compound output carries it once; geometry and paint unchanged |
|
||||
| Attributes fill-rule controls with a compound member selected | done | Edits the compound's rule; direction still edits only the member; rendered-hole and Undo/Redo regression tests (#1197) |
|
||||
| Make Compound Path on a group (such as outlined type) keeps its backmost path's paint; compound paths joined into one keep their holes | done | #1537 |
|
||||
@@ -456,6 +457,7 @@ separate. Scores and hours unchanged. [Behavior and command details](development
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-11-06 | minor | Control bar: with type selected, a Paragraph: link (the Paragraph panel in a popover) and the Align left, Align center and Align right buttons follow the Character controls; the bar leaves them out from its right end when short of room, after X/Y/W/H and the Align buttons (#5372); scores and estimates unchanged |
|
||||
| 2026-11-04 | minor | Contour add-on (beyond Illustrator): drag away from a selected shape's edge to grow a live copy of it, or toward the inside to shrink it; the copy carries a live Offset Path effect, so it stays editable until Bake (Expand Appearance), a second drag changes the same Contour instead of nesting one, and a floating bar sets the distance and the Sharp, Round or Square corners. `addon.contour.set` is the command behind it. It is a built-in add-on: Object › Plug-ins › Contour, and its own heading in All Tools, with no default shortcut or toolbar slot. A VectorCraft design built on Offset Path; no other application was inspected. Scores and estimates unchanged. |
|
||||
| 2026-11-04 | minor | Contour tool (beyond Illustrator): drag away from a selected shape's edge to grow a live copy of it, or toward the inside to shrink it; the copy carries a live Offset Path effect, so it stays editable until Bake (Expand Appearance), a second drag changes the same Contour instead of nesting one, and a floating bar sets the distance and the Sharp, Round or Square corners. `object.contour` is the command behind it. A VectorCraft design built on Offset Path; no other application was inspected. Scores and estimates unchanged. |
|
||||
| 2026-11-05 | minor | Document tabs are reordered by dragging them along the tab strip (`document.move`, #5663). |
|
||||
|
||||
Reference in New Issue
Block a user