ocs_doc_api: layer CRUD, per-curve layer assignment, XDATA/XRECORD support, and bulk SetXDataMany

This commit is contained in:
Sebastian committed 2026-09-10 10:43:15 +02:00
1 parent b19992cbcb
commit 8bf5eac3fc
27 files changed
+3340 -181

No files matched your search

+34 -3
View File
@@ -21,8 +21,39 @@ The bridge converts these objects to the Rust DTOs and bincode 1.3 wire format,
sends `DocApiRequest { tab_id, bytes }`, and decodes `Result<Receipt, ApiError>`.
Host plugin API version 6 and document envelope version 1 are required.
For Rust plugins compiled against `ocs_doc_api` with the `doc_api_host` feature,
use the `doc_api_for_host` helper to build a typed `DocApi` from any
`ocs_plugin_api::host::HostApi` that exposes a `PluginRequestSender`
(out-of-process / worker-thread hosts):
```rust
use ocs_doc_api::doc_api_for_host;
use ocs_plugin_api::host::HostApi;
fn on_dispatch(host: &mut dyn HostApi) -> Option<()> {
let doc_api = doc_api_for_host(host)?;
let doc = doc_api.document(host.tab_id());
let cube = doc.solids().create_cuboid([0.0; 3], [10.0; 3]).ok()?;
// ...
Some(())
}
```
In-process plugins should use `DocApi::in_process(backend, tab_id)` with a
concrete `DocApiBackend`; `doc_api_for_host` returns `None` for hosts that do not
expose a `PluginRequestSender`.
Decode receipt outcomes as `{"NewId": 42}` or `{"NewIds": [42, 43]}` and query
results as externally tagged dictionaries such as `{"Volume": 12.5}`. The facade
unwraps these into typed handles or values. The bridge must raise an exception
for an error response. Transport binding determines the tab; requesting another
tab or combining typed handles from different documents raises an error.
unwraps these into typed handles or values. Layer results use `{"Layers": [...]}`
and `{"EntityLayer": "WALLS"}`. Layer properties (`LayerInfo`, `LayerFlags`,
`Color`, `LineWeight`) appear as plain dictionaries in operation payloads, e.g.
`{"CreateLayer": {"name": "Walls", "flags": {"frozen": false, "locked": false,
"frozen_in_new_viewport": false, "off": false}, "color": {"Index": 7},
"line_type": "Continuous", "line_weight": {"Default": null},
"plot_style": "", "is_plottable": true}}`.
XDATA and XRECORD payloads appear as nested externally tagged dictionaries
(e.g. `{"XData": {"application_name": ..., "values": [...]}}` or
`{"XRecord": {"name": ..., "entries": [...]}}`). The bridge must raise an
exception for an error response. Transport binding determines the tab; requesting
another tab or combining typed handles from different documents raises an error.
@@ -36,6 +36,12 @@ class Entity:
def delete(self):
self._doc._apply_op({"Delete": {"id": self.id}})
def layer(self):
return self._doc._apply_query({"GetEntityLayer": {"id": self.id}})
def set_layer(self, layer):
self._doc._apply_op({"SetEntityLayer": {"id": self.id, "layer": layer}})
'''
DOCUMENT = '''
@@ -79,6 +85,18 @@ class Document:
def curves(self): return Curves(self)
def entities(self): return Entities(self)
def layers(self):
return self._apply_query({"ListLayers": {}})
def create_layer(self, info):
self._apply_op({"CreateLayer": info})
def update_layer(self, name, info):
self._apply_op({"UpdateLayer": {"name": name, "info": info}})
def delete_layer(self, name):
self._apply_op({"DeleteLayer": {"name": name}})
@dataclass
class DocApi:
_transport: Any