The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

254 lines
7.9KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. #include "../../jucer_Headers.h"
  18. #include "jucer_ComponentLayoutEditor.h"
  19. #include "../jucer_UtilityFunctions.h"
  20. //==============================================================================
  21. ComponentOverlayComponent::ComponentOverlayComponent (Component* const target_,
  22. ComponentLayout& layout_)
  23. : target (target_),
  24. borderThickness (4),
  25. layout (layout_),
  26. selected (false),
  27. dragging (false),
  28. originalAspectRatio (1.0)
  29. {
  30. setMinimumOnscreenAmounts (0, 0, 0, 0);
  31. setSizeLimits (borderThickness * 2 + 2, borderThickness * 2 + 2, 8192, 8192);
  32. addChildComponent (border = new ResizableBorderComponent (this, this));
  33. border->setBorderThickness (BorderSize<int> (borderThickness));
  34. target->addComponentListener (this);
  35. changeListenerCallback (nullptr);
  36. layout.getSelectedSet().addChangeListener (this);
  37. setRepaintsOnMouseActivity (true);
  38. border->setRepaintsOnMouseActivity (true);
  39. }
  40. ComponentOverlayComponent::~ComponentOverlayComponent()
  41. {
  42. layout.getSelectedSet().removeChangeListener (this);
  43. if (target != nullptr)
  44. target->removeComponentListener (this);
  45. }
  46. void ComponentOverlayComponent::changeListenerCallback (ChangeBroadcaster*)
  47. {
  48. const bool nowSelected = layout.getSelectedSet().isSelected (target);
  49. if (selected != nowSelected)
  50. {
  51. selected = nowSelected;
  52. border->setVisible (nowSelected);
  53. repaint();
  54. }
  55. }
  56. void ComponentOverlayComponent::paint (Graphics& g)
  57. {
  58. jassert (target != nullptr);
  59. if (selected)
  60. {
  61. const BorderSize<int> borderSize (border->getBorderThickness());
  62. drawResizableBorder (g, getWidth(), getHeight(), borderSize, (isMouseOverOrDragging() || border->isMouseOverOrDragging()));
  63. }
  64. else if (isMouseOverOrDragging())
  65. {
  66. drawMouseOverCorners (g, getWidth(), getHeight());
  67. }
  68. }
  69. void ComponentOverlayComponent::resized()
  70. {
  71. jassert (target != nullptr);
  72. border->setBounds (getLocalBounds());
  73. }
  74. void ComponentOverlayComponent::mouseDown (const MouseEvent& e)
  75. {
  76. dragging = false;
  77. mouseDownSelectStatus = layout.getSelectedSet().addToSelectionOnMouseDown (target, e.mods);
  78. if (e.mods.isPopupMenu())
  79. {
  80. showPopupMenu();
  81. return; // this may be deleted now..
  82. }
  83. }
  84. void ComponentOverlayComponent::mouseDrag (const MouseEvent& e)
  85. {
  86. if (! e.mods.isPopupMenu())
  87. {
  88. if (selected && ! dragging)
  89. {
  90. dragging = e.mouseWasDraggedSinceMouseDown();
  91. if (dragging)
  92. layout.startDragging();
  93. }
  94. if (dragging)
  95. {
  96. layout.dragSelectedComps (e.getDistanceFromDragStartX(),
  97. e.getDistanceFromDragStartY());
  98. }
  99. }
  100. }
  101. void ComponentOverlayComponent::mouseUp (const MouseEvent& e)
  102. {
  103. if (dragging)
  104. layout.endDragging();
  105. layout.getSelectedSet().addToSelectionOnMouseUp (target, e.mods, dragging, mouseDownSelectStatus);
  106. }
  107. void ComponentOverlayComponent::componentMovedOrResized (Component&, bool /*wasMoved*/, bool /*wasResized*/)
  108. {
  109. updateBoundsToMatchTarget();
  110. }
  111. void ComponentOverlayComponent::updateBoundsToMatchTarget()
  112. {
  113. if (Component* const parent = target->getParentComponent())
  114. {
  115. const int dx = parent->getX();
  116. const int dy = parent->getY();
  117. setBounds (dx + target->getX() - borderThickness,
  118. dy + target->getY() - borderThickness,
  119. target->getWidth() + borderThickness * 2,
  120. target->getHeight() + borderThickness * 2);
  121. }
  122. if (border->isMouseButtonDown())
  123. layout.changed();
  124. }
  125. void ComponentOverlayComponent::resizeStart()
  126. {
  127. if (getHeight() > 0)
  128. originalAspectRatio = getWidth() / (double) getHeight();
  129. else
  130. originalAspectRatio = 1.0;
  131. layout.getDocument()->beginTransaction ("Resize components");
  132. }
  133. void ComponentOverlayComponent::resizeEnd()
  134. {
  135. layout.getDocument()->beginTransaction();
  136. }
  137. void ComponentOverlayComponent::checkBounds (Rectangle<int>& b,
  138. const Rectangle<int>& previousBounds,
  139. const Rectangle<int>& limits,
  140. const bool isStretchingTop,
  141. const bool isStretchingLeft,
  142. const bool isStretchingBottom,
  143. const bool isStretchingRight)
  144. {
  145. if (ModifierKeys::getCurrentModifiers().isShiftDown())
  146. setFixedAspectRatio (originalAspectRatio);
  147. else
  148. setFixedAspectRatio (0.0);
  149. ComponentBoundsConstrainer::checkBounds (b, previousBounds, limits, isStretchingTop, isStretchingLeft, isStretchingBottom, isStretchingRight);
  150. if (layout.getDocument()->isSnapActive (true))
  151. {
  152. if (Component* const parent = target->getParentComponent())
  153. {
  154. const int dx = parent->getX();
  155. const int dy = parent->getY();
  156. int x = b.getX();
  157. int y = b.getY();
  158. int w = b.getWidth();
  159. int h = b.getHeight();
  160. x += borderThickness - dx;
  161. y += borderThickness - dy;
  162. w -= borderThickness * 2;
  163. h -= borderThickness * 2;
  164. int right = x + w;
  165. int bottom = y + h;
  166. if (isStretchingRight)
  167. right = layout.getDocument()->snapPosition (right);
  168. if (isStretchingBottom)
  169. bottom = layout.getDocument()->snapPosition (bottom);
  170. if (isStretchingLeft)
  171. x = layout.getDocument()->snapPosition (x);
  172. if (isStretchingTop)
  173. y = layout.getDocument()->snapPosition (y);
  174. w = (right - x) + borderThickness * 2;
  175. h = (bottom - y) + borderThickness * 2;
  176. x -= borderThickness - dx;
  177. y -= borderThickness - dy;
  178. b = Rectangle<int> (x, y, w, h);
  179. }
  180. }
  181. }
  182. void ComponentOverlayComponent::applyBoundsToComponent (Component* component, const Rectangle<int>& b)
  183. {
  184. if (component->getBounds() != b)
  185. {
  186. layout.getDocument()->getUndoManager().undoCurrentTransactionOnly();
  187. component->setBounds (b);
  188. if (Component* const parent = target->getParentComponent())
  189. target->setBounds (b.getX() + borderThickness - parent->getX(),
  190. b.getY() + borderThickness - parent->getY(),
  191. b.getWidth() - borderThickness * 2,
  192. b.getHeight() - borderThickness * 2);
  193. layout.updateStoredComponentPosition (target, true);
  194. }
  195. }
  196. void ComponentOverlayComponent::showPopupMenu()
  197. {
  198. ComponentTypeHandler::getHandlerFor (*target)->showPopupMenu (target, layout);
  199. }