2012-05-26 14:26:10 +02:00
|
|
|
//=============================================================================
|
|
|
|
// MuseScore
|
|
|
|
// Music Composition & Notation
|
|
|
|
//
|
2013-09-06 09:36:31 +02:00
|
|
|
// Copyright (C) 2002-2013 Werner Schweer
|
2012-05-26 14:26:10 +02:00
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License version 2
|
|
|
|
// as published by the Free Software Foundation and appearing in
|
|
|
|
// the file LICENCE.GPL
|
|
|
|
//=============================================================================
|
|
|
|
|
|
|
|
/**
|
|
|
|
\file
|
|
|
|
Implementation of undo functions.
|
|
|
|
|
|
|
|
The undo system requires calling startUndo() when starting a GUI command
|
|
|
|
and calling endUndo() when ending the command. All changes to a score
|
|
|
|
in response to a GUI command must be undoable/redoable by executing
|
|
|
|
a sequence of low-level undo operations. This sequence is built by the code
|
|
|
|
handling the command, by calling one or more undoOp()'s
|
|
|
|
between startUndo() and endUndo().
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "undo.h"
|
|
|
|
#include "element.h"
|
|
|
|
#include "note.h"
|
|
|
|
#include "score.h"
|
|
|
|
#include "segment.h"
|
|
|
|
#include "measure.h"
|
|
|
|
#include "system.h"
|
|
|
|
#include "select.h"
|
|
|
|
#include "input.h"
|
|
|
|
#include "slur.h"
|
2013-08-22 12:18:14 +02:00
|
|
|
#include "tie.h"
|
2012-05-26 14:26:10 +02:00
|
|
|
#include "clef.h"
|
|
|
|
#include "staff.h"
|
|
|
|
#include "chord.h"
|
|
|
|
#include "sig.h"
|
|
|
|
#include "key.h"
|
|
|
|
#include "barline.h"
|
|
|
|
#include "volta.h"
|
|
|
|
#include "tuplet.h"
|
|
|
|
#include "harmony.h"
|
|
|
|
#include "pitchspelling.h"
|
|
|
|
#include "part.h"
|
|
|
|
#include "beam.h"
|
|
|
|
#include "dynamic.h"
|
|
|
|
#include "page.h"
|
|
|
|
#include "keysig.h"
|
|
|
|
#include "image.h"
|
|
|
|
#include "hairpin.h"
|
|
|
|
#include "rest.h"
|
|
|
|
#include "bend.h"
|
|
|
|
#include "tremolobar.h"
|
|
|
|
#include "articulation.h"
|
|
|
|
#include "noteevent.h"
|
|
|
|
#include "slur.h"
|
|
|
|
#include "tempotext.h"
|
|
|
|
#include "instrchange.h"
|
|
|
|
#include "box.h"
|
|
|
|
#include "stafftype.h"
|
|
|
|
#include "accidental.h"
|
|
|
|
#include "layoutbreak.h"
|
|
|
|
#include "spanner.h"
|
|
|
|
#include "sequencer.h"
|
|
|
|
#include "breath.h"
|
|
|
|
#include "fingering.h"
|
2013-02-25 19:05:19 +01:00
|
|
|
#include "rehearsalmark.h"
|
|
|
|
#include "excerpt.h"
|
2013-02-27 21:23:30 +01:00
|
|
|
#include "stafftext.h"
|
2013-02-28 15:06:54 +01:00
|
|
|
#include "chordline.h"
|
2013-02-28 17:46:30 +01:00
|
|
|
#include "tremolo.h"
|
2013-11-11 16:53:03 +01:00
|
|
|
#include "sym.h"
|
2014-08-11 21:17:55 +02:00
|
|
|
#include "utils.h"
|
Fix #29986 : Ottavas in TABs - Solution A)
Ottavas are not used in TAB staves, as they do not really make sense in TAB's. Yet, currently ottavas:
- can be dropped on TAB staves
- ottavas added to standard staves are duplicated in TAB staves linked to them
Fix:
- Ottavas cannot be dropped on TAB staves any longer. Attempting to drop an Ottava on a TAB, results in the action being ignored.
- If an `Ottava` is added to a standard staff linked to TAB staves, the standard staff operation is carried over exactly as before, but the Ottava element is not replicated in the TAB linked staff; instead, the actual pitches of corresponding notes in the TAB staff are shifted by the pitchOffset of the Ottava.
- If the `Ottava` span is later edited (in the standard staff, of course), the pitches of the corresponding TAB staff notes are updated accordingly.
Regarding adding ottavas directly to TAB staves, either linked, there is no difference between Solution A) and Solution B): with both, ottavas **cannot** be added to TAB staves.
When TABs are linked to standard staves and ottavas are added to the standard staff, the differences between Solution A) and B) are:
- A) does not create **any** `Ottava` element in TABs; B) creates hidden `Ottava` elements in the linked TAB.
- A) modifies the TAB note pitches to render the ottava effect; B) does not change the stored pitches, only the fretting.
I am not very fond of the hidden `Ottava` trick of Solution B), but that solution seems more in tune with the current code and easier to understand (and maintain). This solution A) seems to me less tricky, but probably less clear to the unaware developer, as each modification of the 'master' `Ottava` has to be cloned into the linked TAB, at the proper place and time with respect to undo/redo machinery.
My 'instinctive' preference is for Solution B), but advice is welcome!
2015-02-25 23:59:41 +01:00
|
|
|
#include "stringdata.h"
|
2015-02-28 09:57:46 +01:00
|
|
|
#include "glissando.h"
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2013-05-13 18:49:17 +02:00
|
|
|
namespace Ms {
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
extern Measure* tick2measure(int tick);
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// updateNoteLines
|
|
|
|
// compute line position of note heads after
|
|
|
|
// clef change
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void updateNoteLines(Segment* segment, int track)
|
|
|
|
{
|
2012-06-26 15:06:53 +02:00
|
|
|
Staff* staff = segment->score()->staff(track / VOICES);
|
2012-09-20 11:35:34 +02:00
|
|
|
if (staff->isDrumStaff() || staff->isTabStaff())
|
2012-06-26 15:06:53 +02:00
|
|
|
return;
|
2012-05-26 14:26:10 +02:00
|
|
|
for (Segment* s = segment->next1(); s; s = s->next1()) {
|
2014-06-25 11:46:10 +02:00
|
|
|
if (s->segmentType() == Segment::Type::Clef && s->element(track) && !s->element(track)->generated())
|
2012-05-26 14:26:10 +02:00
|
|
|
break;
|
2014-06-25 11:46:10 +02:00
|
|
|
if (s->segmentType() != Segment::Type::ChordRest)
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
2012-09-20 11:35:34 +02:00
|
|
|
for (int t = track; t < track + VOICES; ++t) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Chord* chord = static_cast<Chord*>(s->element(t));
|
2014-06-24 18:36:02 +02:00
|
|
|
if (chord && chord->type() == Element::Type::CHORD) {
|
2013-09-21 15:41:54 +02:00
|
|
|
for (Note* n : chord->notes())
|
|
|
|
n->updateLine();
|
2014-04-09 16:09:21 +02:00
|
|
|
chord->sortNotes();
|
2013-09-21 15:41:54 +02:00
|
|
|
for (Chord* gc : chord->graceNotes()) {
|
2014-04-09 16:09:21 +02:00
|
|
|
for (Note* gn : gc->notes())
|
2013-09-21 15:41:54 +02:00
|
|
|
gn->updateLine();
|
2014-04-09 16:09:21 +02:00
|
|
|
gc->sortNotes();
|
2013-09-21 15:41:54 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// UndoCommand
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
UndoCommand::~UndoCommand()
|
|
|
|
{
|
2014-11-06 11:34:42 +01:00
|
|
|
for (auto c : childList)
|
2012-05-26 14:26:10 +02:00
|
|
|
delete c;
|
|
|
|
}
|
|
|
|
|
2014-11-06 11:34:42 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// UndoCommand::cleanup
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void UndoCommand::cleanup(bool undo)
|
|
|
|
{
|
|
|
|
for (auto c : childList)
|
|
|
|
c->cleanup(undo);
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// undo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void UndoCommand::undo()
|
|
|
|
{
|
|
|
|
int n = childList.size();
|
|
|
|
for (int i = n-1; i >= 0; --i) {
|
|
|
|
#ifdef DEBUG_UNDO
|
|
|
|
qDebug(" undo<%s> %p", childList[i]->name(), childList[i]);
|
|
|
|
#endif
|
|
|
|
childList[i]->undo();
|
|
|
|
}
|
2012-11-19 10:08:15 +01:00
|
|
|
flip();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// redo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void UndoCommand::redo()
|
|
|
|
{
|
|
|
|
int n = childList.size();
|
|
|
|
for (int i = 0; i < n; ++i) {
|
|
|
|
#ifdef DEBUG_UNDO
|
|
|
|
qDebug(" redo<%s> %p", childList[i]->name(), childList[i]);
|
|
|
|
#endif
|
|
|
|
childList[i]->redo();
|
|
|
|
}
|
2012-11-19 10:08:15 +01:00
|
|
|
flip();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// unwind
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void UndoCommand::unwind()
|
|
|
|
{
|
|
|
|
while (!childList.isEmpty()) {
|
|
|
|
UndoCommand* c = childList.takeLast();
|
|
|
|
c->undo();
|
|
|
|
delete c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// UndoStack
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
UndoStack::UndoStack()
|
|
|
|
{
|
|
|
|
curCmd = 0;
|
|
|
|
curIdx = 0;
|
|
|
|
cleanIdx = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// UndoStack
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
UndoStack::~UndoStack()
|
|
|
|
{
|
2014-11-10 10:55:25 +01:00
|
|
|
int idx = 0;
|
|
|
|
for (auto c : list)
|
2014-11-06 11:34:42 +01:00
|
|
|
c->cleanup(idx++ < curIdx);
|
|
|
|
qDeleteAll(list);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// beginMacro
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void UndoStack::beginMacro()
|
|
|
|
{
|
|
|
|
if (curCmd) {
|
2014-01-13 16:37:02 +01:00
|
|
|
qDebug("UndoStack:beginMacro(): already active");
|
2012-05-26 14:26:10 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
curCmd = new UndoCommand();
|
|
|
|
if (MScore::debugMode)
|
|
|
|
qDebug("UndoStack::beginMacro %p, UndoStack %p", curCmd, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// endMacro
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void UndoStack::endMacro(bool rollback)
|
|
|
|
{
|
|
|
|
if (MScore::debugMode)
|
|
|
|
qDebug("UndoStack::endMacro %d", rollback);
|
|
|
|
if (curCmd == 0) {
|
|
|
|
qDebug("UndoStack:endMacro(): not active");
|
|
|
|
return;
|
|
|
|
}
|
2012-09-05 11:49:48 +02:00
|
|
|
if (rollback)
|
2012-05-26 14:26:10 +02:00
|
|
|
delete curCmd;
|
2012-09-05 11:49:48 +02:00
|
|
|
else {
|
2014-11-06 11:34:42 +01:00
|
|
|
// remove redo stack
|
2012-09-05 11:49:48 +02:00
|
|
|
while (list.size() > curIdx) {
|
|
|
|
UndoCommand* cmd = list.takeLast();
|
2014-11-06 11:34:42 +01:00
|
|
|
cmd->cleanup(false); // delete elements for which UndoCommand() holds ownership
|
2012-09-05 11:49:48 +02:00
|
|
|
delete cmd;
|
|
|
|
}
|
|
|
|
list.append(curCmd);
|
|
|
|
++curIdx;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
curCmd = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// push
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void UndoStack::push(UndoCommand* cmd)
|
|
|
|
{
|
|
|
|
if (!curCmd) {
|
|
|
|
// this can happen for layout() outside of a command (load)
|
|
|
|
// qDebug("UndoStack:push(): no active command, UndoStack %p", this);
|
|
|
|
|
|
|
|
cmd->redo();
|
|
|
|
delete cmd;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#ifdef DEBUG_UNDO
|
2014-11-14 18:08:02 +01:00
|
|
|
if (!strcmp(cmd->name(), "ChangeProperty")) {
|
2012-09-05 11:49:48 +02:00
|
|
|
ChangeProperty* cp = static_cast<ChangeProperty*>(cmd);
|
|
|
|
qDebug("UndoStack::push <%s> %p id %d", cmd->name(), cmd, int(cp->getId()));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
qDebug("UndoStack::push <%s> %p", cmd->name(), cmd);
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
#endif
|
|
|
|
curCmd->appendChild(cmd);
|
|
|
|
cmd->redo();
|
|
|
|
}
|
|
|
|
|
2013-02-26 15:50:36 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// push1
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void UndoStack::push1(UndoCommand* cmd)
|
|
|
|
{
|
|
|
|
if (curCmd)
|
|
|
|
curCmd->appendChild(cmd);
|
2013-06-10 11:03:34 +02:00
|
|
|
else
|
|
|
|
qDebug("UndoStack:push1(): no active command, UndoStack %p", this);
|
2013-02-26 15:50:36 +01:00
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// pop
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void UndoStack::pop()
|
|
|
|
{
|
|
|
|
if (!curCmd) {
|
|
|
|
qDebug("UndoStack:pop(): no active command");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
UndoCommand* cmd = curCmd->removeChild();
|
|
|
|
cmd->undo();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// setClean
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void UndoStack::setClean()
|
|
|
|
{
|
|
|
|
if (cleanIdx != curIdx) {
|
|
|
|
cleanIdx = curIdx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void UndoStack::undo()
|
|
|
|
{
|
|
|
|
if (curIdx) {
|
|
|
|
--curIdx;
|
|
|
|
Q_ASSERT(curIdx >= 0);
|
|
|
|
if (MScore::debugMode)
|
|
|
|
qDebug("--undo index %d", curIdx);
|
|
|
|
list[curIdx]->undo();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// redo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void UndoStack::redo()
|
|
|
|
{
|
|
|
|
if (canRedo()) {
|
|
|
|
if (MScore::debugMode)
|
|
|
|
qDebug("--redo index %d", curIdx);
|
|
|
|
list[curIdx++]->redo();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// SaveState
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
SaveState::SaveState(Score* s)
|
2013-10-24 12:09:00 +02:00
|
|
|
: undoInputState(s), redoInputState(s->inputState())
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
score = s;
|
|
|
|
redoSelection = score->selection();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SaveState::undo()
|
|
|
|
{
|
|
|
|
redoInputState = score->inputState();
|
|
|
|
redoSelection = score->selection();
|
|
|
|
score->setInputState(undoInputState);
|
|
|
|
score->setSelection(undoSelection);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SaveState::redo()
|
|
|
|
{
|
|
|
|
undoInputState = score->inputState();
|
|
|
|
undoSelection = score->selection();
|
|
|
|
score->setInputState(redoInputState);
|
|
|
|
score->setSelection(redoSelection);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoChangeProperty
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2015-02-12 11:41:39 +01:00
|
|
|
void Score::undoChangeProperty(ScoreElement* e, P_ID t, const QVariant& st, PropertyStyle ps)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2014-07-17 09:32:30 +02:00
|
|
|
if (propertyLink(t)) {
|
2015-02-12 11:41:39 +01:00
|
|
|
for (ScoreElement* ee : e->linkList()) {
|
|
|
|
if (ee->getProperty(t) != st)
|
|
|
|
undo(new ChangeProperty(ee, t, st, ps));
|
2013-02-27 14:41:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (e->getProperty(t) != st)
|
2015-02-12 11:41:39 +01:00
|
|
|
undo(new ChangeProperty(e, t, st, ps));
|
2013-02-27 14:41:04 +01:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2013-06-10 11:03:34 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoPropertyChanged
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::undoPropertyChanged(Element* e, P_ID t, const QVariant& st)
|
|
|
|
{
|
|
|
|
if (propertyLink(t) && e->links()) {
|
2015-02-12 11:41:39 +01:00
|
|
|
foreach (ScoreElement* ee, *e->links()) {
|
2013-06-10 11:03:34 +02:00
|
|
|
if (ee == e) {
|
|
|
|
if (ee->getProperty(t) != st)
|
|
|
|
undo()->push1(new ChangeProperty(ee, t, st));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// property in linked element has not changed yet
|
|
|
|
// push() calls redo() to change it
|
|
|
|
if (ee->getProperty(t) != e->getProperty(t))
|
|
|
|
undo()->push(new ChangeProperty(ee, t, e->getProperty(t)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (e->getProperty(t) != st) {
|
|
|
|
undo()->push1(new ChangeProperty(e, t, st));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-04 22:12:13 +01:00
|
|
|
void Score::undoPropertyChanged(ScoreElement* e, P_ID t, const QVariant& st)
|
|
|
|
{
|
|
|
|
if (e->getProperty(t) != st)
|
|
|
|
undo()->push1(new ChangeProperty(e, t, st));
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoChangeElement
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::undoChangeElement(Element* oldElement, Element* newElement)
|
|
|
|
{
|
2015-02-14 12:00:42 +01:00
|
|
|
if (!oldElement)
|
|
|
|
undoAddElement(newElement);
|
|
|
|
else
|
|
|
|
undo(new ChangeElement(oldElement, newElement));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoChangePitch
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2014-04-09 09:40:25 +02:00
|
|
|
void Score::undoChangePitch(Note* note, int pitch, int tpc1, int tpc2)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2014-04-09 09:40:25 +02:00
|
|
|
const LinkedElements* l = note->links();
|
2012-09-10 16:10:25 +02:00
|
|
|
if (l) {
|
2015-02-12 11:41:39 +01:00
|
|
|
for (ScoreElement* e : *l) {
|
2014-04-09 09:40:25 +02:00
|
|
|
Note* n = static_cast<Note*>(e);
|
|
|
|
undo()->push(new ChangePitch(n, pitch, tpc1, tpc2));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
2012-09-10 16:10:25 +02:00
|
|
|
else
|
2014-04-09 09:40:25 +02:00
|
|
|
undo()->push(new ChangePitch(note, pitch, tpc1, tpc2));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2014-09-07 10:59:12 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoChangeFretting
|
|
|
|
//
|
|
|
|
// To use with tablatures to force a specific note fretting;
|
|
|
|
// Pitch, string and fret must be changed all together; otherwise,
|
|
|
|
// if they are not consistent among themselves, the refretting algorithm may re-assign
|
|
|
|
// fret and string numbers for (potentially) all the notes of all the chords of a segment.
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::undoChangeFretting(Note* note, int pitch, int string, int fret, int tpc1, int tpc2)
|
|
|
|
{
|
|
|
|
const LinkedElements* l = note->links();
|
|
|
|
if (l) {
|
2015-02-12 11:41:39 +01:00
|
|
|
for (ScoreElement* e : *l) {
|
2014-09-07 10:59:12 +02:00
|
|
|
Note* n = static_cast<Note*>(e);
|
|
|
|
undo()->push(new ChangeFretting(n, pitch, string, fret, tpc1, tpc2));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
undo()->push(new ChangeFretting(note, pitch, string, fret, tpc1, tpc2));
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoChangeKeySig
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2014-12-04 14:40:26 +01:00
|
|
|
void Score::undoChangeKeySig(Staff* ostaff, int tick, KeySigEvent key)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2014-05-21 20:08:37 +02:00
|
|
|
KeySig* lks = 0;
|
|
|
|
foreach (Staff* staff, ostaff->staffList()) {
|
2014-09-01 16:02:57 +02:00
|
|
|
if (staff->isDrumStaff())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Score* score = staff->score();
|
2012-05-26 14:26:10 +02:00
|
|
|
Measure* measure = score->tick2measure(tick);
|
|
|
|
if (!measure) {
|
|
|
|
qDebug("measure for tick %d not found!", tick);
|
|
|
|
continue;
|
|
|
|
}
|
2014-06-25 11:46:10 +02:00
|
|
|
Segment* s = measure->undoGetSegment(Segment::Type::KeySig, tick);
|
2014-06-02 13:07:19 +02:00
|
|
|
int staffIdx = staff->idx();
|
2012-05-26 14:26:10 +02:00
|
|
|
int track = staffIdx * VOICES;
|
|
|
|
KeySig* ks = static_cast<KeySig*>(s->element(track));
|
|
|
|
|
2014-12-15 13:31:59 +01:00
|
|
|
Interval interval = staff->part()->instr()->transpose();
|
2014-12-04 14:40:26 +01:00
|
|
|
KeySigEvent nkey = key;
|
2014-12-15 13:31:59 +01:00
|
|
|
bool concertPitch = score->styleB(StyleIdx::concertPitch);
|
|
|
|
if (interval.chromatic && !concertPitch && !nkey.custom()) {
|
|
|
|
interval.flip();
|
|
|
|
nkey.setKey(transposeKey(key.key(), interval));
|
|
|
|
}
|
2014-06-02 13:07:19 +02:00
|
|
|
if (ks) {
|
|
|
|
ks->undoChangeProperty(P_ID::GENERATED, false);
|
2014-12-04 14:40:26 +01:00
|
|
|
undo(new ChangeKeySig(ks, nkey, ks->showCourtesy()));
|
2014-06-02 13:07:19 +02:00
|
|
|
}
|
2014-05-21 20:08:37 +02:00
|
|
|
else {
|
2014-06-03 15:28:10 +02:00
|
|
|
KeySig* nks = new KeySig(score);
|
2014-05-21 20:08:37 +02:00
|
|
|
nks->setParent(s);
|
|
|
|
nks->setTrack(track);
|
2014-12-04 14:40:26 +01:00
|
|
|
nks->setKeySigEvent(nkey);
|
2012-05-26 14:26:10 +02:00
|
|
|
undo(new AddElement(nks));
|
2014-05-21 20:08:37 +02:00
|
|
|
if (lks)
|
|
|
|
lks->linkTo(nks);
|
|
|
|
else
|
|
|
|
lks = nks;
|
2013-09-25 11:13:50 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoChangeClef
|
2013-06-05 15:47:34 +02:00
|
|
|
// change clef if seg contains a clef
|
|
|
|
// else
|
|
|
|
// create a clef before segment seg
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::undoChangeClef(Staff* ostaff, Segment* seg, ClefType st)
|
|
|
|
{
|
|
|
|
bool firstSeg = seg->measure()->first() == seg;
|
|
|
|
|
2014-07-25 17:13:27 +02:00
|
|
|
Clef* gclef = 0;
|
|
|
|
foreach (Staff* staff, ostaff->staffList()) {
|
2013-09-05 16:37:49 +02:00
|
|
|
if (staff->staffType()->group() != ClefInfo::staffGroup(st))
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
2014-07-25 17:13:27 +02:00
|
|
|
|
|
|
|
Score* score = staff->score();
|
|
|
|
int tick = seg->tick();
|
2013-06-05 09:53:38 +02:00
|
|
|
Measure* measure = score->tick2measure(tick);
|
2012-05-26 14:26:10 +02:00
|
|
|
if (!measure) {
|
2013-06-05 09:53:38 +02:00
|
|
|
qDebug("measure for tick %d not found!", tick);
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-06-25 11:46:10 +02:00
|
|
|
Segment* destSeg = measure->findSegment(Segment::Type::Clef, tick);
|
2013-06-05 15:47:34 +02:00
|
|
|
|
2013-12-24 20:11:51 +01:00
|
|
|
// move measure-initial clef to last segment of prev measure
|
|
|
|
|
|
|
|
if (firstSeg // if at start of measure
|
|
|
|
&& measure->prevMeasure() // and there is a previous measure
|
2012-05-26 14:26:10 +02:00
|
|
|
) {
|
|
|
|
measure = measure->prevMeasure();
|
2014-06-25 11:46:10 +02:00
|
|
|
destSeg = measure->findSegment(Segment::Type::Clef, tick);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2014-07-25 17:13:27 +02:00
|
|
|
if (!destSeg) {
|
2014-06-25 11:46:10 +02:00
|
|
|
destSeg = new Segment(measure, Segment::Type::Clef, seg->tick());
|
2013-12-24 20:11:51 +01:00
|
|
|
score->undoAddElement(destSeg);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
int staffIdx = staff->idx();
|
|
|
|
int track = staffIdx * VOICES;
|
2013-12-24 20:11:51 +01:00
|
|
|
Clef* clef = static_cast<Clef*>(destSeg->element(track));
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
if (clef) {
|
|
|
|
//
|
|
|
|
// for transposing instruments, differentiate
|
|
|
|
// clef type for concertPitch
|
|
|
|
//
|
|
|
|
Instrument* i = staff->part()->instr(tick);
|
|
|
|
ClefType cp, tp;
|
|
|
|
if (i->transpose().isZero()) {
|
|
|
|
cp = st;
|
|
|
|
tp = st;
|
|
|
|
}
|
|
|
|
else {
|
2014-04-09 16:09:21 +02:00
|
|
|
bool concertPitch = clef->concertPitch();
|
2012-05-26 14:26:10 +02:00
|
|
|
if (concertPitch) {
|
|
|
|
cp = st;
|
|
|
|
tp = clef->transposingClef();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
cp = clef->concertClef();
|
|
|
|
tp = st;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
clef->setGenerated(false);
|
|
|
|
score->undo(new ChangeClefType(clef, cp, tp));
|
2014-11-09 20:37:56 +01:00
|
|
|
// change the clef in the mmRest if any
|
|
|
|
if (measure->hasMMRest()) {
|
|
|
|
Measure* mmMeasure = measure->mmRest();
|
|
|
|
Segment* mmDestSeg = mmMeasure->findSegment(Segment::Type::Clef, tick);
|
|
|
|
if (mmDestSeg) {
|
|
|
|
Clef* mmClef = static_cast<Clef*>(mmDestSeg->element(clef->track()));
|
|
|
|
if (mmClef)
|
|
|
|
score->undo(new ChangeClefType(mmClef, cp, tp));
|
|
|
|
}
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else {
|
2014-07-25 17:13:27 +02:00
|
|
|
if (gclef) {
|
|
|
|
clef = static_cast<Clef*>(gclef->linkedClone());
|
|
|
|
clef->setScore(score);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
clef = new Clef(score);
|
|
|
|
gclef = clef;
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
clef->setTrack(track);
|
|
|
|
clef->setClefType(st);
|
2013-12-24 20:11:51 +01:00
|
|
|
clef->setParent(destSeg);
|
2012-05-26 14:26:10 +02:00
|
|
|
score->undo(new AddElement(clef));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// findLinkedVoiceElement
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static Element* findLinkedVoiceElement(Element* e, Staff* nstaff)
|
|
|
|
{
|
|
|
|
Score* score = nstaff->score();
|
|
|
|
Segment* segment = static_cast<Segment*>(e->parent());
|
|
|
|
Measure* measure = segment->measure();
|
|
|
|
Measure* m = score->tick2measure(measure->tick());
|
2013-03-05 20:23:59 +01:00
|
|
|
Segment* s = m->findSegment(segment->segmentType(), segment->tick());
|
2012-05-26 14:26:10 +02:00
|
|
|
int staffIdx = score->staffIdx(nstaff);
|
|
|
|
return s->element(staffIdx * VOICES + e->voice());
|
|
|
|
}
|
|
|
|
|
2014-11-29 08:27:07 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// findLinkedChord
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static Chord* findLinkedChord(Chord* c, Staff* nstaff)
|
|
|
|
{
|
|
|
|
Segment* s = c->segment();
|
|
|
|
Measure* nm = nstaff->score()->tick2measure(s->tick());
|
|
|
|
Segment* ns = nm->findSegment(s->segmentType(), s->tick());
|
|
|
|
Element* ne = ns->element(nstaff->idx() * VOICES + c->voice());
|
|
|
|
if (ne->type() != Element::Type::CHORD)
|
|
|
|
return 0;
|
|
|
|
Chord* nc = static_cast<Chord*>(ne);
|
|
|
|
if (c->isGrace()) {
|
|
|
|
Chord* pc = static_cast<Chord*>(c->parent());
|
|
|
|
int index = 0;
|
|
|
|
for (Chord* gc : pc->graceNotes()) {
|
|
|
|
if (c == gc)
|
|
|
|
break;
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
if (index < nc->graceNotes().length())
|
|
|
|
nc = nc->graceNotes().at(index);
|
|
|
|
}
|
|
|
|
return nc;
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoChangeChordRestLen
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::undoChangeChordRestLen(ChordRest* cr, const TDuration& d)
|
|
|
|
{
|
2015-02-16 09:44:21 +01:00
|
|
|
auto sl = cr->staff()->staffList();
|
|
|
|
for (Staff* staff : sl) {
|
|
|
|
ChordRest *ncr;
|
|
|
|
if (cr->isGrace())
|
|
|
|
ncr = findLinkedChord(static_cast<Chord*>(cr), staff);
|
|
|
|
else
|
|
|
|
ncr = static_cast<ChordRest*>(findLinkedVoiceElement(cr, staff));
|
|
|
|
ncr->undoChangeProperty(P_ID::DURATION_TYPE, QVariant::fromValue(d));
|
|
|
|
ncr->undoChangeProperty(P_ID::DURATION, QVariant::fromValue(d.fraction()));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoChangeEndBarLineType
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::undoChangeEndBarLineType(Measure* m, BarLineType subtype)
|
|
|
|
{
|
|
|
|
undo(new ChangeEndBarLineType(m, subtype));
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoChangeBarLineSpan
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2012-10-14 00:35:11 +02:00
|
|
|
void Score::undoChangeBarLineSpan(Staff* staff, int span, int spanFrom, int spanTo)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2012-10-14 00:35:11 +02:00
|
|
|
undo(new ChangeBarLineSpan(staff, span, spanFrom, spanTo));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2012-10-14 19:48:36 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoChangeSingleBarLineSpan
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::undoChangeSingleBarLineSpan(BarLine* barLine, int span, int spanFrom, int spanTo)
|
|
|
|
{
|
|
|
|
undo(new ChangeSingleBarLineSpan(barLine, span, spanFrom, spanTo));
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoTransposeHarmony
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::undoTransposeHarmony(Harmony* h, int rootTpc, int baseTpc)
|
|
|
|
{
|
|
|
|
undo(new TransposeHarmony(h, rootTpc, baseTpc));
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoExchangeVoice
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::undoExchangeVoice(Measure* measure, int v1, int v2, int staff1, int staff2)
|
|
|
|
{
|
2014-08-29 10:35:17 +02:00
|
|
|
int tick = measure->tick();
|
|
|
|
QSet<Staff*> sl;
|
|
|
|
for (int staffIdx = staff1; staffIdx < staff2; ++staffIdx) {
|
|
|
|
for (Staff* s : staff(staffIdx)->staffList())
|
|
|
|
sl.insert(s);
|
|
|
|
}
|
|
|
|
for (Staff* s : sl) {
|
|
|
|
Measure* m = s->score()->tick2measure(tick);
|
|
|
|
undo(new ExchangeVoice(m, v1, v2, s->idx()));
|
|
|
|
}
|
|
|
|
|
|
|
|
// make sure voice 0 is complete
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
if (v1 == 0 || v2 == 0) {
|
|
|
|
for (int staffIdx = staff1; staffIdx < staff2; ++staffIdx) {
|
|
|
|
// check for complete timeline of voice 0
|
|
|
|
int ctick = measure->tick();
|
|
|
|
int track = staffIdx * VOICES;
|
2014-06-25 11:46:10 +02:00
|
|
|
for (Segment* s = measure->first(Segment::Type::ChordRest); s; s = s->next(Segment::Type::ChordRest)) {
|
2012-05-26 14:26:10 +02:00
|
|
|
ChordRest* cr = static_cast<ChordRest*>(s->element(track));
|
|
|
|
if (cr == 0)
|
|
|
|
continue;
|
|
|
|
if (ctick < s->tick()) {
|
|
|
|
// fill gap
|
|
|
|
int ticks = s->tick() - ctick;
|
|
|
|
setRest(ctick, track, Fraction::fromTicks(ticks), false, 0);
|
|
|
|
}
|
|
|
|
ctick = s->tick() + cr->actualTicks();
|
|
|
|
}
|
|
|
|
int etick = measure->tick() + measure->ticks();
|
|
|
|
if (ctick < etick) {
|
|
|
|
// fill gap
|
|
|
|
int ticks = etick - ctick;
|
|
|
|
setRest(ctick, track, Fraction::fromTicks(ticks), false, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoRemovePart
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::undoRemovePart(Part* part, int idx)
|
|
|
|
{
|
|
|
|
undo(new RemovePart(part, idx));
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoInsertPart
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::undoInsertPart(Part* part, int idx)
|
|
|
|
{
|
|
|
|
undo(new InsertPart(part, idx));
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoRemoveStaff
|
2014-08-11 15:25:55 +02:00
|
|
|
// idx - index of staff in part
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2014-08-11 15:25:55 +02:00
|
|
|
void Score::undoRemoveStaff(Staff* staff)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2014-08-25 19:30:56 +02:00
|
|
|
int idx = staff->idx();
|
2014-08-19 09:52:30 +02:00
|
|
|
Q_ASSERT(idx >= 0);
|
2014-08-16 14:18:06 +02:00
|
|
|
//
|
|
|
|
// adjust measures
|
|
|
|
//
|
2014-08-25 19:30:56 +02:00
|
|
|
for (Measure* m = staff->score()->firstMeasure(); m; m = m->nextMeasure()) {
|
2014-08-16 14:18:06 +02:00
|
|
|
m->cmdRemoveStaves(idx, idx+1);
|
|
|
|
if (m->hasMMRest())
|
|
|
|
m->mmRest()->cmdRemoveStaves(idx, idx+1);
|
|
|
|
}
|
|
|
|
|
2014-08-11 15:25:55 +02:00
|
|
|
undo(new RemoveStaff(staff));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoInsertStaff
|
2014-08-11 15:25:55 +02:00
|
|
|
// idx - index of staff in part
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2014-08-16 17:54:10 +02:00
|
|
|
void Score::undoInsertStaff(Staff* staff, int ridx, bool createRests)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2014-08-16 17:54:10 +02:00
|
|
|
undo(new InsertStaff(staff, ridx));
|
|
|
|
int idx = staffIdx(staff->part()) + ridx;
|
2014-08-16 14:18:06 +02:00
|
|
|
for (Measure* m = firstMeasure(); m; m = m->nextMeasure()) {
|
2014-08-16 16:10:47 +02:00
|
|
|
m->cmdAddStaves(idx, idx+1, createRests);
|
2014-08-16 14:18:06 +02:00
|
|
|
if (m->hasMMRest())
|
2014-09-17 21:52:57 +02:00
|
|
|
m->mmRest()->cmdAddStaves(idx, idx+1, false);
|
2014-08-16 14:18:06 +02:00
|
|
|
}
|
2015-02-20 23:17:53 +01:00
|
|
|
// when newly adding an instrument,
|
|
|
|
// this was already set when we created the staff
|
|
|
|
// we don't have any better info at this point
|
|
|
|
// and it dooesn't work to adjust bracket & barlines until all staves are added
|
|
|
|
// TODO: adjust brackets only when appropriate
|
|
|
|
//adjustBracketsIns(idx, idx+1);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoChangeChordRestSize
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::undoChangeChordRestSize(ChordRest* cr, bool small)
|
|
|
|
{
|
|
|
|
undo(new ChangeChordRestSize(cr, small));
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoChangeChordNoStem
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::undoChangeChordNoStem(Chord* cr, bool noStem)
|
|
|
|
{
|
|
|
|
undo(new ChangeChordNoStem(cr, noStem));
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoChangeBracketSpan
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::undoChangeBracketSpan(Staff* staff, int column, int span)
|
|
|
|
{
|
|
|
|
undo(new ChangeBracketSpan(staff, column, span));
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoChangeInvisible
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::undoChangeInvisible(Element* e, bool v)
|
|
|
|
{
|
2014-05-26 18:18:01 +02:00
|
|
|
undoChangeProperty(e, P_ID::VISIBLE, v);
|
2012-05-26 14:26:10 +02:00
|
|
|
e->setGenerated(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoAddElement
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::undoAddElement(Element* element)
|
|
|
|
{
|
2014-03-14 11:30:19 +01:00
|
|
|
QList<Staff* > staffList;
|
2013-06-10 11:03:34 +02:00
|
|
|
Staff* ostaff = element->staff();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2014-06-24 18:36:02 +02:00
|
|
|
Element::Type et = element->type();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2013-02-25 21:57:11 +01:00
|
|
|
//
|
2013-02-25 19:05:19 +01:00
|
|
|
// some elements are replicated for all parts regardless of
|
|
|
|
// linking:
|
2013-02-25 21:57:11 +01:00
|
|
|
//
|
2013-02-25 19:05:19 +01:00
|
|
|
|
2014-06-24 18:36:02 +02:00
|
|
|
if ((et == Element::Type::REHEARSAL_MARK)
|
|
|
|
|| ((et == Element::Type::STAFF_TEXT) && static_cast<StaffText*>(element)->systemFlag())
|
|
|
|
|| (et == Element::Type::JUMP)
|
|
|
|
|| (et == Element::Type::MARKER)
|
|
|
|
|| (et == Element::Type::TEMPO_TEXT)
|
2014-07-01 01:07:38 +02:00
|
|
|
|| (et == Element::Type::VOLTA)
|
2013-02-27 21:23:30 +01:00
|
|
|
) {
|
2013-02-25 21:57:11 +01:00
|
|
|
foreach(Score* s, scoreList())
|
|
|
|
staffList.append(s->staff(0));
|
2013-02-25 19:05:19 +01:00
|
|
|
|
|
|
|
foreach(Staff* staff, staffList) {
|
|
|
|
Score* score = staff->score();
|
|
|
|
int staffIdx = score->staffIdx(staff);
|
|
|
|
Element* ne;
|
|
|
|
if (staff == ostaff)
|
|
|
|
ne = element;
|
|
|
|
else {
|
|
|
|
ne = element->linkedClone();
|
|
|
|
ne->setScore(score);
|
|
|
|
ne->setSelected(false);
|
|
|
|
ne->setTrack(staffIdx * VOICES + element->voice());
|
|
|
|
}
|
2014-07-01 01:07:38 +02:00
|
|
|
|
|
|
|
if (et == Element::Type::VOLTA) {
|
|
|
|
Spanner* nsp = static_cast<Spanner*>(ne);
|
|
|
|
Spanner* sp = static_cast<Spanner*>(element);
|
|
|
|
int staffIdx1 = sp->track() / VOICES;
|
|
|
|
int staffIdx2 = sp->track2() / VOICES;
|
|
|
|
int diff = staffIdx2 - staffIdx1;
|
|
|
|
nsp->setTrack2((staffIdx + diff) * VOICES + (sp->track2() % VOICES));
|
|
|
|
undo(new AddElement(nsp));
|
|
|
|
}
|
2014-08-05 20:40:43 +02:00
|
|
|
else if (et == Element::Type::MARKER || et == Element::Type::JUMP) {
|
|
|
|
Measure* om = static_cast<Measure*>(element->parent());
|
|
|
|
Measure* m = score->tick2measure(om->tick());
|
|
|
|
ne->setTrack(element->track());
|
|
|
|
ne->setParent(m);
|
|
|
|
undo(new AddElement(ne));
|
|
|
|
}
|
2014-07-01 01:07:38 +02:00
|
|
|
else {
|
2013-02-27 21:23:30 +01:00
|
|
|
Segment* segment = static_cast<Segment*>(element->parent());
|
2013-02-25 19:05:19 +01:00
|
|
|
int tick = segment->tick();
|
|
|
|
Measure* m = score->tick2measure(tick);
|
2014-10-22 06:12:51 +02:00
|
|
|
Segment* seg = m->undoGetSegment(Segment::Type::ChordRest, tick);
|
2013-02-27 21:23:30 +01:00
|
|
|
int ntrack = staffIdx * VOICES + element->voice();
|
|
|
|
ne->setTrack(ntrack);
|
|
|
|
ne->setParent(seg);
|
|
|
|
undo(new AddElement(ne));
|
2013-02-25 19:05:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-06-24 18:36:02 +02:00
|
|
|
if (et == Element::Type::FINGERING
|
|
|
|
|| (et == Element::Type::IMAGE && element->parent()->type() != Element::Type::SEGMENT)
|
|
|
|
|| (et == Element::Type::SYMBOL && element->parent()->type() != Element::Type::SEGMENT)
|
|
|
|
|| et == Element::Type::NOTE
|
2014-08-08 10:23:06 +02:00
|
|
|
|| et == Element::Type::TEXT
|
2014-06-24 18:36:02 +02:00
|
|
|
|| et == Element::Type::GLISSANDO
|
2014-08-08 11:22:59 +02:00
|
|
|
|| et == Element::Type::BEND
|
2014-06-24 18:36:02 +02:00
|
|
|
|| (et == Element::Type::CHORD && static_cast<Chord*>(element)->isGrace())
|
2012-05-26 14:26:10 +02:00
|
|
|
) {
|
|
|
|
Element* parent = element->parent();
|
2014-02-28 14:25:47 +01:00
|
|
|
const LinkedElements* links = parent->links();
|
2014-11-03 17:11:10 +01:00
|
|
|
// don't link part name
|
|
|
|
if (et == Element::Type::TEXT) {
|
|
|
|
Text* t = static_cast<Text*>(element);
|
|
|
|
if (t->textStyleType() == TextStyleType::INSTRUMENT_EXCERPT)
|
|
|
|
links = 0;
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
if (links == 0) {
|
|
|
|
undo(new AddElement(element));
|
2014-10-17 03:42:24 +02:00
|
|
|
if (element->type() == Element::Type::FINGERING && element->userOff().isNull())
|
2012-05-26 14:26:10 +02:00
|
|
|
element->score()->layoutFingering(static_cast<Fingering*>(element));
|
2014-06-24 18:36:02 +02:00
|
|
|
else if (element->type() == Element::Type::CHORD) {
|
2014-05-31 18:43:52 +02:00
|
|
|
#ifndef QT_NO_DEBUG
|
2013-08-30 15:05:17 +02:00
|
|
|
for (Note* n : static_cast<Chord*>(element)->notes()) {
|
2014-05-30 10:18:20 +02:00
|
|
|
// if(n->tpc() == Tpc::TPC_INVALID)
|
2014-04-09 09:40:25 +02:00
|
|
|
// n->setTpcFromPitch();
|
2014-05-30 10:18:20 +02:00
|
|
|
Q_ASSERT(n->tpc() != Tpc::TPC_INVALID);
|
2013-08-30 15:05:17 +02:00
|
|
|
}
|
2014-05-31 18:43:52 +02:00
|
|
|
#endif
|
2013-06-21 11:26:56 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
return;
|
|
|
|
}
|
2015-02-12 11:41:39 +01:00
|
|
|
foreach (ScoreElement* ee, *links) {
|
|
|
|
Element* e = static_cast<Element*>(ee);
|
2015-02-28 09:57:46 +01:00
|
|
|
Element* ne;
|
|
|
|
if (e == parent)
|
|
|
|
ne = element;
|
|
|
|
else {
|
|
|
|
if (element->type() == Element::Type::GLISSANDO) { // and other spanners with Anchor::NOTE
|
|
|
|
Note* newEnd = Spanner::endElementFromSpanner(static_cast<Glissando*>(element), e);
|
|
|
|
if (newEnd) {
|
|
|
|
ne = element->linkedClone();
|
|
|
|
static_cast<Spanner*>(ne)->setNoteSpan(static_cast<Note*>(e), newEnd);
|
|
|
|
}
|
|
|
|
else //couldn't find suitable start note
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ne = element->linkedClone();
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
ne->setScore(e->score());
|
|
|
|
ne->setSelected(false);
|
|
|
|
ne->setParent(e);
|
|
|
|
undo(new AddElement(ne));
|
2014-06-24 18:36:02 +02:00
|
|
|
if (ne->type() == Element::Type::FINGERING)
|
2012-05-26 14:26:10 +02:00
|
|
|
e->score()->layoutFingering(static_cast<Fingering*>(ne));
|
2014-06-24 18:36:02 +02:00
|
|
|
else if (ne->type() == Element::Type::CHORD) {
|
2014-05-31 18:43:52 +02:00
|
|
|
#ifndef QT_NO_DEBUG
|
2014-04-09 09:40:25 +02:00
|
|
|
for (Note* n : static_cast<Chord*>(ne)->notes()) {
|
2014-05-30 10:18:20 +02:00
|
|
|
Q_ASSERT(n->tpc() != Tpc::TPC_INVALID);
|
2014-04-09 09:40:25 +02:00
|
|
|
// n->setTpcFromPitch();
|
|
|
|
}
|
2014-05-31 18:43:52 +02:00
|
|
|
#endif
|
2013-06-21 11:26:56 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-24 12:37:08 +02:00
|
|
|
if (et == Element::Type::LAYOUT_BREAK) {
|
|
|
|
LayoutBreak* lb = static_cast<LayoutBreak*>(element);
|
|
|
|
if (lb->layoutBreakType() == LayoutBreak::Type::SECTION) {
|
|
|
|
Measure* m = lb->measure();
|
|
|
|
foreach(Score* s, scoreList()) {
|
|
|
|
if (s == lb->score())
|
|
|
|
undo(new AddElement(lb));
|
|
|
|
else {
|
|
|
|
Element* e = lb->linkedClone();
|
2015-02-14 20:58:38 +01:00
|
|
|
e->setScore(s);
|
2014-07-24 12:37:08 +02:00
|
|
|
Measure* nm = s->tick2measure(m->tick());
|
|
|
|
e->setParent(nm);
|
|
|
|
undo(new AddElement(e));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-28 15:06:54 +01:00
|
|
|
if (ostaff == 0 || (
|
2014-06-24 18:36:02 +02:00
|
|
|
et != Element::Type::ARTICULATION
|
|
|
|
&& et != Element::Type::CHORDLINE
|
2014-08-30 00:41:28 +02:00
|
|
|
&& et != Element::Type::LYRICS
|
2014-06-24 18:36:02 +02:00
|
|
|
&& et != Element::Type::SLUR
|
|
|
|
&& et != Element::Type::TIE
|
|
|
|
&& et != Element::Type::NOTE
|
|
|
|
&& et != Element::Type::INSTRUMENT_CHANGE
|
|
|
|
&& et != Element::Type::HAIRPIN
|
|
|
|
&& et != Element::Type::OTTAVA
|
|
|
|
&& et != Element::Type::TRILL
|
|
|
|
&& et != Element::Type::TEXTLINE
|
|
|
|
&& et != Element::Type::PEDAL
|
|
|
|
&& et != Element::Type::BREATH
|
|
|
|
&& et != Element::Type::DYNAMIC
|
|
|
|
&& et != Element::Type::STAFF_TEXT
|
|
|
|
&& et != Element::Type::TREMOLO
|
|
|
|
&& et != Element::Type::ARPEGGIO
|
|
|
|
&& et != Element::Type::SYMBOL
|
2014-08-01 05:00:25 +02:00
|
|
|
&& et != Element::Type::FRET_DIAGRAM
|
2014-06-24 18:36:02 +02:00
|
|
|
&& et != Element::Type::HARMONY)
|
2012-05-26 14:26:10 +02:00
|
|
|
) {
|
|
|
|
undo(new AddElement(element));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-30 00:41:28 +02:00
|
|
|
foreach (Staff* staff, ostaff->staffList()) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Score* score = staff->score();
|
|
|
|
int staffIdx = score->staffIdx(staff);
|
|
|
|
Element* ne;
|
|
|
|
if (staff == ostaff)
|
|
|
|
ne = element;
|
|
|
|
else {
|
2013-12-11 07:51:09 +01:00
|
|
|
if (staff->rstaff() != ostaff->rstaff()) {
|
|
|
|
switch (element->type()) {
|
|
|
|
// exclude certain element types except on corresponding staff in part
|
2013-12-11 17:30:43 +01:00
|
|
|
// this should be same list excluded in cloneStaff()
|
2014-06-24 18:36:02 +02:00
|
|
|
case Element::Type::STAFF_TEXT:
|
2014-08-01 05:00:25 +02:00
|
|
|
case Element::Type::FRET_DIAGRAM:
|
2014-06-24 18:36:02 +02:00
|
|
|
case Element::Type::HARMONY:
|
|
|
|
case Element::Type::FIGURED_BASS:
|
|
|
|
case Element::Type::DYNAMIC:
|
2014-09-16 04:38:02 +02:00
|
|
|
case Element::Type::LYRICS: // not normally segment-attached
|
2013-12-11 07:51:09 +01:00
|
|
|
continue;
|
Fix #29986 : Ottavas in TABs - Solution A)
Ottavas are not used in TAB staves, as they do not really make sense in TAB's. Yet, currently ottavas:
- can be dropped on TAB staves
- ottavas added to standard staves are duplicated in TAB staves linked to them
Fix:
- Ottavas cannot be dropped on TAB staves any longer. Attempting to drop an Ottava on a TAB, results in the action being ignored.
- If an `Ottava` is added to a standard staff linked to TAB staves, the standard staff operation is carried over exactly as before, but the Ottava element is not replicated in the TAB linked staff; instead, the actual pitches of corresponding notes in the TAB staff are shifted by the pitchOffset of the Ottava.
- If the `Ottava` span is later edited (in the standard staff, of course), the pitches of the corresponding TAB staff notes are updated accordingly.
Regarding adding ottavas directly to TAB staves, either linked, there is no difference between Solution A) and Solution B): with both, ottavas **cannot** be added to TAB staves.
When TABs are linked to standard staves and ottavas are added to the standard staff, the differences between Solution A) and B) are:
- A) does not create **any** `Ottava` element in TABs; B) creates hidden `Ottava` elements in the linked TAB.
- A) modifies the TAB note pitches to render the ottava effect; B) does not change the stored pitches, only the fretting.
I am not very fond of the hidden `Ottava` trick of Solution B), but that solution seems more in tune with the current code and easier to understand (and maintain). This solution A) seems to me less tricky, but probably less clear to the unaware developer, as each modification of the 'master' `Ottava` has to be cloned into the linked TAB, at the proper place and time with respect to undo/redo machinery.
My 'instinctive' preference is for Solution B), but advice is welcome!
2015-02-25 23:59:41 +01:00
|
|
|
case Element::Type::OTTAVA:
|
|
|
|
if (staff->isTabStaff()) {
|
|
|
|
Ottava* o = static_cast<Ottava*>(element);
|
|
|
|
undo(new TabAdjustOttava(staff,o->tick(), o->tick2(), o->pitchShift()));
|
|
|
|
continue;
|
|
|
|
}
|
2013-12-11 07:51:09 +01:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
ne = element->linkedClone();
|
|
|
|
ne->setScore(score);
|
|
|
|
ne->setSelected(false);
|
|
|
|
ne->setTrack(staffIdx * VOICES + element->voice());
|
|
|
|
}
|
2014-06-24 18:36:02 +02:00
|
|
|
if (element->type() == Element::Type::ARTICULATION) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Articulation* a = static_cast<Articulation*>(element);
|
|
|
|
Segment* segment;
|
2014-06-25 11:46:10 +02:00
|
|
|
Segment::Type st;
|
2012-05-26 14:26:10 +02:00
|
|
|
Measure* m;
|
|
|
|
int tick;
|
|
|
|
if (a->parent()->isChordRest()) {
|
|
|
|
ChordRest* cr = a->chordRest();
|
|
|
|
segment = cr->segment();
|
2014-06-25 11:46:10 +02:00
|
|
|
st = Segment::Type::ChordRest;
|
2012-05-26 14:26:10 +02:00
|
|
|
tick = segment->tick();
|
|
|
|
m = score->tick2measure(tick);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
segment = static_cast<Segment*>(a->parent()->parent());
|
2014-06-25 11:46:10 +02:00
|
|
|
st = Segment::Type::EndBarLine;
|
2012-05-26 14:26:10 +02:00
|
|
|
tick = segment->tick();
|
|
|
|
m = score->tick2measure(tick);
|
|
|
|
if (m->tick() == tick)
|
|
|
|
m = m->prevMeasure();
|
|
|
|
}
|
|
|
|
Segment* seg = m->findSegment(st, tick);
|
|
|
|
if (seg == 0) {
|
|
|
|
qDebug("undoAddSegment: segment not found");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Articulation* na = static_cast<Articulation*>(ne);
|
|
|
|
int ntrack = staffIdx * VOICES + a->voice();
|
|
|
|
na->setTrack(ntrack);
|
|
|
|
if (a->parent()->isChordRest()) {
|
2014-11-29 08:27:07 +01:00
|
|
|
ChordRest* cr = a->chordRest();
|
|
|
|
ChordRest* ncr;
|
|
|
|
if (cr->isGrace())
|
|
|
|
ncr = findLinkedChord(static_cast<Chord*>(cr), score->staff(staffIdx));
|
|
|
|
else
|
|
|
|
ncr = static_cast<ChordRest*>(seg->element(ntrack));
|
2012-05-26 14:26:10 +02:00
|
|
|
na->setParent(ncr);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BarLine* bl = static_cast<BarLine*>(seg->element(ntrack));
|
|
|
|
na->setParent(bl);
|
|
|
|
}
|
|
|
|
undo(new AddElement(na));
|
|
|
|
}
|
2014-08-30 00:41:28 +02:00
|
|
|
else if (element->type() == Element::Type::CHORDLINE
|
|
|
|
|| element->type() == Element::Type::LYRICS) {
|
|
|
|
ChordRest* cr = static_cast<ChordRest*>(element->parent());
|
|
|
|
Segment* segment = cr->segment();
|
2013-02-28 15:06:54 +01:00
|
|
|
int tick = segment->tick();
|
|
|
|
Measure* m = score->tick2measure(tick);
|
2014-06-25 11:46:10 +02:00
|
|
|
Segment* seg = m->findSegment(Segment::Type::ChordRest, tick);
|
2013-02-28 15:06:54 +01:00
|
|
|
if (seg == 0) {
|
|
|
|
qDebug("undoAddSegment: segment not found");
|
|
|
|
break;
|
|
|
|
}
|
2014-08-30 00:41:28 +02:00
|
|
|
int ntrack = staffIdx * VOICES + element->voice();
|
2013-02-28 15:06:54 +01:00
|
|
|
ne->setTrack(ntrack);
|
|
|
|
ChordRest* ncr = static_cast<ChordRest*>(seg->element(ntrack));
|
|
|
|
ne->setParent(ncr);
|
|
|
|
undo(new AddElement(ne));
|
|
|
|
}
|
2013-02-27 21:23:30 +01:00
|
|
|
//
|
|
|
|
// elements with Segment as parent
|
|
|
|
//
|
2014-06-24 18:36:02 +02:00
|
|
|
else if (element->type() == Element::Type::SYMBOL
|
|
|
|
|| element->type() == Element::Type::IMAGE
|
|
|
|
|| element->type() == Element::Type::DYNAMIC
|
|
|
|
|| element->type() == Element::Type::STAFF_TEXT
|
2014-08-01 05:00:25 +02:00
|
|
|
|| element->type() == Element::Type::FRET_DIAGRAM
|
2014-06-24 18:36:02 +02:00
|
|
|
|| element->type() == Element::Type::HARMONY) {
|
2013-02-27 21:23:30 +01:00
|
|
|
Segment* segment = static_cast<Segment*>(element->parent());
|
2012-05-26 14:26:10 +02:00
|
|
|
int tick = segment->tick();
|
|
|
|
Measure* m = score->tick2measure(tick);
|
2014-06-25 11:46:10 +02:00
|
|
|
Segment* seg = m->undoGetSegment(Segment::Type::ChordRest, tick);
|
2013-02-27 21:23:30 +01:00
|
|
|
int ntrack = staffIdx * VOICES + element->voice();
|
|
|
|
ne->setTrack(ntrack);
|
|
|
|
ne->setParent(seg);
|
|
|
|
undo(new AddElement(ne));
|
2014-08-16 19:16:53 +02:00
|
|
|
// transpose harmony if necessary
|
|
|
|
if (element->type() == Element::Type::HARMONY && ne != element) {
|
|
|
|
Harmony* h = static_cast<Harmony*>(ne);
|
|
|
|
if (score->styleB(StyleIdx::concertPitch) != element->score()->styleB(StyleIdx::concertPitch)) {
|
|
|
|
Part* partDest = h->staff()->part();
|
|
|
|
Interval interval = partDest->instr()->transpose();
|
|
|
|
if (!interval.isZero()) {
|
|
|
|
if (!score->styleB(StyleIdx::concertPitch))
|
|
|
|
interval.flip();
|
2014-12-20 00:27:06 +01:00
|
|
|
int rootTpc = transposeTpc(h->rootTpc(), interval, true);
|
|
|
|
int baseTpc = transposeTpc(h->baseTpc(), interval, true);
|
2014-08-16 19:16:53 +02:00
|
|
|
score->undoTransposeHarmony(h, rootTpc, baseTpc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-02-27 15:18:09 +01:00
|
|
|
}
|
2014-06-24 18:36:02 +02:00
|
|
|
else if (element->type() == Element::Type::SLUR
|
|
|
|
|| element->type() == Element::Type::HAIRPIN
|
|
|
|
|| element->type() == Element::Type::OTTAVA
|
|
|
|
|| element->type() == Element::Type::TRILL
|
|
|
|
|| element->type() == Element::Type::TEXTLINE
|
2014-07-01 01:07:38 +02:00
|
|
|
|| element->type() == Element::Type::PEDAL) {
|
2014-07-10 14:32:04 +02:00
|
|
|
Spanner* sp = static_cast<Spanner*>(element);
|
|
|
|
Spanner* nsp = static_cast<Spanner*>(ne);
|
2013-10-10 15:41:25 +02:00
|
|
|
int staffIdx1 = sp->track() / VOICES;
|
|
|
|
int staffIdx2 = sp->track2() / VOICES;
|
2014-07-10 14:32:04 +02:00
|
|
|
int diff = staffIdx2 - staffIdx1;
|
2013-10-10 15:41:25 +02:00
|
|
|
nsp->setTrack2((staffIdx + diff) * VOICES + (sp->track2() % VOICES));
|
2014-07-10 14:32:04 +02:00
|
|
|
|
|
|
|
// determine start/end element for slurs
|
|
|
|
// this is only necessary if start/end element is
|
|
|
|
// a grace note, otherwise the element can be set to zero
|
|
|
|
// and will later be calculated from tick/track values
|
|
|
|
//
|
|
|
|
if (element->type() == Element::Type::SLUR && sp != nsp) {
|
|
|
|
if (sp->startElement()) {
|
2015-02-12 11:41:39 +01:00
|
|
|
QList<ScoreElement*> sel = sp->startElement()->linkList();
|
|
|
|
for (ScoreElement* ee : sel) {
|
|
|
|
Element* e = static_cast<Element*>(ee);
|
2014-07-10 14:32:04 +02:00
|
|
|
if (e->score() == nsp->score() && e->track() == nsp->track()) {
|
|
|
|
nsp->setStartElement(e);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (sp->endElement()) {
|
2015-02-12 11:41:39 +01:00
|
|
|
QList<ScoreElement*> eel = sp->endElement()->linkList();
|
|
|
|
for (ScoreElement* ee : eel) {
|
|
|
|
Element* e = static_cast<Element*>(ee);
|
2014-07-10 14:32:04 +02:00
|
|
|
if (e->score() == nsp->score() && e->track() == nsp->track2()) {
|
|
|
|
nsp->setEndElement(e);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-10-02 07:42:55 +02:00
|
|
|
undo(new AddElement(nsp));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2014-12-13 17:40:39 +01:00
|
|
|
else if (et == Element::Type::GLISSANDO)
|
|
|
|
undo(new AddElement(static_cast<Spanner*>(ne)));
|
2014-06-24 18:36:02 +02:00
|
|
|
else if (element->type() == Element::Type::TREMOLO && static_cast<Tremolo*>(element)->twoNotes()) {
|
2013-02-28 17:46:30 +01:00
|
|
|
Tremolo* tremolo = static_cast<Tremolo*>(element);
|
|
|
|
ChordRest* cr1 = static_cast<ChordRest*>(tremolo->chord1());
|
|
|
|
ChordRest* cr2 = static_cast<ChordRest*>(tremolo->chord2());
|
|
|
|
Segment* s1 = cr1->segment();
|
|
|
|
Segment* s2 = cr2->segment();
|
|
|
|
Measure* m1 = s1->measure();
|
|
|
|
Measure* m2 = s2->measure();
|
|
|
|
Measure* nm1 = score->tick2measure(m1->tick());
|
|
|
|
Measure* nm2 = score->tick2measure(m2->tick());
|
2013-03-05 20:23:59 +01:00
|
|
|
Segment* ns1 = nm1->findSegment(s1->segmentType(), s1->tick());
|
|
|
|
Segment* ns2 = nm2->findSegment(s2->segmentType(), s2->tick());
|
2013-02-28 17:46:30 +01:00
|
|
|
Chord* c1 = static_cast<Chord*>(ns1->element(staffIdx * VOICES + cr1->voice()));
|
|
|
|
Chord* c2 = static_cast<Chord*>(ns2->element(staffIdx * VOICES + cr2->voice()));
|
|
|
|
Tremolo* ntremolo = static_cast<Tremolo*>(ne);
|
|
|
|
ntremolo->setChords(c1, c2);
|
|
|
|
ntremolo->setParent(c1);
|
|
|
|
undo(new AddElement(ntremolo));
|
|
|
|
}
|
2014-11-29 11:09:02 +01:00
|
|
|
else if (element->type() == Element::Type::TREMOLO && !static_cast<Tremolo*>(element)->twoNotes()) {
|
2014-11-29 08:27:07 +01:00
|
|
|
Chord* cr = static_cast<Chord*>(element->parent());
|
|
|
|
Chord* c1 = findLinkedChord(cr, score->staff(staffIdx));
|
2014-11-29 11:09:02 +01:00
|
|
|
ne->setParent(c1);
|
|
|
|
undo(new AddElement(ne));
|
|
|
|
}
|
|
|
|
else if (element->type() == Element::Type::ARPEGGIO) {
|
2013-02-28 17:46:30 +01:00
|
|
|
ChordRest* cr = static_cast<ChordRest*>(element->parent());
|
|
|
|
Segment* s = cr->segment();
|
|
|
|
Measure* m = s->measure();
|
|
|
|
Measure* nm = score->tick2measure(m->tick());
|
2013-03-05 20:23:59 +01:00
|
|
|
Segment* ns = nm->findSegment(s->segmentType(), s->tick());
|
2013-02-28 17:46:30 +01:00
|
|
|
Chord* c1 = static_cast<Chord*>(ns->element(staffIdx * VOICES + cr->voice()));
|
|
|
|
ne->setParent(c1);
|
|
|
|
undo(new AddElement(ne));
|
|
|
|
}
|
2014-06-24 18:36:02 +02:00
|
|
|
else if (element->type() == Element::Type::TIE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Tie* tie = static_cast<Tie*>(element);
|
|
|
|
Note* n1 = tie->startNote();
|
|
|
|
Note* n2 = tie->endNote();
|
|
|
|
Chord* cr1 = n1->chord();
|
|
|
|
Chord* cr2 = n2 ? n2->chord() : 0;
|
2014-11-29 08:27:07 +01:00
|
|
|
|
|
|
|
// find corresponding notes in linked staff
|
|
|
|
// accounting for grace notes and cross-staff notation
|
2013-06-06 15:12:06 +02:00
|
|
|
int sm = 0;
|
|
|
|
if (cr1->staffIdx() != cr2->staffIdx())
|
|
|
|
sm = cr1->staffMove() + cr2->staffMove();
|
2014-11-29 08:27:07 +01:00
|
|
|
Chord* c1 = findLinkedChord(cr1, score->staff(staffIdx));
|
|
|
|
Chord* c2 = findLinkedChord(cr2, score->staff(staffIdx + sm));
|
|
|
|
Note* nn1 = c1->findNote(n1->pitch());
|
|
|
|
Note* nn2 = c2 ? c2->findNote(n2->pitch()) : 0;
|
2014-04-09 16:09:21 +02:00
|
|
|
|
2014-11-29 08:27:07 +01:00
|
|
|
// create tie
|
|
|
|
Tie* ntie = static_cast<Tie*>(ne);
|
2012-05-26 14:26:10 +02:00
|
|
|
QList<SpannerSegment*>& segments = ntie->spannerSegments();
|
2014-11-29 08:27:07 +01:00
|
|
|
foreach (SpannerSegment* segment, segments)
|
2012-05-26 14:26:10 +02:00
|
|
|
delete segment;
|
|
|
|
segments.clear();
|
|
|
|
ntie->setTrack(c1->track());
|
|
|
|
ntie->setStartNote(nn1);
|
|
|
|
ntie->setEndNote(nn2);
|
|
|
|
undo(new AddElement(ntie));
|
|
|
|
}
|
2014-06-24 18:36:02 +02:00
|
|
|
else if (element->type() == Element::Type::INSTRUMENT_CHANGE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
InstrumentChange* is = static_cast<InstrumentChange*>(element);
|
|
|
|
Segment* s1 = is->segment();
|
|
|
|
Measure* m1 = s1->measure();
|
|
|
|
Measure* nm1 = score->tick2measure(m1->tick());
|
2013-03-05 20:23:59 +01:00
|
|
|
Segment* ns1 = nm1->findSegment(s1->segmentType(), s1->tick());
|
2012-05-26 14:26:10 +02:00
|
|
|
InstrumentChange* nis = static_cast<InstrumentChange*>(ne);
|
|
|
|
nis->setParent(ns1);
|
2014-02-21 23:10:28 +01:00
|
|
|
if (is->instrument().channel().isEmpty() || is->instrument().channel(0).program == -1)
|
|
|
|
nis->setInstrument(*staff->part()->instr(s1->tick()));
|
|
|
|
else
|
|
|
|
nis->setInstrument(is->instrument());
|
2012-05-26 14:26:10 +02:00
|
|
|
undo(new AddElement(nis));
|
2014-02-12 21:59:52 +01:00
|
|
|
undo(new ChangeInstrument(nis, nis->instrument()));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2014-06-24 18:36:02 +02:00
|
|
|
else if (element->type() == Element::Type::BREATH) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Breath* breath = static_cast<Breath*>(element);
|
|
|
|
int tick = breath->segment()->tick();
|
|
|
|
Measure* m = score->tick2measure(tick);
|
2015-02-06 17:01:41 +01:00
|
|
|
// breath appears before barline
|
|
|
|
if (m->tick() == tick)
|
|
|
|
m = m->prevMeasure();
|
2014-06-25 11:46:10 +02:00
|
|
|
Segment* seg = m->undoGetSegment(Segment::Type::Breath, tick);
|
2012-05-26 14:26:10 +02:00
|
|
|
Breath* nbreath = static_cast<Breath*>(ne);
|
|
|
|
int ntrack = staffIdx * VOICES + nbreath->voice();
|
|
|
|
nbreath->setScore(score);
|
|
|
|
nbreath->setTrack(ntrack);
|
|
|
|
nbreath->setParent(seg);
|
|
|
|
undo(new AddElement(nbreath));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
qDebug("undoAddElement: unhandled: <%s>", element->name());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoAddCR
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::undoAddCR(ChordRest* cr, Measure* measure, int tick)
|
|
|
|
{
|
2014-06-24 18:36:02 +02:00
|
|
|
Q_ASSERT(cr->type() != Element::Type::CHORD || !(static_cast<Chord*>(cr)->notes()).isEmpty());
|
2014-08-07 19:39:18 +02:00
|
|
|
Q_ASSERT(cr->isChordRest());
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
Staff* ostaff = cr->staff();
|
2014-06-25 11:46:10 +02:00
|
|
|
Segment::Type segmentType = Segment::Type::ChordRest;
|
2013-07-31 16:32:09 +02:00
|
|
|
|
|
|
|
Tuplet* t = cr->tuplet();
|
2014-07-27 15:06:49 +02:00
|
|
|
foreach (Staff* staff, ostaff->staffList()) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Score* score = staff->score();
|
|
|
|
Measure* m = (score == this) ? measure : score->tick2measure(tick);
|
2013-07-31 16:32:09 +02:00
|
|
|
Segment* seg = m->undoGetSegment(segmentType, tick);
|
|
|
|
|
2014-07-27 15:06:49 +02:00
|
|
|
Q_ASSERT(seg->segmentType() == segmentType);
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
ChordRest* newcr = (staff == ostaff) ? cr : static_cast<ChordRest*>(cr->linkedClone());
|
|
|
|
newcr->setScore(score);
|
|
|
|
int staffIdx = score->staffIdx(staff);
|
2014-08-07 19:39:18 +02:00
|
|
|
|
2013-07-31 16:32:09 +02:00
|
|
|
int ntrack = staffIdx * VOICES + cr->voice();
|
2012-05-26 14:26:10 +02:00
|
|
|
newcr->setTrack(ntrack);
|
|
|
|
newcr->setParent(seg);
|
|
|
|
|
2014-05-31 18:43:52 +02:00
|
|
|
#ifndef QT_NO_DEBUG
|
2014-06-24 18:36:02 +02:00
|
|
|
if (newcr->type() == Element::Type::CHORD) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Chord* chord = static_cast<Chord*>(newcr);
|
|
|
|
// setTpcFromPitch needs to know the note tick position
|
|
|
|
foreach(Note* note, chord->notes()) {
|
2014-05-30 10:18:20 +02:00
|
|
|
// if (note->tpc() == Tpc::TPC_INVALID)
|
2014-04-09 09:40:25 +02:00
|
|
|
// note->setTpcFromPitch();
|
2014-05-30 10:18:20 +02:00
|
|
|
Q_ASSERT(note->tpc() != Tpc::TPC_INVALID);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
2014-05-31 18:43:52 +02:00
|
|
|
#endif
|
2013-07-31 16:32:09 +02:00
|
|
|
if (t) {
|
2014-09-28 11:10:18 +02:00
|
|
|
if (staff != ostaff) {
|
|
|
|
Tuplet* nt = 0;
|
2013-07-31 16:32:09 +02:00
|
|
|
if (t->elements().empty() || t->elements().front() == cr) {
|
2015-02-12 11:41:39 +01:00
|
|
|
for (ScoreElement* e : t->linkList()) {
|
2014-09-29 09:39:45 +02:00
|
|
|
Tuplet* nt1 = static_cast<Tuplet*>(e);
|
|
|
|
if (nt1 == t)
|
|
|
|
continue;
|
|
|
|
if (nt1->score() == score && nt1->track() == newcr->track()) {
|
|
|
|
nt = nt1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!nt) {
|
|
|
|
nt = static_cast<Tuplet*>(t->linkedClone());
|
|
|
|
nt->setTuplet(0);
|
|
|
|
nt->setScore(score);
|
|
|
|
nt->setTrack(newcr->track());
|
|
|
|
}
|
2014-09-28 11:10:18 +02:00
|
|
|
|
|
|
|
Tuplet* t2 = t;
|
|
|
|
Tuplet* nt2 = nt;
|
|
|
|
while (t2->tuplet()) {
|
|
|
|
Tuplet* t = t2->tuplet();
|
|
|
|
Tuplet* nt3 = 0;
|
|
|
|
|
|
|
|
for (auto i : t->linkList()) {
|
|
|
|
Tuplet* tt = static_cast<Tuplet*>(i);
|
|
|
|
if (tt != t && tt->score() == score && tt->track() == t2->track()) {
|
|
|
|
nt3 = tt;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (nt3 == 0) {
|
|
|
|
nt3 = static_cast<Tuplet*>(t->linkedClone());
|
|
|
|
nt3->setScore(score);
|
|
|
|
nt3->setTrack(nt2->track());
|
|
|
|
}
|
|
|
|
nt3->add(nt2);
|
|
|
|
nt2->setTuplet(nt3);
|
|
|
|
|
|
|
|
t2 = t;
|
|
|
|
nt2 = nt3;
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
else {
|
2014-02-28 14:25:47 +01:00
|
|
|
const LinkedElements* le = t->links();
|
2013-07-31 16:32:09 +02:00
|
|
|
// search the linked tuplet
|
2014-09-28 11:10:18 +02:00
|
|
|
if (le) {
|
2015-02-12 11:41:39 +01:00
|
|
|
for (ScoreElement* ee : *le) {
|
|
|
|
Element* e = static_cast<Element*>(ee);
|
2014-09-28 11:10:18 +02:00
|
|
|
if (e->score() == score && e->track() == ntrack) {
|
|
|
|
nt = static_cast<Tuplet*>(e);
|
|
|
|
break;
|
|
|
|
}
|
2013-07-31 16:32:09 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2013-07-31 16:32:09 +02:00
|
|
|
if (nt == 0)
|
|
|
|
qDebug("linked tuplet not found");
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2013-07-31 16:32:09 +02:00
|
|
|
newcr->setTuplet(nt);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
undo(new AddElement(newcr));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoRemoveElement
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::undoRemoveElement(Element* element)
|
|
|
|
{
|
|
|
|
QList<Segment*> segments;
|
2015-02-12 11:41:39 +01:00
|
|
|
for (ScoreElement* ee : element->linkList()) {
|
|
|
|
Element* e = static_cast<Element*>(ee);
|
2012-05-26 14:26:10 +02:00
|
|
|
undo(new RemoveElement(e));
|
2014-06-24 18:36:02 +02:00
|
|
|
if (e->parent() && (e->parent()->type() == Element::Type::SEGMENT)) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Segment* s = static_cast<Segment*>(e->parent());
|
|
|
|
if (!segments.contains(s))
|
|
|
|
segments.append(s);
|
|
|
|
}
|
|
|
|
}
|
2013-10-29 09:54:53 +01:00
|
|
|
for (Segment* s : segments) {
|
2014-05-20 17:26:26 +02:00
|
|
|
if (s->isEmpty())
|
2012-05-26 14:26:10 +02:00
|
|
|
undo(new RemoveElement(s));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoChangeTuning
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::undoChangeTuning(Note* n, qreal v)
|
|
|
|
{
|
2014-05-26 18:18:01 +02:00
|
|
|
undoChangeProperty(n, P_ID::TUNING, v);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2014-06-26 10:53:57 +02:00
|
|
|
void Score::undoChangeUserMirror(Note* n, MScore::DirectionH d)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2014-05-26 18:18:01 +02:00
|
|
|
undoChangeProperty(n, P_ID::MIRROR_HEAD, int(d));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoChangePageFormat
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2014-12-28 18:20:12 +01:00
|
|
|
void Score::undoChangePageFormat(PageFormat* p)
|
|
|
|
{
|
|
|
|
undoChangePageFormat(p, spatium(), pageNumberOffset());
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoChangePageFormat
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
void Score::undoChangePageFormat(PageFormat* p, qreal v, int pageOffset)
|
|
|
|
{
|
|
|
|
undo(new ChangePageFormat(this, p, v, pageOffset));
|
|
|
|
}
|
|
|
|
|
2014-04-09 09:40:25 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoChangeTpc
|
|
|
|
// TODO-TPC: check
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::undoChangeTpc(Note* note, int v)
|
|
|
|
{
|
2014-05-26 18:18:01 +02:00
|
|
|
note->undoChangeProperty(P_ID::TPC1, v);
|
2014-04-09 09:40:25 +02:00
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// AddElement
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
AddElement::AddElement(Element* e)
|
|
|
|
{
|
|
|
|
element = e;
|
|
|
|
}
|
|
|
|
|
2014-11-06 11:34:42 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// AddElement::cleanup
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void AddElement::cleanup(bool undo)
|
|
|
|
{
|
|
|
|
if (!undo) {
|
2015-02-20 15:57:24 +01:00
|
|
|
qDebug("AddElement::cleanup: delete %d %p %s", undo, element, element->name());
|
2014-11-06 11:34:42 +01:00
|
|
|
delete element;
|
|
|
|
element = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoRemoveTuplet
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static void undoRemoveTuplet(DurationElement* cr)
|
|
|
|
{
|
|
|
|
if (cr->tuplet()) {
|
|
|
|
cr->tuplet()->remove(cr);
|
|
|
|
if (cr->tuplet()->elements().isEmpty())
|
|
|
|
undoRemoveTuplet(cr->tuplet());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoAddTuplet
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static void undoAddTuplet(DurationElement* cr)
|
|
|
|
{
|
|
|
|
if (cr->tuplet()) {
|
|
|
|
cr->tuplet()->add(cr);
|
|
|
|
if (cr->tuplet()->elements().size() == 1)
|
|
|
|
undoAddTuplet(cr->tuplet());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
2014-04-15 14:18:56 +02:00
|
|
|
// endUndoRedo
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2014-04-15 17:01:41 +02:00
|
|
|
void AddElement::endUndoRedo(bool isUndo) const
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2015-02-17 20:22:24 +01:00
|
|
|
if (element->isChordRest()) {
|
2014-04-15 17:01:41 +02:00
|
|
|
if (isUndo)
|
|
|
|
undoRemoveTuplet(static_cast<ChordRest*>(element));
|
|
|
|
else
|
|
|
|
undoAddTuplet(static_cast<ChordRest*>(element));
|
2014-12-22 15:06:22 +01:00
|
|
|
}
|
2014-04-15 14:18:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void AddElement::undo()
|
|
|
|
{
|
|
|
|
// qDebug("AddElement::undo: %s %p parent %s %p", element->name(), element,
|
|
|
|
// element->parent() ? element->parent()->name() : "nil", element->parent());
|
|
|
|
|
2014-09-29 09:39:45 +02:00
|
|
|
if (element->type() != Element::Type::TUPLET)
|
|
|
|
element->score()->removeElement(element);
|
2014-04-15 17:01:41 +02:00
|
|
|
endUndoRedo(true);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// redo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void AddElement::redo()
|
|
|
|
{
|
2014-07-27 15:58:42 +02:00
|
|
|
// qDebug("AddElement::redo: %s %p parent %s %p, score %p", element->name(), element,
|
|
|
|
// element->parent() ? element->parent()->name() : "nil", element->parent(), element->score());
|
2013-07-29 11:12:32 +02:00
|
|
|
|
2014-09-29 09:39:45 +02:00
|
|
|
if (element->type() != Element::Type::TUPLET)
|
|
|
|
element->score()->addElement(element);
|
2014-04-15 17:01:41 +02:00
|
|
|
endUndoRedo(false);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// name
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
#ifdef DEBUG_UNDO
|
|
|
|
const char* AddElement::name() const
|
|
|
|
{
|
|
|
|
static char buffer[64];
|
2014-08-27 14:35:39 +02:00
|
|
|
if (element->isText())
|
|
|
|
snprintf(buffer, 64, "Add: %s <%s>", element->name(), qPrintable(static_cast<Text*>(element)->text()));
|
|
|
|
else
|
|
|
|
snprintf(buffer, 64, "Add: %s", element->name());
|
2012-05-26 14:26:10 +02:00
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// RemoveElement
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
RemoveElement::RemoveElement(Element* e)
|
|
|
|
{
|
|
|
|
element = e;
|
|
|
|
|
|
|
|
Score* score = element->score();
|
|
|
|
if (element->isChordRest()) {
|
2014-08-22 13:33:36 +02:00
|
|
|
#if 0
|
2014-08-14 14:29:35 +02:00
|
|
|
// do not delete pending slur in note entry mode
|
|
|
|
Slur* pendingSlur = 0;
|
2014-07-28 10:56:50 +02:00
|
|
|
for (Score* sc : score->scoreList()) {
|
|
|
|
if (sc->noteEntryMode()) {
|
2014-08-14 14:29:35 +02:00
|
|
|
pendingSlur = sc->inputState().slur();
|
2014-07-28 10:56:50 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
// remove any slurs pointing to this chor/rest
|
2014-08-14 14:29:35 +02:00
|
|
|
QList<Spanner*> sl;
|
2014-08-16 14:35:48 +02:00
|
|
|
int tick = static_cast<ChordRest*>(element)->tick();
|
2014-08-14 14:29:35 +02:00
|
|
|
for (auto i : score->spanner()) { // TODO: dont search whole list
|
|
|
|
Spanner* s = i.second;
|
|
|
|
if (pendingSlur && pendingSlur->linkList().contains(s)) {
|
|
|
|
if (s->startElement() == e)
|
|
|
|
s->setStartElement(nullptr);
|
|
|
|
else if (s->endElement() == e)
|
|
|
|
s->setEndElement(nullptr);
|
|
|
|
continue;
|
2014-07-08 11:16:21 +02:00
|
|
|
}
|
2014-08-14 14:29:35 +02:00
|
|
|
if (s->type() == Element::Type::SLUR && (s->startElement() == e || s->endElement() == e))
|
|
|
|
sl.append(s);
|
2014-08-16 14:35:48 +02:00
|
|
|
else if ((s->tick() == tick) && (s->track() == element->track()))
|
|
|
|
sl.append(s);
|
2014-07-08 11:16:21 +02:00
|
|
|
}
|
2014-08-14 14:29:35 +02:00
|
|
|
for (auto s : sl) // actually remove scheduled spanners
|
|
|
|
score->undo(new RemoveElement(s));
|
2014-08-22 13:33:36 +02:00
|
|
|
#endif
|
2012-05-26 14:26:10 +02:00
|
|
|
ChordRest* cr = static_cast<ChordRest*>(element);
|
2014-09-29 09:39:45 +02:00
|
|
|
if (cr->tuplet() && cr->tuplet()->elements().size() <= 1)
|
2014-08-07 17:43:42 +02:00
|
|
|
score->undo(new RemoveElement(cr->tuplet()));
|
2014-06-24 18:36:02 +02:00
|
|
|
if (e->type() == Element::Type::CHORD) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Chord* chord = static_cast<Chord*>(e);
|
2013-09-06 09:36:31 +02:00
|
|
|
// remove tremolo between 2 notes
|
|
|
|
if (chord->tremolo()) {
|
|
|
|
Tremolo* tremolo = chord->tremolo();
|
|
|
|
if (tremolo->twoNotes())
|
2014-08-07 17:43:42 +02:00
|
|
|
score->undo(new RemoveElement(tremolo));
|
2013-09-06 09:36:31 +02:00
|
|
|
}
|
2014-07-14 13:59:54 +02:00
|
|
|
for (const Note* note : chord->notes()) {
|
2012-05-26 14:26:10 +02:00
|
|
|
if (note->tieFor() && note->tieFor()->endNote())
|
2014-08-07 17:43:42 +02:00
|
|
|
score->undo(new RemoveElement(note->tieFor()));
|
2013-05-21 13:15:35 +02:00
|
|
|
if (note->tieBack())
|
2014-08-07 17:43:42 +02:00
|
|
|
score->undo(new RemoveElement(note->tieBack()));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
2014-11-06 11:34:42 +01:00
|
|
|
// AddElement::cleanup
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void RemoveElement::cleanup(bool undo)
|
|
|
|
{
|
|
|
|
if (undo) {
|
2014-11-10 10:55:25 +01:00
|
|
|
qDebug("RemoveElement::cleanup: delete %d %s", undo, element->name());
|
2014-11-06 11:34:42 +01:00
|
|
|
delete element;
|
|
|
|
element = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
2012-05-26 14:26:10 +02:00
|
|
|
// undo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void RemoveElement::undo()
|
|
|
|
{
|
2014-09-29 09:39:45 +02:00
|
|
|
if (element->type() != Element::Type::TUPLET)
|
|
|
|
element->score()->addElement(element);
|
2012-05-26 14:26:10 +02:00
|
|
|
if (element->isChordRest()) {
|
2014-06-24 18:36:02 +02:00
|
|
|
if (element->type() == Element::Type::CHORD) {
|
2012-05-26 14:26:10 +02:00
|
|
|
Chord* chord = static_cast<Chord*>(element);
|
|
|
|
foreach(Note* note, chord->notes()) {
|
|
|
|
if (note->tieBack())
|
|
|
|
note->tieBack()->setEndNote(note);
|
2014-01-16 12:33:23 +01:00
|
|
|
if (note->tieFor() && note->tieFor()->endNote())
|
2013-11-14 16:20:41 +01:00
|
|
|
note->tieFor()->endNote()->setTieBack(note->tieFor());
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
undoAddTuplet(static_cast<ChordRest*>(element));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// redo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void RemoveElement::redo()
|
|
|
|
{
|
2014-09-29 09:39:45 +02:00
|
|
|
if (element->type() != Element::Type::TUPLET)
|
|
|
|
element->score()->removeElement(element);
|
2013-11-14 16:20:41 +01:00
|
|
|
if (element->isChordRest()) {
|
2012-05-26 14:26:10 +02:00
|
|
|
undoRemoveTuplet(static_cast<ChordRest*>(element));
|
2014-06-24 18:36:02 +02:00
|
|
|
if (element->type() == Element::Type::CHORD) {
|
2013-11-14 16:20:41 +01:00
|
|
|
Chord* chord = static_cast<Chord*>(element);
|
|
|
|
foreach(Note* note, chord->notes()) {
|
|
|
|
if (note->tieFor() && note->tieFor()->endNote()) {
|
|
|
|
note->tieFor()->endNote()->setTieBack(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// name
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
#ifdef DEBUG_UNDO
|
|
|
|
const char* RemoveElement::name() const
|
|
|
|
{
|
|
|
|
static char buffer[64];
|
2014-08-27 14:35:39 +02:00
|
|
|
if (element->isText())
|
|
|
|
snprintf(buffer, 64, "Rem: %s <%s>", element->name(), qPrintable(static_cast<Text*>(element)->text()));
|
|
|
|
else
|
|
|
|
snprintf(buffer, 64, "Rem: %s", element->name());
|
2012-05-26 14:26:10 +02:00
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeConcertPitch
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
ChangeConcertPitch::ChangeConcertPitch(Score* s, bool v)
|
|
|
|
{
|
|
|
|
score = s;
|
|
|
|
val = v;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeConcertPitch::flip()
|
|
|
|
{
|
2014-05-26 15:31:36 +02:00
|
|
|
int oval = int(score->styleB(StyleIdx::concertPitch));
|
|
|
|
score->style()->set(StyleIdx::concertPitch, val);
|
2014-04-02 18:11:56 +02:00
|
|
|
score->setLayoutAll(true);
|
2012-05-26 14:26:10 +02:00
|
|
|
val = oval;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// InsertPart
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
InsertPart::InsertPart(Part* p, int i)
|
|
|
|
{
|
|
|
|
part = p;
|
|
|
|
idx = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
void InsertPart::undo()
|
|
|
|
{
|
|
|
|
part->score()->removePart(part);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InsertPart::redo()
|
|
|
|
{
|
|
|
|
part->score()->insertPart(part, idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// RemovePart
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
RemovePart::RemovePart(Part* p, int i)
|
|
|
|
{
|
|
|
|
part = p;
|
|
|
|
idx = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RemovePart::undo()
|
|
|
|
{
|
|
|
|
part->score()->insertPart(part, idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RemovePart::redo()
|
|
|
|
{
|
|
|
|
part->score()->removePart(part);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// InsertStaff
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2014-08-16 17:54:10 +02:00
|
|
|
InsertStaff::InsertStaff(Staff* p, int _ridx)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
staff = p;
|
2014-08-16 17:54:10 +02:00
|
|
|
ridx = _ridx;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void InsertStaff::undo()
|
|
|
|
{
|
|
|
|
staff->score()->removeStaff(staff);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InsertStaff::redo()
|
|
|
|
{
|
2014-08-11 15:25:55 +02:00
|
|
|
staff->score()->insertStaff(staff, ridx);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// RemoveStaff
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2014-08-11 15:25:55 +02:00
|
|
|
RemoveStaff::RemoveStaff(Staff* p)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
staff = p;
|
2014-08-11 15:25:55 +02:00
|
|
|
ridx = staff->rstaff();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void RemoveStaff::undo()
|
|
|
|
{
|
2014-08-11 15:25:55 +02:00
|
|
|
staff->score()->insertStaff(staff, ridx);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void RemoveStaff::redo()
|
|
|
|
{
|
|
|
|
staff->score()->removeStaff(staff);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// InsertMStaff
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
InsertMStaff::InsertMStaff(Measure* m, MStaff* ms, int i)
|
|
|
|
{
|
|
|
|
measure = m;
|
|
|
|
mstaff = ms;
|
|
|
|
idx = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
void InsertMStaff::undo()
|
|
|
|
{
|
|
|
|
measure->removeMStaff(mstaff, idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InsertMStaff::redo()
|
|
|
|
{
|
|
|
|
measure->insertMStaff(mstaff, idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// RemoveMStaff
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
RemoveMStaff::RemoveMStaff(Measure* m, MStaff* ms, int i)
|
|
|
|
{
|
|
|
|
measure = m;
|
|
|
|
mstaff = ms;
|
|
|
|
idx = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RemoveMStaff::undo()
|
|
|
|
{
|
|
|
|
measure->insertMStaff(mstaff, idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RemoveMStaff::redo()
|
|
|
|
{
|
|
|
|
measure->removeMStaff(mstaff, idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// InsertMeasure
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void InsertMeasure::undo()
|
|
|
|
{
|
|
|
|
Score* score = measure->score();
|
2014-07-03 15:02:36 +02:00
|
|
|
score->measures()->remove(measure);
|
2015-02-13 19:16:25 +01:00
|
|
|
score->insertTime(measure->tick(), -measure->ticks());
|
|
|
|
score->fixTicks();
|
2012-05-26 14:26:10 +02:00
|
|
|
score->setLayoutAll(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InsertMeasure::redo()
|
|
|
|
{
|
|
|
|
Score* score = measure->score();
|
|
|
|
score->addMeasure(measure, pos);
|
2015-02-14 11:21:09 +01:00
|
|
|
if (pos)
|
|
|
|
score->insertTime(pos->tick(), measure->ticks());
|
2015-02-13 19:16:25 +01:00
|
|
|
score->fixTicks();
|
2012-05-26 14:26:10 +02:00
|
|
|
score->setLayoutAll(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// SortStaves
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
SortStaves::SortStaves(Score* s, QList<int> l)
|
|
|
|
{
|
|
|
|
score = s;
|
|
|
|
|
|
|
|
for(int i=0 ; i < l.size(); i++) {
|
|
|
|
rlist.append(l.indexOf(i));
|
|
|
|
}
|
|
|
|
list = l;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SortStaves::redo()
|
|
|
|
{
|
|
|
|
score->sortStaves(list);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SortStaves::undo()
|
|
|
|
{
|
|
|
|
score->sortStaves(rlist);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangePitch
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2014-04-09 09:40:25 +02:00
|
|
|
ChangePitch::ChangePitch(Note* _note, int _pitch, int _tpc1, int _tpc2)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
note = _note;
|
2014-04-09 09:40:25 +02:00
|
|
|
pitch = _pitch;
|
|
|
|
tpc1 = _tpc1;
|
|
|
|
tpc2 = _tpc2;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void ChangePitch::flip()
|
|
|
|
{
|
2014-04-09 09:40:25 +02:00
|
|
|
int f_pitch = note->pitch();
|
|
|
|
int f_tpc1 = note->tpc1();
|
|
|
|
int f_tpc2 = note->tpc2();
|
2014-09-07 10:59:12 +02:00
|
|
|
// do not change unless necessary
|
2014-04-10 13:13:37 +02:00
|
|
|
if (f_pitch == pitch && f_tpc1 == tpc1 && f_tpc2 == tpc2) {
|
|
|
|
return;
|
2014-04-09 09:40:25 +02:00
|
|
|
}
|
2014-04-10 13:13:37 +02:00
|
|
|
|
|
|
|
note->setPitch(pitch, tpc1, tpc2);
|
2014-04-09 09:40:25 +02:00
|
|
|
pitch = f_pitch;
|
|
|
|
tpc1 = f_tpc1;
|
|
|
|
tpc2 = f_tpc2;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2014-04-10 13:13:37 +02:00
|
|
|
note->score()->setLayoutAll(true);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2014-09-07 10:59:12 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeFretting
|
|
|
|
//
|
|
|
|
// To use with tablatures to force a specific note fretting;
|
|
|
|
// Pitch, string and fret must be changed all together; otherwise,
|
|
|
|
// if they are not consistent among themselves, the refretting algorithm may re-assign
|
|
|
|
// fret and string numbers for (potentially) all the notes of all the chords of a segment.
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
ChangeFretting::ChangeFretting(Note* _note, int _pitch, int _string, int _fret, int _tpc1, int _tpc2)
|
|
|
|
{
|
|
|
|
note = _note;
|
|
|
|
pitch = _pitch;
|
|
|
|
string= _string;
|
|
|
|
fret = _fret;
|
|
|
|
tpc1 = _tpc1;
|
|
|
|
tpc2 = _tpc2;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChangeFretting::flip()
|
|
|
|
{
|
|
|
|
int f_pitch = note->pitch();
|
|
|
|
int f_string= note->string();
|
|
|
|
int f_fret = note->fret();
|
|
|
|
int f_tpc1 = note->tpc1();
|
|
|
|
int f_tpc2 = note->tpc2();
|
|
|
|
// do not change unless necessary
|
|
|
|
if (f_pitch == pitch && f_string == string && f_fret == fret && f_tpc1 == tpc1 && f_tpc2 == tpc2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
note->setPitch(pitch, tpc1, tpc2);
|
|
|
|
note->setString(string);
|
|
|
|
note->setFret(fret);
|
|
|
|
pitch = f_pitch;
|
|
|
|
string= f_string;
|
|
|
|
fret = f_fret;
|
|
|
|
tpc1 = f_tpc1;
|
|
|
|
tpc2 = f_tpc2;
|
|
|
|
note->score()->setLayoutAll(true);
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeElement
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
ChangeElement::ChangeElement(Element* oe, Element* ne)
|
|
|
|
{
|
|
|
|
oldElement = oe;
|
|
|
|
newElement = ne;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChangeElement::flip()
|
|
|
|
{
|
|
|
|
// qDebug("ChangeElement::flip() %s(%p) -> %s(%p) links %d",
|
|
|
|
// oldElement->name(), oldElement, newElement->name(), newElement,
|
|
|
|
// oldElement->links() ? oldElement->links()->size() : -1);
|
|
|
|
|
2014-02-28 14:25:47 +01:00
|
|
|
const LinkedElements* links = oldElement->links();
|
2012-05-26 14:26:10 +02:00
|
|
|
if (links) {
|
2014-05-21 20:08:37 +02:00
|
|
|
oldElement->unlink();
|
2014-02-28 14:25:47 +01:00
|
|
|
oldElement->linkTo(newElement);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Score* score = oldElement->score();
|
|
|
|
if (oldElement->selected())
|
|
|
|
score->deselect(oldElement);
|
|
|
|
if (newElement->selected())
|
|
|
|
score->select(newElement);
|
|
|
|
if (oldElement->parent() == 0) {
|
|
|
|
score->removeElement(oldElement);
|
|
|
|
score->addElement(newElement);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
oldElement->parent()->change(oldElement, newElement);
|
|
|
|
}
|
|
|
|
|
2014-06-24 18:36:02 +02:00
|
|
|
if (newElement->type() == Element::Type::KEYSIG) {
|
2013-03-23 10:52:50 +01:00
|
|
|
KeySig* ks = static_cast<KeySig*>(newElement);
|
2014-06-03 15:28:10 +02:00
|
|
|
if (!ks->generated())
|
2014-12-08 18:02:17 +01:00
|
|
|
ks->staff()->setKey(ks->tick(), ks->keySigEvent());
|
2013-03-23 10:52:50 +01:00
|
|
|
}
|
2014-06-24 18:36:02 +02:00
|
|
|
else if (newElement->type() == Element::Type::DYNAMIC)
|
2014-05-30 10:16:38 +02:00
|
|
|
newElement->score()->addLayoutFlags(LayoutFlag::FIX_PITCH_VELO);
|
2015-01-29 22:37:39 +01:00
|
|
|
else if (newElement->type() == Element::Type::LAYOUT_BREAK && static_cast<LayoutBreak*>(newElement)->layoutBreakType() == LayoutBreak::Type::SECTION)
|
|
|
|
newElement->score()->addLayoutFlags(LayoutFlag::FIX_TICKS);
|
|
|
|
else if (newElement->type() == Element::Type::BREATH)
|
|
|
|
newElement->score()->addLayoutFlags(LayoutFlag::FIX_TICKS);
|
2014-06-24 18:36:02 +02:00
|
|
|
else if (newElement->type() == Element::Type::TEMPO_TEXT) {
|
2012-05-26 14:26:10 +02:00
|
|
|
TempoText* t = static_cast<TempoText*>(oldElement);
|
|
|
|
score->setTempo(t->segment(), t->tempo());
|
|
|
|
}
|
|
|
|
if (newElement->isSegment()) {
|
|
|
|
SpannerSegment* os = static_cast<SpannerSegment*>(oldElement);
|
|
|
|
SpannerSegment* ns = static_cast<SpannerSegment*>(newElement);
|
|
|
|
if (os->system())
|
|
|
|
os->system()->remove(os);
|
|
|
|
if (ns->system())
|
|
|
|
ns->system()->add(ns);
|
|
|
|
}
|
2013-03-23 10:52:50 +01:00
|
|
|
qSwap(oldElement, newElement);
|
2012-05-26 14:26:10 +02:00
|
|
|
score->setLayoutAll(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// InsertStaves
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
InsertStaves::InsertStaves(Measure* m, int _a, int _b)
|
|
|
|
{
|
|
|
|
measure = m;
|
|
|
|
a = _a;
|
|
|
|
b = _b;
|
|
|
|
}
|
|
|
|
|
|
|
|
void InsertStaves::undo()
|
|
|
|
{
|
|
|
|
measure->removeStaves(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InsertStaves::redo()
|
|
|
|
{
|
|
|
|
measure->insertStaves(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// RemoveStaves
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
RemoveStaves::RemoveStaves(Measure* m, int _a, int _b)
|
|
|
|
{
|
|
|
|
measure = m;
|
|
|
|
a = _a;
|
|
|
|
b = _b;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RemoveStaves::undo()
|
|
|
|
{
|
|
|
|
measure->insertStaves(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RemoveStaves::redo()
|
|
|
|
{
|
|
|
|
measure->removeStaves(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
2014-06-04 10:20:14 +02:00
|
|
|
// ChangeKeySig::flip
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeKeySig::flip()
|
|
|
|
{
|
|
|
|
KeySigEvent oe = keysig->keySigEvent();
|
2012-07-27 18:01:15 +02:00
|
|
|
bool sc = keysig->showCourtesy();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
keysig->setKeySigEvent(ks);
|
2012-07-27 18:01:15 +02:00
|
|
|
keysig->setShowCourtesy(showCourtesy);
|
2014-08-21 15:01:54 +02:00
|
|
|
keysig->measure()->setDirty();
|
2013-11-13 23:03:38 +01:00
|
|
|
|
2014-06-03 15:28:10 +02:00
|
|
|
int tick = keysig->segment()->tick();
|
2014-12-15 13:31:59 +01:00
|
|
|
|
2014-06-03 15:28:10 +02:00
|
|
|
// update keys if keysig was not generated
|
2013-11-13 23:03:38 +01:00
|
|
|
if (!keysig->generated())
|
2014-12-08 18:02:17 +01:00
|
|
|
keysig->staff()->setKey(tick, ks);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
showCourtesy = sc;
|
|
|
|
ks = oe;
|
|
|
|
keysig->score()->setLayoutAll(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeMeasureLen
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
ChangeMeasureLen::ChangeMeasureLen(Measure* m, Fraction l)
|
|
|
|
{
|
|
|
|
measure = m;
|
|
|
|
len = l;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChangeMeasureLen::flip()
|
|
|
|
{
|
|
|
|
Fraction oLen = measure->len();
|
|
|
|
|
|
|
|
//
|
|
|
|
// move EndBarLine and TimeSigAnnounce
|
|
|
|
// to end of measure:
|
|
|
|
//
|
|
|
|
int endTick = measure->tick() + len.ticks();
|
|
|
|
for (Segment* segment = measure->first(); segment; segment = segment->next()) {
|
2014-06-25 11:46:10 +02:00
|
|
|
if (segment->segmentType() != Segment::Type::EndBarLine
|
|
|
|
&& segment->segmentType() != Segment::Type::TimeSigAnnounce)
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
|
|
|
segment->setTick(endTick);
|
|
|
|
}
|
|
|
|
measure->setLen(len);
|
2012-09-04 10:34:00 +02:00
|
|
|
// measure->score()->addLayoutFlags(LAYOUT_FIX_TICKS); // we need to fix tick immediately!
|
|
|
|
measure->score()->fixTicks();
|
2012-05-26 14:26:10 +02:00
|
|
|
len = oLen;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeChordRestSize
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
ChangeChordRestSize::ChangeChordRestSize(ChordRest* _cr, bool _small)
|
|
|
|
{
|
|
|
|
cr = _cr;
|
|
|
|
small = _small;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChangeChordRestSize::flip()
|
|
|
|
{
|
|
|
|
bool s = cr->small();
|
|
|
|
cr->setSmall(small);
|
|
|
|
small = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeChordNoStem
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
ChangeChordNoStem::ChangeChordNoStem(Chord* c, bool f)
|
|
|
|
{
|
|
|
|
chord = c;
|
|
|
|
noStem = f;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChangeChordNoStem::flip()
|
|
|
|
{
|
|
|
|
bool ns = chord->noStem();
|
|
|
|
chord->setNoStem(noStem);
|
|
|
|
noStem = ns;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeEndBarLineType
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
ChangeEndBarLineType::ChangeEndBarLineType(Measure* m, BarLineType st)
|
|
|
|
{
|
|
|
|
measure = m;
|
|
|
|
subtype = st;
|
Bar lines: fixing custom type and generated management
There are some inconsistencies in the current management of bar line `_generated` flag and user-modified type:
- Bar lines created by the New Score Wizard are flagged as non-generated, as well as bar lines of measures manually **appended** by the user, while bar lines of measures **inserted** are flagged as generated.
- If a generated bar line is individually changed of typed, it remains flagged as generated, it is not saved and the change is lost upon saving and re-loading.
- The management of the internal flag `BarLine::_customSubtype` is not always consistent.
- The `Measure::_endBarLineGenerated` flag was not always restored properly by undo.
This PR introduces the following fixes:
- The `_generated` flag is consistently used for bar lines whose type can be reconstructed from the context and then do not need to be saved to the output file.
- Normal bar lines are **always** created as generated: initially created by the Wizard, manually appended or inserted.
- Bar lines with custom type (i.e. different from the type which can be expected according to the bar line context) are always flagged as non-generated, ensuring the custom type is written to the output file.
- The `Measure::_endBarLineGenerated` flag is stored by `ChangeEndBarLineType()` and restore upon undo.
- Some test reference scores, based on the inconsistent bar line `_generated` flag, have been uniformed.
Notes:
- Tests about measure (and then bar line) appending, inserting and relative undo's are already included in the `tst_parts` test suite.
- Some inconsistencies remain in the management of custom bar line span and of system-initial bar lines: for the sake of simplicity, they will be dealt with in separate PR's.
2014-09-06 10:36:35 +02:00
|
|
|
// the measure endBarLineGenerated flag will depend on the new bar line type:
|
|
|
|
endBarLineGenerated = (st == BarLineType::NORMAL);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void ChangeEndBarLineType::flip()
|
|
|
|
{
|
|
|
|
BarLineType typ = measure->endBarLineType();
|
Bar lines: fixing custom type and generated management
There are some inconsistencies in the current management of bar line `_generated` flag and user-modified type:
- Bar lines created by the New Score Wizard are flagged as non-generated, as well as bar lines of measures manually **appended** by the user, while bar lines of measures **inserted** are flagged as generated.
- If a generated bar line is individually changed of typed, it remains flagged as generated, it is not saved and the change is lost upon saving and re-loading.
- The management of the internal flag `BarLine::_customSubtype` is not always consistent.
- The `Measure::_endBarLineGenerated` flag was not always restored properly by undo.
This PR introduces the following fixes:
- The `_generated` flag is consistently used for bar lines whose type can be reconstructed from the context and then do not need to be saved to the output file.
- Normal bar lines are **always** created as generated: initially created by the Wizard, manually appended or inserted.
- Bar lines with custom type (i.e. different from the type which can be expected according to the bar line context) are always flagged as non-generated, ensuring the custom type is written to the output file.
- The `Measure::_endBarLineGenerated` flag is stored by `ChangeEndBarLineType()` and restore upon undo.
- Some test reference scores, based on the inconsistent bar line `_generated` flag, have been uniformed.
Notes:
- Tests about measure (and then bar line) appending, inserting and relative undo's are already included in the `tst_parts` test suite.
- Some inconsistencies remain in the management of custom bar line span and of system-initial bar lines: for the sake of simplicity, they will be dealt with in separate PR's.
2014-09-06 10:36:35 +02:00
|
|
|
bool eblg = measure->endBarLineGenerated();
|
|
|
|
measure->setEndBarLineType(subtype, endBarLineGenerated);
|
2012-05-26 14:26:10 +02:00
|
|
|
subtype = typ;
|
Bar lines: fixing custom type and generated management
There are some inconsistencies in the current management of bar line `_generated` flag and user-modified type:
- Bar lines created by the New Score Wizard are flagged as non-generated, as well as bar lines of measures manually **appended** by the user, while bar lines of measures **inserted** are flagged as generated.
- If a generated bar line is individually changed of typed, it remains flagged as generated, it is not saved and the change is lost upon saving and re-loading.
- The management of the internal flag `BarLine::_customSubtype` is not always consistent.
- The `Measure::_endBarLineGenerated` flag was not always restored properly by undo.
This PR introduces the following fixes:
- The `_generated` flag is consistently used for bar lines whose type can be reconstructed from the context and then do not need to be saved to the output file.
- Normal bar lines are **always** created as generated: initially created by the Wizard, manually appended or inserted.
- Bar lines with custom type (i.e. different from the type which can be expected according to the bar line context) are always flagged as non-generated, ensuring the custom type is written to the output file.
- The `Measure::_endBarLineGenerated` flag is stored by `ChangeEndBarLineType()` and restore upon undo.
- Some test reference scores, based on the inconsistent bar line `_generated` flag, have been uniformed.
Notes:
- Tests about measure (and then bar line) appending, inserting and relative undo's are already included in the `tst_parts` test suite.
- Some inconsistencies remain in the management of custom bar line span and of system-initial bar lines: for the sake of simplicity, they will be dealt with in separate PR's.
2014-09-06 10:36:35 +02:00
|
|
|
endBarLineGenerated = eblg;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeBarLineSpan
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2012-10-14 00:35:11 +02:00
|
|
|
ChangeBarLineSpan::ChangeBarLineSpan(Staff* _staff, int _span, int _spanFrom, int _spanTo)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2012-10-14 00:35:11 +02:00
|
|
|
staff = _staff;
|
|
|
|
span = _span;
|
|
|
|
spanFrom = _spanFrom;
|
|
|
|
spanTo = _spanTo;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void ChangeBarLineSpan::flip()
|
|
|
|
{
|
2012-10-14 00:35:11 +02:00
|
|
|
int nspan = staff->barLineSpan();
|
|
|
|
int nspanFrom = staff->barLineFrom();
|
|
|
|
int nspanTo = staff->barLineTo();
|
2012-05-26 14:26:10 +02:00
|
|
|
staff->setBarLineSpan(span);
|
2012-10-14 00:35:11 +02:00
|
|
|
staff->setBarLineFrom(spanFrom);
|
|
|
|
staff->setBarLineTo(spanTo);
|
|
|
|
span = nspan;
|
|
|
|
spanFrom = nspanFrom;
|
|
|
|
spanTo = nspanTo;
|
2012-11-09 17:31:50 +01:00
|
|
|
// all bar lines of this staff across the whole score needs to be re-laid out and re-drawn
|
2012-05-26 14:26:10 +02:00
|
|
|
staff->score()->setLayoutAll(true);
|
|
|
|
}
|
|
|
|
|
2012-10-14 19:48:36 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeSingleBarLineSpan
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
ChangeSingleBarLineSpan::ChangeSingleBarLineSpan(BarLine* _barLine, int _span, int _spanFrom, int _spanTo)
|
|
|
|
{
|
|
|
|
barLine = _barLine;
|
|
|
|
span = _span;
|
|
|
|
spanFrom = _spanFrom;
|
|
|
|
spanTo = _spanTo;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChangeSingleBarLineSpan::flip()
|
|
|
|
{
|
2014-08-08 11:22:59 +02:00
|
|
|
barLine->score()->addRefresh(barLine->canvasBoundingRect()); // area of this bar line needs redraw
|
2012-10-14 19:48:36 +02:00
|
|
|
int nspan = barLine->span();
|
2013-12-21 02:17:06 +01:00
|
|
|
bool respan = (span != nspan);
|
2012-10-14 19:48:36 +02:00
|
|
|
int nspanFrom = barLine->spanFrom();
|
|
|
|
int nspanTo = barLine->spanTo();
|
|
|
|
barLine->setSpan(span);
|
|
|
|
barLine->setSpanFrom(spanFrom);
|
|
|
|
barLine->setSpanTo(spanTo);
|
2014-07-26 10:51:07 +02:00
|
|
|
// barLine->setCustomSpan(true); // let setSpan(), setSpanFrom() and setSpanTo() determine if it is custom or not
|
2012-10-14 19:48:36 +02:00
|
|
|
span = nspan;
|
|
|
|
spanFrom = nspanFrom;
|
|
|
|
spanTo = nspanTo;
|
2012-11-09 17:31:50 +01:00
|
|
|
barLine->layout(); // update bbox
|
2013-12-21 02:17:06 +01:00
|
|
|
// re-create bar lines for other staves, if span of this bar line changed
|
2014-06-24 18:36:02 +02:00
|
|
|
if (respan && barLine->parent() && barLine->parent()->type() == Element::Type::SEGMENT) {
|
2013-12-21 02:17:06 +01:00
|
|
|
Segment * segm = (static_cast<Segment*>(barLine->parent()));
|
|
|
|
Measure * meas = segm->measure();
|
|
|
|
// if it is a start-reapeat bar line at the beginning of a measure, redo measure start bar lines
|
2014-06-25 11:46:10 +02:00
|
|
|
if (barLine->barLineType() == BarLineType::START_REPEAT && segm->segmentType() == Segment::Type::StartRepeatBarLine)
|
2013-12-21 02:17:06 +01:00
|
|
|
meas->setStartRepeatBarLine(true);
|
|
|
|
// otherwise redo measure end bar lines
|
|
|
|
else
|
|
|
|
meas->createEndBarLines();
|
|
|
|
}
|
2014-08-08 11:22:59 +02:00
|
|
|
barLine->score()->addRefresh(barLine->canvasBoundingRect()); // new area of this bar line needs redraw
|
2012-10-14 19:48:36 +02:00
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// TransposeHarmony
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
TransposeHarmony::TransposeHarmony(Harmony* h, int rtpc, int btpc)
|
|
|
|
{
|
|
|
|
harmony = h;
|
|
|
|
rootTpc = rtpc;
|
|
|
|
baseTpc = btpc;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TransposeHarmony::flip()
|
|
|
|
{
|
|
|
|
int baseTpc1 = harmony->baseTpc();
|
|
|
|
int rootTpc1 = harmony->rootTpc();
|
|
|
|
harmony->setBaseTpc(baseTpc);
|
|
|
|
harmony->setRootTpc(rootTpc);
|
2014-11-24 19:31:36 +01:00
|
|
|
harmony->setText(harmony->harmonyName());
|
2012-05-26 14:26:10 +02:00
|
|
|
rootTpc = rootTpc1;
|
|
|
|
baseTpc = baseTpc1;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ExchangeVoice
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2014-08-29 10:35:17 +02:00
|
|
|
ExchangeVoice::ExchangeVoice(Measure* m, int _val1, int _val2, int _staff)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
measure = m;
|
|
|
|
val1 = _val1;
|
|
|
|
val2 = _val2;
|
2014-08-29 10:35:17 +02:00
|
|
|
staff = _staff;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void ExchangeVoice::undo()
|
|
|
|
{
|
2014-08-29 10:35:17 +02:00
|
|
|
measure->exchangeVoice(val2, val1, staff);
|
2014-10-17 22:00:10 +02:00
|
|
|
measure->checkMultiVoices(staff);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void ExchangeVoice::redo()
|
|
|
|
{
|
2014-08-29 10:35:17 +02:00
|
|
|
measure->exchangeVoice(val1, val2, staff);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeInstrumentShort
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2014-02-11 14:27:44 +01:00
|
|
|
ChangeInstrumentShort::ChangeInstrumentShort(int _tick, Part* p, QList<StaffName> t)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
tick = _tick;
|
|
|
|
part = p;
|
|
|
|
text = t;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChangeInstrumentShort::flip()
|
|
|
|
{
|
2014-02-11 14:27:44 +01:00
|
|
|
QList<StaffName> s = part->shortNames(tick);
|
2012-05-26 14:26:10 +02:00
|
|
|
part->setShortNames(text, tick);
|
|
|
|
text = s;
|
|
|
|
part->score()->setLayoutAll(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeInstrumentLong
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2014-02-11 14:27:44 +01:00
|
|
|
ChangeInstrumentLong::ChangeInstrumentLong(int _tick, Part* p, QList<StaffName> t)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
tick = _tick;
|
|
|
|
part = p;
|
|
|
|
text = t;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChangeInstrumentLong::flip()
|
|
|
|
{
|
2014-02-11 14:27:44 +01:00
|
|
|
QList<StaffName> s = part->longNames(tick);
|
2012-05-26 14:26:10 +02:00
|
|
|
part->setLongNames(text, tick);
|
|
|
|
text = s;
|
|
|
|
part->score()->setLayoutAll(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeBracketSpan
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
ChangeBracketSpan::ChangeBracketSpan(Staff* s, int c, int sp)
|
|
|
|
{
|
|
|
|
staff = s;
|
|
|
|
column = c;
|
|
|
|
span = sp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChangeBracketSpan::flip()
|
|
|
|
{
|
|
|
|
int oSpan = staff->bracketSpan(column);
|
|
|
|
staff->setBracketSpan(column, span);
|
|
|
|
span = oSpan;
|
2013-05-31 12:23:07 +02:00
|
|
|
staff->score()->setLayoutAll(true);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// EditText::undo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void EditText::undo()
|
|
|
|
{
|
2014-02-11 14:27:44 +01:00
|
|
|
/* if (!text->styled()) {
|
2012-05-26 14:26:10 +02:00
|
|
|
for (int i = 0; i < undoLevel; ++i)
|
2013-02-18 12:56:09 +01:00
|
|
|
text->undo();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2014-02-11 14:27:44 +01:00
|
|
|
*/
|
2012-05-26 14:26:10 +02:00
|
|
|
undoRedo();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// EditText::redo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void EditText::redo()
|
|
|
|
{
|
2014-02-11 14:27:44 +01:00
|
|
|
/*
|
2012-05-26 14:26:10 +02:00
|
|
|
if (!text->styled()) {
|
|
|
|
for (int i = 0; i < undoLevel; ++i)
|
2013-02-18 12:56:09 +01:00
|
|
|
text->redo();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2014-02-11 14:27:44 +01:00
|
|
|
*/
|
2012-05-26 14:26:10 +02:00
|
|
|
undoRedo();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// EditText::undoRedo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void EditText::undoRedo()
|
|
|
|
{
|
2014-03-14 11:30:19 +01:00
|
|
|
QString s = text->text();
|
|
|
|
text->setText(oldText);
|
|
|
|
oldText = s;
|
2012-05-26 14:26:10 +02:00
|
|
|
text->score()->setLayoutAll(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangePatch
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangePatch::flip()
|
|
|
|
{
|
|
|
|
MidiPatch op;
|
|
|
|
op.prog = channel->program;
|
|
|
|
op.bank = channel->bank;
|
|
|
|
op.synti = channel->synti;
|
|
|
|
|
|
|
|
channel->program = patch.prog;
|
|
|
|
channel->bank = patch.bank;
|
|
|
|
channel->synti = patch.synti;
|
|
|
|
patch = op;
|
|
|
|
|
2013-04-03 19:38:16 +02:00
|
|
|
if (MScore::seq == 0) {
|
|
|
|
qDebug("ChangePatch: no seq");
|
2012-05-26 14:26:10 +02:00
|
|
|
return;
|
2013-04-03 19:38:16 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2013-04-25 09:50:55 +02:00
|
|
|
NPlayEvent event;
|
|
|
|
event.setType(ME_CONTROLLER);
|
2012-05-26 14:26:10 +02:00
|
|
|
event.setChannel(channel->channel);
|
|
|
|
|
|
|
|
int hbank = (channel->bank >> 7) & 0x7f;
|
|
|
|
int lbank = channel->bank & 0x7f;
|
|
|
|
|
|
|
|
event.setController(CTRL_HBANK);
|
|
|
|
event.setValue(hbank);
|
|
|
|
MScore::seq->sendEvent(event);
|
|
|
|
|
|
|
|
event.setController(CTRL_LBANK);
|
|
|
|
event.setValue(lbank);
|
|
|
|
MScore::seq->sendEvent(event);
|
|
|
|
|
|
|
|
event.setController(CTRL_PROGRAM);
|
|
|
|
event.setValue(channel->program);
|
|
|
|
|
|
|
|
MScore::seq->sendEvent(event);
|
2015-03-04 19:08:58 +01:00
|
|
|
channel->updateInitList();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangePageFormat
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
ChangePageFormat::ChangePageFormat(Score* cs, PageFormat* p, qreal s, int po)
|
|
|
|
{
|
|
|
|
score = cs;
|
2012-07-06 14:21:05 +02:00
|
|
|
pf = new PageFormat;
|
|
|
|
pf->copy(*p);
|
2012-05-26 14:26:10 +02:00
|
|
|
spatium = s;
|
|
|
|
pageOffset = po;
|
|
|
|
}
|
|
|
|
|
|
|
|
ChangePageFormat::~ChangePageFormat()
|
|
|
|
{
|
|
|
|
delete pf;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangePageFormat::flip()
|
|
|
|
{
|
2012-07-06 14:21:05 +02:00
|
|
|
PageFormat f;
|
|
|
|
f.copy(*(score->pageFormat()));
|
2012-05-26 14:26:10 +02:00
|
|
|
qreal os = score->spatium();
|
|
|
|
int po = score->pageNumberOffset();
|
|
|
|
|
|
|
|
score->setPageFormat(*pf);
|
|
|
|
if (os != spatium) {
|
|
|
|
score->setSpatium(spatium);
|
|
|
|
score->spatiumChanged(os, spatium);
|
|
|
|
}
|
|
|
|
score->setPageNumberOffset(pageOffset);
|
|
|
|
score->setLayoutAll(true);
|
|
|
|
|
2012-07-06 14:21:05 +02:00
|
|
|
pf->copy(f);
|
2012-05-26 14:26:10 +02:00
|
|
|
spatium = os;
|
|
|
|
pageOffset = po;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeStaff
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2015-02-20 11:56:13 +01:00
|
|
|
ChangeStaff::ChangeStaff(Staff* _staff, bool _invisible,
|
2015-02-04 22:12:13 +01:00
|
|
|
qreal _userDist, bool _neverHide, bool _showIfEmpty, bool hide)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2014-08-06 16:37:41 +02:00
|
|
|
staff = _staff;
|
|
|
|
invisible = _invisible;
|
|
|
|
userDist = _userDist;
|
|
|
|
neverHide = _neverHide;
|
|
|
|
showIfEmpty = _showIfEmpty;
|
2015-01-05 17:55:06 +01:00
|
|
|
hideSystemBarLine = hide;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2014-03-21 11:23:09 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// notifyTimeSigs
|
|
|
|
// mark timesigs for layout
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static void notifyTimeSigs(void*, Element* e)
|
|
|
|
{
|
2014-06-24 18:36:02 +02:00
|
|
|
if (e->type() == Element::Type::TIMESIG)
|
2014-03-21 11:23:09 +01:00
|
|
|
static_cast<TimeSig*>(e)->setNeedLayout(true);
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeStaff::flip()
|
|
|
|
{
|
|
|
|
bool invisibleChanged = staff->invisible() != invisible;
|
|
|
|
|
2014-08-06 16:37:41 +02:00
|
|
|
bool oldInvisible = staff->invisible();
|
|
|
|
qreal oldUserDist = staff->userDist();
|
|
|
|
bool oldNeverHide = staff->neverHide();
|
|
|
|
bool oldShowIfEmpty = staff->showIfEmpty();
|
2015-01-05 17:55:06 +01:00
|
|
|
bool hide = staff->hideSystemBarLine();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
staff->setInvisible(invisible);
|
2013-04-20 01:32:28 +02:00
|
|
|
staff->setUserDist(userDist);
|
2014-07-31 18:46:41 +02:00
|
|
|
staff->setNeverHide(neverHide);
|
2014-08-06 16:37:41 +02:00
|
|
|
staff->setShowIfEmpty(showIfEmpty);
|
2015-01-05 17:55:06 +01:00
|
|
|
staff->setHideSystemBarLine(hideSystemBarLine);
|
2014-08-06 16:37:41 +02:00
|
|
|
|
|
|
|
invisible = oldInvisible;
|
|
|
|
userDist = oldUserDist;
|
|
|
|
neverHide = oldNeverHide;
|
|
|
|
showIfEmpty = oldShowIfEmpty;
|
2015-01-05 17:55:06 +01:00
|
|
|
hideSystemBarLine = hide;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2013-05-28 15:42:02 +02:00
|
|
|
Score* score = staff->score();
|
2014-04-30 10:08:38 +02:00
|
|
|
if (invisibleChanged) {
|
2012-05-26 14:26:10 +02:00
|
|
|
int staffIdx = score->staffIdx(staff);
|
|
|
|
for (Measure* m = score->firstMeasure(); m; m = m->nextMeasure()) {
|
|
|
|
MStaff* mstaff = m->mstaff(staffIdx);
|
|
|
|
mstaff->lines->setVisible(!staff->invisible());
|
|
|
|
}
|
|
|
|
}
|
2013-05-28 15:42:02 +02:00
|
|
|
staff->score()->setLayoutAll(true);
|
2012-05-26 14:26:10 +02:00
|
|
|
staff->score()->rebuildMidiMapping();
|
2015-01-30 17:03:51 +01:00
|
|
|
staff->score()->setPlaylistDirty();
|
2014-03-21 11:23:09 +01:00
|
|
|
|
|
|
|
score->scanElements(0, notifyTimeSigs);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2014-04-30 10:08:38 +02:00
|
|
|
//---------------------------------------------------------
|
2014-08-14 14:29:35 +02:00
|
|
|
// ChangeStaffType::flip
|
2014-04-30 10:08:38 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2014-08-14 14:29:35 +02:00
|
|
|
void ChangeStaffType::flip()
|
2014-05-27 01:47:30 +02:00
|
|
|
{
|
|
|
|
StaffType st = *staff->staffType();
|
2014-08-08 10:07:03 +02:00
|
|
|
|
2014-05-27 01:47:30 +02:00
|
|
|
staff->setStaffType(&staffType);
|
2014-08-08 10:07:03 +02:00
|
|
|
|
2014-04-30 10:08:38 +02:00
|
|
|
staffType = st;
|
2014-05-27 01:47:30 +02:00
|
|
|
|
|
|
|
Score* score = staff->score();
|
2014-06-06 12:56:05 +02:00
|
|
|
score->setLayoutAll(true);
|
|
|
|
score->scanElements(0, notifyTimeSigs);
|
2014-04-30 10:08:38 +02:00
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangePart
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
ChangePart::ChangePart(Part* _part, const Instrument& i, const QString& s)
|
|
|
|
{
|
|
|
|
instrument = i;
|
|
|
|
part = _part;
|
|
|
|
partName = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangePart::flip()
|
|
|
|
{
|
|
|
|
Instrument oi = *part->instr();
|
|
|
|
QString s = part->partName();
|
|
|
|
part->setInstrument(instrument);
|
|
|
|
part->setPartName(partName);
|
2014-06-04 08:30:59 +02:00
|
|
|
Score* score = part->score();
|
|
|
|
score->rebuildMidiMapping();
|
|
|
|
score->setInstrumentsChanged(true);
|
2015-01-30 17:03:51 +01:00
|
|
|
score->setPlaylistDirty();
|
2014-06-04 08:30:59 +02:00
|
|
|
|
2014-07-02 09:55:50 +02:00
|
|
|
// Interval oint = oi.transpose();
|
|
|
|
// Interval nint = part->instr()->transpose();
|
|
|
|
|
2014-06-04 08:30:59 +02:00
|
|
|
// check if notes need to be updated
|
|
|
|
// true if changing into or away from TAB or from one TAB type to another
|
|
|
|
|
|
|
|
score->setLayoutAll(true);
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
partName = s;
|
|
|
|
instrument = oi;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeTextStyle
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
ChangeTextStyle::ChangeTextStyle(Score* s, const TextStyle& st)
|
|
|
|
{
|
|
|
|
score = s;
|
|
|
|
style = st;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// updateTextStyle
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static void updateTextStyle(void* a, Element* e)
|
|
|
|
{
|
|
|
|
QString s = *(QString*)a;
|
|
|
|
if (e->isText()) {
|
|
|
|
Text* text = static_cast<Text*>(e);
|
2014-03-14 11:30:19 +01:00
|
|
|
if (text->textStyle().name() == s) {
|
2012-05-26 14:26:10 +02:00
|
|
|
text->setTextStyle(text->score()->textStyle(s));
|
2013-08-06 19:28:04 +02:00
|
|
|
text->textStyleChanged();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeTextStyle::flip()
|
|
|
|
{
|
|
|
|
TextStyle os = score->style()->textStyle(style.name());
|
|
|
|
score->style()->setTextStyle(style);
|
|
|
|
QString s(style.name());
|
|
|
|
score->scanElements(&s, updateTextStyle);
|
|
|
|
style = os;
|
|
|
|
score->setLayoutAll(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// AddTextStyle::undo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void AddTextStyle::undo()
|
|
|
|
{
|
|
|
|
score->style()->removeTextStyle(style);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// AddTextStyle::redo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void AddTextStyle::redo()
|
|
|
|
{
|
|
|
|
score->style()->addTextStyle(style);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeStretch
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
ChangeStretch::ChangeStretch(Measure* m, qreal s)
|
|
|
|
: measure(m), stretch(s)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeStretch::flip()
|
|
|
|
{
|
|
|
|
qreal oStretch = measure->userStretch();
|
|
|
|
measure->setUserStretch(stretch);
|
|
|
|
measure->score()->setLayoutAll(true);
|
|
|
|
stretch = oStretch;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeStyle
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
ChangeStyle::ChangeStyle(Score* s, const MStyle& st)
|
|
|
|
: score(s), style(st)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-05-02 15:32:18 +02:00
|
|
|
static void updateTimeSigs(void*, Element* e)
|
|
|
|
{
|
2014-06-24 18:36:02 +02:00
|
|
|
if (e->type() == Element::Type::TIMESIG) {
|
2013-05-02 15:32:18 +02:00
|
|
|
TimeSig* ts = static_cast<TimeSig*>(e);
|
|
|
|
ts->setNeedLayout(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
static void updateTextStyle2(void*, Element* e)
|
|
|
|
{
|
2014-01-16 12:33:23 +01:00
|
|
|
e->styleChanged();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeStyle::flip()
|
|
|
|
{
|
|
|
|
MStyle tmp = *score->style();
|
|
|
|
|
2014-05-26 15:31:36 +02:00
|
|
|
if (score->style(StyleIdx::concertPitch) != style.value(StyleIdx::concertPitch))
|
|
|
|
score->cmdConcertPitchChanged(style.value(StyleIdx::concertPitch).toBool(), true);
|
|
|
|
if (score->style(StyleIdx::MusicalSymbolFont) != style.value(StyleIdx::MusicalSymbolFont)) {
|
|
|
|
score->setScoreFont(ScoreFont::fontFactory(style.value(StyleIdx::MusicalSymbolFont).toString()));
|
2013-05-02 15:32:18 +02:00
|
|
|
score->scanElements(0, updateTimeSigs);
|
2013-11-06 15:58:05 +01:00
|
|
|
}
|
2014-03-16 19:23:49 +01:00
|
|
|
if (score->style()->spatium() != style.spatium())
|
|
|
|
score->spatiumChanged(score->style()->spatium(), style.spatium());
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
score->setStyle(style);
|
|
|
|
score->scanElements(0, updateTextStyle2);
|
|
|
|
score->setLayoutAll(true);
|
|
|
|
|
|
|
|
style = tmp;
|
|
|
|
}
|
|
|
|
|
2013-09-28 11:24:00 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeStyleVal::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeStyleVal::flip()
|
|
|
|
{
|
|
|
|
QVariant v = score->style(idx);
|
|
|
|
score->style()->set(idx, value);
|
|
|
|
score->setLayoutAll(true);
|
|
|
|
value = v;
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeChordStaffMove
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2014-10-24 01:28:57 +02:00
|
|
|
ChangeChordStaffMove::ChangeChordStaffMove(ChordRest* cr, int v)
|
|
|
|
: chordRest(cr), staffMove(v)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChangeChordStaffMove::flip()
|
|
|
|
{
|
2014-10-24 01:28:57 +02:00
|
|
|
const LinkedElements* l = chordRest->links();
|
|
|
|
int v = chordRest->staffMove();
|
2014-08-04 12:17:05 +02:00
|
|
|
if (l) {
|
2015-02-12 11:41:39 +01:00
|
|
|
for (ScoreElement* e : *l) {
|
2014-10-24 01:28:57 +02:00
|
|
|
ChordRest* cr = static_cast<ChordRest*>(e);
|
|
|
|
cr->setStaffMove(staffMove);
|
|
|
|
cr->score()->setLayoutAll(true);
|
2014-08-04 12:17:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2014-10-24 01:28:57 +02:00
|
|
|
chordRest->setStaffMove(staffMove);
|
|
|
|
chordRest->score()->setLayoutAll(true);
|
2014-08-04 12:17:05 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
staffMove = v;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeVelocity
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2014-06-25 20:02:40 +02:00
|
|
|
ChangeVelocity::ChangeVelocity(Note* n, Note::ValueType t, int o)
|
2012-05-26 14:26:10 +02:00
|
|
|
: note(n), veloType(t), veloOffset(o)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChangeVelocity::flip()
|
|
|
|
{
|
2014-06-25 20:02:40 +02:00
|
|
|
Note::ValueType t = note->veloType();
|
2012-05-26 14:26:10 +02:00
|
|
|
int o = note->veloOffset();
|
|
|
|
note->setVeloType(veloType);
|
|
|
|
note->setVeloOffset(veloOffset);
|
|
|
|
veloType = t;
|
|
|
|
veloOffset = o;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeMStaffProperties
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
ChangeMStaffProperties::ChangeMStaffProperties(MStaff* ms, bool v, bool s)
|
|
|
|
: mstaff(ms), visible(v), slashStyle(s)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeMStaffProperties::flip()
|
|
|
|
{
|
|
|
|
bool v = mstaff->visible();
|
|
|
|
bool s = mstaff->slashStyle();
|
|
|
|
mstaff->setVisible(visible);
|
|
|
|
mstaff->setSlashStyle(slashStyle);
|
|
|
|
visible = v;
|
|
|
|
slashStyle = s;
|
|
|
|
}
|
|
|
|
|
2014-07-27 12:38:45 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoInsertTime
|
|
|
|
// acts on the linked scores as well
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::undoInsertTime(int tick, int len)
|
|
|
|
{
|
2015-02-17 10:08:23 +01:00
|
|
|
qDebug("undoInsertTime %d at %d, spanners %zd", len, tick, _spanner.map().size());
|
2014-07-27 12:38:45 +02:00
|
|
|
if (len == 0)
|
|
|
|
return;
|
|
|
|
|
2014-08-02 11:53:19 +02:00
|
|
|
QList<Spanner*> sl;
|
|
|
|
for (auto i : _spanner.map()) {
|
2014-07-27 12:38:45 +02:00
|
|
|
Spanner* s = i.second;
|
|
|
|
if (s->tick2() < tick)
|
|
|
|
continue;
|
2014-08-02 11:53:19 +02:00
|
|
|
bool append = false;
|
|
|
|
if (len > 0) {
|
|
|
|
if (tick > s->tick() && tick < s->tick2())
|
|
|
|
append = true;
|
|
|
|
else if (tick <= s->tick())
|
|
|
|
append = true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
int tick2 = tick - len;
|
|
|
|
if (s->tick() >= tick2)
|
|
|
|
append = true;
|
|
|
|
else if ((s->tick() < tick) && (s->tick2() > tick2)) {
|
|
|
|
int t2 = s->tick2() + len;
|
|
|
|
if (t2 > s->tick())
|
|
|
|
append = true;
|
|
|
|
}
|
|
|
|
else if (s->tick() >= tick && s->tick2() < tick2)
|
|
|
|
append = true;
|
|
|
|
else if (s->tick() > tick && s->tick2() > tick2)
|
|
|
|
append = true;
|
|
|
|
}
|
|
|
|
for (Spanner* ss : sl) {
|
|
|
|
if (ss->linkList().contains(s)) {
|
|
|
|
append = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (append)
|
|
|
|
sl.append(s);
|
|
|
|
}
|
|
|
|
for (Spanner* s : sl) {
|
2014-07-27 12:38:45 +02:00
|
|
|
if (len > 0) {
|
|
|
|
if (tick > s->tick() && tick < s->tick2()) {
|
|
|
|
//
|
|
|
|
// case a:
|
|
|
|
// +----spanner--------+
|
|
|
|
// +---add---
|
|
|
|
//
|
2014-08-13 15:42:40 +02:00
|
|
|
undoChangeProperty(s, P_ID::SPANNER_TICKS, s->ticks() + len);
|
2014-07-27 12:38:45 +02:00
|
|
|
}
|
|
|
|
else if (tick <= s->tick()) {
|
|
|
|
//
|
|
|
|
// case b:
|
|
|
|
// +----spanner--------
|
|
|
|
// +---add---
|
|
|
|
// and
|
|
|
|
// +----spanner--------
|
|
|
|
// +---add---+
|
|
|
|
undoChangeProperty(s, P_ID::SPANNER_TICK, s->tick() + len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
int tick2 = tick - len;
|
|
|
|
if (s->tick() >= tick2) {
|
|
|
|
//
|
|
|
|
// case A:
|
|
|
|
// +----remove---+ +---spanner---+
|
|
|
|
//
|
|
|
|
int t = s->tick() + len;
|
|
|
|
if (t < 0)
|
|
|
|
t = 0;
|
|
|
|
undoChangeProperty(s, P_ID::SPANNER_TICK, t);
|
|
|
|
}
|
|
|
|
else if ((s->tick() < tick) && (s->tick2() > tick2)) {
|
|
|
|
//
|
|
|
|
// case B:
|
|
|
|
// +----spanner--------+
|
|
|
|
// +---remove---+
|
|
|
|
//
|
|
|
|
int t2 = s->tick2() + len;
|
|
|
|
if (t2 > s->tick())
|
2014-08-13 15:42:40 +02:00
|
|
|
undoChangeProperty(s, P_ID::SPANNER_TICKS, s->ticks() + len);
|
2014-07-27 12:38:45 +02:00
|
|
|
}
|
|
|
|
else if (s->tick() >= tick && s->tick2() < tick2) {
|
|
|
|
//
|
|
|
|
// case C:
|
|
|
|
// +---spanner---+
|
|
|
|
// +----remove--------+
|
|
|
|
//
|
|
|
|
undoRemoveElement(s);
|
|
|
|
}
|
|
|
|
else if (s->tick() > tick && s->tick2() > tick2) {
|
|
|
|
//
|
|
|
|
// case D:
|
|
|
|
// +----spanner--------+
|
|
|
|
// +---remove---+
|
|
|
|
//
|
|
|
|
int d1 = s->tick() - tick;
|
|
|
|
int d2 = tick2 - s->tick();
|
2014-08-13 15:42:40 +02:00
|
|
|
int len = s->ticks() - d2;
|
2015-02-17 09:36:42 +01:00
|
|
|
if (len == 0) {
|
|
|
|
undoRemoveElement(s);
|
|
|
|
}
|
2014-07-27 12:38:45 +02:00
|
|
|
else {
|
|
|
|
undoChangeProperty(s, P_ID::SPANNER_TICK, s->tick() - d1);
|
2014-08-13 15:42:40 +02:00
|
|
|
undoChangeProperty(s, P_ID::SPANNER_TICKS, len);
|
2014-07-27 12:38:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-19 16:25:29 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoRemoveMeasures
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::undoRemoveMeasures(Measure* m1, Measure* m2)
|
|
|
|
{
|
2013-06-28 10:55:25 +02:00
|
|
|
//
|
|
|
|
// handle ties which start before m1 and end in (m1-m2)
|
|
|
|
//
|
|
|
|
for (Segment* s = m1->first(); s != m2->last(); s = s->next1()) {
|
2014-06-25 11:46:10 +02:00
|
|
|
if (s->segmentType() != Segment::Type::ChordRest)
|
2013-06-28 10:55:25 +02:00
|
|
|
continue;
|
|
|
|
for (int track = 0; track < ntracks(); ++track) {
|
|
|
|
Chord* c = static_cast<Chord*>(s->element(track));
|
2014-06-24 18:36:02 +02:00
|
|
|
if (c == 0 || c->type() != Element::Type::CHORD)
|
2013-06-28 10:55:25 +02:00
|
|
|
continue;
|
|
|
|
for (Note* n : c->notes()) {
|
|
|
|
Tie* t = n->tieBack();
|
|
|
|
if (t) {
|
|
|
|
if (t->startNote()->chord()->tick() < m1->tick()) {
|
|
|
|
t->setEndNote(0);
|
|
|
|
n->setTieBack(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-06-19 16:25:29 +02:00
|
|
|
undo(new RemoveMeasures(m1, m2));
|
2014-06-02 13:07:19 +02:00
|
|
|
|
2014-08-06 14:24:49 +02:00
|
|
|
// int ticks = tick2 - tick1;
|
|
|
|
// undoInsertTime(m1->tick(), -ticks);
|
2013-06-19 16:25:29 +02:00
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// RemoveMeasures
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
RemoveMeasures::RemoveMeasures(Measure* m1, Measure* m2)
|
|
|
|
: fm(m1), lm(m2)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undo
|
|
|
|
// insert back measures
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void RemoveMeasures::undo()
|
|
|
|
{
|
2014-07-27 12:38:45 +02:00
|
|
|
Score* score = fm->score();
|
|
|
|
QList<Clef*> clefs;
|
|
|
|
for (Segment* s = fm->first(); s != lm->last(); s = s->next1()) {
|
|
|
|
if (s->segmentType() != Segment::Type::Clef)
|
|
|
|
continue;
|
|
|
|
for (int track = 0; track < score->ntracks(); track += VOICES) {
|
|
|
|
Clef* c = static_cast<Clef*>(s->element(track));
|
|
|
|
if (c == 0 || c->generated())
|
|
|
|
continue;
|
|
|
|
clefs.append(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
score->measures()->insert(fm, lm);
|
|
|
|
score->fixTicks();
|
|
|
|
score->insertTime(fm->tick(), lm->endTick() - fm->tick());
|
|
|
|
for (Clef* clef : clefs)
|
|
|
|
clef->staff()->setClef(clef);
|
|
|
|
score->setLayoutAll(true);
|
2014-08-11 21:17:55 +02:00
|
|
|
|
|
|
|
//
|
|
|
|
// connect ties
|
|
|
|
//
|
|
|
|
|
|
|
|
if (!fm->prevMeasure())
|
|
|
|
return;
|
|
|
|
Measure* m = fm->prevMeasure();
|
|
|
|
for (Segment* seg = m->first(); seg; seg = seg->next()) {
|
|
|
|
for (int track = 0; track < score->ntracks(); ++track) {
|
|
|
|
Chord* chord = static_cast<Chord*>(seg->element(track));
|
|
|
|
if (chord == 0 || chord->type() != Element::Type::CHORD)
|
|
|
|
continue;
|
|
|
|
foreach (Note* n, chord->notes()) {
|
|
|
|
Tie* tie = n->tieFor();
|
|
|
|
if (!tie)
|
|
|
|
continue;
|
|
|
|
if (!tie->endNote() || tie->endNote()->chord()->segment()->measure() != m) {
|
|
|
|
Note* nn = searchTieNote(n);
|
|
|
|
if (nn) {
|
|
|
|
tie->setEndNote(nn);
|
|
|
|
nn->setTieBack(tie);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// redo
|
|
|
|
// remove measures
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void RemoveMeasures::redo()
|
|
|
|
{
|
2014-07-27 12:38:45 +02:00
|
|
|
Score* score = fm->score();
|
|
|
|
for (Segment* s = fm->first(); s != lm->last(); s = s->next1()) {
|
|
|
|
if (s->segmentType() != Segment::Type::Clef)
|
|
|
|
continue;
|
|
|
|
for (int track = 0; track < score->ntracks(); track += VOICES) {
|
|
|
|
Clef* clef = static_cast<Clef*>(s->element(track));
|
|
|
|
if (clef == 0 || clef->generated())
|
|
|
|
continue;
|
|
|
|
clef->staff()->removeClef(clef);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
score->measures()->remove(fm, lm);
|
|
|
|
score->fixTicks();
|
|
|
|
score->insertTime(fm->tick(), -(lm->endTick() - fm->tick()));
|
|
|
|
score->setLayoutAll(true);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undo
|
|
|
|
// insert back measures
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void InsertMeasures::undo()
|
|
|
|
{
|
2015-02-14 16:24:29 +01:00
|
|
|
Score* s = fm->score();
|
|
|
|
s->measures()->remove(fm, lm);
|
|
|
|
s->fixTicks();
|
|
|
|
s->insertTime(fm->tick(), -(lm->endTick() - fm->tick()));
|
|
|
|
s->setLayoutAll(true);
|
|
|
|
s->connectTies(true);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// redo
|
|
|
|
// remove measures
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void InsertMeasures::redo()
|
|
|
|
{
|
2014-08-11 21:17:55 +02:00
|
|
|
Score* s = fm->score();
|
|
|
|
s->measures()->insert(fm, lm);
|
|
|
|
s->fixTicks();
|
2015-02-14 16:24:29 +01:00
|
|
|
s->insertTime(fm->tick(), lm->endTick() - fm->tick());
|
2014-08-11 21:17:55 +02:00
|
|
|
s->setLayoutAll(true);
|
|
|
|
s->connectTies(true);
|
|
|
|
|
|
|
|
//
|
|
|
|
// connect ties
|
|
|
|
//
|
|
|
|
|
|
|
|
if (!fm->prevMeasure())
|
|
|
|
return;
|
|
|
|
Measure* m = fm->prevMeasure();
|
|
|
|
for (Segment* seg = m->first(); seg; seg = seg->next()) {
|
|
|
|
for (int track = 0; track < s->ntracks(); ++track) {
|
|
|
|
Chord* chord = static_cast<Chord*>(seg->element(track));
|
|
|
|
if (chord == 0 || chord->type() != Element::Type::CHORD)
|
|
|
|
continue;
|
|
|
|
foreach (Note* n, chord->notes()) {
|
|
|
|
Tie* tie = n->tieFor();
|
|
|
|
if (!tie)
|
|
|
|
continue;
|
|
|
|
if (!tie->endNote() || tie->endNote()->chord()->segment()->measure() != m) {
|
|
|
|
Note* nn = searchTieNote(n);
|
|
|
|
if (nn) {
|
|
|
|
tie->setEndNote(nn);
|
|
|
|
nn->setTieBack(tie);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeImage::flip()
|
|
|
|
{
|
|
|
|
bool _lockAspectRatio = image->lockAspectRatio();
|
|
|
|
bool _autoScale = image->autoScale();
|
|
|
|
int _z = image->z();
|
|
|
|
image->setLockAspectRatio(lockAspectRatio);
|
|
|
|
image->setAutoScale(autoScale);
|
|
|
|
image->setZ(z);
|
|
|
|
lockAspectRatio = _lockAspectRatio;
|
|
|
|
autoScale = _autoScale;
|
|
|
|
z = _z;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeDuration::flip()
|
|
|
|
{
|
|
|
|
Fraction od = cr->duration();
|
|
|
|
cr->setDuration(d);
|
|
|
|
d = od;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// AddExcerpt::undo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void AddExcerpt::undo()
|
|
|
|
{
|
|
|
|
score->parentScore()->removeExcerpt(score);
|
|
|
|
score->parentScore()->setExcerptsChanged(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// AddExcerpt::redo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void AddExcerpt::redo()
|
|
|
|
{
|
|
|
|
score->parentScore()->addExcerpt(score);
|
|
|
|
score->parentScore()->setExcerptsChanged(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// RemoveExcerpt::undo()
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void RemoveExcerpt::undo()
|
|
|
|
{
|
|
|
|
score->parentScore()->addExcerpt(score);
|
|
|
|
score->parentScore()->setExcerptsChanged(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// RemoveExcerpt::redo()
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void RemoveExcerpt::redo()
|
|
|
|
{
|
|
|
|
score->parentScore()->removeExcerpt(score);
|
|
|
|
score->parentScore()->setExcerptsChanged(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeBend::flip()
|
|
|
|
{
|
|
|
|
QList<PitchValue> pv = bend->points();
|
2014-08-08 11:22:59 +02:00
|
|
|
bend->score()->addRefresh(bend->canvasBoundingRect());
|
2012-05-26 14:26:10 +02:00
|
|
|
bend->setPoints(points);
|
|
|
|
points = pv;
|
2014-08-08 11:22:59 +02:00
|
|
|
bend->layout();
|
|
|
|
bend->score()->addRefresh(bend->canvasBoundingRect());
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeTremoloBar::flip()
|
|
|
|
{
|
|
|
|
QList<PitchValue> pv = bend->points();
|
|
|
|
bend->setPoints(points);
|
|
|
|
points = pv;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeNoteEvents::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeNoteEvents::flip()
|
|
|
|
{
|
|
|
|
/*TODO: QList<NoteEvent*> e = chord->playEvents();
|
|
|
|
chord->setPlayEvents(events);
|
|
|
|
events = e;
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoChangeBarLine
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::undoChangeBarLine(Measure* m, BarLineType barType)
|
|
|
|
{
|
|
|
|
foreach(Score* s, scoreList()) {
|
|
|
|
Measure* measure = s->tick2measure(m->tick());
|
|
|
|
Measure* nm = m->nextMeasure();
|
2014-07-17 09:32:30 +02:00
|
|
|
Repeat flags = measure->repeatFlags();
|
2012-05-26 14:26:10 +02:00
|
|
|
switch(barType) {
|
2014-05-30 10:14:09 +02:00
|
|
|
case BarLineType::END:
|
|
|
|
case BarLineType::NORMAL:
|
|
|
|
case BarLineType::DOUBLE:
|
|
|
|
case BarLineType::BROKEN:
|
|
|
|
case BarLineType::DOTTED:
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2014-07-17 09:32:30 +02:00
|
|
|
s->undoChangeProperty(measure, P_ID::REPEAT_FLAGS, int(flags) & ~int(Repeat::END));
|
2012-05-26 14:26:10 +02:00
|
|
|
if (nm)
|
2014-07-24 11:20:09 +02:00
|
|
|
s->undoChangeProperty(nm, P_ID::REPEAT_FLAGS, int(nm->repeatFlags()) & ~int(Repeat::START));
|
2012-05-26 14:26:10 +02:00
|
|
|
s->undoChangeEndBarLineType(measure, barType);
|
|
|
|
measure->setEndBarLineGenerated (false);
|
|
|
|
}
|
|
|
|
break;
|
2014-05-30 10:14:09 +02:00
|
|
|
case BarLineType::START_REPEAT:
|
2014-07-17 09:32:30 +02:00
|
|
|
s->undoChangeProperty(measure, P_ID::REPEAT_FLAGS, int(flags | Repeat::START));
|
2012-05-26 14:26:10 +02:00
|
|
|
break;
|
2014-05-30 10:14:09 +02:00
|
|
|
case BarLineType::END_REPEAT:
|
2014-07-17 09:32:30 +02:00
|
|
|
s->undoChangeProperty(measure, P_ID::REPEAT_FLAGS, int(flags | Repeat::END));
|
2012-05-26 14:26:10 +02:00
|
|
|
if (nm)
|
2014-07-24 11:20:09 +02:00
|
|
|
s->undoChangeProperty(nm, P_ID::REPEAT_FLAGS, int(nm->repeatFlags()) & ~int(Repeat::START));
|
2012-05-26 14:26:10 +02:00
|
|
|
break;
|
2014-05-30 10:14:09 +02:00
|
|
|
case BarLineType::END_START_REPEAT:
|
2014-07-17 09:32:30 +02:00
|
|
|
s->undoChangeProperty(measure, P_ID::REPEAT_FLAGS, int(flags | Repeat::END));
|
2012-05-26 14:26:10 +02:00
|
|
|
if (nm)
|
2014-07-24 11:20:09 +02:00
|
|
|
s->undoChangeProperty(nm, P_ID::REPEAT_FLAGS, int(nm->repeatFlags() | Repeat::START));
|
2012-05-26 14:26:10 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeInstrument::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeInstrument::flip()
|
|
|
|
{
|
|
|
|
Instrument oi = is->instrument();
|
|
|
|
is->setInstrument(instrument);
|
|
|
|
|
|
|
|
is->staff()->part()->setInstrument(instrument, is->segment()->tick());
|
|
|
|
is->score()->rebuildMidiMapping();
|
|
|
|
is->score()->setInstrumentsChanged(true);
|
|
|
|
is->score()->setLayoutAll(true);
|
|
|
|
instrument = oi;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void SwapCR::flip()
|
|
|
|
{
|
|
|
|
Segment* s1 = cr1->segment();
|
|
|
|
Segment* s2 = cr2->segment();
|
|
|
|
int track = cr1->track();
|
|
|
|
|
|
|
|
Element* cr = s1->element(track);
|
|
|
|
s1->setElement(track, s2->element(track));
|
|
|
|
s2->setElement(track, cr);
|
|
|
|
cr1->score()->setLayoutAll(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeClefType
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
ChangeClefType::ChangeClefType(Clef* c, ClefType cl, ClefType tc)
|
|
|
|
{
|
|
|
|
clef = c;
|
|
|
|
concertClef = cl;
|
|
|
|
transposingClef = tc;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeClefType::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeClefType::flip()
|
|
|
|
{
|
|
|
|
ClefType ocl = clef->concertClef();
|
|
|
|
ClefType otc = clef->transposingClef();
|
|
|
|
|
|
|
|
clef->setConcertClef(concertClef);
|
|
|
|
clef->setTransposingClef(transposingClef);
|
|
|
|
|
2014-07-25 17:13:27 +02:00
|
|
|
clef->staff()->setClef(clef);
|
2012-05-26 14:26:10 +02:00
|
|
|
Segment* segment = clef->segment();
|
|
|
|
updateNoteLines(segment, clef->track());
|
|
|
|
clef->score()->setLayoutAll(true);
|
|
|
|
|
|
|
|
concertClef = ocl;
|
|
|
|
transposingClef = otc;
|
2014-11-09 20:37:56 +01:00
|
|
|
// layout the clef to align the currentClefType with the actual one immediately
|
|
|
|
clef->layout();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void MoveStaff::flip()
|
|
|
|
{
|
|
|
|
Part* oldPart = staff->part();
|
|
|
|
int idx = staff->rstaff();
|
|
|
|
oldPart->removeStaff(staff);
|
2014-08-11 15:25:55 +02:00
|
|
|
part->insertStaff(staff, rstaff);
|
2012-05-26 14:26:10 +02:00
|
|
|
part = oldPart;
|
|
|
|
rstaff = idx;
|
|
|
|
staff->score()->setLayoutAll(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeDurationType::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeDurationType::flip()
|
|
|
|
{
|
|
|
|
TDuration type = cr->durationType();
|
|
|
|
cr->setDurationType(t);
|
|
|
|
t = type;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeStaffUserDist::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeStaffUserDist::flip()
|
|
|
|
{
|
|
|
|
qreal v = staff->userDist();
|
|
|
|
staff->setUserDist(dist);
|
|
|
|
dist = v;
|
|
|
|
staff->score()->setLayoutAll(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeProperty::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeProperty::flip()
|
|
|
|
{
|
2013-08-07 13:20:44 +02:00
|
|
|
#ifdef DEBUG_UNDO
|
|
|
|
qDebug()
|
|
|
|
<< "ChangeProperty::flip(): "
|
|
|
|
<< propertyName(id)
|
|
|
|
<< " "
|
|
|
|
<< element->getProperty(id)
|
|
|
|
<< " -> "
|
|
|
|
<< property
|
|
|
|
;
|
|
|
|
#endif
|
2015-02-25 13:09:41 +01:00
|
|
|
if (id == P_ID::SPANNER_TICK || id == P_ID::SPANNER_TICKS)
|
2015-02-04 22:12:13 +01:00
|
|
|
static_cast<Element*>(element)->score()->removeSpanner(static_cast<Spanner*>(element));
|
2014-06-24 13:38:05 +02:00
|
|
|
|
2013-08-07 13:20:44 +02:00
|
|
|
QVariant v = element->getProperty(id);
|
|
|
|
PropertyStyle ps = element->propertyStyle(id);
|
|
|
|
if (propertyStyle == PropertyStyle::STYLED)
|
|
|
|
element->resetProperty(id);
|
|
|
|
else
|
|
|
|
element->setProperty(id, property);
|
2014-06-24 13:38:05 +02:00
|
|
|
|
2015-02-25 13:09:41 +01:00
|
|
|
if (id == P_ID::SPANNER_TICK || id == P_ID::SPANNER_TICKS) {
|
2015-02-04 22:12:13 +01:00
|
|
|
static_cast<Element*>(element)->score()->addSpanner(static_cast<Spanner*>(element));
|
2015-02-25 13:09:41 +01:00
|
|
|
// while updating ticks for an Ottava, the parent staff calls updateOttava()
|
|
|
|
// and expects to find the Ottava spanner(s) in the score lists;
|
|
|
|
// thus, the above (re)setProperty() left the staff pitchOffset map in a wrong state
|
|
|
|
// as the spanner has been removed from the score lists; redo the map here
|
|
|
|
if (static_cast<Element*>(element)->type() == Element::Type::OTTAVA)
|
|
|
|
static_cast<Element*>(element)->staff()->updateOttava();
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
property = v;
|
2013-08-07 13:20:44 +02:00
|
|
|
propertyStyle = ps;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeMetaText::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeMetaText::flip()
|
|
|
|
{
|
|
|
|
QString s = score->metaTag(id);
|
|
|
|
score->setMetaTag(id, text);
|
|
|
|
text = s;
|
|
|
|
}
|
|
|
|
|
2014-03-28 16:29:55 +01:00
|
|
|
PlayEventType eventListType = PlayEventType::User;
|
|
|
|
|
|
|
|
void flip();
|
|
|
|
|
2012-11-19 10:08:15 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeEventList
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2014-03-28 16:29:55 +01:00
|
|
|
ChangeEventList::ChangeEventList(Chord* c, const QList<NoteEventList> l)
|
|
|
|
: chord(c), events(l)
|
2012-11-19 10:08:15 +01:00
|
|
|
{
|
2014-03-28 16:29:55 +01:00
|
|
|
eventListType = PlayEventType::User;
|
2012-11-19 10:08:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeEventList::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeEventList::flip()
|
|
|
|
{
|
2012-11-20 20:51:18 +01:00
|
|
|
int n = chord->notes().size();
|
|
|
|
for (int i = 0; i < n; ++i) {
|
|
|
|
Note* note = chord->notes()[i];
|
|
|
|
note->playEvents().swap(events[i]);
|
|
|
|
}
|
2014-03-28 16:29:55 +01:00
|
|
|
PlayEventType t = chord->playEventType();
|
|
|
|
chord->setPlayEventType(eventListType);
|
|
|
|
eventListType = t;
|
2012-11-19 10:08:15 +01:00
|
|
|
}
|
|
|
|
|
2013-04-02 20:46:07 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeSynthesizerState::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeSynthesizerState::flip()
|
|
|
|
{
|
|
|
|
std::swap(state, score->_synthesizerState);
|
|
|
|
}
|
|
|
|
|
2013-06-28 17:46:24 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoAddBracket
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::undoAddBracket(Staff* staff, int level, BracketType type, int span)
|
|
|
|
{
|
|
|
|
undo(new AddBracket(staff, level, type, span));
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undoRemoveBracket
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Score::undoRemoveBracket(Bracket* b)
|
|
|
|
{
|
|
|
|
undo(new RemoveBracket(b->staff(), b->level(), b->bracketType(), b->span()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void AddBracket::redo()
|
|
|
|
{
|
|
|
|
staff->setBracket(level, type);
|
|
|
|
staff->setBracketSpan(level, span);
|
2013-08-13 14:26:40 +02:00
|
|
|
staff->score()->setLayoutAll(true);
|
2013-06-28 17:46:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void AddBracket::undo()
|
|
|
|
{
|
2014-05-26 22:25:34 +02:00
|
|
|
staff->setBracket(level, BracketType::NO_BRACKET);
|
2013-08-13 14:26:40 +02:00
|
|
|
staff->score()->setLayoutAll(true);
|
2013-06-28 17:46:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RemoveBracket::redo()
|
|
|
|
{
|
2014-05-26 22:25:34 +02:00
|
|
|
staff->setBracket(level, BracketType::NO_BRACKET);
|
2013-08-13 14:26:40 +02:00
|
|
|
staff->score()->setLayoutAll(true);
|
2013-06-28 17:46:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void RemoveBracket::undo()
|
|
|
|
{
|
|
|
|
staff->setBracket(level, type);
|
|
|
|
staff->setBracketSpan(level, span);
|
2013-08-13 14:26:40 +02:00
|
|
|
staff->score()->setLayoutAll(true);
|
2013-06-28 17:46:24 +02:00
|
|
|
}
|
|
|
|
|
2013-08-22 12:18:14 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeSpannerElements
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeSpannerElements::flip()
|
|
|
|
{
|
|
|
|
Element* se = spanner->startElement();
|
|
|
|
Element* ee = spanner->endElement();
|
|
|
|
spanner->setStartElement(startElement);
|
|
|
|
spanner->setEndElement(endElement);
|
|
|
|
startElement = se;
|
|
|
|
endElement = ee;
|
2014-06-24 18:36:02 +02:00
|
|
|
if (spanner->type() == Element::Type::TIE) {
|
2013-08-22 12:18:14 +02:00
|
|
|
Tie* tie = static_cast<Tie*>(spanner);
|
|
|
|
static_cast<Note*>(endElement)->setTieBack(0);
|
|
|
|
tie->endNote()->setTieBack(tie);
|
|
|
|
static_cast<Note*>(startElement)->setTieFor(0);
|
|
|
|
tie->startNote()->setTieFor(tie);
|
|
|
|
}
|
|
|
|
spanner->score()->setLayoutAll(true);
|
|
|
|
}
|
2013-06-28 17:46:24 +02:00
|
|
|
|
2013-10-22 12:05:31 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeParent
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeParent::flip()
|
|
|
|
{
|
|
|
|
Element* p = element->parent();
|
|
|
|
int si = element->staffIdx();
|
|
|
|
p->remove(element);
|
|
|
|
element->setParent(parent);
|
|
|
|
element->setTrack(staffIdx * VOICES);
|
|
|
|
parent->add(element);
|
|
|
|
staffIdx = si;
|
|
|
|
parent = p;
|
|
|
|
}
|
2013-06-28 17:46:24 +02:00
|
|
|
|
2013-10-30 14:21:08 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeMMRest
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeMMRest::flip()
|
|
|
|
{
|
|
|
|
Measure* mmr = m->mmRest();
|
|
|
|
m->setMMRest(mmrest);
|
|
|
|
mmrest = mmr;
|
|
|
|
}
|
|
|
|
|
2013-12-28 16:58:06 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// InsertTime
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void InsertTime::redo()
|
|
|
|
{
|
|
|
|
score->insertTime(tick, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InsertTime::undo()
|
|
|
|
{
|
|
|
|
score->insertTime(tick, -len);
|
|
|
|
}
|
|
|
|
|
2014-03-27 14:50:01 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeNoteEvent::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeNoteEvent::flip()
|
|
|
|
{
|
2015-01-30 17:03:51 +01:00
|
|
|
note->score()->setPlaylistDirty();
|
2014-03-28 16:29:55 +01:00
|
|
|
NoteEvent e = *oldEvent;
|
|
|
|
*oldEvent = newEvent;
|
|
|
|
newEvent = e;
|
|
|
|
|
|
|
|
// TODO:
|
|
|
|
note->chord()->setPlayEventType(PlayEventType::User);
|
2014-03-27 14:50:01 +01:00
|
|
|
}
|
2014-05-08 17:59:24 +02:00
|
|
|
|
2014-05-31 12:03:21 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// Unlink
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2015-02-12 11:41:39 +01:00
|
|
|
Unlink::Unlink(ScoreElement* _e) : e(_e)
|
2014-05-31 12:03:21 +02:00
|
|
|
{
|
|
|
|
Q_ASSERT(e->links());
|
|
|
|
}
|
|
|
|
|
2014-05-21 20:08:37 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// Unlink::undo
|
2014-05-31 12:03:21 +02:00
|
|
|
// (link)
|
2014-05-21 20:08:37 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Unlink::undo()
|
|
|
|
{
|
|
|
|
e->linkTo(le);
|
|
|
|
le = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// Unlink::redo
|
2014-05-31 12:03:21 +02:00
|
|
|
// (unlink)
|
2014-05-21 20:08:37 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Unlink::redo()
|
|
|
|
{
|
2014-05-31 12:03:21 +02:00
|
|
|
Q_ASSERT(le == nullptr);
|
2014-05-21 20:08:37 +02:00
|
|
|
const LinkedElements* l = e->links();
|
2015-02-12 11:41:39 +01:00
|
|
|
for (ScoreElement* ee : *l) {
|
2014-05-21 20:08:37 +02:00
|
|
|
if (e != ee) {
|
|
|
|
le = ee;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-08-19 09:52:30 +02:00
|
|
|
// Q_ASSERT(le);
|
2014-05-21 20:08:37 +02:00
|
|
|
e->unlink();
|
|
|
|
}
|
2014-07-10 14:32:04 +02:00
|
|
|
|
2014-08-01 16:21:39 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// Link::redo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Link::redo()
|
|
|
|
{
|
|
|
|
e1->linkTo(e2);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// Link::redo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void Link::undo()
|
|
|
|
{
|
|
|
|
e2->unlink();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// LinkStaff::redo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void LinkStaff::redo()
|
|
|
|
{
|
|
|
|
s1->linkTo(s2);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
2014-08-07 19:39:18 +02:00
|
|
|
// LinkStaff::undo
|
2014-08-01 16:21:39 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void LinkStaff::undo()
|
|
|
|
{
|
|
|
|
s1->unlink(s2);
|
|
|
|
}
|
|
|
|
|
2014-08-07 19:39:18 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// UnlinkStaff::redo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void UnlinkStaff::redo()
|
|
|
|
{
|
|
|
|
s1->unlink(s2);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// UnlinkStaff::undo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void UnlinkStaff::undo()
|
|
|
|
{
|
|
|
|
s1->linkTo(s2);
|
|
|
|
}
|
|
|
|
|
2014-07-10 14:32:04 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeStartEndSpanner::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeStartEndSpanner::flip()
|
|
|
|
{
|
|
|
|
Element* s = spanner->startElement();
|
|
|
|
Element* e = spanner->endElement();
|
|
|
|
spanner->setStartElement(start);
|
|
|
|
spanner->setEndElement(end);
|
|
|
|
start = s;
|
|
|
|
end = e;
|
|
|
|
}
|
|
|
|
|
2014-11-17 13:06:34 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeLayoutMode::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeLayoutMode::flip()
|
|
|
|
{
|
|
|
|
LayoutMode lm = score->layoutMode();
|
|
|
|
score->setLayoutMode(layoutMode);
|
|
|
|
layoutMode = lm;
|
|
|
|
score->setLayoutAll(true);
|
|
|
|
}
|
|
|
|
|
2014-11-23 15:42:06 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeMetaTags::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeMetaTags::flip()
|
|
|
|
{
|
|
|
|
QMap<QString,QString> t = score->metaTags();
|
|
|
|
score->setMetaTags(metaTags);
|
|
|
|
metaTags = t;
|
|
|
|
}
|
|
|
|
|
2015-02-04 19:51:24 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeDrumset::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeDrumset::flip()
|
|
|
|
{
|
|
|
|
Drumset d = *instrument->drumset();
|
|
|
|
instrument->setDrumset(&drumset);
|
|
|
|
drumset = d;
|
|
|
|
}
|
|
|
|
|
Fix #29986 : Ottavas in TABs - Solution A)
Ottavas are not used in TAB staves, as they do not really make sense in TAB's. Yet, currently ottavas:
- can be dropped on TAB staves
- ottavas added to standard staves are duplicated in TAB staves linked to them
Fix:
- Ottavas cannot be dropped on TAB staves any longer. Attempting to drop an Ottava on a TAB, results in the action being ignored.
- If an `Ottava` is added to a standard staff linked to TAB staves, the standard staff operation is carried over exactly as before, but the Ottava element is not replicated in the TAB linked staff; instead, the actual pitches of corresponding notes in the TAB staff are shifted by the pitchOffset of the Ottava.
- If the `Ottava` span is later edited (in the standard staff, of course), the pitches of the corresponding TAB staff notes are updated accordingly.
Regarding adding ottavas directly to TAB staves, either linked, there is no difference between Solution A) and Solution B): with both, ottavas **cannot** be added to TAB staves.
When TABs are linked to standard staves and ottavas are added to the standard staff, the differences between Solution A) and B) are:
- A) does not create **any** `Ottava` element in TABs; B) creates hidden `Ottava` elements in the linked TAB.
- A) modifies the TAB note pitches to render the ottava effect; B) does not change the stored pitches, only the fretting.
I am not very fond of the hidden `Ottava` trick of Solution B), but that solution seems more in tune with the current code and easier to understand (and maintain). This solution A) seems to me less tricky, but probably less clear to the unaware developer, as each modification of the 'master' `Ottava` has to be cloned into the linked TAB, at the proper place and time with respect to undo/redo machinery.
My 'instinctive' preference is for Solution B), but advice is welcome!
2015-02-25 23:59:41 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// TabAdjustOttava::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void TabAdjustOttava::flip()
|
|
|
|
{
|
|
|
|
if (!staff->isTabStaff()) // only affect TAB staves
|
|
|
|
return; // (possibly overkill?)
|
|
|
|
|
|
|
|
int fromTrack = staff->idx() * VOICES;
|
|
|
|
int toTrack = fromTrack + VOICES;
|
|
|
|
Score* score = staff->score();
|
|
|
|
const StringData* stringData = staff->part()->instr()->stringData();
|
|
|
|
// for each ChordRest segment spanned by ottava
|
|
|
|
for (Segment* s = score->tick2segment(fromTick, true, Segment::Type::ChordRest, false);
|
|
|
|
s && s->tick() < toTick; s = s->nextCR()) {
|
|
|
|
Chord* chord = nullptr;
|
|
|
|
// for each segment element
|
|
|
|
for (int track = fromTrack; track < toTrack; track++) {
|
|
|
|
Element* e = s->element(track);
|
|
|
|
if (e && e->type() == Element::Type::CHORD) {
|
|
|
|
if (chord == nullptr)
|
|
|
|
chord = static_cast<Chord*>(e); // at least one chord found
|
|
|
|
// update pitch of each chord note (ottava shift does not change TPC's)
|
|
|
|
for (Note* note : static_cast<Chord*>(e)->notes())
|
|
|
|
note->setPitch(note->pitch() + pitchOffset, note->tpc1(), note->tpc2());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// for each segment, TAB chords from all voices are fretted cumulatively,
|
|
|
|
// by passing any chord in that segment of the TAB staff, as long as there is at least one
|
|
|
|
if (stringData && chord)
|
|
|
|
stringData->fretChords(chord);
|
|
|
|
}
|
|
|
|
pitchOffset = -pitchOffset; // next flip will reverse the offset
|
|
|
|
}
|
|
|
|
|
2013-05-13 18:49:17 +02:00
|
|
|
}
|