Skip to content

Commit

Permalink
added fretboard diagram legend
Browse files Browse the repository at this point in the history
  • Loading branch information
Eism committed Feb 20, 2025
1 parent af80582 commit 3b6688a
Show file tree
Hide file tree
Showing 42 changed files with 1,487 additions and 58 deletions.
145 changes: 141 additions & 4 deletions src/engraving/dom/box.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,6 @@ PropertyValue Box::getProperty(Pid propertyId) const

bool Box::setProperty(Pid propertyId, const PropertyValue& v)
{
score()->addRefresh(canvasBoundingRect(LD_ACCESS::BAD));
switch (propertyId) {
case Pid::BOX_HEIGHT:
m_boxHeight = v.value<Spatium>();
Expand Down Expand Up @@ -668,20 +667,158 @@ void VBox::startEditDrag(EditData& ed)
/// Add new EngravingItem \a e to fret diagram box
//---------------------------------------------------------

FBox::FBox(System* parent)
: VBox(ElementType::FBOX, parent)
{
init();

//! hack: needed for the case when we need to check whether the height was set by the user
//! or we need to take the height that we calculated from the content
setBoxHeight(Spatium(-1.0));

resetProperty(Pid::FRET_FRAME_TEXT_SCALE);
resetProperty(Pid::FRET_FRAME_DIAGRAM_SCALE);
resetProperty(Pid::FRET_FRAME_COLUMN_GAP);
resetProperty(Pid::FRET_FRAME_ROW_GAP);
resetProperty(Pid::FRET_FRAME_CHORDS_PER_ROW);
resetProperty(Pid::FRET_FRAME_H_ALIGN);

resetProperty(Pid::LEFT_MARGIN);
resetProperty(Pid::RIGHT_MARGIN);
resetProperty(Pid::TOP_MARGIN);
resetProperty(Pid::BOTTOM_MARGIN);
resetProperty(Pid::TOP_GAP);
resetProperty(Pid::BOTTOM_GAP);
}

void FBox::add(EngravingItem* e)
{
e->setParent(this);
if (e->isFretDiagram()) {
// FretDiagram* fd = toFretDiagram(e);
// fd->setFlag(ElementFlag::MOVABLE, false);
FretDiagram* fd = toFretDiagram(e);
fd->setFlag(ElementFlag::MOVABLE, false);
m_fretDiagrams.push_back(fd);
} else {
LOGD("FBox::add: element not allowed");
return;
}
el().push_back(e);
e->added();
}

PropertyValue FBox::getProperty(Pid propertyId) const
{
switch (propertyId) {
case Pid::BOX_HEIGHT: {
double boxHeight = this->boxHeight().val();
return boxHeight > 0.0 ? boxHeight : propertyDefault(propertyId);
}
case Pid::FRET_FRAME_TEXT_SCALE:
return m_textScale;
case Pid::FRET_FRAME_DIAGRAM_SCALE:
return m_diagramScale;
case Pid::FRET_FRAME_COLUMN_GAP:
return m_columnGap;
case Pid::FRET_FRAME_ROW_GAP:
return m_rowGap;
case Pid::FRET_FRAME_CHORDS_PER_ROW:
return m_chordsPerRow;
case Pid::FRET_FRAME_H_ALIGN:
return static_cast<int>(m_contentAlignmentH);
case Pid::LEFT_MARGIN:
return m_contentAlignmentH == AlignH::LEFT ? VBox::getProperty(propertyId) : PropertyValue();
case Pid::RIGHT_MARGIN:
return m_contentAlignmentH == AlignH::RIGHT ? VBox::getProperty(propertyId) : PropertyValue();
default:
return VBox::getProperty(propertyId);
}
}

bool FBox::setProperty(Pid propertyId, const PropertyValue& val)
{
switch (propertyId) {
case Pid::FRET_FRAME_TEXT_SCALE:
m_textScale = val.toDouble();
break;
case Pid::FRET_FRAME_DIAGRAM_SCALE:
m_diagramScale = val.toDouble();
break;
case Pid::FRET_FRAME_COLUMN_GAP:
m_columnGap = val.value<Spatium>();
break;
case Pid::FRET_FRAME_ROW_GAP:
m_rowGap = val.value<Spatium>();
break;
case Pid::FRET_FRAME_CHORDS_PER_ROW:
m_chordsPerRow = val.toInt();
break;
case Pid::FRET_FRAME_H_ALIGN:
m_contentAlignmentH = static_cast<AlignH>(val.toInt());
resetProperty(Pid::LEFT_MARGIN);
resetProperty(Pid::RIGHT_MARGIN);
break;
default:
return VBox::setProperty(propertyId, val);
}

triggerLayout();
return true;
}

PropertyValue FBox::propertyDefault(Pid propertyId) const
{
switch (propertyId) {
case Pid::BOX_HEIGHT:
return ldata() && !muse::RealIsNull(ldata()->totalTableHeight)
? std::ceil(ldata()->totalTableHeight / spatium())
: PropertyValue();
case Pid::FRET_FRAME_TEXT_SCALE:
case Pid::FRET_FRAME_DIAGRAM_SCALE:
return 1.0;
case Pid::FRET_FRAME_COLUMN_GAP:
case Pid::FRET_FRAME_ROW_GAP:
return Spatium(4.0);
case Pid::FRET_FRAME_CHORDS_PER_ROW:
return 8;
case Pid::FRET_FRAME_H_ALIGN:
return static_cast<int>(AlignH::HCENTER);
case Pid::TOP_GAP:
case Pid::BOTTOM_GAP:
return 0.0;
default:
return VBox::propertyDefault(propertyId);
}
}

void FBox::init()
{
for (FretDiagram* fretDiagram : m_fretDiagrams) {
fretDiagram->deleteLater();
}

m_fretDiagrams.clear();

for (mu::engraving::Segment* segment = score()->firstSegment(mu::engraving::SegmentType::ChordRest); segment;
segment = segment->next1(mu::engraving::SegmentType::ChordRest)) {
for (EngravingItem* item : segment->annotations()) {
if (!item || !item->part()) {
continue;
}

FretDiagram* fretDiagram = nullptr;

if (item->isHarmony()) {
continue; // todo: create new fret diagram and attach harmony
} else if (item->isFretDiagram()) {
fretDiagram = toFretDiagram(item)->clone();
fretDiagram->harmony()->setAutoplace(false);
fretDiagram->setAutoplace(false);
}

add(fretDiagram);
}
}
}

//---------------------------------------------------------
// TBox
//---------------------------------------------------------
Expand Down
59 changes: 57 additions & 2 deletions src/engraving/dom/box.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,12 +176,67 @@ class FBox : public VBox
DECLARE_CLASSOF(ElementType::FBOX)

public:
FBox(System* parent)
: VBox(ElementType::FBOX, parent) {}
FBox(System* parent);

FBox* clone() const override { return new FBox(*this); }

void add(EngravingItem*) override;

// Score Tree functions
EngravingObject* scanParent() const override;
EngravingObjectList scanChildren() const override;
void scanElements(void* data, void (* func)(void*, EngravingItem*), bool all = true) override;

double textScale() const { return m_textScale; }
void setTextScale(double scale) { m_textScale = scale; }

double diagramScale() const { return m_diagramScale; }
void setDiagramScale(double scale) { m_diagramScale = scale; }

Spatium columnGap() const { return m_columnGap; }
void setColumnGap(Spatium gap) { m_columnGap = gap; }

Spatium rowGap() const { return m_rowGap; }
void setRowGap(Spatium gap) { m_rowGap = gap; }

int chordsPerRow() const { return m_chordsPerRow; }
void setChordsPerRow(int chords) { m_chordsPerRow = chords; }

AlignH contentHorizontallAlignment() const { return m_contentAlignmentH; }
void setContentHorizontallAlignment(AlignH alignment) { m_contentAlignmentH = alignment; }

PropertyValue getProperty(Pid propertyId) const override;
bool setProperty(Pid propertyId, const PropertyValue& val) override;
PropertyValue propertyDefault(Pid propertyId) const override;

const std::vector<FretDiagram*> fretDiagrams() const { return m_fretDiagrams; }

void init();

struct LayoutData : public VBox::LayoutData {
double cellWidth = 0.0;
double cellHeight = 0.0;

double totalTableHeight = 0.0;
double totalTableWidth = 0.0;

double defaultMargins = 0.0;
};

DECLARE_LAYOUTDATA_METHODS(FBox)

private:
void resolveContentRect();

std::vector<FretDiagram*> m_fretDiagrams;

double m_textScale = 0.0;
double m_diagramScale = 0.0;
Spatium m_columnGap;
Spatium m_rowGap;
int m_chordsPerRow = 0;

AlignH m_contentAlignmentH = AlignH::HCENTER;
};

//---------------------------------------------------------
Expand Down
2 changes: 2 additions & 0 deletions src/engraving/dom/cmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2949,6 +2949,7 @@ EngravingItem* Score::move(const String& cmd)
case ElementType::HBOX: // fallthrough
case ElementType::VBOX: // fallthrough
case ElementType::TBOX:
case ElementType::FBOX:
box = toBox(el);
break;
default: // on anything else, return failure
Expand Down Expand Up @@ -4619,6 +4620,7 @@ void Score::cmdToggleLayoutBreak(LayoutBreakType type)
case ElementType::HBOX:
case ElementType::VBOX:
case ElementType::TBOX:
case ElementType::FBOX:
mb = toMeasureBase(el);
break;
default: {
Expand Down
5 changes: 4 additions & 1 deletion src/engraving/dom/engravingitem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,8 @@ PointF EngravingItem::pagePos() const
system = toSystem(explicitParent());
} else if (explicitParent()->isFretDiagram()) {
return p + parentItem()->pagePos();
} else if (explicitParent()->isFBox()) {
return p + parentItem()->pagePos();
} else {
ASSERT_X(String(u"this %1 parent %2\n").arg(String::fromAscii(typeName()), String::fromAscii(explicitParent()->typeName())));
}
Expand Down Expand Up @@ -1608,8 +1610,9 @@ bool EngravingItem::isPlayable() const
switch (type()) {
case ElementType::NOTE:
case ElementType::CHORD:
case ElementType::HARMONY:
return true;
case ElementType::HARMONY:
return explicitParent() && explicitParent()->isSegment();
default:
return false;
}
Expand Down
12 changes: 11 additions & 1 deletion src/engraving/dom/harmony.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1337,7 +1337,8 @@ void Harmony::render()
m_fontList.clear();
for (const ChordFont& cf : chordList->fonts) {
Font ff(font());
ff.setPointSizeF(ff.pointSizeF() * cf.mag);
double mag = m_userMag.value_or(cf.mag);
ff.setPointSizeF(ff.pointSizeF() * mag);
if (!(cf.family.isEmpty() || cf.family == "default")) {
ff.setFamily(cf.family, Font::Type::Harmony);
}
Expand Down Expand Up @@ -1891,4 +1892,13 @@ Sid Harmony::getPropertyStyle(Pid pid) const
}
return TextBase::getPropertyStyle(pid);
}

double Harmony::mag() const
{
if (m_userMag.has_value()) {
return m_userMag.value();
}

return EngravingItem::mag();
}
}
5 changes: 5 additions & 0 deletions src/engraving/dom/harmony.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ class Harmony final : public TextBase
bool setProperty(Pid propertyId, const PropertyValue& v) override;
PropertyValue propertyDefault(Pid id) const override;

double mag() const override;
void setUserMag(double m) { m_userMag = m; }

//! HACK Temporary hack
bool isDrawEditMode() const { return m_isDrawEditMode; }
void setIsDrawEditMode(bool val) { m_isDrawEditMode = val; }
Expand Down Expand Up @@ -246,6 +249,8 @@ class Harmony final : public TextBase
NoteCaseType m_baseRenderCase = NoteCaseType::AUTO; // case to render

bool m_isDrawEditMode = false;

std::optional<double> m_userMag;
};
} // namespace mu::engraving
#endif
16 changes: 16 additions & 0 deletions src/engraving/dom/masterscore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "barline.h"
#include "excerpt.h"
#include "factory.h"
#include "box.h"
#include "linkedobjects.h"
#include "repeatlist.h"
#include "rest.h"
Expand Down Expand Up @@ -456,6 +457,21 @@ void MasterScore::updateExpressive(Synthesizer* synth, bool expressive, bool for
}
}

void MasterScore::rebuildFretDiagramLegend()
{
for (MeasureBase* measure = first(); measure; measure = measure->next()) {
if (!measure->isFBox()) {
continue;
}

FBox* fbox = toFBox(measure);
fbox->init();
fbox->triggerLayout();

break;
}
}

//---------------------------------------------------------
// rebuildAndUpdateExpressive
// implicitly rebuild midi mappings as well. Should be preferred over
Expand Down
1 change: 1 addition & 0 deletions src/engraving/dom/masterscore.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ class MasterScore : public Score
void rebuildAndUpdateExpressive(Synthesizer* synth);
void updateExpressive(Synthesizer* synth);
void updateExpressive(Synthesizer* synth, bool expressive, bool force = false);
void rebuildFretDiagramLegend();

using Score::loopBoundaryTick;
Fraction loopBoundaryTick(LoopBoundaryType type) const;
Expand Down
12 changes: 8 additions & 4 deletions src/engraving/dom/navigate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -821,14 +821,16 @@ EngravingItem* Score::nextElement()
}
case ElementType::VBOX:
case ElementType::HBOX:
case ElementType::TBOX: {
case ElementType::TBOX:
case ElementType::FBOX: {
auto boxChildren = toChildPairsSet(e);

EngravingItem* selectedElement = getSelectedElement();

if ((selectedElement->type() == ElementType::VBOX
|| selectedElement->type() == ElementType::HBOX
|| selectedElement->type() == ElementType::TBOX) && !boxChildren.empty()) {
|| selectedElement->type() == ElementType::TBOX
|| selectedElement->type() == ElementType::FBOX) && !boxChildren.empty()) {
return boxChildren.begin()->first;
}

Expand Down Expand Up @@ -926,7 +928,8 @@ EngravingItem* Score::prevElement()

if (previousElement->type() != ElementType::VBOX
&& previousElement->type() != ElementType::HBOX
&& previousElement->type() != ElementType::TBOX) {
&& previousElement->type() != ElementType::TBOX
&& previousElement->type() == ElementType::FBOX) {
return previousElement;
}

Expand Down Expand Up @@ -1020,7 +1023,8 @@ EngravingItem* Score::prevElement()
}
case ElementType::VBOX:
case ElementType::HBOX:
case ElementType::TBOX: {
case ElementType::TBOX:
case ElementType::FBOX: {
auto boxChildren = toChildPairsSet(e);

EngravingItem* selectedElement = getSelectedElement();
Expand Down
Loading

0 comments on commit 3b6688a

Please sign in to comment.