Skip to content

Commit 74d3598

Browse files
committed
Merge branch 'main' into dev/spectral_processor
2 parents bf844ae + 12b7962 commit 74d3598

6 files changed

Lines changed: 92 additions & 36 deletions

File tree

docs/tutorials/DataTree Tutorial.md

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ String version = appSettings.getProperty("version", "unknown");
3838
bool debugMode = appSettings.getProperty("debug", false);
3939
int maxConn = appSettings.getProperty("maxConnections", 50);
4040

41-
DBG("App version: " << version);
42-
DBG("Debug mode: " << (debugMode ? "enabled" : "disabled"));
41+
YUP_DBG("App version: " << version);
42+
YUP_DBG("Debug mode: " << (debugMode ? "enabled" : "disabled"));
4343
```
4444
4545
### Working with Child Nodes
@@ -68,8 +68,8 @@ if (foundServer.isValid())
6868
// Iterate over children
6969
for (const auto& child : appSettings)
7070
{
71-
DBG("Child type: " << child.getType().toString());
72-
DBG("Properties: " << child.getNumProperties());
71+
YUP_DBG("Child type: " << child.getType().toString());
72+
YUP_DBG("Properties: " << child.getNumProperties());
7373
}
7474
```
7575

@@ -271,7 +271,7 @@ auto firstEnabledButton = DataTreeQuery::from(appRoot)
271271
272272
if (firstEnabledButton.isValid())
273273
{
274-
DBG("First enabled button: " << firstEnabledButton.getProperty("text").toString());
274+
YUP_DBG("First enabled button: " << firstEnabledButton.getProperty("text").toString());
275275
}
276276
```
277277

@@ -316,7 +316,7 @@ if (firstButton.isValid())
316316
auto siblings = DataTreeQuery::from(firstButton)
317317
.siblings()
318318
.nodes();
319-
DBG("Button has " << siblings.size() << " siblings");
319+
YUP_DBG("Button has " << siblings.size() << " siblings");
320320
}
321321
```
322322

@@ -377,7 +377,7 @@ auto buttonTexts = DataTreeQuery::from(appRoot)
377377
378378
for (const String& text : buttonTexts)
379379
{
380-
DBG("Button text: " << text);
380+
YUP_DBG("Button text: " << text);
381381
}
382382
383383
// Extract multiple properties from windows
@@ -397,7 +397,7 @@ auto buttonInfo = DataTreeQuery::from(appRoot)
397397
398398
for (const String& info : buttonInfo)
399399
{
400-
DBG("Button info: " << info);
400+
YUP_DBG("Button info: " << info);
401401
}
402402
```
403403

@@ -588,7 +588,7 @@ auto buttonsByState = DataTreeQuery::from(appRoot)
588588
589589
for (const auto& [state, buttons] : buttonsByState)
590590
{
591-
DBG(state.toString() << ": " << buttons.size() << " buttons");
591+
YUP_DBG(state.toString() << ": " << buttons.size() << " buttons");
592592
}
593593
594594
// Group panels by width ranges
@@ -695,18 +695,18 @@ However, there are still important validation patterns to follow:
695695
auto result = DataTreeQuery::xpath(appRoot, "//Invalid[Syntax");
696696
if (result.empty())
697697
{
698-
DBG("Query returned no results (possibly due to syntax error)");
698+
YUP_DBG("Query returned no results (possibly due to syntax error)");
699699
}
700700

701701
// Check for valid results
702702
auto buttons = DataTreeQuery::from(appRoot).descendants("Button").nodes();
703703
if (buttons.empty())
704704
{
705-
DBG("No buttons found");
705+
YUP_DBG("No buttons found");
706706
}
707707
else
708708
{
709-
DBG("Found " << buttons.size() << " buttons");
709+
YUP_DBG("Found " << buttons.size() << " buttons");
710710
}
711711

712712
// Safe property access
@@ -811,7 +811,7 @@ String schemaJson = R"({
811811
auto schema = DataTreeSchema::fromJsonSchemaString(schemaJson);
812812
if (!schema)
813813
{
814-
DBG("Failed to load schema");
814+
YUP_DBG("Failed to load schema");
815815
return;
816816
}
817817
```
@@ -829,14 +829,14 @@ auto serverConfig = schema->createChildNode("AppSettings", "ServerConfig");
829829

830830
// Query schema metadata
831831
auto themeInfo = schema->getPropertyInfo("AppSettings", "theme");
832-
DBG("Theme type: " << themeInfo.type);
833-
DBG("Default theme: " << themeInfo.defaultValue.toString());
834-
DBG("Allowed values: " << themeInfo.enumValues.size());
832+
YUP_DBG("Theme type: " << themeInfo.type);
833+
YUP_DBG("Default theme: " << themeInfo.defaultValue.toString());
834+
YUP_DBG("Allowed values: " << themeInfo.enumValues.size());
835835

836836
// Check node type capabilities
837837
auto childConstraints = schema->getChildConstraints("AppSettings");
838-
DBG("Max children: " << childConstraints.maxCount);
839-
DBG("Allowed child types: " << childConstraints.allowedTypes.size());
838+
YUP_DBG("Max children: " << childConstraints.maxCount);
839+
YUP_DBG("Allowed child types: " << childConstraints.allowedTypes.size());
840840
```
841841
842842
### Validated Transactions
@@ -879,12 +879,12 @@ if (childResult.wasOk())
879879
auto validationResult = schema->validate(appSettings);
880880
if (validationResult.failed())
881881
{
882-
DBG("Validation failed: " << validationResult.getErrorMessage());
882+
YUP_DBG("Validation failed: " << validationResult.getErrorMessage());
883883
// Handle validation errors
884884
}
885885
else
886886
{
887-
DBG("Tree structure is valid");
887+
YUP_DBG("Tree structure is valid");
888888
// Safe to proceed with application logic
889889
}
890890
```
@@ -911,13 +911,13 @@ public:
911911
{
912912
// Reading from CachedValue is fast (cached)
913913
String currentTheme = theme.get();
914-
DBG("Current theme: " << currentTheme);
914+
YUP_DBG("Current theme: " << currentTheme);
915915
916916
// Setting triggers cache invalidation and change notifications
917917
theme.set("dark");
918918
919919
// Next read will be from cache again
920-
DBG("New theme: " << theme.get());
920+
YUP_DBG("New theme: " << theme.get());
921921
}
922922
923923
void updateFontSize(int newSize)
@@ -999,12 +999,12 @@ public:
999999
, x(tree, "x", 0.0f)
10001000
, y(tree, "y", 0.0f)
10011001
{
1002-
DBG("Created component: " << getName());
1002+
YUP_DBG("Created component: " << getName());
10031003
}
10041004

10051005
~UIComponent()
10061006
{
1007-
DBG("Destroyed component: " << getName());
1007+
YUP_DBG("Destroyed component: " << getName());
10081008
}
10091009

10101010
// Getters using CachedValue
@@ -1068,19 +1068,19 @@ protected:
10681068
// Optional: receive notifications
10691069
void newObjectAdded(UIComponent* object) override
10701070
{
1071-
DBG("UI Component added: " << object->getName());
1071+
YUP_DBG("UI Component added: " << object->getName());
10721072
// Update UI, register callbacks, etc.
10731073
}
10741074

10751075
void objectRemoved(UIComponent* object) override
10761076
{
1077-
DBG("UI Component removed: " << object->getName());
1077+
YUP_DBG("UI Component removed: " << object->getName());
10781078
// Clean up UI, unregister callbacks, etc.
10791079
}
10801080

10811081
void objectOrderChanged() override
10821082
{
1083-
DBG("UI Component order changed");
1083+
YUP_DBG("UI Component order changed");
10841084
// Update rendering order, etc.
10851085
}
10861086
};
@@ -1131,4 +1131,4 @@ EXPECT_EQ(200.0f, buttonObj->getX()); // CachedValue reflects change
11311131
EXPECT_EQ(0, components.objects.size());
11321132
```
11331133

1134-
This tutorial provides a solid foundation for using the YUP DataTree system effectively. The combination of DataTree, DataTreeSchema, DataTreeQuery, DataTreeObjectList and CachedValue provides a powerful, type-safe, and efficient way to manage hierarchical data in your applications.
1134+
This tutorial provides a solid foundation for using the YUP DataTree system effectively. The combination of DataTree, DataTreeSchema, DataTreeQuery, DataTreeObjectList and CachedValue provides a powerful, type-safe, and efficient way to manage hierarchical data in your applications.

modules/yup_audio_devices/audio_io/yup_AudioDeviceManager.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ AudioDeviceManager::AudioDeviceManager()
148148

149149
AudioDeviceManager::~AudioDeviceManager()
150150
{
151+
enabledMidiInputs.clear();
151152
currentAudioDevice.reset();
152153
defaultMidiOutput.reset();
153154
}

modules/yup_gui/widgets/yup_ComboBox.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,10 +207,23 @@ void ComboBox::mouseDown (const MouseEvent& event)
207207
{
208208
takeKeyboardFocus();
209209

210+
if (ignoreMouseDownAfterPopupDismissal)
211+
{
212+
ignoreMouseDownAfterPopupDismissal = false;
213+
popupMenu = nullptr;
214+
repaint();
215+
return;
216+
}
217+
210218
if (popupMenu == nullptr || ! popupMenu->isBeingShown())
219+
{
211220
showPopup();
221+
}
212222
else
223+
{
224+
const auto dismissingFromThisMouseDown = ScopedValueSetter<bool> (dismissingPopupFromMouseDown, true);
213225
hidePopup();
226+
}
214227

215228
repaint();
216229
}
@@ -251,7 +264,20 @@ void ComboBox::showPopup()
251264
popupMenu->show ([this] (int selectedItemID)
252265
{
253266
if (selectedItemID != 0)
267+
{
254268
setSelectedId (selectedItemID);
269+
}
270+
else if (! dismissingPopupFromMouseDown)
271+
{
272+
ignoreMouseDownAfterPopupDismissal = true;
273+
274+
WeakReference<Component> self = this;
275+
MessageManager::callAsync ([this, self]
276+
{
277+
if (self.get() != nullptr)
278+
ignoreMouseDownAfterPopupDismissal = false;
279+
});
280+
}
255281

256282
takeKeyboardFocus();
257283
});

modules/yup_gui/widgets/yup_ComboBox.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ class YUP_API ComboBox : public Component
199199
StyledText styledText;
200200
PopupMenu::Ptr popupMenu;
201201
bool textIsEditable = false;
202+
bool ignoreMouseDownAfterPopupDismissal = false;
203+
bool dismissingPopupFromMouseDown = false;
202204

203205
YUP_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ComboBox)
204206
};

modules/yup_gui/widgets/yup_Label.cpp

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -126,23 +126,29 @@ void Label::prepareText()
126126
if (! needsUpdate)
127127
return;
128128

129-
auto fontSize = getHeight() * 0.8f; // TODO - needs config
130-
auto fontToUse = ApplicationTheme::getGlobalTheme()->getDefaultFont().withHeight (fontSize);
131-
if (font)
132-
fontToUse = *font;
129+
auto fontToUse = font.value_or (ApplicationTheme::getGlobalTheme()->getDefaultFont());
133130

131+
auto setup = [&] (const Font& f)
134132
{
135133
auto modifier = styledText.startUpdate();
136134
modifier.setMaxSize (getSize());
137135
modifier.setHorizontalAlign (StyledText::horizontalAlignFromJustification (justification));
138136
modifier.setVerticalAlign (StyledText::verticalAlignFromJustification (justification));
139-
modifier.setOverflow (StyledText::ellipsis);
137+
modifier.setOverflow (StyledText::visible);
140138
modifier.setWrap (StyledText::noWrap);
141-
142139
modifier.clear();
143-
144140
if (text.isNotEmpty())
145-
modifier.appendText (text, fontToUse);
141+
modifier.appendText (text, f);
142+
};
143+
144+
setup (fontToUse);
145+
146+
if (text.isNotEmpty())
147+
{
148+
const float availableWidth = static_cast<float> (getWidth());
149+
const float textWidth = styledText.getComputedTextBounds().getWidth();
150+
if (availableWidth > 0.0f && textWidth > availableWidth)
151+
setup (fontToUse.withHeight (fontToUse.getHeight() * (availableWidth / textWidth)));
146152
}
147153

148154
needsUpdate = false;

tests/yup_gui/yup_ComboBox.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,27 @@ TEST_F (ComboBoxTest, ComponentIdIsSet)
294294
EXPECT_EQ (String ("uniqueComboBoxId"), newComboBox->getComponentID());
295295
}
296296

297+
TEST_F (ComboBoxTest, PopupDismissalClickDoesNotReopenPopup)
298+
{
299+
comboBox->addItem (kTestText1, kTestId1);
300+
comboBox->addItem (kTestText2, kTestId2);
301+
302+
MouseEvent clickEvent (MouseEvent::leftButton, KeyModifiers(), Point<float> (10.0f, 10.0f), comboBox.get());
303+
304+
comboBox->mouseDown (clickEvent);
305+
ASSERT_TRUE (comboBox->isPopupShown());
306+
307+
PopupMenu::dismissAllPopups();
308+
309+
comboBox->mouseDown (clickEvent);
310+
EXPECT_FALSE (comboBox->isPopupShown());
311+
312+
comboBox->mouseDown (clickEvent);
313+
EXPECT_TRUE (comboBox->isPopupShown());
314+
315+
PopupMenu::dismissAllPopups();
316+
}
317+
297318
TEST_F (ComboBoxTest, BoundsAndSizeWork)
298319
{
299320
Rectangle<int> bounds (10, 20, 150, 25);

0 commit comments

Comments
 (0)