summaryrefslogtreecommitdiff
path: root/linux/platgui.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/platgui.c')
-rw-r--r--linux/platgui.c3703
1 files changed, 3703 insertions, 0 deletions
diff --git a/linux/platgui.c b/linux/platgui.c
new file mode 100644
index 0000000..5fd9c74
--- /dev/null
+++ b/linux/platgui.c
@@ -0,0 +1,3703 @@
+/*
+
+ viDOOM - level editor for DOOM
+
+ Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Platform specific GUI type routines
+
+*/
+static const char rcs_id[]="$Id$";
+
+#include "config.h"
+
+#include "platgui.h"
+#include "gui.h"
+#include "gfx.h"
+#include "mem.h"
+#include "file.h"
+#include "ini.h"
+#include "util.h"
+
+#include "debug.h"
+
+#include <stdio.h>
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <dirent.h>
+
+
+/* ---------------------------------------- MACROS
+*/
+#define CENTRE(x,y,c,t) GFX_print((x)-strlen(t)*FW/2,y,c,"%s",t)
+
+#define CENTREX(x,y,w,c,t) GFX_print(((x)+(w)/2)-strlen(t)*FW/2,y,c,"%s",t)
+#define CENTREY(x,y,h,c,t) GFX_print((x),((y)+(h)/2)-FH/2,c,"%s",t)
+#define CENTREXY(x,y,w,h,c,t) GFX_print(((x)+(w)/2)-strlen(t)*FW/2,\
+ ((y)+(h)/2)-FH/2,c,"%s",t)
+#define LENGTH(t) (strlen(t)*FW)
+
+
+/* ---------------------------------------- CONFIG
+*/
+static char GUI_EDITOR[PATH_MAX]="";
+
+
+static INI_Table ini_conf[]=
+ {
+ {INI_STR,"linux","edit",GUI_EDITOR,NULL},
+ };
+
+/* ---------------------------------------- VARS
+*/
+static Display *disp=NULL;
+static Window win=None;
+static Pixmap pix=None;
+static GC gc=None;
+
+static int SCRW,SCRH;
+static int FW,FH;
+
+static unsigned long hi_col;
+static unsigned long mid_col;
+static unsigned long lo_col;
+static unsigned long txt_col;
+static unsigned long shadow_col;
+static unsigned long bold_col;
+
+static const int BEVEL=2;
+static const int SMALL_BEVEL=1;
+
+#define LIST_SCROLLSIZE 20
+#define LIST_TEXTHEIGHT (FH+(FH>>1))
+
+/* Internal representation used for GFX_IMAGE
+
+ IMPORTANT: This *MUST* match the definition in linux/gfx.c
+
+*/
+typedef struct
+ {
+ int w,h;
+ XImage *p;
+ } GfxImage;
+
+
+/* Vars for GUI_yesno_all()
+*/
+static int all_pressed=FALSE;
+static int all_result=FALSE;
+
+/* Event Vars
+*/
+static int mouse_x=0;
+static int mouse_y=0;
+static int mouse_b=0;
+static int last_mouse_b=0;
+static int is_key=FALSE;
+static int key=0;
+static int shift=0;
+static int ctrl=0;
+static char ascii=0;
+
+/* 'Hidden' interfaces to gfx.c
+*/
+extern void VIDOOM_GET_GFX_VARS(Display **ret_disp,
+ Window *ret_win,
+ Pixmap *ret_pix,
+ GC *ret_gc);
+extern void VIDOOM_GFX_FORCE_REDRAW(void);
+extern void VIDOOM_GFX_SAVE_DISPLAY(void);
+extern void VIDOOM_GFX_RESTORE_DISPLAY(void);
+extern Pixmap VIDOOM_GFX_SAVE_UNDER(int x, int y, int w, int h);
+extern void VIDOOM_GFX_RESTORE_UNDER(Pixmap p, int x, int y, int w, int h);
+extern void VIDOOM_GFX_WAIT_FOR(pid_t pid, int *status);
+
+
+/* Types to define GUI objects. Note picklist done as an image list with
+ no images.
+*/
+typedef enum {GuiBox,
+ GuiLabel,
+ GuiButton,
+ GuiText,
+ GuiToggle,
+ GuiRadio,
+ GuiImageList,
+ GuiFileList,
+ GuiTextEdit} ObjType;
+
+typedef enum {GuiKeyPress,
+ GuiButtonPress,
+ GuiWheelUp,
+ GuiWheelDown,
+ GuiDraw,
+ GuiExit} ObjEvent;
+
+typedef enum {GuiOk,
+ GuiDone,
+ GuiRedraw} CallbackReturn;
+
+typedef enum {GuiTextString,
+ GuiTextInteger,
+ GuiTextDouble,
+ GuiTextReadOnly} GuiTextMode;
+
+typedef struct
+ {
+ int x,y,w,h;
+ } BoundBox;
+
+typedef struct
+ {
+ ObjType type;
+ BoundBox box;
+ int focus;
+ int take_focus;
+ } GuiObjCommon;
+
+typedef struct
+ {
+ GuiObjCommon common;
+ const char *title;
+ int invert;
+ GfxImage *img;
+ } GuiObjBox;
+
+typedef struct
+ {
+ GuiObjCommon common;
+ const char *text;
+ int col;
+ int centre;
+ } GuiObjLabel;
+
+typedef struct
+ {
+ GuiObjCommon common;
+ const char *text;
+ } GuiObjButton;
+
+typedef struct
+ {
+ GuiObjCommon common;
+ char text[PATH_MAX+1];
+ GuiTextMode mode;
+ int len;
+ int no_chars;
+ int first;
+ int curs;
+ int allow_exit;
+ } GuiObjText;
+
+typedef struct
+ {
+ GuiObjCommon common;
+ const char *text;
+ int state;
+ } GuiObjToggle;
+
+typedef struct
+ {
+ GuiObjCommon common;
+ int state;
+ const char *text;
+ int group;
+ } GuiObjRadio;
+
+typedef struct
+ {
+ GuiObjCommon common;
+ int curr;
+ int img_box;
+ int no;
+ char **items;
+ GFX_IMAGE *img;
+ int no_lines;
+ int top;
+ double sbar_step;
+ int scrollbar;
+ BoundBox scroll;
+ BoundBox bar;
+ int double_click;
+ } GuiObjImageList;
+
+typedef struct
+ {
+ char name[PATH_MAX+1];
+ int is_dir;
+ off_t size;
+ } FileEnt;
+
+typedef struct
+ {
+ GuiObjCommon common;
+ int curr;
+ int no;
+ FileEnt *ent;
+ char dir[PATH_MAX+1];
+ char *filter;
+ int no_lines;
+ int top;
+ double sbar_step;
+ int scrollbar;
+ BoundBox scroll;
+ BoundBox bar;
+ int double_click;
+ int path_text;
+ int file_text;
+ int name_width;
+ int size_width;
+ } GuiObjFileList;
+
+#define TE_CHUNK 256
+
+typedef struct
+ {
+ int len;
+ char *p;
+ } TextEditLine;
+
+typedef struct
+ {
+ GuiObjCommon common;
+ TextEditLine *tline;
+ int top;
+ int x,y;
+ int col;
+ int lines;
+ int width;
+ int height;
+ int info;
+ int read_only;
+ } GuiObjTextEdit;
+
+typedef union
+ {
+ GuiObjCommon common;
+ GuiObjBox box;
+ GuiObjLabel lbl;
+ GuiObjButton but;
+ GuiObjText txt;
+ GuiObjToggle tog;
+ GuiObjRadio rad;
+ GuiObjImageList pck;
+ GuiObjFileList fle;
+ GuiObjTextEdit edt;
+ } GuiObj;
+
+static int focus=-1;
+
+static int dialog_no;
+static GuiObj *dialog=NULL;
+
+
+/* Types to define menus
+*/
+typedef enum {MENU_OK,
+ MENU_CANCEL_ESC,
+ MENU_CANCEL_CLICK,
+ MENU_CHILD_RETURN} MenuStatus;
+
+typedef struct
+ {
+ MenuStatus mode;
+ int ret;
+ } MenuControl;
+
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+static void ExecProgram(char *prog_in, char *file)
+{
+ char prog[PATH_MAX];
+ char *arg[PATH_MAX];
+ int no;
+ int f;
+
+ strcpy(prog,prog_in);
+
+ no=0;
+
+ arg[no]=strtok(prog," ");
+
+ while (arg[no])
+ arg[++no]=strtok(NULL," ");
+
+ for(f=0;f<no;f++)
+ if (strcmp(arg[f],"%")==0)
+ arg[f]=file;
+
+ execvp(arg[0],arg);
+}
+
+
+static unsigned long XCol(int col)
+{
+ XColor pix;
+
+ pix.red=((col&0xff0000)>>8)|((col&0xff0000)>>16);
+ pix.green=(col&0xff00)|((col&0xff00)>>8);
+ pix.blue=((col&0xff)<<8)|(col&0xff);
+ pix.flags=DoRed|DoBlue|DoGreen;
+
+ XAllocColor(disp,DefaultColormap(disp,DefaultScreen(disp)),&pix);
+
+ return pix.pixel;
+}
+
+
+static void DumpBox(const char *title, BoundBox b)
+{
+ Debug(("%s.x=%d\n",title,b.x));
+ Debug(("%s.y=%d\n",title,b.y));
+ Debug(("%s.w=%d\n",title,b.w));
+ Debug(("%s.h=%d\n",title,b.h));
+}
+
+
+static int MouseInBox(BoundBox *box, int no)
+{
+ int f;
+
+ for(f=0;f<no;f++)
+ if (((mouse_x>=box[f].x)&&(mouse_x<box[f].x+box[f].w))&&
+ ((mouse_y>=box[f].y)&&(mouse_y<box[f].y+box[f].h)))
+ return f;
+
+ return -1;
+}
+
+
+static int IsInBox(BoundBox *box)
+{
+ if (((mouse_x>=box->x)&&(mouse_x<box->x+box->w))&&
+ ((mouse_y>=box->y)&&(mouse_y<box->y+box->h)))
+ return TRUE;
+
+ return FALSE;
+}
+
+
+static void Rect3D(int x,int y,int w,int h, int invert,int bevel)
+{
+ int f;
+ int mid,lo,hi;
+
+ mid=GUI_MID;
+
+ if (invert)
+ {
+ lo=GUI_HI;
+ hi=GUI_LO;
+ }
+ else
+ {
+ hi=GUI_HI;
+ lo=GUI_LO;
+ }
+
+ GFX_frect(x,y,w,h,mid);
+
+ for(f=0;f<bevel;f++)
+ {
+ GFX_line(x+f,y+f,x+f,y+h-1-f,hi);
+ GFX_line(x+w-1-f,y+f,x+w-1-f,y+h-1-f,lo);
+
+ GFX_line(x+f,y+f,x+w-1-f,y+f,hi);
+ GFX_line(x+f,y+h-1-f,x+w-1-f,y+h-1-f,lo);
+ }
+}
+
+
+static void Rect3DBox(BoundBox *b, int invert, int bevel)
+{
+ Rect3D(b->x,b->y,b->w,b->h,invert,bevel);
+}
+
+
+static void Tickbox(int x,int y,int w,int h, int pick)
+{
+ int f;
+
+ if (pick)
+ GFX_frect(x,y,w,h,BLACK);
+ else
+ GFX_frect(x,y,w,h,WHITE);
+
+
+ for(f=0;f<SMALL_BEVEL;f++)
+ {
+ GFX_line(x+f,y+f,x+f,y+h-1-f,GUI_LO);
+ GFX_line(x+w-1-f,y+f,x+w-1-f,y+h-1-f,GUI_HI);
+
+ GFX_line(x+f,y+f,x+w-1-f,y+f,GUI_LO);
+ GFX_line(x+f,y+h-1-f,x+w-1-f,y+h-1-f,GUI_HI);
+ }
+}
+
+
+static void GetEvent(void)
+{
+ GFXEvent e;
+
+ GFX_await_input_full(&e);
+
+ switch(e.type)
+ {
+ case GFX_KEY_EVENT:
+ is_key=TRUE;
+ key=e.key.code;
+ shift=e.key.shift;
+ ascii=e.key.ascii;
+ ctrl=e.key.ctrl;
+ break;
+
+ case GFX_MOUSE_EVENT:
+ is_key=FALSE;
+ last_mouse_b=mouse_b;
+ mouse_x=e.mouse.x;
+ mouse_y=e.mouse.y;
+ mouse_b=e.mouse.b;
+ break;
+ }
+}
+
+
+static void EventTidy()
+{
+ is_key=FALSE;
+ last_mouse_b=0;
+
+ while(mouse_b)
+ GetEvent();
+
+ GFX_bounce();
+}
+
+
+static void ChopLines(char *text, char *line[],int *no,int *max)
+{
+ char *p;
+ int f;
+
+ *no=0;
+ *max=0;
+ p=text;
+
+ line[(*no)++]=p;
+
+ while(*p)
+ {
+ if (*p=='|')
+ {
+ *p++=0;
+
+ if (*p)
+ line[(*no)++]=p;
+ }
+ else
+ p++;
+ }
+
+ for(f=0;f<*no;f++)
+ *max=MAX(LENGTH(line[f]),*max);
+}
+
+
+/* ---------------------------------------- DIALOG CREATION FUNCTIONS
+*/
+static void InitDial(void)
+{
+ if (dialog)
+ {
+ Release(dialog);
+ dialog=NULL;
+ }
+
+ focus=-1;
+ dialog_no=0;
+}
+
+
+static void ResizeBox(int i)
+{
+ int f;
+ int x1,y1,x2,y2;
+
+ x1=9999;
+ y1=9999;
+ x2=-9999;
+ y2=-9999;
+
+ for(f=0;f<dialog_no;f++)
+ if (f!=i)
+ {
+ x1=MIN(x1,dialog[f].common.box.x);
+ y1=MIN(y1,dialog[f].common.box.y);
+
+ x2=MAX(x2,dialog[f].common.box.x+dialog[f].common.box.w);
+ y2=MAX(y2,dialog[f].common.box.y+dialog[f].common.box.h);
+ }
+
+ x1-=BEVEL*3;
+ y1-=BEVEL*3;
+ x2+=BEVEL*3;
+ y2+=BEVEL*3;
+
+ if (dialog[i].box.title)
+ y1-=FH*2;
+
+ dialog[i].common.box.x=x1;
+ dialog[i].common.box.y=y1;
+ dialog[i].common.box.w=x2-x1;
+ dialog[i].common.box.h=y2-y1;
+}
+
+
+static void DialCommon(int no, ObjType t, int x, int y, int w, int h, int focus)
+{
+ dialog=ReGrab(dialog,sizeof(GuiObj)*(no+1));
+
+ dialog[no].common.type=t;
+ dialog[no].common.box.x=x;
+ dialog[no].common.box.y=y;
+ dialog[no].common.box.w=w;
+ dialog[no].common.box.h=h;
+ dialog[no].common.take_focus=focus;
+ dialog[no].common.focus=FALSE;
+}
+
+
+static int CreateBox(int x, int y, int w, int h, const char *title, int invert)
+{
+ int no=dialog_no++;
+
+ DialCommon(no,GuiBox,x,y,w,h,FALSE);
+
+ dialog[no].box.title=title;
+ dialog[no].box.invert=invert;
+ dialog[no].box.img=NULL;
+
+ return no;
+}
+
+
+static int CreateLabel(int x, int y, int w, int h, const char *label,
+ int col,int centre)
+{
+ int no=dialog_no++;
+
+ if (w==-1)
+ w=LENGTH(label);
+
+ DialCommon(no,GuiLabel,x,y,w,h,FALSE);
+
+ dialog[no].lbl.text=label;
+ dialog[no].lbl.col=col;
+ dialog[no].lbl.centre=centre;
+
+ return no;
+}
+
+
+static int CreateButton(int x, int y, int w, int h, const char *label)
+{
+ int no=dialog_no++;
+
+ DialCommon(no,GuiButton,x,y,w,h,TRUE);
+
+ dialog[no].lbl.text=label;
+
+ return no;
+}
+
+
+static int CreateToggle(int x, int y, int w, int h,
+ const char *label, int state)
+{
+ int no=dialog_no++;
+
+ DialCommon(no,GuiToggle,x,y,w,h,TRUE);
+
+ dialog[no].tog.text=label;
+ dialog[no].tog.state=state;
+
+ return no;
+}
+
+
+static int CreateRadio(int x, int y, int w, int h,
+ const char *label, int group, int state)
+{
+ int no=dialog_no++;
+
+ DialCommon(no,GuiRadio,x,y,w,h,TRUE);
+
+ dialog[no].rad.text=label;
+ dialog[no].rad.group=group;
+ dialog[no].rad.state=state;
+
+ return no;
+}
+
+
+static int CreateText(int x, int y, int w, int h, char *text,
+ GuiTextMode mode, int allow_exit)
+{
+ int no=dialog_no++;
+
+ DialCommon(no,GuiText,x,y,w,h,mode!=GuiTextReadOnly);
+
+ strcpy(dialog[no].txt.text,text);
+
+ dialog[no].txt.len=strlen(text);
+ dialog[no].txt.no_chars=(w-BEVEL*2)/FW;
+ dialog[no].txt.curs=dialog[no].txt.len;
+ dialog[no].txt.mode=mode;
+ dialog[no].txt.allow_exit=allow_exit;
+
+ dialog[no].txt.first=MAX(0,dialog[no].txt.len-dialog[no].txt.no_chars);
+
+ return no;
+}
+
+
+static void ResetText(int no, char *text)
+{
+ if (dialog[no].common.type!=GuiText)
+ return;
+
+ strcpy(dialog[no].txt.text,text);
+
+ dialog[no].txt.len=strlen(text);
+ dialog[no].txt.curs=dialog[no].txt.len;
+ dialog[no].txt.first=MAX(0,dialog[no].txt.len-dialog[no].txt.no_chars);
+}
+
+
+static int CreateImageList(int x, int y, int w, int h,
+ int no_items, char *items[],
+ GFX_IMAGE img[], int curr, int img_box,
+ int allow_double_click)
+{
+ int no=dialog_no++;
+
+ DialCommon(no,GuiImageList,x,y,w,h,TRUE);
+
+ dialog[no].pck.curr=curr;
+ dialog[no].pck.no=no_items;
+ dialog[no].pck.img_box=img_box;
+ dialog[no].pck.items=items;
+ dialog[no].pck.img=img;
+ dialog[no].pck.double_click=allow_double_click;
+
+ dialog[no].pck.no_lines=h/LIST_TEXTHEIGHT;
+
+ if (curr>dialog[no].pck.no_lines)
+ dialog[no].pck.top=curr;
+ else
+ dialog[no].pck.top=0;
+
+ dialog[no].pck.scroll.x=x+w-BEVEL-LIST_SCROLLSIZE;
+ dialog[no].pck.scroll.y=y+BEVEL;
+ dialog[no].pck.scroll.w=LIST_SCROLLSIZE;
+ dialog[no].pck.scroll.h=h-BEVEL*2+1;
+
+ if (no_items>dialog[no].pck.no_lines)
+ {
+ dialog[no].pck.scrollbar=TRUE;
+
+ dialog[no].pck.sbar_step=(double)h/(double)no_items;
+ dialog[no].pck.bar.x=dialog[no].pck.scroll.x;
+ dialog[no].pck.bar.y=dialog[no].pck.scroll.y;
+ dialog[no].pck.bar.w=dialog[no].pck.scroll.w;
+ dialog[no].pck.bar.h=
+ (dialog[no].pck.sbar_step*dialog[no].pck.no_lines+0.5);
+ }
+ else
+ {
+ dialog[no].pck.scrollbar=FALSE;
+
+ dialog[no].pck.bar=dialog[no].pck.scroll;
+ }
+
+ return no;
+}
+
+
+static int CreateFileList(int x, int y, int w, int h,
+ char *path, char *filter,
+ int path_text, int file_text,
+ int allow_double_click)
+{
+ int no=dialog_no++;
+ int charw;
+
+ DialCommon(no,GuiFileList,x,y,w,h,TRUE);
+
+ dialog[no].fle.ent=NULL;
+ strcpy(dialog[no].fle.dir,path);
+ dialog[no].fle.filter=filter;
+ dialog[no].fle.path_text=path_text;
+ dialog[no].fle.file_text=file_text;
+ dialog[no].fle.double_click=allow_double_click;
+
+ dialog[no].fle.no_lines=h/LIST_TEXTHEIGHT;
+
+ dialog[no].fle.scroll.x=x+w-BEVEL-LIST_SCROLLSIZE;
+ dialog[no].fle.scroll.y=y+BEVEL;
+ dialog[no].fle.scroll.w=LIST_SCROLLSIZE;
+ dialog[no].fle.scroll.h=h-BEVEL*2+1;
+
+ charw=(w-BEVEL*2-LIST_SCROLLSIZE)/FW;
+
+ dialog[no].fle.size_width=12;
+ dialog[no].fle.name_width=charw-dialog[no].fle.size_width;
+
+ ResetText(path_text,path);
+ ResetText(file_text,"");
+
+ chdir(path);
+
+ return no;
+}
+
+static int CreateTextEdit(int x, int y, int w, int h,
+ TextEditLine *lines, int no_lines, int info,
+ int read_only)
+{
+ static void TextEditInfo(GuiObjTextEdit *o);
+ int no=dialog_no++;
+
+ DialCommon(no,GuiTextEdit,x,y,w,h,TRUE);
+
+ dialog[no].edt.top=0;
+ dialog[no].edt.x=0;
+ dialog[no].edt.y=0;
+ dialog[no].edt.col=0;
+
+ dialog[no].edt.tline=lines;
+ dialog[no].edt.lines=no_lines;
+
+ dialog[no].edt.info=info;
+ dialog[no].edt.read_only=read_only;
+
+ dialog[no].edt.width=w/FW;
+ dialog[no].edt.height=h/FH;
+
+ TextEditInfo(&dialog[no].edt);
+
+ return no;
+}
+
+
+/* ---------------------------------------- DIALOG CALLBACK FUNCTIONS
+*/
+static CallbackReturn Callback(GuiObj *o, ObjEvent ev)
+{
+ static CallbackReturn BoxCallback(GuiObj *o ,ObjEvent ev);
+ static CallbackReturn LabelCallback(GuiObj *o,ObjEvent ev);
+ static CallbackReturn ButtonCallback(GuiObj *o,ObjEvent ev);
+ static CallbackReturn ToggleCallback(GuiObj *o,ObjEvent ev);
+ static CallbackReturn RadioCallback(GuiObj *o,ObjEvent ev);
+ static CallbackReturn ImageListCallback(GuiObj *o,ObjEvent ev);
+ static CallbackReturn TextCallback(GuiObj *o,ObjEvent ev);
+ static CallbackReturn FileListCallback(GuiObj *o,ObjEvent ev);
+ static CallbackReturn TextEditCallback(GuiObj *o,ObjEvent ev);
+
+ switch(o->common.type)
+ {
+ case GuiBox:
+ return BoxCallback(o,ev);
+ case GuiLabel:
+ return LabelCallback(o,ev);
+ case GuiButton:
+ return ButtonCallback(o,ev);
+ case GuiToggle:
+ return ToggleCallback(o,ev);
+ case GuiRadio:
+ return RadioCallback(o,ev);
+ case GuiImageList:
+ return ImageListCallback(o,ev);
+ case GuiText:
+ return TextCallback(o,ev);
+ case GuiFileList:
+ return FileListCallback(o,ev);
+ case GuiTextEdit:
+ return TextEditCallback(o,ev);
+ default:
+ return GuiOk;
+ }
+}
+
+
+static CallbackReturn BoxCallback(GuiObj *o ,ObjEvent ev)
+{
+ GuiObjBox *b;
+
+ b=&(o->box);
+
+ switch (ev)
+ {
+ case GuiDraw:
+ if (!b->img)
+ {
+ Rect3DBox(&b->common.box,b->invert,BEVEL);
+
+ if (b->title)
+ {
+ int x,y,w;
+
+ x=b->common.box.x+BEVEL*2;
+ y=b->common.box.y+BEVEL;
+ w=b->common.box.w-BEVEL*4;
+
+ CENTREX(x,y,w,GUI_TEXTBOLD,b->title);
+
+ GFX_line(x,y+FH+FH/2,x+w,y+FH+FH/2,GUI_HI);
+ GFX_line(x,y+FH+FH/2+1,x+w,y+FH+FH/2+1,GUI_LO);
+ }
+ }
+ else
+ {
+ Rect3DBox(&b->common.box,b->invert,BEVEL);
+
+ GFX_draw_image(b->img,
+ b->common.box.x+b->common.box.w/2-b->img->w/2,
+ b->common.box.y+b->common.box.h/2-b->img->h/2);
+ }
+ break;
+
+ case GuiKeyPress:
+ break;
+
+ case GuiButtonPress:
+ break;
+
+ case GuiWheelUp:
+ break;
+
+ case GuiWheelDown:
+ break;
+
+ case GuiExit:
+ break;
+ }
+ return GuiOk;
+}
+
+
+static CallbackReturn LabelCallback(GuiObj *o ,ObjEvent ev)
+{
+ GuiObjLabel *l;
+
+ l=&(o->lbl);
+
+ switch (ev)
+ {
+ case GuiDraw:
+ GFX_frect(l->common.box.x,l->common.box.y,
+ l->common.box.w,l->common.box.h,GUI_MID);
+
+ if (l->centre)
+ CENTREXY(l->common.box.x,l->common.box.y,
+ l->common.box.w,l->common.box.h,l->col,l->text);
+ else
+ CENTREY(l->common.box.x,l->common.box.y,
+ l->common.box.h,l->col,l->text);
+ break;
+
+ case GuiKeyPress:
+ break;
+
+ case GuiButtonPress:
+ break;
+
+ case GuiWheelUp:
+ break;
+
+ case GuiWheelDown:
+ break;
+
+ case GuiExit:
+ break;
+ }
+ return GuiOk;
+}
+
+
+static CallbackReturn ButtonCallback(GuiObj *o ,ObjEvent ev)
+{
+ GuiObjButton *b;
+
+ b=&(o->but);
+
+ switch (ev)
+ {
+ case GuiDraw:
+ if (b->common.focus)
+ GFX_rect(b->common.box.x,b->common.box.y,
+ b->common.box.w,b->common.box.h,GUI_TEXTBOLD);
+ else
+ GFX_rect(b->common.box.x,b->common.box.y,
+ b->common.box.w,b->common.box.h,GUI_MID);
+
+ Rect3D(b->common.box.x+1,b->common.box.y+1,
+ b->common.box.w-2,b->common.box.h-2,
+ FALSE,BEVEL);
+
+ CENTREXY(b->common.box.x,b->common.box.y,
+ b->common.box.w,b->common.box.h,GUI_TEXTBOLD,b->text);
+ break;
+
+ case GuiKeyPress:
+ if (key!=GFX_ENTER)
+ break;
+
+ /* CAUTION: Case above runs into this
+ */
+ case GuiButtonPress:
+ Rect3D(b->common.box.x+1,b->common.box.y+1,
+ b->common.box.w-2,b->common.box.h-2,
+ TRUE,BEVEL);
+
+ CENTREXY(b->common.box.x,b->common.box.y,
+ b->common.box.w,b->common.box.h,GUI_TEXTBOLD,b->text);
+
+ return GuiDone;
+ break;
+
+ case GuiWheelUp:
+ break;
+
+ case GuiWheelDown:
+ break;
+
+ case GuiExit:
+ break;
+ }
+
+ return GuiOk;
+}
+
+
+static CallbackReturn ToggleCallback(GuiObj *op ,ObjEvent ev)
+{
+ GuiObjToggle *o;
+ int x,y,w,h;
+
+ o=&(op->tog);
+
+ x=o->common.box.x;
+ y=o->common.box.y;
+ w=o->common.box.h;
+ h=o->common.box.h;
+
+ switch (ev)
+ {
+ case GuiDraw:
+ if (o->common.focus)
+ GFX_rect(x,y,w,h,GUI_TEXTBOLD);
+ else
+ GFX_rect(x,y,w,h,GUI_MID);
+
+ CENTREY(o->common.box.x+o->common.box.h+FW,o->common.box.y,
+ o->common.box.h,GUI_TEXT,o->text);
+
+ Tickbox(x+1,y+1,w-2,h-2,o->state);
+
+ break;
+
+ case GuiKeyPress:
+ if (key!=GFX_ENTER && ascii!=' ')
+ break;
+
+ /* CAUTION: Case above runs into this
+ */
+ case GuiButtonPress:
+ o->state=!o->state;
+ return GuiRedraw;
+ break;
+
+ case GuiWheelUp:
+ break;
+
+ case GuiWheelDown:
+ break;
+
+ case GuiExit:
+ break;
+ }
+
+ return GuiOk;
+}
+
+
+static CallbackReturn RadioCallback(GuiObj *op ,ObjEvent ev)
+{
+ GuiObjRadio *o;
+ int x,y,w,h;
+
+ o=&(op->rad);
+
+ x=o->common.box.x;
+ y=o->common.box.y;
+ w=o->common.box.h;
+ h=o->common.box.h;
+
+ switch (ev)
+ {
+ case GuiDraw:
+ if (o->common.focus)
+ GFX_rect(x,y,w,h,GUI_TEXTBOLD);
+ else
+ GFX_rect(x,y,w,h,GUI_MID);
+
+ CENTREY(o->common.box.x+o->common.box.h+FW,o->common.box.y,
+ o->common.box.h,GUI_TEXT,o->text);
+
+ Tickbox(x+1,y+1,w-2,h-2,o->state);
+
+ break;
+
+ case GuiKeyPress:
+ if (key!=GFX_ENTER && ascii!=' ')
+ break;
+
+ /* CAUTION: Case above runs into this
+ */
+ case GuiButtonPress:
+ if (!o->state)
+ {
+ int f;
+
+ for(f=0;f<dialog_no;f++)
+ if (dialog[f].common.type==GuiRadio &&
+ dialog[f].rad.group==o->group)
+ dialog[f].rad.state=FALSE;
+
+ o->state=TRUE;
+
+ return GuiRedraw;
+ }
+ break;
+
+ case GuiWheelUp:
+ break;
+
+ case GuiWheelDown:
+ break;
+
+ case GuiExit:
+ break;
+ }
+
+ return GuiOk;
+}
+
+
+static CallbackReturn HandleImageListPage(GuiObjImageList *o, int keycode)
+{
+ switch(keycode)
+ {
+ case GFX_UP:
+ case GFX_PGUP:
+ if (o->curr>0)
+ {
+ o->curr=MAX(0,o->curr-(key==GFX_UP ? 1:o->no_lines));
+
+ if (o->curr<o->top)
+ o->top=o->curr;
+
+ if ((o->top+o->no_lines)<=o->curr)
+ o->top=o->curr-o->no_lines+1;
+
+ return GuiRedraw;
+ }
+ break;
+
+ case GFX_DOWN:
+ case GFX_PGDN:
+ if (o->curr<(o->no-1))
+ {
+ o->curr=MIN(o->no-1,o->curr+
+ (key==GFX_DOWN ? 1:o->no_lines));
+
+ if (o->curr<o->top)
+ o->top=o->curr;
+
+ if ((o->top+o->no_lines)<=o->curr)
+ o->top=o->curr-o->no_lines+1;
+
+ return GuiRedraw;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return GuiOk;
+}
+
+
+static CallbackReturn ImageListCallback(GuiObj *op ,ObjEvent ev)
+{
+ static time_t last=0;
+ GuiObjImageList *o;
+ int x,y,w,h;
+ int sx,sy,sw,sh;
+ int f;
+
+ o=&(op->pck);
+
+ x=o->common.box.x+BEVEL;
+ y=o->common.box.y+BEVEL;
+ w=o->common.box.w-BEVEL*2;
+ h=o->common.box.h-BEVEL*2;
+
+ sx=o->scroll.x;
+ sy=o->scroll.y;
+ sw=o->scroll.w;
+ sh=o->scroll.h;
+
+ switch (ev)
+ {
+ case GuiDraw:
+ if (o->common.focus)
+ GFX_rect(x-BEVEL-1,y-BEVEL-1,
+ w+BEVEL*2+2,h+BEVEL*2+2,GUI_TEXTBOLD);
+ else
+ GFX_rect(x-BEVEL-1,y-BEVEL-1,
+ w+BEVEL*2+2,h+BEVEL*2+2,GUI_MID);
+
+ Rect3DBox(&o->common.box,TRUE,BEVEL);
+
+ GFX_frect(x,y,w,h,WHITE);
+
+ GFX_frect(sx,sy,sw,sh,GUI_MID);
+
+ o->bar.y=sy+o->sbar_step*o->top;
+ Rect3DBox(&o->bar,FALSE,SMALL_BEVEL);
+
+ for(f=0;f<o->no_lines;f++)
+ {
+ int col;
+ int p=f+o->top;
+ int tx=x;
+ int ty=y+(f*LIST_TEXTHEIGHT);
+ int tw=w-sw;
+ int th=LIST_TEXTHEIGHT;
+
+ if (p==o->curr)
+ {
+ col=WHITE;
+ GFX_frect(tx,ty,tw,th,BLACK);
+ }
+ else
+ col=BLACK;
+
+ if (p<o->no)
+ CENTREY(tx,ty,th,col,o->items[p]);
+ }
+
+ if (o->img)
+ {
+ dialog[o->img_box].box.img=o->img[o->curr];
+ Callback(dialog+o->img_box,GuiDraw);
+ }
+
+ break;
+
+ case GuiKeyPress:
+ switch(key)
+ {
+ case GFX_UP:
+ case GFX_PGUP:
+ case GFX_DOWN:
+ case GFX_PGDN:
+ return HandleImageListPage(o,key);
+ break;
+
+ case GFX_ENTER:
+ return GuiDone;
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ case GuiButtonPress:
+ if (IsInBox(&o->scroll))
+ {
+ if (!o->scrollbar)
+ return GuiOk;
+
+ if (IsInBox(&o->bar))
+ {
+ int orig;
+ int y;
+ double dtop;
+
+ orig=mouse_y;
+ dtop=o->top;
+
+ while (GFX_mouse(NULL,&y)==GFX_BUTLEFT)
+ {
+ int diff;
+
+ diff=y-orig;
+
+ dtop+=diff/o->sbar_step;
+
+ o->top=(int)dtop;
+
+ o->top=MAX(0,o->top);
+ o->top=MIN(o->no-o->no_lines,o->top);
+
+ Callback(op,GuiDraw);
+ GFX_redraw();
+
+ orig=y;
+ }
+ }
+ else
+ {
+ if (mouse_y<o->bar.y)
+ o->top=MAX(0,o->top-o->no_lines);
+ else
+ o->top=MIN(o->no-1-o->no_lines,o->top+o->no_lines);
+
+ return GuiRedraw;
+ }
+ }
+ else
+ {
+ int my;
+ int pick;
+
+ my=mouse_y-y;
+
+ pick=o->top+my/LIST_TEXTHEIGHT;
+
+ if (pick<o->no)
+ {
+ if (pick==o->curr && (time(NULL)-last)<2 &&
+ o->double_click)
+ return GuiDone;
+
+ last=time(NULL);
+
+ o->curr=pick;
+ return GuiRedraw;
+ }
+ }
+ break;
+
+ case GuiWheelUp:
+ return HandleImageListPage(o,GFX_PGUP);
+ break;
+
+ case GuiWheelDown:
+ return HandleImageListPage(o,GFX_PGDN);
+ break;
+
+ case GuiExit:
+ break;
+ }
+
+ return GuiOk;
+}
+
+
+static CallbackReturn TextCallback(GuiObj *op ,ObjEvent ev)
+{
+ int x,y,w,h;
+ GuiObjText *o;
+ int f;
+ int ok;
+
+ o=&(op->txt);
+
+ x=o->common.box.x+BEVEL;
+ y=o->common.box.y+BEVEL;
+ w=o->common.box.w-BEVEL*2;
+ h=o->common.box.h-BEVEL*2;
+
+ switch (ev)
+ {
+ case GuiDraw:
+ if (o->common.focus)
+ GFX_rect(x-BEVEL-1,y-BEVEL-1,
+ w+BEVEL*2+2,h+BEVEL*2+2,GUI_TEXTBOLD);
+ else
+ GFX_rect(x-BEVEL-1,y-BEVEL-1,
+ w+BEVEL*2+2,h+BEVEL*2+2,GUI_MID);
+
+ Rect3DBox(&o->common.box,TRUE,BEVEL);
+
+ if (o->mode!=GuiTextReadOnly)
+ GFX_frect(x,y,w,h,WHITE);
+
+ for(f=0;f<o->no_chars;f++)
+ {
+ int col;
+ int pos;
+ int tx;
+
+ tx=x+f*FW;
+ pos=o->first+f;
+
+ if (o->common.focus)
+ {
+ if (pos==o->curs)
+ {
+ GFX_frect(tx,y,FW,FH,BLACK);
+ col=WHITE;
+ }
+ else
+ col=BLACK;
+ }
+ else
+ col=BLACK;
+
+ if (pos<o->len)
+ GFX_print(tx,y,col,"%c",o->text[pos]);
+
+ tx+=FW;
+ }
+
+ break;
+
+ case GuiKeyPress:
+ switch(key)
+ {
+ case GFX_LEFT:
+ o->curs--;
+ o->curs=MAX(0,o->curs);
+ o->curs=MIN(o->len,o->curs);
+
+ if (o->curs<o->first)
+ o->first--;
+
+ return GuiRedraw;
+ break;
+
+ case GFX_RIGHT:
+ o->curs++;
+ o->curs=MIN(o->len,o->curs);
+
+ if (o->curs>(o->first+o->no_chars-1))
+ o->first++;
+
+ return GuiRedraw;
+ break;
+
+ case GFX_ENTER:
+ if (o->allow_exit)
+ return GuiDone;
+ break;
+
+ case GFX_BACKSPACE:
+ case GFX_DELETE:
+ if (o->curs)
+ {
+ memmove(o->text+o->curs-1,o->text+o->curs,
+ o->len-o->curs+1);
+
+ if (--o->curs<o->first)
+ o->first--;
+
+ o->len=strlen(o->text);
+
+ return GuiRedraw;
+ }
+ break;
+
+ case GFX_END:
+ o->curs=o->len;
+ o->first=MAX(0,o->len-o->no_chars-1);
+ return GuiRedraw;
+ break;
+
+ case GFX_HOME:
+ o->curs=0;
+ o->first=0;
+ return GuiRedraw;
+ break;
+
+ default:
+ switch(o->mode)
+ {
+ case GuiTextString:
+ ok=isprint(ascii);
+ break;
+ case GuiTextInteger:
+ if (strchr("-+0123456789",ascii))
+ ok=TRUE;
+ else
+ ok=FALSE;
+ break;
+ case GuiTextDouble:
+ if (strchr(".-+0123456789",ascii))
+ ok=TRUE;
+ else
+ ok=FALSE;
+ break;
+ case GuiTextReadOnly:
+ ok=FALSE;
+ break;
+ default:
+ ok=FALSE;
+ break;
+ }
+
+ if (ok && o->len<PATH_MAX)
+ {
+ if (o->curs==o->len)
+ {
+ o->text[o->curs++]=ascii;
+ o->text[o->curs]=0;
+ }
+ else
+ {
+ memmove(o->text+o->curs+1,o->text+o->curs,
+ o->len-o->curs+1);
+ o->text[o->curs++]=ascii;
+ }
+
+ o->len=strlen(o->text);
+
+ if (o->curs>(o->first+o->no_chars-1))
+ o->first++;
+
+ return GuiRedraw;
+ }
+
+ break;
+ }
+
+ break;
+
+ case GuiButtonPress:
+ break;
+
+ case GuiWheelUp:
+ break;
+
+ case GuiWheelDown:
+ break;
+
+ case GuiExit:
+ break;
+ }
+
+ return GuiOk;
+}
+
+
+static CallbackReturn HandleFileListPage(GuiObjFileList *o, int keycode)
+{
+ switch(keycode)
+ {
+ case GFX_UP:
+ case GFX_PGUP:
+ if (o->curr>0)
+ {
+ o->curr=MAX(0,o->curr-(key==GFX_UP ? 1:o->no_lines));
+
+ if (o->curr<o->top)
+ o->top=o->curr;
+
+ if ((o->top+o->no_lines)<=o->curr)
+ o->top=o->curr-o->no_lines+1;
+ }
+ break;
+
+ case GFX_DOWN:
+ case GFX_PGDN:
+ if (o->curr<(o->no-1))
+ {
+ o->curr=MIN(o->no-1,o->curr+
+ (key==GFX_DOWN ? 1:o->no_lines));
+
+ if (o->curr<o->top)
+ o->top=o->curr;
+
+ if ((o->top+o->no_lines)<=o->curr)
+ o->top=o->curr-o->no_lines+1;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (o->ent[o->curr].is_dir)
+ ResetText(o->file_text,"");
+ else
+ ResetText(o->file_text,o->ent[o->curr].name);
+
+ return GuiRedraw;
+}
+
+
+static int SortFiles(const void *a, const void *b)
+{
+ const FileEnt *fa,*fb;
+
+ fa=a;
+ fb=b;
+
+ if (fa->is_dir && !fb->is_dir)
+ return -1;
+ else if (!fa->is_dir && fb->is_dir)
+ return 1;
+ else
+ return strcmp(fa->name,fb->name);
+}
+
+
+static int FilesMatch(const char *file, const char *filter)
+{
+ if (!filter)
+ return TRUE;
+
+ if (strlen(file)<strlen(filter))
+ return FALSE;
+
+ if (strcasecmp(file+strlen(file)-strlen(filter),filter))
+ return FALSE;
+ else
+ return TRUE;
+}
+
+
+static void GetFileList(GuiObjFileList *o)
+{
+ DIR *d;
+ int l;
+
+ if (o->ent)
+ Release(o->ent);
+
+ o->ent=NULL;
+ o->no=0;
+ o->curr=0;
+ o->top=0;
+
+ getcwd(o->dir,PATH_MAX);
+
+ if (o->dir[l=(strlen(o->dir)-1)]!='/')
+ {
+ o->dir[++l]='/';
+ o->dir[++l]=0;
+ }
+
+ if ((d=opendir(o->dir)))
+ {
+ struct dirent *ent;
+ struct stat sbuf;
+
+ while ((ent=readdir(d)))
+ {
+ if (!stat(ent->d_name,&sbuf))
+ if (S_ISDIR(sbuf.st_mode) || FilesMatch(ent->d_name,o->filter))
+ {
+ o->no++;
+ o->ent=ReGrab(o->ent,sizeof(FileEnt)*o->no);
+
+ strcpy(o->ent[o->no-1].name,ent->d_name);
+ o->ent[o->no-1].is_dir=S_ISDIR(sbuf.st_mode);
+ o->ent[o->no-1].size=sbuf.st_size;
+ }
+ }
+
+ closedir(d);
+ }
+
+ ResetText(o->file_text,"");
+ ResetText(o->path_text,o->dir);
+
+ qsort(o->ent,o->no,sizeof(FileEnt),SortFiles);
+
+ if (o->no>o->no_lines)
+ {
+ o->scrollbar=TRUE;
+
+ o->sbar_step=(double)o->common.box.h/(double)o->no;
+ o->bar.x=o->scroll.x;
+ o->bar.y=o->scroll.y;
+ o->bar.w=o->scroll.w;
+ o->bar.h=(o->sbar_step*o->no_lines+0.5);
+ }
+ else
+ {
+ o->scrollbar=FALSE;
+ o->bar=o->scroll;
+ }
+}
+
+
+static CallbackReturn FileListCallback(GuiObj *op ,ObjEvent ev)
+{
+ static time_t last=0;
+ static char buff[PATH_MAX+10];
+ GuiObjFileList *o;
+ int x,y,w,h;
+ int sx,sy,sw,sh;
+ int f;
+
+ o=&(op->fle);
+
+ if (!o->ent)
+ GetFileList(o);
+
+ x=o->common.box.x+BEVEL;
+ y=o->common.box.y+BEVEL;
+ w=o->common.box.w-BEVEL*2;
+ h=o->common.box.h-BEVEL*2;
+
+ sx=o->scroll.x;
+ sy=o->scroll.y;
+ sw=o->scroll.w;
+ sh=o->scroll.h;
+
+ switch (ev)
+ {
+ case GuiDraw:
+ if (o->common.focus)
+ GFX_rect(x-BEVEL-1,y-BEVEL-1,
+ w+BEVEL*2+2,h+BEVEL*2+2,GUI_TEXTBOLD);
+ else
+ GFX_rect(x-BEVEL-1,y-BEVEL-1,
+ w+BEVEL*2+2,h+BEVEL*2+2,GUI_MID);
+
+ Rect3DBox(&o->common.box,TRUE,BEVEL);
+
+ GFX_frect(x,y,w,h,WHITE);
+
+ GFX_frect(sx,sy,sw,sh,GUI_MID);
+
+ o->bar.y=sy+o->sbar_step*o->top;
+ Rect3DBox(&o->bar,FALSE,SMALL_BEVEL);
+
+ for(f=0;f<o->no_lines;f++)
+ {
+ int col;
+ int p=f+o->top;
+ int tx=x;
+ int ty=y+(f*LIST_TEXTHEIGHT);
+ int tw=w-sw;
+ int th=LIST_TEXTHEIGHT;
+
+ if (p==o->curr)
+ {
+ col=WHITE;
+ GFX_frect(tx,ty,tw,th,BLACK);
+ }
+ else
+ col=BLACK;
+
+ if (p<o->no)
+ {
+ if (o->ent[p].is_dir)
+ sprintf(buff,"%-*.*s%*.*s",
+ o->name_width,
+ o->name_width,
+ o->ent[p].name,
+ o->size_width,
+ o->size_width,
+ "<Directory>");
+ else
+ sprintf(buff,"%-*.*s%*ld",
+ o->name_width,
+ o->name_width,
+ o->ent[p].name,
+ o->size_width,
+ o->ent[p].size);
+
+ CENTREY(tx,ty,th,col,buff);
+ }
+ }
+
+ break;
+
+ case GuiKeyPress:
+ switch(key)
+ {
+ case GFX_UP:
+ case GFX_PGUP:
+ case GFX_DOWN:
+ case GFX_PGDN:
+ return HandleFileListPage(o,key);
+ break;
+
+ case GFX_ENTER:
+ if (!o->ent[o->curr].is_dir)
+ return GuiDone;
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ case GuiButtonPress:
+ if (IsInBox(&o->scroll))
+ {
+ if (!o->scrollbar)
+ return GuiOk;
+
+ if (IsInBox(&o->bar))
+ {
+ int orig;
+ int y;
+ double dtop;
+
+ orig=mouse_y;
+ dtop=o->top;
+
+ while (GFX_mouse(NULL,&y)==GFX_BUTLEFT)
+ {
+ int diff;
+
+ diff=y-orig;
+
+ dtop+=diff/o->sbar_step;
+
+ o->top=(int)dtop;
+
+ o->top=MAX(0,o->top);
+ o->top=MIN(o->no-o->no_lines,o->top);
+
+ Callback(op,GuiDraw);
+ GFX_redraw();
+
+ orig=y;
+ }
+ }
+ else
+ {
+ if (mouse_y<o->bar.y)
+ o->top=MAX(0,o->top-o->no_lines);
+ else
+ o->top=MIN(o->no-1-o->no_lines,o->top+o->no_lines);
+
+ return GuiRedraw;
+ }
+ }
+ else
+ {
+ int my;
+ int pick;
+
+ my=mouse_y-y;
+
+ pick=o->top+my/LIST_TEXTHEIGHT;
+
+ if (pick<o->no)
+ {
+ if (pick==o->curr && (time(NULL)-last)<2 && o->double_click)
+ {
+ if (o->ent[o->curr].is_dir)
+ {
+ chdir(o->ent[o->curr].name);
+ GetFileList(o);
+ last=0;
+ return GuiRedraw;
+ }
+ else
+ return GuiDone;
+ }
+
+ last=time(NULL);
+
+ o->curr=pick;
+
+ if (!o->ent[o->curr].is_dir)
+ ResetText(o->file_text,o->ent[o->curr].name);
+
+ return GuiRedraw;
+ }
+ }
+ break;
+
+ case GuiWheelUp:
+ return HandleFileListPage(o,GFX_PGUP);
+ break;
+
+ case GuiWheelDown:
+ return HandleFileListPage(o,GFX_PGDN);
+ break;
+
+ case GuiExit:
+ if (o->ent)
+ Release(o->ent);
+ break;
+ }
+
+ return GuiOk;
+}
+
+
+static void TextEditInfo(GuiObjTextEdit *o)
+{
+ char b1[128];
+ char b2[128];
+ char buff[128];
+
+ sprintf(b1,"Cursor: %d,%d",o->x+1,o->y+1);
+ sprintf(b2,"Lines: %d",o->lines);
+ sprintf(buff,"%-20.20s %s",b1,b2);
+
+ ResetText(o->info,buff);
+}
+
+
+static CallbackReturn TextEditCallback(GuiObj *op ,ObjEvent ev)
+{
+ char out;
+ char *tmp;
+ GuiObjTextEdit *te;
+ TextEditLine *p;
+ int bx,by,bw,bh;
+ int x,y,sx,sy;
+ int f;
+ int mod;
+
+ te=&op->edt;
+ p=te->tline;
+
+ bx=te->common.box.x;
+ by=te->common.box.y;
+ bw=te->common.box.w;
+ bh=te->common.box.h;
+
+ switch(ev)
+ {
+ case GuiDraw:
+ if (te->common.focus)
+ GFX_rect(bx-2,by-2,bw+4,bh+4,GUI_TEXTBOLD);
+ else
+ GFX_rect(bx-2,by-2,bw+4,bh+4,GUI_MID);
+
+ GFX_frect(bx,by,bw,bh,WHITE);
+
+ y=te->top;
+
+ for(sy=0;sy<te->height;sy++,y++)
+ if (y<te->lines)
+ {
+ x=te->col;
+
+ for(sx=0;sx<te->width;sx++,x++)
+ {
+ if (x<p[y].len && isprint(p[y].p[x]))
+ out=p[y].p[x];
+ else
+ out=' ';
+
+ if (x==te->x && y==te->y)
+ {
+ GFX_frect(bx+(sx*FW),by+(sy*FH),FW,FH,BLACK);
+ GFX_print(bx+(sx*FW),by+(sy*FH),WHITE,"%c",out);
+ }
+ else
+ GFX_print(bx+(sx*FW),by+(sy*FH),BLACK,"%c",out);
+ }
+ }
+
+ break;
+
+ case GuiButtonPress:
+ te->y=(mouse_y-by)/FH;
+ te->x=te->col+(mouse_x-bx)/FW;
+
+ if (te->y>=te->lines)
+ te->y=te->lines-1;
+
+ if (te->x>p[te->y].len)
+ te->x=p[te->y].len;
+
+ TextEditInfo(te);
+ return GuiRedraw;
+ break;
+
+ case GuiKeyPress:
+ switch(key)
+ {
+ case GFX_HOME:
+ te->x=0;
+ te->col=0;
+ break;
+
+ case GFX_END:
+ te->x=p[te->y].len;
+ te->col=MAX(0,te->x-te->width);
+ break;
+
+ case GFX_LEFT:
+ mod=ctrl||shift;
+
+ if (mod)
+ while((te->x)&&(isspace(p[te->y].p[te->x])))
+ {
+ if (te->x)
+ te->x--;
+ else
+ mod=FALSE;
+
+ if (te->x<te->col)
+ te->col--;
+ }
+
+ do {
+ if (te->x)
+ te->x--;
+ else
+ mod=FALSE;
+
+ if (te->x<te->col)
+ te->col--;
+
+ if (isspace(p[te->y].p[te->x]))
+ mod=FALSE;
+
+ } while(mod);
+
+ break;
+
+ case GFX_RIGHT:
+ mod=ctrl||shift;
+
+ if (mod)
+ while((te->x<p[te->y].len)&&
+ (isspace(p[te->y].p[te->x])))
+ {
+ te->x++;
+
+ if ((te->x-te->width)>te->col)
+ te->col++;
+ }
+
+ do {
+ if (te->x<p[te->y].len)
+ {
+ te->x++;
+
+ if ((te->x-te->width)>te->col)
+ te->col++;
+ }
+ else
+ mod=FALSE;
+
+ if (isspace(p[te->y].p[te->x]))
+ mod=FALSE;
+
+ } while(mod);
+
+ break;
+
+ case GFX_UP:
+ if (te->y)
+ {
+ te->y--;
+
+ if (te->y<te->top)
+ te->top--;
+
+ if (te->x>p[te->y].len)
+ {
+ te->x=p[te->y].len;
+ te->col=MAX(0,te->x-te->width);
+ }
+ }
+ break;
+
+ case GFX_PGUP:
+ if (te->y)
+ {
+ te->y-=te->height;
+
+ if (te->y<0)
+ te->y=0;
+
+ if (te->y<te->top)
+ te->top=te->y;
+
+ if (te->x>p[te->y].len)
+ {
+ te->x=p[te->y].len;
+ te->col=MAX(0,te->x-te->width);
+ }
+ }
+ break;
+
+ case GFX_DOWN:
+ if (p[te->y+1].p)
+ {
+ te->y++;
+
+ if (te->y>=te->top+te->height)
+ te->top=te->y-te->height+1;
+
+ if (te->x>p[te->y].len)
+ {
+ te->x=p[te->y].len;
+ te->col=MAX(0,te->x-te->width);
+ }
+ }
+ break;
+
+ case GFX_PGDN:
+ te->y+=te->height;
+
+ if (te->y>=te->lines)
+ te->y=te->lines-1;
+
+ if (te->y>=te->top+te->height)
+ te->top=te->y-te->height+1;
+
+ if (te->x>p[te->y].len)
+ {
+ te->x=p[te->y].len;
+ te->col=MAX(0,te->x-te->width);
+ }
+
+ break;
+
+ case GFX_DELETE:
+ if (te->read_only)
+ break;
+
+ if (p[te->y].p[te->x])
+ {
+ for(f=te->x;f<p[te->y].len;f++)
+ p[te->y].p[f]=p[te->y].p[f+1];
+
+ p[te->y].len--;
+ p[te->y].p[p[te->y].len]=0;
+ }
+ else if (p[te->y+1].p)
+ {
+ p[te->y].len+=p[te->y+1].len;
+
+ p[te->y].p=ReGrab(p[te->y].p,
+ (p[te->y].len/TE_CHUNK+1)*TE_CHUNK+1);
+
+ strcat(p[te->y].p,p[te->y+1].p);
+
+ Release(p[te->y+1].p);
+
+ for(f=te->y+1;f<te->lines;f++)
+ p[f]=p[f+1];
+
+ te->lines--;
+
+ p=te->tline=ReGrab(te->tline,
+ sizeof(TextEditLine)*(te->lines+1));
+ p[te->lines].p=NULL;
+ }
+ break;
+
+ case GFX_BACKSPACE:
+ if (te->read_only)
+ break;
+
+ if (te->x)
+ {
+ for(f=te->x;f<p[te->y].len;f++)
+ p[te->y].p[f-1]=p[te->y].p[f];
+
+ p[te->y].len--;
+ te->x--;
+ p[te->y].p[p[te->y].len]=0;
+
+ if (te->x<te->col)
+ te->col--;
+ }
+ else if (te->y)
+ {
+ te->x=p[te->y-1].len;
+ te->col=MAX(0,te->x-te->width);
+
+ p[te->y-1].len+=p[te->y].len;
+
+ p[te->y-1].p=ReGrab(p[te->y-1].p,
+ (p[te->y-1].len/TE_CHUNK+1)*TE_CHUNK+1);
+
+ strcat(p[te->y-1].p,p[te->y].p);
+
+ Release(p[te->y].p);
+
+ for(f=te->y;f<te->lines;f++)
+ p[f]=p[f+1];
+
+ if (--te->y<te->top)
+ te->top--;
+
+ te->lines--;
+ p=te->tline=ReGrab(te->tline,
+ sizeof(TextEditLine)*(te->lines+1));
+ p[te->lines].p=NULL;
+ }
+ break;
+
+ case GFX_ENTER:
+ if (te->read_only)
+ break;
+
+ te->lines++;
+ p=te->tline=ReGrab(te->tline,
+ sizeof(TextEditLine)*(te->lines+1));
+
+ for(f=te->lines;f>te->y;f--)
+ p[f]=p[f-1];
+
+ tmp=Strdup(p[te->y].p+te->x);
+ tmp=ReGrab(tmp,(strlen(tmp)/TE_CHUNK+1)*TE_CHUNK+1);
+
+ p[te->y].p[te->x]=0;
+ p[te->y].len=strlen(p[te->y].p);
+
+ te->y++;
+ te->x=0;
+ te->col=0;
+
+ p[te->y].p=tmp;
+ p[te->y].len=strlen(tmp);
+
+ if (te->y>=te->top+te->height)
+ te->top=te->y-te->height+1;
+
+ break;
+
+ default:
+ if (ascii && !te->read_only)
+ {
+ p[te->y].len++;
+
+ if (!(p[te->y].len%TE_CHUNK))
+ p[te->y].p=ReGrab(p[te->y].p,
+ (p[te->y].len/TE_CHUNK+1)*
+ TE_CHUNK+1);
+
+ for(f=p[te->y].len;f>te->x;f--)
+ p[te->y].p[f]=p[te->y].p[f-1];
+
+ p[te->y].p[te->x]=ascii;
+
+ te->x++;
+
+ if ((te->x-te->width)>te->col)
+ te->col++;
+ }
+ break;
+ }
+
+ TextEditInfo(te);
+ return GuiRedraw;
+ break;
+
+ case GuiWheelUp:
+ if (te->y)
+ {
+ te->y-=te->height;
+
+ if (te->y<0)
+ te->y=0;
+
+ if (te->y<te->top)
+ te->top=te->y;
+
+ if (te->x>p[te->y].len)
+ {
+ te->x=p[te->y].len;
+ te->col=MAX(0,te->x-te->width);
+ }
+ }
+
+ TextEditInfo(te);
+ return GuiRedraw;
+ break;
+
+ case GuiWheelDown:
+ te->y+=te->height;
+
+ if (te->y>=te->lines)
+ te->y=te->lines-1;
+
+ if (te->y>=te->top+te->height)
+ te->top=te->y-te->height+1;
+
+ if (te->x>p[te->y].len)
+ {
+ te->x=p[te->y].len;
+ te->col=MAX(0,te->x-te->width);
+ }
+
+ TextEditInfo(te);
+ return GuiRedraw;
+ break;
+
+ case GuiExit:
+ break;
+ }
+
+ return GuiOk;
+}
+
+
+/* ---------------------------------------- DIALOG MAIN LOOP
+*/
+static int DoDial(void)
+{
+ Pixmap saved;
+ int done=FALSE;
+ int f;
+
+ saved=VIDOOM_GFX_SAVE_UNDER(dialog[0].common.box.x,
+ dialog[0].common.box.y,
+ dialog[0].common.box.w,
+ dialog[0].common.box.h);
+
+ for(f=0;(f<dialog_no)&&(focus==-1);f++)
+ if (dialog[f].common.take_focus)
+ focus=f;
+
+ for(f=0;f<dialog_no;f++)
+ dialog[f].common.focus=(f==focus);
+
+ for(f=0;f<dialog_no;f++)
+ Callback(dialog+f,GuiDraw);
+
+ GFX_redraw();
+
+ while(!done)
+ {
+ CallbackReturn cbret=GuiOk;
+ int in=-1;
+
+ GetEvent();
+
+ if (is_key)
+ {
+ if (key==GFX_TAB)
+ {
+ int new;
+ int i;
+
+ i=(shift ? -1:1);
+
+ new=focus;
+
+ do {
+ new+=i;
+
+ if (new<0)
+ new=dialog_no-1;
+ else if (new==dialog_no)
+ new=0;
+ } while(new!=focus && !dialog[new].common.take_focus);
+
+ dialog[focus].common.focus=FALSE;
+ Callback(dialog+focus,GuiDraw);
+
+ focus=new;
+ dialog[focus].common.focus=TRUE;
+ Callback(dialog+focus,GuiDraw);
+ }
+ else if (key==GFX_ESC)
+ {
+ done=TRUE;
+ focus=-1;
+ }
+ else
+ {
+ if (focus!=-1)
+ cbret=Callback(dialog+focus,GuiKeyPress);
+ }
+ }
+ else
+ {
+ for(f=0;(f<dialog_no)&&(in==-1);f++)
+ if (dialog[f].common.take_focus)
+ if (MouseInBox(&dialog[f].common.box,1)!=-1)
+ in=f;
+
+ if (mouse_b && !last_mouse_b)
+ {
+ if (in!=-1)
+ {
+ if (mouse_b&GFX_BUTLEFT)
+ cbret=Callback(dialog+in,GuiButtonPress);
+ else if (mouse_b&GFX_MSWHEELUP)
+ cbret=Callback(dialog+in,GuiWheelUp);
+ else if (mouse_b&GFX_MSWHEELDOWN)
+ cbret=Callback(dialog+in,GuiWheelDown);
+ }
+ }
+ else
+ {
+ if (in!=-1 && dialog[in].common.take_focus)
+ {
+ if (focus!=-1)
+ {
+ dialog[focus].common.focus=FALSE;
+ Callback(dialog+focus,GuiDraw);
+ }
+
+ focus=in;
+ dialog[focus].common.focus=TRUE;
+ Callback(dialog+focus,GuiDraw);
+ }
+ }
+ }
+
+ switch(cbret)
+ {
+ case GuiDone:
+ done=TRUE;
+ break;
+ case GuiRedraw:
+ for(f=0;f<dialog_no;f++)
+ Callback(dialog+f,GuiDraw);
+ break;
+ case GuiOk:
+ break;
+ }
+
+ GFX_redraw();
+ }
+
+ for(f=0;f<dialog_no;f++)
+ Callback(dialog+f,GuiExit);
+
+ EventTidy();
+
+ VIDOOM_GFX_RESTORE_UNDER(saved,dialog[0].common.box.x,
+ dialog[0].common.box.y,
+ dialog[0].common.box.w,
+ dialog[0].common.box.h);
+
+ return focus;
+}
+
+
+/* ---------------------------------------- MENU FUNCTIONS
+*/
+static void DrawMenuItem(BoundBox *b,char *txt,int sel,PLAT_MENU *child)
+{
+ int h,hy;
+
+ if (sel)
+ Rect3DBox(b,FALSE,SMALL_BEVEL);
+ else
+ GFX_frect(b->x,b->y,b->w,b->h,GUI_MID);
+
+ GFX_print(b->x+SMALL_BEVEL+2,b->y+b->h/2-FH/2,GUI_TEXT,txt);
+
+ if (child)
+ {
+ h=b->h-(SMALL_BEVEL*2)-2;
+ hy=b->y+SMALL_BEVEL+1;
+
+ GFX_line(b->x+b->w-SMALL_BEVEL-2-h/2,hy,
+ b->x+b->w-SMALL_BEVEL-2,hy+h/2,GUI_HI);
+
+ GFX_line(b->x+b->w-SMALL_BEVEL-2-h/2,hy,
+ b->x+b->w-SMALL_BEVEL-2-h/2,hy+h,GUI_HI);
+
+ GFX_line(b->x+b->w-SMALL_BEVEL-2-h/2,hy+h,
+ b->x+b->w-SMALL_BEVEL-2,hy+h/2,GUI_LO);
+ }
+}
+
+
+static MenuControl do_GUI_menu(char *title, int x, int y,
+ PLAT_MENU menu[],int defval,int is_child)
+{
+ Pixmap under;
+ MenuControl ret;
+ MenuControl cr;
+ int no;
+ int f;
+ int cur;
+ int last_cur;
+ int cx;
+ int by;
+ int done;
+ int quit;
+ int child_done;
+ BoundBox *box;
+ BoundBox menu_box;
+ int do_child;
+
+ /* Calc dimensions
+ */
+ no=0;
+ menu_box.x=x;
+ menu_box.y=y;
+ menu_box.w=LENGTH(title);
+
+ while(menu[no].text)
+ {
+ int l;
+
+ l=LENGTH(menu[no].text)+(menu[no].child ? 12 : 0);
+ menu_box.w=MAX(menu_box.w,l);
+ no++;
+ }
+
+ menu_box.h=BEVEL*2+FH+4;
+ menu_box.h+=(FH+SMALL_BEVEL*2+2)*no;
+ menu_box.h+=2;
+ menu_box.w+=BEVEL+SMALL_BEVEL+4;
+
+ box=Grab(sizeof(*box)*no);
+
+ if ((menu_box.x+menu_box.w)>SCRW)
+ menu_box.x=SCRW-menu_box.w;
+
+ if ((menu_box.y+menu_box.h)>SCRH)
+ menu_box.y=SCRH-menu_box.h;
+
+ if ((menu_box.x<0)||(menu_box.y<0))
+ {
+ fprintf(stderr,
+ "Cannot display menu:%s\nMenu is bigger than display!\n",title);
+
+ ret.mode=MENU_CHILD_RETURN;
+ ret.ret=defval;
+
+ return ret;
+ }
+
+ under=VIDOOM_GFX_SAVE_UNDER(menu_box.x,menu_box.y,menu_box.w,menu_box.h);
+
+ cx=menu_box.x+menu_box.w/2;
+
+ /* Draw menu border and title
+ */
+ Rect3DBox(&menu_box,FALSE,BEVEL);
+ CENTRE(cx,menu_box.y+BEVEL*2,GUI_TEXTBOLD,title);
+
+ /* Draw menu items
+ */
+ cur=0;
+ last_cur=0;
+
+ by=menu_box.y+BEVEL*2+FH+4;
+
+ for(f=0;f<no;f++)
+ {
+ box[f].x=menu_box.x+BEVEL;
+ box[f].y=by;
+ box[f].w=menu_box.w-BEVEL*2;
+ box[f].h=FH+SMALL_BEVEL*2+2;
+ by+=box[f].h;
+
+ DrawMenuItem(&box[f],menu[f].text,(f==cur),menu[f].child);
+ }
+
+ GFX_redraw();
+
+ /* Main loop
+ */
+ quit=FALSE;
+ done=FALSE;
+ child_done=FALSE;
+ do_child=FALSE;
+
+ while((!done)&&(!quit)&&(!child_done))
+ {
+ GetEvent();
+
+ /* Handle input
+ */
+ if (!do_child)
+ {
+ if (mouse_b)
+ {
+ int new;
+
+ new=MouseInBox(box,no);
+
+ if (new==-1)
+ {
+ if (MouseInBox(&menu_box,1)==-1)
+ {
+ quit=TRUE;
+ ret.mode=MENU_CANCEL_CLICK;
+ }
+ }
+ else
+ {
+ if (menu[new].child)
+ {
+ cur=new;
+ do_child=TRUE;
+ }
+ else
+ {
+ done=TRUE;
+ cur=new;
+ ret.mode=MENU_OK;
+ }
+ }
+ }
+ else if (is_key)
+ switch(key)
+ {
+ case GFX_ESC:
+ quit=TRUE;
+ ret.mode=MENU_CANCEL_ESC;
+ break;
+
+ case GFX_ENTER:
+ ret.mode=MENU_OK;
+ done=TRUE;
+ break;
+
+ case GFX_DOWN:
+ DrawMenuItem(&box[cur],menu[cur].text,FALSE,
+ menu[cur].child);
+
+ cur=(cur+1)%no;
+
+ DrawMenuItem(&box[cur],menu[cur].text,TRUE,
+ menu[cur].child);
+
+ GFX_redraw();
+ break;
+
+ case GFX_UP:
+ DrawMenuItem(&box[cur],menu[cur].text,FALSE,
+ menu[cur].child);
+
+ if (cur)
+ cur--;
+ else
+ cur=no-1;
+
+ DrawMenuItem(&box[cur],menu[cur].text,TRUE,
+ menu[cur].child);
+
+ GFX_redraw();
+ break;
+
+ case GFX_RIGHT:
+ if (menu[cur].child)
+ do_child=TRUE;
+
+ break;
+
+ case GFX_LEFT:
+ if (is_child)
+ {
+ quit=TRUE;
+ ret.mode=MENU_CHILD_RETURN;
+ }
+ break;
+ }
+ else
+ {
+ int new;
+
+ new=MouseInBox(box,no);
+
+ if (new!=-1)
+ cur=new;
+ }
+ }
+
+
+ /* Draw menu selection if changed
+ */
+ if (cur!=last_cur)
+ {
+ if (last_cur!=-1)
+ DrawMenuItem(&box[last_cur],menu[last_cur].text,FALSE,
+ menu[last_cur].child);
+
+ DrawMenuItem(&box[cur],menu[cur].text,TRUE,
+ menu[cur].child);
+ GFX_redraw();
+ }
+
+ last_cur=cur;
+
+ /* Handle child menus
+ */
+ if (do_child)
+ {
+ do_child=FALSE;
+
+ cr=do_GUI_menu(menu[cur].text,
+ box[cur].x+box[cur].w,box[cur].y,
+ menu[cur].child,defval,TRUE);
+
+ switch(cr.mode)
+ {
+ case MENU_OK:
+ child_done=TRUE;
+ break;
+
+ case MENU_CANCEL_ESC:
+ quit=TRUE;
+ ret.mode=MENU_CANCEL_ESC;
+ break;
+
+ case MENU_CANCEL_CLICK:
+ if (MouseInBox(&menu_box,1)==-1)
+ {
+ quit=TRUE;
+ ret.mode=MENU_CANCEL_CLICK;
+ }
+ else
+ {
+ if ((cur=MouseInBox(box,no))==-1)
+ cur=0;
+ else if (menu[cur].child)
+ do_child=TRUE;
+ }
+
+ break;
+
+ case MENU_CHILD_RETURN:
+ break;
+ }
+ }
+ }
+
+ Release(box);
+
+ if (child_done)
+ ret=cr;
+ else
+ {
+ if (!quit)
+ ret.ret=menu[cur].client_index;
+ else
+ ret.ret=defval;
+ }
+
+ VIDOOM_GFX_RESTORE_UNDER(under,menu_box.x,menu_box.y,menu_box.w,menu_box.h);
+
+ GFX_redraw();
+
+ return ret;
+}
+
+
+/* ---------------------------------------- EXPORTED FUNCTIONS
+*/
+
+void GUI_setscreen(int w,int h)
+{
+ VIDOOM_GET_GFX_VARS(&disp,&win,&pix,&gc);
+
+ hi_col=XCol(GUI_HI);
+ mid_col=XCol(GUI_MID);
+ lo_col=XCol(GUI_LO);
+ txt_col=XCol(GUI_TEXT);
+ shadow_col=XCol(GUI_TEXTSHADOW);
+ bold_col=XCol(GUI_TEXTBOLD);
+
+ SCRW=w;
+ SCRH=h;
+
+ FW=GFX_fw();
+ FH=GFX_fh();
+
+ /* Read in GUI section of [linux] ini
+ */
+ INI_GetTable(ini_conf,INI_TAB_SIZE(ini_conf));
+}
+
+
+int GUI_yesno(char *question)
+{
+ char *cp;
+ char *line[128];
+ int no;
+ int max;
+ int f;
+ int box;
+ int yes;
+ int x,y;
+ int ret;
+
+ cp=Strdup(question);
+
+ ChopLines(cp,line,&no,&max);
+
+ max=MAX(max,FW*20);
+
+ max+=BEVEL*2+10;
+
+ InitDial();
+
+ box=CreateBox(0,0,0,0,NULL,FALSE);
+
+ x=(SCRW-max)/2;
+ y=(SCRH-(no*(FH+2)))/2;
+
+ for(f=0;f<no;f++)
+ CreateLabel(x,y+(FH+2)*f,max,FH,line[f],GUI_TEXT,TRUE);
+
+ yes=CreateButton(x+10,y+(FH+2)*(no+1),max/2-20,FH*2,"Yes");
+ CreateButton(SCRW/2+10,y+(FH+2)*(no+1),max/2-20,FH*2,"No");
+
+ ResizeBox(box);
+
+ ret=DoDial();
+
+ Release(cp);
+
+ return ret==yes;
+}
+
+
+void GUI_start_yesno_all(void)
+{
+ all_pressed=FALSE;
+ all_result=FALSE;
+}
+
+
+int GUI_yesno_all(char *question)
+{
+ char *cp;
+ char *line[128];
+ int no;
+ int max;
+ int f;
+ int box;
+ int yes_but;
+ int no_but;
+ int yes_all_but;
+ int no_all_but;
+ int x,y;
+ int ret;
+
+ if (all_pressed)
+ return all_result;
+
+ cp=Strdup(question);
+
+ ChopLines(cp,line,&no,&max);
+
+ max=MAX(max,FW*30);
+
+ max+=BEVEL*2+10;
+
+ InitDial();
+
+ box=CreateBox(0,0,0,0,NULL,FALSE);
+
+ x=(SCRW-max)/2;
+ y=(SCRH-(no*(FH+2)))/2;
+
+ for(f=0;f<no;f++)
+ CreateLabel(x,y+(FH+2)*f,max,FH,line[f],GUI_TEXT,TRUE);
+
+ yes_but=CreateButton(x+10,y+(FH+2)*(no+1),max/2-20,FH*2,"Yes");
+ no_but=CreateButton(SCRW/2+10,y+(FH+2)*(no+1),max/2-20,FH*2,"No");
+ yes_all_but=CreateButton(x+10,y+(FH+2)*(no+3),max/2-20,FH*2,"Yes to all");
+ no_all_but=CreateButton(SCRW/2+10,y+(FH+2)*(no+3),
+ max/2-20,FH*2,"No to all");
+
+ ResizeBox(box);
+
+ ret=DoDial();
+
+ Release(cp);
+
+ all_result=(ret==yes_but || ret==yes_all_but);
+
+ if (ret==yes_all_but || ret==no_all_but)
+ all_pressed=TRUE;
+
+ return all_result;
+}
+
+
+void GUI_alert(char *title, char *text, char *button_text)
+{
+ char *cp;
+ char *line[128];
+ int no;
+ int max;
+ int f;
+ int box;
+ int x,y;
+
+ cp=Strdup(text);
+
+ ChopLines(cp,line,&no,&max);
+
+ max=MAX(max,LENGTH(title));
+ max=MAX(max,LENGTH("OK"));
+
+ max+=BEVEL*2+10;
+
+ InitDial();
+
+ box=CreateBox(0,0,0,0,title,FALSE);
+
+ x=(SCRW-max)/2;
+ y=(SCRH-(no*(FH+2)))/2;
+
+ for(f=0;f<no;f++)
+ CreateLabel(x,y+(FH+2)*f,max,FH,line[f],GUI_TEXT,TRUE);
+
+ CreateButton(x,y+(FH+2)*(no+1),max,FH*2,"OK");
+
+ ResizeBox(box);
+
+ DoDial();
+
+ Release(cp);
+}
+
+
+int GUI_menu(char *title, int x, int y, PLAT_MENU menu[],int defval)
+{
+ int ret;
+
+ ret=do_GUI_menu(title,x,y,menu,defval,FALSE).ret;
+
+ EventTidy();
+
+ return ret;
+}
+
+
+char *GUI_fsel(char *title, char *default_path, char *filter)
+{
+ char pwd[PATH_MAX+1];
+ char ret[PATH_MAX+1];
+ char *new_title;
+ int ok,cancel,path,file,list,box;
+ int x,y,w,h;
+ int lx,ly,lw,lh;
+ int tw;
+ int press;
+
+ getcwd(pwd,sizeof pwd);
+ strcpy(ret,default_path);
+
+ if (!ret[0])
+ strcpy(ret,pwd);
+
+ if (ret[strlen(ret)-1]!='/')
+ strcat(ret,"/");
+
+ x=50;
+ y=50;
+ w=SCRW-x*2;
+ h=SCRH-y*2;
+
+ lx=x+20;
+ ly=y+20;
+ lw=w-40;
+ lh=h-FH*8;
+
+ while(lh%(LIST_TEXTHEIGHT+BEVEL*2)!=0)
+ lh--;
+
+ InitDial();
+
+ if (filter)
+ new_title=Grab(strlen(title)+10+strlen(filter));
+ else
+ new_title=Grab(strlen(title)+32);
+
+ if (filter)
+ sprintf(new_title,"%s [*%s]",title,filter);
+ else
+ sprintf(new_title,"%s [no filter]",title);
+
+ box=CreateBox(0,0,0,0,new_title,FALSE);
+
+ CreateLabel(x+20,ly+lh+FH*1,-1,FH*1.5,"Dir",GUI_TEXT,FALSE);
+ CreateLabel(x+20,ly+lh+FH*3,-1,FH*1.5,"File",GUI_TEXT,FALSE);
+
+ tw=FW*5;
+
+ path=CreateText(x+20+tw,ly+lh+FH*1,w-tw-50,FH*1.5,"",GuiTextReadOnly,FALSE);
+ file=CreateText(x+20+tw,ly+lh+FH*3,w-tw-50,FH*1.5,"",GuiTextString,TRUE);
+
+ tw=FW*10;
+
+ ok=CreateButton(x+20,ly+lh+FH*5,tw,FH*2,"OK");
+ cancel=CreateButton(x+tw+20,ly+lh+FH*5,tw,FH*2,"Cancel");
+
+ list=CreateFileList(lx,ly,lw,lh,ret,filter,path,file,TRUE);
+
+ ResizeBox(box);
+
+ press=DoDial();
+
+ chdir(pwd);
+
+ Release(new_title);
+
+ if (press!=-1 && press!=cancel)
+ {
+ strcpy(ret,dialog[path].txt.text);
+ strcat(ret,dialog[file].txt.text);
+ return Strdup(ret);
+ }
+ else
+ return NULL;
+}
+
+
+int GUI_picklist(char *title,char *opt[])
+{
+ int max;
+ int no;
+ int box;
+ int pick;
+ int ok;
+ int cancel;
+ int x,y;
+ int press;
+ int boxh;
+
+ max=MAX(FW*20,LENGTH(title));
+
+ no=0;
+ while(opt[no])
+ {
+ max=MAX(max,LENGTH(opt[no]));
+
+ no++;
+ }
+
+ max+=FW+LIST_SCROLLSIZE;
+ boxh=LIST_TEXTHEIGHT*20+SMALL_BEVEL*2;
+
+ InitDial();
+
+ box=CreateBox(0,0,0,0,title,FALSE);
+
+ x=(SCRW-max)/2;
+ y=(SCRH-(boxh))/2;
+
+ pick=CreateImageList(x,y,max,boxh,no,opt,NULL,0,-1,TRUE);
+
+ ok=CreateButton(x+10,y+boxh+FH,max/2-20,FH*2,"OK");
+ cancel=CreateButton(SCRW/2+10,y+boxh+FH,max/2-20,FH*2,"Cancel");
+
+ ResizeBox(box);
+
+ press=DoDial();
+
+ if (press==ok || press==pick)
+ return dialog[pick].pck.curr;
+ else
+ return -1;
+}
+
+
+int GUI_client_picklist(char *title,PLAT_PICKLIST opt[],int defval)
+{
+ int max;
+ int no;
+ int box;
+ int pick;
+ int ok;
+ int cancel;
+ int x,y;
+ int press;
+ int boxh;
+ char **optset;
+ int f;
+
+ max=MAX(FW*20,LENGTH(title));
+
+ no=0;
+ while(opt[no].text)
+ {
+ max=MAX(max,LENGTH(opt[no].text));
+
+ no++;
+ }
+
+ optset=Grab(sizeof(char *)*no);
+
+ for(f=0;f<no;f++)
+ optset[f]=opt[f].text;
+
+ max+=FW+LIST_SCROLLSIZE;
+ boxh=LIST_TEXTHEIGHT*20+SMALL_BEVEL*2;
+
+ InitDial();
+
+ box=CreateBox(0,0,0,0,title,FALSE);
+
+ x=(SCRW-max)/2;
+ y=(SCRH-(boxh))/2;
+
+ pick=CreateImageList(x,y,max,boxh,no,optset,NULL,0,-1,TRUE);
+
+ ok=CreateButton(x+10,y+boxh+FH,max/2-20,FH*2,"OK");
+ cancel=CreateButton(SCRW/2+10,y+boxh+FH,max/2-20,FH*2,"Cancel");
+
+ ResizeBox(box);
+
+ press=DoDial();
+
+ if (press==ok || press==pick)
+ return opt[dialog[pick].pck.curr].client_index;
+ else
+ return defval;
+}
+
+
+int GUI_image_picklist(char *title,PLAT_IMG_PICKLIST opt[],int defval)
+{
+ int max;
+ int max_imgw;
+ int max_imgh;
+ int no;
+ int box;
+ int img_box;
+ int pick;
+ int ok;
+ int cancel;
+ int x,y;
+ int press;
+ int boxh;
+ char **optset;
+ GFX_IMAGE *imgset;
+ int f;
+
+ max=MAX(FW*20,LENGTH(title));
+ max_imgw=0;
+ max_imgh=0;
+
+ no=0;
+ while(opt[no].text)
+ {
+ GfxImage *i;
+
+ max=MAX(max,LENGTH(opt[no].text));
+
+ i=opt[no].img;
+
+ if (i)
+ {
+ max_imgw=MAX(max_imgw,i->w);
+ max_imgh=MAX(max_imgh,i->h);
+ }
+
+ no++;
+ }
+
+ optset=Grab(sizeof(char *)*no);
+ imgset=Grab(sizeof(GFX_IMAGE)*no);
+
+ for(f=0;f<no;f++)
+ {
+ optset[f]=opt[f].text;
+ imgset[f]=opt[f].img;
+ }
+
+ max+=FW+LIST_SCROLLSIZE;
+ boxh=LIST_TEXTHEIGHT*20+SMALL_BEVEL*2;
+
+ InitDial();
+
+ box=CreateBox(0,0,0,0,title,FALSE);
+
+ x=(SCRW-max-20-max_imgw)/2;
+ y=(SCRH-(boxh))/2;
+
+ img_box=CreateBox(x+max+20,y,max_imgw,max_imgh,NULL,FALSE);
+
+ pick=CreateImageList(x,y,max,boxh,no,optset,imgset,0,img_box,TRUE);
+
+ max+=20+max_imgw;
+
+ ok=CreateButton(x+10,y+boxh+FH,max/2-20,FH*2,"OK");
+ cancel=CreateButton(SCRW/2+10,y+boxh+FH,max/2-20,FH*2,"Cancel");
+
+ ResizeBox(box);
+
+ press=DoDial();
+
+ Release(optset);
+ Release(imgset);
+
+ if (press==ok || press==pick)
+ return opt[dialog[pick].pck.curr].client_index;
+ else
+ return defval;
+}
+
+
+int GUI_radio_box(char *title,PLAT_RADIO opt[],int current,int defval)
+{
+ int *radio;
+ int max;
+ int no;
+ int f;
+ int cur;
+ int box;
+ int ok;
+ int cancel;
+ int x,y;
+ int press;
+ int ret;
+ int opt_h;
+
+ max=MAX(FW*20,LENGTH(title));
+ cur=0;
+ ret=defval;
+ opt_h=FH+FH/2;
+
+ no=0;
+ while(opt[no].text)
+ {
+ max=MAX(max,LENGTH(opt[no].text));
+
+ if (opt[no].client_index==current)
+ cur=no;
+
+ no++;
+ }
+
+ radio=Grab(no*sizeof(*radio));
+
+ max+=FW*3;
+
+ InitDial();
+
+ box=CreateBox(0,0,0,0,title,FALSE);
+
+ x=(SCRW-max)/2;
+ y=(SCRH-(no*opt_h))/2;
+
+ for(f=0;f<no;f++)
+ radio[f]=CreateRadio(x,y+opt_h*f,max,FH,opt[f].text,1,(cur==f));
+
+ ok=CreateButton(x+10,y+opt_h*(no+1),max/2-20,FH*2,"OK");
+ cancel=CreateButton(SCRW/2+10,y+opt_h*(no+1),max/2-20,FH*2,"Cancel");
+
+ ResizeBox(box);
+
+ press=DoDial();
+
+ if (press==ok)
+ for(f=0;f<no;f++)
+ if (dialog[radio[f]].rad.state)
+ ret=opt[f].client_index;
+
+ Release(radio);
+
+ return ret;
+}
+
+
+int GUI_multi_box(char *title,PLAT_MULTI p[])
+{
+ int *obj;
+ int max;
+ int no;
+ int f;
+ int box;
+ int ok;
+ int cancel;
+ int x,y;
+ int press;
+ int opt_h;
+
+ max=MAX(FW*20,LENGTH(title));
+ opt_h=FH+FH/2;
+
+ no=0;
+ while(p[no].text)
+ {
+ max=MAX(max,LENGTH(p[no].text));
+
+ no++;
+ }
+
+ obj=Grab(no*sizeof(*obj));
+
+ max+=FW*3;
+
+ InitDial();
+
+ box=CreateBox(0,0,0,0,title,FALSE);
+
+ x=(SCRW-max)/2;
+ y=(SCRH-(no*opt_h))/2;
+
+ for(f=0;f<no;f++)
+ if (p[f].group)
+ obj[f]=CreateRadio(x,y+opt_h*f,max,FH,
+ p[f].text,p[f].group,p[f].val);
+ else
+ obj[f]=CreateToggle(x,y+opt_h*f,max,FH,
+ p[f].text,p[f].val);
+
+ ok=CreateButton(x+10,y+opt_h*(no+1),max/2-20,FH*2,"OK");
+ cancel=CreateButton(SCRW/2+10,y+opt_h*(no+1),max/2-20,FH*2,"Cancel");
+
+ ResizeBox(box);
+
+ press=DoDial();
+
+ if (press==ok)
+ {
+ for(f=0;f<no;f++)
+ if (dialog[obj[f]].common.type==GuiRadio)
+ p[f].val=dialog[obj[f]].rad.state;
+ else
+ p[f].val=dialog[obj[f]].tog.state;
+ }
+
+ Release(obj);
+
+ return press==ok;
+}
+
+
+int GUI_dialog(char *title, int no, PLAT_DIALOG pd[])
+{
+ char buff[256];
+ int lmax;
+ int pmax;
+ int width;
+ int height;
+ int x,y;
+ int f,r;
+ int box;
+ int ok;
+ int cancel;
+ int *obj;
+ int press;
+
+ lmax=LENGTH(title);
+ pmax=FW*20;
+ obj=Grab(sizeof(int)*no);
+
+ for(f=0;f<no;f++)
+ lmax=MAX(lmax,LENGTH(pd[f].text));
+
+ for(f=0;f<no;f++)
+ if (pd[f].type==PLAT_DIAL_PICKLIST)
+ for(r=0;r<pd[f].data.pl.no;r++)
+ pmax=MAX(pmax,LENGTH(pd[f].data.pl.text[r]));
+
+ pmax+=LIST_SCROLLSIZE+FW;
+
+ width=lmax+pmax+FW*3;
+
+ height=0;
+
+ for(f=0;f<no;f++)
+ {
+ if (pd[f].type==PLAT_DIAL_PICKLIST)
+ height+=LIST_TEXTHEIGHT*3+FH/2;
+ else
+ height+=FH*2;
+ }
+
+ InitDial();
+
+ box=CreateBox(0,0,0,0,title,FALSE);
+
+ x=(SCRW-width)/2;
+ y=(SCRH-height)/2;
+
+ for(f=0;f<no;f++)
+ switch(pd[f].type)
+ {
+ case PLAT_DIAL_STRING:
+ CreateLabel(x+FW,y,lmax,FH*1.5,pd[f].text,GUI_TEXT,FALSE);
+ obj[f]=CreateText(x+lmax+FW,y,pmax,FH*1.5,
+ pd[f].data.s,GuiTextString,TRUE);
+ y+=FH*2;
+ break;
+
+ case PLAT_DIAL_INTEGER:
+ CreateLabel(x+FW,y,lmax,FH*1.5,pd[f].text,GUI_TEXT,FALSE);
+ sprintf(buff,"%d",pd[f].data.i);
+ obj[f]=CreateText(x+lmax+FW,y,pmax,FH*1.5,buff,
+ GuiTextInteger,TRUE);
+ y+=FH*2;
+ break;
+
+ case PLAT_DIAL_DOUBLE:
+ CreateLabel(x+FW,y,lmax,FH*1.5,pd[f].text,GUI_TEXT,FALSE);
+ sprintf(buff,"%f",pd[f].data.d);
+ obj[f]=CreateText(x+lmax+FW,y,pmax,FH*1.5,buff,
+ GuiTextDouble,TRUE);
+ y+=FH*2;
+ break;
+
+ case PLAT_DIAL_PICKLIST:
+ CreateLabel(x+FW,y,lmax,FH*1.5,pd[f].text,GUI_TEXT,FALSE);
+ obj[f]=CreateImageList(x+lmax+FW,y,
+ pmax,LIST_TEXTHEIGHT*3+BEVEL*2,
+ pd[f].data.pl.no,pd[f].data.pl.text,
+ NULL,pd[f].data.pl.current,-1,TRUE);
+ y+=LIST_TEXTHEIGHT*3+FH/2;
+ break;
+
+ default:
+ break;
+ }
+
+ ok=CreateButton(x+10,y+FH*2,width/2-20,FH*2,"OK");
+ cancel=CreateButton(SCRW/2+10,y+FH*2,width/2-20,FH*2,"Cancel");
+
+ ResizeBox(box);
+
+ press=DoDial();
+
+ if (press!=-1 && press!=cancel)
+ {
+ for(f=0;f<no;f++)
+ switch(pd[f].type)
+ {
+ case PLAT_DIAL_STRING:
+ strcpy(pd[f].data.s,dialog[obj[f]].txt.text);
+ break;
+
+ case PLAT_DIAL_INTEGER:
+ pd[f].data.i=(int)strtol(dialog[obj[f]].txt.text,NULL,0);
+ break;
+
+ case PLAT_DIAL_DOUBLE:
+ pd[f].data.d=strtod(dialog[obj[f]].txt.text,NULL);
+ break;
+
+ case PLAT_DIAL_PICKLIST:
+ pd[f].data.pl.current=dialog[obj[f]].pck.curr;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ Release(obj);
+
+ return (press!=-1 && press!=cancel);
+}
+
+
+void GUI_view_file (char *title, char *path)
+{
+ TextEditLine *line;
+ int no;
+ int f;
+ int x,y,width,height;
+ int box,info,edit,ok;
+ FILE *fp;
+ char buff[1024];
+
+ if (!(fp=fopen(path,"r")))
+ {
+ GUI_alert(path,"File not found","OK");
+ return;
+ }
+
+ line=Grab(sizeof *line);
+
+ no=0;
+
+ fgets(buff,sizeof buff,fp);
+
+ while(!feof(fp))
+ {
+ /* No overflow checks, but it is a hack this thing!
+ */
+ f=0;
+
+ while(f<strlen(buff))
+ {
+ if (buff[f]=='\t')
+ {
+ buff[f++]=' ';
+ while((f%8))
+ {
+ memmove(buff+f+1,buff+f,strlen(buff)-f+1);
+ buff[f]=' ';
+ f++;
+ }
+ }
+ else
+ f++;
+ }
+
+ line[no].p=Strdup(buff);
+ line[no].len=strlen(buff);
+ no++;
+
+ line=ReGrab(line,sizeof(TextEditLine)*(no+1));
+
+ fgets(buff,sizeof buff,fp);
+ }
+
+ line[no].p=NULL;
+ line[no].len=0;
+
+ InitDial();
+
+ box=CreateBox(0,0,0,0,title,FALSE);
+
+ width=80*FW;
+ height=20*FH;
+
+ while (width>(SCRW-FW*5))
+ width-=FW;
+
+ while (height>(SCRH-FH*5))
+ height-=FH;
+
+ x=(SCRW-width)/2;
+ y=(SCRH-height)/2;
+
+ info=CreateText(x,y-FH*2,width,FH*1.5,"",GuiTextReadOnly,FALSE);
+ edit=CreateTextEdit(x,y,width,height,line,no,info,TRUE);
+
+ ok=CreateButton(x+10,y+height+FH*2,width-20,FH*2,"OK");
+
+ ResizeBox(box);
+
+ DoDial();
+
+ for(f=0;f<dialog[edit].edt.lines;f++)
+ Release(dialog[edit].edt.tline[f].p);
+
+ Release(dialog[edit].edt.tline);
+}
+
+
+static char *GUI_text_edit_external (char *title, char *text)
+{
+ pid_t pid;
+ int status;
+ FILE *fp;
+ char *name;
+ char *new;
+ long len;
+
+ name=tempnam(NULL,"vidoom");
+
+ if (!(fp=fopen(name,"w")))
+ {
+ free(name);
+ return NULL;
+ }
+
+ FWrite(fp,text,strlen(text));
+ fclose(fp);
+
+ switch(pid=fork())
+ {
+ case 0:
+ ExecProgram(GUI_EDITOR,name);
+ _exit(33);
+ break;
+ case -1:
+ break;
+ default:
+ VIDOOM_GFX_SAVE_DISPLAY();
+
+ Rect3D(0,0,SCRW,SCRH,FALSE,20);
+ CENTREX(0,SCRH/2,SCRW,GUI_TEXTBOLD,
+ "Window locked - editing:");
+ CENTREX(0,SCRH/2+FH*2,SCRW,GUI_TEXTBOLD,title);
+
+ GFX_redraw();
+
+ VIDOOM_GFX_WAIT_FOR(pid,&status);
+
+ VIDOOM_GFX_RESTORE_DISPLAY();
+
+ if (WIFEXITED(status) && WEXITSTATUS(status)==33)
+ {
+ char *p;
+
+ p=Grab(strlen(GUI_EDITOR)+128);
+
+ sprintf(p,"Failed to exec:|%s",GUI_EDITOR);
+
+ GUI_alert("Error",p,"OK");
+
+ Release(p);
+
+ free(name);
+
+ return NULL;
+ }
+ break;
+ }
+
+ if (!(fp=fopen(name,"r")))
+ {
+ free(name);
+ return NULL;
+ }
+
+ len=FLen(fp);
+ new=Grab(len+1);
+
+ FRead(fp,new,len);
+
+ new[len]=0;
+
+ fclose(fp);
+
+ return new;
+}
+
+
+char *GUI_text_edit (char *title, char *text)
+{
+ char *cp_text;
+ char *p;
+ TextEditLine *line;
+ char *ret;
+ int no;
+ int f;
+ int x,y,width,height;
+ int box,info,edit,ok,cancel;
+ int press;
+
+ if (GUI_EDITOR[0])
+ return GUI_text_edit_external(title,text);
+
+ p=text;
+
+ if (*(p+strlen(p)-1)=='\n')
+ no=0;
+ else
+ no=1;
+
+ while(*p)
+ if (*p++=='\n')
+ no++;
+
+ line=Grab(sizeof(TextEditLine)*(no+1));
+ cp_text=Strdup(text);
+ p=cp_text;
+
+ for(f=0;f<no;f++)
+ {
+ char *e;
+
+ e=p;
+
+ while((*e)&&(*e!='\n'))
+ e++;
+
+ *e=0;
+
+ /* We rely on the fact that Grab() zeroes data...
+ */
+ line[f].len=strlen(p);
+ line[f].p=Grab((line[f].len/TE_CHUNK+1)*TE_CHUNK+1);
+ strcpy(line[f].p,p);
+ p=e+1;
+ }
+
+ line[f].p=NULL;
+ line[f].len=0;
+ Release(cp_text);
+
+ InitDial();
+
+ box=CreateBox(0,0,0,0,"Text Editor",FALSE);
+
+ width=80*FW;
+ height=20*FH;
+
+ while (width>(SCRW-FW*5))
+ width-=FW;
+
+ while (height>(SCRH-FH*5))
+ height-=FH;
+
+ x=(SCRW-width)/2;
+ y=(SCRH-height)/2;
+
+ info=CreateText(x,y-FH*2,width,FH*1.5,"",GuiTextReadOnly,FALSE);
+ edit=CreateTextEdit(x,y,width,height,line,no,info,FALSE);
+
+ ok=CreateButton(x+10,y+height+FH*2,width/2-20,FH*2,"OK");
+ cancel=CreateButton(SCRW/2+10,y+height+FH*2,width/2-20,FH*2,"Cancel");
+
+ ResizeBox(box);
+
+ press=DoDial();
+
+ if (press==ok)
+ {
+ int tot;
+
+ tot=0;
+
+ for(f=0;f<dialog[edit].edt.lines;f++)
+ tot+=dialog[edit].edt.tline[f].len+1;
+
+ ret=Grab(tot+1);
+ *ret=0;
+
+ for(f=0;f<dialog[edit].edt.lines;f++)
+ {
+ strcat(ret,dialog[edit].edt.tline[f].p);
+ strcat(ret,"\n");
+ }
+ }
+ else
+ ret=NULL;
+
+ for(f=0;f<dialog[edit].edt.lines;f++)
+ Release(dialog[edit].edt.tline[f].p);
+
+ Release(dialog[edit].edt.tline);
+
+ return ret;
+}
+
+
+/* END OF FILE */