PageRenderTime 47ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/tags/release-20060611/Source_Files/Misc/sdl_dialogs.cpp

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