DISTRHO ProM
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.

186 lines
5.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 "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. resizing(false)
  29. {
  30. resetArea();
  31. }
  32. /** Overloaded constructor, will fetch the window from an existing top-level widget. */
  33. explicit ResizeHandle(TopLevelWidget* const tlw)
  34. : TopLevelWidget(tlw->getWindow()),
  35. handleSize(16),
  36. resizing(false)
  37. {
  38. resetArea();
  39. }
  40. /** Set the handle size, minimum 16. */
  41. void setHandleSize(const uint size)
  42. {
  43. handleSize = std::max(16u, size);
  44. resetArea();
  45. }
  46. protected:
  47. void onDisplay() override
  48. {
  49. const GraphicsContext& context(getGraphicsContext());
  50. const double lineWidth = 1.0 * getScaleFactor();
  51. #ifdef DGL_OPENGL
  52. glUseProgram(0);
  53. glMatrixMode(GL_MODELVIEW);
  54. #endif
  55. // draw white lines, 1px wide
  56. Color(1.0f, 1.0f, 1.0f).setFor(context);
  57. l1.draw(context, lineWidth);
  58. l2.draw(context, lineWidth);
  59. l3.draw(context, lineWidth);
  60. // draw black lines, offset by 1px and 1px wide
  61. Color(0.0f, 0.0f, 0.0f).setFor(context);
  62. Line<double> l1b(l1), l2b(l2), l3b(l3);
  63. l1b.moveBy(lineWidth, lineWidth);
  64. l2b.moveBy(lineWidth, lineWidth);
  65. l3b.moveBy(lineWidth, lineWidth);
  66. l1b.draw(context, lineWidth);
  67. l2b.draw(context, lineWidth);
  68. l3b.draw(context, lineWidth);
  69. }
  70. bool onMouse(const MouseEvent& ev) override
  71. {
  72. if (ev.button != 1)
  73. return false;
  74. if (ev.press && area.contains(ev.pos))
  75. {
  76. resizing = true;
  77. resizingSize = Size<double>(getWidth(), getHeight());
  78. lastResizePoint = ev.pos;
  79. return true;
  80. }
  81. if (resizing && ! ev.press)
  82. {
  83. resizing = false;
  84. return true;
  85. }
  86. return false;
  87. }
  88. bool onMotion(const MotionEvent& ev) override
  89. {
  90. if (! resizing)
  91. return false;
  92. const Size<double> offset(ev.pos.getX() - lastResizePoint.getX(),
  93. ev.pos.getY() - lastResizePoint.getY());
  94. resizingSize += offset;
  95. lastResizePoint = ev.pos;
  96. // TODO min width, min height
  97. const uint minWidth = 16;
  98. const uint minHeight = 16;
  99. if (resizingSize.getWidth() < minWidth)
  100. resizingSize.setWidth(minWidth);
  101. if (resizingSize.getWidth() > 16384)
  102. resizingSize.setWidth(16384);
  103. if (resizingSize.getHeight() < minHeight)
  104. resizingSize.setHeight(minHeight);
  105. if (resizingSize.getHeight() > 16384)
  106. resizingSize.setHeight(16384);
  107. setSize(resizingSize.getWidth(), resizingSize.getHeight());
  108. return true;
  109. }
  110. void onResize(const ResizeEvent& ev) override
  111. {
  112. TopLevelWidget::onResize(ev);
  113. resetArea();
  114. }
  115. private:
  116. Rectangle<uint> area;
  117. Line<double> l1, l2, l3;
  118. uint handleSize;
  119. // event handling state
  120. bool resizing;
  121. Point<double> lastResizePoint;
  122. Size<double> resizingSize;
  123. void resetArea()
  124. {
  125. const double scaleFactor = getScaleFactor();
  126. const uint margin = 0.0 * scaleFactor;
  127. const uint size = handleSize * scaleFactor;
  128. area = Rectangle<uint>(getWidth() - size - margin,
  129. getHeight() - size - margin,
  130. size, size);
  131. recreateLines(area.getX(), area.getY(), size);
  132. }
  133. void recreateLines(const uint x, const uint y, const uint size)
  134. {
  135. uint linesize = size;
  136. uint offset = 0;
  137. // 1st line, full diagonal size
  138. l1.setStartPos(x + size, y);
  139. l1.setEndPos(x, y + size);
  140. // 2nd line, bit more to the right and down, cropped
  141. offset += size / 3;
  142. linesize -= size / 3;
  143. l2.setStartPos(x + linesize + offset, y + offset);
  144. l2.setEndPos(x + offset, y + linesize + offset);
  145. // 3rd line, even more right and down
  146. offset += size / 3;
  147. linesize -= size / 3;
  148. l3.setStartPos(x + linesize + offset, y + offset);
  149. l3.setEndPos(x + offset, y + linesize + offset);
  150. }
  151. DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ResizeHandle)
  152. };
  153. END_NAMESPACE_DGL