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