song info editing; switch data over to QString
parent
c74cc70153
commit
12fcaa427c
|
@ -385,7 +385,7 @@ void AudioEngine::nextTick() {
|
|||
for (size_t c = 0; c < cs; c++) {
|
||||
auto& ch = pOld->channels[c];
|
||||
if (!chTrack[c].valid) continue; // skip notes that aren't actually playing
|
||||
if (ch.name.empty()) noteEndQueue.push_back(chTrack[c]); // end notes in unnamed channels right away
|
||||
if (ch.name.isEmpty()) noteEndQueue.push_back(chTrack[c]); // end notes in unnamed channels right away
|
||||
else nameTrack[&ch.name] = chTrack[c]; // otherwise keep track for later
|
||||
}
|
||||
}
|
||||
|
@ -395,7 +395,7 @@ void AudioEngine::nextTick() {
|
|||
size_t cs = p->channels.size();
|
||||
for (size_t c = 0; c < cs; c++) {
|
||||
auto& ch = p->channels[c];
|
||||
if (ch.name.empty()) continue;
|
||||
if (ch.name.isEmpty()) continue;
|
||||
if (auto nt = nameTrack.find(&ch.name); nt != nameTrack.end() && nt->second.valid) {
|
||||
chTrack[c] = nt->second; // carry over
|
||||
nt->second.valid = false; // and invalidate
|
||||
|
|
|
@ -26,7 +26,8 @@ namespace Xybrid::Audio {
|
|||
class AudioWorker;
|
||||
template <typename T> struct PointerCompare {
|
||||
bool operator()(T* a, T* b) const { return *a == *b; }
|
||||
size_t operator()(T* a) const { return std::hash<T>()(*a); }
|
||||
//size_t operator()(T* a) const { return std::hash<T>()(*a); }
|
||||
size_t operator()(T* a) const { return qHash(*a); }
|
||||
};
|
||||
struct NoteInfo {
|
||||
bool valid = false;
|
||||
|
@ -76,14 +77,14 @@ namespace Xybrid::Audio {
|
|||
std::array<uint16_t, 256> portLastNoteId;
|
||||
std::vector<NoteInfo> chTrack;
|
||||
std::vector<NoteInfo> noteEndQueue;
|
||||
std::unordered_map<std::string*, NoteInfo, PointerCompare<std::string>, PointerCompare<std::string>> nameTrack;
|
||||
std::unordered_map<QString*, NoteInfo, PointerCompare<QString>, PointerCompare<QString>> nameTrack;
|
||||
std::vector<uint8_t> buf; /// preallocated buffer for building commands
|
||||
|
||||
uint8_t previewPort_ = 0;
|
||||
uint16_t previewNote_ = 0;
|
||||
|
||||
// playback timing and position
|
||||
float tempo = 140.0;
|
||||
double tempo = 140.0;
|
||||
int seqPos;
|
||||
int curRow;
|
||||
int curTick;
|
||||
|
|
|
@ -22,7 +22,7 @@ Row& Row::operator=(const Row& o) noexcept {
|
|||
return *this;
|
||||
}
|
||||
|
||||
Channel::Channel(int numRows, std::string name) : Channel() {
|
||||
Channel::Channel(int numRows, QString name) : Channel() {
|
||||
this->name = name;
|
||||
rows.resize(static_cast<size_t>(numRows));
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <QString>
|
||||
|
||||
namespace Xybrid::Data {
|
||||
class Project;
|
||||
struct TimeSignature {
|
||||
|
@ -89,12 +91,12 @@ namespace Xybrid::Data {
|
|||
|
||||
class Channel {
|
||||
public:
|
||||
std::string name;
|
||||
QString name;
|
||||
std::vector<Row> rows;
|
||||
|
||||
Channel() = default;
|
||||
Channel(const Channel&) = default;
|
||||
Channel(int numRows, std::string name = "");
|
||||
Channel(int numRows, QString name = "");
|
||||
};
|
||||
private:
|
||||
static Row fallbackRow;
|
||||
|
@ -107,10 +109,10 @@ namespace Xybrid::Data {
|
|||
Project* project;
|
||||
size_t index; // index in project's pattern list
|
||||
|
||||
std::string name;
|
||||
QString name;
|
||||
|
||||
int rows = 64;
|
||||
float tempo = 0; // don't set playback tempo
|
||||
double tempo = 0; // don't set playback tempo
|
||||
TimeSignature time;
|
||||
|
||||
int fold = 0;
|
||||
|
|
|
@ -25,12 +25,12 @@ namespace Xybrid::Data {
|
|||
|
||||
UISocket* socket;
|
||||
|
||||
std::string title;
|
||||
std::string artist;
|
||||
QString title;
|
||||
QString artist;
|
||||
|
||||
QString fileName;
|
||||
|
||||
float tempo = 140.0;
|
||||
double tempo = 140.0;
|
||||
TimeSignature time;
|
||||
// default time signature
|
||||
|
||||
|
|
|
@ -150,7 +150,7 @@ std::shared_ptr<Sample> Sample::fromFile(QString fileName) {
|
|||
|
||||
smp->sampleRate = fmt.sampleRate();
|
||||
smp->uuid = QUuid::createUuid();
|
||||
smp->name = QFileInfo(fileName).fileName();
|
||||
smp->name = QFileInfo(fileName).baseName();
|
||||
|
||||
return smp;
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ void PatternDeltaCommand::undo() {
|
|||
if (!composed) emit pattern->project->socket->rowUpdated(pattern.get(), ch, rw);
|
||||
}
|
||||
|
||||
PatternRenameCommand::PatternRenameCommand(const std::shared_ptr<Pattern>& pattern, const std::string &to) {
|
||||
PatternRenameCommand::PatternRenameCommand(const std::shared_ptr<Pattern>& pattern, const QString& to) {
|
||||
this->pattern = pattern;
|
||||
from = pattern->name;
|
||||
this->to = to;
|
||||
|
@ -179,7 +179,7 @@ void PatternChannelMoveCommand::undo() {
|
|||
emit pattern->project->socket->patternUpdated(pattern.get());
|
||||
}
|
||||
|
||||
PatternChannelRenameCommand::PatternChannelRenameCommand(const std::shared_ptr<Pattern>& pattern, int channel, const std::string &to) {
|
||||
PatternChannelRenameCommand::PatternChannelRenameCommand(const std::shared_ptr<Pattern>& pattern, int channel, const QString& to) {
|
||||
this->pattern = pattern;
|
||||
idx = channel;
|
||||
from = pattern->channel(idx).name;
|
||||
|
|
|
@ -35,10 +35,10 @@ namespace Xybrid::Editing {
|
|||
};
|
||||
|
||||
class PatternRenameCommand : public PatternCommand {
|
||||
std::string from, to;
|
||||
QString from, to;
|
||||
|
||||
public:
|
||||
PatternRenameCommand(const std::shared_ptr<Data::Pattern>& pattern, const std::string& to);
|
||||
PatternRenameCommand(const std::shared_ptr<Data::Pattern>& pattern, const QString& to);
|
||||
~PatternRenameCommand() override = default;
|
||||
|
||||
int id() const override { return 2070; }
|
||||
|
@ -103,10 +103,10 @@ namespace Xybrid::Editing {
|
|||
|
||||
class PatternChannelRenameCommand : public PatternCommand {
|
||||
int idx;
|
||||
std::string from, to;
|
||||
QString from, to;
|
||||
|
||||
public:
|
||||
PatternChannelRenameCommand(const std::shared_ptr<Data::Pattern>& pattern, int channel, const std::string& to);
|
||||
PatternChannelRenameCommand(const std::shared_ptr<Data::Pattern>& pattern, int channel, const QString& to);
|
||||
~PatternChannelRenameCommand() override = default;
|
||||
|
||||
int id() const override { return 2101; }
|
||||
|
|
|
@ -71,8 +71,10 @@ bool FileOps::saveProject(std::shared_ptr<Project> project, QString fileName) {
|
|||
{ /* Project metadata */ } {
|
||||
QCborMap meta;
|
||||
|
||||
meta[qs("artist")] = QString::fromStdString(project->artist);
|
||||
meta[qs("title")] = QString::fromStdString(project->title);
|
||||
meta[qs("artist")] = project->artist;
|
||||
meta[qs("title")] = project->title;
|
||||
|
||||
meta[qs("tempo")] = project->tempo;
|
||||
|
||||
main[qs("meta")] = meta;
|
||||
}
|
||||
|
@ -90,8 +92,9 @@ bool FileOps::saveProject(std::shared_ptr<Project> project, QString fileName) {
|
|||
QCborArray ptns;
|
||||
for (auto p : project->patterns) {
|
||||
QCborMap pm;
|
||||
pm[qs("name")] = QString::fromStdString(p->name);
|
||||
pm[qs("name")] = p->name;
|
||||
pm[qs("fold")] = p->fold;
|
||||
pm[qs("tempo")] = p->tempo;
|
||||
|
||||
{
|
||||
QCborArray ts;
|
||||
|
@ -103,7 +106,7 @@ bool FileOps::saveProject(std::shared_ptr<Project> project, QString fileName) {
|
|||
bool needsCount = true;
|
||||
for (auto& ch : p->channels) {
|
||||
QCborMap chm;
|
||||
chm[qs("name")] = QString::fromStdString(ch.name);
|
||||
chm[qs("name")] = ch.name;
|
||||
QCborArray rows;
|
||||
int skipped = 0;
|
||||
for (auto& r : ch.rows) {
|
||||
|
@ -179,8 +182,9 @@ std::shared_ptr<Project> FileOps::loadProject(QString fileName) {
|
|||
|
||||
{ /* Project metadata */ } {
|
||||
QCborMap meta = main.value("meta").toMap();
|
||||
project->artist = meta.value("artist").toString().toStdString();
|
||||
project->title = meta.value("title").toString().toStdString();
|
||||
project->artist = meta.value("artist").toString();
|
||||
project->title = meta.value("title").toString();
|
||||
project->tempo = meta.value("tempo").toDouble(project->tempo);
|
||||
}
|
||||
|
||||
{ /* Patterns */ } {
|
||||
|
@ -191,8 +195,9 @@ std::shared_ptr<Project> FileOps::loadProject(QString fileName) {
|
|||
auto p = std::make_shared<Pattern>(pm.value("rows").toInteger(1));
|
||||
p->project = project.get();
|
||||
project->patterns.push_back(p);
|
||||
p->name = pm.value("name").toString().toStdString();
|
||||
p->name = pm.value("name").toString();
|
||||
p->fold = static_cast<int>(pm.value("fold").toInteger(0));
|
||||
p->tempo = pm.value("tempo").toDouble(p->tempo);
|
||||
|
||||
if (auto ts = pm.value("time").toArray(); !ts.empty())
|
||||
p->time = Data::TimeSignature(static_cast<int>(ts[0].toInteger()), static_cast<int>(ts[1].toInteger()), static_cast<int>(ts[2].toInteger()));
|
||||
|
@ -205,7 +210,7 @@ std::shared_ptr<Project> FileOps::loadProject(QString fileName) {
|
|||
}
|
||||
auto chm = chm_.toMap();
|
||||
auto& ch = p->channels.emplace_back();
|
||||
ch.name = chm.value("name").toString().toStdString();
|
||||
ch.name = chm.value("name").toString();
|
||||
|
||||
auto rows = chm.value("rows").toArray();
|
||||
ch.rows.reserve(static_cast<size_t>(rows.size()));
|
||||
|
|
|
@ -145,6 +145,19 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||
});//*/
|
||||
}
|
||||
|
||||
{ /* Set up song info pane */ } {
|
||||
ui->expandSongInfo->setIcon(ui->expandSongInfo->style()->standardIcon(QStyle::SP_ToolBarVerticalExtensionButton));
|
||||
ui->collapseSongInfo->setIcon(ui->expandSongInfo->style()->standardIcon(QStyle::SP_ToolBarVerticalExtensionButton));
|
||||
|
||||
connect(ui->expandSongInfo, &QPushButton::pressed, this, [this] { setSongInfoPaneExpanded(true); });
|
||||
connect(ui->collapseSongInfo, &QPushButton::pressed, this, [this] { setSongInfoPaneExpanded(false); });
|
||||
|
||||
connect(ui->editArtist, &QLineEdit::textEdited, this, [this](const QString& s) { project->artist = s; updateTitle(); });
|
||||
connect(ui->editTitle, &QLineEdit::textEdited, this, [this](const QString& s) { project->title = s; updateTitle(); });
|
||||
|
||||
connect(ui->editTempo, qOverload<double>(&QDoubleSpinBox::valueChanged), this, [this](double t) { project->tempo = t; });
|
||||
}
|
||||
|
||||
{ /* Set up sequencer */ } {
|
||||
// model
|
||||
ui->patternSequencer->setModel(new PatternSequencerModel(ui->patternSequencer, this));
|
||||
|
@ -407,6 +420,11 @@ void MainWindow::menuFileSaveAs() {
|
|||
}
|
||||
}
|
||||
|
||||
void MainWindow::menuFileNewWindow() {
|
||||
auto w = new MainWindow();
|
||||
w->show();
|
||||
}
|
||||
|
||||
void MainWindow::onNewProjectLoaded() {
|
||||
undoStack->clear();
|
||||
|
||||
|
@ -426,7 +444,13 @@ void MainWindow::onNewProjectLoaded() {
|
|||
openGraph(gg);
|
||||
});
|
||||
|
||||
ui->editTempo->setValue(project->tempo);
|
||||
|
||||
ui->editArtist->setText(project->artist);
|
||||
ui->editTitle->setText(project->title);
|
||||
|
||||
updateTitle();
|
||||
setSongInfoPaneExpanded(false);
|
||||
|
||||
emit projectLoaded();
|
||||
}
|
||||
|
@ -465,14 +489,29 @@ void MainWindow::updatePatternLists() {
|
|||
}
|
||||
|
||||
void MainWindow::updateTitle() {
|
||||
//if (!isVisible()) return; // prevent stupid errors
|
||||
if (!project) return;
|
||||
QString title = u8"Xybrid - %1%2";
|
||||
if (project->fileName.isEmpty()) title = title.arg("(new project)");
|
||||
else title = title.arg(QFileInfo(project->fileName).baseName());
|
||||
if (undoStack->isClean()) title = title.arg("");
|
||||
else title = title.arg("*");
|
||||
this->setWindowTitle(title);
|
||||
QString songTitle;
|
||||
if (project->title.isEmpty()) {
|
||||
if (project->fileName.isEmpty()) songTitle = qs("(new project)");
|
||||
else songTitle = QFileInfo(project->fileName).baseName();
|
||||
} else {
|
||||
if (!project->artist.isEmpty()) songTitle = qs("%1 - %2").arg(project->artist).arg(project->title);
|
||||
else songTitle = project->title;
|
||||
}
|
||||
|
||||
ui->labelSongInfo->setText(songTitle);
|
||||
setWindowTitle(qs("Xybrid - %1%2").arg(songTitle).arg(undoStack->isClean() ? "" : "*"));
|
||||
}
|
||||
|
||||
void MainWindow::setSongInfoPaneExpanded(bool open) {
|
||||
if (open) {
|
||||
ui->songInfoPane->setCurrentIndex(1);
|
||||
} else {
|
||||
ui->songInfoPane->setCurrentIndex(0);
|
||||
}
|
||||
auto s = ui->songInfoPane->currentWidget()->minimumHeight();
|
||||
ui->songInfoPane->setMinimumHeight(s);
|
||||
ui->songInfoPane->setMaximumHeight(s);
|
||||
}
|
||||
|
||||
bool MainWindow::selectPatternForEditing(Pattern* pattern) {
|
||||
|
@ -531,7 +570,7 @@ void MainWindow::openPatternProperties(const std::shared_ptr<Xybrid::Data::Patte
|
|||
dlg->setLayout(dl);
|
||||
//dlg->layout()->setMargin(3);
|
||||
|
||||
auto eName = new QLineEdit(QString::fromStdString(p->name));
|
||||
auto eName = new QLineEdit(p->name);
|
||||
dl->addWidget(eName);
|
||||
//dlg->layout()->setAlignment(eName, Qt::AlignTop);
|
||||
|
||||
|
@ -578,7 +617,7 @@ void MainWindow::openPatternProperties(const std::shared_ptr<Xybrid::Data::Patte
|
|||
connect(bbox, &QDialogButtonBox::rejected, dlg, &QDialog::reject);
|
||||
connect(bbox, &QDialogButtonBox::accepted, dlg, [=] {
|
||||
auto cc = new CompositeCommand();
|
||||
if (auto n = eName->text().toStdString(); n != p->name) cc->compose(new PatternRenameCommand(p, n));
|
||||
if (auto n = eName->text(); n != p->name) cc->compose(new PatternRenameCommand(p, n));
|
||||
if (auto t = Data::TimeSignature(gTimeBeats->value(), gTimeRows->value(), gTimeTicks->value()); t != p->time)
|
||||
cc->compose(new PatternTimeSignatureCommand(p, t));
|
||||
if (auto nr = gLengthBox->value(); nr != p->rows) {
|
||||
|
|
|
@ -41,6 +41,8 @@ namespace Xybrid {
|
|||
|
||||
void updateTitle();
|
||||
|
||||
void setSongInfoPaneExpanded(bool);
|
||||
|
||||
public:
|
||||
const std::shared_ptr<Data::Project>& getProject() const { return project; }
|
||||
|
||||
|
@ -59,6 +61,8 @@ namespace Xybrid {
|
|||
void menuFileSave();
|
||||
void menuFileSaveAs();
|
||||
|
||||
void menuFileNewWindow();
|
||||
|
||||
signals:
|
||||
void projectLoaded();
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>2</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="documentMode">
|
||||
<bool>true</bool>
|
||||
|
@ -118,6 +118,313 @@
|
|||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="songInfoPane">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>28</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="collapsed">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>28</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>28</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="labelSongInfo">
|
||||
<property name="margin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="expandSongInfo">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>28</width>
|
||||
<height>28</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>28</width>
|
||||
<height>28</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="expanded">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>56</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>240</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="songInfo_row1" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>28</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="labelArtist">
|
||||
<property name="text">
|
||||
<string>Artist</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="editArtist">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>128</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="labelTitle">
|
||||
<property name="text">
|
||||
<string>Title</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="editTitle"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="collapseSongInfo">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>28</width>
|
||||
<height>28</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>28</width>
|
||||
<height>28</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="songInfo_row2" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>28</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="labelTempo">
|
||||
<property name="text">
|
||||
<string>Starting Tempo</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="editTempo">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="correctionMode">
|
||||
<enum>QAbstractSpinBox::CorrectToNearestValue</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>10.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>2048.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>140.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableView" name="patternSequencer">
|
||||
<property name="sizePolicy">
|
||||
|
@ -178,6 +485,12 @@
|
|||
</item>
|
||||
<item>
|
||||
<widget class="Xybrid::UI::PatternEditorView" name="patternEditor">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Iosevka Term Light</family>
|
||||
|
@ -379,9 +692,6 @@
|
|||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<zorder>sampleList</zorder>
|
||||
<zorder>sampleViewPane</zorder>
|
||||
<zorder>sampleViewSplitter</zorder>
|
||||
</widget>
|
||||
<widget class="QWidget" name="extra_">
|
||||
<attribute name="title">
|
||||
|
@ -431,6 +741,9 @@
|
|||
<addaction name="actionOpen"/>
|
||||
<addaction name="actionSave"/>
|
||||
<addaction name="actionSave_As"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionNew_Window"/>
|
||||
<addaction name="actionClose_Window"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuEdit">
|
||||
<property name="title">
|
||||
|
@ -490,6 +803,22 @@
|
|||
<bool>true</bool>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionNew_Window">
|
||||
<property name="text">
|
||||
<string>New Window</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Shift+N</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionClose_Window">
|
||||
<property name="text">
|
||||
<string>Close Window</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+W</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
|
@ -578,11 +907,44 @@
|
|||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionNew_Window</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>menuFileNewWindow()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>459</x>
|
||||
<y>305</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionClose_Window</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>close()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>459</x>
|
||||
<y>305</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<slots>
|
||||
<slot>menuFileNew()</slot>
|
||||
<slot>menuFileOpen()</slot>
|
||||
<slot>menuFileSave()</slot>
|
||||
<slot>menuFileSaveAs()</slot>
|
||||
<slot>menuFileNewWindow()</slot>
|
||||
</slots>
|
||||
</ui>
|
||||
|
|
|
@ -142,7 +142,7 @@ QVariant PatternEditorModel::hdrData(int section, Qt::Orientation, int role) con
|
|||
if (role == Qt::DisplayRole || role == Qt::ToolTipRole) {
|
||||
if (pattern->channels.size() == 0) return QString("(no channels)");
|
||||
if (static_cast<size_t>(section) >= pattern->channels.size()) return QString("");
|
||||
auto n = QString::fromStdString(pattern->channels.at(static_cast<size_t>(section)).name);
|
||||
auto n = pattern->channels.at(static_cast<size_t>(section)).name;
|
||||
//if (n.length() == 0) return QString("(Channel %1)").arg(section);
|
||||
if (n.length() == 0) return QString("(ch%1)").arg(section);
|
||||
return n;
|
||||
|
@ -207,7 +207,7 @@ void PatternEditorModel::updateColumnDisplay() {
|
|||
opt.orientation = Qt::Horizontal;
|
||||
opt.section = 0;
|
||||
opt.fontMetrics = view->horizontalHeader()->fontMetrics();
|
||||
opt.text = QString::fromStdString(c.name);
|
||||
opt.text = c.name;
|
||||
minWidth = view->horizontalHeader()->style()->sizeFromContents(QStyle::CT_HeaderSection, &opt, QSize(), view->horizontalHeader()).width();
|
||||
}
|
||||
int lsw = view->columnWidth(lastShown);
|
||||
|
|
|
@ -374,8 +374,8 @@ void PatternEditorView::startRenameChannel(int channel) {
|
|||
auto c = &p->channel(channel);
|
||||
bool ok = false;
|
||||
auto capt = QString("Rename channel %1:").arg(channel);
|
||||
auto n = QInputDialog::getText(this, "Rename...", capt, QLineEdit::Normal, QString::fromStdString(c->name), &ok);
|
||||
auto n = QInputDialog::getText(this, "Rename...", capt, QLineEdit::Normal, c->name, &ok);
|
||||
if (!ok) return; // canceled
|
||||
if (p != mdl->getPattern() || c != &p->channel(channel)) return; // abort if this somehow isn't the channel it was before
|
||||
(new PatternChannelRenameCommand(p, channel, n.toStdString()))->commit();
|
||||
(new PatternChannelRenameCommand(p, channel, n))->commit();
|
||||
}
|
||||
|
|
|
@ -32,10 +32,10 @@ QVariant PatternListModel::data(const QModelIndex &index, int role) const {
|
|||
if (!project) return QVariant();
|
||||
if (role == Qt::DisplayRole) {
|
||||
auto pattern = project->patterns[static_cast<size_t>(index.row())];
|
||||
return QString("%1: %2").arg(pattern->index, 1, 10, QChar('0')).arg(QString::fromStdString(pattern->name.empty() ? "(unnamed)" : pattern->name));
|
||||
return QString("%1: %2").arg(pattern->index, 1, 10, QChar('0')).arg(pattern->name.isEmpty() ? "(unnamed)" : pattern->name);
|
||||
}
|
||||
if (role == Qt::EditRole) {
|
||||
return QString::fromStdString(project->patterns[static_cast<size_t>(index.row())]->name);
|
||||
return project->patterns[static_cast<size_t>(index.row())]->name;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ bool PatternListModel::setData(const QModelIndex &index, const QVariant &value,
|
|||
if (!project) return true;
|
||||
auto pattern = project->patterns[static_cast<size_t>(index.row())];
|
||||
//pattern->name = value.toString().toStdString();
|
||||
return (new PatternRenameCommand(pattern, value.toString().toStdString()))->commit();
|
||||
return (new PatternRenameCommand(pattern, value.toString()))->commit();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -35,8 +35,8 @@ QVariant PatternSequencerModel::data(const QModelIndex &index, int role) const {
|
|||
auto* pattern = project->sequence[static_cast<size_t>(index.column())];
|
||||
if (!pattern) return !toolTip ? QString("-") : QString("(separator)");
|
||||
if (!toolTip) return QString("%1").arg(pattern->index, 1, 10, QChar('0'));
|
||||
if (pattern->name.empty()) return QVariant(); // no tool tip without name
|
||||
return QString("(%1) %2").arg(pattern->index, 1, 10, QChar('0')).arg(QString::fromStdString(pattern->name));
|
||||
if (pattern->name.isEmpty()) return QVariant(); // no tool tip without name
|
||||
return QString("(%1) %2").arg(pattern->index, 1, 10, QChar('0')).arg(pattern->name);
|
||||
}
|
||||
if (role == Qt::TextAlignmentRole ) return Qt::AlignHCenter + Qt::AlignVCenter;
|
||||
return QVariant();
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
#define qs QStringLiteral
|
||||
|
||||
namespace Xybrid::Util {
|
||||
template<typename Num> inline QString numAndName(Num num, const std::string& name) {
|
||||
if (name.empty()) return QString::number(num);
|
||||
return qs("%1 (\"%2\")").arg(num).arg(QString::fromStdString(name));
|
||||
template<typename Num> inline QString numAndName(Num num, const QString& name) {
|
||||
if (name.isEmpty()) return QString::number(num);
|
||||
return qs("%1 (\"%2\")").arg(num).arg(name);
|
||||
}
|
||||
|
||||
inline QString hex(int num, int fw = 2) {
|
||||
|
|
Loading…
Reference in New Issue