App tree: keep expanded folders open; only the - sign closes one
Rebuilding the tree (live child loads, edits) now restores every row that was expanded, matched by component id or name path. Double-click no longer toggles a row through ttk's default binding. 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.147"
|
VERSION = "0.0.0.148"
|
||||||
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
|
||||||
|
|||||||
@@ -1232,18 +1232,23 @@ def _open_special_view(comp):
|
|||||||
|
|
||||||
|
|
||||||
def on_tree_double_click(event):
|
def on_tree_double_click(event):
|
||||||
"""Double-click on a tree node opens its special view (or Properties)."""
|
"""Double-click on a tree node opens its special view (or Properties).
|
||||||
|
|
||||||
|
Returns "break" so ttk's own double-click does not also toggle the row: only the
|
||||||
|
+/- sign opens or closes a node.
|
||||||
|
"""
|
||||||
tree = app_state.tree
|
tree = app_state.tree
|
||||||
item_id = tree.identify_row(event.y)
|
item_id = tree.identify_row(event.y)
|
||||||
if not item_id:
|
if not item_id:
|
||||||
return
|
return "break"
|
||||||
comp = app_state.tree_element_map.get(item_id)
|
comp = app_state.tree_element_map.get(item_id)
|
||||||
if comp is None:
|
if comp is None:
|
||||||
return
|
return "break"
|
||||||
if tree.parent(item_id) == "":
|
if tree.parent(item_id) == "":
|
||||||
show_properties(comp)
|
show_properties(comp)
|
||||||
else:
|
else:
|
||||||
_open_special_view(comp)
|
_open_special_view(comp)
|
||||||
|
return "break"
|
||||||
|
|
||||||
|
|
||||||
def on_canvas_double_click(event):
|
def on_canvas_double_click(event):
|
||||||
|
|||||||
+47
-1
@@ -59,9 +59,53 @@ def parse_xml_to_tree(treeview, parent_node, xml_element):
|
|||||||
parse_xml_to_tree(treeview, node_id, child)
|
parse_xml_to_tree(treeview, node_id, child)
|
||||||
|
|
||||||
|
|
||||||
|
def _expansion_key(treeview, item, parent_key):
|
||||||
|
"""Names a tree row in a way that survives a rebuild of the tree.
|
||||||
|
|
||||||
|
A component's id is stable across edits and across a fresh DOM read from the
|
||||||
|
device; a row without one (the root, or an id-less file component) falls back to
|
||||||
|
its name under its parent's key.
|
||||||
|
"""
|
||||||
|
elem = app_state.tree_element_map.get(item)
|
||||||
|
comp_id = elem.get("id") if elem is not None else None
|
||||||
|
if comp_id is not None and treeview.parent(item) != "":
|
||||||
|
return ("id", comp_id)
|
||||||
|
name = elem.get("name", "") if elem is not None else treeview.item(item, "text")
|
||||||
|
return ("path", parent_key, name)
|
||||||
|
|
||||||
|
|
||||||
|
def _collect_open_keys(treeview, parent="", parent_key=None, found=None):
|
||||||
|
"""Returns the keys of every row that is expanded right now."""
|
||||||
|
if found is None:
|
||||||
|
found = set()
|
||||||
|
for item in treeview.get_children(parent):
|
||||||
|
key = _expansion_key(treeview, item, parent_key)
|
||||||
|
if treeview.item(item, "open"):
|
||||||
|
found.add(key)
|
||||||
|
_collect_open_keys(treeview, item, key, found)
|
||||||
|
return found
|
||||||
|
|
||||||
|
|
||||||
|
def _reopen_keys(treeview, open_keys, parent="", parent_key=None):
|
||||||
|
"""Expands again the rows that were expanded before the rebuild.
|
||||||
|
|
||||||
|
Setting the open flag in code does not raise <<TreeviewOpen>>, so this never
|
||||||
|
starts a live child load of its own.
|
||||||
|
"""
|
||||||
|
for item in treeview.get_children(parent):
|
||||||
|
key = _expansion_key(treeview, item, parent_key)
|
||||||
|
if key in open_keys:
|
||||||
|
treeview.item(item, open=True)
|
||||||
|
_reopen_keys(treeview, open_keys, item, key)
|
||||||
|
|
||||||
|
|
||||||
def refresh_treeview_from_dom(xml_root):
|
def refresh_treeview_from_dom(xml_root):
|
||||||
"""Rebuilds navigation tree structures using current XML DOM trees."""
|
"""Rebuilds navigation tree structures using current XML DOM trees.
|
||||||
|
|
||||||
|
Rows the user had expanded stay expanded; only the user's own "-" closes one.
|
||||||
|
"""
|
||||||
tree = app_state.tree
|
tree = app_state.tree
|
||||||
|
open_keys = _collect_open_keys(tree)
|
||||||
app_state.tree_element_map.clear()
|
app_state.tree_element_map.clear()
|
||||||
|
|
||||||
for item in tree.get_children():
|
for item in tree.get_children():
|
||||||
@@ -88,6 +132,8 @@ def refresh_treeview_from_dom(xml_root):
|
|||||||
else:
|
else:
|
||||||
parse_xml_to_tree(tree, root_node, xml_root)
|
parse_xml_to_tree(tree, root_node, xml_root)
|
||||||
|
|
||||||
|
_reopen_keys(tree, open_keys)
|
||||||
|
|
||||||
if _tree_filled is not None:
|
if _tree_filled is not None:
|
||||||
_tree_filled()
|
_tree_filled()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user