new_editor: support between-row hierarchy drag drop

This commit is contained in:
2026-04-23 14:09:28 +08:00
parent e63457c72b
commit 5c0a878aa0
63 changed files with 596 additions and 12 deletions

View File

@@ -145,6 +145,79 @@ bool WouldCreateCycle(
return false;
}
std::vector<GameObject*> ResolveSiblingSequence(
Scene& scene,
GameObject* parent) {
return parent != nullptr
? parent->GetChildren()
: scene.GetRootGameObjects();
}
std::optional<std::size_t> FindSiblingIndex(
const std::vector<GameObject*>& siblings,
const GameObject* gameObject) {
if (gameObject == nullptr) {
return std::nullopt;
}
const auto it =
std::find(siblings.begin(), siblings.end(), gameObject);
if (it == siblings.end()) {
return std::nullopt;
}
return static_cast<std::size_t>(std::distance(siblings.begin(), it));
}
bool MoveGameObjectRelativeToTarget(
std::string_view itemId,
std::string_view targetItemId,
bool placeAfterTarget) {
Scene* scene = ResolvePrimaryScene();
GameObject* gameObject = FindEditorGameObject(itemId);
GameObject* target = FindEditorGameObject(targetItemId);
if (scene == nullptr ||
gameObject == nullptr ||
target == nullptr ||
gameObject == target) {
return false;
}
GameObject* targetParent = target->GetParent();
if (targetParent != nullptr &&
WouldCreateCycle(*gameObject, *targetParent)) {
return false;
}
const std::vector<GameObject*> siblings =
ResolveSiblingSequence(*scene, targetParent);
const std::optional<std::size_t> targetIndex =
FindSiblingIndex(siblings, target);
if (!targetIndex.has_value()) {
return false;
}
std::size_t finalIndex =
targetIndex.value() + (placeAfterTarget ? 1u : 0u);
if (gameObject->GetParent() == targetParent) {
const std::optional<std::size_t> sourceIndex =
FindSiblingIndex(siblings, gameObject);
if (sourceIndex.has_value()) {
if ((!placeAfterTarget && sourceIndex.value() < targetIndex.value()) ||
(placeAfterTarget && sourceIndex.value() <= targetIndex.value())) {
--finalIndex;
}
if (finalIndex == sourceIndex.value()) {
return false;
}
}
}
gameObject->SetParent(targetParent, finalIndex, true);
return true;
}
} // namespace
EditorStartupSceneResult EnsureEditorStartupScene(
@@ -330,6 +403,18 @@ bool ReparentEditorGameObject(
return true;
}
bool MoveEditorGameObjectBefore(
std::string_view itemId,
std::string_view targetItemId) {
return MoveGameObjectRelativeToTarget(itemId, targetItemId, false);
}
bool MoveEditorGameObjectAfter(
std::string_view itemId,
std::string_view targetItemId) {
return MoveGameObjectRelativeToTarget(itemId, targetItemId, true);
}
bool MoveEditorGameObjectToRoot(std::string_view itemId) {
GameObject* gameObject = FindEditorGameObject(itemId);
if (gameObject == nullptr || gameObject->GetParent() == nullptr) {