mirror of
https://github.com/storytold/designcraft.git
synced 2026-11-01 06:06:49 -06:00
Merge PR #1512: Preferences › Interface: Color Theme swatches and the Tools panel's columns, as InDesign's
crates/ui-egui/src/dialogs/tests.rs: kept HEAD, appended #1512's new test crates/ui-egui/src/i18n/*.rs: kept both sides' rows (unique keys)
This commit is contained in:
@@ -461,6 +461,7 @@ Newest first.
|
||||
- **2026-10-21** · New Character Style with text selected starts from what the text has of its own over its paragraph style, as InDesign's ("[None] + Bold + color"), and Apply Style to Selection gives the text the new style, with no override left. A new style's dialog is titled New Paragraph Style / New Character Style. `type.selectionAttrs` reports the text's own character attributes (`ownChars`). Found in the Learn Skills Daily course, chapter 22. No readiness percentage change.
|
||||
- **2026-10-21** · New Paragraph Style with text selected starts from it, as InDesign's (Based On [No Paragraph Style], every setting of the text that differs) and Apply Style to Selection gives the paragraph the new style; General has Next Style and Reset To Base; Basic Character Formats is in two columns (Size | Leading, Kerning | Tracking, Case | Position). `style.paragraph.edit` honours `nextStyle` (it was ignored) and takes `resetToBase`. Found in the Learn Skills Daily course, chapter 20. No readiness percentage change.
|
||||
- **2026-10-21** · Find/Change has InDesign's Change Format. Specify Attributes opens Change Format Settings: Style Options (the character and paragraph style to apply, [Any Style] for none), then Basic and Advanced Character Formats, Character Color, OpenType Features, Underline and Strikethrough Options. The box shows the format ("Character Style: eggs"), and Change All gives it to the changed text. With a Change Format and nothing in Change to, the found text stays and is only formatted, as InDesign's (an ⓘ beside Change to says so). `find.change` takes `charStyle` and `paraStyle`. Found in the Learn Skills Daily course, chapter 22. No readiness percentage change.
|
||||
- **2026-10-21** · Preferences › Interface follows InDesign's: Appearance has a Color Theme swatch per interface theme (a click shows it at once, Cancel goes back) and Panels sets the Tools panel to a single or double column; UI Size moves to a UI Scaling section of its own. Interface held only UI Size, and the theme could be changed only from the Window menu. Found in the Learn Skills Daily course, chapter 26. No readiness percentage change.
|
||||
- **2026-10-21** · Properties › Character and Paragraph: ••• (More Options) expands the section in place, as InDesign's: Character adds vertical and horizontal scale, baseline shift, skew, language and OpenType, and All Caps, Small Caps, Superscript, Subscript, Underline and Strikethrough; Paragraph adds the left, right, first line and last line indents, space before and after, the drop cap's lines and characters, Align to Baseline Grid and Hyphenate. It used to open the Character or Paragraph panel; the language field moved under ••• as in InDesign. Found in the Learn Skills Daily course, chapter 16. No readiness percentage change.
|
||||
- **2026-10-21** · The text Control panel has InDesign's two modes: A (Character Formatting Controls: font and style, size and leading, All Caps/Superscript/Underline and Small Caps/Subscript/Strikethrough, kerning and tracking, vertical and horizontal scale, baseline shift and skew, character style and language) and ¶ (Paragraph Formatting Controls: the nine alignments, left/first line and right/last line indents, space before and after, the drop cap's lines and characters, paragraph style, Hyphenate and Align to Baseline Grid). It used to show a fixed mix of both. Found in the Learn Skills Daily course, chapter 16. No readiness percentage change.
|
||||
- **2026-10-20** · With the Type tool, the Control panel's font size, leading and tracking fields have a spinner and a list of common values, as in InDesign (auto leading in parentheses). No readiness percentage change.
|
||||
|
||||
@@ -1728,6 +1728,7 @@ fn preferences(app: &crate::DesignApp, ui: &mut egui::Ui, d: &mut Dialog, max_he
|
||||
&[
|
||||
("general", "General"),
|
||||
("interface", "Interface"),
|
||||
("uiScaling", "UI Scaling"),
|
||||
("type", "Type"),
|
||||
("advancedType", "Advanced Type"),
|
||||
("composition", "Composition"),
|
||||
@@ -1748,6 +1749,7 @@ fn preferences(app: &crate::DesignApp, ui: &mut egui::Ui, d: &mut Dialog, max_he
|
||||
&[
|
||||
("general", "General"),
|
||||
("interface", "Interface"),
|
||||
("uiScaling", "UI Scaling"),
|
||||
("type", "Type"),
|
||||
("composition", "Composition"),
|
||||
("spelling", "Spelling"),
|
||||
@@ -1967,6 +1969,41 @@ fn preferences(app: &crate::DesignApp, ui: &mut egui::Ui, d: &mut Dialog, max_he
|
||||
}
|
||||
}
|
||||
"interface" => {
|
||||
let lang = app.ui.language.clone();
|
||||
let t = crate::theme::Tokens::get(ui.ctx());
|
||||
crate::rtl::label(ui, egui::RichText::new(crate::i18n::tr(&lang, "Appearance")).font(semibold(12.0)));
|
||||
// Color Theme: a swatch per theme, as InDesign's. A click shows it at once;
|
||||
// Cancel goes back to the theme Preferences opened with.
|
||||
ui.horizontal(|ui| {
|
||||
crate::rtl::label(ui, crate::i18n::tr(&lang, "Color Theme:"));
|
||||
let cur = d.s("brightness");
|
||||
for b in crate::theme::Brightness::ALL {
|
||||
let (r, resp) = ui.allocate_exact_size(egui::vec2(24.0, 24.0), egui::Sense::click());
|
||||
let on = cur == b.id();
|
||||
let swatch = r.shrink(4.0);
|
||||
ui.painter().rect_filled(swatch, 1.0, crate::theme::Tokens::for_brightness(b).panel);
|
||||
ui.painter().rect_stroke(swatch, 1.0, egui::Stroke::new(1.0, t.field_border), egui::StrokeKind::Inside);
|
||||
if on || resp.hovered() {
|
||||
let ring = if on { t.accent_strong } else { t.field_border };
|
||||
ui.painter().rect_stroke(r.shrink(1.0), 2.0, egui::Stroke::new(2.0, ring), egui::StrokeKind::Inside);
|
||||
}
|
||||
let name = crate::i18n::tr(&lang, b.label()).to_string();
|
||||
resp.widget_info(|| egui::WidgetInfo::selected(egui::Role::RadioButton, true, on, &name));
|
||||
if resp.on_hover_text(&name).clicked() && !on {
|
||||
d.fields.insert("brightness".into(), json!(b.id()));
|
||||
d.fields.insert("applyBrightness".into(), json!(b.id()));
|
||||
}
|
||||
}
|
||||
});
|
||||
ui.add_space(8.0);
|
||||
crate::rtl::label(ui, egui::RichText::new(crate::i18n::tr(&lang, "Panels")).font(semibold(12.0)));
|
||||
ui.horizontal(|ui| {
|
||||
let name = crate::rtl::label(ui, crate::i18n::tr(&lang, "Tools Panel:"));
|
||||
translated_combo(&lang, ui, d, "toolsColumns", &[("single", "Single Column"), ("double", "Double Column")])
|
||||
.labelled_by(name.id);
|
||||
});
|
||||
}
|
||||
"uiScaling" => {
|
||||
crate::rtl::label(ui, egui::RichText::new(crate::i18n::tr(&app.ui.language, "UI Scaling")).font(semibold(12.0)));
|
||||
ui.horizontal(|ui| {
|
||||
crate::rtl::label(ui, crate::i18n::tr(&app.ui.language, "UI Size:"));
|
||||
@@ -3083,6 +3120,12 @@ pub fn show(app: &mut DesignApp, ctx: &egui::Context) {
|
||||
{
|
||||
d.fields.insert("status".into(), json!(e));
|
||||
}
|
||||
// So does Preferences › Interface › Color Theme, as InDesign's.
|
||||
if let Some(b) = d.fields.remove("applyBrightness")
|
||||
&& let Err(e) = app.run("window.brightness", json!({"brightness": b}))
|
||||
{
|
||||
d.fields.insert("status".into(), json!(e));
|
||||
}
|
||||
if d.id == "newDocument" && result.is_none() {
|
||||
crate::new_document::preview(app, &mut d, ctx);
|
||||
}
|
||||
@@ -3232,10 +3275,18 @@ pub fn cancel(app: &mut DesignApp) {
|
||||
app.cancel_pdf_import();
|
||||
if let Some(d) = d
|
||||
&& d.id == "preferences"
|
||||
&& let Some(lang) = d.fields.get("openedLanguage").and_then(Value::as_str)
|
||||
&& lang != app.ui.language
|
||||
{
|
||||
let _ = app.run("app.language", json!({"lang": lang}));
|
||||
if let Some(lang) = d.fields.get("openedLanguage").and_then(Value::as_str)
|
||||
&& lang != app.ui.language
|
||||
{
|
||||
let _ = app.run("app.language", json!({"lang": lang}));
|
||||
}
|
||||
// The Color Theme shown while choosing goes back too.
|
||||
if let Some(b) = d.fields.get("openedBrightness").and_then(Value::as_str)
|
||||
&& b != app.ui.brightness.id()
|
||||
{
|
||||
let _ = app.run("window.brightness", json!({"brightness": b}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3914,6 +3965,13 @@ fn confirm_part4(app: &mut DesignApp, d: Dialog) -> Result<Value, String> {
|
||||
};
|
||||
app.run(view, json!({}))?;
|
||||
app.run("window.richBlack", json!({"on": d.b("richBlack")}))?;
|
||||
// Interface: the theme (already showing, unless set without a click) and the Tools panel.
|
||||
if let Some(b) = d.fields.get("brightness").and_then(Value::as_str).filter(|b| *b != app.ui.brightness.id()) {
|
||||
app.run("window.brightness", json!({"brightness": b}))?;
|
||||
}
|
||||
if d.fields.contains_key("toolsColumns") {
|
||||
app.run("window.toolsDoubleColumn", json!({"on": d.s("toolsColumns") == "double"}))?;
|
||||
}
|
||||
if let Some(v) = d.n("uiScale") {
|
||||
app.run("window.uiScale", json!({"scale": v / 100.0}))?;
|
||||
}
|
||||
@@ -6522,22 +6580,26 @@ fn delete_character_style(app: &mut DesignApp, ui: &mut egui::Ui, d: &mut Dialog
|
||||
});
|
||||
}
|
||||
|
||||
fn combo(ui: &mut egui::Ui, d: &mut Dialog, key: &str, opts: &[(&str, &str)]) {
|
||||
fn combo(ui: &mut egui::Ui, d: &mut Dialog, key: &str, opts: &[(&str, &str)]) -> egui::Response {
|
||||
let cur = d.s(key);
|
||||
let shown = opts.iter().find(|o| o.0 == cur).map_or(cur.as_str(), |o| o.1).to_string();
|
||||
craft_ui::ComboBox::from_id_salt(key).selected_text(crate::rtl::widget(ui, &shown)).width(170.0).show_ui(ui, |ui| {
|
||||
for (v, label) in opts {
|
||||
if ui.selectable_label(cur == *v, crate::rtl::widget(ui, *label)).clicked() {
|
||||
d.fields.insert(key.into(), json!(v));
|
||||
craft_ui::ComboBox::from_id_salt(key)
|
||||
.selected_text(crate::rtl::widget(ui, &shown))
|
||||
.width(170.0)
|
||||
.show_ui(ui, |ui| {
|
||||
for (v, label) in opts {
|
||||
if ui.selectable_label(cur == *v, crate::rtl::widget(ui, *label)).clicked() {
|
||||
d.fields.insert(key.into(), json!(v));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
.response
|
||||
}
|
||||
|
||||
/// Translate enum captions without changing serialized values or user-defined names.
|
||||
fn translated_combo(lang: &str, ui: &mut egui::Ui, d: &mut Dialog, key: &str, opts: &[(&str, &str)]) {
|
||||
fn translated_combo(lang: &str, ui: &mut egui::Ui, d: &mut Dialog, key: &str, opts: &[(&str, &str)]) -> egui::Response {
|
||||
let opts: Vec<_> = opts.iter().map(|(value, label)| (*value, crate::i18n::tr(lang, label))).collect();
|
||||
combo(ui, d, key, &opts);
|
||||
combo(ui, d, key, &opts)
|
||||
}
|
||||
|
||||
/// Style name picker (paragraph or character styles of the active document).
|
||||
|
||||
@@ -3900,3 +3900,69 @@ fn a_change_format_goes_with_change_all() {
|
||||
assert_eq!(change_format_summary("en", d.fields.get(CHANGE_FORMAT)), "Character Style: eggs + Paragraph Style: Method + Underline: on");
|
||||
assert!(find_change_params(&Dialog::new("findChange", json!({"find": "cook"}))).get("attrs").is_none());
|
||||
}
|
||||
|
||||
/// The course's chapter 26: Preferences › Interface as InDesign's. A Color Theme swatch shows
|
||||
/// its theme at once and Cancel goes back; OK keeps the theme and the Tools panel's columns.
|
||||
/// UI Size is in a UI Scaling section of its own.
|
||||
#[test]
|
||||
fn preferences_interface_sets_the_color_theme_and_tools_panel() {
|
||||
use crate::theme::Brightness;
|
||||
use egui::accesskit::Role;
|
||||
use egui_kittest::{Harness, kittest::Queryable};
|
||||
let mut app = DesignApp::new(designcraft_engine::Session::new(), crate::Services::default());
|
||||
app.run("file.new", json!({})).unwrap();
|
||||
let opened = app.ui.brightness;
|
||||
let open = |app: &mut DesignApp| {
|
||||
app.run("app.preferences", json!({})).unwrap();
|
||||
app.ui.dialog.as_mut().unwrap().fields.insert("section".into(), json!("interface"));
|
||||
};
|
||||
open(&mut app);
|
||||
let mut h = Harness::builder().with_size(egui::vec2(1100.0, 760.0)).build_ui_state(
|
||||
|ui, app: &mut DesignApp| {
|
||||
let key = egui::Id::unique("prefs_interface_test_fonts");
|
||||
if ui.data(|d| d.get_temp::<bool>(key)).is_none() {
|
||||
crate::theme::install_fonts(ui.ctx(), "");
|
||||
ui.data_mut(|d| d.insert_temp(key, true));
|
||||
return;
|
||||
}
|
||||
show(app, ui.ctx());
|
||||
},
|
||||
app,
|
||||
);
|
||||
h.run_steps(3);
|
||||
let swatch = |h: &Harness<'_, DesignApp>, name: &str| h.get_by(|n| n.role() == Role::RadioButton && n.label().as_deref() == Some(name)).click();
|
||||
for l in ["Appearance", "Color Theme:", "Panels", "Tools Panel:"] {
|
||||
assert!(h.query_by_label(l).is_some(), "{l}");
|
||||
}
|
||||
// A click shows the theme at once; Cancel goes back.
|
||||
swatch(&h, "Light");
|
||||
h.run_steps(3);
|
||||
assert_eq!(h.state().ui.brightness, Brightness::Light);
|
||||
h.get_by_label("Cancel").click();
|
||||
h.run_steps(3);
|
||||
assert!(h.state().ui.dialog.is_none());
|
||||
assert_eq!(h.state().ui.brightness, opened, "Cancel goes back to the theme Preferences opened with");
|
||||
// OK keeps the theme and the Tools panel's columns.
|
||||
open(h.state_mut());
|
||||
h.run_steps(3);
|
||||
swatch(&h, "Dark");
|
||||
h.run_steps(2);
|
||||
h.get_by(|n| n.role() == Role::ComboBox && n.value().as_deref() == Some("Single Column")).click();
|
||||
h.run_steps(2);
|
||||
h.get_by_label("Double Column").click();
|
||||
h.run_steps(2);
|
||||
h.get_by_label(" OK ").click();
|
||||
h.run_steps(3);
|
||||
assert!(h.state().ui.dialog.is_none());
|
||||
assert_eq!(h.state().ui.brightness, Brightness::Dark);
|
||||
assert!(h.state().ui.tools_double_column);
|
||||
// The same command the Window menu toggles, with an explicit state for Preferences.
|
||||
assert_eq!(h.state_mut().run("window.toolsDoubleColumn", json!({"on": false})).unwrap(), json!(false));
|
||||
assert_eq!(h.state_mut().run("window.toolsDoubleColumn", json!({"on": false})).unwrap(), json!(false), "set, not toggled");
|
||||
assert_eq!(h.state_mut().run("window.toolsDoubleColumn", json!({})).unwrap(), json!(true), "toggled without `on`");
|
||||
// UI Size has a section of its own.
|
||||
open(h.state_mut());
|
||||
h.state_mut().ui.dialog.as_mut().unwrap().fields.insert("section".into(), json!("uiScaling"));
|
||||
h.run_steps(3);
|
||||
assert!(h.query_by_label("UI Size:").is_some());
|
||||
}
|
||||
|
||||
@@ -48,6 +48,9 @@ pub(super) const TABLE: &[(&str, &str)] = &[
|
||||
"With a Change Format and nothing in Change to, the found text stays and is only formatted",
|
||||
"مع تنسيق للتغيير وحقل «تغيير إلى» فارغ، يبقى النص الذي تم العثور عليه ويتغير تنسيقه فقط",
|
||||
),
|
||||
("Double Column", "عمود مزدوج"),
|
||||
("Tools Panel:", "لوحة الأدوات:"),
|
||||
("Color Theme:", "سمة الألوان:"),
|
||||
("Restart Numbering", "إعادة الترقيم"),
|
||||
("Continue Numbering", "متابعة الترقيم"),
|
||||
("Keep Options…", "خيارات الإبقاء…"),
|
||||
|
||||
@@ -50,6 +50,10 @@ pub(super) const TABLE: &[(&str, &str)] = &[
|
||||
"With a Change Format and nothing in Change to, the found text stays and is only formatted",
|
||||
"Se změnou formátu a prázdným polem „Změnit na“ nalezený text zůstane a změní se jen jeho formát",
|
||||
),
|
||||
("Double Column", "Dvojitý sloupec"),
|
||||
("Single Column", "Jednoduchý sloupec"),
|
||||
("Tools Panel:", "Panel nástrojů:"),
|
||||
("Color Theme:", "Barevný motiv:"),
|
||||
("Restart Numbering", "Začít číslování znovu"),
|
||||
("Continue Numbering", "Pokračovat v číslování"),
|
||||
("Keep Options…", "Volby zachování…"),
|
||||
|
||||
@@ -46,6 +46,9 @@ pub(super) const TABLE: &[(&str, &str)] = &[
|
||||
"With a Change Format and nothing in Change to, the found text stays and is only formatted",
|
||||
"Con un formato di modifica e «Sostituisci con» vuoto, il testo trovato resta e cambia solo la formattazione",
|
||||
),
|
||||
("Double Column", "Colonna doppia"),
|
||||
("Tools Panel:", "Pannello Strumenti:"),
|
||||
("Color Theme:", "Tema colore:"),
|
||||
("Restart Numbering", "Riavvia numerazione"),
|
||||
("Continue Numbering", "Continua numerazione"),
|
||||
("Keep Options…", "Opzioni di separazione…"),
|
||||
|
||||
@@ -49,6 +49,9 @@ pub(super) const TABLE: &[(&str, &str)] = &[
|
||||
"With a Change Format and nothing in Change to, the found text stays and is only formatted",
|
||||
"ფორმატის შეცვლით და ცარიელი „ჩანაცვლება“ ველით ნაპოვნი ტექსტი რჩება და მხოლოდ ფორმატი იცვლება",
|
||||
),
|
||||
("Double Column", "ორმაგი სვეტი"),
|
||||
("Tools Panel:", "ხელსაწყოების პანელი:"),
|
||||
("Color Theme:", "ფერთა თემა:"),
|
||||
("Restart Numbering", "ნუმერაციის თავიდან დაწყება"),
|
||||
("Continue Numbering", "ნუმერაციის გაგრძელება"),
|
||||
("Keep Options…", "შენარჩუნების პარამეტრები…"),
|
||||
|
||||
@@ -48,6 +48,10 @@ pub(super) const TABLE: &[(&str, &str)] = &[
|
||||
"With a Change Format and nothing in Change to, the found text stays and is only formatted",
|
||||
"Przy zmianie formatu i pustym polu „Zmień na” znaleziony tekst zostaje, a zmienia się tylko jego format",
|
||||
),
|
||||
("Double Column", "Podwójna kolumna"),
|
||||
("Single Column", "Pojedyncza kolumna"),
|
||||
("Tools Panel:", "Panel narzędzi:"),
|
||||
("Color Theme:", "Motyw kolorów:"),
|
||||
("Restart Numbering", "Zacznij numerowanie od nowa"),
|
||||
("Continue Numbering", "Kontynuuj numerowanie"),
|
||||
("Keep Options…", "Opcje utrzymywania…"),
|
||||
|
||||
@@ -49,6 +49,9 @@ pub(super) const TABLE: &[(&str, &str)] = &[
|
||||
"With a Change Format and nothing in Change to, the found text stays and is only formatted",
|
||||
"Com um formato de alteração e “Alterar para” vazio, o texto encontrado permanece e só a formatação muda",
|
||||
),
|
||||
("Double Column", "Coluna dupla"),
|
||||
("Tools Panel:", "Painel Ferramentas:"),
|
||||
("Color Theme:", "Tema de cores:"),
|
||||
("Restart Numbering", "Reiniciar numeração"),
|
||||
("Continue Numbering", "Continuar numeração"),
|
||||
("Keep Options…", "Opções de manutenção…"),
|
||||
|
||||
@@ -52,6 +52,10 @@ pub(super) const TABLE: &[(&str, &str)] = &[
|
||||
"With a Change Format and nothing in Change to, the found text stays and is only formatted",
|
||||
"Если задан формат замены, а поле «Заменить на» пусто, найденный текст остаётся, меняется только его формат",
|
||||
),
|
||||
("Double Column", "Две колонки"),
|
||||
("Single Column", "Одна колонка"),
|
||||
("Tools Panel:", "Панель инструментов:"),
|
||||
("Color Theme:", "Цветовая тема:"),
|
||||
("Restart Numbering", "Начать нумерацию заново"),
|
||||
("Continue Numbering", "Продолжить нумерацию"),
|
||||
("Keep Options…", "Параметры удержания…"),
|
||||
|
||||
@@ -2477,6 +2477,9 @@ pub(super) const TABLE: &[(&str, [&str; 5])] = &[
|
||||
),
|
||||
("Typical Display", ["Typical Display", "Affichage standard", "Typical Display", "Typical Display", "典型显示"]),
|
||||
("UI Scaling", ["UI Scaling", "Mise à l'échelle de l'interface", "UI Scaling", "UI Scaling", "UI 缩放"]),
|
||||
("Color Theme:", ["Farbdesign:", "Thème de couleur :", "Tema de color:", "カラーテーマ:", "颜色主题:"]),
|
||||
("Tools Panel:", ["Werkzeugbedienfeld:", "Panneau Outils :", "Panel Herramientas:", "ツールパネル:", "工具面板:"]),
|
||||
("Double Column", ["Doppelte Spalte", "Double colonne", "Columna doble", "2 列", "双栏"]),
|
||||
("Update Link", ["Update Link", "Mettre à jour le lien", "Update Link", "Update Link", "更新链接"]),
|
||||
(
|
||||
"User Dictionary Words",
|
||||
|
||||
@@ -47,6 +47,9 @@ pub(super) const TABLE: &[(&str, &str)] = &[
|
||||
"With a Change Format and nothing in Change to, the found text stays and is only formatted",
|
||||
"Якщо задано формат заміни, а поле «Замінити на» порожнє, знайдений текст лишається, змінюється лише його формат",
|
||||
),
|
||||
("Double Column", "Подвійна колонка"),
|
||||
("Tools Panel:", "Панель інструментів:"),
|
||||
("Color Theme:", "Колірна тема:"),
|
||||
("Restart Numbering", "Почати нумерацію знову"),
|
||||
("Continue Numbering", "Продовжити нумерацію"),
|
||||
("Keep Options…", "Параметри утримання…"),
|
||||
|
||||
@@ -523,6 +523,10 @@ fn run_ui_part2(app: &mut DesignApp, id: &str, p: &Value) -> Option<Result<Value
|
||||
});
|
||||
f["uiScale"] = json!((app.ui.ui_scale * 100.0).round());
|
||||
f["autoCollapseIconicPanels"] = json!(app.ui.dock_auto_collapse);
|
||||
// Interface: Cancel goes back to the theme Preferences opened with.
|
||||
f["brightness"] = json!(app.ui.brightness.id());
|
||||
f["openedBrightness"] = json!(app.ui.brightness.id());
|
||||
f["toolsColumns"] = json!(if app.ui.tools_double_column { "double" } else { "single" });
|
||||
f["richBlack"] = json!(app.ui.rich_black);
|
||||
f["dynamicSpelling"] = json!(app.ui.dynamic_spelling);
|
||||
f["storyEditorSize"] = json!(app.ui.story_editor_size);
|
||||
@@ -984,7 +988,10 @@ fn run_ui_part5(app: &mut DesignApp, id: &str, p: &Value) -> Option<Result<Value
|
||||
app.ui.pending_urls.push(url.clone());
|
||||
Ok(json!({"url": url}))
|
||||
}
|
||||
"window.toolsDoubleColumn" => flag(&mut app.ui.tools_double_column),
|
||||
"window.toolsDoubleColumn" => {
|
||||
app.ui.tools_double_column = p.get("on").and_then(Value::as_bool).unwrap_or(!app.ui.tools_double_column);
|
||||
Ok(json!(app.ui.tools_double_column))
|
||||
}
|
||||
"window.newWorkspace" => {
|
||||
let Some(name) = p.get("name").and_then(Value::as_str).map(str::trim).filter(|n| !n.is_empty()) else {
|
||||
app.ui.dialog =
|
||||
|
||||
@@ -372,7 +372,7 @@ pub const UI_COMMANDS: &[(&str, &str, Option<&str>, &str)] = &[
|
||||
"{open?: true, tab?: \"about\"|\"contributors\"|\"models\"} — the About window: splash with community links, contributor and model credits (open: false closes it)",
|
||||
),
|
||||
("help.checkForUpdates", "Check for Updates…", None, "{} — checks for newer releases and offers to update"),
|
||||
("window.toolsDoubleColumn", "Tools: Double Column", None, "{}"),
|
||||
("window.toolsDoubleColumn", "Tools: Double Column", None, "{on?: bool (default: toggle)} → whether the Tools panel has two columns"),
|
||||
(
|
||||
"window.workspace",
|
||||
"Workspace",
|
||||
|
||||
Reference in New Issue
Block a user