MuseScore/libmscore/spanner.h

232 lines
8.6 KiB
C
Raw Normal View History

2012-05-26 14:26:10 +02:00
//=============================================================================
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 2010-2011 Werner Schweer
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2
// as published by the Free Software Foundation and appearing in
// the file LICENCE.GPL
//=============================================================================
#ifndef __SPANNER_H__
#define __SPANNER_H__
#include "element.h"
2013-05-13 18:49:17 +02:00
namespace Ms {
2012-05-26 14:26:10 +02:00
class Segment;
class Spanner;
class System;
2013-06-16 23:33:37 +02:00
class Chord;
2013-06-10 11:03:34 +02:00
class ChordRest;
class Note;
2013-06-10 11:03:34 +02:00
//---------------------------------------------------------
// SpannerSegmentType
//---------------------------------------------------------
2012-05-26 14:26:10 +02:00
enum class SpannerSegmentType : char {
SINGLE, BEGIN, MIDDLE, END
2012-05-26 14:26:10 +02:00
};
//---------------------------------------------------------
2012-07-25 11:49:34 +02:00
// @@ SpannerSegment
//! parent: System
2012-05-26 14:26:10 +02:00
//---------------------------------------------------------
class SpannerSegment : public Element {
Q_OBJECT
2012-05-26 14:26:10 +02:00
Spanner* _spanner;
2013-06-10 11:03:34 +02:00
SpannerSegmentType _spannerSegmentType;
protected:
QPointF _p2;
QPointF _userOff2;
2012-05-26 14:26:10 +02:00
public:
SpannerSegment(Score* s);
SpannerSegment(const SpannerSegment&);
virtual SpannerSegment* clone() const = 0;
2013-06-10 11:03:34 +02:00
2012-05-26 14:26:10 +02:00
Spanner* spanner() const { return _spanner; }
Spanner* setSpanner(Spanner* val) { return _spanner = val; }
void setSpannerSegmentType(SpannerSegmentType s) { _spannerSegmentType = s; }
SpannerSegmentType spannerSegmentType() const { return _spannerSegmentType; }
2016-06-15 16:11:17 +02:00
bool isSingleType() const { return spannerSegmentType() == SpannerSegmentType::SINGLE; }
bool isBeginType() const { return spannerSegmentType() == SpannerSegmentType::BEGIN; }
2016-07-04 13:21:33 +02:00
bool isSingleBeginType() const { return isSingleType() || isBeginType(); }
bool isSingleEndType() const { return isSingleType() || isEndType(); }
2016-06-15 16:11:17 +02:00
bool isMiddleType() const { return spannerSegmentType() == SpannerSegmentType::MIDDLE; }
bool isEndType() const { return spannerSegmentType() == SpannerSegmentType::END; }
2012-05-26 14:26:10 +02:00
void setSystem(System* s);
System* system() const { return (System*)parent(); }
2013-06-10 11:03:34 +02:00
const QPointF& userOff2() const { return _userOff2; }
void setUserOff2(const QPointF& o) { _userOff2 = o; }
void setUserXoffset2(qreal x) { _userOff2.setX(x); }
2016-07-20 12:45:34 +02:00
qreal& rUserXoffset2() { return _userOff2.rx(); }
qreal& rUserYoffset2() { return _userOff2.ry(); }
2013-06-10 11:03:34 +02:00
void setPos2(const QPointF& p) { _p2 = p; }
QPointF pos2() const { return _p2 + _userOff2; }
const QPointF& ipos2() const { return _p2; }
qreal& rxpos2() { return _p2.rx(); }
qreal& rypos2() { return _p2.ry(); }
2013-06-10 11:03:34 +02:00
virtual void startEdit(MuseScoreView*, const QPointF&) override;
virtual void endEdit() override;
virtual bool isEditable() const override { return true; }
2013-05-02 16:12:17 +02:00
virtual QVariant getProperty(P_ID id) const override;
virtual bool setProperty(P_ID id, const QVariant& v) override;
virtual QVariant propertyDefault(P_ID id) const override;
void reset() override;
2014-05-07 12:10:28 +02:00
virtual void setSelected(bool f) override;
virtual void setVisible(bool f) override;
virtual void setColor(const QColor& col) override;
virtual Element* nextElement() override;
virtual Element* prevElement() override;
virtual bool isSpannerSegment() const override { return true; }
2016-02-04 17:06:32 +01:00
virtual QString accessibleInfo() const override;
virtual void styleChanged() override;
virtual void triggerLayout() const override;
2012-05-26 14:26:10 +02:00
};
2012-09-12 11:16:36 +02:00
//----------------------------------------------------------------------------------
2012-07-16 19:59:32 +02:00
// @@ Spanner
/// Virtual base class for slurs, ties, lines etc.
//
// @P anchor enum (Spanner.CHORD, Spanner.MEASURE, Spanner.NOTE, Spanner.SEGMENT)
// @P endElement Element the element the spanner end is anchored to (read-only)
// @P startElement Element the element the spanner start is anchored to (read-only)
// @P tick int tick start position
// @P tick2 int tick end position
2012-09-12 11:16:36 +02:00
//----------------------------------------------------------------------------------
2012-05-26 14:26:10 +02:00
class Spanner : public Element {
Q_OBJECT
2012-09-12 11:16:36 +02:00
Q_ENUMS(Anchor)
public:
2014-05-26 20:48:27 +02:00
enum class Anchor : char {
SEGMENT, MEASURE, CHORD, NOTE
2012-09-12 11:16:36 +02:00
};
private:
Q_PROPERTY(Ms::Spanner::Anchor anchor READ anchor WRITE setAnchor)
Q_PROPERTY(Ms::Element* endElement READ endElement)
Q_PROPERTY(Ms::Element* startElement READ startElement)
Q_PROPERTY(int tick READ tick WRITE setTick)
Q_PROPERTY(int tick2 READ tick2 WRITE setTick2)
2012-05-26 14:26:10 +02:00
2014-08-13 15:42:40 +02:00
Element* _startElement { 0 };
Element* _endElement { 0 };
2014-08-22 13:33:36 +02:00
Anchor _anchor { Anchor::SEGMENT };
2014-08-13 15:42:40 +02:00
int _tick { -1 };
int _ticks { 0 };
int _track2 { -1 };
2012-05-26 14:26:10 +02:00
2013-06-10 11:03:34 +02:00
static QList<QPointF> userOffsets;
static QList<QPointF> userOffsets2;
2012-05-26 14:26:10 +02:00
2013-07-05 11:23:52 +02:00
protected:
2014-07-31 16:30:04 +02:00
QList<SpannerSegment*> segments;
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
// used to store spanner properties as they were at start of editing
// and detect edit changes when edit is over
2013-09-27 11:18:30 +02:00
static int editTick, editTick2, editTrack2;
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
static Note * editEndNote, * editStartNote;
2013-07-05 11:23:52 +02:00
2012-05-26 14:26:10 +02:00
public:
Spanner(Score* = 0);
2012-05-26 14:26:10 +02:00
Spanner(const Spanner&);
~Spanner();
virtual Element::Type type() const = 0;
2013-08-22 12:18:14 +02:00
virtual void setScore(Score* s) override;
2012-05-26 14:26:10 +02:00
2016-03-08 09:46:33 +01:00
virtual int tick() const override { return _tick; }
int tick2() const { return _tick + _ticks; }
int ticks() const { return _ticks; }
void setTick(int v);
void setTick2(int v);
void setTicks(int v);
2013-09-27 11:18:30 +02:00
int track2() const { return _track2; }
void setTrack2(int v) { _track2 = v; }
2012-05-26 14:26:10 +02:00
Anchor anchor() const { return _anchor; }
void setAnchor(Anchor a) { _anchor = a; }
const QList<SpannerSegment*>& spannerSegments() const { return segments; }
QList<SpannerSegment*>& spannerSegments() { return segments; }
2016-07-10 12:00:57 +02:00
virtual SpannerSegment* layoutSystem(System*);
virtual void triggerLayout() const override;
2013-08-22 12:18:14 +02:00
virtual void add(Element*) override;
virtual void remove(Element*) override;
virtual void scanElements(void* data, void (*func)(void*, Element*), bool all=true) override;
virtual void startEdit(MuseScoreView*, const QPointF&) override;
virtual void endEdit() override;
2012-05-26 14:26:10 +02:00
bool removeSpannerBack();
virtual void removeUnmanaged();
virtual void undoInsertTimeUnmanaged(int tick, int len);
2014-05-26 20:48:27 +02:00
virtual void setYoff(qreal) {} // used in musicxml import
2012-09-12 11:16:36 +02:00
2013-06-10 11:03:34 +02:00
QVariant getProperty(P_ID propertyId) const;
bool setProperty(P_ID propertyId, const QVariant& v);
QVariant propertyDefault(P_ID propertyId) const;
2013-06-16 23:33:37 +02:00
void computeStartElement();
void computeEndElement();
static Note* endElementFromSpanner(Spanner* sp, Element* newStart);
static Note* startElementFromSpanner(Spanner* sp, Element* newEnd);
void setNoteSpan(Note* startNote, Note* endNote);
2013-06-16 23:33:37 +02:00
Element* startElement() const { return _startElement; }
2013-06-19 16:25:29 +02:00
Element* endElement() const { return _endElement; }
Measure* startMeasure() const;
Measure* endMeasure() const;
2014-08-07 10:18:50 +02:00
void setStartElement(Element* e);
void setEndElement(Element* e);
2013-06-16 23:33:37 +02:00
2014-08-22 13:33:36 +02:00
ChordRest* startCR();
ChordRest* endCR();
2013-06-16 23:33:37 +02:00
Chord* startChord();
Chord* endChord();
2013-06-16 23:33:37 +02:00
2013-06-10 11:03:34 +02:00
Segment* startSegment() const;
Segment* endSegment() const;
2014-05-07 12:10:28 +02:00
virtual void setSelected(bool f) override;
virtual void setVisible(bool f) override;
virtual void setColor(const QColor& col) override;
virtual Element* nextElement() override;
virtual Element* prevElement() override;
2014-05-07 12:10:28 +02:00
virtual bool isSpanner() const override { return true; }
2014-05-07 12:10:28 +02:00
friend class SpannerSegment;
2016-07-18 12:34:27 +02:00
#ifndef NDEBUG
bool broken { false };
#endif
2013-06-10 11:03:34 +02:00
};
2013-05-13 18:49:17 +02:00
} // namespace Ms
Q_DECLARE_METATYPE(Ms::Spanner::Anchor);
2013-05-13 18:49:17 +02:00
2012-05-26 14:26:10 +02:00
#endif