@@ -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}
0 commit comments