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.

284 lines
8.9KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  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 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. #include "../../Application/jucer_Headers.h"
  19. #include "jucer_ComponentLayoutEditor.h"
  20. #include "../jucer_UtilityFunctions.h"
  21. //==============================================================================
  22. ComponentOverlayComponent::ComponentOverlayComponent (Component* const target_,
  23. ComponentLayout& layout_)
  24. : target (target_),
  25. borderThickness (4),
  26. layout (layout_),
  27. selected (false),
  28. dragging (false),
  29. originalAspectRatio (1.0)
  30. {
  31. setMinimumOnscreenAmounts (0, 0, 0, 0);
  32. setSizeLimits (borderThickness * 2 + 2, borderThickness * 2 + 2, 8192, 8192);
  33. border.reset (new ResizableBorderComponent (this, this));
  34. addChildComponent (border.get());
  35. border->setBorderThickness (BorderSize<int> (borderThickness));
  36. target->addComponentListener (this);
  37. updateSelected();
  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::updateSelected()
  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::changeListenerCallback (ChangeBroadcaster*)
  59. {
  60. updateSelected();
  61. }
  62. void ComponentOverlayComponent::paint (Graphics& g)
  63. {
  64. jassert (target != nullptr);
  65. border->setColour (backgroundColourId, Colours::transparentBlack);
  66. if (selected)
  67. {
  68. auto selectedItems = layout.getSelectedSet();
  69. auto baseColour = findColour (defaultHighlightColourId);
  70. const BorderSize<int> borderSize (border->getBorderThickness());
  71. drawResizableBorder (g, getWidth(), getHeight(), borderSize,
  72. (isMouseOverOrDragging() || border->isMouseOverOrDragging()),
  73. baseColour.withAlpha (selectedItems.getSelectedItem (0) == target ? 1.0f : 0.3f));
  74. }
  75. else if (isMouseOverOrDragging())
  76. {
  77. drawMouseOverCorners (g, getWidth(), getHeight());
  78. }
  79. }
  80. void ComponentOverlayComponent::resized()
  81. {
  82. jassert (target != nullptr);
  83. border->setBounds (getLocalBounds());
  84. }
  85. void ComponentOverlayComponent::mouseDown (const MouseEvent& e)
  86. {
  87. dragging = false;
  88. mouseDownSelectStatus = layout.getSelectedSet().addToSelectionOnMouseDown (target, e.mods);
  89. if (e.mods.isPopupMenu())
  90. {
  91. showPopupMenu();
  92. return; // this may be deleted now..
  93. }
  94. }
  95. void ComponentOverlayComponent::mouseDrag (const MouseEvent& e)
  96. {
  97. if (! e.mods.isPopupMenu())
  98. {
  99. if (selected && ! dragging)
  100. {
  101. dragging = e.mouseWasDraggedSinceMouseDown();
  102. if (dragging)
  103. layout.startDragging();
  104. }
  105. if (dragging)
  106. {
  107. layout.dragSelectedComps (e.getDistanceFromDragStartX(),
  108. e.getDistanceFromDragStartY());
  109. }
  110. }
  111. }
  112. void ComponentOverlayComponent::mouseUp (const MouseEvent& e)
  113. {
  114. if (dragging)
  115. layout.endDragging();
  116. layout.getSelectedSet().addToSelectionOnMouseUp (target, e.mods, dragging, mouseDownSelectStatus);
  117. }
  118. void ComponentOverlayComponent::componentMovedOrResized (Component&, bool /*wasMoved*/, bool /*wasResized*/)
  119. {
  120. updateBoundsToMatchTarget();
  121. }
  122. void ComponentOverlayComponent::updateBoundsToMatchTarget()
  123. {
  124. if (Component* const parent = target->getParentComponent())
  125. {
  126. const int dx = parent->getX();
  127. const int dy = parent->getY();
  128. setBounds (dx + target->getX() - borderThickness,
  129. dy + target->getY() - borderThickness,
  130. target->getWidth() + borderThickness * 2,
  131. target->getHeight() + borderThickness * 2);
  132. }
  133. if (border->isMouseButtonDown())
  134. layout.changed();
  135. }
  136. void ComponentOverlayComponent::resizeStart()
  137. {
  138. if (getHeight() > 0)
  139. originalAspectRatio = getWidth() / (double) getHeight();
  140. else
  141. originalAspectRatio = 1.0;
  142. layout.getDocument()->beginTransaction ("Resize components");
  143. }
  144. void ComponentOverlayComponent::resizeEnd()
  145. {
  146. layout.getDocument()->beginTransaction();
  147. }
  148. void ComponentOverlayComponent::checkBounds (Rectangle<int>& b,
  149. const Rectangle<int>& previousBounds,
  150. const Rectangle<int>& limits,
  151. const bool isStretchingTop,
  152. const bool isStretchingLeft,
  153. const bool isStretchingBottom,
  154. const bool isStretchingRight)
  155. {
  156. if (ModifierKeys::currentModifiers.isShiftDown())
  157. setFixedAspectRatio (originalAspectRatio);
  158. else
  159. setFixedAspectRatio (0.0);
  160. ComponentBoundsConstrainer::checkBounds (b, previousBounds, limits, isStretchingTop, isStretchingLeft, isStretchingBottom, isStretchingRight);
  161. if (layout.getDocument()->isSnapActive (true))
  162. {
  163. if (Component* const parent = target->getParentComponent())
  164. {
  165. const int dx = parent->getX();
  166. const int dy = parent->getY();
  167. int x = b.getX();
  168. int y = b.getY();
  169. int w = b.getWidth();
  170. int h = b.getHeight();
  171. x += borderThickness - dx;
  172. y += borderThickness - dy;
  173. w -= borderThickness * 2;
  174. h -= borderThickness * 2;
  175. int right = x + w;
  176. int bottom = y + h;
  177. if (isStretchingRight)
  178. right = layout.getDocument()->snapPosition (right);
  179. if (isStretchingBottom)
  180. bottom = layout.getDocument()->snapPosition (bottom);
  181. if (isStretchingLeft)
  182. x = layout.getDocument()->snapPosition (x);
  183. if (isStretchingTop)
  184. y = layout.getDocument()->snapPosition (y);
  185. w = (right - x) + borderThickness * 2;
  186. h = (bottom - y) + borderThickness * 2;
  187. x -= borderThickness - dx;
  188. y -= borderThickness - dy;
  189. b = Rectangle<int> (x, y, w, h);
  190. }
  191. }
  192. }
  193. void ComponentOverlayComponent::applyBoundsToComponent (Component& component, Rectangle<int> b)
  194. {
  195. if (component.getBounds() != b)
  196. {
  197. layout.getDocument()->getUndoManager().undoCurrentTransactionOnly();
  198. auto dX = b.getX() - component.getX();
  199. auto dY = b.getY() - component.getY();
  200. auto dW = b.getWidth() - component.getWidth();
  201. auto dH = b.getHeight() - component.getHeight();
  202. component.setBounds (b);
  203. if (auto* parent = target->getParentComponent())
  204. target->setBounds (b.getX() + borderThickness - parent->getX(),
  205. b.getY() + borderThickness - parent->getY(),
  206. b.getWidth() - borderThickness * 2,
  207. b.getHeight() - borderThickness * 2);
  208. layout.updateStoredComponentPosition (target, true);
  209. if (layout.getSelectedSet().getNumSelected() > 1)
  210. {
  211. for (auto s : layout.getSelectedSet())
  212. {
  213. if (s != target)
  214. {
  215. s->setBounds (s->getX() + dX, s->getY() + dY, s->getWidth() + dW, s->getHeight() + dH);
  216. layout.updateStoredComponentPosition (s, true);
  217. }
  218. }
  219. }
  220. }
  221. }
  222. void ComponentOverlayComponent::showPopupMenu()
  223. {
  224. ComponentTypeHandler::getHandlerFor (*target)->showPopupMenu (target, layout);
  225. }