2013-02-26 15:50:36 +01:00
|
|
|
//=============================================================================
|
|
|
|
// MuseScore
|
|
|
|
// Music Composition & Notation
|
|
|
|
//
|
|
|
|
// Copyright (C) 2002-2011 Werner Schweer
|
|
|
|
//
|
|
|
|
// 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
|
|
|
|
//=============================================================================
|
|
|
|
|
|
|
|
#include "musescore.h"
|
|
|
|
#include "scoreview.h"
|
Lyrics multi-system melisma and dashes
Implements melisma and dash lines for lyrics spanning several systems.
The melisma and dash line is based on the `SLine` class and its segments on the `LineSegment` class. Both the whole line and its segments are not selectable, marked as generated and not saved in the score file, which is not changed in any way.
For very wide dash segments, several dashes are drawn; the distance between the dashes is not configurable.
Lyrics layout code in `Measure` class and in `layout.cpp` file has been commented out as the lyrics line layout is all contained in the lyrics.cpp file
The line is registered with the `Score` (to have its layout delayed until all elements are positioned) with a mechanism similar to other `Spanner`'s, but in a different container (`_unmanagedSpanner`), as the owning `Lyrics` should decide when create, register, unregister and delete its line.
The line segments are registered with the `System` they belong to (to have them drawn), in the same way as other `Spanner`'s.
There is code for using the dash metrics of the lyrics font, but it is turned off via a conditional directive, as there does not seem to be a reliable way to determine the dash metrics; conventional values (determined by trials and errors and based on my taste!) are used when the conditional directive is off.
2015-01-11 10:11:44 +01:00
|
|
|
#include "libmscore/chordrest.h"
|
|
|
|
#include "libmscore/lyrics.h"
|
2013-02-26 15:50:36 +01:00
|
|
|
#include "libmscore/score.h"
|
|
|
|
#include "libmscore/segment.h"
|
|
|
|
|
2013-05-13 18:49:17 +02:00
|
|
|
namespace Ms {
|
|
|
|
|
2013-02-26 15:50:36 +01:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// lyricsUpDown
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ScoreView::lyricsUpDown(bool up, bool end)
|
|
|
|
{
|
2017-03-31 13:03:15 +02:00
|
|
|
Lyrics* lyrics = toLyrics(editElement);
|
2013-02-26 15:50:36 +01:00
|
|
|
int track = lyrics->track();
|
|
|
|
ChordRest* cr = lyrics->chordRest();
|
|
|
|
int verse = lyrics->no();
|
2016-08-24 14:49:34 +02:00
|
|
|
Element::Placement placement = lyrics->placement();
|
2013-02-26 15:50:36 +01:00
|
|
|
|
2016-08-27 13:09:27 +02:00
|
|
|
if (placement == Element::Placement::ABOVE)
|
|
|
|
up = !up;
|
2013-02-26 15:50:36 +01:00
|
|
|
if (up) {
|
|
|
|
if (verse == 0)
|
|
|
|
return;
|
|
|
|
--verse;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
++verse;
|
2016-08-27 13:09:27 +02:00
|
|
|
if (verse > cr->lastVerse(placement))
|
2013-02-26 15:50:36 +01:00
|
|
|
return;
|
|
|
|
}
|
2016-08-27 13:09:27 +02:00
|
|
|
|
2013-02-26 15:50:36 +01:00
|
|
|
endEdit();
|
|
|
|
_score->startCmd();
|
2016-08-24 14:49:34 +02:00
|
|
|
lyrics = cr->lyrics(verse, placement);
|
2013-02-26 15:50:36 +01:00
|
|
|
if (!lyrics) {
|
|
|
|
lyrics = new Lyrics(_score);
|
|
|
|
lyrics->setTrack(track);
|
|
|
|
lyrics->setParent(cr);
|
|
|
|
lyrics->setNo(verse);
|
2016-08-24 14:49:34 +02:00
|
|
|
lyrics->setPlacement(placement);
|
2013-02-26 15:50:36 +01:00
|
|
|
_score->undoAddElement(lyrics);
|
|
|
|
}
|
|
|
|
|
2014-05-27 10:34:08 +02:00
|
|
|
_score->select(lyrics, SelectType::SINGLE, 0);
|
2015-01-19 12:37:17 +01:00
|
|
|
startEdit(lyrics, Grip::NO_GRIP);
|
2013-03-01 19:31:15 +01:00
|
|
|
mscore->changeState(mscoreState());
|
2013-02-26 15:50:36 +01:00
|
|
|
adjustCanvasPosition(lyrics, false);
|
2015-02-02 18:59:01 +01:00
|
|
|
if (end) {
|
2017-03-31 13:03:15 +02:00
|
|
|
((Lyrics*)editElement)->movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);
|
|
|
|
((Lyrics*)editElement)->movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
|
2015-02-02 18:59:01 +01:00
|
|
|
}
|
|
|
|
else {
|
2017-03-31 13:03:15 +02:00
|
|
|
((Lyrics*)editElement)->movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
|
|
|
|
((Lyrics*)editElement)->movePosition(QTextCursor::Start, QTextCursor::KeepAnchor);
|
2015-02-02 18:59:01 +01:00
|
|
|
}
|
2013-02-26 15:50:36 +01:00
|
|
|
|
2016-03-02 13:20:19 +01:00
|
|
|
_score->setLayoutAll();
|
2013-06-05 15:47:34 +02:00
|
|
|
_score->update();
|
2013-02-26 15:50:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// lyricsTab
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ScoreView::lyricsTab(bool back, bool end, bool moveOnly)
|
|
|
|
{
|
2017-03-31 13:03:15 +02:00
|
|
|
Lyrics* lyrics = (Lyrics*)editElement;
|
2013-02-26 15:50:36 +01:00
|
|
|
int track = lyrics->track();
|
|
|
|
Segment* segment = lyrics->segment();
|
|
|
|
int verse = lyrics->no();
|
2016-08-24 14:49:34 +02:00
|
|
|
Element::Placement placement = lyrics->placement();
|
2013-02-26 15:50:36 +01:00
|
|
|
|
|
|
|
Segment* nextSegment = segment;
|
|
|
|
if (back) {
|
|
|
|
// search prev chord
|
2017-03-08 13:12:26 +01:00
|
|
|
while ((nextSegment = nextSegment->prev1(SegmentType::ChordRest))) {
|
2013-02-26 15:50:36 +01:00
|
|
|
Element* el = nextSegment->element(track);
|
2017-01-18 14:16:33 +01:00
|
|
|
if (el && el->type() == ElementType::CHORD)
|
2013-02-26 15:50:36 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// search next chord
|
2017-03-08 13:12:26 +01:00
|
|
|
while ((nextSegment = nextSegment->next1(SegmentType::ChordRest))) {
|
2013-02-26 15:50:36 +01:00
|
|
|
Element* el = nextSegment->element(track);
|
2017-01-18 14:16:33 +01:00
|
|
|
if (el && el->type() == ElementType::CHORD)
|
2013-02-26 15:50:36 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (nextSegment == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
endEdit();
|
|
|
|
|
2015-01-31 19:44:04 +01:00
|
|
|
// look for the lyrics we are moving from; may be the current lyrics or a previous one
|
|
|
|
// if we are skipping several chords with spaces
|
|
|
|
Lyrics* fromLyrics = 0;
|
2013-02-26 15:50:36 +01:00
|
|
|
if (!back) {
|
|
|
|
while (segment) {
|
2016-08-17 12:52:35 +02:00
|
|
|
ChordRest* cr = toChordRest(segment->element(track));
|
|
|
|
if (cr) {
|
2016-08-24 14:49:34 +02:00
|
|
|
fromLyrics = cr->lyrics(verse, placement);
|
2015-01-31 19:44:04 +01:00
|
|
|
if (fromLyrics)
|
2013-02-26 15:50:36 +01:00
|
|
|
break;
|
|
|
|
}
|
2017-03-08 13:12:26 +01:00
|
|
|
segment = segment->prev1(SegmentType::ChordRest);
|
2013-02-26 15:50:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-17 12:52:35 +02:00
|
|
|
ChordRest* cr = toChordRest(nextSegment->element(track));
|
|
|
|
if (!cr) {
|
2013-02-26 15:50:36 +01:00
|
|
|
qDebug("no next lyrics list: %s", nextSegment->element(track)->name());
|
|
|
|
return;
|
|
|
|
}
|
2016-08-24 14:49:34 +02:00
|
|
|
Lyrics* toLyrics = cr->lyrics(verse, placement);
|
2013-02-26 15:50:36 +01:00
|
|
|
|
|
|
|
bool newLyrics = false;
|
2015-01-31 19:44:04 +01:00
|
|
|
if (!toLyrics) {
|
|
|
|
toLyrics = new Lyrics(_score);
|
|
|
|
toLyrics->setTrack(track);
|
2013-02-26 15:50:36 +01:00
|
|
|
ChordRest* cr = static_cast<ChordRest*>(nextSegment->element(track));
|
2015-01-31 19:44:04 +01:00
|
|
|
toLyrics->setParent(cr);
|
|
|
|
toLyrics->setNo(verse);
|
2016-08-24 14:49:34 +02:00
|
|
|
toLyrics->setPlacement(placement);
|
2015-01-31 19:44:04 +01:00
|
|
|
toLyrics->setSyllabic(Lyrics::Syllabic::SINGLE);
|
2013-02-26 15:50:36 +01:00
|
|
|
newLyrics = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
_score->startCmd();
|
|
|
|
|
2015-01-31 19:44:04 +01:00
|
|
|
if (fromLyrics && !moveOnly) {
|
|
|
|
switch(toLyrics->syllabic()) {
|
|
|
|
// as we arrived at toLyrics by a [Space], it can be the beginning
|
|
|
|
// of a multi-syllable, but cannot have syllabic dashes before
|
2014-05-22 21:51:34 +02:00
|
|
|
case Lyrics::Syllabic::SINGLE:
|
|
|
|
case Lyrics::Syllabic::BEGIN:
|
2013-02-26 15:50:36 +01:00
|
|
|
break;
|
2014-05-22 21:51:34 +02:00
|
|
|
case Lyrics::Syllabic::END:
|
2015-01-31 19:44:04 +01:00
|
|
|
toLyrics->undoChangeProperty(P_ID::SYLLABIC, int(Lyrics::Syllabic::SINGLE));
|
2013-02-26 15:50:36 +01:00
|
|
|
break;
|
2014-05-22 21:51:34 +02:00
|
|
|
case Lyrics::Syllabic::MIDDLE:
|
2015-01-31 19:44:04 +01:00
|
|
|
toLyrics->undoChangeProperty(P_ID::SYLLABIC, int(Lyrics::Syllabic::BEGIN));
|
2013-02-26 15:50:36 +01:00
|
|
|
break;
|
|
|
|
}
|
2015-01-31 19:44:04 +01:00
|
|
|
// as we moved away from fromLyrics by a [Space], it can be
|
2015-01-16 02:18:56 +01:00
|
|
|
// the end of a multi-syllable, but cannot have syllabic dashes after
|
2015-01-31 19:44:04 +01:00
|
|
|
switch(fromLyrics->syllabic()) {
|
2014-05-22 21:51:34 +02:00
|
|
|
case Lyrics::Syllabic::SINGLE:
|
|
|
|
case Lyrics::Syllabic::END:
|
2013-02-26 15:50:36 +01:00
|
|
|
break;
|
2014-05-22 21:51:34 +02:00
|
|
|
case Lyrics::Syllabic::BEGIN:
|
2015-01-31 19:44:04 +01:00
|
|
|
fromLyrics->undoChangeProperty(P_ID::SYLLABIC, int(Lyrics::Syllabic::SINGLE));
|
2013-02-26 15:50:36 +01:00
|
|
|
break;
|
2014-05-22 21:51:34 +02:00
|
|
|
case Lyrics::Syllabic::MIDDLE:
|
2015-01-31 19:44:04 +01:00
|
|
|
fromLyrics->undoChangeProperty(P_ID::SYLLABIC, int(Lyrics::Syllabic::END));
|
2013-02-26 15:50:36 +01:00
|
|
|
break;
|
|
|
|
}
|
2015-01-16 02:18:56 +01:00
|
|
|
// for the same reason, it cannot have a melisma
|
2015-01-31 19:44:04 +01:00
|
|
|
fromLyrics->undoChangeProperty(P_ID::LYRIC_TICKS, 0);
|
2013-02-26 15:50:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (newLyrics)
|
2015-01-31 19:44:04 +01:00
|
|
|
_score->undoAddElement(toLyrics);
|
2013-02-26 15:50:36 +01:00
|
|
|
|
2015-01-31 19:44:04 +01:00
|
|
|
_score->select(toLyrics, SelectType::SINGLE, 0);
|
|
|
|
startEdit(toLyrics, Grip::NO_GRIP);
|
2013-02-26 15:50:36 +01:00
|
|
|
mscore->changeState(mscoreState());
|
|
|
|
|
2015-01-31 19:44:04 +01:00
|
|
|
adjustCanvasPosition(toLyrics, false);
|
2015-02-02 18:59:01 +01:00
|
|
|
if (end) {
|
2017-03-31 13:03:15 +02:00
|
|
|
((Lyrics*)editElement)->movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);
|
|
|
|
((Lyrics*)editElement)->movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
|
2015-02-02 18:59:01 +01:00
|
|
|
}
|
|
|
|
else {
|
2017-03-31 13:03:15 +02:00
|
|
|
((Lyrics*)editElement)->movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
|
|
|
|
((Lyrics*)editElement)->movePosition(QTextCursor::Start, QTextCursor::KeepAnchor);
|
2015-02-02 18:59:01 +01:00
|
|
|
}
|
2016-03-02 13:20:19 +01:00
|
|
|
_score->setLayoutAll();
|
2013-06-05 15:47:34 +02:00
|
|
|
_score->update();
|
2013-02-26 15:50:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// lyricsMinus
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ScoreView::lyricsMinus()
|
|
|
|
{
|
2017-03-31 13:03:15 +02:00
|
|
|
Lyrics* lyrics = toLyrics(editElement);
|
2013-02-26 15:50:36 +01:00
|
|
|
int track = lyrics->track();
|
|
|
|
Segment* segment = lyrics->segment();
|
|
|
|
int verse = lyrics->no();
|
2016-08-24 14:49:34 +02:00
|
|
|
Element::Placement placement = lyrics->placement();
|
2013-02-26 15:50:36 +01:00
|
|
|
|
|
|
|
endEdit();
|
|
|
|
|
|
|
|
// search next chord
|
|
|
|
Segment* nextSegment = segment;
|
2017-03-08 13:12:26 +01:00
|
|
|
while ((nextSegment = nextSegment->next1(SegmentType::ChordRest))) {
|
2013-02-26 15:50:36 +01:00
|
|
|
Element* el = nextSegment->element(track);
|
2017-01-18 14:16:33 +01:00
|
|
|
if (el && el->type() == ElementType::CHORD)
|
2013-02-26 15:50:36 +01:00
|
|
|
break;
|
|
|
|
}
|
2014-08-27 10:31:52 +02:00
|
|
|
if (nextSegment == 0)
|
2013-02-26 15:50:36 +01:00
|
|
|
return;
|
|
|
|
|
2015-01-31 19:44:04 +01:00
|
|
|
// look for the lyrics we are moving from; may be the current lyrics or a previous one
|
|
|
|
// we are extending with several dashes
|
|
|
|
Lyrics* fromLyrics = 0;
|
2013-02-26 15:50:36 +01:00
|
|
|
while (segment) {
|
2016-08-17 12:52:35 +02:00
|
|
|
ChordRest* cr = toChordRest(segment->element(track));
|
|
|
|
if (!cr) {
|
2017-03-08 13:12:26 +01:00
|
|
|
segment = segment->prev1(SegmentType::ChordRest);
|
2013-02-26 15:50:36 +01:00
|
|
|
continue;
|
|
|
|
}
|
2016-08-24 14:49:34 +02:00
|
|
|
fromLyrics = cr->lyrics(verse, placement);
|
2015-01-31 19:44:04 +01:00
|
|
|
if (fromLyrics)
|
2013-02-26 15:50:36 +01:00
|
|
|
break;
|
2017-03-08 13:12:26 +01:00
|
|
|
segment = segment->prev1(SegmentType::ChordRest);
|
2013-02-26 15:50:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
_score->startCmd();
|
|
|
|
|
2016-08-17 12:52:35 +02:00
|
|
|
ChordRest* cr = toChordRest(nextSegment->element(track));
|
2016-08-24 14:49:34 +02:00
|
|
|
Lyrics* toLyrics = cr->lyrics(verse, placement);
|
2015-01-31 19:44:04 +01:00
|
|
|
bool newLyrics = (toLyrics == 0);
|
|
|
|
if (!toLyrics) {
|
|
|
|
toLyrics = new Lyrics(_score);
|
|
|
|
toLyrics->setTrack(track);
|
|
|
|
toLyrics->setParent(nextSegment->element(track));
|
|
|
|
toLyrics->setNo(verse);
|
2016-08-24 14:49:34 +02:00
|
|
|
toLyrics->setPlacement(placement);
|
2015-01-31 19:44:04 +01:00
|
|
|
toLyrics->setSyllabic(Lyrics::Syllabic::END);
|
2013-02-26 15:50:36 +01:00
|
|
|
}
|
2014-08-27 10:31:52 +02:00
|
|
|
else {
|
2015-01-31 19:44:04 +01:00
|
|
|
// as we arrived at toLyrics by a dash, it cannot be initial or isolated
|
|
|
|
if (toLyrics->syllabic() == Lyrics::Syllabic::BEGIN)
|
|
|
|
toLyrics->undoChangeProperty(P_ID::SYLLABIC, int(Lyrics::Syllabic::MIDDLE));
|
|
|
|
else if (toLyrics->syllabic() == Lyrics::Syllabic::SINGLE)
|
|
|
|
toLyrics->undoChangeProperty(P_ID::SYLLABIC, int(Lyrics::Syllabic::END));
|
2013-02-26 15:50:36 +01:00
|
|
|
}
|
|
|
|
|
2015-01-31 19:44:04 +01:00
|
|
|
if (fromLyrics) {
|
|
|
|
// as we moved away from fromLyrics by a dash,
|
|
|
|
// it can have syll. dashes before and after but cannot be isolated or terminal
|
|
|
|
switch(fromLyrics->syllabic()) {
|
2014-05-22 21:51:34 +02:00
|
|
|
case Lyrics::Syllabic::BEGIN:
|
|
|
|
case Lyrics::Syllabic::MIDDLE:
|
2013-02-26 15:50:36 +01:00
|
|
|
break;
|
2014-05-22 21:51:34 +02:00
|
|
|
case Lyrics::Syllabic::SINGLE:
|
2015-01-31 19:44:04 +01:00
|
|
|
fromLyrics->undoChangeProperty(P_ID::SYLLABIC, int(Lyrics::Syllabic::BEGIN));
|
2013-02-26 15:50:36 +01:00
|
|
|
break;
|
2014-05-22 21:51:34 +02:00
|
|
|
case Lyrics::Syllabic::END:
|
2015-01-31 19:44:04 +01:00
|
|
|
fromLyrics->undoChangeProperty(P_ID::SYLLABIC, int(Lyrics::Syllabic::MIDDLE));
|
2013-02-26 15:50:36 +01:00
|
|
|
break;
|
|
|
|
}
|
2015-01-31 19:44:04 +01:00
|
|
|
// for the same reason, it cannot have a melisma
|
|
|
|
fromLyrics->undoChangeProperty(P_ID::LYRIC_TICKS, 0);
|
2013-02-26 15:50:36 +01:00
|
|
|
}
|
|
|
|
|
2014-08-27 10:31:52 +02:00
|
|
|
if (newLyrics)
|
2015-01-31 19:44:04 +01:00
|
|
|
_score->undoAddElement(toLyrics);
|
2013-02-26 15:50:36 +01:00
|
|
|
|
2015-01-31 19:44:04 +01:00
|
|
|
_score->select(toLyrics, SelectType::SINGLE, 0);
|
|
|
|
startEdit(toLyrics, Grip::NO_GRIP);
|
2013-02-26 15:50:36 +01:00
|
|
|
mscore->changeState(mscoreState());
|
|
|
|
|
2015-01-31 19:44:04 +01:00
|
|
|
adjustCanvasPosition(toLyrics, false);
|
2017-03-31 13:03:15 +02:00
|
|
|
((Lyrics*)editElement)->selectAll();
|
2013-02-26 15:50:36 +01:00
|
|
|
|
2016-03-02 13:20:19 +01:00
|
|
|
_score->setLayoutAll();
|
2013-06-05 15:47:34 +02:00
|
|
|
_score->update();
|
2013-02-26 15:50:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// lyricsUnderscore
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ScoreView::lyricsUnderscore()
|
|
|
|
{
|
2017-03-31 13:03:15 +02:00
|
|
|
Lyrics* lyrics = static_cast<Lyrics*>(editElement);
|
2013-02-26 15:50:36 +01:00
|
|
|
int track = lyrics->track();
|
|
|
|
Segment* segment = lyrics->segment();
|
|
|
|
int verse = lyrics->no();
|
2016-08-24 14:49:34 +02:00
|
|
|
Element::Placement placement = lyrics->placement();
|
2015-01-31 19:44:04 +01:00
|
|
|
int endTick = segment->tick(); // a previous melisma cannot extend beyond this point
|
2013-02-26 15:50:36 +01:00
|
|
|
|
|
|
|
endEdit();
|
|
|
|
|
|
|
|
// search next chord
|
|
|
|
Segment* nextSegment = segment;
|
2017-03-08 13:12:26 +01:00
|
|
|
while ((nextSegment = nextSegment->next1(SegmentType::ChordRest))) {
|
2013-02-26 15:50:36 +01:00
|
|
|
Element* el = nextSegment->element(track);
|
2017-01-18 14:16:33 +01:00
|
|
|
if (el && el->type() == ElementType::CHORD)
|
2013-02-26 15:50:36 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-01-31 19:44:04 +01:00
|
|
|
// look for the lyrics we are moving from; may be the current lyrics or a previous one
|
|
|
|
// we are extending with several underscores
|
|
|
|
Lyrics* fromLyrics = 0;
|
2013-02-26 15:50:36 +01:00
|
|
|
while (segment) {
|
2016-08-17 12:52:35 +02:00
|
|
|
ChordRest* cr = toChordRest(segment->element(track));
|
|
|
|
if (cr) {
|
2016-08-24 14:49:34 +02:00
|
|
|
fromLyrics = cr->lyrics(verse, placement);
|
2015-01-31 19:44:04 +01:00
|
|
|
if (fromLyrics)
|
2013-02-26 15:50:36 +01:00
|
|
|
break;
|
|
|
|
}
|
2017-03-08 13:12:26 +01:00
|
|
|
segment = segment->prev1(SegmentType::ChordRest);
|
2015-01-15 00:15:19 +01:00
|
|
|
// if the segment has a rest in this track, stop going back
|
2015-01-19 22:18:21 +01:00
|
|
|
Element* e = segment ? segment->element(track) : 0;
|
2017-01-18 14:16:33 +01:00
|
|
|
if (e && e->type() != ElementType::CHORD)
|
2015-01-15 00:15:19 +01:00
|
|
|
break;
|
2013-02-26 15:50:36 +01:00
|
|
|
}
|
|
|
|
|
2015-01-20 21:18:53 +01:00
|
|
|
_score->startCmd();
|
|
|
|
|
2015-01-15 00:01:18 +01:00
|
|
|
// one-chord melisma?
|
|
|
|
// if still at melisma initial chord and there is a valid next chord (if not,
|
|
|
|
// there will be no melisma anyway), set a temporary melisma duration
|
2015-01-31 19:44:04 +01:00
|
|
|
if (fromLyrics == lyrics && nextSegment)
|
2015-01-20 21:18:53 +01:00
|
|
|
lyrics->undoChangeProperty(P_ID::LYRIC_TICKS, Lyrics::TEMP_MELISMA_TICKS);
|
2015-01-15 00:01:18 +01:00
|
|
|
|
2013-02-26 15:50:36 +01:00
|
|
|
if (nextSegment == 0) {
|
2015-01-31 19:44:04 +01:00
|
|
|
if (fromLyrics) {
|
|
|
|
switch(fromLyrics->syllabic()) {
|
2014-05-22 21:51:34 +02:00
|
|
|
case Lyrics::Syllabic::SINGLE:
|
|
|
|
case Lyrics::Syllabic::END:
|
2013-02-26 15:50:36 +01:00
|
|
|
break;
|
|
|
|
default:
|
2015-01-31 19:44:04 +01:00
|
|
|
fromLyrics->undoChangeProperty(P_ID::SYLLABIC, int(Lyrics::Syllabic::END));
|
2013-02-26 15:50:36 +01:00
|
|
|
break;
|
|
|
|
}
|
2015-01-31 19:44:04 +01:00
|
|
|
if (fromLyrics->segment()->tick() < endTick)
|
|
|
|
fromLyrics->undoChangeProperty(P_ID::LYRIC_TICKS, endTick - fromLyrics->segment()->tick());
|
2013-02-26 15:50:36 +01:00
|
|
|
}
|
2015-01-14 13:51:26 +01:00
|
|
|
// leave edit mode, select something (just for user feedback) and update to show extended melisam
|
|
|
|
mscore->changeState(STATE_NORMAL);
|
2015-01-31 19:44:04 +01:00
|
|
|
if (fromLyrics)
|
|
|
|
_score->select(fromLyrics, SelectType::SINGLE, 0);
|
2015-01-20 21:18:53 +01:00
|
|
|
//_score->update();
|
2016-03-02 13:20:19 +01:00
|
|
|
_score->setLayoutAll();
|
2015-01-20 21:18:53 +01:00
|
|
|
_score->endCmd();
|
2013-02-26 15:50:36 +01:00
|
|
|
return;
|
|
|
|
}
|
2015-01-14 13:51:26 +01:00
|
|
|
|
|
|
|
// if a place for a new lyrics has been found, create a lyrics there
|
2013-02-26 15:50:36 +01:00
|
|
|
|
2016-08-24 14:49:34 +02:00
|
|
|
ChordRest* cr = toChordRest(nextSegment->element(track));
|
|
|
|
Lyrics* toLyrics = cr->lyrics(verse, placement);
|
|
|
|
bool newLyrics = (toLyrics == 0);
|
2015-01-31 19:44:04 +01:00
|
|
|
if (!toLyrics) {
|
|
|
|
toLyrics = new Lyrics(_score);
|
|
|
|
toLyrics->setTrack(track);
|
|
|
|
toLyrics->setParent(nextSegment->element(track));
|
|
|
|
toLyrics->setNo(verse);
|
2016-08-24 14:49:34 +02:00
|
|
|
toLyrics->setPlacement(placement);
|
2015-01-31 19:44:04 +01:00
|
|
|
toLyrics->setSyllabic(Lyrics::Syllabic::SINGLE);
|
2013-02-26 15:50:36 +01:00
|
|
|
}
|
2015-01-31 19:44:04 +01:00
|
|
|
// as we arrived at toLyrics by an underscore, it cannot have syllabic dashes before
|
|
|
|
else if (toLyrics->syllabic() == Lyrics::Syllabic::MIDDLE)
|
|
|
|
toLyrics->undoChangeProperty(P_ID::SYLLABIC, int(Lyrics::Syllabic::BEGIN));
|
|
|
|
else if (toLyrics->syllabic() == Lyrics::Syllabic::END)
|
|
|
|
toLyrics->undoChangeProperty(P_ID::SYLLABIC, int(Lyrics::Syllabic::SINGLE));
|
|
|
|
|
|
|
|
if (fromLyrics) {
|
|
|
|
// as we moved away from fromLyrics by an underscore,
|
|
|
|
// it can be isolated or terminal but cannot have dashes after
|
|
|
|
switch(fromLyrics->syllabic()) {
|
2014-05-22 21:51:34 +02:00
|
|
|
case Lyrics::Syllabic::SINGLE:
|
|
|
|
case Lyrics::Syllabic::END:
|
2013-02-26 15:50:36 +01:00
|
|
|
break;
|
|
|
|
default:
|
2015-01-31 19:44:04 +01:00
|
|
|
fromLyrics->undoChangeProperty(P_ID::SYLLABIC, int(Lyrics::Syllabic::END));
|
2013-02-26 15:50:36 +01:00
|
|
|
break;
|
|
|
|
}
|
2015-01-31 19:44:04 +01:00
|
|
|
// for the same reason, if it has a melisma, this cannot extend beyond toLyrics
|
|
|
|
if (fromLyrics->segment()->tick() < endTick)
|
|
|
|
fromLyrics->undoChangeProperty(P_ID::LYRIC_TICKS, endTick - fromLyrics->segment()->tick());
|
2013-02-26 15:50:36 +01:00
|
|
|
}
|
|
|
|
if (newLyrics)
|
2015-01-31 19:44:04 +01:00
|
|
|
_score->undoAddElement(toLyrics);
|
2013-02-26 15:50:36 +01:00
|
|
|
|
2015-01-31 19:44:04 +01:00
|
|
|
_score->select(toLyrics, SelectType::SINGLE, 0);
|
|
|
|
startEdit(toLyrics, Grip::NO_GRIP);
|
2013-02-26 15:50:36 +01:00
|
|
|
mscore->changeState(mscoreState());
|
|
|
|
|
2015-01-31 19:44:04 +01:00
|
|
|
adjustCanvasPosition(toLyrics, false);
|
2017-03-31 13:03:15 +02:00
|
|
|
((Lyrics*)editElement)->selectAll();
|
2013-02-26 15:50:36 +01:00
|
|
|
|
2016-03-02 13:20:19 +01:00
|
|
|
_score->setLayoutAll();
|
2015-01-20 21:18:53 +01:00
|
|
|
//_score->update();
|
|
|
|
_score->endCmd();
|
2013-02-26 15:50:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// lyricsReturn
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ScoreView::lyricsReturn()
|
|
|
|
{
|
2017-03-31 13:03:15 +02:00
|
|
|
Lyrics* lyrics = toLyrics(editElement);
|
2013-02-26 15:50:36 +01:00
|
|
|
Segment* segment = lyrics->segment();
|
|
|
|
|
|
|
|
endEdit();
|
|
|
|
|
|
|
|
_score->startCmd();
|
|
|
|
|
|
|
|
Lyrics* oldLyrics = lyrics;
|
|
|
|
|
2016-08-27 13:09:27 +02:00
|
|
|
int newVerse;
|
|
|
|
if (lyrics->placeAbove()) {
|
|
|
|
newVerse = oldLyrics->no() - 1;
|
|
|
|
if (newVerse == -1) {
|
|
|
|
// raise all lyrics above
|
|
|
|
newVerse = 0;
|
2017-03-08 13:12:26 +01:00
|
|
|
for (Segment* s = _score->firstSegment(SegmentType::ChordRest); s; s = s->next1(SegmentType::ChordRest)) {
|
2016-08-27 13:09:27 +02:00
|
|
|
ChordRest* cr = s->cr(lyrics->track());
|
|
|
|
if (cr) {
|
|
|
|
for (Lyrics* l : cr->lyrics()) {
|
|
|
|
if (l->placement() == oldLyrics->placement())
|
|
|
|
l->undoChangeProperty(P_ID::VERSE, l->no() + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
newVerse = oldLyrics->no() + 1;
|
2013-02-26 15:50:36 +01:00
|
|
|
lyrics = static_cast<Lyrics*>(Element::create(lyrics->type(), _score));
|
|
|
|
lyrics->setTrack(oldLyrics->track());
|
|
|
|
lyrics->setParent(segment->element(oldLyrics->track()));
|
2016-08-24 14:49:34 +02:00
|
|
|
lyrics->setPlacement(oldLyrics->placement());
|
|
|
|
|
2016-08-27 13:09:27 +02:00
|
|
|
lyrics->setNo(newVerse);
|
|
|
|
|
2013-02-26 15:50:36 +01:00
|
|
|
_score->undoAddElement(lyrics);
|
2014-05-27 10:34:08 +02:00
|
|
|
_score->select(lyrics, SelectType::SINGLE, 0);
|
2015-01-19 12:37:17 +01:00
|
|
|
startEdit(lyrics, Grip::NO_GRIP);
|
2013-02-26 15:50:36 +01:00
|
|
|
mscore->changeState(mscoreState());
|
|
|
|
|
|
|
|
adjustCanvasPosition(lyrics, false);
|
2016-03-02 13:20:19 +01:00
|
|
|
_score->setLayoutAll();
|
2013-06-05 15:47:34 +02:00
|
|
|
_score->update();
|
2013-02-26 15:50:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
// lyricsEndEdit
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
void ScoreView::lyricsEndEdit()
|
|
|
|
{
|
2017-03-31 13:03:15 +02:00
|
|
|
Lyrics* lyrics = toLyrics(editElement);
|
2013-02-26 15:50:36 +01:00
|
|
|
|
2015-01-31 19:44:04 +01:00
|
|
|
// if no text, just remove this lyrics
|
2016-02-06 22:03:43 +01:00
|
|
|
if (lyrics->empty())
|
2013-02-26 15:50:36 +01:00
|
|
|
lyrics->parent()->remove(lyrics);
|
2015-01-31 19:44:04 +01:00
|
|
|
// if not empty, make sure this new lyrics does not fall in the middle
|
|
|
|
// of an existing melisma from a previous lyrics; in case, shorten it
|
2013-02-26 15:50:36 +01:00
|
|
|
else {
|
2015-01-31 19:44:04 +01:00
|
|
|
int verse = lyrics->no();
|
2016-08-24 14:49:34 +02:00
|
|
|
Element::Placement placement = lyrics->placement();
|
2015-01-31 19:44:04 +01:00
|
|
|
int track = lyrics->track();
|
|
|
|
|
|
|
|
// search previous lyric
|
|
|
|
Lyrics* prevLyrics = 0;
|
2017-03-08 13:12:26 +01:00
|
|
|
Segment* prevSegment = lyrics->segment()->prev1(SegmentType::ChordRest);
|
2015-01-31 19:44:04 +01:00
|
|
|
Segment* segment = prevSegment;
|
|
|
|
while (segment) {
|
2016-08-17 12:52:35 +02:00
|
|
|
ChordRest* cr = toChordRest(segment->element(track));
|
|
|
|
if (cr) {
|
2016-08-24 14:49:34 +02:00
|
|
|
prevLyrics = cr->lyrics(verse, placement);
|
2015-01-31 19:44:04 +01:00
|
|
|
if (prevLyrics)
|
|
|
|
break;
|
|
|
|
}
|
2017-03-08 13:12:26 +01:00
|
|
|
segment = segment->prev1(SegmentType::ChordRest);
|
2015-01-31 19:44:04 +01:00
|
|
|
}
|
|
|
|
if (prevLyrics && prevLyrics->syllabic() == Lyrics::Syllabic::END) {
|
|
|
|
int endTick = prevSegment->tick(); // a prev. melisma should not go beyond this segment
|
|
|
|
if (prevLyrics->endTick() >= endTick)
|
|
|
|
prevLyrics->undoChangeProperty(P_ID::LYRIC_TICKS, endTick - prevLyrics->segment()->tick());
|
2013-02-26 15:50:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-13 18:49:17 +02:00
|
|
|
}
|
2013-02-26 15:50:36 +01:00
|
|
|
|