summaryrefslogtreecommitdiff
path: root/attic/muse2-oom/muse2/muse/arranger
diff options
context:
space:
mode:
Diffstat (limited to 'attic/muse2-oom/muse2/muse/arranger')
-rw-r--r--attic/muse2-oom/muse2/muse/arranger/CMakeLists.txt82
-rw-r--r--attic/muse2-oom/muse2/muse/arranger/alayout.cpp200
-rw-r--r--attic/muse2-oom/muse2/muse/arranger/alayout.h60
-rw-r--r--attic/muse2-oom/muse2/muse/arranger/arranger.cpp1104
-rw-r--r--attic/muse2-oom/muse2/muse/arranger/arranger.h173
-rw-r--r--attic/muse2-oom/muse2/muse/arranger/pcanvas.cpp2977
-rw-r--r--attic/muse2-oom/muse2/muse/arranger/pcanvas.h139
-rw-r--r--attic/muse2-oom/muse2/muse/arranger/tlist.cpp1595
-rw-r--r--attic/muse2-oom/muse2/muse/arranger/tlist.h115
-rw-r--r--attic/muse2-oom/muse2/muse/arranger/trackautomationview.cpp52
-rw-r--r--attic/muse2-oom/muse2/muse/arranger/trackautomationview.h20
11 files changed, 6517 insertions, 0 deletions
diff --git a/attic/muse2-oom/muse2/muse/arranger/CMakeLists.txt b/attic/muse2-oom/muse2/muse/arranger/CMakeLists.txt
new file mode 100644
index 00000000..21a06698
--- /dev/null
+++ b/attic/muse2-oom/muse2/muse/arranger/CMakeLists.txt
@@ -0,0 +1,82 @@
+#=============================================================================
+# MusE
+# Linux Music Editor
+# $Id:$
+#
+# Copyright (C) 2002-2006 by Werner Schweer and others
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2.
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+#=============================================================================
+
+#
+# Expand Qt macros
+#
+QT4_WRAP_CPP (arranger_mocs
+ alayout.h
+ arranger.h
+ pcanvas.h
+ tlist.h
+ )
+
+#
+# List of source files to compile
+#
+file (GLOB arranger_source_files
+ alayout.cpp
+ arranger.cpp
+ pcanvas.cpp
+ tlist.cpp
+ )
+
+#
+# Define target
+#
+add_library ( arranger SHARED
+ ${arranger_source_files}
+ ${arranger_mocs}
+ )
+
+#
+# Append to the list of translations
+#
+set (FILES_TO_TRANSLATE
+ ${FILES_TO_TRANSLATE}
+ ${arranger_source_files}
+ CACHE INTERNAL ""
+ )
+
+#
+# Compilation flags and target name
+#
+set_target_properties( arranger
+ PROPERTIES COMPILE_FLAGS "-include ${PROJECT_BINARY_DIR}/all.h -fPIC"
+ OUTPUT_NAME muse_arranger
+ )
+
+#
+# Linkage
+#
+target_link_libraries ( arranger
+ ${QT_LIBRARIES}
+ awl
+ mixer
+ widgets
+ )
+
+#
+# Install location
+#
+install(TARGETS arranger
+ DESTINATION ${MusE_MODULES_DIR}
+ )
+
diff --git a/attic/muse2-oom/muse2/muse/arranger/alayout.cpp b/attic/muse2-oom/muse2/muse/arranger/alayout.cpp
new file mode 100644
index 00000000..c7e1e4e3
--- /dev/null
+++ b/attic/muse2-oom/muse2/muse/arranger/alayout.cpp
@@ -0,0 +1,200 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: alayout.cpp,v 1.8 2004/02/28 14:58:24 wschweer Exp $
+// (C) Copyright 2002 Werner Schweer (ws@seh.de)
+//=========================================================
+
+#include "alayout.h"
+#include "arranger.h"
+
+#include <QScrollBar>
+
+//---------------------------------------------------------
+// wadd
+//---------------------------------------------------------
+
+void TLLayout::wadd(int idx, QWidget* w)
+ {
+ li[idx] = new QWidgetItem(w);
+ if (idx == 0)
+ stack = (WidgetStack*)w;
+ if (idx == 1)
+ sb = (QScrollBar*)w;
+ addItem(li[idx]);
+ }
+
+#if 0
+//---------------------------------------------------------
+// TLLayoutIterator
+//---------------------------------------------------------
+
+class TLLayoutIterator // : public QGLayoutIterator ddskrjo
+ {
+ int idx;
+ QList<QLayoutItem*> list;
+
+ public:
+ TLLayoutIterator(QList<QLayoutItem*> l) : idx(0), list(l) {}
+ QLayoutItem *current() { return idx < int(list->count()) ? list->at(idx) : 0; }
+ QLayoutItem *next() { idx++; return current(); }
+ QLayoutItem *takeCurrent() { return list->take( idx ); }
+ };
+
+//---------------------------------------------------------
+// iterator
+//---------------------------------------------------------
+
+QLayoutIterator TLLayout::iterator()
+ {
+ return QLayoutIterator(0); //new TLLayoutIterator(&ilist)); ddskrjo
+ }
+
+void TLLayout::addItem(QLayoutItem *item)
+ {
+ ilist.append(item);
+ }
+
+TLLayout::~TLLayout()
+ {
+ deleteAllItems();
+ }
+
+#endif
+
+//---------------------------------------------------------
+// setGeometry
+// perform geometry management for tracklist:
+//
+// 0 1 2
+// +-----------+--------+---------+
+// | Trackinfo | scroll | header 2|
+// | | bar +---------+ y1
+// | ^ | | ^ |
+// | | | <list> |
+// | 0 | 1 | 3 |
+// +-----------+--------+---------+ y2
+// | hline 4 |
+// +----------+-------------------+ y3
+// | button 5 | |
+// +----------+-------------------+
+//---------------------------------------------------------
+
+void TLLayout::setGeometry(const QRect &rect)
+ {
+ //if(_inSetGeometry) // p4.0.11 Tim
+ // return;
+ //_inSetGeometry = true;
+
+ int w = rect.width();
+ int h = rect.height();
+
+ QSize s0;
+ if (stack->visibleWidget()) {
+ s0 = stack->visibleWidget()->minimumSizeHint();
+ if (!s0.isValid()) // widget has no geometry management
+ s0 = stack->visibleWidget()->size();
+ }
+ else
+ s0 = stack->minimumSizeHint();
+
+ QSize s1 = li[1]->sizeHint();
+ QSize s2 = li[2]->sizeHint();
+ QSize s3 = li[3]->sizeHint();
+ QSize s4 = li[4]->sizeHint();
+ QSize s5 = li[5]->sizeHint();
+
+ int y1 = 30; // fixed header height
+ int ah = h - s5.height() - s4.height() - y1; // list height
+ int aw = w - s1.width() - s0.width(); // list width
+
+ int y2 = ah + s2.height();
+ int y3 = y2 + s4.height();
+ int x1 = s0.width();
+ int x2 = x1 + s1.width();
+
+ li[0]->setGeometry(QRect(0, 0, s0.width(), y2));
+
+ QWidget* widget = stack->visibleWidget();
+ int range = s0.height() - y2;
+ if (range < 0)
+ range = 0;
+ // Note this appears to cause a single recursive call to this function - jumps to beginning,
+ // because now the scroll bar wants to be put in the layout.
+ sb->setVisible(range != 0);
+ if (range)
+ sb->setMaximum(range);
+
+ if (widget) {
+ //QSize r(s0.width(), y2);
+ QSize r(s0.width(), y2 < s0.height() ? s0.height() : y2); // p4.0.11 Tim
+ widget->setGeometry(0, 0, r.width(), r.height());
+ }
+
+ li[1]->setGeometry(QRect(x1, 0, s1.width(), y2));
+ li[2]->setGeometry(QRect(x2, 0, aw, s2.height()));
+ li[3]->setGeometry(QRect(x2, y1, aw, ah));
+ li[4]->setGeometry(QRect(0, y2, w, s4.height()));
+ li[5]->setGeometry(QRect(3, y3, s5.width(), s5.height()));
+
+ //_inSetGeometry = false;
+ }
+
+//---------------------------------------------------------
+// sizeHint
+//---------------------------------------------------------
+
+QSize TLLayout::sizeHint() const
+ {
+ return QSize(150, 100);
+ // p4.0.11 Tim. 100 was allowing vertically shrunk trackinfo widgets. Nope, no help.
+ //return minimumSize();
+ }
+
+//---------------------------------------------------------
+// minimumSize
+//---------------------------------------------------------
+
+QSize TLLayout::minimumSize() const
+ {
+ int w = stack->minimumSizeHint().width();
+ w += li[1]->sizeHint().width();
+
+ return QSize(w, 50);
+ // p4.0.11 Tim. 50 was allowing vertically shrunk trackinfo widgets. Nope, no help.
+ //return QSize(w, stack->minimumSizeHint().height());
+ }
+
+//---------------------------------------------------------
+// maximumSize
+//---------------------------------------------------------
+
+QSize TLLayout::maximumSize() const
+ {
+ return QSize(440, 100000);
+ }
+
+//---------------------------------------------------------
+// takeAt
+//---------------------------------------------------------
+
+QLayoutItem* TLLayout::takeAt(int i)
+ {
+ if (i >= 0 && i < ilist.size())
+ return ilist.takeAt(i);
+ else
+ return 0;
+ }
+
+//---------------------------------------------------------
+// clear
+//---------------------------------------------------------
+
+void TLLayout::clear()
+ {
+ QLayoutItem* child;
+ while ((child = takeAt(0)) != 0) {
+ delete child->widget();
+ delete child;
+ }
+ }
diff --git a/attic/muse2-oom/muse2/muse/arranger/alayout.h b/attic/muse2-oom/muse2/muse/arranger/alayout.h
new file mode 100644
index 00000000..8ba1a829
--- /dev/null
+++ b/attic/muse2-oom/muse2/muse/arranger/alayout.h
@@ -0,0 +1,60 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: alayout.h,v 1.3.2.1 2008/01/19 13:33:46 wschweer Exp $
+// (C) Copyright 2002 Werner Schweer (ws@seh.de)
+//=========================================================
+
+#ifndef __ALAYOUT_H__
+#define __ALAYOUT_H__
+
+#include <QLayout>
+#include <QList>
+
+class QLayoutItem;
+class QScrollBar;
+
+class WidgetStack;
+
+//---------------------------------------------------------
+// TLLayout
+// arranger trackList layout manager
+//---------------------------------------------------------
+
+class TLLayout : public QLayout
+ {
+ Q_OBJECT
+
+ bool _inSetGeometry;
+ QList<QLayoutItem*> ilist;
+ QLayoutItem* li[6];
+ QScrollBar* sb;
+ WidgetStack* stack;
+
+ public:
+ //TLLayout(QWidget *parent) : QLayout(parent, 0, -1) {}
+ TLLayout(QWidget *parent) : QLayout(parent) { _inSetGeometry = false; setContentsMargins(0, 0, 0, 0); setSpacing(-1); }
+ ~TLLayout() { clear(); }
+
+ void addItem(QLayoutItem *item) { ilist.append(item); }
+ virtual Qt::Orientations expandingDirections() const { return 0; }
+ virtual bool hasHeightForWidth() const { return false; }
+ virtual int count() const { return ilist.size(); }
+ void clear();
+
+ void wadd(int idx, QWidget* w);
+ virtual QSize sizeHint() const;
+ virtual QSize minimumSize() const;
+ virtual QSize maximumSize() const;
+ //QSize sizeHint() const;
+ //QSize minimumSize() const;
+ //QSize maximumSize() const;
+ ///QLayoutIterator iterator();
+ virtual void setGeometry(const QRect &rect);
+
+ //virtual QLayoutItem* itemAt(int) const { return 0;} // ddskrjo, is pure virtual, overridden
+ virtual QLayoutItem* itemAt(int i) const { return ilist.value(i);}
+ virtual QLayoutItem* takeAt(int); // { return 0;} // ddskrjo, is pure virtual, overridden
+ ///virtual int count() const { return ilist.count(); } // ddskrjo, is pure virtual, overridden
+ };
+#endif
diff --git a/attic/muse2-oom/muse2/muse/arranger/arranger.cpp b/attic/muse2-oom/muse2/muse/arranger/arranger.cpp
new file mode 100644
index 00000000..134465b9
--- /dev/null
+++ b/attic/muse2-oom/muse2/muse/arranger/arranger.cpp
@@ -0,0 +1,1104 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: arranger.cpp,v 1.33.2.21 2009/11/17 22:08:22 terminator356 Exp $
+// (C) Copyright 1999-2004 Werner Schweer (ws@seh.de)
+//=========================================================
+
+#include "config.h"
+
+#include <stdio.h>
+#include <values.h>
+
+#include <QComboBox>
+#include <QGridLayout>
+#include <QKeyEvent>
+#include <QLabel>
+#include <QList>
+#include <QMainWindow>
+#include <QScrollBar>
+#include <QToolBar>
+#include <QToolButton>
+#include <QVBoxLayout>
+#include <QWheelEvent>
+#include <QPainter>
+//#include <QStackedWidget>
+
+#include "arranger.h"
+#include "song.h"
+#include "app.h"
+#include "mtscale.h"
+#include "scrollscale.h"
+#include "pcanvas.h"
+#include "poslabel.h"
+#include "xml.h"
+#include "splitter.h"
+#include "lcombo.h"
+#include "mtrackinfo.h"
+#include "midiport.h"
+#include "mididev.h"
+#include "utils.h"
+#include "globals.h"
+#include "tlist.h"
+#include "icons.h"
+#include "header.h"
+#include "utils.h"
+#include "alayout.h"
+#include "audio.h"
+#include "event.h"
+#include "midiseq.h"
+#include "midictrl.h"
+#include "mpevent.h"
+#include "gconfig.h"
+#include "mixer/astrip.h"
+#include "spinbox.h"
+#include "tvieweditor.h"
+
+//---------------------------------------------------------
+// Arranger::setHeaderToolTips
+//---------------------------------------------------------
+
+void Arranger::setHeaderToolTips()
+ {
+ header->setToolTip(COL_RECORD, tr("Enable Recording"));
+ header->setToolTip(COL_MUTE, tr("Mute/Off Indicator"));
+ header->setToolTip(COL_SOLO, tr("Solo Indicator"));
+ header->setToolTip(COL_CLASS, tr("Track Type"));
+ header->setToolTip(COL_NAME, tr("Track Name"));
+ header->setToolTip(COL_OCHANNEL, tr("Midi output channel number or audio channels"));
+ header->setToolTip(COL_OPORT, tr("Midi output port or synth midi port"));
+ header->setToolTip(COL_TIMELOCK, tr("Time Lock"));
+ header->setToolTip(COL_AUTOMATION, tr("Automation parameter selection"));
+ }
+
+
+
+//---------------------------------------------------------
+// Arranger::setHeaderWhatsThis
+//---------------------------------------------------------
+
+void Arranger::setHeaderWhatsThis()
+ {
+ header->setWhatsThis(COL_RECORD, tr("Enable recording. Click to toggle."));
+ header->setWhatsThis(COL_MUTE, tr("Mute indicator. Click to toggle.\nRight-click to toggle track on/off.\nMute is designed for rapid, repeated action.\nOn/Off is not!"));
+ header->setWhatsThis(COL_SOLO, tr("Solo indicator. Click to toggle.\nConnected tracks are also 'phantom' soloed,\n indicated by a dark square."));
+ header->setWhatsThis(COL_CLASS, tr("Track type. Right-click to change\n midi and drum track types."));
+ header->setWhatsThis(COL_NAME, tr("Track name. Double-click to edit.\nRight-click for more options."));
+ header->setWhatsThis(COL_OCHANNEL, tr("Midi/drum track: Output channel number.\nAudio track: Channels.\nMid/right-click to change."));
+ header->setWhatsThis(COL_OPORT, tr("Midi/drum track: Output port.\nSynth track: Assigned midi port.\nLeft-click to change.\nRight-click to show GUI."));
+ header->setWhatsThis(COL_TIMELOCK, tr("Time lock"));
+ }
+
+//---------------------------------------------------------
+// Arranger
+// is the central widget in app
+//---------------------------------------------------------
+
+Arranger::Arranger(QMainWindow* parent, const char* name)
+ : QWidget(parent)
+ {
+ setObjectName(name);
+ _raster = 0; // measure
+ selected = 0;
+ // Since program covers 3 controls at once, it is in 'midi controller' units rather than 'gui control' units.
+ //program = -1;
+ ///program = CTRL_VAL_UNKNOWN;
+ ///pan = -65;
+ ///volume = -1;
+ setMinimumSize(600, 50);
+ showTrackinfoFlag = true;
+
+ cursVal = MAXINT;
+
+ //setFocusPolicy(Qt::StrongFocus);
+
+ //---------------------------------------------------
+ // ToolBar
+ // create toolbar in toplevel widget
+ //---------------------------------------------------
+
+ parent->addToolBarBreak();
+ QToolBar* toolbar = parent->addToolBar(tr("Arranger"));
+
+ QLabel* label = new QLabel(tr("Cursor"));
+ label->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
+ label->setIndent(3);
+ //toolbar->addWidget(label);
+ cursorPos = new PosLabel(0);
+ cursorPos->setEnabled(false);
+ cursorPos->setFixedHeight(22);
+ cursorPos->setObjectName("arrangerCursor");
+ toolbar->addWidget(cursorPos);
+
+ /*QToolButton* testView = new QToolButton();
+ testView->setText(QString("TG"));
+ toolbar->addWidget(testView);
+ connect(testView, SIGNAL(clicked()), SLOT(showTrackViews()));
+ */
+
+ const char* rastval[] = {
+ QT_TRANSLATE_NOOP("@default", "Off"), QT_TRANSLATE_NOOP("@default", "Bar"), "1/2", "1/4", "1/8", "1/16"
+ };
+ label = new QLabel(tr("Snap"));
+ label->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
+ label->setIndent(3);
+ toolbar->addWidget(label);
+ QComboBox* raster = new QComboBox();
+ for (int i = 0; i < 6; i++)
+ raster->insertItem(i, tr(rastval[i]));
+ raster->setCurrentIndex(1);
+ // Set the audio record part snapping. Set to 0 (bar), the same as this combo box intial raster.
+ song->setArrangerRaster(0);
+ toolbar->addWidget(raster);
+ connect(raster, SIGNAL(activated(int)), SLOT(_setRaster(int)));
+ ///raster->setFocusPolicy(Qt::NoFocus);
+ raster->setFocusPolicy(Qt::TabFocus);
+
+ // Song len
+ label = new QLabel(tr("Len"));
+ label->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
+ label->setIndent(3);
+ toolbar->addWidget(label);
+
+ // song length is limited to 10000 bars; the real song len is limited
+ // by overflows in tick computations
+ //
+ lenEntry = new SpinBox(1, 10000, 1);
+ lenEntry->setValue(song->len());
+ lenEntry->setToolTip(tr("song length - bars"));
+ lenEntry->setWhatsThis(tr("song length - bars"));
+ toolbar->addWidget(lenEntry);
+ connect(lenEntry, SIGNAL(valueChanged(int)), SLOT(songlenChanged(int)));
+
+ typeBox = new LabelCombo(tr("Type"), 0);
+ typeBox->insertItem(0, tr("NO"));
+ typeBox->insertItem(1, tr("GM"));
+ typeBox->insertItem(2, tr("GS"));
+ typeBox->insertItem(3, tr("XG"));
+ typeBox->setCurrentIndex(0);
+ typeBox->setToolTip(tr("midi song type"));
+ typeBox->setWhatsThis(tr("midi song type"));
+ ///typeBox->setFocusPolicy(Qt::NoFocus);
+ typeBox->setFocusPolicy(Qt::TabFocus);
+ toolbar->addWidget(typeBox);
+ connect(typeBox, SIGNAL(activated(int)), SLOT(modeChange(int)));
+
+ label = new QLabel(tr("Pitch"));
+ label->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
+ label->setIndent(3);
+ toolbar->addWidget(label);
+
+ globalPitchSpinBox = new SpinBox(-127, 127, 1);
+ globalPitchSpinBox->setValue(song->globalPitchShift());
+ globalPitchSpinBox->setToolTip(tr("midi pitch"));
+ globalPitchSpinBox->setWhatsThis(tr("global midi pitch shift"));
+ toolbar->addWidget(globalPitchSpinBox);
+ connect(globalPitchSpinBox, SIGNAL(valueChanged(int)), SLOT(globalPitchChanged(int)));
+
+ label = new QLabel(tr("Tempo"));
+ label->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
+ label->setIndent(3);
+ toolbar->addWidget(label);
+
+ globalTempoSpinBox = new SpinBox(50, 200, 1, toolbar);
+ globalTempoSpinBox->setSuffix(QString("%"));
+ globalTempoSpinBox->setValue(tempomap.globalTempo());
+ globalTempoSpinBox->setToolTip(tr("midi tempo"));
+ globalTempoSpinBox->setWhatsThis(tr("midi tempo"));
+ toolbar->addWidget(globalTempoSpinBox);
+ connect(globalTempoSpinBox, SIGNAL(valueChanged(int)), SLOT(globalTempoChanged(int)));
+
+ QToolButton* tempo50 = new QToolButton();
+ tempo50->setText(QString("50%"));
+ toolbar->addWidget(tempo50);
+ connect(tempo50, SIGNAL(clicked()), SLOT(setTempo50()));
+
+ QToolButton* tempo100 = new QToolButton();
+ tempo100->setText(tr("N"));
+ toolbar->addWidget(tempo100);
+ connect(tempo100, SIGNAL(clicked()), SLOT(setTempo100()));
+
+ QToolButton* tempo200 = new QToolButton();
+ tempo200->setText(QString("200%"));
+ toolbar->addWidget(tempo200);
+ connect(tempo200, SIGNAL(clicked()), SLOT(setTempo200()));
+
+ QVBoxLayout* box = new QVBoxLayout(this);
+ box->setContentsMargins(0, 0, 0, 0);
+ box->setSpacing(0);
+ box->addWidget(hLine(this), Qt::AlignTop);
+ //QFrame* hline = hLine(this);
+ //hline->setLineWidth(0);
+ //box->addWidget(hline, Qt::AlignTop);
+
+ //---------------------------------------------------
+ // Tracklist
+ //---------------------------------------------------
+
+ int xscale = -100;
+ int yscale = 1;
+
+ split = new Splitter(Qt::Horizontal, this, "split");
+ split->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
+ box->addWidget(split, 1000);
+ //split->setHandleWidth(10);
+
+ QWidget* tracklist = new QWidget(split);
+
+ split->setStretchFactor(split->indexOf(tracklist), 0);
+ //tracklist->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding, 0, 100));
+ QSizePolicy tpolicy = QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
+ tpolicy.setHorizontalStretch(0);
+ tpolicy.setVerticalStretch(100);
+ tracklist->setSizePolicy(tpolicy);
+
+ QWidget* editor = new QWidget(split);
+ split->setStretchFactor(split->indexOf(editor), 1);
+ //editor->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding,
+ // Changed by T356. Was causing "large int implicitly truncated" warning. These are UCHAR values...
+ //1000, 100));
+ //232, 100)); // 232 is what it was being truncated to, but what is the right value?...
+ //255, 100));
+ QSizePolicy epolicy = QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ epolicy.setHorizontalStretch(255);
+ epolicy.setVerticalStretch(100);
+ editor->setSizePolicy(epolicy);
+
+ //---------------------------------------------------
+ // Track Info
+ //---------------------------------------------------
+
+ infoScroll = new QScrollBar(Qt::Vertical, tracklist);
+ infoScroll->setObjectName("infoScrollBar");
+ //genTrackInfo(tracklist); // Moved below
+
+ // Track-Info Button
+ ib = new QToolButton(tracklist);
+ ib->setText(tr("TrackInfo"));
+ ib->setCheckable(true);
+ ib->setChecked(showTrackinfoFlag);
+ ib->setFocusPolicy(Qt::NoFocus);
+ connect(ib, SIGNAL(toggled(bool)), SLOT(showTrackInfo(bool)));
+
+ header = new Header(tracklist, "header");
+
+ header->setFixedHeight(30);
+
+ QFontMetrics fm1(header->font());
+ int fw = 8;
+
+ header->setColumnLabel(tr("R"), COL_RECORD, fm1.width('R')+fw);
+ header->setColumnLabel(tr("M"), COL_MUTE, fm1.width('M')+fw);
+ header->setColumnLabel(tr("S"), COL_SOLO, fm1.width('S')+fw);
+ header->setColumnLabel(tr("C"), COL_CLASS, fm1.width('C')+fw);
+ header->setColumnLabel(tr("Track"), COL_NAME, 100);
+ header->setColumnLabel(tr("Port"), COL_OPORT, 60);
+ header->setColumnLabel(tr("Ch"), COL_OCHANNEL, 30);
+ header->setColumnLabel(tr("T"), COL_TIMELOCK, fm1.width('T')+fw);
+ header->setColumnLabel(tr("Automation"), COL_AUTOMATION, 75);
+ header->setResizeMode(COL_RECORD, QHeaderView::Fixed);
+ header->setResizeMode(COL_MUTE, QHeaderView::Fixed);
+ header->setResizeMode(COL_SOLO, QHeaderView::Fixed);
+ header->setResizeMode(COL_CLASS, QHeaderView::Fixed);
+ header->setResizeMode(COL_NAME, QHeaderView::Interactive);
+ header->setResizeMode(COL_OPORT, QHeaderView::Interactive);
+ header->setResizeMode(COL_OCHANNEL, QHeaderView::Fixed);
+ header->setResizeMode(COL_TIMELOCK, QHeaderView::Fixed);
+ header->setResizeMode(COL_AUTOMATION, QHeaderView::Interactive);
+
+ setHeaderToolTips();
+ setHeaderWhatsThis();
+ header->setMovable (true );
+ list = new TList(header, tracklist, "tracklist");
+
+ // Do this now that the list is available.
+ genTrackInfo(tracklist);
+
+ ///connect(list, SIGNAL(selectionChanged()), SLOT(trackSelectionChanged()));
+ connect(list, SIGNAL(selectionChanged(Track*)), SLOT(trackSelectionChanged()));
+ connect(list, SIGNAL(selectionChanged(Track*)), midiTrackInfo, SLOT(setTrack(Track*)));
+ connect(header, SIGNAL(sectionResized(int,int,int)), list, SLOT(redraw()));
+ connect(header, SIGNAL(sectionMoved(int,int,int)), list, SLOT(redraw()));
+ connect(header, SIGNAL(sectionMoved(int,int,int)), this, SLOT(headerMoved()));
+
+ // tracklist:
+ //
+ // 0 1 2
+ // +-----------+--------+---------+
+ // | Trackinfo | scroll | Header | 0
+ // | | bar +---------+
+ // | | | TList | 1
+ // +-----------+--------+---------+
+ // | hline | 2
+ // +-----+------------------------+
+ // | ib | | 3
+ // +-----+------------------------+
+
+ connect(infoScroll, SIGNAL(valueChanged(int)), SLOT(trackInfoScroll(int)));
+ tgrid = new TLLayout(tracklist); // layout manager for this
+ tgrid->wadd(0, trackInfo);
+ tgrid->wadd(1, infoScroll);
+ tgrid->wadd(2, header);
+ tgrid->wadd(3, list);
+ tgrid->wadd(4, hLine(tracklist));
+ tgrid->wadd(5, ib);
+
+ //---------------------------------------------------
+ // Editor
+ //---------------------------------------------------
+
+ int offset = AL::sigmap.ticksMeasure(0);
+ hscroll = new ScrollScale(-1000, -10, xscale, song->len(), Qt::Horizontal, editor, -offset);
+ hscroll->setFocusPolicy(Qt::NoFocus);
+ ib->setFixedHeight(hscroll->sizeHint().height());
+
+ // Changed p3.3.43 Too small steps for me...
+ //vscroll = new QScrollBar(1, 20*20, 1, 5, 0, Vertical, editor);
+ //vscroll = new QScrollBar(1, 20*20, 5, 25, 0, Qt::Vertical, editor);
+ vscroll = new QScrollBar(editor);
+ ///vscroll->setMinimum(1);
+ vscroll->setMinimum(0); // Tim.
+ vscroll->setMaximum(20*20);
+ vscroll->setSingleStep(5);
+ vscroll->setPageStep(25);
+ vscroll->setValue(0);
+ vscroll->setOrientation(Qt::Vertical);
+
+ list->setScroll(vscroll);
+
+ QList<int> vallist;
+ vallist.append(tgrid->maximumSize().width());
+ split->setSizes(vallist);
+
+ QGridLayout* egrid = new QGridLayout(editor);
+ egrid->setColumnStretch(0, 50);
+ egrid->setRowStretch(2, 50);
+ egrid->setContentsMargins(0, 0, 0, 0);
+ egrid->setSpacing(0);
+
+ time = new MTScale(&_raster, editor, xscale);
+ time->setOrigin(-offset, 0);
+ canvas = new PartCanvas(&_raster, editor, xscale, yscale);
+ canvas->setBg(config.partCanvasBg);
+ canvas->setCanvasTools(arrangerTools);
+ canvas->setOrigin(-offset, 0);
+ canvas->setFocus();
+ //parent->setFocusProxy(canvas); // Tim.
+
+ connect(canvas, SIGNAL(setUsedTool(int)), this, SIGNAL(setUsedTool(int)));
+ connect(canvas, SIGNAL(trackChanged(Track*)), list, SLOT(selectTrack(Track*)));
+ connect(list, SIGNAL(keyPressExt(QKeyEvent*)), canvas, SLOT(redirKeypress(QKeyEvent*)));
+ connect(canvas, SIGNAL(selectTrackAbove()), list, SLOT(selectTrackAbove()));
+ connect(canvas, SIGNAL(selectTrackBelow()), list, SLOT(selectTrackBelow()));
+
+ connect(this, SIGNAL(redirectWheelEvent(QWheelEvent*)), canvas, SLOT(redirectedWheelEvent(QWheelEvent*)));
+ connect(list, SIGNAL(redirectWheelEvent(QWheelEvent*)), canvas, SLOT(redirectedWheelEvent(QWheelEvent*)));
+
+ //egrid->addMultiCellWidget(time, 0, 0, 0, 1);
+ //egrid->addMultiCellWidget(hLine(editor), 1, 1, 0, 1);
+ egrid->addWidget(time, 0, 0, 1, 2);
+ egrid->addWidget(hLine(editor), 1, 0, 1, 2);
+
+ egrid->addWidget(canvas, 2, 0);
+ egrid->addWidget(vscroll, 2, 1);
+ egrid->addWidget(hscroll, 3, 0, Qt::AlignBottom);
+
+ connect(vscroll, SIGNAL(valueChanged(int)), canvas, SLOT(setYPos(int)));
+ connect(hscroll, SIGNAL(scrollChanged(int)), canvas, SLOT(setXPos(int)));
+ connect(hscroll, SIGNAL(scaleChanged(int)), canvas, SLOT(setXMag(int)));
+ connect(vscroll, SIGNAL(valueChanged(int)), list, SLOT(setYPos(int)));
+ connect(hscroll, SIGNAL(scrollChanged(int)), time, SLOT(setXPos(int))); //
+ connect(hscroll, SIGNAL(scaleChanged(int)), time, SLOT(setXMag(int)));
+ connect(canvas, SIGNAL(timeChanged(unsigned)), SLOT(setTime(unsigned)));
+ connect(canvas, SIGNAL(verticalScroll(unsigned)),SLOT(verticalScrollSetYpos(unsigned)));
+ connect(canvas, SIGNAL(horizontalScroll(unsigned)),hscroll, SLOT(setPos(unsigned)));
+ connect(canvas, SIGNAL(horizontalScrollNoLimit(unsigned)),hscroll, SLOT(setPosNoLimit(unsigned)));
+ connect(time, SIGNAL(timeChanged(unsigned)), SLOT(setTime(unsigned)));
+
+ connect(canvas, SIGNAL(tracklistChanged()), list, SLOT(tracklistChanged()));
+ connect(canvas, SIGNAL(dclickPart(Track*)), SIGNAL(editPart(Track*)));
+ connect(canvas, SIGNAL(startEditor(PartList*,int)), SIGNAL(startEditor(PartList*, int)));
+
+ connect(song, SIGNAL(songChanged(int)), SLOT(songChanged(int)));
+ //connect(song, SIGNAL(mTypeChanged(MType)), SLOT(setMode((int)MType))); // p4.0.7 Tim.
+ connect(canvas, SIGNAL(followEvent(int)), hscroll, SLOT(setOffset(int)));
+ connect(canvas, SIGNAL(selectionChanged()), SIGNAL(selectionChanged()));
+ connect(canvas, SIGNAL(dropSongFile(const QString&)), SIGNAL(dropSongFile(const QString&)));
+ connect(canvas, SIGNAL(dropMidiFile(const QString&)), SIGNAL(dropMidiFile(const QString&)));
+
+ connect(canvas, SIGNAL(toolChanged(int)), SIGNAL(toolChanged(int)));
+// connect(song, SIGNAL(posChanged(int, unsigned, bool)), SLOT(seek()));
+
+ // Removed p3.3.43
+ // Song::addMarker() already emits a 'markerChanged'.
+ //connect(time, SIGNAL(addMarker(int)), SIGNAL(addMarker(int)));
+
+ configChanged(); // set configuration values
+ if(canvas->part())
+ midiTrackInfo->setTrack(canvas->part()->track()); // Tim.
+ showTrackInfo(showTrackinfoFlag);
+
+ // Take care of some tabbies!
+ setTabOrder(tempo200, trackInfo);
+ setTabOrder(trackInfo, infoScroll);
+ setTabOrder(infoScroll, list);
+ setTabOrder(list, canvas);
+ //setTabOrder(canvas, ib);
+ //setTabOrder(ib, hscroll);
+ }
+
+//---------------------------------------------------------
+// updateHScrollRange
+//---------------------------------------------------------
+
+//void Arranger::updateHScrollRange()
+//{
+// int s = 0, e = song->len();
+ // Show one more measure.
+// e += AL::sigmap.ticksMeasure(e);
+ // Show another quarter measure due to imprecise drawing at canvas end point.
+// e += AL::sigmap.ticksMeasure(e) / 4;
+ // Compensate for the fixed vscroll width.
+// e += canvas->rmapxDev(-vscroll->width());
+// int s1, e1;
+// hscroll->range(&s1, &e1);
+// if(s != s1 || e != e1)
+// hscroll->setRange(s, e);
+//}
+
+//---------------------------------------------------------
+// headerMoved
+//---------------------------------------------------------
+
+void Arranger::headerMoved()
+ {
+ //header->setResizeMode(COL_NAME, QHeaderView::Stretch);
+ }
+
+//---------------------------------------------------------
+// setTime
+//---------------------------------------------------------
+
+void Arranger::setTime(unsigned tick)
+ {
+ if (tick == MAXINT)
+ cursorPos->setEnabled(false);
+ else {
+ cursVal = tick;
+ cursorPos->setEnabled(true);
+ cursorPos->setValue(tick);
+ time->setPos(3, tick, false);
+ }
+ }
+
+//---------------------------------------------------------
+// toolChange
+//---------------------------------------------------------
+
+void Arranger::setTool(int t)
+ {
+ canvas->setTool(t);
+ }
+
+//---------------------------------------------------------
+// dclickPart
+//---------------------------------------------------------
+
+void Arranger::dclickPart(Track* t)
+ {
+ emit editPart(t);
+ }
+
+//---------------------------------------------------------
+// configChanged
+//---------------------------------------------------------
+
+void Arranger::configChanged()
+ {
+ //printf("Arranger::configChanged\n");
+
+ if (config.canvasBgPixmap.isEmpty()) {
+ canvas->setBg(config.partCanvasBg);
+ canvas->setBg(QPixmap());
+ //printf("Arranger::configChanged - no bitmap!\n");
+ }
+ else {
+
+ //printf("Arranger::configChanged - bitmap %s!\n", config.canvasBgPixmap.ascii());
+ canvas->setBg(QPixmap(config.canvasBgPixmap));
+ }
+ ///midiTrackInfo->setFont(config.fonts[2]);
+ //updateTrackInfo(type);
+ }
+
+//---------------------------------------------------------
+// songlenChanged
+//---------------------------------------------------------
+
+void Arranger::songlenChanged(int n)
+ {
+ int newLen = AL::sigmap.bar2tick(n, 0, 0);
+ song->setLen(newLen);
+ }
+//---------------------------------------------------------
+// songChanged
+//---------------------------------------------------------
+
+void Arranger::songChanged(int type)
+ {
+ // Is it simply a midi controller value adjustment? Forget it.
+ if(type != SC_MIDI_CONTROLLER)
+ {
+ unsigned endTick = song->len();
+ int offset = AL::sigmap.ticksMeasure(endTick);
+ hscroll->setRange(-offset, endTick + offset); //DEBUG
+ canvas->setOrigin(-offset, 0);
+ time->setOrigin(-offset, 0);
+
+ int bar, beat;
+ unsigned tick;
+ AL::sigmap.tickValues(endTick, &bar, &beat, &tick);
+ if (tick || beat)
+ ++bar;
+ lenEntry->blockSignals(true);
+ lenEntry->setValue(bar);
+ lenEntry->blockSignals(false);
+
+ if(type & SC_SONG_TYPE) // p4.0.7 Tim.
+ setMode(song->mtype());
+
+ trackSelectionChanged();
+ canvas->partsChanged();
+ typeBox->setCurrentIndex(int(song->mtype()));
+ if (type & SC_SIG)
+ time->redraw();
+ if (type & SC_TEMPO)
+ setGlobalTempo(tempomap.globalTempo());
+
+ if(type & SC_TRACK_REMOVED)
+ {
+ AudioStrip* w = (AudioStrip*)(trackInfo->getWidget(2));
+ //AudioStrip* w = (AudioStrip*)(trackInfo->widget(2));
+ if(w)
+ {
+ Track* t = w->getTrack();
+ if(t)
+ {
+ TrackList* tl = song->tracks();
+ iTrack it = tl->find(t);
+ if(it == tl->end())
+ {
+ delete w;
+ trackInfo->addWidget(0, 2);
+ //trackInfo->insertWidget(2, 0);
+ selected = 0;
+ }
+ }
+ }
+ }
+ }
+
+ updateTrackInfo(type);
+ }
+
+//---------------------------------------------------------
+// trackSelectionChanged
+//---------------------------------------------------------
+
+void Arranger::trackSelectionChanged()
+ {
+ TrackList* tracks = song->tracks();
+ Track* track = 0;
+ for (iTrack t = tracks->begin(); t != tracks->end(); ++t) {
+ if ((*t)->selected()) {
+ track = *t;
+ break;
+ }
+ }
+ if (track == selected)
+ return;
+ selected = track;
+ updateTrackInfo(-1);
+ }
+
+//---------------------------------------------------------
+// modeChange
+//---------------------------------------------------------
+
+void Arranger::modeChange(int mode)
+ {
+ song->setMType(MType(mode));
+ updateTrackInfo(-1);
+ }
+
+//---------------------------------------------------------
+// setMode
+//---------------------------------------------------------
+
+void Arranger::setMode(int mode)
+ {
+ typeBox->blockSignals(true); //
+ // This will only set if different.
+ typeBox->setCurrentIndex(mode);
+ typeBox->blockSignals(false); //
+ }
+
+void Arranger::showTrackViews()
+{
+ TrackViewEditor* ted = new TrackViewEditor(this);
+ ted->show();
+}
+//---------------------------------------------------------
+// writeStatus
+//---------------------------------------------------------
+
+void Arranger::writeStatus(int level, Xml& xml)
+ {
+ xml.tag(level++, "arranger");
+ xml.intTag(level, "info", ib->isChecked());
+ split->writeStatus(level, xml);
+ list->writeStatus(level, xml, "list");
+
+ xml.intTag(level, "xpos", hscroll->pos());
+ xml.intTag(level, "xmag", hscroll->mag());
+ xml.intTag(level, "ypos", vscroll->value());
+ xml.etag(level, "arranger");
+ }
+
+//---------------------------------------------------------
+// readStatus
+//---------------------------------------------------------
+
+void Arranger::readStatus(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 == "info")
+ showTrackinfoFlag = xml.parseInt();
+ else if (tag == split->objectName())
+ split->readStatus(xml);
+ else if (tag == "list")
+ list->readStatus(xml, "list");
+ else if (tag == "xmag")
+ hscroll->setMag(xml.parseInt());
+ else if (tag == "xpos") {
+ int hpos = xml.parseInt();
+ hscroll->setPos(hpos);
+ }
+ else if (tag == "ypos")
+ vscroll->setValue(xml.parseInt());
+ else
+ xml.unknown("Arranger");
+ break;
+ case Xml::TagEnd:
+ if (tag == "arranger") {
+ ib->setChecked(showTrackinfoFlag);
+ return;
+ }
+ default:
+ break;
+ }
+ }
+ }
+
+//---------------------------------------------------------
+// setRaster
+//---------------------------------------------------------
+
+void Arranger::_setRaster(int index)
+ {
+ static int rasterTable[] = {
+ 1, 0, 768, 384, 192, 96
+ };
+ _raster = rasterTable[index];
+ // Set the audio record part snapping.
+ song->setArrangerRaster(_raster);
+ canvas->redraw();
+ }
+
+//---------------------------------------------------------
+// reset
+//---------------------------------------------------------
+
+void Arranger::reset()
+ {
+ canvas->setXPos(0);
+ canvas->setYPos(0);
+ hscroll->setPos(0);
+ vscroll->setValue(0);
+ time->setXPos(0);
+ time->setYPos(0);
+ }
+
+//---------------------------------------------------------
+// cmd
+//---------------------------------------------------------
+
+void Arranger::cmd(int cmd)
+ {
+ int ncmd;
+ switch (cmd) {
+ case CMD_CUT_PART:
+ ncmd = PartCanvas::CMD_CUT_PART;
+ break;
+ case CMD_COPY_PART:
+ ncmd = PartCanvas::CMD_COPY_PART;
+ 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;
+ break;
+ case CMD_INSERT_PART:
+ ncmd = PartCanvas::CMD_INSERT_PART;
+ break;
+ case CMD_INSERT_EMPTYMEAS:
+ ncmd = PartCanvas::CMD_INSERT_EMPTYMEAS;
+ break;
+ default:
+ return;
+ }
+ canvas->cmd(ncmd);
+ }
+
+//---------------------------------------------------------
+// globalPitchChanged
+//---------------------------------------------------------
+
+void Arranger::globalPitchChanged(int val)
+ {
+ song->setGlobalPitchShift(val);
+ }
+
+//---------------------------------------------------------
+// globalTempoChanged
+//---------------------------------------------------------
+
+void Arranger::globalTempoChanged(int val)
+ {
+ audio->msgSetGlobalTempo(val);
+ song->tempoChanged();
+ }
+
+//---------------------------------------------------------
+// setTempo50
+//---------------------------------------------------------
+
+void Arranger::setTempo50()
+ {
+ setGlobalTempo(50);
+ }
+
+//---------------------------------------------------------
+// setTempo100
+//---------------------------------------------------------
+
+void Arranger::setTempo100()
+ {
+ setGlobalTempo(100);
+ }
+
+//---------------------------------------------------------
+// setTempo200
+//---------------------------------------------------------
+
+void Arranger::setTempo200()
+ {
+ setGlobalTempo(200);
+ }
+
+//---------------------------------------------------------
+// setGlobalTempo
+//---------------------------------------------------------
+
+void Arranger::setGlobalTempo(int val)
+ {
+ if(val != globalTempoSpinBox->value())
+ globalTempoSpinBox->setValue(val);
+ }
+
+//---------------------------------------------------------
+// verticalScrollSetYpos
+//---------------------------------------------------------
+void Arranger::verticalScrollSetYpos(unsigned ypos)
+ {
+ vscroll->setValue(ypos);
+ }
+
+//---------------------------------------------------------
+// trackInfoScroll
+//---------------------------------------------------------
+
+void Arranger::trackInfoScroll(int y)
+ {
+ if (trackInfo->visibleWidget())
+ trackInfo->visibleWidget()->move(0, -y);
+ }
+
+//---------------------------------------------------------
+// WidgetStack
+//---------------------------------------------------------
+
+WidgetStack::WidgetStack(QWidget* parent, const char* name)
+ : QWidget(parent)
+ {
+ setObjectName(name);
+ top = -1;
+ }
+
+//---------------------------------------------------------
+// raiseWidget
+//---------------------------------------------------------
+
+void WidgetStack::raiseWidget(int idx)
+ {
+ if (top != -1) {
+ if (stack[top])
+ stack[top]->hide();
+ }
+ top = idx;
+ if (idx == -1)
+ return;
+ int n = stack.size();
+ if (idx >= n)
+ return;
+ if (stack[idx])
+ stack[idx]->show();
+ }
+
+//---------------------------------------------------------
+// addWidget
+//---------------------------------------------------------
+
+void WidgetStack::addWidget(QWidget* w, unsigned int n)
+ {
+ if (w)
+ w->hide();
+ if (stack.size() <= n )
+ stack.push_back(w);
+ else
+ stack[n] = w;
+ }
+
+QWidget* WidgetStack::getWidget(unsigned int n)
+ {
+ if (stack.size() <= n )
+ return 0;
+ return stack[n];
+ }
+
+//---------------------------------------------------------
+// visibleWidget
+//---------------------------------------------------------
+
+QWidget* WidgetStack::visibleWidget() const
+ {
+ if (top != -1)
+ return stack[top];
+ return 0;
+ }
+
+//---------------------------------------------------------
+// minimumSizeHint
+//---------------------------------------------------------
+
+QSize WidgetStack::minimumSizeHint() const
+ {
+ if (top == -1)
+ {
+ //printf("WidgetStack::minimumSizeHint top is -1\n");
+ return (QSize(0, 0));
+ }
+ QSize s(0,0);
+ for (unsigned int i = 0; i < stack.size(); ++i) {
+ if (stack[i]) {
+ QSize ss = stack[i]->minimumSizeHint();
+ if (!ss.isValid())
+ ss = stack[i]->minimumSize();
+ s = s.expandedTo(ss);
+ }
+ }
+ //printf("WidgetStack::minimumSizeHint width:%d height:%d\n", s.width(), s.height()); // REMOVE Tim.
+ return s;
+ }
+
+//---------------------------------------------------------
+// clear
+//---------------------------------------------------------
+
+void Arranger::clear()
+ {
+ AudioStrip* w = (AudioStrip*)(trackInfo->getWidget(2));
+ if (w)
+ delete w;
+ trackInfo->addWidget(0, 2);
+ selected = 0;
+ }
+
+void Arranger::wheelEvent(QWheelEvent* ev)
+ {
+ emit redirectWheelEvent(ev);
+ }
+
+void Arranger::controllerChanged(Track *t)
+{
+ canvas->controllerChanged(t);
+}
+
+//---------------------------------------------------------
+// showTrackInfo
+//---------------------------------------------------------
+
+void Arranger::showTrackInfo(bool flag)
+ {
+ showTrackinfoFlag = flag;
+ trackInfo->setVisible(flag);
+ infoScroll->setVisible(flag);
+ updateTrackInfo(-1);
+ }
+
+//---------------------------------------------------------
+// genTrackInfo
+//---------------------------------------------------------
+
+void Arranger::genTrackInfo(QWidget* parent)
+ {
+ trackInfo = new WidgetStack(parent, "trackInfoStack");
+ //trackInfo->setFocusPolicy(Qt::TabFocus); // p4.0.9
+ //trackInfo->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
+
+ noTrackInfo = new QWidget(trackInfo);
+ noTrackInfo->setAutoFillBackground(true);
+ QPixmap *noInfoPix = new QPixmap(160, 1000); //muse_leftside_logo_xpm);
+ const QPixmap *logo = new QPixmap(*museLeftSideLogo);
+ noInfoPix->fill(noTrackInfo->palette().color(QPalette::Window) );
+ QPainter p(noInfoPix);
+ p.drawPixmap(10, 0, *logo, 0,0, logo->width(), logo->height());
+
+ QPalette palette;
+ palette.setBrush(noTrackInfo->backgroundRole(), QBrush(*noInfoPix));
+ noTrackInfo->setPalette(palette);
+ noTrackInfo->setGeometry(0, 0, 65, 200);
+ noTrackInfo->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding));
+
+ midiTrackInfo = new MidiTrackInfo(trackInfo);
+ //midiTrackInfo->setFocusPolicy(Qt::TabFocus); // p4.0.9
+ //midiTrackInfo->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum));
+ trackInfo->addWidget(noTrackInfo, 0);
+ trackInfo->addWidget(midiTrackInfo, 1);
+ trackInfo->addWidget(0, 2);
+
+/// genMidiTrackInfo();
+ }
+
+//---------------------------------------------------------
+// updateTrackInfo
+//---------------------------------------------------------
+
+void Arranger::updateTrackInfo(int flags)
+ {
+ if (!showTrackinfoFlag) {
+ switchInfo(-1);
+ return;
+ }
+ if (selected == 0) {
+ switchInfo(0);
+ return;
+ }
+ if (selected->isMidiTrack()) {
+ switchInfo(1);
+ // If a new part was selected, and only if it's different.
+ if((flags & SC_SELECTION) && midiTrackInfo->track() != selected)
+ // Set a new track and do a complete update.
+ midiTrackInfo->setTrack(selected);
+ else
+ // Otherwise just regular update with specific flags.
+ midiTrackInfo->updateTrackInfo(flags);
+ }
+ else {
+ switchInfo(2);
+ }
+ }
+
+//---------------------------------------------------------
+// switchInfo
+//---------------------------------------------------------
+
+void Arranger::switchInfo(int n)
+ {
+ if (n == 2) {
+ AudioStrip* w = (AudioStrip*)(trackInfo->getWidget(2));
+ if (w == 0 || selected != w->getTrack()) {
+ if (w)
+ delete w;
+ w = new AudioStrip(trackInfo, (AudioTrack*)selected);
+ switch(selected->type()) {/*{{{*/
+ case Track::AUDIO_OUTPUT:
+ w->setObjectName("MixerAudioOutStrip");
+ break;
+ case Track::AUDIO_GROUP:
+ w->setObjectName("MixerAudioGroupStrip");
+ break;
+ case Track::AUDIO_AUX:
+ w->setObjectName("MixerAuxStrip");
+ break;
+ case Track::WAVE:
+ w->setObjectName("MixerWaveStrip");
+ break;
+ case Track::AUDIO_INPUT:
+ w->setObjectName("MixerAudioInStrip");
+ break;
+ case Track::AUDIO_SOFTSYNTH:
+ w->setObjectName("MixerSynthStrip");
+ break;
+ case Track::MIDI:
+ case Track::DRUM:
+ {
+ w->setObjectName("MidiTrackStrip");
+ }
+ break;
+ }/*}}}*/
+ //w->setFocusPolicy(Qt::TabFocus); // p4.0.9
+ connect(song, SIGNAL(songChanged(int)), w, SLOT(songChanged(int)));
+ connect(muse, SIGNAL(configChanged()), w, SLOT(configChanged()));
+ w->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
+ trackInfo->addWidget(w, 2);
+ w->show();
+ //setTabOrder(midiTrackInfo, w); // p4.0.9
+ tgrid->activate();
+ tgrid->update(); // muse-2 Qt4
+ }
+ }
+ if (trackInfo->curIdx() == n)
+ return;
+ trackInfo->raiseWidget(n);
+ tgrid->activate();
+ tgrid->update(); // muse-2 Qt4
+ }
+
+/*
+QSize WidgetStack::minimumSize() const
+{
+ printf("WidgetStack::minimumSize\n"); // REMOVE Tim.
+ return minimumSizeHint();
+}
+
+int WidgetStack::minimumHeight() const
+{
+ printf("WidgetStack::minimumHeight\n"); // REMOVE Tim.
+ return minimumSizeHint().height();
+}
+*/
diff --git a/attic/muse2-oom/muse2/muse/arranger/arranger.h b/attic/muse2-oom/muse2/muse/arranger/arranger.h
new file mode 100644
index 00000000..dde7c48a
--- /dev/null
+++ b/attic/muse2-oom/muse2/muse/arranger/arranger.h
@@ -0,0 +1,173 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: arranger.h,v 1.17.2.15 2009/11/14 03:37:48 terminator356 Exp $
+// (C) Copyright 1999 Werner Schweer (ws@seh.de)
+//=========================================================
+
+#ifndef __ARRANGER_H__
+#define __ARRANGER_H__
+
+#include <vector>
+
+#include "midieditor.h"
+#include "pcanvas.h"
+#include "trackautomationview.h"
+
+class QAction;
+class QCheckBox;
+class QMainWindow;
+class QMenu;
+class QScrollBar;
+class QToolButton;
+class QWheelEvent;
+class QKeyEvent;
+//class QStackedWidget;
+
+class Header;
+class TList;
+class ScrollScale;
+class MTScale;
+class Track;
+class Xml;
+class Splitter;
+class LabelCombo;
+class PosLabel;
+class MidiTrackInfo;
+class TLLayout;
+class WidgetStack;
+class AudioStrip;
+class SpinBox;
+
+//---------------------------------------------------------
+// WidgetStack
+//---------------------------------------------------------
+
+class WidgetStack : public QWidget {
+ Q_OBJECT
+ std::vector<QWidget*> stack;
+ int top;
+
+ public:
+ WidgetStack(QWidget* parent, const char* name = 0);
+ void raiseWidget(int idx);
+ void addWidget(QWidget* w, unsigned int idx);
+ QWidget* getWidget(unsigned int idx);
+ QWidget* visibleWidget() const;
+ int curIdx() const { return top; }
+ virtual QSize minimumSizeHint() const;
+ //QSize minimumSize() const;
+ //int minimumHeight() const;
+ };
+
+//---------------------------------------------------------
+// Arranger
+//---------------------------------------------------------
+
+class Arranger : public QWidget {
+ Q_OBJECT
+
+ int _quant, _raster;
+ PartCanvas* canvas;
+ ScrollScale* hscroll;
+ QScrollBar* vscroll;
+ TList* list;
+ Header* header;
+ MTScale* time;
+ SpinBox* lenEntry;
+ bool showTrackinfoFlag;
+ WidgetStack* trackInfo;
+ //QStackedWidget* trackInfo;
+ QScrollBar* infoScroll;
+ //MidiTrackInfoBase* midiTrackInfo;
+ MidiTrackInfo* midiTrackInfo;
+ AudioStrip* waveTrackInfo;
+ QWidget* noTrackInfo;
+ TLLayout* tgrid;
+
+ Track* selected;
+
+ LabelCombo* typeBox;
+ QToolButton* ib;
+ int trackInfoType;
+ Splitter* split;
+ ///QMenu* pop;
+ int songType;
+ PosLabel* cursorPos;
+ SpinBox* globalTempoSpinBox;
+ SpinBox* globalPitchSpinBox;
+
+ unsigned cursVal;
+ void genTrackInfo(QWidget* parent);
+ void genMidiTrackInfo();
+ void genWaveTrackInfo();
+ void switchInfo(int);
+ void setHeaderToolTips();
+ void setHeaderWhatsThis();
+
+ private slots:
+ void _setRaster(int);
+ void songlenChanged(int);
+ void showTrackInfo(bool);
+ void trackSelectionChanged();
+ void trackInfoScroll(int);
+ void songChanged(int);
+ void modeChange(int);
+ void setTime(unsigned);
+ void headerMoved();
+ void globalPitchChanged(int);
+ void globalTempoChanged(int);
+ void setTempo50();
+ void setTempo100();
+ void setTempo200();
+ //void seek();
+ void verticalScrollSetYpos(unsigned);
+ void showTrackViews();
+
+ signals:
+ void redirectWheelEvent(QWheelEvent*);
+ void editPart(Track*);
+ void selectionChanged();
+ void dropSongFile(const QString&);
+ void dropMidiFile(const QString&);
+ void startEditor(PartList*, int);
+ void toolChanged(int);
+ //void addMarker(int);
+ void setUsedTool(int);
+
+
+ protected:
+ virtual void wheelEvent(QWheelEvent* e);
+
+ public slots:
+ void dclickPart(Track*);
+ void setTool(int);
+ void updateTrackInfo(int flags);
+ void configChanged();
+ 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 };
+
+ Arranger(QMainWindow* parent, const char* name = 0);
+
+ PartCanvas* getCanvas() { return canvas; }
+ void setMode(int);
+ void reset();
+
+ void writeStatus(int level, Xml&);
+ void readStatus(Xml&);
+
+ Track* curTrack() const { return selected; }
+ void cmd(int);
+ bool isSingleSelection() { return canvas->isSingleSelection(); }
+ int selectionSize() { return canvas->selectionSize(); }
+ void setGlobalTempo(int);
+ void clear();
+
+ unsigned cursorValue() { return cursVal; }
+ };
+
+#endif
+
diff --git a/attic/muse2-oom/muse2/muse/arranger/pcanvas.cpp b/attic/muse2-oom/muse2/muse/arranger/pcanvas.cpp
new file mode 100644
index 00000000..3e6919a7
--- /dev/null
+++ b/attic/muse2-oom/muse2/muse/arranger/pcanvas.cpp
@@ -0,0 +1,2977 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: pcanvas.cpp,v 1.48.2.26 2009/11/22 11:08:33 spamatica Exp $
+// (C) Copyright 1999 Werner Schweer (ws@seh.de)
+//=========================================================
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <values.h>
+#include <uuid/uuid.h>
+#include <math.h>
+
+#include <QClipboard>
+#include <QLineEdit>
+#include <QMenu>
+#include <QMessageBox>
+#include <QPainter>
+#include <QUrl>
+
+#include "widgets/tools.h"
+#include "pcanvas.h"
+#include "midieditor.h"
+#include "globals.h"
+#include "icons.h"
+#include "event.h"
+#include "xml.h"
+#include "wave.h"
+#include "audio.h"
+#include "shortcuts.h"
+#include "gconfig.h"
+#include "app.h"
+#include "filedialog.h"
+#include "marker/marker.h"
+
+// Moved into global config by Tim.
+/*
+const char* partColorNames[] = {
+ "Default",
+ "Refrain",
+ "Bridge",
+ "Intro",
+ "Coda",
+ "Chorus",
+ "Solo",
+ "Brass",
+ "Percussion",
+ "Drums",
+ "Guitar",
+ "Bass",
+ "Flute",
+ "Strings",
+ "Keyboard",
+ "Piano",
+ "Saxophon",
+ };
+*/
+
+/*
+//---------------------------------------------------------
+// ColorListItem
+//---------------------------------------------------------
+
+class ColorListItem { //: public QCustomMenuItem { ddskrjo
+ QColor color;
+ int h;
+ int fontheight;
+ QString label;
+ virtual QSize sizeHint() { return QSize(80, h); }
+ virtual void paint(QPainter* p, const QColorGroup&, bool act, bool enabled, int x, int y, int w, int h)
+ {
+ p->fillRect(x+5, y+2, h-4, h-4, QBrush(color));
+ p->drawText(x+5 + h - 4 + 3, y+(fontheight * 3) / 4, label);
+ }
+
+ public:
+ ColorListItem(const QColor& c, int _h, int _fh, const char* txt)
+ : color(c), h(_h), fontheight(_fh), label(txt) {
+ }
+ QString text() const { return QString("PartColor"); }
+ };
+*/
+// ORCAN : colorRect does the same job as the above class.
+// Shall we get rid of the class?
+
+//---------------------------------------------------------
+// colorRect
+// paints a rectangular icon with a given color
+//---------------------------------------------------------
+
+QIcon colorRect(const QColor& color, int width, int height) {
+ QPainter painter;
+ QPixmap image(width, height);
+ painter.begin(&image);
+ painter.setBrush(color);
+ QRect rectangle(0, 0, width, height);
+ painter.drawRect(rectangle);
+ painter.end();
+ QIcon icon(image);
+ return icon;
+}
+
+//---------------------------------------------------------
+// NPart
+//---------------------------------------------------------
+
+NPart::NPart(Part* e) : CItem(Event(), e)
+ {
+ int th = track()->height();
+ int y = track()->y();
+ //printf("NPart::NPart track name:%s, y:%d h:%d\n", track()->name().toLatin1().constData(), y, th);
+
+ ///setPos(QPoint(e->tick(), y + 1));
+ setPos(QPoint(e->tick(), y));
+
+ ///setBBox(QRect(e->tick(), y + 1, e->lenTick(), th));
+ // NOTE: For adjustable border size: If using a two-pixel border width while drawing, use second line.
+ // If one-pixel width, use first line. Tim.
+ //setBBox(QRect(e->tick(), y, e->lenTick(), th));
+ setBBox(QRect(e->tick(), y + 1, e->lenTick(), th));
+ }
+
+//---------------------------------------------------------
+// PartCanvas
+//---------------------------------------------------------
+
+PartCanvas::PartCanvas(int* r, QWidget* parent, int sx, int sy)
+ : Canvas(parent, sx, sy)
+ {
+ setAcceptDrops(true);
+ _raster = r;
+
+ setFocusPolicy(Qt::StrongFocus);
+ // Defaults:
+ lineEditor = 0;
+ editMode = false;
+
+ tracks = song->tracks();
+ setMouseTracking(true);
+ drag = DRAG_OFF;
+ curColorIndex = 0;
+ partsChanged();
+ }
+
+//---------------------------------------------------------
+// y2pitch
+//---------------------------------------------------------
+
+int PartCanvas::y2pitch(int y) const
+ {
+ TrackList* tl = song->tracks();
+ int yy = 0;
+ int idx = 0;
+ for (iTrack it = tl->begin(); it != tl->end(); ++it, ++idx) {
+ int h = (*it)->height();
+ // if ((y >= yy) && (y < yy+h))
+ if (y < yy+h)
+ break;
+ yy += h;
+ }
+ return idx;
+ }
+
+//---------------------------------------------------------
+// pitch2y
+//---------------------------------------------------------
+
+int PartCanvas::pitch2y(int p) const
+ {
+ TrackList* tl = song->tracks();
+ int yy = 0;
+ int idx = 0;
+ for (iTrack it = tl->begin(); it != tl->end(); ++it, ++idx) {
+ if (idx == p)
+ break;
+ yy += (*it)->height();
+ }
+ return yy;
+ }
+
+//---------------------------------------------------------
+// leaveEvent
+//---------------------------------------------------------
+
+void PartCanvas::leaveEvent(QEvent*)
+ {
+ emit timeChanged(MAXINT);
+ }
+
+//---------------------------------------------------------
+// returnPressed
+//---------------------------------------------------------
+
+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);
+ audio->msgChangePart(oldPart, newPart, true, true, false);
+ //printf("PartCanvas::returnPressed after msgChangePart oldPart refs:%d Arefs:%d newPart refs:%d Arefs:%d\n", oldPart->events()->refCount(), oldPart->events()->arefCount(), newPart->events()->refCount(), newPart->events()->arefCount());
+
+ editMode = false;
+ }
+
+//---------------------------------------------------------
+// viewMouseDoubleClick
+//---------------------------------------------------------
+
+void PartCanvas::viewMouseDoubleClickEvent(QMouseEvent* event)
+ {
+ if (_tool != PointerTool) {
+ viewMousePressEvent(event);
+ return;
+ }
+ QPoint cpos = event->pos();
+ curItem = items.find(cpos);
+ bool shift = event->modifiers() & Qt::ShiftModifier;
+ if (curItem) {
+ if (event->button() == Qt::LeftButton && shift) {
+ editPart = (NPart*)curItem;
+ QRect r = map(curItem->bbox());
+ if (lineEditor == 0) {
+ lineEditor = new QLineEdit(this);
+ lineEditor->setFrame(true);
+ }
+ editMode = true;
+ lineEditor->setGeometry(r);
+ lineEditor->setText(editPart->name());
+ lineEditor->setFocus();
+ lineEditor->show();
+ }
+ else if (event->button() == Qt::LeftButton) {
+ deselectAll();
+ selectItem(curItem, true);
+ emit dclickPart(((NPart*)(curItem))->track());
+ }
+ }
+ //
+ // double click creates new part between left and
+ // right mark
+
+ else {
+ TrackList* tl = song->tracks();
+ iTrack it;
+ int yy = 0;
+ int y = event->y();
+ for (it = tl->begin(); it != tl->end(); ++it) {
+ int h = (*it)->height();
+ if (y >= yy && y < (yy + h))
+ break;
+ yy += h;
+ }
+ if (pos[2] - pos[1] > 0 && it != tl->end()) {
+ Track* track = *it;
+ switch(track->type()) {
+ case Track::MIDI:
+ case Track::DRUM:
+ {
+ MidiPart* part = new MidiPart((MidiTrack*)track);
+ part->setTick(pos[1]);
+ part->setLenTick(pos[2]-pos[1]);
+ part->setName(track->name());
+ NPart* np = new NPart(part);
+ items.add(np);
+ deselectAll();
+ part->setSelected(true);
+ audio->msgAddPart(part);
+ }
+ break;
+ case Track::WAVE:
+ case Track::AUDIO_OUTPUT:
+ case Track::AUDIO_INPUT:
+ case Track::AUDIO_GROUP:
+ case Track::AUDIO_AUX:
+ case Track::AUDIO_SOFTSYNTH:
+ break;
+ }
+ }
+ }
+ }
+
+//---------------------------------------------------------
+// startUndo
+//---------------------------------------------------------
+
+void PartCanvas::startUndo(DragType)
+ {
+ song->startUndo();
+ }
+
+//---------------------------------------------------------
+// endUndo
+//---------------------------------------------------------
+
+void PartCanvas::endUndo(DragType t, int flags)
+ {
+ song->endUndo(flags | ((t == MOVE_COPY || t == MOVE_CLONE)
+ ? SC_PART_INSERTED : SC_PART_MODIFIED));
+ }
+
+//---------------------------------------------------------
+// moveCanvasItems
+//---------------------------------------------------------
+
+void PartCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtype, int*)
+{
+ /*
+ if(editor->parts()->empty())
+ return;
+
+ //struct p2c
+ //{
+ // Part* newp;
+ // int xdiff;
+ //}
+
+ //std::set<Part*> parts2change;
+ //typedef std::set<Part*>::iterator iptc;
+ std::map<Part*, Part*> parts2change;
+ typedef std::map<Part*, Part*>::iterator iP2C;
+
+ int modified = 0;
+ for(iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip)
+ {
+ Part* part = ip->second;
+ if(!part)
+ continue;
+
+ int npartoffset = 0;
+ for(iCItem ici = items.begin(); ici != items.end(); ++ici)
+ {
+ CItem* ci = ici->second;
+ //Part* pt = ci->part();
+ //if(!pt)
+ if(ci->part() != part)
+ continue;
+
+ int x = ci->pos().x() + dx;
+ int y = pitch2y(y2pitch(ci->pos().y()) + dp);
+ QPoint newpos = raster(QPoint(x, y));
+
+ // Test moving the item...
+
+ //int offset = testMoveItem(ci, newpos, dragtype);
+ NEvent* nevent = (NEvent*) ci;
+ Event event = nevent->event();
+ //int npitch = y2pitch(newpos.y());
+ x = newpos.x();
+ if (x < 0)
+ x = 0;
+
+ int ntick = editor->rasterVal(x) - part->tick();
+ if (ntick < 0)
+ ntick = 0;
+ int diff = ntick + event.lenTick() - part->lenTick();
+
+ // If moving the item would require a new part size...
+ if(diff > npartoffset)
+ npartoffset = diff;
+ }
+
+ if(npartoffset > 0)
+ {
+ // Create new part...
+ // if there are several events that are moved outside the part, it will be recreated for each
+ // so the part _in_ the event will not be valid, ask the authority.
+ Part* newPart = part->clone();
+ //Part* newPart = Canvas::part()->clone();
+
+ newPart->setLenTick(newPart->lenTick() + npartoffset);
+ audio->msgChangePart(part, newPart,false);
+
+ modified = SC_PART_MODIFIED;
+
+ // BUG FIX: #1650953
+ // Added by T356.
+ // Fixes posted "select and drag past end of part - crashing" bug
+ for(iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip)
+ {
+ if(ip->second == part)
+ {
+ editor->parts()->erase(ip);
+ break;
+ }
+ }
+
+ editor->parts()->add(newPart);
+ if(parts2change.find(part) == parts2change.end())
+ parts2change.insert(std::pair<Part*, Part*> (part, newPart));
+
+// part = newPart; // reassign
+// item->setPart(part);
+// item->setEvent(newEvent);
+// curPart = part;
+// curPartId = curPart->sn();
+
+ }
+ }
+*/
+
+// int modified = 0;
+ for(iCItem ici = items.begin(); ici != items.end(); ++ici)
+ {
+ CItem* ci = ici->second;
+
+ // If this item's part is in the parts2change list, change the item's part to the new part.
+ //Part* pt = ci->part();
+ //iP2C ip2c = parts2change.find(pt);
+ //if(ip2c != parts2change.end())
+ // ci->setPart(ip2c->second);
+
+ int x = ci->pos().x();
+ int y = ci->pos().y();
+ int nx = x + dx;
+ int ny = pitch2y(y2pitch(y) + dp);
+ QPoint newpos = raster(QPoint(nx, ny));
+ selectItem(ci, true);
+
+ if(moveItem(ci, newpos, dtype))
+ ci->move(newpos);
+ if(moving.size() == 1) {
+ itemReleased(curItem, newpos);
+ }
+ if(dtype == MOVE_COPY || dtype == MOVE_CLONE)
+ selectItem(ci, false);
+ }
+
+
+ //if(pflags)
+ // *pflags = modified;
+}
+
+//---------------------------------------------------------
+// moveItem
+// return false, if copy/move not allowed
+//---------------------------------------------------------
+
+// Changed by T356.
+//bool PartCanvas::moveItem(CItem* item, const QPoint& newpos, DragType t, int*)
+bool PartCanvas::moveItem(CItem* item, const QPoint& newpos, DragType t)
+ {
+ NPart* npart = (NPart*) item;
+ Part* spart = npart->part();
+ Track* track = npart->track();
+ unsigned dtick = newpos.x();
+ unsigned ntrack = y2pitch(item->mp().y());
+ Track::TrackType type = track->type();
+ if (tracks->index(track) == ntrack && (dtick == spart->tick())) {
+ return false;
+ }
+ if (ntrack >= tracks->size()) {
+ ntrack = tracks->size();
+ Track* newTrack = song->addTrack(int(type));
+ if (type == Track::WAVE) {
+ WaveTrack* st = (WaveTrack*) track;
+ WaveTrack* dt = (WaveTrack*) newTrack;
+ dt->setChannels(st->channels());
+ }
+ emit tracklistChanged();
+ }
+ Track* dtrack = tracks->index(ntrack);
+
+ if (dtrack->type() != type) {
+ QMessageBox::critical(this, QString("MusE"),
+ tr("Cannot copy/move/clone to different Track-Type"));
+ return false;
+ }
+
+ Part* dpart;
+ //bool clone = (t == MOVE_CLONE) || (spart->events()->arefCount() > 1);
+ //bool clone = (t == MOVE_CLONE);
+ bool clone = (t == MOVE_CLONE || (t == MOVE_COPY && spart->events()->arefCount() > 1));
+
+ if(t == MOVE_MOVE)
+ {
+ // This doesn't increment aref count, and doesn't chain clones.
+ // It also gives the new part a new serial number, but it is
+ // overwritten with the old one by Song::changePart(), from Audio::msgChangePart() below.
+ dpart = spart->clone();
+ dpart->setTrack(dtrack);
+ }
+ else
+ // This increments aref count if cloned, and chains clones.
+ // It also gives the new part a new serial number.
+ dpart = dtrack->newPart(spart, clone);
+
+ dpart->setTick(dtick);
+
+ //printf("PartCanvas::moveItem before add/changePart clone:%d spart:%p events:%p refs:%d Arefs:%d sn:%d dpart:%p events:%p refs:%d Arefs:%d sn:%d\n", clone, spart, spart->events(), spart->events()->refCount(), spart->events()->arefCount(), spart->sn(), dpart, dpart->events(), dpart->events()->refCount(), dpart->events()->arefCount(), dpart->sn());
+
+ if(t == MOVE_MOVE)
+ item->setPart(dpart);
+ //if (!clone) {
+ if (t == MOVE_COPY && !clone) {
+ //
+ // Copy Events
+ //
+ EventList* se = spart->events();
+ EventList* de = dpart->events();
+ for (iEvent i = se->begin(); i != se->end(); ++i) {
+ Event oldEvent = i->second;
+ Event ev = oldEvent.clone();
+ de->add(ev);
+ }
+ }
+ if (t == MOVE_COPY || t == MOVE_CLONE) {
+ // These will not increment ref count, and will not chain clones...
+ if (dtrack->type() == Track::WAVE)
+ audio->msgAddPart((WavePart*)dpart,false);
+ else
+ audio->msgAddPart(dpart,false);
+ }
+ else if (t == MOVE_MOVE) {
+ dpart->setSelected(spart->selected());
+ // These will increment ref count if not a clone, and will chain clones...
+ if (dtrack->type() == Track::WAVE)
+ // Indicate no undo, and do not do port controller values and clone parts.
+ //audio->msgChangePart((WavePart*)spart, (WavePart*)dpart,false);
+ audio->msgChangePart((WavePart*)spart, (WavePart*)dpart, false, false, false);
+ else
+ // Indicate no undo, and do port controller values but not clone parts.
+ //audio->msgChangePart(spart, dpart, false);
+ audio->msgChangePart(spart, dpart, false, true, false);
+
+ spart->setSelected(false);
+ }
+ //printf("PartCanvas::moveItem after add/changePart spart:%p events:%p refs:%d Arefs:%d dpart:%p events:%p refs:%d Arefs:%d\n", spart, spart->events(), spart->events()->refCount(), spart->events()->arefCount(), dpart, dpart->events(), dpart->events()->refCount(), dpart->events()->arefCount());
+
+ if (song->len() < (dpart->lenTick() + dpart->tick()))
+ song->setLen(dpart->lenTick() + dpart->tick());
+ //endUndo(t);
+ return true;
+ }
+
+//---------------------------------------------------------
+// raster
+//---------------------------------------------------------
+
+QPoint PartCanvas::raster(const QPoint& p) const
+ {
+ int y = pitch2y(y2pitch(p.y()));
+ int x = p.x();
+ if (x < 0)
+ x = 0;
+ x = AL::sigmap.raster(x, *_raster);
+ if (x < 0)
+ x = 0;
+ return QPoint(x, y);
+ }
+
+//---------------------------------------------------------
+// partsChanged
+//---------------------------------------------------------
+
+void PartCanvas::partsChanged()
+ {
+ items.clear();
+ int idx = 0;
+ for (iTrack t = tracks->begin(); t != tracks->end(); ++t) {
+ PartList* pl = (*t)->parts();
+ for (iPart i = pl->begin(); i != pl->end(); ++i) {
+ NPart* np = new NPart(i->second);
+ items.add(np);
+ if (i->second->selected()) {
+ selectItem(np, true);
+ }
+ }
+ ++idx;
+ }
+ redraw();
+ }
+
+//---------------------------------------------------------
+// updateSelection
+//---------------------------------------------------------
+
+void PartCanvas::updateSelection()
+ {
+ for (iCItem i = items.begin(); i != items.end(); ++i) {
+ NPart* part = (NPart*)(i->second);
+ part->part()->setSelected(i->second->isSelected());
+ }
+ emit selectionChanged();
+ redraw();
+ }
+
+//---------------------------------------------------------
+// resizeItem
+//---------------------------------------------------------
+
+void PartCanvas::resizeItem(CItem* i, bool noSnap)
+ {
+ Track* t = ((NPart*)(i))->track();
+ Part* p = ((NPart*)(i))->part();
+
+ int pos = p->tick() + i->width();
+ int snappedpos = p->tick();
+ if (!noSnap) {
+ snappedpos = AL::sigmap.raster(pos, *_raster);
+ }
+ unsigned int newwidth = snappedpos - p->tick();
+ if (newwidth == 0)
+ newwidth = AL::sigmap.rasterStep(p->tick(), *_raster);
+
+ song->cmdResizePart(t, p, newwidth);
+ }
+
+//---------------------------------------------------------
+// newItem
+// first create local Item
+//---------------------------------------------------------
+
+CItem* PartCanvas::newItem(const QPoint& pos, int)
+ {
+ int x = pos.x();
+ if (x < 0)
+ x = 0;
+ x = AL::sigmap.raster(x, *_raster);
+ unsigned trackIndex = y2pitch(pos.y());
+ if (trackIndex >= tracks->size())
+ return 0;
+ Track* track = tracks->index(trackIndex);
+ if(!track)
+ return 0;
+
+ Part* pa = 0;
+ NPart* np = 0;
+ switch(track->type()) {
+ case Track::MIDI:
+ case Track::DRUM:
+ pa = new MidiPart((MidiTrack*)track);
+ pa->setTick(x);
+ pa->setLenTick(0);
+ break;
+ case Track::WAVE:
+ pa = new WavePart((WaveTrack*)track);
+ pa->setTick(x);
+ pa->setLenTick(0);
+ break;
+ case Track::AUDIO_OUTPUT:
+ case Track::AUDIO_INPUT:
+ case Track::AUDIO_GROUP:
+ case Track::AUDIO_AUX:
+ case Track::AUDIO_SOFTSYNTH:
+ return 0;
+ }
+ pa->setName(track->name());
+ pa->setColorIndex(curColorIndex);
+ np = new NPart(pa);
+ return np;
+ }
+
+//---------------------------------------------------------
+// newItem
+//---------------------------------------------------------
+
+void PartCanvas::newItem(CItem* i, bool noSnap)
+ {
+ Part* p = ((NPart*)(i))->part();
+
+ int len = i->width();
+ if (!noSnap)
+ len = AL::sigmap.raster(len, *_raster);
+ if (len == 0)
+ len = AL::sigmap.rasterStep(p->tick(), *_raster);
+ p->setLenTick(len);
+ p->setSelected(true);
+ audio->msgAddPart(p);
+ }
+
+//---------------------------------------------------------
+// deleteItem
+//---------------------------------------------------------
+
+bool PartCanvas::deleteItem(CItem* i)
+ {
+ Part* p = ((NPart*)(i))->part();
+ audio->msgRemovePart(p); //Invokes songChanged which calls partsChanged which makes it difficult to delete them there
+ return true;
+ }
+
+//---------------------------------------------------------
+// splitItem
+//---------------------------------------------------------
+
+void PartCanvas::splitItem(CItem* item, const QPoint& pt)
+ {
+ NPart* np = (NPart*) item;
+ Track* t = np->track();
+ Part* p = np->part();
+ int x = pt.x();
+ if (x < 0)
+ x = 0;
+ song->cmdSplitPart(t, p, AL::sigmap.raster(x, *_raster));
+ }
+
+//---------------------------------------------------------
+// glueItem
+//---------------------------------------------------------
+
+void PartCanvas::glueItem(CItem* item)
+ {
+ NPart* np = (NPart*) item;
+ Track* t = np->track();
+ Part* p = np->part();
+ song->cmdGluePart(t, p);
+ }
+
+//---------------------------------------------------------
+// genItemPopup
+//---------------------------------------------------------
+
+QMenu* PartCanvas::genItemPopup(CItem* item)
+ {
+ NPart* npart = (NPart*) item;
+ Track::TrackType trackType = npart->track()->type();
+
+ QMenu* partPopup = new QMenu(this);
+
+ QAction *act_cut = partPopup->addAction(*editcutIconSet, tr("C&ut"));
+ act_cut->setData(4);
+ act_cut->setShortcut(Qt::CTRL+Qt::Key_X);
+
+ QAction *act_copy = partPopup->addAction(*editcopyIconSet, tr("&Copy"));
+ act_copy->setData(5);
+ act_copy->setShortcut(Qt::CTRL+Qt::Key_C);
+
+ partPopup->addSeparator();
+ int rc = npart->part()->events()->arefCount();
+ QString st = QString(tr("s&elect "));
+ if(rc > 1)
+ st += (QString().setNum(rc) + QString(" "));
+ st += QString(tr("clones"));
+ QAction *act_select = partPopup->addAction(st);
+ act_select->setData(18);
+
+ partPopup->addSeparator();
+ QAction *act_rename = partPopup->addAction(tr("rename"));
+ act_rename->setData(0);
+
+ QMenu* colorPopup = partPopup->addMenu(tr("color"));
+
+ // part color selection
+ //const QFontMetrics& fm = colorPopup->fontMetrics();
+ //int h = fm.lineSpacing();
+
+ for (int i = 0; i < NUM_PARTCOLORS; ++i) {
+ //ColorListItem* item = new ColorListItem(config.partColors[i], h, fontMetrics().height(), partColorNames[i]); //ddskrjo
+ QAction *act_color = colorPopup->addAction(colorRect(config.partColors[i], 80, 80), config.partColorNames[i]);
+ act_color->setData(20+i);
+ }
+
+ QAction *act_delete = partPopup->addAction(QIcon(*deleteIcon), tr("delete")); // ddskrjo added QIcon to all
+ act_delete->setData(1);
+ QAction *act_split = partPopup->addAction(QIcon(*cutIcon), tr("split"));
+ act_split->setData(2);
+ QAction *act_glue = partPopup->addAction(QIcon(*glueIcon), tr("glue"));
+ act_glue->setData(3);
+ QAction *act_declone = partPopup->addAction(tr("de-clone"));
+ act_declone->setData(15);
+
+ partPopup->addSeparator();
+ switch(trackType) {
+ case Track::MIDI: {
+ QAction *act_pianoroll = partPopup->addAction(QIcon(*pianoIconSet), tr("pianoroll"));
+ act_pianoroll->setData(10);
+ QAction *act_mlist = partPopup->addAction(QIcon(*edit_listIcon), tr("list"));
+ act_mlist->setData(12);
+ QAction *act_mexport = partPopup->addAction(tr("export"));
+ act_mexport->setData(16);
+ }
+ break;
+ case Track::DRUM: {
+ QAction *act_dlist = partPopup->addAction(QIcon(*edit_listIcon), tr("list"));
+ act_dlist->setData(12);
+ QAction *act_drums = partPopup->addAction(QIcon(*edit_drummsIcon), tr("drums"));
+ act_drums->setData(13);
+ QAction *act_dexport = partPopup->addAction(tr("export"));
+ act_dexport->setData(16);
+ }
+ break;
+ case Track::WAVE: {
+ QAction *act_wedit = partPopup->addAction(QIcon(*edit_waveIcon), tr("wave edit"));
+ act_wedit->setData(14);
+ QAction *act_wexport = partPopup->addAction(tr("export"));
+ act_wexport->setData(16);
+ QAction *act_wfinfo = partPopup->addAction(tr("file info"));
+ act_wfinfo->setData(17);
+ }
+ break;
+ case Track::AUDIO_OUTPUT:
+ case Track::AUDIO_INPUT:
+ case Track::AUDIO_GROUP:
+ case Track::AUDIO_AUX:
+ case Track::AUDIO_SOFTSYNTH:
+ break;
+ }
+
+ act_select->setEnabled( rc > 1);
+ act_delete->setEnabled( true);
+ act_cut->setEnabled( true);
+ act_declone->setEnabled( rc > 1);
+
+ return partPopup;
+ }
+
+//---------------------------------------------------------
+// itemPopup
+//---------------------------------------------------------
+
+void PartCanvas::itemPopup(CItem* item, int n, const QPoint& pt)
+ {
+ PartList* pl = new PartList;
+ NPart* npart = (NPart*)(item);
+ pl->add(npart->part());
+ switch(n) {
+ case 0: // rename
+ {
+ editPart = npart;
+ QRect r = map(curItem->bbox());
+ if (lineEditor == 0) {
+ lineEditor = new QLineEdit(this);
+ lineEditor->setFrame(true);
+ }
+ lineEditor->setText(editPart->name());
+ lineEditor->setFocus();
+ lineEditor->show();
+ lineEditor->setGeometry(r);
+ editMode = true;
+ }
+ break;
+ case 1: // delete
+ deleteItem(item);
+ break;
+ case 2: // split
+ splitItem(item, pt);
+ break;
+ case 3: // glue
+ glueItem(item);
+ break;
+ case 4:
+ copy(pl);
+ audio->msgRemovePart(npart->part());
+ break;
+ case 5:
+ copy(pl);
+ break;
+ case 10: // pianoroll edit
+ emit startEditor(pl, 0);
+ return;
+ case 12: // list edit
+ emit startEditor(pl, 1);
+ return;
+ case 13: // drum edit
+ emit startEditor(pl, 3);
+ return;
+ case 14: // wave edit
+ {
+ // Changed to allow multiple selected parts to be shown. By T356
+ // Slightly inefficient to add (above), then clear here.
+ // Should really only add npart->part() to pl only if NOT here.
+ // Removed. Added wave editor menu item instead.
+ //pl->clear();
+ //PartList* ptl = npart->track()->parts();
+ //for(ciPart pi = ptl->begin(); pi != ptl->end(); pi++)
+ //{
+ // if(pi->second->selected())
+ // pl->add(pi->second);
+ //}
+ emit startEditor(pl, 4);
+ }
+ return;
+ case 15: // declone
+ {
+ Part* spart = npart->part();
+ Track* track = npart->track();
+ Part* dpart = track->newPart(spart, false);
+ //printf("PartCanvas::itemPopup: #1 spart %s %p next:%s %p prev:%s %p\n", spart->name().toLatin1().constData(), spart, spart->nextClone()->name().toLatin1().constData(), spart->nextClone(), spart->prevClone()->name().toLatin1().constData(), spart->prevClone());
+ //printf("PartCanvas::itemPopup: #1 dpart %s %p next:%s %p prev:%s %p\n", dpart->name().toLatin1().constData(), dpart, dpart->nextClone()->name().toLatin1().constData(), dpart->nextClone(), dpart->prevClone()->name().toLatin1().constData(), dpart->prevClone());
+
+ EventList* se = spart->events();
+ EventList* de = dpart->events();
+ for (iEvent i = se->begin(); i != se->end(); ++i) {
+ Event oldEvent = i->second;
+ Event ev = oldEvent.clone();
+ de->add(ev);
+ }
+ song->startUndo();
+ // Indicate no undo, and do port controller values but not clone parts.
+ //audio->msgChangePart(spart, dpart, false);
+ audio->msgChangePart(spart, dpart, false, true, false);
+ //printf("PartCanvas::itemPopup: #2 spart %s %p next:%s %p prev:%s %p\n", spart->name().toLatin1().constData(), spart, spart->nextClone()->name().toLatin1().constData(), spart->nextClone(), spart->prevClone()->name().toLatin1().constData(), spart->prevClone());
+ //printf("PartCanvas::itemPopup: #2 dpart %s %p next:%s %p prev:%s %p\n", dpart->name().toLatin1().constData(), dpart, dpart->nextClone()->name().toLatin1().constData(), dpart->nextClone(), dpart->prevClone()->name().toLatin1().constData(), dpart->prevClone());
+
+ song->endUndo(SC_PART_MODIFIED);
+ break; // Has to be break here, right?
+ }
+ case 16: // Export to file
+ {
+ const Part* part = item->part();
+ bool popenFlag = false;
+ //QString fn = getSaveFileName(QString(""), part_file_pattern, this, tr("MusE: save part"));
+ QString fn = getSaveFileName(QString(""), part_file_save_pattern, this, tr("MusE: save part"));
+ if (!fn.isEmpty()) {
+ FILE* fp = fileOpen(this, fn, ".mpt", "w", popenFlag, false, false);
+ if (fp) {
+ Xml tmpXml = Xml(fp);
+ //part->write(0, tmpXml);
+ // Write the part. Indicate that it's a copy operation - to add special markers,
+ // and force full wave paths.
+ part->write(0, tmpXml, true, true);
+ fclose(fp);
+ }
+ }
+ break;
+ }
+
+ case 17: // File info
+ {
+ Part* p = item->part();
+ EventList* el = p->events();
+ QString str = tr("Part name") + ": " + p->name() + "\n" + tr("Files") + ":";
+ for (iEvent e = el->begin(); e != el->end(); ++e)
+ {
+ Event event = e->second;
+ SndFileR f = event.sndFile();
+ if (f.isNull())
+ continue;
+ //str.append("\n" + f.path());
+ str.append(QString("\n@") + QString().setNum(event.tick()) + QString(" len:") +
+ QString().setNum(event.lenTick()) + QString(" ") + f.path());
+ }
+ QMessageBox::information(this, "File info", str, "Ok", 0);
+ break;
+ }
+ case 18: // Select clones
+ {
+ Part* part = item->part();
+
+ // Traverse and process the clone chain ring until we arrive at the same part again.
+ // The loop is a safety net.
+ Part* p = part;
+ int j = part->cevents()->arefCount();
+ if(j > 0)
+ {
+ for(int i = 0; i < j; ++i)
+ {
+ //printf("PartCanvas::itemPopup i:%d %s %p events %p refs:%d arefs:%d\n", i, p->name().toLatin1().constData(), p, part->cevents(), part->cevents()->refCount(), j);
+
+ p->setSelected(true);
+ p = p->nextClone();
+ if(p == part)
+ break;
+ }
+ //song->update();
+ song->update(SC_SELECTION);
+ }
+
+ break;
+ }
+ case 20 ... NUM_PARTCOLORS+20:
+ {
+ curColorIndex = n - 20;
+ bool selfound = false;
+ //Loop through all parts and set color on selected:
+ for (iCItem i = items.begin(); i != items.end(); i++) {
+ if (i->second->isSelected()) {
+ selfound = true;
+ i->second->part()->setColorIndex(curColorIndex);
+ }
+ }
+
+ // If no items selected, use the one clicked on.
+ if(!selfound)
+ item->part()->setColorIndex(curColorIndex);
+
+ redraw();
+ break;
+ }
+ default:
+ printf("unknown action %d\n", n);
+ break;
+ }
+ delete pl;
+ }
+
+//---------------------------------------------------------
+// viewMousePressEvent
+//---------------------------------------------------------
+
+void PartCanvas::mousePress(QMouseEvent* event)
+ {
+ if (event->modifiers() & Qt::ShiftModifier) {
+ return;
+ }
+ QPoint pt = event->pos();
+ CItem* item = items.find(pt);
+ if (item == 0)
+ return;
+ switch (_tool) {
+ default:
+ emit trackChanged(item->part()->track());
+ break;
+ case CutTool:
+ splitItem(item, pt);
+ break;
+ case GlueTool:
+ glueItem(item);
+ break;
+ case MuteTool:
+ {
+ NPart* np = (NPart*) item;
+ Part* p = np->part();
+ p->setMute(!p->mute());
+ redraw();
+ break;
+ }
+ }
+ }
+
+//---------------------------------------------------------
+// viewMouseReleaseEvent
+//---------------------------------------------------------
+
+void PartCanvas::mouseRelease(const QPoint&)
+ {
+ }
+
+//---------------------------------------------------------
+// viewMouseMoveEvent
+//---------------------------------------------------------
+
+void PartCanvas::mouseMove(const QPoint& pos)
+ {
+ int x = pos.x();
+ if (x < 0)
+ x = 0;
+ emit timeChanged(AL::sigmap.raster(x, *_raster));
+ }
+
+//---------------------------------------------------------
+// y2Track
+//---------------------------------------------------------
+
+Track* PartCanvas::y2Track(int y) const
+ {
+ TrackList* l = song->tracks();
+ int ty = 0;
+ for (iTrack it = l->begin(); it != l->end(); ++it) {
+ int h = (*it)->height();
+ if (y >= ty && y < ty + h)
+ return *it;
+ ty += h;
+ }
+ return 0;
+ }
+
+//---------------------------------------------------------
+// keyPress
+//---------------------------------------------------------
+
+void PartCanvas::keyPress(QKeyEvent* event)
+ {
+ int key = event->key();
+ if (editMode)
+ {
+ if ( key == Qt::Key_Return || key == Qt::Key_Enter )
+ {
+ returnPressed();
+ return;
+ }
+ else if ( key == Qt::Key_Escape )
+ {
+ lineEditor->hide();
+ editMode = false;
+ return;
+ }
+ }
+
+ if (event->modifiers() & Qt::ShiftModifier)
+ key += Qt::SHIFT;
+ if (event->modifiers() & Qt::AltModifier)
+ key += Qt::ALT;
+ if (event->modifiers() & Qt::ControlModifier)
+ key += Qt::CTRL;
+
+ if (key == shortcuts[SHRT_DELETE].key) {
+ if (getCurrentDrag()) {
+ //printf("dragging!!\n");
+ return;
+ }
+
+ song->startUndo();
+ song->msgRemoveParts();
+ song->endUndo(SC_PART_REMOVED);
+ return;
+ }
+ else if (key == shortcuts[SHRT_POS_DEC].key) {
+ int spos = pos[0];
+ if(spos > 0)
+ {
+ spos -= 1; // Nudge by -1, then snap down with raster1.
+ spos = AL::sigmap.raster1(spos, *_raster);
+ }
+ if(spos < 0)
+ spos = 0;
+ Pos p(spos,true);
+ song->setPos(0, p, true, true, true);
+ return;
+ }
+ else if (key == shortcuts[SHRT_POS_INC].key) {
+ int spos = AL::sigmap.raster2(pos[0] + 1, *_raster); // Nudge by +1, then snap up with raster2.
+ Pos p(spos,true);
+ song->setPos(0, p, true, true, true);
+ return;
+ }
+ else if (key == shortcuts[SHRT_POS_DEC_NOSNAP].key) {
+ int spos = pos[0] - AL::sigmap.rasterStep(pos[0], *_raster);
+ if(spos < 0)
+ spos = 0;
+ Pos p(spos,true);
+ song->setPos(0, p, true, true, true);
+ return;
+ }
+ else if (key == shortcuts[SHRT_POS_INC_NOSNAP].key) {
+ Pos p(pos[0] + AL::sigmap.rasterStep(pos[0], *_raster), true);
+ song->setPos(0, p, true, true, true);
+ return;
+ }
+ else if (key == shortcuts[SHRT_TOOL_POINTER].key) {
+ emit setUsedTool(PointerTool);
+ return;
+ }
+ else if (key == shortcuts[SHRT_TOOL_PENCIL].key) {
+ emit setUsedTool(PencilTool);
+ return;
+ }
+ else if (key == shortcuts[SHRT_TOOL_RUBBER].key) {
+ emit setUsedTool(RubberTool);
+ return;
+ }
+ else if (key == shortcuts[SHRT_TOOL_SCISSORS].key) {
+ emit setUsedTool(CutTool);
+ return;
+ }
+ else if (key == shortcuts[SHRT_TOOL_GLUE].key) {
+ emit setUsedTool(GlueTool);
+ return;
+ }
+ else if (key == shortcuts[SHRT_TOOL_MUTE].key) {
+ emit setUsedTool(MuteTool);
+ return;
+ }
+ else if (key == shortcuts[SHRT_SEL_TRACK_ABOVE].key) {
+ emit selectTrackAbove();
+ return;
+ }
+ else if (key == shortcuts[SHRT_SEL_TRACK_BELOW].key) {
+ emit selectTrackBelow();
+ return;
+ }
+
+ //
+ // Shortcuts that require selected parts from here
+ //
+ if (!curItem) {
+ if (items.size()==0) {
+ event->ignore(); // give global accelerators a chance
+ return;
+ }
+ for (iCItem i = items.begin(); i != items.end(); ++i) {
+ NPart* part = (NPart*)(i->second);
+ if (part->isSelected()) {
+ curItem=part;
+ break;
+ }
+ }
+ if (!curItem)
+ curItem = (NPart*)items.begin()->second; // just grab the first part
+ }
+
+ CItem* newItem = 0;
+ bool singleSelection = isSingleSelection();
+ bool add = false;
+ //Locators to selection
+ if (key == shortcuts[SHRT_LOCATORS_TO_SELECTION].key) {
+ CItem *leftmost = 0, *rightmost = 0;
+ for (iCItem i = items.begin(); i != items.end(); i++) {
+ if (i->second->isSelected()) {
+ // Check leftmost:
+ if (!leftmost)
+ leftmost = i->second;
+ else
+ if (leftmost->x() > i->second->x())
+ leftmost = i->second;
+
+ // Check rightmost:
+ if (!rightmost)
+ rightmost = i->second;
+ else
+ if (rightmost->x() < i->second->x())
+ rightmost = i->second;
+ }
+ }
+
+ int left_tick = leftmost->part()->tick();
+ int right_tick = rightmost->part()->tick() + rightmost->part()->lenTick();
+ Pos p1(left_tick, true);
+ Pos p2(right_tick, true);
+ song->setPos(1, p1);
+ song->setPos(2, p2);
+ return;
+ }
+
+ // Select part to the right
+ else if (key == shortcuts[SHRT_SEL_RIGHT].key || key == shortcuts[SHRT_SEL_RIGHT_ADD].key) {
+ if (key == shortcuts[SHRT_SEL_RIGHT_ADD].key)
+ add = true;
+
+ Part* part = curItem->part();
+ Track* track = part->track();
+ unsigned int tick = part->tick();
+ bool afterthis = false;
+ for (iCItem i = items.begin(); i != items.end(); ++i) {
+ NPart* npart = (NPart*)(i->second);
+ Part* ipart = npart->part();
+ if (ipart->track() != track)
+ continue;
+ if (ipart->tick() < tick)
+ continue;
+ if (ipart == part)
+ {
+ afterthis = true;
+ continue;
+ }
+ if(afterthis)
+ {
+ newItem = i->second;
+ break;
+ }
+ }
+ }
+ // Select part to the left
+ else if (key == shortcuts[SHRT_SEL_LEFT].key || key == shortcuts[SHRT_SEL_LEFT_ADD].key) {
+ if (key == shortcuts[SHRT_SEL_LEFT_ADD].key)
+ add = true;
+
+ Part* part = curItem->part();
+ Track* track = part->track();
+ unsigned int tick = part->tick();
+
+ for (iCItem i = items.begin(); i != items.end(); ++i) {
+ NPart* npart = (NPart*)(i->second);
+ Part* ipart = npart->part();
+
+ if (ipart->track() != track)
+ continue;
+ if (ipart->tick() > tick)
+ continue;
+ if (ipart == part)
+ break;
+ newItem = i->second;
+ }
+ }
+
+ // Select nearest part on track above
+ else if (key == shortcuts[SHRT_SEL_ABOVE].key || key == shortcuts[SHRT_SEL_ABOVE_ADD].key) {
+ if (key == shortcuts[SHRT_SEL_ABOVE_ADD].key)
+ add = true;
+ //To get an idea of which track is above us:
+ int stepsize = rmapxDev(1);
+ Track* track = curItem->part()->track();//top->part()->track();
+ track = y2Track(track->y() - 1);
+
+ //If we're at topmost, leave
+ if (!track) {
+ printf("no track above!\n");
+ return;
+ }
+ int middle = curItem->x() + curItem->part()->lenTick()/2;
+ CItem *aboveL = 0, *aboveR = 0;
+ //Upper limit: song end, lower limit: song start
+ int ulimit = song->len();
+ int llimit = 0;
+
+ while (newItem == 0) {
+ int y = track->y() + 2;
+ int xoffset = 0;
+ int xleft = middle - xoffset;
+ int xright = middle + xoffset;
+ while ((xleft > llimit || xright < ulimit) && (aboveL == 0) && (aboveR == 0)) {
+ xoffset += stepsize;
+ xleft = middle - xoffset;
+ xright = middle + xoffset;
+ if (xleft >= 0)
+ aboveL = items.find(QPoint(xleft,y));
+ if (xright <= ulimit)
+ aboveR = items.find(QPoint(xright,y));
+ }
+
+ if ((aboveL || aboveR) != 0) { //We've hit something
+ CItem* above = 0;
+ above = (aboveL !=0) ? aboveL : aboveR;
+ newItem = above;
+ }
+ else { //We didn't hit anything. Move to track above, if there is one
+ track = y2Track(track->y() - 1);
+ if (track == 0)
+ return;
+ }
+ }
+ emit trackChanged(track);
+ }
+ // Select nearest part on track below
+ else if (key == shortcuts[SHRT_SEL_BELOW].key || key == shortcuts[SHRT_SEL_BELOW_ADD].key) {
+ if (key == shortcuts[SHRT_SEL_BELOW_ADD].key)
+ add = true;
+
+ //To get an idea of which track is below us:
+ int stepsize = rmapxDev(1);
+ Track* track = curItem->part()->track();//bottom->part()->track();
+ track = y2Track(track->y() + track->height() + 1 );
+ int middle = curItem->x() + curItem->part()->lenTick()/2;
+ //If we're at bottommost, leave
+ if (!track)
+ return;
+
+ CItem *belowL = 0, *belowR = 0;
+ //Upper limit: song end , lower limit: song start
+ int ulimit = song->len();
+ int llimit = 0;
+ while (newItem == 0) {
+ int y = track->y() + 1;
+ int xoffset = 0;
+ int xleft = middle - xoffset;
+ int xright = middle + xoffset;
+ while ((xleft > llimit || xright < ulimit) && (belowL == 0) && (belowR == 0)) {
+ xoffset += stepsize;
+ xleft = middle - xoffset;
+ xright = middle + xoffset;
+ if (xleft >= 0)
+ belowL = items.find(QPoint(xleft,y));
+ if (xright <= ulimit)
+ belowR = items.find(QPoint(xright,y));
+ }
+
+ if ((belowL || belowR) != 0) { //We've hit something
+ CItem* below = 0;
+ below = (belowL !=0) ? belowL : belowR;
+ newItem = below;
+ }
+ else {
+ //Get next track below, or abort if this is the lowest
+ track = y2Track(track->y() + track->height() + 1 );
+ if (track == 0)
+ return;
+ }
+ }
+ emit trackChanged(track);
+ }
+ else if (key == shortcuts[SHRT_EDIT_PART].key && curItem) { //This should be the other way around - singleSelection first.
+ if (!singleSelection) {
+ event->ignore();
+ return;
+ }
+ PartList* pl = new PartList;
+ NPart* npart = (NPart*)(curItem);
+ Track* track = npart->part()->track();
+ pl->add(npart->part());
+ int type = 0;
+
+ // Check if track is wave or drum,
+ // else track is midi
+
+ switch (track->type()) {
+ case Track::DRUM:
+ type = 3;
+ break;
+
+ case Track::WAVE:
+ type = 4;
+ break;
+
+ case Track::MIDI:
+ case Track::AUDIO_OUTPUT:
+ case Track::AUDIO_INPUT:
+ case Track::AUDIO_GROUP:
+ case Track::AUDIO_AUX:
+ case Track::AUDIO_SOFTSYNTH: //TODO
+ break;
+ }
+ emit startEditor(pl, type);
+ }
+ else {
+ event->ignore(); // give global accelerators a chance
+ return;
+ }
+
+
+ // Check if anything happened to the selected parts
+ if (newItem) {
+ //If this is a single selection, toggle previous item
+ if (singleSelection && !add)
+ selectItem(curItem, false);
+ else if(!add)
+ deselectAll();
+
+ curItem = newItem;
+ selectItem(newItem, true);
+
+ //Check if we've hit the upper or lower boundaries of the window. If so, set a new position
+ if (newItem->x() < mapxDev(0)) {
+ int curpos = pos[0];
+ setPos(0,newItem->x(),true);
+ setPos(0,curpos,false); //Dummy to put the current position back once we've scrolled
+ }
+ else if (newItem->x() > mapxDev(width())) {
+ int curpos = pos[0];
+ setPos(0,newItem->x(),true);
+ setPos(0,curpos,false); //Dummy to put the current position back once we've scrolled
+ }
+ redraw();
+ }
+ }
+
+//---------------------------------------------------------
+// drawPart
+// draws a part
+//---------------------------------------------------------
+
+void PartCanvas::drawItem(QPainter& p, const CItem* item, const QRect& rect)
+ {
+ int from = rect.x();
+ int to = from + rect.width();
+
+ //printf("from %d to %d\n", from,to);
+ Part* part = ((NPart*)item)->part();
+ int pTick = part->tick();
+ from -= pTick;
+ to -= pTick;
+ if(from < 0)
+ from = 0;
+ if((unsigned int)to > part->lenTick())
+ to = part->lenTick();
+
+ // Item bounding box x is in tick coordinates, same as rectangle.
+ if(item->bbox().intersect(rect).isNull())
+ {
+ //printf("PartCanvas::drawItem rectangle is null\n");
+ return;
+ }
+
+ QRect r = item->bbox();
+
+ //printf("PartCanvas::drawItem %s evRefs:%d pTick:%d pLen:%d\nbb.x:%d bb.y:%d bb.w:%d bb.h:%d\n"
+ // "rect.x:%d rect.y:%d rect.w:%d rect.h:%d\nr.x:%d r.y:%d r.w:%d r.h:%d\n",
+ // part->name().toLatin1().constData(), part->events()->arefCount(), pTick, part->lenTick(),
+ // bb.x(), bb.y(), bb.width(), bb.height(),
+ // rect.x(), rect.y(), rect.width(), rect.height(),
+ // r.x(), r.y(), r.width(), r.height());
+
+ int i = part->colorIndex();
+ p.setPen(Qt::black);
+ if (part->mute()) {
+ QColor c(Qt::white);
+ c.setAlpha(config.globalAlphaBlend);
+ p.setBrush(c);
+
+ // NOTE: For one-pixel border use first line For two-pixel border use second.
+ p.drawRect(QRect(r.x(), r.y()-1, r.width(), r.height()));
+ //p.drawRect(r);
+
+ return;
+ }
+ if (item->isMoving()) {
+ QColor c(Qt::gray);
+ c.setAlpha(config.globalAlphaBlend);
+ p.setBrush(c);
+
+ // NOTE: For one-pixel border use first line. For two-pixel border use second.
+ p.drawRect(QRect(r.x(), r.y()-1, r.width(), r.height()));
+ //p.drawRect(r);
+
+ }
+ //else if (part->mute())
+ // return;
+ else if (part->selected()) {
+ bool clone = part->events()->arefCount() > 1;
+
+ // NOTE: For one-pixel border use first line and don't bother with setCosmetic.
+ // For a two-pixel border use second line and MUST use setCosmetic! Tim.
+ //p.setPen(QPen(config.partColors[i], 0, clone ? Qt::DashLine : Qt::SolidLine));
+ QPen pen(config.partColors[i], 2, clone ? Qt::DashLine : Qt::SolidLine);
+ pen.setCosmetic(true);
+
+ p.setPen(pen);
+ // Hm, put some kind of lower limit? If so do that globally to the adjustment.
+ QColor c(Qt::black);
+ c.setAlpha(config.globalAlphaBlend);
+ p.setBrush(c);
+ p.drawRect(r);
+ }
+ else {
+ bool clone = part->events()->arefCount() > 1;
+
+ // NOTE: Pixel width: See above note.
+ //p.setPen(QPen(Qt::black, 0, clone ? Qt::DashLine : Qt::SolidLine));
+ QPen pen(Qt::black, 2, clone ? Qt::DashLine : Qt::SolidLine);
+ pen.setCosmetic(true);
+
+ p.setPen(pen);
+ QColor c(config.partColors[i]);
+ c.setAlpha(config.globalAlphaBlend);
+ p.setBrush(c);
+
+ p.drawRect(r);
+ }
+
+ MidiPart* mp = 0;
+ WavePart* wp = 0;
+ Track::TrackType type = part->track()->type();
+ if (type == Track::WAVE) {
+ wp =(WavePart*)part;
+ }
+ else {
+ mp = (MidiPart*)part;
+ }
+
+ if (config.canvasShowPartType & 2) { // show events
+ if (mp)
+ {
+ // Do not allow this, causes segfault.
+ if(from <= to)
+ {
+ p.setPen(Qt::darkGray);
+ EventList* events = mp->events();
+ iEvent ito(events->lower_bound(to));
+
+ for (iEvent i = events->lower_bound(from); i != ito; ++i) {
+ EventType type = i->second.type();
+ if (
+ ((config.canvasShowPartEvent & 1) && (type == Note))
+ || ((config.canvasShowPartEvent & 2) && (type == PAfter))
+ || ((config.canvasShowPartEvent & 4) && (type == Controller))
+ || ((config.canvasShowPartEvent &16) && (type == CAfter))
+ || ((config.canvasShowPartEvent &64) && (type == Sysex || type == Meta))
+ ) {
+ int t = i->first + pTick;
+ int th = part->track()->height();
+ if(t >= r.left() && t <= r.right())
+ p.drawLine(t, r.y()+2, t, r.y()+th-4);
+ }
+ }
+ }
+ }
+ else if (wp)
+ drawWavePart(p, rect, wp, r);
+ }
+
+ else { // show Cakewalk Style
+ if (mp) {
+ p.setPen(Qt::darkGray);
+ EventList* events = mp->events();
+ iEvent ito(events->lower_bound(to));
+ //printf("PartCanvas::drawItem pTick:%d from:%d to:%d part len:%d\n", pTick, from, to, part->lenTick());
+
+ for (iEvent i = events->begin(); i != ito; ++i) {
+ int t = i->first + pTick;
+ int te = t + i->second.lenTick();
+
+ if (t > (to + pTick))
+ {
+ printf("PartCanvas::drawItem t:%d > to:%d + pTick:%d i->first:%d\n", t, to, pTick, i->first);
+
+ break;
+ }
+
+ if (te < (from + pTick))
+ continue;
+
+ if (te > (to + pTick))
+ te = to + pTick;
+
+ EventType type = i->second.type();
+ if (type == Note) {
+ int pitch = i->second.pitch();
+ int th = int(part->track()->height() * 0.75); // only draw on three quarters
+ int hoffset = (part->track()->height() - th ) / 2; // offset from bottom
+ int y = hoffset + (r.y() + th - (pitch * (th) / 127));
+ p.drawLine(t, y, te, y);
+ }
+ }
+ }
+ else if (wp)
+ drawWavePart(p, rect, wp, r);
+ }
+ if (config.canvasShowPartType & 1) { // show names
+ // draw name
+ // FN: Set text color depending on part color (black / white)
+ int part_r, part_g, part_b, brightness;
+ config.partColors[i].getRgb(&part_r, &part_g, &part_b);
+ brightness = part_r*29 + part_g*59 + part_b*12;
+ if (brightness < 12000 || part->selected())
+ p.setPen(Qt::white); /* too dark: use white for text color */
+ else
+ p.setPen(Qt::black); /* otherwise use black */
+ QRect rr = map(r);
+ rr.setX(rr.x() + 3);
+ p.save();
+ p.setFont(config.fonts[1]);
+ p.setWorldMatrixEnabled(false);
+ p.drawText(rr, Qt::AlignVCenter|Qt::AlignLeft, part->name());
+ p.restore();
+ }
+ }
+
+//---------------------------------------------------------
+// drawMoving
+// draws moving items
+//---------------------------------------------------------
+
+void PartCanvas::drawMoving(QPainter& p, const CItem* item, const QRect&)
+ {
+ //if(!item->isMoving())
+ // return;
+ p.setPen( Qt::black);
+
+ //p.setBrush( Qt::NoBrush);
+ //QColor c(Qt::gray);
+ Part* part = ((NPart*)item)->part();
+ QColor c(config.partColors[part->colorIndex()]);
+
+ ///c.setAlpha(config.globalAlphaBlend);
+ c.setAlpha(128); // Fix this regardless of global setting. Should be OK.
+
+ p.setBrush(c);
+
+ // NOTE: For one-pixel border use second line. For two-pixel border use first.
+ //p.drawRect(item->mp().x(), item->mp().y()+1, item->width(), item->height());
+ p.drawRect(item->mp().x(), item->mp().y(), item->width(), item->height());
+ }
+
+//---------------------------------------------------------
+// drawWavePart
+// bb - bounding box of paint area
+// pr - part rectangle
+//---------------------------------------------------------
+
+void PartCanvas::drawWavePart(QPainter& p,
+ const QRect& bb, WavePart* wp, const QRect& _pr)
+ {
+ //printf("PartCanvas::drawWavePart bb.x:%d bb.y:%d bb.w:%d bb.h:%d pr.x:%d pr.y:%d pr.w:%d pr.h:%d\n",
+ // bb.x(), bb.y(), bb.width(), bb.height(), _pr.x(), _pr.y(), _pr.width(), _pr.height());
+
+ QRect rr = p.worldMatrix().mapRect(bb);
+ QRect pr = p.worldMatrix().mapRect(_pr);
+
+ p.save();
+ p.resetTransform();
+
+ int x2 = 1;
+ int x1 = rr.x() > pr.x() ? rr.x() : pr.x();
+ x2 += rr.right() < pr.right() ? rr.right() : pr.right();
+
+ if (x1 < 0)
+ x1 = 0;
+ if (x2 > width())
+ x2 = width();
+ int hh = pr.height();
+ int h = hh/2;
+ int y = pr.y() + h;
+
+ EventList* el = wp->events();
+ for (iEvent e = el->begin(); e != el->end(); ++e) {
+ int cc = hh % 2 ? 0 : 1;
+ Event event = e->second;
+ SndFileR f = event.sndFile();
+ if (f.isNull())
+ continue;
+ unsigned channels = f.channels();
+ if (channels == 0) {
+ printf("drawWavePart: channels==0! %s\n", f.name().toLatin1().constData());
+ continue;
+ }
+
+ int xScale;
+ int pos;
+ int tickstep = rmapxDev(1);
+ int postick = tempomap.frame2tick(wp->frame() + event.frame());
+ int eventx = mapx(postick);
+ int drawoffset;
+ if((x1 - eventx) < 0)
+ drawoffset = 0;
+ else
+ drawoffset = rmapxDev(x1 - eventx);
+ postick += drawoffset;
+ pos = event.spos() + tempomap.tick2frame(postick) - wp->frame() - event.frame();
+
+ int i;
+ if(x1 < eventx)
+ i = eventx;
+ else
+ i = x1;
+ int ex = mapx(tempomap.frame2tick(wp->frame() + event.frame() + event.lenFrame()));
+ if(ex > x2)
+ ex = x2;
+ if (h < 20) {
+ //
+ // combine multi channels into one waveform
+ //
+ //printf("PartCanvas::drawWavePart i:%d ex:%d\n", i, ex); // REMOVE Tim.
+
+ for (; i < ex; i++) {
+ SampleV sa[channels];
+ xScale = tempomap.deltaTick2frame(postick, postick + tickstep);
+ f.read(sa, xScale, pos);
+ postick += tickstep;
+ pos += xScale;
+ int peak = 0;
+ int rms = 0;
+ for (unsigned k = 0; k < channels; ++k) {
+ if (sa[k].peak > peak)
+ peak = sa[k].peak;
+ rms += sa[k].rms;
+ }
+ rms /= channels;
+ peak = (peak * (hh-2)) >> 9;
+ rms = (rms * (hh-2)) >> 9;
+ p.setPen(QColor(Qt::darkGray));
+ p.drawLine(i, y - peak - cc, i, y + peak);
+ p.setPen(QColor(Qt::black));
+ p.drawLine(i, y - rms - cc, i, y + rms);
+ }
+ }
+ else {
+ //
+ // multi channel display
+ //
+ int hm = hh / (channels * 2);
+ int cc = hh % (channels * 2) ? 0 : 1;
+ for (; i < ex; i++) {
+ y = pr.y() + hm;
+ SampleV sa[channels];
+ xScale = tempomap.deltaTick2frame(postick, postick + tickstep);
+ f.read(sa, xScale, pos);
+ postick += tickstep;
+ pos += xScale;
+ for (unsigned k = 0; k < channels; ++k) {
+ int peak = (sa[k].peak * (hm - 1)) >> 8;
+ int rms = (sa[k].rms * (hm - 1)) >> 8;
+ p.setPen(QColor(Qt::darkGray));
+ p.drawLine(i, y - peak - cc, i, y + peak);
+ p.setPen(QColor(Qt::black));
+ p.drawLine(i, y - rms - cc, i, y + rms);
+
+ y += 2 * hm;
+ }
+ }
+ }
+ }
+ p.restore();
+ }
+//---------------------------------------------------------
+// cmd
+//---------------------------------------------------------
+
+void PartCanvas::cmd(int cmd)
+ {
+ PartList pl;
+ for (iCItem i = items.begin(); i != items.end(); ++i) {
+ if (!i->second->isSelected())
+ continue;
+ NPart* npart = (NPart*)(i->second);
+ pl.add(npart->part());
+ }
+ switch (cmd) {
+ case CMD_CUT_PART:
+ copy(&pl);
+ song->startUndo();
+
+ bool loop;
+ do
+ {
+ loop = false;
+ for (iCItem i = items.begin(); i != items.end(); ++i) {
+ if (!i->second->isSelected())
+ continue;
+ NPart* p = (NPart*)(i->second);
+ Part* part = p->part();
+ audio->msgRemovePart(part);
+
+ loop = true;
+ break;
+ }
+ } while (loop);
+ song->endUndo(SC_PART_REMOVED);
+ break;
+ case CMD_COPY_PART:
+ copy(&pl);
+ break;
+ case CMD_PASTE_PART:
+ paste(false, false);
+ break;
+ case CMD_PASTE_CLONE_PART:
+ paste(true, false);
+ break;
+ case CMD_PASTE_PART_TO_TRACK:
+ paste();
+ break;
+ case CMD_PASTE_CLONE_PART_TO_TRACK:
+ paste(true);
+ break;
+ case CMD_INSERT_PART:
+ paste(false, false, true);
+ break;
+ case CMD_INSERT_EMPTYMEAS:
+ song->startUndo();
+ int startPos=song->vcpos();
+ int oneMeas=AL::sigmap.ticksMeasure(startPos);
+ movePartsTotheRight(startPos,oneMeas);
+ song->endUndo(SC_PART_INSERTED);
+ break;
+ }
+ }
+
+//---------------------------------------------------------
+// copy
+// cut copy paste
+//---------------------------------------------------------
+
+void PartCanvas::copy(PartList* pl)
+ {
+ //printf("void PartCanvas::copy(PartList* pl)\n");
+ if (pl->empty())
+ return;
+ // Changed by T356. Support mixed .mpt files.
+ //bool isWave = pl->begin()->second->track()->type() == Track::WAVE;
+ bool wave = false;
+ bool midi = false;
+ for(ciPart p = pl->begin(); p != pl->end(); ++p)
+ {
+ if(p->second->track()->isMidiTrack())
+ midi = true;
+ else
+ if(p->second->track()->type() == Track::WAVE)
+ wave = true;
+ if(midi && wave)
+ break;
+ }
+ if(!(midi || wave))
+ return;
+
+ //---------------------------------------------------
+ // write parts as XML into tmp file
+ //---------------------------------------------------
+
+ FILE* tmp = tmpfile();
+ if (tmp == 0) {
+ fprintf(stderr, "PartCanvas::copy() fopen failed: %s\n",
+ strerror(errno));
+ return;
+ }
+ Xml xml(tmp);
+
+ // Clear the copy clone list.
+ cloneList.clear();
+ //copyCloneList.clear();
+
+ int level = 0;
+ int tick = 0;
+ for (ciPart p = pl->begin(); p != pl->end(); ++p) {
+ // Indicate this is a copy operation. Also force full wave paths.
+ //p->second->write(level, xml);
+ p->second->write(level, xml, true, true);
+
+ int endTick = p->second->endTick();
+ if (endTick > tick)
+ tick = endTick;
+ }
+ Pos p(tick, true);
+ song->setPos(0, p);
+
+ //---------------------------------------------------
+ // read tmp file into QTextDrag Object
+ //---------------------------------------------------
+
+ fflush(tmp);
+ struct stat f_stat;
+ if (fstat(fileno(tmp), &f_stat) == -1) {
+ fprintf(stderr, "PartCanvas::copy() fstat failed:<%s>\n",
+ strerror(errno));
+ fclose(tmp);
+ return;
+ }
+ int n = f_stat.st_size;
+ char* fbuf = (char*)mmap(0, n+1, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE, fileno(tmp), 0);
+ fbuf[n] = 0;
+
+ QByteArray data(fbuf);
+ QMimeData* md = new QMimeData();
+
+
+ if(midi && wave)
+ md->setData("text/x-muse-mixedpartlist", data); // By T356. Support mixed .mpt files.
+ else
+ if(midi)
+ md->setData("text/x-muse-midipartlist", data);
+ else
+ if(wave)
+ md->setData("text/x-muse-wavepartlist", data);
+
+ QApplication::clipboard()->setMimeData(md, QClipboard::Clipboard);
+
+ munmap(fbuf, n);
+ fclose(tmp);
+ }
+
+//---------------------------------------------------------
+// pasteAt
+//---------------------------------------------------------
+
+int PartCanvas::pasteAt(const QString& pt, Track* track, unsigned int pos, bool clone, bool toTrack)
+ {
+ //printf("int PartCanvas::pasteAt(const QString& pt, Track* track, int pos)\n");
+ QByteArray ba = pt.toLatin1();
+ const char* ptxt = ba.constData();
+ Xml xml(ptxt);
+ bool firstPart=true;
+ int posOffset=0;
+ //int finalPos=0;
+ unsigned int finalPos = pos;
+ int notDone = 0;
+ int done = 0;
+ bool end = false;
+
+ //song->startUndo();
+ 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;
+ if(clone)
+ {
+ if(!(p = readClone(xml, track, toTrack)))
+ break;
+ }
+ else
+ {
+ if (track->type() == Track::MIDI || track->type() == Track::DRUM)
+ p = new MidiPart((MidiTrack*)track);
+ else if (track->type() == Track::WAVE)
+ p = new WavePart((WaveTrack*)track);
+ else
+ break;
+ p->read(xml, 0, toTrack);
+ }
+ */
+
+ // Read the part.
+ Part* p = 0;
+ p = readXmlPart(xml, track, clone, toTrack);
+ // If it could not be created...
+ if(!p)
+ {
+ // Increment the number of parts not done and break.
+ ++notDone;
+ break;
+ }
+
+ // Increment the number of parts done.
+ ++done;
+
+ if (firstPart) {
+ firstPart=false;
+ posOffset=pos-p->tick();
+ }
+ p->setTick(p->tick()+posOffset);
+ if (p->tick()+p->lenTick()>finalPos) {
+ finalPos=p->tick()+p->lenTick();
+ }
+ //pos += p->lenTick();
+ audio->msgAddPart(p,false);
+ }
+ else
+ xml.unknown("PartCanvas::pasteAt");
+ break;
+ case Xml::TagEnd:
+ break;
+ default:
+ end = true;
+ break;
+ }
+ if(end)
+ break;
+ }
+
+ //song->endUndo(SC_PART_INSERTED);
+ //return pos;
+
+ if(notDone)
+ {
+ int tot = notDone + done;
+ QMessageBox::critical(this, QString("MusE"),
+ QString().setNum(notDone) + (tot > 1 ? (tr(" out of ") + QString().setNum(tot)) : QString("")) +
+ (tot > 1 ? tr(" parts") : tr(" part")) +
+ tr(" could not be pasted.\nLikely the selected track is the wrong type."));
+ }
+
+ return finalPos;
+ }
+
+/*
+//---------------------------------------------------------
+// PartCanvas::readPart
+//---------------------------------------------------------
+
+Part* PartCanvas::readPart(Xml& xml, Track* track, bool doClone, bool toTrack)
+ {
+ int id = -1;
+ Part* npart = 0;
+ uuid_t uuid;
+ uuid_clear(uuid);
+ bool uuidvalid = false;
+ bool clone = true;
+
+ for (;;) {
+ Xml::Token token = xml.parse();
+ const QString& tag = xml.s1();
+ switch (token) {
+ case Xml::Error:
+ case Xml::End:
+ return npart;
+ case Xml::TagStart:
+ // If the part has not been created yet...
+ if(!npart)
+ {
+ // Attribute section did not create a clone from any matching part. Create a non-clone part now.
+ if(!track)
+ {
+ xml.skip("part");
+ return 0;
+ }
+ if (track->type() == Track::MIDI || track->type() == Track::DRUM)
+ npart = new MidiPart((MidiTrack*)track);
+ else if (track->type() == Track::WAVE)
+ npart = new WavePart((WaveTrack*)track);
+ else
+ {
+ xml.skip("part");
+ return 0;
+ }
+
+ // Signify a new non-clone part was created.
+ // Even if the original part was itself a clone, clear this because the
+ // attribute section did not create a clone from any matching part.
+ clone = false;
+
+ // If an id or uuid was found, add the part to the clone list
+ // so that subsequent parts can look it up and clone from it...
+ if(id != -1)
+ {
+ ClonePart ncp(npart, id);
+ cloneList.push_back(ncp);
+ }
+ else
+ if(uuidvalid)
+ {
+ ClonePart ncp(npart);
+ // New ClonePart creates its own uuid, but we need to replace it.
+ uuid_copy(ncp.uuid, uuid);
+ cloneList.push_back(ncp);
+ }
+ }
+
+ if (tag == "name")
+ npart->setName(xml.parse1());
+ else if (tag == "poslen") {
+ ((PosLen*)npart)->read(xml, "poslen");
+ }
+ else if (tag == "pos") {
+ Pos pos;
+ pos.read(xml, "pos"); // obsolete
+ npart->setTick(pos.tick());
+ }
+ else if (tag == "len") {
+ Pos len;
+ len.read(xml, "len"); // obsolete
+ npart->setLenTick(len.tick());
+ }
+ else if (tag == "selected")
+ npart->setSelected(xml.parseInt());
+ else if (tag == "color")
+ npart->setColorIndex(xml.parseInt());
+ else if (tag == "mute")
+ npart->setMute(xml.parseInt());
+ else if (tag == "event")
+ {
+ // If a new non-clone part was created, accept the events...
+ if(!clone)
+ {
+ EventType type = Wave;
+ if(track->isMidiTrack())
+ type = Note;
+ Event e(type);
+ e.read(xml);
+ // stored tickpos for event has absolute value. However internally
+ // tickpos is relative to start of part, we substract tick().
+ // TODO: better handling for wave event
+ e.move( -npart->tick() );
+ int tick = e.tick();
+
+ // Do not discard events belonging to clone parts,
+ // at least not yet. A later clone might have a longer,
+ // fully accommodating part length!
+ //if ((tick < 0) || (tick >= (int) lenTick())) {
+ //if ((tick < 0) || ( id == -1 && !clone && (tick >= (int)lenTick()) ))
+ // No way to tell at the moment whether there will be clones referencing this...
+ // No choice but to accept all events past 0.
+ if(tick < 0)
+ {
+ //printf("readClone: warning: event not in part: %d - %d -%d, discarded\n",
+ printf("readClone: warning: event at tick:%d not in part:%s, discarded\n",
+ tick, npart->name().toLatin1().constData());
+ }
+ else
+ {
+ npart->events()->add(e);
+ }
+ }
+ else
+ // ...Otherwise a clone was created, so we don't need the events.
+ xml.skip(tag);
+ }
+ else
+ xml.unknown("PartCanvas::readClone");
+ break;
+ case Xml::Attribut:
+ if (tag == "cloneId")
+ {
+ id = xml.s2().toInt();
+ if(id != -1)
+ {
+ for(iClone i = cloneList.begin(); i != cloneList.end(); ++i)
+ {
+ // Is a matching part found in the clone list?
+ if(i->id == id)
+ {
+ // If it's a regular paste (not paste clone), and the original part is
+ // not a clone, defer so that a new copy is created in TagStart above.
+ if(!doClone && i->cp->cevents()->arefCount() <= 1)
+ break;
+
+ // This makes a clone, chains the part, and increases ref counts.
+ npart = track->newPart((Part*)i->cp, true);
+ break;
+ }
+ }
+ }
+ }
+ else if (tag == "uuid")
+ {
+ uuid_parse(xml.s2().toLatin1().constData(), uuid);
+ if(!uuid_is_null(uuid))
+ {
+ uuidvalid = true;
+ for(iClone i = cloneList.begin(); i != cloneList.end(); ++i)
+ {
+ // Is a matching part found in the clone list?
+ if(uuid_compare(uuid, i->uuid) == 0)
+ {
+ Track* cpt = i->cp->track();
+ // If we want to paste to the given track...
+ if(toTrack)
+ {
+ // If the given track type is not the same as the part's
+ // original track type, we can't continue. Just return.
+ if(!track || cpt->type() != track->type())
+ {
+ xml.skip("part");
+ return 0;
+ }
+ }
+ else
+ // ...else we want to paste to the part's original track.
+ {
+ // Make sure the track exists (has not been deleted).
+ if((cpt->isMidiTrack() && song->midis()->find(cpt) != song->midis()->end()) ||
+ (cpt->type() == Track::WAVE && song->waves()->find(cpt) != song->waves()->end()))
+ track = cpt;
+ else
+ // Track was not found. Try pasting to the given track, as above...
+ {
+ if(!track || cpt->type() != track->type())
+ {
+ // No luck. Just return.
+ xml.skip("part");
+ return 0;
+ }
+ }
+ }
+
+ // If it's a regular paste (not paste clone), and the original part is
+ // not a clone, defer so that a new copy is created in TagStart above.
+ if(!doClone && i->cp->cevents()->arefCount() <= 1)
+ break;
+
+ // This makes a clone, chains the part, and increases ref counts.
+ npart = track->newPart((Part*)i->cp, true);
+ break;
+ }
+ }
+ }
+ }
+ //else if(tag == "isclone") // Ignore
+ // clone = xml.s2().toInt();
+ break;
+ case Xml::TagEnd:
+ if (tag == "part")
+ return npart;
+ default:
+ break;
+ }
+ }
+ return npart;
+}
+*/
+
+/*
+//---------------------------------------------------------
+// PartCanvas::readClone
+//---------------------------------------------------------
+
+Part* PartCanvas::readClone(Xml& xml, Track* track, bool toTrack)
+ {
+ int id = -1;
+ Part* npart = 0;
+ uuid_t uuid;
+ uuid_clear(uuid);
+ bool uuidvalid = false;
+ bool clone = true;
+
+ for (;;) {
+ Xml::Token token = xml.parse();
+ const QString& tag = xml.s1();
+ switch (token) {
+ case Xml::Error:
+ case Xml::End:
+ return npart;
+ case Xml::TagStart:
+ // If the part has not been created yet...
+ if(!npart)
+ {
+ // Attribute section did not create a clone from any matching part. Create a non-clone part now.
+ if (track->type() == Track::MIDI || track->type() == Track::DRUM)
+ npart = new MidiPart((MidiTrack*)track);
+ else if (track->type() == Track::WAVE)
+ npart = new WavePart((WaveTrack*)track);
+ else
+ return 0;
+
+ // Signify a new non-clone part was created.
+ // Even if the original part was itself a clone, clear this because the
+ // attribute section did not create a clone from any matching part.
+ clone = false;
+
+ // If an id or uuid was found, add the part to the clone list
+ // so that subsequent parts can look it up and clone from it...
+ if(id != -1)
+ {
+ ClonePart ncp(npart, id);
+ cloneList.push_back(ncp);
+ }
+ else
+ if(uuidvalid)
+ {
+ ClonePart ncp(npart);
+ // New ClonePart creates its own uuid, but we need to replace it.
+ uuid_copy(ncp.uuid, uuid);
+ cloneList.push_back(ncp);
+ }
+ }
+
+ if (tag == "name")
+ npart->setName(xml.parse1());
+ else if (tag == "poslen") {
+ ((PosLen*)npart)->read(xml, "poslen");
+ }
+ else if (tag == "pos") {
+ Pos pos;
+ pos.read(xml, "pos"); // obsolete
+ npart->setTick(pos.tick());
+ }
+ else if (tag == "len") {
+ Pos len;
+ len.read(xml, "len"); // obsolete
+ npart->setLenTick(len.tick());
+ }
+ else if (tag == "selected")
+ npart->setSelected(xml.parseInt());
+ else if (tag == "color")
+ npart->setColorIndex(xml.parseInt());
+ else if (tag == "mute")
+ npart->setMute(xml.parseInt());
+ else if (tag == "event")
+ {
+ // If a new non-clone part was created, accept the events...
+ if(!clone)
+ {
+ EventType type = Wave;
+ if(track->isMidiTrack())
+ type = Note;
+ Event e(type);
+ e.read(xml);
+ // stored tickpos for event has absolute value. However internally
+ // tickpos is relative to start of part, we substract tick().
+ // TODO: better handling for wave event
+ e.move( -npart->tick() );
+ int tick = e.tick();
+
+ // Do not discard events belonging to clone parts,
+ // at least not yet. A later clone might have a longer,
+ // fully accommodating part length!
+ //if ((tick < 0) || (tick >= (int) lenTick())) {
+ //if ((tick < 0) || ( id == -1 && !clone && (tick >= (int)lenTick()) ))
+ // No way to tell at the moment whether there will be clones referencing this...
+ // No choice but to accept all events past 0.
+ if(tick < 0)
+ {
+ //printf("readClone: warning: event not in part: %d - %d -%d, discarded\n",
+ printf("readClone: warning: event at tick:%d not in part:%s, discarded\n",
+ tick, npart->name().toLatin1().constData());
+ }
+ else
+ {
+ npart->events()->add(e);
+ }
+ }
+ else
+ // ...Otherwise a clone was created, so we don't need the events.
+ xml.skip(tag);
+ }
+ else
+ xml.unknown("PartCanvas::readClone");
+ break;
+ case Xml::Attribut:
+ if (tag == "cloneId")
+ {
+ id = xml.s2().toInt();
+ if(id != -1)
+ {
+ for(iClone i = cloneList.begin(); i != cloneList.end(); ++i)
+ {
+ // Is a matching part found in the clone list?
+ if(i->id == id)
+ {
+ // This makes a clone, chains the part, and increases ref counts.
+ npart = track->newPart((Part*)i->cp, true);
+ break;
+ }
+ }
+ }
+ }
+ else if (tag == "uuid")
+ {
+ uuid_parse(xml.s2().toLatin1().constData(), uuid);
+ if(!uuid_is_null(uuid))
+ {
+ uuidvalid = true;
+ for(iClone i = cloneList.begin(); i != cloneList.end(); ++i)
+ {
+ // Is a matching part found in the clone list?
+ if(uuid_compare(uuid, i->uuid) == 0)
+ {
+ // If we want to paste to the part's original track...
+ if(!toTrack)
+ {
+ // Make sure the track exists (has not been deleted).
+ if((i->cp->track()->isMidiTrack() && song->midis()->find(i->cp->track()) != song->midis()->end()) ||
+ (i->cp->track()->type() == Track::WAVE && song->waves()->find(i->cp->track()) != song->waves()->end()))
+ track = i->cp->track();
+ }
+ // This makes a clone, chains the part, and increases ref counts.
+ npart = track->newPart((Part*)i->cp, true);
+ break;
+ }
+ }
+ }
+ }
+ //else if(tag == "isclone") // Ignore
+ // clone = xml.s2().toInt();
+ break;
+ case Xml::TagEnd:
+ if (tag == "part")
+ return npart;
+ default:
+ break;
+ }
+ }
+ return npart;
+}
+*/
+
+//---------------------------------------------------------
+// paste
+// paste part to current selected track at cpos
+//---------------------------------------------------------
+
+//void PartCanvas::paste()
+void PartCanvas::paste(bool clone, bool toTrack, bool doInsert)
+{
+ 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)
+ {
+ TrackList* tl = song->tracks();
+ for (iTrack i = tl->begin(); i != tl->end(); ++i) {
+ if ((*i)->selected()) {
+ if (track) {
+ QMessageBox::critical(this, QString("MusE"),
+ tr("Cannot paste: multiple tracks selected"));
+ return;
+ }
+ else
+ track = *i;
+ }
+ }
+ if (track == 0) {
+ QMessageBox::critical(this, QString("MusE"),
+ tr("Cannot paste: no track selected"));
+ return;
+ }
+ }
+
+ 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))
+ {
+ // If we want to paste to a selected track...
+ if(toTrack && !track->isMidiTrack())
+ {
+ QMessageBox::critical(this, QString("MusE"),
+ tr("Can only paste to midi/drum track"));
+ return;
+ }
+ txt = cb->text(mdpl, QClipboard::Clipboard);
+ }
+ else
+ if(md->hasFormat(pfx + wvpl))
+ {
+ // If we want to paste to a selected track...
+ if(toTrack && track->type() != Track::WAVE)
+ {
+ QMessageBox::critical(this, QString("MusE"),
+ tr("Can only paste to wave track"));
+ return;
+ }
+ txt = cb->text(wvpl, QClipboard::Clipboard);
+ }
+ else
+ if(md->hasFormat(pfx + mxpl))
+ {
+ // If we want to paste to a selected track...
+ if(toTrack && !track->isMidiTrack() && track->type() != Track::WAVE)
+ {
+ QMessageBox::critical(this, QString("MusE"),
+ tr("Can only paste to midi or wave track"));
+ return;
+ }
+ txt = cb->text(mxpl, QClipboard::Clipboard);
+ }
+ else
+ {
+ QMessageBox::critical(this, QString("MusE"),
+ tr("Cannot paste: wrong data type"));
+ return;
+ }
+
+ int endPos=0;
+ unsigned int startPos=song->vcpos();
+ if (!txt.isEmpty())
+ {
+ song->startUndo();
+ endPos=pasteAt(txt, track, startPos, clone, toTrack);
+ Pos p(endPos, true);
+ song->setPos(0, p);
+ if (!doInsert)
+ song->endUndo(SC_PART_INSERTED);
+ }
+
+ if (doInsert) {
+ int offset = endPos-startPos;
+ movePartsTotheRight(startPos, offset);
+ song->endUndo(SC_PART_INSERTED);
+ }
+ }
+
+//---------------------------------------------------------
+// movePartsToTheRight
+//---------------------------------------------------------
+void PartCanvas::movePartsTotheRight(unsigned int startTicks, int length)
+{
+ // all parts that start after the pasted parts will be moved the entire length of the pasted parts
+ for (iCItem i = items.begin(); i != items.end(); ++i) {
+ if (!i->second->isSelected()) {
+ Part* part = i->second->part();
+ if (part->tick() >= startTicks) {
+ //void Audio::msgChangePart(Part* oldPart, Part* newPart, bool doUndoFlag, bool doCtrls, bool doClones)
+ Part *newPart = part->clone();
+ newPart->setTick(newPart->tick()+length);
+ if (part->track()->type() == Track::WAVE) {
+ audio->msgChangePart((WavePart*)part,(WavePart*)newPart,false,false,false);
+ } else {
+ audio->msgChangePart(part,newPart,false,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);
+ song->undoOp(UndoOp::ModifyMarker,oldMarker, m);
+ }
+ }
+}
+//---------------------------------------------------------
+// startDrag
+//---------------------------------------------------------
+
+void PartCanvas::startDrag(CItem* item, DragType t)
+ {
+ //printf("PartCanvas::startDrag(CItem* item, DragType t)\n");
+ NPart* p = (NPart*)(item);
+ Part* part = p->part();
+
+ //---------------------------------------------------
+ // write part as XML into tmp file
+ //---------------------------------------------------
+
+ FILE* tmp = tmpfile();
+ if (tmp == 0) {
+ fprintf(stderr, "PartCanvas::startDrag() fopen failed: %s\n",
+ strerror(errno));
+ return;
+ }
+ Xml xml(tmp);
+ int level = 0;
+ part->write(level, xml);
+
+ //---------------------------------------------------
+ // read tmp file into QTextDrag Object
+ //---------------------------------------------------
+
+ fflush(tmp);
+ struct stat f_stat;
+ if (fstat(fileno(tmp), &f_stat) == -1) {
+ fprintf(stderr, "PartCanvas::startDrag fstat failed:<%s>\n",
+ strerror(errno));
+ fclose(tmp);
+ return;
+ }
+ int n = f_stat.st_size + 1;
+ char* fbuf = (char*)mmap(0, n, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE, fileno(tmp), 0);
+ fbuf[n] = 0;
+
+ QByteArray data(fbuf);
+ QMimeData* md = new QMimeData();
+
+ md->setData("text/x-muse-partlist", data);
+
+ // "Note that setMimeData() assigns ownership of the QMimeData object to the QDrag object.
+ // The QDrag must be constructed on the heap with a parent QWidget to ensure that Qt can
+ // clean up after the drag and drop operation has been completed. "
+ QDrag* drag = new QDrag(this);
+ drag->setMimeData(md);
+
+ if (t == MOVE_COPY || t == MOVE_CLONE)
+ drag->exec(Qt::CopyAction);
+ else
+ drag->exec(Qt::MoveAction);
+
+ munmap(fbuf, n);
+ fclose(tmp);
+ }
+
+//---------------------------------------------------------
+// dragEnterEvent
+//---------------------------------------------------------
+
+void PartCanvas::dragEnterEvent(QDragEnterEvent* event)
+ {
+ ///event->accept(Q3TextDrag::canDecode(event));
+ event->acceptProposedAction(); // TODO CHECK Tim.
+ }
+
+//---------------------------------------------------------
+// dragMoveEvent
+//---------------------------------------------------------
+
+void PartCanvas::dragMoveEvent(QDragMoveEvent*)
+ {
+// printf("drag move %x\n", this);
+ //event->acceptProposedAction();
+ }
+
+//---------------------------------------------------------
+// dragLeaveEvent
+//---------------------------------------------------------
+
+void PartCanvas::dragLeaveEvent(QDragLeaveEvent*)
+ {
+// printf("drag leave\n");
+ //event->acceptProposedAction();
+ }
+
+//---------------------------------------------------------
+// dropEvent
+//---------------------------------------------------------
+
+void PartCanvas::viewDropEvent(QDropEvent* event)
+ {
+ //printf("void PartCanvas::viewDropEvent(QDropEvent* event)\n");
+ if (event->source() == this) {
+ printf("local DROP\n");
+ //event->ignore(); // TODO CHECK Tim.
+ return;
+ }
+ int type = 0; // 0 = unknown, 1 = partlist, 2 = uri-list
+ QString text;
+
+ if(event->mimeData()->hasFormat("text/partlist"))
+ type = 1;
+ else
+ //if(event->mimeData()->hasFormat("text/uri-list"))
+ if(event->mimeData()->hasUrls())
+ type = 2;
+ else
+ {
+ if(debugMsg && event->mimeData()->formats().size() != 0)
+ printf("Drop with unknown format. First format:<%s>\n", event->mimeData()->formats()[0].toLatin1().constData());
+ //event->ignore(); // TODO CHECK Tim.
+ return;
+ }
+
+ // Make a backup of the current clone list, to retain any 'copy' items,
+ // so that pasting works properly after.
+ CloneList copyCloneList = cloneList;
+ // Clear the clone list to prevent any dangerous associations with
+ // current non-original parts.
+ cloneList.clear();
+
+ if (type == 1)
+ {
+ text = QString(event->mimeData()->data("text/partlist"));
+
+ int x = AL::sigmap.raster(event->pos().x(), *_raster);
+ if (x < 0)
+ x = 0;
+ unsigned trackNo = y2pitch(event->pos().y());
+ Track* track = 0;
+ if (trackNo < tracks->size())
+ track = tracks->index(trackNo);
+ if (track) {
+ song->startUndo();
+ pasteAt(text, track, x);
+ song->endUndo(SC_PART_INSERTED);
+ }
+ }
+ else if (type == 2)
+ {
+ // Multiple urls not supported here. Grab the first one.
+ text = event->mimeData()->urls()[0].path();
+
+ if (text.endsWith(".wav",Qt::CaseInsensitive) ||
+ text.endsWith(".ogg",Qt::CaseInsensitive) ||
+ text.endsWith(".mpt", Qt::CaseInsensitive) )
+ {
+ int x = AL::sigmap.raster(event->pos().x(), *_raster);
+ if (x < 0)
+ x = 0;
+ unsigned trackNo = y2pitch(event->pos().y());
+ Track* track = 0;
+ if (trackNo < tracks->size())
+ track = tracks->index(trackNo);
+ if (track)
+ {
+ if (track->type() == Track::WAVE &&
+ (text.endsWith(".wav", Qt::CaseInsensitive) ||
+ (text.endsWith(".ogg", Qt::CaseInsensitive))))
+ {
+ unsigned tick = x;
+ muse->importWaveToTrack(text, tick, track);
+ }
+ // Changed by T356. Support mixed .mpt files.
+ else if ((track->isMidiTrack() || track->type() == Track::WAVE) && text.endsWith(".mpt", Qt::CaseInsensitive))
+ {
+ unsigned tick = x;
+ muse->importPartToTrack(text, tick, track);
+ }
+ }
+ }
+ else if(text.endsWith(".med",Qt::CaseInsensitive))
+ {
+ emit dropSongFile(text);
+ }
+ else if(text.endsWith(".mid",Qt::CaseInsensitive))
+ {
+ emit dropMidiFile(text);
+ }
+ else
+ {
+ printf("dropped... something... no hable...\n");
+ }
+ }
+
+ // Restore backup of the clone list, to retain any 'copy' items,
+ // so that pasting works properly after.
+ cloneList.clear();
+ cloneList = copyCloneList;
+ }
+
+//---------------------------------------------------------
+// drawCanvas
+//---------------------------------------------------------
+
+void PartCanvas::drawCanvas(QPainter& p, const QRect& rect)
+{
+ int x = rect.x();
+ int y = rect.y();
+ int w = rect.width();
+ int h = rect.height();
+
+ //////////
+ // GRID //
+ //////////
+ QColor baseColor(config.partCanvasBg.light(104));
+ p.setPen(baseColor);
+
+ //--------------------------------
+ // vertical lines
+ //-------------------------------
+ //printf("raster=%d\n", *_raster);
+ if (config.canvasShowGrid) {
+ int bar, beat;
+ unsigned tick;
+
+ AL::sigmap.tickValues(x, &bar, &beat, &tick);
+ for (;;) {
+ int xt = AL::sigmap.bar2tick(bar++, 0, 0);
+ if (xt >= x + w)
+ break;
+ if (!((bar-1) % 4))
+ p.setPen(baseColor.dark(115));
+ else
+ p.setPen(baseColor);
+ p.drawLine(xt, y, xt, y+h);
+
+ // append
+ int noDivisors=0;
+ if (*_raster == config.division *2) // 1/2
+ noDivisors=2;
+ else if (*_raster== config.division) // 1/4
+ noDivisors=4;
+ else if (*_raster==config.division/2) // 1/8
+ noDivisors=8;
+ else if (*_raster==config.division/4) // 1/16
+ noDivisors=16;
+ else if (*_raster==config.division/8) // 1/16
+ noDivisors=32;
+ else if (*_raster==config.division/16) // 1/16
+ noDivisors=64;
+
+ int r = *_raster;
+ int rr = rmapx(r);
+ if (*_raster > 1) {
+ while (rr < 4) {
+ r *= 2;
+ rr = rmapx(r);
+ noDivisors=noDivisors/2;
+ }
+ p.setPen(baseColor);
+ for (int t=1;t< noDivisors;t++)
+ p.drawLine(xt+r*t, y, xt+r*t, y+h);
+ }
+ }
+ }
+ //--------------------------------
+ // horizontal lines
+ //--------------------------------
+
+ TrackList* tl = song->tracks();
+ int yy = 0;
+ int th;
+ for (iTrack it = tl->begin(); it != tl->end(); ++it) {
+ if (yy > y + h)
+ break;
+ Track* track = *it;
+ th = track->height();
+ ///if (/*config.canvasShowGrid ||*/ !track->isMidiTrack()) {
+ if (config.canvasShowGrid && (track->isMidiTrack() || track->type() == Track::WAVE)) // Tim.
+ {
+ //printf("PartCanvas::drawCanvas track name:%s, y:%d h:%d\n", track->name().toLatin1().constData(), yy, th);
+ p.setPen(baseColor.dark(130));
+ ///p.drawLine(x, yy, x + w, yy);
+ p.drawLine(x, yy + th, x + w, yy + th); // Tim.
+ p.setPen(baseColor);
+ }
+ if (!track->isMidiTrack() && (track->type() != Track::WAVE)) {
+ QRect r = rect & QRect(x, yy, w, track->height());
+ drawAudioTrack(p, r, (AudioTrack*)track);
+ p.setPen(baseColor);
+ }
+ if (!track->isMidiTrack()) { // draw automation
+ QRect r = rect & QRect(x, yy, w, track->height());
+ drawAutomation(p, r, (AudioTrack*)track);
+ p.setPen(baseColor);
+
+ }
+ yy += track->height();
+ }
+}
+
+//---------------------------------------------------------
+// drawAudioTrack
+//---------------------------------------------------------
+
+void PartCanvas::drawAudioTrack(QPainter& p, const QRect& r, AudioTrack* /* t */)
+{
+ // NOTE: For one-pixel border use first line and don't bother with setCosmetic.
+ // For a two-pixel border use second line and MUST use setCosmetic! Tim.
+ QPen pen(Qt::black, 0, Qt::SolidLine);
+ //p.setPen(QPen(Qt::black, 2, Qt::SolidLine));
+ //pen.setCosmetic(true);
+ p.setPen(pen);
+ //p.setBrush(Qt::gray);
+ QColor c(Qt::gray);
+ c.setAlpha(config.globalAlphaBlend);
+ p.setBrush(c);
+
+ // Factor in pen stroking size:
+ //QRect rr(r);
+ //rr.setHeight(rr.height() -1);
+
+ p.drawRect(r);
+}
+
+//---------------------------------------------------------
+// drawAutomation
+//---------------------------------------------------------
+
+void PartCanvas::drawAutomation(QPainter& p, const QRect& r, AudioTrack *t)
+{
+// printf("drawAudioTrack %d x %d y %d w %d h %d\n",t, r.x(), r.y(), r.width(), r.height());
+ //int v2=r.x()+r.width();
+ //printf("v2=%d mapx=%d rmapx=%d mapxdev=%d rmapxdev=%d\n",v2, mapx(v2),rmapx(v2),mapxDev(v2),rmapxDev(v2));
+ //return;
+
+// p.setPen(QPen(Qt::black, 2, Qt::SolidLine));
+ int height=r.bottom()-r.top()-4; // limit height
+
+ CtrlListList* cll = t->controller();
+// QColor cols[10];
+// cols[0]=Qt::white;
+// cols[1]=Qt::red;
+// cols[2]=Qt::yellow;
+// cols[3]=Qt::black;
+// cols[4]=Qt::blue;
+ //int colIndex=0;
+ bool firstRun=true;
+ for(CtrlListList::iterator icll =cll->begin();icll!=cll->end();++icll)
+ {
+ //iCtrlList *icl = icll->second;
+ CtrlList *cl = icll->second;
+ if (cl->dontShow())
+ continue;
+ double prevVal;
+ iCtrl ic=cl->begin();
+ if (!cl->isVisible())
+ continue; // skip this iteration if this controller isn't in the visible list
+ p.setPen(QPen(cl->color(),1,Qt::SolidLine));
+
+ // First check that there ARE automation, ic == cl->end means no automation
+ if (ic != cl->end()) {
+ CtrlVal cvFirst = ic->second;
+ ic++;
+ int prevPos=cvFirst.frame;
+ prevVal = cvFirst.val;
+
+ // prepare prevVal
+ if (cl->id() == AC_VOLUME ) { // use db scale for volume
+ prevVal = (20.0*log10(cvFirst.val)+60) / 70.0; // represent volume between 0 and 1
+ if (prevVal < 0) prevVal = 0.0;
+ }
+ else {
+ // we need to set curVal between 0 and 1
+ double min, max;
+ cl->range(&min,&max);
+ prevVal = (prevVal- min)/(max-min);
+ }
+
+ for (; ic !=cl->end(); ++ic)
+ {
+ CtrlVal cv = ic->second;
+ double nextVal = cv.val; // was curVal
+ if (cl->id() == AC_VOLUME ) { // use db scale for volume
+ nextVal = (20.0*log10(cv.val)+60) / 70.0; // represent volume between 0 and 1
+ if (nextVal < 0) nextVal = 0.0;
+ }
+ else {
+ // we need to set curVal between 0 and 1
+ double min, max;
+ cl->range(&min,&max);
+ nextVal = (nextVal- min)/(max-min);
+ }
+ int leftX=tempomap.frame2tick(prevPos);
+ if (firstRun && leftX>r.x()) {
+ leftX=r.x();
+ }
+
+ p.drawLine( leftX,
+ (r.bottom()-2)-prevVal*height,
+ tempomap.frame2tick(cv.frame),
+ (r.bottom()-2)-nextVal*height);
+ firstRun=false;
+ //printf("draw line: %d %f %d %f\n",tempomap.frame2tick(lastPos),r.bottom()-lastVal*height,tempomap.frame2tick(cv.frame),r.bottom()-curVal*height);
+ prevPos=cv.frame;
+ prevVal=nextVal;
+ }
+ //printf("outer draw %f\n", cvFirst.val );
+ p.drawLine(tempomap.frame2tick(prevPos),
+ (r.bottom()-2)-prevVal*height,
+ r.x()+r.width(),
+ (r.bottom()-2)-prevVal*height);
+ //printf("draw last line: %d %f %d %f\n",tempomap.frame2tick(prevPos),(r.bottom()-2)-prevVal*height,tempomap.frame2tick(prevPos)+r.width(),(r.bottom()-2)-prevVal*height);
+ }
+ }
+}
+
+
+void PartCanvas::controllerChanged(Track* /* t */)
+{
+ redraw();
+}
diff --git a/attic/muse2-oom/muse2/muse/arranger/pcanvas.h b/attic/muse2-oom/muse2/muse/arranger/pcanvas.h
new file mode 100644
index 00000000..103b3d02
--- /dev/null
+++ b/attic/muse2-oom/muse2/muse/arranger/pcanvas.h
@@ -0,0 +1,139 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: pcanvas.h,v 1.11.2.4 2009/05/24 21:43:44 terminator356 Exp $
+// (C) Copyright 1999 Werner Schweer (ws@seh.de)
+//=========================================================
+
+#ifndef __PCANVAS_H__
+#define __PCANVAS_H__
+
+#include "song.h"
+#include "canvas.h"
+#include "trackautomationview.h"
+
+class QDragMoveEvent;
+class QDropEvent;
+class QDragLeaveEvent;
+class QMouseEvent;
+class QKeyEvent;
+class QEvent;
+class QDragEnterEvent;
+
+#define beats 4
+
+//---------------------------------------------------------
+// NPart
+// ''visual'' Part
+// wraps Parts with additional information needed
+// for displaying
+//---------------------------------------------------------
+
+class NPart : public CItem {
+ public:
+ NPart(Part* e);
+ const QString name() const { return part()->name(); }
+ void setName(const QString& s) { part()->setName(s); }
+ Track* track() const { return part()->track(); }
+ };
+
+class QLineEdit;
+class MidiEditor;
+class QMenu;
+class Xml;
+
+//---------------------------------------------------------
+// PartCanvas
+//---------------------------------------------------------
+
+class PartCanvas : public Canvas {
+ int* _raster;
+ TrackList* tracks;
+
+ Part* resizePart;
+ QLineEdit* lineEditor;
+ NPart* editPart;
+ int curColorIndex;
+ bool editMode;
+
+ std::vector<TrackAutomationView*> automationViews;
+ Q_OBJECT
+ virtual void keyPress(QKeyEvent*);
+ virtual void mousePress(QMouseEvent*);
+ virtual void mouseMove(const QPoint&);
+ virtual void mouseRelease(const QPoint&);
+ virtual void viewMouseDoubleClickEvent(QMouseEvent*);
+ virtual void leaveEvent(QEvent*e);
+ virtual void drawItem(QPainter&, const CItem*, const QRect&);
+ virtual void drawMoving(QPainter&, const CItem*, const QRect&);
+ virtual void updateSelection();
+ virtual QPoint raster(const QPoint&) const;
+ virtual int y2pitch(int y) const;
+ virtual int pitch2y(int p) const;
+
+ virtual void moveCanvasItems(CItemList&, int, int, DragType, int*);
+ // Changed by T356.
+ //virtual bool moveItem(CItem*, const QPoint&, DragType, int*);
+ virtual bool moveItem(CItem*, const QPoint&, DragType);
+ virtual CItem* newItem(const QPoint&, int);
+ virtual void resizeItem(CItem*,bool);
+ virtual void newItem(CItem*,bool);
+ virtual bool deleteItem(CItem*);
+ virtual void startUndo(DragType);
+
+ virtual void endUndo(DragType, int);
+ virtual void startDrag(CItem*, DragType);
+ virtual void dragEnterEvent(QDragEnterEvent*);
+ virtual void dragMoveEvent(QDragMoveEvent*);
+ virtual void dragLeaveEvent(QDragLeaveEvent*);
+ virtual void viewDropEvent(QDropEvent*);
+
+ virtual QMenu* genItemPopup(CItem*);
+ virtual void itemPopup(CItem*, int, const QPoint&);
+
+ void glueItem(CItem* item);
+ void splitItem(CItem* item, const QPoint&);
+
+ void copy(PartList*);
+ void paste(bool clone = false, bool toTrack = true, bool doInsert=false);
+ int pasteAt(const QString&, Track*, unsigned int, bool clone = false, bool toTrack = true);
+ void movePartsTotheRight(unsigned int startTick, int length);
+ //Part* readClone(Xml&, Track*, bool toTrack = true);
+ void drawWavePart(QPainter&, const QRect&, WavePart*, const QRect&);
+ Track* y2Track(int) const;
+ void drawAudioTrack(QPainter& p, const QRect& r, AudioTrack* track);
+ void drawAutomation(QPainter& p, const QRect& r, AudioTrack* track);
+
+
+ protected:
+ virtual void drawCanvas(QPainter&, const QRect&);
+
+ signals:
+ void timeChanged(unsigned);
+ void tracklistChanged();
+ void dclickPart(Track*);
+ void selectionChanged();
+ void dropSongFile(const QString&);
+ void dropMidiFile(const QString&);
+ void setUsedTool(int);
+ void trackChanged(Track*);
+ void selectTrackAbove();
+ void selectTrackBelow();
+
+ void startEditor(PartList*, int);
+
+ private slots:
+ 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 };
+
+ PartCanvas(int* raster, QWidget* parent, int, int);
+ void partsChanged();
+ void cmd(int);
+ void controllerChanged(Track *t);
+ public slots:
+ void redirKeypress(QKeyEvent* e) { keyPress(e); }
+ };
+#endif
diff --git a/attic/muse2-oom/muse2/muse/arranger/tlist.cpp b/attic/muse2-oom/muse2/muse/arranger/tlist.cpp
new file mode 100644
index 00000000..02f742f7
--- /dev/null
+++ b/attic/muse2-oom/muse2/muse/arranger/tlist.cpp
@@ -0,0 +1,1595 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: tlist.cpp,v 1.31.2.31 2009/12/15 03:39:58 terminator356 Exp $
+// (C) Copyright 1999 Werner Schweer (ws@seh.de)
+//=========================================================
+
+//#include "config.h"
+
+#include <cmath>
+
+#include <QKeyEvent>
+#include <QLineEdit>
+#include <QMenu>
+#include <QMessageBox>
+#include <QMouseEvent>
+#include <QPainter>
+#include <QPaintEvent>
+#include <QPixmap>
+#include <QResizeEvent>
+#include <QScrollBar>
+#include <QWheelEvent>
+
+#include "popupmenu.h"
+#include "globals.h"
+#include "icons.h"
+#include "scrollscale.h"
+#include "tlist.h"
+#include "xml.h"
+#include "mididev.h"
+#include "midiport.h"
+#include "midiseq.h"
+#include "comment.h"
+#include "track.h"
+#include "song.h"
+#include "header.h"
+#include "node.h"
+#include "audio.h"
+#include "instruments/minstrument.h"
+#include "app.h"
+#include "gconfig.h"
+#include "event.h"
+#include "midiedit/drummap.h"
+#include "synth.h"
+#include "config.h"
+
+#ifdef DSSI_SUPPORT
+#include "dssihost.h"
+#endif
+
+extern QMenu* populateAddSynth(QWidget* parent);
+
+static const int MIN_TRACKHEIGHT = 20;
+static const int WHEEL_DELTA = 120;
+
+//---------------------------------------------------------
+// TList
+//---------------------------------------------------------
+
+TList::TList(Header* hdr, QWidget* parent, const char* name)
+ : QWidget(parent) // Qt::WNoAutoErase | Qt::WResizeNoErase are no longer needed according to Qt4 doc
+ {
+ setBackgroundRole(QPalette::NoRole);
+ setAttribute(Qt::WA_NoSystemBackground);
+ setAttribute(Qt::WA_StaticContents);
+ // This is absolutely required for speed! Otherwise painfully slow because we get
+ // full rect paint events even on small scrolls! See help on QPainter::scroll().
+ setAttribute(Qt::WA_OpaquePaintEvent);
+
+ setObjectName(name);
+ ypos = 0;
+ editMode = false;
+ setFocusPolicy(Qt::StrongFocus);
+ setMouseTracking(true);
+ header = hdr;
+
+ _scroll = 0;
+ editTrack = 0;
+ editor = 0;
+ mode = NORMAL;
+
+ //setBackgroundMode(Qt::NoBackground); // ORCAN - FIXME
+ //setAttribute(Qt::WA_OpaquePaintEvent);
+ resizeFlag = false;
+
+ connect(song, SIGNAL(songChanged(int)), SLOT(songChanged(int)));
+ connect(muse, SIGNAL(configChanged()), SLOT(redraw()));
+ }
+
+//---------------------------------------------------------
+// songChanged
+//---------------------------------------------------------
+
+void TList::songChanged(int flags)
+ {
+ if (flags & (SC_MUTE | SC_SOLO | SC_RECFLAG | SC_TRACK_INSERTED
+ | SC_TRACK_REMOVED | SC_TRACK_MODIFIED | SC_ROUTE | SC_CHANNELS | SC_MIDI_TRACK_PROP))
+ redraw();
+ if (flags & (SC_TRACK_INSERTED | SC_TRACK_REMOVED | SC_TRACK_MODIFIED))
+ adjustScrollbar();
+ }
+
+//---------------------------------------------------------
+// drawCenteredPixmap
+// small helper function for "draw()" below
+//---------------------------------------------------------
+
+static void drawCenteredPixmap(QPainter& p, const QPixmap* pm, const QRect& r)
+ {
+ p.drawPixmap(r.x() + (r.width() - pm->width())/2, r.y() + (r.height() - pm->height())/2, *pm);
+ }
+
+//---------------------------------------------------------
+// paintEvent
+//---------------------------------------------------------
+
+void TList::paintEvent(QPaintEvent* ev)
+ {
+ paint(ev->rect());
+ }
+
+//---------------------------------------------------------
+// redraw
+//---------------------------------------------------------
+
+void TList::redraw()
+ {
+ update();
+ }
+
+//---------------------------------------------------------
+// redraw
+//---------------------------------------------------------
+
+void TList::redraw(const QRect& r)
+ {
+ update(r);
+ }
+
+//---------------------------------------------------------
+// paint
+//---------------------------------------------------------
+
+void TList::paint(const QRect& r)
+ {
+ if (!isVisible())
+ return;
+ QRect rect(r);
+ QPainter p(this);
+
+ if (bgPixmap.isNull())
+ p.fillRect(rect, config.trackBg);
+ else
+ p.drawTiledPixmap(rect, bgPixmap, QPoint(rect.x(), ypos + rect.y()));
+ p.setClipRegion(rect);
+
+ //printf("TList::paint hasClipping:%d\n", p.hasClipping()); // Tested true.
+
+ int y = rect.y();
+ int w = rect.width();
+ int h = rect.height();
+ int x1 = rect.x();
+ int x2 = rect.x() + w;
+
+ //---------------------------------------------------
+ // Tracks
+ //---------------------------------------------------
+
+ TrackList* l = song->tracks();
+ int idx = 0;
+ int yy = -ypos;
+ for (iTrack i = l->begin(); i != l->end(); ++idx, yy += (*i)->height(), ++i) {
+ Track* track = *i;
+ Track::TrackType type = track->type();
+ int trackHeight = track->height();
+ if (yy >= (y + h))
+ break;
+ if ((yy + trackHeight) < y)
+ continue;
+ //
+ // clear one row
+ //
+ QColor bg;
+ if (track->selected()) {
+ bg = config.selectTrackBg;
+ //p.setPen(palette().active().text());
+ p.setPen(config.selectTrackFg);
+ }
+ else {
+ switch(type) {
+ case Track::MIDI:
+ bg = config.midiTrackBg;
+ break;
+ case Track::DRUM:
+ bg = config.drumTrackBg;
+ break;
+ case Track::WAVE:
+ bg = config.waveTrackBg;
+ break;
+ case Track::AUDIO_OUTPUT:
+ bg = config.outputTrackBg;
+ break;
+ case Track::AUDIO_INPUT:
+ bg = config.inputTrackBg;
+ break;
+ case Track::AUDIO_GROUP:
+ bg = config.groupTrackBg;
+ break;
+ case Track::AUDIO_AUX:
+ bg = config.auxTrackBg;
+ break;
+ case Track::AUDIO_SOFTSYNTH:
+ bg = config.synthTrackBg;
+ break;
+ }
+ p.setPen(palette().color(QPalette::Active, QPalette::Text));
+ }
+ p.fillRect(x1, yy, w, trackHeight, bg);
+
+ int x = 0;
+ for (int index = 0; index < header->count(); ++index) {
+ int section = header->logicalIndex(index);
+ int w = header->sectionSize(section);
+ //QRect r = p.xForm(QRect(x+2, yy, w-4, trackHeight));
+ QRect r = p.combinedTransform().mapRect(QRect(x+2, yy, w-4, trackHeight));
+
+ switch (section) {
+ case COL_RECORD:
+ if (track->canRecord()) {
+ drawCenteredPixmap(p,
+ track->recordFlag() ? record_on_Icon : record_off_Icon, r);
+ }
+ break;
+ case COL_CLASS:
+ {
+ const QPixmap* pm = 0;
+ switch(type) {
+ case Track::MIDI:
+ pm = addtrack_addmiditrackIcon;
+ break;
+ case Track::DRUM:
+ pm = addtrack_drumtrackIcon;
+ break;
+ case Track::WAVE:
+ pm = addtrack_wavetrackIcon;
+ break;
+ case Track::AUDIO_OUTPUT:
+ pm = addtrack_audiooutputIcon;
+ break;
+ case Track::AUDIO_INPUT:
+ pm = addtrack_audioinputIcon;
+ break;
+ case Track::AUDIO_GROUP:
+ pm = addtrack_audiogroupIcon;
+ break;
+ case Track::AUDIO_AUX:
+ pm = addtrack_auxsendIcon;
+ break;
+ case Track::AUDIO_SOFTSYNTH:
+ //pm = waveIcon;
+ pm = synthIcon;
+ break;
+ }
+ drawCenteredPixmap(p, pm, r);
+ }
+ break;
+ case COL_MUTE:
+ if (track->off())
+ drawCenteredPixmap(p, offIcon, r);
+ else if (track->mute())
+ drawCenteredPixmap(p, editmuteSIcon, r);
+ break;
+ case COL_SOLO:
+ if(track->solo() && track->internalSolo())
+ drawCenteredPixmap(p, blacksqcheckIcon, r);
+ else
+ if(track->internalSolo())
+ drawCenteredPixmap(p, blacksquareIcon, r);
+ else
+ if (track->solo())
+ drawCenteredPixmap(p, bluedotIcon, r);
+ break;
+ case COL_TIMELOCK:
+ if (track->isMidiTrack()
+ && track->locked()) {
+ drawCenteredPixmap(p, lockIcon, r);
+ }
+ break;
+ case COL_NAME:
+ p.drawText(r, Qt::AlignVCenter|Qt::AlignLeft, track->name());
+ break;
+ case COL_OCHANNEL:
+ {
+ QString s;
+ int n;
+ if (track->isMidiTrack()) {
+ n = ((MidiTrack*)track)->outChannel() + 1;
+ }
+ else {
+ // show number of ports
+ n = ((WaveTrack*)track)->channels();
+ }
+ s.setNum(n);
+ p.drawText(r, Qt::AlignVCenter|Qt::AlignHCenter, s);
+ }
+ break;
+ case COL_OPORT:
+ {
+ QString s;
+ if (track->isMidiTrack()) {
+ int outport = ((MidiTrack*)track)->outPort();
+ s.sprintf("%d:%s", outport+1, midiPorts[outport].portname().toLatin1().constData());
+ }
+ // Added by Tim. p3.3.9
+
+ else
+ if(track->type() == Track::AUDIO_SOFTSYNTH)
+ {
+ MidiDevice* md = dynamic_cast<MidiDevice*>(track);
+ if(md)
+ {
+ int outport = md->midiPort();
+ if((outport >= 0) && (outport < MIDI_PORTS))
+ s.sprintf("%d:%s", outport+1, midiPorts[outport].portname().toLatin1().constData());
+ else
+ s = tr("<none>");
+ }
+ }
+
+ p.drawText(r, Qt::AlignVCenter|Qt::AlignLeft, s);
+ }
+ break;
+ case COL_AUTOMATION:
+ {
+ QString s="-";
+
+ if (!track->isMidiTrack()) {
+ int count = ((AudioTrack*)track)->controller()->size();
+ s.sprintf("%d viewed", count);
+ }
+
+
+ p.drawText(r, Qt::AlignVCenter|Qt::AlignLeft, s);
+ }
+ break;
+ default:
+ break;
+ }
+ x += header->sectionSize(section);
+ }
+ p.setPen(Qt::gray);
+ p.drawLine(x1, yy, x2, yy);
+ }
+ p.drawLine(x1, yy, x2, yy);
+
+ if (mode == DRAG) {
+ int yy = curY - dragYoff;
+ p.setPen(Qt::green);
+ p.drawLine(x1, yy, x2, yy);
+ p.drawLine(x1, yy + dragHeight, x2, yy+dragHeight);
+ }
+
+ //---------------------------------------------------
+ // draw vertical lines
+ //---------------------------------------------------
+
+ int n = header->count();
+ int xpos = 0;
+ p.setPen(Qt::gray);
+ for (int index = 0; index < n; index++) {
+ int section = header->logicalIndex(index);
+ xpos += header->sectionSize(section);
+ p.drawLine(xpos, 0, xpos, height());
+ }
+ }
+
+//---------------------------------------------------------
+// returnPressed
+//---------------------------------------------------------
+
+void TList::returnPressed()
+ {
+ editor->hide();
+ if (editor->text() != editTrack->name()) {
+ TrackList* tl = song->tracks();
+ for (iTrack i = tl->begin(); i != tl->end(); ++i) {
+ if ((*i)->name() == editor->text()) {
+ QMessageBox::critical(this,
+ tr("MusE: bad trackname"),
+ tr("please choose a unique track name"),
+ QMessageBox::Ok,
+ Qt::NoButton,
+ Qt::NoButton);
+ editTrack = 0;
+ setFocus();
+ return;
+ }
+ }
+ //Track* track = editTrack->clone();
+ Track* track = editTrack->clone(false);
+ editTrack->setName(editor->text());
+ audio->msgChangeTrack(track, editTrack);
+ }
+ editTrack = 0;
+ editMode = false;
+ setFocus();
+ }
+
+//---------------------------------------------------------
+// adjustScrollbar
+//---------------------------------------------------------
+
+void TList::adjustScrollbar()
+ {
+ int h = 0;
+ TrackList* l = song->tracks();
+ for (iTrack it = l->begin(); it != l->end(); ++it)
+ h += (*it)->height();
+ _scroll->setMaximum(h +30);
+ redraw();
+ }
+
+//---------------------------------------------------------
+// y2Track
+//---------------------------------------------------------
+
+Track* TList::y2Track(int y) const
+ {
+ TrackList* l = song->tracks();
+ int ty = 0;
+ for (iTrack it = l->begin(); it != l->end(); ++it) {
+ int h = (*it)->height();
+ if (y >= ty && y < ty + h)
+ return *it;
+ ty += h;
+ }
+ return 0;
+ }
+
+//---------------------------------------------------------
+// viewMouseDoubleClickEvent
+//---------------------------------------------------------
+
+void TList::mouseDoubleClickEvent(QMouseEvent* ev)
+ {
+ int x = ev->x();
+ int section = header->logicalIndexAt(x);
+ if (section == -1)
+ return;
+
+ Track* t = y2Track(ev->y() + ypos);
+
+ if (t) {
+ int colx = header->sectionPosition(section);
+ int colw = header->sectionSize(section);
+ int coly = t->y() - ypos;
+ int colh = t->height();
+
+ if (section == COL_NAME) {
+ editTrack = t;
+ if (editor == 0) {
+ editor = new QLineEdit(this);
+ /*connect(editor, SIGNAL(returnPressed()),
+ SLOT(returnPressed()));*/
+ editor->setFrame(true);
+ }
+ editor->setText(editTrack->name());
+ editor->end(false);
+ editor->setGeometry(colx, coly, colw, colh);
+ editMode = true;
+ editor->show();
+ }
+ else
+ mousePressEvent(ev);
+ }
+ }
+
+//---------------------------------------------------------
+// portsPopupMenu
+//---------------------------------------------------------
+
+void TList::portsPopupMenu(Track* t, int x, int y)
+ {
+ switch(t->type()) {
+ case Track::MIDI:
+ case Track::DRUM:
+ case Track::AUDIO_SOFTSYNTH:
+ {
+ MidiTrack* track = (MidiTrack*)t;
+
+ //QPopupMenu* p = midiPortsPopup(0);
+ MidiDevice* md = 0;
+ int port = -1;
+ if(t->type() == Track::AUDIO_SOFTSYNTH)
+ {
+ //MidiDevice* md = dynamic_cast<MidiDevice*>((SynthI*)t);
+ md = dynamic_cast<MidiDevice*>(t);
+ if(md)
+ port = md->midiPort();
+ }
+ else
+ port = track->outPort();
+
+ QMenu* p = midiPortsPopup(0, port);
+ QAction* act = p->exec(mapToGlobal(QPoint(x, y)), 0);
+ if (act) {
+ int n = act->data().toInt();
+ // Changed by T356.
+ //track->setOutPort(n);
+ //audio->msgSetTrackOutPort(track, n);
+
+ //song->update();
+ if (t->type() == Track::DRUM) {
+ bool change = QMessageBox::question(this, tr("Update drummap?"),
+ tr("Do you want to use same port for all instruments in the drummap?"),
+ tr("&Yes"), tr("&No"), QString::null, 0, 1);
+ audio->msgIdle(true);
+ if (!change)
+ {
+ // Delete all port controller events.
+ //audio->msgChangeAllPortDrumCtrlEvents(false);
+ song->changeAllPortDrumCtrlEvents(false);
+ track->setOutPort(n);
+
+ for (int i=0; i<DRUM_MAPSIZE; i++) //Remap all drum instruments to this port
+ drumMap[i].port = track->outPort();
+ // Add all port controller events.
+ //audio->msgChangeAllPortDrumCtrlEvents(true);
+ song->changeAllPortDrumCtrlEvents(true);
+ }
+ else
+ {
+ //audio->msgSetTrackOutPort(track, n);
+ track->setOutPortAndUpdate(n);
+ }
+ audio->msgIdle(false);
+ song->update();
+ }
+ else
+ if (t->type() == Track::AUDIO_SOFTSYNTH)
+ {
+ if(md != 0)
+ {
+ // Idling is already handled in msgSetMidiDevice.
+ //audio->msgIdle(true);
+
+ // Compiler complains if simple cast from Track to SynthI...
+ midiSeq->msgSetMidiDevice(&midiPorts[n], (midiPorts[n].device() == md) ? 0 : md);
+ muse->changeConfig(true); // save configuration file
+
+ //audio->msgIdle(false);
+ song->update();
+ }
+ }
+ else
+ {
+ audio->msgIdle(true);
+ //audio->msgSetTrackOutPort(track, n);
+ track->setOutPortAndUpdate(n);
+ audio->msgIdle(false);
+ song->update();
+ }
+ }
+ delete p;
+ }
+ break;
+
+ case Track::WAVE:
+ case Track::AUDIO_OUTPUT:
+ case Track::AUDIO_INPUT:
+ case Track::AUDIO_GROUP:
+ case Track::AUDIO_AUX: //TODO
+ break;
+ }
+ }
+
+//---------------------------------------------------------
+// oportPropertyPopupMenu
+//---------------------------------------------------------
+
+void TList::oportPropertyPopupMenu(Track* t, int x, int y)
+ {
+ // Added by Tim. p3.3.9
+ if(t->type() == Track::AUDIO_SOFTSYNTH)
+ {
+ SynthI* synth = (SynthI*)t;
+
+ QMenu* p = new QMenu;
+ QAction* act = p->addAction(tr("Show Gui"));
+ act->setCheckable(true);
+ //printf("synth hasgui %d, gui visible %d\n",synth->hasGui(), synth->guiVisible());
+ act->setEnabled(synth->hasGui());
+ act->setChecked(synth->guiVisible());
+
+ // If it has a gui but we don't have OSC, disable the action.
+ #ifndef OSC_SUPPORT
+ #ifdef DSSI_SUPPORT
+ if(dynamic_cast<DssiSynthIF*>(synth->sif()))
+ {
+ act->setChecked(false);
+ act->setEnabled(false);
+ }
+ #endif
+ #endif
+
+ QAction* ract = p->exec(mapToGlobal(QPoint(x, y)), 0);
+ if (ract == act) {
+ bool show = !synth->guiVisible();
+ audio->msgShowInstrumentGui(synth, show);
+ }
+ delete p;
+ return;
+ }
+
+
+ if (t->type() != Track::MIDI && t->type() != Track::DRUM)
+ return;
+ int oPort = ((MidiTrack*)t)->outPort();
+ MidiPort* port = &midiPorts[oPort];
+
+ QMenu* p = new QMenu;
+ QAction* act = p->addAction(tr("Show Gui"));
+ act->setCheckable(true);
+ //printf("synth hasgui %d, gui visible %d\n",port->hasGui(), port->guiVisible());
+ act->setEnabled(port->hasGui());
+ act->setChecked(port->guiVisible());
+
+ // If it has a gui but we don't have OSC, disable the action.
+ #ifndef OSC_SUPPORT
+ #ifdef DSSI_SUPPORT
+ MidiDevice* dev = port->device();
+ if(dev && dev->isSynti() && (dynamic_cast<DssiSynthIF*>(((SynthI*)dev)->sif())))
+ {
+ act->setChecked(false);
+ act->setEnabled(false);
+ }
+ #endif
+ #endif
+
+ QAction* ract = p->exec(mapToGlobal(QPoint(x, y)), 0);
+ if (ract == act) {
+ bool show = !port->guiVisible();
+ audio->msgShowInstrumentGui(port->instrument(), show);
+ }
+ delete p;
+
+ }
+
+//---------------------------------------------------------
+// tracklistChanged
+//---------------------------------------------------------
+
+void TList::tracklistChanged()
+ {
+ redraw();
+ }
+
+//---------------------------------------------------------
+// keyPressEvent
+//---------------------------------------------------------
+
+void TList::keyPressEvent(QKeyEvent* e)
+ {
+ if (editMode)
+ {
+ // First time we get a keypress event when lineedit is open is on the return key:
+ // -- Not true for Qt4. Modifier keys also send key events - Orcan
+ if ( e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter)
+ {
+ returnPressed();
+ return;
+ }
+ else if ( e->key() == Qt::Key_Escape )
+ {
+ editor->hide();
+ editTrack = 0;
+ editMode = false;
+ setFocus();
+ return;
+ }
+ }
+ emit keyPressExt(e); //redirect keypress events to main app
+
+ // p4.0.10 Removed by Tim. keyPressExt are sent to part canvas, where they are
+ // ignored *only* if necessary.
+ //e->ignore();
+
+ /*
+ int key = e->key();
+ switch (key) {
+ case Key_Up:
+ moveSelection(-1);
+ break;
+ case Key_Down:
+ moveSelection(1);
+ break;
+ default:
+
+ break;
+ }
+ */
+ }
+
+//---------------------------------------------------------
+// moveSelection
+//---------------------------------------------------------
+
+void TList::moveSelection(int n)
+ {
+ TrackList* tracks = song->tracks();
+
+ // check for single selection
+ int nselect = 0;
+ for (iTrack t = tracks->begin(); t != tracks->end(); ++t)
+ if ((*t)->selected())
+ ++nselect;
+ if (nselect != 1)
+ return;
+ Track* selTrack = 0;
+ for (iTrack t = tracks->begin(); t != tracks->end(); ++t) {
+ iTrack s = t;
+ if ((*t)->selected()) {
+ selTrack = *t;
+ if (n > 0) {
+ while (n--) {
+ ++t;
+ if (t == tracks->end()) {
+ --t;
+ break;
+ }
+ }
+ }
+ else {
+ while (n++ != 0) {
+ if (t == tracks->begin())
+ break;
+ --t;
+ }
+ }
+ (*s)->setSelected(false);
+ (*t)->setSelected(true);
+
+ // rec enable track if expected
+ TrackList recd = getRecEnabledTracks();
+ if (recd.size() == 1 && config.moveArmedCheckBox) { // one rec enabled track, move rec enabled with selection
+ song->setRecordFlag((Track*)recd.front(),false);
+ song->setRecordFlag((*t),true);
+ }
+
+ if (editTrack && editTrack != *t)
+ returnPressed();
+ redraw();
+ break;
+ }
+ }
+ ///emit selectionChanged();
+ emit selectionChanged(selTrack);
+ }
+
+TrackList TList::getRecEnabledTracks()
+{
+ //printf("getRecEnabledTracks\n");
+ TrackList recEnabled;
+ TrackList* tracks = song->tracks();
+ for (iTrack t = tracks->begin(); t != tracks->end(); ++t) {
+ if ((*t)->recordFlag()) {
+ //printf("rec enabled track\n");
+ recEnabled.push_back(*t);
+ }
+ }
+ return recEnabled;
+}
+
+//---------------------------------------------------------
+// mousePressEvent
+//---------------------------------------------------------
+
+void TList::changeAutomation(QAction* act)
+{
+ printf("changeAutomation!\n");
+ if (editTrack->type() == Track::MIDI) {
+ printf("this is wrong, we can't edit automation for midi tracks from arranger yet!\n");
+ return;
+ }
+
+ CtrlListList* cll = ((AudioTrack*)editTrack)->controller();
+ int index=0;
+ for(CtrlListList::iterator icll =cll->begin();icll!=cll->end();++icll) {
+ if (act->data() == index++) { // got it, change state
+ CtrlList *cl = icll->second;
+ cl->setVisible(!cl->isVisible());
+ }
+ }
+ song->update(SC_TRACK_MODIFIED);
+}
+
+void TList::mousePressEvent(QMouseEvent* ev)
+ {
+ int x = ev->x();
+ int y = ev->y();
+ int button = ev->button();
+ bool shift = ((QInputEvent*)ev)->modifiers() & Qt::ShiftModifier;
+
+ Track* t = y2Track(y + ypos);
+
+ 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);
+
+ // Create a sub-menu and fill it with found synth types. Make p the owner.
+ QMenu* synp = 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))
+ {
+ // 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);
+ 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();
+ }
+ }
+ }
+
+ // Just delete p, and all its children will go too, right?
+ //delete synp;
+ delete p;
+ }
+ return;
+ }
+
+ TrackList* tracks = song->tracks();
+ dragYoff = y - (t->y() - ypos);
+ startY = y;
+
+ if (resizeFlag) {
+ mode = RESIZE;
+ int y = ev->y();
+ int ty = -ypos;
+ sTrack = 0;
+ for (iTrack it = tracks->begin(); it != tracks->end(); ++it, ++sTrack) {
+ int h = (*it)->height();
+ ty += h;
+ if (y >= (ty-2)) {
+
+ if ( (*it) == tracks->back() && y > ty ) {
+ //printf("tracks->back() && y > ty\n");
+ }
+ else if ( y > (ty+2) ) {
+ //printf(" y > (ty+2) \n");
+ }
+ else {
+ //printf("ogga ogga\n");
+
+ break;
+ }
+
+
+ //&& y < (ty))
+ // break;
+ }
+ }
+
+ return;
+ }
+ mode = START_DRAG;
+
+ switch (col) {
+ case COL_AUTOMATION:
+ {
+ if (t->type() != Track::MIDI) {
+ editTrack = t;
+ PopupMenu* p = new PopupMenu();
+ p->disconnect();
+ p->clear();
+ p->setTitle(tr("Viewable automation"));
+ CtrlListList* cll = ((AudioTrack*)t)->controller();
+ QAction* act = 0;
+ int index=0;
+ for(CtrlListList::iterator icll =cll->begin();icll!=cll->end();++icll) {
+ CtrlList *cl = icll->second;
+ if (cl->dontShow())
+ continue;
+ act = p->addAction(cl->name());
+ act->setCheckable(true);
+ act->setChecked(cl->isVisible());
+ act->setData(index++);
+ }
+ connect(p, SIGNAL(triggered(QAction*)), SLOT(changeAutomation(QAction*)));
+ //connect(p, SIGNAL(aboutToHide()), muse, SLOT(routingPopupMenuAboutToHide()));
+ //p->popup(QCursor::pos());
+ p->exec(QCursor::pos());
+
+ delete p;
+ }
+ break;
+ }
+
+ case COL_RECORD:
+ {
+ bool val = !(t->recordFlag());
+ if (button == Qt::LeftButton) {
+ if (!t->isMidiTrack()) {
+ if (t->type() == Track::AUDIO_OUTPUT) {
+ if (val && t->recordFlag() == false) {
+ muse->bounceToFile((AudioOutput*)t);
+ }
+ audio->msgSetRecord((AudioOutput*)t, val);
+ if (!((AudioOutput*)t)->recFile())
+ val = false;
+ else
+ return;
+ }
+ song->setRecordFlag(t, val);
+ }
+ else
+ song->setRecordFlag(t, val);
+ } else if (button == Qt::RightButton) {
+ // enable or disable ALL tracks of this type
+ if (!t->isMidiTrack()) {
+ if (t->type() == Track::AUDIO_OUTPUT) {
+ return;
+ }
+ WaveTrackList* wtl = song->waves();
+ foreach (WaveTrack *wt, *wtl) {
+ song->setRecordFlag(wt, val);
+ }
+ }
+ else {
+ MidiTrackList* mtl = song->midis();
+ foreach (MidiTrack *mt, *mtl) {
+ song->setRecordFlag(mt, val);
+ }
+ }
+ }
+ }
+ break;
+ case COL_NONE:
+ break;
+ case COL_CLASS:
+ if (t->isMidiTrack())
+ classesPopupMenu(t, x, t->y() - ypos);
+ break;
+ case COL_OPORT:
+ // Changed by Tim. p3.3.9
+ // Reverted.
+ if (button == Qt::LeftButton)
+ portsPopupMenu(t, x, t->y() - ypos);
+ else if (button == Qt::RightButton)
+ oportPropertyPopupMenu(t, x, t->y() - ypos);
+ //if(((button == QMouseEvent::LeftButton) && (t->type() == Track::AUDIO_SOFTSYNTH)) || (button == QMouseEvent::RightButton))
+ // oportPropertyPopupMenu(t, x, t->y() - ypos);
+ //else
+ //if(button == QMouseEvent::LeftButton)
+ // portsPopupMenu(t, x, t->y() - ypos);
+
+ break;
+ case COL_MUTE:
+ // p3.3.29
+ if ((button == Qt::RightButton) || (((QInputEvent*)ev)->modifiers() & Qt::ControlModifier))
+ t->setOff(!t->off());
+ else
+ {
+ if (t->off())
+ t->setOff(false);
+ else
+ t->setMute(!t->mute());
+ }
+ song->update(SC_MUTE);
+ break;
+ case COL_SOLO:
+ audio->msgSetSolo(t, !t->solo());
+ song->update(SC_SOLO);
+ break;
+
+ case COL_NAME:
+ if (button == Qt::LeftButton) {
+ if (!shift) {
+ song->deselectTracks();
+ t->setSelected(true);
+
+ // rec enable track if expected
+ TrackList recd = getRecEnabledTracks();
+ if (recd.size() == 1 && config.moveArmedCheckBox) { // one rec enabled track, move rec enabled with selection
+ song->setRecordFlag((Track*)recd.front(),false);
+ song->setRecordFlag(t,true);
+ }
+ }
+ else
+ t->setSelected(!t->selected());
+ if (editTrack && editTrack != t)
+ returnPressed();
+ ///emit selectionChanged();
+ emit selectionChanged(t->selected() ? t : 0);
+ }
+ else if (button == Qt::RightButton) {
+ 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);
+ QAction* act = p->exec(ev->globalPos(), 0);
+ if (act) {
+ int n = act->data().toInt();
+ switch (n) {
+ case 0: // delete track
+ song->removeTrack0(t);
+ audio->msgUpdateSoloStates();
+ break;
+
+ case 1: // show track comment
+ {
+ TrackComment* tc = new TrackComment(t, 0);
+ tc->show();
+ //QToolTip::add( this, "FOOOOOOOOOOOOO" );
+ }
+ break;
+
+ default:
+ printf("action %d\n", n);
+ break;
+ }
+
+ }
+ delete p;
+ }
+ break;
+
+ case COL_TIMELOCK:
+ t->setLocked(!t->locked());
+ break;
+
+ case COL_OCHANNEL:
+ {
+ int delta = 0;
+ if (button == Qt::RightButton)
+ delta = 1;
+ else if (button == Qt::MidButton)
+ delta = -1;
+ if (t->isMidiTrack())
+ {
+ MidiTrack* mt = dynamic_cast<MidiTrack*>(t);
+ if (mt == 0)
+ break;
+
+ int channel = mt->outChannel();
+ channel += delta;
+ if(channel >= MIDI_CHANNELS)
+ channel = MIDI_CHANNELS - 1;
+ if(channel < 0)
+ channel = 0;
+ //if (channel != ((MidiTrack*)t)->outChannel())
+ if (channel != mt->outChannel())
+ {
+ // Changed by T356.
+ //mt->setOutChannel(channel);
+ audio->msgIdle(true);
+ //audio->msgSetTrackOutChannel(mt, channel);
+ mt->setOutChanAndUpdate(channel);
+ audio->msgIdle(false);
+
+ /* --- I really don't like this, you can mess up the whole map "as easy as dell"
+ if (mt->type() == MidiTrack::DRUM) {//Change channel on all drum instruments
+ for (int i=0; i<DRUM_MAPSIZE; i++)
+ drumMap[i].channel = channel;
+ }*/
+
+ // may result in adding/removing mixer strip:
+ //song->update(-1);
+ //song->update(SC_CHANNELS);
+ song->update(SC_MIDI_TRACK_PROP);
+ }
+ }
+ else
+ {
+ if(t->type() != Track::AUDIO_SOFTSYNTH)
+ {
+ AudioTrack* at = dynamic_cast<AudioTrack*>(t);
+ if (at == 0)
+ break;
+
+ int n = t->channels() + delta;
+ if (n > MAX_CHANNELS)
+ n = MAX_CHANNELS;
+ else if (n < 1)
+ n = 1;
+ if (n != t->channels()) {
+ audio->msgSetChannels(at, n);
+ song->update(SC_CHANNELS);
+ }
+ }
+ }
+ }
+ break;
+ }
+ redraw();
+ }
+
+//---------------------------------------------------------
+// selectTrack
+//---------------------------------------------------------
+void TList::selectTrack(Track* tr)
+ {
+ song->deselectTracks();
+ tr->setSelected(true);
+
+
+ // rec enable track if expected
+ TrackList recd = getRecEnabledTracks();
+ if (recd.size() == 1 && config.moveArmedCheckBox) { // one rec enabled track, move rec enabled with selection
+ song->setRecordFlag((Track*)recd.front(),false);
+ song->setRecordFlag(tr,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);
+ }
+
+//---------------------------------------------------------
+// selectTrackAbove
+//---------------------------------------------------------
+void TList::selectTrackAbove()
+{
+ moveSelection(-1);
+}
+//---------------------------------------------------------
+// selectTrackBelow
+//---------------------------------------------------------
+void TList::selectTrackBelow()
+{
+ moveSelection(1);
+}
+
+//---------------------------------------------------------
+// mouseMoveEvent
+//---------------------------------------------------------
+
+void TList::mouseMoveEvent(QMouseEvent* ev)
+ {
+ if ((((QInputEvent*)ev)->modifiers() | ev->buttons()) == 0) {
+ int y = ev->y();
+ int ty = -ypos;
+ TrackList* tracks = song->tracks();
+ iTrack it;
+ for (it = tracks->begin(); it != tracks->end(); ++it) {
+ int h = (*it)->height();
+ ty += h;
+ if (y >= (ty-2)) {
+ if ( (*it) == tracks->back() && y >= ty ) {
+ // outside last track don't change to splitVCursor
+ }
+ else if ( y > (ty+2) ) {
+ //printf(" y > (ty+2) \n");
+ }
+ else {
+ if (!resizeFlag) {
+ resizeFlag = true;
+ setCursor(QCursor(Qt::SplitVCursor));
+ }
+ break;
+ }
+ }
+ }
+ if (it == tracks->end() && resizeFlag) {
+ setCursor(QCursor(Qt::ArrowCursor));
+ resizeFlag = false;
+ }
+ return;
+ }
+ curY = ev->y();
+ int delta = curY - startY;
+ switch (mode) {
+ case START_DRAG:
+ if (delta < 0)
+ delta = -delta;
+ if (delta <= 2)
+ break;
+ {
+ Track* t = y2Track(startY + ypos);
+ if (t == 0)
+ mode = NORMAL;
+ else {
+ mode = DRAG;
+ dragHeight = t->height();
+ sTrack = song->tracks()->index(t);
+ setCursor(QCursor(Qt::SizeVerCursor));
+ redraw();
+ }
+ }
+ break;
+ case NORMAL:
+ break;
+ case DRAG:
+ redraw();
+ break;
+ case RESIZE:
+ {
+ if(sTrack >= 0 && (unsigned) sTrack < song->tracks()->size())
+ {
+ Track* t = song->tracks()->index(sTrack);
+ if(t)
+ {
+ int h = t->height() + delta;
+ startY = curY;
+ if (h < MIN_TRACKHEIGHT)
+ h = MIN_TRACKHEIGHT;
+ t->setHeight(h);
+ song->update(SC_TRACK_MODIFIED);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+//---------------------------------------------------------
+// mouseReleaseEvent
+//---------------------------------------------------------
+
+void TList::mouseReleaseEvent(QMouseEvent* ev)
+ {
+ if (mode == DRAG) {
+ Track* t = y2Track(ev->y() + ypos);
+ if (t) {
+ int dTrack = song->tracks()->index(t);
+ audio->msgMoveTrack(sTrack, dTrack);
+ }
+ }
+ if (mode != NORMAL) {
+ mode = NORMAL;
+ setCursor(QCursor(Qt::ArrowCursor));
+ redraw();
+ }
+ if (editTrack && editor && editor->isVisible())
+ editor->setFocus();
+ adjustScrollbar();
+ }
+
+//---------------------------------------------------------
+// wheelEvent
+//---------------------------------------------------------
+
+void TList::wheelEvent(QWheelEvent* ev)
+ {
+ int x = ev->x();
+ int y = ev->y();
+ Track* t = y2Track(y + ypos);
+ if (t == 0) {
+ emit redirectWheelEvent(ev);
+ return;
+ }
+ TrackColumn col = TrackColumn(header->logicalIndexAt(x));
+ int delta = ev->delta() / WHEEL_DELTA;
+ ev->accept();
+
+ switch (col) {
+ case COL_RECORD:
+ case COL_NONE:
+ case COL_CLASS:
+ case COL_NAME:
+ case COL_AUTOMATION:
+ break;
+ case COL_MUTE:
+ // p3.3.29
+ if (((QInputEvent*)ev)->modifiers() & Qt::ControlModifier)
+ t->setOff(!t->off());
+ else
+ {
+ if (t->off())
+ t->setOff(false);
+ else
+ t->setMute(!t->mute());
+ }
+ song->update(SC_MUTE);
+ break;
+
+ case COL_SOLO:
+ audio->msgSetSolo(t, !t->solo());
+ song->update(SC_SOLO);
+ break;
+
+ case COL_TIMELOCK:
+ t->setLocked(!t->locked());
+ break;
+
+ case COL_OPORT:
+ if (t->isMidiTrack()) {
+ MidiTrack* mt = (MidiTrack*)t;
+ int port = mt->outPort() + delta;
+
+ if (port >= MIDI_PORTS)
+ port = MIDI_PORTS-1;
+ else if (port < 0)
+ port = 0;
+ if (port != ((MidiTrack*)t)->outPort()) {
+ // Changed by T356.
+ //mt->setOutPort(port);
+ audio->msgIdle(true);
+ //audio->msgSetTrackOutPort(mt, port);
+ mt->setOutPortAndUpdate(port);
+ audio->msgIdle(false);
+
+ song->update(SC_ROUTE);
+ }
+ }
+ break;
+
+ case COL_OCHANNEL:
+ if (t->isMidiTrack()) {
+ MidiTrack* mt = (MidiTrack*)t;
+ int channel = mt->outChannel() + delta;
+
+ if (channel >= MIDI_CHANNELS)
+ channel = MIDI_CHANNELS-1;
+ else if (channel < 0)
+ channel = 0;
+ if (channel != ((MidiTrack*)t)->outChannel()) {
+ // Changed by T356.
+ //mt->setOutChannel(channel);
+ audio->msgIdle(true);
+ //audio->msgSetTrackOutChannel(mt, channel);
+ mt->setOutChanAndUpdate(channel);
+ audio->msgIdle(false);
+
+ // may result in adding/removing mixer strip:
+ //song->update(-1);
+ song->update(SC_MIDI_TRACK_PROP);
+ }
+ }
+ else {
+ int n = t->channels() + delta;
+ if (n > MAX_CHANNELS)
+ n = MAX_CHANNELS;
+ else if (n < 1)
+ n = 1;
+ if (n != t->channels()) {
+ audio->msgSetChannels((AudioTrack*)t, n);
+ song->update(SC_CHANNELS);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+//---------------------------------------------------------
+// writeStatus
+//---------------------------------------------------------
+
+void TList::writeStatus(int level, Xml& xml, const char* name) const
+ {
+ xml.tag(level++, name);
+ header->writeStatus(level, xml);
+ xml.etag(level, name);
+ }
+
+//---------------------------------------------------------
+// readStatus
+//---------------------------------------------------------
+
+void TList::readStatus(Xml& xml, const char* name)
+ {
+ 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 == header->objectName())
+ header->readStatus(xml);
+ else
+ xml.unknown("Tlist");
+ break;
+ case Xml::TagEnd:
+ if (tag == name)
+ return;
+ default:
+ break;
+ }
+ }
+ }
+
+//---------------------------------------------------------
+// setYPos
+//---------------------------------------------------------
+
+void TList::setYPos(int y)
+ {
+ int delta = ypos - y; // - -> shift up
+ ypos = y;
+
+ scroll(0, delta);
+ }
+
+//---------------------------------------------------------
+// resizeEvent
+//---------------------------------------------------------
+
+void TList::resizeEvent(QResizeEvent* /*ev*/)
+ {
+
+ }
+
+//---------------------------------------------------------
+// classesPopupMenu
+//---------------------------------------------------------
+
+void TList::classesPopupMenu(Track* t, int x, int y)
+ {
+ QMenu p;
+ p.clear();
+ p.addAction(QIcon(*addtrack_addmiditrackIcon), tr("Midi"))->setData(Track::MIDI);
+ p.addAction(QIcon(*addtrack_drumtrackIcon), tr("Drum"))->setData(Track::DRUM);
+ QAction* act = p.exec(mapToGlobal(QPoint(x, y)), 0);
+
+ if (!act)
+ return;
+
+ int n = act->data().toInt();
+ if (Track::TrackType(n) == Track::MIDI && t->type() == Track::DRUM) {
+ //
+ // Drum -> Midi
+ //
+ audio->msgIdle(true);
+ PartList* pl = t->parts();
+ MidiTrack* m = (MidiTrack*) t;
+ for (iPart ip = pl->begin(); ip != pl->end(); ++ip) {
+ EventList* el = ip->second->events();
+ for (iEvent ie = el->begin(); ie != el->end(); ++ie) {
+ Event ev = ie->second;
+ if(ev.type() == Note)
+ {
+ int pitch = ev.pitch();
+ // Changed by T356.
+ // Tested: Notes were being mixed up switching back and forth between midi and drum.
+ //pitch = drumMap[pitch].anote;
+ pitch = drumMap[pitch].enote;
+
+ ev.setPitch(pitch);
+ }
+ else
+ if(ev.type() == Controller)
+ {
+ int ctl = ev.dataA();
+ // Is it a drum controller event, according to the track port's instrument?
+ MidiController *mc = midiPorts[m->outPort()].drumController(ctl);
+ if(mc)
+ // Change the controller event's index into the drum map to an instrument note.
+ ev.setA((ctl & ~0xff) | drumMap[ctl & 0x7f].enote);
+ }
+
+ }
+ }
+ t->setType(Track::MIDI);
+ audio->msgIdle(false);
+ }
+ else if (Track::TrackType(n) == Track::DRUM && t->type() == Track::MIDI) {
+ //
+ // Midi -> Drum
+ //
+ bool change = QMessageBox::question(this, tr("Update drummap?"),
+ tr("Do you want to use same port and channel for all instruments in the drummap?"),
+ tr("&Yes"), tr("&No"), QString::null, 0, 1);
+
+ audio->msgIdle(true);
+ // Delete all port controller events.
+ //audio->msgChangeAllPortDrumCtrlEvents(false);
+ song->changeAllPortDrumCtrlEvents(false);
+
+ if (!change) {
+ MidiTrack* m = (MidiTrack*) t;
+ for (int i=0; i<DRUM_MAPSIZE; i++) {
+ drumMap[i].channel = m->outChannel();
+ drumMap[i].port = m->outPort();
+ }
+ }
+
+ //audio->msgIdle(true);
+ PartList* pl = t->parts();
+ MidiTrack* m = (MidiTrack*) t;
+ for (iPart ip = pl->begin(); ip != pl->end(); ++ip) {
+ EventList* el = ip->second->events();
+ for (iEvent ie = el->begin(); ie != el->end(); ++ie) {
+ Event ev = ie->second;
+ if (ev.type() == Note)
+ {
+ int pitch = ev.pitch();
+ pitch = drumInmap[pitch];
+ ev.setPitch(pitch);
+ }
+ else
+ {
+ if(ev.type() == Controller)
+ {
+ int ctl = ev.dataA();
+ // Is it a drum controller event, according to the track port's instrument?
+ MidiController *mc = midiPorts[m->outPort()].drumController(ctl);
+ if(mc)
+ // Change the controller event's instrument note to an index into the drum map.
+ ev.setA((ctl & ~0xff) | drumInmap[ctl & 0x7f]);
+ }
+
+ }
+
+ }
+ }
+ t->setType(Track::DRUM);
+
+ // Add all port controller events.
+ //audio->msgChangeAllPortDrumCtrlEvents(true);
+ song->changeAllPortDrumCtrlEvents(true);
+
+ audio->msgIdle(false);
+ }
+ }
+
diff --git a/attic/muse2-oom/muse2/muse/arranger/tlist.h b/attic/muse2-oom/muse2/muse/arranger/tlist.h
new file mode 100644
index 00000000..188685bc
--- /dev/null
+++ b/attic/muse2-oom/muse2/muse/arranger/tlist.h
@@ -0,0 +1,115 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: tlist.h,v 1.8.2.5 2008/01/19 13:33:46 wschweer Exp $
+// (C) Copyright 1999 Werner Schweer (ws@seh.de)
+//=========================================================
+
+#ifndef __TLIST_H__
+#define __TLIST_H__
+
+#include "track.h"
+
+#include <QWidget>
+
+class QKeyEvent;
+class QLineEdit;
+class QMouseEvent;
+class QPaintEvent;
+class QResizeEvent;
+class QScrollBar;
+class QWheelEvent;
+
+class ScrollScale;
+class Track;
+class Xml;
+class Header;
+
+enum TrackColumn {
+ COL_RECORD = 0,
+ COL_MUTE,
+ COL_SOLO,
+ COL_CLASS,
+ COL_NAME,
+ COL_OPORT,
+ COL_OCHANNEL,
+ COL_TIMELOCK,
+ COL_AUTOMATION,
+ COL_NONE = -1
+ };
+
+//---------------------------------------------------------
+// TList
+//---------------------------------------------------------
+
+class TList : public QWidget {
+ Q_OBJECT
+
+ int ypos;
+ bool editMode;
+
+ QPixmap bgPixmap; // background Pixmap
+ bool resizeFlag; // true if resize cursor is shown
+
+ Header* header;
+ QScrollBar* _scroll;
+ QLineEdit* editor;
+ Track* editTrack;
+
+ int startY;
+ int curY;
+ int sTrack;
+ int dragHeight;
+ int dragYoff;
+
+ enum { NORMAL, START_DRAG, DRAG, RESIZE} mode;
+
+ virtual void paintEvent(QPaintEvent*);
+ virtual void mousePressEvent(QMouseEvent* event);
+ virtual void mouseDoubleClickEvent(QMouseEvent*);
+ virtual void mouseMoveEvent(QMouseEvent*);
+ virtual void mouseReleaseEvent(QMouseEvent*);
+ virtual void keyPressEvent(QKeyEvent* e);
+ virtual void wheelEvent(QWheelEvent* e);
+
+ void portsPopupMenu(Track*, int, int);
+ void oportPropertyPopupMenu(Track*, int x, int y);
+ void moveSelection(int n);
+ void adjustScrollbar();
+ void paint(const QRect& r);
+ virtual void resizeEvent(QResizeEvent*);
+ void redraw(const QRect& r);
+ Track* y2Track(int) const;
+ void classesPopupMenu(Track*, int x, int y);
+ TrackList getRecEnabledTracks();
+ void setHeaderToolTips();
+
+ private slots:
+ void returnPressed();
+ void songChanged(int flags);
+ void changeAutomation(QAction*);
+
+ signals:
+ ///void selectionChanged();
+ void selectionChanged(Track*);
+ void keyPressExt(QKeyEvent*);
+ void redirectWheelEvent(QWheelEvent*);
+
+ public slots:
+ void tracklistChanged();
+ void setYPos(int);
+ void redraw();
+ void selectTrack(Track*);
+ void selectTrackAbove();
+ void selectTrackBelow();
+
+ public:
+ TList(Header*, QWidget* parent, const char* name);
+ void setScroll(QScrollBar* s) { _scroll = s; }
+ Track* track() const { return editTrack; }
+ void writeStatus(int level, Xml&, const char* name) const;
+ void readStatus(Xml&, const char* name);
+ };
+
+#endif
+
diff --git a/attic/muse2-oom/muse2/muse/arranger/trackautomationview.cpp b/attic/muse2-oom/muse2/muse/arranger/trackautomationview.cpp
new file mode 100644
index 00000000..8f7cfb12
--- /dev/null
+++ b/attic/muse2-oom/muse2/muse/arranger/trackautomationview.cpp
@@ -0,0 +1,52 @@
+#include "trackautomationview.h"
+#include "math.h"
+
+#include <QPainter>
+#include <QPaintEvent>
+
+#include "track.h"
+
+TrackAutomationView::TrackAutomationView(QWidget *parent, Track *t) : QWidget(parent)
+{
+ printf("created trackautomationview\n");
+ _t = t;
+ //show();
+}
+
+void TrackAutomationView::paintEvent(QPaintEvent* e)
+{
+ QPainter p(this);
+ const QRect &r = e->rect();
+
+ // temporary solution, audio track drawing moved here.
+ // best would be to get transparency to work correctly
+ p.setPen(QPen(Qt::black, 2, Qt::SolidLine));
+ p.setBrush(Qt::gray);
+ p.drawRect(r);
+
+ int height=r.bottom()-r.top();
+ if( _t->type()>1) { // audio type
+ double volume = ((AudioTrack*)_t)->volume();
+ double dbvolume = (20.0*log10(volume)+60) /70.0; // represent volume between 0 and 1
+ if (dbvolume < 0) dbvolume =0.0;
+ printf("height=%d volume=%f dbvolume=%f\n", height, volume, dbvolume);
+ p.setPen(QPen(Qt::yellow,1,Qt::SolidLine));
+ p.drawLine(r.left(),r.bottom()-dbvolume*height,r.right(),r.bottom()-dbvolume*height);
+
+ }
+
+
+
+ printf("paintEvent\n");
+}
+
+void TrackAutomationView::collectAutomationData()
+{
+ // here we should collect all automation data that is currently selected for viewing and
+ // prepare an event list that is easy to draw in paintEvent
+ // the main reason being that the event list in it's entirety likely contains too much data to
+ // be processed in the paintEvent. Better to preprocess.
+
+// CtrlListList cll =((AudioTrack*)_t)->controller();
+// cll.count()
+}
diff --git a/attic/muse2-oom/muse2/muse/arranger/trackautomationview.h b/attic/muse2-oom/muse2/muse/arranger/trackautomationview.h
new file mode 100644
index 00000000..2ef05125
--- /dev/null
+++ b/attic/muse2-oom/muse2/muse/arranger/trackautomationview.h
@@ -0,0 +1,20 @@
+#ifndef TRACKAUTOMATIONVIEW_H
+#define TRACKAUTOMATIONVIEW_H
+
+class QPaintEvent;
+class QWidget;
+
+#include "track.h"
+
+class TrackAutomationView : public QWidget
+{
+ Track *_t;
+ void paintEvent(QPaintEvent *e);
+ std::map<int,int> automationList;
+public:
+ TrackAutomationView(QWidget *parent, Track *t);
+ Track *track() { return _t; }
+ void collectAutomationData();
+};
+
+#endif // TRACKAUTOMATIONVIEW_H