diff options
Diffstat (limited to 'linux')
-rw-r--r-- | linux/file.c | 103 | ||||
-rw-r--r-- | linux/gfx.c | 1013 | ||||
-rw-r--r-- | linux/main.c | 33 | ||||
-rw-r--r-- | linux/mem.c | 107 | ||||
-rw-r--r-- | linux/platgui.c | 3703 | ||||
-rw-r--r-- | linux/runcmd.c | 82 | ||||
-rw-r--r-- | linux/vstring.c | 48 |
7 files changed, 5089 insertions, 0 deletions
diff --git a/linux/file.c b/linux/file.c new file mode 100644 index 0000000..6094021 --- /dev/null +++ b/linux/file.c @@ -0,0 +1,103 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + File system interfaces + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include <unistd.h> + + +/* ---------------------------------------- EXPORTED FUNCS +*/ +char *Pwd(void) +{ + static char s[PATH_MAX]; + + getcwd(s,PATH_MAX); + + return s; +} + +void Cd(char *path) +{ + chdir(path); +} + +char *Dirname(char *path) +{ + static char s[PATH_MAX]; + char *p; + + strcpy(s,path); + + p=s+strlen(s)-1; + + while((*p)&&(p>s)) + if (*p=='/') + *(p+1)=0; + else + p--; + + return s; +} + +char *Basename(char *path) +{ + static char s[PATH_MAX]; + char *p; + + strcpy(s,path); + + p=s+strlen(s)-1; + + while(p>s) + if (*p=='/') + return p+1; + else + p--; + + return(s); +} + +int FileExists(char *path) +{ + FILE *fp; + + if ((fp=fopen(path,"r"))) + { + fclose(fp); + return TRUE; + } + else + return FALSE; +} + +int FilenamesEqual(char *path1, char *path2) +{ + return !strcasecmp(path1,path2); +} + + +/* END OF FILE */ diff --git a/linux/gfx.c b/linux/gfx.c new file mode 100644 index 0000000..01c7f4a --- /dev/null +++ b/linux/gfx.c @@ -0,0 +1,1013 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + Graphics functions + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "gfx.h" +#include "mem.h" + +#include <stdio.h> +#include <ctype.h> +#include <limits.h> +#include <stdarg.h> +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/keysym.h> + +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> + + +/* ---------------------------------------- VARS +*/ +static int init=FALSE; + +static Window win=None; +static Pixmap pix=None; +static Pixmap saved=None; +static GC gc=None; +static Display *disp=NULL; +static XVisualInfo visual; +static XFontStruct *font=NULL; +static int curr_func; + +#define FONTGAP 2 +#define FONTW (font->max_bounds.rbearing - \ + font->min_bounds.lbearing) +#define FONTH (font->max_bounds.descent + \ + font->max_bounds.ascent + FONTGAP) + +static int width=0; +static int height=0; + +static int fw=0; +static int fh=0; + +static int mbuttons=3; /* Assume 3 for X11 */ + +static int dirty_min_x=0; +static int dirty_max_x=0; +static int dirty_min_y=0; +static int dirty_max_y=0; + +static char *font_names[]= + { + "6x9", + NULL + }; + +#define DIRTY(x,y) do { \ + dirty_min_x=MIN(x,dirty_min_x); \ + dirty_min_y=MIN(y,dirty_min_y); \ + dirty_max_x=MAX((x)+1,dirty_max_x); \ + dirty_max_y=MAX((y)+1,dirty_max_y); \ + } while(0) + + +/* Internal representation used for GFX_IMAGE +*/ +typedef struct + { + int w,h; + XImage *p; + } GfxImage; + +/* These are used to define the mappings between X11 scancodes and GFX keys. + Then the scancode can be used to directly index and array. +*/ +static struct + { + int is_special; + int key; + } keycode_map[sizeof(KeyCode)<< CHAR_BIT]; + +typedef struct KBuff + { + GFXKey k; + struct KBuff *next; + } KeyBuff; + +static KeyBuff *kb_head=NULL; +static KeyBuff *kb_tail=NULL; + +static struct + { + KeySym keysym; + int code; + } key_map[]= { + {XK_F1, GFX_F1}, + {XK_F2, GFX_F2}, + {XK_F3, GFX_F3}, + {XK_F4, GFX_F4}, + {XK_F5, GFX_F5}, + {XK_F6, GFX_F6}, + {XK_F7, GFX_F7}, + {XK_F8, GFX_F8}, + {XK_F9, GFX_F9}, + {XK_F10, GFX_F10}, + {XK_F11, GFX_F11}, + {XK_F12, GFX_F12}, + {XK_Escape, GFX_ESC}, + {XK_Insert, GFX_INSERT}, + {XK_Home, GFX_HOME}, + {XK_Page_Up, GFX_PGUP}, + {XK_Delete, GFX_DELETE}, + {XK_End, GFX_END}, + {XK_Page_Down, GFX_PGDN}, + {XK_Up, GFX_UP}, + {XK_Down, GFX_DOWN}, + {XK_Left, GFX_LEFT}, + {XK_Right, GFX_RIGHT}, + {XK_Return, GFX_ENTER}, + {XK_BackSpace, GFX_BACKSPACE}, + {XK_Tab, GFX_TAB}, + + {XK_VoidSymbol, -1}, + }; + +/* Types and vars for event handling +*/ +typedef enum + { + X11_GFXnone=0, + X11_GFXmouse=1, + X11_GFXmouseMove=2, + X11_GFXkey=4, + X11_GFXall=4|2|1 + } EventType; + +typedef enum + { + X11_GFXpress, X11_GFXrelease, X11_GFXmove + } MouseEventType; + +static int mouse_b=0; +static int mouse_x=0; +static int mouse_y=0; +static int is_shift=FALSE; +static int is_ctrl=FALSE; +static int is_alt=FALSE; + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ + +static unsigned long getXCol(int col) +{ + XColor pix; + + pix.red=(col&0xff0000)>>8; + pix.green=(col&0xff00); + pix.blue=(col&0xff)<<8; + pix.flags=DoRed|DoBlue|DoGreen; + + XAllocColor(disp,DefaultColormap(disp,DefaultScreen(disp)),&pix); + + return pix.pixel; +} + + +static void setXCol(int col) +{ + static int last_col=-1; + + if (col==last_col) + return; + + last_col=col; + + XSetForeground(disp,gc,getXCol(col)); +} + + +static void KeyBuffAdd(int code, char ascii, int shift, int ctrl, int alt) +{ + KeyBuff *key; + + key=Grab(sizeof *key); + + key->k.code=code; + key->k.ascii=ascii; + key->k.shift=shift; + key->k.ctrl=ctrl; + key->k.alt=alt; + key->next=NULL; + + if (!kb_head) + kb_head=kb_tail=key; + else + { + kb_tail->next=key; + kb_tail=key; + } +} + + +static void GetKey(GFXKey *key) +{ + if (kb_head) + { + KeyBuff *k=kb_head; + + *key=k->k; + + if (!(kb_head=k->next)) + kb_tail=NULL; + + Release(k); + } +} + + +static int HandleKey(XKeyEvent *key) +{ + int code; + char ascii; + + if (keycode_map[key->keycode].is_special) + { + code=keycode_map[key->keycode].key; + ascii=0; + } + else + { + char buff[2]=""; + + code=GFX_ASCII; + + XLookupString(key,buff,2,NULL,NULL); + + if (!isprint(buff[0])) + return FALSE; + + ascii=buff[0]; + } + + KeyBuffAdd(code,ascii, + key->state&ShiftMask, + key->state&ControlMask, + key->state&Mod1Mask); + + return TRUE; +} + + +static void HandleMouse(int x, int y, int b, MouseEventType type, + unsigned int state) +{ + int mask; + + mouse_x=x; + mouse_y=y; + + if (type!=X11_GFXmove) + { + switch(b) + { + case Button1: + mask=GFX_BUTLEFT; + break; + case Button2: + mask=GFX_BUTMIDDLE; + break; + case Button3: + mask=GFX_BUTRIGHT; + break; + case Button4: + mask=GFX_MSWHEELUP; + break; + case Button5: + mask=GFX_MSWHEELDOWN; + break; + default: + mask=0; + break; + } + + if (type==X11_GFXpress) + mouse_b|=mask; + else + mouse_b&=~mask; + } + + is_shift=state&ShiftMask; + is_ctrl=state&ControlMask; + is_alt=state&Mod1Mask; +} + + +static EventType Wait(EventType etype, int wait) +{ + XEvent ev; + + while(wait || XPending(disp)) + { + XNextEvent(disp,&ev); + + switch(ev.type) + { + case KeyPress: + if (HandleKey(&ev.xkey) && (etype & X11_GFXkey)) + return X11_GFXkey; + + break; + + case ButtonPress: + HandleMouse(ev.xbutton.x,ev.xbutton.y,ev.xbutton.button, + X11_GFXpress,ev.xbutton.state); + + if (etype & X11_GFXmouse) + return X11_GFXmouse; + + break; + + case ButtonRelease: + HandleMouse(ev.xbutton.x,ev.xbutton.y,ev.xbutton.button, + X11_GFXrelease,ev.xbutton.state); + + if (etype & X11_GFXmouse) + return X11_GFXmouse; + + break; + + case MotionNotify: + HandleMouse(ev.xbutton.x,ev.xbutton.y,0, + X11_GFXmove,ev.xbutton.state); + + if (etype & X11_GFXmouseMove) + return X11_GFXmouseMove; + + break; + + case Expose: + DIRTY(ev.xexpose.x,ev.xexpose.y); + DIRTY(ev.xexpose.x+ev.xexpose.width, + ev.xexpose.y+ev.xexpose.height); + + if (ev.xexpose.count==0) + GFX_redraw(); + + break; + + default: + break; + } + } + + return X11_GFXnone; +} + + + +/* ---------------------------------------- 'PRIVATE' EXPORTED FUNCTIONS +*/ +void VIDOOM_GET_GFX_VARS(Display **ret_disp, Window *ret_win, Pixmap *ret_pix, + GC *ret_gc) +{ + *ret_disp=disp; + *ret_win=win; + *ret_pix=pix; + *ret_gc=gc; +} + + +void VIDOOM_GFX_FORCE_REDRAW(void) +{ + dirty_min_x=0; + dirty_max_x=width-1; + dirty_min_y=0; + dirty_max_y=width-1; + + GFX_redraw(); +} + + +void VIDOOM_GFX_SAVE_DISPLAY(void) +{ + if (curr_func!=GXcopy) + XSetFunction(disp,gc,GXcopy); + + XCopyArea(disp,pix,saved,gc,0,0,width,height,0,0); +} + + +void VIDOOM_GFX_RESTORE_DISPLAY(void) +{ + XCopyArea(disp,saved,pix,gc,0,0,width,height,0,0); + VIDOOM_GFX_FORCE_REDRAW(); + + if (curr_func!=GXcopy) + XSetFunction(disp,gc,curr_func); +} + + +Pixmap VIDOOM_GFX_SAVE_UNDER(int x, int y, int w, int h) +{ + Pixmap p; + + p=XCreatePixmap(disp,win,w,h,visual.depth); + XCopyArea(disp,pix,p,gc,x,y,w,h,0,0); + + return p; +} + + +void VIDOOM_GFX_RESTORE_UNDER(Pixmap p, int x, int y, int w, int h) +{ + DIRTY(x,y); + DIRTY(x+w,y+h); + XCopyArea(disp,p,pix,gc,0,0,w,h,x,y); + XFreePixmap(disp,p); +} + + +/* This is done in a *very* bad fashion.... +*/ +void VIDOOM_GFX_WAIT_FOR(pid_t pid, int *status) +{ + XEvent ev; + + while(TRUE) + { + while (XPending(disp)) + { + XNextEvent(disp,&ev); + + if (ev.type==Expose) + { + DIRTY(ev.xexpose.x,ev.xexpose.y); + DIRTY(ev.xexpose.x+ev.xexpose.width, + ev.xexpose.y+ev.xexpose.height); + + if (ev.xexpose.count==0) + GFX_redraw(); + } + } + + if (waitpid(pid,status,WNOHANG)) + return; + + /* Now, this is nasty... + */ + usleep(10000); + } +} + + +/* ---------------------------------------- EXPORTED FUNCTIONS +*/ +void GFX_init(void) +{ + if (!init) + { + int f; + + init=TRUE; + + /* Open display and find an appropriate visual + */ + if (!(disp=XOpenDisplay(NULL))) + GFX_exit(EXIT_FAILURE,"Couldn't open X display\n"); + + if (!XMatchVisualInfo(disp,DefaultScreen(disp),32,TrueColor,&visual) && + !XMatchVisualInfo(disp,DefaultScreen(disp),24,TrueColor,&visual) && + !XMatchVisualInfo(disp,DefaultScreen(disp),16,TrueColor,&visual) && + !XMatchVisualInfo(disp,DefaultScreen(disp),15,TrueColor,&visual)) + GFX_exit(EXIT_FAILURE,"Couldn't find a TrueColor visual\n"); + + f=0; + while(font_names[f] && !font) + font=XLoadQueryFont(disp,font_names[f++]); + + if (!font) + { + font=XLoadQueryFont(disp,"fixed"); + + if (!font) + GFX_exit(EXIT_FAILURE,"Couldn't even load font fixed\n"); + } + + fw=FONTW; + fh=FONTH; + + for(f=0;f<(sizeof(KeyCode)<< CHAR_BIT);f++) + keycode_map[f].is_special=FALSE; + + f=0; + + while(key_map[f].keysym!=XK_VoidSymbol) + { + KeyCode code; + + code=XKeysymToKeycode(disp,key_map[f].keysym); + + keycode_map[code].is_special=TRUE; + keycode_map[code].key=key_map[f].code; + + f++; + } + } +} + + +void GFX_close(void) +{ + if (gc!=None) + { + XFreeGC(disp,gc); + gc=None; + } + + if (pix!=None) + { + XFreePixmap(disp,pix); + pix=None; + } + + if (saved!=None) + { + XFreePixmap(disp,saved); + saved=None; + } + + if (win!=None) + { + XDestroyWindow(disp,win); + win=None; + } +} + + +void GFX_open(int w,int h) +{ + XGCValues gc_val; + XSizeHints hint; + + if (!init) + GFX_exit(EXIT_FAILURE,"GFX_Open() called before GFX_init()\n"); + + height=h; + width=w; + + win=XCreateWindow(disp,DefaultRootWindow(disp), + 0,0,width,height,0, + visual.depth, + InputOutput, + visual.visual, + 0,NULL); + + XSelectInput + (disp,win, + KeyPressMask|ButtonPressMask|ButtonReleaseMask| + PointerMotionMask|ExposureMask); + + XStoreName(disp,win,"viDOOM " VIDOOMVER VIDOOMRELEASE); + + hint.width=hint.min_width=hint.max_width=width; + hint.height=hint.min_height=hint.max_height=height; + hint.flags=PSize|PMinSize|PMaxSize; + + XSetWMNormalHints(disp,win,&hint); + + pix=XCreatePixmap(disp,win,width,height,visual.depth); + saved=XCreatePixmap(disp,win,width,height,visual.depth); + + curr_func=gc_val.function=GXcopy; + gc_val.plane_mask=AllPlanes; + gc_val.line_width=0; + gc_val.line_style=LineSolid; + gc_val.graphics_exposures=False; + gc_val.foreground=WhitePixel(disp,DefaultScreen(disp)); + gc_val.background=BlackPixel(disp,DefaultScreen(disp)); + + gc=XCreateGC(disp,pix, + GCFunction|GCPlaneMask|GCLineWidth|GCForeground|GCBackground| + GCLineStyle|GCGraphicsExposures, + &gc_val); + + GFX_clear(BLACK); + GFX_redraw(); + + XMapWindow(disp,win); +} + + +void GFX_clear(int col) +{ + if (curr_func!=GXcopy) + XSetFunction(disp,gc,GXcopy); + + setXCol(col); + XFillRectangle(disp,pix,gc,0,0,width,height); + + if (curr_func!=GXcopy) + XSetFunction(disp,gc,curr_func); + + dirty_min_x=0; + dirty_max_x=width; + dirty_min_y=0; + dirty_max_y=height; +} + + +void GFX_redraw(void) +{ + if (dirty_max_x<dirty_min_x) + return; + + if (curr_func!=GXcopy) + XSetFunction(disp,gc,GXcopy); + + dirty_min_x=MAX(0,dirty_min_x); + dirty_min_y=MAX(0,dirty_min_y); + dirty_max_x=MIN(width,dirty_max_x); + dirty_max_y=MIN(height,dirty_max_y); + + XCopyArea(disp,pix,win,gc, + dirty_min_x,dirty_min_y, + dirty_max_x-dirty_min_x+1,dirty_max_y-dirty_min_y+1, + dirty_min_x,dirty_min_y); + + if (curr_func!=GXcopy) + XSetFunction(disp,gc,curr_func); + + dirty_max_x=0; + dirty_min_x=width-1; + dirty_max_y=0; + dirty_min_y=width-1; + + XFlush(disp); +} + + +void GFX_line(int x1,int y1,int x2,int y2,int col) +{ + DIRTY(x1,y1); + DIRTY(x2,y2); + + setXCol(col); + XDrawLine(disp,pix,gc,x1,y1,x2,y2); +} + + +void GFX_plot(int x,int y,int col) +{ + DIRTY(x,y); + + setXCol(col); + XDrawPoint(disp,pix,gc,x,y); +} + + +void GFX_circle(int x,int y,int r,int col) +{ + DIRTY(x-r-1,y-r-1); + DIRTY(x+r+1,y+r+1); + + setXCol(col); + XDrawArc(disp,pix,gc,x-r,y-r,r*2,r*2,0,64*360); +} + + +void GFX_fcircle(int x,int y,int r,int col) +{ + DIRTY(x-r-1,y-r-1); + DIRTY(x+r+1,y+r+1); + + setXCol(col); + XFillArc(disp,pix,gc,x-r,y-r,r*2,r*2,0,64*360); +} + + +void GFX_rect(int x,int y,int w,int h,int col) +{ + if (w==0 && h==0) + { + GFX_plot(x,y,col); + return; + } + + w-=SGN(w); + h-=SGN(h); + + if (w<0) + { + x+=w; + w=-w; + } + + if (h<0) + { + y+=h; + h=-h; + } + + DIRTY(x,y); + DIRTY(x+w,y+h); + + setXCol(col); + XDrawRectangle(disp,pix,gc,x,y,w,h); +} + + +void GFX_frect(int x,int y,int w,int h,int col) +{ + if (w==0 && h==0) + { + GFX_plot(x,y,col); + return; + } + + if (w<0) + { + x+=(w+1); + w=-w; + } + + if (h<0) + { + y+=(h+1); + h=-h; + } + + DIRTY(x,y); + DIRTY(x+w,y+h); + + setXCol(col); + XFillRectangle(disp,pix,gc,x,y,w,h); +} + + +void GFX_set_XOR_mode(void) +{ + XSetFunction(disp,gc,curr_func=GXxor); +} + + +void GFX_clear_XOR_mode(void) +{ + XSetFunction(disp,gc,curr_func=GXcopy); +} + + +void GFX_print(int x,int y,int col,char *fmt,...) +{ + char s[1024]; + va_list va; + size_t len; + + va_start(va,fmt); + vsprintf(s,fmt,va); + va_end(va); + + len=strlen(s); + + y+=fh-FONTGAP; + + DIRTY(x,y); + DIRTY(x+fw*strlen(s),y+fh); + + setXCol(col); + XDrawString(disp,pix,gc,x,y,s,len); +} + + +int GFX_fh(void) +{ + return fh; +} + + +int GFX_fw(void) +{ + return fw; +} + + +int GFX_mouse_buttons(void) +{ + return mbuttons; +} + + +int GFX_mouse(int *x,int *y) +{ + Wait(X11_GFXall,FALSE); + + if (x) + *x=mouse_x; + + if (y) + *y=mouse_y; + + return mouse_b; +} + + +void GFX_waitkey(GFXKey *key) +{ + GFXKey ev; + + Wait(X11_GFXkey,TRUE); + GetKey(key ? key:&ev); +} + + +int GFX_key(GFXKey *key) +{ + Wait(X11_GFXall,FALSE); + + if (kb_head) + { + GetKey(key); + return TRUE; + } + else + return FALSE; +} + + +void GFX_bounce(void) +{ + GFXKey d; + + while (kb_head) + GetKey(&d); + + mouse_b=0; +} + + +void GFX_await_input(GFXEvent *ev) +{ + switch(Wait(X11_GFXkey|X11_GFXmouse,TRUE)) + { + case X11_GFXkey: + GetKey(&(ev->key)); + ev->type=GFX_KEY_EVENT; + break; + + case X11_GFXmouse: + ev->type=GFX_MOUSE_EVENT; + ev->mouse.shift=is_shift; + ev->mouse.ctrl=is_ctrl; + ev->mouse.alt=is_alt; + ev->mouse.x=mouse_x; + ev->mouse.y=mouse_y; + ev->mouse.b=mouse_b; + break; + + default: + break; + } +} + + +void GFX_await_input_full(GFXEvent *ev) +{ + switch(Wait(X11_GFXall,TRUE)) + { + case X11_GFXkey: + GetKey(&(ev->key)); + ev->type=GFX_KEY_EVENT; + break; + + case X11_GFXmouse: + case X11_GFXmouseMove: + ev->type=GFX_MOUSE_EVENT; + ev->mouse.shift=is_shift; + ev->mouse.ctrl=is_ctrl; + ev->mouse.alt=is_alt; + ev->mouse.x=mouse_x; + ev->mouse.y=mouse_y; + ev->mouse.b=mouse_b; + break; + + default: + break; + } +} + + +void GFX_exit(int code,char *fmt,...) +{ + va_list va; + + va_start(va,fmt); + vfprintf(stderr,fmt,va); + va_end(va); + + /* Be lazy, and leave the might of Unix to clear up, though may as well + let X know. + */ + if (disp) + XCloseDisplay(disp); + + exit(code); +} + + +GFX_IMAGE GFX_create_image(GFX_BITMAP *bm) +{ + GfxImage i; + char *data; + int x,y; + unsigned long pal[256]; + + data=Grab(bm->w*bm->h*4); + + i.p=XCreateImage(disp,visual.visual,visual.depth, + ZPixmap,0,data,bm->w,bm->h,32,4*bm->w); + + if (!i.p) + { + Release(data); + return NULL; + } + + for(x=0;x<256;x++) + pal[x]=getXCol(bm->pal[x]); + + i.w=bm->w; + i.h=bm->h; + + for(x=0;x<bm->w;x++) + for(y=0;y<bm->h;y++) + XPutPixel(i.p,x,y,pal[*(bm->data+x+y*bm->w)]); + + return Copy(&i,sizeof i); +} + + +void GFX_destroy_image(GFX_IMAGE img) +{ + GfxImage *p=img; + + if (p) + { + XDestroyImage(p->p); + Release(p); + } +} + + +void GFX_draw_image(GFX_IMAGE i, int x, int y) +{ + GfxImage *p=i; + + if (p) + { + if (curr_func!=GXcopy) + XSetFunction(disp,gc,GXcopy); + + XPutImage(disp,pix,gc,p->p,0,0,x,y,p->w,p->h); + + DIRTY(x,y); + DIRTY(x+p->w,y+p->h); + + if (curr_func!=GXcopy) + XSetFunction(disp,gc,curr_func); + } +} + + +void GFX_fill_screen(GFX_IMAGE i) +{ + GfxImage *p=i; + + if (p) + GFX_draw_image(i,(width-p->w)/2,(height-p->h)/2); +} + + +void GFX_save_screen(char *path) +{ +} + + +/* END OF FILE */ diff --git a/linux/main.c b/linux/main.c new file mode 100644 index 0000000..9cda67e --- /dev/null +++ b/linux/main.c @@ -0,0 +1,33 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + Startup code + +*/ +static const char rcs_id[]="$Id$"; + +#include "vidoom.h" + +int main(int argc,char *argv[]) +{ + return viDOOM(argc,argv); +} diff --git a/linux/mem.c b/linux/mem.c new file mode 100644 index 0000000..a23b4ce --- /dev/null +++ b/linux/mem.c @@ -0,0 +1,107 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + Memory allocation code + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" + +#include <stdio.h> +#include <string.h> + +#include "mem.h" +#include "gfx.h" + +void *FGrab(char *fn, int line, int len) +{ + char *ptr; + + if (len==0) + len=1; + + if (!(ptr=malloc(len))) + GFX_exit(EXIT_FAILURE,"Memory allocation failed!\n" + "%s:%d Grab(%d)\n",fn,line,len); + + memset(ptr,0,len); + + return ptr; +} + + +void *FReGrab(char *fn, int line, void *ptr, int len) +{ + if (len==0) + len=1; + + if (!(ptr=realloc(ptr,len))) + GFX_exit(EXIT_FAILURE,"Memory allocation failed!\n" + "%s:%d ReGrab(%d)\n",fn,line,len); + + return ptr; +} + + +void FRelease(char *fn, int line, void *p) +{ + free(p); +} + + +void *FCopy(char *fn, int line, void *p,int len) +{ + void *ptr; + + if (len==0) + ptr=malloc(1); + else + ptr=malloc(len); + + if (!ptr) + GFX_exit(EXIT_FAILURE,"Memory allocation failed!\n" + "%s:%d Copy(%p,%d)\n",fn,line,p,len); + + if (len) + memcpy(ptr,p,len); + + return ptr; +} + + +char *FStrdup(char *fn, int line, char *p) +{ + char n_fn[PATH_MAX]; + char *ptr; + + if (!p) + return NULL; + + if (!(ptr=strdup(p))) + GFX_exit(EXIT_FAILURE,"Memory allocation failed!\n" + "%s:%d Stdup(%s)\n",fn,line,p); + + return ptr; +} + +/* END OF FILE */ 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 */ diff --git a/linux/runcmd.c b/linux/runcmd.c new file mode 100644 index 0000000..bea822b --- /dev/null +++ b/linux/runcmd.c @@ -0,0 +1,82 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + Command execution interface + +*/ +static const char rcs_id[]="$Id$"; + +#include "config.h" +#include "mem.h" + +#include <unistd.h> +#include <stdio.h> + +#define MAX_CMDSIZE 8192 + +static void Write(int fd, char *p) +{ + /* Should really do a loopy proper one... + */ + write(fd,p,strlen(p)); +} + + +int RunCommand(char *argv[], char *path) +{ + FILE *fp; + int output; + int f; + char buff[MAX_CMDSIZE]; + + f=0; + buff[0]=0; + + while(argv[f]) + { + strcat(buff,argv[f++]); + strcat(buff," "); + } + + strcpy(path,"vidoomXXXXXX"); + + if ((output=mkstemp(path))==-1) + return FALSE; + + if (!(fp=popen(buff,"r"))) + return FALSE; + + fgets(buff,sizeof buff,fp); + + while(!feof(fp)) + { + Write(output,buff); + fgets(buff,sizeof buff,fp); + } + + /* Assume that non-zero is error + */ + return pclose(fp)==0; +} + + +/* END OF FILE */ diff --git a/linux/vstring.c b/linux/vstring.c new file mode 100644 index 0000000..947ca99 --- /dev/null +++ b/linux/vstring.c @@ -0,0 +1,48 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + Provides portable versions of necessary string routines + +*/ +static const char rcs_id[]="$Id$"; + +#include <string.h> + + +int StrCaseCmp(char *a, char *b) +{ + if (!a || !b) + return 0; + + return strcasecmp(a,b); +} + +int StrNCaseCmp(char *a, char *b, int n) +{ + if (!a || !b) + return 0; + + return strncasecmp(a,b,n); +} + + +/* END OF FILE */ |