NCBI C Toolkit Cross Reference

C/vibrant/drawing.c


  1 /*   drawing.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:  drawing.c
 27 *
 28 * Author:  Jonathan Kans, Alex Smirnov, Jill Shermer, Denis Vakatov
 29 *
 30 * Version Creation Date:   11/13/92
 31 *
 32 * $Revision: 6.16 $
 33 *
 34 * File Description: 
 35 *
 36 * Modifications:  
 37 * --------------------------------------------------------------------------
 38 * $Log: drawing.c,v $
 39 * Revision 6.16  2003/03/18 17:00:10  kans
 40 * Nlm_AddSilentSegRect does not absorb clicks, SegRect reverted to absorb clicks, so desktop click responsiveness is maintained
 41 *
 42 * Revision 6.15  2003/02/19 17:36:19  rsmith
 43 * SegRect (borders around a SegmenT) can not longer absorb clicks.
 44 *
 45 * Revision 6.14  2001/12/13 14:51:31  kans
 46 * DrawSegment calls SetPrimAttribute only if it will be drawing
 47 *
 48 * Revision 6.13  2000/10/25 20:47:17  vakatov
 49 * Rollback R6.10 (still may need add. fix for MS-Windows) [w/ V.Chetvernin]
 50 *
 51 * Revision 6.12  1999/10/04 17:16:30  kans
 52 * include ncbidraw.h instead of vibrant.h, a couple Nlm_ prefixes
 53 *
 54 * Revision 6.11  1998/07/01 18:27:39  vakatov
 55 * Use "const" qualifier somewhere
 56 *
 57 * Revision 6.10  1998/06/25 18:41:12  vakatov
 58 * s_DoRoundRect(): oval_[hc] -- multiply by 2 when using Paint/FrameRoundRect
 59 *
 60 * Revision 6.9  1998/06/15 22:07:44  vakatov
 61 * RecDrawProc(), RoRecDrawProc() -- do not add extra pixel to the
 62 * horiz. and vert. dimensions; thus get it in-sync with other primitives
 63 *
 64 * Revision 6.8  1998/06/01 17:29:18  vakatov
 65 * Extended rounded rect. options -- let it roundup only two(adjacent)
 66 * corners(see "flags" arg in Nlm_AddRoundedRectangle())
 67 *
 68 * Revision 6.7  1998/04/27 16:03:57  vakatov
 69 * Added rounded rectangles
 70 * Re-implemented the ovals -- dont emulate them by polygons anymore,
 71 * use the "native" drawing functions instead
 72 *
 73 * Revision 6.6  1997/12/16 18:38:39  kans
 74 * sentinel draw callback has draw info context parameter
 75 *
 76 * Revision 6.5  1997/12/15 18:10:46  kans
 77 * added cleanup data function to sentinel
 78 *
 79 * Revision 6.4  1997/11/19 17:38:09  kans
 80 * added ChangeSentinelRectangle
 81 *
 82 * Revision 6.3  1997/11/13 21:41:31  vakatov
 83 * Added "sentinel rectangle" primitive[Nlm_AddSntRectangle] which
 84 * calls its callback procedure[Nlm_SntOnDrawProc] on each redraw
 85 *
 86 * Revision 6.2  1997/10/30 20:01:40  vakatov
 87 * Added Nlm_PrimitiveBox()
 88 *
 89 * Revision 6.1  1997/09/16 18:56:54  vakatov
 90 * RecDrawProc():  setup WIDTH_ATT for non-filled rectangle
 91 *
 92 * Revision 5.4  1997/07/23 19:48:54  vakatov
 93 * Use Nlm_PaintStringEx function where non-display HDC can be used
 94 * (on MS-Win, MoveToEx()/GetCurrentPositionEx() don't work in this case)
 95 *
 96 * Revision 5.3  1997/05/08 14:05:21  vakatov
 97 * [WIN_MSWIN] PaintStringWin() is obsolete; replaced by MoveTo + PaintString
 98 *
 99  * Revision 5.2  1996/11/07  15:06:06  kans
100  * extra break needed
101  *
102  * Revision 5.1  1996/11/05  22:30:11  vakatov
103  * MakeAlignRect()/...Box():  Made the alignment be UPPER_LEFT by default
104  *
105  * Revision 4.7  1996/03/21  21:05:23  vakatov
106  * Arrow-rectangle FRAME_PRIMITIVE highlighting now merely
107  * draw a box embracing RECTANGLE or LINE primitive
108  *
109  * Revision 4.6  1996/03/15  19:49:52  vakatov
110  * Arrow-rectangle FRAME_PRIMITIVE highlighting corrected
111  *
112  * Revision 4.5  1995/11/17  20:44:48  smirnov
113  * Alex: fix DrawArc function.
114  *
115  * Revision 4.4  1995/11/09  16:35:55  kans
116  * removed static from AddArc
117  *
118  * Revision 4.3  1995/11/07  23:21:53  kans
119  * moved Nlm_DrawSegment from viewer.c to drawing.c (for GIF without Vibrant)
120  *
121  * Revision 4.1  1995/09/12  00:39:10  ostell
122  * changes for text to appear in windows metafiles
123  *
124 * ==========================================================================
125 */
126 
127 #ifndef _NCBIDRAW_
128 #include <ncbidraw.h>
129 #endif
130 
131 #ifndef _PICTURE_
132 #include <picture.h>
133 #endif
134 
135 #ifndef _PICTUREP_
136 #include <picturep.h>
137 #endif
138 
139 #ifndef _MAPPINGP_
140 #include <mappingp.h>
141 #endif
142 
143 #ifndef _DRAWINGP_
144 #include <drawingp.h>
145 #endif
146 
147 #ifndef _VIEWERP_
148 #include <viewerp.h>
149 #endif
150 
151 /*****************************************************************************
152 *
153 *   DEFINES
154 *
155 *****************************************************************************/
156 #define ARROWWIDTH2 36
157 
158 /*****************************************************************************
159 *
160 *   EXTERNAL VARIABLES
161 *
162 *****************************************************************************/
163 FonT  smallFont = NULL;
164 FonT  mediumFont = NULL;
165 FonT  largeFont = NULL;
166 
167 AttPData blackAttPData = 
168 { {0,0,0}, SOLID_LINE, SOLID_SHADING, STD_PEN_WIDTH, COPY_MODE };
169 AttPData whiteAttPData = 
170 { {255,255,255}, SOLID_LINE, SOLID_SHADING, STD_PEN_WIDTH, COPY_MODE };
171 
172 /*****************************************************************************
173 *
174 *   STATIC VARIABLES
175 *
176 *****************************************************************************/
177 static Int1 sin100[91] = {
178 0,2,3,5,7,9,10,12,14,16,17,19,21,22,24,26,28,29,31,33,34,36,37,39,41,42,
179 44,45,47,48,50,51,53,54,56,57,59,60,62,63,64,66,67,68,69,71,72,73,74,75,
180 77,78,79,80,81,82,83,84,85,86,87,87,88,89,90,91,91,92,93,93,94,95,95,96,
181 96,97,97,97,98,98,98,99,99,99,99,100,100,100,100,100,100 };
182 
183 static Int1 atan100[101] = {
184 0,1,1,2,2,3,3,4,5,5,6,6,7,7,8,9,9,10,10,11,11,12,12,13,13,14,15,15,16,16,17,
185 17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25,25,26,26,27,27,27,28,28,29,
186 29,30,30,31,31,31,32,32,33,33,33,34,34,35,35,35,36,36,37,37,37,38,38,38,39,
187 39,39,40,40,40,41,41,41,42,42,42,43,43,43,44,44,44,44,45,45 };
188 
189 static PoinT polyPoints[362];
190 
191 static Uint1  thinNews [] = {
192   0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88
193 };
194 static Uint1  thinNwse [] = {
195   0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11
196 };
197 static Uint1  thickNews [] = {
198   0x33, 0x66, 0xCC, 0x99, 0x33, 0x66, 0xCC, 0x99
199 };
200 static Uint1  thickNwse [] = {
201   0x99, 0xCC, 0x66, 0x33, 0x99, 0xCC, 0x66, 0x33
202 };
203 static Uint1  thinHoriz [] = {
204   0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00
205 };
206 static Uint1  thinVert [] = {
207   0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11
208 };
209 static Uint1  thickHoriz [] = {
210   0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00
211 };
212 static Uint1  thickVert [] = {
213   0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33
214 };
215 
216 #ifdef WIN_MAC
217 static Int1 userArrowSize = 10;
218 #endif
219 #ifdef WIN_MSWIN
220 static Int1 userArrowSize = 7;
221 #endif
222 #ifdef WIN_MOTIF
223 static Int1 userArrowSize = 10;
224 #endif
225 
226 /*****************************************************************************
227 *
228 *   SetXXXFont (void)
229 *       Creates fonts of various sizes.
230 *
231 *****************************************************************************/
232 
233 FonT SetSmallFont (void)
234 
235 {
236   if (smallFont == NULL) {
237 #ifdef WIN_MAC
238     smallFont = ParseFont ("Monaco,9");
239 #endif
240 #ifdef WIN_MSWIN
241     smallFont = ParseFont ("Courier,9");
242 #endif
243 #ifdef WIN_MOTIF
244     smallFont = ParseFont ("Courier,12");
245 #endif
246   }
247   return smallFont;
248 }
249 
250 FonT SetMediumFont (void)
251 
252 {
253   if (mediumFont == NULL) {
254 #ifdef WIN_MAC
255     mediumFont = ParseFont ("Monaco,12");
256 #endif
257 #ifdef WIN_MSWIN
258     mediumFont = ParseFont ("Courier,12");
259 #endif
260 #ifdef WIN_MOTIF
261     mediumFont = ParseFont ("Courier,14");
262 #endif
263   }
264   return mediumFont;
265 }
266 
267 FonT SetLargeFont (void)
268 
269 {
270   if (largeFont == NULL) {
271 #ifdef WIN_MAC
272     largeFont = ParseFont ("Monaco,18");
273 #endif
274 #ifdef WIN_MSWIN
275     largeFont = ParseFont ("Courier,18");
276 #endif
277 #ifdef WIN_MOTIF
278     largeFont = ParseFont ("Courier,18");
279 #endif
280   }
281   return largeFont;
282 }
283 
284 /*****************************************************************************
285 *
286 *   DISPATCHERS FOR GENERIC PRIMITIVE OPERATIONS
287 *
288 *****************************************************************************/
289 
290 /*****************************************************************************
291 *
292 *   GetPrimDrawAttribute (primdrawcontect, ...)
293 *      helper function for PrimDrawProc
294 *
295 *****************************************************************************/
296 
297 void Nlm_GetPrimDrawAttribute (PrimitivE prim, 
298                            Uint1Ptr color, Int1Ptr plinestyle,
299                            Int1Ptr pshading, Int1Ptr ppenwidth,
300                            Int1Ptr pmode, Int1Ptr phighlight)
301 {
302   AttPData* atts;
303 
304   if (prim != NULL ) {
305     atts = &(((GenPPtr)prim)->att);
306     if (color != NULL) {
307       color[0] = atts->color[0];
308       color[1] = atts->color[1];
309       color[2] = atts->color[2];
310     }
311     if (plinestyle != NULL) *plinestyle = atts->linestyle;
312     if (pshading != NULL) *pshading = atts->shading;
313     if (ppenwidth != NULL) *ppenwidth = atts->penwidth;
314     if (pmode != NULL) *pmode = atts->mode;
315     if (phighlight != NULL) *phighlight = ((GenPPtr)prim)->highlight;
316   }
317 }
318 
319 /*****************************************************************************
320 *
321 *    HELPER FUNCTIONS
322 *
323 *****************************************************************************/
324 Nlm_BoxPtr Nlm_GetWorldWindow (Nlm_PrimDrawContext pdc) {
325   if ( pdc != NULL ){
326     return ( &(((DrawInfoPtr)pdc)->scale.worldWindow) );
327   }
328   return NULL;
329 }
330 
331 Int4 Nlm_GetScaleX (PrimDrawContext pdc){
332   if ( pdc != NULL ){
333     return ( ((DrawInfoPtr)pdc)->scale.scaleX );
334   }
335   return 0;
336 }
337 
338 Int4 Nlm_GetScaleY (Nlm_PrimDrawContext pdc){
339   if ( pdc != NULL ){
340     return ( ((DrawInfoPtr)pdc)->scale.scaleY );
341   }
342   return 0;
343 }
344 
345 Int4 Nlm_GetOffsetX (PrimDrawContext pdc){
346   if ( pdc != NULL ){
347     return ( ((DrawInfoPtr)pdc)->scale.offsetX );
348   }
349   return 0;
350 }
351 
352 Int4 Nlm_GetOffsetY (PrimDrawContext pdc){
353   if ( pdc != NULL ){
354     return ( ((DrawInfoPtr)pdc)->scale.offsetY );
355   }
356   return 0;
357 }
358 
359 Boolean Nlm_isPrimInWindow (PrimDrawContext pdc){
360   if ( pdc != NULL ){
361     return ( ((DrawInfoPtr)pdc)->checked );
362   }
363   return FALSE;
364 }
365 
366 Int1 Nlm_GetPrimHligh (PrimDrawContext pdc){
367   if ( pdc != NULL ){
368     return ( ((DrawInfoPtr)pdc)->highlight );
369   }
370   return PLAIN_SEGMENT;
371 }
372 
373 BoxPtr Nlm_GetHitWindow (PrimHitContext phc){
374   if ( phc != NULL ){
375     return ( &(((ScalePtr)phc)->worldWindow) );
376   }
377   return NULL;
378 }
379 
380 void Nlm_SetPrimAttribute (PrimDrawContext pdc, Nlm_Uint1 flags ){
381   AttPPtr atts;
382 
383   if (pdc != NULL) {
384     atts = ((DrawInfoPtr)pdc)->primattrib;
385     if ( flags & COLOR_ATT ) {
386       SelectColor (atts->color [0], atts->color [1], atts->color [2]);
387     }
388     if ( flags & WIDTH_ATT ){
389       WidePen (atts->penwidth);
390     }
391     if ( flags & STYLE_ATT ) {
392       switch (atts->linestyle) {
393         case SOLID_LINE :
394           Solid ();
395           break;
396         case DOTTED_LINE :
397           Dotted ();
398           break;
399         case DASHED_LINE :
400           Dashed ();
401       }
402     }
403     if ( flags & SHADING_ATT ) {
404       switch (atts->shading) {
405         case SOLID_SHADING :
406           Solid ();
407           break;
408         case DARK_SHADING :
409           Dark ();
410           break;
411         case MEDIUM_SHADING :
412           Medium ();
413           break;
414         case LIGHT_SHADING :
415           Light ();
416           break;
417         case EMPTY_SHADING :
418           Empty ();
419           break;
420         case THIN_HORIZ_SHADING :
421           SetPenPattern (thinHoriz);
422           break;
423         case THIN_VERT_SHADING :
424           SetPenPattern (thinVert);
425           break;
426         case THICK_HORIZ_SHADING :
427           SetPenPattern (thickHoriz);
428           break;
429         case THICK_VERT_SHADING :
430           SetPenPattern (thickVert);
431           break;
432         case THIN_NESW_SHADING :
433           SetPenPattern (thinNews);
434           break;
435         case THIN_NWSE_SHADING :
436           SetPenPattern (thinNwse);
437           break;
438         case THICK_NESW_SHADING :
439           SetPenPattern (thickNews);
440           break;
441         case THICK_NWSE_SHADING :
442           SetPenPattern (thickNwse);
443       }
444     }
445     if ( flags & MODE_ATT ) {
446       switch (atts->mode) {
447         case COPY_MODE :
448           CopyMode ();
449           break;
450         case MERGE_MODE :
451           MergeMode ();
452           break;
453         case INVERT_MODE :
454           InvertMode ();
455           break;
456         case ERASE_MODE :
457           EraseMode ();
458       }
459     }
460   }
461 }
462 
463 void Nlm_RestorePrimAttribute (PrimDrawContext pdc){
464   Nlm_SetPrimAttribute (pdc, (Uint1)0xFF);
465 }
466 
467 /*****************************************************************************
468 *
469 *     OPERATIONS ON PRIMITIVES
470 *
471 *****************************************************************************/
472 /*****************************************************************************
473 *
474 *   Set Arrow Size
475 *
476 *****************************************************************************/
477 void Nlm_SetDefArrowSize ( Int1 arrowSize )
478 {
479   if ( arrowSize < 4 ) arrowSize = 4;
480   if ( arrowSize > 16 ) arrowSize = 16;
481   userArrowSize = arrowSize;
482 }
483 
484 static void MakeAlignRect ( Int2 x, Int2 y, Int2 width, Int2 height, 
485                             Int2 offset, Int2 align, RectPtr rPtr )
486 {
487   RecT r;
488 
489   switch (align) {
490     case UPPER_CENTER :
491       r.left = x - (width>>1); r.top = y - height - offset;
492       break;
493     case UPPER_RIGHT :
494       r.left = x + offset; r.top = y - height - offset;
495       break;
496     case MIDDLE_LEFT :
497       r.left = x - width - offset; r.top = y - (height>>1);
498       break;
499     case MIDDLE_CENTER :
500       r.left = x - (width>>1); r.top = y - (height>>1);
501       break;
502     case MIDDLE_RIGHT :
503       r.left = x + offset; r.top = y - (height>>1);
504       break;
505     case LOWER_LEFT :
506       r.left = x - width - offset; r.top = y + offset;
507       break;
508     case LOWER_CENTER :
509       r.left = x - (width>>1); r.top = y + offset;
510       break;
511     case LOWER_RIGHT :
512       r.left = x + offset; r.top = y + offset;
513       break;
514     case UPPER_LEFT :
515     default:
516       r.left = x - width - offset; r.top = y - height - offset;
517       break;
518   }
519   r.right = r.left + width; r.bottom = r.top + height;
520   *rPtr = r;
521 }
522 
523 static void MakeAlignBox ( Int4 x, Int4 y, Int4 width, Int4 height, 
524                            Int4 offsetX, Int4 offsetY, Int2 align, 
525                            BoxPtr boxPtr )
526 {
527   BoxInfo box;
528 
529   switch (align) {
530     case UPPER_CENTER :
531       box.left = x - (width>>1); box.top = y + height + offsetY;
532       break;
533     case UPPER_RIGHT :
534       box.left = x + offsetX; box.top = y + height + offsetY;
535       break;
536     case MIDDLE_LEFT :
537       box.left = x - width - offsetX; box.top = y + (height>>1);
538       break;
539     case MIDDLE_CENTER :
540       box.left = x - (width>>1); box.top = y + (height>>1);
541       break;
542     case MIDDLE_RIGHT :
543       box.left = x + offsetX; box.top = y + (height>>1);
544       break;
545     case LOWER_LEFT :
546       box.left = x - width - offsetX; box.top = y - offsetY;
547       break;
548     case LOWER_CENTER :
549       box.left = x - (width>>1); box.top = y - offsetY;
550       break;
551     case LOWER_RIGHT :
552       box.left = x + offsetX; box.top = y - offsetY;
553       break;
554     case UPPER_LEFT :
555     default:
556       box.left = x - width - offsetX; box.top = y + height + offsetY;
557       break;
558   }
559   box.right = box.left + width; box.bottom = box.top - height;
560   *boxPtr = box;
561 }
562 
563 /*****************************************************************************
564 *
565 *   DrawPrimitive (item, scale)
566 *       Draws a primitive
567 *
568 *****************************************************************************/
569 
570 void Nlm_DrawPrimitive (BasePPtr item, DrawInfoPtr drawinfo)
571 {
572   PrimDefPtr pdp;
573 
574   if (item != NULL && drawinfo != NULL) {
575     switch (item->code) {
576       case GENERIC :
577         pdp = ((GenPPtr)item)->pdp;
578         if ( pdp != NULL && pdp->draw != NULL) {
579           pdp->draw ( &(((GenPPtr)item)->data), (PrimDrawContext)drawinfo);
580         }
581         break;
582       default :
583         Message (MSG_ERROR, "DrawPrimitive item unknown");
584         break;
585     }
586   }
587 }
588 
589 /*****************************************************************************
590 *
591 *   PrimitiveIsCloseToPoint (item, &id)
592 *
593 *****************************************************************************/
594 
595 Boolean Nlm_PrimitiveIsCloseToPoint (BasePPtr item, ScalePtr scale )
596 {
597   PrimDefPtr pdp;
598 
599   if (item != NULL && scale != NULL) {
600     switch (item->code) {
601       case GENERIC :
602         pdp = ((GenPPtr)item)->pdp;
603         if ( pdp != NULL && pdp->hittest != NULL) {
604           return pdp->hittest ( &(((GenPPtr)item)->data), 
605                                 (PrimHitContext)scale);
606         }
607         break;
608       default :
609         Message (MSG_ERROR, "PrimitiveIsCloseToPoint item unknown");
610         break;
611     }
612   }
613   return FALSE;
614 }
615 
616 /*****************************************************************************
617 *
618 *   TryHighlightPrimitive (item, highlight)
619 *
620 *****************************************************************************/
621 
622 Boolean Nlm_TryHighlightPrimitive (BasePPtr item, Int1 highlight)
623 {
624   if (item != NULL) {
625     switch (item->code) {
626       case GENERIC :
627         ((GenPPtr)item)->highlight = highlight;
628         return TRUE;
629       default:
630         Message (MSG_ERROR, "TryHighlightPrimitive item unknown");
631         break;
632     }
633   }
634   return FALSE;
635 }
636 
637 /*****************************************************************************
638 *
639 *   TryOffsetPrimitive (item, deltaX, deltaY)
640 *
641 *****************************************************************************/
642 
643 Boolean Nlm_TryOffsetPrimitive (BasePPtr item, Int4 deltaX, Int4 deltaY)
644 {
645   PrimDefPtr pdp;
646 
647   if (item != NULL) {
648     switch (item->code) {
649       case GENERIC :
650         pdp = ((GenPPtr)item)->pdp;
651         if ( pdp != NULL && pdp->offset != NULL) {
652           return pdp->offset ( &(((GenPPtr)item)->data), deltaX, deltaY);
653         }
654         break;
655       default:
656         Message (MSG_ERROR, "TryOffsetPrimitive item unknown");
657         break;
658     }
659   }
660   return FALSE;
661 }
662 
663 /*****************************************************************************
664 *
665 * TryGetPrimitiveLimits (item, scaleX, scaleY, pLimits)
666 *
667 *****************************************************************************/
668 Nlm_Boolean Nlm_TryGetPrimitiveLimits (Nlm_BasePPtr item, Nlm_Int4 scaleX, 
669                                        Nlm_Int4 scaleY, Nlm_BoxPtr pLimits)
670 {
671   PrimDefPtr pdp;
672 
673   if (item != NULL) {
674     switch (item->code) {
675       case GENERIC :
676         pdp = ((GenPPtr)item)->pdp;
677         if ( pdp != NULL && pdp->getlimits != NULL) {
678           return pdp->getlimits ( &(((GenPPtr)item)->data), scaleX, scaleY,
679                                   pLimits );
680         }
681         break;
682       default:
683         Message (MSG_ERROR, "TryOffsetPrimitive item unknown");
684         break;
685     }
686   }
687   return FALSE;
688 }
689 
690 extern Nlm_Boolean Nlm_PrimitiveBox(Nlm_PrimitivE prim,
691                                     Nlm_Int4 scaleX, Nlm_Int4 scaleY,
692                                     Nlm_BoxPtr pBox) {
693   return Nlm_TryGetPrimitiveLimits((Nlm_BasePPtr)prim, scaleX, scaleY, pBox);
694 }
695 
696 
697 /*****************************************************************************
698 *
699 *   CleanupPrimitive (item)
700 *       Deleted all data, owned by primitive
701 *
702 *****************************************************************************/
703 
704 void Nlm_CleanupPrimitive (BasePPtr item)
705 {
706   PrimDefPtr pdp;
707 
708   if (item != NULL) {
709     switch (item->code) {
710       case GENERIC :
711         pdp = ((GenPPtr)item)->pdp;
712         if ( pdp != NULL && pdp->cleanup != NULL) {
713           pdp->cleanup ( &(((GenPPtr)item)->data) );
714         }
715         break;
716       default:
717         Message (MSG_ERROR, "CleanupPrimitive item unknown");
718         break;
719     }
720   }
721 }
722 
723 /*****************************************************************************
724 *
725 *     PRIMITIVES
726 *
727 *****************************************************************************/
728 
729 /*****************************************************************************
730 *
731 *     INVISIBLE FRAME
732 *
733 *****************************************************************************/
734 
735 typedef struct frampdata {
736   BoxInfo  box;
737 } FramPData, PNTR FramPDataPtr;
738 
739 static Boolean FramHitTestProc ( FramPDataPtr pdata, PrimHitContext phc)
740 {
741   register ScalePtr dInfoPtr;
742  
743   dInfoPtr = (ScalePtr)phc;
744   if ( (pdata->box.left < dInfoPtr->worldWindow.right) && 
745        (pdata->box.right > dInfoPtr->worldWindow.left) &&
746        (pdata->box.top > dInfoPtr->worldWindow.bottom) &&
747        (pdata->box.bottom < dInfoPtr->worldWindow.top) ) return TRUE; 
748   return FALSE; 
749 }
750 
751 static Boolean FramOffsetProc ( FramPDataPtr pdata, Int4 deltaX, 
752                                 Int4 deltaY )
753 {
754   pdata->box.left += deltaX;
755   pdata->box.right += deltaX;
756   pdata->box.top += deltaY;
757   pdata->box.bottom += deltaY;
758   return TRUE; 
759 }
760 
761 static Boolean FramGetLimitsProc ( FramPDataPtr pdata, Int4 scaleX,
762                                    Int4 scaleY, BoxPtr pLimits )
763 {
764   *pLimits = pdata->box;
765   return TRUE; 
766 }
767 
768 static PrimDef framPrimDef = {
769   (PrimDrawProc) NULL,
770   (PrimHitTestProc) FramHitTestProc,
771   (PrimOffsetProc) FramOffsetProc,
772   (PrimCleanupProc) NULL,
773   (PrimGetLimitsProc) FramGetLimitsProc
774 };
775 
776 /*****************************************************************************
777 *
778 *   AddInvFrame (parent, left, top, right, bottom, primID)
779 *
780 *****************************************************************************/
781 
782 PrimitivE AddInvFrame  (SegmenT parent, Int4 left, Int4 top, Int4 right,
783                         Int4 bottom, Uint2 primID)
784 {
785   FramPData data;
786   Int4 swap;
787 
788   if (left > right) {
789     swap = left;
790     left = right;
791     right = swap;
792   }
793   if (bottom > top) {
794     swap = bottom;
795     bottom = top;
796     top = swap;
797   }
798   data.box.left = left;
799   data.box.top = top;
800   data.box.right = right;
801   data.box.bottom = bottom;
802   return AddPrimitive (&framPrimDef, parent, primID, (VoidPtr)&data,
803                        sizeof(FramPData));
804 }
805 
806 
807 /*****************************************************************************
808 *
809 *     RECTANGLE
810 *
811 *****************************************************************************/
812 
813 typedef struct recpdata {
814   BoxInfo  box;
815   Int2     arrow;
816   Int1     arrowSize;
817   Boolean  fill;
818 } RecPData, PNTR RecPDataPtr;
819 
820 
821 static void RecDrawProc (RecPDataPtr pdata, PrimDrawContext pdc)
822 {
823   register DrawInfoPtr dInfoPtr = (DrawInfoPtr)pdc;
824   BoxInfo tmpBox;
825   RecT    r;
826   Int4    curScale;
827   PoinT   pts [3];
828   Int1    arrowSize;
829   Boolean vis = TRUE;
830   RecT    rect;
831 
832   tmpBox = pdata->box;
833   if ( (tmpBox.left   > dInfoPtr->scale.worldWindow.right ) || 
834        (tmpBox.right  < dInfoPtr->scale.worldWindow.left  ) || 
835        (tmpBox.top    < dInfoPtr->scale.worldWindow.bottom) || 
836        (tmpBox.bottom > dInfoPtr->scale.worldWindow.top   ) )
837     return;
838   
839   if ( dInfoPtr->checked == FALSE ) {
840     if ( tmpBox.left < dInfoPtr->scale.worldWindow16.left ) 
841       tmpBox.left = dInfoPtr->scale.worldWindow16.left;
842     if ( tmpBox.right > dInfoPtr->scale.worldWindow16.right ) 
843       tmpBox.right = dInfoPtr->scale.worldWindow16.right;
844     if ( tmpBox.top > dInfoPtr->scale.worldWindow16.top ) 
845       tmpBox.top = dInfoPtr->scale.worldWindow16.top;
846     if ( tmpBox.bottom < dInfoPtr->scale.worldWindow16.bottom ) 
847       tmpBox.bottom = dInfoPtr->scale.worldWindow16.bottom;
848   }
849 
850   arrowSize = pdata->arrowSize;
851   curScale = dInfoPtr->scale.scaleX;
852   r.left   = (Int2)((dInfoPtr->scale.offsetX + tmpBox.left )  / curScale);
853   r.right  = (Int2)((dInfoPtr->scale.offsetX + tmpBox.right)  / curScale);
854   curScale = dInfoPtr->scale.scaleY;
855   r.top    = (Int2)((dInfoPtr->scale.offsetY - tmpBox.top   ) / curScale);
856   r.bottom = (Int2)((dInfoPtr->scale.offsetY - tmpBox.bottom) / curScale);
857 
858   /* calculate vertexes */
859   rect = r;
860 
861   switch ( pdata->arrow )
862     {
863       Int2 oldPoint;
864 
865     case LEFT_ARROW :
866       oldPoint = r.left;
867       if (r.right - r.left > (Int2)arrowSize) r.left += (Int2)arrowSize;
868       else r.left += (Int2)(arrowSize>>1); 
869       pts[0].x = r.left;   pts[0].y = r.bottom + (Int2)2;
870       pts[1].x = oldPoint; pts[1].y = (r.bottom + r.top)>>1;
871       pts[2].x = r.left;   pts[2].y = r.top - (Int2)2;
872       if (r.right < r.left)
873         {
874           vis = FALSE;
875           rect.left  = pts[1].x;
876           rect.right = pts[0].x;
877         }
878       break;
879 
880     case RIGHT_ARROW :
881       oldPoint = r.right;
882       if (r.right - r.left >= arrowSize) r.right -= (Int2)arrowSize;
883       else r.right -= (Int2)(arrowSize>>1);
884       if ( r.right < r.left ) vis = FALSE;
885       pts[0].x = r.right;  pts[0].y = r.bottom + (Int2)2;
886       pts[1].x = oldPoint; pts[1].y = (r.bottom + r.top)>>1;
887       pts[2].x = r.right;  pts[2].y = r.top - (Int2)2;
888       if (r.right < r.left)
889         {
890           vis = FALSE;
891           rect.left  = pts[0].x;
892           rect.right = pts[1].x;
893         }
894       break;
895 
896     case UP_ARROW :
897       oldPoint = r.top;
898       if (r.bottom - r.top >= (Int2)arrowSize) r.top += (Int2)arrowSize;
899       else r.top += (Int2)(arrowSize>>1);
900       if ( r.bottom < r.top ) vis = FALSE;
901       pts[0].x = r.right + (Int2)2;   pts[0].y = r.top;
902       pts[1].x = (r.right+r.left)>>1; pts[1].y = oldPoint;
903       pts[2].x = r.left - (Int2)2;    pts[2].y = r.top;
904       if (r.right < r.left)
905         {
906           vis = FALSE;
907           rect.top    = pts[1].y;
908           rect.bottom = pts[0].y;
909         }
910       break;
911 
912     case DOWN_ARROW :
913       oldPoint = r.bottom;
914       if (r.bottom - r.top >= (Int2)arrowSize) r.bottom -= (Int2)arrowSize;
915       else r.bottom -= (Int2)(arrowSize>>1);
916       if ( r.bottom < r.top ) vis = FALSE;
917       pts[0].x = r.right + (Int2)2;   pts[0].y = r.bottom;
918       pts[1].x = (r.right+r.left)>>1; pts[1].y = oldPoint;
919       pts[2].x = r.left - (Int2)2;    pts[2].y = r.bottom;
920       if (r.right < r.left)
921         {
922           vis = FALSE;
923           rect.top    = pts[0].y;
924           rect.bottom = pts[1].y;
925         }
926       break;
927     }
928 
929   SetPrimAttribute (pdc, COLOR_ATT|SHADING_ATT|MODE_ATT);
930   if ( !pdata->fill )
931     SetPrimAttribute (pdc, WIDTH_ATT);
932 
933   /* draw arrow */
934   if (pdata->arrow != NO_ARROW)
935     {
936       if (pdata->fill)
937         PaintPoly (3, pts);
938       else
939         FramePoly (3, pts);
940 
941       if (dInfoPtr->highlight == FILL_PRIMITIVE)
942         PaintPoly(3, pts);
943     }
944 
945   /* draw rectangle */
946   if ( vis ) {
947     if ( pdata->fill )
948       PaintRect( &r );
949     else
950       FrameRect( &r );
951   }
952 
953   /* highlighting */
954   switch ( dInfoPtr->highlight )
955     {
956     case PLAIN_PRIMITIVE:
957       break;
958     case FRAME_PRIMITIVE:
959     case OUTLINE_PRIMITIVE:
960       Black();
961       WidePen( 1 );
962       InsetRect(&rect, -3, -3);
963       FrameRect( &rect );
964       InsetRect(&rect, +3, +3);
965       break;
966     case FILL_PRIMITIVE:
967       InsetRect(&rect, -2, -2);
968       PaintRect( &rect );
969       InsetRect(&rect, +2, +2);
970       break;
971     }
972 }
973 
974 
975 static Boolean RecHitTestProc ( RecPDataPtr pdata, PrimHitContext phc)
976 {
977   register ScalePtr dInfoPtr;
978  
979   dInfoPtr = (ScalePtr)phc;
980   if ( (pdata->box.left < dInfoPtr->worldWindow.right) &&
981        (pdata->box.right > dInfoPtr->worldWindow.left) &&
982        (pdata->box.top > dInfoPtr->worldWindow.bottom) &&
983        (pdata->box.bottom < dInfoPtr->worldWindow.top) ) return TRUE; 
984   return FALSE; 
985 }
986 
987 static Boolean RecOffsetProc ( RecPDataPtr pdata, Int4 deltaX, 
988                                    Int4 deltaY )
989 {
990   pdata->box.left += deltaX;
991   pdata->box.right += deltaX;
992   pdata->box.top += deltaY;
993   pdata->box.bottom += deltaY;
994   return TRUE; 
995 }
996 
997 static Boolean RecGetLimitsProc ( RecPDataPtr pdata, Int4 scaleX,
998                                   Int4 scaleY, BoxPtr pLimits )
999 {
1000   Int4 arrowSize;
1001 
1002   *pLimits = pdata->box;
1003   switch ( pdata->arrow ){
1004     case LEFT_ARROW :
1005       arrowSize = pdata->arrowSize*scaleX/2;
1006       if ( pLimits->right - pLimits->left < arrowSize )
1007         pLimits->right = pLimits->left + arrowSize;
1008       break;
1009     case RIGHT_ARROW :
1010       arrowSize = pdata->arrowSize*scaleX/2;
1011       if ( pLimits->right - pLimits->left < arrowSize )
1012         pLimits->left = pLimits->right - arrowSize;
1013       break;
1014     case UP_ARROW :
1015       arrowSize = pdata->arrowSize*scaleY/2;
1016       if ( pLimits->top - pLimits->bottom < arrowSize )
1017         pLimits->bottom = pLimits->top - arrowSize;
1018       break;
1019     case DOWN_ARROW :
1020       arrowSize = pdata->arrowSize*scaleY/2;
1021       if ( pLimits->top - pLimits->bottom < arrowSize )
1022         pLimits->top = pLimits->bottom + arrowSize;
1023   }
1024   OutsetBox ( pLimits, scaleX<<2, scaleY<<2 );
1025   return TRUE; 
1026 }
1027 
1028 static PrimDef recPrimDef = {
1029   (PrimDrawProc) RecDrawProc,
1030   (PrimHitTestProc) RecHitTestProc,
1031   (PrimOffsetProc) RecOffsetProc,
1032   (PrimCleanupProc) NULL,
1033   (PrimGetLimitsProc) RecGetLimitsProc
1034 };
1035 
1036 /*****************************************************************************
1037 *
1038 *   AddRectangle (parent, left, top, right, bottom, arrow, fill, primID)
1039 *
1040 *****************************************************************************/
1041 
1042 PrimitivE AddRectangle (SegmenT parent, Int4 left, Int4 top, Int4 right,
1043                         Int4 bottom, Int2 arrow, Boolean fill, Uint2 primID)
1044 {
1045   RecPData data;
1046   Int4 swap;
1047 
1048   if (left > right) {
1049     swap = left;
1050     left = right;
1051     right = swap;
1052   }
1053   if (bottom > top) {
1054     swap = bottom;
1055     bottom = top;
1056     top = swap;
1057   }
1058   data.box.left = left;
1059   data.box.top = top;
1060   data.box.right = right;
1061   data.box.bottom = bottom;
1062   data.fill = fill;
1063   data.arrow = arrow;
1064   data.arrowSize = userArrowSize;
1065   return AddPrimitive (&recPrimDef, parent, primID, (VoidPtr)&data,
1066                        sizeof(RecPData));
1067 }
1068 
1069 
1070 /*****************************************************************************
1071 *
1072 *     ROUNDED RECTANGLE
1073 *
1074 *****************************************************************************/
1075 
1076 typedef struct {
1077   BoxInfo box;
1078   Int4    oval_w;
1079   Int4    oval_h;
1080   Boolean fill;
1081   Uint4   flags;
1082 } RoRecPData, PNTR RoRecPDataPtr;
1083 
1084 
1085 static void s_DoRoundRect(RectPtr r,
1086                           Int2 oval_w, Int2 oval_h, Boolean fill, Uint4 flags)
1087 {
1088   Int2 W, dW, H, dH;
1089   RecT r1, r2, qr1, qr2;
1090   EQuadrant q1, q2;
1091   PoinT p1, p2;
1092 
1093   if (!flags  ||
1094       (flags & ROREC_TOP   &&  flags & ROREC_BOTTOM)  ||
1095       (flags & ROREC_LEFT  &&  flags & ROREC_RIGHT)) {
1096     if ( fill )
1097       PaintRoundRect(r, oval_w, oval_h);
1098     else
1099       FrameRoundRect(r, oval_w, oval_h);
1100     return;
1101   }
1102 
1103   W = r->right - r->left;
1104   H = r->bottom - r->top;
1105   LoadRect(&r1, 0, 0, 0, 0);
1106   LoadRect(&r2, 0, 0, 0, 0);
1107 
1108   if (flags & ROREC_TOP  ||  flags & ROREC_BOTTOM) {
1109     if (2 * oval_w > W)
1110       oval_w = W / 2;
1111     dW = W - 2 * oval_w;
1112 
1113     if (oval_h > H)
1114       oval_h = H;
1115     dH = H - oval_h;
1116   }
1117   else { /* ROREC_LEFT || ROREC_RIGHT */
1118     if (2 * oval_h > H)
1119       oval_h = H / 2;
1120     dH = H - 2 * oval_h;
1121 
1122     if (oval_w > W)
1123       oval_w = W;
1124     dW = W - oval_w;
1125   }
1126 
1127   if (oval_w < 2  ||  oval_h < 2) {
1128     if ( fill )
1129       PaintRect(r);
1130     else
1131       FrameRect(r);
1132     return;
1133   }
1134 
1135 
1136   if (flags & ROREC_TOP  ||  flags & ROREC_BOTTOM) {
1137     if (flags & ROREC_TOP) {
1138       if ( dW )
1139         LoadRect(&r1, (Int2)(r->left + oval_w), r->top,
1140                  (Int2)(r->right - oval_w), (Int2)(r->top + oval_h));
1141       if ( dH )
1142         LoadRect(&r2, r->left, (Int2)(r->top + oval_h),
1143                  r->right, r->bottom);
1144       q1 = eQ_LeftTop;
1145       LoadRect(&qr1, r->left, r->top,
1146                (Int2)(r->left + oval_w), (Int2)(r->top + oval_h));
1147       q2 = eQ_RightTop;
1148       LoadRect(&qr2, (Int2)(r->right - oval_w), r->top,
1149                r->right, (Int2)(r->top + oval_h));
1150 
1151       if ( !fill ) {
1152         p1.y = p2.y = r->bottom;  p1.x = r->left;  p2.x = r->right;
1153         DrawLine(p1, p2);
1154         if ( dW ) {
1155           p1.y = p2.y = r1.top;  p1.x = r1.left;  p2.x = r1.right;
1156           DrawLine(p1, p2);
1157         }
1158       }
1159     }
1160     else { /* ROREC_BOTTOM */
1161       if ( dW )
1162         LoadRect(&r1, (Int2)(r->left + oval_w), (Int2)(r->bottom - oval_h),
1163                  (Int2)(r->right - oval_w), r->bottom);
1164       if ( dH )
1165         LoadRect(&r2, r->left, r->top,
1166                  r->right, (Int2)(r->bottom - oval_h));
1167       q1 = eQ_LeftBottom;
1168       LoadRect(&qr1, r->left, r->bottom,
1169                (Int2)(r->left + oval_w), (Int2)(r->bottom - oval_h));
1170       q2 = eQ_RightBottom;
1171       LoadRect(&qr2, (Int2)(r->right - oval_w), r->bottom,
1172                r->right, (Int2)(r->bottom - oval_h));
1173 
1174       if ( !fill ) {
1175         p1.y = p2.y = r->top;  p1.x = r->left;  p2.x = r->right;
1176         DrawLine(p1, p2);
1177         if ( dW ) {
1178           p1.y = p2.y = r->bottom;  p1.x = r1.left;  p2.x = r1.right;
1179           DrawLine(p1, p2);
1180         }
1181       }
1182     }
1183 
1184     if (!fill  &&  dH) {
1185       p1.y = r2.top;  p2.y = r2.bottom;
1186 
1187       p1.x = p2.x = r->left;
1188       DrawLine(p1, p2);
1189       p1.x = p2.x = r->right;
1190       DrawLine(p1, p2);
1191     }
1192   }
1193 
1194   else { /* ROREC_LEFT | ROREC_RIGHT */
1195     if (flags & ROREC_LEFT) {
1196       if ( dH )
1197         LoadRect(&r1, r->left, (Int2)(r->top + oval_h),
1198                  (Int2)(r->left + oval_w), (Int2)(r->bottom - oval_h));
1199       if ( dW )
1200         LoadRect(&r2, (Int2)(r->left + oval_w), r->top,
1201                  r->right, r->bottom);
1202       q1 = eQ_LeftTop;
1203       LoadRect(&qr1, r->left, r->top,
1204           (Int2)(r->left + oval_w), (Int2)(r->top + oval_h));
1205       q2 = eQ_LeftBottom;
1206       LoadRect(&qr2, r->left, r->bottom,
1207                (Int2)(r->left + oval_w), (Int2)(r->bottom - oval_h));
1208       
1209       if ( !fill ) {
1210         p1.x = p2.x = r->right;  p1.y = r->top;  p2.y = r->bottom;
1211         DrawLine(p1, p2);
1212         if ( dW ) {
1213           p1.x = p2.x = r->left;  p1.y = r1.top;  p2.y = r1.bottom;
1214           DrawLine(p1, p2);
1215         }
1216       }
1217     }
1218     else { /* ROREC_RIGHT */
1219       if ( dH )
1220         LoadRect(&r1, (Int2)(r->right - oval_w), (Int2)(r->top + oval_h),
1221                  r->right, (Int2)(r->bottom - oval_h));
1222       if ( dW )
1223         LoadRect(&r2, r->left, r->top,
1224                  (Int2)(r->right - oval_w), r->bottom);
1225       q1 = eQ_RightTop;
1226       LoadRect(&qr1, (Int2)(r->right - oval_w), r->top,
1227                r->right, (Int2)(r->top + oval_h));
1228       q2 = eQ_RightBottom;
1229       LoadRect(&qr2, (Int2)(r->right - oval_w), r->bottom,
1230                r->right, (Int2)(r->bottom - oval_h));
1231       
1232       if ( !fill ) {
1233         p1.x = p2.x = r->left;  p1.y = r->top;  p2.y = r->bottom;
1234         DrawLine(p1, p2);
1235         if ( dW ) {
1236           p1.x = p2.x = r->right;  p1.y = r1.top;  p2.y = r1.bottom;
1237           DrawLine(p1, p2);
1238         }
1239       }
1240     }
1241 
1242     if (!fill  &&  dH) {
1243       p1.x = r2.left;  p2.x = r2.right;
1244 
1245       p1.y = p2.y = r->top;
1246       DrawLine(p1, p2);
1247       p1.y = p2.y = r->bottom;
1248       DrawLine(p1, p2);
1249     }
1250   }
1251 
1252   if ( fill ) {
1253     if ( !EmptyRect(&r1) )
1254       PaintRect(&r1);
1255     if ( !EmptyRect(&r2) )
1256       PaintRect(&r2);
1257     PaintQuadrant(&qr1, q1);
1258     PaintQuadrant(&qr2, q2);
1259   } else {
1260     FrameQuadrant(&qr1, q1);
1261     FrameQuadrant(&qr2, q2);
1262   }
1263 }
1264 
1265 
1266 static void RoRecDrawProc(RoRecPDataPtr pdata, PrimDrawContext pdc)
1267 {
1268   register DrawInfoPtr dInfoPtr = (DrawInfoPtr)pdc;
1269   BoxInfo tmpBox;
1270   RecT    r;
1271   Int4    curScale;
1272   Int2    oval_w, oval_h;
1273 
1274   /* check limits */
1275   tmpBox = pdata->box;
1276   if ( (tmpBox.left   > dInfoPtr->scale.worldWindow.right ) || 
1277        (tmpBox.right  < dInfoPtr->scale.worldWindow.left  ) || 
1278        (tmpBox.top    < dInfoPtr->scale.worldWindow.bottom) || 
1279        (tmpBox.bottom > dInfoPtr->scale.worldWindow.top   ) )
1280     return;
1281   
1282   if ( dInfoPtr->checked == FALSE ) {
1283     if ( tmpBox.left < dInfoPtr->scale.worldWindow16.left ) 
1284       tmpBox.left = dInfoPtr->scale.worldWindow16.left;
1285     if ( tmpBox.right > dInfoPtr->scale.worldWindow16.right ) 
1286       tmpBox.right = dInfoPtr->scale.worldWindow16.right;
1287     if ( tmpBox.top > dInfoPtr->scale.worldWindow16.top ) 
1288       tmpBox.top = dInfoPtr->scale.worldWindow16.top;
1289     if ( tmpBox.bottom < dInfoPtr->scale.worldWindow16.bottom ) 
1290       tmpBox.bottom = dInfoPtr->scale.worldWindow16.bottom;
1291   }
1292 
1293   /* scale */
1294   curScale = dInfoPtr->scale.scaleX;
1295   r.left   = (Int2)((dInfoPtr->scale.offsetX + tmpBox.left )  / curScale);
1296   r.right  = (Int2)((dInfoPtr->scale.offsetX + tmpBox.right)  / curScale);
1297   oval_w   = (Int2)(pdata->oval_w / curScale);
1298 
1299   curScale = dInfoPtr->scale.scaleY;
1300   r.top    = (Int2)((dInfoPtr->scale.offsetY - tmpBox.top   ) / curScale);
1301   r.bottom = (Int2)((dInfoPtr->scale.offsetY - tmpBox.bottom) / curScale);
1302   oval_h   = (Int2)(pdata->oval_h / curScale);
1303 
1304   /* attributes */
1305   SetPrimAttribute(pdc, COLOR_ATT|SHADING_ATT|MODE_ATT);
1306   if ( !pdata->fill )
1307     SetPrimAttribute(pdc, WIDTH_ATT);
1308 
1309   /* draw */
1310   s_DoRoundRect(&r, oval_w, oval_h, pdata->fill, pdata->flags);
1311 
1312   /* highlight */
1313   switch ( dInfoPtr->highlight ) {
1314   case PLAIN_PRIMITIVE:
1315     break;
1316   case FRAME_PRIMITIVE:
1317   case OUTLINE_PRIMITIVE:
1318     Black();
1319     WidePen( 1 );
1320     InsetRect(&r, -3, -3);
1321     s_DoRoundRect(&r, (Int2)(oval_w + 3), (Int2)(oval_h + 3),
1322                   FALSE, pdata->flags);
1323     break;
1324   case FILL_PRIMITIVE:
1325     InsetRect(&r, -2, -2);
1326     s_DoRoundRect(&r, (Int2)(oval_w + 3), (Int2)(oval_h + 3),
1327                   TRUE, pdata->flags);
1328     break;
1329   }
1330 }
1331 
1332 
1333 static Boolean RoRecHitTestProc(RoRecPDataPtr pdata, PrimHitContext phc)
1334 {
1335   ScalePtr dInfoPtr = (ScalePtr)phc;
1336 
1337   return (Boolean)
1338     ((pdata->box.left < dInfoPtr->worldWindow.right) &&
1339      (pdata->box.right > dInfoPtr->worldWindow.left) &&
1340      (pdata->box.top > dInfoPtr->worldWindow.bottom) &&
1341      (pdata->box.bottom < dInfoPtr->worldWindow.top));
1342 }
1343 
1344 static Boolean RoRecOffsetProc(RoRecPDataPtr pdata, Int4 deltaX, Int4 deltaY)
1345 {
1346   pdata->box.left   += deltaX;
1347   pdata->box.right  += deltaX;
1348   pdata->box.top    += deltaY;
1349   pdata->box.bottom += deltaY;
1350   return TRUE; 
1351 }
1352 
1353 static Boolean RoRecGetLimitsProc(RoRecPDataPtr pdata,
1354                                   Int4 scaleX, Int4 scaleY, BoxPtr pLimits )
1355 {
1356   *pLimits = pdata->box;
1357   OutsetBox(pLimits, scaleX<<2, scaleY<<2);
1358   return TRUE; 
1359 }
1360 
1361 static PrimDef rorecPrimDef = {
1362   (PrimDrawProc     ) RoRecDrawProc,
1363   (PrimHitTestProc  ) RoRecHitTestProc,
1364   (PrimOffsetProc   ) RoRecOffsetProc,
1365   (PrimCleanupProc  ) 0,
1366   (PrimGetLimitsProc) RoRecGetLimitsProc
1367 };
1368 
1369 
1370 /*****************************************************************************
1371 *
1372 *   AddRoundedRectangle
1373 *
1374 *****************************************************************************/
1375 
1376 PrimitivE AddRoundedRectangle(SegmenT parent,
1377                               Int4 left, Int4 top, Int4 right, Int4 bottom,
1378                               Int4 oval_w, Int4 oval_h, Boolean fill,
1379                               Uint4 flags, Uint2 primID)
1380 {
1381   RoRecPData data;
1382   Int4 tmp;
1383 
1384   if (left > right) {
1385     tmp = left;
1386     left = right;
1387     right = tmp;
1388   }
1389   if (bottom > top) {
1390     tmp = bottom;
1391     bottom = top;
1392     top = tmp;
1393   }
1394 
1395   data.box.left   = left;
1396   data.box.top    = top;
1397   data.box.right  = right;
1398   data.box.bottom = bottom;
1399 
1400   data.flags = flags;
1401 
1402   data.oval_w = oval_w;
1403   data.oval_h = oval_h;
1404 
1405   data.fill = fill;
1406   return AddPrimitive(&rorecPrimDef, parent, primID, (VoidPtr)&data,
1407                        sizeof(RoRecPData));
1408 }
1409 
1410 
1411 /*****************************************************************************
1412 *
1413 *   SEGMENT  RECTANGLE
1414 *
1415 *****************************************************************************/
1416 
1417 typedef struct segrecpdata {
1418   BoxPtr   parentBox;
1419   Boolean  fill;
1420 } SegRecPData, PNTR SegRecPDataPtr;
1421 
1422 static void SegRecDrawProc (SegRecPDataPtr pdata, PrimDrawContext pdc)
1423 {
1424   register DrawInfoPtr dInfoPtr;
1425   BoxInfo tmpBox;
1426   Int4    curScale;
1427   RecT    r;
1428  
1429   dInfoPtr = (DrawInfoPtr)pdc;
1430   tmpBox = *(pdata->parentBox);
1431   if ( (tmpBox.left > dInfoPtr->scale.worldWindow.right) || 
1432        (tmpBox.right < dInfoPtr->scale.worldWindow.left) || 
1433        (tmpBox.top < dInfoPtr->scale.worldWindow.bottom) || 
1434        (tmpBox.bottom > dInfoPtr->scale.worldWindow.top) ) return; 
1435   if ( dInfoPtr->checked == FALSE ) {
1436     if ( tmpBox.left < dInfoPtr->scale.worldWindow16.left ) 
1437       tmpBox.left = dInfoPtr->scale.worldWindow16.left;
1438     if ( tmpBox.right > dInfoPtr->scale.worldWindow16.right ) 
1439       tmpBox.right = dInfoPtr->scale.worldWindow16.right;
1440     if ( tmpBox.top > dInfoPtr->scale.worldWindow16.top ) 
1441       tmpBox.top = dInfoPtr->scale.worldWindow16.top;
1442     if ( tmpBox.bottom < dInfoPtr->scale.worldWindow16.bottom ) 
1443       tmpBox.bottom = dInfoPtr->scale.worldWindow16.bottom;
1444   }
1445   if (pdata->fill) {
1446     SetPrimAttribute (pdc, COLOR_ATT|SHADING_ATT|MODE_ATT);
1447   } else {
1448     SetPrimAttribute (pdc, COLOR_ATT|STYLE_ATT|WIDTH_ATT|MODE_ATT);
1449   }
1450   curScale = dInfoPtr->scale.scaleX;
1451   r.left = (Int2)((dInfoPtr->scale.offsetX + tmpBox.left) / curScale);
1452   r.right = (Int2)((dInfoPtr->scale.offsetX + tmpBox.right) / curScale);
1453   curScale = dInfoPtr->scale.scaleY;
1454   r.top = (Int2)((dInfoPtr->scale.offsetY - tmpBox.top) / curScale);
1455   r.bottom = (Int2)((dInfoPtr->scale.offsetY - tmpBox.bottom) / curScale);
1456   r.right++;  r.bottom++;
1457   if ( pdata->fill )  PaintRect (&r);
1458   else FrameRect (&r);
1459   r.right--; r.bottom--;
1460   switch ( dInfoPtr->highlight ) {
1461     case FRAME_PRIMITIVE:
1462     case OUTLINE_PRIMITIVE:
1463       SetPrimAttribute (pdc, STYLE_ATT|WIDTH_ATT);
1464       WidePen((Int2)(dInfoPtr->primattrib->penwidth + 1));
1465       r.right ++;  r.bottom ++;
1466       FrameRect (&r);
1467       InsetRect (&r, -1, -1 );
1468       FrameRect (&r);
1469       break;
1470     case FILL_PRIMITIVE:
1471       SetPrimAttribute (pdc, SHADING_ATT);
1472       r.right ++;  r.bottom ++;
1473       InsetRect (&r, -1, -1);
1474       PaintRect (&r);
1475   }
1476 }
1477 
1478 static Boolean SegRecHitTestProc ( SegRecPDataPtr pdata, PrimHitContext phc)
1479 {
1480   register ScalePtr dInfoPtr;
1481   BoxInfo tmpBox;
1482  
1483 
1484   
1485   dInfoPtr = (ScalePtr)phc;
1486   tmpBox = *(pdata->parentBox);
1487   if ( (tmpBox.left < dInfoPtr->worldWindow.right) && 
1488        (tmpBox.right > dInfoPtr->worldWindow.left) &&
1489        (tmpBox.top > dInfoPtr->worldWindow.bottom) &&
1490        (tmpBox.bottom < dInfoPtr->worldWindow.top) ) return TRUE;
1491   return FALSE;
1492 }
1493 
1494 static Boolean SegRecOffsetProc ( SegRecPDataPtr pdata, Int4 deltaX, 
1495                                    Int4 deltaY )
1496 { 
1497   return FALSE; 
1498 }
1499 
1500 static Boolean SegRecGetLimitsProc ( SegRecPDataPtr pdata, Int4 scaleX,
1501 Int4 scaleY, BoxPtr pLimits )
1502 {
1503   *pLimits = *(pdata->parentBox);
1504   return TRUE; 
1505 }
1506 
1507 static PrimDef segrecPrimDef = {
1508   (PrimDrawProc) SegRecDrawProc,
1509   (PrimHitTestProc) SegRecHitTestProc,
1510   (PrimOffsetProc) SegRecOffsetProc,
1511   (PrimCleanupProc) NULL,
1512   (PrimGetLimitsProc) SegRecGetLimitsProc
1513 };
1514 
1515 Nlm_PrimitivE Nlm_AddSegRect ( SegmenT parent, Boolean fill, 
1516                               Uint2 primID )
1517 {
1518   SegRecPData data;
1519 
1520   data.parentBox = &(((SegPPtr)parent)->seg.box);
1521   data.fill  = fill;
1522   return AddPrimitive (&segrecPrimDef, parent, primID, (VoidPtr)&data,
1523                        sizeof(SegRecPData));
1524 }
1525 
1526 static Boolean SilentSegRecHitTestProc ( SegRecPDataPtr pdata, PrimHitContext phc)
1527 {
1528 /* SilentSegRect's should never absorb clicks */
1529   return FALSE;
1530 }
1531 
1532 static PrimDef silentSegrecPrimDef = {
1533   (PrimDrawProc) SegRecDrawProc,
1534   (PrimHitTestProc) SilentSegRecHitTestProc,
1535   (PrimOffsetProc) SegRecOffsetProc,
1536   (PrimCleanupProc) NULL,
1537   (PrimGetLimitsProc) SegRecGetLimitsProc
1538 };
1539 
1540 Nlm_PrimitivE Nlm_AddSilentSegRect ( SegmenT parent, Boolean fill, 
1541                               Uint2 primID )
1542 {
1543   SegRecPData data;
1544 
1545   data.parentBox = &(((SegPPtr)parent)->seg.box);
1546   data.fill  = fill;
1547   return AddPrimitive (&silentSegrecPrimDef, parent, primID, (VoidPtr)&data,
1548                        sizeof(SegRecPData));
1549 }
1550 
1551 /*****************************************************************************
1552 *
1553 *  H - LINE
1554 *
1555 *****************************************************************************/
1556 typedef struct hlinepdata {
1557   Int4     x1;
1558   Int4     x2;
1559   Int4     y;
1560   Int1     fArrowPoint;
1561   Int1     arrowSize;
1562 } HLinePData, PNTR HLinePDataPtr;
1563 
1564 static void HLineDrawProc (HLinePDataPtr pdata, PrimDrawContext pdc)
1565 {
1566   register DrawInfoPtr dInfoPtr;
1567   Int4    curScale;
1568   Int4    x1,x2,y;
1569   PoinT   pt1, pt2;
1570   PoinT   pts [3];
1571   Int2    oldPoint;
1572   Int1    arrowSize;
1573   Boolean vis = TRUE;
1574   RecT    rect;
1575   
1576   dInfoPtr = (DrawInfoPtr)pdc;
1577   x1 = pdata->x1;
1578   x2 = pdata->x2;
1579   y = pdata->y;
1580   if ( (y  > dInfoPtr->scale.worldWindow.top   ) ||
1581        (y  < dInfoPtr->scale.worldWindow.bottom) ||
1582        (x1 > dInfoPtr->scale.worldWindow.right ) ||
1583        (x2 < dInfoPtr->scale.worldWindow.left  ) )
1584     return;
1585 
1586   if ( dInfoPtr->checked == FALSE ) {
1587     curScale = dInfoPtr->scale.worldWindow16.left;
1588     if ( x1 < curScale ) x1 = curScale;
1589     curScale = dInfoPtr->scale.worldWindow16.right;
1590     if ( x2 > curScale ) x2 = curScale;
1591   }
1592 
1593   SetPrimAttribute (pdc, COLOR_ATT|STYLE_ATT|WIDTH_ATT|MODE_ATT);
1594 
1595   arrowSize = pdata->arrowSize;
1596   curScale = dInfoPtr->scale.scaleX;
1597   pt1.x = (Int2)((dInfoPtr->scale.offsetX + x1) / curScale);
1598   pt2.x = (Int2)((dInfoPtr->scale.offsetX + x2) / curScale);
1599   curScale = dInfoPtr->scale.scaleY;
1600   pt1.y = pt2.y = (Int2)((dInfoPtr->scale.offsetY - y) / curScale);
1601 
1602   if (dInfoPtr->highlight != PLAIN_PRIMITIVE)
1603     {
1604       rect.left  = pt1.x;
1605       rect.right = pt2.x;
1606       rect.top   = rect.bottom =  pt1.y;
1607     }
1608 
1609   switch ( pdata->fArrowPoint ) {
1610   case 0:
1611     oldPoint = pt2.x;
1612     if (pt2.x - pt1.x > (Int2)arrowSize) pt2.x -= (Int2)arrowSize;
1613     else pt2.x -= (Int2)(arrowSize>>1);
1614     if ( pt2.x < pt1.x ) vis = FALSE;
1615     pts[1].x = oldPoint; pts[1].y = pt1.y;
1616     oldPoint = (Int2)ARROWWIDTH2 * (Int2)arrowSize / (Int2)100;
1617     pts[0].x = pt2.x; pts[0].y = pt1.y + oldPoint;
1618     pts[2].x = pt2.x; pts[2].y = pt2.y - oldPoint ;
1619     break;
1620   case 1:
1621     oldPoint = pt1.x;
1622     if (pt2.x - pt1.x > (Int2)arrowSize) pt1.x += (Int2)arrowSize;
1623     else pt1.x += (Int2)(arrowSize>>1);
1624     if ( pt2.x < pt1.x ) vis = FALSE;
1625     pts[1].x = oldPoint; pts[1].y = pt1.y;
1626     oldPoint = (Int2)ARROWWIDTH2 * (Int2)arrowSize / (Int2)100;
1627     pts[0].x = pt1.x; pts[0].y = pt1.y - oldPoint;
1628     pts[2].x = pt1.x; pts[2].y = pt2.y + oldPoint ;
1629   }
1630   
1631   if ( vis ) DrawLine (pt1, pt2);
1632   if ( pdata->fArrowPoint != 0xF ){
1633     SetPrimAttribute (pdc, SHADING_ATT);
1634     PaintPoly (3, pts);
1635   }
1636 
1637   switch ( dInfoPtr->highlight )
1638     {
1639     case PLAIN_PRIMITIVE:
1640       break;
1641     case FRAME_PRIMITIVE:
1642     case OUTLINE_PRIMITIVE:
1643       Black();
1644       WidePen( 1 );
1645       InsetRect(&rect, -2, -2);
1646       rect.bottom++;
1647       FrameRect( &rect );
1648       break;
1649     case FILL_PRIMITIVE:
1650       SetPrimAttribute (pdc, STYLE_ATT|WIDTH_ATT);
1651       WidePen((Int2)(((DrawInfoPtr)pdc)->primattrib->penwidth + 2));
1652       if ( vis ) DrawLine (pt1, pt2);
1653       if ( pdata->fArrowPoint != 0xF ){
1654         FramePoly (3, pts);
1655         SetPrimAttribute (pdc, SHADING_ATT);
1656         PaintPoly (3, pts);
1657       }
1658       break;
1659     }
1660 }
1661 
1662 
1663 static Boolean HLineHitTestProc ( HLinePDataPtr pdata, PrimHitContext phc)
1664 {
1665   register ScalePtr dInfoPtr;
1666  
1667   dInfoPtr = (ScalePtr)phc;
1668   if ( (pdata->x1 < dInfoPtr->worldWindow.right) && 
1669        (pdata->x2 > dInfoPtr->worldWindow.left) &&
1670        (pdata->y > dInfoPtr->worldWindow.bottom) &&
1671        (pdata->y < dInfoPtr->worldWindow.top) ) return TRUE;
1672   return FALSE; 
1673 }
1674 
1675 static Boolean HLineOffsetProc ( HLinePDataPtr pdata, Int4 deltaX, 
1676                                      Int4 deltaY )
1677 {
1678   pdata->x1 += deltaX;
1679   pdata->x2 += deltaX;
1680   pdata->y += deltaY;
1681   return TRUE; 
1682 }
1683 
1684 static Boolean HLineGetLimitsProc ( HLinePDataPtr pdata, Int4 scaleX,
1685 Int4 scaleY, BoxPtr pLimits )
1686 {
1687   Int4 arrowSize;
1688 
1689   switch ( pdata->fArrowPoint ) {
1690     case 0:
1691       arrowSize = pdata->arrowSize*scaleX/2;
1692       if ( pdata->x2 - pdata->x1 < arrowSize ) 
1693         pLimits->left = pdata->x2 - arrowSize;
1694       else pLimits->left = pdata->x1;
1695       pLimits->right = pdata->x2;
1696       pLimits->top = pdata->y + arrowSize;
1697       pLimits->bottom = pdata->y - arrowSize;
1698       break;
1699     case 1:
1700       arrowSize = pdata->arrowSize*scaleX/2;
1701       if ( pdata->x2 - pdata->x1 < arrowSize ) 
1702         pLimits->right = pdata->x2 - arrowSize;
1703       else pLimits->right = pdata->x2;
1704       pLimits->left = pdata->x1;
1705       pLimits->top = pdata->y + arrowSize;
1706       pLimits->bottom = pdata->y - arrowSize;
1707       break;
1708     default:
1709       pLimits->left = pdata->x1;
1710       pLimits->right = pdata->x2;
1711       pLimits->top = pLimits->bottom = pdata->y;
1712   }
1713   OutsetBox ( pLimits, scaleX<<2, scaleY<<2 );
1714   return TRUE; 
1715 }
1716 
1717 static PrimDef hlinePrimDef = {
1718   (PrimDrawProc) HLineDrawProc,
1719   (PrimHitTestProc) HLineHitTestProc,
1720   (PrimOffsetProc) HLineOffsetProc,
1721   (PrimCleanupProc) NULL,
1722   (PrimGetLimitsProc) HLineGetLimitsProc
1723 };
1724 
1725 /*****************************************************************************
1726 *
1727 *   AddHLine (parent, x1, x2, y, arrow, primID)
1728 *
1729 *****************************************************************************/
1730 
1731 static PrimitivE Nlm_AddHLine ( SegmenT parent, Int4 pnt1X, Int4 pnt2X, 
1732                                 Int4 pntY, Boolean arrow, Uint2 primID )
1733 {
1734   HLinePData data;
1735 
1736   if ( pnt1X == pnt2X ) arrow = FALSE;
1737   data.y = pntY;
1738   data.arrowSize = userArrowSize;
1739   if ( pnt2X >= pnt1X ) {
1740     data.x1 = pnt1X;
1741     data.x2 = pnt2X;
1742     data.fArrowPoint = 0;
1743   } else {
1744     data.x1 = pnt2X;
1745     data.x2 = pnt1X;
1746     data.fArrowPoint = 1;
1747   }
1748   if ( !arrow ) data.fArrowPoint = (Int1)0xF;
1749   return AddPrimitive (&hlinePrimDef, parent, primID, (VoidPtr)&data,
1750                        sizeof(HLinePData));
1751 }
1752 
1753 /*****************************************************************************
1754 *
1755 *  V - LINE
1756 *
1757 *****************************************************************************/
1758 typedef struct vlinepdata {
1759   Int4     y1;
1760   Int4     y2;
1761   Int4     x;
1762   Int1     fArrowPoint;
1763   Int1     arrowSize;
1764 } VLinePData, PNTR VLinePDataPtr;
1765 
1766 static void VLineDrawProc (VLinePDataPtr pdata, PrimDrawContext pdc)
1767 {
1768   register DrawInfoPtr dInfoPtr;
1769   Int4    curScale;
1770   Int4    y1,y2,x;
1771   PoinT   pt1, pt2;
1772   PoinT   pts [3];
1773   Int2    oldPoint;
1774   Int1    arrowSize;
1775   Boolean vis = TRUE;
1776  
1777   dInfoPtr = (DrawInfoPtr)pdc;
1778   y1 = pdata->y1;
1779   y2 = pdata->y2;
1780   x = pdata->x;
1781   if ( (y1 > dInfoPtr->scale.worldWindow.top) ||
1782        (y2 < dInfoPtr->scale.worldWindow.bottom) ||
1783        (x > dInfoPtr->scale.worldWindow.right) ||
1784        (x < dInfoPtr->scale.worldWindow.left) ) return;
1785   if ( dInfoPtr->checked == FALSE ) {
1786     curScale = dInfoPtr->scale.worldWindow16.bottom;
1787     if ( y1 < curScale ) y1 = curScale;
1788     curScale = dInfoPtr->scale.worldWindow16.top;
1789     if ( y2 > curScale ) y2 = curScale;
1790   }
1791   SetPrimAttribute (pdc, COLOR_ATT|STYLE_ATT|WIDTH_ATT|MODE_ATT);
1792   arrowSize = pdata->arrowSize;
1793   curScale = dInfoPtr->scale.scaleY;
1794   pt1.y = (Int2)((dInfoPtr->scale.offsetY - y1) / curScale);
1795   pt2.y = (Int2)((dInfoPtr->scale.offsetY - y2) / curScale);
1796   curScale = dInfoPtr->scale.scaleX;
1797   pt1.x = pt2.x = (Int2)((dInfoPtr->scale.offsetX + x) / curScale);
1798   switch ( pdata->fArrowPoint ) {
1799     case 0:
1800       oldPoint = pt2.y;
1801       if (pt1.y - pt2.y > (Int2)arrowSize) pt2.y += (Int2)arrowSize;
1802       else pt2.y += (Int2)(arrowSize>>1);
1803       if ( pt2.y > pt1.y ) vis = FALSE;
1804       pts[1].x = pt1.x; pts[1].y = oldPoint;
1805       oldPoint = (Int2)ARROWWIDTH2 * (Int2)arrowSize / (Int2)100;
1806       pts[0].x = pt1.x - oldPoint; pts[0].y = pt2.y;
1807       pts[2].x = pt1.x + oldPoint; pts[2].y = pt2.y;
1808       break;
1809     case 1:
1810       oldPoint = pt1.y;
1811       if (pt1.y - pt2.y > (Int2)arrowSize) pt1.y -= (Int2)arrowSize;
1812       else pt1.y -= (Int2)(arrowSize>>1);
1813       if ( pt2.y > pt1.y ) vis = FALSE;
1814       pts[1].x = pt1.x; pts[1].y = oldPoint;
1815       oldPoint = (Int2)ARROWWIDTH2 * (Int2)arrowSize / (Int2)100;
1816       pts[0].x = pt1.x + oldPoint; pts[0].y = pt1.y;
1817       pts[2].x = pt1.x - oldPoint; pts[2].y = pt1.y;
1818   }
1819   if ( vis ) DrawLine (pt1, pt2);
1820   if ( pdata->fArrowPoint != 0xF ){
1821     FramePoly (3, pts);
1822     SetPrimAttribute (pdc, SHADING_ATT);
1823     PaintPoly (3, pts);
1824   }
1825   if ( dInfoPtr->highlight != PLAIN_SEGMENT ) {
1826     SetPrimAttribute (pdc, STYLE_ATT|WIDTH_ATT);
1827     WidePen((Int2)(((DrawInfoPtr)pdc)->primattrib->penwidth + 2));
1828     if ( vis )  DrawLine (pt1, pt2);
1829     if ( pdata->fArrowPoint != 0xF ){
1830       SetPrimAttribute (pdc, SHADING_ATT);
1831       PaintPoly (3, pts);
1832     }
1833   }
1834 }
1835 
1836 static Boolean VLineHitTestProc ( VLinePDataPtr pdata, PrimHitContext phc)
1837 {
1838   register ScalePtr dInfoPtr;
1839  
1840   dInfoPtr = (ScalePtr)phc;
1841   if ( (pdata->x < dInfoPtr->worldWindow.right) && 
1842        (pdata->x > dInfoPtr->worldWindow.left) &&
1843        (pdata->y1 < dInfoPtr->worldWindow.top) &&
1844        (pdata->y2 > dInfoPtr->worldWindow.bottom) ) return TRUE;
1845   return FALSE; 
1846 }
1847 
1848 static Boolean VLineOffsetProc ( VLinePDataPtr pdata, Int4 deltaX, 
1849                                      Int4 deltaY )
1850 {
1851   pdata->x += deltaX;
1852   pdata->y1 += deltaY;
1853   pdata->y2 += deltaY;
1854   return TRUE; 
1855 }
1856 
1857 static Boolean VLineGetLimitsProc ( VLinePDataPtr pdata, Int4 scaleX,
1858 Int4 scaleY, BoxPtr pLimits )
1859 {
1860   Int4 arrowSize;
1861 
1862   switch ( pdata->fArrowPoint ) {
1863     case 0:
1864       arrowSize = pdata->arrowSize*scaleY/2;
1865       if ( pdata->y2 - pdata->y1 < arrowSize ) 
1866         pLimits->bottom = pdata->y2 + arrowSize;
1867       else pLimits->bottom = pdata->y1;
1868       pLimits->top = pdata->y2;
1869       pLimits->right = pdata->x + arrowSize;
1870       pLimits->left = pdata->x - arrowSize;
1871       break;
1872     case 1:
1873       arrowSize = pdata->arrowSize*scaleY/2;
1874       if ( pdata->y2 - pdata->y1 < arrowSize ) 
1875         pLimits->top = pdata->y1 - arrowSize;
1876       else pLimits->top = pdata->y2;
1877       pLimits->bottom = pdata->y1;
1878       pLimits->right = pdata->x + arrowSize;
1879       pLimits->left = pdata->x - arrowSize;
1880       break;
1881     default:
1882       pLimits->top = pdata->y2;
1883       pLimits->bottom = pdata->y1;
1884       pLimits->left = pLimits->right = pdata->x;
1885   }
1886   OutsetBox ( pLimits, scaleX<<2, scaleY<<2 );
1887   return TRUE; 
1888 }
1889 
1890 static PrimDef vlinePrimDef = {
1891   (PrimDrawProc) VLineDrawProc,
1892   (PrimHitTestProc) VLineHitTestProc,
1893   (PrimOffsetProc) VLineOffsetProc,
1894   (PrimCleanupProc) NULL,
1895   (PrimGetLimitsProc) VLineGetLimitsProc
1896 };
1897 
1898 /*****************************************************************************
1899 *
1900 *   AddVLine (parent, x, y1, y2, arrow, primID)
1901 *
1902 *****************************************************************************/
1903 
1904 static PrimitivE Nlm_AddVLine ( SegmenT parent, Int4 pntX, Int4 pnt1Y, 
1905                                 Int4 pnt2Y, Boolean arrow, Uint2 primID )
1906 {
1907   VLinePData data;
1908 
1909   if ( pnt1Y == pnt2Y ) arrow = FALSE;
1910   data.x = pntX;
1911   data.arrowSize = userArrowSize;
1912   if ( pnt2Y >= pnt1Y ) {
1913     data.y1 = pnt1Y;
1914     data.y2 = pnt2Y;
1915     data.fArrowPoint = 0;
1916   } else {
1917     data.y1 = pnt2Y;
1918     data.y2 = pnt1Y;
1919     data.fArrowPoint = 1;
1920   }
1921   if ( !arrow ) data.fArrowPoint = (Int1)0xF;
1922   return AddPrimitive (&vlinePrimDef, parent, primID, (VoidPtr)&data,
1923                        sizeof(VLinePData));
1924 }
1925 
1926 /*****************************************************************************
1927 *
1928 *     LINE
1929 *
1930 *****************************************************************************/
1931 
1932 typedef struct linepdata {
1933   BoxInfo  box;
1934   Int1     fPoint;
1935   Int1     fArrowPoint;
1936   Int1     arrowSize;
1937 } LinePData, PNTR LinePDataPtr;
1938 
1939 static Int2 MSin(Int4 a)
1940 {
1941   if (a < 0)
1942     a += INT4_MAX / 360 * 360;
1943   a %= 360;
1944 
1945   if (a < 90)
1946     return sin100[a];
1947   if (a < 180)
1948     return sin100[180-a];
1949   if (a < 270)
1950     return -sin100[a-180];
1951   return -sin100[360-a];
1952 }
1953 
1954 /* (for future use)
1955 static Int2 MCos(Int4 a)
1956 {
1957   if (a < 0)
1958     a += INT4_MAX / 360 * 360;
1959   a %= 360;
1960 
1961   if (a < 90)
1962     return sin100[90 - a];
1963   if (a < 180)
1964     return -sin100[a - 90];
1965   if (a < 270)
1966     return -sin100[270 - a];
1967   return sin100[a-270];
1968 }
1969 */
1970 
1971 static void LineDrawProc (LinePDataPtr pdata, PrimDrawContext pdc)
1972 {
1973   register DrawInfoPtr dInfoPtr;
1974   Int4    curScale;
1975   Int4    x1,y1,x2,y2;
1976   PoinT   pt1, pt2;
1977   PoinT   pts [3];
1978   Int2    angle;
1979   Int2    dangle = 20;
1980   Int2    arrowSize;
1981   Int2    arrowLen = 106;
1982   Int2    dx, dy;
1983   Boolean vis = TRUE;
1984  
1985   dInfoPtr = (DrawInfoPtr)pdc;
1986   arrowSize = (Int2)pdata->arrowSize;
1987   x1 = pdata->box.left;
1988   x2 = pdata->box.right;
1989   if ( pdata->fPoint == 0 ) {
1990     y1 = pdata->box.bottom;
1991     y2 = pdata->box.top;
1992   } else {
1993     y1 = pdata->box.top;
1994     y2 = pdata->box.bottom;
1995   }
1996   if ( pdata->fArrowPoint == 0xF ) {
1997     if ( (x1 > dInfoPtr->scale.worldWindow.right) ||
1998          (x2 < dInfoPtr->scale.worldWindow.left) ||
1999          (pdata->box.bottom > dInfoPtr->scale.worldWindow.top) ||
2000          (pdata->box.top < dInfoPtr->scale.worldWindow.bottom) ) return;
2001   } else {
2002     curScale = arrowSize * dInfoPtr->scale.scaleX / 2;
2003     if ( ((x1+curScale) > dInfoPtr->scale.worldWindow.right) ||
2004          ((x2-curScale) < dInfoPtr->scale.worldWindow.left) ) return;
2005     curScale = arrowSize * dInfoPtr->scale.scaleY / 2;
2006     if ( ((pdata->box.bottom+curScale) > dInfoPtr->scale.worldWindow.top) ||
2007          ((pdata->box.top+curScale) < dInfoPtr->scale.worldWindow.bottom) ) 
2008          return;
2009   }
2010   if ( dInfoPtr->checked == FALSE ) {
2011     if ( LineIntoVPort ( &x1, &y1, &x2, &y2,
2012          &(dInfoPtr->scale.worldWindow16)) == FALSE ) return;
2013   }
2014   SetPrimAttribute (pdc, COLOR_ATT|STYLE_ATT|WIDTH_ATT|MODE_ATT);
2015   curScale = dInfoPtr->scale.scaleX;
2016   pt1.x = (Int2)((dInfoPtr->scale.offsetX + x1) / curScale);
2017   pt2.x = (Int2)((dInfoPtr->scale.offsetX + x2) / curScale);
2018   curScale = dInfoPtr->scale.scaleY;
2019   pt1.y = (Int2)((dInfoPtr->scale.offsetY - y1) / curScale);
2020   pt2.y = (Int2)((dInfoPtr->scale.offsetY - y2) / curScale);
2021   if ( pdata->fArrowPoint != 0xF ){
2022     dx = pt2.x - pt1.x;
2023     dy = pt2.y - pt1.y; if ( dy < 0 ) dy = -dy;
2024     if ( (dx < 4) || ( dy < 4 ) ){
2025       x2 -= x1;
2026       y2 -= y1; if ( y2 < 0 ) y2 = -y2;
2027     } else {
2028       x2 = (Int4)dx; y2 = (Int4)dy;
2029     }
2030     x1 = x2*x2 + y2*y2;
2031     y1 = (Int4)arrowSize * (Int4)arrowSize;
2032     if ( x1 < y1 ) {
2033       dangle = 36;
2034       arrowLen = 61;
2035       if ( x1 < y1/4 ) vis = FALSE;
2036     }
2037     if ( x2 > y2 ) {
2038       if ( x2 > 0xFFFFFF ) angle = atan100[ y2/(x2/100) ] ;
2039       else angle = atan100[ y2*100/x2 ] ;
2040     } else {
2041       if ( y2 > 0xFFFFFF ) angle = 90 - atan100[ x2/(y2/100) ] ;
2042       angle = 90 - atan100[ x2*100/y2 ] ;
2043     }
2044     switch ( pdata->fArrowPoint ){
2045       case 0:
2046         pts[0] = pt2;
2047         angle += 180;
2048         break;
2049       case 1:
2050         pts[0] = pt2;
2051         angle = 180 - angle;
2052         break;
2053       case 2:
2054         pts[0] = pt1;
2055         break;
2056       default:
2057         pts[0] = pt1;
2058         angle = 360 - angle;
2059     }
2060     angle += dangle;
2061     pts[1].x = pts[0].x + MSin(angle+90)*arrowLen/100*arrowSize/100;
2062     pts[1].y = pts[0].y - MSin(angle)*arrowLen/100*arrowSize/100;
2063     angle -= 2*dangle;
2064     pts[2].x = pts[0].x + MSin(angle+90)*arrowLen/100*arrowSize/100;
2065     pts[2].y = pts[0].y - MSin(angle)*arrowLen/100*arrowSize/100;
2066   }
2067   if ( vis ) DrawLine (pt1, pt2);
2068   if ( pdata->fArrowPoint != 0xF ){
2069     FramePoly (3, pts);
2070     SetPrimAttribute (pdc, SHADING_ATT);
2071     PaintPoly (3, pts);
2072   }
2073   if ( dInfoPtr->highlight != PLAIN_SEGMENT ) {
2074     SetPrimAttribute (pdc, STYLE_ATT|WIDTH_ATT);
2075     WidePen((Int2)(((DrawInfoPtr)pdc)->primattrib->penwidth + 2));
2076     if ( vis ) DrawLine (pt1, pt2);
2077     if ( pdata->fArrowPoint != 0xF ){
2078       FramePoly (3, pts);
2079       SetPrimAttribute (pdc, SHADING_ATT);
2080       PaintPoly (3, pts);
2081     }
2082   }
2083 }
2084 
2085 static Boolean LineHitTestProc ( LinePDataPtr pdata, PrimHitContext phc)
2086 {
2087   register ScalePtr dInfoPtr;
2088   Int4  x1,y1,x2,y2;
2089  
2090   dInfoPtr = (ScalePtr)phc;
2091   if ( (pdata->box.left < dInfoPtr->worldWindow.right) && 
2092        (pdata->box.right > dInfoPtr->worldWindow.left) &&
2093        (pdata->box.top > dInfoPtr->worldWindow.bottom) &&
2094        (pdata->box.bottom < dInfoPtr->worldWindow.top) ) {
2095     x1 = pdata->box.left;
2096     x2 = pdata->box.right;
2097     if ( pdata->fPoint == 0 ) {
2098       y1 = pdata->box.bottom;
2099       y2 = pdata->box.top;
2100     } else {
2101       y2 = pdata->box.bottom;
2102       y1 = pdata->box.top;
2103     }
2104     return IsLineInVPort ( x1, y1, x2, y2, &(dInfoPtr->worldWindow) );
2105   }
2106   return FALSE; 
2107 }
2108 
2109 static Boolean LineOffsetProc ( LinePDataPtr pdata, Int4 deltaX, 
2110                                     Int4 deltaY )
2111 {
2112   pdata->box.left += deltaX;
2113   pdata->box.right += deltaX;
2114   pdata->box.top += deltaY;
2115   pdata->box.bottom += deltaY;
2116   return TRUE; 
2117 }
2118 
2119 static Boolean LineGetLimitsProc ( LinePDataPtr pdata, Int4 scaleX,
2120 Int4 scaleY, BoxPtr pLimits )
2121 {
2122   *pLimits = pdata->box;
2123   switch ( pdata->fArrowPoint ) {
2124     case 0:
2125       pLimits->right += pdata->arrowSize*scaleX/2;
2126       pLimits->top += pdata->arrowSize*scaleY/2;
2127       break;
2128     case 1:
2129       pLimits->right += pdata->arrowSize*scaleX/2;
2130       pLimits->bottom -= pdata->arrowSize*scaleY/2;
2131       break;
2132     case 2:
2133       pLimits->left -= pdata->arrowSize*scaleX/2;
2134       pLimits->bottom -= pdata->arrowSize*scaleY/2;
2135       break;
2136     case 3:
2137       pLimits->left -= pdata->arrowSize*scaleX/2;
2138       pLimits->top += pdata->arrowSize*scaleY/2;
2139   }
2140   OutsetBox ( pLimits, scaleX<<2, scaleY<<2 );
2141   return TRUE; 
2142 }
2143 
2144 static PrimDef linePrimDef = {
2145   (PrimDrawProc) LineDrawProc,
2146   (PrimHitTestProc) LineHitTestProc,
2147   (PrimOffsetProc) LineOffsetProc,
2148   (PrimCleanupProc) NULL,
2149   (PrimGetLimitsProc) LineGetLimitsProc
2150 };
2151 
2152 /*****************************************************************************
2153 *
2154 *   AddLine (parent, x1, y1, x2, y2, arrow, primID)
2155 *
2156 *****************************************************************************/
2157 
2158 PrimitivE Nlm_AddLine ( SegmenT parent, Int4 pnt1X, Int4 pnt1Y, Int4 pnt2X, 
2159                         Int4 pnt2Y, Boolean arrow, Uint2 primID )
2160 {
2161   LinePData data;
2162   GenPPtr   gpp;
2163 
2164   if ( pnt1Y == pnt2Y ){
2165     return Nlm_AddHLine ( parent, pnt1X, pnt2X, pnt2Y, arrow, primID );
2166   }
2167   if ( pnt1X == pnt2X ){
2168     return Nlm_AddVLine ( parent, pnt1X, pnt1Y, pnt2Y, arrow, primID );
2169   }
2170   if ( (pnt1X == pnt2X) || (pnt1Y == pnt2Y) ) arrow = FALSE;
2171   if ( pnt2X >= pnt1X ) {
2172     data.box.left = pnt1X;
2173     data.box.right = pnt2X;
2174     data.fArrowPoint = 0;
2175   } else {
2176     data.box.left = pnt2X;
2177     data.box.right = pnt1X;
2178     data.fArrowPoint = 2;
2179   }
2180   if ( pnt2Y >= pnt1Y ) {
2181     data.box.bottom = pnt1Y;
2182     data.box.top = pnt2Y;
2183     if ( data.fArrowPoint ) data.fArrowPoint = 3;
2184   } else {
2185     data.box.bottom = pnt2Y;
2186     data.box.top = pnt1Y;
2187     if ( data.fArrowPoint == 0 ) data.fArrowPoint = 1;
2188   }
2189   data.arrowSize = userArrowSize;
2190   if ( data.fArrowPoint & 0x1 ) data.fPoint = 1;
2191   else data.fPoint = 0;
2192   if ( arrow == FALSE ) data.fArrowPoint = (Int1)0xF;
2193   gpp = (GenPPtr)AddPrimitive (&linePrimDef, parent, primID, (VoidPtr)&data,
2194                                sizeof(LinePData));
2195   if ( gpp != NULL ){
2196     gpp->att.shading = SOLID_SHADING;
2197   }
2198   return (PrimitivE)gpp;
2199 }
2200 
2201 /*****************************************************************************
2202 *
2203 *     BITMAP & SYMBOL
2204 *
2205 *****************************************************************************/
2206 
2207 typedef struct bmppdata {
2208   Uint1Ptr bits;
2209   PntInfo  pnt;
2210   Int2     width;
2211   Int2     height;
2212   Int2     align;
2213 } BmpPData, PNTR BmpPDataPtr;
2214 
2215 static void BmpDrawProc (BmpPDataPtr pdata, PrimDrawContext pdc)
2216 {
2217   register DrawInfoPtr dInfoPtr;
2218   Int4     x, y;
2219   BoxInfo  tmpBox;
2220   RecT     r;
2221  
2222   dInfoPtr = (DrawInfoPtr)pdc;
2223   MakeAlignBox ( pdata->pnt.x, pdata->pnt.y, 
2224                  (Int4)pdata->width * dInfoPtr->scale.scaleX, 
2225                  (Int4)pdata->height * dInfoPtr->scale.scaleY, 
2226                   0, 0, pdata->align, &tmpBox );
2227   if ( (tmpBox.left > dInfoPtr->scale.worldWindow.right) || 
2228        (tmpBox.right < dInfoPtr->scale.worldWindow.left) || 
2229        (tmpBox.top < dInfoPtr->scale.worldWindow.bottom) || 
2230        (tmpBox.bottom > dInfoPtr->scale.worldWindow.top) ) return; 
2231   x = (dInfoPtr->scale.offsetX + pdata->pnt.x) / dInfoPtr->scale.scaleX;
2232   y = (dInfoPtr->scale.offsetY - pdata->pnt.y) / dInfoPtr->scale.scaleY;
2233   MakeAlignRect ( (Int2)x, (Int2)y, pdata->width, pdata->height, 
2234                   0, pdata->align, &r );
2235   SetPrimAttribute (pdc, COLOR_ATT|MODE_ATT);
2236   if (pdata->bits != NULL) CopyBits (&r, pdata->bits);
2237   switch ( dInfoPtr->highlight ) {
2238     case FRAME_PRIMITIVE:
2239     case FILL_PRIMITIVE:
2240     case OUTLINE_PRIMITIVE:
2241       r.right ++;  r.bottom ++;
2242       SetPrimAttribute (pdc, STYLE_ATT|WIDTH_ATT);
2243       FrameRect (&r);
2244       InsetRect (&r, -1, -1);
2245       FrameRect (&r);
2246   }
2247 }
2248 
2249 static Boolean BmpHitTestProc ( BmpPDataPtr pdata, PrimHitContext phc)
2250 {
2251   register ScalePtr dInfoPtr;
2252   BoxInfo  box;
2253  
2254   dInfoPtr = (ScalePtr)phc;
2255   MakeAlignBox ( pdata->pnt.x, pdata->pnt.y, 
2256                  (Int4)pdata->width * dInfoPtr->scaleX,
2257                  (Int4)pdata->height * dInfoPtr->scaleY,
2258                  0, 0, pdata->align, &box );
2259   if ( (box.left < dInfoPtr->worldWindow.right) && 
2260        (box.right > dInfoPtr->worldWindow.left) &&
2261        (box.top > dInfoPtr->worldWindow.bottom) &&
2262        (box.bottom < dInfoPtr->worldWindow.top) ) return TRUE; 
2263   return FALSE; 
2264 }
2265 
2266 static Boolean BmpOffsetProc ( BmpPDataPtr pdata, Int4 deltaX, 
2267                                Int4 deltaY )
2268 {
2269   pdata->pnt.x += deltaX;
2270   pdata->pnt.y += deltaY;
2271   return TRUE; 
2272 }
2273 
2274 static Boolean BmpGetLimitsProc ( BmpPDataPtr pdata, Int4 scaleX,
2275                                   Int4 scaleY, BoxPtr pLimits )
2276 {
2277   MakeAlignBox ( pdata->pnt.x, pdata->pnt.y, 
2278                  (Int4)pdata->width * scaleX,
2279                  (Int4)pdata->height * scaleY,
2280                  0, 0, pdata->align, pLimits );
2281   OutsetBox ( pLimits, scaleX<<2, scaleY<<2 );
2282   return TRUE; 
2283 }
2284 
2285 static PrimDef bmpPrimDef = {
2286   (PrimDrawProc) BmpDrawProc,
2287   (PrimHitTestProc) BmpHitTestProc,
2288   (PrimOffsetProc) BmpOffsetProc,
2289   (PrimCleanupProc) NULL,
2290   (PrimGetLimitsProc) BmpGetLimitsProc
2291 };
2292 
2293 /*****************************************************************************
2294 *
2295 *   AddBitmap (parent, pntX, pntY, width, height, data, align, primID)
2296 *
2297 *****************************************************************************/
2298 
2299 PrimitivE AddBitmap (SegmenT parent, Int4 pntX, Int4 pntY, Int2 width,
2300                      Int2 height, Uint1Ptr bits, Int2 align, Uint2 primID)
2301 {
2302   BmpPData data;
2303 
2304   data.pnt.x = pntX;
2305   data.pnt.y = pntY;
2306   data.bits = bits;
2307   data.width = width;
2308   data.height = height;
2309   data.align = align;
2310   return AddPrimitive (&bmpPrimDef, parent, primID, (VoidPtr)&data,
2311                        sizeof(BmpPData));
2312 }
2313 
2314 #define SYMBOL_WIDTH   8
2315 #define SYMBOL_HEIGHT  8
2316 
2317 static Uint1 rectSym [] = {
2318   0xFE, 0x82, 0x82, 0x82, 0x82, 0x82, 0xFE, 0x00
2319 };
2320 static Uint1 diamondSym [] = {
2321   0x10, 0x28, 0x44, 0x82, 0x44, 0x28, 0x10, 0x00
2322 };
2323 static Uint1 ovalSym [] = {
2324   0x38, 0x44, 0x82, 0x82, 0x82, 0x44, 0x38, 0x00
2325 };
2326 static Uint1 leftTriSym [] = {
2327   0x06, 0x1A, 0x62, 0x82, 0x62, 0x1A, 0x06, 0x00
2328 };
2329 static Uint1 rightTriSym [] = {
2330   0xC0, 0xB0, 0x8C, 0x82, 0x8C, 0xB0, 0xC0, 0x00
2331 };
2332 static Uint1 upTriSym [] = {
2333   0x10, 0x28, 0x28, 0x44, 0x44, 0x82, 0xFE, 0x00
2334 };
2335 static Uint1 downTriSym [] = {
2336   0xFE, 0x82, 0x44, 0x44, 0x28, 0x28, 0x10, 0x00
2337 };
2338 static Uint1 rectFillSym [] = {
2339   0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0x00
2340 };
2341 static Uint1 diamondFillSym [] = {
2342   0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00
2343 };
2344 static Uint1 ovalFillSym [] = {
2345   0x38, 0x7C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x00
2346 };
2347 static Uint1 leftTriFillSym [] = {
2348   0x06, 0x1E, 0x7E, 0xFE, 0x7E, 0x1E, 0x06, 0x00
2349 };
2350 static Uint1 rightTriFillSym [] = {
2351   0xC0, 0xF0, 0xFC, 0xFE, 0xFC, 0xF0, 0xC0, 0x00
2352 };
2353 static Uint1 upTriFillSym [] = {
2354   0x10, 0x38, 0x38, 0x7C, 0x7C, 0xFE, 0xFE, 0x00
2355 };
2356 static Uint1 downTriFillSym [] = {
2357   0xFE, 0xFE, 0x7C, 0x7C, 0x38, 0x38, 0x10, 0x00
2358 };
2359 
2360 static Uint1Ptr symbolList [] = {
2361   rectSym, diamondSym, ovalSym, leftTriSym,
2362   rightTriSym, upTriSym, downTriSym,
2363   rectFillSym, diamondFillSym, ovalFillSym, leftTriFillSym,
2364   rightTriFillSym, upTriFillSym, downTriFillSym
2365 };
2366 
2367 /*****************************************************************************
2368 *
2369 *   AddSymbol (parent, pntX, pntY, symbol, fill, align, primID)
2370 *
2371 *****************************************************************************/
2372 
2373 PrimitivE AddSymbol (SegmenT parent, Int4 pntX, Int4 pntY,
2374                      Int2 symbol, Boolean fill, Int2 align, Uint2 primID)
2375 
2376 {
2377   Int2 index;
2378 
2379   if (symbol < RECT_SYMBOL || symbol > DOWN_TRIANGLE_SYMBOL) {
2380     Message (MSG_ERROR, "AddSymbol symbol out of range");
2381     return NULL;
2382   }
2383   index = symbol - (Int2)RECT_SYMBOL;
2384   if (fill) index += 7;
2385   return AddBitmap (parent, pntX, pntY, SYMBOL_WIDTH, SYMBOL_HEIGHT,
2386                     symbolList [index], align, primID);
2387 }
2388 
2389 /*****************************************************************************
2390 *
2391 *     MARKER
2392 *
2393 *****************************************************************************/
2394 typedef struct markpdata {
2395   PntInfo  pnt;
2396   Int2     length;
2397   Int2     orient;
2398 } MarkPData, PNTR MarkPDataPtr;
2399 
2400 static void MarkDrawProc (MarkPDataPtr pdata, PrimDrawContext pdc)
2401 {
2402   register DrawInfoPtr dInfoPtr;
2403   Int4     x1, y1, x2, y2;
2404   Int4     curScale;
2405   Int4     len;
2406  
2407   dInfoPtr = (DrawInfoPtr)pdc;
2408   curScale = dInfoPtr->scale.scaleX;
2409   len = (Int4)pdata->length * curScale;
2410   x1 = (dInfoPtr->scale.offsetX + pdata->pnt.x) / curScale;
2411   if ( ( (pdata->pnt.x+len) < dInfoPtr->scale.worldWindow.left) ||
2412        ( (pdata->pnt.x-len) > dInfoPtr->scale.worldWindow.right) ) return;
2413   curScale = dInfoPtr->scale.scaleY;
2414   len = (Int4)pdata->length * curScale;
2415   y1 = (dInfoPtr->scale.offsetY - pdata->pnt.y) / curScale;
2416   if ( ((pdata->pnt.y+len) < dInfoPtr->scale.worldWindow.bottom) ||
2417        ((pdata->pnt.y-len) > dInfoPtr->scale.worldWindow.top) ) return;
2418   switch (pdata->orient){
2419     case HORIZ_LEFT :
2420       x2 = x1; y2 = y1;
2421       x1 -= (Int4)pdata->length;
2422       break;
2423     case HORIZ_CENTER :
2424       x2 = x1+(Int4)pdata->length / 2; y2 = y1;
2425       x1 = x2 - (Int4)pdata->length;
2426       break;
2427     case HORIZ_RIGHT :
2428       x2 = x1 + (Int4)pdata->length; y2 = y1;
2429       break;
2430     case VERT_ABOVE :
2431       x2 = x1; y2 = y1 - (Int4)pdata->length;
2432       break;
2433     case VERT_MIDDLE :
2434       x2 = x1; y2 = y1 - (Int4)pdata->length / 2;
2435       y1 = y2 + (Int4)pdata->length;
2436       break;
2437     default:
2438       x2 = x1; y2 = y1;
2439       y1 += (Int4)pdata->length;
2440   }
2441   SetPrimAttribute (pdc, COLOR_ATT|STYLE_ATT|WIDTH_ATT|MODE_ATT);
2442   MoveTo ((Int2)x1, (Int2)y1);
2443   LineTo ((Int2)x2, (Int2)y2);
2444   if ( dInfoPtr->highlight != PLAIN_SEGMENT ) {
2445     WidePen((Int2)(((DrawInfoPtr)pdc)->primattrib->penwidth + 2));
2446     MoveTo ((Int2)x1, (Int2)y1);
2447     LineTo ((Int2)x2, (Int2)y2);
2448   }
2449 }
2450 
2451 static Boolean MarkHitTestProc ( MarkPDataPtr pdata, PrimHitContext phc)
2452 {
2453   register ScalePtr dInfoPtr;
2454   Int4     curScale;
2455   Int4     lenXY;
2456 
2457   dInfoPtr = (ScalePtr)phc;
2458   switch (pdata->orient){
2459     case HORIZ_LEFT :
2460     case HORIZ_CENTER :
2461     case HORIZ_RIGHT :
2462       lenXY = pdata->pnt.y;
2463       if ( (lenXY < dInfoPtr->worldWindow.bottom) ||
2464            (lenXY > dInfoPtr->worldWindow.top )) return FALSE;
2465       curScale = dInfoPtr->scaleX;
2466       lenXY = (Int4)pdata->length * curScale;
2467       switch (pdata->orient){
2468         case HORIZ_LEFT :
2469           if ( (pdata->pnt.x < dInfoPtr->worldWindow.left) ||
2470                ((pdata->pnt.x - lenXY) > dInfoPtr->worldWindow.right)) 
2471             return FALSE;
2472           break;
2473         case HORIZ_CENTER :
2474           lenXY /= 2;
2475           if ( ((pdata->pnt.x + lenXY) < dInfoPtr->worldWindow.left) ||
2476                ((pdata->pnt.x - lenXY) > dInfoPtr->worldWindow.right))
2477             return FALSE;
2478           break;
2479         default:
2480           if ( ((pdata->pnt.x + lenXY) < dInfoPtr->worldWindow.left) ||
2481                ( pdata->pnt.x > dInfoPtr->worldWindow.right)) 
2482             return FALSE;
2483       }
2484       break;
2485     default:
2486       lenXY = pdata->pnt.x;
2487       if ( (lenXY < dInfoPtr->worldWindow.left) ||
2488            (lenXY > dInfoPtr->worldWindow.right )) return FALSE;
2489       curScale = dInfoPtr->scaleY;
2490       lenXY = (Int4)pdata->length * curScale;
2491       switch (pdata->orient){
2492         case VERT_ABOVE :
2493           if ( ((pdata->pnt.y + lenXY) < dInfoPtr->worldWindow.bottom) ||
2494                (pdata->pnt.y > dInfoPtr->worldWindow.top)) 
2495             return FALSE;
2496           break;
2497         case VERT_MIDDLE :
2498           lenXY /= 2;
2499           if ( ((pdata->pnt.y + lenXY) < dInfoPtr->worldWindow.bottom) ||
2500                ((pdata->pnt.y - lenXY) > dInfoPtr->worldWindow.top)) 
2501             return FALSE;
2502           break;
2503         default:
2504           if ( (pdata->pnt.y < dInfoPtr->worldWindow.bottom) ||
2505                ((pdata->pnt.y - lenXY) > dInfoPtr->worldWindow.top)) 
2506             return FALSE;
2507           break;
2508       }
2509   }
2510   return TRUE;
2511 }
2512 
2513 static Boolean MarkOffsetProc ( MarkPDataPtr pdata, Int4 deltaX, 
2514                                     Int4 deltaY )
2515 {
2516   pdata->pnt.x += deltaX;
2517   pdata->pnt.y += deltaY;
2518   return TRUE; 
2519 }
2520 
2521 static Boolean MarkGetLimitsProc ( MarkPDataPtr pdata, Int4 scaleX,
2522 Int4 scaleY, BoxPtr pLimits )
2523 {
2524   LoadBox (pLimits, pdata->pnt.x, pdata->pnt.y, pdata->pnt.x, pdata->pnt.y);
2525   switch (pdata->orient){
2526     case HORIZ_LEFT :
2527       pLimits->left -= (Int4)pdata->length * scaleX;
2528       break;
2529     case HORIZ_CENTER :
2530       pLimits->left -= (Int4)pdata->length * scaleX / 2;
2531       pLimits->right += (Int4)pdata->length * scaleX / 2;
2532       break;
2533     case HORIZ_RIGHT :
2534       pLimits->right += (Int4)pdata->length * scaleX;
2535       break;
2536     case VERT_ABOVE :
2537       pLimits->top += (Int4)pdata->length * scaleY;
2538       break;
2539     case VERT_MIDDLE :
2540       pLimits->top += (Int4)pdata->length * scaleY / 2;
2541       pLimits->bottom -= (Int4)pdata->length * scaleY / 2;
2542       break;
2543     default:
2544       pLimits->bottom -= (Int4)pdata->length * scaleY;
2545   }
2546   OutsetBox ( pLimits, scaleX<<2, scaleY<<2 );
2547   return TRUE; 
2548 }
2549 
2550 static PrimDef markPrimDef = {
2551   (PrimDrawProc) MarkDrawProc,
2552   (PrimHitTestProc) MarkHitTestProc,
2553   (PrimOffsetProc) MarkOffsetProc,
2554   (PrimCleanupProc) NULL,
2555   (PrimGetLimitsProc) MarkGetLimitsProc
2556 };
2557 
2558 /*****************************************************************************
2559 *
2560 *   AddMarker (parent, pntX, pntY, length, orient, primID)
2561 *
2562 *****************************************************************************/
2563 
2564 PrimitivE AddMarker (SegmenT parent, Int4 pntX, Int4 pntY,
2565                      Int2 length, Int2 orient, Uint2 primID)
2566 {
2567   MarkPData data;
2568 
2569   data.pnt.x = pntX;
2570   data.pnt.y = pntY;
2571   data.length = length;
2572   data.orient = orient;
2573   return AddPrimitive (&markPrimDef, parent, primID, (VoidPtr)&data,
2574                        sizeof(MarkPData));
2575 }
2576 
2577 /*****************************************************************************
2578 *
2579 *     TEXT LABEL
2580 *
2581 *****************************************************************************/
2582 
2583 typedef struct lblpdata {
2584   PntInfo  pnt;
2585   FonT     font;
2586   Int2     width;
2587   Int2     height;
2588   Int2     align;
2589   Int2     offset;
2590   Char     str;
2591 } LblPData, PNTR LblPDataPtr;
2592 
2593 
2594 static void LblDrawProc (LblPDataPtr pdata, PrimDrawContext pdc)
2595 {
2596   register DrawInfoPtr dInfoPtr;
2597   BoxInfo  tmpBox;
2598   Int4     x, y;
2599   RecT     r;
2600  
2601   dInfoPtr = (DrawInfoPtr)pdc;
2602   MakeAlignBox ( pdata->pnt.x, pdata->pnt.y, 
2603                  (Int4)pdata->width * dInfoPtr->scale.scaleX, 
2604                  (Int4)pdata->height * dInfoPtr->scale.scaleY, 
2605                   pdata->offset * dInfoPtr->scale.scaleX,
2606                   pdata->offset * dInfoPtr->scale.scaleY,
2607                   pdata->align, &tmpBox );
2608   if ( (tmpBox.left > dInfoPtr->scale.worldWindow.right) || 
2609        (tmpBox.right < dInfoPtr->scale.worldWindow.left) || 
2610        (tmpBox.top < dInfoPtr->scale.worldWindow.bottom) || 
2611        (tmpBox.bottom > dInfoPtr->scale.worldWindow.top) ) return; 
2612   x = (dInfoPtr->scale.offsetX + pdata->pnt.x) / dInfoPtr->scale.scaleX;
2613   y = (dInfoPtr->scale.offsetY - pdata->pnt.y) / dInfoPtr->scale.scaleY;
2614   MakeAlignRect ( (Int2)x, (Int2)y, pdata->width, pdata->height, 
2615                   pdata->offset, pdata->align, &r );
2616   SelectFont (pdata->font);
2617   SetPrimAttribute (pdc, COLOR_ATT|MODE_ATT);
2618   PaintStringEx(&pdata->str, r.left, (Nlm_Int2)(r.top + Ascent()));
2619   if ( dInfoPtr->highlight == OUTLINE_PRIMITIVE ){
2620     r.right ++;  r.bottom ++;
2621     SetPrimAttribute (pdc, STYLE_ATT|WIDTH_ATT);
2622     FrameRect (&r);
2623     InsetRect (&r, -1, -1);
2624     FrameRect (&r);
2625   }
2626 }
2627 
2628 static Boolean LblHitTestProc (LblPDataPtr pdata, PrimHitContext phc )
2629 {
2630   register ScalePtr dInfoPtr;
2631   BoxInfo  box;
2632  
2633   dInfoPtr = (ScalePtr)phc;
2634   MakeAlignBox ( pdata->pnt.x, pdata->pnt.y, 
2635                  (Int4)pdata->width * dInfoPtr->scaleX,
2636                  (Int4)pdata->height * dInfoPtr->scaleY,
2637                  pdata->offset * dInfoPtr->scaleX,
2638                  pdata->offset * dInfoPtr->scaleY,
2639                  pdata->align, &box );
2640   if ( (box.left < dInfoPtr->worldWindow.right) && 
2641        (box.right > dInfoPtr->worldWindow.left) &&
2642        (box.top > dInfoPtr->worldWindow.bottom) &&
2643        ((box.bottom + (dInfoPtr->scaleY<<1)) < dInfoPtr->worldWindow.top) )
2644     return TRUE; 
2645   return FALSE; 
2646 }
2647 
2648 static void LblCleanupProc (LblPDataPtr pdata)
2649 {
2650   DeleteFont (pdata->font);
2651 }
2652 
2653 static Boolean LblOffsetProc (LblPDataPtr pdata, Int4 deltaX, Int4 deltaY)
2654 {
2655   pdata->pnt.x += deltaX;
2656   pdata->pnt.y += deltaY;
2657   return TRUE;
2658 }
2659 
2660 static Boolean LblGetLimitsProc ( LblPDataPtr pdata, Int4 scaleX,
2661                                   Int4 scaleY, BoxPtr pLimits )
2662 {
2663   MakeAlignBox ( pdata->pnt.x, pdata->pnt.y, 
2664                  (Int4)pdata->width * scaleX,
2665                  (Int4)pdata->height * scaleY,
2666                  pdata->offset * scaleX,
2667                  pdata->offset * scaleY,
2668                  pdata->align, pLimits );
2669   OutsetBox ( pLimits, scaleX<<2, scaleY<<2 );
2670   return TRUE; 
2671 }
2672 
2673 static PrimDef lblPrimDef = {
2674   (PrimDrawProc) LblDrawProc,
2675   (PrimHitTestProc) LblHitTestProc,
2676   (PrimOffsetProc) LblOffsetProc,
2677   (PrimCleanupProc) LblCleanupProc,
2678   (PrimGetLimitsProc) LblGetLimitsProc
2679 };
2680 
2681 /*****************************************************************************
2682 *
2683 *   AddTextLabel (parent, pntX, pntY, string, font, offset, align, primID)
2684 *
2685 *****************************************************************************/
2686 
2687 PrimitivE Nlm_AddTextLabel (SegmenT parent, Int4 pntX, Int4 pntY,
2688                             const Char* string, FonT font, Int2 offset, 
2689                             Int2 align, Uint2 primID )
2690 {
2691   size_t      data_size = sizeof(LblPData) + Nlm_StringLen(string) + 1;
2692   LblPDataPtr dataPtr   = (LblPDataPtr)MemNew( data_size );
2693   PrimitivE   txtLabel;
2694 
2695   dataPtr->pnt.x = pntX;
2696   dataPtr->pnt.y = pntY;
2697   Nlm_StringCpy(&(dataPtr->str), string);
2698   dataPtr->font = CopyFont (font);
2699   SelectFont (font);
2700   dataPtr->width = StringWidth (string) + 2;
2701   dataPtr->height = LineHeight () + 2;
2702   dataPtr->align = align;
2703   dataPtr->offset = offset;
2704   SelectFont (programFont);
2705   txtLabel = AddPrimitive (&lblPrimDef, parent, primID,
2706                            (VoidPtr)dataPtr, (Int2)data_size);
2707   MemFree ( dataPtr );
2708   return txtLabel;
2709 }
2710 
2711 /*****************************************************************************
2712 *
2713 *   AddLabel (parent, pntX, pntY, string, size, offset, align, primID)
2714 *
2715 *****************************************************************************/
2716 
2717 PrimitivE AddLabel (SegmenT parent, Int4 pntX, Int4 pntY, const Char* string,
2718                     Int2 size, Int2 offset, Int2 align, Uint2 primID)
2719 {
2720   FonT  font;
2721   switch (size) {
2722     case SMALL_TEXT:
2723       if (smallFont == NULL)   SetSmallFont ();
2724       font = smallFont;
2725       break;
2726     case MEDIUM_TEXT:
2727       if (mediumFont == NULL)  SetMediumFont ();
2728       font = mediumFont;
2729       break;
2730     case LARGE_TEXT:
2731       if (largeFont == NULL)   SetLargeFont ();
2732       font = largeFont;
2733       break;
2734     default :
2735       font = programFont;
2736       break;
2737   }
2738   return AddTextLabel (parent, pntX, pntY, string, font,
2739                        offset, align, primID);
2740 }
2741 
2742 
2743 /*****************************************************************************
2744 *
2745 *     OVAL
2746 *
2747 *****************************************************************************/
2748 
2749 typedef struct {
2750   PntInfo pnt;
2751   Int4    radx;
2752   Int4    rady;
2753   Boolean fill;
2754 } OvalPData, PNTR OvalPDataPtr;
2755 
2756 
2757 static void OvalDrawProc(OvalPDataPtr pdata, PrimDrawContext pdc)
2758 {
2759   DrawInfoPtr dInfoPtr = (DrawInfoPtr)pdc;
2760   Int4 rad;
2761   Int4 tmp4;
2762   Int2 radx, rady;
2763   Int2 cx, cy;
2764   RecT oval_rect;
2765  
2766   rad = pdata->radx;
2767   tmp4 = pdata->pnt.x;
2768   if ((tmp4-rad) > dInfoPtr->scale.worldWindow.right || 
2769       (tmp4+rad) < dInfoPtr->scale.worldWindow.left)
2770     return;
2771 
2772   rad = pdata->rady;
2773   tmp4 = pdata->pnt.y;
2774   if ((tmp4+rad) < dInfoPtr->scale.worldWindow.bottom  || 
2775       (tmp4-rad) > dInfoPtr->scale.worldWindow.top)
2776     return; 
2777 
2778   radx = (Int2)(pdata->radx / dInfoPtr->scale.scaleX);
2779   rady = (Int2)(pdata->rady / dInfoPtr->scale.scaleY);
2780   cx = (Int2)((dInfoPtr->scale.offsetX + pdata->pnt.x)
2781        / dInfoPtr->scale.scaleX);
2782   cy = (Int2)((dInfoPtr->scale.offsetY - pdata->pnt.y)
2783        / dInfoPtr->scale.scaleY);
2784   LoadRect(&oval_rect,
2785            (Int2)(cx - radx),     (Int2)(cy - rady),
2786            (Int2)(cx + radx + 1), (Int2)(cy + rady + 1));
2787 
2788   if ( pdata->fill ) {
2789     SetPrimAttribute(pdc, COLOR_ATT|SHADING_ATT|MODE_ATT);
2790     PaintOval(&oval_rect);
2791   }
2792   else {
2793     SetPrimAttribute(pdc, COLOR_ATT|STYLE_ATT|WIDTH_ATT|MODE_ATT);
2794     FrameOval(&oval_rect);
2795   }
2796 
2797   switch ( dInfoPtr->highlight ) {
2798   case PLAIN_SEGMENT:
2799     break;
2800   case FILL_PRIMITIVE:
2801     if ( !pdata->fill ) {
2802       SetPrimAttribute (pdc, SHADING_ATT);
2803       PaintOval(&oval_rect);
2804     }
2805     break;
2806   default :
2807     SetPrimAttribute (pdc, STYLE_ATT|WIDTH_ATT);
2808     FrameRect(&oval_rect);
2809     InsetRect(&oval_rect, -1, -1);
2810     FrameRect(&oval_rect);
2811   }
2812 }
2813 
2814 
2815 static Boolean OvalHitTestProc(OvalPDataPtr pdata, PrimHitContext phc)
2816 {
2817   ScalePtr dInfoPtr = (ScalePtr)phc;
2818   Int4     x,y;
2819   Int4     dx,dy;
2820   Int4     deltax, deltay;
2821   Int2     angle;
2822  
2823   if ((pdata->pnt.x - pdata->radx) > dInfoPtr->worldWindow.right  ||
2824       (pdata->pnt.x + pdata->radx) < dInfoPtr->worldWindow.left   ||
2825       (pdata->pnt.y - pdata->rady) > dInfoPtr->worldWindow.top    ||
2826       (pdata->pnt.y + pdata->rady) < dInfoPtr->worldWindow.bottom) 
2827     return FALSE;
2828 
2829   x = (dInfoPtr->worldWindow.right + dInfoPtr->worldWindow.left) / 2;
2830   y = (dInfoPtr->worldWindow.top + dInfoPtr->worldWindow.bottom) / 2;
2831   deltax = dInfoPtr->worldWindow.right - dInfoPtr->worldWindow.left;
2832   deltay = dInfoPtr->worldWindow.top - dInfoPtr->worldWindow.bottom;
2833   dx = x - pdata->pnt.x;
2834   dy = y - pdata->pnt.y;
2835   if (!dx  &&  !dy)
2836     return TRUE;
2837   x = (dx > 0) ? dx : -dx;
2838   y = (dy > 0) ? dy : -dy;
2839   if (x > y)
2840     angle = atan100[y * 100 / x];
2841   else
2842     angle = 90 - atan100[x * 100 / y] ;
2843   dx = (Int4)MSin(90 + angle) * pdata->radx / 100L;
2844   dy = (Int4)MSin(     angle) * pdata->rady / 100L;
2845 
2846   return (Boolean)(dx + deltax > x  &&  dy + deltay > y);
2847 }
2848 
2849 static Boolean OvalOffsetProc(OvalPDataPtr pdata, Int4 deltaX, Int4 deltaY)
2850 {
2851   pdata->pnt.x += deltaX;
2852   pdata->pnt.y += deltaY;
2853   return TRUE;
2854 }
2855 
2856 static Boolean OvalGetLimitsProc(OvalPDataPtr pdata,
2857                                  Int4 scaleX, Int4 scaleY, BoxPtr pLimits)
2858 {
2859   Int4 xy = pdata->pnt.x;
2860   pLimits->left   = xy - pdata->radx;
2861   pLimits->right  = xy + pdata->radx;
2862   xy = pdata->pnt.y;
2863   pLimits->bottom = xy - pdata->rady;
2864   pLimits->top    = xy + pdata->rady;
2865   OutsetBox(pLimits, scaleX<<2, scaleY<<2);
2866   return TRUE;
2867 }
2868 
2869 static PrimDef ovalPrimDef = {
2870   (PrimDrawProc     ) OvalDrawProc,
2871   (PrimHitTestProc  ) OvalHitTestProc,
2872   (PrimOffsetProc   ) OvalOffsetProc,
2873   (PrimCleanupProc  ) NULL,
2874   (PrimGetLimitsProc) OvalGetLimitsProc
2875 };
2876 
2877 /*****************************************************************************
2878 *
2879 *   AddOval (parent, pntX, pntY, radius, fill, primID)
2880 *
2881 *****************************************************************************/
2882 
2883 PrimitivE AddOval(SegmenT parent, Int4 pntX, Int4 pntY, Int4 radiusX,
2884                   Int4 radiusY, Boolean fill, Uint2 primID)
2885 {
2886   OvalPData data;
2887 
2888   data.pnt.x = pntX;
2889   data.pnt.y = pntY;
2890   data.radx = radiusX;
2891   data.rady = radiusY;
2892   data.fill = fill;
2893   return AddPrimitive(&ovalPrimDef, parent, primID, (VoidPtr)&data,
2894                       sizeof(OvalPData));
2895 }
2896 
2897 
2898 /*****************************************************************************
2899 *
2900 *     ARC
2901 *
2902 *****************************************************************************/
2903 
2904 typedef struct arcpdata {
2905   BoxInfo  box;
2906   PntInfo  pnt;
2907   Int4     radx;
2908   Int4     rady;
2909   Int4     start;
2910   Int4     end;
2911   Boolean  fill;
2912 } ArcPData, PNTR ArcPDataPtr;
2913 
2914 static void FrameArcProc ( Int2 pNum, PoinT PNTR points )
2915 {
2916   Int2 i;
2917 
2918   MoveTo ( points->x, points->y );
2919   points++;
2920   for (i=1; i<pNum; i++ ){
2921     LineTo ( points->x, points->y );
2922     points++;
2923   }
2924 }
2925 
2926 static void ArcDrawProc (ArcPDataPtr pdata, PrimDrawContext pdc)
2927 {
2928   register DrawInfoPtr dInfoPtr;
2929   BoxInfo tmpBox;
2930   Int4     curScale;
2931   Int2     radx, rady;
2932   Int2     cx, cy;
2933   Int2     i,j,pNum;
2934   Int2     start, end;
2935   Int2     step;
2936   RecT     r;
2937  
2938   dInfoPtr = (DrawInfoPtr)pdc;
2939   tmpBox = pdata->box;
2940   if ( (tmpBox.left > dInfoPtr->scale.worldWindow.right) || 
2941        (tmpBox.right < dInfoPtr->scale.worldWindow.left) || 
2942        (tmpBox.top < dInfoPtr->scale.worldWindow.bottom) || 
2943        (tmpBox.bottom > dInfoPtr->scale.worldWindow.top) ) return; 
2944   radx = (Int2)(pdata->radx / dInfoPtr->scale.scaleX);
2945   rady = (Int2)(pdata->rady / dInfoPtr->scale.scaleY);
2946   cx = (Int2)((dInfoPtr->scale.offsetX + pdata->pnt.x)
2947        / dInfoPtr->scale.scaleX);
2948   cy = (Int2)((dInfoPtr->scale.offsetY - pdata->pnt.y)
2949        / dInfoPtr->scale.scaleY);
2950   if ( radx < rady ) i = rady;
2951   else i = radx;
2952   if ( i < 10 ) step = 10;
2953   else if ( i < 30 ) step = 5;
2954   else if ( i < 60 ) step = 3;
2955   else step = 1;
2956   start = (Int2) (pdata->start / 1000);
2957   end = (Int2) (pdata->end / 1000);
2958   if ( end < start ) end += 360;
2959   polyPoints[0].x = cx;
2960   polyPoints[0].y = cy;
2961   pNum = 1;
2962   for (j=0; j<2; j++ ) {
2963     for ( i=MAX(0,start); (i<90) && (i<=end); i+= step){
2964       polyPoints[pNum].x = cx + 
2965         (Int2)(((Int4)radx * (Int4)sin100[90-i]) / (Int4)100);
2966       polyPoints[pNum++].y = cy - 
2967         (Int2)(((Int4)rady * (Int4)sin100[i]) / (Int4)100);
2968     }
2969     start -= 90; end -= 90;
2970     for ( i=MAX(0,start); (i<90) && (i<=end); i+= step){
2971       polyPoints[pNum].x = cx -
2972         (Int2)(((Int4)radx * (Int4)sin100[i]) / (Int4)100);
2973       polyPoints[pNum++].y = cy - 
2974         (Int2)(((Int4)rady * (Int4)sin100[90-i]) / (Int4)100);
2975     }
2976     start -= 90; end -= 90;
2977     for ( i=MAX(0,start); (i<90) && (i<=end); i+= step){
2978       polyPoints[pNum].x = cx -
2979         (Int2)(((Int4)radx * (Int4)sin100[90-i]) / (Int4)100);
2980       polyPoints[pNum++].y = cy + 
2981       (Int2)(((Int4)rady * (Int4)sin100[i]) / (Int4)100);
2982     }
2983     start -= 90; end -= 90;
2984     for ( i=MAX(0,start); (i<90) && (i<=end); i+= step){
2985       polyPoints[pNum].x = cx + 
2986         (Int2)(((Int4)radx * (Int4)sin100[i]) / (Int4)100);
2987       polyPoints[pNum++].y = cy + 
2988         (Int2)(((Int4)rady * (Int4)sin100[90-i]) / (Int4)100);
2989     }
2990     start -= 90; end -= 90;
2991   }
2992   if (pdata->fill) {
2993     SetPrimAttribute (pdc, COLOR_ATT|SHADING_ATT|MODE_ATT);
2994   } else {
2995     SetPrimAttribute (pdc, COLOR_ATT|STYLE_ATT|WIDTH_ATT|MODE_ATT);
2996   }
2997   if ( pdata->fill ) PaintPoly(pNum, polyPoints);
2998   else FrameArcProc ( (Int2)(pNum-1), &(polyPoints[1]));
2999   switch ( dInfoPtr->highlight ) {
3000     case PLAIN_SEGMENT:
3001       break;
3002     case FILL_PRIMITIVE:
3003       if ( pdata->fill == 0 ) {
3004         SetPrimAttribute (pdc, SHADING_ATT);
3005         PaintPoly(pNum, polyPoints);
3006       }
3007       break;
3008     default :
3009       curScale = dInfoPtr->scale.scaleX;
3010       r.left = (Int2)((dInfoPtr->scale.offsetX + tmpBox.left) / curScale);
3011       r.right = (Int2)((dInfoPtr->scale.offsetX + tmpBox.right) / curScale)+1;
3012       curScale = dInfoPtr->scale.scaleY;
3013       r.top = (Int2)((dInfoPtr->scale.offsetY - tmpBox.top) / curScale);
3014       r.bottom = (Int2)((dInfoPtr->scale.offsetY - tmpBox.bottom) / curScale)+1;
3015       SetPrimAttribute (pdc, STYLE_ATT|WIDTH_ATT);
3016       FrameRect (&r);
3017       InsetRect (&r, -1, -1);
3018       FrameRect (&r);
3019   }
3020 }
3021 
3022 static Boolean ArcHitTestProc ( ArcPDataPtr pdata, PrimHitContext phc)
3023 {
3024   register ScalePtr dInfoPtr;
3025  
3026   dInfoPtr = (ScalePtr)phc;
3027   if ( (pdata->box.left < dInfoPtr->worldWindow.right) && 
3028        (pdata->box.right > dInfoPtr->worldWindow.left) &&
3029        (pdata->box.top > dInfoPtr->worldWindow.bottom) &&
3030        (pdata->box.bottom < dInfoPtr->worldWindow.top) ) return TRUE;
3031   return FALSE;
3032 }
3033 
3034 static Boolean ArcOffsetProc ( ArcPDataPtr pdata, Int4 deltaX, 
3035                                Int4 deltaY )
3036 {
3037   pdata->pnt.x += deltaX;
3038   pdata->pnt.y += deltaY;
3039   pdata->box.left += deltaX;
3040   pdata->box.right += deltaX;
3041   pdata->box.bottom += deltaY;
3042   pdata->box.top += deltaY;
3043   return TRUE;
3044 }
3045 
3046 static Boolean ArcGetLimitsProc ( ArcPDataPtr pdata, Int4 scaleX,
3047                                   Int4 scaleY, BoxPtr pLimits )
3048 {
3049   *pLimits = pdata->box;
3050   return TRUE;
3051 }
3052 
3053 static PrimDef arcPrimDef = {
3054   (PrimDrawProc) ArcDrawProc,
3055   (PrimHitTestProc) ArcHitTestProc,
3056   (PrimOffsetProc) ArcOffsetProc,
3057   (PrimCleanupProc) NULL,
3058   (PrimGetLimitsProc) ArcGetLimitsProc
3059 };
3060 
3061 /*****************************************************************************
3062 *
3063 *   AddArc (parent, pntX, pntY, radius, start, end, fill, primID)
3064 *
3065 *****************************************************************************/
3066 
3067 PrimitivE AddArc (SegmenT parent, Int4 pntX, Int4 pntY, Int4 radiusX,
3068                   Int4 radiusY, Int4 start, Int4 end, Boolean fill, 
3069                   Uint2 primID)
3070 {
3071   ArcPData data;
3072 
3073   data.pnt.x = pntX;
3074   data.pnt.y = pntY;
3075   data.radx = radiusX;
3076   data.rady = radiusY;
3077   data.start = start;
3078   data.end = end;
3079   data.fill = fill;
3080   data.box.left = pntX - radiusX;
3081   data.box.right = pntX + radiusX;
3082   data.box.top = pntY + radiusY;
3083   data.box.bottom = pntY - radiusY;
3084   return AddPrimitive (&arcPrimDef, parent, primID, (VoidPtr)&data,
3085                        sizeof(ArcPData));
3086 }
3087 
3088 /*****************************************************************************
3089 *
3090 *     POLYGON
3091 *
3092 *****************************************************************************/
3093 typedef struct polpdata {
3094   BoxInfo  box;
3095   Int2     vernum;
3096   Int2     fill;
3097   PntInfo  pnt;
3098 } PolyPData, PNTR PolyPDataPtr;
3099 
3100 static void PolyDrawProc (PolyPDataPtr pdata, PrimDrawContext pdc)
3101 {
3102   register DrawInfoPtr dInfoPtr;
3103   PntPtr   pPtr;
3104   BoxInfo  tmpBox;
3105   Int4     curScale;
3106   RecT     r;
3107   Int2     vernum;
3108   Int2     i;
3109  
3110   dInfoPtr = (DrawInfoPtr)pdc;
3111   tmpBox = pdata->box;
3112   if ( (tmpBox.left > dInfoPtr->scale.worldWindow.right) || 
3113        (tmpBox.right < dInfoPtr->scale.worldWindow.left) || 
3114        (tmpBox.top < dInfoPtr->scale.worldWindow.bottom) || 
3115        (tmpBox.bottom > dInfoPtr->scale.worldWindow.top) ) return; 
3116   if (pdata->fill) {
3117     SetPrimAttribute (pdc, COLOR_ATT|SHADING_ATT|MODE_ATT);
3118   } else {
3119     SetPrimAttribute (pdc, COLOR_ATT|STYLE_ATT|WIDTH_ATT|MODE_ATT);
3120   }
3121   vernum = pdata->vernum;
3122   pPtr = &(pdata->pnt);
3123   for ( i=0; i<vernum; i++ ){
3124     polyPoints[i].x = (Int2)((dInfoPtr->scale.offsetX + pPtr->x)
3125                       / dInfoPtr->scale.scaleX);
3126     polyPoints[i].y = (Int2)((dInfoPtr->scale.offsetY - pPtr->y)
3127                       / dInfoPtr->scale.scaleY);
3128     pPtr++;
3129   }
3130   if ( pdata->fill ) PaintPoly(vernum, polyPoints);
3131   else FramePoly(vernum, polyPoints);
3132   switch ( dInfoPtr->highlight ) {
3133     case PLAIN_SEGMENT:
3134       break;
3135     case FILL_PRIMITIVE:
3136       if ( pdata->fill == 0 ) {
3137         SetPrimAttribute (pdc, SHADING_ATT);
3138         PaintPoly(vernum, polyPoints);
3139       }
3140       break;
3141     default:
3142       curScale = dInfoPtr->scale.scaleX;
3143       r.left = (Int2)((dInfoPtr->scale.offsetX + tmpBox.left) / curScale);
3144       r.right = (Int2)((dInfoPtr->scale.offsetX + tmpBox.right) / curScale)+1;
3145       curScale = dInfoPtr->scale.scaleY;
3146       r.top = (Int2)((dInfoPtr->scale.offsetY - tmpBox.top) / curScale);
3147       r.bottom = (Int2)((dInfoPtr->scale.offsetY - tmpBox.bottom) / curScale)+1;
3148       SetPrimAttribute (pdc, STYLE_ATT|WIDTH_ATT);
3149       FrameRect (&r);
3150       InsetRect (&r, -1, -1);
3151       FrameRect (&r);
3152   }
3153 }
3154 
3155 static Boolean PolyHitTestProc ( PolyPDataPtr pdata, PrimHitContext phc)
3156 {
3157   register ScalePtr dInfoPtr;
3158  
3159   dInfoPtr = (ScalePtr)phc;
3160   if ( (pdata->box.left < dInfoPtr->worldWindow.right) && 
3161        (pdata->box.right > dInfoPtr->worldWindow.left) &&
3162        (pdata->box.top > dInfoPtr->worldWindow.bottom) &&
3163        (pdata->box.bottom < dInfoPtr->worldWindow.top) ) return TRUE; 
3164   return FALSE; 
3165 }
3166 
3167 static Boolean PolyOffsetProc ( PolyPDataPtr pdata, Int4 deltaX, 
3168                                    Int4 deltaY )
3169 {
3170   PntPtr   pPtr;
3171   Int2     vernum;
3172   Int2     i;
3173 
3174   pdata->box.left += deltaX;
3175   pdata->box.right += deltaX;
3176   pdata->box.top += deltaY;
3177   pdata->box.bottom += deltaY;
3178   vernum = pdata->vernum;
3179   pPtr = &(pdata->pnt);
3180   for ( i=0; i<vernum; i++ ){
3181     pPtr->x += deltaX;
3182     pPtr->y += deltaY;
3183     pPtr++;
3184   }
3185   return TRUE; 
3186 }
3187 
3188 static Boolean PolyGetLimitsProc ( PolyPDataPtr pdata, Int4 scaleX,
3189                                   Int4 scaleY, BoxPtr pLimits )
3190 {
3191   *pLimits = pdata->box;
3192   OutsetBox ( pLimits, scaleX<<2, scaleY<<2 );
3193   return TRUE;
3194 }
3195 
3196 static PrimDef polyPrimDef = {
3197   (PrimDrawProc) PolyDrawProc,
3198   (PrimHitTestProc) PolyHitTestProc,
3199   (PrimOffsetProc) PolyOffsetProc,
3200   (PrimCleanupProc) NULL,
3201   (PrimGetLimitsProc) PolyGetLimitsProc
3202 };
3203 
3204 /*****************************************************************************
3205 *
3206 *   AddPolygon (parent, vernum, points, fill, primID)
3207 *
3208 *****************************************************************************/
3209 
3210 PrimitivE AddPolygon (SegmenT parent, Int2 vernum, PntPtr points,
3211                      Boolean fill, Uint2 primID)
3212 {
3213   PrimitivE    poly = NULL;
3214   PolyPDataPtr dataPtr;
3215   PntPtr       pPtr;
3216   Int2         i;
3217 
3218   if ( (vernum > 1) && (vernum <= 32) && (points != NULL) ){
3219     dataPtr = (PolyPDataPtr)MemNew(sizeof(PolyPData) + vernum*sizeof(PntInfo));
3220     dataPtr->vernum = vernum;
3221     dataPtr->fill = (Int2)fill;
3222     LoadBox ( &(dataPtr->box), INT4_MAX, INT4_MIN, INT4_MIN, INT4_MAX );
3223     pPtr = &(dataPtr->pnt);
3224     for ( i=0; i<vernum; i++ ){
3225       pPtr->x = points[i].x;
3226       if ( dataPtr->box.left > pPtr->x ) dataPtr->box.left = pPtr->x;
3227       if ( dataPtr->box.right < pPtr->x ) dataPtr->box.right = pPtr->x;
3228       pPtr->y = points[i].y;
3229       if ( dataPtr->box.top < pPtr->y ) dataPtr->box.top = pPtr->y;
3230       if ( dataPtr->box.bottom > pPtr->y ) dataPtr->box.bottom = pPtr->y;
3231       pPtr++;
3232     }
3233     poly = AddPrimitive (&polyPrimDef, parent, primID, (VoidPtr)dataPtr,
3234                          (Int2)(sizeof(PolyPData) + vernum*sizeof(PntInfo)));
3235     MemFree ( dataPtr );
3236   }
3237   return poly;
3238 }
3239 
3240 /*****************************************************************************
3241 *
3242 *   DrawSegment (seg, drawinfo )
3243 *       Draws a segment, recursively tracking attributes
3244 *
3245 *****************************************************************************/
3246 
3247 extern void Nlm_DrawSegment (SegPPtr seg, Nlm_DrawInfoPtr drawinfoPtr )
3248 {
3249   BasePPtr  item;
3250   DrawInfo  drawinfo;
3251   RecT      r;
3252   Int1      highlight;
3253   Int1      highlightPrim;
3254 
3255   if (seg != NULL && drawinfoPtr != NULL) {
3256     drawinfo = *drawinfoPtr;
3257     drawinfo.primattrib = &blackAttPData;
3258     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
3259       if (seg->seg.maxscale == 0 || 
3260           seg->seg.maxscale >= 
3261           MAX (drawinfo.scale.scaleX, drawinfo.scale.scaleY)) {
3262         if ( (seg->seg.box.left <= drawinfo.scale.worldWindow.right) &&
3263              (seg->seg.box.right >= drawinfo.scale.worldWindow.left) &&
3264              (seg->seg.box.top >= drawinfo.scale.worldWindow.bottom) &&
3265              (seg->seg.box.bottom <= drawinfo.scale.worldWindow.top) ){
3266           if (seg->seg.visible) {
3267              SetPrimAttribute ( (Nlm_PrimDrawContext)&drawinfo, (Uint1)0xFF );
3268             if ( !drawinfo.checked ) {
3269               if ((seg->seg.box.left >= drawinfo.scale.worldWindow16.left) &&
3270                 (seg->seg.box.right <= drawinfo.scale.worldWindow16.right) &&
3271                 (seg->seg.box.top <= drawinfo.scale.worldWindow16.top) &&
3272                 (seg->seg.box.bottom >= drawinfo.scale.worldWindow16.bottom))
3273                 drawinfo.checked = TRUE;
3274             }
3275             if ( seg->seg.highlight != PLAIN_SEGMENT ) {
3276               highlight = seg->seg.highlight;
3277             } else {
3278               highlight = drawinfo.highlight;
3279             }
3280             switch ( highlight ) {
3281               case FRAME_CONTENTS:
3282                 highlightPrim = FRAME_PRIMITIVE;
3283                 break;
3284               case FILL_CONTENTS:  
3285                 highlightPrim = FILL_PRIMITIVE;
3286                 break;
3287               case OUTLINE_CONTENTS:
3288                 highlightPrim = OUTLINE_PRIMITIVE;
3289                 break;
3290               default:
3291                 highlightPrim = PLAIN_PRIMITIVE;
3292             }
3293             item = seg->seg.head;
3294             while (item != NULL) {
3295               switch (item->code) {
3296                 case GENERIC :
3297                   drawinfo.primattrib = &(((Nlm_GenPPtr)item)->att);
3298                   drawinfo.highlight = ((Nlm_GenPPtr)item)->highlight;
3299                   if ( drawinfo.highlight == PLAIN_PRIMITIVE ) {
3300                     drawinfo.highlight = highlightPrim;
3301                   }
3302                   DrawPrimitive (item, &drawinfo );
3303                   break;
3304                 case PICTURE :
3305                   Message (MSG_ERROR, "DrawSegment child is a picture");
3306                   break;
3307                 case SEGMENT :
3308                   drawinfo.highlight = highlight;
3309                   Nlm_DrawSegment ((SegPPtr)item, &drawinfo);
3310                   break;
3311                 default :
3312                   Message (MSG_ERROR, "DrawSegment child is unknown");
3313               }
3314               item = item->next;
3315             }
3316             if ( seg->seg.highlight != PLAIN_SEGMENT ) {
3317               drawinfo.primattrib = &blackAttPData;
3318                                   SetPrimAttribute ( (Nlm_PrimDrawContext)&drawinfo, 0xFF );
3319               MapWorldBoxToRect ( &r, &(seg->seg.box), &(drawinfo.scale) );
3320               switch (seg->seg.highlight) {
3321                 case FRAME_SEGMENT :
3322                   FrameRect (&r);
3323                   break;
3324                 case FILL_SEGMENT :
3325                   PaintRect (&r);
3326                   break;
3327                 case OUTLINE_SEGMENT :
3328                   InsetRect (&r, -4, -4);
3329                   FrameRect (&r);
3330                   InsetRect (&r, 1, 1);
3331                   FrameRect (&r);
3332                   InsetRect (&r, 2, 2);
3333                   drawinfo.primattrib = &whiteAttPData;
3334                                                 SetPrimAttribute ( (Nlm_PrimDrawContext)&drawinfo, 0xFF );
3335                   FrameRect (&r);
3336               }
3337             }
3338           }
3339         }
3340       }
3341       drawinfoPtr->curattrib = drawinfo.curattrib;
3342     } else {
3343       Message (MSG_ERROR, "DrawSegment argument not a segment or picture");
3344     }
3345   }
3346 }
3347 
3348 
3349 /*****************************************************************************
3350 *
3351 *    SENTINEL RECTANGLE
3352 *
3353 *****************************************************************************/
3354 
3355 typedef struct sntrecpdata {
3356   BoxInfo          box;
3357   SntOnDrawProc    callback;
3358   BigScalar        calldata;
3359   SntOnCleanupProc cleanup;
3360 } SntRecPData, PNTR SntRecPDataPtr;
3361 
3362 
3363 static void SntRecDrawProc(SntRecPDataPtr pdata, PrimDrawContext pdc)
3364 {
3365   BoxPtr primBoxPtr = &pdata->box;
3366   BoxPtr drawBoxPtr = &((DrawInfoPtr)pdc)->scale.worldWindow;
3367 
3368   if ( (primBoxPtr->left   > drawBoxPtr->right ) || 
3369        (primBoxPtr->right  < drawBoxPtr->left  ) || 
3370        (primBoxPtr->top    < drawBoxPtr->bottom) || 
3371        (primBoxPtr->bottom > drawBoxPtr->top   ) )
3372     return;
3373   
3374   if ( pdata->callback )
3375     (*pdata->callback)( pdata->calldata, pdc );
3376 }
3377 
3378 static Boolean SntRecHitTestProc(SntRecPDataPtr pdata, PrimHitContext phc)
3379 {
3380   BoxPtr primBoxPtr = &pdata->box;
3381   BoxPtr drawBoxPtr = &((ScalePtr)phc)->worldWindow;
3382 
3383   return (Boolean)((primBoxPtr->left   < drawBoxPtr->right )  &&
3384                    (primBoxPtr->right  > drawBoxPtr->left  )  &&
3385                    (primBoxPtr->top    > drawBoxPtr->bottom)  &&
3386                    (primBoxPtr->bottom < drawBoxPtr->top   ));
3387 }
3388 
3389 static void SntRecCleanupProc (SntRecPDataPtr pdata)
3390 {
3391   if ( pdata->cleanup )
3392     (*pdata->cleanup)( pdata->calldata );
3393 }
3394 
3395 static Boolean SntRecOffsetProc(SntRecPDataPtr pdata, Int4 deltaX, Int4 deltaY)
3396 {
3397   BoxPtr primBoxPtr = &pdata->box;
3398 
3399   primBoxPtr->left   += deltaX;
3400   primBoxPtr->right  += deltaX;
3401   primBoxPtr->top    += deltaY;
3402   primBoxPtr->bottom += deltaY;
3403 
3404   return TRUE; 
3405 }
3406 
3407 static Boolean SntRecGetLimitsProc(SntRecPDataPtr pdata,
3408                                    Int4 scaleX, Int4 scaleY, BoxPtr pLimits)
3409 {
3410   *pLimits = pdata->box;
3411   OutsetBox(pLimits, scaleX<<2, scaleY<<2);
3412   return TRUE; 
3413 }
3414 
3415 extern void ChangeSentinelRectangle (PrimitivE prim, Int4 left, Int4 top, Int4 right, Int4 bottom)
3416 
3417 {
3418   SntRecPDataPtr  pdata;
3419 
3420   if (prim == NULL) return;
3421   pdata = (SntRecPDataPtr) &(((GenPPtr) prim)->data);
3422   pdata->box.left = left;
3423   pdata->box.top = top;
3424   pdata->box.right = right;
3425   pdata->box.bottom = bottom;
3426 }
3427 
3428 static PrimDef sntrecPrimDef = {
3429   (PrimDrawProc)      SntRecDrawProc,
3430   (PrimHitTestProc)   SntRecHitTestProc,
3431   (PrimOffsetProc)    SntRecOffsetProc,
3432   (PrimCleanupProc)   SntRecCleanupProc,
3433   (PrimGetLimitsProc) SntRecGetLimitsProc
3434 };
3435 
3436 /*****************************************************************************
3437 *
3438 *   AddSntRectangle(parent, left,top,right,bottom, callback,calldata, primID)
3439 *
3440 *****************************************************************************/
3441 extern PrimitivE AddSntRectangle(SegmenT parent,
3442                                  Int4 left, Int4 top, Int4 right, Int4 bottom,
3443                                  SntOnDrawProc callback, BigScalar calldata,
3444                                  SntOnCleanupProc cleanup, Uint2 primID)
3445 {
3446   SntRecPData data;
3447   Int4 swap;
3448 
3449   if (left > right) {
3450     swap = left;
3451     left = right;
3452     right = swap;
3453   }
3454   if (bottom > top) {
3455     swap = bottom;
3456     bottom = top;
3457     top = swap;
3458   }
3459   data.box.left   = left;
3460   data.box.top    = top;
3461   data.box.right  = right;
3462   data.box.bottom = bottom;
3463   data.callback = callback;
3464   data.calldata = calldata;
3465   data.cleanup = cleanup;
3466   return AddPrimitive(&sntrecPrimDef, parent, primID, (VoidPtr)&data,
3467                       sizeof(SntRecPData));
3468 }
3469 
3470 

source navigation ]   [ diff markup ]   [ identifier search ]   [ freetext search ]   [ file search ]  

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.