diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index e4abed4cf..d45f85abc 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -1431,18 +1431,11 @@ static void Rotate(const CPoint *pCenter, CPoint *pPoint, float Rotation) pPoint->y = (int)(x * std::sin(Rotation) + y * std::cos(Rotation) + pCenter->y); } -void CEditor::DoSoundSource(CSoundSource *pSource, int Index) +void CEditor::DoSoundSource(int LayerIndex, CSoundSource *pSource, int Index) { - enum - { - OP_NONE = 0, - OP_MOVE, - OP_CONTEXT_MENU, - }; - void *pID = &pSource->m_Position; - static int s_Operation = OP_NONE; + static ESoundSourceOp s_Operation = ESoundSourceOp::OP_NONE; float wx = UI()->MouseWorldX(); float wy = UI()->MouseWorldY(); @@ -1456,12 +1449,24 @@ void CEditor::DoSoundSource(CSoundSource *pSource, int Index) UI()->SetHotItem(pID); const bool IgnoreGrid = Input()->AltIsPressed(); + static CSoundSourceOperationTracker s_Tracker(this); + + if(s_Operation == ESoundSourceOp::OP_NONE) + { + if(!UI()->MouseButton(0)) + s_Tracker.End(); + } if(UI()->CheckActiveItem(pID)) { + if(s_Operation != ESoundSourceOp::OP_NONE) + { + s_Tracker.Begin(pSource, s_Operation, LayerIndex); + } + if(m_MouseDeltaWx * m_MouseDeltaWx + m_MouseDeltaWy * m_MouseDeltaWy > 0.0f) { - if(s_Operation == OP_MOVE) + if(s_Operation == ESoundSourceOp::OP_MOVE) { float x = wx; float y = wy; @@ -1472,7 +1477,7 @@ void CEditor::DoSoundSource(CSoundSource *pSource, int Index) } } - if(s_Operation == OP_CONTEXT_MENU) + if(s_Operation == ESoundSourceOp::OP_CONTEXT_MENU) { if(!UI()->MouseButton(1)) { @@ -1482,7 +1487,7 @@ void CEditor::DoSoundSource(CSoundSource *pSource, int Index) UI()->DoPopupMenu(&s_PopupSourceId, UI()->MouseX(), UI()->MouseY(), 120, 200, this, PopupSource); UI()->DisableMouseLock(); } - s_Operation = OP_NONE; + s_Operation = ESoundSourceOp::OP_NONE; UI()->SetActiveItem(nullptr); } } @@ -1491,7 +1496,7 @@ void CEditor::DoSoundSource(CSoundSource *pSource, int Index) if(!UI()->MouseButton(0)) { UI()->DisableMouseLock(); - s_Operation = OP_NONE; + s_Operation = ESoundSourceOp::OP_NONE; UI()->SetActiveItem(nullptr); } } @@ -1507,7 +1512,7 @@ void CEditor::DoSoundSource(CSoundSource *pSource, int Index) if(UI()->MouseButton(0)) { - s_Operation = OP_MOVE; + s_Operation = ESoundSourceOp::OP_MOVE; UI()->SetActiveItem(pID); m_SelectedSource = Index; @@ -1516,7 +1521,7 @@ void CEditor::DoSoundSource(CSoundSource *pSource, int Index) if(UI()->MouseButton(1)) { m_SelectedSource = Index; - s_Operation = OP_CONTEXT_MENU; + s_Operation = ESoundSourceOp::OP_CONTEXT_MENU; UI()->SetActiveItem(pID); } } @@ -1988,7 +1993,7 @@ void CEditor::ApplyAxisAlignment(int &OffsetX, int &OffsetY) OffsetY = ((Axis == EAxis::AXIS_NONE || Axis == EAxis::AXIS_Y) ? OffsetY : 0); } -void CEditor::DoQuad(const std::shared_ptr &pLayer, CQuad *pQuad, int Index) +void CEditor::DoQuad(int LayerIndex, const std::shared_ptr &pLayer, CQuad *pQuad, int Index) { enum { @@ -2088,7 +2093,7 @@ void CEditor::DoQuad(const std::shared_ptr &pLayer, CQuad *pQuad, i // check if we only should move pivot if(s_Operation == OP_MOVE_PIVOT) { - m_QuadTracker.BeginQuadTrack(pLayer, m_vSelectedQuads); + m_QuadTracker.BeginQuadTrack(pLayer, m_vSelectedQuads, -1, LayerIndex); s_LastOffset = GetDragOffset(); // Update offset ApplyAxisAlignment(s_LastOffset.x, s_LastOffset.y); // Apply axis alignment to the offset @@ -2104,7 +2109,7 @@ void CEditor::DoQuad(const std::shared_ptr &pLayer, CQuad *pQuad, i } else if(s_Operation == OP_MOVE_ALL) { - m_QuadTracker.BeginQuadTrack(pLayer, m_vSelectedQuads); + m_QuadTracker.BeginQuadTrack(pLayer, m_vSelectedQuads, -1, LayerIndex); // Compute drag offset s_LastOffset = GetDragOffset(); @@ -2124,7 +2129,7 @@ void CEditor::DoQuad(const std::shared_ptr &pLayer, CQuad *pQuad, i } else if(s_Operation == OP_ROTATE) { - m_QuadTracker.BeginQuadTrack(pLayer, m_vSelectedQuads); + m_QuadTracker.BeginQuadTrack(pLayer, m_vSelectedQuads, -1, LayerIndex); for(size_t i = 0; i < m_vSelectedQuads.size(); ++i) { @@ -2309,7 +2314,7 @@ void CEditor::DoQuad(const std::shared_ptr &pLayer, CQuad *pQuad, i Graphics()->QuadsDraw(&QuadItem, 1); } -void CEditor::DoQuadPoint(const std::shared_ptr &pLayer, CQuad *pQuad, int QuadIndex, int V) +void CEditor::DoQuadPoint(int LayerIndex, const std::shared_ptr &pLayer, CQuad *pQuad, int QuadIndex, int V) { void *pID = &pQuad->m_aPoints[V]; @@ -2393,7 +2398,7 @@ void CEditor::DoQuadPoint(const std::shared_ptr &pLayer, CQuad *pQu if(s_Operation == OP_MOVEPOINT) { - m_QuadTracker.BeginQuadTrack(pLayer, m_vSelectedQuads); + m_QuadTracker.BeginQuadTrack(pLayer, m_vSelectedQuads, -1, LayerIndex); s_LastOffset = GetDragOffset(); // Update offset ApplyAxisAlignment(s_LastOffset.x, s_LastOffset.y); // Apply axis alignment to offset @@ -2416,7 +2421,7 @@ void CEditor::DoQuadPoint(const std::shared_ptr &pLayer, CQuad *pQu { int SelectedPoints = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3); - m_QuadTracker.BeginQuadPointPropTrack(pLayer, m_vSelectedQuads, SelectedPoints); + m_QuadTracker.BeginQuadPointPropTrack(pLayer, m_vSelectedQuads, SelectedPoints, -1, LayerIndex); m_QuadTracker.AddQuadPointPropTrack(EQuadPointProp::PROP_TEX_U); m_QuadTracker.AddQuadPointPropTrack(EQuadPointProp::PROP_TEX_V); @@ -3107,17 +3112,17 @@ void CEditor::DoMapEditor(CUIRect View) static int s_Operation = OP_NONE; // draw layer borders - std::shared_ptr apEditLayers[128]; + std::pair> apEditLayers[128]; size_t NumEditLayers = 0; if(m_ShowPicker && GetSelectedLayer(0) && GetSelectedLayer(0)->m_Type == LAYERTYPE_TILES) { - apEditLayers[0] = m_pTilesetPicker; + apEditLayers[0] = {0, m_pTilesetPicker}; NumEditLayers++; } else if(m_ShowPicker) { - apEditLayers[0] = m_pQuadsetPicker; + apEditLayers[0] = {0, m_pQuadsetPicker}; NumEditLayers++; } else @@ -3136,8 +3141,8 @@ void CEditor::DoMapEditor(CUIRect View) } for(size_t i = 0; i < m_vSelectedLayers.size() && NumEditLayers < 128; i++) { - apEditLayers[NumEditLayers] = GetSelectedLayerType(i, EditingType); - if(apEditLayers[NumEditLayers]) + apEditLayers[NumEditLayers] = {m_vSelectedLayers[i], GetSelectedLayerType(i, EditingType)}; + if(apEditLayers[NumEditLayers].second) { NumEditLayers++; } @@ -3261,11 +3266,11 @@ void CEditor::DoMapEditor(CUIRect View) for(size_t k = 0; k < NumEditLayers; k++) { size_t BrushIndex = k % m_pBrush->m_vpLayers.size(); - if(apEditLayers[k]->m_Type == m_pBrush->m_vpLayers[BrushIndex]->m_Type) + if(apEditLayers[k].second->m_Type == m_pBrush->m_vpLayers[BrushIndex]->m_Type) { - if(apEditLayers[k]->m_Type == LAYERTYPE_TILES) + if(apEditLayers[k].second->m_Type == LAYERTYPE_TILES) { - std::shared_ptr pLayer = std::static_pointer_cast(apEditLayers[k]); + std::shared_ptr pLayer = std::static_pointer_cast(apEditLayers[k].second); std::shared_ptr pBrushLayer = std::static_pointer_cast(m_pBrush->m_vpLayers[BrushIndex]); if(pLayer->m_Tele <= pBrushLayer->m_Tele && pLayer->m_Speedup <= pBrushLayer->m_Speedup && pLayer->m_Front <= pBrushLayer->m_Front && pLayer->m_Game <= pBrushLayer->m_Game && pLayer->m_Switch <= pBrushLayer->m_Switch && pLayer->m_Tune <= pBrushLayer->m_Tune) @@ -3273,7 +3278,7 @@ void CEditor::DoMapEditor(CUIRect View) } else { - apEditLayers[k]->BrushDraw(m_pBrush->m_vpLayers[BrushIndex], wx, wy); + apEditLayers[k].second->BrushDraw(m_pBrush->m_vpLayers[BrushIndex], wx, wy); } } } @@ -3307,7 +3312,7 @@ void CEditor::DoMapEditor(CUIRect View) // TODO: do all layers int Grabs = 0; for(size_t k = 0; k < NumEditLayers; k++) - Grabs += apEditLayers[k]->BrushGrab(m_pBrush, r); + Grabs += apEditLayers[k].second->BrushGrab(m_pBrush, r); if(Grabs == 0) m_pBrush->Clear(); @@ -3318,7 +3323,7 @@ void CEditor::DoMapEditor(CUIRect View) else { for(size_t k = 0; k < NumEditLayers; k++) - apEditLayers[k]->BrushSelecting(r); + apEditLayers[k].second->BrushSelecting(r); UI()->MapScreen(); } } @@ -3332,7 +3337,7 @@ void CEditor::DoMapEditor(CUIRect View) if(m_pBrush->m_vpLayers.size() != NumEditLayers) BrushIndex = 0; std::shared_ptr pBrush = m_pBrush->IsEmpty() ? nullptr : m_pBrush->m_vpLayers[BrushIndex]; - apEditLayers[k]->FillSelection(m_pBrush->IsEmpty(), pBrush, r); + apEditLayers[k].second->FillSelection(m_pBrush->IsEmpty(), pBrush, r); } std::shared_ptr Action = std::make_shared(this, m_SelectedGroup); m_EditorHistory.RecordAction(Action); @@ -3340,7 +3345,7 @@ void CEditor::DoMapEditor(CUIRect View) else { for(size_t k = 0; k < NumEditLayers; k++) - apEditLayers[k]->BrushSelecting(r); + apEditLayers[k].second->BrushSelecting(r); UI()->MapScreen(); } } @@ -3367,8 +3372,8 @@ void CEditor::DoMapEditor(CUIRect View) if(m_pBrush->m_vpLayers.size() != NumEditLayers) BrushIndex = 0; - if(apEditLayers[k]->m_Type == m_pBrush->m_vpLayers[BrushIndex]->m_Type) - apEditLayers[k]->BrushPlace(m_pBrush->m_vpLayers[BrushIndex], wx, wy); + if(apEditLayers[k].second->m_Type == m_pBrush->m_vpLayers[BrushIndex]->m_Type) + apEditLayers[k].second->BrushPlace(m_pBrush->m_vpLayers[BrushIndex], wx, wy); } } @@ -3427,9 +3432,11 @@ void CEditor::DoMapEditor(CUIRect View) for(size_t k = 0; k < NumEditLayers; k++) { - if(apEditLayers[k]->m_Type == LAYERTYPE_QUADS) + auto &[LayerIndex, pEditLayer] = apEditLayers[k]; + + if(pEditLayer->m_Type == LAYERTYPE_QUADS) { - std::shared_ptr pLayer = std::static_pointer_cast(apEditLayers[k]); + std::shared_ptr pLayer = std::static_pointer_cast(pEditLayer); if(m_ShowEnvelopePreview == SHOWENV_NONE) m_ShowEnvelopePreview = SHOWENV_ALL; @@ -3445,23 +3452,23 @@ void CEditor::DoMapEditor(CUIRect View) for(size_t i = 0; i < pLayer->m_vQuads.size(); i++) { for(int v = 0; v < 4; v++) - DoQuadPoint(pLayer, &pLayer->m_vQuads[i], i, v); + DoQuadPoint(LayerIndex, pLayer, &pLayer->m_vQuads[i], i, v); - DoQuad(pLayer, &pLayer->m_vQuads[i], i); + DoQuad(LayerIndex, pLayer, &pLayer->m_vQuads[i], i); } Graphics()->QuadsEnd(); } } - if(apEditLayers[k]->m_Type == LAYERTYPE_SOUNDS) + if(pEditLayer->m_Type == LAYERTYPE_SOUNDS) { - std::shared_ptr pLayer = std::static_pointer_cast(apEditLayers[k]); + std::shared_ptr pLayer = std::static_pointer_cast(pEditLayer); Graphics()->TextureClear(); Graphics()->QuadsBegin(); for(size_t i = 0; i < pLayer->m_vSources.size(); i++) { - DoSoundSource(&pLayer->m_vSources[i], i); + DoSoundSource(LayerIndex, &pLayer->m_vSources[i], i); } Graphics()->QuadsEnd(); } @@ -4339,12 +4346,15 @@ void CEditor::RenderLayers(CUIRect LayersBox) else { std::vector> vpActions; - for(int k = 0; k < (int)m_vSelectedLayers.size(); k++) + std::vector vLayerIndices = m_vSelectedLayers; + std::sort(vLayerIndices.begin(), vLayerIndices.end()); + std::sort(s_vInitialLayerIndices.begin(), s_vInitialLayerIndices.end()); + for(int k = 0; k < (int)vLayerIndices.size(); k++) { - int LayerIndex = m_vSelectedLayers[k]; + int LayerIndex = vLayerIndices[k]; vpActions.push_back(std::make_shared(this, m_SelectedGroup, LayerIndex, ELayerProp::PROP_ORDER, s_vInitialLayerIndices[k], LayerIndex)); } - m_EditorHistory.RecordAction(std::make_shared(CEditorActionBulk(this, vpActions))); + m_EditorHistory.RecordAction(std::make_shared(this, vpActions, nullptr, true)); } s_PreviousOperation = OP_NONE; } @@ -5870,6 +5880,8 @@ bool CEditor::IsEnvelopeUsed(int EnvelopeIndex) const void CEditor::RemoveUnusedEnvelopes() { + m_EnvelopeEditorHistory.BeginBulk(); + int DeletedCount = 0; for(size_t Envelope = 0; Envelope < m_Map.m_vpEnvelopes.size();) { if(IsEnvelopeUsed(Envelope)) @@ -5878,9 +5890,14 @@ void CEditor::RemoveUnusedEnvelopes() } else { + m_EnvelopeEditorHistory.RecordAction(std::make_shared(this, Envelope)); m_Map.DeleteEnvelope(Envelope); + DeletedCount++; } } + char aDisplay[256]; + str_format(aDisplay, sizeof(aDisplay), "Tool 'Remove unused envelopes': delete %d envelopes", DeletedCount); + m_EnvelopeEditorHistory.EndBulk(aDisplay); } void CEditor::ZoomAdaptOffsetX(float ZoomFactor, const CUIRect &View) diff --git a/src/game/editor/editor.h b/src/game/editor/editor.h index 372c084a9..84916ec74 100644 --- a/src/game/editor/editor.h +++ b/src/game/editor/editor.h @@ -876,14 +876,14 @@ public: void DoQuadEnvelopes(const std::vector &vQuads, IGraphics::CTextureHandle Texture = IGraphics::CTextureHandle()); void DoQuadEnvPoint(const CQuad *pQuad, int QIndex, int pIndex); - void DoQuadPoint(const std::shared_ptr &pLayer, CQuad *pQuad, int QuadIndex, int v); + void DoQuadPoint(int LayerIndex, const std::shared_ptr &pLayer, CQuad *pQuad, int QuadIndex, int v); void SetHotQuadPoint(const std::shared_ptr &pLayer); float TriangleArea(vec2 A, vec2 B, vec2 C); bool IsInTriangle(vec2 Point, vec2 A, vec2 B, vec2 C); void DoQuadKnife(int QuadIndex); - void DoSoundSource(CSoundSource *pSource, int Index); + void DoSoundSource(int LayerIndex, CSoundSource *pSource, int Index); enum class EAxis { @@ -907,7 +907,7 @@ public: void DoMapEditor(CUIRect View); void DoToolbarLayers(CUIRect Toolbar); void DoToolbarSounds(CUIRect Toolbar); - void DoQuad(const std::shared_ptr &pLayer, CQuad *pQuad, int Index); + void DoQuad(int LayerIndex, const std::shared_ptr &pLayer, CQuad *pQuad, int Index); void PreparePointDrag(const std::shared_ptr &pLayer, CQuad *pQuad, int QuadIndex, int PointIndex); void DoPointDrag(const std::shared_ptr &pLayer, CQuad *pQuad, int QuadIndex, int PointIndex, int OffsetX, int OffsetY); EAxis GetDragAxis(int OffsetX, int OffsetY); diff --git a/src/game/editor/editor_actions.cpp b/src/game/editor/editor_actions.cpp index 88ce5d559..8f37233c6 100644 --- a/src/game/editor/editor_actions.cpp +++ b/src/game/editor/editor_actions.cpp @@ -794,12 +794,14 @@ void CEditorActionEditLayerProp::Apply(int Value) if(m_Prop == ELayerProp::PROP_GROUP) { auto pCurrentGroup = m_pEditor->m_Map.m_vpGroups[Value == m_Previous ? m_Current : m_Previous]; - auto Position = std::find(pCurrentGroup->m_vpLayers.begin(), pCurrentGroup->m_vpLayers.end(), m_pLayer); - if(Position != pCurrentGroup->m_vpLayers.end()) - pCurrentGroup->m_vpLayers.erase(Position); - m_pEditor->m_Map.m_vpGroups[Value]->m_vpLayers.push_back(m_pLayer); + auto pPreviousGroup = m_pEditor->m_Map.m_vpGroups[Value]; + pCurrentGroup->m_vpLayers.erase(pCurrentGroup->m_vpLayers.begin() + pCurrentGroup->m_vpLayers.size() - 1); + if(Value == m_Previous) + pPreviousGroup->m_vpLayers.insert(pPreviousGroup->m_vpLayers.begin() + m_LayerIndex, m_pLayer); + else + pPreviousGroup->m_vpLayers.push_back(m_pLayer); m_pEditor->m_SelectedGroup = Value; - m_pEditor->SelectLayer(m_pEditor->m_Map.m_vpGroups[Value]->m_vpLayers.size() - 1); + m_pEditor->SelectLayer(m_LayerIndex); } else if(m_Prop == ELayerProp::PROP_HQ) { @@ -2065,3 +2067,23 @@ void CEditorActionNewQuad::Redo() std::shared_ptr pLayerQuads = std::static_pointer_cast(m_pLayer); pLayerQuads->m_vQuads.emplace_back(m_Quad); } + +// -------------- + +CEditorActionMoveSoundSource::CEditorActionMoveSoundSource(CEditor *pEditor, int GroupIndex, int LayerIndex, int SourceIndex, CPoint OriginalPosition, CPoint CurrentPosition) : + CEditorActionLayerBase(pEditor, GroupIndex, LayerIndex), m_SourceIndex(SourceIndex), m_OriginalPosition(OriginalPosition), m_CurrentPosition(CurrentPosition) +{ + str_format(m_aDisplayText, sizeof(m_aDisplayText), "Move sound source %d of layer %d in group %d", SourceIndex, LayerIndex, GroupIndex); +} + +void CEditorActionMoveSoundSource::Undo() +{ + dbg_assert(m_pLayer->m_Type == LAYERTYPE_SOUNDS, "Layer type does not match a sound layer"); + std::static_pointer_cast(m_pLayer)->m_vSources[m_SourceIndex].m_Position = m_OriginalPosition; +} + +void CEditorActionMoveSoundSource::Redo() +{ + dbg_assert(m_pLayer->m_Type == LAYERTYPE_SOUNDS, "Layer type does not match a sound layer"); + std::static_pointer_cast(m_pLayer)->m_vSources[m_SourceIndex].m_Position = m_CurrentPosition; +} diff --git a/src/game/editor/editor_actions.h b/src/game/editor/editor_actions.h index 198e02a6f..2519ed648 100644 --- a/src/game/editor/editor_actions.h +++ b/src/game/editor/editor_actions.h @@ -645,4 +645,18 @@ private: CQuad m_Quad; }; +class CEditorActionMoveSoundSource : public CEditorActionLayerBase +{ +public: + CEditorActionMoveSoundSource(CEditor *pEditor, int GroupIndex, int LayerIndex, int SourceIndex, CPoint OriginalPosition, CPoint CurrentPosition); + + void Undo() override; + void Redo() override; + +private: + int m_SourceIndex; + CPoint m_OriginalPosition; + CPoint m_CurrentPosition; +}; + #endif diff --git a/src/game/editor/editor_history.cpp b/src/game/editor/editor_history.cpp index 46110de2d..0a00d9f8a 100644 --- a/src/game/editor/editor_history.cpp +++ b/src/game/editor/editor_history.cpp @@ -17,6 +17,12 @@ void CEditorHistory::Execute(const std::shared_ptr &pAction, cons void CEditorHistory::RecordAction(const std::shared_ptr &pAction, const char *pDisplay) { + if(m_IsBulk) + { + m_vpBulkActions.push_back(pAction); + return; + } + m_vpRedoActions.clear(); if((int)m_vpUndoActions.size() >= g_Config.m_ClEditorMaxHistory) @@ -63,3 +69,22 @@ void CEditorHistory::Clear() m_vpUndoActions.clear(); m_vpRedoActions.clear(); } + +void CEditorHistory::BeginBulk() +{ + m_IsBulk = true; + m_vpBulkActions.clear(); +} + +void CEditorHistory::EndBulk(const char *pDisplay) +{ + if(!m_IsBulk) + return; + m_IsBulk = false; + + // Record bulk action + if(!m_vpBulkActions.empty()) + RecordAction(std::make_shared(m_pEditor, m_vpBulkActions, pDisplay, true)); + + m_vpBulkActions.clear(); +} diff --git a/src/game/editor/editor_history.h b/src/game/editor/editor_history.h index 144147140..b43699a37 100644 --- a/src/game/editor/editor_history.h +++ b/src/game/editor/editor_history.h @@ -11,6 +11,7 @@ public: CEditorHistory() { m_pEditor = nullptr; + m_IsBulk = false; } ~CEditorHistory() @@ -29,9 +30,16 @@ public: bool CanUndo() const { return !m_vpUndoActions.empty(); } bool CanRedo() const { return !m_vpRedoActions.empty(); } + void BeginBulk(); + void EndBulk(const char *pDisplay = nullptr); + CEditor *m_pEditor; std::deque> m_vpUndoActions; std::deque> m_vpRedoActions; + +private: + std::vector> m_vpBulkActions; + bool m_IsBulk; }; #endif diff --git a/src/game/editor/editor_trackers.cpp b/src/game/editor/editor_trackers.cpp index 8f3660422..3200f67b8 100644 --- a/src/game/editor/editor_trackers.cpp +++ b/src/game/editor/editor_trackers.cpp @@ -15,13 +15,15 @@ CQuadEditTracker::~CQuadEditTracker() m_vSelectedQuads.clear(); } -void CQuadEditTracker::BeginQuadTrack(const std::shared_ptr &pLayer, const std::vector &vSelectedQuads) +void CQuadEditTracker::BeginQuadTrack(const std::shared_ptr &pLayer, const std::vector &vSelectedQuads, int GroupIndex, int LayerIndex) { if(m_Tracking) return; m_Tracking = true; m_vSelectedQuads.clear(); m_pLayer = pLayer; + m_GroupIndex = GroupIndex < 0 ? m_pEditor->m_SelectedGroup : GroupIndex; + m_LayerIndex = LayerIndex < 0 ? m_pEditor->m_vSelectedLayers[0] : LayerIndex; // Init all points for(auto QuadIndex : vSelectedQuads) { @@ -37,26 +39,25 @@ void CQuadEditTracker::EndQuadTrack() return; m_Tracking = false; - int GroupIndex = m_pEditor->m_SelectedGroup; - int LayerIndex = m_pEditor->m_vSelectedLayers[0]; - // Record all moved stuff std::vector> vpActions; for(auto QuadIndex : m_vSelectedQuads) { auto &pQuad = m_pLayer->m_vQuads[QuadIndex]; auto vCurrentPoints = std::vector(pQuad.m_aPoints, pQuad.m_aPoints + 5); - vpActions.push_back(std::make_shared(m_pEditor, GroupIndex, LayerIndex, QuadIndex, m_InitalPoints[QuadIndex], vCurrentPoints)); + vpActions.push_back(std::make_shared(m_pEditor, m_GroupIndex, m_LayerIndex, QuadIndex, m_InitalPoints[QuadIndex], vCurrentPoints)); } m_pEditor->m_EditorHistory.RecordAction(std::make_shared(m_pEditor, vpActions)); } -void CQuadEditTracker::BeginQuadPropTrack(const std::shared_ptr &pLayer, const std::vector &vSelectedQuads, EQuadProp Prop) +void CQuadEditTracker::BeginQuadPropTrack(const std::shared_ptr &pLayer, const std::vector &vSelectedQuads, EQuadProp Prop, int GroupIndex, int LayerIndex) { if(m_TrackedProp != EQuadProp::PROP_NONE) return; m_TrackedProp = Prop; m_pLayer = pLayer; + m_GroupIndex = GroupIndex < 0 ? m_pEditor->m_SelectedGroup : GroupIndex; + m_LayerIndex = LayerIndex < 0 ? m_pEditor->m_vSelectedLayers[0] : LayerIndex; m_vSelectedQuads = vSelectedQuads; m_PreviousValues.clear(); @@ -83,16 +84,13 @@ void CQuadEditTracker::EndQuadPropTrack(EQuadProp Prop) std::vector> vpActions; - int GroupIndex = m_pEditor->m_SelectedGroup; - int LayerIndex = m_pEditor->m_vSelectedLayers[0]; - for(auto QuadIndex : m_vSelectedQuads) { auto &Quad = m_pLayer->m_vQuads[QuadIndex]; if(Prop == EQuadProp::PROP_POS_X || Prop == EQuadProp::PROP_POS_Y) { auto vCurrentPoints = std::vector(Quad.m_aPoints, Quad.m_aPoints + 5); - vpActions.push_back(std::make_shared(m_pEditor, GroupIndex, LayerIndex, QuadIndex, m_InitalPoints[QuadIndex], vCurrentPoints)); + vpActions.push_back(std::make_shared(m_pEditor, m_GroupIndex, m_LayerIndex, QuadIndex, m_InitalPoints[QuadIndex], vCurrentPoints)); } else { @@ -107,7 +105,7 @@ void CQuadEditTracker::EndQuadPropTrack(EQuadProp Prop) Value = Quad.m_ColorEnvOffset; if(Value != m_PreviousValues[QuadIndex]) - vpActions.push_back(std::make_shared(m_pEditor, GroupIndex, LayerIndex, QuadIndex, Prop, m_PreviousValues[QuadIndex], Value)); + vpActions.push_back(std::make_shared(m_pEditor, m_GroupIndex, m_LayerIndex, QuadIndex, Prop, m_PreviousValues[QuadIndex], Value)); } } @@ -115,12 +113,14 @@ void CQuadEditTracker::EndQuadPropTrack(EQuadProp Prop) m_pEditor->m_EditorHistory.RecordAction(std::make_shared(m_pEditor, vpActions)); } -void CQuadEditTracker::BeginQuadPointPropTrack(const std::shared_ptr &pLayer, const std::vector &vSelectedQuads, int SelectedQuadPoints) +void CQuadEditTracker::BeginQuadPointPropTrack(const std::shared_ptr &pLayer, const std::vector &vSelectedQuads, int SelectedQuadPoints, int GroupIndex, int LayerIndex) { if(!m_vTrackedProps.empty()) return; m_pLayer = pLayer; + m_GroupIndex = GroupIndex < 0 ? m_pEditor->m_SelectedGroup : GroupIndex; + m_LayerIndex = LayerIndex < 0 ? m_pEditor->m_vSelectedLayers[0] : LayerIndex; m_SelectedQuadPoints = SelectedQuadPoints; m_vSelectedQuads = vSelectedQuads; m_PreviousValuesPoint.clear(); @@ -187,16 +187,13 @@ void CQuadEditTracker::EndQuadPointPropTrack(EQuadPointProp Prop) std::vector> vpActions; - int GroupIndex = m_pEditor->m_SelectedGroup; - int LayerIndex = m_pEditor->m_vSelectedLayers[0]; - for(auto QuadIndex : m_vSelectedQuads) { auto &Quad = m_pLayer->m_vQuads[QuadIndex]; if(Prop == EQuadPointProp::PROP_POS_X || Prop == EQuadPointProp::PROP_POS_Y) { auto vCurrentPoints = std::vector(Quad.m_aPoints, Quad.m_aPoints + 5); - vpActions.push_back(std::make_shared(m_pEditor, GroupIndex, LayerIndex, QuadIndex, m_InitalPoints[QuadIndex], vCurrentPoints)); + vpActions.push_back(std::make_shared(m_pEditor, m_GroupIndex, m_LayerIndex, QuadIndex, m_InitalPoints[QuadIndex], vCurrentPoints)); } else { @@ -219,7 +216,7 @@ void CQuadEditTracker::EndQuadPointPropTrack(EQuadPointProp Prop) } if(Value != m_PreviousValuesPoint[QuadIndex][v][Prop]) - vpActions.push_back(std::make_shared(m_pEditor, GroupIndex, LayerIndex, QuadIndex, v, Prop, m_PreviousValuesPoint[QuadIndex][v][Prop], Value)); + vpActions.push_back(std::make_shared(m_pEditor, m_GroupIndex, m_LayerIndex, QuadIndex, v, Prop, m_PreviousValuesPoint[QuadIndex][v][Prop], Value)); } } } @@ -234,16 +231,13 @@ void CQuadEditTracker::EndQuadPointPropTrackAll() std::vector> vpActions; for(auto &Prop : m_vTrackedProps) { - int GroupIndex = m_pEditor->m_SelectedGroup; - int LayerIndex = m_pEditor->m_vSelectedLayers[0]; - for(auto QuadIndex : m_vSelectedQuads) { auto &Quad = m_pLayer->m_vQuads[QuadIndex]; if(Prop == EQuadPointProp::PROP_POS_X || Prop == EQuadPointProp::PROP_POS_Y) { auto vCurrentPoints = std::vector(Quad.m_aPoints, Quad.m_aPoints + 5); - vpActions.push_back(std::make_shared(m_pEditor, GroupIndex, LayerIndex, QuadIndex, m_InitalPoints[QuadIndex], vCurrentPoints)); + vpActions.push_back(std::make_shared(m_pEditor, m_GroupIndex, m_LayerIndex, QuadIndex, m_InitalPoints[QuadIndex], vCurrentPoints)); } else { @@ -266,7 +260,7 @@ void CQuadEditTracker::EndQuadPointPropTrackAll() } if(Value != m_PreviousValuesPoint[QuadIndex][v][Prop]) - vpActions.push_back(std::make_shared(m_pEditor, GroupIndex, LayerIndex, QuadIndex, v, Prop, m_PreviousValuesPoint[QuadIndex][v][Prop], Value)); + vpActions.push_back(std::make_shared(m_pEditor, m_GroupIndex, m_LayerIndex, QuadIndex, v, Prop, m_PreviousValuesPoint[QuadIndex][v][Prop], Value)); } } } @@ -279,22 +273,6 @@ void CQuadEditTracker::EndQuadPointPropTrackAll() m_vTrackedProps.clear(); } -void CEditorPropTracker::BeginPropTrack(int Prop, int Value) -{ - if(m_TrackedProp != -1 || m_TrackedProp == Prop) - return; - m_TrackedProp = Prop; - m_PreviousValue = Value; -} - -void CEditorPropTracker::StopPropTrack(int Prop, int Value) -{ - if(Prop != m_TrackedProp) - return; - m_TrackedProp = -1; - m_CurrentValue = Value; -} - // ----------------------------- void CEnvelopeEditorOperationTracker::Begin(EEnvelopeEditorOp Operation) @@ -385,20 +363,81 @@ void CEnvelopeEditorOperationTracker::HandlePointDragEnd(bool Switch) m_SavedValues.clear(); } +// ----------------------------------------------------------------------- +CSoundSourceOperationTracker::CSoundSourceOperationTracker(CEditor *pEditor) : + m_pEditor(pEditor), m_pSource(nullptr), m_TrackedOp(ESoundSourceOp::OP_NONE), m_LayerIndex(-1) +{ +} + +void CSoundSourceOperationTracker::Begin(CSoundSource *pSource, ESoundSourceOp Operation, int LayerIndex) +{ + if(m_TrackedOp == Operation || m_TrackedOp != ESoundSourceOp::OP_NONE) + return; + + m_TrackedOp = Operation; + m_pSource = pSource; + m_LayerIndex = LayerIndex; + + if(m_TrackedOp == ESoundSourceOp::OP_MOVE) + HandlePointMove(EState::STATE_BEGIN); +} + +void CSoundSourceOperationTracker::End() +{ + if(m_TrackedOp == ESoundSourceOp::OP_NONE) + return; + + if(m_TrackedOp == ESoundSourceOp::OP_MOVE) + HandlePointMove(EState::STATE_END); + + m_TrackedOp = ESoundSourceOp::OP_NONE; +} + +void CSoundSourceOperationTracker::HandlePointMove(EState State) +{ + if(State == EState::STATE_BEGIN) + { + m_Data.m_OriginalPoint = m_pSource->m_Position; + } + else if(State == EState::STATE_END) + { + m_pEditor->m_EditorHistory.RecordAction(std::make_shared(m_pEditor, m_pEditor->m_SelectedGroup, m_LayerIndex, m_pEditor->m_SelectedSource, m_Data.m_OriginalPoint, m_pSource->m_Position)); + } +} + +// ----------------------------------------------------------------------- + +int SPropTrackerHelper::GetDefaultGroupIndex(CEditor *pEditor) +{ + return pEditor->m_SelectedGroup; +} + +int SPropTrackerHelper::GetDefaultLayerIndex(CEditor *pEditor) +{ + return pEditor->m_vSelectedLayers[0]; +} + // ----------------------------------------------------------------------- void CLayerPropTracker::OnEnd(ELayerProp Prop, int Value) { - m_pEditor->m_EditorHistory.RecordAction(std::make_shared(m_pEditor, m_pEditor->m_SelectedGroup, m_pEditor->m_vSelectedLayers[0], Prop, m_OriginalValue, Value)); + if(Prop == ELayerProp::PROP_GROUP) + { + m_pEditor->m_EditorHistory.RecordAction(std::make_shared(m_pEditor, m_OriginalGroupIndex, std::vector{m_OriginalLayerIndex}, m_CurrentGroupIndex, std::vector{m_CurrentLayerIndex})); + } + else + { + m_pEditor->m_EditorHistory.RecordAction(std::make_shared(m_pEditor, m_CurrentGroupIndex, m_CurrentLayerIndex, Prop, m_OriginalValue, Value)); + } } int CLayerPropTracker::PropToValue(ELayerProp Prop) { switch(Prop) { - case ELayerProp::PROP_GROUP: return m_pEditor->m_SelectedGroup; + case ELayerProp::PROP_GROUP: return m_CurrentGroupIndex; case ELayerProp::PROP_HQ: return m_pObject->m_Flags; - case ELayerProp::PROP_ORDER: return m_pEditor->m_vSelectedLayers[0]; + case ELayerProp::PROP_ORDER: return m_CurrentLayerIndex; default: return 0; } } @@ -439,7 +478,7 @@ void CLayerTilesPropTracker::OnStart(ETilesProp Prop) void CLayerTilesPropTracker::OnEnd(ETilesProp Prop, int Value) { - auto pAction = std::make_shared(m_pEditor, m_pEditor->m_SelectedGroup, m_pEditor->m_vSelectedLayers[0], Prop, m_OriginalValue, Value); + auto pAction = std::make_shared(m_pEditor, m_OriginalGroupIndex, m_OriginalLayerIndex, Prop, m_OriginalValue, Value); pAction->SetSavedLayers(m_SavedLayers); m_SavedLayers.clear(); @@ -490,7 +529,7 @@ void CLayerTilesCommonPropTracker::OnEnd(ETilesCommonProp Prop, int Value) for(auto &pLayer : m_vpLayers) { int LayerIndex = m_vLayerIndices[j++]; - auto pAction = std::make_shared(m_pEditor, m_pEditor->m_SelectedGroup, LayerIndex, s_PropMap[Prop], m_OriginalValue, Value); + auto pAction = std::make_shared(m_pEditor, m_OriginalGroupIndex, LayerIndex, s_PropMap[Prop], m_OriginalValue, Value); pAction->SetSavedLayers(m_SavedLayers[pLayer]); vpActions.push_back(pAction); } @@ -549,7 +588,7 @@ int CLayerGroupPropTracker::PropToValue(EGroupProp Prop) void CLayerQuadsPropTracker::OnEnd(ELayerQuadsProp Prop, int Value) { - auto pAction = std::make_shared(m_pEditor, m_pEditor->m_SelectedGroup, m_pEditor->m_vSelectedLayers[0], Prop, m_OriginalValue, Value); + auto pAction = std::make_shared(m_pEditor, m_OriginalGroupIndex, m_OriginalLayerIndex, Prop, m_OriginalValue, Value); m_pEditor->m_EditorHistory.RecordAction(pAction); } @@ -564,7 +603,7 @@ int CLayerQuadsPropTracker::PropToValue(ELayerQuadsProp Prop) void CLayerSoundsPropTracker::OnEnd(ELayerSoundsProp Prop, int Value) { - auto pAction = std::make_shared(m_pEditor, m_pEditor->m_SelectedGroup, m_pEditor->m_vSelectedLayers[0], Prop, m_OriginalValue, Value); + auto pAction = std::make_shared(m_pEditor, m_OriginalGroupIndex, m_OriginalLayerIndex, Prop, m_OriginalValue, Value); m_pEditor->m_EditorHistory.RecordAction(pAction); } @@ -579,7 +618,7 @@ int CLayerSoundsPropTracker::PropToValue(ELayerSoundsProp Prop) void CSoundSourcePropTracker::OnEnd(ESoundProp Prop, int Value) { - m_pEditor->m_EditorHistory.RecordAction(std::make_shared(m_pEditor, m_pEditor->m_SelectedGroup, m_pEditor->m_vSelectedLayers[0], m_pEditor->m_SelectedSource, Prop, m_OriginalValue, Value)); + m_pEditor->m_EditorHistory.RecordAction(std::make_shared(m_pEditor, m_OriginalGroupIndex, m_OriginalLayerIndex, m_pEditor->m_SelectedSource, Prop, m_OriginalValue, Value)); } int CSoundSourcePropTracker::PropToValue(ESoundProp Prop) @@ -604,7 +643,7 @@ int CSoundSourcePropTracker::PropToValue(ESoundProp Prop) void CSoundSourceRectShapePropTracker::OnEnd(ERectangleShapeProp Prop, int Value) { - m_pEditor->m_EditorHistory.RecordAction(std::make_shared(m_pEditor, m_pEditor->m_SelectedGroup, m_pEditor->m_vSelectedLayers[0], m_pEditor->m_SelectedSource, Prop, m_OriginalValue, Value)); + m_pEditor->m_EditorHistory.RecordAction(std::make_shared(m_pEditor, m_OriginalGroupIndex, m_OriginalLayerIndex, m_pEditor->m_SelectedSource, Prop, m_OriginalValue, Value)); } int CSoundSourceRectShapePropTracker::PropToValue(ERectangleShapeProp Prop) @@ -619,7 +658,7 @@ int CSoundSourceRectShapePropTracker::PropToValue(ERectangleShapeProp Prop) void CSoundSourceCircleShapePropTracker::OnEnd(ECircleShapeProp Prop, int Value) { - m_pEditor->m_EditorHistory.RecordAction(std::make_shared(m_pEditor, m_pEditor->m_SelectedGroup, m_pEditor->m_vSelectedLayers[0], m_pEditor->m_SelectedSource, Prop, m_OriginalValue, Value)); + m_pEditor->m_EditorHistory.RecordAction(std::make_shared(m_pEditor, m_OriginalGroupIndex, m_OriginalLayerIndex, m_pEditor->m_SelectedSource, Prop, m_OriginalValue, Value)); } int CSoundSourceCircleShapePropTracker::PropToValue(ECircleShapeProp Prop) diff --git a/src/game/editor/editor_trackers.h b/src/game/editor/editor_trackers.h index 156096b6a..4767e732d 100644 --- a/src/game/editor/editor_trackers.h +++ b/src/game/editor/editor_trackers.h @@ -21,13 +21,13 @@ public: CQuadEditTracker(); ~CQuadEditTracker(); - void BeginQuadTrack(const std::shared_ptr &pLayer, const std::vector &vSelectedQuads); + void BeginQuadTrack(const std::shared_ptr &pLayer, const std::vector &vSelectedQuads, int GroupIndex = -1, int LayerIndex = -1); void EndQuadTrack(); - void BeginQuadPropTrack(const std::shared_ptr &pLayer, const std::vector &vSelectedQuads, EQuadProp Prop); + void BeginQuadPropTrack(const std::shared_ptr &pLayer, const std::vector &vSelectedQuads, EQuadProp Prop, int GroupIndex = -1, int LayerIndex = -1); void EndQuadPropTrack(EQuadProp Prop); - void BeginQuadPointPropTrack(const std::shared_ptr &pLayer, const std::vector &vSelectedQuads, int SelectedQuadPoints); + void BeginQuadPointPropTrack(const std::shared_ptr &pLayer, const std::vector &vSelectedQuads, int SelectedQuadPoints, int GroupIndex = -1, int LayerIndex = -1); void AddQuadPointPropTrack(EQuadPointProp Prop); void EndQuadPointPropTrack(EQuadPointProp Prop); void EndQuadPointPropTrackAll(); @@ -46,23 +46,8 @@ private: std::vector m_vTrackedProps; std::map m_PreviousValues; std::map>> m_PreviousValuesPoint; -}; - -class CEditorPropTracker -{ -public: - CEditorPropTracker() = default; - - void BeginPropTrack(int Prop, int Value); - void StopPropTrack(int Prop, int Value); - inline void Reset() { m_TrackedProp = -1; } - - CEditor *m_pEditor; - int m_PreviousValue; - int m_CurrentValue; - -private: - int m_TrackedProp = -1; + int m_LayerIndex; + int m_GroupIndex; }; enum class EEnvelopeEditorOp @@ -77,6 +62,13 @@ enum class EEnvelopeEditorOp OP_SCALE }; +enum class ESoundSourceOp +{ + OP_NONE = 0, + OP_MOVE, + OP_CONTEXT_MENU, +}; + class CEnvelopeEditorOperationTracker { public: @@ -104,34 +96,81 @@ private: void HandlePointDragEnd(bool Switch); }; +class CSoundSourceOperationTracker +{ +public: + CSoundSourceOperationTracker(CEditor *pEditor); + + void Begin(CSoundSource *pSource, ESoundSourceOp Operation, int LayerIndex); + void End(); + +private: + CEditor *m_pEditor; + CSoundSource *m_pSource; + ESoundSourceOp m_TrackedOp; + int m_LayerIndex; + + struct SData + { + CPoint m_OriginalPoint; + }; + SData m_Data; + + enum EState + { + STATE_BEGIN, + STATE_EDITING, + STATE_END + }; + void HandlePointMove(EState State); +}; + +struct SPropTrackerHelper +{ + static int GetDefaultGroupIndex(CEditor *pEditor); + static int GetDefaultLayerIndex(CEditor *pEditor); +}; + template class CPropTracker { public: CPropTracker(CEditor *pEditor) : - m_pEditor(pEditor), m_OriginalValue(0) {} + m_pEditor(pEditor), m_OriginalValue(0), m_pObject(nullptr), m_OriginalLayerIndex(-1), m_OriginalGroupIndex(-1), m_CurrentLayerIndex(-1), m_CurrentGroupIndex(-1), m_Tracking(false) {} CEditor *m_pEditor; - void Begin(T *pObject, E Prop, EEditState State) + void Begin(T *pObject, E Prop, EEditState State, int GroupIndex = -1, int LayerIndex = -1) { - if(Prop == static_cast(-1)) + if(m_Tracking || Prop == static_cast(-1)) return; m_pObject = pObject; + + m_OriginalGroupIndex = GroupIndex < 0 ? SPropTrackerHelper::GetDefaultGroupIndex(m_pEditor) : GroupIndex; + m_OriginalLayerIndex = LayerIndex < 0 ? SPropTrackerHelper::GetDefaultLayerIndex(m_pEditor) : LayerIndex; + m_CurrentGroupIndex = m_OriginalGroupIndex; + m_CurrentLayerIndex = m_OriginalLayerIndex; + int Value = PropToValue(Prop); if(StartChecker(Prop, State, Value)) { + m_Tracking = true; m_OriginalValue = Value; OnStart(Prop); } } - void End(E Prop, EEditState State) + void End(E Prop, EEditState State, int GroupIndex = -1, int LayerIndex = -1) { - if(Prop == static_cast(-1)) + if(!m_Tracking || Prop == static_cast(-1)) return; + + m_CurrentGroupIndex = GroupIndex < 0 ? SPropTrackerHelper::GetDefaultGroupIndex(m_pEditor) : GroupIndex; + m_CurrentLayerIndex = LayerIndex < 0 ? SPropTrackerHelper::GetDefaultLayerIndex(m_pEditor) : LayerIndex; + int Value = PropToValue(Prop); if(EndChecker(Prop, State, Value)) { + m_Tracking = false; OnEnd(Prop, Value); } } @@ -151,6 +190,11 @@ protected: int m_OriginalValue; T *m_pObject; + int m_OriginalLayerIndex; + int m_OriginalGroupIndex; + int m_CurrentLayerIndex; + int m_CurrentGroupIndex; + bool m_Tracking; }; class CLayerPropTracker : public CPropTracker diff --git a/src/game/editor/popups.cpp b/src/game/editor/popups.cpp index a9c8e68f6..06c4e5a99 100644 --- a/src/game/editor/popups.cpp +++ b/src/game/editor/popups.cpp @@ -782,7 +782,7 @@ CUI::EPopupMenuFunctionResult CEditor::PopupLayer(void *pContext, CUIRect View, } else if(Prop == ELayerProp::PROP_GROUP) { - if(NewVal >= 0 && (size_t)NewVal < pEditor->m_Map.m_vpGroups.size()) + if(NewVal >= 0 && (size_t)NewVal < pEditor->m_Map.m_vpGroups.size() && NewVal != pEditor->m_SelectedGroup) { auto Position = std::find(pCurrentGroup->m_vpLayers.begin(), pCurrentGroup->m_vpLayers.end(), pCurrentLayer); if(Position != pCurrentGroup->m_vpLayers.end())