mainwindow.cpp 38 KB

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