1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189 |
- /*
- 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+
- */
- #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 "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__ 4
- 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 = 20;
- 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
- _drawZone = nullptr;
- ui->setupUi(this);
- setWindowIcon(QIcon(c_icon_app));
- setWindowTitle(c_qtau_name);
- setAcceptDrops(true);
- setContextMenuPolicy(Qt::NoContextMenu);
- //-----------------------------------------
- DEVLOG_DEBUG("setup Tempo Map");
- //FIXME tempo ui
- // _meterLabel = new QLabel(QString("%1/%2") .arg(_ns.notesInBar).arg(_ns.noteLength), this);
- // _tempoLabel = new QLabel(QString("%1 %2").arg(_ns.tempo).arg(tr("bpm")), this);
- // _meterLabel = new QLabel(QString("%1/%2") .arg(0).arg(0), this);
- //_tempoLabel = new QLabel(QString("%1 %2").arg(0).arg(tr("bpm")), this);
- QPushButton* tempoSelect = new QPushButton("change Tempo");
- tempoSelect->setMaximumHeight(20);
- tempoSelect->setMaximumWidth(100);
- connect(tempoSelect,&QPushButton::clicked,this,&MainWindow::onTempoSelectClicked);
- QHBoxLayout *bpmHBL = new QHBoxLayout();
- bpmHBL->setContentsMargins(0,0,0,0);
- //bpmHBL->addSpacing(5);
- bpmHBL->addWidget(tempoSelect);
- //bpmHBL->addWidget(_meterLabel);
- //bpmHBL->addWidget(_tempoLabel);
- //bpmHBL->addSpacing(5);
- //add Transpose here ?
- QFrame *tempoPanel = new QFrame(this);
- tempoPanel->setMinimumSize(c_piano_min_width, c_meter_min_height);
- tempoPanel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
- tempoPanel->setContentsMargins(1,0,1,1);
- tempoPanel->setFrameStyle(QFrame::Panel | QFrame::Raised);
- tempoPanel->setLayout(bpmHBL);
- _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() * _ns.notesInBar * cdef_bars);
- _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"};
- #if 0
- 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);
- gl->addWidget(tempoPanel, 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);
- _drawZonePanel->setVisible(false);
- _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 );
- //TODO void onRequestSynthesis();
- 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 );
- //-----------------------------------------------------------------------
- // 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 ->configure(_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() * _ns.notesInBar * cdef_bars - _noteEditor->width() + 1);
- _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::onTempoSelectClicked()
- {
- _ns.tmap->beginEditing();
- TempoDialog dialog(_ns.tmap,this);
- if(dialog.exec()==QDialog::Accepted)
- {
- QJsonArray array;
- _ns.tmap->toJson(array);
- _doc->setTempoMap(array);
- DEVLOG_DEBUG("update_setup");
- updateSetup();
- }
- else
- {
- //UNDO changes
- _ns.tmap->undo();
- }
- }
- 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()
- {
- _piano->configure(_ns);
- _meter->configure(_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);
- }
|