uifc32.c 78.4 KB
Newer Older
1
2
/* Curses implementation of UIFC (user interface) library based on uifc.c */

rswindell's avatar
rswindell committed
3
4
/* $Id$ */

5
6
7
8
/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
9
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
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
46
47
 *																			*
 * 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
    #define mswait(x) delay(x)
#elif defined(_WIN32)
	#include <share.h>
	#include <windows.h>
	#define mswait(x) Sleep(x)
#endif
48
#include <genwrap.h>	// for alloca()
49

50
#include "ciolib.h"
51
#include "uifc.h"
52
#define MAX_GETSTR	5120
53
54
55
56
57
58

#define BLINK	128

static int   cursor;
static char* helpfile=0;
static uint  helpline=0;
deuce's avatar
deuce committed
59
60
61
static size_t blk_scrn_len;
static char* blk_scrn;
static uchar* tmp_buffer;
62
static uchar* tmp_buffer2;
63
64
65
66
static win_t sav[MAX_BUFS];
static uifcapi_t* api;

/* Prototypes */
67
static int   uprintf(int x, int y, unsigned attr, char *fmt,...);
68
69
static void  bottomline(int line);
static char  *utimestr(time_t *intime);
deuce's avatar
deuce committed
70
static void  help(void);
71
static int   ugetstr(int left, int top, int width, char *outstr, int max, long mode, int *lastkey);
72
static void  timedisplay(BOOL force);
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

/* 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;
92
static int save_menu_opts=-1;
93

94
95
char* uifcYesNoOpts[]={"Yes","No",NULL};

96
97
98
99
100
static void reset_dynamic(void) {
	last_menu_cur=NULL;
	last_menu_bar=NULL;
	save_menu_cur=-1;
	save_menu_bar=-1;
101
	save_menu_opts=-1;
102
103
}

104
static uifc_graphics_t cp437_chars = {
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
	.background=0xb0,
	.help_char='?',
	.close_char=0xfe,
	.up_arrow=30,
	.down_arrow=31,
	.button_left='[',
	.button_right=']',

	.list_top_left=0xc9,
	.list_top=0xcd,
	.list_top_right=0xbb,
	.list_separator_left=0xcc,
	.list_separator_right=0xb9,
	.list_horizontal_separator=0xcd,
	.list_left=0xba,
	.list_right=0xba,
	.list_bottom_left=0xc8,
	.list_bottom_right=0xbc,
	.list_bottom=0xcd,
	.list_scrollbar_separator=0xb3,

	.input_top_left=0xc9,
	.input_top=0xcd,
	.input_top_right=0xbb,
	.input_left=0xba,
	.input_right=0xba,
	.input_bottom_left=0xc8,
	.input_bottom_right=0xbc,
	.input_bottom=0xcd,

	.popup_top_left=0xda,
	.popup_top=0xc4,
	.popup_top_right=0xbf,
	.popup_left=0xb3,
	.popup_right=0xb3,
	.popup_bottom_left=0xc0,
	.popup_bottom_right=0xd9,
	.popup_bottom=0xc4,

	.help_top_left=0xda,
	.help_top=0xc4,
	.help_top_right=0xbf,
	.help_left=0xb3,
	.help_right=0xb3,
	.help_bottom_left=0xc0,
	.help_bottom_right=0xd9,
	.help_bottom=0xc4,
	.help_titlebreak_left=0xb4,
	.help_titlebreak_right=0xc3,
	.help_hitanykey_left=0xb4,
	.help_hitanykey_right=0xc3,
};

158
159
160
161
162
static uifc_graphics_t ascii_chars = {
	.background='#',
	.help_char='?',
	.close_char='X',
	.up_arrow='^',
163
	.down_arrow='v',
164
165
166
	.button_left='[',
	.button_right=']',

167
	.list_top_left=',',
168
	.list_top='-',
169
	.list_top_right='.',
170
171
172
173
174
	.list_separator_left='+',
	.list_separator_right='+',
	.list_horizontal_separator='-',
	.list_left='|',
	.list_right='|',
175
176
	.list_bottom_left='`',
	.list_bottom_right='\'',
177
178
179
	.list_bottom='-',
	.list_scrollbar_separator='|',

180
	.input_top_left=',',
181
	.input_top='-',
182
	.input_top_right='.',
183
184
	.input_left='|',
	.input_right='|',
185
186
	.input_bottom_left='`',
	.input_bottom_right='\'',
187
188
	.input_bottom='-',

189
	.popup_top_left=',',
190
	.popup_top='-',
191
	.popup_top_right='.',
192
193
	.popup_left='|',
	.popup_right='|',
194
195
	.popup_bottom_left='`',
	.popup_bottom_right='\'',
196
197
	.popup_bottom='-',

198
	.help_top_left=',',
199
	.help_top='-',
200
	.help_top_right='.',
201
202
	.help_left='|',
	.help_right='|',
203
204
	.help_bottom_left='`',
	.help_bottom_right='\'',
205
206
207
208
209
210
211
	.help_bottom='-',
	.help_titlebreak_left='|',
	.help_titlebreak_right='|',
	.help_hitanykey_left='|',
	.help_hitanykey_right='|',
};

212
213
214
215
216
/****************************************************************************/
/* Initialization function, see uifc.h for details.							*/
/* Returns 0 on success.													*/
/****************************************************************************/

217
218
void uifc_mouse_enable(void)
{
219
220
221
222
223
	ciomouse_setevents(0);
	ciomouse_addevent(CIOLIB_BUTTON_1_DRAG_START);
	ciomouse_addevent(CIOLIB_BUTTON_1_DRAG_MOVE);
	ciomouse_addevent(CIOLIB_BUTTON_1_DRAG_END);
	ciomouse_addevent(CIOLIB_BUTTON_1_CLICK);
deuce's avatar
deuce committed
224
	ciomouse_addevent(CIOLIB_BUTTON_2_CLICK);
225
	ciomouse_addevent(CIOLIB_BUTTON_3_CLICK);
226
227
228
229
230
231
232
233
234
	showmouse();
}

void uifc_mouse_disable(void)
{
	ciomouse_setevents(0);
	hidemouse();
}

deuce's avatar
deuce committed
235
int kbwait(void) {
236
	int timeout=0;
237
	while(timeout++<50) {
238
		if(kbhit())
239
			return(TRUE);
240
		mswait(1);
241
242
243
244
	}
	return(FALSE);
}

245
int inkey(void)
deuce's avatar
deuce committed
246
247
248
249
{
	int c;

	c=getch();
250
	if(!c || c==0xe0)
251
		c|=(getch()<<8);
deuce's avatar
deuce committed
252
253
	return(c);
}
254

deuce's avatar
deuce committed
255
int UIFCCALL uifcini32(uifcapi_t* uifcapi)
256
{
257
	unsigned	i;
258
259
260
261
262
263
	struct	text_info txtinfo;

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

    api=uifcapi;
264
265
    if (api->chars == NULL) {
		switch(getfont()) {
266
			case -1:
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
			case 0:
			case 17:
			case 18:
			case 19:
			case 25:
			case 26:
			case 27:
			case 28:
			case 29:
			case 31:
				api->chars = &cp437_chars;
				break;
			default:
				api->chars = &ascii_chars;
				break;
		}
	}
284

285
    /* install function handlers */
286
287
288
289
290
291
292
293
    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
294
	api->showbuf=showbuf;
295
	api->timedisplay=timedisplay;
296
	api->bottomline=bottomline;
297
	api->getstrxy=ugetstr;
298
	api->printf=uprintf;
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328

    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;
        }
    }

329
#if 0
330
    clrscr();
331
#endif
332
333
334
335

    gettextinfo(&txtinfo);
    /* unsupported mode? */
    if(txtinfo.screenheight<MIN_LINES
deuce's avatar
deuce committed
336
/*        || txtinfo.screenheight>MAX_LINES */
deuce's avatar
deuce committed
337
        || txtinfo.screenwidth<40) {
338
339
340
        textmode(C80);  /* set mode to 80x25*/
        gettextinfo(&txtinfo);
    }
341
	window(1,1,txtinfo.screenwidth,txtinfo.screenheight);
342
343

    api->scrn_len=txtinfo.screenheight;
deuce's avatar
deuce committed
344
345
346
    if(api->scrn_len<MIN_LINES) {
        cprintf("\7UIFC: Screen length (%u) must be %d lines or greater\r\n"
            ,api->scrn_len,MIN_LINES);
347
348
349
350
        return(-2);
    }
    api->scrn_len--; /* account for status line */

351
352
    if(txtinfo.screenwidth<40) {
        cprintf("\7UIFC: Screen width (%u) must be at least 40 characters\r\n"
353
354
355
356
357
358
359
            ,txtinfo.screenwidth);
        return(-3);
    }
	api->scrn_width=txtinfo.screenwidth;

    if(!(api->mode&UIFC_COLOR)
        && (api->mode&UIFC_MONO
360
361
362
363
364
365
            || txtinfo.currmode==MONO || txtinfo.currmode==BW40 || txtinfo.currmode==BW80
            || txtinfo.currmode==MONO14 || txtinfo.currmode==BW40X14 || txtinfo.currmode==BW80X14
            || txtinfo.currmode==MONO21 || txtinfo.currmode==BW40X21 || txtinfo.currmode==BW80X21
            || txtinfo.currmode==MONO28 || txtinfo.currmode==BW40X28 || txtinfo.currmode==BW80X28
            || txtinfo.currmode==MONO43 || txtinfo.currmode==BW40X43 || txtinfo.currmode==BW80X43
            || txtinfo.currmode==MONO50 || txtinfo.currmode==BW40X50 || txtinfo.currmode==BW80X50
deuce's avatar
deuce committed
366
            || txtinfo.currmode==MONO60 || txtinfo.currmode==BW40X60 || txtinfo.currmode==BW80X60
367
			|| txtinfo.currmode==ATARI_40X24 || txtinfo.currmode==ATARI_80X25))
368
	{
369
370
371
372
373
        api->bclr=BLACK;
        api->hclr=WHITE;
        api->lclr=LIGHTGRAY;
        api->cclr=LIGHTGRAY;
			api->lbclr=BLACK|(LIGHTGRAY<<4);	/* lightbar color */
374
    } else {
375
376
377
378
379
        api->bclr=BLUE;
        api->hclr=YELLOW;
        api->lclr=WHITE;
        api->cclr=CYAN;
		api->lbclr=BLUE|(LIGHTGRAY<<4);	/* lightbar color */
380
    }
381

deuce's avatar
deuce committed
382
	blk_scrn_len=api->scrn_width*api->scrn_len*2;
deuce's avatar
deuce committed
383
	if((blk_scrn=(char *)malloc(blk_scrn_len))==NULL)  {
deuce's avatar
deuce committed
384
385
386
387
				cprintf("UIFC line %d: error allocating %u bytes."
					,__LINE__,blk_scrn_len);
				return(-1);
	}
deuce's avatar
deuce committed
388
	if((tmp_buffer=(uchar *)malloc(blk_scrn_len))==NULL)  {
deuce's avatar
deuce committed
389
390
391
392
				cprintf("UIFC line %d: error allocating %u bytes."
					,__LINE__,blk_scrn_len);
				return(-1);
	}
deuce's avatar
deuce committed
393
	if((tmp_buffer2=(uchar *)malloc(blk_scrn_len))==NULL)  {
394
395
396
397
				cprintf("UIFC line %d: error allocating %u bytes."
					,__LINE__,blk_scrn_len);
				return(-1);
	}
deuce's avatar
deuce committed
398
    for(i=0;i<blk_scrn_len;i+=2) {
399
        blk_scrn[i]=api->chars->background;
400
        blk_scrn[i+1]=api->cclr|(api->bclr<<4);
401
402
403
404
405
    }

    cursor=_NOCURSOR;
    _setcursortype(cursor);

406
	if(cio_api.mouse) {
407
		api->mode|=UIFC_MOUSE;
408
409
		uifc_mouse_enable();
	}
410

411
412
413
414
415
416
417
	/* A esc_delay of less than 10 is stupid... silently override */
	if(api->esc_delay < 10)
		api->esc_delay=25;

	if(cio_api.ESCDELAY)
		*(cio_api.ESCDELAY)=api->esc_delay;

418
419
	for(i=0; i<MAX_BUFS; i++)
		sav[i].buf=NULL;
deuce's avatar
deuce committed
420
421
422
	api->savnum=0;

	api->initialized=TRUE;
423

424
    return(0);
425
426
}

427
428
429
430
431
432
433
434
435
436
437
438
void docopy(void)
{
	int	key;
	struct mouse_event mevent;
	unsigned char *screen;
	unsigned char *sbuffer;
	int sbufsize=0;
	int x,y,startx,starty,endx,endy,lines;
	int outpos;
	char *copybuf;

	sbufsize=api->scrn_width*2*(api->scrn_len+1);
439
440
	screen=(unsigned char*)alloca(sbufsize);
	sbuffer=(unsigned char*)alloca(sbufsize);
441
442
443
	gettext(1,1,api->scrn_width,api->scrn_len+1,screen);
	while(1) {
		key=getch();
444
		if(key==0 || key==0xe0)
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
			key|=getch()<<8;
		switch(key) {
			case CIO_KEY_MOUSE:
				getmouse(&mevent);
				if(mevent.startx<mevent.endx) {
					startx=mevent.startx;
					endx=mevent.endx;
				}
				else {
					startx=mevent.endx;
					endx=mevent.startx;
				}
				if(mevent.starty<mevent.endy) {
					starty=mevent.starty;
					endy=mevent.endy;
				}
				else {
					starty=mevent.endy;
					endy=mevent.starty;
				}
				switch(mevent.event) {
					case CIOLIB_BUTTON_1_DRAG_MOVE:
						memcpy(sbuffer,screen,sbufsize);
						for(y=starty-1;y<endy;y++) {
							for(x=startx-1;x<endx;x++) {
								int pos=y*api->scrn_width+x;
								if((sbuffer[pos*2+1]&0x70)!=0x10)
deuce's avatar
deuce committed
472
									sbuffer[pos*2+1]=(sbuffer[pos*2+1]&0x8F)|0x10;
473
								else
deuce's avatar
deuce committed
474
									sbuffer[pos*2+1]=(sbuffer[pos*2+1]&0x8F)|0x60;
475
476
477
478
479
480
481
482
483
								if(((sbuffer[pos*2+1]&0x70)>>4) == (sbuffer[pos*2+1]&0x0F)) {
									sbuffer[pos*2+1]|=0x08;
								}
							}
						}
						puttext(1,1,api->scrn_width,api->scrn_len+1,sbuffer);
						break;
					case CIOLIB_BUTTON_1_DRAG_END:
						lines=abs(mevent.endy-mevent.starty)+1;
484
						copybuf=alloca((endy-starty+1)*(endx-startx+1)+1+lines*2);
485
486
487
						outpos=0;
						for(y=starty-1;y<endy;y++) {
							for(x=startx-1;x<endx;x++) {
488
								copybuf[outpos++]=screen[(y*api->scrn_width+x)*2]?screen[(y*api->scrn_width+x)*2]:' ';
489
							}
490
491
492
							#ifdef _WIN32
								copybuf[outpos++]='\r';
							#endif
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
							copybuf[outpos++]='\n';
						}
						copybuf[outpos]=0;
						copytext(copybuf, strlen(copybuf));
						puttext(1,1,api->scrn_width,api->scrn_len+1,screen);
						return;
				}
				break;
			default:
				puttext(1,1,api->scrn_width,api->scrn_len+1,screen);
				ungetch(key);
				return;
		}
	}
}

509
510
511
512
513
514
515
516
517
static int uifc_getmouse(struct mouse_event *mevent)
{
	mevent->startx=0;
	mevent->starty=0;
	mevent->event=0;
	if(api->mode&UIFC_MOUSE) {
		getmouse(mevent);
		if(mevent->event==CIOLIB_BUTTON_3_CLICK)
			return(ESC);
518
519
520
521
		if(mevent->event==CIOLIB_BUTTON_1_DRAG_START) {
			docopy();
			return(0);
		}
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
		if(mevent->starty==api->buttony) {
			if(mevent->startx>=api->exitstart
					&& mevent->startx<=api->exitend
					&& mevent->event==CIOLIB_BUTTON_1_CLICK) {
				return(ESC);
			}
			if(mevent->startx>=api->helpstart
					&& mevent->startx<=api->helpend
					&& mevent->event==CIOLIB_BUTTON_1_CLICK) {
				return(CIO_KEY_F(1));
			}
		}
		return(0);
	}
	return(-1);
}

539
540
void uifcbail(void)
{
deuce's avatar
deuce committed
541
542
	int i;

543
544
	_setcursortype(_NORMALCURSOR);
	textattr(LIGHTGRAY);
545
	uifc_mouse_disable();
546
	suspendciolib();
deuce's avatar
deuce committed
547
548
549
	FREE_AND_NULL(blk_scrn);
	FREE_AND_NULL(tmp_buffer);
	FREE_AND_NULL(tmp_buffer2);
550
	api->initialized=FALSE;
deuce's avatar
deuce committed
551
552
	for(i=0; i< MAX_BUFS; i++)
		FREE_AND_NULL(sav[i].buf);
553
554
555
556
557
558
559
560
}

/****************************************************************************/
/* Clear screen, fill with background attribute, display application title.	*/
/* Returns 0 on success.													*/
/****************************************************************************/
int uscrn(char *str)
{
561
    textattr(api->bclr|(api->cclr<<4));
562
    gotoxy(1,1);
563
    clreol();
564
565
566
567
568
    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);
569
    clreol();
570
	reset_dynamic();
571
	setname(str);
572
573
574
575
576
577
578
    return(0);
}

/****************************************************************************/
/****************************************************************************/
static void scroll_text(int x1, int y1, int x2, int y2, int down)
{
579
	gettext(x1,y1,x2,y2,tmp_buffer2);
580
	if(down)
581
		puttext(x1,y1+1,x2,y2,tmp_buffer2);
582
	else
583
		puttext(x1,y1,x2,y2-1,tmp_buffer2+(((x2-x1)+1)*2));
584
585
586
587
588
589
}

/****************************************************************************/
/* Updates time in upper left corner of screen with current time in ASCII/  */
/* Unix format																*/
/****************************************************************************/
590
static void timedisplay(BOOL force)
591
592
593
594
595
{
	static time_t savetime;
	time_t now;

	now=time(NULL);
596
	if(force || difftime(now,savetime)>=60) {
597
		uprintf(api->scrn_width-25,1,api->bclr|(api->cclr<<4),utimestr(&now));
598
599
600
601
602
603
604
		savetime=now; 
	}
}

/****************************************************************************/
/* Truncates white-space chars off end of 'str'								*/
/****************************************************************************/
605
static void truncspctrl(char *str)
606
607
608
609
{
	uint c;

	c=strlen(str);
deuce's avatar
deuce committed
610
	while(c && (uchar)str[c-1]<=' ') c--;
611
612
613
614
615
616
617
618
	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
deuce's avatar
deuce committed
619
	, char *initial_title, char **option)
620
{
621
	uchar line[MAX_COLS*2],shade[MAX_LINES*4],*ptr
622
623
		,bline=0,*win;
    char search[MAX_OPLN];
624
625
626
	int height,y;
	int i,j,opts=0,s=0; /* s=search index into options */
	int	is_redraw=0;
627
628
629
630
631
632
633
634
635
636
	int s_top=SCRN_TOP;
	int s_left=SCRN_LEFT;
	int s_right=SCRN_RIGHT;
	int s_bottom=api->scrn_len-3;
	int hbrdrsize=2;
	int lbrdrwidth=1;
	int rbrdrwidth=1;
	int vbrdrsize=4;
	int tbrdrwidth=3;
	int bbrdrwidth=1;
637
	int title_len;
638
	int tmpcur=0;
639
	struct mouse_event mevnt;
640
	char	*title=NULL;
641
	int	a,b,c,longopt;
642
	int	optheight=0;
643
	int gotkey;
644
645
	uchar	hclr,lclr,bclr,cclr,lbclr;

646
	if(cur==NULL) cur=&tmpcur;
647
	api->exit_flags = 0;
648
649
650
651
652
653
654
655
656
657
658
659
	hclr=api->hclr;
	lclr=api->lclr;
	bclr=api->bclr;
	cclr=api->cclr;
	lbclr=api->lbclr;
	if(mode & WIN_INACT) {
		bclr=api->cclr;
		hclr=api->lclr;
		lclr=api->lclr;
		cclr=api->cclr;
		lbclr=(api->cclr<<4)|api->hclr;
	}
660
661
	title=strdup(initial_title==NULL?"":initial_title);

662
663
	if(!(api->mode&UIFC_NHM))
		uifc_mouse_disable();
664
665

	title_len=strlen(title);
666
667
668

	if(mode&WIN_FAT) {
		s_top=1;
669
		s_left=2;
670
671
		s_right=api->scrn_width-3;  /* Leave space for the shadow */
		s_bottom=api->scrn_len-1;   /* Leave one for the shadow */
672
	}
673
674
675
676
677
678
679
680
681
	if(mode&WIN_NOBRDR) {
		hbrdrsize=0;
		vbrdrsize=0;
		lbrdrwidth=0;
		rbrdrwidth=0;
		tbrdrwidth=0;
		bbrdrwidth=0;
	}

682
683
	if(mode&WIN_SAV && api->savnum>=MAX_BUFS-1)
		putch(7);
684
	if(api->helpbuf!=NULL || api->helpixbfile[0]!=0) bline|=BL_HELP;
685
686
687
688
	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;
689
	if(mode&WIN_EDIT) bline|=BL_EDIT;
690
691
	if(api->bottomline != NULL)
		api->bottomline(bline);
692
	while(option!=NULL && opts<MAX_OPTS)
693
		if(option[opts]==NULL || option[opts][0]==0)
694
695
			break;
		else opts++;
deuce's avatar
deuce committed
696
	if(mode&WIN_XTR && opts<MAX_OPTS)
697
		opts++;
698
	optheight=opts+vbrdrsize;
699
	height=optheight;
700
701
702
	if(mode&WIN_FIXEDHEIGHT) {
		height=api->list_height;
	}
703
704
	if(top+height>s_bottom)
		height=(s_bottom)-top;
705
706
	if(optheight>height)
		optheight=height;
707
708
	if(!width || width<title_len+hbrdrsize+2) {
		width=title_len+hbrdrsize+2;
709
		for(i=0;i<opts;i++) {
710
			if(option[i]!=NULL) {
711
				truncspctrl(option[i]);
712
713
714
				if((j=strlen(option[i])+hbrdrsize+2+1)>width)
					width=j;
			}
715
716
		}
	}
717
718
719
720
721
722
723
	/* Determine minimum widths here to accomodate mouse "icons" in border */
	if(!(mode&WIN_NOBRDR) && api->mode&UIFC_MOUSE) {
		if(bline&BL_HELP && width<8)
			width=8;
		else if(width<5)
			width=5;
	}
724
725
	if(width>(s_right+1)-s_left) {
		width=(s_right+1)-s_left;
726
727
728
729
730
		if(title_len>(width-hbrdrsize-2)) {
			*(title+width-hbrdrsize-2-3)='.';
			*(title+width-hbrdrsize-2-2)='.';
			*(title+width-hbrdrsize-2-1)='.';
			*(title+width-hbrdrsize-2)=0;
731
			title_len=strlen(title);
732
		}
733
	}
734
	if(mode&WIN_L2R)
deuce's avatar
deuce committed
735
		left=(s_right-s_left-width+1)/2;
736
	else if(mode&WIN_RHT)
737
		left=s_right-(width+hbrdrsize+2+left);
738
	if(mode&WIN_T2B)
deuce's avatar
deuce committed
739
		top=(api->scrn_len-height+1)/2-2;
740
	else if(mode&WIN_BOT)
741
		top=s_bottom-height-top;
742
743
	if(left<0)
		left=0;
744
745
	if(top<0)
		top=0;
746
747

	/* Dynamic Menus */
748
	if(mode&WIN_DYN
749
750
751
			&& cur != NULL
			&& bar != NULL
			&& last_menu_cur==cur
752
753
			&& last_menu_bar==bar
			&& save_menu_cur==*cur
754
			&& save_menu_bar==*bar
deuce's avatar
deuce committed
755
			&& save_menu_opts==opts) {
deuce's avatar
deuce committed
756
		is_redraw=1;
757
758
	}

759
760
761
762
	if(mode&WIN_DYN && mode&WIN_REDRAW)
		is_redraw=1;
	if(mode&WIN_DYN && mode&WIN_NODRAW)
		is_redraw=0;
763

deuce's avatar
deuce committed
764
765
766
	if(mode&WIN_ORG) {		/* Clear all save buffers on WIN_ORG */
		for(i=0; i< MAX_BUFS; i++)
			FREE_AND_NULL(sav[i].buf);
767
		api->savnum=0;
deuce's avatar
deuce committed
768
769
	}

770
	if(mode&WIN_SAV) {
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
		/* Check if this screen (by cur/bar) is already saved */
		for(i=0; i<MAX_BUFS; i++) {
			if(sav[i].buf!=NULL) {
				if(cur==sav[i].cur && bar==sav[i].bar) {
					/* Yes, it is... */
					for(j=api->savnum-1; j>i; j--) {
						/* Retore old screens */
						puttext(sav[j].left,sav[j].top,sav[j].right,sav[j].bot
							,sav[j].buf);	/* put original window back */
						FREE_AND_NULL(sav[j].buf);
					}
					api->savnum=i;
				}
			}
		}
		/* savnum not the next one - must be a dynamic window or we popped back up the stack */
		if(sav[api->savnum].buf != NULL) {
			/* Is this even the right window? */
			if(sav[api->savnum].cur==cur
					&& sav[api->savnum].bar==bar) {
				if((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 */
					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_AND_NULL(sav[api->savnum].buf);
798
					if((sav[api->savnum].buf=malloc((width+3)*(height+2)*2))==NULL) {
799
800
801
						cprintf("UIFC line %d: error allocating %u bytes."
							,__LINE__,(width+3)*(height+2)*2);
						free(title);
802
803
						if(!(api->mode&UIFC_NHM))
							uifc_mouse_enable();
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
						return(-1);
					}
					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;
					sav[api->savnum].cur=cur;
					sav[api->savnum].bar=bar;
				}
			}
			else {
				/* Find something available... */
				while(sav[api->savnum].buf!=NULL)
					api->savnum++;
820
821
			}
		}
822
		else {
823
			if((sav[api->savnum].buf=malloc((width+3)*(height+2)*2))==NULL) {
824
825
				cprintf("UIFC line %d: error allocating %u bytes."
					,__LINE__,(width+3)*(height+2)*2);
826
				free(title);
827
828
				if(!(api->mode&UIFC_NHM))
					uifc_mouse_enable();
829
				return(-1);
830
			}
831
			gettext(s_left+left,s_top+top,s_left+left+width+1
832
				,s_top+top+height,sav[api->savnum].buf);
833
834
835
836
			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;
837
838
			sav[api->savnum].cur=cur;
			sav[api->savnum].bar=bar;
839
		}
840
841
842
843
844
	}

	if(!is_redraw) {
		if(mode&WIN_ORG) { /* Clear around menu */
			if(top)
845
				puttext(1,2,api->scrn_width,s_top+top-1,blk_scrn);
846
			if((unsigned)(s_top+height+top)<=api->scrn_len)
deuce's avatar
deuce committed
847
				puttext(1,s_top+height+top,api->scrn_width,api->scrn_len,blk_scrn);
848
			if(left)
deuce's avatar
deuce committed
849
				puttext(1,s_top+top,s_left+left-1,s_top+height+top
850
					,blk_scrn);
851
			if(s_left+left+width<=s_right)
deuce's avatar
deuce committed
852
				puttext(s_left+left+width,s_top+top,/* s_right+2 */api->scrn_width
853
					,s_top+height+top,blk_scrn);
854
		}
deuce's avatar
deuce committed
855
		ptr=tmp_buffer;
856
		if(!(mode&WIN_NOBRDR)) {
857
			*(ptr++)=api->chars->list_top_left;
858
			*(ptr++)=hclr|(bclr<<4);
859

860
			if(api->mode&UIFC_MOUSE) {
861
				*(ptr++)=api->chars->button_left;
862
				*(ptr++)=hclr|(bclr<<4);
863
				/* *(ptr++)=''; */
864
				*(ptr++)=api->chars->close_char;
865
				*(ptr++)=lclr|(bclr<<4);
866
				*(ptr++)=api->chars->button_right;
867
				*(ptr++)=hclr|(bclr<<4);
868
869
				i=3;
				if(bline&BL_HELP) {
870
					*(ptr++)=api->chars->button_left;
871
					*(ptr++)=hclr|(bclr<<4);
872
					*(ptr++)=api->chars->help_char;
873
					*(ptr++)=lclr|(bclr<<4);
874
					*(ptr++)=api->chars->button_right;
875
					*(ptr++)=hclr|(bclr<<4);
876
877
					i+=3;
				}
878
879
880
881
882
883
884
885
886
887
				api->buttony=s_top+top;
				api->exitstart=s_left+left+1;
				api->exitend=s_left+left+3;
				api->helpstart=s_left+left+4;
				api->helpend=s_left+left+6;
			}
			else
				i=0;

			for(;i<width-2;i++) {
888
				*(ptr++)=api->chars->list_top;
889
				*(ptr++)=hclr|(bclr<<4);
890
			}
891
			*(ptr++)=api->chars->list_top_right;
892
			*(ptr++)=hclr|(bclr<<4);
893
			*(ptr++)=api->chars->list_left;
894
			*(ptr++)=hclr|(bclr<<4);
895
896
897
898
			a=title_len;
			b=(width-a-1)/2;
			for(i=0;i<b;i++) {
				*(ptr++)=' ';
899
				*(ptr++)=hclr|(bclr<<4);
900
901
902
			}
			for(i=0;i<a;i++) {
				*(ptr++)=title[i];
903
				*(ptr++)=hclr|(bclr<<4);
904
905
906
			}
			for(i=0;i<width-(a+b)-2;i++) {
				*(ptr++)=' ';
907
				*(ptr++)=hclr|(bclr<<4);
908
			}
909
			*(ptr++)=api->chars->list_right;
910
			*(ptr++)=hclr|(bclr<<4);
911
			*(ptr++)=api->chars->list_separator_left;
912
			*(ptr++)=hclr|(bclr<<4);
913
			for(i=0;i<width-2;i++) {
914
				*(ptr++)=api->chars->list_horizontal_separator;
915
				*(ptr++)=hclr|(bclr<<4);
916
			}
917
			*(ptr++)=api->chars->list_separator_right;
918
			*(ptr++)=hclr|(bclr<<4);
919
920
921
922
923
924
		}

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

		if(!bar) {
925
926
927
928
			if((*cur)>height-vbrdrsize-1)
				(*cur)=height-vbrdrsize-1;
			if((*cur)>opts-1)
				(*cur)=opts-1;
929
			i=0;
930
931
932
933
		}
		else {
			if((*bar)>=opts)
				(*bar)=opts-1;
934
935
			if((*bar)>height-vbrdrsize-1)
				(*bar)=height-vbrdrsize-1;
936
			if((*cur)==opts-1)
937
938
939
				(*bar)=height-vbrdrsize-1;
			if((*bar)>opts-1)
				(*bar)=opts-1;
940
941
942
943
944
			if((*bar)<0)
				(*bar)=0;
			if((*cur)<(*bar))
				(*cur)=(*bar);
			i=(*cur)-(*bar);
945
946
947
948
			if(i+(height-vbrdrsize-1)>=opts) {
				i=opts-(height-vbrdrsize);
				if(i<0)
					i=0;
949
950
				(*cur)=i+(*bar);
			}
951
952
953
		}
		if((*cur)<0)
			(*cur)=0;
954

955
956
957
		j=0;
		if(i<0) i=0;
		longopt=0;
958
		while(j<height-vbrdrsize) {
959
			if(!(mode&WIN_NOBRDR)) {
960
				*(ptr++)=api->chars->list_left;
961
				*(ptr++)=hclr|(bclr<<4);
962
963
			}
			*(ptr++)=' ';
964
			*(ptr++)=hclr|(bclr<<4);
965
			*(ptr++)=api->chars->list_scrollbar_separator;
966
			*(ptr++)=lclr|(bclr<<4);
967
			if(i==(*cur))
968
				a=lbclr;
969
			else
970
				a=lclr|(bclr<<4);
971
			if(i<opts && option[i]!=NULL) {
972
973
974
975
976
977
978
979
980
				b=strlen(option[i]);
				if(b>longopt)
					longopt=b;
				if(b+hbrdrsize+2>width)
					b=width-hbrdrsize-2;
				for(c=0;c<b;c++) {
					*(ptr++)=option[i][c];
					*(ptr++)=a; 
				}
981
			}
982
983
			else
				c=0;
984
			while(c<width-hbrdrsize-2) {
985
				*(ptr++)=' ';
986
987
988
989
				*(ptr++)=a;
				c++;
			}
			if(!(mode&WIN_NOBRDR)) {
990
				*(ptr++)=api->chars->list_right;
991
				*(ptr++)=hclr|(bclr<<4);
992
			}
993
994
995
996
			i++;
			j++; 
		}
		if(!(mode&WIN_NOBRDR)) {
997
			*(ptr++)=api->chars->list_bottom_left;
998
			*(ptr++)=hclr|(bclr<<4);
999
			for(i=0;i<width-2;i++) {
1000
				*(ptr++)=api->chars->list_bottom;
1001
				*(ptr++)=hclr|(bclr<<4); 
1002
			}
1003
			*(ptr++)=api->chars->list_bottom_right;
1004
			*(ptr)=hclr|(bclr<<4);	/* Not incremented to shut ot BCC */
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
		}
		puttext(s_left+left,s_top+top,s_left+left+width-1
			,s_top+top+height-1,tmp_buffer);
		if(bar)
			y=top+tbrdrwidth+(*bar);
		else
			y=top+tbrdrwidth+(*cur);
		if(opts+vbrdrsize>height && ((!bar && (*cur)!=opts-1)
			|| (bar && ((*cur)-(*bar))+(height-vbrdrsize)<opts))) {
			gotoxy(s_left+left+lbrdrwidth,s_top+top+height-bbrdrwidth-1);
1015
			textattr(lclr|(bclr<<4));
1016
			putch(api->chars->down_arrow);	   /* put down arrow */
1017
			textattr(hclr|(bclr<<4)); 
1018
		}
1019

1020
1021
		if(bar && (*bar)!=(*cur)) {
			gotoxy(s_left+left+lbrdrwidth,s_top+top+tbrdrwidth);
1022
			textattr(lclr|(bclr<<4));
1023
			putch(api->chars->up_arrow);	   /* put the up arrow */
1024
			textattr(hclr|(bclr<<4)); 
1025
		}
1026

1027
1028
		if(!(mode&WIN_NOBRDR)) {
			/* Shadow */
1029
			if(bclr==BLUE) {
1030
1031
				gettext(s_left+left+width,s_top+top+1,s_left+left+width+1
					,s_top+top+height-1,shade);
1032
1033
				for(i=1;i<height*4;i+=2)
					shade[i]=DARKGRAY;
1034
1035
1036
1037
				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);
1038
1039
				for(i=1;i<width*2;i+=2)
					shade[i]=DARKGRAY;
1040
1041
				puttext(s_left+left+2,s_top+top+height,s_left+left+width+1
					,s_top+top+height,shade);
1042
			}
1043
		}
1044
1045
	}
	else {	/* Is a redraw */
deuce's avatar
deuce committed
1046
1047
1048
1049
		if(bar)
			y=top+tbrdrwidth+(*bar);
		else
			y=top+tbrdrwidth+(*cur);
1050
		i=(*cur)+(top+tbrdrwidth-y);
1051
		j=tbrdrwidth-1;