Logo Search packages:      
Sourcecode: ddd version File versions  Download package

PlotArea.C

// $Id$ -*- C++ -*-
// An area to plot upon

// Copyright (C) 1998 Technische Universitaet Braunschweig, Germany.
// Written by Andreas Zeller <zeller@gnu.org>.
// 
// 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.gnu.org/software/ddd/',
// or send a mail to the DDD developers <ddd@gnu.org>.

// 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$";

#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
00060 struct plot_resource_values {
    String font;
    int pointsize;
};

static XtResource plot_subresources[] = {
    {
      XTRESSTR("font"),
      XTRESSTR("Font"),
      XtRString,
      sizeof(String),
      XtOffsetOf(plot_resource_values, font),
      XtRImmediate,
      XtPointer("fixed")
    },
    {
      XTRESSTR("pointsize"),
      XTRESSTR("Pointsize"),
      XtRInt,
      sizeof(int),
      XtOffsetOf(plot_resource_values, pointsize),
      XtRImmediate,
      XtPointer(1)
    }
};


#if 0
static const char * const color_keys[Ncolors] =   { 
   "background", "bordercolor", "text", "border", "axis", 
   "line1", "line2", "line3",  "line4", 
   "line5", "line6", "line7",  "line8" 
   };
#endif

static const char * const color_values[Ncolors] = { 
    "white", "black",  "black",  "black",  "black", 
    "red",   "green",  "blue",   "magenta", 
    "cyan",  "sienna", "orange", "coral" 
};

static const char * const gray_values[Ncolors] = { 
    "black",   "white",  "white",  "gray50", "gray50",
    "gray100", "gray60", "gray80", "gray40", 
    "gray90",  "gray50", "gray70", "gray30" 
};

#if 0
static const char * const dash_keys[Ndashes] =   { 
   "border", "axis",
   "line1", "line2", "line3",  "line4", "line5", "line6", "line7",  "line8" 
};
#endif

static const char * const dash_mono[Ndashes] =   { 
   "0", "16",
   "0", "42", "13",  "44", "15", "4441", "42",  "13" 
};

static const char * const dash_color[Ndashes] =   { 
   "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),
                        ArgList(0), 0);

    // Init font
    font = XLoadQueryFont(dpy, fontname.chars());
    if (font == 0)
      font = XLoadQueryFont(dpy, values.font);
    if (font == 0)
      font = XLoadQueryFont(dpy, "fixed");
    if (font == 0)
    {
      std::cerr << "Cannot load font\n";
      exit(1);
    }
    
    vchar = font->ascent + font->descent;

    // Init point size
    pointsize = values.pointsize;
    if (pointsize <= 0 || pointsize > 10) 
    {
      std::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, XtPointer(0));
    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, XtPointer(0));

      for (int i = 0; i < Ncolors; i++)
      {
          string color = gray ? gray_values[i] : color_values[i];
          XColor xcolor;
          if (!XParseColor(dpy, cmap, color.chars(), &xcolor))
          {
            std::cerr << "Unable to parse " << quote(color) 
                 << ".  Using black.\n";
            colors[i] = black;
          }
          else
          {
            if (XAllocColor(dpy, cmap, &xcolor)) {
                colors[i] = xcolor.pixel;
            }
            else
            {
                std::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)
{
    std::cerr << "PlotArea: unknown plot command " << quote(command) << "\n";
}

void PlotArea::plot_vector(const char *buf)
{
    int x, y;
    int assignments = sscanf(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(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(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(buf, "J%4d", &jmode);
    if (assignments != 1)
    {
      plot_unknown(buf);
      return;
    }
}

void PlotArea::plot_linetype(const char *buf)
{
    int assignments = sscanf(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(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,
              XtPointer(0));

    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, 
              XtPointer(0));
    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
      const 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.chars(), clear);

          last_commands.append(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(commands + discard, length - discard);
    }
    else
    {
      // No `G' command found - append to previous commands
      last_commands.append(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
    const char *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_begin = cmds;

      // Move CMDS to the next line
      while (*cmds != '\0' && *cmds != '\n')
          cmds++;
      if (*cmds == '\0')
          break;        // Command is incomplete - don't do it
      assert(*cmds == '\n');
      cmds++;

      // Copy current command to a NULL-terminated string. Otherwise, 
        // sscanf() takes far too much time.
      const int len_ = cmds-command_begin-1;
      assert(len_ >= 0);
      const string command_s(command_begin,len_);

      const char *command = command_s.chars();
      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;
      }
    }

    return discard;
}

Generated by  Doxygen 1.6.0   Back to index