home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / xsokoban-31 / scoredisp.c < prev    next >
C/C++ Source or Header  |  1997-06-13  |  16KB  |  521 lines

  1.  
  2. #ifndef VMS
  3. #include <X11/X.h>
  4. #include <X11/Xlib.h>
  5. #include <X11/Xresource.h>
  6. /* #include <string> */
  7. #endif
  8.  
  9. #include <assert.h>
  10. #include <string.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13.  
  14. #include "externs.h"
  15. #include "globals.h"
  16. #include "defaults.h"
  17.  
  18. #ifndef EXIT_FAILURE
  19. #define EXIT_FAILURE -1
  20. #endif
  21.  
  22. static Boolean initted = _false_;
  23. static unsigned long sb_bg, panel_bg[3], border_color, panel_fg, 
  24.   text_color, text_highlight, thumb_colors[3], separation_color;
  25. static unsigned int sb_width, panel_height, border_width, bevel_width,
  26.   text_indent;
  27. static unsigned int thumb_height, thumb_width;
  28. static unsigned int bevel_darkening;
  29. static unsigned long white;
  30. static XWindowAttributes wa;
  31. static GC gc, scroll_gc;
  32. static XFontStruct *finfo, *score_finfo;
  33.  
  34. static u_short rank[MAXSCOREENTRIES];
  35.  
  36. #if !defined(STRDUP_PROTO)
  37. char *strdup(const char *s)
  38. {
  39.     int l = strlen(s);
  40.     char *ret = (char *)malloc((size_t)(l + 1));
  41.     strcpy(ret, s);
  42.     return ret;
  43. }
  44. #endif
  45.  
  46. unsigned int GetIntResource(char *resource_name, unsigned int def)
  47. {
  48.     char *ret;
  49.     ret = GetResource(resource_name);
  50.     if (!ret) return def;
  51.     return atoi(ret);
  52. }
  53.  
  54. u_short darken(u_short x)
  55. {
  56.     return (u_short)((u_int)x * (0xFFFF - bevel_darkening)/0xFFFF);
  57. }
  58.  
  59. u_short lighten(u_short x)
  60. {
  61.     return x + bevel_darkening - (u_short)(bevel_darkening * (u_int)x/0xFFFF);
  62. }
  63.  
  64. /* Return 0 on success, an error message on error.
  65.    shades[0] contains the requested color, shades[1] contains
  66.    a darker version of the same color, shades[2] contains a
  67.    lighter version. For use in drawing Motif-oid beveled panels.
  68. */
  69. char *GetColorShades(Display *dpy, 
  70.              XWindowAttributes *wa,
  71.              char *resource_name,
  72.              char *default_name_8,
  73.              Boolean default_white_2,
  74.              unsigned long shades[])
  75. {
  76.     char *rval = GetResource(resource_name);
  77.     char buf[500];
  78.     XColor normal, light, dark;
  79.     if (!rval) {
  80.     if (wa->depth >= 8) rval = default_name_8;
  81.     else rval = default_white_2 ? "white" : "black";
  82.     }
  83.     if (!XParseColor(dpy, wa->colormap, rval, &normal)) {
  84.     sprintf(buf, "Cannot parse color name for resource %s: %s",
  85.         resource_name, rval);
  86.     return strdup(buf);
  87.     }
  88.     dark.red = darken(normal.red);
  89.     dark.green = darken(normal.green);
  90.     dark.blue = darken(normal.blue);
  91.     light.red = lighten(normal.red);
  92.     light.green = lighten(normal.green);
  93.     light.blue = lighten(normal.blue);
  94.     if (!XAllocColor(dpy, wa->colormap, &normal) ||
  95.     !XAllocColor(dpy, wa->colormap, &light) ||
  96.     !XAllocColor(dpy, wa->colormap, &dark)) {
  97.     sprintf(buf, "Cannot allocate color shades for resource %s: %s",
  98.         resource_name, rval);
  99.     return strdup(buf);
  100.     }
  101.     shades[0] = normal.pixel;
  102.     shades[1] = dark.pixel;
  103.     shades[2] = light.pixel;
  104.     return 0;
  105. }
  106.  
  107. unsigned long GetColorOrDefault(Display *dpy,
  108.                 XWindowAttributes *wa,
  109.                 char *resource_name,
  110.                 char *default_name_8,
  111.                 Boolean default_white_2)
  112. {
  113.     XColor c;
  114.     unsigned long pixel;
  115.     if (GetColorResource(resource_name, &pixel)) {
  116.     return pixel;
  117.     } else {
  118.     char *val;
  119.     if (wa->depth >= 8)
  120.       val = default_name_8;
  121.     else
  122.       val = default_white_2 ? "white" : "black";
  123.     if (XParseColor(dpy, wa->colormap, default_name_8, &c) &&
  124.         XAllocColor(dpy, wa->colormap, &c))
  125.       return c.pixel;
  126.     fprintf(stderr, "Cannot obtain color for %s\n", resource_name);
  127.     exit(EXIT_FAILURE);
  128.     }
  129. }
  130.  
  131. /* Return 0 on success, else return an error message. */
  132. char *InitDisplayScores(Display *dpy, Window win)
  133. {
  134.     Status status = XGetWindowAttributes(dpy, win, &wa);
  135.     XGCValues gc_values;
  136.     u_long value_mask;
  137.     assert(status);
  138.     bevel_darkening = GetIntResource("bevel.darkening", 16000);
  139.     sb_bg = GetColorOrDefault(dpy, &wa,
  140.                   "scrollbar.background", "gray", _true_);
  141.     GetColorShades(dpy, &wa,
  142.            "panel.background", "beige", _true_,
  143.            panel_bg);
  144.            
  145.     panel_fg = GetColorOrDefault(dpy, &wa,
  146.                  "panel.foreground", "black", _true_);
  147.     border_color = GetColorOrDefault(dpy, &wa,
  148.                      "border.color", "black", _false_);
  149.     text_color = GetColorOrDefault(dpy, &wa,
  150.                      "text.color", "black", _false_);
  151.     text_highlight = GetColorOrDefault(dpy, &wa,
  152.                        "text.highlight", "red3", _true_);
  153.                      
  154.     text_indent = GetIntResource("text.indent", 3);
  155.     white = GetColorOrDefault(dpy, &wa, "highlight.color", "white", _true_);
  156.     border_width = GetIntResource("border.width", 1);
  157.     sb_width = GetIntResource("scrollbar.width", 25);
  158.     panel_height = GetIntResource("panel.height", 25);
  159.     bevel_width = GetIntResource("bevel.width", 3);
  160.     thumb_height = GetIntResource("scrollbar.thumb.height", sb_width);
  161.     thumb_width = GetIntResource("scrollbar.thumb.width", sb_width);
  162.     separation_color = GetColorOrDefault(dpy, &wa, "sep.color", "gray",
  163.                      _false_);
  164.     GetColorShades(dpy, &wa, "scrollbar.thumb.color", "gray", _true_,
  165.            thumb_colors);
  166.     finfo = GetFontResource("panel.font");
  167.     score_finfo = GetFontResource("text.font");
  168.     if (!score_finfo || !finfo) {
  169.     return "Either cannot get font for panel or for text";
  170.     }
  171.  
  172.     gc_values.function = GXcopy;
  173.     gc_values.foreground = panel_fg;
  174.     gc_values.background = panel_bg[0];
  175.     gc_values.line_width = 1;
  176.     gc_values.font = finfo->fid;
  177.     value_mask = GCForeground | GCBackground | GCFunction | GCFont |
  178.       GCLineWidth;
  179.       
  180.     gc = XCreateGC(dpy, win, value_mask, &gc_values);
  181.     initted = _true_;
  182.     return 0;
  183. }
  184.  
  185. static void DrawPanel(XWindowAttributes *wa, Window panel);
  186. static void DrawScores(XWindowAttributes *wa, Window win);
  187. static void DrawThumb(Window thumb);
  188.  
  189. static int font_height;
  190. static int vmax, vposn;
  191. static int win_height;
  192. static int thumb_range;
  193. static int yclip;
  194.     
  195. static void ComputeRanks()
  196. {
  197.     int i;
  198.     for (i = 0; i < scoreentries; i++) {
  199.     rank[i] = SolnRank(i, 0);
  200.     }
  201. }
  202.  
  203. static int FindCurrent()
  204. {
  205.     int i;
  206.     for (i = 0; i < scoreentries; i++) {
  207.      if (0 == strcmp(scoretable[i].user, username) &&
  208.          (unsigned short)level == scoretable[i].lv) {
  209.          return i;
  210.      }
  211.     }
  212.     for (i = 0; i < scoreentries; i++)
  213.      if ((unsigned short)level > scoretable[i].lv) return i;
  214.     return scoreentries - 1; /* Couldn't find it at all */
  215. }
  216.  
  217. /* Make "vposn" an allowable position. */
  218. static void TrimPosn()
  219. {
  220.     if (vposn >= vmax)
  221.       vposn = vmax - 1;
  222.     if (vposn < 0) vposn = 0; /* must do this after prev stmt */
  223. }
  224.  
  225. static void PositionThumb(Window thumb)
  226. {
  227.     int x = (thumb_width - sb_width)/2 - 1;
  228.     int y = (int)((float)vposn/vmax * (float)thumb_range);
  229.     if (x < 0) x = 0;
  230.     if (y < 0) y = 0;
  231.     if (y > thumb_range) y = thumb_range;
  232.     XMoveWindow(dpy, thumb, x - 1, y - 1);
  233.     /* subtract 1 to fudge thumb into place */
  234. }
  235.  
  236. /* Display scores. Return E_ENDGAME if user wanted to quit from here. */
  237. short DisplayScores_(Display *dpy, Window win)
  238. {
  239.     Status status;
  240.     XEvent xev;
  241.     Window scrollbar, panel, thumb;
  242.     short ret = 0;
  243.     Boolean dragging = _false_;
  244.     Boolean scores_dirty = _false_;
  245.  
  246.     if (!initted) {
  247.     char *msg = InitDisplayScores(dpy, win);
  248.     if (msg) {
  249.         fprintf(stderr, msg);
  250.         exit(EXIT_FAILURE);
  251.     }
  252.     }
  253.     ComputeRanks();
  254.     status = XGetWindowAttributes(dpy, win, &wa); assert(status);
  255.     scrollbar = XCreateSimpleWindow(dpy, win,
  256.                     wa.width - sb_width, 0,
  257.                     sb_width, wa.height - panel_height,
  258.                     border_width, border_color, sb_bg);
  259.     panel = XCreateSimpleWindow(dpy, win,
  260.                 0, wa.height - panel_height,
  261.                 wa.width, panel_height,
  262.                 0, 0, panel_bg[0]);
  263.     XSelectInput(dpy, scrollbar, ExposureMask | KeyPressMask
  264.         | ButtonPressMask | ButtonReleaseMask | PointerMotionMask);
  265.     XSelectInput(dpy, panel, ExposureMask | KeyPressMask);
  266.     XClearWindow(dpy, win);
  267.  
  268.     font_height = score_finfo->max_bounds.ascent +
  269.       score_finfo->max_bounds.descent;
  270.     win_height = wa.height - panel_height - yclip;
  271.     thumb_range = wa.height - panel_height - thumb_height;
  272.     vmax = font_height * (scoreentries + 2) - win_height;
  273.     vposn = (int)(FindCurrent() * font_height) -
  274.           (int)(win_height/2);
  275.     yclip = font_height * 3/2;
  276.     /* coerce to int to make sure we do this in signed arithmetic */
  277.     TrimPosn();
  278.     thumb = XCreateSimpleWindow(dpy, scrollbar,
  279.                 0, 0,
  280.                 thumb_width, thumb_height,
  281.                 border_width, border_color, thumb_colors[0]);
  282.     PositionThumb(thumb);
  283.     XSelectInput(dpy, thumb, ExposureMask);
  284.  
  285.     XMapRaised(dpy, scrollbar);
  286.     XMapRaised(dpy, panel);
  287.     XMapRaised(dpy, thumb);
  288.     {
  289.     XRectangle rectangles[1];
  290.     scroll_gc = XCreateGC(dpy, win, 0, 0);
  291.     XCopyGC(dpy, gc, GCForeground | GCBackground | GCFunction |
  292.         GCFont | GCLineWidth, scroll_gc);
  293.     rectangles[0].x = 0;
  294.     rectangles[0].y = yclip;
  295.     rectangles[0].width = wa.width - sb_width;
  296.     rectangles[0].height = wa.height - panel_height - yclip;
  297.     XSetClipRectangles(dpy, scroll_gc, 0, 0, &rectangles[0], 1, Unsorted);
  298.     XSetFont(dpy, scroll_gc, score_finfo->fid);
  299.     }
  300.     
  301.  
  302.     DrawScores(&wa, win);
  303.       
  304.     for (;;) {
  305.     if (scores_dirty) {
  306.         if (0 == XPending(dpy)) {
  307.         scores_dirty = _false_;
  308.         PositionThumb(thumb);
  309.         XClearWindow(dpy, win);
  310.         DrawScores(&wa, win);
  311.         XSync(dpy, False); /* make sure we don't get ahead */
  312.         }
  313.     }
  314.     XNextEvent(dpy, &xev);
  315.     switch(xev.type) {
  316.       default:
  317.         fprintf(stderr,
  318.         "Warning: unexpected X event type %d seen\n", xev.type);
  319.         break;
  320.       case ClientMessage:
  321.         {
  322.         XClientMessageEvent *cm = (XClientMessageEvent *)&xev;
  323.         if (cm->message_type == wm_protocols &&
  324.             cm->data.l[0] == wm_delete_window) {
  325.               ret = E_ENDGAME;
  326.               goto done;
  327.             }
  328.             
  329.         }
  330.       case NoExpose:
  331.         break;
  332.       case Expose: {
  333.         XExposeEvent *expose = &xev.xexpose;
  334.         Window w = expose->window;
  335.         if (expose->count != 0) break;
  336.         if (w == win) {
  337.             DrawScores(&wa, win);
  338.         } else
  339.         if (w == scrollbar) {
  340.         } else
  341.         if (w == thumb) {
  342.             DrawThumb(thumb);
  343.         }
  344.             if (w == panel) {
  345.             DrawPanel(&wa, panel);
  346.         }
  347.         XFlush(dpy);
  348.         }
  349.         
  350.         break;
  351.         case KeyPress: {
  352.         char buf[1];
  353.         int buflen = 1;
  354.         KeySym sym;
  355.         XComposeStatus compose;
  356.         buf[0] = 0;
  357.         (void)XLookupString(&xev.xkey, &buf[0], buflen,
  358.                           &sym, &compose);
  359.         assert(status);
  360.         switch(sym) {
  361.           case XK_Return:
  362.             goto done;
  363.           case XK_q:
  364.             ret = E_ENDGAME;
  365.             goto done;
  366.           default:
  367.             if (buf[0]) XBell(dpy, 0);
  368.             break;
  369.         }
  370.         
  371.         }
  372.         break;
  373.       case ButtonPress:
  374.         if (xev.xbutton.window == scrollbar) {
  375.         dragging = _true_;
  376.         }
  377.         break;
  378.       case ButtonRelease:
  379.         dragging = _false_;
  380.         break;
  381.       case MotionNotify:
  382.         {
  383.         int old_vposn = vposn;
  384.         int y = xev.xbutton.y;
  385.         if (dragging) {
  386.             vposn = (float)(y - (int)thumb_height/2)/
  387.               thumb_range * vmax;
  388.             TrimPosn();
  389.             if (old_vposn != vposn) {
  390.             scores_dirty = _true_;
  391.             }
  392.         }
  393.         XFlush(dpy);
  394.         }
  395.         break;
  396.     }
  397.     }
  398.   done:
  399.     XDestroySubwindows(dpy, win);
  400.     XFreeGC(dpy, scroll_gc);
  401.     return ret;
  402. }
  403.  
  404. static void DrawScores(XWindowAttributes *wa, Window win)
  405. {
  406.     int first_index = vposn/font_height;
  407.     int last_index = (vposn + win_height - 1)/font_height;
  408.     int i;
  409.     char * header = "Rank      User           Level     Moves    Pushes";
  410.     XSetForeground(dpy, gc, text_color);
  411.     XDrawString(dpy, win, gc, text_indent, font_height, header,
  412.         strlen(header));
  413.     XDrawLine(dpy, win, gc, 0, yclip-1, wa->width - sb_width,
  414.           yclip-1);
  415.     
  416.     for (i = first_index; i <= last_index && i < scoreentries; i++) {
  417.     char buf[500];
  418.     int y = yclip + i * font_height - vposn + font_height;
  419.     if (i < last_index &&
  420.         scoretable[i + 1].lv != scoretable[i].lv) {
  421.         XSetForeground(dpy, scroll_gc, separation_color);
  422.         XDrawLine(dpy, win, scroll_gc, 0, y + 2, wa->width, y + 2);
  423.     }
  424.     if (0 == strcmp(scoretable[i].user, username)) {
  425.         XSetForeground(dpy, scroll_gc, text_highlight);
  426.     } else {
  427.         XSetForeground(dpy, scroll_gc, text_color);
  428.     }
  429.     if (rank[i] <= MAXSOLNRANK)
  430.         sprintf(buf, "%4d", rank[i]);
  431.     else
  432.         sprintf(buf, "    ");
  433.     sprintf(buf + 4, " %15s  %8d  %8d  %8d", scoretable[i].user,
  434.         scoretable[i].lv, scoretable[i].mv, scoretable[i].ps);
  435.     XDrawString(dpy, win, scroll_gc, text_indent, y, buf, strlen(buf));
  436.     }
  437. }
  438.  
  439. static void DrawPanel(XWindowAttributes *wa, Window panel)
  440. {
  441.     char *msg = "Press <Return> to continue, \"q\" to quit";
  442.     XSetForeground(dpy, gc, panel_bg[2]);
  443.     XFillRectangle(dpy, panel, gc,
  444.            0, 0, wa->width - bevel_width, bevel_width);
  445.     XFillRectangle(dpy, panel, gc,
  446.            0, 0, bevel_width, panel_height - bevel_width);
  447.     XSetForeground(dpy, gc, panel_bg[1]);
  448.     {
  449.     XPoint triangle[3];
  450.     triangle[0].x = wa->width;
  451.     triangle[0].y = bevel_width;
  452.     triangle[1].x = wa->width;
  453.     triangle[1].y = 0;
  454.     triangle[2].x = wa->width - bevel_width;
  455.     triangle[2].y = bevel_width;
  456.     XFillPolygon(dpy, panel, gc,
  457.              &triangle[0], 3, Convex, CoordModeOrigin);
  458.     triangle[0].x = bevel_width;
  459.     triangle[0].y = panel_height - bevel_width;
  460.     triangle[1].x = triangle[0].x;
  461.     triangle[1].y = panel_height;
  462.     triangle[2].x = 0;
  463.     triangle[2].y = panel_height;
  464.     XFillPolygon(dpy, panel, gc,
  465.              &triangle[0], 3, Convex, CoordModeOrigin);
  466.     }
  467.     XFillRectangle(dpy, panel, gc,
  468.            bevel_width, panel_height - bevel_width,
  469.            wa->width - bevel_width, bevel_width);
  470.     XFillRectangle(dpy, panel, gc,
  471.            wa->width - bevel_width, bevel_width,
  472.            bevel_width, panel_height - bevel_width);
  473.     XSetForeground(dpy, gc, white);
  474.     XDrawLine(dpy, panel, gc, 0, 0, bevel_width,
  475.           bevel_width);
  476.     XSetForeground(dpy, gc, border_color);
  477.     XDrawLine(dpy, panel, gc, 0, 0,
  478.           wa->width, 0);
  479.     XSetForeground(dpy, gc, text_color);
  480.     XDrawString(dpy, panel, gc, text_indent, panel_height -
  481.         2 * bevel_width, msg, strlen(msg));
  482. }
  483.     
  484. static void DrawThumb(Window thumb)
  485. {
  486.     int wm1 = thumb_width - 1;
  487.     XSetForeground(dpy, gc, thumb_colors[2]);
  488.     XFillRectangle(dpy, thumb, gc,
  489.            0, 0, wm1 - bevel_width, bevel_width);
  490.     XFillRectangle(dpy, thumb, gc,
  491.            0, 0, bevel_width, thumb_height - bevel_width);
  492.     XSetForeground(dpy, gc, thumb_colors[1]);
  493.     {
  494.     XPoint triangle[3];
  495.     triangle[0].x = wm1;
  496.     triangle[0].y = bevel_width;
  497.     triangle[1].x = wm1;
  498.     triangle[1].y = 0;
  499.     triangle[2].x = wm1 - bevel_width;
  500.     triangle[2].y = bevel_width;
  501.     XFillPolygon(dpy, thumb, gc,
  502.              &triangle[0], 3, Convex, CoordModeOrigin);
  503.     triangle[0].x = bevel_width;
  504.     triangle[0].y = thumb_height - bevel_width;
  505.     triangle[1].x = triangle[0].x;
  506.     triangle[1].y = thumb_height;
  507.     triangle[2].x = 0;
  508.     triangle[2].y = thumb_height;
  509.     XFillPolygon(dpy, thumb, gc,
  510.              &triangle[0], 3, Convex, CoordModeOrigin);
  511.     }
  512.     XFillRectangle(dpy, thumb, gc,
  513.            bevel_width, thumb_height - bevel_width,
  514.            wm1 - bevel_width, bevel_width);
  515.     XFillRectangle(dpy, thumb, gc,
  516.            wm1 - bevel_width, bevel_width,
  517.            bevel_width, thumb_height - bevel_width);
  518.     XSetForeground(dpy, gc, white);
  519.     XDrawLine(dpy, thumb, gc, 0, 0, bevel_width, bevel_width);
  520. }
  521. c