Skip to content

Commit

Permalink
fix #293017: add a possibility to change selection from plugins
Browse files Browse the repository at this point in the history
Also expose range selection properties in Selection object
  • Loading branch information
dmitrio95 committed May 16, 2020
1 parent e925ba0 commit da65f99
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 3 deletions.
7 changes: 6 additions & 1 deletion libmscore/undo.cpp
Expand Up @@ -482,14 +482,19 @@ void UndoStack::redo(EditData* ed)
// UndoMacro
//---------------------------------------------------------

bool UndoMacro::canRecordSelectedElement(const Element* e)
{
return e->isNote() || (e->isChordRest() && !e->isChord()) || (e->isTextBase() && !e->isInstrumentName()) || e->isFretDiagram();
}

void UndoMacro::fillSelectionInfo(SelectionInfo& info, const Selection& sel)
{
info.staffStart = info.staffEnd = -1;
info.elements.clear();

if (sel.isList()) {
for (Element* e : sel.elements()) {
if (e->isNote() || e->isChordRest() || (e->isTextBase() && !e->isInstrumentName()) || e->isFretDiagram())
if (canRecordSelectedElement(e))
info.elements.push_back(e);
else {
// don't remember selection we are unable to restore
Expand Down
2 changes: 2 additions & 0 deletions libmscore/undo.h
Expand Up @@ -165,6 +165,8 @@ class UndoMacro : public UndoCommand {
bool empty() const { return childCount() == 0; }
void append(UndoMacro&& other);

static bool canRecordSelectedElement(const Element* e);

UNDO_NAME("UndoMacro");
};

Expand Down
138 changes: 138 additions & 0 deletions mscore/plugin/api/selection.cpp
Expand Up @@ -13,6 +13,8 @@
#include "selection.h"
#include "score.h"

#include "libmscore/undo.h"

namespace Ms {
namespace PluginAPI {

Expand All @@ -28,5 +30,141 @@ Selection* selectionWrap(Ms::Selection* select)
return w;
}

//---------------------------------------------------------
// Selection::checkSelectionIsNotLocked
//---------------------------------------------------------

bool Selection::checkSelectionIsNotLocked() const
{
if (_select->isLocked()) {
qWarning("Cannot change selection: %s", qPrintable(_select->lockReason()));
return false;
}
return true;
}

//---------------------------------------------------------
// Selection::select
/// Selects the given element. At this point only a
/// limited number of element types is supported, like
/// notes, rests and most of text elements.
/// \param e element to select
/// \param add if \p true, appends an element to already
/// existing selection. If \p false (default), deselects
/// all other elements and selects this element.
/// \return \p true on success, \p false if selection
/// cannot be changed, e.g. due to the ongoing operation
/// on a score (like dragging elements) or incorrect
/// arguments to this function.
/// \since MuseScore 3.5
//---------------------------------------------------------

bool Selection::select(Element* elWrapper, bool add)
{
if (!checkSelectionIsNotLocked())
return false;

if (!elWrapper)
return false;

Ms::Element* e = elWrapper->element();

// Check whether it's safe to select this element:
// use types list from UndoMacro for now
if (!Ms::UndoMacro::canRecordSelectedElement(e)) {
qWarning("Cannot select element of type %s", e->name());
return false;
}

if (e->score() != _select->score() || elWrapper->ownership() != Ownership::SCORE) {
qWarning("Selection::select: element does not belong to score");
return false;
}

const SelectType selType = add ? SelectType::ADD : SelectType::SINGLE;
e->score()->select(e, selType);

return true;
}

//---------------------------------------------------------
// Selection::selectRange
/// Selects a range in a score
/// \param startTick start tick to be included in selection
/// \param endTick end tick of selection, excluded from selection
/// \param startStaff start staff index, included in selection
/// \param endStaff end staff index, excluded from seleciton
/// \return \p true on success, \p false if selection
/// cannot be changed, e.g. due to the ongoing operation
/// on a score (like dragging elements) or incorrect
/// arguments to this function.
/// \since MuseScore 3.5
//---------------------------------------------------------

bool Selection::selectRange(int startTick, int endTick, int startStaff, int endStaff)
{
if (!checkSelectionIsNotLocked())
return false;

const int nstaves = _select->score()->nstaves();

startStaff = qBound(0, startStaff, nstaves - 1);
endStaff = qBound(1, endStaff, nstaves);

if (startStaff >= endStaff)
return false;

Ms::Segment* segStart = _select->score()->tick2leftSegmentMM(Ms::Fraction::fromTicks(startTick));
Ms::Segment* segEnd = _select->score()->tick2leftSegmentMM(Ms::Fraction::fromTicks(endTick));

if (!segStart || (segEnd && !((*segEnd) > (*segStart))))
return false;

if (segEnd && _select->score()->undoStack()->active())
_select->setRangeTicks(segStart->tick(), segEnd->tick(), startStaff, endStaff);
else
_select->setRange(segStart, segEnd, startStaff, endStaff);

return true;
}

//---------------------------------------------------------
// Selection::deselect
/// Deselects the given element.
/// \return \p true on success, \p false if selection
/// cannot be changed, e.g. due to the ongoing operation
/// on a score (like dragging elements).
/// \since MuseScore 3.5
//---------------------------------------------------------

bool Selection::deselect(Element* elWrapper)
{
if (!checkSelectionIsNotLocked())
return false;

if (!elWrapper)
return false;

_select->score()->deselect(elWrapper->element());
return true;
}

//---------------------------------------------------------
// Selection::clear
/// Clears the selection.
/// \return \p true on success, \p false if selection
/// cannot be changed, e.g. due to the ongoing operation
/// on a score (like dragging elements).
/// \since MuseScore 3.5
//---------------------------------------------------------

bool Selection::clear()
{
if (!checkSelectionIsNotLocked())
return false;

_select->deselectAll();
return true;
}
}
}
52 changes: 50 additions & 2 deletions mscore/plugin/api/selection.h
Expand Up @@ -31,20 +31,68 @@ class Selection : public QObject {
/// \since MuseScore 3.3
Q_PROPERTY(QQmlListProperty<Ms::PluginAPI::Element> elements READ elements)

/// \cond MS_INTERNAL
/**
* Whether this selection covers a range of a score, as opposed to
* a list of distinct elements.
* \since MuseScore 3.5
*/
Q_PROPERTY(bool isRange READ isRange)
/**
* Start segment of selection, included. This property is valid
* only for range selection.
* \since MuseScore 3.5
* \see \ref isRange
*/
Q_PROPERTY(Ms::PluginAPI::Segment* startSegment READ startSegment)
/**
* End segment of selection, excluded. This property is valid
* only for range selection.
* \since MuseScore 3.5
* \see \ref isRange
*/
Q_PROPERTY(Ms::PluginAPI::Segment* endSegment READ endSegment)
/**
* First staff of selection, included. This property is valid
* only for range selection.
* \since MuseScore 3.5
* \see \ref isRange
*/
Q_PROPERTY(int startStaff READ startStaff)
/**
* End staff of selection, included. This property is valid
* only for range selection.
* \since MuseScore 3.5
* \see \ref isRange
*/
Q_PROPERTY(int endStaff READ endStaff)

protected:
/// \cond MS_INTERNAL
Ms::Selection* _select;

public:
bool checkSelectionIsNotLocked() const;
/// \endcond

public:
/// \cond MS_INTERNAL
Selection(Ms::Selection* select) : QObject(), _select(select) {}
virtual ~Selection() { }

QQmlListProperty<Element> elements()
{ return wrapContainerProperty<Element>(this, _select->elements()); }

bool isRange() const { return _select->isRange(); }

Segment* startSegment() const { return wrap<Segment>(_select->startSegment()); }
Segment* endSegment() const { return wrap<Segment>(_select->endSegment()); }
int startStaff() const { return _select->staffStart(); }
int endStaff() const { return _select->staffEnd(); }
/// \endcond

Q_INVOKABLE bool select(Ms::PluginAPI::Element* e, bool add = false);
Q_INVOKABLE bool selectRange(int startTick, int endTick, int startStaff, int endStaff);
Q_INVOKABLE bool deselect(Ms::PluginAPI::Element* e);
Q_INVOKABLE bool clear();
};

extern Selection* selectionWrap(Ms::Selection* select);
Expand Down

0 comments on commit da65f99

Please sign in to comment.