77 lines
2.6 KiB
Python
77 lines
2.6 KiB
Python
"""Document-level helpers for a Sedona app: the packed 'meta' property and component paths.
|
|
|
|
Pure XML and bit work, deliberately free of Tk so the rules stay testable headless.
|
|
"""
|
|
|
|
import xml.etree.ElementTree as ET
|
|
|
|
|
|
def read_meta_property(meta_str):
|
|
"""Parses 32-bit meta property integer fields via structured byte extraction rules."""
|
|
if meta_str is None or not meta_str:
|
|
return 0, 0, 0, True, False, False, False, 0
|
|
try:
|
|
if meta_str.startswith("0x") or meta_str.startswith("0X"):
|
|
meta_val = int(meta_str, 16)
|
|
else:
|
|
meta_val = int(meta_str)
|
|
|
|
raw_x = (meta_val >> 24) & 0xFF
|
|
raw_y = (meta_val >> 16) & 0xFF
|
|
reserved = (meta_val >> 8) & 0xFF
|
|
user_group_byte = meta_val & 0xFF
|
|
|
|
group1 = bool(user_group_byte & 0x01)
|
|
group2 = bool(user_group_byte & 0x02)
|
|
group3 = bool(user_group_byte & 0x04)
|
|
group4 = bool(user_group_byte & 0x08)
|
|
user_group_reserved = (user_group_byte >> 4) & 0x0F
|
|
|
|
return raw_x, raw_y, reserved, group1, group2, group3, group4, user_group_reserved
|
|
except Exception:
|
|
return 0, 0, 0, True, False, False, False, 0
|
|
|
|
|
|
def update_meta_property(element, meta_str, raw_x, raw_y):
|
|
"""Re-encodes coordinates back into meta, completely preserving existing lower and consecutive bytes."""
|
|
_, _, reserved, g1, g2, g3, g4, ug_res = read_meta_property(meta_str)
|
|
|
|
user_group_byte = 0
|
|
if g1: user_group_byte |= 0x01
|
|
if g2: user_group_byte |= 0x02
|
|
if g3: user_group_byte |= 0x04
|
|
if g4: user_group_byte |= 0x08
|
|
user_group_byte |= (ug_res & 0x0F) << 4
|
|
|
|
new_val = (
|
|
((raw_x & 0xFF) << 24) |
|
|
((raw_y & 0xFF) << 16) |
|
|
((reserved & 0xFF) << 8) |
|
|
(user_group_byte & 0xFF)
|
|
)
|
|
|
|
meta_prop = element.find("prop[@name='meta']")
|
|
if meta_prop is None:
|
|
meta_prop = ET.SubElement(element, "prop", name="meta")
|
|
|
|
meta_prop.set("val", str(new_val))
|
|
|
|
|
|
def find_parent_element(root_elem, child_to_find):
|
|
"""Traverses the XML DOM tree recursively to find the parent element of a given element."""
|
|
for parent in root_elem.iter():
|
|
if child_to_find in list(parent):
|
|
return parent
|
|
return None
|
|
|
|
|
|
def get_component_path(element, root_elem):
|
|
"""Computes the absolute path of a component within the application tree hierarchy."""
|
|
path_parts = []
|
|
curr = element
|
|
while curr is not None and curr.tag == "comp":
|
|
path_parts.append(curr.get("name", ""))
|
|
curr = find_parent_element(root_elem, curr)
|
|
path_parts.reverse()
|
|
return "/" + "/".join(path_parts)
|