Some checks failed
Build / build-gentoo (push) Failing after 14s
Build / download-system-deps (push) Successful in 3m28s
Build / get-source-code (push) Successful in 9m18s
Build / build-deb (push) Failing after 3m41s
Build / build-appimage (push) Successful in 4m12s
Build / build-android (push) Failing after 2m47s
Build / build-windows (push) Failing after 7m10s
- Remove unused OpenMP from playback backend - Fix update_assets on macOS - Add support for Objective C++ on macOS - Add macOS-specific code into the Dear ImGui backend - Add macOS .app packaging - Add support for global menus, and include support for macOS global menu into the Dear ImGui backend
213 lines
6 KiB
C++
213 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;
|
|
}
|
|
}
|