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 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")
|
||||
DEFAULT_GRID_SIZE = 10
|
||||
DEFAULT_ADD_TIMESTAMP = True
|
||||
|
||||
+26
-42
@@ -87,54 +87,39 @@ class DeviceSession:
|
||||
def _load_slot_registry(self, parts):
|
||||
"""Builds slot_registry from kit manifests for the device's schema."""
|
||||
registry = {}
|
||||
base_slots = []
|
||||
own_slots = {} # "kit::Type" -> declared slots
|
||||
bases = {} # "kit::Type" -> "kit::Base" or None
|
||||
for kit_id, part in enumerate(parts):
|
||||
kit_name = part.name
|
||||
checksum = part.checksum
|
||||
manifest = schema.find_manifest(kit_name, checksum)
|
||||
if manifest is None:
|
||||
continue
|
||||
if kit_name == "sys":
|
||||
base_slots = self._extract_component_base_slots(manifest)
|
||||
self._register_kit_types(registry, kit_id, kit_name, manifest)
|
||||
# Prepend inherited Component base slots (meta, etc.) to every type,
|
||||
# then renumber IDs to match the wire slot index (positional in the
|
||||
self._register_kit_types(registry, kit_id, kit_name, manifest,
|
||||
own_slots, bases)
|
||||
# Flatten each type's slots through its whole base chain (e.g.
|
||||
# Component -> Service -> ontrolOx::Widget -> PushButtonImage), then
|
||||
# renumber IDs to match the wire slot index (positional in the
|
||||
# flattened inherited + own list — see sedona Type.java resolveSlots).
|
||||
if base_slots:
|
||||
for key in registry:
|
||||
existing_names = {s["name"] for s in registry[key]}
|
||||
for bs in base_slots:
|
||||
if bs["name"] not in existing_names:
|
||||
registry[key].insert(0, dict(bs))
|
||||
for i, slot in enumerate(registry[key]):
|
||||
qname = self.sox_client.type_name_map[key]
|
||||
chain = []
|
||||
seen = set()
|
||||
t = qname
|
||||
while t and t not in seen and t in own_slots:
|
||||
seen.add(t)
|
||||
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
|
||||
|
||||
def _extract_component_base_slots(self, manifest):
|
||||
"""Extracts base slots from sys::Component that all types inherit."""
|
||||
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):
|
||||
def _register_kit_types(self, registry, kit_id, kit_name, manifest,
|
||||
own_slots, bases):
|
||||
root = manifest
|
||||
for type_elem in root.iter("type"):
|
||||
type_name = type_elem.get("name", "")
|
||||
@@ -165,6 +150,8 @@ class DeviceSession:
|
||||
})
|
||||
registry[(kit_id, type_id_val)] = slots
|
||||
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
|
||||
# update type_name on any cached component of this type
|
||||
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):
|
||||
# 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))
|
||||
if type_name and type_name in app_state.final_components_registry:
|
||||
for s in app_state.final_components_registry[type_name]:
|
||||
if s["slot_id"] == slot_id:
|
||||
return s["name"]
|
||||
# Fallback to slot_registry (local IDs — wrong for inherited types,
|
||||
# but keeps things working when the schema registry is not yet loaded)
|
||||
# Fallback to slot_registry (flattened through the base chain, so
|
||||
# its IDs are absolute too)
|
||||
slots = self.sox_client.slot_registry.get((kit_id, type_id_val))
|
||||
if slots:
|
||||
for s in slots:
|
||||
|
||||
Reference in New Issue
Block a user