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