Skip to content

Commit 76fef15

Browse files
authored
Merge pull request #24147 from ketgg/gsoc_dynamics_popup_part_2
GSoC '24 - Dynamics Popup - Part 2
2 parents 2f1accb + 4d9efc0 commit 76fef15

File tree

10 files changed

+291
-12
lines changed

10 files changed

+291
-12
lines changed

src/engraving/dom/cmd.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -598,7 +598,6 @@ void Score::cmdAddSpanner(Spanner* spanner, const PointF& pos, bool systemStaves
598598

599599
bool ctrlModifier = isSystemTextLine(spanner) && !systemStavesOnly;
600600
undoAddElement(spanner, true /*addToLinkedStaves*/, ctrlModifier);
601-
select(spanner, SelectType::SINGLE, 0);
602601
}
603602

604603
//---------------------------------------------------------

src/engraving/dom/dynamic.cpp

Lines changed: 146 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838

3939
#include "log.h"
4040

41-
using namespace mu;
41+
using namespace muse::draw;
4242
using namespace mu::engraving;
4343

4444
namespace mu::engraving {
@@ -532,6 +532,39 @@ TranslatableString Dynamic::subtypeUserName() const
532532
}
533533
}
534534

535+
void Dynamic::editDrag(EditData& ed)
536+
{
537+
const bool hasLeftGrip = this->hasLeftGrip();
538+
const bool hasRightGrip = this->hasRightGrip();
539+
540+
// Right grip (when two grips/when single grip)
541+
if ((int(ed.curGrip) == 1 && hasLeftGrip && hasRightGrip) || (int(ed.curGrip) == 0 && !hasLeftGrip && hasRightGrip)) {
542+
m_rightDragOffset += ed.evtDelta.x();
543+
if (m_rightDragOffset < 0) {
544+
m_rightDragOffset = 0;
545+
}
546+
return;
547+
}
548+
549+
// Left grip (when two grips or single grip)
550+
if (int(ed.curGrip) == 0 && hasLeftGrip) {
551+
m_leftDragOffset += ed.evtDelta.x();
552+
if (m_leftDragOffset > 0) {
553+
m_leftDragOffset = 0;
554+
}
555+
return;
556+
}
557+
558+
TextBase::editDrag(ed);
559+
}
560+
561+
void Dynamic::endEditDrag(EditData& ed)
562+
{
563+
m_leftDragOffset = m_rightDragOffset = 0.0;
564+
565+
TextBase::endEditDrag(ed);
566+
}
567+
535568
//---------------------------------------------------------
536569
// reset
537570
//---------------------------------------------------------
@@ -717,3 +750,115 @@ String Dynamic::screenReaderInfo() const
717750
return String(u"%1: %2").arg(EngravingItem::accessibleInfo(), s);
718751
}
719752
}
753+
754+
//---------------------------------------------------------
755+
// drawEditMode
756+
//---------------------------------------------------------
757+
758+
void Dynamic::drawEditMode(Painter* p, EditData& ed, double currentViewScaling)
759+
{
760+
if (ed.editTextualProperties) {
761+
TextBase::drawEditMode(p, ed, currentViewScaling);
762+
} else {
763+
EngravingItem::drawEditMode(p, ed, currentViewScaling);
764+
}
765+
}
766+
767+
//---------------------------------------------------------
768+
// hasLeftHairpin
769+
//---------------------------------------------------------
770+
771+
bool Dynamic::hasLeftGrip() const
772+
{
773+
if (segment()->tick().isZero()) {
774+
return false; // Don't show the left grip for the leftmost dynamic with tick zero
775+
}
776+
return m_leftHairpin == nullptr;
777+
}
778+
779+
//---------------------------------------------------------
780+
// hasRightHairpin
781+
//---------------------------------------------------------
782+
783+
bool Dynamic::hasRightGrip() const
784+
{
785+
return m_rightHairpin == nullptr;
786+
}
787+
788+
//---------------------------------------------------------
789+
// findAdjacentHairpins
790+
//---------------------------------------------------------
791+
792+
void Dynamic::findAdjacentHairpins()
793+
{
794+
m_leftHairpin = nullptr;
795+
m_rightHairpin = nullptr;
796+
797+
const Fraction tick = segment()->tick();
798+
const int intTick = tick.ticks();
799+
800+
const auto& spanners = score()->spannerMap().findOverlapping(intTick - 1, intTick + 1);
801+
for (auto i : spanners) {
802+
Spanner* sp = i.value;
803+
if (sp->track() == track() && sp->isHairpin()) {
804+
Hairpin* hp = toHairpin(sp);
805+
if (hp->tick() == tick) {
806+
m_rightHairpin = hp;
807+
} else if (hp->tick2() == tick) {
808+
m_leftHairpin = hp;
809+
}
810+
}
811+
}
812+
}
813+
814+
//---------------------------------------------------------
815+
// gripsCount
816+
//---------------------------------------------------------
817+
818+
int Dynamic::gripsCount() const
819+
{
820+
if (empty()) {
821+
return 0;
822+
}
823+
824+
const bool hasLeftGrip = this->hasLeftGrip();
825+
const bool hasRightGrip = this->hasRightGrip();
826+
827+
if (hasLeftGrip && hasRightGrip) {
828+
return 2;
829+
} else if (hasLeftGrip || hasRightGrip) {
830+
return 1;
831+
} else {
832+
return 0;
833+
}
834+
}
835+
836+
//---------------------------------------------------------
837+
// gripsPositions
838+
//---------------------------------------------------------
839+
840+
std::vector<PointF> Dynamic::gripsPositions(const EditData&) const
841+
{
842+
const LayoutData* ldata = this->ldata();
843+
const PointF pp(pagePos());
844+
double md = score()->style().styleS(Sid::hairpinMinDistance).val() * spatium(); // Minimum distance between dynamic and grip
845+
846+
// Calculated by subtracting the y-value of the dynamic's pagePos from the y-value of hairpin's Grip::START position in HairpinSegment::gripsPositions
847+
const double GRIP_VERTICAL_OFFSET = -11.408;
848+
849+
PointF leftOffset(-ldata->bbox().width() / 2 - md + m_leftDragOffset, GRIP_VERTICAL_OFFSET);
850+
PointF rightOffset(ldata->bbox().width() / 2 + md + m_rightDragOffset, GRIP_VERTICAL_OFFSET);
851+
852+
const bool hasLeftGrip = this->hasLeftGrip();
853+
const bool hasRightGrip = this->hasRightGrip();
854+
855+
if (hasLeftGrip && hasRightGrip) {
856+
return { pp + leftOffset, pp + rightOffset };
857+
} else if (hasLeftGrip) {
858+
return { pp + leftOffset };
859+
} else if (hasRightGrip) {
860+
return { pp + rightOffset };
861+
} else {
862+
return {};
863+
}
864+
}

src/engraving/dom/dynamic.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525

2626
#include "textbase.h"
2727

28+
namespace muse::draw {
29+
class Painter;
30+
}
31+
2832
namespace mu::engraving {
2933
class Measure;
3034
class Segment;
@@ -114,6 +118,26 @@ class Dynamic final : public TextBase
114118

115119
bool hasVoiceAssignmentProperties() const override { return true; }
116120

121+
int gripsCount() const override;
122+
std::vector<PointF> gripsPositions(const EditData& = EditData()) const override;
123+
void editDrag(EditData& editData) override;
124+
void endEditDrag(EditData&) override;
125+
void drawEditMode(muse::draw::Painter* painter, EditData& editData, double currentViewScaling) override;
126+
127+
Hairpin* leftHairpin() const { return m_leftHairpin; }
128+
Hairpin* rightHairpin() const { return m_rightHairpin; }
129+
130+
bool hasLeftGrip() const;
131+
bool hasRightGrip() const;
132+
133+
void resetLeftDragOffset() { m_leftDragOffset = 0.0; }
134+
void resetRightDragOffset() { m_rightDragOffset = 0.0; }
135+
136+
double leftDragOffset() const { return m_leftDragOffset; }
137+
double rightDragOffset() const { return m_rightDragOffset; }
138+
139+
void findAdjacentHairpins();
140+
117141
private:
118142

119143
M_PROPERTY(bool, avoidBarLines, setAvoidBarLines)
@@ -132,6 +156,12 @@ class Dynamic final : public TextBase
132156
DynamicSpeed m_velChangeSpeed = DynamicSpeed::NORMAL;
133157

134158
static const std::vector<Dyn> DYN_LIST;
159+
160+
double m_leftDragOffset = 0.0;
161+
double m_rightDragOffset = 0.0;
162+
163+
Hairpin* m_leftHairpin = nullptr;
164+
Hairpin* m_rightHairpin = nullptr;
135165
};
136166
} // namespace mu::engraving
137167

src/engraving/dom/edit.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "infrastructure/messagebox.h"
2828

2929
#include "accidental.h"
30+
#include "anchors.h"
3031
#include "articulation.h"
3132
#include "barline.h"
3233
#include "beam.h"
@@ -3964,6 +3965,45 @@ void Score::addHairpinToDynamic(Hairpin* hairpin, Dynamic* dynamic)
39643965
undoAddElement(hairpin);
39653966
}
39663967

3968+
Hairpin* Score::addHairpinToDynamicOnGripDrag(Dynamic* dynamic, bool isLeftGrip, const PointF& pos)
3969+
{
3970+
const track_idx_t track = dynamic->track();
3971+
staff_idx_t staffIndex = dynamic->staffIdx();
3972+
Segment* seg = nullptr;
3973+
constexpr double spacingFactor = 0.5;
3974+
3975+
// Ensure time tick segments are created
3976+
EditTimeTickAnchors::updateAnchors(dynamic, track);
3977+
3978+
// Find segment of type ChordRest or TimeTick near cursor postion
3979+
dragPosition(pos, &staffIndex, &seg, spacingFactor, /*allowTimeAnchor*/ true);
3980+
3981+
const bool hasValidTick = seg && (isLeftGrip
3982+
? seg->tick() < dynamic->tick()
3983+
: seg->tick() > dynamic->tick());
3984+
if (!hasValidTick) {
3985+
return nullptr;
3986+
}
3987+
3988+
Hairpin* hairpin = Factory::createHairpin(dummy()->segment());
3989+
hairpin->setHairpinType(isLeftGrip ? HairpinType::DECRESC_HAIRPIN : HairpinType::CRESC_HAIRPIN);
3990+
3991+
hairpin->setTrack(track);
3992+
hairpin->setTrack2(track);
3993+
3994+
if (isLeftGrip) {
3995+
hairpin->setTick(seg->tick());
3996+
hairpin->setTick2(dynamic->tick());
3997+
} else {
3998+
hairpin->setTick(dynamic->tick());
3999+
hairpin->setTick2(seg->tick());
4000+
}
4001+
4002+
undoAddElement(hairpin);
4003+
4004+
return hairpin;
4005+
}
4006+
39674007
//---------------------------------------------------------
39684008
// cmdCreateTuplet
39694009
// replace cr with tuplet

src/engraving/dom/editdata.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ DECLARE_OPERATORS_FOR_FLAGS(MouseButtons)
213213
enum class Grip {
214214
NO_GRIP = -1,
215215
START = 0, END = 1, // arpeggio etc.
216+
LEFT = START, RIGHT = END, // aliases for dynamic
216217
MIDDLE = 2, APERTURE = 3, // Line
217218
/*START, END , */
218219
BEZIER1 = 2, SHOULDER = 3, BEZIER2 = 4, DRAG = 5, // Slur

src/engraving/dom/score.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ class Bracket;
9898
class Chord;
9999
class ChordRest;
100100
class Clef;
101+
class Dynamic;
101102
class Element;
102103
class EventsHolder;
103104
class Excerpt;
@@ -932,6 +933,7 @@ class Score : public EngravingObject, public muse::Injectable
932933
Hairpin* addHairpin(HairpinType type, ChordRest* cr1, ChordRest* cr2 = nullptr);
933934
void addHairpin(Hairpin* hairpin, ChordRest* cr1, ChordRest* cr2 = nullptr);
934935
void addHairpinToDynamic(Hairpin* hairpin, Dynamic* dynamic);
936+
Hairpin* addHairpinToDynamicOnGripDrag(Dynamic* dynamic, bool isLeftGrip, const PointF& pos);
935937

936938
ChordRest* findCR(Fraction tick, track_idx_t track) const;
937939
ChordRest* findChordRestEndingBeforeTickInStaff(const Fraction& tick, staff_idx_t staffIdx) const;

src/notation/inotationinteraction.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ class INotationInteraction
186186
virtual void addLaissezVibToSelection() = 0;
187187
virtual void addSlurToSelection() = 0;
188188
virtual void addOttavaToSelection(OttavaType type) = 0;
189+
virtual void addHairpinOnGripDrag(engraving::Dynamic* dynamic, bool isLeftGrip) = 0;
189190
virtual void addHairpinsToSelection(HairpinType type) = 0;
190191
virtual void putRestToSelection() = 0;
191192
virtual void putRest(Duration duration) = 0;

0 commit comments

Comments
 (0)