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