Merge pull request #1344 from HakanSeven12/plot/b3-psetupin

feat(plot): PSETUPIN, page-setup import and page setup for new layouts
This commit is contained in:
Hakan Seven committed 2026-09-19 22:59:36 +03:00
commit b1080e02ca
35 files changed
+786 -48

No files matched your search

+9
View File
@@ -5111,6 +5111,15 @@ plot =
.system-default-printer = طابعة النظام الافتراضية
.what-to-plot = ما المراد طباعته
.x-mm = X (مم)
.select-drawing-to-import-page-setups-from = اختر الرسم لاستيراد إعدادات الصفحة منه
.drawings-and-templates = الرسومات والقوالب
.psetupin-count-page-setup-s-imported-replaced-replaced = PSETUPIN: تم استيراد __ocs_fmt_0__ من إعدادات الصفحة، واستبدال __ocs_fmt_1__.
.psetupin-error = PSETUPIN: __ocs_fmt_0__
.psetupin-no-page-setup-named-want-in-file = PSETUPIN: لا يوجد إعداد صفحة باسم "__ocs_fmt_0__" في __ocs_fmt_1__.
.psetupin-nothing-to-import-from-file = PSETUPIN: لا يوجد ما يمكن استيراده من __ocs_fmt_0__.
.no-named-page-setups-in-this-drawing = لا توجد إعدادات صفحة مسماة في هذا الرسم.
.import-ellipsis = استيراد…
.show-the-page-setup-for-new-layouts = إظهار إعداد الصفحة للتخطيطات الجديدة
.x-in = X (بوصة)
.y-in = Y (بوصة)
.hide-paperspace-objects = إخفاء كائنات مساحة الورق
+9
View File
@@ -5099,6 +5099,15 @@ plot =
.system-default-printer = Системен принтер по подразбиране
.what-to-plot = Какво да се плотира
.x-mm = X (мм)
.select-drawing-to-import-page-setups-from = Изберете чертеж, от който да се импортират настройките на страницата
.drawings-and-templates = Чертежи и шаблони
.psetupin-count-page-setup-s-imported-replaced-replaced = PSETUPIN: импортирани __ocs_fmt_0__ настройки на страницата, __ocs_fmt_1__ заменени.
.psetupin-error = PSETUPIN: __ocs_fmt_0__
.psetupin-no-page-setup-named-want-in-file = PSETUPIN: няма настройка на страницата с име „__ocs_fmt_0__“ в __ocs_fmt_1__.
.psetupin-nothing-to-import-from-file = PSETUPIN: няма нищо за импортиране от __ocs_fmt_0__.
.no-named-page-setups-in-this-drawing = В този чертеж няма именувани настройки на страницата.
.import-ellipsis = Импортиране…
.show-the-page-setup-for-new-layouts = Показване на настройката на страницата за нови оформления
.x-in = X (инча)
.y-in = Y (инча)
.hide-paperspace-objects = Скриване на обектите в пространството на листа
+9
View File
@@ -5096,6 +5096,15 @@ plot =
.system-default-printer = Výchozí tiskárna systému
.what-to-plot = Co fabulovat
.x-mm = X (mm)
.select-drawing-to-import-page-setups-from = Vyberte výkres pro import nastavení stránky
.drawings-and-templates = Výkresy a šablony
.psetupin-count-page-setup-s-imported-replaced-replaced = PSETUPIN: importováno __ocs_fmt_0__ nastavení stránky, __ocs_fmt_1__ nahrazeno.
.psetupin-error = PSETUPIN: __ocs_fmt_0__
.psetupin-no-page-setup-named-want-in-file = PSETUPIN: žádné nastavení stránky s názvem „__ocs_fmt_0__“ v __ocs_fmt_1__.
.psetupin-nothing-to-import-from-file = PSETUPIN: z __ocs_fmt_0__ není co importovat.
.no-named-page-setups-in-this-drawing = V tomto výkresu nejsou pojmenovaná nastavení stránky.
.import-ellipsis = Importovat…
.show-the-page-setup-for-new-layouts = Zobrazit nastavení stránky pro nová rozvržení
.x-in = X (palce)
.y-in = Y (palce)
.hide-paperspace-objects = Skrýt objekty výkresového prostoru
+9
View File
@@ -5097,6 +5097,15 @@ plot =
.system-default-printer = Systemstandarddrucker
.what-to-plot = Was zu plotten
.x-mm = X (mm)
.select-drawing-to-import-page-setups-from = Zeichnung für den Seiteneinrichtungs-Import wählen
.drawings-and-templates = Zeichnungen und Vorlagen
.psetupin-count-page-setup-s-imported-replaced-replaced = PSETUPIN: __ocs_fmt_0__ Seiteneinrichtung(en) importiert, __ocs_fmt_1__ ersetzt.
.psetupin-error = PSETUPIN: __ocs_fmt_0__
.psetupin-no-page-setup-named-want-in-file = PSETUPIN: keine Seiteneinrichtung namens „__ocs_fmt_0__“ in __ocs_fmt_1__.
.psetupin-nothing-to-import-from-file = PSETUPIN: nichts zu importieren aus __ocs_fmt_0__.
.no-named-page-setups-in-this-drawing = Keine benannten Seiteneinrichtungen in dieser Zeichnung.
.import-ellipsis = Importieren…
.show-the-page-setup-for-new-layouts = Seiteneinrichtung für neue Layouts anzeigen
.x-in = X (Zoll)
.y-in = Y (Zoll)
.hide-paperspace-objects = Papierbereichsobjekte ausblenden
+9
View File
@@ -5099,6 +5099,15 @@ plot =
.system-default-printer = Προεπιλεγμένος εκτυπωτής συστήματος
.what-to-plot = Τι θα εκτυπωθεί
.x-mm = X (mm)
.select-drawing-to-import-page-setups-from = Επιλογή σχεδίου για εισαγωγή page setups
.drawings-and-templates = Σχέδια και πρότυπα
.psetupin-count-page-setup-s-imported-replaced-replaced = PSETUPIN: εισήχθησαν __ocs_fmt_0__ page setup(s), __ocs_fmt_1__ αντικαταστάθηκαν.
.psetupin-error = PSETUPIN: __ocs_fmt_0__
.psetupin-no-page-setup-named-want-in-file = PSETUPIN: δεν υπάρχει page setup με όνομα «__ocs_fmt_0__» στο __ocs_fmt_1__.
.psetupin-nothing-to-import-from-file = PSETUPIN: τίποτα προς εισαγωγή από το __ocs_fmt_0__.
.no-named-page-setups-in-this-drawing = Δεν υπάρχουν επώνυμα page setups σε αυτό το σχέδιο.
.import-ellipsis = Εισαγωγή…
.show-the-page-setup-for-new-layouts = Εμφάνιση του page setup για νέα layouts
.x-in = X (in)
.y-in = Y (in)
.hide-paperspace-objects = Απόκρυψη αντικειμένων χώρου χαρτιού
+9
View File
@@ -5100,6 +5100,15 @@ plot =
.system-default-printer = System default printer
.what-to-plot = What to plot
.x-mm = X (mm)
.select-drawing-to-import-page-setups-from = Select Drawing to Import Page Setups From
.drawings-and-templates = Drawings and templates
.psetupin-count-page-setup-s-imported-replaced-replaced = PSETUPIN: __ocs_fmt_0__ page setup(s) imported, __ocs_fmt_1__ replaced.
.psetupin-error = PSETUPIN: __ocs_fmt_0__
.psetupin-no-page-setup-named-want-in-file = PSETUPIN: no page setup named "__ocs_fmt_0__" in __ocs_fmt_1__.
.psetupin-nothing-to-import-from-file = PSETUPIN: nothing to import from __ocs_fmt_0__.
.no-named-page-setups-in-this-drawing = No named page setups in this drawing.
.import-ellipsis = Import…
.show-the-page-setup-for-new-layouts = Show the page setup for new layouts
.x-in = X (in)
.y-in = Y (in)
.hide-paperspace-objects = Hide paperspace objects
+9
View File
@@ -5099,6 +5099,15 @@ plot =
.system-default-printer = Impresora predeterminada del sistema
.what-to-plot = Qué trazar
.x-mm = X (mm)
.select-drawing-to-import-page-setups-from = Seleccionar dibujo del que importar configuraciones de página
.drawings-and-templates = Dibujos y plantillas
.psetupin-count-page-setup-s-imported-replaced-replaced = PSETUPIN: __ocs_fmt_0__ configuración(es) de página importada(s), __ocs_fmt_1__ reemplazada(s).
.psetupin-error = PSETUPIN: __ocs_fmt_0__
.psetupin-no-page-setup-named-want-in-file = PSETUPIN: no hay ninguna configuración de página llamada "__ocs_fmt_0__" en __ocs_fmt_1__.
.psetupin-nothing-to-import-from-file = PSETUPIN: nada que importar de __ocs_fmt_0__.
.no-named-page-setups-in-this-drawing = No hay configuraciones de página con nombre en este dibujo.
.import-ellipsis = Importar…
.show-the-page-setup-for-new-layouts = Mostrar la configuración de página para las presentaciones nuevas
.x-in = X (pulg)
.y-in = Y (pulg)
.hide-paperspace-objects = Ocultar objetos del espacio papel
+9
View File
@@ -5098,6 +5098,15 @@ plot =
.system-default-printer = Järjestelmän oletustulostin
.what-to-plot = Mitä piirtää
.x-mm = X (mm)
.select-drawing-to-import-page-setups-from = Valitse piirustus, josta sivuasetukset tuodaan
.drawings-and-templates = Piirustukset ja mallipohjat
.psetupin-count-page-setup-s-imported-replaced-replaced = PSETUPIN: __ocs_fmt_0__ sivuasetusta tuotu, __ocs_fmt_1__ korvattu.
.psetupin-error = PSETUPIN: __ocs_fmt_0__
.psetupin-no-page-setup-named-want-in-file = PSETUPIN: sivuasetusta "__ocs_fmt_0__" ei ole tiedostossa __ocs_fmt_1__.
.psetupin-nothing-to-import-from-file = PSETUPIN: ei mitään tuotavaa tiedostosta __ocs_fmt_0__.
.no-named-page-setups-in-this-drawing = Tässä piirustuksessa ei ole nimettyjä sivuasetuksia.
.import-ellipsis = Tuo…
.show-the-page-setup-for-new-layouts = Näytä sivuasetus uusille asetteluille
.x-in = X (tuumaa)
.y-in = Y (tuumaa)
.hide-paperspace-objects = Piilota paperitilan objektit
+9
View File
@@ -5099,6 +5099,15 @@ plot =
.system-default-printer = Imprimante système par défaut
.what-to-plot = Quoi faire?
.x-mm = X (mm)
.select-drawing-to-import-page-setups-from = Sélectionner le dessin d'où importer les mises en page
.drawings-and-templates = Dessins et gabarits
.psetupin-count-page-setup-s-imported-replaced-replaced = PSETUPIN : __ocs_fmt_0__ mise(s) en page importée(s), __ocs_fmt_1__ remplacée(s).
.psetupin-error = PSETUPIN : __ocs_fmt_0__
.psetupin-no-page-setup-named-want-in-file = PSETUPIN : aucune mise en page nommée « __ocs_fmt_0__ » dans __ocs_fmt_1__.
.psetupin-nothing-to-import-from-file = PSETUPIN : rien à importer depuis __ocs_fmt_0__.
.no-named-page-setups-in-this-drawing = Aucune mise en page nommée dans ce dessin.
.import-ellipsis = Importer…
.show-the-page-setup-for-new-layouts = Afficher la mise en page pour les nouvelles présentations
.x-in = X (po)
.y-in = Y (po)
.hide-paperspace-objects = Masquer les objets de l'espace papier
+9
View File
@@ -5087,6 +5087,15 @@ plot =
.system-default-printer = सिस्टम डिफ़ॉल्ट प्रिंटर
.what-to-plot = क्या प्लॉट करना है
.x-mm = एक्स (मिमी)
.select-drawing-to-import-page-setups-from = पेज सेटअप आयात करने के लिए ड्रॉइंग चुनें
.drawings-and-templates = ड्रॉइंग और टेम्पलेट
.psetupin-count-page-setup-s-imported-replaced-replaced = PSETUPIN: __ocs_fmt_0__ पेज सेटअप आयात किए गए, __ocs_fmt_1__ बदले गए।
.psetupin-error = PSETUPIN: __ocs_fmt_0__
.psetupin-no-page-setup-named-want-in-file = PSETUPIN: __ocs_fmt_1__ में "__ocs_fmt_0__" नाम का कोई पेज सेटअप नहीं है।
.psetupin-nothing-to-import-from-file = PSETUPIN: __ocs_fmt_0__ से आयात करने के लिए कुछ नहीं है।
.no-named-page-setups-in-this-drawing = इस ड्रॉइंग में कोई नामित पेज सेटअप नहीं है।
.import-ellipsis = आयात करें…
.show-the-page-setup-for-new-layouts = नए लेआउट के लिए पेज सेटअप दिखाएँ
.x-in = एक्स (इंच)
.y-in = वाई (इंच)
.hide-paperspace-objects = पेपर स्पेस ऑब्जेक्ट छिपाएँ
+9
View File
@@ -5098,6 +5098,15 @@ plot =
.system-default-printer = Rendszer alapértelmezett nyomtató
.what-to-plot = Mit kell kitalálni
.x-mm = X (mm)
.select-drawing-to-import-page-setups-from = Válassza ki a rajzot, amelyből oldalbeállításokat importál
.drawings-and-templates = Rajzok és sablonok
.psetupin-count-page-setup-s-imported-replaced-replaced = PSETUPIN: __ocs_fmt_0__ oldalbeállítás importálva, __ocs_fmt_1__ lecserélve.
.psetupin-error = PSETUPIN: __ocs_fmt_0__
.psetupin-no-page-setup-named-want-in-file = PSETUPIN: nincs „__ocs_fmt_0__” nevű oldalbeállítás a(z) __ocs_fmt_1__ fájlban.
.psetupin-nothing-to-import-from-file = PSETUPIN: nincs mit importálni innen: __ocs_fmt_0__.
.no-named-page-setups-in-this-drawing = Ebben a rajzban nincsenek névvel ellátott oldalbeállítások.
.import-ellipsis = Importálás…
.show-the-page-setup-for-new-layouts = Oldalbeállítás megjelenítése új elrendezésekhez
.x-in = X (hüvelyk)
.y-in = Y (hüvelyk)
.hide-paperspace-objects = Papírtér-objektumok elrejtése
+9
View File
@@ -5098,6 +5098,15 @@ plot =
.system-default-printer = Stampante predefinita del sistema
.what-to-plot = Cosa tracciare
.x-mm = X (mm)
.select-drawing-to-import-page-setups-from = Seleziona il disegno da cui importare le impostazioni di pagina
.drawings-and-templates = Disegni e modelli
.psetupin-count-page-setup-s-imported-replaced-replaced = PSETUPIN: __ocs_fmt_0__ impostazione/i di pagina importata/e, __ocs_fmt_1__ sostituita/e.
.psetupin-error = PSETUPIN: __ocs_fmt_0__
.psetupin-no-page-setup-named-want-in-file = PSETUPIN: nessuna impostazione di pagina chiamata "__ocs_fmt_0__" in __ocs_fmt_1__.
.psetupin-nothing-to-import-from-file = PSETUPIN: niente da importare da __ocs_fmt_0__.
.no-named-page-setups-in-this-drawing = Nessuna impostazione di pagina con nome in questo disegno.
.import-ellipsis = Importa…
.show-the-page-setup-for-new-layouts = Mostra l'impostazione di pagina per i nuovi layout
.x-in = X (poll.)
.y-in = Y (poll.)
.hide-paperspace-objects = Nascondi oggetti dello spazio carta
+9
View File
@@ -5087,6 +5087,15 @@ plot =
.system-default-printer = システムの既定プリンター
.what-to-plot = 印刷対象
.x-mm = X(mm)
.select-drawing-to-import-page-setups-from = ページ設定を読み込む図面を選択
.drawings-and-templates = 図面とテンプレート
.psetupin-count-page-setup-s-imported-replaced-replaced = PSETUPIN: __ocs_fmt_0__ 件のページ設定を読み込み、__ocs_fmt_1__ 件を置き換えました。
.psetupin-error = PSETUPIN: __ocs_fmt_0__
.psetupin-no-page-setup-named-want-in-file = PSETUPIN: __ocs_fmt_1__ に「__ocs_fmt_0__」というページ設定はありません。
.psetupin-nothing-to-import-from-file = PSETUPIN: __ocs_fmt_0__ に読み込むものがありません。
.no-named-page-setups-in-this-drawing = この図面には名前付きページ設定がありません。
.import-ellipsis = 読み込み…
.show-the-page-setup-for-new-layouts = 新しいレイアウトでページ設定を表示
.x-in = X(インチ)
.y-in = Y(インチ)
.hide-paperspace-objects = ペーパー空間のオブジェクトを隠す
+9
View File
@@ -5098,6 +5098,15 @@ plot =
.system-default-printer = 시스템 기본 프린터
.what-to-plot = 무엇을 플롯할 것인가
.x-mm = X (mm)
.select-drawing-to-import-page-setups-from = 페이지 설정을 가져올 도면 선택
.drawings-and-templates = 도면 및 템플릿
.psetupin-count-page-setup-s-imported-replaced-replaced = PSETUPIN: 페이지 설정 __ocs_fmt_0__개를 가져왔고 __ocs_fmt_1__개를 교체했습니다.
.psetupin-error = PSETUPIN: __ocs_fmt_0__
.psetupin-no-page-setup-named-want-in-file = PSETUPIN: __ocs_fmt_1__에 "__ocs_fmt_0__" 페이지 설정이 없습니다.
.psetupin-nothing-to-import-from-file = PSETUPIN: __ocs_fmt_0__에서 가져올 항목이 없습니다.
.no-named-page-setups-in-this-drawing = 이 도면에는 명명된 페이지 설정이 없습니다.
.import-ellipsis = 가져오기…
.show-the-page-setup-for-new-layouts = 새 배치에 페이지 설정 표시
.x-in = X (인치)
.y-in = Y (인치)
.hide-paperspace-objects = 도면 공간 객체 숨기기
+9
View File
@@ -5097,6 +5097,15 @@ plot =
.system-default-printer = Standaardprinter van het systeem
.what-to-plot = Wat te plannen
.x-mm = X (mm)
.select-drawing-to-import-page-setups-from = Tekening kiezen om pagina-instellingen uit te importeren
.drawings-and-templates = Tekeningen en sjablonen
.psetupin-count-page-setup-s-imported-replaced-replaced = PSETUPIN: __ocs_fmt_0__ pagina-instelling(en) geïmporteerd, __ocs_fmt_1__ vervangen.
.psetupin-error = PSETUPIN: __ocs_fmt_0__
.psetupin-no-page-setup-named-want-in-file = PSETUPIN: geen pagina-instelling met de naam "__ocs_fmt_0__" in __ocs_fmt_1__.
.psetupin-nothing-to-import-from-file = PSETUPIN: niets te importeren uit __ocs_fmt_0__.
.no-named-page-setups-in-this-drawing = Geen benoemde pagina-instellingen in deze tekening.
.import-ellipsis = Importeren…
.show-the-page-setup-for-new-layouts = Pagina-instelling tonen voor nieuwe lay-outs
.x-in = X (inch)
.y-in = Y (inch)
.hide-paperspace-objects = Papierruimte-objecten verbergen
+9
View File
@@ -5098,6 +5098,15 @@ plot =
.system-default-printer = Domyślna drukarka systemowa
.what-to-plot = Co nakreślić
.x-mm = X (mm)
.select-drawing-to-import-page-setups-from = Wybierz rysunek, z którego zaimportować ustawienia strony
.drawings-and-templates = Rysunki i szablony
.psetupin-count-page-setup-s-imported-replaced-replaced = PSETUPIN: zaimportowano __ocs_fmt_0__ ustawień strony, zastąpiono __ocs_fmt_1__.
.psetupin-error = PSETUPIN: __ocs_fmt_0__
.psetupin-no-page-setup-named-want-in-file = PSETUPIN: brak ustawienia strony o nazwie „__ocs_fmt_0__” w __ocs_fmt_1__.
.psetupin-nothing-to-import-from-file = PSETUPIN: nie ma nic do zaimportowania z __ocs_fmt_0__.
.no-named-page-setups-in-this-drawing = Brak nazwanych ustawień strony w tym rysunku.
.import-ellipsis = Importuj…
.show-the-page-setup-for-new-layouts = Pokaż ustawienia strony dla nowych arkuszy
.x-in = X (cale)
.y-in = Y (cale)
.hide-paperspace-objects = Ukryj obiekty przestrzeni papieru
+9
View File
@@ -5099,6 +5099,15 @@ plot =
.system-default-printer = Impressora padrão do sistema
.what-to-plot = O que plotar
.x-mm = X (mm)
.select-drawing-to-import-page-setups-from = Selecionar desenho de onde importar configurações de página
.drawings-and-templates = Desenhos e modelos
.psetupin-count-page-setup-s-imported-replaced-replaced = PSETUPIN: __ocs_fmt_0__ configuração(ões) de página importada(s), __ocs_fmt_1__ substituída(s).
.psetupin-error = PSETUPIN: __ocs_fmt_0__
.psetupin-no-page-setup-named-want-in-file = PSETUPIN: nenhuma configuração de página chamada "__ocs_fmt_0__" em __ocs_fmt_1__.
.psetupin-nothing-to-import-from-file = PSETUPIN: nada para importar de __ocs_fmt_0__.
.no-named-page-setups-in-this-drawing = Nenhuma configuração de página nomeada neste desenho.
.import-ellipsis = Importar…
.show-the-page-setup-for-new-layouts = Mostrar a configuração de página para novos layouts
.x-in = X (pol)
.y-in = Y (pol)
.hide-paperspace-objects = Ocultar objetos do espaço do papel
+9
View File
@@ -5100,6 +5100,15 @@ plot =
.system-default-printer = Системный принтер по умолчанию
.what-to-plot = Что спланировать
.x-mm = X (мм)
.select-drawing-to-import-page-setups-from = Выберите чертёж для импорта наборов параметров листа
.drawings-and-templates = Чертежи и шаблоны
.psetupin-count-page-setup-s-imported-replaced-replaced = PSETUPIN: импортировано наборов: __ocs_fmt_0__, заменено: __ocs_fmt_1__.
.psetupin-error = PSETUPIN: __ocs_fmt_0__
.psetupin-no-page-setup-named-want-in-file = PSETUPIN: набор параметров листа «__ocs_fmt_0__» не найден в __ocs_fmt_1__.
.psetupin-nothing-to-import-from-file = PSETUPIN: нечего импортировать из __ocs_fmt_0__.
.no-named-page-setups-in-this-drawing = В этом чертеже нет именованных наборов параметров листа.
.import-ellipsis = Импорт…
.show-the-page-setup-for-new-layouts = Показывать параметры листа для новых листов
.x-in = X (дюймы)
.y-in = Y (дюймы)
.hide-paperspace-objects = Скрыть объекты пространства листа
+9
View File
@@ -5039,6 +5039,15 @@ plot =
.system-default-printer = Varsayılan sistem yazıcısı
.what-to-plot = Yazdırılacak Alan
.x-mm = X (mm)
.select-drawing-to-import-page-setups-from = Sayfa ayarlarının içe aktarılacağı çizimi seçin
.drawings-and-templates = Çizimler ve şablonlar
.psetupin-count-page-setup-s-imported-replaced-replaced = PSETUPIN: __ocs_fmt_0__ sayfa ayarı içe aktarıldı, __ocs_fmt_1__ değiştirildi.
.psetupin-error = PSETUPIN: __ocs_fmt_0__
.psetupin-no-page-setup-named-want-in-file = PSETUPIN: __ocs_fmt_1__ içinde "__ocs_fmt_0__" adlı sayfa ayarı yok.
.psetupin-nothing-to-import-from-file = PSETUPIN: __ocs_fmt_0__ içinden içe aktarılacak bir şey yok.
.no-named-page-setups-in-this-drawing = Bu çizimde adlandırılmış sayfa ayarı yok.
.import-ellipsis = İçe aktar…
.show-the-page-setup-for-new-layouts = Yeni yerleşimler için sayfa ayarını göster
.x-in = X (inç)
.y-in = Y (inç)
.hide-paperspace-objects = Kağıt alanı nesnelerini gizle
+9
View File
@@ -5082,6 +5082,15 @@ plot =
.system-default-printer = 系统默认打印机
.what-to-plot = 打印内容
.x-mm = X (毫米)
.select-drawing-to-import-page-setups-from = 选择要从中输入页面设置的图形
.drawings-and-templates = 图形和样板
.psetupin-count-page-setup-s-imported-replaced-replaced = PSETUPIN:已输入 __ocs_fmt_0__ 个页面设置,替换 __ocs_fmt_1__ 个。
.psetupin-error = PSETUPIN:__ocs_fmt_0__
.psetupin-no-page-setup-named-want-in-file = PSETUPIN:__ocs_fmt_1__ 中没有名为“__ocs_fmt_0__”的页面设置。
.psetupin-nothing-to-import-from-file = PSETUPIN:__ocs_fmt_0__ 中没有可输入的内容。
.no-named-page-setups-in-this-drawing = 此图形中没有命名页面设置。
.import-ellipsis = 输入…
.show-the-page-setup-for-new-layouts = 为新布局显示页面设置
.x-in = X(英寸)
.y-in = Y(英寸)
.hide-paperspace-objects = 隐藏图纸空间对象
+9
View File
@@ -5094,6 +5094,15 @@ plot =
.system-default-printer = 系統預設印表機
.what-to-plot = 列印內容
.x-mm = X (毫米)
.select-drawing-to-import-page-setups-from = 選擇要從中匯入頁面設定的圖面
.drawings-and-templates = 圖面與樣板
.psetupin-count-page-setup-s-imported-replaced-replaced = PSETUPIN:已匯入 __ocs_fmt_0__ 個頁面設定,取代 __ocs_fmt_1__ 個。
.psetupin-error = PSETUPIN:__ocs_fmt_0__
.psetupin-no-page-setup-named-want-in-file = PSETUPIN:__ocs_fmt_1__ 中沒有名為「__ocs_fmt_0__」的頁面設定。
.psetupin-nothing-to-import-from-file = PSETUPIN:__ocs_fmt_0__ 中沒有可匯入的內容。
.no-named-page-setups-in-this-drawing = 此圖面中沒有具名的頁面設定。
.import-ellipsis = 匯入…
.show-the-page-setup-for-new-layouts = 為新配置顯示頁面設定
.x-in = X(英吋)
.y-in = Y(英吋)
.hide-paperspace-objects = 隱藏圖紙空間物件
+2
View File
@@ -567,6 +567,8 @@ inventory::submit!(crate::command::CommandRegistration {
"BACKGROUNDPLOT",
"CTAB",
"TILEMODE",
"PSETUPIN",
"-PSETUPIN",
"DISPSILH",
"WORLDVIEW",
"LIMCHECK",
+18 -6
View File
@@ -1,9 +1,11 @@
//! Plot system variables. `PLOTOFFSET`, `PAPERUPDATE`, `PLOTROTMODE`,
//! `PLOTTRANSPARENCYOVERRIDE` and `BACKGROUNDPLOT` are plot preferences of
//! the application, kept with the Plot dialog's persisted settings; `CTAB`
//! and `TILEMODE` say which layout of the drawing is current. Each is
//! typeable on its own (`PLOTOFFSET 1`, `CTAB Layout1`) and through
//! `SETVAR`, and a bare name prompts for the value like the other variables.
//! Plot system variables and the page-setup import command. `PLOTOFFSET`,
//! `PAPERUPDATE`, `PLOTROTMODE`, `PLOTTRANSPARENCYOVERRIDE` and
//! `BACKGROUNDPLOT` are plot preferences of the application, kept with the
//! Plot dialog's persisted settings; `CTAB` and `TILEMODE` say which layout
//! of the drawing is current. Each is typeable on its own (`PLOTOFFSET 1`,
//! `CTAB Layout1`) and through `SETVAR`, and a bare name prompts for the
//! value like the other variables. `PSETUPIN` brings named page setups in
//! from another drawing (see `app::update::page_setup_import`).
use crate::app::{Message, OpenCADStudio};
use iced::Task;
@@ -39,6 +41,16 @@ enum Outcome {
impl OpenCADStudio {
pub(super) fn dispatch_plotvars(&mut self, cmd: &str, i: usize) -> Option<Task<Message>> {
// PSETUPIN [file [* | name,name…]] — the dash form is the same
// command; both read the file and report on the command line.
for name in ["PSETUPIN", "-PSETUPIN"] {
if cmd == name {
return Some(self.on_psetupin(""));
}
if let Some(args) = cmd.strip_prefix(name).filter(|rest| rest.starts_with(' ')) {
return Some(self.on_psetupin(args));
}
}
let rest = cmd.strip_prefix("SETVAR ").map(str::trim).unwrap_or(cmd);
let mut parts = rest.splitn(2, char::is_whitespace);
let name = parts.next().unwrap_or("").to_ascii_uppercase();
+4
View File
@@ -2196,6 +2196,10 @@ pub enum Message {
SaveTimeChanged(i32),
/// Toggle keeping a `.bak` copy when overwriting a drawing (ISAVEBAK).
BackupOnSaveChanged(bool),
/// A drawing was picked to import page setups from (`PSETUPIN`).
PageSetupImportFile(std::path::PathBuf),
/// Options: open the Plot / Page Setup dialog for every new layout.
PageSetupOnNewLayoutChanged(bool),
/// Toggle filled TrueType glyphs (TEXTFILL).
TextFillChanged(bool),
/// Change how many prompt lines sit above the command window (CLIPROMPTLINES).
+3 -2
View File
@@ -4443,6 +4443,7 @@ impl OpenCADStudio {
Task::none()
}
M::PrinterProperties => self.on_printer_properties(),
M::Import(msg) => self.on_page_setup_import(msg),
M::PrinterOptionsLoaded(printer, result) => {
if let Some(draft) = self.plot_dialog.printer_editor.as_mut() {
if draft.printer == printer {
@@ -4836,7 +4837,7 @@ impl OpenCADStudio {
}
}
fn refresh_page_setups(&mut self) {
pub(super) fn refresh_page_setups(&mut self) {
use crate::ui::window::plot::{SETUP_NONE, SETUP_PREV};
let scene = &self.tabs[self.active_tab].scene;
// <none> / <previous>, then layouts (`*name*`), then named setups.
@@ -4849,7 +4850,7 @@ impl OpenCADStudio {
/// Apply a page-setup list selection to the editor. Handles the pseudo
/// entries (`<none>` / `<previous>`), layout rows (`*name*`) and named
/// setups.
fn select_page_setup(&mut self, name: &str) {
pub(super) fn select_page_setup(&mut self, name: &str) {
use crate::ui::window::plot::{SETUP_NONE, SETUP_PREV};
self.plot_dialog.selected_setup = name.to_string();
if name == SETUP_NONE {
+7
View File
@@ -94,6 +94,7 @@ mod context_menu;
mod dialog;
mod dynamic;
mod file;
mod page_setup_import;
mod style;
mod util;
mod viewport;
@@ -7378,6 +7379,12 @@ impl OpenCADStudio {
Task::none()
}
Message::PageSetupImportFile(path) => self.on_page_setup_import_file(path),
Message::PageSetupOnNewLayoutChanged(enabled) => {
self.plot_dialog.page_setup_on_new_layout = enabled;
self.persist_settings_if_changed();
Task::none()
}
Message::BackupOnSaveChanged(enabled) => {
self.backup_on_save = enabled;
self.persist_settings_if_changed();
+347
View File
@@ -0,0 +1,347 @@
//! Importing named page setups from another drawing (`PSETUPIN`): the
//! "Import…" chooser of the Plot dialog and the command that drives the same
//! path from the command line.
use crate::app::{Message, OpenCADStudio};
use crate::ui::window::plot::{PageSetupImportDraft, PageSetupImportMsg, PlotDlgMsg};
use iced::Task;
use std::path::{Path, PathBuf};
/// Read the named page setups of the drawing at `path` off the UI thread.
/// The result names the file the way the chooser shows it.
fn read_page_setups_task(path: PathBuf) -> Task<Message> {
super::file::background_task(
move || {
let file = path
.file_name()
.map(|name| name.to_string_lossy().into_owned())
.unwrap_or_else(|| path.display().to_string());
crate::io::load_file(&path)
.map(|document| (file, crate::scene::document_page_setups(&document)))
},
|result| Message::PlotDlg(PlotDlgMsg::Import(PageSetupImportMsg::Loaded(result))),
)
}
impl OpenCADStudio {
pub(super) fn on_page_setup_import(&mut self, msg: PageSetupImportMsg) -> Task<Message> {
match msg {
PageSetupImportMsg::Pick => Task::perform(
async {
let handle = rfd::AsyncFileDialog::new()
.set_title(crate::t!("Select Drawing to Import Page Setups From").as_ref())
.add_filter(
crate::t!("Drawings and templates").as_ref(),
&["dwg", "dxf", "dwt", "DWG", "DXF", "DWT"],
)
.pick_file()
.await;
handle.map(|h| crate::sys::handle_path(&h))
},
|picked| match picked {
Some(path) => Message::PageSetupImportFile(path),
None => Message::Noop,
},
),
PageSetupImportMsg::Loaded(result) => {
self.plot_dialog.import_draft = Some(match result {
Ok((file, setups)) => PageSetupImportDraft {
file,
setups: setups.into_iter().map(|(name, ps)| (name, ps, true)).collect(),
error: None,
},
Err(error) => PageSetupImportDraft {
file: String::new(),
setups: Vec::new(),
error: Some(error),
},
});
Task::none()
}
PageSetupImportMsg::Toggle(name) => {
if let Some(draft) = self.plot_dialog.import_draft.as_mut() {
if let Some(entry) = draft.setups.iter_mut().find(|(n, _, _)| *n == name) {
entry.2 = !entry.2;
}
}
Task::none()
}
PageSetupImportMsg::All(on) => {
if let Some(draft) = self.plot_dialog.import_draft.as_mut() {
for entry in &mut draft.setups {
entry.2 = on;
}
}
Task::none()
}
PageSetupImportMsg::Apply => {
let Some(draft) = self.plot_dialog.import_draft.take() else {
return Task::none();
};
let chosen: Vec<(String, acadrust::objects::PlotSettings)> = draft
.selected()
.map(|(name, ps)| (name.to_string(), ps.clone()))
.collect();
let imported = self.import_page_setups(chosen);
if let Some(first) = imported.first() {
let first = first.clone();
self.select_page_setup(&first);
}
Task::none()
}
PageSetupImportMsg::Cancel => {
self.plot_dialog.import_draft = None;
Task::none()
}
}
}
/// A drawing was picked for import: read it in the background; the
/// chooser appears in the Plot dialog once it is read.
pub(super) fn on_page_setup_import_file(&mut self, path: PathBuf) -> Task<Message> {
// The chooser lives in the Plot dialog; open it if the import was
// started from the command line.
let open = if self.active_modal == Some(crate::app::ModalKind::Plot) {
Task::none()
} else {
self.on_plot_dialog_open()
};
Task::batch([open, read_page_setups_task(path)])
}
/// Bring the given setups into the drawing, replacing same-named ones,
/// as one undoable step. Returns the names imported.
pub(super) fn import_page_setups(
&mut self,
setups: Vec<(String, acadrust::objects::PlotSettings)>,
) -> Vec<String> {
if setups.is_empty() {
return Vec::new();
}
let i = self.active_tab;
self.push_undo_snapshot(i, "PSETUPIN");
let mut replaced = 0usize;
let existing = self.tabs[i].scene.page_setup_names();
let mut names = Vec::with_capacity(setups.len());
for (name, ps) in setups {
if existing.iter().any(|n| n.eq_ignore_ascii_case(&name)) {
replaced += 1;
}
self.tabs[i].scene.import_page_setup(&name, ps);
names.push(name);
}
self.tabs[i].dirty = true;
self.refresh_page_setups();
let count = names.len();
self.command_line.push_output(
crate::tf!("PSETUPIN: {count} page setup(s) imported, {replaced} replaced.").as_ref(),
);
names
}
/// `PSETUPIN` / `-PSETUPIN`: with no file, ask for one and offer its
/// setups in the Plot dialog; with `<file> *` or `<file> name,name`
/// import those straight away; with just `<file>` open the chooser on it.
pub(in crate::app) fn on_psetupin(&mut self, args: &str) -> Task<Message> {
let args = args.trim();
if args.is_empty() {
return self.on_page_setup_import(PageSetupImportMsg::Pick);
}
// The file may carry spaces; the setup list, when given, is the last
// word (`*` or a comma-separated list without spaces), so the
// arguments are a file followed by names only when what precedes the
// last word is itself a file.
let (file, names) = match args.rsplit_once(char::is_whitespace) {
Some((file, names)) if Path::new(file.trim()).is_file() => {
(file.trim(), Some(names.trim()))
}
_ => (args, None),
};
let path = PathBuf::from(file);
let Some(names) = names else {
return self.on_page_setup_import_file(path);
};
let available = match crate::io::load_file(&path) {
Ok(document) => crate::scene::document_page_setups(&document),
Err(error) => {
self.command_line
.push_error(crate::tf!("PSETUPIN: {error}").as_ref());
return Task::none();
}
};
let chosen: Vec<(String, acadrust::objects::PlotSettings)> = if names == "*" {
available
} else {
let wanted: Vec<&str> = names.split(',').map(str::trim).collect();
let mut chosen = Vec::new();
for want in wanted {
match available.iter().find(|(n, _)| n.eq_ignore_ascii_case(want)) {
Some(found) => chosen.push(found.clone()),
None => self.command_line.push_error(
crate::tf!("PSETUPIN: no page setup named \"{want}\" in {file}.")
.as_ref(),
),
}
}
chosen
};
if chosen.is_empty() {
self.command_line
.push_info(crate::tf!("PSETUPIN: nothing to import from {file}.").as_ref());
return Task::none();
}
self.import_page_setups(chosen);
Task::none()
}
}
#[cfg(all(test, not(target_arch = "wasm32")))]
mod tests {
use crate::app::{Message, OpenCADStudio};
use crate::ui::window::plot::{PageSetupImportMsg as I, PlotDlgMsg};
const FIXTURE: &str = concat!(
env!("CARGO_MANIFEST_DIR"),
"/tests/fixtures/plot/page-setups-metric.dxf"
);
fn app() -> OpenCADStudio {
let mut app = OpenCADStudio::new_for_test();
app.automation_op(r#"{"op":"new"}"#);
let _ = app.update(Message::LayoutSwitch("Layout1".into()));
app
}
fn last_line(app: &OpenCADStudio) -> String {
app.command_line.history.last().map(|line| line.text.clone()).unwrap_or_default()
}
/// The fixture's page setups as the chooser would hold them, read
/// through the same document reader the command uses.
fn fixture_setups() -> Vec<(String, acadrust::objects::PlotSettings)> {
let document = crate::io::load_file(std::path::Path::new(FIXTURE)).unwrap();
crate::scene::document_page_setups(&document)
}
#[test]
fn the_fixture_reader_lists_its_named_page_setups() {
// The fixture carries its page setups on the layouts, not as named
// setups; a drawing with named ones lists them in dictionary order.
assert!(fixture_setups().is_empty());
let mut app = app();
let i = app.active_tab;
let ps = app.tabs[i].scene.plot_settings_for("Layout1").unwrap();
app.tabs[i].scene.page_setup_save("Site", ps.clone());
app.tabs[i].scene.page_setup_save("Detail", ps);
let names: Vec<String> = crate::scene::document_page_setups(&app.tabs[i].scene.document)
.into_iter()
.map(|(name, _)| name)
.collect();
assert_eq!(names, ["Site", "Detail"]);
}
#[test]
fn psetupin_imports_named_setups_from_a_saved_drawing() {
use acadrust::objects::PlotRotation;
// Author a source drawing with two named setups and save it.
let dir = std::env::temp_dir().join(format!("ocs-psetupin-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let source = dir.join("source.dxf");
{
let mut app = app();
let i = app.active_tab;
let mut ps = app.tabs[i].scene.plot_settings_for("Layout1").unwrap();
ps.printer_name = "DWG To PDF.pc3".into();
ps.paper_size = "ISO_A3_(297.00_x_420.00_MM)".into();
ps.paper_width = 297.0;
ps.paper_height = 420.0;
ps.rotation = PlotRotation::Degrees90;
ps.plot_view_handle = acadrust::Handle::new(0xBEEF);
app.tabs[i].scene.page_setup_save("Site", ps.clone());
ps.paper_size = "ISO_A2_(420.00_x_594.00_MM)".into();
app.tabs[i].scene.page_setup_save("Overview", ps);
let save = format!(r#"{{"op":"save","path":"{}"}}"#, source.display());
let reply = app.automation_op(&save);
assert_eq!(reply["ok"], true, "{reply}");
}
let mut app = app();
let i = app.active_tab;
// One named setup already exists under a name the file also has.
let own = app.tabs[i].scene.plot_settings_for("Layout1").unwrap();
app.tabs[i].scene.page_setup_save("Site", own);
// `*` imports everything, replacing the same-named one.
let _ = app.run_command_line(&format!("PSETUPIN {} *", source.display()));
// The report is translated on localized systems; the counts are not.
let report = last_line(&app);
assert!(report.starts_with("PSETUPIN"), "{report}");
assert!(report.contains('2') && report.contains('1'), "{report}");
let names = app.tabs[i].scene.page_setup_names();
assert_eq!(names, ["Site", "Overview"]);
let site = app.tabs[i].scene.page_setup_get("Site").unwrap();
assert_eq!(site.paper_size, "ISO_A3_(297.00_x_420.00_MM)");
assert_eq!(site.rotation, PlotRotation::Degrees90);
assert!(site.plot_view_handle.is_null(), "foreign handles are dropped");
assert!(app.tabs[i].dirty);
// Undo takes the whole import back.
let _ = app.update(Message::Undo);
let names = app.tabs[i].scene.page_setup_names();
assert_eq!(names, ["Site"]);
assert_ne!(
app.tabs[i].scene.page_setup_get("Site").unwrap().paper_size,
"ISO_A3_(297.00_x_420.00_MM)"
);
// A name list imports just those and reports the unknown ones.
let _ = app.run_command_line(&format!("PSETUPIN {} Overview,Nothing", source.display()));
assert_eq!(app.tabs[i].scene.page_setup_names(), ["Site", "Overview"]);
// A missing file is an error, not a crash.
let _ = app.run_command_line("PSETUPIN /nowhere/at/all.dwg *");
assert!(last_line(&app).starts_with("PSETUPIN:"));
std::fs::remove_dir_all(&dir).ok();
}
#[test]
fn the_chooser_imports_the_ticked_setups_and_selects_the_first() {
let mut app = app();
let i = app.active_tab;
let ps = app.tabs[i].scene.plot_settings_for("Layout1").unwrap();
let _ = app.on_plot_dialog_open();
let setups = ["A", "B", "C"]
.into_iter()
.map(|name| (name.to_string(), ps.clone()))
.collect();
let loaded = Ok(("other.dwg".to_string(), setups));
let _ = app.on_plot_dlg(PlotDlgMsg::Import(I::Loaded(loaded)));
let draft = app.plot_dialog.import_draft.as_ref().expect("chooser open");
assert_eq!(draft.file, "other.dwg");
assert_eq!(draft.selected().count(), 3, "everything ticked to start with");
let _ = app.on_plot_dlg(PlotDlgMsg::Import(I::All(false)));
assert_eq!(app.plot_dialog.import_draft.as_ref().unwrap().selected().count(), 0);
let _ = app.on_plot_dlg(PlotDlgMsg::Import(I::Toggle("B".into())));
let _ = app.on_plot_dlg(PlotDlgMsg::Import(I::Toggle("C".into())));
let _ = app.on_plot_dlg(PlotDlgMsg::Import(I::Apply));
assert!(app.plot_dialog.import_draft.is_none(), "Apply closes the chooser");
assert_eq!(app.tabs[i].scene.page_setup_names(), ["B", "C"]);
assert_eq!(app.plot_dialog.selected_setup, "B");
assert!(app.plot_dialog.page_setups.iter().any(|name| name == "C"));
// A failed read shows its reason in the chooser; Cancel closes it.
let _ = app.on_plot_dlg(PlotDlgMsg::Import(I::Loaded(Err("unreadable".into()))));
assert_eq!(
app.plot_dialog.import_draft.as_ref().unwrap().error.as_deref(),
Some("unreadable")
);
let _ = app.on_plot_dlg(PlotDlgMsg::Import(I::Cancel));
assert!(app.plot_dialog.import_draft.is_none());
}
#[test]
fn a_new_layout_opens_its_page_setup_when_the_option_is_on() {
let mut app = app();
let _ = app.update(Message::LayoutCreate);
assert_ne!(app.active_modal, Some(crate::app::ModalKind::Plot));
let _ = app.update(Message::PageSetupOnNewLayoutChanged(true));
assert!(app.current_config().plot.page_setup_on_new_layout, "persisted");
let _ = app.update(Message::LayoutCreate);
assert_eq!(app.active_modal, Some(crate::app::ModalKind::Plot));
assert_eq!(app.plot_dialog.selected_setup, "*Layout3*");
}
}
+6
View File
@@ -6047,6 +6047,12 @@ properties={:.1}ms picked={}",
crate::tf!("Layout \"{new_name}\" created — use MVIEW to add a viewport")
.as_ref(),
);
// The option that greets every new layout with its page setup.
let switch_task = if self.plot_dialog.page_setup_on_new_layout {
Task::batch([switch_task, self.on_plot_dialog_open()])
} else {
switch_task
};
self.tabs[i].dirty = true;
return Task::batch([cancel_task, switch_task]);
}
+1
View File
@@ -289,6 +289,7 @@ impl OpenCADStudio {
crate::ui::window::options::AppPrefs {
savetime_min: self.savetime_min,
backup_on_save: self.backup_on_save,
page_setup_on_new_layout: self.plot_dialog.page_setup_on_new_layout,
textfill: crate::scene::text::sdf_atlas::textfill(),
cliprompt_lines: self.cliprompt_lines,
commandline_fade_ms: self.commandline_fade_ms,
+9
View File
@@ -3144,6 +3144,15 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static
"World" => Some(("common", "world")),
"Write Block" => Some(("insert", "write-block")),
"X (mm)" => Some(("plot", "x-mm")),
"Select Drawing to Import Page Setups From" => Some(("plot", "select-drawing-to-import-page-setups-from")),
"Drawings and templates" => Some(("plot", "drawings-and-templates")),
"PSETUPIN: {count} page setup(s) imported, {replaced} replaced." => Some(("plot", "psetupin-count-page-setup-s-imported-replaced-replaced")),
"PSETUPIN: {error}" => Some(("plot", "psetupin-error")),
"PSETUPIN: no page setup named \"{want}\" in {file}." => Some(("plot", "psetupin-no-page-setup-named-want-in-file")),
"PSETUPIN: nothing to import from {file}." => Some(("plot", "psetupin-nothing-to-import-from-file")),
"No named page setups in this drawing." => Some(("plot", "no-named-page-setups-in-this-drawing")),
"Import…" => Some(("plot", "import-ellipsis")),
"Show the page setup for new layouts" => Some(("plot", "show-the-page-setup-for-new-layouts")),
"X (in)" => Some(("plot", "x-in")),
"Y (in)" => Some(("plot", "y-in")),
"Hide paperspace objects" => Some(("plot", "hide-paperspace-objects")),
+1 -1
View File
@@ -33,7 +33,7 @@ pub(crate) mod centermark;
pub(crate) mod dimension_assoc;
pub(crate) mod dimension_assoc_chain;
pub use dimension_assoc::{ReferenceStatus, ResolvedReference};
pub use page_setup::{apply_default_page_setup, rotated_margins};
pub use page_setup::{apply_default_page_setup, document_page_setups, rotated_margins};
mod dwg_native_constraints;
mod entity;
#[cfg(test)]
+60 -24
View File
@@ -6,7 +6,7 @@
use super::Scene;
use acadrust::objects::{Dictionary, Layout, ObjectType, PlotSettings};
use acadrust::Handle;
use acadrust::{CadDocument, Handle};
/// Give a freshly created paper layout the page setup a new drawing starts
/// with — ISO A4 landscape on no plotter, plotted 1:1 as a layout — stored the
@@ -59,30 +59,59 @@ pub fn rotated_margins(
}
}
impl Scene {
/// Handle of the `ACAD_PLOTSETTINGS` dictionary, located robustly.
///
/// The canonical path is the header's `acad_plotsettings_dict_handle`, but
/// DWGs written by other programs don't always leave that pointer resolvable
/// (the header handle points at no loaded dictionary — see
/// [`crate::scene::annotative::root_named_dict_handle`]). In that case fall
/// back to the dictionary that owns the drawing's `PlotSettings` objects,
/// mirroring [`Scene::scalelist_dict_handle`]. Returns `None` when the
/// drawing genuinely has no named page setups.
fn plotsettings_dict_handle(&self) -> Option<Handle> {
let dh = self.document.header.acad_plotsettings_dict_handle;
if matches!(self.document.objects.get(&dh), Some(ObjectType::Dictionary(_))) {
return Some(dh);
}
let owner = self.document.objects.values().find_map(|o| match o {
ObjectType::PlotSettings(ps) => Some(ps.owner),
/// Handle of a document's `ACAD_PLOTSETTINGS` dictionary, located robustly.
///
/// The canonical path is the header's `acad_plotsettings_dict_handle`, but
/// DWGs written by other programs don't always leave that pointer resolvable
/// (the header handle points at no loaded dictionary — see
/// [`crate::scene::annotative::root_named_dict_handle`]). In that case fall
/// back to the dictionary that owns the drawing's `PlotSettings` objects,
/// mirroring [`Scene::scalelist_dict_handle`]. Returns `None` when the
/// drawing genuinely has no named page setups.
fn plotsettings_dict_handle_in(document: &CadDocument) -> Option<Handle> {
let dh = document.header.acad_plotsettings_dict_handle;
if matches!(document.objects.get(&dh), Some(ObjectType::Dictionary(_))) {
return Some(dh);
}
let owner = document.objects.values().find_map(|o| match o {
ObjectType::PlotSettings(ps) => Some(ps.owner),
_ => None,
})?;
matches!(document.objects.get(&owner), Some(ObjectType::Dictionary(_))).then_some(owner)
}
/// The named page setups of any document — `(name, settings)` in dictionary
/// order. Reads a drawing that is not open in the editor (the source of a
/// `PSETUPIN` import) the same way the editor reads its own.
pub fn document_page_setups(document: &CadDocument) -> Vec<(String, PlotSettings)> {
let Some(dh) = plotsettings_dict_handle_in(document) else {
return Vec::new();
};
let Some(ObjectType::Dictionary(dict)) = document.objects.get(&dh) else {
return Vec::new();
};
dict.entries
.iter()
.filter_map(|(name, handle)| match document.objects.get(handle) {
Some(ObjectType::PlotSettings(ps)) => Some((name.clone(), ps.clone())),
_ => None,
})?;
matches!(
self.document.objects.get(&owner),
Some(ObjectType::Dictionary(_))
)
.then_some(owner)
})
.collect()
}
/// A page setup copied out of another drawing, made safe for this one: the
/// handles it pointed at (a plot view, a visual style) meant something only
/// in its source, so they are dropped while the names, which travel, stay.
pub fn detach_page_setup(ps: &mut PlotSettings) {
ps.plot_view_handle = Handle::NULL;
ps.visual_style_handle = Handle::NULL;
ps.reactors.clear();
ps.xdictionary_handle = None;
}
impl Scene {
fn plotsettings_dict_handle(&self) -> Option<Handle> {
plotsettings_dict_handle_in(&self.document)
}
/// Names of the document's named page setups, in dictionary order.
@@ -93,6 +122,13 @@ impl Scene {
}
}
/// Bring a page setup from another drawing in under `name`, replacing
/// one of that name the way `PSETUPIN` redefines it.
pub fn import_page_setup(&mut self, name: &str, mut ps: PlotSettings) {
detach_page_setup(&mut ps);
self.page_setup_save(name, ps);
}
/// Clone the named page setup's `PlotSettings`, or `None` if absent.
pub fn page_setup_get(&self, name: &str) -> Option<PlotSettings> {
let dh = self.plotsettings_dict_handle()?;
+25 -14
View File
@@ -77,6 +77,8 @@ pub struct AppPrefs {
pub right_click_mode: RightClickMode,
/// SHORTCUTMENUDURATION: time-sensitive hold threshold, ms.
pub right_click_hold_ms: i32,
/// Open the Plot / Page Setup dialog for every new layout.
pub page_setup_on_new_layout: bool,
}
/// The fixed locations the Files page lists.
@@ -361,6 +363,29 @@ pub fn view_window<'a>(
]
.spacing(10)
.align_y(iced::Center),
Space::new().height(22),
text(crate::t!("Plotting")).size(15),
Space::new().height(10),
row![
text(crate::t!("Plot device, paper, scale and plot styles"))
.size(12)
.width(Fill),
button(text(crate::t!("Plot and Page Setup…")).size(11))
.on_press(Message::PlotDialogOpen)
.padding([4, 10])
.style(button::secondary),
]
.spacing(10)
.align_y(iced::Center),
Space::new().height(10),
row![
iced::widget::checkbox(prefs.page_setup_on_new_layout)
.on_toggle(Message::PageSetupOnNewLayoutChanged)
.size(15),
text(crate::t!("Show the page setup for new layouts")).size(12),
]
.spacing(8)
.align_y(iced::Center),
]
.spacing(0)
.width(sizing.width);
@@ -456,20 +481,6 @@ pub fn view_window<'a>(
]
.spacing(8)
.align_y(iced::Center),
Space::new().height(22),
text(crate::t!("Plotting")).size(15),
Space::new().height(10),
row![
text(crate::t!("Plot device, paper, scale and plot styles"))
.size(12)
.width(Fill),
button(text(crate::t!("Plot and Page Setup…")).size(11))
.on_press(Message::PlotDialogOpen)
.padding([4, 10])
.style(button::secondary),
]
.spacing(10)
.align_y(iced::Center),
]
.spacing(0)
.width(sizing.width);
+113
View File
@@ -151,6 +151,43 @@ pub enum PlotFlag {
SaveToLayout,
}
/// The page setups of another drawing, offered for import (`PSETUPIN`).
#[derive(Debug, Clone, PartialEq)]
pub struct PageSetupImportDraft {
/// The drawing they come from, as shown to the user.
pub file: String,
/// Each setup with whether it is ticked for import. The settings are
/// carried along so the source file is read once.
pub setups: Vec<(String, acadrust::objects::PlotSettings, bool)>,
/// Why the file gave nothing, when it did not.
pub error: Option<String>,
}
impl PageSetupImportDraft {
pub fn selected(&self) -> impl Iterator<Item = (&str, &acadrust::objects::PlotSettings)> {
self.setups
.iter()
.filter(|(_, _, on)| *on)
.map(|(name, ps, _)| (name.as_str(), ps))
}
}
/// Edits of the page-setup import chooser.
#[derive(Debug, Clone)]
pub enum PageSetupImportMsg {
/// Ask for the drawing to import from.
Pick,
/// The drawing was read (or could not be): its name and page setups.
Loaded(Result<(String, Vec<(String, acadrust::objects::PlotSettings)>), String>),
/// Tick or untick one setup.
Toggle(String),
/// Tick or untick every setup.
All(bool),
/// Import the ticked setups and close the chooser.
Apply,
Cancel,
}
/// Every edit the Plot dialog can emit. Wrapped in `Message::PlotDlg` so the
/// top-level match stays a single arm.
#[derive(Debug, Clone)]
@@ -209,6 +246,8 @@ pub enum PlotDlgMsg {
CopySetup,
/// Begin an inline rename of the given page setup row.
RenameStart(String),
/// Import named page setups from another drawing (`PSETUPIN`).
Import(PageSetupImportMsg),
/// Delete the selected named page setup.
DeleteSetup,
/// Live edit of the new/rename name field.
@@ -397,6 +436,12 @@ pub struct PlotDialogState {
/// The in-line printer-properties editor while it is open.
#[serde(skip)]
pub printer_editor: Option<PrinterOptionsDraft>,
/// The page-setup import chooser while it is open.
#[serde(skip)]
pub import_draft: Option<PageSetupImportDraft>,
/// Open the Plot / Page Setup dialog whenever a new layout is created,
/// the way a page-setup manager is expected to greet a new layout.
pub page_setup_on_new_layout: bool,
/// Chosen printer name, or `None` for the system default.
pub printer: Option<String>,
/// Output goes to a PDF file instead of a printer.
@@ -502,6 +547,8 @@ impl Default for PlotDialogState {
custom_editor: None,
driver_options: std::collections::BTreeMap::new(),
printer_editor: None,
import_draft: None,
page_setup_on_new_layout: false,
printer: None,
to_file: false,
paper: paper_catalog::default_paper().canonical.to_string(),
@@ -720,6 +767,58 @@ fn check_enabled<'a>(
.into()
}
/// The import chooser: the source drawing's name, one tick per page setup,
/// All / None, and Import / Cancel.
fn page_setup_import_chooser<'a>(
draft: &'a PageSetupImportDraft,
height: Length,
) -> Element<'a, Message> {
let msg = |m: PageSetupImportMsg| Message::PlotDlg(PlotDlgMsg::Import(m));
let mut rows = column![].spacing(3);
if let Some(error) = &draft.error {
rows = rows.push(text(error.clone()).size(10).style(muted_style));
} else if draft.setups.is_empty() {
let none = text(t!("No named page setups in this drawing.")).size(10);
rows = rows.push(none.style(muted_style));
}
for (name, _, on) in &draft.setups {
let name = name.clone();
rows = rows.push(
checkbox(*on)
.label(name.clone())
.on_toggle(move |_| msg(PageSetupImportMsg::Toggle(name.clone())))
.size(13)
.text_size(11),
);
}
let all = !draft.setups.is_empty() && draft.setups.iter().all(|(_, _, on)| *on);
let any = draft.setups.iter().any(|(_, _, on)| *on);
let mut import = button(text(t!("Import")).size(11)).style(btn(true)).padding([4, 8]);
if any {
import = import.on_press(msg(PageSetupImportMsg::Apply));
}
column![
text(draft.file.clone()).size(10).style(muted_style),
scrollable(rows).height(height),
checkbox(all)
.label(t!("All"))
.on_toggle(move |on| msg(PageSetupImportMsg::All(on)))
.size(13)
.text_size(11),
row![
import,
button(text(t!("Cancel")).size(11))
.on_press(msg(PageSetupImportMsg::Cancel))
.style(btn(false))
.padding([4, 8]),
]
.spacing(4),
]
.spacing(6)
.padding(4)
.into()
}
/// The custom-scale row: `Custom: [paper] mm = [drawing] units`. Editing
/// either side replaces the picked scale with the typed ratio.
fn custom_scale_row<'a>(s: &'a PlotDialogState, enabled: bool) -> Element<'a, Message> {
@@ -1011,6 +1110,12 @@ pub fn view_window(
} else {
Space::new().height(0).into()
};
// While an import is being chosen, the list shows the other drawing's
// setups with a tick each instead of this drawing's.
let list_body: Element<'_, Message> = match &s.import_draft {
Some(draft) => page_setup_import_chooser(draft, height),
None => list_body,
};
let list_panel = container(
column![
text(t!("Page setups")).size(10).style(muted_style),
@@ -1062,10 +1167,18 @@ pub fn view_window(
if is_named && !print_all_options {
delete_button = delete_button.on_press(Message::PlotDlg(PlotDlgMsg::DeleteSetup));
}
let mut import_button = button(text(t!("Import…")).size(11))
.style(btn(false))
.padding([4, 12]);
if !print_all_options && s.import_draft.is_none() {
import_button = import_button
.on_press(Message::PlotDlg(PlotDlgMsg::Import(PageSetupImportMsg::Pick)));
}
let left_bar = row![
new_button,
copy_button,
delete_button,
import_button,
]
.spacing(4);
+1 -1
View File
@@ -1 +1 @@
Open CAD Studio pid=842697 path=/home/panos/OpenCADStudio/tests/fixtures/plot/page-setups-metric.dxf
Open CAD Studio pid=854778 path=/home/panos/OpenCADStudio/tests/fixtures/plot/page-setups-metric.dxf