214 lines
6 KiB
C++
214 lines
6 KiB
C++
|
#include "menus.hpp"
|
||
|
#ifdef __APPLE__
|
||
|
#define IS_MACOSX true
|
||
|
#else
|
||
|
#define IS_MACOSX false
|
||
|
#endif
|
||
|
namespace LooperUI {
|
||
|
static std::unordered_map<MenuType, bool> menu_type_data {
|
||
|
{MenuType_Default, true},
|
||
|
{MenuType_Item, true},
|
||
|
{MenuType_Application, IS_MACOSX},
|
||
|
{MenuType_Window, IS_MACOSX},
|
||
|
{MenuType_Help, true},
|
||
|
{MenuType_Services, IS_MACOSX}
|
||
|
};
|
||
|
bool MenuTypeValidForSystem(MenuType type) {
|
||
|
if (menu_type_data.contains(type)) {
|
||
|
return menu_type_data[type];
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
MenuItemBase::MenuItemBase(std::string title)
|
||
|
: title(title)
|
||
|
, type(MenuType_Default)
|
||
|
{
|
||
|
this->enabled = true;
|
||
|
this->visible = true;
|
||
|
}
|
||
|
MenuItemBase::MenuItemBase(MenuType type)
|
||
|
: MenuItemBase("") {
|
||
|
this->type = type;
|
||
|
}
|
||
|
MenuItem::MenuItem(std::string title, std::string keybindString, std::function<void(MenuItem*, void*)> callback, void *userdata)
|
||
|
: MenuItemBase(title)
|
||
|
{
|
||
|
this->keybindString = keybindString;
|
||
|
this->userdata = userdata;
|
||
|
this->callback = callback;
|
||
|
this->type = MenuType_Item;
|
||
|
}
|
||
|
Menu::iterator Menu::begin() {
|
||
|
return children.begin();
|
||
|
}
|
||
|
Menu::iterator Menu::end() {
|
||
|
return children.end();
|
||
|
}
|
||
|
Menu::const_iterator Menu::cbegin() const {
|
||
|
return children.cbegin();
|
||
|
}
|
||
|
Menu::const_iterator Menu::cend() const {
|
||
|
return children.cend();
|
||
|
}
|
||
|
Menu::reverse_iterator Menu::rbegin() {
|
||
|
return children.rbegin();
|
||
|
}
|
||
|
Menu::reverse_iterator Menu::rend() {
|
||
|
return children.rend();
|
||
|
}
|
||
|
Menu::const_reverse_iterator Menu::crbegin() const {
|
||
|
return children.crbegin();
|
||
|
}
|
||
|
Menu::const_reverse_iterator Menu::crend() const {
|
||
|
return children.crend();
|
||
|
}
|
||
|
MenuItemBase *Menu::operator[](size_t index) {
|
||
|
return children[index];
|
||
|
}
|
||
|
void Menu::Prepend(MenuItemBase *menu) {
|
||
|
children.insert(children.begin(), menu);
|
||
|
}
|
||
|
void Menu::Insert(MenuItemBase *menu, size_t index) {
|
||
|
if (index >= children.size()) {
|
||
|
Append(menu);
|
||
|
} else {
|
||
|
children.insert(children.begin() + index, menu);
|
||
|
}
|
||
|
}
|
||
|
bool MenuItemBase::IsSubmenu() {
|
||
|
return false;
|
||
|
}
|
||
|
bool Menu::IsSubmenu() {
|
||
|
return true;
|
||
|
}
|
||
|
Menu::Menu(std::string title, MenuType type)
|
||
|
: MenuItemBase(title)
|
||
|
{
|
||
|
this->type = type;
|
||
|
}
|
||
|
bool MenuItemBase::HasParent() {
|
||
|
return parent != nullptr;
|
||
|
}
|
||
|
Menu *MenuItemBase::GetParent() {
|
||
|
return parent;
|
||
|
}
|
||
|
void Menu::Append(MenuItemBase *menu) {
|
||
|
if (menu->parent != nullptr) {
|
||
|
throw std::exception();
|
||
|
}
|
||
|
menu->parent = this;
|
||
|
children.push_back(menu);
|
||
|
}
|
||
|
MenuBuilder &MenuBuilder::BeginSubmenu(std::string title, MenuType type, OSOptions allowedOS) {
|
||
|
throwIfBuilt();
|
||
|
Menu *submenu = new Menu(title);
|
||
|
submenu->os_options = allowedOS;
|
||
|
submenu->type = type;
|
||
|
current_menu->Append(submenu);
|
||
|
current_menu = submenu;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
MenuBuilder &MenuBuilder::EndSubmenu() {
|
||
|
throwIfBuilt();
|
||
|
if (current_menu->HasParent()) {
|
||
|
current_menu = current_menu->GetParent();
|
||
|
} else {
|
||
|
throw std::exception();
|
||
|
}
|
||
|
return *this;
|
||
|
}
|
||
|
MenuBuilder &MenuBuilder::AddEmptySubmenu(std::string title, MenuType type, OSOptions allowedOS) {
|
||
|
BeginSubmenu(title, type, allowedOS).EndSubmenu();
|
||
|
return *this;
|
||
|
}
|
||
|
MenuBuilder &MenuBuilder::AddItem(std::string title, std::string keybindString, std::function<void(MenuItem*, void*)> callback, void *userdata, OSOptions allowedOS) {
|
||
|
throwIfBuilt();
|
||
|
MenuItem *newItem = new MenuItem(title, keybindString, callback, userdata);
|
||
|
newItem->os_options = allowedOS;
|
||
|
current_menu->Append(newItem);
|
||
|
return *this;
|
||
|
}
|
||
|
MenuBuilder &MenuBuilder::AddSeparator(OSOptions allowedOS) {
|
||
|
throwIfBuilt();
|
||
|
MenuItemBase *newItem = new MenuItemBase(MenuType_Separator);
|
||
|
newItem->os_options = allowedOS;
|
||
|
current_menu->Append(newItem);
|
||
|
return *this;
|
||
|
}
|
||
|
MenuBuilder &MenuBuilder::AddItemNoUserdata(std::string title, std::string keybindString, std::function<void(MenuItem*)> callback_no_userdata, OSOptions allowedOS) {
|
||
|
AddItem(title, keybindString, [callback_no_userdata](MenuItem *item, void*) {
|
||
|
callback_no_userdata(item);
|
||
|
}, nullptr, allowedOS);
|
||
|
return *this;
|
||
|
}
|
||
|
MenuBuilder &MenuBuilder::AddItemSimple(std::string title, std::string keybindString, std::function<void()> callback_simple, OSOptions allowedOS) {
|
||
|
AddItem(title, keybindString, [callback_simple](MenuItem*, void*) {
|
||
|
callback_simple();
|
||
|
}, nullptr, allowedOS);
|
||
|
return *this;
|
||
|
}
|
||
|
MenuBuilder::MenuBuilder(std::string rootTitle) {
|
||
|
root = new Menu(rootTitle);
|
||
|
current_menu = root;
|
||
|
built = false;
|
||
|
}
|
||
|
Menu *MenuBuilder::Build() {
|
||
|
throwIfBuilt();
|
||
|
built = true;
|
||
|
return root;
|
||
|
}
|
||
|
void MenuBuilder::throwIfBuilt() {
|
||
|
if (built) throw std::exception();
|
||
|
}
|
||
|
static void _IterateMenu(Menu *menu, MenuIteratorCallbacks &callbacks) {
|
||
|
|
||
|
for (MenuItemBase *item : *menu) {
|
||
|
bool allowed = (item->os_options == OSOptions::AnyOS) || (item->os_options ==
|
||
|
#ifdef __APPLE__
|
||
|
OSOptions::OnlyMac
|
||
|
#else
|
||
|
OSOptions::ExcludeMac
|
||
|
#endif
|
||
|
);
|
||
|
if (!allowed) continue;
|
||
|
if (item->type == MenuType_Separator) {
|
||
|
callbacks.AddSeparator();
|
||
|
} else if (item->IsSubmenu()) {
|
||
|
callbacks.BeginSubmenu((Menu*)item);
|
||
|
_IterateMenu((Menu*)item, callbacks);
|
||
|
callbacks.EndSubmenu();
|
||
|
} else {
|
||
|
callbacks.AddNormalItem((MenuItem*)item);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
void IterateMenu(Menu *menu, MenuIteratorCallbacks &callbacks) {
|
||
|
callbacks.Init(menu);
|
||
|
_IterateMenu(menu, callbacks);
|
||
|
callbacks.Finalize();
|
||
|
}
|
||
|
MenuItemBase *FindMenu(Menu *menu, std::string title) {
|
||
|
for (MenuItemBase *item : *menu) {
|
||
|
bool allowed = item->os_options == OSOptions::AnyOS || item->os_options ==
|
||
|
#ifdef __APPLE__
|
||
|
OSOptions::OnlyMac
|
||
|
#else
|
||
|
OSOptions::ExcludeMac
|
||
|
#endif
|
||
|
;
|
||
|
if (!allowed) continue;
|
||
|
if (item->title == title) {
|
||
|
return item;
|
||
|
} else if (item->IsSubmenu()) {
|
||
|
MenuItemBase *maybe_output = FindMenu((Menu*)item, title);
|
||
|
if (maybe_output != nullptr) {
|
||
|
return maybe_output;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return nullptr;
|
||
|
}
|
||
|
}
|