You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

helpers.hpp 7.9KB

6 years ago
6 years ago
6 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. #pragma once
  2. #include <plugin/Model.hpp>
  3. #include <ui/MenuOverlay.hpp>
  4. #include <ui/MenuItem.hpp>
  5. #include <ui/MenuLabel.hpp>
  6. #include <ui/Menu.hpp>
  7. #include <app/PortWidget.hpp>
  8. #include <app/ParamWidget.hpp>
  9. #include <app/ModuleLightWidget.hpp>
  10. #include <app/Scene.hpp>
  11. #include <app/SvgPanel.hpp>
  12. #include <engine/Module.hpp>
  13. #include <engine/ParamQuantity.hpp>
  14. #include <context.hpp>
  15. #include <functional>
  16. namespace rack {
  17. template <class TModule, class TModuleWidget>
  18. plugin::Model* createModel(const std::string& slug) {
  19. struct TModel : plugin::Model {
  20. engine::Module* createModule() override {
  21. engine::Module* m = new TModule;
  22. m->model = this;
  23. return m;
  24. }
  25. app::ModuleWidget* createModuleWidget(engine::Module* m) override {
  26. TModule* tm = NULL;
  27. if (m) {
  28. assert(m->model == this);
  29. tm = dynamic_cast<TModule*>(m);
  30. }
  31. app::ModuleWidget* mw = new TModuleWidget(tm);
  32. mw->model = this;
  33. return mw;
  34. }
  35. };
  36. plugin::Model* o = new TModel;
  37. o->slug = slug;
  38. return o;
  39. }
  40. template <class TWidget>
  41. TWidget* createWidget(math::Vec pos) {
  42. TWidget* o = new TWidget;
  43. o->box.pos = pos;
  44. return o;
  45. }
  46. template <class TWidget>
  47. TWidget* createWidgetCentered(math::Vec pos) {
  48. TWidget* o = createWidget<TWidget>(pos);
  49. o->box.pos = o->box.pos.minus(o->box.size.div(2));
  50. return o;
  51. }
  52. inline app::SvgPanel* createPanel(std::string svgPath) {
  53. app::SvgPanel* panel = new app::SvgPanel;
  54. std::shared_ptr<Svg> svg = Svg::load(svgPath);
  55. panel->setBackground(svg);
  56. return panel;
  57. }
  58. template <class TParamWidget>
  59. TParamWidget* createParam(math::Vec pos, engine::Module* module, int paramId) {
  60. TParamWidget* o = new TParamWidget;
  61. o->box.pos = pos;
  62. o->app::ParamWidget::module = module;
  63. o->app::ParamWidget::paramId = paramId;
  64. o->initParamQuantity();
  65. return o;
  66. }
  67. template <class TParamWidget>
  68. TParamWidget* createParamCentered(math::Vec pos, engine::Module* module, int paramId) {
  69. TParamWidget* o = createParam<TParamWidget>(pos, module, paramId);
  70. o->box.pos = o->box.pos.minus(o->box.size.div(2));
  71. return o;
  72. }
  73. template <class TPortWidget>
  74. TPortWidget* createInput(math::Vec pos, engine::Module* module, int inputId) {
  75. TPortWidget* o = new TPortWidget;
  76. o->box.pos = pos;
  77. o->app::PortWidget::module = module;
  78. o->app::PortWidget::type = engine::Port::INPUT;
  79. o->app::PortWidget::portId = inputId;
  80. return o;
  81. }
  82. template <class TPortWidget>
  83. TPortWidget* createInputCentered(math::Vec pos, engine::Module* module, int inputId) {
  84. TPortWidget* o = createInput<TPortWidget>(pos, module, inputId);
  85. o->box.pos = o->box.pos.minus(o->box.size.div(2));
  86. return o;
  87. }
  88. template <class TPortWidget>
  89. TPortWidget* createOutput(math::Vec pos, engine::Module* module, int outputId) {
  90. TPortWidget* o = new TPortWidget;
  91. o->box.pos = pos;
  92. o->app::PortWidget::module = module;
  93. o->app::PortWidget::type = engine::Port::OUTPUT;
  94. o->app::PortWidget::portId = outputId;
  95. return o;
  96. }
  97. template <class TPortWidget>
  98. TPortWidget* createOutputCentered(math::Vec pos, engine::Module* module, int outputId) {
  99. TPortWidget* o = createOutput<TPortWidget>(pos, module, outputId);
  100. o->box.pos = o->box.pos.minus(o->box.size.div(2));
  101. return o;
  102. }
  103. template <class TModuleLightWidget>
  104. TModuleLightWidget* createLight(math::Vec pos, engine::Module* module, int firstLightId) {
  105. TModuleLightWidget* o = new TModuleLightWidget;
  106. o->box.pos = pos;
  107. o->app::ModuleLightWidget::module = module;
  108. o->app::ModuleLightWidget::firstLightId = firstLightId;
  109. return o;
  110. }
  111. template <class TModuleLightWidget>
  112. TModuleLightWidget* createLightCentered(math::Vec pos, engine::Module* module, int firstLightId) {
  113. TModuleLightWidget* o = createLight<TModuleLightWidget>(pos, module, firstLightId);
  114. o->box.pos = o->box.pos.minus(o->box.size.div(2));
  115. return o;
  116. }
  117. /** Creates a param with a light and calls setFirstLightId() on it. */
  118. template <class TParamWidget>
  119. TParamWidget* createLightParam(math::Vec pos, engine::Module* module, int paramId, int firstLightId) {
  120. TParamWidget* o = createParam<TParamWidget>(pos, module, paramId);
  121. o->setFirstLightId(firstLightId);
  122. return o;
  123. }
  124. template <class TParamWidget>
  125. TParamWidget* createLightParamCentered(math::Vec pos, engine::Module* module, int paramId, int firstLightId) {
  126. TParamWidget* o = createLightParam<TParamWidget>(pos, module, paramId, firstLightId);
  127. o->box.pos = o->box.pos.minus(o->box.size.div(2));
  128. return o;
  129. }
  130. template <class TMenu = ui::Menu>
  131. TMenu* createMenu() {
  132. TMenu* o = new TMenu;
  133. o->box.pos = APP->scene->mousePos;
  134. ui::MenuOverlay* menuOverlay = new ui::MenuOverlay;
  135. menuOverlay->addChild(o);
  136. APP->scene->addChild(menuOverlay);
  137. return o;
  138. }
  139. template <class TMenuLabel = ui::MenuLabel>
  140. TMenuLabel* createMenuLabel(std::string text) {
  141. TMenuLabel* o = new TMenuLabel;
  142. o->text = text;
  143. return o;
  144. }
  145. template <class TMenuItem = ui::MenuItem>
  146. TMenuItem* createMenuItem(std::string text, std::string rightText = "") {
  147. TMenuItem* o = new TMenuItem;
  148. o->text = text;
  149. o->rightText = rightText;
  150. return o;
  151. }
  152. template <class TMenuItem = ui::MenuItem>
  153. TMenuItem* createMenuItem(std::string text, std::string rightText, std::function<void()> action) {
  154. struct Item : TMenuItem {
  155. std::function<void()> action;
  156. void onAction(const event::Action& e) override {
  157. action();
  158. }
  159. };
  160. Item* item = createMenuItem<Item>(text, rightText);
  161. item->action = action;
  162. return item;
  163. }
  164. /** Creates a MenuItem with a check mark set by a lambda function.
  165. */
  166. inline ui::MenuItem* createCheckMenuItem(std::string text, std::function<bool()> checked, std::function<void()> action) {
  167. struct Item : ui::MenuItem {
  168. std::function<void()> action;
  169. void onAction(const event::Action& e) override {
  170. action();
  171. }
  172. };
  173. Item* item = createMenuItem<Item>(text, CHECKMARK(checked()));
  174. item->action = action;
  175. return item;
  176. }
  177. /** Creates a MenuItem that controls a boolean value with a check mark.
  178. */
  179. inline ui::MenuItem* createBoolMenuItem(std::string text, std::function<bool()> getter, std::function<void(bool)> setter) {
  180. struct Item : ui::MenuItem {
  181. std::function<void(size_t)> setter;
  182. bool val;
  183. void onAction(const event::Action& e) override {
  184. setter(val);
  185. }
  186. };
  187. bool currVal = getter();
  188. Item* item = createMenuItem<Item>(text, CHECKMARK(currVal));
  189. item->setter = setter;
  190. item->val = !currVal;
  191. return item;
  192. }
  193. /** Easy wrapper for createBoolMenuItem() to modify a bool pointer.
  194. */
  195. template <typename T>
  196. ui::MenuItem* createBoolPtrMenuItem(std::string text, T* ptr) {
  197. return createBoolMenuItem(text,
  198. [=]() {return *ptr;},
  199. [=](T val) {*ptr = val;}
  200. );
  201. }
  202. /** Creates a MenuItem that when hovered, opens a submenu with several MenuItems indexed by an integer.
  203. */
  204. inline ui::MenuItem* createIndexSubmenuItem(std::string text, std::vector<std::string> labels, std::function<size_t()> getter, std::function<void(size_t)> setter) {
  205. struct IndexItem : ui::MenuItem {
  206. std::function<void(size_t)> setter;
  207. size_t index;
  208. void onAction(const event::Action& e) override {
  209. setter(index);
  210. }
  211. };
  212. struct Item : ui::MenuItem {
  213. std::function<size_t()> getter;
  214. std::function<void(size_t)> setter;
  215. std::vector<std::string> labels;
  216. ui::Menu* createChildMenu() override {
  217. ui::Menu* menu = new ui::Menu;
  218. size_t currIndex = getter();
  219. for (size_t i = 0; i < labels.size(); i++) {
  220. IndexItem* item = createMenuItem<IndexItem>(labels[i], CHECKMARK(currIndex == i));
  221. item->setter = setter;
  222. item->index = i;
  223. menu->addChild(item);
  224. }
  225. return menu;
  226. }
  227. };
  228. size_t currIndex = getter();
  229. std::string label = (currIndex < labels.size()) ? labels[currIndex] : "";
  230. Item* item = createMenuItem<Item>(text, label + " " + RIGHT_ARROW);
  231. item->getter = getter;
  232. item->setter = setter;
  233. item->labels = labels;
  234. return item;
  235. }
  236. /** Easy wrapper for createIndexSubmenuItem() that controls an integer index at a pointer address.
  237. */
  238. template <typename T>
  239. ui::MenuItem* createIndexPtrSubmenuItem(std::string text, std::vector<std::string> labels, T* ptr) {
  240. return createIndexSubmenuItem(text, labels,
  241. [=]() {return *ptr;},
  242. [=](size_t index) {*ptr = T(index);}
  243. );
  244. }
  245. } // namespace rack