diff --git a/src/engraving/dom/fret.h b/src/engraving/dom/fret.h index 0e58fe0f877dd..ae243a64b5135 100644 --- a/src/engraving/dom/fret.h +++ b/src/engraving/dom/fret.h @@ -234,7 +234,7 @@ class FretDiagram final : public EngravingItem bool setProperty(Pid propertyId, const PropertyValue&) override; PropertyValue propertyDefault(Pid) const override; - virtual void setVisible(bool f); + void setVisible(bool f) override; void setTrack(track_idx_t val) override; diff --git a/src/engraving/dom/harmony.h b/src/engraving/dom/harmony.h index 52702d6ffa3a5..1f7e0a9c3f1fd 100644 --- a/src/engraving/dom/harmony.h +++ b/src/engraving/dom/harmony.h @@ -84,22 +84,22 @@ struct HarmonyRenderItem { struct ChordSymbolParen : HarmonyRenderItem { ChordSymbolParen(Parenthesis* p, bool hAlign, double _x, double _y) - : HarmonyRenderItem(hAlign, _x, _y), paren(p) {} - ~ChordSymbolParen() { delete paren; } + : HarmonyRenderItem(hAlign, _x, _y), parenItem(p) {} + ~ChordSymbolParen() { delete parenItem; } - RectF boundingRect() const override { return paren->shape().bbox(); } - RectF tightBoundingRect() const override { return paren->shape().bbox(); } + RectF boundingRect() const override { return parenItem->shape().bbox(); } + RectF tightBoundingRect() const override { return parenItem->shape().bbox(); } double top = DBL_MAX; double bottom = -DBL_MAX; double closingParenPos = -DBL_MAX; - Parenthesis* paren = nullptr; + Parenthesis* parenItem = nullptr; - double height() const override { return paren->height(); } + double height() const override { return parenItem->height(); } - double leftPadding() const override { return paren->direction() == DirectionH::LEFT ? OUTER_PADDING : INNER_PADDING; } - double rightPadding() const override { return paren->direction() == DirectionH::LEFT ? INNER_PADDING : OUTER_PADDING; } + double leftPadding() const override { return parenItem->direction() == DirectionH::LEFT ? OUTER_PADDING : INNER_PADDING; } + double rightPadding() const override { return parenItem->direction() == DirectionH::LEFT ? INNER_PADDING : OUTER_PADDING; } double bboxBaseLine() const override { return bottom; } diff --git a/src/engraving/rendering/score/harmonylayout.cpp b/src/engraving/rendering/score/harmonylayout.cpp index 3a0487ccc6e1f..ff7cc3293ee11 100644 --- a/src/engraving/rendering/score/harmonylayout.cpp +++ b/src/engraving/rendering/score/harmonylayout.cpp @@ -202,11 +202,13 @@ void HarmonyLayout::layoutModifierParentheses(const Harmony* item) const std::vector& itemList = item->ldata()->renderItemList(); // Layout parentheses std::vector openingParenStack; + double lastTextSegHeight = 0.0; + double lastTextSegTop = 0.0; for (HarmonyRenderItem* renderItem : itemList) { - if (ChordSymbolParen* paren = dynamic_cast(renderItem)) { - if (paren->paren->direction() == DirectionH::LEFT) { + if (ChordSymbolParen* curParen = dynamic_cast(renderItem)) { + if (curParen->parenItem->direction() == DirectionH::LEFT) { // Opening paren - openingParenStack.push_back(paren); + openingParenStack.push_back(curParen); } else { // Closing paren ChordSymbolParen* openingParen = openingParenStack.empty() ? nullptr : openingParenStack.back(); @@ -214,29 +216,39 @@ void HarmonyLayout::layoutModifierParentheses(const Harmony* item) continue; } openingParenStack.pop_back(); - paren->top = openingParen->top; - paren->bottom = openingParen->bottom; + curParen->top = openingParen->top; + curParen->bottom = openingParen->bottom; // Layout parenthesis pair double startY = openingParen->top; double height = openingParen->bottom - openingParen->top; - double midPointThickness = height / 30 * openingParen->paren->ldata()->mag(); + if (std::isinf(height)) { + height = lastTextSegHeight; + } + if (muse::RealIsEqual(DBL_MAX, startY)) { + startY = lastTextSegTop; + } + double midPointThickness = height / 30 * openingParen->parenItem->ldata()->mag(); double endPointThickness = 0.05; - openingParen->paren->mutldata()->startY = startY; + openingParen->parenItem->mutldata()->startY = startY; openingParen->sety(startY); - openingParen->paren->mutldata()->height = height; - openingParen->paren->mutldata()->midPointThickness.set_value(midPointThickness); - openingParen->paren->mutldata()->endPointThickness.set_value(endPointThickness); - - paren->paren->mutldata()->startY = startY; - paren->sety(startY); - paren->paren->mutldata()->height = height; - paren->paren->mutldata()->midPointThickness.set_value(midPointThickness); - paren->paren->mutldata()->endPointThickness.set_value(endPointThickness); - paren->setx(openingParen->closingParenPos); + openingParen->parenItem->mutldata()->height = height; + openingParen->parenItem->mutldata()->midPointThickness.set_value(midPointThickness); + openingParen->parenItem->mutldata()->endPointThickness.set_value(endPointThickness); + + curParen->parenItem->mutldata()->startY = startY; + curParen->sety(startY); + curParen->parenItem->mutldata()->height = height; + curParen->parenItem->mutldata()->midPointThickness.set_value(midPointThickness); + curParen->parenItem->mutldata()->endPointThickness.set_value(endPointThickness); + double closingPos = openingParen->closingParenPos; + if (muse::RealIsEqual(-DBL_MAX, closingPos)) { + closingPos = openingParen->x() + openingParen->boundingRect().width(); + } + curParen->setx(closingPos); - ParenthesisLayout::createPathAndShape(openingParen->paren, openingParen->paren->mutldata()); - ParenthesisLayout::createPathAndShape(paren->paren, paren->paren->mutldata()); + ParenthesisLayout::createPathAndShape(openingParen->parenItem, openingParen->parenItem->mutldata()); + ParenthesisLayout::createPathAndShape(curParen->parenItem, curParen->parenItem->mutldata()); // Outer parens must always be the same length or longer than inner parens for (ChordSymbolParen* outerParen : openingParenStack) { @@ -244,13 +256,15 @@ void HarmonyLayout::layoutModifierParentheses(const Harmony* item) outerParen->bottom = std::max(openingParen->bottom, outerParen->bottom); } } - } else if (TextSegment* ts = dynamic_cast(renderItem)) { + } else if (TextSegment* textSeg = dynamic_cast(renderItem)) { // Set top paren height + lastTextSegHeight = textSeg->height(); + lastTextSegTop = textSeg->boundingRect().translated(textSeg->pos()).y(); if (!openingParenStack.empty()) { ChordSymbolParen* topParen = openingParenStack.back(); - topParen->top = std::min(topParen->top, ts->boundingRect().translated(ts->pos()).y()); - topParen->bottom = std::max(topParen->bottom, ts->boundingRect().translated(ts->pos()).y() + ts->boundingRect().height()); - topParen->closingParenPos = std::max(topParen->closingParenPos, ts->x() + ts->width()); + topParen->top = std::min(topParen->top, textSeg->boundingRect().translated(textSeg->pos()).y()); + topParen->bottom = std::max(topParen->bottom, textSeg->boundingRect().translated(textSeg->pos()).y() + textSeg->height()); + topParen->closingParenPos = std::max(topParen->closingParenPos, textSeg->x() + textSeg->width()); continue; } } @@ -282,13 +296,13 @@ void HarmonyLayout::layoutModifierParentheses(const Harmony* item) double padding = i != 0 ? computePadding(itemList.at(i - 1), renderItem) : 0.0; if (ChordSymbolParen* paren = dynamic_cast(renderItem)) { - if (paren->paren->direction() == DirectionH::LEFT) { - additionalSpace += paren->paren->width() + padding; + if (paren->parenItem->direction() == DirectionH::LEFT) { + additionalSpace += paren->parenItem->width() + padding; paren->movex(additionalSpace); } - if (paren->paren->direction() == DirectionH::RIGHT) { + if (paren->parenItem->direction() == DirectionH::RIGHT) { paren->movex(additionalSpace + padding); - additionalSpace += paren->paren->width() + padding; + additionalSpace += paren->parenItem->width() + padding; } } else if (TextSegment* ts = dynamic_cast(renderItem)) { additionalSpace += padding; diff --git a/src/engraving/rendering/score/measurelayout.cpp b/src/engraving/rendering/score/measurelayout.cpp index f3ae17dd1f3e8..eb701614ba87c 100644 --- a/src/engraving/rendering/score/measurelayout.cpp +++ b/src/engraving/rendering/score/measurelayout.cpp @@ -54,6 +54,7 @@ #include "dom/utils.h" #include "types/typesconv.h" +#include "autoplace.h" #include "tlayout.h" #include "layoutcontext.h" #include "arpeggiolayout.h" diff --git a/src/engraving/rendering/score/parenthesislayout.cpp b/src/engraving/rendering/score/parenthesislayout.cpp index a617685ead087..7c5afebd6d6ad 100644 --- a/src/engraving/rendering/score/parenthesislayout.cpp +++ b/src/engraving/rendering/score/parenthesislayout.cpp @@ -253,6 +253,11 @@ void ParenthesisLayout::createPathAndShape(Parenthesis* item, Parenthesis::Layou const double heightInSpatium = height / spatium; const double shoulderYOffset = 0.2 * height; + if (std::isinf(height)) { + LOGE() << "Error: parenthesis height is infinite"; + return; + } + // Control width of parentheses. We don't want tall parens to be too wide, nor do we want parens at a small scale to lose their curve too much double shoulderX = ldata->shoulderWidth.has_value() ? ldata->shoulderWidth() : 0.2 * std::pow(height, 0.95) * std::pow(mag, 0.1); const double minShoulderX = 0.25 * spatium; diff --git a/src/engraving/rendering/score/systemlayout.cpp b/src/engraving/rendering/score/systemlayout.cpp index 431d3cc378a5a..207ab93cbb16f 100644 --- a/src/engraving/rendering/score/systemlayout.cpp +++ b/src/engraving/rendering/score/systemlayout.cpp @@ -426,9 +426,11 @@ System* SystemLayout::collectSystem(LayoutContext& ctx) if (oldSystem && !oldSystem->measures().empty() && oldSystem->measures().front()->tick() >= system->endTick() && !(oldSystem->page() && oldSystem->page() != ctx.state().page())) { - // We may have previously processed the ties of the next system (in LayoutChords::updateLineAttachPoints()). - // We need to restore them to the correct state. - SystemLayout::restoreTiesAndBends(oldSystem, ctx); + // We may have unfinished layouts of certain elements in the next system + // - ties & bends (in LayoutChords::updateLineAttachPoints()) + // - fret diagrams & harmony (in layoutMeasure) + // Restore them to the correct state. + SystemLayout::restoreOldSystemLayout(oldSystem, ctx); } return system; @@ -990,19 +992,53 @@ void SystemLayout::layoutParenthesisAndBigTimeSigs(const ElementsToLayout& eleme } } -void SystemLayout::layoutHarmonies(const std::vector harmonies, System* system, bool verticalAlign, LayoutContext& ctx) +void SystemLayout::layoutHarmonies(const std::vector harmonies, System* system, LayoutContext& ctx) { for (Harmony* harmony : harmonies) { TLayout::layoutHarmony(harmony, harmony->mutldata(), ctx); Autoplace::autoplaceSegmentElement(harmony, harmony->mutldata()); } - if (ctx.conf().styleB(Sid::verticallyAlignChordSymbols) && verticalAlign) { + if (ctx.conf().styleB(Sid::verticallyAlignChordSymbols)) { std::vector harmonyItems(harmonies.begin(), harmonies.end()); AlignmentLayout::alignItemsForSystem(harmonyItems, system); } } +void SystemLayout::layoutFretDiagrams(const ElementsToLayout& elements, System* system, LayoutContext& ctx) +{ + for (FretDiagram* fretDiag : elements.fretDiagrams) { + Autoplace::autoplaceSegmentElement(fretDiag, fretDiag->mutldata()); + } + + if (ctx.conf().styleB(Sid::verticallyAlignChordSymbols)) { + std::vector fretItems(elements.fretDiagrams.begin(), elements.fretDiagrams.end()); + AlignmentLayout::alignItemsForSystem(fretItems, system); + } + + for (Harmony* harmony : elements.harmonies) { + FretDiagram* fdParent = harmony->parent()->isFretDiagram() ? toFretDiagram(harmony->parent()) : nullptr; + if (fdParent && !fdParent->visible()) { + harmony->mutldata()->moveY(-fdParent->pos().y()); + } + Autoplace::autoplaceSegmentElement(harmony, harmony->mutldata()); + } + + if (ctx.conf().styleB(Sid::verticallyAlignChordSymbols)) { + std::vector harmonyItems(elements.harmonies.begin(), elements.harmonies.end()); + AlignmentLayout::alignItemsForSystem(harmonyItems, system); + } + + for (FretDiagram* fretDiag : elements.fretDiagrams) { + if (Harmony* harmony = fretDiag->harmony()) { + SkylineLine& skl = system->staff(fretDiag->staffIdx())->skyline().north(); + Segment* s = fretDiag->segment(); + Shape harmShape = harmony->ldata()->shape().translated(harmony->pos() + fretDiag->pos() + s->pos() + s->measure()->pos()); + skl.add(harmShape); + } + } +} + void SystemLayout::layoutSystemElements(System* system, LayoutContext& ctx) { TRACEFUNC; @@ -1136,7 +1172,7 @@ void SystemLayout::layoutSystemElements(System* system, LayoutContext& ctx) bool hasFretDiagram = elementsToLayout.fretDiagrams.size() > 0; if (!hasFretDiagram) { - layoutHarmonies(elementsToLayout.harmonies, system, true, ctx); + layoutHarmonies(elementsToLayout.harmonies, system, ctx); } for (StaffText* st : elementsToLayout.staffText) { @@ -1152,36 +1188,7 @@ void SystemLayout::layoutSystemElements(System* system, LayoutContext& ctx) } if (hasFretDiagram) { - for (FretDiagram* fretDiag : elementsToLayout.fretDiagrams) { - Autoplace::autoplaceSegmentElement(fretDiag, fretDiag->mutldata()); - } - - if (ctx.conf().styleB(Sid::verticallyAlignChordSymbols)) { - std::vector fretItems(elementsToLayout.fretDiagrams.begin(), elementsToLayout.fretDiagrams.end()); - AlignmentLayout::alignItemsForSystem(fretItems, system); - } - - for (Harmony* harmony : elementsToLayout.harmonies) { - FretDiagram* fdParent = harmony->parent()->isFretDiagram() ? toFretDiagram(harmony->parent()) : nullptr; - if (fdParent && !fdParent->visible()) { - harmony->mutldata()->moveY(-fdParent->pos().y()); - } - Autoplace::autoplaceSegmentElement(harmony, harmony->mutldata()); - } - - if (ctx.conf().styleB(Sid::verticallyAlignChordSymbols)) { - std::vector harmonyItems(elementsToLayout.harmonies.begin(), elementsToLayout.harmonies.end()); - AlignmentLayout::alignItemsForSystem(harmonyItems, system); - } - - for (FretDiagram* fretDiag : elementsToLayout.fretDiagrams) { - if (Harmony* harmony = fretDiag->harmony()) { - SkylineLine& skl = system->staff(fretDiag->staffIdx())->skyline().north(); - Segment* s = fretDiag->segment(); - Shape harmShape = harmony->ldata()->shape().translated(harmony->pos() + fretDiag->pos() + s->pos() + s->measure()->pos()); - skl.add(harmShape); - } - } + layoutFretDiagrams(elementsToLayout, system, ctx); } layoutVoltas(elementsToLayout, ctx); @@ -1910,7 +1917,7 @@ void SystemLayout::updateCrossBeams(System* system, LayoutContext& ctx) } } -void SystemLayout::restoreTiesAndBends(System* system, LayoutContext& ctx) +void SystemLayout::restoreOldSystemLayout(System* system, LayoutContext& ctx) { ElementsToLayout elements(system); for (MeasureBase* mb : system->measures()) { @@ -1920,6 +1927,13 @@ void SystemLayout::restoreTiesAndBends(System* system, LayoutContext& ctx) } layoutTiesAndBends(elements, ctx); + + bool hasFretDiagram = elements.fretDiagrams.size() > 0; + if (hasFretDiagram) { + layoutFretDiagrams(elements, system, ctx); + } else { + layoutHarmonies(elements.harmonies, system, ctx); + } } void SystemLayout::layoutSystem(System* system, LayoutContext& ctx, double xo1, const bool isFirstSystem, bool firstSystemIndent) diff --git a/src/engraving/rendering/score/systemlayout.h b/src/engraving/rendering/score/systemlayout.h index ff76ddd343680..e15df252e8ea4 100644 --- a/src/engraving/rendering/score/systemlayout.h +++ b/src/engraving/rendering/score/systemlayout.h @@ -180,7 +180,7 @@ class SystemLayout static void layoutGuitarBends(Chord* chord, LayoutContext& ctx); static void updateCrossBeams(System* system, LayoutContext& ctx); static bool measureHasCrossStuffOrModifiedBeams(const Measure* measure); - static void restoreTiesAndBends(System* system, LayoutContext& ctx); + static void restoreOldSystemLayout(System* system, LayoutContext& ctx); static void layoutTuplets(const std::vector& chordRests, LayoutContext& ctx); static void layoutTiesAndBends(const ElementsToLayout& elementsToLayout, LayoutContext& ctx); @@ -213,7 +213,8 @@ class SystemLayout static void layoutParenthesisAndBigTimeSigs(const ElementsToLayout& elementsToLayout); - static void layoutHarmonies(const std::vector harmonies, System* system, bool verticalAlign, LayoutContext& ctx); + static void layoutHarmonies(const std::vector harmonies, System* system, LayoutContext& ctx); + static void layoutFretDiagrams(const ElementsToLayout& elements, System* system, LayoutContext& ctx); static void alignRests(const ElementsToLayout& elementsToLayout, LayoutContext& ctx); static void checkFullMeasureRestCollisions(const ElementsToLayout& elementsToLayout, LayoutContext& ctx); diff --git a/src/engraving/rendering/score/tdraw.cpp b/src/engraving/rendering/score/tdraw.cpp index 35f62e27f847b..1d8fd2116c11b 100644 --- a/src/engraving/rendering/score/tdraw.cpp +++ b/src/engraving/rendering/score/tdraw.cpp @@ -1853,7 +1853,7 @@ void TDraw::draw(const Harmony* item, Painter* painter) painter->drawText(ts->pos(), ts->text()); #endif } else if (const ChordSymbolParen* parenItem = dynamic_cast(renderItem)) { - Parenthesis* p = parenItem->paren; + Parenthesis* p = parenItem->parenItem; painter->translate(parenItem->pos()); draw(p, painter); painter->translate(-parenItem->pos()); diff --git a/src/inspector/models/notation/frames/fretframe/fretframechordlistmodel.cpp b/src/inspector/models/notation/frames/fretframe/fretframechordlistmodel.cpp index 528fff6a951ed..44fe1fee401c9 100644 --- a/src/inspector/models/notation/frames/fretframe/fretframechordlistmodel.cpp +++ b/src/inspector/models/notation/frames/fretframe/fretframechordlistmodel.cpp @@ -50,7 +50,7 @@ void FretFrameChordListModel::load() if (const TextSegment* textSeg = dynamic_cast(segment)) { name += textSeg->text().toQString(); } else if (const ChordSymbolParen* parenSeg = dynamic_cast(segment)) { - name += parenSeg->paren->direction() == DirectionH::LEFT ? u"(" : u")"; + name += parenSeg->parenItem->direction() == DirectionH::LEFT ? u"(" : u")"; } }