@@ -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. | |||