implemented creating and removing of excerpts
This commit is contained in:
parent
28fe6ceab4
commit
cb1fe3a1ad
26 changed files with 429 additions and 164 deletions
|
@ -32,7 +32,7 @@ FocusableItem {
|
|||
|
||||
anchors.fill: parent
|
||||
|
||||
color: root.accentButton ? ui.theme.accentColor : ui.theme.buttonColor
|
||||
color: normalStateColor
|
||||
opacity: ui.theme.buttonOpacityNormal
|
||||
border.width: 0
|
||||
radius: 3
|
||||
|
|
|
@ -6,13 +6,16 @@ RadioDelegate {
|
|||
|
||||
default property Component contentComponent
|
||||
|
||||
property alias backgroundColor: backgroundRect.color
|
||||
property alias radius: backgroundRect.radius
|
||||
|
||||
property color normalStateColor: ui.theme.buttonColor
|
||||
property color hoverStateColor: ui.theme.buttonColor
|
||||
property color pressedStateColor: ui.theme.buttonColor
|
||||
property color selectedStateColor: ui.theme.accentColor
|
||||
|
||||
implicitHeight: 30
|
||||
implicitWidth: ListView.view ? (ListView.view.width - (ListView.view.spacing * (ListView.view.count - 1))) / ListView.view.count
|
||||
: 30
|
||||
|
||||
hoverEnabled: true
|
||||
|
||||
background: Rectangle {
|
||||
|
@ -20,10 +23,9 @@ RadioDelegate {
|
|||
|
||||
anchors.fill: parent
|
||||
|
||||
color: ui.theme.buttonColor
|
||||
opacity: root.checked || root.pressed ? 0 : ui.theme.buttonOpacityNormal
|
||||
color: normalStateColor
|
||||
opacity: ui.theme.buttonOpacityNormal
|
||||
|
||||
border.width: 0
|
||||
radius: 2
|
||||
}
|
||||
|
||||
|
@ -39,56 +41,39 @@ RadioDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
indicator: Item {
|
||||
}
|
||||
indicator: Item {}
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "PRESSED"
|
||||
when: root.pressed
|
||||
|
||||
PropertyChanges {
|
||||
target: backgroundRect
|
||||
color: ui.theme.accentColor
|
||||
opacity: ui.theme.accentOpacityHit
|
||||
border.width: 0
|
||||
}
|
||||
},
|
||||
|
||||
State {
|
||||
name: "SELECTED"
|
||||
when: root.checked && !root.hovered
|
||||
|
||||
PropertyChanges {
|
||||
target: backgroundRect
|
||||
color: ui.theme.accentColor
|
||||
opacity: ui.theme.accentOpacityNormal
|
||||
border.width: 0
|
||||
}
|
||||
},
|
||||
|
||||
State {
|
||||
name: "HOVERED"
|
||||
when: root.hovered && !root.checked && !root.pressed
|
||||
|
||||
PropertyChanges {
|
||||
target: backgroundRect
|
||||
color: ui.theme.buttonColor
|
||||
color: hoverStateColor
|
||||
opacity: ui.theme.buttonOpacityHover
|
||||
border.color: ui.theme.strokeColor
|
||||
border.width: 1
|
||||
}
|
||||
},
|
||||
|
||||
State {
|
||||
name: "SELECTED_HOVERED"
|
||||
when: root.hovered && root.checked
|
||||
name: "PRESSED"
|
||||
when: root.pressed && !root.checked
|
||||
|
||||
PropertyChanges {
|
||||
target: backgroundRect
|
||||
color: ui.theme.accentColor
|
||||
opacity: ui.theme.accentOpacityHover
|
||||
border.width: 0
|
||||
color: pressedStateColor
|
||||
opacity: ui.theme.buttonOpacityHit
|
||||
}
|
||||
},
|
||||
|
||||
State {
|
||||
name: "SELECTED"
|
||||
when: root.checked
|
||||
|
||||
PropertyChanges {
|
||||
target: backgroundRect
|
||||
color: selectedStateColor
|
||||
opacity: ui.theme.buttonOpacityNormal
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -174,6 +174,7 @@ void Excerpt::createExcerpt(Excerpt* excerpt)
|
|||
// Set instruments and create linked staves
|
||||
for (const Part* part : parts) {
|
||||
Part* p = new Part(score);
|
||||
p->setId(part->id());
|
||||
p->setInstrument(*part->instrument());
|
||||
p->setPartName(part->partName());
|
||||
|
||||
|
|
|
@ -1424,7 +1424,7 @@ void Score::hideEmptyStaves(System* system, bool isFirstSystem)
|
|||
}
|
||||
}
|
||||
// don’t allow a complete empty system
|
||||
if (systemIsEmpty) {
|
||||
if (systemIsEmpty && !_staves.isEmpty()) {
|
||||
Staff* staff = firstVisible ? firstVisible : _staves.front();
|
||||
SysStaff* ss = system->staff(staff->idx());
|
||||
ss->setShow(true);
|
||||
|
|
|
@ -30,22 +30,28 @@ mu::async::Notification MU4InspectorAdapter::isTextEditingChanged() const
|
|||
|
||||
void MU4InspectorAdapter::beginCommand()
|
||||
{
|
||||
undoStack()->prepareChanges();
|
||||
if (undoStack()) {
|
||||
undoStack()->prepareChanges();
|
||||
}
|
||||
}
|
||||
|
||||
void MU4InspectorAdapter::endCommand()
|
||||
{
|
||||
undoStack()->commitChanges();
|
||||
if (undoStack()) {
|
||||
undoStack()->commitChanges();
|
||||
}
|
||||
}
|
||||
|
||||
void MU4InspectorAdapter::updateStyleValue(const Ms::Sid& styleId, const QVariant& newValue)
|
||||
{
|
||||
style()->setStyleValue(styleId, newValue);
|
||||
if (style()) {
|
||||
style()->setStyleValue(styleId, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
QVariant MU4InspectorAdapter::styleValue(const Ms::Sid& styleId)
|
||||
{
|
||||
return style()->styleValue(styleId);
|
||||
return style() ? style()->styleValue(styleId) : QVariant();
|
||||
}
|
||||
|
||||
void MU4InspectorAdapter::showSpecialCharactersDialog()
|
||||
|
@ -124,7 +130,7 @@ void MU4InspectorAdapter::updateNotation()
|
|||
|
||||
INotationUndoStack* MU4InspectorAdapter::undoStack() const
|
||||
{
|
||||
IF_ASSERT_FAILED(context() && context()->currentNotation()) {
|
||||
if (!context() || !context()->currentNotation()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -133,7 +139,7 @@ INotationUndoStack* MU4InspectorAdapter::undoStack() const
|
|||
|
||||
INotationStyle* MU4InspectorAdapter::style() const
|
||||
{
|
||||
IF_ASSERT_FAILED(context() && context()->currentNotation()) {
|
||||
if (!context() || !context()->currentNotation()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -209,6 +209,7 @@ void InspectorListModel::subscribeOnSelectionChanges()
|
|||
|
||||
if (!m_notation) {
|
||||
setElementList(QList<Ms::Element*>());
|
||||
return;
|
||||
}
|
||||
|
||||
m_notation->interaction()->selectionChanged().onNotify(this, [this]() {
|
||||
|
|
|
@ -162,7 +162,7 @@ InspectorSectionView {
|
|||
checked: root.model && !root.model.horizontalAlignment.isUndefined ? root.model.horizontalAlignment.value === modelData["typeRole"]
|
||||
: false
|
||||
|
||||
backgroundColor: ui.theme.backgroundPrimaryColor
|
||||
normalStateColor: ui.theme.backgroundPrimaryColor
|
||||
|
||||
onToggled: {
|
||||
root.model.horizontalAlignment.value = modelData["typeRole"]
|
||||
|
@ -199,7 +199,7 @@ InspectorSectionView {
|
|||
checked: root.model && !root.model.verticalAlignment.isUndefined ? root.model.verticalAlignment.value === modelData["typeRole"]
|
||||
: false
|
||||
|
||||
backgroundColor: ui.theme.backgroundPrimaryColor
|
||||
normalStateColor: ui.theme.backgroundPrimaryColor
|
||||
|
||||
onToggled: {
|
||||
root.model.verticalAlignment.value = modelData["typeRole"]
|
||||
|
|
|
@ -57,7 +57,7 @@ StyledPopup {
|
|||
|
||||
width: 30
|
||||
|
||||
backgroundColor: "#00000000"
|
||||
normalStateColor: "#00000000"
|
||||
|
||||
ButtonGroup.group: subscriptOptionsButtonList.radioButtonGroup
|
||||
|
||||
|
|
|
@ -22,13 +22,11 @@
|
|||
|
||||
#include "inotation.h"
|
||||
|
||||
namespace mu {
|
||||
namespace notation {
|
||||
namespace mu::notation {
|
||||
class IExcerptNotation : virtual public INotation
|
||||
{
|
||||
};
|
||||
using IExcerptNotationPtr = std::shared_ptr<IExcerptNotation>;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MU_NOTATION_IEXCERPTNOTATION_H
|
||||
|
|
|
@ -24,8 +24,7 @@
|
|||
#include "ret.h"
|
||||
#include "io/path.h"
|
||||
|
||||
namespace mu {
|
||||
namespace notation {
|
||||
namespace mu::notation {
|
||||
class IMasterNotation : virtual public INotation
|
||||
{
|
||||
public:
|
||||
|
@ -35,10 +34,12 @@ public:
|
|||
virtual Ret createNew(const ScoreCreateOptions& scoreInfo) = 0;
|
||||
|
||||
virtual std::vector<IExcerptNotationPtr> excerpts() const = 0;
|
||||
virtual async::Notification excerptsChanged() const = 0;
|
||||
virtual IExcerptNotationPtr appendExcerpt(const Meta& meta) = 0;
|
||||
virtual void removeExcerpt(IExcerptNotationPtr excerpt) = 0;
|
||||
};
|
||||
|
||||
using IMasterNotationPtr = std::shared_ptr<IMasterNotation>;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MU_NOTATION_IMASTERNOTATION_H
|
||||
|
|
|
@ -48,6 +48,9 @@ public:
|
|||
virtual void paint(QPainter* painter) = 0;
|
||||
virtual QRectF previewRect() const = 0;
|
||||
|
||||
virtual ValCh<bool> opened() const = 0;
|
||||
virtual void setOpened(bool opened) = 0;
|
||||
|
||||
// input (mouse)
|
||||
virtual INotationInteraction* interaction() const = 0;
|
||||
|
||||
|
|
|
@ -19,9 +19,27 @@
|
|||
|
||||
#include "excerptnotation.h"
|
||||
|
||||
#include "libmscore/excerpt.h"
|
||||
|
||||
using namespace mu::notation;
|
||||
|
||||
ExcerptNotation::ExcerptNotation(Ms::Score* score)
|
||||
: Notation(score)
|
||||
ExcerptNotation::ExcerptNotation(Ms::Excerpt* excerpt)
|
||||
: Notation(excerpt->partScore()), m_excerpt(excerpt)
|
||||
{
|
||||
}
|
||||
|
||||
ExcerptNotation::~ExcerptNotation()
|
||||
{
|
||||
Ms::MasterScore* master = m_excerpt->oscore();
|
||||
if (master) {
|
||||
master->removeExcerpt(m_excerpt);
|
||||
}
|
||||
|
||||
delete m_excerpt;
|
||||
m_excerpt = nullptr;
|
||||
}
|
||||
|
||||
Ms::Excerpt* ExcerptNotation::excerpt() const
|
||||
{
|
||||
return m_excerpt;
|
||||
}
|
||||
|
|
|
@ -27,14 +27,18 @@ namespace Ms {
|
|||
class Score;
|
||||
}
|
||||
|
||||
namespace mu {
|
||||
namespace notation {
|
||||
namespace mu::notation {
|
||||
class ExcerptNotation : public IExcerptNotation, public Notation
|
||||
{
|
||||
public:
|
||||
explicit ExcerptNotation(Ms::Score* score);
|
||||
explicit ExcerptNotation(Ms::Excerpt* excerpt);
|
||||
~ExcerptNotation() override;
|
||||
|
||||
Ms::Excerpt* excerpt() const;
|
||||
|
||||
private:
|
||||
Ms::Excerpt* m_excerpt = nullptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MU_NOTATION_EXCERPTNOTATION_H
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "libmscore/keysig.h"
|
||||
#include "libmscore/rest.h"
|
||||
#include "libmscore/tempotext.h"
|
||||
#include "libmscore/undo.h"
|
||||
|
||||
#include "../notationerrors.h"
|
||||
|
||||
|
@ -80,8 +81,10 @@ mu::Ret MasterNotation::load(const io::path& path, const INotationReaderPtr& rea
|
|||
|
||||
MasterScore* score = new MasterScore(scoreGlobal()->baseStyle());
|
||||
Ret ret = doLoadScore(score, path, reader);
|
||||
|
||||
if (ret) {
|
||||
setScore(score);
|
||||
initExcerpts();
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -482,19 +485,93 @@ mu::Ret MasterNotation::createNew(const ScoreCreateOptions& scoreOptions)
|
|||
return make_ret(Err::NoError);
|
||||
}
|
||||
|
||||
void MasterNotation::initExcerpts()
|
||||
{
|
||||
MasterScore* master = masterScore();
|
||||
if (!master) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (master->excerpts().isEmpty()) {
|
||||
auto excerpts = Excerpt::createAllExcerpt(master);
|
||||
|
||||
for (Excerpt* excerpt : excerpts) {
|
||||
Score* score = new Score(excerpt->oscore());
|
||||
excerpt->setPartScore(score);
|
||||
score->style().set(Sid::createMultiMeasureRests, true);
|
||||
auto excerptCmdFake = new AddExcerpt(excerpt);
|
||||
excerptCmdFake->redo(nullptr);
|
||||
Excerpt::createExcerpt(excerpt);
|
||||
}
|
||||
}
|
||||
|
||||
for (Excerpt* excerpt: master->excerpts()) {
|
||||
m_excerpts.push_back(std::make_shared<ExcerptNotation>(excerpt));
|
||||
}
|
||||
|
||||
m_excerptsChanged.notify();
|
||||
}
|
||||
|
||||
std::vector<IExcerptNotationPtr> MasterNotation::excerpts() const
|
||||
{
|
||||
std::vector<IExcerptNotationPtr> result;
|
||||
|
||||
const MasterScore* master = masterScore();
|
||||
if (!master) {
|
||||
return result;
|
||||
}
|
||||
|
||||
for (const Excerpt* excerpt: master->excerpts()) {
|
||||
IExcerptNotationPtr part = std::make_shared<ExcerptNotation>(excerpt->partScore());
|
||||
result.push_back(part);
|
||||
for (auto excerpt: m_excerpts) {
|
||||
result.push_back(static_cast<IExcerptNotationPtr>(excerpt));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Notification MasterNotation::excerptsChanged() const
|
||||
{
|
||||
return m_excerptsChanged;
|
||||
}
|
||||
|
||||
IExcerptNotationPtr MasterNotation::appendExcerpt(const Meta& meta)
|
||||
{
|
||||
MasterScore* master = masterScore();
|
||||
if (!master) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Excerpt* excerpt = new Excerpt(master);
|
||||
excerpt->setPartScore(new Score(excerpt->oscore()));
|
||||
excerpt->setTitle(meta.title);
|
||||
Excerpt::createExcerpt(excerpt);
|
||||
|
||||
master->addExcerpt(excerpt);
|
||||
|
||||
std::shared_ptr<ExcerptNotation> excerptNotation = std::make_shared<ExcerptNotation>(excerpt);
|
||||
m_excerpts.push_back(excerptNotation);
|
||||
m_excerptsChanged.notify();
|
||||
|
||||
return excerptNotation;
|
||||
}
|
||||
|
||||
void MasterNotation::removeExcerpt(IExcerptNotationPtr excerpt)
|
||||
{
|
||||
MasterScore* master = masterScore();
|
||||
if (!master) {
|
||||
return;
|
||||
}
|
||||
|
||||
excerpt->setOpened(false);
|
||||
|
||||
for (size_t i = 0; i < m_excerpts.size(); ++i) {
|
||||
if (static_cast<IExcerptNotationPtr>(m_excerpts[i]) == excerpt) {
|
||||
master->deleteExcerpt(m_excerpts[i]->excerpt());
|
||||
m_excerpts.erase(m_excerpts.begin() + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
IDList partsIdList;
|
||||
for (const Part* part: excerpt->parts()->partList()) {
|
||||
partsIdList << part->id();
|
||||
}
|
||||
|
||||
parts()->removeParts(partsIdList);
|
||||
|
||||
m_excerptsChanged.notify();
|
||||
}
|
||||
|
|
|
@ -29,8 +29,8 @@ namespace Ms {
|
|||
class MasterScore;
|
||||
}
|
||||
|
||||
namespace mu {
|
||||
namespace notation {
|
||||
namespace mu::notation {
|
||||
class ExcerptNotation;
|
||||
class MasterNotation : public IMasterNotation, public Notation
|
||||
{
|
||||
INJECT(notation, INotationReadersRegister, readers)
|
||||
|
@ -46,6 +46,9 @@ public:
|
|||
Ret createNew(const ScoreCreateOptions& scoreOptions) override;
|
||||
|
||||
std::vector<IExcerptNotationPtr> excerpts() const override;
|
||||
async::Notification excerptsChanged() const override;
|
||||
IExcerptNotationPtr appendExcerpt(const Meta& meta) override;
|
||||
void removeExcerpt(IExcerptNotationPtr excerpt) override;
|
||||
|
||||
private:
|
||||
Ms::MasterScore* masterScore() const;
|
||||
|
@ -54,14 +57,19 @@ private:
|
|||
Ret doLoadScore(Ms::MasterScore* score, const io::path& path, const INotationReaderPtr& reader) const;
|
||||
mu::RetVal<Ms::MasterScore*> newScore(const ScoreCreateOptions& scoreInfo);
|
||||
|
||||
void initExcerpts();
|
||||
|
||||
void initParts(Ms::MasterScore* score, const QList<instruments::InstrumentTemplate>& instrumentTemplates);
|
||||
void initStaff(Ms::Staff* staff, const instruments::InstrumentTemplate& instrumentTemplate,const instruments::StaffType* staffType,
|
||||
int cidx);
|
||||
|
||||
Ms::Instrument instrumentFromTemplate(const instruments::InstrumentTemplate& instrumentTemplate) const;
|
||||
void numberInstrumentNames(Ms::MasterScore* score);
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<ExcerptNotation> > m_excerpts;
|
||||
async::Notification m_excerptsChanged;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MU_NOTATION_MASTERNOTATION_H
|
||||
|
|
|
@ -41,6 +41,7 @@ using namespace Ms;
|
|||
Notation::Notation(Score* score)
|
||||
{
|
||||
m_scoreGlobal = new MScore(); //! TODO May be static?
|
||||
m_opened.val = false;
|
||||
|
||||
m_interaction = new NotationInteraction(this);
|
||||
m_midiInput = new NotationMidiInput(this);
|
||||
|
@ -166,6 +167,20 @@ void Notation::paint(QPainter* painter)
|
|||
m_interaction->paint(painter);
|
||||
}
|
||||
|
||||
mu::ValCh<bool> Notation::opened() const
|
||||
{
|
||||
return m_opened;
|
||||
}
|
||||
|
||||
void Notation::setOpened(bool opened)
|
||||
{
|
||||
if (m_opened.val == opened) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_opened.set(opened);
|
||||
}
|
||||
|
||||
void Notation::notifyAboutNotationChanged()
|
||||
{
|
||||
m_notationChanged.notify();
|
||||
|
|
|
@ -48,6 +48,9 @@ public:
|
|||
void paint(QPainter* painter) override;
|
||||
QRectF previewRect() const override;
|
||||
|
||||
ValCh<bool> opened() const override;
|
||||
void setOpened(bool opened) override;
|
||||
|
||||
INotationInteraction* interaction() const override;
|
||||
|
||||
INotationMidiInput* midiInput() const override;
|
||||
|
@ -81,6 +84,7 @@ private:
|
|||
QSizeF m_viewSize;
|
||||
Ms::MScore* m_scoreGlobal = nullptr;
|
||||
Ms::Score* m_score = nullptr;
|
||||
ValCh<bool> m_opened;
|
||||
NotationInteraction* m_interaction = nullptr;
|
||||
INotationUndoStack* m_undoStackController = nullptr;
|
||||
INotationStyle* m_style = nullptr;
|
||||
|
|
|
@ -1272,14 +1272,16 @@ void NotationParts::sortParts(const IDList& instrumentIds)
|
|||
return part->instrument()->instrumentId();
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < instrumentIds.size(); i++) {
|
||||
Part* currentPart = score()->parts().at(i);
|
||||
for (int i = 0; i < instrumentIds.size(); ++i) {
|
||||
const Part* currentPart = score()->parts().at(i);
|
||||
|
||||
if (mainInstrumentId(currentPart) == instrumentIds.at(i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = i; j < score()->parts().size(); j++) {
|
||||
Part* part = score()->parts().at(j);
|
||||
for (int j = i; j < score()->parts().size(); ++j) {
|
||||
const Part* part = score()->parts().at(j);
|
||||
|
||||
if (mainInstrumentId(part) == instrumentIds.at(i)) {
|
||||
doMovePart(part->id(), currentPart->id());
|
||||
break;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Layouts 1.3
|
||||
|
||||
import MuseScore.UiComponents 1.0
|
||||
import MuseScore.Ui 1.0
|
||||
|
||||
|
@ -10,41 +11,41 @@ FlatRadioButton {
|
|||
|
||||
signal closeRequested()
|
||||
|
||||
width: 100
|
||||
normalStateColor: ui.theme.backgroundSecondaryColor
|
||||
hoverStateColor: selectedStateColor
|
||||
pressedStateColor: selectedStateColor
|
||||
selectedStateColor: ui.theme.backgroundPrimaryColor
|
||||
|
||||
width: 110
|
||||
radius: 0
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 4
|
||||
anchors.leftMargin: 12
|
||||
|
||||
StyledTextLabel {
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
|
||||
text: root.title
|
||||
font.pixelSize: 12
|
||||
}
|
||||
|
||||
Item {
|
||||
FlatButton {
|
||||
Layout.fillHeight: true
|
||||
Layout.topMargin: 1
|
||||
Layout.bottomMargin: 1
|
||||
Layout.preferredWidth: width
|
||||
Layout.alignment: Qt.AlignRight
|
||||
Layout.fillHeight: true
|
||||
Layout.minimumWidth: 16
|
||||
|
||||
StyledIconLabel {
|
||||
anchors.centerIn: parent
|
||||
iconCode: IconCode.CLOSE_X_ROUNDED
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: root.closeRequested()
|
||||
}
|
||||
normalStateColor: "transparent"
|
||||
icon: IconCode.CLOSE_X_ROUNDED
|
||||
onClicked: root.closeRequested()
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: 1
|
||||
|
||||
color: ui.theme.strokeColor
|
||||
}
|
||||
SeparatorLine { orientation: Qt.Vertical }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,25 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.2
|
||||
|
||||
import MuseScore.NotationScene 1.0
|
||||
import MuseScore.UiComponents 1.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property alias notationsCount: notationsView.count
|
||||
height: 32
|
||||
visible: notationsView.count > 0
|
||||
color: ui.theme.backgroundSecondaryColor
|
||||
|
||||
height: 30
|
||||
border.width: 1
|
||||
border.color: ui.theme.strokeColor
|
||||
|
||||
NotationSwitchListModel {
|
||||
id: notationSwitchModel
|
||||
|
||||
onCurrentNotationIndexChanged: {
|
||||
notationsView.currentIndex = index
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
|
@ -21,16 +29,18 @@ Rectangle {
|
|||
RadioButtonGroup {
|
||||
id: notationsView
|
||||
|
||||
width: contentWidth
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: 1
|
||||
|
||||
width: Math.min(contentWidth, parent.width)
|
||||
|
||||
model: notationSwitchModel
|
||||
currentIndex: 0
|
||||
spacing: 0
|
||||
|
||||
function setCurrentNotation(index) {
|
||||
currentIndex = index
|
||||
notationSwitchModel.setCurrentNotation(index)
|
||||
}
|
||||
interactive: width < contentWidth
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
delegate: NotationSwitchButton {
|
||||
id: button
|
||||
|
@ -50,7 +60,7 @@ Rectangle {
|
|||
}
|
||||
|
||||
onToggled: {
|
||||
notationsView.setCurrentNotation(model.index)
|
||||
notationSwitchModel.setCurrentNotation(model.index)
|
||||
}
|
||||
|
||||
onCloseRequested: {
|
||||
|
@ -61,7 +71,7 @@ Rectangle {
|
|||
|
||||
var index = button.resolveNextNotationIndex()
|
||||
notationSwitchModel.closeNotation(model.index)
|
||||
notationsView.setCurrentNotation(index)
|
||||
notationSwitchModel.setCurrentNotation(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,9 +8,10 @@ FocusScope {
|
|||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
spacing: 0
|
||||
|
||||
NotationSwitchPanel {
|
||||
Layout.fillWidth: true
|
||||
visible: notationsCount > 1
|
||||
}
|
||||
|
||||
NotationPaintView {
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
import QtQuick 2.9
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQml.Models 2.11
|
||||
|
||||
import MuseScore.Ui 1.0
|
||||
import MuseScore.UiComponents 1.0
|
||||
import MuseScore.NotationScene 1.0
|
||||
|
||||
QmlDialog {
|
||||
id: root
|
||||
|
||||
width: 600
|
||||
height: 370
|
||||
|
||||
|
@ -20,21 +24,24 @@ QmlDialog {
|
|||
id: partsModel
|
||||
}
|
||||
|
||||
ItemSelectionModel {
|
||||
id: selectionModel
|
||||
model: partsModel
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
partsModel.load()
|
||||
}
|
||||
|
||||
Column {
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 20
|
||||
|
||||
spacing: 30
|
||||
|
||||
Item {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
height: childrenRect.height
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: childrenRect.height
|
||||
|
||||
StyledTextLabel {
|
||||
anchors.left: parent.left
|
||||
|
@ -51,7 +58,9 @@ QmlDialog {
|
|||
anchors.rightMargin: 8
|
||||
|
||||
onClicked: {
|
||||
partsModel.apply()
|
||||
partsModel.createNewPart()
|
||||
root.hide()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,7 +72,8 @@ QmlDialog {
|
|||
icon: IconCode.DELETE_TANK
|
||||
|
||||
onClicked: {
|
||||
|
||||
partsModel.removeParts(selectionModel.selectedIndexes)
|
||||
selectionModel.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,8 +81,8 @@ QmlDialog {
|
|||
ListView {
|
||||
id: view
|
||||
|
||||
height: 200
|
||||
width: parent.width
|
||||
Layout.preferredHeight: 200
|
||||
Layout.fillWidth: true
|
||||
|
||||
spacing: 0
|
||||
|
||||
|
@ -129,15 +139,34 @@ QmlDialog {
|
|||
|
||||
SeparatorLine { anchors.bottom: parent.bottom }
|
||||
|
||||
property bool selected: false
|
||||
|
||||
Connections {
|
||||
target: selectionModel
|
||||
|
||||
function onHasSelectionChanged() {
|
||||
if (!selectionModel.hasSelection) {
|
||||
selected = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
onClicked: {
|
||||
var index = partsModel.index(model.row, 0)
|
||||
selectionModel.select(index, ItemSelectionModel.Select)
|
||||
selected = !selected
|
||||
}
|
||||
}
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "SELECTED"
|
||||
when: mouseArea.pressed
|
||||
when: selected
|
||||
|
||||
PropertyChanges {
|
||||
target: partRect
|
||||
|
@ -149,13 +178,28 @@ QmlDialog {
|
|||
}
|
||||
}
|
||||
|
||||
FlatButton {
|
||||
anchors.right: parent.right
|
||||
Row {
|
||||
Layout.preferredHeight: childrenRect.height
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
||||
text: qsTrc("notation", "Open all parts")
|
||||
spacing: 16
|
||||
|
||||
onClicked: {
|
||||
partsModel.openAllParts()
|
||||
FlatButton {
|
||||
text: qsTrc("notation", "Cancel")
|
||||
|
||||
onClicked: {
|
||||
root.reject()
|
||||
}
|
||||
}
|
||||
|
||||
FlatButton {
|
||||
text: qsTrc("notation", "Open")
|
||||
|
||||
onClicked: {
|
||||
partsModel.apply()
|
||||
partsModel.openParts(selectionModel.selectedIndexes)
|
||||
root.hide()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,29 +31,75 @@ NotationSwitchListModel::NotationSwitchListModel(QObject* parent)
|
|||
|
||||
void NotationSwitchListModel::load()
|
||||
{
|
||||
updateNotations();
|
||||
loadNotations();
|
||||
|
||||
globalContext()->currentMasterNotationChanged().onNotify(this, [this]() {
|
||||
updateNotations();
|
||||
context()->currentMasterNotationChanged().onNotify(this, [this]() {
|
||||
loadNotations();
|
||||
|
||||
if (!masterNotation()) {
|
||||
return;
|
||||
}
|
||||
|
||||
masterNotation()->excerptsChanged().onNotify(this, [this]() {
|
||||
loadNotations();
|
||||
});
|
||||
});
|
||||
|
||||
context()->currentNotationChanged().onNotify(this, [this]() {
|
||||
INotationPtr notation = context()->currentNotation();
|
||||
if (!notation) {
|
||||
return;
|
||||
}
|
||||
|
||||
int currentNotationIndex = m_notations.indexOf(notation);
|
||||
emit currentNotationIndexChanged(currentNotationIndex);
|
||||
});
|
||||
}
|
||||
|
||||
void NotationSwitchListModel::updateNotations()
|
||||
void NotationSwitchListModel::loadNotations()
|
||||
{
|
||||
IMasterNotationPtr masterNotation = globalContext()->currentMasterNotation();
|
||||
|
||||
beginResetModel();
|
||||
m_notations.clear();
|
||||
|
||||
if (masterNotation) {
|
||||
std::vector<IExcerptNotationPtr> excerpts = masterNotation->excerpts();
|
||||
m_notations.push_back(masterNotation);
|
||||
m_notations.insert(m_notations.end(), excerpts.begin(), excerpts.end());
|
||||
if (!masterNotation()) {
|
||||
endResetModel();
|
||||
return;
|
||||
}
|
||||
|
||||
m_notations << masterNotation();
|
||||
|
||||
for (IExcerptNotationPtr excerpt: masterNotation()->excerpts()) {
|
||||
if (excerpt->opened().val) {
|
||||
m_notations << excerpt;
|
||||
}
|
||||
|
||||
listenNotationOpeningStatus(excerpt);
|
||||
}
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void NotationSwitchListModel::listenNotationOpeningStatus(INotationPtr notation)
|
||||
{
|
||||
notation->opened().ch.onReceive(this, [this, notation](bool opened) {
|
||||
if (opened) {
|
||||
beginInsertRows(QModelIndex(), m_notations.size(), m_notations.size());
|
||||
m_notations << notation;
|
||||
endInsertRows();
|
||||
} else {
|
||||
int notationIndex = m_notations.indexOf(notation);
|
||||
beginRemoveRows(QModelIndex(), notationIndex, notationIndex);
|
||||
m_notations.removeAt(notationIndex);
|
||||
endRemoveRows();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
IMasterNotationPtr NotationSwitchListModel::masterNotation() const
|
||||
{
|
||||
return context()->currentMasterNotation();
|
||||
}
|
||||
|
||||
QVariant NotationSwitchListModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
if (!index.isValid()) {
|
||||
|
@ -86,7 +132,7 @@ void NotationSwitchListModel::setCurrentNotation(int index)
|
|||
return;
|
||||
}
|
||||
|
||||
globalContext()->setCurrentNotation(m_notations[index]);
|
||||
context()->setCurrentNotation(m_notations[index]);
|
||||
}
|
||||
|
||||
void NotationSwitchListModel::closeNotation(int index)
|
||||
|
@ -95,18 +141,16 @@ void NotationSwitchListModel::closeNotation(int index)
|
|||
return;
|
||||
}
|
||||
|
||||
if (globalContext()->currentNotation() == m_notations[index]) {
|
||||
globalContext()->setCurrentNotation(nullptr);
|
||||
INotationPtr notation = m_notations[index];
|
||||
|
||||
if (context()->currentNotation() == notation) {
|
||||
context()->setCurrentNotation(nullptr);
|
||||
}
|
||||
|
||||
beginRemoveRows(QModelIndex(), index, index);
|
||||
|
||||
m_notations.erase(m_notations.begin() + index);
|
||||
|
||||
endRemoveRows();
|
||||
notation->setOpened(false);
|
||||
}
|
||||
|
||||
bool NotationSwitchListModel::isIndexValid(int index) const
|
||||
{
|
||||
return index >= 0 && index < static_cast<int>(m_notations.size());
|
||||
return index >= 0 && index < m_notations.size();
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ class NotationSwitchListModel : public QAbstractListModel, public async::Asyncab
|
|||
{
|
||||
Q_OBJECT
|
||||
|
||||
INJECT(notation, context::IGlobalContext, globalContext)
|
||||
INJECT(notation, context::IGlobalContext, context)
|
||||
|
||||
public:
|
||||
explicit NotationSwitchListModel(QObject* parent = nullptr);
|
||||
|
@ -46,15 +46,21 @@ public:
|
|||
Q_INVOKABLE void setCurrentNotation(int index);
|
||||
Q_INVOKABLE void closeNotation(int index);
|
||||
|
||||
signals:
|
||||
void currentNotationIndexChanged(int index);
|
||||
|
||||
private:
|
||||
void updateNotations();
|
||||
IMasterNotationPtr masterNotation() const;
|
||||
|
||||
void loadNotations();
|
||||
void listenNotationOpeningStatus(INotationPtr notation);
|
||||
bool isIndexValid(int index) const;
|
||||
|
||||
enum Roles {
|
||||
RoleTitle = Qt::UserRole + 1,
|
||||
};
|
||||
|
||||
std::vector<INotationPtr> m_notations;
|
||||
QList<INotationPtr> m_notations;
|
||||
QHash<int, QByteArray> m_roles;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
|
||||
#include "partlistmodel.h"
|
||||
|
||||
#include "iexcerptnotation.h"
|
||||
|
||||
#include "log.h"
|
||||
#include "translation.h"
|
||||
|
||||
using namespace mu::notation;
|
||||
|
||||
|
@ -33,14 +36,7 @@ void PartListModel::load()
|
|||
{
|
||||
beginResetModel();
|
||||
|
||||
m_partsTitles = QStringList {
|
||||
"Main Score",
|
||||
"Flute",
|
||||
"Bassoon",
|
||||
"Horn in F",
|
||||
"Trumpet",
|
||||
"Piano"
|
||||
};
|
||||
m_excerpts = masterNotation()->excerpts();
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
@ -53,7 +49,7 @@ QVariant PartListModel::data(const QModelIndex& index, int role) const
|
|||
|
||||
switch (role) {
|
||||
case RoleTitle:
|
||||
return m_partsTitles[index.row()];
|
||||
return m_excerpts[index.row()]->metaInfo().title;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
|
@ -61,7 +57,7 @@ QVariant PartListModel::data(const QModelIndex& index, int role) const
|
|||
|
||||
int PartListModel::rowCount(const QModelIndex&) const
|
||||
{
|
||||
return m_partsTitles.count();
|
||||
return m_excerpts.size();
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> PartListModel::roleNames() const
|
||||
|
@ -71,16 +67,46 @@ QHash<int, QByteArray> PartListModel::roleNames() const
|
|||
|
||||
void PartListModel::createNewPart()
|
||||
{
|
||||
NOT_IMPLEMENTED;
|
||||
Meta meta;
|
||||
meta.title = qtrc("notation", "Part");
|
||||
|
||||
IExcerptNotationPtr excerpt = masterNotation()->appendExcerpt(meta);
|
||||
excerpt->setOpened(true);
|
||||
context()->setCurrentNotation(excerpt);
|
||||
}
|
||||
|
||||
void PartListModel::openPart(int index)
|
||||
void PartListModel::removeParts(const QModelIndexList& indexes)
|
||||
{
|
||||
Q_UNUSED(index)
|
||||
NOT_IMPLEMENTED;
|
||||
for (const QModelIndex& index: indexes) {
|
||||
int row = index.row();
|
||||
beginRemoveRows(QModelIndex(), row, row);
|
||||
m_excerptsToRemove.push_back(m_excerpts[row]);
|
||||
m_excerpts.erase(m_excerpts.begin() + row);
|
||||
endRemoveRows();
|
||||
}
|
||||
}
|
||||
|
||||
void PartListModel::openAllParts()
|
||||
void PartListModel::openParts(const QModelIndexList& indexes)
|
||||
{
|
||||
NOT_IMPLEMENTED;
|
||||
if (indexes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const QModelIndex& index: indexes) {
|
||||
m_excerpts[index.row()]->setOpened(true);
|
||||
}
|
||||
|
||||
context()->setCurrentNotation(m_excerpts[indexes.last().row()]);
|
||||
}
|
||||
|
||||
void PartListModel::apply()
|
||||
{
|
||||
for (IExcerptNotationPtr excerpt: m_excerptsToRemove) {
|
||||
masterNotation()->removeExcerpt(excerpt);
|
||||
}
|
||||
}
|
||||
|
||||
IMasterNotationPtr PartListModel::masterNotation() const
|
||||
{
|
||||
return context()->currentMasterNotation();
|
||||
}
|
||||
|
|
|
@ -22,11 +22,17 @@
|
|||
|
||||
#include <QAbstractListModel>
|
||||
|
||||
#include "modularity/ioc.h"
|
||||
#include "context/iglobalcontext.h"
|
||||
#include "iexcerptnotation.h"
|
||||
|
||||
namespace mu::notation {
|
||||
class PartListModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
INJECT(notation, context::IGlobalContext, context)
|
||||
|
||||
public:
|
||||
explicit PartListModel(QObject* parent = nullptr);
|
||||
|
||||
|
@ -35,17 +41,21 @@ public:
|
|||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
Q_INVOKABLE void load();
|
||||
Q_INVOKABLE void createNewPart();
|
||||
Q_INVOKABLE void openPart(int index);
|
||||
Q_INVOKABLE void openAllParts();
|
||||
Q_INVOKABLE void createNewPart();
|
||||
Q_INVOKABLE void removeParts(const QModelIndexList& indexes);
|
||||
Q_INVOKABLE void openParts(const QModelIndexList& indexes);
|
||||
Q_INVOKABLE void apply();
|
||||
|
||||
private:
|
||||
IMasterNotationPtr masterNotation() const;
|
||||
|
||||
enum Roles {
|
||||
RoleTitle = Qt::UserRole + 1,
|
||||
};
|
||||
|
||||
QHash<int, QByteArray> m_roles;
|
||||
QStringList m_partsTitles;
|
||||
std::vector<IExcerptNotationPtr> m_excerpts;
|
||||
std::vector<IExcerptNotationPtr> m_excerptsToRemove;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue