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.

194 lines
8.2KB

  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. // Remember to use “smart quotes.”
  26. static const std::vector<TipInfo> tipInfos = {
  27. {"To add a module to your patch, right-click an empty rack space or press Enter. Click and drag a module from the Module Browser into the desired rack space.\n\nYou can force-move modules by holding " RACK_MOD_CTRL_NAME " while dragging them.\n\nClick and drag on empty rack space to select multiple modules.", "", ""},
  28. {"Pan around the rack by using the scroll bars, dragging while holding the middle mouse button, " RACK_MOD_ALT_NAME "+clicking and dragging, or pressing the arrow keys. Arrow key panning speed can be modified by holding " RACK_MOD_CTRL_NAME ", " RACK_MOD_SHIFT_NAME ", or " RACK_MOD_CTRL_NAME "+" RACK_MOD_SHIFT_NAME ".\n\nZoom in and out using the View menu, " RACK_MOD_CTRL_NAME "+scroll, or " RACK_MOD_CTRL_NAME "+= and " RACK_MOD_CTRL_NAME "+minus.", "", ""},
  29. // {"Want to use VCV Rack as a plugin in your DAW? VCV Rack Studio Edition is available now as a 64-bit VST 2 plugin for Ableton Live, FL Studio, Reason, REAPER, Bitwig, and more.", "Learn more", "https://vcvrack.com/Rack"},
  30. {"You can use Rack in fullscreen mode by selecting “View > Fullscreen“ or pressing F11.\n\nIn fullscreen mode, the menu bar and scroll bars are hidden. This is ideal for screen recording with VCV Recorder.", "Get VCV Recorder", "https://vcvrack.com/Recorder"},
  31. {"You can browse thousands of modules on the VCV Library website.\n\nRegister for a VCV account, log into Rack using the Library menu, and browse the VCV Library to add or purchase modules. Keep all plugins up to date by clicking “Library > Update all”.", "VCV Library", "https://library.vcvrack.com/"},
  32. {"Some developers of free plugins accept donations for their work. Right-click your favorite module's panel and select “Info > Donate”.\n\nYou can also donate via the module's VCV Library page.", "VCV Library", "https://library.vcvrack.com/"},
  33. {"You can learn more about VCV Rack by browsing the official manual.", "VCV Rack manual", "https://vcvrack.com/manual/"},
  34. {"Follow VCV Rack on Twitter for new module announcements, development news, and featured artists/music.", "Twitter @vcvrack", "https://twitter.com/vcvrack"},
  35. {"Patch cables in Rack can carry up to 16 signals. You can use this feature to build polyphonic patches using modules with the “Polyphonic” tag. Cables carrying more than 1 signal appear thicker than normal cables. To try out polyphony, add the VCV MIDI-CV module to your patch, right-click its panel, and select your desired number of polyphonic channels.", "Learn more about polyphony in VCV Rack", "https://vcvrack.com/manual/Polyphony"},
  36. {"Know C++ programming and want to create your own modules for Rack? Developing Rack modules is a great way to learn digital signal processing and quickly test your ideas with an easy-to-learn platform.\n\nDownload the Rack SDK and follow the development tutorial to get started.", "Plugin Development Tutorial", "https://vcvrack.com/manual/PluginDevelopmentTutorial"},
  37. {"Wondering how to use a particular module? Right-click its panel and choose “Info > User manual”.\n\nYou can also open the module's Info menu to view the module's tags, website, VCV Library page, and changelog, if available.", "", ""},
  38. {"Did you know that ModularGrid is integrated with the VCV Library? If a Eurorack hardware version of a Rack module is available, right-click its panel and choose “Info > ModularGrid”, or click the “ModularGrid” link on its VCV Library page.\n\nOn ModularGrid.net, search for the VCV logo for certain hardware modules.", "Example: Grayscale Permutation on ModularGrid", "https://www.modulargrid.net/e/grayscale-permutation-18hp"},
  39. {"When a context menu is open, you can " RACK_MOD_CTRL_NAME "+click a menu item to keep the menu open. This can be useful when browsing module presets or settings.", "", ""},
  40. // {"", "", ""},
  41. };
  42. struct TipWindow : widget::OpaqueWidget {
  43. ui::SequentialLayout* layout;
  44. ui::SequentialLayout* buttonLayout;
  45. ui::Label* label;
  46. UrlButton* linkButton;
  47. TipWindow() {
  48. box.size = math::Vec(550, 200);
  49. const float margin = 10;
  50. const float buttonWidth = 100;
  51. layout = new ui::SequentialLayout;
  52. layout->box.pos = math::Vec(0, 10);
  53. layout->box.size = box.size;
  54. layout->orientation = ui::SequentialLayout::VERTICAL_ORIENTATION;
  55. layout->margin = math::Vec(margin, margin);
  56. layout->spacing = math::Vec(margin, margin);
  57. layout->wrap = false;
  58. addChild(layout);
  59. ui::Label* header = new ui::Label;
  60. // header->box.size.x = box.size.x - 2*margin;
  61. header->box.size.y = 20;
  62. header->fontSize = 20;
  63. header->text = "Welcome to " + APP_NAME + " " + APP_VERSION;
  64. layout->addChild(header);
  65. label = new ui::Label;
  66. label->box.size.y = 80;
  67. label->box.size.x = box.size.x - 2*margin;
  68. layout->addChild(label);
  69. // Container for link button so hiding it won't shift layout
  70. widget::Widget* linkPlaceholder = new widget::Widget;
  71. layout->addChild(linkPlaceholder);
  72. linkButton = new UrlButton;
  73. linkButton->box.size.x = box.size.x - 2*margin;
  74. linkPlaceholder->box.size = linkButton->box.size;
  75. linkPlaceholder->addChild(linkButton);
  76. buttonLayout = new ui::SequentialLayout;
  77. buttonLayout->box.size.x = box.size.x - 2*margin;
  78. buttonLayout->spacing = math::Vec(margin, margin);
  79. layout->addChild(buttonLayout);
  80. struct ShowQuantity : Quantity {
  81. void setValue(float value) override {
  82. settings::showTipsOnLaunch = (value > 0.f);
  83. }
  84. float getValue() override {
  85. return settings::showTipsOnLaunch ? 1.f : 0.f;
  86. }
  87. };
  88. static ShowQuantity showQuantity;
  89. ui::OptionButton* showButton = new ui::OptionButton;
  90. showButton->box.size.x = 200;
  91. showButton->text = "Show tips at startup";
  92. showButton->quantity = &showQuantity;
  93. buttonLayout->addChild(showButton);
  94. struct PreviousButton : ui::Button {
  95. TipWindow* tipWindow;
  96. void onAction(const ActionEvent& e) override {
  97. tipWindow->advanceTip(-1);
  98. }
  99. };
  100. PreviousButton* prevButton = new PreviousButton;
  101. prevButton->box.size.x = buttonWidth;
  102. prevButton->text = "◀ Previous";
  103. prevButton->tipWindow = this;
  104. buttonLayout->addChild(prevButton);
  105. struct NextButton : ui::Button {
  106. TipWindow* tipWindow;
  107. void onAction(const ActionEvent& e) override {
  108. tipWindow->advanceTip();
  109. }
  110. };
  111. NextButton* nextButton = new NextButton;
  112. nextButton->box.size.x = buttonWidth;
  113. nextButton->text = "▶ Next";
  114. nextButton->tipWindow = this;
  115. buttonLayout->addChild(nextButton);
  116. struct CloseButton : ui::Button {
  117. TipWindow* tipWindow;
  118. void onAction(const ActionEvent& e) override {
  119. tipWindow->getParent()->requestDelete();
  120. }
  121. };
  122. CloseButton* closeButton = new CloseButton;
  123. closeButton->box.size.x = buttonWidth;
  124. closeButton->text = "✖ Close";
  125. closeButton->tipWindow = this;
  126. buttonLayout->addChild(closeButton);
  127. buttonLayout->box.size.y = closeButton->box.size.y;
  128. // When the TipWindow is created, choose the next tip
  129. advanceTip();
  130. }
  131. void advanceTip(int delta = 1) {
  132. // Increment tip index
  133. settings::tipIndex = math::eucMod(settings::tipIndex + delta, (int) tipInfos.size());
  134. const TipInfo& tipInfo = tipInfos[settings::tipIndex];
  135. label->text = tipInfo.text;
  136. linkButton->setVisible(tipInfo.linkText != "");
  137. linkButton->text = tipInfo.linkText;
  138. linkButton->url = tipInfo.linkUrl;
  139. }
  140. void step() override {
  141. OpaqueWidget::step();
  142. box.pos = parent->box.size.minus(box.size).div(2).round();
  143. }
  144. void draw(const DrawArgs& args) override {
  145. bndMenuBackground(args.vg, 0.0, 0.0, box.size.x, box.size.y, 0);
  146. Widget::draw(args);
  147. }
  148. };
  149. widget::Widget* tipWindowCreate() {
  150. ui::MenuOverlay* overlay = new ui::MenuOverlay;
  151. overlay->bgColor = nvgRGBAf(0, 0, 0, 0.33);
  152. TipWindow* tipWindow = new TipWindow;
  153. overlay->addChild(tipWindow);
  154. return overlay;
  155. }
  156. } // namespace app
  157. } // namespace rack