Files
leocad/common/lc_modelhistory.h
T
Leonardo Zide 851eecee50 Store only changed objects in edit undo history
Full before-and-after model snapshots accumulate large amounts of memory during editing, even when an operation changes only one object. Compact completed edits to retain only added, removed, or modified object states, with ordering metadata kept only for structural changes.

Restore objects by stable IDs, including group relationships, and detach views before removing cameras. Compose merged edits from their deltas and compare animation keys as well as current property values so keyframe-only edits remain undoable.
2026-10-21 10:48:24 -07:00

163 lines
4.6 KiB
C++

#pragma once
#include "lc_model.h"
#include "lc_objecthistory.h"
enum class lcObjectType;
enum class lcSelectionMode;
class lcModelHistory
{
public:
lcModelHistory() = default;
virtual ~lcModelHistory() = default;
virtual void SaveStartState(const lcModel* Model) = 0;
virtual void SaveEndState(const lcModel* Model) = 0;
virtual void LoadStartState(lcModel* Model) const = 0;
virtual void LoadEndState(lcModel* Model) const = 0;
virtual bool StateChanged() const = 0;
virtual void RenamePieces(const std::vector<lcModelPieceRename>& Renames, const lcPieceData* ModelPieceData)
{
Q_UNUSED(Renames);
Q_UNUSED(ModelPieceData);
}
virtual bool CanMergeWith(const lcModelHistory* Other) const
{
Q_UNUSED(Other);
return false;
}
virtual void MergeWith(lcModelHistory* Other)
{
Q_UNUSED(Other);
}
};
struct lcModelHistorySelectState
{
std::vector<bool> PieceSelection;
std::vector<bool> CameraSelection;
std::vector<bool> LightSelection;
size_t FocusIndex = SIZE_MAX;
uint32_t FocusSection = ~0U;
lcObjectType FocusObjectType = static_cast<lcObjectType>(~0);
bool operator!=(const lcModelHistorySelectState& Other) const
{
return PieceSelection != Other.PieceSelection || CameraSelection != Other.CameraSelection || LightSelection != Other.LightSelection ||
FocusIndex != Other.FocusIndex || FocusSection != Other.FocusSection || FocusObjectType != Other.FocusObjectType;
}
};
class lcModelHistorySelect : public lcModelHistory
{
public:
lcModelHistorySelect() = default;
virtual ~lcModelHistorySelect() = default;
void SaveStartState(const lcModel* Model) override;
void SaveEndState(const lcModel* Model) override;
void LoadStartState(lcModel* Model) const override;
void LoadEndState(lcModel* Model) const override;
bool StateChanged() const override;
protected:
static void SaveState(lcModelHistorySelectState& State, const lcModel* Model);
static void LoadState(const lcModelHistorySelectState& State, lcModel* Model);
lcModelHistorySelectState mStartState;
lcModelHistorySelectState mEndState;
};
struct lcGroupHistoryState;
struct lcPieceHistoryState;
struct lcCameraHistoryState;
struct lcLightHistoryState;
struct lcModelHistoryEditState
{
lcObjectHistory<lcGroupHistoryState> Groups;
lcObjectHistory<lcPieceHistoryState> Pieces;
lcObjectHistory<lcCameraHistoryState> Cameras;
lcObjectHistory<lcLightHistoryState> Lights;
bool IsEmpty() const
{
return Groups.IsEmpty() && Pieces.IsEmpty() && Cameras.IsEmpty() && Lights.IsEmpty();
}
};
enum class lcModelHistoryEditMerge
{
None,
KeyboardMove,
KeyboardRotate,
KeyboardZoom,
KeyboardMoveCamera,
PropertiesMove,
PropertiesRotate,
PropertiesEdit
};
struct lcModelHistoryEditMergeKey
{
lcModelHistoryEditMerge Operation;
lcObjectPropertyId PropertyEditId = lcObjectPropertyId::Count;
lcStep Step;
bool AddKeys;
bool operator==(const lcModelHistoryEditMergeKey& Other) const
{
return Operation == Other.Operation && PropertyEditId == Other.PropertyEditId && Step == Other.Step && AddKeys == Other.AddKeys;
}
};
class lcModelHistoryEdit : public lcModelHistory
{
public:
lcModelHistoryEdit(lcModelHistoryEditMergeKey MergeKey);
virtual ~lcModelHistoryEdit();
void SaveStartState(const lcModel* Model) override;
void SaveEndState(const lcModel* Model) override;
void LoadStartState(lcModel* Model) const override;
void LoadEndState(lcModel* Model) const override;
bool StateChanged() const override;
void RenamePieces(const std::vector<lcModelPieceRename>& Renames, const lcPieceData* ModelPieceData) override;
bool CanMergeWith(const lcModelHistory* Other) const override;
void MergeWith(lcModelHistory* Other) override;
protected:
static void SaveState(lcModelHistoryEditState& State, const lcModel* Model);
static void LoadState(const lcModelHistoryEditState& State, lcModel* Model);
lcModelHistoryEditState mStartState;
lcModelHistoryEditState mEndState;
lcModelHistoryEditMergeKey mMergeKey;
};
class lcModelHistoryProperties : public lcModelHistory
{
public:
lcModelHistoryProperties() = default;
virtual ~lcModelHistoryProperties() = default;
void SaveStartState(const lcModel* Model) override;
void SaveEndState(const lcModel* Model) override;
void LoadStartState(lcModel* Model) const override;
void LoadEndState(lcModel* Model) const override;
bool StateChanged() const override;
void RenamePieces(const std::vector<lcModelPieceRename>& Renames, const lcPieceData* ModelPieceData) override;
protected:
static void SaveState(lcModelProperties& State, const lcModel* Model);
static void LoadState(const lcModelProperties& State, lcModel* Model);
lcModelProperties mStartState;
lcModelProperties mEndState;
};