Sheet sets: approved dialogs, sheet status, view categories, model views, navigation fields

Remove Sheets confirmation, Open in drawing editor, Select Layout as Sheet
Template for subsets that prompt, Import Layouts as Sheets with status and
prefix, Rename & Renumber options with Previous/Next and real layout/file
renames, New Subset folder hierarchy and publish setting, subset properties
rows as the reference shows them, sheet status badges (SSMSHEETSTATUS /
SSMPOLLTIME), Sheet Views by category with the View Category dialog, Model
Views locations, Field dialog SheetSet/SheetView navigation, and .dwt/.dws
read as DWG.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ramox81andClaude Opus 5.5 committed 2026-10-05 12:08:29 +03:00
1 parent 612bb26a8c
commit 0a45e59c2f
31 files changed
+2287 -200

No files matched your search

Generated
+1 -1
View File
@@ -4206,7 +4206,7 @@ dependencies = [
[[package]]
name = "opencadcodec"
version = "0.5.5"
source = "git+https://github.com/ramox81/cadcodec.git?rev=3f5d40a#3f5d40a82368cd2dd5e5c44388f8630647ff3533"
source = "git+https://github.com/ramox81/cadcodec.git?rev=d86f57d#d86f57d5d179bc57fe7826d70454bece40c20320"
dependencies = [
"ahash 0.8.12",
"anyhow",
+1 -1
View File
@@ -91,7 +91,7 @@ block2 = "0.5"
objc2-foundation = { version = "0.2", features = ["NSArray", "NSURL", "NSString", "NSObject", "NSNotification", "NSThread", "NSEnumerator"] }
[patch."https://github.com/HakanSeven12/opencadcodec.git"]
opencadcodec = { git = "https://github.com/ramox81/cadcodec.git", rev = "3f5d40a" }
opencadcodec = { git = "https://github.com/ramox81/cadcodec.git", rev = "d86f57d" }
[patch.crates-io]
iced_core = { git = "https://github.com/iced-rs/iced.git", rev = "23604ff22ab0aad9e00b9327cb7b8546ed84db39" }
+39
View File
@@ -4407,6 +4407,45 @@ view =
.ss-new-sheet-location = New sheet location
.ss-remove-subset = Remove Subset
.ss-rename-subset = Rename Subset...
.ss-status-missing = missing
.ss-status-open = open
.ss-view-by-category = View by category
.ss-view-by-sheet = View by sheet
.ss-import-layouts-as-sheets = Import Layouts as Sheets
.ss-remove-sheets = Remove Sheets
.ss-view-category = View Category
.ss-new-view-category = New View Category...
.ss-add-new-location = Add New Location...
.ss-remove-location = Remove Location
.ss-publish-by-sheet = Publish by Sheet 'Include for Publish' Setting
.ss-do-not-publish-sheets = Do Not Publish Sheets
.ss-open-in-drawing-editor = Open in drawing editor
.ss-create-folder-hierarchy = Create folder hierarchy
.ss-publish-sheets-in-subset = Publish sheets in subset
.ss-rename-options = Rename options
.ss-rename-layout-to-match = Rename layout to match:
.ss-prefix-with-sheet-number = Prefix with sheet number
.ss-rename-drawing-file-to-match = Rename drawing file to match:
.ss-available-for-import = Available for import
.ss-belongs-to-sheet-set = Belongs to sheet set __ocs_fmt_0__
.ss-drawings = Drawings
.ss-select-drawing-files-containing-layouts = Select drawing files containing layouts
.ss-browse-for-drawings = Browse for Drawings...
.ss-a-layout-can-belong-to-only-one-sheet-set = A layout can belong to only one sheet set. If a layout already belongs to a sheet set, you must create a copy of the layout to import it.
.ss-prefix-sheet-titles-with-file-name = Prefix sheet titles with file name
.ss-import-checked = Import Checked
.ss-template = Template
.ss-drawing-template-file-name = Drawing template file name
.ss-select-a-layout-to-create-new-sheets = Select a layout to create new sheets
.ss-category-name = Category name
.ss-select-the-callout-blocks = Select the callout blocks to be used in this category
.ss-selected-blocks-will-be-available = Selected blocks will be available for selection when you insert a callout block from the view tab.
.ss-add-blocks = Add Blocks...
.ss-layout-and-drawing-not-deleted = (The layout and the drawing file will not be deleted.)
.ss-remove-sheet-question = Are you sure that you want to remove __ocs_fmt_0__ Sheet from __ocs_fmt_1__ Sheet Set?
.ss-drawing-open-cannot-rename = The drawing is open; close it to rename its file.
.ss-category-name-empty = The category name cannot be empty.
.ss-associate-hyperlink = Associate hyperlink
.ss-remove-sheet = Remove Sheet
.ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set.
.ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets.
+39
View File
@@ -4394,6 +4394,45 @@ view =
.ss-new-sheet-location = New sheet location
.ss-remove-subset = Remove Subset
.ss-rename-subset = Rename Subset...
.ss-status-missing = missing
.ss-status-open = open
.ss-view-by-category = View by category
.ss-view-by-sheet = View by sheet
.ss-import-layouts-as-sheets = Import Layouts as Sheets
.ss-remove-sheets = Remove Sheets
.ss-view-category = View Category
.ss-new-view-category = New View Category...
.ss-add-new-location = Add New Location...
.ss-remove-location = Remove Location
.ss-publish-by-sheet = Publish by Sheet 'Include for Publish' Setting
.ss-do-not-publish-sheets = Do Not Publish Sheets
.ss-open-in-drawing-editor = Open in drawing editor
.ss-create-folder-hierarchy = Create folder hierarchy
.ss-publish-sheets-in-subset = Publish sheets in subset
.ss-rename-options = Rename options
.ss-rename-layout-to-match = Rename layout to match:
.ss-prefix-with-sheet-number = Prefix with sheet number
.ss-rename-drawing-file-to-match = Rename drawing file to match:
.ss-available-for-import = Available for import
.ss-belongs-to-sheet-set = Belongs to sheet set __ocs_fmt_0__
.ss-drawings = Drawings
.ss-select-drawing-files-containing-layouts = Select drawing files containing layouts
.ss-browse-for-drawings = Browse for Drawings...
.ss-a-layout-can-belong-to-only-one-sheet-set = A layout can belong to only one sheet set. If a layout already belongs to a sheet set, you must create a copy of the layout to import it.
.ss-prefix-sheet-titles-with-file-name = Prefix sheet titles with file name
.ss-import-checked = Import Checked
.ss-template = Template
.ss-drawing-template-file-name = Drawing template file name
.ss-select-a-layout-to-create-new-sheets = Select a layout to create new sheets
.ss-category-name = Category name
.ss-select-the-callout-blocks = Select the callout blocks to be used in this category
.ss-selected-blocks-will-be-available = Selected blocks will be available for selection when you insert a callout block from the view tab.
.ss-add-blocks = Add Blocks...
.ss-layout-and-drawing-not-deleted = (The layout and the drawing file will not be deleted.)
.ss-remove-sheet-question = Are you sure that you want to remove __ocs_fmt_0__ Sheet from __ocs_fmt_1__ Sheet Set?
.ss-drawing-open-cannot-rename = The drawing is open; close it to rename its file.
.ss-category-name-empty = The category name cannot be empty.
.ss-associate-hyperlink = Associate hyperlink
.ss-remove-sheet = Remove Sheet
.ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set.
.ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets.
+39
View File
@@ -4392,6 +4392,45 @@ view =
.ss-new-sheet-location = New sheet location
.ss-remove-subset = Remove Subset
.ss-rename-subset = Rename Subset...
.ss-status-missing = missing
.ss-status-open = open
.ss-view-by-category = View by category
.ss-view-by-sheet = View by sheet
.ss-import-layouts-as-sheets = Import Layouts as Sheets
.ss-remove-sheets = Remove Sheets
.ss-view-category = View Category
.ss-new-view-category = New View Category...
.ss-add-new-location = Add New Location...
.ss-remove-location = Remove Location
.ss-publish-by-sheet = Publish by Sheet 'Include for Publish' Setting
.ss-do-not-publish-sheets = Do Not Publish Sheets
.ss-open-in-drawing-editor = Open in drawing editor
.ss-create-folder-hierarchy = Create folder hierarchy
.ss-publish-sheets-in-subset = Publish sheets in subset
.ss-rename-options = Rename options
.ss-rename-layout-to-match = Rename layout to match:
.ss-prefix-with-sheet-number = Prefix with sheet number
.ss-rename-drawing-file-to-match = Rename drawing file to match:
.ss-available-for-import = Available for import
.ss-belongs-to-sheet-set = Belongs to sheet set __ocs_fmt_0__
.ss-drawings = Drawings
.ss-select-drawing-files-containing-layouts = Select drawing files containing layouts
.ss-browse-for-drawings = Browse for Drawings...
.ss-a-layout-can-belong-to-only-one-sheet-set = A layout can belong to only one sheet set. If a layout already belongs to a sheet set, you must create a copy of the layout to import it.
.ss-prefix-sheet-titles-with-file-name = Prefix sheet titles with file name
.ss-import-checked = Import Checked
.ss-template = Template
.ss-drawing-template-file-name = Drawing template file name
.ss-select-a-layout-to-create-new-sheets = Select a layout to create new sheets
.ss-category-name = Category name
.ss-select-the-callout-blocks = Select the callout blocks to be used in this category
.ss-selected-blocks-will-be-available = Selected blocks will be available for selection when you insert a callout block from the view tab.
.ss-add-blocks = Add Blocks...
.ss-layout-and-drawing-not-deleted = (The layout and the drawing file will not be deleted.)
.ss-remove-sheet-question = Are you sure that you want to remove __ocs_fmt_0__ Sheet from __ocs_fmt_1__ Sheet Set?
.ss-drawing-open-cannot-rename = The drawing is open; close it to rename its file.
.ss-category-name-empty = The category name cannot be empty.
.ss-associate-hyperlink = Associate hyperlink
.ss-remove-sheet = Remove Sheet
.ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set.
.ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets.
+39
View File
@@ -4393,6 +4393,45 @@ view =
.ss-new-sheet-location = New sheet location
.ss-remove-subset = Remove Subset
.ss-rename-subset = Rename Subset...
.ss-status-missing = missing
.ss-status-open = open
.ss-view-by-category = View by category
.ss-view-by-sheet = View by sheet
.ss-import-layouts-as-sheets = Import Layouts as Sheets
.ss-remove-sheets = Remove Sheets
.ss-view-category = View Category
.ss-new-view-category = New View Category...
.ss-add-new-location = Add New Location...
.ss-remove-location = Remove Location
.ss-publish-by-sheet = Publish by Sheet 'Include for Publish' Setting
.ss-do-not-publish-sheets = Do Not Publish Sheets
.ss-open-in-drawing-editor = Open in drawing editor
.ss-create-folder-hierarchy = Create folder hierarchy
.ss-publish-sheets-in-subset = Publish sheets in subset
.ss-rename-options = Rename options
.ss-rename-layout-to-match = Rename layout to match:
.ss-prefix-with-sheet-number = Prefix with sheet number
.ss-rename-drawing-file-to-match = Rename drawing file to match:
.ss-available-for-import = Available for import
.ss-belongs-to-sheet-set = Belongs to sheet set __ocs_fmt_0__
.ss-drawings = Drawings
.ss-select-drawing-files-containing-layouts = Select drawing files containing layouts
.ss-browse-for-drawings = Browse for Drawings...
.ss-a-layout-can-belong-to-only-one-sheet-set = A layout can belong to only one sheet set. If a layout already belongs to a sheet set, you must create a copy of the layout to import it.
.ss-prefix-sheet-titles-with-file-name = Prefix sheet titles with file name
.ss-import-checked = Import Checked
.ss-template = Template
.ss-drawing-template-file-name = Drawing template file name
.ss-select-a-layout-to-create-new-sheets = Select a layout to create new sheets
.ss-category-name = Category name
.ss-select-the-callout-blocks = Select the callout blocks to be used in this category
.ss-selected-blocks-will-be-available = Selected blocks will be available for selection when you insert a callout block from the view tab.
.ss-add-blocks = Add Blocks...
.ss-layout-and-drawing-not-deleted = (The layout and the drawing file will not be deleted.)
.ss-remove-sheet-question = Are you sure that you want to remove __ocs_fmt_0__ Sheet from __ocs_fmt_1__ Sheet Set?
.ss-drawing-open-cannot-rename = The drawing is open; close it to rename its file.
.ss-category-name-empty = The category name cannot be empty.
.ss-associate-hyperlink = Associate hyperlink
.ss-remove-sheet = Remove Sheet
.ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set.
.ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets.
+39
View File
@@ -4395,6 +4395,45 @@ view =
.ss-new-sheet-location = New sheet location
.ss-remove-subset = Remove Subset
.ss-rename-subset = Rename Subset...
.ss-status-missing = missing
.ss-status-open = open
.ss-view-by-category = View by category
.ss-view-by-sheet = View by sheet
.ss-import-layouts-as-sheets = Import Layouts as Sheets
.ss-remove-sheets = Remove Sheets
.ss-view-category = View Category
.ss-new-view-category = New View Category...
.ss-add-new-location = Add New Location...
.ss-remove-location = Remove Location
.ss-publish-by-sheet = Publish by Sheet 'Include for Publish' Setting
.ss-do-not-publish-sheets = Do Not Publish Sheets
.ss-open-in-drawing-editor = Open in drawing editor
.ss-create-folder-hierarchy = Create folder hierarchy
.ss-publish-sheets-in-subset = Publish sheets in subset
.ss-rename-options = Rename options
.ss-rename-layout-to-match = Rename layout to match:
.ss-prefix-with-sheet-number = Prefix with sheet number
.ss-rename-drawing-file-to-match = Rename drawing file to match:
.ss-available-for-import = Available for import
.ss-belongs-to-sheet-set = Belongs to sheet set __ocs_fmt_0__
.ss-drawings = Drawings
.ss-select-drawing-files-containing-layouts = Select drawing files containing layouts
.ss-browse-for-drawings = Browse for Drawings...
.ss-a-layout-can-belong-to-only-one-sheet-set = A layout can belong to only one sheet set. If a layout already belongs to a sheet set, you must create a copy of the layout to import it.
.ss-prefix-sheet-titles-with-file-name = Prefix sheet titles with file name
.ss-import-checked = Import Checked
.ss-template = Template
.ss-drawing-template-file-name = Drawing template file name
.ss-select-a-layout-to-create-new-sheets = Select a layout to create new sheets
.ss-category-name = Category name
.ss-select-the-callout-blocks = Select the callout blocks to be used in this category
.ss-selected-blocks-will-be-available = Selected blocks will be available for selection when you insert a callout block from the view tab.
.ss-add-blocks = Add Blocks...
.ss-layout-and-drawing-not-deleted = (The layout and the drawing file will not be deleted.)
.ss-remove-sheet-question = Are you sure that you want to remove __ocs_fmt_0__ Sheet from __ocs_fmt_1__ Sheet Set?
.ss-drawing-open-cannot-rename = The drawing is open; close it to rename its file.
.ss-category-name-empty = The category name cannot be empty.
.ss-associate-hyperlink = Associate hyperlink
.ss-remove-sheet = Remove Sheet
.ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set.
.ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets.
+39
View File
@@ -4396,6 +4396,45 @@ view =
.ss-new-sheet-location = New sheet location
.ss-remove-subset = Remove Subset
.ss-rename-subset = Rename Subset...
.ss-status-missing = missing
.ss-status-open = open
.ss-view-by-category = View by category
.ss-view-by-sheet = View by sheet
.ss-import-layouts-as-sheets = Import Layouts as Sheets
.ss-remove-sheets = Remove Sheets
.ss-view-category = View Category
.ss-new-view-category = New View Category...
.ss-add-new-location = Add New Location...
.ss-remove-location = Remove Location
.ss-publish-by-sheet = Publish by Sheet 'Include for Publish' Setting
.ss-do-not-publish-sheets = Do Not Publish Sheets
.ss-open-in-drawing-editor = Open in drawing editor
.ss-create-folder-hierarchy = Create folder hierarchy
.ss-publish-sheets-in-subset = Publish sheets in subset
.ss-rename-options = Rename options
.ss-rename-layout-to-match = Rename layout to match:
.ss-prefix-with-sheet-number = Prefix with sheet number
.ss-rename-drawing-file-to-match = Rename drawing file to match:
.ss-available-for-import = Available for import
.ss-belongs-to-sheet-set = Belongs to sheet set __ocs_fmt_0__
.ss-drawings = Drawings
.ss-select-drawing-files-containing-layouts = Select drawing files containing layouts
.ss-browse-for-drawings = Browse for Drawings...
.ss-a-layout-can-belong-to-only-one-sheet-set = A layout can belong to only one sheet set. If a layout already belongs to a sheet set, you must create a copy of the layout to import it.
.ss-prefix-sheet-titles-with-file-name = Prefix sheet titles with file name
.ss-import-checked = Import Checked
.ss-template = Template
.ss-drawing-template-file-name = Drawing template file name
.ss-select-a-layout-to-create-new-sheets = Select a layout to create new sheets
.ss-category-name = Category name
.ss-select-the-callout-blocks = Select the callout blocks to be used in this category
.ss-selected-blocks-will-be-available = Selected blocks will be available for selection when you insert a callout block from the view tab.
.ss-add-blocks = Add Blocks...
.ss-layout-and-drawing-not-deleted = (The layout and the drawing file will not be deleted.)
.ss-remove-sheet-question = Are you sure that you want to remove __ocs_fmt_0__ Sheet from __ocs_fmt_1__ Sheet Set?
.ss-drawing-open-cannot-rename = The drawing is open; close it to rename its file.
.ss-category-name-empty = The category name cannot be empty.
.ss-associate-hyperlink = Associate hyperlink
.ss-remove-sheet = Remove Sheet
.ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set.
.ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets.
+39
View File
@@ -4395,6 +4395,45 @@ view =
.ss-new-sheet-location = New sheet location
.ss-remove-subset = Remove Subset
.ss-rename-subset = Rename Subset...
.ss-status-missing = missing
.ss-status-open = open
.ss-view-by-category = View by category
.ss-view-by-sheet = View by sheet
.ss-import-layouts-as-sheets = Import Layouts as Sheets
.ss-remove-sheets = Remove Sheets
.ss-view-category = View Category
.ss-new-view-category = New View Category...
.ss-add-new-location = Add New Location...
.ss-remove-location = Remove Location
.ss-publish-by-sheet = Publish by Sheet 'Include for Publish' Setting
.ss-do-not-publish-sheets = Do Not Publish Sheets
.ss-open-in-drawing-editor = Open in drawing editor
.ss-create-folder-hierarchy = Create folder hierarchy
.ss-publish-sheets-in-subset = Publish sheets in subset
.ss-rename-options = Rename options
.ss-rename-layout-to-match = Rename layout to match:
.ss-prefix-with-sheet-number = Prefix with sheet number
.ss-rename-drawing-file-to-match = Rename drawing file to match:
.ss-available-for-import = Available for import
.ss-belongs-to-sheet-set = Belongs to sheet set __ocs_fmt_0__
.ss-drawings = Drawings
.ss-select-drawing-files-containing-layouts = Select drawing files containing layouts
.ss-browse-for-drawings = Browse for Drawings...
.ss-a-layout-can-belong-to-only-one-sheet-set = A layout can belong to only one sheet set. If a layout already belongs to a sheet set, you must create a copy of the layout to import it.
.ss-prefix-sheet-titles-with-file-name = Prefix sheet titles with file name
.ss-import-checked = Import Checked
.ss-template = Template
.ss-drawing-template-file-name = Drawing template file name
.ss-select-a-layout-to-create-new-sheets = Select a layout to create new sheets
.ss-category-name = Category name
.ss-select-the-callout-blocks = Select the callout blocks to be used in this category
.ss-selected-blocks-will-be-available = Selected blocks will be available for selection when you insert a callout block from the view tab.
.ss-add-blocks = Add Blocks...
.ss-layout-and-drawing-not-deleted = (The layout and the drawing file will not be deleted.)
.ss-remove-sheet-question = Are you sure that you want to remove __ocs_fmt_0__ Sheet from __ocs_fmt_1__ Sheet Set?
.ss-drawing-open-cannot-rename = The drawing is open; close it to rename its file.
.ss-category-name-empty = The category name cannot be empty.
.ss-associate-hyperlink = Associate hyperlink
.ss-remove-sheet = Remove Sheet
.ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set.
.ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets.
+39
View File
@@ -4394,6 +4394,45 @@ view =
.ss-new-sheet-location = New sheet location
.ss-remove-subset = Remove Subset
.ss-rename-subset = Rename Subset...
.ss-status-missing = missing
.ss-status-open = open
.ss-view-by-category = View by category
.ss-view-by-sheet = View by sheet
.ss-import-layouts-as-sheets = Import Layouts as Sheets
.ss-remove-sheets = Remove Sheets
.ss-view-category = View Category
.ss-new-view-category = New View Category...
.ss-add-new-location = Add New Location...
.ss-remove-location = Remove Location
.ss-publish-by-sheet = Publish by Sheet 'Include for Publish' Setting
.ss-do-not-publish-sheets = Do Not Publish Sheets
.ss-open-in-drawing-editor = Open in drawing editor
.ss-create-folder-hierarchy = Create folder hierarchy
.ss-publish-sheets-in-subset = Publish sheets in subset
.ss-rename-options = Rename options
.ss-rename-layout-to-match = Rename layout to match:
.ss-prefix-with-sheet-number = Prefix with sheet number
.ss-rename-drawing-file-to-match = Rename drawing file to match:
.ss-available-for-import = Available for import
.ss-belongs-to-sheet-set = Belongs to sheet set __ocs_fmt_0__
.ss-drawings = Drawings
.ss-select-drawing-files-containing-layouts = Select drawing files containing layouts
.ss-browse-for-drawings = Browse for Drawings...
.ss-a-layout-can-belong-to-only-one-sheet-set = A layout can belong to only one sheet set. If a layout already belongs to a sheet set, you must create a copy of the layout to import it.
.ss-prefix-sheet-titles-with-file-name = Prefix sheet titles with file name
.ss-import-checked = Import Checked
.ss-template = Template
.ss-drawing-template-file-name = Drawing template file name
.ss-select-a-layout-to-create-new-sheets = Select a layout to create new sheets
.ss-category-name = Category name
.ss-select-the-callout-blocks = Select the callout blocks to be used in this category
.ss-selected-blocks-will-be-available = Selected blocks will be available for selection when you insert a callout block from the view tab.
.ss-add-blocks = Add Blocks...
.ss-layout-and-drawing-not-deleted = (The layout and the drawing file will not be deleted.)
.ss-remove-sheet-question = Are you sure that you want to remove __ocs_fmt_0__ Sheet from __ocs_fmt_1__ Sheet Set?
.ss-drawing-open-cannot-rename = The drawing is open; close it to rename its file.
.ss-category-name-empty = The category name cannot be empty.
.ss-associate-hyperlink = Associate hyperlink
.ss-remove-sheet = Remove Sheet
.ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set.
.ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets.
+39
View File
@@ -4395,6 +4395,45 @@ view =
.ss-new-sheet-location = New sheet location
.ss-remove-subset = Remove Subset
.ss-rename-subset = Rename Subset...
.ss-status-missing = missing
.ss-status-open = open
.ss-view-by-category = View by category
.ss-view-by-sheet = View by sheet
.ss-import-layouts-as-sheets = Import Layouts as Sheets
.ss-remove-sheets = Remove Sheets
.ss-view-category = View Category
.ss-new-view-category = New View Category...
.ss-add-new-location = Add New Location...
.ss-remove-location = Remove Location
.ss-publish-by-sheet = Publish by Sheet 'Include for Publish' Setting
.ss-do-not-publish-sheets = Do Not Publish Sheets
.ss-open-in-drawing-editor = Open in drawing editor
.ss-create-folder-hierarchy = Create folder hierarchy
.ss-publish-sheets-in-subset = Publish sheets in subset
.ss-rename-options = Rename options
.ss-rename-layout-to-match = Rename layout to match:
.ss-prefix-with-sheet-number = Prefix with sheet number
.ss-rename-drawing-file-to-match = Rename drawing file to match:
.ss-available-for-import = Available for import
.ss-belongs-to-sheet-set = Belongs to sheet set __ocs_fmt_0__
.ss-drawings = Drawings
.ss-select-drawing-files-containing-layouts = Select drawing files containing layouts
.ss-browse-for-drawings = Browse for Drawings...
.ss-a-layout-can-belong-to-only-one-sheet-set = A layout can belong to only one sheet set. If a layout already belongs to a sheet set, you must create a copy of the layout to import it.
.ss-prefix-sheet-titles-with-file-name = Prefix sheet titles with file name
.ss-import-checked = Import Checked
.ss-template = Template
.ss-drawing-template-file-name = Drawing template file name
.ss-select-a-layout-to-create-new-sheets = Select a layout to create new sheets
.ss-category-name = Category name
.ss-select-the-callout-blocks = Select the callout blocks to be used in this category
.ss-selected-blocks-will-be-available = Selected blocks will be available for selection when you insert a callout block from the view tab.
.ss-add-blocks = Add Blocks...
.ss-layout-and-drawing-not-deleted = (The layout and the drawing file will not be deleted.)
.ss-remove-sheet-question = Are you sure that you want to remove __ocs_fmt_0__ Sheet from __ocs_fmt_1__ Sheet Set?
.ss-drawing-open-cannot-rename = The drawing is open; close it to rename its file.
.ss-category-name-empty = The category name cannot be empty.
.ss-associate-hyperlink = Associate hyperlink
.ss-remove-sheet = Remove Sheet
.ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set.
.ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets.
+39
View File
@@ -4383,6 +4383,45 @@ view =
.ss-new-sheet-location = New sheet location
.ss-remove-subset = Remove Subset
.ss-rename-subset = Rename Subset...
.ss-status-missing = missing
.ss-status-open = open
.ss-view-by-category = View by category
.ss-view-by-sheet = View by sheet
.ss-import-layouts-as-sheets = Import Layouts as Sheets
.ss-remove-sheets = Remove Sheets
.ss-view-category = View Category
.ss-new-view-category = New View Category...
.ss-add-new-location = Add New Location...
.ss-remove-location = Remove Location
.ss-publish-by-sheet = Publish by Sheet 'Include for Publish' Setting
.ss-do-not-publish-sheets = Do Not Publish Sheets
.ss-open-in-drawing-editor = Open in drawing editor
.ss-create-folder-hierarchy = Create folder hierarchy
.ss-publish-sheets-in-subset = Publish sheets in subset
.ss-rename-options = Rename options
.ss-rename-layout-to-match = Rename layout to match:
.ss-prefix-with-sheet-number = Prefix with sheet number
.ss-rename-drawing-file-to-match = Rename drawing file to match:
.ss-available-for-import = Available for import
.ss-belongs-to-sheet-set = Belongs to sheet set __ocs_fmt_0__
.ss-drawings = Drawings
.ss-select-drawing-files-containing-layouts = Select drawing files containing layouts
.ss-browse-for-drawings = Browse for Drawings...
.ss-a-layout-can-belong-to-only-one-sheet-set = A layout can belong to only one sheet set. If a layout already belongs to a sheet set, you must create a copy of the layout to import it.
.ss-prefix-sheet-titles-with-file-name = Prefix sheet titles with file name
.ss-import-checked = Import Checked
.ss-template = Template
.ss-drawing-template-file-name = Drawing template file name
.ss-select-a-layout-to-create-new-sheets = Select a layout to create new sheets
.ss-category-name = Category name
.ss-select-the-callout-blocks = Select the callout blocks to be used in this category
.ss-selected-blocks-will-be-available = Selected blocks will be available for selection when you insert a callout block from the view tab.
.ss-add-blocks = Add Blocks...
.ss-layout-and-drawing-not-deleted = (The layout and the drawing file will not be deleted.)
.ss-remove-sheet-question = Are you sure that you want to remove __ocs_fmt_0__ Sheet from __ocs_fmt_1__ Sheet Set?
.ss-drawing-open-cannot-rename = The drawing is open; close it to rename its file.
.ss-category-name-empty = The category name cannot be empty.
.ss-associate-hyperlink = Associate hyperlink
.ss-remove-sheet = Remove Sheet
.ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set.
.ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets.
+39
View File
@@ -4394,6 +4394,45 @@ view =
.ss-new-sheet-location = New sheet location
.ss-remove-subset = Remove Subset
.ss-rename-subset = Rename Subset...
.ss-status-missing = missing
.ss-status-open = open
.ss-view-by-category = View by category
.ss-view-by-sheet = View by sheet
.ss-import-layouts-as-sheets = Import Layouts as Sheets
.ss-remove-sheets = Remove Sheets
.ss-view-category = View Category
.ss-new-view-category = New View Category...
.ss-add-new-location = Add New Location...
.ss-remove-location = Remove Location
.ss-publish-by-sheet = Publish by Sheet 'Include for Publish' Setting
.ss-do-not-publish-sheets = Do Not Publish Sheets
.ss-open-in-drawing-editor = Open in drawing editor
.ss-create-folder-hierarchy = Create folder hierarchy
.ss-publish-sheets-in-subset = Publish sheets in subset
.ss-rename-options = Rename options
.ss-rename-layout-to-match = Rename layout to match:
.ss-prefix-with-sheet-number = Prefix with sheet number
.ss-rename-drawing-file-to-match = Rename drawing file to match:
.ss-available-for-import = Available for import
.ss-belongs-to-sheet-set = Belongs to sheet set __ocs_fmt_0__
.ss-drawings = Drawings
.ss-select-drawing-files-containing-layouts = Select drawing files containing layouts
.ss-browse-for-drawings = Browse for Drawings...
.ss-a-layout-can-belong-to-only-one-sheet-set = A layout can belong to only one sheet set. If a layout already belongs to a sheet set, you must create a copy of the layout to import it.
.ss-prefix-sheet-titles-with-file-name = Prefix sheet titles with file name
.ss-import-checked = Import Checked
.ss-template = Template
.ss-drawing-template-file-name = Drawing template file name
.ss-select-a-layout-to-create-new-sheets = Select a layout to create new sheets
.ss-category-name = Category name
.ss-select-the-callout-blocks = Select the callout blocks to be used in this category
.ss-selected-blocks-will-be-available = Selected blocks will be available for selection when you insert a callout block from the view tab.
.ss-add-blocks = Add Blocks...
.ss-layout-and-drawing-not-deleted = (The layout and the drawing file will not be deleted.)
.ss-remove-sheet-question = Are you sure that you want to remove __ocs_fmt_0__ Sheet from __ocs_fmt_1__ Sheet Set?
.ss-drawing-open-cannot-rename = The drawing is open; close it to rename its file.
.ss-category-name-empty = The category name cannot be empty.
.ss-associate-hyperlink = Associate hyperlink
.ss-remove-sheet = Remove Sheet
.ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set.
.ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets.
+39
View File
@@ -4394,6 +4394,45 @@ view =
.ss-new-sheet-location = New sheet location
.ss-remove-subset = Remove Subset
.ss-rename-subset = Rename Subset...
.ss-status-missing = missing
.ss-status-open = open
.ss-view-by-category = View by category
.ss-view-by-sheet = View by sheet
.ss-import-layouts-as-sheets = Import Layouts as Sheets
.ss-remove-sheets = Remove Sheets
.ss-view-category = View Category
.ss-new-view-category = New View Category...
.ss-add-new-location = Add New Location...
.ss-remove-location = Remove Location
.ss-publish-by-sheet = Publish by Sheet 'Include for Publish' Setting
.ss-do-not-publish-sheets = Do Not Publish Sheets
.ss-open-in-drawing-editor = Open in drawing editor
.ss-create-folder-hierarchy = Create folder hierarchy
.ss-publish-sheets-in-subset = Publish sheets in subset
.ss-rename-options = Rename options
.ss-rename-layout-to-match = Rename layout to match:
.ss-prefix-with-sheet-number = Prefix with sheet number
.ss-rename-drawing-file-to-match = Rename drawing file to match:
.ss-available-for-import = Available for import
.ss-belongs-to-sheet-set = Belongs to sheet set __ocs_fmt_0__
.ss-drawings = Drawings
.ss-select-drawing-files-containing-layouts = Select drawing files containing layouts
.ss-browse-for-drawings = Browse for Drawings...
.ss-a-layout-can-belong-to-only-one-sheet-set = A layout can belong to only one sheet set. If a layout already belongs to a sheet set, you must create a copy of the layout to import it.
.ss-prefix-sheet-titles-with-file-name = Prefix sheet titles with file name
.ss-import-checked = Import Checked
.ss-template = Template
.ss-drawing-template-file-name = Drawing template file name
.ss-select-a-layout-to-create-new-sheets = Select a layout to create new sheets
.ss-category-name = Category name
.ss-select-the-callout-blocks = Select the callout blocks to be used in this category
.ss-selected-blocks-will-be-available = Selected blocks will be available for selection when you insert a callout block from the view tab.
.ss-add-blocks = Add Blocks...
.ss-layout-and-drawing-not-deleted = (The layout and the drawing file will not be deleted.)
.ss-remove-sheet-question = Are you sure that you want to remove __ocs_fmt_0__ Sheet from __ocs_fmt_1__ Sheet Set?
.ss-drawing-open-cannot-rename = The drawing is open; close it to rename its file.
.ss-category-name-empty = The category name cannot be empty.
.ss-associate-hyperlink = Associate hyperlink
.ss-remove-sheet = Remove Sheet
.ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set.
.ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets.
+39
View File
@@ -4383,6 +4383,45 @@ view =
.ss-new-sheet-location = New sheet location
.ss-remove-subset = Remove Subset
.ss-rename-subset = Rename Subset...
.ss-status-missing = missing
.ss-status-open = open
.ss-view-by-category = View by category
.ss-view-by-sheet = View by sheet
.ss-import-layouts-as-sheets = Import Layouts as Sheets
.ss-remove-sheets = Remove Sheets
.ss-view-category = View Category
.ss-new-view-category = New View Category...
.ss-add-new-location = Add New Location...
.ss-remove-location = Remove Location
.ss-publish-by-sheet = Publish by Sheet 'Include for Publish' Setting
.ss-do-not-publish-sheets = Do Not Publish Sheets
.ss-open-in-drawing-editor = Open in drawing editor
.ss-create-folder-hierarchy = Create folder hierarchy
.ss-publish-sheets-in-subset = Publish sheets in subset
.ss-rename-options = Rename options
.ss-rename-layout-to-match = Rename layout to match:
.ss-prefix-with-sheet-number = Prefix with sheet number
.ss-rename-drawing-file-to-match = Rename drawing file to match:
.ss-available-for-import = Available for import
.ss-belongs-to-sheet-set = Belongs to sheet set __ocs_fmt_0__
.ss-drawings = Drawings
.ss-select-drawing-files-containing-layouts = Select drawing files containing layouts
.ss-browse-for-drawings = Browse for Drawings...
.ss-a-layout-can-belong-to-only-one-sheet-set = A layout can belong to only one sheet set. If a layout already belongs to a sheet set, you must create a copy of the layout to import it.
.ss-prefix-sheet-titles-with-file-name = Prefix sheet titles with file name
.ss-import-checked = Import Checked
.ss-template = Template
.ss-drawing-template-file-name = Drawing template file name
.ss-select-a-layout-to-create-new-sheets = Select a layout to create new sheets
.ss-category-name = Category name
.ss-select-the-callout-blocks = Select the callout blocks to be used in this category
.ss-selected-blocks-will-be-available = Selected blocks will be available for selection when you insert a callout block from the view tab.
.ss-add-blocks = Add Blocks...
.ss-layout-and-drawing-not-deleted = (The layout and the drawing file will not be deleted.)
.ss-remove-sheet-question = Are you sure that you want to remove __ocs_fmt_0__ Sheet from __ocs_fmt_1__ Sheet Set?
.ss-drawing-open-cannot-rename = The drawing is open; close it to rename its file.
.ss-category-name-empty = The category name cannot be empty.
.ss-associate-hyperlink = Associate hyperlink
.ss-remove-sheet = Remove Sheet
.ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set.
.ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets.
+39
View File
@@ -4394,6 +4394,45 @@ view =
.ss-new-sheet-location = New sheet location
.ss-remove-subset = Remove Subset
.ss-rename-subset = Rename Subset...
.ss-status-missing = missing
.ss-status-open = open
.ss-view-by-category = View by category
.ss-view-by-sheet = View by sheet
.ss-import-layouts-as-sheets = Import Layouts as Sheets
.ss-remove-sheets = Remove Sheets
.ss-view-category = View Category
.ss-new-view-category = New View Category...
.ss-add-new-location = Add New Location...
.ss-remove-location = Remove Location
.ss-publish-by-sheet = Publish by Sheet 'Include for Publish' Setting
.ss-do-not-publish-sheets = Do Not Publish Sheets
.ss-open-in-drawing-editor = Open in drawing editor
.ss-create-folder-hierarchy = Create folder hierarchy
.ss-publish-sheets-in-subset = Publish sheets in subset
.ss-rename-options = Rename options
.ss-rename-layout-to-match = Rename layout to match:
.ss-prefix-with-sheet-number = Prefix with sheet number
.ss-rename-drawing-file-to-match = Rename drawing file to match:
.ss-available-for-import = Available for import
.ss-belongs-to-sheet-set = Belongs to sheet set __ocs_fmt_0__
.ss-drawings = Drawings
.ss-select-drawing-files-containing-layouts = Select drawing files containing layouts
.ss-browse-for-drawings = Browse for Drawings...
.ss-a-layout-can-belong-to-only-one-sheet-set = A layout can belong to only one sheet set. If a layout already belongs to a sheet set, you must create a copy of the layout to import it.
.ss-prefix-sheet-titles-with-file-name = Prefix sheet titles with file name
.ss-import-checked = Import Checked
.ss-template = Template
.ss-drawing-template-file-name = Drawing template file name
.ss-select-a-layout-to-create-new-sheets = Select a layout to create new sheets
.ss-category-name = Category name
.ss-select-the-callout-blocks = Select the callout blocks to be used in this category
.ss-selected-blocks-will-be-available = Selected blocks will be available for selection when you insert a callout block from the view tab.
.ss-add-blocks = Add Blocks...
.ss-layout-and-drawing-not-deleted = (The layout and the drawing file will not be deleted.)
.ss-remove-sheet-question = Are you sure that you want to remove __ocs_fmt_0__ Sheet from __ocs_fmt_1__ Sheet Set?
.ss-drawing-open-cannot-rename = The drawing is open; close it to rename its file.
.ss-category-name-empty = The category name cannot be empty.
.ss-associate-hyperlink = Associate hyperlink
.ss-remove-sheet = Remove Sheet
.ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set.
.ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets.
+39
View File
@@ -4393,6 +4393,45 @@ view =
.ss-new-sheet-location = New sheet location
.ss-remove-subset = Remove Subset
.ss-rename-subset = Rename Subset...
.ss-status-missing = missing
.ss-status-open = open
.ss-view-by-category = View by category
.ss-view-by-sheet = View by sheet
.ss-import-layouts-as-sheets = Import Layouts as Sheets
.ss-remove-sheets = Remove Sheets
.ss-view-category = View Category
.ss-new-view-category = New View Category...
.ss-add-new-location = Add New Location...
.ss-remove-location = Remove Location
.ss-publish-by-sheet = Publish by Sheet 'Include for Publish' Setting
.ss-do-not-publish-sheets = Do Not Publish Sheets
.ss-open-in-drawing-editor = Open in drawing editor
.ss-create-folder-hierarchy = Create folder hierarchy
.ss-publish-sheets-in-subset = Publish sheets in subset
.ss-rename-options = Rename options
.ss-rename-layout-to-match = Rename layout to match:
.ss-prefix-with-sheet-number = Prefix with sheet number
.ss-rename-drawing-file-to-match = Rename drawing file to match:
.ss-available-for-import = Available for import
.ss-belongs-to-sheet-set = Belongs to sheet set __ocs_fmt_0__
.ss-drawings = Drawings
.ss-select-drawing-files-containing-layouts = Select drawing files containing layouts
.ss-browse-for-drawings = Browse for Drawings...
.ss-a-layout-can-belong-to-only-one-sheet-set = A layout can belong to only one sheet set. If a layout already belongs to a sheet set, you must create a copy of the layout to import it.
.ss-prefix-sheet-titles-with-file-name = Prefix sheet titles with file name
.ss-import-checked = Import Checked
.ss-template = Template
.ss-drawing-template-file-name = Drawing template file name
.ss-select-a-layout-to-create-new-sheets = Select a layout to create new sheets
.ss-category-name = Category name
.ss-select-the-callout-blocks = Select the callout blocks to be used in this category
.ss-selected-blocks-will-be-available = Selected blocks will be available for selection when you insert a callout block from the view tab.
.ss-add-blocks = Add Blocks...
.ss-layout-and-drawing-not-deleted = (The layout and the drawing file will not be deleted.)
.ss-remove-sheet-question = Are you sure that you want to remove __ocs_fmt_0__ Sheet from __ocs_fmt_1__ Sheet Set?
.ss-drawing-open-cannot-rename = The drawing is open; close it to rename its file.
.ss-category-name-empty = The category name cannot be empty.
.ss-associate-hyperlink = Associate hyperlink
.ss-remove-sheet = Remove Sheet
.ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set.
.ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets.
+39
View File
@@ -4394,6 +4394,45 @@ view =
.ss-new-sheet-location = New sheet location
.ss-remove-subset = Remove Subset
.ss-rename-subset = Rename Subset...
.ss-status-missing = missing
.ss-status-open = open
.ss-view-by-category = View by category
.ss-view-by-sheet = View by sheet
.ss-import-layouts-as-sheets = Import Layouts as Sheets
.ss-remove-sheets = Remove Sheets
.ss-view-category = View Category
.ss-new-view-category = New View Category...
.ss-add-new-location = Add New Location...
.ss-remove-location = Remove Location
.ss-publish-by-sheet = Publish by Sheet 'Include for Publish' Setting
.ss-do-not-publish-sheets = Do Not Publish Sheets
.ss-open-in-drawing-editor = Open in drawing editor
.ss-create-folder-hierarchy = Create folder hierarchy
.ss-publish-sheets-in-subset = Publish sheets in subset
.ss-rename-options = Rename options
.ss-rename-layout-to-match = Rename layout to match:
.ss-prefix-with-sheet-number = Prefix with sheet number
.ss-rename-drawing-file-to-match = Rename drawing file to match:
.ss-available-for-import = Available for import
.ss-belongs-to-sheet-set = Belongs to sheet set __ocs_fmt_0__
.ss-drawings = Drawings
.ss-select-drawing-files-containing-layouts = Select drawing files containing layouts
.ss-browse-for-drawings = Browse for Drawings...
.ss-a-layout-can-belong-to-only-one-sheet-set = A layout can belong to only one sheet set. If a layout already belongs to a sheet set, you must create a copy of the layout to import it.
.ss-prefix-sheet-titles-with-file-name = Prefix sheet titles with file name
.ss-import-checked = Import Checked
.ss-template = Template
.ss-drawing-template-file-name = Drawing template file name
.ss-select-a-layout-to-create-new-sheets = Select a layout to create new sheets
.ss-category-name = Category name
.ss-select-the-callout-blocks = Select the callout blocks to be used in this category
.ss-selected-blocks-will-be-available = Selected blocks will be available for selection when you insert a callout block from the view tab.
.ss-add-blocks = Add Blocks...
.ss-layout-and-drawing-not-deleted = (The layout and the drawing file will not be deleted.)
.ss-remove-sheet-question = Are you sure that you want to remove __ocs_fmt_0__ Sheet from __ocs_fmt_1__ Sheet Set?
.ss-drawing-open-cannot-rename = The drawing is open; close it to rename its file.
.ss-category-name-empty = The category name cannot be empty.
.ss-associate-hyperlink = Associate hyperlink
.ss-remove-sheet = Remove Sheet
.ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set.
.ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets.
+39
View File
@@ -4395,6 +4395,45 @@ view =
.ss-new-sheet-location = New sheet location
.ss-remove-subset = Remove Subset
.ss-rename-subset = Rename Subset...
.ss-status-missing = missing
.ss-status-open = open
.ss-view-by-category = View by category
.ss-view-by-sheet = View by sheet
.ss-import-layouts-as-sheets = Import Layouts as Sheets
.ss-remove-sheets = Remove Sheets
.ss-view-category = View Category
.ss-new-view-category = New View Category...
.ss-add-new-location = Add New Location...
.ss-remove-location = Remove Location
.ss-publish-by-sheet = Publish by Sheet 'Include for Publish' Setting
.ss-do-not-publish-sheets = Do Not Publish Sheets
.ss-open-in-drawing-editor = Open in drawing editor
.ss-create-folder-hierarchy = Create folder hierarchy
.ss-publish-sheets-in-subset = Publish sheets in subset
.ss-rename-options = Rename options
.ss-rename-layout-to-match = Rename layout to match:
.ss-prefix-with-sheet-number = Prefix with sheet number
.ss-rename-drawing-file-to-match = Rename drawing file to match:
.ss-available-for-import = Available for import
.ss-belongs-to-sheet-set = Belongs to sheet set __ocs_fmt_0__
.ss-drawings = Drawings
.ss-select-drawing-files-containing-layouts = Select drawing files containing layouts
.ss-browse-for-drawings = Browse for Drawings...
.ss-a-layout-can-belong-to-only-one-sheet-set = A layout can belong to only one sheet set. If a layout already belongs to a sheet set, you must create a copy of the layout to import it.
.ss-prefix-sheet-titles-with-file-name = Prefix sheet titles with file name
.ss-import-checked = Import Checked
.ss-template = Template
.ss-drawing-template-file-name = Drawing template file name
.ss-select-a-layout-to-create-new-sheets = Select a layout to create new sheets
.ss-category-name = Category name
.ss-select-the-callout-blocks = Select the callout blocks to be used in this category
.ss-selected-blocks-will-be-available = Selected blocks will be available for selection when you insert a callout block from the view tab.
.ss-add-blocks = Add Blocks...
.ss-layout-and-drawing-not-deleted = (The layout and the drawing file will not be deleted.)
.ss-remove-sheet-question = Are you sure that you want to remove __ocs_fmt_0__ Sheet from __ocs_fmt_1__ Sheet Set?
.ss-drawing-open-cannot-rename = The drawing is open; close it to rename its file.
.ss-category-name-empty = The category name cannot be empty.
.ss-associate-hyperlink = Associate hyperlink
.ss-remove-sheet = Remove Sheet
.ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set.
.ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets.
+39
View File
@@ -4396,6 +4396,45 @@ view =
.ss-new-sheet-location = New sheet location
.ss-remove-subset = Remove Subset
.ss-rename-subset = Rename Subset...
.ss-status-missing = missing
.ss-status-open = open
.ss-view-by-category = View by category
.ss-view-by-sheet = View by sheet
.ss-import-layouts-as-sheets = Import Layouts as Sheets
.ss-remove-sheets = Remove Sheets
.ss-view-category = View Category
.ss-new-view-category = New View Category...
.ss-add-new-location = Add New Location...
.ss-remove-location = Remove Location
.ss-publish-by-sheet = Publish by Sheet 'Include for Publish' Setting
.ss-do-not-publish-sheets = Do Not Publish Sheets
.ss-open-in-drawing-editor = Open in drawing editor
.ss-create-folder-hierarchy = Create folder hierarchy
.ss-publish-sheets-in-subset = Publish sheets in subset
.ss-rename-options = Rename options
.ss-rename-layout-to-match = Rename layout to match:
.ss-prefix-with-sheet-number = Prefix with sheet number
.ss-rename-drawing-file-to-match = Rename drawing file to match:
.ss-available-for-import = Available for import
.ss-belongs-to-sheet-set = Belongs to sheet set __ocs_fmt_0__
.ss-drawings = Drawings
.ss-select-drawing-files-containing-layouts = Select drawing files containing layouts
.ss-browse-for-drawings = Browse for Drawings...
.ss-a-layout-can-belong-to-only-one-sheet-set = A layout can belong to only one sheet set. If a layout already belongs to a sheet set, you must create a copy of the layout to import it.
.ss-prefix-sheet-titles-with-file-name = Prefix sheet titles with file name
.ss-import-checked = Import Checked
.ss-template = Template
.ss-drawing-template-file-name = Drawing template file name
.ss-select-a-layout-to-create-new-sheets = Select a layout to create new sheets
.ss-category-name = Category name
.ss-select-the-callout-blocks = Select the callout blocks to be used in this category
.ss-selected-blocks-will-be-available = Selected blocks will be available for selection when you insert a callout block from the view tab.
.ss-add-blocks = Add Blocks...
.ss-layout-and-drawing-not-deleted = (The layout and the drawing file will not be deleted.)
.ss-remove-sheet-question = Are you sure that you want to remove __ocs_fmt_0__ Sheet from __ocs_fmt_1__ Sheet Set?
.ss-drawing-open-cannot-rename = The drawing is open; close it to rename its file.
.ss-category-name-empty = The category name cannot be empty.
.ss-associate-hyperlink = Associate hyperlink
.ss-remove-sheet = Remove Sheet
.ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set.
.ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets.
+39
View File
@@ -4355,6 +4355,45 @@ view =
.ss-new-sheet-location = Yeni sayfa konumu
.ss-remove-subset = Alt Kümeyi Kaldır
.ss-rename-subset = Alt Kümeyi Yeniden Adlandır...
.ss-status-missing = yok
.ss-status-open = açık
.ss-view-by-category = Kategoriye göre
.ss-view-by-sheet = Sayfaya göre
.ss-import-layouts-as-sheets = Düzenleri Sayfa Olarak İçe Aktar
.ss-remove-sheets = Sayfaları Kaldır
.ss-view-category = Görünüm Kategorisi
.ss-new-view-category = Yeni Görünüm Kategorisi…
.ss-add-new-location = Yeni Konum Ekle…
.ss-remove-location = Konumu Kaldır
.ss-publish-by-sheet = Sayfanın 'Yayımlamaya dahil et' ayarına göre
.ss-do-not-publish-sheets = Sayfaları yayımlama
.ss-open-in-drawing-editor = Çizim düzenleyicide aç
.ss-create-folder-hierarchy = Klasör hiyerarşisi oluştur
.ss-publish-sheets-in-subset = Alt kümedeki sayfaları yayımla
.ss-rename-options = Yeniden adlandırma seçenekleri
.ss-rename-layout-to-match = Düzeni eşleşecek şekilde adlandır:
.ss-prefix-with-sheet-number = Önüne sayfa numarası
.ss-rename-drawing-file-to-match = Çizim dosyasını eşleşecek şekilde adlandır:
.ss-available-for-import = Hazır
.ss-belongs-to-sheet-set = Başka kümede: __ocs_fmt_0__
.ss-drawings = Çizimler
.ss-select-drawing-files-containing-layouts = Düzen içeren çizim dosyalarını seçin
.ss-browse-for-drawings = Çizimlere Gözat…
.ss-a-layout-can-belong-to-only-one-sheet-set = Bir düzen yalnız bir sayfa kümesine ait olabilir. Başka bir kümeye ait düzeni içe aktarmak için düzenin kopyasını oluşturun.
.ss-prefix-sheet-titles-with-file-name = Sayfa başlıklarına dosya adını önek olarak ekle
.ss-import-checked = İşaretlileri İçe Aktar
.ss-template = Şablon
.ss-drawing-template-file-name = Çizim şablonu dosya adı
.ss-select-a-layout-to-create-new-sheets = Yeni sayfalar için bir düzen seçin
.ss-category-name = Kategori adı
.ss-select-the-callout-blocks = Bu kategoride kullanılacak açıklama blokları
.ss-selected-blocks-will-be-available = Seçilen bloklar görünüm sekmesinden açıklama bloğu eklerken sunulur.
.ss-add-blocks = Blok Ekle…
.ss-layout-and-drawing-not-deleted = (Düzen ve çizim dosyası silinmez.)
.ss-remove-sheet-question = "__ocs_fmt_0__" sayfası "__ocs_fmt_1__" sayfa kümesinden kaldırılsın mı?
.ss-drawing-open-cannot-rename = Çizim açık; dosyasını yeniden adlandırmak için kapatın.
.ss-category-name-empty = Kategori adı boş olamaz.
.ss-associate-hyperlink = Köprü ilişkilendir
.ss-remove-sheet = Sayfayı Kaldır
.ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Çizim içeren bir veya daha fazla klasör belirtmenizi sağlar. Bu çizimlerdeki düzenler sayfa kümesine otomatik olarak aktarılabilir.
.ss-creates-a-sheet-set-with-no-subsets-or-sheets = Alt kümesi ve sayfası olmayan bir sayfa kümesi oluşturur.
+39
View File
@@ -4378,6 +4378,45 @@ view =
.ss-new-sheet-location = New sheet location
.ss-remove-subset = Remove Subset
.ss-rename-subset = Rename Subset...
.ss-status-missing = missing
.ss-status-open = open
.ss-view-by-category = View by category
.ss-view-by-sheet = View by sheet
.ss-import-layouts-as-sheets = Import Layouts as Sheets
.ss-remove-sheets = Remove Sheets
.ss-view-category = View Category
.ss-new-view-category = New View Category...
.ss-add-new-location = Add New Location...
.ss-remove-location = Remove Location
.ss-publish-by-sheet = Publish by Sheet 'Include for Publish' Setting
.ss-do-not-publish-sheets = Do Not Publish Sheets
.ss-open-in-drawing-editor = Open in drawing editor
.ss-create-folder-hierarchy = Create folder hierarchy
.ss-publish-sheets-in-subset = Publish sheets in subset
.ss-rename-options = Rename options
.ss-rename-layout-to-match = Rename layout to match:
.ss-prefix-with-sheet-number = Prefix with sheet number
.ss-rename-drawing-file-to-match = Rename drawing file to match:
.ss-available-for-import = Available for import
.ss-belongs-to-sheet-set = Belongs to sheet set __ocs_fmt_0__
.ss-drawings = Drawings
.ss-select-drawing-files-containing-layouts = Select drawing files containing layouts
.ss-browse-for-drawings = Browse for Drawings...
.ss-a-layout-can-belong-to-only-one-sheet-set = A layout can belong to only one sheet set. If a layout already belongs to a sheet set, you must create a copy of the layout to import it.
.ss-prefix-sheet-titles-with-file-name = Prefix sheet titles with file name
.ss-import-checked = Import Checked
.ss-template = Template
.ss-drawing-template-file-name = Drawing template file name
.ss-select-a-layout-to-create-new-sheets = Select a layout to create new sheets
.ss-category-name = Category name
.ss-select-the-callout-blocks = Select the callout blocks to be used in this category
.ss-selected-blocks-will-be-available = Selected blocks will be available for selection when you insert a callout block from the view tab.
.ss-add-blocks = Add Blocks...
.ss-layout-and-drawing-not-deleted = (The layout and the drawing file will not be deleted.)
.ss-remove-sheet-question = Are you sure that you want to remove __ocs_fmt_0__ Sheet from __ocs_fmt_1__ Sheet Set?
.ss-drawing-open-cannot-rename = The drawing is open; close it to rename its file.
.ss-category-name-empty = The category name cannot be empty.
.ss-associate-hyperlink = Associate hyperlink
.ss-remove-sheet = Remove Sheet
.ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set.
.ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets.
+39
View File
@@ -4390,6 +4390,45 @@ view =
.ss-new-sheet-location = New sheet location
.ss-remove-subset = Remove Subset
.ss-rename-subset = Rename Subset...
.ss-status-missing = missing
.ss-status-open = open
.ss-view-by-category = View by category
.ss-view-by-sheet = View by sheet
.ss-import-layouts-as-sheets = Import Layouts as Sheets
.ss-remove-sheets = Remove Sheets
.ss-view-category = View Category
.ss-new-view-category = New View Category...
.ss-add-new-location = Add New Location...
.ss-remove-location = Remove Location
.ss-publish-by-sheet = Publish by Sheet 'Include for Publish' Setting
.ss-do-not-publish-sheets = Do Not Publish Sheets
.ss-open-in-drawing-editor = Open in drawing editor
.ss-create-folder-hierarchy = Create folder hierarchy
.ss-publish-sheets-in-subset = Publish sheets in subset
.ss-rename-options = Rename options
.ss-rename-layout-to-match = Rename layout to match:
.ss-prefix-with-sheet-number = Prefix with sheet number
.ss-rename-drawing-file-to-match = Rename drawing file to match:
.ss-available-for-import = Available for import
.ss-belongs-to-sheet-set = Belongs to sheet set __ocs_fmt_0__
.ss-drawings = Drawings
.ss-select-drawing-files-containing-layouts = Select drawing files containing layouts
.ss-browse-for-drawings = Browse for Drawings...
.ss-a-layout-can-belong-to-only-one-sheet-set = A layout can belong to only one sheet set. If a layout already belongs to a sheet set, you must create a copy of the layout to import it.
.ss-prefix-sheet-titles-with-file-name = Prefix sheet titles with file name
.ss-import-checked = Import Checked
.ss-template = Template
.ss-drawing-template-file-name = Drawing template file name
.ss-select-a-layout-to-create-new-sheets = Select a layout to create new sheets
.ss-category-name = Category name
.ss-select-the-callout-blocks = Select the callout blocks to be used in this category
.ss-selected-blocks-will-be-available = Selected blocks will be available for selection when you insert a callout block from the view tab.
.ss-add-blocks = Add Blocks...
.ss-layout-and-drawing-not-deleted = (The layout and the drawing file will not be deleted.)
.ss-remove-sheet-question = Are you sure that you want to remove __ocs_fmt_0__ Sheet from __ocs_fmt_1__ Sheet Set?
.ss-drawing-open-cannot-rename = The drawing is open; close it to rename its file.
.ss-category-name-empty = The category name cannot be empty.
.ss-associate-hyperlink = Associate hyperlink
.ss-remove-sheet = Remove Sheet
.ss-lets-you-specify-one-or-more-folders-containing-drawings-the = Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set.
.ss-creates-a-sheet-set-with-no-subsets-or-sheets = Creates a sheet set with no subsets or sheets.
+52 -1
View File
@@ -4,7 +4,7 @@
use crate::app::{Message, OpenCADStudio};
use crate::command::CadCommand;
use crate::modules::annotate::field_cmd::{FieldObjectPickCommand, FieldPlaceCommand, FieldTablePickCommand};
use crate::ui::window::field_dialog::{
use crate::ui::window::field_dialog::{nav_props,
fields_of, object_properties, FieldDialogMsg, FieldDialogState, FieldTarget, DATE_FORMATS,
NAMED_TYPES,
};
@@ -110,6 +110,8 @@ impl OpenCADStudio {
state.ss_set_custom = names(codec::sheet_set::CUSTOM_SHEET_SET_PROP);
state.ss_set_name = db.name().to_string();
}
state.ss_sets = self.sheet_set.sets.clone();
state.ss_set = self.sheet_set.current.unwrap_or(0);
self.field_dialog = Some(state);
self.fill_named_objects();
self.refresh_field_preview();
@@ -190,8 +192,57 @@ impl OpenCADStudio {
// Sheet set fields start in Title case.
state.text_case = if crate::ui::window::field_dialog::SHEET_SET_FIELDS.contains(&n) { 4 } else { 0 };
state.ss_custom.clear();
state.ss_node.clear();
state.ss_prop.clear();
// SheetSet starts on the set and its first property; SheetView on nothing.
if n == "SheetSet" {
if let Some(db) = state.ss_sets.get(state.ss_set) {
state.ss_node = db.sheet_set().id().to_string();
state.ss_prop = nav_props(db, &state.ss_node).first().map(|p| p.0.clone()).unwrap_or_default();
}
}
}
FieldDialogMsg::SsCustom(name) => state.ss_custom = name,
FieldDialogMsg::SsSet(k) => {
state.ss_set = k;
state.ss_node.clear();
state.ss_prop.clear();
}
FieldDialogMsg::SsNode(id) => {
state.ss_prop = state.ss_sets.get(state.ss_set).and_then(|db| nav_props(db, &id).first().map(|p| p.0.clone())).unwrap_or_default();
state.ss_node = id;
}
FieldDialogMsg::SsProp(p) => state.ss_prop = p,
FieldDialogMsg::SsHref(v) => state.ss_href = v,
FieldDialogMsg::SsBrowse => {
return Task::perform(
async {
crate::sys::file_dialog()
.set_title(crate::t!("Open Sheet Set").as_ref())
.add_filter(crate::t!("Sheet Set (*.dst)").as_ref(), &["dst", "DST"])
.pick_file()
.await
.map(|h| crate::sys::handle_path(&h))
},
|p| Message::FieldDialog(FieldDialogMsg::SsPicked(p)),
);
}
FieldDialogMsg::SsPicked(None) => {}
FieldDialogMsg::SsPicked(Some(path)) => match codec::sheet_set::SheetSetDatabase::read(&path.to_string_lossy()) {
Ok(db) => {
let key = codec::sheet_set::path_key(&path.to_string_lossy());
state.ss_set = match state.ss_sets.iter().position(|d| d.path.as_deref().is_some_and(|p| codec::sheet_set::path_key(p) == key)) {
Some(k) => k,
None => {
state.ss_sets.push(db);
state.ss_sets.len() - 1
}
};
state.ss_node.clear();
state.ss_prop.clear();
}
Err(e) => self.command_line.push_error(&format!("{}: {e}", path.display())),
},
FieldDialogMsg::SsPlaceholder(k) => {
state.ss_placeholder = k;
state.ss_custom.clear();
+578 -82
View File
@@ -4,8 +4,8 @@
use crate::app::{Message, OpenCADStudio};
use crate::ui::window::sheet_set::{
FieldId, Form, FormKind, FoundLayout, MenuAction, PropRow, Properties, RowKey, SheetSetMsg, SsDialog,
Wizard, WizardMsg,
Category, FieldId, Form, FormKind, FoundLayout, ImportRow, MenuAction, PropRow, Properties, RowKey, SheetSetMsg,
SheetStatus, SsDialog, TemplatePick, Wizard, WizardMsg,
};
use codec::sheet_set::{self as ss, ComponentKind, LayoutReference, SheetSetData, SheetSetDatabase};
use iced::Task;
@@ -63,6 +63,77 @@ fn folder_of(path: &str) -> String {
/// Template of a component for new sheets: its own `DefDwtLayout`, else
/// the nearest parent's.
/// Whether new sheets of `component` prompt for their template: its own
/// "Prompt for template", else the nearest parent's.
fn prompts_for_template(db: &SheetSetDatabase, component: &str) -> bool {
let mut id = component.to_string();
for _ in 0..32 {
let Some(el) = db.find(&id) else { return false };
if let Some(v) = el.prop("PromptForDwt") {
return !matches!(v.trim(), "" | "0");
}
match db.parent_of(&id) {
Some(p) => id = p.id().to_string(),
None => return false,
}
}
false
}
/// The layouts of a drawing that can become sheets, each with the sheet set
/// it already belongs to: the drawing's sheet link, or this set.
fn import_rows(path: &Path, db: &SheetSetDatabase) -> Result<Vec<ImportRow>, String> {
let doc = crate::io::load_file(path).map_err(|e| e.to_string())?;
let drawing = path.to_string_lossy().to_string();
let link = doc.sheet_set_data();
Ok(paper_layouts(&doc)
.into_iter()
.map(|(layout, handle)| {
let mine = db.sheet_for(&drawing, Some(&layout)).is_some_and(|s| {
s.named("Layout").and_then(|r| r.prop("Name")).is_some_and(|n| n.eq_ignore_ascii_case(&layout))
});
let owner = if mine {
Some(db.name().to_string())
} else {
link.as_ref().filter(|l| l.layout_name.eq_ignore_ascii_case(&layout) && !l.sheet_set_file_name.is_empty()).map(|l| {
SheetSetDatabase::read(&l.sheet_set_file_name)
.map(|d| d.name().to_string())
.unwrap_or_else(|_| Path::new(&l.sheet_set_file_name).file_stem().map(|s| s.to_string_lossy().to_string()).unwrap_or_default())
})
};
ImportRow { drawing: drawing.clone(), layout, handle, on: owner.is_none(), owner }
})
.collect())
}
/// Rename & Renumber: layout and file names follow the options.
fn follow_rename(f: &mut Form) {
let name = |prefix: bool| if prefix { format!("{} {}", f.number.trim(), f.title.trim()).trim().to_string() } else { f.title.trim().to_string() };
if f.rename[0] {
f.layout_name = name(f.rename[1]);
}
if f.rename[2] {
f.file_name = format!("{}.dwg", name(f.rename[3]));
}
}
fn rename_form(db: &SheetSetDatabase, set: usize, id: &str) -> Form {
let el = db.find(id);
let reference = db.layout_reference(id, "Layout").unwrap_or_default();
let file = Path::new(&reference.file_name);
Form {
kind: FormKind::Rename,
set,
component: id.to_string(),
number: el.and_then(|e| e.prop("Number")).unwrap_or("").to_string(),
title: el.and_then(|e| e.prop("Title")).unwrap_or("").to_string(),
layout_name: reference.name.clone(),
file_name: file.file_name().map(|n| n.to_string_lossy().to_string()).unwrap_or_default(),
folder: file.parent().map(|p| p.to_string_lossy().to_string()).unwrap_or_default(),
..Form::default()
}
}
fn template_of(db: &SheetSetDatabase, component: &str) -> Option<LayoutReference> {
let mut id = component.to_string();
for _ in 0..32 {
@@ -218,6 +289,12 @@ impl OpenCADStudio {
/// Publish the open sets to the field engine and redraw every field.
fn sheet_sets_changed(&mut self) {
crate::entities::field::set_sheet_sets(self.sheet_set.sets.clone());
self.refresh_locations();
if self.sheet_set.settings.sheet_status >= 1 {
self.refresh_sheet_status();
} else {
self.sheet_set.status.clear();
}
for tab in &mut self.tabs {
let changes: Vec<_> = tab
.scene
@@ -365,6 +442,7 @@ impl OpenCADStudio {
SheetSetMsg::PickSet(Some(k)) => {
if k < self.sheet_set.sets.len() {
self.sheet_set.current = Some(k);
self.sheet_sets_changed();
}
}
SheetSetMsg::PickSet(None) => return self.dispatch_command("OPENSHEETSET"),
@@ -384,7 +462,80 @@ impl OpenCADStudio {
self.sheet_set.collapsed.insert(id);
}
}
SheetSetMsg::Poll => self.poll_sheet_sets(),
SheetSetMsg::Poll => {
self.poll_sheet_sets();
// SSMSHEETSTATUS 2: the status is taken again every SSMPOLLTIME seconds.
let every = std::time::Duration::from_secs(u64::from(self.sheet_set.settings.poll_time.max(20)));
if self.sheet_set.settings.sheet_status == 2 && self.sheet_set.status_at.is_none_or(|t| t.elapsed() >= every) {
self.refresh_sheet_status();
}
}
SheetSetMsg::BrowseDrawings => {
return Task::perform(
async {
crate::sys::file_dialog()
.set_title(crate::t!("Select Drawing").as_ref())
.add_filter(crate::t!("Drawing (*.dwg)").as_ref(), &["dwg", "DWG"])
.pick_files()
.await
.map(|hs| hs.iter().map(crate::sys::handle_path).collect::<Vec<_>>())
.unwrap_or_default()
},
|p| Message::SheetSet(SheetSetMsg::ImportAdd(p)),
)
}
SheetSetMsg::ImportAdd(paths) => self.import_add(paths),
SheetSetMsg::Previous => self.rename_step(false),
SheetSetMsg::Next => self.rename_step(true),
SheetSetMsg::ViewsByCategory(v) => self.sheet_set.by_category = v,
SheetSetMsg::NewCategory => self.open_category(None),
SheetSetMsg::CategoryProperties(id) => self.open_category(Some(id)),
SheetSetMsg::CategoryRemove(id) => {
if let Some(db) = self.sheet_set.db_mut() {
db.remove(&id);
}
self.save_current_sheet_set();
}
SheetSetMsg::AddBlocks => {
return Task::perform(
async {
crate::sys::file_dialog()
.set_title(crate::t!("Select Drawing").as_ref())
.add_filter(crate::t!("Drawing (*.dwg)").as_ref(), &["dwg", "DWG", "dwt", "DWT"])
.pick_file()
.await
.map(|h| crate::sys::handle_path(&h))
},
|p| Message::SheetSet(SheetSetMsg::BlocksPicked(p)),
)
}
SheetSetMsg::BlocksPicked(Some(path)) => self.category_add_blocks(path),
SheetSetMsg::BlocksPicked(None) | SheetSetMsg::LocationPicked(None) => {}
SheetSetMsg::AddLocation => {
return Task::perform(
async {
crate::sys::file_dialog()
.set_title(crate::t!("Browse for Folder").as_ref())
.pick_folder()
.await
.map(|h| crate::sys::handle_path(&h))
},
|p| Message::SheetSet(SheetSetMsg::LocationPicked(p)),
)
}
SheetSetMsg::LocationPicked(Some(path)) => {
if let Some(db) = self.sheet_set.db_mut() {
db.add_resource(&path.to_string_lossy());
}
self.save_current_sheet_set();
}
SheetSetMsg::RemoveLocation(id) => {
if let Some(db) = self.sheet_set.db_mut() {
db.remove(&id);
}
self.save_current_sheet_set();
}
SheetSetMsg::OpenDrawing(path) => return self.update(Message::OpenRecent(PathBuf::from(path))),
SheetSetMsg::Refresh => {
if let Some(path) = self.sheet_set.db().and_then(|db| db.path.clone()) {
match SheetSetDatabase::read(&path) {
@@ -437,12 +588,52 @@ impl OpenCADStudio {
}
SheetSetMsg::Input(field, v) => self.dialog_input(field, v),
SheetSetMsg::Toggle(field, v) => {
if let (FieldId::Hierarchy, Some(SsDialog::Wizard(w))) = (field, self.sheet_set.dialog.as_mut()) {
w.hierarchy = v;
let parent_folder = match self.sheet_set.dialog.as_ref() {
Some(SsDialog::Form(f)) if f.kind == FormKind::NewSubset => {
self.sheet_set.sets.get(f.set).map(|db| sheet_folder_of(db, &f.component)).unwrap_or_default()
}
_ => String::new(),
};
match (field, self.sheet_set.dialog.as_mut()) {
(FieldId::Hierarchy, Some(SsDialog::Wizard(w))) => w.hierarchy = v,
(FieldId::Hierarchy, Some(SsDialog::Form(f))) => {
f.hierarchy = v;
f.folder = if v { Path::new(&parent_folder).join(f.title.trim()).to_string_lossy().to_string() } else { parent_folder };
}
(FieldId::Publish, Some(SsDialog::Form(f))) => f.publish = v,
(FieldId::OpenAfter, Some(SsDialog::Form(f))) => f.open_after = v,
(FieldId::ImportPrefix, Some(SsDialog::Form(f))) => f.prefix = v,
(FieldId::ImportRow(k), Some(SsDialog::Form(f))) => {
if let Some(r) = f.rows.get_mut(k) {
r.on = v && r.owner.is_none();
}
}
(FieldId::RenameOption(k), Some(SsDialog::Form(f))) => {
f.rename[k] = v;
// A prefix needs its "Sheet title" option.
if !f.rename[0] {
f.rename[1] = false;
}
if !f.rename[2] {
f.rename[3] = false;
}
follow_rename(f);
}
(FieldId::CategoryBlock(k), Some(SsDialog::Category(c))) => {
if let Some(b) = c.blocks.get_mut(k) {
b.2 = v;
}
}
(FieldId::Row(r), Some(SsDialog::Properties(p))) => {
if let Some(row) = p.rows.get_mut(r) {
row.value = if v { "Publish by Sheet 'Include for Publish' Setting" } else { "Do Not Publish Sheets" }.into();
}
}
_ => {}
}
}
SheetSetMsg::Choose(field, k) => match (field, self.sheet_set.dialog.as_mut()) {
(FieldId::Layout, Some(SsDialog::Form(f))) => f.layout = k,
(FieldId::Layout, Some(SsDialog::Template(t))) => t.layout = k,
(FieldId::CustomOwner, Some(SsDialog::Properties(p))) => {
if let Some(a) = p.adding.as_mut() {
a.2 = k == 1;
@@ -552,23 +743,26 @@ impl OpenCADStudio {
match action {
MenuAction::Open => return self.open_sheet(&id),
MenuAction::NewSheet => {
// Next number: the last sheet's number + 1 when it ends in digits.
let template = template_of(db, &id)
.map(|t| format!("{} ({})", t.name, t.file_name))
.unwrap_or_else(|| crate::t!("(default new drawing)").into_owned());
self.sheet_set.dialog = Some(SsDialog::Form(Form {
let template = template_of(db, &id);
let form = Form {
kind: FormKind::NewSheet,
set,
component: id.clone(),
number: String::new(),
title: String::new(),
file_name: String::new(),
folder: sheet_folder_of(db, &id),
drawing: template,
layouts: Vec::new(),
layout: 0,
error: None,
}));
drawing: template
.as_ref()
.map(|t| format!("{} ({})", t.name, t.file_name))
.unwrap_or_else(|| crate::t!("(default new drawing)").into_owned()),
..Form::default()
};
// A subset that prompts for its template asks for it first.
if prompts_for_template(db, &id) {
let file = template.map(|t| t.file_name).unwrap_or_default();
let layouts = crate::io::load_file(Path::new(&file)).map(|d| paper_layouts(&d).into_iter().map(|(n, _)| n).collect()).unwrap_or_default();
self.sheet_set.dialog = Some(SsDialog::Template(TemplatePick { form, file, layouts, layout: 0 }));
} else {
self.sheet_set.dialog = Some(SsDialog::Form(form));
}
self.active_modal = Some(crate::app::ModalKind::SheetSet);
}
MenuAction::NewSubset => {
@@ -583,14 +777,10 @@ impl OpenCADStudio {
kind: FormKind::NewSubset,
set,
component: id.clone(),
number: String::new(),
title: format!("New Subset ({n})"),
file_name: String::new(),
folder: sheet_folder_of(db, &id),
drawing: String::new(),
layouts: Vec::new(),
layout: 0,
error: None,
publish: true,
..Form::default()
}));
self.active_modal = Some(crate::app::ModalKind::SheetSet);
}
@@ -609,28 +799,23 @@ impl OpenCADStudio {
);
}
MenuAction::Rename => {
let el = db.find(&id);
self.sheet_set.dialog = Some(SsDialog::Form(Form {
kind: FormKind::Rename,
set,
component: id.clone(),
number: el.and_then(|e| e.prop("Number")).unwrap_or("").to_string(),
title: el.and_then(|e| e.prop("Title")).unwrap_or("").to_string(),
file_name: String::new(),
folder: String::new(),
drawing: String::new(),
layouts: Vec::new(),
layout: 0,
error: None,
}));
self.sheet_set.dialog = Some(SsDialog::Form(rename_form(db, set, &id)));
self.active_modal = Some(crate::app::ModalKind::SheetSet);
}
MenuAction::Remove => {
if let Some(db) = self.sheet_set.db_mut() {
db.remove(&id);
// A sheet asks first; a subset can only be removed while empty.
if db.find(&id).and_then(ComponentKind::of) == Some(ComponentKind::Sheet) {
let sheet = db.find(&id).map(ss::number_and_title).unwrap_or_default();
let question = crate::tf!("Are you sure that you want to remove {} Sheet from {} Sheet Set?", sheet, db.name()).into_owned();
self.sheet_set.dialog = Some(SsDialog::Confirm(set, id.clone(), question));
self.active_modal = Some(crate::app::ModalKind::SheetSet);
} else if db.find(&id).is_some_and(|el| el.children.iter().all(|c| ComponentKind::of(c).is_none())) {
if let Some(db) = self.sheet_set.db_mut() {
db.remove(&id);
}
self.sheet_set.selected = None;
self.save_current_sheet_set();
}
self.sheet_set.selected = None;
self.save_current_sheet_set();
}
MenuAction::Properties => {
let p = build_properties(db, &id, Some(set));
@@ -766,15 +951,33 @@ impl OpenCADStudio {
}
_ => {}
},
Some(SsDialog::Category(c)) => {
if field == FieldId::Name {
c.name = v;
}
}
Some(SsDialog::Confirm(..)) | Some(SsDialog::Template(_)) => {}
Some(SsDialog::Form(f)) => {
let file_follows = f.file_name == format!("{} {}", f.number, f.title).trim();
match field {
FieldId::Number => f.number = v,
FieldId::Title => f.title = v,
FieldId::Title => {
// A folder hierarchy follows the subset name.
if f.kind == FormKind::NewSubset && f.hierarchy {
if let Some(parent) = Path::new(&f.folder).parent() {
f.folder = parent.join(v.trim()).to_string_lossy().to_string();
}
}
f.title = v
}
FieldId::FileName => f.file_name = v,
FieldId::Folder => f.folder = v,
FieldId::LayoutName => f.layout_name = v,
_ => {}
}
if f.kind == FormKind::Rename {
follow_rename(f);
}
// The file name follows "Number Title" until edited.
if f.kind == FormKind::NewSheet && file_follows && field != FieldId::FileName {
f.file_name = format!("{} {}", f.number, f.title).trim().to_string();
@@ -865,8 +1068,9 @@ impl OpenCADStudio {
let (Some(set), Some(parent)) = (self.sheet_set.current, self.sheet_set_import_parent.take()) else {
return;
};
let layouts = match crate::io::load_file(&path) {
Ok(doc) => paper_layouts(&doc),
let Some(db) = self.sheet_set.db() else { return };
let rows = match import_rows(&path, db) {
Ok(rows) => rows,
Err(e) => {
self.command_line.push_error(&format!("{}: {e}", path.display()));
return;
@@ -876,20 +1080,255 @@ impl OpenCADStudio {
kind: FormKind::ImportLayout,
set,
component: parent,
number: String::new(),
title: String::new(),
file_name: String::new(),
folder: String::new(),
drawing: path.to_string_lossy().to_string(),
layouts,
layout: 0,
error: None,
rows,
prefix: true,
..Form::default()
}));
self.active_modal = Some(crate::app::ModalKind::SheetSet);
}
/// Browse for Drawings of the open Import dialog: add their layouts.
fn import_add(&mut self, paths: Vec<PathBuf>) {
let Some(SsDialog::Form(f)) = self.sheet_set.dialog.as_ref() else { return };
let Some(db) = self.sheet_set.sets.get(f.set) else { return };
let mut added = Vec::new();
for p in paths {
match import_rows(&p, db) {
Ok(rows) => added.extend(rows),
Err(e) => self.command_line.push_error(&format!("{}: {e}", p.display())),
}
}
if let Some(SsDialog::Form(f)) = self.sheet_set.dialog.as_mut() {
for r in added {
if !f.rows.iter().any(|o| ss::path_key(&o.drawing) == ss::path_key(&r.drawing) && o.layout == r.layout) {
f.rows.push(r);
}
}
}
}
/// Rename & Renumber: number and title into the set, and the layout and
/// drawing file renamed when they changed.
fn apply_rename(&mut self, f: &Form) -> Result<(), String> {
let Some(db) = self.sheet_set.sets.get(f.set) else { return Ok(()) };
let old = db.layout_reference(&f.component, "Layout").unwrap_or_default();
let new_layout = f.layout_name.trim().to_string();
let new_file = if old.file_name.is_empty() || f.file_name.trim().is_empty() {
old.file_name.clone()
} else {
Path::new(&f.folder).join(f.file_name.trim()).to_string_lossy().to_string()
};
let file_changed = !old.file_name.is_empty() && ss::path_key(&new_file) != ss::path_key(&old.file_name);
let layout_changed = !old.name.is_empty() && !new_layout.is_empty() && new_layout != old.name;
let open_tab = self.tab_showing(Path::new(&old.file_name));
if file_changed {
if open_tab.is_some() {
return Err(crate::t!("The drawing is open; close it to rename its file.").into_owned());
}
if Path::new(&new_file).exists() {
return Err(crate::tf!("{} already exists.", new_file).into_owned());
}
}
if layout_changed {
match open_tab {
Some(k) => {
self.tabs[k].scene.rename_layout(&old.name, &new_layout);
if let Some(mut link) = self.tabs[k].scene.document.sheet_set_data() {
link.layout_name = new_layout.clone();
self.tabs[k].scene.document.set_sheet_set_data(&link);
}
}
None => {
let mut scene = crate::scene::Scene::new();
scene.document = crate::io::load_file(Path::new(&old.file_name)).map_err(|e| e.to_string())?;
scene.rename_layout(&old.name, &new_layout);
if let Some(mut link) = scene.document.sheet_set_data() {
link.layout_name = new_layout.clone();
scene.document.set_sheet_set_data(&link);
}
crate::io::save(&scene.document, Path::new(&old.file_name)).map_err(|e| e.to_string())?;
}
}
}
if file_changed {
std::fs::rename(&old.file_name, &new_file).map_err(|e| e.to_string())?;
}
let Some(db) = self.sheet_set.sets.get_mut(f.set) else { return Ok(()) };
if let Some(el) = db.find_mut(&f.component) {
el.set_prop("Number", f.number.trim());
el.set_prop("Title", f.title.trim());
}
if layout_changed || file_changed {
db.set_layout_reference(
&f.component,
"Layout",
&LayoutReference {
file_name: ss::native_path(&new_file),
name: if layout_changed { new_layout } else { old.name },
handle: old.handle,
},
);
}
Ok(())
}
/// Rename & Renumber < Previous / Next >: apply, then the neighbouring sheet.
fn rename_step(&mut self, forward: bool) {
let Some(SsDialog::Form(f)) = self.sheet_set.dialog.take() else { return };
if let Err(e) = self.apply_rename(&f) {
self.sheet_set.dialog = Some(SsDialog::Form(Form { error: Some(e), ..f }));
return;
}
self.sheet_set.current = Some(f.set);
self.save_current_sheet_set();
let Some(db) = self.sheet_set.sets.get(f.set) else { return };
let ids: Vec<String> = db.sheets().iter().map(|s| s.id().to_string()).collect();
let k = ids.iter().position(|i| *i == f.component).unwrap_or(0);
let next = if forward { (k + 1).min(ids.len().saturating_sub(1)) } else { k.saturating_sub(1) };
let mut form = rename_form(db, f.set, &ids[next]);
form.rename = f.rename;
follow_rename(&mut form);
self.sheet_set.selected = Some(ids[next].clone());
self.sheet_set.dialog = Some(SsDialog::Form(form));
}
/// The View Category dialog for a new (`None`) or existing category.
fn open_category(&mut self, id: Option<String>) {
let (Some(set), Some(db)) = (self.sheet_set.current, self.sheet_set.db()) else { return };
let used = id.as_deref().map(|i| db.category_blocks(i));
let blocks = db
.callout_blocks()
.iter()
.map(|b| {
let label = format!("{} ({})", b.prop("Name").unwrap_or(""), db.resolve_file(b));
let on = used.as_ref().is_none_or(|u| u.iter().any(|x| x == b.id()));
(b.id().to_string(), label, on)
})
.collect();
let name = id.as_deref().and_then(|i| db.find(i)).and_then(|c| c.prop("Name")).unwrap_or("").to_string();
self.sheet_set.dialog = Some(SsDialog::Category(Category { set, id, name, blocks, error: None }));
self.active_modal = Some(crate::app::ModalKind::SheetSet);
}
/// Add Blocks...: the named blocks of a drawing become callout blocks.
fn category_add_blocks(&mut self, path: PathBuf) {
let doc = match crate::io::load_file(&path) {
Ok(d) => d,
Err(e) => {
self.command_line.push_error(&format!("{}: {e}", path.display()));
return;
}
};
let file = ss::native_path(&path.to_string_lossy());
let Some(SsDialog::Category(c)) = self.sheet_set.dialog.as_mut() else { return };
let mut names: Vec<(String, String)> = doc
.block_records
.iter()
.filter(|b| !b.name.starts_with('*') && !b.is_layout())
.map(|b| (b.name.clone(), format!("{:X}", b.handle.value())))
.collect();
names.sort();
for (name, handle) in names {
c.blocks.push((format!("new:{file}|{name}|{handle}"), format!("{name} ({file})"), true));
}
}
fn category_ok(&mut self, mut c: Category) {
let name = c.name.trim().to_string();
if name.is_empty() {
c.error = Some(crate::t!("The category name cannot be empty.").into_owned());
self.sheet_set.dialog = Some(SsDialog::Category(c));
return;
}
self.close_active_modal();
let Some(db) = self.sheet_set.sets.get_mut(c.set) else { return };
let mut used = Vec::new();
for (id, _, on) in &c.blocks {
let id = match id.strip_prefix("new:") {
Some(spec) => {
let mut p = spec.splitn(3, '|');
let (file, block, handle) = (p.next().unwrap_or(""), p.next().unwrap_or(""), p.next().unwrap_or(""));
match db.add_callout_block(file, block, handle) {
Some(id) => id,
None => continue,
}
}
None => id.clone(),
};
if *on {
used.push(id);
}
}
db.set_view_category(c.id.as_deref(), &name, &used);
self.sheet_set.current = Some(c.set);
self.save_current_sheet_set();
}
/// Model Views: each location folder of the current set and its drawings.
pub(in crate::app) fn refresh_locations(&mut self) {
let Some(db) = self.sheet_set.db() else {
self.sheet_set.locations.clear();
return;
};
self.sheet_set.locations = db
.sheet_set()
.named("Resources")
.map(|r| {
r.children
.iter()
.map(|c| {
let folder = db.resolve_file(c);
let mut files: Vec<String> = std::fs::read_dir(&folder)
.map(|d| {
d.filter_map(|e| e.ok())
.map(|e| e.file_name().to_string_lossy().to_string())
.filter(|n| n.to_ascii_lowercase().ends_with(".dwg"))
.collect()
})
.unwrap_or_default();
files.sort_by_key(|n| n.to_lowercase());
(c.id().to_string(), folder, files)
})
.collect()
})
.unwrap_or_default();
}
/// SSMSHEETSTATUS: a sheet whose drawing is missing, or open (its `.dwl`
/// lock file, or a tab of this application).
pub(in crate::app) fn refresh_sheet_status(&mut self) {
self.sheet_set.status_at = Some(std::time::Instant::now());
self.sheet_set.status.clear();
if self.sheet_set.settings.sheet_status == 0 {
return;
}
let Some(db) = self.sheet_set.db() else { return };
let mut status = std::collections::HashMap::new();
for sheet in db.sheets() {
let Some(r) = db.layout_reference(sheet.id(), "Layout") else { continue };
let path = Path::new(&r.file_name);
let state = if !path.exists() {
Some(SheetStatus::Missing)
} else if path.with_extension("dwl").exists() || self.tab_showing(path).is_some() {
Some(SheetStatus::Locked)
} else {
None
};
if let Some(st) = state {
status.insert(sheet.id().to_string(), st);
}
}
self.sheet_set.status = status;
}
fn properties_template(&mut self, path: PathBuf) {
let layouts = crate::io::load_file(&path).map(|d| paper_layouts(&d)).unwrap_or_default();
if let Some(SsDialog::Template(t)) = self.sheet_set.dialog.as_mut() {
t.file = path.to_string_lossy().to_string();
t.layouts = layouts.into_iter().map(|(n, _)| n).collect();
t.layout = 0;
return;
}
let Some(SsDialog::Properties(p)) = self.sheet_set.dialog.as_mut() else {
return;
};
@@ -914,6 +1353,29 @@ impl OpenCADStudio {
Task::none()
}
Some(SsDialog::Form(f)) => self.form_ok(f),
Some(SsDialog::Confirm(set, id, _)) => {
self.close_active_modal();
if let Some(db) = self.sheet_set.sets.get_mut(set) {
db.remove(&id);
}
self.sheet_set.current = Some(set);
self.sheet_set.selected = None;
self.save_current_sheet_set();
Task::none()
}
Some(SsDialog::Template(t)) => {
let mut form = t.form;
if let Some(layout) = t.layouts.get(t.layout) {
form.drawing = format!("{layout} ({})", t.file);
form.template = Some((t.file, layout.clone()));
}
self.sheet_set.dialog = Some(SsDialog::Form(form));
Task::none()
}
Some(SsDialog::Category(c)) => {
self.category_ok(c);
Task::none()
}
None => Task::none(),
}
}
@@ -1004,9 +1466,10 @@ impl OpenCADStudio {
};
match f.kind {
FormKind::Rename => {
if let Some(el) = db.find_mut(&f.component) {
el.set_prop("Number", f.number.trim());
el.set_prop("Title", f.title.trim());
if let Err(e) = self.apply_rename(&f) {
f.error = Some(e);
self.sheet_set.dialog = Some(SsDialog::Form(f));
return Task::none();
}
}
FormKind::NewSubset => {
@@ -1016,32 +1479,43 @@ impl OpenCADStudio {
self.sheet_set.dialog = Some(SsDialog::Form(f));
return Task::none();
}
if let Some(sub) = db.add_subset(&f.component, &name, "") {
if !f.folder.trim().is_empty() {
db.set_file_reference(&sub, "NewSheetLocation", f.folder.trim());
let parent_folder = sheet_folder_of(db, &f.component);
if let Some(sub) = db.add_subset(&f.component, &name, "New subset added") {
// Folder hierarchy: the parent's location + the subset name, created now.
let folder = if f.hierarchy {
let folder = Path::new(&parent_folder).join(&name);
let _ = std::fs::create_dir_all(&folder);
folder.to_string_lossy().to_string()
} else {
f.folder.trim().to_string()
};
if !folder.is_empty() {
db.set_file_reference(&sub, "NewSheetLocation", &folder);
}
if !f.publish {
if let Some(el) = db.find_mut(&sub) {
el.set_prop_vt("OverrideSheetPublish", 2, "-1");
}
}
}
}
FormKind::ImportLayout => {
let Some((layout, handle)) = f.layouts.get(f.layout).cloned() else {
let chosen: Vec<&ImportRow> = f.rows.iter().filter(|r| r.on && r.owner.is_none()).collect();
if chosen.is_empty() {
f.error = Some(crate::t!("The drawing has no layout to import.").into_owned());
self.sheet_set.dialog = Some(SsDialog::Form(f));
return Task::none();
};
if db.sheet_for(&f.drawing, Some(&layout)).is_some_and(|s| {
s.named("Layout").and_then(|r| r.prop("Name")).is_some_and(|n| n.eq_ignore_ascii_case(&layout))
}) {
f.error = Some(crate::t!("The layout is already a sheet of this sheet set.").into_owned());
self.sheet_set.dialog = Some(SsDialog::Form(f));
return Task::none();
}
let stem = Path::new(&f.drawing).file_stem().map(|s| s.to_string_lossy().to_string()).unwrap_or_default();
if let Some(sheet) = db.add_sheet(&f.component, "", &format!("{stem} - {layout}"), "") {
db.set_layout_reference(
&sheet,
"Layout",
&LayoutReference { file_name: f.drawing.clone(), name: layout, handle },
);
for r in chosen {
let stem = Path::new(&r.drawing).file_stem().map(|s| s.to_string_lossy().to_string()).unwrap_or_default();
let title = if f.prefix { format!("{stem} - {}", r.layout) } else { r.layout.clone() };
if let Some(sheet) = db.add_sheet(&f.component, "", &title, "") {
db.set_layout_reference(
&sheet,
"Layout",
&LayoutReference { file_name: r.drawing.clone(), name: r.layout.clone(), handle: r.handle.clone() },
);
}
}
}
FormKind::NewSheet => return self.create_sheet(f),
@@ -1080,7 +1554,10 @@ impl OpenCADStudio {
return fail(self, f, crate::tf!("{} already exists.", path.display()).into_owned());
}
let layout_name = format!("{} {}", f.number.trim(), title).trim().to_string();
let template = self.sheet_set.sets.get(f.set).and_then(|db| template_of(db, &f.component));
let template = match f.template.clone() {
Some((file_name, name)) => Some(LayoutReference { file_name, name, handle: String::new() }),
None => self.sheet_set.sets.get(f.set).and_then(|db| template_of(db, &f.component)),
};
let mut scene = crate::scene::Scene::new();
let source_layout = match template.as_ref().and_then(|t| crate::io::load_file(Path::new(&t.file_name)).ok().map(|d| (d, t.name.clone()))) {
Some((doc, name)) => {
@@ -1134,11 +1611,14 @@ impl OpenCADStudio {
if let Err(e) = crate::io::save(&scene.document, &path) {
self.command_line.push_error(&format!("{file}: {e}"));
}
// The new sheet is not opened ("Open in drawing editor" is off by default).
// "Open in drawing editor" (off by default) opens the new sheet.
self.close_active_modal();
self.sheet_set.current = Some(f.set);
self.sheet_set.selected = Some(sheet);
self.sheet_set.selected = Some(sheet.clone());
self.sheet_sets_changed();
if f.open_after {
return self.open_sheet(&sheet);
}
Task::none()
}
}
@@ -1218,7 +1698,12 @@ pub(in crate::app) fn build_properties(db: &SheetSetDatabase, id: &str, set: Opt
ComponentKind::Subset => {
title = format!("{} - {}", crate::t!("Subset Properties"), prop("Name"));
rows.push(row("Subset", "Subset name", RowKey::Prop("Name"), prop("Name")));
rows.push(row("Subset", "Description", RowKey::Prop("Desc"), prop("Desc")));
let publish = if el.prop("OverrideSheetPublish").is_some_and(|v| v.trim() == "-1") {
"Do Not Publish Sheets"
} else {
"Publish by Sheet 'Include for Publish' Setting"
};
rows.push(row("Subset", "Publish sheets in subset", RowKey::Publish, publish.to_string()));
rows.push(row("Subset", "New sheet location", RowKey::Folder("NewSheetLocation"), named_file("NewSheetLocation")));
rows.push(row("Subset", "Sheet creation template", RowKey::Template, template()));
rows.push(row("Subset", "Prompt for template", RowKey::PromptTemplate, prompt()));
@@ -1284,11 +1769,22 @@ fn write_properties(db: &mut SheetSetDatabase, p: &Properties) {
db.set_file_reference(&p.component, name, r.value.trim());
}
RowKey::PromptTemplate => {
// The set keeps it as an int (1), a subset as a short (-1).
if let Some(el) = db.find_mut(&p.component) {
if r.value == "Yes" {
el.set_prop_vt("PromptForDwt", 3, "1");
el.remove_named("PromptForDwt");
match (r.value == "Yes", p.kind) {
(true, ComponentKind::SheetSet) => el.set_prop_vt("PromptForDwt", 3, "1"),
(true, _) => el.set_prop_vt("PromptForDwt", 2, "-1"),
_ => {}
}
}
}
RowKey::Publish => {
if let Some(el) = db.find_mut(&p.component) {
if r.value == "Do Not Publish Sheets" {
el.set_prop_vt("OverrideSheetPublish", 2, "-1");
} else {
el.remove_named("PromptForDwt");
el.remove_named("OverrideSheetPublish");
}
}
}
+70
View File
@@ -1135,6 +1135,21 @@ impl OpenCADStudio {
"link_url" => F::HyperlinkUrl(v.into()),
"plot_scale" => F::PlotScale(index(codec::fields::PLOT_SCALE_FORMATS.len())?),
"ss_custom" => F::SsCustom(v.into()),
"ss_set" => F::SsSet(v.parse().map_err(|_| failure("invalid_value", "index"))?),
"ss_dst" => F::SsPicked(Some(std::path::PathBuf::from(v))),
"ss_node" => {
let state = self.field_dialog.as_ref().ok_or_else(|| failure("invalid_state", "No Field dialog"))?;
let db = state.ss_sets.get(state.ss_set).ok_or_else(|| failure("invalid_state", "No sheet set"))?;
let views = state.name == "SheetView";
let id = fd::nav_nodes(db, views)
.into_iter()
.find(|(_, id, label, _)| label == v || id == v)
.map(|(_, id, _, _)| id)
.ok_or_else(|| failure("invalid_value", "No such node"))?;
F::SsNode(id)
}
"ss_prop" => F::SsProp(v.into()),
"ss_href" => F::SsHref(v == "1"),
"ss_placeholder" => F::SsPlaceholder(index(fd::PLACEHOLDER_TYPES.len())?),
"ss_scale" => F::SsScaleFormat(index(codec::fields::PLOT_SCALE_FORMATS.len())?),
"placeholder" => F::PlaceholderProperty(index(codec::fields::BLOCK_PLACEHOLDER_PROPERTIES.len())?),
@@ -1233,6 +1248,61 @@ impl OpenCADStudio {
"title" => M::Input(F::Title, arg.into()),
"file_name" => M::Input(F::FileName, arg.into()),
"pick_layout" => M::Choose(F::Layout, arg.parse().map_err(|_| failure("invalid_value", "index"))?),
"refresh" => M::Refresh,
"open_after" => M::Toggle(F::OpenAfter, arg == "1"),
"row_toggle" => {
let (i, v) = index_value(arg)?;
M::Toggle(F::Row(i), v == "1")
}
"publish" => M::Toggle(F::Publish, arg == "1"),
"layout_name" => M::Input(F::LayoutName, arg.into()),
"rename_opt" => {
let (i, v) = index_value(arg)?;
M::Toggle(F::RenameOption(i.min(3)), v == "1")
}
"import_add" => M::ImportAdd(arg.split('|').map(std::path::PathBuf::from).collect()),
"import_row" => {
let (i, v) = index_value(arg)?;
M::Toggle(F::ImportRow(i), v == "1")
}
"prefix" => M::Toggle(F::ImportPrefix, arg == "1"),
"previous" => M::Previous,
"next" => M::Next,
"views_by_category" => M::ViewsByCategory(arg == "1"),
"new_category" => M::NewCategory,
"category" => {
let id = self
.sheet_set
.db()
.and_then(|db| db.view_categories().iter().find(|c| c.prop("Name") == Some(arg)).map(|c| c.id().to_string()))
.ok_or_else(|| failure("invalid_value", "No such view category"))?;
M::CategoryProperties(id)
}
"remove_category" => {
let id = self
.sheet_set
.db()
.and_then(|db| db.view_categories().iter().find(|c| c.prop("Name") == Some(arg)).map(|c| c.id().to_string()))
.ok_or_else(|| failure("invalid_value", "No such view category"))?;
M::CategoryRemove(id)
}
"category_block" => {
let (i, v) = index_value(arg)?;
M::Toggle(F::CategoryBlock(i), v == "1")
}
"add_blocks" => M::BlocksPicked(Some(std::path::PathBuf::from(arg))),
"add_location" => M::LocationPicked(Some(std::path::PathBuf::from(arg))),
"remove_location" => {
let id = self
.sheet_set
.locations
.iter()
.find(|(_, folder, _)| codec::sheet_set::path_key(folder) == codec::sheet_set::path_key(arg))
.map(|(id, _, _)| id.clone())
.ok_or_else(|| failure("invalid_value", "No such location"))?;
M::RemoveLocation(id)
}
"open_drawing" => M::OpenDrawing(arg.into()),
"ok" => M::Ok,
"cancel" => M::Cancel,
_ => return Err(failure("invalid_value", "Unknown sheet set action")),
+8 -1
View File
@@ -585,7 +585,14 @@ impl OpenCADStudio {
let (w, h) = match self.sheet_set.dialog.as_ref()? {
crate::ui::window::sheet_set::SsDialog::Wizard(_) => (720, 560),
crate::ui::window::sheet_set::SsDialog::Properties(_) => (640, 700),
crate::ui::window::sheet_set::SsDialog::Form(_) => (560, 420),
crate::ui::window::sheet_set::SsDialog::Form(f) => match f.kind {
crate::ui::window::sheet_set::FormKind::Rename => (560, 470),
crate::ui::window::sheet_set::FormKind::ImportLayout => (620, 470),
_ => (560, 420),
},
crate::ui::window::sheet_set::SsDialog::Confirm(..) => (460, 190),
crate::ui::window::sheet_set::SsDialog::Template(_) => (480, 400),
crate::ui::window::sheet_set::SsDialog::Category(_) => (480, 440),
};
sized_flow(ex, w, h, |flow| crate::ui::window::sheet_set::dialog_view(&self.sheet_set, flow))
}
+3 -2
View File
@@ -759,7 +759,8 @@ pub fn load_bytes(name: &str, bytes: Vec<u8>) -> Result<CadDocument, String> {
ext.as_str()
};
match format {
"dwg" => {
// Templates (.dwt) and standards (.dws) are drawings in the DWG format.
"dwg" | "dwt" | "dws" => {
let mut doc = DwgReader::from_stream(Cursor::new(bytes))
.read()
.map_err(|e| e.to_string())?;
@@ -1022,7 +1023,7 @@ fn read_file_attempt(
};
match effective.as_str() {
"dwg" => read_dwg_path(path, progress, failsafe),
"dwg" | "dwt" | "dws" => read_dwg_path(path, progress, failsafe),
"dxf" => read_dxf_path(path, failsafe),
_ => Err(ReaderFailure::terminal(format!(
"Unsupported file format: .{ext}"
+39
View File
@@ -50,6 +50,45 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static
"New sheet location" => Some(("view", "ss-new-sheet-location")),
"Remove Subset" => Some(("view", "ss-remove-subset")),
"Rename Subset..." => Some(("view", "ss-rename-subset")),
"missing" => Some(("view", "ss-status-missing")),
"open" => Some(("view", "ss-status-open")),
"View by category" => Some(("view", "ss-view-by-category")),
"View by sheet" => Some(("view", "ss-view-by-sheet")),
"Import Layouts as Sheets" => Some(("view", "ss-import-layouts-as-sheets")),
"Remove Sheets" => Some(("view", "ss-remove-sheets")),
"View Category" => Some(("view", "ss-view-category")),
"New View Category..." => Some(("view", "ss-new-view-category")),
"Add New Location..." => Some(("view", "ss-add-new-location")),
"Remove Location" => Some(("view", "ss-remove-location")),
"Publish by Sheet 'Include for Publish' Setting" => Some(("view", "ss-publish-by-sheet")),
"Do Not Publish Sheets" => Some(("view", "ss-do-not-publish-sheets")),
"Open in drawing editor" => Some(("view", "ss-open-in-drawing-editor")),
"Create folder hierarchy" => Some(("view", "ss-create-folder-hierarchy")),
"Publish sheets in subset" => Some(("view", "ss-publish-sheets-in-subset")),
"Rename options" => Some(("view", "ss-rename-options")),
"Rename layout to match:" => Some(("view", "ss-rename-layout-to-match")),
"Prefix with sheet number" => Some(("view", "ss-prefix-with-sheet-number")),
"Rename drawing file to match:" => Some(("view", "ss-rename-drawing-file-to-match")),
"Available for import" => Some(("view", "ss-available-for-import")),
"Belongs to sheet set {}" => Some(("view", "ss-belongs-to-sheet-set")),
"Drawings" => Some(("view", "ss-drawings")),
"Select drawing files containing layouts" => Some(("view", "ss-select-drawing-files-containing-layouts")),
"Browse for Drawings..." => Some(("view", "ss-browse-for-drawings")),
"A layout can belong to only one sheet set. If a layout already belongs to a sheet set, you must create a copy of the layout to import it." => Some(("view", "ss-a-layout-can-belong-to-only-one-sheet-set")),
"Prefix sheet titles with file name" => Some(("view", "ss-prefix-sheet-titles-with-file-name")),
"Import Checked" => Some(("view", "ss-import-checked")),
"Template" => Some(("view", "ss-template")),
"Drawing template file name" => Some(("view", "ss-drawing-template-file-name")),
"Select a layout to create new sheets" => Some(("view", "ss-select-a-layout-to-create-new-sheets")),
"Category name" => Some(("view", "ss-category-name")),
"Select the callout blocks to be used in this category" => Some(("view", "ss-select-the-callout-blocks")),
"Selected blocks will be available for selection when you insert a callout block from the view tab." => Some(("view", "ss-selected-blocks-will-be-available")),
"Add Blocks..." => Some(("view", "ss-add-blocks")),
"(The layout and the drawing file will not be deleted.)" => Some(("view", "ss-layout-and-drawing-not-deleted")),
"Are you sure that you want to remove {} Sheet from {} Sheet Set?" => Some(("view", "ss-remove-sheet-question")),
"The drawing is open; close it to rename its file." => Some(("view", "ss-drawing-open-cannot-rename")),
"The category name cannot be empty." => Some(("view", "ss-category-name-empty")),
"Associate hyperlink" => Some(("view", "ss-associate-hyperlink")),
"Remove Sheet" => Some(("view", "ss-remove-sheet")),
"Lets you specify one or more folders containing drawings. The layouts from these drawings can be automatically imported into the sheet set." => Some(("view", "ss-lets-you-specify-one-or-more-folders-containing-drawings-the")),
"Creates a sheet set with no subsets or sheets." => Some(("view", "ss-creates-a-sheet-set-with-no-subsets-or-sheets")),
+166 -9
View File
@@ -90,6 +90,105 @@ fn sheet_set_code(name: &str, custom: &str) -> String {
format!("\\AcSm{version} {target}")
}
/// The navigation tree of a SheetSet (set, subsets, sheets) or SheetView
/// (set, view categories) field: depth, component id, label, is a sheet.
pub fn nav_nodes(db: &codec::sheet_set::SheetSetDatabase, views: bool) -> Vec<(u16, String, String, bool)> {
use codec::sheet_set::{number_and_title, ComponentKind, Element as SsElement};
let set = db.sheet_set();
let mut out = vec![(0, set.id().to_string(), db.name().to_string(), false)];
if views {
for c in db.view_categories() {
out.push((1, c.id().to_string(), c.prop("Name").unwrap_or("").to_string(), false));
}
return out;
}
fn go(el: &SsElement, depth: u16, out: &mut Vec<(u16, String, String, bool)>) {
for c in &el.children {
match ComponentKind::of(c) {
Some(ComponentKind::Subset) => {
out.push((depth, c.id().to_string(), c.prop("Name").unwrap_or("").to_string(), false));
go(c, depth + 1, out);
}
Some(ComponentKind::Sheet) => out.push((depth, c.id().to_string(), number_and_title(c), true)),
_ => {}
}
}
}
go(set, 1, &mut out);
out
}
/// The properties a navigation node offers: list label, code property, version.
pub fn nav_props(db: &codec::sheet_set::SheetSetDatabase, id: &str) -> Vec<(String, String, &'static str)> {
use codec::sheet_set::{custom_properties, ComponentKind, CUSTOM_SHEET_PROP, CUSTOM_SHEET_SET_PROP};
let Some(el) = db.find(id) else { return Vec::new() };
let fixed = |list: &[(&str, &str, &'static str)]| -> Vec<(String, String, &'static str)> {
list.iter().map(|(l, p, v)| (l.to_string(), p.to_string(), *v)).collect()
};
let custom = |flag: i32| -> Vec<(String, String, &'static str)> {
custom_properties(db.sheet_set()).into_iter().filter(|(_, _, f)| f & flag != 0).map(|(n, _, _)| (n.clone(), n, "")).collect()
};
match ComponentKind::of(el) {
Some(ComponentKind::SheetSet) => {
let mut v = fixed(&[
("SheetSetName", "Name", ""),
("SheetSetDescription", "Description", ""),
("ProjectNumber", "ProjectNumber", ".16.2"),
("ProjectName", "ProjectName", ".16.2"),
("ProjectPhase", "ProjectPhase", ".16.2"),
("ProjectMilestone", "ProjectMilestone", ".16.2"),
]);
v.extend(custom(CUSTOM_SHEET_SET_PROP));
v
}
Some(ComponentKind::Subset) => fixed(&[("SheetSubsetName", "Name", "")]),
Some(ComponentKind::Sheet) => {
let mut v = fixed(&[
("SheetNumberAndTitle", "NumberAndTitle", ""),
("SheetTitle", "Title", ""),
("SheetNumber", "Number", ""),
("SheetDescription", "Description", ""),
("RevisionNumber", "RevisionNumber", ".16.2"),
("RevisionDate", "RevisionDate", ".16.2"),
("IssuePurpose", "IssuePurpose", ".16.2"),
("Category", "Category", ".16.2"),
]);
v.extend(custom(CUSTOM_SHEET_PROP));
v
}
None => fixed(&[("ViewCategoryName", "Name", "")]),
}
}
impl FieldDialogState {
/// `\AcSm Database("…").SheetSet("…")[.Component("…")].Property` of the
/// picked node, with the text case and, on a sheet, the hyperlink to it.
fn navigation_code(&self) -> String {
let Some(db) = self.ss_sets.get(self.ss_set) else { return "\\AcSm".into() };
let Some((_, prop, version)) = nav_props(db, &self.ss_node).into_iter().find(|(l, _, _)| *l == self.ss_prop) else {
return "\\AcSm".into();
};
let set = db.sheet_set().id().to_string();
let path = codec::sheet_set::native_path(db.path.as_deref().unwrap_or(""));
let mut code = format!("\\AcSm{version} Database(\"{path}\").SheetSet(\"{set}\")");
if self.ss_node != set {
code.push_str(&format!(".Component(\"{}\")", self.ss_node));
}
code.push('.');
code.push_str(&prop);
if self.text_case != 0 {
code.push_str(&format!(" \\f \"%tc{}\"", self.text_case));
}
let sheet = db.find(&self.ss_node).and_then(codec::sheet_set::ComponentKind::of) == Some(codec::sheet_set::ComponentKind::Sheet);
if sheet && self.ss_href {
if let Some(r) = db.layout_reference(&self.ss_node, "Layout") {
code.push_str(&format!(" \\href \"{}#,{}##1\"", r.file_name, r.name));
}
}
code
}
}
/// SheetSetPlaceholder types: list label, the `?` target, field version.
pub const PLACEHOLDER_TYPES: &[(&str, &str, &str)] = &[
("SheetNumberAndTitle", "?Sheet.NumberAndTitle", ""),
@@ -232,6 +331,13 @@ pub struct FieldDialogState {
pub ss_scale_format: usize,
/// The open sheet set's name (SheetSet / SheetView fields).
pub ss_set_name: String,
/// SheetSet / SheetView: the sets offered (open ones and any picked with
/// "..."), the one shown, the node and property picked, associate hyperlink.
pub ss_sets: Vec<codec::sheet_set::SheetSetDatabase>,
pub ss_set: usize,
pub ss_node: String,
pub ss_prop: String,
pub ss_href: bool,
/// Today in each of DATE_FORMATS, for the Examples list.
pub examples: Vec<String>,
}
@@ -270,6 +376,11 @@ impl FieldDialogState {
ss_placeholder: 0,
ss_scale_format: 6,
ss_set_name: String::new(),
ss_sets: Vec::new(),
ss_set: 0,
ss_node: String::new(),
ss_prop: String::new(),
ss_href: true,
examples: Vec::new(),
}
}
@@ -324,7 +435,7 @@ impl FieldDialogState {
vec![],
),
FieldKind::SheetSet | FieldKind::SheetSetCustom => (case(sheet_set_code(self.name, &self.ss_custom)), vec![]),
FieldKind::SheetSetNavigation => ("\\AcSm".into(), vec![]),
FieldKind::SheetSetNavigation => (self.navigation_code(), vec![]),
FieldKind::SheetSetPlaceholder => {
let (label, target, version) = PLACEHOLDER_TYPES[self.ss_placeholder.min(PLACEHOLDER_TYPES.len() - 1)];
let target = if label == "Custom" { format!("{target}{}", self.ss_custom) } else { target.to_string() };
@@ -454,6 +565,12 @@ pub enum FieldDialogMsg {
SsCustom(String),
SsPlaceholder(usize),
SsScaleFormat(usize),
SsSet(usize),
SsNode(String),
SsProp(String),
SsHref(bool),
SsBrowse,
SsPicked(Option<std::path::PathBuf>),
Help,
Ok,
}
@@ -814,14 +931,53 @@ fn format_panel<'a>(state: &'a FieldDialogState) -> Element<'a, Message> {
}
col.into()
}
FieldKind::SheetSetNavigation => column![
text(t!("Sheet set")).size(12),
container(text(state.ss_set_name.clone()).size(12).style(muted_style)).padding([5, 8]).width(Fill),
text(t!("Sheet navigation tree")).size(12),
container(Space::new()).height(Length::Fixed(120.0)),
]
.spacing(8)
.into(),
FieldKind::SheetSetNavigation => {
let picks: Vec<Pick> = state.ss_sets.iter().enumerate().map(|(i, d)| Pick(i, d.name().to_string())).collect();
let current = picks.get(state.ss_set).cloned();
let set_row = row![
pick_list(current, picks, |p: &Pick| p.1.clone())
.on_select(|p: Pick| msg(FieldDialogMsg::SsSet(p.0)))
.text_size(12)
.padding([5, 8])
.width(Fill),
button(text("...").size(12)).on_press(msg(FieldDialogMsg::SsBrowse)).style(button_style(false)).padding([5, 10]),
]
.spacing(6);
let db = state.ss_sets.get(state.ss_set);
let nodes = db.map(|d| nav_nodes(d, state.name == "SheetView")).unwrap_or_default();
let tree = list(
nodes
.iter()
.map(|(depth, id, label, _)| {
(format!("{}{label}", " ".repeat(usize::from(*depth))), *id == state.ss_node, FieldDialogMsg::SsNode(id.clone()))
})
.collect(),
118.0,
);
let props = db.map(|d| nav_props(d, &state.ss_node)).unwrap_or_default();
let prop_list = list(
props.iter().map(|(l, _, _)| (l.clone(), *l == state.ss_prop, FieldDialogMsg::SsProp(l.clone()))).collect(),
92.0,
);
let sheet = nodes.iter().any(|(_, id, _, sheet)| *sheet && *id == state.ss_node);
let mut href = checkbox(state.ss_href && sheet).label(t!("Associate hyperlink").into_owned()).text_size(12).size(14);
if sheet {
href = href.on_toggle(|v| msg(FieldDialogMsg::SsHref(v)));
}
column![
text(t!("Sheet set")).size(12),
set_row,
text(t!("Sheet navigation tree")).size(12),
tree,
text(t!("Property")).size(12),
prop_list,
text(t!("Format")).size(12),
case_list(state),
href,
]
.spacing(8)
.into()
}
FieldKind::Object => column![
row![
text(t!("Object type")).size(12).width(Length::Fixed(96.0)),
@@ -918,6 +1074,7 @@ pub fn view<'a>(
.spacing(10),
FieldKind::Hyperlink => column![card(t!("Hyperlink").into_owned(), format_panel(state)), preview].spacing(10),
FieldKind::BlockPlaceholder => column![card(t!("Block placeholder").into_owned(), format_panel(state)), preview].spacing(10),
FieldKind::SheetSetNavigation => column![card(t!("Sheet set").into_owned(), format_panel(state)), preview].spacing(10),
_ => column![card(t!("Format").into_owned(), format_panel(state)), preview].spacing(10),
};
let (code, _) = state.code();
+550 -103
View File
@@ -65,6 +65,20 @@ pub struct SheetSetManager {
pub dialog: Option<SsDialog>,
/// Last seen modification time of each open `.dst` (by path key).
pub seen: std::collections::HashMap<String, std::time::SystemTime>,
/// Sheet status by sheet id (SSMSHEETSTATUS) and when it was taken.
pub status: std::collections::HashMap<String, SheetStatus>,
pub status_at: Option<std::time::Instant>,
/// Sheet Views: by category (else by sheet).
pub by_category: bool,
/// Model Views: location id, folder and its drawings.
pub locations: Vec<(String, String, Vec<String>)>,
}
/// A sheet whose drawing is missing, or open (a `.dwl` lock file, or a tab here).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SheetStatus {
Missing,
Locked,
}
impl SheetSetManager {
@@ -103,6 +117,24 @@ pub enum SheetSetMsg {
Refresh,
/// Once a second: reload sets whose `.dst` changed on disk.
Poll,
/// Import: Browse for Drawings and the drawings picked.
BrowseDrawings,
ImportAdd(Vec<std::path::PathBuf>),
/// Rename & Renumber: apply and go to the previous / next sheet.
Previous,
Next,
/// Sheet Views: by category or by sheet.
ViewsByCategory(bool),
NewCategory,
CategoryProperties(String),
CategoryRemove(String),
AddBlocks,
BlocksPicked(Option<std::path::PathBuf>),
/// Model Views.
AddLocation,
LocationPicked(Option<std::path::PathBuf>),
RemoveLocation(String),
OpenDrawing(String),
/// A `.dst` picked by Open (or given by automation).
OpenPicked(Option<std::path::PathBuf>),
/// A drawing picked by Import Layout as Sheet.
@@ -161,6 +193,15 @@ pub enum FieldId {
AddFolder,
/// Prompt for template (Properties).
PromptTemplate,
OpenAfter,
Publish,
LayoutName,
/// Rename option 0..4.
RenameOption(usize),
ImportRow(usize),
ImportPrefix,
/// View Category: a callout block's check box.
CategoryBlock(usize),
}
/// What a Properties row edits.
@@ -175,6 +216,8 @@ pub enum RowKey {
Template,
/// Yes / No: prompt for template.
PromptTemplate,
/// Publish Sheets in Subset (`OverrideSheetPublish`).
Publish,
/// Shown only.
ReadOnly,
}
@@ -236,15 +279,27 @@ pub struct Wizard {
}
/// New Sheet, New Subset, Rename & Renumber and Import Layout as Sheet.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum FormKind {
#[default]
NewSheet,
NewSubset,
Rename,
ImportLayout,
}
/// One layout of Import Layouts as Sheets.
#[derive(Debug, Clone)]
pub struct ImportRow {
pub drawing: String,
pub layout: String,
pub handle: String,
/// The sheet set the layout already belongs to (cannot be imported).
pub owner: Option<String>,
pub on: bool,
}
#[derive(Debug, Clone, Default)]
pub struct Form {
pub kind: FormKind,
pub set: usize,
@@ -254,10 +309,42 @@ pub struct Form {
pub title: String,
pub file_name: String,
pub folder: String,
/// Import: the drawing and its layouts (name, handle).
/// The sheet template picked when the subset prompts for one (file, layout).
pub drawing: String,
pub layouts: Vec<(String, String)>,
pub template: Option<(String, String)>,
/// New Sheet: open the new sheet afterwards.
pub open_after: bool,
/// New Subset: folder hierarchy; publish sheets by their own setting.
pub hierarchy: bool,
pub publish: bool,
/// Rename & Renumber: layout name and the four rename options
/// (layout = title, layout prefix, file = title, file prefix).
pub layout_name: String,
pub rename: [bool; 4],
/// Import: the layouts found and "prefix sheet titles with file name".
pub rows: Vec<ImportRow>,
pub prefix: bool,
pub error: Option<String>,
}
/// Select Layout as Sheet Template (a subset that prompts for its template).
#[derive(Debug, Clone)]
pub struct TemplatePick {
pub form: Form,
pub file: String,
pub layouts: Vec<String>,
pub layout: usize,
}
/// The View Category dialog.
#[derive(Debug, Clone)]
pub struct Category {
pub set: usize,
/// `None` creates a category.
pub id: Option<String>,
pub name: String,
/// Callout block id, label, used.
pub blocks: Vec<(String, String, bool)>,
pub error: Option<String>,
}
@@ -266,6 +353,10 @@ pub enum SsDialog {
Wizard(Wizard),
Properties(Properties),
Form(Form),
/// Remove Sheets confirmation: set, sheet id, question.
Confirm(usize, String, String),
Template(TemplatePick),
Category(Category),
}
impl SsDialog {
@@ -277,8 +368,11 @@ impl SsDialog {
FormKind::NewSheet => t!("New Sheet").into_owned(),
FormKind::NewSubset => t!("Subset Properties").into_owned(),
FormKind::Rename => t!("Rename & Renumber Sheet").into_owned(),
FormKind::ImportLayout => t!("Import Layout as Sheet").into_owned(),
FormKind::ImportLayout => t!("Import Layouts as Sheets").into_owned(),
},
SsDialog::Confirm(..) => t!("Remove Sheets").into_owned(),
SsDialog::Template(_) => t!("Select Layout as Sheet Template").into_owned(),
SsDialog::Category(_) => t!("View Category").into_owned(),
}
}
}
@@ -369,6 +463,63 @@ fn row_menu(id: String, kind: ComponentKind, empty: bool) -> Element<'static, Me
.into()
}
/// A small status badge after a sheet name.
fn badge<'a>(prefix: &str, label: &str, warn: bool) -> Element<'a, Message> {
container(text(format!("{prefix}{}", t!(label))).size(10))
.padding([0, 5])
.style(move |theme: &Theme| {
let p = theme.palette();
let c = if warn { p.warning.base } else { p.secondary.base };
container::Style {
background: Some(Background::Color(c.color)),
text_color: Some(c.text),
border: Border { radius: 7.0.into(), ..Default::default() },
..Default::default()
}
})
.into()
}
/// A tree row of the Sheet Views / Model Views pages with its own menu.
fn plain_row<'a>(
depth: u16,
icon: &'static [u8],
label: String,
double: Option<Message>,
menu: Vec<(&'static str, Option<Message>)>,
) -> Element<'a, Message> {
let cells = row![
Space::new().width(Length::Fixed(f32::from(depth) * 16.0 + 14.0)),
crate::ui::icons::semantic(icon, 14.0),
text(label).size(12).width(Fill),
]
.spacing(5)
.align_y(iced::Center);
let mut area = mouse_area(container(cells).width(Fill).padding([3, 6]));
if let Some(m) = double {
area = area.on_double_click(m);
}
if menu.is_empty() {
return area.into();
}
iced_aw::ContextMenu::new(area, move || {
let items: Vec<Element<'static, Message>> = menu
.iter()
.map(|(label, m)| if label.is_empty() { menu_separator() } else { menu_entry(t!(*label).into_owned(), m.clone()) })
.collect();
container(iced::widget::Column::with_children(items).spacing(1))
.padding(4)
.width(Length::Fixed(220.0))
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(theme.palette().background.weak.color)),
border: Border { color: theme.palette().background.neutral.color, width: 1.0, radius: 4.0.into() },
..Default::default()
})
.into()
})
.into()
}
fn tree_row<'a>(
state: &SheetSetManager,
el: &SsElement,
@@ -392,14 +543,23 @@ fn tree_row<'a>(
None => Space::new().width(14).into(),
};
let selected = state.selected.as_deref() == Some(id.as_str());
let cells = row![
let status = state.status.get(&id).copied();
let mut cells = row![
Space::new().width(Length::Fixed(f32::from(depth) * 16.0)),
arrow,
crate::ui::icons::semantic(icon, 14.0),
text(label).size(12).width(Fill),
]
.spacing(5)
.align_y(iced::Center);
let name = text(label).size(12);
cells = match status {
// A missing drawing: grey with a "? missing" badge; an open one: a lock badge.
Some(SheetStatus::Missing) => {
cells.push(name.style(muted_style)).push(badge("? ", "missing", true)).push(Space::new().width(Fill))
}
Some(SheetStatus::Locked) => cells.push(name).push(badge("", "open", false)).push(Space::new().width(Fill)),
None => cells.push(name.width(Fill)),
};
let area = mouse_area(container(cells).width(Fill).padding([3, 6]).style(move |theme: &Theme| container::Style {
background: selected.then(|| Background::Color(theme.palette().primary.weak.color)),
text_color: selected.then(|| theme.palette().primary.weak.text),
@@ -434,31 +594,102 @@ fn push_tree<'a>(
}
}
/// Sheet views of the set: each sheet's `AcSmSheetView` children.
fn sheet_views(db: &SheetSetDatabase) -> Vec<String> {
db.sheets()
/// A sheet's views (`AcSmSheetView`): label and the category it references.
fn views_of(sheet: &SsElement) -> Vec<(String, String)> {
sheet
.named("SheetViews")
.map(|v| v.children.iter().filter(|c| c.name == "AcSmSheetView").collect::<Vec<_>>())
.unwrap_or_default()
.into_iter()
.flat_map(|sheet| {
sheet
.named("SheetViews")
.map(|v| v.children.iter().filter(|c| c.name == "AcSmSheetView").collect::<Vec<_>>())
.unwrap_or_default()
.into_iter()
.map(|v| {
let number = v.prop("Number").unwrap_or("");
let title = v.prop("Title").unwrap_or("");
if number.is_empty() { title.to_string() } else { format!("{number} - {title}") }
})
.map(|v| {
let number = v.prop("Number").unwrap_or("");
let title = v.prop("Title").unwrap_or("");
let label = if number.is_empty() { title.to_string() } else { format!("{number} - {title}") };
let category = v.named("Category").and_then(|c| c.prop("ReferencedObject")).unwrap_or("").to_string();
(label, category)
})
.collect()
}
/// Model view locations (`Resources`) of the set.
fn model_views(db: &SheetSetDatabase) -> Vec<String> {
db.sheet_set()
.named("Resources")
.map(|r| r.children.iter().map(|c| db.resolve_file(c)).collect())
.unwrap_or_default()
/// The Sheet Views page: the set, then its view categories (or sheets) and their views.
fn sheet_views_rows<'a>(state: &SheetSetManager, db: &SheetSetDatabase) -> Vec<Element<'a, Message>> {
let mut rows = vec![plain_row(
0,
SET_ICON,
db.name().to_string(),
None,
vec![("New View Category...", Some(msg(SheetSetMsg::NewCategory)))],
)];
if state.by_category {
let views: Vec<(String, String)> = db.sheets().into_iter().flat_map(views_of).collect();
for c in db.view_categories() {
let id = c.id().to_string();
rows.push(plain_row(
1,
crate::ui::icons::FOLDER_OPEN,
c.prop("Name").unwrap_or("").to_string(),
Some(msg(SheetSetMsg::CategoryProperties(id.clone()))),
vec![
("New View Category...", Some(msg(SheetSetMsg::NewCategory))),
("Properties...", Some(msg(SheetSetMsg::CategoryProperties(id.clone())))),
("Remove", Some(msg(SheetSetMsg::CategoryRemove(id.clone())))),
],
));
for (label, _) in views.iter().filter(|(_, cat)| *cat == id) {
rows.push(plain_row(2, crate::ui::icons::DOC, label.clone(), None, vec![]));
}
}
} else {
for sheet in db.sheets() {
let views = views_of(sheet);
if views.is_empty() {
continue;
}
rows.push(plain_row(1, crate::ui::icons::DOC, ss::number_and_title(sheet), None, vec![]));
for (label, _) in views {
rows.push(plain_row(2, crate::ui::icons::DOC, label, None, vec![]));
}
}
}
rows
}
/// The Model Views page: each location folder and its drawings.
fn model_views_rows<'a>(state: &SheetSetManager) -> Vec<Element<'a, Message>> {
let mut rows = Vec::new();
// A location shows relative to the set's folder when it can.
let base = state.db().and_then(|db| db.path.as_deref()).and_then(|p| std::path::Path::new(p).parent().map(|p| p.to_path_buf()));
for (id, folder, files) in &state.locations {
let label = base.as_deref().and_then(|b| ss::relative_path(b, std::path::Path::new(folder))).unwrap_or_else(|| folder.clone());
rows.push(plain_row(
0,
crate::ui::icons::FOLDER_OPEN,
label,
None,
vec![
("Add New Location...", Some(msg(SheetSetMsg::AddLocation))),
("Remove Location", Some(msg(SheetSetMsg::RemoveLocation(id.clone())))),
],
));
for file in files {
let path = std::path::Path::new(folder).join(file).to_string_lossy().to_string();
rows.push(plain_row(
1,
crate::ui::icons::DOC,
file.clone(),
Some(msg(SheetSetMsg::OpenDrawing(path.clone()))),
vec![("Open", Some(msg(SheetSetMsg::OpenDrawing(path))))],
));
}
}
rows.push(
button(text(format!("+ {}", t!("Add New Location..."))).size(12).style(muted_style))
.on_press(msg(SheetSetMsg::AddLocation))
.style(button::text)
.padding([3, 6])
.into(),
);
rows
}
fn heading(label: &str) -> Element<'static, Message> {
@@ -522,24 +753,38 @@ pub fn view<'a>(state: &'a SheetSetManager, width: f32, auto_collapse: bool) ->
.into()
}
(Some(db), SsmTab::SheetViews) => {
let views = sheet_views(db);
let list: Element<'a, Message> = if views.is_empty() {
text(t!("No sheet views.").into_owned()).size(12).style(muted_style).into()
} else {
iced::widget::Column::with_children(views.into_iter().map(|v| text(v).size(12).into())).spacing(3).into()
};
column![heading("Views by sheet"), list].spacing(6).into()
let by = state.by_category;
let header = row![
heading(if by { "View by category" } else { "View by sheet" }),
button(text(format!("{} ⇄", t!(if by { "View by sheet" } else { "View by category" }))).size(11))
.on_press(msg(SheetSetMsg::ViewsByCategory(!by)))
.style(button::subtle)
.padding([2, 4]),
button(crate::ui::icons::semantic(crate::ui::icons::PLUS, 12.0))
.on_press(msg(SheetSetMsg::NewCategory))
.style(button::subtle)
.padding([2, 4]),
]
.spacing(4)
.align_y(iced::Center);
column![header, scrollable(iced::widget::Column::with_children(sheet_views_rows(state, db)).spacing(1)).height(Fill)]
.spacing(6)
.into()
}
(Some(db), SsmTab::ModelViews) => {
let locations = model_views(db);
let list: Element<'a, Message> = if locations.is_empty() {
text(t!("No locations.").into_owned()).size(12).style(muted_style).into()
} else {
iced::widget::Column::with_children(locations.into_iter().map(|v| text(v).size(12).into()))
.spacing(3)
.into()
};
column![heading("Locations"), list].spacing(6).into()
(Some(_), SsmTab::ModelViews) => {
let header = row![
heading("Locations"),
button(text("↻").size(13)).on_press(msg(SheetSetMsg::Refresh)).style(button::subtle).padding([2, 4]),
button(crate::ui::icons::semantic(crate::ui::icons::PLUS, 12.0))
.on_press(msg(SheetSetMsg::AddLocation))
.style(button::subtle)
.padding([2, 4]),
]
.spacing(4)
.align_y(iced::Center);
column![header, scrollable(iced::widget::Column::with_children(model_views_rows(state)).spacing(1)).height(Fill)]
.spacing(6)
.into()
}
};
let card = container(body).padding(6).width(Fill).height(Fill).style(|theme: &Theme| container::Style {
@@ -813,6 +1058,12 @@ fn properties_view<'a>(p: &'a Properties) -> Element<'a, Message> {
.width(Fill)
.into()
}
RowKey::Publish => yes_no(
r.value != "Do Not Publish Sheets",
FieldId::Row(i),
"Publish by Sheet 'Include for Publish' Setting",
"Do Not Publish Sheets",
),
RowKey::Prop(_) => input(&r.value, FieldId::Row(i)),
};
rows.push(labeled(r.label, control));
@@ -906,71 +1157,264 @@ fn properties_view<'a>(p: &'a Properties) -> Element<'a, Message> {
.into()
}
fn form_view<'a>(f: &'a Form) -> Element<'a, Message> {
let body: Element<'a, Message> = match f.kind {
FormKind::NewSheet => column![
labeled("Number", input(&f.number, FieldId::Number)),
labeled("Sheet title", input(&f.title, FieldId::Title)),
labeled("File name", input(&f.file_name, FieldId::FileName)),
labeled("Folder path", container(text(f.folder.clone()).size(12).style(muted_style)).padding([5, 8])),
labeled("Sheet template", container(text(f.drawing.clone()).size(12).style(muted_style)).padding([5, 8])),
]
.spacing(8)
.into(),
FormKind::NewSubset => column![
labeled("Subset name", input(&f.title, FieldId::Title)),
labeled(
"New sheet location",
row![input(&f.folder, FieldId::Folder), browse(SheetSetMsg::Browse(FieldId::Folder))].spacing(6)
),
]
.spacing(8)
.into(),
FormKind::Rename => column![
labeled("Number", input(&f.number, FieldId::Number)),
labeled("Sheet title", input(&f.title, FieldId::Title)),
]
.spacing(8)
.into(),
FormKind::ImportLayout => {
let rows = f.layouts.iter().enumerate().map(|(i, (name, _))| {
button(text(name.clone()).size(12))
.on_press(msg(SheetSetMsg::Choose(FieldId::Layout, i)))
.style(button_style(f.layout == i))
.padding([3, 8])
.width(Fill)
.into()
});
column![
labeled("Drawing", container(text(f.drawing.clone()).size(12).style(muted_style)).padding([5, 8])),
text(t!("Layouts").into_owned()).size(12),
container(scrollable(iced::widget::Column::with_children(rows.collect::<Vec<_>>()).spacing(1)))
.height(Length::Fixed(160.0)),
]
.spacing(8)
.into()
}
};
let mut col = column![card(
match f.kind {
FormKind::NewSheet => "Sheet",
FormKind::NewSubset => "Subset",
FormKind::Rename => "Sheet",
FormKind::ImportLayout => "Import Layout as Sheet",
},
body
)]
.spacing(10);
if let Some(e) = error_band(&f.error) {
col = col.push(e);
fn check<'a>(on: bool, label: &str, field: FieldId, enabled: bool) -> Element<'a, Message> {
let c = checkbox(on).label(t!(label).into_owned()).text_size(12).size(14);
if enabled {
c.on_toggle(move |v| msg(SheetSetMsg::Toggle(field, v))).into()
} else {
c.into()
}
col.push(footer(
}
fn read_only<'a>(value: &str) -> Element<'a, Message> {
container(text(value.to_string()).size(12).style(muted_style)).padding([5, 8]).width(Fill).into()
}
fn ok_cancel<'a>(ok: &str) -> Element<'a, Message> {
footer(
vec![],
vec![
dialog_button(t!("Cancel"), msg(SheetSetMsg::Cancel), false).into(),
dialog_button(t!("OK"), msg(SheetSetMsg::Ok), true).into(),
dialog_button(t!(ok), msg(SheetSetMsg::Ok), true).into(),
],
))
)
}
fn yes_no<'a>(yes: bool, field: FieldId, a: &str, b: &str) -> Element<'a, Message> {
let opts = vec![t!(a).into_owned(), t!(b).into_owned()];
let first = opts[0].clone();
pick_list(Some(opts[if yes { 0 } else { 1 }].clone()), opts, |s: &String| s.clone())
.on_select(move |s: String| msg(SheetSetMsg::Toggle(field, s == first)))
.text_size(12)
.padding([5, 8])
.width(Fill)
.into()
}
fn form_view<'a>(f: &'a Form) -> Element<'a, Message> {
let number_title = row![
text(t!("Number").into_owned()).size(12).width(Length::Fixed(96.0)),
container(input(&f.number, FieldId::Number)).width(Length::Fixed(110.0)),
text(t!("Sheet title").into_owned()).size(12),
input(&f.title, FieldId::Title),
]
.spacing(8)
.align_y(iced::Center);
let short = |label: &str, control: Element<'a, Message>| -> Element<'a, Message> {
row![text(t!(label).into_owned()).size(12).width(Length::Fixed(96.0)), control].spacing(8).align_y(iced::Center).into()
};
let cards: Vec<Element<'a, Message>> = match f.kind {
FormKind::NewSheet => vec![card(
"Sheet",
column![
number_title,
short("File name", input(&f.file_name, FieldId::FileName)),
short("Folder path", read_only(&f.folder)),
short("Sheet template", read_only(&f.drawing)),
row![Space::new().width(Length::Fixed(104.0)), check(f.open_after, "Open in drawing editor", FieldId::OpenAfter, true)],
]
.spacing(8),
)],
FormKind::NewSubset => vec![card(
"Subset",
column![
labeled("Subset name", input(&f.title, FieldId::Title)),
labeled("Create folder hierarchy", yes_no(f.hierarchy, FieldId::Hierarchy, "Yes", "No")),
labeled(
"Publish sheets in subset",
yes_no(f.publish, FieldId::Publish, "Publish by Sheet 'Include for Publish' Setting", "Do Not Publish Sheets")
),
labeled(
"New sheet location",
if f.hierarchy {
read_only(&f.folder)
} else {
row![input(&f.folder, FieldId::Folder), browse(SheetSetMsg::Browse(FieldId::Folder))].spacing(6).into()
}
),
]
.spacing(8),
)],
FormKind::Rename => {
let layout: Element<'a, Message> = if f.rename[0] { read_only(&f.layout_name) } else { input(&f.layout_name, FieldId::LayoutName) };
let file: Element<'a, Message> = if f.rename[2] { read_only(&f.file_name) } else { input(&f.file_name, FieldId::FileName) };
vec![
card(
"Sheet",
column![number_title, short("Layout name", layout), short("File name", file), short("Folder path", read_only(&f.folder))]
.spacing(8),
),
card(
"Rename options",
row![
column![
text(t!("Rename layout to match:").into_owned()).size(12),
check(f.rename[0], "Sheet title", FieldId::RenameOption(0), true),
row![Space::new().width(22), check(f.rename[1], "Prefix with sheet number", FieldId::RenameOption(1), f.rename[0])],
]
.spacing(6)
.width(Fill),
column![
text(t!("Rename drawing file to match:").into_owned()).size(12),
check(f.rename[2], "Sheet title", FieldId::RenameOption(2), true),
row![Space::new().width(22), check(f.rename[3], "Prefix with sheet number", FieldId::RenameOption(3), f.rename[2])],
]
.spacing(6)
.width(Fill),
]
.spacing(16),
),
]
}
FormKind::ImportLayout => {
let head = row![
Space::new().width(22),
text(t!("Layout name").into_owned()).size(11).width(Fill),
text(t!("Drawing").into_owned()).size(11).width(Fill),
text(t!("Status").into_owned()).size(11).width(Fill),
]
.spacing(6);
let mut list = vec![head.into()];
for (k, r) in f.rows.iter().enumerate() {
let file = std::path::Path::new(&r.drawing).file_name().map(|n| n.to_string_lossy().to_string()).unwrap_or_default();
let status: Element<'a, Message> = match &r.owner {
None => text(t!("Available for import").into_owned()).size(12).style(|t: &Theme| text::Style { color: Some(t.palette().success.base.color) }).into(),
Some(owner) => text(crate::tf!("Belongs to sheet set {}", owner).into_owned()).size(12).style(|t: &Theme| text::Style { color: Some(t.palette().warning.base.color) }).into(),
};
let enabled = r.owner.is_none();
let cb = checkbox(r.on).size(14);
let cb: Element<'a, Message> = if enabled { cb.on_toggle(move |v| msg(SheetSetMsg::Toggle(FieldId::ImportRow(k), v))).into() } else { cb.into() };
let name = text(r.layout.clone()).size(12).width(Fill);
let file = text(file).size(12).width(Fill);
list.push(
row![cb, if enabled { name } else { name.style(muted_style) }, if enabled { file } else { file.style(muted_style) }, container(status).width(Fill)]
.spacing(6)
.align_y(iced::Center)
.into(),
);
}
vec![card(
"Drawings",
column![
row![
text(t!("Select drawing files containing layouts").into_owned()).size(12).width(Fill),
button(text(t!("Browse for Drawings...").into_owned()).size(12))
.on_press(msg(SheetSetMsg::BrowseDrawings))
.style(button_style(false))
.padding([5, 12]),
]
.align_y(iced::Center),
text(t!("A layout can belong to only one sheet set. If a layout already belongs to a sheet set, you must create a copy of the layout to import it.").into_owned())
.size(11)
.style(muted_style),
container(scrollable(iced::widget::Column::with_children(list).spacing(4)))
.padding(6)
.height(Length::Fixed(150.0))
.style(card_style),
check(f.prefix, "Prefix sheet titles with file name", FieldId::ImportPrefix, true),
]
.spacing(8),
)]
}
};
let mut col = iced::widget::Column::with_children(cards).spacing(10);
if let Some(e) = error_band(&f.error) {
col = col.push(e);
}
let foot = match f.kind {
FormKind::Rename => footer(
vec![
button(text(format!("‹ {}", t!("Previous"))).size(12)).on_press(msg(SheetSetMsg::Previous)).style(button_style(false)).padding([5, 12]).into(),
button(text(format!("{} ›", t!("Next"))).size(12)).on_press(msg(SheetSetMsg::Next)).style(button_style(false)).padding([5, 12]).into(),
],
vec![
dialog_button(t!("Cancel"), msg(SheetSetMsg::Cancel), false).into(),
dialog_button(t!("OK"), msg(SheetSetMsg::Ok), true).into(),
],
),
FormKind::ImportLayout => ok_cancel("Import Checked"),
_ => ok_cancel("OK"),
};
col.push(foot).into()
}
fn template_view<'a>(t: &'a TemplatePick) -> Element<'a, Message> {
let rows = t.layouts.iter().enumerate().map(|(i, name)| {
button(text(name.clone()).size(12))
.on_press(msg(SheetSetMsg::Choose(FieldId::Layout, i)))
.style(button_style(t.layout == i))
.padding([3, 8])
.width(Fill)
.into()
});
column![
card(
"Template",
column![
text(t!("Drawing template file name").into_owned()).size(12),
row![read_only(&t.file), browse(SheetSetMsg::BrowseTemplate)].spacing(6).align_y(iced::Center),
text(t!("Select a layout to create new sheets").into_owned()).size(12),
container(scrollable(iced::widget::Column::with_children(rows.collect::<Vec<_>>()).spacing(1)))
.padding(4)
.height(Length::Fixed(130.0))
.style(card_style),
]
.spacing(8)
),
ok_cancel("OK"),
]
.spacing(10)
.into()
}
fn category_view<'a>(c: &'a Category) -> Element<'a, Message> {
let blocks = c.blocks.iter().enumerate().map(|(i, (_, label, on))| check(*on, label, FieldId::CategoryBlock(i), true));
let mut col = column![card(
"Category",
column![
labeled("Category name", input(&c.name, FieldId::Name)),
text(t!("Select the callout blocks to be used in this category").into_owned()).size(12),
container(scrollable(iced::widget::Column::with_children(blocks.collect::<Vec<_>>()).spacing(4)))
.padding(6)
.height(Length::Fixed(90.0))
.width(Fill)
.style(card_style),
text(t!("Selected blocks will be available for selection when you insert a callout block from the view tab.").into_owned())
.size(11)
.style(muted_style),
button(text(t!("Add Blocks...").into_owned()).size(12))
.on_press(msg(SheetSetMsg::AddBlocks))
.style(button_style(false))
.padding([5, 12]),
]
.spacing(8)
)]
.spacing(10);
if let Some(e) = error_band(&c.error) {
col = col.push(e);
}
col.push(ok_cancel("OK")).into()
}
fn confirm_view<'a>(question: &'a str) -> Element<'a, Message> {
column![
row![
text("?").size(22).style(accent_text),
column![
text(question.to_string()).size(12),
text(t!("(The layout and the drawing file will not be deleted.)").into_owned()).size(12).style(muted_style),
]
.spacing(4),
]
.spacing(14),
row![
Space::new().width(Fill),
dialog_button(t!("Cancel"), msg(SheetSetMsg::Cancel), false),
dialog_button(t!("Remove"), msg(SheetSetMsg::Ok), true),
]
.spacing(6),
]
.spacing(14)
.into()
}
@@ -979,6 +1423,9 @@ pub fn dialog_view<'a>(state: &'a SheetSetManager, sizing: crate::ui::modal::Mod
Some(SsDialog::Wizard(w)) => wizard_view(w),
Some(SsDialog::Properties(p)) => properties_view(p),
Some(SsDialog::Form(f)) => form_view(f),
Some(SsDialog::Confirm(_, _, q)) => confirm_view(q),
Some(SsDialog::Template(t)) => template_view(t),
Some(SsDialog::Category(c)) => category_view(c),
None => Space::new().into(),
};
container(body).padding([10, 12]).width(sizing.width).into()