window.cpp 47 KB

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