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.

280 lines
8.8KB

  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 "../../Application/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. border.reset (new ResizableBorderComponent (this, this));
  35. addChildComponent (border.get());
  36. border->setBorderThickness (BorderSize<int> (borderThickness));
  37. target->addComponentListener (this);
  38. changeListenerCallback (nullptr);
  39. layout.getSelectedSet().addChangeListener (this);
  40. setRepaintsOnMouseActivity (true);
  41. border->setRepaintsOnMouseActivity (true);
  42. }
  43. ComponentOverlayComponent::~ComponentOverlayComponent()
  44. {
  45. layout.getSelectedSet().removeChangeListener (this);
  46. if (target != nullptr)
  47. target->removeComponentListener (this);
  48. }
  49. void ComponentOverlayComponent::changeListenerCallback (ChangeBroadcaster*)
  50. {
  51. const bool nowSelected = layout.getSelectedSet().isSelected (target);
  52. if (selected != nowSelected)
  53. {
  54. selected = nowSelected;
  55. border->setVisible (nowSelected);
  56. repaint();
  57. }
  58. }
  59. void ComponentOverlayComponent::paint (Graphics& g)
  60. {
  61. jassert (target != nullptr);
  62. border->setColour (backgroundColourId, Colours::transparentBlack);
  63. if (selected)
  64. {
  65. auto selectedItems = layout.getSelectedSet();
  66. auto baseColour = findColour (defaultHighlightColourId);
  67. const BorderSize<int> borderSize (border->getBorderThickness());
  68. drawResizableBorder (g, getWidth(), getHeight(), borderSize,
  69. (isMouseOverOrDragging() || border->isMouseOverOrDragging()),
  70. baseColour.withAlpha (selectedItems.getSelectedItem (0) == target ? 1.0f : 0.3f));
  71. }
  72. else if (isMouseOverOrDragging())
  73. {
  74. drawMouseOverCorners (g, getWidth(), getHeight());
  75. }
  76. }
  77. void ComponentOverlayComponent::resized()
  78. {
  79. jassert (target != nullptr);
  80. border->setBounds (getLocalBounds());
  81. }
  82. void ComponentOverlayComponent::mouseDown (const MouseEvent& e)
  83. {
  84. dragging = false;
  85. mouseDownSelectStatus = layout.getSelectedSet().addToSelectionOnMouseDown (target, e.mods);
  86. if (e.mods.isPopupMenu())
  87. {
  88. showPopupMenu();
  89. return; // this may be deleted now..
  90. }
  91. }
  92. void ComponentOverlayComponent::mouseDrag (const MouseEvent& e)
  93. {
  94. if (! e.mods.isPopupMenu())
  95. {
  96. if (selected && ! dragging)
  97. {
  98. dragging = e.mouseWasDraggedSinceMouseDown();
  99. if (dragging)
  100. layout.startDragging();
  101. }
  102. if (dragging)
  103. {
  104. layout.dragSelectedComps (e.getDistanceFromDragStartX(),
  105. e.getDistanceFromDragStartY());
  106. }
  107. }
  108. }
  109. void ComponentOverlayComponent::mouseUp (const MouseEvent& e)
  110. {
  111. if (dragging)
  112. layout.endDragging();
  113. layout.getSelectedSet().addToSelectionOnMouseUp (target, e.mods, dragging, mouseDownSelectStatus);
  114. }
  115. void ComponentOverlayComponent::componentMovedOrResized (Component&, bool /*wasMoved*/, bool /*wasResized*/)
  116. {
  117. updateBoundsToMatchTarget();
  118. }
  119. void ComponentOverlayComponent::updateBoundsToMatchTarget()
  120. {
  121. if (Component* const parent = target->getParentComponent())
  122. {
  123. const int dx = parent->getX();
  124. const int dy = parent->getY();
  125. setBounds (dx + target->getX() - borderThickness,
  126. dy + target->getY() - borderThickness,
  127. target->getWidth() + borderThickness * 2,
  128. target->getHeight() + borderThickness * 2);
  129. }
  130. if (border->isMouseButtonDown())
  131. layout.changed();
  132. }
  133. void ComponentOverlayComponent::resizeStart()
  134. {
  135. if (getHeight() > 0)
  136. originalAspectRatio = getWidth() / (double) getHeight();
  137. else
  138. originalAspectRatio = 1.0;
  139. layout.getDocument()->beginTransaction ("Resize components");
  140. }
  141. void ComponentOverlayComponent::resizeEnd()
  142. {
  143. layout.getDocument()->beginTransaction();
  144. }
  145. void ComponentOverlayComponent::checkBounds (Rectangle<int>& b,
  146. const Rectangle<int>& previousBounds,
  147. const Rectangle<int>& limits,
  148. const bool isStretchingTop,
  149. const bool isStretchingLeft,
  150. const bool isStretchingBottom,
  151. const bool isStretchingRight)
  152. {
  153. if (ModifierKeys::currentModifiers.isShiftDown())
  154. setFixedAspectRatio (originalAspectRatio);
  155. else
  156. setFixedAspectRatio (0.0);
  157. ComponentBoundsConstrainer::checkBounds (b, previousBounds, limits, isStretchingTop, isStretchingLeft, isStretchingBottom, isStretchingRight);
  158. if (layout.getDocument()->isSnapActive (true))
  159. {
  160. if (Component* const parent = target->getParentComponent())
  161. {
  162. const int dx = parent->getX();
  163. const int dy = parent->getY();
  164. int x = b.getX();
  165. int y = b.getY();
  166. int w = b.getWidth();
  167. int h = b.getHeight();
  168. x += borderThickness - dx;
  169. y += borderThickness - dy;
  170. w -= borderThickness * 2;
  171. h -= borderThickness * 2;
  172. int right = x + w;
  173. int bottom = y + h;
  174. if (isStretchingRight)
  175. right = layout.getDocument()->snapPosition (right);
  176. if (isStretchingBottom)
  177. bottom = layout.getDocument()->snapPosition (bottom);
  178. if (isStretchingLeft)
  179. x = layout.getDocument()->snapPosition (x);
  180. if (isStretchingTop)
  181. y = layout.getDocument()->snapPosition (y);
  182. w = (right - x) + borderThickness * 2;
  183. h = (bottom - y) + borderThickness * 2;
  184. x -= borderThickness - dx;
  185. y -= borderThickness - dy;
  186. b = Rectangle<int> (x, y, w, h);
  187. }
  188. }
  189. }
  190. void ComponentOverlayComponent::applyBoundsToComponent (Component& component, Rectangle<int> b)
  191. {
  192. if (component.getBounds() != b)
  193. {
  194. layout.getDocument()->getUndoManager().undoCurrentTransactionOnly();
  195. auto dX = b.getX() - component.getX();
  196. auto dY = b.getY() - component.getY();
  197. auto dW = b.getWidth() - component.getWidth();
  198. auto dH = b.getHeight() - component.getHeight();
  199. component.setBounds (b);
  200. if (auto* parent = target->getParentComponent())
  201. target->setBounds (b.getX() + borderThickness - parent->getX(),
  202. b.getY() + borderThickness - parent->getY(),
  203. b.getWidth() - borderThickness * 2,
  204. b.getHeight() - borderThickness * 2);
  205. layout.updateStoredComponentPosition (target, true);
  206. if (layout.getSelectedSet().getNumSelected() > 1)
  207. {
  208. for (auto s : layout.getSelectedSet())
  209. {
  210. if (s != target)
  211. {
  212. s->setBounds (s->getX() + dX, s->getY() + dY, s->getWidth() + dW, s->getHeight() + dH);
  213. layout.updateStoredComponentPosition (s, true);
  214. }
  215. }
  216. }
  217. }
  218. }
  219. void ComponentOverlayComponent::showPopupMenu()
  220. {
  221. ComponentTypeHandler::getHandlerFor (*target)->showPopupMenu (target, layout);
  222. }