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 }