123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236 |
- /*
- This file is part of QTau
- Copyright (C) 2013-2018 Tobias "Tomoko" Platen <tplaten@posteo.de>
- Copyright (C) 2013 digited <https://github.com/digited>
- Copyright (C) 2010-2013 HAL@ShurabaP <https://github.com/haruneko>
- QTau is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- SPDX-License-Identifier: GPL-3.0+
- */
- //#define HAVE_DYNDRAWER
- #include "mainwindow.h"
- #include "ui_mainwindow.h"
- #include "qformlayout.h"
- #include <QtGui>
- #include <QtCore>
- #include <QIcon>
- #include "Controller.h"
- #include "Session.h"
- #include <QGridLayout>
- #include <QScrollBar>
- #include <QToolBar>
- #include <QTabWidget>
- #include <QSplitter>
- #include <QGroupBox>
- #include <QScrollArea>
- #include <QTextEdit>
- #include <QComboBox>
- #include <QDial>
- #include <QPushButton>
- #include <QMessageBox>
- #include <QFileDialog>
- #include <QLineEdit>
- #include "ui/Config.h"
- #include "ui/piano.h"
- #include "ui/dynDrawer.h"
- #include "ui/noteEditor.h"
- #include "ui/meter.h"
- #include "tempomap.h"
- #include "ui/tempodialog.h"
- #define __devloglevel__ 8
- const int cdef_bars = 128; // 128 bars "is enough for everyone" // TODO: make dynamic
- const int c_piano_min_width = 110;
- const int c_piano_min_height = 40;
- const int c_meter_min_height = 40;
- const int c_waveform_min_height = 50;
- const int c_drawzone_min_height = 100;
- const int c_dynbuttons_num = 12;
- const QString c_dynlbl_css_off = QString("QLabel { color : %1; }").arg(cdef_color_dynbtn_off);
- const QString c_dynlbl_css_bg = QString("QLabel { color : %1; }").arg(cdef_color_dynbtn_bg);
- const QString c_dynlbl_css_fg = QString("QLabel { color : %1; background-color : %2; }")
- .arg(cdef_color_dynbtn_on).arg(cdef_color_dynbtn_on_bg);
- QSettings settings("QTau_Devgroup", c_qtau_name);
- const QString c_key_dir_score = QStringLiteral("last_score_dir");
- const QString c_key_dir_audio = QStringLiteral("last_audio_dir");
- const QString c_key_win_size = QStringLiteral("window_size");
- const QString c_key_win_max = QStringLiteral("window_fullscreen");
- const QString c_key_show_lognum = QStringLiteral("show_new_log_number");
- const QString c_key_dynpanel_on = QStringLiteral("dynamics_panel_visible");
- const QString c_key_sound = QStringLiteral("sould_level");
- const QString c_key_audio_codec = QStringLiteral("save_audio_codec");
- const QString c_doc_txt = QStringLiteral(":/tr/documentation_en.txt");
- const QString c_icon_app = QStringLiteral(":/images/appicon_ouka_alice.png");
- const QString c_icon_sound = QStringLiteral(":/images/speaker.png");
- const QString c_icon_mute = QStringLiteral(":/images/speaker_mute.png");
- const QString c_icon_editor = QStringLiteral(":/images/b_notes.png");
- const QString c_icon_voices = QStringLiteral(":/images/b_mic.png");
- const QString c_icon_plugins = QStringLiteral(":/images/b_plug.png");
- const QString c_icon_settings = QStringLiteral(":/images/b_gear.png");
- const QString c_icon_doc = QStringLiteral(":/images/b_manual.png");
- const QString c_icon_log = QStringLiteral(":/images/b_envelope.png");
- const QString c_icon_play = QStringLiteral(":/images/b_play.png");
- const QString c_icon_jack = QStringLiteral(":/images/jack-transport.png");
- const QString c_icon_pause = QStringLiteral(":/images/b_pause.png");
- MainWindow::MainWindow(QWidget *parent) :
- QMainWindow(parent), ui(new Ui::MainWindow),
- _logNewMessages(0), _logHasErrors(false), _showNewLogNumber(true)
- {
- _ns.tmap = new TempoMap();
- _ns.tmap->addTempo(0,120);
- _ns.tmap->addTimeSignature(0,4,4);//default values
- _ns.barScreenOffsets = new int[1024];
- _drawZone = nullptr;
- ui->setupUi(this);
- setWindowIcon(QIcon(c_icon_app));
- setWindowTitle(c_qtau_name);
- setAcceptDrops(true);
- setContextMenuPolicy(Qt::NoContextMenu);
- //-----------------------------------------
- _mbe = new MeterBarLineEdit();
- _mbe->setText("");
- _mbl = new QLabel("");
- //QLabel* labelHW = new QLabel("HelloWorld");
- _mbe->setFixedSize(110,20);
- _meter = new qtauMeterBar(this);
- _meter->setMinimumHeight(c_meter_min_height);
- _meter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
- _meter->setContentsMargins(0,0,0,0);
- _piano = new qtauPiano(ui->centralWidget);
- _piano->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
- _piano->setMinimumSize(c_piano_min_width, c_piano_min_height);
- _piano->setContentsMargins(0,0,0,0);
- _zoom = new QSlider(Qt::Horizontal, ui->centralWidget);
- _zoom->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
- _zoom->setRange(0, c_zoom_num - 1);
- _zoom->setSingleStep(1);
- _zoom->setPageStep(1);
- _zoom->setValue(cdef_zoom_index);
- _zoom->setMinimumWidth(c_piano_min_width);
- _zoom->setGeometry(0,0,c_piano_min_width,10);
- _zoom->setContentsMargins(0,0,0,0);
- _noteEditor = new qtauNoteEditor(ui->centralWidget);
- _noteEditor->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
- _noteEditor->setContentsMargins(0,0,0,0);
- _hscr = new QScrollBar(Qt::Horizontal, ui->centralWidget);
- _vscr = new QScrollBar(Qt::Vertical, ui->centralWidget);
- _hscr->setContentsMargins(0,0,0,0);
- _vscr->setContentsMargins(0,0,0,0);
- _hscr->setRange(0, _ns.note.width() * 4 * cdef_bars);//FIXXME
- _vscr->setRange(0, _ns.note.height() * 12 * _ns.numOctaves);
- _hscr->setSingleStep(_ns.note.width());
- _vscr->setSingleStep(_ns.note.height());
- _hscr->setContextMenuPolicy(Qt::NoContextMenu);
- _vscr->setContextMenuPolicy(Qt::NoContextMenu);
- updateSetup();
- //---- vocal and music waveform panels, hidden until synthesized (vocal wave) and/or loaded (music wave)
- QScrollBar *dummySB = new QScrollBar(this);
- dummySB->setOrientation(Qt::Vertical);
- dummySB->setRange(0,0);
- dummySB->setEnabled(false);
- QFrame *waveControls = new QFrame(this);
- waveControls->setContentsMargins(0,0,0,0);
- waveControls->setMinimumSize(c_piano_min_width, c_waveform_min_height);
- waveControls->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
- waveControls->setFrameStyle(QFrame::Panel | QFrame::Raised);
- QGridLayout *waveformL = new QGridLayout();
- waveformL->setContentsMargins(0,0,0,0);
- waveformL->setSpacing(0);
- waveformL->addWidget(waveControls, 0, 0, 2, 1);
- waveformL->addWidget(dummySB, 0, 2, 2, 1);
- _wavePanel = new QWidget(this);
- _wavePanel->setContentsMargins(0,0,0,0);
- _wavePanel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
- _wavePanel->setLayout(waveformL);
- _wavePanel->setVisible(false);
- //---- notes' dynamics setup area --------------
- QGridLayout *dynBtnL = new QGridLayout();
- QString btnNames[c_dynbuttons_num] = {"VEL", "DYN", "BRE", "BRI", "CLE", "OPE", "GEN", "POR", "PIT", "PBS","XSY","GWL"};
- #ifdef HAVE_DYNDRAWER
- for (int i = 0; i < c_dynbuttons_num; ++i)
- {
- qtauDynLabel *l = new qtauDynLabel(btnNames[i], this);
- l->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
- dynBtnL->addWidget(l, i / 2, i % 2, 1, 1);
- l->setStyleSheet(c_dynlbl_css_off);
- l->setFrameStyle(QFrame::Box);
- l->setLineWidth(1);
- connect(l, SIGNAL(leftClicked()), SLOT(dynBtnLClicked()));
- connect(l, SIGNAL(rightClicked()), SLOT(dynBtnRClicked()));
- }
- #endif
- dynBtnL->setRowStretch(c_dynbuttons_num / 2, 100);
- QFrame *dynBtnPanel = new QFrame(this);
- dynBtnPanel->setContentsMargins(0,0,0,0);
- dynBtnPanel->setMinimumSize(c_piano_min_width, c_drawzone_min_height);
- dynBtnPanel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
- dynBtnPanel->setFrameStyle(QFrame::Panel | QFrame::Raised);
- dynBtnPanel->setLayout(dynBtnL);
- _drawZone = new qtauDynDrawer(_noteEditor,ui->centralWidget);
- _drawZone->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
- _drawZone->setMinimumHeight(c_drawzone_min_height);
- _drawZone->setContentsMargins(0,0,0,0);
- _drawZone->configure(_ns);
- QScrollBar *dummySB3 = new QScrollBar(this);
- dummySB3->setOrientation(Qt::Vertical);
- dummySB3->setRange(0,0);
- dummySB3->setEnabled(false);
- QHBoxLayout *singParamsL = new QHBoxLayout();
- singParamsL->setContentsMargins(0,0,0,0);
- singParamsL->setSpacing(0);
- singParamsL->addWidget(dynBtnPanel);
- singParamsL->addWidget(_drawZone);
- singParamsL->addWidget(dummySB3);
- _drawZonePanel = new QWidget(this);
- _drawZonePanel->setContentsMargins(0,0,0,0);
- _drawZonePanel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
- _drawZonePanel->setLayout(singParamsL);
- //---- Combining editor panels into hi-level layout ------
- QGridLayout *gl = new QGridLayout();
- gl->setContentsMargins(0,0,0,0);
- gl->setSpacing(0);
- QFrame* meterFrame = new QFrame(this);
- QVBoxLayout* meterLayout = new QVBoxLayout();
- meterLayout->setSpacing(0);
- meterLayout->setMargin(0);
- meterFrame->setMaximumSize(110,40);
- meterFrame->setLayout(meterLayout);
- meterLayout->addWidget(_mbl);
- meterLayout->addWidget(_mbe);
- gl->addWidget(meterFrame, 0, 0, 1, 1);
- gl->addWidget(_meter, 0, 1, 1, 1);
- gl->addWidget(_piano, 1, 0, 1, 1);
- gl->addWidget(_zoom, 2, 0, 1, 1);
- gl->addWidget(_noteEditor, 1, 1, 1, 1);
- gl->addWidget(_hscr, 2, 1, 1, 1);
- gl->addWidget(_vscr, 1, 2, 1, 1);
- QWidget *editorUpperPanel = new QWidget(this);
- editorUpperPanel->setContentsMargins(0,0,0,0);
- editorUpperPanel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
- editorUpperPanel->setMaximumSize(9000,9000);
- editorUpperPanel->setLayout(gl);
- _editorSplitter = new QSplitter(Qt::Vertical, this);
- _editorSplitter->setContentsMargins(0,0,0,0);
- _editorSplitter->addWidget(editorUpperPanel);
- _wavePanel->setVisible(false);//keep wavepanel for now, but set hidden
- _editorSplitter->addWidget(_wavePanel);
- #ifdef HAVE_DYNDRAWER
- _drawZonePanel->setVisible(true);
- #else
- _drawZonePanel->setVisible(false);
- #endif
- _editorSplitter->addWidget(_drawZonePanel);
- _editorSplitter->setStretchFactor(0, 1);
- _editorSplitter->setStretchFactor(1, 0);
- _editorSplitter->setStretchFactor(2, 0);
- _editorSplitter->setStretchFactor(3, 0);
- QList<int> sizes = _editorSplitter->sizes();
- sizes[1] = 0;
- _editorSplitter->setSizes(sizes);
- QVBoxLayout *edVBL = new QVBoxLayout();
- edVBL->setContentsMargins(0,0,0,0);
- edVBL->addWidget(_editorSplitter);
- QWidget *editorPanel = new QWidget(this);
- editorPanel->setContentsMargins(0,0,0,0);
- editorPanel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
- editorPanel->setMaximumSize(9000,9000);
- editorPanel->setLayout(edVBL);
- //---- Log tab ---------------------------------
- QWidget *logPanel = new QWidget(this);
- logPanel->setContentsMargins(0,0,0,0);
- logPanel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
- logPanel->setMaximumSize(9000,9000);
- _logpad = new QTextEdit(this);
- _logpad->setReadOnly(true);
- _logpad->setUndoRedoEnabled(false);
- _logpad->setContextMenuPolicy(Qt::NoContextMenu);
- _logpad->setStyleSheet("p, pre { white-space: 1.2; }");
- QGridLayout *logL = new QGridLayout();
- logL->setContentsMargins(0,0,0,0);
- logL->addWidget(_logpad, 0, 0, 1, 1);
- logPanel->setLayout(logL);
- //---- Combining tabs togeter ------------------
- _tabs = new QTabWidget(this);
- _tabs->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
- _tabs->setContentsMargins(0,0,0,0);
- _tabs->setMaximumSize(9000, 9000);
- _tabs->setTabPosition(QTabWidget::South);
- _tabs->setMovable(false); // just to be sure
- _tabs->addTab(editorPanel, QIcon(c_icon_editor), tr("Editor"));
- _tabs->addTab(logPanel, QIcon(c_icon_log), tr("Log"));
- _tabs->widget(0)->setContentsMargins(0,0,0,0);
- _tabs->widget(1)->setContentsMargins(0,0,0,0);
- _logTabTextColor = _tabs->tabBar()->tabTextColor(1);
- connect(_tabs, SIGNAL(currentChanged(int)), SLOT(onTabSelected(int)));
- QVBoxLayout *vbl = new QVBoxLayout();
- vbl->setContentsMargins(0,0,0,0);
- vbl->addWidget(_tabs);
- ui->centralWidget->setContentsMargins(0,0,0,0);
- ui->centralWidget->setLayout(vbl);
- //---- Toolbars --------------------------------
- QToolBar *fileTB = new QToolBar("Fileops", this);
- QToolBar *playerTB = new QToolBar("Playback", this);
- QToolBar *toolsTB = new QToolBar("Toolset", this);
- fileTB ->setFloatable(false);
- playerTB->setFloatable(false);
- toolsTB ->setFloatable(false);
- fileTB->addAction(ui->actionSave);
- fileTB->addAction(ui->actionSave_audio_as);
- fileTB->addAction(ui->actionUndo);
- fileTB->addAction(ui->actionRedo);
- playerTB->addAction(ui->actionPlay);
- playerTB->addAction(ui->actionStop);
- playerTB->addAction(ui->actionBack);
- playerTB->addAction(ui->actionJack);
- QComboBox *quantizeCombo = new QComboBox(this);
- QComboBox *lengthCombo = new QComboBox(this);
- quantizeCombo->addItems(QStringList() << "Q/4" << "Q/8" << "Q/16" << "Q/32" << "Q/64");
- lengthCombo ->addItems(QStringList() << "♪/4" << "♪/8" << "♪/16" << "♪/32" << "♪/64");
- quantizeCombo->setCurrentIndex(3);
- lengthCombo ->setCurrentIndex(3);
- toolsTB->addAction(ui->actionEdit_Mode);
- toolsTB->addAction(ui->actionGrid_Snap);
- toolsTB->addSeparator();
- toolsTB->addWidget(quantizeCombo);
- toolsTB->addWidget(lengthCombo);
- toolsTB->addSeparator();
- toolsTB->addWidget(new QLabel("Singer: "));
- _singerSelect = new QComboBox();
- _singerSelect->setMinimumWidth(100);
- connect(_singerSelect, SIGNAL(currentIndexChanged(int)), SLOT(onSingerSelected(int)));
- toolsTB->addWidget(_singerSelect);
- for (int i = 0; i < MAXRECENTFILES; ++i) {
- _recentFileActs[i] = new QAction(this);
- _recentFileActs[i]->setVisible(false);
- this->ui->menuRecent_files->addAction(_recentFileActs[i]);
- connect(_recentFileActs[i], SIGNAL(triggered()),
- this, SLOT(openRecentFile()));
- }
- updateRecentFileActions();
- addToolBar(fileTB);
- addToolBar(playerTB);
- addToolBar(toolsTB);
- _toolbars.append(fileTB);
- _toolbars.append(playerTB);
- _toolbars.append(toolsTB);
- //----------------------------------------------
- connect(quantizeCombo, SIGNAL(currentIndexChanged(int)), SLOT(onQuantizeSelected(int)));
- connect(lengthCombo, SIGNAL(currentIndexChanged(int)), SLOT(onNotelengthSelected(int)));
- connect(_piano, &qtauPiano ::heightChanged, this, &MainWindow::onPianoHeightChanged);
- connect(_noteEditor, &qtauNoteEditor ::widthChanged, this, &MainWindow::onNoteEditorWidthChanged);
- connect(_meter, &qtauMeterBar ::scrolled, this, &MainWindow::notesHScrolled);
- connect(_piano, &qtauPiano ::scrolled, this, &MainWindow::notesVScrolled);
- connect(_drawZone, &qtauDynDrawer ::scrolled, this, &MainWindow::notesHScrolled);
- connect(_noteEditor, &qtauNoteEditor ::vscrolled, this, &MainWindow::notesVScrolled);
- connect(_noteEditor, &qtauNoteEditor ::hscrolled, this, &MainWindow::notesHScrolled);
- connect(_vscr, &QScrollBar ::valueChanged, this, &MainWindow::vertScrolled);
- connect(_hscr, &QScrollBar ::valueChanged, this, &MainWindow::horzScrolled);
- connect(_noteEditor, &qtauNoteEditor ::rmbScrolled, this, &MainWindow::onEditorRMBScrolled);
- connect(_noteEditor, &qtauNoteEditor ::requestsOffset, this, &MainWindow::onEditorRequestOffset);
- connect(_zoom, &QSlider ::valueChanged, this, &MainWindow::onZoomed);
- connect(_meter, &qtauMeterBar ::zoomed, this, &MainWindow::onEditorZoomed);
- connect(_noteEditor, &qtauNoteEditor ::zoomed, this, &MainWindow::onEditorZoomed);
- connect(_drawZone, &qtauDynDrawer ::zoomed, this, &MainWindow::onEditorZoomed);
- connect(ui->actionQuit, &QAction::triggered, [=]() { this->close(); });
- connect(ui->actionOpen, &QAction::triggered, this, &MainWindow::onOpenUST);
- connect(ui->actionSave, &QAction::triggered, this, &MainWindow::onSaveUST);
- connect(ui->actionSave_as, &QAction::triggered, this, &MainWindow::onSaveUSTAs);
- connect(ui->actionMIDI,&QAction::triggered,this,&MainWindow::onMIDIImport);
- connect(ui->actionMIDI_2,&QAction::triggered,this,&MainWindow::onMIDIExport);
- connect(ui->actionUndo, &QAction::triggered, this, &MainWindow::onUndo);
- connect(ui->actionRedo, &QAction::triggered, this, &MainWindow::onRedo);
- connect(ui->actionDelete, &QAction::triggered, this, &MainWindow::onDelete);
- connect(ui->actionEdit_Mode, &QAction::triggered, this, &MainWindow::onEditMode);
- connect(ui->actionGrid_Snap, &QAction::triggered, this, &MainWindow::onGridSnap);
- //----------------------------------------------
- _lastScoreDir = settings.value(c_key_dir_score, "").toString();
- _lastAudioDir = settings.value(c_key_dir_audio, "").toString();
- _audioExt = settings.value(c_key_audio_codec, "").toString();
- _showNewLogNumber = settings.value(c_key_show_lognum, true).toBool();
- if (!settings.value(c_key_dynpanel_on, true).toBool())
- {
- QList<int> panelSizes = _editorSplitter->sizes();
- panelSizes.last() = 0;
- _editorSplitter->setSizes(panelSizes);
- }
- if (settings.value(c_key_win_max, false).toBool())
- showMaximized();
- else
- {
- QRect winGeom = geometry();
- QRect setGeom = settings.value(c_key_win_size, QRect(winGeom.topLeft(), minimumSize())).value<QRect>();
- if (setGeom.width() >= winGeom.width() && setGeom.height() >= setGeom.height())
- setGeometry(setGeom);
- }
- //----------------------------------------------
- // -- hacks for debugging UI -- remove or refactor
- ui->actionPlay->setText(tr("Play"));
- ui->actionPlay->setIcon(QIcon(c_icon_play));
- ui->actionStop->setEnabled(true);
- ui->actionBack->setEnabled(true);
- ui->actionRepeat->setEnabled(false);
- ui->actionSave_audio_as->setEnabled(false);
- ui->actionPlay->setChecked(false);
- ui->actionRepeat->setChecked(false);
- ui->actionPlay->setEnabled(true);
- _menuPlugins = new QMenu("Plugins", this);
- this->ui->menuTools->addMenu(_menuPlugins);
- }
- void MainWindow::addPluginAction(QAction* action)
- {
- _menuPlugins->addAction(action);
- }
- void MainWindow::closeEvent(QCloseEvent *event)
- {
- // store settings
- settings.setValue(c_key_dir_score, _lastScoreDir);
- settings.setValue(c_key_dir_audio, _lastAudioDir);
- settings.setValue(c_key_win_size, geometry());
- settings.setValue(c_key_win_max, isMaximized());
- settings.setValue(c_key_show_lognum, _showNewLogNumber);
- settings.setValue(c_key_audio_codec, _audioExt);
- settings.setValue(c_key_dynpanel_on, _editorSplitter->sizes().last() > 0);
- event->accept();
- }
- MainWindow::~MainWindow() { delete ui; }
- //========================================================================================
- bool MainWindow::setController(qtauController &c, qtauSession &s)
- {
- // NOTE: bind what uses qtauSession only here (menu/toolbar button states etc)
- _doc = &s;
- _ctrl = &c;
- connect(_noteEditor, &qtauNoteEditor::editorEvent, _doc, &qtauSession::onUIEvent );
- connect(&c,&qtauController::transportPositionChanged,this,&MainWindow::onTransportPositionChanged);
- connect(ui->actionNew,&QAction::triggered,&s,&qtauSession::onNewSession);
- connect(_doc, &qtauSession::dataReloaded, this, &MainWindow::onDocReloaded );
- connect(_doc, &qtauSession::modifiedStatus, this, &MainWindow::onDocStatus );
- connect(_doc, &qtauSession::undoStatus, this, &MainWindow::onUndoStatus );
- connect(_doc, &qtauSession::redoStatus, this, &MainWindow::onRedoStatus );
- connect(_doc, &qtauSession::onEvent, this, &MainWindow::onDocEvent );
- connect(ui->actionPlay, &QAction::triggered, &c, &qtauController::onRequestStartPlayback );
- connect(ui->actionStop, &QAction::triggered, &c, &qtauController::onRequestStopPlayback );
- connect(ui->actionBack, &QAction::triggered, &c, &qtauController::onRequestResetPlayback );
- connect(this, &MainWindow::loadUST, &c, &qtauController::onLoadUST );
- connect(this, &MainWindow::saveUST, &c, &qtauController::onSaveUST );
- connect(_piano, &qtauPiano::keyPressed, &c, &qtauController::pianoKeyPressed );
- connect(_piano, &qtauPiano::keyReleased, &c, &qtauController::pianoKeyReleased);
- connect(ui->actionJack, &QAction::triggered, this, &MainWindow::onActionJackTriggered );
- connect(_meter, &qtauMeterBar::barClicked, this, &MainWindow::meter_barClicked);
- connect(_mbe,&MeterBarLineEdit::keyPressHooked,this, &MainWindow::mbe_keyPressHooked);
- //-----------------------------------------------------------------------
- // widget configuration - maybe read app settings here?
- _noteEditor->setRMBScrollEnabled(!ui->actionEdit_Mode->isChecked());
- _noteEditor->setEditingEnabled ( ui->actionEdit_Mode->isChecked());
- _noteEditor->setFocus();
- foreach(QString voice,c.voices())
- {
- _singerSelect->addItem(voice);
- }
- return true;
- }
- void MainWindow::updateUndoRedoTexts()
- {
- if(_doc->canUndo())
- ui->actionUndo->setText("Undo "+_doc->undoAction());
- else
- ui->actionUndo->setText("Undo");
- if(_doc->canRedo())
- ui->actionRedo->setText("Redo "+_doc->redoAction());
- else
- ui->actionRedo->setText("Redo");
- }
- void MainWindow::onOpenUST()
- {
- QString fileName = QFileDialog::getOpenFileName(this,
- tr("Open USTJ"), _lastScoreDir, tr("UTAU JSON Sequence Text Files (*.ustj)"));
- if (!fileName.isEmpty())
- {
- _lastScoreDir = QFileInfo(fileName).absolutePath();
- emit loadUST(fileName);
- }
- }
- void MainWindow::onSaveUST()
- {
- if (_doc->documentFile().isEmpty())
- onSaveUSTAs();
- else
- emit saveUST(_doc->documentFile(), true);
- }
- void MainWindow::onSaveUSTAs()
- {
- QString fileName = QFileDialog::getSaveFileName(this,
- tr("Save USTJ"), _lastScoreDir, tr("UTAU JSON Sequence Text Files (*.ustj)"));
- if (!fileName.isEmpty())
- {
- if(!fileName.endsWith(".ustj")) fileName+=".ustj";
- _lastScoreDir = QFileInfo(fileName).absolutePath();
- emit saveUST(fileName, true);
- }
- }
- void MainWindow::onTransportPositionChanged(float pos)
- {
- _noteEditor->setPlaybackPosition(pos*480); //FIXME: do not hardcode utau
- }
- void MainWindow::onMIDIImport()
- {
- QString fileName = QFileDialog::getOpenFileName(this, tr("Import MIDI"),
- QString(""), //FIXME do not hardcode
- tr("MIDI Files (*.mid *.mid *.smf)"));
- _doc->importMIDI(fileName);
- }
- void MainWindow::onMIDIExport()
- {
- QString fileName = QFileDialog::getSaveFileName(this, tr("Export as MIDI"),
- QString(),
- tr("MIDI Files (*.mid *.mid *.smf)"));
- if(!fileName.endsWith(".mid")) fileName+=".mid";
- _doc->exportMIDI(fileName);
- }
- void MainWindow::notesVScrolled(int delta)
- {
- if (delta > 0 && _vscr->value() > 0) // scroll up
- delta = -_ns.note.height();
- else if (delta < 0 && _vscr->value() < _vscr->maximum()) // scroll down
- delta = _ns.note.height();
- else
- delta = 0;
- if (delta != 0)
- _vscr->setValue(_vscr->value() + delta);
- }
- void MainWindow::notesHScrolled(int delta)
- {
- if (delta > 0 && _hscr->value() > 0) // scroll left
- delta = -_ns.note.width();
- else if (delta < 0 && _hscr->value() < _hscr->maximum()) // scroll right
- delta = _ns.note.width();
- else
- delta = 0;
- if (delta != 0)
- _hscr->setValue(_hscr->value() + delta);
- }
- void MainWindow::vertScrolled(int delta)
- {
- _piano->setOffset(delta);
- _noteEditor->setVOffset(delta);
- }
- void MainWindow::horzScrolled(int delta)
- {
- _noteEditor->setHOffset(delta);
- _meter ->setOffset (delta);
- _drawZone ->setOffset (delta);
- }
- void MainWindow::onEditorRMBScrolled(QPoint mouseDelta, QPoint origOffset)
- {
- // moving editor space in reverse of mouse delta
- int hOff = qMax(qMin(origOffset.x() - mouseDelta.x(), _hscr->maximum()), 0);
- int vOff = qMax(qMin(origOffset.y() - mouseDelta.y(), _vscr->maximum()), 0);
- _hscr->setValue(hOff);
- _vscr->setValue(vOff);
- }
- void MainWindow::onEditorRequestOffset(QPoint off)
- {
- off.setX(qMax(qMin(off.x(), _hscr->maximum()), 0));
- off.setY(qMax(qMin(off.y(), _vscr->maximum()), 0));
- _hscr->setValue(off.x());
- _vscr->setValue(off.y());
- }
- void MainWindow::onPianoHeightChanged(int newHeight)
- {
- _vscr->setMaximum(_ns.note.height() * 12 * _ns.numOctaves - newHeight + 1);
- _vscr->setPageStep(_piano->geometry().height());
- }
- void MainWindow::onNoteEditorWidthChanged(int newWidth)
- {
- //_hscr->setMaximum(_ns.note.width() * _ns.notesInBar * cdef_bars - newWidth + 1);
- _hscr->setMaximum(_ns.note.width() * 4 * cdef_bars - newWidth + 1);
- _hscr->setPageStep(_noteEditor->geometry().width());
- }
- void MainWindow::onUndo()
- {
- if (_doc->canUndo())
- _doc->undo();
- else
- ui->actionUndo->setEnabled(false);
- updateUndoRedoTexts();
- }
- void MainWindow::onRedo()
- {
- if (_doc->canRedo())
- _doc->redo();
- else
- ui->actionRedo->setEnabled(false);
- updateUndoRedoTexts();
- }
- void MainWindow::onDelete()
- {
- _noteEditor->deleteSelected();
- }
- void MainWindow::onEditMode(bool toggled)
- {
- _noteEditor->setEditingEnabled ( toggled);
- _noteEditor->setRMBScrollEnabled(!toggled);
- }
- void MainWindow::onGridSnap(bool toggled)
- {
- _noteEditor->setGridSnapEnabled(toggled);
- }
- void MainWindow::onQuantizeSelected(int index)
- {
- int newQuant = 4 * (int)(pow(2, index) + 0.001);
- if (newQuant != _ns.quantize)
- {
- _ns.quantize = newQuant;
- _noteEditor->configure(_ns);
- }
- }
- void MainWindow::onNotelengthSelected(int index)
- {
- int newNoteLength = 4 * (int)(pow(2, index) + 0.001);
- if (newNoteLength != _ns.length)
- {
- _ns.length = newNoteLength;
- _noteEditor->configure(_ns);
- }
- }
- void MainWindow::dynBtnLClicked()
- {
- qtauDynLabel* l= qobject_cast<qtauDynLabel*>(sender());
- if (l && (_fgDynLbl == 0 || l != _fgDynLbl))
- {
- if (_fgDynLbl)
- {
- _fgDynLbl->setState(qtauDynLabel::off);
- _fgDynLbl->setStyleSheet(c_dynlbl_css_off);
- }
- if (l == _bgDynLbl)
- {
- _bgDynLbl->setState(qtauDynLabel::off);
- _bgDynLbl->setStyleSheet(c_dynlbl_css_off);
- _bgDynLbl = 0;
- }
- l->setStyleSheet(c_dynlbl_css_fg);
- _fgDynLbl = l;
- }
- }
- void MainWindow::dynBtnRClicked()
- {
- qtauDynLabel* l= qobject_cast<qtauDynLabel*>(sender());
- if (l)
- {
- if (_bgDynLbl != 0 && l == _bgDynLbl)
- {
- // clicking on same dynkey - switch it off
- _bgDynLbl->setState(qtauDynLabel::off);
- _bgDynLbl->setStyleSheet(c_dynlbl_css_off);
- _bgDynLbl = 0;
- }
- else
- { // clicking on other dynkey
- if (_bgDynLbl)
- { // switch off previous one, if any
- _bgDynLbl->setState(qtauDynLabel::off);
- _bgDynLbl->setStyleSheet(c_dynlbl_css_off);
- _bgDynLbl = 0;
- }
- if (l != _fgDynLbl)
- { // clicking on not-foreground dynkey
- l->setStyleSheet(c_dynlbl_css_bg);
- _bgDynLbl = l;
- }
- }
- }
- }
- void MainWindow::onLog(const QString &msg, ELog type)
- {
- QString color = "black";
- bool viewingLog = _tabs->currentIndex() == _tabs->count() - 1;
- switch(type)
- {
- case ELog::error:
- color = "red";
- break;
- case ELog::success:
- color = "green";
- break;
- default: break;
- }
- if (!viewingLog)
- {
- QTabBar *tb = const_cast<QTabBar *>(_tabs->tabBar()); // dirty hack I know, but no other way atm
- if (_showNewLogNumber)
- {
- tb->setTabText(tb->count() - 1, tr("Log") + QString(" (%1)").arg(_logNewMessages));
- _logNewMessages++;
- }
- if (type == ELog::error)
- {
- tb->setTabTextColor(tb->count() - 1, QColor(cdef_color_logtab_err));
- _logHasErrors = true;
- }
- }
- _logpad->moveCursor(QTextCursor::End);
- _logpad->insertHtml(QString("<pre style=\"color: %1;\">%2</pre><p></p>").arg(color).arg(msg));
- }
- void MainWindow::enableToolbars(bool enable)
- {
- foreach (QToolBar *t, _toolbars)
- t->setVisible(enable); //t->setEnabled(enable);
- }
- void MainWindow::onTabSelected(int index)
- {
- enableToolbars(index == 0);
- if (index == _tabs->count() - 1)
- {
- QTabBar *tb = const_cast<QTabBar *>(_tabs->tabBar());
- if (_logNewMessages > 0)
- {
- tb->setTabText(tb->count() - 1, tr("Log"));
- _logNewMessages = 0;
- }
- if (_logHasErrors)
- {
- tb->setTabTextColor(tb->count() - 1, _logTabTextColor); // set default color back
- _logHasErrors = false;
- }
- }
- }
- void MainWindow::onZoomed(int z)
- {
- // modify note data and send it to widgets
- _ns.note.setWidth(c_zoom_note_widths[z]);
- _meter ->configure2(_ns);
- _piano ->configure(_ns);
- _noteEditor->configure(_ns);
- _drawZone ->configure(_ns);
- // modify scrollbar sizes and position
- double hscr_val = (double)_hscr->value() / _hscr->maximum();
- _hscr->setMaximum(_ns.note.width() * 4 * cdef_bars - _noteEditor->width() + 1);
- _hscr->setValue(_hscr->maximum() * hscr_val);
- _hscr->setSingleStep(_ns.note.width());
- horzScrolled(_hscr->value());
- }
- void MainWindow::onEditorZoomed(int delta)
- {
- if (delta != 0)
- if ((delta > 0 && _zoom->value() >= 0) ||
- (delta < 0 && _zoom->value() < c_zoom_num))
- _zoom->setValue(_zoom->value() + ((delta > 0) ? 1 : -1));
- }
- void MainWindow::onDocReloaded()
- {
- setWindowTitle(_doc->documentName() + " - QTau");
- _noteEditor->reset();
- }
- void MainWindow::onDocStatus(bool isModified)
- {
- QString newDocName = _doc->documentName();
- if (_docName != newDocName)
- _docName = newDocName;
- setWindowTitle((isModified ? "*" : "") + _docName + " - QTau");
- ui->actionSave->setEnabled(isModified);
- }
- void MainWindow::onUndoStatus(bool canUndo)
- {
- ui->actionUndo->setEnabled(canUndo);
- updateUndoRedoTexts();
- }
- void MainWindow::onRedoStatus(bool canRedo)
- {
- ui->actionRedo->setEnabled(canRedo);
- updateUndoRedoTexts();
- }
- void MainWindow::onDocEvent(qtauEvent* event)
- {
- //FIXME: why here
- QString singerName = _doc->getSingerName();
- if(singerName.length())
- {
- int count = _singerSelect->count();
- for(int i=0;i<count;i++)
- {
- if(singerName==_singerSelect->itemText(i))
- {
- _singerSelect->setCurrentIndex(i);
- _ctrl->selectSinger(singerName);
- break;
- }
- }
- }
- QJsonArray arr = _doc->getTempoMap();
- if(arr.size())
- {
- _ns.tmap->fromJson(arr);
- DEVLOG_DEBUG("update setup from json");
- updateSetup();
- }
- if (event->type() >= ENoteEvents::add && event->type() <= ENoteEvents::effect)
- _noteEditor->onEvent(event);
- else
- DEVLOG_ERROR("bad event");
- }
- void MainWindow::dragEnterEvent(QDragEnterEvent *event)
- {
- // accepting filepaths
- if (event->mimeData()->hasFormat("text/uri-list"))
- event->acceptProposedAction();
- }
- void MainWindow::dragMoveEvent(QDragMoveEvent *event)
- {
- // accepting filepaths
- if (event->mimeData()->hasFormat("text/uri-list"))
- event->acceptProposedAction();
- }
- void MainWindow::dropEvent(QDropEvent *event)
- {
- QList<QUrl> uris;
- foreach (const QByteArray &uriData, event->mimeData()->data("text/uri-list").split('\n'))
- if (!uriData.isEmpty())
- uris << QUrl::fromEncoded(uriData).toLocalFile().remove('\r');
- if (!uris.isEmpty())
- {
- QFileInfo fi(uris.first().toString());
- if (uris.size() > 1)
- DEVLOG_DEBUG("Multiple URIs dropped, currently using only first one");
- if (fi.exists() && !fi.isDir() && !fi.suffix().isEmpty()) // if it's an existing file with some extension
- {
- // maybe it's a note/lyrics file? (ust/vsq/vsqx/midi)
- if (fi.suffix() == "ustj")
- {
- emit loadUST(fi.absoluteFilePath());
- }
- else
- DEVLOG_ERROR("File extension not supported: " + fi.suffix());
- }
- }
- }
- //autoconneccted slot
- void MainWindow::on_actionPhoneme_Transformation_triggered()
- {
- _noteEditor->doPhonemeTransformation();
- }
- void MainWindow::onSingerSelected(int index)
- {
- _ctrl->selectSinger(_singerSelect->itemText(index));
- _doc->setSingerName(_singerSelect->itemText(index));
- }
- void MainWindow::onActionJackTriggered()
- {
- QAction* a = (QAction*)QObject::sender();
- _ctrl->setJackTranportEnabled(a->isChecked());
- }
- void MainWindow::markOverlappingNotes(quint64 id1, quint64 id2)
- {
- _noteEditor->setNoteColor(id1,EColor::red);
- _noteEditor->setNoteColor(id2,EColor::red);
- onLog("found overlapping notes",ELog::error);
- _noteEditor->update();
- }
- void MainWindow::updateNoteColors()
- {
- foreach(quint64 id,_noteEditor->getNoteIDs())
- {
- _noteEditor->setNoteColor(id,EColor::none);
- }
- }
- void MainWindow::updateSetup()
- {
- //DEVLOG_DEBUG("MainWindow::updateSetup()");
- _piano->configure(_ns);
- _meter->configure2(_ns);
- _noteEditor->configure(_ns);
- if(_drawZone) _drawZone ->configure(_ns);
- }
- void MainWindow::updateRecentFileActions()
- {
- QSettings settings;
- QStringList files = settings.value("recentFileList").toStringList();
- int numRecentFiles = qMin(files.size(), (int)MAXRECENTFILES);
- for (int i = 0; i < numRecentFiles; ++i) {
- QString fileName = QFileInfo(files[i]).fileName();
- QString text = tr("&%1 %2").arg(i + 1).arg(fileName);
- _recentFileActs[i]->setText(text);
- _recentFileActs[i]->setData(files[i]);
- _recentFileActs[i]->setVisible(true);
- }
- for (int j = numRecentFiles; j < MAXRECENTFILES; ++j)
- _recentFileActs[j]->setVisible(false);
- }
- void MainWindow::openRecentFile()
- {
- QAction *action = qobject_cast<QAction *>(sender());
- if (action)
- {
- QString ustFileName = action->data().toString();
- if(QFile(ustFileName).exists())
- loadUST(ustFileName);
- else
- {
- QSettings settings;
- QStringList files = settings.value("recentFileList").toStringList();
- files.removeOne(ustFileName);
- settings.setValue("recentFileList", files);
- updateRecentFileActions();
- QMessageBox msgBox;
- msgBox.setText("The file \""+ustFileName+"\"does not exist.");
- msgBox.exec();
- }
- }
- }
- void MainWindow::on_actionSave_Last_Play_triggered()
- {
- QString lastPlay = _ctrl->lastPlay();
- DEVLOG_DEBUG("lastPlay: "+lastPlay);
- if(lastPlay.length())
- {
- QString fileName = QFileInfo(lastPlay).fileName();
- QString fileNameCopy = QFileDialog::getSaveFileName(this,
- tr("Save Last Play"), _lastScoreDir, tr("WAV Files (*.wav)"));
- if (!fileNameCopy.isEmpty())
- {
- if(!fileNameCopy.endsWith(".wav")) fileNameCopy+=".wav";
- DEVLOG_DEBUG("CP lastPlay: "+fileNameCopy);
- if(QFileInfo(fileNameCopy).exists())
- QFile::remove(fileNameCopy);
- QFile::copy(lastPlay,fileNameCopy);
- }
- }
- }
- struct selectionRange MainWindow::getSelectionRange()
- {
- return _noteEditor->getSelectionRange();
- }
- void MainWindow::on_actionMusicXML_triggered()
- {
- QString fileName = QFileDialog::getOpenFileName(this, tr("Import MusicXML"),
- QString("/home/hatsunemiku/Music/MIDIs/"), //FIXME do not hardcode
- tr("MusicXML Files (*.xml)"));
- _doc->importMusicXML(fileName);
- }
- void MainWindow::on_actionUST_triggered()
- {
- QString fileName = QFileDialog::getOpenFileName(this, tr("Import MusicXML"),
- QString("/home/hatsunemiku/Music/MIDIs/"), //FIXME do not hardcode
- tr("UTAU Sequence Text Files (*.ust)"));
- _doc->importUST(fileName);
- }
- void MainWindow::updateTMap()
- {
- QJsonArray array;
- _ns.tmap->toJson(array);
- _doc->setTempoMap(array);
- updateSetup();
- }
- void MainWindow::on_actionEdit_Tempo_Time_Signature_triggered()
- {
- _ns.tmap->beginEditing();
- TempoDialog dialog(_ns.tmap,this);
- if(dialog.exec()==QDialog::Accepted)
- {
- updateTMap();
- }
- else
- {
- //UNDO changes
- _ns.tmap->undo();
- }
- }
- void MainWindow::meter_barClicked(int bar, tmlabel mode)
- {
- //TODO update gui
- _current_bar=bar;
- _current_mode=mode;
- if(mode==TM_BPM)
- {
- _mbl->setText("["+STR(bar)+"] BPM=");
- _mbe->setText("120");//FIXME
- _mbe->setFocus();
- }
- else
- {
- _mbl->setText("["+STR(bar)+"] SIG=");
- _mbe->setText("4/4");
- _mbe->setFocus();
- }
- }
- void MainWindow::mbe_keyPressHooked(int)
- {
- //TODO insert event
- QString text = _mbe->text();
- if(_current_mode==TM_BPM || _current_mode==TM_SIG)
- {
- if(_ns.tmap->setLabel(_current_mode,_current_bar-1,text))
- {
- updateTMap();
- _mbl->setText("");
- _mbe->setText("");
- _current_mode = TM_ALL;
- }
- }
- else
- {
- QStringList cmd = text.split(" ");
- if(cmd.length()==2)
- {
- if(cmd[0]=="BPM") meter_barClicked(QVariant(cmd[1]).toInt(),TM_BPM);
- if(cmd[0]=="SIG") meter_barClicked(QVariant(cmd[1]).toInt(),TM_SIG);
- }
- }
- }
|