window.cpp 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593
  1. /* $Id$
  2. * MegaZeux
  3. *
  4. * Copyright (C) 1996 Greg Janson
  5. * Copyright (C) 1998 Matthew D. Williams - dbwilli@scsn.net
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation; either version 2 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21. // Windowing code- Save/restore screen and draw windows and other elements,
  22. // also displays and runs dialog boxes.
  23. #include "helpsys.h"
  24. #include "hexchar.h"
  25. #include "timer.h"
  26. #include "sfx.h"
  27. #include "ezboard.h"
  28. #include "mod.h"
  29. #include "error.h"
  30. #include "boardmem.h"
  31. #include <stdio.h>
  32. #include "mouse.h"
  33. #include "beep.h"
  34. #include "intake.h"
  35. #include <stdlib.h>
  36. #include "cursor.h"
  37. #include "window.h"
  38. #include "getkey.h"
  39. #include "graphics.h"
  40. #include "string.h"
  41. extern "C" int _CType strcmp(const char *__s1, const char *__s2);
  42. #include <_null.h>
  43. #include "meminter.h"
  44. #include <dos.h>
  45. #include "const.h"
  46. #include "data.h"
  47. #include <dir.h>
  48. #include "helpsys.h"
  49. #define NUM_SAVSCR 2
  50. // Storage for NUM_SAVSCR saved screens- dynamically allocated at runtime
  51. // Another two saved screens use ega pages 2 and 3.
  52. char far *screen_storage[NUM_SAVSCR+2]={ NULL,NULL,
  53. (char far *)MK_FP(0xBA00,0),(char far *)MK_FP(0xBB00,0) };
  54. char curr_screen=0;//Current space for save_screen and restore_screen
  55. char far *vid_usage=NULL;//Mouse video usage array (for dialogs)
  56. // Reserve memory- returns 0 if ok, non-0 for error.
  57. char window_cpp_entry(void) {
  58. int t1=0;
  59. if((vid_usage=(char far *)farmalloc(2000))==NULL) return 1;
  60. for(;t1<NUM_SAVSCR;t1++) {
  61. screen_storage[t1]=(char far *)farmalloc(4000);
  62. if(screen_storage[t1]==NULL) break;
  63. }
  64. if(t1<NUM_SAVSCR) {//Allocation error
  65. if(t1>0) {
  66. for(t1--;t1>=0;t1--) {
  67. farfree(screen_storage[t1]);
  68. screen_storage[t1]=NULL;
  69. }
  70. }
  71. farfree(vid_usage);
  72. vid_usage=NULL;
  73. return 1;
  74. }
  75. return 0;
  76. }
  77. // Free up memory.
  78. void window_cpp_exit(void) {
  79. int t1=0;
  80. if(vid_usage!=NULL) farfree(vid_usage);
  81. for(;t1<NUM_SAVSCR;t1++) {
  82. if(screen_storage[t1]!=NULL) farfree(screen_storage[t1]);
  83. }
  84. }
  85. // The following functions do NOT check to see if memory is reserved, in
  86. // the interest of time, space, and simplicity. Make sure you have already
  87. // called window_cpp_init.
  88. // Saves current screen to buffer and increases buffer count. Returns
  89. // non-0 if the buffer for screens is already full. (IE 6 count)
  90. char save_screen(unsigned int segment) {
  91. if(curr_screen>=(NUM_SAVSCR+2)) {
  92. curr_screen=0;
  93. error("Windowing code bug",2,20,segment,0x1F01);
  94. }
  95. m_hide();
  96. mem_cpy(screen_storage[curr_screen++],(char far *)MK_FP(segment,0),4000);
  97. m_show();
  98. return 0;
  99. }
  100. // Restores top screen from buffer to screen and decreases buffer count.
  101. // Returns non-0 if there are no screens in the buffer.
  102. char restore_screen(unsigned int segment) {
  103. if(curr_screen==0)
  104. error("Windowing code bug",2,20,segment,0x1F02);
  105. m_hide();
  106. mem_cpy((char far *)MK_FP(segment,0),screen_storage[--curr_screen],4000);
  107. m_show();
  108. return 0;
  109. }
  110. // Draws an outlined and filled box from x1/y1 to x2/y2. Color is used to
  111. // fill box and for upper left lines. Dark_color is used for lower right
  112. // lines. Corner_color is used for the single chars in the upper right and
  113. // lower left corners. If Corner_color equals 0, these are auto calculated.
  114. // Returns non-0 for invalid parameters. Shadow (black spaces) is drawn and
  115. // clipped if specified. Operation on a size smaller than 3x3 is undefined.
  116. // This routine is highly unoptimized. Center is not filled if fill_center
  117. // is set to 0. (defaults to 1)
  118. char draw_window_box(int x1,int y1,int x2,int y2,unsigned int segment,
  119. unsigned char color,unsigned char dark_color,unsigned char corner_color,
  120. char shadow,char fill_center) {
  121. int t1,t2;
  122. //Validate parameters
  123. if((x1<0)||(y1<0)||(x1>79)||(y1>24)) return 1;
  124. if((x2<0)||(y2<0)||(x2>79)||(y2>24)) return 1;
  125. if(x2<x1) {
  126. t1=x1;
  127. x1=x2;
  128. x2=t1;
  129. }
  130. if(y2<y1) {
  131. t1=y1;
  132. y1=y2;
  133. y2=t1;
  134. }
  135. m_hide();
  136. //Fill center
  137. if(fill_center) {
  138. for(t1=x1+1;t1<x2;t1++) {
  139. for(t2=y1+1;t2<y2;t2++) {
  140. draw_char(' ',color,t1,t2,segment);
  141. }
  142. }
  143. }
  144. //Draw top and bottom edges
  145. for(t1=x1+1;t1<x2;t1++) {
  146. draw_char('Ä',color,t1,y1,segment);
  147. draw_char('Ä',dark_color,t1,y2,segment);
  148. }
  149. //Draw left and right edges
  150. for(t2=y1+1;t2<y2;t2++) {
  151. draw_char('³',color,x1,t2,segment);
  152. draw_char('³',dark_color,x2,t2,segment);
  153. }
  154. //Draw corners
  155. draw_char('Ú',color,x1,y1,segment);
  156. draw_char('Ù',dark_color,x2,y2,segment);
  157. if(corner_color) {
  158. draw_char('À',corner_color,x1,y2,segment);
  159. draw_char('¿',corner_color,x2,y1,segment);
  160. }
  161. else {
  162. draw_char('À',color,x1,y2,segment);
  163. draw_char('¿',dark_color,x2,y1,segment);
  164. }
  165. //Draw shadow if applicable
  166. if(shadow) {
  167. //Right edge
  168. if(x2<79) {
  169. for(t2=y1+1;t2<=y2;t2++) {
  170. draw_char(' ',0,x2+1,t2,segment);
  171. }
  172. }
  173. //Lower edge
  174. if(y2<24) {
  175. for(t1=x1+1;t1<=x2;t1++) {
  176. draw_char(' ',0,t1,y2+1,segment);
  177. }
  178. }
  179. //Lower right corner
  180. if((y2<24)&&(x2<79)) {
  181. draw_char(' ',0,x2+1,y2+1,segment);
  182. }
  183. }
  184. m_show();
  185. return 0;
  186. }
  187. // Strings for drawing different dialog box elements.
  188. // All parts are assumed 3 wide.
  189. #define check_on "[û]"
  190. #define check_off "[ ]"
  191. #define radio_on "()"
  192. #define radio_off "( )"
  193. #define color_blank ' '
  194. #define color_wild '?'
  195. #define color_dot 'þ'
  196. #define list_button "  "
  197. #define num_buttons "   "
  198. //Foreground colors that look nice for each background color
  199. char fg_per_bk[16]={ 15,15,15,15,15,15,15,0,15,15,0,0,15,15,0,0 };
  200. // For list/choice menus-
  201. #define arrow_char ''
  202. // List/choice menu colors- Box same as dialog, elements same as
  203. // inactive question, current element same as active question, pointer
  204. // same as text, title same as title.
  205. // Put up a box listing choices. Move pointer and enter to pick. choice
  206. // size is the size in bytes per choice in the array of choices. This size
  207. // includes null terminator and any junk padding. All work is done on
  208. // segment given, no page flipping. Choices are drawn using color_string.
  209. // On ESC, returns negative current choice, unless current choice is 0,
  210. // then returns -32767. Returns OUT_OF_WIN_MEM if out of screen storage space.
  211. // A progress column is displayed directly to the right of the list, using
  212. // the following characters. This is mainly used for mouse support.
  213. #define pc_top_arrow ''
  214. #define pc_bottom_arrow ''
  215. #define pc_filler '±'
  216. #define pc_dot 'þ'
  217. // Mouse support- Click on a choice to move there auto, click on progress
  218. // column arrows to move one line, click on progress meter itself to move
  219. // there percentage-wise. If you click on the current choice, it exits.
  220. // If you click on a choice to move there, the mouse cursor moves with it.
  221. int list_menu(char far *choices,char choice_size,char far *title,int
  222. current,int num_choices,unsigned int segment,char xpos) {
  223. int width=choice_size+6,t1;
  224. if(str_len(title)>choice_size) width=str_len(title)+6;
  225. //Save screen
  226. if(save_screen(segment)) return OUT_OF_WIN_MEM;
  227. //Display box
  228. m_hide();
  229. draw_window_box(xpos,2,xpos+width-1,22,segment,DI_MAIN,DI_DARK,DI_CORNER);
  230. //Add title
  231. write_string(title,xpos+3,2,DI_TITLE,segment);
  232. draw_char(' ',DI_TITLE,xpos+2,2,segment);
  233. draw_char(' ',DI_TITLE,xpos+3+str_len(title),2,segment);
  234. //Add pointer
  235. draw_char(arrow_char,DI_TEXT,xpos+2,12,segment);
  236. //Add meter arrows
  237. if(num_choices>1) {
  238. draw_char(pc_top_arrow,DI_PCARROW,xpos+4+choice_size,3,segment);
  239. draw_char(pc_bottom_arrow,DI_PCARROW,xpos+4+choice_size,21,segment);
  240. }
  241. do {
  242. //Fill over old menu
  243. draw_window_box(xpos+3,3,xpos+3+choice_size,21,segment,DI_DARK,DI_MAIN,
  244. DI_CORNER,0);
  245. //Draw current
  246. color_string(&(choices[choice_size*current]),xpos+4,12,DI_ACTIVE,
  247. segment);
  248. //Draw above current
  249. for(t1=1;t1<9;t1++) {
  250. if((current-t1)<0) break;
  251. color_string(&(choices[choice_size*(current-t1)]),xpos+4,12-t1,
  252. DI_NONACTIVE,segment);
  253. }
  254. //Draw below current
  255. for(t1=1;t1<9;t1++) {
  256. if((current+t1)>=num_choices) break;
  257. color_string(&(choices[choice_size*(current+t1)]),xpos+4,12+t1,
  258. DI_NONACTIVE,segment);
  259. }
  260. //Draw meter (xpos 9+choice_size, ypos 4 thru 20)
  261. if(num_choices>1) {
  262. for(t1=4;t1<21;t1++)
  263. draw_char(pc_filler,DI_PCFILLER,xpos+4+choice_size,t1,segment);
  264. //Add progress dot
  265. t1=(current*16)/(num_choices-1);
  266. draw_char(pc_dot,DI_PCDOT,xpos+4+choice_size,t1+4,segment);
  267. }
  268. //Get keypress
  269. m_show();
  270. t1=getkey();
  271. m_hide();
  272. //Act upon it
  273. switch(t1) {
  274. case MOUSE_EVENT:
  275. //Clicking on- List, column, arrow, or nothing?
  276. if((mouse_event.cx==xpos+4+choice_size)&&(mouse_event.cy>3)&&
  277. (mouse_event.cy<21)) {//Column
  278. t1=mouse_event.cy-4;
  279. current=(t1*(num_choices-1))/16;
  280. }
  281. else if((mouse_event.cy>3)&&(mouse_event.cy<21)&&
  282. (mouse_event.cx>xpos+3)&&(mouse_event.cx<xpos+3+choice_size)) {
  283. //List
  284. if(mouse_event.cy==12) goto enter;
  285. current+=(mouse_event.cy)-12;
  286. if(current<0) current=0;
  287. if(current>=num_choices) current=num_choices-1;
  288. //Move mouse with choices
  289. m_move(mouse_event.cx,12);
  290. }
  291. else if((mouse_event.cx==xpos+4+choice_size)&&
  292. (mouse_event.cy==3)) {//Top arrow
  293. if(current>0) current--;
  294. }
  295. else if((mouse_event.cx==xpos+4+choice_size)&&
  296. (mouse_event.cy==21)) {//Bottom arrow
  297. if(current<(num_choices-1)) current++;
  298. }
  299. else beep();//Nothing of importance was clicked on
  300. break;
  301. case 27:
  302. //ESC
  303. restore_screen(segment);
  304. m_show();
  305. if(current==0) return -32767;
  306. else return -current;
  307. case ' ':
  308. case 13:
  309. enter:
  310. //Selected
  311. restore_screen(segment);
  312. m_show();
  313. return current;
  314. case -72:
  315. case '8':
  316. //Up
  317. if(current>0) current--;
  318. break;
  319. case -80:
  320. case '2':
  321. //Down
  322. if(current<(num_choices-1)) current++;
  323. break;
  324. case -73:
  325. //Page Up
  326. current-=8;
  327. if(current<0) current=0;
  328. break;
  329. case -81:
  330. //Page Down
  331. current+=8;
  332. if(current>=num_choices) current=num_choices-1;
  333. break;
  334. case -71:
  335. //Home
  336. current=0;
  337. break;
  338. case -79:
  339. //End
  340. current=num_choices-1;
  341. break;
  342. default:
  343. //Invalid character
  344. beep();
  345. case 0:
  346. break;
  347. }
  348. //Loop
  349. } while(1);
  350. }
  351. // For char selection screen
  352. #define char_sel_arrows_0 ''
  353. #define char_sel_arrows_1 ''
  354. #define char_sel_arrows_2 ''
  355. #define char_sel_arrows_3 ''
  356. // Char selection screen colors- Window colors same as dialog, non-current
  357. // characters same as nonactive, current character same as active, arrows
  358. // along edges same as text, title same as title.
  359. // Put up a character selection box. Returns selected, or negative selected
  360. // for ESC, -256 for -0. Returns OUT_OF_WIN_MEM if out of window mem.
  361. // Display is 32 across, 8 down. All work done on given segment.
  362. // Mouse support- Click on a character to select it. If it is the current
  363. // character, it exits.
  364. int char_selection(unsigned char current,unsigned int segment) {
  365. int t1,t2,t3;
  366. //Save screen
  367. if(save_screen(segment)) return OUT_OF_WIN_MEM;
  368. if(context==72) set_context(98);
  369. else set_context(context);
  370. //Draw box
  371. m_hide();
  372. draw_window_box(20,5,57,16,segment,DI_MAIN,DI_DARK,DI_CORNER);
  373. //Add title
  374. write_string(" Select a character ",22,5,DI_TITLE,segment);
  375. //Draw character set
  376. for(t1=0;t1<32;t1++) {
  377. for(t2=0;t2<8;t2++) {
  378. draw_char(t1+t2*32,DI_NONACTIVE,t1+23,t2+7,segment);
  379. }
  380. }
  381. do {
  382. //Calculate x/y
  383. t1=(current&31)+23; t2=(current>>5)+7,
  384. //Highlight active character
  385. draw_char(current,DI_ACTIVE,t1,t2,segment);
  386. //Draw arrows
  387. draw_window_box(22,6,55,15,segment,DI_DARK,DI_MAIN,DI_CORNER,0,0);
  388. draw_char(char_sel_arrows_0,DI_TEXT,t1,15,segment);
  389. draw_char(char_sel_arrows_1,DI_TEXT,t1,6,segment);
  390. draw_char(char_sel_arrows_2,DI_TEXT,22,t2,segment);
  391. draw_char(char_sel_arrows_3,DI_TEXT,55,t2,segment);
  392. //Write number of character
  393. write_number(current,DI_MAIN,53,16,segment,3);
  394. //Get key
  395. m_show();
  396. t3=getkey();
  397. m_hide();
  398. //Erase marks
  399. draw_char(current,DI_NONACTIVE,t1,t2,segment);
  400. //Process key
  401. switch(t3) {
  402. case MOUSE_EVENT:
  403. //Within area?
  404. if((mouse_event.cx<23)||(mouse_event.cx>54)||
  405. (mouse_event.cy<7)||(mouse_event.cy>14)) {//Nope!
  406. beep();
  407. break;
  408. }
  409. //Yep!
  410. t1=(mouse_event.cx-23)+((mouse_event.cy-7)<<5);
  411. if(current==t1) goto enter;
  412. current=t1;
  413. break;
  414. case 27:
  415. //ESC
  416. pop_context();
  417. restore_screen(segment);
  418. m_show();
  419. if(current==0) return -256;
  420. else return -current;
  421. case ' ':
  422. case 13:
  423. enter:
  424. //Selected
  425. pop_context();
  426. restore_screen(segment);
  427. m_show();
  428. return current;
  429. case -72:
  430. case '8':
  431. //Up
  432. if(current>31) current-=32;
  433. break;
  434. case -80:
  435. case '2':
  436. //Down
  437. if(current<224) current+=32;
  438. break;
  439. case -75:
  440. case '4':
  441. //Left
  442. if(t1>23) current--;
  443. break;
  444. case -77:
  445. case '6':
  446. //Right
  447. if(t1<54) current++;
  448. break;
  449. case -71:
  450. //Home
  451. current=0;
  452. break;
  453. case -79:
  454. //End
  455. current=255;
  456. break;
  457. default:
  458. //If this is from 32 to 255, jump there.
  459. //Else beep.
  460. if(t3>31) current=t3;
  461. else beep();
  462. case 0:
  463. break;
  464. }
  465. //Loop
  466. } while(1);
  467. }
  468. // For color selection screen
  469. #define color_sel_char 'þ'
  470. #define color_sel_wild '?'
  471. // Color selection screen colors- see char selection screen.
  472. // Put up a color selection box. Returns selected, or negative selected
  473. // for ESC, -512 for -0. Returns OUT_OF_WIN_MEM if out of window mem.
  474. // Display is 16 across, 16 down. All work done on given segment. Current
  475. // uses bit 256 for the wild bit.
  476. // Mouse support- Click on a color to select it. If it is the current color,
  477. // it exits.
  478. int color_selection(int current,unsigned int segment,char allow_wild) {
  479. int t1,t2,t3;
  480. char currx,curry;
  481. //Save screen
  482. if(save_screen(segment)) return OUT_OF_WIN_MEM;
  483. if(context==72) set_context(98);
  484. else set_context(context);
  485. //Ensure allow_wild is 0 or 1
  486. allow_wild=(allow_wild!=0);
  487. //Calculate current x/y
  488. if((current&256)&&(allow_wild)) {
  489. //Wild
  490. current-=256;
  491. if(current<16) {
  492. currx=current;
  493. curry=16;
  494. }
  495. else {
  496. curry=current-16;
  497. currx=16;
  498. }
  499. }
  500. else if(current&256) {
  501. //Wild when not allowed to be
  502. current-=256;
  503. currx=current&15;
  504. curry=current>>4;
  505. }
  506. else {
  507. //Normal
  508. currx=current&15;
  509. curry=current>>4;
  510. }
  511. //Draw box
  512. m_hide();
  513. draw_window_box(12,2,33+allow_wild,21+allow_wild,segment,DI_MAIN,DI_DARK,
  514. DI_CORNER);
  515. //Add title
  516. write_string(" Select a color ",14,2,DI_TITLE,segment);
  517. do {
  518. //Draw outer edge
  519. draw_window_box(14,3,31+allow_wild,20+allow_wild,segment,DI_DARK,
  520. DI_MAIN,DI_CORNER,0,0);
  521. //Draw colors
  522. for(t1=0;t1<16+allow_wild;t1++) {
  523. for(t2=0;t2<16+allow_wild;t2++) {
  524. if(t1==16) {
  525. if(t2==16) draw_char(color_sel_wild,135,t1+15,t2+4,segment);
  526. else draw_char(color_sel_wild,fg_per_bk[t2]+t2*16,t1+15,t2+4,
  527. segment);
  528. }
  529. else if(t2==16) {
  530. if(t1==0) draw_char(color_sel_wild,128,t1+15,t2+4,segment);
  531. else draw_char(color_sel_wild,t1,t1+15,t2+4,segment);
  532. }
  533. else draw_char(color_sel_char,t1+t2*16,t1+15,t2+4,segment);
  534. }
  535. }
  536. //Add selection box
  537. draw_window_box(currx+14,curry+3,currx+16,curry+5,segment,DI_MAIN,DI_MAIN,
  538. DI_MAIN,0,0);
  539. //Write number of color
  540. if((allow_wild)&&((currx==16)||(curry==16))) {
  541. //Convert wild
  542. if(currx==16) {
  543. if(curry==16) t1=288;
  544. else t1=272+curry;
  545. }
  546. else t1=256+currx;
  547. }
  548. else t1=currx+curry*16;
  549. write_number(t1,DI_MAIN,28+allow_wild,21+allow_wild,segment,3);
  550. //Get key
  551. m_show();
  552. t3=getkey();
  553. m_hide();
  554. //Process
  555. switch(t3) {
  556. case MOUSE_EVENT:
  557. //Within area?
  558. if((mouse_event.cx<15)||(mouse_event.cx>30+allow_wild)||
  559. (mouse_event.cy<4)||(mouse_event.cy>19+allow_wild)) {//Nope!
  560. beep();
  561. break;
  562. }
  563. //Yep!
  564. t1=mouse_event.cx-15;
  565. t2=mouse_event.cy-4;
  566. if((currx==t1)&&(curry==t2)) {
  567. t3=13;
  568. goto enter;
  569. }
  570. currx=t1;
  571. curry=t2;
  572. break;
  573. case 27:
  574. //ESC
  575. case ' ':
  576. case 13:
  577. enter:
  578. pop_context();
  579. //Selected
  580. restore_screen(segment);
  581. m_show();
  582. if((allow_wild)&&((currx==16)||(curry==16))) {
  583. //Convert wild
  584. if(currx==16) {
  585. if(curry==16) current=288;
  586. else current=272+curry;
  587. }
  588. else current=256+currx;
  589. }
  590. else current=currx+curry*16;
  591. if(t3==27) {
  592. if(current==0) current=-512;
  593. else current=-current;
  594. }
  595. return current;
  596. case -72:
  597. case '8':
  598. //Up
  599. if(curry>0) curry--;
  600. break;
  601. case -80:
  602. case '2':
  603. //Down
  604. if(curry<(15+allow_wild)) curry++;
  605. break;
  606. case -75:
  607. case '4':
  608. //Left
  609. if(currx>0) currx--;
  610. break;
  611. case -77:
  612. case '6':
  613. //Right
  614. if(currx<(15+allow_wild)) currx++;
  615. break;
  616. case -71:
  617. //Home
  618. currx=curry=0;
  619. break;
  620. case -79:
  621. //End
  622. currx=curry=15+allow_wild;
  623. break;
  624. default:
  625. //Invalid character- beep.
  626. beep();
  627. case 0:
  628. break;
  629. }
  630. //Loop
  631. } while(1);
  632. }
  633. //Short function to display a color as a colored box
  634. void draw_color_box(unsigned char color,char q_bit,char x,char y,
  635. unsigned int segment) {
  636. m_hide();
  637. //If q_bit is set, there are unknowns
  638. if(q_bit) {
  639. if(color<16) {
  640. //Unknown background
  641. //Use black except for black fg, which uses grey
  642. if(color==0) color+=128;
  643. draw_char(color_wild,color,x,y,segment);
  644. draw_char(color_dot,color,x+1,y,segment);
  645. draw_char(color_wild,color,x+2,y,segment);
  646. }
  647. else if(color<32) {
  648. //Unkown foreground
  649. //Use foreground from array
  650. color-=16;
  651. color=(color<<4)+fg_per_bk[color];
  652. draw_char(color_wild,color,x,y,segment);
  653. draw_char(color_wild,color,x+1,y,segment);
  654. draw_char(color_wild,color,x+2,y,segment);
  655. }
  656. else {
  657. //Both unknown
  658. draw_char(color_wild,8,x,y,segment);
  659. draw_char(color_wild,135,x+1,y,segment);
  660. draw_char(color_wild,127,x+2,y,segment);
  661. }
  662. }
  663. else {
  664. draw_char(color_blank,color,x,y,segment);
  665. draw_char(color_dot,color,x+1,y,segment);
  666. draw_char(color_blank,color,x+2,y,segment);
  667. }
  668. m_show();
  669. }
  670. //Prototype- Internal function that displays a dialog box element.
  671. void display_element(unsigned int segment,char type,char x,char y,
  672. char far *str,int p1,int p2,void far *value,char active=0,
  673. char curr_check=0,char set_vid_usage=0);
  674. //The code that runs the dialog boxes... Returns OUT_OF_WIN_MEM if can't
  675. //save screen.
  676. //Mouse support- Click to move/select/choose.
  677. int run_dialog(dialog far *di,unsigned int segment,char reset_curr,
  678. char sfx_alt_t) {
  679. int t1,t2,key;
  680. long tlng;
  681. char mouse_held=0;
  682. //Current radio button or check box
  683. int curr_check=0;
  684. //Use these to save time and coding hassle
  685. int num_e=di->num_elements;
  686. int curr_e=di->curr_element;
  687. int x1=di->x1;
  688. int y1=di->y1;
  689. //X pos of title
  690. int titlex=x1+((di->x2-x1+1)>>1)-(str_len(di->title)>>1);
  691. //Save screen
  692. if(save_screen(segment)) return OUT_OF_WIN_MEM;
  693. if(context==72) set_context(98);
  694. else set_context(context);
  695. //Clear mouse usage array
  696. for(t1=0;t1<2000;t1++)
  697. vid_usage[t1]=-1;
  698. //Turn cursor off
  699. cursor_off();
  700. //Draw main box and title
  701. m_hide();
  702. draw_window_box(x1,y1,di->x2,di->y2,segment,DI_MAIN,DI_DARK,
  703. DI_CORNER);
  704. write_string(di->title,titlex,y1,DI_TITLE,segment);
  705. draw_char(' ',DI_TITLE,titlex-1,y1,segment);
  706. draw_char(' ',DI_TITLE,titlex+str_len(di->title),y1,segment);
  707. //Reset current
  708. if(reset_curr) di->curr_element=curr_e=0;
  709. //Initial draw of elements, as well as init of vid_usage
  710. for(t1=0;t1<num_e;t1++)
  711. display_element(segment,di->element_types[t1],x1+di->element_xs[t1],
  712. y1+di->element_ys[t1],di->element_strs[t1],di->element_param1s[t1],
  713. di->element_param2s[t1],di->element_storage[t1],t1==curr_e,0,t1+1);
  714. //Loop of selection
  715. do {
  716. //Check current...
  717. do {
  718. if(curr_e>=num_e) curr_e=0;
  719. t1=di->element_types[curr_e];
  720. if((t1==DE_BOX)||(t1==DE_TEXT)||(t1==DE_LINE))
  721. curr_e++;
  722. else break;
  723. } while(1);
  724. if(t1==DE_CHECK) {
  725. if(curr_check>=di->element_param1s[curr_e]) curr_check=0;
  726. }
  727. //Highlight current...
  728. display_element(segment,t1,x1+di->element_xs[curr_e],
  729. y1+di->element_ys[curr_e],di->element_strs[curr_e],
  730. di->element_param1s[curr_e],di->element_param2s[curr_e],
  731. di->element_storage[curr_e],1,curr_check);
  732. //Get key (through intake for DE_INPUT)
  733. m_show();
  734. if(mouse_held) {
  735. if(m_buttonstatus()&LEFTBDOWN) {
  736. if(mouse_held<3) {
  737. delay_time(100);
  738. if(!(m_buttonstatus()&LEFTBDOWN)) goto nombuttondn;
  739. mouse_held+=2;
  740. }
  741. if(mouse_held==3) {
  742. delay_time(5);
  743. key=-72;
  744. goto change_up;
  745. }
  746. else {
  747. delay_time(5);
  748. key=-80;
  749. goto change_down;
  750. }
  751. }
  752. nombuttondn:
  753. mouse_held=0;
  754. }
  755. if(t1==DE_INPUT) {
  756. key=intake((char far *)di->element_storage[curr_e],
  757. di->element_param1s[curr_e],x1+di->element_xs[curr_e]+
  758. str_len(di->element_strs[curr_e]),
  759. y1+di->element_ys[curr_e],segment,DI_INPUT,2,
  760. di->element_param2s[curr_e]);
  761. if(key==MOUSE_EVENT) acknowledge_mouse();
  762. }
  763. else key=getkey();
  764. //Process key (t1 still holds element type)
  765. switch(key) {
  766. case -20://Alt+T
  767. //Test sfx
  768. if(sfx_alt_t!=1) break;
  769. if((di->element_types[curr_e])!=DE_INPUT) break;
  770. //Play a sfx
  771. clear_sfx_queue();
  772. play_str((char far *)di->element_storage[curr_e]);
  773. break;
  774. case MOUSE_EVENT:
  775. //Is it over anything important?
  776. if(vid_usage[mouse_event.cx+mouse_event.cy*80]==-1) beep();//No.
  777. else {//Yes.
  778. //Get id number
  779. t2=vid_usage[mouse_event.cx+mouse_event.cy*80];
  780. if(t2!=curr_e) {
  781. //Unhighlight old element
  782. m_hide();
  783. display_element(segment,t1,x1+di->element_xs[curr_e],
  784. y1+di->element_ys[curr_e],di->element_strs[curr_e],
  785. di->element_param1s[curr_e],di->element_param2s[curr_e],
  786. di->element_storage[curr_e],0,curr_check);
  787. m_show();
  788. curr_e=t2;
  789. t2=-1;
  790. }
  791. //Get type of new one
  792. t1=di->element_types[curr_e];
  793. //Code for clicking on something... (t1!=-1 means it was
  794. //already current)
  795. switch(t1) {
  796. case DE_INPUT:
  797. //Nothing special
  798. break;
  799. case DE_CHECK:
  800. //Move curr_check and toggle
  801. curr_check=(mouse_event.cy-y1)-di->element_ys[curr_e];
  802. ((char far *)di->element_storage[curr_e])[curr_check]^=1;
  803. break;
  804. case DE_RADIO:
  805. //Move radio button
  806. ((char far *)di->element_storage[curr_e])[0]=
  807. (mouse_event.cy-y1)-di->element_ys[curr_e];
  808. break;
  809. case DE_COLOR:
  810. case DE_CHAR:
  811. case DE_LIST:
  812. case DE_BOARD:
  813. //Just like enter
  814. goto enter;
  815. case DE_BUTTON:
  816. //If it was already current, select. (enter)
  817. //Otherwise nothing happens.
  818. if(t2!=-1) goto enter;
  819. break;
  820. case DE_NUMBER:
  821. //Two types of numeral apply here.
  822. if((di->element_param1s[curr_e]==1)&&
  823. (di->element_param2s[curr_e]<10)) {//Number line
  824. //Select number IF on the number line itself
  825. t2=mouse_event.cx-x1;
  826. t2-=di->element_xs[curr_e];
  827. t2-=str_len(di->element_strs[curr_e]);
  828. if((t2<di->element_param2s[curr_e])&&(t2>=0))
  829. ((int far *)di->element_storage[curr_e])[0]=t2+1;
  830. break;
  831. }
  832. case DE_FIVE:
  833. //Numeric selector
  834. //Go to change_up w/-72 as key for up button
  835. //Go to change_down w/-80 as key for down button
  836. //Anything else is ignored
  837. //Set mouse_held to cycle.
  838. t2=mouse_event.cx-7-x1;
  839. t2-=di->element_xs[curr_e];
  840. t2-=str_len(di->element_strs[curr_e]);
  841. if((t2>=0)&&(t2<=2)) {
  842. key=-72;
  843. mouse_held=1;
  844. goto change_up;
  845. }
  846. else if((t2>=3)&&(t2<=5)) {
  847. key=-80;
  848. mouse_held=2;
  849. goto change_down;
  850. }
  851. break;
  852. }
  853. }
  854. break;
  855. case 9://Tab
  856. next_elem:
  857. //Unhighlight old element
  858. m_hide();
  859. display_element(segment,t1,x1+di->element_xs[curr_e],
  860. y1+di->element_ys[curr_e],di->element_strs[curr_e],
  861. di->element_param1s[curr_e],di->element_param2s[curr_e],
  862. di->element_storage[curr_e],0,curr_check);
  863. m_show();
  864. //Move to next element
  865. curr_e++;
  866. break;
  867. case -15://Shift + Tab
  868. prev_elem:
  869. //Unhighlight old element
  870. m_hide();
  871. display_element(segment,t1,x1+di->element_xs[curr_e],
  872. y1+di->element_ys[curr_e],di->element_strs[curr_e],
  873. di->element_param1s[curr_e],di->element_param2s[curr_e],
  874. di->element_storage[curr_e],0,curr_check);
  875. m_show();
  876. //Move to previous element, going past text/box/line
  877. do {
  878. curr_e--;
  879. if(curr_e<0) curr_e=num_e-1;
  880. t1=di->element_types[curr_e];
  881. if((t1==DE_BOX)||(t1==DE_TEXT)||(t1==DE_LINE)) continue;
  882. } while(0);
  883. break;
  884. case 32://Space
  885. case 13://Enter
  886. enter:
  887. //Activate button, choose from list/menu, or toggle check.
  888. switch(t1) {
  889. case DE_CHECK:
  890. ((char far *)di->element_storage[curr_e])[curr_check]^=1;
  891. break;
  892. case DE_COLOR:
  893. t2=color_selection(
  894. ((int far *)di->element_storage[curr_e])[0],segment,
  895. di->element_param1s[curr_e]);
  896. if(t2>=0) ((int far *)di->element_storage[curr_e])[0]=t2;
  897. break;
  898. case DE_CHAR:
  899. t2=char_selection(
  900. ((unsigned char far *)di->element_storage[curr_e])[0],
  901. segment);
  902. if(t2==0) t2=1;
  903. if((t2==255)&&(di->element_param1s[curr_e]==0)) t2=1;
  904. if(t2>=0)
  905. ((unsigned char far *)di->element_storage[curr_e])[0]=t2;
  906. break;
  907. case DE_BUTTON:
  908. //Restore screen, set current, and return answer
  909. pop_context();
  910. restore_screen(segment);
  911. di->curr_element=curr_e;
  912. return di->element_param1s[curr_e];
  913. case DE_BOARD:
  914. t2=choose_board(((int far *)di->element_storage[curr_e])[0],
  915. di->element_strs[curr_e],segment,
  916. di->element_param1s[curr_e]);
  917. if(t2>=0) ((int far *)di->element_storage[curr_e])[0]=t2;
  918. break;
  919. case DE_LIST:
  920. t2=di->element_param2s[curr_e];
  921. t2=list_menu(&(di->element_strs[curr_e][t2]),t2,
  922. di->element_strs[curr_e],
  923. ((int far *)di->element_storage[curr_e])[0],
  924. di->element_param1s[curr_e],segment);
  925. if(t2>=0) ((int far *)di->element_storage[curr_e])[0]=t2;
  926. break;
  927. default:
  928. //Same as a tab
  929. goto next_elem;
  930. }
  931. break;
  932. case -77://Right
  933. if((t1!=DE_NUMBER)&&(t1!=DE_FIVE)) goto change_down;
  934. case -72://Up
  935. case -152://Alt + Up
  936. case -141://Ctrl + Up
  937. case -73://PageUp
  938. change_up:
  939. //Change numeric, radio, or current check. Otherwise, move
  940. //to previous element.
  941. switch(t1) {
  942. case DE_RADIO:
  943. if(key==-73)
  944. ((char far *)di->element_storage[curr_e])[0]=0;
  945. else {
  946. if(((char far *)di->element_storage[curr_e])[0]>0)
  947. ((char far *)di->element_storage[curr_e])[0]--;
  948. }
  949. break;
  950. case DE_CHECK:
  951. if(key==-73) curr_check=0;
  952. else if(curr_check>0) curr_check--;
  953. break;
  954. case DE_NUMBER:
  955. case DE_FIVE:
  956. switch(key) {
  957. case -77://Right
  958. case -72://Up
  959. t2=1;
  960. break;
  961. case -152://Alt + Up
  962. case -141://Ctrl + Up
  963. t2=10;
  964. break;
  965. case -73://PageUp
  966. t2=100;
  967. break;
  968. }
  969. change_num:
  970. tlng=((int far *)di->element_storage[curr_e])[0];
  971. if((tlng+t2)<di->element_param1s[curr_e]) {
  972. ((int far *)di->element_storage[curr_e])[0]=
  973. di->element_param1s[curr_e];
  974. break;
  975. }
  976. if((tlng+t2)>di->element_param2s[curr_e]) {
  977. ((int far *)di->element_storage[curr_e])[0]=
  978. di->element_param2s[curr_e];
  979. break;
  980. }
  981. ((int far *)di->element_storage[curr_e])[0]+=t2;
  982. break;
  983. default:
  984. goto prev_elem;
  985. }
  986. break;
  987. case -71://Home
  988. //Change numeric, radio, or current check. Otherwise, move
  989. //to first element.
  990. switch(t1) {
  991. case DE_NUMBER:
  992. case DE_FIVE:
  993. ((int far *)di->element_storage[curr_e])[0]=
  994. di->element_param2s[curr_e];
  995. break;
  996. default:
  997. //Unhighlight old element
  998. m_hide();
  999. display_element(segment,t1,x1+di->element_xs[curr_e],
  1000. y1+di->element_ys[curr_e],di->element_strs[curr_e],
  1001. di->element_param1s[curr_e],di->element_param2s[curr_e],
  1002. di->element_storage[curr_e],0,curr_check);
  1003. m_show();
  1004. //Jump to first
  1005. curr_e=0;
  1006. if(sfx_alt_t>1) curr_e=sfx_alt_t;
  1007. else if(sfx_alt_t==1) curr_e=4;
  1008. break;
  1009. }
  1010. break;
  1011. case -75://Left
  1012. if((t1!=DE_NUMBER)&&(t1!=DE_FIVE)) goto change_up;
  1013. case -80://Down
  1014. case -160://Alt + Down
  1015. case -145://Ctrl + Down
  1016. case -81://PageDown
  1017. change_down:
  1018. //Change numeric, radio, or current check. Otherwise, move
  1019. //to next element.
  1020. switch(t1) {
  1021. case DE_RADIO:
  1022. if(key==-81)
  1023. ((char far *)di->element_storage[curr_e])[0]=
  1024. di->element_param1s[curr_e]-1;
  1025. else {
  1026. if(((char far *)di->element_storage[curr_e])[0]<
  1027. di->element_param1s[curr_e]-1)
  1028. ((char far *)di->element_storage[curr_e])[0]++;
  1029. }
  1030. break;
  1031. case DE_CHECK:
  1032. if(key==-81) curr_check=di->element_param1s[curr_e]-1;
  1033. else if(curr_check<di->element_param1s[curr_e]-1)
  1034. curr_check++;
  1035. break;
  1036. case DE_NUMBER:
  1037. case DE_FIVE:
  1038. switch(key) {
  1039. case -75://Left
  1040. case -80://Down
  1041. t2=-1;
  1042. break;
  1043. case -160://Alt + Down
  1044. case -145://Ctrl + Down
  1045. t2=-10;
  1046. break;
  1047. case -81://PageDown
  1048. t2=-100;
  1049. break;
  1050. }
  1051. goto change_num;
  1052. default:
  1053. goto next_elem;
  1054. }
  1055. break;
  1056. case -79://End
  1057. //Change numeric, radio, or current check. Otherwise, move
  1058. //to last element.
  1059. switch(t1) {
  1060. case DE_NUMBER:
  1061. case DE_FIVE:
  1062. ((int far *)di->element_storage[curr_e])[0]=
  1063. di->element_param1s[curr_e];
  1064. break;
  1065. default:
  1066. //Unhighlight old element
  1067. m_hide();
  1068. display_element(segment,t1,x1+di->element_xs[curr_e],
  1069. y1+di->element_ys[curr_e],di->element_strs[curr_e],
  1070. di->element_param1s[curr_e],di->element_param2s[curr_e],
  1071. di->element_storage[curr_e],0,curr_check);
  1072. m_show();
  1073. //Jump to end
  1074. if(sfx_alt_t>0) curr_e=0;
  1075. else {
  1076. curr_e=num_e-1;
  1077. //Work backwards past found text, box, or line
  1078. do {
  1079. curr_e--;
  1080. t1=di->element_types[curr_e];
  1081. if((t1==DE_BOX)||(t1==DE_TEXT)||(t1==DE_LINE)) continue;
  1082. } while(0);
  1083. }
  1084. break;
  1085. }
  1086. break;
  1087. case 27://ESC
  1088. //Restore screen, set current, and return -1
  1089. restore_screen(segment);
  1090. di->curr_element=curr_e;
  1091. pop_context();
  1092. return -1;
  1093. default:
  1094. //Change character to key. Otherwise beep.
  1095. if((t1==DE_CHAR)&&(key>31)&&(key<255))
  1096. ((char far *)di->element_storage[curr_e])[0]=key;
  1097. else beep();
  1098. case 0:
  1099. break;
  1100. }
  1101. m_hide();
  1102. //Loop
  1103. } while(1);
  1104. }
  1105. //Internal function to display an element, whether active or not.
  1106. //Does NOT preserve mouse cursor.
  1107. void display_element(unsigned int segment,char type,char x,char y,
  1108. char far *str,int p1,int p2,void far *value,char active,char curr_check,
  1109. char set_vid_usage) {
  1110. //If set_vid_usage is non-0, set the vid_usage array appropriately.
  1111. //set_vid_usage is equal to the element number plus 1.
  1112. int t1,t2;
  1113. char temp[7];
  1114. //Color for elements (active vs. inactive)
  1115. int color=DI_NONACTIVE;
  1116. if(active) color=DI_ACTIVE;
  1117. //Act according to type, and fill vid_usage array as well if flag set
  1118. switch(type) {
  1119. case DE_TEXT:
  1120. color_string(str,x,y,DI_TEXT,segment);
  1121. break;
  1122. case DE_BOX:
  1123. draw_window_box(x,y,x+p1-1,y+p2-1,segment,DI_DARK,DI_MAIN,DI_CORNER,
  1124. 0,0);
  1125. break;
  1126. case DE_LINE:
  1127. if(p2) {
  1128. //Vertical
  1129. for(t1=0;t1<p1;t1++)
  1130. draw_char('³',DI_LINE,x,y+t1,segment);
  1131. }
  1132. else {
  1133. //Horizontal
  1134. fill_line(p1,x,y,(DI_LINE<<8)+196,segment);
  1135. }
  1136. break;
  1137. case DE_INPUT:
  1138. write_string(str,x,y,color,segment);
  1139. write_string((char far *)value,x+str_len(str),y,DI_INPUT,segment);
  1140. fill_line(p1-str_len((char far *)value)+1,
  1141. x+str_len(str)+str_len((char far *)value),y,(DI_INPUT<<8)+32,
  1142. segment);
  1143. //Fill vid_usage
  1144. if(set_vid_usage) {
  1145. for(t1=0;t1<=p1+str_len(str);t1++)
  1146. vid_usage[t1+x+y*80]=set_vid_usage-1;
  1147. }
  1148. break;
  1149. case DE_CHECK:
  1150. write_string(str,x+4,y,DI_NONACTIVE,segment);
  1151. //Draw boxes
  1152. for(t1=0;t1<p1;t1++) {
  1153. if(((char far *)value)[t1]) write_string(check_on,x,y+t1,
  1154. DI_NONACTIVE,segment);
  1155. else write_string(check_off,x,y+t1,DI_NONACTIVE,segment);
  1156. }
  1157. //Highlight current
  1158. if(active) {
  1159. if(curr_check>=p1) curr_check=p1-1;
  1160. color_line(p2+4,x,y+curr_check,DI_ACTIVE,segment);
  1161. }
  1162. //Fill vid_usage
  1163. if(set_vid_usage) {
  1164. for(t1=0;t1<p1;t1++)
  1165. for(t2=0;t2<p2+4;t2++)
  1166. vid_usage[t2+x+(t1+y)*80]=set_vid_usage-1;
  1167. }
  1168. break;
  1169. case DE_RADIO:
  1170. write_string(str,x+4,y,DI_NONACTIVE,segment);
  1171. //Draw boxes
  1172. for(t1=0;t1<p1;t1++) {
  1173. if(t1==((char far *)value)[0]) write_string(radio_on,x,y+t1,
  1174. DI_NONACTIVE,segment);
  1175. else write_string(radio_off,x,y+t1,DI_NONACTIVE,segment);
  1176. }
  1177. //Highlight current
  1178. if(active) {
  1179. color_line(p2+4,x,y+((char far *)value)[0],DI_ACTIVE,segment);
  1180. }
  1181. //Fill vid_usage
  1182. if(set_vid_usage) {
  1183. for(t1=0;t1<p1;t1++)
  1184. for(t2=0;t2<p2+4;t2++)
  1185. vid_usage[t2+x+(t1+y)*80]=set_vid_usage-1;
  1186. }
  1187. break;
  1188. case DE_COLOR:
  1189. write_string(str,x,y,color,segment);
  1190. t1=((int far *)value)[0];
  1191. draw_color_box(t1&255,(t1&256)==256,x+str_len(str),y,segment);
  1192. //Fill vid_usage
  1193. if(set_vid_usage) {
  1194. t2=str_len(str)+3;
  1195. for(t1=0;t1<t2;t1++)
  1196. vid_usage[t1+x+y*80]=set_vid_usage-1;
  1197. }
  1198. break;
  1199. case DE_CHAR:
  1200. write_string(str,x,y,color,segment);
  1201. draw_char(((unsigned char far *)value)[0],DI_CHAR,x+str_len(str)+1,
  1202. y,segment);
  1203. draw_char(' ',DI_CHAR,x+str_len(str),y,segment);
  1204. draw_char(' ',DI_CHAR,x+str_len(str)+2,y,segment);
  1205. //Fill vid_usage
  1206. if(set_vid_usage) {
  1207. t2=str_len(str)+3;
  1208. for(t1=0;t1<t2;t1++)
  1209. vid_usage[t1+x+y*80]=set_vid_usage-1;
  1210. }
  1211. break;
  1212. case DE_BUTTON:
  1213. if(active) color=DI_ACTIVEBUTTON;
  1214. else color=DI_BUTTON;
  1215. write_string(str,x+1,y,color,segment);
  1216. draw_char(' ',color,x,y,segment);
  1217. draw_char(' ',color,x+str_len(str)+1,y,segment);
  1218. //Fill vid_usage
  1219. if(set_vid_usage) {
  1220. t2=str_len(str)+2;
  1221. for(t1=0;t1<t2;t1++)
  1222. vid_usage[t1+x+y*80]=set_vid_usage-1;
  1223. }
  1224. break;
  1225. case DE_NUMBER:
  1226. case DE_FIVE:
  1227. t1=1;
  1228. if(type==DE_FIVE) t1=5;
  1229. write_string(str,x,y,color,segment);
  1230. x+=str_len(str);
  1231. if((p1==1)&&(p2<10)&&(t1==1)) {
  1232. //Number line
  1233. for(t1=1;t1<=p2;t1++) {
  1234. if(t1==((int far *)value)[0]) draw_char(t1+'0',DI_ACTIVE,
  1235. x+t1-1,y,segment);
  1236. else draw_char(t1+'0',DI_NONACTIVE,x+t1-1,y,segment);
  1237. }
  1238. //Fill vid_usage
  1239. if(set_vid_usage) {
  1240. t2=str_len(str);
  1241. x-=t2;
  1242. t2+=p2;
  1243. for(t1=0;t1<t2;t1++)
  1244. vid_usage[t1+x+y*80]=set_vid_usage-1;
  1245. }
  1246. }
  1247. else {
  1248. //Number
  1249. itoa(((int far *)value)[0]*t1,temp,10);
  1250. fill_line(7,x,y,(DI_NUMERIC<<8)+32,segment);
  1251. write_string(temp,x+6-str_len(temp),y,DI_NUMERIC,segment);
  1252. //Buttons
  1253. write_string(num_buttons,x+7,y,DI_ARROWBUTTON,segment);
  1254. //Fill vid_usage
  1255. if(set_vid_usage) {
  1256. t2=str_len(str);
  1257. x-=t2;
  1258. t2+=13;
  1259. for(t1=0;t1<t2;t1++)
  1260. vid_usage[t1+x+y*80]=set_vid_usage-1;
  1261. }
  1262. }
  1263. break;
  1264. case DE_LIST:
  1265. write_string(str,x,y,color,segment);
  1266. //Draw in current choice
  1267. t1=p2*(((int far *)value)[0]+1);
  1268. fill_line(p2+1,x,y+1,(DI_LIST<<8)+32,segment);
  1269. color_string(&str[t1],x+1,y+1,DI_LIST,segment);
  1270. //Draw button
  1271. write_string(list_button,x+p2+1,y+1,DI_ARROWBUTTON,
  1272. segment);
  1273. //Fill vid_usage
  1274. if(set_vid_usage) {
  1275. for(t1=0;t1<=p2+3;t1++) {
  1276. vid_usage[t1+x+y*80]=set_vid_usage-1;
  1277. vid_usage[t1+x+(y+1)*80]=set_vid_usage-1;
  1278. }
  1279. }
  1280. break;
  1281. case DE_BOARD:
  1282. write_string(str,x,y,color,segment);
  1283. fill_line(BOARD_NAME_SIZE+1,x,y+1,(DI_LIST<<8)+32,segment);
  1284. if(board_where[((int far *)value)[0]]==W_NOWHERE)
  1285. color_string("(no board)",x+1,y+1,DI_LIST,segment);
  1286. else if((((int far *)value)[0]==0)&&(p1))
  1287. color_string("(none)",x+1,y+1,DI_LIST,segment);
  1288. else color_string(&board_list[((int far *)value)[0]*BOARD_NAME_SIZE],
  1289. x+1,y+1,DI_LIST,segment);
  1290. //Draw button
  1291. write_string(list_button,x+BOARD_NAME_SIZE+1,y+1,DI_ARROWBUTTON,
  1292. segment);
  1293. //Fill vid_usage
  1294. if(set_vid_usage) {
  1295. for(t1=0;t1<=BOARD_NAME_SIZE+3;t1++) {
  1296. vid_usage[t1+x+y*80]=set_vid_usage-1;
  1297. vid_usage[t1+x+(y+1)*80]=set_vid_usage-1;
  1298. }
  1299. }
  1300. break;
  1301. }
  1302. //Done!
  1303. }
  1304. //Shell for list_menu()
  1305. int choose_board(int current,char far *title,unsigned int segment,
  1306. char board0_none) {
  1307. int t1,t2=1,old_curr=curr_board,add_board=-1;
  1308. char temp[BOARD_NAME_SIZE];
  1309. //Go through- blank boards get a (no board) marker. t2 keeps track
  1310. //of the number of boards.
  1311. for(t1=0;t1<NUM_BOARDS;t1++) {
  1312. if(board_where[t1]==W_NOWHERE)
  1313. str_cpy(&board_list[t1*BOARD_NAME_SIZE],"(no board)");
  1314. else t2=t1+1;
  1315. }
  1316. if((current<0)||(current>=t2)) current=0;
  1317. //Add (new board) to bottom
  1318. if(t2<NUM_BOARDS) {
  1319. str_cpy(&board_list[t2*BOARD_NAME_SIZE],"(add board)");
  1320. add_board=t2;
  1321. t2++;
  1322. }
  1323. //Change top to (none) if needed
  1324. if(board0_none) {
  1325. str_cpy(temp,board_list);
  1326. str_cpy(board_list,"(none)");
  1327. }
  1328. //Run the list_menu()
  1329. current=list_menu(board_list,BOARD_NAME_SIZE,title,current,t2,segment);
  1330. //Fix board list
  1331. for(t1=0;t1<NUM_BOARDS;t1++)
  1332. if(board_where[t1]==W_NOWHERE)
  1333. board_list[t1*BOARD_NAME_SIZE]=0;
  1334. if(board0_none) str_cpy(board_list,temp);
  1335. //New board? (if select no board or add board)
  1336. if((board_where[current]==W_NOWHERE)&&(current>=0)) {
  1337. //Yepper! Save current board...
  1338. t1=curr_board;
  1339. //Find the first available...
  1340. if(t2==add_board) {
  1341. for(t2=0;t2<NUM_BOARDS;t2++)
  1342. if(board_where[t2]==W_NOWHERE) break;
  1343. }
  1344. else t2=current;//Use the board selected
  1345. //..get a name...
  1346. m_hide();
  1347. save_screen(segment);
  1348. draw_window_box(16,12,64,14,segment,79,64,70);
  1349. write_string("Name for new board:",18,13,78,segment);
  1350. board_list[t2*BOARD_NAME_SIZE]=0;
  1351. m_show();
  1352. if(intake(&board_list[t2*BOARD_NAME_SIZE],BOARD_NAME_SIZE-1,38,13,
  1353. segment,15,1,0)==27) {
  1354. restore_screen(segment);
  1355. return -1;
  1356. }
  1357. restore_screen(segment);
  1358. //...make a new board and return to current board
  1359. store_current();
  1360. clear_current_and_select(t2);
  1361. board_where[curr_board=t2]=W_CURRENT;
  1362. board_sizes[t2]=0;
  1363. swap_with(old_curr);
  1364. return t2;
  1365. }
  1366. //Return board number
  1367. return current;
  1368. }
  1369. char cd_types[2]={ DE_BUTTON,DE_BUTTON };
  1370. char cd_xs[2]={ 15,37 };
  1371. char cd_ys[2]={ 2,2 };
  1372. char far *cd_strs[2]={ "OK","Cancel" };
  1373. int cd_p1s[2]={ 0,1 };
  1374. dialog c_di={ 10,9,69,13,NULL,2,cd_types,cd_xs,cd_ys,cd_strs,cd_p1s,NULL,
  1375. NULL,0 };
  1376. //Shell for run_dialog()
  1377. char confirm(char far *str) {
  1378. c_di.title=str;
  1379. return run_dialog(&c_di,current_pg_seg);
  1380. }
  1381. char yn_types[2]={ DE_BUTTON,DE_BUTTON };
  1382. char yn_xs[2]={ 15,37 };
  1383. char yn_ys[2]={ 2,2 };
  1384. char far *yn_strs[2]={ "Yes","No" };
  1385. int yn_p1s[2]={ 0,1 };
  1386. dialog yn_di={ 10,9,69,13,NULL,2,yn_types,yn_xs,yn_ys,yn_strs,yn_p1s,NULL,
  1387. NULL,0 };
  1388. //Shell for run_dialog()
  1389. char ask_yes_no(char far *str) {
  1390. yn_di.title=str;
  1391. return run_dialog(&yn_di,current_pg_seg);
  1392. }
  1393. //Sort function for below use in qsort
  1394. int cdecl sort_function( const void *a, const void *b) {
  1395. //If one has a space first and the other doesn't, and the other
  1396. //doesn't have a 'ú' first, the other comes first.
  1397. if((((char *)a)[0]==32)&&(((char *)b)[0]!=32)&&
  1398. (((char *)b)[0]!='ú')) return 1;
  1399. if((((char *)b)[0]==32)&&(((char *)a)[0]!=32)&&
  1400. (((char *)a)[0]!='ú')) return -1;
  1401. return strcmp((char *)a,(char *)b);
  1402. }
  1403. //Shell for list_menu() (copies file chosen to ret and returns -1 for ESC)
  1404. //dirs_okay of 1 means drive and directory changing is allowed.
  1405. //Use NULL for wildcards to mean "all module files"
  1406. #define NUM_MOD_TYPES 5
  1407. #define MAX_FILES 1638
  1408. char *mod_types[NUM_MOD_TYPES]={
  1409. "*.MOD","*.NST","*.GDM","*.WOW","*.OCT" };
  1410. char choose_file(char far *wildcards,char far *ret,char far *title,
  1411. char dirs_okay) {
  1412. char prevdir[PATHNAME_SIZE],prevdrive;
  1413. long max_files;
  1414. struct ffblk ff;
  1415. int num=0,t1,t2,t3,curr_mod_type=-1;
  1416. char use_titles=0;
  1417. /* Room for filename AND title */
  1418. char far *list;
  1419. FILE *fp;
  1420. prevdrive=getdisk();
  1421. getcwd(prevdir,PATHNAME_SIZE);
  1422. //Allocate array
  1423. if(wildcards==NULL) free_sam_cache(1);//Okay in editor
  1424. max_files=farcoreleft()/40;
  1425. if(max_files>MAX_FILES) max_files=MAX_FILES;
  1426. if(max_files>100) list=(char far *)farmalloc(40*max_files);
  1427. else list=NULL;
  1428. if(list==NULL) {/* Attempt to grab some memory */
  1429. free_sam_cache(1);
  1430. max_files=farcoreleft()/40;
  1431. if(max_files>MAX_FILES) max_files=MAX_FILES;
  1432. if(max_files>100) list=(char far *)farmalloc(40*max_files);
  1433. else list=NULL;
  1434. if(list==NULL) {/* Free up sample mem */
  1435. free_up_board_memory();
  1436. max_files=farcoreleft()/40;
  1437. if(max_files>MAX_FILES) max_files=MAX_FILES;
  1438. if(max_files>100) list=(char far *)farmalloc(40*max_files);
  1439. else list=NULL;
  1440. if(list==NULL) {/* Clear module.. :( */
  1441. end_mod();
  1442. max_files=farcoreleft()/40;
  1443. if(max_files>MAX_FILES) max_files=MAX_FILES;
  1444. if(max_files>100) list=(char far *)farmalloc(40*max_files);
  1445. else list=NULL;
  1446. if(list==NULL)//Out of mem
  1447. error("Out of memory and/or disk space",2,4,
  1448. current_pg_seg,0x203);
  1449. }
  1450. }
  1451. }
  1452. re_search:
  1453. if(_fstricmp(wildcards,"*.MZX")==0) use_titles=1;
  1454. if(wildcards==NULL) wildcards=mod_types[curr_mod_type=0];
  1455. if(findfirst(wildcards,&ff,0)==-1) goto call_fc;
  1456. do {
  1457. str_cpy(&list[40*num]," ");
  1458. str_cpy(&list[40*num],ff.ff_name);/* Save filename, update num */
  1459. list[40*num+39]=str_len(ff.ff_name);// Save size for copying later
  1460. if(use_titles==1) {
  1461. fp=fopen(ff.ff_name,"rb");/* Open file to read name */
  1462. if(fp!=NULL) {
  1463. list[(40*num)+str_len(ff.ff_name)]=' ';
  1464. fread(&list[(40*num)+14],1,24,fp);/* Read title ! */
  1465. list[(40*num)+38]=0;
  1466. fclose(fp);
  1467. }
  1468. }
  1469. num++;
  1470. if(findnext(&ff)==-1) break;
  1471. if(num==max_files) goto file_lim;/* Limit on files because of memory... :( */
  1472. } while(1);
  1473. call_fc:
  1474. //Next mod type?
  1475. if((curr_mod_type>-1)&&(curr_mod_type<14)) {
  1476. wildcards=mod_types[++curr_mod_type];
  1477. goto re_search;
  1478. }
  1479. //Find directorys too, if wanted
  1480. if(dirs_okay) {
  1481. if(findfirst("*.*",&ff,FA_DIREC)==-1) goto call_fc2;
  1482. do {
  1483. if(!(ff.ff_attrib&FA_DIREC)) goto not_direc;
  1484. if(!_fstricmp(ff.ff_name,".")) goto not_direc;
  1485. str_cpy(&list[40*num]," [subdirectory]");
  1486. str_cpy(&list[40*num+1],ff.ff_name);/* Save filename, update num */
  1487. list[40*num+1+str_len(ff.ff_name)]=' ';
  1488. list[40*num+39]=str_len(ff.ff_name);
  1489. num++;
  1490. not_direc:
  1491. if(findnext(&ff)==-1) break;
  1492. if(num==max_files) goto file_lim;/* Limit on files because of memory... :( */
  1493. } while(1);
  1494. call_fc2:
  1495. //Add drives if room
  1496. t1=setdisk(t3=getdisk());
  1497. //t1=# drives
  1498. for(t2=0;t2<t1;t2++) {
  1499. if(num==max_files) goto file_lim;
  1500. setdisk(t2);
  1501. if(getdisk()!=t2) continue;
  1502. str_cpy(&list[40*num],"úA: [drive]");
  1503. list[40*num+1]+=t2;
  1504. num++;
  1505. }
  1506. setdisk(t3);
  1507. }
  1508. file_lim:
  1509. if(num==0) {
  1510. farfree(list);
  1511. error("No files found to select from",0,24,current_pg_seg,0x1701);
  1512. return -1;//No files to choose from!
  1513. }
  1514. //Sort
  1515. //(directorys automatically at bottom because of starting dot)
  1516. qsort((void *)list,num,40,sort_function);
  1517. num=list_menu(list,40,title,0,num,current_pg_seg,15);
  1518. if(num<0) {
  1519. setdisk(prevdrive);
  1520. chdir(prevdir);
  1521. farfree(list);
  1522. return -1;/* ESC or exit. */
  1523. }
  1524. //Directory or drive
  1525. if(list[40*num]=='ú') {
  1526. setdisk(list[40*num+1]-'A');
  1527. num=0;
  1528. use_titles=0;
  1529. goto re_search;
  1530. }
  1531. else if(list[40*num]==' ') {
  1532. list[40*num+1+list[40*num+39]]=0;
  1533. chdir(&list[40*num+1]);
  1534. num=0;
  1535. use_titles=0;
  1536. goto re_search;
  1537. }
  1538. mem_cpy(ret,&list[40*num],list[40*num+39]);
  1539. ret[list[40*num+39]]=0;
  1540. farfree(list);
  1541. return 0;
  1542. }