//=========================================================
//  MusE
//  Linux Music Editor
//    $Id: drumedit.cpp,v 1.1.1.1 2003/10/29 10:06:08 wschweer Exp $
//  (C) Copyright 1999 Werner Schweer (ws@seh.de)
//=========================================================

#include "drumedit.h"

#include "mtscale.h"
#include "scrollscale.h"
#include "intlabel.h"
#include "xml.h"
#include "dlist.h"
#include "dcanvas.h"
#include "ttoolbar.h"
#include "tb1.h"
#include "splitter.h"
#include "utils.h"
#include "../ctrl/ctrledit.h"
#include "vscale.h"
#include "swidget.h"
#include "globals.h"
#include "icons.h"
#include "event.h"
#include "filedialog.h"
#include "drummap.h"
#include "midithread.h"

#include <qtoolbutton.h>
#include <qaccel.h>
#include <qlayout.h>
#include <qhbox.h>
#include <qsizegrip.h>
#include <qscrollbar.h>
#include <qlabel.h>
#include <qpushbutton.h>
#include <qradiobutton.h>
#include <qbuttongroup.h>
#include <qlistbox.h>
#include <qpopupmenu.h>
#include <qmenubar.h>
#include <qtooltip.h>
#include <qapplication.h>
#include <qclipboard.h>

static const char* map_file_pattern[] = {
      "presets (*.map *.map.gz *.map.bz2)",
      "All Files (*)",
      0
      };
int DrumEdit::_quantInit = 96;
int DrumEdit::_rasterInit = 96;
int DrumEdit::_widthInit = 600;
int DrumEdit::_heightInit = 400;
int DrumEdit::_dlistWidthInit = 50; 
int DrumEdit::_dcanvasWidthInit = 300; 

static const int xscale = -10;
static const int yscale = 1;
static const int drumeditTools = PointerTool | PencilTool | RubberTool;

//---------------------------------------------------------
//   DWhatsThis::text
//---------------------------------------------------------

QString DWhatsThis::text(const QPoint& pos)
      {
      int section = header->sectionAt(pos.x());
      if (section == -1)
            return QString::null;
      switch(section) {
            case 0: return  QHeader::tr("mute instrument"); break;
            case 1: return  QHeader::tr("sound name"); break;
            case 2: return  QHeader::tr("quantisation"
                  "\ncurrently not used"); break;
            case 3: return  QHeader::tr("this input note triggers the sound"); break;
            case 4: return  QHeader::tr("note length"); break;
            case 5: return  QHeader::tr("this note is send for the sound"); break;
            case 6: return  QHeader::tr("output channel"
                  "\ncurrently not used"); break;
            case 7: return  QHeader::tr("output port"
                  "\ncurrently not used"); break;
            case 8: return  QHeader::tr("velocity level 1"); break;
            case 9: return  QHeader::tr("velocity level 2"); break;
            case 10: return QHeader::tr("velocity level 3"); break;
            case 11: return QHeader::tr("velocity level 4"); break;
            default: break;
            }
      return QString::null;
      }

//---------------------------------------------------------
//   DHeaderTip::maybeTip
//---------------------------------------------------------

void DHeaderTip::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 0:  p = QHeader::tr("mute instrument"); break;
            case 1:  p = QHeader::tr("sound name"); break;
            case 2:  p = QHeader::tr("quantisation"); break;
            case 3:  p = QHeader::tr("this input note triggers the sound"); break;
            case 4:  p = QHeader::tr("note length"); break;
            case 5:  p = QHeader::tr("this note is send for the sound"); break;
            case 6:  p = QHeader::tr("output channel"); break;
            case 7:  p = QHeader::tr("output port"); break;
            case 8:  p = QHeader::tr("velocity level 1"); break;
            case 9:  p = QHeader::tr("velocity level 2"); break;
            case 10: p = QHeader::tr("velocity level 3"); break;
            case 11: p = QHeader::tr("velocity level 4"); break;
            default: return;
            }
      tip(r, p);
      }

//---------------------------------------------------------
//   closeEvent
//---------------------------------------------------------

void DrumEdit::closeEvent(QCloseEvent* e)
      {
      //Store values of the horizontal splitter 
      QValueList<int> sizes = split2->sizes(); 
      QValueList<int>::Iterator it = sizes.begin(); 
      _dlistWidthInit = *it; //There are only 2 values stored in the sizelist, size of dlist widget and dcanvas widget 
      it++; 
      _dcanvasWidthInit = *it; 
      emit deleted((int)this);
      e->accept();
      }

//---------------------------------------------------------
//   DrumEdit
//---------------------------------------------------------

DrumEdit::DrumEdit(PartList* pl, QWidget* parent, const char* name)
   : MidiEditor(_quantInit, _rasterInit, pl, parent, name)
      {
      resize(_widthInit, _heightInit);
      selEvent = 0;
      selPart  = 0;
      //---------Pulldown Menu----------------------------
      QPopupMenu* menuFile = new QPopupMenu(this);
      menuBar()->insertItem(tr("&File"), menuFile);

      menuFile->insertItem(*openIcon, tr("Load Map"), DrumCanvas::CMD_LOAD);
      menuFile->setAccel(CTRL+Key_O, DrumCanvas::CMD_LOAD);
      menuFile->insertItem(*saveIcon, tr("Save Map"), DrumCanvas::CMD_SAVE);
      menuFile->setAccel(CTRL+Key_S, DrumCanvas::CMD_SAVE);

      menuEdit = new QPopupMenu(this);
      menuBar()->insertItem(tr("&Edit"), menuEdit);
      undoRedo->addTo(menuEdit);
      QAccel* qa = new QAccel(this); 
      qa->connectItem(qa->insertItem(CTRL+Key_Z), song, SLOT(undo())); 
      menuEdit->insertSeparator();
      menuEdit->insertItem(tr("Cut"),   DrumCanvas::CMD_CUT);
      menuEdit->setAccel(CTRL+Key_X,    DrumCanvas::CMD_CUT);
      menuEdit->insertItem(tr("Copy"),  DrumCanvas::CMD_COPY);
      menuEdit->setAccel(CTRL+Key_C,    DrumCanvas::CMD_COPY);
      menuEdit->insertItem(tr("Paste"), DrumCanvas::CMD_PASTE);
      menuEdit->setAccel(CTRL+Key_V,    DrumCanvas::CMD_PASTE);
      menuEdit->insertSeparator();
      menuEdit->insertItem(tr("Delete Events"), DrumCanvas::CMD_DEL);
      menuEdit->setAccel(Key_Delete, DrumCanvas::CMD_DEL);
      menuEdit->insertSeparator();
      menuEdit->insertItem(tr("Set fixed length"), DrumCanvas::CMD_FIXED_LEN); 
      menuEdit->setAccel(ALT+Key_L,     DrumCanvas::CMD_FIXED_LEN); 

      QPopupMenu* menuSelect = new QPopupMenu(this);
      menuSelect->insertItem(tr("Select All"),   DrumCanvas::CMD_SELECT_ALL);
      menuSelect->insertItem(tr("Select None"),  DrumCanvas::CMD_SELECT_NONE);
      menuSelect->insertItem(tr("Invert"),       DrumCanvas::CMD_SELECT_INVERT);
      menuSelect->insertSeparator();
      menuSelect->insertItem(tr("Inside Loop"),  DrumCanvas::CMD_SELECT_ILOOP);
      menuSelect->insertItem(tr("Outside Loop"), DrumCanvas::CMD_SELECT_OLOOP);
      menuEdit->insertItem(tr("&Select"), menuSelect);

      connect(menuFile, SIGNAL(activated(int)), SLOT(cmd(int)));
      connect(menuEdit, SIGNAL(activated(int)), SLOT(cmd(int)));
      connect(menuSelect, SIGNAL(activated(int)),    SLOT(cmd(int)));

      //---------------------------------------------------
      //    Toolbars
      //---------------------------------------------------

      tools = new QToolBar(this, "drum-tools");
      new QToolButton(*openIcon, tr("Load Drummap"),
                  QString::null, this, SLOT(load()), 
                  tools, "load drummap from file"); 

      new QToolButton(*saveIcon, tr("Store Drummap"),
                  QString::null, 
                  this, SLOT(save()), 
                  tools, "store drummap to file"); 

      QWhatsThis::whatsThisButton(tools);

      tools->addSeparator();
      undoRedo->addTo(tools);
      tools->addSeparator();

      srec  = new QToolButton(tools, "srec");
      QToolTip::add(srec, tr("Step Record"));
      srec->setPixmap(*steprecIcon);
      srec->setToggleButton(true);

      midiin  = new QToolButton(tools, "midiin");
      QToolTip::add(midiin, tr("Midi Input"));
      midiin->setPixmap(*midiinIcon);
      midiin->setToggleButton(true);

      tools2 = new EditToolBar(this, drumeditTools);

      QToolBar* transport = new QToolBar(this);
      transportAction->addTo(transport);

      // dontīt show pitch value in toolbar
      toolbar = new Toolbar1(this, _rasterInit, _quantInit, false);
      info    = new NoteInfo(this);

      //---------------------------------------------------
      //    split
      //---------------------------------------------------

      split1            = new Splitter(Vertical, mainw, "split1");
      QPushButton* ctrl = new QPushButton(tr("ctrl"), mainw, "Ctrl");
      ctrl->setFont(font3);
      hscroll           = new ScrollScale(-25, -2, xscale, 20000, Horizontal, mainw);
      ctrl->setFixedSize(50, hscroll->sizeHint().height());
      QToolTip::add(ctrl, tr("Add Controller View"));

      QSizeGrip* corner = new QSizeGrip(mainw);
      corner->setFixedHeight(hscroll->sizeHint().height());

      mainGrid->setRowStretch(0, 100);
      mainGrid->setColStretch(1, 100);

      mainGrid->addMultiCellWidget(split1, 0, 0, 0, 2);
      mainGrid->addWidget(ctrl,    1, 0);
      mainGrid->addWidget(hscroll, 1, 1);
      mainGrid->addWidget(corner,  1, 2, AlignBottom|AlignRight);
//      mainGrid->addRowSpacing(1, hscroll->sizeHint().height());

      split2              = new Splitter(Horizontal, split1, "split2");
      QWidget* split1w1   = new QWidget(split2, "split1w1");
      QWidget* split1w2   = new QWidget(split2, "split1w2");
      QGridLayout* gridS1 = new QGridLayout(split1w1);
      QGridLayout* gridS2 = new QGridLayout(split1w2);
      time                = new MTScale(&_raster, split1w2, xscale);
      canvas              = new DrumCanvas(this, split1w2, xscale, yscale);
      vscroll             = new ScrollScale(1, 5, yscale, DRUM_MAPSIZE*TH, Vertical, split1w2);
      int offset = -(division/4);
      canvas->setOrigin(offset, 0);
      canvas->setCanvasTools(drumeditTools);
      canvas->setFocus();
      connect(canvas, SIGNAL(toolChanged(int)), tools2, SLOT(set(int)));

      time->setOrigin(offset, 0);
      vscroll->showMag(false);

      QValueList<int> mops;
      mops.append(_dlistWidthInit); 
      mops.append(_dcanvasWidthInit); 
      split2->setSizes(mops);

      gridS2->setRowStretch(1, 100);
      gridS2->setColStretch(0, 100);
      gridS2->addMultiCellWidget(time,  0, 0, 0, 1);
      gridS2->addMultiCellWidget(hLine(split1w2), 1, 1, 0, 1);
      gridS2->addWidget(canvas,  2, 0);
      gridS2->addWidget(vscroll, 2, 1);

      //
      //  Reihenfolge in dlist.c festgeschrieben ("Dcols")
      //
      header = new Header(split1w1, "header");
      header->setFixedHeight(30);
      header->addLabel(tr("M"), 20);
      header->addLabel(tr("Sound"), 100);
      header->addLabel(tr("QNT"));
      header->addLabel(tr("E-Note"));
      header->addLabel(tr("Len"));
      header->addLabel(tr("A-Note"));
      header->addLabel(tr("Ch"));
      header->addLabel(tr("Port"), 60);
      header->addLabel(tr("LV1"));
      header->addLabel(tr("LV2"));
      header->addLabel(tr("LV3"));
      header->addLabel(tr("LV4"));
      new DHeaderTip(header);
      new DWhatsThis(header, header);

      dlist = new DList(header, split1w1, yscale);
      connect(dlist, SIGNAL(keyPressed(int, bool)), canvas, SLOT(keyPressed(int, bool)));
      connect(dlist, SIGNAL(keyReleased(int, bool)), canvas, SLOT(keyReleased(int, bool)));
      connect(dlist, SIGNAL(mapChanged()), canvas, SLOT(mapChanged()));
      connect(dlist, SIGNAL(selectionChanged(DrumMap*)), SLOT(dlistSelectionChanged(DrumMap*)));

      gridS1->setRowStretch(1, 100);
      gridS1->setColStretch(0, 100);
      gridS1->addWidget(header, 0, 0);
      gridS1->addWidget(dlist, 1, 0);

      connect(canvas, SIGNAL(newWidth(int)), SLOT(newCanvasWidth(int)));
      connect(song, SIGNAL(songChanged(int)), SLOT(songChanged(int)));
      connect(vscroll, SIGNAL(scrollChanged(int)), canvas, SLOT(setYPos(int)));
      connect(hscroll, SIGNAL(scrollChanged(int)), canvas, SLOT(setXPos(int)));
      connect(hscroll, SIGNAL(scaleChanged(int)),  canvas, SLOT(setXMag(int)));
      connect(srec, SIGNAL(toggled(bool)),         canvas, SLOT(setSteprec(bool)));
      connect(midiin, SIGNAL(toggled(bool)),       canvas, SLOT(setMidiin(bool)));

      connect(vscroll, SIGNAL(scrollChanged(int)),   dlist,   SLOT(setYPos(int)));
      connect(hscroll, SIGNAL(scrollChanged(int)),   time,   SLOT(setXPos(int)));
      connect(hscroll, SIGNAL(scaleChanged(int)), time,   SLOT(setXMag(int)));

      connect(tools2, SIGNAL(toolChanged(int)), canvas, SLOT(setTool(int)));

      connect(canvas, SIGNAL(selectionChanged(int, Event*, Part*)), this,
         SLOT(setSelection(int, Event*, Part*)));
      connect(canvas, SIGNAL(followEvent(int)), SLOT(follow(int)));

      setCaption(canvas->getCaption());
      int s, e;
      canvas->range(&s, &e);
      hscroll->setRange(s, e);

      // connect toolbar
      connect(canvas,  SIGNAL(timeChanged(int)),  SLOT(setTime(int)));
      connect(time,    SIGNAL(timeChanged(int)),  SLOT(setTime(int)));
      connect(toolbar, SIGNAL(quantChanged(int)), canvas,  SLOT(setQuant(int)));
      connect(toolbar, SIGNAL(quantChanged(int)),          SLOT(setQuant(int)));
      connect(toolbar, SIGNAL(rasterChanged(int)),         SLOT(setRaster(int)));
      connect(toolbar, SIGNAL(soloChanged(bool)),          SLOT(soloChanged(bool)));
      connect(info, SIGNAL(valueChanged(NoteInfo::ValType, int)), SLOT(noteinfoChanged(NoteInfo::ValType, int)));

      connect(ctrl, SIGNAL(clicked()), SLOT(addCtrl()));

      QClipboard* cb = QApplication::clipboard();
      connect(cb, SIGNAL(dataChanged()), SLOT(clipboardChanged()));

      clipboardChanged(); // enable/disable "Paste"
      selectionChanged(); // enable/disable "Copy" & "Paste"
      }

//---------------------------------------------------------
//   follow
//---------------------------------------------------------

void DrumEdit::follow(int pos)
      {
      int s, e;
      canvas->range(&s, &e);

      if (pos < e && pos >= s)
            hscroll->setOffset(pos);
      if (pos < s)
            hscroll->setOffset(s);
      }

//---------------------------------------------------------
//   setTime
//---------------------------------------------------------

void DrumEdit::setTime(int tick)
      {
      toolbar->setTime(tick);
      time->setPos(3, tick, false);
      }

//---------------------------------------------------------
//   ~DrumEdit
//---------------------------------------------------------

DrumEdit::~DrumEdit()
      {
      undoRedo->removeFrom(tools);
      }

//---------------------------------------------------------
//   setSelection
//    update Info Line
//---------------------------------------------------------

void DrumEdit::setSelection(int tick, Event* e, Part* p)
      {
      selEvent = (MidiEvent*)e;
      selPart  = (MidiPart*)p;
      selTick  = tick;
      info->setEnabled(e);
      if (e) {
            info->setValues(tick,
               selEvent->lenTick(),
               selEvent->pitch(),
               selEvent->velo(),
               selEvent->veloOff());
            }
      selectionChanged();
      }

//---------------------------------------------------------
//   soloChanged
//---------------------------------------------------------

void DrumEdit::soloChanged(bool flag)
      {
      canvas->track()->node()->setSolo(flag);
      }

void DrumEdit::soloChanged(SNode* t)
      {
      toolbar->setSolo(t == canvas->track()->node());
      }


void DrumEdit::dlistSelectionChanged(DrumMap* dm)
      {
      QString name = dm->name;
      }
//---------------------------------------------------------
//   setRaster
//---------------------------------------------------------

void DrumEdit::setRaster(int val)
      {
      _rasterInit = val;
      MidiEditor::setRaster(val);
      }

//---------------------------------------------------------
//   setQuant
//---------------------------------------------------------

void DrumEdit::setQuant(int val)
      {
      _quantInit = val;
      canvas->setQuant(val);
      MidiEditor::setQuant(val);
      }

//---------------------------------------------------------
//    edit currently selected Event
//---------------------------------------------------------

void DrumEdit::noteinfoChanged(NoteInfo::ValType type, int val)
      {
      if (selEvent == 0) {
            printf("noteinfoChanged while note is zero %d\n", type);
            return;
            }
      MidiEvent* event = new MidiEvent(*selEvent);
      switch(type) {
            case NoteInfo::VAL_TIME:
                  event->setPosTick(val - selPart->posTick());
                  break;
            case NoteInfo::VAL_LEN:
                  event->setLenTick(val);
                  break;
            case NoteInfo::VAL_VELON:
                  event->setVelo(val);
                  break;
            case NoteInfo::VAL_VELOFF:
                  event->setVeloOff(val);
                  break;
            case NoteInfo::VAL_PITCH:
                  event->setPitch(val);
                  break;
            }
      midiThread->msgChangeEvent(selEvent, event, selPart);
      }

//---------------------------------------------------------
//   writeStatus
//---------------------------------------------------------

void DrumEdit::writeStatus(int level, Xml& xml) const
      {
      writePartList(level, xml);
      xml.tag(level++, "drumedit");
      MidiEditor::writeStatus(level, xml);

      for (std::list<CtrlEdit*>::const_iterator i = ctrlEditList.begin();
         i != ctrlEditList.end(); ++i) {
            (*i)->writeStatus(level, xml);
            }

      split1->writeStatus(level, xml);
      split2->writeStatus(level, xml);

      header->writeStatus(level, xml);
      xml.intTag(level, "steprec", canvas->steprec());
      xml.intTag(level, "midiin",  canvas->midiin());
      xml.intTag(level, "xpos", hscroll->pos());
      xml.intTag(level, "xmag", hscroll->mag());
      xml.intTag(level, "ypos", vscroll->pos());
      xml.intTag(level, "ymag", vscroll->mag());
      xml.tag(level, "/drumedit");
      }

//---------------------------------------------------------
//   readStatus
//---------------------------------------------------------

void DrumEdit::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 == "steprec") {
                              int val = xml.parseInt();
                              canvas->setSteprec(val);
                              srec->setOn(val);
                              }
                        else if (tag == "midiin") {
                              int val = xml.parseInt();
                              canvas->setMidiin(val);
                              midiin->setOn(val);
                              }
                        else if (tag == split1->name())
                              split1->readStatus(xml);
                        else if (tag == split2->name())
                              split2->readStatus(xml);
                        else if (tag == "midieditor")
                              MidiEditor::readStatus(xml);
                        else if (tag == header->name())
                              header->readStatus(xml);
                        else if (tag == "xmag")
                              hscroll->setMag(xml.parseInt());
                        else if (tag == "ctrledit") {
                              CtrlEdit* ctrl = addCtrl();
                              ctrl->readStatus(xml);
                              }
                        else if (tag == "xpos")
                              hscroll->setPos(xml.parseInt());
                        else if (tag == "ymag")
                              vscroll->setMag(xml.parseInt());
                        else if (tag == "ypos")
                              vscroll->setPos(xml.parseInt());
                        else
                              xml.unknown("DrumEdit");
                        break;
                  case Xml::TagEnd:
                        if (tag == "drumedit") {
                              _quantInit  = _quant;
                              _rasterInit = _raster;
                              toolbar->setRaster(_raster);
                              toolbar->setQuant(_quant);
                              canvas->setQuant(_quant);
                              return;
                              }
                  default:
                        break;
                  }
            }
      }

//---------------------------------------------------------
//   readConfiguration
//---------------------------------------------------------

void DrumEdit::readConfiguration(Xml& xml)
      {
      for (;;) {
            Xml::Token token = xml.parse();
            const QString& tag = xml.s1();
            switch (token) {
                  case Xml::Error:
                  case Xml::End:
                        return;
                  case Xml::TagStart:
                        if (tag == "quant")
                              _quantInit = xml.parseInt();
                        else if (tag == "raster")
                              _rasterInit = xml.parseInt();
                        else if (tag == "width")
                              _widthInit = xml.parseInt();
                        else if (tag == "height")
                              _heightInit = xml.parseInt();
                        else if (tag == "dcanvaswidth") 
                              _dcanvasWidthInit = xml.parseInt(); 
                        else if (tag == "dlistwidth") 
                              _dlistWidthInit = xml.parseInt(); 
                        else
                              xml.unknown("DrumEdit");
                        break;
                  case Xml::TagEnd:
                        if (tag == "drumedit") {
                              return;
                              }
                  default:
                        break;
                  }
            }
      }

//---------------------------------------------------------
//   writeConfiguration
//---------------------------------------------------------

void DrumEdit::writeConfiguration(int level, Xml& xml)
      {
      xml.tag(level++, "drumedit");
      xml.intTag(level, "quant", _quantInit);
      xml.intTag(level, "raster", _rasterInit);
      xml.intTag(level, "width", _widthInit);
      xml.intTag(level, "height", _heightInit);
      xml.intTag(level, "dlistwidth", _dlistWidthInit); 
      xml.intTag(level, "dcanvaswidth", _dcanvasWidthInit); 
      xml.tag(level, "/drumedit");
      }

//---------------------------------------------------------
//   load
//---------------------------------------------------------

void DrumEdit::load()
      {
      QString fn = getOpenFileName(tr("drummaps"), map_file_pattern,
         this, tr("Muse: Load Drum Map"));
      if (fn.isEmpty())
            return;
      bool popenFlag;
      FILE* f = fileOpen(this, fn, QString(".map"), "r", popenFlag, true);
      if (f == 0)
            return;

      Xml xml(f);
      int mode = 0;
      for (;;) {
            Xml::Token token = xml.parse();
            const QString& tag = xml.s1();
            switch (token) {
                  case Xml::Error:
                  case Xml::End:
                        return;
                  case Xml::TagStart:
                        if (mode == 0 && tag == "muse")
                              mode = 1;
                        else if (mode == 1 && tag == "drummap") {
                              readDrumMap(xml, true);
                              mode = 0;
                              }
                        else
                              xml.unknown("DrumEdit");
                        break;
                  case Xml::Attribut:
                        break;
                  case Xml::TagEnd:
                        if (!mode && tag == "muse")
                              goto ende;
                  default:
                        break;
                  }
            }
ende:
      if (popenFlag)
            pclose(f);
      else
            fclose(f);
      dlist->redraw();
      canvas->redraw();
      }

//---------------------------------------------------------
//   save
//---------------------------------------------------------

void DrumEdit::save()
      {
      QString fn = getSaveFileName(QString("drummaps"), map_file_pattern,
        this, tr("MusE: Store Drum Map"));
      if (fn.isEmpty())
            return;
      bool popenFlag;
      FILE* f = fileOpen(this, fn, QString(".map"), "w", popenFlag, false, true);
      if (f == 0)
            return;
      Xml xml(f);
      xml.header();
      xml.tag(0, "muse version=\"1.0\"");
      writeDrumMap(1, xml, true);
      xml.tag(1, "/muse");

      if (popenFlag)
            pclose(f);
      else
            fclose(f);
      }

//---------------------------------------------------------
//   cmd
//    pulldown menu commands
//---------------------------------------------------------

void DrumEdit::cmd(int cmd)
      {
      switch(cmd) {
            case DrumCanvas::CMD_LOAD:
                  load();
                  break;
            case DrumCanvas::CMD_SAVE:
                  save();
                  break;
            default:
                  ((DrumCanvas*)(canvas))->cmd(cmd);
                  break;
            }
      }

//---------------------------------------------------------
//   clipboardChanged
//---------------------------------------------------------

void DrumEdit::clipboardChanged()
      {
      QMimeSource* ms = QApplication::clipboard()->data(QClipboard::Clipboard);
      if (ms && ms->format(0)) {
            bool flag = strcmp(ms->format(0), "text/eventlist;charset=UTF-8") == 0;
            menuEdit->setItemEnabled(DrumCanvas::CMD_PASTE, flag);
            }
      }

//---------------------------------------------------------
//   selectionChanged
//---------------------------------------------------------

void DrumEdit::selectionChanged()
      {
      bool flag = canvas->selectionSize() > 0;
      menuEdit->setItemEnabled(DrumCanvas::CMD_CUT, flag);
      menuEdit->setItemEnabled(DrumCanvas::CMD_COPY, flag);
      menuEdit->setItemEnabled(DrumCanvas::CMD_DEL, flag);
      }

//---------------------------------------------------------
//   addCtrl
//---------------------------------------------------------

CtrlEdit* DrumEdit::addCtrl()
      {
      CtrlEdit* ctrlEdit = new CtrlEdit(split1, this, xscale, true, "drumCtrlEdit");
      connect(hscroll,  SIGNAL(scrollChanged(int)), ctrlEdit, SLOT(setXPos(int)));
      connect(hscroll,  SIGNAL(scaleChanged(int)),  ctrlEdit, SLOT(setXMag(int)));
      connect(ctrlEdit, SIGNAL(timeChanged(int)),   SLOT(setTime(int)));
      connect(ctrlEdit, SIGNAL(destroyedCtrl(CtrlEdit*)), SLOT(removeCtrl(CtrlEdit*)));
      connect(ctrlEdit, SIGNAL(yposChanged(int)), toolbar, SLOT(setInt(int)));
      connect(tools2,   SIGNAL(toolChanged(int)),   ctrlEdit, SLOT(setTool(int)));
      connect(dlist, SIGNAL(keyFilterChanged(const char )), ctrlEdit, SLOT(setKeyfilter(const char )));

      ctrlEdit->setXPos(hscroll->pos());
      ctrlEdit->setXMag(hscroll->getScaleValue());

      ctrlEdit->setCanvasWidth(canvas->width());

      ctrlEdit->show();
      ctrlEditList.push_back(ctrlEdit);
      return ctrlEdit;
      }

//---------------------------------------------------------
//   removeCtrl
//---------------------------------------------------------

void DrumEdit::removeCtrl(CtrlEdit* ctrl)
      {
      for (std::list<CtrlEdit*>::iterator i = ctrlEditList.begin();
         i != ctrlEditList.end(); ++i) {
            if (*i == ctrl) {
                  ctrlEditList.erase(i);
                  break;
                  }
            }
      }

//---------------------------------------------------------
//   newCanvasWidth
//---------------------------------------------------------

void DrumEdit::newCanvasWidth(int w)
      {
      for (std::list<CtrlEdit*>::iterator i = ctrlEditList.begin();
         i != ctrlEditList.end(); ++i) {
            (*i)->setCanvasWidth(w);
            }
      }

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

void DrumEdit::resizeEvent(QResizeEvent* ev)
      {
      QWidget::resizeEvent(ev);
      _widthInit = ev->size().width();
      _heightInit = ev->size().height();
 
      //TODO: Make the dlist not expand/shrink, but the canvas instead 
      }


