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.

157 lines
4.3KB

  1. /*
  2. * Resize handle for DPF
  3. * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any purpose with
  6. * or without fee is hereby granted, provided that the above copyright notice and this
  7. * permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
  10. * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
  11. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  12. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  13. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #pragma once
  17. #include "TopLevelWidget.hpp"
  18. #include "../dgl/Color.hpp"
  19. START_NAMESPACE_DGL
  20. /** Resize handle for DPF windows, will sit on bottom-right. */
  21. class ResizeHandle : public TopLevelWidget
  22. {
  23. public:
  24. /** Constructor for placing this handle on top of a window. */
  25. explicit ResizeHandle(Window& window)
  26. : TopLevelWidget(window),
  27. handleSize(16),
  28. hasCursor(false),
  29. isResizing(false)
  30. {
  31. resetArea();
  32. }
  33. /** Overloaded constructor, will fetch the window from an existing top-level widget. */
  34. explicit ResizeHandle(TopLevelWidget* const tlw)
  35. : TopLevelWidget(tlw->getWindow()),
  36. handleSize(16),
  37. hasCursor(false),
  38. isResizing(false)
  39. {
  40. resetArea();
  41. }
  42. /** Set the handle size, minimum 16. */
  43. void setHandleSize(const uint size)
  44. {
  45. handleSize = std::max(16u, size);
  46. resetArea();
  47. }
  48. protected:
  49. void onDisplay() override
  50. {
  51. /* Nothing here, we purposefully avoid drawing anything.
  52. * The resize handle is on the plugin UI directly. */
  53. }
  54. bool onMouse(const MouseEvent& ev) override
  55. {
  56. if (ev.button != 1)
  57. return false;
  58. if (ev.press && area.contains(ev.pos))
  59. {
  60. isResizing = true;
  61. resizingSize = Size<double>(getWidth(), getHeight());
  62. lastResizePoint = ev.pos;
  63. return true;
  64. }
  65. if (isResizing && ! ev.press)
  66. {
  67. isResizing = false;
  68. recheckCursor(ev.pos);
  69. return true;
  70. }
  71. return false;
  72. }
  73. bool onMotion(const MotionEvent& ev) override
  74. {
  75. if (! isResizing)
  76. {
  77. recheckCursor(ev.pos);
  78. return false;
  79. }
  80. const Size<double> offset(ev.pos.getX() - lastResizePoint.getX(),
  81. ev.pos.getY() - lastResizePoint.getY());
  82. resizingSize += offset;
  83. lastResizePoint = ev.pos;
  84. const double scaleFactor = getScaleFactor();
  85. const uint minWidth = 648 * scaleFactor;
  86. const uint minHeight = 538 * scaleFactor;
  87. if (resizingSize.getWidth() < minWidth)
  88. resizingSize.setWidth(minWidth);
  89. else if (resizingSize.getWidth() > 16384)
  90. resizingSize.setWidth(16384);
  91. if (resizingSize.getHeight() < minHeight)
  92. resizingSize.setHeight(minHeight);
  93. else if (resizingSize.getHeight() > 16384)
  94. resizingSize.setHeight(16384);
  95. setSize(resizingSize.getWidth(), resizingSize.getHeight());
  96. return true;
  97. }
  98. void onResize(const ResizeEvent& ev) override
  99. {
  100. TopLevelWidget::onResize(ev);
  101. resetArea();
  102. }
  103. private:
  104. Rectangle<uint> area;
  105. uint handleSize;
  106. // event handling state
  107. bool hasCursor, isResizing;
  108. Point<double> lastResizePoint;
  109. Size<double> resizingSize;
  110. void recheckCursor(const Point<double>& pos)
  111. {
  112. const bool shouldHaveCursor = area.contains(pos);
  113. if (shouldHaveCursor == hasCursor)
  114. return;
  115. hasCursor = shouldHaveCursor;
  116. setCursor(shouldHaveCursor ? kMouseCursorDiagonal : kMouseCursorArrow);
  117. }
  118. void resetArea()
  119. {
  120. const double scaleFactor = getScaleFactor();
  121. const uint size = handleSize * scaleFactor;
  122. area = Rectangle<uint>(getWidth() - size,
  123. getHeight() - size,
  124. size, size);
  125. }
  126. DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ResizeHandle)
  127. };
  128. END_NAMESPACE_DGL