Merge pull request #10401 from RomanPudashkin/grip_points_nagivation
[MU4] Fix #9902: Can't adjust line or slur length via keyboard
This commit is contained in:
commit
a8be42c6ce
10 changed files with 238 additions and 147 deletions
|
@ -1938,10 +1938,10 @@ void Score::cmdAddOttava(OttavaType type)
|
|||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// addHairpin
|
||||
// addHairpins
|
||||
//---------------------------------------------------------
|
||||
|
||||
void Score::addHairpin(HairpinType type)
|
||||
std::vector<Hairpin*> Score::addHairpins(HairpinType type)
|
||||
{
|
||||
// special case for two selected chordrests on same staff
|
||||
bool twoNotesSameStaff = false;
|
||||
|
@ -1954,12 +1954,14 @@ void Score::addHairpin(HairpinType type)
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<Hairpin*> hairpins;
|
||||
|
||||
// add hairpin on each staff if possible
|
||||
if (selection().isRange() && selection().staffStart() != selection().staffEnd() - 1) {
|
||||
for (int staffIdx = selection().staffStart(); staffIdx < selection().staffEnd(); ++staffIdx) {
|
||||
ChordRest* cr1 = selection().firstChordRest(staffIdx * VOICES);
|
||||
ChordRest* cr2 = selection().lastChordRest(staffIdx * VOICES);
|
||||
addHairpin(type, cr1, cr2, /* toCr2End */ true);
|
||||
hairpins.push_back(addHairpin(type, cr1, cr2, /* toCr2End */ true));
|
||||
}
|
||||
} else if (selection().isRange() || selection().isSingle() || twoNotesSameStaff) {
|
||||
// for single staff range selection, or single selection,
|
||||
|
@ -1968,8 +1970,10 @@ void Score::addHairpin(HairpinType type)
|
|||
ChordRest* cr2 = nullptr;
|
||||
getSelectedChordRest2(&cr1, &cr2);
|
||||
|
||||
addHairpin(type, cr1, cr2, /* toCr2End */ !twoNotesSameStaff);
|
||||
hairpins.push_back(addHairpin(type, cr1, cr2, /* toCr2End */ !twoNotesSameStaff));
|
||||
}
|
||||
|
||||
return hairpins;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
|
|
|
@ -584,7 +584,7 @@ public:
|
|||
void cmdToggleTie();
|
||||
static std::vector<Note*> cmdTieNoteList(const Selection& selection, bool noteEntryMode);
|
||||
void cmdAddOttava(OttavaType);
|
||||
void addHairpin(HairpinType);
|
||||
std::vector<Ms::Hairpin*> addHairpins(HairpinType);
|
||||
void addNoteLine();
|
||||
void padToggle(Pad p, const EditData& ed);
|
||||
void cmdAddPitch(const EditData&, int note, bool addFlag, bool insert);
|
||||
|
|
|
@ -174,6 +174,8 @@ bool SlurSegment::edit(EditData& ed)
|
|||
Part* part = e->part();
|
||||
int endTrack = part->endTrack();
|
||||
cr = searchCR(e->segment(), startTrack, endTrack);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (cr && cr != e1) {
|
||||
changeAnchor(ed, cr);
|
||||
|
|
|
@ -101,7 +101,9 @@ public:
|
|||
virtual void redo() = 0;
|
||||
|
||||
// Change selection
|
||||
virtual bool moveSelectionAvailable(MoveSelectionType type) const = 0;
|
||||
virtual void moveSelection(MoveDirection d, MoveSelectionType type) = 0;
|
||||
|
||||
virtual void moveLyrics(MoveDirection d) = 0;
|
||||
virtual void expandSelection(ExpandSelectionMode mode) = 0;
|
||||
virtual void addToSelection(MoveDirection d, MoveSelectionType type) = 0;
|
||||
|
@ -159,7 +161,7 @@ public:
|
|||
virtual void addTiedNoteToChord() = 0;
|
||||
virtual void addSlurToSelection() = 0;
|
||||
virtual void addOttavaToSelection(OttavaType type) = 0;
|
||||
virtual void addHairpinToSelection(HairpinType type) = 0;
|
||||
virtual void addHairpinsToSelection(HairpinType type) = 0;
|
||||
virtual void addAccidentalToSelection(AccidentalType type) = 0;
|
||||
virtual void putRestToSelection() = 0;
|
||||
virtual void putRest(DurationType duration) = 0;
|
||||
|
|
|
@ -162,16 +162,19 @@ void NotationActionController::init()
|
|||
|
||||
registerAction("toggle-visible", &Interaction::toggleVisible);
|
||||
|
||||
registerAction("next-element", &Interaction::moveSelection, MoveDirection::Right, MoveSelectionType::EngravingItem,
|
||||
PlayMode::PlayNote);
|
||||
registerAction("prev-element", &Interaction::moveSelection, MoveDirection::Left, MoveSelectionType::EngravingItem,
|
||||
PlayMode::PlayNote);
|
||||
registerMoveSelectionAction("next-element", MoveSelectionType::EngravingItem, MoveDirection::Right, PlayMode::PlayNote);
|
||||
registerMoveSelectionAction("prev-element", MoveSelectionType::EngravingItem, MoveDirection::Left, PlayMode::PlayNote);
|
||||
registerMoveSelectionAction("next-track", MoveSelectionType::Track, MoveDirection::Right, PlayMode::PlayChord);
|
||||
registerMoveSelectionAction("prev-track", MoveSelectionType::Track, MoveDirection::Left, PlayMode::PlayChord);
|
||||
registerMoveSelectionAction("next-frame", MoveSelectionType::Frame, MoveDirection::Right);
|
||||
registerMoveSelectionAction("prev-frame", MoveSelectionType::Frame, MoveDirection::Left);
|
||||
registerMoveSelectionAction("next-system", MoveSelectionType::System, MoveDirection::Right);
|
||||
registerMoveSelectionAction("prev-system", MoveSelectionType::System, MoveDirection::Left);
|
||||
|
||||
registerAction("notation-move-right", &Controller::move, MoveDirection::Right, false);
|
||||
registerAction("notation-move-left", &Controller::move, MoveDirection::Left, false);
|
||||
registerAction("notation-move-right-quickly", &Controller::move, MoveDirection::Right, true, &Controller::measureNavigationAvailable);
|
||||
registerAction("notation-move-left-quickly", &Controller::move, MoveDirection::Left, true, &Controller::measureNavigationAvailable);
|
||||
registerAction("next-track", &Interaction::moveSelection, MoveDirection::Right, MoveSelectionType::Track, PlayMode::PlayChord);
|
||||
registerAction("prev-track", &Interaction::moveSelection, MoveDirection::Left, MoveSelectionType::Track, PlayMode::PlayChord);
|
||||
registerAction("pitch-up", &Controller::move, MoveDirection::Up, false);
|
||||
registerAction("pitch-down", &Controller::move, MoveDirection::Down, false);
|
||||
registerAction("pitch-up-octave", &Controller::move, MoveDirection::Up, true);
|
||||
|
@ -218,10 +221,6 @@ void NotationActionController::init()
|
|||
registerAction("move-down", &Interaction::moveChordRestToStaff, MoveDirection::Down, &Controller::hasSelection);
|
||||
registerAction("move-left", &Interaction::swapChordRest, MoveDirection::Left, &Controller::isNoteInputMode);
|
||||
registerAction("move-right", &Interaction::swapChordRest, MoveDirection::Right, &Controller::isNoteInputMode);
|
||||
registerAction("next-frame", &Interaction::moveSelection, MoveDirection::Right, MoveSelectionType::Frame);
|
||||
registerAction("prev-frame", &Interaction::moveSelection, MoveDirection::Left, MoveSelectionType::Frame);
|
||||
registerAction("next-system", &Interaction::moveSelection, MoveDirection::Right, MoveSelectionType::System);
|
||||
registerAction("prev-system", &Interaction::moveSelection, MoveDirection::Left, MoveSelectionType::System);
|
||||
registerAction("next-segment-element", &Interaction::moveSegmentSelection, MoveDirection::Right, PlayMode::PlayNote);
|
||||
registerAction("prev-segment-element", &Interaction::moveSegmentSelection, MoveDirection::Left, PlayMode::PlayNote);
|
||||
|
||||
|
@ -286,8 +285,8 @@ void NotationActionController::init()
|
|||
|
||||
registerAction("add-8va", &Interaction::addOttavaToSelection, OttavaType::OTTAVA_8VA);
|
||||
registerAction("add-8vb", &Interaction::addOttavaToSelection, OttavaType::OTTAVA_8VB);
|
||||
registerAction("add-hairpin", &Interaction::addHairpinToSelection, HairpinType::CRESC_HAIRPIN);
|
||||
registerAction("add-hairpin-reverse", &Interaction::addHairpinToSelection, HairpinType::DECRESC_HAIRPIN);
|
||||
registerAction("add-hairpin", &Interaction::addHairpinsToSelection, HairpinType::CRESC_HAIRPIN);
|
||||
registerAction("add-hairpin-reverse", &Interaction::addHairpinsToSelection, HairpinType::DECRESC_HAIRPIN);
|
||||
registerAction("add-noteline", &Interaction::addAnchoredLineToSelectedNotes);
|
||||
|
||||
registerAction("title-text", [this]() { addText(TextStyleType::TITLE); });
|
||||
|
@ -478,7 +477,7 @@ bool NotationActionController::canReceiveAction(const actions::ActionCode& code)
|
|||
|
||||
auto iter = m_isEnabledMap.find(code);
|
||||
if (iter != m_isEnabledMap.end()) {
|
||||
bool enabled = (this->*iter->second)();
|
||||
bool enabled = iter->second();
|
||||
return enabled;
|
||||
}
|
||||
|
||||
|
@ -794,6 +793,22 @@ void NotationActionController::halveNoteInputDuration()
|
|||
}
|
||||
}
|
||||
|
||||
bool NotationActionController::moveSelectionAvailable(MoveSelectionType type) const
|
||||
{
|
||||
auto interaction = currentNotationInteraction();
|
||||
return interaction && interaction->moveSelectionAvailable(type);
|
||||
}
|
||||
|
||||
void NotationActionController::moveSelection(MoveSelectionType type, MoveDirection direction)
|
||||
{
|
||||
auto interaction = currentNotationInteraction();
|
||||
if (!interaction) {
|
||||
return;
|
||||
}
|
||||
|
||||
interaction->moveSelection(direction, type);
|
||||
}
|
||||
|
||||
void NotationActionController::move(MoveDirection direction, bool quickly)
|
||||
{
|
||||
TRACEFUNC;
|
||||
|
@ -1712,7 +1727,7 @@ bool NotationActionController::isNotEditingElement() const
|
|||
void NotationActionController::registerAction(const mu::actions::ActionCode& code,
|
||||
std::function<void()> handler, bool (NotationActionController::* isEnabled)() const)
|
||||
{
|
||||
m_isEnabledMap[code] = isEnabled;
|
||||
m_isEnabledMap[code] = std::bind(isEnabled, this);
|
||||
dispatcher()->reg(this, code, handler);
|
||||
}
|
||||
|
||||
|
@ -1720,7 +1735,7 @@ void NotationActionController::registerAction(const mu::actions::ActionCode& cod
|
|||
std::function<void(const actions::ActionData&)> handler,
|
||||
bool (NotationActionController::* isEnabled)() const)
|
||||
{
|
||||
m_isEnabledMap[code] = isEnabled;
|
||||
m_isEnabledMap[code] = std::bind(isEnabled, this);
|
||||
dispatcher()->reg(this, code, handler);
|
||||
}
|
||||
|
||||
|
@ -1728,7 +1743,7 @@ void NotationActionController::registerAction(const mu::actions::ActionCode& cod
|
|||
void (NotationActionController::* handler)(const actions::ActionData& data),
|
||||
bool (NotationActionController::* isEnabled)() const)
|
||||
{
|
||||
m_isEnabledMap[code] = isEnabled;
|
||||
m_isEnabledMap[code] = std::bind(isEnabled, this);
|
||||
dispatcher()->reg(this, code, this, handler);
|
||||
}
|
||||
|
||||
|
@ -1736,7 +1751,7 @@ void NotationActionController::registerAction(const mu::actions::ActionCode& cod
|
|||
void (NotationActionController::* handler)(),
|
||||
bool (NotationActionController::* isEnabled)() const)
|
||||
{
|
||||
m_isEnabledMap[code] = isEnabled;
|
||||
m_isEnabledMap[code] = std::bind(isEnabled, this);
|
||||
dispatcher()->reg(this, code, this, handler);
|
||||
}
|
||||
|
||||
|
@ -1760,6 +1775,25 @@ void NotationActionController::registerTabPadNoteAction(const mu::actions::Actio
|
|||
registerAction(code, [this, padding]() { padNote(padding); }, &NotationActionController::isTablatureStaff);
|
||||
}
|
||||
|
||||
void NotationActionController::registerMoveSelectionAction(const mu::actions::ActionCode& code, MoveSelectionType type,
|
||||
MoveDirection direction, PlayMode playMode)
|
||||
{
|
||||
auto moveSelectionFunc = [this, type, direction, playMode]() {
|
||||
moveSelection(type, direction);
|
||||
|
||||
if (playMode != PlayMode::NoPlay) {
|
||||
playSelectedElement(playMode == PlayMode::PlayChord);
|
||||
}
|
||||
};
|
||||
|
||||
auto moveSelectionAvailableFunc = [this, type]() {
|
||||
return moveSelectionAvailable(type);
|
||||
};
|
||||
|
||||
m_isEnabledMap[code] = moveSelectionAvailableFunc;
|
||||
dispatcher()->reg(this, code, moveSelectionFunc);
|
||||
}
|
||||
|
||||
void NotationActionController::registerAction(const mu::actions::ActionCode& code,
|
||||
void (INotationInteraction::* handler)(), PlayMode playMode,
|
||||
bool (NotationActionController::* enabler)() const)
|
||||
|
|
|
@ -83,6 +83,8 @@ private:
|
|||
void putTuplet(const TupletOptions& options);
|
||||
void putTuplet(int tupletCount);
|
||||
|
||||
bool moveSelectionAvailable(MoveSelectionType type) const;
|
||||
void moveSelection(MoveSelectionType type, MoveDirection direction);
|
||||
void move(MoveDirection direction, bool quickly = false);
|
||||
void moveWithinChord(MoveDirection direction);
|
||||
void selectTopOrBottomOfChord(MoveDirection direction);
|
||||
|
@ -195,6 +197,7 @@ private:
|
|||
bool (NotationActionController::*)() const = &NotationActionController::isNotEditingElement);
|
||||
void registerAction(const mu::actions::ActionCode&, void (NotationActionController::*)(MoveDirection, bool), MoveDirection, bool,
|
||||
bool (NotationActionController::*)() const = &NotationActionController::isNotEditingElement);
|
||||
|
||||
void registerNoteInputAction(const mu::actions::ActionCode&, NoteInputMethod inputMethod);
|
||||
void registerNoteAction(const mu::actions::ActionCode&, NoteName, NoteAddingMode addingMode = NoteAddingMode::NextChord);
|
||||
|
||||
|
@ -205,6 +208,9 @@ private:
|
|||
NoPlay, PlayNote, PlayChord
|
||||
};
|
||||
|
||||
void registerMoveSelectionAction(const mu::actions::ActionCode& code, MoveSelectionType type, MoveDirection direction,
|
||||
PlayMode playMode = PlayMode::NoPlay);
|
||||
|
||||
void registerAction(const mu::actions::ActionCode&, void (INotationInteraction::*)(), bool (NotationActionController::*)() const);
|
||||
void registerAction(const mu::actions::ActionCode&, void (INotationInteraction::*)(), PlayMode = PlayMode::NoPlay,
|
||||
bool (NotationActionController::*)() const = &NotationActionController::isNotEditingElement);
|
||||
|
@ -218,7 +224,9 @@ private:
|
|||
bool (NotationActionController::*)() const = &NotationActionController::isNotEditingElement);
|
||||
|
||||
async::Notification m_currentNotationNoteInputChanged;
|
||||
std::map<mu::actions::ActionCode, bool (NotationActionController::*)() const> m_isEnabledMap;
|
||||
|
||||
using IsActionEnabledFunc = std::function<bool ()>;
|
||||
std::map<mu::actions::ActionCode, IsActionEnabledFunc> m_isEnabledMap;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -89,10 +89,47 @@ static int findBracketIndex(Ms::EngravingItem* element)
|
|||
if (!element->isBracket()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
Ms::Bracket* bracket = toBracket(element);
|
||||
return bracket->system()->brackets().indexOf(bracket);
|
||||
}
|
||||
|
||||
static qreal nudgeDistance(const Ms::EditData& editData)
|
||||
{
|
||||
qreal spatium = editData.element->spatium();
|
||||
|
||||
if (editData.element->isBeam()) {
|
||||
if (editData.modifiers & Qt::ControlModifier) {
|
||||
return spatium;
|
||||
} else if (editData.modifiers & Qt::AltModifier) {
|
||||
return spatium * 4;
|
||||
}
|
||||
|
||||
return spatium * 0.25;
|
||||
}
|
||||
|
||||
if (editData.modifiers & Qt::ControlModifier) {
|
||||
return spatium * Ms::MScore::nudgeStep10;
|
||||
} else if (editData.modifiers & Qt::AltModifier) {
|
||||
return spatium * Ms::MScore::nudgeStep50;
|
||||
}
|
||||
|
||||
return spatium * Ms::MScore::nudgeStep;
|
||||
}
|
||||
|
||||
static qreal nudgeDistance(const Ms::EditData& editData, qreal raster)
|
||||
{
|
||||
qreal distance = nudgeDistance(editData);
|
||||
if (raster > 0) {
|
||||
raster = editData.element->spatium() / raster;
|
||||
if (distance < raster) {
|
||||
distance = raster;
|
||||
}
|
||||
}
|
||||
|
||||
return distance;
|
||||
}
|
||||
|
||||
NotationInteraction::NotationInteraction(Notation* notation, INotationUndoStackPtr undoStack)
|
||||
: m_notation(notation), m_undoStack(undoStack), m_editData(&m_scoreCallbacks)
|
||||
{
|
||||
|
@ -105,6 +142,14 @@ NotationInteraction::NotationInteraction(Notation* notation, INotationUndoStackP
|
|||
}
|
||||
});
|
||||
|
||||
m_undoStack->undoNotification().onNotify(this, [this]() {
|
||||
endEditElement();
|
||||
});
|
||||
|
||||
m_undoStack->redoNotification().onNotify(this, [this]() {
|
||||
endEditElement();
|
||||
});
|
||||
|
||||
m_dragData.ed = Ms::EditData(&m_scoreCallbacks);
|
||||
m_dropData.ed = Ms::EditData(&m_scoreCallbacks);
|
||||
|
||||
|
@ -180,7 +225,6 @@ void NotationInteraction::notifyAboutTextEditingChanged()
|
|||
|
||||
void NotationInteraction::notifyAboutSelectionChanged()
|
||||
{
|
||||
updateGripEdit();
|
||||
m_selectionChanged.notify();
|
||||
}
|
||||
|
||||
|
@ -192,6 +236,7 @@ void NotationInteraction::paint(mu::draw::Painter* painter)
|
|||
drawTextEditMode(painter);
|
||||
drawSelectionRange(painter);
|
||||
drawGripPoints(painter);
|
||||
|
||||
if (m_lasso && !m_lasso->isEmpty()) {
|
||||
m_lasso->draw(painter);
|
||||
}
|
||||
|
@ -1671,11 +1716,13 @@ void NotationInteraction::doAddSlur(ChordRest* firstChordRest, ChordRest* second
|
|||
if (!slur || slur->slurDirection() != Ms::DirectionV::AUTO) {
|
||||
slur = score()->addSlur(firstChordRest, secondChordRest, slurTemplate);
|
||||
}
|
||||
|
||||
if (m_noteInput->isNoteInputMode()) {
|
||||
m_noteInput->addSlur(slur);
|
||||
} else if (!secondChordRest) {
|
||||
select({ slur->frontSegment() }, SelectType::SINGLE);
|
||||
updateGripEdit();
|
||||
Ms::SlurSegment* segment = slur->frontSegment();
|
||||
select({ segment }, SelectType::SINGLE);
|
||||
startEditGrip(segment, Ms::Grip::END);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1944,22 +1991,13 @@ void NotationInteraction::drawSelectionRange(draw::Painter* painter)
|
|||
|
||||
void NotationInteraction::drawGripPoints(draw::Painter* painter)
|
||||
{
|
||||
Ms::EngravingItem* selectedElement = selection()->element();
|
||||
int gripsCount = selectedElement ? selectedElement->gripsCount() : 0;
|
||||
Ms::EngravingItem* editedElement = m_editData.element;
|
||||
int gripsCount = editedElement ? editedElement->gripsCount() : 0;
|
||||
|
||||
if (gripsCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool editingElement = m_editData.element != nullptr;
|
||||
if (!editingElement) {
|
||||
m_editData.element = selectedElement;
|
||||
|
||||
if (!m_editData.element->isTextBase() && !m_editData.getData(m_editData.element)) {
|
||||
m_editData.element->startEdit(m_editData);
|
||||
}
|
||||
}
|
||||
|
||||
m_editData.grips = gripsCount;
|
||||
m_editData.grip.resize(m_editData.grips);
|
||||
|
||||
|
@ -1968,19 +2006,15 @@ void NotationInteraction::drawGripPoints(draw::Painter* painter)
|
|||
qreal gripSize = DEFAULT_GRIP_SIZE / scaling;
|
||||
RectF newRect(-gripSize / 2, -gripSize / 2, gripSize, gripSize);
|
||||
|
||||
const EngravingItem* page = m_editData.element->findAncestor(ElementType::PAGE);
|
||||
PointF pageOffset = page ? page->pos() : m_editData.element->pos();
|
||||
const EngravingItem* page = editedElement->findAncestor(ElementType::PAGE);
|
||||
PointF pageOffset = page ? page->pos() : editedElement->pos();
|
||||
|
||||
for (RectF& gripRect: m_editData.grip) {
|
||||
gripRect = newRect.translated(pageOffset);
|
||||
}
|
||||
|
||||
m_editData.element->updateGrips(m_editData);
|
||||
m_editData.element->drawEditMode(painter, m_editData, scaling);
|
||||
|
||||
if (!editingElement) {
|
||||
m_editData.element = nullptr;
|
||||
}
|
||||
editedElement->updateGrips(m_editData);
|
||||
editedElement->drawEditMode(painter, m_editData, scaling);
|
||||
}
|
||||
|
||||
ChordRest* activeCr(Ms::Score* score)
|
||||
|
@ -2079,6 +2113,19 @@ void NotationInteraction::addToSelection(MoveDirection d, MoveSelectionType type
|
|||
}
|
||||
}
|
||||
|
||||
bool NotationInteraction::moveSelectionAvailable(MoveSelectionType type) const
|
||||
{
|
||||
if (type != MoveSelectionType::EngravingItem) {
|
||||
return !isElementEditStarted();
|
||||
}
|
||||
|
||||
if (isGripEditStarted()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !isElementEditStarted();
|
||||
}
|
||||
|
||||
void NotationInteraction::moveSelection(MoveDirection d, MoveSelectionType type)
|
||||
{
|
||||
IF_ASSERT_FAILED(MoveSelectionType::Undefined != type) {
|
||||
|
@ -2242,11 +2289,13 @@ void NotationInteraction::moveElementSelection(MoveDirection d)
|
|||
el = score()->selection().elements().last();
|
||||
}
|
||||
|
||||
bool isLeftDirection = MoveDirection::Left == d;
|
||||
|
||||
if (!el) {
|
||||
ChordRest* cr = score()->selection().currentCR();
|
||||
if (cr) {
|
||||
if (cr->isChord()) {
|
||||
if (MoveDirection::Left == d) {
|
||||
if (isLeftDirection) {
|
||||
el = toChord(cr)->upNote();
|
||||
} else {
|
||||
el = toChord(cr)->downNote();
|
||||
|
@ -2259,21 +2308,30 @@ void NotationInteraction::moveElementSelection(MoveDirection d)
|
|||
}
|
||||
|
||||
EngravingItem* toEl = nullptr;
|
||||
|
||||
if (el) {
|
||||
toEl = (MoveDirection::Left == d) ? score()->prevElement() : score()->nextElement();
|
||||
toEl = isLeftDirection ? score()->prevElement() : score()->nextElement();
|
||||
} else {
|
||||
toEl = (MoveDirection::Left == d) ? score()->lastElement() : score()->firstElement();
|
||||
toEl = isLeftDirection ? score()->lastElement() : score()->firstElement();
|
||||
}
|
||||
|
||||
if (!toEl) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isElementEditStarted()) {
|
||||
endEditElement();
|
||||
}
|
||||
|
||||
select({ toEl }, SelectType::SINGLE);
|
||||
|
||||
if (toEl->type() == ElementType::NOTE || toEl->type() == ElementType::HARMONY) {
|
||||
score()->setPlayNote(true);
|
||||
}
|
||||
|
||||
if (toEl->hasGrips()) {
|
||||
startEditGrip(toEl, toEl->defaultGrip());
|
||||
}
|
||||
}
|
||||
|
||||
void NotationInteraction::moveStringSelection(MoveDirection d)
|
||||
|
@ -2463,61 +2521,35 @@ void NotationInteraction::editText(QInputMethodEvent* event)
|
|||
notifyAboutTextEditingChanged();
|
||||
}
|
||||
|
||||
static qreal nudgeDistance(const Ms::EditData& editData)
|
||||
{
|
||||
qreal spatium = editData.element->spatium();
|
||||
if (editData.element->isBeam()) {
|
||||
if (editData.modifiers & Qt::ControlModifier) {
|
||||
return spatium;
|
||||
} else if (editData.modifiers & Qt::AltModifier) {
|
||||
return spatium * 4;
|
||||
} else {
|
||||
return spatium * 0.25;
|
||||
}
|
||||
} else {
|
||||
if (editData.modifiers & Qt::ControlModifier) {
|
||||
return spatium * Ms::MScore::nudgeStep10;
|
||||
} else if (editData.modifiers & Qt::AltModifier) {
|
||||
return spatium * Ms::MScore::nudgeStep50;
|
||||
} else {
|
||||
return spatium * Ms::MScore::nudgeStep;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static qreal nudgeDistance(const Ms::EditData& editData, qreal raster)
|
||||
{
|
||||
qreal distance = nudgeDistance(editData);
|
||||
if (raster > 0) {
|
||||
raster = editData.element->spatium() / raster;
|
||||
if (distance < raster) {
|
||||
distance = raster;
|
||||
}
|
||||
}
|
||||
return distance;
|
||||
}
|
||||
|
||||
bool NotationInteraction::handleKeyPress(QKeyEvent* event)
|
||||
{
|
||||
if (event->modifiers() == Qt::KeyboardModifier::AltModifier && !isElementEditStarted()) {
|
||||
if (event->modifiers() & Qt::KeyboardModifier::AltModifier) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_editData.element->isTextBase()) {
|
||||
return false;
|
||||
}
|
||||
qreal vRaster = Ms::MScore::vRaster(), hRaster = Ms::MScore::hRaster();
|
||||
|
||||
qreal vRaster = Ms::MScore::vRaster();
|
||||
qreal hRaster = Ms::MScore::hRaster();
|
||||
|
||||
switch (event->key()) {
|
||||
case Qt::Key_Tab:
|
||||
if (!m_editData.element->nextGrip(m_editData)) {
|
||||
if (!m_editData.element->hasGrips()) {
|
||||
return false;
|
||||
}
|
||||
updateAnchorLines();
|
||||
|
||||
m_editData.element->nextGrip(m_editData);
|
||||
|
||||
return true;
|
||||
case Qt::Key_Backtab:
|
||||
if (!m_editData.element->prevGrip(m_editData)) {
|
||||
if (!m_editData.element->hasGrips()) {
|
||||
return false;
|
||||
}
|
||||
updateAnchorLines();
|
||||
|
||||
m_editData.element->prevGrip(m_editData);
|
||||
|
||||
return true;
|
||||
case Qt::Key_Left:
|
||||
m_editData.delta = QPointF(-nudgeDistance(m_editData, hRaster), 0);
|
||||
|
@ -2534,18 +2566,24 @@ bool NotationInteraction::handleKeyPress(QKeyEvent* event)
|
|||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
m_editData.evtDelta = m_editData.moveDelta = m_editData.delta;
|
||||
m_editData.hRaster = hRaster;
|
||||
m_editData.vRaster = vRaster;
|
||||
|
||||
if (m_editData.curGrip == Ms::Grip::NO_GRIP) {
|
||||
m_editData.curGrip = m_editData.element->defaultGrip();
|
||||
}
|
||||
|
||||
if (m_editData.curGrip != Ms::Grip::NO_GRIP && int(m_editData.curGrip) < m_editData.grips) {
|
||||
m_editData.pos = m_editData.grip[int(m_editData.curGrip)].center() + m_editData.delta;
|
||||
}
|
||||
|
||||
m_scoreCallbacks.setScore(score());
|
||||
m_editData.element->startEditDrag(m_editData);
|
||||
m_editData.element->editDrag(m_editData);
|
||||
m_editData.element->endEditDrag(m_editData);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2731,43 +2769,50 @@ void NotationInteraction::changeEditElement(EngravingItem* newElement)
|
|||
|
||||
void NotationInteraction::editElement(QKeyEvent* event)
|
||||
{
|
||||
m_editData.modifiers = event->modifiers();
|
||||
if (isDragStarted()) {
|
||||
return; // ignore all key strokes while dragging
|
||||
}
|
||||
bool wasEditing = m_editData.element != nullptr;
|
||||
if (!wasEditing && selection()->element()) {
|
||||
m_editData.element = selection()->element();
|
||||
}
|
||||
|
||||
if (!m_editData.element) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_editData.modifiers = event->modifiers();
|
||||
|
||||
if (isDragStarted()) {
|
||||
return; // ignore all key strokes while dragging
|
||||
}
|
||||
|
||||
m_editData.key = event->key();
|
||||
m_editData.s = event->text();
|
||||
|
||||
startEdit();
|
||||
|
||||
int systemIndex = findSystemIndex(m_editData.element);
|
||||
int bracketIndex = findBracketIndex(m_editData.element);
|
||||
bool handled = m_editData.element->edit(m_editData) || (wasEditing && handleKeyPress(event));
|
||||
if (!wasEditing) {
|
||||
m_editData.element = nullptr;
|
||||
|
||||
bool handled = m_editData.element->edit(m_editData);
|
||||
if (!handled) {
|
||||
handled = handleKeyPress(event);
|
||||
}
|
||||
|
||||
if (handled) {
|
||||
event->accept();
|
||||
apply();
|
||||
|
||||
if (isGripEditStarted()) {
|
||||
updateAnchorLines();
|
||||
}
|
||||
} else {
|
||||
m_undoStack->rollbackChanges();
|
||||
rollback();
|
||||
}
|
||||
|
||||
if (isTextEditingStarted()) {
|
||||
notifyAboutTextEditingChanged();
|
||||
} else {
|
||||
if (bracketIndex >= 0 && systemIndex < score()->systems().size()) {
|
||||
Ms::System* sys = score()->systems()[systemIndex];
|
||||
Ms::EngravingItem* bracket = sys->brackets()[bracketIndex];
|
||||
score()->select(bracket);
|
||||
notifyAboutSelectionChanged();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (bracketIndex >= 0 && systemIndex < score()->systems().size()) {
|
||||
const Ms::System* system = score()->systems()[systemIndex];
|
||||
Ms::EngravingItem* bracket = system->brackets()[bracketIndex];
|
||||
score()->select(bracket);
|
||||
notifyAboutSelectionChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3076,19 +3121,21 @@ void NotationInteraction::deleteSelection()
|
|||
}
|
||||
|
||||
startEdit();
|
||||
|
||||
if (isTextEditingStarted()) {
|
||||
auto textBase = toTextBase(m_editData.element);
|
||||
Ms::TextBase* textBase = toTextBase(m_editData.element);
|
||||
if (!textBase->deleteSelectedText(m_editData)) {
|
||||
m_editData.key = Qt::Key_Backspace;
|
||||
m_editData.modifiers = {};
|
||||
textBase->edit(m_editData);
|
||||
}
|
||||
} else {
|
||||
doEndEditElement();
|
||||
resetGripEdit();
|
||||
score()->cmdDeleteSelection();
|
||||
}
|
||||
apply();
|
||||
|
||||
resetGripEdit();
|
||||
apply();
|
||||
|
||||
notifyAboutSelectionChanged();
|
||||
notifyAboutNotationChanged();
|
||||
|
@ -3151,17 +3198,21 @@ void NotationInteraction::addOttavaToSelection(OttavaType type)
|
|||
notifyAboutSelectionChanged();
|
||||
}
|
||||
|
||||
void NotationInteraction::addHairpinToSelection(HairpinType type)
|
||||
void NotationInteraction::addHairpinsToSelection(HairpinType type)
|
||||
{
|
||||
if (selection()->isNone()) {
|
||||
return;
|
||||
}
|
||||
|
||||
startEdit();
|
||||
score()->addHairpin(type);
|
||||
std::vector<Ms::Hairpin*> hairpins = score()->addHairpins(type);
|
||||
apply();
|
||||
|
||||
notifyAboutSelectionChanged();
|
||||
if (hairpins.size() == 1) {
|
||||
Ms::LineSegment* segment = hairpins.front()->frontSegment();
|
||||
select({ segment });
|
||||
startEditGrip(segment, Ms::Grip::END);
|
||||
}
|
||||
}
|
||||
|
||||
void NotationInteraction::addAccidentalToSelection(AccidentalType type)
|
||||
|
@ -3895,32 +3946,6 @@ bool NotationInteraction::needEndTextEditing(const std::vector<EngravingItem*>&
|
|||
return newSelectedElements.front() != m_editData.element;
|
||||
}
|
||||
|
||||
void NotationInteraction::updateGripEdit()
|
||||
{
|
||||
const auto& elements = score()->selection().elements();
|
||||
|
||||
if (elements.isEmpty() || elements.size() > 1) {
|
||||
resetGripEdit();
|
||||
return;
|
||||
}
|
||||
|
||||
EngravingItem* element = elements.front();
|
||||
if (!element->hasGrips()) {
|
||||
resetGripEdit();
|
||||
return;
|
||||
}
|
||||
|
||||
m_editData.grips = element->gripsCount();
|
||||
m_editData.curGrip = Ms::Grip::NO_GRIP;
|
||||
bool editingElement = m_editData.element != nullptr;
|
||||
m_editData.element = element;
|
||||
element->startEdit(m_editData);
|
||||
updateAnchorLines();
|
||||
if (!editingElement) {
|
||||
m_editData.element = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void NotationInteraction::resetGripEdit()
|
||||
{
|
||||
m_editData.grips = 0;
|
||||
|
|
|
@ -110,6 +110,7 @@ public:
|
|||
void redo() override;
|
||||
|
||||
// Change selection
|
||||
bool moveSelectionAvailable(MoveSelectionType type) const override;
|
||||
void moveSelection(MoveDirection d, MoveSelectionType type) override;
|
||||
void expandSelection(ExpandSelectionMode mode) override;
|
||||
void addToSelection(MoveDirection d, MoveSelectionType type) override;
|
||||
|
@ -165,7 +166,7 @@ public:
|
|||
void addTiedNoteToChord() override;
|
||||
void addSlurToSelection() override;
|
||||
void addOttavaToSelection(OttavaType type) override;
|
||||
void addHairpinToSelection(HairpinType type) override;
|
||||
void addHairpinsToSelection(HairpinType type) override;
|
||||
void addAccidentalToSelection(AccidentalType type) override;
|
||||
void putRestToSelection() override;
|
||||
void putRest(DurationType duration) override;
|
||||
|
@ -328,7 +329,6 @@ private:
|
|||
|
||||
bool needEndTextEditing(const std::vector<EngravingItem*>& newSelectedElements) const;
|
||||
|
||||
void updateGripEdit();
|
||||
void resetGripEdit();
|
||||
|
||||
bool elementsSelected(const std::vector<ElementType>& elementsTypes) const;
|
||||
|
|
|
@ -877,12 +877,26 @@ void NotationPaintView::shortcutOverride(QKeyEvent* event)
|
|||
|
||||
bool NotationPaintView::event(QEvent* event)
|
||||
{
|
||||
if (event->type() == QEvent::Type::ShortcutOverride) {
|
||||
shortcutOverride(dynamic_cast<QKeyEvent*>(event));
|
||||
}
|
||||
QEvent::Type eventType = event->type();
|
||||
|
||||
if (hasFocus() && event->type() == QEvent::Type::ContextMenu) {
|
||||
if (eventType == QEvent::Type::ShortcutOverride) {
|
||||
auto keyEvent = dynamic_cast<QKeyEvent*>(event);
|
||||
shortcutOverride(keyEvent);
|
||||
|
||||
if (keyEvent->isAccepted()) {
|
||||
m_lastAcceptedKey = keyEvent->key();
|
||||
}
|
||||
} else if (eventType == QEvent::Type::KeyPress) {
|
||||
auto keyEvent = dynamic_cast<const QKeyEvent*>(event);
|
||||
|
||||
if (keyEvent->key() == m_lastAcceptedKey) {
|
||||
m_lastAcceptedKey = -1;
|
||||
// required to prevent Qt-Quick from changing focus on tab
|
||||
return true;
|
||||
}
|
||||
} else if (eventType == QEvent::Type::ContextMenu && hasFocus()) {
|
||||
QPointF contextMenuPosition;
|
||||
|
||||
if (m_inputController->selectionType() == ElementType::PAGE) {
|
||||
contextMenuPosition = QPointF(width() / 2, height() / 2);
|
||||
} else {
|
||||
|
|
|
@ -222,7 +222,9 @@ private:
|
|||
|
||||
qreal m_previousVerticalScrollPosition = 0;
|
||||
qreal m_previousHorizontalScrollPosition = 0;
|
||||
|
||||
bool m_publishMode = false;
|
||||
int m_lastAcceptedKey = -1;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue