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
,
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())
44 .withBrightness (0.7f
);
46 int size
= 10 + Random::getSystemRandom().nextInt (30);
52 ~BouncingBallComponent()
56 void paint (Graphics
& g
)
59 g
.fillEllipse (x
- getX(), y
- getY(), getWidth() - 2.0f
, getHeight() - 2.0f
);
70 if (x
> getParentWidth())
76 if (y
> getParentHeight())
79 setTopLeftPosition ((int) x
, (int) y
);
82 bool hitTest (int /*x*/, int /*y*/)
92 //==============================================================================
93 class DragOntoDesktopDemoComp
: public Component
96 DragOntoDesktopDemoComp (Component
* 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
)
119 delete this; // If our parent has been deleted, we'll just get rid of this component
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);
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
)
145 g
.fillAll (Colours::white
);
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");
152 g
.setColour (Colours::black
);
153 g
.drawFittedText (desc
, 4, 0, getWidth() - 8, getHeight(), Justification::horizontallyJustified
, 5);
155 g
.drawRect (0, 0, getWidth(), getHeight());
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
,
170 CustomMenuComponent()
174 // set off a timer to move a blob around on this component every
175 // 300 milliseconds - see the timerCallback() method.
179 ~CustomMenuComponent()
183 void getIdealSize (int& idealWidth
,
186 // tells the menu how big we'd like to be..
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);
208 blobX
= Random::getSystemRandom().nextInt (getWidth());
209 blobY
= Random::getSystemRandom().nextInt (getHeight());
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
224 SnappingSlider (const String
& 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)
237 return attemptedValue
;
241 /** A TextButton that pops up a colour chooser to change its colours. */
242 class ColourChangeButton
: public TextButton
,
243 public ChangeListener
247 : TextButton ("click to change colour...")
250 changeWidthToFitText();
253 ~ColourChangeButton()
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();
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
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!
303 //==============================================================================
304 static Component
* createSlidersPage()
306 DemoPageComp
* page
= new DemoPageComp();
308 const int numSliders
= 11;
309 Slider
* sliders
[numSliders
];
312 for (i
= 0; i
< numSliders
; ++i
)
315 page
->addAndMakeVisible (sliders
[i
] = new SnappingSlider ("slider"));
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
384 We could also optionally keep a copy of this Value elsewhere, and by changing it,
385 cause all the sliders to automatically update.
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
);
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
);
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");
430 tb
->setToggleState (true, false);
433 for (i
= 0; i
< 4; ++i
)
435 DrawablePath normal
, over
;
438 p
.addStar (Point
<float>(), i
+ 5, 20.0f
, 50.0f
, -0.2f
);
440 normal
.setFill (Colours::lightblue
);
441 normal
.setStrokeFill (Colours::black
);
442 normal
.setStrokeThickness (4.0f
);
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
);
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));
478 tb
->setToggleState (true, false);
484 //==============================================================================
485 class ButtonsPage
: public Component
,
486 public ButtonListener
489 ButtonsPage (ButtonListener
* buttonListener
)
491 //==============================================================================
492 // create some drawables to use for our drawable buttons...
493 DrawablePath normal
, over
;
496 p
.addStar (Point
<float>(), 5, 20.0f
, 50.0f
, 0.2f
);
498 normal
.setFill (Colours::red
);
501 p
.addStar (Point
<float>(), 7, 30.0f
, 50.0f
, 0.0f
);
503 over
.setFill (Colours::pink
);
504 over
.setStrokeFill (Colours::black
);
505 over
.setStrokeThickness (5.0f
);
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
),
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);
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!
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),
611 Random::getSystemRandom().nextDouble(),
612 Random::getSystemRandom().nextDouble());
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
);
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);
658 //==============================================================================
659 class ToolbarDemoComp
: public Component
,
660 public SliderListener
,
661 public ButtonListener
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());
708 if (toolbar
.isVertical())
709 toolbar
.setBounds (0, 0, (int) depthSlider
.getValue(), getHeight());
711 toolbar
.setBounds (0, 0, getWidth(), (int) depthSlider
.getValue());
714 void sliderValueChanged (Slider
*)
719 void buttonClicked (Button
* button
)
721 if (button
== &orientationButton
)
723 toolbar
.setVertical (! toolbar
.isVertical());
726 else if (button
== &customiseButton
)
728 toolbar
.showCustomisationDialog (factory
);
735 Label depthLabel
, infoLabel
;
736 TextButton orientationButton
, customiseButton
;
738 //==============================================================================
739 class DemoToolbarItemFactory
: public ToolbarItemFactory
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
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.
770 ids
.add (doc_saveAs
);
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
779 ids
.add (separatorBarId
);
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).
792 ids
.add (doc_saveAs
);
794 ids
.add (separatorBarId
);
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
)
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
);
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
857 class CustomToolbarComboBox
: public ToolbarItemComponent
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
)
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());
906 DemoToolbarItemFactory factory
;
909 //==============================================================================
910 class DemoTabbedComponent
: public TabbedComponent
,
911 public ButtonListener
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);
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.",
942 static const Colour
getRandomBrightColour()
944 return Colour (Random::getSystemRandom().nextFloat(), 0.1f
, 0.97f
, 1.0f
);
949 //==============================================================================
950 class DemoBackgroundThread
: public ThreadWithProgressWindow
953 DemoBackgroundThread()
954 : ThreadWithProgressWindow ("busy doing some important things...",
958 setStatusMessage ("Getting ready...");
963 setProgress (-1.0); // setting a value beyond the range 0 -> 1 will show a spinning bar..
964 setStatusMessage ("Preparing to do some stuff...");
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())
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...");
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!");
990 //==============================================================================
991 /** A DialogWindow containing a ColourSelector component */
992 class ColourSelectorDialogWindow
: public DialogWindow
995 ColourSelectorDialogWindow()
996 : DialogWindow ("Colour selector demo",
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.
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
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)..
1033 setMessage ("Couldn't open the remote control device!");
1036 ~AppleRemoteTestWindow()
1041 void buttonPressed (const ButtonType buttonId
, const bool isDown
)
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;
1061 desc
<< " -- [down]";
1071 //==============================================================================
1072 class WidgetsDemo
: public Component
,
1073 public ButtonListener
,
1074 public SliderListener
1077 //==============================================================================
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);
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
)
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
);
1133 m
.addCustomItem (5, new CustomMenuComponent());
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
);
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
);
1168 m
.addItem (120, "Show a colour selector demo...");
1172 m
.addItem (140, "Run the Apple Remote Control test...");
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
,
1211 "Result code: " + String (result
));
1214 void performDemoMenuItem (int result
)
1216 if (result
>= 100 && result
< 105)
1218 AlertWindow::AlertIconType icon
= AlertWindow::NoIcon
;
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.",
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.",
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");
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
,
1284 "Thread finished ok!");
1288 // user pressed the cancel button..
1289 AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon
,
1291 "You pressed cancel!");
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();
1305 else if (result
== 140)
1308 AppleRemoteTestWindow test
;
1309 test
.runModalLoop();
1312 else if (result
>= 121 && result
< 139)
1314 #if JUCE_MODAL_LOOPS_PERMITTED
1315 const bool useNativeVersion
= result
< 130;
1321 FileChooser
fc ("Choose a file to open...",
1322 File::getCurrentWorkingDirectory(),
1326 if (fc
.browseForMultipleFilesToOpen())
1329 for (int i
= 0; i
< fc
.getResults().size(); ++i
)
1330 chosen
<< fc
.getResults().getReference(i
).getFullPathName() << "\n";
1332 AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon
,
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",
1347 if (fc
.browseForMultipleFilesToOpen (&imagePreview
))
1350 for (int i
= 0; i
< fc
.getResults().size(); ++i
)
1351 chosen
<< fc
.getResults().getReference(i
).getFullPathName() << "\n";
1353 AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon
,
1355 "You picked: " + chosen
);
1358 else if (result
== 122)
1360 FileChooser
fc ("Choose a file to save...",
1361 File::getCurrentWorkingDirectory(),
1365 if (fc
.browseForFileToSave (true))
1367 File chosenFile
= fc
.getResult();
1369 AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon
,
1371 "You picked: " + chosenFile
.getFullPathName());
1374 else if (result
== 123)
1376 FileChooser
fc ("Choose a directory...",
1377 File::getCurrentWorkingDirectory(),
1381 if (fc
.browseForDirectory())
1383 File chosenDirectory
= fc
.getResult();
1385 AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon
,
1387 "You picked: " + chosenDirectory
.getFullPathName());
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
));
1418 TextButton menuButton
;
1419 ToggleButton enableButton
;
1420 Slider transformSlider
;
1421 DemoTabbedComponent tabs
;
1425 //==============================================================================
1426 Component
* createWidgetsDemo()
1428 return new WidgetsDemo();