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.

177 lines
4.2KB

  1. #include <app/RackScrollWidget.hpp>
  2. #include <app/Scene.hpp>
  3. #include <window.hpp>
  4. #include <context.hpp>
  5. #include <settings.hpp>
  6. namespace rack {
  7. namespace app {
  8. RackScrollWidget::RackScrollWidget() {
  9. zoomWidget = new widget::ZoomWidget;
  10. container->addChild(zoomWidget);
  11. rackWidget = new RackWidget;
  12. rackWidget->box.size = RACK_OFFSET.mult(2);
  13. zoomWidget->addChild(rackWidget);
  14. reset();
  15. }
  16. void RackScrollWidget::reset() {
  17. offset = RACK_OFFSET.mult(zoomWidget->zoom);
  18. offset = offset.minus(math::Vec(30, 30));
  19. }
  20. void RackScrollWidget::step() {
  21. // Clamp zoom
  22. settings::zoom = math::clamp(settings::zoom, -2.f, 2.f);
  23. // Compute zoom from exponential zoom
  24. float zoom = std::pow(2.f, settings::zoom);
  25. if (zoom != zoomWidget->zoom) {
  26. // Set offset based on zoomPos
  27. offset = offset.plus(zoomPos).div(zoomWidget->zoom).mult(zoom).minus(zoomPos);
  28. // Set zoom
  29. zoomWidget->setZoom(zoom);
  30. }
  31. zoomPos = box.size.div(2);
  32. // Compute module bounding box
  33. math::Rect moduleBox = rackWidget->moduleContainer->getChildrenBoundingBox();
  34. if (!moduleBox.size.isFinite())
  35. moduleBox = math::Rect(RACK_OFFSET, math::Vec(0, 0));
  36. // Expand moduleBox by half a screen size
  37. math::Rect scrollBox = moduleBox;
  38. scrollBox.pos = scrollBox.pos.mult(zoom);
  39. scrollBox.size = scrollBox.size.mult(zoom);
  40. scrollBox = scrollBox.grow(box.size.mult(0.6666));
  41. // Expand to the current viewport box so that moving modules (and thus changing the module bounding box) doesn't clamp the scroll offset.
  42. math::Rect viewportBox;
  43. viewportBox.pos = oldOffset;
  44. viewportBox.size = box.size;
  45. scrollBox = scrollBox.expand(viewportBox);
  46. // Reposition widgets
  47. zoomWidget->box = scrollBox;
  48. rackWidget->box.pos = scrollBox.pos.div(zoom).neg();
  49. // Scroll rack if dragging cable near the edge of the screen
  50. math::Vec pos = APP->scene->mousePos;
  51. math::Rect viewport = getViewport(box.zeroPos());
  52. if (rackWidget->incompleteCable) {
  53. float margin = 20.0;
  54. float speed = 15.0;
  55. if (pos.x <= viewport.pos.x + margin)
  56. offset.x -= speed;
  57. if (pos.x >= viewport.pos.x + viewport.size.x - margin)
  58. offset.x += speed;
  59. if (pos.y <= viewport.pos.y + margin)
  60. offset.y -= speed;
  61. if (pos.y >= viewport.pos.y + viewport.size.y - margin)
  62. offset.y += speed;
  63. }
  64. // Hide scrollbars if fullscreen
  65. hideScrollbars = APP->window->isFullScreen();
  66. ScrollWidget::step();
  67. oldOffset = offset;
  68. }
  69. void RackScrollWidget::draw(const DrawArgs& args) {
  70. ScrollWidget::draw(args);
  71. }
  72. void RackScrollWidget::onHoverKey(const HoverKeyEvent& e) {
  73. ScrollWidget::onHoverKey(e);
  74. if (e.isConsumed())
  75. return;
  76. // Scroll with arrow keys
  77. float arrowSpeed = 32.f;
  78. if ((e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL)
  79. arrowSpeed /= 4.f;
  80. if ((e.mods & RACK_MOD_MASK) == GLFW_MOD_SHIFT)
  81. arrowSpeed *= 4.f;
  82. if ((e.mods & RACK_MOD_MASK) == (RACK_MOD_CTRL | GLFW_MOD_SHIFT))
  83. arrowSpeed /= 16.f;
  84. if (e.action == RACK_HELD) {
  85. if (e.key == GLFW_KEY_LEFT) {
  86. offset.x -= arrowSpeed;
  87. e.consume(this);
  88. }
  89. if (e.key == GLFW_KEY_RIGHT) {
  90. offset.x += arrowSpeed;
  91. e.consume(this);
  92. }
  93. if (e.key == GLFW_KEY_UP) {
  94. offset.y -= arrowSpeed;
  95. e.consume(this);
  96. }
  97. if (e.key == GLFW_KEY_DOWN) {
  98. offset.y += arrowSpeed;
  99. e.consume(this);
  100. }
  101. }
  102. }
  103. void RackScrollWidget::onHoverScroll(const HoverScrollEvent& e) {
  104. ScrollWidget::onHoverScroll(e);
  105. if (e.isConsumed())
  106. return;
  107. if ((APP->window->getMods() & RACK_MOD_MASK) == RACK_MOD_CTRL) {
  108. // Increase zoom
  109. float zoomDelta = e.scrollDelta.y / 50 / 4;
  110. if (settings::invertZoom)
  111. zoomDelta *= -1;
  112. settings::zoom += zoomDelta;
  113. zoomPos = e.pos;
  114. e.consume(this);
  115. }
  116. }
  117. void RackScrollWidget::onHover(const HoverEvent& e) {
  118. ScrollWidget::onHover(e);
  119. // Hide menu bar if fullscreen and moving mouse over the RackScrollWidget
  120. if (APP->window->isFullScreen()) {
  121. APP->scene->menuBar->hide();
  122. }
  123. }
  124. void RackScrollWidget::onButton(const ButtonEvent& e) {
  125. ScrollWidget::onButton(e);
  126. if (e.isConsumed())
  127. return;
  128. // Zoom in/out with extra mouse buttons
  129. if (e.action == GLFW_PRESS) {
  130. if (e.button == GLFW_MOUSE_BUTTON_4) {
  131. settings::zoom -= 0.5f;
  132. e.consume(this);
  133. }
  134. if (e.button == GLFW_MOUSE_BUTTON_5) {
  135. settings::zoom += 0.5f;
  136. e.consume(this);
  137. }
  138. }
  139. }
  140. } // namespace app
  141. } // namespace rack