← Commit history

0.9.340: land the shipped runtime source for handlers/open_footprint_editor.py (tour fixes 0.9.318-0.9.339 never reached master, issue #79)

John Lauer ·8c147a2e43 ·1mo ago ·parent d65e4be
1 file changed +64−2
handlers/open_footprint_editor.py+64−2
@@ -524,7 +524,7 @@ def _background_navigate_win32_fp(fp_hwnd: int, filter_text: str, verify: str,     fixed the Symbol Editor (0.9.86). WM_SETTEXT into the LIB_TREE filter, Down     through the filter box to select the match, Enter posted to the tree     candidates + PostMessage dblclick fallback. Zero focus, no plugin needed."""-    edit = _find_child_by_class_and_parent(fp_hwnd, "Edit", "searchCtrl")+    edit = _ensure_tree_search(fp_hwnd)     if not edit:         return False     WM_SETTEXT = 0x000C@@ -583,6 +583,61 @@ def _background_navigate_win32_fp(fp_hwnd: int, filter_text: str, verify: str,     return False  ++_TREE_TOGGLED: dict = {}     # fp editor hwnd -> monotonic time we toggled its Library Tree pane on+++def _ensure_tree_search(fp_hwnd: int):+    """The Library Tree's search control, showing the pane through the frame's+    own View menu when the user has it hidden (arav-rog 2026-09-05: every+    background load typed into a control that did not exist). Toggle at most+    once per editor per minute, then WAIT for the control instead of toggling+    again (a second toggle hid it right back)."""+    def _visible(h) -> bool:+        # wx HIDES a closed pane: the control still exists, so "found" is not+        # enough (arav-rog 2026-09-05: the loader typed into a hidden filter box+        # for three runs). Visible means the control and its ancestors are shown.+        try:+            return bool(h) and bool(user32.IsWindowVisible(h))+        except Exception:  # pylint: disable=broad-except+            return bool(h)+    edit = _find_child_by_class_and_parent(fp_hwnd, "Edit", "searchCtrl")+    if _visible(edit):+        return edit+    import time as _t+    now = _t.monotonic()+    if now - _TREE_TOGGLED.get(int(fp_hwnd), 0) > 60 and _show_library_tree_pane():+        _TREE_TOGGLED[int(fp_hwnd)] = now+    for _ in range(16):+        edit = _find_child_by_class_and_parent(fp_hwnd, "Edit", "searchCtrl")+        if _visible(edit):+            return edit+        _t.sleep(0.25)+    return edit if _visible(edit) else None+++def _show_library_tree_pane() -> bool:+    """Tick View > Panels > Library Tree on the Footprint Editor frame via the+    pcbnew plugin (menu id resolved live; the FP editor is not frame 0)."""+    try:+        from handlers.bridge_client import _resolve_plugin, call as _rpc+        meta, err = _resolve_plugin("pcbnew")+        if err or not meta:+            return False+        rpc = _rpc(meta["port"], "get_menu_ids", {}, timeout=8.0)+        frames = ((rpc.get("result") or {}).get("frames")) or []+        for idx, fr in enumerate(frames):+            if "footprint editor" not in str(fr.get("frameTitle") or "").lower():+                continue+            for m in fr.get("menuItems") or []:+                if str(m.get("label") or "").strip().lower() == "library tree":+                    r = _rpc(meta["port"], "wm_command", {"frame_index": idx, "menu_id": int(m["id"])}, timeout=8.0)+                    return bool((r.get("result") or {}).get("posted"))+        return False+    except Exception:  # pylint: disable=broad-except+        return False++ def _navigate_to_footprint(fp_hwnd: int, footprint_name: str, load_after: bool = True) -> dict:     """Call the PowerShell script to navigate to a specific footprint. @@ -593,7 +648,7 @@ def _navigate_to_footprint(fp_hwnd: int, footprint_name: str, load_after: bool =     if not _NAVIGATE_SCRIPT.exists():         return {"status": "error", "error": f"Script not found: {_NAVIGATE_SCRIPT}"} -    search_edit = _find_child_by_class_and_parent(fp_hwnd, "Edit", "searchCtrl")+    search_edit = _ensure_tree_search(fp_hwnd)     if not search_edit:         return {"status": "error", "error": "Search edit control not found in Footprint Editor"} @@ -1035,6 +1090,13 @@ def handle_open_footprint_editor(kicad_info: dict, args: dict) -> dict:             _on_disk = bool(_ls.get("existsInLibrary"))         except Exception:             _ls = {}+        # arav-rog 2026-09-05: with no pcbnew running (plugin_not_running on every+        # tier) the editor never OPENED, yet this block read "on disk but not+        # loaded" as a stale cache and restarted KiCad, twice, 128 s each. A cache+        # verdict needs an open editor that failed to load the part; without one+        # there is no evidence, so fall through to the plain failure and its hint.+        if not fp_hwnd:+            _on_disk = False         if _on_disk and not args.get("_autoRestarted") and not args.get("_treeRefreshed"):             # First resort: reload the tree in place (#51). Cheap, no restart,             # and it keeps every window and the user's other work untouched.