mainwindow.cpp 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236
  1. /*
  2. This file is part of QTau
  3. Copyright (C) 2013-2018 Tobias "Tomoko" Platen <tplaten@posteo.de>
  4. Copyright (C) 2013 digited <https://github.com/digited>
  5. Copyright (C) 2010-2013 HAL@ShurabaP <https://github.com/haruneko>
  6. QTau is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. SPDX-License-Identifier: GPL-3.0+
  17. */
  18. //#define HAVE_DYNDRAWER
  19. #include "mainwindow.h"
  20. #include "ui_mainwindow.h"
  21. #include "qformlayout.h"
  22. #include <QtGui>
  23. #include <QtCore>
  24. #include <QIcon>
  25. #include "Controller.h"
  26. #include "Session.h"
  27. #include <QGridLayout>
  28. #include <QScrollBar>
  29. #include <QToolBar>
  30. #include <QTabWidget>
  31. #include <QSplitter>
  32. #include <QGroupBox>
  33. #include <QScrollArea>
  34. #include <QTextEdit>
  35. #include <QComboBox>
  36. #include <QDial>
  37. #include <QPushButton>
  38. #include <QMessageBox>
  39. #include <QFileDialog>
  40. #include <QLineEdit>
  41. #include "ui/Config.h"
  42. #include "ui/piano.h"
  43. #include "ui/dynDrawer.h"
  44. #include "ui/noteEditor.h"
  45. #include "ui/meter.h"
  46. #include "tempomap.h"
  47. #include "ui/tempodialog.h"
  48. #define __devloglevel__ 8
  49. const int cdef_bars = 128; // 128 bars "is enough for everyone" // TODO: make dynamic
  50. const int c_piano_min_width = 110;
  51. const int c_piano_min_height = 40;
  52. const int c_meter_min_height = 40;
  53. const int c_waveform_min_height = 50;
  54. const int c_drawzone_min_height = 100;
  55. const int c_dynbuttons_num = 12;
  56. const QString c_dynlbl_css_off = QString("QLabel { color : %1; }").arg(cdef_color_dynbtn_off);
  57. const QString c_dynlbl_css_bg = QString("QLabel { color : %1; }").arg(cdef_color_dynbtn_bg);
  58. const QString c_dynlbl_css_fg = QString("QLabel { color : %1; background-color : %2; }")
  59. .arg(cdef_color_dynbtn_on).arg(cdef_color_dynbtn_on_bg);
  60. QSettings settings("QTau_Devgroup", c_qtau_name);
  61. const QString c_key_dir_score = QStringLiteral("last_score_dir");
  62. const QString c_key_dir_audio = QStringLiteral("last_audio_dir");
  63. const QString c_key_win_size = QStringLiteral("window_size");
  64. const QString c_key_win_max = QStringLiteral("window_fullscreen");
  65. const QString c_key_show_lognum = QStringLiteral("show_new_log_number");
  66. const QString c_key_dynpanel_on = QStringLiteral("dynamics_panel_visible");
  67. const QString c_key_sound = QStringLiteral("sould_level");
  68. const QString c_key_audio_codec = QStringLiteral("save_audio_codec");
  69. const QString c_doc_txt = QStringLiteral(":/tr/documentation_en.txt");
  70. const QString c_icon_app = QStringLiteral(":/images/appicon_ouka_alice.png");
  71. const QString c_icon_sound = QStringLiteral(":/images/speaker.png");
  72. const QString c_icon_mute = QStringLiteral(":/images/speaker_mute.png");
  73. const QString c_icon_editor = QStringLiteral(":/images/b_notes.png");
  74. const QString c_icon_voices = QStringLiteral(":/images/b_mic.png");
  75. const QString c_icon_plugins = QStringLiteral(":/images/b_plug.png");
  76. const QString c_icon_settings = QStringLiteral(":/images/b_gear.png");
  77. const QString c_icon_doc = QStringLiteral(":/images/b_manual.png");
  78. const QString c_icon_log = QStringLiteral(":/images/b_envelope.png");
  79. const QString c_icon_play = QStringLiteral(":/images/b_play.png");
  80. const QString c_icon_jack = QStringLiteral(":/images/jack-transport.png");
  81. const QString c_icon_pause = QStringLiteral(":/images/b_pause.png");
  82. MainWindow::MainWindow(QWidget *parent) :
  83. QMainWindow(parent), ui(new Ui::MainWindow),
  84. _logNewMessages(0), _logHasErrors(false), _showNewLogNumber(true)
  85. {
  86. _ns.tmap = new TempoMap();
  87. _ns.tmap->addTempo(0,120);
  88. _ns.tmap->addTimeSignature(0,4,4);//default values
  89. _ns.barScreenOffsets = new int[1024];
  90. _drawZone = nullptr;
  91. ui->setupUi(this);
  92. setWindowIcon(QIcon(c_icon_app));
  93. setWindowTitle(c_qtau_name);
  94. setAcceptDrops(true);
  95. setContextMenuPolicy(Qt::NoContextMenu);
  96. //-----------------------------------------
  97. _mbe = new MeterBarLineEdit();
  98. _mbe->setText("");
  99. _mbl = new QLabel("");
  100. //QLabel* labelHW = new QLabel("HelloWorld");
  101. _mbe->setFixedSize(110,20);
  102. _meter = new qtauMeterBar(this);
  103. _meter->setMinimumHeight(c_meter_min_height);
  104. _meter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
  105. _meter->setContentsMargins(0,0,0,0);
  106. _piano = new qtauPiano(ui->centralWidget);
  107. _piano->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
  108. _piano->setMinimumSize(c_piano_min_width, c_piano_min_height);
  109. _piano->setContentsMargins(0,0,0,0);
  110. _zoom = new QSlider(Qt::Horizontal, ui->centralWidget);
  111. _zoom->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
  112. _zoom->setRange(0, c_zoom_num - 1);
  113. _zoom->setSingleStep(1);
  114. _zoom->setPageStep(1);
  115. _zoom->setValue(cdef_zoom_index);
  116. _zoom->setMinimumWidth(c_piano_min_width);
  117. _zoom->setGeometry(0,0,c_piano_min_width,10);
  118. _zoom->setContentsMargins(0,0,0,0);
  119. _noteEditor = new qtauNoteEditor(ui->centralWidget);
  120. _noteEditor->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  121. _noteEditor->setContentsMargins(0,0,0,0);
  122. _hscr = new QScrollBar(Qt::Horizontal, ui->centralWidget);
  123. _vscr = new QScrollBar(Qt::Vertical, ui->centralWidget);
  124. _hscr->setContentsMargins(0,0,0,0);
  125. _vscr->setContentsMargins(0,0,0,0);
  126. _hscr->setRange(0, _ns.note.width() * 4 * cdef_bars);//FIXXME
  127. _vscr->setRange(0, _ns.note.height() * 12 * _ns.numOctaves);
  128. _hscr->setSingleStep(_ns.note.width());
  129. _vscr->setSingleStep(_ns.note.height());
  130. _hscr->setContextMenuPolicy(Qt::NoContextMenu);
  131. _vscr->setContextMenuPolicy(Qt::NoContextMenu);
  132. updateSetup();
  133. //---- vocal and music waveform panels, hidden until synthesized (vocal wave) and/or loaded (music wave)
  134. QScrollBar *dummySB = new QScrollBar(this);
  135. dummySB->setOrientation(Qt::Vertical);
  136. dummySB->setRange(0,0);
  137. dummySB->setEnabled(false);
  138. QFrame *waveControls = new QFrame(this);
  139. waveControls->setContentsMargins(0,0,0,0);
  140. waveControls->setMinimumSize(c_piano_min_width, c_waveform_min_height);
  141. waveControls->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
  142. waveControls->setFrameStyle(QFrame::Panel | QFrame::Raised);
  143. QGridLayout *waveformL = new QGridLayout();
  144. waveformL->setContentsMargins(0,0,0,0);
  145. waveformL->setSpacing(0);
  146. waveformL->addWidget(waveControls, 0, 0, 2, 1);
  147. waveformL->addWidget(dummySB, 0, 2, 2, 1);
  148. _wavePanel = new QWidget(this);
  149. _wavePanel->setContentsMargins(0,0,0,0);
  150. _wavePanel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
  151. _wavePanel->setLayout(waveformL);
  152. _wavePanel->setVisible(false);
  153. //---- notes' dynamics setup area --------------
  154. QGridLayout *dynBtnL = new QGridLayout();
  155. QString btnNames[c_dynbuttons_num] = {"VEL", "DYN", "BRE", "BRI", "CLE", "OPE", "GEN", "POR", "PIT", "PBS","XSY","GWL"};
  156. #ifdef HAVE_DYNDRAWER
  157. for (int i = 0; i < c_dynbuttons_num; ++i)
  158. {
  159. qtauDynLabel *l = new qtauDynLabel(btnNames[i], this);
  160. l->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
  161. dynBtnL->addWidget(l, i / 2, i % 2, 1, 1);
  162. l->setStyleSheet(c_dynlbl_css_off);
  163. l->setFrameStyle(QFrame::Box);
  164. l->setLineWidth(1);
  165. connect(l, SIGNAL(leftClicked()), SLOT(dynBtnLClicked()));
  166. connect(l, SIGNAL(rightClicked()), SLOT(dynBtnRClicked()));
  167. }
  168. #endif
  169. dynBtnL->setRowStretch(c_dynbuttons_num / 2, 100);
  170. QFrame *dynBtnPanel = new QFrame(this);
  171. dynBtnPanel->setContentsMargins(0,0,0,0);
  172. dynBtnPanel->setMinimumSize(c_piano_min_width, c_drawzone_min_height);
  173. dynBtnPanel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
  174. dynBtnPanel->setFrameStyle(QFrame::Panel | QFrame::Raised);
  175. dynBtnPanel->setLayout(dynBtnL);
  176. _drawZone = new qtauDynDrawer(_noteEditor,ui->centralWidget);
  177. _drawZone->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
  178. _drawZone->setMinimumHeight(c_drawzone_min_height);
  179. _drawZone->setContentsMargins(0,0,0,0);
  180. _drawZone->configure(_ns);
  181. QScrollBar *dummySB3 = new QScrollBar(this);
  182. dummySB3->setOrientation(Qt::Vertical);
  183. dummySB3->setRange(0,0);
  184. dummySB3->setEnabled(false);
  185. QHBoxLayout *singParamsL = new QHBoxLayout();
  186. singParamsL->setContentsMargins(0,0,0,0);
  187. singParamsL->setSpacing(0);
  188. singParamsL->addWidget(dynBtnPanel);
  189. singParamsL->addWidget(_drawZone);
  190. singParamsL->addWidget(dummySB3);
  191. _drawZonePanel = new QWidget(this);
  192. _drawZonePanel->setContentsMargins(0,0,0,0);
  193. _drawZonePanel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
  194. _drawZonePanel->setLayout(singParamsL);
  195. //---- Combining editor panels into hi-level layout ------
  196. QGridLayout *gl = new QGridLayout();
  197. gl->setContentsMargins(0,0,0,0);
  198. gl->setSpacing(0);
  199. QFrame* meterFrame = new QFrame(this);
  200. QVBoxLayout* meterLayout = new QVBoxLayout();
  201. meterLayout->setSpacing(0);
  202. meterLayout->setMargin(0);
  203. meterFrame->setMaximumSize(110,40);
  204. meterFrame->setLayout(meterLayout);
  205. meterLayout->addWidget(_mbl);
  206. meterLayout->addWidget(_mbe);
  207. gl->addWidget(meterFrame, 0, 0, 1, 1);
  208. gl->addWidget(_meter, 0, 1, 1, 1);
  209. gl->addWidget(_piano, 1, 0, 1, 1);
  210. gl->addWidget(_zoom, 2, 0, 1, 1);
  211. gl->addWidget(_noteEditor, 1, 1, 1, 1);
  212. gl->addWidget(_hscr, 2, 1, 1, 1);
  213. gl->addWidget(_vscr, 1, 2, 1, 1);
  214. QWidget *editorUpperPanel = new QWidget(this);
  215. editorUpperPanel->setContentsMargins(0,0,0,0);
  216. editorUpperPanel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  217. editorUpperPanel->setMaximumSize(9000,9000);
  218. editorUpperPanel->setLayout(gl);
  219. _editorSplitter = new QSplitter(Qt::Vertical, this);
  220. _editorSplitter->setContentsMargins(0,0,0,0);
  221. _editorSplitter->addWidget(editorUpperPanel);
  222. _wavePanel->setVisible(false);//keep wavepanel for now, but set hidden
  223. _editorSplitter->addWidget(_wavePanel);
  224. #ifdef HAVE_DYNDRAWER
  225. _drawZonePanel->setVisible(true);
  226. #else
  227. _drawZonePanel->setVisible(false);
  228. #endif
  229. _editorSplitter->addWidget(_drawZonePanel);
  230. _editorSplitter->setStretchFactor(0, 1);
  231. _editorSplitter->setStretchFactor(1, 0);
  232. _editorSplitter->setStretchFactor(2, 0);
  233. _editorSplitter->setStretchFactor(3, 0);
  234. QList<int> sizes = _editorSplitter->sizes();
  235. sizes[1] = 0;
  236. _editorSplitter->setSizes(sizes);
  237. QVBoxLayout *edVBL = new QVBoxLayout();
  238. edVBL->setContentsMargins(0,0,0,0);
  239. edVBL->addWidget(_editorSplitter);
  240. QWidget *editorPanel = new QWidget(this);
  241. editorPanel->setContentsMargins(0,0,0,0);
  242. editorPanel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  243. editorPanel->setMaximumSize(9000,9000);
  244. editorPanel->setLayout(edVBL);
  245. //---- Log tab ---------------------------------
  246. QWidget *logPanel = new QWidget(this);
  247. logPanel->setContentsMargins(0,0,0,0);
  248. logPanel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  249. logPanel->setMaximumSize(9000,9000);
  250. _logpad = new QTextEdit(this);
  251. _logpad->setReadOnly(true);
  252. _logpad->setUndoRedoEnabled(false);
  253. _logpad->setContextMenuPolicy(Qt::NoContextMenu);
  254. _logpad->setStyleSheet("p, pre { white-space: 1.2; }");
  255. QGridLayout *logL = new QGridLayout();
  256. logL->setContentsMargins(0,0,0,0);
  257. logL->addWidget(_logpad, 0, 0, 1, 1);
  258. logPanel->setLayout(logL);
  259. //---- Combining tabs togeter ------------------
  260. _tabs = new QTabWidget(this);
  261. _tabs->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  262. _tabs->setContentsMargins(0,0,0,0);
  263. _tabs->setMaximumSize(9000, 9000);
  264. _tabs->setTabPosition(QTabWidget::South);
  265. _tabs->setMovable(false); // just to be sure
  266. _tabs->addTab(editorPanel, QIcon(c_icon_editor), tr("Editor"));
  267. _tabs->addTab(logPanel, QIcon(c_icon_log), tr("Log"));
  268. _tabs->widget(0)->setContentsMargins(0,0,0,0);
  269. _tabs->widget(1)->setContentsMargins(0,0,0,0);
  270. _logTabTextColor = _tabs->tabBar()->tabTextColor(1);
  271. connect(_tabs, SIGNAL(currentChanged(int)), SLOT(onTabSelected(int)));
  272. QVBoxLayout *vbl = new QVBoxLayout();
  273. vbl->setContentsMargins(0,0,0,0);
  274. vbl->addWidget(_tabs);
  275. ui->centralWidget->setContentsMargins(0,0,0,0);
  276. ui->centralWidget->setLayout(vbl);
  277. //---- Toolbars --------------------------------
  278. QToolBar *fileTB = new QToolBar("Fileops", this);
  279. QToolBar *playerTB = new QToolBar("Playback", this);
  280. QToolBar *toolsTB = new QToolBar("Toolset", this);
  281. fileTB ->setFloatable(false);
  282. playerTB->setFloatable(false);
  283. toolsTB ->setFloatable(false);
  284. fileTB->addAction(ui->actionSave);
  285. fileTB->addAction(ui->actionSave_audio_as);
  286. fileTB->addAction(ui->actionUndo);
  287. fileTB->addAction(ui->actionRedo);
  288. playerTB->addAction(ui->actionPlay);
  289. playerTB->addAction(ui->actionStop);
  290. playerTB->addAction(ui->actionBack);
  291. playerTB->addAction(ui->actionJack);
  292. QComboBox *quantizeCombo = new QComboBox(this);
  293. QComboBox *lengthCombo = new QComboBox(this);
  294. quantizeCombo->addItems(QStringList() << "Q/4" << "Q/8" << "Q/16" << "Q/32" << "Q/64");
  295. lengthCombo ->addItems(QStringList() << "♪/4" << "♪/8" << "♪/16" << "♪/32" << "♪/64");
  296. quantizeCombo->setCurrentIndex(3);
  297. lengthCombo ->setCurrentIndex(3);
  298. toolsTB->addAction(ui->actionEdit_Mode);
  299. toolsTB->addAction(ui->actionGrid_Snap);
  300. toolsTB->addSeparator();
  301. toolsTB->addWidget(quantizeCombo);
  302. toolsTB->addWidget(lengthCombo);
  303. toolsTB->addSeparator();
  304. toolsTB->addWidget(new QLabel("Singer: "));
  305. _singerSelect = new QComboBox();
  306. _singerSelect->setMinimumWidth(100);
  307. connect(_singerSelect, SIGNAL(currentIndexChanged(int)), SLOT(onSingerSelected(int)));
  308. toolsTB->addWidget(_singerSelect);
  309. for (int i = 0; i < MAXRECENTFILES; ++i) {
  310. _recentFileActs[i] = new QAction(this);
  311. _recentFileActs[i]->setVisible(false);
  312. this->ui->menuRecent_files->addAction(_recentFileActs[i]);
  313. connect(_recentFileActs[i], SIGNAL(triggered()),
  314. this, SLOT(openRecentFile()));
  315. }
  316. updateRecentFileActions();
  317. addToolBar(fileTB);
  318. addToolBar(playerTB);
  319. addToolBar(toolsTB);
  320. _toolbars.append(fileTB);
  321. _toolbars.append(playerTB);
  322. _toolbars.append(toolsTB);
  323. //----------------------------------------------
  324. connect(quantizeCombo, SIGNAL(currentIndexChanged(int)), SLOT(onQuantizeSelected(int)));
  325. connect(lengthCombo, SIGNAL(currentIndexChanged(int)), SLOT(onNotelengthSelected(int)));
  326. connect(_piano, &qtauPiano ::heightChanged, this, &MainWindow::onPianoHeightChanged);
  327. connect(_noteEditor, &qtauNoteEditor ::widthChanged, this, &MainWindow::onNoteEditorWidthChanged);
  328. connect(_meter, &qtauMeterBar ::scrolled, this, &MainWindow::notesHScrolled);
  329. connect(_piano, &qtauPiano ::scrolled, this, &MainWindow::notesVScrolled);
  330. connect(_drawZone, &qtauDynDrawer ::scrolled, this, &MainWindow::notesHScrolled);
  331. connect(_noteEditor, &qtauNoteEditor ::vscrolled, this, &MainWindow::notesVScrolled);
  332. connect(_noteEditor, &qtauNoteEditor ::hscrolled, this, &MainWindow::notesHScrolled);
  333. connect(_vscr, &QScrollBar ::valueChanged, this, &MainWindow::vertScrolled);
  334. connect(_hscr, &QScrollBar ::valueChanged, this, &MainWindow::horzScrolled);
  335. connect(_noteEditor, &qtauNoteEditor ::rmbScrolled, this, &MainWindow::onEditorRMBScrolled);
  336. connect(_noteEditor, &qtauNoteEditor ::requestsOffset, this, &MainWindow::onEditorRequestOffset);
  337. connect(_zoom, &QSlider ::valueChanged, this, &MainWindow::onZoomed);
  338. connect(_meter, &qtauMeterBar ::zoomed, this, &MainWindow::onEditorZoomed);
  339. connect(_noteEditor, &qtauNoteEditor ::zoomed, this, &MainWindow::onEditorZoomed);
  340. connect(_drawZone, &qtauDynDrawer ::zoomed, this, &MainWindow::onEditorZoomed);
  341. connect(ui->actionQuit, &QAction::triggered, [=]() { this->close(); });
  342. connect(ui->actionOpen, &QAction::triggered, this, &MainWindow::onOpenUST);
  343. connect(ui->actionSave, &QAction::triggered, this, &MainWindow::onSaveUST);
  344. connect(ui->actionSave_as, &QAction::triggered, this, &MainWindow::onSaveUSTAs);
  345. connect(ui->actionMIDI,&QAction::triggered,this,&MainWindow::onMIDIImport);
  346. connect(ui->actionMIDI_2,&QAction::triggered,this,&MainWindow::onMIDIExport);
  347. connect(ui->actionUndo, &QAction::triggered, this, &MainWindow::onUndo);
  348. connect(ui->actionRedo, &QAction::triggered, this, &MainWindow::onRedo);
  349. connect(ui->actionDelete, &QAction::triggered, this, &MainWindow::onDelete);
  350. connect(ui->actionEdit_Mode, &QAction::triggered, this, &MainWindow::onEditMode);
  351. connect(ui->actionGrid_Snap, &QAction::triggered, this, &MainWindow::onGridSnap);
  352. //----------------------------------------------
  353. _lastScoreDir = settings.value(c_key_dir_score, "").toString();
  354. _lastAudioDir = settings.value(c_key_dir_audio, "").toString();
  355. _audioExt = settings.value(c_key_audio_codec, "").toString();
  356. _showNewLogNumber = settings.value(c_key_show_lognum, true).toBool();
  357. if (!settings.value(c_key_dynpanel_on, true).toBool())
  358. {
  359. QList<int> panelSizes = _editorSplitter->sizes();
  360. panelSizes.last() = 0;
  361. _editorSplitter->setSizes(panelSizes);
  362. }
  363. if (settings.value(c_key_win_max, false).toBool())
  364. showMaximized();
  365. else
  366. {
  367. QRect winGeom = geometry();
  368. QRect setGeom = settings.value(c_key_win_size, QRect(winGeom.topLeft(), minimumSize())).value<QRect>();
  369. if (setGeom.width() >= winGeom.width() && setGeom.height() >= setGeom.height())
  370. setGeometry(setGeom);
  371. }
  372. //----------------------------------------------
  373. // -- hacks for debugging UI -- remove or refactor
  374. ui->actionPlay->setText(tr("Play"));
  375. ui->actionPlay->setIcon(QIcon(c_icon_play));
  376. ui->actionStop->setEnabled(true);
  377. ui->actionBack->setEnabled(true);
  378. ui->actionRepeat->setEnabled(false);
  379. ui->actionSave_audio_as->setEnabled(false);
  380. ui->actionPlay->setChecked(false);
  381. ui->actionRepeat->setChecked(false);
  382. ui->actionPlay->setEnabled(true);
  383. _menuPlugins = new QMenu("Plugins", this);
  384. this->ui->menuTools->addMenu(_menuPlugins);
  385. }
  386. void MainWindow::addPluginAction(QAction* action)
  387. {
  388. _menuPlugins->addAction(action);
  389. }
  390. void MainWindow::closeEvent(QCloseEvent *event)
  391. {
  392. // store settings
  393. settings.setValue(c_key_dir_score, _lastScoreDir);
  394. settings.setValue(c_key_dir_audio, _lastAudioDir);
  395. settings.setValue(c_key_win_size, geometry());
  396. settings.setValue(c_key_win_max, isMaximized());
  397. settings.setValue(c_key_show_lognum, _showNewLogNumber);
  398. settings.setValue(c_key_audio_codec, _audioExt);
  399. settings.setValue(c_key_dynpanel_on, _editorSplitter->sizes().last() > 0);
  400. event->accept();
  401. }
  402. MainWindow::~MainWindow() { delete ui; }
  403. //========================================================================================
  404. bool MainWindow::setController(qtauController &c, qtauSession &s)
  405. {
  406. // NOTE: bind what uses qtauSession only here (menu/toolbar button states etc)
  407. _doc = &s;
  408. _ctrl = &c;
  409. connect(_noteEditor, &qtauNoteEditor::editorEvent, _doc, &qtauSession::onUIEvent );
  410. connect(&c,&qtauController::transportPositionChanged,this,&MainWindow::onTransportPositionChanged);
  411. connect(ui->actionNew,&QAction::triggered,&s,&qtauSession::onNewSession);
  412. connect(_doc, &qtauSession::dataReloaded, this, &MainWindow::onDocReloaded );
  413. connect(_doc, &qtauSession::modifiedStatus, this, &MainWindow::onDocStatus );
  414. connect(_doc, &qtauSession::undoStatus, this, &MainWindow::onUndoStatus );
  415. connect(_doc, &qtauSession::redoStatus, this, &MainWindow::onRedoStatus );
  416. connect(_doc, &qtauSession::onEvent, this, &MainWindow::onDocEvent );
  417. connect(ui->actionPlay, &QAction::triggered, &c, &qtauController::onRequestStartPlayback );
  418. connect(ui->actionStop, &QAction::triggered, &c, &qtauController::onRequestStopPlayback );
  419. connect(ui->actionBack, &QAction::triggered, &c, &qtauController::onRequestResetPlayback );
  420. connect(this, &MainWindow::loadUST, &c, &qtauController::onLoadUST );
  421. connect(this, &MainWindow::saveUST, &c, &qtauController::onSaveUST );
  422. connect(_piano, &qtauPiano::keyPressed, &c, &qtauController::pianoKeyPressed );
  423. connect(_piano, &qtauPiano::keyReleased, &c, &qtauController::pianoKeyReleased);
  424. connect(ui->actionJack, &QAction::triggered, this, &MainWindow::onActionJackTriggered );
  425. connect(_meter, &qtauMeterBar::barClicked, this, &MainWindow::meter_barClicked);
  426. connect(_mbe,&MeterBarLineEdit::keyPressHooked,this, &MainWindow::mbe_keyPressHooked);
  427. //-----------------------------------------------------------------------
  428. // widget configuration - maybe read app settings here?
  429. _noteEditor->setRMBScrollEnabled(!ui->actionEdit_Mode->isChecked());
  430. _noteEditor->setEditingEnabled ( ui->actionEdit_Mode->isChecked());
  431. _noteEditor->setFocus();
  432. foreach(QString voice,c.voices())
  433. {
  434. _singerSelect->addItem(voice);
  435. }
  436. return true;
  437. }
  438. void MainWindow::updateUndoRedoTexts()
  439. {
  440. if(_doc->canUndo())
  441. ui->actionUndo->setText("Undo "+_doc->undoAction());
  442. else
  443. ui->actionUndo->setText("Undo");
  444. if(_doc->canRedo())
  445. ui->actionRedo->setText("Redo "+_doc->redoAction());
  446. else
  447. ui->actionRedo->setText("Redo");
  448. }
  449. void MainWindow::onOpenUST()
  450. {
  451. QString fileName = QFileDialog::getOpenFileName(this,
  452. tr("Open USTJ"), _lastScoreDir, tr("UTAU JSON Sequence Text Files (*.ustj)"));
  453. if (!fileName.isEmpty())
  454. {
  455. _lastScoreDir = QFileInfo(fileName).absolutePath();
  456. emit loadUST(fileName);
  457. }
  458. }
  459. void MainWindow::onSaveUST()
  460. {
  461. if (_doc->documentFile().isEmpty())
  462. onSaveUSTAs();
  463. else
  464. emit saveUST(_doc->documentFile(), true);
  465. }
  466. void MainWindow::onSaveUSTAs()
  467. {
  468. QString fileName = QFileDialog::getSaveFileName(this,
  469. tr("Save USTJ"), _lastScoreDir, tr("UTAU JSON Sequence Text Files (*.ustj)"));
  470. if (!fileName.isEmpty())
  471. {
  472. if(!fileName.endsWith(".ustj")) fileName+=".ustj";
  473. _lastScoreDir = QFileInfo(fileName).absolutePath();
  474. emit saveUST(fileName, true);
  475. }
  476. }
  477. void MainWindow::onTransportPositionChanged(float pos)
  478. {
  479. _noteEditor->setPlaybackPosition(pos*480); //FIXME: do not hardcode utau
  480. }
  481. void MainWindow::onMIDIImport()
  482. {
  483. QString fileName = QFileDialog::getOpenFileName(this, tr("Import MIDI"),
  484. QString(""), //FIXME do not hardcode
  485. tr("MIDI Files (*.mid *.mid *.smf)"));
  486. _doc->importMIDI(fileName);
  487. }
  488. void MainWindow::onMIDIExport()
  489. {
  490. QString fileName = QFileDialog::getSaveFileName(this, tr("Export as MIDI"),
  491. QString(),
  492. tr("MIDI Files (*.mid *.mid *.smf)"));
  493. if(!fileName.endsWith(".mid")) fileName+=".mid";
  494. _doc->exportMIDI(fileName);
  495. }
  496. void MainWindow::notesVScrolled(int delta)
  497. {
  498. if (delta > 0 && _vscr->value() > 0) // scroll up
  499. delta = -_ns.note.height();
  500. else if (delta < 0 && _vscr->value() < _vscr->maximum()) // scroll down
  501. delta = _ns.note.height();
  502. else
  503. delta = 0;
  504. if (delta != 0)
  505. _vscr->setValue(_vscr->value() + delta);
  506. }
  507. void MainWindow::notesHScrolled(int delta)
  508. {
  509. if (delta > 0 && _hscr->value() > 0) // scroll left
  510. delta = -_ns.note.width();
  511. else if (delta < 0 && _hscr->value() < _hscr->maximum()) // scroll right
  512. delta = _ns.note.width();
  513. else
  514. delta = 0;
  515. if (delta != 0)
  516. _hscr->setValue(_hscr->value() + delta);
  517. }
  518. void MainWindow::vertScrolled(int delta)
  519. {
  520. _piano->setOffset(delta);
  521. _noteEditor->setVOffset(delta);
  522. }
  523. void MainWindow::horzScrolled(int delta)
  524. {
  525. _noteEditor->setHOffset(delta);
  526. _meter ->setOffset (delta);
  527. _drawZone ->setOffset (delta);
  528. }
  529. void MainWindow::onEditorRMBScrolled(QPoint mouseDelta, QPoint origOffset)
  530. {
  531. // moving editor space in reverse of mouse delta
  532. int hOff = qMax(qMin(origOffset.x() - mouseDelta.x(), _hscr->maximum()), 0);
  533. int vOff = qMax(qMin(origOffset.y() - mouseDelta.y(), _vscr->maximum()), 0);
  534. _hscr->setValue(hOff);
  535. _vscr->setValue(vOff);
  536. }
  537. void MainWindow::onEditorRequestOffset(QPoint off)
  538. {
  539. off.setX(qMax(qMin(off.x(), _hscr->maximum()), 0));
  540. off.setY(qMax(qMin(off.y(), _vscr->maximum()), 0));
  541. _hscr->setValue(off.x());
  542. _vscr->setValue(off.y());
  543. }
  544. void MainWindow::onPianoHeightChanged(int newHeight)
  545. {
  546. _vscr->setMaximum(_ns.note.height() * 12 * _ns.numOctaves - newHeight + 1);
  547. _vscr->setPageStep(_piano->geometry().height());
  548. }
  549. void MainWindow::onNoteEditorWidthChanged(int newWidth)
  550. {
  551. //_hscr->setMaximum(_ns.note.width() * _ns.notesInBar * cdef_bars - newWidth + 1);
  552. _hscr->setMaximum(_ns.note.width() * 4 * cdef_bars - newWidth + 1);
  553. _hscr->setPageStep(_noteEditor->geometry().width());
  554. }
  555. void MainWindow::onUndo()
  556. {
  557. if (_doc->canUndo())
  558. _doc->undo();
  559. else
  560. ui->actionUndo->setEnabled(false);
  561. updateUndoRedoTexts();
  562. }
  563. void MainWindow::onRedo()
  564. {
  565. if (_doc->canRedo())
  566. _doc->redo();
  567. else
  568. ui->actionRedo->setEnabled(false);
  569. updateUndoRedoTexts();
  570. }
  571. void MainWindow::onDelete()
  572. {
  573. _noteEditor->deleteSelected();
  574. }
  575. void MainWindow::onEditMode(bool toggled)
  576. {
  577. _noteEditor->setEditingEnabled ( toggled);
  578. _noteEditor->setRMBScrollEnabled(!toggled);
  579. }
  580. void MainWindow::onGridSnap(bool toggled)
  581. {
  582. _noteEditor->setGridSnapEnabled(toggled);
  583. }
  584. void MainWindow::onQuantizeSelected(int index)
  585. {
  586. int newQuant = 4 * (int)(pow(2, index) + 0.001);
  587. if (newQuant != _ns.quantize)
  588. {
  589. _ns.quantize = newQuant;
  590. _noteEditor->configure(_ns);
  591. }
  592. }
  593. void MainWindow::onNotelengthSelected(int index)
  594. {
  595. int newNoteLength = 4 * (int)(pow(2, index) + 0.001);
  596. if (newNoteLength != _ns.length)
  597. {
  598. _ns.length = newNoteLength;
  599. _noteEditor->configure(_ns);
  600. }
  601. }
  602. void MainWindow::dynBtnLClicked()
  603. {
  604. qtauDynLabel* l= qobject_cast<qtauDynLabel*>(sender());
  605. if (l && (_fgDynLbl == 0 || l != _fgDynLbl))
  606. {
  607. if (_fgDynLbl)
  608. {
  609. _fgDynLbl->setState(qtauDynLabel::off);
  610. _fgDynLbl->setStyleSheet(c_dynlbl_css_off);
  611. }
  612. if (l == _bgDynLbl)
  613. {
  614. _bgDynLbl->setState(qtauDynLabel::off);
  615. _bgDynLbl->setStyleSheet(c_dynlbl_css_off);
  616. _bgDynLbl = 0;
  617. }
  618. l->setStyleSheet(c_dynlbl_css_fg);
  619. _fgDynLbl = l;
  620. }
  621. }
  622. void MainWindow::dynBtnRClicked()
  623. {
  624. qtauDynLabel* l= qobject_cast<qtauDynLabel*>(sender());
  625. if (l)
  626. {
  627. if (_bgDynLbl != 0 && l == _bgDynLbl)
  628. {
  629. // clicking on same dynkey - switch it off
  630. _bgDynLbl->setState(qtauDynLabel::off);
  631. _bgDynLbl->setStyleSheet(c_dynlbl_css_off);
  632. _bgDynLbl = 0;
  633. }
  634. else
  635. { // clicking on other dynkey
  636. if (_bgDynLbl)
  637. { // switch off previous one, if any
  638. _bgDynLbl->setState(qtauDynLabel::off);
  639. _bgDynLbl->setStyleSheet(c_dynlbl_css_off);
  640. _bgDynLbl = 0;
  641. }
  642. if (l != _fgDynLbl)
  643. { // clicking on not-foreground dynkey
  644. l->setStyleSheet(c_dynlbl_css_bg);
  645. _bgDynLbl = l;
  646. }
  647. }
  648. }
  649. }
  650. void MainWindow::onLog(const QString &msg, ELog type)
  651. {
  652. QString color = "black";
  653. bool viewingLog = _tabs->currentIndex() == _tabs->count() - 1;
  654. switch(type)
  655. {
  656. case ELog::error:
  657. color = "red";
  658. break;
  659. case ELog::success:
  660. color = "green";
  661. break;
  662. default: break;
  663. }
  664. if (!viewingLog)
  665. {
  666. QTabBar *tb = const_cast<QTabBar *>(_tabs->tabBar()); // dirty hack I know, but no other way atm
  667. if (_showNewLogNumber)
  668. {
  669. tb->setTabText(tb->count() - 1, tr("Log") + QString(" (%1)").arg(_logNewMessages));
  670. _logNewMessages++;
  671. }
  672. if (type == ELog::error)
  673. {
  674. tb->setTabTextColor(tb->count() - 1, QColor(cdef_color_logtab_err));
  675. _logHasErrors = true;
  676. }
  677. }
  678. _logpad->moveCursor(QTextCursor::End);
  679. _logpad->insertHtml(QString("<pre style=\"color: %1;\">%2</pre><p></p>").arg(color).arg(msg));
  680. }
  681. void MainWindow::enableToolbars(bool enable)
  682. {
  683. foreach (QToolBar *t, _toolbars)
  684. t->setVisible(enable); //t->setEnabled(enable);
  685. }
  686. void MainWindow::onTabSelected(int index)
  687. {
  688. enableToolbars(index == 0);
  689. if (index == _tabs->count() - 1)
  690. {
  691. QTabBar *tb = const_cast<QTabBar *>(_tabs->tabBar());
  692. if (_logNewMessages > 0)
  693. {
  694. tb->setTabText(tb->count() - 1, tr("Log"));
  695. _logNewMessages = 0;
  696. }
  697. if (_logHasErrors)
  698. {
  699. tb->setTabTextColor(tb->count() - 1, _logTabTextColor); // set default color back
  700. _logHasErrors = false;
  701. }
  702. }
  703. }
  704. void MainWindow::onZoomed(int z)
  705. {
  706. // modify note data and send it to widgets
  707. _ns.note.setWidth(c_zoom_note_widths[z]);
  708. _meter ->configure2(_ns);
  709. _piano ->configure(_ns);
  710. _noteEditor->configure(_ns);
  711. _drawZone ->configure(_ns);
  712. // modify scrollbar sizes and position
  713. double hscr_val = (double)_hscr->value() / _hscr->maximum();
  714. _hscr->setMaximum(_ns.note.width() * 4 * cdef_bars - _noteEditor->width() + 1);
  715. _hscr->setValue(_hscr->maximum() * hscr_val);
  716. _hscr->setSingleStep(_ns.note.width());
  717. horzScrolled(_hscr->value());
  718. }
  719. void MainWindow::onEditorZoomed(int delta)
  720. {
  721. if (delta != 0)
  722. if ((delta > 0 && _zoom->value() >= 0) ||
  723. (delta < 0 && _zoom->value() < c_zoom_num))
  724. _zoom->setValue(_zoom->value() + ((delta > 0) ? 1 : -1));
  725. }
  726. void MainWindow::onDocReloaded()
  727. {
  728. setWindowTitle(_doc->documentName() + " - QTau");
  729. _noteEditor->reset();
  730. }
  731. void MainWindow::onDocStatus(bool isModified)
  732. {
  733. QString newDocName = _doc->documentName();
  734. if (_docName != newDocName)
  735. _docName = newDocName;
  736. setWindowTitle((isModified ? "*" : "") + _docName + " - QTau");
  737. ui->actionSave->setEnabled(isModified);
  738. }
  739. void MainWindow::onUndoStatus(bool canUndo)
  740. {
  741. ui->actionUndo->setEnabled(canUndo);
  742. updateUndoRedoTexts();
  743. }
  744. void MainWindow::onRedoStatus(bool canRedo)
  745. {
  746. ui->actionRedo->setEnabled(canRedo);
  747. updateUndoRedoTexts();
  748. }
  749. void MainWindow::onDocEvent(qtauEvent* event)
  750. {
  751. //FIXME: why here
  752. QString singerName = _doc->getSingerName();
  753. if(singerName.length())
  754. {
  755. int count = _singerSelect->count();
  756. for(int i=0;i<count;i++)
  757. {
  758. if(singerName==_singerSelect->itemText(i))
  759. {
  760. _singerSelect->setCurrentIndex(i);
  761. _ctrl->selectSinger(singerName);
  762. break;
  763. }
  764. }
  765. }
  766. QJsonArray arr = _doc->getTempoMap();
  767. if(arr.size())
  768. {
  769. _ns.tmap->fromJson(arr);
  770. DEVLOG_DEBUG("update setup from json");
  771. updateSetup();
  772. }
  773. if (event->type() >= ENoteEvents::add && event->type() <= ENoteEvents::effect)
  774. _noteEditor->onEvent(event);
  775. else
  776. DEVLOG_ERROR("bad event");
  777. }
  778. void MainWindow::dragEnterEvent(QDragEnterEvent *event)
  779. {
  780. // accepting filepaths
  781. if (event->mimeData()->hasFormat("text/uri-list"))
  782. event->acceptProposedAction();
  783. }
  784. void MainWindow::dragMoveEvent(QDragMoveEvent *event)
  785. {
  786. // accepting filepaths
  787. if (event->mimeData()->hasFormat("text/uri-list"))
  788. event->acceptProposedAction();
  789. }
  790. void MainWindow::dropEvent(QDropEvent *event)
  791. {
  792. QList<QUrl> uris;
  793. foreach (const QByteArray &uriData, event->mimeData()->data("text/uri-list").split('\n'))
  794. if (!uriData.isEmpty())
  795. uris << QUrl::fromEncoded(uriData).toLocalFile().remove('\r');
  796. if (!uris.isEmpty())
  797. {
  798. QFileInfo fi(uris.first().toString());
  799. if (uris.size() > 1)
  800. DEVLOG_DEBUG("Multiple URIs dropped, currently using only first one");
  801. if (fi.exists() && !fi.isDir() && !fi.suffix().isEmpty()) // if it's an existing file with some extension
  802. {
  803. // maybe it's a note/lyrics file? (ust/vsq/vsqx/midi)
  804. if (fi.suffix() == "ustj")
  805. {
  806. emit loadUST(fi.absoluteFilePath());
  807. }
  808. else
  809. DEVLOG_ERROR("File extension not supported: " + fi.suffix());
  810. }
  811. }
  812. }
  813. //autoconneccted slot
  814. void MainWindow::on_actionPhoneme_Transformation_triggered()
  815. {
  816. _noteEditor->doPhonemeTransformation();
  817. }
  818. void MainWindow::onSingerSelected(int index)
  819. {
  820. _ctrl->selectSinger(_singerSelect->itemText(index));
  821. _doc->setSingerName(_singerSelect->itemText(index));
  822. }
  823. void MainWindow::onActionJackTriggered()
  824. {
  825. QAction* a = (QAction*)QObject::sender();
  826. _ctrl->setJackTranportEnabled(a->isChecked());
  827. }
  828. void MainWindow::markOverlappingNotes(quint64 id1, quint64 id2)
  829. {
  830. _noteEditor->setNoteColor(id1,EColor::red);
  831. _noteEditor->setNoteColor(id2,EColor::red);
  832. onLog("found overlapping notes",ELog::error);
  833. _noteEditor->update();
  834. }
  835. void MainWindow::updateNoteColors()
  836. {
  837. foreach(quint64 id,_noteEditor->getNoteIDs())
  838. {
  839. _noteEditor->setNoteColor(id,EColor::none);
  840. }
  841. }
  842. void MainWindow::updateSetup()
  843. {
  844. //DEVLOG_DEBUG("MainWindow::updateSetup()");
  845. _piano->configure(_ns);
  846. _meter->configure2(_ns);
  847. _noteEditor->configure(_ns);
  848. if(_drawZone) _drawZone ->configure(_ns);
  849. }
  850. void MainWindow::updateRecentFileActions()
  851. {
  852. QSettings settings;
  853. QStringList files = settings.value("recentFileList").toStringList();
  854. int numRecentFiles = qMin(files.size(), (int)MAXRECENTFILES);
  855. for (int i = 0; i < numRecentFiles; ++i) {
  856. QString fileName = QFileInfo(files[i]).fileName();
  857. QString text = tr("&%1 %2").arg(i + 1).arg(fileName);
  858. _recentFileActs[i]->setText(text);
  859. _recentFileActs[i]->setData(files[i]);
  860. _recentFileActs[i]->setVisible(true);
  861. }
  862. for (int j = numRecentFiles; j < MAXRECENTFILES; ++j)
  863. _recentFileActs[j]->setVisible(false);
  864. }
  865. void MainWindow::openRecentFile()
  866. {
  867. QAction *action = qobject_cast<QAction *>(sender());
  868. if (action)
  869. {
  870. QString ustFileName = action->data().toString();
  871. if(QFile(ustFileName).exists())
  872. loadUST(ustFileName);
  873. else
  874. {
  875. QSettings settings;
  876. QStringList files = settings.value("recentFileList").toStringList();
  877. files.removeOne(ustFileName);
  878. settings.setValue("recentFileList", files);
  879. updateRecentFileActions();
  880. QMessageBox msgBox;
  881. msgBox.setText("The file \""+ustFileName+"\"does not exist.");
  882. msgBox.exec();
  883. }
  884. }
  885. }
  886. void MainWindow::on_actionSave_Last_Play_triggered()
  887. {
  888. QString lastPlay = _ctrl->lastPlay();
  889. DEVLOG_DEBUG("lastPlay: "+lastPlay);
  890. if(lastPlay.length())
  891. {
  892. QString fileName = QFileInfo(lastPlay).fileName();
  893. QString fileNameCopy = QFileDialog::getSaveFileName(this,
  894. tr("Save Last Play"), _lastScoreDir, tr("WAV Files (*.wav)"));
  895. if (!fileNameCopy.isEmpty())
  896. {
  897. if(!fileNameCopy.endsWith(".wav")) fileNameCopy+=".wav";
  898. DEVLOG_DEBUG("CP lastPlay: "+fileNameCopy);
  899. if(QFileInfo(fileNameCopy).exists())
  900. QFile::remove(fileNameCopy);
  901. QFile::copy(lastPlay,fileNameCopy);
  902. }
  903. }
  904. }
  905. struct selectionRange MainWindow::getSelectionRange()
  906. {
  907. return _noteEditor->getSelectionRange();
  908. }
  909. void MainWindow::on_actionMusicXML_triggered()
  910. {
  911. QString fileName = QFileDialog::getOpenFileName(this, tr("Import MusicXML"),
  912. QString("/home/hatsunemiku/Music/MIDIs/"), //FIXME do not hardcode
  913. tr("MusicXML Files (*.xml)"));
  914. _doc->importMusicXML(fileName);
  915. }
  916. void MainWindow::on_actionUST_triggered()
  917. {
  918. QString fileName = QFileDialog::getOpenFileName(this, tr("Import MusicXML"),
  919. QString("/home/hatsunemiku/Music/MIDIs/"), //FIXME do not hardcode
  920. tr("UTAU Sequence Text Files (*.ust)"));
  921. _doc->importUST(fileName);
  922. }
  923. void MainWindow::updateTMap()
  924. {
  925. QJsonArray array;
  926. _ns.tmap->toJson(array);
  927. _doc->setTempoMap(array);
  928. updateSetup();
  929. }
  930. void MainWindow::on_actionEdit_Tempo_Time_Signature_triggered()
  931. {
  932. _ns.tmap->beginEditing();
  933. TempoDialog dialog(_ns.tmap,this);
  934. if(dialog.exec()==QDialog::Accepted)
  935. {
  936. updateTMap();
  937. }
  938. else
  939. {
  940. //UNDO changes
  941. _ns.tmap->undo();
  942. }
  943. }
  944. void MainWindow::meter_barClicked(int bar, tmlabel mode)
  945. {
  946. //TODO update gui
  947. _current_bar=bar;
  948. _current_mode=mode;
  949. if(mode==TM_BPM)
  950. {
  951. _mbl->setText("["+STR(bar)+"] BPM=");
  952. _mbe->setText("120");//FIXME
  953. _mbe->setFocus();
  954. }
  955. else
  956. {
  957. _mbl->setText("["+STR(bar)+"] SIG=");
  958. _mbe->setText("4/4");
  959. _mbe->setFocus();
  960. }
  961. }
  962. void MainWindow::mbe_keyPressHooked(int)
  963. {
  964. //TODO insert event
  965. QString text = _mbe->text();
  966. if(_current_mode==TM_BPM || _current_mode==TM_SIG)
  967. {
  968. if(_ns.tmap->setLabel(_current_mode,_current_bar-1,text))
  969. {
  970. updateTMap();
  971. _mbl->setText("");
  972. _mbe->setText("");
  973. _current_mode = TM_ALL;
  974. }
  975. }
  976. else
  977. {
  978. QStringList cmd = text.split(" ");
  979. if(cmd.length()==2)
  980. {
  981. if(cmd[0]=="BPM") meter_barClicked(QVariant(cmd[1]).toInt(),TM_BPM);
  982. if(cmd[0]=="SIG") meter_barClicked(QVariant(cmd[1]).toInt(),TM_SIG);
  983. }
  984. }
  985. }