MuseScore/libmscore/line.cpp

1191 lines
50 KiB
C++
Raw Normal View History

2012-05-26 14:26:10 +02:00
//=============================================================================
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 2002-2012 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 "line.h"
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
#include "barline.h"
#include "chord.h"
#include "lyrics.h"
2012-05-26 14:26:10 +02:00
#include "measure.h"
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
#include "note.h"
#include "part.h"
2012-05-26 14:26:10 +02:00
#include "score.h"
#include "segment.h"
2014-08-21 04:01:14 +02:00
#include "staff.h"
#include "sym.h"
#include "system.h"
#include "textline.h"
2012-05-26 14:26:10 +02:00
#include "utils.h"
#include "xml.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
//---------------------------------------------------------
// LineSegment
//---------------------------------------------------------
LineSegment::LineSegment(const LineSegment& s)
: SpannerSegment(s)
{
}
2017-03-31 13:03:15 +02:00
//---------------------------------------------------------
// startEdit
//---------------------------------------------------------
void LineSegment::startEdit(EditData& ed)
{
ed.grips = 3;
ed.curGrip = Grip::END;
2017-07-26 09:59:24 +02:00
Element::startEdit(ed);
2017-03-31 13:03:15 +02:00
}
2012-07-04 13:04:54 +02:00
//---------------------------------------------------------
// readProperties
//---------------------------------------------------------
2013-01-11 18:10:18 +01:00
bool LineSegment::readProperties(XmlReader& e)
2012-07-04 13:04:54 +02:00
{
2013-01-11 18:10:18 +01:00
const QStringRef& tag(e.name());
2012-07-04 13:04:54 +02:00
if (tag == "subtype")
setSpannerSegmentType(SpannerSegmentType(e.readInt()));
else if (tag == "off2") {
2013-01-11 18:10:18 +01:00
setUserOff2(e.readPoint() * spatium());
}
2018-11-07 10:46:04 +01:00
/* else if (tag == "pos") {
setOffset(QPointF());
e.readNext();
2012-07-05 14:49:12 +02:00
}
2018-11-07 10:46:04 +01:00
*/
2013-08-29 11:08:09 +02:00
else if (!SpannerSegment::readProperties(e)) {
2013-01-11 18:10:18 +01:00
e.unknown();
2012-07-04 13:04:54 +02:00
return false;
}
return true;
}
//---------------------------------------------------------
// read
//---------------------------------------------------------
2013-01-11 18:10:18 +01:00
void LineSegment::read(XmlReader& e)
2012-07-04 13:04:54 +02:00
{
2013-01-11 18:10:18 +01:00
while (e.readNextStartElement())
readProperties(e);
2012-07-04 13:04:54 +02:00
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// updateGrips
//---------------------------------------------------------
2017-03-31 13:03:15 +02:00
void LineSegment::updateGrips(EditData& ed) const
2012-05-26 14:26:10 +02:00
{
QPointF pp(pagePos());
2017-03-31 13:03:15 +02:00
ed.grip[int(Grip::START)].translate(pp);
ed.grip[int(Grip::END)].translate(pos2() + pp);
ed.grip[int(Grip::MIDDLE)].translate(pos2() * .5 + pp);
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// gripAnchor
2013-08-30 12:46:15 +02:00
// return page coordinates
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
QPointF LineSegment::gripAnchor(Grip grip) const
2012-05-26 14:26:10 +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
// Middle or aperture grip have no anchor
if (!system() || grip == Grip::MIDDLE || grip == Grip::APERTURE)
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 QPointF(0, 0);
// note-anchored spanners are relative to the system
qreal y = spanner()->anchor() == Spanner::Anchor::NOTE ?
system()->pos().y() : system()->staffYpage(staffIdx());
if (isMiddleType()) {
2012-05-26 14:26:10 +02:00
qreal x;
2014-08-06 12:28:58 +02:00
switch (grip) {
case Grip::START:
2012-05-26 14:26:10 +02:00
x = system()->firstMeasure()->abbox().left();
break;
case Grip::END:
2012-05-26 14:26:10 +02:00
x = system()->lastMeasure()->abbox().right();
break;
default:
x = 0; // No Anchor
y = 0;
break;
}
return QPointF(x, y);
}
else {
if ((grip == Grip::END && isBeginType()) || (grip == Grip::START && isEndType()))
2012-05-26 14:26:10 +02:00
return QPointF(0, 0);
else {
System* s;
QPointF p(line()->linePos(grip, &s));
2014-07-09 18:05:58 +02:00
p.ry() += y - system()->pos().y();
2013-08-30 12:46:15 +02:00
if (s)
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
p += s->pos(); // to page coordinates
2013-08-30 12:46:15 +02:00
return p;
2012-05-26 14:26:10 +02:00
}
}
}
2017-03-31 13:03:15 +02:00
//---------------------------------------------------------
// startEditDrag
//---------------------------------------------------------
void LineSegment::startEditDrag(EditData& ed)
{
2017-07-26 09:59:24 +02:00
ElementEditData* eed = ed.getData(this);
eed->pushProperty(Pid::OFFSET);
eed->pushProperty(Pid::OFFSET2);
2017-03-31 13:03:15 +02:00
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// edit
// return true if event is accepted
//---------------------------------------------------------
2017-03-31 13:03:15 +02:00
bool LineSegment::edit(EditData& ed)
2012-05-26 14:26:10 +02:00
{
if (!((ed.modifiers & Qt::ShiftModifier) && (isSingleType() || (isBeginType() && ed.curGrip == Grip::START)
|| (isEndType() && ed.curGrip == Grip::END))))
2012-05-26 14:26:10 +02:00
return false;
LineSegment* ls = 0;
SpannerSegmentType st = spannerSegmentType(); // may change later
SLine* l = line();
int track = l->track();
int track2 = l->track2(); // assumed to be same as track
2012-05-26 14:26:10 +02:00
switch (l->anchor()) {
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
case Spanner::Anchor::SEGMENT:
{
Segment* s1 = spanner()->startSegment();
Segment* s2 = spanner()->endSegment();
// check for line going to end of score
if (spanner()->tick2() >= score()->lastSegment()->tick()) {
// endSegment calculated above will be the last chord/rest of score
// but that is not correct - it should be an imaginary note *after* the end of the score
// best we can do is set s2 to lastSegment (probably the end barline)
s2 = score()->lastSegment();
}
if (!s1 && !s2) {
qDebug("LineSegment::edit: no start/end segment");
return true;
}
2017-03-31 13:03:15 +02:00
if (ed.key == Qt::Key_Left) {
if (ed.curGrip == Grip::START)
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
s1 = prevSeg1(s1, track);
2017-03-31 13:03:15 +02:00
else if (ed.curGrip == Grip::END || ed.curGrip == Grip::MIDDLE)
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
s2 = prevSeg1(s2, track2);
}
2017-03-31 13:03:15 +02:00
else if (ed.key == Qt::Key_Right) {
if (ed.curGrip == Grip::START)
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
s1 = nextSeg1(s1, track);
2017-03-31 13:03:15 +02:00
else if (ed.curGrip == Grip::END || ed.curGrip == Grip::MIDDLE) {
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
Segment* ns2 = nextSeg1(s2, track2);
if (ns2)
s2 = ns2;
else
s2 = score()->lastSegment();
}
}
if (s1 == 0 || s2 == 0 || s1->tick() >= s2->tick())
return true;
2018-03-27 15:36:00 +02:00
spanner()->undoChangeProperty(Pid::SPANNER_TICK, s1->tick());
spanner()->undoChangeProperty(Pid::SPANNER_TICKS, s2->tick() - s1->tick());
2013-08-11 11:46:04 +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
break;
case Spanner::Anchor::NOTE:
{
Note* note1 = toNote(l->startElement());
Note* note2 = toNote(l->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
Note* oldNote1 = note1;
Note* oldNote2 = note2;
if (!note1 && !note2) {
qDebug("LineSegment::edit: no start/end note");
return true; // accept the event without doing anything
}
2017-03-31 13:03:15 +02:00
switch (ed.key) {
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
case Qt::Key_Left:
2017-03-31 13:03:15 +02:00
if (ed.curGrip == Grip::START)
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
note1 = prevChordNote(note1);
2017-03-31 13:03:15 +02:00
else if (ed.curGrip == Grip::END || ed.curGrip == Grip::MIDDLE)
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
note2 = prevChordNote(note2);
break;
case Qt::Key_Right:
2017-03-31 13:03:15 +02:00
if (ed.curGrip == Grip::START)
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
note1 = nextChordNote(note1);
2017-03-31 13:03:15 +02:00
else if (ed.curGrip == Grip::END || ed.curGrip == Grip::MIDDLE)
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
note2 = nextChordNote(note2);
break;
case Qt::Key_Up:
2017-03-31 13:03:15 +02:00
if (ed.curGrip == Grip::START)
note1 = toNote(score()->upAlt(note1));
else if (ed.curGrip == Grip::END || ed.curGrip == Grip::MIDDLE)
note2 = toNote(score()->upAlt(note2));
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
break;
case Qt::Key_Down:
2017-03-31 13:03:15 +02:00
if (ed.curGrip == Grip::START)
note1 = toNote(score()->downAlt(note1));
else if (ed.curGrip == Grip::END || ed.curGrip == Grip::MIDDLE)
note2 = toNote(score()->downAlt(note2));
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
break;
default:
return true;
}
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
// check prevChordNote() and nextchordNote() didn't return null
// OR Score::upAlt() and Score::downAlt() didn't return non-Note (notably rests)
// OR spanner duration is > 0
// OR note1 and note2 didn't end up in different instruments
// if this is the case, accepts the event and return without doing nothing
if (!note1 || !note2
|| !note1->isNote() || !note2->isNote()
|| note1->chord()->tick() >= note2->chord()->tick()
|| note1->chord()->staff()->part()->instrument(note1->chord()->tick())
!= note2->chord()->staff()->part()->instrument(note2->chord()->tick()) )
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 true;
if (note1 != oldNote1 || note2 != oldNote2)
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
spanner()->setNoteSpan(note1, note2); // set new spanner span
2012-05-26 14:26:10 +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
break;
case Spanner::Anchor::MEASURE:
case Spanner::Anchor::CHORD:
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
{
Measure* m1 = l->startMeasure();
Measure* m2 = l->endMeasure();
2012-05-26 14:26:10 +02:00
2017-03-31 13:03:15 +02:00
if (ed.key == Qt::Key_Left) {
if (ed.curGrip == Grip::START) {
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 (m1->prevMeasure())
m1 = m1->prevMeasure();
}
2017-03-31 13:03:15 +02:00
else if (ed.curGrip == Grip::END || ed.curGrip == Grip::MIDDLE) {
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
Measure* m = m2->prevMeasure();
if (m)
m2 = m;
}
2012-05-26 14:26:10 +02:00
}
2017-03-31 13:03:15 +02:00
else if (ed.key == Qt::Key_Right) {
if (ed.curGrip == Grip::START) {
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 (m1->nextMeasure())
m1 = m1->nextMeasure();
}
2017-03-31 13:03:15 +02:00
else if (ed.curGrip == Grip::END || ed.curGrip == Grip::MIDDLE) {
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 (m2->nextMeasure())
m2 = m2->nextMeasure();
}
2012-05-26 14:26:10 +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
if (m1->tick() > m2->tick())
return true;
if (l->startElement() != m1) {
2018-03-27 15:36:00 +02:00
spanner()->undoChangeProperty(Pid::SPANNER_TICK, m1->tick());
spanner()->undoChangeProperty(Pid::SPANNER_TICKS, m2->endTick() - m1->tick());
2012-05-26 14:26:10 +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
else if (l->endElement() != m2) {
2018-03-27 15:36:00 +02:00
spanner()->undoChangeProperty(Pid::SPANNER_TICKS, m2->endTick() - m1->tick());
2012-05-26 14:26:10 +02:00
}
}
}
triggerLayout();
l->layout(); // recompute segment list, segment type may change
2012-05-26 14:26:10 +02:00
LineSegment* nls = 0;
if (st == SpannerSegmentType::SINGLE) {
2017-03-31 13:03:15 +02:00
if (ed.curGrip == Grip::START)
2012-05-26 14:26:10 +02:00
nls = l->frontSegment();
2017-03-31 13:03:15 +02:00
else if (ed.curGrip == Grip::END)
2012-05-26 14:26:10 +02:00
nls = l->backSegment();
}
else if (st == SpannerSegmentType::BEGIN)
2012-05-26 14:26:10 +02:00
nls = l->frontSegment();
else if (st == SpannerSegmentType::END)
2012-05-26 14:26:10 +02:00
nls = l->backSegment();
else
qDebug("spannerSegmentType %d", int(spannerSegmentType()));
2012-05-26 14:26:10 +02:00
if (nls && (nls != this))
2017-03-31 13:03:15 +02:00
ed.view->changeEditElement(nls);
2012-05-26 14:26:10 +02:00
if (ls)
2016-03-10 10:41:31 +01:00
score()->undoRemoveElement(ls);
2014-07-09 18:05:58 +02:00
triggerLayout();
2012-05-26 14:26:10 +02:00
return true;
}
//---------------------------------------------------------
// editDrag
//---------------------------------------------------------
2017-03-31 13:03:15 +02:00
void LineSegment::editDrag(EditData& ed)
2012-05-26 14:26:10 +02:00
{
2012-09-15 17:12:15 +02:00
// Only for resizing according to the diagonal properties
2012-05-26 14:26:10 +02:00
QPointF deltaResize(ed.delta.x(), line()->diagonal() ? ed.delta.y() : 0.0);
2012-09-15 17:12:15 +02:00
switch (ed.curGrip) {
case Grip::START: // Resize the begin of element (left grip)
setOffset(offset() + deltaResize);
_offset2 -= deltaResize;
2012-05-26 14:26:10 +02:00
break;
case Grip::END: // Resize the end of element (right grip)
_offset2 += deltaResize;
2012-05-26 14:26:10 +02:00
break;
2017-06-13 17:23:11 +02:00
case Grip::MIDDLE: { // Move the element (middle grip)
// Only for moving, no y limitaion
QPointF deltaMove(ed.delta.x(), ed.delta.y());
setOffset(offset() + deltaMove);
2017-06-13 17:23:11 +02:00
}
2012-05-26 14:26:10 +02:00
break;
default:
break;
2012-05-26 14:26:10 +02:00
}
2017-07-26 09:59:24 +02:00
if (line()->anchor() == Spanner::Anchor::NOTE && ed.isStartEndGrip()) {
2012-09-15 17:12:15 +02:00
//
// if we touch a different note, change anchor
//
Element* e = ed.view->elementNear(ed.pos);
2017-06-13 17:23:11 +02:00
if (e && e->isNote()) {
2012-09-15 17:12:15 +02:00
SLine* l = line();
if (ed.curGrip == Grip::END && e != line()->endElement()) {
2012-09-15 17:12:15 +02:00
qDebug("LineSegment: move end anchor");
2017-06-13 17:23:11 +02:00
Note* noteOld = toNote(l->endElement());
Note* noteNew = toNote(e);
Note* sNote = toNote(l->startElement());
// do not change anchor if new note is before start note
if (sNote && sNote->chord() && noteNew->chord() && sNote->chord()->tick() < noteNew->chord()->tick()) {
noteOld->removeSpannerBack(l);
noteNew->addSpannerBack(l);
l->setEndElement(noteNew);
_offset2 += noteOld->canvasPos() - noteNew->canvasPos();
}
2012-09-15 17:12:15 +02:00
}
2017-07-26 09:59:24 +02:00
else if (ed.curGrip == Grip::START && e != l->startElement())
2012-09-15 17:12:15 +02:00
qDebug("LineSegment: move start anchor (not impl.)");
}
}
2016-07-20 12:45:34 +02:00
triggerLayout();
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// spatiumChanged
//---------------------------------------------------------
void LineSegment::spatiumChanged(qreal ov, qreal nv)
{
Element::spatiumChanged(ov, nv);
_offset2 *= nv / ov;
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// localSpatiumChanged
//---------------------------------------------------------
void LineSegment::localSpatiumChanged(qreal ov, qreal nv)
{
Element::localSpatiumChanged(ov, nv);
_offset2 *= nv / ov;
}
//---------------------------------------------------------
// propertyDelegate
//---------------------------------------------------------
Element* LineSegment::propertyDelegate(Pid pid)
{
if (pid == Pid::DIAGONAL
|| pid == Pid::LINE_COLOR
|| pid == Pid::LINE_WIDTH
|| pid == Pid::LINE_STYLE
|| pid == Pid::DASH_LINE_LEN
|| pid == Pid::DASH_GAP_LEN)
return spanner();
return SpannerSegment::propertyDelegate(pid);
}
2014-08-06 12:28:58 +02:00
//---------------------------------------------------------
// dragAnchor
//---------------------------------------------------------
QLineF LineSegment::dragAnchor() const
{
if (spannerSegmentType() != SpannerSegmentType::SINGLE && spannerSegmentType() != SpannerSegmentType::BEGIN)
return QLineF();
System* s;
QPointF p = line()->linePos(Grip::START, &s);
p += QPointF(s->canvasPos().x(), s->staffCanvasYpage(line()->staffIdx()));
2014-08-06 12:28:58 +02:00
return QLineF(p, canvasPos());
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// SLine
//---------------------------------------------------------
2018-03-22 09:51:50 +01:00
SLine::SLine(Score* s, ElementFlags f)
: Spanner(s, f)
2012-05-26 14:26:10 +02:00
{
setTrack(0);
2018-05-07 19:05:34 +02:00
_lineWidth = 0.15 * spatium();
2012-05-26 14:26:10 +02:00
}
SLine::SLine(const SLine& s)
: Spanner(s)
{
2016-06-30 20:22:36 +02:00
_diagonal = s._diagonal;
_lineWidth = s._lineWidth;
_lineColor = s._lineColor;
_lineStyle = s._lineStyle;
_dashLineLen = s._dashLineLen;
_dashGapLen = s._dashGapLen;
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// linePos
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
// Anchor::NOTE: return anchor note position in system coordinates
// Other: return (x position (relative to what?), 0)
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
QPointF SLine::linePos(Grip grip, System** sys) const
2012-05-26 14:26:10 +02:00
{
2012-07-27 18:01:15 +02:00
qreal x = 0.0;
2016-12-23 12:05:18 +01:00
qreal sp = staff()->spatium(tick());
2013-08-11 11:46:04 +02:00
switch (anchor()) {
2014-05-26 20:48:27 +02:00
case Spanner::Anchor::SEGMENT:
2012-09-12 16:19:03 +02:00
{
2014-07-31 13:33:50 +02:00
ChordRest* cr;
if (grip == Grip::START) {
2017-12-20 16:49:30 +01:00
cr = toChordRest(startElement());
2017-01-18 14:16:33 +01:00
if (cr && type() == ElementType::OTTAVA) {
// some sources say to center the text over the notehead
// others say to start the text just to left of notehead
// some say to include accidental, others don't
// our compromise - left align, but account for accidental
if (cr->durationType() == TDuration::DurationType::V_MEASURE && !cr->measure()->hasVoices(cr->staffIdx()))
x = cr->x(); // center for measure rests
2016-01-04 14:48:58 +01:00
//TODO else if (cr->spaceLw > 0.0)
// x = -cr->spaceLw; // account for accidentals, etc
}
2014-08-22 20:59:05 +02:00
}
2014-07-31 13:33:50 +02:00
else {
2017-12-20 16:49:30 +01:00
cr = toChordRest(endElement());
2018-06-29 13:33:47 +02:00
if (isOttava()) {
if (cr && cr->durationType() == TDuration::DurationType::V_MEASURE) {
x = cr->x() + cr->width() + sp;
}
else if (cr) {
// lay out just past right edge of all notes for this segment on this staff
2016-02-06 11:41:16 +01:00
Segment* s = cr->segment();
2018-09-26 18:44:31 +02:00
int startTrack = staffIdx() * VOICES;
int endTrack = startTrack + VOICES;
qreal width = 0.0;
// dont consider full measure rests, which are centered
2018-09-26 18:44:31 +02:00
// (TODO: what if there is only a full measure rest?)
for (int track = startTrack; track < endTrack; ++track) {
ChordRest* cr1 = toChordRest(s->element(track));
if (!cr1)
2018-09-26 18:44:31 +02:00
continue;
if (cr1->isChord()) {
for (Note* n : toChord(cr1)->notes())
width = qMax(width, n->shape().right() + n->pos().x() + cr1->pos().x());
2018-09-26 18:44:31 +02:00
}
else if (cr1->isRest() && (cr1->actualDurationType() != TDuration::DurationType::V_MEASURE))
width = qMax(width, cr1->bbox().right() + cr1->pos().x());
2018-09-26 18:44:31 +02:00
}
x = width + sp;
2016-02-06 11:41:16 +01:00
// extend past chord/rest
// but don't overlap next chord/rest
2016-02-06 11:41:16 +01:00
bool crFound = false;
2016-02-06 11:41:16 +01:00
int n = staffIdx() * VOICES;
Segment* ns = s->next();
while (ns) {
for (int i = 0; i < VOICES; ++i) {
if (ns->element(n + i)) {
crFound = true;
break;
}
}
if (crFound)
break;
ns = ns->next();
}
if (crFound) {
2018-05-07 19:05:34 +02:00
qreal nextNoteDistance = ns->x() - s->x() + lineWidth();
if (x > nextNoteDistance)
x = qMax(width, nextNoteDistance);
}
}
2014-08-21 04:01:14 +02:00
}
2017-12-20 16:49:30 +01:00
else if (isLyricsLine() && toLyrics(parent())->ticks() > 0) {
// melisma line
2015-01-14 00:50:47 +01:00
// it is possible CR won't be in correct track
// prefer element in current track if available
if (!cr)
qDebug("no end for lyricsline segment - start %d, ticks %d", tick(), ticks());
else if (cr->track() != track()) {
2015-01-14 00:50:47 +01:00
Element* e = cr->segment()->element(track());
if (e)
2017-12-20 16:49:30 +01:00
cr = toChordRest(e);
2015-01-14 00:50:47 +01:00
}
2015-01-12 21:03:03 +01:00
// layout to right edge of CR
bool extendToEnd = true; // extend to end or start element?
if (cr == toChordRest(startElement()))
extendToEnd = false;
else if (cr) {
// if next segment is a chord with lyrics which spans to the left
// then do not extend to the right edge of end element.
2018-07-02 10:24:58 +02:00
Segment* seg = cr->segment();
seg = seg->next(SegmentType::ChordRest);
if (seg) {
ChordRest* cr2 = seg->cr(cr->track());
if (cr2 && !cr2->lyrics().empty())
extendToEnd = false;
2015-01-14 00:50:47 +01:00
}
}
ChordRest* right = extendToEnd ? cr : toChordRest(startElement());
if (right) {
qreal maxRight = 0.0;
if (right->isChord()) {
// chord bbox() is unreliable, look at notes
// this also allows us to more easily ignore ledger lines
for (Note* n : toChord(right)->notes())
maxRight = qMax(maxRight, right->x() + n->x() + n->bboxRightPos());
}
else {
// rest - won't normally happen
maxRight = right->x() + right->width();
2015-01-14 00:50:47 +01:00
}
x = maxRight;
2015-01-14 00:50:47 +01:00
}
}
2018-06-29 13:33:47 +02:00
else if (isHairpin() || isTrill() || isVibrato() || isTextLine() || isLyricsLine()) {
// (for LYRICSLINE, this is hyphen; melisma line is handled above)
// lay out to just before next chordrest on this staff, or barline
// tick2 actually tells us the right chordrest to look for
2017-01-18 14:16:33 +01:00
if (cr && endElement()->parent() && endElement()->parent()->type() == ElementType::SEGMENT) {
2016-01-04 14:48:58 +01:00
qreal x2 = cr->x() /* TODO + cr->space().rw() */;
2017-12-20 16:49:30 +01:00
Segment* currentSeg = toSegment(endElement()->parent());
2017-03-08 13:12:26 +01:00
Segment* seg = score()->tick2segmentMM(tick2(), false, SegmentType::ChordRest);
2014-08-21 04:01:14 +02:00
if (!seg) {
// no end segment found, use measure width
x2 = endElement()->parent()->parent()->width() - sp;
}
else if (currentSeg->measure() == seg->measure()) {
// next chordrest found in same measure;
// end line 1sp to left
x2 = qMax(x2, seg->x() - sp);
}
else {
// next chordrest is in next measure
// lay out to end (barline) of current measure instead
2017-03-08 13:12:26 +01:00
seg = currentSeg->next(SegmentType::EndBarLine);
if (!seg)
seg = currentSeg->measure()->last();
// allow lyrics hyphen to extend to barline
// other lines stop 1sp short
2017-01-18 14:16:33 +01:00
qreal gap = (type() == ElementType::LYRICSLINE) ? 0.0 : sp;
x2 = qMax(x2, seg->x() - gap);
}
x = x2 - endElement()->parent()->x();
2014-08-21 04:01:14 +02:00
}
}
2014-07-31 13:33:50 +02:00
}
int t = grip == Grip::START ? tick() : tick2();
2014-07-31 13:33:50 +02:00
Measure* m = cr ? cr->measure() : score()->tick2measure(t);
if (m) {
x += cr ? cr->segment()->pos().x() + m->pos().x() : m->tick2pos(t);
2014-07-31 13:33:50 +02:00
*sys = m->system();
}
else
2014-07-27 16:11:59 +02:00
*sys = 0;
2012-05-26 14:26:10 +02:00
}
2012-09-12 16:19:03 +02:00
break;
2014-05-26 20:48:27 +02:00
case Spanner::Anchor::MEASURE:
2012-09-12 16:19:03 +02:00
{
2014-05-26 20:48:27 +02:00
// anchor() == Anchor::MEASURE
const Measure* m;
if (grip == Grip::START) {
m = startMeasure();
// start after clef/key
qreal offset = 0.0;
2017-03-08 13:12:26 +01:00
Segment* s = m->first(SegmentType::ChordRest);
if (s) {
s = s->prev();
if (s) {
offset = s->x();
Element* e = s->element(staffIdx() * VOICES);
if (e)
offset += e->width();
}
}
x = m->pos().x() + offset;
2018-03-27 15:36:00 +02:00
if (score()->styleB(Sid::createMultiMeasureRests) && m->hasMMRest()) {
x = m->mmRest()->pos().x();
}
2012-09-12 16:19:03 +02:00
}
else {
2014-07-31 13:33:50 +02:00
qreal _spatium = spatium();
2018-03-27 15:36:00 +02:00
if (score()->styleB(Sid::createMultiMeasureRests)) {
// find the actual measure where the volta should stop
m = startMeasure();
if (m->hasMMRest())
m = m->mmRest();
while (m->nextMeasureMM() && (m->endTick() < tick2()))
m = m->nextMeasureMM();
}
else {
m = endMeasure();
}
// back up to barline (skip courtesy elements)
Segment* seg = m->last();
2017-03-08 13:12:26 +01:00
while (seg && seg->segmentType() != SegmentType::EndBarLine)
seg = seg->prev();
if (!seg || !seg->enabled()) {
// no end bar line; look for BeginBarLine of next measure
Measure* nm = m->nextMeasure();
if (nm->system() == m->system())
seg = nm->first(SegmentType::BeginBarLine);
}
qreal mwidth = seg ? seg->x() : m->bbox().right();
x = m->pos().x() + mwidth;
// align to barline
if (seg && seg->isEndBarLineType()) {
Element* e = seg->element(0);
2017-01-18 14:16:33 +01:00
if (e && e->type() == ElementType::BAR_LINE) {
2017-12-20 16:49:30 +01:00
BarLineType blt = toBarLine(e)->barLineType();
switch (blt) {
case BarLineType::END_REPEAT:
// skip dots
x += symWidth(SymId::repeatDot);
2018-03-27 15:36:00 +02:00
x += score()->styleS(Sid::endBarDistance).val() * _spatium;
// fall through
case BarLineType::DOUBLE:
// center on leftmost (thinner) barline
2018-03-27 15:36:00 +02:00
x += score()->styleS(Sid::doubleBarWidth).val() * _spatium * 0.5;
break;
case BarLineType::START_REPEAT:
// center on leftmost (thicker) barline
2018-03-27 15:36:00 +02:00
x += score()->styleS(Sid::endBarWidth).val() * _spatium * 0.5;
break;
default:
// center on barline
2018-03-27 15:36:00 +02:00
x += score()->styleS(Sid::barWidth).val() * _spatium * 0.5;
break;
}
2012-05-26 14:26:10 +02:00
}
}
}
2018-03-27 15:36:00 +02:00
if (score()->styleB(Sid::createMultiMeasureRests))
2014-04-24 17:09:42 +02:00
m = m->mmRest1();
2013-01-23 16:43:22 +01:00
Q_ASSERT(m->system());
2012-09-12 16:19:03 +02:00
*sys = m->system();
2012-05-26 14:26:10 +02:00
}
2012-09-12 16:19:03 +02:00
break;
case Spanner::Anchor::NOTE: {
2015-01-28 23:42:04 +01:00
Element* e = grip == Grip::START ? startElement() : endElement();
if (!e)
return QPointF();
System* s = toNote(e)->chord()->segment()->system();
2017-12-06 15:06:32 +01:00
if (s == 0) {
qDebug("no system: %s start %s chord parent %s\n", name(), e->name(), toNote(e)->chord()->parent()->name());
return QPointF();
2017-12-06 15:06:32 +01:00
}
2012-09-12 16:19:03 +02:00
*sys = s;
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 the position of the anchor note relative to the system
// QPointF elemPagePos = e->pagePos(); // DEBUG
// QPointF systPagePos = s->pagePos();
// qreal staffYPage = s->staffYpage(e->staffIdx());
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 e->pagePos() - s->pagePos();
2012-09-12 16:19:03 +02:00
}
2014-05-26 20:48:27 +02:00
case Spanner::Anchor::CHORD:
qFatal("Sline::linePos(): anchor not implemented");
2012-09-12 16:19:03 +02:00
break;
2012-05-26 14:26:10 +02:00
}
2014-07-09 18:05:58 +02:00
return QPointF(x, 0.0);
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// layoutSystem
// layout spannersegment for system
//---------------------------------------------------------
2016-07-10 12:00:57 +02:00
SpannerSegment* SLine::layoutSystem(System* system)
{
int stick = system->firstMeasure()->tick();
int etick = system->lastMeasure()->endTick();
LineSegment* lineSegm = toLineSegment(getNextLayoutSystemSegment(system, [this]() { return createLineSegment(); }));
SpannerSegmentType sst;
if (tick() >= stick) {
//
// this is the first call to layoutSystem,
// processing the first line segment
//
computeStartElement();
computeEndElement();
sst = tick2() <= etick ? SpannerSegmentType::SINGLE : SpannerSegmentType::BEGIN;
}
else if (tick() < stick && tick2() > etick) {
sst = SpannerSegmentType::MIDDLE;
}
else {
//
// this is the last call to layoutSystem
// processing the last line segment
//
sst = SpannerSegmentType::END;
}
lineSegm->setSpannerSegmentType(sst);
switch (sst) {
case SpannerSegmentType::SINGLE: {
System* s;
QPointF p1 = linePos(Grip::START, &s);
QPointF p2 = linePos(Grip::END, &s);
qreal len = p2.x() - p1.x();
lineSegm->setPos(p1);
lineSegm->setPos2(QPointF(len, p2.y() - p1.y()));
}
break;
case SpannerSegmentType::BEGIN: {
System* s;
QPointF p1 = linePos(Grip::START, &s);
lineSegm->setPos(p1);
qreal x2 = system->bbox().right();
lineSegm->setPos2(QPointF(x2 - p1.x(), 0.0));
}
break;
case SpannerSegmentType::MIDDLE: {
Measure* firstMeasure = system->firstMeasure();
2017-03-08 13:12:26 +01:00
Segment* firstCRSeg = firstMeasure->first(SegmentType::ChordRest);
qreal x1 = (firstCRSeg ? firstCRSeg->pos().x() : 0) + firstMeasure->pos().x();
qreal x2 = system->bbox().right();
System* s;
QPointF p1 = linePos(Grip::START, &s);
lineSegm->setPos(QPointF(x1, p1.y()));
lineSegm->setPos2(QPointF(x2 - x1, 0.0));
}
break;
case SpannerSegmentType::END: {
qreal offset = 0.0;
System* s;
QPointF p2 = linePos(Grip::END, &s);
Measure* firstMeas = system->firstMeasure();
2017-03-08 13:12:26 +01:00
Segment* firstCRSeg = firstMeas->first(SegmentType::ChordRest);
if (anchor() == Anchor::SEGMENT || anchor() == Anchor::MEASURE) {
// start line just after previous element (eg, key signature)
firstCRSeg = firstCRSeg->prev();
Element* e = firstCRSeg ? firstCRSeg->element(staffIdx() * VOICES) : nullptr;
if (e)
offset = e->width();
}
qreal x1 = (firstCRSeg ? firstCRSeg->pos().x() : 0) + firstMeas->pos().x() + offset;
qreal len = p2.x() - x1;
lineSegm->setPos(QPointF(p2.x() - len, p2.y()));
lineSegm->setPos2(QPointF(len, 0.0));
}
break;
}
lineSegm->layout();
2016-07-10 12:00:57 +02:00
return lineSegm;
}
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
// layout
// compute segments from tick1 tick2
// (obsolete)
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
void SLine::layout()
{
2014-08-18 15:58:35 +02:00
if (score() == gscore || tick() == -1 || tick2() == 1) {
2012-05-26 14:26:10 +02:00
//
2014-08-18 15:58:35 +02:00
// when used in a palette or while dragging from palette,
// SLine has no parent and
2012-05-26 14:26:10 +02:00
// tick and tick2 has no meaning so no layout is
// possible and needed
//
2016-10-29 12:32:58 +02:00
setLen(gscore->spatium() * 7);
2016-02-06 22:03:43 +01:00
if (!spannerSegments().empty()) {
LineSegment* lineSegm = frontSegment();
lineSegm->layout();
setbbox(lineSegm->bbox());
2012-05-26 14:26:10 +02:00
}
return;
}
2012-09-15 17:12:15 +02:00
2013-06-19 18:20:09 +02:00
computeStartElement();
computeEndElement();
2012-05-26 14:26:10 +02:00
System* s1;
System* s2;
QPointF p1(linePos(Grip::START, &s1));
QPointF p2(linePos(Grip::END, &s2));
2012-05-26 14:26:10 +02:00
2016-02-04 11:27:47 +01:00
const QList<System*>& systems = score()->systems();
int sysIdx1 = systems.indexOf(s1);
int sysIdx2 = systems.indexOf(s2);
2012-05-26 14:26:10 +02:00
int segmentsNeeded = 0;
if (sysIdx1 == -1 || sysIdx2 == -1)
return;
2017-06-02 10:27:32 +02:00
for (int i = sysIdx1; i <= sysIdx2; ++i) {
2016-03-02 13:20:19 +01:00
if (systems.at(i)->vbox())
continue;
++segmentsNeeded;
2012-05-26 14:26:10 +02:00
}
2013-07-04 13:40:25 +02:00
int segCount = int(spannerSegments().size());
2012-05-26 14:26:10 +02:00
if (segmentsNeeded != segCount) {
fixupSegments(segmentsNeeded, [this]() { return createLineSegment(); });
2012-05-26 14:26:10 +02:00
if (segmentsNeeded > segCount) {
for (int i = segCount; i < segmentsNeeded; ++i) {
LineSegment* lineSegm = segmentAt(i);
2012-05-26 14:26:10 +02:00
// set user offset to previous segment's offset
if (segCount > 0)
lineSegm->setOffset(QPointF(0, segmentAt(i-1)->offset().y()));
else
lineSegm->setOffset(QPointF(0, offset().y()));
2012-05-26 14:26:10 +02:00
}
}
}
int segIdx = 0;
for (int i = sysIdx1; i <= sysIdx2; ++i) {
2016-02-04 11:27:47 +01:00
System* system = systems.at(i);
2016-03-02 13:20:19 +01:00
if (system->vbox())
2012-05-26 14:26:10 +02:00
continue;
LineSegment* lineSegm = segmentAt(segIdx++);
lineSegm->setTrack(track()); // DEBUG
lineSegm->setSystem(system);
2012-05-26 14:26:10 +02:00
Measure* firstMeas = system->firstMeasure();
2017-03-08 13:12:26 +01:00
Segment* firstCRSeg = firstMeas->first(SegmentType::ChordRest);
2012-05-26 14:26:10 +02:00
if (sysIdx1 == sysIdx2) {
// single segment
lineSegm->setSpannerSegmentType(SpannerSegmentType::SINGLE);
qreal len = p2.x() - p1.x();
// enforcing a minimum length would be possible but inadvisable
// the line length calculations are tuned well enough that this should not be needed
2017-01-18 14:16:33 +01:00
//if (anchor() == Anchor::SEGMENT && type() != ElementType::PEDAL)
// len = qMax(1.0 * spatium(), len);
lineSegm->setPos(p1);
lineSegm->setPos2(QPointF(len, p2.y() - p1.y()));
2012-05-26 14:26:10 +02:00
}
else if (i == sysIdx1) {
// start segment
lineSegm->setSpannerSegmentType(SpannerSegmentType::BEGIN);
lineSegm->setPos(p1);
qreal x2 = system->bbox().right();
lineSegm->setPos2(QPointF(x2 - p1.x(), 0.0));
2012-05-26 14:26:10 +02:00
}
else if (i > 0 && i != sysIdx2) {
// middle segment
lineSegm->setSpannerSegmentType(SpannerSegmentType::MIDDLE);
qreal x1 = (firstCRSeg ? firstCRSeg->pos().x() : 0) + firstMeas->pos().x();
qreal x2 = system->bbox().right();
lineSegm->setPos(QPointF(x1, p1.y()));
lineSegm->setPos2(QPointF(x2 - x1, 0.0));
2012-05-26 14:26:10 +02:00
}
else if (i == sysIdx2) {
// end segment
qreal offset = 0.0;
qreal minLen = 0.0;
if (anchor() == Anchor::SEGMENT || anchor() == Anchor::MEASURE) {
// start line just after previous element (eg, key signature)
firstCRSeg = firstCRSeg->prev();
Element* e = firstCRSeg ? firstCRSeg->element(staffIdx() * VOICES) : nullptr;
if (e)
offset = e->width();
// enforcing a minimum length would be possible but inadvisable
// the line length calculations are tuned well enough that this should not be needed
2017-01-18 14:16:33 +01:00
//if (type() != ElementType::PEDAL)
// minLen = 1.0 * spatium();
}
qreal x1 = (firstCRSeg ? firstCRSeg->pos().x() : 0) + firstMeas->pos().x() + offset;
qreal len = qMax(minLen, p2.x() - x1);
lineSegm->setSpannerSegmentType(SpannerSegmentType::END);
lineSegm->setPos(QPointF(p2.x() - len, p2.y()));
lineSegm->setPos2(QPointF(len, 0.0));
2012-05-26 14:26:10 +02:00
}
lineSegm->layout();
2012-05-26 14:26:10 +02:00
}
}
//---------------------------------------------------------
// writeProperties
// write properties different from prototype
//---------------------------------------------------------
2016-11-19 11:51:21 +01:00
void SLine::writeProperties(XmlWriter& xml) const
2012-05-26 14:26:10 +02:00
{
2018-01-11 11:39:14 +01:00
if (!endElement()) {
((Spanner*)this)->computeEndElement(); // HACK
if (!endElement())
xml.tag("ticks", ticks());
}
2014-08-13 15:42:40 +02:00
Spanner::writeProperties(xml);
2013-08-09 11:42:24 +02:00
if (_diagonal)
2012-05-26 14:26:10 +02:00
xml.tag("diagonal", _diagonal);
2018-03-27 15:36:00 +02:00
writeProperty(xml, Pid::LINE_WIDTH);
writeProperty(xml, Pid::LINE_STYLE);
writeProperty(xml, Pid::LINE_COLOR);
writeProperty(xml, Pid::ANCHOR);
writeProperty(xml, Pid::DASH_LINE_LEN);
writeProperty(xml, Pid::DASH_GAP_LEN);
2012-05-26 14:26:10 +02:00
if (score() == gscore) {
// when used as icon
2016-02-06 22:03:43 +01:00
if (!spannerSegments().empty()) {
const LineSegment* s = frontSegment();
2012-05-26 14:26:10 +02:00
xml.tag("length", s->pos2().x());
}
else
xml.tag("length", spatium() * 4);
return;
}
//
// check if user has modified the default layout
//
bool modified = false;
for (const SpannerSegment* seg : spannerSegments()) {
if (!seg->autoplace() || !seg->visible() || (!seg->isStyled(Pid::OFFSET) && !seg->offset().isNull())) {
2012-05-26 14:26:10 +02:00
modified = true;
break;
}
}
if (!modified)
return;
//
// write user modified layout
//
qreal _spatium = spatium();
for (const SpannerSegment* seg : spannerSegments()) {
xml.stag("Segment", seg);
xml.tag("subtype", int(seg->spannerSegmentType()));
xml.tag("offset", seg->offset() / _spatium);
2012-05-26 14:26:10 +02:00
xml.tag("off2", seg->userOff2() / _spatium);
seg->Element::writeProperties(xml);
xml.etag();
}
}
//---------------------------------------------------------
// readProperties
//---------------------------------------------------------
2013-01-11 18:10:18 +01:00
bool SLine::readProperties(XmlReader& e)
2012-05-26 14:26:10 +02:00
{
2013-01-11 18:10:18 +01:00
const QStringRef& tag(e.name());
2012-05-26 14:26:10 +02:00
if (tag == "tick2") { // obsolete
if (tick() == -1) // not necessarily set (for first note of score?) #30151
setTick(e.tick());
setTick2(e.readInt());
}
else if (tag == "tick") // obsolete
setTick(e.readInt());
2014-08-13 15:42:40 +02:00
else if (tag == "ticks")
setTicks(e.readInt());
2012-05-26 14:26:10 +02:00
else if (tag == "Segment") {
LineSegment* ls = createLineSegment();
ls->setTrack(track()); // needed in read to get the right staff mag
2012-07-04 13:04:54 +02:00
ls->read(e);
2012-05-26 14:26:10 +02:00
add(ls);
ls->setVisible(visible());
2012-05-26 14:26:10 +02:00
}
else if (tag == "length")
2013-01-11 18:10:18 +01:00
setLen(e.readDouble());
2012-05-26 14:26:10 +02:00
else if (tag == "diagonal")
2013-01-11 18:10:18 +01:00
setDiagonal(e.readInt());
2012-05-26 14:26:10 +02:00
else if (tag == "anchor")
2013-01-11 18:10:18 +01:00
setAnchor(Anchor(e.readInt()));
else if (tag == "lineWidth")
2018-05-07 19:05:34 +02:00
_lineWidth = e.readDouble() * spatium();
else if (tag == "lineStyle")
_lineStyle = Qt::PenStyle(e.readInt());
2016-06-30 20:22:36 +02:00
else if (tag == "dashLineLength")
_dashLineLen = e.readDouble();
else if (tag == "dashGapLength")
_dashGapLen = e.readDouble();
else if (tag == "lineColor")
_lineColor = e.readColor();
else if (!Element::readProperties(e))
2012-05-26 14:26:10 +02:00
return false;
return true;
}
//---------------------------------------------------------
// setLen
// used to create an element suitable for palette
//---------------------------------------------------------
void SLine::setLen(qreal l)
{
2016-02-06 22:03:43 +01:00
if (spannerSegments().empty())
2012-05-26 14:26:10 +02:00
add(createLineSegment());
LineSegment* s = frontSegment();
s->setPos(QPointF());
s->setPos2(QPointF(l, 0));
}
//---------------------------------------------------------
// bbox
// used by palette: only one segment
//---------------------------------------------------------
2012-07-24 14:20:43 +02:00
const QRectF& SLine::bbox() const
2012-05-26 14:26:10 +02:00
{
2016-02-06 22:03:43 +01:00
if (spannerSegments().empty())
2012-07-24 14:20:43 +02:00
setbbox(QRectF());
2012-05-26 14:26:10 +02:00
else
2012-07-24 14:20:43 +02:00
setbbox(segmentAt(0)->bbox());
return Element::bbox();
2012-05-26 14:26:10 +02:00
}
//---------------------------------------------------------
// write
//---------------------------------------------------------
2016-11-19 11:51:21 +01:00
void SLine::write(XmlWriter& xml) const
2012-05-26 14:26:10 +02:00
{
xml.stag(this);
2012-05-26 14:26:10 +02:00
SLine::writeProperties(xml);
xml.etag();
}
//---------------------------------------------------------
// read
//---------------------------------------------------------
2013-01-11 18:10:18 +01:00
void SLine::read(XmlReader& e)
2012-05-26 14:26:10 +02:00
{
eraseSpannerSegments();
2012-05-26 14:26:10 +02:00
2018-08-27 22:57:15 +02:00
if (score()->mscVersion() < 301)
e.addSpanner(e.intAttribute("id", -1), this);
2013-01-11 18:10:18 +01:00
while (e.readNextStartElement()) {
2012-05-26 14:26:10 +02:00
if (!SLine::readProperties(e))
2013-01-11 18:10:18 +01:00
e.unknown();
2012-05-26 14:26:10 +02:00
}
}
2013-03-27 17:52:26 +01:00
//---------------------------------------------------------
// getProperty
//---------------------------------------------------------
2018-03-27 15:36:00 +02:00
QVariant SLine::getProperty(Pid id) const
2013-03-27 17:52:26 +01:00
{
switch (id) {
2018-03-27 15:36:00 +02:00
case Pid::DIAGONAL:
2013-03-27 17:52:26 +01:00
return _diagonal;
2018-03-27 15:36:00 +02:00
case Pid::LINE_COLOR:
return _lineColor;
2018-03-27 15:36:00 +02:00
case Pid::LINE_WIDTH:
2016-03-05 15:31:26 +01:00
return _lineWidth;
2018-03-27 15:36:00 +02:00
case Pid::LINE_STYLE:
return QVariant(int(_lineStyle));
2018-03-27 15:36:00 +02:00
case Pid::DASH_LINE_LEN:
2016-06-30 20:22:36 +02:00
return dashLineLen();
2018-03-27 15:36:00 +02:00
case Pid::DASH_GAP_LEN:
2016-06-30 20:22:36 +02:00
return dashGapLen();
2013-03-27 17:52:26 +01:00
default:
return Spanner::getProperty(id);
}
}
//---------------------------------------------------------
// setProperty
//---------------------------------------------------------
2018-03-27 15:36:00 +02:00
bool SLine::setProperty(Pid id, const QVariant& v)
2013-03-27 17:52:26 +01:00
{
switch (id) {
2018-03-27 15:36:00 +02:00
case Pid::DIAGONAL:
2013-03-27 17:52:26 +01:00
_diagonal = v.toBool();
break;
2018-03-27 15:36:00 +02:00
case Pid::LINE_COLOR:
_lineColor = v.value<QColor>();
break;
2018-03-27 15:36:00 +02:00
case Pid::LINE_WIDTH:
2018-05-07 19:05:34 +02:00
_lineWidth = v.toReal();
break;
2018-03-27 15:36:00 +02:00
case Pid::LINE_STYLE:
_lineStyle = Qt::PenStyle(v.toInt());
break;
2018-03-27 15:36:00 +02:00
case Pid::DASH_LINE_LEN:
2016-06-30 20:22:36 +02:00
setDashLineLen(v.toDouble());
break;
2018-03-27 15:36:00 +02:00
case Pid::DASH_GAP_LEN:
2016-06-30 20:22:36 +02:00
setDashGapLen(v.toDouble());
break;
2013-03-27 17:52:26 +01:00
default:
return Spanner::setProperty(id, v);
}
triggerLayout();
return true;
2013-03-27 17:52:26 +01:00
}
//---------------------------------------------------------
// propertyDefault
//---------------------------------------------------------
2018-10-26 10:41:07 +02:00
QVariant SLine::propertyDefault(Pid pid) const
2013-03-27 17:52:26 +01:00
{
2018-10-26 10:41:07 +02:00
switch (pid) {
2018-03-27 15:36:00 +02:00
case Pid::DIAGONAL:
return false;
2018-03-27 15:36:00 +02:00
case Pid::LINE_COLOR:
return MScore::defaultColor;
2018-03-27 15:36:00 +02:00
case Pid::LINE_WIDTH:
2018-10-26 10:41:07 +02:00
if (propertyFlags(pid) != PropertyFlags::NOSTYLE)
return Spanner::propertyDefault(pid);
2018-05-07 19:05:34 +02:00
return 0.15 * spatium();
2018-03-27 15:36:00 +02:00
case Pid::LINE_STYLE:
2018-10-26 10:41:07 +02:00
if (propertyFlags(pid) != PropertyFlags::NOSTYLE)
return Spanner::propertyDefault(pid);
2013-08-09 11:42:24 +02:00
return int(Qt::SolidLine);
2018-03-27 15:36:00 +02:00
case Pid::DASH_LINE_LEN:
case Pid::DASH_GAP_LEN:
2018-10-26 10:41:07 +02:00
if (propertyFlags(pid) != PropertyFlags::NOSTYLE)
return Spanner::propertyDefault(pid);
2016-06-30 20:22:36 +02:00
return 5.0;
default:
2018-10-26 10:41:07 +02:00
return Spanner::propertyDefault(pid);
2013-03-27 17:52:26 +01:00
}
}
2013-05-13 18:49:17 +02:00
}