24#include <AppConfigurationBase.h>
30 LoadBar(juce::String label,
bool showPercent =
true,
bool showMax =
true) : juce::Component::Component() { m_label = label; m_showPercent = showPercent; m_showMax = showMax; }
34 void paint(Graphics& g)
override
38 auto bounds = getLocalBounds().toFloat();
40 g.setColour(getLookAndFeel().findColour(juce::LookAndFeel_V4::ColourScheme::windowBackground));
43 auto barBounds = bounds.reduced(margin);
45 auto loadBarHeight = barBounds.getHeight();
46 if (!m_loadsPercent.empty())
47 loadBarHeight = (barBounds.getHeight() / m_loadsPercent.size());
52 for (
auto & loadPercentKV : m_loadsPercent)
54 auto loadPercent = loadPercentKV.second;
55 auto alert = m_alerts[loadPercentKV.first];
57 auto normalPercent = loadPercent;
58 auto warningPercent = 0;
59 auto criticalPercent = 0;
63 warningPercent = loadPercent - normalPercent;
68 criticalPercent = loadPercent - normalPercent - warningPercent;
70 if (loadPercent >= 100)
75 auto individualBarBounds = barBounds.removeFromTop(loadBarHeight);
76 if (i < m_loadsPercent.size()-1)
77 individualBarBounds.removeFromBottom(margin);
81 g.setColour(juce::Colour(0xff, 0x30, 0x02).withAlpha(0.8f));
82 g.fillRect(individualBarBounds);
86 g.setColour(getLookAndFeel().findColour(juce::TextButton::ColourIds::buttonColourId));
87 g.fillRect(individualBarBounds.removeFromLeft(individualBarBounds.getWidth() * (
float(normalPercent) / 100.0f)));
88 if (warningPercent > 0)
90 g.setColour(juce::Colour(0xff, 0xe8, 0x00).withAlpha(0.5f));
91 g.fillRect(individualBarBounds.removeFromLeft(individualBarBounds.getWidth() * (
float(warningPercent) / 25.0f)));
93 if (criticalPercent > 0)
95 g.setColour(juce::Colour(0xff, 0x40, 0x02).withAlpha(0.5f));
96 g.fillRect(individualBarBounds.removeFromLeft(individualBarBounds.getWidth() * (
float(criticalPercent) / 5.0f)));
100 avgLoad += loadPercent;
101 if (maxLoad < loadPercent)
102 maxLoad = loadPercent;
106 if (!m_loadsPercent.empty())
107 avgLoad /=
int(m_loadsPercent.size());
109 auto labelText = m_label;
111 labelText += juce::String(
" ") + juce::String(m_showMax ? maxLoad : avgLoad) + juce::String(
"%");
113 g.setColour(getLookAndFeel().findColour(juce::TextButton::ColourIds::textColourOnId));
114 g.drawText(labelText, bounds, juce::Justification::centred);
116 void mouseUp(
const MouseEvent& event)
override
118 if (contains(event.position))
119 JUCEAppBasics::ServiceTopologyManager::showServiceTopologyMenu(m_sessionTopology);
125 m_sessionTopology = sessionTopology;
131 m_loadsPercent[id] = loadPercent;
136 m_alerts[id] = alert;
141 std::map<int, int> m_loadsPercent;
142 std::map<int, bool> m_alerts;
143 juce::String m_label;
144 bool m_showPercent =
false;
145 bool m_showMax =
false;
146 JUCEAppBasics::SessionServiceTopology m_sessionTopology;
159 g.fillAll(getLookAndFeel().findColour(juce::ResizableWindow::backgroundColourId));
171 m_toggleStandaloneWindowButton = std::make_unique<juce::DrawableButton>(
"Show as standalone window", juce::DrawableButton::ButtonStyle::ImageFitted);
172 m_toggleStandaloneWindowButton->setTooltip(
"Show as standalone window");
175 m_toggleStandaloneWindowButton->setEnabled(
false);
179 m_audioSetupButton = std::make_unique<juce::DrawableButton>(
"Audio Device Setup", juce::DrawableButton::ButtonStyle::ImageFitted);
180 m_audioSetupButton->setTooltip(
"Audio Device Setup");
181 m_audioSetupButton->onClick = [
this] {
196 m_appSettingsButton = std::make_unique<juce::DrawableButton>(
"Application settings", juce::DrawableButton::ButtonStyle::ImageFitted);
197 m_appSettingsButton->setTooltip(
"Application settings");
198 m_appSettingsButton->onClick = [
this] {
211 auto loadDrawable = juce::Drawable::createFromSVG(*juce::XmlDocument::parse(BinaryData::folder_open24px_svg).
get());
214 auto saveDrawable = juce::Drawable::createFromSVG(*juce::XmlDocument::parse(BinaryData::save24px_svg).
get());
221 m_aboutComponent = std::make_unique<AboutComponent>(BinaryData::MemaRect_png, BinaryData::MemaRect_pngSize);
222 m_aboutButton = std::make_unique<juce::DrawableButton>(
"About", juce::DrawableButton::ButtonStyle::ImageFitted);
223 m_aboutButton->setTooltip(juce::String(
"About") + juce::JUCEApplication::getInstance()->getApplicationName());
224 m_aboutButton->onClick = [
this] {
226 aboutMenu.addCustomItem(1, std::make_unique<CustomAboutItem>(m_aboutComponent.get(), juce::Rectangle<int>(250, 250)),
nullptr, juce::String(
"Info about") + juce::JUCEApplication::getInstance()->getApplicationName());
227 aboutMenu.showMenuAsync(juce::PopupMenu::Options());
231 m_powerButton = std::make_unique<juce::DrawableButton>(
"Quit application", juce::DrawableButton::ButtonStyle::ImageFitted);
232 m_powerButton->setTooltip(
"Quit application");
233 m_powerButton->onClick = [
this] {
234 juce::JUCEApplication::getInstance()->quit();
238 m_emptySpace = std::make_unique<EmptySpace>();
241 m_sysLoadBar = std::make_unique<LoadBar>(
"PLoad");
244 m_netHealthBar = std::make_unique<LoadBar>(
"NLoad");
247 juce::Desktop::getInstance().addDarkModeSettingListener(
this);
254 juce::Desktop::getInstance().removeDarkModeSettingListener(
this);
267 int styleFlags = juce::ComponentPeer::windowHasDropShadow
268 | juce::ComponentPeer::windowAppearsOnTaskbar
269 | juce::ComponentPeer::windowHasTitleBar;
285 return m_isStandaloneWindow;
290 if (m_editorComponent)
303 if (
width < (2 * sc_loadNetWidth + 5 * sc_buttonSize))
304 width = 2 * sc_loadNetWidth + 5 * sc_buttonSize;
321 m_netHealthBar->setLoadPercent(
int(
netLoad.second.first * 100.0),
netLoad.first);
354 if (m_appSettingsButton)
357 if (m_audioSetupButton)
360 if (m_toggleStandaloneWindowButton)
369 m_netHealthBar->setBounds(
setupElementArea.removeFromLeft(sc_loadNetWidth));
376 if (m_editorComponent)
382 if (!m_followLocalStyle)
388 applyPaletteStyle(JUCEAppBasics::CustomLookAndFeel::PS_Dark);
393 applyPaletteStyle(JUCEAppBasics::CustomLookAndFeel::PS_Light);
399void MemaUIComponent::applyPaletteStyle(
const JUCEAppBasics::CustomLookAndFeel::PaletteStyle& paletteStyle)
407 auto powerDrawable = juce::Drawable::createFromSVG(*juce::XmlDocument::parse(BinaryData::power_settings_24dp_svg).
get());
419 auto aboutButtonDrawable = juce::Drawable::createFromSVG(*juce::XmlDocument::parse(BinaryData::question_mark_24dp_svg).
get());
430 applyMeteringColour();
438 if (!m_followLocalStyle)
456 if (m_followLocalStyle)
459 applyPaletteStyle(JUCEAppBasics::CustomLookAndFeel::PaletteStyle(
paletteStyle));
475void MemaUIComponent::handleSettingsMenuResult(
int selectedId)
483 handleSettingsLookAndFeelMenuResult(
selectedId);
487 handleSettingsMeteringColourMenuResult(
selectedId);
504void MemaUIComponent::handleSettingsLookAndFeelMenuResult(
int selectedId)
517 m_followLocalStyle =
true;
522 m_followLocalStyle =
false;
523 applyPaletteStyle(JUCEAppBasics::CustomLookAndFeel::PaletteStyle::PS_Dark);
527 m_followLocalStyle =
false;
528 applyPaletteStyle(JUCEAppBasics::CustomLookAndFeel::PaletteStyle::PS_Light);
536void MemaUIComponent::handleSettingsMeteringColourMenuResult(
int selectedId)
551 setMeteringColour(juce::Colours::forestgreen);
555 setMeteringColour(juce::Colours::orangered);
559 setMeteringColour(juce::Colours::dodgerblue);
563 setMeteringColour(juce::Colours::deeppink);
567 setMeteringColour(juce::Colour(0xd1, 0xff, 0x4f));
574void MemaUIComponent::setMeteringColour(
const juce::Colour& meteringColour)
578 applyMeteringColour();
581void MemaUIComponent::applyMeteringColour()
588 case JUCEAppBasics::CustomLookAndFeel::PS_Light:
589 getLookAndFeel().setColour(JUCEAppBasics::CustomLookAndFeel::ColourIds::MeteringPeakColourId, m_meteringColour.brighter());
590 getLookAndFeel().setColour(JUCEAppBasics::CustomLookAndFeel::ColourIds::MeteringRmsColourId, m_meteringColour);
592 case JUCEAppBasics::CustomLookAndFeel::PS_Dark:
594 getLookAndFeel().setColour(JUCEAppBasics::CustomLookAndFeel::ColourIds::MeteringPeakColourId, m_meteringColour.darker());
595 getLookAndFeel().setColour(JUCEAppBasics::CustomLookAndFeel::ColourIds::MeteringRmsColourId, m_meteringColour);
void paint(Graphics &g) override
void mouseUp(const MouseEvent &event) override
void setAlert(bool alert, int id=0)
void setSessionTopology(const JUCEAppBasics::SessionServiceTopology &sessionTopology)
void setLoadPercent(int loadPercent, int id=0)
LoadBar(juce::String label, bool showPercent=true, bool showMax=true)
void paint(Graphics &g) override
static juce::String getTagName(TagID ID)
@ UICONFIG
UI layout and appearance.
static juce::String getAttributeName(AttributeID ID)
@ METERINGCOLOR
Metering bar colour.
@ PALETTESTYLE
Look-and-feel palette style index.
std::function< void()> onDeleted
Called when this component is destroyed.
std::function< void(const JUCEAppBasics::CustomLookAndFeel::PaletteStyle &)> onPaletteStyleChange
Called when palette style changes.
std::function< void()> onSettingsChanged
Called when any setting changes.
std::function< void()> onLoadConfig
Called when the user selects Load Config.
std::function< void(bool)> onToggleStandaloneWindow
Called when the user toggles standalone/popup mode.
@ SaveConfig
Save configuration to file.
@ MeteringColour_Blue
Blue metering bars.
@ MeteringColour_Pink
Pink metering bars.
@ LookAndFeel_Dark
Force dark look-and-feel.
@ LookAndFeel_Automatic
Match the host OS appearance.
@ LoadConfig
Load configuration from file.
@ MeteringColour_Red
Red metering bars.
@ MeteringColour_Green
Green metering bars (default).
@ LookAndFeel_Light
Force light look-and-feel.
@ MeteringColour_Laser
High-visibility laser-green metering bars.
~MemaUIComponent() override
void setStandaloneWindow(bool standalone)
Switches between popup mode (embedded in the system tray/menubar popover) and standalone window mode.
void updateSessionServiceTopology(const JUCEAppBasics::SessionServiceTopology &serviceDiscoveryTopologyString)
Updates the service-topology display (if any) with freshly discovered Mema instances.
void paint(Graphics &) override
Paints the component background using the current look-and-feel background colour.
void setEditorComponent(juce::Component *editorComponent)
Attaches the MemaProcessorEditor to be displayed in the central content area.
std::function< void()> onLookAndFeelChanged
Called after a look-and-feel change is applied.
std::function< void()> onAudioSetupMenuClicked
Called when the audio-setup button is clicked.
bool setStateXml(juce::XmlElement *stateXml) override
Restores UI state from a <UICONFIG> XmlElement.
void updateCpuUsageBar(int loadPercent)
Updates the CPU-load progress bar to reflect the current audio processing load.
std::unique_ptr< juce::XmlElement > createStateXml() override
Serialises the UI state (standalone mode, palette style, metering colour) to XML.
bool isStandaloneWindow()
Returns true when the component is currently shown in standalone window mode.
void resized() override
Lays out all child components.
std::function< void()> onSaveConfig
Called when the user selects Save Config.
void darkModeSettingChanged() override
Responds to an OS dark-mode toggle.
void updateNetworkUsage(const std::map< int, std::pair< double, bool > > &netLoads)
Updates the network-health bar with per-connection traffic metrics.
void handleEditorSizeChangeRequest(const juce::Rectangle< int > &requestedSize)
Responds to a resize request from the embedded editor.
MemaUIComponent()
Constructs the UI component and wires up child components.
void lookAndFeelChanged() override
Propagates a look-and-feel change to all child buttons and bars.