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.

216 lines
5.5KB

  1. #include <thread>
  2. #include <osdialog.h>
  3. #include <app/Scene.hpp>
  4. #include <app/ModuleBrowser.hpp>
  5. #include <app/TipWindow.hpp>
  6. #include <app/MenuBar.hpp>
  7. #include <context.hpp>
  8. #include <system.hpp>
  9. #include <network.hpp>
  10. #include <history.hpp>
  11. #include <settings.hpp>
  12. #include <patch.hpp>
  13. #include <asset.hpp>
  14. namespace rack {
  15. namespace app {
  16. struct Scene::Internal {
  17. };
  18. struct FrameRateWidget : widget::TransparentWidget {
  19. void draw(const DrawArgs& args) override {
  20. std::string text = string::f("%.2lf Hz", 1.0 / APP->window->getLastFrameDuration());
  21. bndLabel(args.vg, 0.0, 0.0, INFINITY, INFINITY, -1, text.c_str());
  22. }
  23. };
  24. Scene::Scene() {
  25. internal = new Internal;
  26. rackScroll = new RackScrollWidget;
  27. addChild(rackScroll);
  28. rack = rackScroll->rackWidget;
  29. menuBar = createMenuBar();
  30. addChild(menuBar);
  31. moduleBrowser = moduleBrowserCreate();
  32. moduleBrowser->hide();
  33. addChild(moduleBrowser);
  34. if (settings::showTipsOnLaunch) {
  35. addChild(tipWindowCreate());
  36. }
  37. // frameRateWidget = new FrameRateWidget;
  38. // frameRateWidget->box.size = math::Vec(80.0, 30.0);
  39. // frameRateWidget->hide();
  40. // addChild(frameRateWidget);
  41. }
  42. Scene::~Scene() {
  43. delete internal;
  44. }
  45. void Scene::step() {
  46. if (APP->window->isFullScreen()) {
  47. // Expand RackScrollWidget to cover entire screen if fullscreen
  48. rackScroll->box.pos.y = 0;
  49. }
  50. else {
  51. // Always show MenuBar if not fullscreen
  52. menuBar->show();
  53. rackScroll->box.pos.y = menuBar->box.size.y;
  54. }
  55. // frameRateWidget->box.pos.x = box.size.x - frameRateWidget->box.size.x;
  56. // Resize owned descendants
  57. menuBar->box.size.x = box.size.x;
  58. rackScroll->box.size = box.size.minus(rackScroll->box.pos);
  59. // Autosave periodically
  60. if (settings::autosaveInterval > 0.0) {
  61. double time = glfwGetTime();
  62. if (time - lastAutosaveTime >= settings::autosaveInterval) {
  63. lastAutosaveTime = time;
  64. APP->patch->saveAutosave();
  65. settings::save(asset::settingsPath);
  66. }
  67. }
  68. Widget::step();
  69. }
  70. void Scene::draw(const DrawArgs& args) {
  71. Widget::draw(args);
  72. }
  73. void Scene::onHover(const event::Hover& e) {
  74. mousePos = e.pos;
  75. if (mousePos.y < menuBar->box.size.y) {
  76. menuBar->show();
  77. }
  78. OpaqueWidget::onHover(e);
  79. }
  80. void Scene::onDragHover(const event::DragHover& e) {
  81. mousePos = e.pos;
  82. OpaqueWidget::onDragHover(e);
  83. }
  84. void Scene::onHoverKey(const event::HoverKey& e) {
  85. OpaqueWidget::onHoverKey(e);
  86. if (e.isConsumed())
  87. return;
  88. if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) {
  89. // DEBUG("key '%d '%c' scancode %d '%c' keyName '%s'", e.key, e.key, e.scancode, e.scancode, e.keyName.c_str());
  90. if (e.keyName == "n" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
  91. APP->patch->loadTemplateDialog();
  92. e.consume(this);
  93. }
  94. if (e.keyName == "q" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
  95. APP->window->close();
  96. e.consume(this);
  97. }
  98. if (e.keyName == "o" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
  99. APP->patch->loadDialog();
  100. e.consume(this);
  101. }
  102. if (e.keyName == "o" && (e.mods & RACK_MOD_MASK) == (RACK_MOD_CTRL | GLFW_MOD_SHIFT)) {
  103. APP->patch->revertDialog();
  104. e.consume(this);
  105. }
  106. if (e.keyName == "s" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
  107. APP->patch->saveDialog();
  108. e.consume(this);
  109. }
  110. if (e.keyName == "s" && (e.mods & RACK_MOD_MASK) == (RACK_MOD_CTRL | GLFW_MOD_SHIFT)) {
  111. APP->patch->saveAsDialog();
  112. e.consume(this);
  113. }
  114. if (e.keyName == "z" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
  115. APP->history->undo();
  116. e.consume(this);
  117. }
  118. if (e.keyName == "z" && (e.mods & RACK_MOD_MASK) == (RACK_MOD_CTRL | GLFW_MOD_SHIFT)) {
  119. APP->history->redo();
  120. e.consume(this);
  121. }
  122. if (e.keyName == "-" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
  123. float zoom = settings::zoom;
  124. zoom *= 2;
  125. zoom = std::ceil(zoom - 0.01f) - 1;
  126. zoom /= 2;
  127. settings::zoom = zoom;
  128. e.consume(this);
  129. }
  130. // Numpad has a "+" key, but the main keyboard section hides it under "="
  131. if ((e.keyName == "=" || e.keyName == "+") && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
  132. float zoom = settings::zoom;
  133. zoom *= 2;
  134. zoom = std::floor(zoom + 0.01f) + 1;
  135. zoom /= 2;
  136. settings::zoom = zoom;
  137. e.consume(this);
  138. }
  139. if ((e.keyName == "0") && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
  140. settings::zoom = 0.f;
  141. e.consume(this);
  142. }
  143. if ((e.key == GLFW_KEY_ENTER || e.key == GLFW_KEY_KP_ENTER) && (e.mods & RACK_MOD_MASK) == 0) {
  144. moduleBrowser->show();
  145. e.consume(this);
  146. }
  147. if (e.key == GLFW_KEY_F1 && (e.mods & RACK_MOD_MASK) == 0) {
  148. std::thread t([] {
  149. system::openBrowser("https://vcvrack.com/manual/");
  150. });
  151. t.detach();
  152. e.consume(this);
  153. }
  154. if (e.key == GLFW_KEY_F3 && (e.mods & RACK_MOD_MASK) == 0) {
  155. settings::cpuMeter ^= true;
  156. e.consume(this);
  157. }
  158. if (e.key == GLFW_KEY_F11 && (e.mods & RACK_MOD_MASK) == 0) {
  159. APP->window->setFullScreen(!APP->window->isFullScreen());
  160. // The MenuBar will be hidden when the mouse moves over the RackScrollWidget.
  161. // menuBar->hide();
  162. e.consume(this);
  163. }
  164. // Alternate key command for exiting fullscreen, since F11 doesn't work reliably on Mac due to "Show desktop" OS binding.
  165. if (e.key == GLFW_KEY_ESCAPE && (e.mods & RACK_MOD_MASK) == 0) {
  166. if (APP->window->isFullScreen())
  167. APP->window->setFullScreen(false);
  168. e.consume(this);
  169. }
  170. }
  171. }
  172. void Scene::onPathDrop(const event::PathDrop& e) {
  173. if (e.paths.size() >= 1) {
  174. const std::string& path = e.paths[0];
  175. if (system::getExtension(path) == ".vcv") {
  176. APP->patch->loadPathDialog(path);
  177. e.consume(this);
  178. return;
  179. }
  180. }
  181. OpaqueWidget::onPathDrop(e);
  182. }
  183. } // namespace app
  184. } // namespace rack