forked from 1b-agent/opencadstudio-upstream
Sheet sets: Place on Sheet, sheet view menus, block lists, missing status, field refresh
Model Views lists named model views and places them on the current sheet (xref, viewport, paper-space named view, view label with navigation fields, sheet view record); sheet view rows get Display, Rename & Renumber View, Set category, Place Callout Block and Place View Label Block; the View Category dialog's Add Blocks opens List of Blocks / Select Block; a sheet whose relative path is gone shows missing; sheet set fields store their values when a set changes; named views keep their centre relative to the target. Codec pin moves to the revision with these field helpers. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
5c9f19a4dc
commit
0d0fbafaa8
31 files changed
+1370
-88
No files matched your search
Generated
+1
-1
@@ -4206,7 +4206,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "opencadcodec"
|
||||
version = "0.5.5"
|
||||
source = "git+https://github.com/ramox81/cadcodec.git?rev=29aff7e#29aff7e8e6f4669cd1f41fc82d39521127c07d03"
|
||||
source = "git+https://github.com/ramox81/cadcodec.git?rev=1ace49e#1ace49ea940cd4e1337befac1004e57a7d36015b"
|
||||
dependencies = [
|
||||
"ahash 0.8.12",
|
||||
"anyhow",
|
||||
|
||||
+1
-1
@@ -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 = "29aff7e" }
|
||||
opencadcodec = { git = "https://github.com/ramox81/cadcodec.git", rev = "1ace49e" }
|
||||
|
||||
[patch.crates-io]
|
||||
iced_core = { git = "https://github.com/iced-rs/iced.git", rev = "23604ff22ab0aad9e00b9327cb7b8546ed84db39" }
|
||||
|
||||
@@ -4407,6 +4407,27 @@ view =
|
||||
.ss-new-sheet-location = New sheet location
|
||||
.ss-remove-subset = Remove Subset
|
||||
.ss-rename-subset = Rename Subset...
|
||||
.ss-rename-renumber-view = Rename & Renumber View
|
||||
.ss-list-of-blocks = List of Blocks
|
||||
.ss-select-block = Select Block
|
||||
.ss-set-category = Set category
|
||||
.ss-place-callout-block = Place Callout Block
|
||||
.ss-place-view-label-block = Place View Label Block
|
||||
.ss-place-on-sheet = Place on Sheet
|
||||
.ss-see-model-space-views = See Model Space Views
|
||||
.ss-view-title = View title
|
||||
.ss-add-x = Add...
|
||||
.ss-blocks-associated = The following blocks are associated with this sheet set:
|
||||
.ss-enter-drawing-file-name = Enter the drawing file name:
|
||||
.ss-enter-drawing-file-name-msg = Enter the drawing file name.
|
||||
.ss-select-drawing-as-block = Select the drawing file as a block
|
||||
.ss-choose-blocks-in-drawing = Choose blocks in the drawing file:
|
||||
.ss-preview = preview
|
||||
.ss-open-sheet-to-place = Open a sheet of this sheet set at its layout to place a view on it.
|
||||
.ss-open-view-sheet = Open the view's sheet at its layout to place a block on it.
|
||||
.ss-no-label-block = The sheet set has no label block for views.
|
||||
.ss-no-view-to-place = __ocs_fmt_0__: no view to place.
|
||||
.ss-cannot-be-read = __ocs_fmt_0__: cannot be read.
|
||||
.ss-layout-already-part = This layout is already part of a sheet set - not available for import.
|
||||
.ss-layout-may-belong = Warning: this layout may belong to another sheet set.
|
||||
.ss-status-missing = missing
|
||||
|
||||
@@ -4394,6 +4394,27 @@ view =
|
||||
.ss-new-sheet-location = New sheet location
|
||||
.ss-remove-subset = Remove Subset
|
||||
.ss-rename-subset = Rename Subset...
|
||||
.ss-rename-renumber-view = Rename & Renumber View
|
||||
.ss-list-of-blocks = List of Blocks
|
||||
.ss-select-block = Select Block
|
||||
.ss-set-category = Set category
|
||||
.ss-place-callout-block = Place Callout Block
|
||||
.ss-place-view-label-block = Place View Label Block
|
||||
.ss-place-on-sheet = Place on Sheet
|
||||
.ss-see-model-space-views = See Model Space Views
|
||||
.ss-view-title = View title
|
||||
.ss-add-x = Add...
|
||||
.ss-blocks-associated = The following blocks are associated with this sheet set:
|
||||
.ss-enter-drawing-file-name = Enter the drawing file name:
|
||||
.ss-enter-drawing-file-name-msg = Enter the drawing file name.
|
||||
.ss-select-drawing-as-block = Select the drawing file as a block
|
||||
.ss-choose-blocks-in-drawing = Choose blocks in the drawing file:
|
||||
.ss-preview = preview
|
||||
.ss-open-sheet-to-place = Open a sheet of this sheet set at its layout to place a view on it.
|
||||
.ss-open-view-sheet = Open the view's sheet at its layout to place a block on it.
|
||||
.ss-no-label-block = The sheet set has no label block for views.
|
||||
.ss-no-view-to-place = __ocs_fmt_0__: no view to place.
|
||||
.ss-cannot-be-read = __ocs_fmt_0__: cannot be read.
|
||||
.ss-layout-already-part = This layout is already part of a sheet set - not available for import.
|
||||
.ss-layout-may-belong = Warning: this layout may belong to another sheet set.
|
||||
.ss-status-missing = missing
|
||||
|
||||
@@ -4392,6 +4392,27 @@ view =
|
||||
.ss-new-sheet-location = New sheet location
|
||||
.ss-remove-subset = Remove Subset
|
||||
.ss-rename-subset = Rename Subset...
|
||||
.ss-rename-renumber-view = Rename & Renumber View
|
||||
.ss-list-of-blocks = List of Blocks
|
||||
.ss-select-block = Select Block
|
||||
.ss-set-category = Set category
|
||||
.ss-place-callout-block = Place Callout Block
|
||||
.ss-place-view-label-block = Place View Label Block
|
||||
.ss-place-on-sheet = Place on Sheet
|
||||
.ss-see-model-space-views = See Model Space Views
|
||||
.ss-view-title = View title
|
||||
.ss-add-x = Add...
|
||||
.ss-blocks-associated = The following blocks are associated with this sheet set:
|
||||
.ss-enter-drawing-file-name = Enter the drawing file name:
|
||||
.ss-enter-drawing-file-name-msg = Enter the drawing file name.
|
||||
.ss-select-drawing-as-block = Select the drawing file as a block
|
||||
.ss-choose-blocks-in-drawing = Choose blocks in the drawing file:
|
||||
.ss-preview = preview
|
||||
.ss-open-sheet-to-place = Open a sheet of this sheet set at its layout to place a view on it.
|
||||
.ss-open-view-sheet = Open the view's sheet at its layout to place a block on it.
|
||||
.ss-no-label-block = The sheet set has no label block for views.
|
||||
.ss-no-view-to-place = __ocs_fmt_0__: no view to place.
|
||||
.ss-cannot-be-read = __ocs_fmt_0__: cannot be read.
|
||||
.ss-layout-already-part = This layout is already part of a sheet set - not available for import.
|
||||
.ss-layout-may-belong = Warning: this layout may belong to another sheet set.
|
||||
.ss-status-missing = missing
|
||||
|
||||
@@ -4393,6 +4393,27 @@ view =
|
||||
.ss-new-sheet-location = New sheet location
|
||||
.ss-remove-subset = Remove Subset
|
||||
.ss-rename-subset = Rename Subset...
|
||||
.ss-rename-renumber-view = Rename & Renumber View
|
||||
.ss-list-of-blocks = List of Blocks
|
||||
.ss-select-block = Select Block
|
||||
.ss-set-category = Set category
|
||||
.ss-place-callout-block = Place Callout Block
|
||||
.ss-place-view-label-block = Place View Label Block
|
||||
.ss-place-on-sheet = Place on Sheet
|
||||
.ss-see-model-space-views = See Model Space Views
|
||||
.ss-view-title = View title
|
||||
.ss-add-x = Add...
|
||||
.ss-blocks-associated = The following blocks are associated with this sheet set:
|
||||
.ss-enter-drawing-file-name = Enter the drawing file name:
|
||||
.ss-enter-drawing-file-name-msg = Enter the drawing file name.
|
||||
.ss-select-drawing-as-block = Select the drawing file as a block
|
||||
.ss-choose-blocks-in-drawing = Choose blocks in the drawing file:
|
||||
.ss-preview = preview
|
||||
.ss-open-sheet-to-place = Open a sheet of this sheet set at its layout to place a view on it.
|
||||
.ss-open-view-sheet = Open the view's sheet at its layout to place a block on it.
|
||||
.ss-no-label-block = The sheet set has no label block for views.
|
||||
.ss-no-view-to-place = __ocs_fmt_0__: no view to place.
|
||||
.ss-cannot-be-read = __ocs_fmt_0__: cannot be read.
|
||||
.ss-layout-already-part = This layout is already part of a sheet set - not available for import.
|
||||
.ss-layout-may-belong = Warning: this layout may belong to another sheet set.
|
||||
.ss-status-missing = missing
|
||||
|
||||
@@ -4395,6 +4395,27 @@ view =
|
||||
.ss-new-sheet-location = New sheet location
|
||||
.ss-remove-subset = Remove Subset
|
||||
.ss-rename-subset = Rename Subset...
|
||||
.ss-rename-renumber-view = Rename & Renumber View
|
||||
.ss-list-of-blocks = List of Blocks
|
||||
.ss-select-block = Select Block
|
||||
.ss-set-category = Set category
|
||||
.ss-place-callout-block = Place Callout Block
|
||||
.ss-place-view-label-block = Place View Label Block
|
||||
.ss-place-on-sheet = Place on Sheet
|
||||
.ss-see-model-space-views = See Model Space Views
|
||||
.ss-view-title = View title
|
||||
.ss-add-x = Add...
|
||||
.ss-blocks-associated = The following blocks are associated with this sheet set:
|
||||
.ss-enter-drawing-file-name = Enter the drawing file name:
|
||||
.ss-enter-drawing-file-name-msg = Enter the drawing file name.
|
||||
.ss-select-drawing-as-block = Select the drawing file as a block
|
||||
.ss-choose-blocks-in-drawing = Choose blocks in the drawing file:
|
||||
.ss-preview = preview
|
||||
.ss-open-sheet-to-place = Open a sheet of this sheet set at its layout to place a view on it.
|
||||
.ss-open-view-sheet = Open the view's sheet at its layout to place a block on it.
|
||||
.ss-no-label-block = The sheet set has no label block for views.
|
||||
.ss-no-view-to-place = __ocs_fmt_0__: no view to place.
|
||||
.ss-cannot-be-read = __ocs_fmt_0__: cannot be read.
|
||||
.ss-layout-already-part = This layout is already part of a sheet set - not available for import.
|
||||
.ss-layout-may-belong = Warning: this layout may belong to another sheet set.
|
||||
.ss-status-missing = missing
|
||||
|
||||
@@ -4396,6 +4396,27 @@ view =
|
||||
.ss-new-sheet-location = New sheet location
|
||||
.ss-remove-subset = Remove Subset
|
||||
.ss-rename-subset = Rename Subset...
|
||||
.ss-rename-renumber-view = Rename & Renumber View
|
||||
.ss-list-of-blocks = List of Blocks
|
||||
.ss-select-block = Select Block
|
||||
.ss-set-category = Set category
|
||||
.ss-place-callout-block = Place Callout Block
|
||||
.ss-place-view-label-block = Place View Label Block
|
||||
.ss-place-on-sheet = Place on Sheet
|
||||
.ss-see-model-space-views = See Model Space Views
|
||||
.ss-view-title = View title
|
||||
.ss-add-x = Add...
|
||||
.ss-blocks-associated = The following blocks are associated with this sheet set:
|
||||
.ss-enter-drawing-file-name = Enter the drawing file name:
|
||||
.ss-enter-drawing-file-name-msg = Enter the drawing file name.
|
||||
.ss-select-drawing-as-block = Select the drawing file as a block
|
||||
.ss-choose-blocks-in-drawing = Choose blocks in the drawing file:
|
||||
.ss-preview = preview
|
||||
.ss-open-sheet-to-place = Open a sheet of this sheet set at its layout to place a view on it.
|
||||
.ss-open-view-sheet = Open the view's sheet at its layout to place a block on it.
|
||||
.ss-no-label-block = The sheet set has no label block for views.
|
||||
.ss-no-view-to-place = __ocs_fmt_0__: no view to place.
|
||||
.ss-cannot-be-read = __ocs_fmt_0__: cannot be read.
|
||||
.ss-layout-already-part = This layout is already part of a sheet set - not available for import.
|
||||
.ss-layout-may-belong = Warning: this layout may belong to another sheet set.
|
||||
.ss-status-missing = missing
|
||||
|
||||
@@ -4395,6 +4395,27 @@ view =
|
||||
.ss-new-sheet-location = New sheet location
|
||||
.ss-remove-subset = Remove Subset
|
||||
.ss-rename-subset = Rename Subset...
|
||||
.ss-rename-renumber-view = Rename & Renumber View
|
||||
.ss-list-of-blocks = List of Blocks
|
||||
.ss-select-block = Select Block
|
||||
.ss-set-category = Set category
|
||||
.ss-place-callout-block = Place Callout Block
|
||||
.ss-place-view-label-block = Place View Label Block
|
||||
.ss-place-on-sheet = Place on Sheet
|
||||
.ss-see-model-space-views = See Model Space Views
|
||||
.ss-view-title = View title
|
||||
.ss-add-x = Add...
|
||||
.ss-blocks-associated = The following blocks are associated with this sheet set:
|
||||
.ss-enter-drawing-file-name = Enter the drawing file name:
|
||||
.ss-enter-drawing-file-name-msg = Enter the drawing file name.
|
||||
.ss-select-drawing-as-block = Select the drawing file as a block
|
||||
.ss-choose-blocks-in-drawing = Choose blocks in the drawing file:
|
||||
.ss-preview = preview
|
||||
.ss-open-sheet-to-place = Open a sheet of this sheet set at its layout to place a view on it.
|
||||
.ss-open-view-sheet = Open the view's sheet at its layout to place a block on it.
|
||||
.ss-no-label-block = The sheet set has no label block for views.
|
||||
.ss-no-view-to-place = __ocs_fmt_0__: no view to place.
|
||||
.ss-cannot-be-read = __ocs_fmt_0__: cannot be read.
|
||||
.ss-layout-already-part = This layout is already part of a sheet set - not available for import.
|
||||
.ss-layout-may-belong = Warning: this layout may belong to another sheet set.
|
||||
.ss-status-missing = missing
|
||||
|
||||
@@ -4394,6 +4394,27 @@ view =
|
||||
.ss-new-sheet-location = New sheet location
|
||||
.ss-remove-subset = Remove Subset
|
||||
.ss-rename-subset = Rename Subset...
|
||||
.ss-rename-renumber-view = Rename & Renumber View
|
||||
.ss-list-of-blocks = List of Blocks
|
||||
.ss-select-block = Select Block
|
||||
.ss-set-category = Set category
|
||||
.ss-place-callout-block = Place Callout Block
|
||||
.ss-place-view-label-block = Place View Label Block
|
||||
.ss-place-on-sheet = Place on Sheet
|
||||
.ss-see-model-space-views = See Model Space Views
|
||||
.ss-view-title = View title
|
||||
.ss-add-x = Add...
|
||||
.ss-blocks-associated = The following blocks are associated with this sheet set:
|
||||
.ss-enter-drawing-file-name = Enter the drawing file name:
|
||||
.ss-enter-drawing-file-name-msg = Enter the drawing file name.
|
||||
.ss-select-drawing-as-block = Select the drawing file as a block
|
||||
.ss-choose-blocks-in-drawing = Choose blocks in the drawing file:
|
||||
.ss-preview = preview
|
||||
.ss-open-sheet-to-place = Open a sheet of this sheet set at its layout to place a view on it.
|
||||
.ss-open-view-sheet = Open the view's sheet at its layout to place a block on it.
|
||||
.ss-no-label-block = The sheet set has no label block for views.
|
||||
.ss-no-view-to-place = __ocs_fmt_0__: no view to place.
|
||||
.ss-cannot-be-read = __ocs_fmt_0__: cannot be read.
|
||||
.ss-layout-already-part = This layout is already part of a sheet set - not available for import.
|
||||
.ss-layout-may-belong = Warning: this layout may belong to another sheet set.
|
||||
.ss-status-missing = missing
|
||||
|
||||
@@ -4395,6 +4395,27 @@ view =
|
||||
.ss-new-sheet-location = New sheet location
|
||||
.ss-remove-subset = Remove Subset
|
||||
.ss-rename-subset = Rename Subset...
|
||||
.ss-rename-renumber-view = Rename & Renumber View
|
||||
.ss-list-of-blocks = List of Blocks
|
||||
.ss-select-block = Select Block
|
||||
.ss-set-category = Set category
|
||||
.ss-place-callout-block = Place Callout Block
|
||||
.ss-place-view-label-block = Place View Label Block
|
||||
.ss-place-on-sheet = Place on Sheet
|
||||
.ss-see-model-space-views = See Model Space Views
|
||||
.ss-view-title = View title
|
||||
.ss-add-x = Add...
|
||||
.ss-blocks-associated = The following blocks are associated with this sheet set:
|
||||
.ss-enter-drawing-file-name = Enter the drawing file name:
|
||||
.ss-enter-drawing-file-name-msg = Enter the drawing file name.
|
||||
.ss-select-drawing-as-block = Select the drawing file as a block
|
||||
.ss-choose-blocks-in-drawing = Choose blocks in the drawing file:
|
||||
.ss-preview = preview
|
||||
.ss-open-sheet-to-place = Open a sheet of this sheet set at its layout to place a view on it.
|
||||
.ss-open-view-sheet = Open the view's sheet at its layout to place a block on it.
|
||||
.ss-no-label-block = The sheet set has no label block for views.
|
||||
.ss-no-view-to-place = __ocs_fmt_0__: no view to place.
|
||||
.ss-cannot-be-read = __ocs_fmt_0__: cannot be read.
|
||||
.ss-layout-already-part = This layout is already part of a sheet set - not available for import.
|
||||
.ss-layout-may-belong = Warning: this layout may belong to another sheet set.
|
||||
.ss-status-missing = missing
|
||||
|
||||
@@ -4383,6 +4383,27 @@ view =
|
||||
.ss-new-sheet-location = New sheet location
|
||||
.ss-remove-subset = Remove Subset
|
||||
.ss-rename-subset = Rename Subset...
|
||||
.ss-rename-renumber-view = Rename & Renumber View
|
||||
.ss-list-of-blocks = List of Blocks
|
||||
.ss-select-block = Select Block
|
||||
.ss-set-category = Set category
|
||||
.ss-place-callout-block = Place Callout Block
|
||||
.ss-place-view-label-block = Place View Label Block
|
||||
.ss-place-on-sheet = Place on Sheet
|
||||
.ss-see-model-space-views = See Model Space Views
|
||||
.ss-view-title = View title
|
||||
.ss-add-x = Add...
|
||||
.ss-blocks-associated = The following blocks are associated with this sheet set:
|
||||
.ss-enter-drawing-file-name = Enter the drawing file name:
|
||||
.ss-enter-drawing-file-name-msg = Enter the drawing file name.
|
||||
.ss-select-drawing-as-block = Select the drawing file as a block
|
||||
.ss-choose-blocks-in-drawing = Choose blocks in the drawing file:
|
||||
.ss-preview = preview
|
||||
.ss-open-sheet-to-place = Open a sheet of this sheet set at its layout to place a view on it.
|
||||
.ss-open-view-sheet = Open the view's sheet at its layout to place a block on it.
|
||||
.ss-no-label-block = The sheet set has no label block for views.
|
||||
.ss-no-view-to-place = __ocs_fmt_0__: no view to place.
|
||||
.ss-cannot-be-read = __ocs_fmt_0__: cannot be read.
|
||||
.ss-layout-already-part = This layout is already part of a sheet set - not available for import.
|
||||
.ss-layout-may-belong = Warning: this layout may belong to another sheet set.
|
||||
.ss-status-missing = missing
|
||||
|
||||
@@ -4394,6 +4394,27 @@ view =
|
||||
.ss-new-sheet-location = New sheet location
|
||||
.ss-remove-subset = Remove Subset
|
||||
.ss-rename-subset = Rename Subset...
|
||||
.ss-rename-renumber-view = Rename & Renumber View
|
||||
.ss-list-of-blocks = List of Blocks
|
||||
.ss-select-block = Select Block
|
||||
.ss-set-category = Set category
|
||||
.ss-place-callout-block = Place Callout Block
|
||||
.ss-place-view-label-block = Place View Label Block
|
||||
.ss-place-on-sheet = Place on Sheet
|
||||
.ss-see-model-space-views = See Model Space Views
|
||||
.ss-view-title = View title
|
||||
.ss-add-x = Add...
|
||||
.ss-blocks-associated = The following blocks are associated with this sheet set:
|
||||
.ss-enter-drawing-file-name = Enter the drawing file name:
|
||||
.ss-enter-drawing-file-name-msg = Enter the drawing file name.
|
||||
.ss-select-drawing-as-block = Select the drawing file as a block
|
||||
.ss-choose-blocks-in-drawing = Choose blocks in the drawing file:
|
||||
.ss-preview = preview
|
||||
.ss-open-sheet-to-place = Open a sheet of this sheet set at its layout to place a view on it.
|
||||
.ss-open-view-sheet = Open the view's sheet at its layout to place a block on it.
|
||||
.ss-no-label-block = The sheet set has no label block for views.
|
||||
.ss-no-view-to-place = __ocs_fmt_0__: no view to place.
|
||||
.ss-cannot-be-read = __ocs_fmt_0__: cannot be read.
|
||||
.ss-layout-already-part = This layout is already part of a sheet set - not available for import.
|
||||
.ss-layout-may-belong = Warning: this layout may belong to another sheet set.
|
||||
.ss-status-missing = missing
|
||||
|
||||
@@ -4394,6 +4394,27 @@ view =
|
||||
.ss-new-sheet-location = New sheet location
|
||||
.ss-remove-subset = Remove Subset
|
||||
.ss-rename-subset = Rename Subset...
|
||||
.ss-rename-renumber-view = Rename & Renumber View
|
||||
.ss-list-of-blocks = List of Blocks
|
||||
.ss-select-block = Select Block
|
||||
.ss-set-category = Set category
|
||||
.ss-place-callout-block = Place Callout Block
|
||||
.ss-place-view-label-block = Place View Label Block
|
||||
.ss-place-on-sheet = Place on Sheet
|
||||
.ss-see-model-space-views = See Model Space Views
|
||||
.ss-view-title = View title
|
||||
.ss-add-x = Add...
|
||||
.ss-blocks-associated = The following blocks are associated with this sheet set:
|
||||
.ss-enter-drawing-file-name = Enter the drawing file name:
|
||||
.ss-enter-drawing-file-name-msg = Enter the drawing file name.
|
||||
.ss-select-drawing-as-block = Select the drawing file as a block
|
||||
.ss-choose-blocks-in-drawing = Choose blocks in the drawing file:
|
||||
.ss-preview = preview
|
||||
.ss-open-sheet-to-place = Open a sheet of this sheet set at its layout to place a view on it.
|
||||
.ss-open-view-sheet = Open the view's sheet at its layout to place a block on it.
|
||||
.ss-no-label-block = The sheet set has no label block for views.
|
||||
.ss-no-view-to-place = __ocs_fmt_0__: no view to place.
|
||||
.ss-cannot-be-read = __ocs_fmt_0__: cannot be read.
|
||||
.ss-layout-already-part = This layout is already part of a sheet set - not available for import.
|
||||
.ss-layout-may-belong = Warning: this layout may belong to another sheet set.
|
||||
.ss-status-missing = missing
|
||||
|
||||
@@ -4383,6 +4383,27 @@ view =
|
||||
.ss-new-sheet-location = New sheet location
|
||||
.ss-remove-subset = Remove Subset
|
||||
.ss-rename-subset = Rename Subset...
|
||||
.ss-rename-renumber-view = Rename & Renumber View
|
||||
.ss-list-of-blocks = List of Blocks
|
||||
.ss-select-block = Select Block
|
||||
.ss-set-category = Set category
|
||||
.ss-place-callout-block = Place Callout Block
|
||||
.ss-place-view-label-block = Place View Label Block
|
||||
.ss-place-on-sheet = Place on Sheet
|
||||
.ss-see-model-space-views = See Model Space Views
|
||||
.ss-view-title = View title
|
||||
.ss-add-x = Add...
|
||||
.ss-blocks-associated = The following blocks are associated with this sheet set:
|
||||
.ss-enter-drawing-file-name = Enter the drawing file name:
|
||||
.ss-enter-drawing-file-name-msg = Enter the drawing file name.
|
||||
.ss-select-drawing-as-block = Select the drawing file as a block
|
||||
.ss-choose-blocks-in-drawing = Choose blocks in the drawing file:
|
||||
.ss-preview = preview
|
||||
.ss-open-sheet-to-place = Open a sheet of this sheet set at its layout to place a view on it.
|
||||
.ss-open-view-sheet = Open the view's sheet at its layout to place a block on it.
|
||||
.ss-no-label-block = The sheet set has no label block for views.
|
||||
.ss-no-view-to-place = __ocs_fmt_0__: no view to place.
|
||||
.ss-cannot-be-read = __ocs_fmt_0__: cannot be read.
|
||||
.ss-layout-already-part = This layout is already part of a sheet set - not available for import.
|
||||
.ss-layout-may-belong = Warning: this layout may belong to another sheet set.
|
||||
.ss-status-missing = missing
|
||||
|
||||
@@ -4394,6 +4394,27 @@ view =
|
||||
.ss-new-sheet-location = New sheet location
|
||||
.ss-remove-subset = Remove Subset
|
||||
.ss-rename-subset = Rename Subset...
|
||||
.ss-rename-renumber-view = Rename & Renumber View
|
||||
.ss-list-of-blocks = List of Blocks
|
||||
.ss-select-block = Select Block
|
||||
.ss-set-category = Set category
|
||||
.ss-place-callout-block = Place Callout Block
|
||||
.ss-place-view-label-block = Place View Label Block
|
||||
.ss-place-on-sheet = Place on Sheet
|
||||
.ss-see-model-space-views = See Model Space Views
|
||||
.ss-view-title = View title
|
||||
.ss-add-x = Add...
|
||||
.ss-blocks-associated = The following blocks are associated with this sheet set:
|
||||
.ss-enter-drawing-file-name = Enter the drawing file name:
|
||||
.ss-enter-drawing-file-name-msg = Enter the drawing file name.
|
||||
.ss-select-drawing-as-block = Select the drawing file as a block
|
||||
.ss-choose-blocks-in-drawing = Choose blocks in the drawing file:
|
||||
.ss-preview = preview
|
||||
.ss-open-sheet-to-place = Open a sheet of this sheet set at its layout to place a view on it.
|
||||
.ss-open-view-sheet = Open the view's sheet at its layout to place a block on it.
|
||||
.ss-no-label-block = The sheet set has no label block for views.
|
||||
.ss-no-view-to-place = __ocs_fmt_0__: no view to place.
|
||||
.ss-cannot-be-read = __ocs_fmt_0__: cannot be read.
|
||||
.ss-layout-already-part = This layout is already part of a sheet set - not available for import.
|
||||
.ss-layout-may-belong = Warning: this layout may belong to another sheet set.
|
||||
.ss-status-missing = missing
|
||||
|
||||
@@ -4393,6 +4393,27 @@ view =
|
||||
.ss-new-sheet-location = New sheet location
|
||||
.ss-remove-subset = Remove Subset
|
||||
.ss-rename-subset = Rename Subset...
|
||||
.ss-rename-renumber-view = Rename & Renumber View
|
||||
.ss-list-of-blocks = List of Blocks
|
||||
.ss-select-block = Select Block
|
||||
.ss-set-category = Set category
|
||||
.ss-place-callout-block = Place Callout Block
|
||||
.ss-place-view-label-block = Place View Label Block
|
||||
.ss-place-on-sheet = Place on Sheet
|
||||
.ss-see-model-space-views = See Model Space Views
|
||||
.ss-view-title = View title
|
||||
.ss-add-x = Add...
|
||||
.ss-blocks-associated = The following blocks are associated with this sheet set:
|
||||
.ss-enter-drawing-file-name = Enter the drawing file name:
|
||||
.ss-enter-drawing-file-name-msg = Enter the drawing file name.
|
||||
.ss-select-drawing-as-block = Select the drawing file as a block
|
||||
.ss-choose-blocks-in-drawing = Choose blocks in the drawing file:
|
||||
.ss-preview = preview
|
||||
.ss-open-sheet-to-place = Open a sheet of this sheet set at its layout to place a view on it.
|
||||
.ss-open-view-sheet = Open the view's sheet at its layout to place a block on it.
|
||||
.ss-no-label-block = The sheet set has no label block for views.
|
||||
.ss-no-view-to-place = __ocs_fmt_0__: no view to place.
|
||||
.ss-cannot-be-read = __ocs_fmt_0__: cannot be read.
|
||||
.ss-layout-already-part = This layout is already part of a sheet set - not available for import.
|
||||
.ss-layout-may-belong = Warning: this layout may belong to another sheet set.
|
||||
.ss-status-missing = missing
|
||||
|
||||
@@ -4394,6 +4394,27 @@ view =
|
||||
.ss-new-sheet-location = New sheet location
|
||||
.ss-remove-subset = Remove Subset
|
||||
.ss-rename-subset = Rename Subset...
|
||||
.ss-rename-renumber-view = Rename & Renumber View
|
||||
.ss-list-of-blocks = List of Blocks
|
||||
.ss-select-block = Select Block
|
||||
.ss-set-category = Set category
|
||||
.ss-place-callout-block = Place Callout Block
|
||||
.ss-place-view-label-block = Place View Label Block
|
||||
.ss-place-on-sheet = Place on Sheet
|
||||
.ss-see-model-space-views = See Model Space Views
|
||||
.ss-view-title = View title
|
||||
.ss-add-x = Add...
|
||||
.ss-blocks-associated = The following blocks are associated with this sheet set:
|
||||
.ss-enter-drawing-file-name = Enter the drawing file name:
|
||||
.ss-enter-drawing-file-name-msg = Enter the drawing file name.
|
||||
.ss-select-drawing-as-block = Select the drawing file as a block
|
||||
.ss-choose-blocks-in-drawing = Choose blocks in the drawing file:
|
||||
.ss-preview = preview
|
||||
.ss-open-sheet-to-place = Open a sheet of this sheet set at its layout to place a view on it.
|
||||
.ss-open-view-sheet = Open the view's sheet at its layout to place a block on it.
|
||||
.ss-no-label-block = The sheet set has no label block for views.
|
||||
.ss-no-view-to-place = __ocs_fmt_0__: no view to place.
|
||||
.ss-cannot-be-read = __ocs_fmt_0__: cannot be read.
|
||||
.ss-layout-already-part = This layout is already part of a sheet set - not available for import.
|
||||
.ss-layout-may-belong = Warning: this layout may belong to another sheet set.
|
||||
.ss-status-missing = missing
|
||||
|
||||
@@ -4395,6 +4395,27 @@ view =
|
||||
.ss-new-sheet-location = New sheet location
|
||||
.ss-remove-subset = Remove Subset
|
||||
.ss-rename-subset = Rename Subset...
|
||||
.ss-rename-renumber-view = Rename & Renumber View
|
||||
.ss-list-of-blocks = List of Blocks
|
||||
.ss-select-block = Select Block
|
||||
.ss-set-category = Set category
|
||||
.ss-place-callout-block = Place Callout Block
|
||||
.ss-place-view-label-block = Place View Label Block
|
||||
.ss-place-on-sheet = Place on Sheet
|
||||
.ss-see-model-space-views = See Model Space Views
|
||||
.ss-view-title = View title
|
||||
.ss-add-x = Add...
|
||||
.ss-blocks-associated = The following blocks are associated with this sheet set:
|
||||
.ss-enter-drawing-file-name = Enter the drawing file name:
|
||||
.ss-enter-drawing-file-name-msg = Enter the drawing file name.
|
||||
.ss-select-drawing-as-block = Select the drawing file as a block
|
||||
.ss-choose-blocks-in-drawing = Choose blocks in the drawing file:
|
||||
.ss-preview = preview
|
||||
.ss-open-sheet-to-place = Open a sheet of this sheet set at its layout to place a view on it.
|
||||
.ss-open-view-sheet = Open the view's sheet at its layout to place a block on it.
|
||||
.ss-no-label-block = The sheet set has no label block for views.
|
||||
.ss-no-view-to-place = __ocs_fmt_0__: no view to place.
|
||||
.ss-cannot-be-read = __ocs_fmt_0__: cannot be read.
|
||||
.ss-layout-already-part = This layout is already part of a sheet set - not available for import.
|
||||
.ss-layout-may-belong = Warning: this layout may belong to another sheet set.
|
||||
.ss-status-missing = missing
|
||||
|
||||
@@ -4396,6 +4396,27 @@ view =
|
||||
.ss-new-sheet-location = New sheet location
|
||||
.ss-remove-subset = Remove Subset
|
||||
.ss-rename-subset = Rename Subset...
|
||||
.ss-rename-renumber-view = Rename & Renumber View
|
||||
.ss-list-of-blocks = List of Blocks
|
||||
.ss-select-block = Select Block
|
||||
.ss-set-category = Set category
|
||||
.ss-place-callout-block = Place Callout Block
|
||||
.ss-place-view-label-block = Place View Label Block
|
||||
.ss-place-on-sheet = Place on Sheet
|
||||
.ss-see-model-space-views = See Model Space Views
|
||||
.ss-view-title = View title
|
||||
.ss-add-x = Add...
|
||||
.ss-blocks-associated = The following blocks are associated with this sheet set:
|
||||
.ss-enter-drawing-file-name = Enter the drawing file name:
|
||||
.ss-enter-drawing-file-name-msg = Enter the drawing file name.
|
||||
.ss-select-drawing-as-block = Select the drawing file as a block
|
||||
.ss-choose-blocks-in-drawing = Choose blocks in the drawing file:
|
||||
.ss-preview = preview
|
||||
.ss-open-sheet-to-place = Open a sheet of this sheet set at its layout to place a view on it.
|
||||
.ss-open-view-sheet = Open the view's sheet at its layout to place a block on it.
|
||||
.ss-no-label-block = The sheet set has no label block for views.
|
||||
.ss-no-view-to-place = __ocs_fmt_0__: no view to place.
|
||||
.ss-cannot-be-read = __ocs_fmt_0__: cannot be read.
|
||||
.ss-layout-already-part = This layout is already part of a sheet set - not available for import.
|
||||
.ss-layout-may-belong = Warning: this layout may belong to another sheet set.
|
||||
.ss-status-missing = missing
|
||||
|
||||
@@ -4355,6 +4355,27 @@ 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-rename-renumber-view = Görünümü Yeniden Adlandır ve Numaralandır
|
||||
.ss-list-of-blocks = Blok Listesi
|
||||
.ss-select-block = Blok Seç
|
||||
.ss-set-category = Kategori ata
|
||||
.ss-place-callout-block = Açıklama Bloğu Yerleştir
|
||||
.ss-place-view-label-block = Görünüm Etiketi Bloğu Yerleştir
|
||||
.ss-place-on-sheet = Sayfaya Yerleştir
|
||||
.ss-see-model-space-views = Model Uzayı Görünümlerini Göster
|
||||
.ss-view-title = Görünüm başlığı
|
||||
.ss-add-x = Ekle…
|
||||
.ss-blocks-associated = Bu sayfa kümesiyle ilişkili bloklar
|
||||
.ss-enter-drawing-file-name = Çizim dosyası adı
|
||||
.ss-enter-drawing-file-name-msg = Çizim dosyası adını girin.
|
||||
.ss-select-drawing-as-block = Çizim dosyasını blok olarak seç
|
||||
.ss-choose-blocks-in-drawing = Çizim dosyasındaki blokları seç
|
||||
.ss-preview = önizleme
|
||||
.ss-open-sheet-to-place = Görünüm yerleştirmek için bu kümenin bir sayfasını kendi düzeninde açın.
|
||||
.ss-open-view-sheet = Blok yerleştirmek için görünümün sayfasını kendi düzeninde açın.
|
||||
.ss-no-label-block = Sayfa kümesinin görünüm etiketi bloğu yok.
|
||||
.ss-no-view-to-place = __ocs_fmt_0__: yerleştirilecek görünüm yok.
|
||||
.ss-cannot-be-read = __ocs_fmt_0__: okunamıyor.
|
||||
.ss-layout-already-part = Bu düzen zaten bir sayfa kümesinde - içe aktarılamaz.
|
||||
.ss-layout-may-belong = Uyarı: bu düzen başka bir sayfa kümesine ait olabilir.
|
||||
.ss-status-missing = yok
|
||||
|
||||
@@ -4378,6 +4378,27 @@ view =
|
||||
.ss-new-sheet-location = New sheet location
|
||||
.ss-remove-subset = Remove Subset
|
||||
.ss-rename-subset = Rename Subset...
|
||||
.ss-rename-renumber-view = Rename & Renumber View
|
||||
.ss-list-of-blocks = List of Blocks
|
||||
.ss-select-block = Select Block
|
||||
.ss-set-category = Set category
|
||||
.ss-place-callout-block = Place Callout Block
|
||||
.ss-place-view-label-block = Place View Label Block
|
||||
.ss-place-on-sheet = Place on Sheet
|
||||
.ss-see-model-space-views = See Model Space Views
|
||||
.ss-view-title = View title
|
||||
.ss-add-x = Add...
|
||||
.ss-blocks-associated = The following blocks are associated with this sheet set:
|
||||
.ss-enter-drawing-file-name = Enter the drawing file name:
|
||||
.ss-enter-drawing-file-name-msg = Enter the drawing file name.
|
||||
.ss-select-drawing-as-block = Select the drawing file as a block
|
||||
.ss-choose-blocks-in-drawing = Choose blocks in the drawing file:
|
||||
.ss-preview = preview
|
||||
.ss-open-sheet-to-place = Open a sheet of this sheet set at its layout to place a view on it.
|
||||
.ss-open-view-sheet = Open the view's sheet at its layout to place a block on it.
|
||||
.ss-no-label-block = The sheet set has no label block for views.
|
||||
.ss-no-view-to-place = __ocs_fmt_0__: no view to place.
|
||||
.ss-cannot-be-read = __ocs_fmt_0__: cannot be read.
|
||||
.ss-layout-already-part = This layout is already part of a sheet set - not available for import.
|
||||
.ss-layout-may-belong = Warning: this layout may belong to another sheet set.
|
||||
.ss-status-missing = missing
|
||||
|
||||
@@ -4390,6 +4390,27 @@ view =
|
||||
.ss-new-sheet-location = New sheet location
|
||||
.ss-remove-subset = Remove Subset
|
||||
.ss-rename-subset = Rename Subset...
|
||||
.ss-rename-renumber-view = Rename & Renumber View
|
||||
.ss-list-of-blocks = List of Blocks
|
||||
.ss-select-block = Select Block
|
||||
.ss-set-category = Set category
|
||||
.ss-place-callout-block = Place Callout Block
|
||||
.ss-place-view-label-block = Place View Label Block
|
||||
.ss-place-on-sheet = Place on Sheet
|
||||
.ss-see-model-space-views = See Model Space Views
|
||||
.ss-view-title = View title
|
||||
.ss-add-x = Add...
|
||||
.ss-blocks-associated = The following blocks are associated with this sheet set:
|
||||
.ss-enter-drawing-file-name = Enter the drawing file name:
|
||||
.ss-enter-drawing-file-name-msg = Enter the drawing file name.
|
||||
.ss-select-drawing-as-block = Select the drawing file as a block
|
||||
.ss-choose-blocks-in-drawing = Choose blocks in the drawing file:
|
||||
.ss-preview = preview
|
||||
.ss-open-sheet-to-place = Open a sheet of this sheet set at its layout to place a view on it.
|
||||
.ss-open-view-sheet = Open the view's sheet at its layout to place a block on it.
|
||||
.ss-no-label-block = The sheet set has no label block for views.
|
||||
.ss-no-view-to-place = __ocs_fmt_0__: no view to place.
|
||||
.ss-cannot-be-read = __ocs_fmt_0__: cannot be read.
|
||||
.ss-layout-already-part = This layout is already part of a sheet set - not available for import.
|
||||
.ss-layout-may-belong = Warning: this layout may belong to another sheet set.
|
||||
.ss-status-missing = missing
|
||||
|
||||
+567
-31
@@ -4,9 +4,13 @@
|
||||
|
||||
use crate::app::{Message, OpenCADStudio};
|
||||
use crate::ui::window::sheet_set::{
|
||||
Category, FieldId, Form, FormKind, FoundLayout, ImportRow, MenuAction, PropRow, Properties, RowKey, SheetSetMsg,
|
||||
SheetStatus, SsDialog, TemplatePick, Wizard, WizardMsg,
|
||||
BlockList, Category, FieldId, Form, FormKind, FoundLayout, ImportRow, MenuAction, Placing, PropRow, Properties,
|
||||
RowKey, SelectBlock, SheetSetMsg, SheetStatus, SsDialog, TemplatePick, ViewAction, Wizard, WizardMsg,
|
||||
};
|
||||
use crate::command::{CadCommand, CmdOption, CmdResult};
|
||||
use codec::entities::Entity as _;
|
||||
use crate::scene::model::wire_model::WireModel;
|
||||
use glam::DVec3;
|
||||
use codec::sheet_set::{self as ss, ComponentKind, LayoutReference, SheetSetData, SheetSetDatabase};
|
||||
use iced::Task;
|
||||
use std::collections::HashSet;
|
||||
@@ -113,6 +117,113 @@ pub(in crate::app) fn release_lock(path: &Path) {
|
||||
let _ = std::fs::remove_file(path.with_extension("dwl2"));
|
||||
}
|
||||
|
||||
/// The insertion point of Place on Sheet (with the scale, picked from the
|
||||
/// right-click list) or of a callout / view label block.
|
||||
struct SheetSetPlaceCommand {
|
||||
/// The view's size in model units (zero for a block).
|
||||
size: (f64, f64),
|
||||
scale: f64,
|
||||
scales: Vec<(String, f64)>,
|
||||
}
|
||||
|
||||
impl CadCommand for SheetSetPlaceCommand {
|
||||
fn name(&self) -> &'static str {
|
||||
"SSMPLACE"
|
||||
}
|
||||
|
||||
fn prompt(&self) -> String {
|
||||
"Specify insertion point:".into()
|
||||
}
|
||||
|
||||
fn options(&self) -> Vec<CmdOption> {
|
||||
self.scales.iter().map(|(name, _)| CmdOption::new(name, name)).collect()
|
||||
}
|
||||
|
||||
fn wants_text_input(&self) -> bool {
|
||||
!self.scales.is_empty()
|
||||
}
|
||||
|
||||
fn on_text_input(&mut self, text: &str) -> Option<CmdResult> {
|
||||
let (_, scale) = self.scales.iter().find(|(name, _)| name.eq_ignore_ascii_case(text.trim()))?;
|
||||
self.scale = *scale;
|
||||
Some(CmdResult::NeedPoint)
|
||||
}
|
||||
|
||||
fn on_point(&mut self, pt: DVec3) -> CmdResult {
|
||||
CmdResult::Dispatch(format!("_SSMPLACEPOINT {} {} {}", pt.x, pt.y, self.scale))
|
||||
}
|
||||
|
||||
fn on_enter(&mut self) -> CmdResult {
|
||||
CmdResult::Cancel
|
||||
}
|
||||
|
||||
fn on_escape(&mut self) -> CmdResult {
|
||||
CmdResult::Cancel
|
||||
}
|
||||
|
||||
/// The viewport's outline follows the cursor at its lower-left corner.
|
||||
fn on_preview_wires(&mut self, pt: DVec3) -> Vec<WireModel> {
|
||||
let (w, h) = (self.size.0 * self.scale, self.size.1 * self.scale);
|
||||
if w <= 0.0 || h <= 0.0 {
|
||||
return Vec::new();
|
||||
}
|
||||
let p = |x: f64, y: f64| [pt.x + x, pt.y + y, pt.z];
|
||||
vec![WireModel::solid_f64(
|
||||
"ssm_place".to_string(),
|
||||
vec![p(0.0, 0.0), p(w, 0.0), p(w, h), p(0.0, h), p(0.0, 0.0)],
|
||||
WireModel::CYAN,
|
||||
false,
|
||||
)]
|
||||
}
|
||||
}
|
||||
|
||||
/// A model view to place: centre (world), width, height, target, direction.
|
||||
struct ModelView {
|
||||
center: codec::types::Vector3,
|
||||
width: f64,
|
||||
height: f64,
|
||||
target: codec::types::Vector3,
|
||||
direction: codec::types::Vector3,
|
||||
}
|
||||
|
||||
/// Named view `view` of a model drawing, or its extents.
|
||||
// ponytail: plan views only (centre = target + view centre); a twisted or 3D
|
||||
// view would need the full DCS transform.
|
||||
fn model_view(doc: &codec::CadDocument, view: Option<&str>) -> Option<ModelView> {
|
||||
use codec::types::Vector3;
|
||||
if let Some(name) = view {
|
||||
let v = doc.views.iter().find(|v| !v.paper_space && v.name.eq_ignore_ascii_case(name))?;
|
||||
return Some(ModelView {
|
||||
center: Vector3::new(v.target.x + v.center.x, v.target.y + v.center.y, v.target.z),
|
||||
width: v.width.abs().max(1e-6),
|
||||
height: v.height.abs().max(1e-6),
|
||||
target: v.target.clone(),
|
||||
direction: v.direction.clone(),
|
||||
});
|
||||
}
|
||||
let (lo, hi) = (&doc.header.model_space_extents_min, &doc.header.model_space_extents_max);
|
||||
let (w, h) = (hi.x - lo.x, hi.y - lo.y);
|
||||
if !(w > 0.0 && h > 0.0 && w.is_finite() && h.is_finite()) {
|
||||
return None;
|
||||
}
|
||||
Some(ModelView {
|
||||
center: Vector3::new((lo.x + hi.x) / 2.0, (lo.y + hi.y) / 2.0, 0.0),
|
||||
width: w,
|
||||
height: h,
|
||||
target: Vector3::ZERO,
|
||||
direction: Vector3::new(0.0, 0.0, 1.0),
|
||||
})
|
||||
}
|
||||
|
||||
/// The `Database("…").SheetSet("…").Component("…").` prefix of a navigation field.
|
||||
fn component_prefix(db: &SheetSetDatabase, id: &str) -> String {
|
||||
format!(
|
||||
"Database(\"{}\").SheetSet(\"{}\").Component(\"{id}\").",
|
||||
ss::native_path(db.path.as_deref().unwrap_or("")),
|
||||
db.sheet_set().id()
|
||||
)
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
@@ -166,6 +277,18 @@ fn follow_rename(f: &mut Form) {
|
||||
}
|
||||
}
|
||||
|
||||
fn view_form(db: &SheetSetDatabase, set: usize, id: &str) -> Form {
|
||||
let el = db.find(id);
|
||||
Form {
|
||||
kind: FormKind::RenameView,
|
||||
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(),
|
||||
..Form::default()
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
@@ -236,6 +359,13 @@ impl OpenCADStudio {
|
||||
self.open_new_sheet_set_wizard();
|
||||
Some(Task::none())
|
||||
}
|
||||
"_SSMPLACEPOINT" => {
|
||||
let v: Vec<f64> = arg.split_whitespace().filter_map(|t| t.parse().ok()).collect();
|
||||
if let [x, y, scale] = v[..] {
|
||||
self.place_at(i, x, y, scale);
|
||||
}
|
||||
Some(Task::none())
|
||||
}
|
||||
"OPENSHEETSET" => {
|
||||
if !arg.is_empty() {
|
||||
return Some(self.update(Message::SheetSet(SheetSetMsg::OpenPicked(Some(PathBuf::from(
|
||||
@@ -345,6 +475,8 @@ impl OpenCADStudio {
|
||||
self.sheet_set.status.clear();
|
||||
}
|
||||
for tab in &mut self.tabs {
|
||||
// The fields keep the new values, as when the reference updates them.
|
||||
crate::entities::field::refresh_sheet_set_fields(&mut tab.scene.document);
|
||||
let changes: Vec<_> = tab
|
||||
.scene
|
||||
.document
|
||||
@@ -571,6 +703,36 @@ impl OpenCADStudio {
|
||||
self.save_current_sheet_set();
|
||||
}
|
||||
SheetSetMsg::AddBlocks => {
|
||||
if let Some(SsDialog::Category(c)) = self.sheet_set.dialog.take() {
|
||||
let blocks = c.blocks.iter().map(|(id, label, _)| (id.clone(), label.clone())).collect();
|
||||
self.sheet_set.dialog = Some(SsDialog::BlockList(BlockList { category: Box::new(c), blocks, selected: None }));
|
||||
}
|
||||
}
|
||||
SheetSetMsg::BlocksPicked(_) | SheetSetMsg::LocationPicked(None) => {}
|
||||
SheetSetMsg::BlockListSelect(k) => {
|
||||
if let Some(SsDialog::BlockList(b)) = self.sheet_set.dialog.as_mut() {
|
||||
b.selected = Some(k);
|
||||
}
|
||||
}
|
||||
SheetSetMsg::BlockListDelete => {
|
||||
if let Some(SsDialog::BlockList(b)) = self.sheet_set.dialog.as_mut() {
|
||||
if let Some(k) = b.selected.take().filter(|k| *k < b.blocks.len()) {
|
||||
b.blocks.remove(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
SheetSetMsg::BlockListAdd => {
|
||||
if let Some(SsDialog::BlockList(b)) = self.sheet_set.dialog.take() {
|
||||
self.sheet_set.dialog = Some(SsDialog::SelectBlock(SelectBlock {
|
||||
list: Box::new(b),
|
||||
file: String::new(),
|
||||
whole: true,
|
||||
names: Vec::new(),
|
||||
error: None,
|
||||
}));
|
||||
}
|
||||
}
|
||||
SheetSetMsg::SelectBlockBrowse => {
|
||||
return Task::perform(
|
||||
async {
|
||||
crate::sys::file_dialog()
|
||||
@@ -580,11 +742,36 @@ impl OpenCADStudio {
|
||||
.await
|
||||
.map(|h| crate::sys::handle_path(&h))
|
||||
},
|
||||
|p| Message::SheetSet(SheetSetMsg::BlocksPicked(p)),
|
||||
|p| Message::SheetSet(SheetSetMsg::SelectBlockPicked(p)),
|
||||
)
|
||||
}
|
||||
SheetSetMsg::BlocksPicked(Some(path)) => self.category_add_blocks(path),
|
||||
SheetSetMsg::BlocksPicked(None) | SheetSetMsg::LocationPicked(None) => {}
|
||||
SheetSetMsg::SelectBlockPicked(None) => {}
|
||||
SheetSetMsg::SelectBlockPicked(Some(path)) => self.select_block_file(path),
|
||||
SheetSetMsg::SelectBlockWhole(v) => {
|
||||
if let Some(SsDialog::SelectBlock(b)) = self.sheet_set.dialog.as_mut() {
|
||||
b.whole = v;
|
||||
}
|
||||
}
|
||||
SheetSetMsg::SelectBlockCheck(k, v) => {
|
||||
if let Some(SsDialog::SelectBlock(b)) = self.sheet_set.dialog.as_mut() {
|
||||
if let Some(n) = b.names.get_mut(k) {
|
||||
n.2 = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
SheetSetMsg::ToggleDrawing(path) => {
|
||||
let key = ss::path_key(&path);
|
||||
if !self.sheet_set.open_drawings.remove(&key) {
|
||||
self.load_model_views(&path);
|
||||
self.sheet_set.open_drawings.insert(key);
|
||||
}
|
||||
}
|
||||
SheetSetMsg::SeeViews(path) => {
|
||||
self.load_model_views(&path);
|
||||
self.sheet_set.open_drawings.insert(ss::path_key(&path));
|
||||
}
|
||||
SheetSetMsg::PlaceOnSheet(path, view) => self.start_place_view(path, view),
|
||||
SheetSetMsg::ViewMenu(id, action) => return self.view_menu(id, action),
|
||||
SheetSetMsg::AddLocation => {
|
||||
return Task::perform(
|
||||
async {
|
||||
@@ -790,6 +977,8 @@ impl OpenCADStudio {
|
||||
/// the wizard goes back to it.
|
||||
pub(in crate::app) fn close_sheet_set_dialog(&mut self) {
|
||||
match self.sheet_set.dialog.take() {
|
||||
Some(SsDialog::BlockList(b)) => self.sheet_set.dialog = Some(SsDialog::Category(*b.category)),
|
||||
Some(SsDialog::SelectBlock(b)) => self.sheet_set.dialog = Some(SsDialog::BlockList(*b.list)),
|
||||
Some(SsDialog::Properties(p)) if p.wizard.is_some() => {
|
||||
self.sheet_set.dialog = p.wizard.map(|w| SsDialog::Wizard(*w));
|
||||
}
|
||||
@@ -936,6 +1125,9 @@ impl OpenCADStudio {
|
||||
if ss::path_key(path) == *want {
|
||||
task = Task::done(Message::LayoutSwitch(layout.clone()));
|
||||
self.sheet_set_pending_layout = None;
|
||||
if let Some(view) = self.sheet_set.pending_view.take() {
|
||||
task = task.chain(Task::done(Message::Command(format!("VIEW RESTORE {view}"))));
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.sheet_set.settings.locate == 1 {
|
||||
@@ -1030,7 +1222,7 @@ impl OpenCADStudio {
|
||||
c.name = v;
|
||||
}
|
||||
}
|
||||
Some(SsDialog::Confirm(..)) | Some(SsDialog::Template(_)) => {}
|
||||
Some(SsDialog::Confirm(..)) | Some(SsDialog::Template(_)) | Some(SsDialog::BlockList(_)) | Some(SsDialog::SelectBlock(_)) => {}
|
||||
Some(SsDialog::Form(f)) => {
|
||||
let file_follows = f.file_name == format!("{} {}", f.number, f.title).trim();
|
||||
match field {
|
||||
@@ -1248,6 +1440,25 @@ impl OpenCADStudio {
|
||||
/// 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 f.kind == FormKind::RenameView {
|
||||
let Some(db) = self.sheet_set.sets.get_mut(f.set) else { return };
|
||||
if let Some(el) = db.find_mut(&f.component) {
|
||||
if f.number.trim().is_empty() {
|
||||
el.remove_named("Number");
|
||||
} else {
|
||||
el.set_prop("Number", f.number.trim());
|
||||
}
|
||||
el.set_prop("Title", f.title.trim());
|
||||
}
|
||||
let ids: Vec<String> = db.sheets().into_iter().flat_map(|s| db.sheet_views(s)).map(|v| v.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 form = view_form(db, f.set, &ids[next]);
|
||||
self.sheet_set.current = Some(f.set);
|
||||
self.save_current_sheet_set();
|
||||
self.sheet_set.dialog = Some(SsDialog::Form(form));
|
||||
return;
|
||||
}
|
||||
if let Err(e) = self.apply_rename(&f) {
|
||||
self.sheet_set.dialog = Some(SsDialog::Form(Form { error: Some(e), ..f }));
|
||||
return;
|
||||
@@ -1279,33 +1490,10 @@ impl OpenCADStudio {
|
||||
})
|
||||
.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.sheet_set.dialog = Some(SsDialog::Category(Category { set, id, name, blocks, removed: Vec::new(), 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() {
|
||||
@@ -1315,6 +1503,21 @@ impl OpenCADStudio {
|
||||
}
|
||||
self.close_active_modal();
|
||||
let Some(db) = self.sheet_set.sets.get_mut(c.set) else { return };
|
||||
// Blocks deleted in List of Blocks leave the set and every category.
|
||||
if !c.removed.is_empty() {
|
||||
let cats: Vec<(String, String, Vec<String>)> = db
|
||||
.view_categories()
|
||||
.iter()
|
||||
.map(|k| (k.id().to_string(), k.prop("Name").unwrap_or("").to_string(), db.category_blocks(k.id())))
|
||||
.collect();
|
||||
for (id, name, blocks) in cats {
|
||||
let kept: Vec<String> = blocks.into_iter().filter(|b| !c.removed.contains(b)).collect();
|
||||
db.set_view_category(Some(&id), &name, &kept);
|
||||
}
|
||||
for id in &c.removed {
|
||||
db.remove(id);
|
||||
}
|
||||
}
|
||||
let mut used = Vec::new();
|
||||
for (id, _, on) in &c.blocks {
|
||||
let id = match id.strip_prefix("new:") {
|
||||
@@ -1337,6 +1540,280 @@ impl OpenCADStudio {
|
||||
self.save_current_sheet_set();
|
||||
}
|
||||
|
||||
/// Named model views of a drawing (read once, when its row is opened).
|
||||
fn load_model_views(&mut self, path: &str) {
|
||||
let key = ss::path_key(path);
|
||||
if self.sheet_set.model_views.contains_key(&key) {
|
||||
return;
|
||||
}
|
||||
let views = crate::io::load_file(Path::new(path))
|
||||
.map(|d| d.views.iter().filter(|v| !v.paper_space).map(|v| v.name.clone()).collect())
|
||||
.unwrap_or_default();
|
||||
self.sheet_set.model_views.insert(key, views);
|
||||
}
|
||||
|
||||
/// The current set's sheet shown by the active tab at its current layout.
|
||||
fn current_sheet(&self) -> Option<(usize, String)> {
|
||||
let set = self.sheet_set.current?;
|
||||
let db = self.sheet_set.db()?;
|
||||
let tab = &self.tabs[self.active_tab];
|
||||
let path = tab.current_path.as_ref()?.to_string_lossy().to_string();
|
||||
let layout = tab.scene.current_layout.clone();
|
||||
let sheet = db.sheet_for(&path, Some(&layout))?;
|
||||
sheet
|
||||
.named("Layout")
|
||||
.and_then(|r| r.prop("Name"))
|
||||
.is_some_and(|n| n.eq_ignore_ascii_case(&layout))
|
||||
.then(|| (set, sheet.id().to_string()))
|
||||
}
|
||||
|
||||
/// Start the insertion point of Place on Sheet / a callout or label block.
|
||||
fn start_placing(&mut self, placing: Placing, size: (f64, f64)) {
|
||||
let i = self.active_tab;
|
||||
let scales: Vec<(String, f64)> = if size.0 > 0.0 {
|
||||
self.tabs[i]
|
||||
.scene
|
||||
.scale_list()
|
||||
.into_iter()
|
||||
.filter(|(_, _, factor)| *factor > 0.0)
|
||||
.map(|(name, _, factor)| (name, factor))
|
||||
.collect()
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
self.sheet_set.placing = Some(placing);
|
||||
let command = SheetSetPlaceCommand { size, scale: 1.0, scales };
|
||||
self.command_line.push_info(&command.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(command));
|
||||
}
|
||||
|
||||
/// Place on Sheet: only on a sheet of this set open at its layout.
|
||||
fn start_place_view(&mut self, drawing: String, view: Option<String>) {
|
||||
let Some((set, sheet)) = self.current_sheet() else {
|
||||
self.command_line
|
||||
.push_error(crate::t!("Open a sheet of this sheet set at its layout to place a view on it.").as_ref());
|
||||
return;
|
||||
};
|
||||
let size = crate::io::load_file(Path::new(&drawing))
|
||||
.ok()
|
||||
.and_then(|d| model_view(&d, view.as_deref()))
|
||||
.map(|v| (v.width, v.height));
|
||||
let Some(size) = size else {
|
||||
self.command_line.push_error(crate::tf!("{}: no view to place.", drawing).as_ref());
|
||||
return;
|
||||
};
|
||||
self.start_placing(Placing::View { set, sheet, drawing, view }, size);
|
||||
}
|
||||
|
||||
/// A sheet view's commands.
|
||||
fn view_menu(&mut self, id: String, action: ViewAction) -> Task<Message> {
|
||||
let Some(set) = self.sheet_set.current else { return Task::none() };
|
||||
let Some(db) = self.sheet_set.db() else { return Task::none() };
|
||||
let Some(sheet) = db.parent_of(&id).and_then(|v| db.parent_of(v.id())).map(|s| s.id().to_string()) else {
|
||||
return Task::none();
|
||||
};
|
||||
let view_name = db.find(&id).and_then(|v| v.named("NamedView")).and_then(|r| r.prop("Name")).unwrap_or("").to_string();
|
||||
match action {
|
||||
ViewAction::Display => {
|
||||
let open = db.layout_reference(&sheet, "Layout").map(|r| self.tab_showing(Path::new(&r.file_name)).is_some()).unwrap_or(false);
|
||||
let task = self.open_sheet(&sheet);
|
||||
if open {
|
||||
return task.chain(Task::done(Message::Command(format!("VIEW RESTORE {view_name}"))));
|
||||
}
|
||||
self.sheet_set.pending_view = Some(view_name);
|
||||
return task;
|
||||
}
|
||||
ViewAction::Rename => {
|
||||
self.sheet_set.dialog = Some(SsDialog::Form(view_form(db, set, &id)));
|
||||
self.active_modal = Some(crate::app::ModalKind::SheetSet);
|
||||
}
|
||||
ViewAction::Category(category) => {
|
||||
if let Some(db) = self.sheet_set.db_mut() {
|
||||
if let Some(v) = db.find_mut(&id) {
|
||||
let mut r = ss::object("AcSmObjectReference", ss::CLSID_OBJECT_REFERENCE, Some("Category"));
|
||||
r.set_prop_vt("ReferencedObject", -1, &category);
|
||||
v.put_named(r);
|
||||
}
|
||||
}
|
||||
self.save_current_sheet_set();
|
||||
}
|
||||
ViewAction::Callout(_) | ViewAction::Label if self.current_sheet().map(|s| s.1) != Some(sheet.clone()) => {
|
||||
self.command_line
|
||||
.push_error(crate::t!("Open the view's sheet at its layout to place a block on it.").as_ref());
|
||||
}
|
||||
ViewAction::Callout(block) => {
|
||||
let Some(b) = db.find(&block) else { return Task::none() };
|
||||
let (file, name) = (db.resolve_file(b), b.prop("Name").unwrap_or("").to_string());
|
||||
self.start_placing(Placing::Block { set, sheet, view: id, file, name }, (0.0, 0.0));
|
||||
}
|
||||
ViewAction::Label => {
|
||||
let Some(b) = db.sheet_set().named("DefLabelBlk") else {
|
||||
self.command_line.push_error(crate::t!("The sheet set has no label block for views.").as_ref());
|
||||
return Task::none();
|
||||
};
|
||||
let (file, name) = (db.resolve_file(b), b.prop("Name").unwrap_or("").to_string());
|
||||
self.start_placing(Placing::Block { set, sheet, view: id, file, name }, (0.0, 0.0));
|
||||
}
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
/// Bring block `name` of drawing `file` into tab `i` (when missing) and
|
||||
/// insert it at `at` with its attributes; their `?View.` / `?Sheet.`
|
||||
/// fields become the view's and sheet's navigation fields.
|
||||
fn insert_set_block(&mut self, i: usize, file: &str, name: &str, at: codec::types::Vector3, view: &str, sheet: &str, set: usize) {
|
||||
let Ok(source) = crate::io::load_file(Path::new(file)) else {
|
||||
self.command_line.push_error(crate::tf!("{}: cannot be read.", file).as_ref());
|
||||
return;
|
||||
};
|
||||
let probe = codec::EntityType::Insert(codec::entities::Insert::new(name.to_string(), codec::types::Vector3::ZERO));
|
||||
let deps = crate::app::ClipboardDeps::capture(&source, std::slice::from_ref(&probe));
|
||||
self.merge_dependencies(i, &deps);
|
||||
for def in deps.blocks {
|
||||
let scene = &mut self.tabs[i].scene;
|
||||
if scene.document.block_records.get(&def.name).is_none() {
|
||||
scene.define_block_raw(&def.name, def.base_point, def.entities);
|
||||
}
|
||||
}
|
||||
let units = source.block_records.get(name).map(|b| b.units).filter(|u| *u != 0).unwrap_or(source.header.insertion_units);
|
||||
let host = self.tabs[i].scene.document.header.insertion_units;
|
||||
let k = crate::app::properties::insert_unit_scale(host, units).unwrap_or(1.0);
|
||||
let mut insert = codec::entities::Insert::new(name.to_string(), at).with_scale(k, k, k);
|
||||
let transform = insert.get_transform();
|
||||
let doc = &self.tabs[i].scene.document;
|
||||
let attdefs: Vec<codec::entities::AttributeDefinition> = doc
|
||||
.block_records
|
||||
.get(name)
|
||||
.map(|br| {
|
||||
br.entity_handles
|
||||
.iter()
|
||||
.filter_map(|h| match doc.get_entity(*h) {
|
||||
Some(codec::EntityType::AttributeDefinition(d)) if !d.flags.constant => Some(d.clone()),
|
||||
_ => None,
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
for d in &attdefs {
|
||||
let mut a = codec::entities::AttributeEntity::from_definition(d, None);
|
||||
a.apply_transform(&transform);
|
||||
insert.attributes.push(a);
|
||||
}
|
||||
let handle = self.tabs[i].scene.add_entity(codec::EntityType::Insert(insert));
|
||||
let Some(db) = self.sheet_set.sets.get(set) else { return };
|
||||
let (view_prefix, sheet_prefix) = (component_prefix(db, view), component_prefix(db, sheet));
|
||||
crate::entities::field::attach_attribute_fields_mapped(&mut self.tabs[i].scene.document, handle, &|code: &str| {
|
||||
code.replace("?View.", &view_prefix).replace("?Sheet.", &sheet_prefix)
|
||||
});
|
||||
self.tabs[i].scene.bump_entities(&[(handle, crate::scene::ChangeKind::Modified)]);
|
||||
}
|
||||
|
||||
/// The insertion point was picked: place the view (xref, viewport, paper
|
||||
/// named view, view label, sheet view record) or the block.
|
||||
fn place_at(&mut self, i: usize, x: f64, y: f64, scale: f64) {
|
||||
use codec::types::Vector3;
|
||||
let Some(placing) = self.sheet_set.placing.take() else { return };
|
||||
self.push_undo_snapshot(i, "Place on Sheet");
|
||||
match placing {
|
||||
Placing::Block { set, sheet, view, file, name } => {
|
||||
self.insert_set_block(i, &file, &name, Vector3::new(x, y, 0.0), &view, &sheet, set);
|
||||
}
|
||||
Placing::View { set, sheet, drawing, view } => {
|
||||
let Some(mv) = crate::io::load_file(Path::new(&drawing)).ok().and_then(|d| model_view(&d, view.as_deref())) else {
|
||||
return;
|
||||
};
|
||||
let title = view.clone().unwrap_or_else(|| {
|
||||
Path::new(&drawing).file_stem().map(|s| s.to_string_lossy().to_string()).unwrap_or_default()
|
||||
});
|
||||
// The model drawing is attached to the sheet's model space.
|
||||
let host = self.tabs[i].current_path.clone();
|
||||
let request = crate::modules::insert::xattach::XrefAttachRequest {
|
||||
path: drawing.clone(),
|
||||
overlay: false,
|
||||
path_type: crate::io::xref_model::Pathtype::Relative,
|
||||
};
|
||||
let scene = &mut self.tabs[i].scene;
|
||||
let xref = crate::modules::insert::xattach::prepare_xref_definition(scene, &request, host.as_deref());
|
||||
let model = scene.document.header.model_space_block_handle;
|
||||
let inserted = scene.document.entities().any(|e| {
|
||||
e.common().owner_handle == model && matches!(e, codec::EntityType::Insert(ins) if ins.block_name.eq_ignore_ascii_case(&xref))
|
||||
});
|
||||
if !inserted {
|
||||
let saved = std::mem::replace(&mut scene.current_layout, "Model".to_string());
|
||||
scene.add_entity(codec::EntityType::Insert(codec::entities::Insert::new(xref, Vector3::ZERO)));
|
||||
scene.current_layout = saved;
|
||||
}
|
||||
// The viewport: lower-left corner at the point, the view at the scale.
|
||||
let (w, h) = (mv.width * scale, mv.height * scale);
|
||||
let mut vp = codec::entities::Viewport::new();
|
||||
vp.center = Vector3::new(x + w / 2.0, y + h / 2.0, 0.0);
|
||||
vp.width = w;
|
||||
vp.height = h;
|
||||
vp.id = 2;
|
||||
vp.view_target = mv.target.clone();
|
||||
vp.view_direction = mv.direction.clone();
|
||||
vp.view_center = Vector3::new(mv.center.x - mv.target.x, mv.center.y - mv.target.y, 0.0);
|
||||
vp.view_height = mv.height;
|
||||
vp.custom_scale = scale;
|
||||
scene.add_entity(codec::EntityType::Viewport(vp));
|
||||
// A paper-space named view of the same name frames it.
|
||||
let mut named = codec::tables::View::new(title.as_str());
|
||||
named.handle = scene.document.allocate_handle();
|
||||
named.paper_space = true;
|
||||
named.center = Vector3::new(x + w / 2.0, y + h / 2.0, 0.0);
|
||||
named.width = w;
|
||||
named.height = h;
|
||||
named.direction = Vector3::new(0.0, 0.0, 1.0);
|
||||
let view_handle = format!("{:X}", named.handle.value());
|
||||
scene.document.views.add_or_replace(named);
|
||||
let file = host.map(|p| ss::native_path(&p.to_string_lossy())).unwrap_or_default();
|
||||
let Some(db) = self.sheet_set.sets.get_mut(set) else { return };
|
||||
// The view joins the set's default (unnamed) category.
|
||||
let category = db
|
||||
.sheet_set()
|
||||
.named("ViewCategories")
|
||||
.and_then(|c| c.children.iter().find(|k| k.name == "AcSmViewCategory" && k.prop("Name").is_none()))
|
||||
.map(|k| k.id().to_string());
|
||||
let reference = LayoutReference { file_name: file, name: title.clone(), handle: view_handle };
|
||||
let Some(view_id) = db.add_sheet_view(&sheet, category.as_deref(), &reference, &title) else { return };
|
||||
let label = db.sheet_set().named("DefLabelBlk").map(|b| (db.resolve_file(b), b.prop("Name").unwrap_or("").to_string()));
|
||||
// The set is written first, so the label's fields find the new view.
|
||||
self.sheet_set.current = Some(set);
|
||||
self.save_current_sheet_set();
|
||||
if let Some((file, name)) = label {
|
||||
self.insert_set_block(i, &file, &name, Vector3::new(x, y, 0.0), &view_id, &sheet, set);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.tabs[i].dirty = true;
|
||||
self.refresh_xref_manager();
|
||||
}
|
||||
|
||||
/// Select Block: read a drawing's named blocks.
|
||||
fn select_block_file(&mut self, path: PathBuf) {
|
||||
let names: Vec<(String, String, bool)> = match crate::io::load_file(&path) {
|
||||
Ok(doc) => {
|
||||
let mut n: Vec<(String, String, bool)> = doc
|
||||
.block_records
|
||||
.iter()
|
||||
.filter(|b| !b.name.starts_with('*') && !b.is_layout())
|
||||
.map(|b| (b.name.clone(), format!("{:X}", b.handle.value()), false))
|
||||
.collect();
|
||||
n.sort();
|
||||
n
|
||||
}
|
||||
Err(e) => {
|
||||
self.command_line.push_error(&format!("{}: {e}", path.display()));
|
||||
return;
|
||||
}
|
||||
};
|
||||
if let Some(SsDialog::SelectBlock(b)) = self.sheet_set.dialog.as_mut() {
|
||||
b.file = path.to_string_lossy().to_string();
|
||||
b.names = names;
|
||||
b.error = None;
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
@@ -1376,11 +1853,20 @@ impl OpenCADStudio {
|
||||
return;
|
||||
}
|
||||
let Some(db) = self.sheet_set.db() else { return };
|
||||
let folder = db.path.as_deref().and_then(|p| Path::new(p).parent().map(Path::to_path_buf));
|
||||
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() {
|
||||
// The reference finds a sheet through its relative path: when that
|
||||
// names no file the sheet is missing, even if the stored absolute
|
||||
// path still exists.
|
||||
let relative = sheet.named("Layout").and_then(|l| l.prop("Relative_FileName")).zip(folder.as_deref());
|
||||
let found = match relative {
|
||||
Some((rel, folder)) => folder.join(rel.replace('\\', std::path::MAIN_SEPARATOR_STR)).exists(),
|
||||
None => path.exists(),
|
||||
};
|
||||
let state = if !found {
|
||||
Some(SheetStatus::Missing)
|
||||
} else if path.with_extension("dwl").exists() {
|
||||
Some(SheetStatus::Locked)
|
||||
@@ -1449,6 +1935,46 @@ impl OpenCADStudio {
|
||||
self.category_ok(c);
|
||||
Task::none()
|
||||
}
|
||||
// List of Blocks: the list goes back to the View Category dialog.
|
||||
Some(SsDialog::BlockList(b)) => {
|
||||
let mut c = *b.category;
|
||||
for (id, _, _) in &c.blocks {
|
||||
if !id.starts_with("new:") && !b.blocks.iter().any(|(k, _)| k == id) {
|
||||
c.removed.push(id.clone());
|
||||
}
|
||||
}
|
||||
c.blocks = b
|
||||
.blocks
|
||||
.into_iter()
|
||||
.map(|(id, label)| {
|
||||
let on = c.blocks.iter().find(|(k, _, _)| *k == id).is_none_or(|(_, _, on)| *on);
|
||||
(id, label, on)
|
||||
})
|
||||
.collect();
|
||||
self.sheet_set.dialog = Some(SsDialog::Category(c));
|
||||
Task::none()
|
||||
}
|
||||
// Select Block: the whole drawing or its checked blocks join the list.
|
||||
Some(SsDialog::SelectBlock(mut b)) => {
|
||||
if b.file.is_empty() {
|
||||
b.error = Some(crate::t!("Enter the drawing file name.").into_owned());
|
||||
self.sheet_set.dialog = Some(SsDialog::SelectBlock(b));
|
||||
return Task::none();
|
||||
}
|
||||
let file = ss::native_path(&b.file);
|
||||
let mut list = *b.list;
|
||||
if b.whole {
|
||||
let stem = Path::new(&file).file_stem().map(|s| s.to_string_lossy().to_string()).unwrap_or_default();
|
||||
list.blocks.push((format!("new:{file}|{stem}|"), format!("{stem} ({file})")));
|
||||
} else {
|
||||
for (name, handle, on) in b.names.into_iter().filter(|n| n.2) {
|
||||
let _ = on;
|
||||
list.blocks.push((format!("new:{file}|{name}|{handle}"), format!("{name} ({file})")));
|
||||
}
|
||||
}
|
||||
self.sheet_set.dialog = Some(SsDialog::BlockList(list));
|
||||
Task::none()
|
||||
}
|
||||
None => Task::none(),
|
||||
}
|
||||
}
|
||||
@@ -1592,6 +2118,16 @@ impl OpenCADStudio {
|
||||
}
|
||||
}
|
||||
FormKind::NewSheet => return self.create_sheet(f),
|
||||
FormKind::RenameView => {
|
||||
if let Some(el) = db.find_mut(&f.component) {
|
||||
if f.number.trim().is_empty() {
|
||||
el.remove_named("Number");
|
||||
} else {
|
||||
el.set_prop("Number", f.number.trim());
|
||||
}
|
||||
el.set_prop("Title", f.title.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
self.close_active_modal();
|
||||
self.sheet_set.current = Some(f.set);
|
||||
|
||||
@@ -1290,7 +1290,6 @@ impl OpenCADStudio {
|
||||
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
|
||||
@@ -1303,6 +1302,58 @@ impl OpenCADStudio {
|
||||
M::RemoveLocation(id)
|
||||
}
|
||||
"open_drawing" => M::OpenDrawing(arg.into()),
|
||||
"toggle_drawing" => M::ToggleDrawing(arg.into()),
|
||||
"see_views" => M::SeeViews(arg.into()),
|
||||
// place=<drawing>[|<view>]
|
||||
"place" => {
|
||||
let (drawing, view) = arg.split_once('|').map_or((arg, None), |(d, v)| (d, Some(v.to_string())));
|
||||
M::PlaceOnSheet(drawing.into(), view)
|
||||
}
|
||||
// view=<view title or number - title>:<display|rename|label|category=<name>|callout=<block>>
|
||||
"view" => {
|
||||
use crate::ui::window::sheet_set::ViewAction as VA;
|
||||
let (spec, action) = arg.rsplit_once(':').ok_or_else(|| failure("invalid_value", "view=<view>:<action>"))?;
|
||||
let db = self.sheet_set.db().ok_or_else(|| failure("invalid_state", "No sheet set"))?;
|
||||
let view = db
|
||||
.sheets()
|
||||
.into_iter()
|
||||
.flat_map(|s| db.sheet_views(s))
|
||||
.find(|v| codec::sheet_set::number_and_title(v) == spec || v.prop("Title") == Some(spec))
|
||||
.map(|v| v.id().to_string())
|
||||
.ok_or_else(|| failure("invalid_value", "No such sheet view"))?;
|
||||
let (verb, name) = action.split_once('=').unwrap_or((action, ""));
|
||||
let a = match verb {
|
||||
"display" => VA::Display,
|
||||
"rename" => VA::Rename,
|
||||
"label" => VA::Label,
|
||||
"category" => VA::Category(
|
||||
db.view_categories()
|
||||
.iter()
|
||||
.find(|c| c.prop("Name") == Some(name))
|
||||
.map(|c| c.id().to_string())
|
||||
.ok_or_else(|| failure("invalid_value", "No such view category"))?,
|
||||
),
|
||||
"callout" => VA::Callout(
|
||||
db.callout_blocks()
|
||||
.iter()
|
||||
.find(|b| b.prop("Name") == Some(name))
|
||||
.map(|b| b.id().to_string())
|
||||
.ok_or_else(|| failure("invalid_value", "No such callout block"))?,
|
||||
),
|
||||
_ => return Err(failure("invalid_value", "display|rename|label|category=|callout=")),
|
||||
};
|
||||
M::ViewMenu(view, a)
|
||||
}
|
||||
"add_blocks" => M::AddBlocks,
|
||||
"block_list_select" => M::BlockListSelect(arg.parse().map_err(|_| failure("invalid_value", "index"))?),
|
||||
"block_list_add" => M::BlockListAdd,
|
||||
"block_list_delete" => M::BlockListDelete,
|
||||
"select_block_file" => M::SelectBlockPicked(Some(std::path::PathBuf::from(arg))),
|
||||
"select_block_whole" => M::SelectBlockWhole(arg == "1"),
|
||||
"select_block_check" => {
|
||||
let (i, v) = index_value(arg)?;
|
||||
M::SelectBlockCheck(i, v == "1")
|
||||
}
|
||||
"ok" => M::Ok,
|
||||
"cancel" => M::Cancel,
|
||||
_ => return Err(failure("invalid_value", "Unknown sheet set action")),
|
||||
|
||||
@@ -5520,12 +5520,9 @@ impl OpenCADStudio {
|
||||
let half_w = view.width.abs() * 0.5;
|
||||
let half_h = view.height.abs() * 0.5;
|
||||
(half_w > 1e-9 && half_h > 1e-9).then_some(())?;
|
||||
self.area_plot_job((
|
||||
view.center.x - half_w,
|
||||
view.center.y - half_h,
|
||||
view.center.x + half_w,
|
||||
view.center.y + half_h,
|
||||
))
|
||||
// The view centre is relative to its target (plan views).
|
||||
let (cx, cy) = (view.target.x + view.center.x, view.target.y + view.center.y);
|
||||
self.area_plot_job((cx - half_w, cy - half_h, cx + half_w, cy + half_h))
|
||||
}
|
||||
|
||||
pub(in crate::app) fn extents_plot_job(&self) -> Option<PdfPageInput> {
|
||||
|
||||
@@ -587,12 +587,15 @@ impl OpenCADStudio {
|
||||
crate::ui::window::sheet_set::SsDialog::Properties(_) => (640, 700),
|
||||
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::RenameView => (520, 200),
|
||||
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),
|
||||
crate::ui::window::sheet_set::SsDialog::BlockList(_) => (540, 330),
|
||||
crate::ui::window::sheet_set::SsDialog::SelectBlock(_) => (580, 390),
|
||||
};
|
||||
sized_flow(ex, w, h, |flow| crate::ui::window::sheet_set::dialog_view(&self.sheet_set, flow))
|
||||
}
|
||||
|
||||
@@ -387,6 +387,18 @@ pub fn attach_attribute_fields(document: &mut CadDocument, insert: Handle) -> Ve
|
||||
document.attach_attribute_fields(insert, &context)
|
||||
}
|
||||
|
||||
/// Store fresh values for the sheet set fields (after a sheet set changed).
|
||||
pub fn refresh_sheet_set_fields(document: &mut CadDocument) -> Vec<Handle> {
|
||||
let context = OcsFieldContext(None);
|
||||
document.refresh_sheet_set_fields(&context)
|
||||
}
|
||||
|
||||
/// [`attach_attribute_fields`] with every field code passed through `map`.
|
||||
pub fn attach_attribute_fields_mapped(document: &mut CadDocument, insert: Handle, map: &dyn Fn(&str) -> String) -> Vec<Handle> {
|
||||
let context = OcsFieldContext(None);
|
||||
document.attach_attribute_fields_mapped(insert, &context, map)
|
||||
}
|
||||
|
||||
/// Whether any attribute definition of `block` hosts a field.
|
||||
pub fn block_has_attribute_fields(document: &CadDocument, block: &str) -> bool {
|
||||
let Some(record) = document.block_records.iter().find(|r| r.name.eq_ignore_ascii_case(block)) else {
|
||||
|
||||
@@ -50,6 +50,27 @@ 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")),
|
||||
"Rename & Renumber View" => Some(("view", "ss-rename-renumber-view")),
|
||||
"List of Blocks" => Some(("view", "ss-list-of-blocks")),
|
||||
"Select Block" => Some(("view", "ss-select-block")),
|
||||
"Set category" => Some(("view", "ss-set-category")),
|
||||
"Place Callout Block" => Some(("view", "ss-place-callout-block")),
|
||||
"Place View Label Block" => Some(("view", "ss-place-view-label-block")),
|
||||
"Place on Sheet" => Some(("view", "ss-place-on-sheet")),
|
||||
"See Model Space Views" => Some(("view", "ss-see-model-space-views")),
|
||||
"View title" => Some(("view", "ss-view-title")),
|
||||
"Add..." => Some(("view", "ss-add-x")),
|
||||
"The following blocks are associated with this sheet set:" => Some(("view", "ss-blocks-associated")),
|
||||
"Enter the drawing file name:" => Some(("view", "ss-enter-drawing-file-name")),
|
||||
"Enter the drawing file name." => Some(("view", "ss-enter-drawing-file-name-msg")),
|
||||
"Select the drawing file as a block" => Some(("view", "ss-select-drawing-as-block")),
|
||||
"Choose blocks in the drawing file:" => Some(("view", "ss-choose-blocks-in-drawing")),
|
||||
"preview" => Some(("view", "ss-preview")),
|
||||
"Open a sheet of this sheet set at its layout to place a view on it." => Some(("view", "ss-open-sheet-to-place")),
|
||||
"Open the view's sheet at its layout to place a block on it." => Some(("view", "ss-open-view-sheet")),
|
||||
"The sheet set has no label block for views." => Some(("view", "ss-no-label-block")),
|
||||
"{}: no view to place." => Some(("view", "ss-no-view-to-place")),
|
||||
"{}: cannot be read." => Some(("view", "ss-cannot-be-read")),
|
||||
"This layout is already part of a sheet set - not available for import." => Some(("view", "ss-layout-already-part")),
|
||||
"Warning: this layout may belong to another sheet set." => Some(("view", "ss-layout-may-belong")),
|
||||
"missing" => Some(("view", "ss-status-missing")),
|
||||
|
||||
@@ -202,6 +202,9 @@ impl Scene {
|
||||
};
|
||||
// Build rotation: canonical eye is +Z, rotate to eye_dir.
|
||||
cam.rotation = glam::Quat::from_rotation_arc(Vec3::Z, eye_dir);
|
||||
// The view centre is an offset in view coordinates from the target.
|
||||
let offset = cam.rotation * Vec3::new(view.center.x as f32, view.center.y as f32, 0.0);
|
||||
cam.target += glam::DVec3::new(offset.x as f64, offset.y as f64, offset.z as f64);
|
||||
// Sync yaw/pitch from new rotation (for ViewCube).
|
||||
let pitch = eye_dir.z.clamp(-1.0, 1.0).asin();
|
||||
let yaw = eye_dir.x.atan2(eye_dir.y);
|
||||
@@ -226,11 +229,8 @@ impl Scene {
|
||||
let height = cam.ortho_size() * 2.0;
|
||||
let width = height; // caller can adjust; rough square
|
||||
let mut view = codec::tables::View::new(name);
|
||||
view.center = Vector3 {
|
||||
x: cam.target.x as f64,
|
||||
y: cam.target.y as f64,
|
||||
z: 0.0,
|
||||
};
|
||||
// The centre is in view (DCS) coordinates, relative to the target.
|
||||
view.center = Vector3 { x: 0.0, y: 0.0, z: 0.0 };
|
||||
view.target = Vector3 {
|
||||
x: cam.target.x as f64,
|
||||
y: cam.target.y as f64,
|
||||
|
||||
+264
-43
@@ -74,6 +74,36 @@ pub struct SheetSetManager {
|
||||
pub locations: Vec<(String, String, Vec<String>)>,
|
||||
/// Drawings this application holds `.dwl` / `.dwl2` lock files for.
|
||||
pub locks: HashSet<std::path::PathBuf>,
|
||||
/// Model Views: drawings shown open (path keys) and their named model
|
||||
/// views, read when a drawing is opened in the tree.
|
||||
pub open_drawings: HashSet<String>,
|
||||
pub model_views: std::collections::HashMap<String, Vec<String>>,
|
||||
/// What the pending insertion point places.
|
||||
pub placing: Option<Placing>,
|
||||
/// A named view to show once the sheet drawing being opened is up.
|
||||
pub pending_view: Option<String>,
|
||||
}
|
||||
|
||||
/// What a sheet set point pick places on the current sheet.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Placing {
|
||||
/// Place on Sheet: a model drawing and its named view (`None`: the
|
||||
/// drawing's extents).
|
||||
View { set: usize, sheet: String, drawing: String, view: Option<String> },
|
||||
/// A callout or view label block (file, block name) for sheet view `view`.
|
||||
Block { set: usize, sheet: String, view: String, file: String, name: String },
|
||||
}
|
||||
|
||||
/// Commands of a sheet view row.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ViewAction {
|
||||
Display,
|
||||
Rename,
|
||||
/// Set the view's category.
|
||||
Category(String),
|
||||
/// Place a callout block (its id in the set's callout blocks).
|
||||
Callout(String),
|
||||
Label,
|
||||
}
|
||||
|
||||
/// A sheet whose drawing is missing, or open (a `.dwl` lock file, or a tab here).
|
||||
@@ -137,6 +167,21 @@ pub enum SheetSetMsg {
|
||||
LocationPicked(Option<std::path::PathBuf>),
|
||||
RemoveLocation(String),
|
||||
OpenDrawing(String),
|
||||
/// Model Views: open / fold a drawing (its named views), See Model Space
|
||||
/// Views, Place on Sheet (drawing, named view).
|
||||
ToggleDrawing(String),
|
||||
SeeViews(String),
|
||||
PlaceOnSheet(String, Option<String>),
|
||||
/// Sheet Views: a view row's command.
|
||||
ViewMenu(String, ViewAction),
|
||||
/// List of Blocks / Select Block.
|
||||
BlockListSelect(usize),
|
||||
BlockListAdd,
|
||||
BlockListDelete,
|
||||
SelectBlockBrowse,
|
||||
SelectBlockPicked(Option<std::path::PathBuf>),
|
||||
SelectBlockWhole(bool),
|
||||
SelectBlockCheck(usize, bool),
|
||||
/// A `.dst` picked by Open (or given by automation).
|
||||
OpenPicked(Option<std::path::PathBuf>),
|
||||
/// A drawing picked by Import Layout as Sheet.
|
||||
@@ -288,6 +333,8 @@ pub enum FormKind {
|
||||
NewSubset,
|
||||
Rename,
|
||||
ImportLayout,
|
||||
/// Rename & Renumber View.
|
||||
RenameView,
|
||||
}
|
||||
|
||||
/// One layout of Import Layouts as Sheets.
|
||||
@@ -347,8 +394,29 @@ pub struct Category {
|
||||
/// `None` creates a category.
|
||||
pub id: Option<String>,
|
||||
pub name: String,
|
||||
/// Callout block id, label, used.
|
||||
/// Callout block id (`new:file|name|handle` until saved), label, used.
|
||||
pub blocks: Vec<(String, String, bool)>,
|
||||
/// Callout blocks deleted in List of Blocks.
|
||||
pub removed: Vec<String>,
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
/// List of Blocks: the set's callout blocks (id, label).
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BlockList {
|
||||
pub category: Box<Category>,
|
||||
pub blocks: Vec<(String, String)>,
|
||||
pub selected: Option<usize>,
|
||||
}
|
||||
|
||||
/// Select Block: a drawing, taken whole or by its named blocks.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SelectBlock {
|
||||
pub list: Box<BlockList>,
|
||||
pub file: String,
|
||||
pub whole: bool,
|
||||
/// Block name, handle, checked.
|
||||
pub names: Vec<(String, String, bool)>,
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
@@ -361,6 +429,8 @@ pub enum SsDialog {
|
||||
Confirm(usize, String, String),
|
||||
Template(TemplatePick),
|
||||
Category(Category),
|
||||
BlockList(BlockList),
|
||||
SelectBlock(SelectBlock),
|
||||
}
|
||||
|
||||
impl SsDialog {
|
||||
@@ -373,7 +443,10 @@ impl SsDialog {
|
||||
FormKind::NewSubset => t!("Subset Properties").into_owned(),
|
||||
FormKind::Rename => t!("Rename & Renumber Sheet").into_owned(),
|
||||
FormKind::ImportLayout => t!("Import Layouts as Sheets").into_owned(),
|
||||
FormKind::RenameView => t!("Rename & Renumber View").into_owned(),
|
||||
},
|
||||
SsDialog::BlockList(_) => t!("List of Blocks").into_owned(),
|
||||
SsDialog::SelectBlock(_) => t!("Select Block").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(),
|
||||
@@ -489,11 +562,21 @@ fn plain_row<'a>(
|
||||
depth: u16,
|
||||
icon: &'static [u8],
|
||||
label: String,
|
||||
fold: Option<(bool, Message)>,
|
||||
double: Option<Message>,
|
||||
menu: Vec<(&'static str, Option<Message>)>,
|
||||
menu: Vec<(String, Option<Message>)>,
|
||||
) -> Element<'a, Message> {
|
||||
let arrow: Element<'a, Message> = match fold {
|
||||
Some((open, m)) => button(if open { crate::ui::icons::themed_arrow_down(10.0) } else { crate::ui::icons::themed_arrow_right(10.0) })
|
||||
.on_press(m)
|
||||
.style(button::text)
|
||||
.padding(2)
|
||||
.into(),
|
||||
None => Space::new().width(14).into(),
|
||||
};
|
||||
let cells = row![
|
||||
Space::new().width(Length::Fixed(f32::from(depth) * 16.0 + 14.0)),
|
||||
Space::new().width(Length::Fixed(f32::from(depth) * 16.0)),
|
||||
arrow,
|
||||
crate::ui::icons::semantic(icon, 14.0),
|
||||
text(label).size(12).width(Fill),
|
||||
]
|
||||
@@ -509,11 +592,11 @@ fn plain_row<'a>(
|
||||
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()) })
|
||||
.map(|(label, m)| if label.is_empty() { menu_separator() } else { menu_entry(label.clone(), m.clone()) })
|
||||
.collect();
|
||||
container(iced::widget::Column::with_children(items).spacing(1))
|
||||
.padding(4)
|
||||
.width(Length::Fixed(220.0))
|
||||
.width(Length::Fixed(240.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() },
|
||||
@@ -524,6 +607,11 @@ fn plain_row<'a>(
|
||||
.into()
|
||||
}
|
||||
|
||||
/// A menu item: translated label and message (an empty label is a separator).
|
||||
fn mi(label: &str, m: Option<Message>) -> (String, Option<Message>) {
|
||||
(if label.is_empty() { String::new() } else { t!(label).into_owned() }, m)
|
||||
}
|
||||
|
||||
fn tree_row<'a>(
|
||||
state: &SheetSetManager,
|
||||
el: &SsElement,
|
||||
@@ -598,67 +686,71 @@ fn push_tree<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
/// 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()
|
||||
.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()
|
||||
/// A sheet view row and its menu: Display, Rename & Renumber, Set category
|
||||
/// (the categories as sub-items), Place Callout Block (the set's callout
|
||||
/// blocks as sub-items) and Place View Label Block.
|
||||
fn view_row<'a>(db: &SheetSetDatabase, view: &SsElement, depth: u16) -> Element<'a, Message> {
|
||||
let id = view.id().to_string();
|
||||
let act = |a: ViewAction| Some(msg(SheetSetMsg::ViewMenu(id.clone(), a)));
|
||||
let mut menu = vec![mi("Display", act(ViewAction::Display)), mi("Rename & Renumber...", act(ViewAction::Rename)), mi("", None)];
|
||||
menu.push((format!("{} ▸", t!("Set category")), None));
|
||||
for c in db.view_categories() {
|
||||
menu.push((format!(" {}", c.prop("Name").unwrap_or("")), act(ViewAction::Category(c.id().to_string()))));
|
||||
}
|
||||
menu.push((format!("{} ▸", t!("Place Callout Block")), None));
|
||||
for b in db.callout_blocks() {
|
||||
menu.push((format!(" {}", b.prop("Name").unwrap_or("")), act(ViewAction::Callout(b.id().to_string()))));
|
||||
}
|
||||
menu.push(mi("Place View Label Block", act(ViewAction::Label)));
|
||||
plain_row(depth, crate::ui::icons::DOC, ss::number_and_title(view), None, act(ViewAction::Display), menu)
|
||||
}
|
||||
|
||||
/// 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)))],
|
||||
)];
|
||||
let new_category = || mi("New View Category...", Some(msg(SheetSetMsg::NewCategory)));
|
||||
let mut rows = vec![plain_row(0, SET_ICON, db.name().to_string(), None, None, vec![new_category()])];
|
||||
let views: Vec<&SsElement> = db.sheets().into_iter().flat_map(|s| db.sheet_views(s)).collect();
|
||||
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 named = db.view_categories();
|
||||
// Views of the unnamed (default) category sit directly under the set.
|
||||
for v in views.iter().filter(|v| !SheetSetDatabase::view_category_of(v).is_some_and(|c| named.iter().any(|n| n.id() == c))) {
|
||||
rows.push(view_row(db, v, 1));
|
||||
}
|
||||
for c in named {
|
||||
let id = c.id().to_string();
|
||||
rows.push(plain_row(
|
||||
1,
|
||||
crate::ui::icons::FOLDER_OPEN,
|
||||
c.prop("Name").unwrap_or("").to_string(),
|
||||
None,
|
||||
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())))),
|
||||
new_category(),
|
||||
mi("Properties...", Some(msg(SheetSetMsg::CategoryProperties(id.clone())))),
|
||||
mi("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![]));
|
||||
for v in views.iter().filter(|v| SheetSetDatabase::view_category_of(v) == Some(id.as_str())) {
|
||||
rows.push(view_row(db, v, 2));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for sheet in db.sheets() {
|
||||
let views = views_of(sheet);
|
||||
let views = db.sheet_views(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.push(plain_row(1, crate::ui::icons::DOC, ss::number_and_title(sheet), None, None, vec![]));
|
||||
for v in views {
|
||||
rows.push(view_row(db, v, 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
rows
|
||||
}
|
||||
|
||||
/// The Model Views page: each location folder and its drawings.
|
||||
/// The Model Views page: each location folder, its drawings and, for an
|
||||
/// opened drawing, its named model views.
|
||||
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.
|
||||
@@ -670,20 +762,45 @@ fn model_views_rows<'a>(state: &SheetSetManager) -> Vec<Element<'a, Message>> {
|
||||
crate::ui::icons::FOLDER_OPEN,
|
||||
label,
|
||||
None,
|
||||
None,
|
||||
vec![
|
||||
("Add New Location...", Some(msg(SheetSetMsg::AddLocation))),
|
||||
("Remove Location", Some(msg(SheetSetMsg::RemoveLocation(id.clone())))),
|
||||
mi("Add New Location...", Some(msg(SheetSetMsg::AddLocation))),
|
||||
mi("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();
|
||||
let key = ss::path_key(&path);
|
||||
let open = state.open_drawings.contains(&key);
|
||||
rows.push(plain_row(
|
||||
1,
|
||||
crate::ui::icons::DOC,
|
||||
file.clone(),
|
||||
Some((open, msg(SheetSetMsg::ToggleDrawing(path.clone())))),
|
||||
Some(msg(SheetSetMsg::OpenDrawing(path.clone()))),
|
||||
vec![("Open", Some(msg(SheetSetMsg::OpenDrawing(path))))],
|
||||
vec![
|
||||
mi("Open", Some(msg(SheetSetMsg::OpenDrawing(path.clone())))),
|
||||
mi("", None),
|
||||
mi("Place on Sheet", Some(msg(SheetSetMsg::PlaceOnSheet(path.clone(), None)))),
|
||||
mi("See Model Space Views", Some(msg(SheetSetMsg::SeeViews(path.clone())))),
|
||||
],
|
||||
));
|
||||
if open {
|
||||
for v in state.model_views.get(&key).cloned().unwrap_or_default() {
|
||||
rows.push(plain_row(
|
||||
2,
|
||||
crate::ui::icons::DOC,
|
||||
v.clone(),
|
||||
None,
|
||||
None,
|
||||
vec![
|
||||
mi("Open", Some(msg(SheetSetMsg::OpenDrawing(path.clone())))),
|
||||
mi("", None),
|
||||
mi("Place on Sheet", Some(msg(SheetSetMsg::PlaceOnSheet(path.clone(), Some(v))))),
|
||||
],
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
rows.push(
|
||||
@@ -1270,6 +1387,17 @@ fn form_view<'a>(f: &'a Form) -> Element<'a, Message> {
|
||||
),
|
||||
]
|
||||
}
|
||||
FormKind::RenameView => vec![card(
|
||||
"View",
|
||||
row![
|
||||
text(t!("Number").into_owned()).size(12).width(Length::Fixed(70.0)),
|
||||
container(input(&f.number, FieldId::Number)).width(Length::Fixed(90.0)),
|
||||
text(t!("View title").into_owned()).size(12),
|
||||
input(&f.title, FieldId::Title),
|
||||
]
|
||||
.spacing(8)
|
||||
.align_y(iced::Center),
|
||||
)],
|
||||
FormKind::ImportLayout => {
|
||||
let head = row![
|
||||
Space::new().width(22),
|
||||
@@ -1335,7 +1463,7 @@ fn form_view<'a>(f: &'a Form) -> Element<'a, Message> {
|
||||
col = col.push(e);
|
||||
}
|
||||
let foot = match f.kind {
|
||||
FormKind::Rename => footer(
|
||||
FormKind::Rename | FormKind::RenameView => 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(),
|
||||
@@ -1409,6 +1537,97 @@ fn category_view<'a>(c: &'a Category) -> Element<'a, Message> {
|
||||
col.push(ok_cancel("OK")).into()
|
||||
}
|
||||
|
||||
fn preview_box<'a>() -> Element<'a, Message> {
|
||||
container(text(t!("preview").into_owned()).size(11).style(muted_style))
|
||||
.center_x(Fill)
|
||||
.center_y(Fill)
|
||||
.style(card_style)
|
||||
.into()
|
||||
}
|
||||
|
||||
fn block_list_view<'a>(b: &'a BlockList) -> Element<'a, Message> {
|
||||
let rows = b.blocks.iter().enumerate().map(|(i, (_, label))| {
|
||||
button(text(label.clone()).size(12))
|
||||
.on_press(msg(SheetSetMsg::BlockListSelect(i)))
|
||||
.style(button_style(b.selected == Some(i)))
|
||||
.padding([3, 8])
|
||||
.width(Fill)
|
||||
.into()
|
||||
});
|
||||
let side = column![
|
||||
button(text(t!("Add...").into_owned()).size(12).center().width(Fill))
|
||||
.on_press(msg(SheetSetMsg::BlockListAdd))
|
||||
.style(button_style(false))
|
||||
.padding([5, 12])
|
||||
.width(Fill),
|
||||
button(text(t!("Delete").into_owned()).size(12).center().width(Fill))
|
||||
.on_press_maybe(b.selected.map(|_| msg(SheetSetMsg::BlockListDelete)))
|
||||
.style(button_style(false))
|
||||
.padding([5, 12])
|
||||
.width(Fill),
|
||||
preview_box(),
|
||||
]
|
||||
.spacing(6)
|
||||
.width(Length::Fixed(130.0));
|
||||
column![
|
||||
card(
|
||||
"Blocks",
|
||||
column![
|
||||
text(t!("The following blocks are associated with this sheet set:").into_owned()).size(12),
|
||||
row![
|
||||
container(scrollable(iced::widget::Column::with_children(rows.collect::<Vec<_>>()).spacing(1)))
|
||||
.padding(4)
|
||||
.height(Length::Fixed(150.0))
|
||||
.width(Fill)
|
||||
.style(card_style),
|
||||
side,
|
||||
]
|
||||
.spacing(10)
|
||||
.height(Length::Fixed(150.0)),
|
||||
]
|
||||
.spacing(8)
|
||||
),
|
||||
ok_cancel("OK"),
|
||||
]
|
||||
.spacing(10)
|
||||
.into()
|
||||
}
|
||||
|
||||
fn select_block_view<'a>(b: &'a SelectBlock) -> Element<'a, Message> {
|
||||
let names = b.names.iter().enumerate().map(|(i, (name, _, on))| {
|
||||
let c = checkbox(*on).label(name.clone()).text_size(12).size(14);
|
||||
if b.whole { c.into() } else { c.on_toggle(move |v| msg(SheetSetMsg::SelectBlockCheck(i, v))).into() }
|
||||
});
|
||||
let radio = |on: bool, label: &str, whole: bool| {
|
||||
checkbox(on).label(t!(label).into_owned()).text_size(12).size(14).on_toggle(move |_| msg(SheetSetMsg::SelectBlockWhole(whole)))
|
||||
};
|
||||
let mut col = column![card(
|
||||
"Drawing",
|
||||
column![
|
||||
text(t!("Enter the drawing file name:").into_owned()).size(12),
|
||||
row![read_only(&b.file), browse(SheetSetMsg::SelectBlockBrowse)].spacing(6).align_y(iced::Center),
|
||||
radio(b.whole, "Select the drawing file as a block", true),
|
||||
radio(!b.whole, "Choose blocks in the drawing file:", false),
|
||||
row![
|
||||
Space::new().width(22),
|
||||
container(scrollable(iced::widget::Column::with_children(names.collect::<Vec<_>>()).spacing(4)))
|
||||
.padding(6)
|
||||
.height(Length::Fixed(110.0))
|
||||
.width(Fill)
|
||||
.style(card_style),
|
||||
container(preview_box()).width(Length::Fixed(130.0)).height(Length::Fixed(110.0)),
|
||||
]
|
||||
.spacing(10),
|
||||
]
|
||||
.spacing(8)
|
||||
)]
|
||||
.spacing(10);
|
||||
if let Some(e) = error_band(&b.error) {
|
||||
col = col.push(e);
|
||||
}
|
||||
col.push(ok_cancel("OK")).into()
|
||||
}
|
||||
|
||||
fn confirm_view<'a>(question: &'a str) -> Element<'a, Message> {
|
||||
column![
|
||||
row![
|
||||
@@ -1439,6 +1658,8 @@ pub fn dialog_view<'a>(state: &'a SheetSetManager, sizing: crate::ui::modal::Mod
|
||||
Some(SsDialog::Confirm(_, _, q)) => confirm_view(q),
|
||||
Some(SsDialog::Template(t)) => template_view(t),
|
||||
Some(SsDialog::Category(c)) => category_view(c),
|
||||
Some(SsDialog::BlockList(b)) => block_list_view(b),
|
||||
Some(SsDialog::SelectBlock(b)) => select_block_view(b),
|
||||
None => Space::new().into(),
|
||||
};
|
||||
container(body).padding([10, 12]).width(sizing.width).into()
|
||||
|
||||
Reference in new issue
Block a user