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 	/**
125 	 * Returns true if the element will generate events on mouse press and mouse release.
126 	 * By default, only release is used.
127 	 */
128 	public @property bool mousePressEvent(bool val) @nogc @safe pure nothrow {
129 		if (val) flags |= ENABLE_MOUSE_PRESS;
130 		else flags &= ~ENABLE_MOUSE_PRESS;
131 		return flags & ENABLE_MOUSE_PRESS ? true : false;
132 	}
133 	
134 	/**
135 	 * Returns the next available StyleSheet.
136 	 */
137 	public StyleSheet getStyleSheet() {
138 		if(customStyle !is null) return customStyle;
139 		else if(parent !is null) return parent.getStyleSheet();
140 		else return globalDefaultStyle;
141 	}
142 	///Called when an object receives focus.
143 	public void focusGiven() {
144 		flags |= IS_FOCUSED;
145 		draw;
146 	}
147 	///Called when an object loses focus.
148 	public void focusTaken() {
149 		flags &= ~IS_FOCUSED;
150 		draw;
151 	}
152 	///Cycles the focus on a single element.
153 	///Returns -1 if end is reached, or the number of remaining elements that
154 	///are cycleable in the direction.
155 	public int cycleFocus(int direction) {
156 		return -1;
157 	}
158 	///Passes key events to the focused element when not in text editing mode.
159 	public void passKey(uint keyCode, ubyte mod) {
160 		
161 	}
162 	/**
163 	 * Returns whether the element is focused
164 	 */
165 	public @property bool isFocused() @nogc @safe pure nothrow const {
166 		return flags & IS_FOCUSED ? true : false;
167 	}
168 	/**
169 	 * Returns whether the element is pressed
170 	 */
171 	public @property bool isPressed() @nogc @safe pure nothrow const {
172 		return flags & IS_PRESSED ? true : false;
173 	}
174 	/**
175 	 * Returns whether the element is checked
176 	 */
177 	public @property bool isChecked() @nogc @safe pure nothrow const {
178 		return flags & IS_CHECKED ? true : false;
179 	}
180 	/**
181 	 * Sets whether the element is checked
182 	 */
183 	protected @property bool isChecked(bool val) @nogc @safe pure nothrow {
184 		if (val) flags |= IS_CHECKED;
185 		else flags &= ~IS_CHECKED;
186 		return flags & IS_CHECKED ? true : false;
187 	}
188 	public void passMCE(MouseEventCommons mec, MouseClickEvent mce) {
189 		if (state != ElementState.Enabled) return;
190 		if (!mce.state && !(isPressed)) return;
191 
192 		parent.requestFocus(this);
193 
194 		if (mce.state == ButtonState.Pressed) {
195 			if (mce.button == MouseButton.Left) flags |= IS_PRESSED;
196 			if (!(mousePressEvent )) {
197 				draw;
198 				return;
199 			}
200 		} else if (mce.button == MouseButton.Left) {
201 			flags &= ~IS_PRESSED;
202 		}
203 
204 		MouseEvent me = new MouseEvent(this, EventType.MouseClick, SourceType.WindowElement);
205 		me.mec = mec;
206 		me.mce = mce;
207 		
208 		switch (mce.button) {
209 			case MouseButton.Left:
210 				if (onMouseLClick !is null && (!mce.state || mousePressEvent))
211 					onMouseLClick(me);
212 				break;
213 			case MouseButton.Right:
214 				if (onMouseRClick !is null && (!mce.state || mousePressEvent))
215 					onMouseRClick(me);
216 				break;
217 			case MouseButton.Mid:
218 				if (onMouseMClick !is null && (!mce.state || mousePressEvent))
219 					onMouseMClick(me);
220 				break;
221 			default:
222 				break;
223 		}
224 		
225 		draw;
226 	}
227 	
228 	public void passMME(MouseEventCommons mec, MouseMotionEvent mme) {
229 		
230 		if (onMouseMove !is null) {
231 			MouseEvent me = new MouseEvent(this, EventType.MouseMotion, SourceType.WindowElement);
232 			me.mme = mme;
233 			me.mec = mec;
234 			onMouseMove(me);
235 		}
236 	}
237 	
238 	public void passMWE(MouseEventCommons mec, MouseWheelEvent mwe) {
239 		if (onMouseScroll !is null) {
240 			MouseEvent me = new MouseEvent(this, EventType.MouseScroll, SourceType.WindowElement);
241 			me.mec = mec;
242 			me.mwe = mwe;
243 			onMouseScroll(me);
244 		}
245 	}
246 	
247 }