view.cc
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:23k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * Copyright (c) 1991,1993 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  * This product includes software developed by the Computer Systems
  16.  * Engineering Group at Lawrence Berkeley Laboratory.
  17.  * 4. Neither the name of the University nor of the Laboratory may be used
  18.  *    to endorse or promote products derived from this software without
  19.  *    specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  *
  33.  * @(#) $Header: /cvsroot/nsnam/nam-1/view.cc,v 1.30 2003/10/11 22:56:51 xuanc Exp $ (LBL)
  34.  */
  35. #include <stdlib.h>
  36. #ifdef WIN32
  37. #include <windows.h>
  38. #endif
  39. #include <ctype.h>
  40. #include <math.h>
  41. #include <tclcl.h>
  42. #include "view.h"
  43. #include "bbox.h"
  44. #include "netview.h"
  45. #include "netmodel.h"
  46. #include "tclcl.h"
  47. #include "paint.h"
  48. #include "packet.h"
  49. // Create list of font names and sizes
  50. static char * fontName[NFONT] = {
  51.   "-adobe-times-medium-r-normal-*-8-*-*-*-*-*-*-*",
  52.   "-adobe-times-medium-r-normal-*-10-*-*-*-*-*-*-*",
  53.   "-adobe-times-medium-r-normal-*-12-*-*-*-*-*-*-*",
  54.   "-adobe-times-medium-r-normal-*-14-*-*-*-*-*-*-*",
  55.   "-adobe-times-medium-r-normal-*-18-*-*-*-*-*-*-*",
  56.   "-adobe-times-medium-r-normal-*-20-*-*-*-*-*-*-*",
  57.   "-adobe-times-medium-r-normal-*-24-*-*-*-*-*-*-*",
  58.   "-adobe-times-medium-r-normal-*-34-*-*-*-*-*-*-*"
  59. };
  60. // Convert a string to world coordinates
  61. int View::getCoord(char *strx, char *stry, float &dx, float &dy) {
  62. Tcl& tcl = Tcl::instance();
  63. double tx, ty;
  64. if ((Tk_GetScreenMM(tcl.interp(), tk_, strx, &tx) != TCL_OK) ||
  65.     (Tk_GetScreenMM(tcl.interp(), tk_, stry, &ty) != TCL_OK)) {
  66. return TCL_ERROR;
  67. }
  68. tx *= pixelsPerMM_;
  69. ty *= pixelsPerMM_;
  70. dx = tx, dy = ty;
  71. matrix_.imap(dx, dy);
  72. return TCL_OK;
  73. }
  74. void View::zoom(float mag)
  75. {
  76.         magnification_ *= mag;
  77.         resize(width_, height_);
  78. }
  79. //---------------------------------------------------------------------
  80. // void
  81. // View::resize(int width, int height)
  82. //   - resize the display canvas and setup the mapping between 
  83. //     world and screen coordinate systems
  84. //---------------------------------------------------------------------
  85. void View::resize(int width, int height) {
  86.   width_ = width;
  87.   height_ = height;
  88.   matrix_.clear();
  89.   BBox bb;
  90.   // a model can choose to use these values, or can set its own
  91.   // NetModel sets it to bb.clear(), while GraphView use this
  92.   bb.xmin = 0;
  93.   bb.ymin = 0;
  94.   bb.xmax = width;
  95.   bb.ymax = height;
  96.   // WorldBox refers to the boundaries for the network model world 
  97.   // Basically NetView and EditView used to return the bounding box
  98.   // for NetModel not for themselves so now BoundingBox returns
  99.   // values based on the canvas size and getWorldBox returns the 
  100.   // NetModel values.
  101.   getWorldBox(bb);
  102.  // BoundingBox(bb);
  103.   double x = (0.0 - panx_) * width;
  104.   double y = (0.0 - pany_) * height;
  105.   double w = width;
  106.   double h = height;
  107.   /*
  108.    * Set up a transform that maps bb -> canvas.  I.e,
  109.    * bb -> unit square -> allocation, but which retains
  110.    * the aspect ratio.  Also, add a margin.
  111.    */
  112.   double world_width = bb.xmax - bb.xmin;
  113.   double world_height = bb.ymax - bb.ymin;
  114.   
  115.   /* 
  116.    * Grow a margin if we asked for square aspect ratio.
  117.    */
  118.   double bbw;
  119.   double bbh;
  120.   if (aspect_ == SQUARE) {
  121.     bbw = 1.1 * world_width;
  122.     bbh = 1.1 * world_height;
  123.    // bbw = world_width;
  124.    // bbh = world_width*height/width;
  125.  //   if (bbh < world_height) {
  126.       // Need to scale in the other direction
  127.   //    bbw = world_height*width/height;
  128.    //   bbh = world_height;
  129.    // }
  130.   } else {
  131.     bbw = world_width;
  132.     bbh = world_height;
  133.   }
  134.   // Calculate the width and height for translating x and y axis
  135.   double tx = bb.xmin - 0.5 * (bbw - world_width);
  136.   double ty = bb.ymin - 0.5 * (bbh - world_height);
  137.   
  138.   // move base coordinate system to origin
  139.   matrix_.translate(-tx, -ty);
  140.   
  141.   // flip vertical axis because Y is backwards.
  142.   matrix_.scale(1.0, -1.0);
  143.   matrix_.translate(0., bbh);
  144.   
  145.   double ws = w / bbw;
  146.   double hs = h / bbh;
  147.   
  148.   // The matrix_.translate(x expression, y expression) takes care of
  149.   // scrolling when clicking on the scroll bars
  150.   if (aspect_ == SQUARE) {
  151.     if (ws <= hs) {
  152.       matrix_.scale(ws, ws);
  153.       matrix_.translate(x, y + 0.5 * (h - ws * bbh));
  154.     } else {
  155.       matrix_.scale(hs, hs);
  156.       matrix_.translate(x + 0.5 * (w - hs * bbw), y);
  157.     }
  158.   } else {
  159.     matrix_.scale(ws, hs);
  160.     matrix_.translate(x, y);
  161.   }
  162.   if (offscreen_ != 0)
  163.     Tk_FreePixmap(Tk_Display(tk_), offscreen_);
  164.   if ((width_<=0) || (height_<=0))
  165.     abort();
  166.   // Create a new offscreen canvas for double buffered drawing
  167.   offscreen_ = Tk_GetPixmap(Tk_Display(tk_), Tk_WindowId(tk_),
  168.                             width_, height_, Tk_Depth(tk_));
  169.   // Scale for any magnification
  170.   matrix_.scale(magnification_, magnification_);
  171.   if (xscroll_ != NULL) {
  172.     Tcl& tcl = Tcl::instance();
  173.     tcl.evalf("%s set %f %f", xscroll_, panx_, 
  174.                               panx_+(1.0/magnification_));
  175.   }
  176.   if (yscroll_ != NULL) {
  177.     Tcl& tcl = Tcl::instance();
  178.     tcl.evalf("%s set %f %f", yscroll_, pany_, 
  179.                               pany_+(1.0/magnification_));
  180.   }
  181.   pixelsPerMM_ = WidthOfScreen(Tk_Screen(tk_)) / 
  182.                  WidthMMOfScreen(Tk_Screen(tk_));
  183.   if (!bClip_) {
  184.     clip_.xmin = 0;
  185.     clip_.ymin = 0;
  186.     clip_.xmax = width_;
  187.     clip_.ymax = height_;
  188.   }
  189. }
  190. //---------------------------------------------------------------------
  191. // void
  192. // View::draw() 
  193. //   - Does double buffered drawing
  194. //     All objects are drawn to an offscreen area and then the whole
  195. //     offscreen area is copied to the current view --mehringe@isi.edu
  196. //   - render is in a sub class of View
  197. //---------------------------------------------------------------------
  198. void
  199. View::draw() {
  200. if (offscreen_ == 0) {
  201. return;
  202. }
  203. // Clear offscreen bitmap
  204. XFillRectangle(Tk_Display(tk_), offscreen_, background_,
  205.                0, 0, width_, height_);
  206. // Draw objects onto offscreen bitmap
  207. render();
  208. // Copy over offscreen bitmap to current view
  209. XCopyArea(Tk_Display(tk_), offscreen_, Tk_WindowId(tk_), background_,
  210.           0, 0, width_, height_, 0, 0);
  211. }
  212. //-----------------------------------------------------------------------
  213. //-----------------------------------------------------------------------
  214. View::View(const char* name, int aspect, int width, int height) :
  215. next_(NULL),
  216. magnification_(1.0),
  217. panx_(0.0),
  218. pany_(0.0), 
  219. aspect_(aspect),
  220. xscroll_(NULL),
  221. yscroll_(NULL),
  222. bClip_(0) {
  223. Tcl& tcl = Tcl::instance();
  224. tk_ = Tk_CreateWindowFromPath(tcl.interp(), tcl.tkmain(),
  225.                               (char *) name, 0);
  226. if (tk_) {
  227. Tk_SetClass(tk_, "NetView");
  228. /*XXX*/
  229. /* Specify preferred window size. */
  230. Tk_GeometryRequest(tk_, width, height);
  231. Tk_CreateEventHandler(tk_, ExposureMask|StructureNotifyMask,
  232.                       handle, (ClientData)this);
  233. Tk_MakeWindowExist(tk_);
  234. pixelsPerMM_ = WidthOfScreen(Tk_Screen(tk_)) / 
  235.                WidthMMOfScreen(Tk_Screen(tk_));
  236. } else {
  237. // Just an arbitrary initialization
  238. pixelsPerMM_ = 1;
  239. }
  240. width_ = height_ = 0;
  241. background_ = Paint::instance()->background_gc();
  242. offscreen_ = 0;
  243. load_fonts();
  244. }
  245. View::~View()
  246. {
  247. /* 
  248.  * Do not do Tk_DestroyWindow() stuff. Should *never* use
  249.  * delete <view> to destroy a view
  250.  */ 
  251. if (tk_ != 0) {
  252. if (offscreen_ != 0)
  253. Tk_FreePixmap(Tk_Display(tk_), offscreen_);
  254. free_fonts();
  255. }
  256. tk_ = 0;
  257. }
  258. //----------------------------------------------------------------------
  259. // void
  260. // View::BoundingBox(BBox& destination)
  261. //  
  262. //----------------------------------------------------------------------
  263. void
  264. View::BoundingBox(BBox& destination) {
  265.   fprintf(stderr,"View::BoundingBoxn");
  266. }
  267. void View::setClipRect(BBox &b) 
  268. {
  269. XRectangle rect;
  270. Paint* paint = Paint::instance();
  271. clip_ = b;
  272. bClip_ = 1;
  273. clip_.xmin = clip_.ymin = 0;
  274. clip_.xmax = (float)width_;
  275. clip_.ymax = (float)height_;
  276. b.xrect(rect);
  277. #ifndef WIN32
  278. for (int i = 0; i < paint->num_gc(); i++) {
  279. XSetClipRectangles(Tk_Display(tk_), paint->paint_to_gc(i),
  280.    0, 0, &rect, 1, Unsorted);
  281. }
  282. #endif
  283. }
  284. void View::clearClipRect()
  285. {
  286. Paint* paint = Paint::instance();
  287. #ifndef WIN32
  288. for (int i = 0; i < paint->num_gc(); i++) {
  289. // XXX Or should I set it to the whole window???
  290. XSetClipRectangles(Tk_Display(tk_), paint->paint_to_gc(i),
  291.    0, 0, None, 1, Unsorted);
  292. }
  293. #endif
  294. bClip_ = 0;
  295. }
  296. void View::setFunction(int func)
  297. {
  298. Paint* paint = Paint::instance();
  299. for (int i = 0; i < paint->num_gc(); i++) 
  300. XSetFunction(Tk_Display(tk_), paint->paint_to_gc(i), func);
  301. }
  302. /* Handler for the Expose, DestroyNotify and ConfigureNotify events. */
  303. void View::handle(ClientData cd, XEvent* ep)
  304. {
  305. View* nv = (View*)cd;
  306. switch (ep->type) {
  307. case Expose:
  308. if (ep->xexpose.count == 0)
  309. /*XXX*/
  310. nv->draw();
  311. break;
  312. case DestroyNotify:
  313. /*XXX kill ourself */
  314. /*XXX: this should kill the viewer! */
  315. /*XXX how about use delete this? */
  316. if (nv->tk_ != 0) {
  317. if (nv->offscreen_ != 0)
  318. Tk_FreePixmap(Tk_Display(nv->tk_), 
  319.       nv->offscreen_);
  320. nv->free_fonts();
  321. }
  322. nv->tk_ = 0;
  323. delete nv;
  324. break;
  325. case ConfigureNotify:
  326. if (nv->width_ != ep->xconfigure.width ||
  327.     nv->height_ != ep->xconfigure.height) {
  328.   //if it gets smaller, there will be no expose event,
  329.   //so we have to draw it outselves - mjh
  330.   int smaller=0;
  331.   if ((nv->width_ >= ep->xconfigure.width) &&
  332.       (nv->height_ >= ep->xconfigure.height))
  333.     smaller=1;
  334.   nv->resize(ep->xconfigure.width,
  335.      ep->xconfigure.height);
  336.   if (smaller)
  337.     nv->draw();
  338. }
  339. break;
  340. }
  341. }
  342. int View::command(ClientData cd, Tcl_Interp* tcl, int argc, CONST84 char **argv)
  343. {
  344.   NetView *nv = (NetView *)cd;
  345.   if (argc < 2) {
  346.     Tcl_AppendResult(tcl, """, argv[0], "": arg mismatch", 0);
  347.     return (TCL_ERROR);
  348.   }
  349.   if (strcmp(argv[1], "xscroll") == 0) {
  350.     if (argc == 3) {
  351.       nv->xscroll_=new char[strlen(argv[2])+1];
  352.       strcpy(nv->xscroll_, argv[2]);
  353.       return TCL_OK;
  354.     } else {
  355.       Tcl_AppendResult(tcl, """, argv[0],
  356.                        "": arg mismatch", 0);
  357.       return TCL_ERROR;
  358.     }
  359.   }
  360.   if (strcmp(argv[1], "yscroll") == 0) {
  361.     if (argc == 3) {
  362.       nv->yscroll_=new char[strlen(argv[2])+1];
  363.       strcpy(nv->yscroll_, argv[2]);
  364.       return TCL_OK;
  365.     } else {
  366.       Tcl_AppendResult(tcl, """, argv[0],
  367.                        "": arg mismatch", 0);
  368.       return TCL_ERROR;
  369.     }
  370.   }
  371.   if (strcmp(argv[1], "zoom") == 0) {
  372.     if (argc == 3) {
  373.       float mag=atof(argv[2]);
  374.       if (mag>1.0) {
  375. nv->panx_+=(1.0-1.0/mag)/(2.0*nv->magnification_);
  376. nv->pany_+=(1.0-1.0/mag)/(2.0*nv->magnification_);
  377.       } else {
  378. nv->panx_-=(1.0-mag)/(2.0*nv->magnification_*mag);
  379. nv->pany_-=(1.0-mag)/(2.0*nv->magnification_*mag);
  380.       }
  381.       nv->zoom(mag);
  382.       nv->draw();
  383.       //nv->pan(panx, pany);
  384.       return TCL_OK;
  385.     } else {
  386.       Tcl_AppendResult(tcl, """, argv[0],
  387.        "": arg mismatch", 0);
  388.       return TCL_ERROR;
  389.     }
  390.   }
  391.   if ((strcmp(argv[1], "xview") == 0) ||
  392.       (strcmp(argv[1], "yview") == 0)) {
  393.     if ((argc==4) && (strcmp(argv[2], "moveto")==0)) {
  394.       if (strcmp(argv[1], "xview") == 0)
  395. nv->panx_=atof(argv[3]);
  396.       else
  397. nv->pany_=atof(argv[3]);
  398.       nv->resize(nv->width_, nv->height_);
  399.       nv->draw();
  400.     } else if ((argc==5) && (strcmp(argv[2], "scroll")==0)) {
  401.       float step = atof(argv[3]);
  402.       if (strcmp(argv[4], "units")==0) {
  403. step *= 0.05/nv->magnification_;
  404.       } else if (strcmp(argv[4], "pages")==0) {
  405. step *= 0.8/nv->magnification_;
  406.       } else if (strcmp(argv[4], "world")==0) {
  407.         // Used for canvas grab style dragging
  408.        // float x0, y0, x_step, y_step;
  409.        // nv->matrix_.map(0.0, 0.0, x0, y0);
  410.       //  if (strcmp(argv[1], "xview") == 0) {
  411.       //    nv->matrix_.map(step, 0.0, x_step, y_step);
  412.       //    step = x0 - x_step;
  413.       //  } else {
  414.       //    nv->matrix_.map(step, 0.0, x_step, y_step);
  415.       //    step = y0 - y_step;
  416.       //  }
  417.         step /= nv->magnification_;
  418.       }  
  419.       if (strcmp(argv[1], "xview") == 0)
  420. nv->panx_ += step;
  421.       else
  422. nv->pany_ += step;
  423.     //  fprintf(stderr, "View::command pan %f,%fn",nv->panx_,nv->pany_);
  424.       nv->resize(nv->width_, nv->height_);
  425.       nv->draw();
  426.     } else if ((argc == 7) && (strcmp(argv[2], "grab") == 0)) {
  427.       float x_start, y_start;
  428.       float world_x_start, world_y_start;
  429.       nv->matrix_.imap(atof(argv[3]), atof(argv[4]),
  430.                        world_x_start, world_y_start); 
  431.       x_start = atof(argv[3]);
  432.       y_start = atof(argv[3]);
  433.     } else {
  434.       Tcl_AppendResult(tcl, """, argv[0],
  435.        "": arg mismatch", 0);
  436.       return TCL_ERROR;
  437.     }
  438.     return TCL_OK;
  439.   }
  440.   Tcl_AppendResult(tcl, """, argv[0], "": unknown arg: ", argv[1], 0);
  441.   return (TCL_ERROR);
  442. }
  443. void 
  444. View::line(float x0, float y0, float x1, float y1, int paint)
  445. {
  446. int ax, ay;
  447. matrix_.map(x0, y0, ax, ay);
  448. int bx, by;
  449. matrix_.map(x1, y1, bx, by);
  450. GC gc = Paint::instance()->paint_to_gc(paint);
  451. XDrawLine(Tk_Display(tk_), offscreen_, gc, ax, ay, bx, by);
  452. }
  453. void View::rect(float x0, float y0, float x1, float y1, int paint)
  454. {
  455. int x, y;
  456. matrix_.map(x0, y0, x, y);
  457. int xx, yy;
  458. matrix_.map(x1, y1, xx, yy);
  459. int w = xx - x;
  460. if (w < 0) {
  461. x = xx;
  462. w = -w;
  463. }
  464. int h = yy - y;
  465. if (h < 0) {
  466. h = -h;
  467. y = yy;
  468. }
  469. GC gc = Paint::instance()->paint_to_gc(paint);
  470. XDrawRectangle(Tk_Display(tk_), offscreen_, gc, x, y, w, h);
  471. }
  472. void View::polygon(const float* x, const float* y, int n, int paint)
  473. {
  474. /*XXX*/
  475. XPoint pts[10];
  476. for (int i = 0; i < n; ++i) {
  477. float tx, ty;
  478. matrix_.map(x[i], y[i], tx, ty);
  479. pts[i].x = int(tx);
  480. pts[i].y = int(ty);
  481. }
  482. pts[n] = pts[0];
  483. GC gc = Paint::instance()->paint_to_gc(paint);
  484. XDrawLines(Tk_Display(tk_), offscreen_, gc, pts, n + 1,
  485.    CoordModeOrigin);
  486. }
  487. void View::fill(const float* x, const float* y, int n, int paint)
  488. {
  489. /*XXX*/
  490. XPoint pts[10];
  491. for (int i = 0; i < n; ++i) {
  492. float tx, ty;
  493. matrix_.map(x[i], y[i], tx, ty);
  494. pts[i].x = int(tx);
  495. pts[i].y = int(ty);
  496. }
  497. pts[n] = pts[0];
  498. GC gc = Paint::instance()->paint_to_gc(paint);
  499. XFillPolygon(Tk_Display(tk_), offscreen_, gc, pts, n + 1,
  500.      Convex, CoordModeOrigin);
  501. }
  502. //----------------------------------------------------------------------
  503. //
  504. //----------------------------------------------------------------------
  505. void View::circle(float x, float y, float r, int paint) {
  506.   int tx, ty;     // Translated x and y
  507.   int tr, dummy;  // Translated radius
  508.   
  509.   // Map world coordinates to current view coordinates
  510.   matrix_.map(x, y, tx, ty);
  511.   matrix_.map(x + r, y, tr, dummy);
  512. //  fprintf(stderr, "View::circle x %f y %f tx %d ty %dn", x,y,tx,ty);
  513.   // XDrawArc starts from the corner so we have to 
  514.   // move the tx and ty coordinates from the center
  515.   // of the circle to the corner
  516.   tr -= tx;
  517.   tx -= tr;
  518.   ty -= tr;
  519.   
  520.   // We want tr to be the diameter of the arc
  521.   tr *= 2;
  522.   GC gc = Paint::instance()->paint_to_gc(paint);
  523.   XDrawArc(Tk_Display(tk_), offscreen_, gc, tx, ty, tr, tr, 0, 64 * 360);
  524. }
  525. //----------------------------------------------------------------------
  526. // void 
  527. // View::load_fonts()
  528. //   - Set the font structures using values in 'fontName'(defined above)
  529. //----------------------------------------------------------------------
  530. void 
  531. View::load_fonts() {
  532. Tcl_Interp* tcl;
  533. nfont_ = 0;
  534. if (tk_) {
  535. tcl = Tcl::instance().interp();
  536. // Load each font described in fontName[]
  537. for (int i = 0; i < NFONT; ++i) {
  538. fonts_[nfont_] = Tk_GetFont(tcl, tk_, fontName[i]);
  539. if (fonts_[nfont_] == 0) {
  540. fprintf(stderr, "Unable to load font: %sn",fontName[i]);
  541. continue;
  542. }
  543. font_gc_[nfont_] = Paint::instance()->text_gc(Tk_FontId(fonts_[nfont_]));
  544. ++nfont_;
  545. }
  546. if (nfont_ == 0) {
  547. fprintf(stderr, "nam: warning no fonts foundn");
  548. } else {
  549. default_font_ = TIMES_14POINT;
  550. }
  551. }
  552. }
  553. void View::free_fonts()
  554. {
  555. /*XXX Tk_FreeFontStruct*/
  556. for (int i = 0; i < NFONT; i++) {
  557. Tk_FreeFont(fonts_[i]);
  558. }
  559. }
  560. //----------------------------------------------------------------------
  561. // int
  562. // View::lookup_font(int d)
  563. //   - returns the index into the fonts_ array that is smaller in size
  564. //     than d
  565. //   - returns -1 if nfont_ is 0 which indicates that no fonts have been
  566. //     loaded
  567. //----------------------------------------------------------------------
  568. int
  569. View::lookup_font(int d) {
  570. int i = nfont_;
  571. while (--i > 0) {
  572. Tk_Font f = fonts_[i];
  573. Tk_FontMetrics p;
  574. Tk_GetFontMetrics(f, &p);
  575. if (d >= p.ascent + p.descent) {
  576. return (i);
  577.     } 
  578. }
  579. if (nfont_) {
  580. return 0;
  581. }
  582. return -1;
  583. }
  584. //----------------------------------------------------------------------
  585. // int
  586. // View::getStringScreenWidth(char * text, double screen_height)
  587. //   - Calculate the width of a string in screen coordinates based upon
  588. //     the font size selected by the height of the string
  589. //----------------------------------------------------------------------
  590. int
  591. View::getStringScreenWidth(const char * text, int screen_height) {
  592. int font_id;
  593. font_id = lookup_font(screen_height);
  594. if (font_id != -1) {
  595. return Tk_TextWidth(fonts_[lookup_font(screen_height)],
  596. text, strlen(text));
  597. } else { 
  598. return 0;
  599. }
  600. }
  601. //----------------------------------------------------------------------
  602. // double
  603. // View::getStringWidth(char * text, double world_height)
  604. //   - calculates a strings width and returns it in world size
  605. //----------------------------------------------------------------------
  606. double
  607. View::getStringWidth(const char * text, double world_height) {
  608.   float x_min, x_max, y_min, y_max, discarded;
  609.   double world_width;
  610.   int screen_height, screen_width;
  611.   
  612.   matrix_.map(0.0, 0.0, discarded, y_min);
  613.   matrix_.map(0.0, world_height, discarded, y_max);
  614.   screen_height = (int) ceil(y_min - y_max);
  615.   screen_width = getStringScreenWidth(text, screen_height);
  616.   matrix_.imap(0.0, 0.0, x_min, discarded);
  617.   matrix_.imap((float) screen_width, 0.0, x_max, discarded);
  618.   world_width = x_max - x_min;
  619.   return world_width;
  620. }
  621. //----------------------------------------------------------------------
  622. //
  623. //----------------------------------------------------------------------
  624. int
  625. View::getStringHeight(char * text) {
  626.   return 0; 
  627. }
  628. //-----------------------------------------------------------------------
  629. // void
  630. // View::string(float fx, float fy, float dim, const char* s, 
  631. //              int anchor, const char* color)
  632. //     - This draws a string on the view
  633. //     - Whoever wrote this code should be shot.  For anyone who is
  634. //       working on nam in the future. Read this:
  635. //         PUT SOME COMMENTS IN YOUR CODE!!!
  636. //         and I don't mean comments like this is a hack or this
  637. //         code is bad.  
  638. //         Also, USE DESCRIPTIVE VARIBALE NAMES!!! Don't use just i or
  639. //         f or d, dlow, dhigh or just p.  What the does that stand for?
  640. //     - This code is driving me insane because I have to rewrite and 
  641. //       comment everything just to understand what the hell the person 
  642. //       before me was trying to do.    
  643. //----------------------------------------------------------------------
  644. void
  645. View::string(float fx, float fy, float dim, const char* s, 
  646.                   int anchor, const char* color) {
  647. if (nfont_ <= 0)
  648. return;
  649. int dummy;
  650. int dlow, dhigh;
  651. //Tcl& tcl = Tcl::instance();
  652. /*XXX this could be cached*/
  653. matrix_.map(0., 0., dummy, dlow);
  654. matrix_.map(0., 0.9 * dim, dummy, dhigh);
  655. int d = dhigh - dlow;
  656. if (d < 0)
  657. d = -d;
  658. int font = lookup_font(d);
  659. Tk_Font f = fonts_[font];
  660. Tk_FontMetrics p;
  661. Tk_GetFontMetrics(f, &p);
  662. int h = p.ascent;
  663. int len = strlen(s);
  664. int w = Tk_TextWidth(f, s, len);
  665. int x, y;
  666. matrix_.map(fx, fy, x, y);
  667. /* XXX still need to adjust for mismatch between d and actual height*/
  668. switch (anchor) {
  669. case ANCHOR_CENTER:
  670. x -= w / 2;
  671. y += h / 2;
  672. break;
  673. case ANCHOR_NORTH:
  674. x -= w / 2;
  675. y += d;
  676. break;
  677. case ANCHOR_SOUTH:
  678. x -= w / 2;
  679. y -= h/2;
  680. break;
  681. case ANCHOR_WEST:
  682. y += h / 2;
  683. break;
  684. case ANCHOR_EAST:
  685. x -= w;
  686. y += h / 2;
  687. break;
  688. }
  689. // XXX Very very very bad hack. Should go through Paint::text_gc()!!
  690. //Colormap cmap;
  691. //Tk_Uid colorname;
  692. GC fgc = font_gc_[font]; // Font gc
  693. if (color != NULL) {
  694. fgc = Paint::instance()->text_gc(Tk_FontId(fonts_[font]), color);
  695. }
  696. Tk_DrawChars(Tk_Display(tk_), offscreen_, fgc, f, s, len, x, y);
  697. if (color != NULL) {
  698. Tk_FreeGC(Tk_Display(tk_), fgc);
  699. }
  700. // XXX We don't free the color allocated above. Hope it won't 
  701. // be a problem!
  702. }
  703. //----------------------------------------------------------------------
  704. //
  705. //----------------------------------------------------------------------
  706. int
  707. View::string(const char * text, double world_x, double world_y,
  708.              double size, const char * color) {
  709.   int screen_x, screen_y, font_index;
  710.   Tk_Font font;
  711.   Tk_FontMetrics font_metrics;
  712.   int width;
  713.   GC font_gc;
  714.   int dummy, y_min, y_max;
  715.   width = 0;
  716.   if (nfont_ > 0) {
  717.     matrix_.map(world_x, world_y, screen_x, screen_y);
  718.     // Find screen height of box
  719.     matrix_.map(0., 0., dummy, y_min);
  720.     matrix_.map(0., 0.9 * size, dummy, y_max);
  721.     int height = y_max - y_min ;
  722.     if (height < 0) {
  723.       height = -1*height;
  724.     }
  725.     font_index = lookup_font(height);
  726.     //font_index = TIMES_14POINT;
  727.     font = fonts_[font_index];
  728.     Tk_GetFontMetrics(font, &font_metrics);
  729.     font_gc = font_gc_[font_index]; // Font gc
  730.     if (color) { 
  731.       font_gc = Paint::instance()->text_gc(Tk_FontId(font), color);
  732.     }
  733.   width = Tk_TextWidth(font, text, strlen(text));
  734.     Tk_DrawChars(Tk_Display(tk_), offscreen_, font_gc, font, text, 
  735.                  strlen(text), screen_x, screen_y);
  736.     if (color) {
  737.       Tk_FreeGC(Tk_Display(tk_), font_gc);
  738.     }
  739.   }
  740.   return width;
  741. }
  742. //----------------------------------------------------------------------
  743. //----------------------------------------------------------------------
  744. void
  745. View::boxedString(const char * text, double world_x, double world_y,
  746.                   double vertical_size, int paint, 
  747.                   const char * color) {
  748.   float box_width, text_width, height;
  749.   float x_padding, y_padding;
  750.   height = 0;
  751.   box_width = getStringWidth(text, vertical_size);
  752.   text_width = getStringWidth(text, 0.9*vertical_size);
  753.   x_padding = (box_width - text_width)/2.0;
  754.   y_padding = 0.05*vertical_size;
  755.   string(text, world_x + x_padding, world_y + y_padding, 0.9*vertical_size, color);
  756.   rect(world_x, world_y, world_x + box_width, world_y + vertical_size, paint);  
  757. }
  758.   
  759.