1 #include <Interface.h>
2 
3 std::map<int, std::unique_ptr<Object>> global_objects;
4 std::vector<int> z_value; //rendering order
5 std::map<int, int> z_index;
6 std::vector<int> del; // deletion stack
7 int all_obj_id = 0;
8 std::map<int, bool> active;
9 int focused = 0;
10 int cursor = 0;
11 int global_focus = 0;
12 
13 sf::Color default_main_color = sf::Color(64, 64, 64, 128);
14 sf::Color default_hover_main_color = sf::Color(200, 128, 128, 128);
15 sf::Color default_active_main_color = sf::Color(255, 128, 128, 255);
16 float default_margin =2;
17 sf::Vector2f default_size = sf::Vector2f(1920, 1080);
18 sf::View default_view = sf::View(sf::FloatRect(0, 0, default_size.x, default_size.y));
19 
20 float animation_sharpness = 5.f;
21 float action_dt = 0.3;
22 
23 
overlap(sf::FloatRect a,sf::FloatRect b)24 sf::FloatRect overlap(sf::FloatRect a, sf::FloatRect b)
25 {
26 	sf::FloatRect c;
27 	c.top = std::max(a.top, b.top);
28 	c.left = std::max(a.left, b.left);
29 	c.height = std::max(std::min(a.top + a.height, b.top + b.height) - c.top, 0.f);
30 	c.width = std::max(std::min(a.left + a.width, b.left + b.width) - c.left, 0.f);
31 	return c;
32 }
33 
operator +(ColorFloat a,ColorFloat b)34 ColorFloat operator+(ColorFloat a, ColorFloat b)
35 {
36 	ColorFloat c;
37 	c.r = a.r + b.r;
38 	c.g = a.g + b.g;
39 	c.b = a.b + b.b;
40 	c.a = a.a + b.a;
41 	return c;
42 }
43 
operator -(ColorFloat a,ColorFloat b)44 ColorFloat operator-(ColorFloat a, ColorFloat b)
45 {
46 	ColorFloat c;
47 	c.r = a.r - b.r;
48 	c.g = a.g - b.g;
49 	c.b = a.b - b.b;
50 	c.a = a.a - b.a;
51 	return c;
52 }
53 
operator *(ColorFloat a,float b)54 ColorFloat operator*(ColorFloat a, float b)
55 {
56 	ColorFloat c;
57 	c.r = a.r * b;
58 	c.g = a.g * b;
59 	c.b = a.b * b;
60 	c.a = a.a * b;
61 	return c;
62 }
63 
ToColor(ColorFloat a)64 sf::Color ToColor(ColorFloat a)
65 {
66 	return sf::Color(a.r, a.g, a.b, a.a);
67 }
68 
ToColorF(sf::Color a)69 ColorFloat ToColorF(sf::Color a)
70 {
71 	return ColorFloat(a.r, a.g, a.b, a.a);
72 }
73 
get_glob_obj(int id)74 Object& get_glob_obj(int id)
75 {
76 	return *global_objects[id].get();
77 }
78 
UpdateAspectRatio(float width,float heigth)79 void UpdateAspectRatio(float width, float heigth)
80 {
81 	sf::Vector2f size = sf::Vector2f(default_size.x * std::max(1.f, (width / heigth) * (default_size.y / default_size.x)), default_size.x * std::max(default_size.y / default_size.x, heigth / width));
82 	default_view.reset(sf::FloatRect(sf::Vector2f(0, 0), size));
83 }
84 
AddGlobalObject(Object & a)85 int AddGlobalObject(Object & a)
86 {
87 	Object* copy = a.GetCopy();
88 	global_objects[copy->id] = std::unique_ptr<Object>(copy);//add a copy to the global list
89 	global_objects[copy->id].get()->id = copy->id;
90 	z_value.push_back(copy->id);
91 	global_focus = copy->id;
92 	focused = copy->id;
93 	return copy->id;
94 }
95 
global_exists(int id)96 bool global_exists(int id)
97 {
98 	for (auto &obj : global_objects)
99 	{
100 		if (obj.first == id)
101 		{
102 			return true;
103 		}
104 	}
105 	return false;
106 }
107 
z_val(int id)108 int z_val(int id)
109 {
110 	std::vector<int>::iterator it = std::find(z_value.begin(), z_value.end(), id);
111 	return std::distance(z_value.begin(), it);
112 }
113 
NoObjects()114 bool NoObjects()
115 {
116 	if (global_objects.size() != 0)
117 	{
118 		return false;
119 	}
120 	return true;
121 }
122 
NumberOfObjects()123 int NumberOfObjects()
124 {
125 	return global_objects.size();
126 }
127 
RemoveGlobalObject(int id)128 void RemoveGlobalObject(int id)
129 {
130 	if (global_objects.count(id) != 0)
131 	{
132 		global_objects.erase(id);
133 		int z_id = z_val(id);
134 		z_value.erase(z_value.begin() + z_id);
135 	}
136 }
137 
RemoveAllObjects1()138 void RemoveAllObjects1()
139 {
140 	global_objects.clear();
141 	z_value.clear();
142 }
143 
144 
RemoveAllObjects()145 void RemoveAllObjects()
146 {
147 	for (auto &obj:global_objects)
148 	{
149 		del.push_back(obj.first);
150 	}
151 }
152 
Add2DeleteQueue(int id)153 void Add2DeleteQueue(int id)
154 {
155 	if (global_objects.count(id) != 0)
156 	{
157 		del.push_back(id);
158 	}
159 }
160 
key_name(sf::Keyboard::Key & key)161 std::string key_name(sf::Keyboard::Key & key)
162 {
163 	//yeah, I dont like this code either
164 #define ITEM(x) case sf::Keyboard::x : return #x;
165 	switch (key)
166 	{
167 		ITEM(A); ITEM(B); ITEM(C);
168 		ITEM(D); ITEM(E); ITEM(F); ITEM(G);
169 		ITEM(H); ITEM(I); ITEM(J); ITEM(K);
170 		ITEM(L); ITEM(M); ITEM(N); ITEM(O);
171 		ITEM(P); ITEM(Q); ITEM(R); ITEM(S);
172 		ITEM(T); ITEM(U); ITEM(V); ITEM(W);
173 		ITEM(X); ITEM(Y); ITEM(Z); ITEM(Num0);
174 		ITEM(Num1); ITEM(Num2); ITEM(Num3); ITEM(Num4);
175 		ITEM(Num5); ITEM(Num6); ITEM(Num7); ITEM(Num8);
176 		ITEM(Num9); ITEM(Escape); ITEM(LControl); ITEM(LShift);
177 		ITEM(LAlt); ITEM(LSystem); ITEM(RControl); ITEM(RShift);
178 		ITEM(RAlt); ITEM(RSystem); ITEM(Menu); ITEM(LBracket);
179 		ITEM(RBracket); /*ITEM(Semicolon);*/ ITEM(Comma); ITEM(Period);
180 		ITEM(Quote); ITEM(Slash); /*ITEM(Backslash);*/ ITEM(Tilde);
181 		ITEM(Equal);/* ITEM(Hyphen);*/ ITEM(Space); /*ITEM(Enter);*/
182 		/*ITEM(Backspace); */ITEM(Tab); ITEM(PageUp); ITEM(PageDown);
183 		ITEM(End); ITEM(Home); ITEM(Insert); ITEM(Delete);
184 		ITEM(Add); ITEM(Subtract); ITEM(Multiply); ITEM(Divide);
185 		ITEM(Left); ITEM(Right); ITEM(Up); ITEM(Down);
186 		ITEM(Numpad0); ITEM(Numpad1); ITEM(Numpad2); ITEM(Numpad3);
187 		ITEM(Numpad4); ITEM(Numpad5); ITEM(Numpad6); ITEM(Numpad7);
188 		ITEM(Numpad8); ITEM(Numpad9); ITEM(F1); ITEM(F2);
189 		ITEM(F3); ITEM(F4); ITEM(F5); ITEM(F6);
190 		ITEM(F7); ITEM(F8); ITEM(F9); ITEM(F10);
191 		ITEM(F11); ITEM(F12); ITEM(F13); ITEM(F14);
192 		ITEM(F15); ITEM(Pause);
193 	default:
194 		return "UNKNOWN";
195 	}
196 }
197 
UpdateAllObjects(sf::RenderWindow * window,InputState & state)198 void UpdateAllObjects(sf::RenderWindow * window, InputState& state)
199 {
200 	for (auto &id : del)
201 	{
202 		RemoveGlobalObject(id);
203 	}
204 
205 	del.clear();
206 
207 	//render stuff in the following order
208 	for (auto &z : z_value)
209 	{
210 		if (global_objects.count(z) != 0)
211 		{
212 			global_objects[z].get()->used_view = default_view;
213 			global_objects[z].get()->Update(window, state);
214 		}
215 	}
216 
217 	if (global_objects.count(global_focus) != 0)
218 	{
219 		//put the focused global object to the top
220 		int top_id = z_value[z_value.size() - 1];
221 
222 		//if not the top object and not a static object
223 		if (top_id != global_focus)
224 		{
225 			if (global_objects.count(top_id) != 0)
226 			{
227 				global_objects[top_id]->UpdateAction(window, state);
228 				if (!global_objects[global_focus].get()->static_object)
229 				{
230 					int global_z = z_val(global_focus);
231 					int top_z = z_value.size() - 1;
232 					std::swap(z_value[top_z], z_value[global_z]);
233 				}
234 			}
235 		}
236 
237 		//update callbacks in the focused object
238 		global_objects[global_focus]->UpdateAction(window, state);
239 	}
240 }
241 
242 
interpolate(State a,State b,float t)243 State interpolate(State a, State b, float t)
244 {
245 	State C;
246 	C.position.x = a.position.x*(1.f - t) + b.position.x*t;
247 	C.position.y = a.position.y*(1.f - t) + b.position.y*t;
248 	C.size.x = a.size.x*(1.f - t) + b.size.x*t;
249 	C.size.y = a.size.y*(1.f - t) + b.size.y*t;
250 	C.border_thickness = a.border_thickness*(1.f - t) + b.border_thickness*t;
251 	C.margin = a.margin*(1.f - t) + b.margin*t;
252 	C.scroll = a.scroll*(1.f - t) + b.scroll*t;
253 	C.font_size = a.font_size*(1.f - t) + b.font_size*t;
254 	C.color_main = a.color_main*(1.f - t) + b.color_main*t;
255 	C.color_second = a.color_second*(1.f - t) + b.color_second*t;
256 	C.color_border = a.color_border*(1.f - t) + b.color_border*t;
257 	return C;
258 }
259 
SetPosition(float x,float y)260 void Object::SetPosition(float x, float y)
261 {
262 	defaultstate.position = sf::Vector2f(x, y);
263 	curstate.position = sf::Vector2f(x, y);
264 	activestate.position = sf::Vector2f(x, y);
265 	hoverstate.position = sf::Vector2f(x, y);
266 }
267 
SetSize(float x,float y)268 void Object::SetSize(float x, float y)
269 {
270 	defaultstate.size = sf::Vector2f(x, y);
271 	activestate.size = sf::Vector2f(x, y);
272 	hoverstate.size = sf::Vector2f(x, y);
273 }
274 
SetHeigth(float x)275 void Object::SetHeigth(float x)
276 {
277 	defaultstate.size.y = x;
278 	activestate.size.y = x;
279 	hoverstate.size.y = x;
280 }
281 
SetWidth(float x)282 void Object::SetWidth(float x)
283 {
284 	defaultstate.size.x = x;
285 	activestate.size.x = x;
286 	hoverstate.size.x = x;
287 }
288 
SetBackgroundColor(sf::Color color)289 void Object::SetBackgroundColor(sf::Color color)
290 {
291 	defaultstate.color_main = color;
292 	activestate.color_main = color;
293 	hoverstate.color_main = color;
294 }
295 
SetBorderColor(sf::Color color)296 void Object::SetBorderColor(sf::Color color)
297 {
298 	defaultstate.color_border = color;
299 	activestate.color_border = color;
300 	hoverstate.color_border = color;
301 }
302 
SetBorderWidth(float S)303 void Object::SetBorderWidth(float S)
304 {
305 	defaultstate.border_thickness = S;
306 	activestate.border_thickness = S;
307 	hoverstate.border_thickness = S;
308 }
309 
SetMargin(float x)310 void Object::SetMargin(float x)
311 {
312 	defaultstate.margin = x;
313 	activestate.margin = x;
314 	hoverstate.margin = x;
315 }
316 
SetInsideSize(float x)317 void Object::SetInsideSize(float x)
318 {
319 	curstate.inside_size = x;
320 	defaultstate.inside_size = x;
321 	activestate.inside_size = x;
322 	hoverstate.inside_size = x;
323 }
324 
SetScroll(float x)325 void Object::SetScroll(float x)
326 {
327 	defaultstate.scroll = x;
328 	activestate.scroll = x;
329 	hoverstate.scroll = x;
330 	curstate.scroll = x;
331 }
332 
ApplyScroll(float x)333 void Object::ApplyScroll(float x)
334 {
335 	defaultstate.scroll = x;
336 	activestate.scroll = x;
337 	hoverstate.scroll = x;
338 }
339 
Move(sf::Vector2f dx)340 void Object::Move(sf::Vector2f dx)
341 {
342 	if (!isnan(dx.x) && !isnan(dx.y) && (dx.x != 0 || dx.y != 0))
343 	{
344 		defaultstate.position += dx;
345 		curstate.position += dx;
346 		activestate.position += dx;
347 		hoverstate.position += dx;
348 	}
349 }
350 
SetDefaultFunction(call_func fun)351 void Object::SetDefaultFunction(call_func fun)
352 {
353 	defaultfn.push_back(fun);
354 }
355 
SetCallbackFunction(call_func fun,bool limit_repeat)356 void Object::SetCallbackFunction(call_func fun, bool limit_repeat)
357 {
358 	callback.push_back(fun);
359 	limiter = limit_repeat;
360 }
361 
SetHoverFunction(call_func fun)362 void Object::SetHoverFunction(call_func fun)
363 {
364 	hoverfn.push_back(fun);
365 }
366 
SetMainDefaultFunction(call_func fun)367 void Object::SetMainDefaultFunction(call_func fun)
368 {
369 	if (defaultfn.size() == 0)
370 		defaultfn.push_back(fun);
371 	else
372 		defaultfn[0] = fun;
373 }
374 
SetMainCallbackFunction(call_func fun,bool limit_repeat)375 void Object::SetMainCallbackFunction(call_func fun, bool limit_repeat)
376 {
377 	if (callback.size() == 0)
378 		callback.push_back(fun);
379 	else
380 		callback[0] = fun;
381 	limiter = limit_repeat;
382 }
383 
384 
SetMainHoverFunction(call_func fun)385 void Object::SetMainHoverFunction(call_func fun)
386 {
387 	if (hoverfn.size() == 0)
388 		hoverfn.push_back(fun);
389 	else
390 		hoverfn[0] = fun;
391 }
392 
ClearDefaultFunctions()393 void Object::ClearDefaultFunctions()
394 {
395 	defaultfn.clear();
396 }
397 
ClearCallbackFunctions()398 void Object::ClearCallbackFunctions()
399 {
400 	callback.clear();
401 }
402 
ClearHoverFunctions()403 void Object::ClearHoverFunctions()
404 {
405 	hoverfn.clear();
406 }
407 
RunCallback(sf::RenderWindow * window,InputState & state)408 bool Object::RunCallback(sf::RenderWindow * window, InputState & state)
409 {
410 	if (callback.size() != 0)
411 	{
412 		//run through all of the callbacks
413 		for (auto &this_callback : callback)
414 		{
415 			this_callback(window, state); //run callback with state info
416 		}
417 		return true;
418 	}
419 	else
420 	{
421 		//try to run a callback inside the object
422 		for (auto &obj : objects)
423 		{
424 			if (obj.get()->RunCallback(window, state))
425 			{
426 				return true;
427 			}
428 		}
429 
430 		//mission failed. we'll get 'em next time
431 		return false;
432 	}
433 }
434 
clone_states()435 void Object::clone_states()
436 {
437 	curstate = defaultstate;
438 	activestate = defaultstate;
439 	hoverstate = defaultstate;
440 }
441 
Update(sf::RenderWindow * window,InputState & state)442 void Object::Update(sf::RenderWindow * window, InputState& state)
443 {
444 	worldPos = window->mapPixelToCoords(sf::Vector2i(state.mouse_pos.x, state.mouse_pos.y));
445 	obj= sf::FloatRect(curstate.position.x, curstate.position.y, curstate.size.x, curstate.size.y);
446 
447 	window->setView(used_view);
448 	state.mouse_speed = window->mapPixelToCoords(sf::Vector2i(state.mouse_pos.x, state.mouse_pos.y)) -
449 						window->mapPixelToCoords(sf::Vector2i(state.mouse_prev.x, state.mouse_prev.y));
450 
451 	if ( ((state.mouse[0] || state.mouse[2]) && !limiter) || ((state.mouse_press[0] || state.mouse_press[2]) && limiter) ) //if clicked
452 	{
453 		if (obj.contains(worldPos)) // if inside object
454 		{
455 			active[id] = true; //set as active
456 			cursor = id;
457 			if (defaultfn.size() != 0)
458 				focused = id; // save this object as the last focused if it has a default callback
459 
460 			if (global_exists(id))
461 			{
462 				global_focus = id;
463 			}
464 		}
465 	}
466 	else
467 	{
468 		active[id] = false; //deactivate
469 	}
470 
471 
472 	float t = 1.f - exp(-animation_sharpness * state.dt);
473 
474 	//update animation
475 	switch (curmode)
476 	{
477 	case DEFAULT:
478 		curstate = interpolate(curstate, defaultstate, t);
479 		break;
480 	case ACTIVE:
481 		curstate = interpolate(curstate, activestate, t);
482 		break;
483 	case ONHOVER:
484 		curstate = interpolate(curstate, hoverstate, t);
485 		break;
486 	}
487 
488 	Draw(window, state);
489 }
490 
UpdateAction(sf::RenderWindow * window,InputState & state)491 void Object::UpdateAction(sf::RenderWindow * window, InputState & state)
492 {
493 	state.mouse_speed = window->mapPixelToCoords(sf::Vector2i(state.mouse_pos.x, state.mouse_pos.y)) -
494 						window->mapPixelToCoords(sf::Vector2i(state.mouse_prev.x, state.mouse_prev.y));
495 
496 	curmode = Object::DEFAULT;
497 	//if mouse is inside the object
498 	if (obj.contains(worldPos))
499 	{
500 		if(!(state.mouse[0] || state.mouse[2])) // if hover
501 		{
502 			for (auto &this_callback : hoverfn)
503 			{
504 				this_callback(window, state); //run callback with state info
505 			}
506 			curmode = ONHOVER;
507 		}
508 	}
509 
510 	if (cursor == id)
511 	{
512 		curmode = ONHOVER;
513 	}
514 
515 	if (active[id])
516 	{
517 		for (auto &this_callback : callback)
518 		{
519 			this_callback(window, state); //run callback with state info
520 		}
521 		curmode = ACTIVE;
522 	}
523 
524 	if (action_time <= 0.f) //limit the repetability
525 	{
526 		if (focused == id) //if this object is the one that is currently in focus
527 		{
528 			for (auto &this_callback : defaultfn)
529 			{
530 				this_callback(window, state); //run callback with state info
531 			}
532 		}
533 	}
534 	else
535 	{
536 		action_time -= state.dt;
537 	}
538 
539 	//update callbacks for all functions inside
540 	for (auto &obj : objects)
541 	{
542 		obj.get()->UpdateAction(window, state);
543 	}
544 }
545 
546 
Object()547 Object::Object() : callback({}), hoverfn({}), defaultfn({}), curmode(DEFAULT), action_time(0.2), obj_allign(LEFT), static_object(false), limiter(false)
548 {
549 	curstate.color_main = default_main_color;
550 	activestate.color_main = default_active_main_color;
551 	hoverstate.color_main = default_hover_main_color;
552 	defaultstate.color_main = default_main_color;
553 
554 	used_view = default_view;
555 
556 	id = all_obj_id;
557 	active[id] = false;
558 	all_obj_id++;
559 }
560 
Object(Object & A)561 Object::Object(Object & A)
562 {
563 	*this = A;
564 }
565 
Object(Object && A)566 Object::Object(Object && A)
567 {
568 	*this = A;
569 }
570 
Object(Object * A)571 Object::Object(Object * A)
572 {
573 	*this = *A;
574 }
575 
operator =(Object & A)576 void Object::operator=(Object & A)
577 {
578 	copy(A);
579 }
580 
operator =(Object && A)581 void Object::operator=(Object && A)
582 {
583 	copy(A);
584 }
585 
copy(Object & A)586 void Object::copy(Object & A)
587 {
588 	curstate = A.curstate;
589 	curstate.margin = A.defaultstate.margin;
590 	activestate = A.activestate;
591 	hoverstate = A.hoverstate;
592 	defaultstate = A.defaultstate;
593 	curmode = A.curmode;
594 	static_object = A.static_object;
595 	limiter = A.limiter;
596 	used_view = A.used_view;
597 	obj_allign = A.obj_allign;
598 
599 	for (auto &a : A.callback) callback.push_back(a);
600 	for (auto &a : A.hoverfn) hoverfn.push_back(a);
601 	for (auto &a : A.defaultfn) defaultfn.push_back(a);
602 
603 	id = all_obj_id;
604 	all_obj_id++;
605 	active[id] = false;
606 
607 	action_time = A.action_time;
608 
609 	for (auto &element : A.objects)
610 		Object::AddObject(element.get(), element.get()->obj_allign);
611 }
612 
copy(Object && A)613 void Object::copy(Object && A)
614 {
615 	std::swap(curstate, A.curstate);
616 	std::swap(activestate, A.activestate);
617 	std::swap(hoverstate, A.hoverstate);
618 	std::swap(defaultstate, A.defaultstate);
619 	std::swap(curmode, A.curmode);
620 	std::swap(limiter, A.limiter);
621 	std::swap(static_object, A.static_object);
622 	std::swap(used_view, A.used_view);
623 	std::swap(obj_allign, A.obj_allign);
624 	std::swap(id, A.id);
625 	std::swap(action_time, A.action_time);
626 	std::swap(objects, A.objects);
627 }
628 
GetCopy()629 Object * Object::GetCopy()
630 {
631 	return new Object(*this);
632 }
633 
Draw(sf::RenderWindow * window,InputState & state)634 void Object::Draw(sf::RenderWindow * window, InputState & state)
635 {
636 	//nothing to draw
637 }
638 
AddObject(Object * something,Allign a)639 void Object::AddObject(Object * something, Allign a)
640 {
641 	something->obj_allign = a;
642 	objects.push_back(std::unique_ptr<Object>(something->GetCopy()));
643 	this->SetInsideSize(defaultstate.inside_size + something->defaultstate.size.y + something->defaultstate.margin);
644 }
645 
SetBackground(const sf::Texture & texture)646 void Box::SetBackground(const sf::Texture & texture)
647 {
648 	image = texture;
649 	rect.setTexture(&image);
650 }
651 
Draw(sf::RenderWindow * window,InputState & state)652 void Box::Draw(sf::RenderWindow * window, InputState& state)
653 {
654 	if (auto_size)
655 	{
656 		SetSize(this->defaultstate.size.x, this->defaultstate.inside_size + this->defaultstate.margin);
657 	}
658 
659 	//update the box itself
660 	if (   !(ToColor(defaultstate.color_main) == sf::Color::Transparent && curmode == DEFAULT)
661 		&& !(ToColor(hoverstate.color_main) == sf::Color::Transparent && curmode == ONHOVER)
662 		&& !(ToColor(activestate.color_main) == sf::Color::Transparent && curmode == ACTIVE)  )
663 	{
664 		rect.setPosition(curstate.position);
665 		rect.setSize(curstate.size);
666 		rect.setFillColor(ToColor(curstate.color_main));
667 		rect.setOutlineThickness(curstate.border_thickness);
668 		rect.setOutlineColor(ToColor(curstate.color_border));
669 		window->draw(rect);
670 	}
671 
672 	sf::Vector2f thisone = this->used_view.getSize();
673 	sf::Vector2f view_size = default_view.getSize();
674 	sf::View gview = window->getView();
675 	sf::FloatRect global_view = sf::FloatRect(gview.getCenter() - gview.getSize()*0.5f, gview.getSize());
676 	sf::FloatRect this_view = overlap(global_view, sf::FloatRect(curstate.position, curstate.size));
677 	boxView.reset(this_view);
678 	sf::FloatRect global_viewport = gview.getViewport();
679 	sf::FloatRect local_viewport = sf::FloatRect(curstate.position.x / view_size.x, curstate.position.y / view_size.y, curstate.size.x / view_size.x, curstate.size.y / view_size.y);
680 	sf::FloatRect this_viewport = overlap(global_viewport, local_viewport);
681 	boxView.setViewport(this_viewport);
682 
683 	float line_height = 0;
684 	float cur_shift_x1 = curstate.margin, cur_shift_x2 = curstate.margin;
685 	float cur_shift_y = curstate.margin + curstate.scroll;
686 
687 	//update all the stuff inside the box
688 	for (auto &obj : objects)
689 	{
690 		Allign A = obj.get()->obj_allign;
691 		bool not_placed = true;
692 		int tries = 0;
693 		int obj_id = obj.get()->id;
694 		float obj_h = obj.get()->curstate.size.y;
695 		while (not_placed && tries < 2) //try to place the object somewhere
696 		{
697 			float space_left = defaultstate.size.x - cur_shift_x1 - cur_shift_x2;
698 			float obj_width = obj.get()->curstate.size.x;
699 
700 			if (space_left >= obj_width || space_left >= defaultstate.size.x - 2 * curstate.margin)
701 			{
702 				not_placed = false;
703 				switch (A)
704 				{
705 				case LEFT:
706 					obj.get()->SetPosition(curstate.position.x + cur_shift_x1, curstate.position.y + cur_shift_y);
707 					cur_shift_x1 += obj_width + curstate.margin;
708 					line_height = std::max(obj_h, line_height);
709 					break;
710 				case CENTER:
711 					obj.get()->SetPosition(curstate.position.x + defaultstate.size.x * 0.5f - obj_width * 0.5f, curstate.position.y + cur_shift_y);
712 					line_height = std::max(obj_h, line_height);
713 					cur_shift_y += line_height + curstate.margin;
714 					line_height = 0;
715 					cur_shift_x1 = curstate.margin;
716 					cur_shift_x2 = curstate.margin;
717 					break;
718 				case RIGHT:
719 					obj.get()->SetPosition(curstate.position.x + defaultstate.size.x - obj_width - cur_shift_x2, curstate.position.y + cur_shift_y);
720 					cur_shift_x2 += obj_width + curstate.margin;
721 					line_height = std::max(obj_h, line_height);
722 					break;
723 				}
724 			}
725 			else
726 			{
727 				cur_shift_y += line_height + curstate.margin;
728 				line_height = 0;
729 				cur_shift_x1 = curstate.margin;
730 				cur_shift_x2 = curstate.margin;
731 				tries++;
732 			}
733 
734 		}
735 		if (tries >= 2)
736 		{
737 			//ERROR_MSG("Object does not fit in the box.");
738 		}
739 		sf::FloatRect obj_box(obj.get()->curstate.position, obj.get()->curstate.size);
740 		sf::FloatRect seen_part = overlap(obj_box, this_view);
741 		//if the object is seen in the view, then update it
742 		if (seen_part.width > 0.f && seen_part.height > 0.f)
743 		{
744 			obj.get()->used_view = boxView;
745 			obj.get()->Update(window, state);
746 		}
747 
748 	}
749 
750 	cur_shift_y += line_height + curstate.margin;
751 
752 	this->SetInsideSize(cur_shift_y - curstate.scroll - curstate.margin);
753 
754 }
755 
Box(float x,float y,float dx,float dy,sf::Color color_main)756 Box::Box(float x, float y, float dx, float dy, sf::Color color_main): auto_size(false)
757 {
758 	defaultstate.position.x = x;
759 	defaultstate.position.y = y;
760 	defaultstate.size.x = dx;
761 	defaultstate.size.y = dy;
762 
763 	defaultstate.color_main = ToColorF(color_main);
764 	clone_states();
765 }
766 
Box(float dx,float dy,sf::Color color_main)767 Box::Box(float dx, float dy, sf::Color color_main) : auto_size(false)
768 {
769 	defaultstate.position.x = 0;
770 	defaultstate.position.y = 0;
771 	defaultstate.size.x = dx;
772 	defaultstate.size.y = dy;
773 	defaultstate.color_main = ToColorF(color_main);
774 	clone_states();
775 }
776 
Box()777 Box::Box() : auto_size(false)
778 { }
779 
Box(Box & A)780 Box::Box(Box & A)
781 {
782 	*this = A;
783 }
784 
Box(Box && A)785 Box::Box(Box && A)
786 {
787 	*this = A;
788 }
789 
SetAutoSize(bool b)790 void Box::SetAutoSize(bool b)
791 {
792 	auto_size = b;
793 }
794 
operator =(Box & A)795 void Box::operator=(Box & A)
796 {
797 	copy(A);
798 
799 	auto_size = A.auto_size;
800 	rect = A.rect;
801 	boxView = A.boxView;
802 	SetBackground(A.image);
803 }
804 
operator =(Box && A)805 void Box::operator=(Box && A)
806 {
807 	copy(A);
808 
809 	std::swap(auto_size, A.auto_size);
810 	std::swap(image, A.image);
811 	std::swap(rect, A.rect);
812 	std::swap(boxView, A.boxView);
813 }
814 
GetCopy()815 Object * Box::GetCopy()
816 {
817 	return static_cast<Object*>(new Box(*this));
818 }
819 
~Box()820 Box::~Box()
821 {
822 
823 }
824 
ColorFloat(float red,float green,float blue,float alpha)825 ColorFloat::ColorFloat(float red, float green, float blue, float alpha): r(red), g(green), b(blue), a(alpha)
826 {
827 
828 }
829 
operator =(sf::Color a)830 void ColorFloat::operator=(sf::Color a)
831 {
832 	*this = ToColorF(a);
833 }
834 
Draw(sf::RenderWindow * window,InputState & state)835 void Text::Draw(sf::RenderWindow * window, InputState& state)
836 {
837 	if (text.get() != nullptr)
838 	{
839 		text.get()->setPosition(curstate.position);
840 		text.get()->setCharacterSize(curstate.font_size);
841 		text.get()->setFillColor(ToColor(curstate.color_main));
842 		text.get()->setOutlineThickness(curstate.border_thickness);
843 		text.get()->setOutlineColor(ToColor(curstate.color_border));
844 		window->draw(*text.get());
845 		SetSize(text.get()->getLocalBounds().width, text.get()->getLocalBounds().height);
846 	}
847 }
848 
Text(sf::Text t)849 Text::Text(sf::Text t)
850 {
851 	text.reset(new sf::Text(t));
852 	defaultstate.font_size = t.getCharacterSize();
853 	defaultstate.color_main = t.getFillColor();
854 	clone_states();
855 }
856 
857 
Text(Text & A)858 Text::Text(Text & A)
859 {
860 	*this = A;
861 }
862 
Text(Text && A)863 Text::Text(Text && A)
864 {
865 	*this = A;
866 }
867 
operator =(Text & A)868 void Text::operator=(Text & A)
869 {
870 	copy(A);
871 	if (A.text.get() != nullptr)
872 	{
873 		text.reset(new sf::Text(*A.text.get()));
874 	}
875 }
876 
operator =(Text && A)877 void Text::operator=(Text && A)
878 {
879 	copy(A);
880 
881 	std::swap(text, A.text);
882 }
883 
GetCopy()884 Object * Text::GetCopy()
885 {
886 	return static_cast<Object*>(new Text(*this));
887 }
888 
Add(Object * something,Allign a)889 void Window::Add(Object* something, Allign a)
890 {
891 	objects[1].get()->AddObject(something, a);
892 }
893 
Window(Window & A)894 Window::Window(Window & A)
895 {
896 	*this = A;
897 }
898 
Window(Window && A)899 Window::Window(Window && A)
900 {
901 	*this = A;
902 }
903 
CreateCallbacks()904 void Window::CreateCallbacks()
905 {
906 	//use lambda funtion
907 	this->objects[0].get()->objects[1].get()->SetMainCallbackFunction([parent = this](sf::RenderWindow * window, InputState & state)
908 	{
909 		Add2DeleteQueue(parent->id);
910 	});
911 
912 	//delete callback
913 	this->SetMainDefaultFunction([parent = this](sf::RenderWindow * window, InputState & state)
914 	{
915 		if (state.key_press[sf::Keyboard::Escape] == true)
916 		{
917 			Add2DeleteQueue(parent->id);
918 			parent->action_time = action_dt;
919 		}
920 	});
921 
922 	//drag callback
923 	this->objects[0].get()->SetMainCallbackFunction([parent = this](sf::RenderWindow * window, InputState & state)
924 	{
925 		parent->Move(state.mouse_speed);
926 	}, false);
927 }
928 
operator =(Window & A)929 void Window::operator=(Window & A)
930 {
931 	Box::operator=(A);
932 	CreateCallbacks();
933 }
934 
operator =(Window && A)935 void Window::operator=(Window && A)
936 {
937 	Box::operator=(A);
938 	CreateCallbacks();
939 }
940 
GetCopy()941 Object * Window::GetCopy()
942 {
943 	return static_cast<Object*>(new Window(*this));
944 }
945 
InputState()946 InputState::InputState(): mouse_pos(sf::Vector2f(0,0)), mouse_speed(sf::Vector2f(0, 0))
947 {
948 	std::fill(keys, keys + sf::Keyboard::KeyCount - 1, false);
949 	std::fill(mouse, mouse + 2, false);
950 }
951 
InputState(bool a[sf::Keyboard::KeyCount],bool b[3],sf::Vector2f c,sf::Vector2f d)952 InputState::InputState(bool a[sf::Keyboard::KeyCount], bool b[3], sf::Vector2f c, sf::Vector2f d):
953 	mouse_pos(c), mouse_speed(d)
954 {
955 	std::copy(a, a + sf::Keyboard::KeyCount - 1, keys);
956 	std::copy(b, b + 2, mouse);
957 }
958 
AddObject(Object * something,Allign a)959 void MenuBox::AddObject(Object * something, Allign a)
960 {
961 	this->objects[0].get()->AddObject(something, a);
962 
963 	//update the slider
964 	float inside_size = this->objects[0].get()->defaultstate.inside_size;
965 	float height = this->objects[0].get()->defaultstate.size.y;
966 	float height_1 = height - 2 * this->objects[1].get()->defaultstate.margin;
967 	float new_h = std::min(height_1 * (height / inside_size), height_1);
968 	if (new_h == height_1 || auto_size)
969 	{
970 		//remove the slider
971 		this->objects[1].get()->SetWidth(0);
972 		this->objects[1].get()->objects[0].get()->SetWidth(0);
973 		this->objects[0].get()->SetWidth(this->defaultstate.size.x);
974 		this->objects[1].get()->SetHeigth(0);
975 	}
976 	else
977 	{
978 		this->objects[0].get()->SetWidth(this->defaultstate.size.x - 40);
979 		this->objects[1].get()->SetWidth(30);
980 		this->objects[1].get()->objects[0].get()->SetWidth(26);
981 		this->objects[1].get()->objects[0].get()->SetHeigth(new_h);
982 		this->objects[1].get()->SetHeigth(height);
983 	}
984 }
985 
Cursor(int d)986 void MenuBox::Cursor(int d)
987 {
988 	if (d == -1) // up
989 	{
990 		if (cursor_id > 0)
991 		{
992 			cursor_id--;
993 		}
994 	}
995 	else if(d == 1)
996 	{
997 		if (cursor_id < this->objects[0].get()->objects.size() - 1)
998 		{
999 			cursor_id++;
1000 		}
1001 	}
1002 	cursor = this->objects[0].get()->objects[cursor_id].get()->id;
1003 
1004 	//apply scroll to chosen object
1005 	float ybox = this->curstate.position.y;
1006 	float yobj = this->objects[0].get()->objects[cursor_id].get()->curstate.position.y;
1007 	float dy = yobj - ybox;
1008 	ScrollTo(dy);
1009 }
1010 
ScrollBy(float dx)1011 void MenuBox::ScrollBy(float dx)
1012 {
1013 	float inside_size = this->objects[0].get()->defaultstate.inside_size;
1014 	float cur_scroll = -this->objects[0].get()->defaultstate.scroll + dx;
1015 	float height_1 = this->objects[0].get()->defaultstate.size.y - 2 * this->objects[1].get()->defaultstate.margin;
1016 	float height_2 = this->objects[1].get()->objects[0].get()->defaultstate.size.y;
1017 	//only scroll within the appropriate range
1018 	if (cur_scroll <= inside_size - height_1 && cur_scroll >= 0 && inside_size > height_1)
1019 	{
1020 		this->objects[0].get()->ApplyScroll(-cur_scroll);
1021 		float max_slide_scroll = height_1 - height_2;
1022 		//relative scroll of the scroll button
1023 		float scroll_a = max_slide_scroll * cur_scroll / (inside_size - height_1);
1024 		this->objects[1].get()->SetScroll(scroll_a);
1025 	}
1026 }
1027 
ScrollTo(float scroll)1028 void MenuBox::ScrollTo(float scroll)
1029 {
1030 	float cur_scroll = this->objects[0].get()->defaultstate.scroll;
1031 	float ds = scroll - this->objects[0].get()->defaultstate.margin;
1032 	ScrollBy(ds);
1033 }
1034 
MenuBox(float dx,float dy,bool auto_y,float x,float y,sf::Color color_main)1035 MenuBox::MenuBox(float dx, float dy, bool auto_y, float x, float y, sf::Color color_main) : cursor_id(0)
1036 {
1037 	SetAutoSize(auto_y);
1038 	defaultstate.position.x = x;
1039 	defaultstate.position.y = y;
1040 	defaultstate.size.x = dx;
1041 	defaultstate.size.y = dy;
1042 	defaultstate.color_main = ToColorF(color_main);
1043 	clone_states();
1044 	float scroll_size = auto_y?0:30;
1045 	Box Inside(0, 0, dx - scroll_size, dy, sf::Color(100, 100, 100, 128)),
1046 		Scroll(0, 0, scroll_size, auto_y ? 0 : dy, sf::Color(150, 150, 150, 128)),
1047 		Scroll_Slide(0, 0, scroll_size-2, 60, sf::Color(255, 150, 0, 128));
1048 
1049 	Inside.SetAutoSize(auto_y);
1050 	Scroll_Slide.hoverstate.color_main = sf::Color(255, 50, 0, 128);
1051 	Scroll_Slide.activestate.color_main = sf::Color(255, 100, 100, 255);
1052 	Inside.SetBackgroundColor(sf::Color::Transparent);
1053 	Scroll.SetMargin(2);
1054 	Inside.SetMargin(12);
1055 	Scroll.AddObject(&Scroll_Slide, Box::CENTER);
1056 	this->Object::AddObject(&Inside, Box::LEFT);
1057 	this->Object::AddObject(&Scroll, Box::RIGHT);
1058 
1059 	CreateCallbacks();
1060 }
1061 
MenuBox(MenuBox & A)1062 MenuBox::MenuBox(MenuBox & A): cursor_id(0)
1063 {
1064 	*this = A;
1065 }
1066 
MenuBox(MenuBox && A)1067 MenuBox::MenuBox(MenuBox && A): cursor_id(0)
1068 {
1069 	*this = A;
1070 }
1071 
CreateCallbacks()1072 void MenuBox::CreateCallbacks()
1073 {
1074 	//use lambda funtion
1075 	this->objects[1].get()->objects[0].get()->SetMainCallbackFunction([parent = this](sf::RenderWindow * window, InputState & state)
1076 	{
1077 		float inside_size = parent->objects[0].get()->defaultstate.inside_size;
1078 		float height_1 = parent->objects[1].get()->defaultstate.size.y - 2 * parent->objects[1].get()->defaultstate.margin;
1079 		float height_2 = parent->objects[1].get()->objects[0].get()->defaultstate.size.y;
1080 		float max_slide_scroll = height_1 - height_2;
1081 		//relative scroll coefficient
1082 		float rel_coef = (inside_size - height_1) / max_slide_scroll;
1083 		parent->ScrollBy(state.mouse_speed.y*rel_coef);
1084 	}, false);
1085 
1086 	this->SetMainHoverFunction([parent = this](sf::RenderWindow * window, InputState & state)
1087 	{
1088 		//wheel scroll
1089 		if (state.wheel != 0.f)
1090 		{
1091 			float ds = 20.f;
1092 			parent->ScrollBy(-state.wheel*ds);
1093 		}
1094 	});
1095 
1096 	this->SetMainDefaultFunction([parent = this](sf::RenderWindow * window, InputState & state)
1097 	{
1098 		bool A = false;
1099 
1100 		if (state.keys[sf::Keyboard::Up])
1101 		{
1102 			parent->Cursor(-1);
1103 			A = 1;
1104 		}
1105 
1106 		if (state.keys[sf::Keyboard::Down])
1107 		{
1108 			parent->Cursor(1);
1109 			A = 1;
1110 		}
1111 
1112 		if (state.keys[sf::Keyboard::Return])
1113 		{
1114 			//run the callback function of the chosen object
1115 			A = parent->objects[0].get()->objects[parent->cursor_id].get()->RunCallback(window, state);
1116 		}
1117 
1118 		if (A) parent->action_time = action_dt;
1119 
1120 		A = false;
1121 
1122 		if (state.key_press[sf::Keyboard::Up])
1123 		{
1124 			parent->action_time = action_dt / 4;
1125 		}
1126 
1127 		if (state.key_press[sf::Keyboard::Down])
1128 		{
1129 			parent->action_time = action_dt / 4;
1130 		}
1131 	});
1132 }
1133 
operator =(MenuBox & A)1134 void MenuBox::operator=(MenuBox & A)
1135 {
1136 	Box::operator=(A);
1137 	CreateCallbacks();
1138 }
1139 
operator =(MenuBox && A)1140 void MenuBox::operator=(MenuBox && A)
1141 {
1142 	Box::operator=(A);
1143 	CreateCallbacks();
1144 }
1145 
GetCopy()1146 Object * MenuBox::GetCopy()
1147 {
1148 	return static_cast<Object*>(new MenuBox(*this));
1149 }
1150 
Button(Button & A)1151 Button::Button(Button & A)
1152 {
1153 	*this = A;
1154 }
1155 
Button(Button && A)1156 Button::Button(Button && A)
1157 {
1158 	*this = A;
1159 }
1160 
operator =(Button & A)1161 void Button::operator=(Button & A)
1162 {
1163 	Box::operator=(A);
1164 }
1165 
operator =(Button && A)1166 void Button::operator=(Button && A)
1167 {
1168 	Box::operator=(A);
1169 }
1170 
GetCopy()1171 Object * Button::GetCopy()
1172 {
1173 	return static_cast<Object*>(new Button(*this));
1174 }
1175 
~Button()1176 Button::~Button()
1177 {
1178 }
1179 
Image(sf::Texture image,float w,float h,sf::Color color_hover)1180 Image::Image(sf::Texture image, float w, float h, sf::Color color_hover)
1181 {
1182 	SetSize((w == 0) ? image.getSize().x : w, (h == 0) ? image.getSize().y : h);
1183 
1184 	SetBackgroundColor(sf::Color::White);
1185 	hoverstate.color_main = color_hover;
1186 
1187 	this->SetBackground(image);
1188 }
1189 
Image(std::string image_path,float w,float h,sf::Color color_hover)1190 Image::Image(std::string image_path, float w, float h, sf::Color color_hover)
1191 {
1192 	sf::Texture image;
1193 	image.loadFromFile(image_path);
1194 
1195 	SetSize((w == 0) ? image.getSize().x : w, (h == 0) ? image.getSize().y : h);
1196 	SetBackgroundColor(sf::Color::White);
1197 	hoverstate.color_main = color_hover;
1198 
1199 	this->SetBackground(image);
1200 }
1201 
Image(Image & A)1202 Image::Image(Image & A)
1203 {
1204 	*this = A;
1205 }
1206 
Image(Image && A)1207 Image::Image(Image && A)
1208 {
1209 	*this = A;
1210 }
1211 
operator =(Image & A)1212 void Image::operator=(Image & A)
1213 {
1214 	Box::operator=(A);
1215 }
1216 
operator =(Image && A)1217 void Image::operator=(Image && A)
1218 {
1219 	Box::operator=(A);
1220 }
1221 
GetCopy()1222 Object * Image::GetCopy()
1223 {
1224 	return static_cast<Object*>(new Image(*this));
1225 }
1226 
~Image()1227 Image::~Image()
1228 {
1229 }
1230 
KeyMapper(KeyMapper & A)1231 KeyMapper::KeyMapper(KeyMapper & A)
1232 {
1233 	*this = A;
1234 }
1235 
KeyMapper(KeyMapper && A)1236 KeyMapper::KeyMapper(KeyMapper && A)
1237 {
1238 	*this = A;
1239 }
1240 
operator =(KeyMapper & A)1241 void KeyMapper::operator=(KeyMapper & A)
1242 {
1243 	Box::operator=(A);
1244 	this_type = A.this_type;
1245 	key_ptr = A.key_ptr;
1246 	waiting = A.waiting;
1247 	wait_text = A.wait_text;
1248 	CreateCallbacks();
1249 }
1250 
operator =(KeyMapper && A)1251 void KeyMapper::operator=(KeyMapper && A)
1252 {
1253 	Box::operator=(A);
1254 	std::swap(this_type, A.this_type);
1255 	std::swap(key_ptr, A.key_ptr);
1256 	waiting = A.waiting;
1257 	wait_text = A.wait_text;
1258 	CreateCallbacks();
1259 }
1260 
CreateCallbacks()1261 void KeyMapper::CreateCallbacks()
1262 {
1263 	//use a lambda function
1264 	this->objects[1].get()->SetMainCallbackFunction([parent = this](sf::RenderWindow * window, InputState & state)
1265 	{
1266 		parent->waiting = true;
1267 		//get the text pointer out of the object pointer inside the parent
1268 		Text *text_ptr = static_cast<Text*>(parent->objects[1].get()->objects[0].get());
1269 		text_ptr->SetString(parent->wait_text);
1270 	});
1271 
1272 
1273 	this->SetMainDefaultFunction([parent = this](sf::RenderWindow * window, InputState & state)
1274 	{
1275 		if (parent->waiting)
1276 		{
1277 			if (state.key_press[sf::Keyboard::Escape])
1278 			{
1279 				parent->SetKeyString(); //exit
1280 			}
1281 			else switch (parent->this_type)
1282 			{
1283 			case KEYBOARD:
1284 				if (state.isKeyPressed)
1285 				{
1286 					//search for the pressed key
1287 					for (sf::Keyboard::Key i = sf::Keyboard::A; i < sf::Keyboard::KeyCount; i = sf::Keyboard::Key(i + 1))
1288 					{
1289 						if (state.keys[i]) //found
1290 						{
1291 							*(parent->key_ptr) = i;
1292 							parent->SetKeyString();
1293 							break;
1294 						}
1295 					}
1296 				}
1297 				break;
1298 			case JOYSTICK_AXIS:
1299 				//search for the axis
1300 				for (int i = 0; i < sf::Joystick::AxisCount; i++)
1301 				{
1302 					if (abs(state.axis_value[i]) > 0.5f  && state.axis_moved[i])
1303 					{
1304 						*(parent->key_ptr) = i;
1305 						parent->SetKeyString();
1306 						break;
1307 					}
1308 				}
1309 				break;
1310 			case JOYSTICK_KEYS:
1311 				//search for the pressed joystick key
1312 				for (int i = 0; i < sf::Joystick::ButtonCount; i++)
1313 				{
1314 					if (state.button_pressed[i])
1315 					{
1316 						*(parent->key_ptr) = i;
1317 						parent->SetKeyString();
1318 						break;
1319 					}
1320 				}
1321 
1322 				break;
1323 			}
1324 		}
1325 	});
1326 }
1327 
SetKeyString()1328 void KeyMapper::SetKeyString()
1329 {
1330 	Text *text_ptr = static_cast<Text*>(objects[1].get()->objects[0].get());
1331 	waiting = false;
1332 	sf::Keyboard::Key key = sf::Keyboard::Key(*key_ptr);
1333 	switch (this_type)
1334 	{
1335 	case KEYBOARD:
1336 		text_ptr->SetString(key_name(key));
1337 		break;
1338 	case JOYSTICK_AXIS:
1339 		text_ptr->SetString("Axis " + num2str(*key_ptr));
1340 		break;
1341 	case JOYSTICK_KEYS:
1342 		text_ptr->SetString("Key " + num2str(*key_ptr));
1343 		break;
1344 	}
1345 }
1346 
GetCopy()1347 Object * KeyMapper::GetCopy()
1348 {
1349 	return static_cast<Object*>(new KeyMapper(*this));
1350 }
1351