This is xvtext.c in view mode; [Download] [Up]
/* * xvtext.c - text file display window routines * * includes: * void CreateTextWins(geom, cmtgeom); * void OpenTextView(text, textlen, title, freeonclose); * void OpenCommentText(); * void CloseCommentText(); * void ChangeCommentText(); * void HideTextWindows(); * void UnHideTextWindows(); * void RaiseTextWindows(); * void SetTextCursor(Cursor); * void KillTextWindows(); * int TextCheckEvent(evt, int *retval, int *done); * */ /* Copyright Notice * ================ * Copyright 1989, 1990, 1991, 1992, 1993 by John Bradley * * Permission to use, copy, and distribute XV in its entirety, for * non-commercial purposes, is hereby granted without fee, provided that * this license information and copyright notice appear in all copies. * * Note that distributing XV 'bundled' in with ANY product is considered * to be a 'commercial purpose'. * * Also note that any copies of XV that are distributed MUST be built * and/or configured to be in their 'unregistered copy' mode, so that it * is made obvious to the user that XV is shareware, and that they should * consider donating, or at least reading this License Info. * * The software may be modified for your own purposes, but modified * versions may NOT be distributed without prior consent of the author. * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author be held liable for any damages * arising from the use of this software. * * If you would like to do something with XV that this copyright * prohibits (such as distributing it with a commercial product, * using portions of the source in some other program, etc.), please * contact the author (preferably via email). Arrangements can * probably be worked out. * * XV is shareware for PERSONAL USE only. You may use XV for your own * amusement, and if you find it nifty, useful, generally cool, or of * some value to you, your non-deductable donation would be greatly * appreciated. $25 is the suggested donation, though, of course, * larger donations are quite welcome. Folks who donate $25 or more * can receive a Real Nice bound copy of the XV manual for no extra * charge. * * Commercial, government, and institutional users MUST register their * copies of XV, for the exceedingly REASONABLE price of just $25 per * workstation/X terminal. Site licenses are available for those who * wish to run XV on a large number of machines. Contact the author * for more details. * * The author may be contacted via: * US Mail: John Bradley * 1053 Floyd Terrace * Bryn Mawr, PA 19010 * * Phone: (215) 898-8813 * EMail: bradley@cis.upenn.edu */ #include "xv.h" #define BUTTW 80 #define BUTTH 24 #define TOPMARGIN 30 /* from top of window to top of text window */ #define BOTMARGIN (5+BUTTH+5) /* room for a row of buttons at bottom */ #define LRMARGINS 5 /* left and right margins */ #define MAXTVWIN 2 /* total # of windows */ #define MAXTEXTWIN 1 /* # of windows for text file viewing */ #define CMTWIN 1 /* cmtwin is reserved for image comments */ /* button/menu indicies */ #define TV_ASCII 0 #define TV_HEX 1 #define TV_CLOSE 2 #define TV_NBUTTS 3 /* constants used in textKey(), below */ #define TV_LEFT 0 #define TV_RIGHT 1 #define TV_UP 2 #define TV_DOWN 3 #define TV_PAGEUP 4 #define TV_PAGEDN 5 #define TV_HOME 6 #define TV_END 7 #define TITLELEN 128 /* data needed per text window */ typedef struct { Window win, textW; int vis, wasvis; char *text; /* text to be displayed */ int freeonclose; /* free text when closing win */ int textlen; /* length of text */ char title[TITLELEN]; /* name of file being displayed */ char **lines; /* ptr to array of line ptrs */ int numlines; /* # of lines in text */ int hexlines; /* # of lines in HEX mode */ int maxwide; /* length of longest line (ascii) */ int wide, high; /* size of outer window (win) */ int twWide, twHigh; /* size of inner window (textW) */ int chwide, chhigh; /* size of textW, in chars */ int hexmode; /* true if disp Hex, else Ascii */ SCRL vscrl, hscrl; BUTT but[TV_NBUTTS], nopBut; } TVINFO; static TVINFO tinfo[MAXTVWIN]; static int hasBeenSized = 0; static int haveWindows = 0; static int mfwide, mfhigh, mfascent; /* size of chars in mono font */ static int *event_retP, *event_doneP; /* used in tvChkEvent() */ #ifdef __STDC__ static void closeText (TVINFO *); static int tvChkEvent (TVINFO *, XEvent *); static void resizeText (TVINFO *, int, int); static void computeScrlVals(TVINFO *); static void doCmd (TVINFO *, int); static void drawTextView (TVINFO *); static void drawNumLines (TVINFO *); static void eraseNumLines (TVINFO *); static void drawTextW (int, SCRL *); static void clickText (TVINFO *, int, int); static void keyText (TVINFO *, XKeyEvent *); static void textKey (TVINFO *, int); static void doHexAsciiCmd (TVINFO *, int); static void computeText (TVINFO *); #else static int tvChkEvent(); static void closeText(), resizeText(), doCmd(), drawTextView(), drawTextW(); static void drawNumLines(), eraseNumLines(), computeScrlVals(); static void clickText(), keyText(), textKey(); static void doHexAsciiCmd(), computeText(); #endif /* HEXMODE output looks like this: 0x00000000: 00 11 22 33 44 55 66 77 - 88 99 aa bb cc dd ee ff 0123456789abcdef 0x00000010: 00 11 22 33 44 55 66 77 - 88 99 aa bb cc dd ee ff 0123456789abcdef etc. */ /***************************************************************/ void CreateTextWins(geom, cmtgeom) char *geom, *cmtgeom; { int i, defwide, defhigh, cmthigh; XSizeHints hints; XSetWindowAttributes xswa; TVINFO *tv; int gx,gy,gw,gh,gset,gx1,gy1; mfwide = monofinfo->max_bounds.width; mfhigh = monofinfo->ascent + monofinfo->descent; mfascent = monofinfo->ascent; /* compute default size of textview windows. should be big enough to hold an 80x24 text window */ defwide = 80 * mfwide + 2*LRMARGINS + 8 + 20; /* -ish */ defhigh = 24 * mfhigh + TOPMARGIN + BOTMARGIN + 8 + 20; /* ish */ cmthigh = 6 * mfhigh + TOPMARGIN + BOTMARGIN + 8 + 20; /* ish */ /* creates *all* textview windows at once */ for (i=0; i<MAXTVWIN; i++) tinfo[i].win = (Window) NULL; for (i=0; i<MAXTVWIN; i++) { tv = &tinfo[i]; tv->win = CreateWindow((i<CMTWIN) ? "xv text viewer" : "xv image comments", "XVtextview", (i<CMTWIN) ? geom : cmtgeom, defwide, (i<CMTWIN) ? defhigh : cmthigh, infofg, infobg, 1); if (!tv->win) FatalError("can't create textview window!"); haveWindows = 1; tv->vis = tv->wasvis = 0; if (ctrlColor) XSetWindowBackground(theDisp, tv->win, locol); else XSetWindowBackgroundPixmap(theDisp, tv->win, grayTile); /* note: everything is sized and positioned in resizeText() */ tv->textW = XCreateSimpleWindow(theDisp, tv->win, 1,1, 100,100, 1,infofg,infobg); if (!tv->textW) FatalError("can't create textview text window!"); SCCreate(&(tv->vscrl), tv->win, 0,0, 1,100, 0,0,0,0, infofg, infobg, hicol, locol, drawTextW); SCCreate(&(tv->hscrl), tv->win, 0,0, 0,100, 0,0,0,0, infofg, infobg, hicol, locol, drawTextW); if (XGetNormalHints(theDisp, tv->win, &hints)) hints.flags |= PMinSize; else hints.flags = PMinSize; hints.min_width = 380; hints.min_height = 200; XSetNormalHints(theDisp, tv->win, &hints); #ifdef BACKING_STORE xswa.backing_store = WhenMapped; XChangeWindowAttributes(theDisp, tv->textW, CWBackingStore, &xswa); #endif XSelectInput(theDisp, tv->textW, ExposureMask | ButtonPressMask); BTCreate(&(tv->but[TV_ASCII]), tv->win, 0,0,BUTTW,BUTTH, "Ascii",infofg,infobg,hicol,locol); BTCreate(&(tv->but[TV_HEX]), tv->win, 0,0,BUTTW,BUTTH, "Hex",infofg,infobg,hicol,locol); BTCreate(&(tv->but[TV_CLOSE]), tv->win, 0,0,BUTTW,BUTTH, "Close",infofg,infobg,hicol,locol); BTCreate(&(tv->nopBut), tv->win, 0,0, tv->vscrl.tsize+1, tv->vscrl.tsize+1, "", infofg, infobg, hicol, locol); tv->nopBut.active = 0; XMapSubwindows(theDisp, tv->win); tv->text = (char *) NULL; tv->textlen = 0; tv->title[0] = '\0'; } for (i=0; i<MAXTVWIN; i++) { resizeText(&tinfo[i], defwide, (i<CMTWIN) ? defhigh : cmthigh); XSelectInput(theDisp, tinfo[i].win, ExposureMask | ButtonPressMask | KeyPressMask | StructureNotifyMask); } hasBeenSized = 1; /* we can now start looking at textview events */ } /***************************************************************/ void TextView(fname) char *fname; { /* given a filename, attempts to read in the file and open a textview win */ int i; long textlen; char *text, buf[512], title[128], rfname[MAXPATHLEN+1]; char *basefname[128]; /* just current fname, no path */ FILE *fp; basefname[0] = '\0'; strcpy(rfname, fname); /* see if this file is compressed. if it is, uncompress it, and view the uncompressed version */ if (ReadFileType(fname) == RFT_COMPRESS) { #ifndef VMS if (!UncompressFile(fname, rfname)) return; /* failed to uncompress */ #else /* chop off trailing '.Z' from friendly displayed basefname, if any */ strcpy (basefname, fname); *rindex (basefname, '.') = '\0'; if (!UncompressFile(basefname, rfname)) return;/* failed to uncompress */ #endif } fp = fopen(rfname, "r"); if (!fp) { sprintf(buf,"Couldn't open '%s': %s", rfname, ERRSTR(errno)); ErrPopUp(buf,"\nOh well"); return; } fseek(fp, 0L, 2); textlen = ftell(fp); fseek(fp, 0L, 0); if (!textlen) { sprintf(buf, "File '%s' contains no data. (Zero length file.)", rfname); ErrPopUp(buf, "\nOk"); fclose(fp); return; } text = (char *) malloc(textlen); if (!text) { sprintf(buf, "Couldn't malloc %ld bytes to read file '%s'", textlen, rfname); ErrPopUp(buf, "\nSo what!"); fclose(fp); return; } if (fread(text, 1, textlen, fp) != textlen) { sprintf(buf, "Warning: Couldn't read all of '%s'. Possibly truncated.", rfname); ErrPopUp(buf, "\nHmm..."); } fclose(fp); sprintf(title, "File: '%s'", BaseName(fname)); OpenTextView(text, textlen, title, 1); /* note: text gets freed when window gets closed */ } /***************************************************************/ void OpenTextView(text, len, title, freeonclose) char *text, *title; int len, freeonclose; { /* opens up a textview window */ int i, oldone; TVINFO *tv; tv = &tinfo[0]; /* kill off old text info */ if (tv->freeonclose && tv->text) free(tv->text); if (tv->lines) free(tv->lines); tv->text = (char *) NULL; tv->lines = (char **) NULL; tv->numlines = tv->textlen = tv->hexmode = 0; tv->text = text; tv->textlen = len; tv->freeonclose = freeonclose; strncpy(tv->title, title, TITLELEN-1); computeText(tv); /* compute # lines and linestarts array */ anyTextUp = 1; if (!tv->vis) XMapRaised(theDisp, tv->win); else { XClearArea(theDisp, tv->win, 0, 0, tv->wide, 30, False); drawTextView(tv); } tv->vis = 1; SCSetVal(&(tv->vscrl), 0); SCSetVal(&(tv->hscrl), 0); computeScrlVals(tv); } /***************************************************************/ void OpenCommentText() { /* opens up the reserved 'comment' textview window */ int i; TVINFO *tv; tv = &tinfo[CMTWIN]; commentUp = 1; XMapRaised(theDisp, tv->win); tv->vis = 1; ChangeCommentText(); } /***************************************************************/ void CloseCommentText() { /* closes the reserved 'comment' textview window */ closeText(&tinfo[CMTWIN]); commentUp = 0; } /***************************************************************/ void ChangeCommentText() { /* called when 'picComments' changes */ TVINFO *tv; tv = &tinfo[CMTWIN]; tv->text = picComments; tv->textlen = (tv->text) ? strlen(tv->text) : 0; tv->freeonclose = 0; if (strlen(fullfname)) sprintf(tv->title, "File: '%s'", BaseName(fullfname)); else sprintf(tv->title, "<no file loaded>"); computeText(tv); /* compute # lines and linestarts array */ if (tv->vis) { XClearArea(theDisp, tv->win, 0, 0, tv->wide, 30, False); drawTextView(tv); } SCSetVal(&(tv->vscrl), 0); SCSetVal(&(tv->hscrl), 0); computeScrlVals(tv); } static char license[10240]; /***************************************************************/ void ShowLicense() { license[0] = '\0'; /* build the license text */ #ifdef LC #undef LC #endif #define LC(x) (strcat(license, x), strcat(license, "\n")) LC("XV License Info"); LC("==============="); LC("Thank you for acquiring a copy of XV. I hope you enjoy it."); LC(""); LC("XV is shareware for PERSONAL USE only. You may use XV for your own"); LC("amusement, and if you find it nifty, useful, generally cool, or of"); LC("some value to you, your non-deductable donation would be greatly"); LC("appreciated. $25 is the suggested donation, though, of course,"); LC("larger donations are quite welcome. Folks who donate $25 or more"); LC("can receive a Real Nice bound copy of the XV manual for no extra"); LC("charge. BE SURE TO SPECIFY THE VERSION OF XV THAT YOU ARE USING!"); LC(""); LC("Commercial, government, and institutional users MUST register their"); LC("copies of XV, for the exceedingly reasonable price of just $25 per"); LC("workstation/X terminal. Site licenses are available for those who"); LC("wish to run XV on a large number of machines. Contact the author"); LC("for more details."); LC(""); LC(""); LC("Copyright Notice"); LC("================"); LC("XV is Copyright 1989, 1990, 1991, 1992, 1993 by John Bradley"); LC(""); LC("Permission to use, copy, and distribute XV in its entirety, for "); LC("non-commercial purposes, is hereby granted without fee, provided that"); LC("this license information and copyright notice appear in all copies."); LC(""); LC("Note that distributing XV 'bundled' in with ANY product is considered"); LC("to be a 'commercial purpose'."); LC(""); LC("If you redistribute XV, the *entire* contents of this distribution"); LC("must be distributed, including the README and INSTALL files, the "); LC("sources, and the entire contents of the 'docs' subdirectory."); LC(""); LC("Also note that any copies of XV that are distributed MUST be built"); LC("and/or configured to be in their 'unregistered copy' mode, so that it"); LC("is made obvious to the user that XV is shareware, and that they should"); LC("consider donating, or at least reading this License Info."); LC(""); LC("The software may be modified for your own purposes, but modified"); LC("versions may NOT be distributed without prior consent of the author."); LC(""); LC("This software is provided 'as-is', without any express or implied"); LC("warranty. In no event will the author be held liable for any damages"); LC("arising from the use of this software."); LC(""); LC("If you would like to do something with XV that this copyright"); LC("prohibits (such as distributing it with a commercial product, "); LC("using portions of the source in some other program, etc.), please"); LC("contact the author (preferably via email). Arrangements can"); LC("probably be worked out."); LC(""); LC(""); LC("The author may be contacted via:"); LC(" US Mail: John Bradley"); LC(" 1053 Floyd Terrace"); LC(" Bryn Mawr, PA 19010"); LC(""); LC(" Phone: (215) 898-8813"); LC(" EMail: bradley@cis.upenn.edu"); LC(""); #undef LC OpenTextView(license, strlen(license), "XV License", 0); } /***************************************************************/ void HideTextWindows() { int i; for (i=0; i<MAXTVWIN; i++) { if (tinfo[i].vis) { XUnmapWindow(theDisp, tinfo[i].win); tinfo[i].wasvis = 1; tinfo[i].vis = 0; } } } /***************************************************************/ void UnHideTextWindows() { int i; for (i=0; i<MAXTVWIN; i++) { if (tinfo[i].wasvis) { XMapRaised(theDisp, tinfo[i].win); tinfo[i].wasvis = 0; tinfo[i].vis = 0; } } } /***************************************************************/ void RaiseTextWindows() { int i; for (i=0; i<MAXTEXTWIN; i++) { if (tinfo[i].vis) { XRaiseWindow(theDisp, tinfo[i].win); } } } /***************************************************************/ void SetTextCursor(c) Cursor c; { int i; for (i=0; i<MAXTVWIN; i++) { if (haveWindows && tinfo[i].win) XDefineCursor(theDisp, tinfo[i].win, c); } } /***************************************************************/ void KillTextWindows() { int i; for (i=0; i<MAXTVWIN; i++) { if (haveWindows && tinfo[i].win) XDestroyWindow(theDisp, tinfo[i].win); } } /***************************************************************/ int TextCheckEvent(xev, retP, doneP) XEvent *xev; int *retP, *doneP; { int i; event_retP = retP; /* so don't have to pass these all over the place */ event_doneP = doneP; for (i=0; i<MAXTVWIN; i++) { if (tvChkEvent(&tinfo[i], xev)) break; } if (i<MAXTVWIN) return 1; return 0; } /***************************************************************/ int TextDelWin(win) Window win; { /* got a delete window request. see if the window is a textview window, and close accordingly. Return 1 if event was eaten */ int i; for (i=0; i<MAXTVWIN; i++) { if (tinfo[i].win == win) { closeText(&tinfo[i]); return 1; } } return 0; } /**************************************************************/ /*** INTERNAL FUNCTIONS ***/ /**************************************************************/ /***************************************************************/ static void closeText(tv) TVINFO *tv; { /* closes specified textview window */ int i; XUnmapWindow(theDisp, tv->win); tv->vis = 0; for (i=0; i<MAXTEXTWIN && !tinfo[i].vis; i++); if (i==MAXTEXTWIN) anyTextUp = 0; /* free all info for this textview window */ if (tv->freeonclose && tv->text) free(tv->text); if (tv->lines) free(tv->lines); tv->text = (char *) NULL; tv->lines = (char **) NULL; tv->numlines = tv->textlen = tv->hexmode = 0; } /***************************************************************/ static int tvChkEvent(tv, xev) TVINFO *tv; XEvent *xev; { /* checks event to see if it's a text-window related thing. If it is, it eats the event and returns '1', otherwise '0'. */ int i, rv; rv = 1; if (!hasBeenSized) return 0; /* ignore evrythng until we get 1st Resize */ if (xev->type == Expose) { int x,y,w,h; XExposeEvent *e = (XExposeEvent *) xev; x = e->x; y = e->y; w = e->width; h = e->height; /* throw away excess redraws for 'dumb' windows */ if (e->count > 0 && (e->window == tv->vscrl.win || e->window == tv->hscrl.win)) {} else if (e->window == tv->vscrl.win) SCRedraw(&(tv->vscrl)); else if (e->window == tv->hscrl.win) SCRedraw(&(tv->hscrl)); else if (e->window == tv->win || e->window == tv->textW) { /* smart wins */ /* group individual expose rects into a single expose region */ int count; Region reg; XRectangle rect; XEvent evt; xvbcopy((char *) e, (char *) &evt, sizeof(XEvent)); reg = XCreateRegion(); count = 0; do { if (DEBUG) fprintf(stderr," expose: %s %d,%d %dx%d\n", (e->window == tv->win) ? "tv win" : "text win", rect.x, rect.y, rect.width, rect.height); rect.x = evt.xexpose.x; rect.y = evt.xexpose.y; rect.width = evt.xexpose.width; rect.height = evt.xexpose.height; XUnionRectWithRegion(&rect, reg, reg); count++; } while (XCheckWindowEvent(theDisp, evt.xexpose.window, ExposureMask, &evt)); XClipBox(reg, &rect); /* bounding box of region */ XSetRegion(theDisp, theGC, reg); if (DEBUG) { fprintf(stderr,"win = %lx, tv->win = %lx, textW = %lx\n", e->window, tv->win, tv->textW); fprintf(stderr,"grouped %d expose events into %d,%d %dx%d rect\n", count, rect.x, rect.y, rect.width, rect.height); } if (e->window == tv->win) drawTextView(tv); else if (e->window == tv->textW) drawTextW(0, &(tv->vscrl)); XSetClipMask(theDisp, theGC, None); XDestroyRegion(reg); } else rv = 0; } else if (xev->type == ButtonPress) { XButtonEvent *e = (XButtonEvent *) xev; int i,x,y; x = e->x; y = e->y; if (e->button == Button1) { if (e->window == tv->win) clickText(tv,x,y); else if (e->window == tv->vscrl.win) SCTrack(&(tv->vscrl),x,y); else if (e->window == tv->hscrl.win) SCTrack(&(tv->hscrl),x,y); else if (e->window == tv->textW) { } else rv = 0; } else rv = 0; } else if (xev->type == KeyPress) { XKeyEvent *e = (XKeyEvent *) xev; if (e->window == tv->win) keyText(tv, e); else rv = 0; } else if (xev->type == ConfigureNotify) { XConfigureEvent *e = (XConfigureEvent *) xev; if (e->window == tv->win) { if (DEBUG) fprintf(stderr,"textview got a configure event (%dx%d)\n", e->width, e->height); if (tv->wide != e->width || tv->high != e->height) { if (DEBUG) fprintf(stderr,"Forcing a redraw! (from configure)\n"); XClearArea(theDisp, tv->win, 0, 0, e->width, e->height, True); resizeText(tv, e->width, e->height); } } else rv = 0; } else rv = 0; return rv; } /***************************************************************/ static void resizeText(tv,w,h) TVINFO *tv; int w,h; { int i, maxw, maxh, hmax, hpage, vmax, vpage; XSizeHints hints; if (tv->wide == w && tv->high == h) return; /* no change in size */ if (XGetNormalHints(theDisp, tv->win, &hints)) { hints.width = w; hints.height = h; hints.flags |= USSize; XSetNormalHints(theDisp, tv->win, &hints); } tv->wide = w; tv->high = h; /* compute maximum size of text window */ maxw = tv->wide - (2*LRMARGINS) - (tv->vscrl.tsize+1) - 2; maxh = tv->high - (TOPMARGIN + BOTMARGIN) - (tv->hscrl.tsize+1) - 2; tv->chwide = ((maxw - 6) / mfwide); tv->chhigh = ((maxh - 6) / mfhigh); tv->twWide = tv->chwide * mfwide + 6; tv->twHigh = tv->chhigh * mfhigh + 6; XMoveResizeWindow(theDisp, tv->textW, LRMARGINS, TOPMARGIN, tv->twWide, tv->twHigh); for (i=0; i<TV_NBUTTS; i++) { tv->but[i].x = tv->wide - (TV_NBUTTS-i) * (BUTTW+5); tv->but[i].y = tv->high - BUTTH - 5; } computeScrlVals(tv); tv->nopBut.x = LRMARGINS + tv->twWide + 1; tv->nopBut.y = TOPMARGIN + tv->twHigh + 1; } /***************************************************************/ static void computeScrlVals(tv) TVINFO *tv; { int hmax, hpag, vmax, vpag; if (tv->hexmode) { hmax = 80 - tv->chwide; vmax = tv->hexlines - tv->chhigh; } else { /* ASCII mode */ hmax = tv->maxwide - tv->chwide; vmax = tv->numlines - tv->chhigh - 1; } hpag = tv->chwide / 4; vpag = tv->chhigh - 1; SCChange(&tv->vscrl, LRMARGINS + tv->twWide+1, TOPMARGIN, 1, tv->twHigh, 0, vmax, tv->vscrl.val, vpag); SCChange(&tv->hscrl, LRMARGINS, TOPMARGIN + tv->twHigh + 1, 0, tv->twWide, 0, hmax, tv->hscrl.val, hpag); } /***************************************************************/ static void doCmd(tv, cmd) TVINFO *tv; int cmd; { switch (cmd) { case TV_ASCII: doHexAsciiCmd(tv, 0); break; case TV_HEX: doHexAsciiCmd(tv, 1); break; case TV_CLOSE: closeText(tv); break; } } /***************************************************************/ static void drawTextView(tv) TVINFO *tv; { /* redraw the outer window */ int i, y; if (strlen(tv->title)) { /* draw the title */ y = 5; XSetForeground(theDisp, theGC, infobg); XFillRectangle(theDisp, tv->win, theGC, 5+1, y+1, StringWidth(tv->title)+6, CHIGH+4); XSetForeground(theDisp, theGC, infofg); XDrawRectangle(theDisp, tv->win, theGC, 5, y, StringWidth(tv->title)+7, CHIGH+5); Draw3dRect(tv->win, 5+1, y+1, StringWidth(tv->title)+5, CHIGH+3, R3D_IN, 2, hicol, locol, infobg); XSetForeground(theDisp, theGC, infofg); XDrawString(theDisp, tv->win, theGC, 5+3, y+ASCENT+3, tv->title, strlen(tv->title)); } drawNumLines(tv); /* draw the buttons */ for (i=0; i<TV_NBUTTS; i++) BTRedraw(&(tv->but[i])); BTRedraw(&tv->nopBut); } /***************************************************************/ static void drawNumLines(tv) TVINFO *tv; { int x, y, w, nl; char tmpstr[128]; if (tv->hexmode) nl = tv->hexlines; else { if (tv->numlines>0 && tv->lines[tv->numlines-1] - tv->lines[tv->numlines-2] == 1) nl = tv->numlines - 2; /* line after last \n has zero length */ else nl = tv->numlines - 1; } if (nl<0) nl = 0; sprintf(tmpstr, "%d byte%s, %d line%s", tv->textlen, (tv->textlen!=1) ? "s" : "", nl, (nl!=1) ? "s" : ""); w = StringWidth(tmpstr) + 7; /* width of frame */ x = LRMARGINS + tv->twWide + tv->vscrl.tsize+1; /* right align point */ y = 6; XSetForeground(theDisp, theGC, infobg); XFillRectangle(theDisp, tv->win, theGC, (x-w)+1, y+1, (w-1), CHIGH+4); XSetForeground(theDisp, theGC, infofg); XDrawRectangle(theDisp, tv->win, theGC, x-w, y, w, CHIGH+5); Draw3dRect(tv->win, (x-w)+1, y+1, w-2,CHIGH+3,R3D_IN,2,hicol,locol,infobg); XSetForeground(theDisp, theGC, infofg); XDrawString(theDisp, tv->win, theGC, (x-w)+3, y+ASCENT+3, tmpstr, strlen(tmpstr)); } /***************************************************************/ static void eraseNumLines(tv) TVINFO *tv; { int x, y, w, nl; char tmpstr[64]; nl = (tv->hexmode) ? tv->hexlines : tv->numlines-1; sprintf(tmpstr, "%d byte%s, %d line%s", tv->textlen, (tv->textlen>1) ? "s" : "", nl, (nl>1) ? "s" : ""); w = StringWidth(tmpstr) + 7; /* width of frame */ x = LRMARGINS + tv->twWide + tv->vscrl.tsize+1; /* right align point */ y = 5; XClearArea(theDisp, tv->win, x-w, y, w+1, CHIGH+7, False); } /***************************************************************/ static void drawTextW(delta, sptr) int delta; SCRL *sptr; { int i, j, lnum, hpos, cpos, extrach, lwide; TVINFO *tv; char linestr[512]; u_char *sp, *ep, *lp; /* figure out TVINFO pointer from SCRL pointer */ for (i=0; i<MAXTVWIN && sptr != &tinfo[i].vscrl && sptr != &tinfo[i].hscrl; i++); if (i==MAXTVWIN) return; /* didn't find one */ tv = &tinfo[i]; /* make sure we've been sized. Necessary, as creating/modifying the scrollbar calls this routine directly, rather than through TextCheckEvent() */ if (!hasBeenSized) return; XSetForeground(theDisp, theGC, infofg); XSetBackground(theDisp, theGC, infobg); XSetFont(theDisp, theGC, monofont); hpos = tv->hscrl.val; lwide = (tv->chwide < 500) ? tv->chwide : 500; /* draw text */ if (!tv->hexmode) { /* ASCII mode */ for (i=0; i<tv->chhigh; i++) { /* draw each line */ lnum = i + tv->vscrl.val; if (lnum < tv->numlines-1) { /* find start of displayed portion of line. This is *wildly* complicated by the ctrl-character and tab expansion... */ sp = (byte *) tv->lines[lnum]; ep = (byte *) tv->lines[lnum+1] - 1; /* ptr to last disp ch in line */ extrach = 0; for (cpos=0; cpos<hpos && sp<ep; cpos++) { if (!extrach) { if (*sp == '\011') { /* tab to next multiple of 8 */ extrach = ((cpos+8) & (~7)) - cpos; extrach--; } else if (*sp == '\015') { /* ^M not displayed */ cpos--; sp++; } else if (*sp < 32) extrach = 1; else if (*sp > 127) extrach = 3; else sp++; } else { extrach--; if (!extrach) sp++; } } /* at this point, 'sp' is pointing to the first char to display. if sp is a 'special' character, extrach is the # of chars left to display of the 'expanded' version. If sp>=ep, a blank line should be printed */ /* build up the linestr buffer, which is the current line, padded with blanks to a width of exactly tv->chwide chars */ for (cpos=0, lp=(byte *) linestr; cpos<lwide; cpos++, lp++) { if (sp>=ep) *lp = ' '; else { if (*sp == '\011') { /* tab to next multiple of 8 */ if (!extrach) extrach = ((cpos+hpos+8) & (~7)) - (cpos+hpos); if (extrach) *lp = ' '; } else if (*sp == '\015') { /* don't show ^M */ cpos--; lp--; sp++; } else if (*sp < 32) { if (!extrach) extrach = 2; if (extrach == 2) *lp = '^'; else if (extrach == 1) *lp = *sp + 64; } else if (*sp > 127) { if (!extrach) extrach = 4; if (extrach == 4) *lp = '\\'; else if (extrach == 3) *lp = ((*sp & 0700) >> 6) + '0'; else if (extrach == 2) *lp = ((*sp & 0070) >> 3) + '0'; else if (extrach == 1) *lp = ((*sp & 0007)) + '0'; } else *lp = *sp++; if (extrach) { extrach--; if (!extrach) sp++; } } } } else { /* below bottom of file. Just build a blank str */ for (cpos = 0; cpos<lwide; cpos++) linestr[cpos]=' '; } /* draw the line */ XDrawImageString(theDisp, tv->textW, theGC, 3, i*mfhigh + 3 + mfascent, linestr, lwide); } /* for i ... */ } /* if hexmode */ else { /* HEX MODE */ for (i=0; i<tv->chhigh; i++) { /* draw each line */ lnum = i + tv->vscrl.val; if (lnum < tv->hexlines) { char hexstr[80], tmpstr[16]; /* generate hex for this line */ sprintf(hexstr, "0x%08x: ", lnum * 0x10); sp = (byte *) tv->text + lnum * 0x10; ep = (byte *) tv->text + tv->textlen; /* ptr to end of buffer */ for (j=0; j<16; j++) { if (sp+j < ep) sprintf(tmpstr,"%02x ", sp[j]); else sprintf(tmpstr," "); strcat(hexstr, tmpstr); if (j==7) { if (sp+8<ep) strcat(hexstr,"- "); else strcat(hexstr," "); } } strcat(hexstr," "); lp = (byte *) hexstr + strlen(hexstr); for (j=0; j<16; j++) { if (sp+j < ep) { if (sp[j] >= 32 && sp[j] <= 127) *lp++ = sp[j]; else *lp++ = '.'; } else *lp++ = ' '; } *lp = '\0'; /* at this point, 'hexstr' contains an 80 column hex thingy. now build 'linestr', which is going to have hexstr shifted and/or padded with blanks (ie, the displayed portion or hexstr) */ /* skip obscured beginning of line, if any */ for (cpos=0, sp=(byte *) hexstr; cpos<hpos && *sp; cpos++, sp++); for (cpos=0, lp=(byte *)linestr; cpos<lwide; cpos++, lp++) { if (*sp) { *lp = *sp++; } else *lp = ' '; } } else { /* below bottom of file. just build blank str */ for (cpos=0; cpos<lwide; cpos++) linestr[cpos]=' '; } /* draw the line */ XDrawImageString(theDisp, tv->textW, theGC, 3, i*mfhigh + 3 + mfascent, linestr, lwide); } /* for i ... */ } /* else hexmode */ XSetFont(theDisp, theGC, mfont); Draw3dRect(tv->textW, 0, 0, tv->twWide-1, tv->twHigh-1, R3D_IN, 2, hicol, locol, infobg); } /***************************************************************/ static void clickText(tv, x,y) TVINFO *tv; int x,y; { int i; BUTT *bp; for (i=0, bp=tv->but; i<TV_NBUTTS; i++, bp++) { if (PTINRECT(x,y,bp->x,bp->y,bp->w,bp->h)) break; } if (i<TV_NBUTTS) { if (BTTrack(bp)) doCmd(tv, i); return; } } /***************************************************************/ static void keyText(tv, kevt) TVINFO *tv; XKeyEvent *kevt; { char buf[128]; KeySym ks; int stlen, shift, dealt; stlen = XLookupString(kevt, buf, 128, &ks, (XComposeStatus *) NULL); shift = kevt->state & ShiftMask; dealt = 1; /* check for arrow keys, Home, End, PgUp, PgDown, etc. */ if (ks==XK_Left || ks==XK_KP_4 || ks==XK_F30) textKey(tv,TV_LEFT); else if (ks==XK_Right || ks==XK_KP_6 || ks==XK_F32) textKey(tv,TV_RIGHT); else if (ks==XK_Home || (ks==XK_Prior && shift)) textKey(tv,TV_HOME); else if (ks==XK_End || (ks==XK_Next && shift)) textKey(tv,TV_END); else if (ks==XK_Prior || (ks==XK_Up && shift)) textKey(tv,TV_PAGEUP); else if (ks==XK_Next || (ks==XK_Down && shift)) textKey(tv,TV_PAGEDN); else if (ks==XK_Up || ks==XK_KP_8 || ks==XK_F28) textKey(tv,TV_UP); else if (ks==XK_Down || ks==XK_KP_2 || ks==XK_F34) textKey(tv,TV_DOWN); else dealt = 0; if (dealt || !stlen) return; /* keyboard equivalents */ switch (buf[0]) { case '\001': doCmd(tv, TV_ASCII); break; /* ^A = Ascii */ case '\010': doCmd(tv, TV_HEX); break; /* ^H = Hex */ case '\033': doCmd(tv, TV_CLOSE); break; /* ESC = Close window */ default: break; } } /***************************************************/ static void textKey(tv, key) TVINFO *tv; int key; { int i,j; if (!tv->textlen) return; /* an arrow key (or something like that) was pressed in icon window. change selection/scrollbar accordingly */ if (key == TV_UP) SCSetVal(&tv->vscrl, tv->vscrl.val - 1); if (key == TV_DOWN) SCSetVal(&tv->vscrl, tv->vscrl.val + 1); if (key == TV_LEFT) SCSetVal(&tv->hscrl, tv->hscrl.val - 1); if (key == TV_RIGHT) SCSetVal(&tv->hscrl, tv->hscrl.val + 1); if (key == TV_PAGEUP) SCSetVal(&tv->vscrl, tv->vscrl.val - tv->vscrl.page); if (key == TV_PAGEDN) SCSetVal(&tv->vscrl, tv->vscrl.val + tv->vscrl.page); if (key == TV_HOME) SCSetVal(&tv->vscrl, tv->vscrl.min); if (key == TV_END) SCSetVal(&tv->vscrl, tv->vscrl.max); } /***************************************************/ static void doHexAsciiCmd(tv, hexval) TVINFO *tv; int hexval; { int i, oldvscrl, pos; if (hexval == tv->hexmode) return; /* already ascii */ eraseNumLines(tv); tv->hexmode = hexval; drawNumLines(tv); oldvscrl = tv->vscrl.val; /* compute vals, as width and length of text has changed */ computeScrlVals(tv); /* try to show same area of file */ if (hexval) { /* switched to hex mode */ if (oldvscrl < tv->numlines-1) { pos = tv->lines[oldvscrl] - tv->text; SCSetVal(&tv->vscrl, pos / 16); } } else { /* switch to ascii mode */ pos = oldvscrl * 16; for (i=0; i<tv->numlines-1; i++) { if (tv->lines[i+1] - tv->text > pos && tv->lines[i] - tv->text <= pos) break; } if (i<tv->numlines-1) SCSetVal(&tv->vscrl, i); } drawTextW(0, &tv->vscrl); } /***************************************************/ static void computeText(tv) TVINFO *tv; { /* compute # of lines and linestarts array for given text */ int i,j,wide,maxwide,space; byte *sp; if (!tv->text) { tv->numlines = tv->hexlines = 0; tv->lines = (char **) NULL; return; } /* count the # of newline characters in text */ for (i=0, sp=(byte *) tv->text, tv->numlines=0; i<tv->textlen; i++, sp++) { if (*sp == '\n') tv->numlines++; } /* +1 for start of line after last \n char, +1 to mark end of that line */ tv->numlines += 2; /* build lines array */ tv->lines = (char **) malloc(tv->numlines * sizeof(char *)); if (!tv->lines) FatalError("out of memory in computeText()"); j = 0; tv->lines[j++] = tv->text; for (i=0, sp=(byte *) tv->text; i<tv->textlen; i++, sp++) { if (*sp == '\n') tv->lines[j++] = (char *) (sp + 1); } tv->lines[tv->numlines - 1] = tv->text + tv->textlen + 1; /* each line has a trailing '\n' character, except for the last line, which has a trailing '\0' character. In any case, all lines can be printed by printing ((lines[n+1] - lines[n]) - 1) characters, starting with lines[n]. Note that there is one more lines[] entry than the actual # of lines, so as to mark the end of the last line in the same way as all the others */ /* compute length of longest line, when shown in 'ascii' mode. Takes into account the fact that non-printing chars (<32 or >127) will be shown in an 'expanded' form. (<32 chars will be shown as '^A' (or whatever), and >127 chars will be shown as octal '\275') */ maxwide = 0; for (i=0; i<tv->numlines-1; i++) { /* compute displayed width of line #i */ for (sp=(byte *) tv->lines[i], wide=0; sp<(byte *) tv->lines[i+1]-1; sp++) { if (*sp == '\011') { /* tab to next multiple of 8 */ space = ((wide+8) & (~7)) - wide; wide += space; } else if (*sp < 32) wide += 2; else if (*sp > 127) wide += 4; else wide++; } if (wide > maxwide) maxwide = wide; } tv->maxwide = maxwide; tv->hexlines = (tv->textlen + 15) / 16; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.