1 /* --------------------------------------------------------------------
2 EXTREME TUXRACER
3
4 Copyright (C) 1999-2001 Jasmin F. Patry (Tuxracer)
5 Copyright (C) 2010 Extreme Tux Racer Team
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 ---------------------------------------------------------------------*/
17
18 #ifdef HAVE_CONFIG_H
19 #include <etr_config.h>
20 #endif
21
22 #include "gui.h"
23 #include "textures.h"
24 #include "font.h"
25 #include "ogl.h"
26 #include "winsys.h"
27 #include <vector>
28
29
30 #define CURSOR_SIZE 10
31
32 static std::vector<TWidget*> Widgets;
33 static int lock_focussed = -1;
34 static int focussed = -1;
35 static bool locked_LR = false;
36 static bool locked_UD = false;
37
AddWidget(TWidget * widget)38 static TWidget* AddWidget(TWidget* widget) {
39 if (Widgets.size() == focussed) {
40 widget->focus = true;
41 widget->Focussed();
42 }
43 Widgets.push_back(widget);
44 return widget;
45 }
46
Inside(int x,int y,const TRect & Rect)47 static bool Inside(int x, int y, const TRect& Rect) {
48 return (x >= Rect.left
49 && x <= Rect.left + Rect.width
50 && y >= Rect.top
51 && y <= Rect.top + Rect.height);
52 }
53
TWidget(int x,int y,int width,int height,bool interactive_)54 TWidget::TWidget(int x, int y, int width, int height, bool interactive_)
55 : active(true)
56 , visible(true)
57 , interactive(interactive_)
58 , focus(false) {
59 mouseRect.top = y;
60 mouseRect.left = x;
61 mouseRect.height = height;
62 mouseRect.width = width;
63 position.x = x;
64 position.y = y;
65 }
66
Click(int x,int y)67 bool TWidget::Click(int x, int y) {
68 return active && visible && Inside(x, y, mouseRect);
69 }
70
MouseMove(int x,int y)71 void TWidget::MouseMove(int x, int y) {
72 bool ofocus = focus;
73 focus = interactive && active && visible && Inside(x, y, mouseRect);
74 if (ofocus != focus)
75 Focussed();
76 }
77
78
TLabel(const sf::String & string,int x,int y,const sf::Color & color)79 TLabel::TLabel(const sf::String& string, int x, int y, const sf::Color& color)
80 : TWidget(x, y, 0, 0, false)
81 , text(string, FT.getCurrentFont(), FT.GetSize()) {
82 if (x == CENTER)
83 text.setPosition((Winsys.resolution.width - text.getLocalBounds().width) / 2, y);
84 else
85 text.setPosition(x, y);
86 text.setFillColor(color);
87 text.setOutlineColor(color);
88 }
89
Focussed(bool masterFocus)90 void TLabel::Focussed(bool masterFocus) {
91 focus = masterFocus && active;
92 if (focus) {
93 text.setFillColor(colDYell);
94 text.setOutlineColor(colDYell);
95 } else {
96 text.setFillColor(colWhite);
97 text.setOutlineColor(colWhite);
98 }
99 }
100
Draw() const101 void TLabel::Draw() const {
102 Winsys.draw(text);
103 }
104
GetSize() const105 sf::Vector2f TLabel::GetSize() const {
106 return sf::Vector2f(text.getLocalBounds().width, text.getLocalBounds().height);
107
108 }
109
AddLabel(const sf::String & string,int x,int y,const sf::Color & color)110 TLabel* AddLabel(const sf::String& string, int x, int y, const sf::Color& color) {
111 return static_cast<TLabel*>(AddWidget(new TLabel(string, x, y, color)));
112 }
113
114
TFramedText(int x,int y,int width,int height,int line,const sf::Color & backcol,const sf::String & string,unsigned int ftsize,bool borderFocus_)115 TFramedText::TFramedText(int x, int y, int width, int height, int line, const sf::Color& backcol, const sf::String& string, unsigned int ftsize, bool borderFocus_)
116 : TWidget(x, y, width, height, false)
117 , frame(sf::Vector2f(width - line * 2, height - line * 2))
118 , text(string, FT.getCurrentFont(), ftsize)
119 , borderFocus(borderFocus_) {
120 text.setPosition(x + line + 20, y + line);
121 if (!borderFocus) {
122 text.setFillColor(colWhite);
123 text.setOutlineColor(colWhite);
124 } else {
125 text.setFillColor(colDYell);
126 text.setOutlineColor(colDYell);
127 }
128 frame.setPosition(x + line, y + line);
129 frame.setOutlineThickness(line);
130 frame.setFillColor(backcol);
131 frame.setOutlineColor(colWhite);
132 }
133
Activated()134 void TFramedText::Activated() {
135 if (!active) {
136 text.setFillColor(colLGrey);
137 text.setOutlineColor(colLGrey);
138 } else if (borderFocus || focus) {
139 text.setFillColor(colDYell);
140 text.setOutlineColor(colDYell);
141 } else {
142 text.setFillColor(colWhite);
143 text.setOutlineColor(colWhite);
144 }
145 }
146
Focussed(bool masterFocus)147 void TFramedText::Focussed(bool masterFocus) {
148 focus = masterFocus && active;
149 if (focus) {
150 frame.setOutlineColor(colDYell);
151 if (!borderFocus) {
152 text.setFillColor(colDYell);
153 text.setOutlineColor(colDYell);
154 }
155 } else {
156 frame.setOutlineColor(colWhite);
157 if (!borderFocus) {
158 text.setFillColor(colWhite);
159 text.setOutlineColor(colWhite);
160 }
161 }
162 }
163
Draw() const164 void TFramedText::Draw() const {
165 Winsys.draw(frame);
166 Winsys.draw(text);
167 }
168
AddFramedText(int x,int y,int width,int height,int line,const sf::Color & backcol,const sf::String & text,unsigned int ftsize,bool borderFocus)169 TFramedText* AddFramedText(int x, int y, int width, int height, int line, const sf::Color& backcol, const sf::String& text, unsigned int ftsize, bool borderFocus) {
170 return static_cast<TFramedText*>(AddWidget(new TFramedText(x, y, width, height, line, backcol, text, ftsize, borderFocus)));
171 }
172
TTextButton(int x,int y,const sf::String & text_,int ftsize)173 TTextButton::TTextButton(int x, int y, const sf::String& text_, int ftsize)
174 : TWidget(x, y, 0, 0)
175 , text(text_, FT.getCurrentFont(), ftsize) {
176 if (ftsize < 0) text.setCharacterSize(FT.AutoSizeN(4));
177
178 int len = text.getLocalBounds().width;
179 if (x == CENTER) position.x = (Winsys.resolution.width - len) / 2;
180 text.setPosition(position.x, position.y);
181 int offs = ftsize / 5;
182 mouseRect.left = position.x-20;
183 mouseRect.top = position.y+offs;
184 mouseRect.width = len+40;
185 mouseRect.height = ftsize+offs;
186 }
187
Focussed()188 void TTextButton::Focussed() {
189 if (focus) {
190 text.setFillColor(colDYell);
191 text.setOutlineColor(colDYell);
192 } else {
193 text.setFillColor(colWhite);
194 text.setOutlineColor(colWhite);
195 }
196 }
197
Draw() const198 void TTextButton::Draw() const {
199 Winsys.draw(text);
200 }
201
AddTextButton(const sf::String & text,int x,int y,int ftsize)202 TTextButton* AddTextButton(const sf::String& text, int x, int y, int ftsize) {
203 return static_cast<TTextButton*>(AddWidget(new TTextButton(x, y, text, ftsize)));
204 }
205
AddTextButtonN(const sf::String & text,int x,int y,int rel_ftsize)206 TTextButton* AddTextButtonN(const sf::String& text, int x, int y, int rel_ftsize) {
207 unsigned int siz = FT.AutoSizeN(rel_ftsize);
208 return AddTextButton(text, x, y, siz);
209 }
210
211
TTextField(int x,int y,int width,int height,const sf::String & text_)212 TTextField::TTextField(int x, int y, int width, int height, const sf::String& text_)
213 : TWidget(x, y, width, height)
214 , text(text_, FT.getCurrentFont(), FT.AutoSizeN(5))
215 , frame(sf::Vector2f(width-6.f, height-6.f))
216 , cursorShape(sf::Vector2f(2.f, 30.f * Winsys.scale))
217 , maxLng(32)
218 , time(0.0)
219 , cursor(false) {
220 text.setPosition(mouseRect.left + 20, mouseRect.top);
221 cursorShape.setFillColor(colYellow);
222 frame.setPosition(x + 3, y + 3);
223 frame.setOutlineThickness(3);
224 frame.setFillColor(colMBackgr);
225 frame.setOutlineColor(colWhite);
226 SetCursorPos(0);
227 }
228
Draw() const229 void TTextField::Draw() const {
230 Winsys.draw(frame);
231 Winsys.draw(text);
232 if (cursor && focus)
233 Winsys.draw(cursorShape);
234 }
235
TextEnter(char c)236 void TTextField::TextEnter(char c) {
237 if (c != '\b') {
238 sf::String string = text.getString();
239 string.insert(cursorPos, c);
240 text.setString(string);
241 SetCursorPos(cursorPos+1);
242 }
243 }
244
SetCursorPos(std::size_t new_pos)245 void TTextField::SetCursorPos(std::size_t new_pos) {
246 cursorPos = new_pos;
247 cursorShape.setPosition(text.findCharacterPos(cursorPos).x, mouseRect.top + 9);
248 }
249
Focussed()250 void TTextField::Focussed() {
251 if (focus) {
252 text.setFillColor(colDYell);
253 text.setOutlineColor(colDYell);
254 frame.setOutlineColor(colDYell);
255 } else {
256 text.setFillColor(colWhite);
257 text.setOutlineColor(colWhite);
258 frame.setOutlineColor(colWhite);
259 }
260 }
261
Click(int x,int y)262 bool TTextField::Click(int x, int y) {
263 if (TWidget::Click(x, y)) {
264 cursorPos = 0;
265 float first = text.findCharacterPos(cursorPos).x;
266 for (;;) {
267 float second = text.findCharacterPos(cursorPos + 1).x;
268 if ((first + second) / 2.f >= x || cursorPos >= text.getString().getSize())
269 break;
270 cursorPos++;
271 first = second;
272 }
273 cursorShape.setPosition(text.findCharacterPos(cursorPos).x, mouseRect.top + 9);
274 return true;
275 }
276 return false;
277 }
278
eraseFromText(sf::Text & text,std::size_t pos)279 static void eraseFromText(sf::Text& text, std::size_t pos) {
280 sf::String str = text.getString();
281 str.erase(pos, 1);
282 text.setString(str);
283 }
Key(sf::Keyboard::Key key,bool released)284 void TTextField::Key(sf::Keyboard::Key key, bool released) {
285 switch (key) {
286 case sf::Keyboard::Delete:
287 if (cursorPos < text.getString().getSize()) eraseFromText(text, cursorPos);
288 break;
289 case sf::Keyboard::BackSpace:
290 if (cursorPos > 0) { eraseFromText(text, cursorPos-1); SetCursorPos(cursorPos - 1); }
291 break;
292 case sf::Keyboard::Right:
293 if (cursorPos < text.getString().getSize()) SetCursorPos(cursorPos + 1);
294 break;
295 case sf::Keyboard::Left:
296 if (cursorPos > 0) SetCursorPos(cursorPos - 1);
297 break;
298 case sf::Keyboard::Home:
299 SetCursorPos(0);
300 break;
301 case sf::Keyboard::End:
302 SetCursorPos(text.getString().getSize());
303 break;
304 default:
305 break;
306 }
307 }
308
UpdateCursor(float timestep)309 void TTextField::UpdateCursor(float timestep) {
310 time += timestep;
311 if (time > CRSR_PERIODE) {
312 time = 0;
313 cursor = !cursor;
314 }
315 }
316
AddTextField(const sf::String & text,int x,int y,int width,int height)317 TTextField* AddTextField(const sf::String& text, int x, int y, int width, int height) {
318 locked_LR = true;
319 return static_cast<TTextField*>(AddWidget(new TTextField(x, y, width, height, text)));
320 }
321
TCheckbox(int x,int y,int width,const sf::String & tag_)322 TCheckbox::TCheckbox(int x, int y, int width, const sf::String& tag_)
323 : TWidget(x, y, 32 * Winsys.scale / 0.8f, 32 * Winsys.scale / 0.8f)
324 , text(tag_, FT.getCurrentFont(), FT.GetSize())
325 , back(Tex.GetSFTexture(CHECKBOX))
326 , checkmark(Tex.GetSFTexture(CHECKMARK_SMALL))
327 , checked(false) {
328 text.setPosition(x, y);
329 back.setPosition(x + width - 32, y);
330 checkmark.setPosition(x + width - 32, y);
331 mouseRect.left = x + width - 32;
332 back.setScale(Winsys.scale / 0.8f, Winsys.scale / 0.8f);
333 checkmark.setScale(Winsys.scale / 0.8f, Winsys.scale / 0.8f);
334 }
335
SetPosition(int x,int y)336 void TCheckbox::SetPosition(int x, int y) {
337 text.setPosition(x, y);
338 back.setPosition(x, y);
339 checkmark.setPosition(x, y);
340 }
341
Focussed()342 void TCheckbox::Focussed() {
343 if (focus) {
344 text.setFillColor(colDYell);
345 text.setOutlineColor(colDYell);
346 } else {
347 text.setFillColor(colWhite);
348 text.setOutlineColor(colWhite);
349 }
350 }
351
Draw() const352 void TCheckbox::Draw() const {
353 Winsys.draw(back);
354 if (checked)
355 Winsys.draw(checkmark);
356 Winsys.draw(text);
357 }
358
Click(int x,int y)359 bool TCheckbox::Click(int x, int y) {
360 if (active && visible && Inside(x, y, mouseRect)) {
361 checked = !checked;
362 return true;
363 }
364 return false;
365 }
366
Key(sf::Keyboard::Key key,bool released)367 void TCheckbox::Key(sf::Keyboard::Key key, bool released) {
368 if (released) return;
369
370 if (key == sf::Keyboard::Space || key == sf::Keyboard::Return) {
371 checked = !checked;
372 }
373 }
374
AddCheckbox(int x,int y,int width,const sf::String & tag)375 TCheckbox* AddCheckbox(int x, int y, int width, const sf::String& tag) {
376 return static_cast<TCheckbox*>(AddWidget(new TCheckbox(x, y, width, tag)));
377 }
378
TIconButton(int x,int y,const sf::Texture & texture,float size_,int max_,int value_)379 TIconButton::TIconButton(int x, int y, const sf::Texture& texture, float size_, int max_, int value_)
380 : TWidget(x, y, 32, 32)
381 , sprite(texture)
382 , frame(sf::Vector2f(size_, size_))
383 , size(size_)
384 , maximum(max_)
385 , value(value_) {
386 sprite.setScale(size / (texture.getSize().x / 2.f), size / (texture.getSize().y / 2.f));
387 sprite.setPosition(x, y);
388 frame.setPosition(x, y);
389 frame.setOutlineColor(colWhite);
390 frame.setOutlineThickness(3.f);
391 SetValue(value_);
392 }
393
SetValue(int _value)394 void TIconButton::SetValue(int _value) {
395 value = _value;
396 if (value > maximum)
397 value = 0;
398 else if (value < 0)
399 value = maximum;
400
401 sf::Vector2u texSize = sprite.getTexture()->getSize();
402 switch (value) {
403 case 0:
404 sprite.setTextureRect(sf::IntRect(0, 0, texSize.x / 2, texSize.y / 2));
405 break;
406 case 1:
407 sprite.setTextureRect(sf::IntRect(texSize.x / 2, 0, texSize.x / 2, texSize.y / 2));
408 break;
409 case 2:
410 sprite.setTextureRect(sf::IntRect(0, texSize.y / 2, texSize.x / 2, texSize.y / 2));
411 break;
412 case 3:
413 sprite.setTextureRect(sf::IntRect(texSize.x / 2, texSize.y / 2, texSize.x / 2, texSize.y / 2));
414 break;
415 }
416 }
417
Draw() const418 void TIconButton::Draw() const {
419 Winsys.draw(frame);
420 Winsys.draw(sprite);
421 }
422
Focussed()423 void TIconButton::Focussed() {
424 if (focus)
425 frame.setOutlineColor(colDYell);
426 else
427 frame.setOutlineColor(colWhite);
428 }
429
Click(int x,int y)430 bool TIconButton::Click(int x, int y) {
431 if (Inside(x, y, mouseRect)) {
432 SetValue(value + 1);
433 return true;
434 }
435 return false;
436 }
437
Key(sf::Keyboard::Key key,bool released)438 void TIconButton::Key(sf::Keyboard::Key key, bool released) {
439 if (released) return;
440
441 if (key == sf::Keyboard::Down) { // Arrow down/left
442 SetValue(value - 1);
443 } else if (key == sf::Keyboard::Up) { // Arrow up/right
444 SetValue(value + 1);
445 }
446 }
447
AddIconButton(int x,int y,const sf::Texture & texture,float size,int maximum,int value)448 TIconButton* AddIconButton(int x, int y, const sf::Texture& texture, float size, int maximum, int value) {
449 locked_UD = true;
450 return static_cast<TIconButton*>(AddWidget(new TIconButton(x, y, texture, size, maximum, value)));
451 }
452
TArrow(int x,int y,bool down_)453 TArrow::TArrow(int x, int y, bool down_)
454 : TWidget(x, y, 32 * Winsys.scale / 0.8f, 16 * Winsys.scale / 0.8f)
455 , sprite(Tex.GetSFTexture(LB_ARROWS))
456 , down(down_) {
457 sprite.setPosition(x, y);
458 sprite.setScale(Winsys.scale / 0.8f, Winsys.scale / 0.8f);
459
460 SetTexture();
461 }
462
Focussed()463 void TArrow::Focussed() {
464 SetTexture();
465 }
466
Activated()467 void TArrow::Activated() {
468 SetTexture();
469 }
470
SetTexture()471 void TArrow::SetTexture() {
472 static const float textl[6] = { 0.5f, 0.f, 0.5f, 0.5f, 0.f, 0.5f };
473 static const float texbr[6] = { 0.5f, 0.5f, 0.f, 0.75f, 0.75f, 0.25f };
474
475 int type = 0;
476 if (active)
477 type = 1;
478 if (focus)
479 type++;
480 if (down)
481 type += 3;
482
483 sf::Vector2u texSize = sprite.getTexture()->getSize();
484 sprite.setTextureRect(sf::IntRect(textl[type] * texSize.x, texbr[type] * texSize.y, texSize.x / 2, texSize.y / 4));
485 }
486
Draw() const487 void TArrow::Draw() const {
488 Winsys.draw(sprite);
489 }
490
AddArrow(int x,int y,bool down)491 TArrow* AddArrow(int x, int y, bool down) {
492 return static_cast<TArrow*>(AddWidget(new TArrow(x, y, down)));
493 }
494
495
TUpDown(int x,int y,int min_,int max_,int value_,int distance,bool swapArrows_)496 TUpDown::TUpDown(int x, int y, int min_, int max_, int value_, int distance, bool swapArrows_)
497 : TWidget(x, y, 32 * Winsys.scale / 0.8f, (32 + distance)*Winsys.scale / 0.8f)
498 , up(x, y + (16 + distance)*Winsys.scale / 0.8f, true)
499 , down(x, y, false)
500 , higher(swapArrows_ ? up : down)
501 , lower(swapArrows_ ? down : up)
502 , value(value_)
503 , minimum(min_)
504 , maximum(max_)
505 , swapArrows(swapArrows_) {
506 lower.SetActive(value < maximum);
507 higher.SetActive(value > minimum);
508 }
509
Draw() const510 void TUpDown::Draw() const {
511 up.Draw();
512 down.Draw();
513 }
514
Click(int x,int y)515 bool TUpDown::Click(int x, int y) {
516 if (active && visible && lower.Click(x, y)) {
517 value++;
518 higher.SetActive(true);
519 if (value == maximum)
520 lower.SetActive(false);
521 return true;
522 }
523 if (active && visible && higher.Click(x, y)) {
524 lower.SetActive(true);
525 value--;
526 if (value == minimum)
527 down.SetActive(false);
528 return true;
529 }
530 return false;
531 }
532
Key(sf::Keyboard::Key key,bool released)533 void TUpDown::Key(sf::Keyboard::Key key, bool released) {
534 if (released) return;
535
536 if ((!swapArrows && key == sf::Keyboard::Up) || (swapArrows && key == sf::Keyboard::Down)) { // Arrow up
537 if (value > minimum) {
538 value--;
539 lower.SetActive(true);
540 if (value == minimum)
541 higher.SetActive(false);
542 }
543 } else if ((!swapArrows && key == sf::Keyboard::Down) || (swapArrows && key == sf::Keyboard::Up)) { // Arrow down
544 if (value < maximum) {
545 value++;
546 higher.SetActive(true);
547 if (value == maximum)
548 lower.SetActive(false);
549 }
550 }
551 }
552
MouseMove(int x,int y)553 void TUpDown::MouseMove(int x, int y) {
554 bool ofocus = focus;
555 focus = active && visible && Inside(x, y, mouseRect);
556 if (ofocus != focus)
557 Focussed();
558 up.MouseMove(x, y);
559 down.MouseMove(x, y);
560 }
561
SetValue(int value_)562 void TUpDown::SetValue(int value_) {
563 value = clamp(minimum, value_, maximum);
564 lower.SetActive(value < maximum);
565 higher.SetActive(value > minimum);
566 }
SetMinimum(int min_)567 void TUpDown::SetMinimum(int min_) {
568 minimum = min_;
569 value = clamp(minimum, value, maximum);
570 lower.SetActive(value < maximum);
571 higher.SetActive(value > minimum);
572 }
SetMaximum(int max_)573 void TUpDown::SetMaximum(int max_) {
574 maximum = max_;
575 value = clamp(minimum, value, maximum);
576 lower.SetActive(value < maximum);
577 higher.SetActive(value > minimum);
578 }
579
AddUpDown(int x,int y,int minimum,int maximum,int value,int distance,bool swapArrows)580 TUpDown* AddUpDown(int x, int y, int minimum, int maximum, int value, int distance, bool swapArrows) {
581 locked_UD = true;
582 return static_cast<TUpDown*>(AddWidget(new TUpDown(x, y, minimum, maximum, value, distance, swapArrows)));
583 }
584
585 // ------------------ Elementary drawing ---------------------------------------------
586
DrawFrameX(int x,int y,int w,int h,int line,const sf::Color & backcol,const sf::Color & framecol,float transp)587 void DrawFrameX(int x, int y, int w, int h, int line, const sf::Color& backcol, const sf::Color& framecol, float transp) {
588 x += line;
589 y += line;
590 w -= line * 2;
591 h -= line * 2;
592 sf::RectangleShape shape(sf::Vector2f(w, h));
593 shape.setPosition(x, y);
594 shape.setOutlineThickness(line);
595 shape.setFillColor(sf::Color(backcol.r, backcol.g, backcol.b, backcol.a * transp));
596 shape.setOutlineColor(sf::Color(framecol.r, framecol.g, framecol.b, framecol.a * transp));
597 Winsys.draw(shape);
598 }
599
DrawBonusExt(int y,std::size_t numraces,std::size_t num)600 void DrawBonusExt(int y, std::size_t numraces, std::size_t num) {
601 std::size_t maxtux = numraces * 3;
602 if (num > maxtux) return;
603
604 static const sf::Color col2(115, 166, 217);
605
606 int lleft[3];
607
608 int framewidth = (int)numraces * 40 + 8;
609 int totalwidth = framewidth * 3 + 8;
610 int xleft = (Winsys.resolution.width - totalwidth) / 2;
611 lleft[0] = xleft;
612 lleft[1] = xleft + framewidth + 4;
613 lleft[2] = xleft + framewidth + framewidth + 8;
614
615 DrawFrameX(lleft[0], y, framewidth, 40, 1, col2, colBlack, 1);
616 DrawFrameX(lleft[1], y, framewidth, 40, 1, col2, colBlack, 1);
617 DrawFrameX(lleft[2], y, framewidth, 40, 1, col2, colBlack, 1);
618
619 static sf::Sprite tuxbonus(Tex.GetSFTexture(TUXBONUS));
620 sf::Vector2u size = tuxbonus.getTexture()->getSize();
621 tuxbonus.setTextureRect(sf::IntRect(0, 0, size.x, size.y/2));
622
623 for (std::size_t i=0; i<maxtux; i++) {
624 std::size_t majr = (i/numraces);
625 std::size_t minr = i - majr * numraces;
626 if (majr > 2) majr = 2;
627 int x = lleft[majr] + (int)minr * 40 + 6;
628
629 if (i<num) {
630 tuxbonus.setPosition(x, y + 4);
631 Winsys.draw(tuxbonus);
632 }
633 }
634 }
635
DrawGUIFrame()636 void DrawGUIFrame() {
637 static sf::Sprite bottom_left(Tex.GetSFTexture(BOTTOM_LEFT));
638 static sf::Sprite bottom_right(Tex.GetSFTexture(BOTTOM_RIGHT));
639 static sf::Sprite top_left(Tex.GetSFTexture(TOP_LEFT));
640 static sf::Sprite top_right(Tex.GetSFTexture(TOP_RIGHT));
641
642 bottom_left.setPosition(0, Winsys.resolution.height - bottom_left.getTexture()->getSize().y);
643 bottom_right.setPosition(Winsys.resolution.width - bottom_right.getTexture()->getSize().x, Winsys.resolution.height - bottom_right.getTexture()->getSize().y);
644 top_right.setPosition(Winsys.resolution.width - top_right.getTexture()->getSize().x, 0);
645
646 Winsys.draw(bottom_left);
647 Winsys.draw(bottom_right);
648 Winsys.draw(top_left);
649 Winsys.draw(top_right);
650 }
651
DrawGUIBackground(float scale)652 void DrawGUIBackground(float scale) {
653 DrawGUIFrame();
654
655 static sf::Sprite logo(Tex.GetSFTexture(T_TITLE));
656 scale *= 0.5f;
657 logo.setScale(scale, scale);
658 logo.setPosition((Winsys.resolution.width - logo.getTextureRect().width*scale)/2, 5);
659 Winsys.draw(logo);
660 }
661
DrawCursor()662 void DrawCursor() {
663 static sf::Sprite s(Tex.GetSFTexture(MOUSECURSOR));
664 static bool init = false;
665 if (!init) {
666 s.setScale((double) Winsys.resolution.width / 1400, (double) Winsys.resolution.width / 1400);
667 init = true;
668 }
669 s.setPosition(cursor_pos.x, cursor_pos.y);
670 Winsys.draw(s);
671 }
672
673
674 // ------------------ Main GUI functions ---------------------------------------------
675
DrawGUI()676 void DrawGUI() {
677 for (std::size_t i = 0; i < Widgets.size(); i++)
678 if (Widgets[i]->GetVisible())
679 Widgets[i]->Draw();
680 if (param.ice_cursor)
681 DrawCursor();
682 }
683
ClickGUI(int x,int y)684 TWidget* ClickGUI(int x, int y) {
685 TWidget* clicked = nullptr;
686 for (std::size_t i = 0; i < Widgets.size(); i++) {
687 if (Widgets[i]->Click(x, y)) {
688 clicked = Widgets[i];
689 lock_focussed = focussed;
690 }
691 }
692 return clicked;
693 }
694
MouseMoveGUI(int x,int y)695 TWidget* MouseMoveGUI(int x, int y) {
696 if (x != 0 || y != 0) {
697 focussed = -1;
698 for (std::size_t i = 0; i < Widgets.size(); i++) {
699 Widgets[i]->MouseMove(cursor_pos.x, cursor_pos.y);
700 if (Widgets[i]->focussed())
701 focussed = (int)i;
702 }
703 }
704 if (focussed == -1) {
705 focussed = lock_focussed;
706 if (focussed != -1) {
707 Widgets[focussed]->focus = true;
708 Widgets[focussed]->Focussed();
709 }
710 return 0;
711 }
712
713 return Widgets[focussed];
714 }
715
KeyGUI(sf::Keyboard::Key key,bool released)716 TWidget* KeyGUI(sf::Keyboard::Key key, bool released) {
717 if (!released) {
718 switch (key) {
719 case sf::Keyboard::Tab:
720 if (sf::Keyboard::isKeyPressed(sf::Keyboard::LShift) || sf::Keyboard::isKeyPressed(sf::Keyboard::RShift))
721 DecreaseFocus();
722 else
723 IncreaseFocus();
724 break;
725 case sf::Keyboard::Up:
726 if (!locked_UD)
727 DecreaseFocus();
728 break;
729 case sf::Keyboard::Left:
730 if (!locked_LR)
731 DecreaseFocus();
732 break;
733 case sf::Keyboard::Down:
734 if (!locked_UD)
735 IncreaseFocus();
736 break;
737 case sf::Keyboard::Right:
738 if (!locked_LR)
739 IncreaseFocus();
740 break;
741 default:
742 break;
743 }
744 }
745 if (focussed == -1)
746 return 0;
747 Widgets[focussed]->Key(key, released);
748 return Widgets[focussed];
749 }
750
TextEnterGUI(char text)751 TWidget* TextEnterGUI(char text) {
752 if (focussed == -1)
753 return 0;
754 Widgets[focussed]->TextEnter(text);
755 return Widgets[focussed];
756 }
757
SetFocus(TWidget * widget)758 void SetFocus(TWidget* widget) {
759 if (!widget)
760 focussed = -1;
761 else
762 for (std::size_t i = 0; i < Widgets.size(); i++) {
763 if (Widgets[i] == widget) {
764 Widgets[i]->focus = true;
765 Widgets[i]->Focussed();
766 focussed = (int)i;
767 break;
768 } else if (Widgets[i]->focus) {
769 Widgets[i]->focus = false;
770 Widgets[i]->Focussed();
771 }
772 }
773 }
774
IncreaseFocus()775 void IncreaseFocus() {
776 if (focussed >= 0) {
777 Widgets[focussed]->focus = false;
778 Widgets[focussed]->Focussed();
779 }
780
781 focussed++;
782 if (focussed >= (int)Widgets.size())
783 focussed = 0;
784 int end = focussed;
785 // Select only active widgets
786 do {
787 if (Widgets[focussed]->GetActive() && Widgets[focussed]->GetInteractive())
788 break;
789
790 focussed++;
791 if (focussed >= (int)Widgets.size())
792 focussed = 0;
793 } while (end != focussed);
794
795 if (focussed >= 0) {
796 Widgets[focussed]->focus = true;
797 Widgets[focussed]->Focussed();
798 }
799 lock_focussed = focussed;
800 }
DecreaseFocus()801 void DecreaseFocus() {
802 if (focussed >= 0) {
803 Widgets[focussed]->focus = false;
804 Widgets[focussed]->Focussed();
805 }
806
807 if (focussed > 0)
808 focussed--;
809 else
810 focussed = (int)Widgets.size()-1;
811 int end = focussed;
812 // Select only active widgets
813 do {
814 if (Widgets[focussed]->GetActive() && Widgets[focussed]->GetInteractive())
815 break;
816
817 if (focussed > 0)
818 focussed--;
819 else
820 focussed = (int)Widgets.size()-1;
821 } while (end != focussed);
822
823 if (focussed >= 0) {
824 Widgets[focussed]->focus = true;
825 Widgets[focussed]->Focussed();
826 }
827 lock_focussed = focussed;
828 }
829
ResetGUI()830 void ResetGUI() {
831 for (std::size_t i = 0; i < Widgets.size(); i++)
832 delete Widgets[i];
833 Widgets.clear();
834 focussed = 0;
835 lock_focussed = -1;
836 locked_LR = locked_UD = false;
837 }
838
839 // ---------------------------------------------------------------
840
AutoYPosN(int percent)841 int AutoYPosN(int percent) {
842 return Winsys.resolution.height * percent / 100;
843 }
844
AutoAreaN(int top_perc,int bott_perc,unsigned int w)845 TArea AutoAreaN(int top_perc, int bott_perc, unsigned int w) {
846 TArea res;
847 res.top = AutoYPosN(top_perc);
848 res.bottom = AutoYPosN(bott_perc);
849 if (w > Winsys.resolution.width) w = Winsys.resolution.width;
850 res.left = (Winsys.resolution.width - w) / 2;
851 res.right = Winsys.resolution.width - res.left;
852 return res;
853 }
854