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.

187 lines
7.9KB

  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 event::Action& e) override {
  17. std::thread t([=] {
  18. system::openBrowser(url);
  19. });
  20. t.detach();
  21. }
  22. };
  23. struct TipInfo {
  24. std::string text;
  25. std::string linkText;
  26. std::string linkUrl;
  27. };
  28. // Remember to use “smart quotes.”
  29. static std::vector<TipInfo> tipInfos = {
  30. {"To add a module to the rack, 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 it.", "", ""}, // reviewed
  31. {"Pan around the rack by using the scroll bars, dragging while holding the middle mouse button, 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 "+= / " RACK_MOD_CTRL_NAME "+-.", "", ""}, // reviewed
  32. // {"Want to use VCV Rack as a plugin in your DAW? VCV Rack for DAWs is available now as a 64-bit VST 2 plugin for Ableton Live, Cubase, FL Studio, Reason, Studio One, REAPER, Bitwig, and more. Other plugin formats coming soon.", "Learn more", "https://vcvrack.com/RackForDAWs"}, // reviewed
  33. {"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"}, // reviewed
  34. {"You can search over 2400 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/"}, // reviewed
  35. {"Some developers of free plugins accept donations for their work. Right-click a module panel and select “Info > Donate”.\n\nYou can support VCV Rack by purchasing VCV plugins.", "VCV Library", "https://library.vcvrack.com/"}, // reviewed
  36. {"You can learn more about VCV Rack by browsing the official Rack manual.", "VCV Rack manual", "https://vcvrack.com/manual/"},
  37. {"Follow VCV Rack on Twitter for new modules, product announcements, and development news.", "Twitter @vcvrack", "https://twitter.com/vcvrack"}, // reviewed
  38. {"Did you know that patch cables in Rack can carry up to 16 signals? You can use this feature to build polyphonic patches with modules having 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"}, // reviewed
  39. {"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 official tutorial to get started.", "Plugin Development Tutorial", "https://vcvrack.com/manual/PluginDevelopmentTutorial"}, // reviewed
  40. {"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 entry, and changelog.", "", ""}, // reviewed
  41. {"Did you know that ModularGrid is interconnected with the VCV Library? If a Eurorack 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.\nOn ModularGrid.net, search for the “Available for VCV Rack” link if a hardware module has a virtual Rack version.", "Example: Grayscale Permutation on ModularGrid", "https://www.modulargrid.net/e/grayscale-permutation-18hp"}, // reviewed
  42. // {"", "", ""},
  43. };
  44. struct TipWindow : widget::OpaqueWidget {
  45. ui::Label* label;
  46. UrlButton* linkButton;
  47. TipWindow() {
  48. float margin = 10;
  49. float buttonWidth = 80;
  50. box.size.x = buttonWidth*5 + margin*6;
  51. ui::Label* header = new ui::Label;
  52. header->box.pos.x = margin;
  53. header->box.pos.y = 20;
  54. // header->box.size.x = box.size.x - margin*2;
  55. header->box.size.y = 20;
  56. header->fontSize = 20;
  57. header->text = "Welcome to VCV Rack v" + APP_VERSION;
  58. addChild(header);
  59. label = new ui::Label;
  60. label->box.pos.x = margin;
  61. label->box.pos.y = header->box.getBottom() + margin;
  62. label->box.size.y = 80;
  63. label->box.size.x = box.size.x - margin*2;
  64. addChild(label);
  65. linkButton = new UrlButton;
  66. linkButton->box.pos.x = margin;
  67. linkButton->box.pos.y = label->box.getBottom() + margin;
  68. linkButton->box.size.x = box.size.x - margin*2;
  69. addChild(linkButton);
  70. ui::SequentialLayout* buttonLayout = new ui::SequentialLayout;
  71. buttonLayout->box.pos.x = margin;
  72. buttonLayout->box.pos.y = linkButton->box.getBottom() + margin;
  73. buttonLayout->box.size.x = box.size.x - margin*2;
  74. buttonLayout->spacing = math::Vec(margin, margin);
  75. addChild(buttonLayout);
  76. struct ShowQuantity : Quantity {
  77. void setValue(float value) override {
  78. settings::showTipsOnLaunch = (value > 0.f);
  79. }
  80. float getValue() override {
  81. return settings::showTipsOnLaunch ? 1.f : 0.f;
  82. }
  83. };
  84. static ShowQuantity showQuantity;
  85. ui::OptionButton* showButton = new ui::OptionButton;
  86. showButton->text = "Show tips at startup";
  87. showButton->quantity = &showQuantity;
  88. showButton->box.size.x = buttonWidth * 2 + margin;
  89. buttonLayout->addChild(showButton);
  90. struct PreviousButton : ui::Button {
  91. TipWindow* tipWindow;
  92. void onAction(const event::Action& e) override {
  93. tipWindow->advanceTip(-1);
  94. }
  95. };
  96. PreviousButton* prevButton = new PreviousButton;
  97. prevButton->box.size.x = buttonWidth;
  98. prevButton->text = "◀ Previous";
  99. prevButton->tipWindow = this;
  100. buttonLayout->addChild(prevButton);
  101. struct NextButton : ui::Button {
  102. TipWindow* tipWindow;
  103. void onAction(const event::Action& e) override {
  104. tipWindow->advanceTip();
  105. }
  106. };
  107. NextButton* nextButton = new NextButton;
  108. nextButton->box.size.x = buttonWidth;
  109. nextButton->text = "▶ Next";
  110. nextButton->tipWindow = this;
  111. buttonLayout->addChild(nextButton);
  112. struct CloseButton : ui::Button {
  113. TipWindow* tipWindow;
  114. void onAction(const event::Action& e) override {
  115. tipWindow->getParent()->requestDelete();
  116. }
  117. };
  118. CloseButton* closeButton = new CloseButton;
  119. closeButton->box.size.x = buttonWidth;
  120. closeButton->text = "✖ Close";
  121. closeButton->tipWindow = this;
  122. buttonLayout->addChild(closeButton);
  123. buttonLayout->box.size.y = closeButton->box.size.y;
  124. box.size.y = buttonLayout->box.getBottom() + margin;
  125. // When the TipWindow is created, choose the next tip
  126. advanceTip();
  127. }
  128. void advanceTip(int delta = 1) {
  129. // Increment tip index
  130. settings::tipIndex = math::eucMod(settings::tipIndex + delta, (int) tipInfos.size());
  131. TipInfo& tipInfo = tipInfos[settings::tipIndex];
  132. label->text = tipInfo.text;
  133. linkButton->setVisible(tipInfo.linkText != "");
  134. linkButton->text = tipInfo.linkText;
  135. linkButton->url = tipInfo.linkUrl;
  136. }
  137. void step() override {
  138. box.pos = parent->box.size.minus(box.size).div(2).round();
  139. OpaqueWidget::step();
  140. }
  141. void draw(const DrawArgs& args) override {
  142. bndMenuBackground(args.vg, 0.0, 0.0, box.size.x, box.size.y, 0);
  143. Widget::draw(args);
  144. }
  145. };
  146. widget::Widget* tipWindowCreate() {
  147. ui::MenuOverlay* overlay = new ui::MenuOverlay;
  148. TipWindow* tipWindow = new TipWindow;
  149. overlay->addChild(tipWindow);
  150. return overlay;
  151. }
  152. } // namespace app
  153. } // namespace rack