Collection of DPF-based plugins for packaging
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.

213 lines
6.0KB

  1. /*
  2. * Resize handle for DPF
  3. * Copyright (C) 2021-2022 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 "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. /** Overloaded constructor, will fetch the window from an existing top-level widget. */
  25. explicit ResizeHandle(TopLevelWidget* const tlw)
  26. : TopLevelWidget(tlw->getWindow()),
  27. handleSize(16),
  28. hasCursor(false),
  29. isResizing(false)
  30. {
  31. resetArea();
  32. }
  33. /** Set the handle size, minimum 16.
  34. * Scale factor is automatically applied on top of this size as needed */
  35. void setHandleSize(const uint size)
  36. {
  37. handleSize = std::max(16u, size);
  38. resetArea();
  39. }
  40. protected:
  41. void onDisplay() override
  42. {
  43. const GraphicsContext& context(getGraphicsContext());
  44. const double lineWidth = 1.0 * getScaleFactor();
  45. glMatrixMode(GL_MODELVIEW);
  46. glLineWidth(lineWidth);
  47. // draw white lines, 1px wide
  48. glColor3f(1.0f, 1.0f, 1.0f);
  49. drawLine(l1);
  50. drawLine(l2);
  51. drawLine(l3);
  52. // draw black lines, offset by 1px and 1px wide
  53. glColor3f(0.0f, 0.0f, 0.0f);
  54. Line<double> l1b(l1), l2b(l2), l3b(l3);
  55. l1b.moveBy(lineWidth, lineWidth);
  56. l2b.moveBy(lineWidth, lineWidth);
  57. l3b.moveBy(lineWidth, lineWidth);
  58. drawLine(l1b);
  59. drawLine(l2b);
  60. drawLine(l3b);
  61. }
  62. bool onMouse(const MouseEvent& ev) override
  63. {
  64. if (ev.button != 1)
  65. return false;
  66. if (ev.press && area.contains(ev.pos))
  67. {
  68. isResizing = true;
  69. resizingSize = Size<double>(getWidth(), getHeight());
  70. lastResizePoint = ev.pos;
  71. return true;
  72. }
  73. if (isResizing && ! ev.press)
  74. {
  75. isResizing = false;
  76. recheckCursor(ev.pos);
  77. return true;
  78. }
  79. return false;
  80. }
  81. bool onMotion(const MotionEvent& ev) override
  82. {
  83. if (! isResizing)
  84. {
  85. recheckCursor(ev.pos);
  86. return false;
  87. }
  88. const Size<double> offset(ev.pos.getX() - lastResizePoint.getX(),
  89. ev.pos.getY() - lastResizePoint.getY());
  90. resizingSize += offset;
  91. lastResizePoint = ev.pos;
  92. // TODO keepAspectRatio
  93. bool keepAspectRatio;
  94. const Size<uint> minSize(getWindow().getGeometryConstraints(keepAspectRatio));
  95. const uint minWidth = minSize.getWidth();
  96. const uint minHeight = minSize.getHeight();
  97. if (resizingSize.getWidth() < minWidth)
  98. resizingSize.setWidth(minWidth);
  99. if (resizingSize.getWidth() > 16384)
  100. resizingSize.setWidth(16384);
  101. if (resizingSize.getHeight() < minHeight)
  102. resizingSize.setHeight(minHeight);
  103. if (resizingSize.getHeight() > 16384)
  104. resizingSize.setHeight(16384);
  105. setSize(resizingSize.getWidth(), resizingSize.getHeight());
  106. return true;
  107. }
  108. void onResize(const ResizeEvent& ev) override
  109. {
  110. TopLevelWidget::onResize(ev);
  111. resetArea();
  112. }
  113. private:
  114. Rectangle<uint> area;
  115. Line<double> l1, l2, l3;
  116. uint handleSize;
  117. // event handling state
  118. bool hasCursor, isResizing;
  119. Point<double> lastResizePoint;
  120. Size<double> resizingSize;
  121. void recheckCursor(const Point<double>& pos)
  122. {
  123. const bool shouldHaveCursor = area.contains(pos);
  124. if (shouldHaveCursor == hasCursor)
  125. return;
  126. hasCursor = shouldHaveCursor;
  127. setCursor(shouldHaveCursor ? kMouseCursorDiagonal : kMouseCursorArrow);
  128. }
  129. void resetArea()
  130. {
  131. const double scaleFactor = getScaleFactor();
  132. const uint margin = 0.0 * scaleFactor;
  133. const uint size = handleSize * scaleFactor;
  134. area = Rectangle<uint>(getWidth() - size - margin,
  135. getHeight() - size - margin,
  136. size, size);
  137. recreateLines(area.getX(), area.getY(), size);
  138. }
  139. void recreateLines(const uint x, const uint y, const uint size)
  140. {
  141. uint linesize = size;
  142. uint offset = 0;
  143. // 1st line, full diagonal size
  144. l1.setStartPos(x + size, y);
  145. l1.setEndPos(x, y + size);
  146. // 2nd line, bit more to the right and down, cropped
  147. offset += size / 3;
  148. linesize -= size / 3;
  149. l2.setStartPos(x + linesize + offset, y + offset);
  150. l2.setEndPos(x + offset, y + linesize + offset);
  151. // 3rd line, even more right and down
  152. offset += size / 3;
  153. linesize -= size / 3;
  154. l3.setStartPos(x + linesize + offset, y + offset);
  155. l3.setEndPos(x + offset, y + linesize + offset);
  156. }
  157. void drawLine(const Line<double>& line)
  158. {
  159. drawLine(line.getStartPos(), line.getEndPos());
  160. }
  161. void drawLine(const Point<double>& posStart, const Point<double>& posEnd)
  162. {
  163. DISTRHO_SAFE_ASSERT_RETURN(posStart != posEnd,);
  164. glBegin(GL_LINES);
  165. {
  166. glVertex2d(posStart.getX(), posStart.getY());
  167. glVertex2d(posEnd.getX(), posEnd.getY());
  168. }
  169. glEnd();
  170. }
  171. DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ResizeHandle)
  172. };
  173. END_NAMESPACE_DGL