| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
- //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
- #include "BsMenuItemManager.h"
- #include "Serialization/BsScriptAssemblyManager.h"
- #include "BsMonoAssembly.h"
- #include "BsMonoClass.h"
- #include "BsMonoMethod.h"
- #include "BsMonoField.h"
- #include "BsMonoManager.h"
- #include "BsMonoUtil.h"
- #include "BsScriptObjectManager.h"
- #include "GUI/BsShortcutKey.h"
- #include "EditorWindow/BsEditorWindowManager.h"
- #include "EditorWindow/BsMainEditorWindow.h"
- #include "GUI/BsGUIMenuBar.h"
- #include "GUI/BsGUIMenu.h"
- using namespace std::placeholders;
- namespace bs
- {
- MenuItemManager::MenuItemManager(ScriptAssemblyManager& scriptObjectManager)
- :mScriptObjectManager(scriptObjectManager), mMenuItemAttribute(nullptr), mPathField(nullptr),
- mShortcutField(nullptr), mPriorityField(nullptr), mSeparatorField(nullptr)
- {
- mDomainLoadedConn = ScriptObjectManager::instance().onRefreshDomainLoaded.connect(std::bind(&MenuItemManager::reloadAssemblyData, this));
- reloadAssemblyData();
- }
- MenuItemManager::~MenuItemManager()
- {
- mDomainLoadedConn.disconnect();
- }
- void MenuItemManager::clearMenuItems()
- {
- MainEditorWindow* mainWindow = EditorWindowManager::instance().getMainWindow();
- UINT32 numItems = (UINT32)mMenuItems.size();
- Vector<bool> destroyedItems(numItems, false);
- // Remove leaf elements only to avoid deleting child menu items
- bool changesMade;
- do
- {
- changesMade = false;
- for (UINT32 i = 0; i < numItems; i++)
- {
- GUIMenuItem* menuItem = mMenuItems[i];
- if (!destroyedItems[i] && menuItem->getNumChildren() == 0)
- {
- mainWindow->getMenuBar().removeMenuItem(menuItem);
- destroyedItems[i] = true;
- changesMade = true;
- }
- }
- } while (changesMade);
- // Remove remaining items regardless (none of their children are our concern). But when running properly there
- // should be no entries to remove at this step.
- for (UINT32 i = 0; i < numItems; i++)
- {
- GUIMenuItem* menuItem = mMenuItems[i];
- if (!destroyedItems[i])
- mainWindow->getMenuBar().removeMenuItem(menuItem);
- }
- mMenuItems.clear();
- }
- void MenuItemManager::reloadAssemblyData()
- {
- clearMenuItems();
- // Reload MenuItem attribute from editor assembly
- MonoAssembly* editorAssembly = MonoManager::instance().getAssembly(EDITOR_ASSEMBLY);
- mMenuItemAttribute = editorAssembly->getClass(EDITOR_NS, "MenuItem");
- if (mMenuItemAttribute == nullptr)
- BS_EXCEPT(InvalidStateException, "Cannot find MenuItem managed class.");
- mPathField = mMenuItemAttribute->getField("path");
- mShortcutField = mMenuItemAttribute->getField("shortcut");
- mPriorityField = mMenuItemAttribute->getField("priority");
- mSeparatorField = mMenuItemAttribute->getField("separator");
- MainEditorWindow* mainWindow = EditorWindowManager::instance().getMainWindow();
- Vector<String> scriptAssemblyNames = mScriptObjectManager.getScriptAssemblies();
- for (auto& assemblyName : scriptAssemblyNames)
- {
- MonoAssembly* assembly = MonoManager::instance().getAssembly(assemblyName);
- // Find new menu item methods
- const Vector<MonoClass*>& allClasses = assembly->getAllClasses();
- for (auto curClass : allClasses)
- {
- const Vector<MonoMethod*>& methods = curClass->getAllMethods();
- for (auto& curMethod : methods)
- {
- String path;
- ShortcutKey shortcutKey = ShortcutKey::NONE;
- INT32 priority = 0;
- bool separator = false;
- if (parseMenuItemMethod(curMethod, path, shortcutKey, priority, separator))
- {
- std::function<void()> callback = std::bind(&MenuItemManager::menuItemCallback, curMethod);
- if (separator)
- {
- Vector<String> pathElements = StringUtil::split(path, "/");
- String separatorPath;
- if (pathElements.size() > 1)
- {
- const String& lastElem = pathElements[pathElements.size() - 1];
- separatorPath = path;
- separatorPath.erase(path.size() - lastElem.size() - 1, lastElem.size() + 1);
- }
- GUIMenuItem* separatorItem = mainWindow->getMenuBar().addMenuItemSeparator(separatorPath, priority);
- mMenuItems.push_back(separatorItem);
- }
- GUIMenuItem* menuItem = mainWindow->getMenuBar().addMenuItem(path, callback, priority, shortcutKey);
- mMenuItems.push_back(menuItem);
- }
- }
- }
- }
- }
- bool MenuItemManager::parseMenuItemMethod(MonoMethod* method, String& path, ShortcutKey& shortcut, INT32& priority, bool& separator) const
- {
- if (!method->hasAttribute(mMenuItemAttribute))
- return false;
- if (method->getNumParameters() != 0)
- return false;
- if (!method->isStatic())
- return false;
- MonoObject* menuItemAttrib = method->getAttribute(mMenuItemAttribute);
- MonoString* monoPath;
- mPathField->get(menuItemAttrib, &monoPath);
- mShortcutField->get(menuItemAttrib, &shortcut);
- path = MonoUtil::monoToString(monoPath);
- mPriorityField->get(menuItemAttrib, &priority);
- mSeparatorField->get(menuItemAttrib, &separator);
- return true;
- }
- void MenuItemManager::menuItemCallback(MonoMethod* method)
- {
- method->invoke(nullptr, nullptr);
- }
- }
|