diff --git a/extras/juce demo/src/ApplicationStartup.cpp b/extras/juce demo/src/ApplicationStartup.cpp index 729f5a859f..88000615ed 100644 --- a/extras/juce demo/src/ApplicationStartup.cpp +++ b/extras/juce demo/src/ApplicationStartup.cpp @@ -1,176 +1,176 @@ -/* - ============================================================================== - - 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 "jucedemo_headers.h" -#include "MainDemoWindow.h" - - -//============================================================================== -class JUCEDemoApplication : public JUCEApplication -{ - /* Important! NEVER embed objects directly inside your JUCEApplication class! Use - ONLY pointers to objects, which you should create during the initialise() method - (NOT in the constructor!) and delete in the shutdown() method (NOT in the - destructor!) - - This is because the application object gets created before Juce has been properly - initialised, so any embedded objects would also get constructed too soon. - */ - MainDemoWindow* theMainWindow; - -public: - //============================================================================== - JUCEDemoApplication() - : theMainWindow (0) - { - // NEVER do anything in here that could involve any Juce function being called - // - leave all your startup tasks until the initialise() method. - } - - ~JUCEDemoApplication() - { - // Your shutdown() method should already have done all the things necessary to - // clean up this app object, so you should never need to put anything in - // the destructor. - - // Making any Juce calls in here could be very dangerous... - } - - //============================================================================== - void initialise (const String& commandLine) - { - // just create the main window... - theMainWindow = new MainDemoWindow(); - theMainWindow->centreWithSize (700, 600); - theMainWindow->setVisible (true); - - // this little function just demonstrates a few system info calls - Logger::outputDebugString (collectSomeSystemInfo()); - - /* on return from this method, the app will go into its the main event - dispatch loop, and this will run until something calls - JUCEAppliction::quit(). - - In this case, JUCEAppliction::quit() will be called by the - demo window when the user clicks on its close button. - */ - } - - void shutdown() - { - delete theMainWindow; - theMainWindow = 0; - } - - //============================================================================== - const String getApplicationName() - { - return T("JUCE Demo"); - } - - const String getApplicationVersion() - { - return T("1.0"); - } - - bool moreThanOneInstanceAllowed() - { - return true; - } - - void anotherInstanceStarted (const String& commandLine) - { - // This will get called if the user launches another copy of the app, but - // there's nothing that the demo app needs to do here. - } - -private: - //============================================================================== - // this little function just demonstrates a few system info calls - static const String collectSomeSystemInfo() - { - String systemInfo; - - systemInfo - << T("Time and date: ") << Time::getCurrentTime().toString (true, true) - << T("\nOperating system: ") << SystemStats::getOperatingSystemName() - << T("\nCPU vendor: ") << SystemStats::getCpuVendor() - << T("\nCPU speed: ") << SystemStats::getCpuSpeedInMegaherz() << T("MHz\n") - << T("\nNumber of CPUs: ") << SystemStats::getNumCpus() - << T("\nCPU has MMX: ") << (SystemStats::hasMMX() ? T("yes") : T("no")) - << T("\nCPU has SSE: ") << (SystemStats::hasSSE() ? T("yes") : T("no")) - << T("\nCPU has SSE2: ") << (SystemStats::hasSSE2() ? T("yes") : T("no")) - << T("\nCPU has 3DNOW: ") << (SystemStats::has3DNow() ? T("yes") : T("no")) - << T("\nMemory size: ") << SystemStats::getMemorySizeInMegabytes() << T("MB\n"); - - int64 macAddresses[8]; - const int numAddresses = SystemStats::getMACAddresses (macAddresses, 8); - - for (int i = 0; i < numAddresses; ++i) - { - systemInfo - << T("Found network card MAC address: ") - << String::formatted (T("%02x-%02x-%02x-%02x-%02x-%02x\n"), - 0xff & (int) (macAddresses [i] >> 40), - 0xff & (int) (macAddresses [i] >> 32), - 0xff & (int) (macAddresses [i] >> 24), - 0xff & (int) (macAddresses [i] >> 16), - 0xff & (int) (macAddresses [i] >> 8), - 0xff & (int) macAddresses [i]); - } - - systemInfo - << T("Current executable file: ") - << File::getSpecialLocation (File::currentExecutableFile).getFullPathName() - << T("\nCurrent application file: ") - << File::getSpecialLocation (File::currentApplicationFile).getFullPathName() - << T("\nUser home directory: ") - << File::getSpecialLocation (File::userHomeDirectory).getFullPathName() - << T("\nUser documents directory: ") - << File::getSpecialLocation (File::userDocumentsDirectory).getFullPathName() - << T("\nUser application data directory: ") - << File::getSpecialLocation (File::userApplicationDataDirectory).getFullPathName() - << T("\nCommon application data directory: ") - << File::getSpecialLocation (File::commonApplicationDataDirectory).getFullPathName() - << T("\nTemp directory: ") - << File::getSpecialLocation (File::tempDirectory).getFullPathName() - << T("\n\n"); - - return systemInfo; - } -}; - - -//============================================================================== -/* - This macro creates the application's main() function.. -*/ -START_JUCE_APPLICATION (JUCEDemoApplication) +/* + ============================================================================== + + 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 "jucedemo_headers.h" +#include "MainDemoWindow.h" + + +//============================================================================== +class JUCEDemoApplication : public JUCEApplication +{ + /* Important! NEVER embed objects directly inside your JUCEApplication class! Use + ONLY pointers to objects, which you should create during the initialise() method + (NOT in the constructor!) and delete in the shutdown() method (NOT in the + destructor!) + + This is because the application object gets created before Juce has been properly + initialised, so any embedded objects would also get constructed too soon. + */ + MainDemoWindow* theMainWindow; + +public: + //============================================================================== + JUCEDemoApplication() + : theMainWindow (0) + { + // NEVER do anything in here that could involve any Juce function being called + // - leave all your startup tasks until the initialise() method. + } + + ~JUCEDemoApplication() + { + // Your shutdown() method should already have done all the things necessary to + // clean up this app object, so you should never need to put anything in + // the destructor. + + // Making any Juce calls in here could be very dangerous... + } + + //============================================================================== + void initialise (const String& commandLine) + { + // just create the main window... + theMainWindow = new MainDemoWindow(); + theMainWindow->centreWithSize (700, 600); + theMainWindow->setVisible (true); + + // this little function just demonstrates a few system info calls + Logger::outputDebugString (collectSomeSystemInfo()); + + /* on return from this method, the app will go into its the main event + dispatch loop, and this will run until something calls + JUCEAppliction::quit(). + + In this case, JUCEAppliction::quit() will be called by the + demo window when the user clicks on its close button. + */ + } + + void shutdown() + { + delete theMainWindow; + theMainWindow = 0; + } + + //============================================================================== + const String getApplicationName() + { + return T("JUCE Demo"); + } + + const String getApplicationVersion() + { + return T("1.0"); + } + + bool moreThanOneInstanceAllowed() + { + return true; + } + + void anotherInstanceStarted (const String& commandLine) + { + // This will get called if the user launches another copy of the app, but + // there's nothing that the demo app needs to do here. + } + +private: + //============================================================================== + // this little function just demonstrates a few system info calls + static const String collectSomeSystemInfo() + { + String systemInfo; + + systemInfo + << T("Time and date: ") << Time::getCurrentTime().toString (true, true) + << T("\nOperating system: ") << SystemStats::getOperatingSystemName() + << T("\nCPU vendor: ") << SystemStats::getCpuVendor() + << T("\nCPU speed: ") << SystemStats::getCpuSpeedInMegaherz() << T("MHz\n") + << T("\nNumber of CPUs: ") << SystemStats::getNumCpus() + << T("\nCPU has MMX: ") << (SystemStats::hasMMX() ? T("yes") : T("no")) + << T("\nCPU has SSE: ") << (SystemStats::hasSSE() ? T("yes") : T("no")) + << T("\nCPU has SSE2: ") << (SystemStats::hasSSE2() ? T("yes") : T("no")) + << T("\nCPU has 3DNOW: ") << (SystemStats::has3DNow() ? T("yes") : T("no")) + << T("\nMemory size: ") << SystemStats::getMemorySizeInMegabytes() << T("MB\n"); + + int64 macAddresses[8]; + const int numAddresses = SystemStats::getMACAddresses (macAddresses, 8); + + for (int i = 0; i < numAddresses; ++i) + { + systemInfo + << T("Found network card MAC address: ") + << String::formatted (T("%02x-%02x-%02x-%02x-%02x-%02x\n"), + 0xff & (int) (macAddresses [i] >> 40), + 0xff & (int) (macAddresses [i] >> 32), + 0xff & (int) (macAddresses [i] >> 24), + 0xff & (int) (macAddresses [i] >> 16), + 0xff & (int) (macAddresses [i] >> 8), + 0xff & (int) macAddresses [i]); + } + + systemInfo + << T("Current executable file: ") + << File::getSpecialLocation (File::currentExecutableFile).getFullPathName() + << T("\nCurrent application file: ") + << File::getSpecialLocation (File::currentApplicationFile).getFullPathName() + << T("\nUser home directory: ") + << File::getSpecialLocation (File::userHomeDirectory).getFullPathName() + << T("\nUser documents directory: ") + << File::getSpecialLocation (File::userDocumentsDirectory).getFullPathName() + << T("\nUser application data directory: ") + << File::getSpecialLocation (File::userApplicationDataDirectory).getFullPathName() + << T("\nCommon application data directory: ") + << File::getSpecialLocation (File::commonApplicationDataDirectory).getFullPathName() + << T("\nTemp directory: ") + << File::getSpecialLocation (File::tempDirectory).getFullPathName() + << T("\n\n"); + + return systemInfo; + } +}; + + +//============================================================================== +/* + This macro creates the application's main() function.. +*/ +START_JUCE_APPLICATION (JUCEDemoApplication) diff --git a/extras/juce demo/src/demos/WidgetsDemo.cpp b/extras/juce demo/src/demos/WidgetsDemo.cpp index 9dd7eff920..7bab1479dd 100644 --- a/extras/juce demo/src/demos/WidgetsDemo.cpp +++ b/extras/juce demo/src/demos/WidgetsDemo.cpp @@ -1,1427 +1,1427 @@ -/* - ============================================================================== - - 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 "../jucedemo_headers.h" - - -//============================================================================== -class BouncingBallComponent : public Component, - public Timer -{ - Colour colour; - float x, y, dx, dy; - -public: - BouncingBallComponent() - { - x = Random::getSystemRandom().nextFloat() * 100.0f; - y = Random::getSystemRandom().nextFloat() * 100.0f; - - dx = Random::getSystemRandom().nextFloat() * 8.0f - 4.0f; - dy = Random::getSystemRandom().nextFloat() * 8.0f - 4.0f; - - colour = Colour (Random::getSystemRandom().nextInt()) - .withAlpha (0.5f) - .withBrightness (0.7f); - - int size = 10 + Random::getSystemRandom().nextInt (30); - setSize (size, size); - - startTimer (60); - } - - ~BouncingBallComponent() - { - } - - void paint (Graphics& g) - { - g.setColour (colour); - g.fillEllipse (x - getX(), y - getY(), getWidth() - 2.0f, getHeight() - 2.0f); - } - - void timerCallback() - { - x += dx; - y += dy; - - if (x < 0) - dx = fabsf (dx); - - if (x > getParentWidth()) - dx = -fabsf (dx); - - if (y < 0) - dy = fabsf (dy); - - if (y > getParentHeight()) - dy = -fabsf (dy); - - setTopLeftPosition ((int) x, (int) y); - } - - bool hitTest (int x, int y) - { - return false; - } -}; - -//============================================================================== -class DragOntoDesktopDemoComp : public Component -{ - Component* parent; - ComponentDragger dragger; - -public: - DragOntoDesktopDemoComp (Component* p) - : parent (p) - { - // show off semi-transparency if it's supported by the current OS. - setOpaque (! Desktop::canUseSemiTransparentWindows()); - - for (int i = 3; --i >= 0;) - addAndMakeVisible (new BouncingBallComponent()); - } - - ~DragOntoDesktopDemoComp() - { - deleteAllChildren(); - } - - void mouseDown (const MouseEvent& e) - { - dragger.startDraggingComponent (this, 0); - } - - void mouseDrag (const MouseEvent& e) - { - if (! parent->isValidComponent()) - { - delete this; - } - else - { - MouseEvent e2 (e.getEventRelativeTo (parent)); - - // if the mouse is inside the parent component, we'll make that the - // parent - otherwise, we'll put this comp on the desktop. - if (e2.x >= 0 && e2.y >= 0 && e2.x < parent->getWidth() && e2.y < parent->getHeight()) - { - // re-add this component to a parent component, which will - // remove it from the desktop.. - parent->addChildComponent (this); - } - else - { - // add the component to the desktop, which will remove it - // from its current parent component.. - addToDesktop (ComponentPeer::windowIsTemporary); - } - - dragger.dragComponent (this, e); - } - } - - void paint (Graphics& g) - { - if (isOpaque()) - g.fillAll (Colours::white); - else - g.fillAll (Colours::blue.withAlpha (0.2f)); - - String desc (T("drag this box onto the desktop to show how the same component can move from being lightweight to being a separate window")); - - g.setFont (15.0f); - g.setColour (Colours::black); - g.drawFittedText (desc, 4, 0, getWidth() - 8, getHeight(), Justification::horizontallyJustified, 5); - - g.drawRect (0, 0, getWidth(), getHeight()); - } -}; - -//============================================================================== -class CustomMenuComponent : public PopupMenuCustomComponent, - public Timer -{ - int blobX, blobY; - -public: - CustomMenuComponent() - : blobX (0), - blobY (0) - { - // set off a timer to move a blob around on this component every - // 300 milliseconds - see the timerCallback() method. - startTimer (300); - } - - ~CustomMenuComponent() - { - } - - void getIdealSize (int& idealWidth, - int& idealHeight) - { - // tells the menu how big we'd like to be.. - idealWidth = 200; - idealHeight = 60; - } - - void paint (Graphics& g) - { - g.fillAll (Colours::yellow.withAlpha (0.3f)); - - g.setColour (Colours::pink); - g.fillEllipse ((float) blobX, (float) blobY, 30.0f, 40.0f); - - g.setFont (14.0f, Font::italic); - g.setColour (Colours::black); - - g.drawFittedText (T("this is a customised menu item (also demonstrating the Timer class)..."), - 4, 0, getWidth() - 8, getHeight(), - Justification::centred, 3); - } - - void timerCallback() - { - blobX = Random::getSystemRandom().nextInt (getWidth()); - blobY = Random::getSystemRandom().nextInt (getHeight()); - repaint(); - } -}; - -//============================================================================== -/** To demonstrate how sliders can have custom snapping applied to their values, - this simple class snaps the value to 50 if it comes near. -*/ -class SnappingSlider : public Slider -{ -public: - SnappingSlider (const String& name) - : Slider (name) - { - } - - double snapValue (double attemptedValue, const bool userIsDragging) - { - if (! userIsDragging) - return attemptedValue; // if they're entering the value in the text-box, don't mess with it. - - if (attemptedValue > 40 && attemptedValue < 60) - return 50.0; - else - return attemptedValue; - } -}; - -/** A TextButton that pops up a colour chooser to change its colours. */ -class ColourChangeButton : public TextButton, - public ChangeListener -{ -public: - ColourChangeButton() - : TextButton (T("click to change colour...")) - { - setSize (10, 24); - changeWidthToFitText(); - } - - ~ColourChangeButton() - { - } - - void clicked() - { - // create two colour selector components for our background and - // text colour.. - ColourSelector colourSelector1; - colourSelector1.setName (T("background")); - colourSelector1.setCurrentColour (findColour (TextButton::buttonColourId)); - colourSelector1.addChangeListener (this); - - ColourSelector colourSelector2; - colourSelector2.setName (T("text")); - colourSelector2.setCurrentColour (findColour (TextButton::textColourId)); - colourSelector2.addChangeListener (this); - - // and add the selectors as custom menu items to a PopupMenu, putting - // them in two different sub-menus.. - PopupMenu m, sub1, sub2; - - sub1.addCustomItem (1234, &colourSelector1, 300, 300, false); - m.addSubMenu (T("background colour"), sub1); - - sub2.addCustomItem (1234, &colourSelector2, 300, 300, false); - m.addSubMenu (T("text colour"), sub2); - - // and show the menu (modally).. - m.showAt (this); - } - - void changeListenerCallback (void* source) - { - ColourSelector* cs = (ColourSelector*) source; - - if (cs->getName() == T("text")) - setColour (TextButton::textColourId, cs->getCurrentColour()); - else - setColour (TextButton::buttonColourId, cs->getCurrentColour()); - } -}; - -//============================================================================== -// just a component that deletes all its children, to use for the tabbed pages to avoid -// memory leaks when they're deleted -class DemoPageComp : public Component -{ -public: - DemoPageComp() - { - } - - ~DemoPageComp() - { - deleteAllChildren(); - } -}; - -//============================================================================== -static Component* createSlidersPage() -{ - DemoPageComp* page = new DemoPageComp(); - - const int numSliders = 11; - Slider* sliders [numSliders]; - - int i; - for (i = 0; i < numSliders; ++i) - { - if (i == 2) - page->addAndMakeVisible (sliders[i] = new SnappingSlider (T("slider"))); - else - page->addAndMakeVisible (sliders[i] = new Slider (T("slider"))); - - sliders[i]->setRange (0.0, 100.0, 0.1); - sliders[i]->setPopupMenuEnabled (true); - sliders[i]->setValue (Random::getSystemRandom().nextDouble() * 100.0, false, false); - } - - sliders[0]->setSliderStyle (Slider::LinearVertical); - sliders[0]->setTextBoxStyle (Slider::TextBoxBelow, false, 100, 20); - sliders[0]->setBounds (10, 25, 70, 200); - sliders[0]->setDoubleClickReturnValue (true, 50.0); // double-clicking this slider will set it to 50.0 - sliders[0]->setTextValueSuffix (T(" units")); - - sliders[1]->setSliderStyle (Slider::LinearVertical); - sliders[1]->setVelocityBasedMode (true); - sliders[1]->setSkewFactor (0.5); - sliders[1]->setTextBoxStyle (Slider::TextBoxAbove, true, 100, 20); - sliders[1]->setBounds (85, 25, 70, 200); - sliders[1]->setTextValueSuffix (T(" rels")); - - sliders[2]->setSliderStyle (Slider::LinearHorizontal); - sliders[2]->setTextBoxStyle (Slider::TextBoxLeft, false, 80, 20); - sliders[2]->setBounds (180, 35, 150, 20); - - sliders[3]->setSliderStyle (Slider::LinearHorizontal); - sliders[3]->setTextBoxStyle (Slider::NoTextBox, false, 0, 0); - sliders[3]->setBounds (180, 65, 150, 20); - sliders[3]->setPopupDisplayEnabled (true, page); - sliders[3]->setTextValueSuffix (T(" nuns required to change a lightbulb")); - - sliders[4]->setSliderStyle (Slider::IncDecButtons); - sliders[4]->setTextBoxStyle (Slider::TextBoxLeft, false, 50, 20); - sliders[4]->setBounds (180, 105, 100, 20); - sliders[4]->setIncDecButtonsMode (Slider::incDecButtonsDraggable_Vertical); - - sliders[5]->setSliderStyle (Slider::Rotary); - sliders[5]->setRotaryParameters (float_Pi * 1.2f, float_Pi * 2.8f, false); - sliders[5]->setTextBoxStyle (Slider::TextBoxRight, false, 70, 20); - sliders[5]->setBounds (190, 145, 120, 40); - sliders[5]->setTextValueSuffix (T(" mm")); - - sliders[6]->setSliderStyle (Slider::LinearBar); - sliders[6]->setBounds (180, 195, 100, 30); - sliders[6]->setTextValueSuffix (T(" gallons")); - - sliders[7]->setSliderStyle (Slider::TwoValueHorizontal); - sliders[7]->setBounds (360, 20, 160, 40); - - sliders[8]->setSliderStyle (Slider::TwoValueVertical); - sliders[8]->setBounds (360, 110, 40, 160); - - sliders[9]->setSliderStyle (Slider::ThreeValueHorizontal); - sliders[9]->setBounds (360, 70, 160, 40); - - sliders[10]->setSliderStyle (Slider::ThreeValueVertical); - sliders[10]->setBounds (440, 110, 40, 160); - - for (i = 7; i <= 10; ++i) - { - sliders[i]->setTextBoxStyle (Slider::NoTextBox, false, 0, 0); - sliders[i]->setMinValue (Random::getSystemRandom().nextDouble() * 100.0, false, false); - sliders[i]->setMaxValue (Random::getSystemRandom().nextDouble() * 100.0, false, false); - sliders[i]->setPopupDisplayEnabled (true, page); - } - - Label* label = new Label (T("hint"), T("Try right-clicking on a slider for an options menu. \n\nAlso, holding down CTRL while dragging will turn on a slider's velocity-sensitive mode")); - label->setBounds (20, 245, 350, 150); - page->addAndMakeVisible (label); - - return page; -} - -//============================================================================== -static Component* createRadioButtonPage() -{ - DemoPageComp* page = new DemoPageComp(); - - GroupComponent* group = new GroupComponent (T("group"), T("radio buttons")); - group->setBounds (20, 20, 220, 140); - page->addAndMakeVisible (group); - - int i; - for (i = 0; i < 4; ++i) - { - ToggleButton* tb = new ToggleButton (T("radio button #") + String (i + 1)); - page->addAndMakeVisible (tb); - tb->setRadioGroupId (1234); - tb->setBounds (45, 46 + i * 22, 180, 22); - tb->setTooltip (T("a set of mutually-exclusive radio buttons")); - - if (i == 0) - tb->setToggleState (true, false); - } - - for (i = 0; i < 4; ++i) - { - DrawablePath normal, over; - - Path p; - p.addStar (0.0f, 0.0f, i + 5, 20.0f, 50.0f, -0.2f); - normal.setPath (p); - normal.setSolidFill (Colours::lightblue); - normal.setOutline (4.0f, Colours::black); - - over.setPath (p); - over.setSolidFill (Colours::blue); - over.setOutline (4.0f, Colours::black); - - DrawableButton* db = new DrawableButton (String (i + 5) + T(" points"), DrawableButton::ImageAboveTextLabel); - db->setImages (&normal, &over, 0); - - page->addAndMakeVisible (db); - db->setClickingTogglesState (true); - db->setRadioGroupId (23456); - - const int buttonSize = 50; - db->setBounds (25 + i * buttonSize, 180, buttonSize, buttonSize); - - if (i == 0) - db->setToggleState (true, false); - } - - for (i = 0; i < 4; ++i) - { - TextButton* tb = new TextButton (T("button ") + String (i + 1)); - - page->addAndMakeVisible (tb); - tb->setClickingTogglesState (true); - tb->setRadioGroupId (34567); - tb->setColour (TextButton::buttonColourId, Colours::white); - tb->setColour (TextButton::buttonOnColourId, Colours::blueviolet.brighter()); - - tb->setBounds (20 + i * 55, 260, 55, 24); - tb->setConnectedEdges (((i != 0) ? Button::ConnectedOnLeft : 0) - | ((i != 3) ? Button::ConnectedOnRight : 0)); - - if (i == 0) - tb->setToggleState (true, false); - } - - return page; -} - -//============================================================================== -class ButtonsPage : public Component, - public ButtonListener -{ -public: - ButtonsPage (ButtonListener* buttonListener) - { - //============================================================================== - // create some drawables to use for our drawable buttons... - DrawablePath normal, over; - - Path p; - p.addStar (0.0f, 0.0f, 5, 20.0f, 50.0f, 0.2f); - normal.setPath (p); - normal.setSolidFill (Colours::red); - - p.clear(); - p.addStar (0.0f, 0.0f, 7, 30.0f, 50.0f, 0.0f); - over.setPath (p); - over.setSolidFill (Colours::pink); - over.setOutline (5.0f, Colours::black); - - DrawableImage down; - down.setImage (ImageCache::getFromMemory (BinaryData::juce_png, BinaryData::juce_pngSize), true); - down.setOverlayColour (Colours::black.withAlpha (0.3f)); - - //============================================================================== - // create an image-above-text button from these drawables.. - DrawableButton* db = new DrawableButton (T("Button 1"), DrawableButton::ImageAboveTextLabel); - db->setImages (&normal, &over, &down); - - addAndMakeVisible (db); - db->setBounds (10, 30, 80, 80); - db->setTooltip (T("this is a DrawableButton with a label")); - - //============================================================================== - // create an image-only button from these drawables.. - db = new DrawableButton (T("Button 2"), DrawableButton::ImageFitted); - db->setImages (&normal, &over, &down); - db->setClickingTogglesState (true); - - addAndMakeVisible (db); - db->setBounds (90, 30, 80, 80); - db->setTooltip (T("this is an image-only DrawableButton")); - db->addButtonListener (buttonListener); - - //============================================================================== - // create an image-on-button-shape button from the same drawables.. - db = new DrawableButton (T("Button 3"), DrawableButton::ImageOnButtonBackground); - db->setImages (&normal, 0, 0); - - addAndMakeVisible (db); - db->setBounds (200, 30, 110, 25); - db->setTooltip (T("this is a DrawableButton on a standard button background")); - - //============================================================================== - db = new DrawableButton (T("Button 4"), DrawableButton::ImageOnButtonBackground); - db->setImages (&normal, &over, &down); - db->setClickingTogglesState (true); - db->setBackgroundColours (Colours::white, Colours::yellow); - - addAndMakeVisible (db); - db->setBounds (200, 70, 50, 50); - db->setTooltip (T("this is a DrawableButton on a standard button background")); - db->addButtonListener (buttonListener); - - //============================================================================== - HyperlinkButton* hyperlink - = new HyperlinkButton (T("this is a HyperlinkButton"), - URL (T("http://www.rawmaterialsoftware.com/juce"))); - - hyperlink->setBounds (10, 130, 200, 24); - addAndMakeVisible (hyperlink); - - //============================================================================== - ImageButton* imageButton = new ImageButton (T("imagebutton")); - addAndMakeVisible (imageButton); - - Image* juceImage = ImageCache::getFromMemory (BinaryData::juce_png, BinaryData::juce_pngSize); - ImageCache::incReferenceCount (juceImage); - ImageCache::incReferenceCount (juceImage); - - imageButton->setImages (true, true, true, - juceImage, 0.7f, Colours::transparentBlack, - juceImage, 1.0f, Colours::transparentBlack, - juceImage, 1.0f, Colours::pink.withAlpha (0.8f), - 0.5f); - - imageButton->setTopLeftPosition (10, 160); - imageButton->setTooltip (T("image button - showing alpha-channel hit-testing and colour overlay when clicked")); - - //============================================================================== - ColourChangeButton* colourChangeButton = new ColourChangeButton(); - addAndMakeVisible (colourChangeButton); - colourChangeButton->setTopLeftPosition (350, 30); - - //============================================================================== - animateButton = new TextButton (T("click to animate...")); - addAndMakeVisible (animateButton); - animateButton->changeWidthToFitText (24); - animateButton->setTopLeftPosition (350, 70); - animateButton->addButtonListener (this); - } - - ~ButtonsPage() - { - deleteAllChildren(); - } - - void buttonClicked (Button*) - { - for (int i = getNumChildComponents(); --i >= 0;) - { - if (getChildComponent (i) != animateButton) - { - animator.animateComponent (getChildComponent (i), - Rectangle (Random::getSystemRandom().nextInt (getWidth() / 2), - Random::getSystemRandom().nextInt (getHeight() / 2), - 60 + Random::getSystemRandom().nextInt (getWidth() / 3), - 16 + Random::getSystemRandom().nextInt (getHeight() / 6)), - 500 + Random::getSystemRandom().nextInt (2000), - Random::getSystemRandom().nextDouble(), - Random::getSystemRandom().nextDouble()); - } - } - } - -private: - TextButton* animateButton; - ComponentAnimator animator; -}; - - -//============================================================================== -static Component* createMiscPage() -{ - DemoPageComp* page = new DemoPageComp(); - - TextEditor* textEditor = new TextEditor(); - page->addAndMakeVisible (textEditor); - textEditor->setBounds (10, 25, 200, 24); - textEditor->setText (T("single-line text box")); - - textEditor = new TextEditor (T("password"), (tchar) 0x2022); - page->addAndMakeVisible (textEditor); - textEditor->setBounds (10, 55, 200, 24); - textEditor->setText (T("password")); - - //============================================================================== - ComboBox* comboBox = new ComboBox (T("combo")); - page->addAndMakeVisible (comboBox); - comboBox->setBounds (300, 25, 200, 24); - comboBox->setEditableText (true); - comboBox->setJustificationType (Justification::centred); - - int i; - for (i = 1; i < 100; ++i) - comboBox->addItem (T("combo box item ") + String (i), i); - - comboBox->setSelectedId (1); - - DragOntoDesktopDemoComp* d = new DragOntoDesktopDemoComp (page); - page->addAndMakeVisible (d); - d->setBounds (20, 100, 200, 80); - - return page; -} - -//============================================================================== -class ToolbarDemoComp : public Component, - public SliderListener, - public ButtonListener -{ -public: - ToolbarDemoComp (ApplicationCommandManager* commandManager) - { - // Create and add the toolbar... - addAndMakeVisible (toolbar = new Toolbar()); - - // And use our item factory to add a set of default icons to it... - toolbar->addDefaultItems (factory); - - // Now we'll just create the other sliders and buttons on the demo page, which adjust - // the toolbar's properties... - Label* info = new Label (String::empty, - "As well as showing off toolbars, this demo illustrates how to store " - "a set of SVG files in a Zip file, embed that in your application, and read " - "them back in at runtime.\n\nThe icon images here are taken from the open-source " - "Tango icon project."); - - addAndMakeVisible (info); - info->setJustificationType (Justification::topLeft); - info->setBounds (80, 80, 450, 100); - info->setInterceptsMouseClicks (false, false); - - addAndMakeVisible (depthSlider = new Slider (T("toolbar depth:"))); - depthSlider->setRange (10.0, 200.0, 1.0); - depthSlider->setValue (50, false); - depthSlider->setSliderStyle (Slider::LinearHorizontal); - depthSlider->setTextBoxStyle (Slider::TextBoxLeft, false, 80, 20); - depthSlider->addListener (this); - depthSlider->setBounds (80, 210, 300, 22); - (new Label (depthSlider->getName(), depthSlider->getName()))->attachToComponent (depthSlider, false); - - addAndMakeVisible (orientationButton = new TextButton (T("vertical/horizontal"))); - orientationButton->addButtonListener (this); - orientationButton->changeWidthToFitText (22); - orientationButton->setTopLeftPosition (depthSlider->getX(), depthSlider->getBottom() + 20); - - addAndMakeVisible (customiseButton = new TextButton (T("customise..."))); - customiseButton->addButtonListener (this); - customiseButton->changeWidthToFitText (22); - customiseButton->setTopLeftPosition (orientationButton->getRight() + 20, orientationButton->getY()); - } - - ~ToolbarDemoComp() - { - deleteAllChildren(); - } - - void resized() - { - if (toolbar->isVertical()) - toolbar->setBounds (0, 0, (int) depthSlider->getValue(), getHeight()); - else - toolbar->setBounds (0, 0, getWidth(), (int) depthSlider->getValue()); - } - - void sliderValueChanged (Slider* slider) - { - resized(); - } - - void buttonClicked (Button* button) - { - if (button == orientationButton) - { - toolbar->setVertical (! toolbar->isVertical()); - resized(); - } - else if (button == customiseButton) - { - toolbar->showCustomisationDialog (factory); - } - } - -private: - Toolbar* toolbar; - Slider* depthSlider; - TextButton* orientationButton; - TextButton* customiseButton; - - //============================================================================== - class DemoToolbarItemFactory : public ToolbarItemFactory - { - public: - DemoToolbarItemFactory() {} - ~DemoToolbarItemFactory() {} - - //============================================================================== - // Each type of item a toolbar can contain must be given a unique ID. These - // are the ones we'll use in this demo. - enum DemoToolbarItemIds - { - doc_new = 1, - doc_open = 2, - doc_save = 3, - doc_saveAs = 4, - edit_copy = 5, - edit_cut = 6, - edit_paste = 7, - juceLogoButton = 8, - customComboBox = 9 - }; - - void getAllToolbarItemIds (Array & ids) - { - // This returns the complete list of all item IDs that are allowed to - // go in our toolbar. Any items you might want to add must be listed here. The - // order in which they are listed will be used by the toolbar customisation panel. - - ids.add (doc_new); - ids.add (doc_open); - ids.add (doc_save); - ids.add (doc_saveAs); - ids.add (edit_copy); - ids.add (edit_cut); - ids.add (edit_paste); - ids.add (juceLogoButton); - ids.add (customComboBox); - - // If you're going to use separators, then they must also be added explicitly - // to the list. - ids.add (separatorBarId); - ids.add (spacerId); - ids.add (flexibleSpacerId); - } - - void getDefaultItemSet (Array & ids) - { - // This returns an ordered list of the set of items that make up a - // toolbar's default set. Not all items need to be on this list, and - // items can appear multiple times (e.g. the separators used here). - ids.add (doc_new); - ids.add (doc_open); - ids.add (doc_save); - ids.add (doc_saveAs); - ids.add (spacerId); - ids.add (separatorBarId); - ids.add (edit_copy); - ids.add (edit_cut); - ids.add (edit_paste); - ids.add (separatorBarId); - ids.add (flexibleSpacerId); - ids.add (customComboBox); - ids.add (flexibleSpacerId); - ids.add (separatorBarId); - ids.add (juceLogoButton); - } - - ToolbarItemComponent* createItem (const int itemId) - { - switch (itemId) - { - case doc_new: - return createButtonFromZipFileSVG (itemId, T("new"), T("document-new.svg")); - - case doc_open: - return createButtonFromZipFileSVG (itemId, T("open"), T("document-open.svg")); - - case doc_save: - return createButtonFromZipFileSVG (itemId, T("save"), T("document-save.svg")); - - case doc_saveAs: - return createButtonFromZipFileSVG (itemId, T("save as"), T("document-save-as.svg")); - - case edit_copy: - return createButtonFromZipFileSVG (itemId, T("copy"), T("edit-copy.svg")); - - case edit_cut: - return createButtonFromZipFileSVG (itemId, T("cut"), T("edit-cut.svg")); - - case edit_paste: - return createButtonFromZipFileSVG (itemId, T("paste"), T("edit-paste.svg")); - - case juceLogoButton: - return new ToolbarButton (itemId, T("juce!"), Drawable::createFromImageData (BinaryData::juce_png, BinaryData::juce_pngSize), 0); - - case customComboBox: - return new CustomToolbarComboBox (itemId); - - default: - break; - } - - return 0; - } - - private: - StringArray iconNames; - OwnedArray iconsFromZipFile; - - // This is a little utility to create a button with one of the SVG images in - // our embedded ZIP file "icons.zip" - ToolbarButton* createButtonFromZipFileSVG (const int itemId, const String& text, const String& filename) - { - if (iconsFromZipFile.size() == 0) - { - // If we've not already done so, load all the images from the zip file.. - MemoryInputStream iconsFileStream (BinaryData::icons_zip, BinaryData::icons_zipSize, false); - ZipFile icons (&iconsFileStream, false); - - for (int i = 0; i < icons.getNumEntries(); ++i) - { - InputStream* svgFileStream = icons.createStreamForEntry (i); - - if (svgFileStream != 0) - { - iconNames.add (icons.getEntry(i)->filename); - iconsFromZipFile.add (Drawable::createFromImageDataStream (*svgFileStream)); - - delete svgFileStream; - } - } - } - - Drawable* image = iconsFromZipFile [iconNames.indexOf (filename)]->createCopy(); - return new ToolbarButton (itemId, text, image, 0); - - return 0; - } - - // Demonstrates how to put a custom component into a toolbar - this one contains - // a ComboBox. - class CustomToolbarComboBox : public ToolbarItemComponent - { - public: - CustomToolbarComboBox (const int toolbarItemId) - : ToolbarItemComponent (toolbarItemId, T("Custom Toolbar Item"), false) - { - addAndMakeVisible (comboBox = new ComboBox (T("demo toolbar combo box"))); - - for (int i = 1; i < 20; ++i) - comboBox->addItem (T("Toolbar ComboBox item ") + String (i), i); - - comboBox->setSelectedId (1); - comboBox->setEditableText (true); - } - - ~CustomToolbarComboBox() - { - delete comboBox; - } - - bool getToolbarItemSizes (int toolbarDepth, - bool isToolbarVertical, - int& preferredSize, int& minSize, int& maxSize) - { - if (isToolbarVertical) - return false; - - preferredSize = 250; - minSize = 80; - maxSize = 300; - return true; - } - - void paintButtonArea (Graphics&, int, int, bool, bool) - { - } - - void contentAreaChanged (const Rectangle& contentArea) - { - comboBox->setSize (contentArea.getWidth() - 2, - jmin (contentArea.getHeight() - 2, 22)); - - comboBox->setCentrePosition (contentArea.getCentreX(), contentArea.getCentreY()); - } - - private: - ComboBox* comboBox; - }; - }; - - DemoToolbarItemFactory factory; -}; - -//============================================================================== -class DemoTabbedComponent : public TabbedComponent, - public ButtonListener -{ -public: - DemoTabbedComponent (ApplicationCommandManager* commandManager) - : TabbedComponent (TabbedButtonBar::TabsAtTop) - { - addTab (T("sliders"), getRandomBrightColour(), createSlidersPage(), true); - addTab (T("toolbars"), getRandomBrightColour(), new ToolbarDemoComp (commandManager), true); - addTab (T("buttons"), getRandomBrightColour(), new ButtonsPage (this), true); - addTab (T("radio buttons"), getRandomBrightColour(), createRadioButtonPage(), true); - addTab (T("misc widgets"), getRandomBrightColour(), createMiscPage(), true); - } - - ~DemoTabbedComponent() - { - } - - void buttonClicked (Button* button) - { - BubbleMessageComponent* bmc = new BubbleMessageComponent(); - - if (Desktop::canUseSemiTransparentWindows()) - { - bmc->setAlwaysOnTop (true); - bmc->addToDesktop (0); - } - else - { - addChildComponent (bmc); - } - - bmc->showAt (button, T("This is a demo of the BubbleMessageComponent, which lets you pop up a message pointing at a component or somewhere on the screen.\n\nThe message bubbles will disappear after a timeout period, or when the mouse is clicked."), - 2000, true, true); - } - - static const Colour getRandomBrightColour() - { - return Colour (Random::getSystemRandom().nextFloat(), 0.1f, 0.97f, 1.0f); - } -}; - - -//============================================================================== -class DemoBackgroundThread : public ThreadWithProgressWindow -{ -public: - DemoBackgroundThread() - : ThreadWithProgressWindow (T("busy doing some important things..."), - true, - true) - { - setStatusMessage (T("Getting ready...")); - } - - ~DemoBackgroundThread() - { - } - - void run() - { - const int thingsToDo = 10; - - for (int i = 0; i < thingsToDo; ++i) - { - // must check this as often as possible, because this is - // how we know if the user's pressed 'cancel' - if (threadShouldExit()) - break; - - // this will update the progress bar on the dialog box - setProgress (i / (double) thingsToDo); - - wait (500); - - setStatusMessage (String (thingsToDo - i) + T(" things left to do...")); - } - } -}; - -//============================================================================== -/** A DialogWindow containing a ColourSelector component */ -class ColourSelectorDialogWindow : public DialogWindow -{ -public: - ColourSelectorDialogWindow() - : DialogWindow (T("Colour selector demo"), - Colours::lightgrey, - true) - { - setContentComponent (new ColourSelector()); - centreWithSize (400, 400); - setResizable (true, true); - } - - ~ColourSelectorDialogWindow() - { - } - - void closeButtonPressed() - { - // we expect this component to be run within a modal loop, so when the close - // button is clicked, we can make it invisible to cause the loop to exit and the - // calling code will delete this object. - setVisible (false); - } -}; - -#if JUCE_MAC - -//============================================================================== -/** This pops open a dialog box and waits for you to press keys on your Apple Remote, - which it describes in the box. -*/ -class AppleRemoteTestWindow : public AlertWindow, - public AppleRemoteDevice -{ -public: - AppleRemoteTestWindow() - : AlertWindow ("Apple Remote Control Test!", - "If you've got an Apple Remote, press some buttons now...", - AlertWindow::NoIcon) - { - addButton (T("done"), 0); - - // (To open the device in non-exclusive mode, pass 'false' in here).. - if (! start (true)) - setMessage ("Couldn't open the remote control device!"); - } - - ~AppleRemoteTestWindow() - { - stop(); - } - - void buttonPressed (const ButtonType buttonId, const bool isDown) - { - String desc; - - switch (buttonId) - { - case menuButton: - desc = "menu button (short)"; - break; - case playButton: - desc = "play button"; - break; - case plusButton: - desc = "plus button"; - break; - case minusButton: - desc = "minus button"; - break; - case rightButton: - desc = "right button (short)"; - break; - case leftButton: - desc = "left button (short)"; - break; - case rightButton_Long: - desc = "right button (long)"; - break; - case leftButton_Long: - desc = "left button (long)"; - break; - case menuButton_Long: - desc = "menu button (long)"; - break; - case playButtonSleepMode: - desc = "play (sleep mode)"; - break; - case switched: - desc = "remote switched"; - break; - } - - if (isDown) - desc << " -- [down]"; - else - desc << " -- [up]"; - - setMessage (desc); - } -}; - -#endif - -//============================================================================== -const int numGroups = 4; - -class WidgetsDemo : public Component, - public ButtonListener -{ - TextButton* menuButton; - ToggleButton* enableButton; - - DemoTabbedComponent* tabs; - -public: - //============================================================================== - WidgetsDemo (ApplicationCommandManager* commandManager) - { - setName (T("Widgets")); - - addAndMakeVisible (tabs = new DemoTabbedComponent (commandManager)); - - //============================================================================== - menuButton = new TextButton (T("click for a popup menu.."), - T("click for a demo of the different types of item you can put into a popup menu...")); - - addAndMakeVisible (menuButton); - menuButton->setBounds (10, 10, 200, 24); - menuButton->addButtonListener (this); - menuButton->setTriggeredOnMouseDown (true); // because this button pops up a menu, this lets us - // hold down the button and drag straight onto the menu - - //============================================================================== - enableButton = new ToggleButton (T("enable/disable components")); - addAndMakeVisible (enableButton); - enableButton->setBounds (230, 10, 180, 24); - enableButton->setTooltip (T("toggle button")); - enableButton->setToggleState (true, false); - enableButton->addButtonListener (this); - } - - ~WidgetsDemo() - { - deleteAllChildren(); - } - - void resized() - { - tabs->setBounds (10, 40, getWidth() - 20, getHeight() - 50); - } - - //============================================================================== - void buttonClicked (Button* button) - { - if (button == enableButton) - { - const bool enabled = enableButton->getToggleState(); - - menuButton->setEnabled (enabled); - tabs->setEnabled (enabled); - } - else if (button == menuButton) - { - PopupMenu m; - m.addItem (1, T("Normal item")); - m.addItem (2, T("Disabled item"), false); - m.addItem (3, T("Ticked item"), true, true); - m.addColouredItem (4, T("Coloured item"), Colours::green); - m.addSeparator(); - m.addCustomItem (5, new CustomMenuComponent()); - - m.addSeparator(); - - PopupMenu tabsMenu; - tabsMenu.addItem (1001, T("Show tabs at the top"), true, tabs->getOrientation() == TabbedButtonBar::TabsAtTop); - tabsMenu.addItem (1002, T("Show tabs at the bottom"), true, tabs->getOrientation() == TabbedButtonBar::TabsAtBottom); - tabsMenu.addItem (1003, T("Show tabs at the left"), true, tabs->getOrientation() == TabbedButtonBar::TabsAtLeft); - tabsMenu.addItem (1004, T("Show tabs at the right"), true, tabs->getOrientation() == TabbedButtonBar::TabsAtRight); - m.addSubMenu (T("Tab position"), tabsMenu); - - m.addSeparator(); - - PopupMenu dialogMenu; - dialogMenu.addItem (100, T("Show a plain alert-window...")); - dialogMenu.addItem (101, T("Show an alert-window with a 'warning' icon...")); - dialogMenu.addItem (102, T("Show an alert-window with an 'info' icon...")); - dialogMenu.addItem (103, T("Show an alert-window with a 'question' icon...")); - - dialogMenu.addSeparator(); - - dialogMenu.addItem (110, T("Show an ok/cancel alert-window...")); - - dialogMenu.addSeparator(); - - dialogMenu.addItem (111, T("Show an alert-window with some extra components...")); - - dialogMenu.addSeparator(); - - dialogMenu.addItem (112, T("Show a ThreadWithProgressWindow demo...")); - - m.addSubMenu (T("AlertWindow demonstrations"), dialogMenu); - - m.addSeparator(); - - m.addItem (120, T("Show a colour selector demo...")); - m.addSeparator(); - -#if JUCE_MAC - m.addItem (140, T("Run the Apple Remote Control test...")); - m.addSeparator(); -#endif - - PopupMenu nativeFileChoosers; - nativeFileChoosers.addItem (121, T("'Load' file browser...")); - nativeFileChoosers.addItem (124, T("'Load' file browser with an image file preview...")); - nativeFileChoosers.addItem (122, T("'Save' file browser...")); - nativeFileChoosers.addItem (123, T("'Choose directory' file browser...")); - - PopupMenu juceFileChoosers; - juceFileChoosers.addItem (131, T("'Load' file browser...")); - juceFileChoosers.addItem (134, T("'Load' file browser with an image file preview...")); - juceFileChoosers.addItem (132, T("'Save' file browser...")); - juceFileChoosers.addItem (133, T("'Choose directory' file browser...")); - - PopupMenu fileChoosers; - fileChoosers.addSubMenu (T("Operating system dialogs"), nativeFileChoosers); - fileChoosers.addSubMenu (T("Juce dialogs"), juceFileChoosers); - - m.addSubMenu (T("File chooser dialogs"), fileChoosers); - - int result = m.showAt (menuButton); - - if (result != 0) - { - // user chose something from the menu.. - - if (result >= 100 && result < 105) - { - AlertWindow::AlertIconType icon = AlertWindow::NoIcon; - - if (result == 101) - icon = AlertWindow::WarningIcon; - else if (result == 102) - icon = AlertWindow::InfoIcon; - else if (result == 103) - icon = AlertWindow::QuestionIcon; - - AlertWindow::showMessageBox (icon, - T("This is an AlertWindow"), - T("And this is the AlertWindow's message. Blah blah blah blah blah blah blah blah blah blah blah blah blah."), - T("ok")); - } - else if (result == 110) - { - bool userPickedOk - = AlertWindow::showOkCancelBox (AlertWindow::QuestionIcon, - T("This is an ok/cancel AlertWindow"), - T("And this is the AlertWindow's message. Blah blah blah blah blah blah blah blah blah blah blah blah blah.")); - } - else if (result == 111) - { - AlertWindow w (T("AlertWindow demo.."), - T("This AlertWindow has a couple of extra components added to show how to add drop-down lists and text entry boxes."), - AlertWindow::QuestionIcon); - - w.addTextEditor (T("text"), T("enter some text here"), T("text field:")); - - StringArray options; - options.add (T("option 1")); - options.add (T("option 2")); - options.add (T("option 3")); - options.add (T("option 4")); - w.addComboBox (T("option"), options, T("some options")); - - w.addButton (T("ok"), 1, KeyPress (KeyPress::returnKey, 0, 0)); - w.addButton (T("cancel"), 0, KeyPress (KeyPress::escapeKey, 0, 0)); - - if (w.runModalLoop() != 0) // is they picked 'ok' - { - // this is the item they chose in the drop-down list.. - const int optionIndexChosen = w.getComboBoxComponent (T("option"))->getSelectedItemIndex(); - - // this is the text they entered.. - String text = w.getTextEditorContents (T("text")); - - } - } - else if (result == 112) - { - DemoBackgroundThread demoThread; - - if (demoThread.runThread()) - { - // thread finished normally.. - AlertWindow::showMessageBox (AlertWindow::WarningIcon, - T("Progress window"), - T("Thread finished ok!")); - } - else - { - // user pressed the cancel button.. - AlertWindow::showMessageBox (AlertWindow::WarningIcon, - T("Progress window"), - T("You pressed cancel!")); - } - - } - else if (result == 120) - { - ColourSelectorDialogWindow colourDialog; - - // this will run an event loop until the dialog's closeButtonPressed() - // method causes the loop to exit. - colourDialog.runModalLoop(); - } - else if (result == 140) - { -#if JUCE_MAC - AppleRemoteTestWindow test; - test.runModalLoop(); -#endif - } - else if (result >= 121 && result < 139) - { - const bool useNativeVersion = result < 130; - if (result > 130) - result -= 10; - - if (result == 121) - { - FileChooser fc (T("Choose a file to open..."), - File::getCurrentWorkingDirectory(), - T("*"), - useNativeVersion); - - if (fc.browseForFileToOpen()) - { - File chosenFile = fc.getResult(); - - AlertWindow::showMessageBox (AlertWindow::InfoIcon, - T("File Chooser..."), - T("You picked: ") + chosenFile.getFullPathName()); - } - } - else if (result == 124) - { - ImagePreviewComponent imagePreview; - imagePreview.setSize (200, 200); - - FileChooser fc (T("Choose an image to open..."), - File::getCurrentWorkingDirectory(), - T("*.jpg;*.jpeg;*.png;*.gif"), - useNativeVersion); - - if (fc.browseForFileToOpen (&imagePreview)) - { - File chosenFile = fc.getResult(); - - AlertWindow::showMessageBox (AlertWindow::InfoIcon, - T("File Chooser..."), - T("You picked: ") + chosenFile.getFullPathName()); - } - } - else if (result == 122) - { - FileChooser fc (T("Choose a file to save..."), - File::getCurrentWorkingDirectory(), - T("*"), - useNativeVersion); - - if (fc.browseForFileToSave (true)) - { - File chosenFile = fc.getResult(); - - AlertWindow::showMessageBox (AlertWindow::InfoIcon, - T("File Chooser..."), - T("You picked: ") + chosenFile.getFullPathName()); - } - } - else if (result == 123) - { - FileChooser fc (T("Choose a directory..."), - File::getCurrentWorkingDirectory(), - T("*"), - useNativeVersion); - - if (fc.browseForDirectory()) - { - File chosenDirectory = fc.getResult(); - - AlertWindow::showMessageBox (AlertWindow::InfoIcon, - T("File Chooser..."), - T("You picked: ") + chosenDirectory.getFullPathName()); - } - } - } - else if (result == 1001) - { - tabs->setOrientation (TabbedButtonBar::TabsAtTop); - } - else if (result == 1002) - { - tabs->setOrientation (TabbedButtonBar::TabsAtBottom); - } - else if (result == 1003) - { - tabs->setOrientation (TabbedButtonBar::TabsAtLeft); - } - else if (result == 1004) - { - tabs->setOrientation (TabbedButtonBar::TabsAtRight); - } - } - } - } -}; - - -//============================================================================== -Component* createWidgetsDemo (ApplicationCommandManager* commandManager) -{ - return new WidgetsDemo (commandManager); -} +/* + ============================================================================== + + 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 "../jucedemo_headers.h" + + +//============================================================================== +class BouncingBallComponent : public Component, + public Timer +{ + Colour colour; + float x, y, dx, dy; + +public: + BouncingBallComponent() + { + x = Random::getSystemRandom().nextFloat() * 100.0f; + y = Random::getSystemRandom().nextFloat() * 100.0f; + + dx = Random::getSystemRandom().nextFloat() * 8.0f - 4.0f; + dy = Random::getSystemRandom().nextFloat() * 8.0f - 4.0f; + + colour = Colour (Random::getSystemRandom().nextInt()) + .withAlpha (0.5f) + .withBrightness (0.7f); + + int size = 10 + Random::getSystemRandom().nextInt (30); + setSize (size, size); + + startTimer (60); + } + + ~BouncingBallComponent() + { + } + + void paint (Graphics& g) + { + g.setColour (colour); + g.fillEllipse (x - getX(), y - getY(), getWidth() - 2.0f, getHeight() - 2.0f); + } + + void timerCallback() + { + x += dx; + y += dy; + + if (x < 0) + dx = fabsf (dx); + + if (x > getParentWidth()) + dx = -fabsf (dx); + + if (y < 0) + dy = fabsf (dy); + + if (y > getParentHeight()) + dy = -fabsf (dy); + + setTopLeftPosition ((int) x, (int) y); + } + + bool hitTest (int x, int y) + { + return false; + } +}; + +//============================================================================== +class DragOntoDesktopDemoComp : public Component +{ + Component* parent; + ComponentDragger dragger; + +public: + DragOntoDesktopDemoComp (Component* p) + : parent (p) + { + // show off semi-transparency if it's supported by the current OS. + setOpaque (! Desktop::canUseSemiTransparentWindows()); + + for (int i = 3; --i >= 0;) + addAndMakeVisible (new BouncingBallComponent()); + } + + ~DragOntoDesktopDemoComp() + { + deleteAllChildren(); + } + + void mouseDown (const MouseEvent& e) + { + dragger.startDraggingComponent (this, 0); + } + + void mouseDrag (const MouseEvent& e) + { + if (! parent->isValidComponent()) + { + delete this; + } + else + { + MouseEvent e2 (e.getEventRelativeTo (parent)); + + // if the mouse is inside the parent component, we'll make that the + // parent - otherwise, we'll put this comp on the desktop. + if (e2.x >= 0 && e2.y >= 0 && e2.x < parent->getWidth() && e2.y < parent->getHeight()) + { + // re-add this component to a parent component, which will + // remove it from the desktop.. + parent->addChildComponent (this); + } + else + { + // add the component to the desktop, which will remove it + // from its current parent component.. + addToDesktop (ComponentPeer::windowIsTemporary); + } + + dragger.dragComponent (this, e); + } + } + + void paint (Graphics& g) + { + if (isOpaque()) + g.fillAll (Colours::white); + else + g.fillAll (Colours::blue.withAlpha (0.2f)); + + String desc (T("drag this box onto the desktop to show how the same component can move from being lightweight to being a separate window")); + + g.setFont (15.0f); + g.setColour (Colours::black); + g.drawFittedText (desc, 4, 0, getWidth() - 8, getHeight(), Justification::horizontallyJustified, 5); + + g.drawRect (0, 0, getWidth(), getHeight()); + } +}; + +//============================================================================== +class CustomMenuComponent : public PopupMenuCustomComponent, + public Timer +{ + int blobX, blobY; + +public: + CustomMenuComponent() + : blobX (0), + blobY (0) + { + // set off a timer to move a blob around on this component every + // 300 milliseconds - see the timerCallback() method. + startTimer (300); + } + + ~CustomMenuComponent() + { + } + + void getIdealSize (int& idealWidth, + int& idealHeight) + { + // tells the menu how big we'd like to be.. + idealWidth = 200; + idealHeight = 60; + } + + void paint (Graphics& g) + { + g.fillAll (Colours::yellow.withAlpha (0.3f)); + + g.setColour (Colours::pink); + g.fillEllipse ((float) blobX, (float) blobY, 30.0f, 40.0f); + + g.setFont (14.0f, Font::italic); + g.setColour (Colours::black); + + g.drawFittedText (T("this is a customised menu item (also demonstrating the Timer class)..."), + 4, 0, getWidth() - 8, getHeight(), + Justification::centred, 3); + } + + void timerCallback() + { + blobX = Random::getSystemRandom().nextInt (getWidth()); + blobY = Random::getSystemRandom().nextInt (getHeight()); + repaint(); + } +}; + +//============================================================================== +/** To demonstrate how sliders can have custom snapping applied to their values, + this simple class snaps the value to 50 if it comes near. +*/ +class SnappingSlider : public Slider +{ +public: + SnappingSlider (const String& name) + : Slider (name) + { + } + + double snapValue (double attemptedValue, const bool userIsDragging) + { + if (! userIsDragging) + return attemptedValue; // if they're entering the value in the text-box, don't mess with it. + + if (attemptedValue > 40 && attemptedValue < 60) + return 50.0; + else + return attemptedValue; + } +}; + +/** A TextButton that pops up a colour chooser to change its colours. */ +class ColourChangeButton : public TextButton, + public ChangeListener +{ +public: + ColourChangeButton() + : TextButton (T("click to change colour...")) + { + setSize (10, 24); + changeWidthToFitText(); + } + + ~ColourChangeButton() + { + } + + void clicked() + { + // create two colour selector components for our background and + // text colour.. + ColourSelector colourSelector1; + colourSelector1.setName (T("background")); + colourSelector1.setCurrentColour (findColour (TextButton::buttonColourId)); + colourSelector1.addChangeListener (this); + + ColourSelector colourSelector2; + colourSelector2.setName (T("text")); + colourSelector2.setCurrentColour (findColour (TextButton::textColourId)); + colourSelector2.addChangeListener (this); + + // and add the selectors as custom menu items to a PopupMenu, putting + // them in two different sub-menus.. + PopupMenu m, sub1, sub2; + + sub1.addCustomItem (1234, &colourSelector1, 300, 300, false); + m.addSubMenu (T("background colour"), sub1); + + sub2.addCustomItem (1234, &colourSelector2, 300, 300, false); + m.addSubMenu (T("text colour"), sub2); + + // and show the menu (modally).. + m.showAt (this); + } + + void changeListenerCallback (void* source) + { + ColourSelector* cs = (ColourSelector*) source; + + if (cs->getName() == T("text")) + setColour (TextButton::textColourId, cs->getCurrentColour()); + else + setColour (TextButton::buttonColourId, cs->getCurrentColour()); + } +}; + +//============================================================================== +// just a component that deletes all its children, to use for the tabbed pages to avoid +// memory leaks when they're deleted +class DemoPageComp : public Component +{ +public: + DemoPageComp() + { + } + + ~DemoPageComp() + { + deleteAllChildren(); + } +}; + +//============================================================================== +static Component* createSlidersPage() +{ + DemoPageComp* page = new DemoPageComp(); + + const int numSliders = 11; + Slider* sliders [numSliders]; + + int i; + for (i = 0; i < numSliders; ++i) + { + if (i == 2) + page->addAndMakeVisible (sliders[i] = new SnappingSlider (T("slider"))); + else + page->addAndMakeVisible (sliders[i] = new Slider (T("slider"))); + + sliders[i]->setRange (0.0, 100.0, 0.1); + sliders[i]->setPopupMenuEnabled (true); + sliders[i]->setValue (Random::getSystemRandom().nextDouble() * 100.0, false, false); + } + + sliders[0]->setSliderStyle (Slider::LinearVertical); + sliders[0]->setTextBoxStyle (Slider::TextBoxBelow, false, 100, 20); + sliders[0]->setBounds (10, 25, 70, 200); + sliders[0]->setDoubleClickReturnValue (true, 50.0); // double-clicking this slider will set it to 50.0 + sliders[0]->setTextValueSuffix (T(" units")); + + sliders[1]->setSliderStyle (Slider::LinearVertical); + sliders[1]->setVelocityBasedMode (true); + sliders[1]->setSkewFactor (0.5); + sliders[1]->setTextBoxStyle (Slider::TextBoxAbove, true, 100, 20); + sliders[1]->setBounds (85, 25, 70, 200); + sliders[1]->setTextValueSuffix (T(" rels")); + + sliders[2]->setSliderStyle (Slider::LinearHorizontal); + sliders[2]->setTextBoxStyle (Slider::TextBoxLeft, false, 80, 20); + sliders[2]->setBounds (180, 35, 150, 20); + + sliders[3]->setSliderStyle (Slider::LinearHorizontal); + sliders[3]->setTextBoxStyle (Slider::NoTextBox, false, 0, 0); + sliders[3]->setBounds (180, 65, 150, 20); + sliders[3]->setPopupDisplayEnabled (true, page); + sliders[3]->setTextValueSuffix (T(" nuns required to change a lightbulb")); + + sliders[4]->setSliderStyle (Slider::IncDecButtons); + sliders[4]->setTextBoxStyle (Slider::TextBoxLeft, false, 50, 20); + sliders[4]->setBounds (180, 105, 100, 20); + sliders[4]->setIncDecButtonsMode (Slider::incDecButtonsDraggable_Vertical); + + sliders[5]->setSliderStyle (Slider::Rotary); + sliders[5]->setRotaryParameters (float_Pi * 1.2f, float_Pi * 2.8f, false); + sliders[5]->setTextBoxStyle (Slider::TextBoxRight, false, 70, 20); + sliders[5]->setBounds (190, 145, 120, 40); + sliders[5]->setTextValueSuffix (T(" mm")); + + sliders[6]->setSliderStyle (Slider::LinearBar); + sliders[6]->setBounds (180, 195, 100, 30); + sliders[6]->setTextValueSuffix (T(" gallons")); + + sliders[7]->setSliderStyle (Slider::TwoValueHorizontal); + sliders[7]->setBounds (360, 20, 160, 40); + + sliders[8]->setSliderStyle (Slider::TwoValueVertical); + sliders[8]->setBounds (360, 110, 40, 160); + + sliders[9]->setSliderStyle (Slider::ThreeValueHorizontal); + sliders[9]->setBounds (360, 70, 160, 40); + + sliders[10]->setSliderStyle (Slider::ThreeValueVertical); + sliders[10]->setBounds (440, 110, 40, 160); + + for (i = 7; i <= 10; ++i) + { + sliders[i]->setTextBoxStyle (Slider::NoTextBox, false, 0, 0); + sliders[i]->setMinValue (Random::getSystemRandom().nextDouble() * 100.0, false, false); + sliders[i]->setMaxValue (Random::getSystemRandom().nextDouble() * 100.0, false, false); + sliders[i]->setPopupDisplayEnabled (true, page); + } + + Label* label = new Label (T("hint"), T("Try right-clicking on a slider for an options menu. \n\nAlso, holding down CTRL while dragging will turn on a slider's velocity-sensitive mode")); + label->setBounds (20, 245, 350, 150); + page->addAndMakeVisible (label); + + return page; +} + +//============================================================================== +static Component* createRadioButtonPage() +{ + DemoPageComp* page = new DemoPageComp(); + + GroupComponent* group = new GroupComponent (T("group"), T("radio buttons")); + group->setBounds (20, 20, 220, 140); + page->addAndMakeVisible (group); + + int i; + for (i = 0; i < 4; ++i) + { + ToggleButton* tb = new ToggleButton (T("radio button #") + String (i + 1)); + page->addAndMakeVisible (tb); + tb->setRadioGroupId (1234); + tb->setBounds (45, 46 + i * 22, 180, 22); + tb->setTooltip (T("a set of mutually-exclusive radio buttons")); + + if (i == 0) + tb->setToggleState (true, false); + } + + for (i = 0; i < 4; ++i) + { + DrawablePath normal, over; + + Path p; + p.addStar (0.0f, 0.0f, i + 5, 20.0f, 50.0f, -0.2f); + normal.setPath (p); + normal.setSolidFill (Colours::lightblue); + normal.setOutline (4.0f, Colours::black); + + over.setPath (p); + over.setSolidFill (Colours::blue); + over.setOutline (4.0f, Colours::black); + + DrawableButton* db = new DrawableButton (String (i + 5) + T(" points"), DrawableButton::ImageAboveTextLabel); + db->setImages (&normal, &over, 0); + + page->addAndMakeVisible (db); + db->setClickingTogglesState (true); + db->setRadioGroupId (23456); + + const int buttonSize = 50; + db->setBounds (25 + i * buttonSize, 180, buttonSize, buttonSize); + + if (i == 0) + db->setToggleState (true, false); + } + + for (i = 0; i < 4; ++i) + { + TextButton* tb = new TextButton (T("button ") + String (i + 1)); + + page->addAndMakeVisible (tb); + tb->setClickingTogglesState (true); + tb->setRadioGroupId (34567); + tb->setColour (TextButton::buttonColourId, Colours::white); + tb->setColour (TextButton::buttonOnColourId, Colours::blueviolet.brighter()); + + tb->setBounds (20 + i * 55, 260, 55, 24); + tb->setConnectedEdges (((i != 0) ? Button::ConnectedOnLeft : 0) + | ((i != 3) ? Button::ConnectedOnRight : 0)); + + if (i == 0) + tb->setToggleState (true, false); + } + + return page; +} + +//============================================================================== +class ButtonsPage : public Component, + public ButtonListener +{ +public: + ButtonsPage (ButtonListener* buttonListener) + { + //============================================================================== + // create some drawables to use for our drawable buttons... + DrawablePath normal, over; + + Path p; + p.addStar (0.0f, 0.0f, 5, 20.0f, 50.0f, 0.2f); + normal.setPath (p); + normal.setSolidFill (Colours::red); + + p.clear(); + p.addStar (0.0f, 0.0f, 7, 30.0f, 50.0f, 0.0f); + over.setPath (p); + over.setSolidFill (Colours::pink); + over.setOutline (5.0f, Colours::black); + + DrawableImage down; + down.setImage (ImageCache::getFromMemory (BinaryData::juce_png, BinaryData::juce_pngSize), true); + down.setOverlayColour (Colours::black.withAlpha (0.3f)); + + //============================================================================== + // create an image-above-text button from these drawables.. + DrawableButton* db = new DrawableButton (T("Button 1"), DrawableButton::ImageAboveTextLabel); + db->setImages (&normal, &over, &down); + + addAndMakeVisible (db); + db->setBounds (10, 30, 80, 80); + db->setTooltip (T("this is a DrawableButton with a label")); + + //============================================================================== + // create an image-only button from these drawables.. + db = new DrawableButton (T("Button 2"), DrawableButton::ImageFitted); + db->setImages (&normal, &over, &down); + db->setClickingTogglesState (true); + + addAndMakeVisible (db); + db->setBounds (90, 30, 80, 80); + db->setTooltip (T("this is an image-only DrawableButton")); + db->addButtonListener (buttonListener); + + //============================================================================== + // create an image-on-button-shape button from the same drawables.. + db = new DrawableButton (T("Button 3"), DrawableButton::ImageOnButtonBackground); + db->setImages (&normal, 0, 0); + + addAndMakeVisible (db); + db->setBounds (200, 30, 110, 25); + db->setTooltip (T("this is a DrawableButton on a standard button background")); + + //============================================================================== + db = new DrawableButton (T("Button 4"), DrawableButton::ImageOnButtonBackground); + db->setImages (&normal, &over, &down); + db->setClickingTogglesState (true); + db->setBackgroundColours (Colours::white, Colours::yellow); + + addAndMakeVisible (db); + db->setBounds (200, 70, 50, 50); + db->setTooltip (T("this is a DrawableButton on a standard button background")); + db->addButtonListener (buttonListener); + + //============================================================================== + HyperlinkButton* hyperlink + = new HyperlinkButton (T("this is a HyperlinkButton"), + URL (T("http://www.rawmaterialsoftware.com/juce"))); + + hyperlink->setBounds (10, 130, 200, 24); + addAndMakeVisible (hyperlink); + + //============================================================================== + ImageButton* imageButton = new ImageButton (T("imagebutton")); + addAndMakeVisible (imageButton); + + Image* juceImage = ImageCache::getFromMemory (BinaryData::juce_png, BinaryData::juce_pngSize); + ImageCache::incReferenceCount (juceImage); + ImageCache::incReferenceCount (juceImage); + + imageButton->setImages (true, true, true, + juceImage, 0.7f, Colours::transparentBlack, + juceImage, 1.0f, Colours::transparentBlack, + juceImage, 1.0f, Colours::pink.withAlpha (0.8f), + 0.5f); + + imageButton->setTopLeftPosition (10, 160); + imageButton->setTooltip (T("image button - showing alpha-channel hit-testing and colour overlay when clicked")); + + //============================================================================== + ColourChangeButton* colourChangeButton = new ColourChangeButton(); + addAndMakeVisible (colourChangeButton); + colourChangeButton->setTopLeftPosition (350, 30); + + //============================================================================== + animateButton = new TextButton (T("click to animate...")); + addAndMakeVisible (animateButton); + animateButton->changeWidthToFitText (24); + animateButton->setTopLeftPosition (350, 70); + animateButton->addButtonListener (this); + } + + ~ButtonsPage() + { + deleteAllChildren(); + } + + void buttonClicked (Button*) + { + for (int i = getNumChildComponents(); --i >= 0;) + { + if (getChildComponent (i) != animateButton) + { + animator.animateComponent (getChildComponent (i), + Rectangle (Random::getSystemRandom().nextInt (getWidth() / 2), + Random::getSystemRandom().nextInt (getHeight() / 2), + 60 + Random::getSystemRandom().nextInt (getWidth() / 3), + 16 + Random::getSystemRandom().nextInt (getHeight() / 6)), + 500 + Random::getSystemRandom().nextInt (2000), + Random::getSystemRandom().nextDouble(), + Random::getSystemRandom().nextDouble()); + } + } + } + +private: + TextButton* animateButton; + ComponentAnimator animator; +}; + + +//============================================================================== +static Component* createMiscPage() +{ + DemoPageComp* page = new DemoPageComp(); + + TextEditor* textEditor = new TextEditor(); + page->addAndMakeVisible (textEditor); + textEditor->setBounds (10, 25, 200, 24); + textEditor->setText (T("single-line text box")); + + textEditor = new TextEditor (T("password"), (tchar) 0x2022); + page->addAndMakeVisible (textEditor); + textEditor->setBounds (10, 55, 200, 24); + textEditor->setText (T("password")); + + //============================================================================== + ComboBox* comboBox = new ComboBox (T("combo")); + page->addAndMakeVisible (comboBox); + comboBox->setBounds (300, 25, 200, 24); + comboBox->setEditableText (true); + comboBox->setJustificationType (Justification::centred); + + int i; + for (i = 1; i < 100; ++i) + comboBox->addItem (T("combo box item ") + String (i), i); + + comboBox->setSelectedId (1); + + DragOntoDesktopDemoComp* d = new DragOntoDesktopDemoComp (page); + page->addAndMakeVisible (d); + d->setBounds (20, 100, 200, 80); + + return page; +} + +//============================================================================== +class ToolbarDemoComp : public Component, + public SliderListener, + public ButtonListener +{ +public: + ToolbarDemoComp (ApplicationCommandManager* commandManager) + { + // Create and add the toolbar... + addAndMakeVisible (toolbar = new Toolbar()); + + // And use our item factory to add a set of default icons to it... + toolbar->addDefaultItems (factory); + + // Now we'll just create the other sliders and buttons on the demo page, which adjust + // the toolbar's properties... + Label* info = new Label (String::empty, + "As well as showing off toolbars, this demo illustrates how to store " + "a set of SVG files in a Zip file, embed that in your application, and read " + "them back in at runtime.\n\nThe icon images here are taken from the open-source " + "Tango icon project."); + + addAndMakeVisible (info); + info->setJustificationType (Justification::topLeft); + info->setBounds (80, 80, 450, 100); + info->setInterceptsMouseClicks (false, false); + + addAndMakeVisible (depthSlider = new Slider (T("toolbar depth:"))); + depthSlider->setRange (10.0, 200.0, 1.0); + depthSlider->setValue (50, false); + depthSlider->setSliderStyle (Slider::LinearHorizontal); + depthSlider->setTextBoxStyle (Slider::TextBoxLeft, false, 80, 20); + depthSlider->addListener (this); + depthSlider->setBounds (80, 210, 300, 22); + (new Label (depthSlider->getName(), depthSlider->getName()))->attachToComponent (depthSlider, false); + + addAndMakeVisible (orientationButton = new TextButton (T("vertical/horizontal"))); + orientationButton->addButtonListener (this); + orientationButton->changeWidthToFitText (22); + orientationButton->setTopLeftPosition (depthSlider->getX(), depthSlider->getBottom() + 20); + + addAndMakeVisible (customiseButton = new TextButton (T("customise..."))); + customiseButton->addButtonListener (this); + customiseButton->changeWidthToFitText (22); + customiseButton->setTopLeftPosition (orientationButton->getRight() + 20, orientationButton->getY()); + } + + ~ToolbarDemoComp() + { + deleteAllChildren(); + } + + void resized() + { + if (toolbar->isVertical()) + toolbar->setBounds (0, 0, (int) depthSlider->getValue(), getHeight()); + else + toolbar->setBounds (0, 0, getWidth(), (int) depthSlider->getValue()); + } + + void sliderValueChanged (Slider* slider) + { + resized(); + } + + void buttonClicked (Button* button) + { + if (button == orientationButton) + { + toolbar->setVertical (! toolbar->isVertical()); + resized(); + } + else if (button == customiseButton) + { + toolbar->showCustomisationDialog (factory); + } + } + +private: + Toolbar* toolbar; + Slider* depthSlider; + TextButton* orientationButton; + TextButton* customiseButton; + + //============================================================================== + class DemoToolbarItemFactory : public ToolbarItemFactory + { + public: + DemoToolbarItemFactory() {} + ~DemoToolbarItemFactory() {} + + //============================================================================== + // Each type of item a toolbar can contain must be given a unique ID. These + // are the ones we'll use in this demo. + enum DemoToolbarItemIds + { + doc_new = 1, + doc_open = 2, + doc_save = 3, + doc_saveAs = 4, + edit_copy = 5, + edit_cut = 6, + edit_paste = 7, + juceLogoButton = 8, + customComboBox = 9 + }; + + void getAllToolbarItemIds (Array & ids) + { + // This returns the complete list of all item IDs that are allowed to + // go in our toolbar. Any items you might want to add must be listed here. The + // order in which they are listed will be used by the toolbar customisation panel. + + ids.add (doc_new); + ids.add (doc_open); + ids.add (doc_save); + ids.add (doc_saveAs); + ids.add (edit_copy); + ids.add (edit_cut); + ids.add (edit_paste); + ids.add (juceLogoButton); + ids.add (customComboBox); + + // If you're going to use separators, then they must also be added explicitly + // to the list. + ids.add (separatorBarId); + ids.add (spacerId); + ids.add (flexibleSpacerId); + } + + void getDefaultItemSet (Array & ids) + { + // This returns an ordered list of the set of items that make up a + // toolbar's default set. Not all items need to be on this list, and + // items can appear multiple times (e.g. the separators used here). + ids.add (doc_new); + ids.add (doc_open); + ids.add (doc_save); + ids.add (doc_saveAs); + ids.add (spacerId); + ids.add (separatorBarId); + ids.add (edit_copy); + ids.add (edit_cut); + ids.add (edit_paste); + ids.add (separatorBarId); + ids.add (flexibleSpacerId); + ids.add (customComboBox); + ids.add (flexibleSpacerId); + ids.add (separatorBarId); + ids.add (juceLogoButton); + } + + ToolbarItemComponent* createItem (const int itemId) + { + switch (itemId) + { + case doc_new: + return createButtonFromZipFileSVG (itemId, T("new"), T("document-new.svg")); + + case doc_open: + return createButtonFromZipFileSVG (itemId, T("open"), T("document-open.svg")); + + case doc_save: + return createButtonFromZipFileSVG (itemId, T("save"), T("document-save.svg")); + + case doc_saveAs: + return createButtonFromZipFileSVG (itemId, T("save as"), T("document-save-as.svg")); + + case edit_copy: + return createButtonFromZipFileSVG (itemId, T("copy"), T("edit-copy.svg")); + + case edit_cut: + return createButtonFromZipFileSVG (itemId, T("cut"), T("edit-cut.svg")); + + case edit_paste: + return createButtonFromZipFileSVG (itemId, T("paste"), T("edit-paste.svg")); + + case juceLogoButton: + return new ToolbarButton (itemId, T("juce!"), Drawable::createFromImageData (BinaryData::juce_png, BinaryData::juce_pngSize), 0); + + case customComboBox: + return new CustomToolbarComboBox (itemId); + + default: + break; + } + + return 0; + } + + private: + StringArray iconNames; + OwnedArray iconsFromZipFile; + + // This is a little utility to create a button with one of the SVG images in + // our embedded ZIP file "icons.zip" + ToolbarButton* createButtonFromZipFileSVG (const int itemId, const String& text, const String& filename) + { + if (iconsFromZipFile.size() == 0) + { + // If we've not already done so, load all the images from the zip file.. + MemoryInputStream iconsFileStream (BinaryData::icons_zip, BinaryData::icons_zipSize, false); + ZipFile icons (&iconsFileStream, false); + + for (int i = 0; i < icons.getNumEntries(); ++i) + { + InputStream* svgFileStream = icons.createStreamForEntry (i); + + if (svgFileStream != 0) + { + iconNames.add (icons.getEntry(i)->filename); + iconsFromZipFile.add (Drawable::createFromImageDataStream (*svgFileStream)); + + delete svgFileStream; + } + } + } + + Drawable* image = iconsFromZipFile [iconNames.indexOf (filename)]->createCopy(); + return new ToolbarButton (itemId, text, image, 0); + + return 0; + } + + // Demonstrates how to put a custom component into a toolbar - this one contains + // a ComboBox. + class CustomToolbarComboBox : public ToolbarItemComponent + { + public: + CustomToolbarComboBox (const int toolbarItemId) + : ToolbarItemComponent (toolbarItemId, T("Custom Toolbar Item"), false) + { + addAndMakeVisible (comboBox = new ComboBox (T("demo toolbar combo box"))); + + for (int i = 1; i < 20; ++i) + comboBox->addItem (T("Toolbar ComboBox item ") + String (i), i); + + comboBox->setSelectedId (1); + comboBox->setEditableText (true); + } + + ~CustomToolbarComboBox() + { + delete comboBox; + } + + bool getToolbarItemSizes (int toolbarDepth, + bool isToolbarVertical, + int& preferredSize, int& minSize, int& maxSize) + { + if (isToolbarVertical) + return false; + + preferredSize = 250; + minSize = 80; + maxSize = 300; + return true; + } + + void paintButtonArea (Graphics&, int, int, bool, bool) + { + } + + void contentAreaChanged (const Rectangle& contentArea) + { + comboBox->setSize (contentArea.getWidth() - 2, + jmin (contentArea.getHeight() - 2, 22)); + + comboBox->setCentrePosition (contentArea.getCentreX(), contentArea.getCentreY()); + } + + private: + ComboBox* comboBox; + }; + }; + + DemoToolbarItemFactory factory; +}; + +//============================================================================== +class DemoTabbedComponent : public TabbedComponent, + public ButtonListener +{ +public: + DemoTabbedComponent (ApplicationCommandManager* commandManager) + : TabbedComponent (TabbedButtonBar::TabsAtTop) + { + addTab (T("sliders"), getRandomBrightColour(), createSlidersPage(), true); + addTab (T("toolbars"), getRandomBrightColour(), new ToolbarDemoComp (commandManager), true); + addTab (T("buttons"), getRandomBrightColour(), new ButtonsPage (this), true); + addTab (T("radio buttons"), getRandomBrightColour(), createRadioButtonPage(), true); + addTab (T("misc widgets"), getRandomBrightColour(), createMiscPage(), true); + } + + ~DemoTabbedComponent() + { + } + + void buttonClicked (Button* button) + { + BubbleMessageComponent* bmc = new BubbleMessageComponent(); + + if (Desktop::canUseSemiTransparentWindows()) + { + bmc->setAlwaysOnTop (true); + bmc->addToDesktop (0); + } + else + { + addChildComponent (bmc); + } + + bmc->showAt (button, T("This is a demo of the BubbleMessageComponent, which lets you pop up a message pointing at a component or somewhere on the screen.\n\nThe message bubbles will disappear after a timeout period, or when the mouse is clicked."), + 2000, true, true); + } + + static const Colour getRandomBrightColour() + { + return Colour (Random::getSystemRandom().nextFloat(), 0.1f, 0.97f, 1.0f); + } +}; + + +//============================================================================== +class DemoBackgroundThread : public ThreadWithProgressWindow +{ +public: + DemoBackgroundThread() + : ThreadWithProgressWindow (T("busy doing some important things..."), + true, + true) + { + setStatusMessage (T("Getting ready...")); + } + + ~DemoBackgroundThread() + { + } + + void run() + { + const int thingsToDo = 10; + + for (int i = 0; i < thingsToDo; ++i) + { + // must check this as often as possible, because this is + // how we know if the user's pressed 'cancel' + if (threadShouldExit()) + break; + + // this will update the progress bar on the dialog box + setProgress (i / (double) thingsToDo); + + wait (500); + + setStatusMessage (String (thingsToDo - i) + T(" things left to do...")); + } + } +}; + +//============================================================================== +/** A DialogWindow containing a ColourSelector component */ +class ColourSelectorDialogWindow : public DialogWindow +{ +public: + ColourSelectorDialogWindow() + : DialogWindow (T("Colour selector demo"), + Colours::lightgrey, + true) + { + setContentComponent (new ColourSelector()); + centreWithSize (400, 400); + setResizable (true, true); + } + + ~ColourSelectorDialogWindow() + { + } + + void closeButtonPressed() + { + // we expect this component to be run within a modal loop, so when the close + // button is clicked, we can make it invisible to cause the loop to exit and the + // calling code will delete this object. + setVisible (false); + } +}; + +#if JUCE_MAC + +//============================================================================== +/** This pops open a dialog box and waits for you to press keys on your Apple Remote, + which it describes in the box. +*/ +class AppleRemoteTestWindow : public AlertWindow, + public AppleRemoteDevice +{ +public: + AppleRemoteTestWindow() + : AlertWindow ("Apple Remote Control Test!", + "If you've got an Apple Remote, press some buttons now...", + AlertWindow::NoIcon) + { + addButton (T("done"), 0); + + // (To open the device in non-exclusive mode, pass 'false' in here).. + if (! start (true)) + setMessage ("Couldn't open the remote control device!"); + } + + ~AppleRemoteTestWindow() + { + stop(); + } + + void buttonPressed (const ButtonType buttonId, const bool isDown) + { + String desc; + + switch (buttonId) + { + case menuButton: + desc = "menu button (short)"; + break; + case playButton: + desc = "play button"; + break; + case plusButton: + desc = "plus button"; + break; + case minusButton: + desc = "minus button"; + break; + case rightButton: + desc = "right button (short)"; + break; + case leftButton: + desc = "left button (short)"; + break; + case rightButton_Long: + desc = "right button (long)"; + break; + case leftButton_Long: + desc = "left button (long)"; + break; + case menuButton_Long: + desc = "menu button (long)"; + break; + case playButtonSleepMode: + desc = "play (sleep mode)"; + break; + case switched: + desc = "remote switched"; + break; + } + + if (isDown) + desc << " -- [down]"; + else + desc << " -- [up]"; + + setMessage (desc); + } +}; + +#endif + +//============================================================================== +const int numGroups = 4; + +class WidgetsDemo : public Component, + public ButtonListener +{ + TextButton* menuButton; + ToggleButton* enableButton; + + DemoTabbedComponent* tabs; + +public: + //============================================================================== + WidgetsDemo (ApplicationCommandManager* commandManager) + { + setName (T("Widgets")); + + addAndMakeVisible (tabs = new DemoTabbedComponent (commandManager)); + + //============================================================================== + menuButton = new TextButton (T("click for a popup menu.."), + T("click for a demo of the different types of item you can put into a popup menu...")); + + addAndMakeVisible (menuButton); + menuButton->setBounds (10, 10, 200, 24); + menuButton->addButtonListener (this); + menuButton->setTriggeredOnMouseDown (true); // because this button pops up a menu, this lets us + // hold down the button and drag straight onto the menu + + //============================================================================== + enableButton = new ToggleButton (T("enable/disable components")); + addAndMakeVisible (enableButton); + enableButton->setBounds (230, 10, 180, 24); + enableButton->setTooltip (T("toggle button")); + enableButton->setToggleState (true, false); + enableButton->addButtonListener (this); + } + + ~WidgetsDemo() + { + deleteAllChildren(); + } + + void resized() + { + tabs->setBounds (10, 40, getWidth() - 20, getHeight() - 50); + } + + //============================================================================== + void buttonClicked (Button* button) + { + if (button == enableButton) + { + const bool enabled = enableButton->getToggleState(); + + menuButton->setEnabled (enabled); + tabs->setEnabled (enabled); + } + else if (button == menuButton) + { + PopupMenu m; + m.addItem (1, T("Normal item")); + m.addItem (2, T("Disabled item"), false); + m.addItem (3, T("Ticked item"), true, true); + m.addColouredItem (4, T("Coloured item"), Colours::green); + m.addSeparator(); + m.addCustomItem (5, new CustomMenuComponent()); + + m.addSeparator(); + + PopupMenu tabsMenu; + tabsMenu.addItem (1001, T("Show tabs at the top"), true, tabs->getOrientation() == TabbedButtonBar::TabsAtTop); + tabsMenu.addItem (1002, T("Show tabs at the bottom"), true, tabs->getOrientation() == TabbedButtonBar::TabsAtBottom); + tabsMenu.addItem (1003, T("Show tabs at the left"), true, tabs->getOrientation() == TabbedButtonBar::TabsAtLeft); + tabsMenu.addItem (1004, T("Show tabs at the right"), true, tabs->getOrientation() == TabbedButtonBar::TabsAtRight); + m.addSubMenu (T("Tab position"), tabsMenu); + + m.addSeparator(); + + PopupMenu dialogMenu; + dialogMenu.addItem (100, T("Show a plain alert-window...")); + dialogMenu.addItem (101, T("Show an alert-window with a 'warning' icon...")); + dialogMenu.addItem (102, T("Show an alert-window with an 'info' icon...")); + dialogMenu.addItem (103, T("Show an alert-window with a 'question' icon...")); + + dialogMenu.addSeparator(); + + dialogMenu.addItem (110, T("Show an ok/cancel alert-window...")); + + dialogMenu.addSeparator(); + + dialogMenu.addItem (111, T("Show an alert-window with some extra components...")); + + dialogMenu.addSeparator(); + + dialogMenu.addItem (112, T("Show a ThreadWithProgressWindow demo...")); + + m.addSubMenu (T("AlertWindow demonstrations"), dialogMenu); + + m.addSeparator(); + + m.addItem (120, T("Show a colour selector demo...")); + m.addSeparator(); + +#if JUCE_MAC + m.addItem (140, T("Run the Apple Remote Control test...")); + m.addSeparator(); +#endif + + PopupMenu nativeFileChoosers; + nativeFileChoosers.addItem (121, T("'Load' file browser...")); + nativeFileChoosers.addItem (124, T("'Load' file browser with an image file preview...")); + nativeFileChoosers.addItem (122, T("'Save' file browser...")); + nativeFileChoosers.addItem (123, T("'Choose directory' file browser...")); + + PopupMenu juceFileChoosers; + juceFileChoosers.addItem (131, T("'Load' file browser...")); + juceFileChoosers.addItem (134, T("'Load' file browser with an image file preview...")); + juceFileChoosers.addItem (132, T("'Save' file browser...")); + juceFileChoosers.addItem (133, T("'Choose directory' file browser...")); + + PopupMenu fileChoosers; + fileChoosers.addSubMenu (T("Operating system dialogs"), nativeFileChoosers); + fileChoosers.addSubMenu (T("Juce dialogs"), juceFileChoosers); + + m.addSubMenu (T("File chooser dialogs"), fileChoosers); + + int result = m.showAt (menuButton); + + if (result != 0) + { + // user chose something from the menu.. + + if (result >= 100 && result < 105) + { + AlertWindow::AlertIconType icon = AlertWindow::NoIcon; + + if (result == 101) + icon = AlertWindow::WarningIcon; + else if (result == 102) + icon = AlertWindow::InfoIcon; + else if (result == 103) + icon = AlertWindow::QuestionIcon; + + AlertWindow::showMessageBox (icon, + T("This is an AlertWindow"), + T("And this is the AlertWindow's message. Blah blah blah blah blah blah blah blah blah blah blah blah blah."), + T("ok")); + } + else if (result == 110) + { + bool userPickedOk + = AlertWindow::showOkCancelBox (AlertWindow::QuestionIcon, + T("This is an ok/cancel AlertWindow"), + T("And this is the AlertWindow's message. Blah blah blah blah blah blah blah blah blah blah blah blah blah.")); + } + else if (result == 111) + { + AlertWindow w (T("AlertWindow demo.."), + T("This AlertWindow has a couple of extra components added to show how to add drop-down lists and text entry boxes."), + AlertWindow::QuestionIcon); + + w.addTextEditor (T("text"), T("enter some text here"), T("text field:")); + + StringArray options; + options.add (T("option 1")); + options.add (T("option 2")); + options.add (T("option 3")); + options.add (T("option 4")); + w.addComboBox (T("option"), options, T("some options")); + + w.addButton (T("ok"), 1, KeyPress (KeyPress::returnKey, 0, 0)); + w.addButton (T("cancel"), 0, KeyPress (KeyPress::escapeKey, 0, 0)); + + if (w.runModalLoop() != 0) // is they picked 'ok' + { + // this is the item they chose in the drop-down list.. + const int optionIndexChosen = w.getComboBoxComponent (T("option"))->getSelectedItemIndex(); + + // this is the text they entered.. + String text = w.getTextEditorContents (T("text")); + + } + } + else if (result == 112) + { + DemoBackgroundThread demoThread; + + if (demoThread.runThread()) + { + // thread finished normally.. + AlertWindow::showMessageBox (AlertWindow::WarningIcon, + T("Progress window"), + T("Thread finished ok!")); + } + else + { + // user pressed the cancel button.. + AlertWindow::showMessageBox (AlertWindow::WarningIcon, + T("Progress window"), + T("You pressed cancel!")); + } + + } + else if (result == 120) + { + ColourSelectorDialogWindow colourDialog; + + // this will run an event loop until the dialog's closeButtonPressed() + // method causes the loop to exit. + colourDialog.runModalLoop(); + } + else if (result == 140) + { +#if JUCE_MAC + AppleRemoteTestWindow test; + test.runModalLoop(); +#endif + } + else if (result >= 121 && result < 139) + { + const bool useNativeVersion = result < 130; + if (result > 130) + result -= 10; + + if (result == 121) + { + FileChooser fc (T("Choose a file to open..."), + File::getCurrentWorkingDirectory(), + T("*"), + useNativeVersion); + + if (fc.browseForFileToOpen()) + { + File chosenFile = fc.getResult(); + + AlertWindow::showMessageBox (AlertWindow::InfoIcon, + T("File Chooser..."), + T("You picked: ") + chosenFile.getFullPathName()); + } + } + else if (result == 124) + { + ImagePreviewComponent imagePreview; + imagePreview.setSize (200, 200); + + FileChooser fc (T("Choose an image to open..."), + File::getCurrentWorkingDirectory(), + T("*.jpg;*.jpeg;*.png;*.gif"), + useNativeVersion); + + if (fc.browseForFileToOpen (&imagePreview)) + { + File chosenFile = fc.getResult(); + + AlertWindow::showMessageBox (AlertWindow::InfoIcon, + T("File Chooser..."), + T("You picked: ") + chosenFile.getFullPathName()); + } + } + else if (result == 122) + { + FileChooser fc (T("Choose a file to save..."), + File::getCurrentWorkingDirectory(), + T("*"), + useNativeVersion); + + if (fc.browseForFileToSave (true)) + { + File chosenFile = fc.getResult(); + + AlertWindow::showMessageBox (AlertWindow::InfoIcon, + T("File Chooser..."), + T("You picked: ") + chosenFile.getFullPathName()); + } + } + else if (result == 123) + { + FileChooser fc (T("Choose a directory..."), + File::getCurrentWorkingDirectory(), + T("*"), + useNativeVersion); + + if (fc.browseForDirectory()) + { + File chosenDirectory = fc.getResult(); + + AlertWindow::showMessageBox (AlertWindow::InfoIcon, + T("File Chooser..."), + T("You picked: ") + chosenDirectory.getFullPathName()); + } + } + } + else if (result == 1001) + { + tabs->setOrientation (TabbedButtonBar::TabsAtTop); + } + else if (result == 1002) + { + tabs->setOrientation (TabbedButtonBar::TabsAtBottom); + } + else if (result == 1003) + { + tabs->setOrientation (TabbedButtonBar::TabsAtLeft); + } + else if (result == 1004) + { + tabs->setOrientation (TabbedButtonBar::TabsAtRight); + } + } + } + } +}; + + +//============================================================================== +Component* createWidgetsDemo (ApplicationCommandManager* commandManager) +{ + return new WidgetsDemo (commandManager); +} diff --git a/src/juce_appframework/audio/devices/juce_MidiInput.h b/src/juce_appframework/audio/devices/juce_MidiInput.h index ada3e44ede..223748bf18 100644 --- a/src/juce_appframework/audio/devices/juce_MidiInput.h +++ b/src/juce_appframework/audio/devices/juce_MidiInput.h @@ -55,6 +55,11 @@ public: /** Receives an incoming message. + A MidiInput object will call this method when a midi event arrives. It'll be + called on a high-priority system thread, so avoid doing anything time-consuming + in here, and avoid making any UI calls. You might find the MidiBuffer class helpful + for queueing incoming messages for use later. + @param source the MidiInput object that generated the message @param message the incoming message. The message's timestamp is set to a value equivalent to (Time::getMillisecondCounter() / 1000.0) to specify the diff --git a/src/juce_appframework/events/juce_InterprocessConnection.cpp b/src/juce_appframework/events/juce_InterprocessConnection.cpp index 354b5414a1..5a96c711e3 100644 --- a/src/juce_appframework/events/juce_InterprocessConnection.cpp +++ b/src/juce_appframework/events/juce_InterprocessConnection.cpp @@ -52,6 +52,7 @@ InterprocessConnection::InterprocessConnection (const bool callbacksOnMessageThr InterprocessConnection::~InterprocessConnection() { + callbackConnectionState = false; disconnect(); } diff --git a/src/juce_appframework/gui/components/buttons/juce_Button.cpp b/src/juce_appframework/gui/components/buttons/juce_Button.cpp index b5f86e9211..ee3ee1556f 100644 --- a/src/juce_appframework/gui/components/buttons/juce_Button.cpp +++ b/src/juce_appframework/gui/components/buttons/juce_Button.cpp @@ -102,7 +102,7 @@ const String Button::getTooltip() for (int i = 0; i < keyPresses.size(); ++i) { - const String key (keyPresses.getUnchecked(i).getTextDescription()); + const String key (keyPresses.getReference(i).getTextDescription()); if (key.length() == 1) tt << " [shortcut: '" << key << "']"; @@ -583,7 +583,7 @@ bool Button::isShortcutPressed() const throw() if (! isCurrentlyBlockedByAnotherModalComponent()) { for (int i = shortcuts.size(); --i >= 0;) - if (shortcuts.getUnchecked(i).isCurrentlyDown()) + if (shortcuts.getReference(i).isCurrentlyDown()) return true; } @@ -593,7 +593,7 @@ bool Button::isShortcutPressed() const throw() bool Button::isRegisteredForShortcut (const KeyPress& key) const throw() { for (int i = shortcuts.size(); --i >= 0;) - if (key == shortcuts.getUnchecked(i)) + if (key == shortcuts.getReference(i)) return true; return false; diff --git a/src/juce_appframework/gui/components/juce_Component.cpp b/src/juce_appframework/gui/components/juce_Component.cpp index 858766923a..b5dccc754e 100644 --- a/src/juce_appframework/gui/components/juce_Component.cpp +++ b/src/juce_appframework/gui/components/juce_Component.cpp @@ -2138,7 +2138,7 @@ void Component::inputAttemptWhenModal() { getTopLevelComponent()->toFront (true); - PlatformUtilities::beep(); + getLookAndFeel().playAlertSound(); } bool Component::canModalEventBeSentToComponent (const Component*) diff --git a/src/juce_appframework/gui/components/juce_Desktop.cpp b/src/juce_appframework/gui/components/juce_Desktop.cpp index 165f8127d6..24308711a2 100644 --- a/src/juce_appframework/gui/components/juce_Desktop.cpp +++ b/src/juce_appframework/gui/components/juce_Desktop.cpp @@ -127,15 +127,23 @@ const Rectangle Desktop::getMainMonitorArea (const bool clippedToWorkArea) const const Rectangle Desktop::getMonitorAreaContaining (int cx, int cy, const bool clippedToWorkArea) const throw() { + Rectangle best (getMainMonitorArea (clippedToWorkArea)); + double bestDistance = 1.0e10; + for (int i = getNumDisplayMonitors(); --i > 0;) { const Rectangle rect (getDisplayMonitorCoordinates (i, clippedToWorkArea)); + const double distance = juce_hypot ((double) (rect.getCentreX() - cx), + (double) (rect.getCentreY() - cy)); - if (rect.contains (cx, cy)) - return rect; + if (distance < bestDistance) + { + bestDistance = distance; + best = rect; + } } - return getMainMonitorArea (clippedToWorkArea); + return best; } //============================================================================== diff --git a/src/juce_appframework/gui/components/keyboard/juce_KeyPressMappingSet.cpp b/src/juce_appframework/gui/components/keyboard/juce_KeyPressMappingSet.cpp index 23350099f7..f6492ef759 100644 --- a/src/juce_appframework/gui/components/keyboard/juce_KeyPressMappingSet.cpp +++ b/src/juce_appframework/gui/components/keyboard/juce_KeyPressMappingSet.cpp @@ -359,7 +359,8 @@ bool KeyPressMappingSet::keyPressed (const KeyPress& key, } else { - PlatformUtilities::beep(); + if (originatingComponent != 0) + originatingComponent->getLookAndFeel().playAlertSound(); } } diff --git a/src/juce_appframework/gui/components/lookandfeel/juce_LookAndFeel.cpp b/src/juce_appframework/gui/components/lookandfeel/juce_LookAndFeel.cpp index 5093078740..308c7cc28a 100644 --- a/src/juce_appframework/gui/components/lookandfeel/juce_LookAndFeel.cpp +++ b/src/juce_appframework/gui/components/lookandfeel/juce_LookAndFeel.cpp @@ -2395,6 +2395,13 @@ Image* LookAndFeel::getDefaultDocumentFileImage() return ImageCache::getFromMemory (fileicon_png, sizeof (fileicon_png)); } + +//============================================================================== +void LookAndFeel::playAlertSound() +{ + PlatformUtilities::beep(); +} + //============================================================================== static void createRoundedPath (Path& p, const float x, const float y, diff --git a/src/juce_appframework/gui/components/lookandfeel/juce_LookAndFeel.h b/src/juce_appframework/gui/components/lookandfeel/juce_LookAndFeel.h index 356fc2fcf0..4ce5b6a119 100644 --- a/src/juce_appframework/gui/components/lookandfeel/juce_LookAndFeel.h +++ b/src/juce_appframework/gui/components/lookandfeel/juce_LookAndFeel.h @@ -503,6 +503,10 @@ public: virtual const Rectangle getPropertyComponentContentPosition (PropertyComponent& component); + //============================================================================== + /** + */ + virtual void playAlertSound(); //============================================================================== /** Utility function to draw a shiny, glassy circle (for round LED-type buttons). */ diff --git a/src/juce_appframework/gui/components/menus/juce_PopupMenu.cpp b/src/juce_appframework/gui/components/menus/juce_PopupMenu.cpp index 1cf5f7144a..ee9ed392cd 100644 --- a/src/juce_appframework/gui/components/menus/juce_PopupMenu.cpp +++ b/src/juce_appframework/gui/components/menus/juce_PopupMenu.cpp @@ -112,7 +112,7 @@ public: for (int i = 0; i < keyPresses.size(); ++i) { - const String key (keyPresses.getUnchecked(i).getTextDescription()); + const String key (keyPresses.getReference(i).getTextDescription()); if (shortcutKey.isNotEmpty()) shortcutKey << ", "; diff --git a/src/juce_appframework/gui/components/special/juce_MidiKeyboardComponent.cpp b/src/juce_appframework/gui/components/special/juce_MidiKeyboardComponent.cpp index 9361c7424a..054f470ef2 100644 --- a/src/juce_appframework/gui/components/special/juce_MidiKeyboardComponent.cpp +++ b/src/juce_appframework/gui/components/special/juce_MidiKeyboardComponent.cpp @@ -842,7 +842,7 @@ bool MidiKeyboardComponent::keyStateChanged() { const int note = 12 * keyMappingOctave + keyPressNotes.getUnchecked (i); - if (keyPresses.getUnchecked (i).isCurrentlyDown()) + if (keyPresses.getReference(i).isCurrentlyDown()) { if (! keysPressed [note]) { diff --git a/src/juce_appframework/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp b/src/juce_appframework/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp index baf0311401..80f51220ca 100644 --- a/src/juce_appframework/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp +++ b/src/juce_appframework/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp @@ -868,7 +868,7 @@ static void transformedImageRender (Image& destImage, const int destClipX, const int destClipY, const int destClipW, const int destClipH, const int srcClipX, const int srcClipY, - const int srcClipRight, const int srcClipBottom, + const int srcClipWidth, const int srcClipHeight, double srcX, double srcY, const double lineDX, const double lineDY, const double pixelDX, const double pixelDY, @@ -883,7 +883,7 @@ static void transformedImageRender (Image& destImage, uint8* const destPixels = destImage.lockPixelDataReadWrite (destClipX, destClipY, destClipW, destClipH, destStride, destPixelStride); int srcStride, srcPixelStride; - const uint8* const srcPixels = sourceImage.lockPixelDataReadOnly (srcClipX, srcClipY, srcClipRight - srcClipX, srcClipBottom - srcClipY, srcStride, srcPixelStride); + const uint8* const srcPixels = sourceImage.lockPixelDataReadOnly (srcClipX, srcClipY, srcClipWidth, srcClipHeight, srcStride, srcPixelStride); if (quality == Graphics::lowResamplingQuality) // nearest-neighbour.. { @@ -896,15 +896,18 @@ static void transformedImageRender (Image& destImage, for (int x = 0; x < destClipW; ++x) { - const int ix = roundDoubleToInt (floor (sx)); - const int iy = roundDoubleToInt (floor (sy)); + const int ix = roundDoubleToInt (floor (sx)) - srcClipX; - if (ix >= srcClipX && iy >= srcClipY - && ix < srcClipRight && iy < srcClipBottom) + if (((unsigned int) ix) < (unsigned int) srcClipWidth) { - const SrcPixelType* const src = (const SrcPixelType*) (srcPixels + srcStride * (iy - srcClipY) + srcPixelStride * (ix - srcClipX)); + const int iy = roundDoubleToInt (floor (sy)) - srcClipY; - dest->blend (*src, alpha); + if (((unsigned int) iy) < (unsigned int) srcClipHeight) + { + const SrcPixelType* const src = (const SrcPixelType*) (srcPixels + srcStride * iy + srcPixelStride * ix); + + dest->blend (*src, alpha); + } } ++dest; @@ -930,42 +933,34 @@ static void transformedImageRender (Image& destImage, { const double fx = floor (sx); const double fy = floor (sy); - int ix = roundDoubleToInt (fx); - int iy = roundDoubleToInt (fy); + const int ix = roundDoubleToInt (fx) - srcClipX; + const int iy = roundDoubleToInt (fy) - srcClipY; - if (ix < srcClipRight && iy < srcClipBottom) + if (ix < srcClipWidth && iy < srcClipHeight) { - const SrcPixelType* src = (const SrcPixelType*) (srcPixels + srcStride * (iy - srcClipY) + srcPixelStride * (ix - srcClipX)); + const SrcPixelType* src = (const SrcPixelType*) (srcPixels + srcStride * iy + srcPixelStride * ix); SrcPixelType p1 (0); const int dx = roundDoubleToInt ((sx - fx) * 255.0); - if (iy >= srcClipY) + if (iy >= 0) { - if (ix >= srcClipX) + if (ix >= 0) p1 = src[0]; - ++ix; - - if (ix >= srcClipX && ix < srcClipRight) + if (((unsigned int) (ix + 1)) < (unsigned int) srcClipWidth) p1.tween (src[1], dx); - - --ix; } - ++iy; - - if (iy >= srcClipY && iy < srcClipBottom) + if (((unsigned int) (iy + 1)) < (unsigned int) srcClipHeight) { SrcPixelType p2 (0); src = (const SrcPixelType*) (((const uint8*) src) + srcStride); - if (ix >= srcClipX) + if (ix >= 0) p2 = src[0]; - ++ix; - - if (ix >= srcClipX && ix < srcClipRight) + if (((unsigned int) (ix + 1)) < (unsigned int) srcClipWidth) p2.tween (src[1], dx); p1.tween (p2, roundDoubleToInt ((sy - fy) * 255.0)); @@ -1808,9 +1803,6 @@ void LowLevelGraphicsSoftwareRenderer::clippedBlendImageWarping (int destClipX, 1 + roundDoubleToInt (imW), 1 + roundDoubleToInt (imH))) { - const int srcClipRight = srcClipX + srcClipW; - const int srcClipBottom = srcClipY + srcClipH; - const uint8 alpha = (uint8) jlimit (0, 0xff, roundDoubleToInt (opacity * 256.0f)); float srcX1 = (float) destClipX; @@ -1836,7 +1828,7 @@ void LowLevelGraphicsSoftwareRenderer::clippedBlendImageWarping (int destClipX, { transformedImageRender (image, sourceImage, destClipX, destClipY, destClipW, destClipH, - srcClipX, srcClipY, srcClipRight, srcClipBottom, + srcClipX, srcClipY, srcClipW, srcClipH, srcX1, srcY1, lineDX, lineDY, pixelDX, pixelDY, alpha, quality, (PixelARGB*)0, (PixelARGB*)0); } @@ -1844,7 +1836,7 @@ void LowLevelGraphicsSoftwareRenderer::clippedBlendImageWarping (int destClipX, { transformedImageRender (image, sourceImage, destClipX, destClipY, destClipW, destClipH, - srcClipX, srcClipY, srcClipRight, srcClipBottom, + srcClipX, srcClipY, srcClipW, srcClipH, srcX1, srcY1, lineDX, lineDY, pixelDX, pixelDY, alpha, quality, (PixelARGB*)0, (PixelRGB*)0); } @@ -1859,7 +1851,7 @@ void LowLevelGraphicsSoftwareRenderer::clippedBlendImageWarping (int destClipX, { transformedImageRender (image, sourceImage, destClipX, destClipY, destClipW, destClipH, - srcClipX, srcClipY, srcClipRight, srcClipBottom, + srcClipX, srcClipY, srcClipW, srcClipH, srcX1, srcY1, lineDX, lineDY, pixelDX, pixelDY, alpha, quality, (PixelRGB*)0, (PixelARGB*)0); } @@ -1867,7 +1859,7 @@ void LowLevelGraphicsSoftwareRenderer::clippedBlendImageWarping (int destClipX, { transformedImageRender (image, sourceImage, destClipX, destClipY, destClipW, destClipH, - srcClipX, srcClipY, srcClipRight, srcClipBottom, + srcClipX, srcClipY, srcClipW, srcClipH, srcX1, srcY1, lineDX, lineDY, pixelDX, pixelDY, alpha, quality, (PixelRGB*)0, (PixelRGB*)0); } @@ -1977,8 +1969,7 @@ void LowLevelGraphicsSoftwareRenderer::clippedDrawVerticalLine (int clipX, int c { jassert (top <= bottom); - if (x >= clipX - && x < clipX + clipW + if (((unsigned int) (x - clipX)) < (unsigned int) clipW && top < clipY + clipH && bottom > clipY && clipW > 0) @@ -2010,8 +2001,7 @@ void LowLevelGraphicsSoftwareRenderer::clippedDrawHorizontalLine (int clipX, int { jassert (left <= right); - if (y >= clipY - && y < clipY + clipH + if (((unsigned int) (y - clipY)) < (unsigned int) clipH && left < clipX + clipW && right > clipX && clipW > 0) diff --git a/src/juce_appframework/gui/graphics/imaging/image_file_formats/pnglib/pngconf.h b/src/juce_appframework/gui/graphics/imaging/image_file_formats/pnglib/pngconf.h index 9097bfc8e6..f48bc0c2bd 100644 --- a/src/juce_appframework/gui/graphics/imaging/image_file_formats/pnglib/pngconf.h +++ b/src/juce_appframework/gui/graphics/imaging/image_file_formats/pnglib/pngconf.h @@ -37,7 +37,7 @@ #define png_error(a, b) png_err(a) #define png_warning(a, b) -#define png_chunk_error(a, b) png_err(a) +#define png_chunk_error(a, b) png_err(a) #define png_chunk_warning(a, b) //============================================================================== diff --git a/src/juce_core/containers/juce_Array.h b/src/juce_core/containers/juce_Array.h index d905828769..cb691ecc36 100644 --- a/src/juce_core/containers/juce_Array.h +++ b/src/juce_core/containers/juce_Array.h @@ -269,8 +269,11 @@ public: */ inline ElementType& getReference (const int index) const throw() { + lock.enter(); jassert (((unsigned int) index) < (unsigned int) numUsed); - return this->elements [index]; + ElementType& result = this->elements [index]; + lock.exit(); + return result; } /** Returns the first element in the array, or 0 if the array is empty. diff --git a/src/juce_core/containers/juce_SortedSet.h b/src/juce_core/containers/juce_SortedSet.h index 1d671f433d..e7b83a6f83 100644 --- a/src/juce_core/containers/juce_SortedSet.h +++ b/src/juce_core/containers/juce_SortedSet.h @@ -218,7 +218,7 @@ public: lock.enter(); const ElementType result = (((unsigned int) index) < (unsigned int) numUsed) ? this->elements [index] - : (ElementType)0; + : (ElementType) 0; lock.exit(); return result;