1 /*
2 
3 *************************************************************************
4 
5 ArmageTron -- Just another Tron Lightcycle Game in 3D.
6 Copyright (C) 2000  Manuel Moos (manuel@moosnet.de)
7 Copyright (C) 2004  Armagetron Advanced Team (http://sourceforge.net/projects/armagetronad/)
8 
9 **************************************************************************
10 
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License
13 as published by the Free Software Foundation; either version 2
14 of the License, or (at your option) any later version.
15 
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 GNU General Public License for more details.
20 
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24 
25 ***************************************************************************
26 
27 */
28 
29 #ifndef ArmageTron_MENU_H
30 #define ArmageTron_MENU_H
31 
32 #include "rFont.h"
33 #include "tList.h"
34 #include "tString.h"
35 #include "tCallback.h"
36 #include "tLocale.h"
37 
38 #include "rSDL.h"
39 #ifndef DEDICATED
40 #include <SDL_events.h>
41 #endif
42 
43 #include <deque>
44 
45 #include "defs.h"
46 
47 class uMenuItem;
48 
49 class uMenu{
50     friend class uMenuItem;
51 
52 protected:
53     tList<uMenuItem>      items;
54     static FUNCPTR       idle;
55 
56     REAL menuTop;
57     REAL menuBot;
58     REAL yOffset;
59 
60     bool                 exitFlag;
61 
62     REAL                 spaceBelow;
63     REAL                 center;
64 
65     int                  selected;
66 
67     REAL YPos(int num);
68 public:
69     static bool          wrap;
70 
71     // different quick exit types
72     enum QuickExit
73     {
74         QuickExit_Off  = 0, // no quick exit, keep going
75         QuickExit_Game = 1, // quit to game selection menu
76         QuickExit_Total = 2 // quit the program
77     };
78 
79     static QuickExit     quickexit;
80     static bool          exitToMain;
81 
82     tOutput              title;
83 
IdleFunc()84     FUNCPTR IdleFunc(){return idle;}
SetIdle(FUNCPTR idle_func)85     static void SetIdle(FUNCPTR idle_func) {idle=idle_func;}
86 
87     // poll input, return true if ESC was pressed
88     static bool IdleInput();
89 
SetCenter(REAL c)90     void SetCenter(REAL c) {center=c;}
SetTop(REAL t)91     void SetTop(REAL t) {menuTop=t;}
SetBot(REAL b)92     void SetBot(REAL b) {menuBot=b;spaceBelow=1+menuBot;}
SetSelected(int s)93     void SetSelected(int s) {selected = s;}
NumItems()94     int  NumItems()         {return items.Len();}
Item(int i)95     uMenuItem* Item(int i)  { return items[i]; }
96     void AddItem(uMenuItem* item);
97     void RemoveItem(uMenuItem* item);
98 
99 #ifdef SLOPPYLOCALE
100     uMenu(const char *t,bool exit_item=true);
101 #endif
102     uMenu(const tOutput &t,bool exit_item=true);
103     virtual ~uMenu();
104 
105     //! enters the menu; calls idle_func before rendering every frame
Enter()106     inline void Enter(){OnEnter();}
107 
108     void ReverseItems();
109 
110     // paints a nice background
111     static void GenericBackground();
112 
113     // marks the menu for exit
Exit()114     inline void Exit(){OnExit();}
115 
RequestSpaceBelow(REAL x)116     void RequestSpaceBelow(REAL x){
117         if (spaceBelow<x)
118             spaceBelow=x;
119     }
120 
121     // print a big message and a small interpretation
122     static bool Message(const tOutput& message, const tOutput& interpretation, REAL timeout = -1);
123 
124     //! returns whether there is currently an active menu
125     static bool MenuActive();
126 protected:
127     //! handles a key press
128     virtual void HandleEvent( SDL_Event event );
129 
130     //! enters the menu; calls idle_func before rendering every frame
131     virtual void OnEnter();
132 
133     //! marks the menu for exit
134     virtual void OnExit();
135 
136     //! called every frame before the menu is rendered
137     virtual void OnRender();
138 };
139 
140 
141 // *****************************************************
142 
143 class uMenuItem{
144     friend class uMenu;
145 
146     int idnum;
uMenuItem()147     uMenuItem(){}
148 protected:
149     uMenu  *menu;
150     tOutput helpText;
151 
152     void DisplayText(REAL x,REAL y,const char *text,bool selected,
153                      REAL alpha=1,int center=0,int cursor=0,int cursorPos=0, rTextField::ColorMode colorMode = rTextField::COLOR_USE );
154     void DisplayTextSpecial(REAL x,REAL y,const char *text,bool selected,
155                             REAL alpha=1,int center=0);
156 public:
uMenuItem(uMenu * M,const tOutput & help)157     uMenuItem(uMenu *M,const tOutput &help)
158             :idnum(-1),menu(M),helpText(help){
159         menu->items.Add(this,idnum);
160     }
161 
162 #ifdef SLOPPYLOCALE
uMenuItem(uMenu * M,const char * help)163     uMenuItem(uMenu *M,const char *help)
164             :idnum(-1),menu(M),helpText(help){
165         menu->items.Add(this,idnum);
166     }
167 #endif
168 
~uMenuItem()169     virtual ~uMenuItem()
170     {
171         if (menu && idnum >= 0)
172             menu->items.Remove(this,idnum);
173     }
174 
Help()175 virtual tString Help(){return tString(helpText);}
176     // displays the menuitem at position x,y. set selected to true
177     // if the item is currently under the cursor
178     virtual void Render(REAL ,REAL ,REAL =1,bool =0){}
179 
RenderBackground()180     virtual void RenderBackground(){
181         menu->GenericBackground();
182     }
183 
184     // if the user presses left/right on menuitem
LeftRight(int)185     virtual void LeftRight(int ){} //lr=-1:left lr=+1: right
LeftRightRelease()186     virtual void LeftRightRelease(){}
187 
Enter()188     virtual void Enter(){} // if the user presses enter/space on menu
189 
Event(SDL_Event &)190     virtual bool Event(SDL_Event &){return false;} // if the key c is
191     // pressed,mouse moved ...
192     // while menuitem is active; return value: key was used
193 
SpaceRight()194     virtual REAL SpaceRight(){return 0;}
195 
GetID()196     int GetID(){return idnum;}
197 
198 protected:
199     void SetColor( bool selected, REAL alpha );            //!< Sets the color of text output for this menuitem
200 };
201 
202 
203 // *****************************************************
204 // Menu Exit
205 // *****************************************************
206 
207 class uMenuItemExit:public uMenuItem{
208     tOutput t;
209 
210     static const tOutput& ExitText();
211     static const tOutput& ExitHelp();
212 
213 public:
214     uMenuItemExit(uMenu *M,
215                   const tOutput &text = ExitText(),
216                   const tOutput &help = ExitHelp())
uMenuItem(M,help)217             :uMenuItem(M,help)
218     ,t(text){}
219 
220     // displays the menuitem at position x,y. set selected to true
221     // if the item is currently under the cursor
222     virtual void Render(REAL x,REAL y,REAL alpha=1,bool selected=0){
223         DisplayTextSpecial(x,y,tString(t),selected,alpha);
224     }
225 
Enter()226     virtual void Enter(){menu->Exit();}
227     // if the user presses enter/space on menu
228 };
229 
230 // *****************************************************
231 // Selection
232 // *****************************************************
233 
234 template<class T> class uSelectItem{
235 public:
236     int idnum;
237 
238     tOutput description;
239     tOutput helpText;
240     T value;
241 
uSelectItem(const tOutput & desc,const tOutput & help,T val)242     uSelectItem(const tOutput& desc,const tOutput& help,T val)
243             :idnum(-1),description(desc),helpText(help),value(val){}
244 };
245 
246 template<class T> class uMenuItemSelection:public uMenuItem{
247 protected:
248     tList<uSelectItem<T> >	choices;
249     tOutput               	title;
250     int                   	select;
251     T *                   	target;
252 public:
253 #ifdef SLOPPYLOCALE
uMenuItemSelection(uMenu * m,const char * tit,const char * help,T & targ)254     uMenuItemSelection(uMenu *m,
255                        const char* tit,const char *help,
256                        T &targ)
257             :uMenuItem(m,help),title(tit),select(0),target(&targ){}
258 #endif
259 
uMenuItemSelection(uMenu * m,const tOutput & tit,const tOutput & help,T & targ)260     uMenuItemSelection(uMenu *m,
261                        const tOutput &tit,const tOutput &help,
262                        T &targ)
263             :uMenuItem(m,help),title(tit),select(0),target(&targ){}
264 
~uMenuItemSelection()265     ~uMenuItemSelection(){
266         Clear();
267     }
268 
Clear()269     void Clear(){
270         for(int i=choices.Len()-1;i>=0;i--){
271             uSelectItem<T> *x=choices(i);
272             choices.Remove(x,x->idnum);
273             delete x;
274         }
275         select=0;
276     }
277 
NewChoice(uSelectItem<T> * c)278     void NewChoice(uSelectItem<T> *c){
279         choices.Add(c,c->idnum);
280     }
281 
NewChoice(const tOutput & desc,const tOutput & help,T val)282     void NewChoice(const tOutput& desc,const tOutput& help,T val){
283         uSelectItem<T> *x=new uSelectItem<T>(desc,help,val);
284         NewChoice(x);
285     }
286 
LeftRight(int lr)287     virtual void LeftRight(int lr){
288         select+=lr;
289         if(select>=choices.Len())
290             select=choices.Len()-1;
291         if(select<0)
292             select=0;
293         if (choices.Len())
294             *target=choices(select)->value;
295     }
296 
297     virtual void Render(REAL x,REAL y,REAL alpha=1,bool selected=0){
298         for(int i=choices.Len()-1;i>=0;i--)
299             if (choices(i)->value==*target)
300                 select=i;
301 
302         DisplayText(REAL(x-.02),y,title,selected,alpha,1);
303         if (choices.Len()>0)
304             DisplayText(REAL(x+.02),y,choices(select)->description,selected,alpha,-1);
305     }
306 
Help()307     virtual tString Help(){
308         tString ret;
309         ret << helpText;
310         ret << "\n";
311         ret << choices(select)->helpText;
312         return ret;
313     }
314 
315 };
316 
317 template<class T> class uSelectEntry{
318 public:
uSelectEntry(uMenuItemSelection<T> & sel,const char * desc,const char * help,T val)319     uSelectEntry(uMenuItemSelection<T> &sel,
320                  const char *desc,
321                  const char *help,T val){
322         sel.NewChoice(desc,help,val);
323     }
324 };
325 
326 // *****************************************
327 //               Toggle
328 // *****************************************
329 
330 class uMenuItemToggle: public uMenuItemSelection<bool>{
331     void NewChoice(uSelectItem<bool> *c);
332     void NewChoice(const char *desc,bool val);
333 public:
334 #ifdef SLOPPYLOCALE
335     uMenuItemToggle(uMenu *m,const char *tit,
336                     const char *help,bool &targ);
337 #endif
338     uMenuItemToggle(uMenu *m,const tOutput& title,
339                     const tOutput& help,bool &targ);
340     ~uMenuItemToggle();
341 
342     virtual void LeftRight(int);
343     virtual void Enter();
344 };
345 
346 
347 // *****************************************
348 //               Integer Choose
349 // *****************************************
350 
351 class uMenuItemInt:public uMenuItem{
352 protected:
353     tOutput title;
354     int &target;
355     int Min,Max;
356     int Step;
357 public:
358     /*
359       uMenuItemInt(uMenu *m,const char *tit,
360       const char *help,int &targ,
361       int mi,int ma,int step=1);
362     */
363     uMenuItemInt(uMenu *m,const tOutput &title,
364                  const tOutput &help,int &targ,
365                  int mi,int ma,int step=1);
366 
~uMenuItemInt()367     ~uMenuItemInt(){}
368 
369     virtual void LeftRight(int);
370 
371     virtual void Render(REAL x,REAL y,REAL alpha=1,bool selected=0);
372 };
373 
374 // *****************************************
375 //               Float Choose
376 // *****************************************
377 
378 class uMenuItemReal:public uMenuItem{
379 protected:
380     tOutput title;
381     REAL &target;
382     REAL Min,Max;
383     REAL Step;
384 public:
385     /*
386       uMenuItemInt(uMenu *m,const char *tit,
387       const char *help,int &targ,
388       int mi,int ma,int step=1);
389     */
390     uMenuItemReal(uMenu *m,const tOutput &title,
391                  const tOutput &help,REAL &targ,
392                  REAL mi,REAL ma,REAL step=1);
393 
~uMenuItemReal()394     ~uMenuItemReal(){}
395 
396     virtual void LeftRight(int);
397 
398     virtual void Render(REAL x,REAL y,REAL alpha=1,bool selected=0);
399 };
400 
401 // *****************************************************
402 //  String query
403 // *****************************************************
404 
405 
406 class uMenuItemString: public uMenuItem{
407 protected:
408     tOutput  description;
409     tString *content;
410     int      cursorPos;
411     int		maxLength_;
412 
413     // color mode used for rendering
414     rTextField::ColorMode colorMode_;
415 public:
416     uMenuItemString(uMenu *M,const tOutput& desc,
417                     const tOutput& help,tString &c, int maxLength = 1024 );
~uMenuItemString()418     virtual ~uMenuItemString(){}
419 
420     virtual void Render(REAL x,REAL y,REAL alpha=1,bool selected=0);
421 
422     virtual bool Event(SDL_Event &e);
423 
MyMenu()424     uMenu *MyMenu(){return menu;}
425 
SetColorMode(rTextField::ColorMode colorMode)426     void SetColorMode( rTextField::ColorMode colorMode )
427     {
428         colorMode_ = colorMode;
429     }
430 
GetColorMode()431     rTextField::ColorMode GetColorMode() const
432     {
433         return colorMode_;
434     }
435 };
436 
437 class uMenuItemStringWithHistory : protected uMenuItemString {
438 protected:
439     std::deque<tString> &m_History;
440     unsigned int m_HistoryPos;
441     unsigned int m_HistoryLimit;
442 public:
443     uMenuItemStringWithHistory(uMenu *M,const tOutput& desc, const tOutput& help,tString &c, int maxLength, std::deque<tString> &history, int limit );
444 
445     ~uMenuItemStringWithHistory();
446 
447     virtual bool Event(SDL_Event &e);
448 };
449 
450 
451 // *****************************************************
452 //  Submenu
453 // *****************************************************
454 
455 
456 class uMenuItemSubmenu: public uMenuItem{
457     uMenu *submenu;
458 public:
459     uMenuItemSubmenu(uMenu *M,uMenu *s,
460                      const tOutput& help);
~uMenuItemSubmenu()461     virtual ~uMenuItemSubmenu(){}
462 
463     virtual void Render(REAL x,REAL y,REAL alpha=1,bool selected=0);
464 
465     virtual void Enter();
466 };
467 
468 
469 // *****************************************************
470 //  generic action
471 // *****************************************************
472 
473 class uMenuItemAction: public uMenuItem{
474 public:
475     uMenuItemAction(uMenu *M,const tOutput& name,
476                     const tOutput& help );
477 
~uMenuItemAction()478     virtual ~uMenuItemAction(){}
479 
480     virtual void Render(REAL x,REAL y,REAL alpha=1,bool selected=0);
481 
482     virtual void Enter() = 0;
483 protected:
484     tOutput  name_;
485 };
486 
487 // *****************************************************
488 //  Execute function
489 // *****************************************************
490 
491 
492 class uMenuItemFunction: public uMenuItemAction{
493     FUNCPTR  func;
494 public:
495     uMenuItemFunction(uMenu *M,const tOutput& name,
496                       const tOutput& help,FUNCPTR f);
497 
~uMenuItemFunction()498     virtual ~uMenuItemFunction(){}
499 
500     virtual void Enter();
501 };
502 
503 
504 class uMenuItemFunctionInt: public uMenuItemAction{
505     INTFUNCPTR  func;
506     int         arg;
507 public:
508     uMenuItemFunctionInt(uMenu *M,const tOutput& name,
509                          const tOutput& help,INTFUNCPTR f,int arg);
510 
~uMenuItemFunctionInt()511     virtual ~uMenuItemFunctionInt(){}
512 
513     virtual void Enter();
514 };
515 
516 // *****************************************************
517 //  File Selection (added by k)
518 // *****************************************************
519 
520 class uMenuItemFileSelection: public uMenuItemSelection<tString>
521 {
522     void NewChoice( uSelectItem<bool> * );
523     void NewChoice( char *, bool );
524 protected:
525     tString dir_;
526     tString fileSpec_;
527     int     getFilesFlag_;
528     bool    formatName_;
529     tString defaultFileName_;
530     tString defaultFilePath_;
531 public:
532     uMenuItemFileSelection( uMenu *m, char *tit, const char *help, tString& targ,
533                             const char *dir, const char *fileSpec, int getFilesFlag = 0, bool formatName = true )
534             :uMenuItemSelection<tString>( m, tit, help, targ )
535     {
536         SetParams( dir, fileSpec, getFilesFlag, formatName, "", "" );
537         Reload();
538     }
539 
540     uMenuItemFileSelection( uMenu *m, char *tit, const char *help, tString& targ,
541                             const char *dir, const char *fileSpec,
542                             const char *defaultFileName, const char *defaultFilePath,
543                             int getFilesFlag = 0, bool formatName = true )
544             :uMenuItemSelection<tString>( m, tit, help, targ )
545     {
546         SetParams( dir, fileSpec, getFilesFlag, formatName, defaultFileName, defaultFilePath );
547         Reload();
548     }
549 
~uMenuItemFileSelection()550     virtual ~uMenuItemFileSelection() {}
551 
SetDir(const char * dir)552     void SetDir( const char *dir ) { dir_ = dir; }
SetFileSpec(const char * fileSpec)553     void SetFileSpec( const char *fileSpec ) { fileSpec_ = fileSpec; }
SetFormatName(bool formatName)554     void SetFormatName( bool formatName ) { formatName_ = formatName; }
SetGetFilesFlag(int getFilesFlag)555     void SetGetFilesFlag( int getFilesFlag ) { getFilesFlag_ = getFilesFlag; }
SetDefaultFileName(const char * defaultFileName)556     void SetDefaultFileName( const char *defaultFileName ) { defaultFileName_ = defaultFileName; }
SetDefaultFilePath(const char * defaultFilePath)557     void SetDefaultFilePath( const char *defaultFilePath ) { defaultFilePath_ = defaultFilePath; }
558 
SetParams(const char * dir,const char * fileSpec,int getFilesFlag,bool formatName,const char * defaultFileName,const char * defaultFilePath)559     void SetParams( const char *dir, const char *fileSpec, int getFilesFlag,
560                     bool formatName, const char *defaultFileName, const char *defaultFilePath )
561     {
562         SetDir( dir );
563         SetFileSpec( fileSpec );
564         SetGetFilesFlag( getFilesFlag );
565         SetFormatName( formatName );
566         SetDefaultFileName( defaultFileName );
567         SetDefaultFilePath( defaultFilePath );
568     }
569 
570     void Reload();
571 
572     void LoadDirectory( const char *dir, const char *fileSpec, bool formatName = true );
573 
574     void AddFile( const char *fileName, const char *filePath, bool formatName = true );
575 };
576 
577 // *****************************************************
578 // Menu Enter/Leave-Callback
579 // *****************************************************
580 
581 class uCallbackMenuEnter: public tCallback{
582 public:
583     uCallbackMenuEnter(VOIDFUNC *f);
584     static void MenuEnter();
585 };
586 
587 class uCallbackMenuLeave: public tCallback{
588 public:
589     uCallbackMenuLeave(VOIDFUNC *f);
590     static void MenuLeave();
591 };
592 
593 class uCallbackMenuBackground: public tCallback{
594 public:
595     uCallbackMenuBackground(VOIDFUNC *f);
596     static void MenuBackground();
597 };
598 
599 
AddItem(uMenuItem * item)600 inline void uMenu::AddItem(uMenuItem* item)     { items.Add(item, item->idnum); }
RemoveItem(uMenuItem * item)601 inline void uMenu::RemoveItem(uMenuItem* item)  { items.Remove(item, item->idnum); }
602 
603 #endif
604 
605