|
- /*
- ==============================================================================
-
- This file is part of the JUCE library - "Jules' Utility Class Extensions"
- Copyright 2004-7 by Raw Material Software ltd.
-
- ------------------------------------------------------------------------------
-
- JUCE can be redistributed and/or modified under the terms of the
- GNU General Public License, as published by the Free Software Foundation;
- either version 2 of the License, or (at your option) any later version.
-
- JUCE is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with JUCE; if not, visit www.gnu.org/licenses or write to the
- Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- Boston, MA 02111-1307 USA
-
- ------------------------------------------------------------------------------
-
- If you'd like to release a closed-source product which uses JUCE, commercial
- licenses are also available: visit www.rawmaterialsoftware.com/juce for
- more information.
-
- ==============================================================================
- */
-
- #include "../../../../juce_core/basics/juce_StandardHeader.h"
-
- BEGIN_JUCE_NAMESPACE
-
- #include "juce_AlertWindow.h"
- #include "../lookandfeel/juce_LookAndFeel.h"
- #include "../buttons/juce_TextButton.h"
- #include "../controls/juce_TextEditor.h"
- #include "../controls/juce_ProgressBar.h"
- #include "../juce_Desktop.h"
- #include "../../../../juce_core/text/juce_LocalisedStrings.h"
- #include "../../../events/juce_MessageManager.h"
-
- static const int titleH = 24;
- static const int iconWidth = 80;
-
-
- //==============================================================================
- class AlertWindowTextEditor : public TextEditor
- {
- public:
- #if JUCE_LINUX
- #define PASSWORD_CHAR 0x2022
- #else
- #define PASSWORD_CHAR 0x25cf
- #endif
-
- AlertWindowTextEditor (const String& name,
- const bool isPasswordBox)
- : TextEditor (name,
- isPasswordBox ? (const tchar) PASSWORD_CHAR
- : (const tchar) 0)
- {
- setSelectAllWhenFocused (true);
- }
-
- ~AlertWindowTextEditor()
- {
- }
-
- void returnPressed()
- {
- // pass these up the component hierarchy to be trigger the buttons
- getParentComponent()->keyPressed (KeyPress (KeyPress::returnKey, 0, T('\n')));
- }
-
- void escapePressed()
- {
- // pass these up the component hierarchy to be trigger the buttons
- getParentComponent()->keyPressed (KeyPress (KeyPress::escapeKey, 0, 0));
- }
-
- private:
- AlertWindowTextEditor (const AlertWindowTextEditor&);
- const AlertWindowTextEditor& operator= (const AlertWindowTextEditor&);
- };
-
-
- //==============================================================================
- AlertWindow::AlertWindow (const String& title,
- const String& message,
- AlertIconType iconType)
- : TopLevelWindow (title, true),
- alertIconType (iconType)
- {
- if (message.isEmpty())
- text = T(" "); // to force an update if the message is empty
-
- setMessage (message);
-
- #if JUCE_MAC
- setAlwaysOnTop (true);
- #else
- for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;)
- {
- Component* const c = Desktop::getInstance().getComponent (i);
-
- if (c != 0 && c->isAlwaysOnTop() && c->isShowing())
- {
- setAlwaysOnTop (true);
- break;
- }
- }
- #endif
-
- lookAndFeelChanged();
-
- constrainer.setMinimumOnscreenAmounts (0x10000, 0x10000, 0x10000, 0x10000);
- }
-
- AlertWindow::~AlertWindow()
- {
- for (int i = customComps.size(); --i >= 0;)
- removeChildComponent ((Component*) customComps[i]);
-
- deleteAllChildren();
- }
-
- void AlertWindow::userTriedToCloseWindow()
- {
- exitModalState (0);
- }
-
- //==============================================================================
- void AlertWindow::setMessage (const String& message)
- {
- const String newMessage (message.substring (0, 2048));
-
- if (text != newMessage)
- {
- text = newMessage;
-
- font.setHeight (15.0f);
-
- Font titleFont (font.getHeight() * 1.1f, Font::bold);
- textLayout.setText (getName() + T("\n\n"), titleFont);
-
- textLayout.appendText (text, font);
-
- updateLayout (true);
- repaint();
- }
- }
-
- //==============================================================================
- void AlertWindow::buttonClicked (Button* button)
- {
- for (int i = 0; i < buttons.size(); i++)
- {
- TextButton* const c = (TextButton*) buttons[i];
-
- if (button->getName() == c->getName())
- {
- if (c->getParentComponent() != 0)
- c->getParentComponent()->exitModalState (c->getCommandID());
-
- break;
- }
- }
- }
-
- //==============================================================================
- void AlertWindow::addButton (const String& name,
- const int returnValue,
- const KeyPress& shortcutKey1,
- const KeyPress& shortcutKey2)
- {
- TextButton* const b = new TextButton (name, String::empty);
-
- b->setWantsKeyboardFocus (true);
- b->setMouseClickGrabsKeyboardFocus (false);
- b->setCommandToTrigger (0, returnValue, false);
- b->addShortcut (shortcutKey1);
- b->addShortcut (shortcutKey2);
- b->addButtonListener (this);
- b->changeWidthToFitText (getLookAndFeel().getAlertWindowButtonHeight());
-
- addAndMakeVisible (b, 0);
- buttons.add (b);
-
- updateLayout (false);
- }
-
- int AlertWindow::getNumButtons() const
- {
- return buttons.size();
- }
-
- //==============================================================================
- void AlertWindow::addTextEditor (const String& name,
- const String& initialContents,
- const String& onScreenLabel,
- const bool isPasswordBox)
- {
- AlertWindowTextEditor* const tc = new AlertWindowTextEditor (name, isPasswordBox);
-
- tc->setColour (TextEditor::outlineColourId, findColour (ComboBox::outlineColourId));
- tc->setFont (font);
- tc->setText (initialContents);
- tc->setCaretPosition (initialContents.length());
- addAndMakeVisible (tc);
- textBoxes.add (tc);
- allComps.add (tc);
- textboxNames.add (onScreenLabel);
-
- updateLayout (false);
- }
-
- const String AlertWindow::getTextEditorContents (const String& nameOfTextEditor) const
- {
- for (int i = textBoxes.size(); --i >= 0;)
- if (((TextEditor*)textBoxes[i])->getName() == nameOfTextEditor)
- return ((TextEditor*)textBoxes[i])->getText();
-
- return String::empty;
- }
-
-
- //==============================================================================
- void AlertWindow::addComboBox (const String& name,
- const StringArray& items,
- const String& onScreenLabel)
- {
- ComboBox* const cb = new ComboBox (name);
-
- for (int i = 0; i < items.size(); ++i)
- cb->addItem (items[i], i + 1);
-
- addAndMakeVisible (cb);
- cb->setSelectedItemIndex (0);
-
- comboBoxes.add (cb);
- allComps.add (cb);
-
- comboBoxNames.add (onScreenLabel);
-
- updateLayout (false);
- }
-
- ComboBox* AlertWindow::getComboBoxComponent (const String& nameOfList) const
- {
- for (int i = comboBoxes.size(); --i >= 0;)
- if (((ComboBox*) comboBoxes[i])->getName() == nameOfList)
- return (ComboBox*) comboBoxes[i];
-
- return 0;
- }
-
- //==============================================================================
- class AlertTextComp : public TextEditor
- {
- AlertTextComp (const AlertTextComp&);
- const AlertTextComp& operator= (const AlertTextComp&);
-
- int bestWidth;
-
- public:
- AlertTextComp (const String& message,
- const Font& font)
- {
- setReadOnly (true);
- setMultiLine (true, true);
- setCaretVisible (false);
- setScrollbarsShown (true);
- lookAndFeelChanged();
- setWantsKeyboardFocus (false);
-
- setFont (font);
- setText (message, false);
-
- bestWidth = 2 * (int) sqrt (font.getHeight() * font.getStringWidth (message));
-
- setColour (TextEditor::backgroundColourId, Colours::transparentBlack);
- setColour (TextEditor::outlineColourId, Colours::transparentBlack);
- setColour (TextEditor::shadowColourId, Colours::transparentBlack);
- }
-
- ~AlertTextComp()
- {
- }
-
- int getPreferredWidth() const throw() { return bestWidth; }
-
- void updateLayout (const int width)
- {
- TextLayout text;
- text.appendText (getText(), getFont());
- text.layout (width - 8, Justification::topLeft, true);
- setSize (width, jmin (width, text.getHeight() + (int) getFont().getHeight()));
- }
- };
-
- void AlertWindow::addTextBlock (const String& text)
- {
- AlertTextComp* const c = new AlertTextComp (text, font);
-
- textBlocks.add (c);
- allComps.add (c);
-
- addAndMakeVisible (c);
-
- updateLayout (false);
- }
-
- //==============================================================================
- void AlertWindow::addProgressBarComponent (double& progressValue)
- {
- ProgressBar* const 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 (const int index) const
- {
- return (Component*) customComps [index];
- }
-
- Component* AlertWindow::removeCustomComponent (const int index)
- {
- Component* const c = getCustomComponent (index);
-
- if (c != 0)
- {
- customComps.removeValue (c);
- allComps.removeValue (c);
- removeChildComponent (c);
-
- updateLayout (false);
- }
-
- return c;
- }
-
- //==============================================================================
- void AlertWindow::paint (Graphics& g)
- {
- getLookAndFeel().drawAlertBox (g, *this, textArea, textLayout);
-
- g.setColour (findColour (textColourId));
- g.setFont (getLookAndFeel().getAlertWindowFont());
-
- int i;
- for (i = textBoxes.size(); --i >= 0;)
- {
- if (textboxNames[i].isNotEmpty())
- {
- const TextEditor* const te = (TextEditor*) textBoxes[i];
-
- g.drawFittedText (textboxNames[i],
- te->getX(), te->getY() - 14,
- te->getWidth(), 14,
- Justification::centredLeft, 1);
- }
- }
-
- for (i = comboBoxNames.size(); --i >= 0;)
- {
- if (comboBoxNames[i].isNotEmpty())
- {
- const ComboBox* const cb = (ComboBox*) comboBoxes[i];
-
- g.drawFittedText (comboBoxNames[i],
- cb->getX(), cb->getY() - 14,
- cb->getWidth(), 14,
- Justification::centredLeft, 1);
- }
- }
- }
-
- void AlertWindow::updateLayout (const bool onlyIncreaseSize)
- {
- const int wid = jmax (font.getStringWidth (text),
- font.getStringWidth (getName()));
-
- const int sw = (int) sqrt (font.getHeight() * wid);
- int w = jmin (300 + sw * 2, (int) (getParentWidth() * 0.7f));
- const int edgeGap = 10;
- int iconSpace;
-
- if (alertIconType == NoIcon)
- {
- textLayout.layout (w, Justification::horizontallyCentred, true);
- iconSpace = 0;
- }
- else
- {
- textLayout.layout (w, Justification::left, true);
- iconSpace = iconWidth;
- }
-
- w = jmax (350, textLayout.getWidth() + iconSpace + edgeGap * 4);
- w = jmin (w, (int) (getParentWidth() * 0.7f));
-
- const int textLayoutH = textLayout.getHeight();
- const int textBottom = 16 + titleH + textLayoutH;
- int h = textBottom;
-
- int buttonW = 40;
- int i;
- for (i = 0; i < buttons.size(); ++i)
- buttonW += 16 + ((const TextButton*) buttons[i])->getWidth();
-
- w = jmax (buttonW, w);
-
- h += (textBoxes.size() + comboBoxes.size() + progressBars.size()) * 50;
-
- if (buttons.size() > 0)
- h += 20 + ((TextButton*) buttons[0])->getHeight();
-
- for (i = customComps.size(); --i >= 0;)
- {
- w = jmax (w, ((Component*) customComps[i])->getWidth() + 40);
- h += 10 + ((Component*) customComps[i])->getHeight();
- }
-
- for (i = textBlocks.size(); --i >= 0;)
- {
- const AlertTextComp* const ac = (AlertTextComp*) textBlocks[i];
- w = jmax (w, ac->getPreferredWidth());
- }
-
- w = jmin (w, (int) (getParentWidth() * 0.7f));
-
- for (i = textBlocks.size(); --i >= 0;)
- {
- AlertTextComp* const ac = (AlertTextComp*) textBlocks[i];
- 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 (0, w, h);
- }
- else
- {
- const int cx = getX() + getWidth() / 2;
- const int cy = getY() + getHeight() / 2;
-
- setBounds (cx - w / 2,
- cy - h / 2,
- w, h);
- }
-
- textArea.setBounds (edgeGap, edgeGap, w - (edgeGap * 2), h - edgeGap);
-
- const int spacer = 16;
- int totalWidth = -spacer;
-
- for (i = buttons.size(); --i >= 0;)
- totalWidth += ((TextButton*) buttons[i])->getWidth() + spacer;
-
- int x = (w - totalWidth) / 2;
- int y = (int) (getHeight() * 0.95f);
-
- for (i = 0; i < buttons.size(); ++i)
- {
- TextButton* const c = (TextButton*) buttons[i];
- 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 (i = 0; i < allComps.size(); ++i)
- {
- Component* const c = (Component*) allComps[i];
-
- const int h = 22;
-
- const int comboIndex = comboBoxes.indexOf (c);
- if (comboIndex >= 0 && comboBoxNames [comboIndex].isNotEmpty())
- y += 18;
-
- const int tbIndex = textBoxes.indexOf (c);
- if (tbIndex >= 0 && textboxNames[tbIndex].isNotEmpty())
- y += 18;
-
- if (customComps.contains (c) || textBlocks.contains (c))
- {
- c->setTopLeftPosition ((getWidth() - c->getWidth()) / 2, y);
- y += c->getHeight() + 10;
- }
- else
- {
- c->setBounds (proportionOfWidth (0.1f), y, proportionOfWidth (0.8f), h);
- y += h + 10;
- }
- }
-
- setWantsKeyboardFocus (getNumChildComponents() == 0);
- }
-
- bool AlertWindow::containsAnyExtraComponents() const
- {
- return textBoxes.size()
- + comboBoxes.size()
- + progressBars.size()
- + customComps.size() > 0;
- }
-
- //==============================================================================
- void AlertWindow::mouseDown (const MouseEvent&)
- {
- dragger.startDraggingComponent (this, &constrainer);
- }
-
- void AlertWindow::mouseDrag (const MouseEvent& e)
- {
- dragger.dragComponent (this, e);
- }
-
- bool AlertWindow::keyPressed (const KeyPress& key)
- {
- for (int i = buttons.size(); --i >= 0;)
- {
- TextButton* const b = (TextButton*) buttons[i];
-
- if (b->isRegisteredForShortcut (key))
- {
- b->triggerClick();
- return true;
- }
- }
-
- if (key.isKeyCode (KeyPress::escapeKey) && buttons.size() == 0)
- {
- exitModalState (0);
- return true;
- }
- else if (key.isKeyCode (KeyPress::returnKey) && buttons.size() == 1)
- {
- ((TextButton*) buttons.getFirst())->triggerClick();
- return true;
- }
-
- return false;
- }
-
- void AlertWindow::lookAndFeelChanged()
- {
- const int flags = getLookAndFeel().getAlertBoxWindowFlags();
-
- setUsingNativeTitleBar ((flags & ComponentPeer::windowHasTitleBar) != 0);
- setDropShadowEnabled ((flags & ComponentPeer::windowHasDropShadow) != 0);
- }
-
- //==============================================================================
- struct AlertWindowInfo
- {
- String title, message, button1, button2, button3;
- AlertWindow::AlertIconType iconType;
- int numButtons;
-
- int run() const
- {
- return (int) (pointer_sized_int)
- MessageManager::getInstance()->callFunctionOnMessageThread (showCallback, (void*) this);
- }
-
- private:
- int show() const
- {
- AlertWindow aw (title, message, iconType);
-
- if (numButtons == 1)
- {
- aw.addButton (button1, 0,
- KeyPress (KeyPress::escapeKey, 0, 0),
- KeyPress (KeyPress::returnKey, 0, 0));
- }
- else
- {
- const KeyPress button1ShortCut (CharacterFunctions::toLowerCase (button1[0]), 0, 0);
- KeyPress button2ShortCut (CharacterFunctions::toLowerCase (button2[0]), 0, 0);
- if (button1ShortCut == button2ShortCut)
- button2ShortCut = KeyPress();
-
- if (numButtons == 2)
- {
- aw.addButton (button1, 1, KeyPress (KeyPress::returnKey, 0, 0), button1ShortCut);
- aw.addButton (button2, 0, KeyPress (KeyPress::escapeKey, 0, 0), button2ShortCut);
- }
- else
- {
- jassert (numButtons == 3);
-
- aw.addButton (button1, 1, button1ShortCut);
- aw.addButton (button2, 2, button2ShortCut);
- aw.addButton (button3, 0, KeyPress (KeyPress::escapeKey, 0, 0));
- }
- }
-
- return aw.runModalLoop();
- }
-
- static void* showCallback (void* userData)
- {
- return (void*) (pointer_sized_int) ((const AlertWindowInfo*) userData)->show();
- }
- };
-
- void AlertWindow::showMessageBox (AlertIconType iconType,
- const String& title,
- const String& message,
- const String& buttonText)
- {
- AlertWindowInfo info;
- info.title = title;
- info.message = message;
- info.button1 = buttonText.isEmpty() ? TRANS("ok") : buttonText;
- info.iconType = iconType;
- info.numButtons = 1;
-
- info.run();
- }
-
- bool AlertWindow::showOkCancelBox (AlertIconType iconType,
- const String& title,
- const String& message,
- const String& button1Text,
- const String& button2Text)
- {
- AlertWindowInfo info;
- info.title = title;
- info.message = message;
- info.button1 = button1Text.isEmpty() ? TRANS("ok") : button1Text;
- info.button2 = button2Text.isEmpty() ? TRANS("cancel") : button2Text;
- info.iconType = iconType;
- info.numButtons = 2;
-
- return info.run() != 0;
- }
-
- int AlertWindow::showYesNoCancelBox (AlertIconType iconType,
- const String& title,
- const String& message,
- const String& button1Text,
- const String& button2Text,
- const String& button3Text)
- {
- AlertWindowInfo info;
- info.title = title;
- info.message = message;
- info.button1 = button1Text.isEmpty() ? TRANS("yes") : button1Text;
- info.button2 = button2Text.isEmpty() ? TRANS("no") : button2Text;
- info.button3 = button3Text.isEmpty() ? TRANS("cancel") : button3Text;
- info.iconType = iconType;
- info.numButtons = 3;
-
- return info.run();
- }
-
- END_JUCE_NAMESPACE
|