Add a Properties view for the app root

The root tree row now names the app component, "app (<host:port>)" or
"app (<file>)", and offers Properties from its context menu and on
double-click. The live DOM's <app> element now carries its type and slot
values, and the refresh-by-id lookup finds it, so the view shows real
sys::App values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-29 21:04:03 +03:00
co-authored by Claude Opus 5.5
parent a9593de065
commit 73d168fd87
5 changed files with 50 additions and 25 deletions
+26 -16
View File
@@ -300,6 +300,10 @@ class DeviceSession:
app_elem = ET.SubElement(sax_root, "app")
if root_comp is not None:
app_elem.set("id", str(root_comp.id))
# The app is a component like any other, so the Properties view needs its
# type and slot values too. A .sax file leaves both implied; here they are not.
app_elem.set("type", root_comp.type_name)
self._add_prop_elements(app_elem, root_comp)
for child_id in root_comp.children:
child_comp = self.sox_client.cache_get(child_id)
if child_comp is not None:
@@ -318,22 +322,7 @@ class DeviceSession:
"type": type_qname,
}
comp_elem = ET.SubElement(parent_elem, "comp", **attribs)
slots = self.sox_client.slot_registry.get(
(sox_comp.kit_id, sox_comp.type_id))
if slots:
for slot in slots:
if slot.get("is_action"):
continue
name = slot["name"]
if name in sox_comp.values:
val = sox_comp.values[name]
if isinstance(val, float):
val_str = _fmt_float(val, _slot_precision(type_qname, name))
else:
val_str = str(val)
ET.SubElement(comp_elem, "prop",
name=name, val=val_str)
self._add_prop_elements(comp_elem, sox_comp)
for child_id in sox_comp.children:
child_comp = self.sox_client.cache_get(child_id)
@@ -346,6 +335,24 @@ class DeviceSession:
return comp_elem
def _add_prop_elements(self, comp_elem, sox_comp):
"""Writes a <prop> for every cached non-action slot value of `sox_comp`."""
slots = self.sox_client.slot_registry.get(
(sox_comp.kit_id, sox_comp.type_id))
if not slots:
return
for slot in slots:
if slot.get("is_action"):
continue
name = slot["name"]
if name in sox_comp.values:
val = sox_comp.values[name]
if isinstance(val, float):
val_str = _fmt_float(val, _slot_precision(sox_comp.type_name, name))
else:
val_str = str(val)
ET.SubElement(comp_elem, "prop", name=name, val=val_str)
def build_links_elements(self, sax_root):
"""Adds <link> elements under a <links> container, matching .sax structure."""
links_elem = sax_root.find("links")
@@ -449,6 +456,9 @@ class DeviceSession:
@staticmethod
def _find_element_by_id(root, comp_id):
target = str(comp_id)
app_elem = root.find("app")
if app_elem is not None and app_elem.get("id") == target:
return app_elem
for elem in root.iter("comp"):
if elem.get("id") == target:
return elem