Advertisement
Guest User

Untitled

a guest
Apr 23rd, 2011
258
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 45.57 KB | None | 0 0
  1. // menus.cpp: ingame menu system (also used for scores and serverlist)
  2.  
  3. #include "cube.h"
  4.  
  5. hashtable<const char *, gmenu> menus;
  6. gmenu *curmenu = NULL, *lastmenu = NULL;
  7. color *menuselbgcolor = NULL;
  8.  
  9. vector<gmenu *> menustack;
  10.  
  11. VARP(browsefiledesc, 0, 1, 1);
  12.  
  13. char *getfiledesc(const char *dir, const char *name, const char *ext)
  14. {
  15. if(!browsefiledesc || !dir || !name || !ext) return NULL;
  16. defformatstring(fn)("%s/%s.%s", dir, name, ext);
  17. path(fn);
  18. string text;
  19. if(!strcmp(ext, "dmo"))
  20. {
  21. stream *f = opengzfile(fn, "rb");
  22. if(!f) return NULL;
  23. demoheader hdr;
  24. if(f->read(&hdr, sizeof(demoheader))!=sizeof(demoheader) || memcmp(hdr.magic, DEMO_MAGIC, sizeof(hdr.magic))) { delete f; return NULL; }
  25. delete f;
  26. lilswap(&hdr.version, 1);
  27. lilswap(&hdr.protocol, 1);
  28. const char *tag = "(incompatible file) ";
  29. if(hdr.version == DEMO_VERSION)
  30. {
  31. if(hdr.protocol == PROTOCOL_VERSION) tag = "";
  32. else if(hdr.protocol == -PROTOCOL_VERSION) tag = "(recorded on modded server) ";
  33. }
  34. formatstring(text)("%s%s", tag, hdr.desc);
  35. text[DHDR_DESCCHARS - 1] = '\0';
  36. return newstring(text);
  37. }
  38. else if(!strcmp(ext, "cgz"))
  39. {
  40. stream *f = opengzfile(fn, "rb");
  41. if(!f) return NULL;
  42. header hdr;
  43. if(f->read(&hdr, sizeof(header))!=sizeof(header) || (strncmp(hdr.head, "CUBE", 4) && strncmp(hdr.head, "ACMP",4))) { delete f; return NULL; }
  44. delete f;
  45. lilswap(&hdr.version, 1);
  46. // hdr.maprevision, hdr.maptitle ... hdr.version, hdr.headersize,
  47. formatstring(text)("%s%s", (hdr.version>MAPVERSION) ? "(incompatible file) " : "", hdr.maptitle);
  48. text[DHDR_DESCCHARS - 1] = '\0';
  49. return newstring(text);
  50. }
  51. return NULL;
  52. }
  53.  
  54. void menuset(void *m, bool save)
  55. {
  56. if(curmenu==m) return;
  57. if(curmenu)
  58. {
  59. if(save && curmenu->allowinput) menustack.add(curmenu);
  60. else curmenu->close();
  61. }
  62. if((curmenu = (gmenu *)m)) curmenu->open();
  63. }
  64.  
  65. void showmenu(const char *name, bool top)
  66. {
  67. if(!name)
  68. {
  69. curmenu = NULL;
  70. return;
  71. }
  72. gmenu *m = menus.access(name);
  73. if(!m) return;
  74. if(!top && curmenu)
  75. {
  76. if(curmenu==m) return;
  77. loopv(menustack) if(menustack[i]==m) return;
  78. menustack.insert(0, m);
  79. return;
  80. }
  81. menuset(m);
  82. }
  83.  
  84. void closemenu(const char *name)
  85. {
  86. gmenu *m;
  87. if(!name)
  88. {
  89. if(curmenu) curmenu->close();
  90. while(!menustack.empty())
  91. {
  92. m = menustack.pop();
  93. if(m) m->close();
  94. }
  95. curmenu = NULL;
  96. return;
  97. }
  98. m = menus.access(name);
  99. if(!m) return;
  100. if(curmenu==m) menuset(menustack.empty() ? NULL : menustack.pop(), false);
  101. else loopv(menustack)
  102. {
  103. if(menustack[i]==m)
  104. {
  105. menustack.remove(i);
  106. return;
  107. }
  108. }
  109. }
  110.  
  111. void showmenu_(const char *name)
  112. {
  113. showmenu(name, true);
  114. }
  115.  
  116. void menuselect(void *menu, int sel)
  117. {
  118. gmenu &m = *(gmenu *)menu;
  119.  
  120. if(sel<0) sel = m.items.length()>0 ? m.items.length()-1 : 0;
  121. else if(sel>=m.items.length()) sel = 0;
  122.  
  123. if(m.items.inrange(sel))
  124. {
  125. int oldsel = m.menusel;
  126. m.menusel = sel;
  127. if(m.allowinput)
  128. {
  129. if(sel!=oldsel)
  130. {
  131. m.items[oldsel]->focus(false);
  132. m.items[sel]->focus(true);
  133. audiomgr.playsound(S_MENUSELECT, SP_HIGHEST);
  134. }
  135. }
  136. }
  137. }
  138.  
  139. void drawarrow(int dir, int x, int y, int size, float r = 1.0f, float g = 1.0f, float b = 1.0f)
  140. {
  141. glDisable(GL_BLEND);
  142. glDisable(GL_TEXTURE_2D);
  143. glColor3f(r, g, b);
  144.  
  145. glBegin(GL_TRIANGLES);
  146. glVertex2f(x, dir ? y+size : y);
  147. glVertex2f(x+size/2, dir ? y : y+size);
  148. glVertex2f(x+size, dir ? y+size : y);
  149. glEnd();
  150. xtraverts += 3;
  151.  
  152. glEnable(GL_TEXTURE_2D);
  153. glEnable(GL_BLEND);
  154. }
  155.  
  156. #define MAXMENU 34
  157.  
  158. bool menuvisible()
  159. {
  160. if(!curmenu) return false;
  161. return true;
  162. }
  163.  
  164. void rendermenu()
  165. {
  166. setscope(false);
  167. gmenu &m = *curmenu;
  168. m.refresh();
  169. m.render();
  170. }
  171.  
  172. void mitem::render(int x, int y, int w)
  173. {
  174. if(isselection()) renderbg(x, y, w, menuselbgcolor);
  175. else if(bgcolor) renderbg(x, y, w, bgcolor);
  176. }
  177.  
  178. void mitem::renderbg(int x, int y, int w, color *c)
  179. {
  180. if(isselection()) blendbox(x-FONTH/4, y-FONTH/6, x+w+FONTH/4, y+FONTH+FONTH/6, false, -1, c);
  181. else blendbox(x, y, x+w, y+FONTH, false, -1, c);
  182. }
  183.  
  184. bool mitem::isselection() { return parent->allowinput && !parent->hotkeys && parent->items.inrange(parent->menusel) && parent->items[parent->menusel]==this; }
  185.  
  186. color mitem::gray(0.2f, 0.2f, 0.2f);
  187. color mitem::white(1.0f, 1.0f, 1.0f);
  188. color mitem::whitepulse(1.0f, 1.0f, 1.0f);
  189.  
  190. // text item
  191.  
  192. struct mitemmanual : mitem
  193. {
  194. const char *text, *action, *hoveraction, *desc;
  195.  
  196. mitemmanual(gmenu *parent, char *text, char *action, char *hoveraction, color *bgcolor, const char *desc) : mitem(parent, bgcolor), text(text), action(action), hoveraction(hoveraction), desc(desc) {}
  197.  
  198. virtual int width() { return text_width(text); }
  199.  
  200. virtual void render(int x, int y, int w)
  201. {
  202. mitem::render(x, y, w);
  203. draw_text(text, x, y);
  204. }
  205.  
  206. virtual void focus(bool on)
  207. {
  208. if(on && hoveraction) execute(hoveraction);
  209. }
  210.  
  211. virtual void select()
  212. {
  213. if(action && action[0])
  214. {
  215. gmenu *oldmenu = curmenu;
  216. push("arg1", text);
  217. int result = execute(action);
  218. pop("arg1");
  219. if(result >= 0 && oldmenu == curmenu)
  220. {
  221. menuset(NULL, false);
  222. menustack.shrink(0);
  223. }
  224. }
  225. }
  226. virtual const char *getdesc() { return desc; }
  227. virtual const char *gettext() { return text; }
  228. virtual const char *getaction() { return action; }
  229. };
  230.  
  231. struct mitemtext : mitemmanual
  232. {
  233. mitemtext(gmenu *parent, char *text, char *action, char *hoveraction, color *bgcolor, const char *desc = NULL) : mitemmanual(parent, text, action, hoveraction, bgcolor, desc) {}
  234. virtual ~mitemtext()
  235. {
  236. DELETEA(text);
  237. DELETEA(action);
  238. DELETEA(hoveraction);
  239. DELETEA(desc);
  240. }
  241. };
  242.  
  243. struct mitemtextvar : mitemmanual
  244. {
  245. string dtext;
  246. const char *textexp;
  247. mitemtextvar(gmenu *parent, const char *evalp, char *action, char *hoveraction) : mitemmanual(parent, dtext, action, hoveraction, NULL, NULL)
  248. {
  249. dtext[0] = '\0';
  250. textexp = evalp;
  251. }
  252. virtual ~mitemtextvar()
  253. {
  254. DELETEA(textexp);
  255. DELETEA(action);
  256. DELETEA(hoveraction);
  257. }
  258. virtual void init()
  259. {
  260. char *r = executeret(textexp);
  261. copystring(dtext, r ? r : "");
  262. if(r) delete[] r;
  263. }
  264. };
  265.  
  266. VARP(hidebigmenuimages, 0, 0, 1);
  267.  
  268. struct mitemimagemanual : mitemmanual
  269. {
  270. const char *filename;
  271. Texture *image;
  272. font *altfont;
  273.  
  274. mitemimagemanual(gmenu *parent, const char *filename, const char *altfontname, char *text, char *action, char *hoveraction, color *bgcolor, const char *desc = NULL) : mitemmanual(parent, text, action, hoveraction, bgcolor, desc), filename(filename)
  275. {
  276. image = filename ? textureload(filename, 3) : NULL;
  277. altfont = altfontname ? getfont(altfontname) : NULL;
  278. }
  279. virtual ~mitemimagemanual() {}
  280. virtual int width()
  281. {
  282. if(image && *text != '\t') return (FONTH*image->xs)/image->ys + FONTH/2 + mitemmanual::width();
  283. return mitemmanual::width();
  284. }
  285. virtual void render(int x, int y, int w)
  286. {
  287. mitem::render(x, y, w);
  288. if(image || altfont)
  289. {
  290. int xs = 0;
  291. if(image)
  292. {
  293. glBindTexture(GL_TEXTURE_2D, image->id);
  294. glDisable(GL_BLEND);
  295. glColor3f(1, 1, 1);
  296. xs = (FONTH*image->xs)/image->ys;
  297. glBegin(GL_TRIANGLE_STRIP);
  298. glTexCoord2f(0, 0); glVertex2f(x, y);
  299. glTexCoord2f(1, 0); glVertex2f(x+xs, y);
  300. glTexCoord2f(0, 1); glVertex2f(x, y+FONTH);
  301. glTexCoord2f(1, 1); glVertex2f(x+xs, y+FONTH);
  302. glEnd();
  303. xtraverts += 4;
  304. glEnable(GL_BLEND);
  305. }
  306. draw_text(text, !image || *text == '\t' ? x : x+xs + FONTH/2, y);
  307. if(altfont && strchr(text, '\a'))
  308. {
  309. char *r = newstring(text), *re, *l = r;
  310. while((re = strchr(l, '\a')) && re[1])
  311. {
  312. *re = '\0';
  313. x += text_width(l);
  314. l = re + 2;
  315. pushfont(altfont->name);
  316. draw_textf("%c", x, y, re[1]);
  317. popfont();
  318. }
  319. delete[] r;
  320. }
  321. if(image && isselection() && !hidebigmenuimages && image->ys > FONTH)
  322. {
  323. w += FONTH;
  324. int xs = (2 * VIRTW - w) / 5, ys = (xs * image->ys) / image->xs;
  325. x = (6 * VIRTW + w - 2 * xs) / 4; y = VIRTH - ys / 2;
  326. blendbox(x - FONTH, y - FONTH, x + xs + FONTH, y + ys + FONTH, false);
  327. glBindTexture(GL_TEXTURE_2D, image->id); // I just copy&pasted this...
  328. glDisable(GL_BLEND);
  329. glColor3f(1, 1, 1);
  330. glBegin(GL_TRIANGLE_STRIP);
  331. glTexCoord2f(0, 0); glVertex2f(x, y);
  332. glTexCoord2f(1, 0); glVertex2f(x+xs, y);
  333. glTexCoord2f(0, 1); glVertex2f(x, y+ys);
  334. glTexCoord2f(1, 1); glVertex2f(x+xs, y+ys);
  335. glEnd();
  336. xtraverts += 4;
  337. glEnable(GL_BLEND);
  338. }
  339. }
  340. else mitemmanual::render(x, y, w);
  341. }
  342. };
  343.  
  344. struct mitemimage : mitemimagemanual
  345. {
  346. mitemimage(gmenu *parent, const char *filename, char *text, char *action, char *hoveraction, color *bgcolor, const char *desc = NULL) : mitemimagemanual(parent, filename, NULL, text, action, hoveraction, bgcolor, desc) {}
  347. virtual ~mitemimage()
  348. {
  349. DELETEA(filename);
  350. DELETEA(text);
  351. DELETEA(action);
  352. DELETEA(hoveraction);
  353. DELETEA(desc);
  354. }
  355. };
  356. VARP(maploaditemlength, 0, 46, 255);
  357. struct mitemmaploadmanual : mitemmanual
  358. {
  359. const char *filename;
  360. string maptitle;
  361. string mapstats;
  362. Texture *image;
  363.  
  364. mitemmaploadmanual(gmenu *parent, const char *filename, const char *altfontname, char *text, char *action, char *hoveraction, color *bgcolor, const char *desc = NULL) : mitemmanual(parent, text, action, NULL, NULL, NULL), filename(filename)
  365. {
  366. image = NULL;
  367. copystring(maptitle, filename ? filename : "-n/a-");
  368. if(filename)
  369. {
  370. // see worldio.cpp:setnames()
  371. string pakname, mapname, cgzpath;
  372. const char *slash = strpbrk(filename, "/\\");
  373. if(slash)
  374. {
  375. copystring(pakname, filename, slash-filename+1);
  376. copystring(mapname, slash+1);
  377. }
  378. else
  379. {
  380. copystring(pakname, "maps");
  381. copystring(mapname, filename);
  382. }
  383. formatstring(cgzpath)("packages/%s", pakname);
  384. char *d = getfiledesc(cgzpath, filename, "cgz");
  385. if( d ) { formatstring(maptitle)("%s", d[0] ? d : "-n/a-"); }
  386. else
  387. {
  388. copystring(pakname, "maps/official");
  389. formatstring(cgzpath)("packages/%s", pakname);
  390. char *d = getfiledesc("packages/maps/official", filename, "cgz");
  391. if( d ) { formatstring(maptitle)("%s", d[0] ? d : "-n/a-"); }
  392. else formatstring(maptitle)("-n/a-:%s", filename);
  393. }
  394. defformatstring(p2p)("%s/preview/%s.jpg", cgzpath, filename);
  395. silent_texture_load = true;
  396. image = textureload(p2p, 3);
  397. if(image==notexture) image = textureload("packages/misc/nopreview.jpg", 3);
  398. silent_texture_load = false;
  399. }
  400. else { formatstring(maptitle)("-n/a-:%s", filename); image = textureload("packages/misc/nopreview.png", 3); }
  401. copystring(mapstats, "");
  402. }
  403. virtual ~mitemmaploadmanual() {}
  404. virtual int width()
  405. {
  406. if(image && *text != '\t') return (FONTH*image->xs)/image->ys + FONTH/2 + mitemmanual::width();
  407. return mitemmanual::width();
  408. }
  409. virtual void render(int x, int y, int w)
  410. {
  411. mitem::render(x, y, w);
  412. if(image)
  413. {
  414. //int xs = 0;
  415. draw_text(text, x, y); // !image || *text == '\t' ? x : x+xs + FONTH/2
  416. if(image && isselection() && !hidebigmenuimages && image->ys > FONTH)
  417. {
  418. w += FONTH;
  419. int xs = (2 * VIRTW - w) / 5, ys = (xs * image->ys) / image->xs;
  420. x = (6 * VIRTW + w - 2 * xs) / 4; y = VIRTH - ys / 2;
  421.  
  422. blendbox(x - FONTH, y - FONTH, x + xs + FONTH, y + ys + FONTH, false);
  423. glBindTexture(GL_TEXTURE_2D, image->id); // I just copy&pasted this...
  424. glDisable(GL_BLEND);
  425. glColor3f(1, 1, 1);
  426. glBegin(GL_TRIANGLE_STRIP);
  427. glTexCoord2f(0, 0); glVertex2f(x, y);
  428. glTexCoord2f(1, 0); glVertex2f(x+xs, y);
  429. glTexCoord2f(0, 1); glVertex2f(x, y+ys);
  430. glTexCoord2f(1, 1); glVertex2f(x+xs, y+ys);
  431. glEnd();
  432. xtraverts += 4;
  433. glEnable(GL_BLEND);
  434. if(maptitle[0])
  435. {
  436. int mlil = maploaditemlength;
  437. string showt;
  438. string restt;
  439. restt[0] = '\0';
  440. filtertext(showt, maptitle, 1);
  441. if(mlil && mlil != 255) // 0 && 255 are 'off'
  442. {
  443. int tl = strlen(showt);
  444. if(tl>mlil)
  445. {
  446. int cr = 0;
  447. int mr = min(max(0, tl-mlil), mlil);
  448. for(cr=0;cr<mr;cr++) { restt[cr] = showt[cr+mlil]; }
  449. if(cr>0) { restt[cr+1] = '\0'; showt[mlil] = '\0'; }
  450. }
  451. }
  452. draw_text(showt, 1*FONTH/2, VIRTH - FONTH/2);
  453. draw_text(restt, 3*FONTH/2, VIRTH + FONTH/2);
  454. }
  455. //if(mapstats[0]) draw_text(mapstats, x, y+ys+5*FONTH/2);
  456. }
  457. }
  458. else mitemmanual::render(x, y, w);
  459. }
  460. };
  461.  
  462. struct mitemmapload : mitemmaploadmanual
  463. {
  464. mitemmapload(gmenu *parent, const char *filename, char *text, char *action, char *hoveraction, color *bgcolor, const char *desc = NULL) : mitemmaploadmanual(parent, filename, NULL, text, action, hoveraction, bgcolor, desc) {}
  465. // mitemimage (gmenu *parent, const char *filename, char *text, char *action, char *hoveraction, color *bgcolor, const char *desc = NULL) : mitemimagemanual (parent, filename, NULL, text, action, hoveraction, bgcolor, desc) {}
  466. // mitemmapload(gmenu *parent, const char *filename, char *text, char *action, char *hoveraction, color *bgcolor, const char *desc = NULL) : mitemmaploadmanual(parent, filename, NULL, text, action, hoveraction, bgcolor, desc) {}
  467. // mitemmanual (gmenu *parent, char *text, char *action, char *hoveraction, color *bgcolor, const char *desc) : mitem(parent, bgcolor), text(text), action(action), hoveraction(hoveraction), desc(desc) {}
  468.  
  469. virtual ~mitemmapload()
  470. {
  471. DELETEA(filename);
  472. //DELETEA(maptitle);
  473. //DELETEA(mapstats);
  474. DELETEA(text);
  475. DELETEA(action);
  476. }
  477. };
  478.  
  479. // text input item
  480.  
  481. struct mitemtextinput : mitemtext
  482. {
  483. textinputbuffer input;
  484. char *defaultvalueexp;
  485. bool modified;
  486.  
  487. mitemtextinput(gmenu *parent, char *text, char *value, char *action, char *hoveraction, color *bgcolor, int maxchars) : mitemtext(parent, text, action, hoveraction, bgcolor), defaultvalueexp(value), modified(false)
  488. {
  489. copystring(input.buf, value);
  490. input.max = maxchars>0 ? maxchars : 15;
  491. }
  492.  
  493. virtual int width()
  494. {
  495. int labelw = text_width(text);
  496. int maxw = min(input.max, 15)*text_width("w"); // w is broadest, not a - but limit to 15*w
  497. return labelw + maxw;
  498. }
  499.  
  500. virtual void render(int x, int y, int w)
  501. {
  502. bool selection = isselection();
  503. int tw = max(VIRTW/4, 15*text_width("w"));
  504. if(selection) renderbg(x+w-tw, y-FONTH/6, tw, NULL);
  505. draw_text(text, x, y);
  506. int cibl = (int)strlen(input.buf); // current input-buffer length
  507. int iboff = input.pos > 14 ? (input.pos < cibl ? input.pos - 14 : cibl - 14) : input.pos==-1 ? (cibl > 14 ? cibl - 14 : 0) : 0; // input-buffer offset
  508. string showinput; int sc = 14;
  509. while(iboff > 0)
  510. {
  511. copystring(showinput, input.buf + iboff - 1, sc + 2);
  512. if(text_width(showinput) > 15 * text_width("w")) break;
  513. iboff--; sc++;
  514. }
  515. while(iboff + sc < cibl)
  516. {
  517. copystring(showinput, input.buf + iboff, sc + 2);
  518. if(text_width(showinput) > 15 * text_width("w")) break;
  519. sc++;
  520. }
  521. copystring(showinput, input.buf + iboff, sc + 1);
  522. draw_text(showinput, x+w-tw, y, 255, 255, 255, 255, selection ? (input.pos>=0 ? (input.pos > sc ? sc : input.pos) : cibl) : -1);
  523. }
  524.  
  525. virtual void focus(bool on)
  526. {
  527. SDL_EnableUNICODE(on);
  528. if(!strlen(input.buf)) setdefaultvalue();
  529. if(action && !on && modified)
  530. {
  531. modified = false;
  532. push("arg1", input.buf);
  533. execute(action);
  534. pop("arg1");
  535. }
  536. }
  537.  
  538. virtual void key(int code, bool isdown, int unicode)
  539. {
  540. if(input.key(code, isdown, unicode)) modified = true;
  541. }
  542.  
  543. virtual void init()
  544. {
  545. setdefaultvalue();
  546. modified = false;
  547. }
  548.  
  549. virtual void select() { }
  550.  
  551. void setdefaultvalue()
  552. {
  553. const char *p = defaultvalueexp;
  554. char *r = executeret(p);
  555. copystring(input.buf, r ? r : "");
  556. if(r) delete[] r;
  557. }
  558. };
  559.  
  560. // slider item
  561.  
  562. struct mitemslider : mitem
  563. {
  564. int min_, max_, step, value, maxvaluewidth;
  565. char *text, *valueexp, *display, *action;
  566. string curval;
  567. static int sliderwidth;
  568.  
  569. mitemslider(gmenu *parent, char *text, int min_, int max_, int step, char *value, char *display, char *action, color *bgcolor) : mitem(parent, bgcolor), min_(min_), max_(max_), step(step), value(min_), maxvaluewidth(0), text(text), valueexp(value), display(display), action(action)
  570. {
  571. if(sliderwidth==0) sliderwidth = max(VIRTW/4, 15*text_width("w")); // match slider width with width of text input fields
  572. }
  573.  
  574. virtual ~mitemslider()
  575. {
  576. DELETEA(text);
  577. DELETEA(valueexp);
  578. DELETEA(display);
  579. DELETEA(action);
  580. }
  581.  
  582. virtual int width() { return text_width(text) + sliderwidth + maxvaluewidth + 2*FONTH; }
  583.  
  584. virtual void render(int x, int y, int w)
  585. {
  586. bool sel = isselection();
  587. int range = max_-min_;
  588. int cval = value-min_;
  589.  
  590. int tw = text_width(text);
  591. if(sel) renderbg(x+w-sliderwidth, y, sliderwidth, NULL);
  592. draw_text(text, x, y);
  593. draw_text(curval, x+tw, y);
  594.  
  595. blendbox(x+w-sliderwidth, y+FONTH/3, x+w, y+FONTH*2/3, false, -1, &gray);
  596. int offset = (int)(cval/((float)range)*sliderwidth);
  597. blendbox(x+w-sliderwidth+offset-FONTH/6, y, x+w-sliderwidth+offset+FONTH/6, y+FONTH, false, -1, sel ? &whitepulse : &white);
  598. }
  599.  
  600. virtual void key(int code, bool isdown, int unicode)
  601. {
  602. if(code == SDLK_LEFT) slide(false);
  603. else if(code == SDLK_RIGHT) slide(true);
  604. }
  605.  
  606. virtual void init()
  607. {
  608. const char *p = valueexp;
  609. char *v = executeret(p);
  610. if(v)
  611. {
  612. value = min(max_, max(min_, atoi(v)));
  613. delete[] v;
  614. }
  615. displaycurvalue();
  616. getmaxvaluewidth();
  617. }
  618.  
  619. void slide(bool right)
  620. {
  621. value += right ? step : -step;
  622. value = min(max_, max(min_, value));
  623. displaycurvalue();
  624. if(action)
  625. {
  626. string v;
  627. itoa(v, value);
  628. push("arg1", v);
  629. execute(action);
  630. pop("arg1");
  631. }
  632. }
  633.  
  634. void displaycurvalue()
  635. {
  636. if(display) // extract display name from list
  637. {
  638. char *val = indexlist(display, value-min_);
  639. copystring(curval, val);
  640. delete[] val;
  641. }
  642. else itoa(curval, value); // display number only
  643. }
  644.  
  645. void getmaxvaluewidth()
  646. {
  647. int oldvalue = value;
  648. maxvaluewidth = 0;
  649. for(int v = min_; v <= max_; v++)
  650. {
  651. value = v;
  652. displaycurvalue();
  653. maxvaluewidth = max(text_width(curval), maxvaluewidth);
  654. }
  655. value = oldvalue;
  656. displaycurvalue();
  657. }
  658. };
  659.  
  660. int mitemslider::sliderwidth = 0;
  661.  
  662. // key input item
  663.  
  664. struct mitemkeyinput : mitem
  665. {
  666. char *text, *bindcmd;
  667. const char *keyname;
  668. static const char *unknown, *empty;
  669. bool capture;
  670.  
  671. mitemkeyinput(gmenu *parent, char *text, char *bindcmd, color *bgcolor) : mitem(parent, bgcolor), text(text), bindcmd(bindcmd), keyname(NULL), capture(false){};
  672.  
  673. ~mitemkeyinput()
  674. {
  675. DELETEA(text);
  676. DELETEA(bindcmd);
  677. }
  678.  
  679. virtual int width() { return text_width(text)+text_width(keyname ? keyname : " "); }
  680.  
  681. virtual void render(int x, int y, int w)
  682. {
  683. int tk = text_width(keyname ? keyname : " ");
  684. static color capturec(0.4f, 0, 0);
  685. if(isselection()) blendbox(x+w-tk-FONTH, y-FONTH/6, x+w+FONTH, y+FONTH+FONTH/6, false, -1, capture ? &capturec : NULL);
  686. draw_text(text, x, y);
  687. draw_text(keyname, x+w-tk, y);
  688. }
  689.  
  690. virtual void init()
  691. {
  692. displaycurrentbind();
  693. capture = false;
  694. }
  695.  
  696. virtual void select()
  697. {
  698. capture = true;
  699. keyname = empty;
  700. }
  701.  
  702. virtual void key(int code, bool isdown, int unicode)
  703. {
  704. if(!capture || code < -5 || code > SDLK_MENU) return;
  705. keym *km;
  706. while((km = findbinda(bindcmd))) { bindkey(km, ""); } // clear existing binds to this cmd
  707. if(bindc(code, bindcmd)) parent->init(); // re-init all bindings
  708. else conoutf("\f3could not bind key");
  709. }
  710.  
  711. void displaycurrentbind()
  712. {
  713. keym *km = findbinda(bindcmd);
  714. keyname = km ? km->name : unknown;
  715. }
  716. };
  717.  
  718. const char *mitemkeyinput::unknown = "?";
  719. const char *mitemkeyinput::empty = " ";
  720.  
  721. // checkbox menu item
  722.  
  723. struct mitemcheckbox : mitem
  724. {
  725. char *text, *valueexp, *action;
  726. bool checked;
  727.  
  728. mitemcheckbox(gmenu *parent, char *text, char *value, char *action, color *bgcolor) : mitem(parent, bgcolor), text(text), valueexp(value), action(action), checked(false) {};
  729.  
  730. ~mitemcheckbox()
  731. {
  732. DELETEA(text);
  733. DELETEA(valueexp);
  734. DELETEA(action);
  735. }
  736.  
  737. virtual int width() { return text_width(text) + FONTH + FONTH/3; }
  738.  
  739. virtual void select()
  740. {
  741. checked = !checked;
  742. if(action && action[0])
  743. {
  744. push("arg1", checked ? "1" : "0");
  745. execute(action);
  746. pop("arg1");
  747. }
  748. }
  749.  
  750. virtual void init()
  751. {
  752. const char *p = valueexp;
  753. char *r = executeret(p);
  754. checked = (r && atoi(r) > 0);
  755. if(r) delete[] r;
  756. }
  757.  
  758. virtual void render(int x, int y, int w)
  759. {
  760. bool sel = isselection();
  761. const static int boxsize = FONTH;
  762. draw_text(text, x, y);
  763. if(isselection()) renderbg(x+w-boxsize, y, boxsize, NULL);
  764. blendbox(x+w-boxsize, y, x+w, y+boxsize, false, -1, &gray);
  765. if(checked)
  766. {
  767. int x1 = x+w-boxsize-FONTH/6, x2 = x+w+FONTH/6, y1 = y-FONTH/6, y2 = y+boxsize+FONTH/6;
  768. line(x1, y1, x2, y2, sel ? &whitepulse : &white);
  769. line(x2, y1, x1, y2, sel ? &whitepulse : &white);
  770. }
  771. }
  772. };
  773.  
  774.  
  775. // console iface
  776.  
  777. void *addmenu(const char *name, const char *title, bool allowinput, void (__cdecl *refreshfunc)(void *, bool), bool (__cdecl *keyfunc)(void *, int, bool, int), bool hotkeys, bool forwardkeys)
  778. {
  779. name = newstring(name);
  780. gmenu &menu = menus[name];
  781. menu.name = name;
  782. menu.title = title;
  783. menu.header = menu.footer = NULL;
  784. menu.menusel = 0;
  785. menu.mdl = NULL;
  786. menu.allowinput = allowinput;
  787. menu.inited = false;
  788. menu.hotkeys = hotkeys;
  789. menu.refreshfunc = refreshfunc;
  790. menu.keyfunc = keyfunc;
  791. menu.initaction = NULL;
  792. menu.usefont = NULL;
  793. menu.dirlist = NULL;
  794. menu.forwardkeys = forwardkeys;
  795. lastmenu = &menu;
  796. return &menu;
  797. }
  798.  
  799. void newmenu(char *name, char *hotkeys, char *forwardkeys)
  800. {
  801. addmenu(name, NULL, true, NULL, NULL, atoi(hotkeys) > 0, atoi(forwardkeys) > 0);
  802. }
  803.  
  804. void menureset(void *menu)
  805. {
  806. gmenu &m = *(gmenu *)menu;
  807. m.items.deletecontents();
  808. }
  809.  
  810. void menumanual(void *menu, char *text, char *action, color *bgcolor, const char *desc)
  811. {
  812. gmenu &m = *(gmenu *)menu;
  813. m.items.add(new mitemmanual(&m, text, action, NULL, bgcolor, desc));
  814. }
  815.  
  816. void menuimagemanual(void *menu, const char *filename, const char *altfontname, char *text, char *action, color *bgcolor, const char *desc)
  817. {
  818. gmenu &m = *(gmenu *)menu;
  819. m.items.add(new mitemimagemanual(&m, filename, altfontname, text, action, NULL, bgcolor, desc));
  820. }
  821.  
  822. void menutitle(void *menu, const char *title)
  823. {
  824. gmenu &m = *(gmenu *)menu;
  825. m.title = title;
  826. }
  827.  
  828. void menuheader(void *menu, char *header, char *footer)
  829. {
  830. gmenu &m = *(gmenu *)menu;
  831. m.header = header && header[0] ? header : NULL;
  832. m.footer = footer && footer[0] ? footer : NULL;
  833. }
  834. void lastmenu_header(char *header, char *footer)
  835. {
  836. if(lastmenu)
  837. {
  838. menuheader(lastmenu, newstring(header), newstring(footer));
  839. }
  840. else conoutf("no last menu to apply to");
  841. }
  842. COMMANDN(menuheader, lastmenu_header, ARG_2STR);
  843.  
  844. void menufont(void *menu, const char *usefont)
  845. {
  846. gmenu &m = *(gmenu *)menu;
  847. if(usefont==NULL)
  848. {
  849. DELETEA(m.usefont);
  850. m.usefont = NULL;
  851. } else m.usefont = newstring(usefont);
  852. }
  853.  
  854. void setmenufont(char *usefont)
  855. {
  856. if(!lastmenu) return;
  857. menufont(lastmenu, usefont);
  858. }
  859.  
  860. void menuinit(char *initaction)
  861. {
  862. if(!lastmenu) return;
  863. lastmenu->initaction = newstring(initaction);
  864. }
  865.  
  866. void menuinitselection(int line)
  867. {
  868. if(!lastmenu) return;
  869. if(lastmenu->items.inrange(line)) lastmenu->menusel = line;
  870. }
  871.  
  872. void menuselection(char *menu, char *line)
  873. {
  874. if(!menu || !line || !menus.access(menu)) return;
  875. gmenu &m = menus[menu];
  876. menuselect(&m, atoi(line));
  877. }
  878.  
  879. void menuitem(char *text, char *action, char *hoveraction)
  880. {
  881. if(!lastmenu) return;
  882. char *t = newstring(text);
  883. lastmenu->items.add(new mitemtext(lastmenu, t, newstring(action[0] ? action : text), hoveraction[0] ? newstring(hoveraction) : NULL, NULL));
  884. }
  885.  
  886. void menuitemvar(char *eval, char *action, char *hoveraction)
  887. {
  888. if(!lastmenu) return;
  889. char *t = newstring(eval);
  890. lastmenu->items.add(new mitemtextvar(lastmenu, t, action[0] ? newstring(action) : NULL, hoveraction[0] ? newstring(hoveraction) : NULL));
  891. }
  892.  
  893. void menuitemimage(char *name, char *text, char *action, char *hoveraction)
  894. {
  895. if(!lastmenu) return;
  896. if(fileexists(name, "r") || findfile(name, "r") != name)
  897. lastmenu->items.add(new mitemimage(lastmenu, newstring(name), newstring(text), action[0] ? newstring(action) : NULL, hoveraction[0] ? newstring(hoveraction) : NULL, NULL));
  898. else
  899. lastmenu->items.add(new mitemtext(lastmenu, newstring(text), newstring(action[0] ? action : text), hoveraction[0] ? newstring(hoveraction) : NULL, NULL));
  900. }
  901.  
  902. void menuitemmapload(char *name, char *text)
  903. {
  904. if(!lastmenu) return;
  905. string caction;
  906. if(!text || text[0]=='\0') formatstring(caction)("map %s", name);
  907. else formatstring(caction)("%s", text);
  908. lastmenu->items.add(new mitemmapload(lastmenu, newstring(name), newstring(name), newstring(caction), NULL, NULL, NULL));
  909. }
  910.  
  911. void menuitemtextinput(char *text, char *value, char *action, char *hoveraction, char *maxchars)
  912. {
  913. if(!lastmenu || !text || !value) return;
  914. lastmenu->items.add(new mitemtextinput(lastmenu, newstring(text), newstring(value), action[0] ? newstring(action) : NULL, hoveraction[0] ? newstring(hoveraction) : NULL, NULL, atoi(maxchars)));
  915. }
  916.  
  917. void menuitemslider(char *text, char *min_, char *max_, char *value, char *step, char *display, char *action)
  918. {
  919. if(!lastmenu) return;
  920. lastmenu->items.add(new mitemslider(lastmenu, newstring(text), atoi(min_), atoi(max_), atoi(step), newstring(value), display[0] ? newstring(display) : NULL, action[0] ? newstring(action) : NULL, NULL));
  921. }
  922.  
  923. void menuitemkeyinput(char *text, char *bindcmd)
  924. {
  925. if(!lastmenu) return;
  926. lastmenu->items.add(new mitemkeyinput(lastmenu, newstring(text), newstring(bindcmd), NULL));
  927. }
  928.  
  929. void menuitemcheckbox(char *text, char *value, char *action)
  930. {
  931. if(!lastmenu) return;
  932. lastmenu->items.add(new mitemcheckbox(lastmenu, newstring(text), newstring(value), action[0] ? newstring(action) : NULL, NULL));
  933. }
  934.  
  935. void menumdl(char *mdl, char *anim, char *rotspeed, char *scale)
  936. {
  937. if(!lastmenu || !mdl || !anim) return;
  938. gmenu &menu = *lastmenu;
  939. menu.mdl = newstring(mdl);
  940. menu.anim = findanim(anim)|ANIM_LOOP;
  941. menu.rotspeed = max(0, min(atoi(rotspeed), 100));
  942. menu.scale = max(0, min(atoi(scale), 100));
  943. }
  944.  
  945. void menudirlist(char *dir, char *ext, char *action, char *image)
  946. {
  947. if(!lastmenu) return;
  948. gmenu *menu = lastmenu;
  949. if(menu->dirlist) delete menu->dirlist;
  950. mdirlist *d = menu->dirlist = new mdirlist;
  951. d->dir = newstring(dir);
  952. d->ext = ext[0] ? newstring(ext): NULL;
  953. d->action = action[0] ? newstring(action) : NULL;
  954. d->image = atoi(image)!=0;
  955. }
  956.  
  957. void chmenumdl(char *menu, char *mdl, char *anim, char *rotspeed, char *scale)
  958. {
  959. if(!menu || !menus.access(menu)) return;
  960. gmenu &m = menus[menu];
  961. DELETEA(m.mdl);
  962. if(!mdl ||!*mdl) return;
  963. m.mdl = newstring(mdl);
  964. m.anim = findanim(anim)|ANIM_LOOP;
  965. m.rotspeed = max(0, min(atoi(rotspeed), 100));
  966. m.scale = max(0, min(atoi(scale), 100));
  967. }
  968.  
  969. bool parsecolor(color *col, const char *r, const char *g, const char *b, const char *a)
  970. {
  971. if(!r[0] || !col) return false; // four possible parameter schemes:
  972. if(!g[0]) g = b = r; // grey
  973. if(!b[0]) { a = g; g = b = r; } // grey alpha
  974. col->r = ((float) atoi(r)) / 100; // red green blue
  975. col->g = ((float) atoi(g)) / 100; // red green blue alpha
  976. col->b = ((float) atoi(b)) / 100;
  977. col->alpha = a[0] ? ((float) atoi(a)) / 100 : 1.0;
  978. return true;
  979. }
  980.  
  981. void menuselectionbgcolor(char *r, char *g, char *b, char *a)
  982. {
  983. if(!menuselbgcolor) menuselbgcolor = new color;
  984. if(!r[0]) { DELETEA(menuselbgcolor); return; }
  985. parsecolor(menuselbgcolor, r, g, b, a);
  986. }
  987.  
  988. COMMAND(newmenu, ARG_3STR);
  989. COMMAND(menumdl, ARG_5STR);
  990. COMMAND(menudirlist, ARG_4STR);
  991. COMMAND(chmenumdl, ARG_6STR);
  992. COMMANDN(showmenu, showmenu_, ARG_1STR);
  993. COMMAND(closemenu, ARG_1STR);
  994. COMMANDN(menufont, setmenufont, ARG_1STR);
  995. COMMAND(menuinit, ARG_1STR);
  996. COMMAND(menuinitselection, ARG_1INT);
  997. COMMAND(menuselection, ARG_2STR);
  998. COMMAND(menuitem, ARG_3STR);
  999. COMMAND(menuitemvar, ARG_3STR);
  1000. COMMAND(menuitemimage, ARG_4STR);
  1001. COMMAND(menuitemmapload, ARG_2STR);
  1002. COMMAND(menuitemtextinput, ARG_5STR);
  1003. COMMAND(menuitemslider, ARG_7STR);
  1004. COMMAND(menuitemkeyinput, ARG_2STR);
  1005. COMMAND(menuitemcheckbox, ARG_3STR);
  1006. COMMAND(menuselectionbgcolor, ARG_4STR);
  1007.  
  1008. bool menukey(int code, bool isdown, int unicode, SDLMod mod)
  1009. {
  1010. if(!curmenu) return false;
  1011. int n = curmenu->items.length(), menusel = curmenu->menusel;
  1012. if(isdown)
  1013. {
  1014. bool hasdesc = false;
  1015. loopv(curmenu->items) if(curmenu->items[i]->getdesc()) { hasdesc = true; break;}
  1016. //int pagesize = MAXMENU - (curmenu->header ? 2 : 0) - (curmenu->footer || hasdesc ? 2 : 0); // FIXME: footer-length
  1017. int pagesize = MAXMENU - (curmenu->header ? 2 : 0) - (curmenu->footer ? (curmenu->footlen?(curmenu->footlen+1):2) : (hasdesc ? 2 : 0)); // FIXME: footer-length
  1018. switch(code)
  1019. {
  1020. case SDLK_PAGEUP: menusel -= pagesize; break;
  1021. case SDLK_PAGEDOWN:
  1022. if(menusel+pagesize>=n && menusel/pagesize!=(n-1)/pagesize) menusel = n-1;
  1023. else menusel += pagesize;
  1024. break;
  1025. case SDLK_ESCAPE:
  1026. case -3:
  1027. if(!curmenu->allowinput) return false;
  1028. menuset(menustack.empty() ? NULL : menustack.pop(), false);
  1029. return true;
  1030. break;
  1031. case SDLK_UP:
  1032. case -4:
  1033. if(!curmenu->allowinput) return false;
  1034. menusel--;
  1035. break;
  1036. case SDLK_DOWN:
  1037. case -5:
  1038. if(!curmenu->allowinput) return false;
  1039. menusel++;
  1040. break;
  1041.  
  1042. case SDLK_TAB:
  1043. if(!curmenu->allowinput) return false;
  1044. if(mod & KMOD_LSHIFT) menusel--;
  1045. else menusel++;
  1046. break;
  1047.  
  1048. case SDLK_PRINT:
  1049. curmenu->conprintmenu();
  1050. return true;
  1051.  
  1052. case SDLK_F12:
  1053. {
  1054. extern void screenshot(const char *imagepath);
  1055. if(!curmenu->allowinput) return false;
  1056. screenshot(NULL);
  1057. break;
  1058. }
  1059.  
  1060. case SDLK_1:
  1061. case SDLK_2:
  1062. case SDLK_3:
  1063. case SDLK_4:
  1064. case SDLK_5:
  1065. case SDLK_6:
  1066. case SDLK_7:
  1067. case SDLK_8:
  1068. case SDLK_9:
  1069. if(curmenu->allowinput && curmenu->hotkeys)
  1070. {
  1071. int idx = code-SDLK_1;
  1072. if(curmenu->items.inrange(idx))
  1073. {
  1074. menuselect(curmenu, idx);
  1075. mitem &m = *curmenu->items[idx];
  1076. m.select();
  1077. }
  1078. return true;
  1079. }
  1080. default:
  1081. {
  1082. if(!curmenu->allowinput) return false;
  1083. if(curmenu->keyfunc && (*curmenu->keyfunc)(curmenu, code, isdown, unicode)) return true;
  1084. if(!curmenu->items.inrange(menusel)) return false;
  1085. mitem &m = *curmenu->items[menusel];
  1086. m.key(code, isdown, unicode);
  1087. return !curmenu->forwardkeys;
  1088. }
  1089. }
  1090.  
  1091. if(!curmenu->hotkeys) menuselect(curmenu, menusel);
  1092. return true;
  1093. }
  1094. else
  1095. {
  1096. if(!curmenu->allowinput || !curmenu->items.inrange(menusel)) return false;
  1097. mitem &m = *curmenu->items[menusel];
  1098. if(code==SDLK_RETURN || code==SDLK_SPACE || code==-1 || code==-2)
  1099. {
  1100. m.select();
  1101. audiomgr.playsound(S_MENUENTER, SP_HIGHEST);
  1102. return true;
  1103. }
  1104. return false;
  1105. }
  1106. }
  1107.  
  1108. void rendermenumdl()
  1109. {
  1110. if(!curmenu) return;
  1111. gmenu &m = *curmenu;
  1112. if(!m.mdl) return;
  1113.  
  1114. glPushMatrix();
  1115. glLoadIdentity();
  1116. glRotatef(90+180, 0, -1, 0);
  1117. glRotatef(90, -1, 0, 0);
  1118. glScalef(1, -1, 1);
  1119.  
  1120. bool isplayermodel = !strncmp(m.mdl, "playermodels", strlen("playermodels"));
  1121.  
  1122. vec pos;
  1123. if(isplayermodel) pos = vec(2.0f, 1.2f, -0.4f);
  1124. else pos = vec(2.0f, 0, 1.7f);
  1125.  
  1126. float yaw = 1.0f;
  1127. if(m.rotspeed) yaw += lastmillis/5.0f/100.0f*m.rotspeed;
  1128.  
  1129. int tex = 0;
  1130. if(isplayermodel)
  1131. {
  1132. defformatstring(skin)("packages/models/%s.jpg", m.mdl);
  1133. tex = -(int)textureload(skin)->id;
  1134. }
  1135. modelattach a[2];
  1136. if(isplayermodel)
  1137. {
  1138. a[0].name = "weapons/subgun/world";
  1139. a[0].tag = "tag_weapon";
  1140. }
  1141. rendermodel(isplayermodel ? "playermodels" : m.mdl, m.anim|ANIM_DYNALLOC, tex, -1, pos, yaw, 0, 0, 0, NULL, a, m.scale ? m.scale/25.0f : 1.0f);
  1142.  
  1143. glPopMatrix();
  1144. }
  1145.  
  1146. void gmenu::refresh()
  1147. {
  1148. if(!refreshfunc) return;
  1149. (*refreshfunc)(this, !inited);
  1150. inited = true;
  1151. if(menusel>=items.length()) menusel = max(items.length()-1, 0);
  1152. }
  1153.  
  1154. void gmenu::open()
  1155. {
  1156. inited = false;
  1157. if(!allowinput) menusel = 0;
  1158. if(!forwardkeys) player1->stopmoving();
  1159. if(items.inrange(menusel)) items[menusel]->focus(true);
  1160. init();
  1161. if(initaction) execute(initaction);
  1162. }
  1163.  
  1164. void gmenu::close()
  1165. {
  1166. if(items.inrange(menusel)) items[menusel]->focus(false);
  1167. }
  1168.  
  1169. void gmenu::conprintmenu()
  1170. {
  1171. if(title) conoutf( "[:: %s ::]", title);//if(items.length()) conoutf( " %03d items", items.length());
  1172. loopv(items) { conoutf("%03d: %s%s%s", 1+i, items[i]->gettext(), items[i]->getaction()?"|\t|":"", items[i]->getaction()?items[i]->getaction():""); }
  1173. }
  1174.  
  1175. void gmenu::init()
  1176. {
  1177. if(dirlist)
  1178. {
  1179. items.deletecontents();
  1180. vector<char *> files;
  1181. listfiles(dirlist->dir, dirlist->ext, files);
  1182. files.sort(stringsort);
  1183. loopv(files)
  1184. {
  1185. char *f = files[i];
  1186. if(!f || !f[0]) continue;
  1187. char *d = getfiledesc(dirlist->dir, f, dirlist->ext);
  1188. defformatstring(jpgname)("%s/preview/%s.jpg", dirlist->dir, f);
  1189. if(dirlist->image)
  1190. {
  1191. string fullname = "";
  1192. if(dirlist->dir[0]) formatstring(fullname)("%s/%s", dirlist->dir, f);
  1193. else copystring(fullname, f);
  1194. if(dirlist->ext)
  1195. {
  1196. concatstring(fullname, ".");
  1197. concatstring(fullname, dirlist->ext);
  1198. }
  1199. items.add(new mitemimage (this, newstring(fullname), f, newstring(dirlist->action), NULL, NULL, d));
  1200. }
  1201. else if(!strcmp(dirlist->ext, "cgz") /*&& (fileexists(jpgname, "r") || findfile(jpgname, "r") != jpgname)*/)
  1202. {
  1203. //items.add(new mitemimage(this, newstring(jpgname), f, newstring(dirlist->action), NULL, NULL, d));
  1204. int diroffset = 0;
  1205. if(dirlist->dir[0])
  1206. {
  1207. unsigned int ddsl = strlen("packages/");
  1208. if(strlen(dirlist->dir)>ddsl)
  1209. {
  1210. string prefix;
  1211. copystring(prefix, dirlist->dir, ddsl+1);
  1212. if(!strcmp(prefix,"packages/")) diroffset = ddsl;
  1213. }
  1214. }
  1215. defformatstring(fullname)("%s%s%s", dirlist->dir[0]?dirlist->dir+diroffset:"", dirlist->dir[0]?"/":"", f);
  1216. defformatstring(caction)("map %s", fullname);
  1217. defformatstring(title)("%s", d[0]!='\0'?d:f);
  1218. items.add(new mitemmapload(this, newstring(fullname), newstring(title), newstring(caction), NULL, NULL, NULL));
  1219. }
  1220. else items.add(new mitemtext(this, f, newstring(dirlist->action), NULL, NULL, d));
  1221. }
  1222. }
  1223. loopv(items) items[i]->init();
  1224. }
  1225.  
  1226. void gmenu::render()
  1227. {
  1228. if(usefont) pushfont(usefont);
  1229. const char *t = title;
  1230. if(!t)
  1231. {
  1232. static string buf;
  1233. if(hotkeys) formatstring(buf)("%s hotkeys", name);
  1234. else formatstring(buf)("[ %s menu ]", name);
  1235. t = buf;
  1236. }
  1237. bool hasdesc = false;
  1238. if(title) text_startcolumns();
  1239. int w = 0;
  1240. loopv(items)
  1241. {
  1242. int x = items[i]->width();
  1243. if(x>w) w = x;
  1244. if(items[i]->getdesc())
  1245. {
  1246. hasdesc = true;
  1247. x = text_width(items[i]->getdesc());
  1248. if(x>w) w = x;
  1249. }
  1250. }
  1251. //int hitems = (header ? 2 : 0) + (footer || hasdesc ? 2 : 0), // FIXME: footer-length
  1252. int hitems = (header ? 2 : 0) + (footer ? (footlen?(footlen+1):2) : (hasdesc ? 2 : 0)),
  1253. pagesize = MAXMENU - hitems,
  1254. offset = menusel - (menusel%pagesize),
  1255. mdisp = min(items.length(), pagesize),
  1256. cdisp = min(items.length()-offset, pagesize);
  1257. mitem::whitepulse.alpha = (sinf(lastmillis/200.0f)+1.0f)/2.0f;
  1258. int tw = text_width(t);
  1259. if(tw>w) w = tw;
  1260. if(header)
  1261. {
  1262. int hw = text_width(header);
  1263. if(hw>w) w = hw;
  1264. }
  1265.  
  1266. int step = (FONTH*5)/4;
  1267. int h = (mdisp+hitems+2)*step;
  1268. int y = (2*VIRTH-h)/2;
  1269. int x = hotkeys ? (2*VIRTW-w)/6 : (2*VIRTW-w)/2;
  1270. if(!hotkeys) renderbg(x-FONTH*3/2, y-FONTH, x+w+FONTH*3/2, y+h+FONTH, true);
  1271. if(offset>0) drawarrow(1, x+w+FONTH*3/2-FONTH*5/6, y-FONTH*5/6, FONTH*2/3);
  1272. if(offset+pagesize<items.length()) drawarrow(0, x+w+FONTH*3/2-FONTH*5/6, y+h+FONTH/6, FONTH*2/3);
  1273. if(header)
  1274. {
  1275. draw_text(header, x, y);
  1276. y += step*2;
  1277. }
  1278. draw_text(t, x, y);
  1279. y += step*2;
  1280. loopj(cdisp)
  1281. {
  1282. items[offset+j]->render(x, y, w);
  1283. y += step;
  1284. }
  1285. if(title) text_endcolumns();
  1286. if(footer || hasdesc)
  1287. {
  1288. y += ((mdisp-cdisp)+1)*step;
  1289. if(!hasdesc)
  1290. {
  1291. footlen = 0;
  1292. if(text_width(footer)>w)
  1293. {
  1294. int tflo = 0;
  1295. int cflw = 0;
  1296. unsigned int cflc = 0;
  1297. string pofl;
  1298. string bufl;
  1299. bool keepon = true;
  1300. while(keepon)
  1301. {
  1302. while(cflw<w && cflc<strlen(footer))
  1303. {
  1304. cflc++;
  1305. formatstring(bufl)("%s", footer+tflo);
  1306. copystring(pofl, bufl, cflc-tflo);
  1307. cflw = text_width(pofl);
  1308. }
  1309. if(cflc<=strlen(footer))
  1310. {
  1311. if(cflc==strlen(footer) || cflc>=MAXSTRLEN) keepon = false;
  1312. cflc--;
  1313. cflw = 0;
  1314. formatstring(bufl)("%s", footer+tflo);
  1315. copystring(pofl, bufl, cflc-tflo);
  1316. draw_text(pofl, x, y);
  1317. y+=step;
  1318. tflo = cflc-1;
  1319. footlen++;
  1320. }
  1321. }
  1322. }
  1323. else draw_text(footer, x, y);
  1324. }
  1325. else if(items.inrange(menusel) && items[menusel]->getdesc())
  1326. draw_text(items[menusel]->getdesc(), x, y);
  1327.  
  1328. }
  1329. if(usefont) popfont(); // setfont("default");
  1330. }
  1331.  
  1332. void gmenu::renderbg(int x1, int y1, int x2, int y2, bool border)
  1333. {
  1334. static Texture *tex = NULL;
  1335. if(!tex) tex = textureload("packages/textures/makke/menu.jpg");
  1336. static color transparent(1, 1, 1, 0.75f);
  1337. blendbox(x1, y1, x2, y2, border, tex->id, allowinput ? NULL : &transparent);
  1338. }
  1339.  
  1340. // apply changes menu
  1341.  
  1342. void *applymenu = NULL;
  1343. static vector<const char *> needsapply;
  1344. VARP(applydialog, 0, 1, 1);
  1345.  
  1346. void addchange(const char *desc, int type)
  1347. {
  1348. if(!applydialog) return;
  1349. if(type!=CHANGE_GFX)
  1350. {
  1351. conoutf(_("..restart AssaultCube for this setting to take effect"));
  1352. return;
  1353. }
  1354. bool changed = false;
  1355. loopv(needsapply) if(!strcmp(needsapply[i], desc)) { changed = true; break; }
  1356. if(!changed) needsapply.add(desc);
  1357. showmenu("apply", false);
  1358. }
  1359.  
  1360. void clearchanges(int type)
  1361. {
  1362. if(type!=CHANGE_GFX) return;
  1363. needsapply.shrink(0);
  1364. closemenu("apply");
  1365. }
  1366.  
  1367. void refreshapplymenu(void *menu, bool init)
  1368. {
  1369. gmenu *m = (gmenu *) menu;
  1370. if(!m || (!init && needsapply.length() != m->items.length()-3)) return;
  1371. m->items.deletecontents();
  1372. loopv(needsapply) m->items.add(new mitemtext(m, newstring(needsapply[i]), NULL, NULL, NULL));
  1373. m->items.add(new mitemtext(m, newstring(""), NULL, NULL, NULL));
  1374. m->items.add(new mitemtext(m, newstring("Yes"), newstring("resetgl"), NULL, NULL));
  1375. m->items.add(new mitemtext(m, newstring("No"), newstring("echo [..restart AssaultCube to apply the new settings]"), NULL, NULL));
  1376. if(init) m->menusel = m->items.length()-2; // select OK
  1377. }
  1378.  
  1379. void reorderscorecolumns();
  1380. VARFP(orderscorecolumns, 0, 0, 1, reorderscorecolumns());
  1381. void reorderscorecolumns()
  1382. {
  1383. extern void *scoremenu, *teammenu, *ctfmenu;
  1384. switch(orderscorecolumns)
  1385. {
  1386. case 1:
  1387. {
  1388. menutitle(scoremenu, "cn\tname\tfrags\tdeaths\tratio\tscore\tpj/ping");
  1389. menutitle( teammenu, "cn\tname\tfrags\tdeaths\tratio\tscore\tpj/ping");
  1390. menutitle( ctfmenu, "cn\tname\tflags\tfrags\tdeaths\tratio\tscore\tpj/ping");
  1391. break;
  1392. }
  1393. case 0:
  1394. default:
  1395. {
  1396. menutitle(scoremenu, "frags\tdeaths\tratio\tscore\tpj/ping\tcn\tname");
  1397. menutitle( teammenu, "frags\tdeaths\tratio\tscore\tpj/ping\tcn\tname");
  1398. menutitle( ctfmenu, "flags\tfrags\tdeaths\tratio\tscore\tpj/ping\tcn\tname");
  1399. break;
  1400. }
  1401. }
  1402. }
  1403.  
  1404. void setscorefont();
  1405. VARFP(scorefont, 0, 0, 1, setscorefont());
  1406. void setscorefont()
  1407. {
  1408. extern void *scoremenu, *teammenu, *ctfmenu;
  1409. switch(scorefont)
  1410. {
  1411. case 1:
  1412. {
  1413. menufont(scoremenu, "mono");
  1414. menufont(teammenu, "mono");
  1415. menufont(ctfmenu, "mono");
  1416. break;
  1417. }
  1418. case 0:
  1419. default:
  1420. {
  1421. menufont(scoremenu, NULL); // "default"
  1422. menufont(teammenu, NULL); // "default"
  1423. menufont(ctfmenu, NULL); // "default"
  1424. break;
  1425. }
  1426. }
  1427. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement