uifc32.c 49.2 KB
Newer Older
deuce's avatar
deuce committed
1
/* uifc32.c */
2
3
4

/* Curses implementation of UIFC (user interface) library based on uifc.c */

rswindell's avatar
rswindell committed
5
6
/* $Id$ */

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
 * Copyright 2003 Rob Swindell - http://www.synchro.net/copyright.html		*
 *																			*
 * This library is free software; you can redistribute it and/or			*
 * modify it under the terms of the GNU Lesser General Public License		*
 * as published by the Free Software Foundation; either version 2			*
 * of the License, or (at your option) any later version.					*
 * See the GNU Lesser General Public License for more details: lgpl.txt or	*
 * http://www.fsf.org/copyleft/lesser.html									*
 *																			*
 * Anonymous FTP access to the most recent released source is available at	*
 * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
 *																			*
 * Anonymous CVS access to the development source and modification history	*
 * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
 *     (just hit return, no password is necessary)							*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * You are encouraged to submit any modifications (preferably in Unix diff	*
 * format) via e-mail to mods@synchro.net									*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

#ifdef __unix__
	#include <stdio.h>
	#include <unistd.h>
	#ifdef __QNX__
		#include <strings.h>
	#endif
	#include "ciowrap.h"
    #define mswait(x) delay(x)
46
47
    #define putch(x)	_putch(x,TRUE)
    #define clreol()	clrtoeol()
48
49
50
51
#elif defined(_WIN32)
	#include <share.h>
	#include <conio.h>
	#include <windows.h>
52
	#include "keys.h"
53
54
55
56
57
58
59
60
61
62
63
	#define mswait(x) Sleep(x)
#endif

#include "uifc.h"

							/* Bottom line elements */
#define BL_INS      (1<<0)  /* INS key */
#define BL_DEL      (1<<1)  /* DEL key */
#define BL_GET      (1<<2)  /* Get key */
#define BL_PUT      (1<<3)  /* Put key */

64
#ifdef __unix__
65
66
67
68
enum {
	 BLACK
	,BLUE	
	,GREEN	
69
	,CYAN
70
	,RED
71
	,MAGENTA
72
73
	,BROWN	
	,LIGHTGRAY	
74
	,DARKGRAY
75
76
	,LIGHTBLUE	
	,LIGHTGREEN	
77
78
	,LIGHTCYAN
	,LIGHTRED
79
80
81
82
	,LIGHTMAGENTA
	,YELLOW
	,WHITE
};
83
#endif
84
85
86

#define BLINK	128

87
static char  hclr,lclr,bclr,cclr,lbclr;
88
89
90
static int   cursor;
static char* helpfile=0;
static uint  helpline=0;
deuce's avatar
deuce committed
91
92
93
static size_t blk_scrn_len;
static char* blk_scrn;
static uchar* tmp_buffer;
94
static uchar* tmp_buffer2;
95
96
97
98
99
100
101
static win_t sav[MAX_BUFS];
static uifcapi_t* api;

/* Prototypes */
static int   uprintf(int x, int y, unsigned char attr, char *fmt,...);
static void  bottomline(int line);
static char  *utimestr(time_t *intime);
deuce's avatar
deuce committed
102
static void  help(void);
103
static int   ugetstr(int left, int top, char *outstr, int max, long mode, int *lastkey);
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
static void  timedisplay(void);

/* API routines */
static void uifcbail(void);
static int  uscrn(char *str);
static int  ulist(int mode, int left, int top, int width, int *dflt, int *bar
	,char *title, char **option);
static int  uinput(int imode, int left, int top, char *prompt, char *str
	,int len ,int kmode);
static void umsg(char *str);
static void upop(char *str);
static void sethelp(int line, char* file);
static void showbuf(int mode, int left, int top, int width, int height, char *title
	, char *hbuf, int *curp, int *barp);

/* Dynamic menu support */
static int *last_menu_cur=NULL;
static int *last_menu_bar=NULL;
static int save_menu_cur=-1;
static int save_menu_bar=-1;

static void reset_dynamic(void) {
	last_menu_cur=NULL;
	last_menu_bar=NULL;
	save_menu_cur=-1;
	save_menu_bar=-1;
}

/****************************************************************************/
/* Initialization function, see uifc.h for details.							*/
/* Returns 0 on success.													*/
/****************************************************************************/

deuce's avatar
deuce committed
137
int kbwait(void) {
138
139
	int timeout=0;
	while(timeout++<500) {
140
		if(kbhit())
141
			return(TRUE);
142
		mswait(1);
143
144
145
146
	}
	return(FALSE);
}

147
148
149
150
int inkey(int mode)
{
	int c;

151
152
153
154
155
156
	if(mode)
		return(kbwait());
	c=getch();
#ifdef _WIN32
	if(!c)
		c=(getch()<<8);
157
#endif
158
159
	return(c);
}
160

161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
int uifcini32(uifcapi_t* uifcapi)
{
	int 	i;
	struct	text_info txtinfo;

    if(uifcapi==NULL || uifcapi->size!=sizeof(uifcapi_t))
        return(-1);

    api=uifcapi;

    /* install function handlers */            
    api->bail=uifcbail;
    api->scrn=uscrn;
    api->msg=umsg;
    api->pop=upop;
    api->list=ulist;
    api->input=uinput;
    api->sethelp=sethelp;
    api->showhelp=help;
deuce's avatar
deuce committed
180
	api->showbuf=showbuf;
181
	api->timedisplay=timedisplay;
182
	api->getstrxy=ugetstr;
183

184
185
186
187
	/* A esc_delay of less than 10 is stupid... silently override */
	if(api->esc_delay < 10)
		api->esc_delay=25;

188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
#ifdef __unix__
	initciowrap(api->mode);
	#ifdef NCURSES_VERSION_MAJOR
		ESCDELAY=api->esc_delay;
	#endif
#else
    if(api->scrn_len!=0) {
        switch(api->scrn_len) {
            case 14:
                textmode(C80X14);
                break;
            case 21:
                textmode(C80X21);
                break;
            case 25:
                textmode(C80);
                break;
            case 28:
                textmode(C80X28);
                break;
            case 43:
                textmode(C80X43);
                break;
            case 50:
                textmode(C80X50);
                break;
            case 60:
                textmode(C80X60);
                break;
            default:
                textmode(C4350);
                break;
        }
    }
#endif

    clrscr();

    gettextinfo(&txtinfo);
#ifdef _WIN32
    /* unsupported mode? */
    if(txtinfo.screenheight<MIN_LINES
deuce's avatar
deuce committed
230
/*        || txtinfo.screenheight>MAX_LINES */
231
232
233
234
235
236
237
        || txtinfo.screenwidth<80) {
        textmode(C80);  /* set mode to 80x25*/
        gettextinfo(&txtinfo);
    }
#endif

    api->scrn_len=txtinfo.screenheight;
deuce's avatar
deuce committed
238
239
240
    if(api->scrn_len<MIN_LINES) {
        cprintf("\7UIFC: Screen length (%u) must be %d lines or greater\r\n"
            ,api->scrn_len,MIN_LINES);
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
        return(-2);
    }
    api->scrn_len--; /* account for status line */

    if(txtinfo.screenwidth<80) {
        cprintf("\7UIFC: Screen width (%u) must be at least 80 characters\r\n"
            ,txtinfo.screenwidth);
        return(-3);
    }
	api->scrn_width=txtinfo.screenwidth;

    if(!(api->mode&UIFC_COLOR)
        && (api->mode&UIFC_MONO
            || txtinfo.currmode==MONO || txtinfo.currmode==BW80)) {
        bclr=BLACK;
        hclr=WHITE;
        lclr=LIGHTGRAY;
        cclr=LIGHTGRAY;
259
260
261
262
263
264
#ifdef __unix__
		if(txtinfo.currmode==MONO)
			lbclr=WHITE|(BLACK<<4);		/* no color on curses means no inverse either */
		else
#endif
			lbclr=BLACK|(LIGHTGRAY<<4);	/* lightbar color */
265
266
267
268
269
    } else {
        bclr=BLUE;
        hclr=YELLOW;
        lclr=WHITE;
        cclr=CYAN;
270
		lbclr=BLUE|(LIGHTGRAY<<4);	/* lightbar color */
271
    }
272

deuce's avatar
deuce committed
273
274
275
276
277
278
279
280
281
282
283
	blk_scrn_len=api->scrn_width*api->scrn_len*2;
	if((blk_scrn=(char *)MALLOC(blk_scrn_len))==NULL)  {
				cprintf("UIFC line %d: error allocating %u bytes."
					,__LINE__,blk_scrn_len);
				return(-1);
	}
	if((tmp_buffer=(uchar *)MALLOC(blk_scrn_len))==NULL)  {
				cprintf("UIFC line %d: error allocating %u bytes."
					,__LINE__,blk_scrn_len);
				return(-1);
	}
284
285
286
287
288
	if((tmp_buffer2=(uchar *)MALLOC(blk_scrn_len))==NULL)  {
				cprintf("UIFC line %d: error allocating %u bytes."
					,__LINE__,blk_scrn_len);
				return(-1);
	}
deuce's avatar
deuce committed
289
    for(i=0;i<blk_scrn_len;i+=2) {
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
        blk_scrn[i]='';
        blk_scrn[i+1]=cclr|(bclr<<4);
    }

    cursor=_NOCURSOR;
    _setcursortype(cursor);

    return(0);
}

void uifcbail(void)
{
	_setcursortype(_NORMALCURSOR);
	textattr(LIGHTGRAY);
	clrscr();
#ifdef __unix__
	nl();
	nocbreak();
	noraw();
	refresh();
	endwin();
#endif
deuce's avatar
deuce committed
312
313
	FREE(blk_scrn);
	FREE(tmp_buffer);
314
	FREE(tmp_buffer2);
315
316
317
318
319
320
321
322
323
324
}

/****************************************************************************/
/* Clear screen, fill with background attribute, display application title.	*/
/* Returns 0 on success.													*/
/****************************************************************************/
int uscrn(char *str)
{
    textattr(bclr|(cclr<<4));
    gotoxy(1,1);
325
    clreol();
326
327
328
329
330
    gotoxy(3,1);
	cputs(str);
    if(!puttext(1,2,api->scrn_width,api->scrn_len,blk_scrn))
        return(-1);
    gotoxy(1,api->scrn_len+1);
331
    clreol();
332
333
334
335
336
337
338
339
	reset_dynamic();
    return(0);
}

/****************************************************************************/
/****************************************************************************/
static void scroll_text(int x1, int y1, int x2, int y2, int down)
{
340
	gettext(x1,y1,x2,y2,tmp_buffer2);
341
	if(down)
342
		puttext(x1,y1+1,x2,y2,tmp_buffer2);
343
	else
344
		puttext(x1,y1,x2,y2-1,tmp_buffer2+(((x2-x1)+1)*2));
345
346
347
348
349
350
351
352
353
354
355
356
357
}

/****************************************************************************/
/* Updates time in upper left corner of screen with current time in ASCII/  */
/* Unix format																*/
/****************************************************************************/
static void timedisplay()
{
	static time_t savetime;
	time_t now;

	now=time(NULL);
	if(difftime(now,savetime)>=60) {
358
		uprintf(api->scrn_width-25,1,bclr|(cclr<<4),utimestr(&now));
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
		savetime=now; 
	}
}

/****************************************************************************/
/* Truncates white-space chars off end of 'str'								*/
/****************************************************************************/
static void truncsp(char *str)
{
	uint c;

	c=strlen(str);
	while(c && (uchar)str[c-1]<=SP) c--;
	if(str[c]!=0)	/* don't write to string constants */
		str[c]=0;
}

/****************************************************************************/
/* General menu function, see uifc.h for details.							*/
/****************************************************************************/
int ulist(int mode, int left, int top, int width, int *cur, int *bar
	, char *title, char **option)
{
deuce's avatar
deuce committed
382
	uchar line[256],shade[256],*ptr,a,b,c,longopt
383
384
385
386
		,search[MAX_OPLN],bline=0;
	int height,y;
	int i,j,opts=0,s=0; /* s=search index into options */
	int	is_redraw=0;
deuce's avatar
deuce committed
387
388
389
390
	uint s_top=SCRN_TOP;
	uint s_left=SCRN_LEFT;
	uint s_right=SCRN_RIGHT;
	uint s_bottom=api->scrn_len-3;
391
392
393
394

	if(mode&WIN_FAT) {
		s_top=1;
		s_left=0;
395
396
		s_right=api->scrn_width-3;  /* Leave space for the shadow */
		s_bottom=api->scrn_len-1;   /* Leave one for the shadow */
397
	}
398
399
400
401
402
403
404
	if(mode&WIN_SAV && api->savnum>=MAX_BUFS-1)
		putch(7);
	if(mode&WIN_INS) bline|=BL_INS;
	if(mode&WIN_DEL) bline|=BL_DEL;
	if(mode&WIN_GET) bline|=BL_GET;
	if(mode&WIN_PUT) bline|=BL_PUT;
	bottomline(bline);
deuce's avatar
deuce committed
405
	while(opts<MAX_OPTS)
406
407
408
		if(option[opts][0]==0)
			break;
		else opts++;
deuce's avatar
deuce committed
409
	if(mode&WIN_XTR && opts<MAX_OPTS)
410
		opts++;
411
	height=opts+4;
412
413
	if(top+height>s_bottom)
		height=(s_bottom)-top;
414
415
416
417
418
	if(!width || width<strlen(title)+6) {
		width=strlen(title)+6;
		for(i=0;i<opts;i++) {
			truncsp(option[i]);
			if((j=strlen(option[i])+5)>width)
419
				width=j;
420
421
		}
	}
422
423
	if(width>(s_right+1)-s_left) {
		width=(s_right+1)-s_left;
424
425
426
427
428
429
		if(strlen(title)>(width-4)) {
			*(title+width-7)='.';
			*(title+width-6)='.';
			*(title+width-5)='.';
			*(title+width-4)=0;
		}
430
	}
431
	if(mode&WIN_L2R)
deuce's avatar
deuce committed
432
		left=(s_right-s_left-width+1)/2;
433
	else if(mode&WIN_RHT)
deuce's avatar
deuce committed
434
		left=s_right-(width+4+left);
435
	if(mode&WIN_T2B)
deuce's avatar
deuce committed
436
		top=(api->scrn_len-height+1)/2-2;
437
	else if(mode&WIN_BOT)
438
		top=s_bottom-height-top;
439
440
	if(left<0)
		left=0;
441
442
	if(top<0)
		top=0;
443
444
445

	/* Dynamic Menus */
	if(mode&WIN_DYN
446
447
448
			&& cur != NULL
			&& bar != NULL
			&& last_menu_cur==cur
449
450
451
452
			&& last_menu_bar==bar
			&& save_menu_cur==*cur
			&& save_menu_bar==*bar)
		is_redraw=1;
453
454
455
456
	if(mode&WIN_DYN && mode&WIN_REDRAW)
		is_redraw=1;
	if(mode&WIN_DYN && mode&WIN_NODRAW)
		is_redraw=0;
457
458
459
460
461
462

	if(!is_redraw) {
		if(mode&WIN_SAV && api->savdepth==api->savnum) {
			if((sav[api->savnum].buf=(char *)MALLOC((width+3)*(height+2)*2))==NULL) {
				cprintf("UIFC line %d: error allocating %u bytes."
					,__LINE__,(width+3)*(height+2)*2);
463
				return(-1);
464
			}
465
466
467
468
469
470
			gettext(s_left+left,s_top+top,s_left+left+width+1
				,s_top+top+height,sav[api->savnum].buf);
			sav[api->savnum].left=s_left+left;
			sav[api->savnum].top=s_top+top;
			sav[api->savnum].right=s_left+left+width+1;
			sav[api->savnum].bot=s_top+top+height;
471
			api->savdepth++;
472
473
		}
		else if(mode&WIN_SAV
474
475
476
477
			&& (sav[api->savnum].left!=s_left+left
			|| sav[api->savnum].top!=s_top+top
			|| sav[api->savnum].right!=s_left+left+width+1
			|| sav[api->savnum].bot!=s_top+top+height)) { /* dimensions have changed */
478
479
480
481
482
483
			puttext(sav[api->savnum].left,sav[api->savnum].top,sav[api->savnum].right,sav[api->savnum].bot
				,sav[api->savnum].buf);	/* put original window back */
			FREE(sav[api->savnum].buf);
			if((sav[api->savnum].buf=(char *)MALLOC((width+3)*(height+2)*2))==NULL) {
				cprintf("UIFC line %d: error allocating %u bytes."
					,__LINE__,(width+3)*(height+2)*2);
484
				return(-1);
485
			}
486
487
488
489
490
491
			gettext(s_left+left,s_top+top,s_left+left+width+1
				,s_top+top+height,sav[api->savnum].buf);	  /* save again */
			sav[api->savnum].left=s_left+left;
			sav[api->savnum].top=s_top+top;
			sav[api->savnum].right=s_left+left+width+1;
			sav[api->savnum].bot=s_top+top+height;
492
		}
493
494
495
496
497
	}

	if(!is_redraw) {
		if(mode&WIN_ORG) { /* Clear around menu */
			if(top)
498
				puttext(1,2,api->scrn_width,s_top+top-1,blk_scrn);
499
			if(s_top+height+top<=api->scrn_len)
deuce's avatar
deuce committed
500
				puttext(1,s_top+height+top,api->scrn_width,api->scrn_len,blk_scrn);
501
			if(left)
deuce's avatar
deuce committed
502
				puttext(1,s_top+top,s_left+left-1,s_top+height+top
503
					,blk_scrn);
504
			if(s_left+left+width<=s_right)
deuce's avatar
deuce committed
505
				puttext(s_left+left+width,s_top+top,/* s_right+2 */api->scrn_width
506
					,s_top+height+top,blk_scrn);
507
		}
deuce's avatar
deuce committed
508
		ptr=tmp_buffer;
509
510
511
512
513
514
		*(ptr++)='';
		*(ptr++)=hclr|(bclr<<4);

		i=0;
		for(;i<width-2;i++) {
			*(ptr++)='';
515
			*(ptr++)=hclr|(bclr<<4);
516
517
518
519
520
521
522
523
524
		}
		*(ptr++)='';
		*(ptr++)=hclr|(bclr<<4);
		*(ptr++)='';
		*(ptr++)=hclr|(bclr<<4);
		a=strlen(title);
		b=(width-a-1)/2;
		for(i=0;i<b;i++) {
			*(ptr++)=' ';
525
			*(ptr++)=hclr|(bclr<<4);
526
527
528
		}
		for(i=0;i<a;i++) {
			*(ptr++)=title[i];
529
			*(ptr++)=hclr|(bclr<<4);
530
531
532
		}
		for(i=0;i<width-(a+b)-2;i++) {
			*(ptr++)=' ';
533
			*(ptr++)=hclr|(bclr<<4);
534
535
536
537
538
539
540
		}
		*(ptr++)='';
		*(ptr++)=hclr|(bclr<<4);
		*(ptr++)='';
		*(ptr++)=hclr|(bclr<<4);
		for(i=0;i<width-2;i++) {
			*(ptr++)='';
541
			*(ptr++)=hclr|(bclr<<4);
542
543
544
545
546
547
548
549
550
551
		}
		*(ptr++)='';
		*(ptr++)=hclr|(bclr<<4);

		if((*cur)>=opts)
			(*cur)=opts-1;			/* returned after scrolled */

		if(!bar) {
			if((*cur)>height-5)
				(*cur)=height-5;
552
			i=0;
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
		}
		else {
			if((*bar)>=opts)
				(*bar)=opts-1;
			if((*bar)>height-5)
				(*bar)=height-5;
			if((*cur)==opts-1)
				(*bar)=height-5;
			if((*bar)<0)
				(*bar)=0;
			if((*cur)<(*bar))
				(*cur)=(*bar);
			i=(*cur)-(*bar);
			if(i+(height-5)>=opts) {
				i=opts-(height-4);
				(*cur)=i+(*bar);
				}
			}
			if((*cur)<0)
				(*cur)=0;

			j=0;
			if(i<0) i=0;
			longopt=0;
			while(j<height-4 && i<opts) {
				*(ptr++)='';
				*(ptr++)=hclr|(bclr<<4);
				*(ptr++)=' ';
				*(ptr++)=hclr|(bclr<<4);
				*(ptr++)='';
				*(ptr++)=lclr|(bclr<<4);
				if(i==(*cur))
585
					a=lbclr;
586
587
588
589
590
591
592
593
594
595
596
597
598
599
				else
					a=lclr|(bclr<<4);
				b=strlen(option[i]);
				if(b>longopt)
					longopt=b;
				if(b+4>width)
					b=width-4;
				for(c=0;c<b;c++) {
					*(ptr++)=option[i][c];
					*(ptr++)=a; 
				}
				while(c<width-4) {
					*(ptr++)=' ';
					*(ptr++)=a;
600
					c++;
601
602
603
604
605
606
607
608
609
610
611
612
613
				}
				*(ptr++)='';
				*(ptr++)=hclr|(bclr<<4);
				i++;
				j++; 
			}
			*(ptr++)='';
			*(ptr++)=hclr|(bclr<<4);
			for(i=0;i<width-2;i++) {
				*(ptr++)='';
				*(ptr++)=hclr|(bclr<<4); 
			}
			*(ptr++)='';
deuce's avatar
deuce committed
614
			*(ptr)=hclr|(bclr<<4);	/* Not incremented to shut ot BCC */
615
			puttext(s_left+left,s_top+top,s_left+left+width-1
deuce's avatar
deuce committed
616
				,s_top+top+height-1,tmp_buffer);
617
618
619
620
621
622
			if(bar)
				y=top+3+(*bar);
			else
				y=top+3+(*cur);
			if(opts+4>height && ((!bar && (*cur)!=opts-1)
				|| (bar && ((*cur)-(*bar))+(height-4)<opts))) {
623
				gotoxy(s_left+left+1,s_top+top+height-2);
624
625
626
627
628
629
				textattr(lclr|(bclr<<4));
				putch(31);	   /* put down arrow */
				textattr(hclr|(bclr<<4)); 
			}

			if(bar && (*bar)!=(*cur)) {
630
				gotoxy(s_left+left+1,s_top+top+3);
631
632
633
634
635
636
				textattr(lclr|(bclr<<4));
				putch(30);	   /* put the up arrow */
				textattr(hclr|(bclr<<4)); 
			}

			if(bclr==BLUE) {
637
638
				gettext(s_left+left+width,s_top+top+1,s_left+left+width+1
					,s_top+top+height-1,shade);
639
640
				for(i=1;i<height*4;i+=2)
					shade[i]=DARKGRAY;
641
642
643
644
				puttext(s_left+left+width,s_top+top+1,s_left+left+width+1
					,s_top+top+height-1,shade);
				gettext(s_left+left+2,s_top+top+height,s_left+left+width+1
					,s_top+top+height,shade);
645
646
				for(i=1;i<width*2;i+=2)
					shade[i]=DARKGRAY;
647
648
				puttext(s_left+left+2,s_top+top+height,s_left+left+width+1
					,s_top+top+height,shade);
649
650
651
652
653
654
655
656
			}
	}
	else {	/* Is a redraw */
		i=(*cur)-(*bar);
		j=2;

		longopt=0;
		while(j<height-2 && i<opts) {
deuce's avatar
deuce committed
657
			ptr=tmp_buffer;
658
			if(i==(*cur))
659
				a=lbclr;
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
			else
				a=lclr|(bclr<<4);
			b=strlen(option[i]);
			if(b>longopt)
				longopt=b;
			if(b+4>width)
				b=width-4;
			for(c=0;c<b;c++) {
				*(ptr++)=option[i][c];
				*(ptr++)=a; 
			}
			while(c<width-4) {
				*(ptr++)=' ';
				*(ptr++)=a;
				c++; 
			}
			i++;
			j++; 
678
			puttext(s_left+left+3,s_top+top+j,s_left+left+width-2
deuce's avatar
deuce committed
679
				,s_top+top+j,tmp_buffer); 
680
681
682
683
684
685
686
687
688
		}
		if(bar)
			y=top+3+(*bar);
		else
			y=top+3+(*cur);
	}

	last_menu_cur=cur;
	last_menu_bar=bar;
689
690
	if(mode&WIN_IMM)
		return(-2);
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
	while(1) {
	#if 0					/* debug */
		gotoxy(30,1);
		cprintf("y=%2d h=%2d c=%2d b=%2d s=%2d o=%2d"
			,y,height,*cur,bar ? *bar :0xff,api->savdepth,opts);
	#endif
		timedisplay();
		i=0;
		if(inkey(1)) {
			i=inkey(0);
			if(i==KEY_BACKSPACE || i==BS)
				i=ESC;
			if(i>255) {
				s=0;
				switch(i) {
					/* ToDo extended keys */
					case KEY_HOME:	/* home */
						if(!opts)
							break;
						if(opts+4>height) {
711
							gotoxy(s_left+left+1,s_top+top+3);
712
713
							textattr(lclr|(bclr<<4));
							putch(' ');    /* Delete the up arrow */
714
							gotoxy(s_left+left+1,s_top+top+height-2);
715
							putch(31);	   /* put the down arrow */
716
							uprintf(s_left+left+3,s_top+top+3
717
								,lbclr
718
719
								,"%-*.*s",width-4,width-4,option[0]);
							for(i=1;i<height-4;i++)    /* re-display options */
720
								uprintf(s_left+left+3,s_top+top+3+i
721
722
723
724
725
726
727
728
									,lclr|(bclr<<4)
									,"%-*.*s",width-4,width-4,option[i]);
							(*cur)=0;
							if(bar)
								(*bar)=0;
							y=top+3;
							break; 
						}
729
730
						gettext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
731
732
						for(i=1;i<width*2;i+=2)
							line[i]=lclr|(bclr<<4);
733
734
						puttext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
735
736
737
738
						(*cur)=0;
						if(bar)
							(*bar)=0;
						y=top+3;
739
740
						gettext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
741
						for(i=1;i<width*2;i+=2)
742
							line[i]=lbclr;
743
744
						puttext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
745
746
747
748
749
						break;
					case KEY_UP:	/* up arrow */
						if(!opts)
							break;
						if(!(*cur) && opts+4>height) {
750
							gotoxy(s_left+left+1,s_top+top+3); /* like end */
751
752
							textattr(lclr|(bclr<<4));
							putch(30);	   /* put the up arrow */
753
							gotoxy(s_left+left+1,s_top+top+height-2);
754
755
							putch(' ');    /* delete the down arrow */
							for(i=(opts+4)-height,j=0;i<opts;i++,j++)
756
								uprintf(s_left+left+3,s_top+top+3+j
757
									,i==opts-1 ? lbclr
758
759
760
761
762
763
764
765
										: lclr|(bclr<<4)
									,"%-*.*s",width-4,width-4,option[i]);
							(*cur)=opts-1;
							if(bar)
								(*bar)=height-5;
							y=top+height-2;
							break; 
						}
766
767
						gettext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
768
769
						for(i=1;i<width*2;i+=2)
							line[i]=lclr|(bclr<<4);
770
771
						puttext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
772
773
774
775
776
777
778
779
780
781
782
783
784
785
						if(!(*cur)) {
							y=top+height-2;
							(*cur)=opts-1;
							if(bar)
								(*bar)=height-5; 
						}
						else {
							(*cur)--;
							y--;
							if(bar && *bar)
								(*bar)--; 
						}
						if(y<top+3) {	/* scroll */
							if(!(*cur)) {
786
								gotoxy(s_left+left+1,s_top+top+3);
787
788
789
790
								textattr(lclr|(bclr<<4));
								putch(' '); /* delete the up arrow */
							}  
							if((*cur)+height-4==opts-1) {
791
								gotoxy(s_left+left+1,s_top+top+height-2);
792
793
794
795
								textattr(lclr|(bclr<<4));
								putch(31);	/* put the dn arrow */
							}
							y++;
796
797
798
							scroll_text(s_left+left+2,s_top+top+3
								,s_left+left+width-3,s_top+top+height-2,1);
							uprintf(s_left+left+3,s_top+top+3
799
								,lbclr
800
801
802
								,"%-*.*s",width-4,width-4,option[*cur]);
						}
						else {
803
804
							gettext(s_left+3+left,s_top+y
								,s_left+left+width-2,s_top+y,line);
805
							for(i=1;i<width*2;i+=2)
806
								line[i]=lbclr;
807
808
							puttext(s_left+3+left,s_top+y
								,s_left+left+width-2,s_top+y,line);
809
810
811
812
813
814
815
816
817
818
819
						}
						break;
#if 0
					case KEY_PPAGE;	/* PgUp */
					case KEY_NPAGE;	/* PgDn */
						if(!opts || (*cur)==(opts-1))
							break;
						(*cur)+=(height-4);
						if((*cur)>(opts-1))
							(*cur)=(opts-1);

820
821
						gettext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
822
823
						for(i=1;i<width*2;i+=2)
							line[i]=lclr|(bclr<<4);
824
825
						puttext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
826
827

						for(i=(opts+4)-height,j=0;i<opts;i++,j++)
828
							uprintf(s_left+left+3,s_top+top+3+j
829
								,i==(*cur) lbclr : lclr|(bclr<<4)
830
831
832
833
								,"%-*.*s",width-4,width-4,option[i]);
						y=top+height-2;
						if(bar)
							(*bar)=height-5;
834
835
						gettext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
836
						for(i=1;i<148;i+=2)
837
							line[i]=lbclr;
838
839
						puttext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
840
841
842
843
844
845
						break;
#endif
					case KEY_END:	/* end */
						if(!opts)
							break;
						if(opts+4>height) {	/* Scroll mode */
846
							gotoxy(s_left+left+1,s_top+top+3);
847
848
							textattr(lclr|(bclr<<4));
							putch(30);	   /* put the up arrow */
849
							gotoxy(s_left+left+1,s_top+top+height-2);
850
851
							putch(' ');    /* delete the down arrow */
							for(i=(opts+4)-height,j=0;i<opts;i++,j++)
852
								uprintf(s_left+left+3,s_top+top+3+j
853
									,i==opts-1 ? lbclr
854
855
856
857
858
859
860
861
										: lclr|(bclr<<4)
									,"%-*.*s",width-4,width-4,option[i]);
							(*cur)=opts-1;
							y=top+height-2;
							if(bar)
								(*bar)=height-5;
							break; 
						}
862
863
						gettext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
864
865
						for(i=1;i<width*2;i+=2)
							line[i]=lclr|(bclr<<4);
866
867
						puttext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
868
869
870
871
						(*cur)=opts-1;
						y=top+height-2;
						if(bar)
							(*bar)=height-5;
872
873
						gettext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
874
						for(i=1;i<148;i+=2)
875
							line[i]=lbclr;
876
877
						puttext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
878
879
880
881
882
						break;
					case KEY_DOWN:	/* dn arrow */
						if(!opts)
							break;
						if((*cur)==opts-1 && opts+4>height) { /* like home */
883
							gotoxy(s_left+left+1,s_top+top+3);
884
885
							textattr(lclr|(bclr<<4));
							putch(' ');    /* Delete the up arrow */
886
							gotoxy(s_left+left+1,s_top+top+height-2);
887
							putch(31);	   /* put the down arrow */
888
							uprintf(s_left+left+3,s_top+top+3
889
								,lbclr
890
891
								,"%-*.*s",width-4,width-4,option[0]);
							for(i=1;i<height-4;i++)    /* re-display options */
892
								uprintf(s_left+left+3,s_top+top+3+i
893
894
895
896
897
898
899
900
									,lclr|(bclr<<4)
									,"%-*.*s",width-4,width-4,option[i]);
							(*cur)=0;
							y=top+3;
							if(bar)
								(*bar)=0;
							break; 
						}
901
902
						gettext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
903
904
						for(i=1;i<width*2;i+=2)
							line[i]=lclr|(bclr<<4);
905
906
						puttext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
						if((*cur)==opts-1) {
							(*cur)=0;
							y=top+3;
							if(bar) {
								/* gotoxy(1,1); cprintf("bar=%08lX ",bar); */
								(*bar)=0; 
							} 
						}
						else {
							(*cur)++;
							y++;
							if(bar && (*bar)<height-5) {
								/* gotoxy(1,1); cprintf("bar=%08lX ",bar); */
								(*bar)++; 
							} 
						}
						if(y==top+height-1) {	/* scroll */
							if(*cur==opts-1) {
925
								gotoxy(s_left+left+1,s_top+top+height-2);
926
927
928
929
								textattr(lclr|(bclr<<4));
								putch(' ');	/* delete the down arrow */
							}
							if((*cur)+4==height) {
930
								gotoxy(s_left+left+1,s_top+top+3);
931
932
933
934
935
								textattr(lclr|(bclr<<4));
								putch(30);	/* put the up arrow */
							}
							y--;
							/* gotoxy(1,1); cprintf("\rdebug: %4d ",__LINE__); */
936
937
							scroll_text(s_left+left+2,s_top+top+3
								,s_left+left+width-3,s_top+top+height-2,0);
938
							/* gotoxy(1,1); cprintf("\rdebug: %4d ",__LINE__); */
939
							uprintf(s_left+left+3,s_top+top+height-2
940
								,lbclr
941
942
943
								,"%-*.*s",width-4,width-4,option[*cur]);
						}
						else {
944
945
							gettext(s_left+3+left,s_top+y
								,s_left+left+width-2,s_top+y
946
947
								,line);
							for(i=1;i<width*2;i+=2)
948
								line[i]=lbclr;
949
950
							puttext(s_left+3+left,s_top+y
								,s_left+left+width-2,s_top+y
951
952
953
954
955
956
957
								,line);
						}
						break;
					case KEY_F(1):	/* F1 */
						help();
						break;
					case KEY_F(5):	/* F5 */
deuce's avatar
deuce committed
958
						if(mode&WIN_GET && !(mode&WIN_XTR && (*cur)==opts-1))
959
							return((*cur)|MSK_GET);
960
961
						break;
					case KEY_F(6):	/* F6 */
deuce's avatar
deuce committed
962
						if(mode&WIN_PUT && !(mode&WIN_XTR && (*cur)==opts-1))
963
							return((*cur)|MSK_PUT);
964
965
966
967
						break;
					case KEY_IC:	/* insert */
						if(mode&WIN_INS) {
							if(mode&WIN_INSACT) {
968
								gettext(s_left+left,s_top+top,s_left
deuce's avatar
deuce committed
969
									+left+width-1,s_top+top+height-1,tmp_buffer);
970
								for(i=1;i<(width*height*2);i+=2)
deuce's avatar
deuce committed
971
									tmp_buffer[i]=lclr|(cclr<<4);
972
973
974
								if(opts) {
									j=(((y-top)*width)*2)+7+((width-4)*2);
									for(i=(((y-top)*width)*2)+7;i<j;i+=2)
deuce's avatar
deuce committed
975
										tmp_buffer[i]=hclr|(cclr<<4); 
976
								}
977
								puttext(s_left+left,s_top+top,s_left
deuce's avatar
deuce committed
978
									+left+width-1,s_top+top+height-1,tmp_buffer);
979
980
981
982
983
984
985
986
987
988
989
990
							}
							if(!opts) {
								return(MSK_INS); 
							}
							return((*cur)|MSK_INS); 
						}
						break;
					case KEY_DC:	/* delete */
						if(mode&WIN_XTR && (*cur)==opts-1)	/* can't delete */
							break;							/* extra line */
						if(mode&WIN_DEL) {
							if(mode&WIN_DELACT) {
991
								gettext(s_left+left,s_top+top,s_left
deuce's avatar
deuce committed
992
									+left+width-1,s_top+top+height-1,tmp_buffer);
993
								for(i=1;i<(width*height*2);i+=2)
deuce's avatar
deuce committed
994
									tmp_buffer[i]=lclr|(cclr<<4);
995
996
								j=(((y-top)*width)*2)+7+((width-4)*2);
								for(i=(((y-top)*width)*2)+7;i<j;i+=2)
deuce's avatar
deuce committed
997
									tmp_buffer[i]=hclr|(cclr<<4);
998
								puttext(s_left+left,s_top+top,s_left
deuce's avatar
deuce committed
999
									+left+width-1,s_top+top+height-1,tmp_buffer);
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
							}
							return((*cur)|MSK_DEL); 
						}
						break;
				} 
			}
			else {
				i&=0xff;
				if(isalnum(i) && opts && option[0][0]) {
					search[s]=i;
					search[s+1]=0;
					for(j=(*cur)+1,a=b=0;a<2;j++) {   /* a = search count */
						if(j==opts) {					/* j = option count */
							j=-1;						/* b = letter count */
							continue; 
						}
						if(j==(*cur)) {
							b++;
							continue; 
						}
						if(b>=longopt) {
							b=0;
							a++; 
						}
						if(a==1 && !s)
							break;
						if(strlen(option[j])>b
1027
							&& ((!a && s && !strnicmp(option[j]+b,search,s+1))
1028
1029
1030
1031
1032
							|| ((a || !s) && toupper(option[j][b])==toupper(i)))) {
							if(a) s=0;
							else s++;
							if(y+(j-(*cur))+2>height+top) {
								(*cur)=j;
1033
								gotoxy(s_left+left+1,s_top+top+3);
1034
1035
1036
								textattr(lclr|(bclr<<4));
								putch(30);	   /* put the up arrow */
								if((*cur)==opts-1) {
1037
									gotoxy(s_left+left+1,s_top+top+height-2);
1038
1039
1040
									putch(' ');	/* delete the down arrow */
								}
								for(i=((*cur)+5)-height,j=0;i<(*cur)+1;i++,j++)
1041
									uprintf(s_left+left+3,s_top+top+3+j
1042
										,i==(*cur) ? lbclr
1043
1044
1045
1046
1047
1048
1049
1050
1051
											: lclr|(bclr<<4)
										,"%-*.*s",width-4,width-4,option[i]);
								y=top+height-2;
								if(bar)
									(*bar)=height-5;
								break; 
							}
							if(y-((*cur)-j)<top+3) {
								(*cur)=j;
1052
								gotoxy(s_left+left+1,s_top+top+3);
1053
1054
1055
								textattr(lclr|(bclr<<4));
								if(!(*cur))
									putch(' ');    /* Delete the up arrow */
1056
								gotoxy(s_left+left+1,s_top+top+height-2);
1057
								putch(31);	   /* put the down arrow */
1058
								uprintf(s_left+left+3,s_top+top+3
1059
									,lbclr
1060
1061
									,"%-*.*s",width-4,width-4,option[(*cur)]);
								for(i=1;i<height-4;i++) 	/* re-display options */
1062
									uprintf(s_left+left+3,s_top+top+3+i
1063
1064
1065
1066
1067
1068
1069
1070
										,lclr|(bclr<<4)
										,"%-*.*s",width-4,width-4
										,option[(*cur)+i]);
								y=top+3;
								if(bar)
									(*bar)=0;
								break; 
							}
1071
1072
							gettext(s_left+3+left,s_top+y
								,s_left+left+width-2,s_top+y,line);
1073
1074
							for(i=1;i<width*2;i+=2)
								line[i]=lclr|(bclr<<4);
1075
1076
							puttext(s_left+3+left,s_top+y
								,s_left+left+width-2,s_top+y,line);
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
							if((*cur)>j)
								y-=(*cur)-j;
							else
								y+=j-(*cur);
							if(bar) {
								if((*cur)>j)
									(*bar)-=(*cur)-j;
								else
									(*bar)+=j-(*cur); 
							}
							(*cur)=j;
1088
1089
							gettext(s_left+3+left,s_top+y
								,s_left+left+width-2,s_top+y,line);
1090
							for(i=1;i<width*2;i+=2)
1091
								line[i]=lbclr;
1092
1093
							puttext(s_left+3+left,s_top+y
								,s_left+left+width-2,s_top+y,line);
1094
1095
1096
1097
							break; 
						} 
					}
					if(a==2)
1098
						s=0;
1099
1100
1101
1102
1103
1104
1105
				}
				else
					switch(i) {
						case CR:
							if(!opts || (mode&WIN_XTR && (*cur)==opts-1))
								break;
							if(mode&WIN_ACT) {
1106
								gettext(s_left+left,s_top+top,s_left
deuce's avatar
deuce committed
1107
									+left+width-1,s_top+top+height-1,tmp_buffer);
1108
								for(i=1;i<(width*height*2);i+=2)
deuce's avatar
deuce committed
1109
									tmp_buffer[i]=lclr|(cclr<<4);
1110
1111
								j=(((y-top)*width)*2)+7+((width-4)*2);
								for(i=(((y-top)*width)*2)+7;i<j;i+=2)
deuce's avatar
deuce committed
1112
									tmp_buffer[i]=hclr|(cclr<<4);
1113

1114
								puttext(s_left+left,s_top+top,s_left
deuce's avatar
deuce committed
1115
									+left+width-1,s_top+top+height-1,tmp_buffer);
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
							}
							else if(mode&WIN_SAV) {
								puttext(sav[api->savnum].left,sav[api->savnum].top
									,sav[api->savnum].right,sav[api->savnum].bot
									,sav[api->savnum].buf);
								FREE(sav[api->savnum].buf);
								api->savdepth--; 
							}
							return(*cur);
						case 3:
						case ESC:
							if((mode&WIN_ESC || (mode&WIN_CHE && api->changes))
								&& !(mode&WIN_SAV)) {
1129
								gettext(s_left+left,s_top+top,s_left
deuce's avatar
deuce committed
1130
									+left+width-1,s_top+top+height-1,tmp_buffer);
1131
								for(i=1;i<(width*height*2);i+=2)
deuce's avatar
deuce committed
1132
									tmp_buffer[i]=lclr|(cclr<<4);
1133
								puttext(s_left+left,s_top+top,s_left
deuce's avatar
deuce committed
1134
									+left+width-1,s_top+top+height-1,tmp_buffer);
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
							}
							else if(mode&WIN_SAV) {
								puttext(sav[api->savnum].left,sav[api->savnum].top
									,sav[api->savnum].right,sav[api->savnum].bot
									,sav[api->savnum].buf);
								FREE(sav[api->savnum].buf);
								api->savdepth--; 
							}
							return(-1);
				} 
			} 
		}
		else
			mswait(1);
		if(mode&WIN_DYN) {
			save_menu_cur=*cur;
			save_menu_bar=*bar;
			return(-2-i);
		}
	}
}


/*************************************************************************/
/* This function is a windowed input string input routine.               */
/*************************************************************************/
int uinput(int mode, int left, int top, char *prompt, char *str,
	int max, int kmode)
{
	unsigned char c,save_buf[2048],in_win[2048]
		,shade[160],width,height=3;
	int i,plen,slen;

	reset_dynamic();
	plen=strlen(prompt);
	if(!plen)
		slen=4;
	else
		slen=6;
	width=plen+slen+max;
1175
1176
	if(width>api->scrn_width-6)
		width=api->scrn_width-6;
1177
	if(mode&WIN_T2B)
deuce's avatar
deuce committed
1178
		top=(api->scrn_len-height+1)/2-2;
1179
	if(mode&WIN_L2R)
1180
1181
1182
		left=(SCRN_RIGHT-SCRN_LEFT-width+2)/2;
	if(left<=-(SCRN_LEFT))
		left=-(SCRN_LEFT)+1;
1183
1184
	if(top<0)
		top=0;
1185
1186
1187
	if(mode&WIN_SAV)
		gettext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT+left+width+1
			,SCRN_TOP+top+height,save_buf);
1188
	max=width-plen-slen;
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
	i=0;
	in_win[i++]='';
	in_win[i++]=hclr|(bclr<<4);
	for(c=1;c<width-1;c++) {
		in_win[i++]='';
		in_win[i++]=hclr|(bclr<<4); 
	}
	in_win[i++]='';
	in_win[i++]=hclr|(bclr<<4);
	in_win[i++]='';
	in_win[i++]=hclr|(bclr<<4);

	if(plen) {
		in_win[i++]=SP;
		in_win[i++]=lclr|(bclr<<4); 
	}

	for(c=0;prompt[c];c++) {
		in_win[i++]=prompt[c