diff --git a/src/uifc/uifc.h b/src/uifc/uifc.h index 97bd41a13ad2f2fb8d1bbc4db2033c899244b4bc..a8db4eedf77853f30b0194927f83461e149d4b7e 100644 --- a/src/uifc/uifc.h +++ b/src/uifc/uifc.h @@ -336,4 +336,8 @@ int uifcini(uifcapi_t*); /* Original implementation based on conio */ int uifcinix(uifcapi_t*); /* Standard I/O implementation */ int uifcinic(uifcapi_t*); /* Unix curses implementation (by Deuce) */ int uifcinid(uifcapi_t*); /* Unix libdialog implementation (by Deuce) */ +#ifdef __cplusplus +extern "C" +#endif +int uifcinifltk(uifcapi_t*); /* FLTK implementation (by Deuce) */ /****************************************************************************/ diff --git a/src/uifc/uifcfltk.cpp b/src/uifc/uifcfltk.cpp new file mode 100644 index 0000000000000000000000000000000000000000..55a054b96df828754a1bc81a8dbb8b872bfa8d1b --- /dev/null +++ b/src/uifc/uifcfltk.cpp @@ -0,0 +1,1209 @@ +/* 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 2002 Rob Swindell - http://www.synchro.net/copyright.html * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU 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 General Public License for more details: gpl.txt or * + * http://www.fsf.org/copyleft/gpl.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. * + ****************************************************************************/ + +/******************/ +/* 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 "Character" +#define UIFC_BORDER_WIDTH 2 // Width of a single border +#define UIFC_SCROLL_WIDTH 18 // Width of the scroll bar + +/*********************************************/ +/* 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_Window.H> +#include <FL/Fl_Group.H> +#include <FL/Fl_Scroll.H> +#include <FL/Fl_Button.H> +#include <FL/Fl_Return_Button.H> +#include <FL/Fl_Input_.H> +#include <FL/Fl_Text_Display.H> +#include <FL/Fl_Box.H> +#include <FL/fl_ask.H> + + +#include <sys/types.h> +#include "uifc.h" + +#ifdef __unix__ +#include <unistd.h> +#define _snprintf snprintf +#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); + +/* Classes */ +class UIFC_PopUp : public Fl_Window { + int handle(int); +public: + UIFC_PopUp(int w,int h,const char *title) : Fl_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; + 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); + color(FL_DARK_BLUE,FL_BACKGROUND_COLOR); + labelcolor(FL_WHITE); + } +}; + +class UIFC_Window : public Fl_Window { +public: + UIFC_Window(int x,int y,int w,int h,const char *title) : Fl_Window(x,y,w,h,title) { + box(FL_UP_BOX); + color(FL_DARK_BLUE,FL_DARK_BLUE); + 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); + HButton->color(FL_BLUE,FL_BLUE); + HButton->labelcolor(FL_YELLOW); + 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); + CButton->color(FL_BLUE,FL_BLUE); + CButton->labelcolor(FL_YELLOW); + } +}; + +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); + SGroup->labelcolor(FL_YELLOW); + SGroup->color(FL_YELLOW); + 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); + labelcolor(FL_YELLOW); + color(FL_DARK_BLUE,FL_DARK_BLUE); + textcolor(FL_WHITE); + } +}; + +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->shortcut(FL_Enter); + 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); + } +}; + +/* Globals */ +Fl_Window *MainWin; +int GUI_RetVal; +UIFC_Menu *Windows[MAX_WINDOWS]; // Array of windows for ulist +int CurrWin; // Current window in array. + +/**********************************/ +/* 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<this->children();i++) { + if(Fl::event_inside(this->child(i))) { + GUI_RetVal=((UIFC_Button *)this->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 (!position() && (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: + if (Fl::event_state() & FL_CTRL) + ascii = ctrl('C'); + else + if (Fl::event_state() & FL_SHIFT) + ascii = ctrl('V'); + break; + case FL_Delete: + if (Fl::event_state() & FL_SHIFT) + ascii = ctrl('X'); + else + ascii = ctrl('D'); + break; + case FL_Left: + return shift_position(position()-1) + 1; + break; + case FL_Right: + ascii = ctrl('F'); + break; + case FL_Home: + if (Fl::event_state() & FL_CTRL) { + shift_position(0); + return 1; + } + return shift_position(line_start(position())) + 1; + break; + case FL_End: + if (Fl::event_state() & FL_CTRL) { + shift_position(size()); + return 1; + } + ascii = ctrl('E'); break; + case FL_BackSpace: + ascii = ctrl('H'); + break; + } + + 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('B'): + case ctrl('I'): + case ctrl('J'): + case ctrl('L'): + case ctrl('M'): + 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) { + 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; + UIFC_Button *w=(UIFC_Button *)Fl::focus(); + if(Fl::event_key()==FL_Insert && (mode&WIN_INS)) { + GUI_RetVal=w->retval|MSK_INS; + return(1); + } + if(Fl::event_key()==FL_Delete && (mode&WIN_DEL)) { + GUI_RetVal=w->retval|MSK_DEL; + return(1); + } + if(Fl::event_key()==FL_F+5 && (mode&WIN_GET)) { + GUI_RetVal=w->retval|MSK_GET; + return(1); + } + if(Fl::event_key()==FL_F+6 && (mode&WIN_PUT)) { + GUI_RetVal=w->retval|MSK_PUT; + return(1); + } + if(Fl::event_key()==FL_F+1) { + GUI_RetVal=UIFC_HELP; + 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->scrn_len=24; + api->mode |= UIFC_MOUSE; + + Fl::add_handler(handle_escape); + Fl::visible_focus(TRUE); + Windows[0]=NULL; + + CurrWin=0; + MainWin=NULL; + return(0); +} + +/****************************************************************************/ +/* Exit/uninitialize UIFC implementation. */ +/****************************************************************************/ +void uifcbail(void) +{ + delete MainWin; +} + +/****************************************************************************/ +/* Clear screen, fill with background attribute, display application title. */ +/* Returns 0 on success. */ +/****************************************************************************/ +int uscrn(char *str) +{ + if(MainWin==NULL) { + MainWin=new Fl_Window(UIFC_CHAR_WIDTH*80,UIFC_LINE_HEIGHT*25,str); + MainWin->color(FL_DARK_CYAN,FL_DARK_CYAN); + } + MainWin->show(); + return(0); +} + +/****************************************************************************/ +/* 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 + +/**********************************/ +/* 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); + + // 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(); + 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) { + if(Fl::event_key()==FL_Button+3) { + 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)+2; + 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)); + + 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; + } + } + + Windows[CurrWin]->deactivate(); + // -1 *sigh* + if(GUI_RetVal!=UIFC_CANCEL&&GUI_RetVal&(MSK_INS|MSK_DEL|MSK_PUT)) + api->changes=1; + *cur=GUI_RetVal&MSK_OFF; + return GUI_RetVal; +} + +/*****************/ +/* Text clean-up */ +/*****************/ +void text_clean(Fl_Widget *w, void *modes) { + char str[256],str2[256]; + int mode=((modes_t*)(modes))->mode; + int max=((modes_t*)(modes))->max; + Fl_Input_ *InputBox=((modes_t*)(modes))->InputBox; + size_t len=0; + size_t pos=0; + + printf("Text Clean-up\n"); + _snprintf(str,max,"%s",InputBox->value()); + len=strlen(str); + if(mode&K_UPPER) /* convert to uppercase? */ + strupr(str); + if((mode&K_ALPHA)||(mode&K_NUMBER)) { /* Numbers only? */ + for(len=0;str[len];len++) { + if(mode&K_ALPHA) { + if(isalpha(str[len])) + str2[pos++]=str[len]; + } + if(mode&K_NUMBER) { + printf("MUST BE NUMBER!\n"); + if(isdigit(str[len])) + str2[pos++]=str[len]; + } + } + str2[pos]=0; + len=pos; + strcpy(str,str2); + } + InputBox->value(str); + InputBox->position(len); +} + +/*************************************************************************/ +/* 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((kmode&K_EDIT)&&(!strcmp(outstr,InputWin->invalue))) + GUI_RetVal=UIFC_CANCEL; + if(GUI_RetVal==0) { + api->changes=TRUE; + _snprintf(outstr,max,"%s",InputWin->invalue); + } + MainWin->remove(InputWin); + delete InputWin; + + 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_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_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; + 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:\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); + + 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); + TextBox->labelcolor(FL_YELLOW); + TextBox->color(FL_DARK_BLUE); + 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 + { FL_WHITE, FL_COURIER, UIFC_CHAR_HEIGHT }, // A - Plain + { FL_YELLOW, FL_COURIER_ITALIC, UIFC_CHAR_HEIGHT }, // B - Bold + { FL_CYAN, FL_COURIER_ITALIC, UIFC_CHAR_HEIGHT }, // C - Inverse + { FL_MAGENTA, 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]==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; +}