/* ============================================================================== This file is part of the JUCE library. Copyright (c) 2017 - ROLI Ltd. JUCE is an open source library subject to commercial or open-source licensing. By using JUCE, you agree to the terms of both the JUCE 5 End-User License Agreement and JUCE 5 Privacy Policy (both updated and effective as of the 27th April 2017). End User License Agreement: www.juce.com/juce-5-licence Privacy Policy: www.juce.com/juce-5-privacy-policy Or: You may also use this code under the terms of the GPL v3 (see www.gnu.org/licenses). JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE DISCLAIMED. ============================================================================== */ #include "../JuceDemoHeader.h" //============================================================================== /** Just a simple window that deletes itself when closed. */ class BasicWindow : public DocumentWindow { public: BasicWindow (const String& name, Colour backgroundColour, int buttonsNeeded) : DocumentWindow (name, backgroundColour, buttonsNeeded) { } void closeButtonPressed() { delete this; } private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BasicWindow) }; //============================================================================== /** This window contains a ColourSelector which can be used to change the window's colour. */ class ColourSelectorWindow : public DocumentWindow, private ChangeListener { public: ColourSelectorWindow (const String& name, Colour backgroundColour, int buttonsNeeded) : DocumentWindow (name, backgroundColour, buttonsNeeded), selector (ColourSelector::showColourAtTop | ColourSelector::showSliders | ColourSelector::showColourspace) { selector.setCurrentColour (backgroundColour); selector.setColour (ColourSelector::backgroundColourId, Colours::transparentWhite); selector.addChangeListener (this); setContentOwned (&selector, false); } ~ColourSelectorWindow() { selector.removeChangeListener (this); } void closeButtonPressed() { delete this; } private: ColourSelector selector; void changeListenerCallback (ChangeBroadcaster* source) { if (source == &selector) setBackgroundColour (selector.getCurrentColour()); } JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ColourSelectorWindow) }; //============================================================================== class BouncingBallComponent : public Component, public Timer { public: BouncingBallComponent() { setInterceptsMouseClicks (false, false); Random random; const float size = 10.0f + random.nextInt (30); ballBounds.setBounds (random.nextFloat() * 100.0f, random.nextFloat() * 100.0f, size, size); direction.x = random.nextFloat() * 8.0f - 4.0f; direction.y = random.nextFloat() * 8.0f - 4.0f; colour = Colour ((juce::uint32) random.nextInt()) .withAlpha (0.5f) .withBrightness (0.7f); startTimer (60); } void paint (Graphics& g) override { g.setColour (colour); g.fillEllipse (ballBounds - getPosition().toFloat()); } void timerCallback() override { ballBounds += direction; if (ballBounds.getX() < 0) direction.x = std::abs (direction.x); if (ballBounds.getY() < 0) direction.y = std::abs (direction.y); if (ballBounds.getRight() > getParentWidth()) direction.x = -std::abs (direction.x); if (ballBounds.getBottom() > getParentHeight()) direction.y = -std::abs (direction.y); setBounds (ballBounds.getSmallestIntegerContainer()); } private: Colour colour; Rectangle ballBounds; Point direction; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BouncingBallComponent) }; //============================================================================== class BouncingBallsContainer : public Component { public: BouncingBallsContainer (int numBalls) { for (int i = 0; i < numBalls; ++i) { BouncingBallComponent* newBall = new BouncingBallComponent(); balls.add (newBall); addAndMakeVisible (newBall); } } void mouseDown (const MouseEvent& e) override { dragger.startDraggingComponent (this, e); } void mouseDrag (const MouseEvent& e) override { // as there's no titlebar we have to manage the dragging ourselves dragger.dragComponent (this, e, 0); } void paint (Graphics& g) override { if (isOpaque()) g.fillAll (Colours::white); else g.fillAll (Colours::blue.withAlpha (0.2f)); g.setFont (16.0f); g.setColour (Colours::black); g.drawFittedText ("This window has no titlebar and a transparent background.", getLocalBounds().reduced (8, 0), Justification::centred, 5); g.drawRect (getLocalBounds()); } private: ComponentDragger dragger; OwnedArray balls; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BouncingBallsContainer) }; //============================================================================== class WindowsDemo : public Component, private Button::Listener { public: enum Windows { dialog, document, alert, numWindows }; WindowsDemo() { setOpaque (true); showWindowsButton.setButtonText ("Show Windows"); addAndMakeVisible (showWindowsButton); showWindowsButton.addListener (this); closeWindowsButton.setButtonText ("Close Windows"); addAndMakeVisible (closeWindowsButton); closeWindowsButton.addListener (this); } ~WindowsDemo() { if (dialogWindow != nullptr) { dialogWindow->exitModalState (0); // we are shutting down: can't wait for the message manager // to eventually delete this delete dialogWindow; } closeAllWindows(); closeWindowsButton.removeListener (this); showWindowsButton.removeListener (this); } void paint (Graphics& g) override { g.fillAll (getUIColourIfAvailable (LookAndFeel_V4::ColourScheme::UIColour::windowBackground, Colours::grey)); } void resized() override { const Rectangle buttonSize (0, 0, 108, 28); Rectangle area ((getWidth() / 2) - (buttonSize.getWidth() / 2), (getHeight() / 2) - buttonSize.getHeight(), buttonSize.getWidth(), buttonSize.getHeight()); showWindowsButton.setBounds (area.reduced (2)); closeWindowsButton.setBounds (area.translated (0, buttonSize.getHeight()).reduced (2)); } private: // Because in this demo the windows delete themselves, we'll use the // Component::SafePointer class to point to them, which automatically becomes // null when the component that it points to is deleted. Array< Component::SafePointer > windows; TextButton showWindowsButton, closeWindowsButton; SafePointer dialogWindow; void showAllWindows() { closeAllWindows(); showDocumentWindow (false); showDocumentWindow (true); showTransparentWindow(); showDialogWindow(); } void closeAllWindows() { for (int i = 0; i < windows.size(); ++i) windows.getReference(i).deleteAndZero(); windows.clear(); } void showDialogWindow() { String m; m << "Dialog Windows can be used to quickly show a component, usually blocking mouse input to other windows." << newLine << newLine << "They can also be quickly closed with the escape key, try it now."; DialogWindow::LaunchOptions options; Label* label = new Label(); label->setText (m, dontSendNotification); label->setColour (Label::textColourId, Colours::whitesmoke); options.content.setOwned (label); Rectangle area (0, 0, 300, 200); options.content->setSize (area.getWidth(), area.getHeight()); options.dialogTitle = "Dialog Window"; options.dialogBackgroundColour = Colour (0xff0e345a); options.escapeKeyTriggersCloseButton = true; options.useNativeTitleBar = false; options.resizable = true; dialogWindow = options.launchAsync(); if (dialogWindow != nullptr) dialogWindow->centreWithSize (300, 200); } void showDocumentWindow (bool native) { DocumentWindow* dw = new ColourSelectorWindow ("Document Window", getRandomBrightColour(), DocumentWindow::allButtons); windows.add (dw); Rectangle area (0, 0, 300, 400); RectanglePlacement placement ((native ? RectanglePlacement::xLeft : RectanglePlacement::xRight) | RectanglePlacement::yTop | RectanglePlacement::doNotResize); Rectangle result (placement.appliedTo (area, Desktop::getInstance().getDisplays() .getMainDisplay().userArea.reduced (20))); dw->setBounds (result); dw->setResizable (true, ! native); dw->setUsingNativeTitleBar (native); dw->setVisible (true); } void showTransparentWindow() { BouncingBallsContainer* balls = new BouncingBallsContainer (3); balls->addToDesktop (ComponentPeer::windowIsTemporary); windows.add (balls); Rectangle area (0, 0, 200, 200); RectanglePlacement placement (RectanglePlacement::xLeft | RectanglePlacement::yBottom | RectanglePlacement::doNotResize); Rectangle result (placement.appliedTo (area, Desktop::getInstance().getDisplays() .getMainDisplay().userArea.reduced (20))); balls->setBounds (result); balls->setVisible (true); } void buttonClicked (Button* button) override { if (button == &showWindowsButton) showAllWindows(); else if (button == &closeWindowsButton) closeAllWindows(); } JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsDemo) }; // This static object will register this demo type in a global list of demos.. static JuceDemoType demo ("10 Components: Windows");