OBOX.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  1. /*
  2. * Seven Kingdoms: Ancient Adversaries
  3. *
  4. * Copyright 1997,1998 Enlight Software Ltd.
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. *
  19. */
  20. //Filename : OBOX.CPP
  21. //Description : A collection of box objects
  22. #include <string.h>
  23. #include <stdio.h>
  24. #include <stdarg.h>
  25. #include <time.h>
  26. #include <KEY.h>
  27. #include <OSYS.h>
  28. #include <OVGA.h>
  29. #include <OMOUSE.h>
  30. #include <OFONT.h>
  31. #include <OBUTTON.h>
  32. #include <OPOWER.h>
  33. #include <OBOX.h>
  34. //----------- Define constant -------------//
  35. enum { BOX_LINE_SPACE = 8,
  36. MAX_BOX_WIDTH = 600,
  37. BOX_X_MARGIN = 30, // Horizontal margin
  38. BOX_TOP_MARGIN = 20,
  39. BOX_BUTTON_MARGIN = 32,
  40. BOX_BOTTOM_MARGIN = 42 }; // margin for display the box button
  41. //------- constant for arrow box ----------//
  42. enum { ARROW_HEIGHT = 20, // Height of the thick end of the arrow
  43. ARROW_MARGIN = 10, // Y margin of the arrow between the box top
  44. ARROW_X_DISTANCE = 40, // X distance of the object to the box
  45. ARROW_Y_DISTANCE = 35 }; // Y distance of the object to the box
  46. //----- Define static member variables ------//
  47. char Box::opened_flag=0;
  48. //----------- Begin of function Box::open ---------//
  49. //
  50. // Open the box with the given coordinations
  51. //
  52. // <int> x1, y1, x2, y2 - coordination of the box
  53. // (default : use current settings)
  54. //
  55. // [int] downCentre - whether paint down the center of the box
  56. // (default : 1)
  57. //
  58. void Box::open(int inX1, int inY1, int inX2, int inY2, int downCentre)
  59. {
  60. box_x1 = inX1;
  61. box_y1 = inY1;
  62. box_x2 = inX2;
  63. box_y2 = inY2;
  64. paint( downCentre );
  65. }
  66. //------------ End of function Box::open -----------//
  67. //----------- Begin of function Box::open ---------//
  68. //
  69. // Given the width & height of the box, and open the box
  70. //
  71. // <int> boxWidth, boxHeight - width & height of the box
  72. //
  73. // [int] downCentre - whether paint down the center of the box
  74. // (default : 1)
  75. //
  76. void Box::open(int boxWidth, int boxHeight, int downCentre)
  77. {
  78. box_x1 = (VGA_WIDTH-boxWidth) / 2;
  79. box_x2 = box_x1 + boxWidth - 1;
  80. box_y1 = (VGA_HEIGHT-boxHeight) / 2;
  81. box_y2 = box_y1 + boxHeight - 1;
  82. paint( downCentre );
  83. }
  84. //------------ End of function Box::open -----------//
  85. //----------- Begin of function Box::paint ---------//
  86. void Box::paint(int downCentre)
  87. {
  88. err_when(opened_flag); // double open
  89. vga_front.save_area_common_buf( box_x1, box_y1, box_x2, box_y2 ); // save to Vga::image_buf
  90. vga_front.d3_panel_up( box_x1, box_y1, box_x2, box_y2, 2 );
  91. if( downCentre )
  92. vga_front.d3_panel_down( box_x1+4, box_y1+4, box_x2-4, box_y2-4, 1 );
  93. opened_flag = 1;
  94. }
  95. //------------ End of function Box::paint -----------//
  96. //----------- Begin of function Box::close --------//
  97. //
  98. // Close the previously opened box
  99. //
  100. void Box::close()
  101. {
  102. err_when(!opened_flag); // double open
  103. vga_front.rest_area_common_buf();
  104. mouse.get_event(); // post the click, prevent effect on other windows
  105. opened_flag = 0;
  106. }
  107. //------------ End of function Box::close -----------//
  108. //----------- Begin of function Box::calc_size ------//
  109. //
  110. // Given a string and then calculate the size of the box
  111. // which can contain the string.
  112. //
  113. // <char*> msgStr = the message string
  114. // <int> minHeight = minimum height of the box
  115. // [int] x1, y1 = the top left corner of the box
  116. //
  117. void Box::calc_size(char* msgStr, int minHeight, int x1, int y1)
  118. {
  119. int width = BOX_X_MARGIN*2 + font_san.text_width(msgStr, -1, MAX_BOX_WIDTH-BOX_X_MARGIN*2);
  120. int height = minHeight + font_san.text_height(BOX_LINE_SPACE);
  121. if( x1 < 0 )
  122. {
  123. box_x1 = (VGA_WIDTH - width) / 2;
  124. box_y1 = (VGA_HEIGHT - height) / 2;
  125. }
  126. else
  127. {
  128. box_x1 = x1;
  129. box_y1 = y1;
  130. }
  131. box_x2 = box_x1+width-1;
  132. box_y2 = box_y1+height-1;
  133. }
  134. //---------- End of function Box::calc_size -------------//
  135. //---------- Begin of function Box::ok_button ---------//
  136. //
  137. // [int] timeOut - 1=enable inactive timeout
  138. // 0=disable inactive timeout
  139. // (default : 1 )
  140. //
  141. void Box::ok_button(int timeOut)
  142. {
  143. Button button;
  144. button.paint_text( box_x1+(box_x2-box_x1+1)/2-10, box_y2-BOX_BUTTON_MARGIN, "Ok" );
  145. if( sys.debug_session )
  146. sys.blt_virtual_buf();
  147. button.wait_press(timeOut);
  148. }
  149. //------------ End of function Box::ok_button ---------//
  150. //---------- Begin of function Box::ask_button ---------//
  151. //
  152. // Display two buttons, and wait for player to click one of them
  153. //
  154. // [char*] buttonDes1 = the description of button 1 (default : "Ok")
  155. // [char*] buttonDes2 = the description of button 2 (default : "Cancel")
  156. // [int] rightClickClose = whether pressing the right button will close the window
  157. // (default: 1)
  158. //
  159. int Box::ask_button(char* buttonDes1, char* buttonDes2, int rightClickClose)
  160. {
  161. int width;
  162. width = box_x2-box_x1+1;
  163. Button buttonOk, buttonCancel;
  164. int buttonWidth1 = 20 + font_san.text_width(buttonDes1 ? buttonDes1 : (char*)"Ok");
  165. buttonOk.create_text( box_x1+width/2-buttonWidth1, box_y2-BOX_BUTTON_MARGIN,
  166. (buttonDes1 ? buttonDes1 : (char*)"Ok") );
  167. buttonCancel.create_text( box_x1+width/2+2 , box_y2-BOX_BUTTON_MARGIN,
  168. (buttonDes2 ? buttonDes2 : (char*)"Cancel") );
  169. buttonOk.paint(); // paint button
  170. buttonCancel.paint();
  171. if( sys.debug_session )
  172. sys.blt_virtual_buf();
  173. //..........................................//
  174. while( 1 )
  175. {
  176. sys.yield();
  177. mouse.get_event();
  178. if( sys.debug_session )
  179. sys.blt_virtual_buf();
  180. if( buttonOk.detect(buttonOk.str_buf[0], KEY_RETURN) )
  181. return 1;
  182. if( buttonCancel.detect(buttonCancel.str_buf[0], KEY_ESC)
  183. || (rightClickClose && mouse.any_click(1)) ) // detect right button only when the button is "Cancel"
  184. {
  185. mouse.get_event();
  186. return 0;
  187. }
  188. }
  189. }
  190. //--------- End of function Box::ask_button --------//
  191. //---------- Begin of function Box::ask_button ---------//
  192. //
  193. // Display a Ok and Cancel button, and wait for player to click one of them
  194. //
  195. // <Button&> buttonOk, buttonCancel = the defined buttons
  196. // [char*] strOk, strCancel = the string of the button Ok & Cancel
  197. // ( default : "Ok" & "Cancel" )
  198. //
  199. void Box::ask_button(Button& buttonOk, Button& buttonCancel, char* strOk, char* strCancel )
  200. {
  201. int width;
  202. width = box_x2-box_x1+1;
  203. buttonOk.create_text( box_x1+width/2-36, box_y2-BOX_BUTTON_MARGIN,
  204. (strOk ? strOk : (char*)"Ok") );
  205. buttonCancel.create_text( box_x1+width/2+2 , box_y2-BOX_BUTTON_MARGIN,
  206. (strCancel ? strCancel : (char*)"Cancel") );
  207. buttonOk.paint(); // paint button
  208. buttonCancel.paint();
  209. if( sys.debug_session )
  210. sys.blt_virtual_buf();
  211. }
  212. //--------- End of function Box::ask_button ---------//
  213. //------- Begin of function Box::ask ----------//
  214. //
  215. // Popup a message box and ask user 'Ok' or 'Cancel'
  216. //
  217. // Syntax :: ask( <char*> )
  218. //
  219. // <char*> msgStr = pointer to the message, use '\n' to seperate lines
  220. // [char*] buttonDes1 = the description of button 1 (default : "Ok")
  221. // [char*] buttonDes2 = the description of button 2 (default : "Cancel")
  222. // [int] x1, y1 = the left corner of the box, if not given
  223. // center the box on the screen
  224. //
  225. // Return : 1 - if user select "Ok" button
  226. // 0 - if user select "Cancel" button
  227. //
  228. //
  229. int Box::ask(char* msgStr, char* buttonDes1, char* buttonDes2, int x1, int y1)
  230. {
  231. int rc;
  232. calc_size(msgStr,BOX_TOP_MARGIN+BOX_BOTTOM_MARGIN,x1,y1); // calculate x1, y1, x2, y2 depended on the msgStr
  233. paint(1);
  234. font_san.put_paragraph( box_x1+BOX_X_MARGIN, box_y1+BOX_TOP_MARGIN, box_x2-BOX_X_MARGIN,
  235. box_y2-BOX_BOTTOM_MARGIN, msgStr, BOX_LINE_SPACE );
  236. rc = ask_button(buttonDes1, buttonDes2);
  237. close();
  238. return rc;
  239. }
  240. //---------- End of function Box::ask ----------//
  241. //------- Begin of function Box::msg ----------//
  242. //
  243. // Popup a message box and ask user to press the 'Ok' button
  244. //
  245. // Syntax :: msg( <char*> )
  246. //
  247. // <char*> msgStr = pointer to the message, use '\n' to
  248. // seperate lines.
  249. // [int] enableTimeOut = enable time out or not (default: 1)
  250. // [int] x1, y1 = the left corner of the box, if not given
  251. // center the box on the screen.
  252. //
  253. void Box::msg(char* msgStr, int enableTimeOut, int x1, int y1)
  254. {
  255. int savedUseBack = vga.use_back_buf;
  256. vga.use_front();
  257. calc_size(msgStr,BOX_TOP_MARGIN+BOX_BOTTOM_MARGIN,x1,y1); // calculate x1, y1, x2, y2 depended on the msgStr
  258. paint(1);
  259. font_san.put_paragraph( box_x1+BOX_X_MARGIN, box_y1+BOX_TOP_MARGIN, box_x2-BOX_X_MARGIN,
  260. box_y2-BOX_BOTTOM_MARGIN, msgStr, BOX_LINE_SPACE );
  261. sys.blt_virtual_buf(); // blt tihe vrtual front buffer to the screen
  262. ok_button(enableTimeOut);
  263. close();
  264. if( savedUseBack )
  265. vga.use_back();
  266. }
  267. //---------- End of function Box::msg ----------//
  268. //------- Begin of function Box::print ----------//
  269. //
  270. // Popup a message box and ask user to press the 'Ok' button
  271. //
  272. // <char*> formatStr - formated message with % argument
  273. // <....> the argument list
  274. //
  275. void Box::print(char* formatStr, ... )
  276. {
  277. //---- format the message and the arguments into one message ----//
  278. enum { RESULT_STR_LEN=200 };
  279. static char resultStr[RESULT_STR_LEN+1];
  280. err_when( strlen(formatStr) > RESULT_STR_LEN/2 ); // the length of the format string cannot > 1/2 of the result string buffer length, the remaining 1/2 is reserved for substituted values.
  281. va_list argPtr; // the argument list structure
  282. va_start( argPtr, formatStr );
  283. vsprintf( resultStr, formatStr, argPtr );
  284. va_end( argPtr );
  285. //------------ display msg --------------//
  286. msg(resultStr);
  287. }
  288. //---------- End of function Box::print ----------//
  289. //------- Begin of function Box::tell ----------//
  290. //
  291. // Popup a box and display a message. Call Box::close() to close the box.
  292. //
  293. // Syntax :: tell( <char*> )
  294. //
  295. // <char*> tellStr = pointer to the message, use '\n' to seperate lines
  296. // [int] x1, y1 = the left corner of the box, if not given
  297. // center the box on the screen
  298. //
  299. void Box::tell(char* tellStr, int x1, int y1)
  300. {
  301. calc_size(tellStr,BOX_TOP_MARGIN+BOX_BOTTOM_MARGIN,x1,y1); // calculate x1, y1, x2, y2 depended on the tellStr
  302. paint(1);
  303. font_san.put_paragraph( box_x1+BOX_X_MARGIN, box_y1+BOX_TOP_MARGIN, box_x2-BOX_X_MARGIN,
  304. box_y2-BOX_BOTTOM_MARGIN, tellStr, BOX_LINE_SPACE );
  305. }
  306. //---------- End of function Box::tell ----------//
  307. /*
  308. //-------- Begin of function Box::arrow_box ---------//
  309. //
  310. // Display a box with an arrow pointing at a specific location.
  311. //
  312. // Note : box_x1...box_y2, arrow_x and arrow_y must be set before
  313. // calling arrow_box() calc_arrow_box() can be called to
  314. // set the positions.
  315. //
  316. // <char*> boxText - box text
  317. // [char*] boxTitle - box title, no title if NULL
  318. // [int] saveScrFlag - save screen or not
  319. // (default : 1)
  320. //
  321. void Box::arrow_box(char* boxText, char* boxTitle, int saveScrFlag)
  322. {
  323. save_scr_flag = saveScrFlag;
  324. if( saveScrFlag )
  325. {
  326. if( arrow_x == 0 )
  327. vga_front.save_scr( box_x1, box_y1, box_x2, box_y2 );
  328. else
  329. vga_front.save_scr( min(box_x1,arrow_x), min(box_y1,arrow_y), max(box_x2,arrow_x), max(box_y2,arrow_y) );
  330. }
  331. //------- Draw box (and arrow if specified object) ------//
  332. if( arrow_x )
  333. draw_arrow();
  334. vga_front.bar( box_x1, box_y1, box_x2, box_y2, V_WHITE );
  335. vga_front.bar( box_x1, box_y1, box_x2, box_y1+1, V_BLACK ); // Top border
  336. vga_front.bar( box_x1, box_y2-1, box_x2, box_y2, V_BLACK ); // Bottom border
  337. vga_front.bar( box_x1, box_y1, box_x1+1, box_y2, V_BLACK ); // Left border
  338. vga_front.bar( box_x2-1, box_y1, box_x2, box_y2, V_BLACK ); // Right border
  339. //--------- display description and text -----------//
  340. if( boxTitle && boxTitle[0] ) // has tutor title
  341. {
  342. font_san.put( box_x1+10, box_y1+10, boxTitle );
  343. vga_front.bar( box_x1, box_y1+ARROW_BOX_TITLE_HEIGHT, box_x2, box_y1+ARROW_BOX_TITLE_HEIGHT+1, V_BLACK ); // line between description and tutor text
  344. font_san.put_paragraph( box_x1+ARROW_BOX_X_MARGIN, box_y1+ARROW_BOX_TITLE_HEIGHT+ARROW_BOX_Y_MARGIN,
  345. box_x2-ARROW_BOX_X_MARGIN, box_y2-ARROW_BOX_Y_MARGIN, boxText, ARROW_BOX_LINE_SPACE );
  346. }
  347. else
  348. {
  349. font_san.put_paragraph( box_x1+ARROW_BOX_X_MARGIN, box_y1+ARROW_BOX_Y_MARGIN, box_x2-ARROW_BOX_X_MARGIN,
  350. box_y2-ARROW_BOX_Y_MARGIN, boxText, ARROW_BOX_LINE_SPACE );
  351. }
  352. }
  353. //---------- End of function Box::arrow_box ---------//
  354. //-------- Begin of function Box::close_arrow_box ---------//
  355. void Box::close_arrow_box()
  356. {
  357. if( save_scr_flag )
  358. {
  359. vga_front.rest_scr();
  360. save_scr_flag = 0;
  361. }
  362. }
  363. //-------- End of function Box::close_arrow_box ---------//
  364. //-------- Begin of function Box::calc_arrow_box ---------//
  365. //
  366. // Calculate box_x1..box_y2 for arrow_box().
  367. //
  368. // <char*> textPtr = box text ptr
  369. // <int> arrowX, arrowY = the pointing location of the arrow
  370. // [int] extraHeight = extra height added to the box
  371. //
  372. void Box::calc_arrow_box(char* textPtr, int arrowX, int arrowY, int extraHeight)
  373. {
  374. int winWidth = font_san.text_width( textPtr, -1, ARROW_BOX_WIDTH-ARROW_BOX_X_MARGIN*2) + ARROW_BOX_X_MARGIN*2;
  375. int winHeight = ARROW_BOX_Y_MARGIN*2+font_san.text_height(ARROW_BOX_LINE_SPACE); // text_width() must be called before calling text_height()
  376. calc_arrow_box( winWidth, winHeight+extraHeight, arrowX, arrowY );
  377. }
  378. //--------- End of function Box::calc_arrow_box ---------//
  379. //-------- Begin of function Box::calc_arrow_box ---------//
  380. //
  381. // Calculate box_x1..box_y2 for arrow_box().
  382. //
  383. // <int> boxWidth, boxHeight = width and height of the arrow box
  384. // <int> arrowX , arrowY = the arrowing location of the arrow
  385. //
  386. void Box::calc_arrow_box(int boxWidth, int boxHeight, int arrowX, int arrowY)
  387. {
  388. arrow_x = arrowX;
  389. arrow_y = arrowY;
  390. //---------- find the coordination of the arrow -------//
  391. if( arrow_x < VGA_WIDTH/2 )
  392. {
  393. //------ Upper left part of the screen -------//
  394. if( arrow_y < VGA_HEIGHT/2 )
  395. {
  396. box_x1 = arrow_x + ARROW_X_DISTANCE;
  397. box_y1 = arrow_y + ARROW_Y_DISTANCE;
  398. }
  399. else //----- Lower left part of the screen -------//
  400. {
  401. box_x1 = arrow_x + ARROW_X_DISTANCE;
  402. box_y1 = arrow_y - ARROW_Y_DISTANCE - boxHeight;
  403. }
  404. }
  405. else
  406. {
  407. //------- Upper right part of the screen ---------//
  408. if( arrow_y < VGA_HEIGHT/2 )
  409. {
  410. box_x1 = arrow_x - ARROW_X_DISTANCE - boxWidth;
  411. box_y1 = arrow_y + ARROW_Y_DISTANCE;
  412. }
  413. else //----- Lower right part of the screen -------//
  414. {
  415. box_x1 = arrow_x - ARROW_X_DISTANCE - boxWidth;
  416. box_y1 = arrow_y - ARROW_Y_DISTANCE - boxHeight;
  417. }
  418. }
  419. //-----------------------------------------//
  420. box_x2 = box_x1 + boxWidth - 1;
  421. box_y2 = box_y1 + boxHeight - 1;
  422. //-------- valid box_x1,box_y1,box_x2 and box_y2 ----------//
  423. if( box_x1 < 0 )
  424. {
  425. box_x2 += -box_x1+10;
  426. box_x1 += -box_x1+10;
  427. }
  428. if( box_x2 >= VGA_WIDTH )
  429. {
  430. box_x1 -= (box_x2-VGA_WIDTH)+10;
  431. box_x2 -= (box_x2-VGA_WIDTH)+10;
  432. }
  433. if( box_y1 < 0 )
  434. {
  435. box_y2 += -box_y1+10;
  436. box_y1 += -box_y1+10;
  437. }
  438. if( box_y2 >= VGA_HEIGHT )
  439. {
  440. box_y1 -= (box_y2-VGA_HEIGHT)+10;
  441. box_y2 -= (box_y2-VGA_HEIGHT)+10;
  442. }
  443. }
  444. //-------- End of function Box::calc_arrow_box ---------//
  445. //-------- Begin of function Box::draw_arrow ---------//
  446. //
  447. // Draw an arrow based on box_x1...box_y1 and arrow_x and arrow_y
  448. //
  449. void Box::draw_arrow()
  450. {
  451. int tx2, ty2;
  452. //---------- find the coordination of the arrow -------//
  453. if( arrow_x < VGA_WIDTH/2 )
  454. {
  455. //------ Upper left part of the screen -------//
  456. if( arrow_y < VGA_HEIGHT/2 )
  457. {
  458. tx2 = box_x1+1;
  459. ty2 = box_y1+ARROW_MARGIN;
  460. }
  461. else //----- Lower left part of the screen -------//
  462. {
  463. tx2 = box_x1+1;
  464. ty2 = box_y2-ARROW_MARGIN-ARROW_HEIGHT;
  465. }
  466. }
  467. else
  468. {
  469. //------- Upper right part of the screen ---------//
  470. if( arrow_y < VGA_HEIGHT/2 )
  471. {
  472. tx2 = box_x2-1;
  473. ty2 = box_y1+ARROW_MARGIN;
  474. }
  475. else //----- Lower right part of the screen -------//
  476. {
  477. tx2 = box_x2-1;
  478. ty2 = box_y2-ARROW_MARGIN-ARROW_HEIGHT;
  479. }
  480. }
  481. //-------- draw and fill the arrow --------//
  482. int ty;
  483. mouse.hide();
  484. for( ty=ty2 ; ty<=ty2+ARROW_HEIGHT ; ty++ )
  485. VGAline( arrow_x, arrow_y, tx2, ty, V_WHITE );
  486. VGAline( arrow_x, arrow_y, tx2, ty2, V_BLACK );
  487. VGAline( arrow_x, arrow_y, tx2, ty2+ARROW_HEIGHT, V_BLACK );
  488. mouse.show();
  489. }
  490. //---------- End of function Box::draw_arrow ---------//
  491. */