1 /**
2  * Copyright:       Copyright (C) 2018 Gabriel Gheorghe, All Rights Reserved
3  * Authors:         $(Gabriel Gheorghe)
4  * License:         $(LINK2 https://www.gnu.org/licenses/gpl-3.0.txt, GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007)
5  * Source
6  * Documentation:
7  * Coverage:
8  */
9 module liberty.core.scenegraph.services;
10 ///
11 immutable NodeServices = q{
12     this(string id, Node parent = CoreEngine.get.activeScene.tree) {
13         if (parent is null) {
14             assert(0, "Parent object cannot be null");
15         }
16         super(id, parent);
17         import std.traits: hasUDA;
18         enum finalClass = __traits(isFinalClass, this);
19         enum abstractClass = __traits(isAbstractClass, this);
20         static if (!(finalClass || abstractClass)) {
21             static assert(0, "A node object class must either be final or abstract!");
22         }
23         static foreach (i, member; __traits(derivedMembers, typeof(this))) {
24             static if (mixin("hasUDA!(" ~ typeof(this).stringof ~ "." ~ member ~ ", Constructor)")) {
25                 enum accessFun = __traits(getProtection, __traits(getMember, this, member));
26                 enum finalFun = __traits(isFinalFunction, __traits(getMember, this, member));
27                 enum abstractFun = __traits(isAbstractFunction, __traits(getMember, this, member));
28                 static if (accessFun == "private" || accessFun == "protected") {
29                     static if ((!finalFun || finalClass) && !abstractFun) {
30 	                    static if (member.stringof == "\"_\"") {
31 	                        mixin(member ~ "();");
32 	                    } else {
33 	                        static assert(0, "NodeObject's constructor must be named '_'!");
34 	                    }
35 	                } else {
36 	                    static assert(0, "NodeObject's constructor cannot be final or abstract!");
37 	                }
38                 } else {
39                     static assert(0, "NodeObject's constructor must be private or protected!");
40                 }
41             }
42         }
43 	    static if (__traits(isFinalClass, this)) {
44 	        static foreach (el; ["start", "update", "process", "render"]) {
45 	            static foreach (super_member; __traits(derivedMembers, typeof(super))) {
46                     static if (super_member.stringof == "\"" ~ el ~ "\"") {
47                         mixin("scene." ~ el ~ "List[id] = this;");
48                     }
49                 }
50 	            static foreach (member; __traits(derivedMembers, typeof(this))) {
51 	                static if (member.stringof == "\"" ~ el ~ "\"") {
52 	                    mixin("scene." ~ el ~ "List[id] = this;");
53 	                }
54 	            }
55 	        }
56         }
57     }
58 };
59 ///
60 immutable ListenerServices = q{
61 	/// Starts current containing events and @Signal events.
62 	/// A @Signal event overrides a current containing event.
63 	void startListening(T)(ref T element) {
64         import std.traits: hasUDA, getUDAs;
65         if (!element.canListen()) {
66             element.__canListen(true);
67             if (typeof(element).stringof == Button.stringof) {
68                 mixin(ButtonListenerServices);
69             }
70         }
71     }
72     /// Clears all events. Restarts only @Signal events.
73     void restartListening(T)(ref T element) {
74         import std.traits: hasUDA, getUDAs;
75         element.stopListening();
76         element.__canListen(true);
77         if (typeof(element).stringof == Button.stringof) {
78             mixin(ButtonListenerServices);
79         }
80     }
81 };
82 ///
83 immutable ButtonListenerServices = q{
84 	static foreach (member; __traits(derivedMembers, typeof(this))) {
85         static if (typeof(super).stringof == "Canvas") {
86             static if (mixin("hasUDA!(" ~ typeof(this).stringof ~ "." ~ member ~ ", Signal)")) {
87                 static foreach (el; ["RightClick", "LeftClick", "MouseMove", "MouseInside", "Update"]) {
88                     static if (member.stringof == "\"on" ~ el ~ getUDAs!(__traits(getMember, this, member), Signal)[0].id ~ "\"") {
89                         if (element.id == getUDAs!(__traits(getMember, this, member), Signal)[0].id) {
90                             mixin("element.on" ~ el ~ " = &on" ~ el ~ getUDAs!(__traits(getMember, this, member), Signal)[0].id ~ ";");
91                         }
92                     }
93                 }
94             }
95         }
96     }
97 };
98 ///
99 struct Constructor;
100 ///
101 struct Signal {
102 	string id;
103 }
104 ///
105 interface Startable {
106 	///
107 	void start();
108 }
109 ///
110 interface Updatable {
111 	///
112 	void update(in float deltaTime);
113 }
114 ///
115 interface Processable {
116 	///
117 	void process();
118 }