Merge pull request #1747 from schoeller/reference_only_entities

Reference-only entities (plugin API v9): a scene-scoped, in-memory
designation for plugin-owned display geometry, plus HostNotification
dispatch to native plugins so they can re-mark on DocumentOpened.

Resolves the new DeltaSnapshot site in block_editor.rs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Hakan SevenandClaude Opus 5.5 committed 2026-10-14 23:46:42 +03:00
commit 68330ce39e
40 files changed
+1977 -85

No files matched your search

+4
View File
@@ -2276,6 +2276,10 @@ impl OpenCADStudio {
.set(crate::app::OPEN_PHASE_FINALIZING, 10000, 1, 1);
}
self.opening.take();
// The document and its derived caches have settled: mark the tab's
// generation so the next message boundary announces `DocumentOpened`
// to native plugins exactly once for this load (API v9).
self.tabs[i].note_document_loaded();
// The tab list just changed (and the active tab with it): remember
// it for the next boot's restore flow (web session memory).
#[cfg(target_arch = "wasm32")]
+38
View File
@@ -312,6 +312,11 @@ impl OpenCADStudio {
self.last_plugin_selection = Some(key);
let handles = self.tabs[i].scene.selected_handles_in_order();
crate::plugin::v4_support::publish_selection_changed_v4(tab_id, handles.clone());
// Same guarded boundary, second surface (API v9): the plain
// `SelectionChanged` reaches every loaded native plugin through
// `BuiltinPlugin::on_notification`, without a shared-view
// subscription.
crate::plugin::v4_support::publish_selection_changed(handles.clone());
self.control_record_selection_event(&handles);
}
@@ -331,6 +336,35 @@ impl OpenCADStudio {
self.last_plugin_document = Some(key);
crate::plugin::v4_support::publish_drawing_changed(tab.id, tab.scene.geometry_epoch);
crate::plugin::v4_support::publish_document_view_v4(tab.id, &tab.scene.document);
// Same guarded boundary, second surface (API v9): the plain
// `DocumentChanged` carries the settled geometry epoch to every
// loaded native plugin through `BuiltinPlugin::on_notification`.
crate::plugin::v4_support::publish_document_changed(tab.scene.geometry_epoch);
}
/// Announce that a whole document became resident in the active tab —
/// opened from file, created from a template, or loaded by a system open
/// (API v9). Keyed on `(tab id, document generation)`, which changes only
/// when a tab's content is wholesale replaced, so an edit can never fire
/// it twice and a reload fires it exactly once. Part of the same
/// post-message boundary as the selection and document dispatches: runs
/// after the mutation settles and pending history scopes closed, never
/// inside history replay or interactive picking.
#[cfg(not(target_arch = "wasm32"))]
pub(super) fn notify_plugins_document_opened(&mut self) {
if self.active_tab >= self.tabs.len() {
return;
}
let i = self.active_tab;
if self.tabs[i].is_start {
return;
}
let key = (self.tabs[i].id, self.tabs[i].document_generation);
if self.last_plugin_document_opened == Some(key) {
return;
}
self.last_plugin_document_opened = Some(key);
crate::plugin::v4_support::publish_document_opened(self.tabs[i].id);
}
pub fn update(&mut self, msg: Message) -> Task<Message> {
@@ -577,6 +611,10 @@ impl OpenCADStudio {
self.notify_plugins_selection_changed();
#[cfg(not(target_arch = "wasm32"))]
self.notify_plugins_document_changed();
// A message may also have installed a whole document into a tab (file
// open, template new); announce it on the same boundary (API v9).
#[cfg(not(target_arch = "wasm32"))]
self.notify_plugins_document_opened();
// OTRACK acquires tracking points only while a command or grip drag is
// running; drop them once neither is active so the temporary tracking
// points / vectors disappear when the command ends (issue #64). A grip
+4
View File
@@ -736,6 +736,9 @@ impl OpenCADStudio {
bounds,
candidate_handles.as_ref(),
));
// Reference-only entities (API v9) are plugin-owned display geometry:
// a box/window selection must not pick them.
handles.retain(|h| !scene.is_reference_only(*h));
timing.hit = elapsed(t_hit);
(handles, timing)
}
@@ -5308,6 +5311,7 @@ properties={:.1}ms picked={}",
.into_iter()
.filter_map(|s| Scene::handle_from_wire_name(s))
.filter(|&h| self.tabs[i].scene.passes_selection_filter(h))
.filter(|&h| !self.tabs[i].scene.is_reference_only(h))
.collect();
if cands.len() >= 2 {
// Overlap: open the list box at the cursor.