/* Copyright (C) 2013 VATSIM Community / contributors * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "menus.h" #include "blackmisc/blackmiscfreefunctions.h" #include #include #include namespace XBus { template void *voidptr_cast(T i) // "safe" cast from integer to void* { static_assert(std::is_integral::value, "voidptr_cast expects an integer"); typedef typename std::conditional::value, intptr_t, uintptr_t>::type intptr_type; return reinterpret_cast(static_cast(i)); } template T intptr_cast(void *p) // "safe" cast from void* to integer { static_assert(std::is_integral::value, "voidptr_cast returns an integer"); typedef typename std::conditional::value, intptr_t, uintptr_t>::type intptr_type; return static_cast(reinterpret_cast(p)); } CMenu::CMenu(XPLMMenuID id, bool isMainMenu, std::unique_ptr items) : m_data(std::make_shared(id, isMainMenu, std::move(items))) {} CMenu::Data::~Data() { if (! isMainMenu) { XPLMDestroyMenu(id); } } CMenu CMenu::mainMenu() { return { XPLMFindPluginsMenu(), true, nullptr }; } CMenuItem CMenu::item(std::string name, std::function callback) { assert(! name.empty()); m_data->items->emplace_back( CMenuItem { m_data->id, XPLMAppendMenuItem(m_data->id, name.c_str(), voidptr_cast(m_data->items->size() + 1), false), false, false }, [callback](bool){ callback(); } ); return m_data->items->back().first; } CMenuItem CMenu::checkableItem(std::string name, bool checked, std::function callback) { assert(! name.empty()); m_data->items->emplace_back( CMenuItem { m_data->id, XPLMAppendMenuItem(m_data->id, name.c_str(), voidptr_cast(m_data->items->size() + 1), false), true, checked }, callback ); return m_data->items->back().first; } void CMenu::sep() { XPLMAppendMenuSeparator(m_data->id); } CMenu CMenu::subMenu(std::string name) { assert(! name.empty()); auto items = BlackMisc::make_unique(); auto itemsVoidPtr = static_cast(&*items); return { XPLMCreateMenu(name.c_str(), m_data->id, XPLMAppendMenuItem(m_data->id, name.c_str(), nullptr, false), handler, itemsVoidPtr), false, std::move(items) }; } void CMenu::handler(void *menuRef, void *itemRef) { if (menuRef && itemRef) { auto items = static_cast(menuRef); auto itemIdx = intptr_cast(itemRef) - 1; assert(itemIdx >= 0); (*items)[itemIdx].second((*items)[itemIdx].first.getChecked()); } } CMenuItem::CMenuItem(XPLMMenuID parent, int item, bool checkable, bool checked) : m_data(std::make_shared(parent, item, checkable)) { if (checkable) { setChecked(checked); } } bool CMenuItem::getChecked() const { XPLMMenuCheck check = xplm_Menu_NoCheck; XPLMCheckMenuItemState(m_data->parent, m_data->item, &check); return check == xplm_Menu_Checked; } void CMenuItem::setChecked(bool checked) { XPLMCheckMenuItem(m_data->parent, m_data->item, checked); } void CMenuItem::setEnabled(bool enabled) { XPLMEnableMenuItem(m_data->parent, m_data->item, enabled); } }