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.

259 lines
8.0KB

  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. border->setColour (backgroundColourId, Colours::transparentBlack);
  62. if (selected)
  63. {
  64. const BorderSize<int> borderSize (border->getBorderThickness());
  65. drawResizableBorder (g, getWidth(), getHeight(), borderSize,
  66. (isMouseOverOrDragging() || border->isMouseOverOrDragging()),
  67. findColour (defaultHighlightColourId));
  68. }
  69. else if (isMouseOverOrDragging())
  70. {
  71. drawMouseOverCorners (g, getWidth(), getHeight());
  72. }
  73. }
  74. void ComponentOverlayComponent::resized()
  75. {
  76. jassert (target != nullptr);
  77. border->setBounds (getLocalBounds());
  78. }
  79. void ComponentOverlayComponent::mouseDown (const MouseEvent& e)
  80. {
  81. dragging = false;
  82. mouseDownSelectStatus = layout.getSelectedSet().addToSelectionOnMouseDown (target, e.mods);
  83. if (e.mods.isPopupMenu())
  84. {
  85. showPopupMenu();
  86. return; // this may be deleted now..
  87. }
  88. }
  89. void ComponentOverlayComponent::mouseDrag (const MouseEvent& e)
  90. {
  91. if (! e.mods.isPopupMenu())
  92. {
  93. if (selected && ! dragging)
  94. {
  95. dragging = e.mouseWasDraggedSinceMouseDown();
  96. if (dragging)
  97. layout.startDragging();
  98. }
  99. if (dragging)
  100. {
  101. layout.dragSelectedComps (e.getDistanceFromDragStartX(),
  102. e.getDistanceFromDragStartY());
  103. }
  104. }
  105. }
  106. void ComponentOverlayComponent::mouseUp (const MouseEvent& e)
  107. {
  108. if (dragging)
  109. layout.endDragging();
  110. layout.getSelectedSet().addToSelectionOnMouseUp (target, e.mods, dragging, mouseDownSelectStatus);
  111. }
  112. void ComponentOverlayComponent::componentMovedOrResized (Component&, bool /*wasMoved*/, bool /*wasResized*/)
  113. {
  114. updateBoundsToMatchTarget();
  115. }
  116. void ComponentOverlayComponent::updateBoundsToMatchTarget()
  117. {
  118. if (Component* const parent = target->getParentComponent())
  119. {
  120. const int dx = parent->getX();
  121. const int dy = parent->getY();
  122. setBounds (dx + target->getX() - borderThickness,
  123. dy + target->getY() - borderThickness,
  124. target->getWidth() + borderThickness * 2,
  125. target->getHeight() + borderThickness * 2);
  126. }
  127. if (border->isMouseButtonDown())
  128. layout.changed();
  129. }
  130. void ComponentOverlayComponent::resizeStart()
  131. {
  132. if (getHeight() > 0)
  133. originalAspectRatio = getWidth() / (double) getHeight();
  134. else
  135. originalAspectRatio = 1.0;
  136. layout.getDocument()->beginTransaction ("Resize components");
  137. }
  138. void ComponentOverlayComponent::resizeEnd()
  139. {
  140. layout.getDocument()->beginTransaction();
  141. }
  142. void ComponentOverlayComponent::checkBounds (Rectangle<int>& b,
  143. const Rectangle<int>& previousBounds,
  144. const Rectangle<int>& limits,
  145. const bool isStretchingTop,
  146. const bool isStretchingLeft,
  147. const bool isStretchingBottom,
  148. const bool isStretchingRight)
  149. {
  150. if (ModifierKeys::getCurrentModifiers().isShiftDown())
  151. setFixedAspectRatio (originalAspectRatio);
  152. else
  153. setFixedAspectRatio (0.0);
  154. ComponentBoundsConstrainer::checkBounds (b, previousBounds, limits, isStretchingTop, isStretchingLeft, isStretchingBottom, isStretchingRight);
  155. if (layout.getDocument()->isSnapActive (true))
  156. {
  157. if (Component* const parent = target->getParentComponent())
  158. {
  159. const int dx = parent->getX();
  160. const int dy = parent->getY();
  161. int x = b.getX();
  162. int y = b.getY();
  163. int w = b.getWidth();
  164. int h = b.getHeight();
  165. x += borderThickness - dx;
  166. y += borderThickness - dy;
  167. w -= borderThickness * 2;
  168. h -= borderThickness * 2;
  169. int right = x + w;
  170. int bottom = y + h;
  171. if (isStretchingRight)
  172. right = layout.getDocument()->snapPosition (right);
  173. if (isStretchingBottom)
  174. bottom = layout.getDocument()->snapPosition (bottom);
  175. if (isStretchingLeft)
  176. x = layout.getDocument()->snapPosition (x);
  177. if (isStretchingTop)
  178. y = layout.getDocument()->snapPosition (y);
  179. w = (right - x) + borderThickness * 2;
  180. h = (bottom - y) + borderThickness * 2;
  181. x -= borderThickness - dx;
  182. y -= borderThickness - dy;
  183. b = Rectangle<int> (x, y, w, h);
  184. }
  185. }
  186. }
  187. void ComponentOverlayComponent::applyBoundsToComponent (Component& component, Rectangle<int> b)
  188. {
  189. if (component.getBounds() != b)
  190. {
  191. layout.getDocument()->getUndoManager().undoCurrentTransactionOnly();
  192. component.setBounds (b);
  193. if (auto* parent = target->getParentComponent())
  194. target->setBounds (b.getX() + borderThickness - parent->getX(),
  195. b.getY() + borderThickness - parent->getY(),
  196. b.getWidth() - borderThickness * 2,
  197. b.getHeight() - borderThickness * 2);
  198. layout.updateStoredComponentPosition (target, true);
  199. }
  200. }
  201. void ComponentOverlayComponent::showPopupMenu()
  202. {
  203. ComponentTypeHandler::getHandlerFor (*target)->showPopupMenu (target, layout);
  204. }