Skip to content

Commit

Permalink
[auto fill lists] Initial implementation of #334: When creating a lis…
Browse files Browse the repository at this point in the history
…t, select if to auto fill the list with either the first patches displayed or a random subset of the current search result.
  • Loading branch information
christofmuc committed Aug 15, 2024
1 parent 110fc21 commit 20d7e95
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 19 deletions.
29 changes: 22 additions & 7 deletions The-Orm/CreateListDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ std::map<int, std::string> bankLookup(std::shared_ptr<midikraft::Synth> synth)
return result;
}

CreateListDialog::CreateListDialog(std::shared_ptr<midikraft::Synth> synth, TCallback &callback, TCallback &deleteCallback) :
CreateListDialog::CreateListDialog(std::shared_ptr<midikraft::Synth> synth, TCallbackWithFill&callback, TCallback &deleteCallback) :
synth_(synth)
, isBank_(true)
, callback_(callback)
Expand All @@ -60,10 +60,10 @@ CreateListDialog::CreateListDialog(std::shared_ptr<midikraft::Synth> synth, TCal
delete_.setVisible(false);

// Finally we need a default size
setBounds(0, 0, 540, 200);
setBounds(0, 0, 540, 300);
}

CreateListDialog::CreateListDialog(TCallback& callback, TCallback& deleteCallback) : isBank_(false), callback_(callback), deleteCallback_(deleteCallback)
CreateListDialog::CreateListDialog(TCallbackWithFill& callback, TCallback& deleteCallback) : isBank_(false), callback_(callback), deleteCallback_(deleteCallback)
{
addAndMakeVisible(propertyEditor_);

Expand All @@ -81,7 +81,7 @@ CreateListDialog::CreateListDialog(TCallback& callback, TCallback& deleteCallbac
delete_.setVisible(false);

// Finally we need a default size
setBounds(0, 0, 540, 200);
setBounds(0, 0, 540, 300);
}

void CreateListDialog::setList(std::shared_ptr<midikraft::PatchList> list)
Expand All @@ -105,6 +105,13 @@ void CreateListDialog::setList(std::shared_ptr<midikraft::PatchList> list)
props.push_back(std::make_shared<TypedNamedValue>("Bank", "General", 0, lookup));
bankValue_ = Value(props[1]->value());
}
std::map<int, std::string> populateModes = { {0, "No fill"}, { 1, "First patches"}, { 2, "Random patches"} };
props.push_back(std::make_shared<TypedNamedValue>("Auto-fill from grid", "Populate", 0, populateModes));
fillMode_ = Value(props.back()->value());
if (!isBank_) {
props.push_back(std::make_shared<TypedNamedValue>("Maximum number of patches", "Populate", 64, 0, 4096));
patchNumber_ = Value(props.back()->value());
}
}
propertyEditor_.setProperties(props);
}
Expand All @@ -130,7 +137,7 @@ static void dialogClosed(int modalResult, CreateListDialog* dialog)
}
}

void CreateListDialog::showCreateListDialog(std::shared_ptr<midikraft::SynthBank> list, std::shared_ptr<midikraft::Synth> synth, Component* centeredAround, TCallback callback, TCallback deleteCallback)
void CreateListDialog::showCreateListDialog(std::shared_ptr<midikraft::SynthBank> list, std::shared_ptr<midikraft::Synth> synth, Component* centeredAround, TCallbackWithFill callback, TCallback deleteCallback)
{
if (!sCreateListDialog_) {
sCreateListDialog_ = std::make_unique<CreateListDialog>(synth, callback, deleteCallback);
Expand All @@ -149,7 +156,7 @@ void CreateListDialog::showCreateListDialog(std::shared_ptr<midikraft::SynthBank
ModalComponentManager::getInstance()->attachCallback(sWindow_, ModalCallbackFunction::forComponent(dialogClosed, sCreateListDialog_.get()));
}

void CreateListDialog::showCreateListDialog(std::shared_ptr<midikraft::PatchList> list, Component* centeredAround, TCallback callback, TCallback deleteCallback)
void CreateListDialog::showCreateListDialog(std::shared_ptr<midikraft::PatchList> list, Component* centeredAround, TCallbackWithFill callback, TCallback deleteCallback)
{
if (!sCreateListDialog_) {
sCreateListDialog_ = std::make_unique<CreateListDialog>(callback, deleteCallback);
Expand Down Expand Up @@ -199,7 +206,15 @@ void CreateListDialog::notifyResult()
list_ = std::make_shared<midikraft::PatchList>(name.toStdString());
}
}
callback_(list_);
TFillParameters fillParameters{ TListFillMode::None, 0 };
if (static_cast<int>(fillMode_.getValue()) == 1) {
fillParameters.fillMode = TListFillMode::Top;
}
else if (static_cast<int>(fillMode_.getValue()) == 2) {
fillParameters.fillMode = TListFillMode::Random;
}
fillParameters.number = patchNumber_.getValue();
callback_(list_, fillParameters);
}

void CreateListDialog::buttonClicked(Button* button) {
Expand Down
22 changes: 17 additions & 5 deletions The-Orm/CreateListDialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,26 @@

class CreateListDialog : public Component, private TextButton::Listener {
public:
enum TListFillMode {
None,
Top,
Random
};
struct TFillParameters {
TListFillMode fillMode;
int number;
};
typedef std::function<void(std::shared_ptr<midikraft::PatchList> result)> TCallback;
typedef std::function<void(std::shared_ptr<midikraft::PatchList> result, TFillParameters fillParameters)> TCallbackWithFill;

CreateListDialog(std::shared_ptr<midikraft::Synth> synth, TCallback& callback, TCallback& deleteCallback);
CreateListDialog(TCallback& callback, TCallback& deleteCallback);
CreateListDialog(std::shared_ptr<midikraft::Synth> synth, TCallbackWithFill& callback, TCallback& deleteCallback);
CreateListDialog(TCallbackWithFill& callback, TCallback& deleteCallback);
void setList(std::shared_ptr<midikraft::PatchList> list);

virtual void resized() override;

static void showCreateListDialog(std::shared_ptr<midikraft::SynthBank> list, std::shared_ptr<midikraft::Synth> synth, Component* centeredAround, TCallback callback, TCallback deleteCallback);
static void showCreateListDialog(std::shared_ptr<midikraft::PatchList> list, Component* centeredAround, TCallback callback, TCallback deleteCallback);
static void showCreateListDialog(std::shared_ptr<midikraft::SynthBank> list, std::shared_ptr<midikraft::Synth> synth, Component* centeredAround, TCallbackWithFill callback, TCallback deleteCallback);
static void showCreateListDialog(std::shared_ptr<midikraft::PatchList> list, Component* centeredAround, TCallbackWithFill callback, TCallback deleteCallback);
static void release();

void notifyResult();
Expand All @@ -41,11 +51,13 @@ class CreateListDialog : public Component, private TextButton::Listener {
std::shared_ptr<midikraft::PatchList> list_;
Value nameValue_;
Value bankValue_;
Value fillMode_;
Value patchNumber_;
PropertyEditor propertyEditor_;
TextButton ok_;
TextButton cancel_;
TextButton delete_;
TCallback callback_;
TCallbackWithFill callback_;
TCallback deleteCallback_;

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CreateListDialog)
Expand Down
25 changes: 18 additions & 7 deletions The-Orm/PatchListTree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,19 @@ PatchListTree::PatchListTree(midikraft::PatchDatabase& db, std::vector<midikraft
auto addNewItem = new TreeViewNode("Add new list", "");
addNewItem->onSingleClick = [this](String id) {
juce::ignoreUnused(id);
CreateListDialog::showCreateListDialog(nullptr, TopLevelWindow::getActiveTopLevelWindow(), [this](std::shared_ptr<midikraft::PatchList> list) {
CreateListDialog::showCreateListDialog(nullptr, TopLevelWindow::getActiveTopLevelWindow(), [this](std::shared_ptr<midikraft::PatchList> list, CreateListDialog::TFillParameters fillParameters) {
if (list) {
db_.putPatchList(list);
spdlog::info("Create new user list named {}", list->name());
regenerateUserLists([]() {});
if (onPatchListFill) {
onPatchListFill(list, fillParameters, [this, list]() {
db_.putPatchList(list);
regenerateUserLists([]() {});
});
}
else {
db_.putPatchList(list);
regenerateUserLists([]() {});
}
}
}, nullptr);
};
Expand Down Expand Up @@ -397,8 +405,11 @@ TreeViewNode* PatchListTree::newTreeViewItemForStoredBanks(std::shared_ptr<midik
auto addNewItem = new TreeViewNode("Add new user bank", "");
addNewItem->onSingleClick = [this, synth, synthBanksNode](String id) {
juce::ignoreUnused(id);
CreateListDialog::showCreateListDialog(nullptr, synth, TopLevelWindow::getActiveTopLevelWindow(), [this, synthBanksNode](std::shared_ptr<midikraft::PatchList> list) {
CreateListDialog::showCreateListDialog(nullptr, synth, TopLevelWindow::getActiveTopLevelWindow(), [this, synthBanksNode](std::shared_ptr<midikraft::PatchList> list, CreateListDialog::TFillParameters fillParameters) {
if (list) {
if (fillParameters.fillMode != CreateListDialog::None) {

}
db_.putPatchList(list);
spdlog::info("Create new user bank named {}", list->name());
MessageManager::callAsync([this, synthBanksNode]() {
Expand Down Expand Up @@ -442,7 +453,7 @@ TreeViewNode* PatchListTree::newTreeViewItemForStoredBanks(std::shared_ptr<midik
CreateListDialog::showCreateListDialog(nullptr,
copyOfList->synth(),
TopLevelWindow::getActiveTopLevelWindow(),
[this, synthBanksNode, loaded_list](std::shared_ptr<midikraft::PatchList> new_list) {
[this, synthBanksNode, loaded_list](std::shared_ptr<midikraft::PatchList> new_list, CreateListDialog::TFillParameters ) {
jassert(new_list);
if (new_list) {
// Copy over patches from droppped list to newly created list
Expand Down Expand Up @@ -523,7 +534,7 @@ TreeViewNode* PatchListTree::newTreeViewItemForUserBank(std::shared_ptr<midikraf
CreateListDialog::showCreateListDialog(std::dynamic_pointer_cast<midikraft::SynthBank>(bank),
synth,
TopLevelWindow::getActiveTopLevelWindow(),
[this, oldname, parent](std::shared_ptr<midikraft::PatchList> new_list) {
[this, oldname, parent](std::shared_ptr<midikraft::PatchList> new_list, CreateListDialog::TFillParameters) {
jassert(new_list);
if (new_list) {
db_.putPatchList(new_list);
Expand Down Expand Up @@ -640,7 +651,7 @@ TreeViewNode* PatchListTree::newTreeViewItemForPatchList(midikraft::ListInfo lis
std::string oldname = node->text().toStdString();
CreateListDialog::showCreateListDialog(std::make_shared<midikraft::PatchList>(node->id().toStdString(), node->text().toStdString()),
TopLevelWindow::getActiveTopLevelWindow(),
[this, oldname](std::shared_ptr<midikraft::PatchList> new_list) {
[this, oldname](std::shared_ptr<midikraft::PatchList> new_list, CreateListDialog::TFillParameters) {
jassert(new_list);
if (new_list) {
db_.putPatchList(new_list);
Expand Down
5 changes: 5 additions & 0 deletions The-Orm/PatchListTree.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,17 @@
#include "PatchDatabase.h"
#include "SynthHolder.h"
#include "TreeViewNode.h"
#include "CreateListDialog.h"


class PatchListTree : public Component, private ChangeListener {
public:
typedef std::function<void(String)> TSelectionHandler;
typedef std::function<void(std::shared_ptr<midikraft::Synth>, MidiBankNumber)> TBankSelectionHandler;
typedef std::function<void(std::shared_ptr<midikraft::Synth>, String)> TUserBankSelectionHandler;
typedef std::function<void(midikraft::PatchHolder)> TPatchSelectionHandler;
typedef std::function<void(std::shared_ptr<midikraft::PatchList>, CreateListDialog::TFillParameters, std::function<void()>)> TPatchListFillHandler;


PatchListTree(midikraft::PatchDatabase &db, std::vector<midikraft::SynthHolder> const& synths);
virtual ~PatchListTree() override;
Expand All @@ -29,6 +33,7 @@ class PatchListTree : public Component, private ChangeListener {
TSelectionHandler onUserListChanged;

TPatchSelectionHandler onPatchSelected;
TPatchListFillHandler onPatchListFill;

virtual void resized() override;

Expand Down
47 changes: 47 additions & 0 deletions The-Orm/PatchView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@
#include <spdlog/spdlog.h>
#include "SpdLogJuce.h"

#include <random>
#include <algorithm>

const char *kAllPatchesFilter = "All patches";

PatchView::PatchView(midikraft::PatchDatabase &database, std::vector<midikraft::SynthHolder> const &synths) :
Expand Down Expand Up @@ -72,6 +75,9 @@ PatchView::PatchView(midikraft::PatchDatabase &database, std::vector<midikraft::
patchListTree_.onPatchSelected = [this](midikraft::PatchHolder patch) {
selectPatch(patch, false);
};
patchListTree_.onPatchListFill = [this](std::shared_ptr<midikraft::PatchList> list, CreateListDialog::TFillParameters parameters, std::function<void()> finishedCallback) {
fillList(list, parameters, finishedCallback);
};

patchButtons_ = std::make_unique<PatchButtonPanel>([this](midikraft::PatchHolder& patch) {
if (UIModel::currentSynth()) {
Expand Down Expand Up @@ -1045,3 +1051,44 @@ void PatchView::selectPatch(midikraft::PatchHolder &patch, bool alsoSendToSynth)
}*/
}

template <typename T>
std::vector<T> getRandomSubset(const std::vector<T>& original, std::size_t subsetSize) {
// Copy the original vector
std::vector<T> shuffled = original;

// If subsetSize is larger than the original vector size, limit it
if (subsetSize > original.size()) {
subsetSize = original.size();
}

// Create a random engine with a seed based on the current time
std::random_device rd;
std::default_random_engine rng(rd());

// Shuffle the copied vector
std::shuffle(shuffled.begin(), shuffled.end(), rng);

// Create a vector to store the subset
std::vector<T> subset(shuffled.begin(), shuffled.begin() + subsetSize);

return subset;
}

void PatchView::fillList(std::shared_ptr<midikraft::PatchList> list, CreateListDialog::TFillParameters fillParameters, std::function<void()> finishedCallback) {
if (fillParameters.fillMode == CreateListDialog::TListFillMode::None) {
finishedCallback();
}
else if (fillParameters.fillMode == CreateListDialog::TListFillMode::Top) {
loadPage(0, fillParameters.number, currentFilter(), [list, finishedCallback](std::vector<midikraft::PatchHolder> patches) {
list->setPatches(patches);
finishedCallback();
});
}
else if (fillParameters.fillMode == CreateListDialog::TListFillMode::Random) {
loadPage(0, -1, currentFilter(), [list, fillParameters, finishedCallback](std::vector<midikraft::PatchHolder> patches) {
list->setPatches(getRandomSubset(patches, fillParameters.number));
finishedCallback();
});
}
}

2 changes: 2 additions & 0 deletions The-Orm/PatchView.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ class PatchView : public Component,
void setUserListFilter(String filter);
void deleteSomething(nlohmann::json const &infos);

void fillList(std::shared_ptr<midikraft::PatchList> list, CreateListDialog::TFillParameters fillParameters, std::function<void()> finishedCallback);

void showBank();

PatchListTree patchListTree_;
Expand Down

0 comments on commit 20d7e95

Please sign in to comment.