1 #include "gui2_element.h"
2 #include "main.h"
3 
GuiElement(GuiContainer * owner,const string & id)4 GuiElement::GuiElement(GuiContainer* owner, const string& id)
5 : position_alignment(ATopLeft), owner(owner), rect(0, 0, 0, 0), visible(true), enabled(true), hover(false), focus(false), active(false), id(id)
6 {
7     owner->elements.push_back(this);
8     destroyed = false;
9 }
10 
~GuiElement()11 GuiElement::~GuiElement()
12 {
13     if (owner)
14     {
15         LOG(ERROR) << "GuiElement was destroyed while it still had an owner...";
16     }
17 }
18 
onMouseDown(sf::Vector2f position)19 bool GuiElement::onMouseDown(sf::Vector2f position)
20 {
21     return false;
22 }
23 
onMouseDrag(sf::Vector2f position)24 void GuiElement::onMouseDrag(sf::Vector2f position)
25 {
26 }
27 
onMouseUp(sf::Vector2f position)28 void GuiElement::onMouseUp(sf::Vector2f position)
29 {
30 }
31 
onKey(sf::Event::KeyEvent key,int unicode)32 bool GuiElement::onKey(sf::Event::KeyEvent key, int unicode)
33 {
34     return false;
35 }
36 
onHotkey(const HotkeyResult & key)37 void GuiElement::onHotkey(const HotkeyResult& key)
38 {
39 }
40 
onJoystickAxis(const AxisAction & axisAction)41 bool GuiElement::onJoystickAxis(const AxisAction& axisAction)
42 {
43     return false;
44 }
45 
setSize(sf::Vector2f size)46 GuiElement* GuiElement::setSize(sf::Vector2f size)
47 {
48     this->size = size;
49     return this;
50 }
51 
setSize(float x,float y)52 GuiElement* GuiElement::setSize(float x, float y)
53 {
54     this->size.x = x;
55     this->size.y = y;
56     return this;
57 }
58 
getSize() const59 sf::Vector2f GuiElement::getSize() const
60 {
61     return size;
62 }
63 
setMargins(float n)64 GuiElement* GuiElement::setMargins(float n)
65 {
66     margins.left = margins.top = margins.width = margins.height = n;
67     return this;
68 }
69 
setMargins(float x,float y)70 GuiElement* GuiElement::setMargins(float x, float y)
71 {
72     margins.left = margins.width = x;
73     margins.top = margins.height = y;
74     return this;
75 }
76 
setMargins(float left,float top,float right,float bottom)77 GuiElement* GuiElement::setMargins(float left, float top, float right, float bottom)
78 {
79     margins.left = left;
80     margins.top = top;
81     margins.width = right;
82     margins.height = bottom;
83     return this;
84 }
85 
setPosition(float x,float y,EGuiAlign alignment)86 GuiElement* GuiElement::setPosition(float x, float y, EGuiAlign alignment)
87 {
88     this->position.x = x;
89     this->position.y = y;
90     this->position_alignment = alignment;
91     return this;
92 }
93 
setPosition(sf::Vector2f position,EGuiAlign alignment)94 GuiElement* GuiElement::setPosition(sf::Vector2f position, EGuiAlign alignment)
95 {
96     this->position = position;
97     this->position_alignment = alignment;
98     return this;
99 }
100 
getPositionOffset() const101 sf::Vector2f GuiElement::getPositionOffset() const
102 {
103     return position;
104 }
105 
setVisible(bool visible)106 GuiElement* GuiElement::setVisible(bool visible)
107 {
108     this->visible = visible;
109     return this;
110 }
111 
hide()112 GuiElement* GuiElement::hide()
113 {
114     setVisible(false);
115     return this;
116 }
117 
show()118 GuiElement* GuiElement::show()
119 {
120     setVisible(true);
121     return this;
122 }
123 
isVisible() const124 bool GuiElement::isVisible() const
125 {
126     return visible;
127 }
128 
setEnable(bool enable)129 GuiElement* GuiElement::setEnable(bool enable)
130 {
131     this->enabled = enable;
132     return this;
133 }
134 
enable()135 GuiElement* GuiElement::enable()
136 {
137     setEnable(true);
138     return this;
139 }
140 
disable()141 GuiElement* GuiElement::disable()
142 {
143     setEnable(false);
144     return this;
145 }
146 
isEnabled() const147 bool GuiElement::isEnabled() const
148 {
149     return enabled;
150 }
151 
setActive(bool active)152 GuiElement* GuiElement::setActive(bool active)
153 {
154     this->active = active;
155     return this;
156 }
157 
isActive() const158 bool GuiElement::isActive() const
159 {
160     return active;
161 }
162 
moveToFront()163 void GuiElement::moveToFront()
164 {
165     if (owner)
166     {
167         owner->elements.remove(this);
168         owner->elements.push_back(this);
169     }
170 }
171 
moveToBack()172 void GuiElement::moveToBack()
173 {
174     if (owner)
175     {
176         owner->elements.remove(this);
177         owner->elements.push_front(this);
178     }
179 }
180 
getCenterPoint() const181 sf::Vector2f GuiElement::getCenterPoint() const
182 {
183     return sf::Vector2f(rect.left + rect.width / 2.0, rect.top + rect.height / 2.0);
184 }
185 
getOwner()186 GuiContainer* GuiElement::getOwner()
187 {
188     return owner;
189 }
190 
getTopLevelContainer()191 GuiContainer* GuiElement::getTopLevelContainer()
192 {
193     GuiContainer* top_level = owner;
194     while(dynamic_cast<GuiElement*>(top_level) != nullptr)
195         top_level = dynamic_cast<GuiElement*>(top_level)->getOwner();
196     return top_level;
197 }
198 
destroy()199 void GuiElement::destroy()
200 {
201     destroyed = true;
202 }
203 
isDestroyed()204 bool GuiElement::isDestroyed()
205 {
206     return destroyed;
207 }
208 
updateRect(sf::FloatRect parent_rect)209 void GuiElement::updateRect(sf::FloatRect parent_rect)
210 {
211     sf::Vector2f local_size = size;
212     if (local_size.x == GuiSizeMax)
213         local_size.x = parent_rect.width - fabs(position.x);
214     if (local_size.y == GuiSizeMax)
215         local_size.y = parent_rect.height - fabs(position.y);
216 
217     if (local_size.x == GuiSizeMatchHeight)
218         local_size.x = local_size.y;
219     if (local_size.y == GuiSizeMatchWidth)
220         local_size.y = local_size.x;
221 
222     local_size.x -= margins.width + margins.left;
223     local_size.y -= margins.height + margins.top;
224 
225     switch(position_alignment)
226     {
227     case ATopLeft:
228     case ACenterLeft:
229     case ABottomLeft:
230         rect.left = parent_rect.left + position.x + margins.left;
231         break;
232     case ATopCenter:
233     case ACenter:
234     case ABottomCenter:
235         rect.left = parent_rect.left + parent_rect.width / 2.0 + position.x - local_size.x / 2.0;
236         break;
237     case ATopRight:
238     case ACenterRight:
239     case ABottomRight:
240         rect.left = parent_rect.left + parent_rect.width + position.x - local_size.x - margins.width;
241         break;
242     }
243 
244     switch(position_alignment)
245     {
246     case ATopLeft:
247     case ATopRight:
248     case ATopCenter:
249         rect.top = parent_rect.top + position.y + margins.top;
250         break;
251     case ACenterLeft:
252     case ACenterRight:
253     case ACenter:
254         rect.top = parent_rect.top + parent_rect.height / 2.0 + position.y - local_size.y / 2.0;
255         break;
256     case ABottomLeft:
257     case ABottomRight:
258     case ABottomCenter:
259         rect.top = parent_rect.top + parent_rect.height + position.y - local_size.y - margins.height;
260         break;
261     }
262 
263     rect.width = local_size.x;
264     rect.height = local_size.y;
265     if (rect.width < 0)
266     {
267         rect.left += rect.width;
268         rect.width = -rect.width;
269     }
270     if (rect.height < 0)
271     {
272         rect.top += rect.height;
273         rect.height = -rect.height;
274     }
275 }
276 
277 [[nodiscard]]
adjustRenderTexture(sf::RenderTexture & texture)278 bool GuiElement::adjustRenderTexture(sf::RenderTexture& texture)
279 {
280 #ifdef SFML_SYSTEM_ANDROID
281     /* On GL ES systems, SFML runs on assumptions regarding
282     the available GL extensions, for instance considering packed depth/stencil is never available.[1]
283     Because of that unreliability, just forego render textures on those systems.
284 
285       [1]: https://github.com/SFML/SFML/blob/2f11710abc5aa478503a7ff3f9e654bd2078ebab/src/SFML/Graphics/GLExtensions.hpp#L128
286     */
287     return false;
288 #else
289     auto success = true;
290     P<WindowManager> window_manager = engine->getObject("windowManager");
291 
292     //Hack the rectangle for this element so it sits perfectly on pixel boundaries.
293     auto pixel_coords = window_manager->mapCoordsToPixel(sf::Vector2f(rect.width, rect.height));
294 
295     sf::Vector2u texture_size{ static_cast<uint32_t>(pixel_coords.x), static_cast<uint32_t>(pixel_coords.y) };
296     if (texture.getSize() != texture_size)
297     {
298         sf::ContextSettings settings{};
299         settings.stencilBits = 8;
300         success = texture.create(texture_size.x, texture_size.y, settings);
301     }
302 
303     if (success)
304     {
305         //Set the view so it covers this elements normal rect. So we can draw exactly the same on this texture as no the normal screen.
306         texture.setView(sf::View{ rect });
307     }
308 
309     return success;
310 #endif
311 }
312 
drawRenderTexture(sf::RenderTexture & texture,sf::RenderTarget & window,sf::Color color,const sf::RenderStates & states)313 void GuiElement::drawRenderTexture(sf::RenderTexture& texture, sf::RenderTarget& window, sf::Color color, const sf::RenderStates& states)
314 {
315     texture.display();
316 
317     sf::Sprite sprite(texture.getTexture());
318 
319     sprite.setColor(color);
320     sprite.setPosition(rect.left, rect.top);
321 
322     const auto& texture_size = texture.getSize();
323     const auto& texture_viewport = texture.getView().getViewport();
324     sprite.setScale(rect.width / float(texture_size.x * texture_viewport.width), rect.height / float(texture_size.y * texture_viewport.height));
325 
326     window.draw(sprite, states);
327 }
328 
drawText(sf::RenderTarget & window,sf::FloatRect rect,const string & text,EGuiAlign align,float font_size,sf::Font * font,sf::Color color)329 void GuiElement::drawText(sf::RenderTarget& window, sf::FloatRect rect, const string& text, EGuiAlign align, float font_size, sf::Font* font, sf::Color color)
330 {
331     sf::Text textElement(sf::String::fromUtf8(std::begin(text), std::end(text)), *font, font_size);
332     float y = 0;
333     float x = 0;
334 
335     //The "base line" of the text draw is the "Y position where the text is drawn" + font_size.
336     //The height of normal text is 70% of the font_size.
337     //So use those properties to align the text. Depending on the localbounds does not work.
338     switch(align)
339     {
340     case ATopLeft:
341     case ATopRight:
342     case ATopCenter:
343         y = rect.top - 0.3 * font_size;
344         break;
345     case ABottomLeft:
346     case ABottomRight:
347     case ABottomCenter:
348         y = rect.top + rect.height - font_size;
349         break;
350     case ACenterLeft:
351     case ACenterRight:
352     case ACenter:
353         y = rect.top + rect.height / 2.0 - font_size + font_size * 0.35;
354         break;
355     }
356 
357     switch(align)
358     {
359     case ATopLeft:
360     case ABottomLeft:
361     case ACenterLeft:
362         x = rect.left - textElement.getLocalBounds().left;
363         break;
364     case ATopRight:
365     case ABottomRight:
366     case ACenterRight:
367         x = rect.left + rect.width - textElement.getLocalBounds().width - textElement.getLocalBounds().left;
368         break;
369     case ATopCenter:
370     case ABottomCenter:
371     case ACenter:
372         x = rect.left + rect.width / 2.0 - textElement.getLocalBounds().width / 2.0 - textElement.getLocalBounds().left;
373         break;
374     }
375     textElement.setPosition(x, y);
376     textElement.setColor(color);
377     window.draw(textElement);
378 }
379 
drawVerticalText(sf::RenderTarget & window,sf::FloatRect rect,const string & text,EGuiAlign align,float font_size,sf::Font * font,sf::Color color)380 void GuiElement::drawVerticalText(sf::RenderTarget& window, sf::FloatRect rect, const string& text, EGuiAlign align, float font_size, sf::Font* font, sf::Color color)
381 {
382     sf::Text textElement(sf::String::fromUtf8(std::begin(text), std::end(text)), *font, font_size);
383     textElement.setRotation(-90);
384     float x = 0;
385     float y = 0;
386     x = rect.left + rect.width / 2.0 - textElement.getLocalBounds().height / 2.0 - textElement.getLocalBounds().top;
387     switch(align)
388     {
389     case ATopLeft:
390     case ABottomLeft:
391     case ACenterLeft:
392         y = rect.top + rect.height;
393         break;
394     case ATopRight:
395     case ABottomRight:
396     case ACenterRight:
397         y = rect.top + textElement.getLocalBounds().left + textElement.getLocalBounds().width;
398         break;
399     case ATopCenter:
400     case ABottomCenter:
401     case ACenter:
402         y = rect.top + rect.height / 2.0 + textElement.getLocalBounds().width / 2.0 + textElement.getLocalBounds().left;
403         break;
404     }
405     textElement.setPosition(x, y);
406     textElement.setColor(color);
407     window.draw(textElement);
408 }
409 
draw9Cut(sf::RenderTarget & window,sf::FloatRect rect,const string & texture,sf::Color color,float width_factor)410 void GuiElement::draw9Cut(sf::RenderTarget& window, sf::FloatRect rect, const string& texture, sf::Color color, float width_factor)
411 {
412     sf::Sprite sprite;
413     textureManager.setTexture(sprite, texture);
414     sf::IntRect textureSize = sprite.getTextureRect();
415     int cornerSizeT = textureSize.height / 3;
416     float cornerSizeR = cornerSizeT;
417     float scale = 1.0;
418     if (cornerSizeT > rect.height / 2)
419     {
420         scale = float(rect.height / 2) / cornerSizeR;
421         sprite.setScale(scale, scale);
422         cornerSizeR *= scale;
423     }else if (cornerSizeT > rect.width / 2)
424     {
425         scale = float(rect.width / 2) / cornerSizeR;
426         sprite.setScale(scale, scale);
427         cornerSizeR *= scale;
428     }
429 
430     sprite.setColor(color);
431     sprite.setOrigin(0, 0);
432 
433     float w = 1.0;
434     if (cornerSizeR > rect.width * width_factor)
435         w = rect.width * width_factor / cornerSizeR;
436 
437     //TopLeft
438     sprite.setPosition(rect.left, rect.top);
439     sprite.setTextureRect(sf::IntRect(0, 0, cornerSizeT * w, cornerSizeT));
440     window.draw(sprite);
441     //BottomLeft
442     sprite.setPosition(rect.left, rect.top + rect.height - cornerSizeR);
443     sprite.setTextureRect(sf::IntRect(0, textureSize.height - cornerSizeT, cornerSizeT * w, cornerSizeT));
444     window.draw(sprite);
445 
446     if (rect.height > cornerSizeR * 2)
447     {
448         //left
449         sprite.setPosition(rect.left, rect.top + cornerSizeR);
450         sprite.setTextureRect(sf::IntRect(0, cornerSizeT, cornerSizeT * w, 1));
451         sprite.setScale(scale, rect.height - cornerSizeR*2);
452         window.draw(sprite);
453         sprite.setScale(scale, scale);
454     }
455     if (w < 1.0)
456         return;
457 
458     if (rect.width - cornerSizeR > rect.width * width_factor)
459         w = (width_factor - cornerSizeR / rect.width) * (rect.width / (rect.width - cornerSizeR * 2));
460 
461     if (rect.width > cornerSizeR * 2)
462     {
463         //Top
464         sprite.setPosition(rect.left + cornerSizeR, rect.top);
465         sprite.setTextureRect(sf::IntRect(cornerSizeT, 0, textureSize.width - cornerSizeT * 2, cornerSizeT));
466         sprite.setScale((rect.width - cornerSizeR*2) / float(textureSize.width - cornerSizeT * 2) * w, scale);
467         window.draw(sprite);
468         //Bottom
469         sprite.setPosition(rect.left + cornerSizeR, rect.top + rect.height - cornerSizeR);
470         sprite.setTextureRect(sf::IntRect(cornerSizeT, textureSize.height - cornerSizeT, textureSize.width - cornerSizeT * 2, cornerSizeT));
471         sprite.setScale((rect.width - cornerSizeR*2) / float(textureSize.width - cornerSizeT * 2) * w, scale);
472         window.draw(sprite);
473         sprite.setScale(scale, scale);
474     }
475 
476     if (rect.width > cornerSizeR * 2 && rect.height > cornerSizeR * 2)
477     {
478         //Center
479         sprite.setPosition(rect.left + cornerSizeR, rect.top + cornerSizeR);
480         sprite.setTextureRect(sf::IntRect(cornerSizeT, cornerSizeT, 1, 1));
481         sprite.setScale((rect.width - cornerSizeR*2) * w, rect.height - cornerSizeR*2);
482         window.draw(sprite);
483         sprite.setScale(scale, scale);
484     }
485     if (w < 1.0)
486         return;
487     if (width_factor < 1.0)
488         w = (width_factor - (rect.width - cornerSizeR) / rect.width) * (rect.width / cornerSizeR);
489 
490     //TopRight
491     sprite.setPosition(rect.left + rect.width - cornerSizeR, rect.top);
492     sprite.setTextureRect(sf::IntRect(textureSize.width - cornerSizeT, 0, cornerSizeT * w, cornerSizeT));
493     window.draw(sprite);
494     //BottomRight
495     sprite.setPosition(rect.left + rect.width - cornerSizeR, rect.top + rect.height - cornerSizeR);
496     sprite.setTextureRect(sf::IntRect(textureSize.width - cornerSizeT, textureSize.height - cornerSizeT, cornerSizeT * w, cornerSizeT));
497     window.draw(sprite);
498 
499     if (rect.height > cornerSizeR * 2)
500     {
501         //Right
502         sprite.setPosition(rect.left + rect.width - cornerSizeR, rect.top + cornerSizeR);
503         sprite.setTextureRect(sf::IntRect(textureSize.width - cornerSizeT, cornerSizeT, cornerSizeT * w, 1));
504         sprite.setScale(scale, rect.height - cornerSizeR*2);
505         window.draw(sprite);
506     }
507 }
508 
draw9CutV(sf::RenderTarget & window,sf::FloatRect rect,const string & texture,sf::Color color,float height_factor)509 void GuiElement::draw9CutV(sf::RenderTarget& window, sf::FloatRect rect, const string& texture, sf::Color color, float height_factor)
510 {
511     sf::Sprite sprite;
512     textureManager.setTexture(sprite, texture);
513     sf::IntRect textureSize = sprite.getTextureRect();
514     int cornerSizeT = textureSize.height / 3;
515     float cornerSizeR = cornerSizeT;
516     float scale = 1.0;
517     if (cornerSizeT > rect.height / 2)
518     {
519         scale = float(rect.height / 2) / cornerSizeR;
520         sprite.setScale(scale, scale);
521         cornerSizeR *= scale;
522     }else if (cornerSizeT > rect.width / 2)
523     {
524         scale = float(rect.width / 2) / cornerSizeR;
525         sprite.setScale(scale, scale);
526         cornerSizeR *= scale;
527     }
528 
529     sprite.setColor(color);
530     sprite.setOrigin(0, 0);
531 
532     float h = 1.0;
533     if (cornerSizeR > rect.height * height_factor)
534         h = rect.height * height_factor / cornerSizeR;
535 
536     //BottomLeft
537     sprite.setPosition(rect.left, rect.top + rect.height - cornerSizeR * h);
538     sprite.setTextureRect(sf::IntRect(0, textureSize.height - cornerSizeT * h, cornerSizeT, cornerSizeT * h));
539     window.draw(sprite);
540     //BottomRight
541     sprite.setPosition(rect.left + rect.width - cornerSizeR, rect.top + rect.height - cornerSizeR * h);
542     sprite.setTextureRect(sf::IntRect(textureSize.width - cornerSizeT, textureSize.height - cornerSizeT * h, cornerSizeT, cornerSizeT * h));
543     window.draw(sprite);
544 
545     if (rect.width > cornerSizeR * 2)
546     {
547         //Bottom
548         sprite.setPosition(rect.left + cornerSizeR, rect.top + rect.height - cornerSizeR * h);
549         sprite.setTextureRect(sf::IntRect(cornerSizeT, textureSize.height - cornerSizeT * h, textureSize.width - cornerSizeT * 2, cornerSizeT * h));
550         sprite.setScale((rect.width - cornerSizeR*2) / float(textureSize.width - cornerSizeT * 2), scale);
551         window.draw(sprite);
552         sprite.setScale(scale, scale);
553     }
554 
555     if (h < 1.0)
556         return;
557 
558     if (rect.height - cornerSizeR > rect.height * height_factor)
559         h = (height_factor - cornerSizeR / rect.height) * (rect.height / (rect.height - cornerSizeR * 2));
560 
561     if (rect.height > cornerSizeR * 2)
562     {
563         //left
564         sprite.setPosition(rect.left, rect.top + cornerSizeR + (rect.height - cornerSizeR * 2) * (1.0f - h));
565         sprite.setTextureRect(sf::IntRect(0, cornerSizeT, cornerSizeT, 1));
566         sprite.setScale(scale, (rect.height - cornerSizeR*2) * h);
567         window.draw(sprite);
568         sprite.setScale(scale, scale);
569         //Right
570         sprite.setPosition(rect.left + rect.width - cornerSizeR, rect.top + cornerSizeR + (rect.height - cornerSizeR * 2) * (1.0f - h));
571         sprite.setTextureRect(sf::IntRect(textureSize.width - cornerSizeT, cornerSizeT, cornerSizeT, 1));
572         sprite.setScale(scale, (rect.height - cornerSizeR*2) * h);
573         window.draw(sprite);
574     }
575 
576     if (rect.width > cornerSizeR * 2 && rect.height > cornerSizeR * 2)
577     {
578         //Center
579         sprite.setPosition(rect.left + cornerSizeR, rect.top + cornerSizeR + (rect.height - cornerSizeR * 2) * (1.0f - h));
580         sprite.setTextureRect(sf::IntRect(cornerSizeT, cornerSizeT, 1, 1));
581         sprite.setScale(rect.width - cornerSizeR*2, (rect.height - cornerSizeR*2) * h);
582         window.draw(sprite);
583         sprite.setScale(scale, scale);
584     }
585 
586     if (h < 1.0)
587         return;
588     if (height_factor < 1.0)
589         h = (height_factor - (rect.height - cornerSizeR) / rect.height) * (rect.height / cornerSizeR);
590 
591     //TopLeft
592     sprite.setPosition(rect.left, rect.top + cornerSizeR * (1.0 - h));
593     sprite.setTextureRect(sf::IntRect(0, cornerSizeT * (1.0 - h), cornerSizeT, cornerSizeT * h));
594     window.draw(sprite);
595     //TopRight
596     sprite.setPosition(rect.left + rect.width - cornerSizeR, rect.top + cornerSizeR * (1.0 - h));
597     sprite.setTextureRect(sf::IntRect(textureSize.width - cornerSizeT, cornerSizeT * (1.0 - h), cornerSizeT, cornerSizeT * h));
598     window.draw(sprite);
599 
600     if (rect.height > cornerSizeR * 2)
601     {
602         //Top
603         sprite.setPosition(rect.left + cornerSizeR, rect.top + cornerSizeR * (1.0 - h));
604         sprite.setTextureRect(sf::IntRect(cornerSizeT, cornerSizeT * (1.0 - h), 1, cornerSizeT * h));
605         sprite.setScale(rect.width - cornerSizeR*2, scale);
606         window.draw(sprite);
607     }
608 }
609 
drawStretched(sf::RenderTarget & window,sf::FloatRect rect,const string & texture,sf::Color color)610 void GuiElement::drawStretched(sf::RenderTarget& window, sf::FloatRect rect, const string& texture, sf::Color color)
611 {
612     if (rect.width >= rect.height)
613     {
614         drawStretchedH(window, rect, texture, color);
615     }else{
616         drawStretchedV(window, rect, texture, color);
617     }
618 }
619 
drawStretchedH(sf::RenderTarget & window,sf::FloatRect rect,const string & texture,sf::Color color)620 void GuiElement::drawStretchedH(sf::RenderTarget& window, sf::FloatRect rect, const string& texture, sf::Color color)
621 {
622     sf::Texture* texture_ptr = textureManager.getTexture(texture);
623     sf::Vector2f texture_size = sf::Vector2f(texture_ptr->getSize());
624     sf::VertexArray a(sf::TrianglesStrip, 8);
625 
626     float w = rect.height / 2.0f;
627     if (w * 2 > rect.width)
628         w = rect.width / 2.0f;
629     a[0].position = sf::Vector2f(rect.left, rect.top);
630     a[1].position = sf::Vector2f(rect.left, rect.top + rect.height);
631     a[2].position = sf::Vector2f(rect.left + w, rect.top);
632     a[3].position = sf::Vector2f(rect.left + w, rect.top + rect.height);
633     a[4].position = sf::Vector2f(rect.left + rect.width - w, rect.top);
634     a[5].position = sf::Vector2f(rect.left + rect.width - w, rect.top + rect.height);
635     a[6].position = sf::Vector2f(rect.left + rect.width, rect.top);
636     a[7].position = sf::Vector2f(rect.left + rect.width, rect.top + rect.height);
637 
638     a[0].texCoords = sf::Vector2f(0, 0);
639     a[1].texCoords = sf::Vector2f(0, texture_size.y);
640     a[2].texCoords = sf::Vector2f(texture_size.x / 2, 0);
641     a[3].texCoords = sf::Vector2f(texture_size.x / 2, texture_size.y);
642     a[4].texCoords = sf::Vector2f(texture_size.x / 2, 0);
643     a[5].texCoords = sf::Vector2f(texture_size.x / 2, texture_size.y);
644     a[6].texCoords = sf::Vector2f(texture_size.x, 0);
645     a[7].texCoords = sf::Vector2f(texture_size.x, texture_size.y);
646 
647     for(int n=0; n<8; n++)
648         a[n].color = color;
649 
650     window.draw(a, texture_ptr);
651 }
652 
drawStretchedV(sf::RenderTarget & window,sf::FloatRect rect,const string & texture,sf::Color color)653 void GuiElement::drawStretchedV(sf::RenderTarget& window, sf::FloatRect rect, const string& texture, sf::Color color)
654 {
655     sf::Texture* texture_ptr = textureManager.getTexture(texture);
656     sf::Vector2f texture_size = sf::Vector2f(texture_ptr->getSize());
657     sf::VertexArray a(sf::TrianglesStrip, 8);
658 
659     float h = rect.width / 2.0;
660     if (h * 2 > rect.height)
661         h = rect.height / 2.0f;
662     a[0].position = sf::Vector2f(rect.left, rect.top);
663     a[1].position = sf::Vector2f(rect.left + rect.width, rect.top);
664     a[2].position = sf::Vector2f(rect.left, rect.top + h);
665     a[3].position = sf::Vector2f(rect.left + rect.width, rect.top + h);
666     a[4].position = sf::Vector2f(rect.left, rect.top + rect.height - h);
667     a[5].position = sf::Vector2f(rect.left + rect.width, rect.top + rect.height - h);
668     a[6].position = sf::Vector2f(rect.left, rect.top + rect.height);
669     a[7].position = sf::Vector2f(rect.left + rect.width, rect.top + rect.height);
670 
671     a[0].texCoords = sf::Vector2f(0, 0);
672     a[1].texCoords = sf::Vector2f(0, texture_size.y);
673     a[2].texCoords = sf::Vector2f(texture_size.x / 2, 0);
674     a[3].texCoords = sf::Vector2f(texture_size.x / 2, texture_size.y);
675     a[4].texCoords = sf::Vector2f(texture_size.x / 2, 0);
676     a[5].texCoords = sf::Vector2f(texture_size.x / 2, texture_size.y);
677     a[6].texCoords = sf::Vector2f(texture_size.x, 0);
678     a[7].texCoords = sf::Vector2f(texture_size.x, texture_size.y);
679 
680     for(int n=0; n<8; n++)
681         a[n].color = color;
682 
683     window.draw(a, texture_ptr);
684 }
685 
drawStretchedHV(sf::RenderTarget & window,sf::FloatRect rect,float corner_size,const string & texture,sf::Color color)686 void GuiElement::drawStretchedHV(sf::RenderTarget& window, sf::FloatRect rect, float corner_size, const string& texture, sf::Color color)
687 {
688     sf::Texture* texture_ptr = textureManager.getTexture(texture);
689     sf::Vector2f texture_size = sf::Vector2f(texture_ptr->getSize());
690     sf::VertexArray a(sf::TrianglesStrip, 8);
691 
692     for(int n=0; n<8; n++)
693         a[n].color = color;
694 
695     corner_size = std::min(corner_size, rect.height / 2.0f);
696     corner_size = std::min(corner_size, rect.width / 2.0f);
697 
698     a[0].position = sf::Vector2f(rect.left, rect.top);
699     a[1].position = sf::Vector2f(rect.left, rect.top + corner_size);
700     a[2].position = sf::Vector2f(rect.left + corner_size, rect.top);
701     a[3].position = sf::Vector2f(rect.left + corner_size, rect.top + corner_size);
702     a[4].position = sf::Vector2f(rect.left + rect.width - corner_size, rect.top);
703     a[5].position = sf::Vector2f(rect.left + rect.width - corner_size, rect.top + corner_size);
704     a[6].position = sf::Vector2f(rect.left + rect.width, rect.top);
705     a[7].position = sf::Vector2f(rect.left + rect.width, rect.top + corner_size);
706 
707     a[0].texCoords = sf::Vector2f(0, 0);
708     a[1].texCoords = sf::Vector2f(0, texture_size.y / 2.0);
709     a[2].texCoords = sf::Vector2f(texture_size.x / 2, 0);
710     a[3].texCoords = sf::Vector2f(texture_size.x / 2, texture_size.y / 2.0);
711     a[4].texCoords = sf::Vector2f(texture_size.x / 2, 0);
712     a[5].texCoords = sf::Vector2f(texture_size.x / 2, texture_size.y / 2.0);
713     a[6].texCoords = sf::Vector2f(texture_size.x, 0);
714     a[7].texCoords = sf::Vector2f(texture_size.x, texture_size.y / 2.0);
715 
716     window.draw(a, texture_ptr);
717 
718     a[0].position.y = rect.top + rect.height - corner_size;
719     a[2].position.y = rect.top + rect.height - corner_size;
720     a[4].position.y = rect.top + rect.height - corner_size;
721     a[6].position.y = rect.top + rect.height - corner_size;
722 
723     a[0].texCoords.y = texture_size.y / 2.0;
724     a[2].texCoords.y = texture_size.y / 2.0;
725     a[4].texCoords.y = texture_size.y / 2.0;
726     a[6].texCoords.y = texture_size.y / 2.0;
727 
728     window.draw(a, texture_ptr);
729 
730     a[1].position.y = rect.top + rect.height;
731     a[3].position.y = rect.top + rect.height;
732     a[5].position.y = rect.top + rect.height;
733     a[7].position.y = rect.top + rect.height;
734 
735     a[1].texCoords.y = texture_size.y;
736     a[3].texCoords.y = texture_size.y;
737     a[5].texCoords.y = texture_size.y;
738     a[7].texCoords.y = texture_size.y;
739 
740     window.draw(a, texture_ptr);
741 }
742 
drawArrow(sf::RenderTarget & window,sf::FloatRect rect,sf::Color color,float rotation)743 void GuiElement::drawArrow(sf::RenderTarget& window, sf::FloatRect rect, sf::Color color, float rotation)
744 {
745     sf::Sprite arrow;
746     textureManager.setTexture(arrow, "gui/SelectorArrow");
747     arrow.setPosition(rect.left + rect.width / 2.0, rect.top + rect.height / 2.0);
748     float f = rect.height / float(arrow.getTextureRect().height);
749     arrow.setScale(f, f);
750     arrow.setRotation(rotation);
751     arrow.setColor(color);
752     window.draw(arrow);
753 }
754 
selectColor(ColorSet & color_set) const755 sf::Color GuiElement::selectColor(ColorSet& color_set) const
756 {
757     if (!enabled)
758         return color_set.disabled;
759     if (active)
760         return color_set.active;
761     if (hover)
762         return color_set.hover;
763     if (focus)
764         return color_set.focus;
765     return color_set.normal;
766 }
767 
doLineWrap(const string & text,float font_size,float width)768 GuiElement::LineWrapResult GuiElement::doLineWrap(const string& text, float font_size, float width)
769 {
770     LineWrapResult result;
771     result.text = text;
772     result.line_count = 1;
773     {
774         float currentOffset = 0;
775         bool first_word = true;
776         std::size_t wordBegining = 0;
777 
778         for (std::size_t pos(0); pos < result.text.length(); ++pos)
779         {
780             char currentChar = result.text[pos];
781             if (currentChar == '\n')
782             {
783                 currentOffset = 0;
784                 first_word = true;
785                 result.line_count += 1;
786                 continue;
787             }
788             else if (currentChar == ' ')
789             {
790                 wordBegining = pos;
791                 first_word = false;
792             }
793 
794             sf::Glyph glyph = main_font->getGlyph(currentChar, font_size, false);
795             currentOffset += glyph.advance;
796 
797             if (!first_word && currentOffset > width)
798             {
799                 pos = wordBegining;
800                 result.text[pos] = '\n';
801                 first_word = true;
802                 currentOffset = 0;
803                 result.line_count += 1;
804             }
805         }
806     }
807     return result;
808 }
809