Add TAL-Reverb-II plugin to test
[juce-lv2.git] / juce / source / extras / JuceDemo / Source / demos / WidgetsDemo.cpp
blob46629140049a90ad342a19afb2b17c0da6740bfe
1 /*
2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-9 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../jucedemo_headers.h"
29 //==============================================================================
30 class BouncingBallComponent : public Component,
31 public Timer
33 public:
34 BouncingBallComponent()
36 x = Random::getSystemRandom().nextFloat() * 100.0f;
37 y = Random::getSystemRandom().nextFloat() * 100.0f;
39 dx = Random::getSystemRandom().nextFloat() * 8.0f - 4.0f;
40 dy = Random::getSystemRandom().nextFloat() * 8.0f - 4.0f;
42 colour = Colour (Random::getSystemRandom().nextInt())
43 .withAlpha (0.5f)
44 .withBrightness (0.7f);
46 int size = 10 + Random::getSystemRandom().nextInt (30);
47 setSize (size, size);
49 startTimer (60);
52 ~BouncingBallComponent()
56 void paint (Graphics& g)
58 g.setColour (colour);
59 g.fillEllipse (x - getX(), y - getY(), getWidth() - 2.0f, getHeight() - 2.0f);
62 void timerCallback()
64 x += dx;
65 y += dy;
67 if (x < 0)
68 dx = fabsf (dx);
70 if (x > getParentWidth())
71 dx = -fabsf (dx);
73 if (y < 0)
74 dy = fabsf (dy);
76 if (y > getParentHeight())
77 dy = -fabsf (dy);
79 setTopLeftPosition ((int) x, (int) y);
82 bool hitTest (int /*x*/, int /*y*/)
84 return false;
87 private:
88 Colour colour;
89 float x, y, dx, dy;
92 //==============================================================================
93 class DragOntoDesktopDemoComp : public Component
95 public:
96 DragOntoDesktopDemoComp (Component* p)
97 : parent (p)
99 // show off semi-transparency if it's supported by the current OS.
100 setOpaque (! Desktop::canUseSemiTransparentWindows());
102 for (int i = 0; i < numElementsInArray (balls); ++i)
103 addAndMakeVisible (&(balls[i]));
106 ~DragOntoDesktopDemoComp()
110 void mouseDown (const MouseEvent& e)
112 dragger.startDraggingComponent (this, e);
115 void mouseDrag (const MouseEvent& e)
117 if (parent == 0)
119 delete this; // If our parent has been deleted, we'll just get rid of this component
121 else
123 // if the mouse is inside the parent component, we'll make that the
124 // parent - otherwise, we'll put this comp on the desktop.
125 if (parent->getLocalBounds().contains (e.getEventRelativeTo (parent).getPosition()))
127 // re-add this component to a parent component, which will
128 // remove it from the desktop..
129 parent->addChildComponent (this);
131 else
133 // add the component to the desktop, which will remove it
134 // from its current parent component..
135 addToDesktop (ComponentPeer::windowIsTemporary);
138 dragger.dragComponent (this, e, 0);
142 void paint (Graphics& g)
144 if (isOpaque())
145 g.fillAll (Colours::white);
146 else
147 g.fillAll (Colours::blue.withAlpha (0.2f));
149 String desc ("drag this box onto the desktop to show how the same component can move from being lightweight to being a separate window");
151 g.setFont (15.0f);
152 g.setColour (Colours::black);
153 g.drawFittedText (desc, 4, 0, getWidth() - 8, getHeight(), Justification::horizontallyJustified, 5);
155 g.drawRect (0, 0, getWidth(), getHeight());
158 private:
159 Component::SafePointer<Component> parent; // A safe-pointer will become zero if the component that it refers to is deleted..
160 ComponentDragger dragger;
162 BouncingBallComponent balls[3];
165 //==============================================================================
166 class CustomMenuComponent : public PopupMenu::CustomComponent,
167 public Timer
169 public:
170 CustomMenuComponent()
171 : blobX (0),
172 blobY (0)
174 // set off a timer to move a blob around on this component every
175 // 300 milliseconds - see the timerCallback() method.
176 startTimer (300);
179 ~CustomMenuComponent()
183 void getIdealSize (int& idealWidth,
184 int& idealHeight)
186 // tells the menu how big we'd like to be..
187 idealWidth = 200;
188 idealHeight = 60;
191 void paint (Graphics& g)
193 g.fillAll (Colours::yellow.withAlpha (0.3f));
195 g.setColour (Colours::pink);
196 g.fillEllipse ((float) blobX, (float) blobY, 30.0f, 40.0f);
198 g.setFont (14.0f, Font::italic);
199 g.setColour (Colours::black);
201 g.drawFittedText ("this is a customised menu item (also demonstrating the Timer class)...",
202 4, 0, getWidth() - 8, getHeight(),
203 Justification::centred, 3);
206 void timerCallback()
208 blobX = Random::getSystemRandom().nextInt (getWidth());
209 blobY = Random::getSystemRandom().nextInt (getHeight());
210 repaint();
213 private:
214 int blobX, blobY;
217 //==============================================================================
218 /** To demonstrate how sliders can have custom snapping applied to their values,
219 this simple class snaps the value to 50 if it comes near.
221 class SnappingSlider : public Slider
223 public:
224 SnappingSlider (const String& name)
225 : Slider (name)
229 double snapValue (double attemptedValue, bool userIsDragging)
231 if (! userIsDragging)
232 return attemptedValue; // if they're entering the value in the text-box, don't mess with it.
234 if (attemptedValue > 40 && attemptedValue < 60)
235 return 50.0;
236 else
237 return attemptedValue;
241 /** A TextButton that pops up a colour chooser to change its colours. */
242 class ColourChangeButton : public TextButton,
243 public ChangeListener
245 public:
246 ColourChangeButton()
247 : TextButton ("click to change colour...")
249 setSize (10, 24);
250 changeWidthToFitText();
253 ~ColourChangeButton()
257 void clicked()
259 #if JUCE_MODAL_LOOPS_PERMITTED
260 ColourSelector colourSelector;
261 colourSelector.setName ("background");
262 colourSelector.setCurrentColour (findColour (TextButton::buttonColourId));
263 colourSelector.addChangeListener (this);
264 colourSelector.setColour (ColourSelector::backgroundColourId, Colours::transparentBlack);
265 colourSelector.setSize (300, 400);
267 CallOutBox callOut (colourSelector, *this, 0);
268 callOut.runModalLoop();
269 #endif
272 void changeListenerCallback (ChangeBroadcaster* source)
274 ColourSelector* cs = dynamic_cast <ColourSelector*> (source);
276 setColour (TextButton::buttonColourId, cs->getCurrentColour());
280 //==============================================================================
281 /* A component to act as a simple container for our demos, which deletes all the child
282 components that we stuff into it.
284 class DemoPageComp : public Component
286 public:
287 DemoPageComp()
291 ~DemoPageComp()
293 /* Deleting your child components indiscriminately using deleteAllChildren() is not recommended! It's much
294 safer to make them embedded members or use ScopedPointers to automatically manage their lifetimes!
296 In this demo, where we're throwing together a whole bunch of random components, it's simpler to do it
297 like this, but don't treat this as an example of good practice!
299 deleteAllChildren();
303 //==============================================================================
304 static Component* createSlidersPage()
306 DemoPageComp* page = new DemoPageComp();
308 const int numSliders = 11;
309 Slider* sliders [numSliders];
311 int i;
312 for (i = 0; i < numSliders; ++i)
314 if (i == 2)
315 page->addAndMakeVisible (sliders[i] = new SnappingSlider ("slider"));
316 else
317 page->addAndMakeVisible (sliders[i] = new Slider ("slider"));
319 sliders[i]->setRange (0.0, 100.0, 0.1);
320 sliders[i]->setPopupMenuEnabled (true);
321 sliders[i]->setValue (Random::getSystemRandom().nextDouble() * 100.0, false, false);
324 sliders[0]->setSliderStyle (Slider::LinearVertical);
325 sliders[0]->setTextBoxStyle (Slider::TextBoxBelow, false, 100, 20);
326 sliders[0]->setBounds (10, 25, 70, 200);
327 sliders[0]->setDoubleClickReturnValue (true, 50.0); // double-clicking this slider will set it to 50.0
328 sliders[0]->setTextValueSuffix (" units");
330 sliders[1]->setSliderStyle (Slider::LinearVertical);
331 sliders[1]->setVelocityBasedMode (true);
332 sliders[1]->setSkewFactor (0.5);
333 sliders[1]->setTextBoxStyle (Slider::TextBoxAbove, true, 100, 20);
334 sliders[1]->setBounds (85, 25, 70, 200);
335 sliders[1]->setTextValueSuffix (" rels");
337 sliders[2]->setSliderStyle (Slider::LinearHorizontal);
338 sliders[2]->setTextBoxStyle (Slider::TextBoxLeft, false, 80, 20);
339 sliders[2]->setBounds (180, 35, 150, 20);
341 sliders[3]->setSliderStyle (Slider::LinearHorizontal);
342 sliders[3]->setTextBoxStyle (Slider::NoTextBox, false, 0, 0);
343 sliders[3]->setBounds (180, 65, 150, 20);
344 sliders[3]->setPopupDisplayEnabled (true, page);
345 sliders[3]->setTextValueSuffix (" nuns required to change a lightbulb");
347 sliders[4]->setSliderStyle (Slider::IncDecButtons);
348 sliders[4]->setTextBoxStyle (Slider::TextBoxLeft, false, 50, 20);
349 sliders[4]->setBounds (180, 105, 100, 20);
350 sliders[4]->setIncDecButtonsMode (Slider::incDecButtonsDraggable_Vertical);
352 sliders[5]->setSliderStyle (Slider::Rotary);
353 sliders[5]->setRotaryParameters (float_Pi * 1.2f, float_Pi * 2.8f, false);
354 sliders[5]->setTextBoxStyle (Slider::TextBoxRight, false, 70, 20);
355 sliders[5]->setBounds (190, 145, 120, 40);
356 sliders[5]->setTextValueSuffix (" mm");
358 sliders[6]->setSliderStyle (Slider::LinearBar);
359 sliders[6]->setBounds (180, 195, 100, 30);
360 sliders[6]->setTextValueSuffix (" gallons");
362 sliders[7]->setSliderStyle (Slider::TwoValueHorizontal);
363 sliders[7]->setBounds (360, 20, 160, 40);
365 sliders[8]->setSliderStyle (Slider::TwoValueVertical);
366 sliders[8]->setBounds (360, 110, 40, 160);
368 sliders[9]->setSliderStyle (Slider::ThreeValueHorizontal);
369 sliders[9]->setBounds (360, 70, 160, 40);
371 sliders[10]->setSliderStyle (Slider::ThreeValueVertical);
372 sliders[10]->setBounds (440, 110, 40, 160);
374 for (i = 7; i <= 10; ++i)
376 sliders[i]->setTextBoxStyle (Slider::NoTextBox, false, 0, 0);
377 sliders[i]->setPopupDisplayEnabled (true, page);
380 /* Here, we'll create a Value object, and tell a bunch of our sliders to use it as their
381 value source. By telling them all to share the same Value, they'll stay in sync with
382 each other.
384 We could also optionally keep a copy of this Value elsewhere, and by changing it,
385 cause all the sliders to automatically update.
387 Value sharedValue;
388 sharedValue = Random::getSystemRandom().nextDouble() * 100;
389 for (i = 0; i < 7; ++i)
390 sliders[i]->getValueObject().referTo (sharedValue);
392 // ..and now we'll do the same for all our min/max slider values..
393 Value sharedValueMin, sharedValueMax;
394 sharedValueMin = Random::getSystemRandom().nextDouble() * 40.0;
395 sharedValueMax = Random::getSystemRandom().nextDouble() * 40.0 + 60.0;
397 for (i = 7; i <= 10; ++i)
399 sliders[i]->getMaxValueObject().referTo (sharedValueMax);
400 sliders[i]->getMinValueObject().referTo (sharedValueMin);
403 // Create a description label...
404 Label* label = new Label ("hint", "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");
405 label->setBounds (20, 245, 350, 150);
406 page->addAndMakeVisible (label);
408 return page;
411 //==============================================================================
412 static Component* createRadioButtonPage()
414 DemoPageComp* page = new DemoPageComp();
416 GroupComponent* group = new GroupComponent ("group", "radio buttons");
417 group->setBounds (20, 20, 220, 140);
418 page->addAndMakeVisible (group);
420 int i;
421 for (i = 0; i < 4; ++i)
423 ToggleButton* tb = new ToggleButton ("radio button #" + String (i + 1));
424 page->addAndMakeVisible (tb);
425 tb->setRadioGroupId (1234);
426 tb->setBounds (45, 46 + i * 22, 180, 22);
427 tb->setTooltip ("a set of mutually-exclusive radio buttons");
429 if (i == 0)
430 tb->setToggleState (true, false);
433 for (i = 0; i < 4; ++i)
435 DrawablePath normal, over;
437 Path p;
438 p.addStar (Point<float>(), i + 5, 20.0f, 50.0f, -0.2f);
439 normal.setPath (p);
440 normal.setFill (Colours::lightblue);
441 normal.setStrokeFill (Colours::black);
442 normal.setStrokeThickness (4.0f);
444 over.setPath (p);
445 over.setFill (Colours::blue);
446 over.setStrokeFill (Colours::black);
447 over.setStrokeThickness (4.0f);
449 DrawableButton* db = new DrawableButton (String (i + 5) + " points", DrawableButton::ImageAboveTextLabel);
450 db->setImages (&normal, &over, 0);
452 page->addAndMakeVisible (db);
453 db->setClickingTogglesState (true);
454 db->setRadioGroupId (23456);
456 const int buttonSize = 50;
457 db->setBounds (25 + i * buttonSize, 180, buttonSize, buttonSize);
459 if (i == 0)
460 db->setToggleState (true, false);
463 for (i = 0; i < 4; ++i)
465 TextButton* tb = new TextButton ("button " + String (i + 1));
467 page->addAndMakeVisible (tb);
468 tb->setClickingTogglesState (true);
469 tb->setRadioGroupId (34567);
470 tb->setColour (TextButton::buttonColourId, Colours::white);
471 tb->setColour (TextButton::buttonOnColourId, Colours::blueviolet.brighter());
473 tb->setBounds (20 + i * 55, 260, 55, 24);
474 tb->setConnectedEdges (((i != 0) ? Button::ConnectedOnLeft : 0)
475 | ((i != 3) ? Button::ConnectedOnRight : 0));
477 if (i == 0)
478 tb->setToggleState (true, false);
481 return page;
484 //==============================================================================
485 class ButtonsPage : public Component,
486 public ButtonListener
488 public:
489 ButtonsPage (ButtonListener* buttonListener)
491 //==============================================================================
492 // create some drawables to use for our drawable buttons...
493 DrawablePath normal, over;
495 Path p;
496 p.addStar (Point<float>(), 5, 20.0f, 50.0f, 0.2f);
497 normal.setPath (p);
498 normal.setFill (Colours::red);
500 p.clear();
501 p.addStar (Point<float>(), 7, 30.0f, 50.0f, 0.0f);
502 over.setPath (p);
503 over.setFill (Colours::pink);
504 over.setStrokeFill (Colours::black);
505 over.setStrokeThickness (5.0f);
507 DrawableImage down;
508 down.setImage (ImageCache::getFromMemory (BinaryData::juce_png, BinaryData::juce_pngSize));
509 down.setOverlayColour (Colours::black.withAlpha (0.3f));
511 //==============================================================================
512 // create an image-above-text button from these drawables..
513 DrawableButton* db = new DrawableButton ("Button 1", DrawableButton::ImageAboveTextLabel);
514 db->setImages (&normal, &over, &down);
516 addAndMakeVisible (db);
517 db->setBounds (10, 30, 80, 80);
518 db->setTooltip ("this is a DrawableButton with a label");
520 //==============================================================================
521 // create an image-only button from these drawables..
522 db = new DrawableButton ("Button 2", DrawableButton::ImageFitted);
523 db->setImages (&normal, &over, &down);
524 db->setClickingTogglesState (true);
526 addAndMakeVisible (db);
527 db->setBounds (90, 30, 80, 80);
528 db->setTooltip ("this is an image-only DrawableButton");
529 db->addListener (buttonListener);
531 //==============================================================================
532 // create an image-on-button-shape button from the same drawables..
533 db = new DrawableButton ("Button 3", DrawableButton::ImageOnButtonBackground);
534 db->setImages (&normal, 0, 0);
536 addAndMakeVisible (db);
537 db->setBounds (200, 30, 110, 25);
538 db->setTooltip ("this is a DrawableButton on a standard button background");
540 //==============================================================================
541 db = new DrawableButton ("Button 4", DrawableButton::ImageOnButtonBackground);
542 db->setImages (&normal, &over, &down);
543 db->setClickingTogglesState (true);
544 db->setBackgroundColours (Colours::white, Colours::yellow);
546 addAndMakeVisible (db);
547 db->setBounds (200, 70, 50, 50);
548 db->setTooltip ("this is a DrawableButton on a standard button background");
549 db->addListener (buttonListener);
551 //==============================================================================
552 HyperlinkButton* hyperlink
553 = new HyperlinkButton ("this is a HyperlinkButton",
554 URL ("http://www.rawmaterialsoftware.com/juce"));
556 hyperlink->setBounds (10, 130, 200, 24);
557 addAndMakeVisible (hyperlink);
559 //==============================================================================
560 ImageButton* imageButton = new ImageButton ("imagebutton");
561 addAndMakeVisible (imageButton);
563 Image juceImage = ImageCache::getFromMemory (BinaryData::juce_png, BinaryData::juce_pngSize);
564 imageButton->setImages (true, true, true,
565 juceImage, 0.7f, Colours::transparentBlack,
566 juceImage, 1.0f, Colours::transparentBlack,
567 juceImage, 1.0f, Colours::pink.withAlpha (0.8f),
568 0.5f);
570 imageButton->setTopLeftPosition (10, 160);
571 imageButton->setTooltip ("image button - showing alpha-channel hit-testing and colour overlay when clicked");
573 //==============================================================================
574 ColourChangeButton* colourChangeButton = new ColourChangeButton();
575 addAndMakeVisible (colourChangeButton);
576 colourChangeButton->setTopLeftPosition (350, 30);
578 //==============================================================================
579 animateButton = new TextButton ("click to animate...");
580 addAndMakeVisible (animateButton);
581 animateButton->changeWidthToFitText (24);
582 animateButton->setTopLeftPosition (350, 70);
583 animateButton->addListener (this);
586 ~ButtonsPage()
588 /* Deleting your child components indiscriminately using deleteAllChildren() is not recommended! It's much
589 safer to make them embedded members or use ScopedPointers to automatically manage their lifetimes!
591 In this demo, where we're throwing together a whole bunch of random components, it's simpler to do it
592 like this, but don't treat this as an example of good practice!
594 deleteAllChildren();
597 void buttonClicked (Button*)
599 for (int i = getNumChildComponents(); --i >= 0;)
601 if (getChildComponent (i) != animateButton)
603 animator.animateComponent (getChildComponent (i),
604 Rectangle<int> (Random::getSystemRandom().nextInt (getWidth() / 2),
605 Random::getSystemRandom().nextInt (getHeight() / 2),
606 60 + Random::getSystemRandom().nextInt (getWidth() / 3),
607 16 + Random::getSystemRandom().nextInt (getHeight() / 6)),
608 Random::getSystemRandom().nextFloat(),
609 500 + Random::getSystemRandom().nextInt (2000),
610 false,
611 Random::getSystemRandom().nextDouble(),
612 Random::getSystemRandom().nextDouble());
617 private:
618 TextButton* animateButton;
619 ComponentAnimator animator;
623 //==============================================================================
624 static Component* createMiscPage()
626 DemoPageComp* page = new DemoPageComp();
628 TextEditor* textEditor1 = new TextEditor();
629 page->addAndMakeVisible (textEditor1);
630 textEditor1->setBounds (10, 25, 200, 24);
631 textEditor1->setText ("single-line text box");
633 TextEditor* textEditor2 = new TextEditor ("password", (juce_wchar) 0x2022);
634 page->addAndMakeVisible (textEditor2);
635 textEditor2->setBounds (10, 55, 200, 24);
636 textEditor2->setText ("password");
638 //==============================================================================
639 ComboBox* comboBox = new ComboBox ("combo");
640 page->addAndMakeVisible (comboBox);
641 comboBox->setBounds (300, 25, 200, 24);
642 comboBox->setEditableText (true);
643 comboBox->setJustificationType (Justification::centred);
645 int i;
646 for (i = 1; i < 100; ++i)
647 comboBox->addItem ("combo box item " + String (i), i);
649 comboBox->setSelectedId (1);
651 DragOntoDesktopDemoComp* d = new DragOntoDesktopDemoComp (page);
652 page->addAndMakeVisible (d);
653 d->setBounds (20, 100, 200, 80);
655 return page;
658 //==============================================================================
659 class ToolbarDemoComp : public Component,
660 public SliderListener,
661 public ButtonListener
663 public:
664 ToolbarDemoComp()
665 : depthLabel (String::empty, "Toolbar depth:"),
666 infoLabel (String::empty, "As well as showing off toolbars, this demo illustrates how to store "
667 "a set of SVG files in a Zip file, embed that in your application, and read "
668 "them back in at runtime.\n\nThe icon images here are taken from the open-source "
669 "Tango icon project."),
670 orientationButton ("Vertical/Horizontal"),
671 customiseButton ("Customise...")
673 // Create and add the toolbar...
674 addAndMakeVisible (&toolbar);
676 // And use our item factory to add a set of default icons to it...
677 toolbar.addDefaultItems (factory);
679 // Now we'll just create the other sliders and buttons on the demo page, which adjust
680 // the toolbar's properties...
681 addAndMakeVisible (&infoLabel);
682 infoLabel.setJustificationType (Justification::topLeft);
683 infoLabel.setBounds (80, 80, 450, 100);
684 infoLabel.setInterceptsMouseClicks (false, false);
686 addAndMakeVisible (&depthSlider);
687 depthSlider.setRange (10.0, 200.0, 1.0);
688 depthSlider.setValue (50, false);
689 depthSlider.setSliderStyle (Slider::LinearHorizontal);
690 depthSlider.setTextBoxStyle (Slider::TextBoxLeft, false, 80, 20);
691 depthSlider.addListener (this);
692 depthSlider.setBounds (80, 210, 300, 22);
693 depthLabel.attachToComponent (&depthSlider, false);
695 addAndMakeVisible (&orientationButton);
696 orientationButton.addListener (this);
697 orientationButton.changeWidthToFitText (22);
698 orientationButton.setTopLeftPosition (depthSlider.getX(), depthSlider.getBottom() + 20);
700 addAndMakeVisible (&customiseButton);
701 customiseButton.addListener (this);
702 customiseButton.changeWidthToFitText (22);
703 customiseButton.setTopLeftPosition (orientationButton.getRight() + 20, orientationButton.getY());
706 void resized()
708 if (toolbar.isVertical())
709 toolbar.setBounds (0, 0, (int) depthSlider.getValue(), getHeight());
710 else
711 toolbar.setBounds (0, 0, getWidth(), (int) depthSlider.getValue());
714 void sliderValueChanged (Slider*)
716 resized();
719 void buttonClicked (Button* button)
721 if (button == &orientationButton)
723 toolbar.setVertical (! toolbar.isVertical());
724 resized();
726 else if (button == &customiseButton)
728 toolbar.showCustomisationDialog (factory);
732 private:
733 Toolbar toolbar;
734 Slider depthSlider;
735 Label depthLabel, infoLabel;
736 TextButton orientationButton, customiseButton;
738 //==============================================================================
739 class DemoToolbarItemFactory : public ToolbarItemFactory
741 public:
742 DemoToolbarItemFactory() {}
743 ~DemoToolbarItemFactory() {}
745 //==============================================================================
746 // Each type of item a toolbar can contain must be given a unique ID. These
747 // are the ones we'll use in this demo.
748 enum DemoToolbarItemIds
750 doc_new = 1,
751 doc_open = 2,
752 doc_save = 3,
753 doc_saveAs = 4,
754 edit_copy = 5,
755 edit_cut = 6,
756 edit_paste = 7,
757 juceLogoButton = 8,
758 customComboBox = 9
761 void getAllToolbarItemIds (Array <int>& ids)
763 // This returns the complete list of all item IDs that are allowed to
764 // go in our toolbar. Any items you might want to add must be listed here. The
765 // order in which they are listed will be used by the toolbar customisation panel.
767 ids.add (doc_new);
768 ids.add (doc_open);
769 ids.add (doc_save);
770 ids.add (doc_saveAs);
771 ids.add (edit_copy);
772 ids.add (edit_cut);
773 ids.add (edit_paste);
774 ids.add (juceLogoButton);
775 ids.add (customComboBox);
777 // If you're going to use separators, then they must also be added explicitly
778 // to the list.
779 ids.add (separatorBarId);
780 ids.add (spacerId);
781 ids.add (flexibleSpacerId);
784 void getDefaultItemSet (Array <int>& ids)
786 // This returns an ordered list of the set of items that make up a
787 // toolbar's default set. Not all items need to be on this list, and
788 // items can appear multiple times (e.g. the separators used here).
789 ids.add (doc_new);
790 ids.add (doc_open);
791 ids.add (doc_save);
792 ids.add (doc_saveAs);
793 ids.add (spacerId);
794 ids.add (separatorBarId);
795 ids.add (edit_copy);
796 ids.add (edit_cut);
797 ids.add (edit_paste);
798 ids.add (separatorBarId);
799 ids.add (flexibleSpacerId);
800 ids.add (customComboBox);
801 ids.add (flexibleSpacerId);
802 ids.add (separatorBarId);
803 ids.add (juceLogoButton);
806 ToolbarItemComponent* createItem (int itemId)
808 switch (itemId)
810 case doc_new: return createButtonFromZipFileSVG (itemId, "new", "document-new.svg");
811 case doc_open: return createButtonFromZipFileSVG (itemId, "open", "document-open.svg");
812 case doc_save: return createButtonFromZipFileSVG (itemId, "save", "document-save.svg");
813 case doc_saveAs: return createButtonFromZipFileSVG (itemId, "save as", "document-save-as.svg");
814 case edit_copy: return createButtonFromZipFileSVG (itemId, "copy", "edit-copy.svg");
815 case edit_cut: return createButtonFromZipFileSVG (itemId, "cut", "edit-cut.svg");
816 case edit_paste: return createButtonFromZipFileSVG (itemId, "paste", "edit-paste.svg");
817 case juceLogoButton: return new ToolbarButton (itemId, "juce!", Drawable::createFromImageData (BinaryData::juce_png, BinaryData::juce_pngSize), 0);
818 case customComboBox: return new CustomToolbarComboBox (itemId);
819 default: break;
822 return 0;
825 private:
826 StringArray iconNames;
827 OwnedArray <Drawable> iconsFromZipFile;
829 // This is a little utility to create a button with one of the SVG images in
830 // our embedded ZIP file "icons.zip"
831 ToolbarButton* createButtonFromZipFileSVG (const int itemId, const String& text, const String& filename)
833 if (iconsFromZipFile.size() == 0)
835 // If we've not already done so, load all the images from the zip file..
836 MemoryInputStream iconsFileStream (BinaryData::icons_zip, BinaryData::icons_zipSize, false);
837 ZipFile icons (&iconsFileStream, false);
839 for (int i = 0; i < icons.getNumEntries(); ++i)
841 ScopedPointer<InputStream> svgFileStream (icons.createStreamForEntry (i));
843 if (svgFileStream != 0)
845 iconNames.add (icons.getEntry(i)->filename);
846 iconsFromZipFile.add (Drawable::createFromImageDataStream (*svgFileStream));
851 Drawable* image = iconsFromZipFile [iconNames.indexOf (filename)]->createCopy();
852 return new ToolbarButton (itemId, text, image, 0);
855 // Demonstrates how to put a custom component into a toolbar - this one contains
856 // a ComboBox.
857 class CustomToolbarComboBox : public ToolbarItemComponent
859 public:
860 CustomToolbarComboBox (const int toolbarItemId)
861 : ToolbarItemComponent (toolbarItemId, "Custom Toolbar Item", false),
862 comboBox ("demo toolbar combo box")
864 addAndMakeVisible (&comboBox);
866 for (int i = 1; i < 20; ++i)
867 comboBox.addItem ("Toolbar ComboBox item " + String (i), i);
869 comboBox.setSelectedId (1);
870 comboBox.setEditableText (true);
873 ~CustomToolbarComboBox()
877 bool getToolbarItemSizes (int /*toolbarDepth*/, bool isToolbarVertical,
878 int& preferredSize, int& minSize, int& maxSize)
880 if (isToolbarVertical)
881 return false;
883 preferredSize = 250;
884 minSize = 80;
885 maxSize = 300;
886 return true;
889 void paintButtonArea (Graphics&, int, int, bool, bool)
893 void contentAreaChanged (const Rectangle<int>& contentArea)
895 comboBox.setSize (contentArea.getWidth() - 2,
896 jmin (contentArea.getHeight() - 2, 22));
898 comboBox.setCentrePosition (contentArea.getCentreX(), contentArea.getCentreY());
901 private:
902 ComboBox comboBox;
906 DemoToolbarItemFactory factory;
909 //==============================================================================
910 class DemoTabbedComponent : public TabbedComponent,
911 public ButtonListener
913 public:
914 DemoTabbedComponent()
915 : TabbedComponent (TabbedButtonBar::TabsAtTop)
917 addTab ("sliders", getRandomBrightColour(), createSlidersPage(), true);
918 addTab ("toolbars", getRandomBrightColour(), new ToolbarDemoComp(), true);
919 addTab ("buttons", getRandomBrightColour(), new ButtonsPage (this), true);
920 addTab ("radio buttons", getRandomBrightColour(), createRadioButtonPage(), true);
921 addTab ("misc widgets", getRandomBrightColour(), createMiscPage(), true);
924 void buttonClicked (Button* button)
926 BubbleMessageComponent* bmc = new BubbleMessageComponent();
928 if (Desktop::canUseSemiTransparentWindows())
930 bmc->setAlwaysOnTop (true);
931 bmc->addToDesktop (0);
933 else
935 addChildComponent (bmc);
938 bmc->showAt (button, "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.",
939 2000, true, true);
942 static const Colour getRandomBrightColour()
944 return Colour (Random::getSystemRandom().nextFloat(), 0.1f, 0.97f, 1.0f);
949 //==============================================================================
950 class DemoBackgroundThread : public ThreadWithProgressWindow
952 public:
953 DemoBackgroundThread()
954 : ThreadWithProgressWindow ("busy doing some important things...",
955 true,
956 true)
958 setStatusMessage ("Getting ready...");
961 void run()
963 setProgress (-1.0); // setting a value beyond the range 0 -> 1 will show a spinning bar..
964 setStatusMessage ("Preparing to do some stuff...");
965 wait (2000);
967 const int thingsToDo = 10;
969 for (int i = 0; i < thingsToDo; ++i)
971 // must check this as often as possible, because this is
972 // how we know if the user's pressed 'cancel'
973 if (threadShouldExit())
974 return;
976 // this will update the progress bar on the dialog box
977 setProgress (i / (double) thingsToDo);
979 setStatusMessage (String (thingsToDo - i) + " things left to do...");
981 wait (500);
984 setProgress (-1.0); // setting a value beyond the range 0 -> 1 will show a spinning bar..
985 setStatusMessage ("Finishing off the last few bits and pieces!");
986 wait (2000);
990 //==============================================================================
991 /** A DialogWindow containing a ColourSelector component */
992 class ColourSelectorDialogWindow : public DialogWindow
994 public:
995 ColourSelectorDialogWindow()
996 : DialogWindow ("Colour selector demo",
997 Colours::lightgrey,
998 true)
1000 setContentOwned (new ColourSelector(), false);
1001 centreWithSize (400, 400);
1002 setResizable (true, true);
1005 void closeButtonPressed()
1007 // we expect this component to be run within a modal loop, so when the close
1008 // button is clicked, we can make it invisible to cause the loop to exit and the
1009 // calling code will delete this object.
1010 setVisible (false);
1014 #if JUCE_MAC
1016 //==============================================================================
1017 /** This pops open a dialog box and waits for you to press keys on your Apple Remote,
1018 which it describes in the box.
1020 class AppleRemoteTestWindow : public AlertWindow,
1021 public AppleRemoteDevice
1023 public:
1024 AppleRemoteTestWindow()
1025 : AlertWindow ("Apple Remote Control Test!",
1026 "If you've got an Apple Remote, press some buttons now...",
1027 AlertWindow::NoIcon)
1029 addButton ("done", 0);
1031 // (To open the device in non-exclusive mode, pass 'false' in here)..
1032 if (! start (true))
1033 setMessage ("Couldn't open the remote control device!");
1036 ~AppleRemoteTestWindow()
1038 stop();
1041 void buttonPressed (const ButtonType buttonId, const bool isDown)
1043 String desc;
1045 switch (buttonId)
1047 case menuButton: desc = "menu button (short)"; break;
1048 case playButton: desc = "play button"; break;
1049 case plusButton: desc = "plus button"; break;
1050 case minusButton: desc = "minus button"; break;
1051 case rightButton: desc = "right button (short)"; break;
1052 case leftButton: desc = "left button (short)"; break;
1053 case rightButton_Long: desc = "right button (long)"; break;
1054 case leftButton_Long: desc = "left button (long)"; break;
1055 case menuButton_Long: desc = "menu button (long)"; break;
1056 case playButtonSleepMode: desc = "play (sleep mode)"; break;
1057 case switched: desc = "remote switched"; break;
1060 if (isDown)
1061 desc << " -- [down]";
1062 else
1063 desc << " -- [up]";
1065 setMessage (desc);
1069 #endif
1071 //==============================================================================
1072 class WidgetsDemo : public Component,
1073 public ButtonListener,
1074 public SliderListener
1076 public:
1077 //==============================================================================
1078 WidgetsDemo()
1079 : menuButton ("click for a popup menu..",
1080 "click for a demo of the different types of item you can put into a popup menu..."),
1081 enableButton ("enable/disable components")
1083 setName ("Widgets");
1085 addAndMakeVisible (&tabs);
1087 //==============================================================================
1088 addAndMakeVisible (&menuButton);
1089 menuButton.setBounds (10, 10, 200, 24);
1090 menuButton.addListener (this);
1091 menuButton.setTriggeredOnMouseDown (true); // because this button pops up a menu, this lets us
1092 // hold down the button and drag straight onto the menu
1094 //==============================================================================
1095 addAndMakeVisible (&enableButton);
1096 enableButton.setBounds (230, 10, 180, 24);
1097 enableButton.setTooltip ("Enables/disables all the components");
1098 enableButton.setToggleState (true, false);
1099 enableButton.addListener (this);
1101 addAndMakeVisible (&transformSlider);
1102 transformSlider.setSliderStyle (Slider::LinearBar);
1103 transformSlider.setTextValueSuffix (" degrees rotation");
1104 transformSlider.setRange (-180.0, 180.0, 0.1);
1105 transformSlider.setBounds (440, 10, 180, 24);
1106 transformSlider.setTooltip ("Applies a transform to the components");
1107 transformSlider.addListener (this);
1110 void resized()
1112 tabs.setBounds (10, 40, getWidth() - 20, getHeight() - 50);
1115 //==============================================================================
1116 void buttonClicked (Button* button)
1118 if (button == &enableButton)
1120 const bool enabled = enableButton.getToggleState();
1122 menuButton.setEnabled (enabled);
1123 tabs.setEnabled (enabled);
1125 else if (button == &menuButton)
1127 PopupMenu m;
1128 m.addItem (1, "Normal item");
1129 m.addItem (2, "Disabled item", false);
1130 m.addItem (3, "Ticked item", true, true);
1131 m.addColouredItem (4, "Coloured item", Colours::green);
1132 m.addSeparator();
1133 m.addCustomItem (5, new CustomMenuComponent());
1135 m.addSeparator();
1137 PopupMenu tabsMenu;
1138 tabsMenu.addItem (1001, "Show tabs at the top", true, tabs.getOrientation() == TabbedButtonBar::TabsAtTop);
1139 tabsMenu.addItem (1002, "Show tabs at the bottom", true, tabs.getOrientation() == TabbedButtonBar::TabsAtBottom);
1140 tabsMenu.addItem (1003, "Show tabs at the left", true, tabs.getOrientation() == TabbedButtonBar::TabsAtLeft);
1141 tabsMenu.addItem (1004, "Show tabs at the right", true, tabs.getOrientation() == TabbedButtonBar::TabsAtRight);
1142 m.addSubMenu ("Tab position", tabsMenu);
1144 m.addSeparator();
1146 PopupMenu dialogMenu;
1147 dialogMenu.addItem (100, "Show a plain alert-window...");
1148 dialogMenu.addItem (101, "Show an alert-window with a 'warning' icon...");
1149 dialogMenu.addItem (102, "Show an alert-window with an 'info' icon...");
1150 dialogMenu.addItem (103, "Show an alert-window with a 'question' icon...");
1152 dialogMenu.addSeparator();
1154 dialogMenu.addItem (110, "Show an ok/cancel alert-window...");
1156 dialogMenu.addSeparator();
1158 dialogMenu.addItem (111, "Show an alert-window with some extra components...");
1160 dialogMenu.addSeparator();
1162 dialogMenu.addItem (112, "Show a ThreadWithProgressWindow demo...");
1164 m.addSubMenu ("AlertWindow demonstrations", dialogMenu);
1166 m.addSeparator();
1168 m.addItem (120, "Show a colour selector demo...");
1169 m.addSeparator();
1171 #if JUCE_MAC
1172 m.addItem (140, "Run the Apple Remote Control test...");
1173 m.addSeparator();
1174 #endif
1176 PopupMenu nativeFileChoosers;
1177 nativeFileChoosers.addItem (121, "'Load' file browser...");
1178 nativeFileChoosers.addItem (124, "'Load' file browser with an image file preview...");
1179 nativeFileChoosers.addItem (122, "'Save' file browser...");
1180 nativeFileChoosers.addItem (123, "'Choose directory' file browser...");
1182 PopupMenu juceFileChoosers;
1183 juceFileChoosers.addItem (131, "'Load' file browser...");
1184 juceFileChoosers.addItem (134, "'Load' file browser with an image file preview...");
1185 juceFileChoosers.addItem (132, "'Save' file browser...");
1186 juceFileChoosers.addItem (133, "'Choose directory' file browser...");
1188 PopupMenu fileChoosers;
1189 fileChoosers.addSubMenu ("Operating system dialogs", nativeFileChoosers);
1190 fileChoosers.addSubMenu ("Juce dialogs", juceFileChoosers);
1192 m.addSubMenu ("File chooser dialogs", fileChoosers);
1194 m.showMenuAsync (PopupMenu::Options().withTargetComponent (&menuButton),
1195 ModalCallbackFunction::forComponent (menuItemChosenCallback, this));
1199 //==============================================================================
1200 // This gets called when our popup menu has an item selected or is dismissed.
1201 static void menuItemChosenCallback (int result, WidgetsDemo* demoComponent)
1203 if (result != 0 && demoComponent != 0)
1204 demoComponent->performDemoMenuItem (result);
1207 static void alertBoxResultChosen (int result, WidgetsDemo* demoComponent)
1209 AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
1210 "Alert Box",
1211 "Result code: " + String (result));
1214 void performDemoMenuItem (int result)
1216 if (result >= 100 && result < 105)
1218 AlertWindow::AlertIconType icon = AlertWindow::NoIcon;
1220 if (result == 101)
1221 icon = AlertWindow::WarningIcon;
1222 else if (result == 102)
1223 icon = AlertWindow::InfoIcon;
1224 else if (result == 103)
1225 icon = AlertWindow::QuestionIcon;
1227 AlertWindow::showMessageBoxAsync (icon,
1228 "This is an AlertWindow",
1229 "And this is the AlertWindow's message. Blah blah blah blah blah blah blah blah blah blah blah blah blah.",
1230 "ok");
1232 else if (result == 110)
1234 AlertWindow::showOkCancelBox (AlertWindow::QuestionIcon,
1235 "This is an ok/cancel AlertWindow",
1236 "And this is the AlertWindow's message. Blah blah blah blah blah blah blah blah blah blah blah blah blah.",
1237 String::empty,
1238 String::empty,
1240 ModalCallbackFunction::forComponent (alertBoxResultChosen, this));
1242 else if (result == 111)
1244 #if JUCE_MODAL_LOOPS_PERMITTED
1245 AlertWindow w ("AlertWindow demo..",
1246 "This AlertWindow has a couple of extra components added to show how to add drop-down lists and text entry boxes.",
1247 AlertWindow::QuestionIcon);
1249 w.addTextEditor ("text", "enter some text here", "text field:");
1251 StringArray options;
1252 options.add ("option 1");
1253 options.add ("option 2");
1254 options.add ("option 3");
1255 options.add ("option 4");
1256 w.addComboBox ("option", options, "some options");
1258 w.addButton ("ok", 1, KeyPress (KeyPress::returnKey, 0, 0));
1259 w.addButton ("cancel", 0, KeyPress (KeyPress::escapeKey, 0, 0));
1261 if (w.runModalLoop() != 0) // is they picked 'ok'
1263 // this is the item they chose in the drop-down list..
1264 const int optionIndexChosen = w.getComboBoxComponent ("option")->getSelectedItemIndex();
1265 (void) optionIndexChosen; // (just avoids a compiler warning about unused variables)
1268 // this is the text they entered..
1269 String text = w.getTextEditorContents ("text");
1272 #endif
1274 else if (result == 112)
1276 DemoBackgroundThread demoThread;
1278 #if JUCE_MODAL_LOOPS_PERMITTED
1279 if (demoThread.runThread())
1281 // thread finished normally..
1282 AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
1283 "Progress window",
1284 "Thread finished ok!");
1286 else
1288 // user pressed the cancel button..
1289 AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
1290 "Progress window",
1291 "You pressed cancel!");
1293 #endif
1295 else if (result == 120)
1297 #if JUCE_MODAL_LOOPS_PERMITTED
1298 ColourSelectorDialogWindow colourDialog;
1300 // this will run an event loop until the dialog's closeButtonPressed()
1301 // method causes the loop to exit.
1302 colourDialog.runModalLoop();
1303 #endif
1305 else if (result == 140)
1307 #if JUCE_MAC
1308 AppleRemoteTestWindow test;
1309 test.runModalLoop();
1310 #endif
1312 else if (result >= 121 && result < 139)
1314 #if JUCE_MODAL_LOOPS_PERMITTED
1315 const bool useNativeVersion = result < 130;
1316 if (result > 130)
1317 result -= 10;
1319 if (result == 121)
1321 FileChooser fc ("Choose a file to open...",
1322 File::getCurrentWorkingDirectory(),
1323 "*",
1324 useNativeVersion);
1326 if (fc.browseForMultipleFilesToOpen())
1328 String chosen;
1329 for (int i = 0; i < fc.getResults().size(); ++i)
1330 chosen << fc.getResults().getReference(i).getFullPathName() << "\n";
1332 AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
1333 "File Chooser...",
1334 "You picked: " + chosen);
1337 else if (result == 124)
1339 ImagePreviewComponent imagePreview;
1340 imagePreview.setSize (200, 200);
1342 FileChooser fc ("Choose an image to open...",
1343 File::getCurrentWorkingDirectory(),
1344 "*.jpg;*.jpeg;*.png;*.gif",
1345 useNativeVersion);
1347 if (fc.browseForMultipleFilesToOpen (&imagePreview))
1349 String chosen;
1350 for (int i = 0; i < fc.getResults().size(); ++i)
1351 chosen << fc.getResults().getReference(i).getFullPathName() << "\n";
1353 AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
1354 "File Chooser...",
1355 "You picked: " + chosen);
1358 else if (result == 122)
1360 FileChooser fc ("Choose a file to save...",
1361 File::getCurrentWorkingDirectory(),
1362 "*",
1363 useNativeVersion);
1365 if (fc.browseForFileToSave (true))
1367 File chosenFile = fc.getResult();
1369 AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
1370 "File Chooser...",
1371 "You picked: " + chosenFile.getFullPathName());
1374 else if (result == 123)
1376 FileChooser fc ("Choose a directory...",
1377 File::getCurrentWorkingDirectory(),
1378 "*",
1379 useNativeVersion);
1381 if (fc.browseForDirectory())
1383 File chosenDirectory = fc.getResult();
1385 AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
1386 "File Chooser...",
1387 "You picked: " + chosenDirectory.getFullPathName());
1390 #endif
1392 else if (result == 1001)
1394 tabs.setOrientation (TabbedButtonBar::TabsAtTop);
1396 else if (result == 1002)
1398 tabs.setOrientation (TabbedButtonBar::TabsAtBottom);
1400 else if (result == 1003)
1402 tabs.setOrientation (TabbedButtonBar::TabsAtLeft);
1404 else if (result == 1004)
1406 tabs.setOrientation (TabbedButtonBar::TabsAtRight);
1410 void sliderValueChanged (Slider*)
1412 // When you move the rotation slider, we'll apply a rotaion transform to the whole tabs component..
1413 tabs.setTransform (AffineTransform::rotation ((float) (transformSlider.getValue() / (180.0 / double_Pi)),
1414 getWidth() * 0.5f, getHeight() * 0.5f));
1417 private:
1418 TextButton menuButton;
1419 ToggleButton enableButton;
1420 Slider transformSlider;
1421 DemoTabbedComponent tabs;
1425 //==============================================================================
1426 Component* createWidgetsDemo()
1428 return new WidgetsDemo();