Flatten SOX slot registry through full base-type chain
Types with intermediate parents (e.g. ontrolOx::PushButtonImage -> Widget -> Service -> Component) only got Component + own slots, so config/runtime streams were decoded against the wrong slot list and x/y/imageFileName came out wrong. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -8,7 +8,7 @@ so later rebinding would only ever be seen by the module that did it.
|
|||||||
import configparser
|
import configparser
|
||||||
import os
|
import os
|
||||||
|
|
||||||
VERSION = "0.0.0.123"
|
VERSION = "0.0.0.124"
|
||||||
PROPERTIES_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "editor.properties")
|
PROPERTIES_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "editor.properties")
|
||||||
DEFAULT_GRID_SIZE = 10
|
DEFAULT_GRID_SIZE = 10
|
||||||
DEFAULT_ADD_TIMESTAMP = True
|
DEFAULT_ADD_TIMESTAMP = True
|
||||||
|
|||||||
+28
-44
@@ -87,54 +87,39 @@ class DeviceSession:
|
|||||||
def _load_slot_registry(self, parts):
|
def _load_slot_registry(self, parts):
|
||||||
"""Builds slot_registry from kit manifests for the device's schema."""
|
"""Builds slot_registry from kit manifests for the device's schema."""
|
||||||
registry = {}
|
registry = {}
|
||||||
base_slots = []
|
own_slots = {} # "kit::Type" -> declared slots
|
||||||
|
bases = {} # "kit::Type" -> "kit::Base" or None
|
||||||
for kit_id, part in enumerate(parts):
|
for kit_id, part in enumerate(parts):
|
||||||
kit_name = part.name
|
kit_name = part.name
|
||||||
checksum = part.checksum
|
checksum = part.checksum
|
||||||
manifest = schema.find_manifest(kit_name, checksum)
|
manifest = schema.find_manifest(kit_name, checksum)
|
||||||
if manifest is None:
|
if manifest is None:
|
||||||
continue
|
continue
|
||||||
if kit_name == "sys":
|
self._register_kit_types(registry, kit_id, kit_name, manifest,
|
||||||
base_slots = self._extract_component_base_slots(manifest)
|
own_slots, bases)
|
||||||
self._register_kit_types(registry, kit_id, kit_name, manifest)
|
# Flatten each type's slots through its whole base chain (e.g.
|
||||||
# Prepend inherited Component base slots (meta, etc.) to every type,
|
# Component -> Service -> ontrolOx::Widget -> PushButtonImage), then
|
||||||
# then renumber IDs to match the wire slot index (positional in the
|
# renumber IDs to match the wire slot index (positional in the
|
||||||
# flattened inherited + own list — see sedona Type.java resolveSlots).
|
# flattened inherited + own list — see sedona Type.java resolveSlots).
|
||||||
if base_slots:
|
for key in registry:
|
||||||
for key in registry:
|
qname = self.sox_client.type_name_map[key]
|
||||||
existing_names = {s["name"] for s in registry[key]}
|
chain = []
|
||||||
for bs in base_slots:
|
seen = set()
|
||||||
if bs["name"] not in existing_names:
|
t = qname
|
||||||
registry[key].insert(0, dict(bs))
|
while t and t not in seen and t in own_slots:
|
||||||
for i, slot in enumerate(registry[key]):
|
seen.add(t)
|
||||||
slot["id"] = i
|
chain.append(t)
|
||||||
|
t = bases.get(t)
|
||||||
|
flat = []
|
||||||
|
for t in reversed(chain):
|
||||||
|
flat.extend(dict(s) for s in own_slots[t])
|
||||||
|
for i, slot in enumerate(flat):
|
||||||
|
slot["id"] = i
|
||||||
|
registry[key] = flat
|
||||||
self.sox_client.slot_registry = registry
|
self.sox_client.slot_registry = registry
|
||||||
|
|
||||||
def _extract_component_base_slots(self, manifest):
|
def _register_kit_types(self, registry, kit_id, kit_name, manifest,
|
||||||
"""Extracts base slots from sys::Component that all types inherit."""
|
own_slots, bases):
|
||||||
for type_elem in manifest.iter("type"):
|
|
||||||
if type_elem.get("name") == "Component":
|
|
||||||
slots = []
|
|
||||||
for slot_elem in type_elem.findall("slot"):
|
|
||||||
slot_name = slot_elem.get("name", "")
|
|
||||||
slot_id = int(slot_elem.get("id", "-1"))
|
|
||||||
slot_type = slot_elem.get("type", "int")
|
|
||||||
flags_str = slot_elem.get("flags", "")
|
|
||||||
slots.append({
|
|
||||||
"name": slot_name,
|
|
||||||
"id": slot_id,
|
|
||||||
"type_name": slot_type,
|
|
||||||
"is_config": "c" in flags_str or "p" in flags_str,
|
|
||||||
"is_runtime": "r" in flags_str,
|
|
||||||
"is_action": "a" in flags_str,
|
|
||||||
"is_operator": "o" in flags_str,
|
|
||||||
"is_as_str": slot_type == "Str",
|
|
||||||
"is_prop": "a" not in flags_str,
|
|
||||||
})
|
|
||||||
return slots
|
|
||||||
return []
|
|
||||||
|
|
||||||
def _register_kit_types(self, registry, kit_id, kit_name, manifest):
|
|
||||||
root = manifest
|
root = manifest
|
||||||
for type_elem in root.iter("type"):
|
for type_elem in root.iter("type"):
|
||||||
type_name = type_elem.get("name", "")
|
type_name = type_elem.get("name", "")
|
||||||
@@ -165,6 +150,8 @@ class DeviceSession:
|
|||||||
})
|
})
|
||||||
registry[(kit_id, type_id_val)] = slots
|
registry[(kit_id, type_id_val)] = slots
|
||||||
full_name = f"{kit_name}::{type_name}"
|
full_name = f"{kit_name}::{type_name}"
|
||||||
|
own_slots[full_name] = slots
|
||||||
|
bases[full_name] = type_elem.get("base") or None
|
||||||
self.sox_client.type_name_map[(kit_id, type_id_val)] = full_name
|
self.sox_client.type_name_map[(kit_id, type_id_val)] = full_name
|
||||||
# update type_name on any cached component of this type
|
# update type_name on any cached component of this type
|
||||||
for c in self.sox_client.cache:
|
for c in self.sox_client.cache:
|
||||||
@@ -368,16 +355,13 @@ class DeviceSession:
|
|||||||
|
|
||||||
def _slot_name_by_id(self, kit_id, type_id_val, slot_id):
|
def _slot_name_by_id(self, kit_id, type_id_val, slot_id):
|
||||||
# SOX links use absolute slot IDs across the full inheritance chain.
|
# SOX links use absolute slot IDs across the full inheritance chain.
|
||||||
# final_components_registry has correctly resolved absolute IDs;
|
|
||||||
# the per-type slot_registry only stores local (per-type) IDs
|
|
||||||
# which are wrong for types with intermediate parents.
|
|
||||||
type_name = self.sox_client.type_name_map.get((kit_id, type_id_val))
|
type_name = self.sox_client.type_name_map.get((kit_id, type_id_val))
|
||||||
if type_name and type_name in app_state.final_components_registry:
|
if type_name and type_name in app_state.final_components_registry:
|
||||||
for s in app_state.final_components_registry[type_name]:
|
for s in app_state.final_components_registry[type_name]:
|
||||||
if s["slot_id"] == slot_id:
|
if s["slot_id"] == slot_id:
|
||||||
return s["name"]
|
return s["name"]
|
||||||
# Fallback to slot_registry (local IDs — wrong for inherited types,
|
# Fallback to slot_registry (flattened through the base chain, so
|
||||||
# but keeps things working when the schema registry is not yet loaded)
|
# its IDs are absolute too)
|
||||||
slots = self.sox_client.slot_registry.get((kit_id, type_id_val))
|
slots = self.sox_client.slot_registry.get((kit_id, type_id_val))
|
||||||
if slots:
|
if slots:
|
||||||
for s in slots:
|
for s in slots:
|
||||||
|
|||||||
Reference in New Issue
Block a user