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 
SetSmallFont(void)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 
SetMediumFont(void)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 
SetLargeFont(void)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 
Nlm_GetPrimDrawAttribute(PrimitivE prim,Uint1Ptr color,Int1Ptr plinestyle,Int1Ptr pshading,Int1Ptr ppenwidth,Int1Ptr pmode,Int1Ptr phighlight)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 *****************************************************************************/
Nlm_GetWorldWindow(Nlm_PrimDrawContext pdc)324 Nlm_BoxPtr Nlm_GetWorldWindow (Nlm_PrimDrawContext pdc) {
325   if ( pdc != NULL ){
326     return ( &(((DrawInfoPtr)pdc)->scale.worldWindow) );
327   }
328   return NULL;
329 }
330 
Nlm_GetScaleX(PrimDrawContext pdc)331 Int4 Nlm_GetScaleX (PrimDrawContext pdc){
332   if ( pdc != NULL ){
333     return ( ((DrawInfoPtr)pdc)->scale.scaleX );
334   }
335   return 0;
336 }
337 
Nlm_GetScaleY(Nlm_PrimDrawContext pdc)338 Int4 Nlm_GetScaleY (Nlm_PrimDrawContext pdc){
339   if ( pdc != NULL ){
340     return ( ((DrawInfoPtr)pdc)->scale.scaleY );
341   }
342   return 0;
343 }
344 
Nlm_GetOffsetX(PrimDrawContext pdc)345 Int4 Nlm_GetOffsetX (PrimDrawContext pdc){
346   if ( pdc != NULL ){
347     return ( ((DrawInfoPtr)pdc)->scale.offsetX );
348   }
349   return 0;
350 }
351 
Nlm_GetOffsetY(PrimDrawContext pdc)352 Int4 Nlm_GetOffsetY (PrimDrawContext pdc){
353   if ( pdc != NULL ){
354     return ( ((DrawInfoPtr)pdc)->scale.offsetY );
355   }
356   return 0;
357 }
358 
Nlm_isPrimInWindow(PrimDrawContext pdc)359 Boolean Nlm_isPrimInWindow (PrimDrawContext pdc){
360   if ( pdc != NULL ){
361     return ( ((DrawInfoPtr)pdc)->checked );
362   }
363   return FALSE;
364 }
365 
Nlm_GetPrimHligh(PrimDrawContext pdc)366 Int1 Nlm_GetPrimHligh (PrimDrawContext pdc){
367   if ( pdc != NULL ){
368     return ( ((DrawInfoPtr)pdc)->highlight );
369   }
370   return PLAIN_SEGMENT;
371 }
372 
Nlm_GetHitWindow(PrimHitContext phc)373 BoxPtr Nlm_GetHitWindow (PrimHitContext phc){
374   if ( phc != NULL ){
375     return ( &(((ScalePtr)phc)->worldWindow) );
376   }
377   return NULL;
378 }
379 
Nlm_SetPrimAttribute(PrimDrawContext pdc,Nlm_Uint1 flags)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 
Nlm_RestorePrimAttribute(PrimDrawContext pdc)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 *****************************************************************************/
Nlm_SetDefArrowSize(Int1 arrowSize)477 void Nlm_SetDefArrowSize ( Int1 arrowSize )
478 {
479   if ( arrowSize < 4 ) arrowSize = 4;
480   if ( arrowSize > 16 ) arrowSize = 16;
481   userArrowSize = arrowSize;
482 }
483 
MakeAlignRect(Int2 x,Int2 y,Int2 width,Int2 height,Int2 offset,Int2 align,RectPtr rPtr)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 
MakeAlignBox(Int4 x,Int4 y,Int4 width,Int4 height,Int4 offsetX,Int4 offsetY,Int2 align,BoxPtr boxPtr)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 
Nlm_DrawPrimitive(BasePPtr item,DrawInfoPtr drawinfo)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 
Nlm_PrimitiveIsCloseToPoint(BasePPtr item,ScalePtr scale)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 
Nlm_TryHighlightPrimitive(BasePPtr item,Int1 highlight)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 
Nlm_TryOffsetPrimitive(BasePPtr item,Int4 deltaX,Int4 deltaY)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 *****************************************************************************/
Nlm_TryGetPrimitiveLimits(Nlm_BasePPtr item,Nlm_Int4 scaleX,Nlm_Int4 scaleY,Nlm_BoxPtr pLimits)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 
Nlm_PrimitiveBox(Nlm_PrimitivE prim,Nlm_Int4 scaleX,Nlm_Int4 scaleY,Nlm_BoxPtr pBox)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 
Nlm_CleanupPrimitive(BasePPtr item)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 
FramHitTestProc(FramPDataPtr pdata,PrimHitContext phc)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 
FramOffsetProc(FramPDataPtr pdata,Int4 deltaX,Int4 deltaY)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 
FramGetLimitsProc(FramPDataPtr pdata,Int4 scaleX,Int4 scaleY,BoxPtr pLimits)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 
AddInvFrame(SegmenT parent,Int4 left,Int4 top,Int4 right,Int4 bottom,Uint2 primID)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 
RecDrawProc(RecPDataPtr pdata,PrimDrawContext pdc)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 
RecHitTestProc(RecPDataPtr pdata,PrimHitContext phc)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 
RecOffsetProc(RecPDataPtr pdata,Int4 deltaX,Int4 deltaY)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 
RecGetLimitsProc(RecPDataPtr pdata,Int4 scaleX,Int4 scaleY,BoxPtr pLimits)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 
AddRectangle(SegmenT parent,Int4 left,Int4 top,Int4 right,Int4 bottom,Int2 arrow,Boolean fill,Uint2 primID)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 
s_DoRoundRect(RectPtr r,Int2 oval_w,Int2 oval_h,Boolean fill,Uint4 flags)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 
RoRecDrawProc(RoRecPDataPtr pdata,PrimDrawContext pdc)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 
RoRecHitTestProc(RoRecPDataPtr pdata,PrimHitContext phc)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 
RoRecOffsetProc(RoRecPDataPtr pdata,Int4 deltaX,Int4 deltaY)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 
RoRecGetLimitsProc(RoRecPDataPtr pdata,Int4 scaleX,Int4 scaleY,BoxPtr pLimits)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 
AddRoundedRectangle(SegmenT parent,Int4 left,Int4 top,Int4 right,Int4 bottom,Int4 oval_w,Int4 oval_h,Boolean fill,Uint4 flags,Uint2 primID)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 
SegRecDrawProc(SegRecPDataPtr pdata,PrimDrawContext pdc)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 
SegRecHitTestProc(SegRecPDataPtr pdata,PrimHitContext phc)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 
SegRecOffsetProc(SegRecPDataPtr pdata,Int4 deltaX,Int4 deltaY)1494 static Boolean SegRecOffsetProc ( SegRecPDataPtr pdata, Int4 deltaX,
1495                                    Int4 deltaY )
1496 {
1497   return FALSE;
1498 }
1499 
SegRecGetLimitsProc(SegRecPDataPtr pdata,Int4 scaleX,Int4 scaleY,BoxPtr pLimits)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 
Nlm_AddSegRect(SegmenT parent,Boolean fill,Uint2 primID)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 
SilentSegRecHitTestProc(SegRecPDataPtr pdata,PrimHitContext phc)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 
Nlm_AddSilentSegRect(SegmenT parent,Boolean fill,Uint2 primID)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 
HLineDrawProc(HLinePDataPtr pdata,PrimDrawContext pdc)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 
HLineHitTestProc(HLinePDataPtr pdata,PrimHitContext phc)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 
HLineOffsetProc(HLinePDataPtr pdata,Int4 deltaX,Int4 deltaY)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 
HLineGetLimitsProc(HLinePDataPtr pdata,Int4 scaleX,Int4 scaleY,BoxPtr pLimits)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 
Nlm_AddHLine(SegmenT parent,Int4 pnt1X,Int4 pnt2X,Int4 pntY,Boolean arrow,Uint2 primID)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 
VLineDrawProc(VLinePDataPtr pdata,PrimDrawContext pdc)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 
VLineHitTestProc(VLinePDataPtr pdata,PrimHitContext phc)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 
VLineOffsetProc(VLinePDataPtr pdata,Int4 deltaX,Int4 deltaY)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 
VLineGetLimitsProc(VLinePDataPtr pdata,Int4 scaleX,Int4 scaleY,BoxPtr pLimits)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 
Nlm_AddVLine(SegmenT parent,Int4 pntX,Int4 pnt1Y,Int4 pnt2Y,Boolean arrow,Uint2 primID)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 
MSin(Int4 a)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 
LineDrawProc(LinePDataPtr pdata,PrimDrawContext pdc)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 
LineHitTestProc(LinePDataPtr pdata,PrimHitContext phc)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 
LineOffsetProc(LinePDataPtr pdata,Int4 deltaX,Int4 deltaY)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 
LineGetLimitsProc(LinePDataPtr pdata,Int4 scaleX,Int4 scaleY,BoxPtr pLimits)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 
Nlm_AddLine(SegmenT parent,Int4 pnt1X,Int4 pnt1Y,Int4 pnt2X,Int4 pnt2Y,Boolean arrow,Uint2 primID)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 
BmpDrawProc(BmpPDataPtr pdata,PrimDrawContext pdc)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 
BmpHitTestProc(BmpPDataPtr pdata,PrimHitContext phc)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 
BmpOffsetProc(BmpPDataPtr pdata,Int4 deltaX,Int4 deltaY)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 
BmpGetLimitsProc(BmpPDataPtr pdata,Int4 scaleX,Int4 scaleY,BoxPtr pLimits)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 
AddBitmap(SegmenT parent,Int4 pntX,Int4 pntY,Int2 width,Int2 height,Uint1Ptr bits,Int2 align,Uint2 primID)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 
AddSymbol(SegmenT parent,Int4 pntX,Int4 pntY,Int2 symbol,Boolean fill,Int2 align,Uint2 primID)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 
MarkDrawProc(MarkPDataPtr pdata,PrimDrawContext pdc)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 
MarkHitTestProc(MarkPDataPtr pdata,PrimHitContext phc)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 
MarkOffsetProc(MarkPDataPtr pdata,Int4 deltaX,Int4 deltaY)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 
MarkGetLimitsProc(MarkPDataPtr pdata,Int4 scaleX,Int4 scaleY,BoxPtr pLimits)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 
AddMarker(SegmenT parent,Int4 pntX,Int4 pntY,Int2 length,Int2 orient,Uint2 primID)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 
LblDrawProc(LblPDataPtr pdata,PrimDrawContext pdc)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 
LblHitTestProc(LblPDataPtr pdata,PrimHitContext phc)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 
LblCleanupProc(LblPDataPtr pdata)2648 static void LblCleanupProc (LblPDataPtr pdata)
2649 {
2650   DeleteFont (pdata->font);
2651 }
2652 
LblOffsetProc(LblPDataPtr pdata,Int4 deltaX,Int4 deltaY)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 
LblGetLimitsProc(LblPDataPtr pdata,Int4 scaleX,Int4 scaleY,BoxPtr pLimits)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 
Nlm_AddTextLabel(SegmenT parent,Int4 pntX,Int4 pntY,const Char * string,FonT font,Int2 offset,Int2 align,Uint2 primID)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 
AddLabel(SegmenT parent,Int4 pntX,Int4 pntY,const Char * string,Int2 size,Int2 offset,Int2 align,Uint2 primID)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 
OvalDrawProc(OvalPDataPtr pdata,PrimDrawContext pdc)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 
OvalHitTestProc(OvalPDataPtr pdata,PrimHitContext phc)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 
OvalOffsetProc(OvalPDataPtr pdata,Int4 deltaX,Int4 deltaY)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 
OvalGetLimitsProc(OvalPDataPtr pdata,Int4 scaleX,Int4 scaleY,BoxPtr pLimits)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 
AddOval(SegmenT parent,Int4 pntX,Int4 pntY,Int4 radiusX,Int4 radiusY,Boolean fill,Uint2 primID)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 
FrameArcProc(Int2 pNum,PoinT PNTR points)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 
ArcDrawProc(ArcPDataPtr pdata,PrimDrawContext pdc)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 
ArcHitTestProc(ArcPDataPtr pdata,PrimHitContext phc)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 
ArcOffsetProc(ArcPDataPtr pdata,Int4 deltaX,Int4 deltaY)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 
ArcGetLimitsProc(ArcPDataPtr pdata,Int4 scaleX,Int4 scaleY,BoxPtr pLimits)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 
AddArc(SegmenT parent,Int4 pntX,Int4 pntY,Int4 radiusX,Int4 radiusY,Int4 start,Int4 end,Boolean fill,Uint2 primID)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 
PolyDrawProc(PolyPDataPtr pdata,PrimDrawContext pdc)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 
PolyHitTestProc(PolyPDataPtr pdata,PrimHitContext phc)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 
PolyOffsetProc(PolyPDataPtr pdata,Int4 deltaX,Int4 deltaY)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 
PolyGetLimitsProc(PolyPDataPtr pdata,Int4 scaleX,Int4 scaleY,BoxPtr pLimits)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 
AddPolygon(SegmenT parent,Int2 vernum,PntPtr points,Boolean fill,Uint2 primID)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 
Nlm_DrawSegment(SegPPtr seg,Nlm_DrawInfoPtr drawinfoPtr)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 
SntRecDrawProc(SntRecPDataPtr pdata,PrimDrawContext pdc)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 
SntRecHitTestProc(SntRecPDataPtr pdata,PrimHitContext phc)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 
SntRecCleanupProc(SntRecPDataPtr pdata)3389 static void SntRecCleanupProc (SntRecPDataPtr pdata)
3390 {
3391   if ( pdata->cleanup )
3392     (*pdata->cleanup)( pdata->calldata );
3393 }
3394 
SntRecOffsetProc(SntRecPDataPtr pdata,Int4 deltaX,Int4 deltaY)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 
SntRecGetLimitsProc(SntRecPDataPtr pdata,Int4 scaleX,Int4 scaleY,BoxPtr pLimits)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 
ChangeSentinelRectangle(PrimitivE prim,Int4 left,Int4 top,Int4 right,Int4 bottom)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 *****************************************************************************/
AddSntRectangle(SegmenT parent,Int4 left,Int4 top,Int4 right,Int4 bottom,SntOnDrawProc callback,BigScalar calldata,SntOnCleanupProc cleanup,Uint2 primID)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