Skip to content
Open
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
18 changes: 18 additions & 0 deletions src/engraving/api/v1/score.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,24 @@ QQmlListProperty<System> Score::systems() const
return wrapContainerProperty<System>(this, score()->systems());
}

/** Exposes the score's live measure-base list without a shared temporary container. */
QQmlListProperty<MeasureBase> Score::measures()
{
return QQmlListProperty<MeasureBase>(this, score()->measures(),
/** Returns the current number of measures and frames. */
[](QQmlListProperty<MeasureBase>* list) -> qsizetype {
return static_cast<engraving::MeasureBaseList*>(list->data)->size();
}, /** Returns the wrapped item at index, or null when the index is invalid. */
[](QQmlListProperty<MeasureBase>* list, qsizetype index) -> MeasureBase* {
const auto* measures = static_cast<engraving::MeasureBaseList*>(list->data);
if (index < 0 || index >= measures->size()) {
return nullptr;
}
engraving::MeasureBase* measure = measures->at(static_cast<size_t>(index));
return qobject_cast<MeasureBase*>(wrap(measure, Ownership::SCORE));
});
}

QQmlListProperty<EngravingItem> Score::brackets(int staffIdx)
{
return wrapContainerProperty<EngravingItem>(this, score()->brackets(static_cast<staff_idx_t>(staffIdx)));
Expand Down
11 changes: 11 additions & 0 deletions src/engraving/api/v1/score.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,15 @@ class Score : public apiv1::ScoreElement, public muse::Contextable
*/
Q_PROPERTY(QQmlListProperty<apiv1::Page> pages READ pages)

/** APIDOC
* List of measures and frames in score order, including individual measures
* within multimeasure rests. This list does not expand playback repeats.
* @readonly
* @q_property {Engraving.MeasureBase[]}
* @since 5.0
*/
Q_PROPERTY(QQmlListProperty<apiv1::MeasureBase> measures READ measures)

/** APIDOC
* Page numbering offset. The user-visible number of the given page is defined as
* ```
Expand Down Expand Up @@ -397,6 +406,8 @@ class Score : public apiv1::ScoreElement, public muse::Contextable

int npages() const { return static_cast<int>(score()->npages()); }
QQmlListProperty<apiv1::Page> pages() const;
/** Returns read-only access to the score's measures and frames. */
QQmlListProperty<apiv1::MeasureBase> measures();
int pageNumberOffset() const { return score()->pageNumberOffset(); }
void setPageNumberOffset(int offset) { score()->undoChangePageNumberOffset(offset); }

Expand Down
31 changes: 31 additions & 0 deletions src/engraving/dom/measurebase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -754,8 +754,25 @@ MeasureBaseList::MeasureBaseList()
m_size = 0;
}

/** Returns a score-order item in constant time after lazily rebuilding the index. */
MeasureBase* MeasureBaseList::at(size_t index) const
{
if (index >= static_cast<size_t>(m_size)) {
return nullptr;
}
if (m_index.empty()) {
m_index.reserve(m_size);
for (MeasureBase* measure = m_first; measure; measure = measure->next()) {
m_index.push_back(measure);
}
}
return m_index.at(index);
}

/** Empties the list and invalidates its lookup indexes without deleting its items. */
void MeasureBaseList::clear()
{
m_index.clear();
m_first = nullptr;
m_last = nullptr;
m_size = 0;
Expand All @@ -766,8 +783,10 @@ void MeasureBaseList::clear()
// push_back
//---------------------------------------------------------

/** Links an item at the end and invalidates indexed access. */
void MeasureBaseList::push_back(MeasureBase* m)
{
m_index.clear();
++m_size;
if (m_last) {
m_last->setNext(m);
Expand All @@ -785,8 +804,10 @@ void MeasureBaseList::push_back(MeasureBase* m)
// push_front
//---------------------------------------------------------

/** Links an item at the beginning and invalidates indexed access. */
void MeasureBaseList::push_front(MeasureBase* m)
{
m_index.clear();
++m_size;
if (m_first) {
m_first->setPrev(m);
Expand All @@ -805,8 +826,10 @@ void MeasureBaseList::push_front(MeasureBase* m)
// insert m before m->next()
//---------------------------------------------------------

/** Inserts an item before its next item and invalidates indexed access. */
void MeasureBaseList::add(MeasureBase* m)
{
m_index.clear();
MeasureBase* el = m->next();
if (el == 0) {
append(m);
Expand All @@ -826,8 +849,10 @@ void MeasureBaseList::add(MeasureBase* m)
// remove
//---------------------------------------------------------

/** Unlinks one item and invalidates indexed access without deleting the item. */
void MeasureBaseList::remove(MeasureBase* m)
{
m_index.clear();
--m_size;
if (m->prev()) {
m->prev()->setNext(m->next());
Expand All @@ -845,8 +870,10 @@ void MeasureBaseList::remove(MeasureBase* m)
// insert
//---------------------------------------------------------

/** Inserts an inclusive linked range and invalidates indexed access. */
void MeasureBaseList::insert(MeasureBase* fm, MeasureBase* lm)
{
m_index.clear();
for (MeasureBase* m = fm; m != lm; m = m->next()) {
++m_size;
}
Expand All @@ -869,8 +896,10 @@ void MeasureBaseList::insert(MeasureBase* fm, MeasureBase* lm)
// remove
//---------------------------------------------------------

/** Unlinks an inclusive range and invalidates indexed access without deleting its items. */
void MeasureBaseList::remove(MeasureBase* fm, MeasureBase* lm)
{
m_index.clear();
for (MeasureBase* m = fm; m != lm; m = m->next()) {
--m_size;
}
Expand All @@ -893,8 +922,10 @@ void MeasureBaseList::remove(MeasureBase* fm, MeasureBase* lm)
// change
//---------------------------------------------------------

/** Replaces an item in place and invalidates indexed access even when the size is unchanged. */
void MeasureBaseList::change(MeasureBase* ob, MeasureBase* nb)
{
m_index.clear();
nb->setPrev(ob->prev());
nb->setNext(ob->next());
if (ob->prev()) {
Expand Down
5 changes: 5 additions & 0 deletions src/engraving/dom/measurebase.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,8 @@ class MeasureBaseList
MeasureBaseList();
MeasureBase* first() const { return m_first; }
MeasureBase* last() const { return m_last; }
/** Returns the item at index, or null if out of bounds; rebuilds the index after list changes. */
MeasureBase* at(size_t index) const;
void clear();
void add(MeasureBase*);
void remove(MeasureBase*);
Expand All @@ -233,6 +235,9 @@ class MeasureBaseList
MeasureBase* m_first = nullptr;
MeasureBase* m_last = nullptr;

// Non-owning index, cleared by every structural mutation and rebuilt on demand.
mutable std::vector<MeasureBase*> m_index;

// At a tick there can be any number of MeasureBases
// There can only be one Measure
// There can be any number of Boxes
Expand Down
Loading