Loading...
Searching...
No Matches
ScenarioCreation_FromState.hpp
1#pragma once
2#include "ScenarioCreationState.hpp"
3
4#include <Scenario/Application/ScenarioEditionSettings.hpp>
5#include <Scenario/Commands/Scenario/Creations/CreateInterval.hpp>
6#include <Scenario/Commands/Scenario/Creations/CreateState.hpp>
7#include <Scenario/Commands/Scenario/Displacement/MoveNewEvent.hpp>
8#include <Scenario/Commands/Scenario/Displacement/MoveNewState.hpp>
9#include <Scenario/Document/TimeSync/TimeSyncModel.hpp>
10#include <Scenario/Palette/Tools/ScenarioRollbackStrategy.hpp>
11#include <Scenario/Palette/Transitions/AnythingTransitions.hpp>
12#include <Scenario/Palette/Transitions/EventTransitions.hpp>
13#include <Scenario/Palette/Transitions/IntervalTransitions.hpp>
14#include <Scenario/Palette/Transitions/NothingTransitions.hpp>
15#include <Scenario/Palette/Transitions/StateTransitions.hpp>
16#include <Scenario/Palette/Transitions/TimeSyncTransitions.hpp>
17#include <Scenario/Process/Algorithms/Accessors.hpp>
18
19#include <QApplication>
20#include <QFinalState>
21
22namespace Scenario
23{
24template <typename Scenario_T, typename ToolPalette_T>
25class Creation_FromState final : public CreationState<Scenario_T, ToolPalette_T>
26{
27public:
29 const ToolPalette_T& stateMachine, const Scenario_T& scenarioPath,
30 const score::CommandStackFacade& stack, QState* parent)
31 : CreationState<Scenario_T, ToolPalette_T>{
32 stateMachine, stack, std::move(scenarioPath), parent}
33 {
34 using namespace Scenario::Command;
35 auto finalState = new QFinalState{this};
36 QObject::connect(finalState, &QState::entered, [&]() { this->clearCreatedIds(); });
37
38 auto mainState = new QState{this};
39 {
40 auto pressed = new QState{mainState};
41 auto released = new QState{mainState};
42 auto move_nothing = new StrongQState<MoveOnNothing>{mainState};
43 auto move_state = new StrongQState<MoveOnState>{mainState};
44 auto move_event = new StrongQState<MoveOnEvent>{mainState};
45 auto move_timesync = new StrongQState<MoveOnTimeSync>{mainState};
46
47 // General setup
48 mainState->setInitialState(pressed);
49 released->addTransition(finalState);
50
51 // Release
52 score::make_transition<ReleaseOnAnything_Transition>(mainState, released);
53
54 // Pressed -> ...
55 score::make_transition<MoveOnNothing_Transition<Scenario_T>>(
56 pressed, move_state, *this);
57 score::make_transition<MoveOnNothing_Transition<Scenario_T>>(
58 pressed, move_nothing, *this);
59
61 // MoveOnNothing -> MoveOnNothing.
62 score::make_transition<MoveOnNothing_Transition<Scenario_T>>(
63 move_nothing, move_nothing, *this);
64
65 // MoveOnNothing -> MoveOnState.
66 this->add_transition(move_nothing, move_state, [&]() {
67 this->rollback();
68 createToState();
69 });
70
71 // MoveOnNothing -> MoveOnEvent.
72 this->add_transition(move_nothing, move_event, [&]() {
73 this->rollback();
74 createToEvent();
75 });
76
77 // MoveOnNothing -> MoveOnTimeSync
78 this->add_transition(move_nothing, move_timesync, [&]() {
79 this->rollback();
80 createToTimeSync();
81 });
82
84 // MoveOnState -> MoveOnNothing
85 this->add_transition(move_state, move_nothing, [&]() {
86 this->rollback();
87 createToNothing();
88 });
89
90 // MoveOnState -> MoveOnState
91 // We don't do anything, the interval should not move.
92
93 // MoveOnState -> MoveOnEvent
94 this->add_transition(move_state, move_event, [&]() {
95 this->rollback();
96 createToEvent();
97 });
98
99 // MoveOnState -> MoveOnTimeSync
100 this->add_transition(move_state, move_timesync, [&]() {
101 this->rollback();
102 createToTimeSync();
103 });
104
106 // MoveOnEvent -> MoveOnNothing
107 this->add_transition(move_event, move_nothing, [&]() {
108 this->rollback();
109 createToNothing();
110 });
111
112 // MoveOnEvent -> MoveOnState
113 this->add_transition(move_event, move_state, [&]() {
114 if(this->clickedState && this->hoveredState)
115 {
116 if(this->m_parentSM.model().state(*this->clickedState).eventId()
117 != this->m_parentSM.model().state(*this->hoveredState).eventId())
118 {
119 this->rollback();
120 createToState();
121 }
122 }
123 });
124
125 // MoveOnEvent -> MoveOnEvent
126 score::make_transition<MoveOnEvent_Transition<Scenario_T>>(
127 move_event, move_event, *this);
128
129 // MoveOnEvent -> MoveOnTimeSync
130 this->add_transition(move_event, move_timesync, [&]() {
131 this->rollback();
132 createToTimeSync();
133 });
134
136 // MoveOnTimeSync -> MoveOnNothing
137 this->add_transition(move_timesync, move_nothing, [&]() {
138 this->rollback();
139 createToNothing();
140 });
141
142 // MoveOnTimeSync -> MoveOnState
143 this->add_transition(move_timesync, move_state, [&]() {
144 this->rollback();
145 createToState();
146 });
147
148 // MoveOnTimeSync -> MoveOnEvent
149 this->add_transition(move_timesync, move_event, [&]() {
150 this->rollback();
151 createToEvent();
152 });
153
154 // MoveOnTimeSync -> MoveOnTimeSync
155 score::make_transition<MoveOnTimeSync_Transition<Scenario_T>>(
156 move_timesync, move_timesync, *this);
157
158 // What happens in each state.
159 QObject::connect(pressed, &QState::entered, [&]() {
160 this->m_clickedPoint = this->currentPoint;
161 createToNothing();
162 });
163
164 QObject::connect(move_nothing, &QState::entered, [&]() {
165 if(this->createdIntervals.empty() || this->createdEvents.empty())
166 {
167 this->rollback();
168 createToNothing();
169 return;
170 }
171
172 Scenario::EditionSettings& settings = this->m_parentSM.editionSettings();
173 if(settings.tool() == Scenario::Tool::CreateGraph)
174 {
175 this->m_dispatcher.template submit<MoveNewEvent>(
176 this->m_scenario, this->createdIntervals.last(),
177 this->createdEvents.last(), this->currentPoint.date, this->currentPoint.y,
178 false);
179 return;
180 }
181
182 this->currentPoint.date = stateMachine.magnetic().getPosition(
183 &stateMachine.model(), this->currentPoint.date);
184
185 if(this->currentPoint.date <= this->m_clickedPoint.date)
186 {
187 this->currentPoint.date = this->m_clickedPoint.date + TimeVal::fromMsecs(10);
188 ;
189 }
190
191 auto sequence = settings.tool() == Tool::CreateSequence;
192 if(sequence)
193 {
194 if(this->clickedState)
195 {
196 const auto& st = this->m_parentSM.model().state(*this->clickedState);
197 this->currentPoint.y = st.heightPercentage();
198 }
199 }
200
201 this->m_dispatcher.template submit<MoveNewEvent>(
202 this->m_scenario, this->createdIntervals.last(), this->createdEvents.last(),
203 this->currentPoint.date, this->currentPoint.y, sequence);
204 });
205
206 QObject::connect(move_event, &QState::entered, [&]() {
207 if(this->createdStates.empty())
208 {
209 this->rollback();
210 createToEvent();
211 return;
212 }
213
214 if(this->currentPoint.date <= this->m_clickedPoint.date)
215 {
216 return;
217 }
218
219 this->m_dispatcher.template submit<MoveNewState>(
220 this->m_scenario, this->createdStates.last(), this->currentPoint.y);
221 });
222
223 QObject::connect(move_timesync, &QState::entered, [&]() {
224 if(this->createdStates.empty())
225 {
226 this->rollback();
227 createToTimeSync();
228 return;
229 }
230
231 if(this->currentPoint.date <= this->m_clickedPoint.date)
232 {
233 return;
234 }
235
236 this->m_dispatcher.template submit<MoveNewState>(
237 this->m_scenario, this->createdStates.last(), this->currentPoint.y);
238 });
239
240 QObject::connect(released, &QState::entered, this, &Creation_FromState::commit);
241 }
242
243 auto rollbackState = new QState{this};
244 score::make_transition<score::Cancel_Transition>(mainState, rollbackState);
245 rollbackState->addTransition(finalState);
246
247 QObject::connect(
248 rollbackState, &QState::entered, this, &Creation_FromState::rollback);
249 this->setInitialState(mainState);
250 }
251
252private:
253 template <typename Fun>
254 void creationCheck(Fun&& fun)
255 {
256 const auto& scenar = this->m_parentSM.model();
257 if(!this->clickedState)
258 return;
259 Scenario::EditionSettings& settings = this->m_parentSM.editionSettings();
260 const bool sequence = settings.tool() == Tool::CreateSequence;
261 const bool new_event = qApp->keyboardModifiers() & Qt::ALT;
262 const bool graph_interval = settings.tool() == Scenario::Tool::CreateGraph;
263 auto& st = scenar.state(*this->clickedState);
264 auto& ev = Scenario::parentEvent(st, scenar);
265 if(ev.date() > this->currentPoint.date && !graph_interval)
266 return;
267
268 if(new_event && !sequence)
269 {
270 // Create new event on the timesync
271 auto tn = ev.timeSync();
273 this->m_scenario, tn, this->currentPoint.y};
274 this->m_dispatcher.submit(cmd);
275
276 this->createdEvents.append(cmd->createdEvent());
277 this->createdStates.append(cmd->createdState());
278 fun(this->createdStates.first());
279 }
280 else
281 {
282 if(!sequence)
283 {
284 // Create new state on the event
285 auto cmd = new Scenario::Command::CreateState{
286 this->m_scenario, st.eventId(), this->currentPoint.y};
287 this->m_dispatcher.submit(cmd);
288
289 this->createdStates.append(cmd->createdState());
290 fun(this->createdStates.first());
291 }
292 else
293 {
294 if(!st.nextInterval()) // TODO & deltaY < deltaX
295 {
296 this->currentPoint.y = st.heightPercentage();
297 fun(*this->clickedState);
298 }
299 else
300 {
301 // Create new state on the event
302 auto cmd = new Scenario::Command::CreateState{
303 this->m_scenario, st.eventId(), this->currentPoint.y};
304 this->m_dispatcher.submit(cmd);
305
306 this->createdStates.append(cmd->createdState());
307 fun(this->createdStates.first());
308 // create a single state on the same event (deltaY > deltaX)
309 }
310 }
311 }
312 }
313
314 // Note : clickedEvent is set at startEvent if clicking in the background.
315 void createToNothing()
316 {
317 creationCheck([&](const Id<StateModel>& id) { this->createToNothing_base(id); });
318 }
319
320 void createToTimeSync()
321 {
322 creationCheck([&](const Id<StateModel>& id) { this->createToTimeSync_base(id); });
323 }
324
325 void createToEvent()
326 {
327 if(this->clickedState)
328 {
329 if(this->hoveredEvent
330 == this->m_parentSM.model().state(*this->clickedState).eventId())
331 {
332 creationCheck([&](const Id<StateModel>& id) {});
333 }
334 else
335 {
336 creationCheck([&](const Id<StateModel>& id) { this->createToEvent_base(id); });
337 }
338 }
339 }
340
341 void createToState()
342 {
343 if(this->hoveredState)
344 {
345 auto& st = this->m_parentSM.model().states.at(*this->hoveredState);
346 if(!st.previousInterval())
347 {
348 // No previous interval -> we create a new interval and link it to
349 // this state
350 creationCheck([&](const Id<StateModel>& id) { this->createToState_base(id); });
351 }
352 else
353 {
354 // Previous interval -> we add a new state to the event and link to
355 // it.
356 this->hoveredEvent = st.eventId();
357 creationCheck([&](const Id<StateModel>& id) { this->createToEvent_base(id); });
358 }
359 }
360 }
361};
362}
Definition CreateEvent_State.hpp:25
Definition CreateState.hpp:22
Definition ScenarioCreation_FromState.hpp:26
Creation_FromState(const ToolPalette_T &stateMachine, const Scenario_T &scenarioPath, const score::CommandStackFacade &stack, QState *parent)
Definition ScenarioCreation_FromState.hpp:28
Definition ScenarioCreationState.hpp:66
Definition ScenarioEditionSettings.hpp:14
Definition ScenarioCreationState.hpp:32
The id_base_t class.
Definition Identifier.hpp:57
A small abstraction layer over the score::CommandStack.
Definition CommandStackFacade.hpp:20
Main plug-in of score.
Definition score-plugin-dataflow/Dataflow/PortItem.hpp:13