1 module PixelPerfectEngine.concrete.elements.base;
2 
3 public import PixelPerfectEngine.concrete.interfaces;
4 public import PixelPerfectEngine.concrete.types.stylesheet;
5 public import PixelPerfectEngine.concrete.types.event;
6 public import PixelPerfectEngine.system.input.handler;
7 //import PixelPerfectEngine.system.input.types : MouseMotionEvent;
8 
9 
10 /**
11  * Definies values about whether a WindowElement is enabled or not.
12  */
13 public enum ElementState : ubyte {
14 	Enabled				=	0,	///Means the element is enabled.
15 	DisabledWOGray		=	1,	///Disabled without grayout, should be only used by elements contained within
16 	Disabled			=	2,	///Means the element is disabled
17 }
18 alias EventDeleg = void delegate(Event ev);
19 /**
20  * All Window elements inherit from this class. Provides basic interfacing with containers.
21  */
22 abstract class WindowElement : Focusable, MouseEventReceptor {
23     public static InputHandler inputHandler;	///Common input handler, must be set upon program initialization for text input, etc.
24     ///Contains the position of the element.
25     ///Should be only modified with functions to ensure consistency.
26 	protected Box			position;
27     ///Points to the container for two-way communication
28 	public ElementContainer	parent;
29 	///Contains the text of the element if any.
30     ///Should be modified with functions to ensure redraws.
31 	protected Text			text;
32     /**
33      * Passed with other event informations when event is caused.
34      * Can be something like the name of the instance.
35      *
36      * Should not be modified after creation.
37      */
38 	protected string		source;
39     ///Contains various status flags.
40     protected uint			flags;
41 	protected static enum	ENABLE_MOUSE_PRESS = 1<<3;
42 	protected static enum	IS_CLICKED = 1<<4;
43 	protected static enum	ENABLE_RCLICK_FLAG = 1<<5;
44 	protected static enum	IS_PRESSED = 1<<6;
45 	protected static enum	IS_CHECKED = 1<<7;
46 	protected static enum	IS_FOCUSED = 1<<8;
47 	protected static enum	IS_LHS = 1<<30;
48     ///Sets a custom style for this element.
49     ///If not set, then it'll get the style from it's parent.
50 	public StyleSheet		customStyle;
51 	//protected ElementState _state;
52 
53 	
54 	//public static PopUpHandler popUpHandler;	///Common pop-up handler
55 	//public static StyleSheet styleSheet;		///Basic stylesheet, all elements default to this if no alternative found
56 
57 	//public static void delegate() onDraw;		///Called when drawing is finished
58 
59 	public EventDeleg 		onMouseLClick;	///Called on left mouseclick released
60 	public EventDeleg 		onMouseRClick;	///Called on right mouseclick released
61 	public EventDeleg 		onMouseMClick;	///Called on middle mouseclick released
62 	public EventDeleg 		onMouseMove;	///Called if mouse is moved on object
63 	public EventDeleg 		onMouseScroll;	///Called if mouse is scrolled on object
64 	
65 	protected MouseMotionEvent		lastMousePosition;	///Stores the last known mouse position for future reference
66     ///Returns the text of this element.
67 	public @nogc Text getText(){
68 		return text;
69 	}
70     public void setText(Text s) {
71 		text = s;
72 		//parent.clearArea(position);
73 		draw();
74 	}
75 	public void setText(dstring s) {
76 		text.text = s;
77 		text.next = null;
78 		//parent.clearArea(position);
79 		draw();
80 	}
81 	/**
82 	 * Sets whether the element is enabled or not.
83 	 */
84 	public @property ElementState state(ElementState state) {
85 		flags &= ~0x3;
86 		flags |= cast(ubyte)state;
87 		draw();
88 		return state;
89 	}
90 	/**
91 	 * Returns whether the element is enabled or not.
92 	 */
93 	public @property ElementState state() @nogc @safe const pure nothrow {
94 		return cast(ElementState)(flags & 0x3);
95 	}
96 	public void setParent(ElementContainer parent) {
97 		this.parent = parent;
98 	}
99 	/**
100 	 * Updates the output. Every subclass must override it.
101 	 */
102 	public abstract void draw();
103 	public Box getPosition() {
104 		return position;
105 	}
106 	public Box setPosition(Box position) {
107 		this.position = position;
108 		draw();
109 		return position;
110 	}
111 	/**
112 	 * Returns the source string.
113 	 */
114 	@property public string getSource(){
115 		return source;
116 	}
117 	/**
118 	 * Returns true if the element will generate events on mouse press and mouse release.
119 	 * By default, only release is used.
120 	 */
121 	public @property bool mousePressEvent() @nogc @safe pure nothrow {
122 		return flags & ENABLE_MOUSE_PRESS ? true : false;
123 	}
124 	/+/**
125 	 * Returns true if middle mouse button events are enabled.
126 	 */
127 	public @property bool mouseMClickEvent() @nogc @safe pure nothrow {
128 		return flags & ENABLE_MCLICK_FLAG ? true : false;
129 	}
130 	/**
131 	 * Returns true if right mouse button events are enabled.
132 	 */
133 	public @property bool mouseRClickEvent() @nogc @safe pure nothrow {
134 		return flags & ENABLE_RCLICK_FLAG ? true : false;
135 	}+/
136 	/**
137 	 * Returns true if the element will generate events on mouse press and mouse release.
138 	 * By default, only release is used.
139 	 */
140 	public @property bool mousePressEvent(bool val) @nogc @safe pure nothrow {
141 		if (val) flags |= ENABLE_MOUSE_PRESS;
142 		else flags &= ~ENABLE_MOUSE_PRESS;
143 		return flags & ENABLE_MOUSE_PRESS ? true : false;
144 	}
145 	/+/**
146 	 * Returns true if middle mouse button events are enabled.
147 	 */
148 	public @property bool mouseMClickEvent(bool val) @nogc @safe pure nothrow {
149 		if (val) flags |= ENABLE_MCLICK_FLAG;
150 		else flags &= ~ENABLE_MCLICK_FLAG;
151 		return flags & ENABLE_MCLICK_FLAG ? true : false;
152 	}
153 	/**
154 	 * Returns true if right mouse button events are enabled.
155 	 */
156 	public @property bool mouseRClickEvent(bool val) @nogc @safe pure nothrow {
157 		if (val) flags |= ENABLE_RCLICK_FLAG;
158 		else flags &= ~ENABLE_RCLICK_FLAG;
159 		return flags & ENABLE_RCLICK_FLAG ? true : false;
160 	}+/
161 	/**
162 	 * Returns the next available StyleSheet.
163 	 */
164 	public StyleSheet getStyleSheet() {
165 		if(customStyle !is null) return customStyle;
166 		else if(parent !is null) return parent.getStyleSheet();
167 		else return globalDefaultStyle;
168 	}
169 	///Called when an object receives focus.
170 	public void focusGiven() {
171 		flags |= IS_FOCUSED;
172 		draw;
173 	}
174 	///Called when an object loses focus.
175 	public void focusTaken() {
176 		flags &= ~IS_FOCUSED;
177 		draw;
178 	}
179 	///Cycles the focus on a single element.
180 	///Returns -1 if end is reached, or the number of remaining elements that
181 	///are cycleable in the direction.
182 	public int cycleFocus(int direction) {
183 		return -1;
184 	}
185 	///Passes key events to the focused element when not in text editing mode.
186 	public void passKey(uint keyCode, ubyte mod) {
187 		
188 	}
189 	/**
190 	 * Returns whether the element is focused
191 	 */
192 	public @property bool isFocused() @nogc @safe pure nothrow const {
193 		return flags & IS_FOCUSED ? true : false;
194 	}
195 	/**
196 	 * Returns whether the element is pressed
197 	 */
198 	public @property bool isPressed() @nogc @safe pure nothrow const {
199 		return flags & IS_PRESSED ? true : false;
200 	}
201 	/**
202 	 * Returns whether the element is checked
203 	 */
204 	public @property bool isChecked() @nogc @safe pure nothrow const {
205 		return flags & IS_CHECKED ? true : false;
206 	}
207 	protected @property bool isChecked(bool val) @nogc @safe pure nothrow {
208 		if (val) flags |= IS_CHECKED;
209 		else flags &= ~IS_CHECKED;
210 		return flags & IS_CHECKED ? true : false;
211 	}
212 	public void passMCE(MouseEventCommons mec, MouseClickEvent mce) {
213 		if (!mce.state && !(isPressed)) return;
214 
215 		parent.requestFocus(this);
216 
217 		if (mce.state == ButtonState.Pressed) {
218 			if (mce.button == MouseButton.Left) flags |= IS_PRESSED;
219 			if (!(mousePressEvent )) {
220 				draw;
221 				return;
222 			}
223 		} else if (mce.button == MouseButton.Left) {
224 			flags &= ~IS_PRESSED;
225 		}
226 
227 		MouseEvent me = new MouseEvent(this, EventType.MouseClick, SourceType.WindowElement);
228 		me.mec = mec;
229 		me.mce = mce;
230 		
231 		switch (mce.button) {
232 			case MouseButton.Left:
233 				if (onMouseLClick !is null && (!mce.state || mousePressEvent))
234 					onMouseLClick(me);
235 				break;
236 			case MouseButton.Right:
237 				if (onMouseRClick !is null && (!mce.state || mousePressEvent))
238 					onMouseRClick(me);
239 				break;
240 			case MouseButton.Mid:
241 				if (onMouseMClick !is null && (!mce.state || mousePressEvent))
242 					onMouseMClick(me);
243 				break;
244 			default:
245 				break;
246 		}
247 		
248 		draw;
249 	}
250 	
251 	public void passMME(MouseEventCommons mec, MouseMotionEvent mme) {
252 		
253 		if (onMouseMove !is null) {
254 			MouseEvent me = new MouseEvent(this, EventType.MouseMotion, SourceType.WindowElement);
255 			me.mme = mme;
256 			me.mec = mec;
257 			onMouseMove(me);
258 		}
259 	}
260 	
261 	public void passMWE(MouseEventCommons mec, MouseWheelEvent mwe) {
262 		if (onMouseScroll !is null) {
263 			MouseEvent me = new MouseEvent(this, EventType.MouseScroll, SourceType.WindowElement);
264 			me.mec = mec;
265 			me.mwe = mwe;
266 			onMouseScroll(me);
267 		}
268 	}
269 	
270 }