Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rebase segment-anchored lines on dragging #5763

Merged
merged 16 commits into from
Apr 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions libmscore/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion libmscore/beam.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2565,7 +2565,7 @@ void Beam::initBeamEditData(EditData& ed)
bed->editFragment = 0;
ed.addData(bed);

QPointF pt(ed.startMove - pagePos());
QPointF pt(ed.normalizedStartMove - pagePos());
qreal ydiff = 100000000.0;
int idx = (_direction == Direction::AUTO || _direction == Direction::DOWN) ? 0 : 1;
int i = 0;
Expand Down
2 changes: 1 addition & 1 deletion libmscore/box.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ Element* Box::drop(EditData& data)
QRectF HBox::drag(EditData& data)
{
QRectF r(canvasBoundingRect());
qreal diff = data.delta.x();
qreal diff = data.evtDelta.x();
qreal x1 = offset().x() + diff;
if (parent()->type() == ElementType::VBOX) {
VBox* vb = toVBox(parent());
Expand Down
23 changes: 20 additions & 3 deletions libmscore/dynamic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//=============================================================================

#include "dynamic.h"
#include "dynamichairpingroup.h"
#include "xml.h"
#include "score.h"
#include "measure.h"
Expand Down Expand Up @@ -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
//---------------------------------------------------------
Expand All @@ -359,15 +373,18 @@ QRectF Dynamic::drag(EditData& ed)
if (km != (Qt::ShiftModifier | Qt::ControlModifier)) {
int si = staffIdx();
Segment* seg = segment();
score()->dragPosition(ed.pos, &si, &seg);
score()->dragPosition(canvasPos(), &si, &seg);
if (seg != segment() || staffIdx() != si) {
const QPointF oldOffset = offset();
QPointF pos1(canvasPos());
score()->undo(new ChangeParent(this, seg, si));
setOffset(QPointF());
layout();
QPointF pos2(canvasPos());
setOffset(pos1 - pos2);
ed.startMove = pos2;
const QPointF newOffset = pos1 - pos2;
setOffset(newOffset);
ElementEditData* eed = ed.getData(this);
eed->initOffset += newOffset - oldOffset;
}
}
return f;
Expand Down
2 changes: 2 additions & 0 deletions libmscore/dynamic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
190 changes: 190 additions & 0 deletions libmscore/dynamichairpingroup.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 68 additions & 0 deletions libmscore/dynamichairpingroup.h
Original file line number Diff line number Diff line change
@@ -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
8 changes: 6 additions & 2 deletions libmscore/element.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1946,6 +1946,7 @@ void Element::startDrag(EditData& ed)
eed->e = this;
eed->pushProperty(Pid::OFFSET);
eed->pushProperty(Pid::AUTOPLACE);
eed->initOffset = offset();
ed.addData(eed);
if (ed.modifiers & Qt::AltModifier)
setAutoplace(false);
Expand All @@ -1963,8 +1964,11 @@ QRectF Element::drag(EditData& ed)

const QRectF r0(canvasBoundingRect());

qreal x = ed.delta.x();
qreal y = ed.delta.y();
const ElementEditData* eed = ed.getData(this);

const QPointF offset0 = ed.moveDelta + eed->initOffset;
qreal x = offset0.x();
qreal y = offset0.y();

qreal _spatium = spatium();
if (ed.hRaster) {
Expand Down
Loading