mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-05-04 17:30:12 +08:00
refs #248 C++ API wrapper for the X-Plane Plugin SDK's C API for creating menus
This commit is contained in:
122
src/xbus/menus.cpp
Normal file
122
src/xbus/menus.cpp
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
/* 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 <type_traits>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace XBus
|
||||||
|
{
|
||||||
|
|
||||||
|
// Own implementation of std::make_unique, a C++14 feature not provided by GCC in C++11 mode
|
||||||
|
template<typename T, typename... Args>
|
||||||
|
std::unique_ptr<T> make_unique(Args&&... args)
|
||||||
|
{
|
||||||
|
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void *voidptr_cast(T i) // "safe" cast from integer to void*
|
||||||
|
{
|
||||||
|
static_assert(std::is_integral<T>::value, "voidptr_cast expects an integer");
|
||||||
|
typedef typename std::conditional<std::is_signed<T>::value, intptr_t, uintptr_t>::type intptr_type;
|
||||||
|
return reinterpret_cast<void *>(static_cast<intptr_type>(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> T intptr_cast(void *p) // "safe" cast from void* to integer
|
||||||
|
{
|
||||||
|
static_assert(std::is_integral<T>::value, "voidptr_cast returns an integer");
|
||||||
|
typedef typename std::conditional<std::is_signed<T>::value, intptr_t, uintptr_t>::type intptr_type;
|
||||||
|
return static_cast<T>(reinterpret_cast<intptr_type>(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
CMenu::CMenu(XPLMMenuID id, bool isMainMenu, std::unique_ptr<ItemList> items)
|
||||||
|
: m_data(std::make_shared<Data>(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<void()> 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<void(bool)> 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 = make_unique<ItemList>();
|
||||||
|
auto itemsVoidPtr = static_cast<void *>(&*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<ItemList *>(menuRef);
|
||||||
|
auto itemIdx = intptr_cast<intptr_t>(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<Data>(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
100
src/xbus/menus.h
Normal file
100
src/xbus/menus.h
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
#ifndef BLACKSIM_XBUS_MENUS_H
|
||||||
|
#define BLACKSIM_XBUS_MENUS_H
|
||||||
|
|
||||||
|
//! \file
|
||||||
|
|
||||||
|
#include <XPLM/XPLMMenus.h>
|
||||||
|
#include <functional>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace XBus
|
||||||
|
{
|
||||||
|
|
||||||
|
class CMenu;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Class-based interface to X-Plane SDK menu items.
|
||||||
|
*/
|
||||||
|
class CMenuItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! Construct an uninitialized menu item object
|
||||||
|
CMenuItem() = default;
|
||||||
|
|
||||||
|
//! Returns true if the menu item is checked
|
||||||
|
bool getChecked() const;
|
||||||
|
|
||||||
|
//! Sets the checked status of the menu item
|
||||||
|
void setChecked(bool checked);
|
||||||
|
|
||||||
|
//! Enables or disabled the menu item
|
||||||
|
void setEnabled(bool enabled);
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class CMenu;
|
||||||
|
|
||||||
|
CMenuItem(XPLMMenuID parent, int item, bool checkable, bool checked);
|
||||||
|
|
||||||
|
struct Data
|
||||||
|
{
|
||||||
|
Data(XPLMMenuID parent_, int item_, bool checkable_) : parent(parent_), item(item_), checkable(checkable_) {}
|
||||||
|
XPLMMenuID parent;
|
||||||
|
int item;
|
||||||
|
bool checkable;
|
||||||
|
};
|
||||||
|
std::shared_ptr<Data> m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Class-based interface to X-Plane SDK menus.
|
||||||
|
*/
|
||||||
|
class CMenu
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! Construct an uninitialized menu object
|
||||||
|
CMenu() = default;
|
||||||
|
|
||||||
|
//! Returns a menu object representing the top-level menu of all plugins.
|
||||||
|
static CMenu mainMenu();
|
||||||
|
|
||||||
|
//! Appends an item to the menu and returns it.
|
||||||
|
CMenuItem item(std::string name, std::function<void()> callback);
|
||||||
|
|
||||||
|
//! Appends a checkbox item to the menu and returns it.
|
||||||
|
CMenuItem checkableItem(std::string name, bool checked, std::function<void(bool)> callback);
|
||||||
|
|
||||||
|
//! Appends a separator to the menu.
|
||||||
|
void sep();
|
||||||
|
|
||||||
|
//! Appends an item to the menu which opens a sub-menu, and returns it.
|
||||||
|
CMenu subMenu(std::string name);
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef std::vector<std::pair<CMenuItem, std::function<void(bool)>>> ItemList;
|
||||||
|
|
||||||
|
CMenu(XPLMMenuID id, bool isMainMenu, std::unique_ptr<ItemList> callbacks);
|
||||||
|
|
||||||
|
static void handler(void *menuRef, void *itemRef);
|
||||||
|
|
||||||
|
struct Data
|
||||||
|
{
|
||||||
|
Data(XPLMMenuID id_, bool isMainMenu_, std::unique_ptr<ItemList> items_)
|
||||||
|
: id(id_), isMainMenu(isMainMenu_), items(std::move(items_)) {}
|
||||||
|
XPLMMenuID id;
|
||||||
|
bool isMainMenu;
|
||||||
|
std::unique_ptr<ItemList> items;
|
||||||
|
std::vector<CMenu> subMenus;
|
||||||
|
~Data();
|
||||||
|
};
|
||||||
|
std::shared_ptr<Data> m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // guard
|
||||||
Reference in New Issue
Block a user