home *** CD-ROM | disk | FTP | other *** search
- // $Id: PlotArea.C,v 1.8 1998/11/17 12:24:31 zeller Exp $ -*- C++ -*-
- // An area to plot upon
-
- // Copyright (C) 1998 Technische Universitaet Braunschweig, Germany.
- // Written by Andreas Zeller <zeller@ips.cs.tu-bs.de>.
- //
- // This file is part of DDD.
- //
- // DDD is free software; you can redistribute it and/or
- // modify it under the terms of the GNU General Public
- // License as published by the Free Software Foundation; either
- // version 2 of the License, or (at your option) any later version.
- //
- // DDD is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- // See the GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public
- // License along with DDD -- see the file COPYING.
- // If not, write to the Free Software Foundation, Inc.,
- // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- //
- // DDD is the data display debugger.
- // For details, see the DDD World-Wide-Web page,
- // `http://www.cs.tu-bs.de/softech/ddd/',
- // or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
-
- // Most of this code is based on `gplt_x11.c' from Gnuplot.
- //
- // Acknowledgements:
- // Chris Peterson (MIT)
- // Dana Chee (Bellcore)
- // Arthur Smith (Cornell)
- // Hendri Hondorp (University of Twente, The Netherlands)
- // Bill Kucharski (Solbourne)
- // Charlie Kline (University of Illinois)
- // Yehavi Bourvine (Hebrew University of Jerusalem, Israel)
- // Russell Lang (Monash University, Australia)
- // O'Reilly & Associates: X Window System - Volumes 1 & 2
- //
- // This code is provided as is and with no warranties of any kind.
-
- char PlotArea_rcsid[] =
- "$Id: PlotArea.C,v 1.8 1998/11/17 12:24:31 zeller Exp $";
-
- #ifdef __GNUG__
- #pragma implementation
- #endif
-
- #include "PlotArea.h"
-
- #include "cook.h"
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <ctype.h>
-
- #include <X11/StringDefs.h>
- #include <X11/Xlib.h>
- #include <Xm/DrawingA.h>
-
- // Data
- struct plot_resource_values {
- String font;
- int pointsize;
- };
-
- static XtResource plot_subresources[] = {
- {
- "font",
- "Font",
- XtRString,
- sizeof(String),
- XtOffsetOf(plot_resource_values, font),
- XtRImmediate,
- XtPointer("fixed")
- },
- {
- "pointsize",
- "Pointsize",
- XtRInt,
- sizeof(int),
- XtOffsetOf(plot_resource_values, pointsize),
- XtRImmediate,
- XtPointer(1)
- }
- };
-
-
- #if 0
- static char color_keys[Ncolors][30] = {
- "background", "bordercolor", "text", "border", "axis",
- "line1", "line2", "line3", "line4",
- "line5", "line6", "line7", "line8"
- };
- #endif
-
- static char color_values[Ncolors][30] = {
- "white", "black", "black", "black", "black",
- "red", "green", "blue", "magenta",
- "cyan", "sienna", "orange", "coral"
- };
-
- static char gray_values[Ncolors][30] = {
- "black", "white", "white", "gray50", "gray50",
- "gray100", "gray60", "gray80", "gray40",
- "gray90", "gray50", "gray70", "gray30"
- };
-
- #if 0
- char dash_keys[Ndashes][10] = {
- "border", "axis",
- "line1", "line2", "line3", "line4", "line5", "line6", "line7", "line8"
- };
- #endif
-
- static char dash_mono[Ndashes][10] = {
- "0", "16",
- "0", "42", "13", "44", "15", "4441", "42", "13"
- };
-
- static char dash_color[Ndashes][10] = {
- "0", "16",
- "0", "0", "0", "0", "0", "0", "0", "0"
- };
-
- // Initialize
- PlotArea::PlotArea(Widget w, const string& fontname)
- : area(w), dpy(XtDisplay(w)), win(XtWindow(w)),
- cx(0), cy(0), px(1), py(1), xscale(0.0), yscale(0.0),
- gc(0), font(0), vchar(0), jmode(0), line_type(0), width(0),
- type(LineSolid), pointsize(1), pending_plots(0), last_commands()
- {
- plot_resource_values values;
- XtGetApplicationResources(area, &values,
- plot_subresources, XtNumber(plot_subresources),
- NULL, 0);
-
- // Init font
- font = XLoadQueryFont(dpy, fontname);
- if (font == 0)
- font = XLoadQueryFont(dpy, values.font);
- if (font == 0)
- font = XLoadQueryFont(dpy, "fixed");
- if (font == 0)
- {
- cerr << "Cannot load font\n";
- exit(1);
- }
-
- vchar = font->ascent + font->descent;
-
- // Init point size
- pointsize = values.pointsize;
- if (pointsize <= 0 || pointsize > 10)
- {
- cerr << "Invalid point size " << pointsize << "\n";
- pointsize = 1;
- }
-
- // Init colors
- Pixel black = BlackPixelOfScreen(XtScreen(area));
- Pixel white = WhitePixelOfScreen(XtScreen(area));
- int depth;
- XtVaGetValues(area, XmNdepth, &depth, NULL);
- if (depth <= 1)
- {
- // Monochrome
- colors[0] = white;
- for (int i = 1; i < Ncolors; i++)
- colors[i] = black;
- }
- else
- {
- // Multi-color or gray
- Visual *vis = DefaultVisualOfScreen(XtScreen(area));
- bool gray = (vis->c_class == StaticGray || vis->c_class == GrayScale);
- Colormap cmap;
- XtVaGetValues(area, XmNcolormap, &cmap, NULL);
-
- for (int i = 0; i < Ncolors; i++)
- {
- string color = gray ? gray_values[i] : color_values[i];
- XColor xcolor;
- if (!XParseColor(dpy, cmap, color, &xcolor))
- {
- cerr << "Unable to parse " << quote(color)
- << ". Using black.\n";
- colors[i] = black;
- }
- else
- {
- if (XAllocColor(dpy, cmap, &xcolor)) {
- colors[i] = xcolor.pixel;
- }
- else
- {
- cerr << "Cannot allocate " << quote(color)
- << ". Using black.\n";
- colors[i] = black;
- }
- }
- }
- }
-
- // Init dashes
- int i;
- for (i = 0; i < Ndashes; i++)
- {
- string v;
- if (depth <= 1)
- v = dash_mono[i];
- else
- v = dash_color[i];
-
- if (v.length() == 0 || v[0] == '0')
- {
- dashes[i][0] = (unsigned char)0;
- }
- else
- {
- for (int j = 0; j < int(v.length()); j++)
- dashes[i][j] = (unsigned char) (v[j] - '0');
- }
- dashes[i][v.length()] = (unsigned char)0;
- }
-
- // Init widths
- widths[0] = 2;
- for (i = 1; i < Nwidths; i++)
- widths[i] = 0;
- }
-
- // Plot functions
-
- #define X(x) (int) (x * xscale)
- #define Y(y) (int) ((4095-y) * yscale)
-
- void PlotArea::plot_nop(const char *)
- {
- // Ignore command
- }
-
- // Unknown command
- void PlotArea::plot_unknown(const char *command)
- {
- cerr << "PlotArea: unknown plot command " << quote(command) << "\n";
- }
-
- void PlotArea::plot_vector(const char *buf)
- {
- int x, y;
- int assignments = sscanf((char *)buf, "V%4d%4d", &x, &y);
- if (assignments != 2)
- {
- plot_unknown(buf);
- return;
- }
-
- XDrawLine(dpy, win, gc, X(cx), Y(cy), X(x), Y(y));
- cx = x; cy = y;
- }
-
- void PlotArea::plot_move(const char *buf)
- {
- int assignments = sscanf((char *)buf, "M%4d%4d", &cx, &cy);
- if (assignments != 2)
- {
- plot_unknown(buf);
- return;
- }
- }
-
- void PlotArea::plot_text(const char *buf)
- {
- int x, y;
- int assignments = sscanf((char *)buf, "T%4d%4d", &x, &y);
- if (assignments != 2)
- {
- plot_unknown(buf);
- return;
- }
-
- const char *str = buf + 9;
- int sl = 0;
- while (str[sl] != '\n' && str[sl] != '\0')
- sl++;
-
- int sw = XTextWidth(font, str, sl);
- switch (jmode)
- {
- case 0: sw = 0; break; // left
- case 1: sw = -sw/2; break; // center
- case 2: sw = -sw; break; // right
- }
-
- XSetForeground(dpy, gc, colors[2]);
- XDrawString(dpy, win, gc, X(x)+sw, Y(y) + vchar / 3, str, sl);
- XSetForeground(dpy, gc, colors[line_type + 3]);
- }
-
- void PlotArea::plot_justify(const char *buf)
- {
- int assignments = sscanf((char *)buf, "J%4d", &jmode);
- if (assignments != 1)
- {
- plot_unknown(buf);
- return;
- }
- }
-
- void PlotArea::plot_linetype(const char *buf)
- {
- int assignments = sscanf((char *)buf, "L%4d", &line_type);
- if (assignments != 1)
- {
- plot_unknown(buf);
- return;
- }
-
- line_type = (line_type % 8) + 2;
- width = widths[line_type];
- if (dashes[line_type][0])
- {
- type = LineOnOffDash;
- XSetDashes(dpy, gc, 0, dashes[line_type], strlen(dashes[line_type]));
- }
- else
- {
- type = LineSolid;
- }
- XSetForeground(dpy, gc, colors[line_type + 3]);
- XSetLineAttributes(dpy, gc, width, type, CapButt, JoinBevel);
- }
-
- void PlotArea::plot_point(const char *buf)
- {
- int point, x, y;
- int assignments = sscanf((char *)buf, "P%1d%4d%4d", &point, &x, &y);
- if (assignments != 3)
- {
- plot_unknown(buf);
- return;
- }
-
- if (point == 7)
- {
- // Set point size
- px = (int) (x * xscale * pointsize);
- py = (int) (y * yscale * pointsize);
- return;
- }
-
- if (type != LineSolid || width != 0)
- {
- // Select solid line
- XSetLineAttributes(dpy, gc, 0, LineSolid, CapButt, JoinBevel);
- }
-
- switch(point) {
- case 0: // Dot
- XDrawLine(dpy,win,gc, X(x), Y(y), X(x), Y(y));
- break;
-
- case 1: // Diamond
- XDrawLine(dpy,win,gc, X(x)-px, Y(y), X(x), Y(y)-py);
- XDrawLine(dpy,win,gc, X(x), Y(y)-py, X(x)+px, Y(y));
- XDrawLine(dpy,win,gc, X(x)+px, Y(y), X(x), Y(y)+py);
- XDrawLine(dpy,win,gc, X(x), Y(y)+py, X(x)-px, Y(y));
- XDrawLine(dpy,win,gc, X(x), Y(y), X(x), Y(y));
- break;
-
- case 2: // Plus
- XDrawLine(dpy,win,gc, X(x)-px, Y(y), X(x)+px, Y(y));
- XDrawLine(dpy,win,gc, X(x), Y(y)-py, X(x), Y(y)+py);
- break;
-
- case 3: // Box
- XDrawLine(dpy,win,gc, X(x)-px, Y(y)-py, X(x)+px, Y(y)-py);
- XDrawLine(dpy,win,gc, X(x)+px, Y(y)-py, X(x)+px, Y(y)+py);
- XDrawLine(dpy,win,gc, X(x)+px, Y(y)+py, X(x)-px, Y(y)+py);
- XDrawLine(dpy,win,gc, X(x)-px, Y(y)+py, X(x)-px, Y(y)-py);
- XDrawLine(dpy,win,gc, X(x), Y(y), X(x), Y(y));
- break;
-
- case 4: // X
- XDrawLine(dpy,win,gc, X(x)-px, Y(y)-py, X(x)+px, Y(y)+py);
- XDrawLine(dpy,win,gc, X(x)-px, Y(y)+py, X(x)+px, Y(y)-py);
- break;
-
- case 5: // Triangle
- XDrawLine(dpy,win,gc, X(x), Y(y)-(4*px/3),
- X(x)-(4*px/3), Y(y)+(2*py/3));
- XDrawLine(dpy,win,gc, X(x), Y(y)-(4*px/3),
- X(x)+(4*px/3), Y(y)+(2*py/3));
- XDrawLine(dpy,win,gc, X(x)-(4*px/3), Y(y)+(2*py/3),
- X(x)+(4*px/3), Y(y)+(2*py/3));
- XDrawLine(dpy,win,gc, X(x), Y(y), X(x), Y(y));
- break;
-
- case 6: // Star
- XDrawLine(dpy,win,gc, X(x)-px, Y(y), X(x)+px, Y(y));
- XDrawLine(dpy,win,gc, X(x), Y(y)-py, X(x), Y(y)+py);
- XDrawLine(dpy,win,gc, X(x)-px, Y(y)-py, X(x)+px, Y(y)+py);
- XDrawLine(dpy,win,gc, X(x)-px, Y(y)+py, X(x)+px, Y(y)-py);
- break;
- }
-
- if (type != LineSolid || width != 0)
- {
- // Restore line type
- XSetLineAttributes(dpy, gc, width, type, CapButt, JoinBevel);
- }
- }
-
- void PlotArea::plot_clear(const char *)
- {
- // Clear window
- Dimension area_width, area_height;
- Pixel area_background;
- XtVaGetValues(area,
- XmNwidth, &area_width,
- XmNheight, &area_height,
- XmNbackground, &area_background,
- NULL);
-
- XSetForeground(dpy, gc, area_background);
- XFillRectangle(dpy, win, gc, 0, 0, area_width, area_height);
- XSetBackground(dpy, gc, area_background);
- }
-
- // Reset all values
- void PlotArea::plot_reset(const char *)
- {
- if (!XtIsRealized(area))
- {
- win = 0;
- return;
- }
-
- win = XtWindow(area);
-
- // Set scaling factor between internal driver & window geometry
- Dimension area_width, area_height;
- XtVaGetValues(area,
- XmNwidth, &area_width,
- XmNheight, &area_height,
- NULL);
- xscale = (double)area_width / 4096.0;
- yscale = (double)area_height / 4096.0;
-
- // Reset center
- cx = 0;
- cy = 0;
-
- // Reset line type
- type = LineSolid;
-
- // Create new GC
- if (gc != 0)
- XFreeGC(dpy, gc);
- gc = XCreateGC(dpy, win, 0, (XGCValues *)0);
- XSetFont(dpy, gc, font->fid);
- }
-
- void PlotArea::plot(const char *commands, int length, bool clear)
- {
- if (last_commands.length() > 0 &&
- last_commands.data()[last_commands.length() - 1] != '\n')
- {
- // Last command was incomplete - complete it
- char *s = last_commands.data();
- int line = last_commands.length() - 1;
- while (line > 0 && s[line - 1] != '\n')
- line--;
- assert(line == 0 || s[line - 1] == '\n');
-
- const char *tail = commands;
- while (length > 0 && *commands != '\n')
- commands++, length--;
-
- if (length > 0 && *commands == '\n')
- {
- commands++, length--;
- string command = string(s + line) + string(tail, commands - tail);
-
- assert(isalpha(command[0]));
- assert(command.contains('\n', -1));
-
- do_plot(command, clear);
-
- last_commands.append((char *)tail, commands - tail);
- }
- }
-
- int discard = do_plot(commands, clear);
-
- if (discard >= 0)
- {
- // `G' command found - forget about old commands
- last_commands.discard();
- last_commands.append((char *)commands + discard, length - discard);
- }
- else
- {
- // No `G' command found - append to previous commands
- last_commands.append((char *)commands, length);
- }
-
- assert(last_commands.length() == 0 || last_commands.data()[0] == 'G');
- }
-
- void PlotArea::replot(bool clear)
- {
- plot_reset("");
-
- do_plot(last_commands.data(), clear);
- }
-
- int PlotArea::do_plot(const char *commands, bool clear)
- {
- // Discard all commands up to `G' command, if any
- int discard = -1;
-
- const char *cmds = commands;
- while (*cmds != '\0')
- {
- if (cmds[0] == 'G' && cmds[1] == '\n')
- {
- if (pending_plots > 0)
- pending_plots--;
-
- discard = (cmds - commands);
- }
-
- while (*cmds != '\n' && *cmds != '\0')
- cmds++;
- if (*cmds != '\0')
- cmds++;
- }
-
- // Process commands
- cmds = commands;
- if (discard >= 0)
- {
- cmds += discard;
- assert(cmds[0] == 'G');
- assert(cmds[1] == '\n');
- }
-
- #if 0 // FIXME: Not thoroughly tested yet -AZ
- if (discard < 0 && pending_plots > 0)
- return discard;
- #endif
-
- while (cmds[0] != '\0')
- {
- const char *command = cmds;
-
- // Move CMDS to the next line
- while (*cmds != '\0' && *cmds != '\n')
- cmds++;
- if (*cmds == '\0')
- break; // Command is incomplete - don't do it
- cmds++;
-
- // Make current command NUL-terminated. Otherwise, sscanf()
- // takes far too much time.
- if (cmds > commands && *cmds != '\0')
- ((char *)cmds)[-1] = '\0';
-
- switch (command[0])
- {
- case 'V':
- if (win)
- plot_vector(command);
- break;
-
- case 'M':
- if (win)
- plot_move(command);
- break;
-
- case 'T':
- if (win)
- plot_text(command);
- break;
-
- case 'J':
- if (win)
- plot_justify(command);
- break;
-
- case 'L':
- if (win)
- plot_linetype(command);
- break;
-
- case 'P':
- if (win)
- plot_point(command);
- break;
-
- case 'G':
- plot_reset(command);
- if (win && clear)
- plot_clear(command);
- break;
-
- case 'E':
- case 'R':
- if (win)
- plot_nop(command);
- break;
-
- default:
- plot_unknown(command);
- break;
- }
-
- // Restore terminator
- if (cmds > commands && *cmds != '\0')
- ((char *)cmds)[-1] = '\n';
- }
-
- return discard;
- }
-