File: common\realdos.c
1 /*
2 Miscellaneous C routines used only in DOS Fractint.
3 */
4
5 #include <string.h>
6 #ifndef XFRACT
7 #include <io.h>
8 #include <process.h>
9 #endif
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <fcntl.h>
13 #include <ctype.h>
14
15 /* see Fractint.c for a description of the "include" hierarchy */
16 #include "port.h"
17 #include "prototyp.h"
18 #include "fractype.h"
19 #include "helpdefs.h"
20
21 static int menu_checkkey(int curkey,int choice);
22
23 /* uncomment following for production version */
24 /*
25 #define PRODUCTION
26 */
27 int release=2004; /* this has 2 implied decimals; increment it every synch */
28 int patchlevel=4; /* patchlevel for DOS version */
29
30 /* fullscreen_choice options */
31 #define CHOICERETURNKEY 1
32 #define CHOICEMENU 2
33 #define CHOICEHELP 4
34 #define CHOICESCRUNCH 16
35 #define CHOICESNOTSORTED 32
36
37 /* int stopmsg(flags,message) displays message and waits for a key:
38 message should be a max of 9 lines with \n's separating them;
39 no leading or trailing \n's in message;
40 no line longer than 76 chars for best appearance;
41 flag options:
42 &1 if already in text display mode, stackscreen is not called
43 and message is displayed at (12,0) instead of (4,0)
44 &2 if continue/cancel indication is to be returned;
45 when not set, "Any key to continue..." is displayed
46 when set, "Escape to cancel, any other key to continue..."
47 -1 is returned for cancel, 0 for continue
48 &4 set to suppress buzzer
49 &8 for Fractint for Windows & parser - use a fixed pitch font
50 &16 for info only message (green box instead of red in DOS vsn)
51 */
52 #ifdef XFRACT
53 static char far s_errorstart[] = {"*** Error during startup:"}; 54 #endif
55 static char far s_escape_cancel[] = {"Escape to cancel, any other key to continue..."};
56 static char far s_anykey[] = {"Any key to continue..."};
57 #if !defined(PRODUCTION) && !defined(XFRACT)
58 static char far s_custom[] = {"Customized Version"};
59 static char far s_incremental[] = {"Incremental release"};
60 #endif
61 int stopmsg (int flags, char far *msg)
62 {
63 int ret,toprow,color,savelookatmouse;
64 static unsigned char batchmode = 0;
65 if(debugflag != 0 || initbatch >= 1)
66 {
67 static FILE *fp = NULL;
68 if(fp==NULL && initbatch == 0)
69 fp=dir_fopen(workdir,"stopmsg.txt","w");
70 else
71 fp=dir_fopen(workdir,"stopmsg.txt","a");
72 if(fp != NULL)
73 #ifndef XFRACT
74 fprintf(fp,"%Fs\n",msg);
77 #endif
78 fclose(fp);
79 }
80 if (active_system == 0 /* DOS */
81 && first_init) { /* & cmdfiles hasn't finished 1st try */
82 #ifdef XFRACT
91 #else
92 printf("%Fs\n",msg);
93 dopause(1); /* pause deferred until after cmdfiles */
94 return(0);
95 #endif
96 }
97 if (initbatch >= 1 || batchmode) { /* in batch mode */
98 initbatch = 4; /* used to set errorlevel */
99 batchmode = 1; /* fixes *second* stopmsg in batch mode bug */
100 return (-1);
101 }
102 ret = 0;
103 savelookatmouse = lookatmouse;
104 lookatmouse = -13;
105 if ((flags & 1))
106 blankrows(toprow=12,10,7);
107 else {
108 stackscreen();
109 toprow = 4;
110 movecursor(4,0);
111 }
112 textcbase = 2; /* left margin is 2 */
113 putstring(toprow,0,7,msg);
114 if (flags & 2)
115 putstring(textrow+2,0,7,s_escape_cancel);
116 else
117 putstring(textrow+2,0,7,s_anykey);
118 textcbase = 0; /* back to full line */
119 color = (flags & 16) ? C_STOP_INFO : C_STOP_ERR;
120 setattr(toprow,0,color,(textrow+1-toprow)*80);
121 movecursor(25,80); /* cursor off */
122 if ((flags & 4) == 0)
123 buzzer((flags & 16) ? 0 : 2);
124 while (keypressed()) /* flush any keyahead */
125 getakey();
126 if(debugflag != 324)
127 if (getakeynohelp() == ESC)
128 ret = -1;
129 if ((flags & 1))
130 blankrows(toprow,10,7);
131 else
132 unstackscreen();
133 lookatmouse = savelookatmouse;
134 return ret;
135 }
136
137
138 static U16 temptextsave = 0;
139 static int textxdots,textydots;
140
141 /* texttempmsg(msg) displays a text message of up to 40 characters, waits
142 for a key press, restores the prior display, and returns (without
143 eating the key).
144 It works in almost any video mode - does nothing in some very odd cases
145 (HCGA hi-res with old bios), or when there isn't 10k of temp mem free. */
146 int texttempmsg(char far *msgparm)
147 {
148 if (showtempmsg(msgparm))
149 return(-1);
150 #ifndef XFRACT
151 while (!keypressed()) ; /* wait for a keystroke but don't eat it */
152 #else
153 waitkeypressed(0); /* wait for a keystroke but don't eat it */ 154 #endif
155 cleartempmsg();
156 return(0);
157 }
158
159 void freetempmsg()
160 {
161 if(temptextsave != 0)
162 MemoryRelease(temptextsave);
163 temptextsave = 0;
164 }
165
166 int showtempmsg(char far *msgparm)
167 {
168 static long size = 0;
169 char msg[41];
170 BYTE buffer[640];
171 BYTE far *fontptr;
172 BYTE *bufptr;
173 int i,j,k,fontchar,charnum;
174 int xrepeat = 0;
175 int yrepeat = 0;
176 int save_sxoffs,save_syoffs;
177 far_strncpy(msg,msgparm,40);
178 msg[40] = 0; /* ensure max message len of 40 chars */
179 if (dotmode == 11) { /* disk video, screen in text mode, easy */
180 dvid_status(0,msg);
181 return(0);
182 }
183 if (active_system == 0 /* DOS */
184 && first_init) { /* & cmdfiles hasn't finished 1st try */
185 printf("%s\n",msg);
186 return(0);
187 }
188
189 if ((fontptr = findfont(0)) == NULL) { /* old bios, no font table? */
190 if (oktoprint == 0 /* can't printf */
191 || sxdots > 640 || sydots > 200) /* not willing to trust char cell size */
192 return(-1); /* sorry, message not displayed */
193 textydots = 8;
194 textxdots = sxdots;
195 }
196 else {
197 xrepeat = (sxdots >= 640) ? 2 : 1;
198 yrepeat = (sydots >= 300) ? 2 : 1;
199 textxdots = strlen(msg) * xrepeat * 8;
200 textydots = yrepeat * 8;
201 }
202 /* worst case needs 10k */
203 if(temptextsave != 0)
204 if(size != (long)textxdots * (long)textydots)
205 freetempmsg();
206 size = (long)textxdots * (long)textydots;
207 save_sxoffs = sxoffs;
208 save_syoffs = syoffs;
209 if (video_scroll) {
210 sxoffs = video_startx;
211 syoffs = video_starty;
212 }
213 else
214 sxoffs = syoffs = 0;
215 if(temptextsave == 0) /* only save screen first time called */
216 {
217 if ((temptextsave = MemoryAlloc((U16)textxdots,(long)textydots,FARMEM)) == 0)
218 return(-1); /* sorry, message not displayed */
219 for (i = 0; i < textydots; ++i) {
220 get_line(i,0,textxdots-1,buffer);
221 MoveToMemory(buffer,(U16)textxdots,1L,(long)i,temptextsave);
222 }
223 }
224 if (fontptr == NULL) { /* bios must do it for us */
225 home();
226 printf(msg);
227 }
228 else { /* generate the characters */
229 find_special_colors(); /* get color_dark & color_medium set */
230 for (i = 0; i < 8; ++i) {
231 memset(buffer,color_dark,640);
232 bufptr = buffer;
233 charnum = -1;
234 while (msg[++charnum] != 0) {
235 fontchar = *(fontptr + msg[charnum]*8 + i);
236 for (j = 0; j < 8; ++j) {
237 for (k = 0; k < xrepeat; ++k) {
238 if ((fontchar & 0x80) != 0)
239 *bufptr = (BYTE)color_medium;
240 ++bufptr;
241 }
242 fontchar <<= 1;
243 }
244 }
245 for (j = 0; j < yrepeat; ++j)
246 put_line(i*yrepeat+j,0,textxdots-1,buffer);
247 }
248 }
249 sxoffs = save_sxoffs;
250 syoffs = save_syoffs;
251 return(0);
252 }
253
254 void cleartempmsg()
255 {
256 BYTE buffer[640];
257 int i;
258 int save_sxoffs,save_syoffs;
259 if (dotmode == 11) /* disk video, easy */
260 dvid_status(0,"");
261 else if (temptextsave != 0) {
262 save_sxoffs = sxoffs;
263 save_syoffs = syoffs;
264 if (video_scroll) {
265 sxoffs = video_startx;
266 syoffs = video_starty;
267 }
268 else
269 sxoffs = syoffs = 0;
270 for (i = 0; i < textydots; ++i) {
271 MoveFromMemory(buffer,(U16)textxdots,1L,(long)i,temptextsave);
272 put_line(i,0,textxdots-1,buffer);
273 }
274 if(using_jiim == 0) /* jiim frees memory with freetempmsg() */
275 {
276 MemoryRelease(temptextsave);
277 temptextsave = 0;
278 }
279 sxoffs = save_sxoffs;
280 syoffs = save_syoffs;
281 }
282 }
283
284
285 void blankrows(int row,int rows,int attr)
286 {
287 char buf[81];
288 memset(buf,' ',80);
289 buf[80] = 0;
290 while (--rows >= 0)
291 putstring(row++,0,attr,buf);
292 }
293
294 #if (_MSC_VER >= 700)
295 #pragma code_seg ("realdos1_text") /* place following in an overlay */
296 #endif
297
298 void helptitle()
299 {
300 char msg[MSGLEN],buf[MSGLEN];
301 setclear(); /* clear the screen */
302 #ifdef XFRACT
304 #else
305 *msg=0;
306 #endif
307 sprintf(buf,"FRACTINT Version %d.%01d",release/100,(release%100)/10);
308 strcat(msg,buf);
309 if (release%10) {
310 sprintf(buf,"%01d",release%10);
311 strcat(msg,buf);
312 }
313 if (patchlevel) {
314 sprintf(buf,".%d",patchlevel);
315 strcat(msg,buf);
316 }
317 putstringcenter(0,0,80,C_TITLE,msg);
318
319 /* uncomment next for production executable: */
320 #if defined(PRODUCTION) || defined(XFRACT)
321 return;
322 /*NOTREACHED*/ 323 #else
324 if (debugflag == 3002) return;
325 #define DEVELOPMENT
326 #ifdef DEVELOPMENT
327 putstring(0,2,C_TITLE_DEV,"Development Version");
330 #endif
331 putstring(0,55,C_TITLE_DEV,s_incremental);
332 #endif
333 }
334
335
336 void footer_msg(int *i, int options, char *speedstring)
337 {
338 static FCODE choiceinstr1a[]="Use the cursor keys to highlight your selection";
339 static FCODE choiceinstr1b[]="Use the cursor keys or type a value to make a selection";
340 static FCODE choiceinstr2a[]="Press ENTER for highlighted choice, or ESCAPE to back out";
341 static FCODE choiceinstr2b[]="Press ENTER for highlighted choice, ESCAPE to back out, or F1 for help";
342 static FCODE choiceinstr2c[]="Press ENTER for highlighted choice, or "FK_F1" for help";
343 putstringcenter((*i)++,0,80,C_PROMPT_BKGRD,
344 (speedstring) ? choiceinstr1b : choiceinstr1a);
345 putstringcenter(*(i++),0,80,C_PROMPT_BKGRD,
346 (options&CHOICEMENU) ? choiceinstr2c
347 : ((options&CHOICEHELP) ? choiceinstr2b : choiceinstr2a));
348 }
349
350 #if (_MSC_VER >= 700)
351 #pragma code_seg () /* back to normal segment */
352 #endif
353
354 int putstringcenter(int row, int col, int width, int attr, char far *msg)
355 {
356 char buf[81];
357 int i,j,k;
358 i = 0;
359 #ifdef XFRACT
360 if (width>=80) width=79; /* Some systems choke in column 80 */ 361 #endif
362 while (msg[i]) ++i; /* strlen for a far */
363 if (i == 0) return(-1);
364 if (i >= width) i = width - 1; /* sanity check */
365 j = (width - i) / 2;
366 j -= (width + 10 - i) / 20; /* when wide a bit left of center looks better */
367 memset(buf,' ',width);
368 buf[width] = 0;
369 i = 0;
370 k = j;
371 while (msg[i]) buf[k++] = msg[i++]; /* strcpy for a far */
372 putstring(row,col,attr,buf);
373 return j;
374 }
375
376 /*
377 * The stackscreen()/unstackscreen() functions for XFRACT have been
378 * moved to unix/video.c to more cleanly separate the XFRACT code.
379 */
380
381 #ifndef XFRACT
382 static int screenctr = -1;
383
384 #define MAXSCREENS 3
385
386 static U16 savescreen[MAXSCREENS];
387 static int saverc[MAXSCREENS+1];
388
389 void stackscreen()
390 {
391 BYTE far *vidmem;
392 int savebytes;
393 int i;
394 if (video_scroll) {
395 scroll_state(0); /* save position */
396 scroll_center(0,0);
397 }
398 if(*s_makepar == 0)
399 return;
400 saverc[screenctr+1] = textrow*80 + textcol;
401 if (++screenctr) { /* already have some stacked */
402 static char far msg[]={"stackscreen overflow"};
403 if ((i = screenctr - 1) >= MAXSCREENS) { /* bug, missing unstack? */
404 stopmsg(1,msg);
405 exit(1);
406 }
407 vidmem = MK_FP(textaddr,0);
408 savebytes = (text_type == 0) ? 4000 : 16384;
409 savescreen[i] = MemoryAlloc((U16)savebytes,1L,FARMEM);
410 if (savescreen[i] != 0)
411 MoveToMemory(vidmem,(U16)savebytes,1L,0L,savescreen[i]);
412 else {
413 static char far msg[]={"insufficient memory, aborting"};
414 stopmsg(1,msg);
415 exit(1);
416 }
417 setclear();
418 }
419 else
420 setfortext();
421 if (video_scroll) {
422 if (boxcount)
423 moveboxf(0.0,0.0);
424 }
425 }
426
427 void unstackscreen()
428 {
429 BYTE far *vidmem;
430 int savebytes;
431 if(*s_makepar == 0)
432 return;
433 textrow = saverc[screenctr] / 80;
434 textcol = saverc[screenctr] % 80;
435 if (--screenctr >= 0) { /* unstack */
436 vidmem = MK_FP(textaddr,0);
437 savebytes = (text_type == 0) ? 4000 : 16384;
438 if (savescreen[screenctr] != 0) {
439 MoveFromMemory(vidmem,(U16)savebytes,1L,0L,savescreen[screenctr]);
440 MemoryRelease(savescreen[screenctr]);
441 savescreen[screenctr] = 0;
442 }
443 }
444 else
445 setforgraphics();
446 movecursor(-1,-1);
447 if (video_scroll) {
448 if (boxcount)
449 moveboxf(0.0,0.0);
450 scroll_state(1); /* restore position */
451 }
452 }
453
454 void discardscreen()
455 {
456 if (--screenctr >= 0) { /* unstack */
457 if (savescreen[screenctr]) {
458 MemoryRelease(savescreen[screenctr]);
459 savescreen[screenctr] = 0;
460 }
461 }
462 else
463 discardgraphics();
464 }
465 #endif
466
467 /* ------------------------------------------------------------------------ */
468
469 char speed_prompt[]="Speed key string";
470
471 /* For file list purposes only, it's a directory name if first
472 char is a dot or last char is a slash */
473 static int isadirname(char far *name)
474 {
475 if(*name == '.' || endswithslash(name))
476 return 1;
477 else
478 return 0;
479 }
480
481 #if (_MSC_VER >= 700)
482 #pragma code_seg ("realdos1_text") /* place following in an overlay */
483 #endif
484
485 void show_speedstring(int speedrow,
486 char *speedstring,
487 int (*speedprompt)(int,int,int,char *,int))
488 {
489 int speed_match = 0;
490 int i,j;
491 char buf[81];
492 memset(buf,' ',80);
493 buf[80] = 0;
494 putstring(speedrow,0,C_PROMPT_BKGRD,buf);
495 if (*speedstring) { /* got a speedstring on the go */
496 putstring(speedrow,15,C_CHOICE_SP_INSTR," ");
497 if (speedprompt)
498 j = speedprompt(speedrow,16,C_CHOICE_SP_INSTR,speedstring,speed_match);
499 else {
500 putstring(speedrow,16,C_CHOICE_SP_INSTR,speed_prompt);
501 j = sizeof(speed_prompt)-1;
502 }
503 strcpy(buf,speedstring);
504 i = strlen(buf);
505 while (i < 30)
506 buf[i++] = ' ';
507 buf[i] = 0;
508 putstring(speedrow,16+j,C_CHOICE_SP_INSTR," ");
509 putstring(speedrow,17+j,C_CHOICE_SP_KEYIN,buf);
510 movecursor(speedrow,17+j+strlen(speedstring));
511 }
512 else
513 movecursor(25,80);
514 }
515
516 void process_speedstring(char *speedstring,
517 char far*far*choices, /* array of choice strings */
518 int curkey,
519 int *pcurrent,
520 int numchoices,
521 int is_unsorted)
522 {
523 int i, comp_result;
524
525 i = strlen(speedstring);
526 if (curkey == 8 && i > 0) /* backspace */
527 speedstring[--i] = 0;
528 if (33 <= curkey && curkey <= 126 && i < 30)
529 {
530 #ifndef XFRACT
531 curkey = tolower(curkey);
532 #endif
533 speedstring[i] = (char)curkey;
534 speedstring[++i] = 0;
535 }
536 if (i > 0) { /* locate matching type */
537 *pcurrent = 0;
538 while (*pcurrent < numchoices
539 && (comp_result = strncasecmp(speedstring,choices[*pcurrent],i))!=0) {
540 if (comp_result < 0 && !is_unsorted) {
541 *pcurrent -= *pcurrent ? 1 : 0;
542 break;
543 }
544 else
545 ++*pcurrent;
546 }
547 if (*pcurrent >= numchoices) /* bumped end of list */
548 *pcurrent = numchoices - 1;
549 /*if the list is unsorted, and the entry found is not the exact
550 entry, then go looking for the exact entry.
551 */
552 else if (is_unsorted && choices[*pcurrent][i]) {
553 int temp = *pcurrent;
554 while(++temp < numchoices) {
555 if (!choices[temp][i] && !strncasecmp(speedstring, choices[temp], i)) {
556 *pcurrent = temp;
557 break;
558 }
559 }
560 }
561 }
562 }
563
564
565 #if (_MSC_VER >= 700)
566 #pragma code_seg () /* back to normal segment */
567 #endif
568
569 int fullscreen_choice(
570 int options, /* &2 use menu coloring scheme */
571 /* &4 include F1 for help in instructions */
572 /* &8 add caller's instr after normal set */
573 /* &16 menu items up one line */
574 char far *hdg, /* heading info, \n delimited */
575 char far *hdg2, /* column heading or NULL */
576 char far *instr, /* instructions, \n delimited, or NULL */
577 int numchoices, /* How many choices in list */
578 char far*far*choices, /* array of choice strings */
579 int far *attributes, /* &3: 0 normal color, 1,3 highlight */
580 /* &256 marks a dummy entry */
581 int boxwidth, /* box width, 0 for calc (in items) */
582 int boxdepth, /* box depth, 0 for calc, 99 for max */
583 int colwidth, /* data width of a column, 0 for calc */
584 int current, /* start with this item */
585 void (*formatitem)(int,char*),/* routine to display an item or NULL */
586 char *speedstring, /* returned speed key value, or NULL */
587 int (*speedprompt)(int,int,int,char *,int),/* routine to display prompt or NULL */
588 int (*checkkey)(int,int) /* routine to check keystroke or NULL */
589 )
590 /* return is: n>=0 for choice n selected,
591 -1 for escape
592 k for checkkey routine return value k (if not 0 nor -1)
593 speedstring[0] != 0 on return if string is present
594 */
595 {
596
597 int titlelines,titlewidth;
598 int reqdrows;
599 int topleftrow,topleftcol;
600 int topleftchoice;
601 int speedrow = 0; /* speed key prompt */
602 int boxitems; /* boxwidth*boxdepth */
603 int curkey,increment,rev_increment = 0;
604 int redisplay;
605 int i,j,k = 0;
606 char far *charptr;
607 char buf[81];
608 char curitem[81];
609 char far *itemptr;
610 int ret,savelookatmouse;
611 int scrunch; /* scrunch up a line */
612
613 if(options&CHOICESCRUNCH)
614 scrunch = 1;
615 else
616 scrunch = 0;
617 savelookatmouse = lookatmouse;
618 lookatmouse = 0;
619 ret = -1;
620 if (speedstring
621 && (i = strlen(speedstring)) > 0) { /* preset current to passed string */
622 current = 0;
623 if(options&CHOICESNOTSORTED)
624 {
625 while (current < numchoices
626 && (k = strncasecmp(speedstring,choices[current],i)) != 0)
627 ++current;
628 if(k != 0)
629 current = 0;
630 }
631 else
632 {
633 while (current < numchoices
634 && (k = strncasecmp(speedstring,choices[current],i)) > 0)
635 ++current;
636 if (k < 0 && current > 0) /* oops - overshot */
637 --current;
638 }
639 if (current >= numchoices) /* bumped end of list */
640 current = numchoices - 1;
641 }
642
643 for(;;) {
644 if (current >= numchoices) /* no real choice in the list? */
645 goto fs_choice_end;
646 if ((attributes[current] & 256) == 0)
647 break;
648 ++current; /* scan for a real choice */
649 }
650
651 titlelines = titlewidth = 0;
652 if (hdg) {
653 charptr = hdg; /* count title lines, find widest */
654 i = 0;
655 titlelines = 1;
656 while (*charptr) {
657 if (*(charptr++) == '\n') {
658 ++titlelines;
659 i = -1;
660 }
661 if (++i > titlewidth)
662 titlewidth = i;
663 }
664 }
665
666 if (colwidth == 0) /* find widest column */
667 for (i = 0; i < numchoices; ++i)
668 {
669 int len;
670 if ((len=far_strlen(choices[i])) > colwidth)
671 colwidth = len;
672 }
673 /* title(1), blank(1), hdg(n), blank(1), body(n), blank(1), instr(?) */
674 reqdrows = 3 - scrunch; /* calc rows available */
675 if (hdg)
676 reqdrows += titlelines + 1;
677 if (instr) { /* count instructions lines */
678 charptr = instr;
679 ++reqdrows;
680 while (*charptr)
681 if (*(charptr++) == '\n')
682 ++reqdrows;
683 if ((options & 8)) /* show std instr too */
684 reqdrows += 2;
685 }
686 else
687 reqdrows += 2; /* standard instructions */
688 if (speedstring) ++reqdrows; /* a row for speedkey prompt */
689 if (boxdepth > (i = 25 - reqdrows)) /* limit the depth to max */
690 boxdepth = i;
691 if (boxwidth == 0) { /* pick box width and depth */
692 if (numchoices <= i - 2) { /* single column is 1st choice if we can */
693 boxdepth = numchoices;
694 boxwidth = 1;
695 }
696 else { /* sort-of-wide is 2nd choice */
697 boxwidth = 60 / (colwidth + 1);
698 if (boxwidth == 0
699 || (boxdepth = (numchoices+boxwidth-1)/boxwidth) > i - 2) {
700 boxwidth = 80 / (colwidth + 1); /* last gasp, full width */
701 if ((boxdepth = (numchoices+boxwidth-1)/boxwidth) > i)
702 boxdepth = i;
703 }
704 }
705 }
706 #if 0
711 #else
712 if ((i = (80 / boxwidth - colwidth) / 2 - 1) == 0) /* to allow wider prompts */
713 i = 1;
714 if (i < 0)
715 i = 0;
716 if (i > 3)
717 i = 3;
718 #endif
719 j = boxwidth * (colwidth += i) + i; /* overall width of box */
720 if (j < titlewidth+2)
721 j = titlewidth + 2;
722 if (j > 80)
723 j = 80;
724 if (j <= 70 && boxwidth == 2) { /* special case makes menus nicer */
725 ++j;
726 ++colwidth;
727 }
728 k = (80 - j) / 2; /* center the box */
729 k -= (90 - j) / 20;
730 topleftcol = k + i; /* column of topleft choice */
731 i = (25 - reqdrows - boxdepth) / 2;
732 i -= i / 4; /* higher is better if lots extra */
733 topleftrow = 3 + titlelines + i; /* row of topleft choice */
734
735 /* now set up the overall display */
736 helptitle(); /* clear, display title line */
737 setattr(1,0,C_PROMPT_BKGRD,24*80); /* init rest to background */
738 for (i = topleftrow-1-titlelines; i < topleftrow+boxdepth+1; ++i)
739 setattr(i,k,C_PROMPT_LO,j); /* draw empty box */
740 if (hdg) {
741 textcbase = (80 - titlewidth) / 2; /* set left margin for putstring */
742 textcbase -= (90 - titlewidth) / 20; /* put heading into box */
743 putstring(topleftrow-titlelines-1,0,C_PROMPT_HI,hdg);
744 textcbase = 0;
745 }
746 if (hdg2) /* display 2nd heading */
747 putstring(topleftrow-1,topleftcol,C_PROMPT_MED,hdg2);
748 i = topleftrow + boxdepth + 1;
749 if (instr == NULL || (options & 8)) { /* display default instructions */
750 if (i < 20) ++i;
751 if (speedstring) {
752 speedrow = i;
753 *speedstring = 0;
754 if (++i < 22) ++i;
755 }
756 i -= scrunch;
757 footer_msg(&i,options,speedstring);
758 }
759 if (instr) { /* display caller's instructions */
760 charptr = instr;
761 j = -1;
762 while ((buf[++j] = *(charptr++)) != 0)
763 if (buf[j] == '\n') {
764 buf[j] = 0;
765 putstringcenter(i++,0,80,C_PROMPT_BKGRD,buf);
766 j = -1;
767 }
768 putstringcenter(i,0,80,C_PROMPT_BKGRD,buf);
769 }
770
771 boxitems = boxwidth * boxdepth;
772 topleftchoice = 0; /* pick topleft for init display */
773 while (current - topleftchoice >= boxitems
774 || (current - topleftchoice > boxitems/2
775 && topleftchoice + boxitems < numchoices))
776 topleftchoice += boxwidth;
777 redisplay = 1;
778 topleftrow -= scrunch;
779 for(;;) { /* main loop */
780 if (redisplay) { /* display the current choices */
781 if ((options & CHOICEMENU) == 0) {
782 memset(buf,' ',80);
783 buf[boxwidth*colwidth] = 0;
784 for (i = (hdg2) ? 0 : -1; i <= boxdepth; ++i) /* blank the box */
785 putstring(topleftrow+i,topleftcol,C_PROMPT_LO,buf);
786 }
787 for (i = 0; i+topleftchoice < numchoices && i < boxitems; ++i) {
788 /* display the choices */
789 if ((k = attributes[j = i+topleftchoice] & 3) == 1)
790 k = C_PROMPT_LO;
791 else if (k == 3)
792 k = C_PROMPT_HI;
793 else
794 k = C_PROMPT_MED;
795 if (formatitem)
796 {
797 (*formatitem)(j,buf);
798 charptr=buf;
799 }
800 else
801 charptr = choices[j];
802 putstring(topleftrow+i/boxwidth,topleftcol+(i%boxwidth)*colwidth,
803 k,charptr);
804 }
805 /***
806 ... format differs for summary/detail, whups, force box width to
807 ... be 72 when detail toggle available? (2 grey margin each
808 ... side, 1 blue margin each side)
809 ***/
810 if (topleftchoice > 0 && hdg2 == NULL)
811 putstring(topleftrow-1,topleftcol,C_PROMPT_LO,"(more)");
812 if (topleftchoice + boxitems < numchoices)
813 putstring(topleftrow+boxdepth,topleftcol,C_PROMPT_LO,"(more)");
814 redisplay = 0;
815 }
816
817 i = current - topleftchoice; /* highlight the current choice */
818 if (formatitem)
819 {
820 (*formatitem)(current,curitem);
821 itemptr=curitem;
822 }
823 else
824 itemptr = choices[current];
825 putstring(topleftrow+i/boxwidth,topleftcol+(i%boxwidth)*colwidth,
826 C_CHOICE_CURRENT,itemptr);
827
828 if (speedstring) { /* show speedstring if any */
829 show_speedstring(speedrow,speedstring,speedprompt);
830 }
831 else
832 movecursor(25,80);
833
834 #ifndef XFRACT
835 while (!keypressed()) { } /* enables help */
836 #else
837 waitkeypressed(0); /* enables help */ 838 #endif
839 curkey = getakey();
840 #ifdef XFRACT
844 #endif
845
846 i = current - topleftchoice; /* unhighlight current choice */
847 if ((k = attributes[current] & 3) == 1)
848 k = C_PROMPT_LO;
849 else if (k == 3)
850 k = C_PROMPT_HI;
851 else
852 k = C_PROMPT_MED;
853 putstring(topleftrow+i/boxwidth,topleftcol+(i%boxwidth)*colwidth,
854 k,itemptr);
855
856 increment = 0;
857 switch (curkey) { /* deal with input key */
858 case ENTER:
859 case ENTER_2:
860 ret = current;
861 goto fs_choice_end;
862 case ESC:
863 goto fs_choice_end;
864 case DOWN_ARROW:
865 rev_increment = 0 - (increment = boxwidth);
866 break;
867 case DOWN_ARROW_2:
868 rev_increment = 0 - (increment = boxwidth);
869 {
870 int newcurrent = current;
871 while((newcurrent+=boxwidth) != current) {
872 if(newcurrent >= numchoices)
873 newcurrent = (newcurrent % boxwidth) - boxwidth;
874 else if(!isadirname(choices[newcurrent])) {
875 if(current != newcurrent)
876 current = newcurrent - boxwidth;
877 break; /* breaks the while loop */
878 }
879 }
880 }
881 break;
882 case UP_ARROW:
883 increment = 0 - (rev_increment = boxwidth);
884 break;
885 case UP_ARROW_2:
886 increment = 0 - (rev_increment = boxwidth);
887 {
888 int newcurrent = current;
889 while((newcurrent-=boxwidth) != current) {
890 if(newcurrent < 0) {
891 newcurrent = (numchoices - current) % boxwidth;
892 newcurrent = numchoices + (newcurrent ? boxwidth - newcurrent: 0);
893 }
894 else if(!isadirname(choices[newcurrent])) {
895 if(current != newcurrent)
896 current = newcurrent + boxwidth;
897 break; /* breaks the while loop */
898 }
899 }
900 }
901 break;
902 case RIGHT_ARROW:
903 increment = 1; rev_increment = -1;
904 break;
905 case RIGHT_ARROW_2: /* move to next file; if at last file, go to
906 first file */
907 increment = 1; rev_increment = -1;
908 {
909 int newcurrent = current;
910 while(++newcurrent != current) {
911 if(newcurrent >= numchoices)
912 newcurrent = -1;
913 else if(!isadirname(choices[newcurrent])) {
914 if(current != newcurrent)
915 current = newcurrent - 1;
916 break; /* breaks the while loop */
917 }
918 }
919 }
920 break;
921 case LEFT_ARROW:
922 increment = -1; rev_increment = 1;
923 break;
924 case LEFT_ARROW_2: /* move to previous file; if at first file, go to
925 last file */
926 increment = -1; rev_increment = 1;
927 {
928 int newcurrent = current;
929 while(--newcurrent != current) {
930 if(newcurrent < 0)
931 newcurrent = numchoices;
932 else if(!isadirname(choices[newcurrent])) {
933 if(current != newcurrent)
934 current = newcurrent + 1;
935 break; /* breaks the while loop */
936 }
937 }
938 }
939 break;
940 case PAGE_UP:
941 if (numchoices > boxitems) {
942 topleftchoice -= boxitems;
943 increment = -boxitems;
944 rev_increment = boxwidth;
945 redisplay = 1;
946 }
947 break;
948 case PAGE_DOWN:
949 if (numchoices > boxitems) {
950 topleftchoice += boxitems;
951 increment = boxitems;
952 rev_increment = -boxwidth;
953 redisplay = 1;
954 }
955 break;
956 case HOME:
957 current = -1;
958 increment = rev_increment = 1;
959 break;
960 case CTL_HOME:
961 current = -1;
962 increment = rev_increment = 1;
963 {
964 int newcurrent;
965 for(newcurrent = 0; newcurrent < numchoices; ++newcurrent) {
966 if(!isadirname(choices[newcurrent])) {
967 current = newcurrent - 1;
968 break; /* breaks the for loop */
969 }
970 }
971 }
972 break;
973 case END:
974 current = numchoices;
975 increment = rev_increment = -1;
976 break;
977 case CTL_END:
978 current = numchoices;
979 increment = rev_increment = -1;
980 {
981 int newcurrent;
982 for(newcurrent = numchoices - 1; newcurrent >= 0; --newcurrent) {
983 if(!isadirname(choices[newcurrent])) {
984 current = newcurrent + 1;
985 break; /* breaks the for loop */
986 }
987 }
988 }
989 break;
990 default:
991 if (checkkey) {
992 if ((ret = (*checkkey)(curkey,current)) < -1 || ret > 0)
993 goto fs_choice_end;
994 if (ret == -1)
995 redisplay = -1;
996 }
997 ret = -1;
998 if (speedstring) {
999 process_speedstring(speedstring,choices,curkey,¤t,
1000 numchoices,options&CHOICESNOTSORTED);
1001 }
1002 break;
1003 }
1004 if (increment) { /* apply cursor movement */
1005 current += increment;
1006 if (speedstring) /* zap speedstring */
1007 speedstring[0] = 0;
1008 }
1009 for(;;) { /* adjust to a non-comment choice */
1010 if (current < 0 || current >= numchoices)
1011 increment = rev_increment;
1012 else if ((attributes[current] & 256) == 0)
1013 break;
1014 current += increment;
1015 }
1016 if (topleftchoice > numchoices - boxitems)
1017 topleftchoice = ((numchoices+boxwidth-1)/boxwidth)*boxwidth - boxitems;
1018 if (topleftchoice < 0)
1019 topleftchoice = 0;
1020 while (current < topleftchoice) {
1021 topleftchoice -= boxwidth;
1022 redisplay = 1;
1023 }
1024 while (current >= topleftchoice + boxitems) {
1025 topleftchoice += boxwidth;
1026 redisplay = 1;
1027 }
1028 }
1029
1030 fs_choice_end:
1031 lookatmouse = savelookatmouse;
1032 return(ret);
1033
1034 }
1035
1036 #if (_MSC_VER >= 700)
1037 #pragma code_seg ("realdos1_text") /* place following in an overlay */
1038 #endif
1039
1040 /* squeeze space out of string */
1041 char *despace(char *str)
1042 {
1043 char *obuf, *nbuf;
1044
1045 for (obuf = str, nbuf = str; *obuf && obuf; ++obuf)
1046 {
1047 if (!isspace(*obuf))
1048 *nbuf++ = *obuf;
1049 }
1050 *nbuf = 0;
1051 return str;
1052 }
1053
1054 #ifndef XFRACT
1055 /* case independent version of strncmp */
1056 int strncasecmp(char far *s,char far *t,int ct)
1057 {
1058 for(; (tolower(*s) == tolower(*t)) && --ct ; s++,t++)
1059 if(*s == '\0')
1060 return(0);
1061 return(tolower(*s) - tolower(*t));
1062 }
1063 #endif
1064
1065 #define LOADPROMPTSCHOICES(X,Y) {\
1066 static FCODE tmp[] = { Y };\
1067 choices[X]= (char far *)tmp;\
1068 }
1069
1070 static int menutype;
1071 #define MENU_HDG 3
1072 #define MENU_ITEM 1
1073
1074 int main_menu(int fullmenu)
1075 {
1076 char far *choices[44]; /* 2 columns * 22 rows */
1077 int attributes[44];
1078 int choicekey[44];
1079 int i;
1080 int nextleft,nextright;
1081 int oldtabmode /* ,oldhelpmode */;
1082 static char far MAIN_MENU[] = {"MAIN MENU"};
1083 int showjuliatoggle;
1084 oldtabmode = tabmode;
1085 /* oldhelpmode = helpmode; */
1086 top:
1087 menutype = fullmenu;
1088 tabmode = 0;
1089 showjuliatoggle = 0;
1090 for (i = 0; i < 44; ++i) {
1091 attributes[i] = 256;
1092 choices[i] = "";
1093 choicekey[i] = -1;
1094 }
1095 nextleft = -2;
1096 nextright = -1;
1097
1098 if (fullmenu) {
1099 LOADPROMPTSCHOICES(nextleft+=2," CURRENT IMAGE ");
1100 attributes[nextleft] = 256+MENU_HDG;
1101 choicekey[nextleft+=2] = 13; /* enter */
1102 attributes[nextleft] = MENU_ITEM;
1103 if (calc_status == 2)
1104 {
1105 LOADPROMPTSCHOICES(nextleft,"continue calculation ");
1106 }
1107 else
1108 {
1109 LOADPROMPTSCHOICES(nextleft,"return to image ");
1110 }
1111 choicekey[nextleft+=2] = 9; /* tab */
1112 attributes[nextleft] = MENU_ITEM;
1113 LOADPROMPTSCHOICES(nextleft,"info about image <tab> ");
1114 choicekey[nextleft+=2] = 'o';
1115 attributes[nextleft] = MENU_ITEM;
1116 LOADPROMPTSCHOICES(nextleft,"orbits window <o> ");
1117 if(!(fractype==JULIA || fractype==JULIAFP || fractype==INVERSEJULIA))
1118 nextleft+=2;
1119 }
1120 LOADPROMPTSCHOICES(nextleft+=2," NEW IMAGE ");
1121 attributes[nextleft] = 256+MENU_HDG;
1122 #ifdef XFRACT
1126 #else
1127 choicekey[nextleft+=2] = DELETE;
1128 attributes[nextleft] = MENU_ITEM;
1129 LOADPROMPTSCHOICES(nextleft,"select video mode... <del> ");
1130 #endif
1131 choicekey[nextleft+=2] = 't';
1132 attributes[nextleft] = MENU_ITEM;
1133 LOADPROMPTSCHOICES(nextleft,"select fractal type <t> ");
1134 if (fullmenu) {
1135 if ((curfractalspecific->tojulia != NOFRACTAL
1136 && param[0] == 0.0 && param[1] == 0.0)
1137 || curfractalspecific->tomandel != NOFRACTAL) {
1138 choicekey[nextleft+=2] = ' ';
1139 attributes[nextleft] = MENU_ITEM;
1140 LOADPROMPTSCHOICES(nextleft,"toggle to/from julia <space>");
1141 showjuliatoggle = 1;
1142 }
1143 if(fractype==JULIA || fractype==JULIAFP || fractype==INVERSEJULIA) {
1144 choicekey[nextleft+=2] = 'j';
1145 attributes[nextleft] = MENU_ITEM;
1146 LOADPROMPTSCHOICES(nextleft,"toggle to/from inverse <j> ");
1147 showjuliatoggle = 1;
1148 }
1149 choicekey[nextleft+=2] = 'h';
1150 attributes[nextleft] = MENU_ITEM;
1151 LOADPROMPTSCHOICES(nextleft,"return to prior image <h> ");
1152
1153 choicekey[nextleft+=2] = 8;
1154 attributes[nextleft] = MENU_ITEM;
1155 LOADPROMPTSCHOICES(nextleft,"reverse thru history <ctl-h> ");
1156 }
1157 else
1158 nextleft += 2;
1159 LOADPROMPTSCHOICES(nextleft+=2," OPTIONS ");
1160 attributes[nextleft] = 256+MENU_HDG;
1161 choicekey[nextleft+=2] = 'x';
1162 attributes[nextleft] = MENU_ITEM;
1163 LOADPROMPTSCHOICES(nextleft,"basic options... <x> ");
1164 choicekey[nextleft+=2] = 'y';
1165 attributes[nextleft] = MENU_ITEM;
1166 LOADPROMPTSCHOICES(nextleft,"extended options... <y> ");
1167 choicekey[nextleft+=2] = 'z';
1168 attributes[nextleft] = MENU_ITEM;
1169 LOADPROMPTSCHOICES(nextleft,"type-specific parms... <z> ");
1170 choicekey[nextleft+=2] = 'p';
1171 attributes[nextleft] = MENU_ITEM;
1172 LOADPROMPTSCHOICES(nextleft,"passes options... <p> ");
1173 choicekey[nextleft+=2] = 'v';
1174 attributes[nextleft] = MENU_ITEM;
1175 LOADPROMPTSCHOICES(nextleft,"view window options... <v> ");
1176 if(showjuliatoggle == 0)
1177 {
1178 choicekey[nextleft+=2] = 'i';
1179 attributes[nextleft] = MENU_ITEM;
1180 LOADPROMPTSCHOICES(nextleft,"fractal 3D parms... <i> ");
1181 }
1182 choicekey[nextleft+=2] = 2;
1183 attributes[nextleft] = MENU_ITEM;
1184 LOADPROMPTSCHOICES(nextleft,"browse parms... <ctl-b>");
1185
1186 if (fullmenu) {
1187 choicekey[nextleft+=2] = 5;
1188 attributes[nextleft] = MENU_ITEM;
1189 LOADPROMPTSCHOICES(nextleft,"evolver parms... <ctl-e>");
1190 }
1191 #ifndef XFRACT
1192 if (fullmenu) {
1193 choicekey[nextleft+=2] = 6;
1194 attributes[nextleft] = MENU_ITEM;
1195 LOADPROMPTSCHOICES(nextleft,"sound parms... <ctl-f>");
1196 }
1197 #endif
1198 LOADPROMPTSCHOICES(nextright+=2," FILE ");
1199 attributes[nextright] = 256+MENU_HDG;
1200 choicekey[nextright+=2] = '@';
1201 attributes[nextright] = MENU_ITEM;
1202 LOADPROMPTSCHOICES(nextright,"run saved command set... <@> ");
1203 if (fullmenu) {
1204 choicekey[nextright+=2] = 's';
1205 attributes[nextright] = MENU_ITEM;
1206 LOADPROMPTSCHOICES(nextright,"save image to file <s> ");
1207 }
1208 choicekey[nextright+=2] = 'r';
1209 attributes[nextright] = MENU_ITEM;
1210 LOADPROMPTSCHOICES(nextright,"load image from file... <r> ");
1211 choicekey[nextright+=2] = '3';
1212 attributes[nextright] = MENU_ITEM;
1213 LOADPROMPTSCHOICES(nextright,"3d transform from file...<3> ");
1214 if (fullmenu) {
1215 choicekey[nextright+=2] = '#';
1216 attributes[nextright] = MENU_ITEM;
1217 LOADPROMPTSCHOICES(nextright,"3d overlay from file.....<#> ");
1218 choicekey[nextright+=2] = 'b';
1219 attributes[nextright] = MENU_ITEM;
1220 LOADPROMPTSCHOICES(nextright,"save current parameters..<b> ");
1221 choicekey[nextright+=2] = 16;
1222 attributes[nextright] = MENU_ITEM;
1223 LOADPROMPTSCHOICES(nextright,"print image <ctl-p> ");
1224 }
1225 #ifdef XFRACT
1229 #else
1230 choicekey[nextright+=2] = 'd';
1231 attributes[nextright] = MENU_ITEM;
1232 LOADPROMPTSCHOICES(nextright,"shell to dos <d> ");
1233 #endif
1234 choicekey[nextright+=2] = 'g';
1235 attributes[nextright] = MENU_ITEM;
1236 LOADPROMPTSCHOICES(nextright,"give command string <g> ");
1237 choicekey[nextright+=2] = ESC;
1238 attributes[nextright] = MENU_ITEM;
1239 LOADPROMPTSCHOICES(nextright,"quit "FRACTINT" <esc> ");
1240 choicekey[nextright+=2] = INSERT;
1241 attributes[nextright] = MENU_ITEM;
1242 LOADPROMPTSCHOICES(nextright,"restart "FRACTINT" <ins> ");
1243 #ifdef XFRACT
1245 #else
1246 if (fullmenu && gotrealdac && colors >= 16) {
1247 #endif
1248 /* nextright += 2; */
1249 LOADPROMPTSCHOICES(nextright+=2," COLORS ");
1250 attributes[nextright] = 256+MENU_HDG;
1251 choicekey[nextright+=2] = 'c';
1252 attributes[nextright] = MENU_ITEM;
1253 LOADPROMPTSCHOICES(nextright,"color cycling mode <c> ");
1254 choicekey[nextright+=2] = '+';
1255 attributes[nextright] = MENU_ITEM;
1256 LOADPROMPTSCHOICES(nextright,"rotate palette <+>, <-> ");
1257 if (colors > 16) {
1258 if (!reallyega) {
1259 choicekey[nextright+=2] = 'e';
1260 attributes[nextright] = MENU_ITEM;
1261 LOADPROMPTSCHOICES(nextright,"palette editing mode <e> ");
1262 }
1263 choicekey[nextright+=2] = 'a';
1264 attributes[nextright] = MENU_ITEM;
1265 LOADPROMPTSCHOICES(nextright,"make starfield <a> ");
1266 }
1267 }
1268 choicekey[nextright+=2] = 1;
1269 attributes[nextright] = MENU_ITEM;
1270 LOADPROMPTSCHOICES(nextright, "ant automaton <ctl-a>");
1271
1272 choicekey[nextright+=2] = 19;
1273 attributes[nextright] = MENU_ITEM;
1274 LOADPROMPTSCHOICES(nextright, "stereogram <ctl-s>");
1275
1276 i = (keypressed()) ? getakey() : 0;
1277 if (menu_checkkey(i,0) == 0) {
1278 helpmode = HELPMAIN; /* switch help modes */
1279 if ((nextleft += 2) < nextright)
1280 nextleft = nextright + 1;
1281 i = fullscreen_choice(CHOICEMENU+CHOICESCRUNCH,
1282 MAIN_MENU,
1283 NULL,NULL,nextleft,(char far * far *)choices,attributes,
1284 2,nextleft/2,29,0,NULL,NULL,NULL,menu_checkkey);
1285 if (i == -1) /* escape */
1286 i = ESC;
1287 else if (i < 0)
1288 i = 0 - i;
1289 else { /* user selected a choice */
1290 i = choicekey[i];
1291 switch (i) { /* check for special cases */
1292 case -10: /* zoombox functions */
1293 helpmode = HELPZOOM;
1294 help(0);
1295 i = 0;
1296 break;
1297 }
1298 }
1299 }
1300 if (i == ESC) { /* escape from menu exits Fractint */
1301 #ifdef XFRACT
1302 static char far s[] = "Exit from Xfractint (y/n)? y"; 1303 #else
1304 static char far s[] = "Exit from Fractint (y/n)? y";
1305 #endif
1306 helptitle();
1307 setattr(1,0,C_GENERAL_MED,24*80);
1308 for (i = 9; i <= 11; ++i)
1309 setattr(i,18,C_GENERAL_INPUT,40);
1310 putstringcenter(10,18,40,C_GENERAL_INPUT,s);
1311 movecursor(25,80);
1312 while ((i = getakey()) != 'y' && i != 'Y' && i != 13) {
1313 if (i == 'n' || i == 'N')
1314 goto top;
1315 }
1316 goodbye();
1317 }
1318 if (i == TAB) {
1319 tab_display();
1320 i = 0;
1321 }
1322 if (i == ENTER || i == ENTER_2)
1323 i = 0; /* don't trigger new calc */
1324 tabmode = oldtabmode;
1325 return(i);
1326 }
1327
1328 #if (_MSC_VER >= 700)
1329 #pragma code_seg () /* back to normal segment */
1330 #endif
1331
1332 static int menu_checkkey(int curkey,int choice)
1333 { /* choice is dummy used by other routines called by fullscreen_choice() */
1334 int testkey;
1335 testkey = choice; /* for warning only */
1336 testkey = (curkey>='A' && curkey<='Z') ? curkey+('a'-'A') : curkey;
1337 #ifdef XFRACT
1340 #endif
1341 if(testkey == '2')
1342 testkey = '@';
1343 if (strchr("#@2txyzgvir3dj",testkey) || testkey == INSERT || testkey == 2
1344 || testkey == ESC || testkey == DELETE || testkey == 6) /*RB 6== ctrl-F for sound menu */
1345 return(0-testkey);
1346 if (menutype) {
1347 if (strchr("\\sobpkrh",testkey) || testkey == TAB
1348 || testkey == 1 || testkey == 5 || testkey == 8
1349 || testkey == 16
1350 || testkey == 19 || testkey == 21) /* ctrl-A, E, H, P, S, U */
1351 return(0-testkey);
1352 if (testkey == ' ')
1353 if ((curfractalspecific->tojulia != NOFRACTAL
1354 && param[0] == 0.0 && param[1] == 0.0)
1355 || curfractalspecific->tomandel != NOFRACTAL)
1356 return(0-testkey);
1357 if (gotrealdac && colors >= 16) {
1358 if (strchr("c+-",testkey))
1359 return(0-testkey);
1360 if (colors > 16
1361 && (testkey == 'a' || (!reallyega && testkey == 'e')))
1362 return(0-testkey);
1363 }
1364 /* Alt-A and Alt-S */
1365 if (testkey == 1030 || testkey == 1031 )
1366 return(0-testkey);
1367 }
1368 if (check_vidmode_key(0,testkey) >= 0)
1369 return(0-testkey);
1370 return(0);
1371 }
1372
1373
1374 int input_field(
1375 int options, /* &1 numeric, &2 integer, &4 double */
1376 int attr, /* display attribute */
1377 char *fld, /* the field itself */
1378 int len, /* field length (declare as 1 larger for \0) */
1379 int row, /* display row */
1380 int col, /* display column */
1381 int (*checkkey)(int) /* routine to check non data keys, or NULL */
1382 )
1383 {
1384 char savefld[81];
1385 char buf[81];
1386 int insert, started, offset, curkey, display;
1387 int i, j;
1388 int ret,savelookatmouse;
1389 savelookatmouse = lookatmouse;
1390 lookatmouse = 0;
1391 ret = -1;
1392 strcpy(savefld,fld);
1393 insert = started = offset = 0;
1394 display = 1;
1395 for(;;) {
1396 strcpy(buf,fld);
1397 i = strlen(buf);
1398 while (i < len)
1399 buf[i++] = ' ';
1400 buf[len] = 0;
1401 if (display) { /* display current value */
1402 putstring(row,col,attr,buf);
1403 display = 0;
1404 }
1405 curkey = keycursor(row+insert,col+offset); /* get a keystroke */
1406 if(curkey == 1047) curkey = 47; /* numeric slash */
1407 switch (curkey) {
1408 case ENTER:
1409 case ENTER_2:
1410 ret = 0;
1411 goto inpfld_end;
1412 case ESC:
1413 goto inpfld_end;
1414 case RIGHT_ARROW:
1415 if (offset < len-1) ++offset;
1416 started = 1;
1417 break;
1418 case LEFT_ARROW:
1419 if (offset > 0) --offset;
1420 started = 1;
1421 break;
1422 case HOME:
1423 offset = 0;
1424 started = 1;
1425 break;
1426 case END:
1427 offset = strlen(fld);
1428 started = 1;
1429 break;
1430 case 8:
1431 case 127: /* backspace */
1432 if (offset > 0) {
1433 j = strlen(fld);
1434 for (i = offset-1; i < j; ++i)
1435 fld[i] = fld[i+1];
1436 --offset;
1437 }
1438 started = display = 1;
1439 break;
1440 case DELETE: /* delete */
1441 j = strlen(fld);
1442 for (i = offset; i < j; ++i)
1443 fld[i] = fld[i+1];
1444 started = display = 1;
1445 break;
1446 case INSERT: /* insert */
1447 insert ^= 0x8000;
1448 started = 1;
1449 break;
1450 case F5:
1451 strcpy(fld,savefld);
1452 insert = started = offset = 0;
1453 display = 1;
1454 break;
1455 default:
1456 if (nonalpha(curkey)) {
1457 if (checkkey && (ret = (*checkkey)(curkey)) != 0)
1458 goto inpfld_end;
1459 break; /* non alphanum char */
1460 }
1461 if (offset >= len) break; /* at end of field */
1462 if (insert && started && strlen(fld) >= (size_t)len)
1463 break; /* insert & full */
1464 if ((options & 1)
1465 && (curkey < '0' || curkey > '9')
1466 && curkey != '+' && curkey != '-') {
1467 if ((options & 2))
1468 break;
1469 /* allow scientific notation, and specials "e" and "p" */
1470 if ( ((curkey != 'e' && curkey != 'E') || offset >= 18)
1471 && ((curkey != 'p' && curkey != 'P') || offset != 0 )
1472 && curkey != '.')
1473 break;
1474 }
1475 if (started == 0) /* first char is data, zap field */
1476 fld[0] = 0;
1477 if (insert) {
1478 j = strlen(fld);
1479 while (j >= offset) {
1480 fld[j+1] = fld[j];
1481 --j;
1482 }
1483 }
1484 if ((size_t)offset >= strlen(fld))
1485 fld[offset+1] = 0;
1486 fld[offset++] = (char)curkey;
1487 /* if "e" or "p" in first col make number e or pi */
1488 if ((options & 3) == 1) { /* floating point */
1489 double tmpd;
1490 int specialv;
1491 char tmpfld[30];
1492 specialv = 0;
1493 if (*fld == 'e' || *fld == 'E') {
1494 tmpd = exp(1.0);
1495 specialv = 1;
1496 }
1497 if (*fld == 'p' || *fld == 'P') {
1498 tmpd = atan(1.0) * 4;
1499 specialv = 1;
1500 }
1501 if (specialv) {
1502 if ((options & 4) == 0)
1503 roundfloatd(&tmpd);
1504 sprintf(tmpfld,"%.15g",tmpd);
1505 tmpfld[len-1] = 0; /* safety, field should be long enough */
1506 strcpy(fld,tmpfld);
1507 offset = 0;
1508 }
1509 }
1510 started = display = 1;
1511 }
1512 }
1513 inpfld_end:
1514 lookatmouse = savelookatmouse;
1515 return(ret);
1516 }
1517
1518 int field_prompt(
1519 int options, /* &1 numeric value, &2 integer */
1520 char far *hdg, /* heading, \n delimited lines */
1521 char far *instr, /* additional instructions or NULL */
1522 char *fld, /* the field itself */
1523 int len, /* field length (declare as 1 larger for \0) */
1524 int (*checkkey)(int) /* routine to check non data keys, or NULL */
1525 )
1526 {
1527 char far *charptr;
1528 int boxwidth,titlelines,titlecol,titlerow;
1529 int promptcol;
1530 int i,j;
1531 char buf[81];
1532 static char far DEFLT_INST[] = {"Press ENTER when finished (or ESCAPE to back out)"};
1533 helptitle(); /* clear screen, display title */
1534 setattr(1,0,C_PROMPT_BKGRD,24*80); /* init rest to background */
1535 charptr = hdg; /* count title lines, find widest */
1536 i = boxwidth = 0;
1537 titlelines = 1;
1538 while (*charptr) {
1539 if (*(charptr++) == '\n') {
1540 ++titlelines;
1541 i = -1;
1542 }
1543 if (++i > boxwidth)
1544 boxwidth = i;
1545 }
1546 if (len > boxwidth)
1547 boxwidth = len;
1548 i = titlelines + 4; /* total rows in box */
1549 titlerow = (25 - i) / 2; /* top row of it all when centered */
1550 titlerow -= titlerow / 4; /* higher is better if lots extra */
1551 titlecol = (80 - boxwidth) / 2; /* center the box */
1552 titlecol -= (90 - boxwidth) / 20;
1553 promptcol = titlecol - (boxwidth-len)/2;
1554 j = titlecol; /* add margin at each side of box */
1555 if ((i = (82-boxwidth)/4) > 3)
1556 i = 3;
1557 j -= i;
1558 boxwidth += i * 2;
1559 for (i = -1; i < titlelines+3; ++i) /* draw empty box */
1560 setattr(titlerow+i,j,C_PROMPT_LO,boxwidth);
1561 textcbase = titlecol; /* set left margin for putstring */
1562 putstring(titlerow,0,C_PROMPT_HI,hdg); /* display heading */
1563 textcbase = 0;
1564 i = titlerow + titlelines + 4;
1565 if (instr) { /* display caller's instructions */
1566 charptr = instr;
1567 j = -1;
1568 while ((buf[++j] = *(charptr++)) != 0)
1569 if (buf[j] == '\n') {
1570 buf[j] = 0;
1571 putstringcenter(i++,0,80,C_PROMPT_BKGRD,buf);
1572 j = -1;
1573 }
1574 putstringcenter(i,0,80,C_PROMPT_BKGRD,buf);
1575 }
1576 else /* default instructions */
1577 putstringcenter(i,0,80,C_PROMPT_BKGRD,DEFLT_INST);
1578 return(input_field(options,C_PROMPT_INPUT,fld,len,
1579 titlerow+titlelines+1,promptcol,checkkey));
1580 }
1581
1582
1583 /* thinking(1,message):
1584 if thinking message not yet on display, it is displayed;
1585 otherwise the wheel is updated
1586 returns 0 to keep going, -1 if keystroke pending
1587 thinking(0,NULL):
1588 call this when thinking phase is done
1589 */
1590
1591 int thinking(int options,char far *msg)
1592 {
1593 static int thinkstate = -1;
1594 char *wheel[] = {"-","\\","|","/"};
1595 static int thinkcol;
1596 static int count = 0;
1597 char buf[81];
1598 if (options == 0) {
1599 if (thinkstate >= 0) {
1600 thinkstate = -1;
1601 unstackscreen();
1602 }
1603 return(0);
1604 }
1605 if (thinkstate < 0) {
1606 stackscreen();
1607 thinkstate = 0;
1608 helptitle();
1609 strcpy(buf," ");
1610 far_strcat(buf,msg);
1611 strcat(buf," ");
1612 putstring(4,10,C_GENERAL_HI,buf);
1613 thinkcol = textcol - 3;
1614 count = 0;
1615 }
1616 if ((count++)<100) {
1617 return 0;
1618 }
1619 count = 0;
1620 putstring(4,thinkcol,C_GENERAL_HI,wheel[thinkstate]);
1621 movecursor(25,80); /* turn off cursor */
1622 thinkstate = (thinkstate + 1) & 3;
1623 return (keypressed());
1624 }
1625
1626
1627 void clear_screen(int dummy) /* a stub for a windows only subroutine */
1628 {
1629 dummy=0; /* quite the warning */
1630 }
1631
1632
1633 /* savegraphics/restoregraphics: video.asm subroutines */
1634
1635 unsigned long swaptotlen;
1636 unsigned long swapoffset;
1637 BYTE far *swapvidbuf;
1638 int swaplength;
1639
1640 #define SWAPBLKLEN 4096 /* must be a power of 2 */
1641 U16 memhandle = 0;
1642
1643 #ifdef XFRACT
1645 #endif
1646
1647 #ifndef XFRACT
1648
1649 int savegraphics()
1650 {
1651 int i;
1652 long count;
1653 unsigned long swaptmpoff;
1654
1655 swaptotlen = (long)(vxdots > sxdots ? vxdots : sxdots) * (long)sydots;
1656 i = colors;
1657 while (i <= 16) {
1658 swaptotlen >>= 1;
1659 i = i * i;
1660 }
1661 count = (long)((swaptotlen / SWAPBLKLEN) + 1);
1662 swapoffset = 0;
1663 if (memhandle != 0)
1664 discardgraphics(); /* if any emm/xmm in use from prior call, release it */
1665 memhandle = MemoryAlloc((U16)SWAPBLKLEN, count, EXPANDED);
1666
1667 while (swapoffset < swaptotlen) {
1668 swaplength = SWAPBLKLEN;
1669 if ((swapoffset & (SWAPBLKLEN-1)) != 0)
1670 swaplength = (int)(SWAPBLKLEN - (swapoffset & (SWAPBLKLEN-1)));
1671 if ((unsigned long)swaplength > (swaptotlen - swapoffset))
1672 swaplength = (int)(swaptotlen - swapoffset);
1673 if (swapoffset == 0)
1674 swaptmpoff = 0;
1675 else
1676 swaptmpoff = swapoffset/swaplength;
1677 (*swapsetup)(); /* swapoffset,swaplength -> sets swapvidbuf,swaplength */
1678
1679 MoveToMemory(swapvidbuf,(U16)swaplength,1L,swaptmpoff,memhandle);
1680
1681 swapoffset += swaplength;
1682 }
1683 return 0;
1684 }
1685
1686 int restoregraphics()
1687 {
1688 unsigned long swaptmpoff;
1689
1690 swapoffset = 0;
1691 swapvidbuf = MK_FP(extraseg+0x1000,0); /* for swapnormwrite case */
1692
1693 while (swapoffset < swaptotlen) {
1694 swaplength = SWAPBLKLEN;
1695 if ((swapoffset & (SWAPBLKLEN-1)) != 0)
1696 swaplength = (int)(SWAPBLKLEN - (swapoffset & (SWAPBLKLEN-1)));
1697 if ((unsigned long)swaplength > (swaptotlen - swapoffset))
1698 swaplength = (int)(swaptotlen - swapoffset);
1699 if (swapoffset == 0)
1700 swaptmpoff = 0;
1701 else
1702 swaptmpoff = swapoffset/swaplength;
1703 if (swapsetup != swapnormread)
1704 (*swapsetup)(); /* swapoffset,swaplength -> sets swapvidbuf,swaplength */
1705
1706 MoveFromMemory(swapvidbuf,(U16)swaplength,1L,swaptmpoff,memhandle);
1707
1708 if (swapsetup == swapnormread)
1709 swapnormwrite();
1710 swapoffset += swaplength;
1711 }
1712
1713 discardgraphics();
1714 return(0);
1715 }
1716
1720 #endif
1721
1722 void discardgraphics() /* release expanded/extended memory if any in use */
1723 {
1724 #ifndef XFRACT
1725 MemoryRelease(memhandle);
1726 memhandle = 0;
1727 #endif
1728 }
1729
1730 #if (_MSC_VER >= 700)
1731 #pragma code_seg ("realdos1_text") /* place following in an overlay */
1732 #endif
1733
1734 VIDEOINFO *vidtbl; /* temporarily loaded fractint.cfg info */
1735 int vidtbllen; /* number of entries in above */
1736
1737 int showvidlength()
1738 {
1739 int sz;
1740 sz = (sizeof(VIDEOINFO)+sizeof(int))*MAXVIDEOMODES;
1741 return(sz);
1742 }
1743
1744
1745 int load_fractint_cfg(int options)
1746 {
1747 /* Reads fractint.cfg, loading videoinfo entries into extraseg. */
1748 /* Sets vidtbl pointing to the loaded table, and returns the */
1749 /* number of entries (also sets vidtbllen to this). */
1750 /* Past vidtbl, cfglinenums are stored for update_fractint_cfg. */
1751 /* If fractint.cfg is not found or invalid, issues a message */
1752 /* (first time the problem occurs only, and only if options is */
1753 /* zero) and uses the hard-coded table. */
1754
1755 FILE *cfgfile;
1756 VIDEOINFO *vident;
1757 int far *cfglinenums;
1758 int linenum;
1759 long xdots, ydots;
1760 int i, j, keynum, ax, bx, cx, dx, dotmode, colors;
1761 int commas[10];
1762 int textsafe2;
1763 char tempstring[150];
1764 int truecolorbits;
1765
1766 vidtbl = MK_FP(extraseg,0);
1767 cfglinenums = (int far *)(&vidtbl[MAXVIDEOMODES]);
1768
1769 #ifdef XFRACT
1771 #endif
1772
1773 if (badconfig) /* fractint.cfg already known to be missing or bad */
1774 goto use_resident_table;
1775
1776 findpath("fractint.cfg",tempstring);
1777 if (tempstring[0] == 0 /* can't find the file */
1778 || (cfgfile = fopen(tempstring,"r")) == NULL) /* can't open it */
1779 goto bad_fractint_cfg;
1780
1781 vidtbllen = 0;
1782 linenum = 0;
1783 vident = vidtbl;
1784 while (vidtbllen < MAXVIDEOMODES
1785 && fgets(tempstring, 120, cfgfile)) {
1786 if(strchr(tempstring,'\n') == NULL)
1787 /* finish reading the line */
1788 while(fgetc(cfgfile) != '\n' && !feof(cfgfile));
1789 ++linenum;
1790 if (tempstring[0] == ';') continue; /* comment line */
1791 tempstring[120] = 0;
1792 tempstring[strlen(tempstring)-1] = 0; /* zap trailing \n */
1793 memset(commas,0,20);
1794 i = j = -1;
1795 for(;;) {
1796 if (tempstring[++i] < ' ') {
1797 if (tempstring[i] == 0) break;
1798 tempstring[i] = ' '; /* convert tab (or whatever) to blank */
1799 }
1800 else if (tempstring[i] == ',' && ++j < 10) {
1801 commas[j] = i + 1; /* remember start of next field */
1802 tempstring[i] = 0; /* make field a separate string */
1803 }
1804 }
1805 keynum = check_vidmode_keyname(tempstring);
1806 sscanf(&tempstring[commas[1]],"%x",&ax);
1807 sscanf(&tempstring[commas[2]],"%x",&bx);
1808 sscanf(&tempstring[commas[3]],"%x",&cx);
1809 sscanf(&tempstring[commas[4]],"%x",&dx);
1810 dotmode = atoi(&tempstring[commas[5]]);
1811 xdots = atol(&tempstring[commas[6]]);
1812 ydots = atol(&tempstring[commas[7]]);
1813 colors = atoi(&tempstring[commas[8]]);
1814 if(colors == 4 && strchr(strlwr(&tempstring[commas[8]]),'g'))
1815 {
1816 colors = 256;
1817 truecolorbits = 4; /* 32 bits */
1818 }
1819 else if(colors == 16 && strchr(&tempstring[commas[8]],'m'))
1820 {
1821 colors = 256;
1822 truecolorbits = 3; /* 24 bits */
1823 }
1824 else if(colors == 64 && strchr(&tempstring[commas[8]],'k'))
1825 {
1826 colors = 256;
1827 truecolorbits = 2; /* 16 bits */
1828 }
1829 else if(colors == 32 && strchr(&tempstring[commas[8]],'k'))
1830 {
1831 colors = 256;
1832 truecolorbits = 1; /* 15 bits */
1833 }
1834 else
1835 truecolorbits = 0;
1836
1837 textsafe2 = dotmode / 100;
1838 dotmode %= 100;
1839 if (j < 9 ||
1840 keynum < 0 ||
1841 dotmode < 0 || dotmode > 30 ||
1842 textsafe2 < 0 || textsafe2 > 4 ||
1843 xdots < MINPIXELS || xdots > MAXPIXELS ||
1844 ydots < MINPIXELS || ydots > MAXPIXELS ||
1845 (colors != 0 && colors != 2 && colors != 4 && colors != 16 &&
1846 colors != 256)
1847 )
1848 goto bad_fractint_cfg;
1849 cfglinenums[vidtbllen] = linenum; /* for update_fractint_cfg */
1850 far_memcpy(vident->name, (char far *)&tempstring[commas[0]],25);
1851 far_memcpy(vident->comment,(char far *)&tempstring[commas[9]],25);
1852 vident->name[25] = vident->comment[25] = 0;
1853 vident->keynum = keynum;
1854 vident->videomodeax = ax;
1855 vident->videomodebx = bx;
1856 vident->videomodecx = cx;
1857 vident->videomodedx = dx;
1858 vident->dotmode = truecolorbits * 1000 + textsafe2 * 100 + dotmode;
1859 vident->xdots = (short)xdots;
1860 vident->ydots = (short)ydots;
1861 vident->colors = colors;
1862 ++vident;
1863 ++vidtbllen;
1864 }
1865 fclose(cfgfile);
1866 return (vidtbllen);
1867
1868 bad_fractint_cfg:
1869 badconfig = -1; /* bad, no message issued yet */
1870 if (options == 0)
1871 bad_fractint_cfg_msg();
1872
1873 use_resident_table:
1874 vidtbllen = 0;
1875 vident = vidtbl;
1876 for (i = 0; i < MAXVIDEOTABLE; ++i) {
1877 if (videotable[i].xdots) {
1878 far_memcpy((char far *)vident,(char far *)&videotable[i],
1879 sizeof(*vident));
1880 ++vident;
1881 ++vidtbllen;
1882 }
1883 }
1884 return (vidtbllen);
1885
1886 }
1887
1888 void bad_fractint_cfg_msg()
1889 {
1890 static char far badcfgmsg[]={"\
1891 File FRACTINT.CFG is missing or invalid.\n\
1892 See Hardware Support and Video Modes in the full documentation for help.\n\
1893 I will continue with only the built-in video modes available."};
1894 stopmsg(0,badcfgmsg);
1895 badconfig = 1; /* bad, message issued */
1896 }
1897
1898 void load_videotable(int options)
1899 {
1900 /* Loads fractint.cfg and copies the video modes which are */
1901 /* assigned to function keys into videotable. */
1902 int keyents,i;
1903 load_fractint_cfg(options); /* load fractint.cfg to extraseg */
1904 keyents = 0;
1905 far_memset((char far *)videotable,0,sizeof(*vidtbl)*MAXVIDEOTABLE);
1906 for (i = 0; i < vidtbllen; ++i) {
1907 if (vidtbl[i].keynum > 0) {
1908 far_memcpy((char far *)&videotable[keyents],(char far *)&vidtbl[i],
1909 sizeof(*vidtbl));
1910 if (++keyents >= MAXVIDEOTABLE)
1911 break;
1912 }
1913 }
1914 }
1915
1916 int check_vidmode_key(int option,int k)
1917 {
1918 int i;
1919 /* returns videotable entry number if the passed keystroke is a */
1920 /* function key currently assigned to a video mode, -1 otherwise */
1921 if (k == 1400) /* special value from select_vid_mode */
1922 return(MAXVIDEOTABLE-1); /* for last entry with no key assigned */
1923 if (k != 0) {
1924 if (option == 0) { /* check resident video mode table */
1925 for (i = 0; i < MAXVIDEOTABLE; ++i) {
1926 if (videotable[i].keynum == k)
1927 return(i);
1928 }
1929 }
1930 else { /* check full vidtbl */
1931 for (i = 0; i < vidtbllen; ++i) {
1932 if (vidtbl[i].keynum == k)
1933 return(i);
1934 }
1935 }
1936 }
1937 return(-1);
1938 }
1939
1940 int check_vidmode_keyname(char *kname)
1941 {
1942 /* returns key number for the passed keyname, 0 if not a keyname */
1943 int i,keyset;
1944 keyset = 1058;
1945 if (*kname == 'S' || *kname == 's') {
1946 keyset = 1083;
1947 ++kname;
1948 }
1949 else if (*kname == 'C' || *kname == 'c') {
1950 keyset = 1093;
1951 ++kname;
1952 }
1953 else if (*kname == 'A' || *kname == 'a') {
1954 keyset = 1103;
1955 ++kname;
1956 }
1957 if (*kname != 'F' && *kname != 'f')
1958 return(0);
1959 if (*++kname < '1' || *kname > '9')
1960 return(0);
1961 i = *kname - '0';
1962 if (*++kname != 0 && *kname != ' ') {
1963 if (*kname != '0' || i != 1)
1964 return(0);
1965 i = 10;
1966 ++kname;
1967 }
1968 while (*kname)
1969 if (*(kname++) != ' ')
1970 return(0);
1971 if ((i += keyset) < 2)
1972 i = 0;
1973 return(i);
1974 }
1975
1976 void vidmode_keyname(int k,char *buf)
1977 {
1978 /* set buffer to name of passed key number */
1979 *buf = 0;
1980 if (k > 0) {
1981 if (k > 1103) {
1982 *(buf++) = 'A';
1983 k -= 1103;
1984 }
1985 else if (k > 1093) {
1986 *(buf++) = 'C';
1987 k -= 1093;
1988 }
1989 else if (k > 1083) {
1990 *(buf++) = 'S';
1991 k -= 1083;
1992 }
1993 else
1994 k -= 1058;
1995 sprintf(buf,"F%d",k);
1996 }
1997 }
1998
1999 #if (_MSC_VER >= 700)
2000 #pragma code_seg () /* back to normal segment */
2001 #endif
2002