docs: 更新 containers 和 threading 模块文档
- containers: 更新 string 类的多个方法文档 - threading: 更新 mutex 和 task-group 方法文档
This commit is contained in:
165
editor/src/Core/UndoManager.cpp
Normal file
165
editor/src/Core/UndoManager.cpp
Normal file
@@ -0,0 +1,165 @@
|
||||
#include "Core/UndoManager.h"
|
||||
|
||||
#include "Core/ISelectionManager.h"
|
||||
#include "Managers/SceneManager.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Editor {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr size_t kMaxUndoHistory = 128;
|
||||
|
||||
} // namespace
|
||||
|
||||
UndoManager::UndoManager(SceneManager& sceneManager, ISelectionManager& selectionManager)
|
||||
: m_sceneManager(sceneManager)
|
||||
, m_selectionManager(selectionManager) {}
|
||||
|
||||
void UndoManager::ClearHistory() {
|
||||
m_history.clear();
|
||||
m_nextIndex = 0;
|
||||
m_pendingInteractiveChange.reset();
|
||||
}
|
||||
|
||||
bool UndoManager::CanUndo() const {
|
||||
return m_nextIndex > 0;
|
||||
}
|
||||
|
||||
bool UndoManager::CanRedo() const {
|
||||
return m_nextIndex < m_history.size();
|
||||
}
|
||||
|
||||
const std::string& UndoManager::GetUndoLabel() const {
|
||||
return CanUndo() ? m_history[m_nextIndex - 1].label : m_emptyLabel;
|
||||
}
|
||||
|
||||
const std::string& UndoManager::GetRedoLabel() const {
|
||||
return CanRedo() ? m_history[m_nextIndex].label : m_emptyLabel;
|
||||
}
|
||||
|
||||
void UndoManager::Undo() {
|
||||
if (HasPendingInteractiveChange()) {
|
||||
FinalizeInteractiveChange();
|
||||
}
|
||||
|
||||
if (!CanUndo()) {
|
||||
return;
|
||||
}
|
||||
|
||||
--m_nextIndex;
|
||||
ApplyState(m_history[m_nextIndex].before);
|
||||
}
|
||||
|
||||
void UndoManager::Redo() {
|
||||
if (HasPendingInteractiveChange()) {
|
||||
FinalizeInteractiveChange();
|
||||
}
|
||||
|
||||
if (!CanRedo()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ApplyState(m_history[m_nextIndex].after);
|
||||
++m_nextIndex;
|
||||
}
|
||||
|
||||
UndoStateSnapshot UndoManager::CaptureCurrentState() const {
|
||||
UndoStateSnapshot snapshot;
|
||||
snapshot.scene = m_sceneManager.CaptureSceneSnapshot();
|
||||
|
||||
if (!snapshot.scene.hasScene) {
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
for (uint64_t entityId : m_selectionManager.GetSelectedEntities()) {
|
||||
if (m_sceneManager.GetEntity(entityId)) {
|
||||
snapshot.selectionIds.push_back(entityId);
|
||||
}
|
||||
}
|
||||
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
void UndoManager::PushCommand(const std::string& label, UndoStateSnapshot before, UndoStateSnapshot after) {
|
||||
if (AreStatesEqual(before, after)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_nextIndex < m_history.size()) {
|
||||
m_history.erase(m_history.begin() + static_cast<std::ptrdiff_t>(m_nextIndex), m_history.end());
|
||||
}
|
||||
|
||||
m_history.push_back(CommandEntry{ label, std::move(before), std::move(after) });
|
||||
if (m_history.size() > kMaxUndoHistory) {
|
||||
m_history.erase(m_history.begin());
|
||||
if (m_nextIndex > 0) {
|
||||
--m_nextIndex;
|
||||
}
|
||||
}
|
||||
|
||||
m_nextIndex = m_history.size();
|
||||
}
|
||||
|
||||
void UndoManager::BeginInteractiveChange(const std::string& label) {
|
||||
if (m_pendingInteractiveChange.has_value()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_pendingInteractiveChange = PendingInteractiveChange{ label, CaptureCurrentState() };
|
||||
}
|
||||
|
||||
bool UndoManager::HasPendingInteractiveChange() const {
|
||||
return m_pendingInteractiveChange.has_value();
|
||||
}
|
||||
|
||||
void UndoManager::FinalizeInteractiveChange() {
|
||||
if (!m_pendingInteractiveChange.has_value()) {
|
||||
return;
|
||||
}
|
||||
|
||||
PushCommand(
|
||||
m_pendingInteractiveChange->label,
|
||||
std::move(m_pendingInteractiveChange->before),
|
||||
CaptureCurrentState());
|
||||
m_pendingInteractiveChange.reset();
|
||||
}
|
||||
|
||||
void UndoManager::CancelInteractiveChange() {
|
||||
m_pendingInteractiveChange.reset();
|
||||
}
|
||||
|
||||
bool UndoManager::ApplyState(const UndoStateSnapshot& state) {
|
||||
if (!m_sceneManager.RestoreSceneSnapshot(state.scene)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint64_t> validSelection;
|
||||
validSelection.reserve(state.selectionIds.size());
|
||||
for (uint64_t entityId : state.selectionIds) {
|
||||
if (m_sceneManager.GetEntity(entityId)) {
|
||||
validSelection.push_back(entityId);
|
||||
}
|
||||
}
|
||||
|
||||
if (validSelection.empty()) {
|
||||
m_selectionManager.ClearSelection();
|
||||
} else {
|
||||
m_selectionManager.SetSelectedEntities(validSelection);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UndoManager::AreStatesEqual(const UndoStateSnapshot& lhs, const UndoStateSnapshot& rhs) {
|
||||
return lhs.scene.hasScene == rhs.scene.hasScene &&
|
||||
lhs.scene.scenePath == rhs.scene.scenePath &&
|
||||
lhs.scene.sceneData == rhs.scene.sceneData &&
|
||||
lhs.scene.dirty == rhs.scene.dirty &&
|
||||
lhs.selectionIds == rhs.selectionIds;
|
||||
}
|
||||
|
||||
} // namespace Editor
|
||||
} // namespace XCEngine
|
||||
Reference in New Issue
Block a user