Extra "ports" of juce-based plugins using the distrho build system
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.

198 lines
6.5KB

  1. /*
  2. modified version of juceCalloutbox
  3. */
  4. #include "CabbageCallOutBox.h"
  5. CabbageCallOutBox::CabbageCallOutBox (Component& c, const Rectangle<int>& area, Component* const parent)
  6. : borderSpace (2), arrowSize (1.0f), content (c)
  7. {
  8. addAndMakeVisible (&content);
  9. if (parent != nullptr)
  10. {
  11. parent->addChildComponent (this);
  12. updatePosition (area, parent->getLocalBounds());
  13. setVisible (true);
  14. }
  15. else
  16. {
  17. setAlwaysOnTop (true);
  18. updatePosition (area, Desktop::getInstance().getDisplays()
  19. .getDisplayContaining (area.getCentre()).userArea);
  20. addToDesktop (ComponentPeer::windowIsTemporary);
  21. }
  22. }
  23. CabbageCallOutBox::~CabbageCallOutBox()
  24. {
  25. }
  26. //==============================================================================
  27. class CallOutBoxCallback : public ModalComponentManager::Callback
  28. {
  29. public:
  30. CallOutBoxCallback (Component* c, const Rectangle<int>& area, Component* parent)
  31. : content (c), callout (*c, area, parent)
  32. {
  33. callout.setVisible (true);
  34. callout.enterModalState (true, this);
  35. }
  36. void modalStateFinished (int) {}
  37. ScopedPointer<Component> content;
  38. CabbageCallOutBox callout;
  39. JUCE_DECLARE_NON_COPYABLE (CallOutBoxCallback)
  40. };
  41. CabbageCallOutBox& CabbageCallOutBox::launchAsynchronously (Component* content,
  42. const Rectangle<int>& area,
  43. Component* parent)
  44. {
  45. jassert (content != nullptr); // must be a valid content component!
  46. return (new CallOutBoxCallback (content, area, parent))->callout;
  47. }
  48. //==============================================================================
  49. void CabbageCallOutBox::paint (Graphics& g)
  50. {
  51. g.fillAll(Colours::black);
  52. // getLookAndFeel().drawCallOutBoxBackground (*this, g, outline, background);
  53. }
  54. void CabbageCallOutBox::resized()
  55. {
  56. content.setTopLeftPosition (0, 0);
  57. refreshPath();
  58. }
  59. void CabbageCallOutBox::moved()
  60. {
  61. refreshPath();
  62. }
  63. void CabbageCallOutBox::childBoundsChanged (Component*)
  64. {
  65. updatePosition (targetArea, availableArea);
  66. }
  67. bool CabbageCallOutBox::hitTest (int x, int y)
  68. {
  69. return outline.contains ((float) x, (float) y);
  70. }
  71. enum { callOutBoxDismissCommandId = 0x4f83a04b };
  72. void CabbageCallOutBox::inputAttemptWhenModal()
  73. {
  74. const Point<int> mousePos (getMouseXYRelative() + getBounds().getPosition());
  75. if (targetArea.contains (mousePos))
  76. {
  77. // if you click on the area that originally popped-up the callout, you expect it
  78. // to get rid of the box, but deleting the box here allows the click to pass through and
  79. // probably re-trigger it, so we need to dismiss the box asynchronously to consume the click..
  80. postCommandMessage (callOutBoxDismissCommandId);
  81. }
  82. else
  83. {
  84. exitModalState (0);
  85. setVisible (false);
  86. }
  87. }
  88. void CabbageCallOutBox::handleCommandMessage (int commandId)
  89. {
  90. Component::handleCommandMessage (commandId);
  91. if (commandId == callOutBoxDismissCommandId)
  92. {
  93. exitModalState (0);
  94. setVisible (false);
  95. }
  96. }
  97. bool CabbageCallOutBox::keyPressed (const KeyPress& key)
  98. {
  99. if (key.isKeyCode (KeyPress::escapeKey))
  100. {
  101. inputAttemptWhenModal();
  102. return true;
  103. }
  104. return false;
  105. }
  106. void CabbageCallOutBox::updatePosition (const Rectangle<int>& newAreaToPointTo, const Rectangle<int>& newAreaToFitIn)
  107. {
  108. targetArea = newAreaToPointTo;
  109. availableArea = newAreaToFitIn;
  110. Rectangle<int> newBounds (content.getWidth(),
  111. content.getHeight());
  112. const int hw = newBounds.getWidth() / 2;
  113. const int hh = newBounds.getHeight() / 2;
  114. const float hwReduced = 0;//(float) (hw - borderSpace);
  115. const float hhReduced = 0;//(float) (hh - borderSpace);
  116. const float arrowIndent = 0;//borderSpace - arrowSize;
  117. Point<float> targets[4] = { Point<float> ((float) targetArea.getCentreX(), (float) targetArea.getBottom()),
  118. Point<float> ((float) targetArea.getRight(), (float) targetArea.getCentreY()),
  119. Point<float> ((float) targetArea.getX(), (float) targetArea.getCentreY()),
  120. Point<float> ((float) targetArea.getCentreX(), (float) targetArea.getY()) };
  121. Line<float> lines[4] = { Line<float> (targets[0].translated (-hwReduced, hh - arrowIndent), targets[0].translated (hwReduced, hh - arrowIndent)),
  122. Line<float> (targets[1].translated (hw - arrowIndent, -hhReduced), targets[1].translated (hw - arrowIndent, hhReduced)),
  123. Line<float> (targets[2].translated (-(hw - arrowIndent), -hhReduced), targets[2].translated (-(hw - arrowIndent), hhReduced)),
  124. Line<float> (targets[3].translated (-hwReduced, -(hh - arrowIndent)), targets[3].translated (hwReduced, -(hh - arrowIndent))) };
  125. const Rectangle<float> centrePointArea (newAreaToFitIn.reduced (hw, hh).toFloat());
  126. const Point<float> targetCentre (targetArea.getCentre().toFloat());
  127. float nearest = 1.0e9f;
  128. for (int i = 0; i < 4; ++i)
  129. {
  130. Line<float> constrainedLine (centrePointArea.getConstrainedPoint (lines[i].getStart()),
  131. centrePointArea.getConstrainedPoint (lines[i].getEnd()));
  132. const Point<float> centre (constrainedLine.findNearestPointTo (targetCentre));
  133. float distanceFromCentre = centre.getDistanceFrom (targets[i]);
  134. if (! (centrePointArea.contains (lines[i].getStart()) || centrePointArea.contains (lines[i].getEnd())))
  135. distanceFromCentre += 1000.0f;
  136. if (distanceFromCentre < nearest)
  137. {
  138. nearest = distanceFromCentre;
  139. targetPoint = targets[i];
  140. newBounds.setPosition ((int) (centre.x - hw),
  141. (int) (centre.y - hh));
  142. }
  143. }
  144. setBounds (newBounds);
  145. }
  146. void CabbageCallOutBox::refreshPath()
  147. {
  148. repaint();
  149. background = Image::null;
  150. outline.clear();
  151. outline.addRectangle(1, 1, getWidth()-2, getHeight()-2);
  152. /*
  153. const float gap = 4.5f;
  154. outline.addBubble (content.getBounds().toFloat().expanded (gap, gap),
  155. getLocalBounds().toFloat(),
  156. targetPoint - getPosition().toFloat(),
  157. 9.0*/
  158. }