From 41dda1029f81da8c799b2ee6a935ca64651fd298 Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Thu, 29 Oct 2026 20:48:21 +0700 Subject: [PATCH] Character: Cmd/Ctrl+Alt+K highlights the kerning and Cmd/Ctrl+Alt+Shift+F highlights the font name Squashed from #4390 onto main. --- crates/ui-egui/src/app.rs | 1 + crates/ui-egui/src/i18n/bg.tsv | 3 + crates/ui-egui/src/i18n/cs.tsv | 3 + crates/ui-egui/src/i18n/da.tsv | 3 + crates/ui-egui/src/i18n/de.tsv | 3 + crates/ui-egui/src/i18n/el.tsv | 3 + crates/ui-egui/src/i18n/es.tsv | 3 + crates/ui-egui/src/i18n/fi.tsv | 3 + crates/ui-egui/src/i18n/fr.tsv | 3 + crates/ui-egui/src/i18n/hu.tsv | 3 + crates/ui-egui/src/i18n/id.tsv | 3 + crates/ui-egui/src/i18n/it.tsv | 3 + crates/ui-egui/src/i18n/ja.tsv | 3 + crates/ui-egui/src/i18n/ka.tsv | 3 + crates/ui-egui/src/i18n/ko.tsv | 3 + crates/ui-egui/src/i18n/nl.tsv | 3 + crates/ui-egui/src/i18n/pl.tsv | 3 + crates/ui-egui/src/i18n/pt-br.tsv | 3 + crates/ui-egui/src/i18n/ru.tsv | 3 + crates/ui-egui/src/i18n/sv.tsv | 3 + crates/ui-egui/src/i18n/tr.tsv | 3 + crates/ui-egui/src/i18n/uk.tsv | 3 + crates/ui-egui/src/i18n/vi.tsv | 3 + crates/ui-egui/src/i18n/zh-hans.tsv | 3 + crates/ui-egui/src/i18n/zh-hant.tsv | 3 + crates/ui-egui/src/lib.rs | 3 + crates/ui-egui/src/menus/run.rs | 3 + crates/ui-egui/src/menus/ui_commands.rs | 18 ++++++ crates/ui-egui/src/panel_docking/tests.rs | 19 +++++++ crates/ui-egui/src/panels/character.rs | 58 ++++++++++++++++++++ crates/ui-egui/src/panels/character/tests.rs | 50 +++++++++++++++++ crates/ui-egui/src/shortcuts/tests.rs | 33 +++++++++++ crates/ui-egui/src/widgets.rs | 4 +- crates/ui-egui/src/widgets/dropdowns.rs | 10 +++- crates/ui-egui/src/widgets/numeric.rs | 15 ++++- crates/ui-egui/src/widgets/text.rs | 37 +++++++++++++ docs/mcp.md | 6 +- docs/target-app-parity.md | 1 + 38 files changed, 325 insertions(+), 5 deletions(-) diff --git a/crates/ui-egui/src/app.rs b/crates/ui-egui/src/app.rs index e117cdefe..925936c06 100644 --- a/crates/ui-egui/src/app.rs +++ b/crates/ui-egui/src/app.rs @@ -79,6 +79,7 @@ impl VectorcraftApp { titlebar_inset: 0.0, last_effect: None, last_warp: None, + character_focus: None, run_count: 0, clipboard_out: None, clipboard_published: None, diff --git a/crates/ui-egui/src/i18n/bg.tsv b/crates/ui-egui/src/i18n/bg.tsv index 3f21100a6..484cd977f 100644 --- a/crates/ui-egui/src/i18n/bg.tsv +++ b/crates/ui-egui/src/i18n/bg.tsv @@ -5292,6 +5292,9 @@ theme Appearance Външен вид # Type › Reset Tracking and Kerning Reset Tracking and Kerning Нулиране на разредката и кернинга Reset Horizontal Scale Нулиране на хоризонталния мащаб + Highlight Font Name Маркиране на името на шрифта + Highlight Kerning Маркиране на кернинга + Highlight Tracking Маркиране на разредката @msg span must be "object" or "selection", got {v} span трябва да е "object" или "selection", а не {v} @msg span: "selection" places a `gradient`, not a swatch span: "selection" поставя `gradient`, а не мостра @msg span: "selection" places a gradient: give `gradient` span: "selection" поставя градиент: задайте `gradient` diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index 7826cb9da..c0bedee88 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -3781,6 +3781,9 @@ axis Both Obě Increase Font Size by Five Steps Zvětšit velikost písma o pět kroků Reset Tracking and Kerning Obnovit prostrkání a vyrovnání párů Reset Horizontal Scale Obnovit vodorovnou změnu velikosti + Highlight Font Name Zvýraznit název písma + Highlight Kerning Zvýraznit vyrovnání párů + Highlight Tracking Zvýraznit prostrkání Step Type Krokovat text Get Text Range Získat rozsah textu Punctuation Interpunkce diff --git a/crates/ui-egui/src/i18n/da.tsv b/crates/ui-egui/src/i18n/da.tsv index 2d598e354..456effa9e 100644 --- a/crates/ui-egui/src/i18n/da.tsv +++ b/crates/ui-egui/src/i18n/da.tsv @@ -5062,6 +5062,9 @@ mark-style Japanese Japansk Panels Except Tools and Control Paneler undtagen værktøjer og kontrol Reset Tracking and Kerning Nulstil sporing og kerning Reset Horizontal Scale Nulstil vandret skalering + Highlight Font Name Fremhæv skrifttypenavn + Highlight Kerning Fremhæv kerning + Highlight Tracking Fremhæv sporing @msg span must be "object" or "selection", got {v} span skal være "object" eller "selection", fik {v} @msg span: "selection" places a `gradient`, not a swatch span: "selection" placerer en `gradient`, ikke en farveprøve @msg span: "selection" places a gradient: give `gradient` span: "selection" placerer en overgang: angiv `gradient` diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index d7ac88702..7f4f154b6 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -1126,6 +1126,9 @@ font-technology Variable Variabel Increase Font Size by Five Steps Schriftgrad um fünf Schritte erhöhen Reset Tracking and Kerning Laufweite und Kerning zurücksetzen Reset Horizontal Scale Horizontale Skalierung zurücksetzen + Highlight Font Name Schriftname hervorheben + Highlight Kerning Kerning hervorheben + Highlight Tracking Laufweite hervorheben Spacing Abstand Step Type Text schrittweise ändern Fit in View In Ansicht einpassen diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index ab586128a..a16caa6d2 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -5281,6 +5281,9 @@ effect Points Σημεία Registration: Σημείο αναφοράς: Reset Horizontal Scale Επαναφορά οριζόντιας κλίμακας Reset Tracking and Kerning Επαναφορά απόστασης χαρακτήρων και διαγραμμάτωσης + Highlight Font Name Επισήμανση ονόματος γραμματοσειράς + Highlight Kerning Επισήμανση διαγραμμάτωσης + Highlight Tracking Επισήμανση απόστασης χαρακτήρων Sample Color from Screen Δειγματοληψία χρώματος από την οθόνη Set as Default Ορισμός ως προεπιλογή Show Template Εμφάνιση προτύπου diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index 8f8e20923..9f60571d8 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -1149,6 +1149,9 @@ font-technology Variable Variables Increase Font Size by Five Steps Aumentar tamaño de fuente en cinco incrementos Reset Tracking and Kerning Restablecer espaciado e interletraje Reset Horizontal Scale Restablecer escala horizontal + Highlight Font Name Resaltar nombre de fuente + Highlight Kerning Resaltar interletraje + Highlight Tracking Resaltar espaciado Spacing Espaciado Step Type Ajustar texto por incrementos Fit in View Encajar en la vista diff --git a/crates/ui-egui/src/i18n/fi.tsv b/crates/ui-egui/src/i18n/fi.tsv index 9cf3a61d1..3652a1ded 100644 --- a/crates/ui-egui/src/i18n/fi.tsv +++ b/crates/ui-egui/src/i18n/fi.tsv @@ -5293,6 +5293,9 @@ mark-style Japanese Japanilainen Registration: Kohdistuspiste: Reset Horizontal Scale Palauta vaakaskaalaus Reset Tracking and Kerning Palauta merkkiväli ja parivälistys + Highlight Font Name Korosta fontin nimi + Highlight Kerning Korosta parivälistys + Highlight Tracking Korosta merkkiväli Sample Color from Screen Poimi väri näytöltä Set as Default Aseta oletukseksi Show Template Näytä mallipohja diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index bac79e522..5b40ecc04 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -1148,6 +1148,9 @@ font-technology Variable Variables Increase Font Size by Five Steps Augmenter la taille de police de cinq incréments Reset Tracking and Kerning Réinitialiser l’approche et le crénage Reset Horizontal Scale Réinitialiser la mise à l’échelle horizontale + Highlight Font Name Surligner le nom de la police + Highlight Kerning Surligner le crénage + Highlight Tracking Surligner l’approche Spacing Espacement Step Type Texte par incréments Fit in View Ajuster à la vue diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index 9a9bd55e3..4fa75f7ab 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -3201,6 +3201,9 @@ mark-style Japanese Japán Reset to White, Black Visszaállítás fehér–fekete átmenetre Reset Tracing Tracing visszaállítása Reset Tracking and Kerning Betűköz és alávágás visszaállítása + Highlight Font Name Betűtípusnév kiemelése + Highlight Kerning Alávágás kiemelése + Highlight Tracking Betűköz kiemelése Reset Typography Typography visszaállítása Reset Web Web visszaállítása Reset with Mesh Visszaállítás hálóval diff --git a/crates/ui-egui/src/i18n/id.tsv b/crates/ui-egui/src/i18n/id.tsv index 2062f2e9b..e5d2a8dcc 100644 --- a/crates/ui-egui/src/i18n/id.tsv +++ b/crates/ui-egui/src/i18n/id.tsv @@ -5062,6 +5062,9 @@ mark-style Japanese Jepang Panels Except Tools and Control Semua panel kecuali Alat dan Kontrol Reset Tracking and Kerning Atur ulang tracking dan kerning Reset Horizontal Scale Atur ulang skala horizontal + Highlight Font Name Sorot nama font + Highlight Kerning Sorot kerning + Highlight Tracking Sorot tracking @msg span must be "object" or "selection", got {v} span harus "object" atau "selection", diterima {v} @msg span: "selection" places a `gradient`, not a swatch span: "selection" menempatkan `gradient`, bukan swatch @msg span: "selection" places a gradient: give `gradient` span: "selection" menempatkan gradien: berikan `gradient` diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index 72813720c..633333518 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -1149,6 +1149,9 @@ font-technology Variable Variabili Increase Font Size by Five Steps Aumenta dimensione font di cinque incrementi Reset Tracking and Kerning Reimposta spaziatura caratteri e crenatura Reset Horizontal Scale Reimposta scala orizzontale + Highlight Font Name Evidenzia nome del font + Highlight Kerning Evidenzia crenatura + Highlight Tracking Evidenzia spaziatura caratteri Spacing Spaziatura Step Type Dimensione testo a incrementi Fit in View Adatta alla vista diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index b3e46eb70..50aea26ac 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -380,6 +380,9 @@ font-technology Variable バリアブル Increase Font Size by Five Steps フォントサイズを5段階大きく Reset Tracking and Kerning トラッキングとカーニングをリセット Reset Horizontal Scale 水平比率をリセット + Highlight Font Name フォント名をハイライト + Highlight Kerning カーニングをハイライト + Highlight Tracking トラッキングをハイライト Step Type 文字を段階的に調整 Find Font… フォントの検索と置換… Change Case 大文字と小文字の変更 diff --git a/crates/ui-egui/src/i18n/ka.tsv b/crates/ui-egui/src/i18n/ka.tsv index 5d574007c..8aa55ab24 100644 --- a/crates/ui-egui/src/i18n/ka.tsv +++ b/crates/ui-egui/src/i18n/ka.tsv @@ -4924,6 +4924,9 @@ imageTrace Outline კონტური The active document changed while the screen color sampler was open აქტიური დოკუმენტი შეიცვალა, სანამ ეკრანიდან ფერის აღება ღია იყო Keep selected მონიშნულად დატოვება Reset Tracking and Kerning ტრეკინგისა და კერნინგის ჩამოყრა + Highlight Font Name შრიფტის სახელის გამოკვეთა + Highlight Kerning კერნინგის გამოკვეთა + Highlight Tracking ტრეკინგის გამოკვეთა Legacy (version 7) ძველი (ვერსია 7) Transparent Images: გამჭვირვალე გამოსახულებები: Flatten გაბრტყელება diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index 2a3ddda7b..3ce7cd48b 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -376,6 +376,9 @@ font-technology Variable 가변 Increase Font Size by Five Steps 글꼴 크기 5단계 키우기 Reset Tracking and Kerning 자간 및 커닝 재설정 Reset Horizontal Scale 가로 비율 재설정 + Highlight Font Name 글꼴 이름 강조 표시 + Highlight Kerning 커닝 강조 표시 + Highlight Tracking 자간 강조 표시 Step Type 단계별 문자 Find Font… 글꼴 찾기… Change Case 대소문자 변경 diff --git a/crates/ui-egui/src/i18n/nl.tsv b/crates/ui-egui/src/i18n/nl.tsv index 7c8ecfcec..7073591f3 100644 --- a/crates/ui-egui/src/i18n/nl.tsv +++ b/crates/ui-egui/src/i18n/nl.tsv @@ -5074,6 +5074,9 @@ mark-style Japanese Japans Panels Except Tools and Control Alle panelen behalve Gereedschap en Bediening Reset Tracking and Kerning Tracking en kerning herstellen Reset Horizontal Scale Horizontale schaal herstellen + Highlight Font Name Lettertypenaam markeren + Highlight Kerning Kerning markeren + Highlight Tracking Tracking markeren @msg span must be "object" or "selection", got {v} span moet "object" of "selection" zijn, maar is {v} @msg span: "selection" places a `gradient`, not a swatch span: "selection" plaatst een `gradient`, geen staal @msg span: "selection" places a gradient: give `gradient` span: "selection" plaatst een verloop: geef `gradient` diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index 62fd5f8f9..841af59a7 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -3623,6 +3623,9 @@ axis Both Obie Increase Font Size by Five Steps Zwiększ rozmiar czcionki o pięć kroków Reset Tracking and Kerning Resetuj światło i kerning Reset Horizontal Scale Resetuj skalę poziomą + Highlight Font Name Wyróżnij nazwę czcionki + Highlight Kerning Wyróżnij kerning + Highlight Tracking Wyróżnij światło Step Type Krok tekstu Get Text Range Pobierz zakres tekstu Punctuation Interpunkcja diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index dc682911a..8e014227f 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -1020,6 +1020,9 @@ Increase Font Size by Five Steps Aumentar Tamanho da Fonte em Cinco Incrementos Reset Tracking and Kerning Redefinir Rastreamento e Kerning Reset Horizontal Scale Redefinir Escala Horizontal + Highlight Font Name Destacar Nome da Fonte + Highlight Kerning Destacar Kerning + Highlight Tracking Destacar Rastreamento Step Type Ajustar Texto em Incrementos Fit dashes to corners and ends Ajustar tracejados aos cantos e extremidades Fit in Window Ajustar na Janela diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index f73c45105..b7bcaadb4 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -1147,6 +1147,9 @@ font-technology Variable Вариативные Increase Font Size by Five Steps Увеличить размер шрифта на пять шагов Reset Tracking and Kerning Сбросить трекинг и кернинг Reset Horizontal Scale Сбросить масштаб по горизонтали + Highlight Font Name Выделить имя шрифта + Highlight Kerning Выделить кернинг + Highlight Tracking Выделить трекинг Spacing Интервал Step Type Подгонять текст по шагам Fit in View Вписать в вид diff --git a/crates/ui-egui/src/i18n/sv.tsv b/crates/ui-egui/src/i18n/sv.tsv index b7c0c88b7..23383f138 100644 --- a/crates/ui-egui/src/i18n/sv.tsv +++ b/crates/ui-egui/src/i18n/sv.tsv @@ -5285,6 +5285,9 @@ theme Appearance Utseende Registration: Registreringspunkt: Reset Horizontal Scale Återställ horisontell skala Reset Tracking and Kerning Återställ spärrning och kerning + Highlight Font Name Framhäv typsnittsnamn + Highlight Kerning Framhäv kerning + Highlight Tracking Framhäv spärrning Sample Color from Screen Hämta färg från skärmen Set as Default Ange som standard Show Template Visa mall diff --git a/crates/ui-egui/src/i18n/tr.tsv b/crates/ui-egui/src/i18n/tr.tsv index c171ded99..7b89cc3c9 100644 --- a/crates/ui-egui/src/i18n/tr.tsv +++ b/crates/ui-egui/src/i18n/tr.tsv @@ -1108,6 +1108,9 @@ font-technology Variable Değişken Increase Font Size by Five Steps Yazı Tipi Boyutunu Beş Adım Artırın Reset Tracking and Kerning Takip ve Karakter Aralığını Sıfırla Reset Horizontal Scale Yatay Ölçeği Sıfırla + Highlight Font Name Yazı Tipi Adını Vurgula + Highlight Kerning Karakter Aralığını Vurgula + Highlight Tracking Takibi Vurgula Spacing Aralık Step Type Adım Türü Fit in View Görünüme Sığdır diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index f3bc6ec3b..8201813c4 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -1143,6 +1143,9 @@ font-technology Variable Варіативні Increase Font Size by Five Steps Збільшити розмір шрифту на п’ять кроків Reset Tracking and Kerning Скинути трекінг і кернінг Reset Horizontal Scale Скинути масштаб по горизонталі + Highlight Font Name Виділити назву шрифту + Highlight Kerning Виділити кернінг + Highlight Tracking Виділити трекінг Spacing Інтервал Step Type Підганяти текст кроками Fit in View Вписати у вигляд diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index 5b6dbe919..64fc5dd66 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -2962,6 +2962,9 @@ mark-style Japanese Kiểu Nhật Reset to default Đặt lại về mặc định Reset to White, Black Đặt lại về Trắng, Đen Reset Tracking and Kerning Đặt lại giãn chữ và kerning + Highlight Font Name Đánh dấu tên phông + Highlight Kerning Đánh dấu kerning + Highlight Tracking Đánh dấu giãn chữ Reset with Mesh Đặt lại với lưới Reset with Mesh… Đặt lại với lưới… Reset with Warp Đặt lại với biến dạng diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index 292a14d4b..e3c10b9e0 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -1089,6 +1089,9 @@ Increase Font Size by Five Steps 按五个增量增大字体大小 Reset Tracking and Kerning 重置字距和字偶距 Reset Horizontal Scale 重置水平缩放 + Highlight Font Name 突出显示字体名称 + Highlight Kerning 突出显示字偶距 + Highlight Tracking 突出显示字距 Spacing 间距 Step Type 按增量调整文字 Fit in View 适合视图 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index 1e495ac08..4e1670624 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -1114,6 +1114,9 @@ font-technology Variable 可變 Increase Font Size by Five Steps 按五個增量放大字體大小 Reset Tracking and Kerning 重設字距與字距微調 Reset Horizontal Scale 重設水平縮放 + Highlight Font Name 反白顯示字體名稱 + Highlight Kerning 反白顯示字距微調 + Highlight Tracking 反白顯示字距 Spacing 間距 Step Type 依增量調整文字 Fit in View 符合檢視 diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index 0262a21ec..88177849e 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -125,6 +125,9 @@ pub struct VectorcraftApp { pub last_effect: Option<(String, serde_json::Value)>, /// Last confirmed Warp Options (bend, distortion, orientation) for the next new warp dialog. pub last_warp: Option, + /// The Character panel field that takes the keyboard focus when the panel next draws it + /// ([`panels::character::highlight`]). + pub(crate) character_focus: Option, /// Commands run through [`Self::run`] so far: the native menu bar reads its rows again when it /// moves ([`native_menu::sync`]). run_count: u64, diff --git a/crates/ui-egui/src/menus/run.rs b/crates/ui-egui/src/menus/run.rs index 53a5a6ad6..10cb2f44a 100644 --- a/crates/ui-egui/src/menus/run.rs +++ b/crates/ui-egui/src/menus/run.rs @@ -236,6 +236,9 @@ fn run_ui_part3(app: &mut VectorcraftApp, id: &str, p: &Value) -> Option flag(&mut app.ui.view.hidden_chars), "type.bold" => crate::panels::character::toggle_face(app, Face::Bold), "type.italic" => crate::panels::character::toggle_face(app, Face::Italic), + "type.highlightFontName" => crate::panels::character::highlight(app, crate::panels::character::Field::FontName), + "type.highlightKerning" => crate::panels::character::highlight(app, crate::panels::character::Field::Kerning), + "type.highlightTracking" => crate::panels::character::highlight(app, crate::panels::character::Field::Tracking), id if let Some((_, justify)) = crate::panels::paragraph::ALIGN_COMMANDS.iter().find(|c| c.0 == id) => { crate::panels::paragraph::align(app, justify) } diff --git a/crates/ui-egui/src/menus/ui_commands.rs b/crates/ui-egui/src/menus/ui_commands.rs index 5022acc5f..99aed8cad 100644 --- a/crates/ui-egui/src/menus/ui_commands.rs +++ b/crates/ui-egui/src/menus/ui_commands.rs @@ -318,6 +318,24 @@ pub const UI_COMMANDS: &[(&str, &str, &str, &str)] = &[ "", "{} the selected type (or the Type tool's selection) in its family's Italic (or Oblique) face, or back upright when it is italic; keeps the weight. A family without that face is left as it is, with a message. While the Type tool edits text, Cmd+Shift+I", ), + ( + "type.highlightFontName", + "Highlight Font Name", + "Cmd+Alt+Shift+F", + "{} show the Character panel if it is hidden and open its font family menu, whose search field takes the keyboard focus: type to search, Enter applies the highlighted font → {field: \"fontName\"}. Without selected type (or text the Type tool edits) the panel shows, and the error says to select type first", + ), + ( + "type.highlightKerning", + "Highlight Kerning", + "Cmd+Alt+K", + "{} show the Character panel if it is hidden and give its Kerning field the keyboard focus with its value selected: type a value and press Enter → {field: \"kerning\"}. Without selected type (or text the Type tool edits) the panel shows, and the error says to select type first", + ), + ( + "type.highlightTracking", + "Highlight Tracking", + "", + "{} show the Character panel if it is hidden and give its Tracking field the keyboard focus with its value selected: type a value and press Enter → {field: \"tracking\"}. Without selected type (or text the Type tool edits) the panel shows, and the error says to select type first", + ), ("effect.last", "Last Effect…", "Cmd+Alt+Shift+E", "{} open the dialog of the last effect applied"), ("view.zoomIn", "Zoom In", "Cmd+=", "{}"), ("view.zoomOut", "Zoom Out", "Cmd+-", "{}"), diff --git a/crates/ui-egui/src/panel_docking/tests.rs b/crates/ui-egui/src/panel_docking/tests.rs index 097da2999..4bb77928b 100644 --- a/crates/ui-egui/src/panel_docking/tests.rs +++ b/crates/ui-egui/src/panel_docking/tests.rs @@ -156,6 +156,25 @@ fn a_tab_dragged_out_floats_and_comes_back_where_it_was_after_its_window_closes( assert!(h.tab("layers").is_some()); } +/// A Character field shortcut with the Character panel in front of its floating window brings +/// that window forward and leaves the panel showing. +#[test] +fn a_character_field_shortcut_brings_the_floating_character_panel_forward() { + let mut h = Harness::new(); + let id = h.app.run("text.create", json!({"x": 20, "y": 50, "text": "AVAX"})).unwrap()["id"].clone(); + h.app.run("select.set", json!({"ids": [id]})).unwrap(); + h.app.run("window.panel.float", json!({"panel": "character"})).unwrap(); + h.frame(vec![]); + assert!(showing(&h.app.ui, "character")); + assert_eq!(h.app.dock_rt.raise, None); + for command in ["type.highlightKerning", "type.highlightTracking", "type.highlightFontName"] { + h.app.run(command, json!({})).unwrap(); + assert_eq!(h.app.dock_rt.raise.as_deref(), Some("character"), "{command}"); + h.frame(vec![]); + assert!(showing(&h.app.ui, "character"), "{command} leaves the panel showing"); + } +} + #[test] fn the_dock_collapses_to_icons_and_back() { let mut h = Harness::new(); diff --git a/crates/ui-egui/src/panels/character.rs b/crates/ui-egui/src/panels/character.rs index 39fd16b9e..1c4c9399f 100644 --- a/crates/ui-egui/src/panels/character.rs +++ b/crates/ui-egui/src/panels/character.rs @@ -328,6 +328,55 @@ pub(crate) fn toggle_face(app: &mut VectorcraftApp, face: Face) -> Result &'static str { + match self { + Field::FontName => "ch-font", + Field::Kerning => "ch-kern", + Field::Tracking => "ch-track", + } + } + + fn name(self) -> &'static str { + match self { + Field::FontName => "fontName", + Field::Kerning => "kerning", + Field::Tracking => "tracking", + } + } +} + +/// `type.highlightFontName`, `type.highlightKerning` and `type.highlightTracking`: show the +/// Character panel if it is hidden (a shown one is activated, so its floating window comes +/// forward), and give `field` the keyboard focus when the panel next draws it, a number field with +/// its value selected (typing replaces it, Enter applies it). Without selected type or text the +/// Type tool edits, the panel shows, nothing takes the focus and the command fails. → `{field}`. +pub(crate) fn highlight(app: &mut VectorcraftApp, field: Field) -> Result { + // `window.panel` would hide a floating panel in front of its window, or an open flyout. + if crate::panel_docking::showing(&app.ui, "character") { + app.run("window.panel.activate", json!({"panel": "character"}))?; + } else { + app.run("window.panel", json!({"panel": "character"}))?; + } + if text_style(app).is_none() { + app.character_focus = None; + return Err("select some type first".into()); + } + app.character_focus = Some(field); + Ok(json!({ "field": field.name() })) +} + /// `text.setRangeStyle` with `p` on the range the Type tool has selected (the whole text when /// nothing is selected). Does nothing unless the Type tool edits text. pub(crate) fn range_style(app: &mut VectorcraftApp, p: Value) { @@ -713,15 +762,24 @@ pub(crate) fn control_bar(app: &mut VectorcraftApp, ui: &mut Ui) { pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) { let Some((s, _)) = text_style(app) else { + app.character_focus = None; super::empty_state(ui, "type", tl!("No text selected"), tl!("Select a text object to edit its character attributes.")); return; }; let w = ui.available_width(); + // The field a Highlight command asked for takes the focus as it is drawn. If no field took it + // (a sizing pass), the next frame tries again. + if let Some(f) = app.character_focus { + widgets::arm_field_focus(ui.ctx(), f.salt()); + } font_pickers(app, ui, &s, ("ch-font", "ch-style"), (w - 4.0, w - 4.0)); variable_font(app, ui, &s, w - 4.0); ui.add_space(2.0); let hidden = pstate::(ui.ctx(), "ch-hide-options"); metrics_grid(app, ui, "ch-grid", &s, w, !hidden); + if app.character_focus.is_some() && !widgets::disarm_field_focus(ui.ctx()) { + app.character_focus = None; + } if hidden { return; } diff --git a/crates/ui-egui/src/panels/character/tests.rs b/crates/ui-egui/src/panels/character/tests.rs index 53f55cef4..5058b5f57 100644 --- a/crates/ui-egui/src/panels/character/tests.rs +++ b/crates/ui-egui/src/panels/character/tests.rs @@ -130,6 +130,56 @@ fn kerning_at_a_caret_sets_the_pair_not_the_whole_text() { assert_eq!((kerning(&app, 1), kerning(&app, 2), kerning(&app, 3)), (Some(-50.0), Some(30.0), Some(30.0))); } +/// Highlight Kerning and Highlight Tracking show the Character panel and give its field the +/// keyboard focus with the value selected: what is typed replaces it, and Enter applies it. +/// Highlight Font Name opens the font family menu with its search field focused. Without +/// selected type the panel shows and nothing takes the focus. +#[test] +fn highlight_commands_focus_the_font_kerning_and_tracking_fields() { + let mut app = VectorcraftApp::new(Session::new(), Default::default()); + app.run("file.new", json!({"width": 300, "height": 200})).unwrap(); + let id = app.run("text.create", json!({"x": 20, "y": 50, "text": "AVAX", "size": 12})).unwrap()["id"].clone(); + let ctx = egui::Context::default(); + let frame = |app: &mut VectorcraftApp, events: Vec| { + let mut out = ctx.run_ui(egui::RawInput { events, ..Default::default() }, |ui| show(app, ui)); + out.textures_delta.clear(); + }; + let typed = |text: &str| { + let enter = egui::Event::Key { key: egui::Key::Enter, physical_key: None, pressed: true, repeat: false, modifiers: Default::default() }; + vec![egui::Event::Text(text.into()), enter] + }; + let spacing = |app: &VectorcraftApp| text_style(app).map(|(s, _)| (s.kerning, s.tracking)).unwrap(); + app.run("select.set", json!({"ids": [id]})).unwrap(); + assert_eq!(app.run("type.highlightKerning", json!({})).unwrap(), json!({"field": "kerning"})); + assert!(crate::panel_docking::showing(&app.ui, "character"), "the panel shows"); + frame(&mut app, vec![]); + assert_eq!(app.character_focus, None, "the Kerning field took the focus"); + frame(&mut app, typed("-40")); + assert_eq!(spacing(&app), (Some(-40.0), 0.0), "typing replaced the kerning"); + app.run("type.highlightTracking", json!({})).unwrap(); + frame(&mut app, vec![]); + frame(&mut app, typed("75")); + assert_eq!(spacing(&app), (Some(-40.0), 75.0), "typing replaced the tracking"); + // Highlighting a field again while it holds typed text that is not applied selects all of it. + app.run("type.highlightKerning", json!({})).unwrap(); + frame(&mut app, vec![]); + frame(&mut app, vec![egui::Event::Text("12345".into())]); + app.run("type.highlightKerning", json!({})).unwrap(); + frame(&mut app, vec![]); + frame(&mut app, typed("-20")); + assert_eq!(spacing(&app), (Some(-20.0), 75.0), "typing replaced the text typed before"); + ctx.memory_mut(|m| m.stop_text_input()); + app.run("type.highlightFontName", json!({})).unwrap(); + frame(&mut app, vec![]); + frame(&mut app, vec![]); + assert!(egui::Popup::is_any_open(&ctx), "the font family menu is open"); + assert!(ctx.memory(|m| m.focused()).is_some(), "its search field has the focus"); + // No type selected: the panel shows, the command fails and nothing is armed. + app.run("select.none", json!({})).unwrap(); + assert!(app.run("type.highlightKerning", json!({})).is_err()); + assert_eq!(app.character_focus, None); +} + /// A variable font gets the Variable Font button, which opens one slider per axis named as the /// font names it; a drag along one sets that axis of the selected type in one undo step. #[test] diff --git a/crates/ui-egui/src/shortcuts/tests.rs b/crates/ui-egui/src/shortcuts/tests.rs index 4d13e07d5..3779daf64 100644 --- a/crates/ui-egui/src/shortcuts/tests.rs +++ b/crates/ui-egui/src/shortcuts/tests.rs @@ -323,6 +323,39 @@ fn cmd_alt_q_resets_tracking_and_kerning() { assert_eq!(spacing(&mut app), [(json!("One "), json!(200.0), json!(-40.0)), (json!("Two"), json!(0.0), json!(null))]); } +/// Cmd+Alt+K highlights the Character panel's Kerning field and Cmd+Alt+Shift+F highlights its +/// font name field for the selected type, and Cmd+Alt+K also does so while the Type tool edits +/// text. Cmd+Alt+K does not open Preferences (Cmd+K). +#[test] +fn cmd_alt_k_and_cmd_alt_shift_f_highlight_the_character_fields() { + use crate::panels::character::Field; + let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), Default::default()); + app.session.execute("file.new", &json!({"width": 200, "height": 200})).unwrap(); + let id = app.session.execute("text.create", &json!({"x": 20, "y": 50, "text": "One Two"})).unwrap()["id"].as_u64().unwrap(); + let chord = |key, m| egui::Event::Key { key, physical_key: None, pressed: true, repeat: false, modifiers: m }; + app.session.execute("select.set", &json!({"ids": [id]})).unwrap(); + frame(&mut app, vec![chord(Key::K, Modifiers::COMMAND | Modifiers::ALT)]); + assert_eq!(app.character_focus, Some(Field::Kerning)); + assert!(app.ui.dialog.is_none(), "not Preferences"); + assert!(crate::panel_docking::showing(&app.ui, "character")); + frame(&mut app, vec![chord(Key::F, Modifiers::COMMAND | Modifiers::ALT | Modifiers::SHIFT)]); + assert_eq!(app.character_focus, Some(Field::FontName)); + // While the Type tool edits text. + app.character_focus = None; + app.select_tool("type"); + app.session.apply_actions(vec![vectorcraft_tools::Action::Notify("text.editNew".into())]).unwrap(); + app.session.set_tool_option("select", &json!({"start": 4, "end": 7})); + assert!(app.session.tool_wants_text()); + frame(&mut app, vec![chord(Key::K, Modifiers::COMMAND | Modifiers::ALT)]); + assert_eq!(app.character_focus, Some(Field::Kerning)); + assert!(app.ui.dialog.is_none(), "not Preferences"); + // Keyboard Shortcuts lists all three under Type; Highlight Tracking has no default key. + for id in ["type.highlightFontName", "type.highlightKerning", "type.highlightTracking"] { + assert_eq!(crate::shortcut_editor::entry(id).map(|e| e.group.as_str()), Some("Type"), "{id}"); + } + assert_eq!(crate::menus::shortcut_of("type.highlightTracking"), None); +} + /// Cmd+Shift+X resets the horizontal scale of the selected type to 100%, and of the Type /// tool's selected text while it edits. egui reports the chord as a Cut with Shift held, and /// the type object is not cut. diff --git a/crates/ui-egui/src/widgets.rs b/crates/ui-egui/src/widgets.rs index f88688f92..e4032b53d 100644 --- a/crates/ui-egui/src/widgets.rs +++ b/crates/ui-egui/src/widgets.rs @@ -56,7 +56,9 @@ pub use numeric::{ use numeric::{decimal_point, share_of, spinner_step, step_through, step_to_multiple, within_a_millionth}; pub(crate) use numeric::{round_to, set_bare_numbers_are_points, typed_unit}; pub use panel_chrome::{bottom_bar, layout_button, list_box, orientation_button, tab_bar}; -pub(crate) use text::{dialog_focus_flag, enter_modifiers, focus_field, own_field_shift_enter, set_dialog_open, take_dialog_focus}; +pub(crate) use text::{ + arm_field_focus, dialog_focus_flag, disarm_field_focus, enter_modifiers, focus_field, own_field_shift_enter, set_dialog_open, take_dialog_focus, +}; pub use text::{ exact_text_field, exact_text_field_named, plain_field, plain_field_named, search_field, text_field, text_field_named, text_presets, text_presets_named, diff --git a/crates/ui-egui/src/widgets/dropdowns.rs b/crates/ui-egui/src/widgets/dropdowns.rs index 70e6920c0..22ae68345 100644 --- a/crates/ui-egui/src/widgets/dropdowns.rs +++ b/crates/ui-egui/src/widgets/dropdowns.rs @@ -1,5 +1,6 @@ use super::drag::PanelDrag; use super::labels::{PreviousLabel, label_field, name_field, take_previous_label}; +use super::text::take_armed_focus; use super::{CornerRadius, HashOnly, Rect, Response, Sense, Stroke, StrokeKind, Tokens, Ui, Vec2, id_with, vec2}; /// A compact dropdown of interface labels (shown in the UI language). Returns the chosen index. @@ -124,7 +125,9 @@ pub(crate) fn combo_named( /// filters in place over a list that scrolls (the font menu and the shortcut import's target /// picker, #555). `menu` shows the menu with one of [`craft_ui::combo::Menu`]'s header forms and /// returns what it returned (`None` while the menu is closed). A click inside the menu keeps it -/// open: it closes itself when an option is chosen. A click outside closes it. +/// open: it closes itself when an option is chosen. A click outside closes it. Armed with id salt +/// `id` ([`arm_field_focus`]), the menu opens and no widget keeps the keyboard focus, so the +/// menu's search field can take it. pub(crate) fn combo_menu( ui: &mut Ui, id: impl std::hash::Hash, @@ -139,7 +142,12 @@ pub(crate) fn combo_menu( .stroke(Stroke::new(1.0, t.input_border)) .corner_radius(CornerRadius::same(3)) .show(ui, |ui| { + let armed = take_armed_focus(ui, &id); let resp = combo_field(ui, id_with(ui.scope_id(), id), label, None, current, width - 4.0); + if armed { + egui::Popup::open_id(ui.ctx(), egui::Popup::default_response_id(&resp)); + ui.memory_mut(|m| m.stop_text_input()); + } menu(craft_ui::combo::Menu::new(ui, &resp).close_behavior(egui::PopupCloseBehavior::CloseOnClickOutside)) }) .inner diff --git a/crates/ui-egui/src/widgets/numeric.rs b/crates/ui-egui/src/widgets/numeric.rs index 234c76dbf..360c9ab5e 100644 --- a/crates/ui-egui/src/widgets/numeric.rs +++ b/crates/ui-egui/src/widgets/numeric.rs @@ -1,6 +1,8 @@ use super::labels::{PreviousLabel, label_field, name_field, take_previous_label}; use super::panel_chrome::chevron_cell; -use super::text::{after_shift_enter, recessed_text, select_all, select_all_on_focus, shift_enter_keeps_focus, take_dialog_focus}; +use super::text::{ + after_shift_enter, focus_field, recessed_text, select_all, select_all_on_focus, shift_enter_keeps_focus, take_armed_focus, take_dialog_focus, +}; use super::{CornerRadius, RangeInclusive, Rect, Response, Sense, Stroke, StrokeKind, Tokens, Ui, Unit, id_with, pos2, scrub, vec2}; /// Preferences › Units › Numbers Without Units Are Points (#394; on until set): the app sets it @@ -356,7 +358,8 @@ pub fn mixed_field_named( } /// [`mixed_field`] whose ↑/↓, wheel and scrub stop at `bounds`; ↑/↓ and the wheel take `step`'s steps -/// when it is given (see [`SliderValue::step`]). +/// when it is given (see [`SliderValue::step`]). Armed with id salt `id` ([`arm_field_focus`]), it +/// takes the keyboard focus with its value selected. #[allow(clippy::too_many_arguments)] fn bounded_field( ui: &mut Ui, @@ -370,6 +373,7 @@ fn bounded_field( bounds: &RangeInclusive, step: Option f64>, ) -> Option { + let armed = take_armed_focus(ui, &id); let id = id_with(ui.scope_id(), id); let show = |value: f64| field_text(value, suffix, decimals); // The suffix (and %, °) may follow any operand: `45*2°`, `50% / 2`. @@ -381,7 +385,14 @@ fn bounded_field( }; let shown = value.map(show).unwrap_or_default(); take_dialog_focus(ui, id, &shown); + if armed { + focus_field(ui, id, &shown); + } let (mut buf, commit, resp, rect) = recessed_text(ui, id, &shown, width, 1, label, name); + if armed { + // A field armed while it has focus keeps the text typed into it: select all of that text. + select_all(ui, id, &buf); + } select_all_on_focus(ui, &resp, &buf); // ↑/↓ and the wheel step at the field's precision (a count ignores Ctrl/Cmd's tenth); a drag on // its label scrubs it. diff --git a/crates/ui-egui/src/widgets/text.rs b/crates/ui-egui/src/widgets/text.rs index ea3bd0da9..ccde3ba38 100644 --- a/crates/ui-egui/src/widgets/text.rs +++ b/crates/ui-egui/src/widgets/text.rs @@ -26,6 +26,43 @@ pub(crate) fn focus_field(ui: &Ui, id: egui::Id, text: &str) { ui.memory_mut(|m| m.request_focus(id)); } +/// The key under which [`arm_field_focus`] keeps the armed field's id salt. +fn armed_field_flag() -> egui::Id { + egui::Id::unique("armed-field-focus") +} + +/// Arm the field drawn with id salt `salt`: a numeric field's `id`, or a searchable menu's (the +/// font family menu's). The next one drawn, enabled and outside a sizing pass, takes the keyboard +/// focus ([`take_armed_focus`]) until [`disarm_field_focus`]. +pub(crate) fn arm_field_focus(ctx: &egui::Context, salt: impl std::hash::Hash) { + ctx.data_mut(|d| d.insert_temp(armed_field_flag(), id_with(egui::Id::NULL, salt))); +} + +/// Disarm the field [`arm_field_focus`] armed. → Whether it was still armed: no field took it. +pub(crate) fn disarm_field_focus(ctx: &egui::Context) -> bool { + ctx.data_mut(|d| { + let armed = d.get_temp::(armed_field_flag()).is_some(); + d.remove::(armed_field_flag()); + armed + }) +} + +/// Whether the field drawn with id salt `salt` is the one armed and can take the keyboard focus +/// now (it is enabled, and this is not a sizing pass). It is then disarmed. +pub(crate) fn take_armed_focus(ui: &Ui, salt: impl std::hash::Hash) -> bool { + if ui.is_sizing_pass() || !ui.is_enabled() { + return false; + } + let salt = id_with(egui::Id::NULL, salt); + ui.data_mut(|d| { + let armed = d.get_temp::(armed_field_flag()) == Some(salt); + if armed { + d.remove::(armed_field_flag()); + } + armed + }) +} + /// The modifiers held with an Enter press among this frame's events, `None` without one, as when a /// field's editing ends with a click elsewhere. pub(crate) fn enter_modifiers(ui: &Ui) -> Option { diff --git a/docs/mcp.md b/docs/mcp.md index 5dfcd6116..77490dc8a 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -3095,7 +3095,11 @@ Pen's second anchor at (150, 431), in line with the square's centre. kerning to Auto in the type objects in `ids`, the Type tool's selected text or the selected type objects; at a caret it resets only the kerning of the character before it. `type.resetHorizontalScale` (Cmd+Shift+X, `press_key {key: "X", mods: {cmd: true, shift: true}}`) sets the horizontal scale to 100%, as the Character panel - shows it, in the same text; at a caret it leaves the text as it is. + shows it, in the same text; at a caret it leaves the text as it is. In the app, `type.highlightKerning` (Cmd+Alt+K), + `type.highlightTracking` (no default key) and `type.highlightFontName` (Cmd+Alt+Shift+F) show the Character panel and + give its Kerning or Tracking field the keyboard focus with the value selected, or open its font family menu with the + search field focused; each replies `{field: "kerning" | "tracking" | "fontName"}`. Without selected type or text the + Type tool edits, the panel shows and the command fails. - `missingGlyphProtection` (on by default): `text.setStyle` and `text.setRangeStyle` changing the font leave the characters the new font has no glyph for in the font that had one. - `typeSelectionByPathOnly` (off by default): on, the Selection tools (`pointer_gesture` with `selection`, and the diff --git a/docs/target-app-parity.md b/docs/target-app-parity.md index 17b48395b..ae741312b 100644 --- a/docs/target-app-parity.md +++ b/docs/target-app-parity.md @@ -617,6 +617,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur - Cmd/Ctrl+/ (`appearance.addFill`) and Cmd/Ctrl+Alt+/ (`appearance.addStroke`) add a new fill and a new stroke to the selected objects, as the Appearance panel's Add New Fill and Add New Stroke buttons do, on the keys the reference app's [Default keyboard shortcuts](https://web.archive.org/web/20260726060015/https://helpx.adobe.com/illustrator/using/default-keyboard-shortcuts.html) page lists for adding a new fill and a new stroke. Keyboard Shortcuts lists both under Window › Appearance. - Cmd/Ctrl+Alt+Shift+. and , (`type.size.increaseByFive`, `type.size.decreaseByFive`) step the font size of the selected type, or of the text the Type tool has selected, by five times the Size/Leading increment (Preferences › Type); Cmd/Ctrl+Shift+. and , still step it by one increment. - Cmd/Ctrl+Alt+Q (`type.resetTracking`) sets the tracking of the selected type, or of the text the Type tool has selected, to 0 and its kerning to Auto (0 in the Character panel), in one undo step; at a caret it resets the kerning of the character before it. + - Cmd/Ctrl+Alt+K (`type.highlightKerning`) and Cmd/Ctrl+Alt+Shift+F (`type.highlightFontName`) show the Character panel and give its Kerning field the keyboard focus with the value selected, or open its font family menu with the search field focused, on the keys the reference app's [Default keyboard shortcuts](https://web.archive.org/web/20260726060015/https://helpx.adobe.com/illustrator/using/default-keyboard-shortcuts.html) page lists for highlighting kerning and the font name field. The page lists the same key for selecting the tracking value; `type.highlightTracking` focuses the Tracking field the same way and has no default key in Keyboard Shortcuts. - Cmd/Ctrl+Alt+L (`ui.newLayer`) opens Layer Options for a new layer, as an Alt-click on the Layers panel's New Layer button does, on the key the reference app's [Default keyboard shortcuts](https://web.archive.org/web/20260726060015/https://helpx.adobe.com/illustrator/using/default-keyboard-shortcuts.html) page lists for adding a layer through the New Layer dialog box. OK adds the layer above the current layer, and Cancel adds none. Cmd/Ctrl+L still adds a layer without the dialog. - F8 (`ui.symbolOptions`) opens Symbol Options for a new symbol made from the selection, as the Symbols panel's New Symbol button does, on the key the reference app's [Default keyboard shortcuts](https://web.archive.org/web/20260726060015/https://helpx.adobe.com/illustrator/using/default-keyboard-shortcuts.html) page lists for making a new symbol. OK makes the symbol and puts an instance of it in place of the art, and Cancel makes none. With nothing selected, F8 opens no dialog, and the status bar says that nothing is selected. Shift+F8 and Cmd/Ctrl+F8 still show the Transform and Info panels. - Cmd/Ctrl+Shift+X (`type.resetHorizontalScale`) sets the horizontal scale of the selected type, or of the text the Type tool has selected, to 100% as the Character panel shows it (the object's own stretch included), in one undo step; at a caret it leaves the text as it is.