Implements automatic bracketing and bar line spanning.
This commit is contained in:
parent
980d36edc4
commit
3d7011315a
5 changed files with 234 additions and 51 deletions
|
@ -3765,6 +3765,15 @@ void Score::setScoreOrder(ScoreOrder order)
|
|||
_scoreOrder = order;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// setBracketsAndBarlines
|
||||
//---------------------------------------------------------
|
||||
|
||||
void Score::setBracketsAndBarlines()
|
||||
{
|
||||
scoreOrder().setBracketsAndBarlines(this);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// lassoSelect
|
||||
//---------------------------------------------------------
|
||||
|
|
|
@ -1030,6 +1030,7 @@ public:
|
|||
|
||||
ScoreOrder scoreOrder() const;
|
||||
void setScoreOrder(ScoreOrder order);
|
||||
void setBracketsAndBarlines();
|
||||
|
||||
void lassoSelect(const mu::RectF&);
|
||||
void lassoSelectEnd(bool);
|
||||
|
|
|
@ -94,60 +94,44 @@ void ScoreOrder::readSoloists(Ms::XmlReader& reader, const QString section)
|
|||
groups << sg;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// readUnsorted
|
||||
//---------------------------------------------------------
|
||||
|
||||
void ScoreOrder::readUnsorted(Ms::XmlReader& reader, const QString section, bool inSection)
|
||||
{
|
||||
QString group { reader.attribute("group", QString("")) };
|
||||
reader.skipCurrentElement();
|
||||
|
||||
if (hasGroup(UNSORTED_ID, group)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ScoreGroup sg;
|
||||
sg.family = QString(UNSORTED_ID);
|
||||
sg.section = section;
|
||||
sg.unsorted = group;
|
||||
sg.bracket = !inSection ? true : false;
|
||||
sg.showSystemMarkings = !inSection ? false : readBoolAttribute(reader, "showSystemMarkings", false);
|
||||
sg.barLineSpan = !inSection ? false : readBoolAttribute(reader, "barLineSpan", true);
|
||||
sg.thinBracket = !inSection ? false : readBoolAttribute(reader, "thinBrackets", true);
|
||||
groups << sg;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// readFamily
|
||||
//---------------------------------------------------------
|
||||
|
||||
void ScoreOrder::readFamily(Ms::XmlReader& reader, const QString section, bool inSection)
|
||||
{
|
||||
const QString id { reader.readElementText().toUtf8().data() };
|
||||
|
||||
ScoreGroup sg;
|
||||
sg.family = id;
|
||||
sg.section = section;
|
||||
sg.bracket = !inSection ? false : true;
|
||||
sg.showSystemMarkings = !inSection ? false : readBoolAttribute(reader, "showSystemMarkings", false);
|
||||
sg.barLineSpan = !inSection ? false : readBoolAttribute(reader, "barLineSpan", true);
|
||||
sg.thinBracket = !inSection ? false : readBoolAttribute(reader, "thinBrackets", true);
|
||||
groups << sg;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// readSection
|
||||
//---------------------------------------------------------
|
||||
|
||||
void ScoreOrder::readSection(Ms::XmlReader& reader)
|
||||
{
|
||||
QString id { reader.attribute("id") };
|
||||
QString sectionId { reader.attribute("id") };
|
||||
bool showSystemMarkings = readBoolAttribute(reader, "showSystemMarkings", false);
|
||||
bool barLineSpan = readBoolAttribute(reader, "barLineSpan", true);
|
||||
bool thinBrackets = readBoolAttribute(reader, "thinBrackets", true);
|
||||
while (reader.readNextStartElement()) {
|
||||
if (reader.name() == "family") {
|
||||
readFamily(reader, id, true);
|
||||
ScoreGroup sg;
|
||||
sg.family = reader.readElementText().toUtf8().data();
|
||||
sg.section = sectionId;
|
||||
sg.bracket = true;
|
||||
sg.showSystemMarkings = showSystemMarkings;
|
||||
sg.barLineSpan = barLineSpan;
|
||||
sg.thinBracket = thinBrackets;
|
||||
groups << sg;
|
||||
} else if (reader.name() == "unsorted") {
|
||||
readUnsorted(reader, id, true);
|
||||
QString group { reader.attribute("group", QString("")) };
|
||||
|
||||
if (hasGroup(UNSORTED_ID, group)) {
|
||||
reader.skipCurrentElement();
|
||||
return;
|
||||
}
|
||||
|
||||
ScoreGroup sg;
|
||||
sg.family = QString(UNSORTED_ID);
|
||||
sg.section = sectionId;
|
||||
sg.unsorted = group;
|
||||
sg.bracket = false;
|
||||
sg.showSystemMarkings = readBoolAttribute(reader, "showSystemMarkings", false);
|
||||
sg.barLineSpan = readBoolAttribute(reader, "barLineSpan", true);
|
||||
sg.thinBracket = readBoolAttribute(reader, "thinBrackets", true);
|
||||
groups << sg;
|
||||
reader.skipCurrentElement();
|
||||
} else {
|
||||
reader.unknown();
|
||||
}
|
||||
|
@ -177,6 +161,155 @@ bool ScoreOrder::isValid() const
|
|||
return !id.isEmpty();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// getFamilyName
|
||||
//---------------------------------------------------------
|
||||
|
||||
QString ScoreOrder::getFamilyName(const InstrumentTemplate* instrTemplate, bool soloist) const
|
||||
{
|
||||
if (!instrTemplate) {
|
||||
return QString("<unsorted>");
|
||||
}
|
||||
|
||||
if (soloist) {
|
||||
return QString("<soloists>");
|
||||
} else if (instrumentMap.contains(instrTemplate->id)) {
|
||||
return instrumentMap[instrTemplate->id].id;
|
||||
} else if (instrTemplate->family) {
|
||||
return instrTemplate->family->id;
|
||||
}
|
||||
return QString("<unsorted>");
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// getGroup
|
||||
//---------------------------------------------------------
|
||||
|
||||
ScoreGroup ScoreOrder::getGroup(const QString family, const QString instrumentGroup) const
|
||||
{
|
||||
static const QString UNSORTED = QString("<unsorted>");
|
||||
|
||||
ScoreGroup unsortedScoreGroup;
|
||||
for (const ScoreGroup& sg : groups) {
|
||||
if ((sg.family == UNSORTED) && sg.unsorted.isEmpty()) {
|
||||
unsortedScoreGroup = sg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (family.isEmpty()) {
|
||||
return unsortedScoreGroup;
|
||||
}
|
||||
|
||||
for (const ScoreGroup& sg : groups) {
|
||||
if (sg.family == family) {
|
||||
return sg;
|
||||
}
|
||||
if ((sg.family == UNSORTED) && (sg.unsorted == instrumentGroup)) {
|
||||
unsortedScoreGroup = sg;
|
||||
}
|
||||
}
|
||||
return unsortedScoreGroup;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// setBracketsAndBarlines
|
||||
//---------------------------------------------------------
|
||||
|
||||
void ScoreOrder::setBracketsAndBarlines(Score* score)
|
||||
{
|
||||
if (groups.size() <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool prvThnBracket { false };
|
||||
bool prvBarLineSpan { false };
|
||||
QString prvSection { "" };
|
||||
int prvInstrument { 0 };
|
||||
Staff* prvStaff { nullptr };
|
||||
|
||||
Staff* thkBracketStaff { nullptr };
|
||||
Staff* thnBracketStaff { nullptr };
|
||||
int thkBracketSpan { 0 };
|
||||
int thnBracketSpan { 0 };
|
||||
|
||||
for (Part* part : score->parts()) {
|
||||
InstrumentIndex ii = searchTemplateIndexForId(part->instrument()->getId());
|
||||
if (!ii.instrTemplate) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QString family { getFamilyName(ii.instrTemplate, part->soloist()) };
|
||||
const ScoreGroup sg = getGroup(family, instrumentGroups[ii.groupIndex]->id);
|
||||
|
||||
int staffIdx { 0 };
|
||||
bool blockThinBracket { false };
|
||||
for (Staff* staff : *part->staves()) {
|
||||
for (BracketItem* bi : staff->brackets()) {
|
||||
score->undo(new RemoveBracket(staff, bi->column(), bi->bracketType(), bi->bracketSpan()));
|
||||
}
|
||||
staff->undoChangeProperty(Pid::STAFF_BARLINE_SPAN, 0);
|
||||
|
||||
if (prvSection.isEmpty() || (sg.section != prvSection)) {
|
||||
if (thkBracketStaff && (thkBracketSpan > 1)) {
|
||||
score->undoAddBracket(thkBracketStaff, 0, BracketType::NORMAL, thkBracketSpan);
|
||||
}
|
||||
if (sg.bracket && !staffIdx) {
|
||||
thkBracketStaff = sg.bracket ? staff : nullptr;
|
||||
thkBracketSpan = 0;
|
||||
}
|
||||
}
|
||||
if (sg.bracket && !staffIdx) {
|
||||
thkBracketSpan += part->nstaves();
|
||||
}
|
||||
|
||||
if (!staffIdx || (ii.instrIndex != prvInstrument)) {
|
||||
if (thnBracketStaff && (thnBracketSpan > 1)) {
|
||||
score->undoAddBracket(thnBracketStaff, 1, BracketType::SQUARE, thnBracketSpan);
|
||||
}
|
||||
if (ii.instrIndex != prvInstrument) {
|
||||
thnBracketStaff = (sg.thinBracket && !blockThinBracket) ? staff : nullptr;
|
||||
thnBracketSpan = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (ii.instrTemplate->nstaves() > 1) {
|
||||
blockThinBracket = true;
|
||||
if (ii.instrTemplate->bracket[staffIdx] != BracketType::NO_BRACKET) {
|
||||
score->undoAddBracket(staff, 2, ii.instrTemplate->bracket[staffIdx], ii.instrTemplate->bracketSpan[staffIdx]);
|
||||
}
|
||||
staff->undoChangeProperty(Pid::STAFF_BARLINE_SPAN, ii.instrTemplate->barlineSpan[staffIdx]);
|
||||
if (staffIdx < ii.instrTemplate->nstaves()) {
|
||||
++staffIdx;
|
||||
}
|
||||
prvStaff = nullptr;
|
||||
} else {
|
||||
if (sg.thinBracket && !staffIdx) {
|
||||
thnBracketSpan += part->nstaves();
|
||||
}
|
||||
if (prvStaff) {
|
||||
prvStaff->undoChangeProperty(Pid::STAFF_BARLINE_SPAN,
|
||||
(prvBarLineSpan && (!prvSection.isEmpty() && (sg.section == prvSection))));
|
||||
}
|
||||
prvStaff = staff;
|
||||
++staffIdx;
|
||||
}
|
||||
prvSection = sg.section;
|
||||
prvBarLineSpan = sg.barLineSpan;
|
||||
prvThnBracket = sg.thinBracket;
|
||||
}
|
||||
|
||||
prvInstrument = ii.instrIndex;
|
||||
}
|
||||
|
||||
if (thkBracketStaff && (thkBracketSpan > 1)) {
|
||||
score->undoAddBracket(thkBracketStaff, 0, BracketType::NORMAL, thkBracketSpan);
|
||||
}
|
||||
if (thnBracketStaff && (thnBracketSpan > 1) && prvThnBracket) {
|
||||
score->undoAddBracket(thnBracketStaff, 1, BracketType::SQUARE, thnBracketSpan);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// read
|
||||
//---------------------------------------------------------
|
||||
|
@ -184,7 +317,7 @@ bool ScoreOrder::isValid() const
|
|||
void ScoreOrder::read(Ms::XmlReader& reader)
|
||||
{
|
||||
id = reader.attribute("id");
|
||||
const QString id { "" };
|
||||
const QString sectionId { "" };
|
||||
while (reader.readNextStartElement()) {
|
||||
if (reader.name() == "name") {
|
||||
name = qApp->translate("OrderXML", reader.readElementText().toUtf8().data());
|
||||
|
@ -193,11 +326,34 @@ void ScoreOrder::read(Ms::XmlReader& reader)
|
|||
} else if (reader.name() == "instrument") {
|
||||
readInstrument(reader);
|
||||
} else if (reader.name() == "family") {
|
||||
readFamily(reader, id, false);
|
||||
ScoreGroup sg;
|
||||
sg.family = reader.readElementText().toUtf8().data();
|
||||
sg.section = sectionId;
|
||||
sg.bracket = false;
|
||||
sg.showSystemMarkings = false;
|
||||
sg.barLineSpan = false;
|
||||
sg.thinBracket = false;
|
||||
groups << sg;
|
||||
} else if (reader.name() == "soloists") {
|
||||
readSoloists(reader, id);
|
||||
readSoloists(reader, sectionId);
|
||||
} else if (reader.name() == "unsorted") {
|
||||
readUnsorted(reader, id, false);
|
||||
QString group { reader.attribute("group", QString("")) };
|
||||
|
||||
if (hasGroup(UNSORTED_ID, group)) {
|
||||
reader.skipCurrentElement();
|
||||
return;
|
||||
}
|
||||
|
||||
ScoreGroup sg;
|
||||
sg.family = QString(UNSORTED_ID);
|
||||
sg.section = sectionId;
|
||||
sg.unsorted = group;
|
||||
sg.bracket = true;
|
||||
sg.showSystemMarkings = false;
|
||||
sg.barLineSpan = false;
|
||||
sg.thinBracket = false;
|
||||
groups << sg;
|
||||
reader.skipCurrentElement();
|
||||
} else {
|
||||
reader.unknown();
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#define __SCOREORDER_H__
|
||||
|
||||
#include "libmscore/mscore.h"
|
||||
#include "instrtemplate.h"
|
||||
|
||||
namespace Ms {
|
||||
//---------------------------------------------------------
|
||||
|
@ -68,12 +69,14 @@ struct ScoreOrder
|
|||
bool readBoolAttribute(Ms::XmlReader& reader, const char* name, bool defValue);
|
||||
void readInstrument(Ms::XmlReader& reader);
|
||||
void readSoloists(Ms::XmlReader& reader, const QString section);
|
||||
void readUnsorted(Ms::XmlReader& reader, const QString section, bool inSection);
|
||||
void readFamily(Ms::XmlReader& reader, const QString section, bool inSection);
|
||||
void readSection(Ms::XmlReader& reader);
|
||||
bool hasGroup(const QString& id, const QString& group=QString()) const;
|
||||
|
||||
bool isValid() const;
|
||||
QString getFamilyName(const InstrumentTemplate* instrTemplate, bool soloist) const;
|
||||
ScoreGroup getGroup(const QString family, const QString instrumentGroup) const;
|
||||
|
||||
void setBracketsAndBarlines(Score* score);
|
||||
|
||||
void read(Ms::XmlReader& reader);
|
||||
void write(Ms::XmlWriter& xml) const;
|
||||
|
|
|
@ -144,6 +144,8 @@ void NotationParts::setParts(const mu::instruments::PartInstrumentList& parts)
|
|||
|
||||
sortParts(parts, masterScore(), originalStaves);
|
||||
|
||||
masterScore()->setBracketsAndBarlines();
|
||||
|
||||
updateScore();
|
||||
|
||||
m_partsNotifier->changed();
|
||||
|
@ -153,6 +155,7 @@ void NotationParts::setScoreOrder(const instruments::ScoreOrder& order)
|
|||
{
|
||||
Ms::ScoreOrder so = ScoreOrderConverter::convertScoreOrder(order);
|
||||
masterScore()->undo(new Ms::ChangeScoreOrder(masterScore(), so));
|
||||
masterScore()->setBracketsAndBarlines();
|
||||
}
|
||||
|
||||
void NotationParts::setPartVisible(const ID& partId, bool visible)
|
||||
|
@ -660,6 +663,9 @@ void NotationParts::appendStaff(Staff* staff, const ID& destinationPartId)
|
|||
staff->setPart(destinationPart);
|
||||
|
||||
insertStaff(staff, staffIndex);
|
||||
|
||||
masterScore()->setBracketsAndBarlines();
|
||||
|
||||
updateScore();
|
||||
|
||||
Ms::Instrument* instrument = instrumentInfo.instrument;
|
||||
|
@ -737,6 +743,8 @@ void NotationParts::removeParts(const IDList& partsIds)
|
|||
|
||||
sortParts(parts, masterScore(), originalStaves);
|
||||
|
||||
masterScore()->setBracketsAndBarlines();
|
||||
|
||||
updateScore();
|
||||
}
|
||||
|
||||
|
@ -799,6 +807,7 @@ void NotationParts::removeStaves(const IDList& stavesIds)
|
|||
score()->cmdRemoveStaff(staff->idx());
|
||||
}
|
||||
|
||||
masterScore()->setBracketsAndBarlines();
|
||||
updateScore();
|
||||
}
|
||||
|
||||
|
@ -846,6 +855,8 @@ void NotationParts::moveParts(const IDList& sourcePartsIds, const ID& destinatio
|
|||
|
||||
sortParts(parts, masterScore(), masterScore()->staves());
|
||||
|
||||
masterScore()->setBracketsAndBarlines();
|
||||
|
||||
updateScore();
|
||||
|
||||
m_partsNotifier->changed();
|
||||
|
@ -1046,6 +1057,9 @@ void NotationParts::moveStaves(const IDList& sourceStavesIds, const ID& destinat
|
|||
destinationStaffIndex -= score()->staffIdx(destinationPart); // NOTE: convert to local part's staff index
|
||||
|
||||
doMoveStaves(staves, destinationStaffIndex, destinationPart);
|
||||
|
||||
masterScore()->setBracketsAndBarlines();
|
||||
|
||||
updateScore();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue