Skip to content

Commit

Permalink
Fix #203026, fix #301847, Add Measure number inspector,
Browse files Browse the repository at this point in the history
providing the ability to place measure numbers above and below the staff,
but also left, centered, and right.
  • Loading branch information
ecstrema committed Apr 18, 2020
1 parent 4bd193a commit 8089119
Show file tree
Hide file tree
Showing 15 changed files with 501 additions and 55 deletions.
1 change: 1 addition & 0 deletions libmscore/edit.cpp
Expand Up @@ -1563,6 +1563,7 @@ void Score::cmdFlip()
|| e->isHarmony()
|| e->isInstrumentChange()
|| e->isRehearsalMark()
|| e->isMeasureNumber()
|| e->isFretDiagram()
|| e->isHairpin()
|| e->isHairpinSegment()
Expand Down
7 changes: 2 additions & 5 deletions libmscore/measure.cpp
Expand Up @@ -1866,11 +1866,8 @@ void Measure::write(XmlWriter& xml, int staff, bool writeSystemElements, bool fo
}
qreal _spatium = spatium();
MStaff* mstaff = _mstaves[staff];
if (mstaff->noText() && !mstaff->noText()->generated()) {
xml.stag("MeasureNumber", mstaff->noText());
mstaff->noText()->writeProperties(xml);
xml.etag();
}
if (mstaff->noText() && !mstaff->noText()->generated())
mstaff->noText()->write(xml);

if (mstaff->vspacerUp())
xml.tag("vspacerUp", mstaff->vspacerUp()->gap() / _spatium);
Expand Down
146 changes: 135 additions & 11 deletions libmscore/measurenumber.cpp
Expand Up @@ -10,6 +10,7 @@
// the file LICENCE.GPL
//=============================================================================

#include "score.h"
#include "measurenumber.h"
// #include "xml.h"
#include "measure.h"
Expand All @@ -22,6 +23,8 @@ namespace Ms {
//---------------------------------------------------------

static const ElementStyle measureNumberStyle {
{ Sid::measureNumberVPlacement, Pid::PLACEMENT },
{ Sid::measureNumberHPlacement, Pid::HPLACEMENT },
};

//---------------------------------------------------------
Expand All @@ -31,8 +34,53 @@ static const ElementStyle measureNumberStyle {
MeasureNumber::MeasureNumber(Score* s) : TextBase(s, Tid::MEASURE_NUMBER)
{
setFlag(ElementFlag::ON_STAFF, true);
resetProperty(Pid::PLACEMENT);
initElementStyle(&measureNumberStyle);

setHPlacement(score()->styleV(Sid::measureNumberHPlacement).value<HPlacement>());
}

//---------------------------------------------------------
// MeasureNumber
// Copy constructor
//---------------------------------------------------------

MeasureNumber::MeasureNumber(const MeasureNumber& other): TextBase(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);
}
}

//---------------------------------------------------------
Expand All @@ -45,12 +93,26 @@ QVariant MeasureNumber::propertyDefault(Pid id) const
case Pid::SUB_STYLE:
return int(Tid::MEASURE_NUMBER);
case Pid::PLACEMENT:
return int (Placement::ABOVE);
return score()->styleV(Sid::measureNumberVPlacement);
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
//---------------------------------------------------------
Expand All @@ -60,18 +122,80 @@ void MeasureNumber::layout()
setPos(QPointF());
if (!parent())
setOffset(0.0, 0.0);
//else if (isStyled(Pid::OFFSET))
// setOffset(propertyDefault(Pid::OFFSET).toPointF());

const StaffType* st = staff() ? staff()->constStaffType(measure()->tick()) : nullptr;
if (st && st->lines() == 1)
rypos() = (placeBelow() ? 2.0 : -2.0) * spatium();
// 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 {
if (placeBelow())
rypos() = staff() ? staff()->height() : 0.0;
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;
}
TextBase::layout1();

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

19 changes: 14 additions & 5 deletions libmscore/measurenumber.h
Expand Up @@ -23,16 +23,25 @@ namespace Ms {

class MeasureNumber final : public TextBase {

M_PROPERTY (HPlacement, hPlacement, setHPlacement) // Horizontal Placement

public:
MeasureNumber(Score* s = 0);
MeasureNumber(Score* s = nullptr);
MeasureNumber(const MeasureNumber& other);

virtual ElementType type() const override { return ElementType::MEASURE_NUMBER; }
virtual MeasureNumber* clone() const override { return new MeasureNumber(*this); }

ElementType type() const override { return ElementType::MEASURE_NUMBER; }
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;

QVariant propertyDefault(Pid id) const override;
virtual bool readProperties(XmlReader&) override;

void layout() 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
Expand Down
27 changes: 24 additions & 3 deletions libmscore/property.cpp
Expand Up @@ -36,10 +36,10 @@ namespace Ms {
//---------------------------------------------------------

struct PropertyMetaData {
Pid id;
Pid id; // associated Pid
bool link; // link this property for linked elements
const char* name; // xml name of property
P_TYPE type;
P_TYPE type; // associated P_TYPE
const char* userName; // user-visible name of property
};

Expand Down Expand Up @@ -164,6 +164,7 @@ static constexpr PropertyMetaData propertyList[] = {
{ Pid::SINGLE_NOTE_DYNAMICS, true, "singleNoteDynamics", P_TYPE::BOOL, DUMMY_QT_TRANSLATE_NOOP("propertyName", "single note dynamics") },
{ Pid::CHANGE_METHOD, true, "changeMethod", P_TYPE::CHANGE_METHOD, DUMMY_QT_TRANSLATE_NOOP("propertyName", "change method") }, // the new, more general version of VELO_CHANGE_METHOD
{ Pid::PLACEMENT, false, "placement", P_TYPE::PLACEMENT, DUMMY_QT_TRANSLATE_NOOP("propertyName", "placement") },
{ Pid::HPLACEMENT, false, "hplacement", P_TYPE::HPLACEMENT, DUMMY_QT_TRANSLATE_NOOP("propertyName", "horizontal placement") },
{ Pid::VELOCITY, false, "velocity", P_TYPE::INT, DUMMY_QT_TRANSLATE_NOOP("propertyName", "velocity") },
{ Pid::JUMP_TO, true, "jumpTo", P_TYPE::STRING, DUMMY_QT_TRANSLATE_NOOP("propertyName", "jump to") },
{ Pid::PLAY_UNTIL, true, "playUntil", P_TYPE::STRING, DUMMY_QT_TRANSLATE_NOOP("propertyName", "play until") },
Expand Down Expand Up @@ -270,13 +271,13 @@ static constexpr PropertyMetaData propertyList[] = {

{ Pid::FONT_FACE, false, "family", P_TYPE::FONT, DUMMY_QT_TRANSLATE_NOOP("propertyName", "family") },
{ Pid::FONT_SIZE, false, "size", P_TYPE::REAL, DUMMY_QT_TRANSLATE_NOOP("propertyName", "size") },
//200
{ Pid::FONT_STYLE, false, "fontStyle", P_TYPE::INT, DUMMY_QT_TRANSLATE_NOOP("propertyName", "font style") },

{ Pid::FRAME_TYPE, false, "frameType", P_TYPE::INT, DUMMY_QT_TRANSLATE_NOOP("propertyName", "frame type") },
{ Pid::FRAME_WIDTH, false, "frameWidth", P_TYPE::SPATIUM, DUMMY_QT_TRANSLATE_NOOP("propertyName", "frame width") },
{ Pid::FRAME_PADDING, false, "framePadding", P_TYPE::SPATIUM, DUMMY_QT_TRANSLATE_NOOP("propertyName", "frame padding") },
{ Pid::FRAME_ROUND, false, "frameRound", P_TYPE::INT, DUMMY_QT_TRANSLATE_NOOP("propertyName", "frame round") },
//200
{ Pid::FRAME_FG_COLOR, false, "frameFgColor", P_TYPE::COLOR, DUMMY_QT_TRANSLATE_NOOP("propertyName", "frame foreground color") },
{ Pid::FRAME_BG_COLOR, false, "frameBgColor", P_TYPE::COLOR, DUMMY_QT_TRANSLATE_NOOP("propertyName", "frame background color") },
{ Pid::SIZE_SPATIUM_DEPENDENT, false, "sizeIsSpatiumDependent",P_TYPE::BOOL, DUMMY_QT_TRANSLATE_NOOP("propertyName", "spatium dependent font") },
Expand Down Expand Up @@ -503,6 +504,15 @@ QVariant propertyFromString(Pid id, QString value)
return QVariant(int(Placement::BELOW));
}
break;
case P_TYPE::HPLACEMENT: {
if (value == "left")
return QVariant(int(HPlacement::LEFT));
else if (value == "center")
return QVariant(int(HPlacement::CENTER));
else if (value == "right")
return QVariant(int(HPlacement::RIGHT));
}
break;
case P_TYPE::TEXT_PLACE: {
if (value == "auto")
return QVariant(int(PlaceText::AUTO));
Expand Down Expand Up @@ -621,6 +631,7 @@ QVariant readProperty(Pid id, XmlReader& e)
case P_TYPE::LAYOUT_BREAK:
case P_TYPE::VALUE_TYPE:
case P_TYPE::PLACEMENT:
case P_TYPE::HPLACEMENT:
case P_TYPE::TEXT_PLACE:
case P_TYPE::BARLINE_TYPE:
case P_TYPE::SYMID:
Expand Down Expand Up @@ -776,6 +787,16 @@ QString propertyToString(Pid id, QVariant value, bool mscx)
return "below";
}
break;
case P_TYPE::HPLACEMENT:
switch (HPlacement(value.toInt())) {
case HPlacement::LEFT:
return "left";
case HPlacement::CENTER:
return "center";
case HPlacement::RIGHT:
return "right";
}
break;
case P_TYPE::TEXT_PLACE:
switch (PlaceText(value.toInt())) {
case PlaceText::AUTO:
Expand Down
6 changes: 4 additions & 2 deletions libmscore/property.h
Expand Up @@ -172,7 +172,8 @@ enum class Pid {
//100
SINGLE_NOTE_DYNAMICS,
CHANGE_METHOD,
PLACEMENT,
PLACEMENT, // Goes with P_TYPE::PLACEMENT
HPLACEMENT, // Goes with P_TYPE::HPLACEMENT
VELOCITY,
JUMP_TO,
PLAY_UNTIL,
Expand Down Expand Up @@ -380,7 +381,8 @@ enum class P_TYPE : char {
LAYOUT_BREAK,
VALUE_TYPE,
BEAM_MODE,
PLACEMENT,
PLACEMENT, // ABOVE or BELOW
HPLACEMENT, // LEFT, CENTER or RIGHT
TEXT_PLACE,
TEMPO,
GROUPS,
Expand Down
4 changes: 3 additions & 1 deletion libmscore/style.cpp
Expand Up @@ -825,8 +825,10 @@ static const StyleType styleTypes[] {
{ Sid::measureNumberFontSpatiumDependent, "measureNumberFontSpatiumDependent", true },
{ Sid::measureNumberFontStyle, "measureNumberFontStyle", int(FontStyle::Normal) },
{ Sid::measureNumberColor, "measureNumberColor", QColor(0, 0, 0, 255) },
{ Sid::measureNumberOffset, "measureNumberOffset", QPointF(0.0, -2.0) },
{ Sid::measureNumberOffset, "measureNumberOffset", QPointF(0.0, 0.0) },
{ Sid::measureNumberOffsetType, "measureNumberOffsetType", int(OffsetType::SPATIUM) },
{ Sid::measureNumberVPlacement, "measureNumberVPlacement", int(Placement::ABOVE) },
{ Sid::measureNumberHPlacement, "measureNumberHPlacement", int(HPlacement::LEFT) },
{ Sid::measureNumberAlign, "measureNumberAlign", QVariant::fromValue(Align::HCENTER | Align::BASELINE) },
{ Sid::measureNumberFrameType, "measureNumberFrameType", int(FrameType::NO_FRAME) },
{ Sid::measureNumberFramePadding, "measureNumberFramePadding", 0.2 },
Expand Down
4 changes: 3 additions & 1 deletion libmscore/style.h
Expand Up @@ -336,8 +336,8 @@ enum class Sid {
showMeasureNumberOne,
measureNumberInterval,
measureNumberSystem,

measureNumberAllStaves,

smallNoteMag,
graceNoteMag,
smallStaffMag,
Expand Down Expand Up @@ -801,6 +801,8 @@ enum class Sid {
measureNumberColor,
measureNumberOffset,
measureNumberOffsetType,
measureNumberVPlacement,
measureNumberHPlacement,
measureNumberAlign,
measureNumberFrameType,
measureNumberFramePadding,
Expand Down

0 comments on commit 8089119

Please sign in to comment.