00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "tSysTime.h"
00030 #include "uMenu.h"
00031 #include "rSysdep.h"
00032 #include "rScreen.h"
00033 #include "rViewport.h"
00034 #include "rTexture.h"
00035 #include "tRecorder.h"
00036 #include "tString.h"
00037 #include "math.h"
00038 #include "uInputQueue.h"
00039 #include "rConsole.h"
00040 #include "uInput.h"
00041 #include "tDirectories.h"
00042
00043 #include "tToDo.h"
00044 #include "tException.h"
00045 #include <iterator>
00046
00047 #ifndef DEDICATED
00048 #include "rRender.h"
00049 #include "rSDL.h"
00050 #endif
00051
00052 #include <vector>
00053
00054 FUNCPTR uMenu::idle(NULL);
00055
00056 bool uMenu::wrap=true;
00057 bool uMenu::quickexit=false;
00058 bool uMenu::exitToMain=false;
00059
00060
00061
00062 #ifdef SLOPPYLOCALE
00063 uMenu::uMenu(const char *t="",bool exit_item)
00064 :exitFlag(0),spaceBelow(.4),title(t){
00065 if (exit_item) new uMenuItemExit(this);
00066 center=0;
00067 menuTop=.7;
00068 menuBot=-.7;
00069 yOffset=0;
00070 selected = 10000000;
00071 }
00072 #endif
00073
00074 uMenu::uMenu(const tOutput &t,bool exit_item)
00075 :exitFlag(0),spaceBelow(.4),title(t){
00076 if (exit_item) new uMenuItemExit(this);
00077 center=0;
00078 menuTop=.7;
00079 menuBot=-.7;
00080 yOffset=0;
00081 selected = 100000000;
00082 }
00083
00084 uMenu::~uMenu(){
00085 for (int i=items.Len()-1;i>=0;i--)
00086 delete items[i];
00087 }
00088
00089 void uMenu::ReverseItems(){
00090 tList<uMenuItem> dummy = items;
00091 items.SetLen(0);
00092
00093 for (int i=dummy.Len()-1; i>=0; i--){
00094 uMenuItem *x = dummy[i];
00095 dummy.Remove(x, x->idnum);
00096 items.Add (x, x->idnum);
00097 }
00098 }
00099
00100
00101
00102
00103 static REAL text_height=.11;
00104
00105 #ifndef DEDICATED
00106 static REAL titlefac=1.2;
00107 #endif
00108 int menuentries=0;
00109
00110 REAL uMenu::YPos(int num){
00111 return yOffset-text_height*(menuentries-num);
00112 }
00113
00114
00115 static inline void arrow(REAL x,REAL y,REAL dy,REAL size){
00116 #ifndef DEDICATED
00117 if (sr_glOut){
00118 BeginLineLoop();
00119 Vertex(x,y+2*dy*size);
00120 Vertex(x+size,y);
00121 Vertex(x+.3*size,y);
00122 Vertex(x+.3*size,y-2*dy*size);
00123 Vertex(x-.3*size,y-2*dy*size);
00124 Vertex(x-.3*size,y);
00125 Vertex(x-size,y);
00126 RenderEnd();
00127 }
00128 #endif
00129 }
00130
00131 static bool repeat = false;
00132
00133 #ifndef DEDICATED
00134 static bool disphelp=false;
00135 static REAL lastkey;
00136 #endif
00137
00138
00139 static bool su_inMenu = false;
00140 bool uMenu::MenuActive()
00141 {
00142 return su_inMenu;
00143 }
00144 static rNoAutoDisplayAtNewlineCallback su_noNewline( uMenu::MenuActive );
00145
00146
00147 void uMenu::OnEnter(){
00148 #ifndef DEDICATED
00149 float nextrepeat = 0.0f;
00150 static const float repeatdelay = 0.3f;
00151 static const float repeatrate = 0.05f;
00152 SDL_Event tEventRepeat;
00153 #else
00154 return;
00155 #endif
00156
00157
00158 su_ClearKeys();
00159
00160 uCallbackMenuEnter::MenuEnter();
00161 su_inMenu = true;
00162
00163 if (items.Len()<=0)
00164 return;
00165
00166 exitFlag=0;
00167 yOffset=menuTop;
00168 REAL lastt=0;
00169 REAL ts=0;
00170
00171 #ifndef DEDICATED
00172 lastkey=tSysTimeFloat();
00173 static const REAL timeout=3;
00174 #endif
00175
00176 selected = GetPrevSelectable(0);
00177 while (!exitFlag && !quickexit && !exitToMain){
00178 st_DoToDo();
00179 tAdvanceFrame();
00180
00181 ts=tSysTimeFloat()-lastt;
00182 lastt=tSysTimeFloat();
00183 if (ts>.2) ts=.2;
00184
00185 menuentries=items.Len();
00186
00187
00188 if (selected < 0 )
00189 selected = 0;
00190 if ( selected >= items.Len())
00191 selected = items.Len()-1;
00192
00193 #ifndef DEDICATED
00194 {
00195 SDL_Event tEvent;
00196 uInputProcessGuard inputProcessGuard;
00197 while (su_GetSDLInput(tEvent))
00198 {
00199 REAL entertime = tSysTimeFloat();
00200
00201 switch (tEvent.type)
00202 {
00203 case SDL_KEYDOWN:
00204 repeat = true;
00205 memcpy( &tEventRepeat, &tEvent, sizeof( SDL_Event ) );
00206 nextrepeat = tSysTimeFloat() + repeatdelay;
00207 break;
00208 case SDL_KEYUP:
00209 repeat = false;
00210 break;
00211 }
00212
00213 this->HandleEvent( tEvent );
00214
00215
00216 if ( quickexit )
00217 break;
00218
00219 if ( tSysTimeFloat() - entertime > 1 )
00220 {
00221 repeat = false;
00222 }
00223 }
00224
00225 if ( repeat && tSysTimeFloat() > nextrepeat )
00226 {
00227 this->HandleEvent( tEventRepeat );
00228 nextrepeat = tSysTimeFloat() + repeatrate;
00229 }
00230 }
00231
00232
00233 OnRender();
00234
00235
00236 if (selected < 0 )
00237 selected = 0;
00238 if ( selected >= items.Len())
00239 selected = items.Len()-1;
00240 #endif
00241
00242 if ( quickexit )
00243 break;
00244
00245
00246 menuBot=-1+spaceBelow;
00247
00248 const REAL border=.3;
00249 const REAL smallborder=.1;
00250
00251 menuentries=items.Len();
00252
00253 REAL ysel=YPos(selected);
00254
00255 if (ysel<menuBot+border)
00256 yOffset+=(menuBot+border-ysel)*6*ts;
00257
00258 if (ysel>menuTop-border)
00259 yOffset+=(menuTop-border-ysel)*6*ts;
00260
00261 if (ysel<menuBot)
00262 yOffset+=(menuBot-ysel);
00263
00264 if (ysel>menuTop-smallborder)
00265 yOffset+=(menuTop-smallborder-ysel);
00266
00267 if (YPos(0)>menuBot+smallborder)
00268 yOffset+=menuBot+smallborder-YPos(0);
00269
00270 if (YPos(menuentries-1)<menuTop-smallborder)
00271 yOffset+=menuTop-smallborder-YPos(menuentries-1);
00272
00273 #ifndef DEDICATED
00274 sr_ResetRenderState(true);
00275 items[selected]->RenderBackground();
00276
00277 if (selected >= items.Len()) selected = items.Len()-1;
00278 if (items.Len() <= 0)
00279 return;
00280
00281 if (sr_glOut && !exitFlag && !quickexit){
00282 items[selected]->Render(center,YPos(selected),1,true);
00283
00284 for (int i=items.Len()-1;i>=0;i--)
00285 if (i!=selected){
00286 REAL y=YPos(i);
00287 REAL alpha=1;
00288 const REAL b=.1;
00289 if (y<menuBot+b)
00290 alpha=(y-menuBot)/b;
00291 if (y>menuTop-b)
00292 alpha=(menuTop-y)/b;
00293 if (y>menuBot && y<menuTop)
00294 {
00295 rTextField::SetDefaultColor( tColor(1,1,1,1) );
00296 rTextField::SetBlendColor( tColor(1,1,1,1) );
00297 items[i]->Render(center,y,alpha,false);
00298 }
00299 }
00300
00301 rTextField::SetDefaultColor( tColor(1,1,1,1) );
00302 rTextField::SetBlendColor( tColor(1,1,1,1) );
00303
00304 Color(.6,.6,1,1);
00305 ::DisplayText(0,menuTop+text_height*titlefac
00306 ,text_height*titlefac,
00307 title,sr_fontMenuTitle,0);
00308
00309 glDisable(GL_TEXTURE_2D);
00310
00311 Color(1,.2,.2,.5);
00312 if (YPos(0)<menuBot+smallborder && (int(tSysTimeFloat()))%2)
00313 arrow(.9,menuBot+.1,-1,.05);
00314 if (YPos(menuentries-1)>menuTop && (int(tSysTimeFloat())+1)%2)
00315 arrow(.9,menuTop,1,.05);
00316
00317 if (tSysTimeFloat()-lastkey>timeout){
00318 disphelp=true;
00319 if (sr_alphaBlend)
00320 glColor4f(1,.8,.8,tSysTimeFloat()-lastkey-timeout);
00321 else
00322 Color(tSysTimeFloat()-lastkey-timeout,
00323 .8*(tSysTimeFloat()-lastkey-timeout),
00324 .8*(tSysTimeFloat()-lastkey-timeout));
00325
00326 rTextField c(-.95f,menuBot-.04f,rCHEIGHT_NORMAL, sr_fontMenu);
00327 c.SetWidth(1.9f-items[selected]->SpaceRight());
00328 c.EnableLineWrap();
00329 c << items[selected]->Help();
00330 }
00331 else disphelp=false;
00332 }
00333 else
00334 #endif
00335 if ( !sr_glOut )
00336 {
00337 tDelay( 10000 );
00338 }
00339
00340 #ifndef DEDICATED
00341 rSysDep::SwapGL();
00342 rSysDep::ClearGL();
00343 #endif
00344 }
00345
00346 repeat = false;
00347
00348 uCallbackMenuLeave::MenuLeave();
00349 su_inMenu = false;
00350 }
00351
00352 void uMenu::HandleEvent( SDL_Event event )
00353 {
00354 #ifndef DEDICATED
00355 if (!items[selected]->Event(event))
00356 {
00357
00358 switch (event.type){
00359 case SDL_KEYDOWN:
00360 {
00361 if (!disphelp)
00362 lastkey=tSysTimeFloat();
00363 switch (event.key.keysym.sym){
00364
00365 case(SDLK_ESCAPE):
00366 repeat = false;
00367 lastkey=tSysTimeFloat();
00368 Exit();
00369 break;
00370
00371 case(SDLK_UP):
00372 lastkey=tSysTimeFloat();
00373 selected = GetNextSelectable(selected);
00374 break;
00375 case(SDLK_DOWN):
00376 lastkey=tSysTimeFloat();
00377 selected = GetPrevSelectable(selected);
00378 break;
00379
00380 case(SDLK_LEFT):
00381 items[selected]->LeftRight(-1);
00382 break;
00383 case(SDLK_RIGHT):
00384 items[selected]->LeftRight(1);
00385 break;
00386
00387 case(SDLK_SPACE):
00388 case(SDLK_KP_ENTER):
00389 case(SDLK_RETURN):
00390 repeat = false;
00391 try
00392 {
00393 su_inMenu = false;
00394 items[selected]->Enter();
00395 }
00396 catch (tException const & e)
00397 {
00398 uMenu::SetIdle(NULL);
00399
00400
00401 tConsole::Message( e.GetName(), e.GetDescription(), 20 );
00402 }
00403 #ifdef _MSC_VER
00404 #pragma warning ( disable : 4286 )
00405
00406
00407 catch ( tGenericException const & e )
00408 {
00409 try
00410 {
00411 tConsole::Message( e.GetName(), e.GetDescription(), 20 );
00412 }
00413 catch (...)
00414 {
00415 }
00416 }
00417 #endif
00418
00419 su_inMenu = true;
00420
00421 repeat = false;
00422 lastkey=tSysTimeFloat();
00423 break;
00424
00425 default:
00426
00427 su_HandleEvent( event, true );
00428 break;
00429 }
00430 }
00431 break;
00432 default:
00433
00434 su_HandleEvent( event, true );
00435 break;
00436 }
00437 }
00438
00439 su_inMenu = true;
00440 #endif
00441 }
00442
00443
00444 int uMenu::GetPrevSelectable(int start)
00445 {
00446 int prev = start-1;
00447 while (prev!=start)
00448 {
00449 if (prev<0)
00450 {
00451 if (wrap)
00452 prev = items.Len()-1;
00453 else
00454 break;
00455 }
00456 if (items[prev]->IsSelectable())
00457 {
00458 return prev;
00459 }
00460 prev--;
00461 }
00462 return start;
00463 }
00464
00465
00466 int uMenu::GetNextSelectable(int start)
00467 {
00468 int next = start+1;
00469 while (next!=start)
00470 {
00471 if (next>=items.Len())
00472 {
00473 if (this->wrap)
00474 next = 0;
00475 else
00476 break;
00477 }
00478 if (items[next]->IsSelectable())
00479 {
00480 return next;
00481 }
00482 next++;
00483 }
00484 return start;
00485 }
00486
00487
00488
00489 void uMenu::GenericBackground(){
00490 #ifndef DEDICATED
00491 if (idle)
00492 {
00493 try
00494 {
00495
00496 (*idle)();
00497 }
00498 catch ( ... )
00499 {
00500
00501 idle = 0;
00502 throw;
00503 }
00504 }
00505 else if (sr_glOut){
00506 uCallbackMenuBackground::MenuBackground();
00507 }
00508 else
00509 tDelay(100000);
00510 #endif
00511 sr_ResetRenderState(true);
00512 }
00513
00514
00515 void uMenu::OnExit(){
00516 exitFlag=1;
00517 }
00518
00520 void uMenu::OnRender()
00521 {
00522 }
00523
00524
00525
00526
00527
00528
00529
00530
00535
00536
00537 void uMenuItem::SetColor( bool selected, REAL alpha )
00538 {
00539
00540 rTextField::SetDefaultColor( tColor(1,1,1,alpha) );
00541
00542 if (selected)
00543 {
00544 REAL time=tSysTimeFloat()*10;
00545 REAL intensity = 1+.3*sin(time);
00546 rTextField::SetDefaultColor( tColor(.8,.3,.3,alpha) );
00547 rTextField::SetBlendColor( tColor(intensity,intensity,intensity,alpha) );
00548 }
00549 }
00550
00551 void uMenuItem::DisplayText(REAL x,REAL y,const char *text,
00552 bool selected,REAL alpha,
00553 int center,int c,int cp, rTextField::ColorMode colorMode, float maxWidth ){
00554 #ifndef DEDICATED
00555 if (sr_glOut){
00556 SetColor( selected, alpha );
00557
00558 REAL th = text_height;
00559
00560 REAL availw = 1.9f;
00561 if (center < 0) availw = (.9f-x);
00562 if (center > 0) availw = (x + .9f);
00563 if (availw > maxWidth) availw = maxWidth;
00564
00565 float usedwidth=rTextField::GetTextLength(tString(text), th, colorMode == rTextField::COLOR_USE);
00566 if (usedwidth > availw)
00567 {
00568 th *= availw/(usedwidth);
00569 }
00570
00571 ::DisplayText(x,y,th,text,sr_fontMenu,center,c,cp, colorMode);
00572 }
00573 #endif
00574 }
00575
00576 void uMenuItem::DisplayTextSpecial(REAL x,REAL y,const char *text,
00577 bool selected,
00578 REAL alpha,int center){
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588 DisplayText(x,y,text,selected,alpha,center);
00589 }
00590
00591
00592
00593 const tOutput& uMenuItemExit::ExitText()
00594 {
00595 static tOutput exitText("$menuitem_exit_text");
00596
00597 return exitText;
00598 }
00599
00600 const tOutput& uMenuItemExit::ExitHelp()
00601 {
00602 static tOutput exitHelp("$menuitem_exit_help");
00603
00604 return exitHelp;
00605 }
00606
00607
00608
00609 void uMenuItemToggle::NewChoice(uSelectItem<bool> *){}
00610 void uMenuItemToggle::NewChoice(const char *,bool ){}
00611
00612 #ifdef SLOPPYLOCALE
00613 uMenuItemToggle::uMenuItemToggle(uMenu *m,
00614 const char *tit,
00615 const char *help,
00616 bool &targ)
00617 :uMenuItemSelection<bool>(m,tit,help,targ){
00618 uMenuItemSelection<bool>::NewChoice("$menuitem_toggle_on","",true);
00619 uMenuItemSelection<bool>::NewChoice("$menuitem_toggle_off","",false);
00620 }
00621 #endif
00622
00623 uMenuItemToggle::uMenuItemToggle(uMenu *m,
00624 const tOutput& tit,
00625 const tOutput& help,
00626 bool &targ)
00627 :uMenuItemSelection<bool>(m,tit,help,targ){
00628 uMenuItemSelection<bool>::NewChoice("$menuitem_toggle_on","",true);
00629 uMenuItemSelection<bool>::NewChoice("$menuitem_toggle_off","",false);
00630 }
00631
00632 uMenuItemToggle::~uMenuItemToggle(){}
00633
00634 void uMenuItemToggle::LeftRight(int){
00635 select=1-select;
00636 *target=!(*target);
00637 }
00638
00639 void uMenuItemToggle::Enter(){
00640 LeftRight(0);
00641 }
00642
00643
00644
00645
00646 #ifdef SLOPPYLOCALE
00647 uMenuItemInt::uMenuItemInt
00648 (uMenu *m,const char *tit,const char *help,int &targ,
00649 int mi,int ma,int step)
00650 :uMenuItem(m,help),title(tit),target(targ),Min(mi),Max(ma),
00651 Step(step){
00652 if (target<Min) target=Min;
00653 if (target>Max) target=Max;
00654 }
00655 #endif
00656
00657 uMenuItemInt::uMenuItemInt
00658 (uMenu *m,const tOutput &tit,const tOutput &help,int &targ,
00659 int mi,int ma,int step)
00660 :uMenuItem(m,help),title(tit),target(targ),Min(mi),Max(ma),
00661 Step(step){
00662 if (target<Min) target=Min;
00663 if (target>Max) target=Max;
00664 }
00665
00666
00667 void uMenuItemInt::LeftRight(int dir){
00668 target+=dir*Step;
00669 if (target<Min) target=Min;
00670 if (target>Max) target=Max;
00671 }
00672
00673 void uMenuItemInt::Render(REAL x,REAL y,REAL alpha,
00674 bool selected){
00675 DisplayText(x-.02,y,title,selected,alpha,1);
00676
00677 tString s;
00678 s << target;
00679 DisplayText(x+.02,y,s,selected,alpha,-1);
00680 }
00681
00682
00683
00684
00685 uMenuItemString::uMenuItemString(uMenu *M,
00686 const tOutput& de,
00687 const tOutput& help,
00688 tString &c,
00689 int maxLength )
00690 :uMenuItem(M,help),description(de),content(&c),cursorPos(0), maxLength_( maxLength ){
00691
00692
00693
00694 cursorPos=content->Len()-1;
00695 colorMode_ = rTextField::COLOR_SHOW;
00696 }
00697
00698 void uMenuItemString::Render(REAL x,REAL y,
00699 REAL alpha,bool selected){
00700 #ifndef DEDICATED
00701 static int counter=0;
00702 counter++;
00703
00704 int cmode=0;
00705 if (selected){
00706 cmode=1;
00707 if (counter & 32) cmode=2;
00708 }
00709
00710
00711 rTextField::ColorMode colorMode = colorMode_;
00712 if ( colorMode == rTextField::COLOR_SHOW && !selected )
00713 colorMode = rTextField::COLOR_USE;
00714
00715 DisplayText(x-.02,y,description,selected,alpha,1);
00716 DisplayText(x+.02,y,*content,selected,alpha,-1,cmode,cursorPos,colorMode);
00717 #endif
00718 }
00719
00720 bool uMenuItemString::Event(SDL_Event &e){
00721 #ifndef DEDICATED
00722 if (e.type!=SDL_KEYDOWN)
00723 return false;
00724 bool ret=true;
00725 SDL_keysym &c=e.key.keysym;
00726 SDLMod mod = c.mod;
00727 bool moveWordLeft, moveWordRight, deleteWordLeft, deleteWordRight, moveBeginning, moveEnd, killForwards;
00728 moveWordLeft = moveWordRight = deleteWordLeft = deleteWordRight = moveBeginning = moveEnd = killForwards = false;
00729
00730 #if defined (MACOSX)
00731
00732 if (mod & KMOD_ALT) {
00733 if (c.sym == SDLK_LEFT) {
00734 moveWordLeft = true;
00735 }
00736 else if (c.sym == SDLK_RIGHT) {
00737 moveWordRight = true;
00738 }
00739 else if (c.sym == SDLK_DELETE) {
00740 deleteWordRight = true;
00741 }
00742 else if (c.sym == SDLK_BACKSPACE) {
00743 deleteWordLeft = true;
00744 }
00745 }
00746
00747 else if (mod & KMOD_META) {
00748 if (c.sym == SDLK_LEFT) {
00749 moveBeginning = true;
00750 }
00751 else if (c.sym == SDLK_RIGHT) {
00752 moveEnd = true;
00753 }
00754 }
00755
00756 #else
00757
00758 if (mod & KMOD_CTRL) {
00759 if (c.sym == SDLK_LEFT) {
00760 moveWordLeft = true;
00761 }
00762 else if (c.sym == SDLK_RIGHT) {
00763 moveWordRight = true;
00764 }
00765 else if (c.sym == SDLK_DELETE) {
00766 deleteWordRight = true;
00767 }
00768 else if (c.sym == SDLK_BACKSPACE) {
00769 deleteWordLeft = true;
00770 }
00771 }
00772 else if (c.sym == SDLK_HOME) {
00773 moveBeginning = true;
00774 }
00775 else if (c.sym == SDLK_END) {
00776 moveEnd = true;
00777 }
00778 #endif
00779
00780 if (mod & KMOD_CTRL) {
00781 if (c.sym == SDLK_a) {
00782 moveBeginning = true;
00783 }
00784 else if (c.sym == SDLK_e) {
00785 moveEnd = true;
00786 }
00787 else if (c.sym == SDLK_k) {
00788 killForwards = true;
00789 }
00790 }
00791
00792
00793 if (moveWordLeft) {
00794 cursorPos += content->PosWordLeft(cursorPos);
00795 }
00796 else if (moveWordRight) {
00797 cursorPos += content->PosWordRight(cursorPos);
00798 }
00799 else if (deleteWordLeft) {
00800 cursorPos += content->RemoveWordLeft(cursorPos);
00801 }
00802 else if (deleteWordRight) {
00803 content->RemoveWordRight(cursorPos);
00804 }
00805 else if (moveBeginning) {
00806 cursorPos = 0;
00807 }
00808 else if (moveEnd) {
00809 cursorPos = content->Len()-1;
00810 }
00811 else if (killForwards) {
00812 content->RemoveSubStr(cursorPos,content->Len()-1-cursorPos);
00813 }
00814 else if (c.sym == SDLK_LEFT) {
00815 if (cursorPos > 0) {
00816 cursorPos--;
00817 }
00818 }
00819 else if (c.sym == SDLK_RIGHT) {
00820 if (cursorPos < content->Len()-1) {
00821 cursorPos++;
00822 }
00823 }
00824 else if (c.sym == SDLK_DELETE) {
00825 if (cursorPos < content->Len()-1) {
00826 content->RemoveSubStr(cursorPos,1);
00827 }
00828 }
00829 else if (c.sym == SDLK_BACKSPACE) {
00830 if (cursorPos > 0) {
00831 content->RemoveSubStr(cursorPos,-1);
00832 cursorPos--;
00833 }
00834 }
00835 else if (c.sym == SDLK_KP_ENTER || c.sym == SDLK_RETURN) {
00836 ret = false;
00837
00838 }
00839 else {
00840 if (32 <= c.unicode && c.unicode < 256)
00841 {
00842 ret=true;
00843
00844
00845 if (content->Len() < maxLength_)
00846 {
00847 tString beg = content->SubStr(0,cursorPos);
00848 tString end = content->SubStr(cursorPos);
00849 *content = beg;
00850 *content += tString::CHAR(c.unicode);
00851 *content += end;
00852 cursorPos++;
00853 }
00854 }
00855 else {
00856 ret=false;
00857 }
00858 }
00859
00860 if (cursorPos<0) cursorPos=0;
00861 if (cursorPos > content->Len()-1) cursorPos=content->Len()-1;
00862
00863 return ret;
00864 #else
00865 return false;
00866 #endif
00867 }
00868
00870 uAutoCompleter::uAutoCompleter(std::deque<tString> &words) :
00871 m_PossibleWords(words),
00872 m_LastCompletion(-1),
00873 m_ignorecase(true)
00874 {}
00875
00879 int uAutoCompleter::FindLengthOfLastWord(tString &string, unsigned pos) {
00880 int charright = ' ', charleft = ' ';
00881 if(string.size() >= 1) {
00882 if (pos == string.size()) {
00883 charleft=string.at(pos-1);
00884 }
00885 else if (pos < string.size()) {
00886 charright=string.at(pos);
00887 if(pos>1) {
00888 charleft=string.at(pos-1);
00889 }
00890 }
00891 }
00892 if(charright != ' ' && charleft != ' ')
00893 return -1;
00894 if(charleft == ' ')
00895 return 0;
00896 else
00897 return pos - string.find_last_of(' ', pos - 1) - 1;
00898 }
00899
00902 void uAutoCompleter::FindPossibleWords(tString word, std::deque<tString> &results) {
00903 if(m_ignorecase)
00904 word = Simplify(word);
00905 for(std::deque<tString>::iterator i=m_PossibleWords.begin(); i!=m_PossibleWords.end(); ++i) {
00906 size_t pos;
00907 if((pos = (m_ignorecase ? Simplify(*i) : *i).find(word)) != tString::npos) {
00908 if(isalpha((*i)[pos]) && pos != 0 && isalpha((*i)[pos-1]))
00909 continue;
00910 results.push_back(*i);
00911 }
00912 }
00913 }
00914
00918 tString uAutoCompleter::FindClosestMatch(tString &word, std::deque<tString> &results) {
00919 tString ret(m_ignorecase?Simplify(word):word);
00920 unsigned int len = ret.size();
00921 while(true) {
00922 std::deque<tString>::iterator i;
00923 i = results.begin();
00924 bool found=true;
00925 tString::size_type pos=(m_ignorecase?Simplify(*i):*i).find(ret);
00926 if(pos!=tString::npos && pos+len < i->size()) {
00927 found=false;
00928 ret+=(m_ignorecase ? tolower(i->at(pos+len)) : i->at(pos+len));
00929 ++i;
00930 for(; i!=results.end(); ++i) {
00931 if((m_ignorecase?Simplify(*i):*i).find(ret) == tString::npos) {
00932 found=true;
00933 ret.erase(ret.length()-1);
00934 break;
00935 }
00936 }
00937 }
00938 if (found)
00939 break;
00940 else
00941 len++;
00942 }
00943 while(true) {
00944 std::deque<tString>::iterator i;
00945 i = results.begin();
00946 bool found=true;
00947 tString::size_type pos=(m_ignorecase?Simplify(*i):*i).find(ret);
00948 if(pos!=tString::npos && pos > 0) {
00949 found=false;
00950 ret.insert(ret.begin(),(m_ignorecase ? tolower(i->at(pos-1)) : i->at(pos-1)));
00951 ++i;
00952 for(; i!=results.end(); ++i) {
00953 if((m_ignorecase?Simplify(*i):*i).find(ret) == tString::npos) {
00954 found=true;
00955 ret.erase(0,1);
00956 break;
00957 }
00958 }
00959 }
00960 if (found)
00961 break;
00962 else
00963 len++;
00964 }
00965 return ret;
00966 }
00967
00970 void uAutoCompleter::ShowPossibilities(std::deque<tString> &results, tString &word) {
00971 if(results.size() > 10) {
00972 con << tOutput("$tab_completion_toomanyresults");
00973 }
00974 else {
00975 con << tOutput("$tab_completion_results");
00976 tString::size_type len=word.length();
00977 for(std::deque<tString>::iterator i=results.begin(); i!=results.end(); ++i) {
00978 tString::size_type pos=(m_ignorecase?Simplify(*i):*i).find(word);
00979 con << i->SubStr(0,pos)
00980 << "0xff8888"
00981 << i->SubStr(pos, len)
00982 << "0xffffff"
00983 << i->SubStr(pos+len)
00984 << "\n";
00985 }
00986 }
00987 }
00988
00994 int uAutoCompleter::DoCompletion(tString &string, int pos, int len, tString &match) {
00995 string.erase(pos-len, len);
00996 string.insert(pos-len, match);
00997 return pos - len + match.size();
00998 }
00999
01005 int uAutoCompleter::DoFullCompletion(tString &string, int pos, int len, tString &match) {
01006 tString actualString = match + " ";
01007 return DoCompletion(string, pos, len, actualString);
01008 }
01009
01014 int uAutoCompleter::TryCompletion(tString &string, unsigned pos, unsigned len) {
01015 tString word(string.SubStr(pos-len, len));
01016 std::deque<tString> results;
01017 FindPossibleWords(word, results);
01018 if(results.size() > 1){
01019 tString match(FindClosestMatch(word, results));
01020 if(match == word) {
01021 ShowPossibilities(results, word);
01022 return pos;
01023 }
01024 else {
01025 return DoCompletion(string, pos, len, match);
01026 }
01027 }
01028 else if(!results.empty()){
01029 return DoFullCompletion(string, pos, len, results.front());
01030 }
01031 return -1;
01032 }
01033
01037 int uAutoCompleter::Complete(tString &string, unsigned pos) {
01038 if(m_LastCompletion != -1 && (unsigned)m_LastCompletion < pos) {
01039 int res = TryCompletion(string, pos, pos - m_LastCompletion);
01040 if(res != -1) return res;
01041 }
01042 int len = FindLengthOfLastWord(string, pos);
01043 if(len == -1) return pos;
01044 int res = TryCompletion(string, pos, len);
01045 if(res != -1) {
01046 m_LastCompletion = pos - len;
01047 return res;
01048 }
01049 return pos;
01050 }
01051
01053 void uAutoCompleter::SetIgnorecase(bool ignorecase) {
01054 m_ignorecase = ignorecase;
01055 }
01056
01059 tString uAutoCompleter::Simplify(tString const &str) {
01060 return str.ToLower();
01061 }
01062
01071 uMenuItemStringWithHistory::uMenuItemStringWithHistory(uMenu *M,const tOutput& desc, const tOutput& help,tString &c, int maxLength, history_t &history, int limit, uAutoCompleter *completer ):
01072 uMenuItemString(M, desc,help,c, maxLength ),
01073 m_History(history),
01074 m_HistoryPos(0),
01075 m_HistoryLimit(limit),
01076 m_Completer(completer),
01077 m_Searchmode(false) {
01078 m_History.push_front(tString());
01079 }
01080
01082 uMenuItemStringWithHistory::~uMenuItemStringWithHistory() {
01083 if(content->Len() > 1){
01084 for(history_t::iterator i=m_History.begin(); i!=m_History.end(); ++i) {
01085 if(*i == *content) {
01086 m_History.erase(i);
01087 break;
01088 }
01089 }
01090 m_History.front() = *content;
01091 } else {
01092 m_History.pop_front();
01093 }
01094 if(m_History.size() > m_HistoryLimit)
01095 m_History.pop_back();
01096 }
01097
01100 bool uMenuItemStringWithHistory::Event(SDL_Event &e){
01101 #ifndef DEDICATED
01102 if (e.type==SDL_KEYDOWN &&
01103 (e.key.keysym.sym==SDLK_UP && !m_Searchmode )){
01104 if (m_History.size() - 1 > m_HistoryPos)
01105 {
01106 if(m_HistoryPos == 0)
01107 m_History.front() = *content;
01108 m_HistoryPos++;
01109 *content = m_History[m_HistoryPos];
01110 cursorPos = content->Len() - 1;
01111 }
01112
01113 return true;
01114 }
01115 else if (e.type==SDL_KEYDOWN &&
01116 (e.key.keysym.sym==SDLK_DOWN && !m_Searchmode)){
01117 if (m_HistoryPos > 0)
01118 {
01119 m_HistoryPos--;
01120 *content = m_History[m_HistoryPos];
01121 cursorPos = content->Len() - 1;
01122 }
01123
01124 return true;
01125 }
01126 else if (e.type==SDL_KEYDOWN && e.key.keysym.mod & KMOD_CTRL && e.key.keysym.sym == SDLK_r ) {
01127 m_Searchmode = true;
01128 if(m_HistoryPos == 0 && !content->empty()) {
01129 m_History.front() = *content;
01130 m_History.push_front(tString());
01131 }
01132 content->erase();
01133 m_HistoryPos++;
01134 cursorPos=0;
01135 m_SearchFailing=false;
01136 return true;
01137 }
01138 else if (e.type==SDL_KEYDOWN &&
01139 (e.key.keysym.sym==SDLK_TAB && !m_Searchmode)){
01140 if(m_Completer != 0) {
01141 cursorPos = m_Completer->Complete(*content, cursorPos);
01142 }
01143
01144 return true;
01145 }
01146 else if (e.type==SDL_KEYDOWN && m_Searchmode) {
01147 if(e.key.keysym.sym==SDLK_LEFT || e.key.keysym.sym==SDLK_RIGHT) {
01148 *content = m_History[m_HistoryPos];
01149 m_Searchmode = false;
01150 cursorPos=0;
01151 return true;
01152 }
01153 bool ret = uMenuItemString::Event(e);
01154 tString searchstring = content->ToLower();
01155 unsigned int pos = 0;
01156 for(history_t::iterator iter = m_History.begin(); iter != m_History.end(); ++iter, ++pos) {
01157 if (iter->ToLower().find(searchstring) != tString::npos) {
01158 m_HistoryPos = pos;
01159 m_SearchFailing=false;
01160 return ret;
01161 }
01162 }
01163 m_SearchFailing=true;
01164 return ret;
01165 }
01166
01167 else
01168 return uMenuItemString::Event(e);
01169 #endif
01170 return false;
01171 }
01172
01173 void uMenuItemStringWithHistory::Render(REAL x,REAL y,REAL alpha,bool selected) {
01174 if(m_Searchmode) {
01175 DisplayText(-.88, y-.1, ((m_SearchFailing ? "Failing reverse search: " : "Reverse search: ") + m_History[m_HistoryPos]).c_str(), selected, alpha, -1);
01176 }
01177 uMenuItemString::Render(x, y, alpha, selected);
01178 }
01179
01181 uMenuItemStringWithHistory::history_t::history_t(char const *filename) : std::deque<tString>(), m_filename(filename) {
01182 tTextFileRecorder the_file ( tDirectories::Var(), m_filename );
01183 while(!the_file.EndOfFile()) {
01184 push_front(the_file.GetLine());
01185 }
01186 }
01187
01188 uMenuItemStringWithHistory::history_t::~history_t() {
01189 std::ofstream the_file;
01190 if(tDirectories::Var().Open( the_file, m_filename)) {
01191 for(reverse_iterator i = rbegin(); i != rend(); ++i) {
01192 the_file << *i << "\n";
01193 }
01194 }
01195 }
01196
01197
01198
01199
01200
01201
01202
01203 uMenuItemSubmenu::uMenuItemSubmenu(uMenu *M,
01204 uMenu *s,
01205 const tOutput& help)
01206 :uMenuItem(M,help),submenu(s){}
01207
01208
01209 void uMenuItemSubmenu::Render(REAL x,REAL y,REAL alpha,bool selected){
01210 DisplayTextSpecial(x,y,submenu->title,selected,alpha,0);
01211 }
01212
01213 void uMenuItemSubmenu::Enter(){
01214 submenu->Enter();
01215 }
01216
01217
01218
01219
01220
01221
01222 uMenuItemAction::uMenuItemAction(uMenu *M,
01223 const tOutput& n, const tOutput& help )
01224 :uMenuItem(M,help),name_(n){}
01225
01226
01227 void uMenuItemAction::Render(REAL x,REAL y,REAL alpha,bool selected){
01228 DisplayTextSpecial(x,y,name_,selected,alpha,0);
01229 }
01230
01231
01232 void uMenuItemAction::Enter()
01233 {
01234 tASSERT( 0 )
01235 }
01236
01237
01238
01239
01240
01241
01242
01243 uMenuItemFunction::uMenuItemFunction(uMenu *M,
01244 const tOutput& n, const tOutput& help,
01245 FUNCPTR f)
01246 :uMenuItemAction(M,n,help),func(f){}
01247
01248 void uMenuItemFunction::Enter(){
01249 (*func)();
01250 }
01251
01252
01253
01254 uMenuItemFunctionInt::uMenuItemFunctionInt(uMenu *M,
01255 const tOutput& n,
01256 const tOutput& help,
01257 INTFUNCPTR f,int a)
01258 :uMenuItemAction(M,n,help),func(f),arg(a){}
01259
01260
01261 void uMenuItemFunctionInt::Enter(){
01262 (*func)(arg);
01263 }
01264
01265
01266
01267
01268
01269 void uMenuItemFileSelection::NewChoice( uSelectItem<bool> * ) {}
01270 void uMenuItemFileSelection::NewChoice( char *, bool ) {}
01271
01272 void uMenuItemFileSelection::Reload()
01273 {
01274 Clear();
01275 if ( defaultFileName_.Len() > 1 && defaultFilePath_.Len() > 1 )
01276 AddFile( defaultFileName_, defaultFilePath_, formatName_ );
01277 LoadDirectory( dir_, fileSpec_, formatName_ );
01278 }
01279
01280 void uMenuItemFileSelection::LoadDirectory( const char *dir, const char *fileSpec,
01281 bool formatName )
01282 {
01283 tArray <tString> files;
01284 tString filePath ( dir );
01285 tDirectories::GetFiles( tString( dir ), tString( fileSpec ), files, getFilesFlag_ );
01286 for ( int i = 0; i < files.Len(); i++ )
01287 {
01288 AddFile( files( i ), filePath + files( i ), formatName );
01289 }
01290 }
01291
01292 void uMenuItemFileSelection::AddFile( const char *fileName, const char *filePath,
01293 bool formatName )
01294 {
01295 tString menuName ( fileName );
01296 if ( formatName )
01297 tDirectories::FileNameToMenuName( fileName, menuName );
01298 uMenuItemSelection<tString>::NewChoice( menuName, "", tString( filePath ) );
01299 }
01300
01301
01302
01303
01304
01305 static tCallback *enter_anchor=NULL,*leave_anchor=NULL, *background_anchor=NULL;
01306
01307 uCallbackMenuEnter::uCallbackMenuEnter(AA_VOIDFUNC *f)
01308 :tCallback(enter_anchor,f){}
01309
01310 void uCallbackMenuEnter::MenuEnter(){
01311 Exec(enter_anchor);
01312 }
01313
01314 uCallbackMenuLeave::uCallbackMenuLeave(AA_VOIDFUNC *f)
01315 :tCallback(leave_anchor,f){}
01316
01317 void uCallbackMenuLeave::MenuLeave(){
01318 Exec(leave_anchor);
01319 }
01320
01321 uCallbackMenuBackground::uCallbackMenuBackground(AA_VOIDFUNC *f)
01322 :tCallback(background_anchor,f){}
01323
01324 void uCallbackMenuBackground::MenuBackground(){
01325 Exec(background_anchor);
01326 }
01327
01328
01329 bool uMenu::IdleInput()
01330 {
01331 #ifndef DEDICATED
01332 SDL_Event event;
01333 uInputProcessGuard inputProcessGuard;
01334 while (su_GetSDLInput(event))
01335 {
01336 switch (event.type)
01337 {
01338 case SDL_KEYDOWN:
01339 switch (event.key.keysym.sym)
01340 {
01341 case(SDLK_ESCAPE):
01342 repeat = false;
01343 lastkey=tSysTimeFloat();
01344 return true;
01345 break;
01346 default:
01347 break;
01348 }
01349 default:
01350 break;
01351 }
01352 }
01353 #endif
01354
01355 return false;
01356 }
01357
01358
01359 bool uMenu::Message(const tOutput& message, const tOutput& interpretation, REAL to){
01360 bool ret = true;
01361 #ifdef DEDICATED
01362 con << message << ":\n";
01363 con << interpretation << '\n';
01364 #else
01365
01366 rITexture::UnloadAll();
01367
01368 tAdvanceFrame();
01369
01370 bool textOutBack = sr_textOut;
01371 sr_textOut = false;
01372
01373 FUNCPTR idle_back = idle;
01374 uMenu::SetIdle(NULL);
01375
01376 rTextField::SetDefaultColor( tColor(1,1,1,1) );
01377 rTextField::SetBlendColor( tColor(1,1,1,1) );
01378
01379 rSysDep::ClearGL();
01380 rSysDep::SwapGL();
01381
01382
01383
01384
01385
01386 rSysDep::ClearGL();
01387 rSysDep::SwapGL();
01388
01389 REAL timeout = tSysTimeFloat() + to;
01390 SDL_Event tEvent;
01391
01392
01393 {
01394 uInputProcessGuard inputProcessGuard;
01395 while (su_GetSDLInput(tEvent));
01396 }
01397
01398 {
01399 uInputProcessGuard inputProcessGuard;
01400
01401 unsigned offset = 0;
01402
01403 tString interpretationString;
01404 interpretationString << interpretation << "\n";
01405 std::vector<tString> lines;
01406 int lastNewline = 0;
01407 for (int i = 0; i < interpretationString.Len() - 1; ++i) {
01408 if (interpretationString[i] == '\n' && i != 0) {
01409 lines.push_back(interpretationString.SubStr(lastNewline, i - lastNewline));
01410 lastNewline = i + 1;
01411 }
01412 }
01413 while ( !quickexit &&
01414 (to < 0 || tSysTimeFloat() < timeout)){
01415
01416
01417 if ( su_GetSDLInput(tEvent) && tEvent.type==SDL_KEYDOWN) {
01418 switch (tEvent.key.keysym.sym) {
01419 case SDLK_UP:
01420 if (offset > 0)
01421 offset -= 1;
01422 continue;
01423 case SDLK_DOWN:
01424 offset += 1;
01425 continue;
01426 case SDLK_ESCAPE:
01427 ret = false;
01428 break;
01429 default:
01430 break;
01431 }
01432 break;
01433 }
01434 if ( sr_glOut )
01435 {
01436 sr_ResetRenderState(true);
01437 rViewport::s_viewportFullscreen.Select();
01438
01439 rSysDep::ClearGL();
01440
01441 GenericBackground();
01442
01443 REAL w=16*3/640.0;
01444 REAL h=32*3/480.0;
01445
01446
01447
01448
01449 tString m(message);
01450 int len = m.Len();
01451 if (w * len > 1.8)
01452 {
01453 h = h * 1.8 / (w * len);
01454 w = 1.8 / len;
01455 }
01456
01457 Color(1,1,1);
01458 DisplayText(0,.8,w,message,sr_fontError);
01459
01460 w = 16/640.0;
01461 h = 32/480.0;
01462
01463 if (offset >= lines.size()) offset = lines.size() - 1;
01464 {
01465 rTextField c(-.8,.6, h, sr_fontError);
01466 c.EnableLineWrap();
01467
01468 for (unsigned i = offset; i < lines.size(); ++i)
01469 c << lines[i] << "\n";
01470 }
01471 }
01472 rSysDep::SwapGL();
01473 tAdvanceFrame();
01474 }
01475 }
01476
01477
01478 {
01479 uInputProcessGuard inputProcessGuard;
01480 while (su_GetSDLInput(tEvent));
01481 }
01482
01483 uMenu::SetIdle(idle_back);
01484
01485
01486 rITexture::UnloadAll();
01487
01488 sr_textOut = textOutBack;
01489 #endif
01490
01491 return ret;
01492 }
01493