directory structure for (displaying and selecting) samples

portability/boost
zetaPRIME 2019-06-25 00:58:23 -04:00
parent 3a054ff1a1
commit 208d515de0
5 changed files with 124 additions and 6 deletions

View File

@ -0,0 +1,51 @@
#include "directorynode.h"
using Xybrid::UI::DirectoryNode;
#include <algorithm>
#include <functional>
#include <QCollator>
#include <QHash>
DirectoryNode::DirectoryNode(DirectoryNode* parent, QString name, QVariant data) {
this->parent = parent;
this->name = name;
this->data = data;
if (parent) parent->children.push_back(this);
}
DirectoryNode::~DirectoryNode() {
qDeleteAll(children);
}
void DirectoryNode::sortChildren() {
QCollator col;
col.setNumericMode(true);
std::sort(children.begin(), children.end(), [&col](auto a, auto b) { if (a->isDirectory() && !b->isDirectory()) return true; return col.compare(a->name, b->name) < 0; });
}
void DirectoryNode::sortTree() {
sortChildren();
for (auto c : children) c->sortTree();
}
DirectoryNode* DirectoryNode::subdir(QString name) {
if (name.isEmpty()) return this;
QString first = name.section('/', 0, 0, QString::SectionSkipEmpty);
QString rest = name.section('/', 1, -1, QString::SectionSkipEmpty);
DirectoryNode* sd = nullptr;
for (auto c : children) if (c->isDirectory() && c->name == first) { sd = c; break; }
if (!sd) sd = new DirectoryNode(this, first);
return sd->subdir(rest);
}
void DirectoryNode::placeData(QString name, QVariant data) {
QString dir = name.section('/', 0, -2, QString::SectionSkipEmpty);
QString file = name.section('/', -1, -1, QString::SectionSkipEmpty);
new DirectoryNode(subdir(dir), file, data);
}
/*void DirectoryNode::placeData(const QVector<std::pair<QString, QVariant>>& data) {
QHash<QString, DirectoryNode*> dirs; // lookup table for directories
dirs[""] = this;
}*/

31
xybrid/ui/directorynode.h Normal file
View File

@ -0,0 +1,31 @@
#pragma once
#include <QString>
#include <QVector>
#include <QVariant>
namespace Xybrid::UI {
class DirectoryNode {
//
public:
QString name;
QVariant data;
DirectoryNode* parent;
QVector<DirectoryNode*> children;
DirectoryNode(DirectoryNode* parent = nullptr, QString name = QString(), QVariant data = QVariant());
~DirectoryNode();
void sortChildren();
void sortTree();
DirectoryNode* subdir(QString name);
void placeData(QString name, QVariant data);
//void placeData(const QVector<std::pair<QString, QVariant>>&);
inline bool isDirectory() const { return data.isNull(); }
};
}

View File

@ -5,7 +5,9 @@ using Xybrid::UI::SampleSelectorGadget;
#include "data/sample.h"
using namespace Xybrid::Data;
#include "ui/directorynode.h"
#include "ui/waveformpreviewwidget.h"
using namespace Xybrid::UI;
#include "config/colorscheme.h"
@ -101,24 +103,54 @@ void SampleSelectorGadget::paint(QPainter* p, const QStyleOptionGraphicsItem* op
p->fillPath(path, QColor(255, 255, 255));
}
void SampleSelectorGadget::buildSubmenu(DirectoryNode* dir, QMenu* menu) {
auto smp = currentSample.lock();
bool needSeparator = false;
for (auto c : dir->children) {
if (c->isDirectory()) {
needSeparator = true;
buildSubmenu(c, menu->addMenu(c->name));
} else {
if (needSeparator) { menu->addSeparator(); needSeparator = false; }
auto s = project->samples[c->data.toUuid()];
auto wa = new QWidgetAction(menu);
auto wfp = new WaveformPreviewWidget(menu);
wa->setDefaultWidget(wfp);
wfp->showName = true;
wfp->highlightable = true;
wfp->setSample(s);
wfp->setMinimumSize(192, 48);
menu->addAction(wa);
if (s == smp) wa->setDisabled(true);
else connect(wa, &QWidgetAction::triggered, [this, s] { setSample(s); });
}
}
}
void SampleSelectorGadget::mousePressEvent(QGraphicsSceneMouseEvent* e) {
if (!project) return;
std::vector<std::shared_ptr<Sample>> displayOrder;
/*std::vector<std::shared_ptr<Sample>> displayOrder;
displayOrder.reserve(static_cast<size_t>(project->samples.size()));
for (auto s : project->samples) displayOrder.push_back(s);
std::sort(displayOrder.begin(), displayOrder.end(), [](std::shared_ptr<Sample> a, std::shared_ptr<Sample> b) {
if (a->name == b->name) return a->uuid < b->uuid;
return a->name < b->name;
});
});*/
if (e->button() == Qt::LeftButton) {
auto smp = currentSample.lock();
auto* m = new QMenu();
if (displayOrder.empty()) m->addAction("(no samples in project)")->setDisabled(true);
if (project->samples.empty()) m->addAction("(no samples in project)")->setDisabled(true);
else {
m->addAction("(no sample)", [this] { setSample(nullptr); });
m->addSeparator();
for (auto s : displayOrder) {
DirectoryNode root;
for (auto s : project->samples) root.placeData(s->name, s->uuid);
root.sortTree();
buildSubmenu(&root, m);
/*for (auto s : displayOrder) {
auto wa = new QWidgetAction(m);
auto wfp = new WaveformPreviewWidget(m);
wa->setDefaultWidget(wfp);
@ -129,7 +161,7 @@ void SampleSelectorGadget::mousePressEvent(QGraphicsSceneMouseEvent* e) {
m->addAction(wa);
if (s == smp) wa->setDisabled(true);
else connect(wa, &QWidgetAction::triggered, [this, s] { setSample(s); });
}
}*/
}
m->setAttribute(Qt::WA_DeleteOnClose);
m->popup(e->screenPos());

View File

@ -5,12 +5,16 @@
namespace Xybrid::Data { class Project; class Sample; }
namespace Xybrid::UI {
class DirectoryNode;
class SampleSelectorGadget : public Gadget {
Q_OBJECT
QSizeF size = {128, 32};
Data::Project* project;
std::weak_ptr<Data::Sample> currentSample;
void buildSubmenu(DirectoryNode* dir, QMenu* menu);
public:
SampleSelectorGadget(Data::Project* project = nullptr, QGraphicsItem* parent = nullptr);
~SampleSelectorGadget() override = default;

View File

@ -81,7 +81,7 @@ void WaveformPreviewWidget::paintEvent(QPaintEvent* event [[maybe_unused]]) {
// draw label
QFont font("Arcon Rounded", 8);
QFontMetrics fm(font);
name = fm.elidedText(name, Qt::ElideRight, rect.width() - 4);
name = fm.elidedText(name.section('/', -1, -1), Qt::ElideRight, rect.width() - 4);
QPainterPath path;
path.addText(rect.bottomLeft() + QPointF(2, -fm.descent()), font, name);