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.

256 lines
7.9KB

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