1 /*   picture.c
2 * ===========================================================================
3 *
4 *                            PUBLIC DOMAIN NOTICE
5 *            National Center for Biotechnology Information (NCBI)
6 *
7 *  This software/database is a "United States Government Work" under the
8 *  terms of the United States Copyright Act.  It was written as part of
9 *  the author's official duties as a United States Government employee and
10 *  thus cannot be copyrighted.  This software/database is freely available
11 *  to the public for use. The National Library of Medicine and the U.S.
12 *  Government do not place any restriction on its use or reproduction.
13 *  We would, however, appreciate having the NCBI and the author cited in
14 *  any work or product based on this material
15 *
16 *  Although all reasonable efforts have been taken to ensure the accuracy
17 *  and reliability of the software and data, the NLM and the U.S.
18 *  Government do not and cannot warrant the performance or results that
19 *  may be obtained by using this software or data. The NLM and the U.S.
20 *  Government disclaim all warranties, express or implied, including
21 *  warranties of performance, merchantability or fitness for any particular
22 *  purpose.
23 *
24 * ===========================================================================
25 *
26 * File Name:  picture.c
27 *
28 * Author:  Jonathan Kans, Alex Smirnov, Jill Shermer
29 *
30 * Version Creation Date:   10/23/92
31 *
32 * $Revision: 6.7 $
33 *
34 * File Description:
35 *
36 * Modifications:
37 * --------------------------------------------------------------------------
38 * Date     Name        Description of modification
39 * -------  ----------  -----------------------------------------------------
40 *
41 *
42 * $Log: picture.c,v $
43 * Revision 6.7  2004/02/17 19:22:54  johnson
44 * make segment ID consistly unsigned
45 *
46 * Revision 6.6  2002/08/07 18:13:42  kans
47 * G/SetPrimitiveIDs, itemID is Uint4
48 *
49 * Revision 6.5  2002/03/07 15:53:45  kans
50 * added SetSegmentVisibleFlag to set/clear the visible flag before attaching to a viewer
51 *
52 * Revision 6.4  1999/10/13 17:45:46  kans
53 * added entityID, itemID, and itemtype to primitive internal structure, added Get and Set functions
54 *
55 * Revision 6.3  1999/10/04 17:16:33  kans
56 * include ncbidraw.h instead of vibrant.h, a couple Nlm_ prefixes
57 *
58 * Revision 6.2  1998/06/30 00:32:02  vakatov
59 * Nlm_AddAttribute():  pass "color" as constant
60 *
61 * Revision 6.1  1997/11/26 21:30:04  vakatov
62 * Fixed errors and warnings issued by C and C++ (GNU and Sun) compilers
63 *
64 * Revision 6.0  1997/08/25 18:56:22  madden
65 * Revision changed to 6.0
66 *
67 * Revision 5.2  1997/07/02 19:40:32  vakatov
68 * Fixed typo:  #DBUG --> #_DEBUG in DeletePrim()
69 *
70 * Revision 5.1  1997/07/02 18:35:51  vakatov
71 * Nlm_DeletePrim() redesigned/rewritten to guarantee prim. list consistency
72 *
73 * Revision 5.0  1996/05/28 13:45:08  ostell
74 * Set to revision 5.0
75 *
76  * Revision 4.4  1996/04/01  16:07:10  hogue
77  * Cast MemCpy to (void *)
78  *
79  * Revision 4.3  1996/03/18  20:42:05  vakatov
80  * ChangeAddPrimOrder(...) function allows one to specify the order of adding
81  * primitives(or segments) to a picture
82  *
83  * Revision 4.2  1995/12/14  17:29:30  kans
84  * moved SearchSegment from viewer.c to picture.c, made extern
85  *
86  * Revision 4.1  1995/11/20  20:36:29  kans
87  * line segments of circle now drawn with visible penwidth on Mac (AS)
88  *
89  * Revision 4.0  1995/07/26  13:51:04  ostell
90  * force revision to 4.0
91  *
92  * Revision 1.30  1995/05/17  15:15:14  kans
93  * added Log line
94  *
95 *
96 * ==========================================================================
97 */
98 
99 #ifndef _NCBIDRAW_
100 #include <ncbidraw.h>
101 #endif
102 
103 #ifndef _PICTURE_
104 #include <picture.h>
105 #endif
106 
107 #ifndef _PICTUREP_
108 #include <picturep.h>
109 #endif
110 
111 #ifndef _MAPPINGP_
112 #include <mappingp.h>
113 #endif
114 
115 #ifndef _DRAWINGP_
116 #include <drawingp.h>
117 #endif
118 
119 /*****************************************************************************
120 *
121 *   EXTERNAL VARIABLES
122 *
123 *****************************************************************************/
124 
125 Uint1 BLACK_COLOR [3] = {0, 0, 0};
126 Uint1 WHITE_COLOR [3] = {255, 255, 255};
127 Uint1 RED_COLOR  [3] = {255, 0, 0};
128 Uint1 GREEN_COLOR [3] = {0, 255, 0};
129 Uint1 BLUE_COLOR [3] = {0, 0, 255};
130 Uint1 YELLOW_COLOR [3] = {255, 255, 0};
131 Uint1 CYAN_COLOR [3] = {0, 255, 255};
132 Uint1 MAGENTA_COLOR [3] = {255, 0, 255};
133 
134 /*****************************************************************************
135 *
136 *   STATIC VARIABLES
137 *
138 *****************************************************************************/
139 
140 static AttPData defAttPData =
141 { {0,0,0}, SOLID_LINE, SOLID_SHADING, STD_PEN_WIDTH, COPY_MODE };
142 
143 /*****************************************************************************
144 *
145 *   CreatePicture (void)
146 *       Creates a Picture Record (same as Segment Record except for base.code)
147 *
148 *****************************************************************************/
149 
Nlm_CreatePicture(void)150 SegmenT Nlm_CreatePicture (void)
151 
152 {
153   PicPPtr  pic;
154 
155   pic = (PicPPtr) MemNew (sizeof (PicPRec));
156   if (pic != NULL) {
157     pic->base.next = NULL;
158     pic->base.prev = NULL;
159     pic->base.code = PICTURE;
160     pic->seg.box.left = INT4_MAX;
161     pic->seg.box.top = INT4_MIN;
162     pic->seg.box.right = INT4_MIN;
163     pic->seg.box.bottom = INT4_MAX;
164     pic->seg.head = NULL;
165     pic->seg.tail = NULL;
166     pic->seg.parent = NULL;
167     pic->seg.visible = TRUE;
168     pic->seg.maxscale = 0;
169     pic->seg.penwidth = STD_PEN_WIDTH;
170     pic->seg.highlight = PLAIN_SEGMENT;
171     pic->seg.segID = 0;
172     pic->attLast = defAttPData;
173   }
174   return (SegmenT) pic;
175 }
176 
177 /*****************************************************************************
178 *
179 *   DeletePicture (picture)
180 *       Removes any previously existing segments, then frees picture node
181 *
182 *****************************************************************************/
183 
Nlm_DeletePicture(SegmenT picture)184 SegmenT Nlm_DeletePicture (SegmenT picture)
185 
186 {
187   PicPPtr  pic;
188 
189   pic = NULL;
190   if (picture != NULL) {
191     pic = (PicPPtr) picture;
192     if (pic->base.code == PICTURE) {
193       ResetSegment ((SegmenT) pic);
194       pic = (PicPPtr) MemFree(pic);
195     } else {
196       Message (MSG_ERROR, "DeletePicture argument not a picture");
197     }
198   }
199   return (SegmenT) pic;
200 }
201 
202 /*****************************************************************************
203 *
204 *   DeleteSegment (segment)
205 *       Removes any previously existing segments, then frees segment node
206 *
207 *****************************************************************************/
208 
Nlm_DeleteSegment(SegmenT segment)209 SegmenT Nlm_DeleteSegment (SegmenT segment)
210 
211 {
212   SegPPtr  seg;
213 
214   seg = NULL;
215   if (segment != NULL) {
216     seg = (SegPPtr) segment;
217     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
218       ResetSegment ((SegmenT) seg);
219       seg = (SegPPtr) MemFree(seg);
220     } else {
221       Message (MSG_ERROR, "DeleteSegment argument not a segment or picture");
222     }
223   }
224   return (SegmenT) seg;
225 }
226 
227 /*****************************************************************************
228 *
229 *   CreatePrimitive (parent, code, size)
230 *       Common routine creates any primitive type, then adds it to the
231 *       parent segment's child list, updating segment pointers
232 *
233 *****************************************************************************/
234 
235 static Nlm_enumPrimAddOrder actualAddPrimOrder = ADD_TO_TAIL;
236 static Nlm_enumPrimAddOrder tempAddPrimOrder   = WHAT_ORDER;
237 
Nlm_ChangeAddPrimOrder(Nlm_enumPrimAddOrder prim_add_order)238 Nlm_enumPrimAddOrder Nlm_ChangeAddPrimOrder(Nlm_enumPrimAddOrder prim_add_order)
239 {
240   Nlm_enumPrimAddOrder prev_order = (tempAddPrimOrder == WHAT_ORDER) ?
241     actualAddPrimOrder : tempAddPrimOrder;
242 
243   switch ( prim_add_order )
244     {
245     case WHAT_ORDER:
246       break;
247     case ADD_TO_TAIL:
248     case ADD_TO_HEAD:
249       actualAddPrimOrder = prim_add_order;
250       tempAddPrimOrder   = WHAT_ORDER;
251       break;
252     case ADD_TO_TAIL_ONCE:
253     case ADD_TO_HEAD_ONCE:
254       tempAddPrimOrder = prim_add_order;
255       break;
256     }
257 
258   return prev_order;
259 }
260 
CreatePrimitive(SegmenT parent,Int1 code,size_t size)261 static BasePPtr CreatePrimitive (SegmenT parent, Int1 code, size_t size)
262 
263 {
264   BasePPtr  prim;
265   SegPPtr   prnt;
266 
267   prim = NULL;
268   if (parent != NULL) {
269     prnt = (SegPPtr) parent;
270     if (prnt->base.code == SEGMENT || prnt->base.code == PICTURE) {
271       prim = (BasePPtr) MemNew (size);
272       if (prim != NULL) {
273 	Nlm_enumPrimAddOrder order = Nlm_ChangeAddPrimOrder( WHAT_ORDER );
274 	tempAddPrimOrder = WHAT_ORDER;
275 
276 	prim->prev = NULL;
277         prim->next = NULL;
278         prim->code = code;
279         if (prnt->seg.head != NULL && prnt->seg.tail != NULL) {
280 	  if (order == ADD_TO_HEAD  ||  order == ADD_TO_HEAD_ONCE)
281 	    {
282 	      prnt->seg.head->prev = prim;
283 	      prim->next = prnt->seg.head;
284 	      prnt->seg.head = prim;
285 	    }
286 	  else
287 	    {
288 	      prnt->seg.tail->next = prim;
289 	      prim->prev = prnt->seg.tail;
290 	      prnt->seg.tail = prim;
291 	    }
292         } else if (prnt->seg.head == NULL && prnt->seg.tail == NULL) {
293           prnt->seg.head = prim;
294           prnt->seg.tail = prim;
295         } else {
296           Message (MSG_ERROR, "CreatePrimitive list integrity problem");
297         }
298       }
299     } else {
300       Message (MSG_ERROR, "CreatePrimitive parent not a segment or picture");
301     }
302   }
303   return prim;
304 }
305 
306 /*****************************************************************************
307 *
308 *   LinkSegment (parent, child)
309 *       Links existing segment into parent
310 *
311 *****************************************************************************/
312 
Nlm_LinkSegment(SegmenT parent,SegmenT child)313 void Nlm_LinkSegment (SegmenT parent, SegmenT child)
314 
315 {
316   BasePPtr  prev;
317   BasePPtr  prim;
318   SegPPtr   prnt;
319   SegPPtr   seg;
320 
321    if (parent != NULL && child != NULL) {
322     prnt = (SegPPtr) parent;
323     if (prnt->base.code == SEGMENT || prnt->base.code == PICTURE) {
324       prim = (BasePPtr) child;
325       seg = (SegPPtr) prim;
326       if (prim->code == SEGMENT) {
327         if (seg->seg.parent == NULL) {
328           seg->seg.parent = (BasePPtr) parent;
329           if (prnt->seg.head != NULL && prnt->seg.tail != NULL) {
330             prev = prnt->seg.tail;
331             prev->next = prim;
332             prim->prev = prev;
333             prnt->seg.tail = prim;
334           } else if (prnt->seg.head == NULL && prnt->seg.tail == NULL) {
335             prnt->seg.head = prim;
336             prnt->seg.tail = prim;
337             prim->prev = NULL;
338           } else {
339             Message (MSG_ERROR, "LinkSegment list integrity problem");
340           }
341         } else {
342           Message (MSG_ERROR, "LinkSegment child already linked");
343         }
344       } else {
345         Message (MSG_ERROR, "LinkSegment child not a segment");
346       }
347     } else {
348       Message (MSG_ERROR, "LinkSegment parent not a segment or picture");
349     }
350   }
351 }
352 
353 /*****************************************************************************
354 *
355 *   UnlinkSegment (child)
356 *       Unlinks existing segment from parent
357 *
358 *****************************************************************************/
359 
Nlm_UnlinkSegment(SegmenT child)360 void Nlm_UnlinkSegment (SegmenT child)
361 
362 {
363   BasePPtr  item;
364   BasePPtr  last;
365   BasePPtr  next;
366   BasePPtr  prim;
367   SegPPtr   prnt;
368   SegPPtr   seg;
369 
370   if (child != NULL) {
371     prim = (BasePPtr) child;
372     if (prim->code == SEGMENT) {
373       seg = (SegPPtr) prim;
374       prnt = (SegPPtr) seg->seg.parent;
375       if (prnt != NULL) {
376         last = NULL;
377         item = prnt->seg.head;
378         while (item != NULL) {
379           if (item == prim) {
380             seg->seg.parent = NULL;
381             next = item->next;
382             if (last != NULL) {
383               last->next = next;
384             }
385             if ( next != NULL ) {
386               next->prev = last;
387             }
388             item->next = NULL;
389             item = NULL;
390             if (prnt->seg.head == prim) {
391               prnt->seg.head = next;
392             }
393             if (prnt->seg.tail == prim) {
394               prnt->seg.tail = last;
395             }
396           } else {
397             last = item;
398             item = item->next;
399           }
400         }
401       }
402     } else {
403       Message (MSG_ERROR, "UnlinkSegment child not a segment");
404     }
405   }
406 }
407 
408 /*****************************************************************************
409 *
410 *   CreateSegment (parent, segID, maxScale)
411 *       Creates a segment primitive that can have its own list of children
412 *
413 *****************************************************************************/
414 
Nlm_CreateSegment(SegmenT parent,Uint2 segID,Int4 maxScale)415 SegmenT Nlm_CreateSegment (SegmenT parent, Uint2 segID, Int4 maxScale)
416 {
417   BasePPtr  prim;
418   SegPPtr   prnt;
419   SegPPtr   seg;
420 
421   if (parent != NULL) {
422     seg = (SegPPtr) CreatePrimitive (parent, SEGMENT, sizeof (SegPRec));
423   } else {
424     prim = (BasePPtr) MemNew (sizeof (SegPRec));
425     if (prim != NULL) {
426       prim->next = NULL;
427       prim->prev = NULL;
428       prim->code = SEGMENT;
429     }
430     seg = (SegPPtr) prim;
431   }
432   if (seg != NULL) {
433     seg->seg.box.left = INT4_MAX;
434     seg->seg.box.top = INT4_MIN;
435     seg->seg.box.right = INT4_MIN;
436     seg->seg.box.bottom = INT4_MAX;
437     seg->seg.head = NULL;
438     seg->seg.tail = NULL;
439     seg->seg.parent = (BasePPtr) parent;
440     seg->seg.visible = TRUE;
441     seg->seg.maxscale = maxScale;
442     prnt = (SegPPtr) parent;
443     seg->seg.penwidth = STD_PEN_WIDTH;
444     seg->attLast = defAttPData;
445     if (prnt != NULL) {
446       if (prnt->base.code == SEGMENT || prnt->base.code == PICTURE) {
447         seg->seg.penwidth = prnt->seg.penwidth;
448         seg->attLast = prnt->attLast;
449       }
450     }
451     seg->seg.highlight = PLAIN_SEGMENT;
452     seg->seg.segID = segID;
453   }
454   return (SegmenT) seg;
455 }
456 
457 /*****************************************************************************
458 *
459 *   ResetSegment (segment)
460 *       Cleaves and deletes the segment's child list (recursively),
461 *       freeing item specific data, and leaving the segment itself
462 *       intact for repopulation
463 *
464 *****************************************************************************/
465 
Nlm_ResetSegment(SegmenT segment)466 SegmenT Nlm_ResetSegment (SegmenT segment)
467 
468 {
469   BasePPtr  item;
470   BasePPtr  next;
471   SegPPtr   seg;
472 
473   seg = NULL;
474   if (segment != NULL) {
475     seg = (SegPPtr) segment;
476     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
477       item = seg->seg.head;
478       while (item != NULL) {
479         next = item->next;
480         switch (item->code) {
481           case PICTURE :
482           case SEGMENT :
483             ResetSegment ((SegmenT) item);
484             break;
485           default :
486             CleanupPrimitive (item);
487             break;
488         }
489         MemFree (item);
490         item = next;
491       }
492       seg->seg.box.left = INT4_MAX;
493       seg->seg.box.top = INT4_MIN;
494       seg->seg.box.right = INT4_MIN;
495       seg->seg.box.bottom = INT4_MAX;
496       seg->seg.head = NULL;
497       seg->seg.tail = NULL;
498       seg->seg.penwidth = STD_PEN_WIDTH;
499       seg->seg.highlight = PLAIN_SEGMENT;
500       seg->attLast = defAttPData;
501     } else {
502       Message (MSG_ERROR, "ResetSegment argument not a segment or picture");
503     }
504   }
505   return (SegmenT) seg;
506 }
507 
508 /*****************************************************************************
509 *
510 *   ParentSegment (segment)
511 *       Returns the parent of a segment
512 *
513 *****************************************************************************/
514 
Nlm_ParentSegment(SegmenT segment)515 SegmenT Nlm_ParentSegment (SegmenT segment)
516 
517 {
518   SegmenT  parent;
519   SegPPtr  seg;
520 
521   parent = NULL;
522   if (segment != NULL) {
523     seg = (SegPPtr) segment;
524     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
525       parent = (SegmenT) seg->seg.parent;
526       if (parent != NULL) {
527         seg = (SegPPtr) parent;
528         if (seg->base.code != SEGMENT && seg->base.code != PICTURE) {
529           Message (MSG_ERROR, "ParentSegment parent not a segment or picture");
530         }
531       }
532     } else {
533       Message (MSG_ERROR, "ParentSegment argument not a segment or picture");
534     }
535   }
536   return parent;
537 }
538 
539 /*****************************************************************************
540 *
541 *   SegmentID (segment)
542 *       Returns the segment ID of a segment
543 *
544 *****************************************************************************/
545 
Nlm_SegmentID(SegmenT segment)546 Uint2 Nlm_SegmentID (SegmenT segment)
547 
548 {
549   SegPPtr  seg;
550   Uint2     segID;
551 
552   segID = 0;
553   if (segment != NULL) {
554     seg = (SegPPtr) segment;
555     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
556       segID = seg->seg.segID;
557     } else {
558       Message (MSG_ERROR, "SegmentID argument not a segment or picture");
559     }
560   }
561   return segID;
562 }
563 
564 /*****************************************************************************
565 *
566 *   SegmentVisible (segment)
567 *       Returns the visibility of a segment
568 *
569 *****************************************************************************/
570 
Nlm_SegmentVisible(SegmenT segment)571 Boolean Nlm_SegmentVisible (SegmenT segment)
572 
573 {
574   SegPPtr  seg;
575   Boolean  vis;
576 
577   vis = FALSE;
578   if (segment != NULL) {
579     seg = (SegPPtr) segment;
580     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
581       vis = seg->seg.visible;
582     } else {
583       Message (MSG_ERROR, "SegmentVisible argument not a segment or picture");
584     }
585   }
586   return vis;
587 }
588 
589 /*****************************************************************************
590 *
591 *   Nlm_SetSegmentVisibleFlag (segment, visible)
592 *       Sets the visibility of a segment
593 *
594 *****************************************************************************/
595 
Nlm_SetSegmentVisibleFlag(SegmenT segment,Boolean visible)596 void Nlm_SetSegmentVisibleFlag (SegmenT segment, Boolean visible)
597 
598 {
599   SegPPtr  seg;
600 
601   if (segment != NULL) {
602     seg = (SegPPtr) segment;
603     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
604       seg->seg.visible = visible;
605     } else {
606       Message (MSG_ERROR, "Nlm_SetSegmentVisibleFlag argument not a segment or picture");
607     }
608   }
609 }
610 
611 /*****************************************************************************
612 *
613 *   SegmentStyle (segment)
614 *       Returns the highlight style of a segment
615 *
616 *****************************************************************************/
617 
Nlm_SegmentStyle(SegmenT segment)618 Int1 Nlm_SegmentStyle (SegmenT segment)
619 
620 {
621   Int1     highlight;
622   SegPPtr  seg;
623 
624   highlight = PLAIN_SEGMENT;
625   if (segment != NULL) {
626     seg = (SegPPtr) segment;
627     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
628       highlight = seg->seg.highlight;
629     } else {
630       Message (MSG_ERROR, "SegmentStyle argument not a segment or picture");
631     }
632   }
633   return highlight;
634 }
635 
636 /*****************************************************************************
637 *
638 *   SegmentBox (segment, box)
639 *       Returns the bounding box of a segment
640 *
641 *****************************************************************************/
642 
Nlm_SegmentBox(SegmenT segment,BoxPtr box)643 void Nlm_SegmentBox (SegmenT segment, BoxPtr box)
644 
645 {
646   SegPPtr  seg;
647 
648   if (segment != NULL) {
649     seg = (SegPPtr) segment;
650     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
651       if (box != NULL) {
652         *box = seg->seg.box;
653       }
654     } else {
655       Message (MSG_ERROR, "SegmentBox argument not a segment or picture");
656     }
657   }
658 }
659 
660 /*****************************************************************************
661 *
662 *   GetPrimitive (segment, primCt)
663 *       Gets a primitive by index within a segment
664 *
665 *****************************************************************************/
666 
Nlm_GetPrimitive(SegmenT segment,Uint2 primCt)667 PrimitivE Nlm_GetPrimitive (SegmenT segment, Uint2 primCt)
668 
669 {
670   BasePPtr  item;
671   SegPPtr   seg;
672 
673   item = NULL;
674   if (segment != NULL && primCt > 0) {
675     seg = (SegPPtr) segment;
676     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
677       item = seg->seg.head;
678       while (item != NULL && primCt > 1) {
679         item = item->next;
680         primCt--;
681       }
682     } else {
683       Message (MSG_ERROR, "FindPrimitive argument not a segment or picture");
684     }
685   }
686   return (PrimitivE) item;
687 }
688 
Nlm_SetPrimitiveIDs(PrimitivE prim,Uint2 entityID,Uint4 itemID,Uint2 itemtype,Uint2 primID)689 void Nlm_SetPrimitiveIDs (PrimitivE prim, Uint2 entityID, Uint4 itemID,
690                           Uint2 itemtype, Uint2 primID)
691 
692 {
693   GenPPtr   gpp;
694   BasePPtr  item;
695 
696   item = (BasePPtr) prim;
697   if (item != NULL && item->code == GENERIC) {
698     gpp = (GenPPtr) item;
699     gpp->entityID = entityID;
700     gpp->itemID = itemID;
701     gpp->itemtype = itemtype;
702     gpp->primID = primID;
703   }
704 }
705 
Nlm_GetPrimitiveIDs(PrimitivE prim,Uint2Ptr entityIDPtr,Uint4Ptr itemIDPtr,Uint2Ptr itemtypePtr,Uint2Ptr primIDPtr)706 void Nlm_GetPrimitiveIDs (PrimitivE prim, Uint2Ptr entityIDPtr, Uint4Ptr itemIDPtr,
707                           Uint2Ptr itemtypePtr, Uint2Ptr primIDPtr)
708 
709 {
710   GenPPtr   gpp;
711   BasePPtr  item;
712   item = (BasePPtr) prim;
713   if (item != NULL && item->code == GENERIC) {
714     gpp = (GenPPtr) item;
715     if (entityIDPtr != NULL) {
716       *entityIDPtr = gpp->entityID;
717     }
718     if (itemIDPtr != NULL) {
719       *itemIDPtr = gpp->itemID;
720     }
721     if (itemtypePtr != NULL) {
722       *itemtypePtr = gpp->itemtype;
723     }
724     if (primIDPtr != NULL) {
725       *primIDPtr = gpp->primID;
726     }
727   }
728 }
729 
730 /*****************************************************************************
731 *
732 *   AdjustParent (parent, left, top, right, bottom)
733 *       Recalculates segment boundaries, propagates up parent list
734 *
735 *****************************************************************************/
736 
AdjustParent(SegmenT parent,Int4 left,Int4 top,Int4 right,Int4 bottom)737 static void AdjustParent (SegmenT parent, Int4 left, Int4 top, Int4 right, Int4 bottom)
738 
739 {
740   SegPPtr  seg;
741 
742   if (parent != NULL) {
743     seg = (SegPPtr) parent;
744     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
745       if (seg->seg.box.left > left) {
746         seg->seg.box.left = left;
747       }
748       if (seg->seg.box.top < top) {
749         seg->seg.box.top = top;
750       }
751       if (seg->seg.box.right < right) {
752         seg->seg.box.right = right;
753       }
754       if (seg->seg.box.bottom > bottom) {
755         seg->seg.box.bottom = bottom;
756       }
757       if ( seg->base.code == SEGMENT ) {
758         AdjustParent ((SegmenT) seg->seg.parent, left, top, right, bottom);
759       }
760     } else {
761       Message (MSG_ERROR, "AdjustParent argument not a segment or picture");
762     }
763   }
764 }
765 
766 /*****************************************************************************
767 *
768 *   AddAttribute (parent, flags, color, linestyle, shading, penwidth, mode)
769 *       Changes current attribute settings (applied only to lower levels)
770 *
771 *****************************************************************************/
772 
Nlm_AddAttribute(SegmenT parent,Uint1 flags,const Uint1 * color,Int1 linestyle,Int1 shading,Int1 penwidth,Int1 mode)773 void Nlm_AddAttribute(SegmenT parent, Uint1 flags, const Uint1* color,
774                       Int1 linestyle, Int1 shading, Int1 penwidth, Int1 mode)
775 
776 {
777   AttPPtr  att;
778   SegPPtr  prnt;
779 
780   prnt = (SegPPtr) parent;
781   if (prnt != NULL) {
782     prnt->seg.penwidth = penwidth;
783     att = &(prnt->attLast);
784     if (linestyle >= NO_LINE_STYLE && linestyle <= DASHED_LINE) {
785       if (shading >= NO_SHADING && shading <= THICK_NWSE_SHADING) {
786         if ( flags & COLOR_ATT ) {
787           if (color != NULL) {
788             att->color [0] = color [0];
789             att->color [1] = color [1];
790             att->color [2] = color [2];
791           } else {
792             att->color [0] = BLACK_COLOR [0];
793             att->color [1] = BLACK_COLOR [1];
794             att->color [2] = BLACK_COLOR [2];
795           }
796         }
797         if ( flags & STYLE_ATT ) att->linestyle = linestyle;
798         if ( flags & SHADING_ATT ) att->shading = shading;
799         if ( flags & WIDTH_ATT ) {
800           att->penwidth = MIN (penwidth, PEN_MAX);
801           if ( att->penwidth <= 0 ) att->penwidth = 1;
802         }
803         if ( flags & MODE_ATT ) att->mode = mode;
804       } else {
805         Message (MSG_ERROR, "AddAttribute shading out of range");
806       }
807     } else {
808       Message (MSG_ERROR, "AddAttribute line style out of range");
809     }
810   } else {
811     Message (MSG_ERROR, "AddAttribute parent is NULL");
812   }
813 }
814 
815 /*****************************************************************************
816 *
817 *   AddPrimitive (pdp, parent, primID, pextra, extrasize )
818 *
819 *****************************************************************************/
820 
Nlm_AddPrimitive(PrimDefPtr pdp,SegmenT parent,Uint2 primID,VoidPtr pextra,Int2 extrasize)821 PrimitivE Nlm_AddPrimitive (PrimDefPtr pdp, SegmenT parent, Uint2 primID,
822                         VoidPtr pextra, Int2 extrasize )
823 {
824   GenPPtr  gpp = NULL;
825   BoxInfo  pLimits;
826 
827   if (pdp == NULL) {
828     Message (MSG_ERROR, "Primitive definition ptr is NULL");
829   } else {
830     gpp = (GenPPtr) CreatePrimitive (parent, GENERIC,
831                     sizeof (GenPRec) + MAX(0,extrasize-sizeof(double)));
832     if (gpp != NULL) {
833       gpp->primID = primID;
834       gpp->pdp = pdp;
835       if (pextra != NULL && extrasize > 0 ) {
836         MemCpy ((void *)&gpp->data, (void *)pextra, (size_t)extrasize);
837       }
838       gpp->highlight = PLAIN_SEGMENT;
839       gpp->att = ((SegPPtr)parent)->attLast;
840       TryGetPrimitiveLimits ((BasePPtr)gpp, 1, 1, &pLimits );
841       AdjustParent (parent,
842                     pLimits.left, pLimits.top,
843                     pLimits.right, pLimits.bottom);
844     }
845   }
846   return (PrimitivE) gpp;
847 }
848 
RecalSegment(SegPPtr seg,Int4 scaleX,Int4 scaleY)849 static void RecalSegment (SegPPtr seg, Int4 scaleX, Int4 scaleY )
850 
851 {
852   BasePPtr item;
853   BoxInfo  pLimits;
854 
855   if (seg != NULL) {
856     seg->seg.box.left = INT4_MAX;
857     seg->seg.box.top = INT4_MIN;
858     seg->seg.box.right = INT4_MIN;
859     seg->seg.box.bottom = INT4_MAX;
860     item = seg->seg.head;
861     while (item != NULL) {
862       switch (item->code) {
863         case PICTURE :
864         case SEGMENT :
865           RecalSegment ((SegPPtr)item, scaleX, scaleY);
866           break;
867         case GENERIC :
868           TryGetPrimitiveLimits ( item, scaleX, scaleY, &pLimits );
869           AdjustParent ((SegmenT)seg,
870                         pLimits.left, pLimits.top,
871                         pLimits.right, pLimits.bottom);
872       }
873       item = item->next;
874     }
875   }
876 }
877 
878 /*****************************************************************************
879 *
880 *   RecalculateSegment (segment, scaleX, scaleY)
881 *       Explores the segment's child list (recursively), recalculating segment
882 *       boundaries and scaled margins, propagating back up parent list
883 *
884 *****************************************************************************/
885 
Nlm_RecalculateSegment(SegmenT segment,Int4 scaleX,Int4 scaleY)886 void Nlm_RecalculateSegment (SegmenT segment, Int4 scaleX, Int4 scaleY )
887 
888 {
889   SegPPtr     seg;
890 
891   if (segment != NULL) {
892     seg = (SegPPtr) segment;
893     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
894       RecalSegment (seg, scaleX, scaleY);
895     } else {
896       Message (MSG_ERROR, "RecalculateSegment argument not a segment or picture");
897     }
898   }
899 }
900 
901 /*****************************************************************************
902 *
903 *   OffsetSegment (segment, deltaX, deltaY)
904 *
905 *****************************************************************************/
906 
Nlm_OffsetSegment(SegmenT segment,Int4 deltaX,Int4 deltaY)907 void Nlm_OffsetSegment (SegmenT segment, Int4 deltaX, Int4 deltaY)
908 
909 {
910   BasePPtr  item;
911   SegPPtr   seg;
912 
913   if (segment != NULL) {
914     item = (BasePPtr)segment;
915     switch (item->code) {
916       case PICTURE :
917       case SEGMENT :
918         seg = (SegPPtr) segment;
919         seg->seg.box.left += deltaX;
920         seg->seg.box.top += deltaY;
921         seg->seg.box.right += deltaX;
922         seg->seg.box.bottom += deltaY;
923         item = seg->seg.head;
924         while (item != NULL) {
925           switch (item->code) {
926             case PICTURE :
927             case SEGMENT :
928               Nlm_OffsetSegment ((SegmenT)item, deltaX, deltaY );
929               break;
930             case GENERIC :
931               TryOffsetPrimitive (item, deltaX, deltaY);
932           }
933           item = item->next;
934         }
935 
936     }
937   }
938 }
939 
940 /*****************************************************************************
941 *
942 *   ExploreSegment (segment, userdata, callback)
943 *       Explores the segment's child list (recursively)
944 *
945 *****************************************************************************/
946 
ExploreSegmentProc(SegmenT segment,VoidPtr userdata,SegmentExploreProc callback)947 static Boolean ExploreSegmentProc (SegmenT segment, VoidPtr userdata, SegmentExploreProc callback)
948 
949 {
950   Boolean   goOn;
951   GenPPtr   gpp;
952   BasePPtr  item;
953   BasePPtr  next;
954   Uint2     primCt;
955   SegPPtr   seg;
956 
957   goOn = FALSE;
958   if (segment != NULL && callback != NULL) {
959     seg = (SegPPtr) segment;
960     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
961       goOn = callback (segment, NULL, seg->seg.segID, 0, 0, userdata);
962       item = seg->seg.head;
963       primCt = 0;
964       while (item != NULL && goOn) {
965         primCt++;
966         next = item->next;
967         switch (item->code) {
968           case PICTURE :
969           case SEGMENT :
970             goOn = ExploreSegmentProc ((SegmenT) item, userdata, callback);
971             break;
972           case GENERIC :
973             gpp = (GenPPtr) item;
974             goOn = callback (segment, (PrimitivE) item, seg->seg.segID,
975                              gpp->primID, primCt, userdata);
976             break;
977           default :
978             break;
979         }
980         item = next;
981       }
982     } else {
983       Message (MSG_ERROR, "ExploreSegment argument not a segment or picture");
984     }
985   }
986   return goOn;
987 }
988 
Nlm_ExploreSegment(SegmenT segment,VoidPtr userdata,SegmentExploreProc callback)989 void Nlm_ExploreSegment (SegmenT segment, VoidPtr userdata, SegmentExploreProc callback)
990 
991 {
992   ExploreSegmentProc (segment, userdata, callback);
993 }
994 
995 /*****************************************************************************
996 *
997 *   SearchSegment (segment, pt, pnt, scale, prID, prCt)
998 *       Returns the deepest segment that contains the pnt in world coordinates
999 *
1000 *****************************************************************************/
1001 
SearchSegment(SegmenT segment,ScalePtr scalePtr,PrimitivE PNTR prPtr)1002 SegmenT SearchSegment (SegmenT segment, ScalePtr scalePtr, PrimitivE PNTR prPtr )
1003 {
1004   SegmenT   foundSeg = NULL;
1005   BasePPtr  item;
1006   SegPPtr   seg;
1007   ScaleInfo scale;
1008 
1009   if (segment != NULL && scalePtr != NULL ) {
1010     seg = (SegPPtr) segment;
1011     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
1012       scale = *scalePtr;
1013       if (seg->seg.maxscale == 0 ||
1014           seg->seg.maxscale >= MAX (scale.scaleX, scale.scaleY)) {
1015         if ( (seg->seg.box.left <= scale.worldWindow.right) &&
1016              (seg->seg.box.right >= scale.worldWindow.left) &&
1017              (seg->seg.box.top >= scale.worldWindow.bottom) &&
1018              (seg->seg.box.bottom <= scale.worldWindow.top) ){
1019           if (seg->seg.visible) {
1020             item = seg->seg.tail;
1021             while (item != NULL && foundSeg == NULL) {
1022               switch (item->code) {
1023                 case GENERIC :
1024                   if (PrimitiveIsCloseToPoint (item, &scale)) {
1025                     foundSeg = (SegmenT) seg;
1026                     *prPtr = (PrimitivE)item;
1027                   }
1028                   break;
1029                 case SEGMENT :
1030                   foundSeg = SearchSegment ((SegmenT)item, &scale, prPtr);
1031                   break;
1032                 default :
1033                   Message (MSG_ERROR, "FindSegment child is a picture");
1034               }
1035               item = item->prev;
1036             }
1037           }
1038         }
1039       }
1040     } else {
1041       Message (MSG_ERROR, "SearchSegment argument not a segment or picture");
1042     }
1043   }
1044   return foundSeg;
1045 }
1046 
1047 /*****************************************************************************
1048 *
1049 *  ChangePrimAttribute (prim, flags, color, linestyle, shading, penwidth, mode)
1050 *
1051 *****************************************************************************/
1052 
Nlm_ChangePrimAttribute(PrimitivE prim,Uint1 flags,Uint1Ptr color,Int1 linestyle,Int1 shading,Int1 penwidth,Int1 mode)1053 void Nlm_ChangePrimAttribute (PrimitivE prim, Uint1 flags, Uint1Ptr color,
1054        Int1 linestyle, Int1 shading, Int1 penwidth, Int1 mode)
1055 {
1056   GenPPtr  gpp = (GenPPtr)prim;
1057   AttPPtr  att;
1058 
1059   if ( gpp ) {
1060     att = &(gpp->att);
1061     if (linestyle >= NO_LINE_STYLE && linestyle <= DASHED_LINE) {
1062       if (shading >= NO_SHADING && shading <= THICK_NWSE_SHADING) {
1063         if ( flags & COLOR_ATT ) {
1064           if (color != NULL) {
1065             att->color [0] = color [0];
1066             att->color [1] = color [1];
1067             att->color [2] = color [2];
1068           } else {
1069             att->color [0] = BLACK_COLOR [0];
1070             att->color [1] = BLACK_COLOR [1];
1071             att->color [2] = BLACK_COLOR [2];
1072           }
1073         }
1074         if ( flags & STYLE_ATT ) att->linestyle = linestyle;
1075         if ( flags & SHADING_ATT ) att->shading = shading;
1076         if ( flags & WIDTH_ATT ) att->penwidth = MIN (penwidth, PEN_MAX);
1077         if ( flags & MODE_ATT ) att->mode = mode;
1078       } else {
1079         Message (MSG_ERROR, "ChangePrimAttribute shading out of range");
1080       }
1081     } else {
1082       Message (MSG_ERROR, "ChangePrimAttribute line style out of range");
1083     }
1084   } else {
1085     Message (MSG_ERROR, "ChangePrimAttribute primitive is NULL");
1086   }
1087 }
1088 
1089 /*****************************************************************************
1090 *
1091 *   OffsetPrim ( prim, deltaX, deltaY)
1092 *
1093 *****************************************************************************/
1094 
Nlm_OffsetPrim(PrimitivE prim,Int4 deltaX,Int4 deltaY)1095 void Nlm_OffsetPrim(PrimitivE prim, Int4 deltaX, Int4 deltaY)
1096 {
1097   BasePPtr item = (BasePPtr)prim;
1098 
1099   if (item  &&  item->code == GENERIC)
1100     TryOffsetPrimitive(item, deltaX, deltaY);
1101 }
1102 
1103 
1104 /*****************************************************************************
1105 *
1106 *   DeletePrim ( prim )
1107 *
1108 *****************************************************************************/
1109 
Nlm_DeletePrim(Nlm_SegmenT parent,Nlm_PrimitivE prim)1110 void Nlm_DeletePrim(Nlm_SegmenT parent, Nlm_PrimitivE prim)
1111 {
1112   BasePPtr      item = (BasePPtr)prim;
1113   Nlm_SegPData *seg  = &((SegPPtr)parent)->seg;
1114 
1115   if ( !item )
1116     return;
1117 
1118 #ifdef _DEBUG
1119   {{
1120     BasePPtr temp = seg->head;
1121     for ( ;  temp  &&  temp != item;  temp = temp->next);
1122     ASSERT ( temp == item );
1123   }}
1124 #endif
1125 
1126   if (item == seg->head)
1127     seg->head = item->next;
1128   if (item == seg->tail)
1129     seg->tail = item->prev;
1130 
1131   if ( item->prev )
1132     item->prev->next = item->next;
1133   if ( item->next )
1134     item->next->prev = item->prev;
1135 
1136   CleanupPrimitive( item );
1137   MemFree( item );
1138 
1139   /* It would be nice to call Nlm_RecalculateSegment() here, but:
1140    *  1) we don't know the scaling factors;
1141    *  2) it can be rather time-consuming if a lot of primitives get
1142    *     deleted at once.
1143    *  Ergo:  that's up to the user to recalc the seg. Take care...
1144    */
1145 }
1146 
1147