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.

212 lines
6.2KB

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