uifc32.c 50.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)
deuce's avatar
deuce committed
46
47
48
49
50
51
	#if defined(putch) && defined(NO_ECHOCHAR)
		#undef putch
	#endif
	#if !defined(putch)
    	#define putch(x)	_putch(x,TRUE)
	#endif
52
    #define clreol()	clrtoeol()
53
54
55
56
#elif defined(_WIN32)
	#include <share.h>
	#include <conio.h>
	#include <windows.h>
57
	#include "keys.h"
58
59
60
61
	#define mswait(x) Sleep(x)
#endif

#include "uifc.h"
62
#define MAX_GETSTR	5120
63
64
65
66
67
68
69
70
							/* 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 */

#define BLINK	128

71
static char  hclr,lclr,bclr,cclr,lbclr;
72
73
74
static int   cursor;
static char* helpfile=0;
static uint  helpline=0;
deuce's avatar
deuce committed
75
76
77
static size_t blk_scrn_len;
static char* blk_scrn;
static uchar* tmp_buffer;
78
static uchar* tmp_buffer2;
79
80
81
82
83
84
85
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
86
static void  help(void);
87
static int   ugetstr(int left, int top, int width, char *outstr, int max, long mode, int *lastkey);
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
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
121
int kbwait(void) {
122
	int timeout=0;
123
	while(timeout++<50) {
124
		if(kbhit())
125
			return(TRUE);
126
		mswait(1);
127
128
129
130
	}
	return(FALSE);
}

131
132
133
134
int inkey(int mode)
{
	int c;

135
136
137
138
139
140
	if(mode)
		return(kbwait());
	c=getch();
#ifdef _WIN32
	if(!c)
		c=(getch()<<8);
141
#endif
142
143
	return(c);
}
144

145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
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
164
	api->showbuf=showbuf;
165
	api->timedisplay=timedisplay;
166
	api->getstrxy=ugetstr;
167

168
169
170
171
	/* A esc_delay of less than 10 is stupid... silently override */
	if(api->esc_delay < 10)
		api->esc_delay=25;

172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
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
#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
214
/*        || txtinfo.screenheight>MAX_LINES */
215
216
217
218
219
220
221
        || txtinfo.screenwidth<80) {
        textmode(C80);  /* set mode to 80x25*/
        gettextinfo(&txtinfo);
    }
#endif

    api->scrn_len=txtinfo.screenheight;
deuce's avatar
deuce committed
222
223
224
    if(api->scrn_len<MIN_LINES) {
        cprintf("\7UIFC: Screen length (%u) must be %d lines or greater\r\n"
            ,api->scrn_len,MIN_LINES);
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
        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;
243
244
245
246
247
248
#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 */
249
250
251
252
253
    } else {
        bclr=BLUE;
        hclr=YELLOW;
        lclr=WHITE;
        cclr=CYAN;
254
		lbclr=BLUE|(LIGHTGRAY<<4);	/* lightbar color */
255
    }
256

deuce's avatar
deuce committed
257
258
259
260
261
262
263
264
265
266
267
	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);
	}
268
269
270
271
272
	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
273
    for(i=0;i<blk_scrn_len;i+=2) {
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
        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
296
297
	FREE(blk_scrn);
	FREE(tmp_buffer);
298
	FREE(tmp_buffer2);
299
300
301
302
303
304
305
306
307
308
}

/****************************************************************************/
/* Clear screen, fill with background attribute, display application title.	*/
/* Returns 0 on success.													*/
/****************************************************************************/
int uscrn(char *str)
{
    textattr(bclr|(cclr<<4));
    gotoxy(1,1);
309
    clreol();
310
311
312
313
314
    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);
315
    clreol();
316
317
318
319
320
321
322
323
	reset_dynamic();
    return(0);
}

/****************************************************************************/
/****************************************************************************/
static void scroll_text(int x1, int y1, int x2, int y2, int down)
{
324
	gettext(x1,y1,x2,y2,tmp_buffer2);
325
	if(down)
326
		puttext(x1,y1+1,x2,y2,tmp_buffer2);
327
	else
328
		puttext(x1,y1,x2,y2-1,tmp_buffer2+(((x2-x1)+1)*2));
329
330
331
332
333
334
335
336
337
338
339
340
341
}

/****************************************************************************/
/* 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) {
342
		uprintf(api->scrn_width-25,1,bclr|(cclr<<4),utimestr(&now));
343
344
345
346
347
348
349
350
351
352
353
354
		savetime=now; 
	}
}

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

	c=strlen(str);
deuce's avatar
deuce committed
355
	while(c && (uchar)str[c-1]<=' ') c--;
356
357
358
359
360
361
362
363
364
365
	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
366
	uchar line[256],shade[256],*ptr,a,b,c,longopt
367
368
369
370
		,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
371
372
373
374
	uint s_top=SCRN_TOP;
	uint s_left=SCRN_LEFT;
	uint s_right=SCRN_RIGHT;
	uint s_bottom=api->scrn_len-3;
375
376
377

	if(mode&WIN_FAT) {
		s_top=1;
378
		s_left=2;
379
380
		s_right=api->scrn_width-3;  /* Leave space for the shadow */
		s_bottom=api->scrn_len-1;   /* Leave one for the shadow */
381
	}
382
383
384
385
386
387
388
	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
389
	while(opts<MAX_OPTS)
390
391
392
		if(option[opts][0]==0)
			break;
		else opts++;
deuce's avatar
deuce committed
393
	if(mode&WIN_XTR && opts<MAX_OPTS)
394
		opts++;
395
	height=opts+4;
396
397
	if(top+height>s_bottom)
		height=(s_bottom)-top;
398
399
400
401
402
	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)
403
				width=j;
404
405
		}
	}
406
407
	if(width>(s_right+1)-s_left) {
		width=(s_right+1)-s_left;
408
409
410
411
412
413
		if(strlen(title)>(width-4)) {
			*(title+width-7)='.';
			*(title+width-6)='.';
			*(title+width-5)='.';
			*(title+width-4)=0;
		}
414
	}
415
	if(mode&WIN_L2R)
deuce's avatar
deuce committed
416
		left=(s_right-s_left-width+1)/2;
417
	else if(mode&WIN_RHT)
deuce's avatar
deuce committed
418
		left=s_right-(width+4+left);
419
	if(mode&WIN_T2B)
deuce's avatar
deuce committed
420
		top=(api->scrn_len-height+1)/2-2;
421
	else if(mode&WIN_BOT)
422
		top=s_bottom-height-top;
423
424
	if(left<0)
		left=0;
425
426
	if(top<0)
		top=0;
427
428
429

	/* Dynamic Menus */
	if(mode&WIN_DYN
430
431
432
			&& cur != NULL
			&& bar != NULL
			&& last_menu_cur==cur
433
434
435
436
			&& last_menu_bar==bar
			&& save_menu_cur==*cur
			&& save_menu_bar==*bar)
		is_redraw=1;
437
438
439
440
	if(mode&WIN_DYN && mode&WIN_REDRAW)
		is_redraw=1;
	if(mode&WIN_DYN && mode&WIN_NODRAW)
		is_redraw=0;
441
442
443
444
445
446

	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);
447
				return(-1);
448
			}
449
450
451
452
453
454
			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;
455
			api->savdepth++;
456
457
		}
		else if(mode&WIN_SAV
458
459
460
461
			&& (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 */
462
463
464
465
466
467
			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);
468
				return(-1);
469
			}
470
471
472
473
474
475
			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;
476
		}
477
478
479
480
481
	}

	if(!is_redraw) {
		if(mode&WIN_ORG) { /* Clear around menu */
			if(top)
482
				puttext(1,2,api->scrn_width,s_top+top-1,blk_scrn);
483
			if(s_top+height+top<=api->scrn_len)
deuce's avatar
deuce committed
484
				puttext(1,s_top+height+top,api->scrn_width,api->scrn_len,blk_scrn);
485
			if(left)
deuce's avatar
deuce committed
486
				puttext(1,s_top+top,s_left+left-1,s_top+height+top
487
					,blk_scrn);
488
			if(s_left+left+width<=s_right)
deuce's avatar
deuce committed
489
				puttext(s_left+left+width,s_top+top,/* s_right+2 */api->scrn_width
490
					,s_top+height+top,blk_scrn);
491
		}
deuce's avatar
deuce committed
492
		ptr=tmp_buffer;
493
494
495
496
497
498
		*(ptr++)='';
		*(ptr++)=hclr|(bclr<<4);

		i=0;
		for(;i<width-2;i++) {
			*(ptr++)='';
499
			*(ptr++)=hclr|(bclr<<4);
500
501
502
503
504
505
506
507
508
		}
		*(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++)=' ';
509
			*(ptr++)=hclr|(bclr<<4);
510
511
512
		}
		for(i=0;i<a;i++) {
			*(ptr++)=title[i];
513
			*(ptr++)=hclr|(bclr<<4);
514
515
516
		}
		for(i=0;i<width-(a+b)-2;i++) {
			*(ptr++)=' ';
517
			*(ptr++)=hclr|(bclr<<4);
518
519
520
521
522
523
524
		}
		*(ptr++)='';
		*(ptr++)=hclr|(bclr<<4);
		*(ptr++)='';
		*(ptr++)=hclr|(bclr<<4);
		for(i=0;i<width-2;i++) {
			*(ptr++)='';
525
			*(ptr++)=hclr|(bclr<<4);
526
527
528
529
530
531
532
533
534
535
		}
		*(ptr++)='';
		*(ptr++)=hclr|(bclr<<4);

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

		if(!bar) {
			if((*cur)>height-5)
				(*cur)=height-5;
536
			i=0;
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
		}
		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))
569
					a=lbclr;
570
571
572
573
574
575
576
577
578
579
580
581
582
583
				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;
584
					c++;
585
586
587
588
589
590
591
592
593
594
595
596
597
				}
				*(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
598
			*(ptr)=hclr|(bclr<<4);	/* Not incremented to shut ot BCC */
599
			puttext(s_left+left,s_top+top,s_left+left+width-1
deuce's avatar
deuce committed
600
				,s_top+top+height-1,tmp_buffer);
601
602
603
604
605
606
			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))) {
607
				gotoxy(s_left+left+1,s_top+top+height-2);
608
609
610
611
612
613
				textattr(lclr|(bclr<<4));
				putch(31);	   /* put down arrow */
				textattr(hclr|(bclr<<4)); 
			}

			if(bar && (*bar)!=(*cur)) {
614
				gotoxy(s_left+left+1,s_top+top+3);
615
616
617
618
619
620
				textattr(lclr|(bclr<<4));
				putch(30);	   /* put the up arrow */
				textattr(hclr|(bclr<<4)); 
			}

			if(bclr==BLUE) {
621
622
				gettext(s_left+left+width,s_top+top+1,s_left+left+width+1
					,s_top+top+height-1,shade);
623
624
				for(i=1;i<height*4;i+=2)
					shade[i]=DARKGRAY;
625
626
627
628
				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);
629
630
				for(i=1;i<width*2;i+=2)
					shade[i]=DARKGRAY;
631
632
				puttext(s_left+left+2,s_top+top+height,s_left+left+width+1
					,s_top+top+height,shade);
633
634
635
636
637
638
639
640
			}
	}
	else {	/* Is a redraw */
		i=(*cur)-(*bar);
		j=2;

		longopt=0;
		while(j<height-2 && i<opts) {
deuce's avatar
deuce committed
641
			ptr=tmp_buffer;
642
			if(i==(*cur))
643
				a=lbclr;
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
			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++; 
662
			puttext(s_left+left+3,s_top+top+j,s_left+left+width-2
deuce's avatar
deuce committed
663
				,s_top+top+j,tmp_buffer); 
664
665
666
667
668
669
670
671
672
		}
		if(bar)
			y=top+3+(*bar);
		else
			y=top+3+(*cur);
	}

	last_menu_cur=cur;
	last_menu_bar=bar;
673
674
	if(mode&WIN_IMM)
		return(-2);
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
	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) {
695
							gotoxy(s_left+left+1,s_top+top+3);
696
697
							textattr(lclr|(bclr<<4));
							putch(' ');    /* Delete the up arrow */
698
							gotoxy(s_left+left+1,s_top+top+height-2);
699
							putch(31);	   /* put the down arrow */
700
							uprintf(s_left+left+3,s_top+top+3
701
								,lbclr
702
703
								,"%-*.*s",width-4,width-4,option[0]);
							for(i=1;i<height-4;i++)    /* re-display options */
704
								uprintf(s_left+left+3,s_top+top+3+i
705
706
707
708
709
710
711
712
									,lclr|(bclr<<4)
									,"%-*.*s",width-4,width-4,option[i]);
							(*cur)=0;
							if(bar)
								(*bar)=0;
							y=top+3;
							break; 
						}
713
714
						gettext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
715
716
						for(i=1;i<width*2;i+=2)
							line[i]=lclr|(bclr<<4);
717
718
						puttext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
719
720
721
722
						(*cur)=0;
						if(bar)
							(*bar)=0;
						y=top+3;
723
724
						gettext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
725
						for(i=1;i<width*2;i+=2)
726
							line[i]=lbclr;
727
728
						puttext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
729
730
731
732
733
						break;
					case KEY_UP:	/* up arrow */
						if(!opts)
							break;
						if(!(*cur) && opts+4>height) {
734
							gotoxy(s_left+left+1,s_top+top+3); /* like end */
735
736
							textattr(lclr|(bclr<<4));
							putch(30);	   /* put the up arrow */
737
							gotoxy(s_left+left+1,s_top+top+height-2);
738
739
							putch(' ');    /* delete the down arrow */
							for(i=(opts+4)-height,j=0;i<opts;i++,j++)
740
								uprintf(s_left+left+3,s_top+top+3+j
741
									,i==opts-1 ? lbclr
742
743
744
745
746
747
748
749
										: lclr|(bclr<<4)
									,"%-*.*s",width-4,width-4,option[i]);
							(*cur)=opts-1;
							if(bar)
								(*bar)=height-5;
							y=top+height-2;
							break; 
						}
750
751
						gettext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
752
753
						for(i=1;i<width*2;i+=2)
							line[i]=lclr|(bclr<<4);
754
755
						puttext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
756
757
758
759
760
761
762
763
764
765
766
767
768
769
						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)) {
770
								gotoxy(s_left+left+1,s_top+top+3);
771
772
773
774
								textattr(lclr|(bclr<<4));
								putch(' '); /* delete the up arrow */
							}  
							if((*cur)+height-4==opts-1) {
775
								gotoxy(s_left+left+1,s_top+top+height-2);
776
777
778
779
								textattr(lclr|(bclr<<4));
								putch(31);	/* put the dn arrow */
							}
							y++;
780
781
782
							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
783
								,lbclr
784
785
786
								,"%-*.*s",width-4,width-4,option[*cur]);
						}
						else {
787
788
							gettext(s_left+3+left,s_top+y
								,s_left+left+width-2,s_top+y,line);
789
							for(i=1;i<width*2;i+=2)
790
								line[i]=lbclr;
791
792
							puttext(s_left+3+left,s_top+y
								,s_left+left+width-2,s_top+y,line);
793
794
						}
						break;
deuce's avatar
deuce committed
795
796
					case KEY_PPAGE:	/* PgUp */
						if(!opts)
797
							break;
deuce's avatar
deuce committed
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
						*cur -= (height-5);
						if(*cur<0)
							*cur = 0;
						if(bar)
							*bar=0;
						y=s_top+top;
						gotoxy(s_left+left+1,s_top+top+3);
						textattr(lclr|(bclr<<4));
						if(*cur && opts>height-3)  /* Scroll mode */
							putch(30);	   /* put the up arrow */
						else
							putch(' ');    /* delete the up arrow */
						gotoxy(s_left+left+1,s_top+top+height-2);
						if(opts > height-3 && *cur + height - 4 < opts)
							putch(31);	   /* put the down arrow */
						else
							putch(' ');    /* delete the down arrow */
						for(i=*cur,j=0;i<=*cur-5+height;i++,j++)
816
							uprintf(s_left+left+3,s_top+top+3+j
deuce's avatar
deuce committed
817
818
								,i==*cur ? lbclr
									: lclr|(bclr<<4)
819
								,"%-*.*s",width-4,width-4,option[i]);
deuce's avatar
deuce committed
820
821
822
823
824
825
826
						break;
					case KEY_NPAGE:	/* PgDn */
						if(!opts)
							break;
						*cur += (height-5);
						if(*cur>opts-1)
							*cur = opts-1;
827
						if(bar)
deuce's avatar
deuce committed
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
							*bar = height-5;
						y=height-5+s_top+top;
						gotoxy(s_left+left+1,s_top+top+3);
						textattr(lclr|(bclr<<4));
						if(*cur>height-5)  /* Scroll mode */
							putch(30);	   /* put the up arrow */
						else
							putch(' ');    /* delete the up arrow */
						gotoxy(s_left+left+1,s_top+top+height-2);
						if(*cur < opts-1)
							putch(31);	   /* put the down arrow */
						else
							putch(' ');    /* delete the down arrow */
						for(i=*cur+5-height,j=0;i<=*cur;i++,j++)
							uprintf(s_left+left+3,s_top+top+3+j
								,i==*cur ? lbclr
									: lclr|(bclr<<4)
								,"%-*.*s",width-4,width-4,option[i]);
846
847
848
849
850
						break;
					case KEY_END:	/* end */
						if(!opts)
							break;
						if(opts+4>height) {	/* Scroll mode */
851
							gotoxy(s_left+left+1,s_top+top+3);
852
853
							textattr(lclr|(bclr<<4));
							putch(30);	   /* put the up arrow */
854
							gotoxy(s_left+left+1,s_top+top+height-2);
855
856
							putch(' ');    /* delete the down arrow */
							for(i=(opts+4)-height,j=0;i<opts;i++,j++)
857
								uprintf(s_left+left+3,s_top+top+3+j
858
									,i==opts-1 ? lbclr
859
860
861
862
863
864
865
866
										: lclr|(bclr<<4)
									,"%-*.*s",width-4,width-4,option[i]);
							(*cur)=opts-1;
							y=top+height-2;
							if(bar)
								(*bar)=height-5;
							break; 
						}
867
868
						gettext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
869
870
						for(i=1;i<width*2;i+=2)
							line[i]=lclr|(bclr<<4);
871
872
						puttext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
873
874
875
876
						(*cur)=opts-1;
						y=top+height-2;
						if(bar)
							(*bar)=height-5;
877
878
						gettext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
879
						for(i=1;i<148;i+=2)
880
							line[i]=lbclr;
881
882
						puttext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
883
884
885
886
887
						break;
					case KEY_DOWN:	/* dn arrow */
						if(!opts)
							break;
						if((*cur)==opts-1 && opts+4>height) { /* like home */
888
							gotoxy(s_left+left+1,s_top+top+3);
889
890
							textattr(lclr|(bclr<<4));
							putch(' ');    /* Delete the up arrow */
891
							gotoxy(s_left+left+1,s_top+top+height-2);
892
							putch(31);	   /* put the down arrow */
893
							uprintf(s_left+left+3,s_top+top+3
894
								,lbclr
895
896
								,"%-*.*s",width-4,width-4,option[0]);
							for(i=1;i<height-4;i++)    /* re-display options */
897
								uprintf(s_left+left+3,s_top+top+3+i
898
899
900
901
902
903
904
905
									,lclr|(bclr<<4)
									,"%-*.*s",width-4,width-4,option[i]);
							(*cur)=0;
							y=top+3;
							if(bar)
								(*bar)=0;
							break; 
						}
906
907
						gettext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
908
909
						for(i=1;i<width*2;i+=2)
							line[i]=lclr|(bclr<<4);
910
911
						puttext(s_left+3+left,s_top+y
							,s_left+left+width-2,s_top+y,line);
912
913
914
915
916
917
						if((*cur)==opts-1) {
							(*cur)=0;
							y=top+3;
							if(bar) {
								/* gotoxy(1,1); cprintf("bar=%08lX ",bar); */
								(*bar)=0; 
deuce's avatar
deuce committed
918
							}
919
920
921
922
923
924
925
						}
						else {
							(*cur)++;
							y++;
							if(bar && (*bar)<height-5) {
								/* gotoxy(1,1); cprintf("bar=%08lX ",bar); */
								(*bar)++; 
deuce's avatar
deuce committed
926
							}
927
928
929
						}
						if(y==top+height-1) {	/* scroll */
							if(*cur==opts-1) {
930
								gotoxy(s_left+left+1,s_top+top+height-2);
931
932
933
934
								textattr(lclr|(bclr<<4));
								putch(' ');	/* delete the down arrow */
							}
							if((*cur)+4==height) {
935
								gotoxy(s_left+left+1,s_top+top+3);
936
937
938
939
940
								textattr(lclr|(bclr<<4));
								putch(30);	/* put the up arrow */
							}
							y--;
							/* gotoxy(1,1); cprintf("\rdebug: %4d ",__LINE__); */
941
942
							scroll_text(s_left+left+2,s_top+top+3
								,s_left+left+width-3,s_top+top+height-2,0);
943
							/* gotoxy(1,1); cprintf("\rdebug: %4d ",__LINE__); */
944
							uprintf(s_left+left+3,s_top+top+height-2
945
								,lbclr
946
947
948
								,"%-*.*s",width-4,width-4,option[*cur]);
						}
						else {
949
950
							gettext(s_left+3+left,s_top+y
								,s_left+left+width-2,s_top+y
951
952
								,line);
							for(i=1;i<width*2;i+=2)
953
								line[i]=lbclr;
954
955
							puttext(s_left+3+left,s_top+y
								,s_left+left+width-2,s_top+y
956
957
958
959
960
961
962
								,line);
						}
						break;
					case KEY_F(1):	/* F1 */
						help();
						break;
					case KEY_F(5):	/* F5 */
deuce's avatar
deuce committed
963
						if(mode&WIN_GET && !(mode&WIN_XTR && (*cur)==opts-1))
964
							return((*cur)|MSK_GET);
965
966
						break;
					case KEY_F(6):	/* F6 */
deuce's avatar
deuce committed
967
						if(mode&WIN_PUT && !(mode&WIN_XTR && (*cur)==opts-1))
968
							return((*cur)|MSK_PUT);
969
970
971
972
						break;
					case KEY_IC:	/* insert */
						if(mode&WIN_INS) {
							if(mode&WIN_INSACT) {
973
								gettext(s_left+left,s_top+top,s_left
deuce's avatar
deuce committed
974
									+left+width-1,s_top+top+height-1,tmp_buffer);
975
								for(i=1;i<(width*height*2);i+=2)
deuce's avatar
deuce committed
976
									tmp_buffer[i]=lclr|(cclr<<4);
977
978
979
								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
980
										tmp_buffer[i]=hclr|(cclr<<4); 
981
								}
982
								puttext(s_left+left,s_top+top,s_left
deuce's avatar
deuce committed
983
									+left+width-1,s_top+top+height-1,tmp_buffer);
984
985
986
987
988
989
990
991
992
993
994
995
							}
							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) {
996
								gettext(s_left+left,s_top+top,s_left
deuce's avatar
deuce committed
997
									+left+width-1,s_top+top+height-1,tmp_buffer);
998
								for(i=1;i<(width*height*2);i+=2)
deuce's avatar
deuce committed
999
									tmp_buffer[i]=lclr|(cclr<<4);
1000
1001
								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
1002
									tmp_buffer[i]=hclr|(cclr<<4);
1003
								puttext(s_left+left,s_top+top,s_left
deuce's avatar
deuce committed
1004
									+left+width-1,s_top+top+height-1,tmp_buffer);
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
							}
							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
1032
							&& ((!a && s && !strnicmp(option[j]+b,search,s+1))
1033
1034
1035
1036
1037
							|| ((a || !s) && toupper(option[j][b])==toupper(i)))) {
							if(a) s=0;
							else s++;
							if(y+(j-(*cur))+2>height+top) {
								(*cur)=j;
1038
								gotoxy(s_left+left+1,s_top+top+3);
1039
1040
1041
								textattr(lclr|(bclr<<4));
								putch(30);	   /* put the up arrow */
								if((*cur)==opts-1) {
1042
									gotoxy(s_left+left+1,s_top+top+height-2);
1043
1044
1045
									putch(' ');	/* delete the down arrow */
								}
								for(i=((*cur)+5)-height,j=0;i<(*cur)+1;i++,j++)
1046
									uprintf(s_left+left+3,s_top+top+3+j
1047
										,i==(*cur) ? lbclr
1048
1049
1050
1051
1052
1053
1054
1055
1056
											: 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;
1057
								gotoxy(s_left+left+1,s_top+top+3);
1058
1059
1060
								textattr(lclr|(bclr<<4));
								if(!(*cur))
									putch(' ');    /* Delete the up arrow */
1061
								gotoxy(s_left+left+1,s_top+top+height-2);
1062
								putch(31);	   /* put the down arrow */
1063
								uprintf(s_left+left+3,s_top+top+3
1064
									,lbclr
1065
1066
									,"%-*.*s",width-4,width-4,option[(*cur)]);
								for(i=1;i<height-4;i++) 	/* re-display options */
1067
									uprintf(s_left+left+3,s_top+top+3+i
1068
1069
1070
1071
1072
1073
1074
1075
										,lclr|(bclr<<4)
										,"%-*.*s",width-4,width-4
										,option[(*cur)+i]);
								y=top+3;
								if(bar)
									(*bar)=0;
								break; 
							}
1076
1077
							gettext(s_left+3+left,s_top+y
								,s_left+left+width-2,s_top+y,line);
1078
1079
							for(i=1;i<width*2;i+=2)
								line[i]=lclr|(bclr<<4);
1080
1081
							puttext(s_left+3+left,s_top+y
								,s_left+left+width-2,s_top+y,line);
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
							if((*cur)>j)
								y-=(*cur)-j;
							else
								y+=j-(*cur);
							if(bar) {
								if((*cur)>j)
									(*bar)-=(*cur)-j;
								else
									(*bar)+=j-(*cur); 
							}
							(*cur)=j;
1093
1094
							gettext(s_left+3+left,s_top+y
								,s_left+left+width-2,s_top+y,line);
1095
							for(i=1;i<width*2;i+=2)
1096
								line[i]=lbclr;
1097
1098
							puttext(s_left+3+left,s_top+y
								,s_left+left+width-2,s_top+y,line);
1099
1100
1101
1102
							break; 
						} 
					}
					if(a==2)
1103
						s=0;
1104
1105
1106
1107
1108
1109
1110
				}
				else
					switch(i) {
						case CR:
							if(!opts || (mode&WIN_XTR && (*cur)==opts-1))
								break;
							if(mode&WIN_ACT) {
1111
								gettext(s_left+left,s_top+top,s_left
deuce's avatar
deuce committed
1112
									+left+width-1,s_top+top+height-1,tmp_buffer);
1113
								for(i=1;i<(width*height*2);i+=2)
deuce's avatar
deuce committed
1114
									tmp_buffer[i]=lclr|(cclr<<4);
1115
1116
								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
1117
									tmp_buffer[i]=hclr|(cclr<<4);
1118

1119
								puttext(s_left+left,s_top+top,s_left
deuce's avatar
deuce committed
1120
									+left+width-1,s_top+top+height-1,tmp_buffer);
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
							}
							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)) {
1134
								gettext(s_left+left,s_top+top,s_left
deuce's avatar
deuce committed
1135
									+left+width-1,s_top+top+height-1,tmp_buffer);
1136
								for(i=1;i<(width*height*2);i+=2)
deuce's avatar
deuce committed
1137
									tmp_buffer[i]=lclr|(cclr<<4);
1138
								puttext(s_left+left,s_top+top,s_left
deuce's avatar
deuce committed
1139
									+left+width-1,s_top+top+height-1,tmp_buffer);
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
							}
							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]
1170
1171
		,shade[160],height=3;
	int	width;
1172
	int i,plen,slen;
1173
	int	iwidth;
1174
1175
1176
1177
1178
1179
1180
1181

	reset_dynamic();
	plen=strlen(prompt);
	if(!plen)
		slen=4;
	else
		slen=6;
	width=plen+slen+max;
1182
1183
	if(width>api->scrn_width-6)
		width=api->scrn_width-6;
1184
	if(mode&WIN_T2B)
deuce's avatar
deuce committed
1185
		top=(api->scrn_len-height+1)/2-2;
1186
	if(mode&WIN_L2R)
1187
1188
1189
		left=(SCRN_RIGHT-SCRN_LEFT-width+2)/2;
	if(left<=-(SCRN_LEFT))
		left=-(SCRN_LEFT)+1;
1190
1191
	if(top<0)
		top=0;
1192
1193
1194
	if(mode&WIN_SAV)
		gettext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT+left+width+1
			,SCRN_TOP+top+height,save_buf);
1195
	iwidth=width-plen-slen;