diff --git a/assets/icons/ui/info.svg b/assets/icons/ui/info.svg new file mode 100644 index 000000000..212f70fce --- /dev/null +++ b/assets/icons/ui/info.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/ui/more.svg b/assets/icons/ui/more.svg new file mode 100644 index 000000000..50d01007a --- /dev/null +++ b/assets/icons/ui/more.svg @@ -0,0 +1 @@ + diff --git a/locales/ar-SA/opencadstudio.ftl b/locales/ar-SA/opencadstudio.ftl index a39edaf12..1c01174f9 100644 --- a/locales/ar-SA/opencadstudio.ftl +++ b/locales/ar-SA/opencadstudio.ftl @@ -5940,8 +5940,6 @@ style-manager = .block-extents = نطاق الكتلة .base-point = نقطة الأساس count-feature = - .palette = Count - .menu = Count .selection = Count Selection .review = Review Count Details .insert-field = Insert Count Field @@ -5964,3 +5962,18 @@ count-feature = .invalid-continue = Continue and count the entire model space .invalid-continue-detail = The count area is dropped; counting goes on in all of model space. .invalid-always = Always perform my current choice + .found = تم العثور على __ocs_fmt_0__ + .found-total = تم العثور على __ocs_fmt_0__، الإجمالي __ocs_fmt_1__ + .field-only-in-count = ** الأمر COUNTFIELD متاح فقط أثناء العد. ** + .area-active = منطقة العد نشطة. + .read-only-value = __ocs_fmt_0__ = __ocs_fmt_1__ (للقراءة فقط) + .requires-0-or-1 = يتطلب 0 أو 1 فقط. + .requires-int-range = يتطلب عددًا صحيحًا بين __ocs_fmt_0__ و __ocs_fmt_1__. + .target-count = __ocs_fmt_0__ ...... __ocs_fmt_1__ + .mtext-current-style = MTEXT نمط النص الحالي: "__ocs_fmt_0__" ارتفاع النص: __ocs_fmt_1__ + .fields-found = تم العثور على __ocs_fmt_0__ من الحقول. + .fields-updated = تم تحديث __ocs_fmt_0__ من الحقول. + .invalid-keyword = كلمة مفتاحية للخيار غير صالحة. + .invalid-boundary = كائن حد منطقة العد غير صالح. حدد خطًا متعددًا مغلقًا يتكون من قطع مستقيمة ولا يتقاطع مع نفسه. + .block-not-found = تعذر العثور على الكتلة "__ocs_fmt_0__". + .invalid-point = نقطة غير صالحة. diff --git a/locales/bg-BG/opencadstudio.ftl b/locales/bg-BG/opencadstudio.ftl index 294ebfdf2..fe2b0bf6c 100644 --- a/locales/bg-BG/opencadstudio.ftl +++ b/locales/bg-BG/opencadstudio.ftl @@ -5928,8 +5928,6 @@ style-manager = .block-extents = Обхват на блок .base-point = Базова точка count-feature = - .palette = Count - .menu = Count .selection = Count Selection .review = Review Count Details .insert-field = Insert Count Field @@ -5952,3 +5950,18 @@ count-feature = .invalid-continue = Continue and count the entire model space .invalid-continue-detail = The count area is dropped; counting goes on in all of model space. .invalid-always = Always perform my current choice + .found = Намерени: __ocs_fmt_0__ + .found-total = Намерени: __ocs_fmt_0__, общо: __ocs_fmt_1__ + .field-only-in-count = ** Командата COUNTFIELD е достъпна само по време на преброяване. ** + .area-active = Областта за преброяване е активна. + .read-only-value = __ocs_fmt_0__ = __ocs_fmt_1__ (само за четене) + .requires-0-or-1 = Изисква се само 0 или 1. + .requires-int-range = Изисква се цяло число между __ocs_fmt_0__ и __ocs_fmt_1__. + .target-count = __ocs_fmt_0__ ...... __ocs_fmt_1__ + .mtext-current-style = MTEXT Текущ текстов стил: "__ocs_fmt_0__" Височина на текста: __ocs_fmt_1__ + .fields-found = Намерени полета: __ocs_fmt_0__. + .fields-updated = Обновени полета: __ocs_fmt_0__. + .invalid-keyword = Невалидна ключова дума на опция. + .invalid-boundary = Невалиден обект за граница на областта за преброяване. Изберете затворена полилиния от отсечки, която не се самопресича. + .block-not-found = Блокът "__ocs_fmt_0__" не може да бъде намерен. + .invalid-point = Невалидна точка. diff --git a/locales/cs-CZ/opencadstudio.ftl b/locales/cs-CZ/opencadstudio.ftl index b26dfe485..10cc0a116 100644 --- a/locales/cs-CZ/opencadstudio.ftl +++ b/locales/cs-CZ/opencadstudio.ftl @@ -5925,8 +5925,6 @@ style-manager = .block-extents = Blokovat rozsahy .base-point = Základní bod count-feature = - .palette = Count - .menu = Count .selection = Count Selection .review = Review Count Details .insert-field = Insert Count Field @@ -5949,3 +5947,18 @@ count-feature = .invalid-continue = Continue and count the entire model space .invalid-continue-detail = The count area is dropped; counting goes on in all of model space. .invalid-always = Always perform my current choice + .found = Nalezeno: __ocs_fmt_0__ + .found-total = Nalezeno: __ocs_fmt_0__, celkem: __ocs_fmt_1__ + .field-only-in-count = ** Příkaz COUNTFIELD je dostupný pouze během počítání. ** + .area-active = Oblast počítání je aktivní. + .read-only-value = __ocs_fmt_0__ = __ocs_fmt_1__ (jen pro čtení) + .requires-0-or-1 = Vyžaduje pouze 0 nebo 1. + .requires-int-range = Vyžaduje celé číslo mezi __ocs_fmt_0__ a __ocs_fmt_1__. + .target-count = __ocs_fmt_0__ ...... __ocs_fmt_1__ + .mtext-current-style = MTEXT Aktuální styl textu: "__ocs_fmt_0__" Výška textu: __ocs_fmt_1__ + .fields-found = Nalezeno polí: __ocs_fmt_0__. + .fields-updated = Aktualizováno polí: __ocs_fmt_0__. + .invalid-keyword = Neplatné klíčové slovo volby. + .invalid-boundary = Neplatný objekt hranice oblasti počítání. Vyberte uzavřenou křivku složenou z úseček, která neprotíná sama sebe. + .block-not-found = Blok "__ocs_fmt_0__" nelze najít. + .invalid-point = Neplatný bod. diff --git a/locales/de-DE/opencadstudio.ftl b/locales/de-DE/opencadstudio.ftl index 14e1ceaa3..605ccb174 100644 --- a/locales/de-DE/opencadstudio.ftl +++ b/locales/de-DE/opencadstudio.ftl @@ -5926,8 +5926,6 @@ style-manager = .block-extents = Blockgrenzen .base-point = Basispunkt count-feature = - .palette = Count - .menu = Count .selection = Count Selection .review = Review Count Details .insert-field = Insert Count Field @@ -5950,3 +5948,18 @@ count-feature = .invalid-continue = Continue and count the entire model space .invalid-continue-detail = The count area is dropped; counting goes on in all of model space. .invalid-always = Always perform my current choice + .found = __ocs_fmt_0__ gefunden + .found-total = __ocs_fmt_0__ gefunden, __ocs_fmt_1__ gesamt + .field-only-in-count = ** Der Befehl COUNTFIELD ist nur während der Zählung verfügbar. ** + .area-active = Zählbereich ist aktiv. + .read-only-value = __ocs_fmt_0__ = __ocs_fmt_1__ (schreibgeschützt) + .requires-0-or-1 = Nur 0 oder 1 zulässig. + .requires-int-range = Erfordert eine ganze Zahl zwischen __ocs_fmt_0__ und __ocs_fmt_1__. + .target-count = __ocs_fmt_0__ ...... __ocs_fmt_1__ + .mtext-current-style = MTEXT Aktueller Textstil: "__ocs_fmt_0__" Texthöhe: __ocs_fmt_1__ + .fields-found = __ocs_fmt_0__ Feld(er) gefunden. + .fields-updated = __ocs_fmt_0__ Feld(er) aktualisiert. + .invalid-keyword = Ungültiges Optionsschlüsselwort. + .invalid-boundary = Ungültiges Begrenzungsobjekt für den Zählbereich. Wählen Sie eine geschlossene Polylinie aus Liniensegmenten, die sich nicht selbst schneidet. + .block-not-found = Block "__ocs_fmt_0__" wurde nicht gefunden. + .invalid-point = Ungültiger Punkt. diff --git a/locales/el-GR/opencadstudio.ftl b/locales/el-GR/opencadstudio.ftl index 047ec281e..433624525 100644 --- a/locales/el-GR/opencadstudio.ftl +++ b/locales/el-GR/opencadstudio.ftl @@ -5928,8 +5928,6 @@ style-manager = .block-extents = Όρια μπλοκ .base-point = Σημείο βάσης count-feature = - .palette = Count - .menu = Count .selection = Count Selection .review = Review Count Details .insert-field = Insert Count Field @@ -5952,3 +5950,18 @@ count-feature = .invalid-continue = Continue and count the entire model space .invalid-continue-detail = The count area is dropped; counting goes on in all of model space. .invalid-always = Always perform my current choice + .found = Βρέθηκαν: __ocs_fmt_0__ + .found-total = Βρέθηκαν: __ocs_fmt_0__, σύνολο: __ocs_fmt_1__ + .field-only-in-count = ** Η εντολή COUNTFIELD είναι διαθέσιμη μόνο κατά την καταμέτρηση. ** + .area-active = Η περιοχή καταμέτρησης είναι ενεργή. + .read-only-value = __ocs_fmt_0__ = __ocs_fmt_1__ (μόνο για ανάγνωση) + .requires-0-or-1 = Απαιτείται μόνο 0 ή 1. + .requires-int-range = Απαιτείται ακέραιος μεταξύ __ocs_fmt_0__ και __ocs_fmt_1__. + .target-count = __ocs_fmt_0__ ...... __ocs_fmt_1__ + .mtext-current-style = MTEXT Τρέχον στυλ κειμένου: "__ocs_fmt_0__" Ύψος κειμένου: __ocs_fmt_1__ + .fields-found = Βρέθηκαν πεδία: __ocs_fmt_0__. + .fields-updated = Ενημερώθηκαν πεδία: __ocs_fmt_0__. + .invalid-keyword = Μη έγκυρη λέξη-κλειδί επιλογής. + .invalid-boundary = Μη έγκυρο αντικείμενο ορίου περιοχής καταμέτρησης. Επιλέξτε μια κλειστή πολυγραμμή από ευθύγραμμα τμήματα που δεν τέμνει τον εαυτό της. + .block-not-found = Το μπλοκ "__ocs_fmt_0__" δεν βρέθηκε. + .invalid-point = Μη έγκυρο σημείο. diff --git a/locales/en-US/opencadstudio.ftl b/locales/en-US/opencadstudio.ftl index 96e53825f..6f3f4730d 100644 --- a/locales/en-US/opencadstudio.ftl +++ b/locales/en-US/opencadstudio.ftl @@ -5929,8 +5929,6 @@ style-manager = .block-extents = Block extents .base-point = Base point count-feature = - .palette = Count - .menu = Count .selection = Count Selection .review = Review Count Details .insert-field = Insert Count Field @@ -5953,3 +5951,18 @@ count-feature = .invalid-continue = Continue and count the entire model space .invalid-continue-detail = The count area is dropped; counting goes on in all of model space. .invalid-always = Always perform my current choice + .found = __ocs_fmt_0__ found + .found-total = __ocs_fmt_0__ found, __ocs_fmt_1__ total + .field-only-in-count = ** COUNTFIELD command only available during Count. ** + .area-active = count area is active. + .read-only-value = __ocs_fmt_0__ = __ocs_fmt_1__ (read only) + .requires-0-or-1 = Requires 0 or 1 only. + .requires-int-range = Requires an integer between __ocs_fmt_0__ and __ocs_fmt_1__. + .target-count = __ocs_fmt_0__ ...... __ocs_fmt_1__ + .mtext-current-style = MTEXT Current text style: "__ocs_fmt_0__" Text height: __ocs_fmt_1__ + .fields-found = __ocs_fmt_0__ field(s) found. + .fields-updated = __ocs_fmt_0__ field(s) updated. + .invalid-keyword = Invalid option keyword. + .invalid-boundary = Invalid count area boundary object. Select a closed polyline consisting of line segments and does not intersect itself. + .block-not-found = Block "__ocs_fmt_0__" cannot be found. + .invalid-point = Invalid point. diff --git a/locales/es-ES/opencadstudio.ftl b/locales/es-ES/opencadstudio.ftl index 79a021096..4bb6669be 100644 --- a/locales/es-ES/opencadstudio.ftl +++ b/locales/es-ES/opencadstudio.ftl @@ -5928,8 +5928,6 @@ style-manager = .block-extents = Extensión del bloque .base-point = Punto base count-feature = - .palette = Count - .menu = Count .selection = Count Selection .review = Review Count Details .insert-field = Insert Count Field @@ -5952,3 +5950,18 @@ count-feature = .invalid-continue = Continue and count the entire model space .invalid-continue-detail = The count area is dropped; counting goes on in all of model space. .invalid-always = Always perform my current choice + .found = __ocs_fmt_0__ encontrado(s) + .found-total = __ocs_fmt_0__ encontrado(s), __ocs_fmt_1__ en total + .field-only-in-count = ** El comando COUNTFIELD solo está disponible durante el recuento. ** + .area-active = El área de recuento está activa. + .read-only-value = __ocs_fmt_0__ = __ocs_fmt_1__ (solo lectura) + .requires-0-or-1 = Solo admite 0 o 1. + .requires-int-range = Se requiere un entero entre __ocs_fmt_0__ y __ocs_fmt_1__. + .target-count = __ocs_fmt_0__ ...... __ocs_fmt_1__ + .mtext-current-style = MTEXT Estilo de texto actual: "__ocs_fmt_0__" Altura de texto: __ocs_fmt_1__ + .fields-found = __ocs_fmt_0__ campo(s) encontrado(s). + .fields-updated = __ocs_fmt_0__ campo(s) actualizado(s). + .invalid-keyword = Palabra clave de opción no válida. + .invalid-boundary = Objeto de contorno de área de recuento no válido. Seleccione una polilínea cerrada formada por segmentos de línea que no se corte a sí misma. + .block-not-found = No se encuentra el bloque "__ocs_fmt_0__". + .invalid-point = Punto no válido. diff --git a/locales/fi-FI/opencadstudio.ftl b/locales/fi-FI/opencadstudio.ftl index 72cbd4dcd..e01e8ffca 100644 --- a/locales/fi-FI/opencadstudio.ftl +++ b/locales/fi-FI/opencadstudio.ftl @@ -5925,8 +5925,6 @@ style-manager = .block-extents = Estä laajuudet .base-point = Peruspiste count-feature = - .palette = Count - .menu = Count .selection = Count Selection .review = Review Count Details .insert-field = Insert Count Field @@ -5949,3 +5947,18 @@ count-feature = .invalid-continue = Continue and count the entire model space .invalid-continue-detail = The count area is dropped; counting goes on in all of model space. .invalid-always = Always perform my current choice + .found = Löytyi __ocs_fmt_0__ + .found-total = Löytyi __ocs_fmt_0__, yhteensä __ocs_fmt_1__ + .field-only-in-count = ** COUNTFIELD-komento on käytettävissä vain laskennan aikana. ** + .area-active = Laskenta-alue on aktiivinen. + .read-only-value = __ocs_fmt_0__ = __ocs_fmt_1__ (vain luku) + .requires-0-or-1 = Vain 0 tai 1 sallitaan. + .requires-int-range = Vaaditaan kokonaisluku väliltä __ocs_fmt_0__–__ocs_fmt_1__. + .target-count = __ocs_fmt_0__ ...... __ocs_fmt_1__ + .mtext-current-style = MTEXT Nykyinen tekstityyli: "__ocs_fmt_0__" Tekstin korkeus: __ocs_fmt_1__ + .fields-found = Kenttiä löytyi: __ocs_fmt_0__. + .fields-updated = Kenttiä päivitetty: __ocs_fmt_0__. + .invalid-keyword = Virheellinen asetuksen avainsana. + .invalid-boundary = Virheellinen laskenta-alueen rajaobjekti. Valitse suljettu, janoista koostuva moniviiva, joka ei leikkaa itseään. + .block-not-found = Lohkoa "__ocs_fmt_0__" ei löydy. + .invalid-point = Virheellinen piste. diff --git a/locales/fr-FR/opencadstudio.ftl b/locales/fr-FR/opencadstudio.ftl index 702e42640..ca2bda963 100644 --- a/locales/fr-FR/opencadstudio.ftl +++ b/locales/fr-FR/opencadstudio.ftl @@ -5927,8 +5927,6 @@ style-manager = .block-extents = Limites du bloc .base-point = Point de base count-feature = - .palette = Count - .menu = Count .selection = Count Selection .review = Review Count Details .insert-field = Insert Count Field @@ -5951,3 +5949,18 @@ count-feature = .invalid-continue = Continue and count the entire model space .invalid-continue-detail = The count area is dropped; counting goes on in all of model space. .invalid-always = Always perform my current choice + .found = __ocs_fmt_0__ trouvé(s) + .found-total = __ocs_fmt_0__ trouvé(s), __ocs_fmt_1__ au total + .field-only-in-count = ** La commande COUNTFIELD n'est disponible que pendant le comptage. ** + .area-active = La zone de comptage est active. + .read-only-value = __ocs_fmt_0__ = __ocs_fmt_1__ (lecture seule) + .requires-0-or-1 = Nécessite 0 ou 1 uniquement. + .requires-int-range = Nécessite un entier compris entre __ocs_fmt_0__ et __ocs_fmt_1__. + .target-count = __ocs_fmt_0__ ...... __ocs_fmt_1__ + .mtext-current-style = MTEXT Style de texte courant : "__ocs_fmt_0__" Hauteur du texte : __ocs_fmt_1__ + .fields-found = __ocs_fmt_0__ champ(s) trouvé(s). + .fields-updated = __ocs_fmt_0__ champ(s) mis à jour. + .invalid-keyword = Mot-clé d'option non valide. + .invalid-boundary = Objet de contour de zone de comptage non valide. Sélectionnez une polyligne fermée composée de segments de ligne et qui ne se recoupe pas. + .block-not-found = Le bloc "__ocs_fmt_0__" est introuvable. + .invalid-point = Point non valide. diff --git a/locales/hi-IN/opencadstudio.ftl b/locales/hi-IN/opencadstudio.ftl index 0ab2cf7fa..3585bacf9 100644 --- a/locales/hi-IN/opencadstudio.ftl +++ b/locales/hi-IN/opencadstudio.ftl @@ -5916,8 +5916,6 @@ style-manager = .block-extents = ब्लॉक परिमिति .base-point = आधार बिंदु count-feature = - .palette = Count - .menu = Count .selection = Count Selection .review = Review Count Details .insert-field = Insert Count Field @@ -5940,3 +5938,18 @@ count-feature = .invalid-continue = Continue and count the entire model space .invalid-continue-detail = The count area is dropped; counting goes on in all of model space. .invalid-always = Always perform my current choice + .found = __ocs_fmt_0__ मिले + .found-total = __ocs_fmt_0__ मिले, कुल __ocs_fmt_1__ + .field-only-in-count = ** COUNTFIELD कमांड केवल गणना के दौरान उपलब्ध है। ** + .area-active = गणना क्षेत्र सक्रिय है। + .read-only-value = __ocs_fmt_0__ = __ocs_fmt_1__ (केवल पढ़ने के लिए) + .requires-0-or-1 = केवल 0 या 1 आवश्यक है। + .requires-int-range = __ocs_fmt_0__ और __ocs_fmt_1__ के बीच पूर्णांक आवश्यक है। + .target-count = __ocs_fmt_0__ ...... __ocs_fmt_1__ + .mtext-current-style = MTEXT वर्तमान टेक्स्ट शैली: "__ocs_fmt_0__" टेक्स्ट ऊँचाई: __ocs_fmt_1__ + .fields-found = __ocs_fmt_0__ फ़ील्ड मिले। + .fields-updated = __ocs_fmt_0__ फ़ील्ड अपडेट किए गए। + .invalid-keyword = अमान्य विकल्प कीवर्ड। + .invalid-boundary = अमान्य गणना क्षेत्र सीमा ऑब्जेक्ट। रेखा खंडों से बनी ऐसी बंद पॉलीलाइन चुनें जो स्वयं को प्रतिच्छेद न करे। + .block-not-found = ब्लॉक "__ocs_fmt_0__" नहीं मिला। + .invalid-point = अमान्य बिंदु। diff --git a/locales/hu-HU/opencadstudio.ftl b/locales/hu-HU/opencadstudio.ftl index a92b034f2..665907146 100644 --- a/locales/hu-HU/opencadstudio.ftl +++ b/locales/hu-HU/opencadstudio.ftl @@ -5927,8 +5927,6 @@ style-manager = .block-extents = Kiterjedések blokkolása .base-point = Alappont count-feature = - .palette = Count - .menu = Count .selection = Count Selection .review = Review Count Details .insert-field = Insert Count Field @@ -5951,3 +5949,18 @@ count-feature = .invalid-continue = Continue and count the entire model space .invalid-continue-detail = The count area is dropped; counting goes on in all of model space. .invalid-always = Always perform my current choice + .found = __ocs_fmt_0__ található + .found-total = __ocs_fmt_0__ található, összesen __ocs_fmt_1__ + .field-only-in-count = ** A COUNTFIELD parancs csak számlálás közben érhető el. ** + .area-active = A számlálási terület aktív. + .read-only-value = __ocs_fmt_0__ = __ocs_fmt_1__ (csak olvasható) + .requires-0-or-1 = Csak 0 vagy 1 adható meg. + .requires-int-range = __ocs_fmt_0__ és __ocs_fmt_1__ közötti egész szám szükséges. + .target-count = __ocs_fmt_0__ ...... __ocs_fmt_1__ + .mtext-current-style = MTEXT Aktuális szövegstílus: "__ocs_fmt_0__" Szövegmagasság: __ocs_fmt_1__ + .fields-found = __ocs_fmt_0__ mező található. + .fields-updated = __ocs_fmt_0__ mező frissítve. + .invalid-keyword = Érvénytelen opciókulcsszó. + .invalid-boundary = Érvénytelen számlálási terület határobjektum. Válasszon egy zárt, vonalszakaszokból álló, önmagát nem metsző vonalláncot. + .block-not-found = A(z) "__ocs_fmt_0__" blokk nem található. + .invalid-point = Érvénytelen pont. diff --git a/locales/it-IT/opencadstudio.ftl b/locales/it-IT/opencadstudio.ftl index d4f900ae2..134de2c2b 100644 --- a/locales/it-IT/opencadstudio.ftl +++ b/locales/it-IT/opencadstudio.ftl @@ -5927,8 +5927,6 @@ style-manager = .block-extents = Blocca estensioni .base-point = Punto base count-feature = - .palette = Count - .menu = Count .selection = Count Selection .review = Review Count Details .insert-field = Insert Count Field @@ -5951,3 +5949,18 @@ count-feature = .invalid-continue = Continue and count the entire model space .invalid-continue-detail = The count area is dropped; counting goes on in all of model space. .invalid-always = Always perform my current choice + .found = __ocs_fmt_0__ trovati + .found-total = __ocs_fmt_0__ trovati, __ocs_fmt_1__ in totale + .field-only-in-count = ** Il comando COUNTFIELD è disponibile solo durante il conteggio. ** + .area-active = L'area di conteggio è attiva. + .read-only-value = __ocs_fmt_0__ = __ocs_fmt_1__ (sola lettura) + .requires-0-or-1 = Richiede solo 0 o 1. + .requires-int-range = Richiede un numero intero compreso tra __ocs_fmt_0__ e __ocs_fmt_1__. + .target-count = __ocs_fmt_0__ ...... __ocs_fmt_1__ + .mtext-current-style = MTEXT Stile di testo corrente: "__ocs_fmt_0__" Altezza testo: __ocs_fmt_1__ + .fields-found = __ocs_fmt_0__ campi trovati. + .fields-updated = __ocs_fmt_0__ campi aggiornati. + .invalid-keyword = Parola chiave dell'opzione non valida. + .invalid-boundary = Oggetto di contorno dell'area di conteggio non valido. Selezionare una polilinea chiusa composta da segmenti di linea che non si interseca. + .block-not-found = Impossibile trovare il blocco "__ocs_fmt_0__". + .invalid-point = Punto non valido. diff --git a/locales/ja-JP/opencadstudio.ftl b/locales/ja-JP/opencadstudio.ftl index 8b1b1dbde..77c7b54d9 100644 --- a/locales/ja-JP/opencadstudio.ftl +++ b/locales/ja-JP/opencadstudio.ftl @@ -5916,8 +5916,6 @@ style-manager = .block-extents = ブロック範囲 .base-point = 基点 count-feature = - .palette = Count - .menu = Count .selection = Count Selection .review = Review Count Details .insert-field = Insert Count Field @@ -5940,3 +5938,18 @@ count-feature = .invalid-continue = Continue and count the entire model space .invalid-continue-detail = The count area is dropped; counting goes on in all of model space. .invalid-always = Always perform my current choice + .found = __ocs_fmt_0__ 個を検出 + .found-total = __ocs_fmt_0__ 個を検出、合計 __ocs_fmt_1__ 個 + .field-only-in-count = ** COUNTFIELD コマンドはカウント中のみ使用できます。 ** + .area-active = カウント領域が有効です。 + .read-only-value = __ocs_fmt_0__ = __ocs_fmt_1__ (読み取り専用) + .requires-0-or-1 = 0 または 1 のみ指定できます。 + .requires-int-range = __ocs_fmt_0__ から __ocs_fmt_1__ までの整数を指定してください。 + .target-count = __ocs_fmt_0__ ...... __ocs_fmt_1__ + .mtext-current-style = MTEXT 現在の文字スタイル: "__ocs_fmt_0__" 文字の高さ: __ocs_fmt_1__ + .fields-found = __ocs_fmt_0__ 個のフィールドが見つかりました。 + .fields-updated = __ocs_fmt_0__ 個のフィールドを更新しました。 + .invalid-keyword = オプションのキーワードが無効です。 + .invalid-boundary = カウント領域の境界オブジェクトが無効です。線分で構成され、自己交差しない閉じたポリラインを選択してください。 + .block-not-found = ブロック "__ocs_fmt_0__" が見つかりません。 + .invalid-point = 点が無効です。 diff --git a/locales/ko-KR/opencadstudio.ftl b/locales/ko-KR/opencadstudio.ftl index 6c3081482..1d4e4ef29 100644 --- a/locales/ko-KR/opencadstudio.ftl +++ b/locales/ko-KR/opencadstudio.ftl @@ -5927,8 +5927,6 @@ style-manager = .block-extents = 블록 범위 .base-point = 기준점 count-feature = - .palette = Count - .menu = Count .selection = Count Selection .review = Review Count Details .insert-field = Insert Count Field @@ -5951,3 +5949,18 @@ count-feature = .invalid-continue = Continue and count the entire model space .invalid-continue-detail = The count area is dropped; counting goes on in all of model space. .invalid-always = Always perform my current choice + .found = __ocs_fmt_0__개 찾음 + .found-total = __ocs_fmt_0__개 찾음, 총 __ocs_fmt_1__개 + .field-only-in-count = ** COUNTFIELD 명령은 개수 세기 중에만 사용할 수 있습니다. ** + .area-active = 개수 영역이 활성화되었습니다. + .read-only-value = __ocs_fmt_0__ = __ocs_fmt_1__ (읽기 전용) + .requires-0-or-1 = 0 또는 1만 입력할 수 있습니다. + .requires-int-range = __ocs_fmt_0__에서 __ocs_fmt_1__ 사이의 정수가 필요합니다. + .target-count = __ocs_fmt_0__ ...... __ocs_fmt_1__ + .mtext-current-style = MTEXT 현재 문자 스타일: "__ocs_fmt_0__" 문자 높이: __ocs_fmt_1__ + .fields-found = 필드 __ocs_fmt_0__개를 찾았습니다. + .fields-updated = 필드 __ocs_fmt_0__개를 업데이트했습니다. + .invalid-keyword = 옵션 키워드가 잘못되었습니다. + .invalid-boundary = 개수 영역 경계 객체가 잘못되었습니다. 선분으로 구성되고 자체 교차하지 않는 닫힌 폴리선을 선택하십시오. + .block-not-found = 블록 "__ocs_fmt_0__"을(를) 찾을 수 없습니다. + .invalid-point = 점이 잘못되었습니다. diff --git a/locales/nl-NL/opencadstudio.ftl b/locales/nl-NL/opencadstudio.ftl index c3fb6b01e..8a7b29a64 100644 --- a/locales/nl-NL/opencadstudio.ftl +++ b/locales/nl-NL/opencadstudio.ftl @@ -5926,8 +5926,6 @@ style-manager = .block-extents = Symboolgrenzen .base-point = Basispunt count-feature = - .palette = Count - .menu = Count .selection = Count Selection .review = Review Count Details .insert-field = Insert Count Field @@ -5950,3 +5948,18 @@ count-feature = .invalid-continue = Continue and count the entire model space .invalid-continue-detail = The count area is dropped; counting goes on in all of model space. .invalid-always = Always perform my current choice + .found = __ocs_fmt_0__ gevonden + .found-total = __ocs_fmt_0__ gevonden, __ocs_fmt_1__ totaal + .field-only-in-count = ** De opdracht COUNTFIELD is alleen beschikbaar tijdens het tellen. ** + .area-active = Telgebied is actief. + .read-only-value = __ocs_fmt_0__ = __ocs_fmt_1__ (alleen-lezen) + .requires-0-or-1 = Alleen 0 of 1 toegestaan. + .requires-int-range = Vereist een geheel getal tussen __ocs_fmt_0__ en __ocs_fmt_1__. + .target-count = __ocs_fmt_0__ ...... __ocs_fmt_1__ + .mtext-current-style = MTEXT Huidige tekststijl: "__ocs_fmt_0__" Teksthoogte: __ocs_fmt_1__ + .fields-found = __ocs_fmt_0__ veld(en) gevonden. + .fields-updated = __ocs_fmt_0__ veld(en) bijgewerkt. + .invalid-keyword = Ongeldig optiesleutelwoord. + .invalid-boundary = Ongeldig grensobject voor het telgebied. Selecteer een gesloten polylijn die uit lijnsegmenten bestaat en zichzelf niet snijdt. + .block-not-found = Blok "__ocs_fmt_0__" kan niet worden gevonden. + .invalid-point = Ongeldig punt. diff --git a/locales/pl-PL/opencadstudio.ftl b/locales/pl-PL/opencadstudio.ftl index 53ad2866a..b425dee41 100644 --- a/locales/pl-PL/opencadstudio.ftl +++ b/locales/pl-PL/opencadstudio.ftl @@ -5927,8 +5927,6 @@ style-manager = .block-extents = Zasięg bloku .base-point = Punkt bazowy count-feature = - .palette = Count - .menu = Count .selection = Count Selection .review = Review Count Details .insert-field = Insert Count Field @@ -5951,3 +5949,18 @@ count-feature = .invalid-continue = Continue and count the entire model space .invalid-continue-detail = The count area is dropped; counting goes on in all of model space. .invalid-always = Always perform my current choice + .found = Znaleziono: __ocs_fmt_0__ + .found-total = Znaleziono: __ocs_fmt_0__, łącznie: __ocs_fmt_1__ + .field-only-in-count = ** Polecenie COUNTFIELD jest dostępne tylko podczas liczenia. ** + .area-active = Obszar liczenia jest aktywny. + .read-only-value = __ocs_fmt_0__ = __ocs_fmt_1__ (tylko do odczytu) + .requires-0-or-1 = Wymaga wyłącznie 0 lub 1. + .requires-int-range = Wymaga liczby całkowitej z zakresu od __ocs_fmt_0__ do __ocs_fmt_1__. + .target-count = __ocs_fmt_0__ ...... __ocs_fmt_1__ + .mtext-current-style = MTEXT Bieżący styl tekstu: "__ocs_fmt_0__" Wysokość tekstu: __ocs_fmt_1__ + .fields-found = Znaleziono pól: __ocs_fmt_0__. + .fields-updated = Zaktualizowano pól: __ocs_fmt_0__. + .invalid-keyword = Nieprawidłowe słowo kluczowe opcji. + .invalid-boundary = Nieprawidłowy obiekt obwiedni obszaru liczenia. Wybierz zamkniętą polilinię złożoną z odcinków, która nie przecina samej siebie. + .block-not-found = Nie można znaleźć bloku "__ocs_fmt_0__". + .invalid-point = Nieprawidłowy punkt. diff --git a/locales/pt-BR/opencadstudio.ftl b/locales/pt-BR/opencadstudio.ftl index 6bfa83486..4f1c800b8 100644 --- a/locales/pt-BR/opencadstudio.ftl +++ b/locales/pt-BR/opencadstudio.ftl @@ -5928,8 +5928,6 @@ style-manager = .block-extents = Extensões do bloco .base-point = Ponto base count-feature = - .palette = Count - .menu = Count .selection = Count Selection .review = Review Count Details .insert-field = Insert Count Field @@ -5952,3 +5950,18 @@ count-feature = .invalid-continue = Continue and count the entire model space .invalid-continue-detail = The count area is dropped; counting goes on in all of model space. .invalid-always = Always perform my current choice + .found = __ocs_fmt_0__ encontrado(s) + .found-total = __ocs_fmt_0__ encontrado(s), __ocs_fmt_1__ no total + .field-only-in-count = ** O comando COUNTFIELD só está disponível durante a contagem. ** + .area-active = A área de contagem está ativa. + .read-only-value = __ocs_fmt_0__ = __ocs_fmt_1__ (somente leitura) + .requires-0-or-1 = Requer apenas 0 ou 1. + .requires-int-range = Requer um número inteiro entre __ocs_fmt_0__ e __ocs_fmt_1__. + .target-count = __ocs_fmt_0__ ...... __ocs_fmt_1__ + .mtext-current-style = MTEXT Estilo de texto atual: "__ocs_fmt_0__" Altura do texto: __ocs_fmt_1__ + .fields-found = __ocs_fmt_0__ campo(s) encontrado(s). + .fields-updated = __ocs_fmt_0__ campo(s) atualizado(s). + .invalid-keyword = Palavra-chave de opção inválida. + .invalid-boundary = Objeto de contorno da área de contagem inválido. Selecione uma polilinha fechada composta de segmentos de linha e que não se cruze. + .block-not-found = O bloco "__ocs_fmt_0__" não foi encontrado. + .invalid-point = Ponto inválido. diff --git a/locales/ru-RU/opencadstudio.ftl b/locales/ru-RU/opencadstudio.ftl index 6bffa6354..3c8c71a8e 100644 --- a/locales/ru-RU/opencadstudio.ftl +++ b/locales/ru-RU/opencadstudio.ftl @@ -5929,8 +5929,6 @@ style-manager = .block-extents = Габариты блока .base-point = Базовая точка count-feature = - .palette = Count - .menu = Count .selection = Count Selection .review = Review Count Details .insert-field = Insert Count Field @@ -5953,3 +5951,18 @@ count-feature = .invalid-continue = Continue and count the entire model space .invalid-continue-detail = The count area is dropped; counting goes on in all of model space. .invalid-always = Always perform my current choice + .found = Найдено: __ocs_fmt_0__ + .found-total = Найдено: __ocs_fmt_0__, всего: __ocs_fmt_1__ + .field-only-in-count = ** Команда COUNTFIELD доступна только в режиме подсчёта. ** + .area-active = Область подсчёта активна. + .read-only-value = __ocs_fmt_0__ = __ocs_fmt_1__ (только чтение) + .requires-0-or-1 = Допускается только 0 или 1. + .requires-int-range = Требуется целое число от __ocs_fmt_0__ до __ocs_fmt_1__. + .target-count = __ocs_fmt_0__ ...... __ocs_fmt_1__ + .mtext-current-style = MTEXT Текущий текстовый стиль: "__ocs_fmt_0__" Высота текста: __ocs_fmt_1__ + .fields-found = Найдено полей: __ocs_fmt_0__. + .fields-updated = Обновлено полей: __ocs_fmt_0__. + .invalid-keyword = Недопустимое ключевое слово параметра. + .invalid-boundary = Недопустимый объект границы области подсчёта. Выберите замкнутую полилинию из отрезков, которая не пересекает саму себя. + .block-not-found = Блок "__ocs_fmt_0__" не найден. + .invalid-point = Недопустимая точка. diff --git a/locales/tr-TR/opencadstudio.ftl b/locales/tr-TR/opencadstudio.ftl index 945dc938e..43908e04f 100644 --- a/locales/tr-TR/opencadstudio.ftl +++ b/locales/tr-TR/opencadstudio.ftl @@ -5851,8 +5851,6 @@ style-manager = .block-extents = Blok sınırları .base-point = Taban noktası count-feature = - .palette = Sayım - .menu = Say .selection = Seçimi say .review = Sayım ayrıntılarını incele .insert-field = Sayım alanı ekle @@ -5875,3 +5873,18 @@ count-feature = .invalid-continue = Devam et ve tüm model alanını say .invalid-continue-detail = Sayım alanı kalkar; sayım tüm model alanında sürer. .invalid-always = Geçerli seçimimi her zaman uygula + .found = __ocs_fmt_0__ bulundu + .found-total = __ocs_fmt_0__ bulundu, toplam __ocs_fmt_1__ + .field-only-in-count = ** COUNTFIELD komutu yalnızca sayım sırasında kullanılabilir. ** + .area-active = Sayım alanı etkin. + .read-only-value = __ocs_fmt_0__ = __ocs_fmt_1__ (salt okunur) + .requires-0-or-1 = Yalnızca 0 veya 1 girilebilir. + .requires-int-range = __ocs_fmt_0__ ile __ocs_fmt_1__ arasında bir tamsayı gerekir. + .target-count = __ocs_fmt_0__ ...... __ocs_fmt_1__ + .mtext-current-style = MTEXT Geçerli metin stili: "__ocs_fmt_0__" Metin yüksekliği: __ocs_fmt_1__ + .fields-found = __ocs_fmt_0__ alan bulundu. + .fields-updated = __ocs_fmt_0__ alan güncellendi. + .invalid-keyword = Geçersiz seçenek anahtar sözcüğü. + .invalid-boundary = Geçersiz sayım alanı sınır nesnesi. Doğru parçalarından oluşan, kendisiyle kesişmeyen kapalı bir çoklu çizgi seçin. + .block-not-found = "__ocs_fmt_0__" bloğu bulunamadı. + .invalid-point = Geçersiz nokta. diff --git a/locales/zh-CN/opencadstudio.ftl b/locales/zh-CN/opencadstudio.ftl index a9fdfa9bc..0249f7cfa 100644 --- a/locales/zh-CN/opencadstudio.ftl +++ b/locales/zh-CN/opencadstudio.ftl @@ -5911,8 +5911,6 @@ style-manager = .block-extents = 块范围 .base-point = 基点 count-feature = - .palette = Count - .menu = Count .selection = Count Selection .review = Review Count Details .insert-field = Insert Count Field @@ -5935,3 +5933,18 @@ count-feature = .invalid-continue = Continue and count the entire model space .invalid-continue-detail = The count area is dropped; counting goes on in all of model space. .invalid-always = Always perform my current choice + .found = 找到 __ocs_fmt_0__ 个 + .found-total = 找到 __ocs_fmt_0__ 个,总计 __ocs_fmt_1__ 个 + .field-only-in-count = ** COUNTFIELD 命令仅在计数期间可用。 ** + .area-active = 计数区域已激活。 + .read-only-value = __ocs_fmt_0__ = __ocs_fmt_1__(只读) + .requires-0-or-1 = 只能为 0 或 1。 + .requires-int-range = 需要介于 __ocs_fmt_0__ 和 __ocs_fmt_1__ 之间的整数。 + .target-count = __ocs_fmt_0__ ...... __ocs_fmt_1__ + .mtext-current-style = MTEXT 当前文字样式: "__ocs_fmt_0__" 文字高度: __ocs_fmt_1__ + .fields-found = 找到 __ocs_fmt_0__ 个字段。 + .fields-updated = 已更新 __ocs_fmt_0__ 个字段。 + .invalid-keyword = 无效的选项关键字。 + .invalid-boundary = 无效的计数区域边界对象。请选择由直线段组成且不自交的闭合多段线。 + .block-not-found = 找不到块 "__ocs_fmt_0__"。 + .invalid-point = 无效的点。 diff --git a/locales/zh-TW/opencadstudio.ftl b/locales/zh-TW/opencadstudio.ftl index ec8dffc8b..354f9442d 100644 --- a/locales/zh-TW/opencadstudio.ftl +++ b/locales/zh-TW/opencadstudio.ftl @@ -5923,8 +5923,6 @@ style-manager = .block-extents = 圖塊範圍 .base-point = 基點 count-feature = - .palette = Count - .menu = Count .selection = Count Selection .review = Review Count Details .insert-field = Insert Count Field @@ -5947,3 +5945,18 @@ count-feature = .invalid-continue = Continue and count the entire model space .invalid-continue-detail = The count area is dropped; counting goes on in all of model space. .invalid-always = Always perform my current choice + .found = 找到 __ocs_fmt_0__ 個 + .found-total = 找到 __ocs_fmt_0__ 個,總計 __ocs_fmt_1__ 個 + .field-only-in-count = ** COUNTFIELD 指令僅在計數期間可用。 ** + .area-active = 計數區域已啟用。 + .read-only-value = __ocs_fmt_0__ = __ocs_fmt_1__(唯讀) + .requires-0-or-1 = 只能為 0 或 1。 + .requires-int-range = 需要介於 __ocs_fmt_0__ 與 __ocs_fmt_1__ 之間的整數。 + .target-count = __ocs_fmt_0__ ...... __ocs_fmt_1__ + .mtext-current-style = MTEXT 目前文字型式: "__ocs_fmt_0__" 文字高度: __ocs_fmt_1__ + .fields-found = 找到 __ocs_fmt_0__ 個欄位。 + .fields-updated = 已更新 __ocs_fmt_0__ 個欄位。 + .invalid-keyword = 無效的選項關鍵字。 + .invalid-boundary = 無效的計數區域邊界物件。請選取由線段組成且不自我相交的封閉聚合線。 + .block-not-found = 找不到圖塊 "__ocs_fmt_0__"。 + .invalid-point = 無效的點。 diff --git a/src/app/command_driver/viewport.rs b/src/app/command_driver/viewport.rs index 35ceafa46..f8eadd485 100644 --- a/src/app/command_driver/viewport.rs +++ b/src/app/command_driver/viewport.rs @@ -418,7 +418,7 @@ impl OpenCADStudio { } } - pub(super) fn handle_zoom_to_window(&mut self, p1: glam::DVec3, p2: glam::DVec3) { + pub(in crate::app) fn handle_zoom_to_window(&mut self, p1: glam::DVec3, p2: glam::DVec3) { let i = self.active_tab; self.tabs[i].active_cmd = None; self.tabs[i].snap_result = None; diff --git a/src/app/commands/count.rs b/src/app/commands/count.rs index d10041a43..06e7f90ea 100644 --- a/src/app/commands/count.rs +++ b/src/app/commands/count.rs @@ -59,7 +59,8 @@ impl OpenCADStudio { let current = matches!(rest.trim_start_matches('_').to_ascii_uppercase().as_str(), "C"); if current && !preselected.is_empty() { // Count Selection: the selection is the target. - self.command_line.push_output(&format!("{} found", preselected.len())); + let found = preselected.len(); + self.command_line.push_output(&crate::tf!("{found} found")); let handles: Vec = preselected.iter().map(|h| hex(*h)).collect(); self.tabs[i].scene.deselect_all(); return Some(self.dispatch_command(&format!("_COUNTRUN C T {}", handles.join(",")))); @@ -67,9 +68,9 @@ impl OpenCADStudio { // Plain COUNT asks for its targets itself. self.tabs[i].scene.deselect_all(); let command = if current { CountCommand::with_area("C") } else { CountCommand::new(false) }; - Some(self.start_count_command(i, Box::new(command), "COUNT")) + Some(self.start_count_command(i, Box::new(command))) } - "COUNTAREA" => Some(self.start_count_command(i, Box::new(CountCommand::new(true)), "COUNTAREA")), + "COUNTAREA" => Some(self.start_count_command(i, Box::new(CountCommand::new(true)))), "COUNTCLOSE" => { self.close_count(i); Some(Task::none()) @@ -91,7 +92,9 @@ impl OpenCADStudio { match self.count_field_code(i) { Some(code) => return Some(self.start_count_field(i, code)), None if self.tabs[i].count.is_some() => {} - None => self.command_line.push_error("** COUNTFIELD command only available during Count. **"), + None => self + .command_line + .push_error(&crate::t!("** COUNTFIELD command only available during Count. **")), } Some(Task::none()) } @@ -115,7 +118,7 @@ impl OpenCADStudio { } } blocks.sort_by_key(|b| b.to_ascii_uppercase()); - Some(self.start_count_command(i, Box::new(CountTableCommand::new(blocks, others)), "COUNTTABLE")) + Some(self.start_count_command(i, Box::new(CountTableCommand::new(blocks, others)))) } "UPDATEFIELD" => { let preselected = self.tabs[i].scene.selected_handles_in_order(); @@ -123,7 +126,7 @@ impl OpenCADStudio { self.update_fields(i, &preselected); return Some(Task::none()); } - Some(self.start_count_command(i, Box::new(UpdateFieldCommand::new()), "UPDATEFIELD")) + Some(self.start_count_command(i, Box::new(UpdateFieldCommand::new()))) } "_UPDATEFIELDRUN" => { let handles: Vec = rest.split(',').filter_map(parse_handle).collect(); @@ -147,7 +150,7 @@ impl OpenCADStudio { mode.cursor = None; self.tabs[i].count = Some(mode); self.apply_count_display(i); - self.command_line.push_output("count area is active."); + self.command_line.push_output(&crate::t!("count area is active.")); } Some(Task::none()) } @@ -164,7 +167,7 @@ impl OpenCADStudio { } } - fn start_count_command(&mut self, i: usize, command: Box, _name: &str) -> Task { + fn start_count_command(&mut self, i: usize, command: Box) -> Task { self.reset_command_start_state(i); self.command_line.push_info(&command.prompt()); self.tabs[i].active_cmd = Some(command); @@ -190,7 +193,7 @@ impl OpenCADStudio { _ => None, }; if let Some(v) = read_only { - self.command_line.push_output(&format!("{name} = {v} (read only)")); + self.command_line.push_output(&crate::tf!("{name} = {v} (read only)")); return; } let (current, min, max) = match name { @@ -199,7 +202,7 @@ impl OpenCADStudio { _ => (self.count_palette.error_color as i32, 1, 255), }; let ask = |app: &mut Self| { - app.command_line.push_output(&format!("Enter new value for {name} <{current}>:")); + app.command_line.push_output(&crate::tf!("Enter new value for {name} <{current}>:")); app.pending_setvar = Some(name.to_string()); }; let Some(value) = value else { @@ -218,9 +221,9 @@ impl OpenCADStudio { } _ => { self.command_line.push_error(&if max == 1 { - "Requires 0 or 1 only.".to_string() + crate::t!("Requires 0 or 1 only.") } else { - format!("Requires an integer between {min} and {max}.") + crate::tf!("Requires an integer between {min} and {max}.") }); ask(self); } @@ -252,8 +255,8 @@ impl OpenCADStudio { let display = self.tabs[i].count.as_ref().filter(|m| m.target.is_some()).map(|m| { let r = m.result(&self.tabs[i].scene.document); crate::scene::CountDisplay { - counted: r.counted.into_iter().collect(), - errors: r.errors.into_iter().chain(r.overlapped).collect(), + counted: r.counted.iter().copied().collect(), + errors: r.errors.iter().chain(&r.overlapped).copied().collect(), color: aci_rgba(self.count_palette.color), error_color: aci_rgba(self.count_palette.error_color), } @@ -303,10 +306,35 @@ impl OpenCADStudio { } /// Invalid Area › Undo (also ✕ and Cancel): the change that took the - /// boundary away is undone. + /// boundary away is reverted — redone when an undo took it, undone + /// otherwise. When that does not bring the boundary back, the history + /// step is put back and the area is dropped as with Continue. fn count_invalid_undo(&mut self, i: usize) { - self.undo_active_tab(); - self.apply_count_display(i); + let Some((boundary, _)) = self.tabs[i].count.as_ref().and_then(|m| m.boundary) else { + return; + }; + // An open step (the edit that just erased the boundary) goes on the + // undo stack first; after that, something to redo means the last + // history step was an undo. + self.finish_pending_history(i); + let redo = !self.tabs[i].history.redo_stack.is_empty(); + if redo || !self.tabs[i].history.undo_stack.is_empty() { + if redo { + self.redo_active_tab(); + } else { + self.undo_active_tab(); + } + if self.tabs[i].scene.document.get_entity(boundary).is_some() { + self.apply_count_display(i); + return; + } + if redo { + self.undo_active_tab(); + } else { + self.redo_active_tab(); + } + } + self.count_invalid_continue(i); } /// Invalid Area › Continue: the area goes, the count covers all of model space. @@ -341,8 +369,10 @@ impl OpenCADStudio { if let Some((h, true)) = boundary { let doc = &self.tabs[i].scene.document; if doc.get_entity(h).is_some() && !boundary_in_use(doc, h) { - self.push_undo_snapshot(i, "COUNT"); - // The area layer is locked; count mode removes its own polyline. + // Count mode removes its own polyline (the area layer is + // locked) outside the history: an open step must not take the + // removal in, or undoing it would bring back an orphan area. + self.finish_pending_history(i); self.tabs[i].scene.rollback_new_entities(&[h]); self.tabs[i].dirty = true; } @@ -465,7 +495,7 @@ impl OpenCADStudio { let mode = CountMode { area, boundary, target, ..CountMode::default() }; if let Some(name) = mode.target_name() { let n = mode.count(&self.tabs[i].scene.document); - self.command_line.push_output(&format!("{name} ...... {n}")); + self.command_line.push_output(&crate::tf!("{name} ...... {n}")); } self.tabs[i].count = Some(mode); self.apply_count_display(i); @@ -503,38 +533,44 @@ impl OpenCADStudio { let doc = &self.tabs[i].scene.document; let value = crate::entities::field::evaluate(doc, &code, &[], None).unwrap_or_else(|| "####".into()); let defaults = crate::scene::creation_style::current_text_defaults(doc); - self.command_line.push_output(&format!( + self.command_line.push_output(&crate::tf!( "MTEXT Current text style: \"{}\" Text height: {:.4}", defaults.style_name, defaults.height )); let command = FieldPlaceCommand::new(value, (code, Vec::new()), defaults.style_name, defaults.height).named("MTEXT"); - self.start_count_command(i, Box::new(command), "COUNTFIELD") + self.start_count_command(i, Box::new(command)) } /// UPDATEFIELD: every field the objects host is evaluated again and its - /// text written back. + /// text written back. A table's fields are hosted by the cell texts of its + /// drawing (its `*T` block); fields a table keeps without such a text are + /// evaluated when drawn and are not counted here. fn update_fields(&mut self, i: usize, handles: &[Handle]) { let doc = &self.tabs[i].scene.document; - let mut updates: Vec<(Handle, String)> = Vec::new(); let mut found = 0; + let mut updates: Vec<(Handle, String)> = Vec::new(); for h in handles { let Some(entity) = doc.get_entity(*h) else { continue }; - if matches!(entity, EntityType::Table(_)) { - // Table cells evaluate their fields when drawn. - if let EntityType::Table(t) = entity { - found += t.field_handles.len(); + let hosts: Vec = match entity { + EntityType::Table(t) => t + .block_record_handle + .and_then(|r| doc.block_records.iter().find(|b| b.handle == r)) + .or_else(|| doc.block_records.get(&t.block_name).filter(|_| !t.block_name.is_empty())) + .map(|record| record.entity_handles.clone()) + .unwrap_or_default(), + _ => vec![*h], + }; + for host in hosts { + if !doc.get_entity(host).is_some_and(|e| crate::entities::field::hosts_field(doc, e)) { + continue; + } + found += 1; + if let Some(text) = crate::entities::field::resolve(doc, host) { + updates.push((host, text)); } - continue; - } - if !crate::entities::field::hosts_field(doc, entity) { - continue; - } - found += 1; - if let Some(text) = crate::entities::field::resolve(doc, *h) { - updates.push((*h, text)); } } - self.command_line.push_output(&format!("{found} field(s) found.")); + self.command_line.push_output(&crate::tf!("{found} field(s) found.")); if found == 0 { return; } @@ -551,15 +587,16 @@ impl OpenCADStudio { changed.push((h, crate::scene::ChangeKind::Modified)); } } - let table_handles: Vec<(Handle, crate::scene::ChangeKind)> = handles - .iter() - .filter(|h| matches!(self.tabs[i].scene.document.get_entity(**h), Some(EntityType::Table(_)))) - .map(|h| (*h, crate::scene::ChangeKind::Modified)) - .collect(); - changed.extend(table_handles); - self.tabs[i].scene.bump_entities(&changed); + let updated = changed.len(); + // Table cell texts live in a block definition. + let scene = &mut self.tabs[i].scene; + if scene.changes_touch_block_definition(&changed) { + scene.bump_geometry(); + } else { + scene.bump_entities(&changed); + } self.tabs[i].dirty = true; - self.command_line.push_output(&format!("{found} field(s) updated.")); + self.command_line.push_output(&crate::tf!("{updated} field(s) updated.")); } /// A count table at `point`: `Item` | `Count`, one row per block (all @@ -652,15 +689,14 @@ impl OpenCADStudio { if outline.is_empty() { return; } - let (mut lo, mut hi) = (glam::Vec3::splat(f32::MAX), glam::Vec3::splat(f32::MIN)); + let (mut lo, mut hi) = (glam::DVec3::splat(f64::MAX), glam::DVec3::splat(f64::MIN)); for c in outline.iter().flat_map(codec::count::Piece::points) { - let p = glam::Vec3::new(c.x as f32, c.y as f32, c.z as f32); + let p = glam::DVec3::new(c.x, c.y, c.z); lo = lo.min(p); hi = hi.max(p); } let pad = (hi - lo) * 1.5; - self.tabs[i].scene.remember_current_view(); - self.tabs[i].scene.zoom_to_window(lo - pad, hi + pad); + self.handle_zoom_to_window(lo - pad, hi + pad); } fn open_count_target(&mut self, i: usize, name: String, key: CountKey) { @@ -773,7 +809,7 @@ impl OpenCADStudio { if names.is_empty() { return Task::none(); } - return self.start_count_command(i, Box::new(CountTableCommand::placing(names)), "COUNTTABLE"); + return self.start_count_command(i, Box::new(CountTableCommand::placing(names))); } CountMsg::Back | CountMsg::Close => self.close_count(i), CountMsg::Match(k, on) => { @@ -787,27 +823,28 @@ impl OpenCADStudio { CountMsg::ShowError(h) => self.zoom_to_insert(i, h), CountMsg::Prev | CountMsg::Next => { let Some(mode) = self.tabs[i].count.as_ref() else { return Task::none() }; - let counted = mode.result(&self.tabs[i].scene.document).counted; - if counted.is_empty() { + let result = mode.result(&self.tabs[i].scene.document); + let n = result.counted.len(); + if n == 0 { return Task::none(); } - let n = counted.len(); let next = match (mode.cursor, matches!(m, CountMsg::Next)) { (None, true) => 0, (None, false) => n - 1, (Some(c), true) => (c + 1) % n, (Some(c), false) => (c + n - 1) % n, }; + let target = result.counted[next]; if let Some(mode) = self.tabs[i].count.as_mut() { mode.cursor = Some(next); } - self.zoom_to_insert(i, counted[next]); + self.zoom_to_insert(i, target); } CountMsg::Area => return self.dispatch_command("COUNTAREA"), CountMsg::Select => { self.tabs[i].scene.deselect_all(); let command = CountCommand::with_area(if self.tabs[i].count.is_some() { "K" } else { "C" }); - return self.start_count_command(i, Box::new(command), "COUNT"); + return self.start_count_command(i, Box::new(command)); } CountMsg::Field => return self.dispatch_command("COUNTFIELD"), CountMsg::InvalidAlways(v) => self.count_palette.invalid_always = v, diff --git a/src/app/control/actions.rs b/src/app/control/actions.rs index 8d63e0176..974939311 100644 --- a/src/app/control/actions.rs +++ b/src/app/control/actions.rs @@ -926,8 +926,6 @@ impl OpenCADStudio { }; Message::PcManager(PcManagerMsg::Toggle(handle, row)) } - // Point Cloud Manager tree: "search=", "collapse", "expand", - // "toggle_node=" or "select=". // Count palette and count mode: "search=", "sort=name|count", // "open=NAME", "child=NAME:" (an expanded row), "menu=:NAME", "create_table", "check=NAME:1", @@ -1000,6 +998,8 @@ impl OpenCADStudio { _ => return Err(bad()), }) } + // Point Cloud Manager tree: "search=", "collapse", "expand", + // "toggle_node=" or "select=". "pc_manager" => { use crate::ui::window::pc_manager::PcManagerMsg as M; let value = string(req, "value")?; diff --git a/src/app/view/mod.rs b/src/app/view/mod.rs index 7a0af5777..021102307 100644 --- a/src/app/view/mod.rs +++ b/src/app/view/mod.rs @@ -3034,6 +3034,7 @@ impl OpenCADStudio { &self.count_palette, tab.count.as_ref(), &tab.scene.document, + tab.id, tab.scene.geometry_epoch, width, auto_collapse, diff --git a/src/locale_catalog.rs b/src/locale_catalog.rs index 40758aea5..f657dec83 100644 --- a/src/locale_catalog.rs +++ b/src/locale_catalog.rs @@ -5530,8 +5530,6 @@ 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")), - "Count palette" => Some(("count-feature", "palette")), - "Count menu" => Some(("count-feature", "menu")), "Count Selection" => Some(("count-feature", "selection")), "Review Count Details" => Some(("count-feature", "review")), "Insert Count Field" => Some(("count-feature", "insert-field")), @@ -5554,6 +5552,21 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static "Continue and count the entire model space" => Some(("count-feature", "invalid-continue")), "The count area is dropped; counting goes on in all of model space." => Some(("count-feature", "invalid-continue-detail")), "Always perform my current choice" => Some(("count-feature", "invalid-always")), + "{found} found" => Some(("count-feature", "found")), + "{found} found, {total} total" => Some(("count-feature", "found-total")), + "** COUNTFIELD command only available during Count. **" => Some(("count-feature", "field-only-in-count")), + "count area is active." => Some(("count-feature", "area-active")), + "{name} = {v} (read only)" => Some(("count-feature", "read-only-value")), + "Requires 0 or 1 only." => Some(("count-feature", "requires-0-or-1")), + "Requires an integer between {min} and {max}." => Some(("count-feature", "requires-int-range")), + "{name} ...... {n}" => Some(("count-feature", "target-count")), + "MTEXT Current text style: \"{}\" Text height: {:.4}" => Some(("count-feature", "mtext-current-style")), + "{found} field(s) found." => Some(("count-feature", "fields-found")), + "{updated} field(s) updated." => Some(("count-feature", "fields-updated")), + "Invalid option keyword." => Some(("count-feature", "invalid-keyword")), + "Invalid count area boundary object. Select a closed polyline consisting of line segments and does not intersect itself." => Some(("count-feature", "invalid-boundary")), + "Block \"{part}\" cannot be found." => Some(("count-feature", "block-not-found")), + "Invalid point." => Some(("count-feature", "invalid-point")), _ => None, } } diff --git a/src/modules/annotate/count_cmd.rs b/src/modules/annotate/count_cmd.rs index f2be96126..9ac6c3d3f 100644 --- a/src/modules/annotate/count_cmd.rs +++ b/src/modules/annotate/count_cmd.rs @@ -9,8 +9,8 @@ // // The command gathers its answers and hands them to the application as // `_COUNTRUN L|T ` (COUNTAREA: `_COUNTAREASET `), the -// area being `C` (current view), `E` (entire model space), `R x,y x,y`, -// `P x,y x,y …` or `O `. +// area being `C` (current area, which counts all of model space), `E` +// (entire model space), `R x,y x,y`, `P x,y x,y …` or `O `. use codec::types::Handle; use codec::EntityType; @@ -82,7 +82,7 @@ impl CountCommand { self.step = Step::PolyStart; CmdResult::NeedPoint } - _ => CmdResult::ReportError("Invalid option keyword.".into()), + _ => CmdResult::ReportError(crate::t!("Invalid option keyword.").into_owned()), } } @@ -150,10 +150,11 @@ impl CadCommand for CountCommand { let found = handles.iter().filter(|h| !self.targets.contains(h)).count(); let first = self.targets.is_empty(); self.targets = handles; + let total = self.targets.len(); CmdResult::ReportMeasurement(if first { - format!("{found} found") + crate::tf!("{found} found").into_owned() } else { - format!("{found} found, {} total", self.targets.len()) + crate::tf!("{found} found, {total} total").into_owned() }) } @@ -175,8 +176,10 @@ impl CadCommand for CountCommand { self.area_done(format!("O {:X}", handle.value())) } _ => CmdResult::CancelWithMessage( - "Invalid count area boundary object. Select a closed polyline consisting of line segments and does not intersect itself." - .into(), + crate::t!( + "Invalid count area boundary object. Select a closed polyline consisting of line segments and does not intersect itself." + ) + .into_owned(), ), } } @@ -298,18 +301,11 @@ impl CountTableCommand { let page: Vec = self.pending.drain(..self.pending.len().min(22)).collect(); if !self.pending.is_empty() { self.step = TableStep::Page; - return CmdResult::ReportMeasurement(page.join(" -")); + return CmdResult::ReportMeasurement(page.join("\n")); } CmdResult::Measurement(format!( - "{} - -User External Dependent Unnamed -Blocks References Blocks Blocks -{:>5}{:>10}{:>12}{:>12} -", - page.join(" -"), + "{}\n\nUser External Dependent Unnamed\nBlocks References Blocks Blocks\n{:>5}{:>10}{:>12}{:>12}\n", + page.join("\n"), self.blocks.len(), self.others[0], self.others[1], @@ -371,7 +367,11 @@ impl CadCommand for CountTableCommand { for part in text.split(',').map(str::trim).filter(|p| !p.is_empty()) { match self.blocks.iter().find(|b| b.eq_ignore_ascii_case(part)) { Some(b) => names.push(b.clone()), - None => return Some(CmdResult::CancelWithMessage(format!("Block \"{part}\" cannot be found."))), + None => { + return Some(CmdResult::CancelWithMessage( + crate::tf!("Block \"{part}\" cannot be found.").into_owned(), + )) + } } } self.names = names; @@ -393,7 +393,7 @@ impl CadCommand for CountTableCommand { fn on_enter(&mut self) -> CmdResult { match self.step { - TableStep::Point => CmdResult::ReportError("Invalid point.".into()), + TableStep::Point => CmdResult::ReportError(crate::t!("Invalid point.").into_owned()), _ => self.on_text_input("").unwrap_or(CmdResult::NeedPoint), } } diff --git a/src/modules/view/count_palette.rs b/src/modules/view/count_palette.rs index fd1d4e652..97321536f 100644 --- a/src/modules/view/count_palette.rs +++ b/src/modules/view/count_palette.rs @@ -4,7 +4,7 @@ pub const ICON: IconKind = IconKind::Svg(include_bytes!("../../../assets/icons/d pub fn tool() -> ToolDef { ToolDef { id: "COUNTLIST", - label: "Count palette", + label: "Count", icon: ICON, event: ModuleEvent::Command("_COUNTLISTTOGGLE".to_string()), } diff --git a/src/ui/icons.rs b/src/ui/icons.rs index 7a2385fb4..a2b5af4e7 100644 --- a/src/ui/icons.rs +++ b/src/ui/icons.rs @@ -83,6 +83,8 @@ pub static GEAR: &[u8] = include_bytes!("../../assets/icons/ui/gear.svg"); pub static DOT: &[u8] = include_bytes!("../../assets/icons/ui/dot.svg"); pub static DIRTY_DOT: &[u8] = include_bytes!("../../assets/icons/ui/dirty_dot.svg"); pub static ARROW_LONG_RIGHT: &[u8] = include_bytes!("../../assets/icons/ui/arrow_long_right.svg"); +pub static MORE: &[u8] = include_bytes!("../../assets/icons/ui/more.svg"); +pub static INFO: &[u8] = include_bytes!("../../assets/icons/ui/info.svg"); // ── Status-bar toggle icons (issue #216) ────────────────────────────────── pub static ST_ORTHO: &[u8] = include_bytes!("../../assets/icons/status/ortho.svg"); diff --git a/src/ui/popup/context_menu.rs b/src/ui/popup/context_menu.rs index 407aa66c2..595184c8d 100644 --- a/src/ui/popup/context_menu.rs +++ b/src/ui/popup/context_menu.rs @@ -726,7 +726,7 @@ fn idle_rows( rows.push(MenuRow::Item(if has_selection { cmd(t!("Count Selection").into_owned(), "COUNT _C") } else { - cmd(t!("Count menu").into_owned(), "COUNT") + cmd(t!("Count").into_owned(), "COUNT") })); rows.push(MenuRow::Separator); diff --git a/src/ui/window/count_palette.rs b/src/ui/window/count_palette.rs index 1f31eeb31..8f8e08d70 100644 --- a/src/ui/window/count_palette.rs +++ b/src/ui/window/count_palette.rs @@ -82,10 +82,11 @@ impl CountMode { } } - pub fn result(&self, doc: &CadDocument) -> CountResult { + /// The cached result, or one worked out from the drawing when there is none. + pub fn result(&self, doc: &CadDocument) -> std::borrow::Cow<'_, CountResult> { match &self.cache { - Some((result, _)) => result.clone(), - None => self.compute(doc).0, + Some((result, _)) => std::borrow::Cow::Borrowed(result), + None => std::borrow::Cow::Owned(self.compute(doc).0), } } @@ -158,8 +159,8 @@ pub struct CountPalette { /// What a lost count boundary does without asking: 0 ask, 1 undo, 2 go /// on with all of model space (kept with the user settings). pub invalid_choice: u8, - /// The list's references for (document, geometry epoch, area). - pub list_cache: std::cell::RefCell>, std::rc::Rc>)>>, + /// The list's references for (document tab id, geometry epoch, area). + pub list_cache: std::cell::RefCell>, std::rc::Rc>)>>, } impl Default for CountPalette { @@ -313,7 +314,7 @@ fn list_row<'a>( name: &str, key: CountKey, label: String, - count: String, + count: Option, errors: bool, depth: u16, expanded: Option, @@ -323,7 +324,7 @@ fn list_row<'a>( let n = name.to_string(); checkbox(on).size(14).on_toggle(move |v| msg(CountMsg::TableCheck(n.clone(), v))).into() } else if expanded == Some(true) { - container(text("−").size(13)).width(Length::Fixed(14.0)).into() + container(crate::ui::icons::themed(crate::ui::icons::MINUS, 12.0)).width(Length::Fixed(14.0)).into() } else { Space::new().width(Length::Fixed(14.0)).into() }; @@ -335,7 +336,11 @@ fn list_row<'a>( if errors { cells = cells.push(crate::ui::icons::themed_warning(WARNING_ICON, 12.0)); } - cells = cells.push(text(count).size(12)); + // An expanded row shows its counts on the rows below it. + cells = cells.push(match count { + Some(n) => Element::from(text(n.to_string()).size(12)), + None => crate::ui::icons::themed(crate::ui::icons::MORE, 12.0), + }); let body = container(cells.spacing(6).align_y(iced::Center)).width(Fill).padding([4, 6]); let area = mouse_area(body) .on_press(msg(CountMsg::Open(name.to_string(), key.clone()))) @@ -345,14 +350,11 @@ fn list_row<'a>( } fn header_button<'a>(label: String, active: bool, descending: bool, m: CountMsg) -> Element<'a, Message> { - let arrow = if !active { - "" - } else if descending { - " ▼" - } else { - " ▲" - }; - button(text(format!("{label}{arrow}")).size(11)) + let mut content = row![text(label).size(11)].spacing(3).align_y(iced::Center); + if active { + content = content.push(crate::ui::icons::themed_arrow_toggle(!descending, 8.0)); + } + button(content) .on_press(msg(m)) .style(button::text) .padding([2, 4]) @@ -385,7 +387,7 @@ fn list_view<'a>(palette: &'a CountPalette, instances: &[BlockInstance]) -> Elem let mut list = column![].spacing(1); for r in rows(instances, palette) { let expansion = palette.expansion(&r.name).filter(|e| e.iter().any(|v| *v)); - let count = if expansion.is_some() { "•••".to_string() } else { r.count.to_string() }; + let count = expansion.is_none().then_some(r.count); list = list.push(list_row( palette, &r.name, @@ -399,7 +401,7 @@ fn list_view<'a>(palette: &'a CountPalette, instances: &[BlockInstance]) -> Elem if let Some([l, s, m]) = expansion { for (key, n) in codec::count::expanded_counts(instances, &r.name, l, s, m) { let label = key.label(); - list = list.push(list_row(palette, &r.name, key, label, n.to_string(), false, 1, None)); + list = list.push(list_row(palette, &r.name, key, label, Some(n), false, 1, None)); } } } @@ -525,16 +527,17 @@ pub fn view<'a>( palette: &'a CountPalette, mode: Option<&'a CountMode>, doc: &'a CadDocument, + doc_id: u64, epoch: u64, width: f32, auto_collapse: bool, ) -> Element<'a, Message> { - let title_bar = crate::ui::dock::title_bar(PanelId::Count, crate::t!("Count palette").into_owned(), auto_collapse); + let title_bar = crate::ui::dock::title_bar(PanelId::Count, crate::t!("Count").into_owned(), auto_collapse); let body = match mode { Some(mode) if mode.target.is_some() => mode_view(palette, mode, doc), _ => { let area = mode.and_then(|m| m.area.clone()); - let key = (doc as *const CadDocument as usize, epoch); + let key = (doc_id, epoch); let mut cache = palette.list_cache.borrow_mut(); let instances = match cache.as_ref() { Some((d, e, a, list)) if (*d, *e) == key && *a == area => list.clone(), @@ -567,13 +570,7 @@ pub fn toolbar<'a>(mode: &CountMode, doc: &CadDocument) -> Element<'a, Message> let status: Element<'a, Message> = if !result.errors.is_empty() { crate::ui::icons::themed_warning(WARNING_ICON, 14.0) } else if has_target { - container(text("i").size(11).style(|theme: &Theme| text::Style { color: Some(theme.palette().primary.base.color) })) - .padding([0, 4]) - .style(|theme: &Theme| container::Style { - border: Border { color: theme.palette().primary.base.color, width: 1.0, radius: 8.0.into() }, - ..Default::default() - }) - .into() + crate::ui::icons::themed_primary(crate::ui::icons::INFO, 14.0) } else { crate::ui::icons::themed_disabled(WARNING_ICON, 14.0) }; @@ -628,7 +625,7 @@ pub fn invalid_area_view<'a>(palette: &CountPalette, sizing: crate::ui::modal::M let action = |title: String, detail: String, m: CountMsg| -> Element<'a, Message> { button( row![ - text("→").size(16).style(|theme: &Theme| text::Style { color: Some(theme.palette().primary.base.color) }), + crate::ui::icons::themed_primary(crate::ui::icons::ARROW_LONG_RIGHT, 16.0), column![text(title).size(13), text(detail).size(11).style(muted_style)].spacing(2), ] .spacing(10)