mirror of
https://github.com/enduro2d/enduro2d.git
synced 2026-01-05 01:51:02 +07:00
basic scene node
This commit is contained in:
@@ -11,6 +11,8 @@
|
||||
#include "assets.hpp"
|
||||
#include "library.hpp"
|
||||
#include "library.inl"
|
||||
#include "scene.hpp"
|
||||
#include "scene.inl"
|
||||
#include "starter.hpp"
|
||||
#include "world.hpp"
|
||||
|
||||
|
||||
@@ -31,6 +31,9 @@ namespace e2d
|
||||
class sprite_system;
|
||||
}
|
||||
|
||||
class node;
|
||||
class scene;
|
||||
|
||||
class asset;
|
||||
class library;
|
||||
|
||||
|
||||
119
headers/enduro2d/high/scene.hpp
Normal file
119
headers/enduro2d/high/scene.hpp
Normal file
@@ -0,0 +1,119 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "Enduro2D"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2018 Matvey Cherevko
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef E2D_INCLUDE_GUARD_8703CE4A74D94C3CA27ED91AFF906936
|
||||
#define E2D_INCLUDE_GUARD_8703CE4A74D94C3CA27ED91AFF906936
|
||||
#pragma once
|
||||
|
||||
#include "_high.hpp"
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
class node;
|
||||
using node_iptr = intrusive_ptr<node>;
|
||||
using const_node_iptr = intrusive_ptr<const node>;
|
||||
|
||||
class scene;
|
||||
using scene_iptr = intrusive_ptr<scene>;
|
||||
using const_scene_iptr = intrusive_ptr<const scene>;
|
||||
|
||||
class node_children_ilist_tag {};
|
||||
using node_children = intrusive_list<node, node_children_ilist_tag>;
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
class node final
|
||||
: private noncopyable
|
||||
, public ref_counter<node>
|
||||
, public intrusive_list_hook<node_children_ilist_tag> {
|
||||
public:
|
||||
~node() noexcept;
|
||||
static node_iptr create();
|
||||
static node_iptr create(const node_iptr& parent);
|
||||
|
||||
node_iptr root() noexcept;
|
||||
const_node_iptr root() const noexcept;
|
||||
|
||||
node_iptr parent() noexcept;
|
||||
const_node_iptr parent() const noexcept;
|
||||
|
||||
bool remove_from_parent() noexcept;
|
||||
std::size_t remove_all_children() noexcept;
|
||||
|
||||
bool add_child(
|
||||
const node_iptr& child) noexcept;
|
||||
|
||||
bool add_child_to_back(
|
||||
const node_iptr& child) noexcept;
|
||||
|
||||
bool add_child_to_front(
|
||||
const node_iptr& child) noexcept;
|
||||
|
||||
bool add_child_after(
|
||||
const const_node_iptr& after,
|
||||
const node_iptr& child) noexcept;
|
||||
|
||||
bool add_child_before(
|
||||
const const_node_iptr& before,
|
||||
const node_iptr& child) noexcept;
|
||||
|
||||
bool send_backward() noexcept;
|
||||
bool bring_to_back() noexcept;
|
||||
|
||||
bool send_forward() noexcept;
|
||||
bool bring_to_front() noexcept;
|
||||
|
||||
std::size_t child_count() const noexcept;
|
||||
std::size_t child_count_recursive() const noexcept;
|
||||
|
||||
node_iptr last_child() noexcept;
|
||||
const_node_iptr last_child() const noexcept;
|
||||
|
||||
node_iptr first_child() noexcept;
|
||||
const_node_iptr first_child() const noexcept;
|
||||
|
||||
node_iptr prev_sibling() noexcept;
|
||||
const_node_iptr prev_sibling() const noexcept;
|
||||
|
||||
node_iptr next_sibling() noexcept;
|
||||
const_node_iptr next_sibling() const noexcept;
|
||||
|
||||
template < typename F >
|
||||
void for_each_child(F&& f);
|
||||
|
||||
template < typename F >
|
||||
void for_each_child(F&& f) const;
|
||||
|
||||
template < typename F >
|
||||
std::size_t remove_child_if(F&& f);
|
||||
private:
|
||||
node();
|
||||
private:
|
||||
node* parent_{nullptr};
|
||||
node_children children_;
|
||||
};
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
class scene final
|
||||
: private noncopyable
|
||||
, public ref_counter<scene> {
|
||||
public:
|
||||
~scene() noexcept;
|
||||
static scene_iptr create();
|
||||
|
||||
const node_iptr& root() const noexcept;
|
||||
private:
|
||||
scene();
|
||||
private:
|
||||
node_iptr root_ = node::create();
|
||||
};
|
||||
}
|
||||
|
||||
#include "scene.inl"
|
||||
#endif
|
||||
46
headers/enduro2d/high/scene.inl
Normal file
46
headers/enduro2d/high/scene.inl
Normal file
@@ -0,0 +1,46 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "Enduro2D"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2018 Matvey Cherevko
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef E2D_INCLUDE_GUARD_27EFFE66AA124FFB862BE95C2FF38017
|
||||
#define E2D_INCLUDE_GUARD_27EFFE66AA124FFB862BE95C2FF38017
|
||||
#pragma once
|
||||
|
||||
#include "scene.hpp"
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
template < typename F >
|
||||
void node::for_each_child(F&& f) {
|
||||
for ( node& child : children_ ) {
|
||||
f(node_iptr(&child));
|
||||
}
|
||||
}
|
||||
|
||||
template < typename F >
|
||||
void node::for_each_child(F&& f) const {
|
||||
for ( const node& child : children_ ) {
|
||||
f(const_node_iptr(&child));
|
||||
}
|
||||
}
|
||||
|
||||
template < typename F >
|
||||
std::size_t node::remove_child_if(F&& f) {
|
||||
std::size_t count = 0u;
|
||||
for ( auto iter = children_.begin(); iter != children_.end(); ) {
|
||||
node_iptr child(&*iter);
|
||||
if ( f(child) ) {
|
||||
++count;
|
||||
++iter;
|
||||
child->remove_from_parent();
|
||||
} else {
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
267
sources/enduro2d/high/scene.cpp
Normal file
267
sources/enduro2d/high/scene.cpp
Normal file
@@ -0,0 +1,267 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "Enduro2D"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2018 Matvey Cherevko
|
||||
******************************************************************************/
|
||||
|
||||
#include <enduro2d/high/scene.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace e2d;
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
node::node() = default;
|
||||
|
||||
node::~node() noexcept {
|
||||
remove_all_children();
|
||||
remove_from_parent();
|
||||
}
|
||||
|
||||
node_iptr node::create() {
|
||||
return node_iptr(new node());
|
||||
}
|
||||
|
||||
node_iptr node::create(const node_iptr& parent) {
|
||||
node_iptr child = create();
|
||||
if ( parent ) {
|
||||
parent->add_child(child);
|
||||
}
|
||||
return child;
|
||||
}
|
||||
|
||||
node_iptr node::root() noexcept {
|
||||
node* root = this;
|
||||
while ( root->parent_ ) {
|
||||
root = root->parent_;
|
||||
}
|
||||
return node_iptr(root);
|
||||
}
|
||||
|
||||
const_node_iptr node::root() const noexcept {
|
||||
const node* root = this;
|
||||
while ( root->parent_ ) {
|
||||
root = root->parent_;
|
||||
}
|
||||
return const_node_iptr(root);
|
||||
}
|
||||
|
||||
node_iptr node::parent() noexcept {
|
||||
return node_iptr(parent_);
|
||||
}
|
||||
|
||||
const_node_iptr node::parent() const noexcept {
|
||||
return const_node_iptr(parent_);
|
||||
}
|
||||
|
||||
bool node::remove_from_parent() noexcept {
|
||||
if ( !parent_ ) {
|
||||
return false;
|
||||
}
|
||||
parent_->children_.erase(
|
||||
node_children::iterator_to(*this));
|
||||
parent_ = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::size_t node::remove_all_children() noexcept {
|
||||
std::size_t count = 0;
|
||||
while ( !children_.empty() ) {
|
||||
children_.back().remove_from_parent();
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
bool node::add_child(const node_iptr& child) noexcept {
|
||||
return add_child_to_front(child);
|
||||
}
|
||||
|
||||
bool node::add_child_to_back(
|
||||
const node_iptr& child) noexcept
|
||||
{
|
||||
if ( !child ) {
|
||||
return false;
|
||||
}
|
||||
child->remove_from_parent();
|
||||
children_.push_front(*child);
|
||||
child->parent_ = this;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool node::add_child_to_front(
|
||||
const node_iptr& child) noexcept
|
||||
{
|
||||
if ( !child ) {
|
||||
return false;
|
||||
}
|
||||
child->remove_from_parent();
|
||||
children_.push_back(*child);
|
||||
child->parent_ = this;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool node::add_child_after(
|
||||
const const_node_iptr& after,
|
||||
const node_iptr& child) noexcept
|
||||
{
|
||||
if ( !after ) {
|
||||
return add_child_to_front(child);
|
||||
}
|
||||
|
||||
if ( !child || after->parent_ != this ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
child->remove_from_parent();
|
||||
const auto iter = ++node_children::iterator_to(*after);
|
||||
children_.insert(iter, *child);
|
||||
child->parent_ = this;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool node::add_child_before(
|
||||
const const_node_iptr& before,
|
||||
const node_iptr& child) noexcept
|
||||
{
|
||||
if ( !before ) {
|
||||
return add_child_to_back(child);
|
||||
}
|
||||
|
||||
if ( !child || before->parent_ != this ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
child->remove_from_parent();
|
||||
const auto iter = node_children::iterator_to(*before);
|
||||
children_.insert(iter, *child);
|
||||
child->parent_ = this;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool node::send_backward() noexcept {
|
||||
const_node_iptr prev = prev_sibling();
|
||||
return prev
|
||||
? parent_->add_child_before(prev, this)
|
||||
: false;
|
||||
}
|
||||
|
||||
bool node::bring_to_back() noexcept {
|
||||
const_node_iptr prev = prev_sibling();
|
||||
return prev
|
||||
? parent_->add_child_to_back(this)
|
||||
: false;
|
||||
}
|
||||
|
||||
bool node::send_forward() noexcept {
|
||||
const_node_iptr next = next_sibling();
|
||||
return next
|
||||
? parent_->add_child_after(next, this)
|
||||
: false;
|
||||
}
|
||||
|
||||
bool node::bring_to_front() noexcept {
|
||||
const_node_iptr next = next_sibling();
|
||||
return next
|
||||
? parent_->add_child_to_front(this)
|
||||
: false;
|
||||
}
|
||||
|
||||
std::size_t node::child_count() const noexcept {
|
||||
return children_.size();
|
||||
}
|
||||
|
||||
std::size_t node::child_count_recursive() const noexcept {
|
||||
std::size_t count = child_count();
|
||||
for ( const node& child : children_ ) {
|
||||
count += child.child_count_recursive();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
node_iptr node::last_child() noexcept {
|
||||
return !children_.empty()
|
||||
? node_iptr(&children_.back())
|
||||
: node_iptr();
|
||||
}
|
||||
|
||||
const_node_iptr node::last_child() const noexcept {
|
||||
return !children_.empty()
|
||||
? const_node_iptr(&children_.back())
|
||||
: const_node_iptr();
|
||||
}
|
||||
|
||||
node_iptr node::first_child() noexcept {
|
||||
return !children_.empty()
|
||||
? node_iptr(&children_.front())
|
||||
: node_iptr();
|
||||
}
|
||||
|
||||
const_node_iptr node::first_child() const noexcept {
|
||||
return !children_.empty()
|
||||
? const_node_iptr(&children_.front())
|
||||
: const_node_iptr();
|
||||
}
|
||||
|
||||
node_iptr node::prev_sibling() noexcept {
|
||||
if ( !parent_ ) {
|
||||
return nullptr;
|
||||
}
|
||||
auto iter = node_children::iterator_to(*this);
|
||||
if ( iter == parent_->children_.begin() ) {
|
||||
return nullptr;
|
||||
}
|
||||
--iter;
|
||||
return node_iptr(&*iter);
|
||||
}
|
||||
|
||||
const_node_iptr node::prev_sibling() const noexcept {
|
||||
if ( !parent_ ) {
|
||||
return nullptr;
|
||||
}
|
||||
auto iter = node_children::iterator_to(*this);
|
||||
if ( iter == parent_->children_.begin() ) {
|
||||
return nullptr;
|
||||
}
|
||||
--iter;
|
||||
return const_node_iptr(&*iter);
|
||||
}
|
||||
|
||||
node_iptr node::next_sibling() noexcept {
|
||||
if ( !parent_ ) {
|
||||
return nullptr;
|
||||
}
|
||||
auto iter = node_children::iterator_to(*this);
|
||||
if ( ++iter == parent_->children_.end() ) {
|
||||
return nullptr;
|
||||
}
|
||||
return node_iptr(&*iter);
|
||||
}
|
||||
|
||||
const_node_iptr node::next_sibling() const noexcept {
|
||||
if ( !parent_ ) {
|
||||
return nullptr;
|
||||
}
|
||||
auto iter = node_children::iterator_to(*this);
|
||||
if ( ++iter == parent_->children_.end() ) {
|
||||
return nullptr;
|
||||
}
|
||||
return const_node_iptr(&*iter);
|
||||
}
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
scene::scene() = default;
|
||||
scene::~scene() noexcept = default;
|
||||
|
||||
scene_iptr scene::create() {
|
||||
return scene_iptr(new scene());
|
||||
}
|
||||
|
||||
const node_iptr& scene::root() const noexcept {
|
||||
return root_;
|
||||
}
|
||||
}
|
||||
424
untests/sources/untests_high/scene.cpp
Normal file
424
untests/sources/untests_high/scene.cpp
Normal file
@@ -0,0 +1,424 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "Enduro2D"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2018 Matvey Cherevko
|
||||
******************************************************************************/
|
||||
|
||||
#include "_high.hpp"
|
||||
using namespace e2d;
|
||||
|
||||
namespace
|
||||
{
|
||||
}
|
||||
|
||||
TEST_CASE("node") {
|
||||
SECTION("empty_node") {
|
||||
auto n = node::create();
|
||||
REQUIRE(n);
|
||||
REQUIRE(n->root() == n);
|
||||
REQUIRE_FALSE(n->parent());
|
||||
REQUIRE(n->child_count() == 0);
|
||||
REQUIRE_FALSE(n->prev_sibling());
|
||||
REQUIRE_FALSE(n->next_sibling());
|
||||
{
|
||||
const_node_iptr cn = n;
|
||||
REQUIRE(cn);
|
||||
REQUIRE(cn->root() == cn);
|
||||
REQUIRE_FALSE(cn->parent());
|
||||
REQUIRE(cn->child_count() == 0);
|
||||
REQUIRE_FALSE(cn->prev_sibling());
|
||||
REQUIRE_FALSE(cn->next_sibling());
|
||||
}
|
||||
}
|
||||
SECTION("parent/root") {
|
||||
{
|
||||
auto p = node::create();
|
||||
auto n = node::create();
|
||||
|
||||
REQUIRE(p->add_child(n));
|
||||
REQUIRE(n->parent() == p);
|
||||
REQUIRE(p->child_count() == 1);
|
||||
|
||||
REQUIRE(p->add_child(n));
|
||||
REQUIRE(n->parent() == p);
|
||||
REQUIRE(p->child_count() == 1);
|
||||
|
||||
REQUIRE_FALSE(p->add_child(nullptr));
|
||||
REQUIRE(n->parent() == p);
|
||||
REQUIRE(p->child_count() == 1);
|
||||
}
|
||||
{
|
||||
auto p = node::create();
|
||||
|
||||
auto n1 = node::create(p);
|
||||
REQUIRE(n1->parent() == p);
|
||||
REQUIRE(p->child_count() == 1);
|
||||
|
||||
auto n2 = node::create(nullptr);
|
||||
REQUIRE_FALSE(n2->parent());
|
||||
REQUIRE(p->child_count() == 1);
|
||||
}
|
||||
{
|
||||
auto p1 = node::create();
|
||||
auto p2 = node::create();
|
||||
|
||||
auto n = node::create(p1);
|
||||
REQUIRE(n->parent() == p1);
|
||||
REQUIRE(p1->child_count() == 1);
|
||||
REQUIRE(p2->child_count() == 0);
|
||||
|
||||
REQUIRE(p2->add_child(n));
|
||||
REQUIRE(n->parent() == p2);
|
||||
REQUIRE(p1->child_count() == 0);
|
||||
REQUIRE(p2->child_count() == 1);
|
||||
}
|
||||
{
|
||||
auto p1 = node::create();
|
||||
auto p2 = node::create(p1);
|
||||
|
||||
auto n1 = node::create(p1);
|
||||
auto n2 = node::create(p2);
|
||||
|
||||
REQUIRE(n1->parent() == p1);
|
||||
REQUIRE(n2->parent() == p2);
|
||||
|
||||
REQUIRE(n1->root() == p1);
|
||||
REQUIRE(n2->root() == p1);
|
||||
|
||||
auto n3 = node::create();
|
||||
REQUIRE_FALSE(n3->parent());
|
||||
REQUIRE(n3->root() == n3);
|
||||
|
||||
{
|
||||
const_node_iptr cn1 = n1;
|
||||
const_node_iptr cn2 = n2;
|
||||
|
||||
REQUIRE(cn1->parent() == p1);
|
||||
REQUIRE(cn2->parent() == p2);
|
||||
|
||||
REQUIRE(cn1->root() == p1);
|
||||
REQUIRE(cn2->root() == p1);
|
||||
|
||||
const_node_iptr cn3 = node::create();
|
||||
REQUIRE_FALSE(cn3->parent());
|
||||
REQUIRE(cn3->root() == cn3);
|
||||
}
|
||||
}
|
||||
}
|
||||
SECTION("auto_remove/remove_all_children") {
|
||||
{
|
||||
auto p = node::create();
|
||||
auto n = node::create(p);
|
||||
n.reset();
|
||||
REQUIRE(p->child_count() == 0);
|
||||
}
|
||||
{
|
||||
auto p = node::create();
|
||||
auto n1 = node::create(p);
|
||||
auto n2 = node::create(p);
|
||||
REQUIRE(p->child_count() == 2);
|
||||
REQUIRE(p->remove_all_children() == 2);
|
||||
REQUIRE_FALSE(n1->parent());
|
||||
REQUIRE_FALSE(n2->parent());
|
||||
REQUIRE(p->child_count() == 0);
|
||||
REQUIRE(p->remove_all_children() == 0);
|
||||
}
|
||||
}
|
||||
SECTION("remove_from_parent") {
|
||||
{
|
||||
auto p = node::create();
|
||||
auto n1 = node::create(p);
|
||||
auto n2 = node::create(p);
|
||||
|
||||
auto np = node::create();
|
||||
np->remove_from_parent();
|
||||
REQUIRE(np->root() == np);
|
||||
REQUIRE_FALSE(np->parent());
|
||||
|
||||
REQUIRE(p->child_count() == 2);
|
||||
REQUIRE(n1->parent() == p);
|
||||
REQUIRE(n2->parent() == p);
|
||||
|
||||
REQUIRE(n1->remove_from_parent());
|
||||
REQUIRE_FALSE(n1->parent());
|
||||
REQUIRE(p->child_count() == 1);
|
||||
|
||||
REQUIRE(n2->remove_from_parent());
|
||||
REQUIRE_FALSE(n2->parent());
|
||||
REQUIRE(p->child_count() == 0);
|
||||
}
|
||||
}
|
||||
SECTION("child_count/child_count_recursive") {
|
||||
auto p1 = node::create();
|
||||
REQUIRE(p1->child_count() == 0);
|
||||
REQUIRE(p1->child_count_recursive() == 0);
|
||||
|
||||
auto p2 = node::create(p1);
|
||||
REQUIRE(p1->child_count() == 1);
|
||||
REQUIRE(p1->child_count_recursive() == 1);
|
||||
REQUIRE(p2->child_count() == 0);
|
||||
REQUIRE(p2->child_count_recursive() == 0);
|
||||
|
||||
auto n1 = node::create(p2);
|
||||
auto n2 = node::create(p2);
|
||||
REQUIRE(p1->child_count() == 1);
|
||||
REQUIRE(p1->child_count_recursive() == 3);
|
||||
REQUIRE(p2->child_count() == 2);
|
||||
REQUIRE(p2->child_count_recursive() == 2);
|
||||
}
|
||||
SECTION("send_backward/bring_to_back") {
|
||||
{
|
||||
auto p = node::create();
|
||||
auto n1 = node::create(p);
|
||||
auto n2 = node::create(p);
|
||||
auto n3 = node::create(p);
|
||||
|
||||
REQUIRE(n3->send_backward()); // n1 n3 n2
|
||||
REQUIRE(n1->next_sibling() == n3);
|
||||
|
||||
REQUIRE(n3->send_backward()); // n3 n1 n2
|
||||
REQUIRE(n3->next_sibling() == n1);
|
||||
|
||||
REQUIRE_FALSE(n3->send_backward()); // n3 n1 n2
|
||||
REQUIRE(n3->next_sibling() == n1);
|
||||
|
||||
REQUIRE(n2->bring_to_back()); // n2 n3 n1
|
||||
REQUIRE(n2->next_sibling() == n3);
|
||||
|
||||
REQUIRE_FALSE(n2->bring_to_back()); // n2 n3 n1
|
||||
REQUIRE(n2->next_sibling() == n3);
|
||||
}
|
||||
{
|
||||
auto n = node::create();
|
||||
REQUIRE_FALSE(n->send_backward());
|
||||
REQUIRE_FALSE(n->bring_to_back());
|
||||
}
|
||||
}
|
||||
SECTION("send_forward/bring_to_front") {
|
||||
{
|
||||
auto p = node::create();
|
||||
auto n1 = node::create(p);
|
||||
auto n2 = node::create(p);
|
||||
auto n3 = node::create(p);
|
||||
|
||||
REQUIRE(n1->send_forward()); // n2 n1 n3
|
||||
REQUIRE(n2->next_sibling() == n1);
|
||||
|
||||
REQUIRE(n1->send_forward()); // n2 n3 n1
|
||||
REQUIRE(n3->next_sibling() == n1);
|
||||
|
||||
REQUIRE_FALSE(n1->send_forward()); // n2 n3 n1
|
||||
REQUIRE(n3->next_sibling() == n1);
|
||||
|
||||
REQUIRE(n2->bring_to_front()); // n3 n1 n2
|
||||
REQUIRE(n1->next_sibling() == n2);
|
||||
|
||||
REQUIRE_FALSE(n2->bring_to_front()); // n3 n1 n2
|
||||
REQUIRE(n1->next_sibling() == n2);
|
||||
}
|
||||
{
|
||||
auto n = node::create();
|
||||
REQUIRE_FALSE(n->send_forward());
|
||||
REQUIRE_FALSE(n->bring_to_back());
|
||||
}
|
||||
}
|
||||
SECTION("last_child/first_child") {
|
||||
auto p = node::create();
|
||||
auto n1 = node::create(p);
|
||||
auto n2 = node::create(p);
|
||||
auto n3 = node::create(p);
|
||||
|
||||
REQUIRE(p->last_child() == n3);
|
||||
REQUIRE(p->first_child() == n1);
|
||||
|
||||
{
|
||||
const_node_iptr cp = p;
|
||||
|
||||
REQUIRE(cp->last_child() == n3);
|
||||
REQUIRE(cp->first_child() == n1);
|
||||
}
|
||||
}
|
||||
SECTION("prev_sibling/next_sibling") {
|
||||
auto p = node::create();
|
||||
|
||||
auto n1 = node::create(p);
|
||||
auto n2 = node::create(p);
|
||||
auto n3 = node::create(p);
|
||||
|
||||
REQUIRE_FALSE(n1->prev_sibling());
|
||||
REQUIRE(n1->next_sibling() == n2);
|
||||
|
||||
REQUIRE(n2->prev_sibling() == n1);
|
||||
REQUIRE(n2->next_sibling() == n3);
|
||||
|
||||
REQUIRE(n3->prev_sibling() == n2);
|
||||
REQUIRE_FALSE(n3->next_sibling());
|
||||
|
||||
auto n4 = node::create();
|
||||
REQUIRE_FALSE(n4->prev_sibling());
|
||||
REQUIRE_FALSE(n4->next_sibling());
|
||||
|
||||
{
|
||||
const_node_iptr cn1 = n1;
|
||||
const_node_iptr cn2 = n2;
|
||||
const_node_iptr cn3 = n3;
|
||||
|
||||
REQUIRE_FALSE(cn1->prev_sibling());
|
||||
REQUIRE(cn1->next_sibling() == cn2);
|
||||
|
||||
REQUIRE(cn2->prev_sibling() == cn1);
|
||||
REQUIRE(cn2->next_sibling() == cn3);
|
||||
|
||||
REQUIRE(cn3->prev_sibling() == cn2);
|
||||
REQUIRE_FALSE(cn3->next_sibling());
|
||||
|
||||
const_node_iptr cn4 = n4;
|
||||
REQUIRE_FALSE(cn4->prev_sibling());
|
||||
REQUIRE_FALSE(cn4->next_sibling());
|
||||
}
|
||||
}
|
||||
SECTION("add_child_to_back/add_child_to_front") {
|
||||
auto p = node::create();
|
||||
auto n1 = node::create();
|
||||
auto n2 = node::create();
|
||||
auto n3 = node::create();
|
||||
{
|
||||
p->remove_all_children();
|
||||
REQUIRE(p->add_child_to_front(n1));
|
||||
REQUIRE(p->add_child_to_front(n2));
|
||||
REQUIRE(p->add_child_to_front(n3));
|
||||
REQUIRE_FALSE(p->add_child_to_front(nullptr));
|
||||
|
||||
REQUIRE(n1->next_sibling() == n2);
|
||||
REQUIRE(n2->next_sibling() == n3);
|
||||
REQUIRE_FALSE(n3->next_sibling());
|
||||
}
|
||||
{
|
||||
p->remove_all_children();
|
||||
REQUIRE(p->add_child_to_back(n1));
|
||||
REQUIRE(p->add_child_to_back(n2));
|
||||
REQUIRE(p->add_child_to_back(n3));
|
||||
REQUIRE_FALSE(p->add_child_to_back(nullptr));
|
||||
|
||||
REQUIRE(n1->prev_sibling() == n2);
|
||||
REQUIRE(n2->prev_sibling() == n3);
|
||||
REQUIRE_FALSE(n3->prev_sibling());
|
||||
}
|
||||
}
|
||||
SECTION("add_child_after/add_child_before") {
|
||||
auto p = node::create();
|
||||
auto n1 = node::create();
|
||||
auto n2 = node::create();
|
||||
auto n3 = node::create();
|
||||
{
|
||||
p->remove_all_children();
|
||||
REQUIRE(p->add_child(n1)); // n1
|
||||
|
||||
REQUIRE(p->add_child_before(n1, n2)); // n2 n1
|
||||
REQUIRE(p->add_child_before(n1, n3)); // n2 n3 n1
|
||||
REQUIRE_FALSE(p->add_child_before(n1, nullptr));
|
||||
REQUIRE_FALSE(p->add_child_before(p, n3));
|
||||
|
||||
REQUIRE(n2->next_sibling() == n3);
|
||||
REQUIRE(n3->next_sibling() == n1);
|
||||
|
||||
auto n4 = node::create();
|
||||
REQUIRE(p->add_child_before(nullptr, n4)); // n4 n2 n3 n1
|
||||
REQUIRE(n4->next_sibling() == n2);
|
||||
|
||||
REQUIRE(n1->parent() == p);
|
||||
REQUIRE(n2->parent() == p);
|
||||
REQUIRE(n3->parent() == p);
|
||||
REQUIRE(n4->parent() == p);
|
||||
}
|
||||
{
|
||||
p->remove_all_children();
|
||||
REQUIRE(p->add_child(n1)); // n1
|
||||
|
||||
REQUIRE(p->add_child_after(n1, n2)); // n1 n2
|
||||
REQUIRE(p->add_child_after(n1, n3)); // n1 n3 n2
|
||||
REQUIRE_FALSE(p->add_child_after(n1, nullptr));
|
||||
REQUIRE_FALSE(p->add_child_after(p, n3));
|
||||
|
||||
REQUIRE(n1->next_sibling() == n3);
|
||||
REQUIRE(n3->next_sibling() == n2);
|
||||
|
||||
auto n4 = node::create();
|
||||
REQUIRE(p->add_child_after(nullptr, n4)); // n1 n3 n2 n4
|
||||
REQUIRE(n2->next_sibling() == n4);
|
||||
|
||||
REQUIRE(n1->parent() == p);
|
||||
REQUIRE(n2->parent() == p);
|
||||
REQUIRE(n3->parent() == p);
|
||||
REQUIRE(n4->parent() == p);
|
||||
}
|
||||
}
|
||||
SECTION("for_each_child") {
|
||||
auto p = node::create();
|
||||
array<node_iptr, 3> ns{
|
||||
node::create(p),
|
||||
node::create(p),
|
||||
node::create(p)};
|
||||
{
|
||||
std::size_t count = 0;
|
||||
p->for_each_child([&ns, &count](const node_iptr& n){
|
||||
REQUIRE(ns[count++] == n);
|
||||
});
|
||||
REQUIRE(count == 3);
|
||||
}
|
||||
{
|
||||
const_node_iptr cp = p;
|
||||
std::size_t count = 0;
|
||||
cp->for_each_child([&ns, &count](const const_node_iptr& n){
|
||||
REQUIRE(ns[count++] == n);
|
||||
});
|
||||
REQUIRE(count == 3);
|
||||
}
|
||||
}
|
||||
SECTION("remove_child_if") {
|
||||
auto p = node::create();
|
||||
auto n1 = node::create(p);
|
||||
auto n2 = node::create(p);
|
||||
auto n3 = node::create(p);
|
||||
auto n4 = node::create(p);
|
||||
|
||||
std::size_t num = 0;
|
||||
std::size_t count = p->remove_child_if([&num](const node_iptr&){
|
||||
return (num++) % 2;
|
||||
});
|
||||
|
||||
REQUIRE(count == 2);
|
||||
REQUIRE(p->child_count() == 2);
|
||||
REQUIRE(n1->parent() == p);
|
||||
REQUIRE_FALSE(n2->parent());
|
||||
REQUIRE(n3->parent() == p);
|
||||
REQUIRE_FALSE(n4->parent());
|
||||
}
|
||||
SECTION("destroy_node") {
|
||||
auto p1 = node::create();
|
||||
auto p2 = node::create(p1);
|
||||
auto n1 = node::create(p2);
|
||||
auto n2 = node::create(p2);
|
||||
|
||||
p2.reset();
|
||||
|
||||
REQUIRE(p1->child_count() == 0);
|
||||
REQUIRE(p1->child_count_recursive() == 0);
|
||||
|
||||
REQUIRE(n1->root() == n1);
|
||||
REQUIRE_FALSE(n1->parent());
|
||||
REQUIRE_FALSE(n1->prev_sibling());
|
||||
REQUIRE_FALSE(n1->next_sibling());
|
||||
|
||||
REQUIRE(n2->root() == n2);
|
||||
REQUIRE_FALSE(n2->parent());
|
||||
REQUIRE_FALSE(n2->prev_sibling());
|
||||
REQUIRE_FALSE(n2->next_sibling());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("scene") {
|
||||
scene_iptr s = scene::create();
|
||||
REQUIRE(s);
|
||||
REQUIRE(s->root());
|
||||
}
|
||||
Reference in New Issue
Block a user