1 #include "pch.h"
2 #include "common/Def_Str.h"
3 #include "common/Gui_Def.h"
4 #include "../vdrift/pathmanager.h"
5 #include "../vdrift/settings.h"
6 #include "../vdrift/game.h"
7 #include "CGame.h"
8 #include "CGui.h"
9 #include "common/data/CData.h"
10 #include "common/data/TracksXml.h"
11 #include "common/GuiCom.h"
12 #include "common/MultiList2.h"
13 #include "common/Slider.h"
14 #include "../network/gameclient.hpp"
15 #include <boost/filesystem.hpp>
16 #include <OgreTimer.h>
17 #include <MyGUI_Gui.h>
18 #include <MyGUI_TabControl.h>
19 #include <MyGUI_TabItem.h>
20 #include <MyGUI_EditBox.h>
21 #include <MyGUI_Window.h>
22 #include <MyGUI_ImageBox.h>
23 #include <MyGUI_MultiListBox.h>
24 #include <MyGUI_PolygonalSkin.h>
25 #include "../tinyxml/tinyxml2.h"
26 using namespace std;
27 using namespace Ogre;
28 using namespace MyGUI;
29 using namespace tinyxml2;
30
31
32 /// Car list
33
34 // sort . . . . . . . . . . . . . . . . . . . . . .
35 //-----------------------------------------------------------------------------------------------------------
36 /* common sort code, no info only by name */
37 #define sArg const CarL& c2, const CarL& c1
38 #define sortDef bool t = false; if (!c1.ci || !c2.ci) return c1.name > c2.name || t;
39 const int allSortFunc = 5;
40
41 // sorting functions for columns
Sort0(sArg)42 /* 0 name */ bool Sort0 (sArg){ sortDef return c1.name < c2.name || t; }
Sort1(sArg)43 /* 1 speed */ bool Sort1 (sArg){ sortDef return c1.ci->speed < c2.ci->speed || t; }
Sort2(sArg)44 /* 2 year */ bool Sort2 (sArg){ sortDef return c1.ci->year < c2.ci->year || t; }
Sort3(sArg)45 /* 3 type */ bool Sort3 (sArg){ sortDef return c1.ci->type < c2.ci->type || t; }
Sort4(sArg)46 /* 4 rate */ bool Sort4 (sArg){ sortDef return c1.ci->rating < c2.ci->rating || t; }
47
48 // sorting functions array (to access by column index)
49 bool (*CarSort[allSortFunc])(const CarL& c1, const CarL& c2) = {
50 Sort0, Sort1, Sort2, Sort3, Sort4 };
51
52
53 // done every list sort column change or find edit text change
54 // fills gui cars list
55 //-----------------------------------------------------------------------------------------------------------
CarListUpd(bool resetNotFound)56 void CGui::CarListUpd(bool resetNotFound)
57 {
58 bool filter = isChallGui();
59
60 if (carList)
61 { carList->removeAllItems();
62 int ii = 0, si = -1; bool bFound = false;
63
64 // sort
65 int numFunc = min(allSortFunc-1, (int)carList->mSortColumnIndex);
66 std::list<CarL> liCar2 = liCar; // copy
67 liCar2.sort(CarSort[numFunc]);
68 if (carList->mSortUp) liCar2.reverse();
69
70 // original
71 for (std::list<CarL>::iterator i = liCar2.begin(); i != liCar2.end(); ++i)
72 {
73 String name = (*i).name; //, nlow = name; StringUtil::toLowerCase(nlow);
74 //if (sTrkFind == "" || strstr(nlow.c_str(), sTrkFind.c_str()) != 0)
75
76 /// filter for challenge
77 if (!filter || IsChallCar(name))
78 {
79 AddCarL(name, (*i).ci);
80 if (name == pSet->gui.car[0]) { si = ii;
81 carList->setIndexSelected(si);
82 bFound = true; }
83 ++ii;
84 } }
85
86 // not found last car, set last
87 if (resetNotFound && !bFound)
88 pSet->gui.car[0] = carList->getItemNameAt(carList->getItemCount()-1).substr(7);
89
90 if (si > -1) // center
91 carList->beginToItemAt(max(0, si-5));
92 }
93 }
94
AddCarL(string name,const CarInfo * ci)95 void CGui::AddCarL(string name, const CarInfo* ci)
96 {
97 MultiList2* li = carList;
98 CarInfo cci;
99 if (!ci) ci = &cci; // details
100 String clr = data->cars->colormap[ci->type]; if (clr.length() != 7) clr = "#C0D0E0";
101
102 li->addItem(clr+ name); int l = li->getItemCount()-1; //, y = ci->year%100;
103 li->setSubItemNameAt(1,l, gcom->clrsDiff[std::min(8, (int)(ci->speed*0.9f))]+ fToStr(ci->speed,1,3));
104 //li->setSubItemNameAt(2,l, clr+ "\'"+toStr(y/10)+toStr(y%10));
105 li->setSubItemNameAt(2,l, clr+ toStr(ci->year));
106 li->setSubItemNameAt(3,l, clr+ TR("#{CarType_"+ci->type+"}"));
107 }
108
FillCarList()109 void CGui::FillCarList()
110 {
111 liCar.clear();
112 strlist li;
113 PATHMANAGER::DirList(PATHMANAGER::Cars(), li);
114 for (strlist::iterator i = li.begin(); i != li.end(); ++i)
115 {
116 if (boost::filesystem::exists(PATHMANAGER::Cars() + "/" + *i + "/about.txt"))
117 { String s = *i;
118 CarL c; c.name = *i; //c.pA = this;
119 int id = data->cars->carmap[*i];
120 if (id)
121 { c.ci = &data->cars->cars[id-1];
122 liCar.push_back(c);
123 } } }
124 }
125 //-----------------------------------------------------------------------------------------------------------
126
127
128 // ghost filename
129 //
ghostFile(SETTINGS * pSet,string sim_mode,string car)130 string ghostFile(SETTINGS* pSet, string sim_mode, string car)
131 {
132 return PATHMANAGER::Ghosts()+"/" +sim_mode+"/"
133 + pSet->game.track + (pSet->game.track_user ? "_u" : "") + (pSet->game.trackreverse ? "_r" : "")
134 + "_" + car + ".rpl";
135 }
136
GetGhostFile(string * ghCar)137 const String& CGui::GetGhostFile(string* ghCar)
138 {
139 static String file;
140 string sim_mode = pSet->game.sim_mode, car = pSet->game.car[0];
141 file = ghostFile(pSet, sim_mode, car);
142 if (PATHMANAGER::FileExists(file))
143 return file;
144
145 if (!ghCar)
146 return file;
147
148 ///-- if doesnt exist look for other cars, then other sim modes
149
150 // cars list sorted by car speed
151 std::list<CarL> liCar2 = liCar;
152 liCar2.sort(CarSort[1]);
153
154 std::vector<string> cars;
155 for (std::list<CarL>::iterator i = liCar2.begin(); i != liCar2.end(); ++i)
156 {
157 String name = (*i).name;
158 cars.push_back(name);
159 //LogO(name);
160 }
161
162 // find current
163 int i = 0, si = cars.size(), ci = 0;
164 while (i < si)
165 { if (cars[i] == car)
166 { ci = i; break; }
167 ++i;
168 }
169 //LogO(toStr(ci)+" ci "+cars[ci]+" all "+toStr(si));
170
171 std::vector<string> cars2;
172 int a = ci, b = ci; i = 0;
173 cars2.push_back(cars[ci]); // 1st cur
174 while (cars2.size() < si) // same size
175 { // +1, -1, +2, -2 ..
176 if (i % 2 == 0)
177 { ++a; // next faster car
178 if (a < si) cars2.push_back(cars[a]);
179 }else
180 { --b; // next slower car
181 if (b >= 0) cars2.push_back(cars[b]);
182 } ++i;
183 }
184 //for (i=0; i < cars2.size(); ++i)
185 // LogO(toStr(i)+"> "+cars2[i]);
186
187 bool srch = true;
188 i = 0; a = 0;
189 while (srch)
190 {
191 const string& car = cars2[i];
192 file = ghostFile(pSet, sim_mode, car);
193
194 if (PATHMANAGER::FileExists(file))
195 { srch = false; *ghCar = car; }
196 ++i;
197 if (i >= si)
198 { i = 0;
199 if (sim_mode == "easy") sim_mode = "normal";
200 else sim_mode = "easy";
201 ++a; if (a==2) srch = false; // only those 2
202 }
203 }
204 return file;
205 }
206
GetRplListDir()207 string CGui::GetRplListDir()
208 {
209 return (pSet->rpl_listghosts
210 ? (PATHMANAGER::Ghosts() + "/" + pSet->gui.sim_mode)
211 : PATHMANAGER::Replays() );
212 }
213
214
215 // [Game] . . . . . . . . . . . . . . . . . . . . --- lists ---- . . . . . . . . . . . . . . . . . .
216
217 // car
listCarChng(MultiList2 * li,size_t)218 void CGui::listCarChng(MultiList2* li, size_t)
219 {
220 size_t i = li->getIndexSelected(); if (i==ITEM_NONE) return;
221 Ogre::Timer ti;
222 sListCar = li->getItemNameAt(i).substr(7);
223
224 if (imgCar && !pSet->dev_no_prvs) imgCar->setImageTexture(sListCar+".jpg");
225 if (app->mClient) app->mClient->updatePlayerInfo(pSet->nickname, sListCar);
226
227 // car desc txt
228 String sd = String("#BFD3E5")+TR("#{CarDesc_"+sListCar+"}");
229
230 // car info
231 bool car = true;
232 int id = data->cars->carmap[sListCar];
233 if (id > 0 && txCarSpeed && barCarSpeed)
234 { const CarInfo& ci = data->cars->cars[id-1];
235 car = ci.car;
236
237 txCarAuthor->setCaption(ci.author);
238 txCarSpeed->setCaption(gcom->clrsDiff[std::min(8, (int)(ci.speed*0.9f))]+ fToStr(ci.speed,1,3));
239 txCarType->setCaption(data->cars->colormap[ci.type]+ TR("#{CarType_"+ci.type+"}"));
240 txCarYear->setCaption(toStr(ci.year));
241
242 if (ci.type == "Spaceship" || ci.type == "Other")
243 sd += TR("#E0E060 #{CarDesc_Pipes}");
244
245 float v = std::max(0.f, 1.f - ci.speed/13.f);
246 barCarSpeed->setImageCoord(IntCoord(v*128.f,0,128,16));
247 barCarSpeed->setColour(Colour(1.f, 0.2f + 0.8f * v, v * 0.3f));
248 }
249 carDesc->setCaption(sd);
250
251 changeCar();
252 UpdCarStats(car);
253 //LogO(String(":::: Time car tab upd: ") + fToStr(ti.getMilliseconds(),0,3) + " ms");
254 }
changeCar()255 void CGui::changeCar()
256 {
257 if (iCurCar < 4)
258 pSet->gui.car[iCurCar] = sListCar;
259 }
260
261
262 /// load car stats xml
263 //-----------------------------------------------------------------------------------------------------------
UpdCarStats(bool car)264 void CGui::UpdCarStats(bool car)
265 {
266 string path = PATHMANAGER::CarSim() + "/" + pSet->gui.sim_mode + "/cars/" + sListCar + "_stats.xml";
267 float f;
268 #define vis(i,v) \
269 { txCarStTxt[i]->setVisible(v); txCarStVals[i]->setVisible(v); barCarSt[i]->setVisible(v); }
270
271 XMLDocument doc; int i;
272 XMLError er = doc.LoadFile(path.c_str());
273 if (er != XML_SUCCESS)
274 {
275 for (i=0; i < iCarSt; ++i) vis(i,false);
276 return;
277 }
278 XMLElement* root = doc.RootElement();
279 if (!root) return;
280
281 for (i=0; i < iCarSt; ++i) vis(i,true);
282
283 // read xml --------
284 XMLElement* e; const char* a;
285 float mass=0.f, comFront=0.f, maxTrq=0.f, rpmMaxTq=0.f, maxPwr=0.f, rpmMaxPwr=0.f, bhpPerTon=0.f,
286 maxVel=0.f, tiMaxVel=0.f, t0to60=0.f, t0to100=0.f, t0to160=0.f, t0to200=0.f,
287 stop60=0.f, stop100=0.f, stop160=0.f, down100=0.f, down160=0.f, down200=0.f;
288
289 e = root->FirstChildElement("car");
290 if (e)
291 { a = e->Attribute("mass"); if (a) mass = s2r(a);
292 //a = e->Attribute("inertia"); if (a) inert = s2v(a);
293 }
294 e = root->FirstChildElement("com");
295 if (e)
296 { a = e->Attribute("frontPercent"); if (a) comFront = s2r(a);
297 //a = e->Attribute("pos"); if (a) com = s2v(a);
298 //a = e->Attribute("whf"); if (a) whf = s2r(a);
299 //a = e->Attribute("whr"); if (a) whr = s2r(a);
300 }
301 e = root->FirstChildElement("torque");
302 if (e)
303 { a = e->Attribute("max"); if (a) maxTrq = s2r(a);
304 //a = e->Attribute("rpm"); if (a) rpmMaxTq = s2r(a);
305 //a = e->Attribute("mul"); if (a) mul = s2r(a);
306 }
307 e = root->FirstChildElement("power");
308 if (e)
309 { a = e->Attribute("max"); if (a) maxPwr = s2r(a);
310 //a = e->Attribute("rpm"); if (a) rpmMaxPwr = s2r(a);
311 }
312 e = root->FirstChildElement("bhpPerTon");
313 if (e)
314 { a = e->Attribute("val"); if (a) bhpPerTon = s2r(a);
315 }
316 e = root->FirstChildElement("top");
317 if (e)
318 { a = e->Attribute("speed"); if (a) maxVel = s2r(a);
319 //a = e->Attribute("time"); if (a) tiMaxVel = s2r(a);
320 }
321 /*e = root->FirstChildElement("quarterMile");
322 if (e)
323 { a = e->Attribute("time"); if (a) timeQM = s2r(a);
324 a = e->Attribute("vel"); if (a) velAtQM = s2r(a);
325 }*/
326 e = root->FirstChildElement("accel");
327 if (e)
328 { a = e->Attribute("t60"); if (a) t0to60 = s2r(a);
329 a = e->Attribute("t100"); if (a) t0to100 = s2r(a);
330 a = e->Attribute("t160"); if (a) t0to160 = s2r(a);
331 a = e->Attribute("t200"); if (a) t0to200 = s2r(a);
332 }
333 /*e = root->FirstChildElement("downForce");
334 if (e)
335 { a = e->Attribute("d100"); if (a) down100 = s2r(a);
336 a = e->Attribute("d160"); if (a) down160 = s2r(a);
337 a = e->Attribute("d200"); if (a) down200 = s2r(a);
338 }*/
339 e = root->FirstChildElement("stop");
340 if (e)
341 { //a = e->Attribute("s160"); if (a) stop160 = s2r(a);
342 a = e->Attribute("s100"); if (a) stop100 = s2r(a);
343 //a = e->Attribute("s60"); if (a) stop60 = s2r(a);
344 }
345
346 // speed graph points
347 e = root->FirstChildElement("velGraph");
348 std::vector<float> ttim,tkmh;
349 if (e)
350 { float t,v;
351 XMLElement* p = e->FirstChildElement("p");
352 while (p)
353 { a = p->Attribute("t"); if (a) { t = s2r(a);
354 a = p->Attribute("v"); if (a) { v = s2r(a);
355 ttim.push_back(t); tkmh.push_back(v);
356 } }
357 p = p->NextSiblingElement("p");
358 } }
359
360
361 /// upd vel graph ~~~
362 float xs = 10.f, ys = 0.4f, yo = 166.f, x2 = 500.f;
363 const IntSize& wi = app->mWndOpts->getSize();
364 const float sx = wi.width/1248.f, sy = wi.height/935.f;
365 xs *= sx; ys *= sy; yo *= sy; x2 *= sx;
366
367 std::vector<FloatPoint> points,grid;
368 points.push_back(FloatPoint(0.f, yo));
369 for (i = 0; i < (int)ttim.size(); ++i)
370 points.push_back(FloatPoint(ttim[i] * xs, yo - ys * tkmh[i]));
371 graphVel->setPoints(points);
372
373 // grid lines
374 const int y1 = yo +10, y2 = -10, x1 = -10; //outside
375 for (i = 0; i < 6; ++i) // ||
376 { float fi = i > 2 ? 10.f*(i-1) : 5.f*i;
377 grid.push_back(FloatPoint(fi * xs, i%2==0 ? y1 : y2));
378 grid.push_back(FloatPoint(fi * xs, i%2==0 ? y2 : y1));
379 }
380 grid.push_back(FloatPoint(x2, y1));
381 grid.push_back(FloatPoint(x1, y1));
382 for (i = 0; i < 4; ++i) // ==
383 { grid.push_back(FloatPoint(i%2==0 ? x1 : x2, yo - ys * i * 100.f));
384 grid.push_back(FloatPoint(i%2==0 ? x2 : x1, yo - ys * i * 100.f));
385 }
386 graphVGrid->setPoints(grid);
387
388
389 // upd text --------
390 bool kmh = !pSet->show_mph; float k2m = 0.621371f;
391 String s[iCarSt], v[iCarSt];
392 float sm = pSet->gui.sim_mode == "easy" ? 0.75f : 1.f;
393
394 #define bar(n,sc, r,g,b) \
395 f = std::max(0.f, (1.f - sc)) * 128.f; barCarSt[n]->setImageCoord(IntCoord(f,0,128,16)); \
396 barCarSt[n]->setColour(Colour(r,g,b));
397
398 s[0]= "#80E080"+ TR("#{Car_Mass}");
399 v[0]= "#90FF90"+ fToStr(mass,0,3) +TR(" #{UnitKg}");
400 bar(0, mass / 3000.f, 0.6,1.0,0.6);
401 s[1]= "#B0E0B0"+ TR("#{Car_MassFront}");
402 v[1]= "#C0FFC0"+ fToStr(comFront,0,3) +"%";
403 bar(1, comFront / 100.f, 0.8,1.0,0.8);
404
405 s[2]= "#E0C0A0"+ TR("#{Car_MaxTorque}");
406 v[2]= "#F0D0B0"+ fToStr(maxTrq,0,3) +TR(" #{UnitNm}"); // #{at} ")+ fToStr(rpmMaxTq,0,3) +TR(" #{UnitRpm} ");
407 bar(2, maxTrq / 970.f, 0.9,0.8,0.6); vis(2,car);
408 s[3]= "#E0B090"+ TR("#{Car_MaxPower}");
409 v[3]= "#F0C0A0"+ fToStr(maxPwr,0,3) +TR(" #{UnitBhp}"); // #{at} ")+ fToStr(rpmMaxPwr,0,3) +TR(" #{UnitRpm} ");
410 bar(3, maxPwr / 700.f, 0.9,0.7,0.5); vis(3,car);
411 s[4]= "#E0E0A0"+ TR("#{Car_BhpPerTon}");
412 v[4]= "#F0F0B0"+ fToStr(bhpPerTon,0,3);
413 bar(4, bhpPerTon / 450.f, 1.0,1.0,0.6); vis(4,car);
414
415 #define sVel(s,v) \
416 if (kmh) s += fToStr(v, 0,3) +TR(" #{UnitKmh}"); \
417 else s += fToStr(v*k2m, 0,3) +TR(" #{UnitMph}");
418
419 s[5]= "#80C0FF"+ TR("#{Car_TopSpeed}");
420 v[5]= "#90D0FF"; sVel(v[5], maxVel); //v[5]+= TR(" #{at} ")+ fToStr(tiMaxVel,1,4) +TR(" #{UnitS} ");
421 bar(5, maxVel / 300.f, 0.6,0.9,1.0);
422
423 s[6]= "#8ECEFE"+ TR("#{Car_TimeTo} "); sVel(s[6], 100.f);
424 v[6]= "#9EDEFF"+ fToStr(t0to100,1,4) +TR(" #{UnitS} ");
425 bar(6, t0to100 / 8.f * sm, 0.8,1.0,1.0);
426
427 s[7]= "#88C8F8"+ TR("#{Car_TimeTo} "); sVel(s[7], 160.f);
428 v[7]= "#98D8FF"+ fToStr(t0to160,1,4) +TR(" #{UnitS} ");
429 bar(7, t0to160 / 17.f * sm, 0.75,1.0,1.0); vis(7, t0to160 > 0.f);
430
431 s[8]= "#80C0F0"+ TR("#{Car_TimeTo} "); sVel(s[8], 200.f);
432 v[8]= "#90D0FF"+ fToStr(t0to200,1,4) +TR(" #{UnitS} ");
433 bar(8, t0to200 / 27.f * sm, 0.7,1.0,1.0); vis(8, t0to200 > 0.f);
434
435 s[9]= "#70E0E0"+ TR("#{Car_StopTimeFrom} "); sVel(s[9], 100.f);
436 v[9]= "#80F0F0"+ fToStr(stop100,1,4) +TR(" #{UnitS} ");
437 bar(9, stop100 / 5.f * sm, 0.5,1.0,1.0);
438
439 for (i=0; i < iCarSt; ++i)
440 { txCarStTxt[i]->setCaption(s[i]); txCarStVals[i]->setCaption(v[i]); }
441 }
442
443
444 // track
changeTrack()445 void CGui::changeTrack()
446 {
447 pSet->gui.track = gcom->sListTrack;
448 pSet->gui.track_user = gcom->bListTrackU;
449 //_ only for host..
450 if (app->mMasterClient && valNetPassword->getVisible())
451 { uploadGameInfo();
452 updateGameInfoGUI(); }
453 }
454
455 // new game
btnNewGame(WP wp)456 void CGui::btnNewGame(WP wp)
457 {
458 if (app->mWndGame->getVisible() && app->mWndTabsGame->getIndexSelected() < TAB_Champs || app->mClient)
459 BackFromChs(); /// champ, back to single race
460
461 bool force = false;
462 if (wp)
463 { string s = wp->getName();
464 s = s.substr(s.length()-1,1);
465 bool force = s=="3" || s=="4";
466 }
467 app->NewGame(force); app->isFocGui = false; // off gui
468 app->mWndOpts->setVisible(app->isFocGui);
469 app->mWndRpl->setVisible(false);//
470 gcom->bnQuit->setVisible(app->isFocGui);
471
472 app->updMouse();
473
474 gcom->mToolTip->setVisible(false);
475 }
btnNewGameStart(WP wp)476 void CGui::btnNewGameStart(WP wp)
477 {
478 changeTrack();
479 btnNewGame(wp);
480 }
481
482
483 // Menu
484 //-----------------------------------------------------------------------------------------------------------
485
toggleGui(bool toggle)486 void CGui::toggleGui(bool toggle)
487 {
488 if (toggle)
489 app->isFocGui = !app->isFocGui;
490
491 bool notMain = app->isFocGui && !pSet->isMain;
492 app->mWndMain->setVisible(app->isFocGui && pSet->isMain);
493 app->mWndReplays->setVisible(notMain && pSet->inMenu == MNU_Replays);
494 app->mWndHelp->setVisible(notMain && pSet->inMenu == MNU_Help);
495 app->mWndOpts->setVisible(notMain && pSet->inMenu == MNU_Options);
496 if (!app->isFocGui) app->mWndTrkFilt->setVisible(false);
497
498 // load Readme editbox from file
499 if (app->mWndHelp->getVisible() && loadReadme)
500 {
501 loadReadme = false;
502 Ed ed = fEd("Readme");
503 if (ed)
504 { string path = PATHMANAGER::Data()+"/../Readme.txt";
505 std::ifstream fi(path.c_str());
506 if (fi.good())
507 { String text = "", s;
508 while (getline(fi,s))
509 text += s + "\n";
510
511 text = StringUtil::replaceAll(text, "#", "##");
512 ed->setCaption(UString(text));
513 ed->setVScrollPosition(0);
514 } } }
515
516 /// update track tab, for champs wnd
517 bool game = pSet->inMenu == MNU_Single, champ = pSet->inMenu == MNU_Champ,
518 tutor = pSet->inMenu == MNU_Tutorial, chall = pSet->inMenu == MNU_Challenge,
519 chAny = champ || tutor || chall, gc = game || chAny;
520 UString sCh = chall ? TR("#90FFD0#{Challenge}") : (tutor ? TR("#FFC020#{Tutorial}") : TR("#80C0FF#{Championship}"));
521
522 UpdChampTabVis();
523
524 bool vis = notMain && gc;
525 app->mWndGame->setVisible(vis);
526 if (vis)
527 {
528 app->mWndGame->setCaption(chAny ? sCh : TR("#{SingleRace}"));
529 TabItem* t = app->mWndTabsGame->getItemAt(TAB_Champs);
530 t->setCaption(sCh);
531 }
532 if (notMain && gc) // show hide champs,stages
533 {
534 Tab t = app->mWndTabsGame;
535 size_t id = t->getIndexSelected();
536 t->setButtonWidthAt(TAB_Track, chAny ? 1 :-1); if (id == TAB_Track && chAny) t->setIndexSelected(TAB_Champs);
537 t->setButtonWidthAt(TAB_Multi, chAny ? 1 :-1); if (id == TAB_Multi && chAny) t->setIndexSelected(TAB_Champs);
538 t->setButtonWidthAt(TAB_Champs,chAny ?-1 : 1); if (id == TAB_Champs && !chAny) t->setIndexSelected(TAB_Track);
539 t->setButtonWidthAt(TAB_Stages,chAny ?-1 : 1); if (id == TAB_Stages && !chAny) t->setIndexSelected(TAB_Track);
540 t->setButtonWidthAt(TAB_Stage, chAny ?-1 : 1); if (id == TAB_Stage && !chAny) t->setIndexSelected(TAB_Track);
541 }
542
543 gcom->bnQuit->setVisible(app->isFocGui);
544 app->updMouse();
545 if (!app->isFocGui) gcom->mToolTip->setVisible(false);
546
547 for (int i=0; i < ciMainBtns; ++i)
548 app->mWndMainPanels[i]->setVisible(pSet->inMenu == i);
549
550 // 1st center mouse
551 static bool first = true;
552 if (app->isFocGui && first)
553 { first = false;
554 gcom->GuiCenterMouse();
555 }
556 }
557
558
559 // Gui Shortcut alt-letters
560 //.......................................................................................
GuiShortcut(MNU_Btns mnu,int tab,int subtab)561 void CGui::GuiShortcut(MNU_Btns mnu, int tab, int subtab)
562 {
563 if (subtab == -1 && (!app->isFocGui || pSet->inMenu != mnu))
564 subtab = -2; // cancel subtab cycling
565
566 app->isFocGui = true;
567 pSet->isMain = false;
568 if (!(tab == TAB_Car && pSet->inMenu >= MNU_Tutorial && pSet->inMenu <= MNU_Challenge)) //
569 pSet->inMenu = mnu;
570
571 TabPtr mWndTabs = 0;
572 std::vector<TabControl*>* subt = 0;
573
574 switch (mnu)
575 { case MNU_Replays: mWndTabs = app->mWndTabsRpl; break;
576 case MNU_Help: mWndTabs = app->mWndTabsHelp; break;
577 case MNU_Options: mWndTabs = app->mWndTabsOpts; subt = &vSubTabsOpts; break;
578 default: mWndTabs = app->mWndTabsGame; subt = &vSubTabsGame; break;
579 }
580 toggleGui(false);
581
582
583 size_t t = mWndTabs->getIndexSelected();
584 mWndTabs->setIndexSelected(tab);
585
586 if (!subt) return;
587 TabControl* tc = (*subt)[tab]; if (!tc) return;
588 int cnt = tc->getItemCount();
589
590 if (t == tab && subtab == -1) // cycle subpages if same tab
591 { if (app->shift)
592 tc->setIndexSelected( (tc->getIndexSelected()-1+cnt) % cnt );
593 else
594 tc->setIndexSelected( (tc->getIndexSelected()+1) % cnt );
595 }
596 if (subtab > -1)
597 tc->setIndexSelected( std::min(cnt-1, subtab) );
598
599 if (!tc->eventTabChangeSelect.empty())
600 tc->eventTabChangeSelect(tc, tc->getIndexSelected());
601 }
602
603 // close netw end
btnNetEndClose(WP)604 void CGui::btnNetEndClose(WP)
605 {
606 app->mWndNetEnd->setVisible(false);
607 app->isFocGui = true; // show back gui
608 toggleGui(false);
609 }
610
611
612 // utility
613 //---------------------------------------------------------------------------------------------------------------------
614
615 // next/prev in list by key
LNext(Mli2 lp,int rel,int ofs)616 int CGui::LNext(Mli2 lp, int rel, int ofs)
617 {
618 size_t cnt = lp->getItemCount();
619 if (cnt==0) return 0;
620 int i = std::max(0, std::min((int)cnt-1, (int)lp->getIndexSelected()+rel ));
621 lp->setIndexSelected(i);
622 lp->beginToItemAt(std::max(0, i-ofs)); // center
623 return i;
624 }
LNext(Mli lp,int rel)625 int CGui::LNext(Mli lp, int rel)
626 {
627 size_t cnt = lp->getItemCount();
628 if (cnt==0) return 0;
629 int i = std::max(0, std::min((int)cnt-1, (int)lp->getIndexSelected()+rel ));
630 lp->setIndexSelected(i);
631 return i;
632 }
LNext(Li lp,int rel,int ofs)633 int CGui::LNext(Li lp, int rel, int ofs)
634 {
635 size_t cnt = lp->getItemCount();
636 if (cnt==0) return 0;
637 int i = std::max(0, std::min((int)cnt-1, (int)lp->getIndexSelected()+rel ));
638 lp->setIndexSelected(i);
639 lp->beginToItemAt(std::max(0, i-ofs)); // center
640 return i;
641 }
642
LNext(int rel)643 void CGui::LNext(int rel)
644 {
645 //if (!ap->isFocGui || pSet->isMain) return;
646 if (pSet->inMenu == MNU_Replays)
647 listRplChng(rplList, LNext(rplList, rel, 11));
648 else
649 if (app->mWndGame->getVisible())
650 switch (app->mWndTabsGame->getIndexSelected())
651 { case TAB_Track: gcom->listTrackChng(gcom->trkList, LNext(gcom->trkList, rel, 11)); return;
652 case TAB_Car: listCarChng(carList, LNext(carList, rel, 5)); return;
653 case TAB_Game: if (rel > 0) radSimNorm(0); else radSimEasy(0); return;
654 case TAB_Champs:
655 if (isChallGui())
656 listChallChng(liChalls, LNext(liChalls, rel, 8));
657 else listChampChng(liChamps, LNext(liChamps, rel, 8));
658 return;
659 case TAB_Stages: listStageChng(liStages, LNext(liStages, rel, 8)); return;
660 case TAB_Stage: if (rel > 0) btnStageNext(0); else btnStagePrev(0); return;
661 }
662 }
663
664
665 /// Update (frame start) .,.,.,.,..,.,.,.,..,.,.,.,..,.,.,.,.
GuiUpdate()666 void CGui::GuiUpdate()
667 {
668 gcom->UnfocusLists();
669
670 if (gcom->bGuiReinit) // after language change from combo
671 { gcom->bGuiReinit = false;
672
673 mGui->destroyWidgets(app->vwGui);
674 gcom->bnQuit=0; app->mWndOpts=0; //todo: rest too.. delete, new gui; ?
675
676 bGI = false;
677 InitGui();
678
679 app->bWindowResized = true;
680 app->mWndTabsOpts->setIndexSelected(3); // switch back to view tab
681 }
682
683
684 // sort trk list
685 gcom->SortTrkList();
686
687 // sort car list
688 if (gcom->needSort(carList))
689 {
690 pSet->cars_sort = carList->mSortColumnIndex;
691 pSet->cars_sortup = carList->mSortUp;
692 CarListUpd(false);
693 }
694
695 // upd tweak tire save
696 if (app->pGame->reloadSimDone)
697 { app->pGame->reloadSimDone = false;
698
699 FillTweakLists();
700 btnTweakTireLoad(0); // load back
701 }
702
703
704 /// rpl convert tool
705 if (bConvertRpl)
706 { boost::this_thread::sleep(boost::posix_time::milliseconds(50));
707
708 txtConvert->setCaption(
709 "#C0C0FF""Path: "+ iToStr(iConvPathCur+1,1) +" / "+ iToStr(iConvPathAll,1) +"\n"+
710 "#A0D0FF""Files: "+ iToStr(iConvCur+1,4) +" / "+ iToStr(iConvAll,4) +" : "+ iToStr(iConvFiles,4) +"\n"+
711 (totalConv == 0 ? "" :
712 "#A0F0F0""Progress: "+ fToStr(100.f* float(totalConvCur)/float(totalConv), 2,5) +" %\n")+
713 "#A0C0E0""Sizes\n"+
714 "#F0A0A0""old: "+ fToStr( float(totalConv)/1000000.f, 2,5) +" MiB\n"+
715 "#A0F0A0""new: "+ fToStr( float(totalConvNew)/1000000.f, 2,5) +" MiB\n"+
716 (totalConvCur!=totalConv || totalConv==0 ? "" :
717 "#F0F0A0""ratio: "+ fToStr(100.f* float(totalConvNew)/float(totalConv), 1,4) +" %") );
718 }
719 }
720