new_editor: support between-row hierarchy drag drop
This commit is contained in:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user