Skip to content

Commit 2acc8ba

Browse files
committed
Update tempo editing and display
1 parent bb603a0 commit 2acc8ba

File tree

14 files changed

+242
-39
lines changed

14 files changed

+242
-39
lines changed

src/libs/application/uishell/src/qml/TempoTimeSignatureIndicator.qml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ Item {
3434
component IndicatorToolButton: ToolButton {
3535
font.family: Theme.font.family
3636
font.pixelSize: 16
37+
implicitWidth: Math.max(control.backgroundVisible ? 54 : 0, implicitContentWidth + 16)
3738
implicitHeight: 24
3839
leftPadding: 12
3940
rightPadding: 12

src/plugins/coreplugin/project/EditTempoTimeSignatureScenario.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ namespace Core {
156156
}
157157
d->document->transactionController()->beginScopedTransaction(tr("Editing tempo"), [=] {
158158
auto tempoSequence = d->document->model()->timeline()->tempos();
159-
auto currentTempos = tempoSequence->slice(position, position + 1);
159+
auto currentTempos = tempoSequence->slice(position, 1);
160160
dspx::Tempo *tempoItem;
161161
if (currentTempos.isEmpty()) {
162162
qCDebug(lcEditTempoTimeSignatureScenario) << "Current tempos is empty";
@@ -225,7 +225,7 @@ namespace Core {
225225
}
226226
d->document->transactionController()->beginScopedTransaction(tr("Editing time signature"), [=] {
227227
auto timeSignatureSequence = d->document->model()->timeline()->timeSignatures();
228-
auto currentTimeSignatures = timeSignatureSequence->slice(measure, measure + 1);
228+
auto currentTimeSignatures = timeSignatureSequence->slice(measure, 1);
229229
dspx::TimeSignature *timeSignatureItem;
230230
if (currentTimeSignatures.isEmpty()) {
231231
qCDebug(lcEditTempoTimeSignatureScenario()) << "Current time signatures is empty";

src/plugins/visualeditor/core/ArrangementPanelInterface.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,10 @@ namespace VisualEditor {
152152
d->bindTimelineInteractionController();
153153
d->bindScrollBehaviorViewModel();
154154
d->bindPositionAlignmentManipulator();
155+
156+
connect(Internal::EditorPreference::instance(), &Internal::EditorPreference::trackCursorPositionChanged, this, [=, this] {
157+
setMouseTrackingDisabled(!Internal::EditorPreference::trackCursorPosition());
158+
});
155159
}
156160

157161
ArrangementPanelInterface::~ArrangementPanelInterface() = default;
@@ -226,6 +230,17 @@ namespace VisualEditor {
226230
Q_EMIT snapTemporarilyDisabledChanged();
227231
}
228232
}
233+
bool ArrangementPanelInterface::isMouseTrackingDisabled() const {
234+
Q_D(const ArrangementPanelInterface);
235+
return d->isMouseTrackingDisabled;
236+
}
237+
void ArrangementPanelInterface::setMouseTrackingDisabled(bool disabled) {
238+
Q_D(ArrangementPanelInterface);
239+
if (d->isMouseTrackingDisabled != disabled) {
240+
d->isMouseTrackingDisabled = disabled;
241+
Q_EMIT mouseTrackingDisabledChanged();
242+
}
243+
}
229244

230245
}
231246

src/plugins/visualeditor/core/ArrangementPanelInterface.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ namespace VisualEditor {
4747
Q_PROPERTY(QQuickItem *arrangementView READ arrangementView CONSTANT)
4848
Q_PROPERTY(Tool tool READ tool WRITE setTool NOTIFY toolChanged)
4949
Q_PROPERTY(bool snapTemporarilyDisabled READ isSnapTemporarilyDisabled WRITE setSnapTemporarilyDisabled NOTIFY snapTemporarilyDisabledChanged)
50+
Q_PROPERTY(bool mouseTrackingDisabled READ isMouseTrackingDisabled WRITE setMouseTrackingDisabled NOTIFY mouseTrackingDisabledChanged)
5051

5152
public:
5253
~ArrangementPanelInterface() override;
@@ -78,9 +79,13 @@ namespace VisualEditor {
7879
bool isSnapTemporarilyDisabled() const;
7980
void setSnapTemporarilyDisabled(bool disabled);
8081

82+
bool isMouseTrackingDisabled() const;
83+
void setMouseTrackingDisabled(bool disabled);
84+
8185
Q_SIGNALS:
8286
void toolChanged();
8387
void snapTemporarilyDisabledChanged();
88+
void mouseTrackingDisabledChanged();
8489

8590
private:
8691
friend class Internal::ArrangementAddOn;

src/plugins/visualeditor/core/ArrangementPanelInterface_p.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ namespace VisualEditor {
2828

2929
ArrangementPanelInterface::Tool tool{ArrangementPanelInterface::PointerTool};
3030
bool isSnapTemporarilyDisabled{false};
31+
bool isMouseTrackingDisabled{false};
3132

3233
mutable PositionAlignmentManipulator::Duration previousDuration{};
3334

src/plugins/visualeditor/core/TempoViewModelContextData.cpp

Lines changed: 86 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -91,50 +91,62 @@ namespace VisualEditor {
9191

9292
tempoSelectionController = new TempoSelectionController(q);
9393

94-
stateMachine = new QStateMachine(q);
94+
stateMachine = new QStateMachine(QState::ExclusiveStates, q);
9595
idleState = new QState;
96+
movePendingState = new QState;
9697
movingState = new QState;
9798
rubberBandDraggingState = new QState;
9899
stateMachine->addState(idleState);
100+
stateMachine->addState(movePendingState);
99101
stateMachine->addState(movingState);
100102
stateMachine->addState(rubberBandDraggingState);
101103
stateMachine->setInitialState(idleState);
102104
stateMachine->start();
103105

104-
QObject::connect(movingState, &QState::exited, q, [=, this] {
105-
QSet<dspx::Tempo *> updatedItems;
106-
for (auto viewItem : transactionalUpdatedTempos) {
107-
auto item = tempoDocumentItemMap.value(viewItem);
108-
Q_ASSERT(item);
109-
item->setPos(viewItem->position());
110-
updatedItems.insert(item);
111-
}
112-
transactionalUpdatedTempos.clear();
113-
for (auto item : updatedItems) {
114-
auto overlappingItems = tempoSequence->slice(item->pos(), item->pos() + 1);
115-
for (auto overlappingItem : overlappingItems) {
116-
if (updatedItems.contains(overlappingItem))
117-
continue;
118-
tempoSequence->removeItem(overlappingItem);
119-
q->windowHandle()->projectDocumentContext()->document()->model()->destroyItem(overlappingItem);
120-
}
121-
}
106+
movePendingState->addTransition(this, &TempoViewModelContextData::transactionStarted, movingState);
107+
movePendingState->addTransition(this, &TempoViewModelContextData::transactionNotStarted, idleState);
108+
109+
connect(idleState, &QState::entered, q, [=, this] {
110+
qCInfo(lcTempoViewModelContextData) << "Idle state entered";
111+
});
112+
connect(idleState, &QState::exited, q, [=, this] {
113+
qCInfo(lcTempoViewModelContextData) << "Idle state exited";
114+
});
115+
connect(movePendingState, &QState::entered, q, [=, this] {
116+
qCInfo(lcTempoViewModelContextData) << "Move pending state entered";
117+
handleMovePendingStateEntered();
118+
});
119+
connect(movePendingState, &QState::exited, q, [=, this] {
120+
qCInfo(lcTempoViewModelContextData) << "Move pending state exited";
121+
});
122+
connect(movingState, &QState::entered, q, [=, this] {
123+
qCInfo(lcTempoViewModelContextData) << "Moving state entered";
124+
});
125+
connect(movingState, &QState::exited, q, [=, this] {
126+
qCInfo(lcTempoViewModelContextData) << "Moving state exited";
127+
handleMovingStateExited();
128+
});
129+
connect(rubberBandDraggingState, &QState::entered, q, [=, this] {
130+
qCInfo(lcTempoViewModelContextData) << "Rubber band dragging state entered";
131+
});
132+
connect(rubberBandDraggingState, &QState::exited, q, [=, this] {
133+
qCInfo(lcTempoViewModelContextData) << "Rubber band dragging state exited";
122134
});
123135
}
124136

125137
void TempoViewModelContextData::bindTempoSequenceViewModel() {
126138
Q_Q(ProjectViewModelContext);
127-
QObject::connect(tempoSequence, &dspx::TempoSequence::itemInserted, tempoSequenceViewModel, [=, this](dspx::Tempo *item) {
139+
connect(tempoSequence, &dspx::TempoSequence::itemInserted, tempoSequenceViewModel, [=, this](dspx::Tempo *item) {
128140
bindTempoDocumentItem(item);
129141
});
130-
QObject::connect(tempoSequence, &dspx::TempoSequence::itemRemoved, tempoSequenceViewModel, [=, this](dspx::Tempo *item) {
142+
connect(tempoSequence, &dspx::TempoSequence::itemRemoved, tempoSequenceViewModel, [=, this](dspx::Tempo *item) {
131143
unbindTempoDocumentItem(item);
132144
});
133145
// For tempo sequence, item will never be inserted or removed from view
134146
for (auto item : tempoSequence->asRange()) {
135147
bindTempoDocumentItem(item);
136148
}
137-
QObject::connect(tempoSelectionModel, &dspx::TempoSelectionModel::itemSelected, q, [=, this](dspx::Tempo *item, bool selected) {
149+
connect(tempoSelectionModel, &dspx::TempoSelectionModel::itemSelected, q, [=, this](dspx::Tempo *item, bool selected) {
138150
qCDebug(lcTempoViewModelContextData) << "Tempo item selected" << item << selected;
139151
auto viewItem = tempoViewItemMap.value(item);
140152
Q_ASSERT(viewItem);
@@ -151,30 +163,31 @@ namespace VisualEditor {
151163
tempoDocumentItemMap.insert(viewItem, item);
152164
qCDebug(lcTempoViewModelContextData) << "Tempo item inserted" << item << viewItem << item->pos() << item->value();
153165

154-
QObject::connect(item, &dspx::Tempo::posChanged, viewItem, [=] {
166+
connect(item, &dspx::Tempo::posChanged, viewItem, [=] {
155167
if (viewItem->position() == item->pos())
156168
return;
157169
qCDebug(lcTempoViewModelContextData) << "Tempo item pos updated" << item << item->pos();
158170
viewItem->setPosition(item->pos());
159171
});
160-
QObject::connect(item, &dspx::Tempo::valueChanged, viewItem, [=] {
172+
connect(item, &dspx::Tempo::valueChanged, viewItem, [=] {
161173
qCDebug(lcTempoViewModelContextData) << "Tempo item value updated" << item << item->value();
162-
viewItem->setContent(QLocale().toString(item->value(), 'f', 2));
174+
viewItem->setContent(QLocale().toString(item->value()));
163175
});
164176
viewItem->setPosition(item->pos());
165-
viewItem->setContent(QLocale().toString(item->value(), 'f', 2));
177+
viewItem->setContent(QLocale().toString(item->value()));
166178

167-
QObject::connect(viewItem, &sflow::LabelViewModel::positionChanged, item, [=] {
179+
connect(viewItem, &sflow::LabelViewModel::positionChanged, item, [=] {
168180
if (viewItem->position() == item->pos())
169181
return;
170182
if (item->pos() == 0) {
171-
viewItem->setPosition(0);
183+
viewItem->setPosition(item->pos());
172184
return;
173185
}
174-
qCDebug(lcTempoViewModelContextData) << "Tempo view item pos updated" << viewItem << viewItem->position();
175186
if (!stateMachine->configuration().contains(movingState)) {
176-
qCWarning(lcTempoViewModelContextData) << "Suspicious tempo view updating: moving state not entered";
187+
viewItem->setPosition(item->pos());
188+
return;
177189
}
190+
qCDebug(lcTempoViewModelContextData) << "Tempo view item pos updated" << viewItem << viewItem->position();
178191
transactionalUpdatedTempos.insert(viewItem);
179192
});
180193

@@ -190,8 +203,8 @@ namespace VisualEditor {
190203
tempoViewItemMap.remove(item);
191204
qCDebug(lcTempoViewModelContextData) << "Tempo item removed" << item << viewItem;
192205

193-
QObject::disconnect(item, nullptr, viewItem, nullptr);
194-
QObject::disconnect(viewItem, nullptr, item, nullptr);
206+
disconnect(item, nullptr, viewItem, nullptr);
207+
disconnect(viewItem, nullptr, item, nullptr);
195208

196209
transactionalUpdatedTempos.remove(viewItem);
197210

@@ -243,7 +256,7 @@ namespace VisualEditor {
243256
controller->setInteraction(sflow::LabelSequenceInteractionController::SelectByRubberBand);
244257
controller->setItemInteraction(sflow::LabelSequenceInteractionController::Move | sflow::LabelSequenceInteractionController::Select);
245258
auto moveStartTransition = new ItemInteractionSignalTransition(controller, sflow::LabelSequenceInteractionController::Move, &sflow::LabelSequenceInteractionController::itemInteractionOperationStarted);
246-
moveStartTransition->setTargetState(movingState);
259+
moveStartTransition->setTargetState(movePendingState);
247260
idleState->addTransition(moveStartTransition);
248261
auto moveFinishTransition = new ItemInteractionSignalTransition(controller, sflow::LabelSequenceInteractionController::Move, &sflow::LabelSequenceInteractionController::itemInteractionOperationFinished);
249262
moveFinishTransition->setTargetState(idleState);
@@ -254,7 +267,7 @@ namespace VisualEditor {
254267
auto rubberBandDragFinishTransition = new InteractionSignalTransition(controller, sflow::LabelSequenceInteractionController::SelectByRubberBand, &sflow::LabelSequenceInteractionController::interactionOperationFinished);
255268
rubberBandDragFinishTransition->setTargetState(idleState);
256269
rubberBandDraggingState->addTransition(rubberBandDragFinishTransition);
257-
QObject::connect(controller, &QObject::destroyed, [=] {
270+
connect(controller, &QObject::destroyed, [=] {
258271
idleState->removeTransition(moveStartTransition);
259272
idleState->removeTransition(rubberBandDragStartTransition);
260273
movingState->removeTransition(moveFinishTransition);
@@ -263,4 +276,43 @@ namespace VisualEditor {
263276
return controller;
264277
}
265278

279+
void TempoViewModelContextData::handleMovePendingStateEntered() {
280+
Q_Q(ProjectViewModelContext);
281+
for (auto item : tempoSelectionModel->selectedItems()) {
282+
if (item->pos() == 0) {
283+
// Not allowed to move tempo to position 0
284+
Q_EMIT transactionNotStarted();
285+
return;
286+
}
287+
}
288+
moveTransactionId = q->windowHandle()->projectDocumentContext()->document()->transactionController()->beginTransaction();
289+
if (moveTransactionId != Core::TransactionController::TransactionId::Invalid) {
290+
Q_EMIT transactionStarted();
291+
} else {
292+
Q_EMIT transactionNotStarted();
293+
}
294+
}
295+
296+
void TempoViewModelContextData::handleMovingStateExited() {
297+
Q_Q(ProjectViewModelContext);
298+
QSet<dspx::Tempo *> updatedItems;
299+
for (auto viewItem : transactionalUpdatedTempos) {
300+
auto item = tempoDocumentItemMap.value(viewItem);
301+
Q_ASSERT(item);
302+
item->setPos(viewItem->position());
303+
updatedItems.insert(item);
304+
}
305+
transactionalUpdatedTempos.clear();
306+
for (auto item : updatedItems) {
307+
auto overlappingItems = tempoSequence->slice(item->pos(), 1);
308+
for (auto overlappingItem : overlappingItems) {
309+
if (updatedItems.contains(overlappingItem))
310+
continue;
311+
tempoSequence->removeItem(overlappingItem);
312+
q->windowHandle()->projectDocumentContext()->document()->model()->destroyItem(overlappingItem);
313+
}
314+
}
315+
q->windowHandle()->projectDocumentContext()->document()->transactionController()->commitTransaction(moveTransactionId, tr("Moving tempo"));
316+
}
317+
266318
}

src/plugins/visualeditor/core/TempoViewModelContextData_p.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
#include <ScopicFlowCore/SelectionController.h>
88

9+
#include <transactional/TransactionController.h>
10+
911
#include <visualeditor/ProjectViewModelContext.h>
1012

1113
class QStateMachine;
@@ -37,7 +39,8 @@ namespace VisualEditor {
3739
dspx::TempoSelectionModel *tempoSelectionModel;
3840
};
3941

40-
class TempoViewModelContextData {
42+
class TempoViewModelContextData : public QObject {
43+
Q_OBJECT
4144
Q_DECLARE_PUBLIC(ProjectViewModelContext)
4245
public:
4346
ProjectViewModelContext *q_ptr;
@@ -55,14 +58,24 @@ namespace VisualEditor {
5558

5659
QStateMachine *stateMachine;
5760
QState *idleState;
61+
QState *movePendingState;
5862
QState *movingState;
5963
QState *rubberBandDraggingState;
6064

65+
Core::TransactionController::TransactionId moveTransactionId{};
66+
6167
void init();
6268
void bindTempoSequenceViewModel();
6369
void bindTempoDocumentItem(dspx::Tempo *item);
6470
void unbindTempoDocumentItem(dspx::Tempo *item);
6571
sflow::LabelSequenceInteractionController *createController(QObject *parent);
72+
73+
void handleMovePendingStateEntered();
74+
void handleMovingStateExited();
75+
76+
Q_SIGNALS:
77+
void transactionStarted();
78+
void transactionNotStarted();
6679
};
6780

6881
}

src/plugins/visualeditor/internal/EditorPreference.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ namespace VisualEditor::Internal {
1717
bool middleButtonAutoScroll{};
1818
int autoDurationPositionAlignment{48};
1919
bool enableTemporarySnapOff{true};
20+
bool trackCursorPosition{true};
2021
};
2122

2223
static EditorPreference *m_instance = nullptr;
@@ -163,5 +164,16 @@ namespace VisualEditor::Internal {
163164
d->enableTemporarySnapOff = enableTemporarySnapOff;
164165
emit m_instance->enableTemporarySnapOffChanged();
165166
}
167+
bool EditorPreference::trackCursorPosition() {
168+
M_INSTANCE_D;
169+
return d->trackCursorPosition;
170+
}
171+
void EditorPreference::setTrackCursorPosition(bool trackCursorPosition) {
172+
M_INSTANCE_D;
173+
if (d->trackCursorPosition == trackCursorPosition)
174+
return;
175+
d->trackCursorPosition = trackCursorPosition;
176+
emit m_instance->trackCursorPositionChanged();
177+
}
166178

167-
}
179+
}

src/plugins/visualeditor/internal/EditorPreference.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ namespace VisualEditor::Internal {
2626
Q_PROPERTY(bool middleButtonAutoScroll READ middleButtonAutoScroll WRITE setMiddleButtonAutoScroll NOTIFY middleButtonAutoScrollChanged)
2727
Q_PROPERTY(int autoDurationPositionAlignment READ autoDurationPositionAlignment WRITE setAutoDurationPositionAlignment NOTIFY autoDurationPositionAlignmentChanged)
2828
Q_PROPERTY(bool enableTemporarySnapOff READ enableTemporarySnapOff WRITE setEnableTemporarySnapOff NOTIFY enableTemporarySnapOffChanged)
29+
Q_PROPERTY(bool trackCursorPosition READ trackCursorPosition WRITE setTrackCursorPosition NOTIFY trackCursorPositionChanged)
2930

3031
public:
3132
~EditorPreference() override;
@@ -67,6 +68,9 @@ namespace VisualEditor::Internal {
6768
static bool enableTemporarySnapOff();
6869
static void setEnableTemporarySnapOff(bool enableTemporarySnapOff);
6970

71+
static bool trackCursorPosition();
72+
static void setTrackCursorPosition(bool trackCursorPosition);
73+
7074
Q_SIGNALS:
7175
void alternateAxisModifierChanged();
7276
void zoomModifierChanged();
@@ -75,6 +79,7 @@ namespace VisualEditor::Internal {
7579
void middleButtonAutoScrollChanged();
7680
void autoDurationPositionAlignmentChanged();
7781
void enableTemporarySnapOffChanged();
82+
void trackCursorPositionChanged();
7883

7984
private:
8085
friend class VisualEditorPlugin;

0 commit comments

Comments
 (0)