| @@ -461,7 +461,8 @@ private: | |||
| //============================================================================== | |||
| struct MiscPage : public Component | |||
| struct MiscPage : public Component, | |||
| private Timer | |||
| { | |||
| MiscPage() | |||
| { | |||
| @@ -482,6 +483,21 @@ struct MiscPage : public Component | |||
| comboBox.addItem ("combo box item " + String (i), i); | |||
| comboBox.setSelectedId (1); | |||
| addAndMakeVisible (linearProgressBar); | |||
| linearProgressBar.setStyle (ProgressBar::Style::linear); | |||
| linearProgressBar.setBounds (10, 115, 200, 24); | |||
| addAndMakeVisible (circularProgressBar); | |||
| circularProgressBar.setStyle (ProgressBar::Style::circular); | |||
| circularProgressBar.setBounds (10, 145, 200, 100); | |||
| startTimerHz (10); | |||
| } | |||
| ~MiscPage() override | |||
| { | |||
| stopTimer(); | |||
| } | |||
| void lookAndFeelChanged() override | |||
| @@ -490,10 +506,37 @@ struct MiscPage : public Component | |||
| textEditor2.applyFontToAllText (textEditor2.getFont()); | |||
| } | |||
| void timerCallback() override | |||
| { | |||
| constexpr auto minValue = -0.2; | |||
| constexpr auto maxValue = 1.2; | |||
| constexpr auto maxIncrement = 0.05; | |||
| if (progress >= maxValue) | |||
| progress = minValue; | |||
| else | |||
| progress += Random::getSystemRandom().nextDouble() * maxIncrement; | |||
| if (isPositiveAndNotGreaterThan (progress, 1.0)) | |||
| { | |||
| linearProgressBar.setPercentageDisplay (true); | |||
| circularProgressBar.setPercentageDisplay (true); | |||
| } | |||
| else | |||
| { | |||
| linearProgressBar.setTextToDisplay ("Linear progress bar"); | |||
| circularProgressBar.setTextToDisplay ("Circular progress bar"); | |||
| } | |||
| } | |||
| TextEditor textEditor1, | |||
| textEditor2 { "Password", (juce_wchar) 0x2022 }; | |||
| ComboBox comboBox { "Combo" }; | |||
| double progress { 0.0 }; | |||
| ProgressBar linearProgressBar { progress }; | |||
| ProgressBar circularProgressBar { progress }; | |||
| }; | |||
| //============================================================================== | |||
| @@ -228,6 +228,9 @@ public: | |||
| addAndMakeVisible (closeWindowsButton); | |||
| closeWindowsButton.onClick = [this] { closeAllWindows(); }; | |||
| addAndMakeVisible (alertWindowResult); | |||
| alertWindowResult.setJustificationType (Justification::centred); | |||
| setSize (250, 250); | |||
| } | |||
| @@ -253,14 +256,27 @@ public: | |||
| void resized() override | |||
| { | |||
| Rectangle<int> buttonSize (0, 0, 108, 28); | |||
| FlexBox flexBox; | |||
| flexBox.flexDirection = FlexBox::Direction::column; | |||
| flexBox.justifyContent = FlexBox::JustifyContent::center; | |||
| constexpr auto buttonWidth = 108.0f; | |||
| constexpr auto componentHeight = 24.0f; | |||
| constexpr auto gap = 4.0f; | |||
| flexBox.items.add (FlexItem { showWindowsButton }.withHeight (componentHeight) | |||
| .withMinWidth (buttonWidth) | |||
| .withAlignSelf (FlexItem::AlignSelf::center)); | |||
| Rectangle<int> area ((getWidth() / 2) - (buttonSize.getWidth() / 2), | |||
| (getHeight() / 2) - buttonSize.getHeight(), | |||
| buttonSize.getWidth(), buttonSize.getHeight()); | |||
| flexBox.items.add (FlexItem{}.withHeight (gap)); | |||
| flexBox.items.add (FlexItem { closeWindowsButton }.withHeight (componentHeight) | |||
| .withMinWidth (buttonWidth) | |||
| .withAlignSelf (FlexItem::AlignSelf::center)); | |||
| showWindowsButton .setBounds (area.reduced (2)); | |||
| closeWindowsButton.setBounds (area.translated (0, buttonSize.getHeight()).reduced (2)); | |||
| flexBox.items.add (FlexItem{}.withHeight (gap)); | |||
| flexBox.items.add (FlexItem { alertWindowResult }.withHeight (componentHeight)); | |||
| flexBox.performLayout (getLocalBounds()); | |||
| } | |||
| private: | |||
| @@ -272,6 +288,7 @@ private: | |||
| TextButton showWindowsButton { "Show Windows" }, | |||
| closeWindowsButton { "Close Windows" }; | |||
| Label alertWindowResult { "Alert Window result" }; | |||
| void showAllWindows() | |||
| { | |||
| @@ -280,6 +297,7 @@ private: | |||
| showDocumentWindow (false); | |||
| showDocumentWindow (true); | |||
| showTransparentWindow(); | |||
| showAlertWindow(); | |||
| showDialogWindow(); | |||
| } | |||
| @@ -289,6 +307,12 @@ private: | |||
| window.deleteAndZero(); | |||
| windows.clear(); | |||
| alertWindowResult.setText ("", dontSendNotification); | |||
| } | |||
| static auto getDisplayArea() | |||
| { | |||
| return Desktop::getInstance().getDisplays().getPrimaryDisplay()->userArea.reduced (20); | |||
| } | |||
| void showDialogWindow() | |||
| @@ -333,8 +357,7 @@ private: | |||
| | RectanglePlacement::yTop | |||
| | RectanglePlacement::doNotResize); | |||
| auto result = placement.appliedTo (area, Desktop::getInstance().getDisplays() | |||
| .getPrimaryDisplay()->userArea.reduced (20)); | |||
| auto result = placement.appliedTo (area, getDisplayArea()); | |||
| dw->setBounds (result); | |||
| dw->setResizable (true, ! native); | |||
| @@ -354,12 +377,113 @@ private: | |||
| | RectanglePlacement::yBottom | |||
| | RectanglePlacement::doNotResize); | |||
| auto result = placement.appliedTo (area, Desktop::getInstance().getDisplays() | |||
| .getPrimaryDisplay()->userArea.reduced (20)); | |||
| auto result = placement.appliedTo (area, getDisplayArea()); | |||
| balls->setBounds (result); | |||
| balls->setVisible (true); | |||
| } | |||
| void showAlertWindow() | |||
| { | |||
| auto* alertWindow = new AlertWindow ("Alert Window", | |||
| "For more complex dialogs, you can easily add components to an AlertWindow, such as...", | |||
| MessageBoxIconType::InfoIcon); | |||
| windows.add (alertWindow); | |||
| alertWindow->addTextBlock ("Text block"); | |||
| alertWindow->addComboBox ("Combo box", {"Combo box", "Item 2", "Item 3"}); | |||
| alertWindow->addTextEditor ("Text editor", "Text editor"); | |||
| alertWindow->addTextEditor ("Password", "password", "including for passwords", true); | |||
| alertWindowCustomComponent.emplace(); | |||
| alertWindow->addCustomComponent (&(*alertWindowCustomComponent)); | |||
| alertWindow->addTextBlock ("Progress bar"); | |||
| alertWindow->addProgressBarComponent (alertWindowCustomComponent->value, ProgressBar::Style::linear); | |||
| alertWindow->addProgressBarComponent (alertWindowCustomComponent->value, ProgressBar::Style::circular); | |||
| alertWindow->addTextBlock ("Press any button, or the escape key, to close the window"); | |||
| enum AlertWindowResult | |||
| { | |||
| noButtonPressed, | |||
| button1Pressed, | |||
| button2Pressed | |||
| }; | |||
| alertWindow->addButton ("Button 1", AlertWindowResult::button1Pressed); | |||
| alertWindow->addButton ("Button 2", AlertWindowResult::button2Pressed); | |||
| RectanglePlacement placement { RectanglePlacement::yMid | |||
| | RectanglePlacement::xLeft | |||
| | RectanglePlacement::doNotResize }; | |||
| alertWindow->setBounds (placement.appliedTo (alertWindow->getBounds(), getDisplayArea())); | |||
| alertWindowResult.setText ("", dontSendNotification); | |||
| alertWindow->enterModalState (false, ModalCallbackFunction::create ([ref = SafePointer { this }] (int result) | |||
| { | |||
| if (ref == nullptr) | |||
| return; | |||
| const auto text = [&] | |||
| { | |||
| switch (result) | |||
| { | |||
| case noButtonPressed: | |||
| return "Dismissed the Alert Window without pressing a button"; | |||
| case button1Pressed: | |||
| return "Dismissed the Alert Window using Button 1"; | |||
| case button2Pressed: | |||
| return "Dismissed the Alert Window using Button 2"; | |||
| } | |||
| return "Unhandled event when dismissing the Alert Window"; | |||
| }(); | |||
| ref->alertWindowResult.setText (text, dontSendNotification); | |||
| }), true); | |||
| } | |||
| class AlertWindowCustomComponent : public Component, | |||
| private Slider::Listener | |||
| { | |||
| public: | |||
| AlertWindowCustomComponent() | |||
| { | |||
| slider.setRange (0.0, 1.0); | |||
| slider.setValue (0.5, NotificationType::dontSendNotification); | |||
| slider.addListener (this); | |||
| addAndMakeVisible (label); | |||
| addAndMakeVisible (slider); | |||
| setSize (200, 50); | |||
| } | |||
| ~AlertWindowCustomComponent() override | |||
| { | |||
| slider.removeListener (this); | |||
| } | |||
| void resized() override | |||
| { | |||
| auto bounds = getLocalBounds(); | |||
| label.setBounds (bounds.removeFromTop (getHeight() / 2)); | |||
| slider.setBounds (bounds); | |||
| } | |||
| void sliderValueChanged (Slider*) override | |||
| { | |||
| value = slider.getValue(); | |||
| } | |||
| double value { -1.0 }; | |||
| private: | |||
| Label label { "Label", "Custom component" }; | |||
| Slider slider { Slider::SliderStyle::LinearHorizontal, | |||
| Slider::TextEntryBoxPosition::NoTextBox }; | |||
| }; | |||
| std::optional<AlertWindowCustomComponent> alertWindowCustomComponent; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsDemo) | |||
| }; | |||
| @@ -367,71 +367,9 @@ void ProjucerLookAndFeel::drawTreeviewPlusMinusBox (Graphics& g, const Rectangle | |||
| g.strokePath (getArrowPath (area, isOpen ? 2 : 1, false, Justification::centredRight), PathStrokeType (2.0f)); | |||
| } | |||
| void ProjucerLookAndFeel::drawProgressBar (Graphics& g, ProgressBar& progressBar, | |||
| int width, int height, double progress, const String& textToShow) | |||
| ProgressBar::Style ProjucerLookAndFeel::getDefaultProgressBarStyle (const ProgressBar&) | |||
| { | |||
| ignoreUnused (width, height, progress); | |||
| const auto background = progressBar.findColour (ProgressBar::backgroundColourId); | |||
| const auto foreground = progressBar.findColour (defaultButtonBackgroundColourId); | |||
| const auto sideLength = jmin (width, height); | |||
| auto barBounds = progressBar.getLocalBounds().withSizeKeepingCentre (sideLength, sideLength).reduced (1).toFloat(); | |||
| auto rotationInDegrees = static_cast<float> ((Time::getMillisecondCounter() / 10) % 360); | |||
| auto normalisedRotation = rotationInDegrees / 360.0f; | |||
| const auto rotationOffset = 22.5f; | |||
| const auto maxRotation = 315.0f; | |||
| auto startInDegrees = rotationInDegrees; | |||
| auto endInDegrees = startInDegrees + rotationOffset; | |||
| if (normalisedRotation >= 0.25f && normalisedRotation < 0.5f) | |||
| { | |||
| const auto rescaledRotation = (normalisedRotation * 4.0f) - 1.0f; | |||
| endInDegrees = startInDegrees + rotationOffset + (maxRotation * rescaledRotation); | |||
| } | |||
| else if (normalisedRotation >= 0.5f && normalisedRotation <= 1.0f) | |||
| { | |||
| endInDegrees = startInDegrees + rotationOffset + maxRotation; | |||
| const auto rescaledRotation = 1.0f - ((normalisedRotation * 2.0f) - 1.0f); | |||
| startInDegrees = endInDegrees - rotationOffset - (maxRotation * rescaledRotation); | |||
| } | |||
| g.setColour (background); | |||
| Path arcPath2; | |||
| arcPath2.addCentredArc (barBounds.getCentreX(), | |||
| barBounds.getCentreY(), | |||
| barBounds.getWidth() * 0.5f, | |||
| barBounds.getHeight() * 0.5f, 0.0f, | |||
| 0.0f, | |||
| MathConstants<float>::twoPi, | |||
| true); | |||
| g.strokePath (arcPath2, PathStrokeType (2.0f)); | |||
| g.setColour (foreground); | |||
| Path arcPath; | |||
| arcPath.addCentredArc (barBounds.getCentreX(), | |||
| barBounds.getCentreY(), | |||
| barBounds.getWidth() * 0.5f, | |||
| barBounds.getHeight() * 0.5f, | |||
| 0.0f, | |||
| degreesToRadians (startInDegrees), | |||
| degreesToRadians (endInDegrees), | |||
| true); | |||
| arcPath.applyTransform (AffineTransform::rotation (normalisedRotation * MathConstants<float>::pi * 2.25f, | |||
| barBounds.getCentreX(), barBounds.getCentreY())); | |||
| g.strokePath (arcPath, PathStrokeType (2.0f)); | |||
| if (textToShow.isNotEmpty()) | |||
| { | |||
| g.setColour (progressBar.findColour (TextButton::textColourOffId)); | |||
| g.setFont (Font (12.0f, 2)); | |||
| g.drawText (textToShow, barBounds, Justification::centred, false); | |||
| } | |||
| return ProgressBar::Style::circular; | |||
| } | |||
| //============================================================================== | |||
| @@ -583,5 +521,6 @@ void ProjucerLookAndFeel::setupColours() | |||
| setColour (TreeView::selectedItemBackgroundColourId, findColour (defaultHighlightColourId)); | |||
| setColour (PopupMenu::highlightedBackgroundColourId, findColour (defaultHighlightColourId).withAlpha (0.75f)); | |||
| setColour (PopupMenu::highlightedTextColourId, findColour (defaultHighlightedTextColourId)); | |||
| setColour (ProgressBar::foregroundColourId, findColour (defaultButtonBackgroundColourId)); | |||
| setColour (0x1000440, /*LassoComponent::lassoFillColourId*/ findColour (defaultHighlightColourId).withAlpha (0.3f)); | |||
| } | |||
| @@ -74,7 +74,7 @@ public: | |||
| void drawTreeviewPlusMinusBox (Graphics&, const Rectangle<float>& area, | |||
| Colour backgroundColour, bool isItemOpen, bool isMouseOver) override; | |||
| void drawProgressBar (Graphics&, ProgressBar&, int width, int height, double progress, const String& textToShow) override; | |||
| ProgressBar::Style getDefaultProgressBarStyle (const ProgressBar&) override; | |||
| //============================================================================== | |||
| static Path getArrowPath (Rectangle<float> arrowZone, const int direction, | |||
| @@ -2128,13 +2128,14 @@ public: | |||
| The callback is an optional object which will receive a callback when the modal | |||
| component loses its modal status, either by being hidden or when exitModalState() | |||
| is called. If you pass an object in here, the system will take care of deleting it | |||
| later, after making the callback | |||
| later, after making the callback. | |||
| If deleteWhenDismissed is true, then when it is dismissed, the component will be | |||
| deleted and then the callback will be called. (This will safely handle the situation | |||
| where the component is deleted before its exitModalState() method is called). | |||
| @see exitModalState, runModalLoop, ModalComponentManager::attachCallback | |||
| @see exitModalState, runModalLoop, ModalComponentManager::attachCallback, | |||
| ModalCallbackFunction | |||
| */ | |||
| void enterModalState (bool takeKeyboardFocus = true, | |||
| ModalComponentManager::Callback* callback = nullptr, | |||
| @@ -615,6 +615,11 @@ bool LookAndFeel_V2::isProgressBarOpaque (ProgressBar& progressBar) | |||
| return progressBar.findColour (ProgressBar::backgroundColourId).isOpaque(); | |||
| } | |||
| ProgressBar::Style LookAndFeel_V2::getDefaultProgressBarStyle (const ProgressBar&) | |||
| { | |||
| return ProgressBar::Style::linear; | |||
| } | |||
| bool LookAndFeel_V2::areScrollbarButtonsVisible() | |||
| { | |||
| return true; | |||
| @@ -97,6 +97,7 @@ public: | |||
| void drawProgressBar (Graphics&, ProgressBar&, int width, int height, double progress, const String& textToShow) override; | |||
| void drawSpinningWaitAnimation (Graphics&, const Colour& colour, int x, int y, int w, int h) override; | |||
| bool isProgressBarOpaque (ProgressBar&) override; | |||
| ProgressBar::Style getDefaultProgressBarStyle (const ProgressBar&) override; | |||
| //============================================================================== | |||
| bool areScrollbarButtonsVisible() override; | |||
| @@ -482,17 +482,30 @@ Font LookAndFeel_V4::getAlertWindowFont() { return { 14.0f }; } | |||
| //============================================================================== | |||
| void LookAndFeel_V4::drawProgressBar (Graphics& g, ProgressBar& progressBar, | |||
| int width, int height, double progress, const String& textToShow) | |||
| int width, int height, double progress, | |||
| const String& textToShow) | |||
| { | |||
| if (width == height) | |||
| drawCircularProgressBar (g, progressBar, textToShow); | |||
| else | |||
| drawLinearProgressBar (g, progressBar, width, height, progress, textToShow); | |||
| switch (progressBar.getResolvedStyle()) | |||
| { | |||
| case ProgressBar::Style::linear: | |||
| drawLinearProgressBar (g, progressBar, width, height, progress, textToShow); | |||
| break; | |||
| case ProgressBar::Style::circular: | |||
| drawCircularProgressBar (g, progressBar, textToShow); | |||
| break; | |||
| } | |||
| } | |||
| ProgressBar::Style LookAndFeel_V4::getDefaultProgressBarStyle (const ProgressBar& progressBar) | |||
| { | |||
| return progressBar.getWidth() == progressBar.getHeight() ? ProgressBar::Style::circular | |||
| : ProgressBar::Style::linear; | |||
| } | |||
| void LookAndFeel_V4::drawLinearProgressBar (Graphics& g, ProgressBar& progressBar, | |||
| int width, int height, | |||
| double progress, const String& textToShow) | |||
| void LookAndFeel_V4::drawLinearProgressBar (Graphics& g, const ProgressBar& progressBar, | |||
| int width, int height, double progress, | |||
| const String& textToShow) | |||
| { | |||
| auto background = progressBar.findColour (ProgressBar::backgroundColourId); | |||
| auto foreground = progressBar.findColour (ProgressBar::foregroundColourId); | |||
| @@ -549,18 +562,20 @@ void LookAndFeel_V4::drawLinearProgressBar (Graphics& g, ProgressBar& progressBa | |||
| } | |||
| } | |||
| void LookAndFeel_V4::drawCircularProgressBar (Graphics& g, ProgressBar& progressBar, const String& progressText) | |||
| void LookAndFeel_V4::drawCircularProgressBar (Graphics& g, const ProgressBar& progressBar, | |||
| const String& textToShow) | |||
| { | |||
| auto background = progressBar.findColour (ProgressBar::backgroundColourId); | |||
| auto foreground = progressBar.findColour (ProgressBar::foregroundColourId); | |||
| const auto background = progressBar.findColour (ProgressBar::backgroundColourId); | |||
| const auto foreground = progressBar.findColour (ProgressBar::foregroundColourId); | |||
| auto barBounds = progressBar.getLocalBounds().reduced (2, 2).toFloat(); | |||
| const auto barBounds = progressBar.getLocalBounds().reduced (2, 2).toFloat(); | |||
| const auto size = jmin (barBounds.getWidth(), barBounds.getHeight()); | |||
| auto rotationInDegrees = static_cast<float> ((Time::getMillisecondCounter() / 10) % 360); | |||
| auto normalisedRotation = rotationInDegrees / 360.0f; | |||
| const auto rotationInDegrees = static_cast<float> ((Time::getMillisecondCounter() / 10) % 360); | |||
| const auto normalisedRotation = rotationInDegrees / 360.0f; | |||
| auto rotationOffset = 22.5f; | |||
| auto maxRotation = 315.0f; | |||
| constexpr auto rotationOffset = 22.5f; | |||
| constexpr auto maxRotation = 315.0f; | |||
| auto startInDegrees = rotationInDegrees; | |||
| auto endInDegrees = startInDegrees + rotationOffset; | |||
| @@ -581,8 +596,8 @@ void LookAndFeel_V4::drawCircularProgressBar (Graphics& g, ProgressBar& progress | |||
| Path arcPath2; | |||
| arcPath2.addCentredArc (barBounds.getCentreX(), | |||
| barBounds.getCentreY(), | |||
| barBounds.getWidth() * 0.5f, | |||
| barBounds.getHeight() * 0.5f, 0.0f, | |||
| size * 0.5f, | |||
| size * 0.5f, 0.0f, | |||
| 0.0f, | |||
| MathConstants<float>::twoPi, | |||
| true); | |||
| @@ -592,8 +607,8 @@ void LookAndFeel_V4::drawCircularProgressBar (Graphics& g, ProgressBar& progress | |||
| Path arcPath; | |||
| arcPath.addCentredArc (barBounds.getCentreX(), | |||
| barBounds.getCentreY(), | |||
| barBounds.getWidth() * 0.5f, | |||
| barBounds.getHeight() * 0.5f, | |||
| size * 0.5f, | |||
| size * 0.5f, | |||
| 0.0f, | |||
| degreesToRadians (startInDegrees), | |||
| degreesToRadians (endInDegrees), | |||
| @@ -602,11 +617,11 @@ void LookAndFeel_V4::drawCircularProgressBar (Graphics& g, ProgressBar& progress | |||
| arcPath.applyTransform (AffineTransform::rotation (normalisedRotation * MathConstants<float>::pi * 2.25f, barBounds.getCentreX(), barBounds.getCentreY())); | |||
| g.strokePath (arcPath, PathStrokeType (4.0f)); | |||
| if (progressText.isNotEmpty()) | |||
| if (textToShow.isNotEmpty()) | |||
| { | |||
| g.setColour (progressBar.findColour (TextButton::textColourOffId)); | |||
| g.setFont ({ 12.0f, Font::italic }); | |||
| g.drawText (progressText, barBounds, Justification::centred, false); | |||
| g.drawText (textToShow, barBounds, Justification::centred, false); | |||
| } | |||
| } | |||
| @@ -140,8 +140,9 @@ public: | |||
| Font getAlertWindowFont() override; | |||
| //============================================================================== | |||
| void drawProgressBar (Graphics&, ProgressBar&, int width, int height, double progress, const String& textToShow) override; | |||
| void drawProgressBar (Graphics&, ProgressBar&, int width, int height, double progress, const String&) override; | |||
| bool isProgressBarOpaque (ProgressBar&) override { return false; } | |||
| ProgressBar::Style getDefaultProgressBarStyle (const ProgressBar&) override; | |||
| //============================================================================== | |||
| int getDefaultScrollbarWidth() override; | |||
| @@ -242,9 +243,10 @@ public: | |||
| private: | |||
| //============================================================================== | |||
| void drawLinearProgressBar (Graphics&, ProgressBar&, int width, int height, double progress, const String&); | |||
| void drawCircularProgressBar (Graphics&, ProgressBar&, const String&); | |||
| static void drawLinearProgressBar (Graphics&, const ProgressBar&, int, int, double, const String&); | |||
| static void drawCircularProgressBar (Graphics&, const ProgressBar&, const String&); | |||
| //============================================================================== | |||
| int getPropertyComponentIndent (PropertyComponent&); | |||
| //============================================================================== | |||
| @@ -26,15 +26,14 @@ | |||
| namespace juce | |||
| { | |||
| ProgressBar::ProgressBar (double& progress_) | |||
| : progress (progress_), | |||
| displayPercentage (true), | |||
| lastCallbackTime (0) | |||
| ProgressBar::ProgressBar (double& progress_, std::optional<Style> style_) | |||
| : progress { progress_ }, | |||
| style { style_ } | |||
| { | |||
| currentValue = jlimit (0.0, 1.0, progress); | |||
| } | |||
| ProgressBar::~ProgressBar() | |||
| ProgressBar::ProgressBar (double& progress_) | |||
| : progress { progress_ } | |||
| { | |||
| } | |||
| @@ -51,6 +50,17 @@ void ProgressBar::setTextToDisplay (const String& text) | |||
| displayedMessage = text; | |||
| } | |||
| void ProgressBar::setStyle (std::optional<Style> newStyle) | |||
| { | |||
| style = newStyle; | |||
| repaint(); | |||
| } | |||
| ProgressBar::Style ProgressBar::getResolvedStyle() const | |||
| { | |||
| return style.value_or (getLookAndFeel().getDefaultProgressBarStyle (*this)); | |||
| } | |||
| void ProgressBar::lookAndFeelChanged() | |||
| { | |||
| setOpaque (getLookAndFeel().isProgressBarOpaque (*this)); | |||
| @@ -76,9 +86,11 @@ void ProgressBar::paint (Graphics& g) | |||
| text = displayedMessage; | |||
| } | |||
| getLookAndFeel().drawProgressBar (g, *this, | |||
| getWidth(), getHeight(), | |||
| currentValue, text); | |||
| const auto w = getWidth(); | |||
| const auto h = getHeight(); | |||
| const auto v = currentValue; | |||
| getLookAndFeel().drawProgressBar (g, *this, w, h, v, text); | |||
| } | |||
| void ProgressBar::visibilityChanged() | |||
| @@ -30,16 +30,14 @@ namespace juce | |||
| /** | |||
| A progress bar component. | |||
| To use this, just create one and make it visible. It'll run its own timer | |||
| to keep an eye on a variable that you give it, and will automatically | |||
| redraw itself when the variable changes. | |||
| To use this, just create one and make it visible. It'll run its own timer to keep an eye on a | |||
| variable that you give it, and will automatically redraw itself when the variable changes. | |||
| If using LookAndFeel_V4 a circular spinning progress bar will be drawn if | |||
| the width and height of the ProgressBar are equal, otherwise the standard, | |||
| linear ProgressBar will be drawn. | |||
| Two styles of progress bars are supported: circular, and linear bar. If a style isn't given the | |||
| look-and-feel will determine the style based on getDefaultProgressBarStyle(). | |||
| For an easy way of running a background task with a dialog box showing its | |||
| progress, see the ThreadWithProgressWindow class. | |||
| For an easy way of running a background task with a dialog box showing its progress, see | |||
| the ThreadWithProgressWindow class. | |||
| @see ThreadWithProgressWindow | |||
| @@ -50,9 +48,21 @@ class JUCE_API ProgressBar : public Component, | |||
| private Timer | |||
| { | |||
| public: | |||
| /** The types of ProgressBar styles available. | |||
| @see setStyle, getStyle, getResolvedStyle | |||
| */ | |||
| enum class Style | |||
| { | |||
| linear, /**< A linear progress bar. */ | |||
| circular, /**< A circular progress indicator. */ | |||
| }; | |||
| //============================================================================== | |||
| /** Creates a ProgressBar. | |||
| The ProgressBar's style will initially be determined by the look-and-feel. | |||
| @param progress pass in a reference to a double that you're going to | |||
| update with your task's progress. The ProgressBar will | |||
| monitor the value of this variable and will redraw itself | |||
| @@ -63,8 +73,21 @@ public: | |||
| */ | |||
| explicit ProgressBar (double& progress); | |||
| /** Creates a ProgressBar with a specific style. | |||
| @param progress pass in a reference to a double that you're going to | |||
| update with your task's progress. The ProgressBar will | |||
| monitor the value of this variable and will redraw itself | |||
| when the value changes. The range is from 0 to 1.0 and JUCE | |||
| LookAndFeel classes will draw a spinning animation for values | |||
| outside this range. Obviously you'd better be careful not to | |||
| delete this variable while the ProgressBar still exists! | |||
| @param style the style of the progress bar. | |||
| */ | |||
| ProgressBar (double& progress, std::optional<Style> style); | |||
| /** Destructor. */ | |||
| ~ProgressBar() override; | |||
| ~ProgressBar() override = default; | |||
| //============================================================================== | |||
| /** Turns the percentage display on or off. | |||
| @@ -81,6 +104,32 @@ public: | |||
| */ | |||
| void setTextToDisplay (const String& text); | |||
| /** Sets the progress bar's current style. | |||
| You can use this to force getResolvedStyle() to return a particular value. | |||
| If a non-nullopt style is passed, that style will always be returned by | |||
| getResolvedStyle(). Otherwise, if nullopt is passed, getResolvedStyle() will | |||
| return its LookAndFeel's getDefaultProgressBarStyle(). | |||
| @see getStyle, getResolvedStyle | |||
| */ | |||
| void setStyle (std::optional<Style> newStyle); | |||
| /** Returns the progress bar's current style, as set in the constructor or in setStyle(). | |||
| @see setStyle, getResolvedStyle | |||
| */ | |||
| std::optional<Style> getStyle() const { return style; } | |||
| /** Returns the progress bar's current style if it has one, or a default style determined by | |||
| the look-and-feel if it doesn't. | |||
| Use this function in overrides of LookAndFeelMethods::drawProgressBar() in order to | |||
| determine which style to draw. | |||
| @see getStyle, setStyle, LookAndFeelMethods::getDefaultProgressBarStyle | |||
| */ | |||
| Style getResolvedStyle() const; | |||
| //============================================================================== | |||
| /** A set of colour IDs to use to change the colour of various aspects of the bar. | |||
| @@ -109,12 +158,22 @@ public: | |||
| bar that fills the whole space (i.e. to say that the app is still busy but the progress | |||
| isn't known). It can use the current time as a basis for playing an animation. | |||
| To determine which style of progress-bar to draw call getResolvedStyle(). | |||
| (Used by progress bars in AlertWindow). | |||
| @see getResolvedStyle | |||
| */ | |||
| virtual void drawProgressBar (Graphics&, ProgressBar&, int width, int height, | |||
| double progress, const String& textToShow) = 0; | |||
| virtual bool isProgressBarOpaque (ProgressBar&) = 0; | |||
| /** Returns the default style a progress bar should use if one hasn't been set. | |||
| @see setStyle, getResolvedStyle | |||
| */ | |||
| virtual Style getDefaultProgressBarStyle (const ProgressBar&) = 0; | |||
| }; | |||
| /** @internal */ | |||
| @@ -133,10 +192,11 @@ protected: | |||
| private: | |||
| double& progress; | |||
| double currentValue; | |||
| bool displayPercentage; | |||
| std::optional<Style> style; | |||
| double currentValue { jlimit (0.0, 1.0, progress) }; | |||
| bool displayPercentage { true }; | |||
| String displayedMessage, currentMessage; | |||
| uint32 lastCallbackTime; | |||
| uint32 lastCallbackTime { 0 }; | |||
| void timerCallback() override; | |||
| @@ -294,9 +294,9 @@ void AlertWindow::addTextBlock (const String& textBlock) | |||
| } | |||
| //============================================================================== | |||
| void AlertWindow::addProgressBarComponent (double& progressValue) | |||
| void AlertWindow::addProgressBarComponent (double& progressValue, std::optional<ProgressBar::Style> style) | |||
| { | |||
| auto* pb = new ProgressBar (progressValue); | |||
| auto* pb = new ProgressBar (progressValue, style); | |||
| progressBars.add (pb); | |||
| allComps.add (pb); | |||
| addAndMakeVisible (pb); | |||
| @@ -33,11 +33,11 @@ namespace juce | |||
| some static methods for running these. | |||
| For more complex dialogs, an AlertWindow can be created, then it can have some | |||
| buttons and components added to it, and its runModalLoop() method is then used to | |||
| show it. The value returned by runModalLoop() shows which button the | |||
| user pressed to dismiss the box. | |||
| buttons and components added to it, and its enterModalState() method is used to | |||
| show it. The value returned to the ModalComponentManager::Callback shows | |||
| which button the user pressed to dismiss the box. | |||
| @see ThreadWithProgressWindow | |||
| @see ThreadWithProgressWindow, Component::enterModalState | |||
| @tags{GUI} | |||
| */ | |||
| @@ -188,8 +188,13 @@ public: | |||
| @param progressValue a variable that will be repeatedly checked while the | |||
| dialog box is visible, to see how far the process has | |||
| got. The value should be in the range 0 to 1.0 | |||
| @param style determines the style the ProgressBar should adopt. | |||
| By default this use a style automatically chosen by | |||
| the LookAndFeel, but you can force a particular style | |||
| by passing a non-optional value. | |||
| @see ProgressBar::setStyle | |||
| */ | |||
| void addProgressBarComponent (double& progressValue); | |||
| void addProgressBarComponent (double& progressValue, std::optional<ProgressBar::Style> style = std::nullopt); | |||
| //============================================================================== | |||
| /** Adds a user-defined component to the dialog box. | |||