text:
/*
  ==============================================================================

   This file is part of the JUCE library.
   Copyright (c) 2017 - ROLI Ltd.

   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 5 End-User License
   Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
   27th April 2017).

   End User License Agreement: www.juce.com/juce-5-licence
   Privacy Policy: www.juce.com/juce-5-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
{

static juce_wchar getDefaultPasswordChar() noexcept
{
   #if JUCE_LINUX
    return 0x2022;
   #else
    return 0x25cf;
   #endif
}

//==============================================================================
AlertWindow::AlertWindow (const String& title,
                          const String& message,
                          AlertIconType iconType,
                          Component* comp)
   : TopLevelWindow (title, true),
     alertIconType (iconType),
     associatedComponent (comp)
{
    setAlwaysOnTop (juce_areThereAnyAlwaysOnTopWindows());

    if (message.isEmpty())
        text = " "; // to force an update if the message is empty

    setMessage (message);

    AlertWindow::lookAndFeelChanged();
    constrainer.setMinimumOnscreenAmounts (0x10000, 0x10000, 0x10000, 0x10000);
}

AlertWindow::~AlertWindow()
{
    removeAllChildren();
}

void AlertWindow::userTriedToCloseWindow()
{
    if (escapeKeyCancels || buttons.size() > 0)
        exitModalState (0);
}

//==============================================================================
void AlertWindow::setMessage (const String& message)
{
    auto newMessage = message.substring (0, 2048);

    if (text != newMessage)
    {
        text = newMessage;
        updateLayout (true);
        repaint();
    }
}

//==============================================================================
void AlertWindow::buttonClicked (Button* button)
{
    if (auto* parent = button->getParentComponent())
        parent->exitModalState (button->getCommandID());
}

//==============================================================================
void AlertWindow::addButton (const String& name,
                             const int returnValue,
                             const KeyPress& shortcutKey1,
                             const KeyPress& shortcutKey2)
{
    auto* b = new TextButton (name, {});
    buttons.add (b);

    b->setWantsKeyboardFocus (true);
    b->setMouseClickGrabsKeyboardFocus (false);
    b->setCommandToTrigger (0, returnValue, false);
    b->addShortcut (shortcutKey1);
    b->addShortcut (shortcutKey2);
    b->addListener (this);

    Array<TextButton*> buttonsArray (buttons.begin(), buttons.size());
    auto& lf = getLookAndFeel();

    auto buttonHeight = lf.getAlertWindowButtonHeight();
    auto buttonWidths = lf.getWidthsForTextButtons (*this, buttonsArray);

    jassert (buttonWidths.size() == buttons.size());
    int i = 0;

    for (auto* button : buttons)
        button->setSize (buttonWidths[i++], buttonHeight);

    addAndMakeVisible (b, 0);
    updateLayout (false);
}

int AlertWindow::getNumButtons() const
{
    return buttons.size();
}

void AlertWindow::triggerButtonClick (const String& buttonName)
{
    for (auto* b : buttons)
    {
        if (buttonName == b->getName())
        {
            b->triggerClick();
            break;
        }
    }
}

void AlertWindow::setEscapeKeyCancels (bool shouldEscapeKeyCancel)
{
    escapeKeyCancels = shouldEscapeKeyCancel;
}

//==============================================================================
void AlertWindow::addTextEditor (const String& name,
                                 const String& initialContents,
                                 const String& onScreenLabel,
                                 const bool isPasswordBox)
{
    auto* ed = new TextEditor (name, isPasswordBox ? getDefaultPasswordChar() : 0);
    ed->setSelectAllWhenFocused (true);
    ed->setEscapeAndReturnKeysConsumed (false);
    textBoxes.add (ed);
    allComps.add (ed);

    ed->setColour (TextEditor::outlineColourId, findColour (ComboBox::outlineColourId));
    ed->setFont (getLookAndFeel().getAlertWindowMessageFont());
    addAndMakeVisible (ed);
    ed->setText (initialContents);
    ed->setCaretPosition (initialContents.length());
    textboxNames.add (onScreenLabel);

    updateLayout (false);
}

TextEditor* AlertWindow::getTextEditor (const String& nameOfTextEditor) const
{
    for (auto* tb : textBoxes)
        if (tb->getName() == nameOfTextEditor)
            return tb;

    return nullptr;
}

String AlertWindow::getTextEditorContents (const String& nameOfTextEditor) const
{
    if (auto* t = getTextEditor (nameOfTextEditor))
        return t->getText();

    return {};
}

//==============================================================================
void AlertWindow::addComboBox (const String& name,
                               const StringArray& items,
                               const String& onScreenLabel)
{
    auto* cb = new ComboBox (name);
    comboBoxes.add (cb);
    allComps.add (cb);

    cb->addItemList (items, 1);

    addAndMakeVisible (cb);
    cb->setSelectedItemIndex (0);

    comboBoxNames.add (onScreenLabel);
    updateLayout (false);
}

ComboBox* AlertWindow::getComboBoxComponent (const String& nameOfList) const
{
    for (auto* cb : comboBoxes)
        if (cb->getName() == nameOfList)
            return cb;

    return nullptr;
}

//==============================================================================
class AlertTextComp  : public TextEditor
{
public:
    AlertTextComp (AlertWindow& owner, const String& message, const Font& font)
    {
        if (owner.isColourSpecified (AlertWindow::textColourId))
            setColour (TextEditor::textColourId, owner.findColour (AlertWindow::textColourId));

        setColour (TextEditor::backgroundColourId, Colours::transparentBlack);
        setColour (TextEditor::outlineColourId, Colours::transparentBlack);
        setColour (TextEditor::shadowColourId, Colours::transparentBlack);

        setReadOnly (true);
        setMultiLine (true, true);
        setCaretVisible (false);
        setScrollbarsShown (true);
        lookAndFeelChanged();
        setWantsKeyboardFocus (false);
        setFont (font);
        setText (message, false);

        bestWidth = 2 * (int) std::sqrt (font.getHeight() * font.getStringWidth (message));
    }

    void updateLayout (const int width)
    {
        AttributedString s;
        s.setJustification (Justification::topLeft);
        s.append (getText(), getFont());

        TextLayout text;
        text.createLayoutWithBalancedLineLengths (s, width - 8.0f);
        setSize (width, jmin (width, (int) (text.getHeight() + getFont().getHeight())));
    }

    int bestWidth;

    JUCE_DECLARE_NON_COPYABLE (AlertTextComp)
};

void AlertWindow::addTextBlock (const String& textBlock)
{
    auto* c = new AlertTextComp (*this, textBlock, getLookAndFeel().getAlertWindowMessageFont());
    textBlocks.add (c);
    allComps.add (c);
    addAndMakeVisible (c);

    updateLayout (false);
}

//==============================================================================
void AlertWindow::addProgressBarComponent (double& progressValue)
{
    auto* pb = new ProgressBar (progressValue);
    progressBars.add (pb);
    allComps.add (pb);
    addAndMakeVisible (pb);

    updateLayout (false);
}

//==============================================================================
void AlertWindow::addCustomComponent (Component* const component)
{
    customComps.add (component);
    allComps.add (component);
    addAndMakeVisible (component);

    updateLayout (false);
}

int AlertWindow::getNumCustomComponents() const                 { return customComps.size(); }
Component* AlertWindow::getCustomComponent (int index) const    { return customComps [index]; }

Component* AlertWindow::removeCustomComponent (const int index)
{
    auto* c = getCustomComponent (index);

    if (c != nullptr)
    {
        customComps.removeFirstMatchingValue (c);
        allComps.removeFirstMatchingValue (c);
        removeChildComponent (c);

        updateLayout (false);
    }

    return c;
}

//==============================================================================
void AlertWindow::paint (Graphics& g)
{
    auto& lf = getLookAndFeel();
    lf.drawAlertBox (g, *this, textArea, textLayout);

    g.setColour (findColour (textColourId));
    g.setFont (lf.getAlertWindowFont());

    for (int i = textBoxes.size(); --i >= 0;)
    {
        auto* te = textBoxes.getUnchecked(i);

        g.drawFittedText (textboxNames[i],
                          te->getX(), te->getY() - 14,
                          te->getWidth(), 14,
                          Justification::centredLeft, 1);
    }

    for (int i = comboBoxNames.size(); --i >= 0;)
    {
        auto* cb = comboBoxes.getUnchecked(i);

        g.drawFittedText (comboBoxNames[i],
                          cb->getX(), cb->getY() - 14,
                          cb->getWidth(), 14,
                          Justification::centredLeft, 1);
    }

    for (auto* c : customComps)
        g.drawFittedText (c->getName(),
                          c->getX(), c->getY() - 14,
                          c->getWidth(), 14,
                          Justification::centredLeft, 1);
}

void AlertWindow::updateLayout (const bool onlyIncreaseSize)
{
    const int titleH = 24;
    const int iconWidth = 80;

    auto& lf = getLookAndFeel();
    auto messageFont (lf.getAlertWindowMessageFont());

    auto wid = jmax (messageFont.getStringWidth (text),
                     messageFont.getStringWidth (getName()));

    auto sw = (int) std::sqrt (messageFont.getHeight() * wid);
    auto w = jmin (300 + sw * 2, (int) (getParentWidth() * 0.7f));
    const int edgeGap = 10;
    const int labelHeight = 18;
    int iconSpace = 0;

    AttributedString attributedText;
    attributedText.append (getName(), lf.getAlertWindowTitleFont());

    if (text.isNotEmpty())
        attributedText.append ("\n\n" + text, messageFont);

    attributedText.setColour (findColour (textColourId));

    if (alertIconType == NoIcon)
    {
        attributedText.setJustification (Justification::centredTop);
        textLayout.createLayoutWithBalancedLineLengths (attributedText, (float) w);
    }
    else
    {
        attributedText.setJustification (Justification::topLeft);
        textLayout.createLayoutWithBalancedLineLengths (attributedText, (float) w);
        iconSpace = iconWidth;
    }

    w = jmax (350, (int) textLayout.getWidth() + iconSpace + edgeGap * 4);
    w = jmin (w, (int) (getParentWidth() * 0.7f));

    auto textLayoutH = (int) textLayout.getHeight();
    auto textBottom = 16 + titleH + textLayoutH;
    int h = textBottom;

    int buttonW = 40;

    for (auto* b : buttons)
        buttonW += 16 + b->getWidth();

    w = jmax (buttonW, w);

    h += (textBoxes.size() + comboBoxes.size() + progressBars.size()) * 50;

    if (auto* b = buttons[0])
        h += 20 + b->getHeight();

    for (auto* c : customComps)
    {
        w = jmax (w, (c->getWidth() * 100) / 80);
        h += 10 + c->getHeight();

        if (c->getName().isNotEmpty())
            h += labelHeight;
    }

    for (auto* tb : textBlocks)
        w = jmax (w, static_cast<const AlertTextComp*> (tb)->bestWidth);

    w = jmin (w, (int) (getParentWidth() * 0.7f));

    for (auto* tb : textBlocks)
    {
        auto* ac = static_cast<AlertTextComp*> (tb);
        ac->updateLayout ((int) (w * 0.8f));
        h += ac->getHeight() + 10;
    }

    h = jmin (getParentHeight() - 50, h);

    if (onlyIncreaseSize)
    {
        w = jmax (w, getWidth());
        h = jmax (h, getHeight());
    }

    if (! isVisible())
        centreAroundComponent (associatedComponent, w, h);
    else
        setBounds (getBounds().withSizeKeepingCentre (w, h));

    textArea.setBounds (edgeGap, edgeGap, w - (edgeGap * 2), h - edgeGap);

    const int spacer = 16;
    int totalWidth = -spacer;

    for (auto* b : buttons)
        totalWidth += b->getWidth() + spacer;

    auto x = (w - totalWidth) / 2;
    auto y = (int) (getHeight() * 0.95f);

    for (auto* c : buttons)
    {
        int ny = proportionOfHeight (0.95f) - c->getHeight();
        c->setTopLeftPosition (x, ny);
        if (ny < y)
            y = ny;

        x += c->getWidth() + spacer;

        c->toFront (false);
    }

    y = textBottom;

    for (auto* c : allComps)
    {
        h = 22;

        const int comboIndex = comboBoxes.indexOf (dynamic_cast<ComboBox*> (c));
        if (comboIndex >= 0 && comboBoxNames [comboIndex].isNotEmpty())
            y += labelHeight;

        const int tbIndex = textBoxes.indexOf (dynamic_cast<TextEditor*> (c));
        if (tbIndex >= 0 && textboxNames[tbIndex].isNotEmpty())
            y += labelHeight;

        if (customComps.contains (c))
        {
            if (c->getName().isNotEmpty())
                y += labelHeight;

            c->setTopLeftPosition (proportionOfWidth (0.1f), y);
            h = c->getHeight();
        }
        else if (textBlocks.contains (c))
        {
            c->setTopLeftPosition ((getWidth() - c->getWidth()) / 2, y);
            h = c->getHeight();
        }
        else
        {
            c->setBounds (proportionOfWidth (0.1f), y, proportionOfWidth (0.8f), h);
        }

        y += h + 10;
    }

    setWantsKeyboardFocus (getNumChildComponents() == 0);
}

bool AlertWindow::containsAnyExtraComponents() const
{
    return allComps.size() > 0;
}

//==============================================================================
void AlertWindow::mouseDown (const MouseEvent& e)
{
    dragger.startDraggingComponent (this, e);
}

void AlertWindow::mouseDrag (const MouseEvent& e)
{
    dragger.dragComponent (this, e, &constrainer);
}

bool AlertWindow::keyPressed (const KeyPress& key)
{
    for (auto* b : buttons)
    {
        if (b->isRegisteredForShortcut (key))
        {
            b->triggerClick();
            return true;
        }
    }

    if (key.isKeyCode (KeyPress::escapeKey) && escapeKeyCancels && buttons.size() == 0)
    {
        exitModalState (0);
        return true;
    }

    if (key.isKeyCode (KeyPress::returnKey) && buttons.size() == 1)
    {
        buttons.getUnchecked(0)->triggerClick();
        return true;
    }

    return false;
}

void AlertWindow::lookAndFeelChanged()
{
    const int newFlags = getLookAndFeel().getAlertBoxWindowFlags();

    setUsingNativeTitleBar ((newFlags & ComponentPeer::windowHasTitleBar) != 0);
    setDropShadowEnabled (isOpaque() && (newFlags & ComponentPeer::windowHasDropShadow) != 0);
    updateLayout (false);
}

int AlertWindow::getDesktopWindowStyleFlags() const
{
    return getLookAndFeel().getAlertBoxWindowFlags();
}

//==============================================================================
class AlertWindowInfo
{
public:
    AlertWindowInfo (const String& t, const String& m, Component* component,
                     AlertWindow::AlertIconType icon, int numButts,
                     ModalComponentManager::Callback* cb, bool runModally)
        : title (t), message (m), iconType (icon), numButtons (numButts),
          associatedComponent (component), callback (cb), modal (runModally)
    {
    }

    String title, message, button1, button2, button3;

    int invoke() const
    {
        MessageManager::getInstance()->callFunctionOnMessageThread (showCallback, (void*) this);
        return returnValue;
    }

private:
    AlertWindow::AlertIconType iconType;
    int numButtons, returnValue = 0;
    WeakReference<Component> associatedComponent;
    ModalComponentManager::Callback* callback;
    bool modal;

    void show()
    {
        auto& lf = associatedComponent != nullptr ? associatedComponent->getLookAndFeel()
                                                  : LookAndFeel::getDefaultLookAndFeel();

        ScopedPointer<Component> alertBox (lf.createAlertWindow (title, message, button1, button2, button3,
                                                                 iconType, numButtons, associatedComponent));

        jassert (alertBox != nullptr); // you have to return one of these!

        alertBox->setAlwaysOnTop (juce_areThereAnyAlwaysOnTopWindows());

       #if JUCE_MODAL_LOOPS_PERMITTED
        if (modal)
        {
            returnValue = alertBox->runModalLoop();
        }
        else
       #endif
        {
            ignoreUnused (modal);

            alertBox->enterModalState (true, callback, true);
            alertBox.release();
        }
    }

    static void* showCallback (void* userData)
    {
        static_cast<AlertWindowInfo*> (userData)->show();
        return nullptr;
    }
};

#if JUCE_MODAL_LOOPS_PERMITTED
void AlertWindow::showMessageBox (AlertIconType iconType,
                                  const String& title,
                                  const String& message,
                                  const String& buttonText,
                                  Component* associatedComponent)
{
    if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows())
    {
        NativeMessageBox::showMessageBox (iconType, title, message, associatedComponent);
    }
    else
    {
        AlertWindowInfo info (title, message, associatedComponent, iconType, 1, nullptr, true);
        info.button1 = buttonText.isEmpty() ? TRANS("OK") : buttonText;

        info.invoke();
    }
}
#endif

void AlertWindow::showMessageBoxAsync (AlertIconType iconType,
                                       const String& title,
                                       const String& message,
                                       const String& buttonText,
                                       Component* associatedComponent,
                                       ModalComponentManager::Callback* callback)
{
    if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows())
    {
        NativeMessageBox::showMessageBoxAsync (iconType, title, message, associatedComponent, callback);
    }
    else
    {
        AlertWindowInfo info (title, message, associatedComponent, iconType, 1, callback, false);
        info.button1 = buttonText.isEmpty() ? TRANS("OK") : buttonText;

        info.invoke();
    }
}

bool AlertWindow::showOkCancelBox (AlertIconType iconType,
                                   const String& title,
                                   const String& message,
                                   const String& button1Text,
                                   const String& button2Text,
                                   Component* associatedComponent,
                                   ModalComponentManager::Callback* callback)
{
    if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows())
        return NativeMessageBox::showOkCancelBox (iconType, title, message, associatedComponent, callback);

    AlertWindowInfo info (title, message, associatedComponent, iconType, 2, callback, callback == nullptr);
    info.button1 = button1Text.isEmpty() ? TRANS("OK")     : button1Text;
    info.button2 = button2Text.isEmpty() ? TRANS("Cancel") : button2Text;

    return info.invoke() != 0;
}

int AlertWindow::showYesNoCancelBox (AlertIconType iconType,
                                     const String& title,
                                     const String& message,
                                     const String& button1Text,
                                     const String& button2Text,
                                     const String& button3Text,
                                     Component* associatedComponent,
                                     ModalComponentManager::Callback* callback)
{
    if (LookAndFeel::getDefaultLookAndFeel().isUsingNativeAlertWindows())
        return NativeMessageBox::showYesNoCancelBox (iconType, title, message, associatedComponent, callback);

    AlertWindowInfo info (title, message, associatedComponent, iconType, 3, callback, callback == nullptr);
    info.button1 = button1Text.isEmpty() ? TRANS("Yes")     : button1Text;
    info.button2 = button2Text.isEmpty() ? TRANS("No")      : button2Text;
    info.button3 = button3Text.isEmpty() ? TRANS("Cancel")  : button3Text;

    return info.invoke();
}

#if JUCE_MODAL_LOOPS_PERMITTED
bool AlertWindow::showNativeDialogBox (const String& title,
                                       const String& bodyText,
                                       bool isOkCancel)
{
    if (isOkCancel)
        return NativeMessageBox::showOkCancelBox (AlertWindow::NoIcon, title, bodyText);

    NativeMessageBox::showMessageBox (AlertWindow::NoIcon, title, bodyText);
    return true;
}
#endif

} // namespace juce


text:
/*
  ==============================================================================

   This file is part of the JUCE library.
   Copyright (c) 2017 - ROLI Ltd.

   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 5 End-User License
   Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
   27th April 2017).

   End User License Agreement: www.juce.com/juce-5-licence
   Privacy Policy: www.juce.com/juce-5-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.
*/
class NativeMessageBox
{
public:
    /** 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.
    */
   #if JUCE_MODAL_LOOPS_PERMITTED
    static void JUCE_CALLTYPE showMessageBox (AlertWindow::AlertIconType iconType,
                                              const String& title,
                                              const String& message,
                                              Component* associatedComponent = nullptr);
   #endif

    /** 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 (AlertWindow::AlertIconType 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, 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 (AlertWindow::AlertIconType 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, 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 (AlertWindow::AlertIconType 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, 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 (AlertWindow::AlertIconType 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() JUCE_DELETED_FUNCTION;
    JUCE_DECLARE_NON_COPYABLE (NativeMessageBox)
};

} // namespace juce

repo_name: fedden/RenderMan

mime_type: text/x-c++


text:
/*
  ==============================================================================

   This file is part of the JUCE library.
   Copyright (c) 2017 - ROLI Ltd.

   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 5 End-User License
   Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
   27th April 2017).

   End User License Agreement: www.juce.com/juce-5-licence
   Privacy Policy: www.juce.com/juce-5-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
*/
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();

    //==============================================================================
    /** 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 contraints 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. */
    };

    //==============================================================================
    // Deprecated: use setContentOwned() and setContentNonOwned() instead.
    JUCE_DEPRECATED (void setContentComponent (Component* newContentComponent,
                                               bool deleteOldOne = true,
                                               bool resizeToFit = false));
    using TopLevelWindow::addToDesktop;

    //==============================================================================
    /** This abstract base class is implemented by LookAndFeel classes to provide
        window drawing functionality.
    */
    struct JUCE_API  LookAndFeelMethods
    {
        virtual ~LookAndFeelMethods() {}

        //==============================================================================
        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

    ScopedPointer<ResizableCornerComponent> resizableCorner;
    ScopedPointer<ResizableBorderComponent> resizableBorder;

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();

   #if JUCE_CATCH_DEPRECATED_CODE_MISUSE
    // The parameters for these methods have changed - please update your code!
    JUCE_DEPRECATED (void getBorderThickness (int& left, int& top, int& right, int& bottom));
    JUCE_DEPRECATED (void getContentComponentBorder (int& left, int& top, int& right, int& bottom));
   #endif

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ResizableWindow)
};

} // namespace juce


text:
/*
  ==============================================================================

   This file is part of the JUCE library.
   Copyright (c) 2017 - ROLI Ltd.

   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 5 End-User License
   Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
   27th April 2017).

   End User License Agreement: www.juce.com/juce-5-licence
   Privacy Policy: www.juce.com/juce-5-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
{

/*
  ==============================================================================

   In accordance with the terms of the JUCE 5 End-Use License Agreement, the
   JUCE Code in SECTION A cannot be removed, changed or otherwise rendered
   ineffective unless you have a JUCE Indie or Pro license, or are using JUCE
   under the GPL v3 license.

   End User License Agreement: www.juce.com/juce-5-licence
  ==============================================================================
*/

// BEGIN SECTION A

#if ! defined (JUCE_REPORT_APP_USAGE)
 #define JUCE_REPORT_APP_USAGE 1
#endif

#if ! defined (JUCE_DISPLAY_SPLASH_SCREEN)
 #define JUCE_DISPLAY_SPLASH_SCREEN 1
#endif

#if ! defined (JUCE_USE_DARK_SPLASH_SCREEN)
 #define JUCE_USE_DARK_SPLASH_SCREEN 1
#endif

static const int millisecondsToDisplaySplash = 2000, splashScreenFadeOutTime = 2000;
static const int splashScreenLogoWidth = 123, splashScreenLogoHeight = 63;
static uint32 splashDisplayTime = 0;
static bool appUsageReported = false;

static Rectangle<float> getLogoArea (Rectangle<float> parentRect)
{
    return parentRect.reduced (6.0f)
                     .removeFromRight  ((float) splashScreenLogoWidth)
                     .removeFromBottom ((float) splashScreenLogoHeight);
}

//==============================================================================
struct ReportingThread;

struct ReportingThreadContainer  : public ChangeListener,
                                   public DeletedAtShutdown
{
    void sendReport (String, String&, StringPairArray&);
    void changeListenerCallback (ChangeBroadcaster*) override;

    ScopedPointer<ReportingThread> reportingThread;

    juce_DeclareSingleton_SingleThreaded_Minimal (ReportingThreadContainer)
};

juce_ImplementSingleton_SingleThreaded (ReportingThreadContainer)

//==============================================================================
struct ReportingThread  : public Thread,
                          private ChangeBroadcaster
{
    ReportingThread (ReportingThreadContainer& container,
                     String& address,
                     String& userAgent,
                     StringPairArray& parameters)
        : Thread ("JUCE app usage reporting"),
          threadContainer (container),
          headers ("User-Agent: " + userAgent)
    {
        StringArray postData;

        for (auto& key : parameters.getAllKeys())
            if (parameters[key].isNotEmpty())
                postData.add (key + "=" + URL::addEscapeChars (parameters[key], true));

        url = URL (address).withPOSTData (postData.joinIntoString ("&"));

        addChangeListener (&threadContainer);
    }

    ~ReportingThread()
    {
        removeChangeListener (&threadContainer);

        if (webStream != nullptr)
            webStream->cancel();

        stopThread (2000);
    }

    void run() override
    {
        webStream = new WebInputStream (url, true);
        webStream->withExtraHeaders (headers);
        webStream->connect (nullptr);

        sendChangeMessage();
    }

private:
    ReportingThreadContainer& threadContainer;
    URL url;
    String headers;
    ScopedPointer<WebInputStream> webStream;
};

//==============================================================================
void ReportingThreadContainer::sendReport (String address, String& userAgent, StringPairArray& parameters)
{
    reportingThread = new ReportingThread (*this, address, userAgent, parameters);

    reportingThread->startThread();
}

void ReportingThreadContainer::changeListenerCallback (ChangeBroadcaster*)
{
    reportingThread = nullptr;
}

//==============================================================================
JUCESplashScreen::JUCESplashScreen (Component& parent)
{
    ignoreUnused (hasStartedFading);
    ignoreUnused (parent);

   #if JUCE_REPORT_APP_USAGE
    if (! appUsageReported)
    {
        const ScopedTryLock appUsageReportingLock (appUsageReporting);

        if (appUsageReportingLock.isLocked() && ! appUsageReported)
        {
            const auto deviceDescription = SystemStats::getDeviceDescription();
            const auto deviceString = SystemStats::getDeviceIdentifiers().joinIntoString (":");
            const auto deviceIdentifier = String::toHexString (deviceString.hashCode64());
            const auto osName = SystemStats::getOperatingSystemName();

            StringPairArray data;

            data.set ("v",   "1");
            data.set ("tid", "UA-19759318-3");
            data.set ("cid", deviceIdentifier);
            data.set ("t",   "event");
            data.set ("ec",  "info");
            data.set ("ea",  "appStarted");

            data.set ("cd1", SystemStats::getJUCEVersion());
            data.set ("cd2", osName);
            data.set ("cd3", deviceDescription);
            data.set ("cd4", deviceIdentifier);

            String appType, appName, appVersion, appManufacturer;

           #if defined(JucePlugin_Name)
            appType         = "Plugin";
            appName         = JucePlugin_Name;
            appVersion      = JucePlugin_VersionString;
            appManufacturer = JucePlugin_Manufacturer;
           #else
            if (JUCEApplicationBase::isStandaloneApp())
            {
                appType = "Application";

                if (auto* app = JUCEApplicationBase::getInstance())
                {
                    appName    = app->getApplicationName();
                    appVersion = app->getApplicationVersion();
                }
            }
            else
            {
                appType = "Library";
            }
           #endif

            data.set ("cd5", appType);
            data.set ("cd6", appName);
            data.set ("cd7", appVersion);
            data.set ("cd8", appManufacturer);

            data.set ("an", appName);
            data.set ("av", appVersion);

            auto agentCPUVendor = SystemStats::getCpuVendor();

            if (agentCPUVendor.isEmpty())
                agentCPUVendor = "CPU";

            auto agentOSName = osName.replaceCharacter ('.', '_')
                                     .replace ("iOS", "iPhone OS");
           #if JUCE_IOS
            agentOSName << " like Mac OS X";
           #endif

            String userAgent;
            userAgent << "Mozilla/5.0 ("
                      << deviceDescription << ";"
                      << agentCPUVendor << " " << agentOSName << ";"
                      << SystemStats::getDisplayLanguage() << ")";

            ReportingThreadContainer::getInstance()->sendReport ("https://www.google-analytics.com/collect", userAgent, data);

            appUsageReported = true;
        }
    }
   #else
    ignoreUnused (appUsageReported);
   #endif

   #if JUCE_DISPLAY_SPLASH_SCREEN
    if (splashDisplayTime == 0
         || Time::getMillisecondCounter() < splashDisplayTime + (uint32) millisecondsToDisplaySplash)
    {
        content = getSplashScreenLogo();

        setAlwaysOnTop (true);
        parent.addAndMakeVisible (this);
    }
    else
   #endif
    {
        startTimer (1);
    }
}

JUCESplashScreen::~JUCESplashScreen()
{
}

Drawable* JUCESplashScreen::getSplashScreenLogo()
{
    const char* svgData = R"JUCESPLASHSCREEN(
      <?xml version="1.0" encoding="UTF-8"?>
      <svg width="123px" height="63px" viewBox="0 0 123 63" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
        <defs>
          <rect id="path-1" x="0.253112033" y="0.253112033" width="122" height="62" rx="10"></rect>
        </defs>
        <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" opacity="0.8">
          <mask id="mask-2" fill="white">
            <use xlink:href="#path-1"></use>
          </mask>
          <rect stroke="#B144C8" stroke-width="2" x="1.25311203" y="1.25311203" width="120" height="60" rx="10" fill=")JUCESPLASHSCREEN"
   #if JUCE_USE_DARK_SPLASH_SCREEN
    "#000000"
   #else
    "#FFFFFF"
   #endif
    "\"></rect>"
    R"JUCESPLASHSCREEN(
        <g id="Slice" mask="url(#mask-2)" fill="#B144C8" transform="translate(6.000000, 14.000000)">
          <path d="M17.728338,35.4569627 C7.9530089,35.4569627 0,27.5039538 0,17.7286247 C0,7.95303496 7.9530089,2.60592054e-05 17.728338,2.60592054e-05 C27.5039277,2.60592054e-05 35.4569366,7.95303496 35.4569366,17.7286247 C35.4569366,27.5039538 27.5039277,35.4569627 17.728338,35.4569627 Z M17.728338,1.18222797 C8.60474962,1.18222797 1.18230615,8.60493204 1.18230615,17.7285204 C1.18230615,26.8521088 8.60474962,34.2745523 17.728338,34.2745523 C26.852187,34.2745523 34.2746305,26.8521088 34.2746305,17.7285204 C34.2746305,8.60493204 26.852187,1.18222797 17.728338,1.18222797 Z" id="Combined-Shape"></path>
          <path d="M31.7163462,17.1373674 C32.0191542,17.1373674 32.3177926,17.0276581 32.5291328,16.8108455 C32.7621021,16.5724038 32.869466,16.2576086 32.8308984,15.9313473 C32.5035948,13.1505695 31.4109323,10.5157233 29.6709592,8.31215687 C29.4580554,8.04244409 29.1630652,7.89364603 28.8404523,7.89364603 C28.5558858,7.89364603 28.2796582,8.01325778 28.062585,8.23007037 L19.5130809,16.7798351 C19.3812213,16.9119552 19.4745133,17.1373674 19.6610972,17.1373674 L31.7163462,17.1373674 Z" id="Fill-6"></path>
          <path d="M28.8404002,27.5631082 L28.8404002,27.5631082 C29.1630131,27.5631082 29.4580033,27.4148313 29.6711676,27.1451185 C31.4108802,24.941031 32.5038033,22.3064453 32.8308463,19.5256675 C32.8694139,19.1994062 32.76205,18.884611 32.5290807,18.6461693 C32.3177405,18.4293567 32.019102,18.3196475 31.7162941,18.3196475 L19.6610451,18.3196475 C19.4747217,18.3196475 19.3811692,18.5453202 19.5130288,18.6771798 L28.0627935,27.2269445 C28.2796061,27.443757 28.5558336,27.5631082 28.8404002,27.5631082" id="Fill-8"></path>
          <path d="M6.61653649,7.89375026 C6.29392353,7.89375026 5.99893332,8.04228773 5.78576902,8.31200051 C4.04605647,10.5158275 2.95313339,13.1506738 2.62609037,15.9314516 C2.58752274,16.2577128 2.69488667,16.572508 2.92785596,16.8109498 C3.13919612,17.0277623 3.43783461,17.1374716 3.74064258,17.1374716 L15.7958916,17.1374716 C15.9822149,17.1374716 16.0757675,16.9117989 15.9439079,16.7799393 L7.39414318,8.23017461 C7.17733059,8.01336202 6.90110301,7.89375026 6.61653649,7.89375026" id="Fill-10"></path>
          <path d="M15.7957874,18.3197256 L3.74053834,18.3197256 C3.43773038,18.3197256 3.13935247,18.4294349 2.92775173,18.6462475 C2.69504302,18.8846892 2.5874185,19.1994844 2.62598613,19.5257457 C2.95328975,22.3065235 4.04595223,24.9411091 5.78592538,27.1449361 C5.99882908,27.4146489 6.29407988,27.5631864 6.61643225,27.5631864 C6.90073818,27.5631864 7.17670517,27.4440958 7.39351776,27.2278044 L7.39403894,27.2272832 L15.9438036,18.6772579 C16.0756632,18.5451378 15.9823713,18.3197256 15.7957874,18.3197256" id="Fill-12"></path>
          <path d="M17.1374455,3.74079894 C17.1374455,3.43773038 17.0277363,3.13909188 16.8109237,2.92775173 C16.572482,2.69478243 16.2574262,2.5874185 15.9314255,2.62598613 C13.1506477,2.95328975 10.5158015,4.04595223 8.31223504,5.78592538 C8.04252227,5.99882908 7.8937242,6.29407988 7.8937242,6.61643225 C7.8937242,6.90099877 8.01307536,7.17748694 8.23014855,7.39429953 L16.7799132,15.9438036 C16.9117728,16.0756632 17.1374455,15.9823713 17.1374455,15.7957874 L17.1374455,3.74079894 Z" id="Fill-14"></path>
          <path d="M27.5631603,6.61648437 L27.5631603,6.61648437 C27.5631603,6.294132 27.4148834,5.9988812 27.1451707,5.7857169 C24.9410831,4.04600435 22.3064974,2.95308127 19.5257196,2.62603825 C19.1994583,2.58747062 18.8846631,2.69483455 18.6459608,2.92780385 C18.4294088,3.139144 18.3196996,3.43778249 18.3196996,3.74085105 L18.3196996,15.7958395 C18.3196996,15.9821628 18.5453723,16.0757153 18.6772319,15.9438558 L27.2269966,7.39409106 C27.4438092,7.17727847 27.5631603,6.90131148 27.5631603,6.61648437" id="Fill-16"></path>
          <path d="M7.89380238,28.840348 C7.89380238,29.162961 8.04233985,29.4579512 8.31205263,29.6711155 C10.5158796,31.4110887 13.1507259,32.5040117 15.9315037,32.8307942 C16.2575044,32.8693618 16.5725601,32.7619979 16.8110019,32.5290286 C17.0278145,32.3176884 17.1375237,32.0190499 17.1375237,31.7162419 L17.1375237,19.6609929 C17.1375237,19.4746696 16.9115904,19.3811171 16.7799914,19.5129766 L8.23022672,28.0627413 C8.01315354,28.2798145 7.89380238,28.5557815 7.89380238,28.840348" id="Fill-18"></path>
          <path d="M18.3197778,31.7163462 C18.3197778,32.0191542 18.429487,32.3175321 18.646039,32.5291328 C18.8847413,32.7618415 19.1995365,32.869466 19.5257978,32.8308984 C22.3065756,32.5038554 24.9411613,31.4111929 27.1449883,29.6709592 C27.414701,29.4580554 27.5632385,29.1630652 27.5632385,28.8404523 C27.5632385,28.5561463 27.4441479,28.2801794 27.2278565,28.0633668 L18.6773101,19.5133415 C18.5451899,19.3812213 18.3197778,19.4745133 18.3197778,19.6613578 L18.3197778,31.7163462 Z" id="Fill-20"></path>
        </g>
        <path d="M57.404,39.48 L57.404,25.688 L53.404,25.688 L53.404,39.48 C53.404,41.912 51.996,43.512 49.884,43.512 C48.7,43.512 47.804,43.032 46.524,41.336 L43.644,43.832 C45.596,46.392 47.484,47.256 49.884,47.256 C54.268,47.256 57.404,44.152 57.404,39.48 Z M78.508,38.296 L78.508,25.688 L74.508,25.688 L74.508,38.136 C74.508,41.4 72.588,43.512 69.836,43.512 C67.084,43.512 65.164,41.4 65.164,38.136 L65.164,25.688 L61.164,25.688 L61.164,38.296 C61.164,43.864 65.196,47.256 69.836,47.256 C74.476,47.256 78.508,43.864 78.508,38.296 Z M99.324,44.6 L96.956,41.624 C94.94,43.032 93.628,43.512 92.06,43.512 C88.188,43.512 85.052,40.376 85.052,36.344 C85.052,32.312 88.188,29.176 92.06,29.176 C93.692,29.176 94.876,29.592 96.988,31.064 L99.324,28.152 C97.116,26.36 94.748,25.432 92.06,25.432 C86.012,25.432 80.956,30.264 80.956,36.344 C80.956,42.392 85.948,47.256 92.06,47.256 C94.524,47.256 96.604,46.648 99.324,44.6 Z M114.796,47 L114.796,43.384 L105.516,43.384 L105.516,38.04 L114.444,38.04 L114.444,34.424 L105.516,34.424 L105.516,29.304 L114.796,29.304 L114.796,25.688 L101.516,25.688 L101.516,47 L114.796,47 Z" id="JUCE" fill="#B144C8" mask="url(#mask-2)"></path>
        <path d="M66.1199999,21 L63.8399999,14.12 L61.8399999,19.17 L59.8399999,14.12 L57.5599999,21 L58.3999999,21 L59.9099999,16.34 L61.8399999,21.22 L63.7699999,16.34 L65.2799999,21 L66.1199999,21 Z M71.2166666,21 L70.4166666,21 C70.2866666,20.77 70.2466666,20.43 70.2466666,20.18 C69.8966666,20.63 69.2066666,21.08 68.4266666,21.08 C67.4766666,21.08 66.8066666,20.56 66.8066666,19.73 C66.8066666,18.89 67.3666666,18.06 70.1766666,17.61 C70.1766666,17.04 69.7466666,16.66 69.0066666,16.66 C68.3666666,16.66 67.9366666,16.89 67.5566666,17.18 L67.0766666,16.61 C67.6066666,16.17 68.2866666,15.9 69.0666666,15.9 C69.9066666,15.9 70.9766666,16.22 70.9766666,17.62 L70.9766666,19.83 C70.9766666,20.19 71.0366666,20.65 71.2166666,21 Z M70.1766666,18.73 L70.1766666,18.29 C68.1366666,18.64 67.6066666,19.15 67.6066666,19.73 C67.6066666,20.2 68.1166666,20.4 68.5866666,20.4 C69.3066666,20.4 70.1766666,19.8 70.1766666,18.73 Z M77.0633333,21 L76.2633333,21 L76.2633333,20.18 C75.9433333,20.68 75.2933333,21.08 74.5033333,21.08 C73.1133333,21.08 71.9833333,19.9 71.9833333,18.49 C71.9833333,17.08 73.1133333,15.9 74.5033333,15.9 C75.2933333,15.9 75.9433333,16.3 76.2633333,16.8 L76.2633333,14 L77.0633333,14 L77.0633333,21 Z M76.2633333,18.49 C76.2633333,17.47 75.5133333,16.66 74.5233333,16.66 C73.5333333,16.66 72.7833333,17.47 72.7833333,18.49 C72.7833333,19.51 73.5333333,20.32 74.5233333,20.32 C75.5133333,20.32 76.2633333,19.51 76.2633333,18.49 Z M83.14,18.46 C83.14,18.64 83.12,18.81 83.12,18.81 L78.9,18.81 C79.04,19.66 79.77,20.32 80.66,20.32 C81.18,20.32 81.73,20.09 82.12,19.67 L82.69,20.19 C82.17,20.78 81.43,21.08 80.66,21.08 C79.23,21.08 78.07,19.91 78.07,18.49 C78.07,17.06 79.22,15.9 80.65,15.9 C82.12,15.9 83.14,17.06 83.14,18.46 Z M82.3,18.1 C82.12,17.2 81.52,16.66 80.65,16.66 C79.78,16.66 79.07,17.27 78.91,18.1 L82.3,18.1 Z M93.5633333,15.98 L92.7233333,15.98 L91.4533333,19.36 L89.8233333,15.7 L88.1933333,19.36 L86.9233333,15.98 L86.0833333,15.98 L88.1433333,21.28 L89.8233333,17.44 L91.5033333,21.28 L93.5633333,15.98 Z M95.4,14.46 C95.4,14.16 95.15,13.91 94.85,13.91 C94.55,13.91 94.3,14.16 94.3,14.46 C94.3,14.76 94.55,15.01 94.85,15.01 C95.15,15.01 95.4,14.76 95.4,14.46 Z M95.25,21 L95.25,15.98 L94.45,15.98 L94.45,21 L95.25,21 Z M99.1466667,16.69 L99.1466667,15.98 L97.8066667,15.98 L97.8066667,14.34 L97.0066667,14.34 L97.0066667,15.98 L95.9966667,15.98 L95.9966667,16.69 L97.0066667,16.69 L97.0066667,21 L97.8066667,21 L97.8066667,16.69 L99.1466667,16.69 Z M104.173333,21 L104.173333,18.12 C104.173333,16.7 103.243333,15.9 102.093333,15.9 C101.403333,15.9 100.833333,16.27 100.623333,16.63 L100.623333,14 L99.8233334,14 L99.8233334,21 L100.623333,21 L100.623333,18.17 C100.623333,17.22 101.233333,16.66 102.013333,16.66 C102.793333,16.66 103.373333,17.22 103.373333,18.17 L103.373333,21 L104.173333,21 Z" id="Made-with" fill="#B144C8" mask="url(#mask-2)"></path>
      </g>
    </svg>
    )JUCESPLASHSCREEN";

    ScopedPointer<XmlElement> svgXml (XmlDocument::parse (svgData));
    return Drawable::createFromSVG (*svgXml);
}

void JUCESplashScreen::paint (Graphics& g)
{
    auto r = getLocalBounds().toFloat();
    Point<float> bottomRight (0.9f * r.getWidth(),
                              0.9f * r.getHeight());

    ColourGradient cg (Colour (0x00000000), Line<float> (0.0f, r.getHeight(), r.getWidth(), 0.0f)
                                              .findNearestPointTo (bottomRight),
                       Colour (0xff000000), bottomRight, false);
    cg.addColour (0.25f, Colour (0x10000000));
    cg.addColour (0.50f, Colour (0x30000000));
    cg.addColour (0.75f, Colour (0x70000000));
    g.setFillType (cg);
    g.fillAll();

    content->drawWithin (g, getLogoArea (r), RectanglePlacement::centred, 1.0f);

    if (splashDisplayTime == 0)
        splashDisplayTime = Time::getMillisecondCounter();

    if (! isTimerRunning())
        startTimer (millisecondsToDisplaySplash);
}

void JUCESplashScreen::timerCallback()
{
   #if JUCE_DISPLAY_SPLASH_SCREEN
    if (isVisible() && ! hasStartedFading)
    {
        hasStartedFading = true;
        fader.animateComponent (this, getBounds(), 0.0f, splashScreenFadeOutTime, false, 0, 0);
    }

    if (hasStartedFading && ! fader.isAnimating())
   #endif
        delete this;
}

void JUCESplashScreen::parentSizeChanged()
{
    if (auto* p = getParentComponent())
        setBounds (p->getLocalBounds().removeFromBottom (splashScreenLogoHeight * 3)
                                      .removeFromRight  (splashScreenLogoWidth  * 3));
}

void JUCESplashScreen::parentHierarchyChanged()
{
    toFront (false);
}

bool JUCESplashScreen::hitTest (int x, int y)
{
    return getLogoArea (getLocalBounds().toFloat()).contains ((float) x, (float) y);
}

void JUCESplashScreen::mouseUp (const MouseEvent&)
{
    URL juceWebsite ("https://juce.com");
    juceWebsite.launchInDefaultBrowser();
}

// END SECTION A

} // namespace juce


text:
/*
  ==============================================================================

   This file is part of the JUCE library.
   Copyright (c) 2017 - ROLI Ltd.

   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 5 End-User License
   Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
   27th April 2017).

   End User License Agreement: www.juce.com/juce-5-licence
   Privacy Policy: www.juce.com/juce-5-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 component for showing a message or other graphics inside a speech-bubble-shaped
    outline, pointing at a location on the screen.

    This is a base class that just draws and positions the bubble shape, but leaves
    the drawing of any content up to a subclass. See BubbleMessageComponent for a subclass
    that draws a text message.

    To use it, create your subclass, then either add it to a parent component or
    put it on the desktop with addToDesktop (0), use setPosition() to
    resize and position it, then make it visible.

    @see BubbleMessageComponent
*/
class JUCE_API  BubbleComponent  : public Component
{
protected:
    //==============================================================================
    /** Creates a BubbleComponent.

        Your subclass will need to implement the getContentSize() and paintContent()
        methods to draw the bubble's contents.
    */
    BubbleComponent();

public:
    /** Destructor. */
    ~BubbleComponent();

    //==============================================================================
    /** A list of permitted placements for the bubble, relative to the coordinates
        at which it should be pointing.

        @see setAllowedPlacement
    */
    enum BubblePlacement
    {
        above   = 1,
        below   = 2,
        left    = 4,
        right   = 8
    };

    /** Tells the bubble which positions it's allowed to put itself in, relative to the
        point at which it's pointing.

        By default when setPosition() is called, the bubble will place itself either
        above, below, left, or right of the target area. You can pass in a bitwise-'or' of
        the values in BubblePlacement to restrict this choice.

        E.g. if you only want your bubble to appear above or below the target area,
        use setAllowedPlacement (above | below);

        @see BubblePlacement
    */
    void setAllowedPlacement (int newPlacement);

    //==============================================================================
    /** Moves and resizes the bubble to point at a given component.

        This will resize the bubble to fit its content, then find a position for it
        so that it's next to, but doesn't overlap the given component.

        It'll put itself either above, below, or to the side of the component depending
        on where there's the most space, honouring any restrictions that were set
        with setAllowedPlacement().
    */
    void setPosition (Component* componentToPointTo,
                      int distanceFromTarget = 15, int arrowLength = 10);

    /** Moves and resizes the bubble to point at a given point.

        This will resize the bubble to fit its content, then position it
        so that the tip of the bubble points to the given coordinate. The coordinates
        are relative to either the bubble component's parent component if it has one, or
        they are screen coordinates if not.

        It'll put itself either above, below, or to the side of this point, depending
        on where there's the most space, honouring any restrictions that were set
        with setAllowedPlacement().
    */
    void setPosition (Point<int> arrowTipPosition, int arrowLength = 10);

    /** Moves and resizes the bubble to point at a given rectangle.

        This will resize the bubble to fit its content, then find a position for it
        so that it's next to, but doesn't overlap the given rectangle. The rectangle's
        coordinates are relative to either the bubble component's parent component
        if it has one, or they are screen coordinates if not.

        It'll put itself either above, below, or to the side of the component depending
        on where there's the most space, honouring any restrictions that were set
        with setAllowedPlacement().

        distanceFromTarget is the amount of space to leave between the bubble and the
        target rectangle, and arrowLength is the length of the arrow that it will draw.
    */
    void setPosition (Rectangle<int> rectangleToPointTo,
                      int distanceFromTarget = 15, int arrowLength = 10);

    //==============================================================================
    /** A set of colour IDs to use to change the colour of various aspects of the bubble component.

        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            = 0x1000af0, /**< A background colour to fill the bubble with. */
        outlineColourId               = 0x1000af1  /**< The colour to use for an outline around the bubble. */
    };

    //==============================================================================
    /** This abstract base class is implemented by LookAndFeel classes.
    */
    struct JUCE_API  LookAndFeelMethods
    {
        virtual ~LookAndFeelMethods() {}

        virtual void drawBubble (Graphics&, BubbleComponent&,
                                 const Point<float>& positionOfTip,
                                 const Rectangle<float>& body) = 0;
    };

protected:
    //==============================================================================
    /** Subclasses should override this to return the size of the content they
        want to draw inside the bubble.
    */
    virtual void getContentSize (int& width, int& height) = 0;

    /** Subclasses should override this to draw their bubble's contents.

        The graphics object's clip region and the dimensions passed in here are
        set up to paint just the rectangle inside the bubble.
    */
    virtual void paintContent (Graphics& g, int width, int height) = 0;

public:
    /** @internal */
    void paint (Graphics&) override;

private:
    Rectangle<int> content;
    Point<int> arrowTip;
    int allowablePlacements;
    DropShadowEffect shadow;

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BubbleComponent)
};

} // namespace juce


text:
/*
  ==============================================================================

   This file is part of the JUCE library.
   Copyright (c) 2017 - ROLI Ltd.

   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 5 End-User License
   Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
   27th April 2017).

   End User License Agreement: www.juce.com/juce-5-licence
   Privacy Policy: www.juce.com/juce-5-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
{

BubbleComponent::BubbleComponent()
  : allowablePlacements (above | below | left | right)
{
    setInterceptsMouseClicks (false, false);

    shadow.setShadowProperties (DropShadow (Colours::black.withAlpha (0.35f), 5, Point<int>()));
    setComponentEffect (&shadow);
}

BubbleComponent::~BubbleComponent() {}

//==============================================================================
void BubbleComponent::paint (Graphics& g)
{
    getLookAndFeel().drawBubble (g, *this, arrowTip.toFloat(), content.toFloat());

    g.reduceClipRegion (content);
    g.setOrigin (content.getPosition());

    paintContent (g, content.getWidth(), content.getHeight());
}

void BubbleComponent::setAllowedPlacement (const int newPlacement)
{
    allowablePlacements = newPlacement;
}

//==============================================================================
void BubbleComponent::setPosition (Component* componentToPointTo, int distanceFromTarget, int arrowLength)
{
    jassert (componentToPointTo != nullptr);

    Rectangle<int> target;

    if (Component* p = getParentComponent())
        target = p->getLocalArea (componentToPointTo, componentToPointTo->getLocalBounds());
    else
        target = componentToPointTo->getScreenBounds();

    setPosition (target, distanceFromTarget, arrowLength);
}

void BubbleComponent::setPosition (Point<int> arrowTipPos, int arrowLength)
{
    setPosition (Rectangle<int> (arrowTipPos.x, arrowTipPos.y, 1, 1), arrowLength, arrowLength);
}

void BubbleComponent::setPosition (Rectangle<int> rectangleToPointTo,
                                   int distanceFromTarget, int arrowLength)
{
    {
        int contentW = 150, contentH = 30;
        getContentSize (contentW, contentH);
        content.setBounds (distanceFromTarget, distanceFromTarget, contentW, contentH);
    }

    const int totalW = content.getWidth()  + distanceFromTarget * 2;
    const int totalH = content.getHeight() + distanceFromTarget * 2;

    const Rectangle<int> availableSpace (getParentComponent() != nullptr ? getParentComponent()->getLocalBounds()
                                                                         : getParentMonitorArea());

    int spaceAbove = ((allowablePlacements & above) != 0) ? jmax (0, rectangleToPointTo.getY()  - availableSpace.getY()) : -1;
    int spaceBelow = ((allowablePlacements & below) != 0) ? jmax (0, availableSpace.getBottom() - rectangleToPointTo.getBottom()) : -1;
    int spaceLeft  = ((allowablePlacements & left)  != 0) ? jmax (0, rectangleToPointTo.getX()  - availableSpace.getX()) : -1;
    int spaceRight = ((allowablePlacements & right) != 0) ? jmax (0, availableSpace.getRight()  - rectangleToPointTo.getRight()) : -1;

    // look at whether the component is elongated, and if so, try to position next to its longer dimension.
    if (rectangleToPointTo.getWidth() > rectangleToPointTo.getHeight() * 2
         && (spaceAbove > totalH + 20 || spaceBelow > totalH + 20))
    {
        spaceLeft = spaceRight = 0;
    }
    else if (rectangleToPointTo.getWidth() < rectangleToPointTo.getHeight() / 2
              && (spaceLeft > totalW + 20 || spaceRight > totalW + 20))
    {
        spaceAbove = spaceBelow = 0;
    }

    int targetX, targetY;

    if (jmax (spaceAbove, spaceBelow) >= jmax (spaceLeft, spaceRight))
    {
        targetX = rectangleToPointTo.getCentre().x;
        arrowTip.x = totalW / 2;

        if (spaceAbove >= spaceBelow)
        {
            // above
            targetY = rectangleToPointTo.getY();
            arrowTip.y = content.getBottom() + arrowLength;
        }
        else
        {
            // below
            targetY = rectangleToPointTo.getBottom();
            arrowTip.y = content.getY() - arrowLength;
        }
    }
    else
    {
        targetY = rectangleToPointTo.getCentre().y;
        arrowTip.y = totalH / 2;

        if (spaceLeft > spaceRight)
        {
            // on the left
            targetX = rectangleToPointTo.getX();
            arrowTip.x = content.getRight() + arrowLength;
        }
        else
        {
            // on the right
            targetX = rectangleToPointTo.getRight();
            arrowTip.x = content.getX() - arrowLength;
        }
    }

    setBounds (targetX - arrowTip.x, targetY - arrowTip.y, totalW, totalH);
}

} // namespace juce


text:
/*
  ==============================================================================

   This file is part of the JUCE library.
   Copyright (c) 2017 - ROLI Ltd.

   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 5 End-User License
   Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
   27th April 2017).

   End User License Agreement: www.juce.com/juce-5-licence
   Privacy Policy: www.juce.com/juce-5-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 DropShadower::ShadowWindow  : public Component
{
public:
    ShadowWindow (Component* comp, const DropShadow& ds)
        : target (comp), shadow (ds)
    {
        setVisible (true);
        setInterceptsMouseClicks (false, false);

        if (comp->isOnDesktop())
        {
            setSize (1, 1); // to keep the OS happy by not having zero-size windows
            addToDesktop (ComponentPeer::windowIgnoresMouseClicks
                            | ComponentPeer::windowIsTemporary
                            | ComponentPeer::windowIgnoresKeyPresses);
        }
        else if (Component* const parent = comp->getParentComponent())
        {
            parent->addChildComponent (this);
        }
    }

    void paint (Graphics& g) override
    {
        if (Component* c = target)
            shadow.drawForRectangle (g, getLocalArea (c, c->getLocalBounds()));
    }

    void resized() override
    {
        repaint();  // (needed for correct repainting)
    }

    float getDesktopScaleFactor() const override
    {
        if (target != nullptr)
            return target->getDesktopScaleFactor();

        return Component::getDesktopScaleFactor();
    }

private:
    WeakReference<Component> target;
    DropShadow shadow;

    JUCE_DECLARE_NON_COPYABLE (ShadowWindow)
};

//==============================================================================
DropShadower::DropShadower (const DropShadow& ds)
   : owner (nullptr), shadow (ds), reentrant (false)
{
}

DropShadower::~DropShadower()
{
    if (owner != nullptr)
    {
        owner->removeComponentListener (this);
        owner = nullptr;
    }

    updateParent();

    reentrant = true;
    shadowWindows.clear();
}

void DropShadower::setOwner (Component* componentToFollow)
{
    if (componentToFollow != owner)
    {
        if (owner != nullptr)
            owner->removeComponentListener (this);

        // (the component can't be null)
        jassert (componentToFollow != nullptr);

        owner = componentToFollow;
        jassert (owner != nullptr);

        updateParent();
        owner->addComponentListener (this);

        updateShadows();
    }
}

void DropShadower::updateParent()
{
    if (Component* p = lastParentComp)
        p->removeComponentListener (this);

    lastParentComp = owner != nullptr ? owner->getParentComponent() : nullptr;

    if (Component* p = lastParentComp)
        p->addComponentListener (this);
}

void DropShadower::componentMovedOrResized (Component& c, bool /*wasMoved*/, bool /*wasResized*/)
{
    if (owner == &c)
        updateShadows();
}

void DropShadower::componentBroughtToFront (Component& c)
{
    if (owner == &c)
        updateShadows();
}

void DropShadower::componentChildrenChanged (Component&)
{
    updateShadows();
}

void DropShadower::componentParentHierarchyChanged (Component& c)
{
    if (owner == &c)
    {
        updateParent();
        updateShadows();
    }
}

void DropShadower::componentVisibilityChanged (Component& c)
{
    if (owner == &c)
        updateShadows();
}

void DropShadower::updateShadows()
{
    if (reentrant)
        return;

    const ScopedValueSetter<bool> setter (reentrant, true, false);

    if (owner == nullptr)
    {
        shadowWindows.clear();
        return;
    }

    if (owner->isShowing()
         && owner->getWidth() > 0 && owner->getHeight() > 0
         && (Desktop::canUseSemiTransparentWindows() || owner->getParentComponent() != nullptr))
    {
        while (shadowWindows.size() < 4)
            shadowWindows.add (new ShadowWindow (owner, shadow));

        const int shadowEdge = jmax (shadow.offset.x, shadow.offset.y) + shadow.radius;
        const int x = owner->getX();
        const int y = owner->getY() - shadowEdge;
        const int w = owner->getWidth();
        const int h = owner->getHeight() + shadowEdge + shadowEdge;

        for (int i = 4; --i >= 0;)
        {
            // there seem to be rare situations where the dropshadower may be deleted by
            // callbacks during this loop, so use a weak ref to watch out for this..
            WeakReference<Component> sw (shadowWindows[i]);

            if (sw != nullptr)
            {
                sw->setAlwaysOnTop (owner->isAlwaysOnTop());

                if (sw == nullptr)
                    return;

                switch (i)
                {
                    case 0: sw->setBounds (x - shadowEdge, y, shadowEdge, h); break;
                    case 1: sw->setBounds (x + w, y, shadowEdge, h); break;
                    case 2: sw->setBounds (x, y, w, shadowEdge); break;
                    case 3: sw->setBounds (x, owner->getBottom(), w, shadowEdge); break;
                    default: break;
                }

                if (sw == nullptr)
                    return;

                sw->toBehind (i == 3 ? owner : shadowWindows.getUnchecked (i + 1));
            }
        }
    }
    else
    {
        shadowWindows.clear();
    }
}

} // namespace juce


text:
/*
  ==============================================================================

   This file is part of the JUCE library.
   Copyright (c) 2017 - ROLI Ltd.

   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 5 End-User License
   Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
   27th April 2017).

   End User License Agreement: www.juce.com/juce-5-licence
   Privacy Policy: www.juce.com/juce-5-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.

  ==============================================================================
*/

/*
  ==============================================================================

   In accordance with the terms of the JUCE 5 End-Use License Agreement, the
   JUCE Code in SECTION A cannot be removed, changed or otherwise rendered
   ineffective unless you have a JUCE Indie or Pro license, or are using JUCE
   under the GPL v3 license.

   End User License Agreement: www.juce.com/juce-5-licence
  ==============================================================================
*/

// BEGIN SECTION A

namespace juce
{

/**
    The standard JUCE splash screen component.
*/
class JUCE_API  JUCESplashScreen  : public Component,
                                    private Timer,
                                    private DeletedAtShutdown
{
public:
    JUCESplashScreen (Component& parentToAddTo);
    ~JUCESplashScreen();

    static Drawable* getSplashScreenLogo();

private:
    void paint (Graphics&) override;
    void timerCallback() override;
    void parentSizeChanged() override;
    void parentHierarchyChanged() override;
    bool hitTest (int, int) override;
    void mouseUp (const MouseEvent&) override;

    ScopedPointer<Drawable> content;
    CriticalSection appUsageReporting;
    ComponentAnimator fader;
    bool hasStartedFading = false;

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JUCESplashScreen)
};

// END SECTION A

} // namespace juce


text:
/*
  ==============================================================================

   This file is part of the JUCE library.
   Copyright (c) 2017 - ROLI Ltd.

   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 5 End-User License
   Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
   27th April 2017).

   End User License Agreement: www.juce.com/juce-5-licence
   Privacy Policy: www.juce.com/juce-5-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
{

//==============================================================================
/**
    Adds a drop-shadow to a component.

    This object creates and manages a set of components which sit around a
    component, creating a gaussian shadow around it. The components will track
    the position of the component and if it's brought to the front they'll also
    follow this.

    For desktop windows you don't need to use this class directly - just
    set the Component::windowHasDropShadow flag when calling
    Component::addToDesktop(), and the system will create one of these if it's
    needed (which it obviously isn't on the Mac, for example).
*/
class JUCE_API  DropShadower  : private ComponentListener
{
public:
    //==============================================================================
    /** Creates a DropShadower. */
    DropShadower (const DropShadow& shadowType);

    /** Destructor. */
    ~DropShadower();

    /** Attaches the DropShadower to the component you want to shadow. */
    void setOwner (Component* componentToFollow);

private:
    //==============================================================================
    class ShadowWindow;

    Component* owner;
    OwnedArray<Component> shadowWindows;
    DropShadow shadow;
    bool reentrant;
    WeakReference<Component> lastParentComp;

    void componentMovedOrResized (Component&, bool, bool) override;
    void componentBroughtToFront (Component&) override;
    void componentChildrenChanged (Component&) override;
    void componentParentHierarchyChanged (Component&) override;
    void componentVisibilityChanged (Component&) override;

    void updateParent();
    void updateShadows();

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DropShadower)
};

} // namespace juce


text:
/*
  ==============================================================================

   This file is part of the JUCE library.
   Copyright (c) 2017 - ROLI Ltd.

   JUCE is an open source library subject to commercial or open-source
   licensing.

   The code included in this file is provided under the terms of the ISC license
   http://www.isc.org/downloads/software-support-policy/isc-license. Permission
   To use, copy, modify, and/or distribute this software for any purpose with or
   without fee is hereby granted provided that the above copyright notice and
   this permission notice appear in all copies.

   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
   DISCLAIMED.

  ==============================================================================
*/

#include "juce_events.cpp"


text:
/*
  ==============================================================================

   This file is part of the JUCE library.
   Copyright (c) 2017 - ROLI Ltd.

   JUCE is an open source library subject to commercial or open-source
   licensing.

   The code included in this file is provided under the terms of the ISC license
   http://www.isc.org/downloads/software-support-policy/isc-license. Permission
   To use, copy, modify, and/or distribute this software for any purpose with or
   without fee is hereby granted provided that the above copyright notice and
   this permission notice appear in all copies.

   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
   DISCLAIMED.

  ==============================================================================
*/

#ifdef JUCE_EVENTS_H_INCLUDED
 /* When you add this cpp file to your project, you mustn't include it in a file where you've
    already included any other headers - just put it inside a file on its own, possibly with your config
    flags preceding it, but don't include anything else. That also includes avoiding any automatic prefix
    header files that the compiler may be using.
 */
 #error "Incorrect use of JUCE cpp file"
#endif

#define JUCE_CORE_INCLUDE_OBJC_HELPERS 1
#define JUCE_CORE_INCLUDE_JNI_HELPERS 1
#define JUCE_CORE_INCLUDE_NATIVE_HEADERS 1
#define JUCE_CORE_INCLUDE_COM_SMART_PTR 1
#define JUCE_EVENTS_INCLUDE_WIN32_MESSAGE_WINDOW 1

#if JUCE_USE_WINRT_MIDI
 #define JUCE_EVENTS_INCLUDE_WINRT_WRAPPER 1
#endif

#include "juce_events.h"

//==============================================================================
#if JUCE_MAC
 #import <IOKit/IOKitLib.h>
 #import <IOKit/IOCFPlugIn.h>
 #import <IOKit/hid/IOHIDLib.h>
 #import <IOKit/hid/IOHIDKeys.h>
 #import <IOKit/pwr_mgt/IOPMLib.h>

#elif JUCE_LINUX
 #include <unistd.h>
#endif

//==============================================================================
#include "messages/juce_ApplicationBase.cpp"
#include "messages/juce_DeletedAtShutdown.cpp"
#include "messages/juce_MessageListener.cpp"
#include "messages/juce_MessageManager.cpp"
#include "broadcasters/juce_ActionBroadcaster.cpp"
#include "broadcasters/juce_AsyncUpdater.cpp"
#include "broadcasters/juce_ChangeBroadcaster.cpp"
#include "timers/juce_MultiTimer.cpp"
#include "timers/juce_Timer.cpp"
#include "interprocess/juce_InterprocessConnection.cpp"
#include "interprocess/juce_InterprocessConnectionServer.cpp"
#include "interprocess/juce_ConnectedChildProcess.cpp"

//==============================================================================
#if JUCE_MAC || JUCE_IOS

 #include "native/juce_osx_MessageQueue.h"

 #if JUCE_CLANG
  #pragma clang diagnostic push
  #pragma clang diagnostic ignored "-Wundeclared-selector"
 #endif

 #if JUCE_MAC
  #include "native/juce_mac_MessageManager.mm"
 #else
  #include "native/juce_ios_MessageManager.mm"
 #endif

 #if JUCE_CLANG
  #pragma clang diagnostic pop
 #endif

#elif JUCE_WINDOWS
 #include "native/juce_win32_Messaging.cpp"
 #if JUCE_EVENTS_INCLUDE_WINRT_WRAPPER
  #include "native/juce_win32_WinRTWrapper.cpp"
 #endif

#elif JUCE_LINUX
 #include "native/juce_linux_Messaging.cpp"

#elif JUCE_ANDROID
 #include "native/juce_android_Messaging.cpp"

#endif