Skip to content

Commit 313bb56

Browse files
committed
Add Score.spanners and Score.spannersOfType() to plugin API
1 parent eb65904 commit 313bb56

File tree

2 files changed

+135
-0
lines changed

2 files changed

+135
-0
lines changed

src/engraving/api/v1/score.cpp

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#include "dom/measure.h"
2929
#include "dom/score.h"
3030
#include "dom/segment.h"
31+
#include "dom/spanner.h"
32+
#include "dom/spannermap.h"
3133
#include "dom/text.h"
3234
#include "editing/editsystemlocks.h"
3335
#include "types/typesconv.h"
@@ -39,6 +41,84 @@
3941

4042
using namespace mu::engraving::apiv1;
4143

44+
Score::SpannerListContext* Score::acquireSpannerContext(bool hasFilter, mu::engraving::ElementType filterType)
45+
{
46+
for (const auto& ctx : m_spannerListContexts) {
47+
if (ctx->hasFilter == hasFilter && ctx->filterType == filterType) {
48+
return ctx.get();
49+
}
50+
}
51+
52+
auto context = std::make_unique<SpannerListContext>();
53+
context->owner = this;
54+
context->hasFilter = hasFilter;
55+
context->filterType = filterType;
56+
m_spannerListContexts.push_back(std::move(context));
57+
return m_spannerListContexts.back().get();
58+
}
59+
60+
qsizetype Score::spannerListCount(QQmlListProperty<Spanner>* list)
61+
{
62+
auto* ctx = static_cast<SpannerListContext*>(list->data);
63+
if (!ctx || !ctx->owner) {
64+
return 0;
65+
}
66+
67+
mu::engraving::Score* nativeScore = ctx->owner->score();
68+
if (!nativeScore) {
69+
return 0;
70+
}
71+
72+
const auto& spanMap = nativeScore->spannerMap().map();
73+
if (!ctx->hasFilter) {
74+
return static_cast<qsizetype>(spanMap.size());
75+
}
76+
77+
qsizetype count = 0;
78+
for (const auto& [tick, spanner] : spanMap) {
79+
UNUSED(tick);
80+
if (spanner && spanner->type() == ctx->filterType) {
81+
++count;
82+
}
83+
}
84+
85+
return count;
86+
}
87+
88+
Spanner* Score::spannerListAt(QQmlListProperty<Spanner>* list, qsizetype index)
89+
{
90+
auto* ctx = static_cast<SpannerListContext*>(list->data);
91+
if (!ctx || !ctx->owner || index < 0) {
92+
return nullptr;
93+
}
94+
95+
mu::engraving::Score* nativeScore = ctx->owner->score();
96+
if (!nativeScore) {
97+
return nullptr;
98+
}
99+
100+
const auto& spanMap = nativeScore->spannerMap().map();
101+
qsizetype current = 0;
102+
for (const auto& [tick, spanner] : spanMap) {
103+
UNUSED(tick);
104+
if (!spanner) {
105+
continue;
106+
}
107+
108+
if (ctx->hasFilter && spanner->type() != ctx->filterType) {
109+
continue;
110+
}
111+
112+
if (current == index) {
113+
return qobject_cast<Spanner*>(wrap(spanner, Ownership::SCORE));
114+
}
115+
116+
++current;
117+
}
118+
119+
return nullptr;
120+
}
121+
42122
Cursor* Score::newCursor()
43123
{
44124
return new Cursor(score());
@@ -262,6 +342,37 @@ QQmlListProperty<System> Score::systems()
262342
return wrapContainerProperty<System>(this, score()->systems());
263343
}
264344

345+
//---------------------------------------------------------
346+
// Score::spanners
347+
//---------------------------------------------------------
348+
349+
QQmlListProperty<Spanner> Score::spanners()
350+
{
351+
auto* context = acquireSpannerContext(false, mu::engraving::ElementType::INVALID);
352+
return QQmlListProperty<Spanner>(this, context, &Score::spannerListCount, &Score::spannerListAt);
353+
}
354+
355+
//---------------------------------------------------------
356+
// Score::spannersOfType
357+
//---------------------------------------------------------
358+
359+
QQmlListProperty<Spanner> Score::spannersOfType(int elementType)
360+
{
361+
using mu::engraving::ElementType;
362+
363+
if (elementType == int(ElementType::INVALID)) {
364+
return spanners();
365+
}
366+
367+
if (elementType <= int(ElementType::INVALID)
368+
|| elementType >= int(ElementType::ROOT_ITEM)) {
369+
return QQmlListProperty<Spanner>();
370+
}
371+
372+
auto* context = acquireSpannerContext(true, static_cast<ElementType>(elementType));
373+
return QQmlListProperty<Spanner>(this, context, &Score::spannerListCount, &Score::spannerListAt);
374+
}
375+
265376
//---------------------------------------------------------
266377
// Score::startCmd
267378
//---------------------------------------------------------

src/engraving/api/v1/score.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@
3030
#include "engraving/dom/masterscore.h"
3131

3232
// api
33+
#include <memory>
34+
#include <utility>
35+
#include <vector>
36+
3337
#include "excerpt.h"
3438
#include "apistructs.h"
3539
#include "style.h"
@@ -41,6 +45,8 @@ Q_MOC_INCLUDE("engraving/api/v1/selection.h")
4145
namespace mu::engraving {
4246
class InstrumentTemplate;
4347
class Selection;
48+
class Spanner;
49+
enum class ElementType : unsigned char;
4450
}
4551

4652
namespace mu::engraving::apiv1 {
@@ -53,6 +59,7 @@ class System;
5359
class Selection;
5460
class Score;
5561
class Staff;
62+
class Spanner;
5663

5764
extern Selection* selectionWrap(mu::engraving::Selection* select);
5865

@@ -165,6 +172,9 @@ class Score : public apiv1::ScoreElement, public muse::Injectable
165172
/// List of systems in this score.
166173
/// \since MuseScore 4.6
167174
Q_PROPERTY(QQmlListProperty<apiv1::System> systems READ systems)
175+
/// List of score-level spanners stored in the SpannerMap.
176+
/// \since MuseScore 4.7
177+
Q_PROPERTY(QQmlListProperty<apiv1::Spanner> spanners READ spanners)
168178

169179
muse::Inject<mu::context::IGlobalContext> context = { this };
170180

@@ -345,12 +355,26 @@ class Score : public apiv1::ScoreElement, public muse::Injectable
345355
QQmlListProperty<apiv1::Staff> staves();
346356
QQmlListProperty<apiv1::Page> pages();
347357
QQmlListProperty<apiv1::System> systems();
358+
QQmlListProperty<apiv1::Spanner> spanners();
359+
Q_INVOKABLE QQmlListProperty<apiv1::Spanner> spannersOfType(int elementType);
348360

349361
static const mu::engraving::InstrumentTemplate* instrTemplateFromName(const QString& name); // used by PluginAPI::newScore()
350362
/// \endcond
351363

352364
private:
353365
mu::notation::INotationPtr notation() const;
354366
mu::notation::INotationUndoStackPtr undoStack() const;
367+
368+
struct SpannerListContext {
369+
Score* owner = nullptr;
370+
bool hasFilter = false;
371+
mu::engraving::ElementType filterType = mu::engraving::ElementType::INVALID;
372+
};
373+
374+
SpannerListContext* acquireSpannerContext(bool hasFilter, mu::engraving::ElementType filterType);
375+
static qsizetype spannerListCount(QQmlListProperty<Spanner>* list);
376+
static Spanner* spannerListAt(QQmlListProperty<Spanner>* list, qsizetype index);
377+
378+
std::vector<std::unique_ptr<SpannerListContext>> m_spannerListContexts;
355379
};
356380
}

0 commit comments

Comments
 (0)