2012-05-26 14:26:10 +02:00
|
|
|
//=============================================================================
|
|
|
|
// MuseScore
|
|
|
|
// Music Composition & Notation
|
|
|
|
//
|
2016-11-02 17:48:13 +01:00
|
|
|
// Copyright (C) 2002-2016 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"
|
2015-02-28 09:57:46 +01:00
|
|
|
#include "glissando.h"
|
2016-12-23 12:05:18 +01:00
|
|
|
#include "stafflines.h"
|
2017-03-31 13:03:15 +02:00
|
|
|
#include "bracket.h"
|
2018-07-16 11:01:05 +02:00
|
|
|
#include "fret.h"
|
2018-09-17 12:48:10 +02:00
|
|
|
#include "textedit.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
|
2016-05-03 01:21:42 +02:00
|
|
|
// compute line position of noteheads after
|
2012-05-26 14:26:10 +02:00
|
|
|
// clef change
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void updateNoteLines(Segment* segment, int track)
|
|
|
|
{
|
2012-06-26 15:06:53 +02:00
|
|
|
Staff* staff = segment->score()->staff(track / VOICES);
|
2016-12-13 13:16:17 +01:00
|
|
|
if (staff->isDrumStaff(segment->tick()) || staff->isTabStaff(segment->tick()))
|
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()) {
|
2017-03-08 13:12:26 +01:00
|
|
|
if ((s->segmentType() & (SegmentType::Clef | SegmentType::HeaderClef)) && s->element(track) && !s->element(track)->generated())
|
2012-05-26 14:26:10 +02:00
|
|
|
break;
|
2016-10-30 16:27:55 +01:00
|
|
|
if (!s->isChordRestType())
|
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) {
|
2016-10-25 17:30:55 +02:00
|
|
|
Element* e = s->element(t);
|
|
|
|
if (e && e->isChord()) {
|
|
|
|
Chord* chord = toChord(e);
|
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
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void UndoCommand::undo(EditData* ed)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
int n = childList.size();
|
|
|
|
for (int i = n-1; i >= 0; --i) {
|
2016-03-24 12:39:18 +01:00
|
|
|
qCDebug(undoRedo) << "<" << childList[i]->name() << ">";
|
2017-04-11 11:34:25 +02:00
|
|
|
childList[i]->undo(ed);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2017-04-11 11:34:25 +02:00
|
|
|
flip(ed);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// redo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void UndoCommand::redo(EditData* ed)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
int n = childList.size();
|
|
|
|
for (int i = 0; i < n; ++i) {
|
2016-03-24 12:39:18 +01:00
|
|
|
qCDebug(undoRedo) << "<" << childList[i]->name() << ">";
|
2017-04-11 11:34:25 +02:00
|
|
|
childList[i]->redo(ed);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2017-04-11 11:34:25 +02:00
|
|
|
flip(ed);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// unwind
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void UndoCommand::unwind()
|
|
|
|
{
|
2016-02-06 22:03:43 +01:00
|
|
|
while (!childList.empty()) {
|
2012-05-26 14:26:10 +02:00
|
|
|
UndoCommand* c = childList.takeLast();
|
2018-06-14 10:19:21 +02:00
|
|
|
qDebug("unwind <%s>", c->name());
|
2017-05-19 09:06:41 +02:00
|
|
|
c->undo(0);
|
2012-05-26 14:26:10 +02:00
|
|
|
delete c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// UndoStack
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
UndoStack::UndoStack()
|
|
|
|
{
|
|
|
|
curCmd = 0;
|
|
|
|
curIdx = 0;
|
2018-07-23 19:50:53 +02:00
|
|
|
cleanState = 0;
|
|
|
|
stateList.push_back(cleanState);
|
|
|
|
nextState = 1;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// 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
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2018-12-12 13:56:07 +01:00
|
|
|
void UndoStack::beginMacro(Score* score)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
if (curCmd) {
|
2018-06-14 10:19:21 +02:00
|
|
|
qWarning("already active");
|
2012-05-26 14:26:10 +02:00
|
|
|
return;
|
|
|
|
}
|
2018-12-12 13:56:07 +01:00
|
|
|
curCmd = new UndoMacro(score);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// push
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void UndoStack::push(UndoCommand* cmd, EditData* ed)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
if (!curCmd) {
|
|
|
|
// this can happen for layout() outside of a command (load)
|
2018-11-08 15:45:14 +01:00
|
|
|
if (!ScoreLoad::loading())
|
|
|
|
qDebug("no active command, UndoStack");
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2017-04-11 11:34:25 +02:00
|
|
|
cmd->redo(ed);
|
2012-05-26 14:26:10 +02:00
|
|
|
delete cmd;
|
|
|
|
return;
|
|
|
|
}
|
2016-03-18 09:29:16 +01:00
|
|
|
#ifndef QT_NO_DEBUG
|
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);
|
2018-02-12 16:34:33 +01:00
|
|
|
qCDebug(undoRedo, "<%s> id %d %s", cmd->name(), int(cp->getId()), propertyName(cp->getId()));
|
2012-09-05 11:49:48 +02:00
|
|
|
}
|
|
|
|
else {
|
2016-10-25 17:30:55 +02:00
|
|
|
qCDebug(undoRedo, "<%s>", cmd->name());
|
2012-09-05 11:49:48 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
#endif
|
|
|
|
curCmd->appendChild(cmd);
|
2017-04-11 11:34:25 +02:00
|
|
|
cmd->redo(ed);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2013-02-26 15:50:36 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// push1
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void UndoStack::push1(UndoCommand* cmd)
|
|
|
|
{
|
2017-05-19 09:06:41 +02:00
|
|
|
if (!curCmd) {
|
2018-11-08 15:45:14 +01:00
|
|
|
if (!ScoreLoad::loading())
|
2018-07-18 09:57:03 +02:00
|
|
|
qWarning("no active command, UndoStack %p", this);
|
2017-05-19 09:06:41 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
curCmd->appendChild(cmd);
|
2013-02-26 15:50:36 +01:00
|
|
|
}
|
|
|
|
|
2018-05-25 09:26:38 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// remove
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void UndoStack::remove(int idx)
|
|
|
|
{
|
2018-06-18 10:51:26 +02:00
|
|
|
Q_ASSERT(idx <= curIdx);
|
2018-07-23 16:50:36 +02:00
|
|
|
Q_ASSERT(curIdx >= 0);
|
2018-05-25 09:26:38 +02:00
|
|
|
// remove redo stack
|
2018-06-18 10:51:26 +02:00
|
|
|
while (list.size() > curIdx) {
|
2018-05-25 09:26:38 +02:00
|
|
|
UndoCommand* cmd = list.takeLast();
|
2018-07-23 19:50:53 +02:00
|
|
|
stateList.pop_back();
|
2018-05-25 09:26:38 +02:00
|
|
|
cmd->cleanup(false); // delete elements for which UndoCommand() holds ownership
|
|
|
|
delete cmd;
|
2018-07-27 12:32:57 +02:00
|
|
|
// --curIdx;
|
2018-06-18 10:51:26 +02:00
|
|
|
}
|
|
|
|
while (list.size() > idx) {
|
|
|
|
UndoCommand* cmd = list.takeLast();
|
2018-07-23 19:50:53 +02:00
|
|
|
stateList.pop_back();
|
2018-06-18 10:51:26 +02:00
|
|
|
cmd->cleanup(true);
|
|
|
|
delete cmd;
|
2018-05-25 09:26:38 +02:00
|
|
|
}
|
|
|
|
curIdx = idx;
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// pop
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void UndoStack::pop()
|
|
|
|
{
|
|
|
|
if (!curCmd) {
|
2018-11-08 15:45:14 +01:00
|
|
|
if (!ScoreLoad::loading())
|
2018-07-18 09:57:03 +02:00
|
|
|
qWarning("no active command");
|
2012-05-26 14:26:10 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
UndoCommand* cmd = curCmd->removeChild();
|
2017-05-19 09:06:41 +02:00
|
|
|
cmd->undo(0);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2018-06-14 10:19:21 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// rollback
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void UndoStack::rollback()
|
|
|
|
{
|
|
|
|
qDebug("==");
|
|
|
|
Q_ASSERT(curCmd == 0);
|
|
|
|
Q_ASSERT(curIdx > 0);
|
|
|
|
int idx = curIdx - 1;
|
|
|
|
list[idx]->unwind();
|
|
|
|
remove(idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// endMacro
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void UndoStack::endMacro(bool rollback)
|
|
|
|
{
|
|
|
|
if (curCmd == 0) {
|
|
|
|
qWarning("not active");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (rollback)
|
|
|
|
delete curCmd;
|
|
|
|
else {
|
|
|
|
// remove redo stack
|
|
|
|
while (list.size() > curIdx) {
|
|
|
|
UndoCommand* cmd = list.takeLast();
|
2018-07-23 19:50:53 +02:00
|
|
|
stateList.pop_back();
|
2018-06-14 10:19:21 +02:00
|
|
|
cmd->cleanup(false); // delete elements for which UndoCommand() holds ownership
|
|
|
|
delete cmd;
|
|
|
|
}
|
|
|
|
list.append(curCmd);
|
2018-07-23 19:50:53 +02:00
|
|
|
stateList.push_back(nextState++);
|
2018-06-14 10:19:21 +02:00
|
|
|
++curIdx;
|
|
|
|
}
|
|
|
|
curCmd = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// reopen
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void UndoStack::reopen()
|
|
|
|
{
|
|
|
|
qDebug("curIdx %d size %d", curIdx, list.size());
|
|
|
|
Q_ASSERT(curCmd == 0);
|
|
|
|
Q_ASSERT(curIdx > 0);
|
|
|
|
--curIdx;
|
|
|
|
curCmd = list.takeAt(curIdx);
|
2018-07-23 19:50:53 +02:00
|
|
|
stateList.erase(stateList.begin() + curIdx);
|
2018-06-14 10:19:21 +02:00
|
|
|
for (auto i : curCmd->commands()) {
|
|
|
|
qDebug(" <%s>", i->name());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// setClean
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void UndoStack::setClean()
|
|
|
|
{
|
2018-07-23 19:50:53 +02:00
|
|
|
cleanState = state();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void UndoStack::undo(EditData* ed)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2016-03-24 12:39:18 +01:00
|
|
|
qCDebug(undoRedo) << "===";
|
2018-09-17 12:48:10 +02:00
|
|
|
// Are we currently editing text?
|
|
|
|
if (ed && ed->element && ed->element->isTextBase()) {
|
|
|
|
TextEditData* ted = static_cast<TextEditData*>(ed->getData(ed->element));
|
|
|
|
if (ted && ted->startUndoIdx == curIdx)
|
|
|
|
// No edits to undo, so do nothing
|
|
|
|
return;
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
if (curIdx) {
|
|
|
|
--curIdx;
|
|
|
|
Q_ASSERT(curIdx >= 0);
|
2017-04-11 11:34:25 +02:00
|
|
|
list[curIdx]->undo(ed);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// redo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void UndoStack::redo(EditData* ed)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2016-03-24 12:39:18 +01:00
|
|
|
qCDebug(undoRedo) << "===";
|
2016-06-03 10:17:06 +02:00
|
|
|
if (canRedo())
|
2017-04-11 11:34:25 +02:00
|
|
|
list[curIdx++]->redo(ed);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
2018-12-12 13:56:07 +01:00
|
|
|
// UndoMacro
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2018-12-12 13:56:07 +01:00
|
|
|
Element* UndoMacro::selectedElement(const Selection& sel)
|
2018-11-26 10:22:34 +01:00
|
|
|
{
|
|
|
|
if (sel.isSingle()) {
|
|
|
|
Element* e = sel.element();
|
|
|
|
Q_ASSERT(e); // otherwise it shouldn't be "single" selection
|
|
|
|
if (e->isNote() || e->isChordRest())
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-12-12 13:56:07 +01:00
|
|
|
UndoMacro::UndoMacro(Score* s)
|
|
|
|
: undoInputState(s->inputState()), redoInputState(s),
|
|
|
|
undoSelectedElement(selectedElement(s->selection())), score(s)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void UndoMacro::undo(EditData* ed)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
redoInputState = score->inputState();
|
2018-11-26 10:22:34 +01:00
|
|
|
redoSelectedElement = selectedElement(score->selection());
|
2018-12-04 15:00:30 +01:00
|
|
|
score->deselectAll();
|
2018-12-12 13:56:07 +01:00
|
|
|
|
|
|
|
// Undo for child commands.
|
|
|
|
UndoCommand::undo(ed);
|
|
|
|
|
|
|
|
score->setInputState(undoInputState);
|
|
|
|
if (undoSelectedElement) {
|
|
|
|
score->deselectAll();
|
2018-12-04 15:00:30 +01:00
|
|
|
score->selection().add(undoSelectedElement);
|
2018-12-12 13:56:07 +01:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2018-12-12 13:56:07 +01:00
|
|
|
void UndoMacro::redo(EditData* ed)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
undoInputState = score->inputState();
|
2018-11-26 10:22:34 +01:00
|
|
|
undoSelectedElement = selectedElement(score->selection());
|
2018-12-12 13:56:07 +01:00
|
|
|
score->deselectAll();
|
|
|
|
|
|
|
|
// Redo for child commands.
|
|
|
|
UndoCommand::redo(ed);
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
score->setInputState(redoInputState);
|
2018-12-12 13:56:07 +01:00
|
|
|
if (redoSelectedElement) {
|
2018-12-04 15:00:30 +01:00
|
|
|
score->deselectAll();
|
2018-12-12 13:56:07 +01:00
|
|
|
score->selection().add(redoSelectedElement);
|
2018-12-04 15:00:30 +01:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2016-07-31 15:23:11 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// CloneVoice
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
CloneVoice::CloneVoice(Segment* _sf, int _lTick, Segment* _d, int _strack, int _dtrack, int _otrack, bool _linked)
|
|
|
|
{
|
|
|
|
sf = _sf; // first source segment
|
|
|
|
lTick = _lTick; // last tick to clone
|
|
|
|
d = _d; // first destination segment
|
|
|
|
strack = _strack;
|
|
|
|
dtrack = _dtrack;
|
2016-07-25 23:22:35 +02:00
|
|
|
otrack = _otrack; // old source track if -1 delete voice in strack after copy
|
|
|
|
linked = _linked; // if true add elements in destination segment only
|
|
|
|
// if false add elements in every linked staff
|
2016-07-31 15:23:11 +02:00
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void CloneVoice::undo(EditData*)
|
2016-07-31 15:23:11 +02:00
|
|
|
{
|
|
|
|
Score* s = d->score();
|
|
|
|
int ticks = d->tick() + lTick - sf->tick();
|
2016-07-25 23:22:35 +02:00
|
|
|
int sTrack = otrack == -1 ? dtrack : otrack; // use the correct source / destination if deleting the source
|
2016-07-31 15:23:11 +02:00
|
|
|
int dTrack = otrack == -1 ? strack : dtrack;
|
|
|
|
|
2016-07-25 23:22:35 +02:00
|
|
|
// Clear destination voice (in case of not linked and otrack = -1 we would delete our source
|
|
|
|
if (otrack != -1 && linked)
|
2016-07-31 15:23:11 +02:00
|
|
|
for (Segment* seg = d; seg && seg->tick() < ticks; seg = seg->next1()) {
|
2016-07-25 23:22:35 +02:00
|
|
|
Element* el = seg->element(dTrack);
|
2016-07-31 15:23:11 +02:00
|
|
|
if (el && el->isChordRest()) {
|
2016-07-25 23:22:35 +02:00
|
|
|
el->unlink();
|
|
|
|
seg->setElement(dTrack, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (otrack == -1 && !linked) {
|
|
|
|
// On the first run get going the undo redo action for adding/deleting elements and slurs
|
|
|
|
if (first) {
|
|
|
|
s->cloneVoice(sTrack, dTrack, sf, ticks, linked);
|
|
|
|
auto spanners = s->spannerMap().findOverlapping(sf->tick(), lTick);
|
|
|
|
for (auto i = spanners.begin(); i < spanners.end(); i++) {
|
|
|
|
Spanner* sp = i->value;
|
|
|
|
if (sp->isSlur() && (sp->track() == sTrack || sp->track2() == sTrack))
|
|
|
|
s->undoRemoveElement(sp);
|
|
|
|
}
|
|
|
|
for (Segment* seg = d; seg && seg->tick() < ticks; seg = seg->next1()) {
|
|
|
|
Element* el = seg->element(sTrack);
|
|
|
|
if (el && el->isChordRest()) {
|
2016-07-31 15:23:11 +02:00
|
|
|
s->undoRemoveElement(el);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-07-25 23:22:35 +02:00
|
|
|
// Set rests if first voice in a staff
|
|
|
|
if (!(sTrack % VOICES))
|
|
|
|
s->setRest(d->tick(), sTrack, Fraction::fromTicks(ticks), false, 0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
s->cloneVoice(sTrack, dTrack, sf, ticks, linked);
|
|
|
|
if (!linked && !(dTrack % VOICES))
|
|
|
|
s->setRest(d->tick(), dTrack, Fraction::fromTicks(ticks), false, 0);
|
2016-07-31 15:23:11 +02:00
|
|
|
}
|
2016-07-25 23:22:35 +02:00
|
|
|
|
|
|
|
first = false;
|
2016-07-31 15:23:11 +02:00
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void CloneVoice::redo(EditData*)
|
2016-07-31 15:23:11 +02:00
|
|
|
{
|
|
|
|
Score* s = d->score();
|
|
|
|
int ticks = d->tick() + lTick - sf->tick();
|
|
|
|
|
2016-07-25 23:22:35 +02:00
|
|
|
// Clear destination voice (in case of not linked and otrack = -1 we would delete our source
|
|
|
|
if (otrack != -1 && linked)
|
2016-07-31 15:23:11 +02:00
|
|
|
for (Segment* seg = d; seg && seg->tick() < ticks; seg = seg->next1()) {
|
2016-07-25 23:22:35 +02:00
|
|
|
Element* el = seg->element(dtrack);
|
2016-07-31 15:23:11 +02:00
|
|
|
if (el && el->isChordRest()) {
|
2016-07-25 23:22:35 +02:00
|
|
|
el->unlink();
|
|
|
|
seg->setElement(dtrack, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (otrack == -1 && !linked) {
|
|
|
|
// On the first run get going the undo redo action for adding/deleting elements and slurs
|
|
|
|
if (first) {
|
|
|
|
s->cloneVoice(strack, dtrack, sf, ticks, linked);
|
|
|
|
auto spanners = s->spannerMap().findOverlapping(sf->tick(), lTick);
|
|
|
|
for (auto i = spanners.begin(); i < spanners.end(); i++) {
|
|
|
|
Spanner* sp = i->value;
|
|
|
|
if (sp->isSlur() && (sp->track() == strack || sp->track2() == strack))
|
|
|
|
s->undoRemoveElement(sp);
|
|
|
|
}
|
|
|
|
for (Segment* seg = d; seg && seg->tick() < ticks; seg = seg->next1()) {
|
|
|
|
Element* el = seg->element(strack);
|
|
|
|
if (el && el->isChordRest()) {
|
2016-07-31 15:23:11 +02:00
|
|
|
s->undoRemoveElement(el);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-07-25 23:22:35 +02:00
|
|
|
// Set rests if first voice in a staff
|
2016-07-31 15:23:11 +02:00
|
|
|
if (!(strack % VOICES))
|
|
|
|
s->setRest(d->tick(), strack, Fraction::fromTicks(ticks), false, 0);
|
|
|
|
}
|
2016-07-25 23:22:35 +02:00
|
|
|
else
|
|
|
|
s->cloneVoice(strack, dtrack, sf, ticks, linked, first);
|
2016-07-31 15:23:11 +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) {
|
|
|
|
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);
|
2016-02-06 22:03:43 +01:00
|
|
|
if (cr->tuplet()->elements().empty())
|
2012-05-26 14:26:10 +02:00
|
|
|
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
|
|
|
{
|
2016-12-12 10:31:37 +01:00
|
|
|
if (element->isChordRest()) {
|
2014-04-15 17:01:41 +02:00
|
|
|
if (isUndo)
|
2016-10-25 17:30:55 +02:00
|
|
|
undoRemoveTuplet(toChordRest(element));
|
2014-04-15 17:01:41 +02:00
|
|
|
else
|
2016-10-25 17:30:55 +02:00
|
|
|
undoAddTuplet(toChordRest(element));
|
|
|
|
}
|
|
|
|
else if (element->isClef()) {
|
|
|
|
element->score()->setLayout(element->tick());
|
|
|
|
element->score()->setLayout(element->staff()->nextClefTick(element->tick()));
|
2014-12-22 15:06:22 +01:00
|
|
|
}
|
2018-04-05 18:39:25 +02:00
|
|
|
else if (element->isKeySig()) {
|
|
|
|
element->score()->setLayout(element->tick());
|
|
|
|
element->score()->setLayout(element->staff()->nextKeyTick(element->tick()));
|
|
|
|
}
|
2014-04-15 14:18:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// undo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void AddElement::undo(EditData*)
|
2014-04-15 14:18:56 +02:00
|
|
|
{
|
2016-12-12 10:31:37 +01:00
|
|
|
if (!element->isTuplet())
|
2014-09-29 09:39:45 +02:00
|
|
|
element->score()->removeElement(element);
|
2014-04-15 17:01:41 +02:00
|
|
|
endUndoRedo(true);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// redo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void AddElement::redo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2016-12-12 10:31:37 +01:00
|
|
|
if (!element->isTuplet())
|
2014-09-29 09:39:45 +02:00
|
|
|
element->score()->addElement(element);
|
2014-04-15 17:01:41 +02:00
|
|
|
endUndoRedo(false);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// name
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
const char* AddElement::name() const
|
|
|
|
{
|
|
|
|
static char buffer[64];
|
2018-04-18 14:31:36 +02:00
|
|
|
if (element->isTextBase())
|
2016-10-25 17:30:55 +02:00
|
|
|
snprintf(buffer, 64, "Add: %s <%s> %p", element->name(),
|
2018-04-18 14:31:36 +02:00
|
|
|
qPrintable(toTextBase(element)->plainText()), element);
|
2016-10-25 17:30:55 +02:00
|
|
|
else if (element->isSegment())
|
|
|
|
snprintf(buffer, 64, "Add: <%s-%s> %p", element->name(), toSegment(element)->subTypeName(), element);
|
2014-08-27 14:35:39 +02:00
|
|
|
else
|
2016-10-25 17:30:55 +02:00
|
|
|
snprintf(buffer, 64, "Add: <%s> %p", element->name(), element);
|
2012-05-26 14:26:10 +02:00
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2018-03-20 17:34:19 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// removeNote
|
|
|
|
// Helper function for RemoveElement class
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
static void removeNote(const Note* note)
|
|
|
|
{
|
|
|
|
Score* score = note->score();
|
|
|
|
if (note->tieFor() && note->tieFor()->endNote())
|
|
|
|
score->undo(new RemoveElement(note->tieFor()));
|
|
|
|
if (note->tieBack())
|
|
|
|
score->undo(new RemoveElement(note->tieBack()));
|
|
|
|
for (Spanner* s : note->spannerBack()) {
|
|
|
|
score->undo(new RemoveElement(s));
|
|
|
|
}
|
|
|
|
for (Spanner* s : note->spannerFor()) {
|
|
|
|
score->undo(new RemoveElement(s));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// RemoveElement
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
RemoveElement::RemoveElement(Element* e)
|
|
|
|
{
|
|
|
|
element = e;
|
|
|
|
|
|
|
|
Score* score = element->score();
|
2016-12-12 10:31:37 +01:00
|
|
|
if (element->isChordRest()) {
|
2016-10-25 17:30:55 +02:00
|
|
|
ChordRest* cr = toChordRest(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()));
|
2016-03-02 13:20:19 +01:00
|
|
|
if (e->isChord()) {
|
|
|
|
Chord* chord = toChord(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()) {
|
2018-03-20 17:34:19 +01:00
|
|
|
removeNote(note);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-03-20 17:34:19 +01:00
|
|
|
else if (element->isNote()) {
|
|
|
|
// Removing an individual note within a chord
|
|
|
|
const Note* note = toNote(element);
|
|
|
|
removeNote(note);
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
2016-10-25 17:30:55 +02:00
|
|
|
// RemoveElement::cleanup
|
2014-11-06 11:34:42 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void RemoveElement::cleanup(bool undo)
|
|
|
|
{
|
|
|
|
if (undo) {
|
|
|
|
delete element;
|
|
|
|
element = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
2012-05-26 14:26:10 +02:00
|
|
|
// undo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void RemoveElement::undo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2016-11-02 17:48:13 +01:00
|
|
|
if (!element->isTuplet())
|
2014-09-29 09:39:45 +02:00
|
|
|
element->score()->addElement(element);
|
2016-12-12 10:31:37 +01:00
|
|
|
if (element->isChordRest()) {
|
2016-03-02 13:20:19 +01:00
|
|
|
if (element->isChord()) {
|
|
|
|
Chord* chord = toChord(element);
|
2016-10-25 17:30:55 +02:00
|
|
|
for (Note* note : chord->notes()) {
|
2018-03-20 17:34:19 +01:00
|
|
|
note->connectTiedNotes();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
}
|
2016-10-25 17:30:55 +02:00
|
|
|
undoAddTuplet(toChordRest(element));
|
|
|
|
}
|
2017-02-13 17:06:30 +01:00
|
|
|
else if (element->isClef())
|
2016-10-25 17:30:55 +02:00
|
|
|
element->score()->setLayout(element->staff()->nextClefTick(element->tick()));
|
2017-02-13 17:06:30 +01:00
|
|
|
else if (element->isKeySig())
|
|
|
|
element->score()->setLayout(element->staff()->nextKeyTick(element->tick()));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// redo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void RemoveElement::redo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2016-11-02 17:48:13 +01:00
|
|
|
if (!element->isTuplet())
|
2014-09-29 09:39:45 +02:00
|
|
|
element->score()->removeElement(element);
|
2016-12-12 10:31:37 +01:00
|
|
|
if (element->isChordRest()) {
|
2016-03-02 13:20:19 +01:00
|
|
|
undoRemoveTuplet(toChordRest(element));
|
|
|
|
if (element->isChord()) {
|
|
|
|
Chord* chord = toChord(element);
|
|
|
|
for (Note* note : chord->notes()) {
|
2018-03-20 17:34:19 +01:00
|
|
|
note->disconnectTiedNotes();
|
2013-11-14 16:20:41 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-02-13 17:06:30 +01:00
|
|
|
else if (element->isClef())
|
2016-10-25 17:30:55 +02:00
|
|
|
element->score()->setLayout(element->staff()->nextClefTick(element->tick()));
|
2017-02-13 17:06:30 +01:00
|
|
|
else if (element->isKeySig())
|
|
|
|
element->score()->setLayout(element->staff()->nextKeyTick(element->tick()));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// name
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
const char* RemoveElement::name() const
|
|
|
|
{
|
|
|
|
static char buffer[64];
|
2018-04-18 14:31:36 +02:00
|
|
|
if (element->isTextBase())
|
2016-03-24 12:39:18 +01:00
|
|
|
snprintf(buffer, 64, "Remove: %s <%s> %p", element->name(),
|
2018-04-18 14:31:36 +02:00
|
|
|
qPrintable(toTextBase(element)->plainText()), element);
|
2016-10-25 17:30:55 +02:00
|
|
|
else if (element->isSegment())
|
|
|
|
snprintf(buffer, 64, "Remove: <%s-%s> %p", element->name(), toSegment(element)->subTypeName(), element);
|
2014-08-27 14:35:39 +02:00
|
|
|
else
|
2016-03-24 12:39:18 +01:00
|
|
|
snprintf(buffer, 64, "Remove: %s %p", element->name(), element);
|
2012-05-26 14:26:10 +02:00
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// InsertPart
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
InsertPart::InsertPart(Part* p, int i)
|
|
|
|
{
|
|
|
|
part = p;
|
|
|
|
idx = i;
|
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void InsertPart::undo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
part->score()->removePart(part);
|
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void InsertPart::redo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
part->score()->insertPart(part, idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// RemovePart
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
RemovePart::RemovePart(Part* p, int i)
|
|
|
|
{
|
|
|
|
part = p;
|
|
|
|
idx = i;
|
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void RemovePart::undo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
part->score()->insertPart(part, idx);
|
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void RemovePart::redo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void InsertStaff::undo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
staff->score()->removeStaff(staff);
|
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void InsertStaff::redo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
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
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void RemoveStaff::undo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2014-08-11 15:25:55 +02:00
|
|
|
staff->score()->insertStaff(staff, ridx);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void RemoveStaff::redo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
staff->score()->removeStaff(staff);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// InsertMStaff
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
InsertMStaff::InsertMStaff(Measure* m, MStaff* ms, int i)
|
|
|
|
{
|
|
|
|
measure = m;
|
|
|
|
mstaff = ms;
|
|
|
|
idx = i;
|
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void InsertMStaff::undo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
measure->removeMStaff(mstaff, idx);
|
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void InsertMStaff::redo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
measure->insertMStaff(mstaff, idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// RemoveMStaff
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
RemoveMStaff::RemoveMStaff(Measure* m, MStaff* ms, int i)
|
|
|
|
{
|
|
|
|
measure = m;
|
|
|
|
mstaff = ms;
|
|
|
|
idx = i;
|
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void RemoveMStaff::undo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
measure->insertMStaff(mstaff, idx);
|
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void RemoveMStaff::redo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
measure->removeMStaff(mstaff, idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void SortStaves::redo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
score->sortStaves(list);
|
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void SortStaves::undo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangePitch::flip(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
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
|
2016-06-03 10:17:06 +02:00
|
|
|
if (f_pitch == pitch && f_tpc1 == tpc1 && f_tpc2 == tpc2)
|
2014-04-10 13:13:37 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
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
|
|
|
|
2016-03-02 13:20:19 +01:00
|
|
|
note->score()->setLayout(note->tick());
|
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;
|
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeFretting::flip(EditData*)
|
2014-09-07 10:59:12 +02:00
|
|
|
{
|
|
|
|
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;
|
2016-06-03 10:17:06 +02:00
|
|
|
note->score()->setLayout(note->tick());
|
2014-09-07 10:59:12 +02:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeElement
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
ChangeElement::ChangeElement(Element* oe, Element* ne)
|
|
|
|
{
|
|
|
|
oldElement = oe;
|
|
|
|
newElement = ne;
|
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeElement::flip(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2014-02-28 14:25:47 +01:00
|
|
|
const LinkedElements* links = oldElement->links();
|
2012-05-26 14:26:10 +02:00
|
|
|
if (links) {
|
2016-11-29 21:20:08 +01:00
|
|
|
newElement->linkTo(oldElement);
|
2014-05-21 20:08:37 +02:00
|
|
|
oldElement->unlink();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Score* score = oldElement->score();
|
2018-02-17 21:11:43 +01:00
|
|
|
if (!score->selection().isRange()) {
|
|
|
|
if (oldElement->selected())
|
|
|
|
score->deselect(oldElement);
|
|
|
|
if (newElement->selected())
|
|
|
|
score->select(newElement, SelectType::ADD);
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
if (oldElement->parent() == 0) {
|
|
|
|
score->removeElement(oldElement);
|
|
|
|
score->addElement(newElement);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
oldElement->parent()->change(oldElement, newElement);
|
|
|
|
}
|
|
|
|
|
2016-12-12 10:31:37 +01:00
|
|
|
if (newElement->isKeySig()) {
|
|
|
|
KeySig* ks = toKeySig(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
|
|
|
}
|
2016-12-12 10:31:37 +01:00
|
|
|
else if (newElement->isDynamic())
|
2014-05-30 10:16:38 +02:00
|
|
|
newElement->score()->addLayoutFlags(LayoutFlag::FIX_PITCH_VELO);
|
2016-12-12 10:31:37 +01:00
|
|
|
else if (newElement->isTempoText()) {
|
|
|
|
TempoText* t = toTempoText(oldElement);
|
2012-05-26 14:26:10 +02:00
|
|
|
score->setTempo(t->segment(), t->tempo());
|
|
|
|
}
|
2018-04-09 11:51:35 +02:00
|
|
|
// if (newElement->isSegmentFlag()) {
|
|
|
|
if (newElement->isSpannerSegment()) {
|
2017-12-20 16:49:30 +01:00
|
|
|
SpannerSegment* os = toSpannerSegment(oldElement);
|
|
|
|
SpannerSegment* ns = toSpannerSegment(newElement);
|
2012-05-26 14:26:10 +02:00
|
|
|
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);
|
2016-06-14 10:32:34 +02:00
|
|
|
oldElement->triggerLayout();
|
|
|
|
newElement->triggerLayout();
|
|
|
|
// score->setLayoutAll();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// InsertStaves
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
InsertStaves::InsertStaves(Measure* m, int _a, int _b)
|
|
|
|
{
|
|
|
|
measure = m;
|
|
|
|
a = _a;
|
|
|
|
b = _b;
|
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void InsertStaves::undo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
measure->removeStaves(a, b);
|
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void InsertStaves::redo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
measure->insertStaves(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// RemoveStaves
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
RemoveStaves::RemoveStaves(Measure* m, int _a, int _b)
|
|
|
|
{
|
|
|
|
measure = m;
|
|
|
|
a = _a;
|
|
|
|
b = _b;
|
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void RemoveStaves::undo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
measure->insertStaves(a, b);
|
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void RemoveStaves::redo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
measure->removeStaves(a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
2014-06-04 10:20:14 +02:00
|
|
|
// ChangeKeySig::flip
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeKeySig::flip(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
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);
|
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;
|
2018-04-05 18:39:25 +02:00
|
|
|
keysig->score()->setLayout(tick);
|
|
|
|
keysig->score()->setLayout(keysig->staff()->nextKeyTick(tick));
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeMeasureLen
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
ChangeMeasureLen::ChangeMeasureLen(Measure* m, Fraction l)
|
|
|
|
{
|
|
|
|
measure = m;
|
|
|
|
len = l;
|
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeMeasureLen::flip(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
Fraction oLen = measure->len();
|
|
|
|
|
|
|
|
//
|
|
|
|
// move EndBarLine and TimeSigAnnounce
|
|
|
|
// to end of measure:
|
|
|
|
//
|
2018-04-23 11:45:54 +02:00
|
|
|
|
|
|
|
std::list<Segment*> sl;
|
2018-12-06 14:02:58 +01:00
|
|
|
for (Segment* s = measure->first(); s; s = s->next()) {
|
|
|
|
if (!s->isEndBarLineType() && !s->isTimeSigAnnounceType())
|
2012-05-26 14:26:10 +02:00
|
|
|
continue;
|
2018-04-23 11:45:54 +02:00
|
|
|
s->setRtick(len.ticks());
|
|
|
|
sl.push_back(s);
|
|
|
|
measure->remove(s);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
measure->setLen(len);
|
2012-09-04 10:34:00 +02:00
|
|
|
measure->score()->fixTicks();
|
2012-05-26 14:26:10 +02:00
|
|
|
len = oLen;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// TransposeHarmony
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
TransposeHarmony::TransposeHarmony(Harmony* h, int rtpc, int btpc)
|
|
|
|
{
|
|
|
|
harmony = h;
|
|
|
|
rootTpc = rtpc;
|
|
|
|
baseTpc = btpc;
|
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void TransposeHarmony::flip(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
int baseTpc1 = harmony->baseTpc();
|
|
|
|
int rootTpc1 = harmony->rootTpc();
|
|
|
|
harmony->setBaseTpc(baseTpc);
|
|
|
|
harmony->setRootTpc(rootTpc);
|
2015-04-27 12:59:30 +02:00
|
|
|
harmony->setXmlText(harmony->harmonyName());
|
2018-11-19 15:30:11 +01:00
|
|
|
harmony->render();
|
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
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ExchangeVoice::undo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2016-07-11 18:29:02 +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
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ExchangeVoice::redo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2016-07-11 18:29:02 +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;
|
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeInstrumentShort::flip(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
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;
|
2016-03-02 13:20:19 +01:00
|
|
|
part->score()->setLayoutAll();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeInstrumentLong::flip(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
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;
|
2016-03-02 13:20:19 +01:00
|
|
|
part->score()->setLayoutAll();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// EditText::undo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void EditText::undo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
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
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void EditText::redo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
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()
|
|
|
|
{
|
2015-04-27 12:59:30 +02:00
|
|
|
QString s = text->xmlText();
|
|
|
|
text->setXmlText(oldText);
|
2014-03-14 11:30:19 +01:00
|
|
|
oldText = s;
|
2016-06-14 10:32:34 +02:00
|
|
|
text->triggerLayout();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangePatch
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangePatch::flip(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
MidiPatch op;
|
fix #275313: rework mixer ui 2
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Setting color in collapsed mode now affects all channels.
Using shared_ptr to track MixerTrackItem. Part changes now affect
all instruments.
Creating new track UI object to handle parts.
Using shard_ptr to track MixerTrackItem objects.
setting port and channel data now.
Changing to horizontal layout.
Fixing knob display. Chaning track control appearance.
Setting init slider window size.
Switchong back to vertical orientation. Fixing a few UI bugs in
the slider.
Tracks now left aligned.
Moving details panel above mixer. Now changing track selection when
user clicks on sliders.
Pan and volume controls now reflect track color.
Showing volume and pan values in tooltips.
Creating a new slider control for mixer.
Switching Channel's volume, pan, reverb and chorus and chaning them
to doubles with a decimal range.
No longer writing out vol, pan, chor, reverb when at default values.
Nolonger writing vol, pan, chorus, reverb as controler values in
output file.
Now testing against default values on write.
More export fixes.
Manually editing test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
More test changes to make Travis happy.
More test changes to make Travis happy.
Importing MusicXML now matches new volume, pan ranges.
Changing range of pan. Fixing a few bugs with calculating MIDI.
Altering test files for Travis.
fix #275313: rework-mixer-ui-2
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Setting color in collapsed mode now affects all channels.
Using shared_ptr to track MixerTrackItem. Part changes now affect
all instruments.
Creating new track UI object to handle parts.
Using shard_ptr to track MixerTrackItem objects.
setting port and channel data now.
Changing to horizontal layout.
Fixing knob display. Chaning track control appearance.
Setting init slider window size.
Switchong back to vertical orientation. Fixing a few UI bugs in
the slider.
Tracks now left aligned.
Moving details panel above mixer. Now changing track selection when
user clicks on sliders.
Pan and volume controls now reflect track color.
Showing volume and pan values in tooltips.
Creating a new slider control for mixer.
Switching Channel's volume, pan, reverb and chorus and chaning them
to doubles with a decimal range.
No longer writing out vol, pan, chor, reverb when at default values.
Nolonger writing vol, pan, chorus, reverb as controler values in
output file.
Now testing against default values on write.
More export fixes.
Manually editing test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
More test changes to make Travis happy.
More test changes to make Travis happy.
Importing MusicXML now matches new volume, pan ranges.
Changing range of pan. Fixing a few bugs with calculating MIDI.
Altering test files for Travis.
Restoring the volume, pan, chorus, reverb to original char data type
& range. UI now shows different 'user friendly' ranges.
Overwriting tests with versions from master.
mtest/libmscore/compat114/clef_missing_first-ref.mscx
mtest/libmscore/compat114/hor_frame_and_mmrest-ref.mscx
mtest/musicxml/io/testInstrumentChangeMIDIportExport_ref.xml
mtest/musicxml/io/testUninitializedDivisions_ref.xml
Restoring test files to original state.
Restoring test files to original state.
Restoring old values for importing files.
Restoring part methods.
mtest/importmidi/simplify_8th_dotted_no_staccato.mscx
mtest/libmscore/compat114/clef_missing_first-ref.mscx
mtest/libmscore/compat114/hor_frame_and_mmrest-ref.mscx
mtest/musicxml/io/testInstrumentChangeMIDIportExport_ref.xml
mtest/musicxml/io/testUninitializedDivisions_ref.xml
Rearranging UI components for better feel.
Improving UI. Fixed crash when changing part name.
Adding support for two lighting modes. Showing part name over
channel expansion.
Adding master gain control to mixer.
Changing color of gain slider.
Adapting to latest source in main.
Changing master gain slider to use decibel calculation.
CSS now set on tracks whenever a Paint event received.
Restoring mixer slider values to refect MIDI ranges. Fixing crash when drumkit checked.
Fixing crash when closing score.
Fixing alignment in mixer details.
Tweaking UI for better appearance.
2018-11-13 18:43:19 +01:00
|
|
|
op.prog = channel->program();
|
|
|
|
op.bank = channel->bank();
|
|
|
|
op.synti = channel->synti();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
fix #275313: rework mixer ui 2
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Setting color in collapsed mode now affects all channels.
Using shared_ptr to track MixerTrackItem. Part changes now affect
all instruments.
Creating new track UI object to handle parts.
Using shard_ptr to track MixerTrackItem objects.
setting port and channel data now.
Changing to horizontal layout.
Fixing knob display. Chaning track control appearance.
Setting init slider window size.
Switchong back to vertical orientation. Fixing a few UI bugs in
the slider.
Tracks now left aligned.
Moving details panel above mixer. Now changing track selection when
user clicks on sliders.
Pan and volume controls now reflect track color.
Showing volume and pan values in tooltips.
Creating a new slider control for mixer.
Switching Channel's volume, pan, reverb and chorus and chaning them
to doubles with a decimal range.
No longer writing out vol, pan, chor, reverb when at default values.
Nolonger writing vol, pan, chorus, reverb as controler values in
output file.
Now testing against default values on write.
More export fixes.
Manually editing test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
More test changes to make Travis happy.
More test changes to make Travis happy.
Importing MusicXML now matches new volume, pan ranges.
Changing range of pan. Fixing a few bugs with calculating MIDI.
Altering test files for Travis.
fix #275313: rework-mixer-ui-2
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Setting color in collapsed mode now affects all channels.
Using shared_ptr to track MixerTrackItem. Part changes now affect
all instruments.
Creating new track UI object to handle parts.
Using shard_ptr to track MixerTrackItem objects.
setting port and channel data now.
Changing to horizontal layout.
Fixing knob display. Chaning track control appearance.
Setting init slider window size.
Switchong back to vertical orientation. Fixing a few UI bugs in
the slider.
Tracks now left aligned.
Moving details panel above mixer. Now changing track selection when
user clicks on sliders.
Pan and volume controls now reflect track color.
Showing volume and pan values in tooltips.
Creating a new slider control for mixer.
Switching Channel's volume, pan, reverb and chorus and chaning them
to doubles with a decimal range.
No longer writing out vol, pan, chor, reverb when at default values.
Nolonger writing vol, pan, chorus, reverb as controler values in
output file.
Now testing against default values on write.
More export fixes.
Manually editing test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
More test changes to make Travis happy.
More test changes to make Travis happy.
Importing MusicXML now matches new volume, pan ranges.
Changing range of pan. Fixing a few bugs with calculating MIDI.
Altering test files for Travis.
Restoring the volume, pan, chorus, reverb to original char data type
& range. UI now shows different 'user friendly' ranges.
Overwriting tests with versions from master.
mtest/libmscore/compat114/clef_missing_first-ref.mscx
mtest/libmscore/compat114/hor_frame_and_mmrest-ref.mscx
mtest/musicxml/io/testInstrumentChangeMIDIportExport_ref.xml
mtest/musicxml/io/testUninitializedDivisions_ref.xml
Restoring test files to original state.
Restoring test files to original state.
Restoring old values for importing files.
Restoring part methods.
mtest/importmidi/simplify_8th_dotted_no_staccato.mscx
mtest/libmscore/compat114/clef_missing_first-ref.mscx
mtest/libmscore/compat114/hor_frame_and_mmrest-ref.mscx
mtest/musicxml/io/testInstrumentChangeMIDIportExport_ref.xml
mtest/musicxml/io/testUninitializedDivisions_ref.xml
Rearranging UI components for better feel.
Improving UI. Fixed crash when changing part name.
Adding support for two lighting modes. Showing part name over
channel expansion.
Adding master gain control to mixer.
Changing color of gain slider.
Adapting to latest source in main.
Changing master gain slider to use decibel calculation.
CSS now set on tracks whenever a Paint event received.
Restoring mixer slider values to refect MIDI ranges. Fixing crash when drumkit checked.
Fixing crash when closing score.
Fixing alignment in mixer details.
Tweaking UI for better appearance.
2018-11-13 18:43:19 +01:00
|
|
|
channel->setProgram(patch.prog);
|
|
|
|
channel->setBank(patch.bank);
|
|
|
|
channel->setSynti(patch.synti);
|
2015-03-05 16:46:37 +01:00
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
patch = op;
|
|
|
|
|
2013-04-03 19:38:16 +02:00
|
|
|
if (MScore::seq == 0) {
|
2018-06-14 10:19:21 +02:00
|
|
|
qWarning("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);
|
fix #275313: rework mixer ui 2
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Setting color in collapsed mode now affects all channels.
Using shared_ptr to track MixerTrackItem. Part changes now affect
all instruments.
Creating new track UI object to handle parts.
Using shard_ptr to track MixerTrackItem objects.
setting port and channel data now.
Changing to horizontal layout.
Fixing knob display. Chaning track control appearance.
Setting init slider window size.
Switchong back to vertical orientation. Fixing a few UI bugs in
the slider.
Tracks now left aligned.
Moving details panel above mixer. Now changing track selection when
user clicks on sliders.
Pan and volume controls now reflect track color.
Showing volume and pan values in tooltips.
Creating a new slider control for mixer.
Switching Channel's volume, pan, reverb and chorus and chaning them
to doubles with a decimal range.
No longer writing out vol, pan, chor, reverb when at default values.
Nolonger writing vol, pan, chorus, reverb as controler values in
output file.
Now testing against default values on write.
More export fixes.
Manually editing test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
More test changes to make Travis happy.
More test changes to make Travis happy.
Importing MusicXML now matches new volume, pan ranges.
Changing range of pan. Fixing a few bugs with calculating MIDI.
Altering test files for Travis.
fix #275313: rework-mixer-ui-2
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Setting color in collapsed mode now affects all channels.
Using shared_ptr to track MixerTrackItem. Part changes now affect
all instruments.
Creating new track UI object to handle parts.
Using shard_ptr to track MixerTrackItem objects.
setting port and channel data now.
Changing to horizontal layout.
Fixing knob display. Chaning track control appearance.
Setting init slider window size.
Switchong back to vertical orientation. Fixing a few UI bugs in
the slider.
Tracks now left aligned.
Moving details panel above mixer. Now changing track selection when
user clicks on sliders.
Pan and volume controls now reflect track color.
Showing volume and pan values in tooltips.
Creating a new slider control for mixer.
Switching Channel's volume, pan, reverb and chorus and chaning them
to doubles with a decimal range.
No longer writing out vol, pan, chor, reverb when at default values.
Nolonger writing vol, pan, chorus, reverb as controler values in
output file.
Now testing against default values on write.
More export fixes.
Manually editing test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
More test changes to make Travis happy.
More test changes to make Travis happy.
Importing MusicXML now matches new volume, pan ranges.
Changing range of pan. Fixing a few bugs with calculating MIDI.
Altering test files for Travis.
Restoring the volume, pan, chorus, reverb to original char data type
& range. UI now shows different 'user friendly' ranges.
Overwriting tests with versions from master.
mtest/libmscore/compat114/clef_missing_first-ref.mscx
mtest/libmscore/compat114/hor_frame_and_mmrest-ref.mscx
mtest/musicxml/io/testInstrumentChangeMIDIportExport_ref.xml
mtest/musicxml/io/testUninitializedDivisions_ref.xml
Restoring test files to original state.
Restoring test files to original state.
Restoring old values for importing files.
Restoring part methods.
mtest/importmidi/simplify_8th_dotted_no_staccato.mscx
mtest/libmscore/compat114/clef_missing_first-ref.mscx
mtest/libmscore/compat114/hor_frame_and_mmrest-ref.mscx
mtest/musicxml/io/testInstrumentChangeMIDIportExport_ref.xml
mtest/musicxml/io/testUninitializedDivisions_ref.xml
Rearranging UI components for better feel.
Improving UI. Fixed crash when changing part name.
Adding support for two lighting modes. Showing part name over
channel expansion.
Adding master gain control to mixer.
Changing color of gain slider.
Adapting to latest source in main.
Changing master gain slider to use decibel calculation.
CSS now set on tracks whenever a Paint event received.
Restoring mixer slider values to refect MIDI ranges. Fixing crash when drumkit checked.
Fixing crash when closing score.
Fixing alignment in mixer details.
Tweaking UI for better appearance.
2018-11-13 18:43:19 +01:00
|
|
|
event.setChannel(channel->channel());
|
2012-05-26 14:26:10 +02:00
|
|
|
|
fix #275313: rework mixer ui 2
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Setting color in collapsed mode now affects all channels.
Using shared_ptr to track MixerTrackItem. Part changes now affect
all instruments.
Creating new track UI object to handle parts.
Using shard_ptr to track MixerTrackItem objects.
setting port and channel data now.
Changing to horizontal layout.
Fixing knob display. Chaning track control appearance.
Setting init slider window size.
Switchong back to vertical orientation. Fixing a few UI bugs in
the slider.
Tracks now left aligned.
Moving details panel above mixer. Now changing track selection when
user clicks on sliders.
Pan and volume controls now reflect track color.
Showing volume and pan values in tooltips.
Creating a new slider control for mixer.
Switching Channel's volume, pan, reverb and chorus and chaning them
to doubles with a decimal range.
No longer writing out vol, pan, chor, reverb when at default values.
Nolonger writing vol, pan, chorus, reverb as controler values in
output file.
Now testing against default values on write.
More export fixes.
Manually editing test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
More test changes to make Travis happy.
More test changes to make Travis happy.
Importing MusicXML now matches new volume, pan ranges.
Changing range of pan. Fixing a few bugs with calculating MIDI.
Altering test files for Travis.
fix #275313: rework-mixer-ui-2
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Setting color in collapsed mode now affects all channels.
Using shared_ptr to track MixerTrackItem. Part changes now affect
all instruments.
Creating new track UI object to handle parts.
Using shard_ptr to track MixerTrackItem objects.
setting port and channel data now.
Changing to horizontal layout.
Fixing knob display. Chaning track control appearance.
Setting init slider window size.
Switchong back to vertical orientation. Fixing a few UI bugs in
the slider.
Tracks now left aligned.
Moving details panel above mixer. Now changing track selection when
user clicks on sliders.
Pan and volume controls now reflect track color.
Showing volume and pan values in tooltips.
Creating a new slider control for mixer.
Switching Channel's volume, pan, reverb and chorus and chaning them
to doubles with a decimal range.
No longer writing out vol, pan, chor, reverb when at default values.
Nolonger writing vol, pan, chorus, reverb as controler values in
output file.
Now testing against default values on write.
More export fixes.
Manually editing test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
More test changes to make Travis happy.
More test changes to make Travis happy.
Importing MusicXML now matches new volume, pan ranges.
Changing range of pan. Fixing a few bugs with calculating MIDI.
Altering test files for Travis.
Restoring the volume, pan, chorus, reverb to original char data type
& range. UI now shows different 'user friendly' ranges.
Overwriting tests with versions from master.
mtest/libmscore/compat114/clef_missing_first-ref.mscx
mtest/libmscore/compat114/hor_frame_and_mmrest-ref.mscx
mtest/musicxml/io/testInstrumentChangeMIDIportExport_ref.xml
mtest/musicxml/io/testUninitializedDivisions_ref.xml
Restoring test files to original state.
Restoring test files to original state.
Restoring old values for importing files.
Restoring part methods.
mtest/importmidi/simplify_8th_dotted_no_staccato.mscx
mtest/libmscore/compat114/clef_missing_first-ref.mscx
mtest/libmscore/compat114/hor_frame_and_mmrest-ref.mscx
mtest/musicxml/io/testInstrumentChangeMIDIportExport_ref.xml
mtest/musicxml/io/testUninitializedDivisions_ref.xml
Rearranging UI components for better feel.
Improving UI. Fixed crash when changing part name.
Adding support for two lighting modes. Showing part name over
channel expansion.
Adding master gain control to mixer.
Changing color of gain slider.
Adapting to latest source in main.
Changing master gain slider to use decibel calculation.
CSS now set on tracks whenever a Paint event received.
Restoring mixer slider values to refect MIDI ranges. Fixing crash when drumkit checked.
Fixing crash when closing score.
Fixing alignment in mixer details.
Tweaking UI for better appearance.
2018-11-13 18:43:19 +01:00
|
|
|
int hbank = (channel->bank() >> 7) & 0x7f;
|
|
|
|
int lbank = channel->bank() & 0x7f;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
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);
|
fix #275313: rework mixer ui 2
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Setting color in collapsed mode now affects all channels.
Using shared_ptr to track MixerTrackItem. Part changes now affect
all instruments.
Creating new track UI object to handle parts.
Using shard_ptr to track MixerTrackItem objects.
setting port and channel data now.
Changing to horizontal layout.
Fixing knob display. Chaning track control appearance.
Setting init slider window size.
Switchong back to vertical orientation. Fixing a few UI bugs in
the slider.
Tracks now left aligned.
Moving details panel above mixer. Now changing track selection when
user clicks on sliders.
Pan and volume controls now reflect track color.
Showing volume and pan values in tooltips.
Creating a new slider control for mixer.
Switching Channel's volume, pan, reverb and chorus and chaning them
to doubles with a decimal range.
No longer writing out vol, pan, chor, reverb when at default values.
Nolonger writing vol, pan, chorus, reverb as controler values in
output file.
Now testing against default values on write.
More export fixes.
Manually editing test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
More test changes to make Travis happy.
More test changes to make Travis happy.
Importing MusicXML now matches new volume, pan ranges.
Changing range of pan. Fixing a few bugs with calculating MIDI.
Altering test files for Travis.
fix #275313: rework-mixer-ui-2
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Moving PartEditBase into separate file. Creating new files for
building mixer.
Creating art assets/UI design for new components.
Styling the track control.
Adding track area.
Separating out score from update.
Creating instances of mixer UI.
Creating part per voice now.
Can click on tracks to select them now.
Can now switch bwtewwn tracks.
Setting patch channel now.
Setting enabled off when no track selected.
Improving slider ui.
Turning Channel into a class and adding listener to it.
Somewhat stabalized sharing track objects between interfaces.
Can now apply volume changes to both expanded and collapsed tracks.
Pan knob is now working.
Encapsulating the rest of the fields in Channel.
Mute and solo now working.
Reverb and chorus now working.
Drumkit checkbox now working. Port and channel somewhat working.
Adding support for colors per track.
Part name change now working.
Separating out MixerTrackItem
Finishing moving MixerTrackItem to new file.
Cleaning up code.
Setting color in collapsed mode now affects all channels.
Using shared_ptr to track MixerTrackItem. Part changes now affect
all instruments.
Creating new track UI object to handle parts.
Using shard_ptr to track MixerTrackItem objects.
setting port and channel data now.
Changing to horizontal layout.
Fixing knob display. Chaning track control appearance.
Setting init slider window size.
Switchong back to vertical orientation. Fixing a few UI bugs in
the slider.
Tracks now left aligned.
Moving details panel above mixer. Now changing track selection when
user clicks on sliders.
Pan and volume controls now reflect track color.
Showing volume and pan values in tooltips.
Creating a new slider control for mixer.
Switching Channel's volume, pan, reverb and chorus and chaning them
to doubles with a decimal range.
No longer writing out vol, pan, chor, reverb when at default values.
Nolonger writing vol, pan, chorus, reverb as controler values in
output file.
Now testing against default values on write.
More export fixes.
Manually editing test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
Manually editing more test files to reflect new channel parameters.
More test changes to make Travis happy.
More test changes to make Travis happy.
Importing MusicXML now matches new volume, pan ranges.
Changing range of pan. Fixing a few bugs with calculating MIDI.
Altering test files for Travis.
Restoring the volume, pan, chorus, reverb to original char data type
& range. UI now shows different 'user friendly' ranges.
Overwriting tests with versions from master.
mtest/libmscore/compat114/clef_missing_first-ref.mscx
mtest/libmscore/compat114/hor_frame_and_mmrest-ref.mscx
mtest/musicxml/io/testInstrumentChangeMIDIportExport_ref.xml
mtest/musicxml/io/testUninitializedDivisions_ref.xml
Restoring test files to original state.
Restoring test files to original state.
Restoring old values for importing files.
Restoring part methods.
mtest/importmidi/simplify_8th_dotted_no_staccato.mscx
mtest/libmscore/compat114/clef_missing_first-ref.mscx
mtest/libmscore/compat114/hor_frame_and_mmrest-ref.mscx
mtest/musicxml/io/testInstrumentChangeMIDIportExport_ref.xml
mtest/musicxml/io/testUninitializedDivisions_ref.xml
Rearranging UI components for better feel.
Improving UI. Fixed crash when changing part name.
Adding support for two lighting modes. Showing part name over
channel expansion.
Adding master gain control to mixer.
Changing color of gain slider.
Adapting to latest source in main.
Changing master gain slider to use decibel calculation.
CSS now set on tracks whenever a Paint event received.
Restoring mixer slider values to refect MIDI ranges. Fixing crash when drumkit checked.
Fixing crash when closing score.
Fixing alignment in mixer details.
Tweaking UI for better appearance.
2018-11-13 18:43:19 +01:00
|
|
|
event.setValue(channel->program());
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2015-03-05 16:46:37 +01:00
|
|
|
score->setInstrumentsChanged(true);
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
MScore::seq->sendEvent(event);
|
2015-03-04 19:08:58 +01:00
|
|
|
channel->updateInitList();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeStaff
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-27 17:53:08 +02:00
|
|
|
ChangeStaff::ChangeStaff(Staff* _staff, bool _invisible, ClefTypeList _clefType,
|
2015-08-04 19:53:54 +02:00
|
|
|
qreal _userDist, Staff::HideMode _hideMode, bool _showIfEmpty, bool _cutaway, bool hide)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2014-08-06 16:37:41 +02:00
|
|
|
staff = _staff;
|
|
|
|
invisible = _invisible;
|
2017-05-27 17:53:08 +02:00
|
|
|
clefType = _clefType;
|
2014-08-06 16:37:41 +02:00
|
|
|
userDist = _userDist;
|
2015-08-04 19:53:54 +02:00
|
|
|
hideMode = _hideMode;
|
2014-08-06 16:37:41 +02:00
|
|
|
showIfEmpty = _showIfEmpty;
|
2015-08-04 19:53:54 +02:00
|
|
|
cutaway = _cutaway;
|
2015-01-05 17:55:06 +01:00
|
|
|
hideSystemBarLine = hide;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeStaff::flip(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
bool invisibleChanged = staff->invisible() != invisible;
|
2017-05-27 17:53:08 +02:00
|
|
|
ClefTypeList oldClefType = staff->defaultClefType();
|
2014-08-06 16:37:41 +02:00
|
|
|
bool oldInvisible = staff->invisible();
|
|
|
|
qreal oldUserDist = staff->userDist();
|
2015-08-04 19:53:54 +02:00
|
|
|
Staff::HideMode oldHideMode = staff->hideWhenEmpty();
|
2014-08-06 16:37:41 +02:00
|
|
|
bool oldShowIfEmpty = staff->showIfEmpty();
|
2015-08-04 19:53:54 +02:00
|
|
|
bool oldCutaway = staff->cutaway();
|
2015-01-05 17:55:06 +01:00
|
|
|
bool hide = staff->hideSystemBarLine();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
staff->setInvisible(invisible);
|
2017-05-27 17:53:08 +02:00
|
|
|
staff->setDefaultClefType(clefType);
|
2013-04-20 01:32:28 +02:00
|
|
|
staff->setUserDist(userDist);
|
2015-08-04 19:53:54 +02:00
|
|
|
staff->setHideWhenEmpty(hideMode);
|
2014-08-06 16:37:41 +02:00
|
|
|
staff->setShowIfEmpty(showIfEmpty);
|
2015-08-04 19:53:54 +02:00
|
|
|
staff->setCutaway(cutaway);
|
2015-01-05 17:55:06 +01:00
|
|
|
staff->setHideSystemBarLine(hideSystemBarLine);
|
2014-08-06 16:37:41 +02:00
|
|
|
|
|
|
|
invisible = oldInvisible;
|
2017-05-27 17:53:08 +02:00
|
|
|
clefType = oldClefType;
|
2014-08-06 16:37:41 +02:00
|
|
|
userDist = oldUserDist;
|
2015-08-04 19:53:54 +02:00
|
|
|
hideMode = oldHideMode;
|
2014-08-06 16:37:41 +02:00
|
|
|
showIfEmpty = oldShowIfEmpty;
|
2015-08-04 19:53:54 +02:00
|
|
|
cutaway = oldCutaway;
|
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) {
|
2016-09-28 21:13:05 +02:00
|
|
|
int staffIdx = staff->idx();
|
2016-12-12 14:55:35 +01:00
|
|
|
for (Measure* m = score->firstMeasure(); m; m = m->nextMeasure())
|
|
|
|
m->staffLines(staffIdx)->setVisible(!staff->invisible());
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
2016-03-02 13:20:19 +01:00
|
|
|
staff->score()->setLayoutAll();
|
2016-03-11 12:18:46 +01:00
|
|
|
staff->masterScore()->rebuildMidiMapping();
|
2015-01-30 17:03:51 +01:00
|
|
|
staff->score()->setPlaylistDirty();
|
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
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeStaffType::flip(EditData*)
|
2014-05-27 01:47:30 +02:00
|
|
|
{
|
2016-12-13 13:16:17 +01:00
|
|
|
StaffType st = *staff->staffType(0); // TODO
|
2014-08-08 10:07:03 +02:00
|
|
|
|
2018-11-08 15:45:14 +01:00
|
|
|
staff->setStaffType(0, 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();
|
2016-03-02 13:20:19 +01:00
|
|
|
score->setLayoutAll();
|
2014-04-30 10:08:38 +02:00
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangePart
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2015-03-05 16:46:37 +01:00
|
|
|
ChangePart::ChangePart(Part* _part, Instrument* i, const QString& s)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
instrument = i;
|
|
|
|
part = _part;
|
|
|
|
partName = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangePart::flip(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2015-03-13 11:16:43 +01:00
|
|
|
Instrument* oi = part->instrument();
|
2015-03-05 16:46:37 +01:00
|
|
|
QString s = part->partName();
|
2012-05-26 14:26:10 +02:00
|
|
|
part->setInstrument(instrument);
|
|
|
|
part->setPartName(partName);
|
2015-03-06 09:59:34 +01:00
|
|
|
|
2014-06-04 08:30:59 +02:00
|
|
|
Score* score = part->score();
|
2016-03-11 12:18:46 +01:00
|
|
|
score->masterScore()->rebuildMidiMapping();
|
2014-06-04 08:30:59 +02:00
|
|
|
score->setInstrumentsChanged(true);
|
2015-01-30 17:03:51 +01:00
|
|
|
score->setPlaylistDirty();
|
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
|
|
|
|
|
2016-03-02 13:20:19 +01:00
|
|
|
score->setLayoutAll();
|
2014-06-04 08:30:59 +02:00
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
partName = s;
|
|
|
|
instrument = oi;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeStyle
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
ChangeStyle::ChangeStyle(Score* s, const MStyle& st)
|
|
|
|
: score(s), style(st)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeStyle::flip(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2017-01-05 11:23:47 +01:00
|
|
|
MStyle tmp = score->style();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2018-03-27 15:36:00 +02:00
|
|
|
if (score->styleV(Sid::concertPitch) != style.value(Sid::concertPitch))
|
|
|
|
score->cmdConcertPitchChanged(style.value(Sid::concertPitch).toBool(), true);
|
|
|
|
if (score->styleV(Sid::MusicalSymbolFont) != style.value(Sid::MusicalSymbolFont)) {
|
|
|
|
score->setScoreFont(ScoreFont::fontFactory(style.value(Sid::MusicalSymbolFont).toString()));
|
2013-11-06 15:58:05 +01:00
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
score->setStyle(style);
|
2016-09-28 10:01:20 +02:00
|
|
|
score->styleChanged();
|
2012-05-26 14:26:10 +02:00
|
|
|
style = tmp;
|
|
|
|
}
|
|
|
|
|
2013-09-28 11:24:00 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeStyleVal::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeStyleVal::flip(EditData*)
|
2013-09-28 11:24:00 +02:00
|
|
|
{
|
2017-01-05 11:23:47 +01:00
|
|
|
QVariant v = score->styleV(idx);
|
2016-09-28 10:01:20 +02:00
|
|
|
if (v != value) {
|
2017-01-05 11:23:47 +01:00
|
|
|
score->style().set(idx, value);
|
2018-03-27 15:36:00 +02:00
|
|
|
if (idx == Sid::chordDescriptionFile) {
|
2017-01-05 11:23:47 +01:00
|
|
|
score->style().chordList()->unload();
|
2018-12-13 01:03:36 +01:00
|
|
|
if (score->styleB(Sid::chordsXmlFile))
|
|
|
|
score->style().chordList()->read("chords.xml");
|
2017-01-05 11:23:47 +01:00
|
|
|
score->style().chordList()->read(value.toString());
|
2016-09-28 10:01:20 +02:00
|
|
|
}
|
|
|
|
score->styleChanged();
|
|
|
|
}
|
2013-09-28 11:24:00 +02:00
|
|
|
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
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeChordStaffMove::flip(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2014-10-24 01:28:57 +02:00
|
|
|
int v = chordRest->staffMove();
|
2016-06-14 10:32:34 +02:00
|
|
|
for (ScoreElement* e : chordRest->linkList()) {
|
2017-12-20 16:49:30 +01:00
|
|
|
ChordRest* cr = toChordRest(e);
|
2016-06-14 10:32:34 +02:00
|
|
|
cr->setStaffMove(staffMove);
|
|
|
|
cr->triggerLayout();
|
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)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeVelocity::flip(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
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
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2016-12-12 14:55:35 +01:00
|
|
|
ChangeMStaffProperties::ChangeMStaffProperties(Measure* m, int i, bool v, bool s)
|
|
|
|
: measure(m), staffIdx(i), visible(v), slashStyle(s)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeMStaffProperties::flip(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2016-12-12 14:55:35 +01:00
|
|
|
bool v = measure->visible(staffIdx);
|
|
|
|
bool s = measure->slashStyle(staffIdx);
|
|
|
|
measure->setStaffVisible(staffIdx, visible);
|
|
|
|
measure->setStaffSlashStyle(staffIdx, slashStyle);
|
2012-05-26 14:26:10 +02:00
|
|
|
visible = v;
|
|
|
|
slashStyle = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
2015-03-09 18:31:28 +01:00
|
|
|
// insertMeasures
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2015-03-09 18:31:28 +01:00
|
|
|
void InsertRemoveMeasures::insertMeasures()
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2014-07-27 12:38:45 +02:00
|
|
|
Score* score = fm->score();
|
|
|
|
QList<Clef*> clefs;
|
2015-03-09 18:31:28 +01:00
|
|
|
QList<KeySig*> keys;
|
2018-06-14 10:19:21 +02:00
|
|
|
Segment* fs = 0;
|
|
|
|
Segment* ls = 0;
|
2016-12-12 10:31:37 +01:00
|
|
|
if (fm->isMeasure()) {
|
2015-03-11 12:53:13 +01:00
|
|
|
score->setPlaylistDirty();
|
2017-07-18 10:46:15 +02:00
|
|
|
fs = toMeasure(fm)->first();
|
|
|
|
ls = toMeasure(lm)->last();
|
|
|
|
for (Segment* s = fs; s && s != ls; s = s->next1()) {
|
2017-03-08 13:12:26 +01:00
|
|
|
if (!(s->segmentType() & (SegmentType::Clef | SegmentType::KeySig)))
|
2014-07-27 12:38:45 +02:00
|
|
|
continue;
|
2015-03-11 12:53:13 +01:00
|
|
|
for (int track = 0; track < score->ntracks(); track += VOICES) {
|
|
|
|
Element* e = s->element(track);
|
|
|
|
if (!e || e->generated())
|
|
|
|
continue;
|
2016-12-12 10:31:37 +01:00
|
|
|
if (e->isClef())
|
|
|
|
clefs.append(toClef(e));
|
|
|
|
else if (e->isKeySig())
|
|
|
|
keys.append(toKeySig(e));
|
2015-03-11 12:53:13 +01:00
|
|
|
}
|
2014-07-27 12:38:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
score->measures()->insert(fm, lm);
|
2015-03-11 12:53:13 +01:00
|
|
|
|
2016-12-12 10:31:37 +01:00
|
|
|
if (fm->isMeasure()) {
|
2015-03-11 12:53:13 +01:00
|
|
|
score->fixTicks();
|
|
|
|
score->insertTime(fm->tick(), lm->endTick() - fm->tick());
|
2015-03-13 12:39:38 +01:00
|
|
|
|
|
|
|
// move ownership of Instrument back to part
|
2017-07-18 10:46:15 +02:00
|
|
|
for (Segment* s = fs; s && s != ls; s = s->next1()) {
|
2015-03-13 12:39:38 +01:00
|
|
|
for (Element* e : s->annotations()) {
|
2016-12-12 10:31:37 +01:00
|
|
|
if (e->isInstrumentChange()) {
|
|
|
|
e->part()->setInstrument(toInstrumentChange(e)->instrument(), s->tick());
|
2015-03-13 12:39:38 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-03-11 12:53:13 +01:00
|
|
|
for (Clef* clef : clefs)
|
|
|
|
clef->staff()->setClef(clef);
|
|
|
|
for (KeySig* key : keys)
|
|
|
|
key->staff()->setKey(key->segment()->tick(), key->keySigEvent());
|
|
|
|
}
|
|
|
|
|
2016-03-02 13:20:19 +01:00
|
|
|
score->setLayoutAll();
|
2014-08-11 21:17:55 +02:00
|
|
|
|
|
|
|
//
|
|
|
|
// connect ties
|
|
|
|
//
|
|
|
|
|
2016-12-12 10:31:37 +01:00
|
|
|
if (!fm->isMeasure() || !fm->prevMeasure())
|
2014-08-11 21:17:55 +02:00
|
|
|
return;
|
|
|
|
Measure* m = fm->prevMeasure();
|
|
|
|
for (Segment* seg = m->first(); seg; seg = seg->next()) {
|
|
|
|
for (int track = 0; track < score->ntracks(); ++track) {
|
2017-12-20 16:49:30 +01:00
|
|
|
Element* e = seg->element(track);
|
|
|
|
if (e == 0 || !e->isChord())
|
2014-08-11 21:17:55 +02:00
|
|
|
continue;
|
2017-12-20 16:49:30 +01:00
|
|
|
Chord* chord = toChord(e);
|
2014-08-11 21:17:55 +02:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
2015-03-09 18:31:28 +01:00
|
|
|
// removeMeasures
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2015-03-09 18:31:28 +01:00
|
|
|
void InsertRemoveMeasures::removeMeasures()
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2014-07-27 12:38:45 +02:00
|
|
|
Score* score = fm->score();
|
2015-03-09 18:31:28 +01:00
|
|
|
|
2015-03-10 11:38:27 +01:00
|
|
|
int tick1 = fm->tick();
|
|
|
|
int tick2 = lm->endTick();
|
2017-02-15 13:58:54 +01:00
|
|
|
|
|
|
|
QList<System*> systemList;
|
|
|
|
for (MeasureBase* mb = lm;; mb = mb->prev()) {
|
|
|
|
System* system = mb->system();
|
|
|
|
if (system) {
|
|
|
|
if (!systemList.contains(system)) {
|
|
|
|
systemList.push_back(system);
|
|
|
|
}
|
|
|
|
auto i = std::find(system->measures().begin(), system->measures().end(), mb);
|
2018-06-14 10:19:21 +02:00
|
|
|
if (i != system->measures().end()) {
|
|
|
|
(*i)->setParent(0);
|
2018-08-30 13:11:49 +02:00
|
|
|
system->measures().erase(i);
|
2018-06-14 10:19:21 +02:00
|
|
|
}
|
2017-02-15 13:58:54 +01:00
|
|
|
}
|
|
|
|
if (mb == fm)
|
|
|
|
break;
|
|
|
|
}
|
2014-07-27 12:38:45 +02:00
|
|
|
score->measures()->remove(fm, lm);
|
2017-02-15 13:58:54 +01:00
|
|
|
|
2017-02-22 10:40:35 +01:00
|
|
|
score->fixTicks();
|
2016-04-01 14:57:24 +02:00
|
|
|
if (fm->isMeasure()) {
|
2015-03-11 12:53:13 +01:00
|
|
|
score->setPlaylistDirty();
|
2015-06-09 17:41:05 +02:00
|
|
|
|
|
|
|
// check if there is a clef at the end of last measure
|
|
|
|
// remove clef from staff cleflist
|
|
|
|
|
2016-04-01 14:57:24 +02:00
|
|
|
if (lm->isMeasure()) {
|
|
|
|
Measure* m = toMeasure(lm);
|
2017-03-08 13:12:26 +01:00
|
|
|
Segment* s = m->findSegment(SegmentType::Clef, tick2);
|
2015-06-09 17:41:05 +02:00
|
|
|
if (s) {
|
2016-04-01 14:57:24 +02:00
|
|
|
for (Element* e : s->elist()) {
|
|
|
|
Clef* clef = toClef(e);
|
2015-06-09 17:41:05 +02:00
|
|
|
if (clef)
|
2016-04-01 14:57:24 +02:00
|
|
|
score->staff(clef->staffIdx())->removeClef(clef);
|
2015-06-09 17:41:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-02-20 11:43:54 +01:00
|
|
|
if (score->firstMeasure())
|
|
|
|
score->insertTime(tick1, -(tick2 - tick1));
|
2016-04-11 15:28:32 +02:00
|
|
|
for (Spanner* sp : score->unmanagedSpanners()) {
|
|
|
|
if ((sp->tick() >= tick1 && sp->tick() < tick2) || (sp->tick2() >= tick1 && sp->tick2() < tick2))
|
2015-03-11 12:53:13 +01:00
|
|
|
sp->removeUnmanaged();
|
2016-04-11 15:28:32 +02:00
|
|
|
}
|
2015-03-11 12:53:13 +01:00
|
|
|
score->connectTies(true); // ??
|
|
|
|
}
|
2017-02-15 13:58:54 +01:00
|
|
|
|
|
|
|
// remove empty systems
|
|
|
|
|
|
|
|
for (System* s : systemList) {
|
|
|
|
if (s->measures().empty()) {
|
|
|
|
Page* page = s->page();
|
|
|
|
if (page) {
|
|
|
|
// erase system from page
|
2018-09-25 15:55:08 +02:00
|
|
|
QList<System*>& sl = page->systems();
|
|
|
|
auto i = std::find(sl.begin(), sl.end(), s);
|
|
|
|
if (i != sl.end())
|
|
|
|
sl.erase(i);
|
2017-02-15 13:58:54 +01:00
|
|
|
// erase system from score
|
|
|
|
auto k = std::find(score->systems().begin(), score->systems().end(), s);
|
|
|
|
if (k != score->systems().end())
|
|
|
|
score->systems().erase(k);
|
|
|
|
// finally delete system
|
2017-02-20 11:43:54 +01:00
|
|
|
score->deleteLater(s);
|
2017-02-15 13:58:54 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-02 13:20:19 +01:00
|
|
|
score->setLayoutAll();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeImage::flip(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// AddExcerpt::undo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void AddExcerpt::undo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2016-10-10 18:37:28 +02:00
|
|
|
excerpt->oscore()->removeExcerpt(excerpt);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// AddExcerpt::redo
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void AddExcerpt::redo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2016-10-10 18:37:28 +02:00
|
|
|
excerpt->oscore()->addExcerpt(excerpt);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// RemoveExcerpt::undo()
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void RemoveExcerpt::undo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2016-10-10 18:37:28 +02:00
|
|
|
excerpt->oscore()->addExcerpt(excerpt);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// RemoveExcerpt::redo()
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void RemoveExcerpt::redo(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2016-10-10 18:37:28 +02:00
|
|
|
excerpt->oscore()->removeExcerpt(excerpt);
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2015-12-15 18:23:47 +01:00
|
|
|
//---------------------------------------------------------
|
2017-04-11 11:34:25 +02:00
|
|
|
// SwapExcerpt::flip
|
2015-12-15 18:23:47 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void SwapExcerpt::flip(EditData*)
|
2015-12-15 18:23:47 +01:00
|
|
|
{
|
2016-10-10 18:37:28 +02:00
|
|
|
score->excerpts().swap(pos1, pos2);
|
2015-12-15 18:23:47 +01:00
|
|
|
score->setExcerptsChanged(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
2017-04-11 11:34:25 +02:00
|
|
|
// ChangeExcerptTitle::flip
|
2015-12-15 18:23:47 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeExcerptTitle::flip(EditData*)
|
2015-12-15 18:23:47 +01:00
|
|
|
{
|
2016-10-10 18:37:28 +02:00
|
|
|
QString s = title;
|
|
|
|
title = excerpt->title();
|
|
|
|
excerpt->setTitle(s);
|
|
|
|
excerpt->oscore()->setExcerptsChanged(true);
|
2015-12-15 18:23:47 +01:00
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeBend::flip(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
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
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeTremoloBar::flip(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
QList<PitchValue> pv = bend->points();
|
|
|
|
bend->setPoints(points);
|
|
|
|
points = pv;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeNoteEvents::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeNoteEvents::flip(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
/*TODO: QList<NoteEvent*> e = chord->playEvents();
|
|
|
|
chord->setPlayEvents(events);
|
|
|
|
events = e;
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeInstrument::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeInstrument::flip(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2018-07-27 21:55:07 +02:00
|
|
|
Part* part = is->staff()->part();
|
|
|
|
int tickStart = is->segment()->tick();
|
2015-09-21 02:13:22 +02:00
|
|
|
Instrument* oi = is->instrument(); //new Instrument(*is->instrument());
|
|
|
|
|
2018-07-27 21:55:07 +02:00
|
|
|
// set instrument in both part and instrument change element
|
|
|
|
is->setInstrument(instrument); //*instrument
|
|
|
|
part->setInstrument(instrument, tickStart);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
2018-07-27 21:55:07 +02:00
|
|
|
// update score
|
2016-03-11 12:18:46 +01:00
|
|
|
is->masterScore()->rebuildMidiMapping();
|
2018-07-27 21:55:07 +02:00
|
|
|
is->masterScore()->updateChannel();
|
2012-05-26 14:26:10 +02:00
|
|
|
is->score()->setInstrumentsChanged(true);
|
2016-03-02 13:20:19 +01:00
|
|
|
is->score()->setLayoutAll();
|
2018-07-27 21:55:07 +02:00
|
|
|
|
|
|
|
// remember original instrument
|
2012-05-26 14:26:10 +02:00
|
|
|
instrument = oi;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void SwapCR::flip(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
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);
|
2016-06-03 10:17:06 +02:00
|
|
|
cr1->score()->setLayout(s1->tick());
|
|
|
|
cr1->score()->setLayout(s2->tick());
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeClefType
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
ChangeClefType::ChangeClefType(Clef* c, ClefType cl, ClefType tc)
|
|
|
|
{
|
|
|
|
clef = c;
|
|
|
|
concertClef = cl;
|
|
|
|
transposingClef = tc;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeClefType::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeClefType::flip(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
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());
|
2016-06-14 10:32:34 +02:00
|
|
|
clef->score()->setLayoutAll(); // TODO: reduce layout to clef range
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void MoveStaff::flip(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
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;
|
2016-03-02 13:20:19 +01:00
|
|
|
staff->score()->setLayoutAll();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeStaffUserDist::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeStaffUserDist::flip(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
qreal v = staff->userDist();
|
|
|
|
staff->setUserDist(dist);
|
|
|
|
dist = v;
|
2016-03-02 13:20:19 +01:00
|
|
|
staff->score()->setLayoutAll();
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeProperty::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeProperty::flip(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
2018-02-12 16:34:33 +01:00
|
|
|
qCDebug(undoRedo) << element->name() << int(id) << "(" << propertyName(id) << ")" << element->getProperty(id) << "->" << property;
|
2016-06-01 10:47:27 +02:00
|
|
|
|
2013-08-07 13:20:44 +02:00
|
|
|
QVariant v = element->getProperty(id);
|
2017-01-16 20:51:12 +01:00
|
|
|
PropertyFlags ps = element->propertyFlags(id);
|
2017-01-17 17:52:17 +01:00
|
|
|
|
2017-01-19 09:35:38 +01:00
|
|
|
element->setProperty(id, property);
|
|
|
|
element->setPropertyFlags(id, flags);
|
2012-05-26 14:26:10 +02:00
|
|
|
property = v;
|
2017-01-19 09:35:38 +01:00
|
|
|
flags = ps;
|
2012-05-26 14:26:10 +02:00
|
|
|
}
|
|
|
|
|
2018-06-19 13:07:00 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeBracketProperty::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ChangeBracketProperty::flip(EditData* ed)
|
|
|
|
{
|
|
|
|
element = staff->brackets()[level];
|
|
|
|
ChangeProperty::flip(ed);
|
|
|
|
level = toBracketItem(element)->column();
|
|
|
|
}
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeMetaText::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeMetaText::flip(EditData*)
|
2012-05-26 14:26:10 +02:00
|
|
|
{
|
|
|
|
QString s = score->metaTag(id);
|
|
|
|
score->setMetaTag(id, text);
|
|
|
|
text = s;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeEventList::flip(EditData*)
|
2012-11-19 10:08:15 +01:00
|
|
|
{
|
2018-09-11 16:56:50 +02:00
|
|
|
size_t n = chord->notes().size();
|
|
|
|
for (size_t i = 0; i < n; ++i) {
|
2012-11-20 20:51:18 +01:00
|
|
|
Note* note = chord->notes()[i];
|
2018-09-11 16:56:50 +02:00
|
|
|
note->playEvents().swap(events[int(i)]);
|
2012-11-20 20:51:18 +01:00
|
|
|
}
|
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
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeSynthesizerState::flip(EditData*)
|
2013-04-02 20:46:07 +02:00
|
|
|
{
|
|
|
|
std::swap(state, score->_synthesizerState);
|
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void AddBracket::redo(EditData*)
|
2013-06-28 17:46:24 +02:00
|
|
|
{
|
2017-03-31 13:03:15 +02:00
|
|
|
staff->setBracketType(level, type);
|
2013-06-28 17:46:24 +02:00
|
|
|
staff->setBracketSpan(level, span);
|
2016-03-02 13:20:19 +01:00
|
|
|
staff->score()->setLayoutAll();
|
2013-06-28 17:46:24 +02:00
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void AddBracket::undo(EditData*)
|
2013-06-28 17:46:24 +02:00
|
|
|
{
|
2017-03-31 13:03:15 +02:00
|
|
|
staff->setBracketType(level, BracketType::NO_BRACKET);
|
2016-03-02 13:20:19 +01:00
|
|
|
staff->score()->setLayoutAll();
|
2013-06-28 17:46:24 +02:00
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void RemoveBracket::redo(EditData*)
|
2013-06-28 17:46:24 +02:00
|
|
|
{
|
2017-03-31 13:03:15 +02:00
|
|
|
staff->setBracketType(level, BracketType::NO_BRACKET);
|
2016-03-02 13:20:19 +01:00
|
|
|
staff->score()->setLayoutAll();
|
2013-06-28 17:46:24 +02:00
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void RemoveBracket::undo(EditData*)
|
2013-06-28 17:46:24 +02:00
|
|
|
{
|
2017-03-31 13:03:15 +02:00
|
|
|
staff->setBracketType(level, type);
|
2013-06-28 17:46:24 +02:00
|
|
|
staff->setBracketSpan(level, span);
|
2016-03-02 13:20:19 +01:00
|
|
|
staff->score()->setLayoutAll();
|
2013-06-28 17:46:24 +02:00
|
|
|
}
|
|
|
|
|
2013-08-22 12:18:14 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeSpannerElements
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeSpannerElements::flip(EditData*)
|
2013-08-22 12:18:14 +02:00
|
|
|
{
|
Fixes #19155, #22861 (duplicate of the former) and #23100.
__References__:
Issues: https://musescore.org/en/node/19155 https://musescore.org/en/node/22861 https://musescore.org/en/node/23100
__Description__:
Allows to change the start and end note to which a glissando is anchored after it has been entered. Either anchor can be changed independently.
The user interface follows the current working of other 'snappable' lines. Once either the start or end grip is selected:
- `[Shift]+[Left]` snaps the anchor to the previous chord, defaulting to its top note.
- `[Shift]+[Right]` snaps to the next chord, defaulting to its top note.
- `[Shift]+[Up]` snaps to the note above (possibly in a chord, voice or staff above the current one).
- `[Shift]+[Down]` snaps to the note below (possibly in a chord, voice or staff below the current one).
This permits to set the anchor points of a glissando to any note in the score, allowing several glissandi between the notes of the same two chords and other complex configurations (glissandi skipping intermediate chords, start and end notes in different voices or staves, and so on).
It is possible to move the anchor to a different staff of the same instrument, but not to a different instrument; also, it is not possible to 'cross' a change of instrument in the same staff.
__Known limitations__:
- The `[Shift]+[Up]` and `[Shift]+[Down]` use the same note-finding functions as the `[Alt]+[Up]` and `[Alt]+[Down]`actions which move the selection cursor to the above and below note, even across voices or staves. Occasionally, in particular if the note immediately above or below is not time-aligned, the algorithm has little expected results; however, the behaviour is already known to the user. Improving the algorithm would benefit both uses.
__Notes__:
- Most of the added infrastructure is not specific to glissando but to any spanner anchored to notes, then it should also add after-the-fact "snap to" note support to note-anchored text line.
- When moving an anchor, the algorithm usually prefers a note in the same voice/staff of the old note if it exists; if there is none, it tries other voices of the same staff.
- The change of anchor is undoable.
- The fix corrects the management of the `Chord::_endsGlissando` flag, taking into account that a chord can be the ending point of several glissandi and removing one of them not necessarily means the chord no longer ends a glissando (another glissando may still exists).
- The fix also improved the rendering of the glissando wavy line, with better alignment with anchor notes and, with glissando text, better text-line spacing.
2015-08-06 11:11:16 +02:00
|
|
|
Element* oldStartElement = spanner->startElement();
|
|
|
|
Element* oldEndElement = spanner->endElement();
|
|
|
|
if (spanner->anchor() == Spanner::Anchor::NOTE) {
|
|
|
|
// be sure new spanner elements are of the right type
|
2016-12-12 10:31:37 +01:00
|
|
|
if (!startElement->isNote() || !endElement->isNote())
|
Fixes #19155, #22861 (duplicate of the former) and #23100.
__References__:
Issues: https://musescore.org/en/node/19155 https://musescore.org/en/node/22861 https://musescore.org/en/node/23100
__Description__:
Allows to change the start and end note to which a glissando is anchored after it has been entered. Either anchor can be changed independently.
The user interface follows the current working of other 'snappable' lines. Once either the start or end grip is selected:
- `[Shift]+[Left]` snaps the anchor to the previous chord, defaulting to its top note.
- `[Shift]+[Right]` snaps to the next chord, defaulting to its top note.
- `[Shift]+[Up]` snaps to the note above (possibly in a chord, voice or staff above the current one).
- `[Shift]+[Down]` snaps to the note below (possibly in a chord, voice or staff below the current one).
This permits to set the anchor points of a glissando to any note in the score, allowing several glissandi between the notes of the same two chords and other complex configurations (glissandi skipping intermediate chords, start and end notes in different voices or staves, and so on).
It is possible to move the anchor to a different staff of the same instrument, but not to a different instrument; also, it is not possible to 'cross' a change of instrument in the same staff.
__Known limitations__:
- The `[Shift]+[Up]` and `[Shift]+[Down]` use the same note-finding functions as the `[Alt]+[Up]` and `[Alt]+[Down]`actions which move the selection cursor to the above and below note, even across voices or staves. Occasionally, in particular if the note immediately above or below is not time-aligned, the algorithm has little expected results; however, the behaviour is already known to the user. Improving the algorithm would benefit both uses.
__Notes__:
- Most of the added infrastructure is not specific to glissando but to any spanner anchored to notes, then it should also add after-the-fact "snap to" note support to note-anchored text line.
- When moving an anchor, the algorithm usually prefers a note in the same voice/staff of the old note if it exists; if there is none, it tries other voices of the same staff.
- The change of anchor is undoable.
- The fix corrects the management of the `Chord::_endsGlissando` flag, taking into account that a chord can be the ending point of several glissandi and removing one of them not necessarily means the chord no longer ends a glissando (another glissando may still exists).
- The fix also improved the rendering of the glissando wavy line, with better alignment with anchor notes and, with glissando text, better text-line spacing.
2015-08-06 11:11:16 +02:00
|
|
|
return;
|
|
|
|
Note* newStartNote;
|
|
|
|
Note* newEndNote;
|
|
|
|
Note* oldStartNote;
|
|
|
|
Note* oldEndNote;
|
|
|
|
int startDeltaTrack = oldStartElement->track() - startElement->track();
|
|
|
|
int endDeltaTrack = oldEndElement->track() - endElement->track();
|
|
|
|
// scan all spanners linked to this one
|
|
|
|
for (ScoreElement* el : spanner->linkList()) {
|
|
|
|
Spanner* sp = static_cast<Spanner*>(el);
|
|
|
|
newStartNote = newEndNote = nullptr;
|
2017-12-20 16:49:30 +01:00
|
|
|
oldStartNote = toNote(sp->startElement());
|
|
|
|
oldEndNote = toNote(sp->endElement());
|
Fixes #19155, #22861 (duplicate of the former) and #23100.
__References__:
Issues: https://musescore.org/en/node/19155 https://musescore.org/en/node/22861 https://musescore.org/en/node/23100
__Description__:
Allows to change the start and end note to which a glissando is anchored after it has been entered. Either anchor can be changed independently.
The user interface follows the current working of other 'snappable' lines. Once either the start or end grip is selected:
- `[Shift]+[Left]` snaps the anchor to the previous chord, defaulting to its top note.
- `[Shift]+[Right]` snaps to the next chord, defaulting to its top note.
- `[Shift]+[Up]` snaps to the note above (possibly in a chord, voice or staff above the current one).
- `[Shift]+[Down]` snaps to the note below (possibly in a chord, voice or staff below the current one).
This permits to set the anchor points of a glissando to any note in the score, allowing several glissandi between the notes of the same two chords and other complex configurations (glissandi skipping intermediate chords, start and end notes in different voices or staves, and so on).
It is possible to move the anchor to a different staff of the same instrument, but not to a different instrument; also, it is not possible to 'cross' a change of instrument in the same staff.
__Known limitations__:
- The `[Shift]+[Up]` and `[Shift]+[Down]` use the same note-finding functions as the `[Alt]+[Up]` and `[Alt]+[Down]`actions which move the selection cursor to the above and below note, even across voices or staves. Occasionally, in particular if the note immediately above or below is not time-aligned, the algorithm has little expected results; however, the behaviour is already known to the user. Improving the algorithm would benefit both uses.
__Notes__:
- Most of the added infrastructure is not specific to glissando but to any spanner anchored to notes, then it should also add after-the-fact "snap to" note support to note-anchored text line.
- When moving an anchor, the algorithm usually prefers a note in the same voice/staff of the old note if it exists; if there is none, it tries other voices of the same staff.
- The change of anchor is undoable.
- The fix corrects the management of the `Chord::_endsGlissando` flag, taking into account that a chord can be the ending point of several glissandi and removing one of them not necessarily means the chord no longer ends a glissando (another glissando may still exists).
- The fix also improved the rendering of the glissando wavy line, with better alignment with anchor notes and, with glissando text, better text-line spacing.
2015-08-06 11:11:16 +02:00
|
|
|
// if not the current spanner, but one linked to it, determine its new start and end notes
|
|
|
|
// as modifications 'parallel' to the modifications of the current spanner's start and end notes
|
|
|
|
if (sp != spanner) {
|
|
|
|
// determine the track where to expect the 'parallel' start element
|
|
|
|
int newTrack = sp->startElement()->track() + startDeltaTrack;
|
|
|
|
// look in notes linked to new start note for a note with
|
|
|
|
// same score as linked spanner and appropriate track
|
|
|
|
for (ScoreElement* newEl : startElement->linkList())
|
|
|
|
if (static_cast<Note*>(newEl)->score() == sp->score()
|
|
|
|
&& static_cast<Note*>(newEl)->track() == newTrack) {
|
|
|
|
newStartNote = static_cast<Note*>(newEl);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// similarly to determine the 'parallel' end element
|
|
|
|
newTrack = sp->endElement()->track() + endDeltaTrack;
|
|
|
|
for (ScoreElement* newEl : endElement->linkList())
|
|
|
|
if (static_cast<Note*>(newEl)->score() == sp->score()
|
|
|
|
&& static_cast<Note*>(newEl)->track() == newTrack) {
|
|
|
|
newEndNote = static_cast<Note*>(newEl);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// if current spanner, just use stored start and end elements
|
|
|
|
else {
|
2017-12-20 16:49:30 +01:00
|
|
|
newStartNote = toNote(startElement);
|
|
|
|
newEndNote = toNote(endElement);
|
Fixes #19155, #22861 (duplicate of the former) and #23100.
__References__:
Issues: https://musescore.org/en/node/19155 https://musescore.org/en/node/22861 https://musescore.org/en/node/23100
__Description__:
Allows to change the start and end note to which a glissando is anchored after it has been entered. Either anchor can be changed independently.
The user interface follows the current working of other 'snappable' lines. Once either the start or end grip is selected:
- `[Shift]+[Left]` snaps the anchor to the previous chord, defaulting to its top note.
- `[Shift]+[Right]` snaps to the next chord, defaulting to its top note.
- `[Shift]+[Up]` snaps to the note above (possibly in a chord, voice or staff above the current one).
- `[Shift]+[Down]` snaps to the note below (possibly in a chord, voice or staff below the current one).
This permits to set the anchor points of a glissando to any note in the score, allowing several glissandi between the notes of the same two chords and other complex configurations (glissandi skipping intermediate chords, start and end notes in different voices or staves, and so on).
It is possible to move the anchor to a different staff of the same instrument, but not to a different instrument; also, it is not possible to 'cross' a change of instrument in the same staff.
__Known limitations__:
- The `[Shift]+[Up]` and `[Shift]+[Down]` use the same note-finding functions as the `[Alt]+[Up]` and `[Alt]+[Down]`actions which move the selection cursor to the above and below note, even across voices or staves. Occasionally, in particular if the note immediately above or below is not time-aligned, the algorithm has little expected results; however, the behaviour is already known to the user. Improving the algorithm would benefit both uses.
__Notes__:
- Most of the added infrastructure is not specific to glissando but to any spanner anchored to notes, then it should also add after-the-fact "snap to" note support to note-anchored text line.
- When moving an anchor, the algorithm usually prefers a note in the same voice/staff of the old note if it exists; if there is none, it tries other voices of the same staff.
- The change of anchor is undoable.
- The fix corrects the management of the `Chord::_endsGlissando` flag, taking into account that a chord can be the ending point of several glissandi and removing one of them not necessarily means the chord no longer ends a glissando (another glissando may still exists).
- The fix also improved the rendering of the glissando wavy line, with better alignment with anchor notes and, with glissando text, better text-line spacing.
2015-08-06 11:11:16 +02:00
|
|
|
}
|
|
|
|
// update spanner's start and end notes
|
2016-03-18 09:29:16 +01:00
|
|
|
if (newStartNote && newEndNote) {
|
Fixes #19155, #22861 (duplicate of the former) and #23100.
__References__:
Issues: https://musescore.org/en/node/19155 https://musescore.org/en/node/22861 https://musescore.org/en/node/23100
__Description__:
Allows to change the start and end note to which a glissando is anchored after it has been entered. Either anchor can be changed independently.
The user interface follows the current working of other 'snappable' lines. Once either the start or end grip is selected:
- `[Shift]+[Left]` snaps the anchor to the previous chord, defaulting to its top note.
- `[Shift]+[Right]` snaps to the next chord, defaulting to its top note.
- `[Shift]+[Up]` snaps to the note above (possibly in a chord, voice or staff above the current one).
- `[Shift]+[Down]` snaps to the note below (possibly in a chord, voice or staff below the current one).
This permits to set the anchor points of a glissando to any note in the score, allowing several glissandi between the notes of the same two chords and other complex configurations (glissandi skipping intermediate chords, start and end notes in different voices or staves, and so on).
It is possible to move the anchor to a different staff of the same instrument, but not to a different instrument; also, it is not possible to 'cross' a change of instrument in the same staff.
__Known limitations__:
- The `[Shift]+[Up]` and `[Shift]+[Down]` use the same note-finding functions as the `[Alt]+[Up]` and `[Alt]+[Down]`actions which move the selection cursor to the above and below note, even across voices or staves. Occasionally, in particular if the note immediately above or below is not time-aligned, the algorithm has little expected results; however, the behaviour is already known to the user. Improving the algorithm would benefit both uses.
__Notes__:
- Most of the added infrastructure is not specific to glissando but to any spanner anchored to notes, then it should also add after-the-fact "snap to" note support to note-anchored text line.
- When moving an anchor, the algorithm usually prefers a note in the same voice/staff of the old note if it exists; if there is none, it tries other voices of the same staff.
- The change of anchor is undoable.
- The fix corrects the management of the `Chord::_endsGlissando` flag, taking into account that a chord can be the ending point of several glissandi and removing one of them not necessarily means the chord no longer ends a glissando (another glissando may still exists).
- The fix also improved the rendering of the glissando wavy line, with better alignment with anchor notes and, with glissando text, better text-line spacing.
2015-08-06 11:11:16 +02:00
|
|
|
oldStartNote->removeSpannerFor(sp);
|
|
|
|
oldEndNote->removeSpannerBack(sp);
|
|
|
|
sp->setNoteSpan(newStartNote, newEndNote);
|
|
|
|
newStartNote->addSpannerFor(sp);
|
|
|
|
newEndNote->addSpannerBack(sp);
|
|
|
|
|
2016-12-12 10:31:37 +01:00
|
|
|
if (sp->isGlissando())
|
Fixes #19155, #22861 (duplicate of the former) and #23100.
__References__:
Issues: https://musescore.org/en/node/19155 https://musescore.org/en/node/22861 https://musescore.org/en/node/23100
__Description__:
Allows to change the start and end note to which a glissando is anchored after it has been entered. Either anchor can be changed independently.
The user interface follows the current working of other 'snappable' lines. Once either the start or end grip is selected:
- `[Shift]+[Left]` snaps the anchor to the previous chord, defaulting to its top note.
- `[Shift]+[Right]` snaps to the next chord, defaulting to its top note.
- `[Shift]+[Up]` snaps to the note above (possibly in a chord, voice or staff above the current one).
- `[Shift]+[Down]` snaps to the note below (possibly in a chord, voice or staff below the current one).
This permits to set the anchor points of a glissando to any note in the score, allowing several glissandi between the notes of the same two chords and other complex configurations (glissandi skipping intermediate chords, start and end notes in different voices or staves, and so on).
It is possible to move the anchor to a different staff of the same instrument, but not to a different instrument; also, it is not possible to 'cross' a change of instrument in the same staff.
__Known limitations__:
- The `[Shift]+[Up]` and `[Shift]+[Down]` use the same note-finding functions as the `[Alt]+[Up]` and `[Alt]+[Down]`actions which move the selection cursor to the above and below note, even across voices or staves. Occasionally, in particular if the note immediately above or below is not time-aligned, the algorithm has little expected results; however, the behaviour is already known to the user. Improving the algorithm would benefit both uses.
__Notes__:
- Most of the added infrastructure is not specific to glissando but to any spanner anchored to notes, then it should also add after-the-fact "snap to" note support to note-anchored text line.
- When moving an anchor, the algorithm usually prefers a note in the same voice/staff of the old note if it exists; if there is none, it tries other voices of the same staff.
- The change of anchor is undoable.
- The fix corrects the management of the `Chord::_endsGlissando` flag, taking into account that a chord can be the ending point of several glissandi and removing one of them not necessarily means the chord no longer ends a glissando (another glissando may still exists).
- The fix also improved the rendering of the glissando wavy line, with better alignment with anchor notes and, with glissando text, better text-line spacing.
2015-08-06 11:11:16 +02:00
|
|
|
oldEndNote->chord()->updateEndsGlissando();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
spanner->setStartElement(startElement);
|
|
|
|
spanner->setEndElement(endElement);
|
|
|
|
}
|
|
|
|
startElement = oldStartElement;
|
|
|
|
endElement = oldEndElement;
|
2016-12-12 10:31:37 +01:00
|
|
|
if (spanner->isTie()) {
|
|
|
|
Tie* tie = toTie(spanner);
|
|
|
|
toNote(endElement)->setTieBack(0);
|
2013-08-22 12:18:14 +02:00
|
|
|
tie->endNote()->setTieBack(tie);
|
2016-12-12 10:31:37 +01:00
|
|
|
toNote(startElement)->setTieFor(0);
|
2013-08-22 12:18:14 +02:00
|
|
|
tie->startNote()->setTieFor(tie);
|
|
|
|
}
|
2016-06-03 10:17:06 +02:00
|
|
|
spanner->score()->setLayout(spanner->tick());
|
|
|
|
spanner->score()->setLayout(spanner->tick2());
|
2013-08-22 12:18:14 +02:00
|
|
|
}
|
2013-06-28 17:46:24 +02:00
|
|
|
|
2013-10-22 12:05:31 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeParent
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeParent::flip(EditData*)
|
2013-10-22 12:05:31 +02:00
|
|
|
{
|
|
|
|
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
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeMMRest::flip(EditData*)
|
2013-10-30 14:21:08 +01:00
|
|
|
{
|
|
|
|
Measure* mmr = m->mmRest();
|
|
|
|
m->setMMRest(mmrest);
|
|
|
|
mmrest = mmr;
|
|
|
|
}
|
|
|
|
|
2013-12-28 16:58:06 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// InsertTime
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void InsertTime::redo(EditData*)
|
2013-12-28 16:58:06 +01:00
|
|
|
{
|
|
|
|
score->insertTime(tick, len);
|
|
|
|
}
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void InsertTime::undo(EditData*)
|
2013-12-28 16:58:06 +01:00
|
|
|
{
|
|
|
|
score->insertTime(tick, -len);
|
|
|
|
}
|
|
|
|
|
2014-03-27 14:50:01 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeNoteEvent::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeNoteEvent::flip(EditData*)
|
2014-03-27 14:50:01 +01:00
|
|
|
{
|
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
|
|
|
//---------------------------------------------------------
|
2016-03-18 09:29:16 +01:00
|
|
|
// LinkUnlink
|
2014-05-21 20:08:37 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2018-04-27 13:29:20 +02:00
|
|
|
LinkUnlink::~LinkUnlink()
|
2014-05-21 20:08:37 +02:00
|
|
|
{
|
2018-05-03 11:26:12 +02:00
|
|
|
if (le && mustDelete) {
|
|
|
|
Q_ASSERT(le->size() <= 1);
|
2018-04-27 13:29:20 +02:00
|
|
|
delete le;
|
2018-05-03 11:26:12 +02:00
|
|
|
}
|
2014-05-21 20:08:37 +02:00
|
|
|
}
|
|
|
|
|
2018-04-27 13:29:20 +02:00
|
|
|
void LinkUnlink::link()
|
2014-05-21 20:08:37 +02:00
|
|
|
{
|
2018-04-27 13:29:20 +02:00
|
|
|
if (le->size() == 1)
|
|
|
|
le->front()->setLinks(le);
|
2018-05-03 11:26:12 +02:00
|
|
|
mustDelete = false;
|
2018-04-27 13:29:20 +02:00
|
|
|
le->append(e);
|
|
|
|
e->setLinks(le);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LinkUnlink::unlink()
|
|
|
|
{
|
|
|
|
Q_ASSERT(le->contains(e));
|
|
|
|
le->removeOne(e);
|
|
|
|
if (le->size() == 1) {
|
|
|
|
le->front()->setLinks(0);
|
|
|
|
mustDelete = true;
|
2014-05-21 20:08:37 +02:00
|
|
|
}
|
2015-03-18 00:55:23 +01:00
|
|
|
|
2018-04-27 13:29:20 +02:00
|
|
|
e->setLinks(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// Link
|
|
|
|
// link e1 to e2
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
Link::Link(ScoreElement* e1, ScoreElement* e2)
|
|
|
|
{
|
|
|
|
Q_ASSERT(e1->links() == 0);
|
|
|
|
le = e2->links();
|
|
|
|
if (!le) {
|
|
|
|
if (e1->isStaff())
|
|
|
|
le = new LinkedElements(e1->score(), -1);
|
|
|
|
else
|
|
|
|
le = new LinkedElements(e1->score());
|
|
|
|
le->push_back(e2);
|
|
|
|
}
|
|
|
|
e = e1;
|
2014-05-21 20:08:37 +02:00
|
|
|
}
|
2014-07-10 14:32:04 +02:00
|
|
|
|
2018-04-27 13:29:20 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// Unlink
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
Unlink::Unlink(ScoreElement* _e)
|
|
|
|
{
|
|
|
|
e = _e;
|
|
|
|
le = e->links();
|
|
|
|
Q_ASSERT(le);
|
|
|
|
}
|
2014-08-07 19:39:18 +02:00
|
|
|
|
2014-07-10 14:32:04 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeStartEndSpanner::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeStartEndSpanner::flip(EditData*)
|
2014-07-10 14:32:04 +02:00
|
|
|
{
|
|
|
|
Element* s = spanner->startElement();
|
|
|
|
Element* e = spanner->endElement();
|
|
|
|
spanner->setStartElement(start);
|
|
|
|
spanner->setEndElement(end);
|
|
|
|
start = s;
|
|
|
|
end = e;
|
|
|
|
}
|
|
|
|
|
2014-11-23 15:42:06 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeMetaTags::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeMetaTags::flip(EditData*)
|
2014-11-23 15:42:06 +01:00
|
|
|
{
|
|
|
|
QMap<QString,QString> t = score->metaTags();
|
|
|
|
score->setMetaTags(metaTags);
|
|
|
|
metaTags = t;
|
|
|
|
}
|
|
|
|
|
2015-02-04 19:51:24 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// ChangeDrumset::flip
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeDrumset::flip(EditData*)
|
2015-02-04 19:51:24 +01:00
|
|
|
{
|
|
|
|
Drumset d = *instrument->drumset();
|
|
|
|
instrument->setDrumset(&drumset);
|
|
|
|
drumset = d;
|
|
|
|
}
|
|
|
|
|
2016-02-04 11:27:47 +01:00
|
|
|
//---------------------------------------------------------
|
2018-07-16 11:01:05 +02:00
|
|
|
// ChangeGap
|
2016-02-04 11:27:47 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
|
2017-05-19 09:06:41 +02:00
|
|
|
void ChangeGap::flip(EditData*)
|
2016-02-04 11:27:47 +01:00
|
|
|
{
|
2017-04-11 11:34:25 +02:00
|
|
|
rest->setGap(v);
|
|
|
|
v = !v;
|
2016-02-04 11:27:47 +01:00
|
|
|
}
|
|
|
|
|
2018-07-16 11:01:05 +02:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// FretDot
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void FretDot::flip(EditData*)
|
|
|
|
{
|
|
|
|
int ov = fret->dot(string);
|
|
|
|
fret->setDot(string, dot);
|
|
|
|
dot = ov;
|
|
|
|
fret->triggerLayout();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// FretMarker
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void FretMarker::flip(EditData*)
|
|
|
|
{
|
|
|
|
int om = fret->marker(string);
|
|
|
|
fret->setMarker(string, marker);
|
|
|
|
marker = om;
|
|
|
|
fret->triggerLayout();
|
|
|
|
}
|
|
|
|
|
2013-05-13 18:49:17 +02:00
|
|
|
}
|