Skip to content
Snippets Groups Projects
Commit c0e38373 authored by rswindell's avatar rswindell
Browse files

These are unmaintained (deprecated, obsolete) implementations of UIFC.

parent ec2ba21a
No related branches found
No related tags found
No related merge requests found
/* uifcc.c */
/* Curses implementation of UIFC (user interface) library based on uifc.c */
/* $Id$ */
/****************************************************************************
* @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. *
****************************************************************************/
#include <stdio.h>
#include <curs_fix.h>
#include <unistd.h>
#include <sys/time.h>
#include "uifc.h"
#ifdef __QNX__
#include <strings.h>
#endif
#if defined(__OS2__)
#define INCL_BASE
#include <os2.h>
void mswait(int msec)
{
DosSleep(msec ? msec : 1);
}
#elif defined(_WIN32)
#include <windows.h>
#define mswait(x) Sleep(x)
#elif defined(__FLAT__)
#define mswait(x) delay(x)
#endif
/* 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 */
enum {
BLACK
,BLUE
,GREEN
,CYAN
,RED
,MAGENTA
,BROWN
,LIGHTGRAY
,DARKGRAY
,LIGHTBLUE
,LIGHTGREEN
,LIGHTCYAN
,LIGHTRED
,LIGHTMAGENTA
,YELLOW
,WHITE
};
#define BLINK 128
#define SH_DENYWR 1
#define SH_DENYRW 2
#ifndef O_BINARY
#define O_BINARY 0
#endif
static char hfclr,hbclr,hclr,lclr,bclr,cclr,show_free_mem=0;
static char* helpfile=0;
static uint helpline=0;
static char blk_scrn[MAX_BFLN];
static win_t sav[MAX_BUFS];
static uint max_opts=MAX_OPTS;
static uifcapi_t* api;
static int lastattr=0;
/* Prototypes */
static int uprintf(int x, int y, unsigned char attr, char *fmt,...);
static void bottomline(int line);
static char *utimestr(time_t *intime);
static void help();
static int puttext(int sx, int sy, int ex, int ey, unsigned char *fill);
static int gettext(int sx, int sy, int ex, int ey, unsigned char *fill);
static short curses_color(short color);
static void textattr(unsigned char attr);
static int kbhit(void);
#ifndef __QNX__
static void delay(int msec);
#endif
static int ugetstr(char *outstr, int max, long mode);
static int wherey(void);
static int wherex(void);
static int cprintf(char *fmat, ...);
static void cputs(char *str);
static void gotoxy(int x, int y);
static void _putch(unsigned char ch, BOOL refresh);
static void timedisplay(void);
#define putch(x) _putch(x,TRUE)
/* 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);
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;
void reset_dynamic(void) {
last_menu_cur=NULL;
last_menu_bar=NULL;
save_menu_cur=-1;
save_menu_bar=-1;
}
int inkey(int mode)
{
if(mode)
return(kbhit());
return(getch());
}
/****************************************************************************/
/* Initialization function, see uifc.h for details. */
/* Returns 0 on success. */
/****************************************************************************/
int uifcinic(uifcapi_t* uifcapi)
{
int i;
int height, width;
short fg, bg, pair=0;
#ifndef __FLAT__
union REGS r;
#endif
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;
api->showbuf=showbuf;
api->timedisplay=timedisplay;
#if defined(LOCALE)
(void) setlocale(LC_ALL, "");
#endif
initscr();
start_color();
cbreak();
noecho();
nonl();
// intrflush(stdscr, FALSE);
keypad(stdscr, TRUE);
scrollok(stdscr,FALSE);
raw();
#ifdef NCURSES_VERSION_MAJOR
ESCDELAY=api->esc_delay;
#endif
// Set up color pairs
for(bg=0;bg<8;bg++) {
for(fg=0;fg<8;fg++) {
init_pair(++pair,curses_color(fg),curses_color(bg));
}
}
clear();
refresh();
getmaxyx(stdscr,height,width);
/* unsupported mode? */
if(height<MIN_LINES
|| height>MAX_LINES
|| width<80) {
}
api->scrn_len=height;
if(api->scrn_len<MIN_LINES || api->scrn_len>MAX_LINES) {
uifcbail();
fprintf(stderr,"\7UIFC: Screen length (%u) must be between %d and %d lines\n"
,api->scrn_len,MIN_LINES,MAX_LINES);
return(-2);
}
if(width*height*2>MAX_BFLN) {
uifcbail();
fprintf(stderr,"\7UIFC: Screen size (%u x %u) must be smaller than %u\n"
,width,height,(uchar)(MAX_BFLN/2));
return(-2);
}
api->scrn_len--; /* account for status line */
api->scrn_width=width;
if(width<80) {
uifcbail();
fprintf(stderr,"\7UIFC: Screen width (%u) must be at least 80 characters\n"
,width);
return(-3);
}
/* ToDo - Set up mousemask() here */
if(!has_colors()) {
bclr=BLACK;
hclr=WHITE;
lclr=LIGHTGRAY;
cclr=LIGHTGRAY;
hbclr=BLACK; /* Highlight Background Colour */
hfclr=WHITE; /* Highlight Foreground Colour */
} else {
bclr=BLUE;
hclr=YELLOW;
lclr=WHITE;
cclr=CYAN;
hbclr=LIGHTGRAY;
hfclr=YELLOW;
}
for(i=0;i<MAX_BFLN;i+=2) {
blk_scrn[i]='';
blk_scrn[i+1]=cclr|(bclr<<4);
}
curs_set(0);
refresh();
return(0);
}
short curses_color(short color)
{
switch(color)
{
case 0 :
return(COLOR_BLACK);
case 1 :
return(COLOR_BLUE);
case 2 :
return(COLOR_GREEN);
case 3 :
return(COLOR_CYAN);
case 4 :
return(COLOR_RED);
case 5 :
return(COLOR_MAGENTA);
case 6 :
return(COLOR_YELLOW);
case 7 :
return(COLOR_WHITE);
case 8 :
return(COLOR_BLACK);
case 9 :
return(COLOR_BLUE);
case 10 :
return(COLOR_GREEN);
case 11 :
return(COLOR_CYAN);
case 12 :
return(COLOR_RED);
case 13 :
return(COLOR_MAGENTA);
case 14 :
return(COLOR_YELLOW);
case 15 :
return(COLOR_WHITE);
}
return(0);
}
static void hidemouse(void)
{
/* ToDo - Mouse stuff here */
}
static void showmouse(void)
{
/* ToDo - Mouse stuff here */
}
void uifcbail(void)
{
curs_set(1);
clear();
nl();
nocbreak();
noraw();
refresh();
endwin();
}
/****************************************************************************/
/* Clear screen, fill with background attribute, display application title. */
/* Returns 0 on success. */
/****************************************************************************/
int uscrn(char *str)
{
textattr(bclr|(cclr<<4));
gotoxy(1,1);
clrtoeol();
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);
clrtoeol();
refresh();
reset_dynamic();
return(0);
}
/****************************************************************************/
/****************************************************************************/
static void scroll_text(int x1, int y1, int x2, int y2, int down)
{
uchar buf[MAX_BFLN];
gettext(x1,y1,x2,y2,buf);
if(down)
puttext(x1,y1+1,x2,y2,buf);
else
puttext(x1,y1,x2,y2-1,buf+(((x2-x1)+1)*2));
}
/****************************************************************************/
/* 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) {
uprintf(55,1,bclr|(cclr<<4),utimestr(&now));
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]<=' ') 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)
{
uchar line[256],shade[256],win[MAX_BFLN],*ptr,a,b,c,longopt
,search[MAX_OPLN],bline=0;
int height,y;
int i,j,opts=0,s=0; /* s=search index into options */
int is_redraw=0;
#ifndef __FLAT__
/* ToDo Mouse stuff */
#endif
if(mode&WIN_SAV && api->savnum>=MAX_BUFS-1)
putch(7);
i=0;
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);
while(opts<max_opts && opts<MAX_OPTS)
if(option[opts]==NULL || option[opts][0]==0)
break;
else opts++;
if(mode&WIN_XTR && opts<max_opts && opts<MAX_OPTS)
option[opts++][0]=0;
height=opts+4;
if(top+height>api->scrn_len-3)
height=(api->scrn_len-3)-top;
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)
width=j;
}
}
if(width>(SCRN_RIGHT+1)-SCRN_LEFT)
width=(SCRN_RIGHT+1)-SCRN_LEFT;
if(mode&WIN_L2R)
left=36-(width/2);
else if(mode&WIN_RHT)
left=SCRN_RIGHT-(width+4+left);
if(mode&WIN_T2B)
top=(api->scrn_len/2)-(height/2)-2;
else if(mode&WIN_BOT)
top=api->scrn_len-height-3-top;
/* Dynamic Menus */
if(mode&WIN_DYN
&& cur != NULL
&& bar != NULL
&& last_menu_cur==cur
&& last_menu_bar==bar
&& save_menu_cur==*cur
&& save_menu_bar==*bar)
is_redraw=1;
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);
return(-1);
}
gettext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT+left+width+1
,SCRN_TOP+top+height,sav[api->savnum].buf);
sav[api->savnum].left=SCRN_LEFT+left;
sav[api->savnum].top=SCRN_TOP+top;
sav[api->savnum].right=SCRN_LEFT+left+width+1;
sav[api->savnum].bot=SCRN_TOP+top+height;
api->savdepth++;
}
else if(mode&WIN_SAV
&& (sav[api->savnum].left!=SCRN_LEFT+left
|| sav[api->savnum].top!=SCRN_TOP+top
|| sav[api->savnum].right!=SCRN_LEFT+left+width+1
|| sav[api->savnum].bot!=SCRN_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(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);
return(-1);
}
gettext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT+left+width+1
,SCRN_TOP+top+height,sav[api->savnum].buf); /* save again */
sav[api->savnum].left=SCRN_LEFT+left;
sav[api->savnum].top=SCRN_TOP+top;
sav[api->savnum].right=SCRN_LEFT+left+width+1;
sav[api->savnum].bot=SCRN_TOP+top+height;
}
}
#ifndef __FLAT__
if(show_free_mem) {
/* ToDo Show free memory */
// uprintf(58,1,bclr|(cclr<<4),"%10u bytes free",coreleft());
}
#endif
if(!is_redraw) {
if(mode&WIN_ORG) { /* Clear around menu */
if(top)
puttext(SCRN_LEFT,SCRN_TOP,SCRN_RIGHT+2,SCRN_TOP+top-1,blk_scrn);
if(SCRN_TOP+height+top<=api->scrn_len)
puttext(SCRN_LEFT,SCRN_TOP+height+top,SCRN_RIGHT+2,api->scrn_len,blk_scrn);
if(left)
puttext(SCRN_LEFT,SCRN_TOP+top,SCRN_LEFT+left-1,SCRN_TOP+height+top
,blk_scrn);
if(SCRN_LEFT+left+width<=SCRN_RIGHT)
puttext(SCRN_LEFT+left+width,SCRN_TOP+top,SCRN_RIGHT+2
,SCRN_TOP+height+top,blk_scrn);
}
ptr=win;
*(ptr++)='';
*(ptr++)=hclr|(bclr<<4);
if(api->mode&UIFC_MOUSE) {
/* ToDo Mouse stuff */
i=0;
}
else
i=0;
for(;i<width-2;i++) {
*(ptr++)='';
*(ptr++)=hclr|(bclr<<4);
}
*(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++)=' ';
*(ptr++)=hclr|(bclr<<4);
}
for(i=0;i<a;i++) {
*(ptr++)=title[i];
*(ptr++)=hclr|(bclr<<4);
}
for(i=0;i<width-(a+b)-2;i++) {
*(ptr++)=' ';
*(ptr++)=hclr|(bclr<<4);
}
*(ptr++)='';
*(ptr++)=hclr|(bclr<<4);
*(ptr++)='';
*(ptr++)=hclr|(bclr<<4);
for(i=0;i<width-2;i++) {
*(ptr++)='';
*(ptr++)=hclr|(bclr<<4);
}
*(ptr++)='';
*(ptr++)=hclr|(bclr<<4);
if((*cur)>=opts)
(*cur)=opts-1; /* returned after scrolled */
if(!bar) {
if((*cur)>height-5)
(*cur)=height-5;
i=0;
}
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))
a=hfclr|(hbclr<<4);
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++;
}
*(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++)='';
*(ptr++)=hclr|(bclr<<4);
puttext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT+left+width-1
,SCRN_TOP+top+height-1,win);
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))) {
gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+height-2);
textattr(lclr|(bclr<<4));
putch(31); /* put down arrow */
textattr(hclr|(bclr<<4));
}
if(bar && (*bar)!=(*cur)) {
gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+3);
textattr(lclr|(bclr<<4));
putch(30); /* put the up arrow */
textattr(hclr|(bclr<<4));
}
if(bclr==BLUE) {
gettext(SCRN_LEFT+left+width,SCRN_TOP+top+1,SCRN_LEFT+left+width+1
,SCRN_TOP+top+height-1,shade);
for(i=1;i<height*4;i+=2)
shade[i]=DARKGRAY;
puttext(SCRN_LEFT+left+width,SCRN_TOP+top+1,SCRN_LEFT+left+width+1
,SCRN_TOP+top+height-1,shade);
gettext(SCRN_LEFT+left+2,SCRN_TOP+top+height,SCRN_LEFT+left+width+1
,SCRN_TOP+top+height,shade);
for(i=1;i<width*2;i+=2)
shade[i]=DARKGRAY;
puttext(SCRN_LEFT+left+2,SCRN_TOP+top+height,SCRN_LEFT+left+width+1
,SCRN_TOP+top+height,shade);
}
showmouse();
}
else { /* Is a redraw */
i=(*cur)-(*bar);
j=2;
longopt=0;
while(j<height-2 && i<opts) {
ptr=win;
if(i==(*cur))
a=hfclr|(hbclr<<4);
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++;
puttext(SCRN_LEFT+left+3,SCRN_TOP+top+j,SCRN_LEFT+left+width-2
,SCRN_TOP+top+j,win);
}
if(bar)
y=top+3+(*bar);
else
y=top+3+(*cur);
}
last_menu_cur=cur;
last_menu_bar=bar;
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
if(!show_free_mem)
timedisplay();
#ifndef __FLAT__
if(api->mode&UIFC_MOUSE) {
/* ToDo Serious mouse stuff here */
}
#endif
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) {
hidemouse();
gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+3);
textattr(lclr|(bclr<<4));
putch(' '); /* Delete the up arrow */
gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+height-2);
putch(31); /* put the down arrow */
uprintf(SCRN_LEFT+left+3,SCRN_TOP+top+3
,hfclr|(hbclr<<4)
,"%-*.*s",width-4,width-4,option[0]);
for(i=1;i<height-4;i++) /* re-display options */
uprintf(SCRN_LEFT+left+3,SCRN_TOP+top+3+i
,lclr|(bclr<<4)
,"%-*.*s",width-4,width-4,option[i]);
(*cur)=0;
if(bar)
(*bar)=0;
y=top+3;
showmouse();
break;
}
hidemouse();
gettext(SCRN_LEFT+3+left,SCRN_TOP+y
,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
for(i=1;i<width*2;i+=2)
line[i]=lclr|(bclr<<4);
puttext(SCRN_LEFT+3+left,SCRN_TOP+y
,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
(*cur)=0;
if(bar)
(*bar)=0;
y=top+3;
gettext(SCRN_LEFT+3+left,SCRN_TOP+y
,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
for(i=1;i<width*2;i+=2)
line[i]=hfclr|(hbclr<<4);
puttext(SCRN_LEFT+3+left,SCRN_TOP+y
,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
showmouse();
break;
case KEY_UP: /* up arrow */
if(!opts)
break;
if(!(*cur) && opts+4>height) {
hidemouse();
gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+3); /* like end */
textattr(lclr|(bclr<<4));
putch(30); /* put the up arrow */
gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+height-2);
putch(' '); /* delete the down arrow */
for(i=(opts+4)-height,j=0;i<opts;i++,j++)
uprintf(SCRN_LEFT+left+3,SCRN_TOP+top+3+j
,i==opts-1 ? hfclr|(hbclr<<4)
: lclr|(bclr<<4)
,"%-*.*s",width-4,width-4,option[i]);
(*cur)=opts-1;
if(bar)
(*bar)=height-5;
y=top+height-2;
showmouse();
break;
}
hidemouse();
gettext(SCRN_LEFT+3+left,SCRN_TOP+y
,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
for(i=1;i<width*2;i+=2)
line[i]=lclr|(bclr<<4);
puttext(SCRN_LEFT+3+left,SCRN_TOP+y
,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
showmouse();
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 */
hidemouse();
if(!(*cur)) {
gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+3);
textattr(lclr|(bclr<<4));
putch(' '); /* delete the up arrow */
}
if((*cur)+height-4==opts-1) {
gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+height-2);
textattr(lclr|(bclr<<4));
putch(31); /* put the dn arrow */
}
y++;
scroll_text(SCRN_LEFT+left+2,SCRN_TOP+top+3
,SCRN_LEFT+left+width-3,SCRN_TOP+top+height-2,1);
uprintf(SCRN_LEFT+left+3,SCRN_TOP+top+3
,hfclr|(hbclr<<4)
,"%-*.*s",width-4,width-4,option[*cur]);
showmouse();
}
else {
hidemouse();
gettext(SCRN_LEFT+3+left,SCRN_TOP+y
,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
for(i=1;i<width*2;i+=2)
line[i]=hfclr|(hbclr<<4);
puttext(SCRN_LEFT+3+left,SCRN_TOP+y
,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
showmouse();
}
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);
hidemouse();
gettext(SCRN_LEFT+3+left,SCRN_TOP+y
,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
for(i=1;i<width*2;i+=2)
line[i]=lclr|(bclr<<4);
puttext(SCRN_LEFT+3+left,SCRN_TOP+y
,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
for(i=(opts+4)-height,j=0;i<opts;i++,j++)
uprintf(SCRN_LEFT+left+3,SCRN_TOP+top+3+j
,i==(*cur) hfclr|(hbclr<<4) : lclr|(bclr<<4)
,"%-*.*s",width-4,width-4,option[i]);
y=top+height-2;
if(bar)
(*bar)=height-5;
gettext(SCRN_LEFT+3+left,SCRN_TOP+y
,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
for(i=1;i<148;i+=2)
line[i]=hfclr|(hbclr<<4);
puttext(SCRN_LEFT+3+left,SCRN_TOP+y
,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
showmouse();
break;
#endif
case KEY_END: /* end */
if(!opts)
break;
if(opts+4>height) { /* Scroll mode */
hidemouse();
gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+3);
textattr(lclr|(bclr<<4));
putch(30); /* put the up arrow */
gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+height-2);
putch(' '); /* delete the down arrow */
for(i=(opts+4)-height,j=0;i<opts;i++,j++)
uprintf(SCRN_LEFT+left+3,SCRN_TOP+top+3+j
,i==opts-1 ? hfclr|(hbclr<<4)
: lclr|(bclr<<4)
,"%-*.*s",width-4,width-4,option[i]);
(*cur)=opts-1;
y=top+height-2;
if(bar)
(*bar)=height-5;
showmouse();
break;
}
hidemouse();
gettext(SCRN_LEFT+3+left,SCRN_TOP+y
,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
for(i=1;i<width*2;i+=2)
line[i]=lclr|(bclr<<4);
puttext(SCRN_LEFT+3+left,SCRN_TOP+y
,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
(*cur)=opts-1;
y=top+height-2;
if(bar)
(*bar)=height-5;
gettext(SCRN_LEFT+3+left,SCRN_TOP+y
,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
for(i=1;i<148;i+=2)
line[i]=hfclr|(hbclr<<4);
puttext(SCRN_LEFT+3+left,SCRN_TOP+y
,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
showmouse();
break;
case KEY_DOWN: /* dn arrow */
if(!opts)
break;
if((*cur)==opts-1 && opts+4>height) { /* like home */
hidemouse();
gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+3);
textattr(lclr|(bclr<<4));
putch(' '); /* Delete the up arrow */
gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+height-2);
putch(31); /* put the down arrow */
uprintf(SCRN_LEFT+left+3,SCRN_TOP+top+3
,hfclr|(hbclr<<4)
,"%-*.*s",width-4,width-4,option[0]);
for(i=1;i<height-4;i++) /* re-display options */
uprintf(SCRN_LEFT+left+3,SCRN_TOP+top+3+i
,lclr|(bclr<<4)
,"%-*.*s",width-4,width-4,option[i]);
(*cur)=0;
y=top+3;
if(bar)
(*bar)=0;
showmouse();
break;
}
hidemouse();
gettext(SCRN_LEFT+3+left,SCRN_TOP+y
,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
for(i=1;i<width*2;i+=2)
line[i]=lclr|(bclr<<4);
puttext(SCRN_LEFT+3+left,SCRN_TOP+y
,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
showmouse();
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 */
hidemouse();
if(*cur==opts-1) {
gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+height-2);
textattr(lclr|(bclr<<4));
putch(' '); /* delete the down arrow */
}
if((*cur)+4==height) {
gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+3);
textattr(lclr|(bclr<<4));
putch(30); /* put the up arrow */
}
y--;
/* gotoxy(1,1); cprintf("\rdebug: %4d ",__LINE__); */
scroll_text(SCRN_LEFT+left+2,SCRN_TOP+top+3
,SCRN_LEFT+left+width-3,SCRN_TOP+top+height-2,0);
/* gotoxy(1,1); cprintf("\rdebug: %4d ",__LINE__); */
uprintf(SCRN_LEFT+left+3,SCRN_TOP+top+height-2
,hfclr|(hbclr<<4)
,"%-*.*s",width-4,width-4,option[*cur]);
showmouse();
}
else {
hidemouse();
gettext(SCRN_LEFT+3+left,SCRN_TOP+y
,SCRN_LEFT+left+width-2,SCRN_TOP+y
,line);
for(i=1;i<width*2;i+=2)
line[i]=hfclr|(hbclr<<4);
puttext(SCRN_LEFT+3+left,SCRN_TOP+y
,SCRN_LEFT+left+width-2,SCRN_TOP+y
,line);
showmouse();
}
break;
case KEY_F(1): /* F1 */
help();
break;
case KEY_F(5): /* F5 */
if(mode&WIN_GET && !(mode&WIN_XTR && (*cur)==opts-1)) {
return((*cur)|MSK_GET);
}
break;
case KEY_F(6): /* F6 */
if(mode&WIN_PUT && !(mode&WIN_XTR && (*cur)==opts-1)) {
return((*cur)|MSK_PUT);
}
break;
case KEY_IC: /* insert */
if(mode&WIN_INS) {
if(mode&WIN_INSACT) {
hidemouse();
gettext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT
+left+width-1,SCRN_TOP+top+height-1,win);
for(i=1;i<(width*height*2);i+=2)
win[i]=lclr|(cclr<<4);
if(opts) {
j=(((y-top)*width)*2)+7+((width-4)*2);
for(i=(((y-top)*width)*2)+7;i<j;i+=2)
win[i]=hclr|(cclr<<4);
}
puttext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT
+left+width-1,SCRN_TOP+top+height-1,win);
showmouse();
}
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) {
hidemouse();
gettext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT
+left+width-1,SCRN_TOP+top+height-1,win);
for(i=1;i<(width*height*2);i+=2)
win[i]=lclr|(cclr<<4);
j=(((y-top)*width)*2)+7+((width-4)*2);
for(i=(((y-top)*width)*2)+7;i<j;i+=2)
win[i]=hclr|(cclr<<4);
puttext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT
+left+width-1,SCRN_TOP+top+height-1,win);
showmouse();
}
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
&& ((!a && s && !strncasecmp(option[j]+b,search,s+1))
|| ((a || !s) && toupper(option[j][b])==toupper(i)))) {
if(a) s=0;
else s++;
if(y+(j-(*cur))+2>height+top) {
(*cur)=j;
gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+3);
textattr(lclr|(bclr<<4));
putch(30); /* put the up arrow */
if((*cur)==opts-1) {
gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+height-2);
putch(' '); /* delete the down arrow */
}
for(i=((*cur)+5)-height,j=0;i<(*cur)+1;i++,j++)
uprintf(SCRN_LEFT+left+3,SCRN_TOP+top+3+j
,i==(*cur) ? hfclr|(hbclr<<4)
: 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;
gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+3);
textattr(lclr|(bclr<<4));
if(!(*cur))
putch(' '); /* Delete the up arrow */
gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+height-2);
putch(31); /* put the down arrow */
uprintf(SCRN_LEFT+left+3,SCRN_TOP+top+3
,hfclr|(hbclr<<4)
,"%-*.*s",width-4,width-4,option[(*cur)]);
for(i=1;i<height-4;i++) /* re-display options */
uprintf(SCRN_LEFT+left+3,SCRN_TOP+top+3+i
,lclr|(bclr<<4)
,"%-*.*s",width-4,width-4
,option[(*cur)+i]);
y=top+3;
if(bar)
(*bar)=0;
break;
}
hidemouse();
gettext(SCRN_LEFT+3+left,SCRN_TOP+y
,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
for(i=1;i<width*2;i+=2)
line[i]=lclr|(bclr<<4);
puttext(SCRN_LEFT+3+left,SCRN_TOP+y
,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
if((*cur)>j)
y-=(*cur)-j;
else
y+=j-(*cur);
if(bar) {
if((*cur)>j)
(*bar)-=(*cur)-j;
else
(*bar)+=j-(*cur);
}
(*cur)=j;
gettext(SCRN_LEFT+3+left,SCRN_TOP+y
,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
for(i=1;i<width*2;i+=2)
line[i]=hfclr|(hbclr<<4);
puttext(SCRN_LEFT+3+left,SCRN_TOP+y
,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
showmouse();
break;
}
}
if(a==2)
s=0;
}
else
switch(i) {
case CR:
if(!opts || (mode&WIN_XTR && (*cur)==opts-1))
break;
if(mode&WIN_ACT) {
hidemouse();
gettext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT
+left+width-1,SCRN_TOP+top+height-1,win);
for(i=1;i<(width*height*2);i+=2)
win[i]=lclr|(cclr<<4);
j=(((y-top)*width)*2)+7+((width-4)*2);
for(i=(((y-top)*width)*2)+7;i<j;i+=2)
win[i]=hclr|(cclr<<4);
puttext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT
+left+width-1,SCRN_TOP+top+height-1,win);
showmouse();
}
else if(mode&WIN_SAV) {
hidemouse();
puttext(sav[api->savnum].left,sav[api->savnum].top
,sav[api->savnum].right,sav[api->savnum].bot
,sav[api->savnum].buf);
showmouse();
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)) {
hidemouse();
gettext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT
+left+width-1,SCRN_TOP+top+height-1,win);
for(i=1;i<(width*height*2);i+=2)
win[i]=lclr|(cclr<<4);
puttext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT
+left+width-1,SCRN_TOP+top+height-1,win);
showmouse();
}
else if(mode&WIN_SAV) {
hidemouse();
puttext(sav[api->savnum].left,sav[api->savnum].top
,sav[api->savnum].right,sav[api->savnum].bot
,sav[api->savnum].buf);
showmouse();
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;
hidemouse();
reset_dynamic();
plen=strlen(prompt);
if(!plen)
slen=4;
else
slen=6;
width=plen+slen+max;
if(mode&WIN_T2B)
top=(api->scrn_len/2)-(height/2)-2;
if(mode&WIN_L2R)
left=36-(width/2);
if(mode&WIN_SAV)
gettext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT+left+width+1
,SCRN_TOP+top+height,save_buf);
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++]=' ';
in_win[i++]=lclr|(bclr<<4);
}
for(c=0;prompt[c];c++) {
in_win[i++]=prompt[c];
in_win[i++]=lclr|(bclr<<4);
}
if(plen) {
in_win[i++]=':';
in_win[i++]=lclr|(bclr<<4);
c++;
}
for(c=0;c<max+2;c++) {
in_win[i++]=' ';
in_win[i++]=lclr|(bclr<<4);
}
in_win[i++]='';
in_win[i++]=hclr|(bclr<<4);
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);
puttext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT+left+width-1
,SCRN_TOP+top+height-1,in_win);
if(bclr==BLUE) {
gettext(SCRN_LEFT+left+width,SCRN_TOP+top+1,SCRN_LEFT+left+width+1
,SCRN_TOP+top+(height-1),shade);
for(c=1;c<12;c+=2)
shade[c]=DARKGRAY;
puttext(SCRN_LEFT+left+width,SCRN_TOP+top+1,SCRN_LEFT+left+width+1
,SCRN_TOP+top+(height-1),shade);
gettext(SCRN_LEFT+left+2,SCRN_TOP+top+3,SCRN_LEFT+left+width+1
,SCRN_TOP+top+height,shade);
for(c=1;c<width*2;c+=2)
shade[c]=DARKGRAY;
puttext(SCRN_LEFT+left+2,SCRN_TOP+top+3,SCRN_LEFT+left+width+1
,SCRN_TOP+top+height,shade);
}
textattr(lclr|(bclr<<4));
if(!plen)
gotoxy(SCRN_LEFT+left+2,SCRN_TOP+top+1);
else
gotoxy(SCRN_LEFT+left+plen+4,SCRN_TOP+top+1);
i=ugetstr(str,max,kmode);
if(mode&WIN_SAV)
puttext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT+left+width+1
,SCRN_TOP+top+height,save_buf);
showmouse();
return(i);
}
/****************************************************************************/
/* Displays the message 'str' and waits for the user to select "OK" */
/****************************************************************************/
void umsg(char *str)
{
int i=0;
char *ok[2]={"OK",""};
if(api->mode&UIFC_INMSG) /* non-cursive */
return;
api->mode|=UIFC_INMSG;
if(api->savdepth) api->savnum++;
ulist(WIN_SAV|WIN_MID,0,0,0,&i,0,str,ok);
if(api->savdepth) api->savnum--;
api->mode&=~UIFC_INMSG;
}
/****************************************************************************/
/* Gets a string of characters from the user. Turns cursor on. Allows */
/* Different modes - K_* macros. ESC aborts input. */
/* Cursor should be at END of where string prompt will be placed. */
/****************************************************************************/
static int ugetstr(char *outstr, int max, long mode)
{
uchar str[256],ins=0,buf[256],y;
int ch;
int i,j,k,f=0; /* i=offset, j=length */
#ifndef __FLAT__
union REGS r;
#endif
curs_set(1);
y=wherey();
if(mode&K_EDIT && outstr[0]) {
/***
truncsp(outstr);
***/
outstr[max]=0;
textattr(hfclr|(hbclr<<4));
cputs(outstr);
textattr(lclr|(bclr<<4));
strcpy(str,outstr);
i=j=strlen(str);
#if 0
while(inkey(1)==0) {
#ifndef __FLAT__
if(api->mode&UIFC_MOUSE) {
/* ToDo More mouse stuff */
}
#endif
mswait(1);
}
#endif
f=inkey(0);
gotoxy(wherex()-i,y);
if(f == CR || f >= 0xff)
{
cputs(outstr);
}
else
{
cprintf("%*s",i,"");
gotoxy(wherex()-i,y);
i=j=0;
}
}
else
i=j=0;
ch=0;
while(ch!=CR)
{
if(i>j) j=i;
#ifndef __FLAT__
if(api->mode&UIFC_MOUSE)
{
/* ToDo More Mouse Stuff */
}
#endif
if(f || inkey(1))
{
if(f)
ch=f;
else
ch=inkey(0);
f=0;
switch(ch)
{
case KEY_F(1): /* F1 Help */
help();
continue;
case KEY_LEFT: /* left arrow */
if(i)
{
gotoxy(wherex()-1,y);
i--;
}
continue;
case KEY_RIGHT: /* right arrow */
if(i<j)
{
gotoxy(wherex()+1,y);
i++;
}
continue;
case KEY_HOME: /* home */
if(i)
{
gotoxy(wherex()-i,y);
i=0;
}
continue;
case KEY_END: /* end */
if(i<j)
{
gotoxy(wherex()+(j-i),y);
i=j;
}
continue;
case KEY_IC: /* insert */
ins=!ins;
if(ins)
{
curs_set(2);
refresh();
}
else
{
curs_set(1);
refresh();
}
continue;
case BS:
case KEY_BACKSPACE:
if(i)
{
if(i==j)
{
cputs("\b \b");
j--;
i--;
}
else {
gettext(wherex(),y,wherex()+(j-i),y,buf);
puttext(wherex()-1,y,wherex()+(j-i)-1,y,buf);
gotoxy(wherex()+(j-i),y);
putch(' ');
gotoxy(wherex()-((j-i)+2),y);
i--;
j--;
for(k=i;k<j;k++)
str[k]=str[k+1];
}
continue;
}
case KEY_DC: /* delete */
if(i<j)
{
gettext(wherex()+1,y,wherex()+(j-i),y,buf);
puttext(wherex(),y,wherex()+(j-i)-1,y,buf);
gotoxy(wherex()+(j-i),y);
putch(' ');
gotoxy(wherex()-((j-i)+1),y);
for(k=i;k<j;k++)
str[k]=str[k+1];
j--;
}
continue;
case 3:
case ESC:
{
curs_set(0);
refresh();
return(-1);
}
case CR:
break;
case 24: /* ctrl-x */
if(j)
{
gotoxy(wherex()-i,y);
cprintf("%*s",j,"");
gotoxy(wherex()-j,y);
i=j=0;
}
continue;
case 25: /* ctrl-y */
if(i<j)
{
cprintf("%*s",(j-i),"");
gotoxy(wherex()-(j-i),y);
j=i;
}
continue;
}
if(mode&K_NUMBER && !isdigit(ch))
continue;
if(mode&K_ALPHA && !isalpha(ch))
continue;
if((ch>=' ' || (ch==1 && mode&K_MSG)) && i<max && (!ins || j<max) && isprint(ch))
{
if(mode&K_UPPER)
ch=toupper(ch);
if(ins)
{
gettext(wherex(),y,wherex()+(j-i),y,buf);
puttext(wherex()+1,y,wherex()+(j-i)+1,y,buf);
for(k=++j;k>i;k--)
str[k]=str[k-1];
}
putch(ch);
str[i++]=ch;
}
}
else
mswait(1);
}
str[j]=0;
if(mode&K_EDIT)
{
truncsp(str);
if(strcmp(outstr,str))
api->changes=1;
}
else
{
if(j)
api->changes=1;
}
strcpy(outstr,str);
curs_set(0);
refresh();
return(j);
}
/****************************************************************************/
/* Performs printf() through puttext() routine */
/****************************************************************************/
static int uprintf(int x, int y, unsigned char attr, char *fmat, ...)
{
va_list argptr;
char str[256],buf[512];
int i,j;
va_start(argptr,fmat);
vsprintf(str,fmat,argptr);
va_end(argptr);
for(i=j=0;str[i];i++) {
buf[j++]=str[i];
buf[j++]=attr;
}
puttext(x,y,x+(i-1),y,buf);
return(i);
}
/****************************************************************************/
/* Display bottom line of screen in inverse */
/****************************************************************************/
void bottomline(int line)
{
int i=4;
uprintf(i,api->scrn_len+1,bclr|(cclr<<4),"F1 ");
i+=3;
uprintf(i,api->scrn_len+1,BLACK|(cclr<<4),"Help ");
i+=6;
if(line&BL_GET) {
uprintf(i,api->scrn_len+1,bclr|(cclr<<4),"F5 ");
i+=3;
uprintf(i,api->scrn_len+1,BLACK|(cclr<<4),"Copy Item ");
i+=11;
}
if(line&BL_PUT) {
uprintf(i,api->scrn_len+1,bclr|(cclr<<4),"F6 ");
i+=3;
uprintf(i,api->scrn_len+1,BLACK|(cclr<<4),"Paste ");
i+=7;
}
if(line&BL_INS) {
uprintf(i,api->scrn_len+1,bclr|(cclr<<4),"INS ");
i+=4;
uprintf(i,api->scrn_len+1,BLACK|(cclr<<4),"Add Item ");
i+=10;
}
if(line&BL_DEL) {
uprintf(i,api->scrn_len+1,bclr|(cclr<<4),"DEL ");
i+=4;
uprintf(i,api->scrn_len+1,BLACK|(cclr<<4),"Delete Item ");
i+=13;
}
uprintf(i,api->scrn_len+1,bclr|(cclr<<4),"ESC "); /* Backspace is no good no way to abort editing */
i+=4;
uprintf(i,api->scrn_len+1,BLACK|(cclr<<4),"Exit");
i+=4;
gotoxy(i,api->scrn_len+1);
textattr(BLACK|(cclr<<4));
clrtoeol();
}
/*****************************************************************************/
/* Generates a 24 character ASCII string that represents the time_t pointer */
/* Used as a replacement for ctime() */
/*****************************************************************************/
char *utimestr(time_t *intime)
{
static char str[25];
char wday[4],mon[4],mer[3],hour;
struct tm *gm;
gm=localtime(intime);
switch(gm->tm_wday) {
case 0:
strcpy(wday,"Sun");
break;
case 1:
strcpy(wday,"Mon");
break;
case 2:
strcpy(wday,"Tue");
break;
case 3:
strcpy(wday,"Wed");
break;
case 4:
strcpy(wday,"Thu");
break;
case 5:
strcpy(wday,"Fri");
break;
case 6:
strcpy(wday,"Sat");
break;
}
switch(gm->tm_mon) {
case 0:
strcpy(mon,"Jan");
break;
case 1:
strcpy(mon,"Feb");
break;
case 2:
strcpy(mon,"Mar");
break;
case 3:
strcpy(mon,"Apr");
break;
case 4:
strcpy(mon,"May");
break;
case 5:
strcpy(mon,"Jun");
break;
case 6:
strcpy(mon,"Jul");
break;
case 7:
strcpy(mon,"Aug");
break;
case 8:
strcpy(mon,"Sep");
break;
case 9:
strcpy(mon,"Oct");
break;
case 10:
strcpy(mon,"Nov");
break;
case 11:
strcpy(mon,"Dec");
break;
}
if(gm->tm_hour>12) {
strcpy(mer,"pm");
hour=gm->tm_hour-12;
}
else {
if(!gm->tm_hour)
hour=12;
else
hour=gm->tm_hour;
strcpy(mer,"am");
}
sprintf(str,"%s %s %02d %4d %02d:%02d %s",wday,mon,gm->tm_mday,1900+gm->tm_year
,hour,gm->tm_min,mer);
return(str);
}
/****************************************************************************/
/* Status popup/down function, see uifc.h for details. */
/****************************************************************************/
void upop(char *str)
{
static char sav[26*3*2];
char buf[26*3*2];
int i,j,k;
reset_dynamic();
hidemouse();
if(!str) {
puttext(28,12,53,14,sav);
showmouse();
return;
}
gettext(28,12,53,14,sav);
memset(buf,' ',25*3*2);
for(i=1;i<26*3*2;i+=2)
buf[i]=(hclr|(bclr<<4));
buf[0]='';
for(i=2;i<25*2;i+=2)
buf[i]='';
buf[i]=''; i+=2;
buf[i]=''; i+=2;
i+=2;
k=strlen(str);
i+=(((23-k)/2)*2);
for(j=0;j<k;j++,i+=2) {
buf[i]=str[j];
buf[i+1]|=BLINK;
}
i=((25*2)+1)*2;
buf[i]=''; i+=2;
buf[i]=''; i+=2;
for(;i<((26*3)-1)*2;i+=2)
buf[i]='';
buf[i]='';
puttext(28,12,53,14,buf);
showmouse();
}
/****************************************************************************/
/* Sets the current help index by source code file and line number. */
/****************************************************************************/
void sethelp(int line, char* file)
{
helpline=line;
helpfile=file;
}
/****************************************************************************/
/* Shows a scrollable text buffer - optionally parsing "help markup codes" */
/****************************************************************************/
void showbuf(int mode, int left, int top, int width, int height, char *title, char *hbuf, int *curp, int *barp)
{
char *savscrn,inverse=0,high=0;
char *buf;
char *textbuf;
char *p;
uint i,j,k,len;
int old_curs;
int lines;
#ifndef __FLAT__
union REGS r;
#endif
int pad=1;
int is_redraw=0;
if(top+height>api->scrn_len-3)
height=(api->scrn_len-3)-top;
if(!width || width<strlen(title)+6)
width=strlen(title)+6;
if(width>api->scrn_width)
width=api->scrn_width;
if(mode&WIN_L2R)
left=(api->scrn_width-width)/2+1;
else if(mode&WIN_RHT)
left=api->scrn_width-(width+4+left);
if(mode&WIN_T2B)
top=(api->scrn_len/2)-(height/2)-2;
else if(mode&WIN_BOT)
top=api->scrn_len-height-3-top;
if(mode&WIN_PACK)
pad=0;
old_curs=curs_set(0);
/* Dynamic Menus */
if(mode&WIN_DYN
&& curp != NULL
&& barp != NULL
&& last_menu_cur==curp
&& last_menu_bar==barp
&& save_menu_cur==*curp
&& save_menu_bar==*barp)
is_redraw=1;
if((savscrn=(char *)MALLOC(api->scrn_width*api->scrn_len*2))==NULL) {
cprintf("UIFC line %d: error allocating %u bytes\r\n"
,__LINE__,api->scrn_width*25*2);
curs_set(1);
return;
}
if((buf=(char *)MALLOC(width*height*2))==NULL) {
cprintf("UIFC line %d: error allocating %u bytes\r\n"
,__LINE__,width*21*2);
FREE(savscrn);
curs_set(1);
return;
}
hidemouse();
gettext(1,1,api->scrn_width,api->scrn_len,savscrn);
if(!is_redraw) {
memset(buf,' ',width*height*2);
for(i=1;i<width*height*2;i+=2)
buf[i]=(hclr|(bclr<<4));
buf[0]='';
j=strlen(title);
if(j>width-6)
*(title+width-6)=0;
for(i=2;i<((width-6)/2-(j/2))*2;i+=2)
buf[i]='';
buf[i]=''; i+=4;
for(p=title;*p;p++) {
buf[i]=*p;
i+=2;
}
i+=2;
buf[i]=''; i+=2;
for(j=i;j<((width-1)*2);j+=2)
buf[j]='';
i=j;
buf[i]=''; i+=2;
j=i; /* leave i alone */
for(k=0;k<(height-2);k++) { /* the sides of the box */
buf[j]=''; j+=2;
j+=((width-2)*2);
buf[j]=''; j+=2;
}
buf[j]=''; j+=2;
if(!(mode&WIN_DYN) && (width>31)) {
for(k=j;k<j+(((width-4)/2-13)*2);k+=2)
buf[k]='';
buf[k]=''; k+=4;
buf[k]='H'; k+=2;
buf[k]='i'; k+=2;
buf[k]='t'; k+=4;
buf[k]='a'; k+=2;
buf[k]='n'; k+=2;
buf[k]='y'; k+=4;
buf[k]='k'; k+=2;
buf[k]='e'; k+=2;
buf[k]='y'; k+=4;
buf[k]='t'; k+=2;
buf[k]='o'; k+=4;
buf[k]='c'; k+=2;
buf[k]='o'; k+=2;
buf[k]='n'; k+=2;
buf[k]='t'; k+=2;
buf[k]='i'; k+=2;
buf[k]='n'; k+=2;
buf[k]='u'; k+=2;
buf[k]='e'; k+=4;
buf[k]=''; k+=2;
for(j=k;j<k+(((width-4)/2-12)*2);j+=2)
buf[j]='';
}
else {
for(k=j;k<j+((width-2)*2);k+=2)
buf[k]='';
j=k;
}
buf[j]='';
puttext(left,top+1,left+width-1,top+height,buf);
}
len=strlen(hbuf);
i=0;
lines=1; /* The first one is free */
k=0;
for(j=0;j<len;j++) {
k++;
if(hbuf[j]==LF)
lines++;
if(k>72) {
k=0;
lines++;
}
}
if(lines < height-2-pad-pad)
lines=height-2-pad-pad;
if((buf=(char *)textbuf=MALLOC((width-2-pad-pad)*lines*2))==NULL) {
cprintf("UIFC line %d: error allocating %u bytes\r\n"
,__LINE__,(width-2-pad-pad)*lines*2);
FREE(savscrn);
FREE(buf);
curs_set(1);
return;
}
memset(textbuf,' ',(width-2-pad-pad)*lines*2);
for(i=1;i<(width-2-pad-pad)*lines*2;i+=2)
buf[i]=(hclr|(bclr<<4));
i=0;
for(j=0;j<len;j++,i+=2) {
if(hbuf[j]==LF) {
i+=2;
while(i%((width-2-pad-pad)*2)) i++; i-=2;
}
else if(mode&WIN_HLP && (hbuf[j]==2 || hbuf[j]=='~')) { /* Ctrl-b toggles inverse */
inverse=!inverse;
i-=2;
}
else if(mode&WIN_HLP && (hbuf[j]==1 || hbuf[j]=='`')) { /* Ctrl-a toggles high intensity */
high=!high;
i-=2;
}
else if(hbuf[j]!=CR) {
textbuf[i]=hbuf[j];
textbuf[i+1]=inverse ? (bclr|(cclr<<4))
: high ? (hclr|(bclr<<4)) : (lclr|(bclr<<4));
}
}
showmouse();
i=0;
p=textbuf;
if(mode&WIN_DYN) {
puttext(left+1+pad,top+2+pad,left+width-2-pad,top+height-1-pad,p);
}
else {
while(i==0) {
puttext(left+1+pad,top+2+pad,left+width-2-pad,top+height-1-pad,p);
if(inkey(1)) {
switch(inkey(0)) {
case KEY_HOME: /* home */
p=textbuf;
break;
case KEY_UP: /* up arrow */
p = p-((width-4)*2);
if(p<textbuf)
p=textbuf;
break;
case KEY_PPAGE: /* PgUp */
p = p-((width-4)*2*(height-5));
if(p<textbuf)
p=textbuf;
break;
case KEY_NPAGE: /* PgDn */
p=p+(width-4)*2*(height-5);
if(p > textbuf+(lines-height+1)*(width-4)*2)
p=textbuf+(lines-height+1)*(width-4)*2;
if(p<textbuf)
p=textbuf;
break;
case KEY_END: /* end */
p=textbuf+(lines-height+1)*(width-4)*2;
if(p<textbuf)
p=textbuf;
break;
case KEY_DOWN: /* dn arrow */
p = p+((width-4)*2);
if(p > textbuf+(lines-height+1)*(width-4)*2)
p=textbuf+(lines-height+1)*(width-4)*2;
if(p<textbuf)
p=textbuf;
break;
default:
i=1;
}
}
mswait(1);
}
#ifndef __FLAT__
if(api->mode&UIFC_MOUSE) {
/* ToDo more mouse stiff */
}
#endif
hidemouse();
puttext(1,1,api->scrn_width,api->scrn_len,savscrn);
showmouse();
}
if(is_redraw) /* Force redraw of menu also. */
reset_dynamic();
FREE(savscrn);
FREE(buf);
if(old_curs != ERR)
curs_set(old_curs);
}
/************************************************************/
/* Help (F1) key function. Uses helpbuf as the help input. */
/************************************************************/
void help()
{
char hbuf[HELPBUF_SIZE],str[256];
char *p;
unsigned short line;
long l;
FILE *fp;
int old_curs;
#ifndef __FLAT__
union REGS r;
#endif
old_curs=curs_set(0);
if(!api->helpbuf) {
if((fp=fopen(api->helpixbfile,"rb"))==NULL)
sprintf(hbuf," ERROR  Cannot open help index:\r\n %s"
,api->helpixbfile);
else {
p=strrchr(helpfile,'/');
if(p==NULL)
p=strrchr(helpfile,'\\');
if(p==NULL)
p=helpfile;
else
p++;
l=-1L;
while(!feof(fp)) {
if(!fread(str,12,1,fp))
break;
str[12]=0;
fread(&line,2,1,fp);
if(stricmp(str,p) || line!=helpline) {
fseek(fp,4,SEEK_CUR);
continue;
}
fread(&l,4,1,fp);
break;
}
fclose(fp);
if(l==-1L)
sprintf(hbuf," ERROR  Cannot locate help key (%s:%u) in:\r\n"
" %s",p,helpline,api->helpixbfile);
else {
if((fp=fopen(api->helpdatfile,"rb"))==NULL)
sprintf(hbuf," ERROR  Cannot open help file:\r\n %s"
,api->helpdatfile);
else {
fseek(fp,l,SEEK_SET);
fread(hbuf,HELPBUF_SIZE,1,fp);
fclose(fp);
}
}
}
}
else
strcpy(hbuf,api->helpbuf);
showbuf(WIN_MID|WIN_HLP, 0, 0, 76, api->scrn_len-2, "Online Help", hbuf, NULL, NULL);
}
static int puttext(int sx, int sy, int ex, int ey, unsigned char *fill)
{
int x,y;
int fillpos=0;
unsigned char attr;
unsigned char fill_char;
unsigned char orig_attr;
int oldx, oldy;
getyx(stdscr,oldy,oldx);
orig_attr=lastattr;
for(y=sy-1;y<=ey-1;y++)
{
for(x=sx-1;x<=ex-1;x++)
{
fill_char=fill[fillpos++];
attr=fill[fillpos++];
textattr(attr);
move(y, x);
_putch(fill_char,FALSE);
}
}
textattr(orig_attr);
move(oldy, oldx);
refresh();
return(1);
}
static int gettext(int sx, int sy, int ex, int ey, unsigned char *fill)
{
int x,y;
int fillpos=0;
chtype attr;
unsigned char attrib;
unsigned char colour;
int oldx, oldy;
unsigned char thischar;
int ext_char;
getyx(stdscr,oldy,oldx);
for(y=sy-1;y<=ey-1;y++)
{
for(x=sx-1;x<=ex-1;x++)
{
attr=mvinch(y, x);
if(attr&A_ALTCHARSET && !(api->mode&UIFC_IBM)){
ext_char=A_ALTCHARSET|(attr&255);
/* likely ones */
if (ext_char == ACS_CKBOARD)
{
thischar=176;
}
else if (ext_char == ACS_BOARD)
{
thischar=177;
}
else if (ext_char == ACS_BSSB)
{
thischar=218;
}
else if (ext_char == ACS_SSBB)
{
thischar=192;
}
else if (ext_char == ACS_BBSS)
{
thischar=191;
}
else if (ext_char == ACS_SBBS)
{
thischar=217;
}
else if (ext_char == ACS_SBSS)
{
thischar=180;
}
else if (ext_char == ACS_SSSB)
{
thischar=195;
}
else if (ext_char == ACS_SSBS)
{
thischar=193;
}
else if (ext_char == ACS_BSSS)
{
thischar=194;
}
else if (ext_char == ACS_BSBS)
{
thischar=196;
}
else if (ext_char == ACS_SBSB)
{
thischar=179;
}
else if (ext_char == ACS_SSSS)
{
thischar=197;
}
else if (ext_char == ACS_BLOCK)
{
thischar=219;
}
else if (ext_char == ACS_UARROW)
{
thischar=30;
}
else if (ext_char == ACS_DARROW)
{
thischar=31;
}
/* unlikely (Not in ncurses) */
else if (ext_char == ACS_SBSD)
{
thischar=181;
}
else if (ext_char == ACS_DBDS)
{
thischar=182;
}
else if (ext_char == ACS_BBDS)
{
thischar=183;
}
else if (ext_char == ACS_BBSD)
{
thischar=184;
}
else if (ext_char == ACS_DBDD)
{
thischar=185;
}
else if (ext_char == ACS_DBDB)
{
thischar=186;
}
else if (ext_char == ACS_BBDD)
{
thischar=187;
}
else if (ext_char == ACS_DBBD)
{
thischar=188;
}
else if (ext_char == ACS_DBBS)
{
thischar=189;
}
else if (ext_char == ACS_SBBD)
{
thischar=190;
}
else if (ext_char == ACS_SDSB)
{
thischar=198;
}
else if (ext_char == ACS_DSDB)
{
thischar=199;
}
else if (ext_char == ACS_DDBB)
{
thischar=200;
}
else if (ext_char == ACS_BDDB)
{
thischar=201;
}
else if (ext_char == ACS_DDBD)
{
thischar=202;
}
else if (ext_char == ACS_BDDD)
{
thischar=203;
}
else if (ext_char == ACS_DDDB)
{
thischar=204;
}
else if (ext_char == ACS_BDBD)
{
thischar=205;
}
else if (ext_char == ACS_DDDD)
{
thischar=206;
}
else if (ext_char == ACS_SDBD)
{
thischar=207;
}
else if (ext_char == ACS_DSBS)
{
thischar=208;
}
else if (ext_char == ACS_BDSD)
{
thischar=209;
}
else if (ext_char == ACS_BSDS)
{
thischar=210;
}
else if (ext_char == ACS_DSBB)
{
thischar=211;
}
else if (ext_char == ACS_SDBB)
{
thischar=212;
}
else if (ext_char == ACS_BDSB)
{
thischar=213;
}
else if (ext_char == ACS_BSDB)
{
thischar=214;
}
else if (ext_char == ACS_DSDS)
{
thischar=215;
}
else if (ext_char == ACS_SDSD)
{
thischar=216;
}
else
{
thischar=attr&255;
}
}
else
thischar=attr;
fill[fillpos++]=(unsigned char)(thischar);
attrib=0;
if (attr & A_BOLD)
{
attrib |= 8;
}
if (attr & A_BLINK)
{
attrib |= 128;
}
colour=PAIR_NUMBER(attr&A_COLOR)-1;
colour=((colour&56)<<1)|(colour&7);
fill[fillpos++]=colour|attrib;
}
}
move(oldy, oldx);
return(1);
}
static void textattr(unsigned char attr)
{
int attrs=A_NORMAL;
short colour;
if (lastattr==attr)
return;
lastattr=attr;
if (attr & 8) {
attrs |= A_BOLD;
}
if (attr & 128)
{
attrs |= A_BLINK;
}
attrset(attrs);
colour = COLOR_PAIR( ((attr&7)|((attr>>1)&56))+1 );
#ifdef NCURSES_VERSION_MAJOR
color_set(colour,NULL);
#endif
bkgdset(colour);
}
static int kbhit(void)
{
struct timeval timeout;
fd_set rfds;
timeout.tv_sec=1;
timeout.tv_usec=0;
FD_ZERO(&rfds);
FD_SET(fileno(stdin),&rfds);
return(select(fileno(stdin)+1,&rfds,NULL,NULL,&timeout));
}
#ifndef __QNX__
static void delay(msec)
{
usleep(msec*1000);
}
#endif
static int wherey(void)
{
int x,y;
getyx(stdscr,y,x);
return(y+1);
}
static int wherex(void)
{
int x,y;
getyx(stdscr,y,x);
return(x+1);
}
static void _putch(unsigned char ch, BOOL refresh_now)
{
int cha;
if(!(api->mode&UIFC_IBM))
{
switch(ch)
{
case 30:
cha=ACS_UARROW;
break;
case 31:
cha=ACS_DARROW;
break;
case 176:
cha=ACS_CKBOARD;
break;
case 177:
cha=ACS_BOARD;
break;
case 178:
cha=ACS_BOARD;
break;
case 179:
cha=ACS_SBSB;
break;
case 180:
cha=ACS_SBSS;
break;
case 181:
cha=ACS_SBSD;
break;
case 182:
cha=ACS_DBDS;
break;
case 183:
cha=ACS_BBDS;
break;
case 184:
cha=ACS_BBSD;
break;
case 185:
cha=ACS_DBDD;
break;
case 186:
cha=ACS_DBDB;
break;
case 187:
cha=ACS_BBDD;
break;
case 188:
cha=ACS_DBBD;
break;
case 189:
cha=ACS_DBBS;
break;
case 190:
cha=ACS_SBBD;
break;
case 191:
cha=ACS_BBSS;
break;
case 192:
cha=ACS_SSBB;
break;
case 193:
cha=ACS_SSBS;
break;
case 194:
cha=ACS_BSSS;
break;
case 195:
cha=ACS_SSSB;
break;
case 196:
cha=ACS_BSBS;
break;
case 197:
cha=ACS_SSSS;
break;
case 198:
cha=ACS_SDSB;
break;
case 199:
cha=ACS_DSDB;
break;
case 200:
cha=ACS_DDBB;
break;
case 201:
cha=ACS_BDDB;
break;
case 202:
cha=ACS_DDBD;
break;
case 203:
cha=ACS_BDDD;
break;
case 204:
cha=ACS_DDDB;
break;
case 205:
cha=ACS_BDBD;
break;
case 206:
cha=ACS_DDDD;
break;
case 207:
cha=ACS_SDBD;
break;
case 208:
cha=ACS_DSBS;
break;
case 209:
cha=ACS_BDSD;
break;
case 210:
cha=ACS_BSDS;
break;
case 211:
cha=ACS_DSBB;
break;
case 212:
cha=ACS_SDBB;
break;
case 213:
cha=ACS_BDSB;
break;
case 214:
cha=ACS_BSDB;
break;
case 215:
cha=ACS_DSDS;
break;
case 216:
cha=ACS_SDSD;
break;
case 217:
cha=ACS_SBBS;
break;
case 218:
cha=ACS_BSSB;
break;
case 219:
cha=ACS_BLOCK;
break;
default:
cha=ch;
}
}
else
{
switch(ch) {
case 30:
cha=ACS_UARROW;
break;
case 31:
cha=ACS_DARROW;
break;
default:
cha=ch;
}
}
addch(cha);
if(refresh_now)
refresh();
}
static int cprintf(char *fmat, ...)
{
va_list argptr;
char str[MAX_BFLN];
int pos;
va_start(argptr,fmat);
vsprintf(str,fmat,argptr);
va_end(argptr);
for(pos=0;str[pos];pos++)
{
_putch(str[pos],FALSE);
}
refresh();
return(1);
}
static void cputs(char *str)
{
int pos;
for(pos=0;str[pos];pos++)
{
_putch(str[pos],FALSE);
}
refresh();
}
static void gotoxy(int x, int y)
{
move(y-1,x-1);
refresh();
}
/* uifcd.c */
/* Unix libdialog implementation of UIFC library (by Deuce) */
/* $Id$ */
/****************************************************************************
* @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. *
****************************************************************************/
#include "uifc.h"
#include "dialog.h"
static char app_title[81]="";
static char *helpfile=0;
static uint helpline=0;
static uifcapi_t* api;
/* Prototypes */
static void help();
/* 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);
/****************************************************************************/
/* Initialization function, see uifc.h for details. */
/* Returns 0 on success. */
/****************************************************************************/
int uifcinid(uifcapi_t* uifcapi)
{
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;
api->showbuf=NULL;
api->timedisplay=NULL;
setvbuf(stdout,NULL,_IONBF,0);
api->scrn_len=24;
init_dialog();
return(0);
}
/****************************************************************************/
/* Exit/uninitialize UIFC implementation. */
/****************************************************************************/
void uifcbail(void)
{
end_dialog();
}
/****************************************************************************/
/* Clear screen, fill with background attribute, display application title. */
/* Returns 0 on success. */
/****************************************************************************/
int uscrn(char *str)
{
sprintf(app_title,"%.*s",(int)sizeof(app_title)-1,str);
/**********************************************************************/
/* ToDo - Does not display application title... mostly 'cause I clear */
/* the screen so often */
/**********************************************************************/
dialog_clear();
return(0);
}
/**************************************************************************/
/* General menu display function. see uifc.h for details */
/**************************************************************************/
int ulist(int mode, int left, int top, int width, int *cur, int *bar
, char *title, char **option)
{
int cnt;
int cnt2;
int options;
int freecnt;
int i;
int scrollpos;
int height=14; /* default menu height */
size_t app_title_len;
char **it;
char str[128];
char tmpstr[MAX_OPLN+1]; // Used for restoring the <-- At End --> bit
char tmpstr2[MAX_OPLN+1]; // for Add and Paste
int ret;
/* Count number of menu options */
for(cnt=0;cnt<MAX_OPTS;cnt++)
if(option[cnt]==NULL || option[cnt][0]==0)
break;
options=cnt;
freecnt=cnt+5; /* Add, Delete, Copy, Paste, At End */
// Allocate and fill **it
it=(char **)MALLOC(sizeof(char *)*2*(freecnt));
if(it==NULL)
return(-1);
for(i=0;i<freecnt*2;i++) {
it[i]=(char *)MALLOC(MAX_OPLN+1);
if(it[i]==NULL)
return(-1);
}
strcpy(str,"1");
cnt2 = 0;
for(i=0;i<cnt;i++) {
sprintf(it[cnt2++],"%u",i+1);
strcpy(it[cnt2++],option[i]);
/* Adjust width if it's too small */
if(width<strlen(option[i])+12)
width=strlen(option[i])+12;
}
// Make up for expanding first column in width adjustment.
i=cnt;
while(i>9) {
i /= 10;
width+=1;
}
if(mode&WIN_INS) {
strcpy(it[cnt2++],"A"); /* Changed from "I" */
strcpy(it[cnt2++],"Add New");
cnt++;
}
if(mode&WIN_DEL) {
strcpy(it[cnt2++],"D");
strcpy(it[cnt2++],"Delete");
cnt++;
}
if(mode&WIN_GET) {
strcpy(it[cnt2++],"C");
strcpy(it[cnt2++],"Copy");
cnt++;
}
if(mode&WIN_PUT) {
strcpy(it[cnt2++],"P");
strcpy(it[cnt2++],"Paste");
cnt++;
}
if(width<strlen(title)+4)
width=strlen(title)+4;
app_title_len=strlen(app_title);
if(*cur<0 || *cur>cnt)*cur=0;
if(height>cnt)
height=cnt; /* no reason to display overly "tall" menus */
while(1) {
i=*cur;
if(i<0) i=0;
if(cnt==2 && strcmp(option[0],"Yes")==0 && strcmp(option[1],"No")==0) {
if(i==0)
ret=dialog_yesno((char*)NULL,title,5,width);
else
ret=dialog_noyes((char*)NULL,title,5,width);
break;
}
/* make sure we're wide enough to display the application title */
if(width<app_title_len+4)
width=app_title_len+4;
dialog_clear_norefresh();
scrollpos=0;
if(i>=height) // Whenever advanced was returned from, it had something
scrollpos=i-height+1; // Beyond the bottom selected
i=i-scrollpos; // Apparently, *ch is the current position ON THE SCREEN
ret=dialog_menu(app_title, title, height+8, width, height, cnt, it, str, &i, &scrollpos);
if(ret==1) { /* Cancel */
ret = -1;
*cur = -1;
break;
}
if(ret==-1) /* ESC */
break;
if(ret==-2) { /* Help */
help();
continue;
}
if(ret!=0) /* ??? */
continue;
switch(str[0]) {
case 'A': /* Add */
dialog_clear_norefresh();
if(options>0) {
strncpy(tmpstr,it[options*2],MAX_OPLN);
sprintf(it[options*2],"%u",options+1);
strncpy(tmpstr2,it[options*2+1],MAX_OPLN);
strcpy(it[options*2+1],"<-- At End -->");
ret=dialog_menu(title, "Insert Where?", height+8, width, height, options+1, it, str, 0, 0);
strncpy(it[options*2],tmpstr,MAX_OPLN);
strncpy(it[(options*2)+1],tmpstr2,MAX_OPLN);
if(ret==0) {
*cur=atoi(str)-1;
ret=*cur|MSK_INS;
}
}
else {
*cur=0;
ret=MSK_INS;
}
break;
case 'D': /* Delete */
dialog_clear_norefresh();
if(options>0) {
ret=dialog_menu(title, "Delete Which?", height+8, width, height, options, it, str, 0, 0);
if(ret==0) {
*cur=atoi(str)-1;
ret=*cur|MSK_DEL;
}
}
else {
*cur=0;
ret=MSK_DEL;
}
break;
case 'C': /* Copy */
dialog_clear_norefresh();
if(options>0) {
ret=dialog_menu(title, "Copy Which?", height+8, width, height, options, it, str, 0, 0);
if(ret==0) {
*cur=atoi(str)-1;
ret=*cur|MSK_GET;
}
}
else {
*cur=0;
ret=MSK_GET;
}
break;
case 'P': /* Paste */
dialog_clear_norefresh();
if(options>0) {
strncpy(tmpstr,it[options*2],MAX_OPLN);
sprintf(it[options*2],"%u",options+1);
strncpy(tmpstr2,it[options*2+1],MAX_OPLN);
strcpy(it[options*2+1],"<-- At End -->");
ret=dialog_menu(title, "Paste Where?", height+8, width, height, options+1, it, str, 0, 0);
strncpy(it[options*2],tmpstr,MAX_OPLN);
strncpy(it[(options*2)+1],tmpstr2,MAX_OPLN);
if(ret==0) {
*cur=atoi(str)-1;
ret=*cur|MSK_PUT;
}
}
else {
*cur=0;
ret=MSK_PUT;
}
break;
default:
*cur=atoi(str)-1;
ret=*cur;
break;
}
break;
}
// free() the strings!
for(i=0;i<freecnt*2;i++)
free(it[i]);
free(it);
return(ret);
}
/****************************************************************************/
/* Convert ASCIIZ string to upper case */
/****************************************************************************/
#if defined(__unix__)
static char* strupr(char* str)
{
char* p=str;
while(*p) {
*p=toupper(*p);
p++;
}
return(str);
}
#endif
/*************************************************************************/
/* This function is a windowed input string input routine. */
/*************************************************************************/
int uinput(int mode, int left, int top, char *prompt, char *outstr,
int max, int kmode)
{
char str[256];
if(!(kmode&K_EDIT))
outstr[0]=0;
sprintf(str,"%.*s",(int)sizeof(str)-1,outstr);
while(dialog_inputbox((char*)NULL, prompt, 9, max+4, str)==-2)
help();
if(kmode&K_UPPER) /* convert to uppercase? */
strupr(str);
if(strcmp(str,outstr)) { /* changed? */
api->changes=TRUE;
sprintf(outstr,"%.*s",max,str);
}
return strlen(outstr);
}
/****************************************************************************/
/* Displays the message 'str' and waits for the user to select "OK" */
/****************************************************************************/
void umsg(char *str)
{
dialog_mesgbox((char*)NULL, str, 7, strlen(str)+4);
}
/****************************************************************************/
/* Status popup/down function, see uifc.h for details. */
/****************************************************************************/
void upop(char *str)
{
// Pop-down doesn't do much... the mext item should over-write this.
if(str!=NULL)
dialog_gauge((char*)NULL,str,8,20,7,40,0);
}
/****************************************************************************/
/* Sets the current help index by source code file and line number. */
/****************************************************************************/
void sethelp(int line, char* file)
{
helpfile=file;
helpline=line;
}
/************************************************************/
/* Help function. */
/************************************************************/
void help()
{
char hbuf[HELPBUF_SIZE],str[256];
char *p;
unsigned short line;
long l;
FILE *fp;
printf("\n");
if(!api->helpbuf) {
if((fp=fopen(api->helpixbfile,"rb"))==NULL)
sprintf(hbuf,"ERROR: Cannot open help index: %s"
,api->helpixbfile);
else {
p=strrchr(helpfile,'/');
if(p==NULL)
p=strrchr(helpfile,'\\');
if(p==NULL)
p=helpfile;
else
p++;
l=-1L;
while(!feof(fp)) {
if(!fread(str,12,1,fp))
break;
str[12]=0;
fread(&line,2,1,fp);
if(stricmp(str,p) || line!=helpline) {
fseek(fp,4,SEEK_CUR);
continue; }
fread(&l,4,1,fp);
break; }
fclose(fp);
if(l==-1L)
sprintf(hbuf,"ERROR: Cannot locate help key (%s:%u) in: %s"
,p,helpline,api->helpixbfile);
else {
if((fp=fopen(api->helpdatfile,"rb"))==NULL)
sprintf(hbuf,"ERROR: Cannot open help file: %s"
,api->helpdatfile);
else {
fseek(fp,l,SEEK_SET);
fread(hbuf,HELPBUF_SIZE,1,fp);
fclose(fp);
}
}
}
}
else
strcpy(hbuf,api->helpbuf);
dialog_mesgbox((char*)NULL, hbuf, 24, 80);
}
/* uifcfltk.c */
/* X/Windows Implementation of UIFC (user interface) library */
/* $Id$ */
/****************************************************************************
* @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. *
****************************************************************************/
/*********************************************/
/* UIFC Defines specific to the FLTK version */
/*********************************************/
#define MAX_POPUPS 10 // Maximum number of popup()s
#define MAX_WINDOWS 100 // Maximum number of list()s
#define UIFC_CANCEL -1 // Return value for Cancel
#define UIFC_MENU -2 // Keep looping value
#define UIFC_INPUT -3 // Input Box
#define UIFC_HELP -4 // Return value for Help
#define UIFC_RCLICK -5 // Right-click
/***********************
* Fast Light Includes *
***********************/
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Scroll.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Input_.H>
#include <FL/Fl_Text_Display.H>
#include <FL/Fl_Box.H>
#include <FL/fl_ask.H> // fl_beep(), fl_message()
/* How can we tell if the user has num lock down or not? */
#define FL_KP_Home (FL_KP+'7')
#define FL_KP_End (FL_KP+'1')
#define FL_KP_Up (FL_KP+'8')
#define FL_KP_Down (FL_KP+'2')
#define FL_KP_Left (FL_KP+'4')
#define FL_KP_Right (FL_KP+'6')
#define FL_KP_PgUp (FL_KP+'9')
#define FL_KP_PgDn (FL_KP+'3')
#define FL_KP_Ins (FL_KP+'0')
#define FL_KP_Del (FL_KP+'.')
/******************/
/* Layout Defines */
/******************/
#define UIFC_CHAR_WIDTH 8 // Width of one "Character" (Assumes 80x25)
#define UIFC_CHAR_HEIGHT 12 // Height of one Character
#define UIFC_LINE_HEIGHT 16 // Height of one "Line"
#define UIFC_BORDER_WIDTH 2 // Width of a single border
#define UIFC_SCROLL_WIDTH 18 // Width of the scroll bar
#define UIFC_MAIN_BG_COLOR FL_DARK_CYAN
#define UIFC_BORDER_COLOR FL_YELLOW
#define UIFC_BUTTON_TEXT_COLOR FL_WHITE
#define UIFC_BUTTON_COLOR FL_DARK_BLUE
#define UIFC_BUTTON_SELECTED_COLOR FL_BLUE
#define UIFC_WINDOW_TITLE_COLOR FL_YELLOW
#define UIFC_INPUT_WIN_BG_COLOR FL_DARK_BLUE
#define UIFC_INPUT_TEXT_COLOR FL_WHITE
#define UIFC_INPUT_BOX_BG_COLOR FL_DARK_BLUE
#define UIFC_INPUT_PROMPT_COLOR FL_YELLOW
#define UIFC_HELP_PLAIN_COLOR FL_WHITE
#define UIFC_HELP_HIGH_COLOR FL_YELLOW
#define UIFC_HELP_INVERSE_COLOR FL_CYAN
#define UIFC_HELP_BOTH_COLOR FL_MAGENTA
#define UIFC_HELP_WIN_BG_COLOR FL_DARK_BLUE
#define UIFC_LIST_WIN_BG_COLOR FL_DARK_BLUE
#define UIFC_FOREGROUND 255,255,0
#define UIFC_BACKGROUND 0,64,64
#define UIFC_BACKGROUND2 0,0,255
#include <sys/types.h>
#include "uifc.h"
#ifdef __unix__
#include <unistd.h>
#else
#include <stdio.h>
#endif
static char *helpfile=0;
static uint helpline=0;
static uifcapi_t* api;
/* Typedefs */
typedef struct {
int mode;
int max;
Fl_Input_ *InputBox;
} modes_t;
/* Prototypes */
static void help(void);
static void GenCallback(Fl_Widget *, void *);
static void LBCallback(Fl_Widget *, 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);
/* Interal routines */
void delwin(int WinNum);
/* Classes */
class UIFC_PopUp : public Fl_Double_Window {
int handle(int);
public:
UIFC_PopUp(int w,int h,const char *title) : Fl_Double_Window(w,h,title) {
border(FALSE);
box(FL_UP_BOX);
set_modal();
}
};
class UIFC_Button : public Fl_Button {
char uifc_label[MAX_OPLN+1];
public:
int retval;
int mode;
int handle(int);
UIFC_Button(int x,int y,int w,int h,const char *label) : Fl_Button(x,y,w,h,label) {
if(label==NULL)
strcpy(uifc_label,"");
else
strcpy(uifc_label,label);
this->label(uifc_label);
labelfont(FL_COURIER);
labelsize(UIFC_CHAR_HEIGHT);
when(FL_WHEN_RELEASE|FL_WHEN_CHANGED);
box(FL_FLAT_BOX);
if(!(api->mode&UIFC_MONO)) {
color(UIFC_BUTTON_COLOR,UIFC_BUTTON_SELECTED_COLOR);
labelcolor(UIFC_BUTTON_TEXT_COLOR);
}
}
};
class UIFC_Window : public Fl_Double_Window {
public:
UIFC_Window(int x,int y,int w,int h,const char *title) : Fl_Double_Window(x,y,w,h,title) {
box(FL_UP_BOX);
if(!(api->mode&UIFC_MONO))
color(UIFC_LIST_WIN_BG_COLOR);
UIFC_Button *HButton = new UIFC_Button(
w-(UIFC_LINE_HEIGHT*2)+UIFC_BORDER_WIDTH*3,
UIFC_BORDER_WIDTH,
UIFC_LINE_HEIGHT-(UIFC_BORDER_WIDTH*2),
UIFC_LINE_HEIGHT-(UIFC_BORDER_WIDTH*2),
"?");
HButton->box(FL_NO_BOX);
HButton->labelfont(FL_SCREEN);
HButton->labelsize(UIFC_LINE_HEIGHT-(UIFC_BORDER_WIDTH*4));
HButton->callback(GenCallback);
HButton->retval=UIFC_HELP;
HButton->when(FL_WHEN_CHANGED);
if(!(api->mode&UIFC_MONO)) {
HButton->color(FL_BLUE,FL_BLUE);
HButton->labelcolor(UIFC_WINDOW_TITLE_COLOR);
}
UIFC_Button *CButton = new UIFC_Button(
w-(UIFC_LINE_HEIGHT)+UIFC_BORDER_WIDTH,
UIFC_BORDER_WIDTH,
UIFC_LINE_HEIGHT-(UIFC_BORDER_WIDTH*2),
UIFC_LINE_HEIGHT-(UIFC_BORDER_WIDTH*2),
"X");
CButton->box(FL_NO_BOX);
CButton->labelfont(FL_SCREEN);
CButton->labelsize(UIFC_LINE_HEIGHT-(UIFC_BORDER_WIDTH*4));
CButton->callback(GenCallback);
CButton->retval=UIFC_CANCEL;
CButton->when(FL_WHEN_CHANGED);
if(!(api->mode&UIFC_MONO)) {
CButton->color(FL_BLUE,FL_BLUE);
CButton->labelcolor(UIFC_WINDOW_TITLE_COLOR);
}
}
};
class UIFC_Menu : public UIFC_Window {
public:
int *uifc_id;
UIFC_Menu(int x,int y,int w,int h,const char *title,int mode,int opts,int *cur,char **option) : UIFC_Window(x,y,w,h,title) {
UIFC_Button *Button;
Fl_Scroll *SGroup;
int opt=0;
int scrolloffset=0;
uifc_id=cur;
if(opts>20)
scrolloffset=UIFC_SCROLL_WIDTH;
SGroup = new Fl_Scroll(
UIFC_CHAR_WIDTH-UIFC_BORDER_WIDTH,
UIFC_LINE_HEIGHT-UIFC_BORDER_WIDTH,
w-(2*UIFC_CHAR_WIDTH)+(UIFC_BORDER_WIDTH*2),
UIFC_LINE_HEIGHT*(((opts<20)?opts:20))+(UIFC_BORDER_WIDTH*4),
title);
SGroup->box(FL_DOWN_BOX);
SGroup->labelfont(FL_COURIER_BOLD);
SGroup->labelsize(UIFC_CHAR_HEIGHT);
if(!(api->mode&UIFC_MONO)) {
SGroup->labelcolor(UIFC_WINDOW_TITLE_COLOR);
SGroup->color(UIFC_BORDER_COLOR);
}
for(opt=0;option[opt][0];opt++) {
Button=new UIFC_Button(
UIFC_CHAR_WIDTH+UIFC_BORDER_WIDTH,
UIFC_LINE_HEIGHT*(opt+1)+UIFC_BORDER_WIDTH,
w-(2*UIFC_CHAR_WIDTH)-(2*UIFC_BORDER_WIDTH)-scrolloffset,
UIFC_LINE_HEIGHT,
option[opt]);
Button->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE|FL_ALIGN_CENTER);
Button->callback(LBCallback);
Button->retval=opt;
Button->mode=mode;
}
if((mode&WIN_XTR)&&(mode&WIN_INS)) {
Button=new UIFC_Button(
UIFC_CHAR_WIDTH+UIFC_BORDER_WIDTH,
UIFC_LINE_HEIGHT*(opt+1)+UIFC_BORDER_WIDTH,
w-(2*UIFC_CHAR_WIDTH)-(2*UIFC_BORDER_WIDTH)-scrolloffset,
UIFC_LINE_HEIGHT,
NULL);
Button->callback(LBCallback);
Button->retval=opt|MSK_INS;
Button->mode=mode;
opt++;
}
}
};
class UIFC_Input_Box : public Fl_Input_ {
int handle(int);
void draw();
int handle_key();
int shift_position(int);
public:
int mode;
int max;
UIFC_Input_Box(int x,int y,int w,int h,const char *title,int inmode,int inmax,char *outval) : Fl_Input_(x,y,w,h,title) {
mode=inmode;
max=inmax;
if(mode&K_EDIT)
value(outval);
else
value("");
position(strlen(value()));
maximum_size(max);
if(!(api->mode&UIFC_MONO)) {
labelcolor(UIFC_INPUT_PROMPT_COLOR);
color(UIFC_INPUT_BOX_BG_COLOR);
textcolor(UIFC_INPUT_TEXT_COLOR);
}
}
};
class UIFC_Input : public UIFC_Window {
public:
char invalue[256];
UIFC_Input(int x,int y,int w,int h,const char *title,int inmode,int inmax,int len,int width,char *outval) : UIFC_Window(x,y,w,h,title) {
box(FL_UP_BOX);
new UIFC_Input_Box(
UIFC_CHAR_WIDTH*(len+2),
UIFC_LINE_HEIGHT,
(width)*UIFC_CHAR_WIDTH,
UIFC_LINE_HEIGHT,
title,
inmode,
inmax,
outval);
int button_left=w/2-(UIFC_CHAR_WIDTH*10);
UIFC_Button *OkButton = new UIFC_Button(
button_left,
UIFC_LINE_HEIGHT*3,
(8)*UIFC_CHAR_WIDTH,
UIFC_LINE_HEIGHT,
"Ok");
OkButton->callback(GenCallback);
OkButton->retval=0;
UIFC_Button *CancelButton=new UIFC_Button(
button_left+UIFC_CHAR_WIDTH*10,
UIFC_LINE_HEIGHT*3,
(10)*UIFC_CHAR_WIDTH
,UIFC_LINE_HEIGHT
,"Cancel");
CancelButton->retval=UIFC_CANCEL;
CancelButton->shortcut(FL_Escape);
CancelButton->callback(GenCallback);
if(inmode&K_EDIT)
snprintf(invalue,inmax,"%s",outval);
else
invalue[0]=0;
}
};
/* Globals */
Fl_Double_Window *MainWin;
int GUI_RetVal;
UIFC_Menu *Windows[MAX_WINDOWS]; // Array of windows for ulist
int CurrWin; // Current window in array.
int *uifc_cur=NULL; // Current selection.
/*****************************/
/* UIFC_Button ENTER catcher */
/*****************************/
int UIFC_Button::handle(int event) {
if (event == FL_FOCUS) {
if(uifc_cur != NULL)
*uifc_cur=retval&MSK_OFF;
if(!(api->mode&UIFC_MONO))
color(UIFC_BUTTON_SELECTED_COLOR);
Fl_Scroll *s=(Fl_Scroll *)parent();
/******************************************************************************
* This works, it will always work if there is vertical room for at least one *
* button in the scroll box. For gods sake, don't touch this unless you KNOW *
* how it works, and can do it better. *
******************************************************************************/
if(s->type()==Fl_Scroll::BOTH) {
if(y() + h() + Fl::box_dy(box()) + Fl::box_dh(box()) > s->y()+Fl::box_dy(s->box())+s->h()-Fl::box_dh(s->box())) {
// Scroll Down
s->position(0,s->yposition()-(s->y() + Fl::box_dy(s->box()) + s->h() - Fl::box_dh(s->box()) - y() - h() - Fl::box_dy(box()) - Fl::box_dh(box())));
}
if(y() < s->y()+Fl::box_dy(s->box())) {
// Scroll Up
s->position(0,s->yposition()-(s->y() + Fl::box_dy(s->box()) - y()));
}
}
}
else if (event == FL_UNFOCUS) {
if(!(api->mode&UIFC_MONO))
color(UIFC_BUTTON_COLOR);
}
else if (event == FL_KEYBOARD) {
int key=Fl::event_key();
int i;
if (key == FL_Enter || key == FL_KP_Enter) {
do_callback();
return 1;
}
if(key==FL_Page_Up || key==FL_KP_PgUp) {
for(i=0;i<parent()->children() && this!=parent()->child(i);i++) {}
i=i-((parent()->h() - Fl::box_dh(parent()->box()))/UIFC_LINE_HEIGHT)+1;
if(i<0)
i=0;
Fl::focus(parent()->child(i));
parent()->child(i)->handle(FL_FOCUS);
return(1);
}
if(key==FL_Page_Down || key==FL_KP_PgDn) {
for(i=0;i<parent()->children() && this!=parent()->child(i);i++) {}
i=i+((parent()->h() - Fl::box_dh(parent()->box()))/UIFC_LINE_HEIGHT)-1;
if(i>parent()->children()-3)
i=parent()->children()-3;
Fl::focus(parent()->child(i));
parent()->child(i)->handle(FL_FOCUS);
return(1);
}
if(key==FL_Up || key==FL_KP_Up) {
for(i=0;i<parent()->children() && this!=parent()->child(i);i++) {}
i=i-1;
if(i<0)
i=parent()->children()-3;
Fl::focus(parent()->child(i));
parent()->child(i)->handle(FL_FOCUS);
return(1);
}
if(key==FL_Down || key==FL_KP_Down) {
for(i=0;i<parent()->children() && this!=parent()->child(i);i++) {}
i=i+1;
if(i>parent()->children()-3)
i=0;
Fl::focus(parent()->child(i));
parent()->child(i)->handle(FL_FOCUS);
return(1);
}
if(key==FL_Home || key==FL_KP_Home) {
i=0;
Fl::focus(parent()->child(i));
parent()->child(i)->handle(FL_FOCUS);
return(1);
}
if(key==FL_End || key==FL_KP_End) {
i=parent()->children()-3;
Fl::focus(parent()->child(i));
parent()->child(i)->handle(FL_FOCUS);
return(1);
}
}
return Fl_Button::handle(event);
}
/**********************************/
/* right-click menu event handler */
/**********************************/
int UIFC_PopUp::handle(int event) {
int i;
if(event == FL_SHORTCUT && Fl::test_shortcut(FL_Escape)) {
GUI_RetVal=UIFC_CANCEL;
return(1);
}
if(event==FL_PUSH) {
for(i=0;i<children();i++) {
if(Fl::event_inside(child(i))) {
GUI_RetVal=((UIFC_Button *)child(i))->retval;
return(1);
}
}
GUI_RetVal=UIFC_CANCEL;
return(1);
}
return(0);
}
/*******************/
/* Input Box stuff */
/*******************/
void UIFC_Input_Box::draw() {
if (input_type() == FL_HIDDEN_INPUT) return;
Fl_Boxtype b = box();
if (damage() & FL_DAMAGE_ALL) draw_box(b, color());
Fl_Input_::drawtext(x()+Fl::box_dx(b), y()+Fl::box_dy(b),
w()-Fl::box_dw(b), h()-Fl::box_dh(b));
}
// kludge so shift causes selection to extend:
int UIFC_Input_Box::shift_position(int p) {
return position(p, Fl::event_state(FL_SHIFT) ? mark() : p);
}
#define ctrl(x) (x^0x40)
int UIFC_Input_Box::handle_key() {
char ascii = Fl::event_text()[0];
int del;
if (Fl::compose(del)) {
// Insert characters into numeric fields after checking for legality:
if (mode&K_NUMBER) {
Fl::compose_reset(); // ignore any foreign letters...
// This is complex to allow "0xff12" hex to be typed:
if (ascii >= '0' && ascii <= '9') {
if (readonly())
fl_beep();
else
replace(position(), mark(), &ascii, 1);
}
strcpy(((UIFC_Input *)parent())->invalue,value());
return 1;
}
if (del || Fl::event_length()) {
if (readonly())
fl_beep();
else
replace(position(), del ? position()-del : mark(),
Fl::event_text(), Fl::event_length());
}
strcpy(((UIFC_Input *)parent())->invalue,value());
return 1;
}
switch (Fl::event_key()) {
case FL_Insert:
case FL_KP_Ins:
if (Fl::event_state() & FL_CTRL)
ascii = ctrl('C');
else
if (Fl::event_state() & FL_SHIFT)
ascii = ctrl('V');
break;
case FL_Delete:
case FL_KP_Del:
if (Fl::event_state() & FL_SHIFT)
ascii = ctrl('X');
else
ascii = ctrl('D');
break;
case FL_Left:
case FL_KP_Left:
return shift_position(position()-1) + 1;
break;
case FL_Right:
case FL_KP_Right:
ascii = ctrl('F');
break;
case FL_Home:
case FL_KP_Home:
if (Fl::event_state() & FL_CTRL) {
shift_position(0);
return 1;
}
return shift_position(line_start(position())) + 1;
break;
case FL_End:
case FL_KP_End:
if (Fl::event_state() & FL_CTRL) {
shift_position(size());
return 1;
}
ascii = ctrl('E'); break;
case FL_BackSpace:
ascii = ctrl('H');
break;
case FL_Enter:
case FL_KP_Enter:
GUI_RetVal=0;
return 1;
}
int i;
switch (ascii) {
case ctrl('C'): // copy
return copy(1);
case ctrl('D'):
case ctrl('?'):
if (readonly()) {
fl_beep();
return 1;
}
if (mark() != position()) {
i=cut();
strcpy(((UIFC_Input *)parent())->invalue,value());
return i;
}
else {
i=cut(1);
strcpy(((UIFC_Input *)parent())->invalue,value());
return i;
}
case ctrl('E'):
return shift_position(line_end(position())) + 1;
case ctrl('F'):
return shift_position(position()+1) + 1;
case ctrl('H'):
if (readonly()) {
fl_beep();
return 1;
}
if (mark() != position()) {
i=cut();
strcpy(((UIFC_Input *)parent())->invalue,value());
}
else {
i=cut(-1);
strcpy(((UIFC_Input *)parent())->invalue,value());
}
return i;
case ctrl('K'):
if (readonly()) {
fl_beep();
return 1;
}
if (position()>=size()) return 0;
i = line_end(position());
if (i == position() && i < size())
i++;
cut(position(), i);
i=copy_cuts();
strcpy(((UIFC_Input *)parent())->invalue,value());
return i;
case ctrl('U'):
if (readonly()) {
fl_beep();
return 1;
}
i=cut(0, size());
strcpy(((UIFC_Input *)parent())->invalue,value());
return i;
case ctrl('V'):
case ctrl('Y'):
if (readonly()) {
fl_beep();
return 1;
}
Fl::paste(*this, 1);
strcpy(((UIFC_Input *)parent())->invalue,value());
return 1;
case ctrl('X'):
case ctrl('W'):
if (readonly()) {
fl_beep();
return 1;
}
copy(1);
i=cut();
strcpy(((UIFC_Input *)parent())->invalue,value());
return i;
case ctrl('Z'):
case ctrl('_'):
if (readonly()) {
fl_beep();
return 1;
}
i=undo();
strcpy(((UIFC_Input *)parent())->invalue,value());
return i;
case ctrl('A'):
case ctrl('G'):
if (readonly()) {
fl_beep();
return 1;
}
// insert a few selected control characters literally:
if (!(mode&K_NUMBER) && (mode&K_MSG)) {
i=replace(position(), mark(), &ascii, 1);
strcpy(((UIFC_Input *)parent())->invalue,value());
return i;
}
}
return 0;
}
int UIFC_Input_Box::handle(int event) {
static int drag_start = -1;
switch (event) {
case FL_FOCUS:
switch (Fl::event_key()) {
case FL_Right:
position(0);
break;
case FL_Left:
position(size());
break;
case FL_Down:
up_down_position(0);
break;
case FL_Up:
up_down_position(line_start(size()));
break;
case FL_Tab:
case 0xfe20: // XK_ISO_Left_Tab
position(size(),0);
break;
default:
position(position(),mark());// turns off the saved up/down arrow position
break;
}
break;
case FL_KEYBOARD:
if (Fl::event_key() == FL_Tab && mark() != position()) {
// Set the current cursor position to the end of the selection...
if (mark() > position())
position(mark());
else
position(position());
return (1);
}
else
return handle_key();
case FL_PUSH:
if (Fl::focus() != this) {
Fl::focus(this);
handle(FL_FOCUS);
}
break;
case FL_RELEASE:
if (Fl::event_button() == 2) {
Fl::event_is_click(0); // stop double click from picking a word
Fl::paste(*this, 0);
}
else if (!Fl::event_is_click()) {
// copy drag-selected text to the clipboard.
copy(0);
}
else if (Fl::event_is_click() && drag_start >= 0) {
// user clicked in the field and wants to reset the cursor position...
position(drag_start, drag_start);
drag_start = -1;
}
// For output widgets, do the callback so the app knows the user
// did something with the mouse...
if (readonly())
do_callback();
return 1;
}
Fl_Boxtype b = box();
return Fl_Input_::handletext(event,
x()+Fl::box_dx(b), y()+Fl::box_dy(b),
w()-Fl::box_dw(b), h()-Fl::box_dh(b));
}
/*********************/
/* top level handler */
/*********************/
static int handle_escape(int event) {
UIFC_Button *w=(UIFC_Button *)Fl::focus();
int i,j,key;
if(event == FL_SHORTCUT && Fl::test_shortcut(FL_Escape)) {
GUI_RetVal=UIFC_CANCEL;
return(1);
}
if(event == FL_SHORTCUT && Fl::focus()->type()==FL_NORMAL_BUTTON) {
int mode=((UIFC_Button *)Fl::focus())->mode;
key=Fl::event_key();
if((key==FL_Insert || key==FL_KP_Ins) && (mode&WIN_INS)) {
GUI_RetVal=w->retval|MSK_INS;
return(1);
}
if((key==FL_Delete || key==FL_KP_Del) && (mode&WIN_DEL)) {
GUI_RetVal=w->retval|MSK_DEL;
return(1);
}
if(key==FL_F+5 && (mode&WIN_GET)) {
GUI_RetVal=w->retval|MSK_GET;
return(1);
}
if(key==FL_F+6 && (mode&WIN_PUT)) {
GUI_RetVal=w->retval|MSK_PUT;
return(1);
}
if(key==FL_F+1) {
GUI_RetVal=UIFC_HELP;
return(1);
}
if((key>='a' && key<='z')||(key>='0' && key<='9')) {
for(i=0;i<w->parent()->children() && w!=w->parent()->child(i);i++) {}
if(i!=w->parent()->children()) {
j=i;
for(i++;i!=j;i++) {
if(i>=w->parent()->children())
i=0;
if(w->parent()->child(i)->type()==FL_NORMAL_BUTTON
&& w->parent()->child(i)!=NULL
&& w->parent()->child(i)->label()!=NULL) {
if(toupper(key)==toupper(*(char *)w->parent()->child(i)->label())) {
Fl::focus(w->parent()->child(i));
w->parent()->child(i)->handle(FL_FOCUS);
return(1);
}
}
}
}
}
}
return(0);
}
/****************************************************************************/
/* Initialization function, see uifc.h for details. */
/* Returns 0 on success. */
/****************************************************************************/
int uifcinifltk(uifcapi_t* uifcapi)
{
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;
api->showbuf=NULL;
api->timedisplay=NULL;
api->scrn_len=24;
api->scrn_width=80;
api->mode |= UIFC_MOUSE;
// Fl::scheme("plastic");
Fl::add_handler(handle_escape);
Fl::visible_focus(TRUE);
Fl::visual(FL_DOUBLE|FL_INDEX);
if(!(api->mode&UIFC_MONO)) {
Fl::foreground(UIFC_FOREGROUND);
Fl::background(UIFC_BACKGROUND);
Fl::background2(UIFC_BACKGROUND2);
}
Windows[0]=NULL;
CurrWin=0;
MainWin=NULL;
#if defined(_WIN32) && !defined(_DEBUG)
FreeConsole(); // close popup console window
#endif
return(0);
}
/****************************************************************************/
/* Exit/uninitialize UIFC implementation. */
/****************************************************************************/
void uifcbail(void)
{
int i;
for(i=CurrWin;i>=0;i--) {
delwin(i);
}
if(MainWin != NULL) {
MainWin->hide();
delete MainWin;
}
Fl::wait(5);
}
/****************************************************************************/
/* Clear screen, fill with background attribute, display application title. */
/* Returns 0 on success. */
/****************************************************************************/
int uscrn(char *str)
{
if(MainWin==NULL) {
MainWin=new Fl_Double_Window(UIFC_CHAR_WIDTH*80,UIFC_LINE_HEIGHT*25,str);
if(!(api->mode&UIFC_MONO))
MainWin->color(UIFC_MAIN_BG_COLOR,UIFC_MAIN_BG_COLOR);
}
MainWin->show();
return(0);
}
/**********************************/
/* Delete window and all children */
/**********************************/
void delwin(int WinNum) {
if(WinNum<0)
return;
if(Windows[WinNum]!=NULL) {
MainWin->remove(Windows[WinNum]);
delete Windows[WinNum];
Windows[WinNum]=NULL;
}
}
/********************/
/* Generic callback */
/********************/
static void GenCallback(Fl_Widget *w, void *data) {
GUI_RetVal=((UIFC_Button *)w)->retval;
}
/*****************/
/* NULL callback */
/*****************/
static void NULLCallback(int i, void *data) {
}
/***************/
/* Pop up menu */
/***************/
static void doPopUp(int mode) {
int height=0;
int width=3;
int curry=0;
Fl_Widget *w=Fl::pushed();
if(w->type()==FL_NORMAL_BUTTON) {
((Fl_Button *)w)->value(0);
if(!(api->mode&UIFC_MONO))
w->color(UIFC_BUTTON_SELECTED_COLOR);
}
// Right Click
if(mode&WIN_INS) {
height++;
width=7;
}
if(mode&WIN_DEL) {
height++;
width=7;
}
if(mode&WIN_GET) {
height++;
}
if(mode&WIN_PUT) {
height++;
}
if(height) {
UIFC_PopUp *PopUp=new UIFC_PopUp(
UIFC_CHAR_WIDTH*width+UIFC_BORDER_WIDTH*2,
UIFC_LINE_HEIGHT*height+UIFC_BORDER_WIDTH*2,
"PopUp");
PopUp->position(Fl::event_x_root()+3,Fl::event_y_root()+3);
if(mode&WIN_INS) {
UIFC_Button *InsertButton=new UIFC_Button(
UIFC_BORDER_WIDTH,
UIFC_LINE_HEIGHT*curry+UIFC_BORDER_WIDTH,
UIFC_CHAR_WIDTH*width,
UIFC_LINE_HEIGHT,
"Insert");
InsertButton->retval=((UIFC_Button *)w)->retval|MSK_INS;
InsertButton->mode=0;
InsertButton->box(FL_NO_BOX);
curry++;
}
if(mode&WIN_DEL) {
UIFC_Button *DeleteButton=new UIFC_Button(
UIFC_BORDER_WIDTH,
UIFC_LINE_HEIGHT*curry+UIFC_BORDER_WIDTH,
UIFC_CHAR_WIDTH*width,
UIFC_LINE_HEIGHT,
"Delete");
DeleteButton->retval=((UIFC_Button *)w)->retval|MSK_DEL;
DeleteButton->mode=0;
DeleteButton->box(FL_NO_BOX);
curry++;
}
if(mode&WIN_GET) {
UIFC_Button *GetButton=new UIFC_Button(
UIFC_BORDER_WIDTH,
UIFC_LINE_HEIGHT*curry+UIFC_BORDER_WIDTH,
UIFC_CHAR_WIDTH*width,
UIFC_LINE_HEIGHT,
"Get");
GetButton->retval=((UIFC_Button *)w)->retval|MSK_GET;
GetButton->mode=0;
GetButton->box(FL_NO_BOX);
curry++;
}
if(mode&WIN_PUT) {
UIFC_Button *PutButton=new UIFC_Button(
UIFC_BORDER_WIDTH,
UIFC_LINE_HEIGHT*curry+UIFC_BORDER_WIDTH,
UIFC_CHAR_WIDTH*width,
UIFC_LINE_HEIGHT,
"Put");
PutButton->retval=((UIFC_Button *)w)->retval|MSK_PUT;
PutButton->mode=0;
PutButton->box(FL_NO_BOX);
curry++;
}
PopUp->end();
PopUp->show();
PopUp->show();
if(w->type()==FL_NORMAL_BUTTON) {
if(!(api->mode&UIFC_MONO))
w->color(UIFC_BUTTON_SELECTED_COLOR);
w->redraw();
}
Fl::grab(PopUp);
while(GUI_RetVal==UIFC_RCLICK) {
Fl::wait();
}
Fl::grab(0);
delete PopUp;
}
return;
}
/************************/
/* List button Callback */
/************************/
static void LBCallback(Fl_Widget *w, void *data) {
((Fl_Button *)w)->value(1);
if(uifc_cur != NULL)
*uifc_cur=((UIFC_Button *)w)->retval&MSK_OFF;
if(Fl::event_key()==FL_Button+3) {
Fl::focus(w);
w->handle(FL_FOCUS);
GUI_RetVal=UIFC_RCLICK;
return;
}
GUI_RetVal=((UIFC_Button *)w)->retval;
}
/****************************************************************************/
/* 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)
{
int opts,i;
int len;
int scrolloffset=0;
// Find WinID
for(i=CurrWin;(i>=0)&&(Windows[i]==NULL || Windows[i]->uifc_id!=cur);i--) {}
if(i>=0) {
for(;CurrWin>=i;CurrWin--)
delwin(CurrWin);
}
CurrWin++;
delwin(CurrWin);
len=strlen(title)+6;
if(width<len)
width=len;
for(opts=0;option[opts][0];opts++) {
len=strlen(option[opts])+4;
if(width<len)
width=len;
}
if(mode&WIN_XTR)
opts+=1;
if(*cur>=opts)
*cur=opts-1;
if(*cur<0)
*cur=0;
if(opts>20)
scrolloffset=UIFC_SCROLL_WIDTH;
GUI_RetVal=UIFC_MENU;
if(top==0)
top=SCRN_TOP;
if(left==0)
left=SCRN_LEFT;
if(mode&WIN_RHT)
left=SCRN_RIGHT-width;
while(left+width>79)
left--;
if(left<=0 || (mode&WIN_L2R))
left=(80-width)/2;
if(mode&WIN_BOT)
top=23;
while (top+((opts<20)?opts:20)>22)
top--;
if (mode&WIN_T2B)
top=0;
if(top<=0)
top=(23-((opts<20)?opts:20))/2;
Windows[CurrWin] = new UIFC_Menu(
UIFC_CHAR_WIDTH*left-UIFC_BORDER_WIDTH-(scrolloffset/2),
UIFC_LINE_HEIGHT*top-UIFC_BORDER_WIDTH,
UIFC_CHAR_WIDTH*width+(UIFC_BORDER_WIDTH*2)+scrolloffset,
UIFC_LINE_HEIGHT*(((opts<20)?opts:20)+1)+(UIFC_BORDER_WIDTH*6),
title,
mode,
opts,
cur,
option);
MainWin->add(Windows[CurrWin]);
Windows[CurrWin]->end();
Windows[CurrWin]->show();
Windows[CurrWin]->show();
/* This is kind of kludgy... it doesn't allow for adding of buttons to
the UIFC_Window before the Scroll Group */
Fl::focus(((UIFC_Menu *)Windows[CurrWin]->child(2))->child(*cur));
if(!(api->mode&UIFC_MONO))
((UIFC_Menu *)Windows[CurrWin]->child(2))->child(*cur)->color(UIFC_BUTTON_SELECTED_COLOR);
uifc_cur=cur;
while(GUI_RetVal==UIFC_MENU) {
Fl::wait();
if(GUI_RetVal==UIFC_HELP) {
help();
GUI_RetVal=UIFC_MENU;
}
else if(GUI_RetVal==UIFC_RCLICK) {
doPopUp(mode);
if(GUI_RetVal==UIFC_CANCEL)
GUI_RetVal=UIFC_MENU;
}
}
uifc_cur=NULL;
Windows[CurrWin]->deactivate();
return GUI_RetVal;
}
/*************************************************************************/
/* This function is a windowed input string input routine. */
/*************************************************************************/
int uinput(int mode, int left, int top, char *prompt, char *outstr,
int max, int kmode)
{
int width;
int wwidth;
int len;
width=max;
len=strlen(prompt);
if(width>(76-len))
width=76-len;
wwidth=width+len+1;
if(wwidth<18) {
len+=(18-wwidth)/2;
wwidth=18;
}
GUI_RetVal=UIFC_INPUT;
if(top==0)
top=SCRN_TOP;
if(left==0)
left=SCRN_LEFT;
if(mode&WIN_RHT)
left=SCRN_RIGHT-width;
while(left+wwidth>79)
left--;
if(left<=0 || (mode&WIN_L2R))
left=(80-wwidth)/2;
if(mode&WIN_BOT)
top=23;
while (top+5>22)
top--;
if (mode&WIN_T2B)
top=0;
if(top<=0)
top=(23-5)/2;
UIFC_Input *InputWin = new UIFC_Input(
UIFC_CHAR_WIDTH*left,
UIFC_LINE_HEIGHT*top,
UIFC_CHAR_WIDTH*(wwidth+4),
UIFC_LINE_HEIGHT*5,
prompt,
kmode,
max,
len,
width,
outstr);
MainWin->add(InputWin);
InputWin->end();
InputWin->show();
InputWin->show();
/* This is kind of kludgy... it doesn't allow for adding of buttons to
the UIFC_Window before the UIFC_Input_Box */
Fl::focus((UIFC_Menu *)InputWin->child(2));
while(GUI_RetVal==UIFC_INPUT) {
Fl::wait();
if(GUI_RetVal==UIFC_HELP) {
help();
GUI_RetVal=UIFC_INPUT;
}
else if(GUI_RetVal==UIFC_RCLICK)
GUI_RetVal=UIFC_INPUT;
}
if(GUI_RetVal==0) {
if(kmode&K_EDIT) {
if(strcmp(outstr,InputWin->invalue)) {
api->changes=TRUE;
}
}
else {
if(strlen(InputWin->invalue)) {
api->changes=TRUE;
}
}
snprintf(outstr,max,"%s",InputWin->invalue);
}
MainWin->remove(InputWin);
delete InputWin;
if(GUI_RetVal==UIFC_CANCEL)
return(-1);
return(strlen(outstr));
}
/****************************************************************************/
/* Displays the message 'str' and waits for the user to select "OK" */
/****************************************************************************/
void umsg(char *str)
{
fl_message(str);
}
/****************************************************************************/
/* Status popup/down function, see uifc.h for details. */
/****************************************************************************/
void upop(char *str)
{
static Fl_Double_Window *PopUp[MAX_POPUPS];
static int CurrPop=0;
int width=0;
int height=1;
if(str == NULL) {
for(;CurrPop>0;CurrPop--) {
delete PopUp[CurrPop-1];
}
return;
}
width=strlen(str);
while(width>78) {
height+=1;
width-=78;
}
PopUp[CurrPop]=new Fl_Double_Window((width+4)*UIFC_CHAR_WIDTH,(height+2)*UIFC_LINE_HEIGHT,NULL);
PopUp[CurrPop]->border(FALSE);
Fl_Box *box = new Fl_Box(
UIFC_CHAR_WIDTH,UIFC_LINE_HEIGHT,
UIFC_CHAR_WIDTH*width,UIFC_LINE_HEIGHT*height,"str");
box->align(FL_ALIGN_CENTER|FL_ALIGN_WRAP|FL_ALIGN_INSIDE);
PopUp[CurrPop]->set_modal();
PopUp[CurrPop]->end();
PopUp[CurrPop]->show();
PopUp[CurrPop]->show();
CurrPop++;
}
/****************************************************************************/
/* Sets the current help index by source code file and line number. */
/****************************************************************************/
void sethelp(int line, char* file)
{
helpline=line;
helpfile=file;
}
/****************************************************************************/
/* Help function. */
/****************************************************************************/
void help()
{
char hbuf[HELPBUF_SIZE],str[256];
char ch[2]={0,0};
char *p;
unsigned short line;
size_t len,j;
int i=0;
long l;
FILE *fp;
int inverse=0;
int high=0;
// Read help buffer
if(!api->helpbuf) {
if((fp=fopen(api->helpixbfile,"rb"))==NULL)
sprintf(hbuf," ERROR  Cannot open help index:\n %s"
,api->helpixbfile);
else {
p=strrchr(helpfile,'/');
if(p==NULL)
p=strrchr(helpfile,'\\');
if(p==NULL)
p=helpfile;
else
p++;
l=-1L;
while(!feof(fp)) {
if(!fread(str,12,1,fp))
break;
str[12]=0;
fread(&line,2,1,fp);
if(stricmp(str,p) || line != helpline) {
fseek(fp,4,SEEK_CUR);
continue;
}
fread(&l,4,1,fp);
break;
}
fclose(fp);
if(l==-1L)
sprintf(hbuf," ERROR  Cannot locate help key (%s:%u) in:\n"
" %s",p,helpline,api->helpixbfile);
else {
if((fp=fopen(api->helpdatfile,"rb"))==NULL)
sprintf(hbuf," ERROR  Cannot open help file:\n %s"
,api->helpdatfile);
else {
fseek(fp,l,SEEK_SET);
fread(hbuf,HELPBUF_SIZE,1,fp);
fclose(fp);
}
}
}
}
else
strcpy(hbuf,api->helpbuf);
len=strlen(hbuf);
UIFC_Window *HelpWin = new UIFC_Window(
UIFC_CHAR_WIDTH*2-UIFC_BORDER_WIDTH,
UIFC_LINE_HEIGHT*1-UIFC_BORDER_WIDTH,
UIFC_CHAR_WIDTH*76+(UIFC_BORDER_WIDTH*2),
UIFC_LINE_HEIGHT*22+(UIFC_BORDER_WIDTH*2),
"Help Window");
Fl_Text_Display *TextBox = new Fl_Text_Display(
UIFC_BORDER_WIDTH,
UIFC_LINE_HEIGHT+UIFC_BORDER_WIDTH,
UIFC_CHAR_WIDTH*76,
UIFC_LINE_HEIGHT*20+(UIFC_BORDER_WIDTH*6),
"Help Window");
TextBox->labelfont(FL_COURIER_BOLD);
TextBox->labelsize(UIFC_CHAR_HEIGHT);
if(!(api->mode&UIFC_MONO)) {
TextBox->labelcolor(UIFC_WINDOW_TITLE_COLOR);
TextBox->color(UIFC_HELP_WIN_BG_COLOR);
}
TextBox->textfont(FL_COURIER);
TextBox->textsize(UIFC_CHAR_HEIGHT);
TextBox->buffer(new Fl_Text_Buffer(HELPBUF_SIZE));
Fl_Text_Display::Style_Table_Entry styletable[] = { // Style table
{ UIFC_HELP_PLAIN_COLOR, FL_COURIER, UIFC_CHAR_HEIGHT }, // A - Plain
{ UIFC_HELP_HIGH_COLOR, FL_COURIER_ITALIC, UIFC_CHAR_HEIGHT }, // B - Bold
{ UIFC_HELP_INVERSE_COLOR, FL_COURIER_ITALIC, UIFC_CHAR_HEIGHT }, // C - Inverse
{ UIFC_HELP_BOTH_COLOR, FL_COURIER_ITALIC, UIFC_CHAR_HEIGHT }, // D - Both
};
Fl_Text_Buffer *StyleBuf=new Fl_Text_Buffer(HELPBUF_SIZE);
TextBox->highlight_data(StyleBuf, styletable,
(int)(sizeof(styletable) / sizeof(styletable[0])),
'A',NULLCallback,(void *)NULL);
MainWin->add(HelpWin);
HelpWin->end();
HelpWin->show();
HelpWin->show();
for(j=0;j<len;j++) {
if(hbuf[j]=='\r') /* don't display <cr> */
continue;
if(hbuf[j]==2 || hbuf[j]=='~') { /* Ctrl-b toggles inverse */
if(inverse)
inverse=0;
else
inverse=1;
}
else if(hbuf[j]==1 || hbuf[j]=='`') { /* Ctrl-a toggles high intensity */
if(high)
high=0;
else
high=1;
}
else {
ch[0]=hbuf[j];
TextBox->insert(ch);
ch[0]='A'+(high|(inverse<<1));
StyleBuf->insert(i,ch);
i++;
}
}
while(GUI_RetVal==UIFC_HELP) {
Fl::wait();
if(GUI_RetVal==UIFC_RCLICK)
GUI_RetVal=UIFC_HELP;
}
delete StyleBuf;
MainWin->remove(HelpWin);
delete HelpWin;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment