CGII/framework/include/cgv/base/traverser.h
2018-05-17 15:50:03 +02:00

131 lines
5 KiB
C++

#pragma once
#include "group.h"
#include "action.h"
#include <string>
#include "lib_begin.h"
namespace cgv {
namespace base {
/// different traversal policies
enum TraversePolicy {
TP_ALL, /// traverse all children
TP_ONLY_FOCUS, /// traverse only the focused child
TP_FIRST_FOCUS, /// first traverse focused and then the remaining children
TP_AUTO_FOCUS, /// like previous but change focus to the child, where traversal succeeded
TP_STOP_ON_SUCCESS = 8, /// this is an optional flag for traversals with methods that return a bool. If the returned bool is true, traversal stops if this flag is set
TP_STOP_ON_FAILURE = 16 /// this is an optional flag for traversals with methods that return a bool. If the returned bool is false, traversal stops if this flag is set
};
/// nodes should inherit from this policy class to allow selective tree traversals
class CGV_API traverse_policy
{
protected:
TraversePolicy policy;
bool active;
int focus;
public:
/// construct default traverse policy that visits everything
traverse_policy(int _policy = TP_ALL+TP_STOP_ON_SUCCESS, bool _active = true, int _focus = -1);
/// return the policy without the stop on success flag
int get_policy() const;
/// return whether to stop on success
bool stop_on_success() const;
/// return whether to stop on failure
bool stop_on_failure() const;
/// set a new policy, always add stop on success flag if needed
void set_policy(int _policy);
/// return the focused child or -1 if none is focused
int get_focused_child() const;
/// set the focused child
void set_focused_child(int _focused_child);
/// return whether the current node is active
bool get_active() const;
/// set the active flag of the current node
void set_active(bool _active);
};
/// try to grab the focus in the path of this node to the root of the tree
template <class X>
bool grab_focus(X* instance) {
node* n = dynamic_cast<node*>(instance);
if (!n)
return true;
base_ptr p = n->get_parent();
if (p.empty())
return true;
group_ptr g = p->get_group();
if (g.empty())
return true;
X* pinstance = p->get_interface<X>();
if (!pinstance)
return true;
for (unsigned int i=0; i<g->get_nr_children(); ++i) {
if (g->get_child(i)->get_interface<X>() == instance) {
pinstance->set_focused_child(i);
return grab_focus(pinstance);
}
}
// at this point we did not find the instance in the children of its parent
return false;
}
/// interface of a handler for traverse callbacks
class CGV_API traverse_callback_handler
{
public:
/// called before a node b is processed, return, whether to skip this node. If the node is skipped, the on_leave_node callback is still called
virtual bool on_enter_node(base_ptr b);
/// called when a node b is left, return whether to terminate traversal
virtual bool on_leave_node(base_ptr b);
/// called before the children of a group node g are processed, return whether these should be skipped. If children are skipped, the on_leave_children callback is still called.
virtual bool on_enter_children(group_ptr g);
/// called when the children of a group node g have been left, return whether to terminate traversal
virtual bool on_leave_children(group_ptr g);
/// called before the parent of a node n is processed, return whether this should be skipped. If the parent is skipped, the on_leave_parent callback is still called.
virtual bool on_enter_parent(node_ptr n);
/// called when the parent of a node n has been left, return whether to terminate traversal
virtual bool on_leave_parent(node_ptr n);
};
/// not yet implemented
enum TraverseStrategy
{
TS_DEPTH_FIRST,
TS_BREADTH_FIRST
};
/// class used to traverse a tree structure
class CGV_API traverser
{
protected:
action& a;
TraverseStrategy strategy;
std::string visit_order;
bool stop_if_not_implemented;
/// traverse a single object, template over a static traverse callback handler interface
template <typename TCH>
bool traverse_tmp_1(base_ptr dest, base_ptr src, bool& force_termination, TCH& tch);
/// helper method encapsulating common functionality
template <typename TCH>
bool traverse_tmp_2(base_ptr p, base_ptr dest, base_ptr src, traverse_policy* tp, bool& force_termination, TCH& tch);
public:
/// construct from reference on action and traversal order string
traverser(action& _a,
const std::string& _visit_order = "pnc",
TraverseStrategy _strategy = TS_DEPTH_FIRST,
bool _stop_if_not_implemented = false);
/// set a different visiting order of node, children and parent
traverser& set_visit_order(const std::string& _visit_order);
/// set a different traverse strategy
traverser& set_strategy(TraverseStrategy _strategy);
/// traverse a tree starting at given node according to set strategy, order and dest and previously coming from src and return whether traversal yielded success
bool traverse(base_ptr start, traverse_callback_handler* tch = 0);
};
}
}
#include <cgv/config/lib_end.h>