The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1410 lines
54KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-9 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #include "../jucedemo_headers.h"
  19. //==============================================================================
  20. class BouncingBallComponent : public Component,
  21. public Timer
  22. {
  23. public:
  24. BouncingBallComponent()
  25. {
  26. Random random;
  27. const float size = 10.0f + random.nextInt (30);
  28. ballBounds.setBounds (random.nextFloat() * 100.0f,
  29. random.nextFloat() * 100.0f,
  30. size, size);
  31. direction.x = random.nextFloat() * 8.0f - 4.0f;
  32. direction.y = random.nextFloat() * 8.0f - 4.0f;
  33. colour = Colour (random.nextInt())
  34. .withAlpha (0.5f)
  35. .withBrightness (0.7f);
  36. startTimer (60);
  37. }
  38. void paint (Graphics& g)
  39. {
  40. g.setColour (colour);
  41. g.fillEllipse (ballBounds - getPosition().toFloat());
  42. }
  43. void timerCallback()
  44. {
  45. ballBounds += direction;
  46. if (ballBounds.getX() < 0) direction.x = fabsf (direction.x);
  47. if (ballBounds.getY() < 0) direction.y = fabsf (direction.y);
  48. if (ballBounds.getRight() > getParentWidth()) direction.x = -fabsf (direction.x);
  49. if (ballBounds.getBottom() > getParentHeight()) direction.y = -fabsf (direction.y);
  50. setBounds (ballBounds.getSmallestIntegerContainer());
  51. }
  52. bool hitTest (int /* x */, int /* y */)
  53. {
  54. return false;
  55. }
  56. private:
  57. Colour colour;
  58. Rectangle<float> ballBounds;
  59. Point<float> direction;
  60. };
  61. //==============================================================================
  62. class DragOntoDesktopDemoComp : public Component
  63. {
  64. public:
  65. DragOntoDesktopDemoComp (Component* p)
  66. : parent (p)
  67. {
  68. // show off semi-transparency if it's supported by the current OS.
  69. setOpaque (! Desktop::canUseSemiTransparentWindows());
  70. for (int i = 0; i < numElementsInArray (balls); ++i)
  71. addAndMakeVisible (&(balls[i]));
  72. }
  73. void mouseDown (const MouseEvent& e)
  74. {
  75. dragger.startDraggingComponent (this, e);
  76. }
  77. void mouseDrag (const MouseEvent& e)
  78. {
  79. if (parent == nullptr)
  80. {
  81. delete this; // If our parent has been deleted, we'll just get rid of this component
  82. }
  83. else
  84. {
  85. // if the mouse is inside the parent component, we'll make that the
  86. // parent - otherwise, we'll put this comp on the desktop.
  87. if (parent->getLocalBounds().contains (e.getEventRelativeTo (parent).getPosition()))
  88. {
  89. // re-add this component to a parent component, which will
  90. // remove it from the desktop..
  91. parent->addChildComponent (this);
  92. }
  93. else
  94. {
  95. // add the component to the desktop, which will remove it
  96. // from its current parent component..
  97. addToDesktop (ComponentPeer::windowIsTemporary);
  98. }
  99. dragger.dragComponent (this, e, 0);
  100. }
  101. }
  102. void paint (Graphics& g)
  103. {
  104. if (isOpaque())
  105. g.fillAll (Colours::white);
  106. else
  107. g.fillAll (Colours::blue.withAlpha (0.2f));
  108. g.setFont (15.0f);
  109. g.setColour (Colours::black);
  110. g.drawFittedText ("drag this box onto the desktop to show how the same component can move from being lightweight to being a separate window",
  111. getLocalBounds().reduced (4, 0),
  112. Justification::horizontallyJustified, 5);
  113. g.drawRect (getLocalBounds());
  114. }
  115. private:
  116. Component::SafePointer<Component> parent; // A safe-pointer will become null if the component that it refers to is deleted..
  117. ComponentDragger dragger;
  118. BouncingBallComponent balls[3];
  119. };
  120. //==============================================================================
  121. class CustomMenuComponent : public PopupMenu::CustomComponent,
  122. public Timer
  123. {
  124. public:
  125. CustomMenuComponent()
  126. {
  127. // set off a timer to move a blob around on this component every
  128. // 300 milliseconds - see the timerCallback() method.
  129. startTimer (300);
  130. }
  131. void getIdealSize (int& idealWidth,
  132. int& idealHeight)
  133. {
  134. // tells the menu how big we'd like to be..
  135. idealWidth = 200;
  136. idealHeight = 60;
  137. }
  138. void paint (Graphics& g)
  139. {
  140. g.fillAll (Colours::yellow.withAlpha (0.3f));
  141. g.setColour (Colours::pink);
  142. g.fillEllipse (blobPosition);
  143. g.setFont (Font (14.0f, Font::italic));
  144. g.setColour (Colours::black);
  145. g.drawFittedText ("this is a customised menu item (also demonstrating the Timer class)...",
  146. getLocalBounds().reduced (4, 0),
  147. Justification::centred, 3);
  148. }
  149. void timerCallback()
  150. {
  151. Random random;
  152. blobPosition.setBounds ((float) random.nextInt (getWidth()),
  153. (float) random.nextInt (getHeight()),
  154. 40.0f, 30.0f);
  155. repaint();
  156. }
  157. private:
  158. Rectangle<float> blobPosition;
  159. };
  160. //==============================================================================
  161. /** To demonstrate how sliders can have custom snapping applied to their values,
  162. this simple class snaps the value to 50 if it comes near.
  163. */
  164. class SnappingSlider : public Slider
  165. {
  166. public:
  167. SnappingSlider (const String& name)
  168. : Slider (name)
  169. {
  170. }
  171. double snapValue (double attemptedValue, bool userIsDragging)
  172. {
  173. if (! userIsDragging)
  174. return attemptedValue; // if they're entering the value in the text-box, don't mess with it.
  175. if (attemptedValue > 40 && attemptedValue < 60)
  176. return 50.0;
  177. else
  178. return attemptedValue;
  179. }
  180. };
  181. /** A TextButton that pops up a colour chooser to change its colours. */
  182. class ColourChangeButton : public TextButton,
  183. public ChangeListener
  184. {
  185. public:
  186. ColourChangeButton()
  187. : TextButton ("click to change colour...")
  188. {
  189. setSize (10, 24);
  190. changeWidthToFitText();
  191. }
  192. void clicked()
  193. {
  194. ColourSelector* colourSelector = new ColourSelector();
  195. colourSelector->setName ("background");
  196. colourSelector->setCurrentColour (findColour (TextButton::buttonColourId));
  197. colourSelector->addChangeListener (this);
  198. colourSelector->setColour (ColourSelector::backgroundColourId, Colours::transparentBlack);
  199. colourSelector->setSize (300, 400);
  200. CallOutBox::launchAsynchronously (colourSelector, getScreenBounds(), nullptr);
  201. }
  202. void changeListenerCallback (ChangeBroadcaster* source)
  203. {
  204. ColourSelector* cs = dynamic_cast <ColourSelector*> (source);
  205. setColour (TextButton::buttonColourId, cs->getCurrentColour());
  206. }
  207. };
  208. //==============================================================================
  209. /* A component to act as a simple container for our demos, which deletes all the child
  210. components that we stuff into it.
  211. */
  212. class DemoPageComp : public Component
  213. {
  214. public:
  215. DemoPageComp()
  216. {
  217. }
  218. ~DemoPageComp()
  219. {
  220. /* Deleting your child components indiscriminately using deleteAllChildren() is not recommended! It's much
  221. safer to make them embedded members or use ScopedPointers to automatically manage their lifetimes!
  222. In this demo, where we're throwing together a whole bunch of random components, it's simpler to do it
  223. like this, but don't treat this as an example of good practice!
  224. */
  225. deleteAllChildren();
  226. }
  227. };
  228. //==============================================================================
  229. static Component* createSlidersPage()
  230. {
  231. DemoPageComp* page = new DemoPageComp();
  232. const int numSliders = 11;
  233. Slider* sliders [numSliders];
  234. for (int i = 0; i < numSliders; ++i)
  235. {
  236. if (i == 2)
  237. page->addAndMakeVisible (sliders[i] = new SnappingSlider ("slider"));
  238. else
  239. page->addAndMakeVisible (sliders[i] = new Slider ("slider"));
  240. sliders[i]->setRange (0.0, 100.0, 0.1);
  241. sliders[i]->setPopupMenuEnabled (true);
  242. sliders[i]->setValue (Random::getSystemRandom().nextDouble() * 100.0, dontSendNotification);
  243. }
  244. sliders[0]->setSliderStyle (Slider::LinearVertical);
  245. sliders[0]->setTextBoxStyle (Slider::TextBoxBelow, false, 100, 20);
  246. sliders[0]->setBounds (10, 25, 70, 200);
  247. sliders[0]->setDoubleClickReturnValue (true, 50.0); // double-clicking this slider will set it to 50.0
  248. sliders[0]->setTextValueSuffix (" units");
  249. sliders[1]->setSliderStyle (Slider::LinearVertical);
  250. sliders[1]->setVelocityBasedMode (true);
  251. sliders[1]->setSkewFactor (0.5);
  252. sliders[1]->setTextBoxStyle (Slider::TextBoxAbove, true, 100, 20);
  253. sliders[1]->setBounds (85, 25, 70, 200);
  254. sliders[1]->setTextValueSuffix (" rels");
  255. sliders[2]->setSliderStyle (Slider::LinearHorizontal);
  256. sliders[2]->setTextBoxStyle (Slider::TextBoxLeft, false, 80, 20);
  257. sliders[2]->setBounds (180, 35, 150, 20);
  258. sliders[3]->setSliderStyle (Slider::LinearHorizontal);
  259. sliders[3]->setTextBoxStyle (Slider::NoTextBox, false, 0, 0);
  260. sliders[3]->setBounds (180, 65, 150, 20);
  261. sliders[3]->setPopupDisplayEnabled (true, page);
  262. sliders[3]->setTextValueSuffix (" nuns required to change a lightbulb");
  263. sliders[4]->setSliderStyle (Slider::IncDecButtons);
  264. sliders[4]->setTextBoxStyle (Slider::TextBoxLeft, false, 50, 20);
  265. sliders[4]->setBounds (180, 105, 100, 20);
  266. sliders[4]->setIncDecButtonsMode (Slider::incDecButtonsDraggable_Vertical);
  267. sliders[5]->setSliderStyle (Slider::Rotary);
  268. sliders[5]->setRotaryParameters (float_Pi * 1.2f, float_Pi * 2.8f, false);
  269. sliders[5]->setTextBoxStyle (Slider::TextBoxRight, false, 70, 20);
  270. sliders[5]->setBounds (190, 145, 120, 40);
  271. sliders[5]->setTextValueSuffix (" mm");
  272. sliders[6]->setSliderStyle (Slider::LinearBar);
  273. sliders[6]->setBounds (180, 195, 100, 30);
  274. sliders[6]->setTextValueSuffix (" gallons");
  275. sliders[7]->setSliderStyle (Slider::TwoValueHorizontal);
  276. sliders[7]->setBounds (360, 20, 160, 40);
  277. sliders[8]->setSliderStyle (Slider::TwoValueVertical);
  278. sliders[8]->setBounds (360, 110, 40, 160);
  279. sliders[9]->setSliderStyle (Slider::ThreeValueHorizontal);
  280. sliders[9]->setBounds (360, 70, 160, 40);
  281. sliders[10]->setSliderStyle (Slider::ThreeValueVertical);
  282. sliders[10]->setBounds (440, 110, 40, 160);
  283. for (int i = 7; i <= 10; ++i)
  284. {
  285. sliders[i]->setTextBoxStyle (Slider::NoTextBox, false, 0, 0);
  286. sliders[i]->setPopupDisplayEnabled (true, page);
  287. }
  288. /* Here, we'll create a Value object, and tell a bunch of our sliders to use it as their
  289. value source. By telling them all to share the same Value, they'll stay in sync with
  290. each other.
  291. We could also optionally keep a copy of this Value elsewhere, and by changing it,
  292. cause all the sliders to automatically update.
  293. */
  294. Value sharedValue;
  295. sharedValue = Random::getSystemRandom().nextDouble() * 100;
  296. for (int i = 0; i < 7; ++i)
  297. sliders[i]->getValueObject().referTo (sharedValue);
  298. // ..and now we'll do the same for all our min/max slider values..
  299. Value sharedValueMin, sharedValueMax;
  300. sharedValueMin = Random::getSystemRandom().nextDouble() * 40.0;
  301. sharedValueMax = Random::getSystemRandom().nextDouble() * 40.0 + 60.0;
  302. for (int i = 7; i <= 10; ++i)
  303. {
  304. sliders[i]->getMaxValueObject().referTo (sharedValueMax);
  305. sliders[i]->getMinValueObject().referTo (sharedValueMin);
  306. }
  307. // Create a description label...
  308. 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");
  309. label->setBounds (20, 245, 350, 150);
  310. page->addAndMakeVisible (label);
  311. return page;
  312. }
  313. //==============================================================================
  314. static Component* createRadioButtonPage()
  315. {
  316. DemoPageComp* page = new DemoPageComp();
  317. GroupComponent* group = new GroupComponent ("group", "radio buttons");
  318. group->setBounds (20, 20, 220, 140);
  319. page->addAndMakeVisible (group);
  320. for (int i = 0; i < 4; ++i)
  321. {
  322. ToggleButton* tb = new ToggleButton ("radio button #" + String (i + 1));
  323. page->addAndMakeVisible (tb);
  324. tb->setRadioGroupId (1234);
  325. tb->setBounds (45, 46 + i * 22, 180, 22);
  326. tb->setTooltip ("a set of mutually-exclusive radio buttons");
  327. if (i == 0)
  328. tb->setToggleState (true, false);
  329. }
  330. for (int i = 0; i < 4; ++i)
  331. {
  332. DrawablePath normal, over;
  333. Path p;
  334. p.addStar (Point<float>(), i + 5, 20.0f, 50.0f, -0.2f);
  335. normal.setPath (p);
  336. normal.setFill (Colours::lightblue);
  337. normal.setStrokeFill (Colours::black);
  338. normal.setStrokeThickness (4.0f);
  339. over.setPath (p);
  340. over.setFill (Colours::blue);
  341. over.setStrokeFill (Colours::black);
  342. over.setStrokeThickness (4.0f);
  343. DrawableButton* db = new DrawableButton (String (i + 5) + " points", DrawableButton::ImageAboveTextLabel);
  344. db->setImages (&normal, &over, 0);
  345. page->addAndMakeVisible (db);
  346. db->setClickingTogglesState (true);
  347. db->setRadioGroupId (23456);
  348. const int buttonSize = 50;
  349. db->setBounds (25 + i * buttonSize, 180, buttonSize, buttonSize);
  350. if (i == 0)
  351. db->setToggleState (true, false);
  352. }
  353. for (int i = 0; i < 4; ++i)
  354. {
  355. TextButton* tb = new TextButton ("button " + String (i + 1));
  356. page->addAndMakeVisible (tb);
  357. tb->setClickingTogglesState (true);
  358. tb->setRadioGroupId (34567);
  359. tb->setColour (TextButton::buttonColourId, Colours::white);
  360. tb->setColour (TextButton::buttonOnColourId, Colours::blueviolet.brighter());
  361. tb->setBounds (20 + i * 55, 260, 55, 24);
  362. tb->setConnectedEdges (((i != 0) ? Button::ConnectedOnLeft : 0)
  363. | ((i != 3) ? Button::ConnectedOnRight : 0));
  364. if (i == 0)
  365. tb->setToggleState (true, false);
  366. }
  367. return page;
  368. }
  369. //==============================================================================
  370. class ButtonsPage : public Component,
  371. public ButtonListener
  372. {
  373. public:
  374. ButtonsPage (ButtonListener* buttonListener)
  375. {
  376. //==============================================================================
  377. // create some drawables to use for our drawable buttons...
  378. DrawablePath normal, over;
  379. Path p;
  380. p.addStar (Point<float>(), 5, 20.0f, 50.0f, 0.2f);
  381. normal.setPath (p);
  382. normal.setFill (Colours::red);
  383. p.clear();
  384. p.addStar (Point<float>(), 7, 30.0f, 50.0f, 0.0f);
  385. over.setPath (p);
  386. over.setFill (Colours::pink);
  387. over.setStrokeFill (Colours::black);
  388. over.setStrokeThickness (5.0f);
  389. DrawableImage down;
  390. down.setImage (ImageCache::getFromMemory (BinaryData::juce_png, BinaryData::juce_pngSize));
  391. down.setOverlayColour (Colours::black.withAlpha (0.3f));
  392. //==============================================================================
  393. // create an image-above-text button from these drawables..
  394. DrawableButton* db = new DrawableButton ("Button 1", DrawableButton::ImageAboveTextLabel);
  395. db->setImages (&normal, &over, &down);
  396. db->setBounds (10, 30, 80, 80);
  397. db->setTooltip ("this is a DrawableButton with a label");
  398. addAndMakeVisible (db);
  399. //==============================================================================
  400. // create an image-only button from these drawables..
  401. db = new DrawableButton ("Button 2", DrawableButton::ImageFitted);
  402. db->setImages (&normal, &over, &down);
  403. db->setClickingTogglesState (true);
  404. db->setBounds (90, 30, 80, 80);
  405. db->setTooltip ("this is an image-only DrawableButton");
  406. db->addListener (buttonListener);
  407. addAndMakeVisible (db);
  408. //==============================================================================
  409. // create an image-on-button-shape button from the same drawables..
  410. db = new DrawableButton ("Button 3", DrawableButton::ImageOnButtonBackground);
  411. db->setImages (&normal, 0, 0);
  412. db->setBounds (200, 30, 110, 25);
  413. db->setTooltip ("this is a DrawableButton on a standard button background");
  414. addAndMakeVisible (db);
  415. //==============================================================================
  416. db = new DrawableButton ("Button 4", DrawableButton::ImageOnButtonBackground);
  417. db->setImages (&normal, &over, &down);
  418. db->setClickingTogglesState (true);
  419. db->setColour (DrawableButton::backgroundColourId, Colours::white);
  420. db->setColour (DrawableButton::backgroundOnColourId, Colours::yellow);
  421. db->setBounds (200, 70, 50, 50);
  422. db->setTooltip ("this is a DrawableButton on a standard button background");
  423. db->addListener (buttonListener);
  424. addAndMakeVisible (db);
  425. //==============================================================================
  426. HyperlinkButton* hyperlink
  427. = new HyperlinkButton ("this is a HyperlinkButton",
  428. URL ("http://www.rawmaterialsoftware.com/juce"));
  429. hyperlink->setBounds (10, 130, 200, 24);
  430. addAndMakeVisible (hyperlink);
  431. //==============================================================================
  432. ImageButton* imageButton = new ImageButton ("imagebutton");
  433. addAndMakeVisible (imageButton);
  434. Image juceImage = ImageCache::getFromMemory (BinaryData::juce_png, BinaryData::juce_pngSize);
  435. imageButton->setImages (true, true, true,
  436. juceImage, 0.7f, Colours::transparentBlack,
  437. juceImage, 1.0f, Colours::transparentBlack,
  438. juceImage, 1.0f, Colours::pink.withAlpha (0.8f),
  439. 0.5f);
  440. imageButton->setTopLeftPosition (10, 160);
  441. imageButton->setTooltip ("image button - showing alpha-channel hit-testing and colour overlay when clicked");
  442. //==============================================================================
  443. ColourChangeButton* colourChangeButton = new ColourChangeButton();
  444. addAndMakeVisible (colourChangeButton);
  445. colourChangeButton->setTopLeftPosition (350, 30);
  446. //==============================================================================
  447. animateButton = new TextButton ("click to animate...");
  448. animateButton->changeWidthToFitText (24);
  449. animateButton->setTopLeftPosition (350, 70);
  450. animateButton->addListener (this);
  451. addAndMakeVisible (animateButton);
  452. }
  453. ~ButtonsPage()
  454. {
  455. /* Deleting your child components indiscriminately using deleteAllChildren() is not recommended! It's much
  456. safer to make them embedded members or use ScopedPointers to automatically manage their lifetimes!
  457. In this demo, where we're throwing together a whole bunch of random components, it's simpler to do it
  458. like this, but don't treat this as an example of good practice!
  459. */
  460. deleteAllChildren();
  461. }
  462. void buttonClicked (Button*)
  463. {
  464. for (int i = getNumChildComponents(); --i >= 0;)
  465. {
  466. if (getChildComponent (i) != animateButton)
  467. {
  468. animator.animateComponent (getChildComponent (i),
  469. Rectangle<int> (Random::getSystemRandom().nextInt (getWidth() / 2),
  470. Random::getSystemRandom().nextInt (getHeight() / 2),
  471. 60 + Random::getSystemRandom().nextInt (getWidth() / 3),
  472. 16 + Random::getSystemRandom().nextInt (getHeight() / 6)),
  473. Random::getSystemRandom().nextFloat(),
  474. 500 + Random::getSystemRandom().nextInt (2000),
  475. false,
  476. Random::getSystemRandom().nextDouble(),
  477. Random::getSystemRandom().nextDouble());
  478. }
  479. }
  480. }
  481. private:
  482. TextButton* animateButton;
  483. ComponentAnimator animator;
  484. };
  485. //==============================================================================
  486. static Component* createMiscPage()
  487. {
  488. DemoPageComp* page = new DemoPageComp();
  489. TextEditor* textEditor1 = new TextEditor();
  490. page->addAndMakeVisible (textEditor1);
  491. textEditor1->setBounds (10, 25, 200, 24);
  492. textEditor1->setText ("single-line text box");
  493. TextEditor* textEditor2 = new TextEditor ("password", (juce_wchar) 0x2022);
  494. page->addAndMakeVisible (textEditor2);
  495. textEditor2->setBounds (10, 55, 200, 24);
  496. textEditor2->setText ("password");
  497. //==============================================================================
  498. ComboBox* comboBox = new ComboBox ("combo");
  499. page->addAndMakeVisible (comboBox);
  500. comboBox->setBounds (300, 25, 200, 24);
  501. comboBox->setEditableText (true);
  502. comboBox->setJustificationType (Justification::centred);
  503. for (int i = 1; i < 100; ++i)
  504. comboBox->addItem ("combo box item " + String (i), i);
  505. comboBox->setSelectedId (1);
  506. DragOntoDesktopDemoComp* d = new DragOntoDesktopDemoComp (page);
  507. page->addAndMakeVisible (d);
  508. d->setBounds (20, 100, 200, 80);
  509. return page;
  510. }
  511. //==============================================================================
  512. class ToolbarDemoComp : public Component,
  513. public SliderListener,
  514. public ButtonListener
  515. {
  516. public:
  517. ToolbarDemoComp()
  518. : depthLabel (String::empty, "Toolbar depth:"),
  519. infoLabel (String::empty, "As well as showing off toolbars, this demo illustrates how to store "
  520. "a set of SVG files in a Zip file, embed that in your application, and read "
  521. "them back in at runtime.\n\nThe icon images here are taken from the open-source "
  522. "Tango icon project."),
  523. orientationButton ("Vertical/Horizontal"),
  524. customiseButton ("Customise...")
  525. {
  526. // Create and add the toolbar...
  527. addAndMakeVisible (&toolbar);
  528. // And use our item factory to add a set of default icons to it...
  529. toolbar.addDefaultItems (factory);
  530. // Now we'll just create the other sliders and buttons on the demo page, which adjust
  531. // the toolbar's properties...
  532. addAndMakeVisible (&infoLabel);
  533. infoLabel.setJustificationType (Justification::topLeft);
  534. infoLabel.setBounds (80, 80, 450, 100);
  535. infoLabel.setInterceptsMouseClicks (false, false);
  536. addAndMakeVisible (&depthSlider);
  537. depthSlider.setRange (10.0, 200.0, 1.0);
  538. depthSlider.setValue (50, dontSendNotification);
  539. depthSlider.setSliderStyle (Slider::LinearHorizontal);
  540. depthSlider.setTextBoxStyle (Slider::TextBoxLeft, false, 80, 20);
  541. depthSlider.addListener (this);
  542. depthSlider.setBounds (80, 210, 300, 22);
  543. depthLabel.attachToComponent (&depthSlider, false);
  544. addAndMakeVisible (&orientationButton);
  545. orientationButton.addListener (this);
  546. orientationButton.changeWidthToFitText (22);
  547. orientationButton.setTopLeftPosition (depthSlider.getX(), depthSlider.getBottom() + 20);
  548. addAndMakeVisible (&customiseButton);
  549. customiseButton.addListener (this);
  550. customiseButton.changeWidthToFitText (22);
  551. customiseButton.setTopLeftPosition (orientationButton.getRight() + 20, orientationButton.getY());
  552. }
  553. void resized()
  554. {
  555. int toolbarThickness = (int) depthSlider.getValue();
  556. if (toolbar.isVertical())
  557. toolbar.setBounds (getLocalBounds().removeFromLeft (toolbarThickness));
  558. else
  559. toolbar.setBounds (getLocalBounds().removeFromTop (toolbarThickness));
  560. }
  561. void sliderValueChanged (Slider*)
  562. {
  563. resized();
  564. }
  565. void buttonClicked (Button* button)
  566. {
  567. if (button == &orientationButton)
  568. {
  569. toolbar.setVertical (! toolbar.isVertical());
  570. resized();
  571. }
  572. else if (button == &customiseButton)
  573. {
  574. toolbar.showCustomisationDialog (factory);
  575. }
  576. }
  577. private:
  578. Toolbar toolbar;
  579. Slider depthSlider;
  580. Label depthLabel, infoLabel;
  581. TextButton orientationButton, customiseButton;
  582. //==============================================================================
  583. class DemoToolbarItemFactory : public ToolbarItemFactory
  584. {
  585. public:
  586. DemoToolbarItemFactory() {}
  587. //==============================================================================
  588. // Each type of item a toolbar can contain must be given a unique ID. These
  589. // are the ones we'll use in this demo.
  590. enum DemoToolbarItemIds
  591. {
  592. doc_new = 1,
  593. doc_open = 2,
  594. doc_save = 3,
  595. doc_saveAs = 4,
  596. edit_copy = 5,
  597. edit_cut = 6,
  598. edit_paste = 7,
  599. juceLogoButton = 8,
  600. customComboBox = 9
  601. };
  602. void getAllToolbarItemIds (Array <int>& ids)
  603. {
  604. // This returns the complete list of all item IDs that are allowed to
  605. // go in our toolbar. Any items you might want to add must be listed here. The
  606. // order in which they are listed will be used by the toolbar customisation panel.
  607. ids.add (doc_new);
  608. ids.add (doc_open);
  609. ids.add (doc_save);
  610. ids.add (doc_saveAs);
  611. ids.add (edit_copy);
  612. ids.add (edit_cut);
  613. ids.add (edit_paste);
  614. ids.add (juceLogoButton);
  615. ids.add (customComboBox);
  616. // If you're going to use separators, then they must also be added explicitly
  617. // to the list.
  618. ids.add (separatorBarId);
  619. ids.add (spacerId);
  620. ids.add (flexibleSpacerId);
  621. }
  622. void getDefaultItemSet (Array <int>& ids)
  623. {
  624. // This returns an ordered list of the set of items that make up a
  625. // toolbar's default set. Not all items need to be on this list, and
  626. // items can appear multiple times (e.g. the separators used here).
  627. ids.add (doc_new);
  628. ids.add (doc_open);
  629. ids.add (doc_save);
  630. ids.add (doc_saveAs);
  631. ids.add (spacerId);
  632. ids.add (separatorBarId);
  633. ids.add (edit_copy);
  634. ids.add (edit_cut);
  635. ids.add (edit_paste);
  636. ids.add (separatorBarId);
  637. ids.add (flexibleSpacerId);
  638. ids.add (customComboBox);
  639. ids.add (flexibleSpacerId);
  640. ids.add (separatorBarId);
  641. ids.add (juceLogoButton);
  642. }
  643. ToolbarItemComponent* createItem (int itemId)
  644. {
  645. switch (itemId)
  646. {
  647. case doc_new: return createButtonFromZipFileSVG (itemId, "new", "document-new.svg");
  648. case doc_open: return createButtonFromZipFileSVG (itemId, "open", "document-open.svg");
  649. case doc_save: return createButtonFromZipFileSVG (itemId, "save", "document-save.svg");
  650. case doc_saveAs: return createButtonFromZipFileSVG (itemId, "save as", "document-save-as.svg");
  651. case edit_copy: return createButtonFromZipFileSVG (itemId, "copy", "edit-copy.svg");
  652. case edit_cut: return createButtonFromZipFileSVG (itemId, "cut", "edit-cut.svg");
  653. case edit_paste: return createButtonFromZipFileSVG (itemId, "paste", "edit-paste.svg");
  654. case juceLogoButton: return new ToolbarButton (itemId, "juce!", Drawable::createFromImageData (BinaryData::juce_png, BinaryData::juce_pngSize), 0);
  655. case customComboBox: return new CustomToolbarComboBox (itemId);
  656. default: break;
  657. }
  658. return 0;
  659. }
  660. private:
  661. StringArray iconNames;
  662. OwnedArray <Drawable> iconsFromZipFile;
  663. // This is a little utility to create a button with one of the SVG images in
  664. // our embedded ZIP file "icons.zip"
  665. ToolbarButton* createButtonFromZipFileSVG (const int itemId, const String& text, const String& filename)
  666. {
  667. if (iconsFromZipFile.size() == 0)
  668. {
  669. // If we've not already done so, load all the images from the zip file..
  670. MemoryInputStream iconsFileStream (BinaryData::icons_zip, BinaryData::icons_zipSize, false);
  671. ZipFile icons (&iconsFileStream, false);
  672. for (int i = 0; i < icons.getNumEntries(); ++i)
  673. {
  674. ScopedPointer<InputStream> svgFileStream (icons.createStreamForEntry (i));
  675. if (svgFileStream != 0)
  676. {
  677. iconNames.add (icons.getEntry(i)->filename);
  678. iconsFromZipFile.add (Drawable::createFromImageDataStream (*svgFileStream));
  679. }
  680. }
  681. }
  682. Drawable* image = iconsFromZipFile [iconNames.indexOf (filename)]->createCopy();
  683. return new ToolbarButton (itemId, text, image, 0);
  684. }
  685. // Demonstrates how to put a custom component into a toolbar - this one contains
  686. // a ComboBox.
  687. class CustomToolbarComboBox : public ToolbarItemComponent
  688. {
  689. public:
  690. CustomToolbarComboBox (const int toolbarItemId)
  691. : ToolbarItemComponent (toolbarItemId, "Custom Toolbar Item", false),
  692. comboBox ("demo toolbar combo box")
  693. {
  694. addAndMakeVisible (&comboBox);
  695. for (int i = 1; i < 20; ++i)
  696. comboBox.addItem ("Toolbar ComboBox item " + String (i), i);
  697. comboBox.setSelectedId (1);
  698. comboBox.setEditableText (true);
  699. }
  700. bool getToolbarItemSizes (int /*toolbarDepth*/, bool isToolbarVertical,
  701. int& preferredSize, int& minSize, int& maxSize)
  702. {
  703. if (isToolbarVertical)
  704. return false;
  705. preferredSize = 250;
  706. minSize = 80;
  707. maxSize = 300;
  708. return true;
  709. }
  710. void paintButtonArea (Graphics&, int, int, bool, bool)
  711. {
  712. }
  713. void contentAreaChanged (const Rectangle<int>& contentArea)
  714. {
  715. comboBox.setSize (contentArea.getWidth() - 2,
  716. jmin (contentArea.getHeight() - 2, 22));
  717. comboBox.setCentrePosition (contentArea.getCentreX(), contentArea.getCentreY());
  718. }
  719. private:
  720. ComboBox comboBox;
  721. };
  722. };
  723. DemoToolbarItemFactory factory;
  724. };
  725. //==============================================================================
  726. class DemoTabbedComponent : public TabbedComponent,
  727. public ButtonListener
  728. {
  729. public:
  730. DemoTabbedComponent()
  731. : TabbedComponent (TabbedButtonBar::TabsAtTop)
  732. {
  733. addTab ("sliders", getRandomBrightColour(), createSlidersPage(), true);
  734. addTab ("toolbars", getRandomBrightColour(), new ToolbarDemoComp(), true);
  735. addTab ("buttons", getRandomBrightColour(), new ButtonsPage (this), true);
  736. addTab ("radio buttons", getRandomBrightColour(), createRadioButtonPage(), true);
  737. addTab ("misc widgets", getRandomBrightColour(), createMiscPage(), true);
  738. getTabbedButtonBar().getTabButton (2)->setExtraComponent (new CustomTabButton(), TabBarButton::afterText);
  739. }
  740. void buttonClicked (Button* button)
  741. {
  742. showBubbleMessage (button,
  743. "This is a demo of the BubbleMessageComponent, which lets you pop up a message pointing "
  744. "at a component or somewhere on the screen.\n\n"
  745. "The message bubbles will disappear after a timeout period, or when the mouse is clicked.");
  746. }
  747. void showBubbleMessage (Component* targetComponent, const String& textToShow)
  748. {
  749. BubbleMessageComponent* bmc = new BubbleMessageComponent();
  750. if (Desktop::canUseSemiTransparentWindows())
  751. {
  752. bmc->setAlwaysOnTop (true);
  753. bmc->addToDesktop (0);
  754. }
  755. else
  756. {
  757. addChildComponent (bmc);
  758. }
  759. AttributedString text (textToShow);
  760. text.setJustification (Justification::centred);
  761. bmc->showAt (targetComponent, text, 2000, true, true);
  762. }
  763. static const Colour getRandomBrightColour()
  764. {
  765. return Colour (Random::getSystemRandom().nextFloat(), 0.1f, 0.97f, 1.0f);
  766. }
  767. // This is a small star button that is put inside one of the tabs. You can
  768. // use this technique to create things like "close tab" buttons, etc.
  769. class CustomTabButton : public Component
  770. {
  771. public:
  772. CustomTabButton()
  773. {
  774. setSize (20, 20);
  775. }
  776. void paint (Graphics& g)
  777. {
  778. Path p;
  779. p.addStar (Point<float>(), 7, 1.0f, 2.0f);
  780. g.setColour (Colours::green);
  781. g.fillPath (p, RectanglePlacement (RectanglePlacement::centred)
  782. .getTransformToFit (p.getBounds(), getLocalBounds().reduced (2).toFloat()));
  783. }
  784. void mouseDown (const MouseEvent&)
  785. {
  786. DemoTabbedComponent* dtc = findParentComponentOfClass<DemoTabbedComponent>();
  787. dtc->showBubbleMessage (this, "This is a custom tab component");
  788. }
  789. };
  790. };
  791. //==============================================================================
  792. class DemoBackgroundThread : public ThreadWithProgressWindow
  793. {
  794. public:
  795. DemoBackgroundThread()
  796. : ThreadWithProgressWindow ("busy doing some important things...",
  797. true,
  798. true)
  799. {
  800. setStatusMessage ("Getting ready...");
  801. }
  802. void run()
  803. {
  804. setProgress (-1.0); // setting a value beyond the range 0 -> 1 will show a spinning bar..
  805. setStatusMessage ("Preparing to do some stuff...");
  806. wait (2000);
  807. const int thingsToDo = 10;
  808. for (int i = 0; i < thingsToDo; ++i)
  809. {
  810. // must check this as often as possible, because this is
  811. // how we know if the user's pressed 'cancel'
  812. if (threadShouldExit())
  813. return;
  814. // this will update the progress bar on the dialog box
  815. setProgress (i / (double) thingsToDo);
  816. setStatusMessage (String (thingsToDo - i) + " things left to do...");
  817. wait (500);
  818. }
  819. setProgress (-1.0); // setting a value beyond the range 0 -> 1 will show a spinning bar..
  820. setStatusMessage ("Finishing off the last few bits and pieces!");
  821. wait (2000);
  822. }
  823. };
  824. #if JUCE_MAC
  825. //==============================================================================
  826. /** This pops open a dialog box and waits for you to press keys on your Apple Remote,
  827. which it describes in the box.
  828. */
  829. class AppleRemoteTestWindow : public AlertWindow,
  830. public AppleRemoteDevice
  831. {
  832. public:
  833. AppleRemoteTestWindow()
  834. : AlertWindow ("Apple Remote Control Test!",
  835. "If you've got an Apple Remote, press some buttons now...",
  836. AlertWindow::NoIcon)
  837. {
  838. addButton ("done", 0);
  839. // (To open the device in non-exclusive mode, pass 'false' in here)..
  840. if (! start (true))
  841. setMessage ("Couldn't open the remote control device!");
  842. }
  843. ~AppleRemoteTestWindow()
  844. {
  845. stop();
  846. }
  847. void buttonPressed (const ButtonType buttonId, const bool isDown)
  848. {
  849. setMessage (getDescriptionOfButtonType (buttonId) + (isDown ? " -- [down]"
  850. : " -- [up]"));
  851. }
  852. static String getDescriptionOfButtonType (const ButtonType type)
  853. {
  854. switch (type)
  855. {
  856. case menuButton: return "menu button (short)";
  857. case playButton: return "play button";
  858. case plusButton: return "plus button";
  859. case minusButton: return "minus button";
  860. case rightButton: return "right button (short)";
  861. case leftButton: return "left button (short)";
  862. case rightButton_Long: return "right button (long)";
  863. case leftButton_Long: return "left button (long)";
  864. case menuButton_Long: return "menu button (long)";
  865. case playButtonSleepMode: return "play (sleep mode)";
  866. case switched: return "remote switched";
  867. default: return "unknown";
  868. }
  869. }
  870. };
  871. #endif
  872. //==============================================================================
  873. class WidgetsDemo : public Component,
  874. public ButtonListener,
  875. public SliderListener
  876. {
  877. public:
  878. //==============================================================================
  879. WidgetsDemo()
  880. : menuButton ("click for a popup menu..",
  881. "click for a demo of the different types of item you can put into a popup menu..."),
  882. enableButton ("enable/disable components")
  883. {
  884. setName ("Widgets");
  885. addAndMakeVisible (&tabs);
  886. //==============================================================================
  887. addAndMakeVisible (&menuButton);
  888. menuButton.setBounds (10, 10, 200, 24);
  889. menuButton.addListener (this);
  890. menuButton.setTriggeredOnMouseDown (true); // because this button pops up a menu, this lets us
  891. // hold down the button and drag straight onto the menu
  892. //==============================================================================
  893. addAndMakeVisible (&enableButton);
  894. enableButton.setBounds (230, 10, 180, 24);
  895. enableButton.setTooltip ("Enables/disables all the components");
  896. enableButton.setToggleState (true, false);
  897. enableButton.addListener (this);
  898. addAndMakeVisible (&transformSlider);
  899. transformSlider.setSliderStyle (Slider::LinearBar);
  900. transformSlider.setTextValueSuffix (" degrees rotation");
  901. transformSlider.setRange (-180.0, 180.0, 0.1);
  902. transformSlider.setBounds (440, 10, 180, 24);
  903. transformSlider.setTooltip ("Applies a transform to the components");
  904. transformSlider.addListener (this);
  905. }
  906. ~WidgetsDemo()
  907. {
  908. PopupMenu::dismissAllActiveMenus();
  909. }
  910. void resized()
  911. {
  912. tabs.setBounds (10, 40, getWidth() - 20, getHeight() - 50);
  913. }
  914. //==============================================================================
  915. void buttonClicked (Button* button)
  916. {
  917. if (button == &enableButton)
  918. {
  919. const bool enabled = enableButton.getToggleState();
  920. menuButton.setEnabled (enabled);
  921. tabs.setEnabled (enabled);
  922. }
  923. else if (button == &menuButton)
  924. {
  925. PopupMenu m;
  926. m.addItem (1, "Normal item");
  927. m.addItem (2, "Disabled item", false);
  928. m.addItem (3, "Ticked item", true, true);
  929. m.addColouredItem (4, "Coloured item", Colours::green);
  930. m.addSeparator();
  931. m.addCustomItem (5, new CustomMenuComponent());
  932. m.addSeparator();
  933. PopupMenu tabsMenu;
  934. tabsMenu.addItem (1001, "Show tabs at the top", true, tabs.getOrientation() == TabbedButtonBar::TabsAtTop);
  935. tabsMenu.addItem (1002, "Show tabs at the bottom", true, tabs.getOrientation() == TabbedButtonBar::TabsAtBottom);
  936. tabsMenu.addItem (1003, "Show tabs at the left", true, tabs.getOrientation() == TabbedButtonBar::TabsAtLeft);
  937. tabsMenu.addItem (1004, "Show tabs at the right", true, tabs.getOrientation() == TabbedButtonBar::TabsAtRight);
  938. m.addSubMenu ("Tab position", tabsMenu);
  939. m.addSeparator();
  940. PopupMenu dialogMenu;
  941. dialogMenu.addItem (100, "Show a plain alert-window...");
  942. dialogMenu.addItem (101, "Show an alert-window with a 'warning' icon...");
  943. dialogMenu.addItem (102, "Show an alert-window with an 'info' icon...");
  944. dialogMenu.addItem (103, "Show an alert-window with a 'question' icon...");
  945. dialogMenu.addSeparator();
  946. dialogMenu.addItem (110, "Show an ok/cancel alert-window...");
  947. dialogMenu.addSeparator();
  948. dialogMenu.addItem (111, "Show an alert-window with some extra components...");
  949. dialogMenu.addSeparator();
  950. dialogMenu.addItem (112, "Show a ThreadWithProgressWindow demo...");
  951. m.addSubMenu ("AlertWindow demonstrations", dialogMenu);
  952. m.addSeparator();
  953. m.addItem (120, "Show a colour selector demo...");
  954. m.addSeparator();
  955. #if JUCE_MAC
  956. m.addItem (140, "Run the Apple Remote Control test...");
  957. m.addSeparator();
  958. #endif
  959. PopupMenu nativeFileChoosers;
  960. nativeFileChoosers.addItem (121, "'Load' file browser...");
  961. nativeFileChoosers.addItem (124, "'Load' file browser with an image file preview...");
  962. nativeFileChoosers.addItem (122, "'Save' file browser...");
  963. nativeFileChoosers.addItem (123, "'Choose directory' file browser...");
  964. PopupMenu juceFileChoosers;
  965. juceFileChoosers.addItem (131, "'Load' file browser...");
  966. juceFileChoosers.addItem (134, "'Load' file browser with an image file preview...");
  967. juceFileChoosers.addItem (132, "'Save' file browser...");
  968. juceFileChoosers.addItem (133, "'Choose directory' file browser...");
  969. PopupMenu fileChoosers;
  970. fileChoosers.addSubMenu ("Operating system dialogs", nativeFileChoosers);
  971. fileChoosers.addSubMenu ("Juce dialogs", juceFileChoosers);
  972. m.addSubMenu ("File chooser dialogs", fileChoosers);
  973. m.showMenuAsync (PopupMenu::Options().withTargetComponent (&menuButton),
  974. ModalCallbackFunction::forComponent (menuItemChosenCallback, this));
  975. }
  976. }
  977. //==============================================================================
  978. // This gets called when our popup menu has an item selected or is dismissed.
  979. static void menuItemChosenCallback (int result, WidgetsDemo* demoComponent)
  980. {
  981. if (result != 0 && demoComponent != 0)
  982. demoComponent->performDemoMenuItem (result);
  983. }
  984. static void alertBoxResultChosen (int result, WidgetsDemo*)
  985. {
  986. AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
  987. "Alert Box",
  988. "Result code: " + String (result));
  989. }
  990. void performDemoMenuItem (int result)
  991. {
  992. if (result >= 100 && result < 105)
  993. {
  994. AlertWindow::AlertIconType icon = AlertWindow::NoIcon;
  995. switch (result)
  996. {
  997. case 101: icon = AlertWindow::WarningIcon; break;
  998. case 102: icon = AlertWindow::InfoIcon; break;
  999. case 103: icon = AlertWindow::QuestionIcon; break;
  1000. }
  1001. AlertWindow::showMessageBoxAsync (icon,
  1002. "This is an AlertWindow",
  1003. "And this is the AlertWindow's message. Blah blah blah blah blah blah blah blah blah blah blah blah blah.",
  1004. "ok");
  1005. }
  1006. else if (result == 110)
  1007. {
  1008. AlertWindow::showOkCancelBox (AlertWindow::QuestionIcon,
  1009. "This is an ok/cancel AlertWindow",
  1010. "And this is the AlertWindow's message. Blah blah blah blah blah blah blah blah blah blah blah blah blah.",
  1011. String::empty,
  1012. String::empty,
  1013. 0,
  1014. ModalCallbackFunction::forComponent (alertBoxResultChosen, this));
  1015. }
  1016. else if (result == 111)
  1017. {
  1018. #if JUCE_MODAL_LOOPS_PERMITTED
  1019. AlertWindow w ("AlertWindow demo..",
  1020. "This AlertWindow has a couple of extra components added to show how to add drop-down lists and text entry boxes.",
  1021. AlertWindow::QuestionIcon);
  1022. w.addTextEditor ("text", "enter some text here", "text field:");
  1023. const char* options[] = { "option 1", "option 2", "option 3", "option 4", nullptr };
  1024. w.addComboBox ("option", StringArray (options), "some options");
  1025. w.addButton ("ok", 1, KeyPress (KeyPress::returnKey, 0, 0));
  1026. w.addButton ("cancel", 0, KeyPress (KeyPress::escapeKey, 0, 0));
  1027. if (w.runModalLoop() != 0) // is they picked 'ok'
  1028. {
  1029. // this is the item they chose in the drop-down list..
  1030. const int optionIndexChosen = w.getComboBoxComponent ("option")->getSelectedItemIndex();
  1031. (void) optionIndexChosen; // (just avoids a compiler warning about unused variables)
  1032. // this is the text they entered..
  1033. String text = w.getTextEditorContents ("text");
  1034. }
  1035. #endif
  1036. }
  1037. else if (result == 112)
  1038. {
  1039. DemoBackgroundThread demoThread;
  1040. #if JUCE_MODAL_LOOPS_PERMITTED
  1041. if (demoThread.runThread())
  1042. {
  1043. // thread finished normally..
  1044. AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
  1045. "Progress window",
  1046. "Thread finished ok!");
  1047. }
  1048. else
  1049. {
  1050. // user pressed the cancel button..
  1051. AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
  1052. "Progress window",
  1053. "You pressed cancel!");
  1054. }
  1055. #endif
  1056. }
  1057. else if (result == 120)
  1058. {
  1059. DialogWindow::LaunchOptions o;
  1060. o.content.setOwned (new ColourSelector());
  1061. o.content->setSize (400, 400);
  1062. o.dialogTitle = "Colour Selector Demo";
  1063. o.dialogBackgroundColour = Colours::grey;
  1064. o.escapeKeyTriggersCloseButton = true;
  1065. o.useNativeTitleBar = false;
  1066. o.resizable = true;
  1067. o.launchAsync();
  1068. }
  1069. else if (result == 140)
  1070. {
  1071. #if JUCE_MAC
  1072. AppleRemoteTestWindow test;
  1073. test.runModalLoop();
  1074. #endif
  1075. }
  1076. else if (result >= 121 && result < 139)
  1077. {
  1078. #if JUCE_MODAL_LOOPS_PERMITTED
  1079. const bool useNativeVersion = result < 130;
  1080. if (result > 130)
  1081. result -= 10;
  1082. if (result == 121)
  1083. {
  1084. FileChooser fc ("Choose a file to open...",
  1085. File::getCurrentWorkingDirectory(),
  1086. "*",
  1087. useNativeVersion);
  1088. if (fc.browseForMultipleFilesToOpen())
  1089. {
  1090. String chosen;
  1091. for (int i = 0; i < fc.getResults().size(); ++i)
  1092. chosen << fc.getResults().getReference(i).getFullPathName() << "\n";
  1093. AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
  1094. "File Chooser...",
  1095. "You picked: " + chosen);
  1096. }
  1097. }
  1098. else if (result == 124)
  1099. {
  1100. ImagePreviewComponent imagePreview;
  1101. imagePreview.setSize (200, 200);
  1102. FileChooser fc ("Choose an image to open...",
  1103. File::getCurrentWorkingDirectory(),
  1104. "*.jpg;*.jpeg;*.png;*.gif",
  1105. useNativeVersion);
  1106. if (fc.browseForMultipleFilesToOpen (&imagePreview))
  1107. {
  1108. String chosen;
  1109. for (int i = 0; i < fc.getResults().size(); ++i)
  1110. chosen << fc.getResults().getReference(i).getFullPathName() << "\n";
  1111. AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
  1112. "File Chooser...",
  1113. "You picked: " + chosen);
  1114. }
  1115. }
  1116. else if (result == 122)
  1117. {
  1118. FileChooser fc ("Choose a file to save...",
  1119. File::getCurrentWorkingDirectory(),
  1120. "*",
  1121. useNativeVersion);
  1122. if (fc.browseForFileToSave (true))
  1123. {
  1124. File chosenFile = fc.getResult();
  1125. AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
  1126. "File Chooser...",
  1127. "You picked: " + chosenFile.getFullPathName());
  1128. }
  1129. }
  1130. else if (result == 123)
  1131. {
  1132. FileChooser fc ("Choose a directory...",
  1133. File::getCurrentWorkingDirectory(),
  1134. "*",
  1135. useNativeVersion);
  1136. if (fc.browseForDirectory())
  1137. {
  1138. File chosenDirectory = fc.getResult();
  1139. AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
  1140. "File Chooser...",
  1141. "You picked: " + chosenDirectory.getFullPathName());
  1142. }
  1143. }
  1144. #endif
  1145. }
  1146. else if (result == 1001)
  1147. {
  1148. tabs.setOrientation (TabbedButtonBar::TabsAtTop);
  1149. }
  1150. else if (result == 1002)
  1151. {
  1152. tabs.setOrientation (TabbedButtonBar::TabsAtBottom);
  1153. }
  1154. else if (result == 1003)
  1155. {
  1156. tabs.setOrientation (TabbedButtonBar::TabsAtLeft);
  1157. }
  1158. else if (result == 1004)
  1159. {
  1160. tabs.setOrientation (TabbedButtonBar::TabsAtRight);
  1161. }
  1162. }
  1163. void sliderValueChanged (Slider*)
  1164. {
  1165. // When you move the rotation slider, we'll apply a rotaion transform to the whole tabs component..
  1166. tabs.setTransform (AffineTransform::rotation ((float) (transformSlider.getValue() / (180.0 / double_Pi)),
  1167. getWidth() * 0.5f, getHeight() * 0.5f));
  1168. }
  1169. private:
  1170. TextButton menuButton;
  1171. ToggleButton enableButton;
  1172. Slider transformSlider;
  1173. DemoTabbedComponent tabs;
  1174. };
  1175. //==============================================================================
  1176. Component* createWidgetsDemo()
  1177. {
  1178. return new WidgetsDemo();
  1179. }