Skip to content

Commit

Permalink
Percussion shadow note popup - improve stability of popup
Browse files Browse the repository at this point in the history
  • Loading branch information
mathesoncalum committed Jan 13, 2025
1 parent 23b01e1 commit e9cfe53
Show file tree
Hide file tree
Showing 14 changed files with 97 additions and 17 deletions.
3 changes: 3 additions & 0 deletions src/engraving/dom/engravingobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ class VoltaSegment;
class WhammyBar;
class WhammyBarSegment;
class FretCircle;
class ShadowNote;

class LinkedObjects;

Expand Down Expand Up @@ -452,6 +453,7 @@ class EngravingObject
CONVERT(FretCircle, FRET_CIRCLE)
CONVERT(StringTunings, STRING_TUNINGS)
CONVERT(TimeTickAnchor, TIME_TICK_ANCHOR)
CONVERT(ShadowNote, SHADOW_NOTE)
#undef CONVERT

virtual bool isEngravingItem() const { return false; } // overridden in element.h
Expand Down Expand Up @@ -857,5 +859,6 @@ CONVERT(SoundFlag)
CONVERT(TimeTickAnchor)
CONVERT(LaissezVib)
CONVERT(PartialTie)
CONVERT(ShadowNote)
#undef CONVERT
}
1 change: 1 addition & 0 deletions src/notation/inotationinteraction.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class INotationInteraction
virtual bool showShadowNote(const muse::PointF& pos) = 0;
virtual void hideShadowNote() = 0;
virtual muse::RectF shadowNoteRect() const = 0;
virtual muse::async::Notification shadowNoteChanged() const = 0;

// Visibility
virtual void toggleVisible() = 0;
Expand Down
11 changes: 11 additions & 0 deletions src/notation/internal/notationinteraction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,8 @@ bool NotationInteraction::showShadowNote(const PointF& pos)
mu::engraving::Position position;
if (!score()->getPosition(&position, pos, inputState.voice())) {
shadowNote.setVisible(false);
shadowNote.setDrumNotePitch(-1);
m_shadowNoteChanged.notify();
return false;
}

Expand Down Expand Up @@ -419,9 +421,12 @@ bool NotationInteraction::showShadowNote(const PointF& pos)
} while (pitch != startPitch);
if (!drumNoteFound) {
shadowNote.setVisible(false);
shadowNote.setDrumNotePitch(-1);
m_shadowNoteChanged.notify();
return false;
}
} else {
shadowNote.setDrumNotePitch(-1);
voice = inputState.voice();
}

Expand Down Expand Up @@ -455,6 +460,7 @@ bool NotationInteraction::showShadowNote(const PointF& pos)
score()->renderer()->layoutItem(&shadowNote);

shadowNote.setPos(position.pos);
m_shadowNoteChanged.notify();

return true;
}
Expand Down Expand Up @@ -485,6 +491,11 @@ RectF NotationInteraction::shadowNoteRect() const
return rect;
}

muse::async::Notification NotationInteraction::shadowNoteChanged() const
{
return m_shadowNoteChanged;
}

void NotationInteraction::toggleVisible()
{
startEdit(TranslatableString("undoableAction", "Toggle visible"));
Expand Down
2 changes: 2 additions & 0 deletions src/notation/internal/notationinteraction.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class NotationInteraction : public INotationInteraction, public muse::Injectable
bool showShadowNote(const muse::PointF& pos) override;
void hideShadowNote() override;
muse::RectF shadowNoteRect() const override;
muse::async::Notification shadowNoteChanged() const override;

// Visibility
void toggleVisible() override;
Expand Down Expand Up @@ -440,6 +441,7 @@ class NotationInteraction : public INotationInteraction, public muse::Injectable

std::shared_ptr<NotationSelection> m_selection = nullptr;
muse::async::Notification m_selectionChanged;
muse::async::Notification m_shadowNoteChanged;

DragData m_dragData;
muse::async::Notification m_dragChanged;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ Row {

PercussionNotePopupContentModel {
id: contentModel

Component.onCompleted: {
contentModel.init()
}
}

Row {
Expand Down
1 change: 1 addition & 0 deletions src/notation/tests/mocks/notationinteractionmock.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class NotationInteractionMock : public INotationInteraction
MOCK_METHOD(bool, showShadowNote, (const muse::PointF&), (override));
MOCK_METHOD(void, hideShadowNote, (), (override));
MOCK_METHOD(muse::RectF, shadowNoteRect, (), (const, override));
MOCK_METHOD(muse::async::Notification, shadowNoteChanged, (), (const, override));

MOCK_METHOD(void, toggleVisible, (), (override));

Expand Down
5 changes: 4 additions & 1 deletion src/notation/view/abstractelementpopupmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include "abstractelementpopupmodel.h"
#include "internal/partialtiepopupmodel.h"
#include "internal/shadownotepopupmodel.h"
#include "log.h"

using namespace mu::notation;
Expand Down Expand Up @@ -75,6 +76,8 @@ bool AbstractElementPopupModel::supportsPopup(const EngravingItem* element)
switch (modelType) {
case PopupModelType::TYPE_PARTIAL_TIE:
return PartialTiePopupModel::canOpen(element);
case PopupModelType::TYPE_SHADOW_NOTE:
return ShadowNotePopupModel::canOpen(element);
default:
return true;
}
Expand Down Expand Up @@ -233,7 +236,7 @@ const mu::engraving::ElementTypeSet& AbstractElementPopupModel::dependentElement

void AbstractElementPopupModel::updateItemRect()
{
QRect rect = m_item ? fromLogical(m_item->canvasBoundingRect()).toQRect() : QRect();
const QRect rect = m_item ? fromLogical(m_item->canvasBoundingRect()).toQRect() : QRect();

if (m_itemRect != rect) {
m_itemRect = rect;
Expand Down
6 changes: 3 additions & 3 deletions src/notation/view/abstractelementpopupmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ class AbstractElementPopupModel : public QObject, public muse::Injectable, publi
void itemRectChanged(QRect rect);

protected:
virtual void updateItemRect();

muse::PointF fromLogical(muse::PointF point) const;
muse::RectF fromLogical(muse::RectF rect) const;

Expand All @@ -87,17 +89,15 @@ class AbstractElementPopupModel : public QObject, public muse::Injectable, publi
void changeItemProperty(mu::engraving::Pid id, const PropertyValue& value, engraving::PropertyFlags flags);

EngravingItem* m_item = nullptr;
QRect m_itemRect;

private:
INotationSelectionPtr selection() const;

engraving::ElementType elementType() const;
const engraving::ElementTypeSet& dependentElementTypes() const;

void updateItemRect();

PopupModelType m_modelType = PopupModelType::TYPE_UNDEFINED;
QRect m_itemRect;
};

using PopupModelType = AbstractElementPopupModel::PopupModelType;
Expand Down
15 changes: 12 additions & 3 deletions src/notation/view/internal/percussionnotepopupcontentmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ PercussionNotePopupContentModel::PercussionNotePopupContentModel(QObject* parent
{
}

void PercussionNotePopupContentModel::init()
{
interaction()->shadowNoteChanged().onNotify(this, [this]() {
emit shouldShowButtonsChanged();
emit percussionNoteNameChanged();
emit keyboardShortcutChanged();
});
}

void PercussionNotePopupContentModel::prevDrumNote()
{
const Drumset* ds = currentDrumset();
Expand Down Expand Up @@ -98,7 +107,7 @@ bool PercussionNotePopupContentModel::shouldShowButtons() const
{
const Drumset* ds = currentDrumset();
const mu::engraving::ShadowNote* shadowNote = currentShadowNote();
if (!ds || !shadowNote) {
if (!ds || !shadowNote || !shadowNote->visible() || shadowNote->drumNotePitch() < 0) {
return false;
}

Expand All @@ -121,7 +130,7 @@ QString PercussionNotePopupContentModel::percussionNoteName() const
{
const Drumset* ds = currentDrumset();
const mu::engraving::ShadowNote* shadowNote = currentShadowNote();
if (!ds || !shadowNote) {
if (!ds || !shadowNote || !shadowNote->visible() || shadowNote->drumNotePitch() < 0) {
return QString();
}

Expand All @@ -132,7 +141,7 @@ QString PercussionNotePopupContentModel::keyboardShortcut() const
{
const Drumset* ds = currentDrumset();
const mu::engraving::ShadowNote* shadowNote = currentShadowNote();
if (!ds || !shadowNote) {
if (!ds || !shadowNote || !shadowNote->visible() || shadowNote->drumNotePitch() < 0) {
return QString();
}

Expand Down
6 changes: 5 additions & 1 deletion src/notation/view/internal/percussionnotepopupcontentmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@

#include <QObject>

#include "async/asyncable.h"

#include "modularity/ioc.h"
#include "context/iglobalcontext.h"

namespace mu::notation {
class PercussionNotePopupContentModel : public QObject, public muse::Injectable
class PercussionNotePopupContentModel : public QObject, public muse::Injectable, public muse::async::Asyncable
{
Q_OBJECT

Expand All @@ -41,6 +43,8 @@ class PercussionNotePopupContentModel : public QObject, public muse::Injectable
public:
explicit PercussionNotePopupContentModel(QObject* parent = nullptr);

Q_INVOKABLE void init();

Q_INVOKABLE void prevDrumNote();
Q_INVOKABLE void nextDrumNote();

Expand Down
42 changes: 40 additions & 2 deletions src/notation/view/internal/shadownotepopupmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,54 @@ ShadowNotePopupModel::ShadowNotePopupModel(QObject* parent)
{
}

bool ShadowNotePopupModel::canOpen(const EngravingItem* element)
{
if (!element || !element->isShadowNote() || !element->visible()) {
return false;
}

const mu::engraving::ShadowNote* shadowNote = toShadowNote(element);
if (shadowNote->drumNotePitch() > -1) {
// Can open with PERCUSSON_CONTENT type
return true;
}

return false;
}

void ShadowNotePopupModel::init()
{
AbstractElementPopupModel::init();

m_item = interaction()->shadowNote();

interaction()->shadowNoteChanged().onNotify(this, [this]() {
updateItemRect();
});

emit currentPopupTypeChanged();
}

ShadowNotePopupContent::ContentType ShadowNotePopupModel::currentPopupType() const
{
// TODO: evaluate the current content type based on the context
return ShadowNotePopupContent::ContentType::PERCUSSION_CONTENT;
const mu::engraving::ShadowNote* shadowNote = interaction()->shadowNote();
if (shadowNote && shadowNote->visible() && shadowNote->drumNotePitch() > -1) {
return ShadowNotePopupContent::ContentType::PERCUSSION_CONTENT;
}
return ShadowNotePopupContent::ContentType::NONE;
}

void ShadowNotePopupModel::updateItemRect()
{
const mu::engraving::ShadowNote* shadowNote = interaction()->shadowNote();
if (!shadowNote || !shadowNote->visible()) {
m_itemRect = QRect();
emit itemRectChanged(m_itemRect);
}

muse::RectF noteHeadRect = shadowNote->symBbox(shadowNote->noteheadSymbol());
noteHeadRect.translate(shadowNote->canvasPos().x(), shadowNote->canvasPos().y());

m_itemRect = fromLogical(noteHeadRect).toQRect();
emit itemRectChanged(m_itemRect);
}
6 changes: 6 additions & 0 deletions src/notation/view/internal/shadownotepopupmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,17 @@ class ShadowNotePopupModel : public AbstractElementPopupModel

public:
explicit ShadowNotePopupModel(QObject* parent = nullptr);

static bool canOpen(const EngravingItem* shadowNote);

Q_INVOKABLE void init();

ShadowNotePopupContent::ContentType currentPopupType() const;

signals:
void currentPopupTypeChanged();

protected:
void updateItemRect() override;
};
} // namespace mu::notation
11 changes: 4 additions & 7 deletions src/notation/view/notationviewinputcontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1014,10 +1014,6 @@ void NotationViewInputController::hoverMoveEvent(QHoverEvent* event)
}

m_view->showShadowNote(pos);

if (event->modifiers() == Qt::ShiftModifier) {
updateShadowNotePopupVisibility();
}
}

bool NotationViewInputController::shortcutOverrideEvent(QKeyEvent* event)
Expand All @@ -1042,9 +1038,9 @@ void NotationViewInputController::keyPressEvent(QKeyEvent* event)
dispatcher()->dispatch("edit-text");
event->accept();
}
} else if (event->key() == Qt::Key_Shift) {
updateShadowNotePopupVisibility();
}

updateShadowNotePopupVisibility();
}

void NotationViewInputController::keyReleaseEvent(QKeyEvent* event)
Expand Down Expand Up @@ -1247,8 +1243,9 @@ void NotationViewInputController::togglePopupForItemIfSupports(const EngravingIt
void NotationViewInputController::updateShadowNotePopupVisibility()
{
const mu::engraving::ShadowNote* shadowNote = viewInteraction()->shadowNote();
if (!shadowNote || !shadowNote->visible()) {
if (!shadowNote || !AbstractElementPopupModel::supportsPopup(shadowNote)) {
m_view->hideElementPopup(); // TEMP HACK - we only want to hide the shadow note popup here
return;
}

RectF noteHeadRect = shadowNote->symBbox(shadowNote->noteheadSymbol());
Expand Down
1 change: 1 addition & 0 deletions src/notation/view/notationviewinputcontroller.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "actions/iactionsdispatcher.h"
#include "actions/actionable.h"
#include "async/asyncable.h"
#include "async/async.h"

#include "context/iglobalcontext.h"

Expand Down

0 comments on commit e9cfe53

Please sign in to comment.