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.

209 lines
6.6KB

  1. #include <thread>
  2. #include <app/TipWindow.hpp>
  3. #include <widget/OpaqueWidget.hpp>
  4. #include <ui/MenuOverlay.hpp>
  5. #include <ui/Label.hpp>
  6. #include <ui/Button.hpp>
  7. #include <ui/OptionButton.hpp>
  8. #include <ui/MenuItem.hpp>
  9. #include <ui/SequentialLayout.hpp>
  10. #include <settings.hpp>
  11. #include <system.hpp>
  12. namespace rack {
  13. namespace app {
  14. struct UrlButton : ui::Button {
  15. std::string url;
  16. void onAction(const ActionEvent& e) override {
  17. system::openBrowser(url);
  18. }
  19. };
  20. struct TipInfo {
  21. std::string text;
  22. std::string linkText;
  23. std::string linkUrl;
  24. };
  25. static std::vector<TipInfo> getTipInfos() {
  26. // Remember to use “smart quotes.”
  27. return {
  28. {string::translate("TipWindow.addModule"), "", ""},
  29. {string::f(string::translate("TipWindow.moveRack"),
  30. widget::getKeyCommandName(0, RACK_MOD_ALT) + string::translate("key.click"),
  31. string::translate("key.ctrl"),
  32. string::translate("key.shift"),
  33. string::translate("key.ctrl"),
  34. string::translate("key.shift"),
  35. string::translate("key.ctrl"),
  36. widget::getKeyCommandName(GLFW_KEY_EQUAL, RACK_MOD_CTRL),
  37. widget::getKeyCommandName(GLFW_KEY_MINUS, RACK_MOD_CTRL)),
  38. "", ""},
  39. {string::translate("TipWindow.fullscreen"), string::translate("TipWindow.fullscreenButton"), "https://vcvrack.com/Recorder"},
  40. {string::translate("TipWindow.library"), string::translate("TipWindow.libraryButton"), "https://library.vcvrack.com/"},
  41. {string::translate("TipWindow.donation"), string::translate("TipWindow.libraryButton"), "https://library.vcvrack.com/"},
  42. {string::translate("TipWindow.daw"), string::translate("TipWindow.learnMore"), "https://vcvrack.com/Rack"},
  43. {string::translate("TipWindow.manual"), string::translate("TipWindow.manualButton"), "https://vcvrack.com/manual/"},
  44. {string::translate("TipWindow.twitter"), string::translate("TipWindow.twitterHandle"), "https://twitter.com/vcvrack"},
  45. {string::translate("TipWindow.polyphony"), string::translate("TipWindow.polyphonyButton"), "https://vcvrack.com/manual/Polyphony"},
  46. {string::translate("TipWindow.develop"), string::translate("TipWindow.developButton"), "https://vcvrack.com/manual/PluginDevelopmentTutorial"},
  47. {string::translate("TipWindow.moduleManual"), "", ""},
  48. {string::translate("TipWindow.modularGrid"), string::translate("TipWindow.modularGridButton"), "https://www.modulargrid.net/e/grayscale-permutation-18hp"},
  49. {string::f(string::translate("TipWindow.menuKeepOpen"),
  50. widget::getKeyCommandName(0, RACK_MOD_CTRL) + string::translate("key.click")),
  51. "", ""},
  52. // {"", "", ""},
  53. };
  54. }
  55. struct TipWindow : widget::OpaqueWidget {
  56. ui::SequentialLayout* layout;
  57. ui::SequentialLayout* buttonLayout;
  58. ui::Label* label;
  59. UrlButton* linkButton;
  60. TipWindow() {
  61. box.size = math::Vec(550, 200);
  62. const float margin = 10;
  63. const float buttonWidth = 100;
  64. layout = new ui::SequentialLayout;
  65. layout->box.pos = math::Vec(0, 10);
  66. layout->box.size = box.size;
  67. layout->orientation = ui::SequentialLayout::VERTICAL_ORIENTATION;
  68. layout->margin = math::Vec(margin, margin);
  69. layout->spacing = math::Vec(margin, margin);
  70. layout->wrap = false;
  71. addChild(layout);
  72. ui::Label* header = new ui::Label;
  73. // header->box.size.x = box.size.x - 2*margin;
  74. header->box.size.y = 20;
  75. header->fontSize = 20;
  76. header->text = string::f(string::translate("TipWindow.welcome"), APP_NAME + " " + APP_EDITION_NAME + " " + APP_VERSION);
  77. layout->addChild(header);
  78. label = new ui::Label;
  79. label->box.size.y = 80;
  80. label->box.size.x = box.size.x - 2*margin;
  81. layout->addChild(label);
  82. // Container for link button so hiding it won't shift layout
  83. widget::Widget* linkPlaceholder = new widget::Widget;
  84. layout->addChild(linkPlaceholder);
  85. linkButton = new UrlButton;
  86. linkButton->box.size.x = box.size.x - 2*margin;
  87. linkPlaceholder->box.size = linkButton->box.size;
  88. linkPlaceholder->addChild(linkButton);
  89. buttonLayout = new ui::SequentialLayout;
  90. buttonLayout->box.size.x = box.size.x - 2*margin;
  91. buttonLayout->spacing = math::Vec(margin, margin);
  92. layout->addChild(buttonLayout);
  93. struct ShowQuantity : Quantity {
  94. void setValue(float value) override {
  95. settings::showTipsOnLaunch = (value > 0.f);
  96. }
  97. float getValue() override {
  98. return settings::showTipsOnLaunch ? 1.f : 0.f;
  99. }
  100. };
  101. static ShowQuantity showQuantity;
  102. ui::OptionButton* showButton = new ui::OptionButton;
  103. showButton->box.size.x = 200;
  104. showButton->text = string::translate("TipWindow.startup");
  105. showButton->quantity = &showQuantity;
  106. buttonLayout->addChild(showButton);
  107. struct PreviousButton : ui::Button {
  108. TipWindow* tipWindow;
  109. void onAction(const ActionEvent& e) override {
  110. tipWindow->advanceTip(-1);
  111. }
  112. };
  113. PreviousButton* prevButton = new PreviousButton;
  114. prevButton->box.size.x = buttonWidth;
  115. prevButton->text = "◀ " + string::translate("TipWindow.previous");
  116. prevButton->tipWindow = this;
  117. buttonLayout->addChild(prevButton);
  118. struct NextButton : ui::Button {
  119. TipWindow* tipWindow;
  120. void onAction(const ActionEvent& e) override {
  121. tipWindow->advanceTip();
  122. }
  123. };
  124. NextButton* nextButton = new NextButton;
  125. nextButton->box.size.x = buttonWidth;
  126. nextButton->text = "▶ " + string::translate("TipWindow.next");
  127. nextButton->tipWindow = this;
  128. buttonLayout->addChild(nextButton);
  129. struct CloseButton : ui::Button {
  130. TipWindow* tipWindow;
  131. void onAction(const ActionEvent& e) override {
  132. tipWindow->getParent()->requestDelete();
  133. }
  134. };
  135. CloseButton* closeButton = new CloseButton;
  136. closeButton->box.size.x = buttonWidth;
  137. closeButton->text = "✖ " + string::translate("TipWindow.close");
  138. closeButton->tipWindow = this;
  139. buttonLayout->addChild(closeButton);
  140. buttonLayout->box.size.y = closeButton->box.size.y;
  141. // When the TipWindow is created, choose the next tip
  142. advanceTip();
  143. }
  144. void advanceTip(int delta = 1) {
  145. std::vector<TipInfo> tipInfos = getTipInfos();
  146. // Increment tip index
  147. settings::tipIndex = math::eucMod(settings::tipIndex + delta, (int) tipInfos.size());
  148. const TipInfo& tipInfo = tipInfos[settings::tipIndex];
  149. label->text = tipInfo.text;
  150. linkButton->setVisible(tipInfo.linkText != "");
  151. linkButton->text = tipInfo.linkText;
  152. linkButton->url = tipInfo.linkUrl;
  153. }
  154. void step() override {
  155. OpaqueWidget::step();
  156. box.pos = parent->box.size.minus(box.size).div(2).round();
  157. }
  158. void draw(const DrawArgs& args) override {
  159. bndMenuBackground(args.vg, 0.0, 0.0, box.size.x, box.size.y, 0);
  160. Widget::draw(args);
  161. }
  162. };
  163. widget::Widget* tipWindowCreate() {
  164. ui::MenuOverlay* overlay = new ui::MenuOverlay;
  165. overlay->bgColor = nvgRGBAf(0, 0, 0, 0.33);
  166. TipWindow* tipWindow = new TipWindow;
  167. overlay->addChild(tipWindow);
  168. return overlay;
  169. }
  170. } // namespace app
  171. } // namespace rack