1 /**
2 Pre-parsed scene tree path.
3 
4 Copyright:
5 Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur.  
6 Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md)  
7 Copyright (c) 2017-2018 Godot-D contributors  
8 
9 License: $(LINK2 https://opensource.org/licenses/MIT, MIT License)
10 
11 
12 */
13 module godot.core.nodepath;
14 
15 import godot.core.string;
16 import godot.c;
17 
18 /**
19 A pre-parsed relative or absolute path in a scene tree, for use with $(D Node.getNode) and similar functions. It can reference a node, a resource within a node, or a property of a node or resource. For instance, `"Path2D/PathFollow2D/Sprite:texture:size"` would refer to the size property of the texture resource on the node named “Sprite” which is a child of the other named nodes in the path. Note that if you want to get a resource, you must end the path with a colon, otherwise the last element will be used as a property name.
20 
21 Exporting a `NodePath` variable will give you a node selection widget in the properties panel of the editor, which can often be useful.
22 
23 A `NodePath` is made up of a list of node names, a list of “subnode” (resource) names, and the name of a property in the final node or resource.
24 */
25 struct NodePath
26 {
27 	@nogc nothrow:
28 	
29 	package(godot) godot_node_path _node_path;
30 	
31 	this(this)
32 	{
33 		godot_node_path other = _node_path;
34 		_godot_api.godot_node_path_new_copy(&_node_path, &other);
35 	}
36 	
37 	this(in String from)
38 	{
39 		_godot_api.godot_node_path_new(&_node_path, &from._godot_string);
40 	}
41 	
42 	this(in string name)
43 	{
44 		String from = String(name);
45 		_godot_api.godot_node_path_new(&_node_path, &from._godot_string);
46 	}
47 
48 	bool opEquals(in NodePath other) const
49 	{
50 		if(_node_path == other._node_path) return true;
51 		return _godot_api.godot_node_path_operator_equal(&_node_path, &other._node_path);
52 	}
53 	
54 	String getName(in int idx) const
55 	{
56 		godot_string str = _godot_api.godot_node_path_get_name(&_node_path, idx);
57 		return String(str);
58 	}
59 	
60 	int getNameCount() const
61 	{
62 		return _godot_api.godot_node_path_get_name_count(&_node_path);
63 	}
64 	
65 	String getSubname(in int idx) const
66 	{
67 		godot_string str = _godot_api.godot_node_path_get_subname(&_node_path, idx);
68 		return String(str);
69 	}
70 	
71 	int getSubnameCount() const
72 	{
73 		return _godot_api.godot_node_path_get_subname_count(&_node_path);
74 	}
75 	
76 	bool isAbsolute() const
77 	{
78 		return cast(bool)_godot_api.godot_node_path_is_absolute(&_node_path);
79 	}
80 	
81 	bool isEmpty() const
82 	{
83 		return cast(bool)_godot_api.godot_node_path_is_empty(&_node_path);
84 	}
85 	
86 	String str() const
87 	{
88 		godot_string str = _godot_api.godot_node_path_as_string(&_node_path);
89 		return String(str);
90 	}
91 
92 	/// Splits a NodePath into a main node path and a property subpath (starting
93 	/// with a ':'). The second element is left empty if there is no property.
94 	NodePath[2] split() const
95 	{
96 		static immutable wchar_t colon = ':';
97 		NodePath[2] ret;
98 		if(_node_path == godot_node_path.init) return ret;
99 		String path = str();
100 		immutable(wchar_t)[] data = path.data();
101 		if(data.length == 0) return ret;
102 		if(data[0] == colon)
103 		{
104 			ret[1] = this;
105 			return ret;
106 		}
107 
108 		ptrdiff_t colonIndex = 0;
109 		// Windows requires UTF-16 decoding to find the ':'
110 		static if(is(wchar_t == wchar))
111 		{
112 			import utf_bc;
113 			enum TextFormat gdFormat = TextFormat.UTF_16;
114 			auto decoded = data.decode!gdFormat;
115 			do
116 			{
117 				dchar front = decoded.front;
118 				decoded.popFront();
119 				if(front == colon) break;
120 				colonIndex += codeLength!gdFormat(front);
121 			}
122 			while(!decoded.empty);
123 			if(decoded.empty) colonIndex = -1;
124 		}
125 		else
126 		{
127 			import std.algorithm : countUntil;
128 			colonIndex = data[].countUntil(colon);
129 		}
130 
131 		// node only
132 		if(colonIndex == -1)
133 		{
134 			ret[0] = this;
135 			return ret;
136 		}
137 		ret[0] = NodePath(String(data[0..colonIndex]));
138 		ret[1] = NodePath(String(data[colonIndex..$]));
139 		return ret;
140 	}
141 	
142 	/+void opAssign(in ref NodePath other)
143 	{
144 		godot_node_path_copy(&_node_path, &other._node_path);
145 	}+/
146 	
147 	~this()
148 	{
149 		_godot_api.godot_node_path_destroy(&_node_path);
150 	}
151 }