1 | #include "editor_actions.h" |
2 | #include <game/editor/mapitems/image.h> |
3 | |
4 | CEditorBrushDrawAction::CEditorBrushDrawAction(CEditor *pEditor, int Group) : |
5 | IEditorAction(pEditor), m_Group(Group) |
6 | { |
7 | auto &Map = pEditor->m_Map; |
8 | for(size_t k = 0; k < Map.m_vpGroups[Group]->m_vpLayers.size(); k++) |
9 | { |
10 | auto pLayer = Map.m_vpGroups[Group]->m_vpLayers[k]; |
11 | |
12 | if(pLayer->m_Type == LAYERTYPE_TILES) |
13 | { |
14 | auto pLayerTiles = std::static_pointer_cast<CLayerTiles>(r: pLayer); |
15 | |
16 | if(pLayer == Map.m_pTeleLayer) |
17 | { |
18 | if(!Map.m_pTeleLayer->m_History.empty()) |
19 | { |
20 | m_TeleTileChanges = std::map(Map.m_pTeleLayer->m_History); |
21 | Map.m_pTeleLayer->ClearHistory(); |
22 | } |
23 | } |
24 | else if(pLayer == Map.m_pTuneLayer) |
25 | { |
26 | if(!Map.m_pTuneLayer->m_History.empty()) |
27 | { |
28 | m_TuneTileChanges = std::map(Map.m_pTuneLayer->m_History); |
29 | Map.m_pTuneLayer->ClearHistory(); |
30 | } |
31 | } |
32 | else if(pLayer == Map.m_pSwitchLayer) |
33 | { |
34 | if(!Map.m_pSwitchLayer->m_History.empty()) |
35 | { |
36 | m_SwitchTileChanges = std::map(Map.m_pSwitchLayer->m_History); |
37 | Map.m_pSwitchLayer->ClearHistory(); |
38 | } |
39 | } |
40 | else if(pLayer == Map.m_pSpeedupLayer) |
41 | { |
42 | if(!Map.m_pSpeedupLayer->m_History.empty()) |
43 | { |
44 | m_SpeedupTileChanges = std::map(Map.m_pSpeedupLayer->m_History); |
45 | Map.m_pSpeedupLayer->ClearHistory(); |
46 | } |
47 | } |
48 | |
49 | if(!pLayerTiles->m_TilesHistory.empty()) |
50 | { |
51 | m_vTileChanges.emplace_back(args&: k, args: std::map(pLayerTiles->m_TilesHistory)); |
52 | pLayerTiles->ClearHistory(); |
53 | } |
54 | } |
55 | } |
56 | |
57 | SetInfos(); |
58 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Brush draw (x%d) on %d layers" , m_TotalTilesDrawn, m_TotalLayers); |
59 | } |
60 | |
61 | void CEditorBrushDrawAction::SetInfos() |
62 | { |
63 | m_TotalTilesDrawn = 0; |
64 | m_TotalLayers = 0; |
65 | |
66 | // Process normal tiles |
67 | for(auto const &Pair : m_vTileChanges) |
68 | { |
69 | int Layer = Pair.first; |
70 | std::shared_ptr<CLayer> pLayer = m_pEditor->m_Map.m_vpGroups[m_Group]->m_vpLayers[Layer]; |
71 | m_TotalLayers++; |
72 | |
73 | if(pLayer->m_Type == LAYERTYPE_TILES) |
74 | { |
75 | std::shared_ptr<CLayerTiles> pLayerTiles = std::static_pointer_cast<CLayerTiles>(r: pLayer); |
76 | auto Changes = Pair.second; |
77 | for(auto &Change : Changes) |
78 | { |
79 | m_TotalTilesDrawn += Change.second.size(); |
80 | } |
81 | } |
82 | } |
83 | |
84 | // Process speedup tiles |
85 | for(auto const &SpeedupChange : m_SpeedupTileChanges) |
86 | { |
87 | m_TotalTilesDrawn += SpeedupChange.second.size(); |
88 | } |
89 | |
90 | // Process tele tiles |
91 | for(auto const &TeleChange : m_TeleTileChanges) |
92 | { |
93 | m_TotalTilesDrawn += TeleChange.second.size(); |
94 | } |
95 | |
96 | // Process switch tiles |
97 | for(auto const &SwitchChange : m_SwitchTileChanges) |
98 | { |
99 | m_TotalTilesDrawn += SwitchChange.second.size(); |
100 | } |
101 | |
102 | // Process tune tiles |
103 | for(auto const &TuneChange : m_TuneTileChanges) |
104 | { |
105 | m_TotalTilesDrawn += TuneChange.second.size(); |
106 | } |
107 | |
108 | m_TotalLayers += !m_SpeedupTileChanges.empty(); |
109 | m_TotalLayers += !m_SwitchTileChanges.empty(); |
110 | m_TotalLayers += !m_TeleTileChanges.empty(); |
111 | m_TotalLayers += !m_TuneTileChanges.empty(); |
112 | } |
113 | |
114 | bool CEditorBrushDrawAction::IsEmpty() |
115 | { |
116 | return m_vTileChanges.empty() && m_SpeedupTileChanges.empty() && m_SwitchTileChanges.empty() && m_TeleTileChanges.empty() && m_TuneTileChanges.empty(); |
117 | } |
118 | |
119 | void CEditorBrushDrawAction::Undo() |
120 | { |
121 | Apply(Undo: true); |
122 | } |
123 | |
124 | void CEditorBrushDrawAction::Redo() |
125 | { |
126 | Apply(Undo: false); |
127 | } |
128 | |
129 | void CEditorBrushDrawAction::Apply(bool Undo) |
130 | { |
131 | auto &Map = m_pEditor->m_Map; |
132 | |
133 | // Process normal tiles |
134 | for(auto const &Pair : m_vTileChanges) |
135 | { |
136 | int Layer = Pair.first; |
137 | std::shared_ptr<CLayer> pLayer = Map.m_vpGroups[m_Group]->m_vpLayers[Layer]; |
138 | |
139 | if(pLayer->m_Type == LAYERTYPE_TILES) |
140 | { |
141 | std::shared_ptr<CLayerTiles> pLayerTiles = std::static_pointer_cast<CLayerTiles>(r: pLayer); |
142 | auto Changes = Pair.second; |
143 | for(auto &Change : Changes) |
144 | { |
145 | int y = Change.first; |
146 | auto Line = Change.second; |
147 | for(auto &Tile : Line) |
148 | { |
149 | int x = Tile.first; |
150 | STileStateChange State = Tile.second; |
151 | pLayerTiles->SetTileIgnoreHistory(x, y, Tile: Undo ? State.m_Previous : State.m_Current); |
152 | } |
153 | } |
154 | } |
155 | } |
156 | |
157 | // Process speedup tiles |
158 | for(auto const &SpeedupChange : m_SpeedupTileChanges) |
159 | { |
160 | int y = SpeedupChange.first; |
161 | auto Line = SpeedupChange.second; |
162 | for(auto &Tile : Line) |
163 | { |
164 | int x = Tile.first; |
165 | int Index = y * Map.m_pSpeedupLayer->m_Width + x; |
166 | SSpeedupTileStateChange State = Tile.second; |
167 | SSpeedupTileStateChange::SData Data = Undo ? State.m_Previous : State.m_Current; |
168 | |
169 | Map.m_pSpeedupLayer->m_pSpeedupTile[Index].m_Force = Data.m_Force; |
170 | Map.m_pSpeedupLayer->m_pSpeedupTile[Index].m_MaxSpeed = Data.m_MaxSpeed; |
171 | Map.m_pSpeedupLayer->m_pSpeedupTile[Index].m_Angle = Data.m_Angle; |
172 | Map.m_pSpeedupLayer->m_pSpeedupTile[Index].m_Type = Data.m_Type; |
173 | Map.m_pSpeedupLayer->m_pTiles[Index].m_Index = Data.m_Index; |
174 | } |
175 | } |
176 | |
177 | // Process tele tiles |
178 | for(auto const &TeleChange : m_TeleTileChanges) |
179 | { |
180 | int y = TeleChange.first; |
181 | auto Line = TeleChange.second; |
182 | for(auto &Tile : Line) |
183 | { |
184 | int x = Tile.first; |
185 | int Index = y * Map.m_pTeleLayer->m_Width + x; |
186 | STeleTileStateChange State = Tile.second; |
187 | STeleTileStateChange::SData Data = Undo ? State.m_Previous : State.m_Current; |
188 | |
189 | Map.m_pTeleLayer->m_pTeleTile[Index].m_Number = Data.m_Number; |
190 | Map.m_pTeleLayer->m_pTeleTile[Index].m_Type = Data.m_Type; |
191 | Map.m_pTeleLayer->m_pTiles[Index].m_Index = Data.m_Index; |
192 | } |
193 | } |
194 | |
195 | // Process switch tiles |
196 | for(auto const &SwitchChange : m_SwitchTileChanges) |
197 | { |
198 | int y = SwitchChange.first; |
199 | auto Line = SwitchChange.second; |
200 | for(auto &Tile : Line) |
201 | { |
202 | int x = Tile.first; |
203 | int Index = y * Map.m_pSwitchLayer->m_Width + x; |
204 | SSwitchTileStateChange State = Tile.second; |
205 | SSwitchTileStateChange::SData Data = Undo ? State.m_Previous : State.m_Current; |
206 | |
207 | Map.m_pSwitchLayer->m_pSwitchTile[Index].m_Number = Data.m_Number; |
208 | Map.m_pSwitchLayer->m_pSwitchTile[Index].m_Type = Data.m_Type; |
209 | Map.m_pSwitchLayer->m_pSwitchTile[Index].m_Flags = Data.m_Flags; |
210 | Map.m_pSwitchLayer->m_pSwitchTile[Index].m_Delay = Data.m_Delay; |
211 | Map.m_pSwitchLayer->m_pTiles[Index].m_Index = Data.m_Index; |
212 | } |
213 | } |
214 | |
215 | // Process tune tiles |
216 | for(auto const &TuneChange : m_TuneTileChanges) |
217 | { |
218 | int y = TuneChange.first; |
219 | auto Line = TuneChange.second; |
220 | for(auto &Tile : Line) |
221 | { |
222 | int x = Tile.first; |
223 | int Index = y * Map.m_pTuneLayer->m_Width + x; |
224 | STuneTileStateChange State = Tile.second; |
225 | STuneTileStateChange::SData Data = Undo ? State.m_Previous : State.m_Current; |
226 | |
227 | Map.m_pTuneLayer->m_pTuneTile[Index].m_Number = Data.m_Number; |
228 | Map.m_pTuneLayer->m_pTuneTile[Index].m_Type = Data.m_Type; |
229 | Map.m_pTuneLayer->m_pTiles[Index].m_Index = Data.m_Index; |
230 | } |
231 | } |
232 | } |
233 | |
234 | // ------------------------------------------- |
235 | |
236 | CEditorActionQuadPlace::CEditorActionQuadPlace(CEditor *pEditor, int GroupIndex, int LayerIndex, std::vector<CQuad> &vBrush) : |
237 | CEditorActionLayerBase(pEditor, GroupIndex, LayerIndex), m_vBrush(vBrush) |
238 | { |
239 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Quad place (x%d)" , (int)m_vBrush.size()); |
240 | } |
241 | |
242 | void CEditorActionQuadPlace::Undo() |
243 | { |
244 | std::shared_ptr<CLayerQuads> pLayerQuads = std::static_pointer_cast<CLayerQuads>(r: m_pLayer); |
245 | for(size_t k = 0; k < m_vBrush.size(); k++) |
246 | pLayerQuads->m_vQuads.pop_back(); |
247 | |
248 | m_pEditor->m_Map.OnModify(); |
249 | } |
250 | void CEditorActionQuadPlace::Redo() |
251 | { |
252 | std::shared_ptr<CLayerQuads> pLayerQuads = std::static_pointer_cast<CLayerQuads>(r: m_pLayer); |
253 | for(auto &Brush : m_vBrush) |
254 | pLayerQuads->m_vQuads.push_back(x: Brush); |
255 | |
256 | m_pEditor->m_Map.OnModify(); |
257 | } |
258 | |
259 | CEditorActionSoundPlace::CEditorActionSoundPlace(CEditor *pEditor, int GroupIndex, int LayerIndex, std::vector<CSoundSource> &vBrush) : |
260 | CEditorActionLayerBase(pEditor, GroupIndex, LayerIndex), m_vBrush(vBrush) |
261 | { |
262 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Sound place (x%d)" , (int)m_vBrush.size()); |
263 | } |
264 | |
265 | void CEditorActionSoundPlace::Undo() |
266 | { |
267 | std::shared_ptr<CLayerSounds> pLayerSounds = std::static_pointer_cast<CLayerSounds>(r: m_pLayer); |
268 | for(size_t k = 0; k < m_vBrush.size(); k++) |
269 | pLayerSounds->m_vSources.pop_back(); |
270 | |
271 | m_pEditor->m_Map.OnModify(); |
272 | } |
273 | |
274 | void CEditorActionSoundPlace::Redo() |
275 | { |
276 | std::shared_ptr<CLayerSounds> pLayerSounds = std::static_pointer_cast<CLayerSounds>(r: m_pLayer); |
277 | for(auto &Brush : m_vBrush) |
278 | pLayerSounds->m_vSources.push_back(x: Brush); |
279 | |
280 | m_pEditor->m_Map.OnModify(); |
281 | } |
282 | |
283 | // --------------------------------------------------------------------------------------- |
284 | |
285 | CEditorActionDeleteQuad::CEditorActionDeleteQuad(CEditor *pEditor, int GroupIndex, int LayerIndex, std::vector<int> const &vQuadsIndices, std::vector<CQuad> const &vDeletedQuads) : |
286 | CEditorActionLayerBase(pEditor, GroupIndex, LayerIndex), m_vQuadsIndices(vQuadsIndices), m_vDeletedQuads(vDeletedQuads) |
287 | { |
288 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Delete quad (x%d)" , (int)m_vDeletedQuads.size()); |
289 | } |
290 | |
291 | void CEditorActionDeleteQuad::Undo() |
292 | { |
293 | std::shared_ptr<CLayerQuads> pLayerQuads = std::static_pointer_cast<CLayerQuads>(r: m_pLayer); |
294 | for(size_t k = 0; k < m_vQuadsIndices.size(); k++) |
295 | { |
296 | pLayerQuads->m_vQuads.insert(position: pLayerQuads->m_vQuads.begin() + m_vQuadsIndices[k], x: m_vDeletedQuads[k]); |
297 | } |
298 | } |
299 | |
300 | void CEditorActionDeleteQuad::Redo() |
301 | { |
302 | std::shared_ptr<CLayerQuads> pLayerQuads = std::static_pointer_cast<CLayerQuads>(r: m_pLayer); |
303 | std::vector<int> vQuads(m_vQuadsIndices); |
304 | |
305 | for(int i = 0; i < (int)vQuads.size(); ++i) |
306 | { |
307 | pLayerQuads->m_vQuads.erase(position: pLayerQuads->m_vQuads.begin() + vQuads[i]); |
308 | for(int j = i + 1; j < (int)vQuads.size(); ++j) |
309 | if(vQuads[j] > vQuads[i]) |
310 | vQuads[j]--; |
311 | |
312 | vQuads.erase(position: vQuads.begin() + i); |
313 | |
314 | i--; |
315 | } |
316 | } |
317 | |
318 | // --------------------------------------------------------------------------------------- |
319 | |
320 | CEditorActionEditQuadPoint::CEditorActionEditQuadPoint(CEditor *pEditor, int GroupIndex, int LayerIndex, int QuadIndex, std::vector<CPoint> const &vPreviousPoints, std::vector<CPoint> const &vCurrentPoints) : |
321 | CEditorActionLayerBase(pEditor, GroupIndex, LayerIndex), m_QuadIndex(QuadIndex), m_vPreviousPoints(vPreviousPoints), m_vCurrentPoints(vCurrentPoints) |
322 | { |
323 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Edit quad points" ); |
324 | } |
325 | |
326 | void CEditorActionEditQuadPoint::Undo() |
327 | { |
328 | std::shared_ptr<CLayerQuads> pLayerQuads = std::static_pointer_cast<CLayerQuads>(r: m_pLayer); |
329 | CQuad &Quad = pLayerQuads->m_vQuads[m_QuadIndex]; |
330 | for(int k = 0; k < 5; k++) |
331 | Quad.m_aPoints[k] = m_vPreviousPoints[k]; |
332 | } |
333 | |
334 | void CEditorActionEditQuadPoint::Redo() |
335 | { |
336 | std::shared_ptr<CLayerQuads> pLayerQuads = std::static_pointer_cast<CLayerQuads>(r: m_pLayer); |
337 | CQuad &Quad = pLayerQuads->m_vQuads[m_QuadIndex]; |
338 | for(int k = 0; k < 5; k++) |
339 | Quad.m_aPoints[k] = m_vCurrentPoints[k]; |
340 | } |
341 | |
342 | CEditorActionEditQuadProp::CEditorActionEditQuadProp(CEditor *pEditor, int GroupIndex, int LayerIndex, int QuadIndex, EQuadProp Prop, int Previous, int Current) : |
343 | CEditorActionLayerBase(pEditor, GroupIndex, LayerIndex), m_QuadIndex(QuadIndex), m_Prop(Prop), m_Previous(Previous), m_Current(Current) |
344 | { |
345 | static const char *s_apNames[] = { |
346 | "order" , |
347 | "pos X" , |
348 | "pos Y" , |
349 | "pos env" , |
350 | "pos env offset" , |
351 | "color env" , |
352 | "color env offset" }; |
353 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Edit quad %s property in layer %d of group %d" , s_apNames[(int)m_Prop], m_LayerIndex, m_GroupIndex); |
354 | } |
355 | |
356 | void CEditorActionEditQuadProp::Undo() |
357 | { |
358 | Apply(Value: m_Previous); |
359 | } |
360 | |
361 | void CEditorActionEditQuadProp::Redo() |
362 | { |
363 | Apply(Value: m_Current); |
364 | } |
365 | |
366 | void CEditorActionEditQuadProp::Apply(int Value) |
367 | { |
368 | std::shared_ptr<CLayerQuads> pLayerQuads = std::static_pointer_cast<CLayerQuads>(r: m_pLayer); |
369 | CQuad &Quad = pLayerQuads->m_vQuads[m_QuadIndex]; |
370 | if(m_Prop == EQuadProp::PROP_POS_ENV) |
371 | Quad.m_PosEnv = Value; |
372 | else if(m_Prop == EQuadProp::PROP_POS_ENV_OFFSET) |
373 | Quad.m_PosEnvOffset = Value; |
374 | else if(m_Prop == EQuadProp::PROP_COLOR_ENV) |
375 | Quad.m_ColorEnv = Value; |
376 | else if(m_Prop == EQuadProp::PROP_COLOR_ENV_OFFSET) |
377 | Quad.m_ColorEnvOffset = Value; |
378 | } |
379 | |
380 | CEditorActionEditQuadPointProp::CEditorActionEditQuadPointProp(CEditor *pEditor, int GroupIndex, int LayerIndex, int QuadIndex, int PointIndex, EQuadPointProp Prop, int Previous, int Current) : |
381 | CEditorActionLayerBase(pEditor, GroupIndex, LayerIndex), m_QuadIndex(QuadIndex), m_PointIndex(PointIndex), m_Prop(Prop), m_Previous(Previous), m_Current(Current) |
382 | { |
383 | static const char *s_apNames[] = { |
384 | "pos X" , |
385 | "pos Y" , |
386 | "color" , |
387 | "tex U" , |
388 | "tex V" }; |
389 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Edit quad point %s property in layer %d of group %d" , s_apNames[(int)m_Prop], m_LayerIndex, m_GroupIndex); |
390 | } |
391 | |
392 | void CEditorActionEditQuadPointProp::Undo() |
393 | { |
394 | Apply(Value: m_Previous); |
395 | } |
396 | |
397 | void CEditorActionEditQuadPointProp::Redo() |
398 | { |
399 | Apply(Value: m_Current); |
400 | } |
401 | |
402 | void CEditorActionEditQuadPointProp::Apply(int Value) |
403 | { |
404 | std::shared_ptr<CLayerQuads> pLayerQuads = std::static_pointer_cast<CLayerQuads>(r: m_pLayer); |
405 | CQuad &Quad = pLayerQuads->m_vQuads[m_QuadIndex]; |
406 | |
407 | if(m_Prop == EQuadPointProp::PROP_COLOR) |
408 | { |
409 | const ColorRGBA ColorPick = ColorRGBA::UnpackAlphaLast<ColorRGBA>(Color: Value); |
410 | |
411 | Quad.m_aColors[m_PointIndex].r = ColorPick.r * 255.0f; |
412 | Quad.m_aColors[m_PointIndex].g = ColorPick.g * 255.0f; |
413 | Quad.m_aColors[m_PointIndex].b = ColorPick.b * 255.0f; |
414 | Quad.m_aColors[m_PointIndex].a = ColorPick.a * 255.0f; |
415 | |
416 | m_pEditor->m_ColorPickerPopupContext.m_RgbaColor = ColorPick; |
417 | m_pEditor->m_ColorPickerPopupContext.m_HslaColor = color_cast<ColorHSLA>(rgb: ColorPick); |
418 | m_pEditor->m_ColorPickerPopupContext.m_HsvaColor = color_cast<ColorHSVA>(hsl: m_pEditor->m_ColorPickerPopupContext.m_HslaColor); |
419 | } |
420 | else if(m_Prop == EQuadPointProp::PROP_TEX_U) |
421 | { |
422 | Quad.m_aTexcoords[m_PointIndex].x = Value; |
423 | } |
424 | else if(m_Prop == EQuadPointProp::PROP_TEX_V) |
425 | { |
426 | Quad.m_aTexcoords[m_PointIndex].y = Value; |
427 | } |
428 | } |
429 | |
430 | // --------------------------------------------------------------------------------------- |
431 | |
432 | CEditorActionBulk::CEditorActionBulk(CEditor *pEditor, const std::vector<std::shared_ptr<IEditorAction>> &vpActions, const char *pDisplay, bool Reverse) : |
433 | IEditorAction(pEditor), m_vpActions(vpActions), m_Reverse(Reverse) |
434 | { |
435 | // Assuming we only use bulk for actions of same type, if no display was provided |
436 | if(!pDisplay) |
437 | { |
438 | const char *pBaseDisplay = m_vpActions[0]->DisplayText(); |
439 | if(m_vpActions.size() == 1) |
440 | str_copy(dst&: m_aDisplayText, src: pBaseDisplay); |
441 | else |
442 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "%s (x%d)" , pBaseDisplay, (int)m_vpActions.size()); |
443 | } |
444 | else |
445 | { |
446 | str_copy(dst&: m_aDisplayText, src: pDisplay); |
447 | } |
448 | } |
449 | |
450 | void CEditorActionBulk::Undo() |
451 | { |
452 | if(m_Reverse) |
453 | { |
454 | for(auto pIt = m_vpActions.rbegin(); pIt != m_vpActions.rend(); pIt++) |
455 | { |
456 | auto &pAction = *pIt; |
457 | pAction->Undo(); |
458 | } |
459 | } |
460 | else |
461 | { |
462 | for(auto &pAction : m_vpActions) |
463 | { |
464 | pAction->Undo(); |
465 | } |
466 | } |
467 | } |
468 | |
469 | void CEditorActionBulk::Redo() |
470 | { |
471 | for(auto &pAction : m_vpActions) |
472 | { |
473 | pAction->Redo(); |
474 | } |
475 | } |
476 | |
477 | // --------- |
478 | |
479 | CEditorActionTileChanges::CEditorActionTileChanges(CEditor *pEditor, int GroupIndex, int LayerIndex, const char *pAction, const EditorTileStateChangeHistory<STileStateChange> &Changes) : |
480 | CEditorActionLayerBase(pEditor, GroupIndex, LayerIndex), m_Changes(Changes) |
481 | { |
482 | ComputeInfos(); |
483 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "%s (x%d)" , pAction, m_TotalChanges); |
484 | } |
485 | |
486 | void CEditorActionTileChanges::Undo() |
487 | { |
488 | Apply(Undo: true); |
489 | } |
490 | |
491 | void CEditorActionTileChanges::Redo() |
492 | { |
493 | Apply(Undo: false); |
494 | } |
495 | |
496 | void CEditorActionTileChanges::Apply(bool Undo) |
497 | { |
498 | auto &Map = m_pEditor->m_Map; |
499 | std::shared_ptr<CLayerTiles> pLayerTiles = std::static_pointer_cast<CLayerTiles>(r: m_pLayer); |
500 | for(auto &Change : m_Changes) |
501 | { |
502 | int y = Change.first; |
503 | auto Line = Change.second; |
504 | for(auto &Tile : Line) |
505 | { |
506 | int x = Tile.first; |
507 | STileStateChange State = Tile.second; |
508 | pLayerTiles->SetTileIgnoreHistory(x, y, Tile: Undo ? State.m_Previous : State.m_Current); |
509 | } |
510 | } |
511 | |
512 | Map.OnModify(); |
513 | } |
514 | |
515 | void CEditorActionTileChanges::ComputeInfos() |
516 | { |
517 | m_TotalChanges = 0; |
518 | for(auto &Line : m_Changes) |
519 | m_TotalChanges += Line.second.size(); |
520 | } |
521 | |
522 | // --------- |
523 | |
524 | CEditorActionLayerBase::CEditorActionLayerBase(CEditor *pEditor, int GroupIndex, int LayerIndex) : |
525 | IEditorAction(pEditor), m_GroupIndex(GroupIndex), m_LayerIndex(LayerIndex) |
526 | { |
527 | m_pLayer = pEditor->m_Map.m_vpGroups[GroupIndex]->m_vpLayers[LayerIndex]; |
528 | } |
529 | |
530 | // ---------- |
531 | |
532 | CEditorActionAddLayer::CEditorActionAddLayer(CEditor *pEditor, int GroupIndex, int LayerIndex, bool Duplicate) : |
533 | CEditorActionLayerBase(pEditor, GroupIndex, LayerIndex), m_Duplicate(Duplicate) |
534 | { |
535 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "%s %s layer in group %d" , m_Duplicate ? "Duplicate" : "New" , m_pLayer->TypeName(), m_GroupIndex); |
536 | } |
537 | |
538 | void CEditorActionAddLayer::Undo() |
539 | { |
540 | // Undo: remove layer from vector but keep it in case we want to add it back |
541 | auto &vLayers = m_pEditor->m_Map.m_vpGroups[m_GroupIndex]->m_vpLayers; |
542 | vLayers.erase(position: vLayers.begin() + m_LayerIndex); |
543 | |
544 | m_pEditor->m_Map.m_vpGroups[m_GroupIndex]->m_Collapse = false; |
545 | if(m_LayerIndex >= (int)vLayers.size()) |
546 | m_pEditor->SelectLayer(LayerIndex: vLayers.size() - 1, GroupIndex: m_GroupIndex); |
547 | |
548 | m_pEditor->m_Map.OnModify(); |
549 | } |
550 | |
551 | void CEditorActionAddLayer::Redo() |
552 | { |
553 | // Redo: add back the removed layer contained in this class |
554 | auto &vLayers = m_pEditor->m_Map.m_vpGroups[m_GroupIndex]->m_vpLayers; |
555 | vLayers.insert(position: vLayers.begin() + m_LayerIndex, x: m_pLayer); |
556 | |
557 | m_pEditor->m_Map.m_vpGroups[m_GroupIndex]->m_Collapse = false; |
558 | m_pEditor->SelectLayer(LayerIndex: m_LayerIndex, GroupIndex: m_GroupIndex); |
559 | m_pEditor->m_Map.OnModify(); |
560 | } |
561 | |
562 | CEditorActionDeleteLayer::CEditorActionDeleteLayer(CEditor *pEditor, int GroupIndex, int LayerIndex) : |
563 | CEditorActionLayerBase(pEditor, GroupIndex, LayerIndex) |
564 | { |
565 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Delete %s layer of group %d" , m_pLayer->TypeName(), m_GroupIndex); |
566 | } |
567 | |
568 | void CEditorActionDeleteLayer::Redo() |
569 | { |
570 | // Redo: remove layer from vector but keep it in case we want to add it back |
571 | auto &vLayers = m_pEditor->m_Map.m_vpGroups[m_GroupIndex]->m_vpLayers; |
572 | |
573 | if(m_pLayer->m_Type == LAYERTYPE_TILES) |
574 | { |
575 | std::shared_ptr<CLayerTiles> pLayerTiles = std::static_pointer_cast<CLayerTiles>(r: m_pLayer); |
576 | if(pLayerTiles->m_Front) |
577 | m_pEditor->m_Map.m_pFrontLayer = nullptr; |
578 | else if(pLayerTiles->m_Tele) |
579 | m_pEditor->m_Map.m_pTeleLayer = nullptr; |
580 | else if(pLayerTiles->m_Speedup) |
581 | m_pEditor->m_Map.m_pSpeedupLayer = nullptr; |
582 | else if(pLayerTiles->m_Switch) |
583 | m_pEditor->m_Map.m_pSwitchLayer = nullptr; |
584 | else if(pLayerTiles->m_Tune) |
585 | m_pEditor->m_Map.m_pTuneLayer = nullptr; |
586 | } |
587 | |
588 | m_pEditor->m_Map.m_vpGroups[m_GroupIndex]->DeleteLayer(Index: m_LayerIndex); |
589 | |
590 | m_pEditor->m_Map.m_vpGroups[m_GroupIndex]->m_Collapse = false; |
591 | if(m_LayerIndex >= (int)vLayers.size()) |
592 | m_pEditor->SelectLayer(LayerIndex: vLayers.size() - 1, GroupIndex: m_GroupIndex); |
593 | |
594 | m_pEditor->m_Map.OnModify(); |
595 | } |
596 | |
597 | void CEditorActionDeleteLayer::Undo() |
598 | { |
599 | // Undo: add back the removed layer contained in this class |
600 | auto &vLayers = m_pEditor->m_Map.m_vpGroups[m_GroupIndex]->m_vpLayers; |
601 | |
602 | if(m_pLayer->m_Type == LAYERTYPE_TILES) |
603 | { |
604 | std::shared_ptr<CLayerTiles> pLayerTiles = std::static_pointer_cast<CLayerTiles>(r: m_pLayer); |
605 | if(pLayerTiles->m_Front) |
606 | m_pEditor->m_Map.m_pFrontLayer = std::static_pointer_cast<CLayerFront>(r: m_pLayer); |
607 | else if(pLayerTiles->m_Tele) |
608 | m_pEditor->m_Map.m_pTeleLayer = std::static_pointer_cast<CLayerTele>(r: m_pLayer); |
609 | else if(pLayerTiles->m_Speedup) |
610 | m_pEditor->m_Map.m_pSpeedupLayer = std::static_pointer_cast<CLayerSpeedup>(r: m_pLayer); |
611 | else if(pLayerTiles->m_Switch) |
612 | m_pEditor->m_Map.m_pSwitchLayer = std::static_pointer_cast<CLayerSwitch>(r: m_pLayer); |
613 | else if(pLayerTiles->m_Tune) |
614 | m_pEditor->m_Map.m_pTuneLayer = std::static_pointer_cast<CLayerTune>(r: m_pLayer); |
615 | } |
616 | |
617 | vLayers.insert(position: vLayers.begin() + m_LayerIndex, x: m_pLayer); |
618 | |
619 | m_pEditor->m_Map.m_vpGroups[m_GroupIndex]->m_Collapse = false; |
620 | m_pEditor->SelectLayer(LayerIndex: m_LayerIndex, GroupIndex: m_GroupIndex); |
621 | m_pEditor->m_Map.OnModify(); |
622 | } |
623 | |
624 | CEditorActionGroup::CEditorActionGroup(CEditor *pEditor, int GroupIndex, bool Delete) : |
625 | IEditorAction(pEditor), m_GroupIndex(GroupIndex), m_Delete(Delete) |
626 | { |
627 | m_pGroup = pEditor->m_Map.m_vpGroups[GroupIndex]; |
628 | if(m_Delete) |
629 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Delete group %d" , m_GroupIndex); |
630 | else |
631 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "New group" ); |
632 | } |
633 | |
634 | void CEditorActionGroup::Undo() |
635 | { |
636 | if(m_Delete) |
637 | { |
638 | // Undo: add back the group |
639 | m_pEditor->m_Map.m_vpGroups.insert(position: m_pEditor->m_Map.m_vpGroups.begin() + m_GroupIndex, x: m_pGroup); |
640 | m_pEditor->m_SelectedGroup = m_GroupIndex; |
641 | m_pEditor->m_Map.OnModify(); |
642 | } |
643 | else |
644 | { |
645 | // Undo: delete the group |
646 | m_pEditor->m_Map.DeleteGroup(Index: m_GroupIndex); |
647 | m_pEditor->m_SelectedGroup = maximum(a: 0, b: m_GroupIndex - 1); |
648 | } |
649 | |
650 | m_pEditor->m_Map.OnModify(); |
651 | } |
652 | |
653 | void CEditorActionGroup::Redo() |
654 | { |
655 | if(!m_Delete) |
656 | { |
657 | // Redo: add back the group |
658 | m_pEditor->m_Map.m_vpGroups.insert(position: m_pEditor->m_Map.m_vpGroups.begin() + m_GroupIndex, x: m_pGroup); |
659 | m_pEditor->m_SelectedGroup = m_GroupIndex; |
660 | } |
661 | else |
662 | { |
663 | // Redo: delete the group |
664 | m_pEditor->m_Map.DeleteGroup(Index: m_GroupIndex); |
665 | m_pEditor->m_SelectedGroup = maximum(a: 0, b: m_GroupIndex - 1); |
666 | } |
667 | |
668 | m_pEditor->m_Map.OnModify(); |
669 | } |
670 | |
671 | CEditorActionEditGroupProp::CEditorActionEditGroupProp(CEditor *pEditor, int GroupIndex, EGroupProp Prop, int Previous, int Current) : |
672 | IEditorAction(pEditor), m_GroupIndex(GroupIndex), m_Prop(Prop), m_Previous(Previous), m_Current(Current) |
673 | { |
674 | static const char *s_apNames[] = { |
675 | "order" , |
676 | "pos X" , |
677 | "pos Y" , |
678 | "para X" , |
679 | "para Y" , |
680 | "use clipping" , |
681 | "clip X" , |
682 | "clip Y" , |
683 | "clip W" , |
684 | "clip H" }; |
685 | |
686 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Edit group %d %s property" , m_GroupIndex, s_apNames[(int)Prop]); |
687 | } |
688 | |
689 | void CEditorActionEditGroupProp::Undo() |
690 | { |
691 | auto pGroup = m_pEditor->m_Map.m_vpGroups[m_GroupIndex]; |
692 | |
693 | if(m_Prop == EGroupProp::PROP_ORDER) |
694 | { |
695 | int CurrentOrder = m_Current; |
696 | bool Dir = m_Current > m_Previous; |
697 | while(CurrentOrder != m_Previous) |
698 | { |
699 | CurrentOrder = m_pEditor->m_Map.SwapGroups(Index0: CurrentOrder, Index1: Dir ? CurrentOrder - 1 : CurrentOrder + 1); |
700 | } |
701 | m_pEditor->m_SelectedGroup = m_Previous; |
702 | } |
703 | else |
704 | Apply(Value: m_Previous); |
705 | } |
706 | |
707 | void CEditorActionEditGroupProp::Redo() |
708 | { |
709 | auto pGroup = m_pEditor->m_Map.m_vpGroups[m_GroupIndex]; |
710 | |
711 | if(m_Prop == EGroupProp::PROP_ORDER) |
712 | { |
713 | int CurrentOrder = m_Previous; |
714 | bool Dir = m_Previous > m_Current; |
715 | while(CurrentOrder != m_Current) |
716 | { |
717 | CurrentOrder = m_pEditor->m_Map.SwapGroups(Index0: CurrentOrder, Index1: Dir ? CurrentOrder - 1 : CurrentOrder + 1); |
718 | } |
719 | m_pEditor->m_SelectedGroup = m_Current; |
720 | } |
721 | else |
722 | Apply(Value: m_Current); |
723 | } |
724 | |
725 | void CEditorActionEditGroupProp::Apply(int Value) |
726 | { |
727 | auto pGroup = m_pEditor->m_Map.m_vpGroups[m_GroupIndex]; |
728 | |
729 | if(m_Prop == EGroupProp::PROP_POS_X) |
730 | pGroup->m_OffsetX = Value; |
731 | if(m_Prop == EGroupProp::PROP_POS_Y) |
732 | pGroup->m_OffsetY = Value; |
733 | if(m_Prop == EGroupProp::PROP_PARA_X) |
734 | pGroup->m_ParallaxX = Value; |
735 | if(m_Prop == EGroupProp::PROP_PARA_Y) |
736 | pGroup->m_ParallaxY = Value; |
737 | if(m_Prop == EGroupProp::PROP_USE_CLIPPING) |
738 | pGroup->m_UseClipping = Value; |
739 | if(m_Prop == EGroupProp::PROP_CLIP_X) |
740 | pGroup->m_ClipX = Value; |
741 | if(m_Prop == EGroupProp::PROP_CLIP_Y) |
742 | pGroup->m_ClipY = Value; |
743 | if(m_Prop == EGroupProp::PROP_CLIP_W) |
744 | pGroup->m_ClipW = Value; |
745 | if(m_Prop == EGroupProp::PROP_CLIP_H) |
746 | pGroup->m_ClipH = Value; |
747 | |
748 | m_pEditor->m_Map.OnModify(); |
749 | } |
750 | |
751 | template<typename E> |
752 | CEditorActionEditLayerPropBase<E>::CEditorActionEditLayerPropBase(CEditor *pEditor, int GroupIndex, int LayerIndex, E Prop, int Previous, int Current) : |
753 | CEditorActionLayerBase(pEditor, GroupIndex, LayerIndex), m_Prop(Prop), m_Previous(Previous), m_Current(Current) |
754 | { |
755 | } |
756 | |
757 | CEditorActionEditLayerProp::CEditorActionEditLayerProp(CEditor *pEditor, int GroupIndex, int LayerIndex, ELayerProp Prop, int Previous, int Current) : |
758 | CEditorActionEditLayerPropBase(pEditor, GroupIndex, LayerIndex, Prop, Previous, Current) |
759 | { |
760 | static const char *s_apNames[] = { |
761 | "group" , |
762 | "order" , |
763 | "HQ" }; |
764 | |
765 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Edit layer %d in group %d %s property" , m_LayerIndex, m_GroupIndex, s_apNames[(int)m_Prop]); |
766 | } |
767 | |
768 | void CEditorActionEditLayerProp::Undo() |
769 | { |
770 | auto pCurrentGroup = m_pEditor->m_Map.m_vpGroups[m_GroupIndex]; |
771 | |
772 | if(m_Prop == ELayerProp::PROP_ORDER) |
773 | { |
774 | m_pEditor->SelectLayer(LayerIndex: pCurrentGroup->SwapLayers(Index0: m_Current, Index1: m_Previous)); |
775 | } |
776 | else |
777 | Apply(Value: m_Previous); |
778 | } |
779 | |
780 | void CEditorActionEditLayerProp::Redo() |
781 | { |
782 | auto pCurrentGroup = m_pEditor->m_Map.m_vpGroups[m_GroupIndex]; |
783 | |
784 | if(m_Prop == ELayerProp::PROP_ORDER) |
785 | { |
786 | m_pEditor->SelectLayer(LayerIndex: pCurrentGroup->SwapLayers(Index0: m_Previous, Index1: m_Current)); |
787 | } |
788 | else |
789 | Apply(Value: m_Current); |
790 | } |
791 | |
792 | void CEditorActionEditLayerProp::Apply(int Value) |
793 | { |
794 | if(m_Prop == ELayerProp::PROP_GROUP) |
795 | { |
796 | auto pCurrentGroup = m_pEditor->m_Map.m_vpGroups[Value == m_Previous ? m_Current : m_Previous]; |
797 | auto pPreviousGroup = m_pEditor->m_Map.m_vpGroups[Value]; |
798 | pCurrentGroup->m_vpLayers.erase(position: pCurrentGroup->m_vpLayers.begin() + pCurrentGroup->m_vpLayers.size() - 1); |
799 | if(Value == m_Previous) |
800 | pPreviousGroup->m_vpLayers.insert(position: pPreviousGroup->m_vpLayers.begin() + m_LayerIndex, x: m_pLayer); |
801 | else |
802 | pPreviousGroup->m_vpLayers.push_back(x: m_pLayer); |
803 | m_pEditor->m_SelectedGroup = Value; |
804 | m_pEditor->SelectLayer(LayerIndex: m_LayerIndex); |
805 | } |
806 | else if(m_Prop == ELayerProp::PROP_HQ) |
807 | { |
808 | m_pLayer->m_Flags = Value; |
809 | } |
810 | |
811 | m_pEditor->m_Map.OnModify(); |
812 | } |
813 | |
814 | CEditorActionEditLayerTilesProp::CEditorActionEditLayerTilesProp(CEditor *pEditor, int GroupIndex, int LayerIndex, ETilesProp Prop, int Previous, int Current) : |
815 | CEditorActionEditLayerPropBase(pEditor, GroupIndex, LayerIndex, Prop, Previous, Current) |
816 | { |
817 | static const char *s_apNames[] = { |
818 | "width" , |
819 | "height" , |
820 | "shift" , |
821 | "shift by" , |
822 | "image" , |
823 | "color" , |
824 | "color env" , |
825 | "color env offset" , |
826 | "automapper" , |
827 | "seed" }; |
828 | |
829 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Edit tiles layer %d in group %d %s property" , m_LayerIndex, m_GroupIndex, s_apNames[(int)Prop]); |
830 | } |
831 | |
832 | void CEditorActionEditLayerTilesProp::SetSavedLayers(const std::map<int, std::shared_ptr<CLayer>> &SavedLayers) |
833 | { |
834 | m_SavedLayers = std::map(SavedLayers); |
835 | } |
836 | |
837 | void CEditorActionEditLayerTilesProp::Undo() |
838 | { |
839 | std::shared_ptr<CLayerTiles> pLayerTiles = std::static_pointer_cast<CLayerTiles>(r: m_pLayer); |
840 | std::shared_ptr<CLayerTiles> pSavedLayerTiles = nullptr; |
841 | |
842 | if(m_Prop == ETilesProp::PROP_WIDTH || m_Prop == ETilesProp::PROP_HEIGHT) |
843 | { |
844 | if(m_Prop == ETilesProp::PROP_HEIGHT) |
845 | pLayerTiles->Resize(NewW: pLayerTiles->m_Width, NewH: m_Previous); |
846 | else if(m_Prop == ETilesProp::PROP_WIDTH) |
847 | pLayerTiles->Resize(NewW: m_Previous, NewH: pLayerTiles->m_Height); |
848 | |
849 | RestoreLayer(Layer: LAYERTYPE_TILES, pLayerTiles); |
850 | if(pLayerTiles->m_Game || pLayerTiles->m_Front || pLayerTiles->m_Switch || pLayerTiles->m_Speedup || pLayerTiles->m_Tune) |
851 | { |
852 | if(m_pEditor->m_Map.m_pFrontLayer && !pLayerTiles->m_Front) |
853 | RestoreLayer(Layer: LAYERTYPE_FRONT, pLayerTiles: m_pEditor->m_Map.m_pFrontLayer); |
854 | if(m_pEditor->m_Map.m_pTeleLayer && !pLayerTiles->m_Tele) |
855 | RestoreLayer(Layer: LAYERTYPE_TELE, pLayerTiles: m_pEditor->m_Map.m_pTeleLayer); |
856 | if(m_pEditor->m_Map.m_pSwitchLayer && !pLayerTiles->m_Switch) |
857 | RestoreLayer(Layer: LAYERTYPE_SWITCH, pLayerTiles: m_pEditor->m_Map.m_pSwitchLayer); |
858 | if(m_pEditor->m_Map.m_pSpeedupLayer && !pLayerTiles->m_Speedup) |
859 | RestoreLayer(Layer: LAYERTYPE_SPEEDUP, pLayerTiles: m_pEditor->m_Map.m_pSpeedupLayer); |
860 | if(m_pEditor->m_Map.m_pTuneLayer && !pLayerTiles->m_Tune) |
861 | RestoreLayer(Layer: LAYERTYPE_TUNE, pLayerTiles: m_pEditor->m_Map.m_pTuneLayer); |
862 | if(!pLayerTiles->m_Game) |
863 | RestoreLayer(Layer: LAYERTYPE_GAME, pLayerTiles: m_pEditor->m_Map.m_pGameLayer); |
864 | } |
865 | } |
866 | else if(m_Prop == ETilesProp::PROP_SHIFT) |
867 | { |
868 | RestoreLayer(Layer: LAYERTYPE_TILES, pLayerTiles); |
869 | } |
870 | else if(m_Prop == ETilesProp::PROP_SHIFT_BY) |
871 | { |
872 | m_pEditor->m_ShiftBy = m_Previous; |
873 | } |
874 | else if(m_Prop == ETilesProp::PROP_IMAGE) |
875 | { |
876 | if(m_Previous == -1) |
877 | { |
878 | pLayerTiles->m_Image = -1; |
879 | } |
880 | else |
881 | { |
882 | pLayerTiles->m_Image = m_Previous % m_pEditor->m_Map.m_vpImages.size(); |
883 | pLayerTiles->m_AutoMapperConfig = -1; |
884 | } |
885 | } |
886 | else if(m_Prop == ETilesProp::PROP_COLOR) |
887 | { |
888 | const ColorRGBA ColorPick = ColorRGBA::UnpackAlphaLast<ColorRGBA>(Color: m_Previous); |
889 | |
890 | pLayerTiles->m_Color.r = ColorPick.r * 255.0f; |
891 | pLayerTiles->m_Color.g = ColorPick.g * 255.0f; |
892 | pLayerTiles->m_Color.b = ColorPick.b * 255.0f; |
893 | pLayerTiles->m_Color.a = ColorPick.a * 255.0f; |
894 | |
895 | m_pEditor->m_ColorPickerPopupContext.m_RgbaColor = ColorPick; |
896 | m_pEditor->m_ColorPickerPopupContext.m_HslaColor = color_cast<ColorHSLA>(rgb: ColorPick); |
897 | m_pEditor->m_ColorPickerPopupContext.m_HsvaColor = color_cast<ColorHSVA>(hsl: m_pEditor->m_ColorPickerPopupContext.m_HslaColor); |
898 | } |
899 | else if(m_Prop == ETilesProp::PROP_COLOR_ENV) |
900 | { |
901 | pLayerTiles->m_ColorEnv = m_Previous; |
902 | } |
903 | else if(m_Prop == ETilesProp::PROP_COLOR_ENV_OFFSET) |
904 | { |
905 | pLayerTiles->m_ColorEnvOffset = m_Previous; |
906 | } |
907 | else if(m_Prop == ETilesProp::PROP_AUTOMAPPER) |
908 | { |
909 | pLayerTiles->m_AutoMapperConfig = m_Previous; |
910 | } |
911 | else if(m_Prop == ETilesProp::PROP_SEED) |
912 | { |
913 | pLayerTiles->m_Seed = m_Previous; |
914 | } |
915 | |
916 | m_pEditor->m_Map.OnModify(); |
917 | } |
918 | |
919 | void CEditorActionEditLayerTilesProp::Redo() |
920 | { |
921 | std::shared_ptr<CLayerTiles> pLayerTiles = std::static_pointer_cast<CLayerTiles>(r: m_pLayer); |
922 | |
923 | if(m_Prop == ETilesProp::PROP_WIDTH || m_Prop == ETilesProp::PROP_HEIGHT) |
924 | { |
925 | if(m_Prop == ETilesProp::PROP_HEIGHT) |
926 | pLayerTiles->Resize(NewW: pLayerTiles->m_Width, NewH: m_Current); |
927 | else if(m_Prop == ETilesProp::PROP_WIDTH) |
928 | pLayerTiles->Resize(NewW: m_Current, NewH: pLayerTiles->m_Height); |
929 | |
930 | if(pLayerTiles->m_Game || pLayerTiles->m_Front || pLayerTiles->m_Switch || pLayerTiles->m_Speedup || pLayerTiles->m_Tune) |
931 | { |
932 | if(m_pEditor->m_Map.m_pFrontLayer && !pLayerTiles->m_Front) |
933 | m_pEditor->m_Map.m_pFrontLayer->Resize(NewW: pLayerTiles->m_Width, NewH: pLayerTiles->m_Height); |
934 | if(m_pEditor->m_Map.m_pTeleLayer && !pLayerTiles->m_Tele) |
935 | m_pEditor->m_Map.m_pTeleLayer->Resize(NewW: pLayerTiles->m_Width, NewH: pLayerTiles->m_Height); |
936 | if(m_pEditor->m_Map.m_pSwitchLayer && !pLayerTiles->m_Switch) |
937 | m_pEditor->m_Map.m_pSwitchLayer->Resize(NewW: pLayerTiles->m_Width, NewH: pLayerTiles->m_Height); |
938 | if(m_pEditor->m_Map.m_pSpeedupLayer && !pLayerTiles->m_Speedup) |
939 | m_pEditor->m_Map.m_pSpeedupLayer->Resize(NewW: pLayerTiles->m_Width, NewH: pLayerTiles->m_Height); |
940 | if(m_pEditor->m_Map.m_pTuneLayer && !pLayerTiles->m_Tune) |
941 | m_pEditor->m_Map.m_pTuneLayer->Resize(NewW: pLayerTiles->m_Width, NewH: pLayerTiles->m_Height); |
942 | if(!pLayerTiles->m_Game) |
943 | m_pEditor->m_Map.m_pGameLayer->Resize(NewW: pLayerTiles->m_Width, NewH: pLayerTiles->m_Height); |
944 | } |
945 | } |
946 | else if(m_Prop == ETilesProp::PROP_SHIFT) |
947 | { |
948 | pLayerTiles->Shift(Direction: m_Current); |
949 | } |
950 | else if(m_Prop == ETilesProp::PROP_SHIFT_BY) |
951 | { |
952 | m_pEditor->m_ShiftBy = m_Current; |
953 | } |
954 | else if(m_Prop == ETilesProp::PROP_IMAGE) |
955 | { |
956 | if(m_Current == -1) |
957 | { |
958 | pLayerTiles->m_Image = -1; |
959 | } |
960 | else |
961 | { |
962 | pLayerTiles->m_Image = m_Current % m_pEditor->m_Map.m_vpImages.size(); |
963 | pLayerTiles->m_AutoMapperConfig = -1; |
964 | } |
965 | } |
966 | else if(m_Prop == ETilesProp::PROP_COLOR) |
967 | { |
968 | const ColorRGBA ColorPick = ColorRGBA::UnpackAlphaLast<ColorRGBA>(Color: m_Current); |
969 | |
970 | pLayerTiles->m_Color.r = ColorPick.r * 255.0f; |
971 | pLayerTiles->m_Color.g = ColorPick.g * 255.0f; |
972 | pLayerTiles->m_Color.b = ColorPick.b * 255.0f; |
973 | pLayerTiles->m_Color.a = ColorPick.a * 255.0f; |
974 | |
975 | m_pEditor->m_ColorPickerPopupContext.m_RgbaColor = ColorPick; |
976 | m_pEditor->m_ColorPickerPopupContext.m_HslaColor = color_cast<ColorHSLA>(rgb: ColorPick); |
977 | m_pEditor->m_ColorPickerPopupContext.m_HsvaColor = color_cast<ColorHSVA>(hsl: m_pEditor->m_ColorPickerPopupContext.m_HslaColor); |
978 | } |
979 | else if(m_Prop == ETilesProp::PROP_COLOR_ENV) |
980 | { |
981 | pLayerTiles->m_ColorEnv = m_Current; |
982 | } |
983 | else if(m_Prop == ETilesProp::PROP_COLOR_ENV_OFFSET) |
984 | { |
985 | pLayerTiles->m_ColorEnvOffset = m_Current; |
986 | } |
987 | else if(m_Prop == ETilesProp::PROP_AUTOMAPPER) |
988 | { |
989 | pLayerTiles->m_AutoMapperConfig = m_Current; |
990 | } |
991 | else if(m_Prop == ETilesProp::PROP_SEED) |
992 | { |
993 | pLayerTiles->m_Seed = m_Current; |
994 | } |
995 | |
996 | m_pEditor->m_Map.OnModify(); |
997 | } |
998 | |
999 | void CEditorActionEditLayerTilesProp::RestoreLayer(int Layer, const std::shared_ptr<CLayerTiles> &pLayerTiles) |
1000 | { |
1001 | if(m_SavedLayers[Layer] != nullptr) |
1002 | { |
1003 | std::shared_ptr<CLayerTiles> pSavedLayerTiles = std::static_pointer_cast<CLayerTiles>(r: m_SavedLayers[Layer]); |
1004 | mem_copy(dest: pLayerTiles->m_pTiles, source: pSavedLayerTiles->m_pTiles, size: (size_t)pLayerTiles->m_Width * pLayerTiles->m_Height * sizeof(CTile)); |
1005 | |
1006 | if(pLayerTiles->m_Tele) |
1007 | { |
1008 | std::shared_ptr<CLayerTele> pLayerTele = std::static_pointer_cast<CLayerTele>(r: pLayerTiles); |
1009 | std::shared_ptr<CLayerTele> pSavedLayerTele = std::static_pointer_cast<CLayerTele>(r: pSavedLayerTiles); |
1010 | mem_copy(dest: pLayerTele->m_pTeleTile, source: pSavedLayerTele->m_pTeleTile, size: (size_t)pLayerTiles->m_Width * pLayerTiles->m_Height * sizeof(CTeleTile)); |
1011 | } |
1012 | else if(pLayerTiles->m_Speedup) |
1013 | { |
1014 | std::shared_ptr<CLayerSpeedup> pLayerSpeedup = std::static_pointer_cast<CLayerSpeedup>(r: pLayerTiles); |
1015 | std::shared_ptr<CLayerSpeedup> pSavedLayerSpeedup = std::static_pointer_cast<CLayerSpeedup>(r: pSavedLayerTiles); |
1016 | mem_copy(dest: pLayerSpeedup->m_pSpeedupTile, source: pSavedLayerSpeedup->m_pSpeedupTile, size: (size_t)pLayerTiles->m_Width * pLayerTiles->m_Height * sizeof(CSpeedupTile)); |
1017 | } |
1018 | else if(pLayerTiles->m_Switch) |
1019 | { |
1020 | std::shared_ptr<CLayerSwitch> pLayerSwitch = std::static_pointer_cast<CLayerSwitch>(r: pLayerTiles); |
1021 | std::shared_ptr<CLayerSwitch> pSavedLayerSwitch = std::static_pointer_cast<CLayerSwitch>(r: pSavedLayerTiles); |
1022 | mem_copy(dest: pLayerSwitch->m_pSwitchTile, source: pSavedLayerSwitch->m_pSwitchTile, size: (size_t)pLayerTiles->m_Width * pLayerTiles->m_Height * sizeof(CSwitchTile)); |
1023 | } |
1024 | else if(pLayerTiles->m_Tune) |
1025 | { |
1026 | std::shared_ptr<CLayerTune> pLayerTune = std::static_pointer_cast<CLayerTune>(r: pLayerTiles); |
1027 | std::shared_ptr<CLayerTune> pSavedLayerTune = std::static_pointer_cast<CLayerTune>(r: pSavedLayerTiles); |
1028 | mem_copy(dest: pLayerTune->m_pTuneTile, source: pSavedLayerTune->m_pTuneTile, size: (size_t)pLayerTiles->m_Width * pLayerTiles->m_Height * sizeof(CTuneTile)); |
1029 | } |
1030 | } |
1031 | } |
1032 | |
1033 | CEditorActionEditLayerQuadsProp::CEditorActionEditLayerQuadsProp(CEditor *pEditor, int GroupIndex, int LayerIndex, ELayerQuadsProp Prop, int Previous, int Current) : |
1034 | CEditorActionEditLayerPropBase(pEditor, GroupIndex, LayerIndex, Prop, Previous, Current) |
1035 | { |
1036 | static const char *s_apNames[] = { |
1037 | "image" }; |
1038 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Edit quads layer %d in group %d %s property" , m_LayerIndex, m_GroupIndex, s_apNames[(int)m_Prop]); |
1039 | } |
1040 | |
1041 | void CEditorActionEditLayerQuadsProp::Undo() |
1042 | { |
1043 | Apply(Value: m_Previous); |
1044 | } |
1045 | |
1046 | void CEditorActionEditLayerQuadsProp::Redo() |
1047 | { |
1048 | Apply(Value: m_Current); |
1049 | } |
1050 | |
1051 | void CEditorActionEditLayerQuadsProp::Apply(int Value) |
1052 | { |
1053 | std::shared_ptr<CLayerQuads> pLayerQuads = std::static_pointer_cast<CLayerQuads>(r: m_pLayer); |
1054 | if(m_Prop == ELayerQuadsProp::PROP_IMAGE) |
1055 | { |
1056 | if(Value >= 0) |
1057 | pLayerQuads->m_Image = Value % m_pEditor->m_Map.m_vpImages.size(); |
1058 | else |
1059 | pLayerQuads->m_Image = -1; |
1060 | } |
1061 | |
1062 | m_pEditor->m_Map.OnModify(); |
1063 | } |
1064 | |
1065 | // -------------------------------------------------------------- |
1066 | |
1067 | CEditorActionEditLayersGroupAndOrder::CEditorActionEditLayersGroupAndOrder(CEditor *pEditor, int GroupIndex, const std::vector<int> &LayerIndices, int NewGroupIndex, const std::vector<int> &NewLayerIndices) : |
1068 | IEditorAction(pEditor), m_GroupIndex(GroupIndex), m_LayerIndices(LayerIndices), m_NewGroupIndex(NewGroupIndex), m_NewLayerIndices(NewLayerIndices) |
1069 | { |
1070 | std::sort(first: m_LayerIndices.begin(), last: m_LayerIndices.end()); |
1071 | std::sort(first: m_NewLayerIndices.begin(), last: m_NewLayerIndices.end()); |
1072 | |
1073 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Edit layers group and order (x%d)" , (int)m_LayerIndices.size()); |
1074 | } |
1075 | |
1076 | void CEditorActionEditLayersGroupAndOrder::Undo() |
1077 | { |
1078 | // Undo : restore group and order |
1079 | auto &Map = m_pEditor->m_Map; |
1080 | auto &pCurrentGroup = Map.m_vpGroups[m_NewGroupIndex]; |
1081 | auto &pPreviousGroup = Map.m_vpGroups[m_GroupIndex]; |
1082 | std::vector<std::shared_ptr<CLayer>> vpLayers; |
1083 | vpLayers.reserve(n: m_NewLayerIndices.size()); |
1084 | for(auto &LayerIndex : m_NewLayerIndices) |
1085 | vpLayers.push_back(x: pCurrentGroup->m_vpLayers[LayerIndex]); |
1086 | |
1087 | int k = 0; |
1088 | for(auto &pLayer : vpLayers) |
1089 | { |
1090 | pCurrentGroup->m_vpLayers.erase(position: std::find(first: pCurrentGroup->m_vpLayers.begin(), last: pCurrentGroup->m_vpLayers.end(), val: pLayer)); |
1091 | pPreviousGroup->m_vpLayers.insert(position: pPreviousGroup->m_vpLayers.begin() + m_LayerIndices[k++], x: pLayer); |
1092 | } |
1093 | |
1094 | m_pEditor->m_vSelectedLayers = m_LayerIndices; |
1095 | m_pEditor->m_SelectedGroup = m_GroupIndex; |
1096 | } |
1097 | |
1098 | void CEditorActionEditLayersGroupAndOrder::Redo() |
1099 | { |
1100 | // Redo : move layers |
1101 | auto &Map = m_pEditor->m_Map; |
1102 | auto &pCurrentGroup = Map.m_vpGroups[m_GroupIndex]; |
1103 | auto &pPreviousGroup = Map.m_vpGroups[m_NewGroupIndex]; |
1104 | std::vector<std::shared_ptr<CLayer>> vpLayers; |
1105 | vpLayers.reserve(n: m_LayerIndices.size()); |
1106 | for(auto &LayerIndex : m_LayerIndices) |
1107 | vpLayers.push_back(x: pCurrentGroup->m_vpLayers[LayerIndex]); |
1108 | |
1109 | int k = 0; |
1110 | for(auto &pLayer : vpLayers) |
1111 | { |
1112 | pCurrentGroup->m_vpLayers.erase(position: std::find(first: pCurrentGroup->m_vpLayers.begin(), last: pCurrentGroup->m_vpLayers.end(), val: pLayer)); |
1113 | pPreviousGroup->m_vpLayers.insert(position: pPreviousGroup->m_vpLayers.begin() + m_NewLayerIndices[k++], x: pLayer); |
1114 | } |
1115 | |
1116 | m_pEditor->m_vSelectedLayers = m_NewLayerIndices; |
1117 | m_pEditor->m_SelectedGroup = m_NewGroupIndex; |
1118 | } |
1119 | |
1120 | // ----------------------------------- |
1121 | |
1122 | CEditorActionAppendMap::CEditorActionAppendMap(CEditor *pEditor, const char *pMapName, const SPrevInfo &PrevInfo, std::vector<int> &vImageIndexMap) : |
1123 | IEditorAction(pEditor), m_PrevInfo(PrevInfo), m_vImageIndexMap(vImageIndexMap) |
1124 | { |
1125 | str_copy(dst&: m_aMapName, src: pMapName); |
1126 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Append %s" , m_aMapName); |
1127 | } |
1128 | |
1129 | void CEditorActionAppendMap::Undo() |
1130 | { |
1131 | auto &Map = m_pEditor->m_Map; |
1132 | // Undo append: |
1133 | // - delete added groups |
1134 | // - delete added envelopes |
1135 | // - delete added images |
1136 | // - delete added sounds |
1137 | |
1138 | // Delete added groups |
1139 | while((int)Map.m_vpGroups.size() != m_PrevInfo.m_Groups) |
1140 | { |
1141 | Map.m_vpGroups.pop_back(); |
1142 | } |
1143 | |
1144 | // Delete added envelopes |
1145 | while((int)Map.m_vpEnvelopes.size() != m_PrevInfo.m_Envelopes) |
1146 | { |
1147 | Map.m_vpEnvelopes.pop_back(); |
1148 | } |
1149 | |
1150 | // Delete added sounds |
1151 | while((int)Map.m_vpSounds.size() != m_PrevInfo.m_Sounds) |
1152 | { |
1153 | Map.m_vpSounds.pop_back(); |
1154 | } |
1155 | |
1156 | // Delete added images |
1157 | // Images are sorted when appending, so we need to revert sorting before deleting the images |
1158 | if(!m_vImageIndexMap.empty()) |
1159 | { |
1160 | std::vector<int> vReverseIndexMap; |
1161 | vReverseIndexMap.resize(new_size: m_vImageIndexMap.size()); |
1162 | |
1163 | for(int k = 0; k < (int)m_vImageIndexMap.size(); k++) |
1164 | vReverseIndexMap[m_vImageIndexMap[k]] = k; |
1165 | |
1166 | std::vector<std::shared_ptr<CEditorImage>> vpRevertedImages; |
1167 | vpRevertedImages.resize(new_size: Map.m_vpImages.size()); |
1168 | |
1169 | for(int k = 0; k < (int)vReverseIndexMap.size(); k++) |
1170 | { |
1171 | vpRevertedImages[vReverseIndexMap[k]] = Map.m_vpImages[k]; |
1172 | } |
1173 | Map.m_vpImages = vpRevertedImages; |
1174 | |
1175 | Map.ModifyImageIndex(pfnFunc: [vReverseIndexMap](int *pIndex) { |
1176 | if(*pIndex >= 0) |
1177 | { |
1178 | *pIndex = vReverseIndexMap[*pIndex]; |
1179 | } |
1180 | }); |
1181 | } |
1182 | |
1183 | while((int)Map.m_vpImages.size() != m_PrevInfo.m_Images) |
1184 | { |
1185 | Map.m_vpImages.pop_back(); |
1186 | } |
1187 | } |
1188 | |
1189 | void CEditorActionAppendMap::Redo() |
1190 | { |
1191 | // Redo is just re-appending the same map |
1192 | m_pEditor->Append(pFilename: m_aMapName, StorageType: IStorage::TYPE_ALL, IgnoreHistory: true); |
1193 | } |
1194 | |
1195 | // --------------------------- |
1196 | |
1197 | CEditorActionTileArt::CEditorActionTileArt(CEditor *pEditor, int PreviousImageCount, const char *pTileArtFile, std::vector<int> &vImageIndexMap) : |
1198 | IEditorAction(pEditor), m_PreviousImageCount(PreviousImageCount), m_vImageIndexMap(vImageIndexMap) |
1199 | { |
1200 | str_copy(dst&: m_aTileArtFile, src: pTileArtFile); |
1201 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Tile art" ); |
1202 | } |
1203 | |
1204 | void CEditorActionTileArt::Undo() |
1205 | { |
1206 | auto &Map = m_pEditor->m_Map; |
1207 | |
1208 | // Delete added group |
1209 | Map.m_vpGroups.pop_back(); |
1210 | |
1211 | // Delete added images |
1212 | // Images are sorted when appending, so we need to revert sorting before deleting the images |
1213 | if(!m_vImageIndexMap.empty()) |
1214 | { |
1215 | std::vector<int> vReverseIndexMap; |
1216 | vReverseIndexMap.resize(new_size: m_vImageIndexMap.size()); |
1217 | |
1218 | for(int k = 0; k < (int)m_vImageIndexMap.size(); k++) |
1219 | vReverseIndexMap[m_vImageIndexMap[k]] = k; |
1220 | |
1221 | std::vector<std::shared_ptr<CEditorImage>> vpRevertedImages; |
1222 | vpRevertedImages.resize(new_size: Map.m_vpImages.size()); |
1223 | |
1224 | for(int k = 0; k < (int)vReverseIndexMap.size(); k++) |
1225 | { |
1226 | vpRevertedImages[vReverseIndexMap[k]] = Map.m_vpImages[k]; |
1227 | } |
1228 | Map.m_vpImages = vpRevertedImages; |
1229 | |
1230 | Map.ModifyImageIndex(pfnFunc: [vReverseIndexMap](int *pIndex) { |
1231 | if(*pIndex >= 0) |
1232 | { |
1233 | *pIndex = vReverseIndexMap[*pIndex]; |
1234 | } |
1235 | }); |
1236 | } |
1237 | |
1238 | while((int)Map.m_vpImages.size() != m_PreviousImageCount) |
1239 | { |
1240 | Map.m_vpImages.pop_back(); |
1241 | } |
1242 | } |
1243 | |
1244 | void CEditorActionTileArt::Redo() |
1245 | { |
1246 | if(!m_pEditor->Graphics()->LoadPng(Image&: m_pEditor->m_TileartImageInfo, pFilename: m_aTileArtFile, StorageType: IStorage::TYPE_ALL)) |
1247 | { |
1248 | m_pEditor->ShowFileDialogError(pFormat: "Failed to load image from file '%s'." , m_aTileArtFile); |
1249 | return; |
1250 | } |
1251 | |
1252 | IStorage::StripPathAndExtension(pFilename: m_aTileArtFile, pBuffer: m_pEditor->m_aTileartFilename, BufferSize: sizeof(m_pEditor->m_aTileartFilename)); |
1253 | m_pEditor->AddTileart(IgnoreHistory: true); |
1254 | } |
1255 | |
1256 | // --------------------------------- |
1257 | |
1258 | CEditorCommandAction::CEditorCommandAction(CEditor *pEditor, EType Type, int *pSelectedCommandIndex, int CommandIndex, const char *pPreviousCommand, const char *pCurrentCommand) : |
1259 | IEditorAction(pEditor), m_Type(Type), m_pSelectedCommandIndex(pSelectedCommandIndex), m_CommandIndex(CommandIndex) |
1260 | { |
1261 | if(pPreviousCommand != nullptr) |
1262 | m_PreviousCommand = std::string(pPreviousCommand); |
1263 | if(pCurrentCommand != nullptr) |
1264 | m_CurrentCommand = std::string(pCurrentCommand); |
1265 | |
1266 | switch(m_Type) |
1267 | { |
1268 | case EType::ADD: |
1269 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Add command" ); |
1270 | break; |
1271 | case EType::EDIT: |
1272 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Edit command %d" , m_CommandIndex); |
1273 | break; |
1274 | case EType::DELETE: |
1275 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Delete command %d" , m_CommandIndex); |
1276 | break; |
1277 | case EType::MOVE_UP: |
1278 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Move command %d up" , m_CommandIndex); |
1279 | break; |
1280 | case EType::MOVE_DOWN: |
1281 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Move command %d down" , m_CommandIndex); |
1282 | break; |
1283 | default: |
1284 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Edit command %d" , m_CommandIndex); |
1285 | break; |
1286 | } |
1287 | } |
1288 | |
1289 | void CEditorCommandAction::Undo() |
1290 | { |
1291 | auto &Map = m_pEditor->m_Map; |
1292 | switch(m_Type) |
1293 | { |
1294 | case EType::DELETE: |
1295 | { |
1296 | Map.m_vSettings.insert(position: Map.m_vSettings.begin() + m_CommandIndex, x: m_PreviousCommand.c_str()); |
1297 | *m_pSelectedCommandIndex = m_CommandIndex; |
1298 | break; |
1299 | } |
1300 | case EType::ADD: |
1301 | { |
1302 | Map.m_vSettings.erase(position: Map.m_vSettings.begin() + m_CommandIndex); |
1303 | *m_pSelectedCommandIndex = Map.m_vSettings.size() - 1; |
1304 | break; |
1305 | } |
1306 | case EType::EDIT: |
1307 | { |
1308 | str_copy(dst&: Map.m_vSettings[m_CommandIndex].m_aCommand, src: m_PreviousCommand.c_str()); |
1309 | *m_pSelectedCommandIndex = m_CommandIndex; |
1310 | break; |
1311 | } |
1312 | case EType::MOVE_DOWN: |
1313 | { |
1314 | std::swap(a&: Map.m_vSettings[m_CommandIndex], b&: Map.m_vSettings[m_CommandIndex + 1]); |
1315 | *m_pSelectedCommandIndex = m_CommandIndex; |
1316 | break; |
1317 | } |
1318 | case EType::MOVE_UP: |
1319 | { |
1320 | std::swap(a&: Map.m_vSettings[m_CommandIndex], b&: Map.m_vSettings[m_CommandIndex - 1]); |
1321 | *m_pSelectedCommandIndex = m_CommandIndex; |
1322 | break; |
1323 | } |
1324 | } |
1325 | } |
1326 | |
1327 | void CEditorCommandAction::Redo() |
1328 | { |
1329 | auto &Map = m_pEditor->m_Map; |
1330 | switch(m_Type) |
1331 | { |
1332 | case EType::DELETE: |
1333 | { |
1334 | Map.m_vSettings.erase(position: Map.m_vSettings.begin() + m_CommandIndex); |
1335 | *m_pSelectedCommandIndex = Map.m_vSettings.size() - 1; |
1336 | break; |
1337 | } |
1338 | case EType::ADD: |
1339 | { |
1340 | Map.m_vSettings.insert(position: Map.m_vSettings.begin() + m_CommandIndex, x: m_PreviousCommand.c_str()); |
1341 | *m_pSelectedCommandIndex = m_CommandIndex; |
1342 | break; |
1343 | } |
1344 | case EType::EDIT: |
1345 | { |
1346 | str_copy(dst&: Map.m_vSettings[m_CommandIndex].m_aCommand, src: m_CurrentCommand.c_str()); |
1347 | *m_pSelectedCommandIndex = m_CommandIndex; |
1348 | break; |
1349 | } |
1350 | case EType::MOVE_DOWN: |
1351 | { |
1352 | std::swap(a&: Map.m_vSettings[m_CommandIndex], b&: Map.m_vSettings[m_CommandIndex + 1]); |
1353 | *m_pSelectedCommandIndex = m_CommandIndex; |
1354 | break; |
1355 | } |
1356 | case EType::MOVE_UP: |
1357 | { |
1358 | std::swap(a&: Map.m_vSettings[m_CommandIndex], b&: Map.m_vSettings[m_CommandIndex - 1]); |
1359 | *m_pSelectedCommandIndex = m_CommandIndex; |
1360 | break; |
1361 | } |
1362 | } |
1363 | } |
1364 | |
1365 | // ------------------------------------------------ |
1366 | |
1367 | CEditorActionEnvelopeAdd::CEditorActionEnvelopeAdd(CEditor *pEditor, const std::shared_ptr<CEnvelope> &pEnv) : |
1368 | IEditorAction(pEditor), m_pEnv(pEnv) |
1369 | { |
1370 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Add new %s envelope" , pEnv->Type() == CEnvelope::EType::COLOR ? "color" : (pEnv->Type() == CEnvelope::EType::POSITION ? "position" : "sound" )); |
1371 | } |
1372 | |
1373 | void CEditorActionEnvelopeAdd::Undo() |
1374 | { |
1375 | // Undo is removing the envelope, which was added at the back of the list |
1376 | m_pEditor->m_Map.m_vpEnvelopes.pop_back(); |
1377 | m_pEditor->m_SelectedEnvelope = m_pEditor->m_Map.m_vpEnvelopes.size() - 1; |
1378 | } |
1379 | |
1380 | void CEditorActionEnvelopeAdd::Redo() |
1381 | { |
1382 | // Redo is adding back at the back the saved envelope |
1383 | m_pEditor->m_Map.m_vpEnvelopes.push_back(x: m_pEnv); |
1384 | m_pEditor->m_SelectedEnvelope = m_pEditor->m_Map.m_vpEnvelopes.size() - 1; |
1385 | } |
1386 | |
1387 | CEditorActionEveloppeDelete::CEditorActionEveloppeDelete(CEditor *pEditor, int EnvelopeIndex) : |
1388 | IEditorAction(pEditor), m_EnvelopeIndex(EnvelopeIndex), m_pEnv(pEditor->m_Map.m_vpEnvelopes[EnvelopeIndex]) |
1389 | { |
1390 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Delete envelope %d" , m_EnvelopeIndex); |
1391 | } |
1392 | |
1393 | void CEditorActionEveloppeDelete::Undo() |
1394 | { |
1395 | // Undo is adding back the envelope |
1396 | m_pEditor->m_Map.m_vpEnvelopes.insert(position: m_pEditor->m_Map.m_vpEnvelopes.begin() + m_EnvelopeIndex, x: m_pEnv); |
1397 | m_pEditor->m_SelectedEnvelope = m_EnvelopeIndex; |
1398 | } |
1399 | |
1400 | void CEditorActionEveloppeDelete::Redo() |
1401 | { |
1402 | // Redo is erasing the same envelope index |
1403 | m_pEditor->m_Map.m_vpEnvelopes.erase(position: m_pEditor->m_Map.m_vpEnvelopes.begin() + m_EnvelopeIndex); |
1404 | if(m_pEditor->m_SelectedEnvelope >= (int)m_pEditor->m_Map.m_vpEnvelopes.size()) |
1405 | m_pEditor->m_SelectedEnvelope = m_pEditor->m_Map.m_vpEnvelopes.size() - 1; |
1406 | } |
1407 | |
1408 | CEditorActionEnvelopeEdit::CEditorActionEnvelopeEdit(CEditor *pEditor, int EnvelopeIndex, EEditType EditType, int Previous, int Current) : |
1409 | IEditorAction(pEditor), m_EnvelopeIndex(EnvelopeIndex), m_EditType(EditType), m_Previous(Previous), m_Current(Current), m_pEnv(pEditor->m_Map.m_vpEnvelopes[EnvelopeIndex]) |
1410 | { |
1411 | static const char *s_apNames[] = { |
1412 | "sync" , |
1413 | "order" }; |
1414 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Edit envelope %d %s" , m_EnvelopeIndex, s_apNames[(int)m_EditType]); |
1415 | } |
1416 | |
1417 | void CEditorActionEnvelopeEdit::Undo() |
1418 | { |
1419 | switch(m_EditType) |
1420 | { |
1421 | case EEditType::ORDER: |
1422 | { |
1423 | m_pEditor->m_Map.SwapEnvelopes(Index0: m_Current, Index1: m_Previous); |
1424 | break; |
1425 | } |
1426 | case EEditType::SYNC: |
1427 | { |
1428 | m_pEnv->m_Synchronized = m_Previous; |
1429 | break; |
1430 | } |
1431 | } |
1432 | m_pEditor->m_Map.OnModify(); |
1433 | m_pEditor->m_SelectedEnvelope = m_EnvelopeIndex; |
1434 | } |
1435 | |
1436 | void CEditorActionEnvelopeEdit::Redo() |
1437 | { |
1438 | switch(m_EditType) |
1439 | { |
1440 | case EEditType::ORDER: |
1441 | { |
1442 | m_pEditor->m_Map.SwapEnvelopes(Index0: m_Previous, Index1: m_Current); |
1443 | break; |
1444 | } |
1445 | case EEditType::SYNC: |
1446 | { |
1447 | m_pEnv->m_Synchronized = m_Current; |
1448 | break; |
1449 | } |
1450 | } |
1451 | m_pEditor->m_Map.OnModify(); |
1452 | m_pEditor->m_SelectedEnvelope = m_EnvelopeIndex; |
1453 | } |
1454 | |
1455 | CEditorActionEnvelopeEditPoint::CEditorActionEnvelopeEditPoint(CEditor *pEditor, int EnvelopeIndex, int PointIndex, int Channel, EEditType EditType, int Previous, int Current) : |
1456 | IEditorAction(pEditor), m_EnvelopeIndex(EnvelopeIndex), m_PointIndex(PointIndex), m_Channel(Channel), m_EditType(EditType), m_Previous(Previous), m_Current(Current), m_pEnv(pEditor->m_Map.m_vpEnvelopes[EnvelopeIndex]) |
1457 | { |
1458 | static const char *s_apNames[] = { |
1459 | "time" , |
1460 | "value" , |
1461 | "curve type" }; |
1462 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Edit %s of point %d (channel %d) of env %d" , s_apNames[(int)m_EditType], m_PointIndex, m_Channel, m_EnvelopeIndex); |
1463 | } |
1464 | |
1465 | void CEditorActionEnvelopeEditPoint::Undo() |
1466 | { |
1467 | Apply(Value: m_Previous); |
1468 | } |
1469 | |
1470 | void CEditorActionEnvelopeEditPoint::Redo() |
1471 | { |
1472 | Apply(Value: m_Current); |
1473 | } |
1474 | |
1475 | void CEditorActionEnvelopeEditPoint::Apply(int Value) |
1476 | { |
1477 | if(m_EditType == EEditType::TIME) |
1478 | { |
1479 | m_pEnv->m_vPoints[m_PointIndex].m_Time = Value; |
1480 | } |
1481 | else if(m_EditType == EEditType::VALUE) |
1482 | { |
1483 | m_pEnv->m_vPoints[m_PointIndex].m_aValues[m_Channel] = Value; |
1484 | |
1485 | if(m_pEnv->GetChannels() == 4) |
1486 | { |
1487 | auto *pValues = m_pEnv->m_vPoints[m_PointIndex].m_aValues; |
1488 | const ColorRGBA Color = ColorRGBA(fx2f(v: pValues[0]), fx2f(v: pValues[1]), fx2f(v: pValues[2]), fx2f(v: pValues[3])); |
1489 | |
1490 | m_pEditor->m_ColorPickerPopupContext.m_RgbaColor = Color; |
1491 | m_pEditor->m_ColorPickerPopupContext.m_HslaColor = color_cast<ColorHSLA>(rgb: Color); |
1492 | m_pEditor->m_ColorPickerPopupContext.m_HsvaColor = color_cast<ColorHSVA>(hsl: m_pEditor->m_ColorPickerPopupContext.m_HslaColor); |
1493 | } |
1494 | } |
1495 | else if(m_EditType == EEditType::CURVE_TYPE) |
1496 | { |
1497 | m_pEnv->m_vPoints[m_PointIndex].m_Curvetype = Value; |
1498 | } |
1499 | |
1500 | m_pEditor->m_Map.OnModify(); |
1501 | } |
1502 | |
1503 | // ---- |
1504 | |
1505 | CEditorActionEditEnvelopePointValue::CEditorActionEditEnvelopePointValue(CEditor *pEditor, int EnvIndex, int PointIndex, int Channel, EType Type, int OldTime, int OldValue, int NewTime, int NewValue) : |
1506 | IEditorAction(pEditor), m_EnvIndex(EnvIndex), m_PtIndex(PointIndex), m_Channel(Channel), m_Type(Type), m_OldTime(OldTime), m_OldValue(OldValue), m_NewTime(NewTime), m_NewValue(NewValue) |
1507 | { |
1508 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Edit point %d%s value (envelope %d, channel %d)" , PointIndex, m_Type == EType::TANGENT_IN ? "tangent in" : (m_Type == EType::TANGENT_OUT ? "tangent out" : "" ), m_EnvIndex, m_Channel); |
1509 | } |
1510 | |
1511 | void CEditorActionEditEnvelopePointValue::Undo() |
1512 | { |
1513 | Apply(Undo: true); |
1514 | } |
1515 | |
1516 | void CEditorActionEditEnvelopePointValue::Redo() |
1517 | { |
1518 | Apply(Undo: false); |
1519 | } |
1520 | |
1521 | void CEditorActionEditEnvelopePointValue::Apply(bool Undo) |
1522 | { |
1523 | float CurrentValue = fx2f(v: Undo ? m_OldValue : m_NewValue); |
1524 | float CurrentTime = (Undo ? m_OldTime : m_NewTime) / 1000.0f; |
1525 | |
1526 | std::shared_ptr<CEnvelope> pEnvelope = m_pEditor->m_Map.m_vpEnvelopes[m_EnvIndex]; |
1527 | if(m_Type == EType::TANGENT_IN) |
1528 | { |
1529 | pEnvelope->m_vPoints[m_PtIndex].m_Bezier.m_aInTangentDeltaX[m_Channel] = minimum<int>(a: CurrentTime * 1000.0f - pEnvelope->m_vPoints[m_PtIndex].m_Time, b: 0); |
1530 | pEnvelope->m_vPoints[m_PtIndex].m_Bezier.m_aInTangentDeltaY[m_Channel] = f2fx(v: CurrentValue) - pEnvelope->m_vPoints[m_PtIndex].m_aValues[m_Channel]; |
1531 | } |
1532 | else if(m_Type == EType::TANGENT_OUT) |
1533 | { |
1534 | pEnvelope->m_vPoints[m_PtIndex].m_Bezier.m_aOutTangentDeltaX[m_Channel] = maximum<int>(a: CurrentTime * 1000.0f - pEnvelope->m_vPoints[m_PtIndex].m_Time, b: 0); |
1535 | pEnvelope->m_vPoints[m_PtIndex].m_Bezier.m_aOutTangentDeltaY[m_Channel] = f2fx(v: CurrentValue) - pEnvelope->m_vPoints[m_PtIndex].m_aValues[m_Channel]; |
1536 | } |
1537 | else |
1538 | { |
1539 | if(pEnvelope->GetChannels() == 1 || pEnvelope->GetChannels() == 4) |
1540 | CurrentValue = clamp(val: CurrentValue, lo: 0.0f, hi: 1.0f); |
1541 | pEnvelope->m_vPoints[m_PtIndex].m_aValues[m_Channel] = f2fx(v: CurrentValue); |
1542 | |
1543 | if(m_PtIndex != 0) |
1544 | { |
1545 | pEnvelope->m_vPoints[m_PtIndex].m_Time = CurrentTime * 1000.0f; |
1546 | |
1547 | if(pEnvelope->m_vPoints[m_PtIndex].m_Time < pEnvelope->m_vPoints[m_PtIndex - 1].m_Time) |
1548 | pEnvelope->m_vPoints[m_PtIndex].m_Time = pEnvelope->m_vPoints[m_PtIndex - 1].m_Time + 1; |
1549 | if(static_cast<size_t>(m_PtIndex) + 1 != pEnvelope->m_vPoints.size() && pEnvelope->m_vPoints[m_PtIndex].m_Time > pEnvelope->m_vPoints[m_PtIndex + 1].m_Time) |
1550 | pEnvelope->m_vPoints[m_PtIndex].m_Time = pEnvelope->m_vPoints[m_PtIndex + 1].m_Time - 1; |
1551 | } |
1552 | else |
1553 | { |
1554 | pEnvelope->m_vPoints[m_PtIndex].m_Time = 0.0f; |
1555 | } |
1556 | } |
1557 | |
1558 | m_pEditor->m_Map.OnModify(); |
1559 | m_pEditor->m_UpdateEnvPointInfo = true; |
1560 | } |
1561 | |
1562 | // --------------------- |
1563 | |
1564 | CEditorActionResetEnvelopePointTangent::CEditorActionResetEnvelopePointTangent(CEditor *pEditor, int EnvIndex, int PointIndex, int Channel, bool In) : |
1565 | IEditorAction(pEditor), m_EnvIndex(EnvIndex), m_PointIndex(PointIndex), m_Channel(Channel), m_In(In) |
1566 | { |
1567 | std::shared_ptr<CEnvelope> pEnvelope = pEditor->m_Map.m_vpEnvelopes[EnvIndex]; |
1568 | if(In) |
1569 | { |
1570 | m_Previous[0] = pEnvelope->m_vPoints[PointIndex].m_Bezier.m_aInTangentDeltaX[Channel]; |
1571 | m_Previous[1] = pEnvelope->m_vPoints[PointIndex].m_Bezier.m_aInTangentDeltaY[Channel]; |
1572 | } |
1573 | else |
1574 | { |
1575 | m_Previous[0] = pEnvelope->m_vPoints[PointIndex].m_Bezier.m_aOutTangentDeltaX[Channel]; |
1576 | m_Previous[1] = pEnvelope->m_vPoints[PointIndex].m_Bezier.m_aOutTangentDeltaY[Channel]; |
1577 | } |
1578 | |
1579 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Reset point %d of env %d tangent %s" , m_PointIndex, m_EnvIndex, m_In ? "in" : "out" ); |
1580 | } |
1581 | |
1582 | void CEditorActionResetEnvelopePointTangent::Undo() |
1583 | { |
1584 | std::shared_ptr<CEnvelope> pEnvelope = m_pEditor->m_Map.m_vpEnvelopes[m_EnvIndex]; |
1585 | if(m_In) |
1586 | { |
1587 | pEnvelope->m_vPoints[m_PointIndex].m_Bezier.m_aInTangentDeltaX[m_Channel] = m_Previous[0]; |
1588 | pEnvelope->m_vPoints[m_PointIndex].m_Bezier.m_aInTangentDeltaY[m_Channel] = m_Previous[1]; |
1589 | } |
1590 | else |
1591 | { |
1592 | pEnvelope->m_vPoints[m_PointIndex].m_Bezier.m_aOutTangentDeltaX[m_Channel] = m_Previous[0]; |
1593 | pEnvelope->m_vPoints[m_PointIndex].m_Bezier.m_aOutTangentDeltaY[m_Channel] = m_Previous[1]; |
1594 | } |
1595 | m_pEditor->m_Map.OnModify(); |
1596 | } |
1597 | |
1598 | void CEditorActionResetEnvelopePointTangent::Redo() |
1599 | { |
1600 | std::shared_ptr<CEnvelope> pEnvelope = m_pEditor->m_Map.m_vpEnvelopes[m_EnvIndex]; |
1601 | if(m_In) |
1602 | { |
1603 | pEnvelope->m_vPoints[m_PointIndex].m_Bezier.m_aInTangentDeltaX[m_Channel] = 0.0f; |
1604 | pEnvelope->m_vPoints[m_PointIndex].m_Bezier.m_aInTangentDeltaY[m_Channel] = 0.0f; |
1605 | } |
1606 | else |
1607 | { |
1608 | pEnvelope->m_vPoints[m_PointIndex].m_Bezier.m_aOutTangentDeltaX[m_Channel] = 0.0f; |
1609 | pEnvelope->m_vPoints[m_PointIndex].m_Bezier.m_aOutTangentDeltaY[m_Channel] = 0.0f; |
1610 | } |
1611 | m_pEditor->m_Map.OnModify(); |
1612 | } |
1613 | |
1614 | // ------------------ |
1615 | |
1616 | CEditorActionAddEnvelopePoint::CEditorActionAddEnvelopePoint(CEditor *pEditor, int EnvIndex, int Time, ColorRGBA Channels) : |
1617 | IEditorAction(pEditor), m_EnvIndex(EnvIndex), m_Time(Time), m_Channels(Channels) |
1618 | { |
1619 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Add new point in envelope %d at time %f" , m_EnvIndex, Time / 1000.0); |
1620 | } |
1621 | |
1622 | void CEditorActionAddEnvelopePoint::Undo() |
1623 | { |
1624 | // Delete added point |
1625 | auto pEnvelope = m_pEditor->m_Map.m_vpEnvelopes[m_EnvIndex]; |
1626 | auto pIt = std::find_if(first: pEnvelope->m_vPoints.begin(), last: pEnvelope->m_vPoints.end(), pred: [this](const CEnvPoint_runtime &Point) { |
1627 | return Point.m_Time == m_Time; |
1628 | }); |
1629 | if(pIt != pEnvelope->m_vPoints.end()) |
1630 | { |
1631 | pEnvelope->m_vPoints.erase(position: pIt); |
1632 | } |
1633 | |
1634 | m_pEditor->m_Map.OnModify(); |
1635 | } |
1636 | |
1637 | void CEditorActionAddEnvelopePoint::Redo() |
1638 | { |
1639 | auto pEnvelope = m_pEditor->m_Map.m_vpEnvelopes[m_EnvIndex]; |
1640 | pEnvelope->AddPoint(Time: m_Time, |
1641 | v0: f2fx(v: m_Channels.r), v1: f2fx(v: m_Channels.g), |
1642 | v2: f2fx(v: m_Channels.b), v3: f2fx(v: m_Channels.a)); |
1643 | |
1644 | m_pEditor->m_Map.OnModify(); |
1645 | } |
1646 | |
1647 | CEditorActionDeleteEnvelopePoint::CEditorActionDeleteEnvelopePoint(CEditor *pEditor, int EnvIndex, int PointIndex) : |
1648 | IEditorAction(pEditor), m_EnvIndex(EnvIndex), m_PointIndex(PointIndex), m_Point(pEditor->m_Map.m_vpEnvelopes[EnvIndex]->m_vPoints[PointIndex]) |
1649 | { |
1650 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Delete point %d of envelope %d" , m_PointIndex, m_EnvIndex); |
1651 | } |
1652 | |
1653 | void CEditorActionDeleteEnvelopePoint::Undo() |
1654 | { |
1655 | std::shared_ptr<CEnvelope> pEnvelope = m_pEditor->m_Map.m_vpEnvelopes[m_EnvIndex]; |
1656 | pEnvelope->m_vPoints.insert(position: pEnvelope->m_vPoints.begin() + m_PointIndex, x: m_Point); |
1657 | |
1658 | m_pEditor->m_Map.OnModify(); |
1659 | } |
1660 | |
1661 | void CEditorActionDeleteEnvelopePoint::Redo() |
1662 | { |
1663 | std::shared_ptr<CEnvelope> pEnvelope = m_pEditor->m_Map.m_vpEnvelopes[m_EnvIndex]; |
1664 | pEnvelope->m_vPoints.erase(position: pEnvelope->m_vPoints.begin() + m_PointIndex); |
1665 | |
1666 | auto pSelectedPointIt = std::find_if(first: m_pEditor->m_vSelectedEnvelopePoints.begin(), last: m_pEditor->m_vSelectedEnvelopePoints.end(), pred: [this](const std::pair<int, int> Pair) { |
1667 | return Pair.first == m_PointIndex; |
1668 | }); |
1669 | |
1670 | if(pSelectedPointIt != m_pEditor->m_vSelectedEnvelopePoints.end()) |
1671 | m_pEditor->m_vSelectedEnvelopePoints.erase(position: pSelectedPointIt); |
1672 | |
1673 | m_pEditor->m_Map.OnModify(); |
1674 | } |
1675 | |
1676 | // ------------------------------- |
1677 | |
1678 | CEditorActionEditLayerSoundsProp::CEditorActionEditLayerSoundsProp(CEditor *pEditor, int GroupIndex, int LayerIndex, ELayerSoundsProp Prop, int Previous, int Current) : |
1679 | CEditorActionEditLayerPropBase(pEditor, GroupIndex, LayerIndex, Prop, Previous, Current) |
1680 | { |
1681 | static const char *s_apNames[] = { |
1682 | "sound" }; |
1683 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Edit sounds layer %d in group %d %s property" , m_LayerIndex, m_GroupIndex, s_apNames[(int)m_Prop]); |
1684 | } |
1685 | |
1686 | void CEditorActionEditLayerSoundsProp::Undo() |
1687 | { |
1688 | Apply(Value: m_Previous); |
1689 | } |
1690 | |
1691 | void CEditorActionEditLayerSoundsProp::Redo() |
1692 | { |
1693 | Apply(Value: m_Current); |
1694 | } |
1695 | |
1696 | void CEditorActionEditLayerSoundsProp::Apply(int Value) |
1697 | { |
1698 | std::shared_ptr<CLayerSounds> pLayerSounds = std::static_pointer_cast<CLayerSounds>(r: m_pLayer); |
1699 | if(m_Prop == ELayerSoundsProp::PROP_SOUND) |
1700 | { |
1701 | if(Value >= 0) |
1702 | pLayerSounds->m_Sound = Value % m_pEditor->m_Map.m_vpSounds.size(); |
1703 | else |
1704 | pLayerSounds->m_Sound = -1; |
1705 | } |
1706 | |
1707 | m_pEditor->m_Map.OnModify(); |
1708 | } |
1709 | |
1710 | // --- |
1711 | |
1712 | CEditorActionDeleteSoundSource::CEditorActionDeleteSoundSource(CEditor *pEditor, int GroupIndex, int LayerIndex, int SourceIndex) : |
1713 | CEditorActionLayerBase(pEditor, GroupIndex, LayerIndex), m_SourceIndex(SourceIndex) |
1714 | { |
1715 | std::shared_ptr<CLayerSounds> pLayerSounds = std::static_pointer_cast<CLayerSounds>(r: m_pLayer); |
1716 | m_Source = pLayerSounds->m_vSources[SourceIndex]; |
1717 | |
1718 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Delete sound source %d in layer %d of group %d" , SourceIndex, LayerIndex, GroupIndex); |
1719 | } |
1720 | |
1721 | void CEditorActionDeleteSoundSource::Undo() |
1722 | { |
1723 | std::shared_ptr<CLayerSounds> pLayerSounds = std::static_pointer_cast<CLayerSounds>(r: m_pLayer); |
1724 | pLayerSounds->m_vSources.insert(position: pLayerSounds->m_vSources.begin() + m_SourceIndex, x: m_Source); |
1725 | m_pEditor->m_SelectedSource = m_SourceIndex; |
1726 | m_pEditor->m_Map.OnModify(); |
1727 | } |
1728 | |
1729 | void CEditorActionDeleteSoundSource::Redo() |
1730 | { |
1731 | std::shared_ptr<CLayerSounds> pLayerSounds = std::static_pointer_cast<CLayerSounds>(r: m_pLayer); |
1732 | pLayerSounds->m_vSources.erase(position: pLayerSounds->m_vSources.begin() + m_SourceIndex); |
1733 | m_pEditor->m_SelectedSource--; |
1734 | m_pEditor->m_Map.OnModify(); |
1735 | } |
1736 | |
1737 | // --------------- |
1738 | |
1739 | CEditorActionEditSoundSource::CEditorActionEditSoundSource(CEditor *pEditor, int GroupIndex, int LayerIndex, int SourceIndex, EEditType Type, int Value) : |
1740 | CEditorActionLayerBase(pEditor, GroupIndex, LayerIndex), m_SourceIndex(SourceIndex), m_EditType(Type), m_CurrentValue(Value), m_pSavedObject(nullptr) |
1741 | { |
1742 | Save(); |
1743 | |
1744 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Edit sound source %d in layer %d of group %d" , SourceIndex, LayerIndex, GroupIndex); |
1745 | } |
1746 | |
1747 | void CEditorActionEditSoundSource::Undo() |
1748 | { |
1749 | std::shared_ptr<CLayerSounds> pLayerSounds = std::static_pointer_cast<CLayerSounds>(r: m_pLayer); |
1750 | CSoundSource *pSource = &pLayerSounds->m_vSources[m_SourceIndex]; |
1751 | |
1752 | if(m_EditType == EEditType::SHAPE) |
1753 | { |
1754 | CSoundShape *pSavedShape = (CSoundShape *)m_pSavedObject; |
1755 | pSource->m_Shape.m_Type = pSavedShape->m_Type; |
1756 | |
1757 | // set default values |
1758 | switch(pSource->m_Shape.m_Type) |
1759 | { |
1760 | case CSoundShape::SHAPE_CIRCLE: |
1761 | { |
1762 | pSource->m_Shape.m_Circle.m_Radius = pSavedShape->m_Circle.m_Radius; |
1763 | break; |
1764 | } |
1765 | case CSoundShape::SHAPE_RECTANGLE: |
1766 | { |
1767 | pSource->m_Shape.m_Rectangle.m_Width = pSavedShape->m_Rectangle.m_Width; |
1768 | pSource->m_Shape.m_Rectangle.m_Height = pSavedShape->m_Rectangle.m_Height; |
1769 | break; |
1770 | } |
1771 | } |
1772 | } |
1773 | |
1774 | m_pEditor->m_Map.OnModify(); |
1775 | } |
1776 | |
1777 | void CEditorActionEditSoundSource::Redo() |
1778 | { |
1779 | std::shared_ptr<CLayerSounds> pLayerSounds = std::static_pointer_cast<CLayerSounds>(r: m_pLayer); |
1780 | CSoundSource *pSource = &pLayerSounds->m_vSources[m_SourceIndex]; |
1781 | |
1782 | if(m_EditType == EEditType::SHAPE) |
1783 | { |
1784 | pSource->m_Shape.m_Type = m_CurrentValue; |
1785 | |
1786 | // set default values |
1787 | switch(pSource->m_Shape.m_Type) |
1788 | { |
1789 | case CSoundShape::SHAPE_CIRCLE: |
1790 | { |
1791 | pSource->m_Shape.m_Circle.m_Radius = 1000.0f; |
1792 | break; |
1793 | } |
1794 | case CSoundShape::SHAPE_RECTANGLE: |
1795 | { |
1796 | pSource->m_Shape.m_Rectangle.m_Width = f2fx(v: 1000.0f); |
1797 | pSource->m_Shape.m_Rectangle.m_Height = f2fx(v: 800.0f); |
1798 | break; |
1799 | } |
1800 | } |
1801 | } |
1802 | |
1803 | m_pEditor->m_Map.OnModify(); |
1804 | } |
1805 | |
1806 | void CEditorActionEditSoundSource::Save() |
1807 | { |
1808 | std::shared_ptr<CLayerSounds> pLayerSounds = std::static_pointer_cast<CLayerSounds>(r: m_pLayer); |
1809 | CSoundSource *pSource = &pLayerSounds->m_vSources[m_SourceIndex]; |
1810 | |
1811 | if(m_EditType == EEditType::SHAPE) |
1812 | { |
1813 | CSoundShape *pShapeInfo = new CSoundShape; |
1814 | pShapeInfo->m_Type = pSource->m_Shape.m_Type; |
1815 | |
1816 | switch(pSource->m_Shape.m_Type) |
1817 | { |
1818 | case CSoundShape::SHAPE_CIRCLE: |
1819 | { |
1820 | pShapeInfo->m_Circle.m_Radius = pSource->m_Shape.m_Circle.m_Radius; |
1821 | break; |
1822 | } |
1823 | case CSoundShape::SHAPE_RECTANGLE: |
1824 | { |
1825 | pShapeInfo->m_Rectangle.m_Width = pSource->m_Shape.m_Rectangle.m_Width; |
1826 | pShapeInfo->m_Rectangle.m_Height = pSource->m_Shape.m_Rectangle.m_Height; |
1827 | break; |
1828 | } |
1829 | } |
1830 | |
1831 | m_pSavedObject = pShapeInfo; |
1832 | } |
1833 | } |
1834 | |
1835 | CEditorActionEditSoundSource::~CEditorActionEditSoundSource() |
1836 | { |
1837 | if(m_EditType == EEditType::SHAPE) |
1838 | { |
1839 | CSoundShape *pSavedShape = (CSoundShape *)m_pSavedObject; |
1840 | delete pSavedShape; |
1841 | } |
1842 | } |
1843 | |
1844 | // ----- |
1845 | |
1846 | CEditorActionEditSoundSourceProp::CEditorActionEditSoundSourceProp(CEditor *pEditor, int GroupIndex, int LayerIndex, int SourceIndex, ESoundProp Prop, int Previous, int Current) : |
1847 | CEditorActionEditLayerPropBase(pEditor, GroupIndex, LayerIndex, Prop, Previous, Current), m_SourceIndex(SourceIndex) |
1848 | { |
1849 | static const char *s_apNames[] = { |
1850 | "pos X" , |
1851 | "pos Y" , |
1852 | "loop" , |
1853 | "pan" , |
1854 | "time delay" , |
1855 | "falloff" , |
1856 | "pos env" , |
1857 | "pos env offset" , |
1858 | "sound env" , |
1859 | "sound env offset" }; |
1860 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Edit sound source %d in layer %d of group %d %s property" , SourceIndex, LayerIndex, GroupIndex, s_apNames[(int)Prop]); |
1861 | } |
1862 | |
1863 | void CEditorActionEditSoundSourceProp::Undo() |
1864 | { |
1865 | Apply(Value: m_Previous); |
1866 | } |
1867 | |
1868 | void CEditorActionEditSoundSourceProp::Redo() |
1869 | { |
1870 | Apply(Value: m_Current); |
1871 | } |
1872 | |
1873 | void CEditorActionEditSoundSourceProp::Apply(int Value) |
1874 | { |
1875 | std::shared_ptr<CLayerSounds> pLayerSounds = std::static_pointer_cast<CLayerSounds>(r: m_pLayer); |
1876 | CSoundSource *pSource = &pLayerSounds->m_vSources[m_SourceIndex]; |
1877 | |
1878 | if(m_Prop == ESoundProp::PROP_POS_X) |
1879 | { |
1880 | pSource->m_Position.x = Value; |
1881 | } |
1882 | else if(m_Prop == ESoundProp::PROP_POS_Y) |
1883 | { |
1884 | pSource->m_Position.y = Value; |
1885 | } |
1886 | else if(m_Prop == ESoundProp::PROP_LOOP) |
1887 | { |
1888 | pSource->m_Loop = Value; |
1889 | } |
1890 | else if(m_Prop == ESoundProp::PROP_PAN) |
1891 | { |
1892 | pSource->m_Pan = Value; |
1893 | } |
1894 | else if(m_Prop == ESoundProp::PROP_TIME_DELAY) |
1895 | { |
1896 | pSource->m_TimeDelay = Value; |
1897 | } |
1898 | else if(m_Prop == ESoundProp::PROP_FALLOFF) |
1899 | { |
1900 | pSource->m_Falloff = Value; |
1901 | } |
1902 | else if(m_Prop == ESoundProp::PROP_POS_ENV) |
1903 | { |
1904 | pSource->m_PosEnv = Value; |
1905 | } |
1906 | else if(m_Prop == ESoundProp::PROP_POS_ENV_OFFSET) |
1907 | { |
1908 | pSource->m_PosEnvOffset = Value; |
1909 | } |
1910 | else if(m_Prop == ESoundProp::PROP_SOUND_ENV) |
1911 | { |
1912 | pSource->m_SoundEnv = Value; |
1913 | } |
1914 | else if(m_Prop == ESoundProp::PROP_SOUND_ENV_OFFSET) |
1915 | { |
1916 | pSource->m_SoundEnvOffset = Value; |
1917 | } |
1918 | |
1919 | m_pEditor->m_Map.OnModify(); |
1920 | } |
1921 | |
1922 | CEditorActionEditRectSoundSourceShapeProp::CEditorActionEditRectSoundSourceShapeProp(CEditor *pEditor, int GroupIndex, int LayerIndex, int SourceIndex, ERectangleShapeProp Prop, int Previous, int Current) : |
1923 | CEditorActionEditLayerPropBase(pEditor, GroupIndex, LayerIndex, Prop, Previous, Current), m_SourceIndex(SourceIndex) |
1924 | { |
1925 | static const char *s_apNames[] = { |
1926 | "width" , |
1927 | "height" }; |
1928 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Edit sound source %d in layer %d of group %d sound shape %s property" , m_SourceIndex, m_LayerIndex, m_GroupIndex, s_apNames[(int)Prop]); |
1929 | } |
1930 | |
1931 | void CEditorActionEditRectSoundSourceShapeProp::Undo() |
1932 | { |
1933 | Apply(Value: m_Previous); |
1934 | } |
1935 | |
1936 | void CEditorActionEditRectSoundSourceShapeProp::Redo() |
1937 | { |
1938 | Apply(Value: m_Current); |
1939 | } |
1940 | |
1941 | void CEditorActionEditRectSoundSourceShapeProp::Apply(int Value) |
1942 | { |
1943 | std::shared_ptr<CLayerSounds> pLayerSounds = std::static_pointer_cast<CLayerSounds>(r: m_pLayer); |
1944 | CSoundSource *pSource = &pLayerSounds->m_vSources[m_SourceIndex]; |
1945 | |
1946 | if(m_Prop == ERectangleShapeProp::PROP_RECTANGLE_WIDTH) |
1947 | { |
1948 | pSource->m_Shape.m_Rectangle.m_Width = Value; |
1949 | } |
1950 | else if(m_Prop == ERectangleShapeProp::PROP_RECTANGLE_HEIGHT) |
1951 | { |
1952 | pSource->m_Shape.m_Rectangle.m_Height = Value; |
1953 | } |
1954 | |
1955 | m_pEditor->m_Map.OnModify(); |
1956 | } |
1957 | |
1958 | CEditorActionEditCircleSoundSourceShapeProp::CEditorActionEditCircleSoundSourceShapeProp(CEditor *pEditor, int GroupIndex, int LayerIndex, int SourceIndex, ECircleShapeProp Prop, int Previous, int Current) : |
1959 | CEditorActionEditLayerPropBase(pEditor, GroupIndex, LayerIndex, Prop, Previous, Current), m_SourceIndex(SourceIndex) |
1960 | { |
1961 | static const char *s_apNames[] = { |
1962 | "radius" }; |
1963 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Edit sound source %d in layer %d of group %d sound shape %s property" , m_SourceIndex, m_LayerIndex, m_GroupIndex, s_apNames[(int)Prop]); |
1964 | } |
1965 | |
1966 | void CEditorActionEditCircleSoundSourceShapeProp::Undo() |
1967 | { |
1968 | Apply(Value: m_Previous); |
1969 | } |
1970 | |
1971 | void CEditorActionEditCircleSoundSourceShapeProp::Redo() |
1972 | { |
1973 | Apply(Value: m_Current); |
1974 | } |
1975 | |
1976 | void CEditorActionEditCircleSoundSourceShapeProp::Apply(int Value) |
1977 | { |
1978 | std::shared_ptr<CLayerSounds> pLayerSounds = std::static_pointer_cast<CLayerSounds>(r: m_pLayer); |
1979 | CSoundSource *pSource = &pLayerSounds->m_vSources[m_SourceIndex]; |
1980 | |
1981 | if(m_Prop == ECircleShapeProp::PROP_CIRCLE_RADIUS) |
1982 | { |
1983 | pSource->m_Shape.m_Circle.m_Radius = Value; |
1984 | } |
1985 | |
1986 | m_pEditor->m_Map.OnModify(); |
1987 | } |
1988 | |
1989 | // -------------------------- |
1990 | |
1991 | CEditorActionNewEmptySound::CEditorActionNewEmptySound(CEditor *pEditor, int GroupIndex, int LayerIndex, int x, int y) : |
1992 | CEditorActionLayerBase(pEditor, GroupIndex, LayerIndex), m_X(x), m_Y(y) |
1993 | { |
1994 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "New sound in layer %d of group %d" , LayerIndex, GroupIndex); |
1995 | } |
1996 | |
1997 | void CEditorActionNewEmptySound::Undo() |
1998 | { |
1999 | // Undo is simply deleting the added source |
2000 | std::shared_ptr<CLayerSounds> pLayerSounds = std::static_pointer_cast<CLayerSounds>(r: m_pLayer); |
2001 | pLayerSounds->m_vSources.pop_back(); |
2002 | |
2003 | m_pEditor->m_Map.OnModify(); |
2004 | } |
2005 | |
2006 | void CEditorActionNewEmptySound::Redo() |
2007 | { |
2008 | auto &Map = m_pEditor->m_Map; |
2009 | std::shared_ptr<CLayerSounds> pLayerSounds = std::static_pointer_cast<CLayerSounds>(r: m_pLayer); |
2010 | pLayerSounds->NewSource(x: m_X, y: m_Y); |
2011 | |
2012 | Map.OnModify(); |
2013 | } |
2014 | |
2015 | CEditorActionNewEmptyQuad::CEditorActionNewEmptyQuad(CEditor *pEditor, int GroupIndex, int LayerIndex, int x, int y) : |
2016 | CEditorActionLayerBase(pEditor, GroupIndex, LayerIndex), m_X(x), m_Y(y) |
2017 | { |
2018 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "New quad in layer %d of group %d" , LayerIndex, GroupIndex); |
2019 | } |
2020 | |
2021 | void CEditorActionNewEmptyQuad::Undo() |
2022 | { |
2023 | // Undo is simply deleting the added quad |
2024 | std::shared_ptr<CLayerQuads> pLayerQuads = std::static_pointer_cast<CLayerQuads>(r: m_pLayer); |
2025 | pLayerQuads->m_vQuads.pop_back(); |
2026 | |
2027 | m_pEditor->m_Map.OnModify(); |
2028 | } |
2029 | |
2030 | void CEditorActionNewEmptyQuad::Redo() |
2031 | { |
2032 | auto &Map = m_pEditor->m_Map; |
2033 | std::shared_ptr<CLayerQuads> pLayerQuads = std::static_pointer_cast<CLayerQuads>(r: m_pLayer); |
2034 | |
2035 | int Width = 64; |
2036 | int Height = 64; |
2037 | if(pLayerQuads->m_Image >= 0) |
2038 | { |
2039 | Width = Map.m_vpImages[pLayerQuads->m_Image]->m_Width; |
2040 | Height = Map.m_vpImages[pLayerQuads->m_Image]->m_Height; |
2041 | } |
2042 | |
2043 | pLayerQuads->NewQuad(x: m_X, y: m_Y, Width, Height); |
2044 | |
2045 | Map.OnModify(); |
2046 | } |
2047 | |
2048 | // ------------- |
2049 | |
2050 | CEditorActionNewQuad::CEditorActionNewQuad(CEditor *pEditor, int GroupIndex, int LayerIndex) : |
2051 | CEditorActionLayerBase(pEditor, GroupIndex, LayerIndex) |
2052 | { |
2053 | std::shared_ptr<CLayerQuads> pLayerQuads = std::static_pointer_cast<CLayerQuads>(r: m_pLayer); |
2054 | m_Quad = pLayerQuads->m_vQuads[pLayerQuads->m_vQuads.size() - 1]; |
2055 | |
2056 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "New quad in layer %d of group %d" , LayerIndex, GroupIndex); |
2057 | } |
2058 | |
2059 | void CEditorActionNewQuad::Undo() |
2060 | { |
2061 | std::shared_ptr<CLayerQuads> pLayerQuads = std::static_pointer_cast<CLayerQuads>(r: m_pLayer); |
2062 | pLayerQuads->m_vQuads.pop_back(); |
2063 | } |
2064 | |
2065 | void CEditorActionNewQuad::Redo() |
2066 | { |
2067 | std::shared_ptr<CLayerQuads> pLayerQuads = std::static_pointer_cast<CLayerQuads>(r: m_pLayer); |
2068 | pLayerQuads->m_vQuads.emplace_back(args&: m_Quad); |
2069 | } |
2070 | |
2071 | // -------------- |
2072 | |
2073 | CEditorActionMoveSoundSource::CEditorActionMoveSoundSource(CEditor *pEditor, int GroupIndex, int LayerIndex, int SourceIndex, CPoint OriginalPosition, CPoint CurrentPosition) : |
2074 | CEditorActionLayerBase(pEditor, GroupIndex, LayerIndex), m_SourceIndex(SourceIndex), m_OriginalPosition(OriginalPosition), m_CurrentPosition(CurrentPosition) |
2075 | { |
2076 | str_format(buffer: m_aDisplayText, buffer_size: sizeof(m_aDisplayText), format: "Move sound source %d of layer %d in group %d" , SourceIndex, LayerIndex, GroupIndex); |
2077 | } |
2078 | |
2079 | void CEditorActionMoveSoundSource::Undo() |
2080 | { |
2081 | dbg_assert(m_pLayer->m_Type == LAYERTYPE_SOUNDS, "Layer type does not match a sound layer" ); |
2082 | std::static_pointer_cast<CLayerSounds>(r: m_pLayer)->m_vSources[m_SourceIndex].m_Position = m_OriginalPosition; |
2083 | } |
2084 | |
2085 | void CEditorActionMoveSoundSource::Redo() |
2086 | { |
2087 | dbg_assert(m_pLayer->m_Type == LAYERTYPE_SOUNDS, "Layer type does not match a sound layer" ); |
2088 | std::static_pointer_cast<CLayerSounds>(r: m_pLayer)->m_vSources[m_SourceIndex].m_Position = m_CurrentPosition; |
2089 | } |
2090 | |