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

view.cc

/*
 * Copyright (c) 1991,1993 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    This product includes software developed by the Computer Systems
 *    Engineering Group at Lawrence Berkeley Laboratory.
 * 4. Neither the name of the University nor of the Laboratory may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * @(#) $Header: /cvsroot/nsnam/nam-1/view.cc,v 1.30 2003/10/11 22:56:51 xuanc Exp $ (LBL)
 */

#include <stdlib.h>
#ifdef WIN32
#include <windows.h>
#endif

#include <ctype.h>
#include <math.h>

#include <tclcl.h>
#include "view.h"
#include "bbox.h"
#include "netview.h"
#include "netmodel.h"
#include "tclcl.h"
#include "paint.h"
#include "packet.h"

// Create list of font names and sizes
static char * fontName[NFONT] = {
  "-adobe-times-medium-r-normal-*-8-*-*-*-*-*-*-*",
  "-adobe-times-medium-r-normal-*-10-*-*-*-*-*-*-*",
  "-adobe-times-medium-r-normal-*-12-*-*-*-*-*-*-*",
  "-adobe-times-medium-r-normal-*-14-*-*-*-*-*-*-*",
  "-adobe-times-medium-r-normal-*-18-*-*-*-*-*-*-*",
  "-adobe-times-medium-r-normal-*-20-*-*-*-*-*-*-*",
  "-adobe-times-medium-r-normal-*-24-*-*-*-*-*-*-*",
  "-adobe-times-medium-r-normal-*-34-*-*-*-*-*-*-*"
};


// Convert a string to world coordinates
int View::getCoord(char *strx, char *stry, float &dx, float &dy) {
      Tcl& tcl = Tcl::instance();

      double tx, ty;
      if ((Tk_GetScreenMM(tcl.interp(), tk_, strx, &tx) != TCL_OK) ||
          (Tk_GetScreenMM(tcl.interp(), tk_, stry, &ty) != TCL_OK)) {
            return TCL_ERROR;
      }
      
      tx *= pixelsPerMM_;
      ty *= pixelsPerMM_;
      dx = tx, dy = ty;
      matrix_.imap(dx, dy);
      return TCL_OK;
}

void View::zoom(float mag)
{
        magnification_ *= mag;
        resize(width_, height_);
}

//---------------------------------------------------------------------
// void
// View::resize(int width, int height)
//   - resize the display canvas and setup the mapping between 
//     world and screen coordinate systems
//---------------------------------------------------------------------
void View::resize(int width, int height) {
  width_ = width;
  height_ = height;

  matrix_.clear();

  BBox bb;

  // a model can choose to use these values, or can set its own
  // NetModel sets it to bb.clear(), while GraphView use this
  bb.xmin = 0;
  bb.ymin = 0;
  bb.xmax = width;
  bb.ymax = height;

  // WorldBox refers to the boundaries for the network model world 
  // Basically NetView and EditView used to return the bounding box
  // for NetModel not for themselves so now BoundingBox returns
  // values based on the canvas size and getWorldBox returns the 
  // NetModel values.
  getWorldBox(bb);
 // BoundingBox(bb);

  double x = (0.0 - panx_) * width;
  double y = (0.0 - pany_) * height;
  double w = width;
  double h = height;
  /*
   * Set up a transform that maps bb -> canvas.  I.e,
   * bb -> unit square -> allocation, but which retains
   * the aspect ratio.  Also, add a margin.
   */
  double world_width = bb.xmax - bb.xmin;
  double world_height = bb.ymax - bb.ymin;

  
  /* 
   * Grow a margin if we asked for square aspect ratio.
   */
  double bbw;
  double bbh;

  if (aspect_ == SQUARE) {
    bbw = 1.1 * world_width;
    bbh = 1.1 * world_height;

   // bbw = world_width;
   // bbh = world_width*height/width;

 //   if (bbh < world_height) {
      // Need to scale in the other direction
  //    bbw = world_height*width/height;
   //   bbh = world_height;
   // }
  } else {
    bbw = world_width;
    bbh = world_height;
  }

  // Calculate the width and height for translating x and y axis
  double tx = bb.xmin - 0.5 * (bbw - world_width);
  double ty = bb.ymin - 0.5 * (bbh - world_height);
  
  // move base coordinate system to origin
  matrix_.translate(-tx, -ty);
  
  // flip vertical axis because Y is backwards.
  matrix_.scale(1.0, -1.0);
  matrix_.translate(0., bbh);
  
  double ws = w / bbw;
  double hs = h / bbh;
  
  // The matrix_.translate(x expression, y expression) takes care of
  // scrolling when clicking on the scroll bars
  if (aspect_ == SQUARE) {
    if (ws <= hs) {
      matrix_.scale(ws, ws);
      matrix_.translate(x, y + 0.5 * (h - ws * bbh));
    } else {
      matrix_.scale(hs, hs);
      matrix_.translate(x + 0.5 * (w - hs * bbw), y);
    }
  } else {
    matrix_.scale(ws, hs);
    matrix_.translate(x, y);
  }

  if (offscreen_ != 0)
    Tk_FreePixmap(Tk_Display(tk_), offscreen_);

  if ((width_<=0) || (height_<=0))
    abort();

  // Create a new offscreen canvas for double buffered drawing
  offscreen_ = Tk_GetPixmap(Tk_Display(tk_), Tk_WindowId(tk_),
                            width_, height_, Tk_Depth(tk_));


  // Scale for any magnification
  matrix_.scale(magnification_, magnification_);

  if (xscroll_ != NULL) {
    Tcl& tcl = Tcl::instance();
    tcl.evalf("%s set %f %f", xscroll_, panx_, 
                              panx_+(1.0/magnification_));
  }

  if (yscroll_ != NULL) {
    Tcl& tcl = Tcl::instance();
    tcl.evalf("%s set %f %f", yscroll_, pany_, 
                              pany_+(1.0/magnification_));
  }

  pixelsPerMM_ = WidthOfScreen(Tk_Screen(tk_)) / 
                 WidthMMOfScreen(Tk_Screen(tk_));

  if (!bClip_) {
    clip_.xmin = 0;
    clip_.ymin = 0;
    clip_.xmax = width_;
    clip_.ymax = height_;
  }
}

//---------------------------------------------------------------------
// void
// View::draw() 
//   - Does double buffered drawing
//     All objects are drawn to an offscreen area and then the whole
//     offscreen area is copied to the current view --mehringe@isi.edu
//   - render is in a sub class of View
//---------------------------------------------------------------------
void
View::draw() {
      if (offscreen_ == 0) {
            return;
      }
      
      // Clear offscreen bitmap
      XFillRectangle(Tk_Display(tk_), offscreen_, background_,
                     0, 0, width_, height_);

      // Draw objects onto offscreen bitmap
      render();
      
      // Copy over offscreen bitmap to current view
      XCopyArea(Tk_Display(tk_), offscreen_, Tk_WindowId(tk_), background_,
                0, 0, width_, height_, 0, 0);
}

//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
View::View(const char* name, int aspect, int width, int height) :
      next_(NULL),
      magnification_(1.0),
      panx_(0.0),
      pany_(0.0), 
      aspect_(aspect),
      xscroll_(NULL),
      yscroll_(NULL),
      bClip_(0) {

      Tcl& tcl = Tcl::instance();
      tk_ = Tk_CreateWindowFromPath(tcl.interp(), tcl.tkmain(),
                                    (char *) name, 0);

      if (tk_) {
            Tk_SetClass(tk_, "NetView");
            /*XXX*/
            /* Specify preferred window size. */
            Tk_GeometryRequest(tk_, width, height);

            Tk_CreateEventHandler(tk_, ExposureMask|StructureNotifyMask,
                                  handle, (ClientData)this);

            Tk_MakeWindowExist(tk_);

            pixelsPerMM_ = WidthOfScreen(Tk_Screen(tk_)) / 
                           WidthMMOfScreen(Tk_Screen(tk_));
      } else {
            // Just an arbitrary initialization
            pixelsPerMM_ = 1;
      }

      width_ = height_ = 0;
      background_ = Paint::instance()->background_gc();
      offscreen_ = 0;
      load_fonts();
}



View::~View()
{
      /* 
       * Do not do Tk_DestroyWindow() stuff. Should *never* use
       * delete <view> to destroy a view
       */ 
      if (tk_ != 0) {
            if (offscreen_ != 0)
                  Tk_FreePixmap(Tk_Display(tk_), offscreen_);
            free_fonts();
      }
      tk_ = 0;
}

//----------------------------------------------------------------------
// void
// View::BoundingBox(BBox& destination)
//  
//----------------------------------------------------------------------
void
View::BoundingBox(BBox& destination) {
  fprintf(stderr,"View::BoundingBox\n");
}

void View::setClipRect(BBox &b) 
{
      XRectangle rect;
      Paint* paint = Paint::instance();
      clip_ = b;
      bClip_ = 1;
      clip_.xmin = clip_.ymin = 0;
      clip_.xmax = (float)width_;
      clip_.ymax = (float)height_;
      b.xrect(rect);
#ifndef WIN32
      for (int i = 0; i < paint->num_gc(); i++) {
            XSetClipRectangles(Tk_Display(tk_), paint->paint_to_gc(i),
                           0, 0, &rect, 1, Unsorted);
      }
#endif
}

void View::clearClipRect()
{
      Paint* paint = Paint::instance();
#ifndef WIN32
      for (int i = 0; i < paint->num_gc(); i++) {
            // XXX Or should I set it to the whole window???
            XSetClipRectangles(Tk_Display(tk_), paint->paint_to_gc(i),
                           0, 0, None, 1, Unsorted);
      }
#endif
      bClip_ = 0;
}

void View::setFunction(int func)
{
      Paint* paint = Paint::instance();
      for (int i = 0; i < paint->num_gc(); i++) 
            XSetFunction(Tk_Display(tk_), paint->paint_to_gc(i), func);
}

/* Handler for the Expose, DestroyNotify and ConfigureNotify events. */
void View::handle(ClientData cd, XEvent* ep)
{
      View* nv = (View*)cd;
      
      switch (ep->type) {
      case Expose:
            if (ep->xexpose.count == 0)
                  /*XXX*/
                  nv->draw();
            break;
            
      case DestroyNotify:
            /*XXX kill ourself */
            /*XXX: this should kill the viewer! */
            /*XXX how about use delete this? */
            if (nv->tk_ != 0) {
                  if (nv->offscreen_ != 0)
                        Tk_FreePixmap(Tk_Display(nv->tk_), 
                                    nv->offscreen_);
                  nv->free_fonts();
            }
            nv->tk_ = 0;
            delete nv;
            break;
            
      case ConfigureNotify:
            if (nv->width_ != ep->xconfigure.width ||
                nv->height_ != ep->xconfigure.height) {
              //if it gets smaller, there will be no expose event,
              //so we have to draw it outselves - mjh
              int smaller=0;
              if ((nv->width_ >= ep->xconfigure.width) &&
                  (nv->height_ >= ep->xconfigure.height))
                smaller=1;
              nv->resize(ep->xconfigure.width,
                       ep->xconfigure.height);
              if (smaller)
                nv->draw();
            }
            break;
      }
}

int View::command(ClientData cd, Tcl_Interp* tcl, int argc, CONST84 char **argv)
{
  NetView *nv = (NetView *)cd;
  if (argc < 2) {
    Tcl_AppendResult(tcl, "\"", argv[0], "\": arg mismatch", 0);
    return (TCL_ERROR);
  }
  if (strcmp(argv[1], "xscroll") == 0) {
    if (argc == 3) {
      nv->xscroll_=new char[strlen(argv[2])+1];
      strcpy(nv->xscroll_, argv[2]);
      return TCL_OK;
    } else {
      Tcl_AppendResult(tcl, "\"", argv[0],
                       "\": arg mismatch", 0);
      return TCL_ERROR;
    }
  }
  if (strcmp(argv[1], "yscroll") == 0) {
    if (argc == 3) {
      nv->yscroll_=new char[strlen(argv[2])+1];
      strcpy(nv->yscroll_, argv[2]);
      return TCL_OK;
    } else {
      Tcl_AppendResult(tcl, "\"", argv[0],
                       "\": arg mismatch", 0);
      return TCL_ERROR;
    }
  }
  if (strcmp(argv[1], "zoom") == 0) {
    if (argc == 3) {
      float mag=atof(argv[2]);
      if (mag>1.0) {
      nv->panx_+=(1.0-1.0/mag)/(2.0*nv->magnification_);
      nv->pany_+=(1.0-1.0/mag)/(2.0*nv->magnification_);
      } else {
      nv->panx_-=(1.0-mag)/(2.0*nv->magnification_*mag);
      nv->pany_-=(1.0-mag)/(2.0*nv->magnification_*mag);
      }
      nv->zoom(mag);
      nv->draw();
      //nv->pan(panx, pany);
      return TCL_OK;
    } else {
      Tcl_AppendResult(tcl, "\"", argv[0],
                   "\": arg mismatch", 0);
      return TCL_ERROR;
    }
  }
  if ((strcmp(argv[1], "xview") == 0) ||
      (strcmp(argv[1], "yview") == 0)) {
    if ((argc==4) && (strcmp(argv[2], "moveto")==0)) {
      if (strcmp(argv[1], "xview") == 0)
      nv->panx_=atof(argv[3]);
      else
      nv->pany_=atof(argv[3]);
      nv->resize(nv->width_, nv->height_);
      nv->draw();

    } else if ((argc==5) && (strcmp(argv[2], "scroll")==0)) {
      float step = atof(argv[3]);

      if (strcmp(argv[4], "units")==0) {
      step *= 0.05/nv->magnification_;
      } else if (strcmp(argv[4], "pages")==0) {
      step *= 0.8/nv->magnification_;
      } else if (strcmp(argv[4], "world")==0) {
        // Used for canvas grab style dragging
       // float x0, y0, x_step, y_step;
       // nv->matrix_.map(0.0, 0.0, x0, y0);
      //  if (strcmp(argv[1], "xview") == 0) {
      //    nv->matrix_.map(step, 0.0, x_step, y_step);
      //    step = x0 - x_step;
      //  } else {
      //    nv->matrix_.map(step, 0.0, x_step, y_step);
      //    step = y0 - y_step;
      //  }
        step /= nv->magnification_;
      }  

      if (strcmp(argv[1], "xview") == 0)
      nv->panx_ += step;
      else
      nv->pany_ += step;

    //  fprintf(stderr, "View::command pan %f,%f\n",nv->panx_,nv->pany_);

      nv->resize(nv->width_, nv->height_);
      nv->draw();

    } else if ((argc == 7) && (strcmp(argv[2], "grab") == 0)) {
      float x_start, y_start;
      float world_x_start, world_y_start;

      nv->matrix_.imap(atof(argv[3]), atof(argv[4]),
                       world_x_start, world_y_start); 
      x_start = atof(argv[3]);
      y_start = atof(argv[3]);


    } else {
      Tcl_AppendResult(tcl, "\"", argv[0],
                   "\": arg mismatch", 0);
      return TCL_ERROR;
    }
    return TCL_OK;
  }
  Tcl_AppendResult(tcl, "\"", argv[0], "\": unknown arg: ", argv[1], 0);
  return (TCL_ERROR);
}


void 
View::line(float x0, float y0, float x1, float y1, int paint)
{
      int ax, ay;
      matrix_.map(x0, y0, ax, ay);
      int bx, by;
      matrix_.map(x1, y1, bx, by);
      GC gc = Paint::instance()->paint_to_gc(paint);
      XDrawLine(Tk_Display(tk_), offscreen_, gc, ax, ay, bx, by);
}

void View::rect(float x0, float y0, float x1, float y1, int paint)
{
      int x, y;
      matrix_.map(x0, y0, x, y);
      int xx, yy;
      matrix_.map(x1, y1, xx, yy);
      
      int w = xx - x;
      if (w < 0) {
            x = xx;
            w = -w;
      }
      int h = yy - y;
      if (h < 0) {
            h = -h;
            y = yy;
      }
      GC gc = Paint::instance()->paint_to_gc(paint);
      XDrawRectangle(Tk_Display(tk_), offscreen_, gc, x, y, w, h);
}

void View::polygon(const float* x, const float* y, int n, int paint)
{
      /*XXX*/
      XPoint pts[10];
      
      for (int i = 0; i < n; ++i) {
            float tx, ty;
            matrix_.map(x[i], y[i], tx, ty);
            pts[i].x = int(tx);
            pts[i].y = int(ty);
      }
      pts[n] = pts[0];
      GC gc = Paint::instance()->paint_to_gc(paint);
      XDrawLines(Tk_Display(tk_), offscreen_, gc, pts, n + 1,
               CoordModeOrigin);
}

void View::fill(const float* x, const float* y, int n, int paint)
{
      /*XXX*/
      XPoint pts[10];
      
      for (int i = 0; i < n; ++i) {
            float tx, ty;
            matrix_.map(x[i], y[i], tx, ty);
            pts[i].x = int(tx);
            pts[i].y = int(ty);
      }
      pts[n] = pts[0];
      GC gc = Paint::instance()->paint_to_gc(paint);
      XFillPolygon(Tk_Display(tk_), offscreen_, gc, pts, n + 1,
                 Convex, CoordModeOrigin);
}

//----------------------------------------------------------------------
//
//----------------------------------------------------------------------
void View::circle(float x, float y, float r, int paint) {
  int tx, ty;     // Translated x and y
  int tr, dummy;  // Translated radius
  
  // Map world coordinates to current view coordinates
  matrix_.map(x, y, tx, ty);
  matrix_.map(x + r, y, tr, dummy);

//  fprintf(stderr, "View::circle x %f y %f tx %d ty %d\n", x,y,tx,ty);

  // XDrawArc starts from the corner so we have to 
  // move the tx and ty coordinates from the center
  // of the circle to the corner
  tr -= tx;
  tx -= tr;
  ty -= tr;
  
  // We want tr to be the diameter of the arc
  tr *= 2;
  GC gc = Paint::instance()->paint_to_gc(paint);
  XDrawArc(Tk_Display(tk_), offscreen_, gc, tx, ty, tr, tr, 0, 64 * 360);
}

//----------------------------------------------------------------------
// void 
// View::load_fonts()
//   - Set the font structures using values in 'fontName'(defined above)
//----------------------------------------------------------------------
void 
View::load_fonts() {
      Tcl_Interp* tcl;
      nfont_ = 0;
      
      if (tk_) {
            tcl = Tcl::instance().interp();
            // Load each font described in fontName[]
            for (int i = 0; i < NFONT; ++i) {
                  fonts_[nfont_] = Tk_GetFont(tcl, tk_, fontName[i]);
                  if (fonts_[nfont_] == 0) {
                        fprintf(stderr, "Unable to load font: %s\n",fontName[i]);
                        continue;
                  }
                  font_gc_[nfont_] = Paint::instance()->text_gc(Tk_FontId(fonts_[nfont_]));
                  ++nfont_;
            }
            if (nfont_ == 0) {
                  fprintf(stderr, "nam: warning no fonts found\n");
            } else {
                  default_font_ = TIMES_14POINT;
            }
      }
}

void View::free_fonts()
{
      /*XXX Tk_FreeFontStruct*/
      for (int i = 0; i < NFONT; i++) {
            Tk_FreeFont(fonts_[i]);
      }
}

//----------------------------------------------------------------------
// int
// View::lookup_font(int d)
//   - returns the index into the fonts_ array that is smaller in size
//     than d
//   - returns -1 if nfont_ is 0 which indicates that no fonts have been
//     loaded
//----------------------------------------------------------------------
int
View::lookup_font(int d) {
      int i = nfont_;
      while (--i > 0) {
            Tk_Font f = fonts_[i];
            Tk_FontMetrics p;
            Tk_GetFontMetrics(f, &p);
            if (d >= p.ascent + p.descent) {
                  return (i);
    } 
      }
      if (nfont_) {
            return 0;
      }

      return -1;
}

//----------------------------------------------------------------------
// int
// View::getStringScreenWidth(char * text, double screen_height)
//   - Calculate the width of a string in screen coordinates based upon
//     the font size selected by the height of the string
//----------------------------------------------------------------------
int
View::getStringScreenWidth(const char * text, int screen_height) {
      int font_id;
      font_id = lookup_font(screen_height);
      if (font_id != -1) {
            return Tk_TextWidth(fonts_[lookup_font(screen_height)],
                                                                        text, strlen(text));
      } else { 
            return 0;
      }
            
}


//----------------------------------------------------------------------
// double
// View::getStringWidth(char * text, double world_height)
//   - calculates a strings width and returns it in world size
//----------------------------------------------------------------------
double
View::getStringWidth(const char * text, double world_height) {
  float x_min, x_max, y_min, y_max, discarded;
  double world_width;
  int screen_height, screen_width;
  
  matrix_.map(0.0, 0.0, discarded, y_min);
  matrix_.map(0.0, world_height, discarded, y_max);
  screen_height = (int) ceil(y_min - y_max);

  screen_width = getStringScreenWidth(text, screen_height);
  matrix_.imap(0.0, 0.0, x_min, discarded);
  matrix_.imap((float) screen_width, 0.0, x_max, discarded);
  world_width = x_max - x_min;

  return world_width;
}

//----------------------------------------------------------------------
//
//----------------------------------------------------------------------
int
View::getStringHeight(char * text) {
  return 0; 
}


//-----------------------------------------------------------------------
// void
// View::string(float fx, float fy, float dim, const char* s, 
//              int anchor, const char* color)
//     - This draws a string on the view
//     - Whoever wrote this code should be shot.  For anyone who is
//       working on nam in the future. Read this:
//         PUT SOME COMMENTS IN YOUR CODE!!!
//         and I don't mean comments like this is a hack or this
//         code is bad.  
//         Also, USE DESCRIPTIVE VARIBALE NAMES!!! Don't use just i or
//         f or d, dlow, dhigh or just p.  What the does that stand for?
//     - This code is driving me insane because I have to rewrite and 
//       comment everything just to understand what the hell the person 
//       before me was trying to do.    
//----------------------------------------------------------------------
void
View::string(float fx, float fy, float dim, const char* s, 
                  int anchor, const char* color) {
      if (nfont_ <= 0)
            return;
      
      int dummy;
      int dlow, dhigh;
      //Tcl& tcl = Tcl::instance();
      
      /*XXX this could be cached*/
      matrix_.map(0., 0., dummy, dlow);
      matrix_.map(0., 0.9 * dim, dummy, dhigh);
      int d = dhigh - dlow;
      if (d < 0)
            d = -d;
      int font = lookup_font(d);
      Tk_Font f = fonts_[font];
      Tk_FontMetrics p;
      Tk_GetFontMetrics(f, &p);

      int h = p.ascent;
      int len = strlen(s);
      int w = Tk_TextWidth(f, s, len);
      
      int x, y;
      matrix_.map(fx, fy, x, y);
      
      /* XXX still need to adjust for mismatch between d and actual height*/
      
      switch (anchor) {
            
      case ANCHOR_CENTER:
            x -= w / 2;
            y += h / 2;
            break;
            
      case ANCHOR_NORTH:
            x -= w / 2;
            y += d;
            break;
            
      case ANCHOR_SOUTH:
            x -= w / 2;
            y -= h/2;
            break;
            
      case ANCHOR_WEST:
            y += h / 2;
            break;
            
      case ANCHOR_EAST:
            x -= w;
            y += h / 2;
            break;
      }

      // XXX Very very very bad hack. Should go through Paint::text_gc()!!
      //Colormap cmap;
      //Tk_Uid colorname;
      GC fgc = font_gc_[font]; // Font gc
      if (color != NULL) {
            fgc = Paint::instance()->text_gc(Tk_FontId(fonts_[font]), color);
      }

      Tk_DrawChars(Tk_Display(tk_), offscreen_, fgc, f, s, len, x, y);
      if (color != NULL) {
            Tk_FreeGC(Tk_Display(tk_), fgc);
      }
      // XXX We don't free the color allocated above. Hope it won't 
      // be a problem!
}


//----------------------------------------------------------------------
//
//----------------------------------------------------------------------
int
View::string(const char * text, double world_x, double world_y,
             double size, const char * color) {
  int screen_x, screen_y, font_index;
  Tk_Font font;
  Tk_FontMetrics font_metrics;
  int width;
  GC font_gc;
  int dummy, y_min, y_max;

  width = 0;
  if (nfont_ > 0) {
    matrix_.map(world_x, world_y, screen_x, screen_y);

    // Find screen height of box
    matrix_.map(0., 0., dummy, y_min);
    matrix_.map(0., 0.9 * size, dummy, y_max);
    int height = y_max - y_min ;
    if (height < 0) {
      height = -1*height;
    }
    font_index = lookup_font(height);

    //font_index = TIMES_14POINT;
    font = fonts_[font_index];
    Tk_GetFontMetrics(font, &font_metrics);

    font_gc = font_gc_[font_index]; // Font gc
    if (color) { 
      font_gc = Paint::instance()->text_gc(Tk_FontId(font), color);
    }

        width = Tk_TextWidth(font, text, strlen(text));

    Tk_DrawChars(Tk_Display(tk_), offscreen_, font_gc, font, text, 
                 strlen(text), screen_x, screen_y);

    if (color) {
      Tk_FreeGC(Tk_Display(tk_), font_gc);
    }
  }
  return width;
}


//----------------------------------------------------------------------
//----------------------------------------------------------------------
void
View::boxedString(const char * text, double world_x, double world_y,
                  double vertical_size, int paint, 
                  const char * color) {
  float box_width, text_width, height;
  float x_padding, y_padding;

  height = 0;

  box_width = getStringWidth(text, vertical_size);
  text_width = getStringWidth(text, 0.9*vertical_size);

  x_padding = (box_width - text_width)/2.0;
  y_padding = 0.05*vertical_size;
  string(text, world_x + x_padding, world_y + y_padding, 0.9*vertical_size, color);

  rect(world_x, world_y, world_x + box_width, world_y + vertical_size, paint);  
}
  
  


Generated by  Doxygen 1.6.0   Back to index