//=========================================================
//  MusE
//  Linux Music Editor
//    $Id: tlist.cpp,v 1.2 2003/10/29 22:02:27 spamatica Exp $
//  (C) Copyright 1999 Werner Schweer (ws@seh.de)
//=========================================================

#include <qfileinfo.h>
#include <qpainter.h>
#include <qlineedit.h>
#include <qpopupmenu.h>
#include <qmessagebox.h>
#include <qscrollbar.h>
#include <cmath>

#include "globals.h"
#include "icons.h"
#include "scrollscale.h"
#include "tlist.h"
#include "xml.h"
#include "driver/mididev.h"
#include "midiport.h"
#include "comment.h"
#include "track.h"
#include "song.h"
#include "header.h"
#include "midithread.h"
#include "node.h"
#include "audio.h"
#include "app.h"

static const int MIN_TRACKHEIGHT = 20;

//---------------------------------------------------------
//   THeaderTip::maybeTip
//---------------------------------------------------------

void THeaderTip::maybeTip(const QPoint &pos)
      {
      Header* w  = (Header*)parentWidget();
      int section = w->sectionAt(pos.x());
      if (section == -1)
            return;
      QRect r(w->sectionPos(section), 0, w->sectionSize(section),
         w->height());
      QString p;
      switch (section) {
            case COL_RECORD:   p = QHeader::tr("Enable Recording"); break;
            case COL_ACTIVITY: p = QHeader::tr("Track Activity"); break;
            case COL_MUTE:     p = QHeader::tr("Mute Indicator"); break;
            case COL_SOLO:     p = QHeader::tr("Solo/Pre Fader Listening"); break;
            case COL_CLASS:    p = QHeader::tr("Track Type"); break;
            case COL_NAME:     p = QHeader::tr("Track Name"); break;
            case COL_OCHANNEL: p = QHeader::tr("Output Channel Number"); break;
            case COL_OPORT:    p = QHeader::tr("Output Port"); break;
            case COL_TIMELOCK: p = QHeader::tr("Time Lock"); break;
            default: return;
            }
      tip(r, p);
      }

//---------------------------------------------------------
//   TList
//---------------------------------------------------------

TList::TList(Header* hdr, QWidget* parent, const char* name)
   : QWidget(parent, name, WRepaintNoErase | WResizeNoErase)
      {
      ypos = 0;
      setFocusPolicy(QWidget::StrongFocus);
      setMouseTracking(true);
      header    = hdr;

      scroll    = 0;
      editTrack = 0;
      editor    = 0;
      mode      = NORMAL;
      activityColor = black;

      setBackgroundMode(NoBackground);
      brush.setStyle(SolidPattern);
      brush.setColor(palette().active().background());

      connect(song, SIGNAL(heartBeat()),               SLOT(updateActivity()));
      connect(song, SIGNAL(recordFlagChanged(Track*)), SLOT(redraw()));
      connect(song, SIGNAL(songChanged(int)),          SLOT(songChanged(int)));
      }

//---------------------------------------------------------
//   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))
            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)
      {
      if (!pmValid)
            paint(ev->rect());
      bitBlt(this, ev->rect().topLeft(), &pm, ev->rect(), CopyROP, true);
      }

//---------------------------------------------------------
//   redraw
//---------------------------------------------------------

void TList::redraw()
      {
      paint(QRect(0, 0, pm.width(), pm.height()));
      update();
      }

//---------------------------------------------------------
//   redraw
//---------------------------------------------------------

void TList::redraw(const QRect& r)
      {
      paint(r);
      update(r);
      }

//---------------------------------------------------------
//   paint
//---------------------------------------------------------

void TList::paint(const QRect& r)
      {
      if (!isVisible())
            return;
      QRect rect(r);
      if (!pmValid) {
            pmValid = true;
            rect = QRect(0, 0, pm.width(), pm.height());
            }
      QPainter p(&pm);

      if (bgPixmap.isNull())
            p.fillRect(rect, brush);
      else
            p.drawTiledPixmap(rect, bgPixmap, QPoint(rect.x(), ypos + rect.y()));
      p.setClipRegion(rect);

      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;
            int trackHeight = track->height();
            if (yy >= (y + h))
                  break;
            if ((yy + trackHeight) < y)
                  continue;
            //
            // clear one row
            //
            if ((*i)->selected()) {
                  p.fillRect(x1, yy, w, trackHeight, palette().active().highlight());
                  p.setPen(palette().active().highlightedText());
                  }
            else {
                  p.setPen(palette().active().text());
                  }

            Track::TrackType type = (*i)->type();
            int x = 0;
            for (int index = 0; index < header->count(); ++index) {
                  int section = header->mapToSection(index);
                  int w   = header->sectionSize(section);
                  QRect r = p.xForm(QRect(x+2, yy, w-4, trackHeight));

                  switch (section) {
                        case COL_RECORD:
                              drawCenteredPixmap(p,
                                 (*i)->recordFlag() ? reddotIcon : darkreddotIcon, r);
                              break;
                        case COL_CLASS:
                              {
                              const QPixmap* pm = 0;
                              switch((*i)->type()) {
                                    case Track::MIDI: pm = noteIcon;  break;
                                    case Track::DRUM: pm = stickIcon; break;
                                    case Track::WAVE: pm = waveIcon;  break;
                                    }
                              drawCenteredPixmap(p, pm, r);
                              }
                              break;
                        case COL_MUTE:
                              if ((*i)->node()->off())
                                    drawCenteredPixmap(p, offIcon, r);
                              else if ((*i)->node()->mute())
                                    drawCenteredPixmap(p, editmuteSIcon, r);
                              break;
                        case COL_SOLO:
                              if ((*i)->node()->solo())
                                    drawCenteredPixmap(p, bluedotIcon, r);
                              break;
                        case COL_TIMELOCK:
                              if ((type == Track::MIDI || type == Track::DRUM)
                                 && (*i)->locked()) {
                                    drawCenteredPixmap(p, lockIcon, r);
                                    }
                              break;
                        case COL_NAME:
                              p.drawText(r, Qt::AlignVCenter|Qt::AlignLeft, (*i)->name());
                              break;
                        case COL_OCHANNEL:
                              {
                              QString s;
                              int n;
                              if (type == Track::WAVE) {
                                    // show number of ports
                                    n = ((WaveTrack*)(*i))->ports();
                                    }
                              else {
                                    n = (*i)->outChannel() + 1;
                                    }
                              s.setNum(n);
                              p.drawText(r, Qt::AlignVCenter|Qt::AlignLeft, s);
                              }
                              break;
                        case COL_OPORT:
                              {
                              int outport = (*i)->outPort() + 1;
                              QString s;
                              s.sprintf("%d(none)", outport);
                              switch((*i)->type()) {
                                    case Track::WAVE:
                                          {
                                          WaveTrack* wt = (WaveTrack*)(*i);
                                          s = node2Name(wt->route());
                                          }
                                          break;
                                    case Track::MIDI:
                                    case Track::DRUM:
                                          {
                                          MidiDevice* dev = ((MidiTrack*)(*i))->outDevice();
                                          if (dev)
                                                s.sprintf("%d(%s)", outport,
                                                    dev->name().latin1());
                                          }
                                          break;
                                    }
                              p.drawText(r, Qt::AlignVCenter|Qt::AlignLeft, s);
                              }
                              break;
                        default:
                              break;
                        }
                  x += header->sectionSize(section);
                  }
            p.setPen(gray);
            p.drawLine(x1, yy, x2, yy);
            }
      p.drawLine(x1, yy, x2, yy);

      if (mode == DRAG) {
            int yy = curY - dragYoff;
            p.setPen(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(gray);
      for (int index = 0; index < n-1; index++) {
            int section = header->mapToSection(index);
            xpos += header->sectionSize(section);
            p.drawLine(xpos, 0, xpos, height());
            }
      }

//---------------------------------------------------------
//   returnPressed
//---------------------------------------------------------

void TList::returnPressed()
      {
      editor->hide();
      if (editor->text() != editTrack->name()) {
            Track* track = editTrack->clone();
            track->setName(editor->text());
            midiThread->msgChangeTrack(editTrack, track);
            }
      editTrack = 0;
      setFocus();
      }

//---------------------------------------------------------
//   adjustScrollbar
//---------------------------------------------------------

void TList::adjustScrollbar()
      {
      int h = 0;
      TrackList* l = song->tracks();
      for (iTrack it = l->begin(); it != l->end(); ++it) {
            h += (*it)->height();
            (*it)->setY(h);
            }
      scroll->setMaxValue(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();
      bool shift  = ev->state() & ShiftButton;
      int section = header->sectionAt(x);
      if (section == -1)
            return;

      Track* t = y2Track(ev->y() + ypos);

      if (t == 0) {
            Track* t = song->addTrack();
            if (!shift)
                  song->tracks()->deselect();
            t->setSelected(true);
            emit selectionChanged();
            // adjustScrollbar();
            }
      else {
            int colx = header->sectionPos(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);
                  editor->show();
                  }
            else
                  mousePressEvent(ev);
            }
      }

//---------------------------------------------------------
//   portsPopupMenu
//---------------------------------------------------------

void TList::portsPopupMenu(Track* t, int x, int y)
      {
      switch(t->type()) {
            case Track::MIDI:
            case Track::DRUM:
                  {
                  MidiTrack* track = (MidiTrack*)t;
                  QPopupMenu* p = midiPortsPopup(0);
                  int n = p->exec(mapToGlobal(QPoint(x, y)), 0);
                  if (n != -1) {
                        track->setOutPort(n);
                        song->update();
                        }
                  delete p;
                  }
                  break;
            case Track::WAVE:
                  break;
            }
      }

//---------------------------------------------------------
//   oportPropertyPopupMenu
//---------------------------------------------------------

void TList::oportPropertyPopupMenu(Track* t, int x, int y)
      {
      if (t->type() != Track::MIDI && t->type() != Track::DRUM)
            return;
      int oPort      = t->outPort();
      MidiPort* port = &midiPorts[oPort];

      QPopupMenu* p = new QPopupMenu(this);
      p->setCheckable(true);
      p->insertItem(tr("Show Gui"), 0);

      p->setItemEnabled(0, port->hasGui());
      p->setItemChecked(0, port->guiVisible());

      int n = p->exec(mapToGlobal(QPoint(x, y)), 0);
      if (n == 0) {
            port->showGui(!port->guiVisible());
            }
      delete p;
      }

//---------------------------------------------------------
//   tracklistChanged
//---------------------------------------------------------

void TList::tracklistChanged()
      {
      redraw();
      }

//---------------------------------------------------------
//   keyPressEvent
//---------------------------------------------------------

void TList::keyPressEvent(QKeyEvent* e)
      {
      int key = e->key();
      switch (key) {
            case Key_Up:
                  moveSelection(-1);
                  break;
            case Key_Down:
                  moveSelection(1);
                  break;
            default:
                  e->ignore();
                  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;
      for (iTrack t = tracks->begin(); t != tracks->end(); ++t) {
            iTrack s = t;
            if ((*t)->selected()) {
                  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);
                  if (editTrack && editTrack != *t)
                        returnPressed();
                  redraw();
                  break;
                  }
            }
      emit selectionChanged();
      }

//---------------------------------------------------------
//   mousePressEvent
//---------------------------------------------------------

void TList::mousePressEvent(QMouseEvent* ev)
      {
      int x       = ev->x();
      int y       = ev->y();
      int button  = ev->button();
      bool shift  = ev->state() & ShiftButton;
      Track* t    = y2Track(y + ypos);

      TrackColumn col = TrackColumn(header->sectionAt(x));
      if (t == 0) {
            if (button == QMouseEvent::RightButton) {
                  QPopupMenu* p = new QPopupMenu(this);
                  p->clear();
                  p->insertItem(*noteIcon, tr("Add Midi Track"), 0);
                  p->insertItem(*stickIcon, tr("Add Drum Track"), 1);
                  p->insertItem(*waveIcon, tr("Add Wave Track"), 2);
                  int n = p->exec(ev->globalPos(), 0);
                  switch (n) {
                        case -1:
                              break;
                        case 0:     // add midi track
                              t = song->addTrack(Track::MIDI);
                              break;
                        case 1:     // add drum track
                              t = song->addTrack(Track::DRUM);
                              break;
                        case 2:     // add wave track
                              t = song->addTrack(Track::WAVE);
                              break;
                        }
                  if (t) {
                        song->tracks()->deselect();
                        t->setSelected(true);
                        emit selectionChanged();
                        adjustScrollbar();
                        }
                 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) && y < (ty+2))
                        break;
                  }
            return;
            }
      mode = START_DRAG;

      switch (col) {
            case COL_RECORD:
                  if (t->type() == Track::WAVE)
                        song->setRecordFlag(t, !t->recordFlag() && ((WaveTrack*)t)->canRecord());
                  else
                        song->setRecordFlag(t, !t->recordFlag());
                  break;
            case COL_NONE:
            case COL_ACTIVITY:
                  break;
            case COL_CLASS:
                  classesPopupMenu(tracks->index(t), x, t->y() - ypos);
                  break;
            case COL_OPORT:
                  if (button == QMouseEvent::LeftButton)
                        portsPopupMenu(t, x, t->y() - ypos);
                  else if (button == QMouseEvent::RightButton)
                        oportPropertyPopupMenu(t, x, t->y() - ypos);
                  break;
            case COL_MUTE:
                  {
                  SNode* node = t->node();
                  if (node->off())
                        node->setOff(false);
                  else
                        node->setMute(!node->mute());
                  }
                  break;

            case COL_SOLO:
                  {
                  SNode* ss = t->node();
                  ss->setSolo(!ss->solo());
                  }
                  break;

            case COL_NAME:
                  if (button == QMouseEvent::LeftButton) {
                        if (!shift) {
                              tracks->deselect();
                              t->setSelected(true);
                              }
                        else
                              t->setSelected(!t->selected());
                        if (editTrack && editTrack != t)
                              returnPressed();
                        emit selectionChanged();
                        }
                  else if (button == QMouseEvent::RightButton) {
                        QPopupMenu* p = new QPopupMenu(this);
                        p->clear();
                        p->insertItem(*deleteIcon, tr("Delete Track"), 0);
                        p->insertItem(tr("Track Comment"), 1);
                        int n = p->exec(ev->globalPos(), 0);
                        if (n != -1) {
                              switch (n) {
                                    case 0:     // delete track
                                          for (iTrack it = tracks->begin(); it != tracks->end(); ++it)
                                                (*it)->setSelected(false);
                                          t->setSelected(true);
                                          song->startUndo();
                                          midiThread->msgRemoveTracks();
                                          song->endUndo(SC_TRACK_REMOVED);
                                          break;

                                    case 1:     // show track comment
                                          {
                                          TrackComment* tc = new TrackComment(t, 0);
                                          tc->show();
                                          }
                                          break;

                                    default:
                                          printf("action %d\n", n);
                                          break;
                                    }

                              }
                        delete p;
                        }
                  break;

            case COL_TIMELOCK:
                  t->setLocked(!t->locked());
                  break;

            case COL_OCHANNEL:
                  {
                  MidiTrack* mt = dynamic_cast<MidiTrack*>(t);
                  if (mt == 0)
                        break;
                  int channel = mt->outChannel();
                  if (button == QMouseEvent::RightButton) {
                        if (channel < 15)
                              ++channel;
                        }
                  else if (button == QMouseEvent::MidButton) {
                        if (channel > 0)
                              --channel;
                        }
                  if (channel != t->outChannel()) {
                        mt->setOutChannel(channel);
                        song->update();
                        }
                  }
            }
      redraw();
      }

//---------------------------------------------------------
//   mouseMoveEvent
//---------------------------------------------------------

void TList::mouseMoveEvent(QMouseEvent* ev)
      {
      if (ev->state() == 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) && y < (ty+2)) {
                        if (!resizeFlag) {
                              resizeFlag = true;
                              setCursor(QCursor(splitVCursor));
                              }
                        break;
                        }
                  }
            if (it == tracks->end() && resizeFlag) {
                  setCursor(QCursor(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;
                  mode = DRAG;
                  {
                  Track* t   = y2Track(startY + ypos);
                  dragHeight = t->height();
                  sTrack     = song->tracks()->index(t);
                  }
                  setCursor(QCursor(sizeVerCursor));
                  redraw();
                  break;
            case NORMAL:
                  break;
            case DRAG:
                  redraw();
                  break;
            case RESIZE:
                  {
                  Track* t = song->tracks()->findIdx(sTrack);
                  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);
                  midiThread->msgMoveTrack(sTrack, dTrack);
                  }
            }
      if (mode != NORMAL) {
            mode = NORMAL;
            setCursor(QCursor(arrowCursor));
            redraw();
            }
      if (editTrack)
            editor->setFocus();
      adjustScrollbar();
      }

//---------------------------------------------------------
//   updateActivity
//---------------------------------------------------------

extern "C" double log2(double);

void TList::updateActivity()
      {
      TrackList* tl = song->tracks();
      int idx = 0;
      QPainter p(this);
      int y = 0;
      for (iTrack i = tl->begin(); i != tl->end();
         ++idx, y += (*i)->height(), ++i) {
            // normal cast does not work!
            SNode* ss = (*i)->node();
            if (ss->activity() == ss->lastActivity())
                  continue;
            int w = header->sectionSize(COL_ACTIVITY);
            int x = header->sectionPos(COL_ACTIVITY);

            int val  = ss->activity();

            double ko = double(w) / 10.0;
            int nval  = lrint(log2(double(val)) * ko);
            if (nval < 0)
                  nval = 0;
            if (nval > w)
                  nval = w;

            ss->setLastActivity(val);
            int mval = val/10;
            if (mval == 0)
                  mval = 1;
            val -= mval;              // ramp down
            if (val < 0)
                  val = 0;
            ss->setActivity(val);

            int th = (*i)->height();
            if (activityMode == 0) {
                  p.fillRect(x+1, y+1, nval, th-1, activityColor);
                  }
            else {
	            for (int count = 1; count < nval; count++) {
	                  int percent = (count * 0xff) / w;
	                  int r = (percent<0x7f) ? percent * 2 : 0xff;
	                  int g = (percent>0x7f) ? (0x1ff-(percent*2)) : 0xff;
	                  int b = 0;
	                  if (!(count % 2))
	                        r = g = b = 0xff;
	                  p.fillRect(count+x, y+1, 1, -1, QBrush(QColor(r, g, b)));
	                  }
	            }
            p.fillRect(x+nval+1, y+1, w-nval-1, th-1, white);
            }
      }

//---------------------------------------------------------
//   checkEmpty
//---------------------------------------------------------

static bool checkEmpty(Track* t, QWidget* parent)
      {
      if (t->parts()->size()) {
            QMessageBox::information(parent, QString("MusE"),
               QWidget::tr("Cannot transform non empty track"));
            return true;
            }
      return false;
      }

//---------------------------------------------------------
//   classesPopupMenu
//---------------------------------------------------------

void TList::classesPopupMenu(int track, int x, int y)
      {
      TrackList* tracks = song->tracks();
      Track* t = tracks->findIdx(track);
      QPopupMenu p(this);
      p.clear();
      p.insertItem(*noteIcon, tr("Midi"), Track::MIDI);
      p.insertItem(*stickIcon, tr("Drum"), Track::DRUM);
      p.insertItem(*waveIcon, tr("Wave"), Track::WAVE);
      int n = p.exec(mapToGlobal(QPoint(x, y)), 0);

      if (n == -1)
            return;

      QString name  = t->name();
      bool selected = t->selected();

      switch (Track::TrackType(n)) {
            case Track::MIDI:
                  if (t->type() == Track::DRUM)
                        t->setType(Track::MIDI);
                  else if (t->type() == Track::WAVE) {
                        if (checkEmpty(t, this))
                              break;
                        MidiTrack* mt = new MidiTrack(name);
                        WaveTrack* wt = (WaveTrack*) t;
                        mt->setSn(t->sn());
                        mt->setSelected(selected);
                        mt->setMute(wt->mute());
                        mt->setSolo(wt->solo());
                        midiThread->msgChangeTrack(t, mt);
                        }
                  break;
            case Track::DRUM:
                  if (t->type() == Track::MIDI)
                        t->setType(Track::DRUM);
                  else if (t->type() == Track::WAVE) {
                        if (checkEmpty(t, this))
                              break;
                        MidiTrack* mt = new MidiTrack(name);
                        WaveTrack* wt = (WaveTrack*) t;
                        mt->setSn(t->sn());
                        mt->setType(Track::DRUM);
                        mt->setSelected(selected);
                        mt->setMute(wt->mute());
                        mt->setSolo(wt->solo());
                        midiThread->msgChangeTrack(t, mt);
                        }
                  break;
            case Track::WAVE:
                  if (t->type() == Track::MIDI || t->type() == Track::DRUM) {
                        if (checkEmpty(t, this))
                              break;
                        MidiTrack* mt = (MidiTrack*) t;
                        // MUTABOR!
                        bool mute = mt->mute();
                        bool solo = mt->mute();

                  if (WaveTrack::firstWaveTrack == true && QFileInfo(museProject).isRelative()) {
                        if(QMessageBox::information( this, "MusE",
                                 tr("This is your first wave track and the project\n"
                                    "doesn't appear to be saved yet.\n\n"
                                    "It is recommended that you save a project file now!\n\n"
                                    "By doing that you are implicitly selecting a folder\n"
                                    "where the audio files will end up."), tr("Save dialog"), tr("Cancel"),
				    QString::null ,0,1 ) == 0) {
				           muse->saveAs();
                                 }
                        }

                        WaveTrack* wt = new WaveTrack(name);

                        wt->setSn(t->sn());
                        wt->setSelected(selected);
                        wt->setMute(mute);
                        wt->setSolo(solo);
                        midiThread->msgChangeTrack(t, wt);

                        if (selected)
                              emit selectionChanged();
                        }
                  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->name())
                              header->readStatus(xml);
                        else
                              xml.unknown("Tlist");
                        break;
                  case Xml::TagEnd:
                        if (tag == name)
                              return;
                  default:
                        break;
                  }
            }
      }

//---------------------------------------------------------
//   setActivityMode
//---------------------------------------------------------

void TList::setActivityMode(int i)
      {
      activityMode = i;
      }

//---------------------------------------------------------
//   setActivityColor
//---------------------------------------------------------

void TList::setActivityColor(QColor c)
      {
      activityColor = c;
      }

//---------------------------------------------------------
//   setYPos
//---------------------------------------------------------

void TList::setYPos(int y)
      {
      int delta  = ypos - y;         // -  -> shift up
      ypos  = y;
      if (pm.isNull())
            return;
      if (!pmValid) {
            redraw();
            return;
            }
      int w = width();
      int h = height();
      QRect r;
      if (delta >= h || delta <= -h)
            r = QRect(0, 0, w, h);
      else if (delta < 0) {   // shift up
            bitBlt(&pm,  0, 0, &pm, 0, -delta, w, h + delta, CopyROP, true);
            r = QRect(0, h + delta, w, -delta);
            }
      else {                  // shift down
            bitBlt(&pm,  0, delta, &pm, 0, 0, w, h-delta, CopyROP, true);
            r = QRect(0, 0, w, delta);
            }
      paint(r);
      update();
      }

//---------------------------------------------------------
//   resizeEvent
//---------------------------------------------------------

void TList::resizeEvent(QResizeEvent* ev)
      {
      pm.resize(ev->size());
      pmValid = false;
      }

