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:          $(LINK2 https://github.com/GabyForceQ/LibertyEngine/blob/master/source/liberty/framework/gui/meta.d)
6  * Documentation:
7  * Coverage:
8 **/
9 module liberty.framework.gui.meta;
10 
11 import liberty.framework.gui.widget;
12 
13 /**
14  *
15 **/
16 mixin template WidgetEventProps(alias event, string options = "default") {
17   static string[] getEventArrayString()   {
18     return event;
19   }
20 
21   static if (options == "default") {
22     import std.algorithm : canFind;
23     import std.traits : EnumMembers;
24 
25     private {
26       static foreach (name; EnumMembers!Event)
27         mixin("enum bool _" ~ name ~ " = getEventArrayString.canFind(Event." ~ name ~ ");");
28       
29       enum bool _MouseEnterLeave = _MouseEnter && _MouseLeave;
30       enum bool _CheckUncheck = _Check && _Uncheck && _Checked && _Unchecked && _StateChange;
31 
32       static if (_MouseEnterLeave)
33         bool mouseEntered;
34 
35       static if (_CheckUncheck) {
36         bool checked;
37         
38         public bool isChecked()   const {
39           return checked;
40         }
41       }
42 
43       static if (_StateChange)
44         bool state;
45 
46       static foreach (member; event) {
47         mixin("void delegate(Widget, Event) on" ~ member ~ " = null;");
48 
49         static if (member != "Update")
50           mixin("bool isOn" ~ member ~ ";");
51       }
52     }
53 
54     static if (_MouseEnter || _MouseLeave)
55       static assert(_MouseEnterLeave,
56         "In default mode MouseEnter and MouseLeave events should be declared together.");
57 
58     static if (_Check || _Uncheck || _Checked || _Unchecked)
59       static assert(_CheckUncheck,
60         "In default mode Check, Uncheck, Checked and Unchecked events should be declared together.");
61 
62     static foreach (member; event) {
63       /**
64       *
65       **/
66       mixin("typeof(this) setOn" ~ member ~ "(void delegate(Widget, Event) on" ~ member ~ ")   {" ~
67         "this.on" ~ member ~ " = on" ~ member ~ "; return this; }");
68 
69       static if (member != "Update")
70         /**
71         *
72         **/
73         mixin("bool hasOn" ~ member ~ "()   const {" ~
74           "return on" ~ member ~ " !is null; }");
75     }
76     
77     private void clearAllBooleans() {
78       static foreach (member; event)
79         static if (member != "Update")
80           mixin("isOn" ~ member ~ " = false;");
81     }
82 
83     private void clearAllEvents() {
84       static foreach (member; event)
85         static if (member != "Update")
86           mixin("on" ~ member ~ " = null;");
87     }
88   } else static if (options == "custom") {
89     
90   } else
91     static assert(0, "Invalid options.");
92 }
93 
94 /**
95  *
96 **/
97 mixin template WidgetConstructor(string code = "") {
98   import liberty.framework.gui.impl;
99   
100   /**
101    *
102   **/
103   this(string id, Gui gui) {
104     super(id, gui);
105     mixin(code);
106   }
107 }
108 
109 /**
110  *
111 **/
112 mixin template WidgetUpdate() {
113   import liberty.input.impl;
114   import liberty.input.mouse.constants;
115   
116   /**
117    *
118   **/
119   override void update() {
120     clearAllBooleans();
121 
122     static if (_StateChange)
123       state = false;
124 
125     if (Input.getMouse.getCursorType != CursorType.DISABLED) {
126       if (isMouseColliding) {
127         static if (_MouseOver)
128           if (hasOnMouseOver) {
129             onMouseOver(this, Event.MouseOver);
130             isOnMouseOver = true;
131           }
132 
133         static if (_MouseMove)
134           if (hasOnMouseMove)
135             if (Input.getMouse.isMoving) {
136               onMouseMove(this, Event.MouseMove);
137               isOnMouseMove = true;
138             }
139 
140         static if (_MouseEnterLeave) {
141           if (hasOnMouseLeave && !hasOnMouseEnter) {
142             if (!mouseEntered)
143               mouseEntered = true;
144           } else if (hasOnMouseEnter && !mouseEntered) {
145             onMouseEnter(this, Event.MouseEnter);
146             mouseEntered = true;
147             isOnMouseEnter = true;
148           }
149         }
150 
151         static if (_MouseLeftClick)
152           if (hasOnMouseLeftClick)
153             if (Input.getMouse.isButtonDown(MouseButton.LEFT)) {
154               onMouseLeftClick(this, Event.MouseLeftClick);
155               isOnMouseLeftClick = true;
156             }
157 
158         static if (_MouseMiddleClick)
159           if (hasOnMouseMiddleClick)
160             if (Input.getMouse.isButtonDown(MouseButton.MIDDLE)) {
161               onMouseMiddleClick(this, Event.MouseMiddleClick);
162               isOnMouseMiddleClick = true;
163             }
164 
165         static if (_MouseRightClick)
166           if (hasOnMouseRightClick)
167             if (Input.getMouse.isButtonDown(MouseButton.RIGHT)) {
168               onMouseRightClick(this, Event.MouseRightClick);
169               isOnMouseRightClick = true;
170             }
171 
172         static if (_CheckUncheck) {
173           if (hasOnCheck && !checked) {
174             if (Input.getMouse.isButtonDown(MouseButton.LEFT)) {
175               onCheck(this, Event.Check);
176               checked = true;
177               isOnCheck = true;
178               static if (_StateChange)
179                 state = true;
180             }
181           } else if (hasOnUncheck && checked)
182             if (Input.getMouse.isButtonDown(MouseButton.LEFT)) {
183               onUncheck(this, Event.Uncheck);
184               checked = false;
185               isOnUncheck = true;
186               static if (_StateChange)
187                 state = true;
188             }
189 
190           static if (_StateChange)
191             if (hasOnStateChange && state) {
192               onStateChange(this, Event.StateChange);
193               isOnStateChange = true;
194             }
195         }
196       } else {
197         static if (_MouseLeave) {
198           if (hasOnMouseLeave && mouseEntered) {
199             onMouseLeave(this, Event.MouseLeave);
200             isOnMouseLeave = true;
201           }
202 
203           if (mouseEntered)
204             mouseEntered = false;
205         }
206       }
207     }
208 
209     static if (_CheckUncheck) {
210       if (hasOnChecked && checked) {
211         onChecked(this, Event.Checked);
212         isOnChecked = true;
213       } else if (hasOnUnchecked && !checked) {
214         onUnchecked(this, Event.Unchecked);
215         isOnUnchecked = true;
216       }
217     }
218 
219     static if (_Update)
220       if (onUpdate !is null)
221         onUpdate(this, Event.Update);
222   }
223 }