diff --git a/locales/ar-SA/opencadstudio.ftl b/locales/ar-SA/opencadstudio.ftl index 7add46a5d..904deb79d 100644 --- a/locales/ar-SA/opencadstudio.ftl +++ b/locales/ar-SA/opencadstudio.ftl @@ -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 يجري ملء السمات... diff --git a/locales/bg-BG/opencadstudio.ftl b/locales/bg-BG/opencadstudio.ftl index c7fb5e456..882902324 100644 --- a/locales/bg-BG/opencadstudio.ftl +++ b/locales/bg-BG/opencadstudio.ftl @@ -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 Попълване на атрибути... diff --git a/locales/cs-CZ/opencadstudio.ftl b/locales/cs-CZ/opencadstudio.ftl index c585c046b..b14d1ed37 100644 --- a/locales/cs-CZ/opencadstudio.ftl +++ b/locales/cs-CZ/opencadstudio.ftl @@ -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ů... diff --git a/locales/de-DE/opencadstudio.ftl b/locales/de-DE/opencadstudio.ftl index 3b2fe629e..9fb3f67c1 100644 --- a/locales/de-DE/opencadstudio.ftl +++ b/locales/de-DE/opencadstudio.ftl @@ -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... diff --git a/locales/el-GR/opencadstudio.ftl b/locales/el-GR/opencadstudio.ftl index e3cb58071..4368f1a98 100644 --- a/locales/el-GR/opencadstudio.ftl +++ b/locales/el-GR/opencadstudio.ftl @@ -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 Συμπλήρωση χαρακτηριστικών... diff --git a/locales/en-US/opencadstudio.ftl b/locales/en-US/opencadstudio.ftl index 8fba57187..913a3fb44 100644 --- a/locales/en-US/opencadstudio.ftl +++ b/locales/en-US/opencadstudio.ftl @@ -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... diff --git a/locales/es-ES/opencadstudio.ftl b/locales/es-ES/opencadstudio.ftl index 6d5500dae..610ed1cc0 100644 --- a/locales/es-ES/opencadstudio.ftl +++ b/locales/es-ES/opencadstudio.ftl @@ -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... diff --git a/locales/fi-FI/opencadstudio.ftl b/locales/fi-FI/opencadstudio.ftl index da2de7a81..cadc87848 100644 --- a/locales/fi-FI/opencadstudio.ftl +++ b/locales/fi-FI/opencadstudio.ftl @@ -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ä... diff --git a/locales/fr-FR/opencadstudio.ftl b/locales/fr-FR/opencadstudio.ftl index 899c9b245..fd2ca452b 100644 --- a/locales/fr-FR/opencadstudio.ftl +++ b/locales/fr-FR/opencadstudio.ftl @@ -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... diff --git a/locales/hi-IN/opencadstudio.ftl b/locales/hi-IN/opencadstudio.ftl index ea5c4c076..fada860e7 100644 --- a/locales/hi-IN/opencadstudio.ftl +++ b/locales/hi-IN/opencadstudio.ftl @@ -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 गुण भरना ... diff --git a/locales/hu-HU/opencadstudio.ftl b/locales/hu-HU/opencadstudio.ftl index d59408b22..b396047f1 100644 --- a/locales/hu-HU/opencadstudio.ftl +++ b/locales/hu-HU/opencadstudio.ftl @@ -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... diff --git a/locales/it-IT/opencadstudio.ftl b/locales/it-IT/opencadstudio.ftl index c66383d3f..869962176 100644 --- a/locales/it-IT/opencadstudio.ftl +++ b/locales/it-IT/opencadstudio.ftl @@ -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... diff --git a/locales/ja-JP/opencadstudio.ftl b/locales/ja-JP/opencadstudio.ftl index 2cbbdba5b..fee586634 100644 --- a/locales/ja-JP/opencadstudio.ftl +++ b/locales/ja-JP/opencadstudio.ftl @@ -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 属性を入力中... diff --git a/locales/ko-KR/opencadstudio.ftl b/locales/ko-KR/opencadstudio.ftl index fcb1ba020..ced37f07c 100644 --- a/locales/ko-KR/opencadstudio.ftl +++ b/locales/ko-KR/opencadstudio.ftl @@ -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 채우기 속성... diff --git a/locales/nl-NL/opencadstudio.ftl b/locales/nl-NL/opencadstudio.ftl index bbfb0bbb2..eba2b66cc 100644 --- a/locales/nl-NL/opencadstudio.ftl +++ b/locales/nl-NL/opencadstudio.ftl @@ -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... diff --git a/locales/pl-PL/opencadstudio.ftl b/locales/pl-PL/opencadstudio.ftl index 5f625c4de..0180fa543 100644 --- a/locales/pl-PL/opencadstudio.ftl +++ b/locales/pl-PL/opencadstudio.ftl @@ -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... diff --git a/locales/pt-BR/opencadstudio.ftl b/locales/pt-BR/opencadstudio.ftl index d6ecda397..f8fc5f572 100644 --- a/locales/pt-BR/opencadstudio.ftl +++ b/locales/pt-BR/opencadstudio.ftl @@ -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... diff --git a/locales/ru-RU/opencadstudio.ftl b/locales/ru-RU/opencadstudio.ftl index 9235e6a4d..df3813448 100644 --- a/locales/ru-RU/opencadstudio.ftl +++ b/locales/ru-RU/opencadstudio.ftl @@ -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 Наполнение атрибутов... diff --git a/locales/tr-TR/opencadstudio.ftl b/locales/tr-TR/opencadstudio.ftl index 49c6d8870..90eb67861 100644 --- a/locales/tr-TR/opencadstudio.ftl +++ b/locales/tr-TR/opencadstudio.ftl @@ -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... diff --git a/locales/zh-CN/opencadstudio.ftl b/locales/zh-CN/opencadstudio.ftl index 6780264a2..b8580356a 100644 --- a/locales/zh-CN/opencadstudio.ftl +++ b/locales/zh-CN/opencadstudio.ftl @@ -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 正在填充属性... diff --git a/locales/zh-TW/opencadstudio.ftl b/locales/zh-TW/opencadstudio.ftl index 810b88978..dfba68e70 100644 --- a/locales/zh-TW/opencadstudio.ftl +++ b/locales/zh-TW/opencadstudio.ftl @@ -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 正在填充屬性... diff --git a/src/app/commands/mod.rs b/src/app/commands/mod.rs index 4f819ae37..6cde08be6 100644 --- a/src/app/commands/mod.rs +++ b/src/app/commands/mod.rs @@ -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", diff --git a/src/app/commands/styleprops.rs b/src/app/commands/styleprops.rs index 13f79e8c4..bccc07f54 100644 --- a/src/app/commands/styleprops.rs +++ b/src/app/commands/styleprops.rs @@ -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 — 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!( diff --git a/src/app/settings.rs b/src/app/settings.rs index 9823e0aac..f4a62191c 100644 --- a/src/app/settings.rs +++ b/src/app/settings.rs @@ -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, diff --git a/src/app/update/file.rs b/src/app/update/file.rs index 6a49b66d4..8a8f4ea93 100644 --- a/src/app/update/file.rs +++ b/src/app/update/file.rs @@ -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; diff --git a/src/app/update/mod.rs b/src/app/update/mod.rs index f84c315a4..b25942360 100644 --- a/src/app/update/mod.rs +++ b/src/app/update/mod.rs @@ -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 { if let Some(tab) = self.tabs.get(self.active_tab) { crate::entities::common::set_unit_context( diff --git a/src/app/update/viewport.rs b/src/app/update/viewport.rs index bb34d867c..00990c1cd 100644 --- a/src/app/update/viewport.rs +++ b/src/app/update/viewport.rs @@ -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, diff --git a/src/entities/dimension.rs b/src/entities/dimension.rs index a4b105512..c1d50ca53 100644 --- a/src/entities/dimension.rs +++ b/src/entities/dimension.rs @@ -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, diff --git a/src/entities/leader.rs b/src/entities/leader.rs index 7530f8ec0..717ee110f 100644 --- a/src/entities/leader.rs +++ b/src/entities/leader.rs @@ -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, diff --git a/src/entities/multileader.rs b/src/entities/multileader.rs index ef3d7fd8a..74de8d97a 100644 --- a/src/entities/multileader.rs +++ b/src/entities/multileader.rs @@ -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, diff --git a/src/entities/raster_image.rs b/src/entities/raster_image.rs index d7fdcd8b0..87a51dab4 100644 --- a/src/entities/raster_image.rs +++ b/src/entities/raster_image.rs @@ -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> { - 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 { 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() diff --git a/src/entities/table.rs b/src/entities/table.rs index c5250ca64..e4634e920 100644 --- a/src/entities/table.rs +++ b/src/entities/table.rs @@ -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, diff --git a/src/entities/underlay.rs b/src/entities/underlay.rs index 2570093d7..29f12d15b 100644 --- a/src/entities/underlay.rs +++ b/src/entities/underlay.rs @@ -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![], }) } diff --git a/src/locale_catalog.rs b/src/locale_catalog.rs index d2150f076..107e318c5 100644 --- a/src/locale_catalog.rs +++ b/src/locale_catalog.rs @@ -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")), diff --git a/src/modules/annotate/aligned_dim.rs b/src/modules/annotate/aligned_dim.rs index aba871423..313f16e92 100644 --- a/src/modules/annotate/aligned_dim.rs +++ b/src/modules/annotate/aligned_dim.rs @@ -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, diff --git a/src/modules/annotate/angular_dim.rs b/src/modules/annotate/angular_dim.rs index 4e45d342c..d26a84dec 100644 --- a/src/modules/annotate/angular_dim.rs +++ b/src/modules/annotate/angular_dim.rs @@ -1249,6 +1249,7 @@ fn preview_wire(points: Vec) -> 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, diff --git a/src/modules/annotate/data_link.rs b/src/modules/annotate/data_link.rs index cbb68a71e..00472d3bd 100644 --- a/src/modules/annotate/data_link.rs +++ b/src/modules/annotate/data_link.rs @@ -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, diff --git a/src/modules/annotate/diameter_dim.rs b/src/modules/annotate/diameter_dim.rs index 6ae3a0bc6..c9155b8c1 100644 --- a/src/modules/annotate/diameter_dim.rs +++ b/src/modules/annotate/diameter_dim.rs @@ -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, diff --git a/src/modules/annotate/dim_baseline.rs b/src/modules/annotate/dim_baseline.rs index 63ffdf79f..06ed14422 100644 --- a/src/modules/annotate/dim_baseline.rs +++ b/src/modules/annotate/dim_baseline.rs @@ -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, diff --git a/src/modules/annotate/jogged_radius_dim.rs b/src/modules/annotate/jogged_radius_dim.rs index fca5da971..f022f2657 100644 --- a/src/modules/annotate/jogged_radius_dim.rs +++ b/src/modules/annotate/jogged_radius_dim.rs @@ -480,6 +480,7 @@ fn preview_wire(points: Vec) -> 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, diff --git a/src/modules/annotate/leader_cmd.rs b/src/modules/annotate/leader_cmd.rs index 7d81c3a88..f7894581c 100644 --- a/src/modules/annotate/leader_cmd.rs +++ b/src/modules/annotate/leader_cmd.rs @@ -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, diff --git a/src/modules/annotate/linear_dim.rs b/src/modules/annotate/linear_dim.rs index 27149b707..31a3df457 100644 --- a/src/modules/annotate/linear_dim.rs +++ b/src/modules/annotate/linear_dim.rs @@ -561,6 +561,7 @@ fn preview_wire(points: Vec) -> 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, diff --git a/src/modules/annotate/mleader_cmd.rs b/src/modules/annotate/mleader_cmd.rs index 11904ee88..262010a0d 100644 --- a/src/modules/annotate/mleader_cmd.rs +++ b/src/modules/annotate/mleader_cmd.rs @@ -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, diff --git a/src/modules/annotate/mleader_edit.rs b/src/modules/annotate/mleader_edit.rs index 091aa538e..ac78d9926 100644 --- a/src/modules/annotate/mleader_edit.rs +++ b/src/modules/annotate/mleader_edit.rs @@ -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, diff --git a/src/modules/annotate/ordinate_dim.rs b/src/modules/annotate/ordinate_dim.rs index 78f707c57..0f5fba809 100644 --- a/src/modules/annotate/ordinate_dim.rs +++ b/src/modules/annotate/ordinate_dim.rs @@ -289,6 +289,7 @@ fn preview_wire(points: Vec) -> 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, diff --git a/src/modules/annotate/radius_dim.rs b/src/modules/annotate/radius_dim.rs index 639c97998..737ae0bd3 100644 --- a/src/modules/annotate/radius_dim.rs +++ b/src/modules/annotate/radius_dim.rs @@ -350,6 +350,7 @@ fn preview_wire(points: Vec) -> 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, diff --git a/src/modules/annotate/table_cmd.rs b/src/modules/annotate/table_cmd.rs index 0ad146b04..7193b5397 100644 --- a/src/modules/annotate/table_cmd.rs +++ b/src/modules/annotate/table_cmd.rs @@ -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, diff --git a/src/modules/annotate/tolerance_cmd.rs b/src/modules/annotate/tolerance_cmd.rs index 5b7d67b3c..d884253b4 100644 --- a/src/modules/annotate/tolerance_cmd.rs +++ b/src/modules/annotate/tolerance_cmd.rs @@ -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, diff --git a/src/modules/draw/draw/attdef.rs b/src/modules/draw/draw/attdef.rs index 416b415f4..053ffe8af 100644 --- a/src/modules/draw/draw/attdef.rs +++ b/src/modules/draw/draw/attdef.rs @@ -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, diff --git a/src/modules/draw/draw/mline.rs b/src/modules/draw/draw/mline.rs index c84d4bf3e..51306e6d9 100644 --- a/src/modules/draw/draw/mline.rs +++ b/src/modules/draw/draw/mline.rs @@ -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, diff --git a/src/modules/draw/draw/raster_image.rs b/src/modules/draw/draw/raster_image.rs index eb5b62959..63a69e202 100644 --- a/src/modules/draw/draw/raster_image.rs +++ b/src/modules/draw/draw/raster_image.rs @@ -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, diff --git a/src/modules/draw/draw/ray.rs b/src/modules/draw/draw/ray.rs index 700f50643..bc2bf4eb7 100644 --- a/src/modules/draw/draw/ray.rs +++ b/src/modules/draw/draw/ray.rs @@ -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, diff --git a/src/modules/draw/inquiry/area.rs b/src/modules/draw/inquiry/area.rs index 70daa9b6a..6a33bc06a 100644 --- a/src/modules/draw/inquiry/area.rs +++ b/src/modules/draw/inquiry/area.rs @@ -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, diff --git a/src/modules/draw/inquiry/dist.rs b/src/modules/draw/inquiry/dist.rs index 2454ee470..8592655b6 100644 --- a/src/modules/draw/inquiry/dist.rs +++ b/src/modules/draw/inquiry/dist.rs @@ -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, diff --git a/src/modules/draw/inquiry/measuregeom.rs b/src/modules/draw/inquiry/measuregeom.rs index ff3a8dd3b..11502eccc 100644 --- a/src/modules/draw/inquiry/measuregeom.rs +++ b/src/modules/draw/inquiry/measuregeom.rs @@ -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, diff --git a/src/modules/draw/modify/trim.rs b/src/modules/draw/modify/trim.rs index baf068f25..f8c7ebf96 100644 --- a/src/modules/draw/modify/trim.rs +++ b/src/modules/draw/modify/trim.rs @@ -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, diff --git a/src/modules/insert/mod.rs b/src/modules/insert/mod.rs index 0e3393464..d75eec575 100644 --- a/src/modules/insert/mod.rs +++ b/src/modules/insert/mod.rs @@ -63,9 +63,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", }, diff --git a/src/modules/model/primitive_cmd.rs b/src/modules/model/primitive_cmd.rs index c707b9531..8ccdaeb61 100644 --- a/src/modules/model/primitive_cmd.rs +++ b/src/modules/model/primitive_cmd.rs @@ -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, diff --git a/src/modules/view/plot_window.rs b/src/modules/view/plot_window.rs index 896985e39..cca291c52 100644 --- a/src/modules/view/plot_window.rs +++ b/src/modules/view/plot_window.rs @@ -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, diff --git a/src/modules/view/zoom_window.rs b/src/modules/view/zoom_window.rs index 35fefe986..2ac31bd98 100644 --- a/src/modules/view/zoom_window.rs +++ b/src/modules/view/zoom_window.rs @@ -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, diff --git a/src/scene/cache/block_cache.rs b/src/scene/cache/block_cache.rs index db59d9d93..5af7d3cd5 100644 --- a/src/scene/cache/block_cache.rs +++ b/src/scene/cache/block_cache.rs @@ -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, diff --git a/src/scene/convert/tess.rs b/src/scene/convert/tess.rs index b3ce78917..24678504d 100644 --- a/src/scene/convert/tess.rs +++ b/src/scene/convert/tess.rs @@ -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, diff --git a/src/scene/convert/tessellate.rs b/src/scene/convert/tessellate.rs index 3c9e261b1..a75dcbc04 100644 --- a/src/scene/convert/tessellate.rs +++ b/src/scene/convert/tessellate.rs @@ -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, diff --git a/src/scene/frame.rs b/src/scene/frame.rs index 729215155..dbb730f7b 100644 --- a/src/scene/frame.rs +++ b/src/scene/frame.rs @@ -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 { + 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 { 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::().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 { 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 { pub(crate) fn entity_kind(entity: &EntityType) -> Option { 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(_)), diff --git a/src/scene/model/wire_model.rs b/src/scene/model/wire_model.rs index 6f921505c..dad7fef4d 100644 --- a/src/scene/model/wire_model.rs +++ b/src/scene/model/wire_model.rs @@ -506,6 +506,9 @@ pub struct WireModel { pub depth_override: Option, /// 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, diff --git a/src/scene/pick/hit_test.rs b/src/scene/pick/hit_test.rs index cda978265..dc4754370 100644 --- a/src/scene/pick/hit_test.rs +++ b/src/scene/pick/hit_test.rs @@ -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() { diff --git a/src/scene/pick/xclip.rs b/src/scene/pick/xclip.rs index c1199f1ad..f59666954 100644 --- a/src/scene/pick/xclip.rs +++ b/src/scene/pick/xclip.rs @@ -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, diff --git a/src/scene/text/complex_lt.rs b/src/scene/text/complex_lt.rs index 0cac9c0f2..302f8a2ba 100644 --- a/src/scene/text/complex_lt.rs +++ b/src/scene/text/complex_lt.rs @@ -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, diff --git a/src/ui/ribbon/mod.rs b/src/ui/ribbon/mod.rs index b5b8e6f6f..1aea6eccb 100644 --- a/src/ui/ribbon/mod.rs +++ b/src/ui/ribbon/mod.rs @@ -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 = @@ -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]) diff --git a/src/ui/ribbon/widgets.rs b/src/ui/ribbon/widgets.rs index 83c90bd97..c5ea6acfa 100644 --- a/src/ui/ribbon/widgets.rs +++ b/src/ui/ribbon/widgets.rs @@ -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()))