Add a way to handle dragging elements collectively
Also draw anchor lines for multiple selected elements on dragging
This commit is contained in:
parent
ad6c8581d7
commit
55230ca86d
12 changed files with 439 additions and 25 deletions
|
@ -62,8 +62,8 @@ add_library (
|
|||
fermata.cpp articulation.cpp barline.cpp beam.cpp bend.cpp box.cpp
|
||||
bracket.cpp breath.cpp bsp.cpp changeMap.cpp chord.cpp chordline.cpp
|
||||
chordlist.cpp chordrest.cpp clef.cpp cleflist.cpp
|
||||
drumset.cpp durationtype.cpp dynamic.cpp edit.cpp noteentry.cpp
|
||||
element.cpp excerpt.cpp
|
||||
drumset.cpp durationtype.cpp dynamic.cpp dynamichairpingroup.cpp edit.cpp noteentry.cpp
|
||||
element.cpp elementgroup.cpp excerpt.cpp
|
||||
fifo.cpp fret.cpp glissando.cpp hairpin.cpp
|
||||
harmony.cpp hook.cpp image.cpp iname.cpp instrchange.cpp
|
||||
instrtemplate.cpp instrument.cpp interval.cpp
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
//=============================================================================
|
||||
|
||||
#include "dynamic.h"
|
||||
#include "dynamichairpingroup.h"
|
||||
#include "xml.h"
|
||||
#include "score.h"
|
||||
#include "measure.h"
|
||||
|
@ -344,6 +345,19 @@ void Dynamic::reset()
|
|||
TextBase::reset();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// getDragGroup
|
||||
//---------------------------------------------------------
|
||||
|
||||
std::unique_ptr<ElementGroup> Dynamic::getDragGroup(std::function<bool(const Element*)> isDragged)
|
||||
{
|
||||
if (auto g = HairpinWithDynamicsDragGroup::detectFor(this, isDragged))
|
||||
return g;
|
||||
if (auto g = DynamicNearHairpinsDragGroup::detectFor(this, isDragged))
|
||||
return g;
|
||||
return TextBase::getDragGroup(isDragged);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// drag
|
||||
//---------------------------------------------------------
|
||||
|
|
|
@ -137,6 +137,8 @@ class Dynamic final : public TextBase {
|
|||
Pid propertyId(const QStringRef& xmlName) const override;
|
||||
QString propertyUserValue(Pid) const override;
|
||||
|
||||
std::unique_ptr<ElementGroup> getDragGroup(std::function<bool(const Element*)> isDragged) override;
|
||||
|
||||
QString accessibleInfo() const override;
|
||||
QString screenReaderInfo() const override;
|
||||
void doAutoplace();
|
||||
|
|
190
libmscore/dynamichairpingroup.cpp
Normal file
190
libmscore/dynamichairpingroup.cpp
Normal file
|
@ -0,0 +1,190 @@
|
|||
//=============================================================================
|
||||
// MuseScore
|
||||
// Music Composition & Notation
|
||||
//
|
||||
// Copyright (C) 2020 MuseScore BVBA
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2
|
||||
// as published by the Free Software Foundation and appearing in
|
||||
// the file LICENCE.GPL
|
||||
//=============================================================================
|
||||
|
||||
#include "dynamichairpingroup.h"
|
||||
#include "dynamic.h"
|
||||
#include "hairpin.h"
|
||||
#include "score.h"
|
||||
#include "segment.h"
|
||||
|
||||
namespace Ms {
|
||||
|
||||
static std::pair<Hairpin*, Hairpin*> findAdjacentHairpins(Dynamic* d)
|
||||
{
|
||||
Score* score = d->score();
|
||||
const Segment* dSeg = d->segment();
|
||||
Hairpin* leftHairpin = nullptr;
|
||||
Hairpin* rightHairpin = nullptr;
|
||||
|
||||
const Fraction tick = dSeg->tick();
|
||||
const int intTick = tick.ticks();
|
||||
|
||||
const auto& nearSpanners = score->spannerMap().findOverlapping(intTick - 1, intTick + 1);
|
||||
for (auto i : nearSpanners) {
|
||||
Spanner* s = i.value;
|
||||
if (s->track() == d->track() && s->isHairpin()) {
|
||||
Hairpin* h = toHairpin(s);
|
||||
if (h->tick() == tick)
|
||||
rightHairpin = h;
|
||||
else if (h->tick2() == tick)
|
||||
leftHairpin = h;
|
||||
}
|
||||
}
|
||||
|
||||
return { leftHairpin, rightHairpin };
|
||||
}
|
||||
|
||||
std::unique_ptr<ElementGroup> HairpinWithDynamicsDragGroup::detectFor(HairpinSegment* hs, std::function<bool(const Element*)> isDragged)
|
||||
{
|
||||
if (!hs->isSingleType())
|
||||
return nullptr;
|
||||
|
||||
Hairpin* hairpin = hs->hairpin();
|
||||
|
||||
Segment* startSegment = hairpin->startSegment();
|
||||
Segment* endSegment = hairpin->endSegment();
|
||||
const int track = hs->track();
|
||||
|
||||
Dynamic* startDynamic = toDynamic(startSegment->findAnnotation(ElementType::DYNAMIC, track, track));
|
||||
Dynamic* endDynamic = toDynamic(endSegment->findAnnotation(ElementType::DYNAMIC, track, track));
|
||||
|
||||
// Include only dragged dynamics to this group
|
||||
if (!isDragged(startDynamic))
|
||||
startDynamic = nullptr;
|
||||
if (!isDragged(endDynamic))
|
||||
endDynamic = nullptr;
|
||||
|
||||
if (startDynamic || endDynamic)
|
||||
return std::unique_ptr<ElementGroup>(new HairpinWithDynamicsDragGroup(startDynamic, hs, endDynamic));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<ElementGroup> HairpinWithDynamicsDragGroup::detectFor(Dynamic* d, std::function<bool(const Element*)> isDragged)
|
||||
{
|
||||
Hairpin* leftHairpin = nullptr;
|
||||
Hairpin* rightHairpin = nullptr;
|
||||
|
||||
std::tie(leftHairpin, rightHairpin) = findAdjacentHairpins(d);
|
||||
|
||||
// Dynamic will be governed bt HairpinWithDynamicsDragGroup if any of adjacent
|
||||
// hairpins is dragged, disable separate drag logic for dynamic in this case.
|
||||
if (isDragged(leftHairpin))
|
||||
return std::unique_ptr<ElementGroup>(new DisabledElementGroup());
|
||||
if (isDragged(rightHairpin))
|
||||
return std::unique_ptr<ElementGroup>(new DisabledElementGroup());
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void HairpinWithDynamicsDragGroup::startDrag(EditData& ed)
|
||||
{
|
||||
if (startDynamic)
|
||||
startDynamic->startDrag(ed);
|
||||
static_cast<Element*>(hairpinSegment)->startDrag(ed);
|
||||
if (endDynamic)
|
||||
endDynamic->startDrag(ed);
|
||||
}
|
||||
|
||||
QRectF HairpinWithDynamicsDragGroup::drag(EditData& ed)
|
||||
{
|
||||
QRectF r;
|
||||
|
||||
if (startDynamic)
|
||||
r |= static_cast<Element*>(startDynamic)->drag(ed);
|
||||
r |= hairpinSegment->drag(ed);
|
||||
if (endDynamic)
|
||||
r |= static_cast<Element*>(endDynamic)->drag(ed);
|
||||
|
||||
Hairpin* h = hairpinSegment->hairpin();
|
||||
|
||||
const Fraction startTick = startDynamic ? startDynamic->segment()->tick() : h->tick();
|
||||
const Fraction endTick = endDynamic ? endDynamic->segment()->tick() : h->tick2();
|
||||
|
||||
if (endTick > startTick) {
|
||||
if (h->tick() != startTick)
|
||||
h->undoChangeProperty(Pid::SPANNER_TICK, startTick);
|
||||
if (h->tick2() != endTick)
|
||||
h->undoChangeProperty(Pid::SPANNER_TICKS, endTick - startTick);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void HairpinWithDynamicsDragGroup::endDrag(EditData& ed)
|
||||
{
|
||||
if (startDynamic) {
|
||||
startDynamic->endDrag(ed);
|
||||
startDynamic->triggerLayout();
|
||||
}
|
||||
|
||||
hairpinSegment->endDrag(ed);
|
||||
hairpinSegment->triggerLayout();
|
||||
|
||||
if (endDynamic) {
|
||||
endDynamic->endDrag(ed);
|
||||
endDynamic->triggerLayout();
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<ElementGroup> DynamicNearHairpinsDragGroup::detectFor(Dynamic* d, std::function<bool(const Element*)> isDragged)
|
||||
{
|
||||
Hairpin* leftHairpin = nullptr;
|
||||
Hairpin* rightHairpin = nullptr;
|
||||
|
||||
std::tie(leftHairpin, rightHairpin) = findAdjacentHairpins(d);
|
||||
|
||||
// Drag hairpins according to this rule only if they are not being dragged themselves
|
||||
if (isDragged(leftHairpin))
|
||||
leftHairpin = nullptr;
|
||||
if (isDragged(rightHairpin))
|
||||
rightHairpin = nullptr;
|
||||
|
||||
if (leftHairpin || rightHairpin)
|
||||
return std::unique_ptr<ElementGroup>(new DynamicNearHairpinsDragGroup(leftHairpin, d, rightHairpin));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void DynamicNearHairpinsDragGroup::startDrag(EditData& ed)
|
||||
{
|
||||
dynamic->startDrag(ed);
|
||||
}
|
||||
|
||||
QRectF DynamicNearHairpinsDragGroup::drag(EditData& ed)
|
||||
{
|
||||
QRectF r(static_cast<Element*>(dynamic)->drag(ed));
|
||||
|
||||
const Fraction tick = dynamic->segment()->tick();
|
||||
|
||||
if (leftHairpin && leftHairpin->tick2() != tick && tick > leftHairpin->tick())
|
||||
leftHairpin->undoChangeProperty(Pid::SPANNER_TICKS, tick - leftHairpin->tick());
|
||||
|
||||
if (rightHairpin && rightHairpin->tick() != tick) {
|
||||
const Fraction tick2 = rightHairpin->tick2();
|
||||
if (tick < tick2) {
|
||||
rightHairpin->undoChangeProperty(Pid::SPANNER_TICK, tick);
|
||||
rightHairpin->undoChangeProperty(Pid::SPANNER_TICKS, tick2 - tick);
|
||||
}
|
||||
}
|
||||
|
||||
if (leftHairpin || rightHairpin)
|
||||
dynamic->triggerLayout();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void DynamicNearHairpinsDragGroup::endDrag(EditData& ed)
|
||||
{
|
||||
dynamic->endDrag(ed);
|
||||
dynamic->triggerLayout();
|
||||
}
|
||||
|
||||
} // namespace Ms
|
68
libmscore/dynamichairpingroup.h
Normal file
68
libmscore/dynamichairpingroup.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
//=============================================================================
|
||||
// MuseScore
|
||||
// Music Composition & Notation
|
||||
//
|
||||
// Copyright (C) 2020 MuseScore BVBA
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2
|
||||
// as published by the Free Software Foundation and appearing in
|
||||
// the file LICENCE.GPL
|
||||
//=============================================================================
|
||||
|
||||
#ifndef __DYNAMICHAIPRINGROUP_H__
|
||||
#define __DYNAMICHAIRPINGROUP_H__
|
||||
|
||||
#include "elementgroup.h"
|
||||
|
||||
namespace Ms {
|
||||
|
||||
class Dynamic;
|
||||
class Hairpin;
|
||||
class HairpinSegment;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// HairpinWithDynamicsDragGroup
|
||||
/// Sequence of Dynamics and Hairpins
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
class HairpinWithDynamicsDragGroup : public ElementGroup {
|
||||
Dynamic* startDynamic;
|
||||
HairpinSegment* hairpinSegment;
|
||||
Dynamic* endDynamic;
|
||||
|
||||
public:
|
||||
HairpinWithDynamicsDragGroup(Dynamic* start, HairpinSegment* hs, Dynamic* end)
|
||||
: startDynamic(start), hairpinSegment(hs), endDynamic(end) {}
|
||||
|
||||
void startDrag(EditData&) override;
|
||||
QRectF drag(EditData&) override;
|
||||
void endDrag(EditData&) override;
|
||||
|
||||
static std::unique_ptr<ElementGroup> detectFor(HairpinSegment* hs, std::function<bool(const Element*)> isDragged);
|
||||
static std::unique_ptr<ElementGroup> detectFor(Dynamic* d, std::function<bool(const Element*)> isDragged);
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// DynamicNearHairpinsDragGroup
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
class DynamicNearHairpinsDragGroup : public ElementGroup {
|
||||
Hairpin* leftHairpin;
|
||||
Dynamic* dynamic;
|
||||
Hairpin* rightHairpin;
|
||||
|
||||
public:
|
||||
DynamicNearHairpinsDragGroup(Hairpin* left, Dynamic* d, Hairpin* right)
|
||||
: leftHairpin(left), dynamic(d), rightHairpin(right) {}
|
||||
|
||||
void startDrag(EditData&) override;
|
||||
QRectF drag(EditData&) override;
|
||||
void endDrag(EditData&) override;
|
||||
|
||||
static std::unique_ptr<ElementGroup> detectFor(Dynamic* d, std::function<bool(const Element*)> isDragged);
|
||||
};
|
||||
|
||||
} // namespace Ms
|
||||
|
||||
#endif
|
|
@ -13,6 +13,7 @@
|
|||
#ifndef __ELEMENT_H__
|
||||
#define __ELEMENT_H__
|
||||
|
||||
#include "elementgroup.h"
|
||||
#include "spatium.h"
|
||||
#include "fraction.h"
|
||||
#include "scoreElement.h"
|
||||
|
@ -296,6 +297,9 @@ class Element : public ScoreElement {
|
|||
virtual void write(XmlWriter&) const;
|
||||
virtual void read(XmlReader&);
|
||||
|
||||
// virtual ElementGroup getElementGroup() { return SingleElementGroup(this); }
|
||||
virtual std::unique_ptr<ElementGroup> getDragGroup(std::function<bool(const Element*)> isDragged) { Q_UNUSED(isDragged); return std::unique_ptr<ElementGroup>(new SingleElementGroup(this)); }
|
||||
|
||||
virtual void startDrag(EditData&);
|
||||
virtual QRectF drag(EditData&);
|
||||
virtual void endDrag(EditData&);
|
||||
|
|
34
libmscore/elementgroup.cpp
Normal file
34
libmscore/elementgroup.cpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
//=============================================================================
|
||||
// MuseScore
|
||||
// Music Composition & Notation
|
||||
//
|
||||
// Copyright (C) 2020 MuseScore BVBA
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2
|
||||
// as published by the Free Software Foundation and appearing in
|
||||
// the file LICENCE.GPL
|
||||
//=============================================================================
|
||||
|
||||
#include "elementgroup.h"
|
||||
#include "element.h"
|
||||
|
||||
namespace Ms {
|
||||
|
||||
void SingleElementGroup::startDrag(EditData& ed)
|
||||
{
|
||||
e->startDrag(ed);
|
||||
}
|
||||
|
||||
QRectF SingleElementGroup::drag(EditData& ed)
|
||||
{
|
||||
return e->drag(ed);
|
||||
}
|
||||
|
||||
void SingleElementGroup::endDrag(EditData& ed)
|
||||
{
|
||||
e->endDrag(ed);
|
||||
e->triggerLayout();
|
||||
}
|
||||
|
||||
} // namespace Ms
|
68
libmscore/elementgroup.h
Normal file
68
libmscore/elementgroup.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
//=============================================================================
|
||||
// MuseScore
|
||||
// Music Composition & Notation
|
||||
//
|
||||
// Copyright (C) 2020 MuseScore BVBA
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2
|
||||
// as published by the Free Software Foundation and appearing in
|
||||
// the file LICENCE.GPL
|
||||
//=============================================================================
|
||||
|
||||
#ifndef __ELEMENTGROUP_H__
|
||||
#define __ELEMENTGROUP_H__
|
||||
|
||||
namespace Ms {
|
||||
|
||||
class Element;
|
||||
class EditData;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// ElementGroup
|
||||
/// Base class for implementing logic to handle groups of elements
|
||||
/// together in certain operations.
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
class ElementGroup {
|
||||
public:
|
||||
virtual ~ElementGroup() {}
|
||||
|
||||
virtual void startDrag(EditData&) = 0;
|
||||
virtual QRectF drag(EditData&) = 0;
|
||||
virtual void endDrag(EditData&) = 0;
|
||||
|
||||
virtual bool enabled() const { return true; }
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// DisabledElementGroup
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
class DisabledElementGroup final : public ElementGroup {
|
||||
public:
|
||||
bool enabled() const override { return false; }
|
||||
|
||||
void startDrag(EditData&) override {}
|
||||
QRectF drag(EditData&) override { return QRectF(); }
|
||||
void endDrag(EditData&) override {}
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// SingleElementGroup
|
||||
/// Element group for single element.
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
class SingleElementGroup final : public ElementGroup {
|
||||
Element* e;
|
||||
public:
|
||||
SingleElementGroup(Element* el) : e(el) {}
|
||||
|
||||
void startDrag(EditData& ed) override;
|
||||
QRectF drag(EditData& ed) override;
|
||||
void endDrag(EditData& ed) override;
|
||||
};
|
||||
|
||||
} // namespace Ms
|
||||
|
||||
#endif
|
|
@ -11,6 +11,7 @@
|
|||
//=============================================================================
|
||||
|
||||
#include "hairpin.h"
|
||||
#include "dynamichairpingroup.h"
|
||||
#include "style.h"
|
||||
#include "xml.h"
|
||||
#include "utils.h"
|
||||
|
@ -400,6 +401,17 @@ std::vector<QPointF> HairpinSegment::gripsPositions(const EditData&) const
|
|||
return grips;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// getDragGroup
|
||||
//---------------------------------------------------------
|
||||
|
||||
std::unique_ptr<ElementGroup> HairpinSegment::getDragGroup(std::function<bool(const Element*)> isDragged)
|
||||
{
|
||||
if (auto g = HairpinWithDynamicsDragGroup::detectFor(this, isDragged))
|
||||
return g;
|
||||
return TextLineBaseSegment::getDragGroup(isDragged);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// startEditDrag
|
||||
//---------------------------------------------------------
|
||||
|
|
|
@ -67,6 +67,8 @@ class HairpinSegment final : public TextLineBaseSegment {
|
|||
|
||||
int gripsCount() const override { return 4; }
|
||||
std::vector<QPointF> gripsPositions(const EditData& = EditData()) const override;
|
||||
|
||||
std::unique_ptr<ElementGroup> getDragGroup(std::function<bool(const Element*)> isDragged) override;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------
|
||||
|
|
|
@ -33,10 +33,27 @@ void ScoreView::startDrag()
|
|||
editData.clearData();
|
||||
editData.normalizedStartMove = editData.startMove - editData.element->offset();
|
||||
|
||||
const Selection& sel = _score->selection();
|
||||
const bool filterType = sel.isRange();
|
||||
const ElementType type = editData.element->type();
|
||||
|
||||
const auto isDragged = [filterType, type](const Element* e) {
|
||||
return e && e->selected() && (!filterType || type == e->type());
|
||||
};
|
||||
|
||||
for (Element* e : sel.elements()) {
|
||||
if (!isDragged(e))
|
||||
continue;
|
||||
|
||||
std::unique_ptr<ElementGroup> g = e->getDragGroup(isDragged);
|
||||
if (g && g->enabled())
|
||||
dragGroups.push_back(std::move(g));
|
||||
}
|
||||
|
||||
_score->startCmd();
|
||||
|
||||
for (Element* e : _score->selection().elements())
|
||||
e->startDrag(editData);
|
||||
for (auto& g : dragGroups)
|
||||
g->startDrag(editData);
|
||||
|
||||
_score->selection().lock("drag");
|
||||
}
|
||||
|
@ -72,33 +89,35 @@ void ScoreView::doDragElement(QMouseEvent* ev)
|
|||
editData.pos = logicalPos;
|
||||
|
||||
const Selection& sel = _score->selection();
|
||||
const bool filterType = sel.isRange();
|
||||
const ElementType type = editData.element->type();
|
||||
|
||||
for (auto& g : dragGroups)
|
||||
_score->addRefresh(g->drag(editData));
|
||||
|
||||
_score->update();
|
||||
QVector<QLineF> anchorLines;
|
||||
|
||||
for (Element* e : sel.elements()) {
|
||||
if (filterType && type != e->type())
|
||||
continue;
|
||||
_score->addRefresh(e->drag(editData));
|
||||
QVector<QLineF> elAnchorLines = e->dragAnchorLines();
|
||||
const QPointF pageOffset(e->findAncestor(ElementType::PAGE)->pos());
|
||||
|
||||
if (!elAnchorLines.isEmpty()) {
|
||||
for (QLineF& l : elAnchorLines)
|
||||
l.translate(pageOffset);
|
||||
anchorLines.append(elAnchorLines);
|
||||
}
|
||||
}
|
||||
|
||||
if (anchorLines.isEmpty())
|
||||
setDropTarget(0); // this also resets dropAnchor
|
||||
else
|
||||
setDropAnchorLines(anchorLines);
|
||||
|
||||
Element* e = _score->getSelectedElement();
|
||||
if (e) {
|
||||
if (_score->playNote()) {
|
||||
mscore->play(e);
|
||||
_score->setPlayNote(false);
|
||||
}
|
||||
_score->update();
|
||||
|
||||
QVector<QLineF> anchorLines = e->dragAnchorLines();
|
||||
const QPointF pageOffset(e->findAncestor(ElementType::PAGE)->pos());
|
||||
|
||||
if (!anchorLines.isEmpty()) {
|
||||
for (QLineF& l : anchorLines)
|
||||
l.translate(pageOffset);
|
||||
setDropAnchorLines(anchorLines);
|
||||
}
|
||||
else
|
||||
setDropTarget(0); // this also resets dropAnchor
|
||||
}
|
||||
updateGrips();
|
||||
_score->update();
|
||||
|
@ -110,11 +129,10 @@ void ScoreView::doDragElement(QMouseEvent* ev)
|
|||
|
||||
void ScoreView::endDrag()
|
||||
{
|
||||
for (Element* e : _score->selection().elements()) {
|
||||
e->endDrag(editData);
|
||||
e->triggerLayout();
|
||||
}
|
||||
for (auto& g : dragGroups)
|
||||
g->endDrag(editData);
|
||||
|
||||
dragGroups.clear();
|
||||
_score->selection().unlock("drag");
|
||||
setDropTarget(0); // this also resets dropAnchor
|
||||
_score->endCmd();
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include "globals.h"
|
||||
#include "libmscore/element.h"
|
||||
#include "libmscore/elementgroup.h"
|
||||
#include "libmscore/durationtype.h"
|
||||
#include "libmscore/mscore.h"
|
||||
#include "libmscore/mscoreview.h"
|
||||
|
@ -115,6 +116,7 @@ class ScoreView : public QWidget, public MuseScoreView {
|
|||
QFocusFrame* focusFrame;
|
||||
|
||||
EditData editData;
|
||||
std::vector<std::unique_ptr<ElementGroup>> dragGroups;
|
||||
|
||||
//--input state:
|
||||
PositionCursor* _cursor;
|
||||
|
|
Loading…
Reference in a new issue