Initial Commit
This commit is contained in:
commit
8f1ce37f3b
|
@ -0,0 +1,26 @@
|
|||
|
||||
using Godot;
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[GlobalClass]
|
||||
public partial class ActionList : RJAction
|
||||
{
|
||||
[Export]
|
||||
public RJAction[] actions;
|
||||
[Export]
|
||||
public bool triggerDirectChildren = true;
|
||||
|
||||
protected override void _OnTrigger()
|
||||
{
|
||||
for ( int i = 0; i < actions.Length; i++ )
|
||||
{
|
||||
Actions.Trigger( actions[ i ] );
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
using Godot;
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class Actions
|
||||
{
|
||||
public static Trigger( RJAction action )
|
||||
{
|
||||
if ( action == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
action.Trigger();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
|
||||
public class ReadonlyEventProperty<T>: EventSlot<T>
|
||||
{
|
||||
protected T _value;
|
||||
public T value
|
||||
{
|
||||
get { return _value; }
|
||||
protected set { }
|
||||
}
|
||||
}
|
||||
|
||||
public class EventProperty<T>:ReadonlyEventProperty<T>
|
||||
{
|
||||
public new T value
|
||||
{
|
||||
get { return _value; }
|
||||
set
|
||||
{
|
||||
if ( IsEqual( _value, value ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_value = value;
|
||||
DispatchEvent();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void DispatchEvent()
|
||||
{
|
||||
_actions.ForEach( a => { if ( a != null ){ a( _value ); } } );
|
||||
|
||||
_ClearOnceActions();
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected bool IsEqual( T oldValue, T newValue )
|
||||
{
|
||||
if ( oldValue == null && newValue == null )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( oldValue == null || newValue == null )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( EqualityComparer<T>.Default.Equals( oldValue , newValue ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SetSilent( T value )
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class EventSlot<T>
|
||||
{
|
||||
protected List<Action<T>> _actions = new List<Action<T>>();
|
||||
List<Action<T>> _once = new List<Action<T>>();
|
||||
|
||||
public bool hasListeners => _once.Count > 0 || _actions.Count > 0;
|
||||
|
||||
public void AddAction( Action<T> action )
|
||||
{
|
||||
_actions.Add( action );
|
||||
}
|
||||
|
||||
public void RemoveAction( Action<T> action )
|
||||
{
|
||||
_actions.Remove( action );
|
||||
}
|
||||
|
||||
public void Once( Action<T> action )
|
||||
{
|
||||
_actions.Add( action );
|
||||
_once.Add( action );
|
||||
}
|
||||
|
||||
protected void _ClearOnceActions()
|
||||
{
|
||||
_once.ForEach( a => { _actions.Remove( a ); } );
|
||||
_once.Clear();
|
||||
}
|
||||
|
||||
public void DispatchEvent( T t )
|
||||
{
|
||||
_actions.ForEach( a => { if ( a != null ){ a( t ); } } );
|
||||
|
||||
_ClearOnceActions();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class Null
|
||||
{
|
||||
private Null(){}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
using Godot;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class HierarchyName
|
||||
{
|
||||
public static string Of( Node node, string seperator = "/" )
|
||||
{
|
||||
if ( node == null )
|
||||
{
|
||||
return "null";
|
||||
}
|
||||
|
||||
var list = new List<string>();
|
||||
|
||||
var it = node;
|
||||
|
||||
while ( it != null )
|
||||
{
|
||||
list.Add( it.Name );
|
||||
it = it.GetParent();
|
||||
}
|
||||
|
||||
list.Reverse();
|
||||
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
for ( int i = 0; i < list.Count; i++)
|
||||
{
|
||||
if ( i != 0 )
|
||||
{
|
||||
sb.Append( seperator );
|
||||
}
|
||||
|
||||
sb.Append( list[ i ] );
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
using Godot;
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class Nodes
|
||||
{
|
||||
public static T GetSibling<T>( Node node ) where T:Node
|
||||
{
|
||||
if ( node == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var parent = node.GetParent();
|
||||
|
||||
if ( parent == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return GetDirectChild<T>( parent );
|
||||
}
|
||||
|
||||
public static T GetDirectChild<T>( Node parent ) where T:Node
|
||||
{
|
||||
if ( parent == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var numChildren = parent.GetChildCount();
|
||||
|
||||
for ( int i = 0; i < numChildren; i++ )
|
||||
{
|
||||
var node = parent.GetChild( i );
|
||||
|
||||
if ( node is T )
|
||||
{
|
||||
return (T)node;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static NodesWalker nodesWalker = new NodesWalker();
|
||||
|
||||
public static T GetAnyChild<T>( Node parent ) where T:Node
|
||||
{
|
||||
return (T) nodesWalker.Find( parent, ( n )=> n is T, true );
|
||||
}
|
||||
|
||||
public static void Enable( Node n, bool affectProcess = true, bool affectPhysicsProcess = true, bool affectInput = true )
|
||||
{
|
||||
SetState.SetStateOfNode( NodeStateType.Enabled, n, affectProcess, affectPhysicsProcess, affectInput );
|
||||
}
|
||||
|
||||
public static void Disable( Node n, bool affectProcess = true, bool affectPhysicsProcess = true, bool affectInput = true )
|
||||
{
|
||||
SetState.SetStateOfNode( NodeStateType.Disabled, n, affectProcess, affectPhysicsProcess, affectInput );
|
||||
}
|
||||
|
||||
public static void Iterate( Node[] nodes, System.Action<Node> callback )
|
||||
{
|
||||
for ( int i = 0; i < nodes.Length; i++ )
|
||||
{
|
||||
nodesWalker.Iterate( nodes[ i ], callback );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
using Godot;
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class NodesWalker: TreeWalker<Node>
|
||||
{
|
||||
static NodesWalker _singleton = new NodesWalker();
|
||||
public static NodesWalker Get()
|
||||
{
|
||||
return _singleton;
|
||||
}
|
||||
|
||||
public override Node Parent( Node n )
|
||||
{
|
||||
if ( n == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return n.GetParent();
|
||||
}
|
||||
|
||||
public override Node ChildAt( Node n, int index )
|
||||
{
|
||||
if ( n == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return n.GetChild( index );
|
||||
}
|
||||
|
||||
public override int NumChildren( Node n )
|
||||
{
|
||||
if ( n == null )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return n.GetChildCount();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
using Godot;
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public partial class Root:Node
|
||||
{
|
||||
private static Root _singleton;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_singleton = this;
|
||||
}
|
||||
|
||||
public static SceneTree Tree()
|
||||
{
|
||||
return _singleton.GetTree();
|
||||
}
|
||||
|
||||
public static Window Window()
|
||||
{
|
||||
return Tree().Root;
|
||||
}
|
||||
|
||||
public static Root Get()
|
||||
{
|
||||
var r = Window();
|
||||
return _singleton;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Godot;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class Unique<N> where N:Node
|
||||
{
|
||||
private static N _singleton;
|
||||
|
||||
public static N Get()
|
||||
{
|
||||
if ( _singleton != null )
|
||||
{
|
||||
return _singleton;
|
||||
}
|
||||
|
||||
_singleton = Nodes.GetAnyChild<N>( Root.Window() );
|
||||
|
||||
return _singleton;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class ChildrenIterator<N>: TreeIterator<N> where N:class
|
||||
{
|
||||
N parent;
|
||||
N current;
|
||||
N end;
|
||||
N next;
|
||||
TreeWalker<N> walker;
|
||||
|
||||
public static ChildrenIterator<N> Create( TreeWalker<N> walker, N node )
|
||||
{
|
||||
var iterator = new ChildrenIterator<N>();
|
||||
|
||||
iterator.walker = walker;
|
||||
iterator.current = null;
|
||||
iterator.parent = node;
|
||||
iterator.end = walker.IterationEndOf( node );
|
||||
iterator.next = walker.NextNode( node );
|
||||
|
||||
if ( iterator.next == iterator.end )
|
||||
{
|
||||
iterator.next = null;
|
||||
}
|
||||
|
||||
return iterator;
|
||||
}
|
||||
|
||||
public override bool HasNext()
|
||||
{
|
||||
return next != null;
|
||||
}
|
||||
|
||||
public override N Current()
|
||||
{
|
||||
return current;
|
||||
}
|
||||
|
||||
protected override void _MoveToNext()
|
||||
{
|
||||
current = next;
|
||||
|
||||
next = walker.NextNode( current );
|
||||
|
||||
if ( next == end )
|
||||
{
|
||||
next = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class DirectChildrenIterator<N>: TreeIterator<N> where N:class
|
||||
{
|
||||
N parent;
|
||||
N current;
|
||||
int index = 0;
|
||||
TreeWalker<N> walker;
|
||||
|
||||
public static DirectChildrenIterator<N> Create( TreeWalker<N> walker, N node )
|
||||
{
|
||||
var iterator = new DirectChildrenIterator<N>();
|
||||
|
||||
iterator.parent = node;
|
||||
iterator.walker = walker;
|
||||
iterator.current = null;
|
||||
iterator.index = -1;
|
||||
|
||||
return iterator;
|
||||
}
|
||||
|
||||
public override bool HasNext()
|
||||
{
|
||||
return ( index + 1 ) < walker.NumChildren( parent );
|
||||
}
|
||||
|
||||
public override N Current()
|
||||
{
|
||||
return current;
|
||||
}
|
||||
|
||||
protected override void _MoveToNext()
|
||||
{
|
||||
index ++;
|
||||
current = walker.ChildAt( parent, index );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class NodesIterator<N>: TreeIterator<N> where N:class
|
||||
{
|
||||
N node;
|
||||
N current;
|
||||
bool isForward = true;
|
||||
TreeWalker<N> walker;
|
||||
|
||||
public static NodesIterator<N> Create( TreeWalker<N> walker, N node, bool forward )
|
||||
{
|
||||
var iterator = new NodesIterator<N>();
|
||||
|
||||
iterator.walker = walker;
|
||||
iterator.node = node;
|
||||
iterator.current = null;
|
||||
iterator.isForward = forward;
|
||||
|
||||
return iterator;
|
||||
}
|
||||
|
||||
public override bool HasNext()
|
||||
{
|
||||
return node != null;
|
||||
}
|
||||
|
||||
public override N Current()
|
||||
{
|
||||
return current;
|
||||
}
|
||||
|
||||
protected override void _MoveToNext()
|
||||
{
|
||||
if ( isForward )
|
||||
{
|
||||
node = walker.NextNode( node );
|
||||
}
|
||||
else
|
||||
{
|
||||
node = walker.PreviousNode( node );
|
||||
}
|
||||
|
||||
current = node;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class ParentsIterator<N>: TreeIterator<N> where N:class
|
||||
{
|
||||
N iterator;
|
||||
N current;
|
||||
TreeWalker<N> walker;
|
||||
|
||||
public static ParentsIterator<N> Create( TreeWalker<N> walker, N start )
|
||||
{
|
||||
var iterator = new ParentsIterator<N>();
|
||||
|
||||
iterator.current = null;
|
||||
iterator.iterator = start;
|
||||
iterator.walker = walker;
|
||||
|
||||
return iterator;
|
||||
}
|
||||
|
||||
public override bool HasNext()
|
||||
{
|
||||
return walker.HasParent( iterator );
|
||||
}
|
||||
|
||||
public override N Current()
|
||||
{
|
||||
return current;
|
||||
}
|
||||
|
||||
protected override void _MoveToNext()
|
||||
{
|
||||
iterator = walker.Parent( iterator );
|
||||
current = iterator;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class SiblingsIterator<N>: TreeIterator<N> where N:class
|
||||
{
|
||||
bool nextSiblings = true;
|
||||
|
||||
N parent;
|
||||
N current;
|
||||
int index = 0;
|
||||
int nodeIndex = 0;
|
||||
TreeWalker<N> walker;
|
||||
|
||||
public static SiblingsIterator<N> Create( TreeWalker<N> walker, N node, bool previous = true, bool next = true )
|
||||
{
|
||||
var iterator = new SiblingsIterator<N>();
|
||||
|
||||
iterator.parent = node;
|
||||
iterator.walker = walker;
|
||||
iterator.current = null;
|
||||
iterator.nodeIndex = walker.ChildIndexOf( node );
|
||||
iterator.index = previous ? -1 : iterator.nodeIndex;
|
||||
|
||||
return iterator;
|
||||
}
|
||||
|
||||
public override bool HasNext()
|
||||
{
|
||||
if ( ! nextSiblings )
|
||||
{
|
||||
return ( index + 1 ) < nodeIndex;
|
||||
}
|
||||
|
||||
var nextIndex = index + 1;
|
||||
|
||||
if ( nextIndex == nodeIndex )
|
||||
{
|
||||
nextIndex ++;
|
||||
}
|
||||
|
||||
return nextIndex < walker.NumChildren( parent );
|
||||
|
||||
}
|
||||
|
||||
public override N Current()
|
||||
{
|
||||
return current;
|
||||
}
|
||||
|
||||
protected override void _MoveToNext()
|
||||
{
|
||||
index ++;
|
||||
|
||||
if ( index == nodeIndex )
|
||||
{
|
||||
index ++;
|
||||
}
|
||||
|
||||
current = walker.ChildAt( parent, index );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace Rokojori.Core
|
||||
{
|
||||
public class SinlgeIterator<N>: TreeIterator<N> where N:class
|
||||
{
|
||||
N node;
|
||||
N current;
|
||||
|
||||
public static SinlgeIterator<N> Create( N node )
|
||||
{
|
||||
var iterator = new SinlgeIterator<N>();
|
||||
|
||||
iterator.node = node;
|
||||
iterator.current = null;
|
||||
|
||||
return iterator;
|
||||
}
|
||||
|
||||
public override bool HasNext()
|
||||
{
|
||||
return node != null;
|
||||
}
|
||||
|
||||
public override N Current()
|
||||
{
|
||||
return current;
|
||||
}
|
||||
|
||||
protected override void _MoveToNext()
|
||||
{
|
||||
current = node;
|
||||
node = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public enum TreeIteratorType
|
||||
{
|
||||
Parent,
|
||||
|
||||
NextSibling,
|
||||
PreviousSibling,
|
||||
|
||||
FirstChild,
|
||||
LastChild,
|
||||
LastGrandChild,
|
||||
|
||||
NextNode,
|
||||
PreviousNode,
|
||||
|
||||
Parents,
|
||||
|
||||
DirectChildren,
|
||||
Children,
|
||||
|
||||
Siblings,
|
||||
PreviousSiblings,
|
||||
NextSiblings,
|
||||
|
||||
PreviousNodes,
|
||||
NextNodes
|
||||
}
|
||||
|
||||
public abstract class TreeIterator<N> where N:class
|
||||
{
|
||||
public abstract bool HasNext();
|
||||
public abstract N Current();
|
||||
protected abstract void _MoveToNext();
|
||||
bool safeMoving = true;
|
||||
|
||||
public void MoveToNext()
|
||||
{
|
||||
if ( safeMoving && ! HasNext() )
|
||||
{
|
||||
throw new System.Exception( "Has no more elements" );
|
||||
}
|
||||
|
||||
_MoveToNext();
|
||||
}
|
||||
|
||||
public void ForEach( System.Action<N> callback )
|
||||
{
|
||||
while ( HasNext() )
|
||||
{
|
||||
_MoveToNext();
|
||||
callback( Current() );
|
||||
}
|
||||
}
|
||||
|
||||
public N Get( System.Func<N,bool> predicate )
|
||||
{
|
||||
while ( HasNext() )
|
||||
{
|
||||
_MoveToNext();
|
||||
|
||||
var current = Current();
|
||||
var result = predicate( current );
|
||||
|
||||
if ( result )
|
||||
{
|
||||
return current;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool Has( System.Func<N,bool> predicate )
|
||||
{
|
||||
return Get( predicate ) != null;
|
||||
}
|
||||
|
||||
public List<N> All( System.Func<N,bool> predicate )
|
||||
{
|
||||
var list = new List<N>();
|
||||
|
||||
while ( HasNext() )
|
||||
{
|
||||
_MoveToNext();
|
||||
|
||||
var current = Current();
|
||||
var result = predicate( current );
|
||||
|
||||
if ( result )
|
||||
{
|
||||
list.Add( current );
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public static TreeIterator<N> GetIterator( TreeIteratorType type, N node, TreeWalker<N> walker )
|
||||
{
|
||||
|
||||
switch ( type )
|
||||
{
|
||||
case TreeIteratorType.Parent:
|
||||
return SinlgeIterator<N>.Create( walker.Parent( node ) );
|
||||
|
||||
case TreeIteratorType.NextSibling:
|
||||
return SinlgeIterator<N>.Create( walker.NextSibling( node ) );
|
||||
|
||||
case TreeIteratorType.PreviousSibling:
|
||||
return SinlgeIterator<N>.Create( walker.PreviousSibling( node ) );
|
||||
|
||||
case TreeIteratorType.FirstChild:
|
||||
return SinlgeIterator<N>.Create( walker.ChildAt( node, 0 ) );
|
||||
|
||||
case TreeIteratorType.LastChild:
|
||||
return SinlgeIterator<N>.Create( walker.ChildAt( node, walker.NumChildren( node ) - 1 ) );
|
||||
|
||||
case TreeIteratorType.LastGrandChild:
|
||||
return SinlgeIterator<N>.Create( walker.LastGrandChild( node ) );
|
||||
|
||||
case TreeIteratorType.NextNode:
|
||||
return SinlgeIterator<N>.Create( walker.NextNode( node ) );
|
||||
|
||||
case TreeIteratorType.PreviousNode:
|
||||
return SinlgeIterator<N>.Create( walker.PreviousNode( node ) );
|
||||
|
||||
|
||||
case TreeIteratorType.Parents:
|
||||
return ParentsIterator<N>.Create( walker, node );
|
||||
|
||||
|
||||
case TreeIteratorType.DirectChildren:
|
||||
return DirectChildrenIterator<N>.Create( walker, node );
|
||||
|
||||
case TreeIteratorType.Children:
|
||||
return ChildrenIterator<N>.Create( walker, node );
|
||||
|
||||
|
||||
case TreeIteratorType.Siblings:
|
||||
return SiblingsIterator<N>.Create( walker, node, true, true );
|
||||
|
||||
case TreeIteratorType.PreviousSiblings:
|
||||
return SiblingsIterator<N>.Create( walker, node, true, false );
|
||||
|
||||
case TreeIteratorType.NextSiblings:
|
||||
return SiblingsIterator<N>.Create( walker, node, false, true );
|
||||
|
||||
|
||||
case TreeIteratorType.NextNodes:
|
||||
return NodesIterator<N>.Create( walker, node, true );
|
||||
|
||||
case TreeIteratorType.PreviousNodes:
|
||||
return NodesIterator<N>.Create( walker, node, false );
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,322 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public abstract class TreeWalker<N> where N:class
|
||||
{
|
||||
public abstract N Parent( N node );
|
||||
|
||||
public abstract N ChildAt( N node, int index );
|
||||
|
||||
public abstract int NumChildren( N node );
|
||||
|
||||
public bool HasChildren( N node )
|
||||
{
|
||||
return NumChildren( node ) > 0;
|
||||
}
|
||||
|
||||
public bool HasParent( N node )
|
||||
{
|
||||
return Parent( node ) != null;
|
||||
}
|
||||
|
||||
|
||||
public int ChildIndexOf( N node )
|
||||
{
|
||||
var p = Parent( node );
|
||||
|
||||
if ( p == null )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
var numKids = NumChildren( p );
|
||||
|
||||
for ( var i = 0; i<numKids; i++ )
|
||||
{
|
||||
if ( ChildAt( p, i ) == node )
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
public N SiblingAt( N node, int index )
|
||||
{
|
||||
var p = Parent( node );
|
||||
|
||||
if ( p == null || index<0 || index >= NumChildren( p ) )
|
||||
{ return null; }
|
||||
|
||||
return ChildAt( p, index );
|
||||
}
|
||||
|
||||
|
||||
public N NextSibling( N node )
|
||||
{
|
||||
var index = ChildIndexOf( node );
|
||||
return SiblingAt( node, index+1 );
|
||||
}
|
||||
|
||||
|
||||
public N PreviousSibling( N node )
|
||||
{
|
||||
var index = ChildIndexOf( node );
|
||||
return SiblingAt( node, index-1 );
|
||||
}
|
||||
|
||||
|
||||
public bool HasSiblingAt( N node, int index )
|
||||
{
|
||||
var p = Parent( node );
|
||||
if ( p == null || index<0 || index >= NumChildren( p ) )
|
||||
{ return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public N FirstChild( N node )
|
||||
{
|
||||
return NumChildren( node )<=0?null:ChildAt( node, 0 );
|
||||
}
|
||||
|
||||
|
||||
public N LastChild( N node )
|
||||
{
|
||||
var num = NumChildren( node );
|
||||
return num <= 0 ? null : ChildAt( node, num - 1 );
|
||||
}
|
||||
|
||||
|
||||
public N NextNode( N node )
|
||||
{
|
||||
if ( HasChildren( node ) )
|
||||
{
|
||||
return FirstChild( node );
|
||||
}
|
||||
|
||||
var next = NextSibling( node );
|
||||
|
||||
if ( next != null )
|
||||
{
|
||||
return next;
|
||||
}
|
||||
|
||||
var parent = Parent( node );
|
||||
|
||||
while ( parent != null )
|
||||
{
|
||||
var n = NextSibling( parent );
|
||||
|
||||
if ( n != null )
|
||||
{
|
||||
return n;
|
||||
}
|
||||
|
||||
parent = Parent( parent );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public N PreviousNode( N node )
|
||||
{
|
||||
var prev = PreviousSibling( node );
|
||||
|
||||
if ( prev != null )
|
||||
{
|
||||
while ( HasChildren( prev ) )
|
||||
{
|
||||
prev = LastChild( prev );
|
||||
}
|
||||
return prev;
|
||||
}
|
||||
|
||||
return Parent( node );
|
||||
}
|
||||
|
||||
|
||||
public N RootParent( N node )
|
||||
{
|
||||
node = Parent( node );
|
||||
|
||||
if ( node == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
while ( HasParent( node ) )
|
||||
{
|
||||
node = Parent( node );
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
public N LastGrandChild( N node )
|
||||
{
|
||||
if ( HasChildren( node ) )
|
||||
{
|
||||
node = LastChild( node );
|
||||
|
||||
while ( HasChildren( node ) )
|
||||
{
|
||||
node = LastChild( node );
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public bool IsChildOf( N child, N parent )
|
||||
{
|
||||
var p = Parent( child );
|
||||
|
||||
while ( p != null )
|
||||
{
|
||||
if ( p == parent )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
p = Parent( p );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public int NumParents( N node )
|
||||
{
|
||||
var num = 0;
|
||||
var p = Parent( node );
|
||||
|
||||
while ( p != null )
|
||||
{
|
||||
num++;
|
||||
p = Parent( p );
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
|
||||
public N LastOuterNode( N node )
|
||||
{
|
||||
var its = 0;
|
||||
var max = 10000;
|
||||
|
||||
while ( HasChildren( node ) )
|
||||
{
|
||||
its++;
|
||||
|
||||
if ( its > max )
|
||||
{
|
||||
throw new System.Exception();
|
||||
}
|
||||
|
||||
node = LastChild( node );
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
public N NextNonChild( N node )
|
||||
{
|
||||
return NextNode( LastOuterNode( node ) );
|
||||
}
|
||||
|
||||
public N IterationEndOf( N node )
|
||||
{
|
||||
return NextNonChild( node );
|
||||
}
|
||||
|
||||
public void Iterate( N node, System.Action<N> callback, bool childrenOnly = false )
|
||||
{
|
||||
var end = IterationEndOf( node );
|
||||
var it = node;
|
||||
|
||||
if ( childrenOnly )
|
||||
{
|
||||
it = NextNode( it );
|
||||
}
|
||||
|
||||
while ( it != end )
|
||||
{
|
||||
callback( it );
|
||||
it = NextNode( it );
|
||||
}
|
||||
}
|
||||
|
||||
public N Find( N node, System.Predicate<N> predicate, bool childrenOnly )
|
||||
{
|
||||
var end = IterationEndOf( node );
|
||||
var it = node;
|
||||
|
||||
if ( childrenOnly )
|
||||
{
|
||||
it = NextNode( it );
|
||||
}
|
||||
|
||||
while ( it != end )
|
||||
{
|
||||
if ( predicate( it ) )
|
||||
{
|
||||
return it;
|
||||
}
|
||||
|
||||
it = NextNode( it );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Filter( List<N> list, N node, System.Predicate<N> predicate, bool childrenOnly )
|
||||
{
|
||||
System.Action<N> addToList = ( N n ) =>
|
||||
{
|
||||
if ( predicate( n ) )
|
||||
{
|
||||
list.Add( n );
|
||||
}
|
||||
};
|
||||
|
||||
Iterate( node, addToList, childrenOnly );
|
||||
}
|
||||
|
||||
public void FilterAndMap<U>( List<U> list, N node, System.Predicate<N> predicate, System.Func<N,U> mapper, bool childrenOnly )
|
||||
{
|
||||
System.Action<N> addToList = ( N n ) =>
|
||||
{
|
||||
if ( predicate( n ) )
|
||||
{
|
||||
list.Add( mapper( n ) );
|
||||
}
|
||||
};
|
||||
|
||||
Iterate( node, addToList, childrenOnly );
|
||||
}
|
||||
|
||||
public void Map<U>( List<U> list, N node, System.Predicate<N> predicate, System.Func<N,U> mapper, bool childrenOnly )
|
||||
{
|
||||
System.Action<N> addToList = ( N n ) =>
|
||||
{
|
||||
list.Add( mapper( n ) );
|
||||
};
|
||||
|
||||
Iterate( node, addToList, childrenOnly );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue