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.

198 lines
5.1KB

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