2 ==============================================================================
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
7 JUCE is an open source library subject to commercial or open-source
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
23 ==============================================================================
29 BubbleComponent::BubbleComponent()
30 : allowablePlacements (above
| below
| left
| right
)
32 setInterceptsMouseClicks (false, false);
34 shadow
.setShadowProperties (DropShadow (Colours::black
.withAlpha (0.35f
), 5, Point
<int>()));
35 setComponentEffect (&shadow
);
38 BubbleComponent::~BubbleComponent() {}
40 //==============================================================================
41 void BubbleComponent::paint (Graphics
& g
)
43 getLookAndFeel().drawBubble (g
, *this, arrowTip
.toFloat(), content
.toFloat());
45 g
.reduceClipRegion (content
);
46 g
.setOrigin (content
.getPosition());
48 paintContent (g
, content
.getWidth(), content
.getHeight());
51 void BubbleComponent::setAllowedPlacement (const int newPlacement
)
53 allowablePlacements
= newPlacement
;
56 //==============================================================================
57 void BubbleComponent::setPosition (Component
* componentToPointTo
, int distanceFromTarget
, int arrowLength
)
59 jassert (componentToPointTo
!= nullptr);
61 Rectangle
<int> target
;
63 if (Component
* p
= getParentComponent())
64 target
= p
->getLocalArea (componentToPointTo
, componentToPointTo
->getLocalBounds());
66 target
= componentToPointTo
->getScreenBounds().transformedBy (getTransform().inverted());
68 setPosition (target
, distanceFromTarget
, arrowLength
);
71 void BubbleComponent::setPosition (Point
<int> arrowTipPos
, int arrowLength
)
73 setPosition (Rectangle
<int> (arrowTipPos
.x
, arrowTipPos
.y
, 1, 1), arrowLength
, arrowLength
);
76 void BubbleComponent::setPosition (Rectangle
<int> rectangleToPointTo
,
77 int distanceFromTarget
, int arrowLength
)
80 int contentW
= 150, contentH
= 30;
81 getContentSize (contentW
, contentH
);
82 content
.setBounds (distanceFromTarget
, distanceFromTarget
, contentW
, contentH
);
85 const int totalW
= content
.getWidth() + distanceFromTarget
* 2;
86 const int totalH
= content
.getHeight() + distanceFromTarget
* 2;
88 auto availableSpace
= (getParentComponent() != nullptr ? getParentComponent()->getLocalBounds()
89 : getParentMonitorArea().transformedBy (getTransform().inverted()));
91 int spaceAbove
= ((allowablePlacements
& above
) != 0) ? jmax (0, rectangleToPointTo
.getY() - availableSpace
.getY()) : -1;
92 int spaceBelow
= ((allowablePlacements
& below
) != 0) ? jmax (0, availableSpace
.getBottom() - rectangleToPointTo
.getBottom()) : -1;
93 int spaceLeft
= ((allowablePlacements
& left
) != 0) ? jmax (0, rectangleToPointTo
.getX() - availableSpace
.getX()) : -1;
94 int spaceRight
= ((allowablePlacements
& right
) != 0) ? jmax (0, availableSpace
.getRight() - rectangleToPointTo
.getRight()) : -1;
96 // look at whether the component is elongated, and if so, try to position next to its longer dimension.
97 if (rectangleToPointTo
.getWidth() > rectangleToPointTo
.getHeight() * 2
98 && (spaceAbove
> totalH
+ 20 || spaceBelow
> totalH
+ 20))
100 spaceLeft
= spaceRight
= 0;
102 else if (rectangleToPointTo
.getWidth() < rectangleToPointTo
.getHeight() / 2
103 && (spaceLeft
> totalW
+ 20 || spaceRight
> totalW
+ 20))
105 spaceAbove
= spaceBelow
= 0;
108 int targetX
, targetY
;
110 if (jmax (spaceAbove
, spaceBelow
) >= jmax (spaceLeft
, spaceRight
))
112 targetX
= rectangleToPointTo
.getCentre().x
;
113 arrowTip
.x
= totalW
/ 2;
115 if (spaceAbove
>= spaceBelow
)
118 targetY
= rectangleToPointTo
.getY();
119 arrowTip
.y
= content
.getBottom() + arrowLength
;
124 targetY
= rectangleToPointTo
.getBottom();
125 arrowTip
.y
= content
.getY() - arrowLength
;
130 targetY
= rectangleToPointTo
.getCentre().y
;
131 arrowTip
.y
= totalH
/ 2;
133 if (spaceLeft
> spaceRight
)
136 targetX
= rectangleToPointTo
.getX();
137 arrowTip
.x
= content
.getRight() + arrowLength
;
142 targetX
= rectangleToPointTo
.getRight();
143 arrowTip
.x
= content
.getX() - arrowLength
;
147 setBounds (targetX
- arrowTip
.x
, targetY
- arrowTip
.y
, totalW
, totalH
);