MuseScore/libmscore/glissando.h
Maurizio M. Gavioli 49edb8d0c3 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-09-30 09:16:47 +02:00

126 lines
4.5 KiB
C++

//=============================================================================
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 2008-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 __GLISSANDO_H__
#define __GLISSANDO_H__
#include "element.h"
#include "line.h"
namespace Ms {
// the amount of white space to leave before a system-initial chord with glissando
static const qreal GLISS_STARTOFSYSTEM_WIDTH = 4; // in sp
class Glissando;
class Note;
//---------------------------------------------------------
// @@ GlissandoSegment
//---------------------------------------------------------
class GlissandoSegment : public LineSegment {
Q_OBJECT
protected:
public:
GlissandoSegment(Score* s) : LineSegment(s) {}
Glissando* glissando() const { return (Glissando*)spanner(); }
virtual Element::Type type() const override { return Element::Type::GLISSANDO_SEGMENT; }
virtual GlissandoSegment* clone() const override { return new GlissandoSegment(*this); }
virtual void draw(QPainter*) const override;
virtual void layout() override;
virtual QVariant getProperty(P_ID id) const override;
virtual bool setProperty(P_ID propertyId, const QVariant&) override;
virtual QVariant propertyDefault(P_ID id) const override;
};
//---------------------------------------------------------
// @@ Glissando
// @P glissandoType enum (Glissando.STRAIGHT, Glissando.WAVY)
// @P showText bool
// @P text string
//---------------------------------------------------------
class Glissando : public SLine {
Q_OBJECT
Q_PROPERTY(Ms::Glissando::Type glissandoType READ glissandoType WRITE undoSetGlissandoType)
Q_PROPERTY(QString text READ text WRITE undoSetText)
Q_PROPERTY(bool showText READ showText WRITE undoSetShowText)
Q_ENUMS(Type)
public:
enum class Type : char {
STRAIGHT, WAVY
};
private:
Type _glissandoType;
QString _text;
bool _showText;
MScore::GlissandoStyle _glissandoStyle;
bool _playGlissando;
protected:
public:
Glissando(Score* s);
Glissando(const Glissando&);
static Note* guessInitialNote(Chord* chord);
static Note* guessFinalNote(Chord* chord);
// overriden inherited methods
virtual Glissando* clone() const override { return new Glissando(*this); }
virtual Element::Type type() const override { return Element::Type::GLISSANDO; }
virtual LineSegment* createLineSegment() override;
virtual void scanElements(void* data, void (*func)(void*, Element*), bool all=true) override;
virtual Space space() const override;
// virtual void draw(QPainter*) const override;
virtual void layout() override;
virtual void write(Xml&) const override;
virtual void read(XmlReader&) override;
// Glissando specific methods
Type glissandoType() const { return _glissandoType;}
void setGlissandoType(Type v) { _glissandoType = v; }
MScore::GlissandoStyle glissandoStyle() const { return _glissandoStyle;}
void setGlissandoStyle(MScore::GlissandoStyle s) { _glissandoStyle = s; }
bool playGlissando() const { return _playGlissando;}
void setPlayGlissando(bool v) { _playGlissando = v; }
QString text() const { return _text; }
void setText(const QString& t) { _text = t; }
bool showText() const { return _showText; }
void setShowText(bool v) { _showText = v; }
// void setSize(const QSizeF&); // was used for palette; no longer used?
void undoSetGlissandoType(Type);
void undoSetText(const QString&);
void undoSetShowText(bool);
// property methods
virtual QVariant getProperty(P_ID propertyId) const override;
virtual bool setProperty(P_ID propertyId, const QVariant&) override;
virtual QVariant propertyDefault(P_ID) const override;
};
} // namespace Ms
Q_DECLARE_METATYPE(Ms::Glissando::Type);
#endif