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.

255 lines
8.2KB

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