| @@ -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) | |||
| { | |||
| if (w > 1.0f && h > 1.0f) | |||
| { | |||
| 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); | |||
| } | |||
| void Path::addBubble (const Rectangle<float>& bodyArea, | |||
| const Rectangle<float>& maximumArea, | |||
| const Point<float>& arrowTip, | |||
| const float cornerSize, | |||
| const float arrowBaseWidth) | |||
| { | |||
| const float cornerSize2 = 2.0f * cornerSize; | |||
| lineTo (x + w - cs, y); | |||
| startNewSubPath (bodyArea.getX() + cornerSize, bodyArea.getY()); | |||
| if (cs > 0.0f) | |||
| addArc (x + w - cs2, y, cs2, cs2, 0, float_Pi * 0.5f); | |||
| const float targetLimitX = bodyArea.getX() + cornerSize + arrowBaseWidth; | |||
| const float targetLimitW = bodyArea.getWidth() - cornerSize2 - arrowBaseWidth * 2.0f; | |||
| 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); | |||
| } | |||
| const float targetLimitY = bodyArea.getY() + cornerSize + arrowBaseWidth; | |||
| const float targetLimitH = bodyArea.getHeight() - cornerSize2 - arrowBaseWidth * 2.0f; | |||
| lineTo (x + w, y + h - cs); | |||
| if (Rectangle<float> (targetLimitX, maximumArea.getY(), | |||
| targetLimitW, bodyArea.getY() - maximumArea.getY()).contains (arrowTip)) | |||
| { | |||
| lineTo (arrowTip.x - arrowBaseWidth, bodyArea.getY()); | |||
| lineTo (arrowTip.x, arrowTip.y); | |||
| lineTo (arrowTip.x + arrowBaseWidth, bodyArea.getY()); | |||
| } | |||
| if (cs > 0.0f) | |||
| addArc (x + w - cs2, y + h - cs2, cs2, cs2, float_Pi * 0.5f, float_Pi); | |||
| lineTo (bodyArea.getRight() - cornerSize, bodyArea.getY()); | |||
| addArc (bodyArea.getRight() - cornerSize2, bodyArea.getY(), cornerSize2, cornerSize2, 0, float_Pi * 0.5f); | |||
| 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); | |||
| } | |||
| 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 (x + cs, y + h); | |||
| lineTo (bodyArea.getRight(), bodyArea.getBottom() - cornerSize); | |||
| addArc (bodyArea.getRight() - cornerSize2, bodyArea.getBottom() - cornerSize2, cornerSize2, cornerSize2, float_Pi * 0.5f, float_Pi); | |||
| if (cs > 0.0f) | |||
| addArc (x, y + h - cs2, cs2, cs2, float_Pi, float_Pi * 1.5f); | |||
| 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()); | |||
| } | |||
| 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 (bodyArea.getX() + cornerSize, bodyArea.getBottom()); | |||
| addArc (bodyArea.getX(), bodyArea.getBottom() - cornerSize2, cornerSize2, cornerSize2, float_Pi, float_Pi * 1.5f); | |||
| lineTo (x, y + cs); | |||
| 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); | |||
| } | |||
| if (cs > 0.0f) | |||
| addArc (x, y, cs2, cs2, float_Pi * 1.5f, float_Pi * 2.0f - PathHelpers::ellipseAngularIncrement); | |||
| lineTo (bodyArea.getX(), bodyArea.getY() + cornerSize); | |||
| addArc (bodyArea.getX(), bodyArea.getY(), cornerSize2, cornerSize2, float_Pi * 1.5f, float_Pi * 2.0f - 0.05f); | |||
| closeSubPath(); | |||
| } | |||
| 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 | |||
| */ | |||
| void addBubble (float bodyX, float bodyY, | |||
| float bodyW, float bodyH, | |||
| float cornerSize, | |||
| float arrowTipX, | |||
| float arrowTipY, | |||
| int whichSide, | |||
| float arrowPositionAlongEdgeProportional, | |||
| float arrowWidth); | |||
| @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 (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; | |||
| { | |||
| int contentW = 150, contentH = 30; | |||
| getContentSize (contentW, contentH); | |||
| content.setBounds (edgeSpace, edgeSpace, contentW, contentH); | |||
| } | |||
| getContentSize (w, h); | |||
| w += 30; | |||
| h += 30; | |||
| int totalW = content.getWidth() + edgeSpace * 2; | |||
| int totalH = content.getHeight() + edgeSpace * 2; | |||
| int targetX, targetY; | |||
| const float edgeIndent = 2.0f; | |||
| const int arrowLength = jmin (10, h / 3, w / 3); | |||
| const Rectangle<int> availableSpace (getParentComponent() != nullptr ? getParentComponent()->getLocalBounds() | |||
| : getParentMonitorArea()); | |||
| int spaceAbove = ((allowablePlacements & above) != 0) ? jmax (0, rectangleToPointTo.getY() - availableSpace.getY()) : -1; | |||
| 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); | |||
| }; | |||