forked from 1b-agent/opencadstudio-upstream
Frames: state-following ribbon list, DWF/DGN frames, image frame encoding and profile, frame-only picking
- The Frames list shows the drawing's frame state (hide / display and plot / display but not plot / frames vary), follows commands, undo and document switches, and lists the mixed state as a disabled item. - DWFFRAME and DGNFRAME are frame variables of their own, kept in the header, and FRAME sets them with the others. - Out-of-range frame values say "Requires an integer between 0 and 2." and ask again; a set value reports "Regenerating model.". - IMAGEFRAME is stored in the image variables as bits (2 is written as 3) and a drawing without them uses the profile value, which setting IMAGEFRAME updates and the settings file keeps. - Raster images, PDF underlays and wipeouts are picked on their frame only; underlay snap geometry is never picked. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
801882314f
commit
7f8f8457c7
72 files changed
+451
-65
No files matched your search
Generated
+1
-1
@@ -4201,7 +4201,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "opencadcodec"
|
||||
version = "0.5.5"
|
||||
source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=42b44d2#42b44d2343e9925cff8a0c9e94c1d1c5ae8541c7"
|
||||
source = "git+https://github.com/ramox81/cadcodec.git?rev=ea5edaa#ea5edaaac269ae957805a2ff8a595db7fd7f4002"
|
||||
dependencies = [
|
||||
"ahash 0.8.12",
|
||||
"anyhow",
|
||||
|
||||
@@ -82,6 +82,11 @@ objc2-app-kit = { version = "0.2", features = ["NSApplication", "NSResponder", "
|
||||
block2 = "0.5"
|
||||
objc2-foundation = { version = "0.2", features = ["NSArray", "NSURL", "NSString", "NSObject", "NSNotification", "NSThread", "NSEnumerator"] }
|
||||
|
||||
# Frame header variables (DWFFRAME/DGNFRAME) until the codec change is released;
|
||||
# every crate that pulls the codec must see the same build.
|
||||
[patch."https://github.com/HakanSeven12/opencadcodec.git"]
|
||||
opencadcodec = { git = "https://github.com/ramox81/cadcodec.git", rev = "ea5edaa" }
|
||||
|
||||
[patch.crates-io]
|
||||
iced_core = { git = "https://github.com/iced-rs/iced.git", rev = "23604ff22ab0aad9e00b9327cb7b8546ed84db39" }
|
||||
iced_widget = { git = "https://github.com/iced-rs/iced.git", rev = "23604ff22ab0aad9e00b9327cb7b8546ed84db39" }
|
||||
|
||||
@@ -3667,6 +3667,12 @@ insert =
|
||||
.frames-print = الإطارات والطباعة
|
||||
.frames-off = إيقاف الإطارات
|
||||
.frames-on = تشغيل الإطارات
|
||||
.hide-frames = Hide frames
|
||||
.display-and-plot-frames = Display and plot frames
|
||||
.display-not-plot-frames = Display but don't plot frames
|
||||
.frames-vary = *Frames vary*
|
||||
.regenerating-model = Regenerating model.
|
||||
.requires-int-0-2 = Requires an integer between 0 and 2.
|
||||
.insert-prompt-hint = INSERT __ocs_arg_prompt____ocs_arg_hint__:
|
||||
.insert-enter-block-name-hint = INSERT أدخل اسم الكتلة:__ocs_arg_hint__
|
||||
.insert-filling-attributes = INSERT يجري ملء السمات...
|
||||
|
||||
@@ -3654,6 +3654,12 @@ insert =
|
||||
.frames-print = Рамки и печат
|
||||
.frames-off = Рамки изкл.
|
||||
.frames-on = Рамки вкл.
|
||||
.hide-frames = Hide frames
|
||||
.display-and-plot-frames = Display and plot frames
|
||||
.display-not-plot-frames = Display but don't plot frames
|
||||
.frames-vary = *Frames vary*
|
||||
.regenerating-model = Regenerating model.
|
||||
.requires-int-0-2 = Requires an integer between 0 and 2.
|
||||
.insert-prompt-hint = INSERT __ocs_arg_prompt____ocs_arg_hint__:
|
||||
.insert-enter-block-name-hint = INSERT Въведи име на блок:__ocs_arg_hint__
|
||||
.insert-filling-attributes = INSERT Попълване на атрибути...
|
||||
|
||||
@@ -3652,6 +3652,12 @@ insert =
|
||||
.frames-print = Rámy a tisk
|
||||
.frames-off = Rámy vypnuty
|
||||
.frames-on = Rámy zapnuty
|
||||
.hide-frames = Hide frames
|
||||
.display-and-plot-frames = Display and plot frames
|
||||
.display-not-plot-frames = Display but don't plot frames
|
||||
.frames-vary = *Frames vary*
|
||||
.regenerating-model = Regenerating model.
|
||||
.requires-int-0-2 = Requires an integer between 0 and 2.
|
||||
.insert-prompt-hint = INSERT __ocs_arg_prompt____ocs_arg_hint__:
|
||||
.insert-enter-block-name-hint = INSERT Název bloku Enter:__ocs_arg_hint__
|
||||
.insert-filling-attributes = INSERT Vyplňování atributů...
|
||||
|
||||
@@ -3655,6 +3655,12 @@ insert =
|
||||
.frames-print = Rahmen und Drucken
|
||||
.frames-off = Rahmen aus
|
||||
.frames-on = Rahmen ein
|
||||
.hide-frames = Hide frames
|
||||
.display-and-plot-frames = Display and plot frames
|
||||
.display-not-plot-frames = Display but don't plot frames
|
||||
.frames-vary = *Frames vary*
|
||||
.regenerating-model = Regenerating model.
|
||||
.requires-int-0-2 = Requires an integer between 0 and 2.
|
||||
.insert-prompt-hint = INSERT __ocs_arg_prompt____ocs_arg_hint__:
|
||||
.insert-enter-block-name-hint = INSERT Blockname eingeben:__ocs_arg_hint__
|
||||
.insert-filling-attributes = INSERT Attribute ausfüllen...
|
||||
|
||||
@@ -3662,6 +3662,12 @@ insert =
|
||||
.frames-print = Πλαίσια και εκτύπωση
|
||||
.frames-off = Πλαίσια ανενεργά
|
||||
.frames-on = Πλαίσια ενεργά
|
||||
.hide-frames = Hide frames
|
||||
.display-and-plot-frames = Display and plot frames
|
||||
.display-not-plot-frames = Display but don't plot frames
|
||||
.frames-vary = *Frames vary*
|
||||
.regenerating-model = Regenerating model.
|
||||
.requires-int-0-2 = Requires an integer between 0 and 2.
|
||||
.insert-prompt-hint = INSERT __ocs_arg_prompt____ocs_arg_hint__:
|
||||
.insert-enter-block-name-hint = INSERT Δώστε όνομα μπλοκ:__ocs_arg_hint__
|
||||
.insert-filling-attributes = INSERT Συμπλήρωση χαρακτηριστικών...
|
||||
|
||||
@@ -3656,6 +3656,12 @@ insert =
|
||||
.frames-print = Frames & Print
|
||||
.frames-off = Frames Off
|
||||
.frames-on = Frames On
|
||||
.hide-frames = Hide frames
|
||||
.display-and-plot-frames = Display and plot frames
|
||||
.display-not-plot-frames = Display but don't plot frames
|
||||
.frames-vary = *Frames vary*
|
||||
.regenerating-model = Regenerating model.
|
||||
.requires-int-0-2 = Requires an integer between 0 and 2.
|
||||
.insert-prompt-hint = INSERT __ocs_arg_prompt____ocs_arg_hint__:
|
||||
.insert-enter-block-name-hint = INSERT Enter block name:__ocs_arg_hint__
|
||||
.insert-filling-attributes = INSERT Filling attributes...
|
||||
|
||||
@@ -3655,6 +3655,12 @@ insert =
|
||||
.frames-print = Marcos e impresión
|
||||
.frames-off = Marcos desactivados
|
||||
.frames-on = Marcos activados
|
||||
.hide-frames = Hide frames
|
||||
.display-and-plot-frames = Display and plot frames
|
||||
.display-not-plot-frames = Display but don't plot frames
|
||||
.frames-vary = *Frames vary*
|
||||
.regenerating-model = Regenerating model.
|
||||
.requires-int-0-2 = Requires an integer between 0 and 2.
|
||||
.insert-prompt-hint = INSERT __ocs_arg_prompt____ocs_arg_hint__:
|
||||
.insert-enter-block-name-hint = INSERT Introduzca el nombre del bloque:__ocs_arg_hint__
|
||||
.insert-filling-attributes = INSERT Rellenando atributos...
|
||||
|
||||
@@ -3654,6 +3654,12 @@ insert =
|
||||
.frames-print = Kehykset ja painatus
|
||||
.frames-off = Kehykset pois päältä
|
||||
.frames-on = Kehykset päällä
|
||||
.hide-frames = Hide frames
|
||||
.display-and-plot-frames = Display and plot frames
|
||||
.display-not-plot-frames = Display but don't plot frames
|
||||
.frames-vary = *Frames vary*
|
||||
.regenerating-model = Regenerating model.
|
||||
.requires-int-0-2 = Requires an integer between 0 and 2.
|
||||
.insert-prompt-hint = INSERT __ocs_arg_prompt____ocs_arg_hint__:
|
||||
.insert-enter-block-name-hint = INSERT Enter -lohkon nimi:__ocs_arg_hint__
|
||||
.insert-filling-attributes = INSERT Täytetään määritteitä...
|
||||
|
||||
@@ -3655,6 +3655,12 @@ insert =
|
||||
.frames-print = Cadres & Imprimer
|
||||
.frames-off = Cadres désactivés
|
||||
.frames-on = Cadres en marche
|
||||
.hide-frames = Hide frames
|
||||
.display-and-plot-frames = Display and plot frames
|
||||
.display-not-plot-frames = Display but don't plot frames
|
||||
.frames-vary = *Frames vary*
|
||||
.regenerating-model = Regenerating model.
|
||||
.requires-int-0-2 = Requires an integer between 0 and 2.
|
||||
.insert-prompt-hint = INSERT __ocs_arg_prompt____ocs_arg_hint__:
|
||||
.insert-enter-block-name-hint = INSERT Saisissez le nom du bloc:__ocs_arg_hint__
|
||||
.insert-filling-attributes = INSERT Attributs de remplissage...
|
||||
|
||||
@@ -3643,6 +3643,12 @@ insert =
|
||||
.frames-print = फ्रेम्स एंड प्रिंट
|
||||
.frames-off = फ़्रेम बंद
|
||||
.frames-on = फ्रेम्स ऑन
|
||||
.hide-frames = Hide frames
|
||||
.display-and-plot-frames = Display and plot frames
|
||||
.display-not-plot-frames = Display but don't plot frames
|
||||
.frames-vary = *Frames vary*
|
||||
.regenerating-model = Regenerating model.
|
||||
.requires-int-0-2 = Requires an integer between 0 and 2.
|
||||
.insert-prompt-hint = INSERT __ocs_arg_prompt____ocs_arg_hint__:
|
||||
.insert-enter-block-name-hint = INSERT ब्लॉक का नाम दर्ज करें:__ocs_arg_hint__
|
||||
.insert-filling-attributes = INSERT गुण भरना ...
|
||||
|
||||
@@ -3654,6 +3654,12 @@ insert =
|
||||
.frames-print = Keretek és nyomtatás
|
||||
.frames-off = Keretek ki
|
||||
.frames-on = Keretek bekapcsolva
|
||||
.hide-frames = Hide frames
|
||||
.display-and-plot-frames = Display and plot frames
|
||||
.display-not-plot-frames = Display but don't plot frames
|
||||
.frames-vary = *Frames vary*
|
||||
.regenerating-model = Regenerating model.
|
||||
.requires-int-0-2 = Requires an integer between 0 and 2.
|
||||
.insert-prompt-hint = INSERT __ocs_arg_prompt____ocs_arg_hint__:
|
||||
.insert-enter-block-name-hint = INSERT Enter blokknév: __ocs_arg_hint__
|
||||
.insert-filling-attributes = INSERT Attribútumok kitöltése...
|
||||
|
||||
@@ -3654,6 +3654,12 @@ insert =
|
||||
.frames-print = Cornici e stampa
|
||||
.frames-off = Cornici disattivate
|
||||
.frames-on = Cornici attivate
|
||||
.hide-frames = Hide frames
|
||||
.display-and-plot-frames = Display and plot frames
|
||||
.display-not-plot-frames = Display but don't plot frames
|
||||
.frames-vary = *Frames vary*
|
||||
.regenerating-model = Regenerating model.
|
||||
.requires-int-0-2 = Requires an integer between 0 and 2.
|
||||
.insert-prompt-hint = INSERT __ocs_arg_prompt____ocs_arg_hint__:
|
||||
.insert-enter-block-name-hint = INSERT Enter nome del blocco:__ocs_arg_hint__
|
||||
.insert-filling-attributes = INSERT Attributi di riempimento...
|
||||
|
||||
@@ -3643,6 +3643,12 @@ insert =
|
||||
.frames-print = フレームと印刷
|
||||
.frames-off = フレームをオフ
|
||||
.frames-on = フレームをオン
|
||||
.hide-frames = Hide frames
|
||||
.display-and-plot-frames = Display and plot frames
|
||||
.display-not-plot-frames = Display but don't plot frames
|
||||
.frames-vary = *Frames vary*
|
||||
.regenerating-model = Regenerating model.
|
||||
.requires-int-0-2 = Requires an integer between 0 and 2.
|
||||
.insert-prompt-hint = INSERT __ocs_arg_prompt____ocs_arg_hint__:
|
||||
.insert-enter-block-name-hint = INSERT ブロック名を入力:__ocs_arg_hint__
|
||||
.insert-filling-attributes = INSERT 属性を入力中...
|
||||
|
||||
@@ -3654,6 +3654,12 @@ insert =
|
||||
.frames-print = 프레임 및 인쇄
|
||||
.frames-off = 프레임 끄기
|
||||
.frames-on = 프레임 켜짐
|
||||
.hide-frames = Hide frames
|
||||
.display-and-plot-frames = Display and plot frames
|
||||
.display-not-plot-frames = Display but don't plot frames
|
||||
.frames-vary = *Frames vary*
|
||||
.regenerating-model = Regenerating model.
|
||||
.requires-int-0-2 = Requires an integer between 0 and 2.
|
||||
.insert-prompt-hint = INSERT __ocs_arg_prompt____ocs_arg_hint__:
|
||||
.insert-enter-block-name-hint = INSERT Enter 블록 이름:__ocs_arg_hint__
|
||||
.insert-filling-attributes = INSERT 채우기 속성...
|
||||
|
||||
@@ -3653,6 +3653,12 @@ insert =
|
||||
.frames-print = Frames & afdrukken
|
||||
.frames-off = Frames uitgeschakeld
|
||||
.frames-on = Frames aan
|
||||
.hide-frames = Hide frames
|
||||
.display-and-plot-frames = Display and plot frames
|
||||
.display-not-plot-frames = Display but don't plot frames
|
||||
.frames-vary = *Frames vary*
|
||||
.regenerating-model = Regenerating model.
|
||||
.requires-int-0-2 = Requires an integer between 0 and 2.
|
||||
.insert-prompt-hint = INSERT __ocs_arg_prompt____ocs_arg_hint__:
|
||||
.insert-enter-block-name-hint = INSERT Geef symboolnaam in:__ocs_arg_hint__
|
||||
.insert-filling-attributes = INSERT Attributen vullen...
|
||||
|
||||
@@ -3654,6 +3654,12 @@ insert =
|
||||
.frames-print = Ramki i druk
|
||||
.frames-off = Ramki wyłączone
|
||||
.frames-on = Ramki włączone
|
||||
.hide-frames = Hide frames
|
||||
.display-and-plot-frames = Display and plot frames
|
||||
.display-not-plot-frames = Display but don't plot frames
|
||||
.frames-vary = *Frames vary*
|
||||
.regenerating-model = Regenerating model.
|
||||
.requires-int-0-2 = Requires an integer between 0 and 2.
|
||||
.insert-prompt-hint = INSERT __ocs_arg_prompt____ocs_arg_hint__:
|
||||
.insert-enter-block-name-hint = INSERT Enter nazwa bloku: __ocs_arg_hint__
|
||||
.insert-filling-attributes = INSERT Wypełnianie atrybutów...
|
||||
|
||||
@@ -3655,6 +3655,12 @@ insert =
|
||||
.frames-print = Molduras e impressão
|
||||
.frames-off = Molduras desativadas
|
||||
.frames-on = Molduras ativadas
|
||||
.hide-frames = Hide frames
|
||||
.display-and-plot-frames = Display and plot frames
|
||||
.display-not-plot-frames = Display but don't plot frames
|
||||
.frames-vary = *Frames vary*
|
||||
.regenerating-model = Regenerating model.
|
||||
.requires-int-0-2 = Requires an integer between 0 and 2.
|
||||
.insert-prompt-hint = INSERT __ocs_arg_prompt____ocs_arg_hint__:
|
||||
.insert-enter-block-name-hint = INSERT Insira o nome do bloco:__ocs_arg_hint__
|
||||
.insert-filling-attributes = INSERT Preenchendo atributos...
|
||||
|
||||
@@ -3656,6 +3656,12 @@ insert =
|
||||
.frames-print = Frames & Print (недоступная ссылка)
|
||||
.frames-off = Снятие рам
|
||||
.frames-on = В кадрах
|
||||
.hide-frames = Hide frames
|
||||
.display-and-plot-frames = Display and plot frames
|
||||
.display-not-plot-frames = Display but don't plot frames
|
||||
.frames-vary = *Frames vary*
|
||||
.regenerating-model = Regenerating model.
|
||||
.requires-int-0-2 = Requires an integer between 0 and 2.
|
||||
.insert-prompt-hint = INSERT __ocs_arg_prompt____ocs_arg_hint__:
|
||||
.insert-enter-block-name-hint = INSERT Введите имя блока: __ocs_arg_hint__
|
||||
.insert-filling-attributes = INSERT Наполнение атрибутов...
|
||||
|
||||
@@ -3625,6 +3625,12 @@ insert =
|
||||
.frames-print = Çerçeveler ve Yazdırma
|
||||
.frames-off = Çerçeveler Kapalı
|
||||
.frames-on = Çerçeveler Açık
|
||||
.hide-frames = Çerçeveleri gizle
|
||||
.display-and-plot-frames = Çerçeveleri göster ve çizdir
|
||||
.display-not-plot-frames = Çerçeveleri göster, çizdirme
|
||||
.frames-vary = *Çerçeveler farklı*
|
||||
.regenerating-model = Model yeniden oluşturuluyor.
|
||||
.requires-int-0-2 = 0 ile 2 arasında bir tamsayı gerekli.
|
||||
.insert-prompt-hint = INSERT __ocs_arg_prompt____ocs_arg_hint__:
|
||||
.insert-enter-block-name-hint = INSERT Blok adını girin:__ocs_arg_hint__
|
||||
.insert-filling-attributes = INSERT Öznitelikler dolduruluyor...
|
||||
|
||||
@@ -3640,6 +3640,12 @@ insert =
|
||||
.frames-print = 边框与打印
|
||||
.frames-off = 边框关
|
||||
.frames-on = 边框开
|
||||
.hide-frames = Hide frames
|
||||
.display-and-plot-frames = Display and plot frames
|
||||
.display-not-plot-frames = Display but don't plot frames
|
||||
.frames-vary = *Frames vary*
|
||||
.regenerating-model = Regenerating model.
|
||||
.requires-int-0-2 = Requires an integer between 0 and 2.
|
||||
.insert-prompt-hint = INSERT __ocs_arg_prompt____ocs_arg_hint__:
|
||||
.insert-enter-block-name-hint = INSERT 输入块名:__ocs_arg_hint__
|
||||
.insert-filling-attributes = INSERT 正在填充属性...
|
||||
|
||||
@@ -3652,6 +3652,12 @@ insert =
|
||||
.frames-print = 邊框與列印
|
||||
.frames-off = 邊框關
|
||||
.frames-on = 邊框開
|
||||
.hide-frames = Hide frames
|
||||
.display-and-plot-frames = Display and plot frames
|
||||
.display-not-plot-frames = Display but don't plot frames
|
||||
.frames-vary = *Frames vary*
|
||||
.regenerating-model = Regenerating model.
|
||||
.requires-int-0-2 = Requires an integer between 0 and 2.
|
||||
.insert-prompt-hint = INSERT __ocs_arg_prompt____ocs_arg_hint__:
|
||||
.insert-enter-block-name-hint = INSERT 輸入圖塊名:__ocs_arg_hint__
|
||||
.insert-filling-attributes = INSERT 正在填充屬性...
|
||||
|
||||
@@ -618,6 +618,8 @@ inventory::submit!(crate::command::CommandRegistration {
|
||||
"FRAME",
|
||||
"IMAGEFRAME",
|
||||
"PDFFRAME",
|
||||
"DWFFRAME",
|
||||
"DGNFRAME",
|
||||
"PDFOSNAP",
|
||||
"UOSNAP",
|
||||
"PDFIMPORTMODE",
|
||||
@@ -630,6 +632,7 @@ inventory::submit!(crate::command::CommandRegistration {
|
||||
"WIPEOUTFRAME",
|
||||
"FRAMES0",
|
||||
"FRAMES1",
|
||||
"FRAMES3",
|
||||
"FRAMES2",
|
||||
"UOSNAP0",
|
||||
"UOSNAP1",
|
||||
|
||||
@@ -10,6 +10,8 @@ impl OpenCADStudio {
|
||||
"FRAMES0" => return self.dispatch_styleprops("SETVAR FRAME 0", i),
|
||||
"FRAMES1" => return self.dispatch_styleprops("SETVAR FRAME 1", i),
|
||||
"FRAMES2" => return self.dispatch_styleprops("SETVAR FRAME 2", i),
|
||||
// The mixed state is shown, never chosen.
|
||||
"FRAMES3" => return Some(Task::none()),
|
||||
"UOSNAP0" => return self.dispatch_styleprops("SETVAR UOSNAP 0", i),
|
||||
"UOSNAP1" => return self.dispatch_styleprops("SETVAR UOSNAP 1", i),
|
||||
// COLOR <ByLayer|ByBlock|1-255|name> — the colour applied to new
|
||||
@@ -1017,6 +1019,8 @@ impl OpenCADStudio {
|
||||
| "FRAME"
|
||||
| "IMAGEFRAME"
|
||||
| "PDFFRAME"
|
||||
| "DWFFRAME"
|
||||
| "DGNFRAME"
|
||||
| "PDFOSNAP"
|
||||
| "UOSNAP"
|
||||
| "PDFIMPORTMODE"
|
||||
@@ -1283,13 +1287,23 @@ impl OpenCADStudio {
|
||||
self.tabs[i].scene.bump_entities(&changes);
|
||||
}
|
||||
self.tabs[i].dirty = true;
|
||||
// IMAGEFRAME also lands in the profile.
|
||||
self.save_config();
|
||||
}
|
||||
self.command_line
|
||||
.push_output(&crate::tf!("{name} = {mode}"));
|
||||
.push_output(crate::t!("Regenerating model.").as_ref());
|
||||
}
|
||||
// Out of range: say so and ask again.
|
||||
_ => {
|
||||
self.command_line.push_error(
|
||||
crate::t!("Requires an integer between 0 and 2.").as_ref(),
|
||||
);
|
||||
self.command_line.push_output(
|
||||
crate::tf!("Enter new value for {name} <{current}>:")
|
||||
.as_ref(),
|
||||
);
|
||||
self.pending_setvar = Some(name.clone());
|
||||
}
|
||||
_ => self.command_line.push_error(
|
||||
crate::tf!("SETVAR: {name} requires 0, 1, or 2.").as_ref(),
|
||||
),
|
||||
},
|
||||
None => {
|
||||
self.command_line.push_output(crate::tf!(
|
||||
|
||||
@@ -366,6 +366,9 @@ pub struct UserSettings {
|
||||
/// GRIPOBJLIMIT: past this many selected objects, no grips are drawn at
|
||||
/// all. 0 means no limit. The drawing header carries no slot for it.
|
||||
pub grip_object_limit: i32,
|
||||
/// IMAGEFRAME of the profile: used by new drawings and by drawings that
|
||||
/// carry no image variables of their own.
|
||||
pub image_frame: i16,
|
||||
/// Nested-copy symbol handling: false inserts, true binds.
|
||||
pub ncopy_bind: bool,
|
||||
/// Last Options page; unknown saved names fall back without rejecting the config.
|
||||
@@ -653,6 +656,7 @@ impl Default for UserSettings {
|
||||
right_click_mode: RightClickMode::ShortcutMenu,
|
||||
right_click_hold_ms: 250,
|
||||
grip_object_limit: DEFAULT_GRIP_OBJECT_LIMIT,
|
||||
image_frame: 1,
|
||||
ncopy_bind: false,
|
||||
cursor_type: CursorType::Crosshair,
|
||||
crosshair_color: None,
|
||||
|
||||
@@ -614,6 +614,7 @@ impl OpenCADStudio {
|
||||
right_click_mode: self.right_click_mode,
|
||||
right_click_hold_ms: self.right_click_hold_ms,
|
||||
grip_object_limit: self.grip_object_limit,
|
||||
image_frame: crate::scene::frame::profile_image_mode(),
|
||||
ncopy_bind: self.ncopy_bind,
|
||||
cursor_type: self.cursor_type,
|
||||
crosshair_color: self.crosshair_color,
|
||||
@@ -698,6 +699,7 @@ impl OpenCADStudio {
|
||||
self.right_click_mode = s.right_click_mode;
|
||||
self.right_click_hold_ms = super::super::settings::clamp_right_click_hold_ms(s.right_click_hold_ms);
|
||||
self.grip_object_limit = s.grip_object_limit.clamp(0, 32767);
|
||||
crate::scene::frame::set_profile_image_mode(s.image_frame);
|
||||
self.ncopy_bind = s.ncopy_bind;
|
||||
self.cursor_type = s.cursor_type;
|
||||
self.crosshair_color = s.crosshair_color;
|
||||
|
||||
@@ -326,9 +326,26 @@ impl OpenCADStudio {
|
||||
if self.tabs.get(self.active_tab).map(|tab| tab.id) != before {
|
||||
self.sync_underlay_tab();
|
||||
}
|
||||
self.sync_frame_dropdown();
|
||||
task
|
||||
}
|
||||
|
||||
/// The Frames list on the ribbon shows the active drawing's frame state
|
||||
/// (FRAME), however it was changed: the list, a command, undo or another
|
||||
/// drawing.
|
||||
fn sync_frame_dropdown(&mut self) {
|
||||
let Some(tab) = self.tabs.get(self.active_tab).filter(|tab| !tab.is_start) else {
|
||||
return;
|
||||
};
|
||||
let current = match crate::scene::frame::master_mode(&tab.scene.document) {
|
||||
0 => "FRAMES0",
|
||||
1 => "FRAMES1",
|
||||
2 => "FRAMES2",
|
||||
_ => "FRAMES3",
|
||||
};
|
||||
self.ribbon.set_dropdown_current("FRAMES_DROPDOWN", current);
|
||||
}
|
||||
|
||||
fn update_message(&mut self, msg: Message) -> Task<Message> {
|
||||
if let Some(tab) = self.tabs.get(self.active_tab) {
|
||||
crate::entities::common::set_unit_context(
|
||||
|
||||
@@ -2726,6 +2726,7 @@ impl OpenCADStudio {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -4041,6 +4041,7 @@ fn tessellate_dimension_inner(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -4077,6 +4078,7 @@ fn tessellate_dimension_inner(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -4113,6 +4115,7 @@ fn tessellate_dimension_inner(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -4150,6 +4153,7 @@ fn tessellate_dimension_inner(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -4195,6 +4199,7 @@ fn tessellate_dimension_inner(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -4244,6 +4249,7 @@ fn tessellate_dimension_inner(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -4295,6 +4301,7 @@ fn tessellate_dimension_inner(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -679,6 +679,7 @@ impl LeaderTess for Leader {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -860,6 +861,7 @@ impl LeaderTess for Leader {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -2075,6 +2075,7 @@ impl MultiLeaderTess for MultiLeader {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -2389,6 +2390,7 @@ impl MultiLeaderTess for MultiLeader {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -2464,6 +2466,7 @@ impl MultiLeaderTess for MultiLeader {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -2554,6 +2557,7 @@ impl MultiLeaderTess for MultiLeader {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -2599,6 +2603,7 @@ impl MultiLeaderTess for MultiLeader {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -178,9 +178,9 @@ impl RenderConvertible for RasterImage {
|
||||
path.is_empty() || crate::scene::model::image_model::resolve_image(path).is_some();
|
||||
if resolvable {
|
||||
return Some(RenderEntity {
|
||||
// Interior pick surface: the image selects on a click anywhere
|
||||
// inside its frame, not just on the border.
|
||||
pick_tris: crate::entities::common::quad_pick_tris(&corners),
|
||||
// Picked on its frame only (shown or hidden), like the other
|
||||
// framed objects: a click inside the picture selects nothing.
|
||||
pick_tris: vec![],
|
||||
object: RenderObject::Lines(pts),
|
||||
snap_pts: vec![],
|
||||
tangent_geoms: vec![],
|
||||
@@ -269,7 +269,7 @@ impl RenderConvertible for RasterImage {
|
||||
}
|
||||
|
||||
Some(RenderEntity {
|
||||
pick_tris: crate::entities::common::quad_pick_tris(&corners),
|
||||
pick_tris: vec![],
|
||||
object: RenderObject::Text(groups),
|
||||
snap_pts: vec![],
|
||||
tangent_geoms: vec![],
|
||||
@@ -512,30 +512,6 @@ fn wipeout_axis_length(axis: &codec::types::Vector3, size: f64) -> f64 {
|
||||
(axis.x * axis.x + axis.y * axis.y + axis.z * axis.z).sqrt() * size.abs()
|
||||
}
|
||||
|
||||
fn wipeout_pick_rings(wipeout: &Wipeout) -> Vec<Vec<[f64; 3]>> {
|
||||
let boundary = wipeout_boundary(wipeout);
|
||||
if wipeout_is_polygonal(wipeout)
|
||||
&& matches!(
|
||||
wipeout.clip_mode,
|
||||
codec::entities::WipeoutClipMode::Inside
|
||||
)
|
||||
{
|
||||
vec![
|
||||
image_corners(
|
||||
&wipeout.insertion_point,
|
||||
&wipeout.u_vector,
|
||||
&wipeout.v_vector,
|
||||
wipeout.size.x,
|
||||
wipeout.size.y,
|
||||
)
|
||||
.to_vec(),
|
||||
boundary,
|
||||
]
|
||||
} else {
|
||||
vec![boundary]
|
||||
}
|
||||
}
|
||||
|
||||
fn wipeout_world_to_clip(wipeout: &Wipeout, world: [f64; 3]) -> Option<codec::types::Vector2> {
|
||||
let [x, y] = wipeout_plane(wipeout).project(world)?;
|
||||
Some(codec::types::Vector2::new(
|
||||
@@ -553,10 +529,8 @@ impl RenderConvertible for Wipeout {
|
||||
}
|
||||
|
||||
Some(RenderEntity {
|
||||
pick_tris: kernel::space::polygon::triangulate_rings(
|
||||
&wipeout_pick_rings(self),
|
||||
kernel::geom2d::Tolerance::default(),
|
||||
),
|
||||
// Picked on its frame only; the masked area selects nothing.
|
||||
pick_tris: vec![],
|
||||
object: RenderObject::Lines(pts),
|
||||
snap_pts: boundary
|
||||
.iter()
|
||||
|
||||
@@ -2036,6 +2036,7 @@ pub fn tessellate_table(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -288,21 +288,20 @@ impl RenderConvertible for Underlay {
|
||||
});
|
||||
}
|
||||
|
||||
// Pick surface over the shown area so a click inside selects it.
|
||||
let pick_ring: Vec<[f64; 3]> = if !clip.is_empty() && !self.clip_inverted {
|
||||
// Picked on its frame only; the page itself selects nothing.
|
||||
let key_ring: Vec<[f64; 3]> = if !clip.is_empty() && !self.clip_inverted {
|
||||
clip.clone()
|
||||
} else {
|
||||
quad.map(|q| q.to_vec()).unwrap_or_default()
|
||||
};
|
||||
let pick_tris = crate::entities::mesh::triangulate_planar(&pick_ring);
|
||||
let mut snap_pts = vec![insertion_snap];
|
||||
snap_pts.extend(crate::scene::model::pdf_vector::underlay_snap_points(self, document));
|
||||
Some(RenderEntity {
|
||||
pick_tris,
|
||||
pick_tris: vec![],
|
||||
object: RenderObject::Lines(pts),
|
||||
snap_pts,
|
||||
tangent_geoms: vec![],
|
||||
key_vertices: pick_ring,
|
||||
key_vertices: key_ring,
|
||||
fill_tris: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1197,6 +1197,12 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static
|
||||
"Frames & Print" => Some(("insert", "frames-print")),
|
||||
"Frames Off" => Some(("insert", "frames-off")),
|
||||
"Frames On" => Some(("insert", "frames-on")),
|
||||
"Hide frames" => Some(("insert", "hide-frames")),
|
||||
"Display and plot frames" => Some(("insert", "display-and-plot-frames")),
|
||||
"Display but don't plot frames" => Some(("insert", "display-not-plot-frames")),
|
||||
"*Frames vary*" => Some(("insert", "frames-vary")),
|
||||
"Regenerating model." => Some(("insert", "regenerating-model")),
|
||||
"Requires an integer between 0 and 2." => Some(("insert", "requires-int-0-2")),
|
||||
"Frames On, Not Plotted" => Some(("draw", "frames-on-not-plotted")),
|
||||
"Freeze" => Some(("layers", "freeze")),
|
||||
"From DXF" => Some(("properties", "from-dxf")),
|
||||
|
||||
@@ -340,6 +340,7 @@ impl CadCommand for AlignedDimensionCommand {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -432,6 +433,7 @@ fn preview_aligned(p1: DVec3, p2: DVec3, dim_pt: DVec3) -> WireModel {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -1249,6 +1249,7 @@ fn preview_wire(points: Vec<DVec3>) -> WireModel {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -108,6 +108,7 @@ impl DataLinkPlaceCommand {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -332,6 +332,7 @@ fn preview_line(far_chord: Vec3, chord: Vec3, text: Vec3) -> WireModel {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -729,6 +729,7 @@ fn preview_for_dimension(dimension: &Dimension) -> WireModel {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -480,6 +480,7 @@ fn preview_wire(points: Vec<Vec3>) -> WireModel {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -444,6 +444,7 @@ fn preview_wire(pts: &[Vec3], arrow_size: f32) -> WireModel {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -561,6 +561,7 @@ fn preview_wire(points: Vec<DVec3>) -> WireModel {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -773,6 +773,7 @@ fn preview_wire(pts: &[Vec3], arrow_size: f32) -> WireModel {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -497,6 +497,7 @@ fn preview_wire(pts: &[Vec3]) -> WireModel {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -289,6 +289,7 @@ fn preview_wire(points: Vec<Vec3>) -> WireModel {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -350,6 +350,7 @@ fn preview_wire(points: Vec<Vec3>) -> WireModel {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -315,6 +315,7 @@ impl TableCommand {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -88,6 +88,7 @@ impl CadCommand for ToleranceCommand {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -206,6 +206,7 @@ impl CadCommand for AttdefCommand {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -187,6 +187,7 @@ impl MlineCommand {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: true,
|
||||
|
||||
@@ -176,6 +176,7 @@ impl CadCommand for ImageCommand {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -93,6 +93,7 @@ impl CadCommand for RayCommand {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -378,6 +379,7 @@ impl CadCommand for XLineCommand {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -375,6 +375,7 @@ impl CadCommand for AreaCommand {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -95,6 +95,7 @@ impl CadCommand for DistCommand {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -77,6 +77,7 @@ impl MeasureGeomCommand {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -4151,6 +4151,7 @@ fn preview_wire(points: Vec<[f32; 3]>, color: [f32; 4], name: &str) -> WireModel
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -62,9 +62,12 @@ impl CadModule for InsertModule {
|
||||
label: "",
|
||||
icon: FRAMES_ICON,
|
||||
items: vec![
|
||||
("FRAMES0", "Frames Off", FRAMES_ICON),
|
||||
("FRAMES1", "Frames On", FRAMES_ICON),
|
||||
("FRAMES2", "Frames On, Not Plotted", FRAMES_ICON),
|
||||
("FRAMES0", "Hide frames", FRAMES_ICON),
|
||||
("FRAMES1", "Display and plot frames", FRAMES_ICON),
|
||||
("FRAMES2", "Display but don't plot frames", FRAMES_ICON),
|
||||
// Shown (not selectable) while the frame
|
||||
// variables differ from each other.
|
||||
("FRAMES3", "*Frames vary*", FRAMES_ICON),
|
||||
],
|
||||
default: "FRAMES1",
|
||||
},
|
||||
|
||||
@@ -3647,6 +3647,7 @@ fn wire(name: &str, points: Vec<[f32; 3]>) -> WireModel {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -61,6 +61,7 @@ impl CadCommand for PlotWindowCommand {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -143,6 +143,7 @@ impl CadCommand for ZoomWindowCommand {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
Vendored
+2
@@ -1750,6 +1750,7 @@ impl Batches {
|
||||
world_width: b.world_width,
|
||||
depth_override: b.local_depth,
|
||||
display_visible: !b.hide_unselected || selected,
|
||||
snap_only: false,
|
||||
plot_visible: b.plot_visible,
|
||||
fill_is_3d: b.fill_is_3d,
|
||||
fill_is_2d_solid: b.fill_is_2d_solid,
|
||||
@@ -2516,6 +2517,7 @@ fn emit_wire(
|
||||
world_width: 0.0,
|
||||
depth_override: local_depth,
|
||||
display_visible: !lw.hide_unselected || ctx.selected,
|
||||
snap_only: false,
|
||||
plot_visible: lw.plot_visible,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -931,6 +931,7 @@ fn tessellate_entity_inner(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1176,6 +1177,7 @@ fn tessellate_entity_inner(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1296,6 +1298,8 @@ fn tessellate_entity_inner(
|
||||
wire.points_low = points_low;
|
||||
wire.display_visible = false;
|
||||
wire.plot_visible = false;
|
||||
// Snaps find it; a click on the page does not select the underlay.
|
||||
wire.snap_only = true;
|
||||
if let Some((center, radius)) = piece.circle {
|
||||
wire.tangent_geoms = vec![crate::scene::model::wire_model::TangentGeom::PlanarCircle {
|
||||
center,
|
||||
@@ -1549,6 +1553,7 @@ fn lod_stub_wire(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1645,6 +1650,7 @@ fn lod_stub_wire_3d(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -373,6 +373,7 @@ fn split_mixed_polyline(
|
||||
world_width,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -508,6 +509,7 @@ fn split_mixed_polyline(
|
||||
world_width: line_world_width,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -571,6 +573,7 @@ fn point_cloud_wires(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -826,6 +829,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: true,
|
||||
@@ -990,6 +994,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1382,6 +1387,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1439,6 +1445,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1493,6 +1500,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1528,6 +1536,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1593,6 +1602,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1640,6 +1650,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1684,6 +1695,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1721,6 +1733,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1792,6 +1805,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1951,6 +1965,7 @@ pub fn tessellate(
|
||||
world_width: polyline_band_width(entity, document.header.fill_mode),
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -2022,6 +2037,7 @@ pub fn tessellate(
|
||||
render_instance: None,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
});
|
||||
}
|
||||
@@ -2035,6 +2051,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -2094,6 +2111,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -2183,6 +2201,7 @@ pub fn tessellate(
|
||||
world_width: polyline_band_width(entity, document.header.fill_mode),
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -2261,6 +2280,7 @@ pub fn tessellate(
|
||||
world_width,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -2370,6 +2390,7 @@ pub fn tessellate(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
+57
-13
@@ -5,19 +5,52 @@ use codec::{CadDocument, EntityType, Handle};
|
||||
pub(crate) enum FrameKind {
|
||||
Image,
|
||||
Pdf,
|
||||
Dwf,
|
||||
Dgn,
|
||||
Wipeout,
|
||||
Xclip,
|
||||
PointCloudClip,
|
||||
}
|
||||
|
||||
pub(crate) const ALL_KINDS: [FrameKind; 5] = [
|
||||
pub(crate) const ALL_KINDS: [FrameKind; 7] = [
|
||||
FrameKind::Image,
|
||||
FrameKind::Pdf,
|
||||
FrameKind::Dwf,
|
||||
FrameKind::Dgn,
|
||||
FrameKind::Wipeout,
|
||||
FrameKind::Xclip,
|
||||
FrameKind::PointCloudClip,
|
||||
];
|
||||
|
||||
/// IMAGEFRAME of the user profile: what a drawing without its own image
|
||||
/// variables shows, and what a new drawing starts with. Setting IMAGEFRAME
|
||||
/// updates it, so it carries over to new drawings and later sessions.
|
||||
static PROFILE_IMAGE_FRAME: std::sync::atomic::AtomicI16 = std::sync::atomic::AtomicI16::new(1);
|
||||
|
||||
pub(crate) fn profile_image_mode() -> i16 {
|
||||
PROFILE_IMAGE_FRAME.load(std::sync::atomic::Ordering::Relaxed)
|
||||
}
|
||||
|
||||
pub(crate) fn set_profile_image_mode(value: i16) {
|
||||
PROFILE_IMAGE_FRAME.store(value.clamp(0, 2), std::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
|
||||
/// The image variables store the frame as bits: 1 shown, 2 not plotted, so
|
||||
/// "shown but not plotted" is 3. Any other value is not one the variable
|
||||
/// can hold, and the profile setting applies.
|
||||
fn image_mode_from_flags(flags: i16) -> Option<i16> {
|
||||
match flags {
|
||||
0 => Some(0),
|
||||
1 => Some(1),
|
||||
3 => Some(2),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn image_flags_from_mode(mode: i16) -> i16 {
|
||||
if mode == 2 { 3 } else { mode }
|
||||
}
|
||||
|
||||
fn root_entry(document: &CadDocument, name: &str) -> Option<Handle> {
|
||||
let from_dictionary = |handle| match document.objects.get(&handle) {
|
||||
Some(ObjectType::Dictionary(dictionary)) => dictionary
|
||||
@@ -58,12 +91,15 @@ pub(crate) fn mode(document: &CadDocument, kind: FrameKind) -> i16 {
|
||||
match kind {
|
||||
FrameKind::Image => raster_variables_handle(document)
|
||||
.and_then(|handle| match document.objects.get(&handle) {
|
||||
Some(ObjectType::RasterVariables(value)) => Some(value.display_image_frame),
|
||||
Some(ObjectType::RasterVariables(value)) => {
|
||||
image_mode_from_flags(value.display_image_frame)
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.unwrap_or(1)
|
||||
.clamp(0, 2),
|
||||
.unwrap_or_else(profile_image_mode),
|
||||
FrameKind::Pdf => drawing_mode(document, "PDFFRAME", 1),
|
||||
FrameKind::Dwf => document.header.dwf_frame.clamp(0, 2),
|
||||
FrameKind::Dgn => document.header.dgn_frame.clamp(0, 2),
|
||||
FrameKind::Wipeout => crate::io::drawing_variable(document, "WIPEOUTFRAME")
|
||||
.and_then(|value| value.parse::<i16>().ok())
|
||||
.or_else(|| {
|
||||
@@ -115,8 +151,9 @@ fn set_image_mode(document: &mut CadDocument, value: i16) {
|
||||
});
|
||||
if let Some(ObjectType::RasterVariables(variables)) = document.objects.get_mut(&handle) {
|
||||
variables.owner = owner;
|
||||
variables.display_image_frame = value;
|
||||
variables.display_image_frame = image_flags_from_mode(value);
|
||||
}
|
||||
set_profile_image_mode(value);
|
||||
attach_root_entry(document, "ACAD_IMAGE_VARS", handle);
|
||||
}
|
||||
|
||||
@@ -145,6 +182,8 @@ pub(crate) fn set_mode(document: &mut CadDocument, kind: FrameKind, value: i16)
|
||||
match kind {
|
||||
FrameKind::Image => set_image_mode(document, value),
|
||||
FrameKind::Pdf => crate::io::set_drawing_variable(document, "PDFFRAME", &value.to_string()),
|
||||
FrameKind::Dwf => document.header.dwf_frame = value,
|
||||
FrameKind::Dgn => document.header.dgn_frame = value,
|
||||
FrameKind::Wipeout => set_wipeout_mode(document, value),
|
||||
FrameKind::Xclip => document.header.xclip_frame = value,
|
||||
FrameKind::PointCloudClip => crate::io::set_drawing_variable(
|
||||
@@ -168,6 +207,8 @@ pub(crate) fn kind_for_name(name: &str) -> Option<FrameKind> {
|
||||
match name {
|
||||
"IMAGEFRAME" => Some(FrameKind::Image),
|
||||
"PDFFRAME" => Some(FrameKind::Pdf),
|
||||
"DWFFRAME" => Some(FrameKind::Dwf),
|
||||
"DGNFRAME" => Some(FrameKind::Dgn),
|
||||
"WIPEOUTFRAME" => Some(FrameKind::Wipeout),
|
||||
"XCLIPFRAME" => Some(FrameKind::Xclip),
|
||||
"POINTCLOUDCLIPFRAME" => Some(FrameKind::PointCloudClip),
|
||||
@@ -178,23 +219,26 @@ pub(crate) fn kind_for_name(name: &str) -> Option<FrameKind> {
|
||||
pub(crate) fn entity_kind(entity: &EntityType) -> Option<FrameKind> {
|
||||
match entity {
|
||||
EntityType::RasterImage(_) => Some(FrameKind::Image),
|
||||
EntityType::Underlay(underlay)
|
||||
if matches!(underlay.underlay_type, codec::entities::UnderlayType::Pdf) =>
|
||||
{
|
||||
Some(FrameKind::Pdf)
|
||||
}
|
||||
EntityType::Underlay(underlay) => Some(underlay_kind(underlay)),
|
||||
EntityType::Wipeout(_) => Some(FrameKind::Wipeout),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn underlay_kind(underlay: &codec::entities::Underlay) -> FrameKind {
|
||||
match underlay.underlay_type {
|
||||
codec::entities::UnderlayType::Pdf => FrameKind::Pdf,
|
||||
codec::entities::UnderlayType::Dwf => FrameKind::Dwf,
|
||||
codec::entities::UnderlayType::Dgn => FrameKind::Dgn,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn affected(entity: &EntityType, kind: FrameKind) -> bool {
|
||||
match kind {
|
||||
FrameKind::Image => matches!(entity, EntityType::RasterImage(_)),
|
||||
FrameKind::Pdf => matches!(
|
||||
FrameKind::Pdf | FrameKind::Dwf | FrameKind::Dgn => matches!(
|
||||
entity,
|
||||
EntityType::Underlay(underlay)
|
||||
if matches!(underlay.underlay_type, codec::entities::UnderlayType::Pdf)
|
||||
EntityType::Underlay(underlay) if underlay_kind(underlay) == kind
|
||||
),
|
||||
FrameKind::Wipeout => matches!(entity, EntityType::Wipeout(_)),
|
||||
FrameKind::Xclip => matches!(entity, EntityType::Insert(_)),
|
||||
|
||||
@@ -506,6 +506,9 @@ pub struct WireModel {
|
||||
pub depth_override: Option<f32>,
|
||||
/// Whether this wire is drawn in the normal viewport pass.
|
||||
pub display_visible: bool,
|
||||
/// Geometry that only object snaps use (the content of an underlay):
|
||||
/// never drawn, plotted or picked.
|
||||
pub snap_only: bool,
|
||||
/// Whether this wire is included in plotted output.
|
||||
pub plot_visible: bool,
|
||||
/// `true` when [`fill_tris`] is a real 3-D surface (PolyfaceMesh /
|
||||
@@ -580,6 +583,7 @@ impl WireModel {
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -1009,6 +1013,7 @@ impl Default for WireModel {
|
||||
fill_tris_low: Vec::new(),
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -249,6 +249,9 @@ pub fn click_hit<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(segment.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if wire.point_marker.is_some() {
|
||||
continue;
|
||||
}
|
||||
@@ -277,6 +280,9 @@ pub fn click_hit<'a, W: WireSource + ?Sized>(
|
||||
} else {
|
||||
// Q: lazy projection — no Vec allocation per wire; NaN resets the segment chain.
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if wire.point_marker.is_some() {
|
||||
continue;
|
||||
}
|
||||
@@ -329,6 +335,9 @@ pub fn click_hit<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(triangle.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if let Some(depth) = triangle_ref_hit_depth(
|
||||
cursor,
|
||||
wire,
|
||||
@@ -345,6 +354,9 @@ pub fn click_hit<'a, W: WireSource + ?Sized>(
|
||||
}
|
||||
} else {
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if wire.fill_tris.is_empty() {
|
||||
continue;
|
||||
}
|
||||
@@ -381,6 +393,9 @@ pub fn click_hit<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(triangle.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if let Some(depth) = triangle_ref_hit_depth(
|
||||
cursor,
|
||||
wire,
|
||||
@@ -397,6 +412,9 @@ pub fn click_hit<'a, W: WireSource + ?Sized>(
|
||||
}
|
||||
} else {
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if wire.pick_tris.is_empty() {
|
||||
continue;
|
||||
}
|
||||
@@ -438,6 +456,9 @@ pub fn click_hit<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(glyph.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
let start = glyph.start as usize;
|
||||
let Some(vertices) = wire.text_verts.get(start..start + 6) else {
|
||||
continue;
|
||||
@@ -451,6 +472,9 @@ pub fn click_hit<'a, W: WireSource + ?Sized>(
|
||||
}
|
||||
} else {
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if wire.text_verts.is_empty() {
|
||||
continue;
|
||||
}
|
||||
@@ -516,6 +540,9 @@ pub fn click_hits_all<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(segment.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if wire.point_marker.is_some() {
|
||||
continue;
|
||||
}
|
||||
@@ -550,6 +577,9 @@ pub fn click_hits_all<'a, W: WireSource + ?Sized>(
|
||||
}));
|
||||
} else {
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if wire.point_marker.is_some() {
|
||||
continue;
|
||||
}
|
||||
@@ -593,6 +623,9 @@ pub fn click_hits_all<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(triangle.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if hits.iter().any(|&(_, name)| name == wire.name) {
|
||||
matched.insert(triangle.wire);
|
||||
continue;
|
||||
@@ -614,6 +647,9 @@ pub fn click_hits_all<'a, W: WireSource + ?Sized>(
|
||||
}
|
||||
} else {
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if wire.fill_tris.is_empty() || hits.iter().any(|&(_, name)| name == wire.name) {
|
||||
continue;
|
||||
}
|
||||
@@ -647,6 +683,9 @@ pub fn click_hits_all<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(triangle.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if hits.iter().any(|&(_, name)| name == wire.name) {
|
||||
matched.insert(triangle.wire);
|
||||
continue;
|
||||
@@ -668,6 +707,9 @@ pub fn click_hits_all<'a, W: WireSource + ?Sized>(
|
||||
}
|
||||
} else {
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if wire.pick_tris.is_empty() || hits.iter().any(|&(_, name)| name == wire.name) {
|
||||
continue;
|
||||
}
|
||||
@@ -697,6 +739,9 @@ pub fn click_hits_all<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(glyph.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if hits.iter().any(|&(_, name)| name == wire.name) {
|
||||
matched.insert(glyph.wire);
|
||||
continue;
|
||||
@@ -712,6 +757,9 @@ pub fn click_hits_all<'a, W: WireSource + ?Sized>(
|
||||
}
|
||||
} else {
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if wire.text_verts.is_empty() || hits.iter().any(|&(_, name)| name == wire.name) {
|
||||
continue;
|
||||
}
|
||||
@@ -1252,6 +1300,9 @@ fn indexed_box_crossing_hits<'a, W: WireSource + ?Sized>(
|
||||
// path below run identical code.
|
||||
let hit_name = |segment: &SegmentRef| -> Option<&'a str> {
|
||||
let wire = wires.source_wire(segment.wire)?;
|
||||
if wire.snap_only {
|
||||
return None;
|
||||
}
|
||||
let start = segment.start as usize;
|
||||
if start + 1 >= wire.points.len() {
|
||||
return None;
|
||||
@@ -1310,6 +1361,9 @@ fn indexed_box_crossing_hits<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(triangle.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if already(&wire_hit, triangle.wire) {
|
||||
continue;
|
||||
}
|
||||
@@ -1334,6 +1388,9 @@ fn indexed_box_crossing_hits<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(glyph.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if already(&wire_hit, glyph.wire) {
|
||||
continue;
|
||||
}
|
||||
@@ -1355,6 +1412,9 @@ fn indexed_box_crossing_hits<'a, W: WireSource + ?Sized>(
|
||||
|
||||
// Degenerate point-only wires have no indexed segment or surface primitive.
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if wire.points.len() >= 2
|
||||
|| !wire.fill_tris.is_empty()
|
||||
|| !wire.pick_tris.is_empty()
|
||||
@@ -1411,6 +1471,9 @@ pub fn poly_fence_hit<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(segment.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
let start = segment.start as usize;
|
||||
if start + 1 >= wire.points.len() || seen.contains(wire.name.as_str()) {
|
||||
continue;
|
||||
@@ -1442,6 +1505,9 @@ pub fn poly_fence_hit<'a, W: WireSource + ?Sized>(
|
||||
return out;
|
||||
}
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if wire.points.len() < 2 {
|
||||
continue;
|
||||
}
|
||||
@@ -1480,6 +1546,9 @@ fn indexed_polygon_crossing_hits<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(segment.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
let start = segment.start as usize;
|
||||
if start + 1 >= wire.points.len() {
|
||||
continue;
|
||||
@@ -1524,6 +1593,9 @@ fn indexed_polygon_crossing_hits<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(triangle.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if seen.contains(wire.name.as_str()) {
|
||||
continue;
|
||||
}
|
||||
@@ -1546,6 +1618,9 @@ fn indexed_polygon_crossing_hits<'a, W: WireSource + ?Sized>(
|
||||
let Some(wire) = wires.source_wire(glyph.wire) else {
|
||||
continue;
|
||||
};
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if seen.contains(wire.name.as_str()) {
|
||||
continue;
|
||||
}
|
||||
@@ -1565,6 +1640,9 @@ fn indexed_polygon_crossing_hits<'a, W: WireSource + ?Sized>(
|
||||
}
|
||||
}
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
if wire.points.len() >= 2
|
||||
|| !wire.fill_tris.is_empty()
|
||||
|| !wire.pick_tris.is_empty()
|
||||
@@ -1644,6 +1722,9 @@ pub fn box_hit<'a, W: WireSource + ?Sized>(
|
||||
let mut out = Vec::new();
|
||||
let mut seen = HashSet::default();
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
// Fallback: when wire has no line geometry (e.g. greek text emits
|
||||
// only fill_tris) treat the AABB rectangle as the hit-test shape
|
||||
// so low-LOD text stays selectable. See #19.
|
||||
@@ -1729,6 +1810,9 @@ pub fn box_hit<'a, W: WireSource + ?Sized>(
|
||||
let mut seen = HashSet::default();
|
||||
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
let name = wire.name.as_str();
|
||||
if disqualified.contains(name) {
|
||||
continue;
|
||||
@@ -1838,6 +1922,9 @@ pub fn poly_hit<'a, W: WireSource + ?Sized>(
|
||||
let mut out = Vec::new();
|
||||
let mut seen = HashSet::default();
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
// Same AABB fallback as `box_hit`: when a wire has no line
|
||||
// geometry (e.g. greek-LOD text emits only fill_tris) treat the
|
||||
// AABB rectangle as the hit-test shape so low-LOD text stays
|
||||
@@ -1925,6 +2012,9 @@ pub fn poly_hit<'a, W: WireSource + ?Sized>(
|
||||
let mut seen = HashSet::default();
|
||||
|
||||
for wire in wires.iter() {
|
||||
if wire.snap_only {
|
||||
continue;
|
||||
}
|
||||
let aabb_pts: Vec<[f32; 3]>;
|
||||
let empty_pts: [[f32; 3]; 0] = [];
|
||||
let pts: &[[f32; 3]] = if !wire.points.is_empty() {
|
||||
|
||||
@@ -551,6 +551,7 @@ pub fn frame_wire(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
@@ -316,6 +316,7 @@ pub fn apply_along(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
@@ -365,6 +366,7 @@ pub fn apply_along(
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
snap_only: false,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
|
||||
+12
-3
@@ -477,6 +477,14 @@ impl Ribbon {
|
||||
self.close_dropdown();
|
||||
}
|
||||
|
||||
/// Show `cmd` as the current item of a dropdown that mirrors a drawing
|
||||
/// setting, without running it.
|
||||
pub fn set_dropdown_current(&mut self, dropdown_id: &'static str, cmd: &'static str) {
|
||||
if self.last_cmd.get(dropdown_id) != Some(&cmd) {
|
||||
self.last_cmd.insert(dropdown_id, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
// ── View ──────────────────────────────────────────────────────────────
|
||||
|
||||
pub fn view(
|
||||
@@ -873,6 +881,7 @@ impl Ribbon {
|
||||
.iter()
|
||||
.map(|(cmd, label, item_icon)| {
|
||||
let is_current = *cmd == last_cmd;
|
||||
let disabled = widgets::is_disabled_item(cmd);
|
||||
let checkmark: Element<'_, Message> =
|
||||
crate::ui::icons::themed_check_cell(is_current);
|
||||
let icon_el: Element<Message> =
|
||||
@@ -884,7 +893,7 @@ impl Ribbon {
|
||||
.size(11)
|
||||
.wrapping(iced::advanced::text::Wrapping::None)
|
||||
.style(move |theme: &Theme| iced::widget::text::Style {
|
||||
color: (!is_current).then_some(
|
||||
color: (!is_current || disabled).then_some(
|
||||
theme
|
||||
.palette()
|
||||
.background
|
||||
@@ -899,10 +908,10 @@ impl Ribbon {
|
||||
.spacing(4)
|
||||
.align_y(iced::Center),
|
||||
)
|
||||
.on_press(Message::DropdownSelectItem {
|
||||
.on_press_maybe((!disabled).then_some(Message::DropdownSelectItem {
|
||||
dropdown_id: dd_id,
|
||||
cmd: *cmd,
|
||||
})
|
||||
}))
|
||||
.style(popup_row_style)
|
||||
.width(Fill)
|
||||
.padding([4, 10])
|
||||
|
||||
@@ -94,6 +94,11 @@ thread_local! {
|
||||
RefCell::new(HashMap::default());
|
||||
}
|
||||
|
||||
/// Dropdown items that report a state and cannot be picked.
|
||||
pub(super) fn is_disabled_item(cmd: &str) -> bool {
|
||||
cmd == "FRAMES3"
|
||||
}
|
||||
|
||||
fn ribbon_label_bounds(
|
||||
renderer: &iced::Renderer,
|
||||
label: &str,
|
||||
@@ -678,13 +683,18 @@ pub(super) fn render_small<'a>(
|
||||
container(make_icon(cur_icon, SMALL_ICON)).width(Length::Fixed(SMALL_W)),
|
||||
text(localized_label.clone()).size(10).wrapping(advanced_text::Wrapping::None),
|
||||
].spacing(3).align_y(iced::Center);
|
||||
// A state that is only shown (not chosen) opens the list instead.
|
||||
let face_btn = button(face)
|
||||
.on_press(Message::RibbonToolClick {
|
||||
tool_id: last.to_string(),
|
||||
event: ModuleEvent::Command(last.to_string()),
|
||||
.on_press(if is_disabled_item(last) {
|
||||
Message::ToggleRibbonDropdown(id.to_string())
|
||||
} else {
|
||||
Message::RibbonToolClick {
|
||||
tool_id: last.to_string(),
|
||||
event: ModuleEvent::Command(last.to_string()),
|
||||
}
|
||||
})
|
||||
.style(move |theme: &Theme, status| tool_btn_style(theme, active, status))
|
||||
.width(Length::Fixed(LABELED_SMALL_W)).height(ROW_H).padding([3, 4]);
|
||||
.width(Length::Shrink).height(ROW_H).padding([3, 4]);
|
||||
let arrow = button(container(icons::themed_arrow_down(8.0))
|
||||
.width(Fill).height(Fill).align_x(iced::Center).align_y(iced::Center))
|
||||
.on_press(Message::ToggleRibbonDropdown(id.to_string()))
|
||||
|
||||
Reference in new issue
Block a user