PageRenderTime 60ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/ports/psp/branches/alephonepsp-old/Source_Files/Misc/sdl_dialogs.cpp

#
C++ | 1429 lines | 965 code | 243 blank | 221 comment | 210 complexity | fbd42993eb2f20b087579f1457538ba6 MD5 | raw file
Possible License(s): LGPL-2.0, LGPL-2.1, BSD-3-Clause, GPL-3.0, LGPL-3.0, MPL-2.0-no-copyleft-exception, Zlib, GPL-2.0
  1. #include <cstdlib>
  2. /*
  3. Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
  4. and the "Aleph One" developers.
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. This license is contained in the file "COPYING",
  14. which is included with this source code; it is available online at
  15. http://www.gnu.org/licenses/gpl.html
  16. */
  17. /*
  18. * sdl_dialogs.cpp - SDL implementation of user dialogs
  19. *
  20. * Written in 2000 by Christian Bauer
  21. *
  22. * 11 Mar 2002 (Woody Zenfell): renamed XML_FrameParser to XML_DFrameParser
  23. * to resolve conflict with new animated-model frame parsing code.
  24. *
  25. * 5 Feb 2003 (Woody Zenfell): exposed draw_dirty_widgets() functionality
  26. * also trying to fix fullscreen drawing problems related to flipping
  27. */
  28. #include "cseries.h"
  29. #include "sdl_dialogs.h"
  30. #include "sdl_fonts.h"
  31. #include "sdl_widgets.h"
  32. #include "shape_descriptors.h"
  33. #include "screen_drawing.h"
  34. #include "shell.h"
  35. #include "screen.h"
  36. #include "images.h"
  37. #include "world.h"
  38. #include "mysound.h"
  39. #include "game_errors.h"
  40. //#include "gp2x_joystick.h"
  41. #include "XML_Loader_SDL.h"
  42. #include "XML_ParseTreeRoot.h"
  43. #include <map>
  44. #ifdef __MVCPP__
  45. #include <string>
  46. #endif
  47. // Global variables
  48. dialog *top_dialog = NULL;
  49. static SDL_Surface *dialog_surface = NULL;
  50. static sdl_font_info *default_font = NULL;
  51. static SDL_Surface *default_image = NULL;
  52. static OpenedResourceFile theme_resources;
  53. static TextSpec dialog_font_spec[NUM_DIALOG_FONTS];
  54. static sdl_font_info *dialog_font[NUM_DIALOG_FONTS];
  55. static SDL_Color dialog_color[NUM_DIALOG_COLORS];
  56. static uint16 dialog_space[NUM_DIALOG_SPACES];
  57. static struct dialog_image_spec_type {
  58. string name;
  59. bool scale;
  60. } dialog_image_spec[NUM_DIALOG_IMAGES];
  61. static SDL_Surface *dialog_image[NUM_DIALOG_IMAGES];
  62. // Prototypes
  63. static void shutdown_dialogs(void);
  64. static void unload_theme(void);
  65. static void set_theme_defaults(void);
  66. /*
  67. * Initialize dialog manager
  68. */
  69. void initialize_dialogs(FileSpecifier &theme)
  70. {
  71. // Allocate surface for dialogs (this surface is needed because when
  72. // OpenGL is active, we can't write directly to the screen)
  73. dialog_surface = SDL_CreateRGBSurface(SDL_SWSURFACE, 640, 480, 16, 0x7c00, 0x03e0, 0x001f, 0);
  74. assert(dialog_surface);
  75. // Default font and image
  76. static const TextSpec default_font_spec = {kFontIDMonaco, styleNormal, 12};
  77. default_font = load_font(default_font_spec);
  78. assert(default_font);
  79. default_image = SDL_CreateRGBSurface(SDL_SWSURFACE, 1, 1, 24, 0xff0000, 0x00ff00, 0x0000ff, 0);
  80. assert(default_image);
  81. uint32 transp = SDL_MapRGB(default_image->format, 0x00, 0xff, 0xff);
  82. SDL_FillRect(default_image, NULL, transp);
  83. SDL_SetColorKey(default_image, SDL_SRCCOLORKEY, transp);
  84. // Load theme from preferences
  85. load_theme(theme);
  86. atexit(shutdown_dialogs);
  87. }
  88. /*
  89. * Shutdown dialog manager
  90. */
  91. static void shutdown_dialogs(void)
  92. {
  93. unload_theme();
  94. }
  95. /*
  96. * Theme MML parser
  97. */
  98. class XML_ImageParser : public XML_ElementParser {
  99. public:
  100. XML_ImageParser(int base, int num = 1) : XML_ElementParser("image"), base_index(base), max_index(num - 1) {}
  101. bool Start()
  102. {
  103. have_index = have_name = false;
  104. scale = false;
  105. return true;
  106. }
  107. bool HandleAttribute(const char *tag, const char *value)
  108. {
  109. if (StringsEqual(tag, "index")) {
  110. if (ReadBoundedNumericalValue(value, "%d", index, 0, max_index))
  111. have_index = true;
  112. else
  113. return false;
  114. } else if (StringsEqual(tag, "file")) {
  115. name = value;
  116. have_name = true;
  117. } else if (StringsEqual(tag, "scale")) {
  118. return ReadBooleanValue(value, scale);
  119. } else {
  120. UnrecognizedTag();
  121. return false;
  122. }
  123. return true;
  124. }
  125. bool AttributesDone()
  126. {
  127. if (!have_index || !have_name) {
  128. AttribsMissing();
  129. return false;
  130. }
  131. dialog_image_spec[base_index + index].name = name;
  132. dialog_image_spec[base_index + index].scale = scale;
  133. return true;
  134. }
  135. private:
  136. int base_index, max_index;
  137. bool have_index, have_name;
  138. int index;
  139. string name;
  140. bool scale;
  141. };
  142. static XML_ImageParser FrameImageParser(FRAME_TL_IMAGE, 8);
  143. static XML_ImageParser ListImageParser(LIST_TL_IMAGE, 8);
  144. static XML_ImageParser ThumbImageParser(THUMB_T_IMAGE, 5);
  145. static XML_ImageParser SliderImageParser(SLIDER_L_IMAGE, 4);
  146. static XML_ImageParser ButtonImageParser(BUTTON_L_IMAGE, 3);
  147. class XML_DColorParser : public XML_ElementParser {
  148. public:
  149. XML_DColorParser(int base, int num = 1) : XML_ElementParser("color"), base_index(base), max_index(num - 1) {}
  150. bool Start()
  151. {
  152. have_red = have_green = have_blue = false;
  153. idx = 0;
  154. return true;
  155. }
  156. bool HandleAttribute(const char *tag, const char *value)
  157. {
  158. float v;
  159. if (StringsEqual(tag, "index")) {
  160. return ReadBoundedNumericalValue(value, "%d", idx, 0, max_index);
  161. } else if (StringsEqual(tag, "red")) {
  162. if (ReadNumericalValue(value, "%f", v)) {
  163. have_red = true;
  164. color.r = uint8(PIN(255 * v + 0.5, 0, 255));
  165. } else
  166. return false;
  167. } else if (StringsEqual(tag, "green")) {
  168. if (ReadNumericalValue(value, "%f", v)) {
  169. have_green = true;
  170. color.g = uint8(PIN(255 * v + 0.5, 0, 255));
  171. } else
  172. return false;
  173. } else if (StringsEqual(tag, "blue")) {
  174. if (ReadNumericalValue(value, "%f", v)) {
  175. have_blue = true;
  176. color.b = uint8(PIN(255 * v + 0.5, 0, 255));
  177. } else
  178. return false;
  179. } else {
  180. UnrecognizedTag();
  181. return false;
  182. }
  183. return true;
  184. }
  185. bool AttributesDone()
  186. {
  187. if (!have_red || !have_green || !have_blue) {
  188. AttribsMissing();
  189. return false;
  190. }
  191. dialog_color[base_index + idx] = color;
  192. return true;
  193. }
  194. private:
  195. int base_index, max_index;
  196. bool have_red, have_green, have_blue;
  197. int idx;
  198. SDL_Color color;
  199. };
  200. static XML_DColorParser BackgroundColorParser(BACKGROUND_COLOR);
  201. static XML_DColorParser TitleColorParser(TITLE_COLOR);
  202. static XML_DColorParser ButtonColorParser(BUTTON_COLOR, 2);
  203. static XML_DColorParser LabelColorParser(LABEL_COLOR, 2);
  204. static XML_DColorParser ItemColorParser(ITEM_COLOR, 2);
  205. static XML_DColorParser MessageColorParser(MESSAGE_COLOR);
  206. static XML_DColorParser TextEntryColorParser(TEXT_ENTRY_COLOR, 3);
  207. class XML_DFontParser : public XML_ElementParser {
  208. public:
  209. XML_DFontParser(int i) : XML_ElementParser("font"), idx(i) {}
  210. bool Start()
  211. {
  212. have_id = have_size = false;
  213. style = 0;
  214. return true;
  215. }
  216. bool HandleAttribute(const char *tag, const char *value)
  217. {
  218. if (StringsEqual(tag, "id")) {
  219. if (ReadNumericalValue(value, "%d", id))
  220. have_id = true;
  221. else
  222. return false;
  223. } else if (StringsEqual(tag, "size")) {
  224. if (ReadNumericalValue(value, "%d", size))
  225. have_size = true;
  226. else
  227. return false;
  228. } else if (StringsEqual(tag, "style")) {
  229. return ReadNumericalValue(value, "%d", style);
  230. } else {
  231. UnrecognizedTag();
  232. return false;
  233. }
  234. return true;
  235. }
  236. bool AttributesDone()
  237. {
  238. if (!have_id || !have_size) {
  239. AttribsMissing();
  240. return false;
  241. }
  242. dialog_font_spec[idx].font = id;
  243. dialog_font_spec[idx].style = style;
  244. dialog_font_spec[idx].size = size;
  245. return true;
  246. }
  247. private:
  248. bool have_id, have_size;
  249. int idx;
  250. int id, size, style;
  251. };
  252. static XML_DFontParser TitleFontParser(TITLE_FONT);
  253. static XML_DFontParser ButtonFontParser(BUTTON_FONT);
  254. static XML_DFontParser LabelFontParser(LABEL_FONT);
  255. static XML_DFontParser ItemFontParser(ITEM_FONT);
  256. static XML_DFontParser MessageFontParser(MESSAGE_FONT);
  257. static XML_DFontParser TextEntryFontParser(TEXT_ENTRY_FONT);
  258. static XML_DFontParser TextBoxFontParser(TEXT_BOX_FONT);
  259. class XML_DFrameParser : public XML_ElementParser {
  260. public:
  261. XML_DFrameParser() : XML_ElementParser("frame") {}
  262. bool HandleAttribute(const char *tag, const char *value)
  263. {
  264. if (StringsEqual(tag, "top")) {
  265. return ReadNumericalValue(value, "%hu", dialog_space[FRAME_T_SPACE]);
  266. } else if (StringsEqual(tag, "bottom")) {
  267. return ReadNumericalValue(value, "%hu", dialog_space[FRAME_B_SPACE]);
  268. } else if (StringsEqual(tag, "left")) {
  269. return ReadNumericalValue(value, "%hu", dialog_space[FRAME_L_SPACE]);
  270. } else if (StringsEqual(tag, "right")) {
  271. return ReadNumericalValue(value, "%hu", dialog_space[FRAME_R_SPACE]);
  272. } else {
  273. UnrecognizedTag();
  274. return false;
  275. }
  276. return true;
  277. }
  278. };
  279. static XML_DFrameParser FrameParser;
  280. struct XML_BackgroundParser : public XML_ElementParser {XML_BackgroundParser() : XML_ElementParser("background") {}};
  281. static XML_BackgroundParser BackgroundParser;
  282. struct XML_TitleParser : public XML_ElementParser {XML_TitleParser() : XML_ElementParser("title") {}};
  283. static XML_TitleParser TitleParser;
  284. class XML_SpacerParser : public XML_ElementParser {
  285. public:
  286. XML_SpacerParser() : XML_ElementParser("spacer") {}
  287. bool HandleAttribute(const char *tag, const char *value)
  288. {
  289. if (StringsEqual(tag, "height")) {
  290. return ReadNumericalValue(value, "%hu", dialog_space[SPACER_HEIGHT]);
  291. } else {
  292. UnrecognizedTag();
  293. return false;
  294. }
  295. return true;
  296. }
  297. };
  298. static XML_SpacerParser SpacerParser;
  299. class XML_ButtonParser : public XML_ElementParser {
  300. public:
  301. XML_ButtonParser() : XML_ElementParser("button") {}
  302. bool HandleAttribute(const char *tag, const char *value)
  303. {
  304. if (StringsEqual(tag, "top")) {
  305. return ReadNumericalValue(value, "%hu", dialog_space[BUTTON_T_SPACE]);
  306. } else if (StringsEqual(tag, "left")) {
  307. return ReadNumericalValue(value, "%hu", dialog_space[BUTTON_L_SPACE]);
  308. } else if (StringsEqual(tag, "right")) {
  309. return ReadNumericalValue(value, "%hu", dialog_space[BUTTON_R_SPACE]);
  310. } else if (StringsEqual(tag, "height")) {
  311. return ReadNumericalValue(value, "%hu", dialog_space[BUTTON_HEIGHT]);
  312. } else {
  313. UnrecognizedTag();
  314. return false;
  315. }
  316. return true;
  317. }
  318. };
  319. static XML_ButtonParser ButtonParser;
  320. struct XML_LabelParser : public XML_ElementParser {XML_LabelParser() : XML_ElementParser("label") {}};
  321. static XML_LabelParser LabelParser;
  322. class XML_DItemParser : public XML_ElementParser {
  323. public:
  324. XML_DItemParser() : XML_ElementParser("item") {}
  325. bool HandleAttribute(const char *tag, const char *value)
  326. {
  327. if (StringsEqual(tag, "space")) {
  328. return ReadNumericalValue(value, "%hu", dialog_space[LABEL_ITEM_SPACE]);
  329. } else {
  330. UnrecognizedTag();
  331. return false;
  332. }
  333. return true;
  334. }
  335. };
  336. static XML_DItemParser ItemParser;
  337. struct XML_MessageParser : public XML_ElementParser {XML_MessageParser() : XML_ElementParser("message") {}};
  338. static XML_MessageParser MessageParser;
  339. struct XML_TextEntryParser : public XML_ElementParser {XML_TextEntryParser() : XML_ElementParser("text_entry") {}};
  340. static XML_TextEntryParser TextEntryParser;
  341. struct XML_TextBoxParser : public XML_ElementParser { XML_TextBoxParser() : XML_ElementParser("text_box") {}};
  342. static XML_TextBoxParser TextBoxParser;
  343. class XML_TroughParser : public XML_ElementParser {
  344. public:
  345. XML_TroughParser() : XML_ElementParser("trough") {}
  346. bool HandleAttribute(const char *tag, const char *value)
  347. {
  348. if (StringsEqual(tag, "top")) {
  349. return ReadNumericalValue(value, "%hu", dialog_space[TROUGH_T_SPACE]);
  350. } else if (StringsEqual(tag, "bottom")) {
  351. return ReadNumericalValue(value, "%hu", dialog_space[TROUGH_B_SPACE]);
  352. } else if (StringsEqual(tag, "right")) {
  353. return ReadNumericalValue(value, "%hu", dialog_space[TROUGH_R_SPACE]);
  354. } else if (StringsEqual(tag, "width")) {
  355. return ReadNumericalValue(value, "%hu", dialog_space[TROUGH_WIDTH]);
  356. } else {
  357. UnrecognizedTag();
  358. return false;
  359. }
  360. return true;
  361. }
  362. };
  363. static XML_TroughParser TroughParser;
  364. struct XML_ThumbParser : public XML_ElementParser {XML_ThumbParser() : XML_ElementParser("thumb") {}};
  365. static XML_ThumbParser ThumbParser;
  366. class XML_ListParser : public XML_ElementParser {
  367. public:
  368. XML_ListParser() : XML_ElementParser("list") {}
  369. bool HandleAttribute(const char *tag, const char *value)
  370. {
  371. if (StringsEqual(tag, "top")) {
  372. return ReadNumericalValue(value, "%hu", dialog_space[LIST_T_SPACE]);
  373. } else if (StringsEqual(tag, "bottom")) {
  374. return ReadNumericalValue(value, "%hu", dialog_space[LIST_B_SPACE]);
  375. } else if (StringsEqual(tag, "left")) {
  376. return ReadNumericalValue(value, "%hu", dialog_space[LIST_L_SPACE]);
  377. } else if (StringsEqual(tag, "right")) {
  378. return ReadNumericalValue(value, "%hu", dialog_space[LIST_R_SPACE]);
  379. } else {
  380. UnrecognizedTag();
  381. return false;
  382. }
  383. return true;
  384. }
  385. };
  386. static XML_ListParser ListParser;
  387. class XML_SliderParser : public XML_ElementParser {
  388. public:
  389. XML_SliderParser() : XML_ElementParser("slider") {}
  390. bool HandleAttribute(const char *tag, const char *value)
  391. {
  392. if (StringsEqual(tag, "top")) {
  393. return ReadNumericalValue(value, "%hu", dialog_space[SLIDER_T_SPACE]);
  394. } else if (StringsEqual(tag, "left")) {
  395. return ReadNumericalValue(value, "%hu", dialog_space[SLIDER_L_SPACE]);
  396. } else if (StringsEqual(tag, "right")) {
  397. return ReadNumericalValue(value, "%hu", dialog_space[SLIDER_R_SPACE]);
  398. } else {
  399. UnrecognizedTag();
  400. return false;
  401. }
  402. return true;
  403. }
  404. };
  405. static XML_SliderParser SliderParser;
  406. class XML_ThemeParser : public XML_ElementParser {
  407. public:
  408. XML_ThemeParser() : XML_ElementParser("theme") {}
  409. };
  410. static XML_ThemeParser ThemeParser;
  411. XML_ElementParser *Theme_GetParser()
  412. {
  413. FrameParser.AddChild(&FrameImageParser);
  414. ThemeParser.AddChild(&FrameParser);
  415. BackgroundParser.AddChild(&BackgroundColorParser);
  416. ThemeParser.AddChild(&BackgroundParser);
  417. TitleParser.AddChild(&TitleFontParser);
  418. TitleParser.AddChild(&TitleColorParser);
  419. ThemeParser.AddChild(&TitleParser);
  420. ThemeParser.AddChild(&SpacerParser);
  421. ButtonParser.AddChild(&ButtonFontParser);
  422. ButtonParser.AddChild(&ButtonColorParser);
  423. ButtonParser.AddChild(&ButtonImageParser);
  424. ThemeParser.AddChild(&ButtonParser);
  425. LabelParser.AddChild(&LabelFontParser);
  426. LabelParser.AddChild(&LabelColorParser);
  427. ThemeParser.AddChild(&LabelParser);
  428. ItemParser.AddChild(&ItemFontParser);
  429. ItemParser.AddChild(&ItemColorParser);
  430. ThemeParser.AddChild(&ItemParser);
  431. MessageParser.AddChild(&MessageFontParser);
  432. MessageParser.AddChild(&MessageColorParser);
  433. ThemeParser.AddChild(&MessageParser);
  434. TextEntryParser.AddChild(&TextEntryFontParser);
  435. TextEntryParser.AddChild(&TextEntryColorParser);
  436. ThemeParser.AddChild(&TextEntryParser);
  437. TextBoxParser.AddChild(&TextBoxFontParser);
  438. ThemeParser.AddChild(&TextBoxParser);
  439. ListParser.AddChild(&ListImageParser);
  440. ListParser.AddChild(&TroughParser);
  441. ThumbParser.AddChild(&ThumbImageParser);
  442. ListParser.AddChild(&ThumbParser);
  443. ThemeParser.AddChild(&ListParser);
  444. SliderParser.AddChild(&SliderImageParser);
  445. ThemeParser.AddChild(&SliderParser);
  446. return &ThemeParser;
  447. }
  448. /*
  449. * Load theme
  450. */
  451. void load_theme(FileSpecifier &theme)
  452. {
  453. // Unload previous theme
  454. unload_theme();
  455. // Set defaults, the theme overrides these
  456. set_theme_defaults();
  457. // Parse theme MML script
  458. FileSpecifier theme_mml = theme + "theme.mml";
  459. XML_Loader_SDL loader;
  460. loader.CurrentElement = &RootParser;
  461. loader.ParseFile(theme_mml);
  462. // Open resource file
  463. FileSpecifier theme_rsrc = theme + "resources";
  464. theme_rsrc.Open(theme_resources);
  465. clear_game_error();
  466. // Load fonts
  467. for (int i=0; i<NUM_DIALOG_FONTS; i++)
  468. dialog_font[i] = load_font(dialog_font_spec[i]);
  469. // Load images
  470. for (int i=0; i<NUM_DIALOG_IMAGES; i++) {
  471. FileSpecifier file = theme + dialog_image_spec[i].name;
  472. SDL_Surface *s =SDL_LoadBMP(file.GetPath());
  473. if (s)
  474. SDL_SetColorKey(s, SDL_SRCCOLORKEY, SDL_MapRGB(s->format, 0x00, 0xff, 0xff));
  475. dialog_image[i] = s;
  476. }
  477. }
  478. /*
  479. * Set theme default values
  480. */
  481. static const SDL_Color default_dialog_color[NUM_DIALOG_COLORS] = {
  482. {0x00, 0x00, 0x00}, // BACKGROUND COLOR
  483. {0xc0, 0xc0, 0xc0}, // TITLE_COLOR
  484. {0xc0, 0x00, 0x00}, // BUTTON_COLOR
  485. {0xff, 0xff, 0xff}, // BUTTON_ACTIVE_COLOR
  486. {0x20, 0x20, 0xff}, // LABEL_COLOR
  487. {0x80, 0x80, 0xff}, // LABEL_ACTIVE_COLOR
  488. {0x40, 0xff, 0x40}, // ITEM_COLOR
  489. {0xff, 0xff, 0xff}, // ITEM_ACTIVE_COLOR
  490. {0xff, 0xff, 0xff}, // MESSAGE_COLOR
  491. {0x40, 0xff, 0x40}, // TEXT_ENTRY_COLOR
  492. {0xff, 0xff, 0xff}, // TEXT_ENTRY_ACTIVE_COLOR
  493. {0xff, 0xff, 0xff}, // TEXT_ENTRY_CURSOR_COLOR
  494. {0x60, 0x60, 0x60} // KEY_BINDING_COLOR
  495. };
  496. static const int default_dialog_space[NUM_DIALOG_SPACES] = {
  497. 6, // FRAME_T_SPACE
  498. 6, // FRAME_L_SPACE
  499. 6, // FRAME_R_SPACE
  500. 6, // FRAME_B_SPACE
  501. 8, // SPACER_HEIGHT
  502. 16, // LABEL_ITEM_SPACE
  503. 2, // LIST_T_SPACE
  504. 2, // LIST_L_SPACE
  505. 18, // LIST_R_SPACE
  506. 2, // LIST_B_SPACE
  507. 0, // TROUGH_T_SPACE
  508. 16, // TROUGH_R_SPACE
  509. 0, // TROUGH_B_SPACE
  510. 16, // TROUGH_WIDTH
  511. 0, // SLIDER_T_SPACE
  512. 0, // SLIDER_L_SPACE
  513. 0, // SLIDER_R_SPACE
  514. 0, // BUTTON_T_SPACE
  515. 0, // BUTTON_L_SPACE
  516. 0, // BUTTON_R_SPACE
  517. 14 // BUTTON_HEIGHT
  518. };
  519. static void set_theme_defaults(void)
  520. {
  521. for (int i=0; i<NUM_DIALOG_FONTS; i++)
  522. dialog_font[i] = NULL;
  523. for (int i=0; i<NUM_DIALOG_COLORS; i++)
  524. dialog_color[i] = default_dialog_color[i];
  525. for (int i=0; i<NUM_DIALOG_IMAGES; i++) {
  526. dialog_image_spec[i].name = "";
  527. dialog_image_spec[i].scale = false;
  528. dialog_image[i] = NULL;
  529. }
  530. for (int i=0; i<NUM_DIALOG_SPACES; i++)
  531. dialog_space[i] = default_dialog_space[i];
  532. }
  533. /*
  534. * Unload theme
  535. */
  536. static void unload_theme(void)
  537. {
  538. // Unload fonts
  539. for (int i=0; i<NUM_DIALOG_FONTS; i++)
  540. if (dialog_font[i]) {
  541. unload_font(dialog_font[i]);
  542. dialog_font[i] = NULL;
  543. }
  544. // Free surfaces
  545. for (int i=0; i<NUM_DIALOG_IMAGES; i++)
  546. if (dialog_image[i]) {
  547. SDL_FreeSurface(dialog_image[i]);
  548. dialog_image[i] = NULL;
  549. }
  550. // Close resource file
  551. theme_resources.Close();
  552. }
  553. /*
  554. * Get dialog font/color/image/space from theme
  555. */
  556. const sdl_font_info *get_dialog_font(int which, uint16 &style)
  557. {
  558. assert(which >= 0 && which < NUM_DIALOG_FONTS);
  559. const sdl_font_info *font = dialog_font[which];
  560. if (font) {
  561. style = dialog_font_spec[which].style;
  562. return font;
  563. } else {
  564. style = styleNormal;
  565. return default_font;
  566. }
  567. }
  568. uint32 get_dialog_color(int which)
  569. {
  570. assert(which >= 0 && which < NUM_DIALOG_COLORS);
  571. return SDL_MapRGB(dialog_surface->format, dialog_color[which].r, dialog_color[which].g, dialog_color[which].b);
  572. }
  573. // ZZZ: added this for convenience; taken from w_player_color::draw().
  574. // Obviously, this color does not come from the theme.
  575. uint32 get_dialog_player_color(size_t colorIndex) {
  576. SDL_Color c;
  577. _get_interface_color(PLAYER_COLOR_BASE_INDEX + colorIndex, &c);
  578. return SDL_MapRGB(dialog_surface->format, c.r, c.g, c.b);
  579. }
  580. SDL_Surface *get_dialog_image(int which, int width, int height)
  581. {
  582. assert(which >= 0 && which < NUM_DIALOG_IMAGES);
  583. SDL_Surface *s = dialog_image[which];
  584. if (s == NULL)
  585. s = default_image;
  586. // If no width and height is given, the surface is returned as-is and must
  587. // not be freed by the caller
  588. if (width == 0 && height == 0)
  589. return s;
  590. // Otherwise, a new tiled/rescaled surface is created which must be freed
  591. // by the caller
  592. int req_width = width ? width : s->w;
  593. int req_height = height ? height : s->h;
  594. SDL_Surface *s2 = dialog_image_spec[which].scale ? rescale_surface(s, req_width, req_height) : tile_surface(s, req_width, req_height);
  595. SDL_SetColorKey(s2, SDL_SRCCOLORKEY, SDL_MapRGB(s2->format, 0x00, 0xff, 0xff));
  596. return s2;
  597. }
  598. uint16 get_dialog_space(size_t which)
  599. {
  600. assert(which < NUM_DIALOG_SPACES);
  601. return dialog_space[which];
  602. }
  603. /*
  604. * Play dialog sound
  605. */
  606. void play_dialog_sound(int which)
  607. {
  608. play_sound(which, NULL, NONE);
  609. }
  610. /*
  611. * Dialog constructor
  612. */
  613. dialog::dialog() : active_widget(NULL), active_widget_num(UNONE), done(false),
  614. cursor_was_visible(false), parent_dialog(NULL),
  615. processing_function(NULL), active_tab(0)
  616. {
  617. }
  618. /*
  619. * Dialog destructor
  620. */
  621. dialog::~dialog()
  622. {
  623. // Free all widgets
  624. vector<widget *>::const_iterator i = widgets.begin(), end = widgets.end();
  625. while (i != end) {
  626. delete *i;
  627. i++;
  628. }
  629. }
  630. /*
  631. * Add widget
  632. */
  633. void dialog::add(widget *w)
  634. {
  635. widgets.push_back(w);
  636. tabs.push_back(NONE);
  637. w->set_owning_dialog(this);
  638. }
  639. void dialog::add_to_tab(widget *w, int tab)
  640. {
  641. widgets.push_back(w);
  642. tabs.push_back(tab);
  643. w->set_owning_dialog(this);
  644. }
  645. /*
  646. * Layout dialog
  647. */
  648. void dialog::layout()
  649. {
  650. // Layout all widgets, calculate total width and height
  651. int y = get_dialog_space(FRAME_T_SPACE);
  652. int left = 0;
  653. int right = 0;
  654. // Initialise tab-specific y's
  655. map<int, int> y_per_tab;
  656. for (vector<int>::const_iterator tab = tabs.begin(); tab != tabs.end(); ++tab)
  657. if (*tab != NONE)
  658. y_per_tab[*tab] = y;
  659. vector<widget *>::const_iterator i = widgets.begin(), end = widgets.end();
  660. vector<int>::const_iterator j = tabs.begin();
  661. while (i != end) {
  662. // Are we interested in the global y or a tab-specific?
  663. int& the_y = (*j == NONE) ? y : y_per_tab[*j];
  664. widget *w = *i;
  665. w->rect.y = the_y;
  666. the_y += w->layout();
  667. if (w->rect.x < left)
  668. left = w->rect.x;
  669. if (w->rect.x + w->rect.w > right)
  670. right = w->rect.x + w->rect.w;
  671. if (*j == NONE)
  672. // Later tabbed widgets must appear below this widget
  673. for (map<int, int>::iterator tab = y_per_tab.begin(); tab != y_per_tab.end(); ++tab)
  674. (*tab).second = y;
  675. else
  676. // The next untabbed widget must appear below this widget
  677. if (y < y_per_tab[*j])
  678. y = y_per_tab[*j];
  679. i++;
  680. j++;
  681. }
  682. left = abs(left);
  683. rect.w = (left > right ? left : right) * 2 + get_dialog_space(FRAME_L_SPACE) + get_dialog_space(FRAME_R_SPACE);
  684. rect.h = y + get_dialog_space(FRAME_B_SPACE);
  685. // Center dialog on video surface
  686. SDL_Surface *video = SDL_GetVideoSurface();
  687. rect.x = (video->w - rect.w) / 2;
  688. rect.y = (video->h - rect.h) / 2;
  689. // Transform positions of all widgets to be relative to the dialog surface
  690. i = widgets.begin();
  691. int offset_x = (rect.w - get_dialog_space(FRAME_L_SPACE) - get_dialog_space(FRAME_R_SPACE)) / 2 + get_dialog_space(FRAME_L_SPACE);
  692. // ZZZ: to provide more detailed layout info to widgets
  693. int leftmost_x = get_dialog_space(FRAME_L_SPACE);
  694. int usable_width = rect.w - leftmost_x - get_dialog_space(FRAME_R_SPACE);
  695. while (i != end) {
  696. (*i)->rect.x += offset_x;
  697. (*i)->capture_layout_information(leftmost_x, usable_width);
  698. i++;
  699. }
  700. }
  701. /*
  702. * Update part of dialog on screen
  703. */
  704. void dialog::update(SDL_Rect r) const
  705. {
  706. SDL_Surface *video = SDL_GetVideoSurface();
  707. // ZZZ: this less efficient way (copies more stuff) is an attempt to fix dialog updating
  708. // in the face of double-buffered page-flipping.
  709. /*
  710. SDL_Rect dst_rect = {r.x + rect.x, r.y + rect.y, r.w, r.h};
  711. SDL_BlitSurface(dialog_surface, &r, video, &dst_rect);
  712. SDL_UpdateRects(video, 1, &dst_rect);
  713. */
  714. // this is needed because 'rect' is const here and SDL_* don't seem to use const.
  715. SDL_Rect dst_rect = rect;
  716. SDL_Rect src_rect = { 0, 0, rect.w, rect.h };
  717. SDL_BlitSurface(dialog_surface, &src_rect, video, &dst_rect);
  718. #ifdef PSP
  719. SDL_Flip(video);
  720. #else
  721. SDL_UpdateRects(video, 1, &dst_rect);
  722. #endif
  723. #ifdef HAVE_OPENGL
  724. if (video->flags & SDL_OPENGL)
  725. SDL_GL_SwapBuffers();
  726. #endif
  727. }
  728. /*
  729. * Draw dialog
  730. */
  731. void dialog::draw_widget(widget *w, bool do_update) const
  732. {
  733. // Clear and redraw widget
  734. SDL_FillRect(dialog_surface, &w->rect, get_dialog_color(BACKGROUND_COLOR));
  735. w->draw(dialog_surface);
  736. w->dirty = false;
  737. // Blit to screen
  738. if (do_update)
  739. update(w->rect);
  740. }
  741. static void draw_frame_image(SDL_Surface *s, int x, int y)
  742. {
  743. SDL_Rect r = {x, y, s->w, s->h};
  744. SDL_BlitSurface(s, NULL, dialog_surface, &r);
  745. }
  746. void dialog::draw(void) const
  747. {
  748. // Clear dialog surface
  749. SDL_FillRect(dialog_surface, NULL, get_dialog_color(BACKGROUND_COLOR));
  750. // Draw frame
  751. draw_frame_image(frame_tl, 0, 0);
  752. draw_frame_image(frame_t, frame_tl->w, 0);
  753. draw_frame_image(frame_tr, frame_tl->w + frame_t->w, 0);
  754. draw_frame_image(frame_l, 0, frame_tl->h);
  755. draw_frame_image(frame_r, rect.w - frame_r->w, frame_tr->h);
  756. draw_frame_image(frame_bl, 0, frame_tl->h + frame_l->h);
  757. draw_frame_image(frame_b, frame_bl->w, rect.h - frame_b->h);
  758. draw_frame_image(frame_br, frame_bl->w + frame_b->w, frame_tr->h + frame_r->h);
  759. // Draw all widgets, except those with inactive tabs
  760. vector<widget *>::const_iterator i = widgets.begin(), end = widgets.end();
  761. vector<int>::const_iterator j = tabs.begin();
  762. while (i != end) {
  763. if (*j == NONE || *j == active_tab)
  764. draw_widget(*i, false);
  765. i++;
  766. j++;
  767. }
  768. // Blit to screen
  769. SDL_Rect r = {0, 0, rect.w, rect.h};
  770. update(r);
  771. }
  772. void
  773. dialog::draw_dirty_widgets() const
  774. {
  775. for (unsigned i=0; i<widgets.size(); i++)
  776. if (widgets[i]->dirty)
  777. if (tabs[i] == NONE || tabs[i] == active_tab)
  778. draw_widget(widgets[i]);
  779. }
  780. /*
  781. * Deactivate currently active widget
  782. */
  783. void dialog::deactivate_currently_active_widget(bool draw)
  784. {
  785. if (active_widget) {
  786. active_widget->active = false;
  787. if (draw)
  788. draw_widget(active_widget);
  789. active_widget = NULL;
  790. active_widget_num = UNONE;
  791. }
  792. }
  793. /*
  794. * Activate widget
  795. */
  796. void dialog::activate_widget(size_t num, bool draw)
  797. {
  798. if (num == active_widget_num)
  799. return;
  800. // BUG: may crash if num==UNONE or NONE
  801. if (!widgets[num]->is_selectable())
  802. return;
  803. // Deactivate previously active widget
  804. deactivate_currently_active_widget(draw);
  805. // Activate new widget
  806. active_widget = widgets[num];
  807. active_widget_num = num;
  808. active_widget->active = true;
  809. if (draw) {
  810. draw_widget(active_widget);
  811. // play_dialog_sound(DIALOG_SELECT_SOUND);
  812. }
  813. }
  814. /*
  815. * Activate first selectable widget (don't draw)
  816. */
  817. void dialog::activate_first_widget(void)
  818. {
  819. for (size_t i=0; i<widgets.size(); i++) {
  820. if (widgets[i]->is_selectable() && (tabs[i] == NONE || tabs[i] == active_tab)) {
  821. activate_widget(i, false);
  822. break;
  823. }
  824. }
  825. }
  826. /*
  827. * Activate next/previous selectable widget
  828. */
  829. void dialog::activate_next_widget(void)
  830. {
  831. size_t i = active_widget_num;
  832. // BUG: infinate loop if active_widget_num == UNONE or NONE
  833. do {
  834. i++;
  835. if (i >= int(widgets.size()))
  836. i = 0;
  837. } while (!(widgets[i]->is_selectable() && (tabs[i] == NONE || tabs[i] == active_tab)) && i != active_widget_num);
  838. // Either widgets[i] is selectable, or i == active_widget_num (in which case we wrapped all the way around)
  839. if (widgets[i]->is_selectable())
  840. activate_widget(i);
  841. else
  842. deactivate_currently_active_widget();
  843. }
  844. void dialog::activate_prev_widget(void)
  845. {
  846. size_t i = active_widget_num;
  847. // BUG: infinate loop if active_widget_num == UNONE or NONE
  848. do {
  849. if (i == 0)
  850. i = widgets.size() - 1;
  851. else
  852. i--;
  853. } while (!(widgets[i]->is_selectable() && (tabs[i] == NONE || tabs[i] == active_tab)) && i != active_widget_num);
  854. // Either widgets[i] is selectable, or i == active_widget_num (in which case we wrapped all the way around)
  855. if (widgets[i]->is_selectable())
  856. activate_widget(i);
  857. else
  858. deactivate_currently_active_widget();
  859. }
  860. /*
  861. * Find widget given video surface coordinates (<0 = none found)
  862. */
  863. int dialog::find_widget(int x, int y)
  864. {
  865. // Transform to dialog coordinates
  866. x -= rect.x;
  867. y -= rect.y;
  868. // Find widget
  869. vector<int>::const_iterator j = tabs.begin();
  870. vector<widget *>::const_iterator i = widgets.begin(), end = widgets.end();
  871. int num = 0;
  872. while (i != end) {
  873. widget *w = *i;
  874. if (*j == NONE || *j == active_tab) // Don't find widgets in inactive tabs
  875. if (x >= w->rect.x && y >= w->rect.y && x < w->rect.x + w->rect.w && y < w->rect.y + w->rect.h)
  876. return num;
  877. i++; j++; num++;
  878. }
  879. return -1;
  880. }
  881. /*
  882. * Find widget by its numeric ID
  883. */
  884. widget *dialog::get_widget_by_id(short inID) const
  885. {
  886. // Find first matching widget
  887. vector<widget *>::const_iterator i = widgets.begin(), end = widgets.end();
  888. while (i != end) {
  889. widget *w = *i;
  890. if (w->get_identifier() == inID)
  891. return w;
  892. i++;
  893. }
  894. return NULL;
  895. }
  896. /*
  897. * Handle event
  898. */
  899. void dialog::event(SDL_Event &e)
  900. {
  901. bool handled = false;
  902. //unsigned long c = gp2x_joystick_read();
  903. // handle events we do not want widgets to see or modify
  904. switch (e.type) {
  905. case SDL_KEYDOWN:
  906. if (e.key.keysym.sym == SDLK_RETURN
  907. && ((e.key.keysym.mod & KMOD_ALT) || (e.key.keysym.mod & KMOD_META))) {
  908. toggle_fullscreen();
  909. draw();
  910. handled = true;
  911. }
  912. break;
  913. case SDL_ACTIVEEVENT:
  914. if (e.active.state & SDL_APPACTIVE) {
  915. if (e.active.gain) {
  916. draw();
  917. handled = true;
  918. }
  919. }
  920. break;
  921. }
  922. if (!handled) {
  923. // First pass event to active widget (which may modify it)
  924. if (active_widget)
  925. active_widget->event(e);
  926. //if(c&GP2X_START) quit(-1);
  927. //if(c&GP2X_UP||c&GP2X_LEFT) activate_prev_widget();
  928. //if(c&GP2X_DOWN||c&GP2X_RIGHT) activate_next_widget();
  929. //if(c&GP2X_X||c&GP2X_L) active_widget->click(0,0);
  930. // Remaining events handled by dialog
  931. switch (e.type) {
  932. // Key pressed
  933. case SDL_KEYDOWN:
  934. switch (e.key.keysym.sym) {
  935. case SDLK_ESCAPE: // ESC = Exit dialog
  936. quit(-1);
  937. break;
  938. case SDLK_UP: // Up = Activate previous widget
  939. case SDLK_LEFT:
  940. activate_prev_widget();
  941. break;
  942. case SDLK_DOWN: // Down = Activate next widget
  943. case SDLK_RIGHT:
  944. activate_next_widget();
  945. break;
  946. case SDLK_TAB:
  947. if (e.key.keysym.mod & KMOD_SHIFT)
  948. activate_prev_widget();
  949. else
  950. activate_next_widget();
  951. break;
  952. case SDLK_RETURN: // Return = Action on widget
  953. active_widget->click(0, 0);
  954. break;
  955. case SDLK_F9: // F9 = Screen dump
  956. dump_screen();
  957. break;
  958. default:
  959. break;
  960. }
  961. break;
  962. case SDL_JOYBUTTONUP:
  963. switch (e.jbutton.button) {
  964. case 1: // CIRCLE = Exit dialog
  965. quit(-1);
  966. break;
  967. case 8: // Up = Activate previous widget
  968. case 7: // LEFT
  969. activate_prev_widget();
  970. break;
  971. case 6: // Down = Activate next widget
  972. case 9:
  973. activate_next_widget();
  974. break;
  975. case 2: // CROSS = Action on widget
  976. active_widget->click(0, 0);
  977. break;
  978. case 10: // SELECT = Screen dump
  979. dump_screen();
  980. break;
  981. default:
  982. break;
  983. }
  984. // Mouse moved
  985. case SDL_MOUSEMOTION: {
  986. int x = e.motion.x, y = e.motion.y;
  987. int num = find_widget(x, y);
  988. if (num >= 0) {
  989. assert(num == (size_t)num);
  990. activate_widget(num);
  991. widget *w = widgets[num];
  992. w->mouse_move(x - rect.x - w->rect.x, y - rect.y - w->rect.y);
  993. }
  994. break;
  995. }
  996. // Mouse button pressed
  997. case SDL_MOUSEBUTTONDOWN: {
  998. int x = e.button.x, y = e.button.y;
  999. int num = find_widget(x, y);
  1000. if (num >= 0) {
  1001. widget *w = widgets[num];
  1002. w->click(x - rect.x - w->rect.x, y - rect.y - w->rect.y);
  1003. }
  1004. break;
  1005. }
  1006. // Quit requested
  1007. case SDL_QUIT:
  1008. exit(0);
  1009. break;
  1010. }
  1011. }
  1012. // Redraw dirty widgets
  1013. draw_dirty_widgets();
  1014. }
  1015. /*
  1016. * Run dialog modally, returns result code (0 = ok, -1 = cancel)
  1017. */
  1018. int dialog::run(bool intro_exit_sounds)
  1019. {
  1020. // Put dialog on screen
  1021. start(intro_exit_sounds);
  1022. // Run dialog loop
  1023. while (!done) {
  1024. // Process events
  1025. process_events();
  1026. if (done)
  1027. break;
  1028. // Run custom processing function
  1029. if (processing_function)
  1030. processing_function(this);
  1031. // Give time to system
  1032. global_idle_proc();
  1033. SDL_Delay(10);
  1034. }
  1035. // Remove dialog from screen
  1036. return finish(intro_exit_sounds);
  1037. }
  1038. /*
  1039. * Put dialog on screen
  1040. */
  1041. void dialog::start(bool play_sound)
  1042. {
  1043. // Make sure nobody tries re-entrancy with us
  1044. assert(!done);
  1045. // Set new active dialog
  1046. parent_dialog = top_dialog;
  1047. top_dialog = this;
  1048. // Clear dialog surface
  1049. SDL_FillRect(dialog_surface, NULL, get_dialog_color(BACKGROUND_COLOR));
  1050. // Activate first widget
  1051. activate_first_widget();
  1052. // Layout dialog
  1053. layout();
  1054. // Get frame images
  1055. frame_tl = get_dialog_image(FRAME_TL_IMAGE);
  1056. frame_tr = get_dialog_image(FRAME_TR_IMAGE);
  1057. frame_bl = get_dialog_image(FRAME_BL_IMAGE);
  1058. frame_br = get_dialog_image(FRAME_BR_IMAGE);
  1059. frame_t = get_dialog_image(FRAME_T_IMAGE, rect.w - frame_tl->w - frame_tr->w, 0);
  1060. frame_l = get_dialog_image(FRAME_L_IMAGE, 0, rect.h - frame_tl->h - frame_bl->h);
  1061. frame_r = get_dialog_image(FRAME_R_IMAGE, 0, rect.h - frame_tr->h - frame_br->h);
  1062. frame_b = get_dialog_image(FRAME_B_IMAGE, rect.w - frame_bl->w - frame_br->w, 0);
  1063. // Draw dialog
  1064. #if defined(MAC_SDL_KLUDGE)
  1065. clear_screen();
  1066. #endif
  1067. draw();
  1068. // Show cursor
  1069. cursor_was_visible = (SDL_ShowCursor(SDL_ENABLE) == SDL_ENABLE);
  1070. // Welcome sound
  1071. if (play_sound)
  1072. play_dialog_sound(DIALOG_INTRO_SOUND);
  1073. // Enable unicode key translation
  1074. // (ZZZ: hmm maybe this should be done on entering/leaving run_a_little?
  1075. // I guess really we need to "push" the current UNICODE state and set it true on entering run_a_little,
  1076. // then "pop" the previous state on leaving run_a_little. In the meantime, we hope nobody tries their own
  1077. // event processing between dialog::start and dialog::finish (or at least is prepared to live with UNICODE) :) )
  1078. saved_unicode_state = SDL_EnableUNICODE(true);
  1079. // Prepare for dialog event loop
  1080. result = 0;
  1081. done = false;
  1082. }
  1083. /*
  1084. * Process pending dialog events
  1085. */
  1086. bool dialog::process_events()
  1087. {
  1088. while (!done) {
  1089. //unsigned long c = gp2x_joystick_read();
  1090. // Get next event
  1091. SDL_Event e;
  1092. e.type = SDL_NOEVENT;
  1093. SDL_PollEvent(&e);
  1094. //if(c&GP2X_LEFT||c&GP2X_UP||c&GP2X_RIGHT||c&GP2X_DOWN||c&GP2X_X||c&GP2X_L||c&GP2X_Y) {
  1095. //e.type=SDL_JOYBUTTONDOWN;
  1096. //}
  1097. if (e.type == SDL_NOEVENT)
  1098. break;
  1099. // Handle event
  1100. event(e);
  1101. }
  1102. return done;
  1103. }
  1104. /*
  1105. * Remove dialog from screen
  1106. */
  1107. int dialog::finish(bool play_sound)
  1108. {
  1109. // Disable unicode key translation
  1110. SDL_EnableUNICODE(saved_unicode_state);
  1111. // Farewell sound
  1112. if (play_sound)
  1113. play_dialog_sound(result == 0 ? DIALOG_OK_SOUND : DIALOG_CANCEL_SOUND);
  1114. // Hide cursor
  1115. if (!cursor_was_visible)
  1116. SDL_ShowCursor(false);
  1117. // Clear dialog surface
  1118. SDL_FillRect(dialog_surface, NULL, get_dialog_color(BACKGROUND_COLOR));
  1119. // Erase dialog from screen
  1120. SDL_Surface *video = SDL_GetVideoSurface();
  1121. SDL_FillRect(video, &rect, SDL_MapRGB(video->format, 0, 0, 0));
  1122. #ifdef PSP
  1123. SDL_Flip(video);
  1124. #else
  1125. SDL_UpdateRects(video, 1, &rect);
  1126. #endif
  1127. #ifdef HAVE_OPENGL
  1128. if (video->flags & SDL_OPENGL)
  1129. SDL_GL_SwapBuffers();
  1130. #endif
  1131. // Free frame images
  1132. if (frame_t) SDL_FreeSurface(frame_t);
  1133. if (frame_l) SDL_FreeSurface(frame_l);
  1134. if (frame_r) SDL_FreeSurface(frame_r);
  1135. if (frame_b) SDL_FreeSurface(frame_b);
  1136. // Restore active dialog
  1137. top_dialog = parent_dialog;
  1138. parent_dialog = NULL;
  1139. if (top_dialog) {
  1140. clear_screen();
  1141. top_dialog->draw();
  1142. }
  1143. // Allow dialog to be run again later
  1144. done = false;
  1145. return result;
  1146. }
  1147. /*
  1148. * Quit dialog, return result
  1149. */
  1150. void dialog::quit(int r)
  1151. {
  1152. result = r;
  1153. done = true;
  1154. }
  1155. /*
  1156. * Standard callback functions
  1157. */
  1158. void dialog_ok(void *arg)
  1159. {
  1160. dialog *d = (dialog *)arg;
  1161. d->quit(0);
  1162. }
  1163. void dialog_cancel(void *arg)
  1164. {
  1165. dialog *d = (dialog *)arg;
  1166. d->quit(-1);
  1167. }
  1168. // ZZZ: commonly-used callback for text entry enter_pressed_callback
  1169. void dialog_try_ok(w_text_entry* text_entry) {
  1170. w_button* ok_button = dynamic_cast<w_button*>(text_entry->get_owning_dialog()->get_widget_by_id(iOK));
  1171. // This is arguably a violation of the sdl_dialog/sdl_widget standard behavior since
  1172. // ok_button is clicked without first becoming the active widget. With the current
  1173. // implementation of w_button::click, should not be a problem...
  1174. if(ok_button != NULL)
  1175. ok_button->click(0,0);
  1176. }
  1177. // ZZZ: commonly-used callback to enable/disable "OK" based on whether a text_entry has data
  1178. void dialog_disable_ok_if_empty(w_text_entry* inTextEntry) {
  1179. modify_control_enabled(inTextEntry->get_owning_dialog(), iOK,
  1180. (inTextEntry->get_text()[0] == 0) ? CONTROL_INACTIVE : CONTROL_ACTIVE);
  1181. }