From c21a1e653894c04a2c11b0da3df1d98576da7037 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 7 Oct 2026 18:38:04 +0000 Subject: [PATCH] Graphic Attributes: tidy helpers, split tests, translate the palette - The hatch pattern picker takes its messages as one PatternPickerMessages struct instead of eight arguments. - The palette's fill index is keyed on the scene's geometry epoch alone; epochs are unique across scenes, so the scene address is not needed. - The ribbon lineweight handler is an on_ribbon_lineweight_changed method, used by the palette instead of a recursive update() call. - The 430-line palette test is split into eight focused tests with shared helpers; no checks were dropped. - Palette, gradient editor, prompts, messages and undo labels go through t!/tf!. The 33 new strings are in a graphic-attributes Fluent group in all 21 locales; "[Yes / No] ", ByLayer and ByBlock stay English. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VgkJN8DEojuPTumAXLHotu --- locales/ar-SA/opencadstudio.ftl | 35 ++ locales/bg-BG/opencadstudio.ftl | 35 ++ locales/cs-CZ/opencadstudio.ftl | 35 ++ locales/de-DE/opencadstudio.ftl | 35 ++ locales/el-GR/opencadstudio.ftl | 35 ++ locales/en-US/opencadstudio.ftl | 35 ++ locales/es-ES/opencadstudio.ftl | 35 ++ locales/fi-FI/opencadstudio.ftl | 35 ++ locales/fr-FR/opencadstudio.ftl | 35 ++ locales/hi-IN/opencadstudio.ftl | 35 ++ locales/hu-HU/opencadstudio.ftl | 35 ++ locales/it-IT/opencadstudio.ftl | 35 ++ locales/ja-JP/opencadstudio.ftl | 35 ++ locales/ko-KR/opencadstudio.ftl | 35 ++ locales/nl-NL/opencadstudio.ftl | 35 ++ locales/pl-PL/opencadstudio.ftl | 35 ++ locales/pt-BR/opencadstudio.ftl | 35 ++ locales/ru-RU/opencadstudio.ftl | 35 ++ locales/tr-TR/opencadstudio.ftl | 35 ++ locales/zh-CN/opencadstudio.ftl | 35 ++ locales/zh-TW/opencadstudio.ftl | 35 ++ src/app/update/command.rs | 26 ++ src/app/update/graphic_attributes.rs | 580 +++++++++------------------ src/app/update/mod.rs | 26 +- src/locale_catalog.rs | 33 ++ src/ui/properties.rs | 35 +- src/ui/window/gradient_editor.rs | 36 +- src/ui/window/graphic_attributes.rs | 71 ++-- 28 files changed, 1060 insertions(+), 482 deletions(-) diff --git a/locales/ar-SA/opencadstudio.ftl b/locales/ar-SA/opencadstudio.ftl index 63a632194..0766b2552 100644 --- a/locales/ar-SA/opencadstudio.ftl +++ b/locales/ar-SA/opencadstudio.ftl @@ -5627,3 +5627,38 @@ style-manager = .center-of-text-overline = مركز النص مع خط علوي .block-extents = نطاق الكتلة .base-point = نقطة الأساس + +graphic-attributes = + .title = سمات الرسم + .set-all-bylayer = تعيين كل السمات إلى ByLayer + .set-all-byblock = تعيين كل السمات إلى ByBlock + .remove-bylayer-byblock = إزالة ByLayer / ByBlock + .create-layer-active-settings = إنشاء طبقة بالإعدادات النشطة + .fills-on-current-layer = إنشاء التعبئات على الطبقة الحالية + .edit-hatch = تحرير التهشير + .edit-gradient = تحرير التدرج + .close-open-object = الكائن المحدد مفتوح. هل تريد إغلاقه قبل إنشاء التعبئة؟ [Yes / No] + .close-open-objects = __ocs_fmt_0__ من الكائنات المحددة مفتوحة. هل تريد إغلاقها قبل إنشاء التعبئة؟ [Yes / No] + .enter-new-layer-name = أدخل اسمًا للطبقة الجديدة: + .invalid-layer-name = سمات الرسم: أدخل اسم طبقة صالحًا بدون <>/\":;?*|,=`. + .layer-exists = سمات الرسم: الطبقة "__ocs_fmt_0__" موجودة بالفعل. + .layer-not-created = سمات الرسم: تعذر إنشاء الطبقة. + .layer-created = تم إنشاء الطبقة "__ocs_fmt_0__" بإعدادات سمات الرسم النشطة. + .gradient-fill-locked = تعبئة متدرجة: التعبئة على طبقة مقفلة. + .select-closed-objects = حدد كائنًا مغلقًا واحدًا أو أكثر أولاً. + .locked-objects-skipped = سمات الرسم: لم يتم تغيير __ocs_fmt_0__ من الكائنات على طبقة مقفلة. + .no-hatch-pattern = سمات الرسم: لا يتوفر نمط تهشير. + .associated-fill-locked = سمات الرسم: توجد تعبئة مرتبطة على طبقة مقفلة. + .one-unsupported = سمات الرسم: لم يتم تغيير كائن واحد غير مدعوم. + .unsupported-skipped = سمات الرسم: لم يتم تغيير __ocs_fmt_0__ من الكائنات غير المدعومة. + .fill-transparency = شفافية التعبئة + .line-linetype = نوع خط الخطوط + .line-transparency = شفافية الخطوط + .cylindrical-short = أسطواني + .spherical-short = كروي + .hemispherical-short = نصف كروي + .invert-gradient = عكس التدرج + .tone = الدرجة + .reset-angle = إعادة تعيين الزاوية + .one-color = لون واحد + .two-colors = لونان diff --git a/locales/bg-BG/opencadstudio.ftl b/locales/bg-BG/opencadstudio.ftl index 3c2daed2b..bc8e77fe8 100644 --- a/locales/bg-BG/opencadstudio.ftl +++ b/locales/bg-BG/opencadstudio.ftl @@ -5615,3 +5615,38 @@ style-manager = .center-of-text-overline = Център на надчертан текст .block-extents = Обхват на блок .base-point = Базова точка + +graphic-attributes = + .title = Графични атрибути + .set-all-bylayer = Задаване на всички атрибути на ByLayer + .set-all-byblock = Задаване на всички атрибути на ByBlock + .remove-bylayer-byblock = Премахване на ByLayer / ByBlock + .create-layer-active-settings = Създаване на слой с активните настройки + .fills-on-current-layer = Създаване на запълвания в текущия слой + .edit-hatch = Редактиране на щриховката + .edit-gradient = Редактиране на преливането + .close-open-object = Избраният обект е отворен. Да се затвори ли преди създаване на запълването? [Yes / No] + .close-open-objects = __ocs_fmt_0__ от избраните обекти са отворени. Да се затворят ли преди създаване на запълването? [Yes / No] + .enter-new-layer-name = Въведете име за новия слой: + .invalid-layer-name = Графични атрибути: въведете валидно име на слой без <>/\":;?*|,=`. + .layer-exists = Графични атрибути: слоят "__ocs_fmt_0__" вече съществува. + .layer-not-created = Графични атрибути: слоят не можа да бъде създаден. + .layer-created = Създаден е слой "__ocs_fmt_0__" с активните настройки на графичните атрибути. + .gradient-fill-locked = Преливащо запълване: запълването е в заключен слой. + .select-closed-objects = Първо изберете един или повече затворени обекта. + .locked-objects-skipped = Графични атрибути: __ocs_fmt_0__ обекта в заключен слой не бяха променени. + .no-hatch-pattern = Графични атрибути: няма наличен шаблон за щриховка. + .associated-fill-locked = Графични атрибути: свързано запълване е в заключен слой. + .one-unsupported = Графични атрибути: 1 неподдържан обект не беше променен. + .unsupported-skipped = Графични атрибути: __ocs_fmt_0__ неподдържани обекта не бяха променени. + .fill-transparency = Прозрачност на запълването + .line-linetype = Тип линия на линиите + .line-transparency = Прозрачност на линиите + .cylindrical-short = Цил. + .spherical-short = Сфер. + .hemispherical-short = Полусф. + .invert-gradient = Обръщане на преливането + .tone = Тон + .reset-angle = Нулиране на ъгъла + .one-color = Един цвят + .two-colors = Два цвята diff --git a/locales/cs-CZ/opencadstudio.ftl b/locales/cs-CZ/opencadstudio.ftl index 8b099c672..bfbd5cec9 100644 --- a/locales/cs-CZ/opencadstudio.ftl +++ b/locales/cs-CZ/opencadstudio.ftl @@ -5612,3 +5612,38 @@ style-manager = .center-of-text-overline = Střed textu s přeškrtnutím .block-extents = Blokovat rozsahy .base-point = Základní bod + +graphic-attributes = + .title = Grafické atributy + .set-all-bylayer = Nastavit všechny atributy na ByLayer + .set-all-byblock = Nastavit všechny atributy na ByBlock + .remove-bylayer-byblock = Odebrat ByLayer / ByBlock + .create-layer-active-settings = Vytvořit hladinu s aktivním nastavením + .fills-on-current-layer = Vytvářet výplně v aktuální hladině + .edit-hatch = Upravit šrafu + .edit-gradient = Upravit přechod + .close-open-object = Vybraný objekt je otevřený. Uzavřít jej před vytvořením výplně? [Yes / No] + .close-open-objects = Vybrané objekty jsou otevřené (__ocs_fmt_0__). Uzavřít je před vytvořením výplně? [Yes / No] + .enter-new-layer-name = Zadejte název nové hladiny: + .invalid-layer-name = Grafické atributy: zadejte platný název hladiny bez <>/\":;?*|,=`. + .layer-exists = Grafické atributy: hladina "__ocs_fmt_0__" již existuje. + .layer-not-created = Grafické atributy: hladinu nelze vytvořit. + .layer-created = Hladina "__ocs_fmt_0__" byla vytvořena s aktivním nastavením grafických atributů. + .gradient-fill-locked = Přechodová výplň: výplň je v zamčené hladině. + .select-closed-objects = Nejprve vyberte jeden nebo více uzavřených objektů. + .locked-objects-skipped = Grafické atributy: objekty v zamčené hladině (__ocs_fmt_0__) nebyly změněny. + .no-hatch-pattern = Grafické atributy: není k dispozici žádný vzor šraf. + .associated-fill-locked = Grafické atributy: přidružená výplň je v zamčené hladině. + .one-unsupported = Grafické atributy: 1 nepodporovaný objekt nebyl změněn. + .unsupported-skipped = Grafické atributy: nepodporované objekty (__ocs_fmt_0__) nebyly změněny. + .fill-transparency = Průhlednost výplně + .line-linetype = Typ čáry + .line-transparency = Průhlednost čar + .cylindrical-short = Válc. + .spherical-short = Kul. + .hemispherical-short = Polokul. + .invert-gradient = Obrátit přechod + .tone = Tón + .reset-angle = Obnovit úhel + .one-color = Jedna barva + .two-colors = Dvě barvy diff --git a/locales/de-DE/opencadstudio.ftl b/locales/de-DE/opencadstudio.ftl index 225f32ba6..9708790cf 100644 --- a/locales/de-DE/opencadstudio.ftl +++ b/locales/de-DE/opencadstudio.ftl @@ -5613,3 +5613,38 @@ style-manager = .center-of-text-overline = Textzentrum mit Oberstrich .block-extents = Blockgrenzen .base-point = Basispunkt + +graphic-attributes = + .title = Grafikattribute + .set-all-bylayer = Alle Attribute auf ByLayer setzen + .set-all-byblock = Alle Attribute auf ByBlock setzen + .remove-bylayer-byblock = ByLayer / ByBlock entfernen + .create-layer-active-settings = Layer mit aktiven Einstellungen erstellen + .fills-on-current-layer = Füllungen auf dem aktuellen Layer erstellen + .edit-hatch = Schraffur bearbeiten + .edit-gradient = Verlauf bearbeiten + .close-open-object = Das ausgewählte Objekt ist offen. Vor dem Erstellen der Füllung schließen? [Yes / No] + .close-open-objects = __ocs_fmt_0__ ausgewählte Objekte sind offen. Vor dem Erstellen der Füllung schließen? [Yes / No] + .enter-new-layer-name = Namen für den neuen Layer eingeben: + .invalid-layer-name = Grafikattribute: gültigen Layernamen ohne <>/\":;?*|,=` eingeben. + .layer-exists = Grafikattribute: Layer "__ocs_fmt_0__" ist bereits vorhanden. + .layer-not-created = Grafikattribute: Der Layer konnte nicht erstellt werden. + .layer-created = Layer "__ocs_fmt_0__" mit den aktiven Grafikattributen erstellt. + .gradient-fill-locked = Verlaufsfüllung: Die Füllung liegt auf einem gesperrten Layer. + .select-closed-objects = Zuerst ein oder mehrere geschlossene Objekte auswählen. + .locked-objects-skipped = Grafikattribute: __ocs_fmt_0__ Objekt(e) auf einem gesperrten Layer wurden nicht geändert. + .no-hatch-pattern = Grafikattribute: Kein Schraffurmuster verfügbar. + .associated-fill-locked = Grafikattribute: Eine zugehörige Füllung liegt auf einem gesperrten Layer. + .one-unsupported = Grafikattribute: 1 nicht unterstütztes Objekt wurde nicht geändert. + .unsupported-skipped = Grafikattribute: __ocs_fmt_0__ nicht unterstützte Objekte wurden nicht geändert. + .fill-transparency = Füllungstransparenz + .line-linetype = Linientyp der Linien + .line-transparency = Linientransparenz + .cylindrical-short = Zyl. + .spherical-short = Kugel + .hemispherical-short = Halbk. + .invert-gradient = Verlauf umkehren + .tone = Ton + .reset-angle = Winkel zurücksetzen + .one-color = Einfarbig + .two-colors = Zweifarbig diff --git a/locales/el-GR/opencadstudio.ftl b/locales/el-GR/opencadstudio.ftl index ef73bc35e..e9aac1bb9 100644 --- a/locales/el-GR/opencadstudio.ftl +++ b/locales/el-GR/opencadstudio.ftl @@ -5615,3 +5615,38 @@ style-manager = .center-of-text-overline = Κέντρο του κειμένου με επιγράμμιση .block-extents = Όρια μπλοκ .base-point = Σημείο βάσης + +graphic-attributes = + .title = Γραφικά χαρακτηριστικά + .set-all-bylayer = Ορισμός όλων των χαρακτηριστικών σε ByLayer + .set-all-byblock = Ορισμός όλων των χαρακτηριστικών σε ByBlock + .remove-bylayer-byblock = Αφαίρεση ByLayer / ByBlock + .create-layer-active-settings = Δημιουργία επιπέδου με τις ενεργές ρυθμίσεις + .fills-on-current-layer = Δημιουργία γεμισμάτων στο τρέχον επίπεδο + .edit-hatch = Επεξεργασία διαγράμμισης + .edit-gradient = Επεξεργασία διαβάθμισης + .close-open-object = Το επιλεγμένο αντικείμενο είναι ανοιχτό. Να κλείσει πριν από τη δημιουργία του γεμίσματος; [Yes / No] + .close-open-objects = __ocs_fmt_0__ επιλεγμένα αντικείμενα είναι ανοιχτά. Να κλείσουν πριν από τη δημιουργία του γεμίσματος; [Yes / No] + .enter-new-layer-name = Εισαγάγετε όνομα για το νέο επίπεδο: + .invalid-layer-name = Γραφικά χαρακτηριστικά: εισαγάγετε έγκυρο όνομα επιπέδου χωρίς <>/\":;?*|,=`. + .layer-exists = Γραφικά χαρακτηριστικά: το επίπεδο "__ocs_fmt_0__" υπάρχει ήδη. + .layer-not-created = Γραφικά χαρακτηριστικά: δεν ήταν δυνατή η δημιουργία του επιπέδου. + .layer-created = Δημιουργήθηκε το επίπεδο "__ocs_fmt_0__" με τις ενεργές ρυθμίσεις γραφικών χαρακτηριστικών. + .gradient-fill-locked = Γέμισμα διαβάθμισης: το γέμισμα βρίσκεται σε κλειδωμένο επίπεδο. + .select-closed-objects = Επιλέξτε πρώτα ένα ή περισσότερα κλειστά αντικείμενα. + .locked-objects-skipped = Γραφικά χαρακτηριστικά: __ocs_fmt_0__ αντικείμενα σε κλειδωμένο επίπεδο δεν άλλαξαν. + .no-hatch-pattern = Γραφικά χαρακτηριστικά: δεν υπάρχει διαθέσιμο μοτίβο διαγράμμισης. + .associated-fill-locked = Γραφικά χαρακτηριστικά: ένα συσχετισμένο γέμισμα βρίσκεται σε κλειδωμένο επίπεδο. + .one-unsupported = Γραφικά χαρακτηριστικά: 1 μη υποστηριζόμενο αντικείμενο δεν άλλαξε. + .unsupported-skipped = Γραφικά χαρακτηριστικά: __ocs_fmt_0__ μη υποστηριζόμενα αντικείμενα δεν άλλαξαν. + .fill-transparency = Διαφάνεια γεμίσματος + .line-linetype = Τύπος γραμμής + .line-transparency = Διαφάνεια γραμμών + .cylindrical-short = Κυλ. + .spherical-short = Σφαιρ. + .hemispherical-short = Ημισφ. + .invert-gradient = Αντιστροφή διαβάθμισης + .tone = Τόνος + .reset-angle = Επαναφορά γωνίας + .one-color = Ένα χρώμα + .two-colors = Δύο χρώματα diff --git a/locales/en-US/opencadstudio.ftl b/locales/en-US/opencadstudio.ftl index 109c504f8..456f168f4 100644 --- a/locales/en-US/opencadstudio.ftl +++ b/locales/en-US/opencadstudio.ftl @@ -5616,3 +5616,38 @@ style-manager = .center-of-text-overline = Center of text with overline .block-extents = Block extents .base-point = Base point + +graphic-attributes = + .title = Graphic Attributes + .set-all-bylayer = Set all attributes ByLayer + .set-all-byblock = Set all attributes ByBlock + .remove-bylayer-byblock = Remove ByLayer / ByBlock + .create-layer-active-settings = Create Layer with active settings + .fills-on-current-layer = Create fills on the current layer + .edit-hatch = Edit hatch + .edit-gradient = Edit gradient + .close-open-object = The selected object is open. Close it before creating the fill? [Yes / No] + .close-open-objects = __ocs_fmt_0__ selected objects are open. Close them before creating the fill? [Yes / No] + .enter-new-layer-name = Enter a name for the new layer: + .invalid-layer-name = Graphic Attributes: enter a valid layer name without <>/\":;?*|,=`. + .layer-exists = Graphic Attributes: layer "__ocs_fmt_0__" already exists. + .layer-not-created = Graphic Attributes: the layer could not be created. + .layer-created = Created layer "__ocs_fmt_0__" with the active Graphic Attributes settings. + .gradient-fill-locked = Gradient Fill: the fill is on a locked layer. + .select-closed-objects = Select one or more closed objects first. + .locked-objects-skipped = Graphic Attributes: __ocs_fmt_0__ object(s) on a locked layer were not changed. + .no-hatch-pattern = Graphic Attributes: no hatch pattern is available. + .associated-fill-locked = Graphic Attributes: an associated fill is on a locked layer. + .one-unsupported = Graphic Attributes: 1 unsupported object was not changed. + .unsupported-skipped = Graphic Attributes: __ocs_fmt_0__ unsupported objects were not changed. + .fill-transparency = Fill transparency + .line-linetype = Line linetype + .line-transparency = Line transparency + .cylindrical-short = Cyl. + .spherical-short = Spher. + .hemispherical-short = Hemi. + .invert-gradient = Invert gradient + .tone = Tone + .reset-angle = Reset angle + .one-color = One Color + .two-colors = Two Colors diff --git a/locales/es-ES/opencadstudio.ftl b/locales/es-ES/opencadstudio.ftl index 7faf157ce..8005d34de 100644 --- a/locales/es-ES/opencadstudio.ftl +++ b/locales/es-ES/opencadstudio.ftl @@ -5615,3 +5615,38 @@ style-manager = .center-of-text-overline = Centro del texto con suprarrayado .block-extents = Extensión del bloque .base-point = Punto base + +graphic-attributes = + .title = Atributos gráficos + .set-all-bylayer = Establecer todos los atributos en ByLayer + .set-all-byblock = Establecer todos los atributos en ByBlock + .remove-bylayer-byblock = Quitar ByLayer / ByBlock + .create-layer-active-settings = Crear capa con la configuración activa + .fills-on-current-layer = Crear rellenos en la capa actual + .edit-hatch = Editar sombreado + .edit-gradient = Editar degradado + .close-open-object = El objeto seleccionado está abierto. ¿Cerrarlo antes de crear el relleno? [Yes / No] + .close-open-objects = __ocs_fmt_0__ objetos seleccionados están abiertos. ¿Cerrarlos antes de crear el relleno? [Yes / No] + .enter-new-layer-name = Introduzca un nombre para la capa nueva: + .invalid-layer-name = Atributos gráficos: introduzca un nombre de capa válido sin <>/\":;?*|,=`. + .layer-exists = Atributos gráficos: la capa "__ocs_fmt_0__" ya existe. + .layer-not-created = Atributos gráficos: no se pudo crear la capa. + .layer-created = Se creó la capa "__ocs_fmt_0__" con la configuración activa de atributos gráficos. + .gradient-fill-locked = Relleno degradado: el relleno está en una capa bloqueada. + .select-closed-objects = Seleccione primero uno o varios objetos cerrados. + .locked-objects-skipped = Atributos gráficos: no se modificaron __ocs_fmt_0__ objeto(s) en una capa bloqueada. + .no-hatch-pattern = Atributos gráficos: no hay ningún patrón de sombreado disponible. + .associated-fill-locked = Atributos gráficos: un relleno asociado está en una capa bloqueada. + .one-unsupported = Atributos gráficos: no se modificó 1 objeto no admitido. + .unsupported-skipped = Atributos gráficos: no se modificaron __ocs_fmt_0__ objetos no admitidos. + .fill-transparency = Transparencia del relleno + .line-linetype = Tipo de línea + .line-transparency = Transparencia de línea + .cylindrical-short = Cil. + .spherical-short = Esfér. + .hemispherical-short = Semiesf. + .invert-gradient = Invertir degradado + .tone = Tono + .reset-angle = Restablecer ángulo + .one-color = Un color + .two-colors = Dos colores diff --git a/locales/fi-FI/opencadstudio.ftl b/locales/fi-FI/opencadstudio.ftl index 917ad12ac..2cbd7647e 100644 --- a/locales/fi-FI/opencadstudio.ftl +++ b/locales/fi-FI/opencadstudio.ftl @@ -5612,3 +5612,38 @@ style-manager = .center-of-text-overline = Tekstin keskikohta yliviivauksella .block-extents = Estä laajuudet .base-point = Peruspiste + +graphic-attributes = + .title = Grafiikkamääritteet + .set-all-bylayer = Aseta kaikki määritteet arvoon ByLayer + .set-all-byblock = Aseta kaikki määritteet arvoon ByBlock + .remove-bylayer-byblock = Poista ByLayer / ByBlock + .create-layer-active-settings = Luo taso aktiivisilla asetuksilla + .fills-on-current-layer = Luo täytöt nykyiselle tasolle + .edit-hatch = Muokkaa viivoitusta + .edit-gradient = Muokkaa liukuväriä + .close-open-object = Valittu objekti on avoin. Suljetaanko se ennen täytön luomista? [Yes / No] + .close-open-objects = __ocs_fmt_0__ valittua objektia on avoimia. Suljetaanko ne ennen täytön luomista? [Yes / No] + .enter-new-layer-name = Anna uuden tason nimi: + .invalid-layer-name = Grafiikkamääritteet: anna kelvollinen tason nimi ilman merkkejä <>/\":;?*|,=`. + .layer-exists = Grafiikkamääritteet: taso "__ocs_fmt_0__" on jo olemassa. + .layer-not-created = Grafiikkamääritteet: tasoa ei voitu luoda. + .layer-created = Taso "__ocs_fmt_0__" luotiin aktiivisilla grafiikkamääritteillä. + .gradient-fill-locked = Liukuväritäyttö: täyttö on lukitulla tasolla. + .select-closed-objects = Valitse ensin yksi tai useampi suljettu objekti. + .locked-objects-skipped = Grafiikkamääritteet: __ocs_fmt_0__ lukitulla tasolla olevaa objektia jätettiin muuttamatta. + .no-hatch-pattern = Grafiikkamääritteet: viivoituskuviota ei ole saatavilla. + .associated-fill-locked = Grafiikkamääritteet: liitetty täyttö on lukitulla tasolla. + .one-unsupported = Grafiikkamääritteet: 1 tukematonta objektia ei muutettu. + .unsupported-skipped = Grafiikkamääritteet: __ocs_fmt_0__ tukematonta objektia jätettiin muuttamatta. + .fill-transparency = Täytön läpinäkyvyys + .line-linetype = Viivojen viivatyyppi + .line-transparency = Viivojen läpinäkyvyys + .cylindrical-short = Lieriö + .spherical-short = Pallo + .hemispherical-short = Puolip. + .invert-gradient = Käännä liukuväri + .tone = Sävy + .reset-angle = Palauta kulma + .one-color = Yksi väri + .two-colors = Kaksi väriä diff --git a/locales/fr-FR/opencadstudio.ftl b/locales/fr-FR/opencadstudio.ftl index cb1d177e9..2d0f667ca 100644 --- a/locales/fr-FR/opencadstudio.ftl +++ b/locales/fr-FR/opencadstudio.ftl @@ -5614,3 +5614,38 @@ style-manager = .center-of-text-overline = Centre du texte avec surlignement .block-extents = Limites du bloc .base-point = Point de base + +graphic-attributes = + .title = Attributs graphiques + .set-all-bylayer = Définir tous les attributs sur ByLayer + .set-all-byblock = Définir tous les attributs sur ByBlock + .remove-bylayer-byblock = Supprimer ByLayer / ByBlock + .create-layer-active-settings = Créer un calque avec les paramètres actifs + .fills-on-current-layer = Créer les remplissages sur le calque courant + .edit-hatch = Modifier la hachure + .edit-gradient = Modifier le dégradé + .close-open-object = L'objet sélectionné est ouvert. Le fermer avant de créer le remplissage ? [Yes / No] + .close-open-objects = __ocs_fmt_0__ objets sélectionnés sont ouverts. Les fermer avant de créer le remplissage ? [Yes / No] + .enter-new-layer-name = Entrez un nom pour le nouveau calque : + .invalid-layer-name = Attributs graphiques : entrez un nom de calque valide sans <>/\":;?*|,=`. + .layer-exists = Attributs graphiques : le calque "__ocs_fmt_0__" existe déjà. + .layer-not-created = Attributs graphiques : impossible de créer le calque. + .layer-created = Calque "__ocs_fmt_0__" créé avec les attributs graphiques actifs. + .gradient-fill-locked = Remplissage dégradé : le remplissage est sur un calque verrouillé. + .select-closed-objects = Sélectionnez d'abord un ou plusieurs objets fermés. + .locked-objects-skipped = Attributs graphiques : __ocs_fmt_0__ objet(s) sur un calque verrouillé n'ont pas été modifiés. + .no-hatch-pattern = Attributs graphiques : aucun motif de hachure n'est disponible. + .associated-fill-locked = Attributs graphiques : un remplissage associé est sur un calque verrouillé. + .one-unsupported = Attributs graphiques : 1 objet non pris en charge n'a pas été modifié. + .unsupported-skipped = Attributs graphiques : __ocs_fmt_0__ objets non pris en charge n'ont pas été modifiés. + .fill-transparency = Transparence du remplissage + .line-linetype = Type de ligne + .line-transparency = Transparence des lignes + .cylindrical-short = Cyl. + .spherical-short = Sphér. + .hemispherical-short = Hémi. + .invert-gradient = Inverser le dégradé + .tone = Ton + .reset-angle = Réinitialiser l'angle + .one-color = Une couleur + .two-colors = Deux couleurs diff --git a/locales/hi-IN/opencadstudio.ftl b/locales/hi-IN/opencadstudio.ftl index 03319c8b6..27fa7766e 100644 --- a/locales/hi-IN/opencadstudio.ftl +++ b/locales/hi-IN/opencadstudio.ftl @@ -5603,3 +5603,38 @@ style-manager = .center-of-text-overline = ऊपरी रेखा सहित टेक्स्ट का केंद्र .block-extents = ब्लॉक परिमिति .base-point = आधार बिंदु + +graphic-attributes = + .title = ग्राफ़िक गुण + .set-all-bylayer = सभी गुण ByLayer पर सेट करें + .set-all-byblock = सभी गुण ByBlock पर सेट करें + .remove-bylayer-byblock = ByLayer / ByBlock हटाएँ + .create-layer-active-settings = सक्रिय सेटिंग्स के साथ लेयर बनाएँ + .fills-on-current-layer = भराव वर्तमान लेयर पर बनाएँ + .edit-hatch = हैच संपादित करें + .edit-gradient = ग्रेडिएंट संपादित करें + .close-open-object = चयनित ऑब्जेक्ट खुला है। भराव बनाने से पहले इसे बंद करें? [Yes / No] + .close-open-objects = __ocs_fmt_0__ चयनित ऑब्जेक्ट खुले हैं। भराव बनाने से पहले इन्हें बंद करें? [Yes / No] + .enter-new-layer-name = नई लेयर का नाम दर्ज करें: + .invalid-layer-name = ग्राफ़िक गुण: <>/\":;?*|,=` के बिना मान्य लेयर नाम दर्ज करें। + .layer-exists = ग्राफ़िक गुण: लेयर "__ocs_fmt_0__" पहले से मौजूद है। + .layer-not-created = ग्राफ़िक गुण: लेयर नहीं बनाई जा सकी। + .layer-created = सक्रिय ग्राफ़िक गुण सेटिंग्स के साथ लेयर "__ocs_fmt_0__" बनाई गई। + .gradient-fill-locked = ग्रेडिएंट भराव: भराव लॉक की गई लेयर पर है। + .select-closed-objects = पहले एक या अधिक बंद ऑब्जेक्ट चुनें। + .locked-objects-skipped = ग्राफ़िक गुण: लॉक की गई लेयर पर __ocs_fmt_0__ ऑब्जेक्ट नहीं बदले गए। + .no-hatch-pattern = ग्राफ़िक गुण: कोई हैच पैटर्न उपलब्ध नहीं है। + .associated-fill-locked = ग्राफ़िक गुण: एक संबद्ध भराव लॉक की गई लेयर पर है। + .one-unsupported = ग्राफ़िक गुण: 1 असमर्थित ऑब्जेक्ट नहीं बदला गया। + .unsupported-skipped = ग्राफ़िक गुण: __ocs_fmt_0__ असमर्थित ऑब्जेक्ट नहीं बदले गए। + .fill-transparency = भराव पारदर्शिता + .line-linetype = रेखा का लाइनटाइप + .line-transparency = रेखा पारदर्शिता + .cylindrical-short = बेलन. + .spherical-short = गोल. + .hemispherical-short = अर्धगोल. + .invert-gradient = ग्रेडिएंट उलटें + .tone = टोन + .reset-angle = कोण रीसेट करें + .one-color = एक रंग + .two-colors = दो रंग diff --git a/locales/hu-HU/opencadstudio.ftl b/locales/hu-HU/opencadstudio.ftl index 534a1264c..ce71c489d 100644 --- a/locales/hu-HU/opencadstudio.ftl +++ b/locales/hu-HU/opencadstudio.ftl @@ -5614,3 +5614,38 @@ style-manager = .center-of-text-overline = Szöveg közepe áthúzással .block-extents = Kiterjedések blokkolása .base-point = Alappont + +graphic-attributes = + .title = Grafikus jellemzők + .set-all-bylayer = Minden jellemző ByLayer értékre + .set-all-byblock = Minden jellemző ByBlock értékre + .remove-bylayer-byblock = ByLayer / ByBlock eltávolítása + .create-layer-active-settings = Fólia létrehozása az aktív beállításokkal + .fills-on-current-layer = Kitöltések létrehozása az aktuális fólián + .edit-hatch = Sraffozás szerkesztése + .edit-gradient = Színátmenet szerkesztése + .close-open-object = A kijelölt objektum nyitott. Bezárja a kitöltés létrehozása előtt? [Yes / No] + .close-open-objects = __ocs_fmt_0__ kijelölt objektum nyitott. Bezárja őket a kitöltés létrehozása előtt? [Yes / No] + .enter-new-layer-name = Adja meg az új fólia nevét: + .invalid-layer-name = Grafikus jellemzők: adjon meg érvényes fólianevet <>/\":;?*|,=` nélkül. + .layer-exists = Grafikus jellemzők: a(z) "__ocs_fmt_0__" fólia már létezik. + .layer-not-created = Grafikus jellemzők: a fóliát nem sikerült létrehozni. + .layer-created = A(z) "__ocs_fmt_0__" fólia létrejött az aktív grafikus jellemzőkkel. + .gradient-fill-locked = Színátmenetes kitöltés: a kitöltés zárolt fólián van. + .select-closed-objects = Először jelöljön ki egy vagy több zárt objektumot. + .locked-objects-skipped = Grafikus jellemzők: __ocs_fmt_0__ zárolt fólián lévő objektum nem változott. + .no-hatch-pattern = Grafikus jellemzők: nincs elérhető sraffozási minta. + .associated-fill-locked = Grafikus jellemzők: egy társított kitöltés zárolt fólián van. + .one-unsupported = Grafikus jellemzők: 1 nem támogatott objektum nem változott. + .unsupported-skipped = Grafikus jellemzők: __ocs_fmt_0__ nem támogatott objektum nem változott. + .fill-transparency = Kitöltés átlátszósága + .line-linetype = Vonaltípus + .line-transparency = Vonalak átlátszósága + .cylindrical-short = Henger + .spherical-short = Gömb + .hemispherical-short = Félgömb + .invert-gradient = Színátmenet megfordítása + .tone = Tónus + .reset-angle = Szög visszaállítása + .one-color = Egy szín + .two-colors = Két szín diff --git a/locales/it-IT/opencadstudio.ftl b/locales/it-IT/opencadstudio.ftl index 325895258..bac57efe9 100644 --- a/locales/it-IT/opencadstudio.ftl +++ b/locales/it-IT/opencadstudio.ftl @@ -5614,3 +5614,38 @@ style-manager = .center-of-text-overline = Centro del testo con sopralineato .block-extents = Blocca estensioni .base-point = Punto base + +graphic-attributes = + .title = Attributi grafici + .set-all-bylayer = Imposta tutti gli attributi su ByLayer + .set-all-byblock = Imposta tutti gli attributi su ByBlock + .remove-bylayer-byblock = Rimuovi ByLayer / ByBlock + .create-layer-active-settings = Crea layer con le impostazioni attive + .fills-on-current-layer = Crea i riempimenti sul layer corrente + .edit-hatch = Modifica tratteggio + .edit-gradient = Modifica sfumatura + .close-open-object = L'oggetto selezionato è aperto. Chiuderlo prima di creare il riempimento? [Yes / No] + .close-open-objects = __ocs_fmt_0__ oggetti selezionati sono aperti. Chiuderli prima di creare il riempimento? [Yes / No] + .enter-new-layer-name = Immettere un nome per il nuovo layer: + .invalid-layer-name = Attributi grafici: immettere un nome di layer valido senza <>/\":;?*|,=`. + .layer-exists = Attributi grafici: il layer "__ocs_fmt_0__" esiste già. + .layer-not-created = Attributi grafici: impossibile creare il layer. + .layer-created = Layer "__ocs_fmt_0__" creato con le impostazioni attive degli attributi grafici. + .gradient-fill-locked = Riempimento sfumato: il riempimento è su un layer bloccato. + .select-closed-objects = Selezionare prima uno o più oggetti chiusi. + .locked-objects-skipped = Attributi grafici: __ocs_fmt_0__ oggetto/i su un layer bloccato non sono stati modificati. + .no-hatch-pattern = Attributi grafici: nessun modello di tratteggio disponibile. + .associated-fill-locked = Attributi grafici: un riempimento associato è su un layer bloccato. + .one-unsupported = Attributi grafici: 1 oggetto non supportato non è stato modificato. + .unsupported-skipped = Attributi grafici: __ocs_fmt_0__ oggetti non supportati non sono stati modificati. + .fill-transparency = Trasparenza riempimento + .line-linetype = Tipo di linea + .line-transparency = Trasparenza linee + .cylindrical-short = Cil. + .spherical-short = Sfer. + .hemispherical-short = Emisf. + .invert-gradient = Inverti sfumatura + .tone = Tono + .reset-angle = Reimposta angolo + .one-color = Un colore + .two-colors = Due colori diff --git a/locales/ja-JP/opencadstudio.ftl b/locales/ja-JP/opencadstudio.ftl index 03cdaf6dc..fec230084 100644 --- a/locales/ja-JP/opencadstudio.ftl +++ b/locales/ja-JP/opencadstudio.ftl @@ -5603,3 +5603,38 @@ style-manager = .center-of-text-overline = 上線付きテキストの中心 .block-extents = ブロック範囲 .base-point = 基点 + +graphic-attributes = + .title = グラフィック属性 + .set-all-bylayer = すべての属性を ByLayer に設定 + .set-all-byblock = すべての属性を ByBlock に設定 + .remove-bylayer-byblock = ByLayer / ByBlock を解除 + .create-layer-active-settings = 現在の設定で画層を作成 + .fills-on-current-layer = 塗り潰しを現在の画層に作成 + .edit-hatch = ハッチングを編集 + .edit-gradient = グラデーションを編集 + .close-open-object = 選択したオブジェクトは開いています。塗り潰しを作成する前に閉じますか? [Yes / No] + .close-open-objects = 選択した __ocs_fmt_0__ 個のオブジェクトは開いています。塗り潰しを作成する前に閉じますか? [Yes / No] + .enter-new-layer-name = 新しい画層の名前を入力: + .invalid-layer-name = グラフィック属性: <>/\":;?*|,=` を含まない有効な画層名を入力してください。 + .layer-exists = グラフィック属性: 画層 "__ocs_fmt_0__" は既に存在します。 + .layer-not-created = グラフィック属性: 画層を作成できませんでした。 + .layer-created = 現在のグラフィック属性の設定で画層 "__ocs_fmt_0__" を作成しました。 + .gradient-fill-locked = グラデーション塗り潰し: 塗り潰しはロックされた画層にあります。 + .select-closed-objects = 先に 1 つ以上の閉じたオブジェクトを選択してください。 + .locked-objects-skipped = グラフィック属性: ロックされた画層上の __ocs_fmt_0__ 個のオブジェクトは変更されませんでした。 + .no-hatch-pattern = グラフィック属性: 使用できるハッチング パターンがありません。 + .associated-fill-locked = グラフィック属性: 関連付けられた塗り潰しがロックされた画層にあります。 + .one-unsupported = グラフィック属性: サポートされていないオブジェクト 1 個は変更されませんでした。 + .unsupported-skipped = グラフィック属性: サポートされていないオブジェクト __ocs_fmt_0__ 個は変更されませんでした。 + .fill-transparency = 塗り潰しの透過性 + .line-linetype = 線の線種 + .line-transparency = 線の透過性 + .cylindrical-short = 円柱 + .spherical-short = 球 + .hemispherical-short = 半球 + .invert-gradient = グラデーションを反転 + .tone = 濃淡 + .reset-angle = 角度をリセット + .one-color = 1 色 + .two-colors = 2 色 diff --git a/locales/ko-KR/opencadstudio.ftl b/locales/ko-KR/opencadstudio.ftl index d01f1d748..c1fcbc464 100644 --- a/locales/ko-KR/opencadstudio.ftl +++ b/locales/ko-KR/opencadstudio.ftl @@ -5614,3 +5614,38 @@ style-manager = .center-of-text-overline = 윗줄이 있는 텍스트 중앙 .block-extents = 블록 범위 .base-point = 기준점 + +graphic-attributes = + .title = 그래픽 속성 + .set-all-bylayer = 모든 속성을 ByLayer로 설정 + .set-all-byblock = 모든 속성을 ByBlock으로 설정 + .remove-bylayer-byblock = ByLayer / ByBlock 제거 + .create-layer-active-settings = 현재 설정으로 도면층 작성 + .fills-on-current-layer = 현재 도면층에 채우기 작성 + .edit-hatch = 해치 편집 + .edit-gradient = 그라데이션 편집 + .close-open-object = 선택한 객체가 열려 있습니다. 채우기를 작성하기 전에 닫겠습니까? [Yes / No] + .close-open-objects = 선택한 객체 __ocs_fmt_0__개가 열려 있습니다. 채우기를 작성하기 전에 닫겠습니까? [Yes / No] + .enter-new-layer-name = 새 도면층 이름 입력: + .invalid-layer-name = 그래픽 속성: <>/\":;?*|,=`이(가) 없는 올바른 도면층 이름을 입력하십시오. + .layer-exists = 그래픽 속성: 도면층 "__ocs_fmt_0__"이(가) 이미 있습니다. + .layer-not-created = 그래픽 속성: 도면층을 작성할 수 없습니다. + .layer-created = 현재 그래픽 속성 설정으로 도면층 "__ocs_fmt_0__"을(를) 작성했습니다. + .gradient-fill-locked = 그라데이션 채우기: 채우기가 잠긴 도면층에 있습니다. + .select-closed-objects = 먼저 닫힌 객체를 하나 이상 선택하십시오. + .locked-objects-skipped = 그래픽 속성: 잠긴 도면층의 객체 __ocs_fmt_0__개가 변경되지 않았습니다. + .no-hatch-pattern = 그래픽 속성: 사용 가능한 해치 패턴이 없습니다. + .associated-fill-locked = 그래픽 속성: 연관된 채우기가 잠긴 도면층에 있습니다. + .one-unsupported = 그래픽 속성: 지원되지 않는 객체 1개가 변경되지 않았습니다. + .unsupported-skipped = 그래픽 속성: 지원되지 않는 객체 __ocs_fmt_0__개가 변경되지 않았습니다. + .fill-transparency = 채우기 투명도 + .line-linetype = 선의 선종류 + .line-transparency = 선 투명도 + .cylindrical-short = 원통 + .spherical-short = 구 + .hemispherical-short = 반구 + .invert-gradient = 그라데이션 반전 + .tone = 색조 + .reset-angle = 각도 재설정 + .one-color = 단색 + .two-colors = 두 색 diff --git a/locales/nl-NL/opencadstudio.ftl b/locales/nl-NL/opencadstudio.ftl index bce553628..2c9de8d1a 100644 --- a/locales/nl-NL/opencadstudio.ftl +++ b/locales/nl-NL/opencadstudio.ftl @@ -5613,3 +5613,38 @@ style-manager = .center-of-text-overline = Tekstmiddelpunt met bovenstreep .block-extents = Symboolgrenzen .base-point = Basispunt + +graphic-attributes = + .title = Grafische attributen + .set-all-bylayer = Alle attributen op ByLayer zetten + .set-all-byblock = Alle attributen op ByBlock zetten + .remove-bylayer-byblock = ByLayer / ByBlock verwijderen + .create-layer-active-settings = Laag maken met actieve instellingen + .fills-on-current-layer = Vullingen op de huidige laag maken + .edit-hatch = Arcering bewerken + .edit-gradient = Kleurverloop bewerken + .close-open-object = Het geselecteerde object is open. Sluiten voordat de vulling wordt gemaakt? [Yes / No] + .close-open-objects = __ocs_fmt_0__ geselecteerde objecten zijn open. Sluiten voordat de vulling wordt gemaakt? [Yes / No] + .enter-new-layer-name = Voer een naam in voor de nieuwe laag: + .invalid-layer-name = Grafische attributen: voer een geldige laagnaam in zonder <>/\":;?*|,=`. + .layer-exists = Grafische attributen: laag "__ocs_fmt_0__" bestaat al. + .layer-not-created = Grafische attributen: de laag kon niet worden gemaakt. + .layer-created = Laag "__ocs_fmt_0__" gemaakt met de actieve instellingen van Grafische attributen. + .gradient-fill-locked = Verloopvulling: de vulling staat op een vergrendelde laag. + .select-closed-objects = Selecteer eerst een of meer gesloten objecten. + .locked-objects-skipped = Grafische attributen: __ocs_fmt_0__ object(en) op een vergrendelde laag zijn niet gewijzigd. + .no-hatch-pattern = Grafische attributen: er is geen arceerpatroon beschikbaar. + .associated-fill-locked = Grafische attributen: een gekoppelde vulling staat op een vergrendelde laag. + .one-unsupported = Grafische attributen: 1 niet-ondersteund object is niet gewijzigd. + .unsupported-skipped = Grafische attributen: __ocs_fmt_0__ niet-ondersteunde objecten zijn niet gewijzigd. + .fill-transparency = Transparantie vulling + .line-linetype = Lijntype lijnen + .line-transparency = Transparantie lijnen + .cylindrical-short = Cil. + .spherical-short = Bol + .hemispherical-short = Halfbol + .invert-gradient = Kleurverloop omkeren + .tone = Toon + .reset-angle = Hoek herstellen + .one-color = Eén kleur + .two-colors = Twee kleuren diff --git a/locales/pl-PL/opencadstudio.ftl b/locales/pl-PL/opencadstudio.ftl index 9ac4ad83b..70af7f1fa 100644 --- a/locales/pl-PL/opencadstudio.ftl +++ b/locales/pl-PL/opencadstudio.ftl @@ -5614,3 +5614,38 @@ style-manager = .center-of-text-overline = Środek tekstu z podkreśleniem .block-extents = Zasięg bloku .base-point = Punkt bazowy + +graphic-attributes = + .title = Atrybuty graficzne + .set-all-bylayer = Ustaw wszystkie atrybuty na ByLayer + .set-all-byblock = Ustaw wszystkie atrybuty na ByBlock + .remove-bylayer-byblock = Usuń ByLayer / ByBlock + .create-layer-active-settings = Utwórz warstwę z aktywnymi ustawieniami + .fills-on-current-layer = Twórz wypełnienia na bieżącej warstwie + .edit-hatch = Edytuj kreskowanie + .edit-gradient = Edytuj gradient + .close-open-object = Wybrany obiekt jest otwarty. Zamknąć go przed utworzeniem wypełnienia? [Yes / No] + .close-open-objects = Wybrane obiekty są otwarte (__ocs_fmt_0__). Zamknąć je przed utworzeniem wypełnienia? [Yes / No] + .enter-new-layer-name = Podaj nazwę nowej warstwy: + .invalid-layer-name = Atrybuty graficzne: podaj prawidłową nazwę warstwy bez <>/\":;?*|,=`. + .layer-exists = Atrybuty graficzne: warstwa "__ocs_fmt_0__" już istnieje. + .layer-not-created = Atrybuty graficzne: nie można utworzyć warstwy. + .layer-created = Utworzono warstwę "__ocs_fmt_0__" z aktywnymi atrybutami graficznymi. + .gradient-fill-locked = Wypełnienie gradientowe: wypełnienie jest na zablokowanej warstwie. + .select-closed-objects = Najpierw wybierz jeden lub więcej zamkniętych obiektów. + .locked-objects-skipped = Atrybuty graficzne: obiekty na zablokowanej warstwie (__ocs_fmt_0__) nie zostały zmienione. + .no-hatch-pattern = Atrybuty graficzne: brak dostępnego wzoru kreskowania. + .associated-fill-locked = Atrybuty graficzne: skojarzone wypełnienie jest na zablokowanej warstwie. + .one-unsupported = Atrybuty graficzne: 1 nieobsługiwany obiekt nie został zmieniony. + .unsupported-skipped = Atrybuty graficzne: nieobsługiwane obiekty (__ocs_fmt_0__) nie zostały zmienione. + .fill-transparency = Przezroczystość wypełnienia + .line-linetype = Rodzaj linii + .line-transparency = Przezroczystość linii + .cylindrical-short = Walc. + .spherical-short = Sfer. + .hemispherical-short = Półsf. + .invert-gradient = Odwróć gradient + .tone = Ton + .reset-angle = Resetuj kąt + .one-color = Jeden kolor + .two-colors = Dwa kolory diff --git a/locales/pt-BR/opencadstudio.ftl b/locales/pt-BR/opencadstudio.ftl index 385759cd2..c007c8458 100644 --- a/locales/pt-BR/opencadstudio.ftl +++ b/locales/pt-BR/opencadstudio.ftl @@ -5615,3 +5615,38 @@ style-manager = .center-of-text-overline = Centro do texto com sobrelinha .block-extents = Extensões do bloco .base-point = Ponto base + +graphic-attributes = + .title = Atributos gráficos + .set-all-bylayer = Definir todos os atributos como ByLayer + .set-all-byblock = Definir todos os atributos como ByBlock + .remove-bylayer-byblock = Remover ByLayer / ByBlock + .create-layer-active-settings = Criar camada com as configurações ativas + .fills-on-current-layer = Criar preenchimentos na camada atual + .edit-hatch = Editar hachura + .edit-gradient = Editar gradiente + .close-open-object = O objeto selecionado está aberto. Fechá-lo antes de criar o preenchimento? [Yes / No] + .close-open-objects = __ocs_fmt_0__ objetos selecionados estão abertos. Fechá-los antes de criar o preenchimento? [Yes / No] + .enter-new-layer-name = Digite um nome para a nova camada: + .invalid-layer-name = Atributos gráficos: digite um nome de camada válido sem <>/\":;?*|,=`. + .layer-exists = Atributos gráficos: a camada "__ocs_fmt_0__" já existe. + .layer-not-created = Atributos gráficos: não foi possível criar a camada. + .layer-created = Camada "__ocs_fmt_0__" criada com as configurações ativas de atributos gráficos. + .gradient-fill-locked = Preenchimento gradiente: o preenchimento está em uma camada bloqueada. + .select-closed-objects = Selecione primeiro um ou mais objetos fechados. + .locked-objects-skipped = Atributos gráficos: __ocs_fmt_0__ objeto(s) em uma camada bloqueada não foram alterados. + .no-hatch-pattern = Atributos gráficos: nenhum padrão de hachura disponível. + .associated-fill-locked = Atributos gráficos: um preenchimento associado está em uma camada bloqueada. + .one-unsupported = Atributos gráficos: 1 objeto não suportado não foi alterado. + .unsupported-skipped = Atributos gráficos: __ocs_fmt_0__ objetos não suportados não foram alterados. + .fill-transparency = Transparência do preenchimento + .line-linetype = Tipo de linha + .line-transparency = Transparência da linha + .cylindrical-short = Cil. + .spherical-short = Esfér. + .hemispherical-short = Hemisf. + .invert-gradient = Inverter gradiente + .tone = Tom + .reset-angle = Redefinir ângulo + .one-color = Uma cor + .two-colors = Duas cores diff --git a/locales/ru-RU/opencadstudio.ftl b/locales/ru-RU/opencadstudio.ftl index 05ec1405c..3b4d84356 100644 --- a/locales/ru-RU/opencadstudio.ftl +++ b/locales/ru-RU/opencadstudio.ftl @@ -5616,3 +5616,38 @@ style-manager = .center-of-text-overline = Центр текста с надчёркиванием .block-extents = Габариты блока .base-point = Базовая точка + +graphic-attributes = + .title = Графические атрибуты + .set-all-bylayer = Задать всем атрибутам ByLayer + .set-all-byblock = Задать всем атрибутам ByBlock + .remove-bylayer-byblock = Убрать ByLayer / ByBlock + .create-layer-active-settings = Создать слой с текущими настройками + .fills-on-current-layer = Создавать заливки на текущем слое + .edit-hatch = Редактировать штриховку + .edit-gradient = Редактировать градиент + .close-open-object = Выбранный объект разомкнут. Замкнуть его перед созданием заливки? [Yes / No] + .close-open-objects = Выбранные объекты разомкнуты (__ocs_fmt_0__). Замкнуть их перед созданием заливки? [Yes / No] + .enter-new-layer-name = Введите имя нового слоя: + .invalid-layer-name = Графические атрибуты: введите допустимое имя слоя без <>/\":;?*|,=`. + .layer-exists = Графические атрибуты: слой "__ocs_fmt_0__" уже существует. + .layer-not-created = Графические атрибуты: не удалось создать слой. + .layer-created = Создан слой "__ocs_fmt_0__" с текущими графическими атрибутами. + .gradient-fill-locked = Градиентная заливка: заливка находится на заблокированном слое. + .select-closed-objects = Сначала выберите один или несколько замкнутых объектов. + .locked-objects-skipped = Графические атрибуты: объекты на заблокированном слое (__ocs_fmt_0__) не изменены. + .no-hatch-pattern = Графические атрибуты: нет доступного образца штриховки. + .associated-fill-locked = Графические атрибуты: связанная заливка находится на заблокированном слое. + .one-unsupported = Графические атрибуты: 1 неподдерживаемый объект не изменён. + .unsupported-skipped = Графические атрибуты: неподдерживаемые объекты (__ocs_fmt_0__) не изменены. + .fill-transparency = Прозрачность заливки + .line-linetype = Тип линий + .line-transparency = Прозрачность линий + .cylindrical-short = Цил. + .spherical-short = Сфер. + .hemispherical-short = Полусф. + .invert-gradient = Инвертировать градиент + .tone = Тон + .reset-angle = Сбросить угол + .one-color = Один цвет + .two-colors = Два цвета diff --git a/locales/tr-TR/opencadstudio.ftl b/locales/tr-TR/opencadstudio.ftl index 22abcc5ce..f94360dbd 100644 --- a/locales/tr-TR/opencadstudio.ftl +++ b/locales/tr-TR/opencadstudio.ftl @@ -5538,3 +5538,38 @@ style-manager = .center-of-text-overline = Üst çizgili metin merkezi .block-extents = Blok sınırları .base-point = Taban noktası + +graphic-attributes = + .title = Grafik öznitelikleri + .set-all-bylayer = Tüm öznitelikleri ByLayer yap + .set-all-byblock = Tüm öznitelikleri ByBlock yap + .remove-bylayer-byblock = ByLayer / ByBlock kaldır + .create-layer-active-settings = Etkin ayarlarla katman oluştur + .fills-on-current-layer = Dolguları geçerli katmanda oluştur + .edit-hatch = Taramayı düzenle + .edit-gradient = Gradyanı düzenle + .close-open-object = Seçili nesne açık. Dolgu oluşturmadan önce kapatılsın mı? [Yes / No] + .close-open-objects = __ocs_fmt_0__ seçili nesne açık. Dolgu oluşturmadan önce kapatılsın mı? [Yes / No] + .enter-new-layer-name = Yeni katman için bir ad girin: + .invalid-layer-name = Grafik öznitelikleri: <>/\":;?*|,=` içermeyen geçerli bir katman adı girin. + .layer-exists = Grafik öznitelikleri: "__ocs_fmt_0__" katmanı zaten var. + .layer-not-created = Grafik öznitelikleri: katman oluşturulamadı. + .layer-created = "__ocs_fmt_0__" katmanı etkin grafik öznitelikleriyle oluşturuldu. + .gradient-fill-locked = Gradyan dolgu: dolgu kilitli bir katmanda. + .select-closed-objects = Önce bir veya daha fazla kapalı nesne seçin. + .locked-objects-skipped = Grafik öznitelikleri: kilitli katmandaki __ocs_fmt_0__ nesne değiştirilmedi. + .no-hatch-pattern = Grafik öznitelikleri: kullanılabilir tarama deseni yok. + .associated-fill-locked = Grafik öznitelikleri: ilişkili bir dolgu kilitli katmanda. + .one-unsupported = Grafik öznitelikleri: desteklenmeyen 1 nesne değiştirilmedi. + .unsupported-skipped = Grafik öznitelikleri: desteklenmeyen __ocs_fmt_0__ nesne değiştirilmedi. + .fill-transparency = Dolgu saydamlığı + .line-linetype = Çizgi tipi + .line-transparency = Çizgi saydamlığı + .cylindrical-short = Sil. + .spherical-short = Küre + .hemispherical-short = Yarıküre + .invert-gradient = Gradyanı ters çevir + .tone = Ton + .reset-angle = Açıyı sıfırla + .one-color = Tek renk + .two-colors = İki renk diff --git a/locales/zh-CN/opencadstudio.ftl b/locales/zh-CN/opencadstudio.ftl index a1fb404ee..bf728d3a4 100644 --- a/locales/zh-CN/opencadstudio.ftl +++ b/locales/zh-CN/opencadstudio.ftl @@ -5598,3 +5598,38 @@ style-manager = .center-of-text-overline = 带上划线的文字中心 .block-extents = 块范围 .base-point = 基点 + +graphic-attributes = + .title = 图形特性 + .set-all-bylayer = 将所有特性设为 ByLayer + .set-all-byblock = 将所有特性设为 ByBlock + .remove-bylayer-byblock = 移除 ByLayer / ByBlock + .create-layer-active-settings = 用当前设置创建图层 + .fills-on-current-layer = 在当前图层上创建填充 + .edit-hatch = 编辑填充图案 + .edit-gradient = 编辑渐变色 + .close-open-object = 选定对象未闭合。创建填充前是否将其闭合? [Yes / No] + .close-open-objects = __ocs_fmt_0__ 个选定对象未闭合。创建填充前是否将其闭合? [Yes / No] + .enter-new-layer-name = 输入新图层的名称: + .invalid-layer-name = 图形特性: 请输入不含 <>/\":;?*|,=` 的有效图层名称。 + .layer-exists = 图形特性: 图层 "__ocs_fmt_0__" 已存在。 + .layer-not-created = 图形特性: 无法创建图层。 + .layer-created = 已用当前图形特性设置创建图层 "__ocs_fmt_0__"。 + .gradient-fill-locked = 渐变填充: 填充位于锁定的图层上。 + .select-closed-objects = 请先选择一个或多个闭合对象。 + .locked-objects-skipped = 图形特性: 锁定图层上的 __ocs_fmt_0__ 个对象未更改。 + .no-hatch-pattern = 图形特性: 没有可用的填充图案。 + .associated-fill-locked = 图形特性: 关联的填充位于锁定的图层上。 + .one-unsupported = 图形特性: 1 个不支持的对象未更改。 + .unsupported-skipped = 图形特性: __ocs_fmt_0__ 个不支持的对象未更改。 + .fill-transparency = 填充透明度 + .line-linetype = 线的线型 + .line-transparency = 线的透明度 + .cylindrical-short = 圆柱 + .spherical-short = 球形 + .hemispherical-short = 半球 + .invert-gradient = 反转渐变 + .tone = 明暗 + .reset-angle = 重置角度 + .one-color = 单色 + .two-colors = 双色 diff --git a/locales/zh-TW/opencadstudio.ftl b/locales/zh-TW/opencadstudio.ftl index ad0d17c01..e8953c1a2 100644 --- a/locales/zh-TW/opencadstudio.ftl +++ b/locales/zh-TW/opencadstudio.ftl @@ -5610,3 +5610,38 @@ style-manager = .center-of-text-overline = 帶上划線的文字中心 .block-extents = 圖塊範圍 .base-point = 基點 + +graphic-attributes = + .title = 圖形特性 + .set-all-bylayer = 將所有特性設為 ByLayer + .set-all-byblock = 將所有特性設為 ByBlock + .remove-bylayer-byblock = 移除 ByLayer / ByBlock + .create-layer-active-settings = 以目前設定建立圖層 + .fills-on-current-layer = 在目前圖層上建立填充 + .edit-hatch = 編輯填充線 + .edit-gradient = 編輯漸層 + .close-open-object = 選取的物件未封閉。建立填充前是否將其封閉? [Yes / No] + .close-open-objects = __ocs_fmt_0__ 個選取的物件未封閉。建立填充前是否將其封閉? [Yes / No] + .enter-new-layer-name = 輸入新圖層的名稱: + .invalid-layer-name = 圖形特性: 請輸入不含 <>/\":;?*|,=` 的有效圖層名稱。 + .layer-exists = 圖形特性: 圖層 "__ocs_fmt_0__" 已存在。 + .layer-not-created = 圖形特性: 無法建立圖層。 + .layer-created = 已以目前圖形特性設定建立圖層 "__ocs_fmt_0__"。 + .gradient-fill-locked = 漸層填充: 填充位於鎖定的圖層上。 + .select-closed-objects = 請先選取一個或多個封閉物件。 + .locked-objects-skipped = 圖形特性: 鎖定圖層上的 __ocs_fmt_0__ 個物件未變更。 + .no-hatch-pattern = 圖形特性: 沒有可用的填充線樣式。 + .associated-fill-locked = 圖形特性: 關聯的填充位於鎖定的圖層上。 + .one-unsupported = 圖形特性: 1 個不支援的物件未變更。 + .unsupported-skipped = 圖形特性: __ocs_fmt_0__ 個不支援的物件未變更。 + .fill-transparency = 填充透明度 + .line-linetype = 線的線型 + .line-transparency = 線的透明度 + .cylindrical-short = 圓柱 + .spherical-short = 球形 + .hemispherical-short = 半球 + .invert-gradient = 反轉漸層 + .tone = 明暗 + .reset-angle = 重設角度 + .one-color = 單色 + .two-colors = 雙色 diff --git a/src/app/update/command.rs b/src/app/update/command.rs index 6b13e7fa4..43a20b304 100644 --- a/src/app/update/command.rs +++ b/src/app/update/command.rs @@ -2155,6 +2155,32 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task { Task::none() } + pub(super) fn on_ribbon_lineweight_changed(&mut self, lw: acadrust::types::LineWeight) -> Task { + let i = self.active_tab; + self.ribbon.close_dropdown(); + let handles = self.property_target_handles(i); + if handles.is_empty() { + if self.has_property_selection(i) { + return Task::none(); + } + // Persist into the tab's header (CELWEIGHT). #21. + self.tabs[i].scene.document.header.current_line_weight = lw.value(); + self.tabs[i].dirty = true; + self.ribbon.active_lineweight = lw; + } else { + // Lineweight is baked into the cached wire geometry — + // re-tessellate so the change shows immediately (issue #231 + // class). + self.apply_property_op(i, "CHPROP", &handles, |app, handle| { + if let Some(entity) = app.tabs[i].scene.document.get_entity_mut(handle) { + crate::scene::view::dispatch::apply_line_weight(entity, lw); + } + }); + self.ribbon.active_lineweight = lw; + } + Task::none() + } + pub(super) fn on_ribbon_linetype_changed(&mut self, lt: String) -> Task { let i = self.active_tab; self.ribbon.close_dropdown(); diff --git a/src/app/update/graphic_attributes.rs b/src/app/update/graphic_attributes.rs index 36dc86b5a..f41e7f147 100644 --- a/src/app/update/graphic_attributes.rs +++ b/src/app/update/graphic_attributes.rs @@ -305,7 +305,7 @@ impl OpenCADStudio { "" | "Y" | "YES" => self.on_graphic_fill_close_response(true), "N" | "NO" => self.on_graphic_fill_close_response(false), _ => { - self.command_line.push_error("Enter Yes or No."); + self.command_line.push_error(crate::t!("Enter Yes or No.").as_ref()); Task::none() } } @@ -422,7 +422,7 @@ impl OpenCADStudio { self.set_current_graphic_attributes(color, linetype.to_owned(), lineweight, transparency); return Task::none(); } - self.edit_graphic_part(Part::Both, "Graphic Attributes", |entity| { + self.edit_graphic_part(Part::Both, &crate::t!("Graphic Attributes"), |entity| { crate::scene::view::dispatch::apply_color(entity, color); crate::scene::view::dispatch::apply_common_prop(entity, "linetype", linetype); crate::scene::view::dispatch::apply_line_weight(entity, lineweight); @@ -463,7 +463,7 @@ impl OpenCADStudio { }) .collect(); let handles: Vec<_> = values.keys().copied().collect(); - self.apply_property_op(i, "Graphic Attributes", &handles, |app, handle| { + self.apply_property_op(i, crate::t!("Graphic Attributes"), &handles, |app, handle| { let (Some(values), Some(entity)) = ( values.get(&handle), app.tabs[i].scene.document.get_entity_mut(handle), @@ -483,7 +483,7 @@ impl OpenCADStudio { let name = raw_name.trim(); if !crate::scene::valid_block_name(name) { self.command_line - .push_error("Graphic Attributes: enter a valid layer name without <>/\\\":;?*|,=`."); + .push_error(crate::t!("Graphic Attributes: enter a valid layer name without <>/\\\":;?*|,=`.").as_ref()); return Task::none(); } if self.tabs[i] @@ -503,7 +503,7 @@ impl OpenCADStudio { let layer_name = name.to_owned(); let undo = self.begin_layer_undo( i, - "Create layer with active settings", + crate::t!("Create Layer with active settings"), std::slice::from_ref(&layer_name), ); let mut layer = acadrust::tables::Layer::new(name); @@ -514,7 +514,7 @@ impl OpenCADStudio { layer.transparency = values.transparency; if self.tabs[i].scene.document.layers.add(layer).is_err() { self.command_line - .push_error("Graphic Attributes: the layer could not be created."); + .push_error(crate::t!("Graphic Attributes: the layer could not be created.").as_ref()); return Task::none(); } self.tabs[i].dirty = true; @@ -614,12 +614,12 @@ impl OpenCADStudio { .any(|handle| self.tabs[i].scene.is_layer_locked(*handle)) { self.command_line - .push_error("Gradient Fill: the fill is on a locked layer."); + .push_error(crate::t!("Gradient Fill: the fill is on a locked layer.").as_ref()); self.graphic_attributes.gradient_editor = Some(state); return Task::none(); } let angle = state.angle_radians(); - let pending = self.begin_undo(i, "Edit gradient", targets.len(), true); + let pending = self.begin_undo(i, crate::t!("Edit gradient"), targets.len(), true); for handle in &targets { let Some(mut entity) = self.tabs[i].scene.document.get_entity(*handle).cloned() else { continue; @@ -731,7 +731,7 @@ impl OpenCADStudio { ); } let selected = selected.as_slice(); - let pending = self.begin_undo(i, "Graphic Attributes", selected.len(), true); + let pending = self.begin_undo(i, crate::t!("Graphic Attributes"), selected.len(), true); let mut changed = false; for handle in to_close { let Some(mut entity) = self.tabs[i].scene.document.get_entity(*handle).cloned() else { @@ -768,7 +768,7 @@ impl OpenCADStudio { } else { let Some((name, pattern)) = fill_pattern(value) else { self.command_line - .push_error("Graphic Attributes: no hatch pattern is available."); + .push_error(crate::t!("Graphic Attributes: no hatch pattern is available.").as_ref()); return false; }; let working = if self.tabs[i].editing_model_space() { @@ -867,16 +867,17 @@ impl OpenCADStudio { .any(|handle| self.tabs[i].scene.is_layer_locked(*handle)) { self.command_line - .push_error("Graphic Attributes: an associated fill is on a locked layer."); + .push_error(crate::t!("Graphic Attributes: an associated fill is on a locked layer.").as_ref()); return false; } if skipped == 1 { self.command_line - .push_info("Graphic Attributes: 1 unsupported object was not changed."); + .push_info(crate::t!("Graphic Attributes: 1 unsupported object was not changed.").as_ref()); } else if skipped > 1 { - self.command_line.push_info(&format!( - "Graphic Attributes: {skipped} unsupported objects were not changed." - )); + self.command_line.push_info( + crate::tf!("Graphic Attributes: {skipped} unsupported objects were not changed.") + .as_ref(), + ); } if associated.is_empty() && new_hatches.is_empty() && updated_hatches.is_empty() { return false; @@ -892,14 +893,14 @@ impl OpenCADStudio { } pub(super) fn on_solid_fill_color(&mut self, color: AcadColor) -> Task { - self.edit_graphic_part(Part::Fill, "Fill color", |entity| { + self.edit_graphic_part(Part::Fill, &crate::t!("Fill color"), |entity| { crate::scene::view::dispatch::apply_color(entity, color); }); Task::none() } pub(super) fn on_fill_transparency(&mut self, transparency: Transparency) -> Task { - self.edit_graphic_part(Part::Fill, "Fill transparency", |entity| { + self.edit_graphic_part(Part::Fill, &crate::t!("Fill transparency"), |entity| { entity.common_mut().transparency = transparency; }); Task::none() @@ -909,7 +910,7 @@ impl OpenCADStudio { if !self.has_selection() { return self.on_ribbon_color_changed(color); } - self.edit_graphic_part(Part::Line, "Line color", |entity| { + self.edit_graphic_part(Part::Line, &crate::t!("Line color"), |entity| { crate::scene::view::dispatch::apply_color(entity, color); }); Task::none() @@ -919,7 +920,7 @@ impl OpenCADStudio { if !self.has_selection() { return self.on_ribbon_linetype_changed(linetype); } - self.edit_graphic_part(Part::Line, "Line linetype", |entity| { + self.edit_graphic_part(Part::Line, &crate::t!("Line linetype"), |entity| { crate::scene::view::dispatch::apply_common_prop(entity, "linetype", &linetype); }); Task::none() @@ -927,9 +928,9 @@ impl OpenCADStudio { pub(super) fn on_line_lineweight(&mut self, lineweight: LineWeight) -> Task { if !self.has_selection() { - return self.update(Message::RibbonLineweightChanged(lineweight)); + return self.on_ribbon_lineweight_changed(lineweight); } - self.edit_graphic_part(Part::Line, "Line weight", |entity| { + self.edit_graphic_part(Part::Line, &crate::t!("Line weight"), |entity| { crate::scene::view::dispatch::apply_line_weight(entity, lineweight); }); Task::none() @@ -946,7 +947,7 @@ impl OpenCADStudio { self.refresh_properties(); return Task::none(); } - self.edit_graphic_part(Part::Line, "Linetype scale", |entity| { + self.edit_graphic_part(Part::Line, &crate::t!("Linetype scale"), |entity| { entity.common_mut().linetype_scale = scale; }); Task::none() @@ -965,7 +966,7 @@ impl OpenCADStudio { } return Task::none(); } - self.edit_graphic_part(Part::Line, "Line transparency", |entity| { + self.edit_graphic_part(Part::Line, &crate::t!("Line transparency"), |entity| { entity.common_mut().transparency = transparency; }); Task::none() @@ -988,113 +989,114 @@ mod tests { app } - #[test] - fn graphic_attributes_creates_one_associative_fill_per_object() { - let mut app = fresh(); - let i = app.active_tab; - let mut boundaries = Vec::new(); - // Coincident boundaries must still own independent associations. - for offset in [0.0, 0.0] { - let mut polyline = LwPolyline::new(); - for (x, y) in [(0.0, 0.0), (10.0, 0.0), (10.0, 10.0), (0.0, 10.0)] { - polyline.add_point(Vector2::new(x + offset, y)); - } - polyline.close(); - let handle = app.tabs[i] - .scene - .add_entity(EntityType::LwPolyline(polyline)); - app.tabs[i].scene.select_entity(handle, false); - boundaries.push(handle); + fn add_closed_square(app: &mut OpenCADStudio, x: f64) -> Handle { + let mut polyline = LwPolyline::new(); + for (px, py) in [(0.0, 0.0), (10.0, 0.0), (10.0, 10.0), (0.0, 10.0)] { + polyline.add_point(Vector2::new(px + x, py)); } + polyline.close(); + let i = app.active_tab; + app.tabs[i].scene.add_entity(EntityType::LwPolyline(polyline)) + } - let _ = app.on_graphic_attribute(GraphicAttribute::Solid); - let hatches: Vec<_> = app.tabs[i] + fn select(app: &mut OpenCADStudio, handles: &[Handle]) { + let i = app.active_tab; + app.tabs[i].scene.deselect_all(); + for handle in handles { + app.tabs[i].scene.select_entity(*handle, false); + } + } + + fn hatches(app: &OpenCADStudio) -> Vec<&acadrust::entities::Hatch> { + app.tabs[app.active_tab] .scene .document .entities() - .filter_map(|entity| { - let EntityType::Hatch(hatch) = entity else { - return None; - }; - Some(hatch) + .filter_map(|entity| match entity { + EntityType::Hatch(hatch) => Some(hatch), + _ => None, }) - .collect(); - assert_eq!(hatches.len(), 2); - assert!(hatches - .iter() - .all(|hatch| hatch.is_solid && hatch.is_associative)); - assert!(hatches.iter().all(|hatch| hatch + .collect() + } + + fn common(app: &OpenCADStudio, handle: Handle) -> &acadrust::entities::EntityCommon { + app.tabs[app.active_tab] + .scene + .document + .get_entity(handle) + .expect("entity") + .common() + } + + fn fill_kind(app: &OpenCADStudio, handle: Handle) -> GraphicAttribute { + palette::current(&app.tabs[app.active_tab].scene.document, &[handle]) + } + + /// A closed square with a fill of `kind`; the fill HATCH is selected. + fn filled_square(app: &mut OpenCADStudio, kind: GraphicAttribute) -> (Handle, Handle) { + let boundary = add_closed_square(app, 0.0); + select(app, &[boundary]); + let _ = app.on_graphic_attribute(kind); + let hatch = hatches(app)[0].common.handle; + select(app, &[hatch]); + (boundary, hatch) + } + + #[test] + fn coincident_boundaries_each_get_their_own_associative_fill() { + let mut app = fresh(); + let boundaries = [add_closed_square(&mut app, 0.0), add_closed_square(&mut app, 0.0)]; + select(&mut app, &boundaries); + + let _ = app.on_graphic_attribute(GraphicAttribute::Solid); + let fills = hatches(&app); + assert_eq!(fills.len(), 2); + assert!(fills.iter().all(|hatch| hatch.is_solid && hatch.is_associative)); + assert!(fills.iter().all(|hatch| hatch .paths .iter() .flat_map(|path| &path.boundary_handles) .count() == 1)); - app.tabs[i].scene.deselect_all(); - app.tabs[i].scene.select_entity(boundaries[0], false); + select(&mut app, &boundaries[..1]); + let _ = app.on_graphic_attribute(GraphicAttribute::Gradient); + assert_eq!(fill_kind(&app, boundaries[0]), GraphicAttribute::Gradient); + assert_eq!(fill_kind(&app, boundaries[1]), GraphicAttribute::Solid); + assert_eq!(hatches(&app).len(), 2); + } + + #[test] + fn unsupported_objects_are_skipped_while_the_rest_is_filled() { + let mut app = fresh(); + let i = app.active_tab; + let boundaries = [add_closed_square(&mut app, 0.0), add_closed_square(&mut app, 20.0)]; + select(&mut app, &boundaries); let _ = app.on_graphic_attribute(GraphicAttribute::Gradient); - let hatches: Vec<_> = app.tabs[i] - .scene - .document - .entities() - .filter_map(|entity| { - let EntityType::Hatch(hatch) = entity else { - return None; - }; - Some(hatch) - }) - .collect(); - assert_eq!(hatches.len(), 2); - assert_eq!( - hatches - .iter() - .filter(|hatch| hatch.gradient_color.enabled) - .count(), - 1 - ); - assert_eq!( - hatches - .iter() - .filter(|hatch| hatch.is_solid && !hatch.gradient_color.enabled) - .count(), - 1 - ); - // An invalid boundary is skipped while valid selected boundaries are - // still updated. let line = app.tabs[i].scene.add_entity(EntityType::Line(Line::new())); - app.tabs[i].scene.select_entity(line, false); + select(&mut app, &[boundaries[0], line]); let _ = app.on_graphic_attribute(GraphicAttribute::Solid); - let hatches: Vec<_> = app.tabs[i] - .scene - .document - .entities() - .filter_map(|entity| { - let EntityType::Hatch(hatch) = entity else { - return None; - }; - Some(hatch) - }) - .collect(); - assert_eq!(hatches.len(), 2); - assert!(hatches - .iter() - .all(|hatch| hatch.is_solid && !hatch.gradient_color.enabled)); - assert!(hatches.iter().all(|hatch| hatch - .paths - .iter() - .flat_map(|path| &path.boundary_handles) - .all(|handle| *handle != line))); + assert_eq!(fill_kind(&app, boundaries[0]), GraphicAttribute::Solid); + assert_eq!(fill_kind(&app, boundaries[1]), GraphicAttribute::Gradient); + assert_eq!(fill_kind(&app, line), GraphicAttribute::None); + assert_eq!(hatches(&app).len(), 2); + } - // Editing a common gradient updates each object's independent hatch - // and records the whole operation as one undo step. - app.tabs[i].scene.deselect_all(); - for handle in &boundaries { - app.tabs[i].scene.select_entity(*handle, false); - } + #[test] + fn editing_a_shared_gradient_is_one_undo_step() { + let mut app = fresh(); + let i = app.active_tab; + let boundaries = [add_closed_square(&mut app, 0.0), add_closed_square(&mut app, 20.0)]; + select(&mut app, &boundaries); let _ = app.on_graphic_attribute(GraphicAttribute::Gradient); + app.open_gradient_editor(); - let editor = app.graphic_attributes.gradient_editor.as_mut().expect("gradient editor"); + let editor = app + .graphic_attributes + .gradient_editor + .as_mut() + .expect("gradient editor"); assert_eq!(editor.handles.len(), 2); editor.kind = crate::scene::model::hatch_model::GradientKind::Curved; editor.inverted = true; @@ -1104,319 +1106,105 @@ mod tests { let _ = app.apply_gradient_editor(); assert_eq!(app.tabs[i].history.undo_stack.len(), undo_before + 1); - let gradients: Vec<_> = app.tabs[i] - .scene - .document - .entities() - .filter_map(|entity| { - let EntityType::Hatch(hatch) = entity else { - return None; - }; - hatch.gradient_color.enabled.then_some(hatch) - }) - .collect(); + let gradients = hatches(&app); assert_eq!(gradients.len(), 2); assert!(gradients.iter().all(|hatch| { hatch.gradient_color.name == "INVCURVED" && (hatch.gradient_color.angle.to_degrees() - 45.0).abs() < 1.0e-9 && (hatch.gradient_color.shift - 1.0).abs() < 1.0e-9 })); + } - // A selection change closes the flyout and it remains closed until - // the user explicitly opens it again. + #[test] + fn gradient_editor_closes_when_the_selection_changes() { + let mut app = fresh(); + filled_square(&mut app, GraphicAttribute::Gradient); app.open_gradient_editor(); assert!(app.graphic_attributes.gradient_editor.is_some()); - app.tabs[i].scene.deselect_all(); + + app.tabs[app.active_tab].scene.deselect_all(); let _ = app.update(ga(GraphicAttributesMsg::CloseMenu)); assert!(app.graphic_attributes.gradient_editor.is_none()); + } - let selected_hatch = app.tabs[i] - .scene - .document - .entities() - .find_map(|entity| { - matches!(entity, EntityType::Hatch(_)).then_some(entity.common().handle) - }) - .expect("gradient hatch"); - let associated_lines = palette::line_handles( - &app.tabs[i].scene.document, - &[selected_hatch], - ); - assert_eq!(associated_lines.len(), 1); - assert!(boundaries.contains(&associated_lines[0])); - assert_eq!( - palette::current( - &app.tabs[i].scene.document, - &[selected_hatch], - ), - GraphicAttribute::Gradient, - ); - app.tabs[i].scene.deselect_all(); - app.tabs[i].scene.select_entity(selected_hatch, false); + #[test] + fn a_selected_hatch_is_converted_in_place() { + let mut app = fresh(); + let (boundary, hatch) = filled_square(&mut app, GraphicAttribute::Gradient); + let document = &app.tabs[app.active_tab].scene.document; + assert_eq!(palette::line_handles(document, &[hatch]), vec![boundary]); + assert_eq!(fill_kind(&app, hatch), GraphicAttribute::Gradient); - // A directly selected hatch is edited in place instead of being - // rejected as an unsupported boundary object. - let _ = app.on_graphic_attribute(GraphicAttribute::Solid); - assert_eq!( - palette::current( - &app.tabs[i].scene.document, - &[selected_hatch], - ), - GraphicAttribute::Solid, - ); - let _ = app.on_solid_fill_color(acadrust::types::Color::Index(3)); - assert_eq!( - app.tabs[i] - .scene - .document - .get_entity(selected_hatch) - .expect("solid hatch") - .common() - .color, - acadrust::types::Color::Index(3), - ); - let _ = app.on_fill_transparency(acadrust::types::Transparency::from_percent(0.35)); - assert!( - (app.tabs[i] - .scene - .document - .get_entity(selected_hatch) - .expect("transparent solid hatch") - .common() - .transparency - .as_percent() - - 0.35) - .abs() - < 0.01 - ); - let _ = app.on_fill_transparency(acadrust::types::Transparency::BY_LAYER); - assert!(app.tabs[i] - .scene - .document - .get_entity(selected_hatch) - .expect("ByLayer solid hatch") - .common() - .transparency - .is_by_layer()); + for kind in [GraphicAttribute::Solid, GraphicAttribute::Hatch, GraphicAttribute::Gradient] { + let _ = app.on_graphic_attribute(kind); + assert_eq!(fill_kind(&app, hatch), kind); + } + assert_eq!(hatches(&app).len(), 1); + + let pattern = default_hatch_pattern().expect("pattern hatch").name.clone(); + let _ = app.update(ga(GraphicAttributesMsg::HatchPattern(pattern.clone()))); + assert_eq!(hatches(&app)[0].pattern.name, pattern); + } + + #[test] + fn line_and_fill_controls_only_edit_their_own_part() { + let mut app = fresh(); + let i = app.active_tab; + let (_, hatch) = filled_square(&mut app, GraphicAttribute::Solid); + let line = app.tabs[i].scene.add_entity(EntityType::Line(Line::new())); + select(&mut app, &[hatch, line]); + + let _ = app.on_solid_fill_color(AcadColor::Index(3)); + let _ = app.on_line_color(AcadColor::Index(4)); + assert_eq!(common(&app, hatch).color, AcadColor::Index(3)); + assert_eq!(common(&app, line).color, AcadColor::Index(4)); - // Line controls ignore HATCH entities, while fill controls ignore - // ordinary geometry in the same mixed selection. - app.tabs[i].scene.select_entity(line, false); - let _ = app.on_line_color(acadrust::types::Color::Index(4)); - assert_eq!( - app.tabs[i] - .scene - .document - .get_entity(line) - .expect("line") - .common() - .color, - acadrust::types::Color::Index(4), - ); - assert_eq!( - app.tabs[i] - .scene - .document - .get_entity(selected_hatch) - .expect("solid hatch") - .common() - .color, - acadrust::types::Color::Index(3), - ); - let _ = app.on_solid_fill_color(acadrust::types::Color::Index(5)); - assert_eq!( - app.tabs[i] - .scene - .document - .get_entity(selected_hatch) - .expect("solid hatch") - .common() - .color, - acadrust::types::Color::Index(5), - ); - assert_eq!( - app.tabs[i] - .scene - .document - .get_entity(line) - .expect("line") - .common() - .color, - acadrust::types::Color::Index(4), - ); let _ = app.on_line_linetype("ByBlock".to_string()); - assert_eq!( - app.tabs[i] - .scene - .document - .get_entity(line) - .expect("line") - .common() - .linetype, - "ByBlock", - ); - let _ = app.on_line_lineweight(acadrust::types::LineWeight::Value(50)); - assert_eq!( - app.tabs[i] - .scene - .document - .get_entity(line) - .expect("line") - .common() - .line_weight, - acadrust::types::LineWeight::Value(50), - ); - assert_ne!( - app.tabs[i] - .scene - .document - .get_entity(selected_hatch) - .expect("solid hatch") - .common() - .line_weight, - acadrust::types::LineWeight::Value(50), - ); - let _ = app.on_line_linetype_scale(2.5); - assert!( - (app.tabs[i] - .scene - .document - .get_entity(line) - .expect("line") - .common() - .linetype_scale - - 2.5) - .abs() - < f64::EPSILON - ); - assert!( - (app.tabs[i] - .scene - .document - .get_entity(selected_hatch) - .expect("solid hatch") - .common() - .linetype_scale - - 1.0) - .abs() - < f64::EPSILON - ); - let _ = app.update(ga(GraphicAttributesMsg::LineLinetypeScale(f64::NAN))); - assert_eq!( - app.tabs[i] - .scene - .document - .get_entity(line) - .expect("line") - .common() - .linetype_scale, - 2.5 - ); - let _ = app.update(ga(GraphicAttributesMsg::LineLinetypeScale(1.2000000000000002))); - assert_eq!( - app.tabs[i] - .scene - .document - .get_entity(line) - .expect("line") - .common() - .linetype_scale, - 1.2 - ); - let _ = app.on_line_transparency(acadrust::types::Transparency::from_percent(0.2)); - assert!( - (app.tabs[i] - .scene - .document - .get_entity(line) - .expect("line") - .common() - .transparency - .as_percent() - - 0.2) - .abs() - < 0.01 - ); - assert!(app.tabs[i] - .scene - .document - .get_entity(selected_hatch) - .expect("solid hatch") - .common() - .transparency - .is_by_layer()); - let _ = app.on_fill_transparency(acadrust::types::Transparency::from_percent(0.4)); - assert!( - (app.tabs[i] - .scene - .document - .get_entity(line) - .expect("line") - .common() - .transparency - .as_percent() - - 0.2) - .abs() - < 0.01 - ); - let pattern_name = crate::scene::model::hatch_patterns::catalog() - .iter() - .find(|entry| { - matches!( - entry.gpu, - crate::scene::model::hatch_model::HatchPattern::Pattern(_) - ) - }) - .expect("pattern hatch") - .name - .clone(); - let _ = app.update(ga(GraphicAttributesMsg::HatchPattern(pattern_name.clone()))); - let selected_pattern = match app.tabs[i] - .scene - .document - .get_entity(selected_hatch) - .expect("pattern hatch") - { - EntityType::Hatch(hatch) => hatch.pattern.name.as_str(), - _ => panic!("fill target is not a hatch"), - }; - assert_eq!(selected_pattern, pattern_name); - app.tabs[i].scene.deselect_all(); - app.tabs[i].scene.select_entity(selected_hatch, false); + assert_eq!(common(&app, line).linetype, "ByBlock"); - let _ = app.on_graphic_attribute(GraphicAttribute::Hatch); - assert_eq!( - palette::current( - &app.tabs[i].scene.document, - &[selected_hatch], - ), - GraphicAttribute::Hatch, - ); - let _ = app.on_graphic_attribute(GraphicAttribute::Gradient); - assert_eq!( - palette::current( - &app.tabs[i].scene.document, - &[selected_hatch], - ), - GraphicAttribute::Gradient, - ); + let _ = app.on_line_lineweight(LineWeight::Value(50)); + assert_eq!(common(&app, line).line_weight, LineWeight::Value(50)); + assert_ne!(common(&app, hatch).line_weight, LineWeight::Value(50)); + + let _ = app.on_line_linetype_scale(2.5); + assert_eq!(common(&app, line).linetype_scale, 2.5); + assert_eq!(common(&app, hatch).linetype_scale, 1.0); + let _ = app.update(ga(GraphicAttributesMsg::LineLinetypeScale(f64::NAN))); + assert_eq!(common(&app, line).linetype_scale, 2.5); + + let _ = app.on_line_transparency(Transparency::from_percent(0.2)); + let _ = app.on_fill_transparency(Transparency::from_percent(0.4)); + assert!((common(&app, line).transparency.as_percent() - 0.2).abs() < 0.01); + assert!((common(&app, hatch).transparency.as_percent() - 0.4).abs() < 0.01); + let _ = app.on_fill_transparency(Transparency::BY_LAYER); + assert!(common(&app, hatch).transparency.is_by_layer()); + assert!((common(&app, line).transparency.as_percent() - 0.2).abs() < 0.01); + } + + #[test] + fn choosing_another_fill_closes_the_editors() { + let mut app = fresh(); + filled_square(&mut app, GraphicAttribute::Gradient); app.open_gradient_editor(); assert!(app.graphic_attributes.gradient_editor.is_some()); let _ = app.on_graphic_attribute(GraphicAttribute::Hatch); assert!(app.graphic_attributes.gradient_editor.is_none()); + let _ = app.update(ga(GraphicAttributesMsg::HatchEditorOpen)); assert!(app.graphic_attributes.hatch_editor.is_some()); let _ = app.on_graphic_attribute(GraphicAttribute::Gradient); assert!(app.graphic_attributes.hatch_editor.is_none()); assert!(app.graphic_attributes.gradient_editor.is_none()); + } + #[test] + fn removing_the_fill_erases_it_in_one_undo_step() { + let mut app = fresh(); + let i = app.active_tab; + let (_, hatch) = filled_square(&mut app, GraphicAttribute::Solid); let undo_before = app.tabs[i].history.undo_stack.len(); let _ = app.on_graphic_attribute(GraphicAttribute::None); - assert!(app.tabs[i] - .scene - .document - .get_entity(selected_hatch) - .is_none()); + assert!(app.tabs[i].scene.document.get_entity(hatch).is_none()); assert_eq!(app.tabs[i].history.undo_stack.len(), undo_before + 1); } diff --git a/src/app/update/mod.rs b/src/app/update/mod.rs index 2d682e884..36097bbff 100644 --- a/src/app/update/mod.rs +++ b/src/app/update/mod.rs @@ -6477,31 +6477,7 @@ impl OpenCADStudio { Task::none() } Message::RibbonLinetypeChanged(lt) => self.on_ribbon_linetype_changed(lt), - Message::RibbonLineweightChanged(lw) => { - let i = self.active_tab; - self.ribbon.close_dropdown(); - let handles = self.property_target_handles(i); - if handles.is_empty() { - if self.has_property_selection(i) { - return Task::none(); - } - // Persist into the tab's header (CELWEIGHT). #21. - self.tabs[i].scene.document.header.current_line_weight = lw.value(); - self.tabs[i].dirty = true; - self.ribbon.active_lineweight = lw; - } else { - // Lineweight is baked into the cached wire geometry — - // re-tessellate so the change shows immediately (issue #231 - // class). - self.apply_property_op(i, "CHPROP", &handles, |app, handle| { - if let Some(entity) = app.tabs[i].scene.document.get_entity_mut(handle) { - crate::scene::view::dispatch::apply_line_weight(entity, lw); - } - }); - self.ribbon.active_lineweight = lw; - } - Task::none() - } + Message::RibbonLineweightChanged(lw) => self.on_ribbon_lineweight_changed(lw), Message::RibbonStyleChanged { key, name } => self.on_ribbon_style_changed(key, name), diff --git a/src/locale_catalog.rs b/src/locale_catalog.rs index bb32171c4..f9e70e4b4 100644 --- a/src/locale_catalog.rs +++ b/src/locale_catalog.rs @@ -5251,6 +5251,39 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static "US Survey Feet" => Some(("common", "us-survey-feet")), "to layout" => Some(("common", "to-layout")), "{count} objects selected" => Some(("common", "count-objects-selected")), + "Graphic Attributes" => Some(("graphic-attributes", "title")), + "Set all attributes ByLayer" => Some(("graphic-attributes", "set-all-bylayer")), + "Set all attributes ByBlock" => Some(("graphic-attributes", "set-all-byblock")), + "Remove ByLayer / ByBlock" => Some(("graphic-attributes", "remove-bylayer-byblock")), + "Create Layer with active settings" => Some(("graphic-attributes", "create-layer-active-settings")), + "Create fills on the current layer" => Some(("graphic-attributes", "fills-on-current-layer")), + "Edit hatch" => Some(("graphic-attributes", "edit-hatch")), + "Edit gradient" => Some(("graphic-attributes", "edit-gradient")), + "The selected object is open. Close it before creating the fill? [Yes / No] " => Some(("graphic-attributes", "close-open-object")), + "{count} selected objects are open. Close them before creating the fill? [Yes / No] " => Some(("graphic-attributes", "close-open-objects")), + "Enter a name for the new layer:" => Some(("graphic-attributes", "enter-new-layer-name")), + "Graphic Attributes: enter a valid layer name without <>/\\\":;?*|,=`." => Some(("graphic-attributes", "invalid-layer-name")), + "Graphic Attributes: layer \"{name}\" already exists." => Some(("graphic-attributes", "layer-exists")), + "Graphic Attributes: the layer could not be created." => Some(("graphic-attributes", "layer-not-created")), + "Created layer \"{name}\" with the active Graphic Attributes settings." => Some(("graphic-attributes", "layer-created")), + "Gradient Fill: the fill is on a locked layer." => Some(("graphic-attributes", "gradient-fill-locked")), + "Select one or more closed objects first." => Some(("graphic-attributes", "select-closed-objects")), + "Graphic Attributes: {} object(s) on a locked layer were not changed." => Some(("graphic-attributes", "locked-objects-skipped")), + "Graphic Attributes: no hatch pattern is available." => Some(("graphic-attributes", "no-hatch-pattern")), + "Graphic Attributes: an associated fill is on a locked layer." => Some(("graphic-attributes", "associated-fill-locked")), + "Graphic Attributes: 1 unsupported object was not changed." => Some(("graphic-attributes", "one-unsupported")), + "Graphic Attributes: {skipped} unsupported objects were not changed." => Some(("graphic-attributes", "unsupported-skipped")), + "Fill transparency" => Some(("graphic-attributes", "fill-transparency")), + "Line linetype" => Some(("graphic-attributes", "line-linetype")), + "Line transparency" => Some(("graphic-attributes", "line-transparency")), + "Cyl." => Some(("graphic-attributes", "cylindrical-short")), + "Spher." => Some(("graphic-attributes", "spherical-short")), + "Hemi." => Some(("graphic-attributes", "hemispherical-short")), + "Invert gradient" => Some(("graphic-attributes", "invert-gradient")), + "Tone" => Some(("graphic-attributes", "tone")), + "Reset angle" => Some(("graphic-attributes", "reset-angle")), + "One Color" => Some(("graphic-attributes", "one-color")), + "Two Colors" => Some(("graphic-attributes", "two-colors")), _ => None, } } diff --git a/src/ui/properties.rs b/src/ui/properties.rs index f0a86db38..ca12bf0e0 100644 --- a/src/ui/properties.rs +++ b/src/ui/properties.rs @@ -249,16 +249,29 @@ pub(crate) fn filtered_hatch_patterns( .collect() } +/// Messages of a hatch pattern picker; the Properties panel and the Graphic +/// Attributes palette each route them to their own state. +pub(crate) struct PatternPickerMessages { + pub search_id: &'static str, + pub on_search: fn(String) -> Message, + pub on_confirm: Message, + pub on_focus: fn(usize) -> Message, + pub on_changed: fn(String) -> Message, +} + pub(crate) fn hatch_pattern_picker_content<'a>( search_value: &'a str, focus: usize, current: &'a str, - search_id: &'static str, - on_search: fn(String) -> Message, - on_confirm: Message, - on_focus: fn(usize) -> Message, - on_changed: fn(String) -> Message, + messages: PatternPickerMessages, ) -> Element<'a, Message> { + let PatternPickerMessages { + search_id, + on_search, + on_confirm, + on_focus, + on_changed, + } = messages; let search = text_input(t!("Search patterns…").as_ref(), search_value) .id(iced::widget::Id::new(search_id)) .on_input(on_search) @@ -1663,11 +1676,13 @@ impl PropertiesPanel { &self.hatch_pattern_search, self.hatch_pattern_focus, current, - "hatch-pattern-search", - Message::PropHatchPatternSearchChanged, - Message::PropHatchPatternConfirm, - Message::PropHatchPatternFocus, - Message::PropHatchPatternChanged, + PatternPickerMessages { + search_id: "hatch-pattern-search", + on_search: Message::PropHatchPatternSearchChanged, + on_confirm: Message::PropHatchPatternConfirm, + on_focus: Message::PropHatchPatternFocus, + on_changed: Message::PropHatchPatternChanged, + }, ); prop_row_widget( diff --git a/src/ui/window/gradient_editor.rs b/src/ui/window/gradient_editor.rs index a51976f1d..d050b2a83 100644 --- a/src/ui/window/gradient_editor.rs +++ b/src/ui/window/gradient_editor.rs @@ -276,7 +276,7 @@ pub fn view(state: &GradientEditorState, dimmed: bool) -> Element<'_, Message> { } }) }; - let color_field = |label: &'static str, index, color: AcadColor| { + let color_field = |label: std::borrow::Cow<'static, str>, index, color: AcadColor| { let (background, _) = crate::ui::properties::acad_color_display(color); let value = crate::ui::color_select::color_display_name(color); let picker = button( @@ -320,11 +320,11 @@ pub fn view(state: &GradientEditorState, dimmed: bool) -> Element<'_, Message> { .width(Fill) }; let kinds = [ - (GradientKind::Linear, "Linear"), - (GradientKind::Cylinder, "Cyl."), - (GradientKind::Spherical, "Spher."), - (GradientKind::Hemispherical, "Hemi."), - (GradientKind::Curved, "Curved"), + (GradientKind::Linear, crate::t!("Linear")), + (GradientKind::Cylinder, crate::t!("Cyl.")), + (GradientKind::Spherical, crate::t!("Spher.")), + (GradientKind::Hemispherical, crate::t!("Hemi.")), + (GradientKind::Curved, crate::t!("Curved")), ]; let mut type_row = row![].spacing(3); for (kind, label) in kinds { @@ -357,7 +357,7 @@ pub fn view(state: &GradientEditorState, dimmed: bool) -> Element<'_, Message> { )); } let invert_selected = state.inverted && state.kind != GradientKind::Linear; - let invert = button(column![text("⇄").size(18), text("Invert").size(9)].align_x(iced::Center)) + let invert = button(column![text("⇄").size(18), text(crate::t!("Invert")).size(9)].align_x(iced::Center)) .on_press_maybe( (state.kind != GradientKind::Linear).then(|| msg(GradientMsg::InvertToggled)), ) @@ -378,21 +378,21 @@ pub fn view(state: &GradientEditorState, dimmed: bool) -> Element<'_, Message> { }); type_row = type_row.push(separator).push(tooltip( invert, - text("Invert gradient").size(10), + text(crate::t!("Invert gradient")).size(10), tooltip::Position::Bottom, )); let colors: Element<'_, Message> = if state.color_mode == GradientColorMode::Two { row![ - color_field("Color 1", 1, state.color_1), - color_field("Color 2", 2, state.color_2) + color_field(crate::t!("Color 1"), 1, state.color_1), + color_field(crate::t!("Color 2"), 2, state.color_2) ] .spacing(6) .into() } else { row![ - color_field("Color 1", 1, state.color_1), + color_field(crate::t!("Color 1"), 1, state.color_1), row![ - text("Tone").size(11).width(43), + text(crate::t!("Tone")).size(11).width(43), slider(0..=100, (state.shade_tint * 100.0) as i32, |v| { msg(GradientMsg::ShadeTint(v as f32 / 100.0)) }) @@ -408,7 +408,7 @@ pub fn view(state: &GradientEditorState, dimmed: bool) -> Element<'_, Message> { .into() }; let angle = row![ - text("Angle").size(11).width(43), + text(crate::t!("Angle")).size(11).width(43), text_input("0.0°", &state.angle) .on_input(|value| msg(GradientMsg::Angle(value))) .size(11) @@ -420,19 +420,19 @@ pub fn view(state: &GradientEditorState, dimmed: bool) -> Element<'_, Message> { .padding(3) .width(24) .height(crate::ui::ROW_H), - text("Reset angle").size(10), + text(crate::t!("Reset angle")).size(10), tooltip::Position::Bottom, ), Space::new().width(Fill), checkbox(state.centered) - .label("Centered") + .label(crate::t!("Centered")) .on_toggle(|value| msg(GradientMsg::Centered(value))) .size(14) .text_size(11) ] .spacing(6) .align_y(iced::Center); - let types = row![text("Type").size(11).width(43), type_row] + let types = row![text(crate::t!("Type")).size(11).width(43), type_row] .spacing(4) .align_y(iced::Center); let actions = container( @@ -453,8 +453,8 @@ pub fn view(state: &GradientEditorState, dimmed: bool) -> Element<'_, Message> { let content = column![ container(preview(state)).width(Fill).height(80), row![ - segment("One Color", GradientColorMode::One), - segment("Two Colors", GradientColorMode::Two) + segment(crate::t!("One Color"), GradientColorMode::One), + segment(crate::t!("Two Colors"), GradientColorMode::Two) ] .spacing(2), colors, diff --git a/src/ui/window/graphic_attributes.rs b/src/ui/window/graphic_attributes.rs index 5d327e91b..9a435c725 100644 --- a/src/ui/window/graphic_attributes.rs +++ b/src/ui/window/graphic_attributes.rs @@ -71,12 +71,12 @@ impl GraphicAttribute { impl std::fmt::Display for GraphicAttribute { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(match self { - Self::Varies => "*VARIES*", - Self::None => "None", - Self::Solid => "Solid", - Self::Hatch => "Hatch", - Self::Gradient => "Gradient", + f.write_str(&match self { + Self::Varies => "*VARIES*".into(), + Self::None => crate::t!("None"), + Self::Solid => crate::t!("Solid"), + Self::Hatch => crate::t!("Hatch"), + Self::Gradient => crate::t!("Gradient"), }) } } @@ -152,7 +152,7 @@ pub struct GraphicAttributesState { pub fill_on_current_layer: bool, /// View-side caches; `view` runs after every message, so neither the /// fill lookup nor the gradient preview is rebuilt unless its input changed. - fill_index: RefCell>, + fill_index: RefCell>, gradient_preview: RefCell)>>, } @@ -166,7 +166,9 @@ impl GraphicAttributesState { /// The fills and fill kind of `selected`, from an index of associative /// fills that is rebuilt only when the scene's geometry changes. pub(crate) fn fills(&self, scene: &Scene, selected: &[Handle]) -> (Vec, GraphicAttribute) { - let key = (std::ptr::from_ref(scene) as usize, scene.geometry_epoch); + // Geometry epochs are unique across all scenes, so the epoch alone + // identifies both the tab and the state of its drawing. + let key = scene.geometry_epoch; let mut cache = self.fill_index.borrow_mut(); if cache.as_ref().is_none_or(|(cached, _)| *cached != key) { *cache = Some((key, FillIndex::build(&scene.document))); @@ -219,12 +221,13 @@ impl GraphicAttributesState { pub fn fill_close_prompt(&self) -> Option { let count = self.pending_fill_close.as_ref()?.open_boundaries.len(); Some(if count == 1 { - "The selected object is open. Close it before creating the fill? [Yes / No] " - .to_string() + crate::t!("The selected object is open. Close it before creating the fill? [Yes / No] ") + .into_owned() } else { - format!( + crate::tf!( "{count} selected objects are open. Close them before creating the fill? [Yes / No] " ) + .into_owned() }) } } @@ -634,7 +637,7 @@ fn compact_button_content(label: &'static str) -> Element<'static, Message> { .into() } -fn popup_item<'a>(label: &'a str, message: Message) -> Element<'a, Message> { +fn popup_item<'a>(label: std::borrow::Cow<'a, str>, message: Message) -> Element<'a, Message> { button(text(label).size(11)) .on_press(message) .style(crate::ui::color_select::list_row_style) @@ -650,7 +653,7 @@ fn mode_menu<'a>( menu: Menu, open_menu: Option, height: f32, - items: Vec<(&'a str, Message)>, + items: Vec<(std::borrow::Cow<'a, str>, Message)>, ) -> Element<'a, Message> { let open = open_menu == Some(menu); let more = button(compact_button_content(mode.button_label())) @@ -738,9 +741,9 @@ fn color_control<'a>( open_menu, COMPACT_BUTTON_HEIGHT, vec![ - ("ByLayer", msg(changed(AcadColor::ByLayer))), - ("ByBlock", msg(changed(AcadColor::ByBlock))), - ("Custom...", Message::OpenColorWindow(target, info.color)), + ("ByLayer".into(), msg(changed(AcadColor::ByLayer))), + ("ByBlock".into(), msg(changed(AcadColor::ByBlock))), + (crate::t!("Custom…"), Message::OpenColorWindow(target, info.color)), ], ); row![swatch, more].spacing(4).align_y(iced::Center).into() @@ -777,9 +780,9 @@ fn transparency_control<'a>( open_menu, crate::ui::ROW_H, vec![ - ("ByLayer", msg(changed(Transparency::BY_LAYER))), - ("ByBlock", msg(changed(Transparency::BY_BLOCK))), - ("Custom", msg(changed(percent(info.value)))), + ("ByLayer".into(), msg(changed(Transparency::BY_LAYER))), + ("ByBlock".into(), msg(changed(Transparency::BY_BLOCK))), + (crate::t!("Custom"), msg(changed(percent(info.value)))), ], ); row![control, more].spacing(4).align_y(iced::Center).into() @@ -804,7 +807,7 @@ fn header_menu(side: DockSide, open: bool, fill_on_current_layer: bool) -> Eleme } let item = |label: &'static str, message| { - button(text(label).size(11)) + button(text(crate::t!(label)).size(11)) .on_press(msg(message)) .style(crate::ui::color_select::list_row_style) .width(Fill) @@ -817,7 +820,7 @@ fn header_menu(side: DockSide, open: bool, fill_on_current_layer: bool) -> Eleme item("Create Layer with active settings", GraphicAttributesMsg::CreateLayer), container( iced::widget::checkbox(fill_on_current_layer) - .label("Create fills on the current layer") + .label(crate::t!("Create fills on the current layer")) .on_toggle(|_| msg(GraphicAttributesMsg::ToggleFillOnCurrentLayer)) .size(12) .text_size(11), @@ -952,7 +955,7 @@ fn preview_row<'a>( preview: Element<'a, Message>, editor_open: bool, toggle: GraphicAttributesMsg, - tooltip_label: &'static str, + tooltip_label: std::borrow::Cow<'static, str>, flyout: Option<(Element<'a, Message>, f32, Option)>, side: DockSide, ) -> Element<'a, Message> { @@ -1054,8 +1057,8 @@ fn linetype_row<'a>( open_menu, COMPACT_BUTTON_HEIGHT, vec![ - ("ByLayer", msg(GraphicAttributesMsg::LineLinetype("ByLayer".into()))), - ("ByBlock", msg(GraphicAttributesMsg::LineLinetype("ByBlock".into()))), + ("ByLayer".into(), msg(GraphicAttributesMsg::LineLinetype("ByLayer".into()))), + ("ByBlock".into(), msg(GraphicAttributesMsg::LineLinetype("ByBlock".into()))), ], ); row![crate::ui::wide_menu::wide_menu(combo, 220.0), more] @@ -1166,8 +1169,8 @@ fn lineweight_field<'a>( open_menu, COMPACT_BUTTON_HEIGHT, vec![ - ("ByLayer", msg(GraphicAttributesMsg::LineLineweight(LineWeight::ByLayer))), - ("ByBlock", msg(GraphicAttributesMsg::LineLineweight(LineWeight::ByBlock))), + ("ByLayer".into(), msg(GraphicAttributesMsg::LineLineweight(LineWeight::ByLayer))), + ("ByBlock".into(), msg(GraphicAttributesMsg::LineLineweight(LineWeight::ByBlock))), ], ); row![ @@ -1324,11 +1327,13 @@ pub fn view<'a>( &editor.search, editor.focus, hatch.map_or("", |hatch| hatch.pattern.name.as_str()), - "graphic-hatch-pattern-search", - |search| msg(GraphicAttributesMsg::HatchPatternSearch(search)), - msg(GraphicAttributesMsg::HatchPatternConfirm), - |index| msg(GraphicAttributesMsg::HatchPatternFocus(index)), - |name| msg(GraphicAttributesMsg::HatchPattern(name)), + crate::ui::properties::PatternPickerMessages { + search_id: "graphic-hatch-pattern-search", + on_search: |search| msg(GraphicAttributesMsg::HatchPatternSearch(search)), + on_confirm: msg(GraphicAttributesMsg::HatchPatternConfirm), + on_focus: |index| msg(GraphicAttributesMsg::HatchPatternFocus(index)), + on_changed: |name| msg(GraphicAttributesMsg::HatchPattern(name)), + }, ); let popup = container(picker) .padding(1) @@ -1352,7 +1357,7 @@ pub fn view<'a>( } else { GraphicAttributesMsg::HatchEditorOpen }, - "Edit hatch", + crate::t!("Edit hatch"), flyout, side, )); @@ -1390,7 +1395,7 @@ pub fn view<'a>( } else { GradientMsg::Open }), - "Edit gradient", + crate::t!("Edit gradient"), flyout, side, ));