mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-27 02:20:05 +00:00
Refactored Path::addBubble, BubbleMessageComponent and BubbleComponent classes to work better and avoid duplicated code.
This commit is contained in:
parent
fb29acf1fa
commit
27f1901fe6
11 changed files with 160 additions and 292 deletions
|
|
@ -507,7 +507,7 @@ bool ProjectContentComponent::reinvokeCommandAfterClosingPropertyEditors (const
|
|||
return false;
|
||||
}
|
||||
|
||||
void ProjectContentComponent::showBubbleMessage (const Point<int>& pos, const String& text)
|
||||
void ProjectContentComponent::showBubbleMessage (const Rectangle<int>& pos, const String& text)
|
||||
{
|
||||
addChildComponent (&bubbleMessage);
|
||||
bubbleMessage.setAlwaysOnTop (true);
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ public:
|
|||
void updateMissingFileStatuses();
|
||||
virtual void createProjectTabs();
|
||||
|
||||
void showBubbleMessage (const Point<int>& pos, const String& text);
|
||||
void showBubbleMessage (const Rectangle<int>& pos, const String& text);
|
||||
|
||||
void changeListenerCallback (ChangeBroadcaster*);
|
||||
|
||||
|
|
|
|||
|
|
@ -688,80 +688,66 @@ void Path::addStar (const Point<float>& centre, const int numberOfPoints,
|
|||
}
|
||||
}
|
||||
|
||||
void Path::addBubble (float x, float y,
|
||||
float w, float h,
|
||||
float cs,
|
||||
float tipX,
|
||||
float tipY,
|
||||
int whichSide,
|
||||
float arrowPos,
|
||||
float arrowWidth)
|
||||
void Path::addBubble (const Rectangle<float>& bodyArea,
|
||||
const Rectangle<float>& maximumArea,
|
||||
const Point<float>& arrowTip,
|
||||
const float cornerSize,
|
||||
const float arrowBaseWidth)
|
||||
{
|
||||
if (w > 1.0f && h > 1.0f)
|
||||
const float cornerSize2 = 2.0f * cornerSize;
|
||||
|
||||
startNewSubPath (bodyArea.getX() + cornerSize, bodyArea.getY());
|
||||
|
||||
const float targetLimitX = bodyArea.getX() + cornerSize + arrowBaseWidth;
|
||||
const float targetLimitW = bodyArea.getWidth() - cornerSize2 - arrowBaseWidth * 2.0f;
|
||||
|
||||
const float targetLimitY = bodyArea.getY() + cornerSize + arrowBaseWidth;
|
||||
const float targetLimitH = bodyArea.getHeight() - cornerSize2 - arrowBaseWidth * 2.0f;
|
||||
|
||||
if (Rectangle<float> (targetLimitX, maximumArea.getY(),
|
||||
targetLimitW, bodyArea.getY() - maximumArea.getY()).contains (arrowTip))
|
||||
{
|
||||
cs = jmin (cs, w * 0.5f, h * 0.5f);
|
||||
const float cs2 = 2.0f * cs;
|
||||
|
||||
startNewSubPath (x + cs, y);
|
||||
|
||||
if (whichSide == 0)
|
||||
{
|
||||
const float halfArrowW = jmin (arrowWidth, w - cs2) * 0.5f;
|
||||
const float arrowX1 = x + cs + jmax (0.0f, (w - cs2 - arrowWidth) * arrowPos - halfArrowW);
|
||||
lineTo (arrowX1, y);
|
||||
lineTo (tipX, tipY);
|
||||
lineTo (arrowX1 + halfArrowW * 2.0f, y);
|
||||
}
|
||||
|
||||
lineTo (x + w - cs, y);
|
||||
|
||||
if (cs > 0.0f)
|
||||
addArc (x + w - cs2, y, cs2, cs2, 0, float_Pi * 0.5f);
|
||||
|
||||
if (whichSide == 3)
|
||||
{
|
||||
const float halfArrowH = jmin (arrowWidth, h - cs2) * 0.5f;
|
||||
const float arrowY1 = y + cs + jmax (0.0f, (h - cs2 - arrowWidth) * arrowPos - halfArrowH);
|
||||
lineTo (x + w, arrowY1);
|
||||
lineTo (tipX, tipY);
|
||||
lineTo (x + w, arrowY1 + halfArrowH * 2.0f);
|
||||
}
|
||||
|
||||
lineTo (x + w, y + h - cs);
|
||||
|
||||
if (cs > 0.0f)
|
||||
addArc (x + w - cs2, y + h - cs2, cs2, cs2, float_Pi * 0.5f, float_Pi);
|
||||
|
||||
if (whichSide == 2)
|
||||
{
|
||||
const float halfArrowW = jmin (arrowWidth, w - cs2) * 0.5f;
|
||||
const float arrowX1 = x + cs + jmax (0.0f, (w - cs2 - arrowWidth) * arrowPos - halfArrowW);
|
||||
lineTo (arrowX1 + halfArrowW * 2.0f, y + h);
|
||||
lineTo (tipX, tipY);
|
||||
lineTo (arrowX1, y + h);
|
||||
}
|
||||
|
||||
lineTo (x + cs, y + h);
|
||||
|
||||
if (cs > 0.0f)
|
||||
addArc (x, y + h - cs2, cs2, cs2, float_Pi, float_Pi * 1.5f);
|
||||
|
||||
if (whichSide == 1)
|
||||
{
|
||||
const float halfArrowH = jmin (arrowWidth, h - cs2) * 0.5f;
|
||||
const float arrowY1 = y + cs + jmax (0.0f, (h - cs2 - arrowWidth) * arrowPos - halfArrowH);
|
||||
lineTo (x, arrowY1 + halfArrowH * 2.0f);
|
||||
lineTo (tipX, tipY);
|
||||
lineTo (x, arrowY1);
|
||||
}
|
||||
|
||||
lineTo (x, y + cs);
|
||||
|
||||
if (cs > 0.0f)
|
||||
addArc (x, y, cs2, cs2, float_Pi * 1.5f, float_Pi * 2.0f - PathHelpers::ellipseAngularIncrement);
|
||||
|
||||
closeSubPath();
|
||||
lineTo (arrowTip.x - arrowBaseWidth, bodyArea.getY());
|
||||
lineTo (arrowTip.x, arrowTip.y);
|
||||
lineTo (arrowTip.x + arrowBaseWidth, bodyArea.getY());
|
||||
}
|
||||
|
||||
lineTo (bodyArea.getRight() - cornerSize, bodyArea.getY());
|
||||
addArc (bodyArea.getRight() - cornerSize2, bodyArea.getY(), cornerSize2, cornerSize2, 0, float_Pi * 0.5f);
|
||||
|
||||
if (Rectangle<float> (bodyArea.getRight(), targetLimitY,
|
||||
maximumArea.getRight() - bodyArea.getRight(), targetLimitH).contains (arrowTip))
|
||||
{
|
||||
lineTo (bodyArea.getRight(), arrowTip.y - arrowBaseWidth);
|
||||
lineTo (arrowTip.x, arrowTip.y);
|
||||
lineTo (bodyArea.getRight(), arrowTip.y + arrowBaseWidth);
|
||||
}
|
||||
|
||||
lineTo (bodyArea.getRight(), bodyArea.getBottom() - cornerSize);
|
||||
addArc (bodyArea.getRight() - cornerSize2, bodyArea.getBottom() - cornerSize2, cornerSize2, cornerSize2, float_Pi * 0.5f, float_Pi);
|
||||
|
||||
if (Rectangle<float> (targetLimitX, bodyArea.getBottom(),
|
||||
targetLimitW, maximumArea.getBottom() - bodyArea.getBottom()).contains (arrowTip))
|
||||
{
|
||||
lineTo (arrowTip.x + arrowBaseWidth, bodyArea.getBottom());
|
||||
lineTo (arrowTip.x, arrowTip.y);
|
||||
lineTo (arrowTip.x - arrowBaseWidth, bodyArea.getBottom());
|
||||
}
|
||||
|
||||
lineTo (bodyArea.getX() + cornerSize, bodyArea.getBottom());
|
||||
addArc (bodyArea.getX(), bodyArea.getBottom() - cornerSize2, cornerSize2, cornerSize2, float_Pi, float_Pi * 1.5f);
|
||||
|
||||
if (Rectangle<float> (maximumArea.getX(), targetLimitY, bodyArea.getX() - maximumArea.getX(), targetLimitH).contains (arrowTip))
|
||||
{
|
||||
lineTo (bodyArea.getX(), arrowTip.y + arrowBaseWidth);
|
||||
lineTo (arrowTip.x, arrowTip.y);
|
||||
lineTo (bodyArea.getX(), arrowTip.y - arrowBaseWidth);
|
||||
}
|
||||
|
||||
lineTo (bodyArea.getX(), bodyArea.getY() + cornerSize);
|
||||
addArc (bodyArea.getX(), bodyArea.getY(), cornerSize2, cornerSize2, float_Pi * 1.5f, float_Pi * 2.0f - 0.05f);
|
||||
|
||||
closeSubPath();
|
||||
}
|
||||
|
||||
void Path::addPath (const Path& other)
|
||||
|
|
|
|||
|
|
@ -519,26 +519,19 @@ public:
|
|||
|
||||
/** Adds a speech-bubble shape to the path.
|
||||
|
||||
@param bodyX the left of the main body area of the bubble
|
||||
@param bodyY the top of the main body area of the bubble
|
||||
@param bodyW the width of the main body area of the bubble
|
||||
@param bodyH the height of the main body area of the bubble
|
||||
@param cornerSize the amount by which to round off the corners of the main body rectangle
|
||||
@param arrowTipX the x position that the tip of the arrow should connect to
|
||||
@param arrowTipY the y position that the tip of the arrow should connect to
|
||||
@param whichSide the side to connect the arrow to: 0 = top, 1 = left, 2 = bottom, 3 = right
|
||||
@param arrowPositionAlongEdgeProportional how far along the edge of the main rectangle the
|
||||
arrow's base should be - this is a proportional distance between 0 and 1.0
|
||||
@param arrowWidth how wide the base of the arrow should be where it joins the main rectangle
|
||||
@param bodyArea the area of the body of the bubble shape
|
||||
@param maximumArea an area which encloses the body area and defines the limits within which
|
||||
the arrow tip can be drawn - if the tip lies outside this area, the bubble
|
||||
will be drawn without an arrow
|
||||
@param arrowTipPosition the location of the tip of the arrow
|
||||
@param cornerSize the size of the rounded corners
|
||||
@param arrowBaseWidth the width of the base of the arrow where it joins the main rectangle
|
||||
*/
|
||||
void addBubble (float bodyX, float bodyY,
|
||||
float bodyW, float bodyH,
|
||||
float cornerSize,
|
||||
float arrowTipX,
|
||||
float arrowTipY,
|
||||
int whichSide,
|
||||
float arrowPositionAlongEdgeProportional,
|
||||
float arrowWidth);
|
||||
void addBubble (const Rectangle<float>& bodyArea,
|
||||
const Rectangle<float>& maximumArea,
|
||||
const Point<float>& arrowTipPosition,
|
||||
const float cornerSize,
|
||||
const float arrowBaseWidth);
|
||||
|
||||
/** Adds another path to this one.
|
||||
|
||||
|
|
|
|||
|
|
@ -46,11 +46,11 @@ public:
|
|||
isMoving = (finalBounds != component->getBounds());
|
||||
isChangingAlpha = (finalAlpha != component->getAlpha());
|
||||
|
||||
left = component->getX();
|
||||
top = component->getY();
|
||||
right = component->getRight();
|
||||
bottom = component->getBottom();
|
||||
alpha = component->getAlpha();
|
||||
left = component->getX();
|
||||
top = component->getY();
|
||||
right = component->getRight();
|
||||
bottom = component->getBottom();
|
||||
alpha = component->getAlpha();
|
||||
|
||||
const double invTotalDistance = 4.0 / (startSpeed_ + endSpeed_ + 2.0);
|
||||
startSpeed = jmax (0.0, startSpeed_ * invTotalDistance);
|
||||
|
|
|
|||
|
|
@ -949,26 +949,13 @@ void LookAndFeel::drawBubble (Graphics& g,
|
|||
float boxX, float boxY,
|
||||
float boxW, float boxH)
|
||||
{
|
||||
int side = 0;
|
||||
const Rectangle<float> body (boxX, boxY, boxW, boxH);
|
||||
|
||||
if (tipX < boxX)
|
||||
side = 1;
|
||||
else if (tipX > boxX + boxW)
|
||||
side = 3;
|
||||
else if (tipY > boxY + boxH)
|
||||
side = 2;
|
||||
|
||||
const float indent = 2.0f;
|
||||
Path p;
|
||||
p.addBubble (boxX + indent,
|
||||
boxY + indent,
|
||||
boxW - indent * 2.0f,
|
||||
boxH - indent * 2.0f,
|
||||
5.0f,
|
||||
tipX, tipY,
|
||||
side,
|
||||
0.5f,
|
||||
jmin (15.0f, boxW * 0.3f, boxH * 0.3f));
|
||||
p.addBubble (body,
|
||||
body.getUnion (Rectangle<float> (tipX, tipY, 1.0f, 1.0f)),
|
||||
Point<float> (tipX, tipY),
|
||||
5.0f, jmin (15.0f, boxW * 0.2f, boxH * 0.2f));
|
||||
|
||||
//xxx need to take comp as param for colour
|
||||
g.setColour (findColour (TooltipWindow::backgroundColourId).withAlpha (0.9f));
|
||||
|
|
|
|||
|
|
@ -24,10 +24,7 @@
|
|||
*/
|
||||
|
||||
BubbleComponent::BubbleComponent()
|
||||
: side (0),
|
||||
allowablePlacements (above | below | left | right),
|
||||
arrowTipX (0.0f),
|
||||
arrowTipY (0.0f)
|
||||
: allowablePlacements (above | below | left | right)
|
||||
{
|
||||
setInterceptsMouseClicks (false, false);
|
||||
|
||||
|
|
@ -42,41 +39,14 @@ BubbleComponent::~BubbleComponent()
|
|||
//==============================================================================
|
||||
void BubbleComponent::paint (Graphics& g)
|
||||
{
|
||||
int x = content.getX();
|
||||
int y = content.getY();
|
||||
int w = content.getWidth();
|
||||
int h = content.getHeight();
|
||||
getLookAndFeel().drawBubble (g, arrowTip.x, arrowTip.y,
|
||||
(float) content.getX(), (float) content.getY(),
|
||||
(float) content.getWidth(), (float) content.getHeight());
|
||||
|
||||
int cw, ch;
|
||||
getContentSize (cw, ch);
|
||||
g.setOrigin (content.getX(), content.getY());
|
||||
g.reduceClipRegion (0, 0, content.getWidth(), content.getHeight());
|
||||
|
||||
if (side == 3)
|
||||
x += w - cw;
|
||||
else if (side != 1)
|
||||
x += (w - cw) / 2;
|
||||
|
||||
w = cw;
|
||||
|
||||
if (side == 2)
|
||||
y += h - ch;
|
||||
else if (side != 0)
|
||||
y += (h - ch) / 2;
|
||||
|
||||
h = ch;
|
||||
|
||||
getLookAndFeel().drawBubble (g, arrowTipX, arrowTipY,
|
||||
(float) x, (float) y,
|
||||
(float) w, (float) h);
|
||||
|
||||
const int cx = x + (w - cw) / 2;
|
||||
const int cy = y + (h - ch) / 2;
|
||||
|
||||
const int indent = 3;
|
||||
|
||||
g.setOrigin (cx + indent, cy + indent);
|
||||
g.reduceClipRegion (0, 0, cw - indent * 2, ch - indent * 2);
|
||||
|
||||
paintContent (g, cw - indent * 2, ch - indent * 2);
|
||||
paintContent (g, content.getWidth(), content.getHeight());
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -89,102 +59,89 @@ void BubbleComponent::setPosition (Component* componentToPointTo)
|
|||
{
|
||||
jassert (componentToPointTo != nullptr);
|
||||
|
||||
Point<int> pos;
|
||||
|
||||
if (getParentComponent() != nullptr)
|
||||
pos = getParentComponent()->getLocalPoint (componentToPointTo, pos);
|
||||
setPosition (getParentComponent()->getLocalArea (componentToPointTo, componentToPointTo->getLocalBounds()));
|
||||
else
|
||||
pos = componentToPointTo->localPointToGlobal (pos);
|
||||
|
||||
setPosition (Rectangle<int> (pos.x, pos.y, componentToPointTo->getWidth(), componentToPointTo->getHeight()));
|
||||
setPosition (componentToPointTo->getScreenBounds());
|
||||
}
|
||||
|
||||
void BubbleComponent::setPosition (const int arrowTipX_,
|
||||
const int arrowTipY_)
|
||||
void BubbleComponent::setPosition (const Point<int>& pos)
|
||||
{
|
||||
setPosition (Rectangle<int> (arrowTipX_, arrowTipY_, 1, 1));
|
||||
setPosition (Rectangle<int> (pos.x, pos.y, 1, 1));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void BubbleComponent::setPosition (const Rectangle<int>& rectangleToPointTo)
|
||||
{
|
||||
Rectangle<int> availableSpace (getParentComponent() != nullptr ? getParentComponent()->getLocalBounds()
|
||||
: getParentMonitorArea());
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int w = 150;
|
||||
int h = 30;
|
||||
const int edgeSpace = 15;
|
||||
const int arrowLength = 10;
|
||||
|
||||
getContentSize (w, h);
|
||||
w += 30;
|
||||
h += 30;
|
||||
{
|
||||
int contentW = 150, contentH = 30;
|
||||
getContentSize (contentW, contentH);
|
||||
content.setBounds (edgeSpace, edgeSpace, contentW, contentH);
|
||||
}
|
||||
|
||||
const float edgeIndent = 2.0f;
|
||||
const int arrowLength = jmin (10, h / 3, w / 3);
|
||||
int totalW = content.getWidth() + edgeSpace * 2;
|
||||
int totalH = content.getHeight() + edgeSpace * 2;
|
||||
int targetX, targetY;
|
||||
|
||||
int spaceAbove = ((allowablePlacements & above) != 0) ? jmax (0, rectangleToPointTo.getY() - availableSpace.getY()) : -1;
|
||||
const Rectangle<int> availableSpace (getParentComponent() != nullptr ? getParentComponent()->getLocalBounds()
|
||||
: getParentMonitorArea());
|
||||
|
||||
int spaceAbove = ((allowablePlacements & above) != 0) ? jmax (0, rectangleToPointTo.getY() - availableSpace.getY()) : -1;
|
||||
int spaceBelow = ((allowablePlacements & below) != 0) ? jmax (0, availableSpace.getBottom() - rectangleToPointTo.getBottom()) : -1;
|
||||
int spaceLeft = ((allowablePlacements & left) != 0) ? jmax (0, rectangleToPointTo.getX() - availableSpace.getX()) : -1;
|
||||
int spaceRight = ((allowablePlacements & right) != 0) ? jmax (0, availableSpace.getRight() - rectangleToPointTo.getRight()) : -1;
|
||||
int spaceLeft = ((allowablePlacements & left) != 0) ? jmax (0, rectangleToPointTo.getX() - availableSpace.getX()) : -1;
|
||||
int spaceRight = ((allowablePlacements & right) != 0) ? jmax (0, availableSpace.getRight() - rectangleToPointTo.getRight()) : -1;
|
||||
|
||||
// look at whether the component is elongated, and if so, try to position next to its longer dimension.
|
||||
if (rectangleToPointTo.getWidth() > rectangleToPointTo.getHeight() * 2
|
||||
&& (spaceAbove > h + 20 || spaceBelow > h + 20))
|
||||
&& (spaceAbove > totalH + 20 || spaceBelow > totalH + 20))
|
||||
{
|
||||
spaceLeft = spaceRight = 0;
|
||||
}
|
||||
else if (rectangleToPointTo.getWidth() < rectangleToPointTo.getHeight() / 2
|
||||
&& (spaceLeft > w + 20 || spaceRight > w + 20))
|
||||
&& (spaceLeft > totalW + 20 || spaceRight > totalW + 20))
|
||||
{
|
||||
spaceAbove = spaceBelow = 0;
|
||||
}
|
||||
|
||||
if (jmax (spaceAbove, spaceBelow) >= jmax (spaceLeft, spaceRight))
|
||||
{
|
||||
x = rectangleToPointTo.getX() + (rectangleToPointTo.getWidth() - w) / 2;
|
||||
arrowTipX = w * 0.5f;
|
||||
content.setSize (w, h - arrowLength);
|
||||
targetX = rectangleToPointTo.getCentre().x;
|
||||
arrowTip.x = totalW * 0.5f;
|
||||
|
||||
if (spaceAbove >= spaceBelow)
|
||||
{
|
||||
// above
|
||||
y = rectangleToPointTo.getY() - h;
|
||||
content.setPosition (0, 0);
|
||||
arrowTipY = h - edgeIndent;
|
||||
side = 2;
|
||||
targetY = rectangleToPointTo.getY();
|
||||
arrowTip.y = content.getBottom() + arrowLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
// below
|
||||
y = rectangleToPointTo.getBottom();
|
||||
content.setPosition (0, arrowLength);
|
||||
arrowTipY = edgeIndent;
|
||||
side = 0;
|
||||
targetY = rectangleToPointTo.getBottom();
|
||||
arrowTip.y = content.getY() - arrowLength;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
y = rectangleToPointTo.getY() + (rectangleToPointTo.getHeight() - h) / 2;
|
||||
arrowTipY = h * 0.5f;
|
||||
content.setSize (w - arrowLength, h);
|
||||
targetY = rectangleToPointTo.getCentre().y;
|
||||
arrowTip.y = totalH * 0.5f;
|
||||
|
||||
if (spaceLeft > spaceRight)
|
||||
{
|
||||
// on the left
|
||||
x = rectangleToPointTo.getX() - w;
|
||||
content.setPosition (0, 0);
|
||||
arrowTipX = w - edgeIndent;
|
||||
side = 3;
|
||||
targetX = rectangleToPointTo.getX();
|
||||
arrowTip.x = content.getRight() + arrowLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
// on the right
|
||||
x = rectangleToPointTo.getRight();
|
||||
content.setPosition (arrowLength, 0);
|
||||
arrowTipX = edgeIndent;
|
||||
side = 1;
|
||||
targetX = rectangleToPointTo.getRight();
|
||||
arrowTip.x = content.getX() - arrowLength;
|
||||
}
|
||||
}
|
||||
|
||||
setBounds (x, y, w, h);
|
||||
setBounds (targetX - arrowTip.x, targetY - arrowTip.y, totalW, totalH);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,8 +108,7 @@ public:
|
|||
on where there's the most space, honouring any restrictions that were set
|
||||
with setAllowedPlacement().
|
||||
*/
|
||||
void setPosition (int arrowTipX,
|
||||
int arrowTipY);
|
||||
void setPosition (const Point<int>& arrowTipPosition);
|
||||
|
||||
/** Moves and resizes the bubble to point at a given rectangle.
|
||||
|
||||
|
|
@ -145,8 +144,8 @@ public:
|
|||
|
||||
private:
|
||||
Rectangle<int> content;
|
||||
int side, allowablePlacements;
|
||||
float arrowTipX, arrowTipY;
|
||||
Point<float> arrowTip;
|
||||
int allowablePlacements;
|
||||
DropShadowEffect shadow;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BubbleComponent);
|
||||
|
|
|
|||
|
|
@ -199,63 +199,9 @@ void CallOutBox::refreshPath()
|
|||
outline.clear();
|
||||
|
||||
const float gap = 4.5f;
|
||||
const float cornerSize = 9.0f;
|
||||
const float cornerSize2 = 2.0f * cornerSize;
|
||||
const float arrowBaseWidth = arrowSize * 0.7f;
|
||||
|
||||
const Rectangle<float> area (content.getBounds().toFloat().expanded (gap, gap));
|
||||
const Point<float> target (targetPoint - getPosition().toFloat());
|
||||
|
||||
outline.startNewSubPath (area.getX() + cornerSize, area.getY());
|
||||
|
||||
const float targetLimitX = area.getX() + cornerSize + arrowBaseWidth;
|
||||
const float targetLimitW = area.getWidth() - cornerSize2 - arrowBaseWidth * 2.0f;
|
||||
|
||||
const float targetLimitY = area.getY() + cornerSize + arrowBaseWidth;
|
||||
const float targetLimitH = area.getHeight() - cornerSize2 - arrowBaseWidth * 2.0f;
|
||||
|
||||
if (Rectangle<float> (targetLimitX, 1.0f,
|
||||
targetLimitW, area.getY() - 2.0f).contains (target))
|
||||
{
|
||||
outline.lineTo (target.x - arrowBaseWidth, area.getY());
|
||||
outline.lineTo (target.x, target.y);
|
||||
outline.lineTo (target.x + arrowBaseWidth, area.getY());
|
||||
}
|
||||
|
||||
outline.lineTo (area.getRight() - cornerSize, area.getY());
|
||||
outline.addArc (area.getRight() - cornerSize2, area.getY(), cornerSize2, cornerSize2, 0, float_Pi * 0.5f);
|
||||
|
||||
if (Rectangle<float> (area.getRight() + 1.0f, targetLimitY,
|
||||
getWidth() - area.getRight() - 2.0f, targetLimitH).contains (target))
|
||||
{
|
||||
outline.lineTo (area.getRight(), target.y - arrowBaseWidth);
|
||||
outline.lineTo (target.x, target.y);
|
||||
outline.lineTo (area.getRight(), target.y + arrowBaseWidth);
|
||||
}
|
||||
|
||||
outline.lineTo (area.getRight(), area.getBottom() - cornerSize);
|
||||
outline.addArc (area.getRight() - cornerSize2, area.getBottom() - cornerSize2, cornerSize2, cornerSize2, float_Pi * 0.5f, float_Pi);
|
||||
|
||||
if (Rectangle<float> (targetLimitX, area.getBottom() + 1.0f,
|
||||
targetLimitW, getHeight() - area.getBottom() - 2.0f).contains (target))
|
||||
{
|
||||
outline.lineTo (target.x + arrowBaseWidth, area.getBottom());
|
||||
outline.lineTo (target.x, target.y);
|
||||
outline.lineTo (target.x - arrowBaseWidth, area.getBottom());
|
||||
}
|
||||
|
||||
outline.lineTo (area.getX() + cornerSize, area.getBottom());
|
||||
outline.addArc (area.getX(), area.getBottom() - cornerSize2, cornerSize2, cornerSize2, float_Pi, float_Pi * 1.5f);
|
||||
|
||||
if (Rectangle<float> (1.0f, targetLimitY, area.getX() - 2.0f, targetLimitH).contains (target))
|
||||
{
|
||||
outline.lineTo (area.getX(), target.y + arrowBaseWidth);
|
||||
outline.lineTo (target.x, target.y);
|
||||
outline.lineTo (area.getX(), target.y - arrowBaseWidth);
|
||||
}
|
||||
|
||||
outline.lineTo (area.getX(), area.getY() + cornerSize);
|
||||
outline.addArc (area.getX(), area.getY(), cornerSize2, cornerSize2, float_Pi * 1.5f, float_Pi * 2.0f - 0.05f);
|
||||
|
||||
outline.closeSubPath();
|
||||
outline.addBubble (content.getBounds().toFloat().expanded (gap, gap),
|
||||
getLocalBounds().toFloat(),
|
||||
targetPoint - getPosition().toFloat(),
|
||||
9.0f, arrowSize * 0.7f);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,17 +31,16 @@ BubbleMessageComponent::BubbleMessageComponent (int fadeOutLengthMs)
|
|||
|
||||
BubbleMessageComponent::~BubbleMessageComponent()
|
||||
{
|
||||
Desktop::getInstance().getAnimator().fadeOut (this, fadeOutLength);
|
||||
}
|
||||
|
||||
void BubbleMessageComponent::showAt (int x, int y,
|
||||
void BubbleMessageComponent::showAt (const Rectangle<int>& pos,
|
||||
const AttributedString& text,
|
||||
const int numMillisecondsBeforeRemoving,
|
||||
const bool removeWhenMouseClicked,
|
||||
const bool deleteSelfAfterUse)
|
||||
{
|
||||
createLayout (text);
|
||||
setPosition (x, y);
|
||||
setPosition (pos);
|
||||
init (numMillisecondsBeforeRemoving, removeWhenMouseClicked, deleteSelfAfterUse);
|
||||
}
|
||||
|
||||
|
|
@ -65,55 +64,56 @@ void BubbleMessageComponent::init (const int numMillisecondsBeforeRemoving,
|
|||
const bool removeWhenMouseClicked,
|
||||
const bool deleteSelfAfterUse)
|
||||
{
|
||||
setAlpha (1.0f);
|
||||
setVisible (true);
|
||||
|
||||
deleteAfterUse = deleteSelfAfterUse;
|
||||
|
||||
if (numMillisecondsBeforeRemoving > 0)
|
||||
expiryTime = Time::getMillisecondCounter() + numMillisecondsBeforeRemoving;
|
||||
else
|
||||
expiryTime = 0;
|
||||
|
||||
startTimer (77);
|
||||
expiryTime = numMillisecondsBeforeRemoving > 0
|
||||
? (Time::getMillisecondCounter() + numMillisecondsBeforeRemoving) : 0;
|
||||
|
||||
mouseClickCounter = Desktop::getInstance().getMouseButtonClickCounter();
|
||||
|
||||
if (! (removeWhenMouseClicked && isShowing()))
|
||||
mouseClickCounter += 0xfffff;
|
||||
|
||||
startTimer (77);
|
||||
repaint();
|
||||
}
|
||||
|
||||
const float bubblePaddingX = 20.0f;
|
||||
const float bubblePaddingY = 14.0f;
|
||||
|
||||
void BubbleMessageComponent::getContentSize (int& w, int& h)
|
||||
{
|
||||
w = 20 + (int) textLayout.getWidth();
|
||||
h = 20 + (int) textLayout.getHeight();
|
||||
w = (int) (bubblePaddingX + textLayout.getWidth());
|
||||
h = (int) (bubblePaddingY + textLayout.getHeight());
|
||||
}
|
||||
|
||||
void BubbleMessageComponent::paintContent (Graphics& g, int w, int h)
|
||||
{
|
||||
g.setColour (findColour (TooltipWindow::textColourId));
|
||||
|
||||
textLayout.draw (g, Rectangle<float> (6.0f, 6.0f, w - 12.0f, h - 12.0f));
|
||||
textLayout.draw (g, Rectangle<float> (bubblePaddingX / 2.0f, bubblePaddingY / 2.0f,
|
||||
w - bubblePaddingX, h - bubblePaddingY));
|
||||
}
|
||||
|
||||
void BubbleMessageComponent::timerCallback()
|
||||
{
|
||||
if (Desktop::getInstance().getMouseButtonClickCounter() > mouseClickCounter)
|
||||
{
|
||||
stopTimer();
|
||||
hide (false);
|
||||
else if (expiryTime != 0 && Time::getMillisecondCounter() > expiryTime)
|
||||
hide (true);
|
||||
}
|
||||
|
||||
void BubbleMessageComponent::hide (const bool fadeOut)
|
||||
{
|
||||
stopTimer();
|
||||
|
||||
if (fadeOut)
|
||||
Desktop::getInstance().getAnimator().fadeOut (this, fadeOutLength);
|
||||
else
|
||||
setVisible (false);
|
||||
|
||||
if (deleteAfterUse)
|
||||
delete this;
|
||||
}
|
||||
else if (expiryTime != 0 && Time::getMillisecondCounter() > expiryTime)
|
||||
{
|
||||
stopTimer();
|
||||
|
||||
if (deleteAfterUse)
|
||||
delete this;
|
||||
else
|
||||
Desktop::getInstance().getAnimator().fadeOut (this, fadeOutLength);
|
||||
}
|
||||
if (deleteAfterUse)
|
||||
delete this;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,8 +65,7 @@ public:
|
|||
For details about exactly how it decides where to position itself, see
|
||||
BubbleComponent::updatePosition().
|
||||
|
||||
@param x the x co-ordinate of end of the bubble's tail
|
||||
@param y the y co-ordinate of end of the bubble's tail
|
||||
@param position the coords of the object to point to
|
||||
@param message the text to display
|
||||
@param numMillisecondsBeforeRemoving how long to leave it on the screen before removing itself
|
||||
from its parent compnent. If this is 0 or less, it
|
||||
|
|
@ -76,7 +75,7 @@ public:
|
|||
@param deleteSelfAfterUse if true, then the component will delete itself after
|
||||
it becomes invisible
|
||||
*/
|
||||
void showAt (int x, int y,
|
||||
void showAt (const Rectangle<int>& position,
|
||||
const AttributedString& message,
|
||||
int numMillisecondsBeforeRemoving,
|
||||
bool removeWhenMouseClicked = true,
|
||||
|
|
@ -125,6 +124,7 @@ private:
|
|||
void init (int numMillisecondsBeforeRemoving,
|
||||
bool removeWhenMouseClicked,
|
||||
bool deleteSelfAfterUse);
|
||||
void hide (bool fadeOut);
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BubbleMessageComponent);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue