diff options
| author | Florian Jung <flo@windfisch.org> | 2011-09-09 15:55:09 +0000 | 
|---|---|---|
| committer | Florian Jung <flo@windfisch.org> | 2011-09-09 15:55:09 +0000 | 
| commit | 38c5cccc7273247353264bb7dc97f42296d8e259 (patch) | |
| tree | aa148b85e0169c6a10a680678ad7bdb8aec62b5d /muse2/muse | |
| parent | b95aeb4245e9bc6e67df6cd489c5f29192c962cf (diff) | |
began with improved pasting in editors
still TODO: - show a dialog
            - test it
            - add generated parts to editor automatically
Diffstat (limited to 'muse2/muse')
| -rw-r--r-- | muse2/muse/functions.cpp | 198 | ||||
| -rw-r--r-- | muse2/muse/functions.h | 4 | ||||
| -rw-r--r-- | muse2/muse/midiedit/drumedit.cpp | 4 | ||||
| -rw-r--r-- | muse2/muse/midiedit/ecanvas.cpp | 6 | ||||
| -rw-r--r-- | muse2/muse/midiedit/pianoroll.cpp | 4 | ||||
| -rw-r--r-- | muse2/muse/midiedit/scoreedit.cpp | 10 | 
6 files changed, 154 insertions, 72 deletions
| diff --git a/muse2/muse/functions.cpp b/muse2/muse/functions.cpp index d410844a..bacd6e34 100644 --- a/muse2/muse/functions.cpp +++ b/muse2/muse/functions.cpp @@ -8,6 +8,7 @@  #include "functions.h"  #include "song.h"  #include "undo.h" +#include "helper.h"  #include "event.h"  #include "audio.h" @@ -848,34 +849,28 @@ void copy_notes(const set<Part*>& parts, int range)  		QApplication::clipboard()->setMimeData(drag, QClipboard::Clipboard);  } -void paste_notes(Part* dest_part) +void paste_notes(int max_distance, bool always_new_part, bool never_new_part, Part* paste_into_part)  { -	QString tmp="x-muse-eventlist"; // QClipboard::text() expects a QString&, not a QString :( +	QString tmp="x-muse-groupedeventlists"; // QClipboard::text() expects a QString&, not a QString :(  	QString s = QApplication::clipboard()->text(tmp, QClipboard::Clipboard);  // TODO CHECK Tim. -	paste_at(dest_part, s, song->cpos()); +	paste_at(s, song->cpos(), max_distance, always_new_part, never_new_part, paste_into_part);  } + +// if nothing is selected/relevant, this function returns NULL  QMimeData* selected_events_to_mime(const set<Part*>& parts, int range)  { -	map<Event*, Part*> events=get_events(parts,range); - -	//--------------------------------------------------- -	//   generate event list from selected events -	//--------------------------------------------------- - -	EventList el; -	unsigned startTick = MAXINT; //will be the tick of the first event or MAXINT if no events are there - -	for (map<Event*, Part*>::iterator it=events.begin(); it!=events.end(); it++) -	{ -		Event& e   = *it->first; -		 -		if (e.tick() < startTick) -			startTick = e.tick(); -			 -		el.add(e); -	} - +	unsigned start_tick = MAXINT; //will be the tick of the first event or MAXINT if no events are there +	 +	for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++) +		for (iEvent ev=(*part)->events()->begin(); ev!=(*part)->events()->end(); ev++) +			if (is_relevant(ev->second, *part, range)) +				if (ev->second.tick() < start_tick) +					start_tick=ev->second.tick(); +	 +	if (start_tick == MAXINT) +		return NULL; +	  	//---------------------------------------------------  	//    write events as XML into tmp file  	//--------------------------------------------------- @@ -890,10 +885,14 @@ QMimeData* selected_events_to_mime(const set<Part*>& parts, int range)  	Xml xml(tmp);  	int level = 0; -	xml.tag(level++, "eventlist"); -	for (ciEvent e = el.begin(); e != el.end(); ++e) -		e->second.write(level, xml, -startTick); -	xml.etag(--level, "eventlist"); +	for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++) +	{ +		xml.tag(level++, "eventlist part_id=\"%d\"", (*part)->sn()); +		for (iEvent ev=(*part)->events()->begin(); ev!=(*part)->events()->end(); ev++) +			if (is_relevant(ev->second, *part, range)) +				ev->second.write(level, xml, -start_tick); +		xml.etag(--level, "eventlist"); +	}  	//---------------------------------------------------  	//    read tmp file into drag Object @@ -903,7 +902,7 @@ QMimeData* selected_events_to_mime(const set<Part*>& parts, int range)  	struct stat f_stat;  	if (fstat(fileno(tmp), &f_stat) == -1)  	{ -		fprintf(stderr, "PianoCanvas::copy() fstat failed:<%s>\n", +		fprintf(stderr, "copy_notes() fstat failed:<%s>\n",  		strerror(errno));  		fclose(tmp);  		return 0; @@ -916,7 +915,7 @@ QMimeData* selected_events_to_mime(const set<Part*>& parts, int range)  	QByteArray data(fbuf);  	QMimeData* md = new QMimeData(); -	md->setData("text/x-muse-eventlist", data); +	md->setData("text/x-muse-groupedeventlists", data);  	munmap(fbuf, n);  	fclose(tmp); @@ -924,10 +923,52 @@ QMimeData* selected_events_to_mime(const set<Part*>& parts, int range)  	return md;  } -void paste_at(Part* dest_part, const QString& pt, int pos) +bool read_eventlist_and_part(Xml& xml, EventList* el, int* part_id) // true on success, false on failure +{ +	*part_id = -1; +	 +	for (;;) +	{ +		Xml::Token token = xml.parse(); +		const QString& tag = xml.s1(); +		switch (token) +		{ +			case Xml::Error: +			case Xml::End: +				return false; +				 +			case Xml::Attribut: +				if (tag == "part_id") +					*part_id = xml.s2().toInt(); +				else +					printf("unknown attribute '%s' in read_eventlist_and_part(), ignoring it...\n", tag.toAscii().data()); +				break; +				 +			case Xml::TagStart: +				if (tag == "event") +				{ +					Event e(Note); +					e.read(xml); +					el->add(e); +				} +				else +					xml.unknown("read_eventlist_and_part"); +				break; +				 +			case Xml::TagEnd: +				if (tag == "eventlist") +					return true; +				 +			default: +				break; +		} +	} +} + +void paste_at(const QString& pt, int pos, int max_distance, bool always_new_part, bool never_new_part, Part* paste_into_part)  {  	Undo operations; -	unsigned newpartlen=dest_part->lenTick(); +	map<Part*, unsigned> expand_map;  	Xml xml(pt.toLatin1().constData());  	for (;;)  @@ -938,53 +979,82 @@ void paste_at(Part* dest_part, const QString& pt, int pos)  		{  			case Xml::Error:  			case Xml::End: -				goto end_of_paste_at; +				goto out_of_paste_at_for;  			case Xml::TagStart:  				if (tag == "eventlist")  				{  					EventList el; -					el.read(xml, "eventlist", true); -					for (iEvent i = el.begin(); i != el.end(); ++i) +					int part_id; +		 +					if (read_eventlist_and_part(xml, &el, &part_id))  					{ -						Event e = i->second; -						int tick = e.tick() + pos - dest_part->tick(); -						if (tick<0) +						Part* dest_part; +						Track* dest_track; +						 +						if (paste_into_part == NULL) +							dest_part = partFromSerialNumber(part_id); +						else +							dest_part=paste_into_part; +						 +						if (dest_part == NULL)  						{ -							printf("ERROR: trying to add event before current part!\n"); -							goto end_of_paste_at; +							printf("ERROR: destination part wasn't found. ignoring these events\n");  						} - -						e.setTick(tick); -						e.setSelected(true); -						 -						if (e.endTick() > dest_part->lenTick()) // event exceeds part? +						else  						{ -							if (dest_part->hasHiddenEvents()) // auto-expanding is forbidden? +							dest_track=dest_part->track(); +							 +							unsigned first_paste_tick = el.begin()->first + pos; +							if ( (dest_part->tick() > first_paste_tick) ||   // dest_part begins too late +									 ( ( (dest_part->endTick() + max_distance < first_paste_tick) || // dest_part is too far away +										 always_new_part ) && !never_new_part ) )  							{ -								if (e.tick() < dest_part->lenTick()) -									e.setLenTick(dest_part->lenTick() - e.tick()); // clip -								else -									e.setLenTick(0); // don't insert that note at all +								dest_part = dest_track->newPart(); +								dest_part->setTick(AL::sigmap.raster1(first_paste_tick, config.division)); +								operations.push_back(UndoOp(UndoOp::AddPart, dest_part));  							} -							else +							 +							for (iEvent i = el.begin(); i != el.end(); ++i)  							{ -								if (e.endTick() > newpartlen) -									newpartlen=e.endTick(); +								Event e = i->second; +								int tick = e.tick() + pos - dest_part->tick(); +								if (tick<0) +								{ +									printf("ERROR: trying to add event before current part! ignoring this event\n"); +									continue; +								} + +								e.setTick(tick); +								e.setSelected(true); +								 +								if (e.endTick() > dest_part->lenTick()) // event exceeds part? +								{ +									if (dest_part->hasHiddenEvents()) // auto-expanding is forbidden? +									{ +										if (e.tick() < dest_part->lenTick()) +											e.setLenTick(dest_part->lenTick() - e.tick()); // clip +										else +											e.setLenTick(0); // don't insert that note at all +									} +									else +									{ +										if (e.endTick() > expand_map[dest_part]) +											expand_map[dest_part]=e.endTick(); +									} +								} +								 +								if (e.lenTick() != 0) operations.push_back(UndoOp(UndoOp::AddEvent,e, dest_part, false, false));  							}  						} -						 -						if (e.lenTick() != 0) operations.push_back(UndoOp(UndoOp::AddEvent,e, dest_part, false, false));  					} -					 -					if (newpartlen != dest_part->lenTick()) -						schedule_resize_all_same_len_clone_parts(dest_part, newpartlen, operations); - -					song->applyOperationGroup(operations); -					goto end_of_paste_at; +					else +					{ +						printf("ERROR: reading eventlist from clipboard failed. ignoring this one...\n"); +					}  				}  				else -				xml.unknown("paste_at"); +					xml.unknown("paste_at");  				break;  			case Xml::Attribut: @@ -994,7 +1064,13 @@ void paste_at(Part* dest_part, const QString& pt, int pos)  		}  	} -	end_of_paste_at: +	out_of_paste_at_for: +	 +	for (map<Part*, unsigned>::iterator it = expand_map.begin(); it!=expand_map.end(); it++) +		if (it->second != it->first->lenTick()) +			schedule_resize_all_same_len_clone_parts(it->first, it->second, operations); + +	song->applyOperationGroup(operations);  	song->update(SC_SELECTION);  } diff --git a/muse2/muse/functions.h b/muse2/muse/functions.h index 1d3233b7..cc2768cb 100644 --- a/muse2/muse/functions.h +++ b/muse2/muse/functions.h @@ -69,9 +69,9 @@ bool legato();  //functions for copy'n'paste  void copy_notes(const std::set<Part*>& parts, int range); -void paste_notes(Part* dest_part); +void paste_notes(int max_distance=3072, bool always_new_part=false, bool never_new_part=false, Part* paste_into_part=NULL);  QMimeData* selected_events_to_mime(const std::set<Part*>& parts, int range); -void paste_at(Part* dest_part, const QString& pt, int pos); +void paste_at(const QString& pt, int pos, int max_distance=3072, bool always_new_part=false, bool never_new_part=false, Part* paste_into_part=NULL);  //functions for selections  void select_all(const std::set<Part*>& parts); diff --git a/muse2/muse/midiedit/drumedit.cpp b/muse2/muse/midiedit/drumedit.cpp index 14419e0f..1553ec2b 100644 --- a/muse2/muse/midiedit/drumedit.cpp +++ b/muse2/muse/midiedit/drumedit.cpp @@ -904,7 +904,7 @@ void DrumEdit::cmd(int cmd)              case DrumCanvas::CMD_COPY: copy_notes(partlist_to_set(parts()), 1); break;              case DrumCanvas::CMD_PASTE:                     ((DrumCanvas*)canvas)->cmd(DrumCanvas::CMD_SELECT_NONE); -                  paste_notes(canvas->part()); +                  paste_notes(); // (canvas->part());  TODO FINDMICHJETZT                    break;              case DrumCanvas::CMD_LOAD: load(); break;              case DrumCanvas::CMD_SAVE: save(); break; @@ -936,7 +936,7 @@ void DrumEdit::cmd(int cmd)  void DrumEdit::clipboardChanged()        { -      pasteAction->setEnabled(QApplication::clipboard()->mimeData()->hasFormat(QString("text/x-muse-eventlist"))); +      pasteAction->setEnabled(QApplication::clipboard()->mimeData()->hasFormat(QString("text/x-muse-groupedeventlists")));        }  //--------------------------------------------------------- diff --git a/muse2/muse/midiedit/ecanvas.cpp b/muse2/muse/midiedit/ecanvas.cpp index a829650c..a0545412 100644 --- a/muse2/muse/midiedit/ecanvas.cpp +++ b/muse2/muse/midiedit/ecanvas.cpp @@ -379,13 +379,13 @@ void EventCanvas::viewDropEvent(QDropEvent* event)              //event->ignore();                     // TODO CHECK Tim.              return;              } -      if (event->mimeData()->hasFormat("text/x-muse-eventlist")) { -            text = QString(event->mimeData()->data("text/x-muse-eventlist")); +      if (event->mimeData()->hasFormat("text/x-muse-groupedeventlists")) { +            text = QString(event->mimeData()->data("text/x-muse-groupedeventlists"));              int x = editor->rasterVal(event->pos().x());              if (x < 0)                    x = 0; -            paste_at(curPart, text, x); +            paste_at(text,x); //(curPart, text, x); TODO FINDMICHJETZT              //event->accept();  // TODO              }        else { diff --git a/muse2/muse/midiedit/pianoroll.cpp b/muse2/muse/midiedit/pianoroll.cpp index 89f84062..258efe19 100644 --- a/muse2/muse/midiedit/pianoroll.cpp +++ b/muse2/muse/midiedit/pianoroll.cpp @@ -617,7 +617,7 @@ void PianoRoll::cmd(int cmd)              case PianoCanvas::CMD_COPY: copy_notes(partlist_to_set(parts()), 1); break;              case PianoCanvas::CMD_PASTE:                                 ((PianoCanvas*)canvas)->cmd(PianoCanvas::CMD_SELECT_NONE); -                              paste_notes(canvas->part()); +                              paste_notes(); //(canvas->part()); TODO FINDMICHJETZT                                break;  						case PianoCanvas::CMD_MODIFY_GATE_TIME: modify_notelen(partlist_to_set(parts())); break;  						case PianoCanvas::CMD_MODIFY_VELOCITY: modify_velocity(partlist_to_set(parts())); break; @@ -1180,7 +1180,7 @@ void PianoRoll::setEventColorMode(int mode)  void PianoRoll::clipboardChanged()        { -      editPasteAction->setEnabled(QApplication::clipboard()->mimeData()->hasFormat(QString("text/x-muse-eventlist"))); +      editPasteAction->setEnabled(QApplication::clipboard()->mimeData()->hasFormat(QString("text/x-muse-groupedeventlists")));        }  //--------------------------------------------------------- diff --git a/muse2/muse/midiedit/scoreedit.cpp b/muse2/muse/midiedit/scoreedit.cpp index b65192e5..72740a8e 100644 --- a/muse2/muse/midiedit/scoreedit.cpp +++ b/muse2/muse/midiedit/scoreedit.cpp @@ -679,7 +679,7 @@ void ScoreEdit::menu_command(int cmd)  		case CMD_COPY: copy_notes(score_canvas->get_all_parts(), 1); break;  		case CMD_PASTE:   			menu_command(CMD_SELECT_NONE);  -			paste_notes(score_canvas->get_selected_part()); +			paste_notes(); //(score_canvas->get_selected_part()); TODO FINDMICHJETZT  			break;  		case CMD_QUANTIZE: quantize_notes(score_canvas->get_all_parts()); break;  		case CMD_VELOCITY: modify_velocity(score_canvas->get_all_parts()); break; @@ -700,7 +700,7 @@ void ScoreEdit::menu_command(int cmd)  void ScoreEdit::clipboard_changed()  { -	paste_action->setEnabled(QApplication::clipboard()->mimeData()->hasFormat(QString("text/x-muse-eventlist"))); +	paste_action->setEnabled(QApplication::clipboard()->mimeData()->hasFormat(QString("text/x-muse-groupedeventlists")));  }  void ScoreEdit::selection_changed() @@ -4486,10 +4486,16 @@ void ScoreEdit::keyPressEvent(QKeyEvent* event)   *     changing "share" status, the changed state isn't stored   *    * CURRENT TODO + *   o when pasting and creating new parts, inform the editors about that! + *   o TEST pasting in editors! + *   o pasting in editors: add dialogs + *    * ! o fix sigedit boxes   * M o remove that ugly "bool initalizing" stuff. it's probably unneeded (watch out for the FINDMICH message)   *   o mirror most menus to an additional right-click context menu to avoid the long mouse pointer   *     journey to the menu bar. try to find a way which does not involve duplicate code! + *   o sane defaults for toolbars + *   o paste in midi editors   *   o implement borland-style maximize: free windows do not cover the main menu, even when maximized   *   o smart range selection: if range markers have been used recently (that is, a dialog with   *     "range" setting, or they've been modified), default to "in range" or "selected in range" | 
