home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / DCLAP 6d / dclap6d / vibrant / picture.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-05  |  26.9 KB  |  960 lines  |  [TEXT/R*ch]

  1. /*   picture.c
  2. * ===========================================================================
  3. *
  4. *                            PUBLIC DOMAIN NOTICE
  5. *            National Center for Biotechnology Information (NCBI)
  6. *
  7. *  This software/database is a "United States Government Work" under the
  8. *  terms of the United States Copyright Act.  It was written as part of
  9. *  the author's official duties as a United States Government employee and
  10. *  thus cannot be copyrighted.  This software/database is freely available
  11. *  to the public for use. The National Library of Medicine and the U.S.
  12. *  Government do not place any restriction on its use or reproduction.
  13. *  We would, however, appreciate having the NCBI and the author cited in
  14. *  any work or product based on this material
  15. *
  16. *  Although all reasonable efforts have been taken to ensure the accuracy
  17. *  and reliability of the software and data, the NLM and the U.S.
  18. *  Government do not and cannot warrant the performance or results that
  19. *  may be obtained by using this software or data. The NLM and the U.S.
  20. *  Government disclaim all warranties, express or implied, including
  21. *  warranties of performance, merchantability or fitness for any particular
  22. *  purpose.
  23. *
  24. * ===========================================================================
  25. *
  26. * File Name:  picture.c
  27. *
  28. * Author:  Jonathan Kans, Jill Shermer
  29. *
  30. * Version Creation Date:   10/23/92
  31. *
  32. * $Revision: 1.15 $
  33. *
  34. * File Description: 
  35. *
  36. * Modifications:  
  37. * --------------------------------------------------------------------------
  38. * Date     Name        Description of modification
  39. * -------  ----------  -----------------------------------------------------
  40. *
  41. *
  42. * ==========================================================================
  43. */
  44.  
  45. #ifndef _VIBRANT_
  46. #include <vibrant.h>
  47. #endif
  48.  
  49. #ifndef _PICTURE_
  50. #include <picture.h>
  51. #endif
  52.  
  53. #ifndef _PICTUREP_
  54. #include <pictureP.h>
  55. #endif
  56.  
  57. #ifndef _MAPPINGP_
  58. #include <mappingP.h>
  59. #endif
  60.  
  61. #ifndef _DRAWINGP_
  62. #include <drawingP.h>
  63. #endif
  64.  
  65. /*****************************************************************************
  66. *
  67. *   EXTERNAL VARIABLES
  68. *
  69. *****************************************************************************/
  70.  
  71. Uint1 BLACK_COLOR [3] = {0, 0, 0};
  72. Uint1 WHITE_COLOR [3] = {255, 255, 255};
  73. Uint1 RED_COLOR  [3] = {255, 0, 0};
  74. Uint1 GREEN_COLOR [3] = {0, 255, 0};
  75. Uint1 BLUE_COLOR [3] = {0, 0, 255};
  76. Uint1 YELLOW_COLOR [3] = {255, 255, 0};
  77. Uint1 CYAN_COLOR [3] = {0, 255, 255};
  78. Uint1 MAGENTA_COLOR [3] = {255, 0, 255};
  79.  
  80. /*****************************************************************************
  81. *
  82. *   STATIC VARIABLES
  83. *
  84. *****************************************************************************/
  85.  
  86. static PoinT  emptyPt = {0, 0};
  87.  
  88. /*****************************************************************************
  89. *
  90. *   CreatePicture (void)
  91. *       Creates a Picture Record (same as Segment Record except for base.code)
  92. *
  93. *****************************************************************************/
  94.  
  95. SegmenT CreatePicture (void)
  96.  
  97. {
  98.   PicPPtr  pic;
  99.  
  100.   pic = (PicPPtr) MemNew (sizeof (PicPRec));
  101.   if (pic != NULL) {
  102.     pic->base.next = NULL;
  103.     pic->base.code = PICTURE;
  104.     pic->seg.box.left = INT4_MAX;
  105.     pic->seg.box.top = INT4_MIN;
  106.     pic->seg.box.right = INT4_MIN;
  107.     pic->seg.box.bottom = INT4_MAX;
  108.     pic->seg.head = NULL;
  109.     pic->seg.tail = NULL;
  110.     pic->seg.parent = NULL;
  111.     pic->seg.visible = TRUE;
  112.     pic->seg.margin.left = 0;
  113.     pic->seg.margin.top = 0;
  114.     pic->seg.margin.right = 0;
  115.     pic->seg.margin.bottom = 0;
  116.     pic->seg.maxscale = 0;
  117.     pic->seg.penwidth = STD_PEN_WIDTH;
  118.     pic->seg.highlight = PLAIN_SEGMENT;
  119.     pic->seg.segID = 0;
  120.   }
  121.   return (SegmenT) pic;
  122. }
  123.  
  124. /*****************************************************************************
  125. *
  126. *   DeletePicture (picture)
  127. *       Removes any previously existing segments, then frees picture node
  128. *
  129. *****************************************************************************/
  130.  
  131. SegmenT DeletePicture (SegmenT picture)
  132.  
  133. {
  134.   PicPPtr  pic;
  135.  
  136.   if (picture != NULL) {
  137.     pic = (PicPPtr) picture;
  138.     if (pic->base.code == PICTURE) {
  139.       ResetSegment ((SegmenT) pic);
  140.       pic = (PicPPtr) MemFree (pic);
  141.     } else {
  142.       Message (MSG_ERROR, "DeletePicture argument not a picture");
  143.     }
  144.   }
  145.   return (SegmenT) pic;
  146. }
  147.  
  148. /*****************************************************************************
  149. *
  150. *   CreatePrimitive (parent, code)
  151. *       Common routine creates any primitive type, then adds it to the end
  152. *       of the parent segment's child list, updating segment pointers
  153. *
  154. *****************************************************************************/
  155.  
  156. static BasePPtr CreatePrimitive (SegmenT parent, Int1 code, Nlm_sizeT size)
  157.  
  158. {
  159.   BasePPtr  prev;
  160.   BasePPtr  prim;
  161.   SegPPtr   prnt;
  162.  
  163.   prim = NULL;
  164.   if (parent != NULL) {
  165.     prnt = (SegPPtr) parent;
  166.     if (prnt->base.code == SEGMENT || prnt->base.code == PICTURE) {
  167.       prim = (BasePPtr) MemNew (size);
  168.       if (prim != NULL) {
  169.         prim->next = NULL;
  170.         prim->code = code;
  171.         if (prnt->seg.head != NULL && prnt->seg.tail != NULL) {
  172.           prev = prnt->seg.tail;
  173.           prev->next = prim;
  174.           prnt->seg.tail = prim;
  175.         } else if (prnt->seg.head == NULL && prnt->seg.tail == NULL) {
  176.           prnt->seg.head = prim;
  177.           prnt->seg.tail = prim;
  178.         } else {
  179.           Message (MSG_ERROR, "CreatePrimitive list integrity problem");
  180.         }
  181.       }
  182.     } else {
  183.       Message (MSG_ERROR, "CreatePrimitive parent not a segment or picture");
  184.     }
  185.   }
  186.   return prim;
  187. }
  188.  
  189. /*****************************************************************************
  190. *
  191. *   CreateSegment (parent, segID, maxScale)
  192. *       Creates a segment primitive that can have its own list of children
  193. *
  194. *****************************************************************************/
  195.  
  196. SegmenT CreateSegment (SegmenT parent, Uint2 segID, Int4 maxScale)
  197.  
  198. {
  199.   SegPPtr  prnt;
  200.   SegPPtr  seg;
  201.  
  202.   seg = (SegPPtr) CreatePrimitive (parent, SEGMENT, sizeof (SegPRec));
  203.   if (seg != NULL) {
  204.     seg->seg.box.left = INT4_MAX;
  205.     seg->seg.box.top = INT4_MIN;
  206.     seg->seg.box.right = INT4_MIN;
  207.     seg->seg.box.bottom = INT4_MAX;
  208.     seg->seg.head = NULL;
  209.     seg->seg.tail = NULL;
  210.     seg->seg.parent = (BasePPtr) parent;
  211.     seg->seg.visible = TRUE;
  212.     seg->seg.margin.left = 0;
  213.     seg->seg.margin.top = 0;
  214.     seg->seg.margin.right = 0;
  215.     seg->seg.margin.bottom = 0;
  216.     seg->seg.maxscale = maxScale;
  217.     prnt = (SegPPtr) parent;
  218.     seg->seg.penwidth = STD_PEN_WIDTH;
  219.     if (prnt != NULL) {
  220.       if (prnt->base.code == SEGMENT || prnt->base.code == PICTURE) {
  221.         seg->seg.penwidth = prnt->seg.penwidth;
  222.       }
  223.     }
  224.     seg->seg.highlight = PLAIN_SEGMENT;
  225.     seg->seg.segID = segID;
  226.   }
  227.   return (SegmenT) seg;
  228. }
  229.  
  230. /*****************************************************************************
  231. *
  232. *   ResetSegment (segment)
  233. *       Cleaves and deletes the segment's child list (recursively),
  234. *       freeing item specific data, and leaving the segment itself
  235. *       intact for repopulation
  236. *
  237. *****************************************************************************/
  238.  
  239. SegmenT ResetSegment (SegmenT segment)
  240.  
  241. {
  242.   BasePPtr  item;
  243.   LblPPtr   lbl;
  244.   BasePPtr  next;
  245.   SegPPtr   seg;
  246.  
  247.   if (segment != NULL) {
  248.     seg = (SegPPtr) segment;
  249.     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
  250.       item = seg->seg.head;
  251.       while (item != NULL) {
  252.         next = item->next;
  253.         switch (item->code) {
  254.           case PICTURE :
  255.             ResetSegment ((SegmenT) item);
  256.             break;
  257.           case SEGMENT :
  258.             ResetSegment ((SegmenT) item);
  259.             break;
  260.           case LABEL :
  261.             lbl = (LblPPtr) item;
  262.             MemFree (lbl->str);
  263.             break;
  264.           default :
  265.             break;
  266.         }
  267.         MemFree (item);
  268.         item = next;
  269.       }
  270.       seg->seg.box.left = INT4_MAX;
  271.       seg->seg.box.top = INT4_MIN;
  272.       seg->seg.box.right = INT4_MIN;
  273.       seg->seg.box.bottom = INT4_MAX;
  274.       seg->seg.head = NULL;
  275.       seg->seg.tail = NULL;
  276.       seg->seg.margin.left = 0;
  277.       seg->seg.margin.top = 0;
  278.       seg->seg.margin.right = 0;
  279.       seg->seg.margin.bottom = 0;
  280.       seg->seg.penwidth = STD_PEN_WIDTH;
  281.       seg->seg.highlight = PLAIN_SEGMENT;
  282.     } else {
  283.       Message (MSG_ERROR, "ResetSegment argument not a segment or picture");
  284.     }
  285.   }
  286.   return (SegmenT) seg;
  287. }
  288.  
  289. /*****************************************************************************
  290. *
  291. *   ParentSegment (segment)
  292. *       Returns the parent of a segment
  293. *
  294. *****************************************************************************/
  295.  
  296. SegmenT ParentSegment (SegmenT segment)
  297.  
  298. {
  299.   SegmenT  parent;
  300.   SegPPtr  seg;
  301.  
  302.   parent = NULL;
  303.   if (segment != NULL) {
  304.     seg = (SegPPtr) segment;
  305.     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
  306.       parent = (SegmenT) seg->seg.parent;
  307.       if (parent != NULL) {
  308.         seg = (SegPPtr) parent;
  309.         if (seg->base.code != SEGMENT && seg->base.code != PICTURE) {
  310.           Message (MSG_ERROR, "ParentSegment parent not a segment or picture");
  311.         }
  312.       }
  313.     } else {
  314.       Message (MSG_ERROR, "ParentSegment argument not a segment or picture");
  315.     }
  316.   }
  317.   return parent;
  318. }
  319.  
  320. /*****************************************************************************
  321. *
  322. *   SegmentID (segment)
  323. *       Returns the segment ID of a segment
  324. *
  325. *****************************************************************************/
  326.  
  327. Int2 SegmentID (SegmenT segment)
  328.  
  329. {
  330.   SegPPtr  seg;
  331.   Int2     segID;
  332.  
  333.   segID = 0;
  334.   if (segment != NULL) {
  335.     seg = (SegPPtr) segment;
  336.     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
  337.       segID = seg->seg.segID;
  338.     } else {
  339.       Message (MSG_ERROR, "SegmentID argument not a segment or picture");
  340.     }
  341.   }
  342.   return segID;
  343. }
  344.  
  345. /*****************************************************************************
  346. *
  347. *   SegmentVisible (segment)
  348. *       Returns the visibility of a segment
  349. *
  350. *****************************************************************************/
  351.  
  352. Boolean SegmentVisible (SegmenT segment)
  353.  
  354. {
  355.   SegPPtr  seg;
  356.   Boolean  vis;
  357.  
  358.   vis = FALSE;
  359.   if (segment != NULL) {
  360.     seg = (SegPPtr) segment;
  361.     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
  362.       vis = seg->seg.visible;
  363.     } else {
  364.       Message (MSG_ERROR, "SegmentVisible argument not a segment or picture");
  365.     }
  366.   }
  367.   return vis;
  368. }
  369.  
  370. /*****************************************************************************
  371. *
  372. *   SegmentStyle (segment)
  373. *       Returns the highlight style of a segment
  374. *
  375. *****************************************************************************/
  376.  
  377. Int1 SegmentStyle (SegmenT segment)
  378.  
  379. {
  380.   Int1     highlight;
  381.   SegPPtr  seg;
  382.  
  383.   highlight = PLAIN_SEGMENT;
  384.   if (segment != NULL) {
  385.     seg = (SegPPtr) segment;
  386.     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
  387.       highlight = seg->seg.highlight;
  388.     } else {
  389.       Message (MSG_ERROR, "SegmentStyle argument not a segment or picture");
  390.     }
  391.   }
  392.   return highlight;
  393. }
  394.  
  395. /*****************************************************************************
  396. *
  397. *   SegmentBox (segment, box, mrg)
  398. *       Returns the bounding box and mrg of a segment
  399. *
  400. *****************************************************************************/
  401.  
  402. void SegmentBox (SegmenT segment, BoxPtr box, RectPtr mrg)
  403.  
  404. {
  405.   SegPPtr  seg;
  406.  
  407.   if (segment != NULL) {
  408.     seg = (SegPPtr) segment;
  409.     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
  410.       if (box != NULL) {
  411.         *box = seg->seg.box;
  412.       }
  413.       if (mrg != NULL) {
  414.         *mrg = seg->seg.margin;
  415.       }
  416.     } else {
  417.       Message (MSG_ERROR, "SegmentBox argument not a segment or picture");
  418.     }
  419.   }
  420. }
  421.  
  422. /*****************************************************************************
  423. *
  424. *   GetPrimitive (segment, primCt)
  425. *       Gets a primitive by index within a segment
  426. *
  427. *****************************************************************************/
  428.  
  429. PrimitivE GetPrimitive (SegmenT segment, Uint2 primCt)
  430.  
  431. {
  432.   BasePPtr  item;
  433.   SegPPtr   seg;
  434.  
  435.   item = NULL;
  436.   if (segment != NULL && primCt > 0) {
  437.     seg = (SegPPtr) segment;
  438.     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
  439.       item = seg->seg.head;
  440.       while (item != NULL && primCt > 1) {
  441.         item = item->next;
  442.         primCt--;
  443.       }
  444.     } else {
  445.       Message (MSG_ERROR, "FindPrimitive argument not a segment or picture");
  446.     }
  447.   }
  448.   return (PrimitivE) item;
  449. }
  450.  
  451. /*****************************************************************************
  452. *
  453. *   AdjustParent (parent, left, top, right, bottom)
  454. *       Recalculates segment boundaries, propagates up parent list
  455. *
  456. *****************************************************************************/
  457.  
  458. static void AdjustParent (SegmenT parent, Int4 left, Int4 top, Int4 right, Int4 bottom)
  459.  
  460. {
  461.   SegPPtr  seg;
  462.  
  463.   if (parent != NULL) {
  464.     seg = (SegPPtr) parent;
  465.     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
  466.       if (seg->seg.box.left > left) {
  467.         seg->seg.box.left = left;
  468.       }
  469.       if (seg->seg.box.top < top) {
  470.         seg->seg.box.top = top;
  471.       }
  472.       if (seg->seg.box.right < right) {
  473.         seg->seg.box.right = right;
  474.       }
  475.       if (seg->seg.box.bottom > bottom) {
  476.         seg->seg.box.bottom = bottom;
  477.       }
  478.       if (seg->base.code == SEGMENT) {
  479.         AdjustParent ((SegmenT) seg->seg.parent, left, top, right, bottom);
  480.       }
  481.     } else {
  482.       Message (MSG_ERROR, "AdjustParent argument not a segment or picture");
  483.     }
  484.   } else {
  485.     Message (MSG_ERROR, "AdjustParent sent a null parent");
  486.   }
  487. }
  488.  
  489. /*****************************************************************************
  490. *
  491. *   AdjustMargin (parent, left, top, right, bottom)
  492. *       Recalculates segment margin, propagates up parent list
  493. *
  494. *****************************************************************************/
  495.  
  496. static void AdjustMargin (SegmenT parent, Int2 left, Int2 top, Int2 right, Int2 bottom)
  497.  
  498. {
  499.   SegPPtr  seg;
  500.  
  501.   if (parent != NULL) {
  502.     seg = (SegPPtr) parent;
  503.     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
  504.       if (seg->seg.margin.left > left) {
  505.         seg->seg.margin.left = left;
  506.       }
  507.       if (seg->seg.margin.top > top) {
  508.         seg->seg.margin.top = top;
  509.       }
  510.       if (seg->seg.margin.right < right) {
  511.         seg->seg.margin.right = right;
  512.       }
  513.       if (seg->seg.margin.bottom < bottom) {
  514.         seg->seg.margin.bottom = bottom;
  515.       }
  516.       if (seg->base.code == SEGMENT) {
  517.         AdjustMargin ((SegmenT) seg->seg.parent, left, top, right, bottom);
  518.       }
  519.     } else {
  520.       Message (MSG_ERROR, "AdjustMargin argument not a segment or picture");
  521.     }
  522.   } else {
  523.     Message (MSG_ERROR, "AdjustMargin sent a null parent");
  524.   }
  525. }
  526.  
  527. /*****************************************************************************
  528. *
  529. *   AddAttribute (parent, flags, color, linestyle, shading, penwidth, mode)
  530. *       Changes current attribute settings (applied only to lower levels)
  531. *
  532. *****************************************************************************/
  533.  
  534. void AddAttribute (SegmenT parent, Uint1 flags, Uint1Ptr color,
  535.                    Int1 linestyle, Int1 shading, Int1 penwidth, Int1 mode)
  536.  
  537. {
  538.   AttPPtr  att;
  539.   SegPPtr  prnt;
  540.  
  541.   att = (AttPPtr) CreatePrimitive (parent, ATTRIBUTE, sizeof (AttPRec));
  542.   if (att != NULL) {
  543.     if (linestyle >= NO_LINE_STYLE && linestyle <= DASHED_LINE) {
  544.       if (shading >= NO_SHADING && shading <= EMPTY_SHADING) {
  545.         att->att.flags = flags;
  546.         if (color != NULL) {
  547.           att->att.color [0] = color [0];
  548.           att->att.color [1] = color [1];
  549.           att->att.color [2] = color [2];
  550.         } else {
  551.           att->att.color [0] = BLACK_COLOR [0];
  552.           att->att.color [1] = BLACK_COLOR [1];
  553.           att->att.color [2] = BLACK_COLOR [2];
  554.         }
  555.         att->att.linestyle = linestyle;
  556.         att->att.shading = shading;
  557.         att->att.penwidth = MIN (penwidth, PEN_MAX);
  558.         att->att.mode = mode;
  559.         att->att.highlight = PLAIN_SEGMENT;
  560.         prnt = (SegPPtr) parent;
  561.         if (prnt != NULL) {
  562.           prnt->seg.penwidth = penwidth;
  563.         }
  564.       } else {
  565.         Message (MSG_ERROR, "AddAttribute shading out of range");
  566.       }
  567.     } else {
  568.       Message (MSG_ERROR, "AddAttribute line style out of range");
  569.     }
  570.   }
  571. }
  572.  
  573. /*****************************************************************************
  574. *
  575. *   AddRectangle (parent, left, top, right, bottom, arrow, fill, primID)
  576. *
  577. *****************************************************************************/
  578.  
  579. PrimitivE AddRectangle (SegmenT parent, Int4 left, Int4 top, Int4 right,
  580.                         Int4 bottom, Int2 arrow, Boolean fill, Uint2 primID)
  581.  
  582. {
  583.   Int2     align;
  584.   Int2     height;
  585.   RecT     rct;
  586.   RecPPtr  rec;
  587.   Int4     swap;
  588.   Int2     width;
  589.  
  590.   rec = (RecPPtr) CreatePrimitive (parent, RECTANGLE, sizeof (RecPRec));
  591.   if (rec != NULL) {
  592.     if (arrow >= NO_ARROW && arrow <= DOWN_ARROW) {
  593.       if (left > right) {
  594.         swap = left;
  595.         left = right;
  596.         right = swap;
  597.       }
  598.       if (bottom > top) {
  599.         swap = bottom;
  600.         bottom = top;
  601.         top = swap;
  602.       }
  603.       rec->box.left = left;
  604.       rec->box.top = top;
  605.       rec->box.right = right;
  606.       rec->box.bottom = bottom;
  607.       rec->arrow = arrow;
  608.       rec->fill = fill;
  609.       rec->highlight = PLAIN_PRIMITIVE;
  610.       rec->primID = primID;
  611.       align = 0;
  612.       width = 6;
  613.       height = 6;
  614.       switch (arrow) {
  615.         case NO_ARROW :
  616.           align = MIDDLE_CENTER;
  617.           break;
  618.         case LEFT_ARROW :
  619.           align = MIDDLE_LEFT;
  620.           width = ARROW_PIXELS + ARROW_OVERHANG;
  621.           break;
  622.         case RIGHT_ARROW :
  623.           align = MIDDLE_RIGHT;
  624.           width = ARROW_PIXELS + ARROW_OVERHANG;
  625.           break;
  626.         case UP_ARROW :
  627.           align = UPPER_CENTER;
  628.           height = ARROW_PIXELS + ARROW_OVERHANG;
  629.           break;
  630.         case DOWN_ARROW :
  631.           align = LOWER_CENTER;
  632.           height = ARROW_PIXELS + ARROW_OVERHANG;
  633.           break;
  634.         default :
  635.           break;
  636.       }
  637.       MapToRect (&rct, emptyPt, width, height, 0, align);
  638.       rec->rct = rct;
  639.       AdjustParent (parent, left, top, right, bottom);
  640.       AdjustMargin (parent, rct.left, rct.top, rct.right, rct.bottom);
  641.     } else {
  642.       Message (MSG_ERROR, "AddRectangle arrow out of range");
  643.     }
  644.   }
  645.   return (PrimitivE) rec;
  646. }
  647.  
  648. /*****************************************************************************
  649. *
  650. *   AddLine (parent, pnt1X, pnt1Y, pnt2X, pnt2Y, arrow, primID)
  651. *
  652. *****************************************************************************/
  653.  
  654. PrimitivE AddLine (SegmenT parent, Int4 pnt1X, Int4 pnt1Y,
  655.                    Int4 pnt2X, Int4 pnt2Y, Boolean arrow, Uint2 primID)
  656.  
  657. {
  658.   Int2     length;
  659.   LinPPtr  lin;
  660.   RecT     rct;
  661.   SegPPtr  seg;
  662.  
  663.   lin = (LinPPtr) CreatePrimitive (parent, LINE, sizeof (LinPRec));
  664.   if (lin != NULL) {
  665.     lin->pnt1.x = pnt1X;
  666.     lin->pnt1.y = pnt1Y;
  667.     lin->pnt2.x = pnt2X;
  668.     lin->pnt2.y = pnt2Y;
  669.     lin->arrow = arrow;
  670.     lin->highlight = PLAIN_PRIMITIVE;
  671.     lin->primID = primID;
  672.     seg = (SegPPtr) parent;
  673.     if (arrow) {
  674.       length = (ARROW_LENGTH + seg->seg.penwidth) * 2;
  675.     } else {
  676.       length = seg->seg.penwidth * 2;
  677.     }
  678.     MapToRect (&rct, emptyPt, length, length, 0, MIDDLE_CENTER);
  679.     lin->rct = rct;
  680.     AdjustParent (parent, MIN (pnt1X, pnt2X), MAX (pnt1Y, pnt2Y),
  681.                   MAX (pnt1X, pnt2X), MIN (pnt1Y, pnt2Y));
  682.     AdjustMargin (parent, rct.left, rct.top, rct.right, rct.bottom);
  683.   }
  684.   return (PrimitivE) lin;
  685. }
  686.  
  687. /*****************************************************************************
  688. *
  689. *   AddSymbol (parent, pntX, pntY, symbol, fill, align, primID)
  690. *
  691. *****************************************************************************/
  692.  
  693. static Uint1 rectSym [] = {
  694.   0xFE, 0x82, 0x82, 0x82, 0x82, 0x82, 0xFE, 0x00
  695. };
  696. static Uint1 diamondSym [] = {
  697.   0x10, 0x28, 0x44, 0x82, 0x44, 0x28, 0x10, 0x00
  698. };
  699. static Uint1 ovalSym [] = {
  700.   0x38, 0x44, 0x82, 0x82, 0x82, 0x44, 0x38, 0x00
  701. };
  702. static Uint1 leftTriSym [] = {
  703.   0x06, 0x1A, 0x62, 0x82, 0x62, 0x1A, 0x06, 0x00
  704. };
  705. static Uint1 rightTriSym [] = {
  706.   0xC0, 0xB0, 0x8C, 0x82, 0x8C, 0xB0, 0xC0, 0x00
  707. };
  708. static Uint1 upTriSym [] = {
  709.   0x10, 0x28, 0x28, 0x44, 0x44, 0x82, 0xFE, 0x00
  710. };
  711. static Uint1 downTriSym [] = {
  712.   0xFE, 0x82, 0x44, 0x44, 0x28, 0x28, 0x10, 0x00
  713. };
  714. static Uint1 rectFillSym [] = {
  715.   0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0x00
  716. };
  717. static Uint1 diamondFillSym [] = {
  718.   0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00
  719. };
  720. static Uint1 ovalFillSym [] = {
  721.   0x38, 0x7C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x00
  722. };
  723. static Uint1 leftTriFillSym [] = {
  724.   0x06, 0x1E, 0x7E, 0xFE, 0x7E, 0x1E, 0x06, 0x00
  725. };
  726. static Uint1 rightTriFillSym [] = {
  727.   0xC0, 0xF0, 0xFC, 0xFE, 0xFC, 0xF0, 0xC0, 0x00
  728. };
  729. static Uint1 upTriFillSym [] = {
  730.   0x10, 0x38, 0x38, 0x7C, 0x7C, 0xFE, 0xFE, 0x00
  731. };
  732. static Uint1 downTriFillSym [] = {
  733.   0xFE, 0xFE, 0x7C, 0x7C, 0x38, 0x38, 0x10, 0x00
  734. };
  735.  
  736. static Uint1Ptr symbolList [] = {
  737.   rectSym, diamondSym, ovalSym, leftTriSym,
  738.   rightTriSym, upTriSym, downTriSym,
  739.   rectFillSym, diamondFillSym, ovalFillSym, leftTriFillSym,
  740.   rightTriFillSym, upTriFillSym, downTriFillSym
  741. };
  742.  
  743. PrimitivE AddSymbol (SegmenT parent, Int4 pntX, Int4 pntY,
  744.                      Int2 symbol, Boolean fill, Int2 align, Uint2 primID)
  745.  
  746. {
  747.   Int2     index;
  748.   RecT     rct;
  749.   SymPPtr  sym;
  750.  
  751.   sym = (SymPPtr) CreatePrimitive (parent, SYMBOL, sizeof (SymPRec));
  752.   if (sym != NULL) {
  753.     if (align >= MIDDLE_CENTER && align <= MIDDLE_RIGHT) {
  754.       if (symbol >= RECT_SYMBOL && symbol <= DOWN_TRIANGLE_SYMBOL) {
  755.         sym->pnt.x = pntX;
  756.         sym->pnt.y = pntY;
  757.         MapToRect (&rct, emptyPt, SYMBOL_WIDTH, SYMBOL_HEIGHT, 0, align);
  758.         sym->rct = rct;
  759.         index = symbol - RECT_SYMBOL;
  760.         if (fill) {
  761.           index += 7;
  762.         }
  763.         sym->data = symbolList [index];
  764.         sym->primID = primID;
  765.         AdjustParent (parent, pntX, pntY, pntX, pntY);
  766.         AdjustMargin (parent, rct.left, rct.top, rct.right, rct.bottom);
  767.       } else {
  768.         Message (MSG_ERROR, "AddSymbol symbol out of range");
  769.       }
  770.     } else {
  771.       Message (MSG_ERROR, "AddSymbol alignment out of range");
  772.     }
  773.   }
  774.   return (PrimitivE) sym;
  775. }
  776.  
  777. /*****************************************************************************
  778. *
  779. *   AddBitmap (parent, pntX, pntY, width, height, data, align, primID)
  780. *
  781. *****************************************************************************/
  782.  
  783. PrimitivE AddBitmap (SegmenT parent, Int4 pntX, Int4 pntY, Int2 width,
  784.                      Int2 height, Uint1Ptr data, Int2 align, Uint2 primID)
  785.  
  786. {
  787.   BtmPPtr  btm;
  788.   RecT     rct;
  789.  
  790.   btm = (BtmPPtr) CreatePrimitive (parent, BITMAP, sizeof (BtmPRec));
  791.   if (btm != NULL) {
  792.     if (align >= MIDDLE_CENTER && align <= MIDDLE_RIGHT) {
  793.       btm->pnt.x = pntX;
  794.       btm->pnt.y = pntY;
  795.       MapToRect (&rct, emptyPt, width, height, 0, align);
  796.       btm->rct = rct;
  797.       btm->data = data;
  798.       btm->primID = primID;
  799.       AdjustParent (parent, pntX, pntY, pntX, pntY);
  800.       AdjustMargin (parent, rct.left, rct.top, rct.right, rct.bottom);
  801.     } else {
  802.       Message (MSG_ERROR, "AddBitmap alignment out of range");
  803.     }
  804.   }
  805.   return (PrimitivE) btm;
  806. }
  807.  
  808. /*****************************************************************************
  809. *
  810. *   AddCustom (parent, pntX, pntY, width, height, proc, align, primID)
  811. *
  812. *****************************************************************************/
  813.  
  814. PrimitivE AddCustom (SegmenT parent, Int4 pntX, Int4 pntY, Int2 width,
  815.                      Int2 height, CustomProc proc, Int2 align, Uint2 primID)
  816.  
  817. {
  818.   CstPPtr  cst;
  819.   RecT     rct;
  820.  
  821.   cst = (CstPPtr) CreatePrimitive (parent, CUSTOM, sizeof (CstPRec));
  822.   if (cst != NULL) {
  823.     if (align >= MIDDLE_CENTER && align <= MIDDLE_RIGHT) {
  824.       cst->pnt.x = pntX;
  825.       cst->pnt.y = pntY;
  826.       MapToRect (&rct, emptyPt, width, height, 0, align);
  827.       cst->rct = rct;
  828.       cst->proc = proc;
  829.       cst->primID = primID;
  830.       AdjustParent (parent, pntX, pntY, pntX, pntY);
  831.       AdjustMargin (parent, rct.left, rct.top, rct.right, rct.bottom);
  832.     } else {
  833.       Message (MSG_ERROR, "AddCustom alignment out of range");
  834.     }
  835.   }
  836.   return (PrimitivE) cst;
  837. }
  838.  
  839. /*****************************************************************************
  840. *
  841. *   AddMarker (parent, pntX, pntY, length, orient, primID)
  842. *
  843. *****************************************************************************/
  844.  
  845. PrimitivE AddMarker (SegmenT parent, Int4 pntX, Int4 pntY,
  846.                      Int2 length, Int2 orient, Uint2 primID)
  847.  
  848. {
  849.   Int2     align;
  850.   Int2     height;
  851.   MrkPPtr  mrk;
  852.   RecT     rct;
  853.   Int2     width;
  854.  
  855.   mrk = (MrkPPtr) CreatePrimitive (parent, MARKER, sizeof (MrkPRec));
  856.   if (mrk != NULL) {
  857.     if (orient >= HORIZ_LEFT && orient <= VERT_BELOW) {
  858.       mrk->pnt.x = pntX;
  859.       mrk->pnt.y = pntY;
  860.       align = 0;
  861.       width = 0;
  862.       height = 0;
  863.       switch (orient) {
  864.         case HORIZ_LEFT :
  865.           align = MIDDLE_LEFT;
  866.           width = length;
  867.           break;
  868.         case HORIZ_CENTER :
  869.           align = MIDDLE_CENTER;
  870.           width = length;
  871.           break;
  872.         case HORIZ_RIGHT :
  873.           align = MIDDLE_RIGHT;
  874.           width = length;
  875.           break;
  876.         case VERT_ABOVE :
  877.           align = UPPER_CENTER;
  878.           height = length;
  879.           break;
  880.         case VERT_MIDDLE :
  881.           align = MIDDLE_CENTER;
  882.           height = length;
  883.           break;
  884.         case VERT_BELOW :
  885.           align = LOWER_CENTER;
  886.           height = length;
  887.           break;
  888.         default :
  889.           break;
  890.       }
  891.       MapToRect (&rct, emptyPt, width, height, 0, align);
  892.       mrk->rct = rct;
  893.       mrk->primID = primID;
  894.       AdjustParent (parent, pntX, pntY, pntX, pntY);
  895.       AdjustMargin (parent, rct.left, rct.top, rct.right, rct.bottom);
  896.     } else {
  897.       Message (MSG_ERROR, "AddMarker orientation out of range");
  898.     }
  899.   }
  900.   return (PrimitivE) mrk;
  901. }
  902.  
  903. /*****************************************************************************
  904. *
  905. *   AddLabel (parent, pntX, pntY, string, size, offset, align, primID)
  906. *
  907. *****************************************************************************/
  908.  
  909. PrimitivE AddLabel (SegmenT parent, Int4 pntX, Int4 pntY, CharPtr string,
  910.                     Int2 size, Int2 offset, Int2 align, Uint2 primID)
  911.  
  912. {
  913.   FonT     fnt;
  914.   LblPPtr  lbl;
  915.   RecT     rct;
  916.  
  917.   lbl = (LblPPtr) CreatePrimitive (parent, LABEL, sizeof (LblPRec));
  918.   if (lbl != NULL) {
  919.     if (align >= MIDDLE_CENTER && align <= MIDDLE_RIGHT) {
  920.       lbl->pnt.x = pntX;
  921.       lbl->pnt.y = pntY;
  922.       lbl->str = StringSave (string);
  923.       lbl->size = size;
  924.       switch (lbl->size) {
  925.         case SMALL_TEXT:
  926.           if (smallFont == NULL) {
  927.             SetSmallFont ();
  928.           }
  929.           fnt = smallFont;
  930.           break;
  931.         case MEDIUM_TEXT:
  932.           if (mediumFont == NULL) {
  933.             SetMediumFont ();
  934.           }
  935.           fnt = mediumFont;
  936.           break;
  937.         case LARGE_TEXT:
  938.           if (largeFont == NULL) {
  939.             SetLargeFont ();
  940.           }
  941.           fnt = largeFont;
  942.           break;
  943.         default :
  944.           fnt = programFont;
  945.           break;
  946.       }
  947.       SelectFont (fnt);
  948.       MapToRect (&rct, emptyPt, StringWidth (string) + 2,
  949.                  LineHeight (), offset, align);
  950.       lbl->rct = rct;
  951.       lbl->primID = primID;
  952.       AdjustParent (parent, pntX, pntY, pntX, pntY);
  953.       AdjustMargin (parent, rct.left, rct.top, rct.right, rct.bottom);
  954.     } else {
  955.       Message (MSG_ERROR, "AddLabel alignment out of range");
  956.     }
  957.   }
  958.   return (PrimitivE) lbl;
  959. }
  960.