home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1999 mARCH / PCWK3A99.iso / Linux / DDD331 / DDD-3_1_.000 / DDD-3_1_ / ddd-3.1.1 / ddd / PlotArea.C < prev    next >
C/C++ Source or Header  |  1998-11-17  |  14KB  |  629 lines

  1. // $Id: PlotArea.C,v 1.8 1998/11/17 12:24:31 zeller Exp $ -*- C++ -*-
  2. // An area to plot upon
  3.  
  4. // Copyright (C) 1998 Technische Universitaet Braunschweig, Germany.
  5. // Written by Andreas Zeller <zeller@ips.cs.tu-bs.de>.
  6. // 
  7. // This file is part of DDD.
  8. // 
  9. // DDD is free software; you can redistribute it and/or
  10. // modify it under the terms of the GNU General Public
  11. // License as published by the Free Software Foundation; either
  12. // version 2 of the License, or (at your option) any later version.
  13. // 
  14. // DDD is distributed in the hope that it will be useful,
  15. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  17. // See the GNU General Public License for more details.
  18. // 
  19. // You should have received a copy of the GNU General Public
  20. // License along with DDD -- see the file COPYING.
  21. // If not, write to the Free Software Foundation, Inc.,
  22. // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23. // 
  24. // DDD is the data display debugger.
  25. // For details, see the DDD World-Wide-Web page, 
  26. // `http://www.cs.tu-bs.de/softech/ddd/',
  27. // or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
  28.  
  29. // Most of this code is based on `gplt_x11.c' from Gnuplot.
  30. //
  31. // Acknowledgements: 
  32. //    Chris Peterson (MIT)
  33. //    Dana Chee (Bellcore) 
  34. //    Arthur Smith (Cornell)
  35. //    Hendri Hondorp (University of Twente, The Netherlands)
  36. //    Bill Kucharski (Solbourne)
  37. //    Charlie Kline (University of Illinois)
  38. //    Yehavi Bourvine (Hebrew University of Jerusalem, Israel)
  39. //    Russell Lang (Monash University, Australia)
  40. //    O'Reilly & Associates: X Window System - Volumes 1 & 2
  41. //
  42. // This code is provided as is and with no warranties of any kind.
  43.  
  44. char PlotArea_rcsid[] = 
  45.     "$Id: PlotArea.C,v 1.8 1998/11/17 12:24:31 zeller Exp $";
  46.  
  47. #ifdef __GNUG__
  48. #pragma implementation
  49. #endif
  50.  
  51. #include "PlotArea.h"
  52.  
  53. #include "cook.h"
  54.  
  55. #include <stdio.h>
  56. #include <stdlib.h>
  57. #include <ctype.h>
  58.  
  59. #include <X11/StringDefs.h>
  60. #include <X11/Xlib.h>
  61. #include <Xm/DrawingA.h>
  62.  
  63. // Data
  64. struct plot_resource_values {
  65.     String font;
  66.     int pointsize;
  67. };
  68.  
  69. static XtResource plot_subresources[] = {
  70.     {
  71.     "font",
  72.     "Font",
  73.     XtRString,
  74.     sizeof(String),
  75.     XtOffsetOf(plot_resource_values, font),
  76.     XtRImmediate,
  77.     XtPointer("fixed")
  78.     },
  79.     {
  80.     "pointsize",
  81.     "Pointsize",
  82.     XtRInt,
  83.     sizeof(int),
  84.     XtOffsetOf(plot_resource_values, pointsize),
  85.     XtRImmediate,
  86.     XtPointer(1)
  87.     }
  88. };
  89.  
  90.  
  91. #if 0
  92. static char color_keys[Ncolors][30] =   { 
  93.    "background", "bordercolor", "text", "border", "axis", 
  94.    "line1", "line2", "line3",  "line4", 
  95.    "line5", "line6", "line7",  "line8" 
  96.    };
  97. #endif
  98.  
  99. static char color_values[Ncolors][30] = { 
  100.     "white", "black",  "black",  "black",  "black", 
  101.     "red",   "green",  "blue",   "magenta", 
  102.     "cyan",  "sienna", "orange", "coral" 
  103. };
  104.  
  105. static char gray_values[Ncolors][30] = { 
  106.     "black",   "white",  "white",  "gray50", "gray50",
  107.     "gray100", "gray60", "gray80", "gray40", 
  108.     "gray90",  "gray50", "gray70", "gray30" 
  109. };
  110.  
  111. #if 0
  112. char dash_keys[Ndashes][10] =   { 
  113.    "border", "axis",
  114.    "line1", "line2", "line3",  "line4", "line5", "line6", "line7",  "line8" 
  115. };
  116. #endif
  117.  
  118. static char dash_mono[Ndashes][10] =   { 
  119.    "0", "16",
  120.    "0", "42", "13",  "44", "15", "4441", "42",  "13" 
  121. };
  122.  
  123. static char dash_color[Ndashes][10] =   { 
  124.    "0", "16",
  125.    "0", "0", "0", "0", "0", "0", "0", "0" 
  126. };
  127.  
  128. // Initialize
  129. PlotArea::PlotArea(Widget w, const string& fontname)
  130.     : area(w), dpy(XtDisplay(w)), win(XtWindow(w)),
  131.       cx(0), cy(0), px(1), py(1), xscale(0.0), yscale(0.0),
  132.       gc(0), font(0), vchar(0), jmode(0), line_type(0), width(0),
  133.       type(LineSolid), pointsize(1), pending_plots(0), last_commands()
  134. {
  135.     plot_resource_values values;
  136.     XtGetApplicationResources(area, &values,
  137.                   plot_subresources, XtNumber(plot_subresources),
  138.                   NULL, 0);
  139.  
  140.     // Init font
  141.     font = XLoadQueryFont(dpy, fontname);
  142.     if (font == 0)
  143.     font = XLoadQueryFont(dpy, values.font);
  144.     if (font == 0)
  145.     font = XLoadQueryFont(dpy, "fixed");
  146.     if (font == 0)
  147.     {
  148.     cerr << "Cannot load font\n";
  149.     exit(1);
  150.     }
  151.     
  152.     vchar = font->ascent + font->descent;
  153.  
  154.     // Init point size
  155.     pointsize = values.pointsize;
  156.     if (pointsize <= 0 || pointsize > 10) 
  157.     {
  158.     cerr << "Invalid point size " << pointsize << "\n";
  159.     pointsize = 1;
  160.     }
  161.  
  162.     // Init colors
  163.     Pixel black = BlackPixelOfScreen(XtScreen(area));
  164.     Pixel white = WhitePixelOfScreen(XtScreen(area));
  165.     int depth;
  166.     XtVaGetValues(area, XmNdepth, &depth, NULL);
  167.     if (depth <= 1)
  168.     {
  169.     // Monochrome
  170.     colors[0] = white;
  171.     for (int i = 1; i < Ncolors; i++)
  172.         colors[i] = black;
  173.     }
  174.     else
  175.     {
  176.     // Multi-color or gray
  177.     Visual *vis = DefaultVisualOfScreen(XtScreen(area));
  178.     bool gray = (vis->c_class == StaticGray || vis->c_class == GrayScale);
  179.     Colormap cmap;
  180.     XtVaGetValues(area, XmNcolormap, &cmap, NULL);
  181.  
  182.     for (int i = 0; i < Ncolors; i++)
  183.     {
  184.         string color = gray ? gray_values[i] : color_values[i];
  185.         XColor xcolor;
  186.         if (!XParseColor(dpy, cmap, color, &xcolor))
  187.         {
  188.         cerr << "Unable to parse " << quote(color) 
  189.              << ".  Using black.\n";
  190.         colors[i] = black;
  191.         }
  192.         else
  193.         {
  194.         if (XAllocColor(dpy, cmap, &xcolor)) {
  195.             colors[i] = xcolor.pixel;
  196.         }
  197.         else
  198.         {
  199.             cerr << "Cannot allocate " << quote(color)
  200.              << ".  Using black.\n";
  201.             colors[i] = black;
  202.         }
  203.         }
  204.     }
  205.     }
  206.  
  207.     // Init dashes
  208.     int i;
  209.     for (i = 0; i < Ndashes; i++)
  210.     { 
  211.     string v;
  212.     if (depth <= 1)
  213.         v = dash_mono[i];
  214.     else
  215.         v = dash_color[i];
  216.  
  217.     if (v.length() == 0 || v[0] == '0')
  218.     {
  219.         dashes[i][0] = (unsigned char)0;
  220.     }
  221.     else
  222.     {
  223.         for (int j = 0; j < int(v.length()); j++)
  224.         dashes[i][j] = (unsigned char) (v[j] - '0');
  225.     }
  226.     dashes[i][v.length()] = (unsigned char)0;
  227.     }
  228.  
  229.     // Init widths
  230.     widths[0] = 2;
  231.     for (i = 1; i < Nwidths; i++)
  232.     widths[i] = 0;
  233. }
  234.  
  235. // Plot functions
  236.  
  237. #define X(x) (int) (x * xscale)
  238. #define Y(y) (int) ((4095-y) * yscale)
  239.  
  240. void PlotArea::plot_nop(const char *)
  241. {
  242.     // Ignore command
  243. }
  244.  
  245. // Unknown command
  246. void PlotArea::plot_unknown(const char *command)
  247. {
  248.     cerr << "PlotArea: unknown plot command " << quote(command) << "\n";
  249. }
  250.  
  251. void PlotArea::plot_vector(const char *buf)
  252. {
  253.     int x, y;
  254.     int assignments = sscanf((char *)buf, "V%4d%4d", &x, &y);
  255.     if (assignments != 2)
  256.     {
  257.     plot_unknown(buf);
  258.     return;
  259.     }
  260.  
  261.     XDrawLine(dpy, win, gc, X(cx), Y(cy), X(x), Y(y));
  262.     cx = x; cy = y;
  263. }
  264.  
  265. void PlotArea::plot_move(const char *buf)
  266. {
  267.     int assignments = sscanf((char *)buf, "M%4d%4d", &cx, &cy);
  268.     if (assignments != 2)
  269.     {
  270.     plot_unknown(buf);
  271.     return;
  272.     }
  273. }
  274.  
  275. void PlotArea::plot_text(const char *buf)
  276. {
  277.     int x, y;
  278.     int assignments = sscanf((char *)buf, "T%4d%4d", &x, &y);  
  279.     if (assignments != 2)
  280.     {
  281.     plot_unknown(buf);
  282.     return;
  283.     }
  284.  
  285.     const char *str = buf + 9;
  286.     int sl = 0;
  287.     while (str[sl] != '\n' && str[sl] != '\0')
  288.     sl++;
  289.  
  290.     int sw = XTextWidth(font, str, sl);
  291.     switch (jmode) 
  292.     {
  293.     case 0: sw = 0;     break;    // left
  294.     case 1: sw = -sw/2; break;    // center
  295.     case 2: sw = -sw;   break;    // right
  296.     }
  297.  
  298.     XSetForeground(dpy, gc, colors[2]);
  299.     XDrawString(dpy, win, gc, X(x)+sw, Y(y) + vchar / 3, str, sl);
  300.     XSetForeground(dpy, gc, colors[line_type + 3]);
  301. }
  302.  
  303. void PlotArea::plot_justify(const char *buf)
  304. {
  305.     int assignments = sscanf((char *)buf, "J%4d", &jmode);
  306.     if (assignments != 1)
  307.     {
  308.     plot_unknown(buf);
  309.     return;
  310.     }
  311. }
  312.  
  313. void PlotArea::plot_linetype(const char *buf)
  314. {
  315.     int assignments = sscanf((char *)buf, "L%4d", &line_type);
  316.     if (assignments != 1)
  317.     {
  318.     plot_unknown(buf);
  319.     return;
  320.     }
  321.  
  322.     line_type = (line_type % 8) + 2;
  323.     width = widths[line_type];
  324.     if (dashes[line_type][0])
  325.     {
  326.     type = LineOnOffDash;
  327.     XSetDashes(dpy, gc, 0, dashes[line_type], strlen(dashes[line_type]));
  328.     }
  329.     else
  330.     {
  331.     type = LineSolid;
  332.     }
  333.     XSetForeground(dpy, gc, colors[line_type + 3]);
  334.     XSetLineAttributes(dpy, gc, width, type, CapButt, JoinBevel);
  335. }
  336.  
  337. void PlotArea::plot_point(const char *buf)
  338. {
  339.     int point, x, y;
  340.     int assignments = sscanf((char *)buf, "P%1d%4d%4d", &point, &x, &y);  
  341.     if (assignments != 3)
  342.     {
  343.     plot_unknown(buf);
  344.     return;
  345.     }
  346.  
  347.     if (point == 7) 
  348.     {
  349.     // Set point size
  350.     px = (int) (x * xscale * pointsize);
  351.     py = (int) (y * yscale * pointsize);
  352.     return;
  353.     }
  354.  
  355.     if (type != LineSolid || width != 0) 
  356.     {
  357.     // Select solid line
  358.     XSetLineAttributes(dpy, gc, 0, LineSolid, CapButt, JoinBevel);
  359.     }
  360.  
  361.     switch(point) {
  362.     case 0: // Dot
  363.     XDrawLine(dpy,win,gc, X(x), Y(y), X(x), Y(y));
  364.     break;
  365.  
  366.     case 1: // Diamond
  367.     XDrawLine(dpy,win,gc, X(x)-px, Y(y), X(x), Y(y)-py);
  368.     XDrawLine(dpy,win,gc, X(x), Y(y)-py, X(x)+px, Y(y));
  369.     XDrawLine(dpy,win,gc, X(x)+px, Y(y), X(x), Y(y)+py);
  370.     XDrawLine(dpy,win,gc, X(x), Y(y)+py, X(x)-px, Y(y));
  371.     XDrawLine(dpy,win,gc, X(x), Y(y), X(x), Y(y));
  372.     break;
  373.  
  374.     case 2: // Plus
  375.     XDrawLine(dpy,win,gc, X(x)-px, Y(y), X(x)+px, Y(y));
  376.     XDrawLine(dpy,win,gc, X(x), Y(y)-py, X(x), Y(y)+py);
  377.     break;
  378.  
  379.     case 3: // Box
  380.     XDrawLine(dpy,win,gc, X(x)-px, Y(y)-py, X(x)+px, Y(y)-py);
  381.     XDrawLine(dpy,win,gc, X(x)+px, Y(y)-py, X(x)+px, Y(y)+py);
  382.     XDrawLine(dpy,win,gc, X(x)+px, Y(y)+py, X(x)-px, Y(y)+py);
  383.     XDrawLine(dpy,win,gc, X(x)-px, Y(y)+py, X(x)-px, Y(y)-py);
  384.     XDrawLine(dpy,win,gc, X(x), Y(y), X(x), Y(y));
  385.     break;
  386.  
  387.     case 4: // X
  388.     XDrawLine(dpy,win,gc, X(x)-px, Y(y)-py, X(x)+px, Y(y)+py);
  389.     XDrawLine(dpy,win,gc, X(x)-px, Y(y)+py, X(x)+px, Y(y)-py);
  390.     break;
  391.  
  392.     case 5: // Triangle
  393.     XDrawLine(dpy,win,gc, X(x), Y(y)-(4*px/3), 
  394.           X(x)-(4*px/3), Y(y)+(2*py/3));
  395.     XDrawLine(dpy,win,gc, X(x), Y(y)-(4*px/3), 
  396.           X(x)+(4*px/3), Y(y)+(2*py/3));
  397.     XDrawLine(dpy,win,gc, X(x)-(4*px/3), Y(y)+(2*py/3), 
  398.           X(x)+(4*px/3), Y(y)+(2*py/3));
  399.     XDrawLine(dpy,win,gc, X(x), Y(y), X(x), Y(y));
  400.     break;
  401.  
  402.     case 6: // Star
  403.     XDrawLine(dpy,win,gc, X(x)-px, Y(y), X(x)+px, Y(y));
  404.     XDrawLine(dpy,win,gc, X(x), Y(y)-py, X(x), Y(y)+py);
  405.     XDrawLine(dpy,win,gc, X(x)-px, Y(y)-py, X(x)+px, Y(y)+py);
  406.     XDrawLine(dpy,win,gc, X(x)-px, Y(y)+py, X(x)+px, Y(y)-py);
  407.     break;
  408.     }
  409.  
  410.     if (type != LineSolid || width != 0)
  411.     {  
  412.     // Restore line type
  413.     XSetLineAttributes(dpy, gc, width, type, CapButt, JoinBevel);
  414.     }
  415. }
  416.  
  417. void PlotArea::plot_clear(const char *)
  418. {
  419.     // Clear window
  420.     Dimension area_width, area_height;
  421.     Pixel area_background;
  422.     XtVaGetValues(area, 
  423.           XmNwidth, &area_width, 
  424.           XmNheight, &area_height, 
  425.           XmNbackground, &area_background,
  426.           NULL);
  427.  
  428.     XSetForeground(dpy, gc, area_background);
  429.     XFillRectangle(dpy, win, gc, 0, 0, area_width, area_height);
  430.     XSetBackground(dpy, gc, area_background);
  431. }
  432.  
  433. // Reset all values
  434. void PlotArea::plot_reset(const char *)
  435. {
  436.     if (!XtIsRealized(area))
  437.     {
  438.     win = 0;
  439.     return;
  440.     }
  441.  
  442.     win = XtWindow(area);
  443.  
  444.     // Set scaling factor between internal driver & window geometry
  445.     Dimension area_width, area_height;
  446.     XtVaGetValues(area, 
  447.           XmNwidth, &area_width, 
  448.           XmNheight, &area_height, 
  449.           NULL);
  450.     xscale = (double)area_width  / 4096.0;
  451.     yscale = (double)area_height / 4096.0;
  452.  
  453.     // Reset center
  454.     cx = 0;
  455.     cy = 0;
  456.  
  457.     // Reset line type
  458.     type = LineSolid;
  459.  
  460.     // Create new GC
  461.     if (gc != 0)
  462.     XFreeGC(dpy, gc);
  463.     gc = XCreateGC(dpy, win, 0, (XGCValues *)0);
  464.     XSetFont(dpy, gc, font->fid);
  465. }
  466.  
  467. void PlotArea::plot(const char *commands, int length, bool clear)
  468. {
  469.     if (last_commands.length() > 0 && 
  470.     last_commands.data()[last_commands.length() - 1] != '\n')
  471.     {
  472.     // Last command was incomplete - complete it
  473.     char *s = last_commands.data();
  474.     int line = last_commands.length() - 1;
  475.     while (line > 0 && s[line - 1] != '\n')
  476.         line--;
  477.     assert(line == 0 || s[line - 1] == '\n');
  478.  
  479.     const char *tail = commands;
  480.     while (length > 0 && *commands != '\n')
  481.         commands++, length--;
  482.  
  483.     if (length > 0 && *commands == '\n')
  484.     {
  485.         commands++, length--;
  486.         string command = string(s + line) + string(tail, commands - tail);
  487.  
  488.         assert(isalpha(command[0]));
  489.         assert(command.contains('\n', -1));
  490.  
  491.         do_plot(command, clear);
  492.  
  493.         last_commands.append((char *)tail, commands - tail);
  494.     }
  495.     }
  496.  
  497.     int discard = do_plot(commands, clear);
  498.  
  499.     if (discard >= 0)
  500.     {
  501.     // `G' command found - forget about old commands
  502.     last_commands.discard();
  503.     last_commands.append((char *)commands + discard, length - discard);
  504.     }
  505.     else
  506.     {
  507.     // No `G' command found - append to previous commands
  508.     last_commands.append((char *)commands, length);
  509.     }
  510.  
  511.     assert(last_commands.length() == 0 || last_commands.data()[0] == 'G');
  512. }
  513.  
  514. void PlotArea::replot(bool clear)
  515. {
  516.     plot_reset("");
  517.  
  518.     do_plot(last_commands.data(), clear);
  519. }
  520.  
  521. int PlotArea::do_plot(const char *commands, bool clear)
  522. {
  523.     // Discard all commands up to `G' command, if any
  524.     int discard = -1;
  525.  
  526.     const char *cmds = commands;
  527.     while (*cmds != '\0')
  528.     {
  529.     if (cmds[0] == 'G' && cmds[1] == '\n')
  530.     {
  531.         if (pending_plots > 0)
  532.         pending_plots--;
  533.  
  534.         discard = (cmds - commands);
  535.     }
  536.  
  537.     while (*cmds != '\n' && *cmds != '\0')
  538.         cmds++;
  539.     if (*cmds != '\0')
  540.         cmds++;
  541.     }
  542.  
  543.     // Process commands
  544.     cmds = commands;
  545.     if (discard >= 0)
  546.     {
  547.     cmds += discard;
  548.     assert(cmds[0] == 'G');
  549.     assert(cmds[1] == '\n');
  550.     }
  551.  
  552. #if 0                // FIXME: Not thoroughly tested yet  -AZ
  553.     if (discard < 0 && pending_plots > 0)
  554.     return discard;
  555. #endif
  556.  
  557.     while (cmds[0] != '\0')
  558.     {
  559.     const char *command = cmds;
  560.  
  561.     // Move CMDS to the next line
  562.     while (*cmds != '\0' && *cmds != '\n')
  563.         cmds++;
  564.     if (*cmds == '\0')
  565.         break;        // Command is incomplete - don't do it
  566.     cmds++;
  567.  
  568.     // Make current command NUL-terminated.  Otherwise, sscanf()
  569.     // takes far too much time.
  570.     if (cmds > commands && *cmds != '\0')
  571.         ((char *)cmds)[-1] = '\0';
  572.  
  573.     switch (command[0])
  574.     {
  575.     case 'V':
  576.         if (win)
  577.         plot_vector(command);
  578.         break;
  579.  
  580.     case 'M':
  581.         if (win)
  582.         plot_move(command);
  583.         break;
  584.  
  585.     case 'T':
  586.         if (win)
  587.         plot_text(command);
  588.         break;
  589.  
  590.     case 'J':
  591.         if (win)
  592.         plot_justify(command);
  593.         break;
  594.  
  595.     case 'L':
  596.         if (win)
  597.         plot_linetype(command);
  598.         break;
  599.  
  600.     case 'P':
  601.         if (win)
  602.         plot_point(command);
  603.         break;
  604.  
  605.     case 'G':
  606.         plot_reset(command);
  607.         if (win && clear)
  608.         plot_clear(command);
  609.         break;
  610.  
  611.     case 'E':
  612.     case 'R':
  613.         if (win)
  614.         plot_nop(command);
  615.         break;
  616.  
  617.     default:
  618.         plot_unknown(command);
  619.         break;
  620.     }
  621.  
  622.     // Restore terminator
  623.     if (cmds > commands && *cmds != '\0')
  624.         ((char *)cmds)[-1] = '\n';
  625.     }
  626.  
  627.     return discard;
  628. }
  629.