Skip to content

Commit 86d435e

Browse files
committed
Implement chord parentheses
1 parent 0f1609b commit 86d435e

File tree

19 files changed

+491
-70
lines changed

19 files changed

+491
-70
lines changed

src/engraving/dom/chord.cpp

Lines changed: 7 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "articulation.h"
3636
#include "beam.h"
3737
#include "chordline.h"
38+
#include "dom/parenthesis.h"
3839
#include "drumset.h"
3940
#include "factory.h"
4041
#include "guitarbend.h"
@@ -64,6 +65,7 @@
6465
#include "tremolotwochord.h"
6566
#include "trill.h"
6667
#include "tuplet.h"
68+
#include "utils.h"
6769

6870
#ifndef ENGRAVING_NO_ACCESSIBILITY
6971
#include "accessibility/accessibleitem.h"
@@ -1252,6 +1254,11 @@ void Chord::scanElements(std::function<void(EngravingItem*)> func)
12521254
for (EngravingItem* e : el()) {
12531255
e->scanElements(func);
12541256
}
1257+
1258+
for (auto& p : m_noteParens) {
1259+
p.first.first->scanElements(func);
1260+
p.first.second->scanElements(func);
1261+
}
12551262
ChordRest::scanElements(func);
12561263
}
12571264

@@ -2106,36 +2113,6 @@ void Chord::requestShowStemSlash(bool show)
21062113
// sortNotes
21072114
//---------------------------------------------------------
21082115

2109-
static bool noteIsBefore(const Note* n1, const Note* n2)
2110-
{
2111-
const int l1 = n1->line();
2112-
const int l2 = n2->line();
2113-
if (l1 != l2) {
2114-
return l1 > l2;
2115-
}
2116-
2117-
const int p1 = n1->pitch();
2118-
const int p2 = n2->pitch();
2119-
if (p1 != p2) {
2120-
return p1 < p2;
2121-
}
2122-
2123-
if (n1->tieBack()) {
2124-
if (n2->tieBack() && !n2->incomingPartialTie()) {
2125-
const Note* sn1 = n1->tieBack()->startNote();
2126-
const Note* sn2 = n2->tieBack()->startNote();
2127-
if (sn1->chord() == sn2->chord()) {
2128-
return sn1->unisonIndex() < sn2->unisonIndex();
2129-
}
2130-
return sn1->chord()->isBefore(sn2->chord());
2131-
} else {
2132-
return true; // place tied notes before
2133-
}
2134-
}
2135-
2136-
return false;
2137-
}
2138-
21392116
void Chord::sortNotes()
21402117
{
21412118
std::sort(notes().begin(), notes().end(), noteIsBefore);

src/engraving/dom/chord.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ class GraceNotesGroup final : public std::vector<Chord*>, public EngravingItem
115115
// @P stemDirection Direction the stem direction of the chord: AUTO, UP, DOWN (read only)
116116
//---------------------------------------------------------
117117

118+
using ParenthesisPair = std::pair<Parenthesis*, Parenthesis*>;
119+
using NoteParenthesisInfo = std::map<ParenthesisPair, std::vector<Note*> >;
120+
118121
class Chord final : public ChordRest
119122
{
120123
OBJECT_ALLOCATOR(engraving, Chord)
@@ -159,6 +162,9 @@ class Chord final : public ChordRest
159162
std::vector<Note*>& notes() { return m_notes; }
160163
const std::vector<Note*>& notes() const { return m_notes; }
161164

165+
const NoteParenthesisInfo& noteParens() const { return m_noteParens; }
166+
NoteParenthesisInfo& noteParens() { return m_noteParens; }
167+
162168
bool isChordPlayable() const;
163169
void setIsChordPlayable(const bool isPlayable);
164170

@@ -368,6 +374,7 @@ class Chord final : public ChordRest
368374

369375
std::vector<Note*> m_notes; // sorted to decreasing line step
370376
std::vector<LedgerLine*> m_ledgerLines;
377+
NoteParenthesisInfo m_noteParens;
371378

372379
Stem* m_stem = nullptr;
373380
Hook* m_hook = nullptr;

src/engraving/dom/chordrest.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,7 @@ void ChordRest::add(EngravingItem* e)
573573
e->added();
574574
break;
575575
default:
576-
ASSERT_X(u"ChordRest::add: unknown element " + String::fromAscii(e->typeName()));
576+
EngravingItem::add(e);
577577
break;
578578
}
579579
}
@@ -597,7 +597,7 @@ void ChordRest::remove(EngravingItem* e)
597597
}
598598
break;
599599
default:
600-
ASSERT_X(u"ChordRest::remove: unknown element " + String::fromAscii(e->typeName()));
600+
EngravingItem::remove(e);
601601
}
602602
}
603603

@@ -1057,6 +1057,13 @@ void ChordRest::scanElements(std::function<void(EngravingItem*)> func)
10571057
if (m_tabDur) {
10581058
func(m_tabDur);
10591059
}
1060+
1061+
if (leftParen()) {
1062+
func(leftParen());
1063+
}
1064+
if (rightParen()) {
1065+
func(rightParen());
1066+
}
10601067
}
10611068

10621069
//---------------------------------------------------------

src/engraving/dom/note.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2941,6 +2941,8 @@ PropertyValue Note::getProperty(Pid propertyId) const
29412941
return fixed();
29422942
case Pid::FIXED_LINE:
29432943
return fixedLine();
2944+
case Pid::HAS_PARENTHESES:
2945+
return m_hasParens ? ParenthesesMode::BOTH : ParenthesesMode::NONE;
29442946
case Pid::POSITION_LINKED_TO_MASTER:
29452947
case Pid::APPEARANCE_LINKED_TO_MASTER:
29462948
if (chord()) {
@@ -3048,7 +3050,10 @@ bool Note::setProperty(Pid propertyId, const PropertyValue& v)
30483050
setFixedLine(v.toInt());
30493051
break;
30503052
case Pid::HAS_PARENTHESES:
3051-
setParenthesesMode(v.value<ParenthesesMode>());
3053+
if (v.value<ParenthesesMode>() != ParenthesesMode::BOTH && v.value<ParenthesesMode>() != ParenthesesMode::NONE) {
3054+
ASSERT_X("Notes cannot set left & right parens individually");
3055+
}
3056+
m_hasParens = v.value<ParenthesesMode>() == ParenthesesMode::BOTH;
30523057
if (links()) {
30533058
for (EngravingObject* scoreElement : *links()) {
30543059
Note* note = toNote(scoreElement);

src/engraving/dom/note.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,8 @@ class Note final : public EngravingItem
524524

525525
bool m_harmonic = false;
526526

527+
bool m_hasParens = false;
528+
527529
ElementList m_el; // fingering, other text, symbols or images
528530
std::vector<NoteDot*> m_dots;
529531
NoteEventList m_playEvents;

src/engraving/dom/utils.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1847,4 +1847,34 @@ std::vector<EngravingItem*> filterTargetElements(const Selection& sel, Engraving
18471847
}
18481848
return result;
18491849
}
1850+
1851+
bool noteIsBefore(const Note* n1, const Note* n2)
1852+
{
1853+
const int l1 = n1->line();
1854+
const int l2 = n2->line();
1855+
if (l1 != l2) {
1856+
return l1 > l2;
1857+
}
1858+
1859+
const int p1 = n1->pitch();
1860+
const int p2 = n2->pitch();
1861+
if (p1 != p2) {
1862+
return p1 < p2;
1863+
}
1864+
1865+
if (n1->tieBack()) {
1866+
if (n2->tieBack() && !n2->incomingPartialTie()) {
1867+
const Note* sn1 = n1->tieBack()->startNote();
1868+
const Note* sn2 = n2->tieBack()->startNote();
1869+
if (sn1->chord() == sn2->chord()) {
1870+
return sn1->unisonIndex() < sn2->unisonIndex();
1871+
}
1872+
return sn1->chord()->isBefore(sn2->chord());
1873+
} else {
1874+
return true; // place tied notes before
1875+
}
1876+
}
1877+
1878+
return false;
1879+
}
18501880
}

src/engraving/dom/utils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,6 @@ extern bool isValidBarLineForRepeatSection(const Segment* firstSeg, const Segmen
126126
extern bool isElementInFretBox(const EngravingItem* item);
127127

128128
extern std::vector<EngravingItem*> filterTargetElements(const Selection& sel, EngravingItem* dropElement, bool& unique);
129+
130+
extern bool noteIsBefore(const Note* n1, const Note* n2);
129131
} // namespace mu::engraving

src/engraving/editing/cmd.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3395,6 +3395,26 @@ void Score::cmdAddBracket()
33953395

33963396
void Score::cmdAddParentheses()
33973397
{
3398+
std::list<Note*> notes = selection().uniqueNotes();
3399+
if (!notes.empty()) {
3400+
std::map<Chord*, std::vector<Note*> > notesByChord;
3401+
for (Note* note : notes) {
3402+
Chord* chord = note->chord();
3403+
auto it = notesByChord.find(chord);
3404+
if (it != notesByChord.end()) {
3405+
it->second.push_back(note);
3406+
} else {
3407+
std::vector<Note*> noteVector{ note };
3408+
notesByChord.insert(std::make_pair(chord, noteVector));
3409+
}
3410+
}
3411+
3412+
for (auto& i : notesByChord) {
3413+
Chord* chord = i.first;
3414+
EditChord::toggleChordParentheses(chord, i.second);
3415+
}
3416+
}
3417+
33983418
for (EngravingItem* el : selection().elements()) {
33993419
cmdAddParentheses(el);
34003420
}

0 commit comments

Comments
 (0)