1 /*=============================================================================
2 Blobby Volley 2
3 Copyright (C) 2006 Jonathan Sieber (jonathan_sieber@yahoo.de)
4 Copyright (C) 2006 Daniel Knobe (daniel-knobe@web.de)
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 =============================================================================*/
20
21 /* header include */
22 #include "IMGUI.h"
23
24 /* includes */
25 #include <queue>
26 #include <cassert>
27
28 #include <SDL2/SDL.h>
29
30 #include "InputManager.h"
31
32 /* implementation */
33
34 enum ObjectType
35 {
36 IMAGE,
37 OVERLAY,
38 TEXT,
39 BUTTON, // Unused!
40 SCROLLBAR,
41 ACTIVESCROLLBAR,
42 EDITBOX,
43 ACTIVEEDITBOX,
44 SELECTBOX,
45 ACTIVESELECTBOX,
46 BLOB,
47 CHAT
48 };
49
50 struct QueueObject
51 {
52 ObjectType type;
53 int id;
54 Vector2 pos1;
55 Vector2 pos2;
56 Color col;
57 float alpha;
58 std::string text;
59 std::vector<std::string> entries;
60 int selected;
61 int length;
62 unsigned int flags;
63 };
64
65 typedef std::queue<QueueObject> RenderQueue;
66
67 IMGUI* IMGUI::mSingleton = 0;
68 RenderQueue *mQueue;
69
IMGUI()70 IMGUI::IMGUI()
71 {
72 mQueue = new RenderQueue;
73 mActiveButton = -1;
74 mHeldWidget = 0;
75 mLastKeyAction = NONE;
76 mLastWidget = 0;
77 mButtonReset = false;
78 mInactive = false;
79 }
80
~IMGUI()81 IMGUI::~IMGUI()
82 {
83 delete mQueue;
84 }
85
getSingleton()86 IMGUI& IMGUI::getSingleton()
87 {
88 if (!mSingleton)
89 mSingleton = new IMGUI;
90 return *mSingleton;
91 }
92
begin()93 void IMGUI::begin()
94 {
95 mUsingCursor = false;
96 mButtonReset = false;
97
98 while (!mQueue->empty())
99 mQueue->pop();
100
101
102 mLastKeyAction = NONE;
103
104 if (InputManager::getSingleton()->up())
105 mLastKeyAction = UP;
106
107 if (InputManager::getSingleton()->down())
108 mLastKeyAction = DOWN;
109
110 if (InputManager::getSingleton()->left())
111 mLastKeyAction = LEFT;
112
113 if (InputManager::getSingleton()->right())
114 mLastKeyAction = RIGHT;
115
116 if (InputManager::getSingleton()->select())
117 mLastKeyAction = SELECT;
118
119 if (InputManager::getSingleton()->exit())
120 mLastKeyAction = BACK;
121 }
122
end()123 void IMGUI::end()
124 {
125 int FontSize;
126 RenderManager& rmanager = RenderManager::getSingleton();
127
128 while (!mQueue->empty())
129 {
130 QueueObject& obj = mQueue->front();
131 switch (obj.type)
132 {
133 case IMAGE:
134 rmanager.drawImage(obj.text, obj.pos1, obj.pos2);
135 break;
136
137 case OVERLAY:
138 rmanager.drawOverlay(obj.alpha, obj.pos1, obj.pos2, obj.col);
139 break;
140
141 case TEXT:
142 rmanager.drawText(obj.text, obj.pos1, obj.flags);
143 break;
144
145 case SCROLLBAR:
146 rmanager.drawOverlay(0.5, obj.pos1, obj.pos1 + Vector2(210.0, 26.0));
147 rmanager.drawImage("gfx/scrollbar.bmp",obj.pos1 + Vector2(obj.pos2.x * 200.0 + 5 , 13));
148 break;
149
150 case ACTIVESCROLLBAR:
151 rmanager.drawOverlay(0.4, obj.pos1, obj.pos1 + Vector2(210.0, 26.0));
152 rmanager.drawImage("gfx/scrollbar.bmp",obj.pos1 + Vector2(obj.pos2.x * 200.0 + 5 , 13));
153 break;
154
155 case EDITBOX:
156 FontSize = (obj.flags & TF_SMALL_FONT ? FONT_WIDTH_SMALL : FONT_WIDTH_NORMAL);
157 rmanager.drawOverlay(0.5, obj.pos1, obj.pos1 + Vector2(10+obj.length*FontSize, 10+FontSize));
158 rmanager.drawText(obj.text, obj.pos1+Vector2(5, 5), obj.flags);
159 break;
160
161 case ACTIVEEDITBOX:
162 FontSize = (obj.flags & TF_SMALL_FONT ? FONT_WIDTH_SMALL : FONT_WIDTH_NORMAL);
163 rmanager.drawOverlay(0.3, obj.pos1, obj.pos1 + Vector2(10+obj.length*FontSize, 10+FontSize));
164 rmanager.drawText(obj.text, obj.pos1+Vector2(5, 5), obj.flags);
165 if (obj.pos2.x >= 0)
166 rmanager.drawOverlay(1.0, Vector2((obj.pos2.x)*FontSize+obj.pos1.x+5, obj.pos1.y+5), Vector2((obj.pos2.x)*FontSize+obj.pos1.x+5+3, obj.pos1.y+5+FontSize), Color(255,255,255));
167 break;
168
169 case SELECTBOX:
170 FontSize = (obj.flags & TF_SMALL_FONT ? (FONT_WIDTH_SMALL+LINE_SPACER_SMALL) : (FONT_WIDTH_NORMAL+LINE_SPACER_NORMAL));
171 rmanager.drawOverlay(0.5, obj.pos1, obj.pos2);
172 for (unsigned int c = 0; c < obj.entries.size(); c++)
173 {
174 if( c == static_cast<unsigned int>(obj.selected) )
175 rmanager.drawText(obj.entries[c], Vector2(obj.pos1.x+5, obj.pos1.y+(c*FontSize)+5), obj.flags | TF_HIGHLIGHT);
176 else
177 rmanager.drawText(obj.entries[c], Vector2(obj.pos1.x+5, obj.pos1.y+(c*FontSize)+5), obj.flags);
178 }
179 break;
180
181 case ACTIVESELECTBOX:
182 FontSize = (obj.flags & TF_SMALL_FONT ? (FONT_WIDTH_SMALL+LINE_SPACER_SMALL) : (FONT_WIDTH_NORMAL+LINE_SPACER_NORMAL));
183 rmanager.drawOverlay(0.3, obj.pos1, obj.pos2);
184 for (unsigned int c = 0; c < obj.entries.size(); c++)
185 {
186 if( c == static_cast<unsigned int>(obj.selected) )
187 rmanager.drawText(obj.entries[c], Vector2(obj.pos1.x+5, obj.pos1.y+(c*FontSize)+5), obj.flags | TF_HIGHLIGHT);
188 else
189 rmanager.drawText(obj.entries[c], Vector2(obj.pos1.x+5, obj.pos1.y+(c*FontSize)+5), obj.flags);
190 }
191 break;
192
193 case CHAT:
194 FontSize = (obj.flags & TF_SMALL_FONT ? (FONT_WIDTH_SMALL+LINE_SPACER_SMALL) : (FONT_WIDTH_NORMAL+LINE_SPACER_NORMAL));
195 rmanager.drawOverlay(0.5, obj.pos1, obj.pos2);
196 for (unsigned int c = 0; c < obj.entries.size(); c++)
197 {
198 if (obj.text[c] == 'R' )
199 rmanager.drawText(obj.entries[c], Vector2(obj.pos1.x+5, obj.pos1.y+(c*FontSize)+5), obj.flags | TF_HIGHLIGHT);
200 else
201 rmanager.drawText(obj.entries[c], Vector2(obj.pos1.x+5, obj.pos1.y+(c*FontSize)+5), obj.flags);
202 }
203 break;
204
205 case BLOB:
206 rmanager.drawBlob(obj.pos1, obj.col);
207 break;
208
209 default:
210 break;
211 }
212 mQueue->pop();
213 }
214 #if __DESKTOP__
215 if (mDrawCursor)
216 {
217 rmanager.drawImage("gfx/cursor.bmp", InputManager::getSingleton()->position() + Vector2(24.0, 24.0));
218 mDrawCursor = false;
219 }
220 #endif
221 }
222
doImage(int id,const Vector2 & position,const std::string & name,const Vector2 & size)223 void IMGUI::doImage(int id, const Vector2& position, const std::string& name, const Vector2& size)
224 {
225 QueueObject obj;
226 obj.type = IMAGE;
227 obj.id = id;
228 obj.pos1 = position;
229 obj.pos2 = size;
230 obj.text = name;
231 mQueue->push(obj);
232 }
233
doText(int id,const Vector2 & position,const std::string & text,unsigned int flags)234 void IMGUI::doText(int id, const Vector2& position, const std::string& text, unsigned int flags)
235 {
236 QueueObject obj;
237 obj.type = TEXT;
238 obj.id = id;
239 obj.pos1 = position;
240
241 int fontSize = flags & TF_SMALL_FONT ? FONT_WIDTH_SMALL : FONT_WIDTH_NORMAL;
242 // update position depending on alignment
243 if( flags & TF_ALIGN_CENTER )
244 {
245 obj.pos1.x -= text.size() * fontSize / 2;
246 }
247
248 if( flags & TF_ALIGN_RIGHT )
249 {
250 obj.pos1.x -= text.size() * fontSize;
251 }
252
253
254 obj.text = text;
255 obj.flags = flags;
256 mQueue->push(obj);
257 }
258
doText(int id,const Vector2 & position,TextManager::STRING text,unsigned int flags)259 void IMGUI::doText(int id, const Vector2& position, TextManager::STRING text, unsigned int flags)
260 {
261 doText(id, position, TextManager::getSingleton()->getString(text), flags);
262 }
263
doOverlay(int id,const Vector2 & pos1,const Vector2 & pos2,const Color & col,float alpha)264 void IMGUI::doOverlay(int id, const Vector2& pos1, const Vector2& pos2, const Color& col, float alpha)
265 {
266 QueueObject obj;
267 obj.type = OVERLAY;
268 obj.id = id;
269 obj.pos1 = pos1;
270 obj.pos2 = pos2;
271 obj.col = col;
272 obj.alpha = alpha;
273 mQueue->push(obj);
274 RenderManager::getSingleton().redraw();
275 }
276
doButton(int id,const Vector2 & position,TextManager::STRING text,unsigned int flags)277 bool IMGUI::doButton(int id, const Vector2& position, TextManager::STRING text, unsigned int flags)
278 {
279 return doButton(id, position, TextManager::getSingleton()->getString(text), flags);
280 }
281
doButton(int id,const Vector2 & position,const std::string & text,unsigned int flags)282 bool IMGUI::doButton(int id, const Vector2& position, const std::string& text, unsigned int flags)
283 {
284 bool clicked = false;
285 QueueObject obj;
286 obj.id = id;
287 obj.pos1 = position;
288 obj.text = text;
289 obj.type = TEXT;
290 obj.flags = flags;
291
292 int fontSize = flags & TF_SMALL_FONT ? FONT_WIDTH_SMALL : FONT_WIDTH_NORMAL;
293 // update position depending on alignment
294 if( flags & TF_ALIGN_CENTER )
295 {
296 obj.pos1.x -= text.size() * fontSize / 2;
297 }
298
299 if( flags & TF_ALIGN_RIGHT )
300 {
301 obj.pos1.x -= text.size() * fontSize;
302 }
303
304 if (!mInactive)
305 {
306 // M.W. : Activate cursorless object-highlighting once the up or down key is pressed.
307 if (mActiveButton == -1)
308 {
309 switch (mLastKeyAction)
310 {
311 case DOWN:
312 mActiveButton = 0;
313 mLastKeyAction = NONE;
314 break;
315
316 case UP:
317 mActiveButton = mLastWidget;
318 mLastKeyAction = NONE;
319 break;
320
321 default:
322 break;
323 }
324 }
325
326 // Highlight first menu object for arrow key navigation.
327 if (mActiveButton == 0 && !mButtonReset)
328 mActiveButton = id;
329
330 // React to keyboard input.
331 if (id == mActiveButton)
332 {
333 obj.flags = obj.flags | TF_HIGHLIGHT;
334 switch (mLastKeyAction)
335 {
336 case DOWN:
337 mActiveButton = 0;
338 mLastKeyAction = NONE;
339 break;
340
341 case UP:
342 mActiveButton = mLastWidget;
343 mLastKeyAction = NONE;
344 break;
345
346 case SELECT:
347 clicked = true;
348 mLastKeyAction = NONE;
349 break;
350 default:
351 break;
352 }
353 }
354
355 // React to back button
356 if (mLastKeyAction == BACK)
357 {
358 if ((text == (TextManager::getSingleton())->getString(TextManager::LBL_CANCEL)) ||
359 (text == (TextManager::getSingleton())->getString(TextManager::MNU_LABEL_EXIT)))
360 {
361 //todo: Workarround to catch backkey
362 clicked = true;
363 mActiveButton = id;
364 }
365 }
366
367 #if __MOBILE__
368 const int tolerance = 3;
369 #else
370 const int tolerance = 0;
371 #endif
372 // React to mouse input.
373 Vector2 mousepos = InputManager::getSingleton()->position();
374 if (mousepos.x + tolerance >= position.x &&
375 mousepos.y + tolerance * 2 >= position.y &&
376 mousepos.x - tolerance <= position.x + text.length() * (flags & TF_SMALL_FONT ? FONT_WIDTH_SMALL : FONT_WIDTH_NORMAL) &&
377 mousepos.y - tolerance * 2 <= position.y + (flags & TF_SMALL_FONT ? FONT_WIDTH_SMALL : FONT_WIDTH_NORMAL))
378 {
379 obj.flags = obj.flags
380 #if __DESKTOP__
381 | TF_HIGHLIGHT
382 #endif
383 ;
384 if (InputManager::getSingleton()->click())
385 {
386 clicked = true;
387 mActiveButton = id;
388 }
389 }
390 }
391
392 mLastWidget = id;
393 mQueue->push(obj);
394 return clicked;
395 }
396
doImageButton(int id,const Vector2 & position,const Vector2 & size,const std::string & image)397 bool IMGUI::doImageButton(int id, const Vector2& position, const Vector2& size, const std::string& image)
398 {
399 doImage(id, position, image);
400
401 // React to mouse input.
402 if (InputManager::getSingleton()->click())
403 {
404 Vector2 mousepos = InputManager::getSingleton()->position();
405 Vector2 btnpos = position - size * 0.5;
406 if (mousepos.x > btnpos.x && mousepos.y > btnpos.y &&
407 mousepos.x < btnpos.x + size.x && mousepos.y < btnpos.y + size.y)
408 {
409 return true;
410 }
411 }
412
413 return false;
414 }
415
doScrollbar(int id,const Vector2 & position,float & value)416 bool IMGUI::doScrollbar(int id, const Vector2& position, float& value)
417 {
418 QueueObject obj;
419 obj.id = id;
420 obj.pos1 = position;
421 obj.type = SCROLLBAR;
422
423 bool deselected = false;
424
425 if (InputManager::getSingleton()->unclick())
426 {
427 if (id == mHeldWidget)
428 deselected = true;
429
430 mHeldWidget = 0;
431 }
432
433 if (!mInactive)
434 {
435 // M.W. : Activate cursorless object-highlighting once the up or down key is pressed.
436 if (mActiveButton == -1)
437 {
438 switch (mLastKeyAction)
439 {
440 case DOWN:
441 mActiveButton = 0;
442 mLastKeyAction = NONE;
443 break;
444
445 case UP:
446 mActiveButton = mLastWidget;
447 mLastKeyAction = NONE;
448 break;
449
450 default:
451 break;
452 }
453 }
454
455 // Highlight first menu object for arrow key navigation.
456 if (mActiveButton == 0 && !mButtonReset)
457 mActiveButton = id;
458
459 // React to keyboard input.
460 if (id == mActiveButton)
461 {
462 obj.type = ACTIVESCROLLBAR;
463 switch (mLastKeyAction)
464 {
465 case DOWN:
466 mActiveButton = 0;
467 mLastKeyAction = NONE;
468 break;
469
470 case UP:
471 mActiveButton = mLastWidget;
472 mLastKeyAction = NONE;
473 break;
474
475 case LEFT:
476 value -= 0.1;
477 mLastKeyAction = NONE;
478 break;
479
480 case RIGHT:
481 value += 0.1;
482 mLastKeyAction = NONE;
483 break;
484
485 default:
486 break;
487 }
488 }
489
490 #if __MOBILE__
491 const int tolerance = 3;
492 #else
493 const int tolerance = 0;
494 #endif
495
496 // React to mouse input.
497 Vector2 mousepos = InputManager::getSingleton()->position();
498 if (mousepos.x + 5 > position.x &&
499 mousepos.y + tolerance * 2 > position.y &&
500 mousepos.x < position.x + 205 &&
501 mousepos.y - tolerance < position.y + 24.0)
502 {
503 obj.type = ACTIVESCROLLBAR;
504
505 if (InputManager::getSingleton()->click())
506 {
507 mHeldWidget = id;
508 }
509
510 if (mHeldWidget == id)
511 {
512 value = (mousepos.x - position.x) / 200.0;
513 mActiveButton = id;
514 }
515
516 if(InputManager::getSingleton()->mouseWheelUp())
517 value += 0.1;
518
519 if(InputManager::getSingleton()->mouseWheelDown())
520 value -= 0.1;
521 }
522 }
523
524 value = value > 0.0 ? (value < 1.0 ? value : 1.0) : 0.0;
525 obj.pos2.x = value;
526
527 mLastWidget = id;
528 mQueue->push(obj);
529
530 return deselected;
531 }
532
resetSelection()533 void IMGUI::resetSelection()
534 {
535 mInactive = false;
536 mActiveButton = -1;
537 mButtonReset = true;
538 }
539
doEditbox(int id,const Vector2 & position,unsigned int length,std::string & text,unsigned & cpos,unsigned int flags,bool force_active)540 bool IMGUI::doEditbox(int id, const Vector2& position, unsigned int length, std::string& text, unsigned& cpos, unsigned int flags, bool force_active)
541 {
542 int FontSize = (flags & TF_SMALL_FONT ? FONT_WIDTH_SMALL : FONT_WIDTH_NORMAL);
543 bool changed = false;
544 QueueObject obj;
545 obj.id = id;
546 obj.pos1 = position;
547 obj.type = EDITBOX;
548 obj.length = length; // lenght does not actually work!
549 obj.flags = flags;
550
551 // React to mouse input.
552 Vector2 mousepos = InputManager::getSingleton()->position();
553 if (mousepos.x > position.x &&
554 mousepos.y > position.y &&
555 mousepos.x < position.x + length * FontSize + 10 &&
556 mousepos.y < position.y + FontSize + 10)
557 {
558 obj.flags = obj.flags | TF_HIGHLIGHT;
559 if (InputManager::getSingleton()->click())
560 {
561 // Handle click on the text.
562 if (mousepos.x < position.x + text.length() * FontSize)
563 cpos = (int) ((mousepos.x-position.x-5+(FontSize/2)) / FontSize);
564 // Handle click behind the text.
565 else if (mousepos.x < position.x + length * FontSize + 10)
566 cpos = (int) text.length();
567
568 mActiveButton = id;
569
570 // Show keyboard
571 SDL_StartTextInput();
572 }
573 }
574
575 if (!mInactive)
576 {
577 // M.W. : Activate cursorless object-highlighting once the up or down key is pressed.
578 if (mActiveButton == -1)
579 {
580 switch (mLastKeyAction)
581 {
582 case DOWN:
583 mActiveButton = 0;
584 mLastKeyAction = NONE;
585 break;
586
587 case UP:
588 mActiveButton = mLastWidget;
589 mLastKeyAction = NONE;
590 break;
591
592 default:
593 break;
594 }
595
596 // M.W. : Initialize the cursor position at the end of the string.
597 // IMPORTANT: If you make changes to EditBox text that alter the length
598 // of the text, either call resetSelection() to come back
599 // to this area of code or update cpos manually to prevent
600 // crashes due to a misplaced cursor.
601 cpos = text.length();
602 }
603
604 // Highlight first menu object for arrow key navigation.
605 if (mActiveButton == 0 && !mButtonReset)
606 mActiveButton = id;
607
608 // React to keyboard input.
609 if (id == mActiveButton || force_active)
610 {
611 obj.type = ACTIVEEDITBOX;
612 switch (mLastKeyAction)
613 {
614 case DOWN:
615 mActiveButton = 0;
616 mLastKeyAction = NONE;
617 break;
618
619 case UP:
620 mActiveButton = mLastWidget;
621 mLastKeyAction = NONE;
622 break;
623
624 case LEFT:
625 if (cpos > 0)
626 cpos--;
627 mLastKeyAction = NONE;
628 break;
629
630 case RIGHT:
631 if (cpos < text.length())
632 cpos++;
633 mLastKeyAction = NONE;
634 break;
635
636 default:
637 break;
638 }
639 std::string input = InputManager::getSingleton()->getLastTextKey();
640 if (input == "backspace" && text.length() > 0 && cpos > 0)
641 {
642 text.erase(cpos - 1, 1);
643 cpos--;
644 }
645 else if (input == "del" && text.length() > cpos)
646 {
647 text.erase(cpos, 1);
648 }
649 else if (input == "return")
650 {
651 // Workarround for chatwindow! Delete this after GUI-Rework
652 changed = true;
653 }
654 // This is a temporary solution until the new
655 // UTF-8 class can tell the real length!!!
656 else if (text.length() < length)
657 {
658 if (input == "space")
659 {
660 text.insert(cpos, " ");
661 cpos++;
662 changed = true;
663 }
664 else if (input == "keypad0")
665 {
666 text.insert(cpos, "0");
667 cpos++;
668 changed = true;
669 }
670 else if (input == "keypad1")
671 {
672 text.insert(cpos, "1");
673 cpos++;
674 changed = true;
675 }
676 else if (input == "keypad2")
677 {
678 text.insert(cpos, "2");
679 cpos++;
680 changed = true;
681 }
682 else if (input == "keypad3")
683 {
684 text.insert(cpos, "3");
685 cpos++;
686 changed = true;
687 }
688 else if (input == "keypad4")
689 {
690 text.insert(cpos, "4");
691 cpos++;
692 changed = true;
693 }
694 else if (input == "keypad5")
695 {
696 text.insert(cpos, "5");
697 cpos++;
698 changed = true;
699 }
700 else if (input == "keypad6")
701 {
702 text.insert(cpos, "6");
703 cpos++;
704 changed = true;
705 }
706 else if (input == "keypad7")
707 {
708 text.insert(cpos, "7");
709 cpos++;
710 changed = true;
711 }
712 else if (input == "keypad8")
713 {
714 text.insert(cpos, "8");
715 cpos++;
716 changed = true;
717 }
718 else if (input == "keypad9")
719 {
720 text.insert(cpos, "9");
721 cpos++;
722 changed = true;
723 }
724 else if (input.length() == 1)
725 {
726 text.insert(cpos, input);
727 cpos++;
728 changed = true;
729 }
730 }
731 }
732 }
733
734 obj.pos2.x = SDL_GetTicks() % 1000 >= 500 ? cpos : -1.0;
735 obj.text = text;
736
737 mLastWidget = id;
738 mQueue->push(obj);
739
740 // when content changed, it is active
741 // part of chat window hack
742 if( changed && force_active )
743 mActiveButton = id;
744
745 return changed;
746 }
747
doSelectbox(int id,const Vector2 & pos1,const Vector2 & pos2,const std::vector<std::string> & entries,unsigned int & selected,unsigned int flags)748 SelectBoxAction IMGUI::doSelectbox(int id, const Vector2& pos1, const Vector2& pos2, const std::vector<std::string>& entries, unsigned int& selected, unsigned int flags)
749 {
750 int FontSize = (flags & TF_SMALL_FONT ? (FONT_WIDTH_SMALL+LINE_SPACER_SMALL) : (FONT_WIDTH_NORMAL+LINE_SPACER_NORMAL));
751 SelectBoxAction changed = SBA_NONE;
752 QueueObject obj;
753 obj.id = id;
754 obj.pos1 = pos1;
755 obj.pos2 = pos2;
756 obj.type = SELECTBOX;
757 obj.flags = flags;
758
759 const int itemsPerPage = int(pos2.y - pos1.y - 10) / FontSize;
760 int first = (int)(selected / itemsPerPage)*itemsPerPage; //the first visible element in the list
761
762 if (!mInactive)
763 {
764 // M.W. : Activate cursorless object-highlighting once the up or down key is pressed.
765 if (mActiveButton == -1)
766 {
767 switch (mLastKeyAction)
768 {
769 case DOWN:
770 mActiveButton = 0;
771 mLastKeyAction = NONE;
772 break;
773
774 case UP:
775 mActiveButton = mLastWidget;
776 mLastKeyAction = NONE;
777 break;
778
779 default:
780 break;
781 }
782 }
783
784 // Highlight first menu object for arrow key navigation.
785 if (mActiveButton == 0 && !mButtonReset)
786 mActiveButton = id;
787
788 // React to keyboard input.
789 if (id == mActiveButton)
790 {
791 obj.type = ACTIVESELECTBOX;
792 switch (mLastKeyAction)
793 {
794 case DOWN:
795 mActiveButton = 0;
796 mLastKeyAction = NONE;
797 break;
798
799 case UP:
800 mActiveButton = mLastWidget;
801 mLastKeyAction = NONE;
802 break;
803
804 case LEFT:
805 if (selected > 0)
806 {
807 selected--;
808 changed = SBA_SELECT;
809 }
810 mLastKeyAction = NONE;
811 break;
812
813 case RIGHT:
814 if (selected + 1 < entries.size())
815 {
816 selected++;
817 changed = SBA_SELECT;
818 }
819 mLastKeyAction = NONE;
820 break;
821
822 default:
823 break;
824 }
825 }
826
827 // React to mouse input.
828 Vector2 mousepos = InputManager::getSingleton()->position();
829 if (mousepos.x > pos1.x && mousepos.y > pos1.y && mousepos.x < pos2.x && mousepos.y < pos2.y)
830 {
831 obj.type = ACTIVESELECTBOX;
832 if (InputManager::getSingleton()->click())
833 mActiveButton = id;
834 }
835 //entries mouseclick:
836 if (mousepos.x > pos1.x &&
837 mousepos.y > pos1.y+5 &&
838 mousepos.x < pos2.x-35 &&
839 mousepos.y < pos1.y+5+FontSize*itemsPerPage)
840 {
841 if (InputManager::getSingleton()->click())
842 {
843 int tmp = (int)((mousepos.y - pos1.y - 5) / FontSize) + first;
844 /// \todo well, it's not really a doulbe click...
845 /// we need to do this in inputmanager
846 if( selected == tmp && InputManager::getSingleton()->doubleClick() )
847 changed = SBA_DBL_CLICK;
848
849 if (tmp >= 0 && static_cast<unsigned int>(tmp) < entries.size())
850 selected = tmp;
851
852 mActiveButton = id;
853 }
854 if ((InputManager::getSingleton()->mouseWheelUp()) && (selected > 0))
855 {
856 selected--;
857 changed = SBA_SELECT;
858 }
859 if ((InputManager::getSingleton()->mouseWheelDown()) && (selected + 1 < entries.size()))
860 {
861 selected++;
862 changed = SBA_SELECT;
863 }
864 }
865 //arrows mouseclick:
866 if (mousepos.x > pos2.x-30 && mousepos.x < pos2.x-30+24 && InputManager::getSingleton()->click())
867 {
868 if (mousepos.y > pos1.y+3 && mousepos.y < pos1.y+3+24 && selected > 0)
869 {
870 selected--;
871 changed = SBA_SELECT;
872 }
873
874 if (mousepos.y > pos2.y-27 && mousepos.y < pos2.y-27+24 && selected + 1 < entries.size())
875 {
876 selected++;
877 changed = SBA_SELECT;
878 }
879 }
880 }
881 doImage(GEN_ID, Vector2(pos2.x-15, pos1.y+15), "gfx/pfeil_oben.bmp");
882 doImage(GEN_ID, Vector2(pos2.x-15, pos2.y-15), "gfx/pfeil_unten.bmp");
883
884 first = (selected / itemsPerPage)*itemsPerPage; //recalc first
885 if ( !entries.empty() )
886 {
887 unsigned int last = first + itemsPerPage;
888 if (last > entries.size())
889 last = entries.size();
890
891 obj.entries = std::vector<std::string>(entries.begin()+first, entries.begin()+last);
892 }
893 else
894 obj.entries = std::vector<std::string>();
895
896 obj.selected = selected-first;
897
898 mLastWidget = id;
899 mQueue->push(obj);
900
901 return changed;
902 }
903
doChatbox(int id,const Vector2 & pos1,const Vector2 & pos2,const std::vector<std::string> & entries,unsigned int & selected,const std::vector<bool> & local,unsigned int flags)904 void IMGUI::doChatbox(int id, const Vector2& pos1, const Vector2& pos2, const std::vector<std::string>& entries, unsigned int& selected, const std::vector<bool>& local, unsigned int flags)
905 {
906 assert( entries.size() == local.size() );
907 int FontSize = (flags & TF_SMALL_FONT ? (FONT_WIDTH_SMALL+LINE_SPACER_SMALL) : (FONT_WIDTH_NORMAL+LINE_SPACER_NORMAL));
908 QueueObject obj;
909 obj.id = id;
910 obj.pos1 = pos1;
911 obj.pos2 = pos2;
912 obj.type = CHAT;
913 obj.flags = flags;
914
915 const unsigned int itemsPerPage = int(pos2.y - pos1.y - 10) / FontSize;
916
917 if (!mInactive)
918 {
919 // M.W. : Activate cursorless object-highlighting once the up or down key is pressed.
920 if (mActiveButton == -1)
921 {
922 switch (mLastKeyAction)
923 {
924 case DOWN:
925 mActiveButton = 0;
926 mLastKeyAction = NONE;
927 break;
928
929 case UP:
930 mActiveButton = mLastWidget;
931 mLastKeyAction = NONE;
932 break;
933
934 default:
935 break;
936 }
937 }
938
939 // Highlight first menu object for arrow key navigation.
940 if (mActiveButton == 0 && !mButtonReset)
941 mActiveButton = id;
942
943 // React to keyboard input.
944 if (id == mActiveButton)
945 {
946 switch (mLastKeyAction)
947 {
948 case DOWN:
949 mActiveButton = 0;
950 mLastKeyAction = NONE;
951 break;
952
953 case UP:
954 mActiveButton = mLastWidget;
955 mLastKeyAction = NONE;
956 break;
957
958 case LEFT:
959 if (selected > 0)
960 {
961 selected--;
962 }
963 mLastKeyAction = NONE;
964 break;
965
966 case RIGHT:
967 if (selected + 1 < entries.size())
968 {
969 selected++;
970 }
971 mLastKeyAction = NONE;
972 break;
973
974 default:
975 break;
976 }
977 }
978
979 // React to mouse input.
980 Vector2 mousepos = InputManager::getSingleton()->position();
981 if (mousepos.x > pos1.x && mousepos.y > pos1.y && mousepos.x < pos2.x && mousepos.y < pos2.y)
982 {
983 if (InputManager::getSingleton()->click())
984 mActiveButton = id;
985 }
986 //entries mouseclick:
987 if (mousepos.x > pos1.x &&
988 mousepos.y > pos1.y+5 &&
989 mousepos.x < pos2.x-35 &&
990 mousepos.y < pos1.y+5+FontSize*itemsPerPage)
991 {
992 if ((InputManager::getSingleton()->mouseWheelUp()) && (selected > 0))
993 {
994 selected--;
995 }
996
997 if ((InputManager::getSingleton()->mouseWheelDown()) && (selected + 1 < entries.size()))
998 {
999 selected++;
1000 }
1001 }
1002 //arrows mouseclick:
1003 if (mousepos.x > pos2.x-30 && mousepos.x < pos2.x-30+24 && InputManager::getSingleton()->click())
1004 {
1005 if (mousepos.y > pos1.y+3 && mousepos.y < pos1.y+3+24 && selected > 0)
1006 {
1007 selected--;
1008 }
1009
1010 if (mousepos.y > pos2.y-27 && mousepos.y < pos2.y-27+24 && selected + 1 < entries.size())
1011 {
1012 selected++;
1013 }
1014 }
1015 }
1016 doImage(GEN_ID, Vector2(pos2.x-15, pos1.y+15), "gfx/pfeil_oben.bmp");
1017 doImage(GEN_ID, Vector2(pos2.x-15, pos2.y-15), "gfx/pfeil_unten.bmp");
1018
1019 unsigned int first = (selected / itemsPerPage) * itemsPerPage; //recalc first
1020 if ( !entries.empty() )
1021 {
1022 unsigned int last = selected + 1;
1023 /// \todo maybe we should adapt selected so we even can't scroll up further!
1024 // we don't want negative chatlog, so we just scroll upward without coming to negative
1025 // elements.
1026 if (last >= itemsPerPage)
1027 first = last - itemsPerPage;
1028 else
1029 first = 0;
1030
1031 // check that we don't create out of bounds problems
1032 if(last > entries.size())
1033 {
1034 last = entries.size();
1035 }
1036
1037 obj.entries = std::vector<std::string>(entries.begin()+first, entries.begin()+last);
1038 // HACK: we use taxt to store information which text is from local player and which from
1039 // remote player.
1040 obj.text = "";
1041 for(unsigned int i = first; i < last; ++i)
1042 {
1043 obj.text += local[i] ? 'L' : 'R';
1044 }
1045 }
1046 else
1047 obj.entries = std::vector<std::string>();
1048
1049 obj.selected = selected-first;
1050
1051 mLastWidget = id;
1052 mQueue->push(obj);
1053 }
1054
1055
doBlob(int id,const Vector2 & position,const Color & col)1056 bool IMGUI::doBlob(int id, const Vector2& position, const Color& col)
1057 {
1058 QueueObject obj;
1059 obj.id = id;
1060 obj.pos1 = position;
1061 obj.type = BLOB;
1062 obj.col = col;
1063 mQueue->push(obj);
1064 return false;
1065 }
1066
usingCursor() const1067 bool IMGUI::usingCursor() const
1068 {
1069 return mUsingCursor;
1070 }
1071