From c6f2151b1589c91292563a1b319cdbd193834d67 Mon Sep 17 00:00:00 2001
From: Florian Jung <flo@windfisch.org>
Date: Tue, 7 Jun 2011 18:45:32 +0000
Subject: modified behaviour for clones:   - resizing a clone in the arranger
 also resizes all clones with     the same length   - same for auto-expanding
 in the pianoroll   - auto-expanding in the pianoroll does NOT expand for
 parts     which already contain hidden notes; then inserting notes     is
 forbidden; buggy, see below

still TODO and BUGS:
  - forbidding notes doesn't work properly. the pianoroll still displays
    them until the next full song update.
  - that stuff must be done in the drum canvas as well
  - step-rec and the score editor need support for auto-expanding
---
 muse2/muse/arranger/pcanvas.cpp   |  4 +--
 muse2/muse/arranger/pcanvas.h     |  2 +-
 muse2/muse/functions.cpp          | 39 ++++++++++++++++++++++++++
 muse2/muse/functions.h            |  2 ++
 muse2/muse/midiedit/dcanvas.cpp   |  2 +-
 muse2/muse/midiedit/dcanvas.h     |  2 +-
 muse2/muse/midiedit/prcanvas.cpp  | 58 +++++++++++++++++++--------------------
 muse2/muse/midiedit/prcanvas.h    |  2 +-
 muse2/muse/midiedit/scoreedit.cpp |  9 ++++--
 muse2/muse/part.cpp               | 53 +++++++++++++++++++----------------
 muse2/muse/part.h                 |  2 ++
 muse2/muse/song.h                 |  2 +-
 muse2/muse/widgets/canvas.cpp     |  2 +-
 muse2/muse/widgets/canvas.h       |  2 +-
 14 files changed, 117 insertions(+), 64 deletions(-)

diff --git a/muse2/muse/arranger/pcanvas.cpp b/muse2/muse/arranger/pcanvas.cpp
index f7a2abde..9fefaf70 100644
--- a/muse2/muse/arranger/pcanvas.cpp
+++ b/muse2/muse/arranger/pcanvas.cpp
@@ -448,7 +448,7 @@ void PartCanvas::updateSelection()
 //   resizeItem
 //---------------------------------------------------------
 
-void PartCanvas::resizeItem(CItem* i, bool noSnap)
+void PartCanvas::resizeItem(CItem* i, bool noSnap, bool ctrl)
       {
       Track* t = ((NPart*)(i))->track();
       Part*  p = ((NPart*)(i))->part();
@@ -462,7 +462,7 @@ void PartCanvas::resizeItem(CItem* i, bool noSnap)
       if (newwidth == 0)
             newwidth = AL::sigmap.rasterStep(p->tick(), *_raster);
 
-      song->cmdResizePart(t, p, newwidth);
+      song->cmdResizePart(t, p, newwidth, !ctrl);
       }
 
 //---------------------------------------------------------
diff --git a/muse2/muse/arranger/pcanvas.h b/muse2/muse/arranger/pcanvas.h
index acfe565e..ccfb1fcc 100644
--- a/muse2/muse/arranger/pcanvas.h
+++ b/muse2/muse/arranger/pcanvas.h
@@ -83,7 +83,7 @@ class PartCanvas : public Canvas {
       virtual int pitch2y(int p) const;
       
       virtual CItem* newItem(const QPoint&, int);
-      virtual void resizeItem(CItem*,bool);
+      virtual void resizeItem(CItem*,bool, bool ctrl);
       virtual void newItem(CItem*,bool);
       virtual bool deleteItem(CItem*);
       virtual void moveCanvasItems(CItemList&, int, int, DragType);
diff --git a/muse2/muse/functions.cpp b/muse2/muse/functions.cpp
index b47874fd..9ab209c6 100644
--- a/muse2/muse/functions.cpp
+++ b/muse2/muse/functions.cpp
@@ -866,6 +866,45 @@ void shrink_parts(int raster)
 	song->applyOperationGroup(operations);
 }
 
+void internal_schedule_expand_part(Part* part, int raster, Undo& operations)
+{
+	EventList* events=part->events();
+	unsigned len=part->lenTick();
+	
+	for (iEvent ev=events->begin(); ev!=events->end(); ev++)
+		if (ev->second.endTick() > len)
+			len=ev->second.endTick();
+
+	if (raster) len=ceil((float)len/raster)*raster;
+					
+	if (len > part->lenTick())
+	{
+		MidiPart* new_part = new MidiPart(*(MidiPart*)part);
+		new_part->setLenTick(len);
+		operations.push_back(UndoOp(UndoOp::ModifyPart, part, new_part, true, false));
+	}
+}
+
+void schedule_resize_all_same_len_clone_parts(Part* part, unsigned new_len, Undo& operations)
+{
+	unsigned old_len=part->lenTick();
+	if (old_len!=new_len)
+	{
+		Part* part_it=part;
+		do
+		{
+			if (part_it->lenTick()==old_len)
+			{
+				MidiPart* new_part = new MidiPart(*(MidiPart*)part_it);
+				new_part->setLenTick(new_len);
+				operations.push_back(UndoOp(UndoOp::ModifyPart, part_it, new_part, true, false));
+			}
+			
+			part_it=part_it->nextClone();
+		} while (part_it!=part);
+	}
+}
+
 void expand_parts(int raster)
 {
 	Undo operations;
diff --git a/muse2/muse/functions.h b/muse2/muse/functions.h
index 633457a9..90fc64e9 100644
--- a/muse2/muse/functions.h
+++ b/muse2/muse/functions.h
@@ -24,6 +24,7 @@
 
 class QString;
 class QMimeData;
+class Undo;
 
 extern GateTime* gatetime_dialog;
 extern Velocity* velocity_dialog;
@@ -87,6 +88,7 @@ void select_not_in_loop(const std::set<Part*>& parts);
 //functions for parts
 void shrink_parts(int raster=-1); //negative values mean "config.division"
 void expand_parts(int raster=-1);
+void schedule_resize_all_same_len_clone_parts(Part* part, unsigned new_len, Undo& operations);
 void clean_parts();
 
 //functions for reading and writing default values
diff --git a/muse2/muse/midiedit/dcanvas.cpp b/muse2/muse/midiedit/dcanvas.cpp
index 92e514af..b19831a0 100644
--- a/muse2/muse/midiedit/dcanvas.cpp
+++ b/muse2/muse/midiedit/dcanvas.cpp
@@ -308,7 +308,7 @@ CItem* DrumCanvas::newItem(int tick, int instrument, int velocity)
 //   resizeItem
 //---------------------------------------------------------
 
-void DrumCanvas::resizeItem(CItem* item, bool)
+void DrumCanvas::resizeItem(CItem* item, bool, bool)
       {
       DEvent* nevent = (DEvent*) item;
       Event ev = nevent->event();
diff --git a/muse2/muse/midiedit/dcanvas.h b/muse2/muse/midiedit/dcanvas.h
index 868113a6..a2d0f7de 100644
--- a/muse2/muse/midiedit/dcanvas.h
+++ b/muse2/muse/midiedit/dcanvas.h
@@ -57,7 +57,7 @@ class DrumCanvas : public EventCanvas {
       virtual Undo moveCanvasItems(CItemList&, int, int, DragType);
       virtual UndoOp moveItem(CItem*, const QPoint&, DragType);
       virtual CItem* newItem(const QPoint&, int);
-      virtual void resizeItem(CItem*, bool);
+      virtual void resizeItem(CItem*, bool, bool);
       virtual void newItem(CItem*, bool);
       virtual void newItem(CItem*, bool, bool replace );
       virtual bool deleteItem(CItem*);
diff --git a/muse2/muse/midiedit/prcanvas.cpp b/muse2/muse/midiedit/prcanvas.cpp
index 091582ef..db42be6c 100644
--- a/muse2/muse/midiedit/prcanvas.cpp
+++ b/muse2/muse/midiedit/prcanvas.cpp
@@ -479,28 +479,28 @@ void PianoCanvas::newItem(CItem* item, bool noSnap)
       event.setLenTick(w);
       event.setPitch(y2pitch(item->y()));
 
-      song->startUndo();
-      int modified=SC_EVENT_MODIFIED;
+      Undo operations;
       int diff = event.endTick()-part->lenTick();
-      if (diff > 0)  {// too short part? extend it
-            //printf("extend Part!\n");
-            Part* newPart = part->clone();
-            newPart->setLenTick(newPart->lenTick()+diff);
-            // Indicate no undo, and do port controller values but not clone parts. 
-            audio->msgChangePart(part, newPart, false, true, false);
-            modified=modified|SC_PART_MODIFIED;
-            part = newPart; // reassign
+      
+      if (! ((diff > 0) && part->hasHiddenNotes()) ) //operation is allowed
+      {
+        operations.push_back(UndoOp(UndoOp::AddEvent,event, part, false, false));
+        
+        if (diff > 0)// part must be extended?
+        {
+              schedule_resize_all_same_len_clone_parts(part, event.endTick(), operations);
+              printf("newItem: extending\n");
             }
-      // Indicate no undo, and do not do port controller values and clone parts. 
-      audio->msgAddEvent(event, part, false, false, false);
-      song->endUndo(modified);
+      }
+      //FINDMICH TODO: forbid action! this is currently wrong!
+      song->applyOperationGroup(operations);
       }
 
 //---------------------------------------------------------
 //   resizeItem
 //---------------------------------------------------------
 
-void PianoCanvas::resizeItem(CItem* item, bool noSnap)         // experimental changes to try dynamically extending parts
+void PianoCanvas::resizeItem(CItem* item, bool noSnap, bool)         // experimental changes to try dynamically extending parts
       {
       //printf("resizeItem!\n");
       NEvent* nevent = (NEvent*) item;
@@ -519,23 +519,23 @@ void PianoCanvas::resizeItem(CItem* item, bool noSnap)         // experimental c
             if (len <= 0)
                   len = editor->raster();
       }
-      song->startUndo();
-      int modified=SC_EVENT_MODIFIED;
+
+      Undo operations;
       int diff = event.tick()+len-part->lenTick();
-      if (diff > 0)  {// too short part? extend it
-            //printf("extend Part!\n");
-            Part* newPart = part->clone();
-            newPart->setLenTick(newPart->lenTick()+diff);
-            // Indicate no undo, and do port controller values but not clone parts. 
-            audio->msgChangePart(part, newPart, false, true, false);
-            modified=modified|SC_PART_MODIFIED;
-            part = newPart; // reassign
-            }
+      
+      if (! ((diff > 0) && part->hasHiddenNotes()) ) //operation is allowed
+      {
+        newEvent.setLenTick(len);
+        operations.push_back(UndoOp(UndoOp::ModifyEvent,newEvent, event, nevent->part(), false, false));
+        
+        if (diff > 0)// part must be extended?
+        {
+              schedule_resize_all_same_len_clone_parts(part, event.tick()+len, operations);
+              printf("resizeItem: extending\n");}
+      }
+      //FINDMICH TODO: forbid action! this is currently wrong!
+      song->applyOperationGroup(operations);
 
-      newEvent.setLenTick(len);
-      // Indicate no undo, and do not do port controller values and clone parts. 
-      audio->msgChangeEvent(event, newEvent, nevent->part(), false, false, false);
-      song->endUndo(modified);
       }
 
 //---------------------------------------------------------
diff --git a/muse2/muse/midiedit/prcanvas.h b/muse2/muse/midiedit/prcanvas.h
index c6e47c9e..d96dd4df 100644
--- a/muse2/muse/midiedit/prcanvas.h
+++ b/muse2/muse/midiedit/prcanvas.h
@@ -57,7 +57,7 @@ class PianoCanvas : public EventCanvas {
       virtual Undo moveCanvasItems(CItemList&, int, int, DragType);
       virtual UndoOp moveItem(CItem*, const QPoint&, DragType);
       virtual CItem* newItem(const QPoint&, int);
-      virtual void resizeItem(CItem*, bool noSnap);
+      virtual void resizeItem(CItem*, bool noSnap, bool);
       virtual void newItem(CItem*, bool noSnap);
       virtual bool deleteItem(CItem*);
       virtual void startDrag(CItem* item, bool copymode);
diff --git a/muse2/muse/midiedit/scoreedit.cpp b/muse2/muse/midiedit/scoreedit.cpp
index 1a885d99..f7d9237b 100644
--- a/muse2/muse/midiedit/scoreedit.cpp
+++ b/muse2/muse/midiedit/scoreedit.cpp
@@ -4457,11 +4457,14 @@ void staff_t::update_part_indices()
  *     between, for example, when a cis is tied to a des
  * 
  * CURRENT TODO
- *   o clones should have same size
- *   o insert empty measure should also work inside parts, that is,
- *     move notes _within_ parts
+ *   o do autoexpand correctly in prcanvas.cpp, then port that to 
+ *     dcanvas.cpp, steprec.cpp and scoreedit.cpp
  * 
  * IMPORTANT TODO
+ *   o shrink a part from its beginning as well! watch out for clones!
+ *   o insert empty measure should also work inside parts, that is,
+ *     move notes _within_ parts
+ *
  *   o canvas editor: create clone via "alt+drag" moves window instead
  *   o investigate with valgrind
  *   o controller view in score editor
diff --git a/muse2/muse/part.cpp b/muse2/muse/part.cpp
index 398720af..9bb3431c 100644
--- a/muse2/muse/part.cpp
+++ b/muse2/muse/part.cpp
@@ -819,7 +819,7 @@ void Song::removePart(Part* part)
 //   cmdResizePart
 //---------------------------------------------------------
 
-void Song::cmdResizePart(Track* track, Part* oPart, unsigned int len)
+void Song::cmdResizePart(Track* track, Part* oPart, unsigned int len, bool doClones)
       {
       switch(track->type()) {
             case Track::WAVE:
@@ -899,28 +899,21 @@ void Song::cmdResizePart(Track* track, Part* oPart, unsigned int len)
             case Track::DRUM:
                   {
                   Undo operations;
-
-                  MidiPart* nPart = new MidiPart(*(MidiPart*)oPart);
-                  nPart->setLenTick(len);
-                  // Do port controller values but not clone parts. 
-                  operations.push_back(UndoOp(UndoOp::ModifyPart, oPart, nPart, true, false));
-
-                  // cut Events in nPart
-                  // Changed by T356. Don't delete events if this is a clone part.
-                  // The other clones might be longer than this one and need these events.
-                  if(nPart->cevents()->arefCount() <= 1)
-                  {
-                    if(oPart->lenTick() > len) { 
-                          EventList* el = nPart->events();
-                          iEvent ie = el->lower_bound(len);
-                          for (; ie != el->end();) {
-                                iEvent i = ie;
-                                ++ie;
-                                // Do port controller values and clone parts. 
-                                operations.push_back(UndoOp(UndoOp::DeleteEvent, i->second, nPart, true, true));
-                                }
-                          }
-                  }        
+									
+									unsigned orig_len=oPart->lenTick();
+									MidiPart* part_it=(MidiPart*)oPart;
+									do
+									{
+										if (part_it->lenTick()==orig_len)
+										{
+											MidiPart* newPart = new MidiPart(*part_it);
+											newPart->setLenTick(len);
+											// Do port controller values but not clone parts. 
+											operations.push_back(UndoOp(UndoOp::ModifyPart, part_it, newPart, true, false));
+										}
+										
+										part_it=(MidiPart*)part_it->nextClone();
+									} while (doClones && (part_it != (MidiPart*)oPart));
                   
                   song->applyOperationGroup(operations);
                   break;
@@ -1176,3 +1169,17 @@ WavePart* WavePart::clone() const
       return new WavePart(*this);
       }
 
+
+
+bool Part::hasHiddenNotes()
+{
+	unsigned lastNote=0;
+
+	for (iEvent ev=events()->begin(); ev!=events()->end(); ev++)
+		if (ev->second.endTick() > lastNote)
+			lastNote=ev->second.endTick();
+	
+	printf ("in hasHiddenNotes: lastNote=%i, lenTick=%i\n",lastNote, lenTick());
+	
+	return lastNote > lenTick();
+}
diff --git a/muse2/muse/part.h b/muse2/muse/part.h
index 9b037edd..ff7091a6 100644
--- a/muse2/muse/part.h
+++ b/muse2/muse/part.h
@@ -82,6 +82,8 @@ class Part : public PosLen {
       void setPrevClone(Part* p)       { _prevClone = p; }
       void setNextClone(Part* p)       { _nextClone = p; }
       
+      bool hasHiddenNotes();
+      
       iEvent addEvent(Event& p);
 
       virtual void write(int, Xml&, bool isCopy = false, bool forceWavePaths = false) const;
diff --git a/muse2/muse/song.h b/muse2/muse/song.h
index fd88b278..45751418 100644
--- a/muse2/muse/song.h
+++ b/muse2/muse/song.h
@@ -253,7 +253,7 @@ class Song : public QObject {
       //   part manipulations
       //-----------------------------------------
 
-      void cmdResizePart(Track* t, Part* p, unsigned int size);
+      void cmdResizePart(Track* t, Part* p, unsigned int size, bool doClones=false);
       void cmdSplitPart(Track* t, Part* p, int tick);
       void cmdGluePart(Track* t, Part* p);
 
diff --git a/muse2/muse/widgets/canvas.cpp b/muse2/muse/widgets/canvas.cpp
index 650b10b7..9025590a 100644
--- a/muse2/muse/widgets/canvas.cpp
+++ b/muse2/muse/widgets/canvas.cpp
@@ -1131,7 +1131,7 @@ void Canvas::viewMouseReleaseEvent(QMouseEvent* event)
             case DRAG_OFF:
                   break;
             case DRAG_RESIZE:
-                  resizeItem(curItem, false);
+                  resizeItem(curItem, false, ctrl);
                   break;
             case DRAG_NEW:
                   newItem(curItem, false);
diff --git a/muse2/muse/widgets/canvas.h b/muse2/muse/widgets/canvas.h
index 2eae3d03..dbe13fcb 100644
--- a/muse2/muse/widgets/canvas.h
+++ b/muse2/muse/widgets/canvas.h
@@ -102,7 +102,7 @@ class Canvas : public View {
       virtual int pitch2y(int) const = 0; //CDW
 
       virtual CItem* newItem(const QPoint&, int state) = 0;
-      virtual void resizeItem(CItem*, bool noSnap=false) = 0;
+      virtual void resizeItem(CItem*, bool noSnap=false, bool ctrl=false) = 0;
       virtual void newItem(CItem*, bool noSnap=false) = 0;
       virtual bool deleteItem(CItem*) = 0;
       int getCurrentDrag();
-- 
cgit v1.2.3