diff options
author | Florian Jung <flo@windfisch.org> | 2011-09-14 19:33:40 +0000 |
---|---|---|
committer | Florian Jung <flo@windfisch.org> | 2011-09-14 19:33:40 +0000 |
commit | 58033553a3e7d529a27a2b3d9ccc721d1e2dcc17 (patch) | |
tree | 160bd9993bca91b68475d4ad4249cc07b89692dd /muse2/muse/arranger | |
parent | 42269af2e0cc7a8c7b70d89ffa270184acde3dec (diff) | |
parent | 2529ef06d1227b457af051a494ddb579ef590fe3 (diff) |
merged experimental into trunk
new features:
- MDI user interface
- improved pasting (dialogs etc)
- some fixes
Diffstat (limited to 'muse2/muse/arranger')
-rw-r--r-- | muse2/muse/arranger/CMakeLists.txt | 2 | ||||
-rw-r--r-- | muse2/muse/arranger/arranger.cpp | 22 | ||||
-rw-r--r-- | muse2/muse/arranger/arranger.h | 10 | ||||
-rw-r--r-- | muse2/muse/arranger/arrangerview.cpp | 726 | ||||
-rw-r--r-- | muse2/muse/arranger/arrangerview.h | 156 | ||||
-rw-r--r-- | muse2/muse/arranger/pcanvas.cpp | 354 | ||||
-rw-r--r-- | muse2/muse/arranger/pcanvas.h | 14 | ||||
-rw-r--r-- | muse2/muse/arranger/tlist.cpp | 171 |
8 files changed, 1234 insertions, 221 deletions
diff --git a/muse2/muse/arranger/CMakeLists.txt b/muse2/muse/arranger/CMakeLists.txt index af6a30b5..d81d92c6 100644 --- a/muse2/muse/arranger/CMakeLists.txt +++ b/muse2/muse/arranger/CMakeLists.txt @@ -27,6 +27,7 @@ QT4_WRAP_CPP (arranger_mocs alayout.h arranger.h + arrangerview.h pcanvas.h tlist.h ) @@ -37,6 +38,7 @@ QT4_WRAP_CPP (arranger_mocs file (GLOB arranger_source_files alayout.cpp arranger.cpp + arrangerview.cpp pcanvas.cpp tlist.cpp ) diff --git a/muse2/muse/arranger/arranger.cpp b/muse2/muse/arranger/arranger.cpp index 3052d7d4..09e67151 100644 --- a/muse2/muse/arranger/arranger.cpp +++ b/muse2/muse/arranger/arranger.cpp @@ -38,6 +38,7 @@ #include <QWheelEvent> #include <QPainter> //#include <QStackedWidget> +#include "arrangerview.h" #include "arranger.h" #include "song.h" @@ -111,7 +112,7 @@ void Arranger::setHeaderWhatsThis() // is the central widget in app //--------------------------------------------------------- -Arranger::Arranger(QMainWindow* parent, const char* name) +Arranger::Arranger(ArrangerView* parent, const char* name) : QWidget(parent) { setObjectName(name); @@ -122,11 +123,12 @@ Arranger::Arranger(QMainWindow* parent, const char* name) ///program = CTRL_VAL_UNKNOWN; ///pan = -65; ///volume = -1; - setMinimumSize(600, 50); showTrackinfoFlag = true; cursVal = MAXINT; + parentWin=parent; + //setFocusPolicy(Qt::StrongFocus); //--------------------------------------------------- @@ -396,7 +398,7 @@ Arranger::Arranger(QMainWindow* parent, const char* name) canvas->setCanvasTools(MusEWidget::arrangerTools); canvas->setOrigin(-offset, 0); canvas->setFocus(); - //parent->setFocusProxy(canvas); // Tim. + setFocusProxy(canvas); // once removed by Tim (r735), added by flo again connect(canvas, SIGNAL(setUsedTool(int)), this, SIGNAL(setUsedTool(int))); connect(canvas, SIGNAL(trackChanged(Track*)), list, SLOT(selectTrack(Track*))); @@ -761,20 +763,20 @@ void Arranger::cmd(int cmd) case CMD_COPY_PART: ncmd = PartCanvas::CMD_COPY_PART; break; + case CMD_COPY_PART_IN_RANGE: + ncmd = PartCanvas::CMD_COPY_PART_IN_RANGE; + break; case CMD_PASTE_PART: ncmd = PartCanvas::CMD_PASTE_PART; break; case CMD_PASTE_CLONE_PART: ncmd = PartCanvas::CMD_PASTE_CLONE_PART; break; - case CMD_PASTE_PART_TO_TRACK: - ncmd = PartCanvas::CMD_PASTE_PART_TO_TRACK; - break; - case CMD_PASTE_CLONE_PART_TO_TRACK: - ncmd = PartCanvas::CMD_PASTE_CLONE_PART_TO_TRACK; + case CMD_PASTE_DIALOG: + ncmd = PartCanvas::CMD_PASTE_DIALOG; break; - case CMD_INSERT_PART: - ncmd = PartCanvas::CMD_INSERT_PART; + case CMD_PASTE_CLONE_DIALOG: + ncmd = PartCanvas::CMD_PASTE_CLONE_DIALOG; break; case CMD_INSERT_EMPTYMEAS: ncmd = PartCanvas::CMD_INSERT_EMPTYMEAS; diff --git a/muse2/muse/arranger/arranger.h b/muse2/muse/arranger/arranger.h index 77299ef6..1e3943be 100644 --- a/muse2/muse/arranger/arranger.h +++ b/muse2/muse/arranger/arranger.h @@ -57,6 +57,8 @@ class Splitter; class SpinBox; } +class ArrangerView; + //--------------------------------------------------------- // WidgetStack //--------------------------------------------------------- @@ -167,10 +169,10 @@ class Arranger : public QWidget { void controllerChanged(Track *t); public: - enum { CMD_CUT_PART, CMD_COPY_PART, CMD_PASTE_PART, CMD_PASTE_CLONE_PART, CMD_PASTE_PART_TO_TRACK, CMD_PASTE_CLONE_PART_TO_TRACK, - CMD_INSERT_PART, CMD_INSERT_EMPTYMEAS }; + enum { CMD_CUT_PART, CMD_COPY_PART, CMD_COPY_PART_IN_RANGE, CMD_PASTE_PART, CMD_PASTE_CLONE_PART, + CMD_PASTE_DIALOG, CMD_PASTE_CLONE_DIALOG, CMD_INSERT_EMPTYMEAS }; - Arranger(QMainWindow* parent, const char* name = 0); + Arranger(ArrangerView* parent, const char* name = 0); PartCanvas* getCanvas() { return canvas; } void setMode(int); @@ -187,6 +189,8 @@ class Arranger : public QWidget { void clear(); unsigned cursorValue() { return cursVal; } + + ArrangerView* parentWin; }; #endif diff --git a/muse2/muse/arranger/arrangerview.cpp b/muse2/muse/arranger/arrangerview.cpp new file mode 100644 index 00000000..0cc75db9 --- /dev/null +++ b/muse2/muse/arranger/arrangerview.cpp @@ -0,0 +1,726 @@ +//========================================================= +// MusE +// Linux Music Editor +// arrangerview.cpp +// (C) Copyright 2011 Florian Jung (flo93@users.sourceforge.net) +// +// 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 <QApplication> +#include <QClipboard> +#include <QCloseEvent> +#include <QDir> +#include <QGridLayout> +#include <QImage> +#include <QInputDialog> +#include <QKeyEvent> +#include <QKeySequence> +#include <QLabel> +#include <QLayout> +#include <QMenu> +#include <QMenuBar> +#include <QMessageBox> +#include <QMimeData> +#include <QPushButton> +#include <QResizeEvent> +#include <QScrollArea> +#include <QScrollBar> +#include <QSettings> +#include <QShortcut> +#include <QSignalMapper> +#include <QSizeGrip> +#include <QToolButton> +#include <QToolTip> + +#include "al/sig.h" +#include "app.h" +#include "arrangerview.h" +#include "audio.h" +#include "functions.h" +#include "gconfig.h" +#include "globals.h" +#include "helper.h" +#include "icons.h" +#include "mtscale.h" +#include "scoreedit.h" +#include "shortcuts.h" +#include "sig.h" +#include "song.h" +#include "structure.h" +#include "tb1.h" +#include "tools.h" +#include "ttoolbar.h" +#include "visibletracks.h" +#include "xml.h" + + +//--------------------------------------------------------- +// ArrangerView +//--------------------------------------------------------- + +ArrangerView::ArrangerView(QWidget* parent) + : TopWin(TopWin::ARRANGER, parent, "arrangerview", Qt::Window) +{ + using MusEGlobal::muse; + + //setAttribute(Qt::WA_DeleteOnClose); + setWindowTitle(tr("MusE: Arranger")); + setFocusPolicy(Qt::StrongFocus); + + arranger = new Arranger(this, "arranger"); + setCentralWidget(arranger); + setFocusProxy(arranger); + + scoreOneStaffPerTrackMapper = new QSignalMapper(this); + scoreAllInOneMapper = new QSignalMapper(this); + + editSignalMapper = new QSignalMapper(this); + QShortcut* sc = new QShortcut(shortcuts[SHRT_DELETE].key, this); + sc->setContext(Qt::WindowShortcut); + connect(sc, SIGNAL(activated()), editSignalMapper, SLOT(map())); + editSignalMapper->setMapping(sc, CMD_DELETE); + + // Toolbars --------------------------------------------------------- + QToolBar* undo_tools=addToolBar(tr("Undo/Redo tools")); + undo_tools->setObjectName("Undo/Redo tools"); + undo_tools->addActions(MusEGlobal::undoRedo->actions()); + + + QToolBar* panic_toolbar = addToolBar(tr("panic")); + panic_toolbar->setObjectName("panic"); + panic_toolbar->addAction(MusEGlobal::panicAction); + + QToolBar* transport_toolbar = addToolBar(tr("transport")); + transport_toolbar->setObjectName("transport"); + transport_toolbar->addActions(MusEGlobal::transportAction->actions()); + + editTools = new MusEWidget::EditToolBar(this, MusEWidget::arrangerTools); + addToolBar(editTools); + editTools->setObjectName("arrangerTools"); + + visTracks = new MusEWidget::VisibleTracks(this); + addToolBar(visTracks); + + + + connect(editTools, SIGNAL(toolChanged(int)), arranger, SLOT(setTool(int))); + connect(visTracks, SIGNAL(visibilityChanged()), song, SLOT(update()) ); + connect(arranger, SIGNAL(editPart(Track*)), muse, SLOT(startEditor(Track*))); + connect(arranger, SIGNAL(dropSongFile(const QString&)), muse, SLOT(loadProjectFile(const QString&))); + connect(arranger, SIGNAL(dropMidiFile(const QString&)), muse, SLOT(importMidi(const QString&))); + connect(arranger, SIGNAL(startEditor(PartList*,int)), muse, SLOT(startEditor(PartList*,int))); + connect(arranger, SIGNAL(toolChanged(int)), editTools, SLOT(set(int))); + connect(muse, SIGNAL(configChanged()), arranger, SLOT(configChanged())); + connect(arranger, SIGNAL(setUsedTool(int)), editTools, SLOT(set(int))); + connect(arranger, SIGNAL(selectionChanged()), SLOT(selectionChanged())); + + + + + + + //-------- Edit Actions + editCutAction = new QAction(QIcon(*editcutIconSet), tr("C&ut"), this); + editCopyAction = new QAction(QIcon(*editcopyIconSet), tr("&Copy"), this); + editCopyRangeAction = new QAction(QIcon(*editcopyIconSet), tr("&Copy in range"), this); + editPasteAction = new QAction(QIcon(*editpasteIconSet), tr("&Paste"), this); + editPasteDialogAction = new QAction(QIcon(*editpasteIconSet), tr("Paste (show dialog)"), this); + editPasteCloneAction = new QAction(QIcon(*editpasteCloneIconSet), tr("Paste c&lone"), this); + editPasteCloneDialogAction = new QAction(QIcon(*editpasteCloneIconSet), tr("Paste clone (show dialog)"), this); + editInsertEMAction = new QAction(QIcon(*editpasteIconSet), tr("&Insert Empty Measure"), this); + editDeleteSelectedAction = new QAction(QIcon(*edit_track_delIcon), tr("Delete Selected Tracks"), this); + + editShrinkPartsAction = new QAction(tr("Shrink selected parts"), this); //FINDMICH TODO tooltips! + editExpandPartsAction = new QAction(tr("Expand selected parts"), this); + editCleanPartsAction = new QAction(tr("Clean selected parts"), this); + + + addTrack = new QMenu(tr("Add Track"), this); + addTrack->setIcon(QIcon(*edit_track_addIcon)); + select = new QMenu(tr("Select"), this); + select->setIcon(QIcon(*selectIcon)); + + editSelectAllAction = new QAction(QIcon(*select_allIcon), tr("Select &All"), this); + editDeselectAllAction = new QAction(QIcon(*select_deselect_allIcon), tr("&Deselect All"), this); + editInvertSelectionAction = new QAction(QIcon(*select_invert_selectionIcon), tr("Invert &Selection"), this); + editInsideLoopAction = new QAction(QIcon(*select_inside_loopIcon), tr("&Inside Loop"), this); + editOutsideLoopAction = new QAction(QIcon(*select_outside_loopIcon), tr("&Outside Loop"), this); + editAllPartsAction = new QAction( QIcon(*select_all_parts_on_trackIcon), tr("All &Parts on Track"), this); + + + scoreSubmenu = new QMenu(tr("Score"), this); + scoreSubmenu->setIcon(QIcon(*scoreIconSet)); + + scoreAllInOneSubsubmenu = new QMenu(tr("all parts in one staff"), this); + scoreOneStaffPerTrackSubsubmenu = new QMenu(tr("one staff per part"), this); + + scoreSubmenu->addMenu(scoreAllInOneSubsubmenu); + scoreSubmenu->addMenu(scoreOneStaffPerTrackSubsubmenu); + updateScoreMenus(); + + startScoreEditAction = new QAction(*scoreIconSet, tr("New score window"), this); + startPianoEditAction = new QAction(*pianoIconSet, tr("Pianoroll"), this); + startDrumEditAction = new QAction(QIcon(*edit_drummsIcon), tr("Drums"), this); + startListEditAction = new QAction(QIcon(*edit_listIcon), tr("List"), this); + startWaveEditAction = new QAction(QIcon(*edit_waveIcon), tr("Wave"), this); + + master = new QMenu(tr("Mastertrack"), this); + master->setIcon(QIcon(*edit_mastertrackIcon)); + masterGraphicAction = new QAction(QIcon(*mastertrack_graphicIcon),tr("Graphic"), this); + masterListAction = new QAction(QIcon(*mastertrack_listIcon),tr("List"), this); + + midiTransformerAction = new QAction(QIcon(*midi_transformIcon), tr("Midi &Transform"), this); + + + //-------- Structure Actions + strGlobalCutAction = new QAction(tr("Global Cut"), this); + strGlobalInsertAction = new QAction(tr("Global Insert"), this); + strGlobalSplitAction = new QAction(tr("Global Split"), this); + + + + //------------------------------------------------------------- + // popup Edit + //------------------------------------------------------------- + + QMenu* menuEdit = menuBar()->addMenu(tr("&Edit")); + menuEdit->addActions(MusEGlobal::undoRedo->actions()); + menuEdit->addSeparator(); + + menuEdit->addAction(editCutAction); + menuEdit->addAction(editCopyAction); + menuEdit->addAction(editCopyRangeAction); + menuEdit->addAction(editPasteAction); + menuEdit->addAction(editPasteDialogAction); + menuEdit->addAction(editPasteCloneAction); + menuEdit->addAction(editPasteCloneDialogAction); + menuEdit->addAction(editInsertEMAction); + menuEdit->addSeparator(); + menuEdit->addAction(editShrinkPartsAction); + menuEdit->addAction(editExpandPartsAction); + menuEdit->addAction(editCleanPartsAction); + menuEdit->addSeparator(); + menuEdit->addAction(editDeleteSelectedAction); + + menuEdit->addMenu(addTrack); + menuEdit->addMenu(select); + select->addAction(editSelectAllAction); + select->addAction(editDeselectAllAction); + select->addAction(editInvertSelectionAction); + select->addAction(editInsideLoopAction); + select->addAction(editOutsideLoopAction); + select->addAction(editAllPartsAction); + menuEdit->addSeparator(); + + menuEdit->addAction(startPianoEditAction); + menuEdit->addMenu(scoreSubmenu); + menuEdit->addAction(startScoreEditAction); + menuEdit->addAction(startDrumEditAction); + menuEdit->addAction(startListEditAction); + menuEdit->addAction(startWaveEditAction); + + menuEdit->addMenu(master); + master->addAction(masterGraphicAction); + master->addAction(masterListAction); + menuEdit->addSeparator(); + + menuEdit->addAction(midiTransformerAction); + + QMenu* menuStructure = menuEdit->addMenu(tr("&Structure")); + menuStructure->addAction(strGlobalCutAction); + menuStructure->addAction(strGlobalInsertAction); + menuStructure->addAction(strGlobalSplitAction); + + + + QMenu* functions_menu = menuBar()->addMenu(tr("Functions")); + QAction* func_quantize_action = functions_menu->addAction(tr("&Quantize Notes"), editSignalMapper, SLOT(map())); + QAction* func_notelen_action = functions_menu->addAction(tr("Change note &length"), editSignalMapper, SLOT(map())); + QAction* func_velocity_action = functions_menu->addAction(tr("Change note &velocity"), editSignalMapper, SLOT(map())); + QAction* func_cresc_action = functions_menu->addAction(tr("Crescendo/Decrescendo"), editSignalMapper, SLOT(map())); + QAction* func_transpose_action = functions_menu->addAction(tr("Transpose"), editSignalMapper, SLOT(map())); + QAction* func_erase_action = functions_menu->addAction(tr("Erase Events (Not Parts)"), editSignalMapper, SLOT(map())); + QAction* func_move_action = functions_menu->addAction(tr("Move Events (Not Parts)"), editSignalMapper, SLOT(map())); + QAction* func_fixed_len_action = functions_menu->addAction(tr("Set Fixed Note Length"), editSignalMapper, SLOT(map())); + QAction* func_del_overlaps_action = functions_menu->addAction(tr("Delete Overlapping Notes"), editSignalMapper, SLOT(map())); + QAction* func_legato_action = functions_menu->addAction(tr("Legato"), editSignalMapper, SLOT(map())); + editSignalMapper->setMapping(func_quantize_action, CMD_QUANTIZE); + editSignalMapper->setMapping(func_notelen_action, CMD_NOTELEN); + editSignalMapper->setMapping(func_velocity_action, CMD_VELOCITY); + editSignalMapper->setMapping(func_cresc_action, CMD_CRESCENDO); + editSignalMapper->setMapping(func_transpose_action, CMD_TRANSPOSE); + editSignalMapper->setMapping(func_erase_action, CMD_ERASE); + editSignalMapper->setMapping(func_move_action, CMD_MOVE); + editSignalMapper->setMapping(func_fixed_len_action, CMD_FIXED_LEN); + editSignalMapper->setMapping(func_del_overlaps_action, CMD_DELETE_OVERLAPS); + editSignalMapper->setMapping(func_legato_action, CMD_LEGATO); + + + + QMenu* menuSettings = menuBar()->addMenu(tr("Window &Config")); + menuSettings->addAction(subwinAction); + menuSettings->addAction(shareAction); + menuSettings->addAction(fullscreenAction); + + + //-------- Edit connections + connect(editCutAction, SIGNAL(triggered()), editSignalMapper, SLOT(map())); + connect(editCopyAction, SIGNAL(triggered()), editSignalMapper, SLOT(map())); + connect(editCopyRangeAction, SIGNAL(triggered()), editSignalMapper, SLOT(map())); + connect(editPasteAction, SIGNAL(triggered()), editSignalMapper, SLOT(map())); + connect(editPasteCloneAction, SIGNAL(triggered()), editSignalMapper, SLOT(map())); + connect(editPasteDialogAction, SIGNAL(triggered()), editSignalMapper, SLOT(map())); + connect(editPasteCloneDialogAction, SIGNAL(triggered()), editSignalMapper, SLOT(map())); + connect(editInsertEMAction, SIGNAL(triggered()), editSignalMapper, SLOT(map())); + connect(editDeleteSelectedAction, SIGNAL(triggered()), editSignalMapper, SLOT(map())); + + connect(editShrinkPartsAction, SIGNAL(triggered()), editSignalMapper, SLOT(map())); + connect(editExpandPartsAction, SIGNAL(triggered()), editSignalMapper, SLOT(map())); + connect(editCleanPartsAction, SIGNAL(triggered()), editSignalMapper, SLOT(map())); + + connect(editSelectAllAction, SIGNAL(triggered()), editSignalMapper, SLOT(map())); + connect(editDeselectAllAction, SIGNAL(triggered()), editSignalMapper, SLOT(map())); + connect(editInvertSelectionAction, SIGNAL(triggered()), editSignalMapper, SLOT(map())); + connect(editInsideLoopAction, SIGNAL(triggered()), editSignalMapper, SLOT(map())); + connect(editOutsideLoopAction, SIGNAL(triggered()), editSignalMapper, SLOT(map())); + connect(editAllPartsAction, SIGNAL(triggered()), editSignalMapper, SLOT(map())); + + editSignalMapper->setMapping(editCutAction, CMD_CUT); + editSignalMapper->setMapping(editCopyAction, CMD_COPY); + editSignalMapper->setMapping(editCopyRangeAction, CMD_COPY_RANGE); + editSignalMapper->setMapping(editPasteAction, CMD_PASTE); + editSignalMapper->setMapping(editPasteCloneAction, CMD_PASTE_CLONE); + editSignalMapper->setMapping(editPasteDialogAction, CMD_PASTE_DIALOG); + editSignalMapper->setMapping(editPasteCloneDialogAction, CMD_PASTE_CLONE_DIALOG); + editSignalMapper->setMapping(editInsertEMAction, CMD_INSERTMEAS); + editSignalMapper->setMapping(editDeleteSelectedAction, CMD_DELETE_TRACK); + editSignalMapper->setMapping(editShrinkPartsAction, CMD_SHRINK_PART); + editSignalMapper->setMapping(editExpandPartsAction, CMD_EXPAND_PART); + editSignalMapper->setMapping(editCleanPartsAction, CMD_CLEAN_PART); + editSignalMapper->setMapping(editSelectAllAction, CMD_SELECT_ALL); + editSignalMapper->setMapping(editDeselectAllAction, CMD_SELECT_NONE); + editSignalMapper->setMapping(editInvertSelectionAction, CMD_SELECT_INVERT); + editSignalMapper->setMapping(editInsideLoopAction, CMD_SELECT_ILOOP); + editSignalMapper->setMapping(editOutsideLoopAction, CMD_SELECT_OLOOP); + editSignalMapper->setMapping(editAllPartsAction, CMD_SELECT_PARTS); + + connect(editSignalMapper, SIGNAL(mapped(int)), this, SLOT(cmd(int))); + + connect(startPianoEditAction, SIGNAL(activated()), muse, SLOT(startPianoroll())); + connect(startScoreEditAction, SIGNAL(activated()), muse, SLOT(startScoreQuickly())); + connect(startDrumEditAction, SIGNAL(activated()), muse, SLOT(startDrumEditor())); + connect(startListEditAction, SIGNAL(activated()), muse, SLOT(startListEditor())); + connect(startWaveEditAction, SIGNAL(activated()), muse, SLOT(startWaveEditor())); + connect(scoreOneStaffPerTrackMapper, SIGNAL(mapped(QWidget*)), muse, SLOT(openInScoreEdit_oneStaffPerTrack(QWidget*))); + connect(scoreAllInOneMapper, SIGNAL(mapped(QWidget*)), muse, SLOT(openInScoreEdit_allInOne(QWidget*))); + + + connect(masterGraphicAction, SIGNAL(activated()), muse, SLOT(startMasterEditor())); + connect(masterListAction, SIGNAL(activated()), muse, SLOT(startLMasterEditor())); + + connect(midiTransformerAction, SIGNAL(activated()), muse, SLOT(startMidiTransformer())); + + + //-------- Structure connections + connect(strGlobalCutAction, SIGNAL(activated()), SLOT(globalCut())); + connect(strGlobalInsertAction, SIGNAL(activated()), SLOT(globalInsert())); + connect(strGlobalSplitAction, SIGNAL(activated()), SLOT(globalSplit())); + + + + connect(muse, SIGNAL(configChanged()), SLOT(updateShortcuts())); + + + QClipboard* cb = QApplication::clipboard(); + connect(cb, SIGNAL(dataChanged()), SLOT(clipboardChanged())); + connect(cb, SIGNAL(selectionChanged()), SLOT(clipboardChanged())); + + + + // work around for probable QT/WM interaction bug. + // for certain window managers, e.g xfce, this window is + // is displayed although not specifically set to show(); + // bug: 2811156 Softsynth GUI unclosable with XFCE4 (and a few others) + show(); + hide(); +} + +ArrangerView::~ArrangerView() +{ + +} + +void ArrangerView::closeEvent(QCloseEvent* e) +{ + emit deleted(static_cast<TopWin*>(this)); + emit closed(); + e->accept(); +} + + + +void ArrangerView::writeStatus(int level, Xml& xml) const +{ + xml.tag(level++, "arrangerview"); + TopWin::writeStatus(level, xml); + xml.intTag(level, "tool", editTools->curTool()); + xml.tag(level, "/arrangerview"); +} + +void ArrangerView::readStatus(Xml& xml) +{ + for (;;) + { + Xml::Token token = xml.parse(); + if (token == Xml::Error || token == Xml::End) + break; + + const QString& tag = xml.s1(); + switch (token) + { + case Xml::TagStart: + if (tag == "tool") + editTools->set(xml.parseInt()); + else if (tag == "topwin") + TopWin::readStatus(xml); + else + xml.unknown("ArrangerView"); + break; + + case Xml::TagEnd: + if (tag == "arrangerview") + return; + + default: + break; + } + } +} + +//--------------------------------------------------------- +// readConfiguration +//--------------------------------------------------------- + +void ArrangerView::readConfiguration(Xml& xml) + { + for (;;) { + Xml::Token token = xml.parse(); + const QString& tag = xml.s1(); + switch (token) { + case Xml::Error: + case Xml::End: + return; + case Xml::TagStart: + if (tag == "topwin") + TopWin::readConfiguration(ARRANGER, xml); + else + xml.unknown("ArrangerView"); + break; + case Xml::TagEnd: + if (tag == "arrangerview") + return; + default: + break; + } + } + } + +//--------------------------------------------------------- +// writeConfiguration +//--------------------------------------------------------- + +void ArrangerView::writeConfiguration(int level, Xml& xml) + { + xml.tag(level++, "arrangerview"); + TopWin::writeConfiguration(ARRANGER, level, xml); + xml.tag(level, "/arrangerview"); + } + + +void ArrangerView::cmd(int cmd) + { + TrackList* tracks = song->tracks(); + int l = song->lpos(); + int r = song->rpos(); + + switch(cmd) { + case CMD_CUT: + arranger->cmd(Arranger::CMD_CUT_PART); + break; + case CMD_COPY: + arranger->cmd(Arranger::CMD_COPY_PART); + break; + case CMD_COPY_RANGE: + arranger->cmd(Arranger::CMD_COPY_PART_IN_RANGE); + break; + case CMD_PASTE: + arranger->cmd(Arranger::CMD_PASTE_PART); + break; + case CMD_PASTE_CLONE: + arranger->cmd(Arranger::CMD_PASTE_CLONE_PART); + break; + case CMD_PASTE_DIALOG: + arranger->cmd(Arranger::CMD_PASTE_DIALOG); + break; + case CMD_PASTE_CLONE_DIALOG: + arranger->cmd(Arranger::CMD_PASTE_CLONE_DIALOG); + break; + case CMD_INSERTMEAS: + arranger->cmd(Arranger::CMD_INSERT_EMPTYMEAS); + break; + case CMD_DELETE: + if (!song->msgRemoveParts()) //automatically does undo if neccessary and returns true then + { + //msgRemoveParts() returned false -> no parts to remove? + song->startUndo(); + audio->msgRemoveTracks(); //TODO FINDME this could still be speeded up! + song->endUndo(SC_TRACK_REMOVED); + } + break; + case CMD_DELETE_TRACK: + song->startUndo(); + audio->msgRemoveTracks(); + song->endUndo(SC_TRACK_REMOVED); + audio->msgUpdateSoloStates(); + break; + + case CMD_SELECT_ALL: + case CMD_SELECT_NONE: + case CMD_SELECT_INVERT: + case CMD_SELECT_ILOOP: + case CMD_SELECT_OLOOP: + for (iTrack i = tracks->begin(); i != tracks->end(); ++i) { + PartList* parts = (*i)->parts(); + for (iPart p = parts->begin(); p != parts->end(); ++p) { + bool f = false; + int t1 = p->second->tick(); + int t2 = t1 + p->second->lenTick(); + bool inside = + ((t1 >= l) && (t1 < r)) + || ((t2 > l) && (t2 < r)) + || ((t1 <= l) && (t2 > r)); + switch(cmd) { + case CMD_SELECT_INVERT: + f = !p->second->selected(); + break; + case CMD_SELECT_NONE: + f = false; + break; + case CMD_SELECT_ALL: + f = true; + break; + case CMD_SELECT_ILOOP: + f = inside; + break; + case CMD_SELECT_OLOOP: + f = !inside; + break; + } + p->second->setSelected(f); + } + } + song->update(); + break; + + case CMD_SELECT_PARTS: + for (iTrack i = tracks->begin(); i != tracks->end(); ++i) { + if (!(*i)->selected()) + continue; + PartList* parts = (*i)->parts(); + for (iPart p = parts->begin(); p != parts->end(); ++p) + p->second->setSelected(true); + } + song->update(); + break; + + case CMD_SHRINK_PART: shrink_parts(); break; + case CMD_EXPAND_PART: expand_parts(); break; + case CMD_CLEAN_PART: clean_parts(); break; + + case CMD_QUANTIZE: quantize_notes(); break; + case CMD_VELOCITY: modify_velocity(); break; + case CMD_CRESCENDO: crescendo(); break; + case CMD_NOTELEN: modify_notelen(); break; + case CMD_TRANSPOSE: transpose_notes(); break; + case CMD_ERASE: erase_notes(); break; + case CMD_MOVE: move_notes(); break; + case CMD_FIXED_LEN: set_notelen(); break; + case CMD_DELETE_OVERLAPS: delete_overlaps(); break; + case CMD_LEGATO: legato(); break; + + } + } + +void ArrangerView::scoreNamingChanged() +{ + updateScoreMenus(); +} + +void ArrangerView::updateScoreMenus() +{ + QAction* action; + + + scoreOneStaffPerTrackSubsubmenu->clear(); + scoreAllInOneSubsubmenu->clear(); + + + action=new QAction(tr("New"), this); + connect(action, SIGNAL(activated()), scoreOneStaffPerTrackMapper, SLOT(map())); + scoreOneStaffPerTrackMapper->setMapping(action, (QWidget*)NULL); + scoreOneStaffPerTrackSubsubmenu->addAction(action); + + + action=new QAction(tr("New"), this); //the above action may NOT be reused! + connect(action, SIGNAL(activated()), scoreAllInOneMapper, SLOT(map())); + scoreAllInOneMapper->setMapping(action, (QWidget*)NULL); + scoreAllInOneSubsubmenu->addAction(action); + + const ToplevelList* toplevels=MusEGlobal::muse->getToplevels(); + + for (ToplevelList::const_iterator it=toplevels->begin(); it!=toplevels->end(); it++) + if ((*it)->type()==TopWin::SCORE) + { + ScoreEdit* score = dynamic_cast<ScoreEdit*>(*it); + + action=new QAction(score->get_name(), this); + connect(action, SIGNAL(activated()), scoreOneStaffPerTrackMapper, SLOT(map())); + scoreOneStaffPerTrackMapper->setMapping(action, (QWidget*)score); + scoreOneStaffPerTrackSubsubmenu->addAction(action); + + + action=new QAction(score->get_name(), this); //the above action may NOT be reused! + connect(action, SIGNAL(activated()), scoreAllInOneMapper, SLOT(map())); + scoreAllInOneMapper->setMapping(action, (QWidget*)score); + scoreAllInOneSubsubmenu->addAction(action); + } +} + +void ArrangerView::clearScoreMenuMappers() +{ + delete scoreOneStaffPerTrackMapper; + delete scoreAllInOneMapper; + + scoreOneStaffPerTrackMapper = new QSignalMapper(this); + scoreAllInOneMapper = new QSignalMapper(this); + + connect(scoreOneStaffPerTrackMapper, SIGNAL(mapped(QWidget*)), this, SLOT(openInScoreEdit_oneStaffPerTrack(QWidget*))); + connect(scoreAllInOneMapper, SIGNAL(mapped(QWidget*)), this, SLOT(openInScoreEdit_allInOne(QWidget*))); +} + +void ArrangerView::populateAddTrack() +{ + QActionGroup *grp = MusEUtil::populateAddTrack(addTrack); + connect(addTrack, SIGNAL(triggered(QAction *)), SLOT(addNewTrack(QAction *))); + + trackMidiAction = grp->actions()[0]; + trackDrumAction = grp->actions()[1]; + trackWaveAction = grp->actions()[2]; + trackAOutputAction = grp->actions()[3]; + trackAGroupAction = grp->actions()[4]; + trackAInputAction = grp->actions()[5]; + trackAAuxAction = grp->actions()[6]; +} + +void ArrangerView::addNewTrack(QAction* action) +{ + song->addNewTrack(action, MusEGlobal::muse->arranger()->curTrack()); // Insert at current selected track. + //song->addNewTrack(action); // Add at end. +} + +void ArrangerView::updateShortcuts() +{ + editCutAction->setShortcut(shortcuts[SHRT_CUT].key); + editCopyAction->setShortcut(shortcuts[SHRT_COPY].key); + editCopyRangeAction->setShortcut(shortcuts[SHRT_COPY_RANGE].key); + editPasteAction->setShortcut(shortcuts[SHRT_PASTE].key); + editPasteCloneAction->setShortcut(shortcuts[SHRT_PASTE_CLONE].key); + editPasteDialogAction->setShortcut(shortcuts[SHRT_PASTE_DIALOG].key); + editPasteCloneDialogAction->setShortcut(shortcuts[SHRT_PASTE_CLONE_DIALOG].key); + editInsertEMAction->setShortcut(shortcuts[SHRT_INSERTMEAS].key); + + //editDeleteSelectedAction has no acceleration + + trackMidiAction->setShortcut(shortcuts[SHRT_ADD_MIDI_TRACK].key); + trackDrumAction->setShortcut(shortcuts[SHRT_ADD_DRUM_TRACK].key); + trackWaveAction->setShortcut(shortcuts[SHRT_ADD_WAVE_TRACK].key); + trackAOutputAction->setShortcut(shortcuts[SHRT_ADD_AUDIO_OUTPUT].key); + trackAGroupAction->setShortcut(shortcuts[SHRT_ADD_AUDIO_GROUP].key); + trackAInputAction->setShortcut(shortcuts[SHRT_ADD_AUDIO_INPUT].key); + trackAAuxAction->setShortcut(shortcuts[SHRT_ADD_AUDIO_AUX].key); + + editSelectAllAction->setShortcut(shortcuts[SHRT_SELECT_ALL].key); + editDeselectAllAction->setShortcut(shortcuts[SHRT_SELECT_NONE].key); + editInvertSelectionAction->setShortcut(shortcuts[SHRT_SELECT_INVERT].key); + editInsideLoopAction->setShortcut(shortcuts[SHRT_SELECT_OLOOP].key); + editOutsideLoopAction->setShortcut(shortcuts[SHRT_SELECT_OLOOP].key); + editAllPartsAction->setShortcut(shortcuts[SHRT_SELECT_PRTSTRACK].key); + + startPianoEditAction->setShortcut(shortcuts[SHRT_OPEN_PIANO].key); + startDrumEditAction->setShortcut(shortcuts[SHRT_OPEN_DRUMS].key); + startListEditAction->setShortcut(shortcuts[SHRT_OPEN_LIST].key); + startWaveEditAction->setShortcut(shortcuts[SHRT_OPEN_WAVE].key); + + masterGraphicAction->setShortcut(shortcuts[SHRT_OPEN_GRAPHIC_MASTER].key); + masterListAction->setShortcut(shortcuts[SHRT_OPEN_LIST_MASTER].key); + + midiTransformerAction->setShortcut(shortcuts[SHRT_OPEN_MIDI_TRANSFORM].key); + strGlobalCutAction->setShortcut(shortcuts[SHRT_GLOBAL_CUT].key); + strGlobalInsertAction->setShortcut(shortcuts[SHRT_GLOBAL_INSERT].key); + strGlobalSplitAction->setShortcut(shortcuts[SHRT_GLOBAL_SPLIT].key); +} + +//--------------------------------------------------------- +// clipboardChanged +//--------------------------------------------------------- + +void ArrangerView::clipboardChanged() + { + bool flag = false; + if(QApplication::clipboard()->mimeData()->hasFormat(QString("text/x-muse-midipartlist")) || + QApplication::clipboard()->mimeData()->hasFormat(QString("text/x-muse-wavepartlist")) || + QApplication::clipboard()->mimeData()->hasFormat(QString("text/x-muse-mixedpartlist"))) + flag = true; + + editPasteAction->setEnabled(flag); + editPasteCloneAction->setEnabled(flag); + editPasteDialogAction->setEnabled(flag); + editPasteCloneDialogAction->setEnabled(flag); + } + +//--------------------------------------------------------- +// selectionChanged +//--------------------------------------------------------- + +void ArrangerView::selectionChanged() + { + //bool flag = arranger->isSingleSelection(); // -- Hmm, why only single? + bool flag = arranger->selectionSize() > 0; // -- Test OK cut and copy. For muse2. Tim. + editCutAction->setEnabled(flag); + editCopyAction->setEnabled(flag); + } + + +void ArrangerView::updateVisibleTracksButtons() +{ + visTracks->updateVisibleTracksButtons(); +} + +void ArrangerView::globalCut() { ::globalCut(); } +void ArrangerView::globalInsert() { ::globalInsert(); } +void ArrangerView::globalSplit() { ::globalSplit(); } diff --git a/muse2/muse/arranger/arrangerview.h b/muse2/muse/arranger/arrangerview.h new file mode 100644 index 00000000..bdb450ae --- /dev/null +++ b/muse2/muse/arranger/arrangerview.h @@ -0,0 +1,156 @@ +//========================================================= +// MusE +// Linux Music Editor +// arrangerview.h +// (C) Copyright 2011 Florian Jung (flo93@users.sourceforge.net) +// +// 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. +// +//========================================================= + +#ifndef __ARRANGERVIEW_H__ +#define __ARRANGERVIEW_H__ + +#include <QCloseEvent> +#include <QResizeEvent> +#include <QLabel> +#include <QKeyEvent> +#include <QPainter> +#include <QPixmap> +#include <QTimer> +#include <QScrollBar> +#include <QComboBox> +#include <QSignalMapper> +#include <QAction> +#include <QActionGroup> +#include <QGridLayout> +#include <QByteArray> +#include <QToolButton> + +#include <values.h> +#include "noteinfo.h" +#include "cobject.h" +#include "event.h" +#include "view.h" +#include "gconfig.h" +#include "part.h" +#include "keyevent.h" +#include "mtscale_flo.h" +#include "steprec.h" +#include "cleftypes.h" +#include "helper.h" +#include "arranger.h" + +namespace MusEWidget { class VisibleTracks; } + + +class ArrangerView : public TopWin +{ + Q_OBJECT + + private: + + enum cmd_enum + {CMD_CUT, CMD_COPY, CMD_COPY_RANGE, CMD_PASTE, CMD_INSERTMEAS, CMD_PASTE_CLONE, + CMD_PASTE_DIALOG, CMD_PASTE_CLONE_DIALOG, CMD_DELETE, + CMD_SELECT_ALL, CMD_SELECT_NONE, CMD_SELECT_INVERT, + CMD_SELECT_ILOOP, CMD_SELECT_OLOOP, CMD_SELECT_PARTS, + CMD_DELETE_TRACK, CMD_EXPAND_PART, CMD_SHRINK_PART, CMD_CLEAN_PART, + CMD_QUANTIZE, CMD_VELOCITY, CMD_CRESCENDO, CMD_NOTELEN, CMD_TRANSPOSE, + CMD_ERASE, CMD_MOVE, CMD_FIXED_LEN, CMD_DELETE_OVERLAPS, CMD_LEGATO }; + + virtual void closeEvent(QCloseEvent*); + + QGridLayout* mainGrid; + QWidget* mainw; + + MusEWidget::EditToolBar* editTools; + MusEWidget::VisibleTracks* visTracks; + + Arranger* arranger; + + // Edit Menu actions + QMenu* select; + QMenu* addTrack; + QMenu* master; + + QAction *strGlobalCutAction, *strGlobalInsertAction, *strGlobalSplitAction; + QAction *trackMidiAction, *trackDrumAction, *trackWaveAction, *trackAOutputAction, *trackAGroupAction; + QAction *trackAInputAction, *trackAAuxAction; + QAction *editCutAction, *editCopyAction, *editCopyRangeAction; + QAction *editPasteAction, *editPasteCloneAction, *editPasteDialogAction, *editPasteCloneDialogAction; + QAction *editInsertEMAction, *editPasteC2TAction, *editDeleteSelectedAction, *editSelectAllAction, *editDeselectAllAction; + QAction *editInvertSelectionAction, *editInsideLoopAction, *editOutsideLoopAction, *editAllPartsAction; + QAction *masterGraphicAction, *masterListAction; + QAction *midiTransformerAction; + QAction *editCleanPartsAction, *editShrinkPartsAction, *editExpandPartsAction; + + QAction* func_quantize_action; + QAction* func_notelen_action; + QAction* func_velocity_action; + QAction* func_cresc_action; + QAction* func_transpose_action; + QAction* func_erase_action; + QAction* func_move_action; + QAction* func_fixed_len_action; + QAction* func_del_overlaps_action; + QAction* func_legato_action; + + QSignalMapper *editSignalMapper; + QSignalMapper *scoreOneStaffPerTrackMapper; + QSignalMapper *scoreAllInOneMapper; + + private slots: + void clearScoreMenuMappers(); + void globalCut(); + void globalInsert(); + void globalSplit(); + void cmd(int); + void addNewTrack(QAction* action); + + signals: + void deleted(TopWin*); + void closed(); + + public slots: + void scoreNamingChanged(); + void updateScoreMenus(); + void clipboardChanged(); + void selectionChanged(); + void updateShortcuts(); + void updateVisibleTracksButtons(); + + public: + ArrangerView(QWidget* parent = 0); + ~ArrangerView(); + + QAction *startScoreEditAction, *startPianoEditAction, *startDrumEditAction, *startListEditAction, *startWaveEditAction; + QMenu *scoreSubmenu, *scoreOneStaffPerTrackSubsubmenu, *scoreAllInOneSubsubmenu; + + void populateAddTrack(); + + Arranger* getArranger() {return arranger;} + + void writeStatus(int level, Xml& xml) const; + void readStatus(Xml& xml); + static void readConfiguration(Xml&); + static void writeConfiguration(int, Xml&); +}; + + + + +#endif + diff --git a/muse2/muse/arranger/pcanvas.cpp b/muse2/muse/arranger/pcanvas.cpp index 0d73ace6..056dcce7 100644 --- a/muse2/muse/arranger/pcanvas.cpp +++ b/muse2/muse/arranger/pcanvas.cpp @@ -40,6 +40,9 @@ #include "fastlog.h" #include "widgets/tools.h" +#include "arranger.h" +#include "arrangerview.h" +#include "structure.h" #include "pcanvas.h" #include "midieditor.h" #include "globals.h" @@ -58,11 +61,17 @@ #include "midi.h" #include "midictrl.h" #include "utils.h" +#include "dialogs.h" +#include "widgets/pastedialog.h" //#define ABS(x) ((x) < 0) ? -(x) : (x)) //#define ABS(x) (x>=0?x:-x) #define ABS(x) (abs(x)) +using std::set; + +int get_paste_len(); + //--------------------------------------------------------- // colorRect // paints a rectangular icon with a given color @@ -172,15 +181,19 @@ void PartCanvas::leaveEvent(QEvent*) void PartCanvas::returnPressed() { lineEditor->hide(); - Part* oldPart = editPart->part(); - Part* newPart = oldPart->clone(); - //printf("PartCanvas::returnPressed before msgChangePart oldPart refs:%d Arefs:%d newPart refs:%d Arefs:%d\n", oldPart->events()->refCount(), oldPart->events()->arefCount(), newPart->events()->refCount(), newPart->events()->arefCount()); - - newPart->setName(lineEditor->text()); - // Indicate do undo, and do port controller values but not clone parts. - audio->msgChangePart(oldPart, newPart, true, true, false); - - editMode = false; + if (editMode) { + //this check is neccessary, because it returnPressed may be called + //twice. the second call would cause a crash, however! + Part* oldPart = editPart->part(); + Part* newPart = oldPart->clone(); + //printf("PartCanvas::returnPressed before msgChangePart oldPart refs:%d Arefs:%d newPart refs:%d Arefs:%d\n", oldPart->events()->refCount(), oldPart->events()->arefCount(), newPart->events()->refCount(), newPart->events()->arefCount()); + + newPart->setName(lineEditor->text()); + // Indicate do undo, and do port controller values but not clone parts. + audio->msgChangePart(oldPart, newPart, true, true, false); + + editMode = false; + } } //--------------------------------------------------------- @@ -203,6 +216,7 @@ void PartCanvas::viewMouseDoubleClickEvent(QMouseEvent* event) if (lineEditor == 0) { lineEditor = new QLineEdit(this); lineEditor->setFrame(true); + connect(lineEditor, SIGNAL(editingFinished()),SLOT(returnPressed())); } editMode = true; lineEditor->setGeometry(r); @@ -335,7 +349,7 @@ UndoOp PartCanvas::moveItem(MusEWidget::CItem* item, const QPoint& newpos, DragT ntrack = tracks->size(); if (MusEGlobal::debugMsg) printf("PartCanvas::moveItem - add new track\n"); - Track* newTrack = song->addTrack(int(type)); + Track* newTrack = song->addTrack(type, false); // Add at end of list. if (type == Track::WAVE) { WaveTrack* st = (WaveTrack*) track; WaveTrack* dt = (WaveTrack*) newTrack; @@ -648,17 +662,17 @@ QMenu* PartCanvas::genItemPopup(MusEWidget::CItem* item) partPopup->addSeparator(); switch(trackType) { case Track::MIDI: { - partPopup->addAction(MusEGlobal::muse->startPianoEditAction); - partPopup->addMenu(MusEGlobal::muse->scoreSubmenu); - partPopup->addAction(MusEGlobal::muse->startScoreEditAction); - partPopup->addAction(MusEGlobal::muse->startListEditAction); + partPopup->addAction(MusEGlobal::muse->arranger()->parentWin->startPianoEditAction); + partPopup->addMenu(MusEGlobal::muse->arranger()->parentWin->scoreSubmenu); + partPopup->addAction(MusEGlobal::muse->arranger()->parentWin->startScoreEditAction); + partPopup->addAction(MusEGlobal::muse->arranger()->parentWin->startListEditAction); QAction *act_mexport = partPopup->addAction(tr("save part to disk")); act_mexport->setData(16); } break; case Track::DRUM: { - partPopup->addAction(MusEGlobal::muse->startDrumEditAction); - partPopup->addAction(MusEGlobal::muse->startListEditAction); + partPopup->addAction(MusEGlobal::muse->arranger()->parentWin->startDrumEditAction); + partPopup->addAction(MusEGlobal::muse->arranger()->parentWin->startListEditAction); QAction *act_dexport = partPopup->addAction(tr("save part to disk")); act_dexport->setData(16); } @@ -705,6 +719,7 @@ void PartCanvas::itemPopup(MusEWidget::CItem* item, int n, const QPoint& pt) if (lineEditor == 0) { lineEditor = new QLineEdit(this); lineEditor->setFrame(true); + connect(lineEditor, SIGNAL(editingFinished()),SLOT(returnPressed())); } lineEditor->setText(editPart->name()); lineEditor->setFocus(); @@ -846,25 +861,32 @@ void PartCanvas::mousePress(QMouseEvent* event) } QPoint pt = event->pos(); MusEWidget::CItem* item = items.find(pt); - if (item == 0 && _tool!=MusEWidget::AutomationTool) - return; + + //if (item == 0 && _tool!=MusEWidget::AutomationTool) // FINDMICHJETZT. neccessary? (flo93) + // return; + switch (_tool) { default: - emit trackChanged(item->part()->track()); + if (item) + emit trackChanged(item->part()->track()); + else + emit trackChanged(NULL); break; case MusEWidget::CutTool: - splitItem(item, pt); + if (item) splitItem(item, pt); break; case MusEWidget::GlueTool: - glueItem(item); + if (item) glueItem(item); break; case MusEWidget::MuteTool: { - NPart* np = (NPart*) item; - Part* p = np->part(); - p->setMute(!p->mute()); - redraw(); - break; + if (item) { + NPart* np = (NPart*) item; + Part* p = np->part(); + p->setMute(!p->mute()); + redraw(); + break; + } } case MusEWidget::AutomationTool: if (automation.controllerState != doNothing) @@ -943,7 +965,7 @@ void PartCanvas::keyPress(QKeyEvent* event) { if ( key == Qt::Key_Return || key == Qt::Key_Enter ) { - returnPressed(); + //returnPressed(); commented out by flo return; } else if ( key == Qt::Key_Escape ) @@ -2588,21 +2610,39 @@ void PartCanvas::cmd(int cmd) case CMD_COPY_PART: copy(&pl); break; - case CMD_PASTE_PART: - paste(false, false); - break; - case CMD_PASTE_CLONE_PART: - paste(true, false); + case CMD_COPY_PART_IN_RANGE: + copy_in_range(&pl); break; - case CMD_PASTE_PART_TO_TRACK: + case CMD_PASTE_PART: paste(); break; - case CMD_PASTE_CLONE_PART_TO_TRACK: + case CMD_PASTE_CLONE_PART: paste(true); break; - case CMD_INSERT_PART: - paste(false, false, true); + case CMD_PASTE_DIALOG: + case CMD_PASTE_CLONE_DIALOG: + { + unsigned temp_begin = AL::sigmap.raster1(song->vcpos(),0); + unsigned temp_end = AL::sigmap.raster2(temp_begin + get_paste_len(), 0); + paste_dialog->raster = temp_end - temp_begin; + paste_dialog->clone = (cmd == CMD_PASTE_CLONE_DIALOG); + + if (paste_dialog->exec()) + { + paste_mode_t paste_mode; + switch (paste_dialog->insert_method) + { + case 0: paste_mode=PASTEMODE_MIX; break; + case 1: paste_mode=PASTEMODE_MOVEALL; break; + case 2: paste_mode=PASTEMODE_MOVESOME; break; + } + + paste(paste_dialog->clone, paste_mode, paste_dialog->all_in_one_track, + paste_dialog->number, paste_dialog->raster); + } + break; + } case CMD_INSERT_EMPTYMEAS: int startPos=song->vcpos(); int oneMeas=AL::sigmap.ticksMeasure(startPos); @@ -2617,6 +2657,70 @@ void PartCanvas::cmd(int cmd) // cut copy paste //--------------------------------------------------------- +void PartCanvas::copy_in_range(PartList* pl_) +{ + PartList pl; + PartList result_pl; + unsigned int lpos = song->lpos(); + unsigned int rpos = song->rpos(); + + if (pl_->empty()) + { + for (MusEWidget::iCItem i = items.begin(); i != items.end(); ++i) + { + Part* part=static_cast<NPart*>(i->second)->part(); + if ( (part->track()->isMidiTrack()) || (part->track()->type() == Track::WAVE) ) + pl.add(part); + } + } + else + { + for(ciPart p = pl_->begin(); p != pl_->end(); ++p) + if ( (p->second->track()->isMidiTrack()) || (p->second->track()->type() == Track::WAVE) ) + pl.add(p->second); + } + + if (!pl.empty() && (rpos>lpos)) + { + for(ciPart p = pl.begin(); p != pl.end(); ++p) + { + Part* part=p->second; + Track* track=part->track(); + + if ((part->tick() < rpos) && (part->endTick() > lpos)) //is the part in the range? + { + if ((lpos > part->tick()) && (lpos < part->endTick())) + { + Part* p1; + Part* p2; + + track->splitPart(part, lpos, p1, p2); + p1->events()->incARef(-1); + p2->events()->incARef(-1); + + part=p2; + } + + if ((rpos > part->tick()) && (rpos < part->endTick())) + { + Part* p1; + Part* p2; + + track->splitPart(part, rpos, p1, p2); + p1->events()->incARef(-1); + p2->events()->incARef(-1); + + part=p1; + } + + result_pl.add(part); + } + } + + copy(&result_pl); + } +} + void PartCanvas::copy(PartList* pl) { if (pl->empty()) @@ -2700,11 +2804,88 @@ void PartCanvas::copy(PartList* pl) fclose(tmp); } -//--------------------------------------------------------- -// pasteAt -//--------------------------------------------------------- -Undo PartCanvas::pasteAt(const QString& pt, Track* track, unsigned int pos, bool clone, bool toTrack, int* finalPosPtr) + +int get_paste_len() +{ + QClipboard* cb = QApplication::clipboard(); + const QMimeData* md = cb->mimeData(QClipboard::Clipboard); + + QString pfx("text/"); + QString mdpl("x-muse-midipartlist"); + QString wvpl("x-muse-wavepartlist"); + QString mxpl("x-muse-mixedpartlist"); + QString txt; + + if(md->hasFormat(pfx + mdpl)) + txt = cb->text(mdpl, QClipboard::Clipboard); + else if(md->hasFormat(pfx + wvpl)) + txt = cb->text(wvpl, QClipboard::Clipboard); + else if(md->hasFormat(pfx + mxpl)) + txt = cb->text(mxpl, QClipboard::Clipboard); + else + return 0; + + + QByteArray ba = txt.toLatin1(); + const char* ptxt = ba.constData(); + Xml xml(ptxt); + bool end = false; + + unsigned begin_tick=-1; //this uses the greatest possible begin_tick + unsigned end_tick=0; + + for (;;) + { + Xml::Token token = xml.parse(); + const QString& tag = xml.s1(); + switch (token) + { + case Xml::Error: + case Xml::End: + end = true; + break; + + case Xml::TagStart: + if (tag == "part") + { + Part* p = 0; + p = readXmlPart(xml, NULL, false, false); + + if (p) + { + if (p->tick() < begin_tick) + begin_tick=p->tick(); + + if (p->endTick() > end_tick) + end_tick=p->endTick(); + + delete p; + } + } + else + xml.unknown("PartCanvas::get_paste_len"); + break; + + case Xml::TagEnd: + break; + + default: + end = true; + break; + } + if(end) + break; + } + + if (begin_tick > end_tick) + return 0; + else + return end_tick - begin_tick; +} + + +Undo PartCanvas::pasteAt(const QString& pt, Track* track, unsigned int pos, bool clone, bool toTrack, int* finalPosPtr, set<Track*>* affected_tracks) { Undo operations; @@ -2754,7 +2935,10 @@ Undo PartCanvas::pasteAt(const QString& pt, Track* track, unsigned int pos, bool if (p->tick()+p->lenTick()>finalPos) { finalPos=p->tick()+p->lenTick(); } + p->setSelected(true); operations.push_back(UndoOp(UndoOp::AddPart,p)); + if (affected_tracks) + affected_tracks->insert(p->track()); } else xml.unknown("PartCanvas::pasteAt"); @@ -2789,16 +2973,12 @@ Undo PartCanvas::pasteAt(const QString& pt, Track* track, unsigned int pos, bool // paste part to current selected track at cpos //--------------------------------------------------------- -void PartCanvas::paste(bool clone, bool toTrack, bool doInsert) +void PartCanvas::paste(bool clone, paste_mode_t paste_mode, bool to_single_track, int amount, int raster) { Track* track = 0; - - if (doInsert) // logic depends on keeping track of newly selected tracks - deselectAll(); - - + // If we want to paste to a selected track... - if(toTrack) + if (to_single_track) { TrackList* tl = song->tracks(); for (iTrack i = tl->begin(); i != tl->end(); ++i) { @@ -2831,7 +3011,7 @@ void PartCanvas::paste(bool clone, bool toTrack, bool doInsert) if(md->hasFormat(pfx + mdpl)) { // If we want to paste to a selected track... - if(toTrack && !track->isMidiTrack()) + if(to_single_track && !track->isMidiTrack()) { QMessageBox::critical(this, QString("MusE"), tr("Can only paste to midi/drum track")); @@ -2839,11 +3019,10 @@ void PartCanvas::paste(bool clone, bool toTrack, bool doInsert) } txt = cb->text(mdpl, QClipboard::Clipboard); } - else - if(md->hasFormat(pfx + wvpl)) + else if(md->hasFormat(pfx + wvpl)) { // If we want to paste to a selected track... - if(toTrack && track->type() != Track::WAVE) + if(to_single_track && track->type() != Track::WAVE) { QMessageBox::critical(this, QString("MusE"), tr("Can only paste to wave track")); @@ -2851,11 +3030,10 @@ void PartCanvas::paste(bool clone, bool toTrack, bool doInsert) } txt = cb->text(wvpl, QClipboard::Clipboard); } - else - if(md->hasFormat(pfx + mxpl)) + else if(md->hasFormat(pfx + mxpl)) { // If we want to paste to a selected track... - if(toTrack && !track->isMidiTrack() && track->type() != Track::WAVE) + if(to_single_track && !track->isMidiTrack() && track->type() != Track::WAVE) { QMessageBox::critical(this, QString("MusE"), tr("Can only paste to midi or wave track")); @@ -2874,54 +3052,41 @@ void PartCanvas::paste(bool clone, bool toTrack, bool doInsert) { int endPos=0; unsigned int startPos=song->vcpos(); - Undo operations=pasteAt(txt, track, startPos, clone, toTrack, &endPos); + set<Track*> affected_tracks; + + deselectAll(); + + Undo operations; + for (int i=0;i<amount;i++) + { + Undo temp = pasteAt(txt, track, startPos + i*raster, clone, to_single_track, &endPos, &affected_tracks); + operations.insert(operations.end(), temp.begin(), temp.end()); + } + Pos p(endPos, true); song->setPos(0, p); - if (doInsert) { - int offset = endPos-startPos; - Undo temp=movePartsTotheRight(startPos, offset); + + if (paste_mode != PASTEMODE_MIX) + { + int offset; + if (amount==1) offset = endPos-startPos; + else offset = amount*raster; + + Undo temp; + if (paste_mode==PASTEMODE_MOVESOME) + temp=movePartsTotheRight(startPos, offset, false, &affected_tracks); + else + temp=movePartsTotheRight(startPos, offset); + operations.insert(operations.end(), temp.begin(), temp.end()); } + song->applyOperationGroup(operations); } } //--------------------------------------------------------- -// movePartsToTheRight -//--------------------------------------------------------- -Undo PartCanvas::movePartsTotheRight(unsigned int startTicks, int length) -{ - Undo operations; - - // all parts that start after the pasted parts will be moved the entire length of the pasted parts - for (MusEWidget::iCItem i = items.begin(); i != items.end(); ++i) { - if (!i->second->isSelected()) { - Part* part = i->second->part(); - if (part->tick() >= startTicks) { - Part *newPart = part->clone(); - newPart->setTick(newPart->tick()+length); - - operations.push_back(UndoOp(UndoOp::ModifyPart,part,newPart,false,false)); - } - } - } - // perhaps ask if markers should be moved? - MarkerList *markerlist = song->marker(); - for(iMarker i = markerlist->begin(); i != markerlist->end(); ++i) - { - Marker* m = &i->second; - if (m->tick() >= startTicks) { - Marker *oldMarker = new Marker(); - *oldMarker = *m; - m->setTick(m->tick()+length); - operations.push_back(UndoOp(UndoOp::ModifyMarker,oldMarker, m)); - } - } - - return operations; -} -//--------------------------------------------------------- // startDrag //--------------------------------------------------------- @@ -3044,6 +3209,7 @@ void PartCanvas::viewDropEvent(QDropEvent* event) track = tracks->index(trackNo); if (track) { + deselectAll(); Undo temp=pasteAt(text, track, x); song->applyOperationGroup(temp); } @@ -3070,9 +3236,9 @@ void PartCanvas::viewDropEvent(QDropEvent* event) if (!track) { // we need to create a track for this drop if (text.endsWith(".mpt", Qt::CaseInsensitive)) { - track = song->addTrack((Track::MIDI)); + track = song->addTrack(Track::MIDI, false); // Add at end of list. } else { - track = song->addTrack((Track::WAVE)); + track = song->addTrack(Track::WAVE, false); // Add at end of list. } } if (track->type() == Track::WAVE && diff --git a/muse2/muse/arranger/pcanvas.h b/muse2/muse/arranger/pcanvas.h index 927a64e1..2bce9035 100644 --- a/muse2/muse/arranger/pcanvas.h +++ b/muse2/muse/arranger/pcanvas.h @@ -25,6 +25,7 @@ #define __PCANVAS_H__ #include <QVector> +#include <set> #include "song.h" #include "canvas.h" @@ -124,9 +125,10 @@ class PartCanvas : public MusEWidget::Canvas { void splitItem(MusEWidget::CItem* item, const QPoint&); void copy(PartList*); - void paste(bool clone = false, bool toTrack = true, bool doInsert=false); - Undo pasteAt(const QString&, Track*, unsigned int, bool clone = false, bool toTrack = true, int* finalPosPtr = NULL); - Undo movePartsTotheRight(unsigned int startTick, int length); + void copy_in_range(PartList*); + enum paste_mode_t { PASTEMODE_MIX, PASTEMODE_MOVEALL, PASTEMODE_MOVESOME }; + void paste(bool clone = false, paste_mode_t paste_mode = PASTEMODE_MIX, bool to_single_track=false, int amount=1, int raster=1536); + Undo pasteAt(const QString&, Track*, unsigned int, bool clone = false, bool toTrack = true, int* finalPosPtr = NULL, std::set<Track*>* affected_tracks = NULL); //Part* readClone(Xml&, Track*, bool toTrack = true); void drawWavePart(QPainter&, const QRect&, WavePart*, const QRect&); //void drawMidiPart(QPainter&, const QRect& rect, EventList* events, MidiTrack*mt, const QRect& r, int pTick, int from, int to); @@ -141,8 +143,6 @@ class PartCanvas : public MusEWidget::Canvas { double dbToVal(double inDb); double valToDb(double inV); - - protected: virtual void drawCanvas(QPainter&, const QRect&); virtual void endMoveItems(const QPoint&, DragType, int dir); @@ -165,8 +165,8 @@ class PartCanvas : public MusEWidget::Canvas { void returnPressed(); public: - enum { CMD_CUT_PART, CMD_COPY_PART, CMD_PASTE_PART, CMD_PASTE_CLONE_PART, CMD_PASTE_PART_TO_TRACK, CMD_PASTE_CLONE_PART_TO_TRACK, - CMD_INSERT_PART, CMD_INSERT_EMPTYMEAS }; + enum { CMD_CUT_PART, CMD_COPY_PART, CMD_COPY_PART_IN_RANGE, CMD_PASTE_PART, CMD_PASTE_CLONE_PART, + CMD_PASTE_DIALOG, CMD_PASTE_CLONE_DIALOG, CMD_INSERT_EMPTYMEAS }; PartCanvas(int* raster, QWidget* parent, int, int); void partsChanged(); diff --git a/muse2/muse/arranger/tlist.cpp b/muse2/muse/arranger/tlist.cpp index 87f5acde..28b12fdc 100644 --- a/muse2/muse/arranger/tlist.cpp +++ b/muse2/muse/arranger/tlist.cpp @@ -55,6 +55,7 @@ #include "audio.h" #include "instruments/minstrument.h" #include "app.h" +#include "helper.h" #include "gconfig.h" #include "event.h" #include "midiedit/drummap.h" @@ -66,10 +67,6 @@ #include "dssihost.h" #endif -namespace MusEApp { -extern QMenu* populateAddSynth(QWidget* parent); -} - static const int MIN_TRACKHEIGHT = 20; static const int WHEEL_DELTA = 120; QColor collist[] = { Qt::red, Qt::yellow, Qt::blue , Qt::black, Qt::white, Qt::green }; @@ -993,105 +990,44 @@ void TList::mousePressEvent(QMouseEvent* ev) Track* t = y2Track(y + ypos); + // FIXME Observed: Ancient bug: Track Info doesn't change if selecting multiple tracks in reverse order. + // Will need to be fixed if/when adding 'multiple track global editing'. + TrackColumn col = TrackColumn(header->logicalIndexAt(x)); if (t == 0) { if (button == Qt::RightButton) { QMenu* p = new QMenu; - //p->clear(); - QAction* midi = p->addAction(*addtrack_addmiditrackIcon, - tr("Add Midi Track")); - midi->setData(Track::MIDI); - QAction* drum = p->addAction(*addtrack_drumtrackIcon, - tr("Add Drum Track")); - drum->setData(Track::DRUM); - QAction* wave = p->addAction(*addtrack_wavetrackIcon, - tr("Add Wave Track")); - wave->setData(Track::WAVE); - QAction* aoutput = p->addAction(*addtrack_audiooutputIcon, - tr("Add Output")); - aoutput->setData(Track::AUDIO_OUTPUT); - QAction* agroup = p->addAction(*addtrack_audiogroupIcon, - tr("Add Group")); - agroup->setData(Track::AUDIO_GROUP); - QAction* ainput = p->addAction(*addtrack_audioinputIcon, - tr("Add Input")); - ainput->setData(Track::AUDIO_INPUT); - QAction* aaux = p->addAction(*addtrack_auxsendIcon, - tr("Add Aux Send")); - aaux->setData(Track::AUDIO_AUX); + MusEUtil::populateAddTrack(p); - // Create a sub-menu and fill it with found synth types. Make p the owner. - QMenu* synp = MusEApp::populateAddSynth(p); - synp->setIcon(*synthIcon); - synp->setTitle(QT_TRANSLATE_NOOP("@default", "Add Synth")); - - // Add the 'Add Synth' sub-menu to the menu. - p->addMenu(synp); - // Show the menu QAction* act = p->exec(ev->globalPos(), 0); // Valid click? if(act) { - int n = act->data().toInt(); - // Valid item? - if((n >= 0) && ((Track::TrackType)n != Track::AUDIO_SOFTSYNTH)) + t = song->addNewTrack(act); // Add at end of list. + if(t) { - // Synth sub-menu id? - if(n >= MENU_ADD_SYNTH_ID_BASE) - { - n -= MENU_ADD_SYNTH_ID_BASE; - //if(n < synthis.size()) - // t = song->createSynthI(synthis[n]->baseName()); - //if((n - MENU_ADD_SYNTH_ID_BASE) < (int)synthis.size()) - if(n < (int)synthis.size()) - { - //t = song->createSynthI(synp->text(n)); - //t = song->createSynthI(synthis[n]->name()); - t = song->createSynthI(synthis[n]->baseName(), synthis[n]->name()); - - if(t) - { - // Add instance last in midi device list. - for (int i = 0; i < MIDI_PORTS; ++i) - { - MidiPort* port = &midiPorts[i]; - MidiDevice* dev = port->device(); - if (dev==0) - { - midiSeq->msgSetMidiDevice(port, (SynthI*)t); - MusEGlobal::muse->changeConfig(true); // save configuration file - song->update(); - break; - } - } - } - } - } - // Normal track. - else - t = song->addTrack((Track::TrackType)n); - - if(t) - { - song->deselectTracks(); - t->setSelected(true); - - ///emit selectionChanged(); - emit selectionChanged(t); - adjustScrollbar(); - } - } + song->deselectTracks(); + t->setSelected(true); + + ///emit selectionChanged(); + emit selectionChanged(t); + adjustScrollbar(); + } } // Just delete p, and all its children will go too, right? //delete synp; delete p; - } + } else if (button == Qt::LeftButton) { - if (!ctrl) song->deselectTracks(); - } + if (!ctrl) + { + song->deselectTracks(); + emit selectionChanged(0); + } + } return; } @@ -1297,18 +1233,28 @@ void TList::mousePressEvent(QMouseEvent* ev) mode = NORMAL; QMenu* p = new QMenu; //p->clear(); - p->addAction(QIcon(*automation_clear_dataIcon), tr("Delete Track"))->setData(0); - p->addAction(QIcon(*track_commentIcon), tr("Track Comment"))->setData(1); + // Leave room for normal track IDs - base these at AUDIO_SOFTSYNTH. + p->addAction(QIcon(*automation_clear_dataIcon), tr("Delete Track"))->setData(Track::AUDIO_SOFTSYNTH + 1); + p->addAction(QIcon(*track_commentIcon), tr("Track Comment"))->setData(Track::AUDIO_SOFTSYNTH + 2); + p->addSeparator(); + QMenu* pnew = new QMenu(p); + pnew->setTitle(tr("Insert Track")); + pnew->setIcon(QIcon(*edit_track_addIcon)); + MusEUtil::populateAddTrack(pnew); + p->addMenu(pnew); QAction* act = p->exec(ev->globalPos(), 0); if (act) { int n = act->data().toInt(); - switch (n) { - case 0: // delete track + if(n >= Track::AUDIO_SOFTSYNTH && n < MENU_ADD_SYNTH_ID_BASE) + { + n -= Track::AUDIO_SOFTSYNTH; + switch (n) { + case 1: // delete track song->removeTrack0(t); audio->msgUpdateSoloStates(); break; - case 1: // show track comment + case 2: // show track comment { MusEWidget::TrackComment* tc = new MusEWidget::TrackComment(t, 0); tc->show(); @@ -1320,8 +1266,19 @@ void TList::mousePressEvent(QMouseEvent* ev) printf("action %d\n", n); break; } - } + else + { + t = song->addNewTrack(act, t); // Let addNewTrack handle it. Insert before clicked-on track 't'. + if(t) + { + song->deselectTracks(); + t->setSelected(true); + emit selectionChanged(t); + adjustScrollbar(); + } + } + } delete p; } break; @@ -1405,24 +1362,24 @@ void TList::mousePressEvent(QMouseEvent* ev) // selectTrack //--------------------------------------------------------- void TList::selectTrack(Track* tr) - { - song->deselectTracks(); - tr->setSelected(true); - +{ + song->deselectTracks(); - // rec enable track if expected - TrackList recd = getRecEnabledTracks(); - if (recd.size() == 1 && MusEConfig::config.moveArmedCheckBox) { // one rec enabled track, move rec enabled with selection - song->setRecordFlag((Track*)recd.front(),false); - song->setRecordFlag(tr,true); - } + if (tr) { + tr->setSelected(true); - // By T356. Force a redraw for wave tracks, since it does not seem to happen. - //if(!tr->isMidiTrack()) - redraw(); - ///emit selectionChanged(); - emit selectionChanged(tr); - } + + // rec enable track if expected + TrackList recd = getRecEnabledTracks(); + if (recd.size() == 1 && MusEConfig::config.moveArmedCheckBox) { // one rec enabled track, move rec enabled with selection + song->setRecordFlag((Track*)recd.front(),false); + song->setRecordFlag(tr,true); + } + } + + redraw(); + emit selectionChanged(tr); +} //--------------------------------------------------------- // selectTrackAbove |