1 /**
2 Grimoire
3 Copyright (c) 2017 Enalye
4 
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising
7 from the use of this software.
8 
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute
11 it freely, subject to the following restrictions:
12 
13 	1. The origin of this software must not be misrepresented;
14 	   you must not claim that you wrote the original software.
15 	   If you use this software in a product, an acknowledgment
16 	   in the product documentation would be appreciated but
17 	   is not required.
18 
19 	2. Altered source versions must be plainly marked as such,
20 	   and must not be misrepresented as being the original software.
21 
22 	3. This notice may not be removed or altered from any source distribution.
23 */
24 
25 module ui.button;
26 
27 import std.conv: to;
28 
29 import core.all;
30 import render.all;
31 import common.all;
32 
33 import ui.widget;
34 import ui.label;
35 
36 class Button: Widget {
37 	void function() onClick;
38 
39 	override void update(float deltaTime) {}
40 	override void onEvent(Event event) {}
41 
42     override void onSelect() {
43         if(!_isLocked && !_isSelected && _isHovered)
44             isValidated = true;
45 		else
46 			isValidated = false;
47     }
48 
49     override void onValidate() {
50         if(_isValidated) {
51 			if(onClick !is null)
52 				onClick();
53 			triggerCallback();
54 		}
55     }
56 }
57 
58 class ListButton: Button {
59 	protected Sprite _sprite;
60 	Label label;
61 
62 	@property {
63 		alias color = label.color;
64 		alias text = label.text;
65 
66 		Sprite sprite() { return _sprite; }
67 		Sprite sprite(Sprite newSprite) {
68 			_sprite = newSprite;
69 			reload();
70 			return _sprite;
71 		}
72 	}
73 
74 	this(string text) {
75 		label = new Label;
76 		label.text = text;
77 		_size = label.size;
78 	}
79 
80 	this(Sprite newSprite) {
81 		label = new Label;
82 		_sprite = newSprite;
83 		reload();
84 	}
85 
86 	this(string text, Sprite newSprite) {
87 		label = new Label;
88 		label.text = text;
89 		_size = label.size;
90 		_sprite = newSprite;
91 		reload();
92 	}
93 
94 	override void update(float deltaTime) {
95 		super.update(deltaTime);
96 		label.position = _position;
97 	}
98 
99 	override void draw() {
100 		if(_isValidated)
101 			drawFilledRect(_position - _size / 2f, _size, Color.white * 0.8f);
102 		else if(_isHovered)
103 			drawFilledRect(_position - _size / 2f, _size, Color.white * 0.25f);
104 		else
105 			drawFilledRect(_position - _size / 2f, _size, Color.white * 0.15f);
106 
107 		if(sprite.texture)
108 			sprite.draw(_position);
109 
110 		if(label.isLoaded)
111 			label.draw();
112 	}
113 
114     override void onPosition() {
115         reload();
116     }
117 
118     override void onSize() {
119         reload();
120     }
121 
122 	private void reload() {
123 		label.position = _position;
124 		if(_sprite.texture) {
125 			_sprite.fit(_size);
126 		}
127 	}
128 }
129 
130 class TextButton: Button {
131 	Label label;
132 
133 	@property {
134 		alias color = label.color;
135 		alias text = label.text;
136 	}
137 
138 	this(string text) {
139 		label = new Label;
140 		label.text = text;
141 		_size = label.size;
142 	}
143 
144 	override void update(float deltaTime) {
145 		super.update(deltaTime);
146 		label.position = _position;
147 	}
148 
149 	override void draw() {
150 		if(_isLocked)
151 			drawFilledRect(_position - _size / 2f, _size, Color.white * 0.055f);
152 		else if(_isSelected)
153 			drawFilledRect(_position - _size / 2f + (_isSelected ? 1f : 0f), _size, Color.white * 0.4f);
154 		else if(_isHovered)
155 			drawFilledRect(_position - _size / 2f + (_isSelected ? 1f : 0f), _size, Color.white * 0.25f);
156 		else
157 			drawFilledRect(_position - _size / 2f + (_isSelected ? 1f : 0f), _size, Color.white * 0.15f);
158 		if(label.isLoaded)
159 			label.draw();
160 	}
161 
162     override void onPosition() {
163         label.position = _position;
164     }
165 }
166 
167 class ImgButton: Button {
168 	Label label;
169 
170 	protected {
171 		bool _isFixedSize, _isScaleLocked;
172 		Sprite _idleSprite, _hoveredSprite, _clickedSprite, _lockedSprite;
173 	}
174 
175 	@property {
176 		alias color = label.color;
177 		alias text = label.text;
178 
179 		bool isScaleLocked() { return _isScaleLocked; }
180 		bool isScaleLocked(bool newIsScaleLocked) {
181 			_isScaleLocked = newIsScaleLocked;
182 			if(_idleSprite.texture)
183 				setToSize(_idleSprite);
184 			if(_hoveredSprite.texture)
185 				setToSize(_hoveredSprite);
186 			if(_clickedSprite.texture)
187 				setToSize(_clickedSprite);
188 			if(_lockedSprite.texture)
189 				setToSize(_lockedSprite);
190 			return _isScaleLocked;
191 		}
192 
193 		Sprite idleSprite() { return _idleSprite; }
194 		Sprite idleSprite(Sprite newSprite) {
195 			if(_isFixedSize)
196 				setToSize(newSprite);
197 			else
198 				_size = newSprite.size;
199 			return _idleSprite = newSprite;
200 		}
201 
202 		Sprite hoveredSprite() { return _hoveredSprite; }
203 		Sprite hoveredSprite(Sprite newSprite) {
204 			if(_isFixedSize)
205 				setToSize(newSprite);
206 			else {
207 				if(_idleSprite.texture is null)
208 					_size = newSprite.size;
209 			}
210 			return _hoveredSprite = newSprite;
211 		}
212 
213 		Sprite clickedSprite() { return _clickedSprite; }
214 		Sprite clickedSprite(Sprite newSprite) {
215 			if(_isFixedSize)
216 				setToSize(newSprite);
217 			else {
218 				if(_idleSprite.texture is null)
219 					_size = newSprite.size;
220 			}
221 			return _clickedSprite = newSprite;
222 		}
223 
224 		Sprite lockedSprite() { return _lockedSprite; }
225 		Sprite lockedSprite(Sprite newSprite) {
226 			if(_isFixedSize)
227 				setToSize(newSprite);
228 			else {
229 				if(_idleSprite.texture is null)
230 					_size = newSprite.size;
231 			}
232 			return _lockedSprite = newSprite;
233 		}
234 	}
235 
236 	this() {
237 		label = new Label;
238 	}
239 
240 	this(string text) {
241 		label = new Label;
242 		label.text = text;
243 		_size = label.size;
244 	}
245 
246 	private void setToSize(Sprite sprite) {
247 		if(!_isFixedSize) 
248 			return;
249 
250 		if(_isScaleLocked) {
251 			Vec2f clip = to!Vec2f(sprite.clip.zw);
252 			float scale;
253 			if(_size.x / _size.y > clip.x / clip.y)
254 				scale = _size.y / clip.y;
255 			else
256 				scale = _size.x / clip.x;
257 			sprite.size = clip * scale;
258 		}
259 		else
260 			sprite.size = _size;
261 	}
262 
263 	override void update(float deltaTime) {
264 		super.update(deltaTime);
265 		label.position = _position;
266 	}
267 
268 	override void draw() {
269 		if(_isLocked) {
270 			if(_lockedSprite.texture)
271 				_lockedSprite.drawUnchecked(_position);
272 			else if(_idleSprite.texture)
273 				_idleSprite.drawUnchecked(_position);
274 			else
275 				drawFilledRect(_position - _size / 2f, _size, Color.gray);
276 		}
277 		else if(_isSelected) {
278 			if(_clickedSprite.texture)
279 				_clickedSprite.drawUnchecked(_position);
280 			else if(_idleSprite.texture)
281 				_idleSprite.drawUnchecked(_position + Vec2f.one);
282 			else
283 				drawFilledRect(_position - _size / 2f + Vec2f.one, _size, Color.blue);
284 		}
285 		else if(_isHovered) {
286 			if(_hoveredSprite.texture)
287 				_hoveredSprite.drawUnchecked(_position);
288 			else if(_idleSprite.texture)
289 				_idleSprite.drawUnchecked(_position);
290 			else
291 				drawFilledRect(_position - _size / 2f, _size, Color.green);
292 		}
293 		else {
294 			if(_idleSprite.texture)
295 				_idleSprite.drawUnchecked(_position);
296 			else
297 				drawFilledRect(_position - _size / 2f, _size, Color.red);
298 		}
299 		if(label.isLoaded)
300 			label.draw();
301 	}
302     
303     override void onSize() {
304         _isFixedSize = true;
305         if(_idleSprite.texture)
306             setToSize(_idleSprite);
307         if(_hoveredSprite.texture)
308             setToSize(_hoveredSprite);
309         if(_clickedSprite.texture)
310             setToSize(_clickedSprite);
311         if(_lockedSprite.texture)
312             setToSize(_lockedSprite);
313     }
314 }