ported #6935, #6987, #7395: Add a style option to show measure number range at mmrests

This commit is contained in:
Igor Korsukov 2021-02-04 15:13:07 +02:00 committed by pereverzev+v
parent c91d1475b5
commit 094cb955d7
21 changed files with 632 additions and 165 deletions

View file

@ -165,11 +165,15 @@ set(MODULE_SRC
measure.h
measurenumber.cpp
measurenumber.h
measurenumberbase.cpp
measurenumberbase.h
measurerepeat.cpp
measurerepeat.h
midimapping.cpp
mmrest.cpp
mmrest.h
mmrestrange.cpp
mmrestrange.h
mscore.cpp
mscore.h
mscoreview.cpp

View file

@ -485,6 +485,7 @@ void Ambitus::draw(QPainter* p) const
qreal ledgerLineLength = score()->styleS(Sid::ledgerLineLength).val() * _spatium;
qreal ledgerLineWidth = score()->styleS(Sid::ledgerLineWidth).val() * _spatium;
p->setPen(QPen(curColor(), ledgerLineWidth, Qt::SolidLine, Qt::FlatCap));
if (_topPos.y() - stepTolerance <= -step) {
qreal xMin = _topPos.x() - ledgerLineLength;
qreal xMax = _topPos.x() + headWidth() + ledgerLineLength;
@ -492,6 +493,7 @@ void Ambitus::draw(QPainter* p) const
p->drawLine(QPointF(xMin, y), QPointF(xMax, y));
}
}
if (_bottomPos.y() + stepTolerance >= numOfLines * step) {
qreal xMin = _bottomPos.x() - ledgerLineLength;
qreal xMax = _bottomPos.x() + headWidth() + ledgerLineLength;

View file

@ -83,6 +83,7 @@
#include "textframe.h"
#include "text.h"
#include "measurenumber.h"
#include "mmrestrange.h"
#include "textline.h"
#include "tie.h"
#include "timesig.h"
@ -1097,6 +1098,7 @@ Element* Element::create(ElementType type, Score* score)
case ElementType::DYNAMIC: return new Dynamic(score);
case ElementType::TEXT: return new Text(score);
case ElementType::MEASURE_NUMBER: return new MeasureNumber(score);
case ElementType::MMREST_RANGE: return new MMRestRange(score);
case ElementType::INSTRUMENT_NAME: return new InstrumentName(score);
case ElementType::STAFF_TEXT: return new StaffText(score);
case ElementType::SYSTEM_TEXT: return new SystemText(score);

View file

@ -30,6 +30,7 @@
#include "lyrics.h"
#include "marker.h"
#include "measure.h"
#include "mmrestrange.h"
#include "mmrest.h"
#include "mscore.h"
#include "notedot.h"
@ -4306,6 +4307,8 @@ void Score::layoutSystemElements(System* system, LayoutContext& lc)
}
Measure* m = toMeasure(mb);
m->layoutMeasureNumber();
m->layoutMMRestRange();
// in continuous view, entire score is one system
// but we only need to process the range
if (lineMode() && (m->tick() < lc.startTick || m->tick() > lc.endTick)) {
@ -4358,6 +4361,7 @@ void Score::layoutSystemElements(System* system, LayoutContext& lc)
}
Measure* m = toMeasure(mb);
MeasureNumber* mno = m->noText(staffIdx);
MMRestRange* mmrr = m->mmRangeText(staffIdx);
// no need to build skyline outside of range in continuous view
if (lineMode() && (m->tick() < lc.startTick || m->tick() > lc.endTick)) {
continue;
@ -4365,6 +4369,9 @@ void Score::layoutSystemElements(System* system, LayoutContext& lc)
if (mno && mno->addToSkyline()) {
ss->skyline().add(mno->bbox().translated(m->pos() + mno->pos()));
}
if (mmrr && mmrr->addToSkyline()) {
ss->skyline().add(mmrr->bbox().translated(m->pos() + mmrr->pos()));
}
if (m->staffLines(staffIdx)->addToSkyline()) {
ss->skyline().add(m->staffLines(staffIdx)->bbox().translated(m->pos()));
}

View file

@ -69,6 +69,7 @@
#include "system.h"
#include "tempotext.h"
#include "measurenumber.h"
#include "mmrestrange.h"
#include "tie.h"
#include "tiemap.h"
#include "timesig.h"
@ -94,6 +95,7 @@ namespace Ms {
MStaff::~MStaff()
{
delete m_noText;
delete m_mmRangeText;
delete m_lines;
delete m_vspacerUp;
delete m_vspacerDown;
@ -102,6 +104,7 @@ MStaff::~MStaff()
MStaff::MStaff(const MStaff& m)
{
m_noText = 0;
m_mmRangeText = 0;
m_lines = new StaffLines(*m.m_lines);
m_hasVoices = m.m_hasVoices;
m_vspacerUp = 0;
@ -132,6 +135,9 @@ void MStaff::setScore(Score* score)
if (m_noText) {
m_noText->setScore(score);
}
if (m_mmRangeText) {
m_mmRangeText->setScore(score);
}
}
//---------------------------------------------------------
@ -152,6 +158,9 @@ void MStaff::setTrack(int track)
if (m_noText) {
m_noText->setTrack(track);
}
if (m_mmRangeText) {
m_mmRangeText->setTrack(track);
}
}
//---------------------------------------------------------
@ -269,7 +278,6 @@ MStaff* Measure::mstaff(int staffIndex) const
bool Measure::hasVoices(int staffIdx) const
{
MStaff* staff = mstaff(staffIdx);
return staff ? staff->hasVoices() : false;
}
@ -321,6 +329,16 @@ void Measure::setStaffStemless(int staffIdx, bool stemless)
}
}
void Measure::setMMRangeText(int staffIdx, MMRestRange* t)
{
m_mstaves[staffIdx]->setMMRangeText(t);
}
MMRestRange* Measure::mmRangeText(int staffIdx) const
{
return m_mstaves[staffIdx]->mmRangeText();
}
//---------------------------------------------------------
// Measure
//---------------------------------------------------------
@ -464,7 +482,7 @@ AccidentalVal Measure::findAccidental(Segment* s, int staffIdx, int line, bool&
//---------------------------------------------------------
// tick2pos
// return x position for tick relative to System
/// return x position for tick relative to System
//---------------------------------------------------------
qreal Measure::tick2pos(Fraction tck) const
@ -617,6 +635,51 @@ void Measure::layoutMeasureNumber()
}
}
void Measure::layoutMMRestRange()
{
if (!isMMRest() || !score()->styleB(Sid::mmRestShowMeasureNumberRange)) {
// Remove existing
for (unsigned staffIdx = 0; staffIdx < m_mstaves.size(); ++staffIdx) {
MStaff* ms = m_mstaves[staffIdx];
MMRestRange* rr = ms->mmRangeText();
if (rr) {
if (rr->generated()) {
score()->removeElement(rr);
} else {
score()->undo(new RemoveElement(rr));
}
}
}
return;
}
QString s;
if (mmRestCount() > 1) {
// middle char is an en dash (not em)
s = QString("%1%2").arg(no() + 1).arg(no() + mmRestCount());
} else {
// If the minimum range to create a mmrest is set to 1,
// then simply show the measure number as there is no range
s = QString("%1").arg(no() + 1);
}
for (unsigned staffIdx = 0; staffIdx < m_mstaves.size(); ++staffIdx) {
MStaff* ms = m_mstaves[staffIdx];
MMRestRange* rr = ms->mmRangeText();
if (!rr) {
rr = new MMRestRange(score());
rr->setTrack(staffIdx * VOICES);
rr->setGenerated(true);
rr->setParent(this);
add(rr);
}
// setXmlText is reimplemented to take care of brackets
rr->setXmlText(s);
rr->layout();
}
}
//---------------------------------------------------------
// layout2
// called after layout of page
@ -866,6 +929,15 @@ void Measure::add(Element* e)
}
break;
case ElementType::MMREST_RANGE:
if (e->staffIdx() < int(m_mstaves.size())) {
if (e->isStyled(Pid::OFFSET)) {
e->setOffset(e->propertyDefault(Pid::OFFSET).toPointF());
}
m_mstaves[e->staffIdx()]->setMMRangeText(toMMRestRange(e));
}
break;
case ElementType::SPACER:
{
Spacer* sp = toSpacer(e);
@ -964,6 +1036,10 @@ void Measure::remove(Element* e)
m_mstaves[e->staffIdx()]->setNoText(nullptr);
break;
case ElementType::MMREST_RANGE:
m_mstaves[e->staffIdx()]->setMMRangeText(nullptr);
break;
case ElementType::SPACER:
switch (toSpacer(e)->spacerType()) {
case SpacerType::DOWN:
@ -1932,6 +2008,10 @@ void Measure::write(XmlWriter& xml, int staff, bool writeSystemElements, bool fo
mstaff->noText()->write(xml);
}
if (mstaff->mmRangeText() && !mstaff->mmRangeText()->generated()) {
mstaff->mmRangeText()->write(xml);
}
if (mstaff->vspacerUp()) {
xml.tag("vspacerUp", mstaff->vspacerUp()->gap() / _spatium);
}
@ -2085,6 +2165,11 @@ void Measure::read(XmlReader& e, int staffIdx)
noText->read(e);
noText->setTrack(e.track());
add(noText);
} else if (tag == "MMRestRange") {
MMRestRange* range = new MMRestRange(score());
range->read(e);
range->setTrack(e.track());
add(range);
} else if (MeasureBase::readProperties(e)) {
} else {
e.unknown();

View file

@ -29,6 +29,7 @@ class Tuplet;
class Staff;
class Chord;
class MeasureNumber;
class MMRestRange;
class ChordRest;
class Score;
class MuseScoreView;
@ -69,6 +70,9 @@ public:
MeasureNumber* noText() const { return m_noText; }
void setNoText(MeasureNumber* t) { m_noText = t; }
MMRestRange* mmRangeText() const { return m_mmRangeText; }
void setMMRangeText(MMRestRange* r) { m_mmRangeText = r; }
StaffLines* lines() const { return m_lines; }
void setLines(StaffLines* l) { m_lines = l; }
@ -96,6 +100,7 @@ public:
private:
MeasureNumber* m_noText { nullptr }; ///< Measure number text object
MMRestRange* m_mmRangeText { nullptr }; ///< Multi measure rest range text object
StaffLines* m_lines { nullptr };
Spacer* m_vspacerUp { nullptr };
Spacer* m_vspacerDown { nullptr };
@ -166,6 +171,9 @@ public:
MeasureNumber* noText(int staffIdx) const { return m_mstaves[staffIdx]->noText(); }
void setNoText(int staffIdx, MeasureNumber* t) { m_mstaves[staffIdx]->setNoText(t); }
void setMMRangeText(int staffIdx, MMRestRange*);
MMRestRange* mmRangeText(int staffIdx) const;
void createStaves(int);
MeasureNumberMode measureNumberMode() const { return m_noMode; }
@ -195,6 +203,7 @@ public:
bool showsMeasureNumber();
bool showsMeasureNumberInAutoMode();
void layoutMeasureNumber();
void layoutMMRestRange();
Chord* findChord(Fraction tick, int track);
ChordRest* findChordRest(Fraction tick, int track);

View file

@ -19,9 +19,7 @@
#include "score.h"
#include "measurenumber.h"
// #include "xml.h"
#include "measure.h"
#include "staff.h"
namespace Ms {
//---------------------------------------------------------
@ -37,10 +35,9 @@ static const ElementStyle measureNumberStyle {
// MeasureNumber
//---------------------------------------------------------
MeasureNumber::MeasureNumber(Score* s)
: TextBase(s, Tid::MEASURE_NUMBER)
MeasureNumber::MeasureNumber(Score* s, Tid tid)
: MeasureNumberBase(s, tid)
{
setFlag(ElementFlag::ON_STAFF, true);
initElementStyle(&measureNumberStyle);
setHPlacement(score()->styleV(Sid::measureNumberHPlacement).value<HPlacement>());
@ -52,43 +49,9 @@ MeasureNumber::MeasureNumber(Score* s)
//---------------------------------------------------------
MeasureNumber::MeasureNumber(const MeasureNumber& other)
: TextBase(other)
: MeasureNumberBase(other)
{
setFlag(ElementFlag::ON_STAFF, true);
initElementStyle(&measureNumberStyle);
setHPlacement(other.hPlacement());
}
//---------------------------------------------------------
// getProperty
//---------------------------------------------------------
QVariant MeasureNumber::getProperty(Pid id) const
{
switch (id) {
case Pid::HPLACEMENT:
return int(hPlacement());
default:
return TextBase::getProperty(id);
}
}
//---------------------------------------------------------
// setProperty
//---------------------------------------------------------
bool MeasureNumber::setProperty(Pid id, const QVariant& val)
{
switch (id) {
case Pid::HPLACEMENT:
setHPlacement(HPlacement(val.toInt()));
setLayoutInvalid();
triggerLayout();
return true;
default:
return TextBase::setProperty(id, val);
}
}
//---------------------------------------------------------
@ -105,109 +68,7 @@ QVariant MeasureNumber::propertyDefault(Pid id) const
case Pid::HPLACEMENT:
return score()->styleV(Sid::measureNumberHPlacement);
default:
return TextBase::propertyDefault(id);
}
}
//---------------------------------------------------------
// readProperties
//---------------------------------------------------------
bool MeasureNumber::readProperties(XmlReader& xml)
{
if (readProperty(xml.name(), xml, Pid::HPLACEMENT)) {
return true;
} else {
return TextBase::readProperties(xml);
}
}
//---------------------------------------------------------
// layout
//---------------------------------------------------------
void MeasureNumber::layout()
{
setPos(QPointF());
if (!parent()) {
setOffset(0.0, 0.0);
}
// TextBase::layout1() needs to be called even if there's no measure attached to it.
// This happens for example in the palettes.
TextBase::layout1();
// this could be if (!measure()) but it is the same as current and slower
// See implementation of MeasureNumber::measure().
if (!parent()) {
return;
}
static constexpr qreal MN_DEFAULT_Y_OFFSET = 2.0;
if (placeBelow()) {
qreal yoff = MN_DEFAULT_Y_OFFSET * spatium() + bbox().height();
// If there is only one line, the barline spans outside the staff lines, so the default position is not correct.
if (staff()->constStaffType(measure()->tick())->lines() == 1) {
yoff += 2 * spatium();
} else {
yoff += staff()->height();
}
rypos() = yoff;
} else {
qreal yoff = -1 * MN_DEFAULT_Y_OFFSET * spatium();
// If there is only one line, the barline spans outside the staff lines, so the default position is not correct.
if (staff()->constStaffType(measure()->tick())->lines() == 1) {
yoff -= 2 * spatium();
}
rypos() = yoff;
}
if (hPlacement() == HPlacement::CENTER) {
// measure numbers should be centered over where there can be notes.
// This means that header and trailing segments should be ignored,
// which includes all timesigs, clefs, keysigs, etc.
// This is how it should be centered:
// |bb 4/4 notes-chords #| other measure |
// | ------18------ | other measure |
// x1 - left measure position of free space
// x2 - right measure position of free space
const Measure* mea = measure();
// find first chordrest
Segment* chordRest = mea->first(SegmentType::ChordRest);
Segment* s1 = chordRest->prevActive();
// unfortunately, using !s1->header() does not work
while (s1 && (s1->isChordRestType()
|| s1->isBreathType()
|| s1->isClefType()
|| s1->isBarLineType()
|| !s1->element(staffIdx() * VOICES))) {
s1 = s1->prevActive();
}
Segment* s2 = chordRest->next();
// unfortunately, using !s1->trailer() does not work
while (s2 && (s2->isChordRestType()
|| s2->isBreathType()
|| s2->isClefType()
|| s2->isBarLineType()
|| !s2->element(staffIdx() * VOICES))) {
s2 = s2->nextActive();
}
// if s1/s2 does not exist, it means there is no header/trailer segment. Align with start/end of measure.
qreal x1 = s1 ? s1->x() + s1->minRight() : 0;
qreal x2 = s2 ? s2->x() - s2->minLeft() : mea->width();
rxpos() = (x1 + x2) * 0.5;
} else if (hPlacement() == HPlacement::RIGHT) {
rxpos() = measure()->width();
return MeasureNumberBase::propertyDefault(id);
}
}
} // namespace MS

View file

@ -2,45 +2,41 @@
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 2014 Werner Schweer
// Copyright (C) 2020 MuseScore BVBA and others
//
// 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
// it under the terms of the GNU General Public License version 2.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//=============================================================================
#ifndef __MEASURENUMBER_H__
#define __MEASURENUMBER_H__
#include "textbase.h"
#include "measurenumberbase.h"
namespace Ms {
//---------------------------------------------------------
// MeasureNumber
//---------------------------------------------------------
class MeasureNumber final : public TextBase
class MeasureNumber : public MeasureNumberBase
{
M_PROPERTY(HPlacement, hPlacement, setHPlacement) // Horizontal Placement
public:
MeasureNumber(Score* s = nullptr);
MeasureNumber(Score* = nullptr, Tid tid = Tid::MEASURE_NUMBER);
MeasureNumber(const MeasureNumber& other);
virtual ElementType type() const override { return ElementType::MEASURE_NUMBER; }
virtual MeasureNumber* clone() const override { return new MeasureNumber(*this); }
virtual QVariant getProperty(Pid id) const override;
virtual bool setProperty(Pid id, const QVariant& val) override;
virtual QVariant propertyDefault(Pid id) const override;
virtual bool readProperties(XmlReader&) override;
virtual void layout() override;
Measure* measure() const { return toMeasure(parent()); }
virtual bool isEditable() const override { return false; } // The measure numbers' text should not be editable
};
} // namespace Ms

View file

@ -0,0 +1,193 @@
//=============================================================================
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 2020 MuseScore BVBA and others
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//=============================================================================
#include "score.h"
#include "measurenumberbase.h"
#include "measure.h"
#include "staff.h"
namespace Ms {
//---------------------------------------------------------
// MeasureNumberBase
//---------------------------------------------------------
MeasureNumberBase::MeasureNumberBase(Score* s, Tid tid)
: TextBase(s, tid)
{
setFlag(ElementFlag::ON_STAFF, true);
}
//---------------------------------------------------------
// MeasureNumberBase
// Copy constructor
//---------------------------------------------------------
MeasureNumberBase::MeasureNumberBase(const MeasureNumberBase& other)
: TextBase(other)
{
setFlag(ElementFlag::ON_STAFF, true);
setHPlacement(other.hPlacement());
}
//---------------------------------------------------------
// getProperty
//---------------------------------------------------------
QVariant MeasureNumberBase::getProperty(Pid id) const
{
switch (id) {
case Pid::HPLACEMENT:
return int(hPlacement());
default:
return TextBase::getProperty(id);
}
}
//---------------------------------------------------------
// setProperty
//---------------------------------------------------------
bool MeasureNumberBase::setProperty(Pid id, const QVariant& val)
{
switch (id) {
case Pid::HPLACEMENT:
setHPlacement(HPlacement(val.toInt()));
setLayoutInvalid();
triggerLayout();
return true;
default:
return TextBase::setProperty(id, val);
}
}
//---------------------------------------------------------
// propertyDefault
//---------------------------------------------------------
QVariant MeasureNumberBase::propertyDefault(Pid id) const
{
switch (id) {
case Pid::SUB_STYLE:
return int(Tid::DEFAULT);
default:
return TextBase::propertyDefault(id);
}
}
//---------------------------------------------------------
// readProperties
//---------------------------------------------------------
bool MeasureNumberBase::readProperties(XmlReader& xml)
{
if (readProperty(xml.name(), xml, Pid::HPLACEMENT)) {
return true;
} else {
return TextBase::readProperties(xml);
}
}
//---------------------------------------------------------
// layout
//---------------------------------------------------------
void MeasureNumberBase::layout()
{
setPos(QPointF());
if (!parent()) {
setOffset(0.0, 0.0);
}
// TextBase::layout1() needs to be called even if there's no measure attached to it.
// This happens for example in the palettes.
TextBase::layout1();
// this could be if (!measure()) but it is the same as current and slower
// See implementation of MeasureNumberBase::measure().
if (!parent()) {
return;
}
if (placeBelow()) {
qreal yoff = bbox().height();
// If there is only one line, the barline spans outside the staff lines, so the default position is not correct.
if (staff()->constStaffType(measure()->tick())->lines() == 1) {
yoff += 2.0 * spatium();
} else {
yoff += staff()->height();
}
rypos() = yoff;
} else {
qreal yoff = 0.0;
// If there is only one line, the barline spans outside the staff lines, so the default position is not correct.
if (staff()->constStaffType(measure()->tick())->lines() == 1) {
yoff -= 2.0 * spatium();
}
rypos() = yoff;
}
if (hPlacement() == HPlacement::CENTER) {
// measure numbers should be centered over where there can be notes.
// This means that header and trailing segments should be ignored,
// which includes all timesigs, clefs, keysigs, etc.
// This is how it should be centered:
// |bb 4/4 notes-chords #| other measure |
// | ------18------ | other measure |
// x1 - left measure position of free space
// x2 - right measure position of free space
const Measure* mea = measure();
// find first chordrest
Segment* chordRest = mea->first(SegmentType::ChordRest);
Segment* s1 = chordRest->prevActive();
// unfortunately, using !s1->header() does not work
while (s1 && (s1->isChordRestType()
|| s1->isBreathType()
|| s1->isClefType()
|| s1->isBarLineType()
|| !s1->element(staffIdx() * VOICES))) {
s1 = s1->prevActive();
}
Segment* s2 = chordRest->next();
// unfortunately, using !s1->trailer() does not work
while (s2 && (s2->isChordRestType()
|| s2->isBreathType()
|| s2->isClefType()
|| s2->isBarLineType()
|| !s2->element(staffIdx() * VOICES))) {
s2 = s2->nextActive();
}
// if s1/s2 does not exist, it means there is no header/trailer segment. Align with start/end of measure.
qreal x1 = s1 ? s1->x() + s1->minRight() : 0;
qreal x2 = s2 ? s2->x() - s2->minLeft() : mea->width();
rxpos() = (x1 + x2) * 0.5;
} else if (hPlacement() == HPlacement::RIGHT) {
rxpos() = measure()->width();
}
}
} // namespace MS

View file

@ -0,0 +1,53 @@
//=============================================================================
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 2020 MuseScore BVBA and others
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//=============================================================================
#ifndef __MEASURENUMBERBASE_H__
#define __MEASURENUMBERBASE_H__
#include "textbase.h"
namespace Ms {
//---------------------------------------------------------
// MeasureNumberBase
/// The basic element making measure numbers.
/// Reimplemented by MMRestRange
//---------------------------------------------------------
class MeasureNumberBase : public TextBase
{
M_PROPERTY(HPlacement, hPlacement, setHPlacement) // Horizontal Placement
public:
MeasureNumberBase(Score* = nullptr, Tid = Tid::DEFAULT);
MeasureNumberBase(const MeasureNumberBase& other);
virtual QVariant getProperty(Pid id) const override;
virtual bool setProperty(Pid id, const QVariant& val) override;
virtual QVariant propertyDefault(Pid id) const override;
virtual bool readProperties(XmlReader&) override;
virtual void layout() override;
Measure* measure() const { return toMeasure(parent()); }
virtual bool isEditable() const override { return false; } // The measure numbers' text should not be editable
};
} // namespace Ms
#endif

View file

@ -0,0 +1,118 @@
//=============================================================================
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 2020 MuseScore BVBA and others
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//=============================================================================
#include "score.h"
#include "mmrestrange.h"
#include "measure.h"
namespace Ms {
//---------------------------------------------------------
// mmRestRangeStyle
//---------------------------------------------------------
static const ElementStyle mmRestRangeStyle {
{ Sid::mmRestRangeBracketType, Pid::MMREST_RANGE_BRACKET_TYPE },
{ Sid::mmRestRangeVPlacement, Pid::PLACEMENT },
{ Sid::mmRestRangeHPlacement, Pid::HPLACEMENT }
};
MMRestRange::MMRestRange(Score* s)
: MeasureNumberBase(s, Tid::MMREST_RANGE)
{
initElementStyle(&mmRestRangeStyle);
}
//---------------------------------------------------------
// MMRestRange
/// Copy constructor
//---------------------------------------------------------
MMRestRange::MMRestRange(const MMRestRange& other)
: MeasureNumberBase(other)
{
initElementStyle(&mmRestRangeStyle);
}
QVariant MMRestRange::getProperty(Pid id) const
{
switch (id) {
case Pid::MMREST_RANGE_BRACKET_TYPE:
return int(bracketType());
default:
return MeasureNumberBase::getProperty(id);
}
}
bool MMRestRange::setProperty(Pid id, const QVariant& val)
{
switch (id) {
case Pid::MMREST_RANGE_BRACKET_TYPE:
setBracketType(MMRestRangeBracketType(val.toInt()));
setLayoutInvalid();
triggerLayout();
return true;
default:
return MeasureNumberBase::setProperty(id, val);
}
}
QVariant MMRestRange::propertyDefault(Pid id) const
{
switch (id) {
case Pid::SUB_STYLE:
return int(Tid::MMREST_RANGE);
case Pid::PLACEMENT:
return score()->styleV(Sid::mmRestRangeVPlacement);
case Pid::HPLACEMENT:
return score()->styleV(Sid::mmRestRangeHPlacement);
default:
return MeasureNumberBase::propertyDefault(id);
}
}
bool MMRestRange::readProperties(XmlReader& xml)
{
if (readProperty(xml.name(), xml, Pid::MMREST_RANGE_BRACKET_TYPE)) {
return true;
} else {
return MeasureNumberBase::readProperties(xml);
}
}
//---------------------------------------------------------
// setXmlText
/// This is reimplemented from TextBase::setXmlText to take care of the brackets
//---------------------------------------------------------
void MMRestRange::setXmlText(const QString& s)
{
switch (bracketType()) {
case MMRestRangeBracketType::BRACKETS:
TextBase::setXmlText("[" + s + "]");
break;
case MMRestRangeBracketType::PARENTHESES:
TextBase::setXmlText("(" + s + ")");
break;
case MMRestRangeBracketType::NONE:
default:
TextBase::setXmlText(s);
break;
}
}
} // namespace MS

View file

@ -0,0 +1,53 @@
//=============================================================================
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 2020 MuseScore BVBA and others
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//=============================================================================
#ifndef __MMRESTRANGE_H__
#define __MMRESTRANGE_H__
#include "measurenumberbase.h"
#include "property.h"
namespace Ms {
//---------------------------------------------------------
// MMRestRange
//---------------------------------------------------------
class MMRestRange : public MeasureNumberBase
{
/// Bracketing: [18-24], (18-24) or 18-24
M_PROPERTY(MMRestRangeBracketType, bracketType, setBracketType)
public:
MMRestRange(Score* s = nullptr);
MMRestRange(const MMRestRange& other);
virtual ElementType type() const override { return ElementType::MMREST_RANGE; }
virtual MMRestRange* clone() const override { return new MMRestRange(*this); }
virtual QVariant getProperty(Pid id) const override;
virtual bool setProperty(Pid id, const QVariant& val) override;
virtual QVariant propertyDefault(Pid id) const override;
virtual bool readProperties(XmlReader&) override;
virtual void setXmlText(const QString&) override;
};
} // namespace Ms
#endif

View file

@ -269,6 +269,8 @@ static constexpr PropertyMetaData propertyList[] = {
DUMMY_QT_TRANSLATE_NOOP("propertyName", "placement") },
{ Pid::HPLACEMENT, false, "hplacement", P_TYPE::HPLACEMENT,
DUMMY_QT_TRANSLATE_NOOP("propertyName", "horizontal placement") },
{ Pid::MMREST_RANGE_BRACKET_TYPE, false, "mmrestRangeBracketType", P_TYPE::INT,
DUMMY_QT_TRANSLATE_NOOP("propertyName", "multimeasure rest range bracket type") },
{ Pid::VELOCITY, false, "velocity", P_TYPE::INT,
DUMMY_QT_TRANSLATE_NOOP("propertyName", "velocity") },
{ Pid::JUMP_TO, true, "jumpTo", P_TYPE::STRING,

View file

@ -180,6 +180,7 @@ enum class Pid {
CHANGE_METHOD,
PLACEMENT, // Goes with P_TYPE::PLACEMENT
HPLACEMENT, // Goes with P_TYPE::HPLACEMENT
MMREST_RANGE_BRACKET_TYPE, // The brackets used arond the measure numbers indicating the range covered by the mmrest
VELOCITY,
JUMP_TO,
PLAY_UNTIL,
@ -418,7 +419,7 @@ enum class P_TYPE : char {
FONT,
SUB_STYLE,
ALIGN,
CHANGE_METHOD, // enum class VeloChangeMethod (for single notedynamics)
CHANGE_METHOD, // enum class VeloChangeMethod (for single note dynamics)
CHANGE_SPEED, // enum class Dynamic::Speed
CLEF_TYPE, // enum class ClefType
DYNAMIC_TYPE, // enum class Dynamic::Type

View file

@ -35,6 +35,7 @@ static const ElementName elementNames[] = {
{ ElementType::SYMBOL, "Symbol", QT_TRANSLATE_NOOP("elementName", "Symbol") },
{ ElementType::TEXT, "Text", QT_TRANSLATE_NOOP("elementName", "Text") },
{ ElementType::MEASURE_NUMBER, "MeasureNumber", QT_TRANSLATE_NOOP("elementName", "Measure Number") },
{ ElementType::MMREST_RANGE, "MMRestRange", QT_TRANSLATE_NOOP("elementName", "Multimeasure Rest Range") },
{ ElementType::INSTRUMENT_NAME, "InstrumentName", QT_TRANSLATE_NOOP("elementName", "Instrument Name") },
{ ElementType::SLUR_SEGMENT, "SlurSegment", QT_TRANSLATE_NOOP("elementName", "Slur Segment") },
{ ElementType::TIE_SEGMENT, "TieSegment", QT_TRANSLATE_NOOP("elementName", "Tie Segment") },
@ -933,6 +934,7 @@ bool ScoreElement::isTextBase() const
|| type() == ElementType::TEMPO_TEXT
|| type() == ElementType::INSTRUMENT_NAME
|| type() == ElementType::MEASURE_NUMBER
|| type() == ElementType::MMREST_RANGE
|| type() == ElementType::STICKING
;
}

View file

@ -132,6 +132,7 @@ class VibratoSegment;
class PalmMute;
class PalmMuteSegment;
class MeasureNumber;
class MMRestRange;
class StaffTextBase;
@ -387,6 +388,7 @@ public:
CONVERT(Page, PAGE)
CONVERT(Text, TEXT)
CONVERT(MeasureNumber, MEASURE_NUMBER)
CONVERT(MMRestRange, MMREST_RANGE)
CONVERT(StaffText, STAFF_TEXT)
CONVERT(SystemText, SYSTEM_TEXT)
CONVERT(BracketItem, BRACKET_ITEM)
@ -652,6 +654,7 @@ CONVERT(InstrumentChange)
CONVERT(StaffTypeChange)
CONVERT(Text)
CONVERT(MeasureNumber)
CONVERT(MMRestRange)
CONVERT(Hairpin)
CONVERT(HairpinSegment)
CONVERT(Bend)

View file

@ -882,6 +882,27 @@ static const StyleType styleTypes[] {
{ Sid::measureNumberFrameFgColor, "measureNumberFrameFgColor", QColor(0, 0, 0, 255) },
{ Sid::measureNumberFrameBgColor, "measureNumberFrameBgColor", QColor(255, 255, 255, 0) },
{ Sid::mmRestShowMeasureNumberRange, "mmRestShowMeasureNumberRange", false },
{ Sid::mmRestRangeBracketType, "mmRestRangeBracketType", int(MMRestRangeBracketType::BRACKETS) },
{ Sid::mmRestRangeFontFace, "mmRestRangeFontFace", "Edwin" },
{ Sid::mmRestRangeFontSize, "mmRestRangeFontSize", 8.0 },
{ Sid::mmRestRangeFontSpatiumDependent, "mmRestRangeFontSpatiumDependent", true },
{ Sid::mmRestRangeFontStyle, "mmRestRangeFontStyle", int(FontStyle::Normal) },
{ Sid::mmRestRangeColor, "mmRestRangeColor", QColor(0, 0, 0, 255) },
{ Sid::mmRestRangePosAbove, "measureNumberPosAbove", QPointF(0.0, -3.0) },
{ Sid::mmRestRangePosBelow, "measureNumberPosBelow", QPointF(0.0, 1.0) },
{ Sid::mmRestRangeOffsetType, "mmRestRangeOffsetType", int(OffsetType::SPATIUM) },
{ Sid::mmRestRangeVPlacement, "mmRestRangeVPlacement", int(Placement::BELOW) },
{ Sid::mmRestRangeHPlacement, "mmRestRangeHPlacement", int(HPlacement::CENTER) },
{ Sid::mmRestRangeAlign, "mmRestRangeAlign", QVariant::fromValue(Align::HCENTER | Align::BASELINE) },
{ Sid::mmRestRangeFrameType, "mmRestRangeFrameType", int(FrameType::NO_FRAME) },
{ Sid::mmRestRangeFramePadding, "mmRestRangeFramePadding", 0.2 },
{ Sid::mmRestRangeFrameWidth, "mmRestRangeFrameWidth", 0.1 },
{ Sid::mmRestRangeFrameRound, "mmRestRangeFrameRound", 0 },
{ Sid::mmRestRangeFrameFgColor, "mmRestRangeFrameFgColor", QColor(0, 0, 0, 255) },
{ Sid::mmRestRangeFrameBgColor, "mmRestRangeFrameBgColor", QColor(255, 255, 255, 0) },
{ Sid::translatorFontFace, "translatorFontFace", "FreeSerif" },
{ Sid::translatorFontSize, "translatorFontSize", 11.0 },
{ Sid::translatorFontSpatiumDependent, "translatorFontSpatiumDependent", false },
@ -1693,6 +1714,22 @@ const TextStyle measureNumberTextStyle { {
{ Sid::measureNumberFrameBgColor, Pid::FRAME_BG_COLOR },
} };
const TextStyle mmRestRangeTextStyle { {
{ Sid::mmRestRangeFontFace, Pid::FONT_FACE },
{ Sid::mmRestRangeFontSize, Pid::FONT_SIZE },
{ Sid::mmRestRangeFontSpatiumDependent, Pid::SIZE_SPATIUM_DEPENDENT },
{ Sid::mmRestRangeFontStyle, Pid::FONT_STYLE },
{ Sid::mmRestRangeColor, Pid::COLOR },
{ Sid::mmRestRangeAlign, Pid::ALIGN },
{ Sid::mmRestRangePosAbove, Pid::OFFSET },
{ Sid::mmRestRangeFrameType, Pid::FRAME_TYPE },
{ Sid::mmRestRangeFramePadding, Pid::FRAME_PADDING },
{ Sid::mmRestRangeFrameWidth, Pid::FRAME_WIDTH },
{ Sid::mmRestRangeFrameRound, Pid::FRAME_ROUND },
{ Sid::mmRestRangeFrameFgColor, Pid::FRAME_FG_COLOR },
{ Sid::mmRestRangeFrameBgColor, Pid::FRAME_BG_COLOR },
} };
const TextStyle translatorTextStyle { {
{ Sid::translatorFontFace, Pid::FONT_FACE },
{ Sid::translatorFontSize, Pid::FONT_SIZE },
@ -2320,6 +2357,7 @@ static constexpr std::array<TextStyleName, int(Tid::TEXT_STYLES)> textStyles { {
{ QT_TRANSLATE_NOOP("TextStyle", "Tempo"), &tempoTextStyle, Tid::TEMPO },
{ QT_TRANSLATE_NOOP("TextStyle", "Metronome"), &metronomeTextStyle, Tid::METRONOME },
{ QT_TRANSLATE_NOOP("TextStyle", "Measure Number"), &measureNumberTextStyle, Tid::MEASURE_NUMBER },
{ QT_TRANSLATE_NOOP("TextStyle", "Multi-Measure Rest Range"), &mmRestRangeTextStyle, Tid::MMREST_RANGE },
{ QT_TRANSLATE_NOOP("TextStyle", "Translator"), &translatorTextStyle, Tid::TRANSLATOR },
{ QT_TRANSLATE_NOOP("TextStyle", "Tuplet"), &tupletTextStyle, Tid::TUPLET },
@ -2437,6 +2475,7 @@ static const std::vector<Tid> _primaryTextStyles = {
Tid::HEADER,
Tid::FOOTER,
Tid::MEASURE_NUMBER,
Tid::MMREST_RANGE,
Tid::INSTRUMENT_EXCERPT,
Tid::INSTRUMENT_CHANGE,
Tid::STAFF,

View file

@ -850,6 +850,27 @@ enum class Sid {
measureNumberFrameFgColor,
measureNumberFrameBgColor,
mmRestShowMeasureNumberRange,
mmRestRangeBracketType,
mmRestRangeFontFace,
mmRestRangeFontSize,
mmRestRangeFontSpatiumDependent,
mmRestRangeFontStyle,
mmRestRangeColor,
mmRestRangePosAbove,
mmRestRangePosBelow,
mmRestRangeOffsetType,
mmRestRangeVPlacement,
mmRestRangeHPlacement,
mmRestRangeAlign,
mmRestRangeFrameType,
mmRestRangeFramePadding,
mmRestRangeFrameWidth,
mmRestRangeFrameRound,
mmRestRangeFrameFgColor,
mmRestRangeFrameBgColor,
translatorFontFace,
translatorFontSize,
translatorFontSpatiumDependent,

View file

@ -2813,6 +2813,7 @@ QString TextBase::accessibleInfo() const
case Tid::POET:
case Tid::TRANSLATOR:
case Tid::MEASURE_NUMBER:
case Tid::MMREST_RANGE:
rez = score() ? score()->getTextStyleUserName(tid()) : textStyleUserName(tid());
break;
default:
@ -2842,6 +2843,7 @@ QString TextBase::screenReaderInfo() const
case Tid::POET:
case Tid::TRANSLATOR:
case Tid::MEASURE_NUMBER:
case Tid::MMREST_RANGE:
rez = score() ? score()->getTextStyleUserName(tid()) : textStyleUserName(tid());
break;
default:
@ -3180,6 +3182,8 @@ Sid TextBase::offsetSid() const
return above ? Sid::systemTextPosAbove : Sid::systemTextPosBelow;
case Tid::TEMPO:
return above ? Sid::tempoPosAbove : Sid::tempoPosBelow;
case Tid::MMREST_RANGE:
return above ? Sid::mmRestRangePosAbove : Sid::mmRestRangePosBelow;
default:
break;
}

View file

@ -288,7 +288,7 @@ public:
static QString plainToXmlText(const QString& s) { return s.toHtmlEscaped(); }
void setPlainText(const QString& t) { setXmlText(plainToXmlText(t)); }
void setXmlText(const QString&);
virtual void setXmlText(const QString&);
QString xmlText() const;
QString plainText() const;

View file

@ -43,6 +43,7 @@ enum class ElementType {
SYMBOL,
TEXT,
MEASURE_NUMBER,
MMREST_RANGE,
INSTRUMENT_NAME,
SLUR_SEGMENT,
TIE_SEGMENT,
@ -416,6 +417,16 @@ enum class HPlacement {
///\}
};
//---------------------------------------------------------
// MMRestRangeBracketType
//---------------------------------------------------------
enum class MMRestRangeBracketType {
///.\{
BRACKETS, PARENTHESES, NONE
///\}
};
//---------------------------------------------------------
// OffsetType
//---------------------------------------------------------
@ -493,6 +504,7 @@ enum class Tid {
TEMPO,
METRONOME,
MEASURE_NUMBER,
MMREST_RANGE,
TRANSLATOR,
TUPLET,
SYSTEM,