mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-28 19:57:05 -06:00
Color panel: Hide Options comes back after a restart, and ui.colorPanel sets the mode and options
Show Options and Hide Options were kept in egui's temporary memory, so
the Color panel showed its options again after every restart. No
command set them or the panel's mode.
- `UiState::color_hide_options` holds Hide Options and is saved with the
preferences. Its reader reads `true` as hidden and any other value as
shown, so a bad value leaves the other preferences as they are.
- `ui.colorPanel {mode?, options?}` picks a mode as the panel menu does
(the active color converts to the mode's model as one undo step) and
shows or hides the options. It answers `{mode, options, shown}`. A mode
the menu does not list, `lab` included, answers an error. The panel
menu's Show Options and Hide Options call the command's function.
- `ui.inspect` reports the setting as `ui.color_hide_options`.
Docs: docs/control-protocol.md, docs/target-app-parity.md.
This commit is contained in:
@@ -1344,6 +1344,7 @@ lighting Light Světlo
|
||||
Roman Baseline Latinková účaří
|
||||
Select a text object to edit its character attributes. Vyberte textový objekt, abyste mohli upravit atributy jeho znaků.
|
||||
Show Options Zobrazit možnosti
|
||||
Color Panel Options Možnosti panelu Barva
|
||||
Small Caps Kapitálky
|
||||
Small Caps (on the roadmap) Kapitálky (v plánu)
|
||||
Standard Vertical Roman Alignment Standardní svislé zarovnání latinky
|
||||
@@ -3910,6 +3911,7 @@ imageTrace Outline Obrys
|
||||
@msg `{key}` must be between {min} and {max} (got {x}) `{key}` musí být mezi {min} a {max} (zadáno {x})
|
||||
@msg `{key}` must be one of {_1} `{key}` musí být jedno z {_1}
|
||||
@msg `{key}` must be true or false `{key}` musí být true nebo false
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe `mode` musí být grayscale, rgb, hsb, cmyk nebo websafe
|
||||
@msg `{k}` must be [x, y] `{k}` musí být [x, y]
|
||||
@msg `{name}` has no options `{name}` nemá žádné možnosti
|
||||
@msg `{name}` is a built-in workspace; choose another name `{name}` je vestavěný pracovní prostor; zvolte jiný název
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2694,6 +2694,7 @@
|
||||
Show Modified Geänderte einblenden
|
||||
Show Note Notiz einblenden
|
||||
Show Options Optionen einblenden
|
||||
Color Panel Options Optionen für das Farbbedienfeld
|
||||
Show Package Paket anzeigen
|
||||
Show Panel Bedienfeld einblenden
|
||||
Show Pattern Swatches Musterfelder einblenden
|
||||
@@ -3516,6 +3517,7 @@ theme Appearance Erscheinungsbild
|
||||
@msg `{key}` must be between {min} and {max} (got {x}) `{key}` muss zwischen {min} und {max} liegen (erhalten: {x})
|
||||
@msg `{key}` must be one of {_1} `{key}` muss einer der folgenden Werte sein: {_1}
|
||||
@msg `{key}` must be true or false `{key}` muss true oder false sein
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe `mode` muss grayscale, rgb, hsb, cmyk oder websafe sein
|
||||
@msg `{k}` must be [x, y] `{k}` muss [x, y] sein
|
||||
@msg `{name}` has no options `{name}` hat keine Optionen
|
||||
@msg `{name}` is a built-in workspace; choose another name `{name}` ist ein integrierter Arbeitsbereich; wählen Sie einen anderen Namen
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2743,6 +2743,7 @@
|
||||
Show Modified Mostrar modificados
|
||||
Show Note Mostrar nota
|
||||
Show Options Mostrar opciones
|
||||
Color Panel Options Opciones del panel Color
|
||||
Show Package Mostrar paquete
|
||||
Show Panel Mostrar panel
|
||||
Show Pattern Swatches Mostrar muestras de motivo
|
||||
@@ -3614,6 +3615,7 @@ axis Both Ambos
|
||||
@msg `{key}` must be between {min} and {max} (got {x}) `{key}` debe estar entre {min} y {max} (se recibió {x})
|
||||
@msg `{key}` must be one of {_1} `{key}` debe ser uno de estos: {_1}
|
||||
@msg `{key}` must be true or false `{key}` debe ser true o false
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe `mode` debe ser grayscale, rgb, hsb, cmyk o websafe
|
||||
@msg `{k}` must be [x, y] `{k}` debe ser [x, y]
|
||||
@msg `{name}` has no options `{name}` no tiene opciones
|
||||
@msg `{name}` is a built-in workspace; choose another name `{name}` es un espacio de trabajo integrado; elige otro nombre
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2740,6 +2740,7 @@
|
||||
Show Modified Afficher les éléments modifiés
|
||||
Show Note Afficher la note
|
||||
Show Options Afficher les options
|
||||
Color Panel Options Options du panneau Couleur
|
||||
Show Package Afficher le dossier d’assemblage
|
||||
Show Panel Afficher le panneau
|
||||
Show Pattern Swatches Afficher les nuances de motif
|
||||
@@ -3611,6 +3612,7 @@ axis Both Les deux
|
||||
@msg `{key}` must be between {min} and {max} (got {x}) `{key}` doit être compris entre {min} et {max} (reçu : {x})
|
||||
@msg `{key}` must be one of {_1} `{key}` doit valoir l’une de ces valeurs : {_1}
|
||||
@msg `{key}` must be true or false `{key}` doit valoir true ou false
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe `mode` doit valoir grayscale, rgb, hsb, cmyk ou websafe
|
||||
@msg `{k}` must be [x, y] `{k}` doit être [x, y]
|
||||
@msg `{name}` has no options `{name}` n’a pas d’options
|
||||
@msg `{name}` is a built-in workspace; choose another name `{name}` est un espace de travail intégré ; choisissez un autre nom
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3325,6 +3325,7 @@
|
||||
Show Modified Módosultak megjelenítése
|
||||
Show Note Megjegyzés megjelenítése
|
||||
Show Options Beállítások megjelenítése
|
||||
Color Panel Options Szín panel beállításai
|
||||
Show Package Csomag megjelenítése
|
||||
Show Panel Panel megjelenítése
|
||||
Show Pattern Swatches Mintázat-színminták megjelenítése
|
||||
@@ -4103,6 +4104,7 @@ imageTrace Outline Körvonal
|
||||
@msg `{key}` must be between {min} and {max} (got {x}) `{key}`: {min} és {max} közötti érték kell (kapott érték: {x})
|
||||
@msg `{key}` must be one of {_1} `{key}`: ezek egyike kell: {_1}
|
||||
@msg `{key}` must be true or false `{key}`: true vagy false kell
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe `mode`: grayscale, rgb, hsb, cmyk vagy websafe kell
|
||||
@msg `{k}` must be [x, y] `{k}`: [x, y] kell
|
||||
@msg `{name}` has no options ennek nincsenek beállításai: `{name}`
|
||||
@msg `{name}` is a built-in workspace; choose another name beépített munkaterület: `{name}`; válassz másik nevet
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2745,6 +2745,7 @@
|
||||
Show Modified Mostra modificati
|
||||
Show Note Mostra nota
|
||||
Show Options Mostra opzioni
|
||||
Color Panel Options Opzioni pannello Colore
|
||||
Show Package Mostra pacchetto
|
||||
Show Panel Mostra pannello
|
||||
Show Pattern Swatches Mostra campioni motivo
|
||||
@@ -3616,6 +3617,7 @@ axis Both Entrambi
|
||||
@msg `{key}` must be between {min} and {max} (got {x}) `{key}` deve essere compreso tra {min} e {max} (ricevuto {x})
|
||||
@msg `{key}` must be one of {_1} `{key}` deve essere uno dei seguenti: {_1}
|
||||
@msg `{key}` must be true or false `{key}` deve essere true o false
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe `mode` deve essere grayscale, rgb, hsb, cmyk o websafe
|
||||
@msg `{k}` must be [x, y] `{k}` deve essere [x, y]
|
||||
@msg `{name}` has no options `{name}` non ha opzioni
|
||||
@msg `{name}` is a built-in workspace; choose another name `{name}` è un'area di lavoro integrata; scegli un altro nome
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2564,6 +2564,7 @@
|
||||
Show List View リスト表示
|
||||
Show Note メモを表示
|
||||
Show Options オプションを表示
|
||||
Color Panel Options カラーパネルオプション
|
||||
Show Package パッケージを表示
|
||||
Show Panel パネルを表示
|
||||
Show Perspective Grid 遠近グリッドを表示
|
||||
@@ -4013,6 +4014,7 @@ theme Appearance 外観
|
||||
@msg Opened {url} {url} を開きました
|
||||
@msg No saved views (View → New View…) 保存した表示はありません (表示 → 新規表示…)
|
||||
@msg `command` must be a command whose menu item opens a dialog (see ui.menuDialog) `command` には、メニュー項目がダイアログを開くコマンドを指定してください (ui.menuDialog を参照)
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe `mode` には grayscale、rgb、hsb、cmyk、websafe のいずれかを指定してください
|
||||
@msg `{key}` must be true or false `{key}` には true または false を指定してください
|
||||
@msg brightness must be dark|mediumDark|mediumLight|light brightness には dark|mediumDark|mediumLight|light のいずれかを指定してください
|
||||
@msg index must be a number or first, previous, next or last index には数値、または first、previous、next、last のいずれかを指定してください
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2558,6 +2558,7 @@
|
||||
Show List View 목록 보기 표시
|
||||
Show Note 메모 표시
|
||||
Show Options 옵션 표시
|
||||
Color Panel Options 색상 패널 옵션
|
||||
Show Package 패키지 표시
|
||||
Show Panel 패널 표시
|
||||
Show Perspective Grid 원근 격자 표시
|
||||
@@ -3991,6 +3992,7 @@ theme Appearance 외관
|
||||
@msg Opened {url} {url}을(를) 열었습니다
|
||||
@msg No saved views (View → New View…) 저장된 보기가 없습니다(보기 → 새 보기…)
|
||||
@msg `command` must be a command whose menu item opens a dialog (see ui.menuDialog) `command`는 메뉴 항목이 대화상자를 여는 명령이어야 합니다(ui.menuDialog 참조)
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe `mode`은(는) grayscale, rgb, hsb, cmyk, websafe 중 하나여야 합니다
|
||||
@msg `{key}` must be true or false `{key}`은(는) true 또는 false여야 합니다
|
||||
@msg brightness must be dark|mediumDark|mediumLight|light brightness는 dark|mediumDark|mediumLight|light 중 하나여야 합니다
|
||||
@msg index must be a number or first, previous, next or last index는 숫자이거나 first, previous, next, last 중 하나여야 합니다
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1256,6 +1256,7 @@ lighting Light Światło
|
||||
Roman Baseline Linia bazowa łacińska
|
||||
Select a text object to edit its character attributes. Zaznacz obiekt tekstowy, aby edytować atrybuty znaków.
|
||||
Show Options Pokaż opcje
|
||||
Color Panel Options Opcje panelu Kolor
|
||||
Small Caps Kapitaliki
|
||||
Small Caps (on the roadmap) Kapitaliki (w planach)
|
||||
Standard Vertical Roman Alignment Standardowe pionowe wyrównanie łacińskie
|
||||
@@ -3724,6 +3725,7 @@ imageTrace Outline Kontur
|
||||
@msg `{key}` must be between {min} and {max} (got {x}) `{key}` musi mieścić się w zakresie od {min} do {max} (podano {x})
|
||||
@msg `{key}` must be one of {_1} `{key}` musi mieć jedną z wartości: {_1}
|
||||
@msg `{key}` must be true or false `{key}` musi mieć wartość true lub false
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe `mode` musi mieć wartość grayscale, rgb, hsb, cmyk lub websafe
|
||||
@msg `{k}` must be [x, y] `{k}` musi mieć postać [x, y]
|
||||
@msg `{name}` has no options `{name}` nie ma opcji
|
||||
@msg `{name}` is a built-in workspace; choose another name `{name}` to wbudowany obszar roboczy; wybierz inną nazwę
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2741,6 +2741,7 @@
|
||||
Show Modified Показать изменённые
|
||||
Show Note Показать примечание
|
||||
Show Options Показать параметры
|
||||
Color Panel Options Параметры панели «Цвет»
|
||||
Show Package Показать пакет
|
||||
Show Panel Показать панель
|
||||
Show Pattern Swatches Показать образцы узоров
|
||||
@@ -3612,6 +3613,7 @@ axis Both Оба
|
||||
@msg `{key}` must be between {min} and {max} (got {x}) `{key}` должно быть от {min} до {max} (получено {x})
|
||||
@msg `{key}` must be one of {_1} `{key}` должно быть одним из: {_1}
|
||||
@msg `{key}` must be true or false `{key}` должно быть true или false
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe `mode` должно быть grayscale, rgb, hsb, cmyk или websafe
|
||||
@msg `{k}` must be [x, y] `{k}` должно быть [x, y]
|
||||
@msg `{name}` has no options `{name}` не имеет параметров
|
||||
@msg `{name}` is a built-in workspace; choose another name `{name}` — встроенная рабочая среда; выберите другое имя
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2737,6 +2737,7 @@
|
||||
Show Modified Показати змінені
|
||||
Show Note Показати примітку
|
||||
Show Options Показати параметри
|
||||
Color Panel Options Параметри панелі «Колір»
|
||||
Show Package Показати пакет
|
||||
Show Panel Показати панель
|
||||
Show Pattern Swatches Показати зразки візерунків
|
||||
@@ -3600,6 +3601,7 @@ axis Both Обидві
|
||||
@msg `{key}` must be between {min} and {max} (got {x}) `{key}` має бути від {min} до {max} (отримано {x})
|
||||
@msg `{key}` must be one of {_1} `{key}` має бути одним з: {_1}
|
||||
@msg `{key}` must be true or false `{key}` має бути true або false
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe `mode` має бути grayscale, rgb, hsb, cmyk або websafe
|
||||
@msg `{k}` must be [x, y] `{k}` має бути [x, y]
|
||||
@msg `{name}` has no options `{name}` не має параметрів
|
||||
@msg `{name}` is a built-in workspace; choose another name `{name}` - вбудоване робоче середовище; виберіть інше ім’я
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 715 and column 40.
|
@@ -3048,6 +3048,7 @@
|
||||
Show Modified Hiện đã sửa đổi
|
||||
Show Note Hiện ghi chú
|
||||
Show Options Hiện tùy chọn
|
||||
Color Panel Options Tùy chọn bảng màu
|
||||
Show Package Hiện gói
|
||||
Show Panel Hiện bảng
|
||||
Show Pattern Swatches Hiện mẫu họa tiết
|
||||
@@ -3733,6 +3734,7 @@ theme Appearance Giao diện
|
||||
@msg `{key}` must be between {min} and {max} (got {x}) `{key}` phải nằm trong khoảng {min} đến {max} (nhận được {x})
|
||||
@msg `{key}` must be one of {_1} `{key}` phải là một trong {_1}
|
||||
@msg `{key}` must be true or false `{key}` phải là true hoặc false
|
||||
@msg `mode` must be grayscale, rgb, hsb, cmyk or websafe `mode` phải là grayscale, rgb, hsb, cmyk hoặc websafe
|
||||
@msg `{k}` must be [x, y] `{k}` phải là [x, y]
|
||||
@msg `{name}` has no options `{name}` không có tùy chọn
|
||||
@msg `{name}` is a built-in workspace; choose another name `{name}` là không gian làm việc tích hợp sẵn; hãy chọn tên khác
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 3706 and column 10.
|
@@ -2594,6 +2594,7 @@
|
||||
Show Modified 显示已修改
|
||||
Show Note 显示注解
|
||||
Show Options 显示选项
|
||||
Color Panel Options 颜色面板选项
|
||||
Show Package 显示打包
|
||||
Show Panel 显示面板
|
||||
Show Pattern Swatches 显示图案色板
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2723,6 +2723,7 @@
|
||||
Show Modified 顯示已修改
|
||||
Show Note 顯示註解
|
||||
Show Options 顯示選項
|
||||
Color Panel Options 顏色面板選項
|
||||
Show Package 顯示封裝
|
||||
Show Panel 顯示面板
|
||||
Show Pattern Swatches 顯示圖樣色票
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -620,6 +620,12 @@ pub const UI_COMMANDS: &[(&str, &str, &str, &str)] = &[
|
||||
"",
|
||||
"{library: swatch library id or name (see swatch.library.list) | \"document\" (the document's swatches) | \"\" or null (no limit)} limit the Color Guide panel's colours to that library: every harmony colour and variation snaps to its nearest colour, as color.harmony {limitTo} answers (ui.inspect: ui.color_guide_limit) → {limitTo, name}",
|
||||
),
|
||||
(
|
||||
"ui.colorPanel",
|
||||
"Color Panel Options",
|
||||
"",
|
||||
"{mode?: grayscale|rgb|hsb|cmyk|websafe, options?: bool} pick the Color panel's mode as its panel menu does (the active color converts to the mode's model as one undo step), and Show Options (true) or Hide Options (false); both are kept with the preferences (ui.inspect: ui.color_mode, ui.color_hide_options) → {mode (null: none picked yet), options, shown: the mode the panel shows the color in, or tint for a tint of a global or spot swatch}",
|
||||
),
|
||||
(
|
||||
"ui.savePdfDialog",
|
||||
"Save PDF Dialog",
|
||||
@@ -1425,6 +1431,7 @@ pub fn run_ui_command(app: &mut VectorcraftApp, id: &str, p: &Value) -> Option<R
|
||||
"ui.widthPointEdit" => crate::dialogs::width_point::open(app, p),
|
||||
"ui.corners" => crate::dialogs::corners::open(app, p),
|
||||
"ui.colorGuideLimit" => crate::panels::color_guide::set_limit(app, p),
|
||||
"ui.colorPanel" => crate::panels::color::command(app, p),
|
||||
"ui.savePdfDialog" => crate::dialogs::open_save_pdf(app, p),
|
||||
"file.exportAs" if s("path").is_none() => {
|
||||
crate::dialogs::open_export_as(app, s("format").as_deref(), p);
|
||||
|
||||
@@ -9,10 +9,11 @@
|
||||
//! model and shows the defaults for new art; the app keeps it between sessions). Alt-clicking the
|
||||
//! spectrum or a chip paints the inactive proxy; Shift-clicking the spectrum cycles the modes;
|
||||
//! Shift-dragging a slider moves the others in tandem; RGB and HSB show the out-of-gamut warning;
|
||||
//! Hide Options leaves just the proxy and the spectrum.
|
||||
//! Hide Options leaves just the proxy and the spectrum (the app keeps it between sessions too).
|
||||
//! `ui.colorPanel` picks a mode and shows or hides the options as the panel menu does.
|
||||
|
||||
use egui::{Color32, Rect, Sense, Stroke, StrokeKind, Ui, vec2};
|
||||
use serde_json::json;
|
||||
use serde_json::{Value, json};
|
||||
use vectorcraft_color::{Color, GradientKind, Paint};
|
||||
|
||||
use super::{active_paint, color_json, live_run, pstate, set_pstate};
|
||||
@@ -251,8 +252,21 @@ pub(crate) fn gamut_fix(app: &mut VectorcraftApp, ctx: &egui::Context, key: &str
|
||||
/// Serde reader for the saved panel mode ([`crate::UiState::color_mode`]): a menu mode, else none,
|
||||
/// so an unknown value doesn't lose the rest of the preferences.
|
||||
pub fn deserialize_mode<'de, D: serde::Deserializer<'de>>(d: D) -> Result<Option<Mode>, D::Error> {
|
||||
let v = <serde_json::Value as serde::Deserialize>::deserialize(d)?;
|
||||
Ok(Mode::ALL.into_iter().find(|m| serde_json::to_value(m).is_ok_and(|id| id == v)))
|
||||
let v = <Value as serde::Deserialize>::deserialize(d)?;
|
||||
Ok(menu_mode(&v))
|
||||
}
|
||||
|
||||
/// The menu mode whose id (`"grayscale"`, `"rgb"`, `"hsb"`, `"cmyk"`, `"websafe"`) is `v`.
|
||||
fn menu_mode(v: &Value) -> Option<Mode> {
|
||||
Mode::ALL.into_iter().find(|m| serde_json::to_value(m).is_ok_and(|id| id == *v))
|
||||
}
|
||||
|
||||
/// Serde reader for the saved Hide Options ([`crate::UiState::color_hide_options`]): `true` hides
|
||||
/// the options and any other value shows them, so an unknown value doesn't lose the rest of the
|
||||
/// preferences.
|
||||
pub fn deserialize_hide_options<'de, D: serde::Deserializer<'de>>(d: D) -> Result<bool, D::Error> {
|
||||
let v = <Value as serde::Deserialize>::deserialize(d)?;
|
||||
Ok(v.as_bool().unwrap_or_default())
|
||||
}
|
||||
|
||||
/// The mode the panel shows `color` in: with nothing selected (the defaults for new art) the mode
|
||||
@@ -366,7 +380,13 @@ impl Target {
|
||||
|
||||
/// The active proxy's colour or gradient stop; no colour for None, patterns and a "?" proxy.
|
||||
fn target(app: &VectorcraftApp, ui: &Ui) -> Target {
|
||||
if super::active_mixed(app, ui.ctx()) {
|
||||
target_with(app, super::active_mixed(app, ui.ctx()))
|
||||
}
|
||||
|
||||
/// [`target`] with `mixed` for a "?" active proxy: the panel reads it from its per-frame cache,
|
||||
/// `ui.colorPanel` from the session.
|
||||
fn target_with(app: &VectorcraftApp, mixed: bool) -> Target {
|
||||
if mixed {
|
||||
return Target::Paint(None, None);
|
||||
}
|
||||
let p = active_paint(app);
|
||||
@@ -439,6 +459,32 @@ fn set_mode(app: &mut VectorcraftApp, tgt: &Target, mode: Mode) {
|
||||
}
|
||||
}
|
||||
|
||||
/// `ui.colorPanel {mode?, options?}`: pick a mode as the panel menu does ([`set_mode`]), and Show
|
||||
/// Options (true) or Hide Options (false). → {mode, options, shown}: the mode picked last (null:
|
||||
/// none yet), whether the options show, and the mode the panel shows the color in (`tint` for a
|
||||
/// tint of a global or spot swatch).
|
||||
pub(crate) fn command(app: &mut VectorcraftApp, p: &Value) -> Result<Value, String> {
|
||||
let mode = match p.get("mode") {
|
||||
None | Some(Value::Null) => None,
|
||||
Some(v) => Some(menu_mode(v).ok_or("`mode` must be grayscale, rgb, hsb, cmyk or websafe")?),
|
||||
};
|
||||
let options = crate::menus::opt_bool(p, "options")?;
|
||||
let (fill, stroke) = app.session.proxy_mixed();
|
||||
let mixed = if app.session.fill_active { fill } else { stroke };
|
||||
if let Some(m) = mode {
|
||||
set_mode(app, &target_with(app, mixed), m);
|
||||
}
|
||||
if let Some(shown) = options {
|
||||
app.ui.color_hide_options = !shown;
|
||||
}
|
||||
let tgt = target_with(app, mixed);
|
||||
let shown = match tgt.tint() {
|
||||
Some(_) => json!("tint"),
|
||||
None => json!(shown_mode(app, tgt.color().as_ref())),
|
||||
};
|
||||
Ok(json!({"mode": app.ui.color_mode, "options": !app.ui.color_hide_options, "shown": shown}))
|
||||
}
|
||||
|
||||
/// Tint mode's rows: the swatch's chip and name, and the T slider and field. Returns a new tint
|
||||
/// (0..1) and its phase.
|
||||
fn tint_rows(ui: &mut Ui, tint: &Tint, slider_w: f32, field_w: f32) -> Option<(f32, Live)> {
|
||||
@@ -494,7 +540,7 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
let mode = shown_mode(app, color.as_ref());
|
||||
let alt = super::alt_held(ui);
|
||||
// Hide Options: just the proxy and the spectrum.
|
||||
if pstate::<bool>(ui.ctx(), "color-hide-options") {
|
||||
if app.ui.color_hide_options {
|
||||
let hit = ui
|
||||
.horizontal(|ui| {
|
||||
super::proxy(app, ui, 40.0);
|
||||
@@ -650,9 +696,9 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
}
|
||||
|
||||
pub fn menu(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
let hidden: bool = pstate(ui.ctx(), "color-hide-options");
|
||||
let hidden = app.ui.color_hide_options;
|
||||
if menu_item(ui, if hidden { tl!("Show Options") } else { tl!("Hide Options") }, true, false) {
|
||||
set_pstate(ui.ctx(), "color-hide-options", !hidden);
|
||||
command(app, &json!({ "options": hidden })).ok();
|
||||
}
|
||||
ui.separator();
|
||||
let tgt = target(app, ui);
|
||||
@@ -1047,9 +1093,77 @@ mod tests {
|
||||
let ctx = egui::Context::default();
|
||||
let (spectrum, full) = frame(&mut app, &ctx, vec![], egui::Modifiers::NONE);
|
||||
assert!(spectrum.is_some());
|
||||
set_pstate(&ctx, "color-hide-options", true);
|
||||
assert_eq!(app.run("ui.colorPanel", json!({"options": false})).unwrap()["options"], false);
|
||||
let (_, hidden) = frame(&mut app, &ctx, vec![], egui::Modifiers::NONE);
|
||||
assert!(hidden <= 44.0 && full > 150.0, "{hidden} / {full}");
|
||||
app.run("ui.colorPanel", json!({"options": true})).unwrap();
|
||||
assert_eq!(frame(&mut app, &ctx, vec![], egui::Modifiers::NONE).1, full);
|
||||
}
|
||||
|
||||
/// Hide Options is kept with the UI state, which the app saves with its preferences. A saved
|
||||
/// value that isn't true or false reads as Show Options, and the rest of the state still loads.
|
||||
#[test]
|
||||
fn hide_options_comes_back_after_a_restart() {
|
||||
let mut app = app();
|
||||
app.run("ui.colorPanel", json!({"options": false})).unwrap();
|
||||
let saved: crate::UiState = serde_json::from_value(serde_json::to_value(&app.ui).unwrap()).unwrap();
|
||||
assert!(saved.color_hide_options);
|
||||
assert_eq!(crate::control::inspect(&app, &egui::Context::default())["ui"]["color_hide_options"], true);
|
||||
for v in [json!(7), json!("hide"), json!({}), Value::Null] {
|
||||
let ui: crate::UiState = serde_json::from_value(json!({"color_hide_options": v, "color_mode": "future", "place_link": false})).unwrap();
|
||||
assert_eq!((ui.color_hide_options, ui.color_mode, ui.place_link), (false, None, false), "{v}");
|
||||
}
|
||||
}
|
||||
|
||||
/// `ui.colorPanel {mode}` picks a mode as the panel menu does: HSB shows an RGB fill as H, S and
|
||||
/// B, and CMYK converts it as one undo step.
|
||||
#[test]
|
||||
fn ui_color_panel_picks_a_mode_as_the_menu_does() {
|
||||
let mut app = app();
|
||||
let ctx = egui::Context::default();
|
||||
app.run("paint.setFill", json!({"color": "#336699"})).unwrap();
|
||||
let r = app.run("ui.colorPanel", json!({"mode": "hsb"})).unwrap();
|
||||
assert_eq!(r, json!({"mode": "hsb", "options": true, "shown": "hsb"}));
|
||||
assert_eq!(slider_labels(&mut app, &ctx), ["H", "S", "B"]);
|
||||
assert_eq!(crate::control::inspect(&app, &ctx)["ui"]["color_mode"], "hsb");
|
||||
assert_eq!(paints_hex(&app).0, "#336699", "HSB keeps the RGB color");
|
||||
assert_eq!(app.run("ui.colorPanel", json!({"mode": "cmyk"})).unwrap()["shown"], "cmyk");
|
||||
assert!(matches!(crate::panels::current_paints(&app).0.color(), Some(Color::Cmyk { .. })), "CMYK converts the color");
|
||||
app.run("edit.undo", json!({})).unwrap();
|
||||
assert!(matches!(crate::panels::current_paints(&app).0.color(), Some(Color::Rgb { .. })), "undo restores it");
|
||||
assert_eq!(paints_hex(&app).0, "#336699");
|
||||
// `{}` reads the settings: CMYK stays picked, and the RGB fill shows in its own model.
|
||||
assert_eq!(app.run("ui.colorPanel", json!({})).unwrap(), json!({"mode": "cmyk", "options": true, "shown": "rgb"}));
|
||||
// A tint of a global swatch shows Tint mode.
|
||||
app.run("swatch.new", json!({"name": "Ink", "color": {"c": 0, "m": 1, "y": 0, "k": 0}, "spot": true})).unwrap();
|
||||
app.run("paint.setFill", json!({"swatch": "Ink", "tint": 50})).unwrap();
|
||||
assert_eq!(app.run("ui.colorPanel", json!({})).unwrap()["shown"], "tint");
|
||||
}
|
||||
|
||||
/// A mode the panel menu doesn't list, Lab included, and an options value that isn't true or
|
||||
/// false answer an error, and the command then changes nothing.
|
||||
#[test]
|
||||
fn ui_color_panel_answers_an_error_for_a_mode_off_the_menu() {
|
||||
let mut app = app();
|
||||
for m in [json!("lab"), json!("oklch"), json!("hsl"), json!("future"), json!("RGB"), json!(3)] {
|
||||
let e = app.run("ui.colorPanel", json!({"mode": m})).unwrap_err();
|
||||
assert_eq!(e, "`mode` must be grayscale, rgb, hsb, cmyk or websafe", "{m}");
|
||||
}
|
||||
assert_eq!(app.run("ui.colorPanel", json!({"mode": "cmyk", "options": "no"})).unwrap_err(), "`options` must be true or false");
|
||||
assert_eq!((app.ui.color_mode, app.ui.color_hide_options), (None, false));
|
||||
}
|
||||
|
||||
/// `ui.colorPanel` answers every junk parameter, with and without a document, without a panic.
|
||||
#[test]
|
||||
fn ui_color_panel_answers_junk_params_without_a_panic() {
|
||||
let doc = crate::menus::UI_COMMANDS.iter().find(|c| c.0 == "ui.colorPanel").expect("registered").3;
|
||||
let mut app = app();
|
||||
app.run("paint.setFill", json!({"color": "#336699"})).unwrap();
|
||||
for p in vectorcraft_testkit::strategies::junk_params(doc, "/nonexistent").into_iter().chain(vectorcraft_testkit::strategies::junk_values()) {
|
||||
let _ = app.run("ui.colorPanel", p);
|
||||
}
|
||||
let mut app = VectorcraftApp::new(Session::new(), Default::default());
|
||||
assert_eq!(app.run("ui.colorPanel", json!({"mode": "cmyk"})).unwrap()["mode"], "cmyk");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -380,6 +380,10 @@ pub struct UiState {
|
||||
/// shows the defaults for new art ([`crate::panels::color::deserialize_mode`]).
|
||||
#[serde(default, deserialize_with = "crate::panels::color::deserialize_mode")]
|
||||
pub color_mode: Option<crate::panels::color::Mode>,
|
||||
/// Color panel: Hide Options, which leaves just the proxy and the spectrum (`ui.colorPanel`,
|
||||
/// [`crate::panels::color::deserialize_hide_options`]).
|
||||
#[serde(default, deserialize_with = "crate::panels::color::deserialize_hide_options")]
|
||||
pub color_hide_options: bool,
|
||||
/// The SVG Options chosen last (`svg` object of the export/save commands; null: never used).
|
||||
#[serde(default)]
|
||||
pub svg_options: Value,
|
||||
@@ -715,6 +719,7 @@ impl Default for UiState {
|
||||
color_guide_limit: String::new(),
|
||||
align_to: Default::default(),
|
||||
color_mode: None,
|
||||
color_hide_options: false,
|
||||
svg_options: Value::Null,
|
||||
place_link: true,
|
||||
dialog_file: None,
|
||||
|
||||
@@ -207,6 +207,13 @@ Edit or Apply Colors runs `ui.recolorDialog {colors, library?}` with the harmony
|
||||
recolours as usual; with nothing selected the colours themselves are the rows and `ui.dialog.confirm` saves them as a
|
||||
new colour group (`swatch.newGroup`, named by the `groupName` field).
|
||||
|
||||
Color panel options: `ui.colorPanel {mode?, options?}` picks the panel's mode as its panel menu does (`grayscale`,
|
||||
`rgb`, `hsb`, `cmyk` or `websafe`; the active color converts to the mode's model as one undo step) and shows
|
||||
(`options: true`) or hides (`false`) the options. It answers `{mode, options, shown}`: `mode` is null until a mode is
|
||||
picked, and `shown` is the mode the panel shows the color in, or `tint` for a tint of a global or spot swatch.
|
||||
Another mode, `lab` included, answers an error. The desktop app keeps both settings with its preferences, and
|
||||
`ui.inspect` reports them as `ui.color_mode` and `ui.color_hide_options`.
|
||||
|
||||
Color Themes panel (`window.panel {panel: "colorThemes"}`): its Create tab makes a theme on a harmony wheel and its
|
||||
My Themes tab lists the saved themes; every action runs a command (`colorTheme.save`, `colorTheme.delete`,
|
||||
`colorTheme.addToSwatches`, `swatch.newGroup` for the theme being made), and `colorTheme.list` reads the library.
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user