migrating to the latest JUCE version
This commit is contained in:
		
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,274 +1,271 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
CallOutBox::CallOutBox (Component& c, Rectangle<int> area, Component* const parent)
 | 
			
		||||
    : content (c)
 | 
			
		||||
{
 | 
			
		||||
    addAndMakeVisible (content);
 | 
			
		||||
 | 
			
		||||
    if (parent != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        parent->addChildComponent (this);
 | 
			
		||||
        updatePosition (area, parent->getLocalBounds());
 | 
			
		||||
        setVisible (true);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        setAlwaysOnTop (juce_areThereAnyAlwaysOnTopWindows());
 | 
			
		||||
        updatePosition (area, Desktop::getInstance().getDisplays().getDisplayForRect (area)->userArea);
 | 
			
		||||
        addToDesktop (ComponentPeer::windowIsTemporary);
 | 
			
		||||
 | 
			
		||||
        startTimer (100);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    creationTime = Time::getCurrentTime();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class CallOutBoxCallback  : public ModalComponentManager::Callback,
 | 
			
		||||
                            private Timer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    CallOutBoxCallback (std::unique_ptr<Component> c, const Rectangle<int>& area, Component* parent, bool dismissIfBg)
 | 
			
		||||
        : content (std::move (c)),
 | 
			
		||||
          callout (*content, area, parent), dismissIfBackgrounded(dismissIfBg)
 | 
			
		||||
    {
 | 
			
		||||
        callout.setVisible (true);
 | 
			
		||||
        callout.enterModalState (true, this);
 | 
			
		||||
        if (dismissIfBackgrounded) {
 | 
			
		||||
            startTimer (200);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void modalStateFinished (int) override {}
 | 
			
		||||
 | 
			
		||||
    void timerCallback() override
 | 
			
		||||
    {
 | 
			
		||||
        if (! isForegroundOrEmbeddedProcess (&callout))
 | 
			
		||||
            callout.dismiss();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<Component> content;
 | 
			
		||||
    CallOutBox callout;
 | 
			
		||||
    bool dismissIfBackgrounded = true;
 | 
			
		||||
    
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE (CallOutBoxCallback)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
CallOutBox& CallOutBox::launchAsynchronously (std::unique_ptr<Component> content, Rectangle<int> area, Component* parent, bool dismissIfBackgrounded)
 | 
			
		||||
{
 | 
			
		||||
    jassert (content != nullptr); // must be a valid content component!
 | 
			
		||||
 | 
			
		||||
    return (new CallOutBoxCallback (std::move (content), area, parent, dismissIfBackgrounded))->callout;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void CallOutBox::setArrowSize (const float newSize)
 | 
			
		||||
{
 | 
			
		||||
    arrowSize = newSize;
 | 
			
		||||
    refreshPath();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int CallOutBox::getBorderSize() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return jmax (getLookAndFeel().getCallOutBoxBorderSize (*this), (int) arrowSize);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CallOutBox::lookAndFeelChanged()
 | 
			
		||||
{
 | 
			
		||||
    resized();
 | 
			
		||||
    repaint();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CallOutBox::paint (Graphics& g)
 | 
			
		||||
{
 | 
			
		||||
    getLookAndFeel().drawCallOutBoxBackground (*this, g, outline, background);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CallOutBox::resized()
 | 
			
		||||
{
 | 
			
		||||
    auto borderSpace = getBorderSize();
 | 
			
		||||
    content.setTopLeftPosition (borderSpace, borderSpace);
 | 
			
		||||
    refreshPath();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CallOutBox::moved()
 | 
			
		||||
{
 | 
			
		||||
    refreshPath();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CallOutBox::childBoundsChanged (Component*)
 | 
			
		||||
{
 | 
			
		||||
    updatePosition (targetArea, availableArea);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CallOutBox::hitTest (int x, int y)
 | 
			
		||||
{
 | 
			
		||||
    return outline.contains ((float) x, (float) y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CallOutBox::inputAttemptWhenModal()
 | 
			
		||||
{
 | 
			
		||||
    if (dismissalMouseClicksAreAlwaysConsumed
 | 
			
		||||
         || targetArea.contains (getMouseXYRelative() + getBounds().getPosition()))
 | 
			
		||||
    {
 | 
			
		||||
        // if you click on the area that originally popped-up the callout, you expect it
 | 
			
		||||
        // to get rid of the box, but deleting the box here allows the click to pass through and
 | 
			
		||||
        // probably re-trigger it, so we need to dismiss the box asynchronously to consume the click..
 | 
			
		||||
 | 
			
		||||
        // For touchscreens, we make sure not to dismiss the CallOutBox immediately,
 | 
			
		||||
        // as Windows still sends touch events before the CallOutBox had a chance
 | 
			
		||||
        // to really open.
 | 
			
		||||
 | 
			
		||||
        auto elapsed = Time::getCurrentTime() - creationTime;
 | 
			
		||||
 | 
			
		||||
        if (elapsed.inMilliseconds() > 200)
 | 
			
		||||
            dismiss();
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        exitModalState (0);
 | 
			
		||||
        setVisible (false);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CallOutBox::setDismissalMouseClicksAreAlwaysConsumed (bool b) noexcept
 | 
			
		||||
{
 | 
			
		||||
    dismissalMouseClicksAreAlwaysConsumed = b;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static constexpr int callOutBoxDismissCommandId = 0x4f83a04b;
 | 
			
		||||
 | 
			
		||||
void CallOutBox::handleCommandMessage (int commandId)
 | 
			
		||||
{
 | 
			
		||||
    Component::handleCommandMessage (commandId);
 | 
			
		||||
 | 
			
		||||
    if (commandId == callOutBoxDismissCommandId)
 | 
			
		||||
    {
 | 
			
		||||
        exitModalState (0);
 | 
			
		||||
        setVisible (false);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CallOutBox::dismiss()
 | 
			
		||||
{
 | 
			
		||||
    postCommandMessage (callOutBoxDismissCommandId);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CallOutBox::keyPressed (const KeyPress& key)
 | 
			
		||||
{
 | 
			
		||||
    if (key.isKeyCode (KeyPress::escapeKey))
 | 
			
		||||
    {
 | 
			
		||||
        inputAttemptWhenModal();
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CallOutBox::updatePosition (const Rectangle<int>& newAreaToPointTo, const Rectangle<int>& newAreaToFitIn)
 | 
			
		||||
{
 | 
			
		||||
    targetArea = newAreaToPointTo;
 | 
			
		||||
    availableArea = newAreaToFitIn;
 | 
			
		||||
 | 
			
		||||
    auto borderSpace = getBorderSize();
 | 
			
		||||
    auto newBounds = getLocalArea (&content, Rectangle<int> (content.getWidth()  + borderSpace * 2,
 | 
			
		||||
                                                             content.getHeight() + borderSpace * 2));
 | 
			
		||||
 | 
			
		||||
    auto hw = newBounds.getWidth() / 2;
 | 
			
		||||
    auto hh = newBounds.getHeight() / 2;
 | 
			
		||||
    auto hwReduced = (float) (hw - borderSpace * 2);
 | 
			
		||||
    auto hhReduced = (float) (hh - borderSpace * 2);
 | 
			
		||||
    auto arrowIndent = (float) borderSpace - arrowSize;
 | 
			
		||||
 | 
			
		||||
    Point<float> targets[4] = { { (float) targetArea.getCentreX(), (float) targetArea.getBottom() },
 | 
			
		||||
                                { (float) targetArea.getRight(),   (float) targetArea.getCentreY() },
 | 
			
		||||
                                { (float) targetArea.getX(),       (float) targetArea.getCentreY() },
 | 
			
		||||
                                { (float) targetArea.getCentreX(), (float) targetArea.getY() } };
 | 
			
		||||
 | 
			
		||||
    Line<float> lines[4] = { { targets[0].translated (-hwReduced, hh - arrowIndent),    targets[0].translated (hwReduced, hh - arrowIndent) },
 | 
			
		||||
                             { targets[1].translated (hw - arrowIndent, -hhReduced),    targets[1].translated (hw - arrowIndent, hhReduced) },
 | 
			
		||||
                             { targets[2].translated (-(hw - arrowIndent), -hhReduced), targets[2].translated (-(hw - arrowIndent), hhReduced) },
 | 
			
		||||
                             { targets[3].translated (-hwReduced, -(hh - arrowIndent)), targets[3].translated (hwReduced, -(hh - arrowIndent)) } };
 | 
			
		||||
 | 
			
		||||
    auto centrePointArea = newAreaToFitIn.reduced (hw, hh).toFloat();
 | 
			
		||||
    auto targetCentre = targetArea.getCentre().toFloat();
 | 
			
		||||
 | 
			
		||||
    float nearest = 1.0e9f;
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < 4; ++i)
 | 
			
		||||
    {
 | 
			
		||||
        Line<float> constrainedLine (centrePointArea.getConstrainedPoint (lines[i].getStart()),
 | 
			
		||||
                                     centrePointArea.getConstrainedPoint (lines[i].getEnd()));
 | 
			
		||||
 | 
			
		||||
        auto centre = constrainedLine.findNearestPointTo (targetCentre);
 | 
			
		||||
        auto distanceFromCentre = centre.getDistanceFrom (targets[i]);
 | 
			
		||||
 | 
			
		||||
        if (! centrePointArea.intersects (lines[i]))
 | 
			
		||||
            distanceFromCentre += 1000.0f;
 | 
			
		||||
 | 
			
		||||
        if (distanceFromCentre < nearest)
 | 
			
		||||
        {
 | 
			
		||||
            nearest = distanceFromCentre;
 | 
			
		||||
            targetPoint = targets[i];
 | 
			
		||||
 | 
			
		||||
            newBounds.setPosition ((int) (centre.x - (float) hw),
 | 
			
		||||
                                   (int) (centre.y - (float) hh));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setBounds (newBounds);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CallOutBox::refreshPath()
 | 
			
		||||
{
 | 
			
		||||
    repaint();
 | 
			
		||||
    background = {};
 | 
			
		||||
    outline.clear();
 | 
			
		||||
 | 
			
		||||
    const float gap = 4.5f;
 | 
			
		||||
 | 
			
		||||
    outline.addBubble (getLocalArea (&content, content.getLocalBounds().toFloat()).expanded (gap, gap),
 | 
			
		||||
                       getLocalBounds().toFloat(),
 | 
			
		||||
                       targetPoint - getPosition().toFloat(),
 | 
			
		||||
                       getLookAndFeel().getCallOutBoxCornerSize (*this), arrowSize * 0.7f);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CallOutBox::timerCallback()
 | 
			
		||||
{
 | 
			
		||||
    toFront (true);
 | 
			
		||||
    stopTimer();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
std::unique_ptr<AccessibilityHandler> CallOutBox::createAccessibilityHandler()
 | 
			
		||||
{
 | 
			
		||||
    return std::make_unique<AccessibilityHandler> (*this, AccessibilityRole::window);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - 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 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
CallOutBox::CallOutBox (Component& c, Rectangle<int> area, Component* const parent)
 | 
			
		||||
    : content (c)
 | 
			
		||||
{
 | 
			
		||||
    addAndMakeVisible (content);
 | 
			
		||||
 | 
			
		||||
    if (parent != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        parent->addChildComponent (this);
 | 
			
		||||
        updatePosition (area, parent->getLocalBounds());
 | 
			
		||||
        setVisible (true);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        setAlwaysOnTop (juce_areThereAnyAlwaysOnTopWindows());
 | 
			
		||||
        updatePosition (area, Desktop::getInstance().getDisplays().getDisplayForRect (area)->userArea);
 | 
			
		||||
        addToDesktop (ComponentPeer::windowIsTemporary);
 | 
			
		||||
 | 
			
		||||
        startTimer (100);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    creationTime = Time::getCurrentTime();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class CallOutBoxCallback  : public ModalComponentManager::Callback,
 | 
			
		||||
                            private Timer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    CallOutBoxCallback (std::unique_ptr<Component> c, const Rectangle<int>& area, Component* parent)
 | 
			
		||||
        : content (std::move (c)),
 | 
			
		||||
          callout (*content, area, parent)
 | 
			
		||||
    {
 | 
			
		||||
        callout.setVisible (true);
 | 
			
		||||
        callout.enterModalState (true, this);
 | 
			
		||||
        startTimer (200);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void modalStateFinished (int) override {}
 | 
			
		||||
 | 
			
		||||
    void timerCallback() override
 | 
			
		||||
    {
 | 
			
		||||
        if (! isForegroundOrEmbeddedProcess (&callout))
 | 
			
		||||
            callout.dismiss();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<Component> content;
 | 
			
		||||
    CallOutBox callout;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE (CallOutBoxCallback)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
CallOutBox& CallOutBox::launchAsynchronously (std::unique_ptr<Component> content, Rectangle<int> area, Component* parent)
 | 
			
		||||
{
 | 
			
		||||
    jassert (content != nullptr); // must be a valid content component!
 | 
			
		||||
 | 
			
		||||
    return (new CallOutBoxCallback (std::move (content), area, parent))->callout;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void CallOutBox::setArrowSize (const float newSize)
 | 
			
		||||
{
 | 
			
		||||
    arrowSize = newSize;
 | 
			
		||||
    refreshPath();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int CallOutBox::getBorderSize() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return jmax (getLookAndFeel().getCallOutBoxBorderSize (*this), (int) arrowSize);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CallOutBox::lookAndFeelChanged()
 | 
			
		||||
{
 | 
			
		||||
    resized();
 | 
			
		||||
    repaint();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CallOutBox::paint (Graphics& g)
 | 
			
		||||
{
 | 
			
		||||
    getLookAndFeel().drawCallOutBoxBackground (*this, g, outline, background);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CallOutBox::resized()
 | 
			
		||||
{
 | 
			
		||||
    auto borderSpace = getBorderSize();
 | 
			
		||||
    content.setTopLeftPosition (borderSpace, borderSpace);
 | 
			
		||||
    refreshPath();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CallOutBox::moved()
 | 
			
		||||
{
 | 
			
		||||
    refreshPath();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CallOutBox::childBoundsChanged (Component*)
 | 
			
		||||
{
 | 
			
		||||
    updatePosition (targetArea, availableArea);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CallOutBox::hitTest (int x, int y)
 | 
			
		||||
{
 | 
			
		||||
    return outline.contains ((float) x, (float) y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CallOutBox::inputAttemptWhenModal()
 | 
			
		||||
{
 | 
			
		||||
    if (dismissalMouseClicksAreAlwaysConsumed
 | 
			
		||||
         || targetArea.contains (getMouseXYRelative() + getBounds().getPosition()))
 | 
			
		||||
    {
 | 
			
		||||
        // if you click on the area that originally popped-up the callout, you expect it
 | 
			
		||||
        // to get rid of the box, but deleting the box here allows the click to pass through and
 | 
			
		||||
        // probably re-trigger it, so we need to dismiss the box asynchronously to consume the click..
 | 
			
		||||
 | 
			
		||||
        // For touchscreens, we make sure not to dismiss the CallOutBox immediately,
 | 
			
		||||
        // as Windows still sends touch events before the CallOutBox had a chance
 | 
			
		||||
        // to really open.
 | 
			
		||||
 | 
			
		||||
        auto elapsed = Time::getCurrentTime() - creationTime;
 | 
			
		||||
 | 
			
		||||
        if (elapsed.inMilliseconds() > 200)
 | 
			
		||||
            dismiss();
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        exitModalState (0);
 | 
			
		||||
        setVisible (false);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CallOutBox::setDismissalMouseClicksAreAlwaysConsumed (bool b) noexcept
 | 
			
		||||
{
 | 
			
		||||
    dismissalMouseClicksAreAlwaysConsumed = b;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static constexpr int callOutBoxDismissCommandId = 0x4f83a04b;
 | 
			
		||||
 | 
			
		||||
void CallOutBox::handleCommandMessage (int commandId)
 | 
			
		||||
{
 | 
			
		||||
    Component::handleCommandMessage (commandId);
 | 
			
		||||
 | 
			
		||||
    if (commandId == callOutBoxDismissCommandId)
 | 
			
		||||
    {
 | 
			
		||||
        exitModalState (0);
 | 
			
		||||
        setVisible (false);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CallOutBox::dismiss()
 | 
			
		||||
{
 | 
			
		||||
    postCommandMessage (callOutBoxDismissCommandId);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CallOutBox::keyPressed (const KeyPress& key)
 | 
			
		||||
{
 | 
			
		||||
    if (key.isKeyCode (KeyPress::escapeKey))
 | 
			
		||||
    {
 | 
			
		||||
        inputAttemptWhenModal();
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CallOutBox::updatePosition (const Rectangle<int>& newAreaToPointTo, const Rectangle<int>& newAreaToFitIn)
 | 
			
		||||
{
 | 
			
		||||
    targetArea = newAreaToPointTo;
 | 
			
		||||
    availableArea = newAreaToFitIn;
 | 
			
		||||
 | 
			
		||||
    auto borderSpace = getBorderSize();
 | 
			
		||||
    auto newBounds = getLocalArea (&content, Rectangle<int> (content.getWidth()  + borderSpace * 2,
 | 
			
		||||
                                                             content.getHeight() + borderSpace * 2));
 | 
			
		||||
 | 
			
		||||
    auto hw = newBounds.getWidth() / 2;
 | 
			
		||||
    auto hh = newBounds.getHeight() / 2;
 | 
			
		||||
    auto hwReduced = (float) (hw - borderSpace * 2);
 | 
			
		||||
    auto hhReduced = (float) (hh - borderSpace * 2);
 | 
			
		||||
    auto arrowIndent = (float) borderSpace - arrowSize;
 | 
			
		||||
 | 
			
		||||
    Point<float> targets[4] = { { (float) targetArea.getCentreX(), (float) targetArea.getBottom() },
 | 
			
		||||
                                { (float) targetArea.getRight(),   (float) targetArea.getCentreY() },
 | 
			
		||||
                                { (float) targetArea.getX(),       (float) targetArea.getCentreY() },
 | 
			
		||||
                                { (float) targetArea.getCentreX(), (float) targetArea.getY() } };
 | 
			
		||||
 | 
			
		||||
    Line<float> lines[4] = { { targets[0].translated (-hwReduced, hh - arrowIndent),    targets[0].translated (hwReduced, hh - arrowIndent) },
 | 
			
		||||
                             { targets[1].translated (hw - arrowIndent, -hhReduced),    targets[1].translated (hw - arrowIndent, hhReduced) },
 | 
			
		||||
                             { targets[2].translated (-(hw - arrowIndent), -hhReduced), targets[2].translated (-(hw - arrowIndent), hhReduced) },
 | 
			
		||||
                             { targets[3].translated (-hwReduced, -(hh - arrowIndent)), targets[3].translated (hwReduced, -(hh - arrowIndent)) } };
 | 
			
		||||
 | 
			
		||||
    auto centrePointArea = newAreaToFitIn.reduced (hw, hh).toFloat();
 | 
			
		||||
    auto targetCentre = targetArea.getCentre().toFloat();
 | 
			
		||||
 | 
			
		||||
    float nearest = 1.0e9f;
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < 4; ++i)
 | 
			
		||||
    {
 | 
			
		||||
        Line<float> constrainedLine (centrePointArea.getConstrainedPoint (lines[i].getStart()),
 | 
			
		||||
                                     centrePointArea.getConstrainedPoint (lines[i].getEnd()));
 | 
			
		||||
 | 
			
		||||
        auto centre = constrainedLine.findNearestPointTo (targetCentre);
 | 
			
		||||
        auto distanceFromCentre = centre.getDistanceFrom (targets[i]);
 | 
			
		||||
 | 
			
		||||
        if (! centrePointArea.intersects (lines[i]))
 | 
			
		||||
            distanceFromCentre += 1000.0f;
 | 
			
		||||
 | 
			
		||||
        if (distanceFromCentre < nearest)
 | 
			
		||||
        {
 | 
			
		||||
            nearest = distanceFromCentre;
 | 
			
		||||
            targetPoint = targets[i];
 | 
			
		||||
 | 
			
		||||
            newBounds.setPosition ((int) (centre.x - (float) hw),
 | 
			
		||||
                                   (int) (centre.y - (float) hh));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setBounds (newBounds);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CallOutBox::refreshPath()
 | 
			
		||||
{
 | 
			
		||||
    repaint();
 | 
			
		||||
    background = {};
 | 
			
		||||
    outline.clear();
 | 
			
		||||
 | 
			
		||||
    const float gap = 4.5f;
 | 
			
		||||
 | 
			
		||||
    outline.addBubble (getLocalArea (&content, content.getLocalBounds().toFloat()).expanded (gap, gap),
 | 
			
		||||
                       getLocalBounds().toFloat(),
 | 
			
		||||
                       targetPoint - getPosition().toFloat(),
 | 
			
		||||
                       getLookAndFeel().getCallOutBoxCornerSize (*this), arrowSize * 0.7f);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CallOutBox::timerCallback()
 | 
			
		||||
{
 | 
			
		||||
    toFront (true);
 | 
			
		||||
    stopTimer();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
std::unique_ptr<AccessibilityHandler> CallOutBox::createAccessibilityHandler()
 | 
			
		||||
{
 | 
			
		||||
    return std::make_unique<AccessibilityHandler> (*this, AccessibilityRole::dialogWindow);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,190 +1,187 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A box with a small arrow that can be used as a temporary pop-up window to show
 | 
			
		||||
    extra controls when a button or other component is clicked.
 | 
			
		||||
 | 
			
		||||
    Using one of these is similar to having a popup menu attached to a button or
 | 
			
		||||
    other component - but it looks fancier, and has an arrow that can indicate the
 | 
			
		||||
    object that it applies to.
 | 
			
		||||
 | 
			
		||||
    The class works best when shown modally, but obviously running modal loops is
 | 
			
		||||
    evil and must never be done, so the launchAsynchronously method is provided as
 | 
			
		||||
    a handy way of launching an instance of a CallOutBox and automatically managing
 | 
			
		||||
    its lifetime, e.g.
 | 
			
		||||
 | 
			
		||||
    @code
 | 
			
		||||
    void mouseUp (const MouseEvent&)
 | 
			
		||||
    {
 | 
			
		||||
        auto content = std::make_unique<FoobarContentComp>();
 | 
			
		||||
        content->setSize (300, 300);
 | 
			
		||||
 | 
			
		||||
        auto& myBox = CallOutBox::launchAsynchronously (std::move (content),
 | 
			
		||||
                                                        getScreenBounds(),
 | 
			
		||||
                                                        nullptr);
 | 
			
		||||
    }
 | 
			
		||||
    @endcode
 | 
			
		||||
 | 
			
		||||
    The call-out will resize and position itself when the content changes size.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  CallOutBox    : public Component,
 | 
			
		||||
                                private Timer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a CallOutBox.
 | 
			
		||||
 | 
			
		||||
        @param contentComponent     the component to display inside the call-out. This should
 | 
			
		||||
                                    already have a size set (although the call-out will also
 | 
			
		||||
                                    update itself when the component's size is changed later).
 | 
			
		||||
                                    Obviously this component must not be deleted until the
 | 
			
		||||
                                    call-out box has been deleted.
 | 
			
		||||
        @param areaToPointTo        the area that the call-out's arrow should point towards. If
 | 
			
		||||
                                    a parentComponent is supplied, then this is relative to that
 | 
			
		||||
                                    parent; otherwise, it's a global screen coord.
 | 
			
		||||
        @param parentComponent      if not a nullptr, this is the component to add the call-out to.
 | 
			
		||||
                                    If this is a nullptr, the call-out will be added to the desktop.
 | 
			
		||||
    */
 | 
			
		||||
    CallOutBox (Component& contentComponent,
 | 
			
		||||
                Rectangle<int> areaToPointTo,
 | 
			
		||||
                Component* parentComponent);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Changes the base width of the arrow. */
 | 
			
		||||
    void setArrowSize (float newSize);
 | 
			
		||||
 | 
			
		||||
    /** Updates the position and size of the box.
 | 
			
		||||
 | 
			
		||||
        You shouldn't normally need to call this, unless you need more precise control over the
 | 
			
		||||
        layout.
 | 
			
		||||
 | 
			
		||||
        @param newAreaToPointTo     the rectangle to make the box's arrow point to
 | 
			
		||||
        @param newAreaToFitIn       the area within which the box's position should be constrained
 | 
			
		||||
    */
 | 
			
		||||
    void updatePosition (const Rectangle<int>& newAreaToPointTo,
 | 
			
		||||
                         const Rectangle<int>& newAreaToFitIn);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** This will launch a callout box containing the given content, pointing to the
 | 
			
		||||
        specified target component.
 | 
			
		||||
 | 
			
		||||
        This method will create and display a callout, returning immediately, after which
 | 
			
		||||
        the box will continue to run modally until the user clicks on some other component, at
 | 
			
		||||
        which point it will be dismissed and deleted automatically.
 | 
			
		||||
 | 
			
		||||
        It returns a reference to the newly-created box so that you can customise it, but don't
 | 
			
		||||
        keep a pointer to it, as it'll be deleted at some point when it gets closed.
 | 
			
		||||
 | 
			
		||||
        @param contentComponent     the component to display inside the call-out. This should
 | 
			
		||||
                                    already have a size set (although the call-out will also
 | 
			
		||||
                                    update itself when the component's size is changed later).
 | 
			
		||||
        @param areaToPointTo        the area that the call-out's arrow should point towards. If
 | 
			
		||||
                                    a parentComponent is supplied, then this is relative to that
 | 
			
		||||
                                    parent; otherwise, it's a global screen coord.
 | 
			
		||||
        @param parentComponent      if not a nullptr, this is the component to add the call-out to.
 | 
			
		||||
                                    If this is a nullptr, the call-out will be added to the desktop.
 | 
			
		||||
        @param dismissIfBackgrounded      If this is true, the call-out will be dismissed if we are no
 | 
			
		||||
                                    longer the foreground app.
 | 
			
		||||
    */
 | 
			
		||||
    static CallOutBox& launchAsynchronously (std::unique_ptr<Component> contentComponent,
 | 
			
		||||
                                             Rectangle<int> areaToPointTo,
 | 
			
		||||
                                             Component* parentComponent,
 | 
			
		||||
                                             bool dismissIfBackgrounded=true);
 | 
			
		||||
 | 
			
		||||
    /** Posts a message which will dismiss the callout box asynchronously.
 | 
			
		||||
        NB: it's safe to call this method from any thread.
 | 
			
		||||
    */
 | 
			
		||||
    void dismiss();
 | 
			
		||||
 | 
			
		||||
    /** Determines whether the mouse events for clicks outside the calloutbox are
 | 
			
		||||
        consumed, or allowed to arrive at the other component that they were aimed at.
 | 
			
		||||
 | 
			
		||||
        By default this is false, so that when you click on something outside the calloutbox,
 | 
			
		||||
        that event will also be sent to the component that was clicked on. If you set it to
 | 
			
		||||
        true, then the first click will always just dismiss the box and not be sent to
 | 
			
		||||
        anything else.
 | 
			
		||||
    */
 | 
			
		||||
    void setDismissalMouseClicksAreAlwaysConsumed (bool shouldAlwaysBeConsumed) noexcept;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This abstract base class is implemented by LookAndFeel classes. */
 | 
			
		||||
    struct JUCE_API  LookAndFeelMethods
 | 
			
		||||
    {
 | 
			
		||||
        virtual ~LookAndFeelMethods() = default;
 | 
			
		||||
 | 
			
		||||
        virtual void drawCallOutBoxBackground (CallOutBox&, Graphics&, const Path&, Image&) = 0;
 | 
			
		||||
        virtual int getCallOutBoxBorderSize (const CallOutBox&) = 0;
 | 
			
		||||
        virtual float getCallOutBoxCornerSize (const CallOutBox&) = 0;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void resized() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void moved() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void childBoundsChanged (Component*) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    bool hitTest (int x, int y) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void inputAttemptWhenModal() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    bool keyPressed (const KeyPress&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void handleCommandMessage (int) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    int getBorderSize() const noexcept;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void lookAndFeelChanged() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    Component& content;
 | 
			
		||||
    Path outline;
 | 
			
		||||
    Point<float> targetPoint;
 | 
			
		||||
    Rectangle<int> availableArea, targetArea;
 | 
			
		||||
    Image background;
 | 
			
		||||
    float arrowSize = 16.0f;
 | 
			
		||||
    bool dismissalMouseClicksAreAlwaysConsumed = false;
 | 
			
		||||
 | 
			
		||||
    Time creationTime;
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override;
 | 
			
		||||
    void refreshPath();
 | 
			
		||||
    void timerCallback() override;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CallOutBox)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - 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 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A box with a small arrow that can be used as a temporary pop-up window to show
 | 
			
		||||
    extra controls when a button or other component is clicked.
 | 
			
		||||
 | 
			
		||||
    Using one of these is similar to having a popup menu attached to a button or
 | 
			
		||||
    other component - but it looks fancier, and has an arrow that can indicate the
 | 
			
		||||
    object that it applies to.
 | 
			
		||||
 | 
			
		||||
    The class works best when shown modally, but obviously running modal loops is
 | 
			
		||||
    evil and must never be done, so the launchAsynchronously method is provided as
 | 
			
		||||
    a handy way of launching an instance of a CallOutBox and automatically managing
 | 
			
		||||
    its lifetime, e.g.
 | 
			
		||||
 | 
			
		||||
    @code
 | 
			
		||||
    void mouseUp (const MouseEvent&)
 | 
			
		||||
    {
 | 
			
		||||
        auto content = std::make_unique<FoobarContentComp>();
 | 
			
		||||
        content->setSize (300, 300);
 | 
			
		||||
 | 
			
		||||
        auto& myBox = CallOutBox::launchAsynchronously (std::move (content),
 | 
			
		||||
                                                        getScreenBounds(),
 | 
			
		||||
                                                        nullptr);
 | 
			
		||||
    }
 | 
			
		||||
    @endcode
 | 
			
		||||
 | 
			
		||||
    The call-out will resize and position itself when the content changes size.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  CallOutBox    : public Component,
 | 
			
		||||
                                private Timer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a CallOutBox.
 | 
			
		||||
 | 
			
		||||
        @param contentComponent     the component to display inside the call-out. This should
 | 
			
		||||
                                    already have a size set (although the call-out will also
 | 
			
		||||
                                    update itself when the component's size is changed later).
 | 
			
		||||
                                    Obviously this component must not be deleted until the
 | 
			
		||||
                                    call-out box has been deleted.
 | 
			
		||||
        @param areaToPointTo        the area that the call-out's arrow should point towards. If
 | 
			
		||||
                                    a parentComponent is supplied, then this is relative to that
 | 
			
		||||
                                    parent; otherwise, it's a global screen coord.
 | 
			
		||||
        @param parentComponent      if not a nullptr, this is the component to add the call-out to.
 | 
			
		||||
                                    If this is a nullptr, the call-out will be added to the desktop.
 | 
			
		||||
    */
 | 
			
		||||
    CallOutBox (Component& contentComponent,
 | 
			
		||||
                Rectangle<int> areaToPointTo,
 | 
			
		||||
                Component* parentComponent);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Changes the base width of the arrow. */
 | 
			
		||||
    void setArrowSize (float newSize);
 | 
			
		||||
 | 
			
		||||
    /** Updates the position and size of the box.
 | 
			
		||||
 | 
			
		||||
        You shouldn't normally need to call this, unless you need more precise control over the
 | 
			
		||||
        layout.
 | 
			
		||||
 | 
			
		||||
        @param newAreaToPointTo     the rectangle to make the box's arrow point to
 | 
			
		||||
        @param newAreaToFitIn       the area within which the box's position should be constrained
 | 
			
		||||
    */
 | 
			
		||||
    void updatePosition (const Rectangle<int>& newAreaToPointTo,
 | 
			
		||||
                         const Rectangle<int>& newAreaToFitIn);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** This will launch a callout box containing the given content, pointing to the
 | 
			
		||||
        specified target component.
 | 
			
		||||
 | 
			
		||||
        This method will create and display a callout, returning immediately, after which
 | 
			
		||||
        the box will continue to run modally until the user clicks on some other component, at
 | 
			
		||||
        which point it will be dismissed and deleted automatically.
 | 
			
		||||
 | 
			
		||||
        It returns a reference to the newly-created box so that you can customise it, but don't
 | 
			
		||||
        keep a pointer to it, as it'll be deleted at some point when it gets closed.
 | 
			
		||||
 | 
			
		||||
        @param contentComponent     the component to display inside the call-out. This should
 | 
			
		||||
                                    already have a size set (although the call-out will also
 | 
			
		||||
                                    update itself when the component's size is changed later).
 | 
			
		||||
        @param areaToPointTo        the area that the call-out's arrow should point towards. If
 | 
			
		||||
                                    a parentComponent is supplied, then this is relative to that
 | 
			
		||||
                                    parent; otherwise, it's a global screen coord.
 | 
			
		||||
        @param parentComponent      if not a nullptr, this is the component to add the call-out to.
 | 
			
		||||
                                    If this is a nullptr, the call-out will be added to the desktop.
 | 
			
		||||
    */
 | 
			
		||||
    static CallOutBox& launchAsynchronously (std::unique_ptr<Component> contentComponent,
 | 
			
		||||
                                             Rectangle<int> areaToPointTo,
 | 
			
		||||
                                             Component* parentComponent);
 | 
			
		||||
 | 
			
		||||
    /** Posts a message which will dismiss the callout box asynchronously.
 | 
			
		||||
        NB: it's safe to call this method from any thread.
 | 
			
		||||
    */
 | 
			
		||||
    void dismiss();
 | 
			
		||||
 | 
			
		||||
    /** Determines whether the mouse events for clicks outside the calloutbox are
 | 
			
		||||
        consumed, or allowed to arrive at the other component that they were aimed at.
 | 
			
		||||
 | 
			
		||||
        By default this is false, so that when you click on something outside the calloutbox,
 | 
			
		||||
        that event will also be sent to the component that was clicked on. If you set it to
 | 
			
		||||
        true, then the first click will always just dismiss the box and not be sent to
 | 
			
		||||
        anything else.
 | 
			
		||||
    */
 | 
			
		||||
    void setDismissalMouseClicksAreAlwaysConsumed (bool shouldAlwaysBeConsumed) noexcept;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This abstract base class is implemented by LookAndFeel classes. */
 | 
			
		||||
    struct JUCE_API  LookAndFeelMethods
 | 
			
		||||
    {
 | 
			
		||||
        virtual ~LookAndFeelMethods() = default;
 | 
			
		||||
 | 
			
		||||
        virtual void drawCallOutBoxBackground (CallOutBox&, Graphics&, const Path&, Image&) = 0;
 | 
			
		||||
        virtual int getCallOutBoxBorderSize (const CallOutBox&) = 0;
 | 
			
		||||
        virtual float getCallOutBoxCornerSize (const CallOutBox&) = 0;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void resized() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void moved() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void childBoundsChanged (Component*) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    bool hitTest (int x, int y) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void inputAttemptWhenModal() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    bool keyPressed (const KeyPress&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void handleCommandMessage (int) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    int getBorderSize() const noexcept;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void lookAndFeelChanged() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    Component& content;
 | 
			
		||||
    Path outline;
 | 
			
		||||
    Point<float> targetPoint;
 | 
			
		||||
    Rectangle<int> availableArea, targetArea;
 | 
			
		||||
    Image background;
 | 
			
		||||
    float arrowSize = 16.0f;
 | 
			
		||||
    bool dismissalMouseClicksAreAlwaysConsumed = false;
 | 
			
		||||
 | 
			
		||||
    Time creationTime;
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override;
 | 
			
		||||
    void refreshPath();
 | 
			
		||||
    void timerCallback() override;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CallOutBox)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,181 +1,181 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
DialogWindow::DialogWindow (const String& name, Colour colour,
 | 
			
		||||
                            const bool escapeCloses, const bool onDesktop,
 | 
			
		||||
                            const float scale)
 | 
			
		||||
    : DocumentWindow (name, colour, DocumentWindow::closeButton, onDesktop),
 | 
			
		||||
      desktopScale (scale),
 | 
			
		||||
      escapeKeyTriggersCloseButton (escapeCloses)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DialogWindow::~DialogWindow() = default;
 | 
			
		||||
 | 
			
		||||
bool DialogWindow::escapeKeyPressed()
 | 
			
		||||
{
 | 
			
		||||
    if (escapeKeyTriggersCloseButton)
 | 
			
		||||
    {
 | 
			
		||||
        setVisible (false);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool DialogWindow::keyPressed (const KeyPress& key)
 | 
			
		||||
{
 | 
			
		||||
    if (key == KeyPress::escapeKey && escapeKeyPressed())
 | 
			
		||||
        return true;
 | 
			
		||||
 | 
			
		||||
    return DocumentWindow::keyPressed (key);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DialogWindow::resized()
 | 
			
		||||
{
 | 
			
		||||
    DocumentWindow::resized();
 | 
			
		||||
 | 
			
		||||
    if (escapeKeyTriggersCloseButton)
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* close = getCloseButton())
 | 
			
		||||
        {
 | 
			
		||||
            const KeyPress esc (KeyPress::escapeKey, 0, 0);
 | 
			
		||||
 | 
			
		||||
            if (! close->isRegisteredForShortcut (esc))
 | 
			
		||||
                close->addShortcut (esc);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class DefaultDialogWindow   : public DialogWindow
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    DefaultDialogWindow (LaunchOptions& options)
 | 
			
		||||
        : DialogWindow (options.dialogTitle, options.dialogBackgroundColour,
 | 
			
		||||
                        options.escapeKeyTriggersCloseButton, true,
 | 
			
		||||
                        options.componentToCentreAround != nullptr
 | 
			
		||||
                            ? Component::getApproximateScaleFactorForComponent (options.componentToCentreAround)
 | 
			
		||||
                            : 1.0f)
 | 
			
		||||
    {
 | 
			
		||||
        setUsingNativeTitleBar (options.useNativeTitleBar);
 | 
			
		||||
        setAlwaysOnTop (juce_areThereAnyAlwaysOnTopWindows());
 | 
			
		||||
 | 
			
		||||
        if (options.content.willDeleteObject())
 | 
			
		||||
            setContentOwned (options.content.release(), true);
 | 
			
		||||
        else
 | 
			
		||||
            setContentNonOwned (options.content.release(), true);
 | 
			
		||||
 | 
			
		||||
        centreAroundComponent (options.componentToCentreAround, getWidth(), getHeight());
 | 
			
		||||
        setResizable (options.resizable, options.useBottomRightCornerResizer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void closeButtonPressed() override
 | 
			
		||||
    {
 | 
			
		||||
        setVisible (false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE (DefaultDialogWindow)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
DialogWindow::LaunchOptions::LaunchOptions() noexcept {}
 | 
			
		||||
 | 
			
		||||
DialogWindow* DialogWindow::LaunchOptions::create()
 | 
			
		||||
{
 | 
			
		||||
    jassert (content != nullptr); // You need to provide some kind of content for the dialog!
 | 
			
		||||
 | 
			
		||||
    return new DefaultDialogWindow (*this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DialogWindow* DialogWindow::LaunchOptions::launchAsync()
 | 
			
		||||
{
 | 
			
		||||
    auto* d = create();
 | 
			
		||||
    d->enterModalState (true, nullptr, true);
 | 
			
		||||
    return d;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
int DialogWindow::LaunchOptions::runModal()
 | 
			
		||||
{
 | 
			
		||||
    return launchAsync()->runModalLoop();
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void DialogWindow::showDialog (const String& dialogTitle,
 | 
			
		||||
                               Component* const contentComponent,
 | 
			
		||||
                               Component* const componentToCentreAround,
 | 
			
		||||
                               Colour backgroundColour,
 | 
			
		||||
                               const bool escapeKeyTriggersCloseButton,
 | 
			
		||||
                               const bool resizable,
 | 
			
		||||
                               const bool useBottomRightCornerResizer)
 | 
			
		||||
{
 | 
			
		||||
    LaunchOptions o;
 | 
			
		||||
    o.dialogTitle = dialogTitle;
 | 
			
		||||
    o.content.setNonOwned (contentComponent);
 | 
			
		||||
    o.componentToCentreAround = componentToCentreAround;
 | 
			
		||||
    o.dialogBackgroundColour = backgroundColour;
 | 
			
		||||
    o.escapeKeyTriggersCloseButton = escapeKeyTriggersCloseButton;
 | 
			
		||||
    o.useNativeTitleBar = false;
 | 
			
		||||
    o.resizable = resizable;
 | 
			
		||||
    o.useBottomRightCornerResizer = useBottomRightCornerResizer;
 | 
			
		||||
 | 
			
		||||
    o.launchAsync();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
int DialogWindow::showModalDialog (const String& dialogTitle,
 | 
			
		||||
                                   Component* const contentComponent,
 | 
			
		||||
                                   Component* const componentToCentreAround,
 | 
			
		||||
                                   Colour backgroundColour,
 | 
			
		||||
                                   const bool escapeKeyTriggersCloseButton,
 | 
			
		||||
                                   const bool resizable,
 | 
			
		||||
                                   const bool useBottomRightCornerResizer)
 | 
			
		||||
{
 | 
			
		||||
    LaunchOptions o;
 | 
			
		||||
    o.dialogTitle = dialogTitle;
 | 
			
		||||
    o.content.setNonOwned (contentComponent);
 | 
			
		||||
    o.componentToCentreAround = componentToCentreAround;
 | 
			
		||||
    o.dialogBackgroundColour = backgroundColour;
 | 
			
		||||
    o.escapeKeyTriggersCloseButton = escapeKeyTriggersCloseButton;
 | 
			
		||||
    o.useNativeTitleBar = false;
 | 
			
		||||
    o.resizable = resizable;
 | 
			
		||||
    o.useBottomRightCornerResizer = useBottomRightCornerResizer;
 | 
			
		||||
 | 
			
		||||
    return o.runModal();
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
std::unique_ptr<AccessibilityHandler> DialogWindow::createAccessibilityHandler()
 | 
			
		||||
{
 | 
			
		||||
    return std::make_unique<AccessibilityHandler> (*this, AccessibilityRole::dialogWindow);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - 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 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
DialogWindow::DialogWindow (const String& name, Colour colour,
 | 
			
		||||
                            const bool escapeCloses, const bool onDesktop,
 | 
			
		||||
                            const float scale)
 | 
			
		||||
    : DocumentWindow (name, colour, DocumentWindow::closeButton, onDesktop),
 | 
			
		||||
      desktopScale (scale),
 | 
			
		||||
      escapeKeyTriggersCloseButton (escapeCloses)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DialogWindow::~DialogWindow() = default;
 | 
			
		||||
 | 
			
		||||
bool DialogWindow::escapeKeyPressed()
 | 
			
		||||
{
 | 
			
		||||
    if (escapeKeyTriggersCloseButton)
 | 
			
		||||
    {
 | 
			
		||||
        setVisible (false);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool DialogWindow::keyPressed (const KeyPress& key)
 | 
			
		||||
{
 | 
			
		||||
    if (key == KeyPress::escapeKey && escapeKeyPressed())
 | 
			
		||||
        return true;
 | 
			
		||||
 | 
			
		||||
    return DocumentWindow::keyPressed (key);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DialogWindow::resized()
 | 
			
		||||
{
 | 
			
		||||
    DocumentWindow::resized();
 | 
			
		||||
 | 
			
		||||
    if (escapeKeyTriggersCloseButton)
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* close = getCloseButton())
 | 
			
		||||
        {
 | 
			
		||||
            const KeyPress esc (KeyPress::escapeKey, 0, 0);
 | 
			
		||||
 | 
			
		||||
            if (! close->isRegisteredForShortcut (esc))
 | 
			
		||||
                close->addShortcut (esc);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class DefaultDialogWindow   : public DialogWindow
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    DefaultDialogWindow (LaunchOptions& options)
 | 
			
		||||
        : DialogWindow (options.dialogTitle, options.dialogBackgroundColour,
 | 
			
		||||
                        options.escapeKeyTriggersCloseButton, true,
 | 
			
		||||
                        options.componentToCentreAround != nullptr
 | 
			
		||||
                            ? Component::getApproximateScaleFactorForComponent (options.componentToCentreAround)
 | 
			
		||||
                            : 1.0f)
 | 
			
		||||
    {
 | 
			
		||||
        if (options.content.willDeleteObject())
 | 
			
		||||
            setContentOwned (options.content.release(), true);
 | 
			
		||||
        else
 | 
			
		||||
            setContentNonOwned (options.content.release(), true);
 | 
			
		||||
 | 
			
		||||
        centreAroundComponent (options.componentToCentreAround, getWidth(), getHeight());
 | 
			
		||||
        setResizable (options.resizable, options.useBottomRightCornerResizer);
 | 
			
		||||
 | 
			
		||||
        setUsingNativeTitleBar (options.useNativeTitleBar);
 | 
			
		||||
        setAlwaysOnTop (juce_areThereAnyAlwaysOnTopWindows());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void closeButtonPressed() override
 | 
			
		||||
    {
 | 
			
		||||
        setVisible (false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE (DefaultDialogWindow)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
DialogWindow::LaunchOptions::LaunchOptions() noexcept {}
 | 
			
		||||
 | 
			
		||||
DialogWindow* DialogWindow::LaunchOptions::create()
 | 
			
		||||
{
 | 
			
		||||
    jassert (content != nullptr); // You need to provide some kind of content for the dialog!
 | 
			
		||||
 | 
			
		||||
    return new DefaultDialogWindow (*this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DialogWindow* DialogWindow::LaunchOptions::launchAsync()
 | 
			
		||||
{
 | 
			
		||||
    auto* d = create();
 | 
			
		||||
    d->enterModalState (true, nullptr, true);
 | 
			
		||||
    return d;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
int DialogWindow::LaunchOptions::runModal()
 | 
			
		||||
{
 | 
			
		||||
    return launchAsync()->runModalLoop();
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void DialogWindow::showDialog (const String& dialogTitle,
 | 
			
		||||
                               Component* const contentComponent,
 | 
			
		||||
                               Component* const componentToCentreAround,
 | 
			
		||||
                               Colour backgroundColour,
 | 
			
		||||
                               const bool escapeKeyTriggersCloseButton,
 | 
			
		||||
                               const bool resizable,
 | 
			
		||||
                               const bool useBottomRightCornerResizer)
 | 
			
		||||
{
 | 
			
		||||
    LaunchOptions o;
 | 
			
		||||
    o.dialogTitle = dialogTitle;
 | 
			
		||||
    o.content.setNonOwned (contentComponent);
 | 
			
		||||
    o.componentToCentreAround = componentToCentreAround;
 | 
			
		||||
    o.dialogBackgroundColour = backgroundColour;
 | 
			
		||||
    o.escapeKeyTriggersCloseButton = escapeKeyTriggersCloseButton;
 | 
			
		||||
    o.useNativeTitleBar = false;
 | 
			
		||||
    o.resizable = resizable;
 | 
			
		||||
    o.useBottomRightCornerResizer = useBottomRightCornerResizer;
 | 
			
		||||
 | 
			
		||||
    o.launchAsync();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
int DialogWindow::showModalDialog (const String& dialogTitle,
 | 
			
		||||
                                   Component* const contentComponent,
 | 
			
		||||
                                   Component* const componentToCentreAround,
 | 
			
		||||
                                   Colour backgroundColour,
 | 
			
		||||
                                   const bool escapeKeyTriggersCloseButton,
 | 
			
		||||
                                   const bool resizable,
 | 
			
		||||
                                   const bool useBottomRightCornerResizer)
 | 
			
		||||
{
 | 
			
		||||
    LaunchOptions o;
 | 
			
		||||
    o.dialogTitle = dialogTitle;
 | 
			
		||||
    o.content.setNonOwned (contentComponent);
 | 
			
		||||
    o.componentToCentreAround = componentToCentreAround;
 | 
			
		||||
    o.dialogBackgroundColour = backgroundColour;
 | 
			
		||||
    o.escapeKeyTriggersCloseButton = escapeKeyTriggersCloseButton;
 | 
			
		||||
    o.useNativeTitleBar = false;
 | 
			
		||||
    o.resizable = resizable;
 | 
			
		||||
    o.useBottomRightCornerResizer = useBottomRightCornerResizer;
 | 
			
		||||
 | 
			
		||||
    return o.runModal();
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
std::unique_ptr<AccessibilityHandler> DialogWindow::createAccessibilityHandler()
 | 
			
		||||
{
 | 
			
		||||
    return std::make_unique<AccessibilityHandler> (*this, AccessibilityRole::dialogWindow);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,276 +1,276 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A dialog-box style window.
 | 
			
		||||
 | 
			
		||||
    This class is a convenient way of creating a DocumentWindow with a close button
 | 
			
		||||
    that can be triggered by pressing the escape key.
 | 
			
		||||
 | 
			
		||||
    Any of the methods available to a DocumentWindow or ResizableWindow are also
 | 
			
		||||
    available to this, so it can be made resizable, have a menu bar, etc.
 | 
			
		||||
 | 
			
		||||
    You can either override or use an instance of the DialogWindow class directly,
 | 
			
		||||
    or you can use a DialogWindow::LaunchOptions structure to quickly set up and
 | 
			
		||||
    launch a box containing a content component.
 | 
			
		||||
 | 
			
		||||
    If you use the class directly, you'll need to override the
 | 
			
		||||
    DocumentWindow::closeButtonPressed() method to handle the user clicking the close
 | 
			
		||||
    button - for more info, see the DocumentWindow help.
 | 
			
		||||
 | 
			
		||||
    @see DocumentWindow, ResizableWindow
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  DialogWindow   : public DocumentWindow
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a DialogWindow.
 | 
			
		||||
 | 
			
		||||
        @param name                 the name to give the component - this is also
 | 
			
		||||
                                    the title shown at the top of the window. To change
 | 
			
		||||
                                    this later, use setName()
 | 
			
		||||
        @param backgroundColour     the colour to use for filling the window's background.
 | 
			
		||||
        @param escapeKeyTriggersCloseButton if true, then pressing the escape key will cause the
 | 
			
		||||
                                            close button to be triggered
 | 
			
		||||
        @param addToDesktop         if true, the window will be automatically added to the
 | 
			
		||||
                                    desktop; if false, you can use it as a child component
 | 
			
		||||
        @param desktopScale         specifies the scale to use when drawing the window. In a plugin,
 | 
			
		||||
                                    the host controls the scale used to render the plugin editor.
 | 
			
		||||
                                    You should query the editor scale with
 | 
			
		||||
                                    Component::getApproximateScaleFactorForComponent() and pass the
 | 
			
		||||
                                    result here. You can ignore this parameter in a standalone app
 | 
			
		||||
    */
 | 
			
		||||
    DialogWindow (const String& name,
 | 
			
		||||
                  Colour backgroundColour,
 | 
			
		||||
                  bool escapeKeyTriggersCloseButton,
 | 
			
		||||
                  bool addToDesktop = true,
 | 
			
		||||
                  float desktopScale = 1.0f);
 | 
			
		||||
 | 
			
		||||
    /** Destructor.
 | 
			
		||||
        If a content component has been set with setContentOwned(), it will be deleted.
 | 
			
		||||
    */
 | 
			
		||||
    ~DialogWindow() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This class defines a collection of settings to be used to open a DialogWindow.
 | 
			
		||||
 | 
			
		||||
        The easiest way to open a DialogWindow is to create yourself a LaunchOptions structure,
 | 
			
		||||
        initialise its fields with the appropriate details, and then call its launchAsync()
 | 
			
		||||
        method to launch the dialog.
 | 
			
		||||
    */
 | 
			
		||||
    struct JUCE_API  LaunchOptions
 | 
			
		||||
    {
 | 
			
		||||
        LaunchOptions() noexcept;
 | 
			
		||||
 | 
			
		||||
        /** The title to give the window. */
 | 
			
		||||
        String dialogTitle;
 | 
			
		||||
 | 
			
		||||
        /** The background colour for the window. */
 | 
			
		||||
        Colour dialogBackgroundColour = Colours::lightgrey;
 | 
			
		||||
 | 
			
		||||
        /** The content component to show in the window. This must not be null!
 | 
			
		||||
            Using an OptionalScopedPointer to hold this pointer lets you indicate whether
 | 
			
		||||
            you'd like the dialog to automatically delete the component when the dialog
 | 
			
		||||
            has terminated.
 | 
			
		||||
        */
 | 
			
		||||
        OptionalScopedPointer<Component> content;
 | 
			
		||||
 | 
			
		||||
        /** If this is not a nullptr, it indicates a component that you'd like to position this
 | 
			
		||||
            dialog box in front of. See the DocumentWindow::centreAroundComponent() method for
 | 
			
		||||
            more info about this parameter.
 | 
			
		||||
        */
 | 
			
		||||
        Component* componentToCentreAround = nullptr;
 | 
			
		||||
 | 
			
		||||
        /** If true, then the escape key will trigger the dialog's close button. */
 | 
			
		||||
        bool escapeKeyTriggersCloseButton = true;
 | 
			
		||||
        /** If true, the dialog will use a native title bar. See TopLevelWindow::setUsingNativeTitleBar() */
 | 
			
		||||
        bool useNativeTitleBar = true;
 | 
			
		||||
        /** If true, the window will be resizable. See ResizableWindow::setResizable() */
 | 
			
		||||
        bool resizable = true;
 | 
			
		||||
        /** Indicates whether to use a border or corner resizer component. See ResizableWindow::setResizable() */
 | 
			
		||||
        bool useBottomRightCornerResizer = false;
 | 
			
		||||
 | 
			
		||||
        /** Launches a new modal dialog window.
 | 
			
		||||
            This will create a dialog based on the settings in this structure,
 | 
			
		||||
            launch it modally, and return immediately. The window that is returned
 | 
			
		||||
            will be automatically deleted when the modal state is terminated.
 | 
			
		||||
 | 
			
		||||
            When the dialog's close button is clicked, it'll automatically terminate its
 | 
			
		||||
            modal state, but you can also do this programmatically by calling
 | 
			
		||||
            exitModalState (returnValue) on the DialogWindow.
 | 
			
		||||
 | 
			
		||||
            If your content component needs to find the dialog window that it is
 | 
			
		||||
            contained in, a quick trick is to do this:
 | 
			
		||||
            @code
 | 
			
		||||
            if (DialogWindow* dw = contentComponent->findParentComponentOfClass<DialogWindow>())
 | 
			
		||||
                dw->exitModalState (1234);
 | 
			
		||||
            @endcode
 | 
			
		||||
        */
 | 
			
		||||
        DialogWindow* launchAsync();
 | 
			
		||||
 | 
			
		||||
        /** Creates a new DialogWindow instance with these settings.
 | 
			
		||||
            This method simply creates the window, it doesn't run it modally. In most cases
 | 
			
		||||
            you'll want to use launchAsync() or runModal() instead.
 | 
			
		||||
        */
 | 
			
		||||
        DialogWindow* create();
 | 
			
		||||
 | 
			
		||||
       #if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
        /** Launches and runs the dialog modally, returning the status code that was
 | 
			
		||||
            used to terminate the modal loop.
 | 
			
		||||
 | 
			
		||||
            Note that running modal loops inline is a BAD technique. If possible, always
 | 
			
		||||
            use launchAsync() instead of this method.
 | 
			
		||||
        */
 | 
			
		||||
        int runModal();
 | 
			
		||||
       #endif
 | 
			
		||||
 | 
			
		||||
        JUCE_DECLARE_NON_COPYABLE (LaunchOptions)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Easy way of quickly showing a dialog box containing a given component.
 | 
			
		||||
 | 
			
		||||
        Note: This method has been superseded by the DialogWindow::LaunchOptions structure,
 | 
			
		||||
        which does the same job with some extra flexibility. The showDialog method is here
 | 
			
		||||
        for backwards compatibility, but please use DialogWindow::LaunchOptions in new code.
 | 
			
		||||
 | 
			
		||||
        This will open and display a DialogWindow containing a given component, making it
 | 
			
		||||
        modal, but returning immediately to allow the dialog to finish in its own time. If
 | 
			
		||||
        you want to block and run a modal loop until the dialog is dismissed, use showModalDialog()
 | 
			
		||||
        instead.
 | 
			
		||||
 | 
			
		||||
        To close the dialog programmatically, you should call exitModalState (returnValue) on
 | 
			
		||||
        the DialogWindow that is created. To find a pointer to this window from your
 | 
			
		||||
        contentComponent, you can do something like this:
 | 
			
		||||
        @code
 | 
			
		||||
        if (DialogWindow* dw = contentComponent->findParentComponentOfClass<DialogWindow>())
 | 
			
		||||
            dw->exitModalState (1234);
 | 
			
		||||
        @endcode
 | 
			
		||||
 | 
			
		||||
        @param dialogTitle          the dialog box's title
 | 
			
		||||
        @param contentComponent     the content component for the dialog box. Make sure
 | 
			
		||||
                                    that this has been set to the size you want it to
 | 
			
		||||
                                    be before calling this method. The component won't
 | 
			
		||||
                                    be deleted by this call, so you can re-use it or delete
 | 
			
		||||
                                    it afterwards
 | 
			
		||||
        @param componentToCentreAround  if this is not a nullptr, it indicates a component that
 | 
			
		||||
                                    you'd like to show this dialog box in front of. See the
 | 
			
		||||
                                    DocumentWindow::centreAroundComponent() method for more
 | 
			
		||||
                                    info on this parameter
 | 
			
		||||
        @param backgroundColour     a colour to use for the dialog box's background colour
 | 
			
		||||
        @param escapeKeyTriggersCloseButton if true, then pressing the escape key will cause the
 | 
			
		||||
                                            close button to be triggered
 | 
			
		||||
        @param shouldBeResizable    if true, the dialog window has either a resizable border, or
 | 
			
		||||
                                    a corner resizer
 | 
			
		||||
        @param useBottomRightCornerResizer     if shouldBeResizable is true, this indicates whether
 | 
			
		||||
                                    to use a border or corner resizer component. See ResizableWindow::setResizable()
 | 
			
		||||
    */
 | 
			
		||||
    static void showDialog (const String& dialogTitle,
 | 
			
		||||
                            Component* contentComponent,
 | 
			
		||||
                            Component* componentToCentreAround,
 | 
			
		||||
                            Colour backgroundColour,
 | 
			
		||||
                            bool escapeKeyTriggersCloseButton,
 | 
			
		||||
                            bool shouldBeResizable = false,
 | 
			
		||||
                            bool useBottomRightCornerResizer = false);
 | 
			
		||||
 | 
			
		||||
   #if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
    /** Easy way of quickly showing a dialog box containing a given component.
 | 
			
		||||
 | 
			
		||||
        Note: This method has been superseded by the DialogWindow::LaunchOptions structure,
 | 
			
		||||
        which does the same job with some extra flexibility. The showDialog method is here
 | 
			
		||||
        for backwards compatibility, but please use DialogWindow::LaunchOptions in new code.
 | 
			
		||||
 | 
			
		||||
        This will open and display a DialogWindow containing a given component, returning
 | 
			
		||||
        when the user clicks its close button.
 | 
			
		||||
 | 
			
		||||
        It returns the value that was returned by the dialog box's runModalLoop() call.
 | 
			
		||||
 | 
			
		||||
        To close the dialog programmatically, you should call exitModalState (returnValue) on
 | 
			
		||||
        the DialogWindow that is created. To find a pointer to this window from your
 | 
			
		||||
        contentComponent, you can do something like this:
 | 
			
		||||
        @code
 | 
			
		||||
        if (DialogWindow* dw = contentComponent->findParentComponentOfClass<DialogWindow>())
 | 
			
		||||
            dw->exitModalState (1234);
 | 
			
		||||
        @endcode
 | 
			
		||||
 | 
			
		||||
        @param dialogTitle          the dialog box's title
 | 
			
		||||
        @param contentComponent     the content component for the dialog box. Make sure
 | 
			
		||||
                                    that this has been set to the size you want it to
 | 
			
		||||
                                    be before calling this method. The component won't
 | 
			
		||||
                                    be deleted by this call, so you can re-use it or delete
 | 
			
		||||
                                    it afterwards
 | 
			
		||||
        @param componentToCentreAround  if this is not a nullptr, it indicates a component that
 | 
			
		||||
                                    you'd like to show this dialog box in front of. See the
 | 
			
		||||
                                    DocumentWindow::centreAroundComponent() method for more
 | 
			
		||||
                                    info on this parameter
 | 
			
		||||
        @param backgroundColour     a colour to use for the dialog box's background colour
 | 
			
		||||
        @param escapeKeyTriggersCloseButton if true, then pressing the escape key will cause the
 | 
			
		||||
                                            close button to be triggered
 | 
			
		||||
        @param shouldBeResizable    if true, the dialog window has either a resizable border, or
 | 
			
		||||
                                    a corner resizer
 | 
			
		||||
        @param useBottomRightCornerResizer     if shouldBeResizable is true, this indicates whether
 | 
			
		||||
                                    to use a border or corner resizer component. See ResizableWindow::setResizable()
 | 
			
		||||
    */
 | 
			
		||||
    static int showModalDialog (const String& dialogTitle,
 | 
			
		||||
                                Component* contentComponent,
 | 
			
		||||
                                Component* componentToCentreAround,
 | 
			
		||||
                                Colour backgroundColour,
 | 
			
		||||
                                bool escapeKeyTriggersCloseButton,
 | 
			
		||||
                                bool shouldBeResizable = false,
 | 
			
		||||
                                bool useBottomRightCornerResizer = false);
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** Called when the escape key is pressed.
 | 
			
		||||
        This can be overridden to do things other than the default behaviour, which is to hide
 | 
			
		||||
        the window. Return true if the key has been used, or false if it was ignored.
 | 
			
		||||
    */
 | 
			
		||||
    virtual bool escapeKeyPressed();
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void resized() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    bool keyPressed (const KeyPress&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    float getDesktopScaleFactor() const override { return desktopScale * Desktop::getInstance().getGlobalScaleFactor(); }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override;
 | 
			
		||||
 | 
			
		||||
    float desktopScale = 1.0f;
 | 
			
		||||
    bool escapeKeyTriggersCloseButton;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DialogWindow)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - 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 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A dialog-box style window.
 | 
			
		||||
 | 
			
		||||
    This class is a convenient way of creating a DocumentWindow with a close button
 | 
			
		||||
    that can be triggered by pressing the escape key.
 | 
			
		||||
 | 
			
		||||
    Any of the methods available to a DocumentWindow or ResizableWindow are also
 | 
			
		||||
    available to this, so it can be made resizable, have a menu bar, etc.
 | 
			
		||||
 | 
			
		||||
    You can either override or use an instance of the DialogWindow class directly,
 | 
			
		||||
    or you can use a DialogWindow::LaunchOptions structure to quickly set up and
 | 
			
		||||
    launch a box containing a content component.
 | 
			
		||||
 | 
			
		||||
    If you use the class directly, you'll need to override the
 | 
			
		||||
    DocumentWindow::closeButtonPressed() method to handle the user clicking the close
 | 
			
		||||
    button - for more info, see the DocumentWindow help.
 | 
			
		||||
 | 
			
		||||
    @see DocumentWindow, ResizableWindow
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  DialogWindow   : public DocumentWindow
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a DialogWindow.
 | 
			
		||||
 | 
			
		||||
        @param name                 the name to give the component - this is also
 | 
			
		||||
                                    the title shown at the top of the window. To change
 | 
			
		||||
                                    this later, use setName()
 | 
			
		||||
        @param backgroundColour     the colour to use for filling the window's background.
 | 
			
		||||
        @param escapeKeyTriggersCloseButton if true, then pressing the escape key will cause the
 | 
			
		||||
                                            close button to be triggered
 | 
			
		||||
        @param addToDesktop         if true, the window will be automatically added to the
 | 
			
		||||
                                    desktop; if false, you can use it as a child component
 | 
			
		||||
        @param desktopScale         specifies the scale to use when drawing the window. In a plugin,
 | 
			
		||||
                                    the host controls the scale used to render the plugin editor.
 | 
			
		||||
                                    You should query the editor scale with
 | 
			
		||||
                                    Component::getApproximateScaleFactorForComponent() and pass the
 | 
			
		||||
                                    result here. You can ignore this parameter in a standalone app
 | 
			
		||||
    */
 | 
			
		||||
    DialogWindow (const String& name,
 | 
			
		||||
                  Colour backgroundColour,
 | 
			
		||||
                  bool escapeKeyTriggersCloseButton,
 | 
			
		||||
                  bool addToDesktop = true,
 | 
			
		||||
                  float desktopScale = 1.0f);
 | 
			
		||||
 | 
			
		||||
    /** Destructor.
 | 
			
		||||
        If a content component has been set with setContentOwned(), it will be deleted.
 | 
			
		||||
    */
 | 
			
		||||
    ~DialogWindow() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This class defines a collection of settings to be used to open a DialogWindow.
 | 
			
		||||
 | 
			
		||||
        The easiest way to open a DialogWindow is to create yourself a LaunchOptions structure,
 | 
			
		||||
        initialise its fields with the appropriate details, and then call its launchAsync()
 | 
			
		||||
        method to launch the dialog.
 | 
			
		||||
    */
 | 
			
		||||
    struct JUCE_API  LaunchOptions
 | 
			
		||||
    {
 | 
			
		||||
        LaunchOptions() noexcept;
 | 
			
		||||
 | 
			
		||||
        /** The title to give the window. */
 | 
			
		||||
        String dialogTitle;
 | 
			
		||||
 | 
			
		||||
        /** The background colour for the window. */
 | 
			
		||||
        Colour dialogBackgroundColour = Colours::lightgrey;
 | 
			
		||||
 | 
			
		||||
        /** The content component to show in the window. This must not be null!
 | 
			
		||||
            Using an OptionalScopedPointer to hold this pointer lets you indicate whether
 | 
			
		||||
            you'd like the dialog to automatically delete the component when the dialog
 | 
			
		||||
            has terminated.
 | 
			
		||||
        */
 | 
			
		||||
        OptionalScopedPointer<Component> content;
 | 
			
		||||
 | 
			
		||||
        /** If this is not a nullptr, it indicates a component that you'd like to position this
 | 
			
		||||
            dialog box in front of. See the DocumentWindow::centreAroundComponent() method for
 | 
			
		||||
            more info about this parameter.
 | 
			
		||||
        */
 | 
			
		||||
        Component* componentToCentreAround = nullptr;
 | 
			
		||||
 | 
			
		||||
        /** If true, then the escape key will trigger the dialog's close button. */
 | 
			
		||||
        bool escapeKeyTriggersCloseButton = true;
 | 
			
		||||
        /** If true, the dialog will use a native title bar. See TopLevelWindow::setUsingNativeTitleBar() */
 | 
			
		||||
        bool useNativeTitleBar = true;
 | 
			
		||||
        /** If true, the window will be resizable. See ResizableWindow::setResizable() */
 | 
			
		||||
        bool resizable = true;
 | 
			
		||||
        /** Indicates whether to use a border or corner resizer component. See ResizableWindow::setResizable() */
 | 
			
		||||
        bool useBottomRightCornerResizer = false;
 | 
			
		||||
 | 
			
		||||
        /** Launches a new modal dialog window.
 | 
			
		||||
            This will create a dialog based on the settings in this structure,
 | 
			
		||||
            launch it modally, and return immediately. The window that is returned
 | 
			
		||||
            will be automatically deleted when the modal state is terminated.
 | 
			
		||||
 | 
			
		||||
            When the dialog's close button is clicked, it'll automatically terminate its
 | 
			
		||||
            modal state, but you can also do this programmatically by calling
 | 
			
		||||
            exitModalState (returnValue) on the DialogWindow.
 | 
			
		||||
 | 
			
		||||
            If your content component needs to find the dialog window that it is
 | 
			
		||||
            contained in, a quick trick is to do this:
 | 
			
		||||
            @code
 | 
			
		||||
            if (DialogWindow* dw = contentComponent->findParentComponentOfClass<DialogWindow>())
 | 
			
		||||
                dw->exitModalState (1234);
 | 
			
		||||
            @endcode
 | 
			
		||||
        */
 | 
			
		||||
        DialogWindow* launchAsync();
 | 
			
		||||
 | 
			
		||||
        /** Creates a new DialogWindow instance with these settings.
 | 
			
		||||
            This method simply creates the window, it doesn't run it modally. In most cases
 | 
			
		||||
            you'll want to use launchAsync() or runModal() instead.
 | 
			
		||||
        */
 | 
			
		||||
        DialogWindow* create();
 | 
			
		||||
 | 
			
		||||
       #if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
        /** Launches and runs the dialog modally, returning the status code that was
 | 
			
		||||
            used to terminate the modal loop.
 | 
			
		||||
 | 
			
		||||
            Note that running modal loops inline is a BAD technique. If possible, always
 | 
			
		||||
            use launchAsync() instead of this method.
 | 
			
		||||
        */
 | 
			
		||||
        int runModal();
 | 
			
		||||
       #endif
 | 
			
		||||
 | 
			
		||||
        JUCE_DECLARE_NON_COPYABLE (LaunchOptions)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Easy way of quickly showing a dialog box containing a given component.
 | 
			
		||||
 | 
			
		||||
        Note: This method has been superseded by the DialogWindow::LaunchOptions structure,
 | 
			
		||||
        which does the same job with some extra flexibility. The showDialog method is here
 | 
			
		||||
        for backwards compatibility, but please use DialogWindow::LaunchOptions in new code.
 | 
			
		||||
 | 
			
		||||
        This will open and display a DialogWindow containing a given component, making it
 | 
			
		||||
        modal, but returning immediately to allow the dialog to finish in its own time. If
 | 
			
		||||
        you want to block and run a modal loop until the dialog is dismissed, use showModalDialog()
 | 
			
		||||
        instead.
 | 
			
		||||
 | 
			
		||||
        To close the dialog programmatically, you should call exitModalState (returnValue) on
 | 
			
		||||
        the DialogWindow that is created. To find a pointer to this window from your
 | 
			
		||||
        contentComponent, you can do something like this:
 | 
			
		||||
        @code
 | 
			
		||||
        if (DialogWindow* dw = contentComponent->findParentComponentOfClass<DialogWindow>())
 | 
			
		||||
            dw->exitModalState (1234);
 | 
			
		||||
        @endcode
 | 
			
		||||
 | 
			
		||||
        @param dialogTitle          the dialog box's title
 | 
			
		||||
        @param contentComponent     the content component for the dialog box. Make sure
 | 
			
		||||
                                    that this has been set to the size you want it to
 | 
			
		||||
                                    be before calling this method. The component won't
 | 
			
		||||
                                    be deleted by this call, so you can re-use it or delete
 | 
			
		||||
                                    it afterwards
 | 
			
		||||
        @param componentToCentreAround  if this is not a nullptr, it indicates a component that
 | 
			
		||||
                                    you'd like to show this dialog box in front of. See the
 | 
			
		||||
                                    DocumentWindow::centreAroundComponent() method for more
 | 
			
		||||
                                    info on this parameter
 | 
			
		||||
        @param backgroundColour     a colour to use for the dialog box's background colour
 | 
			
		||||
        @param escapeKeyTriggersCloseButton if true, then pressing the escape key will cause the
 | 
			
		||||
                                            close button to be triggered
 | 
			
		||||
        @param shouldBeResizable    if true, the dialog window has either a resizable border, or
 | 
			
		||||
                                    a corner resizer
 | 
			
		||||
        @param useBottomRightCornerResizer     if shouldBeResizable is true, this indicates whether
 | 
			
		||||
                                    to use a border or corner resizer component. See ResizableWindow::setResizable()
 | 
			
		||||
    */
 | 
			
		||||
    static void showDialog (const String& dialogTitle,
 | 
			
		||||
                            Component* contentComponent,
 | 
			
		||||
                            Component* componentToCentreAround,
 | 
			
		||||
                            Colour backgroundColour,
 | 
			
		||||
                            bool escapeKeyTriggersCloseButton,
 | 
			
		||||
                            bool shouldBeResizable = false,
 | 
			
		||||
                            bool useBottomRightCornerResizer = false);
 | 
			
		||||
 | 
			
		||||
   #if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
    /** Easy way of quickly showing a dialog box containing a given component.
 | 
			
		||||
 | 
			
		||||
        Note: This method has been superseded by the DialogWindow::LaunchOptions structure,
 | 
			
		||||
        which does the same job with some extra flexibility. The showDialog method is here
 | 
			
		||||
        for backwards compatibility, but please use DialogWindow::LaunchOptions in new code.
 | 
			
		||||
 | 
			
		||||
        This will open and display a DialogWindow containing a given component, returning
 | 
			
		||||
        when the user clicks its close button.
 | 
			
		||||
 | 
			
		||||
        It returns the value that was returned by the dialog box's runModalLoop() call.
 | 
			
		||||
 | 
			
		||||
        To close the dialog programmatically, you should call exitModalState (returnValue) on
 | 
			
		||||
        the DialogWindow that is created. To find a pointer to this window from your
 | 
			
		||||
        contentComponent, you can do something like this:
 | 
			
		||||
        @code
 | 
			
		||||
        if (DialogWindow* dw = contentComponent->findParentComponentOfClass<DialogWindow>())
 | 
			
		||||
            dw->exitModalState (1234);
 | 
			
		||||
        @endcode
 | 
			
		||||
 | 
			
		||||
        @param dialogTitle          the dialog box's title
 | 
			
		||||
        @param contentComponent     the content component for the dialog box. Make sure
 | 
			
		||||
                                    that this has been set to the size you want it to
 | 
			
		||||
                                    be before calling this method. The component won't
 | 
			
		||||
                                    be deleted by this call, so you can re-use it or delete
 | 
			
		||||
                                    it afterwards
 | 
			
		||||
        @param componentToCentreAround  if this is not a nullptr, it indicates a component that
 | 
			
		||||
                                    you'd like to show this dialog box in front of. See the
 | 
			
		||||
                                    DocumentWindow::centreAroundComponent() method for more
 | 
			
		||||
                                    info on this parameter
 | 
			
		||||
        @param backgroundColour     a colour to use for the dialog box's background colour
 | 
			
		||||
        @param escapeKeyTriggersCloseButton if true, then pressing the escape key will cause the
 | 
			
		||||
                                            close button to be triggered
 | 
			
		||||
        @param shouldBeResizable    if true, the dialog window has either a resizable border, or
 | 
			
		||||
                                    a corner resizer
 | 
			
		||||
        @param useBottomRightCornerResizer     if shouldBeResizable is true, this indicates whether
 | 
			
		||||
                                    to use a border or corner resizer component. See ResizableWindow::setResizable()
 | 
			
		||||
    */
 | 
			
		||||
    static int showModalDialog (const String& dialogTitle,
 | 
			
		||||
                                Component* contentComponent,
 | 
			
		||||
                                Component* componentToCentreAround,
 | 
			
		||||
                                Colour backgroundColour,
 | 
			
		||||
                                bool escapeKeyTriggersCloseButton,
 | 
			
		||||
                                bool shouldBeResizable = false,
 | 
			
		||||
                                bool useBottomRightCornerResizer = false);
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** Called when the escape key is pressed.
 | 
			
		||||
        This can be overridden to do things other than the default behaviour, which is to hide
 | 
			
		||||
        the window. Return true if the key has been used, or false if it was ignored.
 | 
			
		||||
    */
 | 
			
		||||
    virtual bool escapeKeyPressed();
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void resized() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    bool keyPressed (const KeyPress&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    float getDesktopScaleFactor() const override { return desktopScale * Desktop::getInstance().getGlobalScaleFactor(); }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override;
 | 
			
		||||
 | 
			
		||||
    float desktopScale = 1.0f;
 | 
			
		||||
    bool escapeKeyTriggersCloseButton;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DialogWindow)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,360 +1,360 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class DocumentWindow::ButtonListenerProxy  : public Button::Listener
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    ButtonListenerProxy (DocumentWindow& w) : owner (w) {}
 | 
			
		||||
 | 
			
		||||
    void buttonClicked (Button* button) override
 | 
			
		||||
    {
 | 
			
		||||
        if      (button == owner.getMinimiseButton())  owner.minimiseButtonPressed();
 | 
			
		||||
        else if (button == owner.getMaximiseButton())  owner.maximiseButtonPressed();
 | 
			
		||||
        else if (button == owner.getCloseButton())     owner.closeButtonPressed();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    DocumentWindow& owner;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ButtonListenerProxy)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
DocumentWindow::DocumentWindow (const String& title,
 | 
			
		||||
                                Colour backgroundColour,
 | 
			
		||||
                                int requiredButtons_,
 | 
			
		||||
                                bool addToDesktop_)
 | 
			
		||||
    : ResizableWindow (title, backgroundColour, addToDesktop_),
 | 
			
		||||
      requiredButtons (requiredButtons_),
 | 
			
		||||
     #if JUCE_MAC
 | 
			
		||||
      positionTitleBarButtonsOnLeft (true)
 | 
			
		||||
     #else
 | 
			
		||||
      positionTitleBarButtonsOnLeft (false)
 | 
			
		||||
     #endif
 | 
			
		||||
{
 | 
			
		||||
    setResizeLimits (128, 128, 32768, 32768);
 | 
			
		||||
 | 
			
		||||
    DocumentWindow::lookAndFeelChanged();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DocumentWindow::~DocumentWindow()
 | 
			
		||||
{
 | 
			
		||||
    // Don't delete or remove the resizer components yourself! They're managed by the
 | 
			
		||||
    // DocumentWindow, and you should leave them alone! You may have deleted them
 | 
			
		||||
    // accidentally by careless use of deleteAllChildren()..?
 | 
			
		||||
    jassert (menuBar == nullptr || getIndexOfChildComponent (menuBar.get()) >= 0);
 | 
			
		||||
    jassert (titleBarButtons[0] == nullptr || getIndexOfChildComponent (titleBarButtons[0].get()) >= 0);
 | 
			
		||||
    jassert (titleBarButtons[1] == nullptr || getIndexOfChildComponent (titleBarButtons[1].get()) >= 0);
 | 
			
		||||
    jassert (titleBarButtons[2] == nullptr || getIndexOfChildComponent (titleBarButtons[2].get()) >= 0);
 | 
			
		||||
 | 
			
		||||
    for (auto& b : titleBarButtons)
 | 
			
		||||
        b.reset();
 | 
			
		||||
 | 
			
		||||
    menuBar.reset();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void DocumentWindow::repaintTitleBar()
 | 
			
		||||
{
 | 
			
		||||
    repaint (getTitleBarArea());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::setName (const String& newName)
 | 
			
		||||
{
 | 
			
		||||
    if (newName != getName())
 | 
			
		||||
    {
 | 
			
		||||
        Component::setName (newName);
 | 
			
		||||
        repaintTitleBar();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::setIcon (const Image& imageToUse)
 | 
			
		||||
{
 | 
			
		||||
    titleBarIcon = imageToUse;
 | 
			
		||||
    repaintTitleBar();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::setTitleBarHeight (const int newHeight)
 | 
			
		||||
{
 | 
			
		||||
    titleBarHeight = newHeight;
 | 
			
		||||
    resized();
 | 
			
		||||
    repaintTitleBar();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::setTitleBarButtonsRequired (const int buttons, const bool onLeft)
 | 
			
		||||
{
 | 
			
		||||
    requiredButtons = buttons;
 | 
			
		||||
    positionTitleBarButtonsOnLeft = onLeft;
 | 
			
		||||
    lookAndFeelChanged();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::setTitleBarTextCentred (const bool textShouldBeCentred)
 | 
			
		||||
{
 | 
			
		||||
    drawTitleTextCentred = textShouldBeCentred;
 | 
			
		||||
    repaintTitleBar();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void DocumentWindow::setMenuBar (MenuBarModel* newMenuBarModel, const int newMenuBarHeight)
 | 
			
		||||
{
 | 
			
		||||
    if (menuBarModel != newMenuBarModel)
 | 
			
		||||
    {
 | 
			
		||||
        menuBar.reset();
 | 
			
		||||
 | 
			
		||||
        menuBarModel = newMenuBarModel;
 | 
			
		||||
        menuBarHeight = newMenuBarHeight > 0 ? newMenuBarHeight
 | 
			
		||||
                                             : getLookAndFeel().getDefaultMenuBarHeight();
 | 
			
		||||
 | 
			
		||||
        if (menuBarModel != nullptr)
 | 
			
		||||
            setMenuBarComponent (new MenuBarComponent (menuBarModel));
 | 
			
		||||
 | 
			
		||||
        resized();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Component* DocumentWindow::getMenuBarComponent() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return menuBar.get();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::setMenuBarComponent (Component* newMenuBarComponent)
 | 
			
		||||
{
 | 
			
		||||
    menuBar.reset (newMenuBarComponent);
 | 
			
		||||
    Component::addAndMakeVisible (menuBar.get()); // (call the superclass method directly to avoid the assertion in ResizableWindow)
 | 
			
		||||
 | 
			
		||||
    if (menuBar != nullptr)
 | 
			
		||||
        menuBar->setEnabled (isActiveWindow());
 | 
			
		||||
 | 
			
		||||
    resized();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void DocumentWindow::closeButtonPressed()
 | 
			
		||||
{
 | 
			
		||||
    /*  If you've got a close button, you have to override this method to get
 | 
			
		||||
        rid of your window!
 | 
			
		||||
 | 
			
		||||
        If the window is just a pop-up, you should override this method and make
 | 
			
		||||
        it delete the window in whatever way is appropriate for your app. E.g. you
 | 
			
		||||
        might just want to call "delete this".
 | 
			
		||||
 | 
			
		||||
        If your app is centred around this window such that the whole app should quit when
 | 
			
		||||
        the window is closed, then you will probably want to use this method as an opportunity
 | 
			
		||||
        to call JUCEApplicationBase::quit(), and leave the window to be deleted later by your
 | 
			
		||||
        JUCEApplicationBase::shutdown() method. (Doing it this way means that your window will
 | 
			
		||||
        still get cleaned-up if the app is quit by some other means (e.g. a cmd-Q on the mac
 | 
			
		||||
        or closing it via the taskbar icon on Windows).
 | 
			
		||||
    */
 | 
			
		||||
    jassertfalse;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::minimiseButtonPressed()
 | 
			
		||||
{
 | 
			
		||||
    setMinimised (true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::maximiseButtonPressed()
 | 
			
		||||
{
 | 
			
		||||
    setFullScreen (! isFullScreen());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void DocumentWindow::paint (Graphics& g)
 | 
			
		||||
{
 | 
			
		||||
    ResizableWindow::paint (g);
 | 
			
		||||
 | 
			
		||||
    auto titleBarArea = getTitleBarArea();
 | 
			
		||||
    g.reduceClipRegion (titleBarArea);
 | 
			
		||||
    g.setOrigin (titleBarArea.getPosition());
 | 
			
		||||
 | 
			
		||||
    int titleSpaceX1 = 6;
 | 
			
		||||
    int titleSpaceX2 = titleBarArea.getWidth() - 6;
 | 
			
		||||
 | 
			
		||||
    for (auto& b : titleBarButtons)
 | 
			
		||||
    {
 | 
			
		||||
        if (b != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            if (positionTitleBarButtonsOnLeft)
 | 
			
		||||
                titleSpaceX1 = jmax (titleSpaceX1, b->getRight() + (getWidth() - b->getRight()) / 8);
 | 
			
		||||
            else
 | 
			
		||||
                titleSpaceX2 = jmin (titleSpaceX2, b->getX() - (b->getX() / 8));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getLookAndFeel().drawDocumentWindowTitleBar (*this, g,
 | 
			
		||||
                                                 titleBarArea.getWidth(),
 | 
			
		||||
                                                 titleBarArea.getHeight(),
 | 
			
		||||
                                                 titleSpaceX1,
 | 
			
		||||
                                                 jmax (1, titleSpaceX2 - titleSpaceX1),
 | 
			
		||||
                                                 titleBarIcon.isValid() ? &titleBarIcon : nullptr,
 | 
			
		||||
                                                 ! drawTitleTextCentred);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::resized()
 | 
			
		||||
{
 | 
			
		||||
    ResizableWindow::resized();
 | 
			
		||||
 | 
			
		||||
    if (auto* b = getMaximiseButton())
 | 
			
		||||
        b->setToggleState (isFullScreen(), dontSendNotification);
 | 
			
		||||
 | 
			
		||||
    auto titleBarArea = getTitleBarArea();
 | 
			
		||||
 | 
			
		||||
    getLookAndFeel()
 | 
			
		||||
        .positionDocumentWindowButtons (*this,
 | 
			
		||||
                                        titleBarArea.getX(), titleBarArea.getY(),
 | 
			
		||||
                                        titleBarArea.getWidth(), titleBarArea.getHeight(),
 | 
			
		||||
                                        titleBarButtons[0].get(),
 | 
			
		||||
                                        titleBarButtons[1].get(),
 | 
			
		||||
                                        titleBarButtons[2].get(),
 | 
			
		||||
                                        positionTitleBarButtonsOnLeft);
 | 
			
		||||
 | 
			
		||||
    if (menuBar != nullptr)
 | 
			
		||||
        menuBar->setBounds (titleBarArea.getX(), titleBarArea.getBottom(),
 | 
			
		||||
                            titleBarArea.getWidth(), menuBarHeight);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BorderSize<int> DocumentWindow::getBorderThickness()
 | 
			
		||||
{
 | 
			
		||||
    return ResizableWindow::getBorderThickness();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BorderSize<int> DocumentWindow::getContentComponentBorder()
 | 
			
		||||
{
 | 
			
		||||
    auto border = getBorderThickness();
 | 
			
		||||
 | 
			
		||||
    if (! isKioskMode())
 | 
			
		||||
        border.setTop (border.getTop()
 | 
			
		||||
                        + (isUsingNativeTitleBar() ? 0 : titleBarHeight)
 | 
			
		||||
                        + (menuBar != nullptr ? menuBarHeight : 0));
 | 
			
		||||
 | 
			
		||||
    return border;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int DocumentWindow::getTitleBarHeight() const
 | 
			
		||||
{
 | 
			
		||||
    return isUsingNativeTitleBar() ? 0 : jmin (titleBarHeight, getHeight() - 4);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Rectangle<int> DocumentWindow::getTitleBarArea()
 | 
			
		||||
{
 | 
			
		||||
    if (isKioskMode())
 | 
			
		||||
        return {};
 | 
			
		||||
 | 
			
		||||
    auto border = getBorderThickness();
 | 
			
		||||
    return { border.getLeft(), border.getTop(), getWidth() - border.getLeftAndRight(), getTitleBarHeight() };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Button* DocumentWindow::getCloseButton()    const noexcept  { return titleBarButtons[2].get(); }
 | 
			
		||||
Button* DocumentWindow::getMinimiseButton() const noexcept  { return titleBarButtons[0].get(); }
 | 
			
		||||
Button* DocumentWindow::getMaximiseButton() const noexcept  { return titleBarButtons[1].get(); }
 | 
			
		||||
 | 
			
		||||
int DocumentWindow::getDesktopWindowStyleFlags() const
 | 
			
		||||
{
 | 
			
		||||
    auto styleFlags = ResizableWindow::getDesktopWindowStyleFlags();
 | 
			
		||||
 | 
			
		||||
    if ((requiredButtons & minimiseButton) != 0)  styleFlags |= ComponentPeer::windowHasMinimiseButton;
 | 
			
		||||
    if ((requiredButtons & maximiseButton) != 0)  styleFlags |= ComponentPeer::windowHasMaximiseButton;
 | 
			
		||||
    if ((requiredButtons & closeButton)    != 0)  styleFlags |= ComponentPeer::windowHasCloseButton;
 | 
			
		||||
 | 
			
		||||
    return styleFlags;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::lookAndFeelChanged()
 | 
			
		||||
{
 | 
			
		||||
    for (auto& b : titleBarButtons)
 | 
			
		||||
        b.reset();
 | 
			
		||||
 | 
			
		||||
    if (! isUsingNativeTitleBar())
 | 
			
		||||
    {
 | 
			
		||||
        auto& lf = getLookAndFeel();
 | 
			
		||||
 | 
			
		||||
        if ((requiredButtons & minimiseButton) != 0)  titleBarButtons[0].reset (lf.createDocumentWindowButton (minimiseButton));
 | 
			
		||||
        if ((requiredButtons & maximiseButton) != 0)  titleBarButtons[1].reset (lf.createDocumentWindowButton (maximiseButton));
 | 
			
		||||
        if ((requiredButtons & closeButton)    != 0)  titleBarButtons[2].reset (lf.createDocumentWindowButton (closeButton));
 | 
			
		||||
 | 
			
		||||
        for (auto& b : titleBarButtons)
 | 
			
		||||
        {
 | 
			
		||||
            if (b != nullptr)
 | 
			
		||||
            {
 | 
			
		||||
                if (buttonListener == nullptr)
 | 
			
		||||
                    buttonListener.reset (new ButtonListenerProxy (*this));
 | 
			
		||||
 | 
			
		||||
                b->addListener (buttonListener.get());
 | 
			
		||||
                b->setWantsKeyboardFocus (false);
 | 
			
		||||
 | 
			
		||||
                // (call the Component method directly to avoid the assertion in ResizableWindow)
 | 
			
		||||
                Component::addAndMakeVisible (b.get());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (auto* b = getCloseButton())
 | 
			
		||||
        {
 | 
			
		||||
           #if JUCE_MAC
 | 
			
		||||
            b->addShortcut (KeyPress ('w', ModifierKeys::commandModifier, 0));
 | 
			
		||||
           #else
 | 
			
		||||
            b->addShortcut (KeyPress (KeyPress::F4Key, ModifierKeys::altModifier, 0));
 | 
			
		||||
           #endif
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    activeWindowStatusChanged();
 | 
			
		||||
 | 
			
		||||
    ResizableWindow::lookAndFeelChanged();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::parentHierarchyChanged()
 | 
			
		||||
{
 | 
			
		||||
    lookAndFeelChanged();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::activeWindowStatusChanged()
 | 
			
		||||
{
 | 
			
		||||
    ResizableWindow::activeWindowStatusChanged();
 | 
			
		||||
    bool isActive = isActiveWindow();
 | 
			
		||||
 | 
			
		||||
    for (auto& b : titleBarButtons)
 | 
			
		||||
        if (b != nullptr)
 | 
			
		||||
            b->setEnabled (isActive);
 | 
			
		||||
 | 
			
		||||
    if (menuBar != nullptr)
 | 
			
		||||
        menuBar->setEnabled (isActive);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::mouseDoubleClick (const MouseEvent& e)
 | 
			
		||||
{
 | 
			
		||||
    if (getTitleBarArea().contains (e.x, e.y))
 | 
			
		||||
        if (auto* maximise = getMaximiseButton())
 | 
			
		||||
            maximise->triggerClick();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::userTriedToCloseWindow()
 | 
			
		||||
{
 | 
			
		||||
    closeButtonPressed();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - 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 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class DocumentWindow::ButtonListenerProxy  : public Button::Listener
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    ButtonListenerProxy (DocumentWindow& w) : owner (w) {}
 | 
			
		||||
 | 
			
		||||
    void buttonClicked (Button* button) override
 | 
			
		||||
    {
 | 
			
		||||
        if      (button == owner.getMinimiseButton())  owner.minimiseButtonPressed();
 | 
			
		||||
        else if (button == owner.getMaximiseButton())  owner.maximiseButtonPressed();
 | 
			
		||||
        else if (button == owner.getCloseButton())     owner.closeButtonPressed();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    DocumentWindow& owner;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ButtonListenerProxy)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
DocumentWindow::DocumentWindow (const String& title,
 | 
			
		||||
                                Colour backgroundColour,
 | 
			
		||||
                                int requiredButtons_,
 | 
			
		||||
                                bool addToDesktop_)
 | 
			
		||||
    : ResizableWindow (title, backgroundColour, addToDesktop_),
 | 
			
		||||
      requiredButtons (requiredButtons_),
 | 
			
		||||
     #if JUCE_MAC
 | 
			
		||||
      positionTitleBarButtonsOnLeft (true)
 | 
			
		||||
     #else
 | 
			
		||||
      positionTitleBarButtonsOnLeft (false)
 | 
			
		||||
     #endif
 | 
			
		||||
{
 | 
			
		||||
    setResizeLimits (128, 128, 32768, 32768);
 | 
			
		||||
 | 
			
		||||
    DocumentWindow::lookAndFeelChanged();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DocumentWindow::~DocumentWindow()
 | 
			
		||||
{
 | 
			
		||||
    // Don't delete or remove the resizer components yourself! They're managed by the
 | 
			
		||||
    // DocumentWindow, and you should leave them alone! You may have deleted them
 | 
			
		||||
    // accidentally by careless use of deleteAllChildren()..?
 | 
			
		||||
    jassert (menuBar == nullptr || getIndexOfChildComponent (menuBar.get()) >= 0);
 | 
			
		||||
    jassert (titleBarButtons[0] == nullptr || getIndexOfChildComponent (titleBarButtons[0].get()) >= 0);
 | 
			
		||||
    jassert (titleBarButtons[1] == nullptr || getIndexOfChildComponent (titleBarButtons[1].get()) >= 0);
 | 
			
		||||
    jassert (titleBarButtons[2] == nullptr || getIndexOfChildComponent (titleBarButtons[2].get()) >= 0);
 | 
			
		||||
 | 
			
		||||
    for (auto& b : titleBarButtons)
 | 
			
		||||
        b.reset();
 | 
			
		||||
 | 
			
		||||
    menuBar.reset();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void DocumentWindow::repaintTitleBar()
 | 
			
		||||
{
 | 
			
		||||
    repaint (getTitleBarArea());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::setName (const String& newName)
 | 
			
		||||
{
 | 
			
		||||
    if (newName != getName())
 | 
			
		||||
    {
 | 
			
		||||
        Component::setName (newName);
 | 
			
		||||
        repaintTitleBar();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::setIcon (const Image& imageToUse)
 | 
			
		||||
{
 | 
			
		||||
    titleBarIcon = imageToUse;
 | 
			
		||||
    repaintTitleBar();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::setTitleBarHeight (const int newHeight)
 | 
			
		||||
{
 | 
			
		||||
    titleBarHeight = newHeight;
 | 
			
		||||
    resized();
 | 
			
		||||
    repaintTitleBar();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::setTitleBarButtonsRequired (const int buttons, const bool onLeft)
 | 
			
		||||
{
 | 
			
		||||
    requiredButtons = buttons;
 | 
			
		||||
    positionTitleBarButtonsOnLeft = onLeft;
 | 
			
		||||
    lookAndFeelChanged();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::setTitleBarTextCentred (const bool textShouldBeCentred)
 | 
			
		||||
{
 | 
			
		||||
    drawTitleTextCentred = textShouldBeCentred;
 | 
			
		||||
    repaintTitleBar();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void DocumentWindow::setMenuBar (MenuBarModel* newMenuBarModel, const int newMenuBarHeight)
 | 
			
		||||
{
 | 
			
		||||
    if (menuBarModel != newMenuBarModel)
 | 
			
		||||
    {
 | 
			
		||||
        menuBar.reset();
 | 
			
		||||
 | 
			
		||||
        menuBarModel = newMenuBarModel;
 | 
			
		||||
        menuBarHeight = newMenuBarHeight > 0 ? newMenuBarHeight
 | 
			
		||||
                                             : getLookAndFeel().getDefaultMenuBarHeight();
 | 
			
		||||
 | 
			
		||||
        if (menuBarModel != nullptr)
 | 
			
		||||
            setMenuBarComponent (new MenuBarComponent (menuBarModel));
 | 
			
		||||
 | 
			
		||||
        resized();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Component* DocumentWindow::getMenuBarComponent() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return menuBar.get();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::setMenuBarComponent (Component* newMenuBarComponent)
 | 
			
		||||
{
 | 
			
		||||
    menuBar.reset (newMenuBarComponent);
 | 
			
		||||
    Component::addAndMakeVisible (menuBar.get()); // (call the superclass method directly to avoid the assertion in ResizableWindow)
 | 
			
		||||
 | 
			
		||||
    if (menuBar != nullptr)
 | 
			
		||||
        menuBar->setEnabled (isActiveWindow());
 | 
			
		||||
 | 
			
		||||
    resized();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void DocumentWindow::closeButtonPressed()
 | 
			
		||||
{
 | 
			
		||||
    /*  If you've got a close button, you have to override this method to get
 | 
			
		||||
        rid of your window!
 | 
			
		||||
 | 
			
		||||
        If the window is just a pop-up, you should override this method and make
 | 
			
		||||
        it delete the window in whatever way is appropriate for your app. E.g. you
 | 
			
		||||
        might just want to call "delete this".
 | 
			
		||||
 | 
			
		||||
        If your app is centred around this window such that the whole app should quit when
 | 
			
		||||
        the window is closed, then you will probably want to use this method as an opportunity
 | 
			
		||||
        to call JUCEApplicationBase::quit(), and leave the window to be deleted later by your
 | 
			
		||||
        JUCEApplicationBase::shutdown() method. (Doing it this way means that your window will
 | 
			
		||||
        still get cleaned-up if the app is quit by some other means (e.g. a cmd-Q on the mac
 | 
			
		||||
        or closing it via the taskbar icon on Windows).
 | 
			
		||||
    */
 | 
			
		||||
    jassertfalse;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::minimiseButtonPressed()
 | 
			
		||||
{
 | 
			
		||||
    setMinimised (true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::maximiseButtonPressed()
 | 
			
		||||
{
 | 
			
		||||
    setFullScreen (! isFullScreen());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void DocumentWindow::paint (Graphics& g)
 | 
			
		||||
{
 | 
			
		||||
    ResizableWindow::paint (g);
 | 
			
		||||
 | 
			
		||||
    auto titleBarArea = getTitleBarArea();
 | 
			
		||||
    g.reduceClipRegion (titleBarArea);
 | 
			
		||||
    g.setOrigin (titleBarArea.getPosition());
 | 
			
		||||
 | 
			
		||||
    int titleSpaceX1 = 6;
 | 
			
		||||
    int titleSpaceX2 = titleBarArea.getWidth() - 6;
 | 
			
		||||
 | 
			
		||||
    for (auto& b : titleBarButtons)
 | 
			
		||||
    {
 | 
			
		||||
        if (b != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            if (positionTitleBarButtonsOnLeft)
 | 
			
		||||
                titleSpaceX1 = jmax (titleSpaceX1, b->getRight() + (getWidth() - b->getRight()) / 8);
 | 
			
		||||
            else
 | 
			
		||||
                titleSpaceX2 = jmin (titleSpaceX2, b->getX() - (b->getX() / 8));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getLookAndFeel().drawDocumentWindowTitleBar (*this, g,
 | 
			
		||||
                                                 titleBarArea.getWidth(),
 | 
			
		||||
                                                 titleBarArea.getHeight(),
 | 
			
		||||
                                                 titleSpaceX1,
 | 
			
		||||
                                                 jmax (1, titleSpaceX2 - titleSpaceX1),
 | 
			
		||||
                                                 titleBarIcon.isValid() ? &titleBarIcon : nullptr,
 | 
			
		||||
                                                 ! drawTitleTextCentred);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::resized()
 | 
			
		||||
{
 | 
			
		||||
    ResizableWindow::resized();
 | 
			
		||||
 | 
			
		||||
    if (auto* b = getMaximiseButton())
 | 
			
		||||
        b->setToggleState (isFullScreen(), dontSendNotification);
 | 
			
		||||
 | 
			
		||||
    auto titleBarArea = getTitleBarArea();
 | 
			
		||||
 | 
			
		||||
    getLookAndFeel()
 | 
			
		||||
        .positionDocumentWindowButtons (*this,
 | 
			
		||||
                                        titleBarArea.getX(), titleBarArea.getY(),
 | 
			
		||||
                                        titleBarArea.getWidth(), titleBarArea.getHeight(),
 | 
			
		||||
                                        titleBarButtons[0].get(),
 | 
			
		||||
                                        titleBarButtons[1].get(),
 | 
			
		||||
                                        titleBarButtons[2].get(),
 | 
			
		||||
                                        positionTitleBarButtonsOnLeft);
 | 
			
		||||
 | 
			
		||||
    if (menuBar != nullptr)
 | 
			
		||||
        menuBar->setBounds (titleBarArea.getX(), titleBarArea.getBottom(),
 | 
			
		||||
                            titleBarArea.getWidth(), menuBarHeight);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BorderSize<int> DocumentWindow::getBorderThickness()
 | 
			
		||||
{
 | 
			
		||||
    return ResizableWindow::getBorderThickness();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BorderSize<int> DocumentWindow::getContentComponentBorder()
 | 
			
		||||
{
 | 
			
		||||
    auto border = getBorderThickness();
 | 
			
		||||
 | 
			
		||||
    if (! isKioskMode())
 | 
			
		||||
        border.setTop (border.getTop()
 | 
			
		||||
                        + (isUsingNativeTitleBar() ? 0 : titleBarHeight)
 | 
			
		||||
                        + (menuBar != nullptr ? menuBarHeight : 0));
 | 
			
		||||
 | 
			
		||||
    return border;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int DocumentWindow::getTitleBarHeight() const
 | 
			
		||||
{
 | 
			
		||||
    return isUsingNativeTitleBar() ? 0 : jmin (titleBarHeight, getHeight() - 4);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Rectangle<int> DocumentWindow::getTitleBarArea()
 | 
			
		||||
{
 | 
			
		||||
    if (isKioskMode())
 | 
			
		||||
        return {};
 | 
			
		||||
 | 
			
		||||
    auto border = getBorderThickness();
 | 
			
		||||
    return { border.getLeft(), border.getTop(), getWidth() - border.getLeftAndRight(), getTitleBarHeight() };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Button* DocumentWindow::getCloseButton()    const noexcept  { return titleBarButtons[2].get(); }
 | 
			
		||||
Button* DocumentWindow::getMinimiseButton() const noexcept  { return titleBarButtons[0].get(); }
 | 
			
		||||
Button* DocumentWindow::getMaximiseButton() const noexcept  { return titleBarButtons[1].get(); }
 | 
			
		||||
 | 
			
		||||
int DocumentWindow::getDesktopWindowStyleFlags() const
 | 
			
		||||
{
 | 
			
		||||
    auto styleFlags = ResizableWindow::getDesktopWindowStyleFlags();
 | 
			
		||||
 | 
			
		||||
    if ((requiredButtons & minimiseButton) != 0)  styleFlags |= ComponentPeer::windowHasMinimiseButton;
 | 
			
		||||
    if ((requiredButtons & maximiseButton) != 0)  styleFlags |= ComponentPeer::windowHasMaximiseButton;
 | 
			
		||||
    if ((requiredButtons & closeButton)    != 0)  styleFlags |= ComponentPeer::windowHasCloseButton;
 | 
			
		||||
 | 
			
		||||
    return styleFlags;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::lookAndFeelChanged()
 | 
			
		||||
{
 | 
			
		||||
    for (auto& b : titleBarButtons)
 | 
			
		||||
        b.reset();
 | 
			
		||||
 | 
			
		||||
    if (! isUsingNativeTitleBar())
 | 
			
		||||
    {
 | 
			
		||||
        auto& lf = getLookAndFeel();
 | 
			
		||||
 | 
			
		||||
        if ((requiredButtons & minimiseButton) != 0)  titleBarButtons[0].reset (lf.createDocumentWindowButton (minimiseButton));
 | 
			
		||||
        if ((requiredButtons & maximiseButton) != 0)  titleBarButtons[1].reset (lf.createDocumentWindowButton (maximiseButton));
 | 
			
		||||
        if ((requiredButtons & closeButton)    != 0)  titleBarButtons[2].reset (lf.createDocumentWindowButton (closeButton));
 | 
			
		||||
 | 
			
		||||
        for (auto& b : titleBarButtons)
 | 
			
		||||
        {
 | 
			
		||||
            if (b != nullptr)
 | 
			
		||||
            {
 | 
			
		||||
                if (buttonListener == nullptr)
 | 
			
		||||
                    buttonListener.reset (new ButtonListenerProxy (*this));
 | 
			
		||||
 | 
			
		||||
                b->addListener (buttonListener.get());
 | 
			
		||||
                b->setWantsKeyboardFocus (false);
 | 
			
		||||
 | 
			
		||||
                // (call the Component method directly to avoid the assertion in ResizableWindow)
 | 
			
		||||
                Component::addAndMakeVisible (b.get());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (auto* b = getCloseButton())
 | 
			
		||||
        {
 | 
			
		||||
           #if JUCE_MAC
 | 
			
		||||
            b->addShortcut (KeyPress ('w', ModifierKeys::commandModifier, 0));
 | 
			
		||||
           #else
 | 
			
		||||
            b->addShortcut (KeyPress (KeyPress::F4Key, ModifierKeys::altModifier, 0));
 | 
			
		||||
           #endif
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    activeWindowStatusChanged();
 | 
			
		||||
 | 
			
		||||
    ResizableWindow::lookAndFeelChanged();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::parentHierarchyChanged()
 | 
			
		||||
{
 | 
			
		||||
    lookAndFeelChanged();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::activeWindowStatusChanged()
 | 
			
		||||
{
 | 
			
		||||
    ResizableWindow::activeWindowStatusChanged();
 | 
			
		||||
    bool isActive = isActiveWindow();
 | 
			
		||||
 | 
			
		||||
    for (auto& b : titleBarButtons)
 | 
			
		||||
        if (b != nullptr)
 | 
			
		||||
            b->setEnabled (isActive);
 | 
			
		||||
 | 
			
		||||
    if (menuBar != nullptr)
 | 
			
		||||
        menuBar->setEnabled (isActive);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::mouseDoubleClick (const MouseEvent& e)
 | 
			
		||||
{
 | 
			
		||||
    if (getTitleBarArea().contains (e.x, e.y))
 | 
			
		||||
        if (auto* maximise = getMaximiseButton())
 | 
			
		||||
            maximise->triggerClick();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DocumentWindow::userTriedToCloseWindow()
 | 
			
		||||
{
 | 
			
		||||
    closeButtonPressed();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,295 +1,307 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A resizable window with a title bar and maximise, minimise and close buttons.
 | 
			
		||||
 | 
			
		||||
    This subclass of ResizableWindow creates a fairly standard type of window with
 | 
			
		||||
    a title bar and various buttons. The name of the component is shown in the
 | 
			
		||||
    title bar, and an icon can optionally be specified with setIcon().
 | 
			
		||||
 | 
			
		||||
    All the methods available to a ResizableWindow are also available to this,
 | 
			
		||||
    so it can easily be made resizable, minimised, maximised, etc.
 | 
			
		||||
 | 
			
		||||
    It's not advisable to add child components directly to a DocumentWindow: put them
 | 
			
		||||
    inside your content component instead. And overriding methods like resized(), moved(), etc
 | 
			
		||||
    is also not recommended - instead override these methods for your content component.
 | 
			
		||||
    (If for some obscure reason you do need to override these methods, always remember to
 | 
			
		||||
    call the super-class's resized() method too, otherwise it'll fail to lay out the window
 | 
			
		||||
    decorations correctly).
 | 
			
		||||
 | 
			
		||||
    You can also automatically add a menu bar to the window, using the setMenuBar()
 | 
			
		||||
    method.
 | 
			
		||||
 | 
			
		||||
    @see ResizableWindow, DialogWindow
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  DocumentWindow   : public ResizableWindow
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** The set of available button-types that can be put on the title bar.
 | 
			
		||||
 | 
			
		||||
        @see setTitleBarButtonsRequired
 | 
			
		||||
    */
 | 
			
		||||
    enum TitleBarButtons
 | 
			
		||||
    {
 | 
			
		||||
        minimiseButton = 1,
 | 
			
		||||
        maximiseButton = 2,
 | 
			
		||||
        closeButton = 4,
 | 
			
		||||
 | 
			
		||||
        /** A combination of all the buttons above. */
 | 
			
		||||
        allButtons = 7
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a DocumentWindow.
 | 
			
		||||
 | 
			
		||||
        @param name             the name to give the component - this is also
 | 
			
		||||
                                the title shown at the top of the window. To change
 | 
			
		||||
                                this later, use setName()
 | 
			
		||||
        @param backgroundColour the colour to use for filling the window's background.
 | 
			
		||||
        @param requiredButtons  specifies which of the buttons (close, minimise, maximise)
 | 
			
		||||
                                should be shown on the title bar. This value is a bitwise
 | 
			
		||||
                                combination of values from the TitleBarButtons enum. Note
 | 
			
		||||
                                that it can be "allButtons" to get them all. You
 | 
			
		||||
                                can change this later with the setTitleBarButtonsRequired()
 | 
			
		||||
                                method, which can also specify where they are positioned.
 | 
			
		||||
        @param addToDesktop     if true, the window will be automatically added to the
 | 
			
		||||
                                desktop; if false, you can use it as a child component
 | 
			
		||||
        @see TitleBarButtons
 | 
			
		||||
    */
 | 
			
		||||
    DocumentWindow (const String& name,
 | 
			
		||||
                    Colour backgroundColour,
 | 
			
		||||
                    int requiredButtons,
 | 
			
		||||
                    bool addToDesktop = true);
 | 
			
		||||
 | 
			
		||||
    /** Destructor.
 | 
			
		||||
        If a content component has been set with setContentOwned(), it will be deleted.
 | 
			
		||||
    */
 | 
			
		||||
    ~DocumentWindow() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Changes the component's name.
 | 
			
		||||
 | 
			
		||||
        (This is overridden from Component::setName() to cause a repaint, as
 | 
			
		||||
        the name is what gets drawn across the window's title bar).
 | 
			
		||||
    */
 | 
			
		||||
    void setName (const String& newName) override;
 | 
			
		||||
 | 
			
		||||
    /** Sets an icon to show in the title bar, next to the title.
 | 
			
		||||
 | 
			
		||||
        A copy is made internally of the image, so the caller can delete the
 | 
			
		||||
        image after calling this. If an empty Image is passed-in, any existing icon
 | 
			
		||||
        will be removed.
 | 
			
		||||
    */
 | 
			
		||||
    void setIcon (const Image& imageToUse);
 | 
			
		||||
 | 
			
		||||
    /** Changes the height of the title-bar. */
 | 
			
		||||
    void setTitleBarHeight (int newHeight);
 | 
			
		||||
 | 
			
		||||
    /** Returns the current title bar height. */
 | 
			
		||||
    int getTitleBarHeight() const;
 | 
			
		||||
 | 
			
		||||
    /** Changes the set of title-bar buttons being shown.
 | 
			
		||||
 | 
			
		||||
        @param requiredButtons  specifies which of the buttons (close, minimise, maximise)
 | 
			
		||||
                                should be shown on the title bar. This value is a bitwise
 | 
			
		||||
                                combination of values from the TitleBarButtons enum. Note
 | 
			
		||||
                                that it can be "allButtons" to get them all.
 | 
			
		||||
        @param positionTitleBarButtonsOnLeft    if true, the buttons should go at the
 | 
			
		||||
                                left side of the bar; if false, they'll be placed at the right
 | 
			
		||||
    */
 | 
			
		||||
    void setTitleBarButtonsRequired (int requiredButtons,
 | 
			
		||||
                                     bool positionTitleBarButtonsOnLeft);
 | 
			
		||||
 | 
			
		||||
    /** Sets whether the title should be centred within the window.
 | 
			
		||||
 | 
			
		||||
        If true, the title text is shown in the middle of the title-bar; if false,
 | 
			
		||||
        it'll be shown at the left of the bar.
 | 
			
		||||
    */
 | 
			
		||||
    void setTitleBarTextCentred (bool textShouldBeCentred);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a menu inside this window.
 | 
			
		||||
 | 
			
		||||
        @param menuBarModel     this specifies a MenuBarModel that should be used to
 | 
			
		||||
                                generate the contents of a menu bar that will be placed
 | 
			
		||||
                                just below the title bar, and just above any content
 | 
			
		||||
                                component. If this value is a nullptr, any existing menu bar
 | 
			
		||||
                                will be removed from the component; if it is not a nullptr,
 | 
			
		||||
                                one will be added if it's required.
 | 
			
		||||
        @param menuBarHeight    the height of the menu bar component, if one is needed. Pass a value of zero
 | 
			
		||||
                                or less to use the look-and-feel's default size.
 | 
			
		||||
    */
 | 
			
		||||
    void setMenuBar (MenuBarModel* menuBarModel,
 | 
			
		||||
                     int menuBarHeight = 0);
 | 
			
		||||
 | 
			
		||||
    /** Returns the current menu bar component, or null if there isn't one.
 | 
			
		||||
        This is probably a MenuBarComponent, unless a custom one has been set using
 | 
			
		||||
        setMenuBarComponent().
 | 
			
		||||
    */
 | 
			
		||||
    Component* getMenuBarComponent() const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Replaces the current menu bar with a custom component.
 | 
			
		||||
        The component will be owned and deleted by the document window.
 | 
			
		||||
    */
 | 
			
		||||
    void setMenuBarComponent (Component* newMenuBarComponent);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This method is called when the user tries to close the window.
 | 
			
		||||
 | 
			
		||||
        This is triggered by the user clicking the close button, or using some other
 | 
			
		||||
        OS-specific key shortcut or OS menu for getting rid of a window.
 | 
			
		||||
 | 
			
		||||
        If the window is just a pop-up, you should override this closeButtonPressed()
 | 
			
		||||
        method and make it delete the window in whatever way is appropriate for your
 | 
			
		||||
        app. E.g. you might just want to call "delete this".
 | 
			
		||||
 | 
			
		||||
        If your app is centred around this window such that the whole app should quit when
 | 
			
		||||
        the window is closed, then you will probably want to use this method as an opportunity
 | 
			
		||||
        to call JUCEApplicationBase::quit(), and leave the window to be deleted later by your
 | 
			
		||||
        JUCEApplicationBase::shutdown() method. (Doing it this way means that your window will
 | 
			
		||||
        still get cleaned-up if the app is quit by some other means (e.g. a cmd-Q on the mac
 | 
			
		||||
        or closing it via the taskbar icon on Windows).
 | 
			
		||||
 | 
			
		||||
        (Note that the DocumentWindow class overrides Component::userTriedToCloseWindow() and
 | 
			
		||||
        redirects it to call this method, so any methods of closing the window that are
 | 
			
		||||
        caught by userTriedToCloseWindow() will also end up here).
 | 
			
		||||
    */
 | 
			
		||||
    virtual void closeButtonPressed();
 | 
			
		||||
 | 
			
		||||
    /** Callback that is triggered when the minimise button is pressed.
 | 
			
		||||
 | 
			
		||||
        The default implementation of this calls ResizableWindow::setMinimised(), but
 | 
			
		||||
        you can override it to do more customised behaviour.
 | 
			
		||||
    */
 | 
			
		||||
    virtual void minimiseButtonPressed();
 | 
			
		||||
 | 
			
		||||
    /** Callback that is triggered when the maximise button is pressed, or when the
 | 
			
		||||
        title-bar is double-clicked.
 | 
			
		||||
 | 
			
		||||
        The default implementation of this calls ResizableWindow::setFullScreen(), but
 | 
			
		||||
        you can override it to do more customised behaviour.
 | 
			
		||||
    */
 | 
			
		||||
    virtual void maximiseButtonPressed();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the close button, (or nullptr if there isn't one). */
 | 
			
		||||
    Button* getCloseButton() const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns the minimise button, (or nullptr if there isn't one). */
 | 
			
		||||
    Button* getMinimiseButton() const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns the maximise button, (or nullptr if there isn't one). */
 | 
			
		||||
    Button* getMaximiseButton() const noexcept;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** A set of colour IDs to use to change the colour of various aspects of the window.
 | 
			
		||||
 | 
			
		||||
        These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
 | 
			
		||||
        methods.
 | 
			
		||||
 | 
			
		||||
        @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
 | 
			
		||||
    */
 | 
			
		||||
    enum ColourIds
 | 
			
		||||
    {
 | 
			
		||||
        textColourId                = 0x1005701,  /**< The colour to draw any text with. It's up to the look
 | 
			
		||||
                                                       and feel class how this is used. */
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This abstract base class is implemented by LookAndFeel classes to provide
 | 
			
		||||
        window drawing functionality.
 | 
			
		||||
    */
 | 
			
		||||
    struct JUCE_API  LookAndFeelMethods
 | 
			
		||||
    {
 | 
			
		||||
        virtual ~LookAndFeelMethods() = default;
 | 
			
		||||
 | 
			
		||||
        virtual void drawDocumentWindowTitleBar (DocumentWindow&,
 | 
			
		||||
                                                 Graphics&, int w, int h,
 | 
			
		||||
                                                 int titleSpaceX, int titleSpaceW,
 | 
			
		||||
                                                 const Image* icon,
 | 
			
		||||
                                                 bool drawTitleTextOnLeft) = 0;
 | 
			
		||||
 | 
			
		||||
        virtual Button* createDocumentWindowButton (int buttonType) = 0;
 | 
			
		||||
 | 
			
		||||
        virtual void positionDocumentWindowButtons (DocumentWindow&,
 | 
			
		||||
                                                    int titleBarX, int titleBarY, int titleBarW, int titleBarH,
 | 
			
		||||
                                                    Button* minimiseButton,
 | 
			
		||||
                                                    Button* maximiseButton,
 | 
			
		||||
                                                    Button* closeButton,
 | 
			
		||||
                                                    bool positionTitleBarButtonsOnLeft) = 0;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
   #ifndef DOXYGEN
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void resized() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void lookAndFeelChanged() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    BorderSize<int> getBorderThickness() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    BorderSize<int> getContentComponentBorder() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void mouseDoubleClick (const MouseEvent&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void userTriedToCloseWindow() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void activeWindowStatusChanged() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    int getDesktopWindowStyleFlags() const override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void parentHierarchyChanged() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    Rectangle<int> getTitleBarArea();
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    int titleBarHeight = 26, menuBarHeight = 24, requiredButtons;
 | 
			
		||||
    bool positionTitleBarButtonsOnLeft, drawTitleTextCentred = true;
 | 
			
		||||
    std::unique_ptr<Button> titleBarButtons [3];
 | 
			
		||||
    Image titleBarIcon;
 | 
			
		||||
    std::unique_ptr<Component> menuBar;
 | 
			
		||||
    MenuBarModel* menuBarModel = nullptr;
 | 
			
		||||
 | 
			
		||||
    class ButtonListenerProxy;
 | 
			
		||||
    std::unique_ptr<ButtonListenerProxy> buttonListener;
 | 
			
		||||
 | 
			
		||||
    void repaintTitleBar();
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DocumentWindow)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - 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 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A resizable window with a title bar and maximise, minimise and close buttons.
 | 
			
		||||
 | 
			
		||||
    This subclass of ResizableWindow creates a fairly standard type of window with
 | 
			
		||||
    a title bar and various buttons. The name of the component is shown in the
 | 
			
		||||
    title bar, and an icon can optionally be specified with setIcon().
 | 
			
		||||
 | 
			
		||||
    All the methods available to a ResizableWindow are also available to this,
 | 
			
		||||
    so it can easily be made resizable, minimised, maximised, etc.
 | 
			
		||||
 | 
			
		||||
    It's not advisable to add child components directly to a DocumentWindow: put them
 | 
			
		||||
    inside your content component instead. And overriding methods like resized(), moved(), etc
 | 
			
		||||
    is also not recommended - instead override these methods for your content component.
 | 
			
		||||
    (If for some obscure reason you do need to override these methods, always remember to
 | 
			
		||||
    call the super-class's resized() method too, otherwise it'll fail to lay out the window
 | 
			
		||||
    decorations correctly).
 | 
			
		||||
 | 
			
		||||
    You can also automatically add a menu bar to the window, using the setMenuBar()
 | 
			
		||||
    method.
 | 
			
		||||
 | 
			
		||||
    @see ResizableWindow, DialogWindow
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  DocumentWindow   : public ResizableWindow
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** The set of available button-types that can be put on the title bar.
 | 
			
		||||
 | 
			
		||||
        @see setTitleBarButtonsRequired
 | 
			
		||||
    */
 | 
			
		||||
    enum TitleBarButtons
 | 
			
		||||
    {
 | 
			
		||||
        minimiseButton = 1,
 | 
			
		||||
        maximiseButton = 2,
 | 
			
		||||
        closeButton = 4,
 | 
			
		||||
 | 
			
		||||
        /** A combination of all the buttons above. */
 | 
			
		||||
        allButtons = 7
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a DocumentWindow.
 | 
			
		||||
 | 
			
		||||
        @param name             the name to give the component - this is also
 | 
			
		||||
                                the title shown at the top of the window. To change
 | 
			
		||||
                                this later, use setName()
 | 
			
		||||
        @param backgroundColour the colour to use for filling the window's background.
 | 
			
		||||
        @param requiredButtons  specifies which of the buttons (close, minimise, maximise)
 | 
			
		||||
                                should be shown on the title bar. This value is a bitwise
 | 
			
		||||
                                combination of values from the TitleBarButtons enum. Note
 | 
			
		||||
                                that it can be "allButtons" to get them all. You
 | 
			
		||||
                                can change this later with the setTitleBarButtonsRequired()
 | 
			
		||||
                                method, which can also specify where they are positioned.
 | 
			
		||||
                                The behaviour of native titlebars on macOS is slightly different:
 | 
			
		||||
                                the maximiseButton flag controls whether or not the window can enter
 | 
			
		||||
                                native fullscreen mode, and the zoom button can be disabled by
 | 
			
		||||
                                making the window non-resizable.
 | 
			
		||||
        @param addToDesktop     if true, the window will be automatically added to the
 | 
			
		||||
                                desktop; if false, you can use it as a child component
 | 
			
		||||
        @see TitleBarButtons
 | 
			
		||||
    */
 | 
			
		||||
    DocumentWindow (const String& name,
 | 
			
		||||
                    Colour backgroundColour,
 | 
			
		||||
                    int requiredButtons,
 | 
			
		||||
                    bool addToDesktop = true);
 | 
			
		||||
 | 
			
		||||
    /** Destructor.
 | 
			
		||||
        If a content component has been set with setContentOwned(), it will be deleted.
 | 
			
		||||
    */
 | 
			
		||||
    ~DocumentWindow() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Changes the component's name.
 | 
			
		||||
 | 
			
		||||
        (This is overridden from Component::setName() to cause a repaint, as
 | 
			
		||||
        the name is what gets drawn across the window's title bar).
 | 
			
		||||
    */
 | 
			
		||||
    void setName (const String& newName) override;
 | 
			
		||||
 | 
			
		||||
    /** Sets an icon to show in the title bar, next to the title.
 | 
			
		||||
 | 
			
		||||
        A copy is made internally of the image, so the caller can delete the
 | 
			
		||||
        image after calling this. If an empty Image is passed-in, any existing icon
 | 
			
		||||
        will be removed.
 | 
			
		||||
    */
 | 
			
		||||
    void setIcon (const Image& imageToUse);
 | 
			
		||||
 | 
			
		||||
    /** Changes the height of the title-bar. */
 | 
			
		||||
    void setTitleBarHeight (int newHeight);
 | 
			
		||||
 | 
			
		||||
    /** Returns the current title bar height. */
 | 
			
		||||
    int getTitleBarHeight() const;
 | 
			
		||||
 | 
			
		||||
    /** Changes the set of title-bar buttons being shown.
 | 
			
		||||
 | 
			
		||||
        @param requiredButtons  specifies which of the buttons (close, minimise, maximise)
 | 
			
		||||
                                should be shown on the title bar. This value is a bitwise
 | 
			
		||||
                                combination of values from the TitleBarButtons enum. Note
 | 
			
		||||
                                that it can be "allButtons" to get them all.
 | 
			
		||||
                                The behaviour of native titlebars on macOS is slightly different:
 | 
			
		||||
                                the maximiseButton flag controls whether or not the window can enter
 | 
			
		||||
                                native fullscreen mode, and the zoom button can be disabled by
 | 
			
		||||
                                making the window non-resizable.
 | 
			
		||||
        @param positionTitleBarButtonsOnLeft    if true, the buttons should go at the
 | 
			
		||||
                                left side of the bar; if false, they'll be placed at the right
 | 
			
		||||
    */
 | 
			
		||||
    void setTitleBarButtonsRequired (int requiredButtons,
 | 
			
		||||
                                     bool positionTitleBarButtonsOnLeft);
 | 
			
		||||
 | 
			
		||||
    /** Sets whether the title should be centred within the window.
 | 
			
		||||
 | 
			
		||||
        If true, the title text is shown in the middle of the title-bar; if false,
 | 
			
		||||
        it'll be shown at the left of the bar.
 | 
			
		||||
    */
 | 
			
		||||
    void setTitleBarTextCentred (bool textShouldBeCentred);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a menu inside this window.
 | 
			
		||||
 | 
			
		||||
        @param menuBarModel     this specifies a MenuBarModel that should be used to
 | 
			
		||||
                                generate the contents of a menu bar that will be placed
 | 
			
		||||
                                just below the title bar, and just above any content
 | 
			
		||||
                                component. If this value is a nullptr, any existing menu bar
 | 
			
		||||
                                will be removed from the component; if it is not a nullptr,
 | 
			
		||||
                                one will be added if it's required.
 | 
			
		||||
        @param menuBarHeight    the height of the menu bar component, if one is needed. Pass a value of zero
 | 
			
		||||
                                or less to use the look-and-feel's default size.
 | 
			
		||||
    */
 | 
			
		||||
    void setMenuBar (MenuBarModel* menuBarModel,
 | 
			
		||||
                     int menuBarHeight = 0);
 | 
			
		||||
 | 
			
		||||
    /** Returns the current menu bar component, or null if there isn't one.
 | 
			
		||||
        This is probably a MenuBarComponent, unless a custom one has been set using
 | 
			
		||||
        setMenuBarComponent().
 | 
			
		||||
    */
 | 
			
		||||
    Component* getMenuBarComponent() const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Replaces the current menu bar with a custom component.
 | 
			
		||||
        The component will be owned and deleted by the document window.
 | 
			
		||||
    */
 | 
			
		||||
    void setMenuBarComponent (Component* newMenuBarComponent);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This method is called when the user tries to close the window.
 | 
			
		||||
 | 
			
		||||
        This is triggered by the user clicking the close button, or using some other
 | 
			
		||||
        OS-specific key shortcut or OS menu for getting rid of a window.
 | 
			
		||||
 | 
			
		||||
        If the window is just a pop-up, you should override this closeButtonPressed()
 | 
			
		||||
        method and make it delete the window in whatever way is appropriate for your
 | 
			
		||||
        app. E.g. you might just want to call "delete this".
 | 
			
		||||
 | 
			
		||||
        If your app is centred around this window such that the whole app should quit when
 | 
			
		||||
        the window is closed, then you will probably want to use this method as an opportunity
 | 
			
		||||
        to call JUCEApplicationBase::quit(), and leave the window to be deleted later by your
 | 
			
		||||
        JUCEApplicationBase::shutdown() method. (Doing it this way means that your window will
 | 
			
		||||
        still get cleaned-up if the app is quit by some other means (e.g. a cmd-Q on the mac
 | 
			
		||||
        or closing it via the taskbar icon on Windows).
 | 
			
		||||
 | 
			
		||||
        (Note that the DocumentWindow class overrides Component::userTriedToCloseWindow() and
 | 
			
		||||
        redirects it to call this method, so any methods of closing the window that are
 | 
			
		||||
        caught by userTriedToCloseWindow() will also end up here).
 | 
			
		||||
    */
 | 
			
		||||
    virtual void closeButtonPressed();
 | 
			
		||||
 | 
			
		||||
    /** Callback that is triggered when the minimise button is pressed.
 | 
			
		||||
 | 
			
		||||
        This function is only called when using a non-native titlebar.
 | 
			
		||||
 | 
			
		||||
        The default implementation of this calls ResizableWindow::setMinimised(), but
 | 
			
		||||
        you can override it to do more customised behaviour.
 | 
			
		||||
    */
 | 
			
		||||
    virtual void minimiseButtonPressed();
 | 
			
		||||
 | 
			
		||||
    /** Callback that is triggered when the maximise button is pressed, or when the
 | 
			
		||||
        title-bar is double-clicked.
 | 
			
		||||
 | 
			
		||||
        This function is only called when using a non-native titlebar.
 | 
			
		||||
 | 
			
		||||
        The default implementation of this calls ResizableWindow::setFullScreen(), but
 | 
			
		||||
        you can override it to do more customised behaviour.
 | 
			
		||||
    */
 | 
			
		||||
    virtual void maximiseButtonPressed();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the close button, (or nullptr if there isn't one). */
 | 
			
		||||
    Button* getCloseButton() const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns the minimise button, (or nullptr if there isn't one). */
 | 
			
		||||
    Button* getMinimiseButton() const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns the maximise button, (or nullptr if there isn't one). */
 | 
			
		||||
    Button* getMaximiseButton() const noexcept;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** A set of colour IDs to use to change the colour of various aspects of the window.
 | 
			
		||||
 | 
			
		||||
        These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
 | 
			
		||||
        methods.
 | 
			
		||||
 | 
			
		||||
        @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
 | 
			
		||||
    */
 | 
			
		||||
    enum ColourIds
 | 
			
		||||
    {
 | 
			
		||||
        textColourId                = 0x1005701,  /**< The colour to draw any text with. It's up to the look
 | 
			
		||||
                                                       and feel class how this is used. */
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This abstract base class is implemented by LookAndFeel classes to provide
 | 
			
		||||
        window drawing functionality.
 | 
			
		||||
    */
 | 
			
		||||
    struct JUCE_API  LookAndFeelMethods
 | 
			
		||||
    {
 | 
			
		||||
        virtual ~LookAndFeelMethods() = default;
 | 
			
		||||
 | 
			
		||||
        virtual void drawDocumentWindowTitleBar (DocumentWindow&,
 | 
			
		||||
                                                 Graphics&, int w, int h,
 | 
			
		||||
                                                 int titleSpaceX, int titleSpaceW,
 | 
			
		||||
                                                 const Image* icon,
 | 
			
		||||
                                                 bool drawTitleTextOnLeft) = 0;
 | 
			
		||||
 | 
			
		||||
        virtual Button* createDocumentWindowButton (int buttonType) = 0;
 | 
			
		||||
 | 
			
		||||
        virtual void positionDocumentWindowButtons (DocumentWindow&,
 | 
			
		||||
                                                    int titleBarX, int titleBarY, int titleBarW, int titleBarH,
 | 
			
		||||
                                                    Button* minimiseButton,
 | 
			
		||||
                                                    Button* maximiseButton,
 | 
			
		||||
                                                    Button* closeButton,
 | 
			
		||||
                                                    bool positionTitleBarButtonsOnLeft) = 0;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
   #ifndef DOXYGEN
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void resized() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void lookAndFeelChanged() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    BorderSize<int> getBorderThickness() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    BorderSize<int> getContentComponentBorder() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void mouseDoubleClick (const MouseEvent&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void userTriedToCloseWindow() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void activeWindowStatusChanged() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    int getDesktopWindowStyleFlags() const override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void parentHierarchyChanged() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    Rectangle<int> getTitleBarArea();
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    int titleBarHeight = 26, menuBarHeight = 24, requiredButtons;
 | 
			
		||||
    bool positionTitleBarButtonsOnLeft, drawTitleTextCentred = true;
 | 
			
		||||
    std::unique_ptr<Button> titleBarButtons [3];
 | 
			
		||||
    Image titleBarIcon;
 | 
			
		||||
    std::unique_ptr<Component> menuBar;
 | 
			
		||||
    MenuBarModel* menuBarModel = nullptr;
 | 
			
		||||
 | 
			
		||||
    class ButtonListenerProxy;
 | 
			
		||||
    std::unique_ptr<ButtonListenerProxy> buttonListener;
 | 
			
		||||
 | 
			
		||||
    void repaintTitleBar();
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DocumentWindow)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,143 +1,143 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
/** The type of icon to show in the dialog box. */
 | 
			
		||||
enum class MessageBoxIconType
 | 
			
		||||
{
 | 
			
		||||
    NoIcon,         /**< No icon will be shown on the dialog box. */
 | 
			
		||||
    QuestionIcon,   /**< A question-mark icon, for dialog boxes that need the
 | 
			
		||||
                         user to answer a question. */
 | 
			
		||||
    WarningIcon,    /**< An exclamation mark to indicate that the dialog is a
 | 
			
		||||
                         warning about something and shouldn't be ignored. */
 | 
			
		||||
    InfoIcon        /**< An icon that indicates that the dialog box is just
 | 
			
		||||
                         giving the user some information, which doesn't require
 | 
			
		||||
                         a response from them. */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/** Class used to create a set of options to pass to the AlertWindow and NativeMessageBox
 | 
			
		||||
    methods for showing dialog boxes.
 | 
			
		||||
 | 
			
		||||
    You can chain together a series of calls to this class's methods to create
 | 
			
		||||
    a set of whatever options you want to specify.
 | 
			
		||||
 | 
			
		||||
    E.g. @code
 | 
			
		||||
    AlertWindow::showAsync (MessageBoxOptions()
 | 
			
		||||
                              .withIconType (MessageBoxIconType::InfoIcon)
 | 
			
		||||
                              .withTitle ("A Title")
 | 
			
		||||
                              .withMessage ("A message.")
 | 
			
		||||
                              .withButton ("OK")
 | 
			
		||||
                              .withButton ("Cancel")
 | 
			
		||||
                              .withAssociatedComponent (myComp),
 | 
			
		||||
                            myCallback);
 | 
			
		||||
    @endcode
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  MessageBoxOptions
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    MessageBoxOptions() = default;
 | 
			
		||||
    MessageBoxOptions (const MessageBoxOptions&) = default;
 | 
			
		||||
    MessageBoxOptions& operator= (const MessageBoxOptions&) = default;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Sets the type of icon that should be used for the dialog box. */
 | 
			
		||||
    MessageBoxOptions withIconType (MessageBoxIconType type) const          { return with (*this, &MessageBoxOptions::iconType, type); }
 | 
			
		||||
 | 
			
		||||
    /** Sets the title of the dialog box. */
 | 
			
		||||
    MessageBoxOptions withTitle (const String& boxTitle) const              { return with (*this, &MessageBoxOptions::title, boxTitle); }
 | 
			
		||||
 | 
			
		||||
    /** Sets the message that should be displayed in the dialog box. */
 | 
			
		||||
    MessageBoxOptions withMessage (const String& boxMessage) const          { return with (*this, &MessageBoxOptions::message, boxMessage); }
 | 
			
		||||
 | 
			
		||||
    /** If the string passed in is not empty, this will add a button to the
 | 
			
		||||
        dialog box with the specified text.
 | 
			
		||||
 | 
			
		||||
        Generally up to 3 buttons are supported for dialog boxes, so adding any more
 | 
			
		||||
        than this may have no effect.
 | 
			
		||||
    */
 | 
			
		||||
    MessageBoxOptions withButton (const String& text) const                 { auto copy = *this; copy.buttons.add (text); return copy; }
 | 
			
		||||
 | 
			
		||||
    /** The component that the dialog box should be associated with. */
 | 
			
		||||
    MessageBoxOptions withAssociatedComponent (Component* component) const  { return with (*this, &MessageBoxOptions::associatedComponent, component); }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the icon type of the dialog box.
 | 
			
		||||
 | 
			
		||||
        @see withIconType
 | 
			
		||||
    */
 | 
			
		||||
    MessageBoxIconType getIconType() const noexcept          { return iconType; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the title of the dialog box.
 | 
			
		||||
 | 
			
		||||
        @see withTitle
 | 
			
		||||
    */
 | 
			
		||||
    String getTitle() const                                  { return title; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the message of the dialog box.
 | 
			
		||||
 | 
			
		||||
        @see withMessage
 | 
			
		||||
    */
 | 
			
		||||
    String getMessage() const                                { return message; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the number of buttons that have been added to the dialog box.
 | 
			
		||||
 | 
			
		||||
        @see withButtonText
 | 
			
		||||
    */
 | 
			
		||||
    int getNumButtons() const noexcept                       { return buttons.size(); }
 | 
			
		||||
 | 
			
		||||
    /** Returns the text that has been set for one of the buttons of the dialog box.
 | 
			
		||||
 | 
			
		||||
        @see withButtonText, getNumButtons
 | 
			
		||||
    */
 | 
			
		||||
    String getButtonText (int buttonIndex) const             { return buttons[buttonIndex]; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the component that the dialog box is associated with.
 | 
			
		||||
 | 
			
		||||
        @see withAssociatedComponent
 | 
			
		||||
    */
 | 
			
		||||
    Component* getAssociatedComponent() const noexcept       { return associatedComponent; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    template <typename Member, typename Item>
 | 
			
		||||
    static MessageBoxOptions with (MessageBoxOptions options, Member&& member, Item&& item)
 | 
			
		||||
    {
 | 
			
		||||
        options.*member = std::forward<Item> (item);
 | 
			
		||||
        return options;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    MessageBoxIconType iconType = MessageBoxIconType::InfoIcon;
 | 
			
		||||
    String title, message;
 | 
			
		||||
    StringArray buttons;
 | 
			
		||||
    WeakReference<Component> associatedComponent;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - 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 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
/** The type of icon to show in the dialog box. */
 | 
			
		||||
enum class MessageBoxIconType
 | 
			
		||||
{
 | 
			
		||||
    NoIcon,         /**< No icon will be shown on the dialog box. */
 | 
			
		||||
    QuestionIcon,   /**< A question-mark icon, for dialog boxes that need the
 | 
			
		||||
                         user to answer a question. */
 | 
			
		||||
    WarningIcon,    /**< An exclamation mark to indicate that the dialog is a
 | 
			
		||||
                         warning about something and shouldn't be ignored. */
 | 
			
		||||
    InfoIcon        /**< An icon that indicates that the dialog box is just
 | 
			
		||||
                         giving the user some information, which doesn't require
 | 
			
		||||
                         a response from them. */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/** Class used to create a set of options to pass to the AlertWindow and NativeMessageBox
 | 
			
		||||
    methods for showing dialog boxes.
 | 
			
		||||
 | 
			
		||||
    You can chain together a series of calls to this class's methods to create
 | 
			
		||||
    a set of whatever options you want to specify.
 | 
			
		||||
 | 
			
		||||
    E.g. @code
 | 
			
		||||
    AlertWindow::showAsync (MessageBoxOptions()
 | 
			
		||||
                              .withIconType (MessageBoxIconType::InfoIcon)
 | 
			
		||||
                              .withTitle ("A Title")
 | 
			
		||||
                              .withMessage ("A message.")
 | 
			
		||||
                              .withButton ("OK")
 | 
			
		||||
                              .withButton ("Cancel")
 | 
			
		||||
                              .withAssociatedComponent (myComp),
 | 
			
		||||
                            myCallback);
 | 
			
		||||
    @endcode
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  MessageBoxOptions
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    MessageBoxOptions() = default;
 | 
			
		||||
    MessageBoxOptions (const MessageBoxOptions&) = default;
 | 
			
		||||
    MessageBoxOptions& operator= (const MessageBoxOptions&) = default;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Sets the type of icon that should be used for the dialog box. */
 | 
			
		||||
    JUCE_NODISCARD MessageBoxOptions withIconType (MessageBoxIconType type) const          { return with (*this, &MessageBoxOptions::iconType, type); }
 | 
			
		||||
 | 
			
		||||
    /** Sets the title of the dialog box. */
 | 
			
		||||
    JUCE_NODISCARD MessageBoxOptions withTitle (const String& boxTitle) const              { return with (*this, &MessageBoxOptions::title, boxTitle); }
 | 
			
		||||
 | 
			
		||||
    /** Sets the message that should be displayed in the dialog box. */
 | 
			
		||||
    JUCE_NODISCARD MessageBoxOptions withMessage (const String& boxMessage) const          { return with (*this, &MessageBoxOptions::message, boxMessage); }
 | 
			
		||||
 | 
			
		||||
    /** If the string passed in is not empty, this will add a button to the
 | 
			
		||||
        dialog box with the specified text.
 | 
			
		||||
 | 
			
		||||
        Generally up to 3 buttons are supported for dialog boxes, so adding any more
 | 
			
		||||
        than this may have no effect.
 | 
			
		||||
    */
 | 
			
		||||
    JUCE_NODISCARD MessageBoxOptions withButton (const String& text) const                 { auto copy = *this; copy.buttons.add (text); return copy; }
 | 
			
		||||
 | 
			
		||||
    /** The component that the dialog box should be associated with. */
 | 
			
		||||
    JUCE_NODISCARD MessageBoxOptions withAssociatedComponent (Component* component) const  { return with (*this, &MessageBoxOptions::associatedComponent, component); }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the icon type of the dialog box.
 | 
			
		||||
 | 
			
		||||
        @see withIconType
 | 
			
		||||
    */
 | 
			
		||||
    MessageBoxIconType getIconType() const noexcept          { return iconType; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the title of the dialog box.
 | 
			
		||||
 | 
			
		||||
        @see withTitle
 | 
			
		||||
    */
 | 
			
		||||
    String getTitle() const                                  { return title; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the message of the dialog box.
 | 
			
		||||
 | 
			
		||||
        @see withMessage
 | 
			
		||||
    */
 | 
			
		||||
    String getMessage() const                                { return message; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the number of buttons that have been added to the dialog box.
 | 
			
		||||
 | 
			
		||||
        @see withButtonText
 | 
			
		||||
    */
 | 
			
		||||
    int getNumButtons() const noexcept                       { return buttons.size(); }
 | 
			
		||||
 | 
			
		||||
    /** Returns the text that has been set for one of the buttons of the dialog box.
 | 
			
		||||
 | 
			
		||||
        @see withButtonText, getNumButtons
 | 
			
		||||
    */
 | 
			
		||||
    String getButtonText (int buttonIndex) const             { return buttons[buttonIndex]; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the component that the dialog box is associated with.
 | 
			
		||||
 | 
			
		||||
        @see withAssociatedComponent
 | 
			
		||||
    */
 | 
			
		||||
    Component* getAssociatedComponent() const noexcept       { return associatedComponent; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    template <typename Member, typename Item>
 | 
			
		||||
    static MessageBoxOptions with (MessageBoxOptions options, Member&& member, Item&& item)
 | 
			
		||||
    {
 | 
			
		||||
        options.*member = std::forward<Item> (item);
 | 
			
		||||
        return options;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    MessageBoxIconType iconType = MessageBoxIconType::InfoIcon;
 | 
			
		||||
    String title, message;
 | 
			
		||||
    StringArray buttons;
 | 
			
		||||
    WeakReference<Component> associatedComponent;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,265 +1,265 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    This class contains some static methods for showing native alert windows.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class NativeMessageBox
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
   #if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
    /** Shows a dialog box that just has a message and a single 'ok' button to close it.
 | 
			
		||||
 | 
			
		||||
        The box is shown modally, and the method will block until the user has clicked its
 | 
			
		||||
        button (or pressed the escape or return keys).
 | 
			
		||||
 | 
			
		||||
        @param iconType     the type of icon to show.
 | 
			
		||||
        @param title        the headline to show at the top of the box.
 | 
			
		||||
        @param message      a longer, more descriptive message to show underneath the title.
 | 
			
		||||
        @param associatedComponent   if this is non-null, it specifies the component that the
 | 
			
		||||
                            alert window should be associated with. Depending on the look
 | 
			
		||||
                            and feel, this might be used for positioning of the alert window.
 | 
			
		||||
    */
 | 
			
		||||
    static void JUCE_CALLTYPE showMessageBox (MessageBoxIconType iconType,
 | 
			
		||||
                                              const String& title,
 | 
			
		||||
                                              const String& message,
 | 
			
		||||
                                              Component* associatedComponent = nullptr);
 | 
			
		||||
 | 
			
		||||
    /** Shows a dialog box using the specified options.
 | 
			
		||||
 | 
			
		||||
        The box is shown modally, and the method will block until the user dismisses it.
 | 
			
		||||
 | 
			
		||||
        @param options  the options to use when creating the dialog.
 | 
			
		||||
 | 
			
		||||
        @returns  the index of the button that was clicked.
 | 
			
		||||
 | 
			
		||||
        @see MessageBoxOptions
 | 
			
		||||
    */
 | 
			
		||||
    static int JUCE_CALLTYPE show (const MessageBoxOptions& options);
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    /** Shows a dialog box using the specified options.
 | 
			
		||||
 | 
			
		||||
        The box will be displayed and placed into a modal state, but this method will return
 | 
			
		||||
        immediately, and the callback will be invoked later when the user dismisses the box.
 | 
			
		||||
 | 
			
		||||
        @param options   the options to use when creating the dialog.
 | 
			
		||||
        @param callback  if this is non-null, the callback will receive a call to its
 | 
			
		||||
                         modalStateFinished() when the box is dismissed with the index of the
 | 
			
		||||
                         button that was clicked as its argument.
 | 
			
		||||
                         The callback object will be owned and deleted by the system, so make sure
 | 
			
		||||
                         that it works safely and doesn't keep any references to objects that might
 | 
			
		||||
                         be deleted before it gets called.
 | 
			
		||||
 | 
			
		||||
        @see MessageBoxOptions
 | 
			
		||||
    */
 | 
			
		||||
    static void JUCE_CALLTYPE showAsync (const MessageBoxOptions& options,
 | 
			
		||||
                                         ModalComponentManager::Callback* callback);
 | 
			
		||||
 | 
			
		||||
    /** Shows a dialog box using the specified options.
 | 
			
		||||
 | 
			
		||||
        The box will be displayed and placed into a modal state, but this method will return
 | 
			
		||||
        immediately, and the callback will be invoked later when the user dismisses the box.
 | 
			
		||||
 | 
			
		||||
        @param options   the options to use when creating the dialog.
 | 
			
		||||
        @param callback  if this is non-null, the callback will be called when the box is
 | 
			
		||||
                         dismissed with the index of the button that was clicked as its argument.
 | 
			
		||||
 | 
			
		||||
        @see MessageBoxOptions
 | 
			
		||||
    */
 | 
			
		||||
    static void JUCE_CALLTYPE showAsync (const MessageBoxOptions& options,
 | 
			
		||||
                                         std::function<void (int)> callback);
 | 
			
		||||
 | 
			
		||||
    /** Shows a dialog box that just has a message and a single 'ok' button to close it.
 | 
			
		||||
 | 
			
		||||
        The box will be displayed and placed into a modal state, but this method will return
 | 
			
		||||
        immediately, and the callback will be invoked later when the user dismisses the box.
 | 
			
		||||
 | 
			
		||||
        @param iconType     the type of icon to show.
 | 
			
		||||
        @param title        the headline to show at the top of the box.
 | 
			
		||||
        @param message      a longer, more descriptive message to show underneath the title.
 | 
			
		||||
        @param associatedComponent   if this is non-null, it specifies the component that the
 | 
			
		||||
                            alert window should be associated with. Depending on the look
 | 
			
		||||
                            and feel, this might be used for positioning of the alert window.
 | 
			
		||||
        @param callback     if this is non-null, the callback will receive a call to its
 | 
			
		||||
                            modalStateFinished() when the box is dismissed. The callback object
 | 
			
		||||
                            will be owned and deleted by the system, so make sure that it works
 | 
			
		||||
                            safely and doesn't keep any references to objects that might be deleted
 | 
			
		||||
                            before it gets called. You can use the ModalCallbackFunction to easily
 | 
			
		||||
                            pass in a lambda for this parameter.
 | 
			
		||||
 | 
			
		||||
        @see ModalCallbackFunction
 | 
			
		||||
    */
 | 
			
		||||
    static void JUCE_CALLTYPE showMessageBoxAsync (MessageBoxIconType iconType,
 | 
			
		||||
                                                   const String& title,
 | 
			
		||||
                                                   const String& message,
 | 
			
		||||
                                                   Component* associatedComponent = nullptr,
 | 
			
		||||
                                                   ModalComponentManager::Callback* callback = nullptr);
 | 
			
		||||
 | 
			
		||||
    /** Shows a dialog box with two buttons.
 | 
			
		||||
 | 
			
		||||
        Ideal for ok/cancel or yes/no choices. The return key can also be used
 | 
			
		||||
        to trigger the first button, and the escape key for the second button.
 | 
			
		||||
 | 
			
		||||
        If the callback parameter is null and modal loops are enabled, the box is shown modally,
 | 
			
		||||
        and the method will block until the user has clicked the button (or pressed the escape or
 | 
			
		||||
        return keys). If the callback parameter is non-null, the box will be displayed and placed
 | 
			
		||||
        into a modal state, but this method will return immediately, and the callback will be invoked
 | 
			
		||||
        later when the user dismisses the box.
 | 
			
		||||
 | 
			
		||||
        @param iconType     the type of icon to show.
 | 
			
		||||
        @param title        the headline to show at the top of the box.
 | 
			
		||||
        @param message      a longer, more descriptive message to show underneath the title.
 | 
			
		||||
        @param associatedComponent   if this is non-null, it specifies the component that the
 | 
			
		||||
                            alert window should be associated with. Depending on the look
 | 
			
		||||
                            and feel, this might be used for positioning of the alert window.
 | 
			
		||||
        @param callback     if this is non-null, the box will be launched asynchronously,
 | 
			
		||||
                            returning immediately, and the callback will receive a call to its
 | 
			
		||||
                            modalStateFinished() when the box is dismissed, with its parameter
 | 
			
		||||
                            being 1 if the ok button was pressed, or 0 for cancel, The callback object
 | 
			
		||||
                            will be owned and deleted by the system, so make sure that it works
 | 
			
		||||
                            safely and doesn't keep any references to objects that might be deleted
 | 
			
		||||
                            before it gets called. You can use the ModalCallbackFunction to easily
 | 
			
		||||
                            pass in a lambda for this parameter.
 | 
			
		||||
        @returns true if button 1 was clicked, false if it was button 2. If the callback parameter
 | 
			
		||||
                 is not null, the method always returns false, and the user's choice is delivered
 | 
			
		||||
                 later by the callback.
 | 
			
		||||
 | 
			
		||||
        @see ModalCallbackFunction
 | 
			
		||||
    */
 | 
			
		||||
    static bool JUCE_CALLTYPE showOkCancelBox (MessageBoxIconType iconType,
 | 
			
		||||
                                               const String& title,
 | 
			
		||||
                                               const String& message,
 | 
			
		||||
                                              #if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
                                               Component* associatedComponent = nullptr,
 | 
			
		||||
                                               ModalComponentManager::Callback* callback = nullptr);
 | 
			
		||||
                                              #else
 | 
			
		||||
                                               Component* associatedComponent,
 | 
			
		||||
                                               ModalComponentManager::Callback* callback);
 | 
			
		||||
                                              #endif
 | 
			
		||||
 | 
			
		||||
    /** Shows a dialog box with three buttons.
 | 
			
		||||
 | 
			
		||||
        Ideal for yes/no/cancel boxes.
 | 
			
		||||
 | 
			
		||||
        The escape key can be used to trigger the third button.
 | 
			
		||||
 | 
			
		||||
        If the callback parameter is null and modal loops are enabled, the box is shown modally,
 | 
			
		||||
        and the method will block until the user has clicked the button (or pressed the escape or
 | 
			
		||||
        return keys). If the callback parameter is non-null, the box will be displayed and placed
 | 
			
		||||
        into a modal state, but this method will return immediately, and the callback will be invoked
 | 
			
		||||
        later when the user dismisses the box.
 | 
			
		||||
 | 
			
		||||
        @param iconType     the type of icon to show.
 | 
			
		||||
        @param title        the headline to show at the top of the box.
 | 
			
		||||
        @param message      a longer, more descriptive message to show underneath the title.
 | 
			
		||||
        @param associatedComponent   if this is non-null, it specifies the component that the
 | 
			
		||||
                            alert window should be associated with. Depending on the look
 | 
			
		||||
                            and feel, this might be used for positioning of the alert window.
 | 
			
		||||
        @param callback     if this is non-null, the box will be launched asynchronously,
 | 
			
		||||
                            returning immediately, and the callback will receive a call to its
 | 
			
		||||
                            modalStateFinished() when the box is dismissed, with its parameter
 | 
			
		||||
                            being 1 if the "yes" button was pressed, 2 for the "no" button, or 0
 | 
			
		||||
                            if it was cancelled, The callback object will be owned and deleted by the
 | 
			
		||||
                            system, so make sure that it works safely and doesn't keep any references
 | 
			
		||||
                            to objects that might be deleted before it gets called. You can use the
 | 
			
		||||
                            ModalCallbackFunction to easily pass in a lambda for this parameter.
 | 
			
		||||
 | 
			
		||||
        @returns If the callback parameter has been set, this returns 0. Otherwise, it returns one
 | 
			
		||||
                 of the following values:
 | 
			
		||||
                 - 0 if 'cancel' was pressed
 | 
			
		||||
                 - 1 if 'yes' was pressed
 | 
			
		||||
                 - 2 if 'no' was pressed
 | 
			
		||||
 | 
			
		||||
        @see ModalCallbackFunction
 | 
			
		||||
    */
 | 
			
		||||
    static int JUCE_CALLTYPE showYesNoCancelBox (MessageBoxIconType iconType,
 | 
			
		||||
                                                 const String& title,
 | 
			
		||||
                                                 const String& message,
 | 
			
		||||
                                                #if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
                                                 Component* associatedComponent = nullptr,
 | 
			
		||||
                                                 ModalComponentManager::Callback* callback = nullptr);
 | 
			
		||||
                                                #else
 | 
			
		||||
                                                 Component* associatedComponent,
 | 
			
		||||
                                                 ModalComponentManager::Callback* callback);
 | 
			
		||||
                                                #endif
 | 
			
		||||
 | 
			
		||||
    /** Shows a dialog box with two buttons.
 | 
			
		||||
 | 
			
		||||
        Ideal for yes/no boxes.
 | 
			
		||||
 | 
			
		||||
        The escape key can be used to trigger the no button.
 | 
			
		||||
 | 
			
		||||
        If the callback parameter is null and modal loops are enabled, the box is shown modally,
 | 
			
		||||
        and the method will block until the user has clicked the button (or pressed the escape or
 | 
			
		||||
        return keys). If the callback parameter is non-null, the box will be displayed and placed
 | 
			
		||||
        into a modal state, but this method will return immediately, and the callback will be invoked
 | 
			
		||||
        later when the user dismisses the box.
 | 
			
		||||
 | 
			
		||||
        @param iconType     the type of icon to show.
 | 
			
		||||
        @param title        the headline to show at the top of the box.
 | 
			
		||||
        @param message      a longer, more descriptive message to show underneath the title.
 | 
			
		||||
        @param associatedComponent   if this is non-null, it specifies the component that the
 | 
			
		||||
                            alert window should be associated with. Depending on the look
 | 
			
		||||
                            and feel, this might be used for positioning of the alert window.
 | 
			
		||||
        @param callback     if this is non-null, the box will be launched asynchronously,
 | 
			
		||||
                            returning immediately, and the callback will receive a call to its
 | 
			
		||||
                            modalStateFinished() when the box is dismissed, with its parameter
 | 
			
		||||
                            being 1 if the "yes" button was pressed or 0 for the "no" button was
 | 
			
		||||
                            pressed. The callback object will be owned and deleted by the
 | 
			
		||||
                            system, so make sure that it works safely and doesn't keep any references
 | 
			
		||||
                            to objects that might be deleted before it gets called. You can use the
 | 
			
		||||
                            ModalCallbackFunction to easily pass in a lambda for this parameter.
 | 
			
		||||
 | 
			
		||||
        @returns If the callback parameter has been set, this returns 0. Otherwise, it returns one
 | 
			
		||||
                 of the following values:
 | 
			
		||||
                 - 0 if 'no' was pressed
 | 
			
		||||
                 - 1 if 'yes' was pressed
 | 
			
		||||
 | 
			
		||||
        @see ModalCallbackFunction
 | 
			
		||||
    */
 | 
			
		||||
    static int JUCE_CALLTYPE showYesNoBox (MessageBoxIconType iconType,
 | 
			
		||||
                                           const String& title,
 | 
			
		||||
                                           const String& message,
 | 
			
		||||
                                          #if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
                                           Component* associatedComponent = nullptr,
 | 
			
		||||
                                           ModalComponentManager::Callback* callback = nullptr);
 | 
			
		||||
                                          #else
 | 
			
		||||
                                           Component* associatedComponent,
 | 
			
		||||
                                           ModalComponentManager::Callback* callback);
 | 
			
		||||
                                          #endif
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    NativeMessageBox() = delete;
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE (NativeMessageBox)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - 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 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    This class contains some static methods for showing native alert windows.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class NativeMessageBox
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
   #if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
    /** Shows a dialog box that just has a message and a single 'ok' button to close it.
 | 
			
		||||
 | 
			
		||||
        The box is shown modally, and the method will block until the user has clicked its
 | 
			
		||||
        button (or pressed the escape or return keys).
 | 
			
		||||
 | 
			
		||||
        @param iconType     the type of icon to show.
 | 
			
		||||
        @param title        the headline to show at the top of the box.
 | 
			
		||||
        @param message      a longer, more descriptive message to show underneath the title.
 | 
			
		||||
        @param associatedComponent   if this is non-null, it specifies the component that the
 | 
			
		||||
                            alert window should be associated with. Depending on the look
 | 
			
		||||
                            and feel, this might be used for positioning of the alert window.
 | 
			
		||||
    */
 | 
			
		||||
    static void JUCE_CALLTYPE showMessageBox (MessageBoxIconType iconType,
 | 
			
		||||
                                              const String& title,
 | 
			
		||||
                                              const String& message,
 | 
			
		||||
                                              Component* associatedComponent = nullptr);
 | 
			
		||||
 | 
			
		||||
    /** Shows a dialog box using the specified options.
 | 
			
		||||
 | 
			
		||||
        The box is shown modally, and the method will block until the user dismisses it.
 | 
			
		||||
 | 
			
		||||
        @param options  the options to use when creating the dialog.
 | 
			
		||||
 | 
			
		||||
        @returns  the index of the button that was clicked.
 | 
			
		||||
 | 
			
		||||
        @see MessageBoxOptions
 | 
			
		||||
    */
 | 
			
		||||
    static int JUCE_CALLTYPE show (const MessageBoxOptions& options);
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    /** Shows a dialog box using the specified options.
 | 
			
		||||
 | 
			
		||||
        The box will be displayed and placed into a modal state, but this method will return
 | 
			
		||||
        immediately, and the callback will be invoked later when the user dismisses the box.
 | 
			
		||||
 | 
			
		||||
        @param options   the options to use when creating the dialog.
 | 
			
		||||
        @param callback  if this is non-null, the callback will receive a call to its
 | 
			
		||||
                         modalStateFinished() when the box is dismissed with the index of the
 | 
			
		||||
                         button that was clicked as its argument.
 | 
			
		||||
                         The callback object will be owned and deleted by the system, so make sure
 | 
			
		||||
                         that it works safely and doesn't keep any references to objects that might
 | 
			
		||||
                         be deleted before it gets called.
 | 
			
		||||
 | 
			
		||||
        @see MessageBoxOptions
 | 
			
		||||
    */
 | 
			
		||||
    static void JUCE_CALLTYPE showAsync (const MessageBoxOptions& options,
 | 
			
		||||
                                         ModalComponentManager::Callback* callback);
 | 
			
		||||
 | 
			
		||||
    /** Shows a dialog box using the specified options.
 | 
			
		||||
 | 
			
		||||
        The box will be displayed and placed into a modal state, but this method will return
 | 
			
		||||
        immediately, and the callback will be invoked later when the user dismisses the box.
 | 
			
		||||
 | 
			
		||||
        @param options   the options to use when creating the dialog.
 | 
			
		||||
        @param callback  if this is non-null, the callback will be called when the box is
 | 
			
		||||
                         dismissed with the index of the button that was clicked as its argument.
 | 
			
		||||
 | 
			
		||||
        @see MessageBoxOptions
 | 
			
		||||
    */
 | 
			
		||||
    static void JUCE_CALLTYPE showAsync (const MessageBoxOptions& options,
 | 
			
		||||
                                         std::function<void (int)> callback);
 | 
			
		||||
 | 
			
		||||
    /** Shows a dialog box that just has a message and a single 'ok' button to close it.
 | 
			
		||||
 | 
			
		||||
        The box will be displayed and placed into a modal state, but this method will return
 | 
			
		||||
        immediately, and the callback will be invoked later when the user dismisses the box.
 | 
			
		||||
 | 
			
		||||
        @param iconType     the type of icon to show.
 | 
			
		||||
        @param title        the headline to show at the top of the box.
 | 
			
		||||
        @param message      a longer, more descriptive message to show underneath the title.
 | 
			
		||||
        @param associatedComponent   if this is non-null, it specifies the component that the
 | 
			
		||||
                            alert window should be associated with. Depending on the look
 | 
			
		||||
                            and feel, this might be used for positioning of the alert window.
 | 
			
		||||
        @param callback     if this is non-null, the callback will receive a call to its
 | 
			
		||||
                            modalStateFinished() when the box is dismissed. The callback object
 | 
			
		||||
                            will be owned and deleted by the system, so make sure that it works
 | 
			
		||||
                            safely and doesn't keep any references to objects that might be deleted
 | 
			
		||||
                            before it gets called. You can use the ModalCallbackFunction to easily
 | 
			
		||||
                            pass in a lambda for this parameter.
 | 
			
		||||
 | 
			
		||||
        @see ModalCallbackFunction
 | 
			
		||||
    */
 | 
			
		||||
    static void JUCE_CALLTYPE showMessageBoxAsync (MessageBoxIconType iconType,
 | 
			
		||||
                                                   const String& title,
 | 
			
		||||
                                                   const String& message,
 | 
			
		||||
                                                   Component* associatedComponent = nullptr,
 | 
			
		||||
                                                   ModalComponentManager::Callback* callback = nullptr);
 | 
			
		||||
 | 
			
		||||
    /** Shows a dialog box with two buttons.
 | 
			
		||||
 | 
			
		||||
        Ideal for ok/cancel or yes/no choices. The return key can also be used
 | 
			
		||||
        to trigger the first button, and the escape key for the second button.
 | 
			
		||||
 | 
			
		||||
        If the callback parameter is null and modal loops are enabled, the box is shown modally,
 | 
			
		||||
        and the method will block until the user has clicked the button (or pressed the escape or
 | 
			
		||||
        return keys). If the callback parameter is non-null, the box will be displayed and placed
 | 
			
		||||
        into a modal state, but this method will return immediately, and the callback will be invoked
 | 
			
		||||
        later when the user dismisses the box.
 | 
			
		||||
 | 
			
		||||
        @param iconType     the type of icon to show.
 | 
			
		||||
        @param title        the headline to show at the top of the box.
 | 
			
		||||
        @param message      a longer, more descriptive message to show underneath the title.
 | 
			
		||||
        @param associatedComponent   if this is non-null, it specifies the component that the
 | 
			
		||||
                            alert window should be associated with. Depending on the look
 | 
			
		||||
                            and feel, this might be used for positioning of the alert window.
 | 
			
		||||
        @param callback     if this is non-null, the box will be launched asynchronously,
 | 
			
		||||
                            returning immediately, and the callback will receive a call to its
 | 
			
		||||
                            modalStateFinished() when the box is dismissed, with its parameter
 | 
			
		||||
                            being 1 if the ok button was pressed, or 0 for cancel, The callback object
 | 
			
		||||
                            will be owned and deleted by the system, so make sure that it works
 | 
			
		||||
                            safely and doesn't keep any references to objects that might be deleted
 | 
			
		||||
                            before it gets called. You can use the ModalCallbackFunction to easily
 | 
			
		||||
                            pass in a lambda for this parameter.
 | 
			
		||||
        @returns true if button 1 was clicked, false if it was button 2. If the callback parameter
 | 
			
		||||
                 is not null, the method always returns false, and the user's choice is delivered
 | 
			
		||||
                 later by the callback.
 | 
			
		||||
 | 
			
		||||
        @see ModalCallbackFunction
 | 
			
		||||
    */
 | 
			
		||||
    static bool JUCE_CALLTYPE showOkCancelBox (MessageBoxIconType iconType,
 | 
			
		||||
                                               const String& title,
 | 
			
		||||
                                               const String& message,
 | 
			
		||||
                                              #if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
                                               Component* associatedComponent = nullptr,
 | 
			
		||||
                                               ModalComponentManager::Callback* callback = nullptr);
 | 
			
		||||
                                              #else
 | 
			
		||||
                                               Component* associatedComponent,
 | 
			
		||||
                                               ModalComponentManager::Callback* callback);
 | 
			
		||||
                                              #endif
 | 
			
		||||
 | 
			
		||||
    /** Shows a dialog box with three buttons.
 | 
			
		||||
 | 
			
		||||
        Ideal for yes/no/cancel boxes.
 | 
			
		||||
 | 
			
		||||
        The escape key can be used to trigger the third button.
 | 
			
		||||
 | 
			
		||||
        If the callback parameter is null and modal loops are enabled, the box is shown modally,
 | 
			
		||||
        and the method will block until the user has clicked the button (or pressed the escape or
 | 
			
		||||
        return keys). If the callback parameter is non-null, the box will be displayed and placed
 | 
			
		||||
        into a modal state, but this method will return immediately, and the callback will be invoked
 | 
			
		||||
        later when the user dismisses the box.
 | 
			
		||||
 | 
			
		||||
        @param iconType     the type of icon to show.
 | 
			
		||||
        @param title        the headline to show at the top of the box.
 | 
			
		||||
        @param message      a longer, more descriptive message to show underneath the title.
 | 
			
		||||
        @param associatedComponent   if this is non-null, it specifies the component that the
 | 
			
		||||
                            alert window should be associated with. Depending on the look
 | 
			
		||||
                            and feel, this might be used for positioning of the alert window.
 | 
			
		||||
        @param callback     if this is non-null, the box will be launched asynchronously,
 | 
			
		||||
                            returning immediately, and the callback will receive a call to its
 | 
			
		||||
                            modalStateFinished() when the box is dismissed, with its parameter
 | 
			
		||||
                            being 1 if the "yes" button was pressed, 2 for the "no" button, or 0
 | 
			
		||||
                            if it was cancelled, The callback object will be owned and deleted by the
 | 
			
		||||
                            system, so make sure that it works safely and doesn't keep any references
 | 
			
		||||
                            to objects that might be deleted before it gets called. You can use the
 | 
			
		||||
                            ModalCallbackFunction to easily pass in a lambda for this parameter.
 | 
			
		||||
 | 
			
		||||
        @returns If the callback parameter has been set, this returns 0. Otherwise, it returns one
 | 
			
		||||
                 of the following values:
 | 
			
		||||
                 - 0 if 'cancel' was pressed
 | 
			
		||||
                 - 1 if 'yes' was pressed
 | 
			
		||||
                 - 2 if 'no' was pressed
 | 
			
		||||
 | 
			
		||||
        @see ModalCallbackFunction
 | 
			
		||||
    */
 | 
			
		||||
    static int JUCE_CALLTYPE showYesNoCancelBox (MessageBoxIconType iconType,
 | 
			
		||||
                                                 const String& title,
 | 
			
		||||
                                                 const String& message,
 | 
			
		||||
                                                #if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
                                                 Component* associatedComponent = nullptr,
 | 
			
		||||
                                                 ModalComponentManager::Callback* callback = nullptr);
 | 
			
		||||
                                                #else
 | 
			
		||||
                                                 Component* associatedComponent,
 | 
			
		||||
                                                 ModalComponentManager::Callback* callback);
 | 
			
		||||
                                                #endif
 | 
			
		||||
 | 
			
		||||
    /** Shows a dialog box with two buttons.
 | 
			
		||||
 | 
			
		||||
        Ideal for yes/no boxes.
 | 
			
		||||
 | 
			
		||||
        The escape key can be used to trigger the no button.
 | 
			
		||||
 | 
			
		||||
        If the callback parameter is null and modal loops are enabled, the box is shown modally,
 | 
			
		||||
        and the method will block until the user has clicked the button (or pressed the escape or
 | 
			
		||||
        return keys). If the callback parameter is non-null, the box will be displayed and placed
 | 
			
		||||
        into a modal state, but this method will return immediately, and the callback will be invoked
 | 
			
		||||
        later when the user dismisses the box.
 | 
			
		||||
 | 
			
		||||
        @param iconType     the type of icon to show.
 | 
			
		||||
        @param title        the headline to show at the top of the box.
 | 
			
		||||
        @param message      a longer, more descriptive message to show underneath the title.
 | 
			
		||||
        @param associatedComponent   if this is non-null, it specifies the component that the
 | 
			
		||||
                            alert window should be associated with. Depending on the look
 | 
			
		||||
                            and feel, this might be used for positioning of the alert window.
 | 
			
		||||
        @param callback     if this is non-null, the box will be launched asynchronously,
 | 
			
		||||
                            returning immediately, and the callback will receive a call to its
 | 
			
		||||
                            modalStateFinished() when the box is dismissed, with its parameter
 | 
			
		||||
                            being 1 if the "yes" button was pressed or 0 for the "no" button was
 | 
			
		||||
                            pressed. The callback object will be owned and deleted by the
 | 
			
		||||
                            system, so make sure that it works safely and doesn't keep any references
 | 
			
		||||
                            to objects that might be deleted before it gets called. You can use the
 | 
			
		||||
                            ModalCallbackFunction to easily pass in a lambda for this parameter.
 | 
			
		||||
 | 
			
		||||
        @returns If the callback parameter has been set, this returns 0. Otherwise, it returns one
 | 
			
		||||
                 of the following values:
 | 
			
		||||
                 - 0 if 'no' was pressed
 | 
			
		||||
                 - 1 if 'yes' was pressed
 | 
			
		||||
 | 
			
		||||
        @see ModalCallbackFunction
 | 
			
		||||
    */
 | 
			
		||||
    static int JUCE_CALLTYPE showYesNoBox (MessageBoxIconType iconType,
 | 
			
		||||
                                           const String& title,
 | 
			
		||||
                                           const String& message,
 | 
			
		||||
                                          #if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
                                           Component* associatedComponent = nullptr,
 | 
			
		||||
                                           ModalComponentManager::Callback* callback = nullptr);
 | 
			
		||||
                                          #else
 | 
			
		||||
                                           Component* associatedComponent,
 | 
			
		||||
                                           ModalComponentManager::Callback* callback);
 | 
			
		||||
                                          #endif
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    NativeMessageBox() = delete;
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE (NativeMessageBox)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,413 +1,413 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A base class for top-level windows that can be dragged around and resized.
 | 
			
		||||
 | 
			
		||||
    To add content to the window, use its setContentOwned() or setContentNonOwned() methods
 | 
			
		||||
    to give it a component that will remain positioned inside it (leaving a gap around
 | 
			
		||||
    the edges for a border).
 | 
			
		||||
 | 
			
		||||
    It's not advisable to add child components directly to a ResizableWindow: put them
 | 
			
		||||
    inside your content component instead. And overriding methods like resized(), moved(), etc
 | 
			
		||||
    is also not recommended - instead override these methods for your content component.
 | 
			
		||||
    (If for some obscure reason you do need to override these methods, always remember to
 | 
			
		||||
    call the super-class's resized() method too, otherwise it'll fail to lay out the window
 | 
			
		||||
    decorations correctly).
 | 
			
		||||
 | 
			
		||||
    By default resizing isn't enabled - use the setResizable() method to enable it and
 | 
			
		||||
    to choose the style of resizing to use.
 | 
			
		||||
 | 
			
		||||
    @see TopLevelWindow
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  ResizableWindow  : public TopLevelWindow
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a ResizableWindow.
 | 
			
		||||
 | 
			
		||||
        This constructor doesn't specify a background colour, so the LookAndFeel's default
 | 
			
		||||
        background colour will be used.
 | 
			
		||||
 | 
			
		||||
        @param name                 the name to give the component
 | 
			
		||||
        @param addToDesktop         if true, the window will be automatically added to the
 | 
			
		||||
                                    desktop; if false, you can use it as a child component
 | 
			
		||||
    */
 | 
			
		||||
    ResizableWindow (const String& name,
 | 
			
		||||
                     bool addToDesktop);
 | 
			
		||||
 | 
			
		||||
    /** Creates a ResizableWindow.
 | 
			
		||||
 | 
			
		||||
        @param name                 the name to give the component
 | 
			
		||||
        @param backgroundColour     the colour to use for filling the window's background.
 | 
			
		||||
        @param addToDesktop         if true, the window will be automatically added to the
 | 
			
		||||
                                    desktop; if false, you can use it as a child component
 | 
			
		||||
    */
 | 
			
		||||
    ResizableWindow (const String& name,
 | 
			
		||||
                     Colour backgroundColour,
 | 
			
		||||
                     bool addToDesktop);
 | 
			
		||||
 | 
			
		||||
    /** Destructor.
 | 
			
		||||
        If a content component has been set with setContentOwned(), it will be deleted.
 | 
			
		||||
    */
 | 
			
		||||
    ~ResizableWindow() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the colour currently being used for the window's background.
 | 
			
		||||
 | 
			
		||||
        As a convenience the window will fill itself with this colour, but you
 | 
			
		||||
        can override the paint() method if you need more customised behaviour.
 | 
			
		||||
 | 
			
		||||
        This method is the same as retrieving the colour for ResizableWindow::backgroundColourId.
 | 
			
		||||
 | 
			
		||||
        @see setBackgroundColour
 | 
			
		||||
    */
 | 
			
		||||
    Colour getBackgroundColour() const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Changes the colour currently being used for the window's background.
 | 
			
		||||
 | 
			
		||||
        As a convenience the window will fill itself with this colour, but you
 | 
			
		||||
        can override the paint() method if you need more customised behaviour.
 | 
			
		||||
 | 
			
		||||
        Note that the opaque state of this window is altered by this call to reflect
 | 
			
		||||
        the opacity of the colour passed-in. On window systems which can't support
 | 
			
		||||
        semi-transparent windows this might cause problems, (though it's unlikely you'll
 | 
			
		||||
        be using this class as a base for a semi-transparent component anyway).
 | 
			
		||||
 | 
			
		||||
        You can also use the ResizableWindow::backgroundColourId colour id to set
 | 
			
		||||
        this colour.
 | 
			
		||||
 | 
			
		||||
        @see getBackgroundColour
 | 
			
		||||
    */
 | 
			
		||||
    void setBackgroundColour (Colour newColour);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Make the window resizable or fixed.
 | 
			
		||||
 | 
			
		||||
        @param shouldBeResizable            whether it's resizable at all
 | 
			
		||||
        @param useBottomRightCornerResizer  if true, it'll add a ResizableCornerComponent at the
 | 
			
		||||
                                            bottom-right; if false, it'll use a ResizableBorderComponent
 | 
			
		||||
                                            around the edge
 | 
			
		||||
        @see setResizeLimits, isResizable
 | 
			
		||||
    */
 | 
			
		||||
    void setResizable (bool shouldBeResizable,
 | 
			
		||||
                       bool useBottomRightCornerResizer);
 | 
			
		||||
 | 
			
		||||
    /** Returns true if resizing is enabled.
 | 
			
		||||
        @see setResizable
 | 
			
		||||
    */
 | 
			
		||||
    bool isResizable() const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** This sets the maximum and minimum sizes for the window.
 | 
			
		||||
 | 
			
		||||
        If the window's current size is outside these limits, it will be resized to
 | 
			
		||||
        make sure it's within them.
 | 
			
		||||
 | 
			
		||||
        A direct call to setBounds() will bypass any constraint checks, but when the
 | 
			
		||||
        window is dragged by the user or resized by other indirect means, the constrainer
 | 
			
		||||
        will limit the numbers involved.
 | 
			
		||||
 | 
			
		||||
        @see setResizable, setFixedAspectRatio
 | 
			
		||||
    */
 | 
			
		||||
    void setResizeLimits (int newMinimumWidth,
 | 
			
		||||
                          int newMinimumHeight,
 | 
			
		||||
                          int newMaximumWidth,
 | 
			
		||||
                          int newMaximumHeight) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Can be used to enable or disable user-dragging of the window. */
 | 
			
		||||
    void setDraggable (bool shouldBeDraggable) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the window can be dragged around by the user. */
 | 
			
		||||
    bool isDraggable() const noexcept                               { return canDrag; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the bounds constrainer object that this window is using.
 | 
			
		||||
        You can access this to change its properties.
 | 
			
		||||
    */
 | 
			
		||||
    ComponentBoundsConstrainer* getConstrainer() noexcept           { return constrainer; }
 | 
			
		||||
 | 
			
		||||
    /** Sets the bounds-constrainer object to use for resizing and dragging this window.
 | 
			
		||||
 | 
			
		||||
        A pointer to the object you pass in will be kept, but it won't be deleted
 | 
			
		||||
        by this object, so it's the caller's responsibility to manage it.
 | 
			
		||||
 | 
			
		||||
        If you pass a nullptr, then no constraints will be placed on the positioning of the window.
 | 
			
		||||
    */
 | 
			
		||||
    void setConstrainer (ComponentBoundsConstrainer* newConstrainer);
 | 
			
		||||
 | 
			
		||||
    /** Calls the window's setBounds method, after first checking these bounds
 | 
			
		||||
        with the current constrainer.
 | 
			
		||||
        @see setConstrainer
 | 
			
		||||
    */
 | 
			
		||||
    void setBoundsConstrained (const Rectangle<int>& newBounds);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns true if the window is currently in full-screen mode.
 | 
			
		||||
        @see setFullScreen
 | 
			
		||||
    */
 | 
			
		||||
    bool isFullScreen() const;
 | 
			
		||||
 | 
			
		||||
    /** Puts the window into full-screen mode, or restores it to its normal size.
 | 
			
		||||
 | 
			
		||||
        If true, the window will become full-screen; if false, it will return to the
 | 
			
		||||
        last size it was before being made full-screen.
 | 
			
		||||
 | 
			
		||||
        @see isFullScreen
 | 
			
		||||
    */
 | 
			
		||||
    void setFullScreen (bool shouldBeFullScreen);
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the window is currently minimised.
 | 
			
		||||
        @see setMinimised
 | 
			
		||||
    */
 | 
			
		||||
    bool isMinimised() const;
 | 
			
		||||
 | 
			
		||||
    /** Minimises the window, or restores it to its previous position and size.
 | 
			
		||||
 | 
			
		||||
        When being un-minimised, it'll return to the last position and size it
 | 
			
		||||
        was in before being minimised.
 | 
			
		||||
 | 
			
		||||
        @see isMinimised
 | 
			
		||||
    */
 | 
			
		||||
    void setMinimised (bool shouldMinimise);
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the window has been placed in kiosk-mode.
 | 
			
		||||
        @see Desktop::setKioskComponent
 | 
			
		||||
    */
 | 
			
		||||
    bool isKioskMode() const;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns a string which encodes the window's current size and position.
 | 
			
		||||
 | 
			
		||||
        This string will encapsulate the window's size, position, and whether it's
 | 
			
		||||
        in full-screen mode. It's intended for letting your application save and
 | 
			
		||||
        restore a window's position.
 | 
			
		||||
 | 
			
		||||
        Use the restoreWindowStateFromString() to restore from a saved state.
 | 
			
		||||
 | 
			
		||||
        @see restoreWindowStateFromString
 | 
			
		||||
    */
 | 
			
		||||
    String getWindowStateAsString();
 | 
			
		||||
 | 
			
		||||
    /** Restores the window to a previously-saved size and position.
 | 
			
		||||
 | 
			
		||||
        This restores the window's size, position and full-screen status from an
 | 
			
		||||
        string that was previously created with the getWindowStateAsString()
 | 
			
		||||
        method.
 | 
			
		||||
 | 
			
		||||
        @returns false if the string wasn't a valid window state
 | 
			
		||||
        @see getWindowStateAsString
 | 
			
		||||
    */
 | 
			
		||||
    bool restoreWindowStateFromString (const String& previousState);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the current content component.
 | 
			
		||||
 | 
			
		||||
        This will be the component set by setContentOwned() or setContentNonOwned, or
 | 
			
		||||
        nullptr if none has yet been specified.
 | 
			
		||||
 | 
			
		||||
        @see setContentOwned, setContentNonOwned
 | 
			
		||||
    */
 | 
			
		||||
    Component* getContentComponent() const noexcept                 { return contentComponent; }
 | 
			
		||||
 | 
			
		||||
    /** Changes the current content component.
 | 
			
		||||
 | 
			
		||||
        This sets a component that will be placed in the centre of the ResizableWindow,
 | 
			
		||||
        (leaving a space around the edge for the border).
 | 
			
		||||
 | 
			
		||||
        You should never add components directly to a ResizableWindow (or any of its subclasses)
 | 
			
		||||
        with addChildComponent(). Instead, add them to the content component.
 | 
			
		||||
 | 
			
		||||
        @param newContentComponent  the new component to use - this component will be deleted when it's
 | 
			
		||||
                                    no longer needed (i.e. when the window is deleted or a new content
 | 
			
		||||
                                    component is set for it). To set a component that this window will not
 | 
			
		||||
                                    delete, call setContentNonOwned() instead.
 | 
			
		||||
        @param resizeToFitWhenContentChangesSize  if true, then the ResizableWindow will maintain its size
 | 
			
		||||
                                    such that it always fits around the size of the content component. If false,
 | 
			
		||||
                                    the new content will be resized to fit the current space available.
 | 
			
		||||
    */
 | 
			
		||||
    void setContentOwned (Component* newContentComponent,
 | 
			
		||||
                          bool resizeToFitWhenContentChangesSize);
 | 
			
		||||
 | 
			
		||||
    /** Changes the current content component.
 | 
			
		||||
 | 
			
		||||
        This sets a component that will be placed in the centre of the ResizableWindow,
 | 
			
		||||
        (leaving a space around the edge for the border).
 | 
			
		||||
 | 
			
		||||
        You should never add components directly to a ResizableWindow (or any of its subclasses)
 | 
			
		||||
        with addChildComponent(). Instead, add them to the content component.
 | 
			
		||||
 | 
			
		||||
        @param newContentComponent  the new component to use - this component will NOT be deleted by this
 | 
			
		||||
                                    component, so it's the caller's responsibility to manage its lifetime (it's
 | 
			
		||||
                                    ok to delete it while this window is still using it). To set a content
 | 
			
		||||
                                    component that the window will delete, call setContentOwned() instead.
 | 
			
		||||
        @param resizeToFitWhenContentChangesSize  if true, then the ResizableWindow will maintain its size
 | 
			
		||||
                                    such that it always fits around the size of the content component. If false,
 | 
			
		||||
                                    the new content will be resized to fit the current space available.
 | 
			
		||||
    */
 | 
			
		||||
    void setContentNonOwned (Component* newContentComponent,
 | 
			
		||||
                             bool resizeToFitWhenContentChangesSize);
 | 
			
		||||
 | 
			
		||||
    /** Removes the current content component.
 | 
			
		||||
        If the previous content component was added with setContentOwned(), it will also be deleted. If
 | 
			
		||||
        it was added with setContentNonOwned(), it will simply be removed from this component.
 | 
			
		||||
    */
 | 
			
		||||
    void clearContentComponent();
 | 
			
		||||
 | 
			
		||||
    /** Changes the window so that the content component ends up with the specified size.
 | 
			
		||||
 | 
			
		||||
        This is basically a setSize call on the window, but which adds on the borders,
 | 
			
		||||
        so you can specify the content component's target size.
 | 
			
		||||
    */
 | 
			
		||||
    void setContentComponentSize (int width, int height);
 | 
			
		||||
 | 
			
		||||
    /** Returns the width of the frame to use around the window.
 | 
			
		||||
        @see getContentComponentBorder
 | 
			
		||||
    */
 | 
			
		||||
    virtual BorderSize<int> getBorderThickness();
 | 
			
		||||
 | 
			
		||||
    /** Returns the insets to use when positioning the content component.
 | 
			
		||||
        @see getBorderThickness
 | 
			
		||||
    */
 | 
			
		||||
    virtual BorderSize<int> getContentComponentBorder();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** A set of colour IDs to use to change the colour of various aspects of the window.
 | 
			
		||||
 | 
			
		||||
        These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
 | 
			
		||||
        methods.
 | 
			
		||||
 | 
			
		||||
        @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
 | 
			
		||||
    */
 | 
			
		||||
    enum ColourIds
 | 
			
		||||
    {
 | 
			
		||||
        backgroundColourId          = 0x1005700,  /**< A colour to use to fill the window's background. */
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
   #ifndef DOXYGEN
 | 
			
		||||
    [[deprecated ("use setContentOwned and setContentNonOwned instead.")]]
 | 
			
		||||
    void setContentComponent (Component* newContentComponent,
 | 
			
		||||
                              bool deleteOldOne = true,
 | 
			
		||||
                              bool resizeToFit = false);
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    using TopLevelWindow::addToDesktop;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This abstract base class is implemented by LookAndFeel classes to provide
 | 
			
		||||
        window drawing functionality.
 | 
			
		||||
    */
 | 
			
		||||
    struct JUCE_API  LookAndFeelMethods
 | 
			
		||||
    {
 | 
			
		||||
        virtual ~LookAndFeelMethods() = default;
 | 
			
		||||
 | 
			
		||||
        //==============================================================================
 | 
			
		||||
        virtual void drawCornerResizer (Graphics&, int w, int h, bool isMouseOver, bool isMouseDragging) = 0;
 | 
			
		||||
        virtual void drawResizableFrame (Graphics&, int w, int h, const BorderSize<int>&) = 0;
 | 
			
		||||
 | 
			
		||||
        virtual void fillResizableWindowBackground (Graphics&, int w, int h, const BorderSize<int>&, ResizableWindow&) = 0;
 | 
			
		||||
        virtual void drawResizableWindowBorder (Graphics&, int w, int h, const BorderSize<int>& border, ResizableWindow&) = 0;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
    /** (if overriding this, make sure you call ResizableWindow::moved() in your subclass) */
 | 
			
		||||
    void moved() override;
 | 
			
		||||
    /** (if overriding this, make sure you call ResizableWindow::resized() in your subclass) */
 | 
			
		||||
    void resized() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void mouseDown (const MouseEvent&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void mouseDrag (const MouseEvent&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void mouseUp (const MouseEvent&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void lookAndFeelChanged() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void childBoundsChanged (Component*) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void parentSizeChanged() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void visibilityChanged() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void activeWindowStatusChanged() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    int getDesktopWindowStyleFlags() const override;
 | 
			
		||||
 | 
			
		||||
   #if JUCE_DEBUG
 | 
			
		||||
    /** Overridden to warn people about adding components directly to this component
 | 
			
		||||
        instead of using setContentOwned().
 | 
			
		||||
 | 
			
		||||
        If you know what you're doing and are sure you really want to add a component, specify
 | 
			
		||||
        a base-class method call to Component::addAndMakeVisible(), to side-step this warning.
 | 
			
		||||
    */
 | 
			
		||||
    void addChildComponent (Component*, int zOrder = -1);
 | 
			
		||||
    /** Overridden to warn people about adding components directly to this component
 | 
			
		||||
        instead of using setContentOwned().
 | 
			
		||||
 | 
			
		||||
        If you know what you're doing and are sure you really want to add a component, specify
 | 
			
		||||
        a base-class method call to Component::addAndMakeVisible(), to side-step this warning.
 | 
			
		||||
    */
 | 
			
		||||
    void addAndMakeVisible (Component*, int zOrder = -1);
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<ResizableCornerComponent> resizableCorner;
 | 
			
		||||
    std::unique_ptr<ResizableBorderComponent> resizableBorder;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    // The parameters for these methods have changed - please update your code!
 | 
			
		||||
    void getBorderThickness (int& left, int& top, int& right, int& bottom);
 | 
			
		||||
    void getContentComponentBorder (int& left, int& top, int& right, int& bottom);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    Component::SafePointer<Component> contentComponent, splashScreen;
 | 
			
		||||
    bool ownsContentComponent = false, resizeToFitContent = false, fullscreen = false, canDrag = true, dragStarted = false;
 | 
			
		||||
    ComponentDragger dragger;
 | 
			
		||||
    Rectangle<int> lastNonFullScreenPos;
 | 
			
		||||
    ComponentBoundsConstrainer defaultConstrainer;
 | 
			
		||||
    ComponentBoundsConstrainer* constrainer = nullptr;
 | 
			
		||||
   #if JUCE_DEBUG
 | 
			
		||||
    bool hasBeenResized = false;
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    void initialise (bool addToDesktop);
 | 
			
		||||
    void updateLastPosIfNotFullScreen();
 | 
			
		||||
    void updateLastPosIfShowing();
 | 
			
		||||
    void setContent (Component*, bool takeOwnership, bool resizeToFit);
 | 
			
		||||
    void updatePeerConstrainer();
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ResizableWindow)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - 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 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A base class for top-level windows that can be dragged around and resized.
 | 
			
		||||
 | 
			
		||||
    To add content to the window, use its setContentOwned() or setContentNonOwned() methods
 | 
			
		||||
    to give it a component that will remain positioned inside it (leaving a gap around
 | 
			
		||||
    the edges for a border).
 | 
			
		||||
 | 
			
		||||
    It's not advisable to add child components directly to a ResizableWindow: put them
 | 
			
		||||
    inside your content component instead. And overriding methods like resized(), moved(), etc
 | 
			
		||||
    is also not recommended - instead override these methods for your content component.
 | 
			
		||||
    (If for some obscure reason you do need to override these methods, always remember to
 | 
			
		||||
    call the super-class's resized() method too, otherwise it'll fail to lay out the window
 | 
			
		||||
    decorations correctly).
 | 
			
		||||
 | 
			
		||||
    By default resizing isn't enabled - use the setResizable() method to enable it and
 | 
			
		||||
    to choose the style of resizing to use.
 | 
			
		||||
 | 
			
		||||
    @see TopLevelWindow
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  ResizableWindow  : public TopLevelWindow
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a ResizableWindow.
 | 
			
		||||
 | 
			
		||||
        This constructor doesn't specify a background colour, so the LookAndFeel's default
 | 
			
		||||
        background colour will be used.
 | 
			
		||||
 | 
			
		||||
        @param name                 the name to give the component
 | 
			
		||||
        @param addToDesktop         if true, the window will be automatically added to the
 | 
			
		||||
                                    desktop; if false, you can use it as a child component
 | 
			
		||||
    */
 | 
			
		||||
    ResizableWindow (const String& name,
 | 
			
		||||
                     bool addToDesktop);
 | 
			
		||||
 | 
			
		||||
    /** Creates a ResizableWindow.
 | 
			
		||||
 | 
			
		||||
        @param name                 the name to give the component
 | 
			
		||||
        @param backgroundColour     the colour to use for filling the window's background.
 | 
			
		||||
        @param addToDesktop         if true, the window will be automatically added to the
 | 
			
		||||
                                    desktop; if false, you can use it as a child component
 | 
			
		||||
    */
 | 
			
		||||
    ResizableWindow (const String& name,
 | 
			
		||||
                     Colour backgroundColour,
 | 
			
		||||
                     bool addToDesktop);
 | 
			
		||||
 | 
			
		||||
    /** Destructor.
 | 
			
		||||
        If a content component has been set with setContentOwned(), it will be deleted.
 | 
			
		||||
    */
 | 
			
		||||
    ~ResizableWindow() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the colour currently being used for the window's background.
 | 
			
		||||
 | 
			
		||||
        As a convenience the window will fill itself with this colour, but you
 | 
			
		||||
        can override the paint() method if you need more customised behaviour.
 | 
			
		||||
 | 
			
		||||
        This method is the same as retrieving the colour for ResizableWindow::backgroundColourId.
 | 
			
		||||
 | 
			
		||||
        @see setBackgroundColour
 | 
			
		||||
    */
 | 
			
		||||
    Colour getBackgroundColour() const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Changes the colour currently being used for the window's background.
 | 
			
		||||
 | 
			
		||||
        As a convenience the window will fill itself with this colour, but you
 | 
			
		||||
        can override the paint() method if you need more customised behaviour.
 | 
			
		||||
 | 
			
		||||
        Note that the opaque state of this window is altered by this call to reflect
 | 
			
		||||
        the opacity of the colour passed-in. On window systems which can't support
 | 
			
		||||
        semi-transparent windows this might cause problems, (though it's unlikely you'll
 | 
			
		||||
        be using this class as a base for a semi-transparent component anyway).
 | 
			
		||||
 | 
			
		||||
        You can also use the ResizableWindow::backgroundColourId colour id to set
 | 
			
		||||
        this colour.
 | 
			
		||||
 | 
			
		||||
        @see getBackgroundColour
 | 
			
		||||
    */
 | 
			
		||||
    void setBackgroundColour (Colour newColour);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Make the window resizable or fixed.
 | 
			
		||||
 | 
			
		||||
        @param shouldBeResizable            whether it's resizable at all
 | 
			
		||||
        @param useBottomRightCornerResizer  if true, it'll add a ResizableCornerComponent at the
 | 
			
		||||
                                            bottom-right; if false, it'll use a ResizableBorderComponent
 | 
			
		||||
                                            around the edge
 | 
			
		||||
        @see setResizeLimits, isResizable
 | 
			
		||||
    */
 | 
			
		||||
    void setResizable (bool shouldBeResizable,
 | 
			
		||||
                       bool useBottomRightCornerResizer);
 | 
			
		||||
 | 
			
		||||
    /** Returns true if resizing is enabled.
 | 
			
		||||
        @see setResizable
 | 
			
		||||
    */
 | 
			
		||||
    bool isResizable() const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** This sets the maximum and minimum sizes for the window.
 | 
			
		||||
 | 
			
		||||
        If the window's current size is outside these limits, it will be resized to
 | 
			
		||||
        make sure it's within them.
 | 
			
		||||
 | 
			
		||||
        A direct call to setBounds() will bypass any constraint checks, but when the
 | 
			
		||||
        window is dragged by the user or resized by other indirect means, the constrainer
 | 
			
		||||
        will limit the numbers involved.
 | 
			
		||||
 | 
			
		||||
        @see setResizable, setFixedAspectRatio
 | 
			
		||||
    */
 | 
			
		||||
    void setResizeLimits (int newMinimumWidth,
 | 
			
		||||
                          int newMinimumHeight,
 | 
			
		||||
                          int newMaximumWidth,
 | 
			
		||||
                          int newMaximumHeight) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Can be used to enable or disable user-dragging of the window. */
 | 
			
		||||
    void setDraggable (bool shouldBeDraggable) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the window can be dragged around by the user. */
 | 
			
		||||
    bool isDraggable() const noexcept                               { return canDrag; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the bounds constrainer object that this window is using.
 | 
			
		||||
        You can access this to change its properties.
 | 
			
		||||
    */
 | 
			
		||||
    ComponentBoundsConstrainer* getConstrainer() noexcept           { return constrainer; }
 | 
			
		||||
 | 
			
		||||
    /** Sets the bounds-constrainer object to use for resizing and dragging this window.
 | 
			
		||||
 | 
			
		||||
        A pointer to the object you pass in will be kept, but it won't be deleted
 | 
			
		||||
        by this object, so it's the caller's responsibility to manage it.
 | 
			
		||||
 | 
			
		||||
        If you pass a nullptr, then no constraints will be placed on the positioning of the window.
 | 
			
		||||
    */
 | 
			
		||||
    void setConstrainer (ComponentBoundsConstrainer* newConstrainer);
 | 
			
		||||
 | 
			
		||||
    /** Calls the window's setBounds method, after first checking these bounds
 | 
			
		||||
        with the current constrainer.
 | 
			
		||||
        @see setConstrainer
 | 
			
		||||
    */
 | 
			
		||||
    void setBoundsConstrained (const Rectangle<int>& newBounds);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns true if the window is currently in full-screen mode.
 | 
			
		||||
        @see setFullScreen
 | 
			
		||||
    */
 | 
			
		||||
    bool isFullScreen() const;
 | 
			
		||||
 | 
			
		||||
    /** Puts the window into full-screen mode, or restores it to its normal size.
 | 
			
		||||
 | 
			
		||||
        If true, the window will become full-screen; if false, it will return to the
 | 
			
		||||
        last size it was before being made full-screen.
 | 
			
		||||
 | 
			
		||||
        @see isFullScreen
 | 
			
		||||
    */
 | 
			
		||||
    void setFullScreen (bool shouldBeFullScreen);
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the window is currently minimised.
 | 
			
		||||
        @see setMinimised
 | 
			
		||||
    */
 | 
			
		||||
    bool isMinimised() const;
 | 
			
		||||
 | 
			
		||||
    /** Minimises the window, or restores it to its previous position and size.
 | 
			
		||||
 | 
			
		||||
        When being un-minimised, it'll return to the last position and size it
 | 
			
		||||
        was in before being minimised.
 | 
			
		||||
 | 
			
		||||
        @see isMinimised
 | 
			
		||||
    */
 | 
			
		||||
    void setMinimised (bool shouldMinimise);
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the window has been placed in kiosk-mode.
 | 
			
		||||
        @see Desktop::setKioskComponent
 | 
			
		||||
    */
 | 
			
		||||
    bool isKioskMode() const;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns a string which encodes the window's current size and position.
 | 
			
		||||
 | 
			
		||||
        This string will encapsulate the window's size, position, and whether it's
 | 
			
		||||
        in full-screen mode. It's intended for letting your application save and
 | 
			
		||||
        restore a window's position.
 | 
			
		||||
 | 
			
		||||
        Use the restoreWindowStateFromString() to restore from a saved state.
 | 
			
		||||
 | 
			
		||||
        @see restoreWindowStateFromString
 | 
			
		||||
    */
 | 
			
		||||
    String getWindowStateAsString();
 | 
			
		||||
 | 
			
		||||
    /** Restores the window to a previously-saved size and position.
 | 
			
		||||
 | 
			
		||||
        This restores the window's size, position and full-screen status from an
 | 
			
		||||
        string that was previously created with the getWindowStateAsString()
 | 
			
		||||
        method.
 | 
			
		||||
 | 
			
		||||
        @returns false if the string wasn't a valid window state
 | 
			
		||||
        @see getWindowStateAsString
 | 
			
		||||
    */
 | 
			
		||||
    bool restoreWindowStateFromString (const String& previousState);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the current content component.
 | 
			
		||||
 | 
			
		||||
        This will be the component set by setContentOwned() or setContentNonOwned, or
 | 
			
		||||
        nullptr if none has yet been specified.
 | 
			
		||||
 | 
			
		||||
        @see setContentOwned, setContentNonOwned
 | 
			
		||||
    */
 | 
			
		||||
    Component* getContentComponent() const noexcept                 { return contentComponent; }
 | 
			
		||||
 | 
			
		||||
    /** Changes the current content component.
 | 
			
		||||
 | 
			
		||||
        This sets a component that will be placed in the centre of the ResizableWindow,
 | 
			
		||||
        (leaving a space around the edge for the border).
 | 
			
		||||
 | 
			
		||||
        You should never add components directly to a ResizableWindow (or any of its subclasses)
 | 
			
		||||
        with addChildComponent(). Instead, add them to the content component.
 | 
			
		||||
 | 
			
		||||
        @param newContentComponent  the new component to use - this component will be deleted when it's
 | 
			
		||||
                                    no longer needed (i.e. when the window is deleted or a new content
 | 
			
		||||
                                    component is set for it). To set a component that this window will not
 | 
			
		||||
                                    delete, call setContentNonOwned() instead.
 | 
			
		||||
        @param resizeToFitWhenContentChangesSize  if true, then the ResizableWindow will maintain its size
 | 
			
		||||
                                    such that it always fits around the size of the content component. If false,
 | 
			
		||||
                                    the new content will be resized to fit the current space available.
 | 
			
		||||
    */
 | 
			
		||||
    void setContentOwned (Component* newContentComponent,
 | 
			
		||||
                          bool resizeToFitWhenContentChangesSize);
 | 
			
		||||
 | 
			
		||||
    /** Changes the current content component.
 | 
			
		||||
 | 
			
		||||
        This sets a component that will be placed in the centre of the ResizableWindow,
 | 
			
		||||
        (leaving a space around the edge for the border).
 | 
			
		||||
 | 
			
		||||
        You should never add components directly to a ResizableWindow (or any of its subclasses)
 | 
			
		||||
        with addChildComponent(). Instead, add them to the content component.
 | 
			
		||||
 | 
			
		||||
        @param newContentComponent  the new component to use - this component will NOT be deleted by this
 | 
			
		||||
                                    component, so it's the caller's responsibility to manage its lifetime (it's
 | 
			
		||||
                                    ok to delete it while this window is still using it). To set a content
 | 
			
		||||
                                    component that the window will delete, call setContentOwned() instead.
 | 
			
		||||
        @param resizeToFitWhenContentChangesSize  if true, then the ResizableWindow will maintain its size
 | 
			
		||||
                                    such that it always fits around the size of the content component. If false,
 | 
			
		||||
                                    the new content will be resized to fit the current space available.
 | 
			
		||||
    */
 | 
			
		||||
    void setContentNonOwned (Component* newContentComponent,
 | 
			
		||||
                             bool resizeToFitWhenContentChangesSize);
 | 
			
		||||
 | 
			
		||||
    /** Removes the current content component.
 | 
			
		||||
        If the previous content component was added with setContentOwned(), it will also be deleted. If
 | 
			
		||||
        it was added with setContentNonOwned(), it will simply be removed from this component.
 | 
			
		||||
    */
 | 
			
		||||
    void clearContentComponent();
 | 
			
		||||
 | 
			
		||||
    /** Changes the window so that the content component ends up with the specified size.
 | 
			
		||||
 | 
			
		||||
        This is basically a setSize call on the window, but which adds on the borders,
 | 
			
		||||
        so you can specify the content component's target size.
 | 
			
		||||
    */
 | 
			
		||||
    void setContentComponentSize (int width, int height);
 | 
			
		||||
 | 
			
		||||
    /** Returns the width of the frame to use around the window.
 | 
			
		||||
        @see getContentComponentBorder
 | 
			
		||||
    */
 | 
			
		||||
    virtual BorderSize<int> getBorderThickness();
 | 
			
		||||
 | 
			
		||||
    /** Returns the insets to use when positioning the content component.
 | 
			
		||||
        @see getBorderThickness
 | 
			
		||||
    */
 | 
			
		||||
    virtual BorderSize<int> getContentComponentBorder();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** A set of colour IDs to use to change the colour of various aspects of the window.
 | 
			
		||||
 | 
			
		||||
        These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
 | 
			
		||||
        methods.
 | 
			
		||||
 | 
			
		||||
        @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
 | 
			
		||||
    */
 | 
			
		||||
    enum ColourIds
 | 
			
		||||
    {
 | 
			
		||||
        backgroundColourId          = 0x1005700,  /**< A colour to use to fill the window's background. */
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
   #ifndef DOXYGEN
 | 
			
		||||
    [[deprecated ("use setContentOwned and setContentNonOwned instead.")]]
 | 
			
		||||
    void setContentComponent (Component* newContentComponent,
 | 
			
		||||
                              bool deleteOldOne = true,
 | 
			
		||||
                              bool resizeToFit = false);
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    using TopLevelWindow::addToDesktop;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This abstract base class is implemented by LookAndFeel classes to provide
 | 
			
		||||
        window drawing functionality.
 | 
			
		||||
    */
 | 
			
		||||
    struct JUCE_API  LookAndFeelMethods
 | 
			
		||||
    {
 | 
			
		||||
        virtual ~LookAndFeelMethods() = default;
 | 
			
		||||
 | 
			
		||||
        //==============================================================================
 | 
			
		||||
        virtual void drawCornerResizer (Graphics&, int w, int h, bool isMouseOver, bool isMouseDragging) = 0;
 | 
			
		||||
        virtual void drawResizableFrame (Graphics&, int w, int h, const BorderSize<int>&) = 0;
 | 
			
		||||
 | 
			
		||||
        virtual void fillResizableWindowBackground (Graphics&, int w, int h, const BorderSize<int>&, ResizableWindow&) = 0;
 | 
			
		||||
        virtual void drawResizableWindowBorder (Graphics&, int w, int h, const BorderSize<int>& border, ResizableWindow&) = 0;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
    /** (if overriding this, make sure you call ResizableWindow::moved() in your subclass) */
 | 
			
		||||
    void moved() override;
 | 
			
		||||
    /** (if overriding this, make sure you call ResizableWindow::resized() in your subclass) */
 | 
			
		||||
    void resized() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void mouseDown (const MouseEvent&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void mouseDrag (const MouseEvent&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void mouseUp (const MouseEvent&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void lookAndFeelChanged() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void childBoundsChanged (Component*) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void parentSizeChanged() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void visibilityChanged() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void activeWindowStatusChanged() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    int getDesktopWindowStyleFlags() const override;
 | 
			
		||||
 | 
			
		||||
   #if JUCE_DEBUG
 | 
			
		||||
    /** Overridden to warn people about adding components directly to this component
 | 
			
		||||
        instead of using setContentOwned().
 | 
			
		||||
 | 
			
		||||
        If you know what you're doing and are sure you really want to add a component, specify
 | 
			
		||||
        a base-class method call to Component::addAndMakeVisible(), to side-step this warning.
 | 
			
		||||
    */
 | 
			
		||||
    void addChildComponent (Component*, int zOrder = -1);
 | 
			
		||||
    /** Overridden to warn people about adding components directly to this component
 | 
			
		||||
        instead of using setContentOwned().
 | 
			
		||||
 | 
			
		||||
        If you know what you're doing and are sure you really want to add a component, specify
 | 
			
		||||
        a base-class method call to Component::addAndMakeVisible(), to side-step this warning.
 | 
			
		||||
    */
 | 
			
		||||
    void addAndMakeVisible (Component*, int zOrder = -1);
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<ResizableCornerComponent> resizableCorner;
 | 
			
		||||
    std::unique_ptr<ResizableBorderComponent> resizableBorder;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    // The parameters for these methods have changed - please update your code!
 | 
			
		||||
    void getBorderThickness (int& left, int& top, int& right, int& bottom);
 | 
			
		||||
    void getContentComponentBorder (int& left, int& top, int& right, int& bottom);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    Component::SafePointer<Component> contentComponent, splashScreen;
 | 
			
		||||
    bool ownsContentComponent = false, resizeToFitContent = false, fullscreen = false, canDrag = true, dragStarted = false;
 | 
			
		||||
    ComponentDragger dragger;
 | 
			
		||||
    Rectangle<int> lastNonFullScreenPos;
 | 
			
		||||
    ComponentBoundsConstrainer defaultConstrainer;
 | 
			
		||||
    ComponentBoundsConstrainer* constrainer = nullptr;
 | 
			
		||||
   #if JUCE_DEBUG
 | 
			
		||||
    bool hasBeenResized = false;
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    void initialise (bool addToDesktop);
 | 
			
		||||
    void updateLastPosIfNotFullScreen();
 | 
			
		||||
    void updateLastPosIfShowing();
 | 
			
		||||
    void setContent (Component*, bool takeOwnership, bool resizeToFit);
 | 
			
		||||
    void updatePeerConstrainer();
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ResizableWindow)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,119 +1,119 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
ThreadWithProgressWindow::ThreadWithProgressWindow (const String& title,
 | 
			
		||||
                                                    const bool hasProgressBar,
 | 
			
		||||
                                                    const bool hasCancelButton,
 | 
			
		||||
                                                    const int cancellingTimeOutMs,
 | 
			
		||||
                                                    const String& cancelButtonText,
 | 
			
		||||
                                                    Component* componentToCentreAround)
 | 
			
		||||
   : Thread ("ThreadWithProgressWindow"),
 | 
			
		||||
     progress (0.0),
 | 
			
		||||
     timeOutMsWhenCancelling (cancellingTimeOutMs),
 | 
			
		||||
     wasCancelledByUser (false)
 | 
			
		||||
{
 | 
			
		||||
    alertWindow.reset (LookAndFeel::getDefaultLookAndFeel()
 | 
			
		||||
                           .createAlertWindow (title, {},
 | 
			
		||||
                                               cancelButtonText.isEmpty() ? TRANS("Cancel")
 | 
			
		||||
                                                                          : cancelButtonText,
 | 
			
		||||
                                               {}, {}, MessageBoxIconType::NoIcon, hasCancelButton ? 1 : 0,
 | 
			
		||||
                                               componentToCentreAround));
 | 
			
		||||
 | 
			
		||||
    // if there are no buttons, we won't allow the user to interrupt the thread.
 | 
			
		||||
    alertWindow->setEscapeKeyCancels (false);
 | 
			
		||||
 | 
			
		||||
    if (hasProgressBar)
 | 
			
		||||
        alertWindow->addProgressBarComponent (progress);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ThreadWithProgressWindow::~ThreadWithProgressWindow()
 | 
			
		||||
{
 | 
			
		||||
    stopThread (timeOutMsWhenCancelling);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ThreadWithProgressWindow::launchThread (int priority)
 | 
			
		||||
{
 | 
			
		||||
    JUCE_ASSERT_MESSAGE_THREAD
 | 
			
		||||
 | 
			
		||||
    startThread (priority);
 | 
			
		||||
    startTimer (100);
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        const ScopedLock sl (messageLock);
 | 
			
		||||
        alertWindow->setMessage (message);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    alertWindow->enterModalState();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ThreadWithProgressWindow::setProgress (const double newProgress)
 | 
			
		||||
{
 | 
			
		||||
    progress = newProgress;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ThreadWithProgressWindow::setStatusMessage (const String& newStatusMessage)
 | 
			
		||||
{
 | 
			
		||||
    const ScopedLock sl (messageLock);
 | 
			
		||||
    message = newStatusMessage;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ThreadWithProgressWindow::timerCallback()
 | 
			
		||||
{
 | 
			
		||||
    bool threadStillRunning = isThreadRunning();
 | 
			
		||||
 | 
			
		||||
    if (! (threadStillRunning && alertWindow->isCurrentlyModal (false)))
 | 
			
		||||
    {
 | 
			
		||||
        stopTimer();
 | 
			
		||||
        stopThread (timeOutMsWhenCancelling);
 | 
			
		||||
        alertWindow->exitModalState (1);
 | 
			
		||||
        alertWindow->setVisible (false);
 | 
			
		||||
 | 
			
		||||
        wasCancelledByUser = threadStillRunning;
 | 
			
		||||
        threadComplete (threadStillRunning);
 | 
			
		||||
        return; // (this may be deleted now)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const ScopedLock sl (messageLock);
 | 
			
		||||
    alertWindow->setMessage (message);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ThreadWithProgressWindow::threadComplete (bool) {}
 | 
			
		||||
 | 
			
		||||
#if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
bool ThreadWithProgressWindow::runThread (const int priority)
 | 
			
		||||
{
 | 
			
		||||
    launchThread (priority);
 | 
			
		||||
 | 
			
		||||
    while (isTimerRunning())
 | 
			
		||||
        MessageManager::getInstance()->runDispatchLoopUntil (5);
 | 
			
		||||
 | 
			
		||||
    return ! wasCancelledByUser;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - 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 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
ThreadWithProgressWindow::ThreadWithProgressWindow (const String& title,
 | 
			
		||||
                                                    const bool hasProgressBar,
 | 
			
		||||
                                                    const bool hasCancelButton,
 | 
			
		||||
                                                    const int cancellingTimeOutMs,
 | 
			
		||||
                                                    const String& cancelButtonText,
 | 
			
		||||
                                                    Component* componentToCentreAround)
 | 
			
		||||
   : Thread ("ThreadWithProgressWindow"),
 | 
			
		||||
     progress (0.0),
 | 
			
		||||
     timeOutMsWhenCancelling (cancellingTimeOutMs),
 | 
			
		||||
     wasCancelledByUser (false)
 | 
			
		||||
{
 | 
			
		||||
    alertWindow.reset (LookAndFeel::getDefaultLookAndFeel()
 | 
			
		||||
                           .createAlertWindow (title, {},
 | 
			
		||||
                                               cancelButtonText.isEmpty() ? TRANS("Cancel")
 | 
			
		||||
                                                                          : cancelButtonText,
 | 
			
		||||
                                               {}, {}, MessageBoxIconType::NoIcon, hasCancelButton ? 1 : 0,
 | 
			
		||||
                                               componentToCentreAround));
 | 
			
		||||
 | 
			
		||||
    // if there are no buttons, we won't allow the user to interrupt the thread.
 | 
			
		||||
    alertWindow->setEscapeKeyCancels (false);
 | 
			
		||||
 | 
			
		||||
    if (hasProgressBar)
 | 
			
		||||
        alertWindow->addProgressBarComponent (progress);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ThreadWithProgressWindow::~ThreadWithProgressWindow()
 | 
			
		||||
{
 | 
			
		||||
    stopThread (timeOutMsWhenCancelling);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ThreadWithProgressWindow::launchThread (int priority)
 | 
			
		||||
{
 | 
			
		||||
    JUCE_ASSERT_MESSAGE_THREAD
 | 
			
		||||
 | 
			
		||||
    startThread (priority);
 | 
			
		||||
    startTimer (100);
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        const ScopedLock sl (messageLock);
 | 
			
		||||
        alertWindow->setMessage (message);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    alertWindow->enterModalState();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ThreadWithProgressWindow::setProgress (const double newProgress)
 | 
			
		||||
{
 | 
			
		||||
    progress = newProgress;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ThreadWithProgressWindow::setStatusMessage (const String& newStatusMessage)
 | 
			
		||||
{
 | 
			
		||||
    const ScopedLock sl (messageLock);
 | 
			
		||||
    message = newStatusMessage;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ThreadWithProgressWindow::timerCallback()
 | 
			
		||||
{
 | 
			
		||||
    bool threadStillRunning = isThreadRunning();
 | 
			
		||||
 | 
			
		||||
    if (! (threadStillRunning && alertWindow->isCurrentlyModal (false)))
 | 
			
		||||
    {
 | 
			
		||||
        stopTimer();
 | 
			
		||||
        stopThread (timeOutMsWhenCancelling);
 | 
			
		||||
        alertWindow->exitModalState (1);
 | 
			
		||||
        alertWindow->setVisible (false);
 | 
			
		||||
 | 
			
		||||
        wasCancelledByUser = threadStillRunning;
 | 
			
		||||
        threadComplete (threadStillRunning);
 | 
			
		||||
        return; // (this may be deleted now)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const ScopedLock sl (messageLock);
 | 
			
		||||
    alertWindow->setMessage (message);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ThreadWithProgressWindow::threadComplete (bool) {}
 | 
			
		||||
 | 
			
		||||
#if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
bool ThreadWithProgressWindow::runThread (const int priority)
 | 
			
		||||
{
 | 
			
		||||
    launchThread (priority);
 | 
			
		||||
 | 
			
		||||
    while (isTimerRunning())
 | 
			
		||||
        MessageManager::getInstance()->runDispatchLoopUntil (5);
 | 
			
		||||
 | 
			
		||||
    return ! wasCancelledByUser;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,175 +1,175 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A thread that automatically pops up a modal dialog box with a progress bar
 | 
			
		||||
    and cancel button while it's busy running.
 | 
			
		||||
 | 
			
		||||
    These are handy for performing some sort of task while giving the user feedback
 | 
			
		||||
    about how long there is to go, etc.
 | 
			
		||||
 | 
			
		||||
    E.g. @code
 | 
			
		||||
    class MyTask  : public ThreadWithProgressWindow
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        MyTask()    : ThreadWithProgressWindow ("busy...", true, true)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void run()
 | 
			
		||||
        {
 | 
			
		||||
            for (int i = 0; i < thingsToDo; ++i)
 | 
			
		||||
            {
 | 
			
		||||
                // must check this as often as possible, because this is
 | 
			
		||||
                // how we know if the user's pressed 'cancel'
 | 
			
		||||
                if (threadShouldExit())
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                // this will update the progress bar on the dialog box
 | 
			
		||||
                setProgress (i / (double) thingsToDo);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                //   ... do the business here...
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    void doTheTask()
 | 
			
		||||
    {
 | 
			
		||||
        MyTask m;
 | 
			
		||||
 | 
			
		||||
        if (m.runThread())
 | 
			
		||||
        {
 | 
			
		||||
            // thread finished normally..
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            // user pressed the cancel button..
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @endcode
 | 
			
		||||
 | 
			
		||||
    @see Thread, AlertWindow
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  ThreadWithProgressWindow  : public Thread,
 | 
			
		||||
                                            private Timer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates the thread.
 | 
			
		||||
 | 
			
		||||
        Initially, the dialog box won't be visible, it'll only appear when the
 | 
			
		||||
        runThread() method is called.
 | 
			
		||||
 | 
			
		||||
        @param windowTitle              the title to go at the top of the dialog box
 | 
			
		||||
        @param hasProgressBar           whether the dialog box should have a progress bar (see
 | 
			
		||||
                                        setProgress() )
 | 
			
		||||
        @param hasCancelButton          whether the dialog box should have a cancel button
 | 
			
		||||
        @param timeOutMsWhenCancelling  when 'cancel' is pressed, this is how long to wait for
 | 
			
		||||
                                        the thread to stop before killing it forcibly (see
 | 
			
		||||
                                        Thread::stopThread() )
 | 
			
		||||
        @param cancelButtonText         the text that should be shown in the cancel button
 | 
			
		||||
                                        (if it has one). Leave this empty for the default "Cancel"
 | 
			
		||||
        @param componentToCentreAround  if this is non-null, the window will be positioned
 | 
			
		||||
                                        so that it's centred around this component.
 | 
			
		||||
    */
 | 
			
		||||
    ThreadWithProgressWindow (const String& windowTitle,
 | 
			
		||||
                              bool hasProgressBar,
 | 
			
		||||
                              bool hasCancelButton,
 | 
			
		||||
                              int timeOutMsWhenCancelling = 10000,
 | 
			
		||||
                              const String& cancelButtonText = String(),
 | 
			
		||||
                              Component* componentToCentreAround = nullptr);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~ThreadWithProgressWindow() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
   #if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
    /** Starts the thread and waits for it to finish.
 | 
			
		||||
 | 
			
		||||
        This will start the thread, make the dialog box appear, and wait until either
 | 
			
		||||
        the thread finishes normally, or until the cancel button is pressed.
 | 
			
		||||
 | 
			
		||||
        Before returning, the dialog box will be hidden.
 | 
			
		||||
 | 
			
		||||
        @param priority   the priority to use when starting the thread - see
 | 
			
		||||
                          Thread::startThread() for values
 | 
			
		||||
        @returns true if the thread finished normally; false if the user pressed cancel
 | 
			
		||||
    */
 | 
			
		||||
    bool runThread (int priority = 5);
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    /** Starts the thread and returns.
 | 
			
		||||
 | 
			
		||||
        This will start the thread and make the dialog box appear in a modal state. When
 | 
			
		||||
        the thread finishes normally, or the cancel button is pressed, the window will be
 | 
			
		||||
        hidden and the threadComplete() method will be called.
 | 
			
		||||
 | 
			
		||||
        @param priority   the priority to use when starting the thread - see
 | 
			
		||||
                          Thread::startThread() for values
 | 
			
		||||
    */
 | 
			
		||||
    void launchThread (int priority = 5);
 | 
			
		||||
 | 
			
		||||
    /** The thread should call this periodically to update the position of the progress bar.
 | 
			
		||||
 | 
			
		||||
        @param newProgress  the progress, from 0.0 to 1.0
 | 
			
		||||
        @see setStatusMessage
 | 
			
		||||
    */
 | 
			
		||||
    void setProgress (double newProgress);
 | 
			
		||||
 | 
			
		||||
    /** The thread can call this to change the message that's displayed in the dialog box. */
 | 
			
		||||
    void setStatusMessage (const String& newStatusMessage);
 | 
			
		||||
 | 
			
		||||
    /** Returns the AlertWindow that is being used. */
 | 
			
		||||
    AlertWindow* getAlertWindow() const noexcept        { return alertWindow.get(); }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This method is called (on the message thread) when the operation has finished.
 | 
			
		||||
        You may choose to use this callback to delete the ThreadWithProgressWindow object.
 | 
			
		||||
    */
 | 
			
		||||
    virtual void threadComplete (bool userPressedCancel);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    void timerCallback() override;
 | 
			
		||||
 | 
			
		||||
    double progress;
 | 
			
		||||
    std::unique_ptr<AlertWindow> alertWindow;
 | 
			
		||||
    String message;
 | 
			
		||||
    CriticalSection messageLock;
 | 
			
		||||
    const int timeOutMsWhenCancelling;
 | 
			
		||||
    bool wasCancelledByUser;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ThreadWithProgressWindow)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - 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 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A thread that automatically pops up a modal dialog box with a progress bar
 | 
			
		||||
    and cancel button while it's busy running.
 | 
			
		||||
 | 
			
		||||
    These are handy for performing some sort of task while giving the user feedback
 | 
			
		||||
    about how long there is to go, etc.
 | 
			
		||||
 | 
			
		||||
    E.g. @code
 | 
			
		||||
    class MyTask  : public ThreadWithProgressWindow
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        MyTask()    : ThreadWithProgressWindow ("busy...", true, true)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void run()
 | 
			
		||||
        {
 | 
			
		||||
            for (int i = 0; i < thingsToDo; ++i)
 | 
			
		||||
            {
 | 
			
		||||
                // must check this as often as possible, because this is
 | 
			
		||||
                // how we know if the user's pressed 'cancel'
 | 
			
		||||
                if (threadShouldExit())
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                // this will update the progress bar on the dialog box
 | 
			
		||||
                setProgress (i / (double) thingsToDo);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                //   ... do the business here...
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    void doTheTask()
 | 
			
		||||
    {
 | 
			
		||||
        MyTask m;
 | 
			
		||||
 | 
			
		||||
        if (m.runThread())
 | 
			
		||||
        {
 | 
			
		||||
            // thread finished normally..
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            // user pressed the cancel button..
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @endcode
 | 
			
		||||
 | 
			
		||||
    @see Thread, AlertWindow
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  ThreadWithProgressWindow  : public Thread,
 | 
			
		||||
                                            private Timer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates the thread.
 | 
			
		||||
 | 
			
		||||
        Initially, the dialog box won't be visible, it'll only appear when the
 | 
			
		||||
        runThread() method is called.
 | 
			
		||||
 | 
			
		||||
        @param windowTitle              the title to go at the top of the dialog box
 | 
			
		||||
        @param hasProgressBar           whether the dialog box should have a progress bar (see
 | 
			
		||||
                                        setProgress() )
 | 
			
		||||
        @param hasCancelButton          whether the dialog box should have a cancel button
 | 
			
		||||
        @param timeOutMsWhenCancelling  when 'cancel' is pressed, this is how long to wait for
 | 
			
		||||
                                        the thread to stop before killing it forcibly (see
 | 
			
		||||
                                        Thread::stopThread() )
 | 
			
		||||
        @param cancelButtonText         the text that should be shown in the cancel button
 | 
			
		||||
                                        (if it has one). Leave this empty for the default "Cancel"
 | 
			
		||||
        @param componentToCentreAround  if this is non-null, the window will be positioned
 | 
			
		||||
                                        so that it's centred around this component.
 | 
			
		||||
    */
 | 
			
		||||
    ThreadWithProgressWindow (const String& windowTitle,
 | 
			
		||||
                              bool hasProgressBar,
 | 
			
		||||
                              bool hasCancelButton,
 | 
			
		||||
                              int timeOutMsWhenCancelling = 10000,
 | 
			
		||||
                              const String& cancelButtonText = String(),
 | 
			
		||||
                              Component* componentToCentreAround = nullptr);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~ThreadWithProgressWindow() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
   #if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
    /** Starts the thread and waits for it to finish.
 | 
			
		||||
 | 
			
		||||
        This will start the thread, make the dialog box appear, and wait until either
 | 
			
		||||
        the thread finishes normally, or until the cancel button is pressed.
 | 
			
		||||
 | 
			
		||||
        Before returning, the dialog box will be hidden.
 | 
			
		||||
 | 
			
		||||
        @param priority   the priority to use when starting the thread - see
 | 
			
		||||
                          Thread::startThread() for values
 | 
			
		||||
        @returns true if the thread finished normally; false if the user pressed cancel
 | 
			
		||||
    */
 | 
			
		||||
    bool runThread (int priority = 5);
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    /** Starts the thread and returns.
 | 
			
		||||
 | 
			
		||||
        This will start the thread and make the dialog box appear in a modal state. When
 | 
			
		||||
        the thread finishes normally, or the cancel button is pressed, the window will be
 | 
			
		||||
        hidden and the threadComplete() method will be called.
 | 
			
		||||
 | 
			
		||||
        @param priority   the priority to use when starting the thread - see
 | 
			
		||||
                          Thread::startThread() for values
 | 
			
		||||
    */
 | 
			
		||||
    void launchThread (int priority = 5);
 | 
			
		||||
 | 
			
		||||
    /** The thread should call this periodically to update the position of the progress bar.
 | 
			
		||||
 | 
			
		||||
        @param newProgress  the progress, from 0.0 to 1.0
 | 
			
		||||
        @see setStatusMessage
 | 
			
		||||
    */
 | 
			
		||||
    void setProgress (double newProgress);
 | 
			
		||||
 | 
			
		||||
    /** The thread can call this to change the message that's displayed in the dialog box. */
 | 
			
		||||
    void setStatusMessage (const String& newStatusMessage);
 | 
			
		||||
 | 
			
		||||
    /** Returns the AlertWindow that is being used. */
 | 
			
		||||
    AlertWindow* getAlertWindow() const noexcept        { return alertWindow.get(); }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This method is called (on the message thread) when the operation has finished.
 | 
			
		||||
        You may choose to use this callback to delete the ThreadWithProgressWindow object.
 | 
			
		||||
    */
 | 
			
		||||
    virtual void threadComplete (bool userPressedCancel);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    void timerCallback() override;
 | 
			
		||||
 | 
			
		||||
    double progress;
 | 
			
		||||
    std::unique_ptr<AlertWindow> alertWindow;
 | 
			
		||||
    String message;
 | 
			
		||||
    CriticalSection messageLock;
 | 
			
		||||
    const int timeOutMsWhenCancelling;
 | 
			
		||||
    bool wasCancelledByUser;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ThreadWithProgressWindow)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,232 +1,255 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   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);
 | 
			
		||||
 | 
			
		||||
    if (Desktop::getInstance().getMainMouseSource().canHover())
 | 
			
		||||
        startTimer (123);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TooltipWindow::~TooltipWindow()
 | 
			
		||||
{
 | 
			
		||||
    hideTip();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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&)
 | 
			
		||||
{
 | 
			
		||||
    hideTip();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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());
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 (! reentrant)
 | 
			
		||||
    {
 | 
			
		||||
        tipShowing.clear();
 | 
			
		||||
        removeFromDesktop();
 | 
			
		||||
        setVisible (false);
 | 
			
		||||
 | 
			
		||||
       #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()
 | 
			
		||||
{
 | 
			
		||||
    auto& desktop = Desktop::getInstance();
 | 
			
		||||
    auto mouseSource = desktop.getMainMouseSource();
 | 
			
		||||
    auto now = Time::getApproximateMillisecondCounter();
 | 
			
		||||
 | 
			
		||||
    auto* newComp = mouseSource.isTouch() ? nullptr : mouseSource.getComponentUnderMouse();
 | 
			
		||||
 | 
			
		||||
    if (newComp == nullptr || getParentComponent() == nullptr || newComp->getPeer() == getPeer())
 | 
			
		||||
    {
 | 
			
		||||
        auto newTip = newComp != nullptr ? getTipFor (*newComp) : String();
 | 
			
		||||
        bool tipChanged = (newTip != lastTipUnderMouse || newComp != lastComponentUnderMouse);
 | 
			
		||||
        lastComponentUnderMouse = newComp;
 | 
			
		||||
        lastTipUnderMouse = newTip;
 | 
			
		||||
 | 
			
		||||
        auto clickCount = desktop.getMouseButtonClickCounter();
 | 
			
		||||
        auto wheelCount = desktop.getMouseWheelMoveCounter();
 | 
			
		||||
        bool mouseWasClicked = (clickCount > mouseClicks || wheelCount > mouseWheelMoves);
 | 
			
		||||
        mouseClicks = clickCount;
 | 
			
		||||
        mouseWheelMoves = wheelCount;
 | 
			
		||||
 | 
			
		||||
        auto mousePos = mouseSource.getScreenPosition();
 | 
			
		||||
        bool mouseMovedQuickly = mousePos.getDistanceFrom (lastMousePos) > 12;
 | 
			
		||||
        lastMousePos = mousePos;
 | 
			
		||||
 | 
			
		||||
        if (tipChanged || mouseWasClicked || mouseMovedQuickly)
 | 
			
		||||
            lastCompChangeTime = now;
 | 
			
		||||
 | 
			
		||||
        auto showTip = [this, &mouseSource, &mousePos, &newTip]
 | 
			
		||||
        {
 | 
			
		||||
            bool mouseHasMovedSinceClick = mouseSource.getLastMouseDownPosition() != lastMousePos;
 | 
			
		||||
 | 
			
		||||
            if (mouseHasMovedSinceClick)
 | 
			
		||||
                displayTip (mousePos.roundToInt(), newTip);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        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 || mouseWasClicked || newTip.isEmpty())
 | 
			
		||||
            {
 | 
			
		||||
                if (isVisible())
 | 
			
		||||
                {
 | 
			
		||||
                    lastHideTime = now;
 | 
			
		||||
                    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
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - 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 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-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
 | 
			
		||||
 
 | 
			
		||||
@@ -1,149 +1,159 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A window that displays a pop-up tooltip when the mouse hovers over another component.
 | 
			
		||||
 | 
			
		||||
    To enable tooltips in your app, just create a single instance of a TooltipWindow
 | 
			
		||||
    object. Note that if you instantiate more than one instance of this class with the
 | 
			
		||||
    same parentComponent (even if both TooltipWindow's parentComponent is nil), you'll
 | 
			
		||||
    end up with multiple tooltips being shown! To avoid this use a SharedResourcePointer
 | 
			
		||||
    to instantiate the TooltipWindow only once.
 | 
			
		||||
 | 
			
		||||
    For audio plug-ins (which should not be opening native windows) it is better
 | 
			
		||||
    to add a TooltipWindow as a member variable to the editor and ensure that the
 | 
			
		||||
    editor is the parentComponent of your TooltipWindow. This will ensure that your
 | 
			
		||||
    TooltipWindow is scaled according to your editor and the DAWs scaling setting.
 | 
			
		||||
 | 
			
		||||
    The TooltipWindow object will then stay invisible, waiting until the mouse
 | 
			
		||||
    hovers for the specified length of time - it will then see if it's currently
 | 
			
		||||
    over a component which implements the TooltipClient interface, and if so,
 | 
			
		||||
    it will make itself visible to show the tooltip in the appropriate place.
 | 
			
		||||
 | 
			
		||||
    @see TooltipClient, SettableTooltipClient, SharedResourcePointer
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  TooltipWindow  : public Component,
 | 
			
		||||
                                 private Timer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a tooltip window.
 | 
			
		||||
 | 
			
		||||
        Make sure your app only creates one instance of this class, otherwise you'll
 | 
			
		||||
        get multiple overlaid tooltips appearing. The window will initially be invisible
 | 
			
		||||
        and will make itself visible when it needs to display a tip.
 | 
			
		||||
 | 
			
		||||
        To change the style of tooltips, see the LookAndFeel class for its tooltip
 | 
			
		||||
        methods.
 | 
			
		||||
 | 
			
		||||
        @param parentComponent  if set to nullptr, the TooltipWindow will appear on the desktop,
 | 
			
		||||
                                otherwise the tooltip will be added to the given parent
 | 
			
		||||
                                component.
 | 
			
		||||
        @param millisecondsBeforeTipAppears     the time for which the mouse has to stay still
 | 
			
		||||
                                                before a tooltip will be shown
 | 
			
		||||
 | 
			
		||||
        @see TooltipClient, LookAndFeel::drawTooltip, LookAndFeel::getTooltipBounds
 | 
			
		||||
    */
 | 
			
		||||
    explicit TooltipWindow (Component* parentComponent = nullptr,
 | 
			
		||||
                            int millisecondsBeforeTipAppears = 700);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~TooltipWindow() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Changes the time before the tip appears.
 | 
			
		||||
        This lets you change the value that was set in the constructor.
 | 
			
		||||
    */
 | 
			
		||||
    void setMillisecondsBeforeTipAppears (int newTimeMs = 700) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Can be called to manually force a tip to be shown at a particular location. */
 | 
			
		||||
    void displayTip (Point<int> screenPosition, const String& text);
 | 
			
		||||
 | 
			
		||||
    /** Can be called to manually hide the tip if it's showing. */
 | 
			
		||||
    void hideTip();
 | 
			
		||||
 | 
			
		||||
    /** Asks a component for its tooltip.
 | 
			
		||||
        This can be overridden if you need custom lookup behaviour or to modify the strings.
 | 
			
		||||
    */
 | 
			
		||||
    virtual String getTipFor (Component&);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** A set of colour IDs to use to change the colour of various aspects of the tooltip.
 | 
			
		||||
 | 
			
		||||
        These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
 | 
			
		||||
        methods.
 | 
			
		||||
 | 
			
		||||
        @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
 | 
			
		||||
    */
 | 
			
		||||
    enum ColourIds
 | 
			
		||||
    {
 | 
			
		||||
        backgroundColourId      = 0x1001b00,    /**< The colour to fill the background with. */
 | 
			
		||||
        textColourId            = 0x1001c00,    /**< The colour to use for the text. */
 | 
			
		||||
        outlineColourId         = 0x1001c10     /**< The colour to use to draw an outline around the tooltip. */
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This abstract base class is implemented by LookAndFeel classes to provide
 | 
			
		||||
        window drawing functionality.
 | 
			
		||||
    */
 | 
			
		||||
    struct JUCE_API  LookAndFeelMethods
 | 
			
		||||
    {
 | 
			
		||||
        virtual ~LookAndFeelMethods() = default;
 | 
			
		||||
 | 
			
		||||
        /** returns the bounds for a tooltip at the given screen coordinate, constrained within the given desktop area. */
 | 
			
		||||
        virtual Rectangle<int> getTooltipBounds (const String& tipText, Point<int> screenPos, Rectangle<int> parentArea) = 0;
 | 
			
		||||
        virtual void drawTooltip (Graphics&, const String& text, int width, int height) = 0;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    float getDesktopScaleFactor() const override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    Point<float> lastMousePos;
 | 
			
		||||
    Component* lastComponentUnderMouse = nullptr;
 | 
			
		||||
    String tipShowing, lastTipUnderMouse;
 | 
			
		||||
    int millisecondsBeforeTipAppears;
 | 
			
		||||
    int mouseClicks = 0, mouseWheelMoves = 0;
 | 
			
		||||
    unsigned int lastCompChangeTime = 0, lastHideTime = 0;
 | 
			
		||||
    bool reentrant = false;
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override;
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
    void mouseEnter (const MouseEvent&) override;
 | 
			
		||||
    void timerCallback() override;
 | 
			
		||||
    void updatePosition (const String&, Point<int>, Rectangle<int>);
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TooltipWindow)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - 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 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A window that displays a pop-up tooltip when the mouse hovers over another component.
 | 
			
		||||
 | 
			
		||||
    To enable tooltips in your app, just create a single instance of a TooltipWindow
 | 
			
		||||
    object. Note that if you instantiate more than one instance of this class with the
 | 
			
		||||
    same parentComponent (even if both TooltipWindow's parentComponent is nil), you'll
 | 
			
		||||
    end up with multiple tooltips being shown! To avoid this use a SharedResourcePointer
 | 
			
		||||
    to instantiate the TooltipWindow only once.
 | 
			
		||||
 | 
			
		||||
    For audio plug-ins (which should not be opening native windows) it is better
 | 
			
		||||
    to add a TooltipWindow as a member variable to the editor and ensure that the
 | 
			
		||||
    editor is the parentComponent of your TooltipWindow. This will ensure that your
 | 
			
		||||
    TooltipWindow is scaled according to your editor and the DAWs scaling setting.
 | 
			
		||||
 | 
			
		||||
    The TooltipWindow object will then stay invisible, waiting until the mouse
 | 
			
		||||
    hovers for the specified length of time - it will then see if it's currently
 | 
			
		||||
    over a component which implements the TooltipClient interface, and if so,
 | 
			
		||||
    it will make itself visible to show the tooltip in the appropriate place.
 | 
			
		||||
 | 
			
		||||
    @see TooltipClient, SettableTooltipClient, SharedResourcePointer
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  TooltipWindow  : public Component,
 | 
			
		||||
                                 private Timer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a tooltip window.
 | 
			
		||||
 | 
			
		||||
        Make sure your app only creates one instance of this class, otherwise you'll
 | 
			
		||||
        get multiple overlaid tooltips appearing. The window will initially be invisible
 | 
			
		||||
        and will make itself visible when it needs to display a tip.
 | 
			
		||||
 | 
			
		||||
        To change the style of tooltips, see the LookAndFeel class for its tooltip
 | 
			
		||||
        methods.
 | 
			
		||||
 | 
			
		||||
        @param parentComponent  if set to nullptr, the TooltipWindow will appear on the desktop,
 | 
			
		||||
                                otherwise the tooltip will be added to the given parent
 | 
			
		||||
                                component.
 | 
			
		||||
        @param millisecondsBeforeTipAppears     the time for which the mouse has to stay still
 | 
			
		||||
                                                before a tooltip will be shown
 | 
			
		||||
 | 
			
		||||
        @see TooltipClient, LookAndFeel::drawTooltip, LookAndFeel::getTooltipBounds
 | 
			
		||||
    */
 | 
			
		||||
    explicit TooltipWindow (Component* parentComponent = nullptr,
 | 
			
		||||
                            int millisecondsBeforeTipAppears = 700);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~TooltipWindow() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Changes the time before the tip appears.
 | 
			
		||||
        This lets you change the value that was set in the constructor.
 | 
			
		||||
    */
 | 
			
		||||
    void setMillisecondsBeforeTipAppears (int newTimeMs = 700) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Can be called to manually force a tip to be shown at a particular location.
 | 
			
		||||
 | 
			
		||||
        The tip will be shown until hideTip() is called, or a dismissal mouse event
 | 
			
		||||
        occurs.
 | 
			
		||||
 | 
			
		||||
        @see hideTip
 | 
			
		||||
    */
 | 
			
		||||
    void displayTip (Point<int> screenPosition, const String& text);
 | 
			
		||||
 | 
			
		||||
    /** Can be called to manually hide the tip if it's showing. */
 | 
			
		||||
    void hideTip();
 | 
			
		||||
 | 
			
		||||
    /** Asks a component for its tooltip.
 | 
			
		||||
        This can be overridden if you need custom lookup behaviour or to modify the strings.
 | 
			
		||||
    */
 | 
			
		||||
    virtual String getTipFor (Component&);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** A set of colour IDs to use to change the colour of various aspects of the tooltip.
 | 
			
		||||
 | 
			
		||||
        These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
 | 
			
		||||
        methods.
 | 
			
		||||
 | 
			
		||||
        @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
 | 
			
		||||
    */
 | 
			
		||||
    enum ColourIds
 | 
			
		||||
    {
 | 
			
		||||
        backgroundColourId      = 0x1001b00,    /**< The colour to fill the background with. */
 | 
			
		||||
        textColourId            = 0x1001c00,    /**< The colour to use for the text. */
 | 
			
		||||
        outlineColourId         = 0x1001c10     /**< The colour to use to draw an outline around the tooltip. */
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This abstract base class is implemented by LookAndFeel classes to provide
 | 
			
		||||
        window drawing functionality.
 | 
			
		||||
    */
 | 
			
		||||
    struct JUCE_API  LookAndFeelMethods
 | 
			
		||||
    {
 | 
			
		||||
        virtual ~LookAndFeelMethods() = default;
 | 
			
		||||
 | 
			
		||||
        /** returns the bounds for a tooltip at the given screen coordinate, constrained within the given desktop area. */
 | 
			
		||||
        virtual Rectangle<int> getTooltipBounds (const String& tipText, Point<int> screenPos, Rectangle<int> parentArea) = 0;
 | 
			
		||||
        virtual void drawTooltip (Graphics&, const String& text, int width, int height) = 0;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    float getDesktopScaleFactor() const override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    Point<float> lastMousePos;
 | 
			
		||||
    SafePointer<Component> lastComponentUnderMouse;
 | 
			
		||||
    String tipShowing, lastTipUnderMouse, manuallyShownTip;
 | 
			
		||||
    int millisecondsBeforeTipAppears;
 | 
			
		||||
    unsigned int lastCompChangeTime = 0, lastHideTime = 0;
 | 
			
		||||
    bool reentrant = false, dismissalMouseEventOccurred = false;
 | 
			
		||||
 | 
			
		||||
    enum ShownManually { yes, no };
 | 
			
		||||
    void displayTipInternal (Point<int>, const String&, ShownManually);
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override;
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
    void mouseEnter (const MouseEvent&) override;
 | 
			
		||||
    void mouseDown (const MouseEvent&) override;
 | 
			
		||||
    void mouseWheelMove (const MouseEvent&, const MouseWheelDetails&) override;
 | 
			
		||||
    void timerCallback() override;
 | 
			
		||||
    void updatePosition (const String&, Point<int>, Rectangle<int>);
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TooltipWindow)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,358 +1,358 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
/** Keeps track of the active top level window. */
 | 
			
		||||
class TopLevelWindowManager  : private Timer,
 | 
			
		||||
                               private DeletedAtShutdown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    TopLevelWindowManager() {}
 | 
			
		||||
    ~TopLevelWindowManager() override    { clearSingletonInstance(); }
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL (TopLevelWindowManager)
 | 
			
		||||
 | 
			
		||||
    void checkFocusAsync()
 | 
			
		||||
    {
 | 
			
		||||
        startTimer (10);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void checkFocus()
 | 
			
		||||
    {
 | 
			
		||||
        startTimer (jmin (1731, getTimerInterval() * 2));
 | 
			
		||||
 | 
			
		||||
        auto* newActive = findCurrentlyActiveWindow();
 | 
			
		||||
 | 
			
		||||
        if (newActive != currentActive)
 | 
			
		||||
        {
 | 
			
		||||
            currentActive = newActive;
 | 
			
		||||
 | 
			
		||||
            for (int i = windows.size(); --i >= 0;)
 | 
			
		||||
                if (auto* tlw = windows[i])
 | 
			
		||||
                    tlw->setWindowActive (isWindowActive (tlw));
 | 
			
		||||
 | 
			
		||||
            Desktop::getInstance().triggerFocusCallback();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool addWindow (TopLevelWindow* const w)
 | 
			
		||||
    {
 | 
			
		||||
        windows.add (w);
 | 
			
		||||
        checkFocusAsync();
 | 
			
		||||
 | 
			
		||||
        return isWindowActive (w);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void removeWindow (TopLevelWindow* const w)
 | 
			
		||||
    {
 | 
			
		||||
        checkFocusAsync();
 | 
			
		||||
 | 
			
		||||
        if (currentActive == w)
 | 
			
		||||
            currentActive = nullptr;
 | 
			
		||||
 | 
			
		||||
        windows.removeFirstMatchingValue (w);
 | 
			
		||||
 | 
			
		||||
        if (windows.isEmpty())
 | 
			
		||||
            deleteInstance();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Array<TopLevelWindow*> windows;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    TopLevelWindow* currentActive = nullptr;
 | 
			
		||||
 | 
			
		||||
    void timerCallback() override
 | 
			
		||||
    {
 | 
			
		||||
        checkFocus();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool isWindowActive (TopLevelWindow* const tlw) const
 | 
			
		||||
    {
 | 
			
		||||
        return (tlw == currentActive
 | 
			
		||||
                 || tlw->isParentOf (currentActive)
 | 
			
		||||
                 || tlw->hasKeyboardFocus (true))
 | 
			
		||||
                && tlw->isShowing();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    TopLevelWindow* findCurrentlyActiveWindow() const
 | 
			
		||||
    {
 | 
			
		||||
        if (Process::isForegroundProcess())
 | 
			
		||||
        {
 | 
			
		||||
            auto* focusedComp = Component::getCurrentlyFocusedComponent();
 | 
			
		||||
            auto* w = dynamic_cast<TopLevelWindow*> (focusedComp);
 | 
			
		||||
 | 
			
		||||
            if (w == nullptr && focusedComp != nullptr)
 | 
			
		||||
                w = focusedComp->findParentComponentOfClass<TopLevelWindow>();
 | 
			
		||||
 | 
			
		||||
            if (w == nullptr)
 | 
			
		||||
                w = currentActive;
 | 
			
		||||
 | 
			
		||||
            if (w != nullptr && w->isShowing())
 | 
			
		||||
                return w;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE (TopLevelWindowManager)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_IMPLEMENT_SINGLETON (TopLevelWindowManager)
 | 
			
		||||
 | 
			
		||||
void juce_checkCurrentlyFocusedTopLevelWindow();
 | 
			
		||||
void juce_checkCurrentlyFocusedTopLevelWindow()
 | 
			
		||||
{
 | 
			
		||||
    if (auto* wm = TopLevelWindowManager::getInstanceWithoutCreating())
 | 
			
		||||
        wm->checkFocusAsync();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
TopLevelWindow::TopLevelWindow (const String& name, const bool shouldAddToDesktop)
 | 
			
		||||
    : Component (name)
 | 
			
		||||
{
 | 
			
		||||
    setTitle (name);
 | 
			
		||||
 | 
			
		||||
    setOpaque (true);
 | 
			
		||||
 | 
			
		||||
    if (shouldAddToDesktop)
 | 
			
		||||
        Component::addToDesktop (TopLevelWindow::getDesktopWindowStyleFlags());
 | 
			
		||||
    else
 | 
			
		||||
        setDropShadowEnabled (true);
 | 
			
		||||
 | 
			
		||||
    setWantsKeyboardFocus (true);
 | 
			
		||||
    setBroughtToFrontOnMouseClick (true);
 | 
			
		||||
    isCurrentlyActive = TopLevelWindowManager::getInstance()->addWindow (this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TopLevelWindow::~TopLevelWindow()
 | 
			
		||||
{
 | 
			
		||||
    shadower.reset();
 | 
			
		||||
    TopLevelWindowManager::getInstance()->removeWindow (this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void TopLevelWindow::focusOfChildComponentChanged (FocusChangeType)
 | 
			
		||||
{
 | 
			
		||||
    auto* wm = TopLevelWindowManager::getInstance();
 | 
			
		||||
 | 
			
		||||
    if (hasKeyboardFocus (true))
 | 
			
		||||
        wm->checkFocus();
 | 
			
		||||
    else
 | 
			
		||||
        wm->checkFocusAsync();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TopLevelWindow::setWindowActive (const bool isNowActive)
 | 
			
		||||
{
 | 
			
		||||
    if (isCurrentlyActive != isNowActive)
 | 
			
		||||
    {
 | 
			
		||||
        isCurrentlyActive = isNowActive;
 | 
			
		||||
        activeWindowStatusChanged();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TopLevelWindow::activeWindowStatusChanged()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool TopLevelWindow::isUsingNativeTitleBar() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return useNativeTitleBar && (isOnDesktop() || ! isShowing());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TopLevelWindow::visibilityChanged()
 | 
			
		||||
{
 | 
			
		||||
    if (isShowing())
 | 
			
		||||
        if (auto* p = getPeer())
 | 
			
		||||
            if ((p->getStyleFlags() & (ComponentPeer::windowIsTemporary
 | 
			
		||||
                                        | ComponentPeer::windowIgnoresKeyPresses)) == 0)
 | 
			
		||||
                toFront (true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TopLevelWindow::parentHierarchyChanged()
 | 
			
		||||
{
 | 
			
		||||
    setDropShadowEnabled (useDropShadow);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int TopLevelWindow::getDesktopWindowStyleFlags() const
 | 
			
		||||
{
 | 
			
		||||
    int styleFlags = ComponentPeer::windowAppearsOnTaskbar;
 | 
			
		||||
 | 
			
		||||
    if (useDropShadow)       styleFlags |= ComponentPeer::windowHasDropShadow;
 | 
			
		||||
    if (useNativeTitleBar)   styleFlags |= ComponentPeer::windowHasTitleBar;
 | 
			
		||||
 | 
			
		||||
    return styleFlags;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TopLevelWindow::setDropShadowEnabled (const bool useShadow)
 | 
			
		||||
{
 | 
			
		||||
    useDropShadow = useShadow;
 | 
			
		||||
 | 
			
		||||
    if (isOnDesktop())
 | 
			
		||||
    {
 | 
			
		||||
        shadower.reset();
 | 
			
		||||
        Component::addToDesktop (getDesktopWindowStyleFlags());
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        if (useShadow && isOpaque())
 | 
			
		||||
        {
 | 
			
		||||
            if (shadower == nullptr)
 | 
			
		||||
            {
 | 
			
		||||
                shadower.reset (getLookAndFeel().createDropShadowerForComponent (this));
 | 
			
		||||
 | 
			
		||||
                if (shadower != nullptr)
 | 
			
		||||
                    shadower->setOwner (this);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            shadower.reset();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TopLevelWindow::setUsingNativeTitleBar (const bool shouldUseNativeTitleBar)
 | 
			
		||||
{
 | 
			
		||||
    if (useNativeTitleBar != shouldUseNativeTitleBar)
 | 
			
		||||
    {
 | 
			
		||||
        FocusRestorer focusRestorer;
 | 
			
		||||
        useNativeTitleBar = shouldUseNativeTitleBar;
 | 
			
		||||
        recreateDesktopWindow();
 | 
			
		||||
        sendLookAndFeelChange();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TopLevelWindow::recreateDesktopWindow()
 | 
			
		||||
{
 | 
			
		||||
    if (isOnDesktop())
 | 
			
		||||
    {
 | 
			
		||||
        Component::addToDesktop (getDesktopWindowStyleFlags());
 | 
			
		||||
        toFront (true);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TopLevelWindow::addToDesktop()
 | 
			
		||||
{
 | 
			
		||||
    shadower.reset();
 | 
			
		||||
    Component::addToDesktop (getDesktopWindowStyleFlags());
 | 
			
		||||
    setDropShadowEnabled (isDropShadowEnabled()); // force an update to clear away any fake shadows if necessary.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TopLevelWindow::addToDesktop (int windowStyleFlags, void* nativeWindowToAttachTo)
 | 
			
		||||
{
 | 
			
		||||
    /* It's not recommended to change the desktop window flags directly for a TopLevelWindow,
 | 
			
		||||
       because this class needs to make sure its layout corresponds with settings like whether
 | 
			
		||||
       it's got a native title bar or not.
 | 
			
		||||
 | 
			
		||||
       If you need custom flags for your window, you can override the getDesktopWindowStyleFlags()
 | 
			
		||||
       method. If you do this, it's best to call the base class's getDesktopWindowStyleFlags()
 | 
			
		||||
       method, then add or remove whatever flags are necessary from this value before returning it.
 | 
			
		||||
    */
 | 
			
		||||
    jassert ((windowStyleFlags & ~ComponentPeer::windowIsSemiTransparent)
 | 
			
		||||
               == (getDesktopWindowStyleFlags() & ~ComponentPeer::windowIsSemiTransparent));
 | 
			
		||||
 | 
			
		||||
    Component::addToDesktop (windowStyleFlags, nativeWindowToAttachTo);
 | 
			
		||||
 | 
			
		||||
    if (windowStyleFlags != getDesktopWindowStyleFlags())
 | 
			
		||||
        sendLookAndFeelChange();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::unique_ptr<AccessibilityHandler> TopLevelWindow::createAccessibilityHandler()
 | 
			
		||||
{
 | 
			
		||||
    return std::make_unique<AccessibilityHandler> (*this, AccessibilityRole::window);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void TopLevelWindow::centreAroundComponent (Component* c, const int width, const int height)
 | 
			
		||||
{
 | 
			
		||||
    if (c == nullptr)
 | 
			
		||||
        c = TopLevelWindow::getActiveTopLevelWindow();
 | 
			
		||||
 | 
			
		||||
    if (c == nullptr || c->getBounds().isEmpty())
 | 
			
		||||
    {
 | 
			
		||||
        centreWithSize (width, height);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        const auto scale = getDesktopScaleFactor() / Desktop::getInstance().getGlobalScaleFactor();
 | 
			
		||||
 | 
			
		||||
        auto targetCentre = c->localPointToGlobal (c->getLocalBounds().getCentre()) / scale;
 | 
			
		||||
        auto parentArea = c->getParentMonitorArea();
 | 
			
		||||
 | 
			
		||||
        if (auto* parent = getParentComponent())
 | 
			
		||||
        {
 | 
			
		||||
            targetCentre = parent->getLocalPoint (nullptr, targetCentre);
 | 
			
		||||
            parentArea   = parent->getLocalBounds();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        setBounds (Rectangle<int> (targetCentre.x - width / 2,
 | 
			
		||||
                                   targetCentre.y - height / 2,
 | 
			
		||||
                                   width, height)
 | 
			
		||||
                     .constrainedWithin (parentArea.reduced (12, 12)));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
int TopLevelWindow::getNumTopLevelWindows() noexcept
 | 
			
		||||
{
 | 
			
		||||
    return TopLevelWindowManager::getInstance()->windows.size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TopLevelWindow* TopLevelWindow::getTopLevelWindow (const int index) noexcept
 | 
			
		||||
{
 | 
			
		||||
    return TopLevelWindowManager::getInstance()->windows [index];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TopLevelWindow* TopLevelWindow::getActiveTopLevelWindow() noexcept
 | 
			
		||||
{
 | 
			
		||||
    TopLevelWindow* best = nullptr;
 | 
			
		||||
    int bestNumTWLParents = -1;
 | 
			
		||||
 | 
			
		||||
    for (int i = TopLevelWindow::getNumTopLevelWindows(); --i >= 0;)
 | 
			
		||||
    {
 | 
			
		||||
        auto* tlw = TopLevelWindow::getTopLevelWindow (i);
 | 
			
		||||
 | 
			
		||||
        if (tlw->isActiveWindow())
 | 
			
		||||
        {
 | 
			
		||||
            int numTWLParents = 0;
 | 
			
		||||
 | 
			
		||||
            for (auto* c = tlw->getParentComponent(); c != nullptr; c = c->getParentComponent())
 | 
			
		||||
                if (dynamic_cast<const TopLevelWindow*> (c) != nullptr)
 | 
			
		||||
                    ++numTWLParents;
 | 
			
		||||
 | 
			
		||||
            if (bestNumTWLParents < numTWLParents)
 | 
			
		||||
            {
 | 
			
		||||
                best = tlw;
 | 
			
		||||
                bestNumTWLParents = numTWLParents;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return best;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - 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 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
/** Keeps track of the active top level window. */
 | 
			
		||||
class TopLevelWindowManager  : private Timer,
 | 
			
		||||
                               private DeletedAtShutdown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    TopLevelWindowManager() {}
 | 
			
		||||
    ~TopLevelWindowManager() override    { clearSingletonInstance(); }
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL (TopLevelWindowManager)
 | 
			
		||||
 | 
			
		||||
    void checkFocusAsync()
 | 
			
		||||
    {
 | 
			
		||||
        startTimer (10);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void checkFocus()
 | 
			
		||||
    {
 | 
			
		||||
        startTimer (jmin (1731, getTimerInterval() * 2));
 | 
			
		||||
 | 
			
		||||
        auto* newActive = findCurrentlyActiveWindow();
 | 
			
		||||
 | 
			
		||||
        if (newActive != currentActive)
 | 
			
		||||
        {
 | 
			
		||||
            currentActive = newActive;
 | 
			
		||||
 | 
			
		||||
            for (int i = windows.size(); --i >= 0;)
 | 
			
		||||
                if (auto* tlw = windows[i])
 | 
			
		||||
                    tlw->setWindowActive (isWindowActive (tlw));
 | 
			
		||||
 | 
			
		||||
            Desktop::getInstance().triggerFocusCallback();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool addWindow (TopLevelWindow* const w)
 | 
			
		||||
    {
 | 
			
		||||
        windows.add (w);
 | 
			
		||||
        checkFocusAsync();
 | 
			
		||||
 | 
			
		||||
        return isWindowActive (w);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void removeWindow (TopLevelWindow* const w)
 | 
			
		||||
    {
 | 
			
		||||
        checkFocusAsync();
 | 
			
		||||
 | 
			
		||||
        if (currentActive == w)
 | 
			
		||||
            currentActive = nullptr;
 | 
			
		||||
 | 
			
		||||
        windows.removeFirstMatchingValue (w);
 | 
			
		||||
 | 
			
		||||
        if (windows.isEmpty())
 | 
			
		||||
            deleteInstance();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Array<TopLevelWindow*> windows;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    TopLevelWindow* currentActive = nullptr;
 | 
			
		||||
 | 
			
		||||
    void timerCallback() override
 | 
			
		||||
    {
 | 
			
		||||
        checkFocus();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool isWindowActive (TopLevelWindow* const tlw) const
 | 
			
		||||
    {
 | 
			
		||||
        return (tlw == currentActive
 | 
			
		||||
                 || tlw->isParentOf (currentActive)
 | 
			
		||||
                 || tlw->hasKeyboardFocus (true))
 | 
			
		||||
                && tlw->isShowing();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    TopLevelWindow* findCurrentlyActiveWindow() const
 | 
			
		||||
    {
 | 
			
		||||
        if (Process::isForegroundProcess())
 | 
			
		||||
        {
 | 
			
		||||
            auto* focusedComp = Component::getCurrentlyFocusedComponent();
 | 
			
		||||
            auto* w = dynamic_cast<TopLevelWindow*> (focusedComp);
 | 
			
		||||
 | 
			
		||||
            if (w == nullptr && focusedComp != nullptr)
 | 
			
		||||
                w = focusedComp->findParentComponentOfClass<TopLevelWindow>();
 | 
			
		||||
 | 
			
		||||
            if (w == nullptr)
 | 
			
		||||
                w = currentActive;
 | 
			
		||||
 | 
			
		||||
            if (w != nullptr && w->isShowing())
 | 
			
		||||
                return w;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE (TopLevelWindowManager)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_IMPLEMENT_SINGLETON (TopLevelWindowManager)
 | 
			
		||||
 | 
			
		||||
void juce_checkCurrentlyFocusedTopLevelWindow();
 | 
			
		||||
void juce_checkCurrentlyFocusedTopLevelWindow()
 | 
			
		||||
{
 | 
			
		||||
    if (auto* wm = TopLevelWindowManager::getInstanceWithoutCreating())
 | 
			
		||||
        wm->checkFocusAsync();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
TopLevelWindow::TopLevelWindow (const String& name, const bool shouldAddToDesktop)
 | 
			
		||||
    : Component (name)
 | 
			
		||||
{
 | 
			
		||||
    setTitle (name);
 | 
			
		||||
 | 
			
		||||
    setOpaque (true);
 | 
			
		||||
 | 
			
		||||
    if (shouldAddToDesktop)
 | 
			
		||||
        Component::addToDesktop (TopLevelWindow::getDesktopWindowStyleFlags());
 | 
			
		||||
    else
 | 
			
		||||
        setDropShadowEnabled (true);
 | 
			
		||||
 | 
			
		||||
    setWantsKeyboardFocus (true);
 | 
			
		||||
    setBroughtToFrontOnMouseClick (true);
 | 
			
		||||
    isCurrentlyActive = TopLevelWindowManager::getInstance()->addWindow (this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TopLevelWindow::~TopLevelWindow()
 | 
			
		||||
{
 | 
			
		||||
    shadower = nullptr;
 | 
			
		||||
    TopLevelWindowManager::getInstance()->removeWindow (this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void TopLevelWindow::focusOfChildComponentChanged (FocusChangeType)
 | 
			
		||||
{
 | 
			
		||||
    auto* wm = TopLevelWindowManager::getInstance();
 | 
			
		||||
 | 
			
		||||
    if (hasKeyboardFocus (true))
 | 
			
		||||
        wm->checkFocus();
 | 
			
		||||
    else
 | 
			
		||||
        wm->checkFocusAsync();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TopLevelWindow::setWindowActive (const bool isNowActive)
 | 
			
		||||
{
 | 
			
		||||
    if (isCurrentlyActive != isNowActive)
 | 
			
		||||
    {
 | 
			
		||||
        isCurrentlyActive = isNowActive;
 | 
			
		||||
        activeWindowStatusChanged();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TopLevelWindow::activeWindowStatusChanged()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool TopLevelWindow::isUsingNativeTitleBar() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return useNativeTitleBar && (isOnDesktop() || ! isShowing());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TopLevelWindow::visibilityChanged()
 | 
			
		||||
{
 | 
			
		||||
    if (isShowing())
 | 
			
		||||
        if (auto* p = getPeer())
 | 
			
		||||
            if ((p->getStyleFlags() & (ComponentPeer::windowIsTemporary
 | 
			
		||||
                                        | ComponentPeer::windowIgnoresKeyPresses)) == 0)
 | 
			
		||||
                toFront (true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TopLevelWindow::parentHierarchyChanged()
 | 
			
		||||
{
 | 
			
		||||
    setDropShadowEnabled (useDropShadow);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int TopLevelWindow::getDesktopWindowStyleFlags() const
 | 
			
		||||
{
 | 
			
		||||
    int styleFlags = ComponentPeer::windowAppearsOnTaskbar;
 | 
			
		||||
 | 
			
		||||
    if (useDropShadow)       styleFlags |= ComponentPeer::windowHasDropShadow;
 | 
			
		||||
    if (useNativeTitleBar)   styleFlags |= ComponentPeer::windowHasTitleBar;
 | 
			
		||||
 | 
			
		||||
    return styleFlags;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TopLevelWindow::setDropShadowEnabled (const bool useShadow)
 | 
			
		||||
{
 | 
			
		||||
    useDropShadow = useShadow;
 | 
			
		||||
 | 
			
		||||
    if (isOnDesktop())
 | 
			
		||||
    {
 | 
			
		||||
        shadower = nullptr;
 | 
			
		||||
        Component::addToDesktop (getDesktopWindowStyleFlags());
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        if (useShadow && isOpaque())
 | 
			
		||||
        {
 | 
			
		||||
            if (shadower == nullptr)
 | 
			
		||||
            {
 | 
			
		||||
                shadower = getLookAndFeel().createDropShadowerForComponent (*this);
 | 
			
		||||
 | 
			
		||||
                if (shadower != nullptr)
 | 
			
		||||
                    shadower->setOwner (this);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            shadower = nullptr;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TopLevelWindow::setUsingNativeTitleBar (const bool shouldUseNativeTitleBar)
 | 
			
		||||
{
 | 
			
		||||
    if (useNativeTitleBar != shouldUseNativeTitleBar)
 | 
			
		||||
    {
 | 
			
		||||
        FocusRestorer focusRestorer;
 | 
			
		||||
        useNativeTitleBar = shouldUseNativeTitleBar;
 | 
			
		||||
        recreateDesktopWindow();
 | 
			
		||||
        sendLookAndFeelChange();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TopLevelWindow::recreateDesktopWindow()
 | 
			
		||||
{
 | 
			
		||||
    if (isOnDesktop())
 | 
			
		||||
    {
 | 
			
		||||
        Component::addToDesktop (getDesktopWindowStyleFlags());
 | 
			
		||||
        toFront (true);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TopLevelWindow::addToDesktop()
 | 
			
		||||
{
 | 
			
		||||
    shadower = nullptr;
 | 
			
		||||
    Component::addToDesktop (getDesktopWindowStyleFlags());
 | 
			
		||||
    setDropShadowEnabled (isDropShadowEnabled()); // force an update to clear away any fake shadows if necessary.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TopLevelWindow::addToDesktop (int windowStyleFlags, void* nativeWindowToAttachTo)
 | 
			
		||||
{
 | 
			
		||||
    /* It's not recommended to change the desktop window flags directly for a TopLevelWindow,
 | 
			
		||||
       because this class needs to make sure its layout corresponds with settings like whether
 | 
			
		||||
       it's got a native title bar or not.
 | 
			
		||||
 | 
			
		||||
       If you need custom flags for your window, you can override the getDesktopWindowStyleFlags()
 | 
			
		||||
       method. If you do this, it's best to call the base class's getDesktopWindowStyleFlags()
 | 
			
		||||
       method, then add or remove whatever flags are necessary from this value before returning it.
 | 
			
		||||
    */
 | 
			
		||||
    jassert ((windowStyleFlags & ~ComponentPeer::windowIsSemiTransparent)
 | 
			
		||||
               == (getDesktopWindowStyleFlags() & ~ComponentPeer::windowIsSemiTransparent));
 | 
			
		||||
 | 
			
		||||
    Component::addToDesktop (windowStyleFlags, nativeWindowToAttachTo);
 | 
			
		||||
 | 
			
		||||
    if (windowStyleFlags != getDesktopWindowStyleFlags())
 | 
			
		||||
        sendLookAndFeelChange();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::unique_ptr<AccessibilityHandler> TopLevelWindow::createAccessibilityHandler()
 | 
			
		||||
{
 | 
			
		||||
    return std::make_unique<AccessibilityHandler> (*this, AccessibilityRole::window);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void TopLevelWindow::centreAroundComponent (Component* c, const int width, const int height)
 | 
			
		||||
{
 | 
			
		||||
    if (c == nullptr)
 | 
			
		||||
        c = TopLevelWindow::getActiveTopLevelWindow();
 | 
			
		||||
 | 
			
		||||
    if (c == nullptr || c->getBounds().isEmpty())
 | 
			
		||||
    {
 | 
			
		||||
        centreWithSize (width, height);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        const auto scale = getDesktopScaleFactor() / Desktop::getInstance().getGlobalScaleFactor();
 | 
			
		||||
 | 
			
		||||
        auto targetCentre = c->localPointToGlobal (c->getLocalBounds().getCentre()) / scale;
 | 
			
		||||
        auto parentArea = getLocalArea (nullptr, c->getParentMonitorArea());
 | 
			
		||||
 | 
			
		||||
        if (auto* parent = getParentComponent())
 | 
			
		||||
        {
 | 
			
		||||
            targetCentre = parent->getLocalPoint (nullptr, targetCentre);
 | 
			
		||||
            parentArea   = parent->getLocalBounds();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        setBounds (Rectangle<int> (targetCentre.x - width / 2,
 | 
			
		||||
                                   targetCentre.y - height / 2,
 | 
			
		||||
                                   width, height)
 | 
			
		||||
                     .constrainedWithin (parentArea.reduced (12, 12)));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
int TopLevelWindow::getNumTopLevelWindows() noexcept
 | 
			
		||||
{
 | 
			
		||||
    return TopLevelWindowManager::getInstance()->windows.size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TopLevelWindow* TopLevelWindow::getTopLevelWindow (const int index) noexcept
 | 
			
		||||
{
 | 
			
		||||
    return TopLevelWindowManager::getInstance()->windows [index];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TopLevelWindow* TopLevelWindow::getActiveTopLevelWindow() noexcept
 | 
			
		||||
{
 | 
			
		||||
    TopLevelWindow* best = nullptr;
 | 
			
		||||
    int bestNumTWLParents = -1;
 | 
			
		||||
 | 
			
		||||
    for (int i = TopLevelWindow::getNumTopLevelWindows(); --i >= 0;)
 | 
			
		||||
    {
 | 
			
		||||
        auto* tlw = TopLevelWindow::getTopLevelWindow (i);
 | 
			
		||||
 | 
			
		||||
        if (tlw->isActiveWindow())
 | 
			
		||||
        {
 | 
			
		||||
            int numTWLParents = 0;
 | 
			
		||||
 | 
			
		||||
            for (auto* c = tlw->getParentComponent(); c != nullptr; c = c->getParentComponent())
 | 
			
		||||
                if (dynamic_cast<const TopLevelWindow*> (c) != nullptr)
 | 
			
		||||
                    ++numTWLParents;
 | 
			
		||||
 | 
			
		||||
            if (bestNumTWLParents < numTWLParents)
 | 
			
		||||
            {
 | 
			
		||||
                best = tlw;
 | 
			
		||||
                bestNumTWLParents = numTWLParents;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return best;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,166 +1,166 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A base class for top-level windows.
 | 
			
		||||
 | 
			
		||||
    This class is used for components that are considered a major part of your
 | 
			
		||||
    application - e.g. ResizableWindow, DocumentWindow, DialogWindow, AlertWindow,
 | 
			
		||||
    etc. Things like menus that pop up briefly aren't derived from it.
 | 
			
		||||
 | 
			
		||||
    A TopLevelWindow is probably on the desktop, but this isn't mandatory - it
 | 
			
		||||
    could itself be the child of another component.
 | 
			
		||||
 | 
			
		||||
    The class manages a list of all instances of top-level windows that are in use,
 | 
			
		||||
    and each one is also given the concept of being "active". The active window is
 | 
			
		||||
    one that is actively being used by the user. This isn't quite the same as the
 | 
			
		||||
    component with the keyboard focus, because there may be a popup menu or other
 | 
			
		||||
    temporary window which gets keyboard focus while the active top level window is
 | 
			
		||||
    unchanged.
 | 
			
		||||
 | 
			
		||||
    A top-level window also has an optional drop-shadow.
 | 
			
		||||
 | 
			
		||||
    @see ResizableWindow, DocumentWindow, DialogWindow
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  TopLevelWindow  : public Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a TopLevelWindow.
 | 
			
		||||
 | 
			
		||||
        @param name                 the name to give the component
 | 
			
		||||
        @param addToDesktop         if true, the window will be automatically added to the
 | 
			
		||||
                                    desktop; if false, you can use it as a child component
 | 
			
		||||
    */
 | 
			
		||||
    TopLevelWindow (const String& name, bool addToDesktop);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~TopLevelWindow() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** True if this is currently the TopLevelWindow that is actively being used.
 | 
			
		||||
 | 
			
		||||
        This isn't quite the same as having keyboard focus, because the focus may be
 | 
			
		||||
        on a child component or a temporary pop-up menu, etc, while this window is
 | 
			
		||||
        still considered to be active.
 | 
			
		||||
 | 
			
		||||
        @see activeWindowStatusChanged
 | 
			
		||||
    */
 | 
			
		||||
    bool isActiveWindow() const noexcept                    { return isCurrentlyActive; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This will set the bounds of the window so that it's centred in front of another
 | 
			
		||||
        window.
 | 
			
		||||
 | 
			
		||||
        If your app has a few windows open and want to pop up a dialog box for one of
 | 
			
		||||
        them, you can use this to show it in front of the relevant parent window, which
 | 
			
		||||
        is a bit neater than just having it appear in the middle of the screen.
 | 
			
		||||
 | 
			
		||||
        If componentToCentreAround is nullptr, then the currently active TopLevelWindow will
 | 
			
		||||
        be used instead. If no window is focused, it'll just default to the middle of the
 | 
			
		||||
        screen.
 | 
			
		||||
    */
 | 
			
		||||
    void centreAroundComponent (Component* componentToCentreAround,
 | 
			
		||||
                                int width, int height);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Turns the drop-shadow on and off. */
 | 
			
		||||
    void setDropShadowEnabled (bool useShadow);
 | 
			
		||||
 | 
			
		||||
    /** True if drop-shadowing is enabled. */
 | 
			
		||||
    bool isDropShadowEnabled() const noexcept               { return useDropShadow; }
 | 
			
		||||
 | 
			
		||||
    /** Sets whether an OS-native title bar will be used, or a JUCE one.
 | 
			
		||||
        @see isUsingNativeTitleBar
 | 
			
		||||
    */
 | 
			
		||||
    void setUsingNativeTitleBar (bool useNativeTitleBar);
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the window is currently using an OS-native title bar.
 | 
			
		||||
        @see setUsingNativeTitleBar
 | 
			
		||||
    */
 | 
			
		||||
    bool isUsingNativeTitleBar() const noexcept;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the number of TopLevelWindow objects currently in use.
 | 
			
		||||
        @see getTopLevelWindow
 | 
			
		||||
    */
 | 
			
		||||
    static int getNumTopLevelWindows() noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns one of the TopLevelWindow objects currently in use.
 | 
			
		||||
        The index is 0 to (getNumTopLevelWindows() - 1).
 | 
			
		||||
    */
 | 
			
		||||
    static TopLevelWindow* getTopLevelWindow (int index) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns the currently-active top level window.
 | 
			
		||||
        There might not be one, of course, so this can return nullptr.
 | 
			
		||||
    */
 | 
			
		||||
    static TopLevelWindow* getActiveTopLevelWindow() noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Adds the window to the desktop using the default flags. */
 | 
			
		||||
    void addToDesktop();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void addToDesktop (int windowStyleFlags, void* nativeWindowToAttachTo = nullptr) override;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This callback happens when this window becomes active or inactive.
 | 
			
		||||
        @see isActiveWindow
 | 
			
		||||
    */
 | 
			
		||||
    virtual void activeWindowStatusChanged();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void focusOfChildComponentChanged (FocusChangeType) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void parentHierarchyChanged() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    virtual int getDesktopWindowStyleFlags() const;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void recreateDesktopWindow();
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void visibilityChanged() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    friend class TopLevelWindowManager;
 | 
			
		||||
    friend class ResizableWindow;
 | 
			
		||||
    bool useDropShadow = true, useNativeTitleBar = false, isCurrentlyActive = false;
 | 
			
		||||
    std::unique_ptr<DropShadower> shadower;
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override;
 | 
			
		||||
    void setWindowActive (bool);
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TopLevelWindow)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - 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 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-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
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A base class for top-level windows.
 | 
			
		||||
 | 
			
		||||
    This class is used for components that are considered a major part of your
 | 
			
		||||
    application - e.g. ResizableWindow, DocumentWindow, DialogWindow, AlertWindow,
 | 
			
		||||
    etc. Things like menus that pop up briefly aren't derived from it.
 | 
			
		||||
 | 
			
		||||
    A TopLevelWindow is probably on the desktop, but this isn't mandatory - it
 | 
			
		||||
    could itself be the child of another component.
 | 
			
		||||
 | 
			
		||||
    The class manages a list of all instances of top-level windows that are in use,
 | 
			
		||||
    and each one is also given the concept of being "active". The active window is
 | 
			
		||||
    one that is actively being used by the user. This isn't quite the same as the
 | 
			
		||||
    component with the keyboard focus, because there may be a popup menu or other
 | 
			
		||||
    temporary window which gets keyboard focus while the active top level window is
 | 
			
		||||
    unchanged.
 | 
			
		||||
 | 
			
		||||
    A top-level window also has an optional drop-shadow.
 | 
			
		||||
 | 
			
		||||
    @see ResizableWindow, DocumentWindow, DialogWindow
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  TopLevelWindow  : public Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a TopLevelWindow.
 | 
			
		||||
 | 
			
		||||
        @param name                 the name to give the component
 | 
			
		||||
        @param addToDesktop         if true, the window will be automatically added to the
 | 
			
		||||
                                    desktop; if false, you can use it as a child component
 | 
			
		||||
    */
 | 
			
		||||
    TopLevelWindow (const String& name, bool addToDesktop);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~TopLevelWindow() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** True if this is currently the TopLevelWindow that is actively being used.
 | 
			
		||||
 | 
			
		||||
        This isn't quite the same as having keyboard focus, because the focus may be
 | 
			
		||||
        on a child component or a temporary pop-up menu, etc, while this window is
 | 
			
		||||
        still considered to be active.
 | 
			
		||||
 | 
			
		||||
        @see activeWindowStatusChanged
 | 
			
		||||
    */
 | 
			
		||||
    bool isActiveWindow() const noexcept                    { return isCurrentlyActive; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This will set the bounds of the window so that it's centred in front of another
 | 
			
		||||
        window.
 | 
			
		||||
 | 
			
		||||
        If your app has a few windows open and want to pop up a dialog box for one of
 | 
			
		||||
        them, you can use this to show it in front of the relevant parent window, which
 | 
			
		||||
        is a bit neater than just having it appear in the middle of the screen.
 | 
			
		||||
 | 
			
		||||
        If componentToCentreAround is nullptr, then the currently active TopLevelWindow will
 | 
			
		||||
        be used instead. If no window is focused, it'll just default to the middle of the
 | 
			
		||||
        screen.
 | 
			
		||||
    */
 | 
			
		||||
    void centreAroundComponent (Component* componentToCentreAround,
 | 
			
		||||
                                int width, int height);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Turns the drop-shadow on and off. */
 | 
			
		||||
    void setDropShadowEnabled (bool useShadow);
 | 
			
		||||
 | 
			
		||||
    /** True if drop-shadowing is enabled. */
 | 
			
		||||
    bool isDropShadowEnabled() const noexcept               { return useDropShadow; }
 | 
			
		||||
 | 
			
		||||
    /** Sets whether an OS-native title bar will be used, or a JUCE one.
 | 
			
		||||
        @see isUsingNativeTitleBar
 | 
			
		||||
    */
 | 
			
		||||
    void setUsingNativeTitleBar (bool useNativeTitleBar);
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the window is currently using an OS-native title bar.
 | 
			
		||||
        @see setUsingNativeTitleBar
 | 
			
		||||
    */
 | 
			
		||||
    bool isUsingNativeTitleBar() const noexcept;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the number of TopLevelWindow objects currently in use.
 | 
			
		||||
        @see getTopLevelWindow
 | 
			
		||||
    */
 | 
			
		||||
    static int getNumTopLevelWindows() noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns one of the TopLevelWindow objects currently in use.
 | 
			
		||||
        The index is 0 to (getNumTopLevelWindows() - 1).
 | 
			
		||||
    */
 | 
			
		||||
    static TopLevelWindow* getTopLevelWindow (int index) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns the currently-active top level window.
 | 
			
		||||
        There might not be one, of course, so this can return nullptr.
 | 
			
		||||
    */
 | 
			
		||||
    static TopLevelWindow* getActiveTopLevelWindow() noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Adds the window to the desktop using the default flags. */
 | 
			
		||||
    void addToDesktop();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void addToDesktop (int windowStyleFlags, void* nativeWindowToAttachTo = nullptr) override;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This callback happens when this window becomes active or inactive.
 | 
			
		||||
        @see isActiveWindow
 | 
			
		||||
    */
 | 
			
		||||
    virtual void activeWindowStatusChanged();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void focusOfChildComponentChanged (FocusChangeType) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void parentHierarchyChanged() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    virtual int getDesktopWindowStyleFlags() const;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void recreateDesktopWindow();
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void visibilityChanged() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    friend class TopLevelWindowManager;
 | 
			
		||||
    friend class ResizableWindow;
 | 
			
		||||
    bool useDropShadow = true, useNativeTitleBar = false, isCurrentlyActive = false;
 | 
			
		||||
    std::unique_ptr<DropShadower> shadower;
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override;
 | 
			
		||||
    void setWindowActive (bool);
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TopLevelWindow)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user