//========================================================= // MusE // Linux Music Editor // $Id: lmaster.cpp,v 1.2.2.8 2009/03/09 02:05:18 terminator356 Exp $ // (C) Copyright 2000 Werner Schweer (ws@seh.de) // // This program 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; version 2 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, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // //========================================================= #include "awl/posedit.h" #include "awl/sigedit.h" #include "lmaster.h" #include "xml.h" #include "song.h" #include "globals.h" #include "app.h" #include "audio.h" #include "shortcuts.h" #include "debug.h" #include "gconfig.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define LMASTER_BEAT_COL 0 #define LMASTER_TIME_COL 1 #define LMASTER_TYPE_COL 2 #define LMASTER_VAL_COL 3 #define LMASTER_MSGBOX_STRING "MusE: List Editor" namespace MusECore { //don't remove or insert new elements in keyStrs. //only renaming (keeping the semantic sense) is allowed! (flo) QStringList keyStrs = QStringList() << "C (sharps)" << "G" << "D" << "A"<< "E" << "B" << "F#" << "C (flats)"<< "F"<< "Bb" << "Eb"<< "Ab"<< "Db"<< "Gb"; //don't change this function (except when renaming stuff) key_enum stringToKey(QString input) //flo { int index = keyStrs.indexOf(input); key_enum map[]={KEY_C, KEY_G, KEY_D, KEY_A, KEY_E, KEY_B, KEY_FIS, KEY_C_B, KEY_F, KEY_BES, KEY_ES, KEY_AS, KEY_DES, KEY_GES}; return map[index]; } //don't change the below two functions (except when renaming stuff) int keyToIndex(key_enum key) { int index=0; switch(key) { case KEY_C: index= 0; break; case KEY_G: index= 1; break; case KEY_D: index= 2; break; case KEY_A: index= 3; break; case KEY_E: index= 4; break; case KEY_B: index= 5; break; case KEY_FIS: index= 6; break; case KEY_C_B: index= 7; break; case KEY_F: index= 8; break; case KEY_BES: index= 9; break; case KEY_ES: index=10; break; case KEY_AS: index=11; break; case KEY_DES: index=12; break; case KEY_GES: index=13; break; case KEY_SHARP_BEGIN: case KEY_SHARP_END: case KEY_B_BEGIN: case KEY_B_END: printf("ILLEGAL FUNCTION CALL: keyToIndex called with key_sharp_begin etc.\n"); return 0; break; default: printf("ILLEGAL FUNCTION CALL: keyToIndex called with illegal key value (not in enum)\n"); return 0; } return index; } QString keyToString(key_enum key) { return keyStrs[keyToIndex(key)]; } } // namespace MusECore namespace MusEGui { //--------------------------------------------------------- // closeEvent //--------------------------------------------------------- void LMaster::closeEvent(QCloseEvent* e) { _isDeleting = true; // Set flag so certain signals like songChanged, which may cause crash during delete, can be ignored. emit isDeleting(static_cast(this)); e->accept(); } //--------------------------------------------------------- // songChanged //--------------------------------------------------------- void LMaster::songChanged(MusECore::SongChangedFlags_t type) { if(_isDeleting) // Ignore while while deleting to prevent crash. return; if (type & (SC_SIG | SC_TEMPO | SC_KEY )) updateList(); } //--------------------------------------------------------- // LMaster //--------------------------------------------------------- LMaster::LMaster(QWidget* parent, const char* name) : MidiEditor(TopWin::LMASTER, 0, 0, parent, name) { pos_editor = 0; tempo_editor = 0; sig_editor = 0; key_editor = 0; editedItem = 0; editingNewItem = false; setWindowTitle(tr("MusE: Mastertrack")); setMinimumHeight(100); //setFixedWidth(400); // FIXME: Arbitrary. But without this, sig editor is too wide. Must fix sig editor width... setFocusPolicy(Qt::NoFocus); comboboxTimer=new QTimer(this); comboboxTimer->setInterval(150); comboboxTimer->setSingleShot(true); connect(comboboxTimer, SIGNAL(timeout()), this, SLOT(comboboxTimerSlot())); //---------Pulldown Menu---------------------------- menuEdit = menuBar()->addMenu(tr("&Edit")); QSignalMapper *signalMapper = new QSignalMapper(this); menuEdit->addActions(MusEGlobal::undoRedo->actions()); menuEdit->addSeparator(); tempoAction = menuEdit->addAction(tr("Insert Tempo")); signAction = menuEdit->addAction(tr("Insert Signature")); keyAction = menuEdit->addAction(tr("Insert Key")); posAction = menuEdit->addAction(tr("Edit Positon")); valAction = menuEdit->addAction(tr("Edit Value")); delAction = menuEdit->addAction(tr("Delete Event")); delAction->setShortcut(Qt::Key_Delete); QMenu* settingsMenu = menuBar()->addMenu(tr("Window &Config")); settingsMenu->addAction(subwinAction); settingsMenu->addAction(shareAction); settingsMenu->addAction(fullscreenAction); connect(tempoAction, SIGNAL(triggered()), signalMapper, SLOT(map())); connect(signAction, SIGNAL(triggered()), signalMapper, SLOT(map())); connect(keyAction, SIGNAL(triggered()), signalMapper, SLOT(map())); connect(posAction, SIGNAL(triggered()), signalMapper, SLOT(map())); connect(valAction, SIGNAL(triggered()), signalMapper, SLOT(map())); connect(delAction, SIGNAL(triggered()), signalMapper, SLOT(map())); signalMapper->setMapping(tempoAction, CMD_INSERT_TEMPO); signalMapper->setMapping(signAction, CMD_INSERT_SIG); signalMapper->setMapping(keyAction, CMD_INSERT_KEY); signalMapper->setMapping(posAction, CMD_EDIT_BEAT); signalMapper->setMapping(valAction, CMD_EDIT_VALUE); signalMapper->setMapping(delAction, CMD_DELETE); connect(signalMapper, SIGNAL(mapped(int)), SLOT(cmd(int))); // Toolbars --------------------------------------------------------- QToolBar* edit = addToolBar(tr("Edit tools")); edit->setObjectName("Master List Edit Tools"); QToolButton* tempoButton = new QToolButton(); QToolButton* timeSigButton = new QToolButton(); QToolButton* keyButton = new QToolButton(); tempoButton->setFocusPolicy(Qt::NoFocus); timeSigButton->setFocusPolicy(Qt::NoFocus); keyButton->setFocusPolicy(Qt::NoFocus); tempoButton->setText(tr("Tempo")); timeSigButton->setText(tr("Timesig")); keyButton->setText(tr("Key")); tempoButton->setToolTip(tr("new tempo")); timeSigButton->setToolTip(tr("new signature")); keyButton->setToolTip(tr("new key")); edit->addWidget(tempoButton); edit->addWidget(timeSigButton); edit->addWidget(keyButton); //--------------------------------------------------- // master //--------------------------------------------------- view = new QTreeWidget; view->setAllColumnsShowFocus(true); view->setSelectionMode(QAbstractItemView::SingleSelection); QStringList columnnames; columnnames << tr("Meter") << tr("Time") << tr("Type") << tr("Value"); view->setHeaderLabels(columnnames); view->setColumnWidth(2,80); view->header()->setStretchLastSection(true); //--------------------------------------------------- // Rest //--------------------------------------------------- mainGrid->setRowStretch(0, 100); mainGrid->setColumnStretch(0, 100); mainGrid->addWidget(view, 0, 0); updateList(); tempo_editor = new QLineEdit(view->viewport()); tempo_editor->setFrame(false); tempo_editor->hide(); connect(tempo_editor, SIGNAL(returnPressed()), SLOT(returnPressed())); sig_editor = new SigEdit(view->viewport()); sig_editor->setFrame(false); sig_editor->hide(); connect(sig_editor, SIGNAL(returnPressed()), SLOT(returnPressed())); pos_editor = new Awl::PosEdit(view->viewport()); pos_editor->setFrame(false); pos_editor->hide(); connect(pos_editor, SIGNAL(returnPressed()), SLOT(returnPressed())); key_editor = new QComboBox(view->viewport()); key_editor->setFrame(false); key_editor->addItems(MusECore::keyStrs); key_editor->hide(); connect(key_editor, SIGNAL(activated(int)), SLOT(returnPressed())); connect(view, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), SLOT(select(QTreeWidgetItem*, QTreeWidgetItem*))); connect(view, SIGNAL(itemPressed(QTreeWidgetItem*, int)), SLOT(itemPressed(QTreeWidgetItem*, int))); connect(view, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), SLOT(itemDoubleClicked(QTreeWidgetItem*))); connect(MusEGlobal::song, SIGNAL(songChanged(MusECore::SongChangedFlags_t)), SLOT(songChanged(MusECore::SongChangedFlags_t))); connect(this, SIGNAL(seekTo(int)), MusEGlobal::song, SLOT(seekTo(int))); connect(tempoButton, SIGNAL(clicked()), SLOT(tempoButtonClicked())); connect(timeSigButton, SIGNAL(clicked()), SLOT(timeSigButtonClicked())); connect(keyButton, SIGNAL(clicked()), SLOT(insertKey())); initShortcuts(); finalizeInit(); } //--------------------------------------------------------- // ~LMaster //--------------------------------------------------------- LMaster::~LMaster() { } //--------------------------------------------------------- // focusCanvas //--------------------------------------------------------- void LMaster::focusCanvas() { if(MusEGlobal::config.smartFocus) { view->setFocus(); view->activateWindow(); } } //--------------------------------------------------------- // insertSig //--------------------------------------------------------- void LMaster::insertSig(const AL::SigEvent* ev) { new LMasterSigEventItem(view, ev); } //--------------------------------------------------------- // insertTempo //--------------------------------------------------------- void LMaster::insertTempo(const MusECore::TEvent* ev) { new LMasterTempoItem(view, ev); } void LMaster::insertKey(const MusECore::KeyEvent& ev) { new LMasterKeyEventItem(view, ev); } //--------------------------------------------------------- // updateList //--------------------------------------------------------- void LMaster::updateList() { LMasterLViewItem* selected = (LMasterLViewItem*) view->currentItem(); LMASTER_LVTYPE type = LMASTER_TEMPO; unsigned tick = 0; if (selected) { type = selected->getType(); tick = selected->tick(); } view->clear(); const MusECore::TempoList* t = &MusEGlobal::tempomap; const AL::SigList* s = &AL::sigmap; const MusECore::KeyList* k = &MusEGlobal::keymap; MusECore::criTEvent it = t->rbegin(); AL::criSigEvent is = s->rbegin(); MusECore::criKeyEvent ik = k->rbegin(); // three lists that should be added to the view. // question if it would not be easier to merge the lists and use a sorting algorithm? // how often is this function called? A: only on songChanged (SC_TEMPO && SC_SIG) for (;;) { // crazy long, must be possible to solve more elegantly... if (ik != k->rend() && is == s->rend() && it == t->rend()) {// ik biggest insertKey(ik->second); ++ik; } else if (is != s->rend() && ik == k->rend() && it == t->rend()) {// is biggest insertSig(is->second); ++is; } else if (it != t->rend() && ik == k->rend() && is == s->rend()) {// it biggest insertTempo(it->second); ++it; } else if ( ((ik != k->rend()) && (is == s->rend()) && (ik->second.tick >= it->second->tick)) || ((it == t->rend()) && (ik->second.tick >= is->second->tick ) )) {// ik biggest insertKey(ik->second); ++ik; } else if ( ((is != s->rend()) && (ik == k->rend()) && (is->second->tick >= it->second->tick)) || ((it == t->rend()) && (is->second->tick >= ik->second.tick ))) {// is biggest insertSig(is->second); ++is; } else if (((it != t->rend()) && (ik == k->rend()) && (it->second->tick >= is->second->tick)) || ((is == s->rend()) && (it->second->tick >= ik->second.tick ))) {// it biggest insertTempo(it->second); ++it; } else if (ik != k->rend() && ik->second.tick >= is->second->tick && ik->second.tick >= it->second->tick) {// ik biggest insertKey(ik->second); ++ik; } else if (is != s->rend() && is->second->tick >= it->second->tick && is->second->tick >= ik->second.tick) { // is biggest insertSig(is->second); ++is; } else if (it != t->rend() && it->second->tick >= is->second->tick && it->second->tick >= ik->second.tick) { // it biggest insertTempo(it->second); ++it; } if (ik == k->rend() && is == s->rend() && it == t->rend() ) break; } // Try to reselect the previous selection: if(selected) { LMasterLViewItem* tmp = getItemAtPos(tick, type); if (tmp) { view->clearSelection(); view->setCurrentItem(tmp); } } } //--------------------------------------------------------- // readStatus //--------------------------------------------------------- void LMaster::readStatus(MusECore::Xml& xml) { for (;;) { MusECore::Xml::Token token = xml.parse(); const QString& tag = xml.s1(); if (token == MusECore::Xml::Error || token == MusECore::Xml::End) break; switch (token) { case MusECore::Xml::TagStart: if (tag == "midieditor") MidiEditor::readStatus(xml); else xml.unknown("LMaster"); break; case MusECore::Xml::TagEnd: if (tag == "lmaster") return; default: break; } } } //--------------------------------------------------------- // writeStatus //--------------------------------------------------------- void LMaster::writeStatus(int level, MusECore::Xml& xml) const { xml.tag(level++, "lmaster"); MidiEditor::writeStatus(level, xml); xml.tag(level, "/lmaster"); } //--------------------------------------------------------- // readConfiguration //--------------------------------------------------------- void LMaster::readConfiguration(MusECore::Xml& xml) { for (;;) { MusECore::Xml::Token token = xml.parse(); const QString& tag = xml.s1(); switch (token) { case MusECore::Xml::Error: case MusECore::Xml::End: return; case MusECore::Xml::TagStart: if (tag == "topwin") TopWin::readConfiguration(LMASTER, xml); else xml.unknown("LMaster"); break; case MusECore::Xml::TagEnd: if (tag == "lmaster") return; default: break; } } } //--------------------------------------------------------- // writeConfiguration //--------------------------------------------------------- void LMaster::writeConfiguration(int level, MusECore::Xml& xml) { xml.tag(level++, "lmaster"); TopWin::writeConfiguration(LMASTER, level, xml); xml.tag(level, "/lmaster"); } //--------------------------------------------------------- // select //--------------------------------------------------------- //DELETETHIS (whole function)? or is this todo? void LMaster::select(QTreeWidgetItem* /*item*/, QTreeWidgetItem* /*previous_item*/) { } //--------------------------------------------------------- // cmd //--------------------------------------------------------- void LMaster::cmd(int cmd) { switch(cmd) { case CMD_DELETE: { LMasterLViewItem* l = (LMasterLViewItem*) view->currentItem(); if (!l) return; // Delete item: if (l->tick() != 0) { if (l == view->topLevelItem(view->topLevelItemCount() - 1)) view->setCurrentItem(view->itemAbove(l)); else view->setCurrentItem(view->itemBelow(l)); switch (l->getType()) { case LMASTER_TEMPO: { LMasterTempoItem* t = (LMasterTempoItem*) l; MusEGlobal::audio->msgDeleteTempo(t->tick(), t->tempo(), true); break; } case LMASTER_SIGEVENT: { LMasterSigEventItem* s = (LMasterSigEventItem*) l; MusEGlobal::audio->msgRemoveSig(s->tick(), s->z(), s->n()); break; } case LMASTER_KEYEVENT: { LMasterKeyEventItem* k = (LMasterKeyEventItem*) l; MusEGlobal::audio->msgRemoveKey(k->tick(), k->key()); break; } default: M_ERROR("Default switch statement reached"); break; } } break; } case CMD_INSERT_TEMPO: tempoButtonClicked(); break; case CMD_INSERT_SIG: timeSigButtonClicked(); break; case CMD_INSERT_KEY: insertKey(); break; case CMD_EDIT_BEAT: case CMD_EDIT_VALUE: cmd == CMD_EDIT_VALUE ? editorColumn = LMASTER_VAL_COL : editorColumn = LMASTER_BEAT_COL; if (view->currentItem() && !editedItem) { itemDoubleClicked(view->currentItem()); } break; } } /*! \fn LMaster::itemPressed(QListViewItem* i, const QPoint& p, int column) */ void LMaster::itemPressed(QTreeWidgetItem* i, int column) { if (editedItem) { if (editorColumn != column || editedItem != i) returnPressed(); } else { if (key_editor) key_editor->hide(); setFocus(); editorColumn = column; } } //--------------------------------------------------------- // itemDoubleClicked(QListViewItem* item) //! Sets lmaster in edit mode, and opens editor for selected value //--------------------------------------------------------- void LMaster::itemDoubleClicked(QTreeWidgetItem* i) { emit seekTo(((LMasterLViewItem*) i)->tick()); QFontMetrics fm(font()); int fnt_w = fm.width('0'); if (!editedItem && editorColumn == LMASTER_VAL_COL) { editedItem = (LMasterLViewItem*) i; QRect itemRect = view->visualItemRect(editedItem); int x1 = view->columnWidth(LMASTER_BEAT_COL) + view->columnWidth(LMASTER_TIME_COL) + view->columnWidth(LMASTER_TYPE_COL); itemRect.setX(x1); //Qt makes crazy things with itemRect if this is called directly.. if (editingNewItem) { int fw = style()->pixelMetric(QStyle::PM_DefaultFrameWidth,0 , this); // ddskrjo 0 int h = fm.height() + fw * 2; itemRect.setWidth(view->columnWidth(LMASTER_VAL_COL)); itemRect.setY(1); itemRect.setHeight(h); } // Edit tempo value: if (editedItem->getType() == LMASTER_TEMPO) { tempo_editor->setText(editedItem->text(LMASTER_VAL_COL)); tempo_editor->setGeometry(itemRect); tempo_editor->show(); tempo_editor->setFocus(); tempo_editor->selectAll(); } else if (editedItem->getType() == LMASTER_SIGEVENT) { // Edit signatur value: sig_editor->setValue(((LMasterSigEventItem*)editedItem)->getEvent()->sig); int w = fnt_w * 14; if(w > itemRect.width()) w = itemRect.width(); sig_editor->setGeometry(itemRect.x(), itemRect.y(), w, itemRect.height()); sig_editor->show(); sig_editor->setFocus(); } else if (editedItem->getType() == LMASTER_KEYEVENT) { key_editor->setGeometry(itemRect); key_editor->setCurrentIndex(keyToIndex(dynamic_cast(editedItem)->key())); key_editor->show(); key_editor->setFocus(); comboboxTimer->start(); } else { printf("illegal Master list type\n"); } } // Edit tempo or signal position: else if (!editedItem && editorColumn == LMASTER_BEAT_COL) { editedItem = (LMasterLViewItem*) i; // Don't allow movement of initial values: if (editedItem->tick() == 0) { QMessageBox::information(this, tr(LMASTER_MSGBOX_STRING), tr("Reposition of the initial tempo and signature events is not allowed") ); editedItem = 0; } // Everything OK else { pos_editor->setValue(editedItem->tick()); QRect itemRect = view->visualItemRect(editedItem); itemRect.setX(view->indentation()); int w = view->columnWidth(LMASTER_BEAT_COL) - view->indentation(); if(w < (fnt_w * 13)) w = fnt_w * 13; itemRect.setWidth(w); pos_editor->setGeometry(itemRect); pos_editor->show(); pos_editor->setFocus(); } } } //--------------------------------------------------------- // returnPressed() //! called when editor is closed //--------------------------------------------------------- void LMaster::returnPressed() { if (!editedItem) return; setFocus(); // Tempo event: if (editedItem->getType() == LMASTER_TEMPO && editorColumn == LMASTER_VAL_COL) { QString input = tempo_editor->text(); tempo_editor->hide(); repaint(); LMasterTempoItem* e = (LMasterTempoItem*) editedItem; const MusECore::TEvent* t = e->getEvent(); unsigned tick = t->tick; bool conversionOK; double dbl_input = input.toDouble(&conversionOK); if (conversionOK && dbl_input < 250.0) { int tempo = (int) ((1000000.0 * 60.0)/dbl_input); if (!editingNewItem) { MusEGlobal::song->startUndo(); MusEGlobal::audio->msgDeleteTempo(tick, e->tempo(), false); MusEGlobal::audio->msgAddTempo(tick, tempo, false); MusEGlobal::song->endUndo(SC_TEMPO); } // // New item edited: // else { MusEGlobal::audio->msgAddTempo(tick, tempo, true); } } else { QMessageBox::warning(this, tr("MusE: List Editor"), tr("Input error, conversion not OK or value out of range"), QMessageBox::Ok, Qt::NoButton ); } } // // Beat column, change position of a particular tempo or signature event // else if (editorColumn == LMASTER_BEAT_COL) { int oldtick = editedItem->tick(); int newtick = pos_editor->pos().tick(); if (newtick == 0) { // Do not allow change of position to beginning of song QMessageBox::warning(this, tr(LMASTER_MSGBOX_STRING), tr("Reposition of tempo and signature events to start position is not allowed!"), QMessageBox::Ok, Qt::NoButton ); } else if (oldtick != newtick) { // Ignore if tick hasn't changed if (editedItem->getType() == LMASTER_TEMPO) { LMasterTempoItem* t = (LMasterTempoItem*) editedItem; int tempo = t->tempo(); MusEGlobal::song->startUndo(); MusEGlobal::audio->msgDeleteTempo(oldtick, tempo, false); MusEGlobal::audio->msgAddTempo(newtick, tempo, false); MusEGlobal::song->endUndo(SC_TEMPO); // Select the item: QTreeWidgetItem* newSelected = (QTreeWidgetItem*) getItemAtPos(newtick, LMASTER_TEMPO); if (newSelected) { view->clearSelection(); view->setCurrentItem(newSelected); } } else if (editedItem->getType() == LMASTER_SIGEVENT) { LMasterSigEventItem* t = (LMasterSigEventItem*) editedItem; int z = t->z(); int n = t->n(); if (!editingNewItem) { MusEGlobal::song->startUndo(); MusEGlobal::audio->msgRemoveSig(oldtick, z, n, false); //Delete first, in order to get sane tick-value newtick = pos_editor->pos().tick(); MusEGlobal::audio->msgAddSig(newtick, z, n, false); MusEGlobal::song->endUndo(SC_SIG); } else MusEGlobal::audio->msgAddSig(newtick, z, n, false); // Select the item: QTreeWidgetItem* newSelected = (QTreeWidgetItem*) getItemAtPos(newtick, LMASTER_SIGEVENT); if (newSelected) { view->clearSelection(); view->setCurrentItem(newSelected); } } else if (editedItem->getType() == LMASTER_KEYEVENT) { LMasterKeyEventItem* k = (LMasterKeyEventItem*) editedItem; MusECore::key_enum key = k->key(); MusEGlobal::song->startUndo(); MusEGlobal::audio->msgRemoveKey(oldtick, key, false); MusEGlobal::audio->msgAddKey(newtick, key, false); MusEGlobal::song->endUndo(SC_KEY); // Select the item: QTreeWidgetItem* newSelected = (QTreeWidgetItem*) getItemAtPos(newtick, LMASTER_KEYEVENT); if (newSelected) { view->clearSelection(); view->setCurrentItem(newSelected); } } else { printf("unknown master list event type!\n"); } } pos_editor->hide(); repaint(); } // // SigEvent, value changed: // else if (editedItem->getType() == LMASTER_SIGEVENT && editorColumn == LMASTER_VAL_COL) { AL::TimeSignature newSig = sig_editor->sig(); sig_editor->hide(); // Added p3.3.43 Prevents aborting with 0 z or n. if(newSig.isValid()) { LMasterSigEventItem* e = (LMasterSigEventItem*) editedItem; int tick = e->tick(); if (!editingNewItem) { MusEGlobal::song->startUndo(); MusEGlobal::audio->msgRemoveSig(tick, e->z(), e->n(), false); MusEGlobal::audio->msgAddSig(tick, newSig.z, newSig.n, false); MusEGlobal::song->endUndo(SC_SIG); } else MusEGlobal::audio->msgAddSig(tick, newSig.z, newSig.n, true); } else { printf("Signature is not valid!\n"); } } else if (editedItem->getType() == LMASTER_KEYEVENT && editorColumn == LMASTER_VAL_COL) { QString input = key_editor->currentText(); key_editor->hide(); repaint(); LMasterKeyEventItem* e = (LMasterKeyEventItem*) editedItem; const MusECore::KeyEvent& t = e->getEvent(); unsigned tick = t.tick; MusECore::key_enum key = MusECore::stringToKey(input); if (!editingNewItem) { MusEGlobal::song->startUndo(); MusEGlobal::audio->msgRemoveKey(tick, e->key(), false); MusEGlobal::audio->msgAddKey(tick, key, false); MusEGlobal::song->endUndo(SC_KEY); } // // New item edited: // else { MusEGlobal::audio->msgAddKey(tick, key, true); } } updateList(); view->setFocus(); // No item edited now: editedItem = 0; editorColumn = -1; editingNewItem = false; } /*! \fn LMasterLViewItem::text(int column) \brief Returns the initialized text to the View */ QString LMasterLViewItem::text(int column) const { QString ret = "?"; switch (column) { case LMASTER_BEAT_COL: ret = c1; break; case LMASTER_TIME_COL: ret = c2; break; case LMASTER_TYPE_COL: ret = c3; break; case LMASTER_VAL_COL: ret = c4; break; default: fprintf(stderr,"LMasterLViewItem::text(int): Default switch statement reached... Unknown column.\n"); break; } return ret; } //--------------------------------------------------------- // LMasterKeyEventItem //! Initializes a LMasterKeyEventItem with a KeyEvent //--------------------------------------------------------- LMasterKeyEventItem::LMasterKeyEventItem(QTreeWidget* parent, const MusECore::KeyEvent& ev) : LMasterLViewItem(parent) { keyEvent = ev; unsigned t = ev.tick; int bar, beat; unsigned tick; AL::sigmap.tickValues(t, &bar, &beat, &tick); c1.sprintf("%04d.%02d.%03d", bar+1, beat+1, tick); double time = double(MusEGlobal::tempomap.tick2frame(t)) / double(MusEGlobal::sampleRate); int min = int(time) / 60; int sec = int(time) % 60; int msec = int((time - (min*60 + sec)) * 1000.0); c2.sprintf("%03d:%02d:%03d", min, sec, msec); c3 = "Key"; c4 = keyToString(ev.key); setText(0, c1); setText(1, c2); setText(2, c3); setText(3, c4); } //--------------------------------------------------------- // LMasterTempoItem //! Initializes a LMasterTempoItem with a TEvent //--------------------------------------------------------- LMasterTempoItem::LMasterTempoItem(QTreeWidget* parent, const MusECore::TEvent* ev) : LMasterLViewItem(parent) { tempoEvent = ev; unsigned t = ev->tick; int bar, beat; unsigned tick; AL::sigmap.tickValues(t, &bar, &beat, &tick); c1.sprintf("%04d.%02d.%03d", bar+1, beat+1, tick); double time = double(MusEGlobal::tempomap.tick2frame(t)) / double(MusEGlobal::sampleRate); int min = int(time) / 60; int sec = int(time) % 60; int msec = int((time - (min*60 + sec)) * 1000.0); c2.sprintf("%03d:%02d:%03d", min, sec, msec); c3 = "Tempo"; double dt = (1000000.0 * 60.0)/ev->tempo; c4.setNum(dt, 'f', 3); setText(0, c1); setText(1, c2); setText(2, c3); setText(3, c4); } //--------------------------------------------------------- // LMasterSigEventItem //! Initializes a ListView item with a SigEvent //--------------------------------------------------------- LMasterSigEventItem::LMasterSigEventItem(QTreeWidget* parent, const AL::SigEvent* ev) : LMasterLViewItem(parent) { sigEvent = ev; unsigned t = ev->tick; int bar, beat; unsigned tick; AL::sigmap.tickValues(t, &bar, &beat, &tick); c1.sprintf("%04d.%02d.%03d", bar+1, beat+1, tick); double time = double(MusEGlobal::tempomap.tick2frame(t)) / double (MusEGlobal::sampleRate); int min = int(time) / 60; int sec = int(time) % 60; int msec = int((time - (min*60 + sec)) * 1000.0); c2.sprintf("%03d:%02d:%03d", min, sec, msec); c3 = "Timesig"; c4.sprintf("%d / %d", ev->sig.z, ev->sig.n); setText(0, c1); setText(1, c2); setText(2, c3); setText(3, c4); } //--------------------------------------------------------- // tempoButtonClicked() //! inserts a new tempo-item in the list and starts the editor for it //--------------------------------------------------------- void LMaster::tempoButtonClicked() { LMasterTempoItem* lastTempo = (LMasterTempoItem*) getLastOfType(LMASTER_TEMPO); // QString beatString = ((LMasterLViewItem*)lastTempo)->text(LMASTER_BEAT_COL); DELETETHIS? // int m, b, t; // Pos p = Pos(beatString); // p.mbt(&m, &b, &t); // m++; //Next bar // int newTick = AL::sigmap.bar2tick(m, b, t); int newTick = MusEGlobal::song->cpos(); MusECore::TEvent* ev = new MusECore::TEvent(lastTempo->tempo(), newTick); new LMasterTempoItem(view, ev); QTreeWidgetItem* newTempoItem = view->topLevelItem(0); editingNewItem = true; // State editorColumn = LMASTER_VAL_COL; // Set that we edit editorColumn view->clearSelection(); view->setCurrentItem(newTempoItem); itemDoubleClicked(newTempoItem); } //--------------------------------------------------------- // timeSigButtonClicked() //! inserts a new sig-item in the list and starts the editor for it //--------------------------------------------------------- void LMaster::timeSigButtonClicked() { LMasterSigEventItem* lastSig = (LMasterSigEventItem*) getLastOfType(LMASTER_SIGEVENT); // QString beatString = ((LMasterLViewItem*)lastSig)->text(LMASTER_BEAT_COL); DELETETHIS // int m, b, t; // Pos p = Pos(beatString); // p.mbt(&m, &b, &t); // m++; // int newTick = AL::sigmap.bar2tick(m, b, t); int newTick = MusEGlobal::song->cpos(); AL::SigEvent* ev = new AL::SigEvent(AL::TimeSignature(lastSig->z(), lastSig->n()), newTick); new LMasterSigEventItem(view, ev); QTreeWidgetItem* newSigItem = view->topLevelItem(0); editingNewItem = true; // State editorColumn = LMASTER_VAL_COL; // Set that we edit editorColumn view->clearSelection(); view->setCurrentItem(newSigItem); itemDoubleClicked(newSigItem); } //--------------------------------------------------------- // insertKey() //! inserts a new key in the list and starts the editor for it //--------------------------------------------------------- void LMaster::insertKey() { LMasterKeyEventItem* lastKey = (LMasterKeyEventItem*) getLastOfType(LMASTER_KEYEVENT); //QString beatString = ((LMasterLViewItem*)lastKey)->text(LMASTER_BEAT_COL); DELETETHIS //int m, b, t; //Pos p = Pos(beatString); //p.mbt(&m, &b, &t); //m++; //Next bar int newTick = MusEGlobal::song->cpos(); new LMasterKeyEventItem(view, MusECore::KeyEvent(lastKey->key(), newTick)); QTreeWidgetItem* newKeyItem = view->topLevelItem(0); editingNewItem = true; // State editorColumn = LMASTER_VAL_COL; // Set that we edit editorColumn view->clearSelection(); view->setCurrentItem(newKeyItem); itemDoubleClicked(newKeyItem); } /*! \fn LMaster::getLastOfType(LMASTER_LVTYPE t) */ LMasterLViewItem* LMaster::getLastOfType(LMASTER_LVTYPE t) { LMasterLViewItem* tmp = (LMasterLViewItem*) view->topLevelItem(view->topLevelItemCount() - 1); while (tmp->getType() != t) { tmp = (LMasterLViewItem*) view->itemAbove(tmp); } return tmp; } /*! \fn LMaster::getItemAtPos(unsigned tick, LMASTER_LVTYPE t) */ LMasterLViewItem* LMaster::getItemAtPos(unsigned tick, LMASTER_LVTYPE t) { LMasterLViewItem* tmp = (LMasterLViewItem*) view->topLevelItem(0); while (tmp) { if (tmp->getType() == t && tmp->tick() == tick) return tmp; tmp = (LMasterLViewItem*) view->itemBelow(tmp); } return 0; } /*! \fn LMaster::configChanged() */ void LMaster::configChanged() { initShortcuts(); } /*! \fn LMaster::initShortcuts() */ void LMaster::initShortcuts() { tempoAction->setShortcut(shortcuts[SHRT_LM_INS_TEMPO].key); signAction->setShortcut(shortcuts[SHRT_LM_INS_SIG].key); keyAction->setShortcut(shortcuts[SHRT_LM_INS_KEY].key); posAction->setShortcut(shortcuts[SHRT_LM_EDIT_BEAT].key); valAction->setShortcut(shortcuts[SHRT_LM_EDIT_VALUE].key); } void LMaster::comboboxTimerSlot() { key_editor->showPopup(); } } // namespace MusEGui