directory structure for (displaying and selecting) samples
parent
3a054ff1a1
commit
208d515de0
|
@ -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;
|
||||
}*/
|
|
@ -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(); }
|
||||
};
|
||||
}
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue