| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE library.
 -    Copyright (c) 2020 - Raw Material Software Limited
 - 
 -    JUCE is an open source library subject to commercial or open-source
 -    licensing.
 - 
 -    By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 -    Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 - 
 -    End User License Agreement: www.juce.com/juce-6-licence
 -    Privacy Policy: www.juce.com/juce-privacy-policy
 - 
 -    Or: You may also use this code under the terms of the GPL v3 (see
 -    www.gnu.org/licenses).
 - 
 -    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 -    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 -    DISCLAIMED.
 - 
 -   ==============================================================================
 - */
 - 
 - namespace juce
 - {
 - 
 - TooltipWindow::TooltipWindow (Component* parentComp, int delayMs)
 -     : Component ("tooltip"),
 -       millisecondsBeforeTipAppears (delayMs)
 - {
 -     setAlwaysOnTop (true);
 -     setOpaque (true);
 -     setAccessible (false);
 - 
 -     if (parentComp != nullptr)
 -         parentComp->addChildComponent (this);
 - 
 -     auto& desktop = Desktop::getInstance();
 - 
 -     if (desktop.getMainMouseSource().canHover())
 -     {
 -         desktop.addGlobalMouseListener (this);
 -         startTimer (123);
 -     }
 - }
 - 
 - TooltipWindow::~TooltipWindow()
 - {
 -     hideTip();
 -     Desktop::getInstance().removeGlobalMouseListener (this);
 - }
 - 
 - void TooltipWindow::setMillisecondsBeforeTipAppears (const int newTimeMs) noexcept
 - {
 -     millisecondsBeforeTipAppears = newTimeMs;
 - }
 - 
 - void TooltipWindow::paint (Graphics& g)
 - {
 -     getLookAndFeel().drawTooltip (g, tipShowing, getWidth(), getHeight());
 - }
 - 
 - void TooltipWindow::mouseEnter (const MouseEvent& e)
 - {
 -     if (e.eventComponent == this)
 -         hideTip();
 - }
 - 
 - void TooltipWindow::mouseDown (const MouseEvent&)
 - {
 -     if (isVisible())
 -         dismissalMouseEventOccurred = true;
 - }
 - 
 - void TooltipWindow::mouseWheelMove (const MouseEvent&, const MouseWheelDetails&)
 - {
 -     if (isVisible())
 -         dismissalMouseEventOccurred = true;
 - }
 - 
 - void TooltipWindow::updatePosition (const String& tip, Point<int> pos, Rectangle<int> parentArea)
 - {
 -     setBounds (getLookAndFeel().getTooltipBounds (tip, pos, parentArea));
 -     setVisible (true);
 - }
 - 
 - #if JUCE_DEBUG
 - static Array<TooltipWindow*> activeTooltipWindows;
 - #endif
 - 
 - void TooltipWindow::displayTip (Point<int> screenPos, const String& tip)
 - {
 -     jassert (tip.isNotEmpty());
 - 
 -     displayTipInternal (screenPos, tip, ShownManually::yes);
 - }
 - 
 - void TooltipWindow::displayTipInternal (Point<int> screenPos, const String& tip, ShownManually shownManually)
 - {
 -     if (! reentrant)
 -     {
 -         ScopedValueSetter<bool> setter (reentrant, true, false);
 - 
 -         if (tipShowing != tip)
 -         {
 -             tipShowing = tip;
 -             repaint();
 -         }
 - 
 -         if (auto* parent = getParentComponent())
 -         {
 -             updatePosition (tip, parent->getLocalPoint (nullptr, screenPos),
 -                             parent->getLocalBounds());
 -         }
 -         else
 -         {
 -             const auto physicalPos = ScalingHelpers::scaledScreenPosToUnscaled (screenPos);
 -             const auto scaledPos = ScalingHelpers::unscaledScreenPosToScaled (*this, physicalPos);
 -             updatePosition (tip, scaledPos, Desktop::getInstance().getDisplays().getDisplayForPoint (screenPos)->userArea);
 - 
 -             addToDesktop (ComponentPeer::windowHasDropShadow
 -                           | ComponentPeer::windowIsTemporary
 -                           | ComponentPeer::windowIgnoresKeyPresses
 -                           | ComponentPeer::windowIgnoresMouseClicks);
 -         }
 - 
 -        #if JUCE_DEBUG
 -         activeTooltipWindows.addIfNotAlreadyThere (this);
 - 
 -         auto* parent = getParentComponent();
 - 
 -         for (auto* w : activeTooltipWindows)
 -         {
 -             if (w != nullptr && w != this && w->tipShowing == tipShowing && w->getParentComponent() == parent)
 -             {
 -                 // Looks like you have more than one TooltipWindow showing the same tip..
 -                 // Be careful not to create more than one instance of this class with the
 -                 // same parent component!
 -                 jassertfalse;
 -             }
 -         }
 -        #endif
 - 
 -         toFront (false);
 -         manuallyShownTip = shownManually == ShownManually::yes ? tip : String();
 -         dismissalMouseEventOccurred = false;
 -     }
 - }
 - 
 - String TooltipWindow::getTipFor (Component& c)
 - {
 -     if (isForegroundOrEmbeddedProcess (&c)
 -          && ! ModifierKeys::currentModifiers.isAnyMouseButtonDown())
 -     {
 -         if (auto* ttc = dynamic_cast<TooltipClient*> (&c))
 -             if (! c.isCurrentlyBlockedByAnotherModalComponent())
 -                 return ttc->getTooltip();
 -     }
 - 
 -     return {};
 - }
 - 
 - void TooltipWindow::hideTip()
 - {
 -     if (isVisible() && ! reentrant)
 -     {
 -         tipShowing = {};
 -         manuallyShownTip = {};
 -         dismissalMouseEventOccurred = false;
 - 
 -         removeFromDesktop();
 -         setVisible (false);
 - 
 -         lastHideTime = Time::getApproximateMillisecondCounter();
 - 
 -        #if JUCE_DEBUG
 -         activeTooltipWindows.removeAllInstancesOf (this);
 -        #endif
 -     }
 - }
 - 
 - float TooltipWindow::getDesktopScaleFactor() const
 - {
 -     if (lastComponentUnderMouse != nullptr)
 -         return Component::getApproximateScaleFactorForComponent (lastComponentUnderMouse);
 - 
 -     return Component::getDesktopScaleFactor();
 - }
 - 
 - std::unique_ptr<AccessibilityHandler> TooltipWindow::createAccessibilityHandler()
 - {
 -     return createIgnoredAccessibilityHandler (*this);
 - }
 - 
 - void TooltipWindow::timerCallback()
 - {
 -     const auto mouseSource = Desktop::getInstance().getMainMouseSource();
 -     auto* newComp = mouseSource.isTouch() ? nullptr : mouseSource.getComponentUnderMouse();
 - 
 -     if (manuallyShownTip.isNotEmpty())
 -     {
 -         if (dismissalMouseEventOccurred || newComp == nullptr)
 -             hideTip();
 - 
 -         return;
 -     }
 - 
 -     if (newComp == nullptr || getParentComponent() == nullptr || newComp->getPeer() == getPeer())
 -     {
 -         const auto newTip = newComp != nullptr ? getTipFor (*newComp) : String();
 - 
 -         const auto mousePos = mouseSource.getScreenPosition();
 -         const auto mouseMovedQuickly = (mousePos.getDistanceFrom (lastMousePos) > 12);
 -         lastMousePos = mousePos;
 - 
 -         const auto tipChanged = (newTip != lastTipUnderMouse || newComp != lastComponentUnderMouse);
 -         const auto now = Time::getApproximateMillisecondCounter();
 - 
 -         lastComponentUnderMouse = newComp;
 -         lastTipUnderMouse = newTip;
 - 
 -         if (tipChanged || dismissalMouseEventOccurred || mouseMovedQuickly)
 -             lastCompChangeTime = now;
 - 
 -         const auto showTip = [this, &mouseSource, &mousePos, &newTip]
 -         {
 -             if (mouseSource.getLastMouseDownPosition() != lastMousePos)
 -                 displayTipInternal (mousePos.roundToInt(), newTip, ShownManually::no);
 -         };
 - 
 -         if (isVisible() || now < lastHideTime + 500)
 -         {
 -             // if a tip is currently visible (or has just disappeared), update to a new one
 -             // immediately if needed..
 -             if (newComp == nullptr || dismissalMouseEventOccurred || newTip.isEmpty())
 -                 hideTip();
 -             else if (tipChanged)
 -                 showTip();
 -         }
 -         else
 -         {
 -             // if there isn't currently a tip, but one is needed, only let it appear after a timeout
 -             if (newTip.isNotEmpty()
 -                 && newTip != tipShowing
 -                 && now > lastCompChangeTime + (uint32) millisecondsBeforeTipAppears)
 -             {
 -                 showTip();
 -             }
 -         }
 -     }
 - }
 - 
 - } // namespace juce
 
 
  |