| 497 | } |
| 498 | |
| 499 | void PyMenuRegistry::sync_from_python() const { |
| 500 | // GIL is already held by callers (bridge functions in python_runtime.cpp) |
| 501 | try { |
| 502 | auto menus_module = nb::module_::import_("lfs_plugins.layouts.menus"); |
| 503 | auto get_menu_classes = menus_module.attr("get_menu_classes"); |
| 504 | auto menu_classes = get_menu_classes(); |
| 505 | |
| 506 | std::lock_guard lock(mutex_); |
| 507 | |
| 508 | menu_classes_.clear(); |
| 509 | |
| 510 | for (nb::handle menu_class_handle : menu_classes) { |
| 511 | nb::object menu_class = nb::borrow(menu_class_handle); |
| 512 | if (!menu_class.is_valid()) |
| 513 | continue; |
| 514 | |
| 515 | std::string idname = nb::cast<std::string>(menu_class.attr("__module__")) + "." + |
| 516 | nb::cast<std::string>(menu_class.attr("__qualname__")); |
| 517 | |
| 518 | std::string label; |
| 519 | MenuLocation location = MenuLocation::File; |
| 520 | int order = 100; |
| 521 | |
| 522 | if (nb::hasattr(menu_class, "label")) { |
| 523 | label = nb::cast<std::string>(menu_class.attr("label")); |
| 524 | } |
| 525 | if (nb::hasattr(menu_class, "location")) { |
| 526 | location = parse_menu_location(nb::cast<std::string>(menu_class.attr("location"))); |
| 527 | } |
| 528 | if (nb::hasattr(menu_class, "order")) { |
| 529 | order = nb::cast<int>(menu_class.attr("order")); |
| 530 | } |
| 531 | |
| 532 | nb::object instance = menu_class(); |
| 533 | |
| 534 | PyMenuClassInfo info; |
| 535 | info.idname = idname; |
| 536 | info.label = label; |
| 537 | info.location = location; |
| 538 | info.order = order; |
| 539 | info.menu_class = menu_class; |
| 540 | info.menu_instance = instance; |
| 541 | |
| 542 | menu_classes_.push_back(std::move(info)); |
| 543 | } |
| 544 | |
| 545 | sort_by_order(menu_classes_); |
| 546 | |
| 547 | LOG_INFO("Synced {} menus from Python registry", menu_classes_.size()); |
| 548 | } catch (const std::exception& e) { |
| 549 | LOG_ERROR("Failed to sync menus from Python: {}", e.what()); |
| 550 | } |
| 551 | } |
| 552 | |
| 553 | vis::gui::MenuDropdownContent PyMenuRegistry::collect_menu_content(const std::string& idname) { |
| 554 | vis::gui::MenuDropdownContent content; |
nothing calls this directly
no test coverage detected