Skip to content

Commit

Permalink
Fix #23090: Added style option to use expression font for dynamics
Browse files Browse the repository at this point in the history
This commit introduces a new class DynamicFragment which inherits the TextFragment class. This is used to handle the changes for Dynamics.
  • Loading branch information
HemantAntony committed Dec 20, 2024
1 parent 77fc27c commit dd49c24
Show file tree
Hide file tree
Showing 11 changed files with 595 additions and 266 deletions.
261 changes: 221 additions & 40 deletions src/engraving/dom/dynamic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#include "types/translatablestring.h"
#include "types/typesconv.h"
#include "types/symnames.h"

#include "anchors.h"
#include "dynamichairpingroup.h"
Expand All @@ -48,58 +49,85 @@ namespace mu::engraving {
//-----------------------------------------------------------------------------

// variant with ligatures, works for both emmentaler and bravura:
constexpr DynamicType P = DynamicType::P;
constexpr DynamicType M = DynamicType::M;
constexpr DynamicType F = DynamicType::F;
constexpr DynamicType S = DynamicType::S;
constexpr DynamicType Z = DynamicType::Z;
constexpr DynamicType R = DynamicType::R;
constexpr DynamicType N = DynamicType::N;
const std::vector<Dyn> Dynamic::DYN_LIST = {
// dynamic:
{ DynamicType::OTHER, -1, 0, true, "" },
{ DynamicType::PPPPPP, 1, 0, false,
{ DynamicType::OTHER, -1, 0, true, {}, "", "" },
{ DynamicType::PPPPPP, 1, 0, false, { P, P, P, P, P, P }, "pppppp",
"<sym>dynamicPiano</sym><sym>dynamicPiano</sym><sym>dynamicPiano</sym><sym>dynamicPiano</sym><sym>dynamicPiano</sym><sym>dynamicPiano</sym>" },
{ DynamicType::PPPPP, 5, 0, false,
{ DynamicType::PPPPP, 5, 0, false, { P, P, P, P, P }, "ppppp",
"<sym>dynamicPiano</sym><sym>dynamicPiano</sym><sym>dynamicPiano</sym><sym>dynamicPiano</sym><sym>dynamicPiano</sym>" },
{ DynamicType::PPPP, 10, 0, false,
{ DynamicType::PPPP, 10, 0, false, { P, P, P, P }, "pppp",
"<sym>dynamicPiano</sym><sym>dynamicPiano</sym><sym>dynamicPiano</sym><sym>dynamicPiano</sym>" },
{ DynamicType::PPP, 16, 0, false,
{ DynamicType::PPP, 16, 0, false, { P, P, P }, "ppp",
"<sym>dynamicPiano</sym><sym>dynamicPiano</sym><sym>dynamicPiano</sym>" },
{ DynamicType::PP, 33, 0, false, "<sym>dynamicPiano</sym><sym>dynamicPiano</sym>" },
{ DynamicType::P, 49, 0, false, "<sym>dynamicPiano</sym>" },

{ DynamicType::MP, 64, 0, false, "<sym>dynamicMezzo</sym><sym>dynamicPiano</sym>" },
{ DynamicType::MF, 80, 0, false, "<sym>dynamicMezzo</sym><sym>dynamicForte</sym>" },

{ DynamicType::F, 96, 0, false, "<sym>dynamicForte</sym>" },
{ DynamicType::FF, 112, 0, false, "<sym>dynamicForte</sym><sym>dynamicForte</sym>" },
{ DynamicType::FFF, 126, 0, false, "<sym>dynamicForte</sym><sym>dynamicForte</sym><sym>dynamicForte</sym>" },
{ DynamicType::FFFF, 127, 0, false,
{ DynamicType::PP, 33, 0, false, { P, P }, "pp",
"<sym>dynamicPiano</sym><sym>dynamicPiano</sym>" },
{ DynamicType::P, 49, 0, false, { P }, "p",
"<sym>dynamicPiano</sym>" },

{ DynamicType::MP, 64, 0, false, { M, P }, "mp",
"<sym>dynamicMezzo</sym><sym>dynamicPiano</sym>" },
{ DynamicType::MF, 80, 0, false, { M, F }, "mf",
"<sym>dynamicMezzo</sym><sym>dynamicForte</sym>" },

{ DynamicType::F, 96, 0, false, { F }, "f",
"<sym>dynamicForte</sym>" },
{ DynamicType::FF, 112, 0, false, { F, F }, "ff",
"<sym>dynamicForte</sym><sym>dynamicForte</sym>" },
{ DynamicType::FFF, 126, 0, false, { F, F, F }, "fff",
"<sym>dynamicForte</sym><sym>dynamicForte</sym><sym>dynamicForte</sym>" },
{ DynamicType::FFFF, 127, 0, false, { F, F, F, F }, "ffff",
"<sym>dynamicForte</sym><sym>dynamicForte</sym><sym>dynamicForte</sym><sym>dynamicForte</sym>" },
{ DynamicType::FFFFF, 127, 0, false,
{ DynamicType::FFFFF, 127, 0, false, { F, F, F, F, F }, "fffff",
"<sym>dynamicForte</sym><sym>dynamicForte</sym><sym>dynamicForte</sym><sym>dynamicForte</sym><sym>dynamicForte</sym>" },
{ DynamicType::FFFFFF, 127, 0, false,
{ DynamicType::FFFFFF, 127, 0, false, { F, F, F, F, F, F }, "ffffff",
"<sym>dynamicForte</sym><sym>dynamicForte</sym><sym>dynamicForte</sym><sym>dynamicForte</sym><sym>dynamicForte</sym><sym>dynamicForte</sym>" },

{ DynamicType::FP, 96, -47, true, "<sym>dynamicForte</sym><sym>dynamicPiano</sym>" },
{ DynamicType::PF, 49, 47, true, "<sym>dynamicPiano</sym><sym>dynamicForte</sym>" },

{ DynamicType::SF, 112, -18, true, "<sym>dynamicSforzando</sym><sym>dynamicForte</sym>" },
{ DynamicType::SFZ, 112, -18, true, "<sym>dynamicSforzando</sym><sym>dynamicForte</sym><sym>dynamicZ</sym>" },
{ DynamicType::SFF, 126, -18, true, "<sym>dynamicSforzando</sym><sym>dynamicForte</sym><sym>dynamicForte</sym>" },
{ DynamicType::SFFZ, 126, -18, true,
{ DynamicType::FP, 96, -47, true, { F, P }, "fp",
"<sym>dynamicForte</sym><sym>dynamicPiano</sym>" },
{ DynamicType::PF, 49, 47, true, { P, F }, "pf",
"<sym>dynamicPiano</sym><sym>dynamicForte</sym>" },

{ DynamicType::SF, 112, -18, true, { S, F }, "sf",
"<sym>dynamicSforzando</sym><sym>dynamicForte</sym>" },
{ DynamicType::SFZ, 112, -18, true, { S, F, Z }, "sfz",
"<sym>dynamicSforzando</sym><sym>dynamicForte</sym><sym>dynamicZ</sym>" },
{ DynamicType::SFF, 126, -18, true, { S, F, F }, "sff",
"<sym>dynamicSforzando</sym><sym>dynamicForte</sym><sym>dynamicForte</sym>" },
{ DynamicType::SFFZ, 126, -18, true, { S, F, F, Z }, "sffz",
"<sym>dynamicSforzando</sym><sym>dynamicForte</sym><sym>dynamicForte</sym><sym>dynamicZ</sym>" },
{ DynamicType::SFFF, 127, -18, true,
{ DynamicType::SFFF, 127, -18, true, { S, F, F, F }, "sfff",
"<sym>dynamicSforzando</sym><sym>dynamicForte</sym><sym>dynamicForte</sym><sym>dynamicForte</sym>" },
{ DynamicType::SFFFZ, 127, -18, true,
{ DynamicType::SFFFZ, 127, -18, true, { S, F, F, F, Z }, "sfffz",
"<sym>dynamicSforzando</sym><sym>dynamicForte</sym><sym>dynamicForte</sym><sym>dynamicForte</sym><sym>dynamicZ</sym>" },
{ DynamicType::SFP, 112, -47, true, "<sym>dynamicSforzando</sym><sym>dynamicForte</sym><sym>dynamicPiano</sym>" },
{ DynamicType::SFPP, 112, -79, true,
{ DynamicType::SFP, 112, -47, true, { S, F, P }, "sfp",
"<sym>dynamicSforzando</sym><sym>dynamicForte</sym><sym>dynamicPiano</sym>" },
{ DynamicType::SFPP, 112, -79, true, { S, F, P, P }, "sfpp",
"<sym>dynamicSforzando</sym><sym>dynamicForte</sym><sym>dynamicPiano</sym><sym>dynamicPiano</sym>" },

{ DynamicType::RFZ, 112, -18, true, "<sym>dynamicRinforzando</sym><sym>dynamicForte</sym><sym>dynamicZ</sym>" },
{ DynamicType::RF, 112, -18, true, "<sym>dynamicRinforzando</sym><sym>dynamicForte</sym>" },
{ DynamicType::FZ, 112, -18, true, "<sym>dynamicForte</sym><sym>dynamicZ</sym>" },

{ DynamicType::M, 96, -16, true, "<sym>dynamicMezzo</sym>" },
{ DynamicType::R, 112, -18, true, "<sym>dynamicRinforzando</sym>" },
{ DynamicType::S, 112, -18, true, "<sym>dynamicSforzando</sym>" },
{ DynamicType::Z, 80, 0, true, "<sym>dynamicZ</sym>" },
{ DynamicType::N, 49, -48, true, "<sym>dynamicNiente</sym>" }
{ DynamicType::RFZ, 112, -18, true, { R, F, Z }, "rfz",
"<sym>dynamicRinforzando</sym><sym>dynamicForte</sym><sym>dynamicZ</sym>" },
{ DynamicType::RF, 112, -18, true, { R, F }, "rf",
"<sym>dynamicRinforzando</sym><sym>dynamicForte</sym>" },
{ DynamicType::FZ, 112, -18, true, { F, Z }, "fz",
"<sym>dynamicForte</sym><sym>dynamicZ</sym>" },

{ DynamicType::M, 96, -16, true, { M }, "m",
"<sym>dynamicMezzo</sym>" },
{ DynamicType::R, 112, -18, true, { R }, "r",
"<sym>dynamicRinforzando</sym>" },
{ DynamicType::S, 112, -18, true, { S }, "s",
"<sym>dynamicSforzando</sym>" },
{ DynamicType::Z, 80, 0, true, { Z }, "z",
"<sym>dynamicZ</sym>" },
{ DynamicType::N, 49, -48, true, { N }, "n",
"<sym>dynamicNiente</sym>" }
};

//---------------------------------------------------------
Expand All @@ -113,6 +141,107 @@ static const ElementStyle dynamicsStyle {
{ Sid::centerOnNotehead, Pid::CENTER_ON_NOTEHEAD },
};

//---------------------------------------------------------
// DynamicFragment
//---------------------------------------------------------

DynamicFragment::DynamicFragment(CharFormat charFormat, String dynamicText, bool displayAsExpression)
{
format = charFormat;
m_dynamicText = dynamicText;
calculatePlainText(getDynamics(dynamicText));
setDisplayAsExpressionText(displayAsExpression);
}

DynamicFragment::DynamicFragment(const DynamicFragment& dynamicFragment)
: TextFragment(dynamicFragment)
{
m_displayAsExpressionText = dynamicFragment.m_displayAsExpressionText;
m_dynamicText = dynamicFragment.m_dynamicText;
m_plainText = dynamicFragment.m_plainText;
}

DynamicFragment& DynamicFragment::operator =(const DynamicFragment& dynamicFragment)
{
TextFragment::operator =(dynamicFragment);
m_dynamicText = dynamicFragment.m_dynamicText;
m_plainText = dynamicFragment.m_plainText;

return *this;
}

void DynamicFragment::setText(String newText)
{
std::vector<DynamicType> dynamics = getDynamics(newText);
calculateDynamicText(dynamics);
calculatePlainText(dynamics);
setDisplayAsExpressionText(m_displayAsExpressionText);
}

std::vector<DynamicType> DynamicFragment::getDynamics(String text)
{
static std::shared_ptr<IEngravingFontsProvider> provider = muse::modularity::globalIoc()->resolve<IEngravingFontsProvider>("engraving");

std::vector<DynamicType> dynamics;
for (char32_t i = 0; i < text.size(); i++) {
SymId symId = provider->fallbackFont()->fromCode(text[i]);
DynamicType dt = TConv::dynamicType(symId);
if (dt == DynamicType::OTHER) {
return dynamics;
}
dynamics.push_back(dt);
}

return dynamics;
}

void DynamicFragment::setDisplayAsExpressionText(bool asExpression)
{
m_displayAsExpressionText = asExpression;
if (asExpression) {
TextFragment::setText(m_plainText);
} else {
format.setFontFamily(u"ScoreText");
TextFragment::setText(m_dynamicText);
}
}

void DynamicFragment::calculateDynamicText(std::vector<DynamicType> dynamics)
{
static std::shared_ptr<IEngravingFontsProvider> provider = muse::modularity::globalIoc()->resolve<IEngravingFontsProvider>("engraving");

m_dynamicText.clear();
for (DynamicType dynamic : dynamics) {
m_dynamicText += provider->fallbackFont()->symCode(TConv::symId(dynamic));
}
}

void DynamicFragment::calculatePlainText(std::vector<DynamicType> dynamics)
{
m_plainText.clear();
for (DynamicType dynamic : dynamics) {
for (const Dyn& dyn : Dynamic::dynamicList()) {
if (dyn.type == dynamic) {
m_plainText += *dyn.plainText;
break;
}
}
}
}

String DynamicFragment::toSymbolXml()
{
static std::shared_ptr<IEngravingFontsProvider> provider = muse::modularity::globalIoc()->resolve<IEngravingFontsProvider>("engraving");

String xmlText;
for (size_t i = 0; i < m_dynamicText.size(); i++) {
SymId symId = provider->fallbackFont()->fromCode(m_dynamicText.at(i).unicode());
xmlText += u"<sym>" + String::fromAscii(SymNames::nameForSymId(symId).ascii()) + u"</sym>";
}

return xmlText;
}

//---------------------------------------------------------
// Dynamic
//---------------------------------------------------------
Expand Down Expand Up @@ -438,9 +567,23 @@ void Dynamic::setDynamicType(const String& tag)
setXmlText(tag);
}

bool Dynamic::isDynamicType(String s)
{
static std::shared_ptr<IEngravingFontsProvider> provider = muse::modularity::globalIoc()->resolve<IEngravingFontsProvider>("engraving");

for (char32_t i = 0; i < s.size(); i++) {
SymId symId = provider->fallbackFont()->fromCode(s[i]);
if (TConv::dynamicType(symId) == DynamicType::OTHER) {
return false;
}
}

return true;
}

String Dynamic::dynamicText(DynamicType t)
{
return String::fromUtf8(DYN_LIST[int(t)].text);
return String::fromStdString(DYN_LIST[int(t)].text);
}

Expression* Dynamic::snappedExpression() const
Expand Down Expand Up @@ -537,6 +680,16 @@ TranslatableString Dynamic::subtypeUserName() const
void Dynamic::startEdit(EditData& ed)
{
if (ed.editTextualProperties) {
if (useExpressionFontFace()) {
for (TextBlock block : ldata()->blocks) {
for (std::shared_ptr<TextFragment> fragment : block.fragments()) {
if (DynamicFragment* dynamicFragment = dynamic_cast<DynamicFragment*>(fragment.get())) {
dynamicFragment->setDisplayAsExpressionText(false);
}
}
}
}

TextBase::startEdit(ed);
} else {
startEditNonTextual(ed);
Expand Down Expand Up @@ -768,8 +921,17 @@ void Dynamic::editDrag(EditData& ed)
void Dynamic::endEdit(EditData& ed)
{
if (ed.editTextualProperties) {
if (useExpressionFontFace()) {
for (TextBlock block : ldata()->blocks) {
for (std::shared_ptr<TextFragment> fragment : block.fragments()) {
if (DynamicFragment* dynamicFragment = dynamic_cast<DynamicFragment*>(fragment.get())) {
dynamicFragment->setDisplayAsExpressionText(true);
}
}
}
}
TextBase::endEdit(ed);
if (!xmlText().contains(String::fromUtf8(DYN_LIST[int(m_dynamicType)].text))) {
if (!xmlText().contains(String::fromStdString(DYN_LIST[int(m_dynamicType)].text))) {
m_dynamicType = DynamicType::OTHER;
}
} else {
Expand Down Expand Up @@ -933,6 +1095,20 @@ Sid Dynamic::getPropertyStyle(Pid pid) const
}
}

void Dynamic::styleChanged()
{
for (const TextBlock& block : ldata()->blocks) {
for (const std::shared_ptr<TextFragment>& fragment : block.fragments()) {
DynamicFragment* dynamicFragment = dynamic_cast<DynamicFragment*>(fragment.get());
if (dynamicFragment) {
dynamicFragment->setDisplayAsExpressionText(useExpressionFontFace());
}
}
}

TextBase::styleChanged();
}

//---------------------------------------------------------
// accessibleInfo
//---------------------------------------------------------
Expand All @@ -957,4 +1133,9 @@ String Dynamic::screenReaderInfo() const
}
return String(u"%1: %2").arg(EngravingItem::accessibleInfo(), s);
}

bool Dynamic::useExpressionFontFace() const
{
return style().styleB(Sid::dynamicsOverrideFont) && style().styleB(Sid::dynamicsUseExpressionFont);
}
}
39 changes: 36 additions & 3 deletions src/engraving/dom/dynamic.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,39 @@ class Segment;

struct Dyn {
DynamicType type = DynamicType::OTHER;
int velocity = -1; // associated midi velocity (0-127, -1 = none)
int velocity = -1; // associated midi velocity (0-127, -1 = none)
int changeInVelocity = 0;
bool accent = 0; // if true add velocity to current chord velocity
const char* text = nullptr; // utf8 text of dynamic
bool accent = 0; // if true add velocity to current chord velocity
std::vector<DynamicType> dynamics;// dynamics which is used to build up the
const char* plainText = nullptr; // text to display when in expression text style
const char* text = nullptr; // utf8 text of dynamic
};

class DynamicFragment final : public TextFragment
{
public:
DynamicFragment() = default;
DynamicFragment(CharFormat charFormat, String dynamictext, bool displayAsExpression = false); // Pointer to CharFormat?
DynamicFragment(const DynamicFragment& dynamicFragment);

DynamicFragment& operator =(const DynamicFragment& dynamicFragment);

std::shared_ptr<TextFragment> clone() override { return std::make_shared<TextFragment>(*this); }

void setText(String newText) override;
void appendText(String newText) override { setText(m_dynamicText + newText); }

void setDisplayAsExpressionText(bool asExpression);
String toSymbolXml();

private:
std::vector<DynamicType> getDynamics(String text);
void calculateDynamicText(std::vector<DynamicType> dynamics);
void calculatePlainText(std::vector<DynamicType> dynamics);

String m_dynamicText;
String m_plainText;
bool m_displayAsExpressionText = false;
};

//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -99,6 +128,7 @@ class Dynamic final : public TextBase
bool setProperty(Pid propertyId, const PropertyValue&) override;
PropertyValue propertyDefault(Pid id) const override;
Sid getPropertyStyle(Pid) const override;
void styleChanged() override;

std::unique_ptr<ElementGroup> getDragGroup(std::function<bool(const EngravingItem*)> isDragged) override;

Expand Down Expand Up @@ -130,6 +160,9 @@ class Dynamic final : public TextBase

bool hasVoiceAssignmentProperties() const override { return true; }

bool useExpressionFontFace() const;
static bool isDynamicType(String s);

private:

M_PROPERTY(bool, avoidBarLines, setAvoidBarLines)
Expand Down
Loading

0 comments on commit dd49c24

Please sign in to comment.