Skip to content

Commit cfe1548

Browse files
committed
MIDI fixes, welcome panel fixes
1 parent dde8da9 commit cfe1548

File tree

3 files changed

+136
-39
lines changed

3 files changed

+136
-39
lines changed

Source/Components/WelcomePanel.h

Lines changed: 127 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class WelcomePanel : public Component
7070

7171
void setSearchQuery(String const& searchQuery)
7272
{
73-
setVisible(tileName.upToFirstOccurrenceOf(".pd", false, false).containsIgnoreCase(searchQuery));
73+
setVisible(tileName.containsIgnoreCase(searchQuery));
7474
}
7575

7676
void paint(Graphics& g) override
@@ -247,16 +247,16 @@ class WelcomePanel : public Component
247247
: NVGComponent(this)
248248
, editor(pluginEditor)
249249
{
250-
recentlyOpenedViewport.setViewedComponent(&recentlyOpenedComponent, false);
251-
recentlyOpenedViewport.setScrollBarsShown(true, false, false, false);
252-
recentlyOpenedComponent.setVisible(true);
250+
viewport.setViewedComponent(&contentComponent, false);
251+
viewport.setScrollBarsShown(true, false, false, false);
252+
contentComponent.setVisible(true);
253253
#if JUCE_IOS
254-
recentlyOpenedViewport.setVisible(OSUtils::isIPad());
254+
viewport.setVisible(OSUtils::isIPad());
255255
#else
256-
recentlyOpenedViewport.setVisible(true);
256+
viewport.setVisible(true);
257257
#endif
258258

259-
addChildComponent(recentlyOpenedViewport);
259+
addChildComponent(viewport);
260260

261261
// A top rectangle component that hides anything behind (we use this instead of scissoring)
262262
topFillAllRect.setBGColour(findColour(PlugDataColour::panelBackgroundColourId));
@@ -286,6 +286,7 @@ class WelcomePanel : public Component
286286
if(newPatchTile) newPatchTile->setVisible(searchQuery.isEmpty());
287287
if(openPatchTile) openPatchTile->setVisible(searchQuery.isEmpty());
288288

289+
auto& tiles = currentTab == Home ? recentlyOpenedTiles : libraryTiles;
289290
for (auto* tile : tiles) {
290291
tile->setSearchQuery(searchQuery);
291292
}
@@ -306,31 +307,29 @@ class WelcomePanel : public Component
306307
// Adjust the tile width to fit within the available width
307308
int actualTileWidth = (totalWidth - (numColumns - 1) * tileSpacing) / numColumns;
308309

309-
if (newPatchTile && newPatchTile->isVisible())
310+
if (newPatchTile && currentTab == Home)
310311
newPatchTile->setBounds(rowBounds.removeFromLeft(actualTileWidth));
311312
rowBounds.removeFromLeft(4);
312-
if (openPatchTile && openPatchTile->isVisible())
313+
if (openPatchTile && currentTab == Home)
313314
openPatchTile->setBounds(rowBounds.removeFromLeft(actualTileWidth));
314315

315-
auto viewPos = recentlyOpenedViewport.getViewPosition();
316-
recentlyOpenedViewport.setBounds(getLocalBounds().withTrimmedTop((newPatchTile && newPatchTile->isVisible()) ? 200 : 0));
317-
318-
// Place a rectangle directly behind the newTile & openTile so to hide any content that draws behind it.
319-
topFillAllRect.setBounds(0, 0, getWidth(), recentlyOpenedViewport.getY());
316+
auto viewPos = viewport.getViewPosition();
317+
viewport.setBounds(getLocalBounds());
320318

319+
auto& tiles = currentTab == Home ? recentlyOpenedTiles : libraryTiles;
321320
int numRows = (tiles.size() + numColumns - 1) / numColumns;
322-
int totalHeight = numRows * 160;
321+
int totalHeight = (numRows * 160) + 200;
323322

324-
auto scrollable = Rectangle<int>(24, 6, totalWidth + 24, totalHeight + 24);
325-
recentlyOpenedComponent.setBounds(scrollable);
323+
auto tilesBounds = Rectangle<int>(24, currentTab == Home ? 206 : 6, totalWidth + 24, totalHeight + 24);
324+
contentComponent.setBounds(tilesBounds);
326325

327-
// Start positioning the tiles
328-
rowBounds = scrollable.removeFromTop(160);
326+
// Start positioning the recentlyOpenedTiles
327+
rowBounds = tilesBounds.removeFromTop(160);
329328
for (auto* tile : tiles) {
330329
if(!tile->isVisible()) continue;
331330
if (tile->isFavourited) {
332331
if (rowBounds.getWidth() < actualTileWidth) {
333-
rowBounds = scrollable.removeFromTop(160);
332+
rowBounds = tilesBounds.removeFromTop(160);
334333
}
335334
tile->setBounds(rowBounds.removeFromLeft(actualTileWidth));
336335
rowBounds.removeFromLeft(tileSpacing);
@@ -341,13 +340,13 @@ class WelcomePanel : public Component
341340
if(!tile->isVisible()) continue;
342341
if (!tile->isFavourited) {
343342
if (rowBounds.getWidth() < actualTileWidth) {
344-
rowBounds = scrollable.removeFromTop(160);
343+
rowBounds = tilesBounds.removeFromTop(160);
345344
}
346345
tile->setBounds(rowBounds.removeFromLeft(actualTileWidth));
347346
rowBounds.removeFromLeft(tileSpacing);
348347
}
349348
}
350-
recentlyOpenedViewport.setViewPosition(viewPos);
349+
viewport.setViewPosition(viewPos);
351350
}
352351

353352
void setShownTab(WelcomePanel::Tab tab)
@@ -357,23 +356,34 @@ class WelcomePanel : public Component
357356
{
358357
newPatchTile->setVisible(true);
359358
openPatchTile->setVisible(true);
360-
for(auto* tile : tiles)
359+
for(auto* tile : recentlyOpenedTiles)
361360
{
362361
tile->setVisible(true);
363362
}
363+
for(auto* tile : libraryTiles)
364+
{
365+
tile->setVisible(false);
366+
}
364367
}
365368
else {
366369
newPatchTile->setVisible(false);
367370
openPatchTile->setVisible(false);
368-
for(auto* tile : tiles)
371+
for(auto* tile : recentlyOpenedTiles)
369372
{
370373
tile->setVisible(false);
371374
}
375+
for(auto* tile : libraryTiles)
376+
{
377+
tile->setVisible(true);
378+
}
372379
}
380+
381+
triggerAsyncUpdate();
373382
}
374383

375384
void handleAsyncUpdate() override
376385
{
386+
// TODO: why are we updating this??
377387
newPatchTile = std::make_unique<WelcomePanelTile>(*this, "New Patch", "Create a new empty patch", newIcon, findColour(PlugDataColour::panelTextColourId), 0.33f, false);
378388
openPatchTile = std::make_unique<WelcomePanelTile>(*this, "Open Patch", "Browse for a patch to open", openIcon, findColour(PlugDataColour::panelTextColourId), 0.33f, false);
379389

@@ -383,10 +393,10 @@ class WelcomePanel : public Component
383393
topFillAllRect.setBGColour(findColour(PlugDataColour::panelBackgroundColourId));
384394
addAndMakeVisible(topFillAllRect);
385395

386-
addAndMakeVisible(*newPatchTile);
387-
addAndMakeVisible(*openPatchTile);
396+
contentComponent.addAndMakeVisible(*newPatchTile);
397+
contentComponent.addAndMakeVisible(*openPatchTile);
388398

389-
tiles.clear();
399+
recentlyOpenedTiles.clear();
390400

391401
auto settingsTree = SettingsFile::getInstance()->getValueTree();
392402
auto recentlyOpenedTree = settingsTree.getChildWithName("RecentlyOpened");
@@ -435,7 +445,7 @@ class WelcomePanel : public Component
435445
String time = openTime.toString(false, true, false, true);
436446
String timeDescription = date + ", " + time;
437447

438-
auto* tile = tiles.add(new WelcomePanelTile(*this, patchFile.getFileName(), timeDescription, silhoutteSvg, snapshotColour, 1.0f, favourited, thumbImage));
448+
auto* tile = recentlyOpenedTiles.add(new WelcomePanelTile(*this, patchFile.getFileNameWithoutExtension(), timeDescription, silhoutteSvg, snapshotColour, 1.0f, favourited, thumbImage));
439449
tile->onClick = [this, patchFile]() mutable {
440450
if (patchFile.existsAsFile()) {
441451
editor->pd->autosave->checkForMoreRecentAutosave(patchFile, editor, [this, patchFile]() {
@@ -456,12 +466,77 @@ class WelcomePanel : public Component
456466
subTree.setProperty("Pinned", shouldBeFavourite, nullptr);
457467
resized();
458468
};
459-
recentlyOpenedComponent.addAndMakeVisible(tile);
469+
contentComponent.addAndMakeVisible(tile);
460470
}
461471
}
462472

473+
findLibraryPatches();
463474
resized();
464475
}
476+
477+
void findLibraryPatches()
478+
{
479+
libraryTiles.clear();
480+
481+
auto addTile = [this](File& patchFile){
482+
auto patchThumbnailBase = File(patchFile.getParentDirectory().getFullPathName() + "\\" + patchFile.getFileNameWithoutExtension() + "_thumb");
483+
StringArray possibleExtensions { ".png", ".jpg", ".jpeg", ".gif" };
484+
485+
float scale = 1.0f;
486+
Image thumbImage;
487+
for (auto& ext : possibleExtensions) {
488+
auto patchThumbnail = patchThumbnailBase.withFileExtension(ext);
489+
if (patchThumbnail.existsAsFile()) {
490+
FileInputStream fileStream(patchThumbnail);
491+
if (fileStream.openedOk()) {
492+
thumbImage = ImageFileFormat::loadFrom(fileStream).convertedToFormat(Image::ARGB);
493+
break;
494+
}
495+
}
496+
}
497+
String placeholderIcon;
498+
if(!thumbImage.isValid())
499+
{
500+
scale = 0.6f;
501+
placeholderIcon = libraryPlaceholderIcon;
502+
}
503+
auto snapshotColour = LookAndFeel::getDefaultLookAndFeel().findColour(PlugDataColour::objectSelectedOutlineColourId).withAlpha(0.3f);
504+
505+
auto* tile = libraryTiles.add(new WelcomePanelTile(*this, patchFile.getFileNameWithoutExtension(), "", placeholderIcon, snapshotColour, scale, false, thumbImage));
506+
tile->onClick = [this, patchFile]() mutable {
507+
if (patchFile.existsAsFile()) {
508+
editor->pd->autosave->checkForMoreRecentAutosave(patchFile, editor, [this, patchFile]() {
509+
editor->getTabComponent().openPatch(URL(patchFile));
510+
SettingsFile::getInstance()->addToRecentlyOpened(patchFile);
511+
});
512+
} else {
513+
editor->pd->logError("Patch not found");
514+
}
515+
};
516+
contentComponent.addAndMakeVisible(tile);
517+
};
518+
auto patchesFolder = ProjectInfo::appDataDir.getChildFile("Patches");
519+
for(auto& file : OSUtils::iterateDirectory(patchesFolder, false, false))
520+
{
521+
if(OSUtils::isDirectoryFast(file.getFullPathName()))
522+
{
523+
for(auto& subfile : OSUtils::iterateDirectory(file, false, false))
524+
{
525+
if(subfile.hasFileExtension("pd"))
526+
{
527+
addTile(subfile);
528+
break;
529+
}
530+
}
531+
}
532+
else {
533+
if(file.hasFileExtension("pd"))
534+
{
535+
addTile(file);
536+
}
537+
}
538+
}
539+
}
465540

466541
void show()
467542
{
@@ -486,10 +561,10 @@ class WelcomePanel : public Component
486561
g.reduceClipRegion(editor->nvgSurface.getInvalidArea());
487562
paintEntireComponent(g, false);
488563

489-
auto gradient = nvgLinearGradient(nvg, 0, recentlyOpenedViewport.getY(), 0, recentlyOpenedViewport.getY() + 20, convertColour(findColour(PlugDataColour::panelBackgroundColourId)), nvgRGBA(255, 255, 255, 0));
564+
auto gradient = nvgLinearGradient(nvg, 0, viewport.getY(), 0, viewport.getY() + 20, convertColour(findColour(PlugDataColour::panelBackgroundColourId)), nvgRGBA(255, 255, 255, 0));
490565

491566
nvgFillPaint(nvg, gradient);
492-
nvgFillRect(nvg, recentlyOpenedViewport.getX() + 8, recentlyOpenedViewport.getY(), recentlyOpenedViewport.getWidth() - 16, 20);
567+
nvgFillRect(nvg, viewport.getX() + 8, viewport.getY(), viewport.getWidth() - 16, 20);
493568
}
494569

495570
void lookAndFeelChanged() override
@@ -511,22 +586,39 @@ class WelcomePanel : public Component
511586
"d=\"M1180 555h506q72 0 126 47t64 118v13l2 14v768q0 76 -52 131t-128 60h-12h-1324q-76 0 -131 -51.5t-59 -127.5l-2 -12v-620l530 2l17 -2q51 -4 92 -33l4 -3t6 -5l4 -2zM700 342q59 0 109 32l14 11l181 149l-263 219l-8 4q-10 8 -24 11h-9h-530v-236q0 -76 52 -131\n"
512587
"t128 -59h12h338z\" />\n"
513588
"</svg>\n";
589+
590+
static inline String const libraryPlaceholderIcon = "<svg width=\"864\" height=\"864\" viewBox=\"0 0 864 864\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n"
591+
"<path d=\"M538.114 201.488C550.72 201.488 560.94 191.268 560.94 178.662C560.94 166.055 550.72 155.836 538.114 155.836C525.507 155.836 515.288 166.055 515.288 178.662C515.288 191.268 525.507 201.488 538.114 201.488Z\" fill=\"black\"/>\n"
592+
"<path d=\"M178.662 560.94C191.268 560.94 201.488 550.72 201.488 538.114C201.488 525.507 191.268 515.288 178.662 515.288C166.055 515.288 155.836 525.507 155.836 538.114C155.836 550.72 166.055 560.94 178.662 560.94Z\" fill=\"black\"/>\n"
593+
"<path d=\"M695.922 201.488C708.528 201.488 718.748 191.268 718.748 178.662C718.748 166.055 708.528 155.836 695.922 155.836C683.315 155.836 673.096 166.055 673.096 178.662C673.096 191.268 683.315 201.488 695.922 201.488Z\" fill=\"black\"/>\n"
594+
"<path d=\"M336.47 560.94C349.076 560.94 359.296 550.72 359.296 538.114C359.296 525.507 349.076 515.288 336.47 515.288C323.863 515.288 313.644 525.507 313.644 538.114C313.644 550.72 323.863 560.94 336.47 560.94Z\" fill=\"black\"/>\n"
595+
"<path d=\"M695.922 359.296C708.528 359.296 718.748 349.076 718.748 336.47C718.748 323.863 708.528 313.644 695.922 313.644C683.315 313.644 673.096 323.863 673.096 336.47C673.096 349.076 683.315 359.296 695.922 359.296Z\" fill=\"black\"/>\n"
596+
"<path d=\"M336.47 718.748C349.076 718.748 359.296 708.528 359.296 695.922C359.296 683.315 349.076 673.096 336.47 673.096C323.863 673.096 313.644 683.315 313.644 695.922C313.644 708.528 323.863 718.748 336.47 718.748Z\" fill=\"black\"/>\n"
597+
"<path d=\"M538.114 359.296C550.72 359.296 560.94 349.076 560.94 336.47C560.94 323.863 550.72 313.644 538.114 313.644C525.507 313.644 515.288 323.863 515.288 336.47C515.288 349.076 525.507 359.296 538.114 359.296Z\" fill=\"black\"/>\n"
598+
"<path d=\"M178.662 718.748C191.268 718.748 201.488 708.528 201.488 695.922C201.488 683.315 191.268 673.096 178.662 673.096C166.055 673.096 155.836 683.315 155.836 695.922C155.836 708.528 166.055 718.748 178.662 718.748Z\" fill=\"black\"/>\n"
599+
"<path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M216.158 112L287.842 112C324.06 112 337.194 115.771 350.434 122.852C363.675 129.933 374.066 140.325 381.148 153.566C388.229 166.806 392 179.94 392 216.158V287.842C392 324.06 388.229 337.194 381.148 350.434C374.066 363.675 363.675 374.066 350.434 381.148C337.194 388.229 324.06 392 287.842 392H216.158C179.94 392 166.806 388.229 153.566 381.148C140.325 374.066 129.933 363.675 122.852 350.434C115.771 337.194 112 324.06 112 287.842V216.158C112 179.94 115.771 166.806 122.852 153.566C129.933 140.325 140.325 129.933 153.566 122.852C166.806 115.771 179.94 112 216.158 112Z\" fill=\"black\"/>\n"
600+
"<path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M576.158 472H647.842C684.06 472 697.194 475.771 710.434 482.852C723.675 489.933 734.066 500.325 741.148 513.566C748.229 526.806 752 539.94 752 576.158V647.842C752 684.06 748.229 697.194 741.148 710.434C734.066 723.675 723.675 734.066 710.434 741.148C697.194 748.229 684.06 752 647.842 752H576.158C539.94 752 526.806 748.229 513.566 741.148C500.325 734.066 489.933 723.675 482.852 710.434C475.771 697.194 472 684.06 472 647.842V576.158C472 539.94 475.771 526.806 482.852 513.566C489.933 500.325 500.325 489.933 513.566 482.852C526.806 475.771 539.94 472 576.158 472Z\" fill=\"black\"/>\n"
601+
"<rect x=\"30\" y=\"30\" width=\"804\" height=\"804\" rx=\"172\" stroke=\"black\" stroke-width=\"8\"/>\n"
602+
"</svg>\n";
514603

515604
std::unique_ptr<WelcomePanelTile> newPatchTile;
516605
std::unique_ptr<WelcomePanelTile> openPatchTile;
517606

518-
Component recentlyOpenedComponent;
519-
BouncingViewport recentlyOpenedViewport;
607+
Component contentComponent;
608+
BouncingViewport viewport;
520609

521610
TopFillAllRect topFillAllRect;
522611

523612
std::unique_ptr<NanoVGGraphicsContext> nvgContext = nullptr;
524613

525614
NVGImage shadowImage;
526-
OwnedArray<WelcomePanelTile> tiles;
615+
OwnedArray<WelcomePanelTile> recentlyOpenedTiles;
616+
OwnedArray<WelcomePanelTile> libraryTiles;
527617
PluginEditor* editor;
618+
619+
static inline Image logo = ImageFileFormat::loadFrom(BinaryData::plugdata_logo_png, BinaryData::plugdata_logo_pngSize).rescaled(128, 128);
528620

529621
String searchQuery;
530-
Tab currentTab;
622+
Tab currentTab = Home;
531623

532624
};

Source/PluginEditor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,7 @@ void PluginEditor::resized()
686686
runButton.setBounds(startX + buttonSize - 1, 1, buttonSize, buttonSize - 2);
687687
presentButton.setBounds(startX + (2 * buttonSize) - 2, 1, buttonSize, buttonSize - 2);
688688

689-
auto welcomeSelectorBounds = getLocalBounds().removeFromTop(toolbarHeight + 8).withSizeKeepingCentre(200, toolbarHeight);
689+
auto welcomeSelectorBounds = getLocalBounds().removeFromTop(toolbarHeight + 8).withSizeKeepingCentre(200, toolbarHeight).translated(0, -1);
690690
recentlyOpenedPanelSelector.setBounds(welcomeSelectorBounds.removeFromLeft(100));
691691
libraryPanelSelector.setBounds(welcomeSelectorBounds.removeFromLeft(100));
692692

Source/Utility/MidiDeviceManager.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -219,15 +219,20 @@ class MidiDeviceManager : public ChangeListener
219219
void enqueueMidiOutput(int port, MidiMessage const& message, int samplePosition)
220220
{
221221
ScopedLock lock(midiDeviceLock);
222-
midiBufferOut[port].addEvent(message, samplePosition);
222+
auto midiOutputBufferIter = midiBufferOut.find(port);
223+
if (midiOutputBufferIter == midiBufferOut.end()) {
224+
midiOutputBufferIter->second.addEvent(message, samplePosition);
225+
}
223226
}
224227

225228
// Read output buffer for a port. Used to pass back into the DAW or into the internal GM synth
226229
void dequeueMidiOutput(int port, MidiBuffer& buffer, int numSamples)
227230
{
228231
ScopedLock lock(midiDeviceLock);
229-
auto& outputBuffer = midiBufferOut[port];
230-
buffer.addEvents(outputBuffer, 0, numSamples, 0);
232+
auto midiOutputBufferIter = midiBufferOut.find(port);
233+
if (midiOutputBufferIter == midiBufferOut.end()) {
234+
buffer.addEvents(midiOutputBufferIter->second, 0, numSamples, 0);
235+
}
231236
}
232237

233238
// Send all MIDI output to target devices

0 commit comments

Comments
 (0)