Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion src/engraving/dom/keysig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ bool KeySig::isChange() const
if (!segment() || segment()->segmentType() != SegmentType::KeySig) {
return false;
}
Fraction keyTick = tick();
const Fraction keyTick = tick();
return staff()->currentKeyTick(keyTick) == keyTick;
}

Expand Down Expand Up @@ -197,12 +197,41 @@ PointF KeySig::staffOffset() const
return PointF(0.0, 0.0);
}

EngravingObject* KeySig::propertyDelegate(Pid propertyId) const
{
if (!_isCourtesy) {
return nullptr;
}
switch (propertyId) {
case Pid::KEY:
case Pid::KEY_CONCERT:
case Pid::SHOW_COURTESY:
case Pid::KEYSIG_MODE:
case Pid::IS_COURTESY:
{
Segment* thisSeg = segment();
Segment* nextKSSeg = thisSeg ? thisSeg->next1(SegmentType::KeySig) : nullptr;
if (nextKSSeg && nextKSSeg->tick() == thisSeg->tick()) {
return nextKSSeg->element(track());
}
break;
}
default:
break;
}

return nullptr;
}

//---------------------------------------------------------
// getProperty
//---------------------------------------------------------

PropertyValue KeySig::getProperty(Pid propertyId) const
{
if (EngravingObject* e = propertyDelegate(propertyId)) {
return e->getProperty(propertyId);
}
switch (propertyId) {
case Pid::KEY:
return int(key());
Expand All @@ -225,6 +254,9 @@ PropertyValue KeySig::getProperty(Pid propertyId) const

bool KeySig::setProperty(Pid propertyId, const PropertyValue& v)
{
if (EngravingObject* e = propertyDelegate(propertyId)) {
return e->setProperty(propertyId, v);
}
switch (propertyId) {
case Pid::KEY:
if (generated()) {
Expand Down
1 change: 1 addition & 0 deletions src/engraving/dom/keysig.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ class KeySig final : public EngravingItem
PropertyValue getProperty(Pid propertyId) const override;
bool setProperty(Pid propertyId, const PropertyValue&) override;
PropertyValue propertyDefault(Pid id) const override;
EngravingObject* propertyDelegate(Pid) const override;

EngravingItem* nextSegmentElement() override;
EngravingItem* prevSegmentElement() override;
Expand Down
2 changes: 1 addition & 1 deletion src/engraving/rendering/score/measurelayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2561,7 +2561,7 @@ Segment* MeasureLayout::addHeaderKeySig(Measure* m, bool isFirstKeysig, const St
KeySigEvent keyIdx = staff->keySigEvent(m->tick());
KeySig* ksAnnounce = 0;
if ((isFirstKeysig || ctx.conf().styleB(Sid::genKeysig)) && (keyIdx.key() == Key::C)) {
Measure* pm = m->prevMeasure();
Measure* pm = m->prevMeasureMM();
if (pm && pm->hasCourtesyKeySig()) {
Segment* ks = pm->first(SegmentType::KeySigAnnounce);
if (ks) {
Expand Down
236 changes: 87 additions & 149 deletions src/engraving/rendering/score/tlayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3653,7 +3653,7 @@ static void keySigAddLayout(const KeySig* item, const LayoutConfiguration& conf,
KeySym ks;
ks.sym = sym;
double x = 0.0;
if (ldata->keySymbols.size() > 0) {
if (!ldata->keySymbols.empty()) {
const KeySym& previous = ldata->keySymbols.back();
double accidentalGap = conf.styleS(Sid::keysigAccidentalDistance).val();
if (previous.sym != sym) {
Expand Down Expand Up @@ -3688,40 +3688,38 @@ void TLayout::layoutKeySig(const KeySig* item, KeySig::LayoutData* ldata, const
// return;
// }

double spatium = item->spatium();
double step = spatium * (item->staff() ? item->staff()->staffTypeForElement(item)->lineDistance().val() * 0.5 : 0.5);

ldata->setBbox(RectF());

ldata->keySymbols.clear();
if (item->staff() && !item->staff()->staffType(item->tick())->genKeysig()) {

const StaffType* st = item->staffType();
if (st && !st->genKeysig()) {
return;
}
const Segment* s = item->segment();
track_idx_t track = item->track();
double spatium = item->spatium();
double step = spatium * (st ? st->lineDistance().val() * 0.5 : 0.5);

// determine current clef for this staff
ClefType clef = ClefType::G;
if (item->staff()) {
// Look for a clef before the key signature at the same tick
Clef* c = nullptr;
if (item->segment()) {
for (Segment* seg = item->segment()->prev1(); !c && seg && seg->tick() == item->tick(); seg = seg->prev1()) {
const bool isClefSeg
= (seg->isClefType() || seg->isHeaderClefType()
|| (seg->isClefRepeatAnnounceType() && item->segment()->isKeySigRepeatAnnounceType()));
if (s) {
for (Segment* seg = s->prev1(); !c && seg && seg->tick() == item->tick(); seg = seg->prev1()) {
const bool isClefSeg = seg->isClefType() || seg->isHeaderClefType()
|| (seg->isClefRepeatAnnounceType() && s->isKeySigRepeatAnnounceType());
if (seg->enabled() && isClefSeg) {
c = toClef(seg->element(item->track()));
c = toClef(seg->element(track));
}
}
}
if (c) {
clef = c->clefType();
} else {
// no clef found, so get the clef type from the clefs list, using the previous tick
clef = item->staff()->clef(item->tick() - Fraction::eps());
}
// If no clef found, get the clef type from the clefs list (using the previous tick)
clef = c ? c->clefType() : item->staff()->clef(item->tick() - Fraction::eps());
}

int t1 = int(item->key());
const signed char* lines = ClefInfo::lines(clef);

if (item->isCustom() && !item->isAtonal()) {
double accidentalGap = conf.styleS(Sid::keysigAccidentalDistance).val();
Expand All @@ -3740,8 +3738,8 @@ void TLayout::layoutKeySig(const KeySig* item, KeySig::LayoutData* ldata, const
KeySym ks;
int lineIndexOffset = t1 > 0 ? -1 : 6;
ks.sym = t1 > 0 ? SymId::accidentalSharp : SymId::accidentalFlat;
ks.line = ClefInfo::lines(clef)[lineIndexOffset + i];
if (ldata->keySymbols.size() > 0) {
ks.line = lines[lineIndexOffset + i];
if (!ldata->keySymbols.empty()) {
const KeySym& previous = ldata->keySymbols.back();
double previousWidth = item->symWidth(previous.sym) / spatium;
ks.xPos = previous.xPos + previousWidth + accidentalGap;
Expand All @@ -3758,9 +3756,9 @@ void TLayout::layoutKeySig(const KeySig* item, KeySig::LayoutData* ldata, const
bool flat = std::string(SymNames::nameForSymId(sym).ascii()).find("Flat") != std::string::npos;
int accIdx = (degree * 2 + 1) % 7; // C D E F ... index to F C G D index
accIdx = flat ? 13 - accIdx : accIdx;
int line = ClefInfo::lines(clef)[accIdx] + cd.octAlt * 7;
int line = lines[accIdx] + cd.octAlt * 7;
double xpos = cd.xAlt;
if (ldata->keySymbols.size() > 0) {
if (!ldata->keySymbols.empty()) {
const KeySym& previous = ldata->keySymbols.back();
double previousWidth = item->symWidth(previous.sym) / spatium;
xpos += previous.xPos + previousWidth + accidentalGap;
Expand Down Expand Up @@ -3791,147 +3789,87 @@ void TLayout::layoutKeySig(const KeySig* item, KeySig::LayoutData* ldata, const
}
}
} else {
int accidentals = 0, naturals = 0;
switch (std::abs(t1)) {
case 7: accidentals = 0x7f;
break;
case 6: accidentals = 0x3f;
break;
case 5: accidentals = 0x1f;
break;
case 4: accidentals = 0xf;
break;
case 3: accidentals = 0x7;
break;
case 2: accidentals = 0x3;
break;
case 1: accidentals = 0x1;
break;
case 0: accidentals = 0;
break;
default:
LOGD("illegal t1 key %d", t1);
break;
}

// manage display of naturals:
// naturals are shown if there is some natural AND prev. measure has no section break
// AND style says they are not off
// OR key sig is CMaj/Amin (in which case they are always shown)

bool naturalsOn = false;
Measure* prevMeasure = item->measure() ? item->measure()->prevMeasure() : 0;

// If we're not force hiding naturals (Continuous panel), use score style settings
if (!item->hideNaturals()) {
const bool newSection = (!item->segment()
|| (item->segment()->rtick().isZero() && (!prevMeasure || prevMeasure->sectionBreak()))
);
naturalsOn = !newSection && (conf.styleI(Sid::keySigNaturals) != int(KeySigNatural::NONE) || (t1 == 0));
}

// Don't repeat naturals if shown in courtesy
if (item->measure() && item->measure()->system() && item->measure()->isFirstInSystem()
&& prevMeasure && prevMeasure->findSegment(SegmentType::KeySigAnnounce, item->tick())
&& !item->segment()->isKeySigAnnounceType()) {
naturalsOn = false;
}
if (item->track() == muse::nidx) {
naturalsOn = false;
}

int coffset = 0;
Key t2 = Key::C;
if (naturalsOn) {
if (item->staff()) {
t2 = item->staff()->key(item->tick() - Fraction::eps());
auto layoutSharpsFlats = [&]() {
if (std::abs(t1) > 7) {
LOGD("illegal t1 key %d", t1);
return;
}
if (item->segment() && item->segment()->isType(SegmentType::KeySigStartRepeatAnnounce)) {
// Handle naturals in continuation courtesy
Segment* prevCourtesySeg
= prevMeasure ? prevMeasure->findSegmentR(SegmentType::KeySigRepeatAnnounce, prevMeasure->ticks()) : nullptr;
EngravingItem* prevCourtesy = prevCourtesySeg ? prevCourtesySeg->element(item->track()) : nullptr;
t2 = prevCourtesy && prevCourtesy->isKeySig() ? toKeySig(prevCourtesy)->key() : t2;
}
if (t2 == Key::C) {
naturalsOn = false;
} else {
switch (std::abs(int(t2))) {
case 7: naturals = 0x7f;
break;
case 6: naturals = 0x3f;
break;
case 5: naturals = 0x1f;
break;
case 4: naturals = 0xf;
break;
case 3: naturals = 0x7;
break;
case 2: naturals = 0x3;
break;
case 1: naturals = 0x1;
break;
case 0: naturals = 0;
break;
default:
LOGD("illegal t2 key %d", int(t2));
break;
}
// remove redundant naturals
if (!((t1 > 0) ^ (t2 > 0))) {
naturals &= ~accidentals;
}
if (t2 < 0) {
coffset = 7;
}
}
}

// naturals should go BEFORE accidentals if style says so
// OR going from sharps to flats or vice versa (i.e. t1 & t2 have opposite signs)

bool prefixNaturals = naturalsOn
&& (conf.styleI(Sid::keySigNaturals) == int(KeySigNatural::BEFORE)
|| t1 * int(t2) < 0);

// naturals should go AFTER accidentals if they should not go before!
bool suffixNaturals = naturalsOn && !prefixNaturals;

const signed char* lines = ClefInfo::lines(clef);

if (prefixNaturals) {
for (int i = 0; i < 7; ++i) {
if (naturals & (1 << i)) {
keySigAddLayout(item, conf, SymId::accidentalNatural, lines[i + coffset], ldata);
}
}
}
if (std::abs(t1) <= 7) {
SymId symbol = t1 > 0 ? SymId::accidentalSharp : SymId::accidentalFlat;
int lineIndexOffset = t1 > 0 ? 0 : 7;
for (int i = 0; i < std::abs(t1); ++i) {
keySigAddLayout(item, conf, symbol, lines[lineIndexOffset + i], ldata);
}
} else {
LOGD("illegal t1 key %d", t1);
}
};

// Naturals are shown if:
// Key signature is courtesy, mid-measure or prev. measure has no section break and no courtesy keysig.
// AND we're not force hiding naturals (continuous mode)
// AND key sig is CMaj/Amin OR style says they are on
const Measure* pm = item->measure() ? item->measure()->prevMeasureMM() : nullptr;
if (!item->hideNaturals() && track != muse::nidx
&& (conf.styleI(Sid::keySigNaturals) != int(KeySigNatural::NONE) || (t1 == 0))
&& ((s && (s->isType(SegmentType::CourtesyKeySigType) || !s->rtick().isZero()))
|| (pm && !pm->sectionBreak() && !pm->hasCourtesyKeySig()))) {
int t2 = item->staff() ? int(item->staff()->key(item->tick() - Fraction::eps())) : 0;

// Handle naturals in continuation courtesy
if (pm && s && s->isType(SegmentType::KeySigStartRepeatAnnounce)) {
Segment* prevCourtesySeg = pm->findSegmentR(SegmentType::KeySigRepeatAnnounce, pm->ticks());
if (prevCourtesySeg && prevCourtesySeg->element(track)) {
t2 = int(toKeySig(prevCourtesySeg->element(track))->key());
}
}
// Don't show naturals when going from sharps to flats, if style says so
const bool sameAccidentals = t1 * t2 >= 0;
if (t2 != 0 && (sameAccidentals || conf.styleB(Sid::keySigShowNaturalsChangingSharpsFlats))) {
auto key2accidentals = [](int key) -> int {
switch (std::abs(key)) {
case 7: return 0x7f;
case 6: return 0x3f;
case 5: return 0x1f;
case 4: return 0xf;
case 3: return 0x7;
case 2: return 0x3;
case 1: return 0x1;
case 0: return 0;
default:
LOGD("illegal key %d", key);
return 0;
}
};

// add suffixed naturals, if any
if (suffixNaturals) {
for (int i = 0; i < 7; ++i) {
if (naturals & (1 << i)) {
keySigAddLayout(item, conf, SymId::accidentalNatural, lines[i + coffset], ldata);
int naturals = key2accidentals(t2);
// remove redundant naturals
if (!((t1 > 0) ^ (t2 > 0))) {
naturals &= ~key2accidentals(t1);
}
auto layoutNaturals = [&]() {
int lineIndexOffset = t2 > 0 ? 0 : 7;
for (int i = 0; i < 7; ++i) {
if (naturals & (1 << i)) {
keySigAddLayout(item, conf, SymId::accidentalNatural, lines[i + lineIndexOffset], ldata);
}
}
};
// Naturals should go BEFORE accidentals if style says so
// or going from sharps to flats or vice versa (i.e. t1 & t2 have opposite signs)
if (conf.styleI(Sid::keySigNaturals) == int(KeySigNatural::BEFORE) || !sameAccidentals) {
layoutNaturals();
layoutSharpsFlats();
} else {
layoutSharpsFlats();
layoutNaturals();
}
}
}

// Follow stepOffset
if (item->staffType()) {
ldata->setPosY(item->staffType()->stepOffset() * 0.5 * spatium);
// No naturals were added, so just create a regular keysig
if (ldata->keySymbols.empty()) {
layoutSharpsFlats();
}
}

ldata->moveY(item->staffOffsetY());
ldata->setPosY((st ? step * st->stepOffset() : 0.0) + item->staffOffsetY());

Shape keySigShape;
for (const KeySym& ks : ldata->keySymbols) {
Expand Down
Loading
Loading