]> granicus.if.org Git - nethack/commitdiff
*** empty log message ***
authorjwalz <jwalz>
Sat, 5 Jan 2002 21:06:03 +0000 (21:06 +0000)
committerjwalz <jwalz>
Sat, 5 Jan 2002 21:06:03 +0000 (21:06 +0000)
win/X11/wintext.c [new file with mode: 0644]

diff --git a/win/X11/wintext.c b/win/X11/wintext.c
new file mode 100644 (file)
index 0000000..ee0d753
--- /dev/null
@@ -0,0 +1,626 @@
+/*     SCCS Id: @(#)wintext.c  3.3     96/04/05        */
+/* Copyright (c) Dean Luick, 1992                                */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * File for dealing with text windows.
+ *
+ *     + No global functions.
+ */
+
+#ifndef SYSV
+#define PRESERVE_NO_SYSV       /* X11 include files may define SYSV */
+#endif
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h>
+#include <X11/Xos.h>
+#include <X11/Xaw/Form.h>
+#include <X11/Xaw/AsciiText.h>
+#include <X11/Xaw/Cardinals.h>
+#include <X11/Xatom.h>
+
+#ifdef PRESERVE_NO_SYSV
+# ifdef SYSV
+#  undef SYSV
+# endif
+# undef PRESERVE_NO_SYSV
+#endif
+
+#include "hack.h"
+#include "winX.h"
+#include "xwindow.h"
+
+#ifdef GRAPHIC_TOMBSTONE
+#include <X11/xpm.h>
+#endif
+
+
+#define TRANSIENT_TEXT /* text window is a transient window (no positioning) */
+
+static const char text_translations[] =
+    "#override\n\
+     <BtnDown>: dismiss_text()\n\
+     <Key>: key_dismiss_text()";
+
+#ifdef GRAPHIC_TOMBSTONE
+static const char rip_translations[] =
+    "#override\n\
+     <BtnDown>: rip_dismiss_text()\n\
+     <Key>: rip_dismiss_text()";
+
+static Widget FDECL(create_ripout_widget, (Widget));
+#endif
+
+/*ARGSUSED*/
+void
+delete_text(w, event, params, num_params)
+    Widget w;
+    XEvent *event;
+    String *params;
+    Cardinal *num_params;
+{
+    struct xwindow *wp;
+    struct text_info_t *text_info;
+
+    wp = find_widget(w);
+    text_info = wp->text_information;
+
+    nh_XtPopdown(wp->popup);
+
+    if (text_info->blocked) {
+       exit_x_event = TRUE;
+    } else if (text_info->destroy_on_ack) {
+       destroy_text_window(wp);
+    }
+}
+
+/*
+ * Callback used for all text windows.  The window is poped down on any key
+ * or button down event.  It is destroyed if the main nethack code is done
+ * with it.
+ */
+/*ARGSUSED*/
+void
+dismiss_text(w, event, params, num_params)
+    Widget w;
+    XEvent *event;
+    String *params;
+    Cardinal *num_params;
+{
+    struct xwindow *wp;
+    struct text_info_t *text_info;
+
+    wp = find_widget(w);
+    text_info = wp->text_information;
+
+    nh_XtPopdown(wp->popup);
+
+    if (text_info->blocked) {
+       exit_x_event = TRUE;
+    } else if (text_info->destroy_on_ack) {
+       destroy_text_window(wp);
+    }
+}
+
+/* Dismiss when a non-modifier key pressed. */
+void
+key_dismiss_text(w, event, params, num_params)
+    Widget w;
+    XEvent *event;
+    String *params;
+    Cardinal *num_params;
+{
+    char ch = key_event_to_char((XKeyEvent *) event);
+    if (ch) dismiss_text(w, event, params, num_params);
+}
+
+#ifdef GRAPHIC_TOMBSTONE
+/* Dismiss from clicking on rip image. */
+void
+rip_dismiss_text(w, event, params, num_params)
+    Widget w;
+    XEvent *event;
+    String *params;
+    Cardinal *num_params;
+{
+    dismiss_text(XtParent(w), event, params, num_params);
+}
+#endif
+
+
+/* ARGSUSED */
+void
+add_to_text_window(wp, attr, str)
+    struct xwindow *wp;
+    int attr;  /* currently unused */
+    const char *str;
+{
+    struct text_info_t *text_info = wp->text_information;
+    int width;
+
+    append_text_buffer(&text_info->text, str, FALSE);
+
+    /* Calculate text width and save longest line */
+    width = XTextWidth(text_info->fs, str, (int) strlen(str));
+    if (width > text_info->max_width)
+       text_info->max_width = width;
+}
+
+void
+display_text_window(wp, blocking)
+    struct xwindow *wp;
+    boolean blocking;
+{
+    struct text_info_t *text_info;
+    Arg args[8];
+    Cardinal num_args;
+    Dimension width, height, font_height;
+    int nlines;
+
+    text_info = wp->text_information;
+    width  = text_info->max_width + text_info->extra_width;
+    text_info->blocked = blocking;
+    text_info->destroy_on_ack = FALSE;
+    font_height = nhFontHeight(wp->w);
+
+    /*
+     * Calculate the number of lines to use.  First, find the number of
+     * lines that would fit on the screen.  Next, remove four of these
+     * lines to give room for a possible window manager titlebar (some
+     * wm's put a titlebar on transient windows).  Make sure we have
+     * _some_ lines.  Finally, use the number of lines in the text if
+     * there are fewer than the max.
+     */
+    nlines = (XtScreen(wp->w)->height - text_info->extra_height) / font_height;
+    nlines -= 4;
+
+    if (nlines > text_info->text.num_lines)
+       nlines = text_info->text.num_lines;
+    if (nlines <= 0) nlines = 1;
+
+    height = nlines * font_height + text_info->extra_height;
+
+    num_args = 0;
+
+    if (nlines < text_info->text.num_lines) {
+       /* add on width of scrollbar.  Really should look this up,
+        * but can't until the window is realized.  Chicken-and-egg problem.
+        */
+       width += 20;
+    }
+
+#ifdef GRAPHIC_TOMBSTONE
+    if (text_info->is_rip) {
+       Widget rip = create_ripout_widget(XtParent(wp->w));
+       XtSetArg(args[num_args], XtNfromVert, rip);     num_args++;
+    }
+#endif
+
+    if (width > (Dimension) XtScreen(wp->w)->width) { /* too wide for screen */
+       /* Back off some amount - we really need to back off the scrollbar */
+       /* width plus some extra.                                          */
+       width = XtScreen(wp->w)->width - 20;
+    }
+    XtSetArg(args[num_args], XtNstring, text_info->text.text); num_args++;
+    XtSetArg(args[num_args], XtNwidth,  width);                        num_args++;
+    XtSetArg(args[num_args], XtNheight, height);               num_args++;
+    XtSetValues(wp->w, args, num_args);
+
+#ifdef TRANSIENT_TEXT
+    XtRealizeWidget(wp->popup);
+    XSetWMProtocols(XtDisplay(wp->popup), XtWindow(wp->popup),
+                   &wm_delete_window, 1);
+    positionpopup(wp->popup, FALSE);
+#endif
+
+    nh_XtPopup(wp->popup, (int)XtGrabNone, wp->w);
+
+    /* Kludge alert.  Scrollbars are not sized correctly by the Text widget */
+    /* if added before the window is displayed, so do it afterward. */
+    num_args = 0;
+    if (nlines < text_info->text.num_lines) {  /* add vert scrollbar */
+       XtSetArg(args[num_args], XtNscrollVertical, XawtextScrollAlways);
+                                                               num_args++;
+    }
+    if (width >= (Dimension) (XtScreen(wp->w)->width-20)) {    /* too wide */
+       XtSetArg(args[num_args], XtNscrollHorizontal, XawtextScrollAlways);
+                                                               num_args++;
+    }
+    if (num_args) XtSetValues(wp->w, args, num_args);
+
+    /* We want the user to acknowlege. */
+    if (blocking) {
+       (void) x_event(EXIT_ON_EXIT);
+       nh_XtPopdown(wp->popup);
+    }
+}
+
+
+void
+create_text_window(wp)
+    struct xwindow *wp;
+{
+    struct text_info_t *text_info;
+    Arg args[8];
+    Cardinal num_args;
+    Position top_margin, bottom_margin, left_margin, right_margin;
+    Widget form;
+
+    wp->type = NHW_TEXT;
+
+    wp->text_information = text_info =
+                   (struct text_info_t *) alloc(sizeof(struct text_info_t));
+
+    init_text_buffer(&text_info->text);
+    text_info->max_width      = 0;
+    text_info->extra_width    = 0;
+    text_info->extra_height   = 0;
+    text_info->blocked       = FALSE;
+    text_info->destroy_on_ack = TRUE;  /* Ok to destroy before display */
+#ifdef GRAPHIC_TOMBSTONE
+    text_info->is_rip        = FALSE;
+#endif
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNallowShellResize, True); num_args++;
+    XtSetArg(args[num_args], XtNtranslations,
+               XtParseTranslationTable(text_translations));    num_args++;
+
+#ifdef TRANSIENT_TEXT
+    wp->popup = XtCreatePopupShell("text", transientShellWidgetClass,
+                                  toplevel, args, num_args);
+#else
+    wp->popup = XtCreatePopupShell("text", topLevelShellWidgetClass,
+                                  toplevel, args, num_args);
+#endif
+    XtOverrideTranslations(wp->popup,
+       XtParseTranslationTable("<Message>WM_PROTOCOLS: delete_text()"));
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNallowShellResize, True);       num_args++;
+    form = XtCreateManagedWidget("form", formWidgetClass, wp->popup,
+               args, num_args);
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNdisplayCaret, False);          num_args++;
+    XtSetArg(args[num_args], XtNresize, XawtextResizeBoth);    num_args++;
+    XtSetArg(args[num_args], XtNtranslations,
+               XtParseTranslationTable(text_translations));    num_args++;
+
+    wp->w = XtCreateManagedWidget(
+               killer && WIN_MAP == WIN_ERR ?
+                                 "tombstone" : "text_text", /* name */
+               asciiTextWidgetClass,
+               form,                   /* parent widget */
+               args,                   /* set some values */
+               num_args);              /* number of values to set */
+
+    /* Get the font and margin information. */
+    num_args = 0;
+    XtSetArg(args[num_args], XtNfont,        &text_info->fs); num_args++;
+    XtSetArg(args[num_args], XtNtopMargin,    &top_margin);    num_args++;
+    XtSetArg(args[num_args], XtNbottomMargin, &bottom_margin); num_args++;
+    XtSetArg(args[num_args], XtNleftMargin,   &left_margin);   num_args++;
+    XtSetArg(args[num_args], XtNrightMargin,  &right_margin);  num_args++;
+    XtGetValues(wp->w, args, num_args);
+
+    text_info->extra_width  = left_margin + right_margin;
+    text_info->extra_height = top_margin + bottom_margin;
+}
+
+void
+destroy_text_window(wp)
+    struct xwindow *wp;
+{
+    /* Don't need to pop down, this only called from dismiss_text(). */
+
+    struct text_info_t *text_info = wp->text_information;
+
+    /*
+     * If the text window was blocked, then the user has already ACK'ed
+     * it and we are free to really destroy the window.  Otherwise, don't
+     * destroy until the user dismisses the window via a key or button
+     * press.
+     */
+    if (text_info->blocked || text_info->destroy_on_ack) {
+       XtDestroyWidget(wp->popup);
+       free_text_buffer(&text_info->text);
+       free((genericptr_t)text_info),  wp->text_information = 0;
+       wp->type = NHW_NONE;    /* allow reuse */
+    } else {
+       text_info->destroy_on_ack = TRUE;       /* destroy on next ACK */
+    }
+}
+
+void
+clear_text_window(wp)
+    struct xwindow *wp;
+{
+    clear_text_buffer(&wp->text_information->text);
+}
+
+
+/* text buffer routines ---------------------------------------------------- */
+
+/* Append a line to the text buffer. */
+void
+append_text_buffer(tb, str, concat)
+    struct text_buffer *tb;
+    const char *str;
+    boolean concat;
+{
+    char *copy;
+    int length;
+
+    if (!tb->text) panic("append_text_buffer:  null text buffer");
+
+    if (str) {
+       length = strlen(str);
+    } else {
+       length = 0;
+    }
+
+    if (length + tb->text_last + 1 >= tb->text_size) {
+       /* we need to go to a bigger buffer! */
+#ifdef VERBOSE
+       printf("append_text_buffer: text buffer growing from %d to %d bytes\n",
+                               tb->text_size, 2*tb->text_size);
+#endif
+       copy = (char *) alloc((unsigned)tb->text_size*2);
+       (void) memcpy(copy, tb->text, tb->text_last);
+       free(tb->text);
+       tb->text = copy;
+       tb->text_size *= 2;
+    }
+
+    if (tb->num_lines) {       /* not first --- append a newline */
+       char appchar = '\n';
+
+       if(concat && !index("!.?'\")", tb->text[tb->text_last-1])) {
+           appchar = ' ';
+           tb->num_lines--; /* offset increment at end of function */
+       }
+
+       *(tb->text + tb->text_last) = appchar;
+       tb->text_last++;
+    }
+
+    if (str) {
+       (void) memcpy((tb->text+tb->text_last), str, length+1);
+       if(length) {
+           /* Remove all newlines. Otherwise we have a confused line count. */
+           copy = (tb->text+tb->text_last);
+           while ((copy = index(copy, '\n')) != (char*)0)
+               *copy = ' ';
+       }
+
+       tb->text_last += length;
+    }
+    tb->text[tb->text_last] = '\0';
+    tb->num_lines++;
+}
+
+/* Initialize text buffer. */
+void
+init_text_buffer(tb)
+    struct text_buffer *tb;
+{
+    tb->text     = (char *) alloc(START_SIZE);
+    tb->text[0]   = '\0';
+    tb->text_size = START_SIZE;
+    tb->text_last = 0;
+    tb->num_lines = 0;
+}
+
+/* Empty the text buffer */
+void
+clear_text_buffer(tb)
+    struct text_buffer *tb;
+{
+    tb->text_last = 0;
+    tb->text[0]   = '\0';
+    tb->num_lines = 0;
+}
+
+/* Free up allocated memory. */
+void
+free_text_buffer(tb)
+    struct text_buffer *tb;
+{
+    free(tb->text);
+    tb->text = (char *) 0;
+    tb->text_size = 0;
+    tb->text_last = 0;
+    tb->num_lines = 0;
+}
+
+
+#ifdef GRAPHIC_TOMBSTONE
+
+static void FDECL(rip_exposed, (Widget,XtPointer,XtPointer));
+
+static XImage* rip_image=0;
+
+
+#define STONE_LINE_LEN 16      /* # chars that fit on one line */
+#define NAME_LINE 0            /* line # for player name */
+#define GOLD_LINE 1            /* line # for amount of gold */
+#define DEATH_LINE 2           /* line # for death description */
+#define YEAR_LINE 6            /* line # for year */
+
+static char rip_line[YEAR_LINE+1][STONE_LINE_LEN+1];
+
+extern const char *killed_by_prefix[];
+
+void
+calculate_rip_text(int how)
+{
+       /* Follows same algorithm as genl_outrip() */
+
+       char buf[BUFSZ];
+       char *dpx;
+       int line;
+
+       /* Put name on stone */
+       Sprintf(rip_line[NAME_LINE], "%s", plname);
+
+       /* Put $ on stone */
+       Sprintf(rip_line[GOLD_LINE], "%ld Au",
+#ifndef GOLDOBJ
+               u.ugold);
+#else
+               money_cnt(invent));
+#endif
+       /* Put together death description */
+       switch (killer_format) {
+               default: impossible("bad killer format?");
+               case KILLED_BY_AN:
+                       Strcpy(buf, killed_by_prefix[how]);
+                       Strcat(buf, an(killer));
+                       break;
+               case KILLED_BY:
+                       Strcpy(buf, killed_by_prefix[how]);
+                       Strcat(buf, killer);
+                       break;
+               case NO_KILLER_PREFIX:
+                       Strcpy(buf, killer);
+                       break;
+       }
+
+       /* Put death type on stone */
+       for (line=DEATH_LINE, dpx = buf; line<YEAR_LINE; line++) {
+               register int i,i0;
+               char tmpchar;
+
+               if ( (i0=strlen(dpx)) > STONE_LINE_LEN) {
+                       for(i = STONE_LINE_LEN;
+                           ((i0 > STONE_LINE_LEN) && i); i--)
+                               if(dpx[i] == ' ') i0 = i;
+                       if(!i) i0 = STONE_LINE_LEN;
+               }
+               tmpchar = dpx[i0];
+               dpx[i0] = 0;
+               strcpy(rip_line[line], dpx);
+               if (tmpchar != ' ') {
+                       dpx[i0] = tmpchar;
+                       dpx= &dpx[i0];
+               } else  dpx= &dpx[i0+1];
+       }
+
+       /* Put year on stone */
+       Sprintf(rip_line[YEAR_LINE], "%4d", getyear());
+}
+
+
+/*
+ * RIP image expose callback.
+ */
+/*ARGSUSED*/
+static void
+rip_exposed(w, client_data, widget_data)
+    Widget w;
+    XtPointer client_data;     /* unused */
+    XtPointer widget_data;     /* expose event from Window widget */
+{
+    XExposeEvent *event = (XExposeEvent *) widget_data;
+    Display* dpy=XtDisplay(w);
+    Arg args[8];
+    XGCValues values;
+    XtGCMask mask;
+    GC gc;
+    static Pixmap rip_pixmap=None;
+    int i, x, y;
+
+    if (!XtIsRealized(w) || event->count > 0) return;
+
+    if (rip_pixmap == None && rip_image) {
+       rip_pixmap = XCreatePixmap(dpy, XtWindow(w),
+                       rip_image->width,
+                       rip_image->height,
+                       DefaultDepth(dpy, DefaultScreen(dpy)));
+       XPutImage(dpy, rip_pixmap,
+               DefaultGC(dpy, DefaultScreen(dpy)),
+               rip_image,
+               0,0, 0,0,               /* src, dest top left */
+               rip_image->width,
+               rip_image->height);
+       XDestroyImage(rip_image);       /* data bytes free'd also */
+    }
+
+    mask = GCFunction | GCForeground | GCGraphicsExposures | GCFont;
+    values.graphics_exposures = False;
+    XtSetArg(args[0], XtNforeground, &values.foreground);
+    XtGetValues(w, args, 1);
+    values.function = GXcopy;
+    values.font = WindowFont(w);
+    gc = XtGetGC(w, mask, &values);
+
+    if (rip_pixmap != None) {
+       XCopyArea(dpy, rip_pixmap, XtWindow(w), gc,
+               event->x, event->y, event->width, event->height,
+               event->x, event->y);
+    }
+
+    x=appResources.tombtext_x;
+    y=appResources.tombtext_y;
+    for (i=0; i<=YEAR_LINE; i++) {
+       int len=strlen(rip_line[i]);
+       XFontStruct* font=WindowFontStruct(w);
+       int width=XTextWidth(font, rip_line[i], len);
+       XDrawString(dpy, XtWindow(w), gc,
+               x-width/2, y, rip_line[i], len);
+       x+=appResources.tombtext_dx;
+       y+=appResources.tombtext_dy;
+    }
+
+    XtReleaseGC(w, gc);
+}
+
+/*
+ * The ripout window creation routine.
+ */
+static Widget
+create_ripout_widget(Widget parent)
+{
+    Widget imageport;
+    Arg args[16];
+    Cardinal num_args;
+
+    static int rip_width, rip_height;
+
+    if (!rip_image) {
+       XpmAttributes attributes;
+       int errorcode;
+
+       attributes.valuemask = XpmCloseness;
+       attributes.closeness = 65535; /* Try anything */
+       errorcode = XpmReadFileToImage(XtDisplay(parent), appResources.tombstone, &rip_image, 0, &attributes);
+       if (errorcode != XpmSuccess) {
+           char buf[BUFSZ];
+           Sprintf(buf, "Failed to load %s: %s", appResources.tombstone,
+                       XpmGetErrorString(errorcode));
+           X11_raw_print(buf);
+       }
+       rip_width = rip_image->width;
+       rip_height = rip_image->height;
+    }
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNwidth, rip_width); num_args++;
+    XtSetArg(args[num_args], XtNheight, rip_height); num_args++;
+    XtSetArg(args[num_args], XtNtranslations,
+               XtParseTranslationTable(rip_translations));     num_args++;
+
+    imageport = XtCreateManagedWidget("rip", windowWidgetClass,
+               parent, args, num_args);
+
+    XtAddCallback(imageport, XtNexposeCallback, rip_exposed, (XtPointer) 0);
+
+    return imageport;
+}
+
+#endif /* GRAPHIC_TOMBSTONE */
+
+/*wintext.c*/