|
|
@@ -13,6 +13,8 @@ |
|
|
|
#include <engine/ParamQuantity.hpp> |
|
|
|
#include <context.hpp> |
|
|
|
|
|
|
|
#include <functional> |
|
|
|
|
|
|
|
|
|
|
|
namespace rack { |
|
|
|
|
|
|
@@ -189,23 +191,60 @@ TMenu* createMenu() { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
template <typename T = int> |
|
|
|
ui::MenuItem* createIndexMenuItem(T* ptr, std::string name, std::vector<std::string> labels) { |
|
|
|
/** Creates a MenuItem that controls a boolean value with a check mark. |
|
|
|
*/ |
|
|
|
inline ui::MenuItem* createBoolMenuItem(std::string name, std::function<bool()> getter, std::function<void(bool)> setter) { |
|
|
|
struct Item : ui::MenuItem { |
|
|
|
std::function<void(size_t)> setter; |
|
|
|
bool val; |
|
|
|
|
|
|
|
void onAction(const event::Action& e) override { |
|
|
|
setter(val); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
bool currVal = getter(); |
|
|
|
Item* item = createMenuItem<Item>(name, CHECKMARK(currVal)); |
|
|
|
item->setter = setter; |
|
|
|
item->val = !currVal; |
|
|
|
return item; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** Easy wrapper for createBoolMenuItem() to modify a bool pointer. |
|
|
|
*/ |
|
|
|
template <typename T> |
|
|
|
ui::MenuItem* createBoolPtrMenuItem(std::string name, T* ptr) { |
|
|
|
return createBoolMenuItem(name, |
|
|
|
[=]() {return *ptr;}, |
|
|
|
[=](T val) {*ptr = val;} |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** Creates a MenuItem that when hovered, opens a submenu with several MenuItems indexed by an integer. |
|
|
|
*/ |
|
|
|
inline ui::MenuItem* createIndexSubmenuItem(std::string name, std::vector<std::string> labels, std::function<size_t()> getter, std::function<void(size_t)> setter) { |
|
|
|
struct IndexItem : ui::MenuItem { |
|
|
|
T* ptr; |
|
|
|
T index; |
|
|
|
std::function<void(size_t)> setter; |
|
|
|
size_t index; |
|
|
|
|
|
|
|
void onAction(const event::Action& e) override { |
|
|
|
*ptr = index; |
|
|
|
setter(index); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
struct Item : ui::MenuItem { |
|
|
|
T* ptr; |
|
|
|
std::function<size_t()> getter; |
|
|
|
std::function<void(size_t)> setter; |
|
|
|
std::vector<std::string> labels; |
|
|
|
|
|
|
|
ui::Menu* createChildMenu() override { |
|
|
|
ui::Menu* menu = new ui::Menu; |
|
|
|
for (T i = 0; i < (T) labels.size(); i++) { |
|
|
|
IndexItem* item = createMenuItem<IndexItem>(labels[i], CHECKMARK(*ptr == i)); |
|
|
|
item->ptr = ptr; |
|
|
|
size_t currIndex = getter(); |
|
|
|
for (size_t i = 0; i < labels.size(); i++) { |
|
|
|
IndexItem* item = createMenuItem<IndexItem>(labels[i], CHECKMARK(currIndex == i)); |
|
|
|
item->setter = setter; |
|
|
|
item->index = i; |
|
|
|
menu->addChild(item); |
|
|
|
} |
|
|
@@ -213,13 +252,25 @@ ui::MenuItem* createIndexMenuItem(T* ptr, std::string name, std::vector<std::str |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
T index = *ptr; |
|
|
|
std::string label = (0 <= index && index < (T) labels.size()) ? labels[index] : ""; |
|
|
|
size_t currIndex = getter(); |
|
|
|
std::string label = (currIndex < labels.size()) ? labels[currIndex] : ""; |
|
|
|
Item* item = createMenuItem<Item>(name, label + " " + RIGHT_ARROW); |
|
|
|
item->ptr = ptr; |
|
|
|
item->getter = getter; |
|
|
|
item->setter = setter; |
|
|
|
item->labels = labels; |
|
|
|
return item; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** Easy wrapper for createIndexSubmenuItem() that controls an integer index at a pointer address. |
|
|
|
*/ |
|
|
|
template <typename T> |
|
|
|
ui::MenuItem* createIndexPtrSubmenuItem(std::string name, std::vector<std::string> labels, T* ptr) { |
|
|
|
return createIndexSubmenuItem(name, labels, |
|
|
|
[=]() {return *ptr;}, |
|
|
|
[=](T index) {*ptr = index;} |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} // namespace rack |