|
NCBI Home IEB Home C Toolkit docs C++ Toolkit source browser C Toolkit source browser (2) |
NCBI C Toolkit Cross ReferenceC/desktop/asn2graphic.c |
source navigation diff markup identifier search freetext search file search |
1 /* asn2graphic.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: asn2graphic.c
27 * Author: Eric Northup
28 *
29 * Version Creation Date: 11/8/01
30 *
31 * $Revision: 6.131 $
32 *
33 * File Description:
34 *
35 * Modifications:
36 * --------------------------------------------------------------------------
37 *
38 * ==========================================================================
39 */
40
41 #include <asn2graphicp.h>
42 #include <sequtil.h>
43 #include <sqnutils.h>
44 #include <explore.h>
45 #include <drawingp.h>
46 #include <alignmgr2.h>
47
48 /* type used to accumulate align score weights, should be small to save space, but large enough we do not overflow. */
49 typedef Int2 AccumValue_t;
50 typedef AccumValue_t PNTR AccumValuePtr_t;
51 #define ACCUMVALUE_MAX INT2_MAX
52
53 /*
54 Given a sequence alignment, look at its score
55 and return a suitable integer (AccumValue_t) weight.'
56 scoretype gives which part of the score to use.
57 */
58 enum {
59 NLM_SCORE_COUNT = 0,
60 NLM_SCORE_SCORE,
61 NLM_SCORE_BIT,
62 NLM_SCORE_EVALUE,
63 NLM_SCORE_NUMBER,
64 NLM_SCORE_TOOBIG
65 };
66
67
68 #define RELEVANT_FEATS_PER_CHUNK 128
69
70 /* these do not apply to individual features; they are used, ie in "AddFeatureToFilter (FEATDEF_ANY_RNA. . .)
71 that would make the filter include _all_ types of RNA */
72 #define FEATDEF_ANY_PROT (APPEARANCEITEM_MAX + 1)
73 #define FEATDEF_ANY_RNA (APPEARANCEITEM_MAX + 2)
74
75 typedef struct renderInput {
76 AppearanceItemPtr AIP;
77 FilterItemPtr FIP;
78 RelevantFeatureItemPtr RFIP;
79 SegmenT labelSeg;
80 SegmenT drawSeg;
81 Int4 yStart;
82 Int4 decorationLeft;
83 Int4 decorationRight;
84 Int4 decorationHeight;
85 Uint2 featureOffset;
86 Uint2 Height, rowHeight;
87 } RenderInput, PNTR RenderInputPtr;
88
89 typedef struct viewerInstanceData {
90 BioseqPtr BSP;
91 Uint4 viewScale;
92 Uint4 seqLength;
93 Int4Ptr ceiling;
94 SeqAnnotPtr PNTR sapList;
95 Uint2 sapCount;
96 SeqAnnotPtr currentSAP;
97 SegmenT drawOnMe;
98 SegmenT sanLevelSeg;
99 SegmenT topLevelSeg;
100 Uint4 featureCount;
101 ValNodePtr featVNP; /* data.ptrvalue == RelevantFeatureItem [RELEVANT_FEATS_PER_CHUNK] */
102 ValNodePtr BSPsegmentVNP;
103 AppearancePtr AppPtr;
104 FilterPtr FltPtr;
105 LayoutAlgorithm overrideLayout;
106 Int4 gphheight;
107 SegmenT gphseg;
108 Int4 gphyOffset;
109 Int4 from;
110 Int4 to;
111 Boolean allFeatures;
112 GraphicViewExtrasPtr extras;
113 } ViewerContext, PNTR ViewerContextPtr;
114
115 typedef struct featureFilterState {
116 ValNodePtr currentRFIPblockVNP;
117 Uint4 featureBlockOffset;
118 Uint2 indexInBlock;
119 } FeatureFilterState, PNTR FeatureFilterStatePtr;
120
121 #define MAX_ALIGN_SORT_LABEL 20
122 typedef struct seq_align_sort_info {
123 SeqAlignPtr sap;
124 Int4 start, stop;
125 Uint1 strand;
126 Char label[MAX_ALIGN_SORT_LABEL + 1];
127 AccumValue_t normScore;
128 } SeqAlignSortInfo, PNTR SeqAlignSortInfoPtr;
129
130 typedef struct AlignmentFilterState {
131 /* SeqAlignPtr SAPhead, SAPcurrent; */ /* obsolete */
132 SeqAlignSortInfoPtr alignSorted; /* array of SeqAlignPtrs & Info about them, sorted */
133 Int4 alignSortedLen; /* len of alignSorted */
134 Int4 alignIndex; /* index of current alignment in alignSorted */
135 Uint1 scoreType; /* what kind of score will we filter and weight by? */
136 Int2 cutoffPercent; /* include alignments in alignSorted only if their score is in the top cutoffPercent */
137 AccumValue_t cutoffScore; /* normalised score Below which aligns won't get into alignSorted. */
138 AccumValue_t cutoffScoreHi; /* normalised score Above which aligns won't get into alignSorted. */
139 Int4 minScore, maxScore; /* un-normalised min & max scores seen on these alignments */
140 } AlignmentFilterState, PNTR AlignmentFilterStatePtr;
141
142 /*
143 Bioseq's are still special-case for now. todo: make bioseq segments use this mechanism
144 */
145
146 typedef union filterState {
147 FeatureFilterState feat;
148 AlignmentFilterState align;
149 } FilterState, PNTR FilterStatePtr;
150
151 typedef struct filterProcessState {
152 FilterState state;
153 FilterItemPtr currentFIP;
154 ValNodePtr currentFilterVNP;
155 ValNodePtr needFreeList; /* things to be freed with ValNodeFreeData() after finishing this filter */
156 ValNodePtr lastInFreeList;
157 SegmenT labelSegs [APPEARANCEITEM_MAX];
158 SegmenT drawSegs [APPEARANCEITEM_MAX];
159 Int4 ceiling;
160 RenderInput renderParm;
161 Uint4 featuresProcessedCount;
162 BoolPtr featuresProcessed; /*points to an array of boolean [vContext->featureCount] */
163 ViewerContextPtr vContext;
164 Boolean groupBoxDrawn;
165 Boolean groupLabelDrawn;
166 Boolean annotBoxDrawn;
167 Boolean annotLabelDrawn;
168 } FilterProcessState, PNTR FilterProcessStatePtr;
169
170 typedef void (*RenderFuncPtr) (RenderInputPtr rip, ViewerContextPtr vContext);
171 typedef void (*GetDimensionsPtr) (RenderInputPtr, Int4Ptr start, Int4Ptr stop, Uint2Ptr height, ViewerContextPtr vContext);
172
173 typedef struct renderClass {
174 RenderFuncPtr RenderFunc;
175 GetDimensionsPtr GetDimensions;
176 } RenderClass, PNTR RenderClassPtr;
177
178 typedef struct internalRow {
179 Uint4 rowFeatureCount;
180 DataVal layoutData;
181 ValNodePtr feats; /* data.ptrvalue == RelevantFeatureItemPtr */
182 struct internalRow PNTR next;
183 } InternalRow, PNTR InternalRowPtr;
184
185 /* returns the total number of _rows_ */
186 typedef Uint2 (PNTR LayoutFunction) (InternalRowPtr firstRow, FilterProcessStatePtr FPSP);
187
188
189 static CharPtr LayoutStrings [] = {
190 "Inherit", /* Do not override layout in filter */
191 "Diagonal", /* One feature per row */
192 /* "DiagonalSawtooth" */
193 "ByType", /* like "compact", except that no row will contain _different_ types of features (this may use more rows) */
194 "Smear", /* one row contains all features of a given type (overlapping features will render as an anonymous smear */
195 /* "Single Row", -- not working currently*/ /* _all_ features are rendered in a single row (equivalent to "smear" if given only one type of features)*/
196 "Compact", /* Overlapping features are drawn in different rows, but this tries to minimize the number of rows, */
197 "GeneProducts", /* Group associated mRNA and CDS regions . . . */
198 "GeneProductsX", /* Like GeneProducts, but may display the same mRNA multiple times if it maps to multiple CDS regions. . . */
199 NULL
200 };
201
202 static LayoutAlgorithm LayoutValues [] = {
203 Layout_Inherit,
204 Layout_Diagonal,
205 /* Layout_DiagonalSawtooth, */
206 Layout_FeatTypePerLineGroup,
207 Layout_FeatTypePerLine,
208 /* Layout_AllInOneLine, not working currently (and not all that useful, either)*/
209 Layout_PackUpward,
210 Layout_GroupCorrespondingFeats,
211 Layout_GroupCorrespondingFeatsRepeat
212 };
213
214 static CharPtr AlnScoreStrings [] = {
215 "None",
216 "Score",
217 "Bit Score",
218 "E-value",
219 "Number",
220 NULL
221 };
222
223 /*
224 static CharPtr AlnScoreCutoffStrings[] = {
225 "100%",
226 "50%",
227 "20%",
228 "10%",
229 "5%",
230 "2%",
231 "1%",
232 NULL
233 };
234
235 static Int2 AlnScoreCutoffValues [] = {
236 100,
237 50,
238 20,
239 10,
240 5,
241 2,
242 1,
243 0
244 };
245 */
246
247
248 static CharPtr AlnScoreCutoffStrings[] = {
249 "None",
250 "40",
251 "50",
252 "60",
253 "70",
254 "80",
255 "100",
256 "200",
257 "400",
258 NULL
259 };
260
261 static Int2 AlnScoreCutoffValues [] = {
262 -1,
263 40,
264 50,
265 60,
266 70,
267 80,
268 100,
269 200,
270 400,
271 0
272 };
273
274 static CharPtr LlocStrings [] = {
275 "none",
276 "clip",
277 "cull",
278 "inside",
279 "above",
280 "below",
281 "left",
282 "right",
283 NULL
284 };
285
286 static LabelLocEnum LlocValues [] = {
287 LabelNone,
288 LabelAboveClip, /* above, but not wider than the feature*/
289 LabelAboveCull, /* above, but only displayed iff wider than the feature */
290 LabelInside,
291 LabelAbove,
292 LabelBelow,
293 LabelLeft,
294 LabelRight
295 };
296
297 static CharPtr BoolStrings [] = {
298 "yes",
299 "true",
300 "on",
301 "no",
302 "false",
303 "off",
304 NULL
305 };
306
307 static Boolean BoolValues [] = {
308 TRUE,
309 TRUE,
310 TRUE,
311 FALSE,
312 FALSE,
313 FALSE
314 };
315
316 static CharPtr RenderStrings [] = {
317 "none",
318 "line",
319 "cappedline",
320 "box",
321 "outlinebox",
322 NULL
323 };
324
325 static RenderAlgorithm RenderValues [] = {
326 Do_Not_Render,
327 Render_Line,
328 Render_CappedLine,
329 Render_Box,
330 Render_OutlineBox
331 };
332
333 static CharPtr GapStrings [] = {
334 "none",
335 "line",
336 "angle",
337 NULL
338 };
339
340 static GapEnum GapValues [] = {
341 NoGap,
342 LineGap,
343 AngleGap
344 };
345
346 static CharPtr GroupLabelLocations [] = {
347 "above",
348 "top",
349 "left",
350 "below",
351 "none",
352 NULL
353 };
354
355 static GroupLabelLocation GroupLabelLocationValues [] = {
356 LabelOnTop,
357 LabelOnTop,
358 LabelOnSide,
359 LabelOnBottom,
360 NoLabel
361 };
362
363 static CharPtr BioseqFormat [] = {
364 "accession",
365 "accn",
366 "fasta",
367 "long",
368 NULL
369 };
370
371 static Uint1 BioseqFormatValues [] = {
372 PRINTID_TEXTID_ACC_VER,
373 PRINTID_TEXTID_ACC_VER,
374 PRINTID_FASTA_SHORT,
375 PRINTID_FASTA_LONG
376 };
377
378 static CharPtr StrandStrings [] = {
379 "both",
380 "minus",
381 "plus",
382 /* these could be added if people would find them useful. . .
383 "-",
384 "+",
385 */
386 NULL
387 };
388
389 static StrandChoice StrandValues [] = {
390 BothStrands,
391 MinusStrand,
392 PlusStrand
393 };
394
395 static CharPtr ColorStrings [] = {
396 "black", /*0,0,0*/
397 "blue", /*0,0,255*/
398 "brown", /*133,62,38*/
399 "coral", /*255,127,80*/
400 "cyan", /*0,255,255*/
401 "gray", /*127,127,127*/
402 "green", /*0,255,0*/
403 "grey", /*127,127,127*/
404 "lavender", /*230,230,250*/
405 "magenta", /*255,0,255*/
406 "maroon", /*176,48,96*/
407 "orange", /*255,165,0*/
408 "olive", /*107,142,35*/
409 "pink", /*255,192,203*/
410 "purple", /*175,0,255*/
411 "red", /*255,0,0*/
412 "white", /*255,255,255*/
413 "yellow", /*255,255,0*/
414 NULL
415 };
416
417 static Uint1 ColorValues[][3] = {
418 /*black*/ {0, 0, 0},
419 /*blue*/ {0, 0, 255},
420 /*brown*/ {133, 62, 38},
421 /*coral*/ {255, 127, 80},
422 /*cyan*/ {0, 255, 255},
423 /*gray*/ {127, 127, 127},
424 /*green*/ {0, 255, 0},
425 /*grey*/ {127, 127, 127},
426 /*lavender*/ {230, 230, 250},
427 /*magenta*/ {255, 0, 255},
428 /*maroon*/ {176, 48, 96},
429 /*orange*/ {255, 165, 0},
430 /*olive*/ {107, 142, 35},
431 /*pink*/ {255, 192, 203},
432 /*purple*/ {175, 0, 255},
433 /*red*/ {255, 0, 0},
434 /*white*/ {255, 255, 255},
435 /*yellow*/ {255, 255, 0}
436 };
437
438 static Char config_filename [] = "asn2gph";
439
440 /*** Static function declarations ****/
441
442 static Int4 PixelsBetweenSeqCoords(Int4 left, Int4 right, Uint4 viewScale);
443 static Boolean IsInsertTic(RelevantFeatureItemPtr RFIP);
444 static void render_insert_tics(RenderInputPtr RIP);
445
446 /* functions for working with alignments */
447 /* perhaps some of these should be moved to the alignment manager. */
448 static Boolean SeqAlignContentLabel(SeqAlignPtr sap, SeqIdPtr notThisSID, CharPtr buf, Int4 buflen, Uint1 format);
449 AccumValue_t NormaliseScore(Int4 rawscore, Int4 min, Int4 max);
450 static Int4 WeightFromAlignScore(SeqAlignPtr sap, Uint1 scoreType);
451 static void FindCutoffScore(SeqAlignPtr sap, Int4 alignCnt, AlignmentFilterStatePtr afsp);
452 static void GatherAlignInfo(
453 SeqAlignPtr sap,
454 Int4 alignCnt,
455 SeqIdPtr bioSeqId,
456 AlignmentFilterStatePtr afsp
457 );
458 static Boolean AlignmentFilterStateInit(SeqAlignPtr sap, SeqIdPtr sid, AlignmentFilterStatePtr afsp, GraphicViewExtrasPtr extras);
459 static Boolean AlignmentFilterStateDone(AlignmentFilterStatePtr afsp);
460 static void AlignmentFilterStateFree( AlignmentFilterStatePtr afsp);
461
462 typedef struct align_seg_iterator {
463 SeqAlignPtr sap;
464 SeqIdPtr sip;
465
466 Int4 nsegs;
467 Int4 start, stop; /* left and rightmost bioseq coords for this alignment. */
468 Uint1 strand; /* so we iterate the right direction */
469 Int4 alignRow; /* from sip on non-stdseg aligns */
470 Int4 currentSeg; /* for indexed aligns */
471 StdSegPtr currentStdSeg; /* for std seg aligns */
472 } AlignSegIterator, PNTR AlignSegIteratorPtr;
473
474 static Int4 AlignSegIteratorCreate(SeqAlignPtr sap, SeqIdPtr sip, AlignSegIteratorPtr asi);
475 static Boolean AlignSegIteratorNext(AlignSegIteratorPtr asip, Int4Ptr start, Int4Ptr stop, Uint1Ptr strand, Uint1Ptr segType);
476
477
478 static Int1 StringIndexInStringList (CharPtr testString, CharPtr PNTR stringList) {
479
480 Int1 i;
481
482 if (testString == NULL || stringList == NULL) return -1;
483 /*
484 for (i = 0; stringList [i] != NULL; i++) {
485 if (StringICmp (testString, stringList [i]) == 0) return i;
486 }
487 */
488 i = 0;
489 while (stringList [i] != NULL) {
490 if (StringICmp (testString, stringList [i]) == 0) return i;
491 i++;
492 }
493 return -1;
494 }
495
496 /* this parses fonts either in the format used by Vibrant's ParseFont, or allows "small" "meduim", etc. . . */
497 static FonT LocalParseFont (
498 CharPtr FontSpec
499 )
500
501 {
502 if (FontSpec == NULL) return NULL;
503 if (StringICmp (FontSpec, "small") == 0) {
504 return SetSmallFont ();
505 } else if (StringICmp (FontSpec, "medium") == 0) {
506 return SetMediumFont ();
507 } else if (StringICmp (FontSpec, "large") == 0) {
508 return SetLargeFont ();
509 } else if (StringICmp (FontSpec, "system") == 0) {
510 return systemFont;
511 } else if (StringICmp (FontSpec, "program") == 0) {
512 return programFont;
513 } else {
514 return ParseFont (FontSpec);
515 }
516 }
517
518 static CharPtr ColorModifiers [] = {
519 "light",
520 "lt",
521 "dark",
522 "drk",
523 "dk",
524 NULL
525 };
526
527 /* COLOR must point to an array of Uint1 [3]; */
528 static Boolean ParseColor (
529 CharPtr string,
530 Uint1Ptr color
531 )
532
533 {
534 unsigned sscanfOffset, localColor [3] = { 0, 0, 0 }; /* "unsigned", to match %u and %n*/
535 Uint1 offset = 0;
536 Uint1 i;
537 Boolean isLight = FALSE, isDark = FALSE;
538 Char ch, modifierBuffer [8];
539 CharPtr tmp;
540
541
542 if (string == NULL || color == NULL) return FALSE;
543
544 /* first try to parse a human-readable color (ie, light blue)*/
545 StringNCpy_0 (modifierBuffer, string, sizeof (modifierBuffer));
546 /* truncate at space */
547 tmp = modifierBuffer;
548 ch = *tmp;
549 while (ch != '\0' && ch != ' ') {
550 tmp++;
551 ch = *tmp;
552 }
553 *tmp = '\0';
554
555 i = StringIndexInStringList (modifierBuffer, ColorModifiers);
556 if (i > 0 && i < DIM (ColorModifiers)) {
557 switch (i) {
558 case 1 :
559 case 2 :
560 isLight = TRUE;
561 offset = StringLen (modifierBuffer);
562 break;
563 case 3 :
564 case 4 :
565 case 5 :
566 isDark = TRUE;
567 offset = StringLen (modifierBuffer);
568 break;
569 default :
570 break;
571 }
572 }
573 while (string[offset] != '\0' && (! IS_ALPHA (string[offset]))) {
574 offset ++;
575 }
576
577 i = StringIndexInStringList (string + offset, ColorStrings);
578 if (i > 0 && i < DIM (ColorValues)) {
579 color [0] = ColorValues [i] [0];
580 color [1] = ColorValues [i] [1];
581 color [2] = ColorValues [i] [2];
582 if (isLight) {
583 color [0] = MIN (((3 * color [0]) / 2), 255);
584 color [1] = MIN (((3 * color [1]) / 2), 255);
585 color [2] = MIN (((3 * color [2]) / 2), 255);
586 } else if (isDark) {
587 color [0] = (2 * color [0]) / 3;
588 color [1] = (2 * color [1]) / 3;
589 color [2] = (2 * color [2]) / 3;
590 }
591 } else {
592 offset = 0;
593 for (i = 0; i < 3; i++) {
594 for (; string[offset] != '\0' && (! IS_DIGIT (string [offset])); offset++) continue;
595 if (string [offset] == '\0') return FALSE;
596 if (sscanf (string + offset, "%u%n", localColor + i, &sscanfOffset) == 0) return FALSE;
597 offset += sscanfOffset;
598 }
599 color [0] = localColor [0];
600 color [1] = localColor [1];
601 color [2] = localColor [2];
602 }
603 return TRUE;
604 }
605
606
607 NLM_EXTERN FilterPtr FindFilterByName (
608 CharPtr name,
609 ViewerConfigsPtr VCP
610 )
611
612 {
613 Int1 i;
614
615 if (VCP == NULL || StringHasNoText (name) || (! VCP->ArraysPopulated)) return NULL;
616 i = StringIndexInStringList (name, VCP->FilterNameArray);
617 if (i < VCP->FilterCount && i >= 0) return (VCP->FilterArray[i]);
618 return NULL;
619 }
620
621 NLM_EXTERN AppearancePtr FindAppearanceByName (
622 CharPtr name,
623 ViewerConfigsPtr VCP
624 )
625
626 {
627 Int1 i;
628
629 if (VCP == NULL || StringHasNoText (name) || (! VCP->ArraysPopulated)) return NULL;
630 i = StringIndexInStringList (name, VCP->AppearanceNameArray);
631 if (i < VCP->AppearanceCount && i>= 0) return (VCP->AppearanceArray[i]);
632 return NULL;
633 }
634
635 NLM_EXTERN LayoutAlgorithm FindLayoutByName (
636 CharPtr name
637 )
638
639 {
640 Int1 i;
641
642 if (StringHasNoText (name)) return Layout_Inherit;
643 i = StringIndexInStringList (name, LayoutStrings);
644 if (i >= 0 && i < DIM (LayoutValues)) {
645 return LayoutValues [i];
646 }
647 return Layout_Inherit;
648 }
649
650 static FilterPtr FindFilterByName_T (
651 CharPtr name,
652 ViewerConfigsPtr VCP
653 )
654
655 {
656 ValNodePtr nameVNP, filtVNP;
657
658 if (VCP == NULL || StringHasNoText (name)) return NULL;
659 for (nameVNP = VCP->FilterNameList, filtVNP = VCP->FilterList;
660 nameVNP != NULL && filtVNP != NULL;
661 nameVNP = nameVNP->next, filtVNP = filtVNP->next) {
662 if (nameVNP->data.ptrvalue != NULL &&
663 StringICmp (name, nameVNP->data.ptrvalue) == 0) {
664 return ((FilterPtr) filtVNP->data.ptrvalue);
665 }
666 }
667 return NULL;
668 }
669
670 static AppearancePtr FindAppearanceByName_T (
671 CharPtr name,
672 ViewerConfigsPtr VCP
673 )
674
675 {
676 ValNodePtr nameVNP, appVNP;
677
678 if (VCP == NULL || StringHasNoText (name)) return NULL;
679 for (nameVNP = VCP->AppearanceNameList, appVNP = VCP->AppearanceList;
680 nameVNP != NULL && appVNP != NULL;
681 nameVNP = nameVNP->next, appVNP = appVNP->next) {
682 if (nameVNP->data.ptrvalue != NULL &&
683 StringICmp (name, nameVNP->data.ptrvalue) == 0) {
684 return ((AppearancePtr) appVNP->data.ptrvalue);
685 }
686 }
687 return NULL;
688 }
689
690 static CharPtr FindFeatStrFromFeatDefType (Uint1 type)
691 {
692 CharPtr featName;
693
694 featName = FindKeyFromFeatDefType (type, FALSE);
695 /* handle locally defined feature types. */
696 if (type > FEATDEF_MAX)
697 {
698 switch (type) {
699 case APPEARANCEITEM_Alignment:
700 featName = "align";
701 break;
702 case APPEARANCEITEM_Segment:
703 featName = "segment";
704 break;
705 case APPEARANCEITEM_Graph:
706 featName = "graph";
707 break;
708 }
709 }
710 return featName;
711 }
712
713
714 NLM_EXTERN AppearancePtr CreateAppearance (
715 CharPtr newname,
716 ViewerConfigsPtr VCP
717 )
718
719 {
720 AppearancePtr AP;
721
722 if (VCP == NULL || StringHasNoText (newname)) return NULL;
723 if (FindAppearanceByName_T (newname, VCP) != NULL) return NULL; /* don't allow duplicate names */
724 AP = (AppearancePtr) MemNew (sizeof (Appearance));
725 if (AP == NULL) return NULL;
726 AP->name = StringSave (newname);
727 VCP->AppearanceCount++;
728 ValNodeAddPointer (&VCP->AppearanceList, VCP->AppearanceCount, AP);
729 ValNodeAddPointer (&VCP->AppearanceNameList, VCP->AppearanceCount, AP->name);
730 return AP;
731 }
732
733 static BioseqAppearanceItemPtr ParseBioseqAppearanceItem (
734 CharPtr sect,
735 ViewerConfigsPtr VCP
736 )
737
738 {
739 Char buf [128];
740 BioseqAppearanceItemPtr bioseqAIP;
741 Int2 i;
742 unsigned val; /* "unsigned" to match sscanf("%ud")*/
743
744 bioseqAIP = MemNew (sizeof (BioseqAppearanceItem));
745 if (bioseqAIP == NULL) return NULL;
746
747 bioseqAIP->labelLoc = GroupLabelLocationValues [0];
748 if (GetAppParam (config_filename, sect, "label", NULL, buf, sizeof (buf))) {
749 i = StringIndexInStringList (buf, GroupLabelLocations);
750 if (i >= 0 && i < DIM (GroupLabelLocationValues)) {
751 bioseqAIP->labelLoc = GroupLabelLocationValues [i];
752 }
753 }
754
755 bioseqAIP->drawScale = TRUE;
756 if (GetAppParam (config_filename, sect, "scale", NULL, buf, sizeof (buf))) {
757 i = StringIndexInStringList (buf, BoolStrings);
758 if (i >= 0 && i < DIM (BoolValues)) {
759 bioseqAIP->drawScale = BoolValues [i];
760 }
761 }
762
763 if (GetAppParam (config_filename, sect, "labelfont", NULL, buf, sizeof (buf))) {
764 bioseqAIP->labelFont = LocalParseFont (buf);
765 }
766 if (bioseqAIP->labelFont == NULL) {
767 bioseqAIP->labelFont = systemFont;
768 }
769
770 if (GetAppParam (config_filename, sect, "scalefont", NULL, buf, sizeof (buf))) {
771 bioseqAIP->scaleFont = LocalParseFont (buf);
772 }
773 if (bioseqAIP->scaleFont == NULL) {
774 bioseqAIP->scaleFont = SetSmallFont ();
775 }
776
777 if (GetAppParam (config_filename, sect, "height", NULL, buf, sizeof (buf))) {
778 if (buf != NULL) {
779 sscanf (buf, "%ud", &val);
780 bioseqAIP->height = MIN (val, 16);
781 }
782 }
783 if (bioseqAIP->height == 0) {
784 bioseqAIP->height = 10;
785 }
786
787 if (GetAppParam (config_filename, sect, "scaleheight", NULL, buf, sizeof (buf))) {
788 if (buf != NULL) {
789 sscanf (buf, "%ud", &val);
790 bioseqAIP->scaleHeight = MIN (val, 16);
791 }
792 }
793 if (bioseqAIP->scaleHeight == 0) {
794 bioseqAIP->scaleHeight = 10;
795 }
796
797 if (GetAppParam (config_filename, sect, "color", NULL, buf, sizeof (buf))) {
798 ParseColor (buf, bioseqAIP->bioseqColor);
799 }
800 if (GetAppParam (config_filename, sect, "labelcolor", NULL, buf, sizeof (buf))) {
801 ParseColor (buf, bioseqAIP->labelColor);
802 }
803 if (GetAppParam (config_filename, sect, "scalecolor", NULL, buf, sizeof (buf))) {
804 ParseColor (buf, bioseqAIP->scaleColor);
805 }
806
807 bioseqAIP->format = BioseqFormatValues [0];
808 if (GetAppParam (config_filename, sect, "format", NULL, buf, sizeof (buf))) {
809 i = StringIndexInStringList (buf, BioseqFormat);
810 if (i >= 0 && i < DIM (BioseqFormatValues)) {
811 bioseqAIP->format = BioseqFormatValues [i];
812 }
813 }
814
815 return bioseqAIP;
816 }
817
818 static AppearanceItemPtr ParseFeatureAppearanceItem (
819 CharPtr sect,
820 AppearanceItemPtr inheritFromMe,
821 Boolean recursing,
822 ViewerConfigsPtr VCP
823 )
824
825 {
826 Char buf [128];
827 AppearanceItemPtr newAIP;
828 Int2 i;
829 Boolean changed = FALSE;
830 unsigned val; /* "unsigned" to match sscanf("%ud")*/
831 AppearanceItemPtr namedAIP;
832
833 if (! recursing) {
834 if (GetAppParam (config_filename, sect, "usenamedstyle", NULL, buf, sizeof (buf))) {
835 namedAIP = ParseFeatureAppearanceItem (buf, inheritFromMe, TRUE, VCP);
836 if (namedAIP != NULL) {
837 inheritFromMe = namedAIP;
838 changed = TRUE; /* !!! this will use more memory than necessary */
839 }
840 }
841 }
842 newAIP = MemNew (sizeof (AppearanceItem));
843 if (newAIP == NULL) return NULL;
844 MemCopy (newAIP, inheritFromMe, sizeof (AppearanceItem));
845 if (GetAppParam (config_filename, sect, "color", NULL, buf, sizeof (buf))) {
846 changed = ParseColor (buf, newAIP->Color);
847 }
848 if (GetAppParam (config_filename, sect, "labelcolor", NULL, buf, sizeof (buf))) {
849 changed = ParseColor (buf, newAIP->LabelColor);
850 }
851
852 newAIP->LabelLoc = LabelAbove;
853 if (GetAppParam (config_filename, sect, "label", NULL, buf, sizeof (buf))) {
854 i = StringIndexInStringList (buf, LlocStrings);
855 if (i >= 0 && i < DIM (LlocValues)) {
856 newAIP->LabelLoc = LlocValues [i];
857 }
858 }
859 if (GetAppParam (config_filename, sect, "displaywith", NULL, buf, sizeof (buf))) {
860 i = StringIndexInStringList (buf, RenderStrings);
861 if (i >= 0 && i < DIM (RenderValues)) {
862 newAIP->RenderChoice = RenderValues [i];
863 changed = TRUE;
864 }
865 }
866 if (GetAppParam (config_filename, sect, "showarrow", NULL, buf, sizeof (buf))) {
867 i = StringIndexInStringList (buf, BoolStrings);
868 if (i >= 0 && i < DIM (BoolValues)) {
869 newAIP->ShowArrow = BoolValues [i];
870 changed = TRUE;
871 }
872 }
873 if (GetAppParam (config_filename, sect, "gap", NULL, buf, sizeof (buf))) {
874 i = StringIndexInStringList (buf, GapStrings);
875 if (i >= 0 && i < DIM (RenderValues)) {
876 newAIP->GapChoice = GapValues [i];
877 changed = TRUE;
878 }
879 }
880 if (GetAppParam (config_filename, sect, "showtype", NULL, buf, sizeof (buf))) {
881 i = StringIndexInStringList (buf, BoolStrings);
882 if (i >= 0 && i < DIM (BoolValues)) {
883 newAIP->AddTypeToLabel = BoolValues [i];
884 }
885 }
886 if (GetAppParam (config_filename, sect, "showcontent", NULL, buf, sizeof (buf))) {
887 i = StringIndexInStringList (buf, BoolStrings);
888 if (i >= 0 && i < DIM (BoolValues)) {
889 newAIP->AddDescToLabel = BoolValues [i];
890 }
891 }
892 if (GetAppParam (config_filename, sect, "height", NULL, buf, sizeof (buf))) {
893 if (buf != NULL) {
894 sscanf (buf, "%ud", &val);
895 newAIP->Height = MIN (val, 16);
896 changed = TRUE;
897 }
898 }
899 if (GetAppParam (config_filename, sect, "labelfont", NULL, buf, sizeof (buf))) {
900 newAIP->LabelFont = LocalParseFont (buf);
901 }
902 if (newAIP->LabelFont == NULL) {
903 newAIP->LabelFont = programFont;
904 }
905 if (newAIP->LabelFont != inheritFromMe->LabelFont) {
906 changed = TRUE;
907 }
908
909 /* this is only meaningful for alignment styles to change the appearance of the alignment's label. */
910 newAIP->format = BioseqFormatValues [0];
911 if (GetAppParam (config_filename, sect, "format", NULL, buf, sizeof (buf))) {
912 i = StringIndexInStringList (buf, BioseqFormat);
913 if (i >= 0 && i < DIM (BioseqFormatValues)) {
914 newAIP->format = BioseqFormatValues [i];
915 }
916 }
917
918
919 if (! changed) {
920 MemFree (newAIP);
921 return NULL;
922 }
923 return newAIP;
924 }
925
926 static AppearancePtr ParseAppearance (
927 CharPtr appearanceNameInFile,
928 ViewerConfigsPtr VCP
929 )
930
931 {
932 AppearancePtr AP;
933 AppearanceItemPtr AIP, impAIP, newAIP;
934 Char buf [128];
935 Char sect [128];
936 Char outputBuffer [128];
937 AppearanceItem DefaultAppearanceItem = {
938 {0, 0, 0}, {64, 64, 64}, Render_Box, 0, 5, 0, FALSE, LineGap, TRUE, TRUE, NULL, LabelAbove
939 };
940 Int1 i;
941 unsigned val;
942
943 if (appearanceNameInFile == NULL) return NULL;
944 DefaultAppearanceItem.LabelFont = programFont;
945 sprintf (sect, "%s.master", appearanceNameInFile);
946 /* require all styles to have a name, since high-level interface uses the name to identify Filters */
947 if (! GetAppParam (config_filename, sect, "name", NULL, buf, sizeof (buf))) return NULL;
948 if (StringHasNoText (buf)) return NULL;
949 AP = CreateAppearance (buf, VCP);
950 if (AP == NULL) return NULL;
951 AIP = ParseFeatureAppearanceItem (sect, &DefaultAppearanceItem, FALSE, VCP); /*parse xyz.master */
952 if (AIP == NULL) { /* require a "master" style */
953 DestroyAppearance (AP, VCP);
954 return NULL;
955 }
956 val = VCP->DefaultMaxScaleForArrow;
957 if (GetAppParam (config_filename, sect, "maxarrowscale", NULL, buf, sizeof (buf))) {
958 sscanf (buf, "%ud", &val);
959 }
960 AP->MaxScaleForArrow = val;
961 val = VCP->DefaultMinPixelsForArrow;
962 if (GetAppParam (config_filename, sect, "minarrowpixels", NULL, buf, sizeof (buf))) {
963 sscanf (buf, "%ud", &val);
964 }
965 AP->MinPixelsForArrow = val;
966 AP->ShadeSmears = VCP->DefaultShadeSmears;
967 if (GetAppParam (config_filename, sect, "shadesmears", NULL, buf, sizeof (buf))) {
968 i = StringIndexInStringList (buf, BoolStrings);
969 if (i >= 0 && i < DIM (BoolValues)) {
970 AP->ShadeSmears = BoolValues [i];
971 }
972 }
973
974 /* group box settings */
975 if (GetAppParam (config_filename, sect, "groupboxcolor", NULL, buf, sizeof (buf))) {
976 ParseColor (buf, AP->GroupBoxColor);
977 }
978
979 if (GetAppParam (config_filename, sect, "grouplabelfont", NULL, buf, sizeof (buf))) {
980 AP->GroupLabelFont = LocalParseFont (buf);
981 if (AP->GroupLabelFont == NULL) {
982 AP->GroupLabelFont = programFont;
983 }
984 }
985 if (GetAppParam (config_filename, sect, "grouplabelcolor", NULL, buf, sizeof (buf))) {
986 ParseColor (buf, AP->GroupLabelColor);
987 }
988
989 /* Named Annotation Style settings */
990 if (GetAppParam (config_filename, sect, "annotboxcolor", NULL, buf, sizeof (buf))) {
991 ParseColor (buf, AP->AnnotBoxColor);
992 }
993
994 if (GetAppParam (config_filename, sect, "annotlabelfont", NULL, buf, sizeof (buf))) {
995 AP->AnnotLabelFont = LocalParseFont (buf);
996 if (AP->AnnotLabelFont == NULL) {
997 AP->AnnotLabelFont = programFont;
998 }
999 }
1000 if (GetAppParam (config_filename, sect, "annotlabelcolor", NULL, buf, sizeof (buf))) {
1001 ParseColor (buf, AP->AnnotLabelColor);
1002 }
1003
1004
1005 sprintf (outputBuffer, "%s.bioseq", appearanceNameInFile);
1006 AP->bioseqAIP = ParseBioseqAppearanceItem (outputBuffer, VCP);
1007 sprintf (outputBuffer, "%s.imp", appearanceNameInFile);
1008 impAIP = ParseFeatureAppearanceItem (outputBuffer, AIP, FALSE, VCP);
1009 if (impAIP == NULL) {
1010 sprintf (outputBuffer, "%s.import", appearanceNameInFile);
1011 impAIP = ParseFeatureAppearanceItem (outputBuffer, AIP, FALSE, VCP);
1012 }
1013 if (impAIP == NULL) {
1014 impAIP = AIP;
1015 } else {
1016 AddAppearanceItemToAppearance (impAIP, AP, FEATDEF_IMP, VCP);
1017 }
1018 for (i = 1; i < APPEARANCEITEM_MAX; i++) {
1019 if (i == FEATDEF_IMP) continue;
1020 sprintf (outputBuffer, "%s.%s", appearanceNameInFile, FindFeatStrFromFeatDefType (i));
1021 if (i >= FEATDEF_allele && i <= FEATDEF_35_signal) { /* is it an imp-feat ? */
1022 newAIP = ParseFeatureAppearanceItem (outputBuffer, impAIP, FALSE, VCP);
1023 newAIP = newAIP ? newAIP : impAIP;
1024 } else {
1025 newAIP = ParseFeatureAppearanceItem (outputBuffer, AIP, FALSE, VCP);
1026 newAIP = newAIP ? newAIP : AIP;
1027 }
1028 if (newAIP != NULL) {
1029 AddAppearanceItemToAppearance (newAIP, AP, i, VCP);
1030 }
1031 }
1032 AddAppearanceItemToAppearance (AIP, AP, FEATDEF_BAD, VCP);
1033 return AP;
1034 }
1035
1036 NLM_EXTERN FilterPtr CreateFilter (
1037 CharPtr name,
1038 ViewerConfigsPtr VCP
1039 )
1040
1041 {
1042 FilterPtr FP;
1043
1044 if (VCP == NULL || StringHasNoText (name)) return NULL;
1045 if (FindFilterByName_T (name, VCP) != NULL) return NULL; /* don't allow duplicate names */
1046 FP = MemNew (sizeof (Filter));
1047 if (FP == NULL) return FP;
1048 FP->name = StringSave (name);
1049 VCP->FilterCount++;
1050 ValNodeAddPointer (&VCP->FilterList, VCP->FilterCount, FP);
1051 ValNodeAddPointer (&VCP->FilterNameList, VCP->FilterCount, FP->name);
1052 return FP;
1053 }
1054
1055 static void ChangeFeatureInFilterItem (
1056 FilterItemPtr FIP,
1057 Uint1 newFeatdef,
1058 Boolean includeMe,
1059 ViewerConfigsPtr VCP
1060 )
1061
1062 {
1063 Uint1 i;
1064 Uint1 order = 0;
1065 Uint1 orderIncrement = 0;
1066
1067 if (FIP == NULL) return;
1068
1069 if (includeMe) {
1070 orderIncrement = 1;
1071 for (i = 0; i < APPEARANCEITEM_MAX; i++) {
1072 order = MAX (order, FIP->IncludeFeature [i]);
1073 }
1074 order++; /* the lowest available order index */
1075 }
1076
1077 if (newFeatdef == FEATDEF_ANY) {
1078 for (i = 1; i < APPEARANCEITEM_MAX; i++) { /* start at 1 since we do not want to ever include FEATDEF_BAD */
1079 FIP->IncludeFeature [i] = order;
1080 order += orderIncrement;
1081 }
1082 } else if (newFeatdef == FEATDEF_ANY_RNA) {
1083 for (i = FEATDEF_preRNA; i <= FEATDEF_otherRNA; i++) {
1084 FIP->IncludeFeature [i] = order;
1085 order += orderIncrement;
1086 }
1087 FIP->IncludeFeature [FEATDEF_misc_RNA] = order;
1088 order += orderIncrement;
1089 FIP->IncludeFeature [FEATDEF_precursor_RNA] = order;
1090 order += orderIncrement;
1091 FIP->IncludeFeature [FEATDEF_snoRNA] = order;
1092 } else if (newFeatdef == FEATDEF_ANY_PROT) {
1093 FIP->IncludeFeature [FEATDEF_PROT] = order;
1094 order += orderIncrement;
1095 for (i = FEATDEF_preprotein; i <= FEATDEF_transit_peptide_aa; i++) {
1096 FIP->IncludeFeature [i] = order;
1097 order += orderIncrement;
1098 }
1099 } else if (newFeatdef == FEATDEF_IMP) {
1100 for (i = FEATDEF_allele; i <= FEATDEF_35_signal; i++) {
1101 FIP->IncludeFeature [i] = order;
1102 order += orderIncrement;
1103 }
1104 } else if (newFeatdef < APPEARANCEITEM_MAX) {
1105 FIP->IncludeFeature [newFeatdef] = order;
1106 }
1107 }
1108
1109 NLM_EXTERN void AddFeatureToFilterItem (
1110 FilterItemPtr FIP,
1111 Uint1 newFeatdef,
1112 ViewerConfigsPtr VCP
1113 )
1114
1115 {
1116 ChangeFeatureInFilterItem (FIP, newFeatdef, TRUE, VCP);
1117 }
1118
1119 NLM_EXTERN void RemoveFeatureFromFilterItem (
1120 FilterItemPtr FIP,
1121 Uint1 newFeatdef,
1122 ViewerConfigsPtr VCP
1123 )
1124
1125 {
1126 ChangeFeatureInFilterItem (FIP, newFeatdef, FALSE, VCP);
1127 }
1128
1129 static void AddFilterItemToFilter (
1130 FilterItemPtr newFIP,
1131 FilterPtr parent,
1132 ViewerConfigsPtr VCP
1133 )
1134
1135 {
1136 ValNodePtr newVNP, lastVNP;
1137
1138 for (lastVNP = parent->FilterItemList;
1139 lastVNP != NULL && lastVNP->next != NULL;
1140 lastVNP = lastVNP->next) continue;
1141 newVNP = ValNodeAdd (&parent->FilterItemList);
1142 newVNP->data.ptrvalue = newFIP;
1143 }
1144
1145 NLM_EXTERN FilterItemPtr CreateNewFilterItemInFilter (
1146 CharPtr name,
1147 FilterPtr parent,
1148 ViewerConfigsPtr VCP
1149 )
1150
1151 {
1152 FilterItemPtr FIP;
1153
1154 FIP = MemNew (sizeof (FilterItem));
1155 if (FIP == NULL) return FIP;
1156 FIP->GroupLabel = StringSaveNoNull (name);
1157 AddFilterItemToFilter (FIP, parent, VCP);
1158 return FIP;
1159 }
1160
1161 static CharPtr SpecialFeatures [] = {
1162 "everything",
1163 "all",
1164 "every",
1165 "any",
1166 "imp",
1167 "rna",
1168 "prot",
1169 "bioseq",
1170 "graph",
1171 "align",
1172 NULL
1173 };
1174
1175 static FilterItemPtr ParseFilterItem (
1176 CharPtr filterItemName,
1177 Uint2 defaultRowPadding,
1178 Uint2 defaultGroupPadding,
1179 LayoutAlgorithm defaultLayout,
1180 ViewerConfigsPtr VCP
1181 )
1182
1183 {
1184 Char sect [128];
1185 Char featureNum [128];
1186 Char buf [128];
1187 Uint4 featdeftype;
1188 Uint4 featureCount = 0;
1189 FilterItemPtr FIP;
1190 Int2 i, j;
1191 unsigned val;
1192
1193 FIP = MemNew (sizeof (FilterItem));
1194 if (FIP == NULL) return FIP;
1195 FIP->DrawScale = TristateUnset;
1196 FIP->Type = FeatureFilter; /* this will get changed if a graph or alignment is discovered instead */
1197 sprintf (sect, "filters.%s", filterItemName);
1198 GetAppParam (config_filename, sect, "layout", "inherit", buf, sizeof (buf));
1199 i = StringIndexInStringList (buf, LayoutStrings);
1200 if (i >= 0 && i < DIM (LayoutStrings)) {
1201 FIP->LayoutChoice = LayoutValues [i];
1202 } else {
1203 FIP->LayoutChoice = defaultLayout;
1204 }
1205
1206 FIP->GroupPadding = defaultGroupPadding;
1207 if (GetAppParam (config_filename, sect, "grouppadding", NULL, buf, sizeof (buf))) {
1208 sscanf (buf, "%ud", &val);
1209 val = MIN (val, 100);
1210 FIP->GroupPadding = val;
1211 }
1212
1213 FIP->IntraRowPaddingPixels = defaultRowPadding;
1214 if (GetAppParam (config_filename, sect, "rowpadding", NULL, buf, sizeof (buf))) {
1215 sscanf (buf, "%ud", &val);
1216 val = MIN (val, 100);
1217 FIP->IntraRowPaddingPixels = val;
1218 }
1219 FIP->DrawGroupBox = FALSE;
1220 FIP->FillGroupBox = FALSE;
1221 if (GetAppParam (config_filename, sect, "groupbox", NULL, buf, sizeof (buf))) {
1222 i = StringIndexInStringList (buf, BoolStrings);
1223 if (i >= 0 && i < DIM (BoolValues) && i >= 0) {
1224 FIP->DrawGroupBox = BoolValues [i];
1225 }
1226 }
1227 if (FIP->DrawGroupBox) {
1228 if (GetAppParam (config_filename, sect, "groupboxcolor", NULL, buf, sizeof (buf))) {
1229 FIP->GroupBoxColorSet = TRUE;
1230 ParseColor (buf, FIP->GroupBoxColor);
1231 }
1232 if (GetAppParam (config_filename, sect, "fillbox", NULL, buf, sizeof (buf))) {
1233 i = StringIndexInStringList (buf, BoolStrings);
1234 if (i >= 0 && i < DIM (BoolValues)) {
1235 FIP->FillGroupBox = BoolValues[i];
1236 }
1237 }
1238 }
1239
1240 FIP->GroupLabel = NoLabel;
1241 FIP->GroupLabelFont = programFont;
1242 if (GetAppParam (config_filename, sect, "name", NULL, buf, sizeof (buf))) {
1243 FIP->GroupLabel = StringSaveNoNull (buf);
1244 FIP->GroupLabelLoc = LabelOnTop;
1245 if (GetAppParam (config_filename, sect, "grouplabel", NULL, buf, sizeof (buf))) {
1246 i = StringIndexInStringList (buf, GroupLabelLocations);
1247 if (i >= 0 && i < DIM (GroupLabelLocationValues)) {
1248 FIP->GroupLabelLoc = GroupLabelLocationValues[i];
1249 }
1250 }
1251 if (GetAppParam (config_filename, sect, "grouplabelfont", NULL, buf, sizeof (buf))) {
1252 FIP->GroupLabelFontSet = TRUE;
1253 FIP->GroupLabelFont = LocalParseFont (buf);
1254 if (FIP->GroupLabelFont == NULL) {
1255 FIP->GroupLabelFont = programFont;
1256 }
1257 }
1258 if (GetAppParam (config_filename, sect, "grouplabelcolor", NULL, buf, sizeof (buf))) {
1259 FIP->GroupLabelColorSet = TRUE;
1260 ParseColor (buf, FIP->GroupLabelColor);
1261 }
1262 }
1263
1264 FIP->LabelLoc = LabelAbove;
1265 if (GetAppParam (config_filename, sect, "label", NULL, buf, sizeof (buf))) {
1266 i = StringIndexInStringList (buf, LlocStrings);
1267 if (i >= 0 && i < DIM (LlocValues)) {
1268 FIP->LabelLoc = LlocValues [i];
1269 }
1270 }
1271
1272 FIP->AddTypeToLabel = TristateUnset;
1273 if (FIP->LabelLoc != LabelNone && GetAppParam (config_filename, sect, "showtype", NULL, buf, sizeof (buf))) {
1274 i = StringIndexInStringList (buf, BoolStrings);
1275 if (i >= 0 && i < DIM (BoolValues)) {
1276 FIP->AddTypeToLabel = BOOL_TO_TRISTATE (BoolValues [i]);
1277 }
1278 }
1279 FIP->AddDescToLabel = TristateUnset;
1280 if (FIP->LabelLoc != LabelNone && GetAppParam (config_filename, sect, "showcontent", NULL, buf, sizeof (buf))) {
1281 i = StringIndexInStringList (buf, BoolStrings);
1282 if (i >= 0 && i < DIM (BoolValues)) {
1283 FIP->AddDescToLabel = BOOL_TO_TRISTATE (BoolValues [i]);
1284 }
1285 }
1286
1287 FIP->MatchStrand = StrandValues [0];
1288 if (GetAppParam (config_filename, sect, "strand", NULL, buf, sizeof (buf))) {
1289 i = StringIndexInStringList (buf, StrandStrings);
1290 if (i >= 0 && i < DIM (StrandValues)) {
1291 FIP->MatchStrand = StrandValues [i];
1292 }
1293 }
1294 for (i = 1; i < APPEARANCEITEM_MAX; i++) {
1295 sprintf (featureNum, "feature%d", (unsigned) i);
1296 if (GetAppParam (config_filename, sect, featureNum, NULL, buf, sizeof (buf))) {
1297 featdeftype = FindFeatDefTypeFromKey (buf);
1298 if (featdeftype == FEATDEF_BAD) {
1299 /* special-case checks for types of features not found by FindFeatDefTypeFromKey () */
1300 j = StringIndexInStringList (buf, SpecialFeatures);
1301 /*
1302 if (j >= 0 && j < DIM (SpecialFeatures)) {
1303 switch (j) {
1304 case 1 :
1305 case 2 :
1306 case 3 :
1307 case 4 :
1308 featdeftype = FEATDEF_ANY;
1309 break;
1310 case 5 :
1311 featdeftype = FEATDEF_IMP;
1312 break;
1313 case 6 :
1314 featdeftype = FEATDEF_ANY_RNA;
1315 break;
1316 case 7 :
1317 featdeftype = FEATDEF_ANY_PROT;
1318 break;
1319 case 8 :
1320 FIP->Type = BioseqFilter;
1321 break;
1322 case 9 :
1323 FIP->Type = GraphFilter;
1324 break;
1325 case 10 :
1326 FIP->Type = AlignmentFilter;
1327 break;
1328 default :
1329 break;
1330 }
1331 } else continue; */
1332 /* insert special-case checks for types of features not found by FindFeatDefTypeFromKey () here */
1333 if (StringICmp (buf, "everything") == 0 ||
1334 StringICmp (buf, "all") == 0 ||
1335 StringICmp (buf, "every") == 0 ||
1336 StringICmp (buf, "any") == 0) {
1337 featdeftype = FEATDEF_ANY;
1338 } else if (StringICmp (buf, "imp") == 0) {
1339 featdeftype = FEATDEF_IMP; /* FindFeatDefTypeFromKey matches 'import', but not 'imp' */
1340 } else if (StringICmp (buf, "rna") == 0) {
1341 featdeftype = FEATDEF_ANY_RNA;
1342 } else if (StringICmp (buf, "prot") == 0) {
1343 featdeftype = FEATDEF_ANY_PROT;
1344 } else if (StringICmp (buf, "bioseq") == 0) {
1345 FIP->Type = BioseqFilter;
1346 } else if (StringICmp (buf, "graph") == 0) {
1347 featdeftype = APPEARANCEITEM_Graph;
1348 FIP->Type = GraphFilter;
1349 } else if (StringICmp (buf, "align") == 0) {
1350 featdeftype = APPEARANCEITEM_Alignment;
1351 FIP->Type = AlignmentFilter;
1352 } else continue; /* failed to find a match */
1353 }
1354 AddFeatureToFilterItem (FIP, featdeftype, VCP);
1355 featureCount++;
1356 }
1357 }
1358 if (FIP->Type == BioseqFilter) {
1359 FIP->DrawScale = TristateUnset;
1360 if (GetAppParam (config_filename, sect, "scale", NULL, buf, sizeof (buf))) {
1361 i = StringIndexInStringList (buf, BoolStrings);
1362 if (i >= 0 && i < DIM (BoolValues)) {
1363 FIP->DrawScale = BOOL_TO_TRISTATE (BoolValues [i]);
1364 }
1365 }
1366 }
1367 if (featureCount == 0) {
1368 MemFree (FIP);
1369 return NULL;
1370 }
1371 return FIP;
1372 }
1373
1374 static FilterPtr ParseFilter (
1375 CharPtr filterNameInFile,
1376 ViewerConfigsPtr VCP
1377 )
1378
1379 {
1380
1381 FilterPtr FP;
1382 FilterItemPtr FIP;
1383 Int2 i;
1384 Uint1 filterItemCount = 0;
1385 Char buf [128]; /* for input *from* GetAppParam */
1386 Char outputBuffer [128]; /* paramater *to* GetAppParam */
1387 Char sect [128];
1388 Boolean foundBioseqFilter = FALSE;
1389 Boolean foundGraphFilter = FALSE;
1390 Boolean foundAlignmentFilter = FALSE;
1391 ValNodePtr VNP;
1392 Boolean createImplicitBioseq = TRUE;
1393 Boolean createImplicitGraphs = TRUE;
1394 unsigned val; /* to match sscanf ("%d"...)*/
1395 Uint2 defaultRowPadding;
1396 Uint2 defaultGroupPadding;
1397 LayoutAlgorithm defaultLayout;
1398
1399 if (filterNameInFile == NULL) return NULL;
1400 sprintf (sect, "%s", filterNameInFile);
1401 /* require all styles to have a name, since high-level interface uses the name to identify Filters */
1402 if (! GetAppParam (config_filename, sect, "name", NULL, buf, sizeof (buf))) return NULL;
1403 FP = CreateFilter (buf, VCP); /* Createfilter will check for duplucate names */
1404 if (FP == NULL) return FP;
1405 val = VCP->DefaultMaxScaleWithLabels;
1406 if (GetAppParam (config_filename, sect, "maxlabelscale", NULL, buf, sizeof (buf))) {
1407 sscanf (buf, "%ud", &val);
1408 }
1409 FP->MaxScaleWithLabels = val;
1410
1411 /* Group by Named Annotation stuff */
1412 FP->AnnotBoxColorSet = FALSE;
1413 FP->AnnotLabelFontSet = FALSE;
1414 FP->AnnotLabelColorSet = FALSE;
1415
1416 FP->GroupByAnnot = TRUE;
1417 if (GetAppParam (config_filename, sect, "annotgroup", NULL, buf, sizeof (buf))) {
1418 i = StringIndexInStringList (buf, BoolStrings);
1419 if (i >= 0 && i < DIM (BoolStrings)) {
1420 FP->GroupByAnnot = (BoolValues [i]);
1421 }
1422 }
1423 if (FP->GroupByAnnot) {
1424 FP->DrawAnnotBox = TRUE;
1425 if (GetAppParam (config_filename, sect, "annotbox", NULL, buf, sizeof (buf))) {
1426 i = StringIndexInStringList (buf, BoolStrings);
1427 if (i >= 0 && i < DIM (BoolStrings)) {
1428 FP->DrawAnnotBox = (BoolValues [i]);
1429 }
1430 }
1431 if (FP->DrawAnnotBox) {
1432 if (GetAppParam (config_filename, sect, "annotboxcolor", NULL, buf, sizeof (buf))) {
1433 FP->AnnotBoxColorSet = TRUE;
1434 ParseColor (buf, FP->AnnotBoxColor);
1435 }
1436 }
1437 FP->AnnotLabelLoc = LabelOnTop;
1438 if (GetAppParam (config_filename, sect, "annotlabel", NULL, buf, sizeof (buf))) {
1439 i = StringIndexInStringList (buf, GroupLabelLocations);
1440 if (i >= 0 && i < DIM (GroupLabelLocationValues)) {
1441 FP->AnnotLabelLoc = GroupLabelLocationValues[i];
1442 }
1443 }
1444 if (FP->AnnotLabelLoc != NoLabel) {
1445 FP->AnnotLabelFont = programFont;
1446 if (GetAppParam (config_filename, sect, "annotlabelfont", NULL, buf, sizeof (buf))) {
1447 FP->AnnotLabelFont = LocalParseFont (buf);
1448 if (FP->AnnotLabelFont == NULL) {
1449 FP->AnnotLabelFont = programFont;
1450 } else {
1451 FP->AnnotLabelFontSet = TRUE;
1452 }
1453 }
1454 if (GetAppParam (config_filename, sect, "annotlabelcolor", NULL, buf, sizeof (buf))) {
1455 FP->AnnotLabelColorSet = TRUE;
1456 ParseColor (buf, FP->AnnotLabelColor);
1457 }
1458 }
1459 }
1460
1461 /* other default values */
1462 GetAppParam (config_filename, sect, "layout", NULL, buf, sizeof (buf));
1463 i = StringIndexInStringList (buf, LayoutStrings);
1464 if (i >= 0 && i < DIM (LayoutValues)) {
1465 defaultLayout = LayoutValues [i];
1466 } else {
1467 defaultLayout = Layout_Inherit;
1468 }
1469
1470 val = VCP->DefaultGroupPadding;
1471 if (GetAppParam (config_filename, sect, "grouppadding", NULL, buf, sizeof (buf))) {
1472 sscanf (buf, "%ud", &val);
1473 val = MIN (val, 100);
1474 }
1475 defaultGroupPadding = val;
1476
1477 val = VCP->DefaultRowPadding;
1478 if (GetAppParam (config_filename, sect, "rowpadding", NULL, buf, sizeof (buf))) {
1479 sscanf (buf, "%ud", &val);
1480 }
1481 defaultRowPadding = val;
1482
1483 if (GetAppParam (config_filename, sect, "suppressbioseq", NULL, buf, sizeof (buf))) {
1484 i = StringIndexInStringList (buf, BoolStrings);
1485 if (i >= 0 && i < DIM (BoolStrings)) {
1486 createImplicitBioseq = ! (BoolValues [i]);
1487 }
1488 }
1489 if (GetAppParam (config_filename, sect, "suppressgraphs", NULL, buf, sizeof (buf))) {
1490 i = StringIndexInStringList (buf, BoolStrings);
1491 if (i >= 0 && i < DIM (BoolStrings)) {
1492 createImplicitGraphs = ! (BoolValues [i]);
1493 }
1494 }
1495
1496 for (i = 1; i < APPEARANCEITEM_MAX; i++) {
1497 sprintf (outputBuffer, "%s%d", "group", (unsigned) i);
1498 if (GetAppParam (config_filename, sect, outputBuffer, NULL, buf, sizeof (buf))) {
1499 FIP = ParseFilterItem (buf, defaultRowPadding, defaultGroupPadding, defaultLayout, VCP);
1500 if (FIP == NULL) continue;
1501 if (FIP->Type == BioseqFilter) {
1502 foundBioseqFilter = TRUE;
1503 }
1504 if (FIP->Type == GraphFilter) {
1505 foundGraphFilter = TRUE;
1506 }
1507 if (FIP->Type == AlignmentFilter) {
1508 foundAlignmentFilter = TRUE;
1509 }
1510 AddFilterItemToFilter (FIP, FP, VCP);
1511 filterItemCount++;
1512 }
1513 }
1514 if (filterItemCount == 0) {
1515 DestroyFilter (FP, VCP);
1516 return NULL;
1517 }
1518
1519 if (createImplicitBioseq && ! foundBioseqFilter) {
1520 VNP = MemNew (sizeof (ValNode));
1521 FIP = MemNew (sizeof (FilterItem));
1522 if (VNP == NULL || FIP == NULL) {
1523 DestroyFilter (FP, VCP);
1524 return NULL;
1525 }
1526 /* insert a Bioseq filter at the head of the list */
1527 VNP->next = FP->FilterItemList;
1528 VNP->data.ptrvalue = FIP;
1529 FP->FilterItemList = VNP;
1530
1531 FIP->Type = BioseqFilter;
1532 FIP->IntraRowPaddingPixels = defaultRowPadding;
1533 }
1534
1535 if (createImplicitGraphs && ! foundAlignmentFilter) {
1536 /* insert an alignment filter at the_end of the list */
1537 FIP = MemNew (sizeof (FilterItem));
1538 VNP = ValNodeAddPointer (&FP->FilterItemList, 0, FIP);
1539 if (FIP == NULL || VNP == NULL ) {
1540 DestroyFilter (FP, VCP);
1541 return NULL;
1542 }
1543 FIP->Type = AlignmentFilter;
1544 FIP->LayoutChoice = defaultLayout;
1545 FIP->GroupPadding = defaultGroupPadding;
1546 FIP->IntraRowPaddingPixels = defaultRowPadding;
1547 FIP->LabelLoc = LabelAbove;
1548 FIP->MatchStrand = StrandValues [0];
1549 }
1550
1551 if (createImplicitGraphs && ! foundGraphFilter) {
1552 /* insert a Graph filter at the_end of the list */
1553 FIP = MemNew (sizeof (FilterItem));
1554 VNP = ValNodeAddPointer (&FP->FilterItemList, 0, FIP);
1555 if (FIP == NULL || VNP == NULL ) {
1556 DestroyFilter (FP, VCP);
1557 return NULL;
1558 }
1559 FIP->Type = GraphFilter;
1560 FIP->IntraRowPaddingPixels = 5;
1561 }
1562
1563 return FP;
1564 }
1565
1566 /* if this will be used by multiple threads in a multi-threaded application, there should be a lock around writing this */
1567 static ViewerConfigsPtr newGraphicViewer_ConfigFileParse_Global = NULL;
1568
1569 static void InitializeDefaultStyle (
1570 CharPtr configFileName
1571 );
1572
1573 NLM_EXTERN ViewerConfigsPtr GetGraphicConfigParseResults (
1574 void
1575 )
1576
1577 {
1578 Uint1 AppearanceCount;
1579 Uint1 FilterCount;
1580 Uint1 i;
1581 void PNTR PNTR ptr2;
1582 ViewerConfigsPtr VCP;
1583 ValNodePtr nameVNP;
1584 ValNodePtr VNP;
1585
1586 if (newGraphicViewer_ConfigFileParse_Global != NULL) {
1587 return newGraphicViewer_ConfigFileParse_Global;
1588 }
1589
1590 InitializeDefaultStyle (config_filename);
1591
1592 VCP = MemNew (sizeof (ViewerConfigs));
1593 if (VCP == NULL) return NULL;
1594
1595 if (ParseConfigFile (VCP) == 0) return NULL;
1596 /* this should never happen, because of the static default style*/
1597 if (VCP->AppearanceCount == 0 || VCP->FilterCount == 0) return NULL;
1598
1599 AppearanceCount = VCP->AppearanceCount;
1600 FilterCount = VCP->FilterCount;
1601 i = (AppearanceCount + FilterCount) * 2 + 2; /* total number of pointers needed (the extra 2 are NULL's to terminate the name lists) */
1602 ptr2 = MemNew (i * sizeof (VoidPtr));
1603 if (ptr2 == NULL) {
1604 MemFree (VCP);
1605 return NULL;
1606 }
1607 VCP->AppearanceArray = (AppearancePtr PNTR) ptr2;
1608 ptr2 += AppearanceCount;
1609 VCP->AppearanceNameArray = (CharPtr PNTR) ptr2;
1610 ptr2 += AppearanceCount + 1; /* add a NULL pointer to terminate the list */
1611 VCP->FilterArray = (FilterPtr PNTR) ptr2;
1612 ptr2 += FilterCount;
1613 VCP->FilterNameArray = (CharPtr PNTR) ptr2;
1614 VNP = VCP->AppearanceList;
1615 nameVNP = VCP->AppearanceNameList;
1616 for (i = 0; i < AppearanceCount; i++) {
1617 VCP->AppearanceArray[i] = VNP->data.ptrvalue;
1618 VCP->AppearanceNameArray[i] = nameVNP->data.ptrvalue;
1619 VNP = VNP->next;
1620 nameVNP = nameVNP->next;
1621 }
1622
1623 VNP = VCP->FilterList;
1624 nameVNP = VCP->FilterNameList;
1625 for (i = 0; i < FilterCount; i++) {
1626 VCP->FilterArray[i] = VNP->data.ptrvalue;
1627 VCP->FilterNameArray[i] = nameVNP->data.ptrvalue;
1628 VNP = VNP->next;
1629 nameVNP = nameVNP->next;
1630 }
1631 VCP->ArraysPopulated = TRUE;
1632 newGraphicViewer_ConfigFileParse_Global = VCP;
1633 return VCP;
1634 }
1635
1636 /* returns count of objects successfully parsed -- so 0 on failure */
1637 NLM_EXTERN Uint2 ParseConfigFile (
1638 ViewerConfigsPtr VCP
1639 )
1640
1641 {
1642 Char tag [32];
1643 Char name [128];
1644 Int2 i;
1645 Uint2 fCount = 0, aCount = 0;
1646 VoidPtr tempPtr;
1647 unsigned val; /* to match scanf("%ud"...) */
1648
1649 GetAppParam (config_filename, "filters", "maxlabelscale", NULL, tag, sizeof (tag));
1650 if (sscanf (tag, "%ud", &val) != 1) {
1651 val = 200;
1652 }
1653 VCP->DefaultMaxScaleWithLabels = val;
1654
1655 GetAppParam (config_filename, "filters", "grouppadding", NULL, tag, sizeof (tag));
1656 if (sscanf (tag, "%ud", &val) != 1) {
1657 val = 3;
1658 }
1659 VCP->DefaultGroupPadding = val;
1660
1661 GetAppParam (config_filename, "filters", "rowpadding", NULL, tag, sizeof (tag));
1662 if (sscanf (tag, "%ud", &val) != 1) {
1663 val = 5;
1664 }
1665 VCP->DefaultRowPadding = val;
1666
1667 GetAppParam (config_filename, "styles", "maxarrowscale", NULL, tag, sizeof (tag));
1668 if (sscanf (tag, "%ud", &val) != 1) {
1669 val = 5;
1670 }
1671 VCP->DefaultMaxScaleForArrow = val;
1672
1673 GetAppParam (config_filename, "styles", "minarrowpixels", NULL, tag, sizeof (tag));
1674 if (sscanf (tag, "%ud", &val) != 1) {
1675 val = 5;
1676 }
1677 VCP->DefaultMinPixelsForArrow = val;
1678
1679 VCP->DefaultShadeSmears = FALSE;
1680 if (GetAppParam (config_filename, "styles", "shadesmears", NULL, tag, sizeof (tag))) {
1681 i = StringIndexInStringList (tag, BoolStrings);
1682 if (i >= 0 && i < DIM (BoolValues)) {
1683 VCP->DefaultShadeSmears = BoolValues [i];
1684 }
1685 }
1686
1687 for (i = 0; i < 110; i++) { /* do filters first */
1688 if (i < 10) {
1689 sprintf (tag, "filter0%d", (unsigned) i);
1690 } else {
1691 sprintf (tag, "filter%d", (unsigned) i - 9);
1692 }
1693 if (GetAppParam (config_filename, "filters", tag, NULL, name, sizeof (name))) {
1694 tempPtr = ParseFilter (name, VCP);
1695 if (tempPtr == NULL) continue;
1696 fCount++;
1697 }
1698 }
1699 for (i = 0; i < 110; i++) {
1700 if (i < 10) {
1701 sprintf (tag, "style0%d", (unsigned) i);
1702 } else {
1703 sprintf (tag, "style%d", (unsigned) i - 9);
1704 }
1705 if (GetAppParam (config_filename, "styles", tag, NULL, name, sizeof (name))) {
1706 tempPtr = ParseAppearance (name, VCP);
1707 if (tempPtr == NULL) continue;
1708 aCount++;
1709 }
1710 }
1711 return (aCount + fCount);
1712 }
1713
1714 NLM_EXTERN FilterPtr DestroyFilter (
1715 FilterPtr FP,
1716 ViewerConfigsPtr VCP
1717 )
1718
1719 {
1720 FilterItemPtr FIP;
1721 ValNodePtr VNP;
1722 Uint1 i;
1723
1724 if (FP == NULL || VCP == NULL) {
1725 return NULL;
1726 }
1727 for (VNP = FP->FilterItemList; VNP; VNP = VNP->next) { /* free all filterItems, and their labels */
1728 FIP = (FilterItemPtr) VNP->data.ptrvalue;
1729 if (FIP == NULL) {
1730 continue;
1731 }
1732 MemFree (FIP->GroupLabel);
1733 MemFree (FIP);
1734 }
1735 for (VNP = VCP->FilterList; VNP != NULL; VNP = VNP->next) {
1736 if (VNP->data.ptrvalue == FP) {
1737 i = VNP->choice;
1738 VNP = ValNodeExtract (&VCP->FilterList, i);
1739 break;
1740 }
1741 }
1742 if (VNP != NULL) {
1743 MemFree (VNP);
1744 VNP = ValNodeExtract (&VCP->FilterNameList, i);
1745 MemFree (VNP->data.ptrvalue);
1746 MemFree (VNP);
1747 }
1748 --VCP->FilterCount;
1749 MemFree (FP);
1750 return NULL;
1751 }
1752
1753 NLM_EXTERN void AddAppearanceItemToAppearance (
1754 AppearanceItemPtr AIP,
1755 AppearancePtr AP,
1756 Uint1 newFeatdef,
1757 ViewerConfigsPtr VCP
1758 )
1759
1760 {
1761 Uint1 i;
1762 ValNodePtr VNP;
1763
1764 if (AIP == NULL || AP == NULL || VCP == NULL) return;
1765 if (newFeatdef == FEATDEF_ANY) {
1766 for (i = 0; i < APPEARANCEITEM_MAX; i++) {
1767 AP->FeaturesAppearanceItem [i] = AIP;
1768 }
1769 } else if (newFeatdef == FEATDEF_ANY_RNA) {
1770 for (i = FEATDEF_preRNA; i <= FEATDEF_otherRNA; i++) {
1771 AP->FeaturesAppearanceItem [i] = AIP;
1772 }
1773 AP->FeaturesAppearanceItem [FEATDEF_misc_RNA] = AIP;
1774 AP->FeaturesAppearanceItem [FEATDEF_precursor_RNA] = AIP;
1775 AP->FeaturesAppearanceItem [FEATDEF_snoRNA] = AIP;
1776 } else if (newFeatdef == FEATDEF_ANY_PROT) {
1777 AP->FeaturesAppearanceItem [FEATDEF_PROT] = AIP;
1778 for (i = FEATDEF_preprotein; i <= FEATDEF_transit_peptide_aa; i++) {
1779 AP->FeaturesAppearanceItem [i] = AIP;
1780 }
1781 } else if (newFeatdef == FEATDEF_IMP) {
1782 for (i = FEATDEF_allele; i <= FEATDEF_35_signal; i++) {
1783 AP->FeaturesAppearanceItem [i] = AIP;
1784 }
1785 } else if (newFeatdef < APPEARANCEITEM_MAX) {
1786 AP->FeaturesAppearanceItem [newFeatdef] = AIP;
1787 } else return;
1788 for (VNP = AP->AppearanceItemList; VNP != NULL && VNP->data.ptrvalue != AIP; VNP = VNP->next) continue;
1789 if (! (VNP != NULL && VNP->data.ptrvalue == AIP)) { /* AIP was not previously in the AppearanceItemList */
1790 ValNodeAddPointer (&AP->AppearanceItemList, 0, AIP);
1791 }
1792 }
1793
1794 NLM_EXTERN AppearancePtr DestroyAppearance (
1795 AppearancePtr AP,
1796 ViewerConfigsPtr VCP
1797 )
1798
1799 {
1800 Uint1 i;
1801 ValNodePtr VNP;
1802
1803 if (AP == NULL || VCP == NULL) return NULL;
1804 if (AP->AppearanceItemList != NULL) {
1805 ValNodeFreeData (AP->AppearanceItemList);
1806 }
1807 for (VNP = VCP->AppearanceList; VNP != NULL; VNP = VNP->next) {
1808 if (VNP->data.ptrvalue == AP) {
1809 i = VNP->choice;
1810 VNP = ValNodeExtract (&VCP->AppearanceList, i);
1811 break;
1812 }
1813 }
1814 if (VNP != NULL) {
1815 MemFree (VNP);
1816 VNP = ValNodeExtract (&VCP->AppearanceNameList, i);
1817 MemFree (VNP);
1818 }
1819 MemFree (AP);
1820 return NULL;
1821 }
1822
1823 static void getDim_do_not_render (
1824 RenderInputPtr RIP,
1825 Int4Ptr Start,
1826 Int4Ptr Stop,
1827 Uint2Ptr height,
1828 ViewerContextPtr vContext
1829 )
1830
1831 {
1832 RelevantFeatureItemPtr RFIP;
1833
1834 RFIP = RIP->RFIP;
1835
1836 *Start = *Stop = RFIP->Left;
1837 *height = 1;
1838 }
1839
1840 static void do_not_render (
1841 RenderInputPtr RIP,
1842 ViewerContextPtr vContext
1843 )
1844
1845 {
1846 return;
1847 }
1848
1849 static void getDim_render_with_line (
1850 RenderInputPtr RIP,
1851 Int4Ptr Start,
1852 Int4Ptr Stop,
1853 Uint2Ptr height,
1854 ViewerContextPtr vContext
1855 )
1856
1857 {
1858 RelevantFeatureItemPtr RFIP;
1859
1860 RFIP = RIP->RFIP;
1861
1862 if (vContext->allFeatures) {
1863 *Start = RFIP->Left;
1864 *Stop = RFIP->Right;
1865 } else {
1866 *Start = MAX (RFIP->Left, vContext->from);
1867 *Stop = MAX (RFIP->Right, vContext->to);
1868 }
1869 *height = 1;
1870 }
1871
1872 static void render_wrap_around_markers(
1873 RenderInputPtr RIP,
1874 ViewerContextPtr vContext
1875 )
1876 {
1877 Uint4 StartY;
1878 RelevantFeatureItemPtr RFIP;
1879 AppearanceItemPtr AIP;
1880
1881 RFIP = RIP->RFIP;
1882 AIP = RIP->AIP;
1883 StartY = RIP->yStart - (RIP->featureOffset) - AIP->Height / 2 - 1;
1884
1885 AddSymbol(RIP->drawSeg, RFIP->Left - 3 * vContext->viewScale, StartY, LEFT_TRIANGLE_SYMBOL, FALSE, MIDDLE_LEFT, 0);
1886 AddSymbol(RIP->drawSeg, RFIP->Right + 3 * vContext->viewScale, StartY, RIGHT_TRIANGLE_SYMBOL, FALSE, MIDDLE_RIGHT, 0);
1887 }
1888
1889 static void render_with_line (
1890 RenderInputPtr RIP,
1891 ViewerContextPtr vContext
1892 )
1893
1894 {
1895 Uint4 StartY;
1896 PrimitivE thisPrim;
1897 RelevantFeatureItemPtr RFIP;
1898 AppearanceItemPtr AIP;
1899 Int4 start, stop;
1900
1901 RFIP = RIP->RFIP;
1902 AIP = RIP->AIP;
1903
1904 StartY = RIP->yStart - (RIP->featureOffset) - AIP->Height / 2;
1905 if (vContext->allFeatures) {
1906 start = RFIP->Left;
1907 stop = RFIP->Right;
1908 } else {
1909 start = MAX (RFIP->Left, vContext->from);
1910 stop = MAX (RFIP->Right, vContext->to);
1911 }
1912
1913 if (!RFIP->circularSpanningOrigin || RFIP->numivals < 2) {
1914 thisPrim = AddLine (RIP->drawSeg, start, StartY, stop, StartY, 0, 0);
1915 SetPrimitiveIDs (thisPrim, RFIP->entityID, RFIP->itemID, RFIP->itemType, 0);
1916 } else {
1917 /* feature spans the origin. draw specially */
1918 if (RFIP->ivals[0] < stop) {
1919 thisPrim = AddLine (RIP->drawSeg, RFIP->ivals[0], StartY, stop, StartY, 0, 0);
1920 SetPrimitiveIDs (thisPrim, RFIP->entityID, RFIP->itemID, RFIP->itemType, 0);
1921 }
1922 if (RFIP->ivals[2* RFIP->numivals - 1] > start) {
1923 thisPrim = AddLine (RIP->drawSeg, start, StartY, RFIP->ivals[2* RFIP->numivals - 1], StartY, 0, 0);
1924 SetPrimitiveIDs (thisPrim, RFIP->entityID, RFIP->itemID, RFIP->itemType, 0);
1925 }
1926 render_wrap_around_markers(RIP, vContext);
1927 }
1928 }
1929
1930 static void getDim_render_with_capped_line (
1931 RenderInputPtr RIP,
1932 Int4Ptr Start,
1933 Int4Ptr Stop,
1934 Uint2Ptr height,
1935 ViewerContextPtr vContext
1936 )
1937
1938 {
1939 RelevantFeatureItemPtr RFIP;
1940 AppearanceItemPtr AIP;
1941
1942 RFIP = RIP->RFIP;
1943 AIP = RIP->AIP;
1944
1945
1946 if (vContext->allFeatures) {
1947 *Start = RFIP->Left;
1948 *Stop = RFIP->Right;
1949 } else {
1950 *Start = MAX (RFIP->Left, vContext->from);
1951 *Stop = MAX (RFIP->Right, vContext->to);
1952 }
1953 *height = AIP->Height;
1954 }
1955
1956 static void render_with_capped_line (
1957 RenderInputPtr RIP,
1958 ViewerContextPtr vContext
1959 )
1960
1961 {
1962 PrimitivE thisPrim;
1963 AppearanceItemPtr AIP;
1964 RelevantFeatureItemPtr RFIP;
1965 Int4 StartY;
1966
1967 StartY = RIP->yStart - (RIP->featureOffset);
1968 render_with_line (RIP, vContext);
1969 RFIP = RIP->RFIP;
1970 AIP = RIP->AIP;
1971
1972
1973 if (!RFIP->circularSpanningOrigin || RFIP->numivals < 2) {
1974 thisPrim = AddLine (RIP->drawSeg, RFIP->Left, StartY, RFIP->Left, StartY - AIP->Height, 0, 0);
1975 SetPrimitiveIDs (thisPrim, RFIP->entityID, RFIP->itemID, RFIP->itemType, 0);
1976 thisPrim = AddLine (RIP->drawSeg, RFIP->Right, StartY, RFIP->Right, StartY - AIP->Height, 0, 0);
1977 SetPrimitiveIDs (thisPrim, RFIP->entityID, RFIP->itemID, RFIP->itemType, 0);
1978 } else {
1979 /* origin spanning feature */
1980 thisPrim = AddLine (RIP->drawSeg, RFIP->ivals[0], StartY, RFIP->ivals[0], StartY - AIP->Height, 0, 0);
1981 SetPrimitiveIDs (thisPrim, RFIP->entityID, RFIP->itemID, RFIP->itemType, 0);
1982 thisPrim = AddLine (RIP->drawSeg, RFIP->ivals[2* RFIP->numivals - 1], StartY, RFIP->ivals[2* RFIP->numivals - 1], StartY - AIP->Height, 0, 0);
1983 SetPrimitiveIDs (thisPrim, RFIP->entityID, RFIP->itemID, RFIP->itemType, 0);
1984 }
1985 }
1986
1987 static void getDim_render_with_box (
1988 RenderInputPtr RIP,
1989 Int4Ptr Start,
1990 Int4Ptr Stop,
1991 Uint2Ptr height,
1992 ViewerContextPtr vContext
1993 )
1994 {
1995 RelevantFeatureItemPtr RFIP;
1996 AppearanceItemPtr AIP;
1997
1998 RFIP = RIP->RFIP;
1999 AIP = RIP->AIP;
2000 *Start = RFIP->Left;
2001 *Stop = RFIP->Right;
2002 *height = AIP->Height;
2003 if (IsInsertTic(RFIP))
2004 *height += AIP->Height;
2005 }
2006
2007 static Boolean IsInsertTic(RelevantFeatureItemPtr RFIP)
2008 {
2009 int iival;
2010
2011 /* Insert Tics only on alignments with more than one segment */
2012 if (RFIP->featdeftype != APPEARANCEITEM_Alignment || RFIP->numivals < 2)
2013 return FALSE;
2014
2015 for (iival = 0; iival < RFIP->numivals; ++iival) {
2016 /* a segment with beginning and end the same is an insert */
2017 if (RFIP->ivals [2 * iival] == RFIP->ivals [2 * iival + 1] ) {
2018 return TRUE;
2019 }
2020 }
2021 return FALSE;
2022 }
2023
2024 #if 0 /* TestForSmearOverlap was replaced by PixelsBetweenSeqCoords everwhere it was used */
2025 static Boolean TestForSmearOverlap (
2026 Int4 PrevEnd,
2027 Int4 NewStart,
2028 ViewerContextPtr vContext
2029 )
2030 {
2031 return PixelsBetweenSeqCoords(PrevEnd, NewStart, vContext->viewScale) < 1;
2032 }
2033 #endif
2034
2035 /* returns TRUE if no visible gap. */
2036 static Boolean NoVisibleGap (
2037 Int4 x1,
2038 Int4 x2,
2039 Uint4 viewScale
2040 )
2041 {
2042 return abs(PixelsBetweenSeqCoords(x1, x2, viewScale)) < 2;
2043 }
2044
2045 static Boolean TestForSmear (
2046 RelevantFeatureItemPtr RFIP1,
2047 RelevantFeatureItemPtr RFIP2,
2048 Uint4 viewScale
2049 )
2050 {
2051 Uint4 minSeperation;
2052
2053 minSeperation = 5; /* do not smear a feature more than 5 pixels wide */
2054
2055 if (abs(PixelsBetweenSeqCoords(RFIP1->Right, RFIP1->Left, viewScale)) >= minSeperation) return FALSE;
2056 if (abs(PixelsBetweenSeqCoords(RFIP2->Right, RFIP2->Left, viewScale)) >= minSeperation) return FALSE;
2057
2058 return (NoVisibleGap (RFIP1->Right, RFIP2->Left, viewScale)
2059 || NoVisibleGap (RFIP1->Right, RFIP2->Right, viewScale)
2060 || NoVisibleGap (RFIP1->Left, RFIP2->Right, viewScale)
2061 || NoVisibleGap (RFIP1->Left, RFIP2->Left, viewScale) );
2062
2063 }
2064
2065 static Int4 PixelsBetweenSeqCoords(Int4 left, Int4 right, Uint4 viewScale)
2066 {
2067 /* Will be negative if right is really not right of left. */
2068 /* 0 if they fall on the same pixel. */
2069 /* Do NOT change this to (right - left)/viewScale. NOT the same. */
2070 return (right/viewScale - left/viewScale);
2071 }
2072
2073 static void render_with_box_master (
2074 RenderInputPtr RIP,
2075 Boolean fillBox,
2076 ViewerContextPtr vContext
2077 )
2078
2079 {
2080 Int4 StartY;
2081 Uint2 pieceIValStart;
2082 PrimitivE thisPrim;
2083 Uint2 i;
2084 Int4 mid;
2085 AppearanceItemPtr AIP;
2086 AppearancePtr AP;
2087 RelevantFeatureItemPtr RFIP;
2088 Boolean shade_p;
2089 Uint1 arrow;
2090
2091 RFIP = RIP->RFIP;
2092 AIP = RIP->AIP;
2093 AP = vContext->AppPtr;
2094 StartY = RIP->yStart - (RIP->featureOffset);
2095 if (RFIP->LeftEnd == EndClipped) {
2096 thisPrim = AddLine (RIP->drawSeg, vContext->from, StartY - AIP->Height / 2, RFIP->Left, StartY - AIP->Height / 2, 0, 0);
2097 SetPrimitiveIDs (thisPrim, RFIP->entityID, RFIP->itemID, RFIP->itemType, 0);
2098 }
2099 if (RFIP->RightEnd == EndClipped) {
2100 thisPrim = AddLine (RIP->drawSeg, vContext->to, StartY - AIP->Height / 2, RFIP->Right, StartY - AIP->Height / 2, 0, 0);
2101 SetPrimitiveIDs (thisPrim, RFIP->entityID, RFIP->itemID, RFIP->itemType, 0);
2102 }
2103 if (RFIP->numivals == 1) {
2104 shade_p = (RFIP->entityID == 0 && RFIP->itemID == 0) ? AP->ShadeSmears : FALSE;
2105 if (RFIP->entityID == 0 && RFIP->itemID == 0) { /* is this a multi-feature smear? */
2106 if (shade_p) {
2107 /* AddAttribute (RIP->drawSeg, SHADING_ATT, 0, 0, MEDIUM_SHADING, 0, 0);*/
2108 }
2109 thisPrim = AddRectangle (RIP->drawSeg, RFIP->Left, StartY, RFIP->Right, StartY - AIP->Height, NO_ARROW, fillBox, 0);
2110 SetPrimitiveIDs (thisPrim, RFIP->entityID, RFIP->itemID, RFIP->itemType, 0);
2111 if (shade_p) {
2112 /* AddAttribute (RIP->drawSeg, SHADING_ATT, 0, 0, NO_SHADING, 0, 0);*/
2113 }
2114
2115 } else { /* nope */
2116 arrow = NO_ARROW;
2117 if (RFIP->featstrand == Seq_strand_plus) {
2118 arrow = RIGHT_ARROW;
2119 } else if (RFIP->featstrand == Seq_strand_minus) {
2120 arrow = LEFT_ARROW;
2121 }
2122 if (! AIP->ShowArrow) {
2123 arrow = NO_ARROW;
2124 }
2125 if (abs(PixelsBetweenSeqCoords( RFIP->Left, RFIP->Right, vContext->viewScale)) < AP->MinPixelsForArrow) {
2126 arrow = NO_ARROW;
2127 }
2128 if (vContext->viewScale > AP->MaxScaleForArrow) {
2129 arrow = NO_ARROW;
2130 }
2131 thisPrim = AddRectangle (RIP->drawSeg, RFIP->Left, StartY, RFIP->Right, StartY - AIP->Height, arrow, fillBox, 0);
2132 SetPrimitiveIDs (thisPrim, RFIP->entityID, RFIP->itemID, RFIP->itemType, 0);
2133 }
2134 return;
2135 } else {
2136 i = 0;
2137 while (i < RFIP->numivals) {
2138 /* collect a group of interval(s) which do not contain any pixels between them */
2139 pieceIValStart = i;
2140 /* this tests is the i-plus-1th feature is part of the smear, which goes from pieceIValStart to i, inclusive */
2141 /* On alignments only smear away the gaps caused by inserts. */
2142 if (RFIP->featdeftype == APPEARANCEITEM_Alignment) {
2143 while (i + 1 < RFIP->numivals &&
2144 NoVisibleGap (RFIP->ivals [2 * i + 1], RFIP->ivals [2 * i + 2], vContext->viewScale) &&
2145 (RFIP->ivals [2 * i] == RFIP->ivals [2 * i + 1] || RFIP->ivals [2 * i + 2] == RFIP->ivals [2 * i + 3])) {
2146 i++;
2147 }
2148 } else {
2149 while (i + 1 < RFIP->numivals &&
2150 NoVisibleGap (RFIP->ivals [2 * i + 1], RFIP->ivals [2 * i + 2], vContext->viewScale)) {
2151 i++;
2152 }
2153 }
2154
2155 /* draw the segment and the gap -- drawing the gap first, so that it is overdrawn by the segment */
2156 if (i + 1 < RFIP->numivals) { /* a gap is present if there are more ivals to consider after i*/
2157 if (RFIP->circularSpanningOrigin && RFIP->ivals [2 * i + 1] > RFIP->ivals [2 * i + 2]) {
2158 /* on a circular bioseq, this gap spans the origin and has to be drawn specially */
2159 /* RFIP->Left will be 0, RFIP->Right will be the length of the Bioseq */
2160 if (RFIP->ivals [2 * i + 1] < RFIP->Right - 1) {
2161 /* Draw the part of the gap at the right end. Might not be any. */
2162 thisPrim = AddLine (RIP->drawSeg, RFIP->ivals[2 * i + 1], StartY - AIP->Height / 2, RFIP->Right, StartY - AIP->Height / 2, 0, 0);
2163 SetPrimitiveIDs (thisPrim, RFIP->entityID, RFIP->itemID, RFIP->itemType, 0);
2164 }
2165 if (RFIP->Left < RFIP->ivals [2 * i + 2]) {
2166 /* draw the part of the gap at the left end. */
2167 thisPrim = AddLine (RIP->drawSeg, RFIP->Left, StartY - AIP->Height / 2, RFIP->ivals[2 * i + 2], StartY - AIP->Height / 2, 0, 0);
2168 SetPrimitiveIDs (thisPrim, RFIP->entityID, RFIP->itemID, RFIP->itemType, 0);
2169 }
2170 /* No. I didn't put in code to make those lines 'Angle Gap' style. Figured it wouldn't show up very well. You can if you want. */
2171
2172 /* draw markers to show that this wraps around */
2173 render_wrap_around_markers(RIP, vContext);
2174
2175 } else {
2176 /* ordinary gap */
2177 if (AIP->GapChoice == LineGap) {
2178 thisPrim = AddLine (RIP->drawSeg, RFIP->ivals [2 * i + 1], StartY - AIP->Height / 2,
2179 RFIP->ivals [2 * i + 2] - vContext->viewScale, StartY - AIP->Height / 2, 0, 0);
2180 SetPrimitiveIDs (thisPrim, RFIP->entityID, RFIP->itemID, RFIP->itemType, 0);
2181 } else if (AIP->GapChoice == AngleGap) {
2182 mid = (RFIP->ivals [2 * i + 2] + RFIP->ivals [2 * i + 1]) / 2;
2183 thisPrim = AddLine (RIP->drawSeg, RFIP->ivals [2 * i + 1], StartY - AIP->Height / 2,
2184 mid, StartY, 0, 0);
2185 SetPrimitiveIDs (thisPrim, RFIP->entityID, RFIP->itemID, RFIP->itemType, 0);
2186 thisPrim = AddLine (RIP->drawSeg, mid, StartY,
2187 RFIP->ivals [2 * i + 2] - vContext->viewScale, StartY - AIP->Height / 2, 0, 0);
2188 SetPrimitiveIDs (thisPrim, RFIP->entityID, RFIP->itemID, RFIP->itemType, 0);
2189 }
2190 }
2191 }
2192 arrow = NO_ARROW;
2193 if (i == RFIP->numivals - 1 && RFIP->featstrand == Seq_strand_plus) {
2194 arrow = RIGHT_ARROW;
2195 } else if (RFIP->featstrand == Seq_strand_minus) {
2196 /* on minus strands, Alignments put their intervals in coordinate order.
2197 Other features put theirs in biological order (right to left),
2198 so we have to draw the arrow differently (or we could sort the intervals so they
2199 ended up the same. */
2200 if ((pieceIValStart == 0 && RFIP->featdeftype == APPEARANCEITEM_Alignment) ||
2201 (i == RFIP->numivals - 1 && RFIP->featdeftype != APPEARANCEITEM_Alignment))
2202 arrow = LEFT_ARROW;
2203 }
2204 if (! AIP->ShowArrow) {
2205 arrow = NO_ARROW;
2206 }
2207 if (ABS (RFIP->Right - RFIP->Left) / vContext->viewScale < AP->MinPixelsForArrow) {
2208 arrow = NO_ARROW;
2209 }
2210 if (vContext->viewScale > AP->MaxScaleForArrow) {
2211 arrow = NO_ARROW;
2212 }
2213 thisPrim = AddRectangle (RIP->drawSeg, RFIP->ivals [2 * pieceIValStart], StartY, RFIP->ivals [2 * i + 1], StartY - AIP->Height, arrow, fillBox, 0);
2214 SetPrimitiveIDs (thisPrim, RFIP->entityID, RFIP->itemID, RFIP->itemType, 0);
2215 i++;
2216 }
2217 if (RFIP->featdeftype == APPEARANCEITEM_Alignment) {
2218 render_insert_tics(RIP);
2219 }
2220 }
2221 }
2222
2223
2224 static void render_insert_tics(RenderInputPtr RIP)
2225 {
2226 AppearanceItemPtr AIP;
2227 RelevantFeatureItemPtr RFIP;
2228 PrimitivE thisPrim;
2229 Int4 StartY;
2230 Int4 i;
2231
2232 RFIP = RIP->RFIP;
2233 AIP = RIP->AIP;
2234 StartY = RIP->yStart - (RIP->featureOffset);
2235
2236 /* if we are drawing an aligment, and the interval is zero length, It is an insert.
2237 Draw a vertical line the height of the bar under the bar to show this. */
2238 for (i = 0; i < RFIP->numivals; ++i) {
2239 /* a segment with beginning and end the same is an insert */
2240 if (RFIP->ivals [2 * i] == RFIP->ivals [2 * i + 1] ) {
2241 thisPrim = AddLine(RIP->drawSeg, RFIP->ivals [2 * i], StartY - AIP->Height,
2242 RFIP->ivals [2 * i], StartY - AIP->Height * 2, FALSE, 0);
2243 SetPrimitiveIDs(thisPrim, RFIP->entityID, RFIP->itemID, RFIP->itemType, 0);
2244 }
2245 }
2246 }
2247
2248
2249 static void render_with_box (
2250 RenderInputPtr RIP,
2251 ViewerContextPtr vContext
2252 )
2253
2254 {
2255 render_with_box_master (RIP, TRUE, vContext);
2256
2257 }
2258
2259 static void render_with_outline_box (
2260 RenderInputPtr RIP,
2261 ViewerContextPtr vContext
2262 )
2263
2264 {
2265 render_with_box_master (RIP, FALSE, vContext);
2266 }
2267
2268 static const RenderClass RenderAlgorithmTable [] = {
2269 {do_not_render, getDim_do_not_render}, /* do_not_render */
2270 {render_with_line, getDim_render_with_line}, /* Render_Line */
2271 {render_with_capped_line, getDim_render_with_capped_line}, /* Render_CappedLine */
2272 {render_with_box, getDim_render_with_box}, /* Render_Box */
2273 {render_with_outline_box, getDim_render_with_box}, /* Render_OutlineBox */
2274 /* !!! these do not exist right now - can they be removed? !!! */
2275 {render_with_line, getDim_render_with_line},
2276 {render_with_box, getDim_render_with_box},
2277 {render_with_line, getDim_render_with_line},
2278 {render_with_line, getDim_render_with_line},
2279 {render_with_line, getDim_render_with_line},
2280 {render_with_line, getDim_render_with_line},
2281 {render_with_line, getDim_render_with_line}
2282 };
2283
2284 static void DrawFeatureAndLabel (
2285 RenderInputPtr RIP,
2286 ViewerContextPtr vContext
2287 )
2288
2289 {
2290 AppearanceItemPtr AIP;
2291 RelevantFeatureItemPtr RFIP;
2292 FilterItemPtr FIP;
2293 FilterPtr FP;
2294 CharPtr label;
2295 Char tempStringBuffer [256];
2296 Char shortLabel [41];
2297 Uint1 stringFlags;
2298 Uint4 textWidthBP;
2299 Int4 textStartX;
2300 Int4 textStartY;
2301 Uint1 labelAlign, fitChars;
2302 PrimitivE thisPrim;
2303 Boolean addType;
2304 Boolean addDesc;
2305
2306 FIP = RIP->FIP;
2307 RFIP = RIP->RFIP;
2308 AIP = RIP->AIP;
2309 FP = vContext->FltPtr;
2310 addType = AIP->AddTypeToLabel;
2311 addDesc = AIP->AddDescToLabel;
2312 if (FIP->AddTypeToLabel != TristateUnset) {
2313 addType = BOOL_FROM_SET_TRISTATE (FIP->AddTypeToLabel);
2314 }
2315 if (FIP->AddDescToLabel != TristateUnset) {
2316 addDesc = BOOL_FROM_SET_TRISTATE (FIP->AddDescToLabel);
2317 }
2318
2319 /* RIP->drawSeg = CreateSegment (RIP->drawSeg, 0, 0);*/
2320 /* Place each feature in its own segment. This is not necessary for simple features
2321 but perhaps the inefficiency is acceptable because it simplifies the algorithm. */
2322 (*RenderAlgorithmTable [AIP->RenderChoice].RenderFunc) (RIP, vContext);
2323 if (FIP->LabelLoc == LabelNone) return;
2324 if (vContext->viewScale > FP->MaxScaleWithLabels) return;
2325 stringFlags = 0;
2326 if (addDesc && RFIP->ContentLabel != NULL) {
2327 stringFlags |= 1;
2328 }
2329 if (addType) {
2330 stringFlags |= 2;
2331 }
2332 label = NULL;
2333 switch (stringFlags) {
2334 case 0: /* no label */
2335 return;
2336 case 1: /*comment but not type */
2337 label = RFIP->ContentLabel;
2338 break;
2339 case 2: /*only type */
2340 label = FindFeatStrFromFeatDefType (RFIP->featdeftype);
2341 break;
2342 case 3: /*add both */
2343 if (StringCmp (FindFeatStrFromFeatDefType (RFIP->featdeftype), RFIP->ContentLabel) != 0) {
2344 sprintf (tempStringBuffer, "%s: %s", FindFeatStrFromFeatDefType (RFIP->featdeftype), RFIP->ContentLabel);
2345 label = tempStringBuffer;
2346 } else {
2347 label = RFIP->ContentLabel;
2348 }
2349 break;
2350 }
2351 if (StringHasNoText (label)) return;
2352 LabelCopy (shortLabel, label, sizeof (shortLabel)-1);
2353 SelectFont (AIP->LabelFont);
2354 textWidthBP = StringWidth (shortLabel) * vContext->viewScale;
2355 switch (FIP->LabelLoc) {
2356 case LabelAboveClip:
2357 if (textWidthBP + 2 * vContext->viewScale >= (RFIP->Right - RFIP->Left)) {
2358 fitChars = Nlm_FitStringWidth (shortLabel, (RFIP->Right - RFIP->Left) / vContext->viewScale);
2359 if (fitChars <= 2 && StringLen (shortLabel) != fitChars) return;
2360 shortLabel [fitChars] = '>';
2361 shortLabel [fitChars + 1] = '\0';
2362 }
2363 textStartX = (RFIP->Left + RFIP->Right) / 2;
2364 /* textStartY = RIP->yStart - RIP->rowHeight / 2; -- change "labelInside" to mean "above, but not wider than"*/
2365 textStartY = RIP->yStart;
2366 labelAlign = LOWER_CENTER;
2367 break;
2368 case LabelInside:
2369 if (textWidthBP + 2 * vContext->viewScale >= (RFIP->Right - RFIP->Left)) {
2370 fitChars = Nlm_FitStringWidth (shortLabel, (RFIP->Right - RFIP->Left) / vContext->viewScale);
2371 shortLabel [fitChars + 1] = '\0';
2372 }
2373 textStartX = (RFIP->Left + RFIP->Right) / 2;
2374 textStartY = RIP->yStart - RIP->rowHeight / 2;
2375 labelAlign = MIDDLE_CENTER;
2376 break;
2377 case LabelAboveCull:
2378 if (textWidthBP + 2 * vContext->viewScale >= (RFIP->Right - RFIP->Left)) return;
2379 /* else fall through and display the label above */
2380 case LabelAbove:
2381 textStartX = (RFIP->Left + RFIP->Right) / 2;
2382 textStartY = RIP->yStart;
2383 labelAlign = LOWER_CENTER;
2384 break;
2385 case LabelBelow:
2386 textStartY = RIP->yStart - RIP->Height;
2387 textStartX = (RFIP->Left + RFIP->Right) / 2;
2388 labelAlign = LOWER_CENTER;
2389 break;
2390 case LabelLeft:
2391 textStartX = (RFIP->Left);
2392 textStartY = (RIP->yStart);
2393 labelAlign = LOWER_LEFT;
2394 break;
2395 case LabelRight:
2396 textStartX = (RFIP->Right);
2397 textStartY = (RIP->yStart);
2398 labelAlign = LOWER_RIGHT;
2399 break;
2400 default:
2401 return;
2402 }
2403 thisPrim = AddTextLabel (RIP->labelSeg, textStartX, textStartY, shortLabel, AIP->LabelFont, 1, labelAlign, 0);
2404 SetPrimitiveIDs (thisPrim, RFIP->entityID, RFIP->itemID, RFIP->itemType, 0);
2405 }
2406
2407 static RelevantFeatureItemPtr BuildClippedRFIP (
2408 RelevantFeatureItemPtr inputRFIP,
2409 FilterProcessStatePtr FPSP,
2410 ViewerContextPtr vContext
2411 )
2412
2413 {
2414 RelevantFeatureItemPtr newRFIP;
2415 ValNodePtr VNP = NULL;
2416 Uint2 i, newnumivals;
2417 Int4 from, to;
2418 Boolean useThis = TRUE, useLast;
2419 Boolean clippedLeft, clippedRight;
2420 Boolean lastClippedLeft, lastClippedRight;
2421
2422 if ((newRFIP = MemNew (sizeof (RelevantFeatureItem))) == NULL) return NULL;
2423 if ((VNP = MemNew (sizeof (ValNode))) == NULL) {
2424 MemFree (newRFIP);
2425 return NULL;
2426 }
2427 VNP->data.ptrvalue = newRFIP;
2428 VNP->next = FPSP->needFreeList;
2429 FPSP->needFreeList = VNP;
2430 MemCopy (newRFIP, inputRFIP, sizeof (RelevantFeatureItem));
2431 if ((inputRFIP->Left <= vContext->from && inputRFIP->Right <= vContext->from)
2432 || (inputRFIP->Left >= vContext->to && inputRFIP->Right >= vContext->to)) {
2433 return NULL; /* entire feature removed by clipping */
2434 }
2435 newRFIP->LeftEnd = (inputRFIP->Left >= vContext->from) ? inputRFIP->LeftEnd : EndPartial;
2436 newRFIP->RightEnd = (inputRFIP->Right <= vContext->to) ? inputRFIP->RightEnd : EndPartial;
2437 if (inputRFIP->numivals == 1) {
2438 newRFIP->Left = MAX (vContext->from, MIN (vContext->to, inputRFIP->Left ));
2439 newRFIP->Right = MAX (vContext->from, MIN (vContext->to, inputRFIP->Right));
2440 newRFIP->LeftEnd = (inputRFIP->Left >= vContext->from) ? inputRFIP->LeftEnd : EndPartial;
2441 newRFIP->RightEnd = (inputRFIP->Right <= vContext->to) ? inputRFIP->RightEnd : EndPartial;
2442 } else {
2443 newRFIP->Left = vContext->to;
2444 newRFIP->Right = vContext->from;
2445 newnumivals = 0;
2446 for (i = 0; i < inputRFIP->numivals; i++) {
2447 from = inputRFIP->ivals [2 * i];
2448 to = inputRFIP->ivals [2 * i + 1];
2449 if (from <= vContext->to && from >= vContext->from) {
2450 newnumivals ++;
2451 } else if (to <= vContext->to && to >= vContext->from) {
2452 newnumivals ++;
2453 }
2454 }
2455 newRFIP->numivals = newnumivals;
2456 if ((newRFIP->ivals = MemNew (2 * newnumivals * sizeof (Int4))) == NULL) return NULL;
2457 if ((VNP = MemNew (sizeof (ValNode))) == NULL) {
2458 MemFree (newRFIP->ivals);
2459 return NULL;
2460 }
2461 VNP->data.ptrvalue = newRFIP->ivals;
2462 VNP->next = FPSP->needFreeList;
2463 FPSP->needFreeList = VNP;
2464 newnumivals = 0;
2465 for (i = 0; i < inputRFIP->numivals; i++) {
2466 from = inputRFIP->ivals [2 * i];
2467 to = inputRFIP->ivals [2 * i + 1];
2468 if (from <= vContext->to && from >= vContext->from) {
2469 useThis = TRUE;
2470 clippedLeft = clippedRight = FALSE;
2471 } else if (to <= vContext->to && to >= vContext->from) {
2472 useThis = TRUE;
2473 clippedLeft = clippedRight = FALSE;
2474 } else {
2475 useThis = FALSE;
2476 clippedLeft = ((from + to) < (vContext->from + vContext->to));
2477 clippedRight = !clippedLeft;
2478 }
2479 if (i == 0) {
2480 useLast = useThis;
2481 lastClippedLeft = clippedLeft;
2482 lastClippedRight = clippedRight;
2483 }
2484 if (lastClippedLeft && useThis) {
2485 newRFIP->LeftEnd = EndClipped;
2486 } else if (lastClippedRight && useThis) {
2487 newRFIP->RightEnd = EndClipped;
2488 } else if (useLast && clippedLeft) {
2489 newRFIP->LeftEnd = EndClipped;
2490 } else if (useLast && clippedRight) {
2491 newRFIP->RightEnd = EndClipped;
2492 }
2493 if (useThis) {
2494 from = MAX (vContext->from, MIN (vContext->to, from));
2495 to = MAX (vContext->from, MIN (vContext->to, to ));
2496 newRFIP->Left = MIN (newRFIP->Left, from);
2497 newRFIP->Left = MIN (newRFIP->Left, to);
2498 newRFIP->Right = MAX (newRFIP->Right, to);
2499 newRFIP->Right = MAX (newRFIP->Right, from);
2500 newRFIP->ivals [newnumivals++] = from;
2501 newRFIP->ivals [newnumivals++] = to;
2502 }
2503 useLast = useThis;
2504 }
2505 }
2506 if (newRFIP->Left > newRFIP->Right) return NULL;
2507 return newRFIP;
2508 }
2509
2510
2511 static void GetFeatureAndDecorationDimensions (
2512 RenderInputPtr RIP,
2513 ViewerContextPtr vContext
2514 )
2515
2516 {
2517 AppearanceItemPtr AIP;
2518 RelevantFeatureItemPtr RFIP;
2519 FilterItemPtr FIP;
2520 FilterPtr FP;
2521 Int4 Start, Stop;
2522 Uint2 Height;
2523 Int2 lineHeight;
2524 Int4 textStartX;
2525 Uint4 textWidthBP;
2526 CharPtr label = NULL;
2527 Char tempStringBuffer [256];
2528 Uint1 stringFlags;
2529 Uint2 featureOffset = 0;
2530 Boolean addType;
2531 Boolean addDesc;
2532
2533 RFIP = RIP->RFIP;
2534 AIP = RIP->AIP;
2535 FIP = RIP->FIP;
2536 FP = vContext->FltPtr;
2537 addType = AIP->AddTypeToLabel;
2538 addDesc = AIP->AddDescToLabel;
2539 if (FIP->AddTypeToLabel != TristateUnset) {
2540 addType = BOOL_FROM_SET_TRISTATE (FIP->AddTypeToLabel);
2541 }
2542 if (FIP->AddDescToLabel != TristateUnset) {
2543 addDesc = BOOL_FROM_SET_TRISTATE (FIP->AddDescToLabel);
2544 }
2545
2546 (*RenderAlgorithmTable [AIP->RenderChoice].GetDimensions) (RIP, &Start, &Stop, &Height, vContext);
2547 RIP->Height = Height;
2548 RIP->decorationHeight = Height;
2549 RIP->decorationLeft = RFIP->Left;
2550 RIP->decorationRight = RFIP->Right;
2551 RIP->featureOffset = 0;
2552
2553 if (FIP->LabelLoc != LabelNone && vContext->viewScale <= FP->MaxScaleWithLabels) {
2554 stringFlags = 0;
2555 if (addDesc && RFIP->ContentLabel != NULL) {
2556 stringFlags |= 1;
2557 }
2558 if (addType) {
2559 stringFlags |= 2;
2560 }
2561
2562 switch (stringFlags) {
2563 case 0: /* no label */
2564 break;
2565 case 1: /*comment but not type */
2566 label = RFIP->ContentLabel;
2567 break;
2568 case 2: /*only type */
2569 label = FindFeatStrFromFeatDefType (RFIP->featdeftype);
2570 break;
2571 case 3: /*add both */
2572 if (StringCmp (FindFeatStrFromFeatDefType (RFIP->featdeftype), RFIP->ContentLabel) != 0) {
2573 sprintf (tempStringBuffer, "%s: %s", FindFeatStrFromFeatDefType (RFIP->featdeftype), RFIP->ContentLabel);
2574 label = tempStringBuffer;
2575 } else {
2576 label = RFIP->ContentLabel;
2577 }
2578 break;
2579 default:
2580 return;
2581 }
2582 }
2583 if (! StringHasNoText (label)) {
2584 SelectFont (AIP->LabelFont);
2585 textWidthBP = StringWidth (label) * vContext->viewScale;
2586 lineHeight = LineHeight ();
2587 switch (FIP->LabelLoc) {
2588 case LabelInside:
2589 Height = MAX (Height + lineHeight, Height);
2590 featureOffset = lineHeight + 1;
2591 break;
2592 case LabelAbove:
2593 textStartX = (Start + Stop) / 2;
2594 Start = MIN (Start, (signed)(textStartX - textWidthBP / 2));
2595 Stop = MAX (Stop, textStartX + textWidthBP / 2);
2596 featureOffset = lineHeight + 1;
2597 Height += lineHeight + 3;
2598 break;
2599 case LabelAboveClip:
2600 Height += lineHeight + 3;
2601 featureOffset = lineHeight + 1;
2602 case LabelAboveCull:
2603 if (textWidthBP + 2 * vContext->viewScale >= (Stop - Start)) {
2604 Height += lineHeight + 3;
2605 featureOffset = lineHeight + 1;
2606 }
2607 case LabelBelow:
2608 textStartX = (Start + Stop) / 2;
2609 Start = MIN (Start, (signed)(textStartX - textWidthBP / 2));
2610 Stop = MAX (Stop, textStartX + textWidthBP / 2);
2611 Height += lineHeight + 3;
2612 break;
2613 case LabelLeft:
2614 Start -= textWidthBP;
2615 Height = MAX (Height + lineHeight, Height);
2616 break;
2617 case LabelRight:
2618 Stop = RFIP->Right + textWidthBP;
2619 Height = MAX (Height + lineHeight, Height);
2620 break;
2621 default:
2622 return;
2623 }
2624 }
2625 RIP->decorationLeft = Start;
2626 RIP->decorationRight = Stop;
2627 RIP->decorationHeight = Height;
2628 RIP->featureOffset = featureOffset;
2629 }
2630
2631
2632 static Boolean BuildRenderInputFromRFIP (
2633 RenderInputPtr target,
2634 RelevantFeatureItemPtr RFIP,
2635 FilterProcessStatePtr FPSP
2636 )
2637
2638 {
2639 AppearancePtr AppPtr;
2640 FilterItemPtr currentFIP;
2641 ViewerContextPtr vContext;
2642 RelevantFeatureItemPtr newRFIP;
2643
2644 vContext = FPSP->vContext;
2645
2646 if (target == NULL || RFIP == NULL) return FALSE;
2647 if (!vContext->allFeatures &&
2648 (
2649 (RFIP->Left < vContext->from && RFIP->Right < vContext->from)
2650 || (RFIP->Left > vContext->to && RFIP->Right > vContext->to)
2651 )) {
2652 return FALSE; /* this feature is outside the clipping seqloc */
2653 }
2654 if (! vContext->allFeatures && (
2655 (RFIP->Right >= vContext->from || RFIP->Left <= vContext->to)
2656 || (RFIP->Right < vContext->from && RFIP->Left > vContext->to)
2657 )) {
2658 newRFIP = BuildClippedRFIP (RFIP, FPSP, vContext);
2659 if (newRFIP == NULL) return FALSE;
2660 RFIP = newRFIP;
2661 }
2662 target->RFIP = RFIP;
2663 target->labelSeg = FPSP->labelSegs [RFIP->featdeftype];
2664 target->drawSeg = FPSP->drawSegs [RFIP->featdeftype];
2665 AppPtr = vContext->AppPtr;
2666 currentFIP = FPSP->currentFIP;
2667 target->AIP = AppPtr->FeaturesAppearanceItem [RFIP->featdeftype];
2668 target->FIP = FPSP->currentFIP;
2669 GetFeatureAndDecorationDimensions (target, vContext);
2670 target->rowHeight = MAX (target->Height, target->decorationHeight) + currentFIP->IntraRowPaddingPixels;
2671 return TRUE;
2672 }
2673
2674 /* If this is a named Seq Annotation, return its name. Otherwise, return NULL */
2675 static CharPtr GetSeqAnnotName(SeqAnnotPtr sap)
2676 {
2677 if (sap != NULL && sap->desc != NULL)
2678 {
2679 AnnotDescrPtr descPtr;
2680 /* look for a 'title' record */
2681 for (descPtr = sap->desc; descPtr != NULL; descPtr = descPtr->next)
2682 {
2683 if (Annot_descr_title == descPtr->choice) /* title choice */
2684 return descPtr->data.ptrvalue;
2685 }
2686 /* then try for a 'name' record */
2687 for (descPtr = sap->desc; descPtr != NULL; descPtr = descPtr->next)
2688 {
2689 if (Annot_descr_name == descPtr->choice) /* name choice */
2690 return descPtr->data.ptrvalue;
2691 }
2692 /* if an alignment look for a Blast Type or a Hist Seqalign user object */
2693 if(sap->type ==2) /* not an alignment annotation */
2694 {
2695 UserObjectPtr uop;
2696 ObjectIdPtr oip;
2697 UserFieldPtr ufp;
2698
2699 for (descPtr = sap->desc; descPtr; descPtr = descPtr->next)
2700 {
2701 if (Annot_descr_user == descPtr->choice)
2702 {
2703
2704 for (uop = descPtr->data.ptrvalue; uop; uop = uop->next)
2705 {
2706 if (uop->type)
2707 {
2708 oip = uop->type;
2709
2710 if (StringCmp(oip->str, "Blast Type") == 0)
2711 {
2712 ufp = uop->data;
2713 if (ufp && ufp->choice == 2)
2714 {
2715 oip = ufp->label;
2716 if (oip && oip->str)
2717 {
2718 return oip->str;
2719 }
2720 }
2721 }
2722 }
2723 }
2724 }
2725 }
2726 for (descPtr = sap->desc; descPtr; descPtr = descPtr->next)
2727 {
2728 if (Annot_descr_user == descPtr->choice)
2729 {
2730
2731 for (uop = descPtr->data.ptrvalue; uop; uop = uop->next)
2732 {
2733 if (uop->type)
2734 {
2735 oip = uop->type;
2736
2737 if (StringCmp(oip->str, "Hist Seqalign") == 0)
2738 {
2739 ufp = uop->data;
2740 if (ufp && ufp->choice == 4 && ufp->data.boolvalue)
2741 {
2742 oip = ufp->label;
2743 if (oip && oip->str)
2744 {
2745 return oip->str;
2746 }
2747 }
2748 }
2749 }
2750 }
2751 }
2752 }
2753 }
2754 }
2755 return NULL;
2756 }
2757
2758 static Boolean GetAndCountFeatures (
2759 ViewerContextPtr vContext
2760 )
2761
2762 {
2763 SeqFeatPtr sfp;
2764 SeqMgrFeatContext fContext;
2765 RelevantFeatureItemPtr rFeats;
2766 ValNodePtr sapList = NULL, VNP, VNPtail;
2767 SeqAnnotPtr SAnnP;
2768 Uint2 i;
2769 Int4 swap;
2770
2771 if (vContext == NULL) return FALSE;
2772 vContext->sapCount = 0;
2773 vContext->featureCount = 0;
2774 vContext->featVNP = NULL;
2775 vContext->sapList = NULL;
2776
2777 /* create list of all named SeqAnnot's in this BioSeq. */
2778 for (SAnnP = vContext->BSP->annot; SAnnP != NULL; SAnnP = SAnnP->next)
2779 {
2780 if (GetSeqAnnotName(SAnnP)) {
2781 vContext->sapCount++;
2782 ValNodeAddPointer (&sapList, 0, SAnnP);
2783 }
2784 }
2785 if (vContext->sapCount > 0) {
2786 vContext->sapList = MemNew (vContext->sapCount * sizeof (SeqAnnotPtr));
2787 if (vContext->sapList == NULL) {
2788 ValNodeFree (sapList);
2789 return FALSE;
2790 }
2791 for (i = 0, VNP = sapList; VNP != NULL && i < vContext->sapCount; VNP = VNP->next, i++) {
2792 vContext->sapList[i] = VNP->data.ptrvalue;
2793 }
2794 ValNodeFree (sapList);
2795 }
2796
2797 rFeats = MemNew (RELEVANT_FEATS_PER_CHUNK * sizeof (RelevantFeatureItem));
2798 if (rFeats == NULL) return FALSE;
2799 ValNodeAddPointer (&vContext->featVNP, 0, rFeats);
2800 VNPtail = vContext->featVNP;
2801 i = 0;
2802 sfp = SeqMgrGetNextFeature (vContext->BSP, NULL, 0, 0, &fContext);
2803 while (sfp != NULL) {
2804 vContext->featureCount++;
2805
2806 rFeats [i].Left = fContext.left;
2807 rFeats [i].Right = fContext.right;
2808 rFeats [i].LeftEnd = fContext.partialL ? EndPartial : EndAbsolute;
2809 rFeats [i].RightEnd = fContext.partialR ? EndPartial : EndAbsolute;
2810 rFeats [i].ContentLabel = fContext.label;
2811 rFeats [i].featdeftype = fContext.featdeftype;
2812 rFeats [i].entityID = fContext.entityID;
2813 rFeats [i].itemID = fContext.itemID;
2814 rFeats [i].itemType = OBJ_SEQFEAT;
2815 rFeats [i].numivals = fContext.numivals;
2816 rFeats [i].ivals = fContext.ivals;
2817 rFeats [i].featstrand = fContext.strand;
2818 rFeats [i].circularSpanningOrigin = FALSE;
2819 if (rFeats [i].Left < 0 && fContext.bsp != NULL) {
2820 /* !!! for features that span origin JK !!! */
2821 rFeats [i].circularSpanningOrigin = TRUE;
2822 rFeats [i].Left = 0;
2823 rFeats [i].Right = fContext.bsp->length;
2824 }
2825 if (rFeats [i].Right < rFeats [i].Left) {
2826 /* protection against (feature indexing vs. trans-spliced features) */
2827 swap = rFeats [i].Right;
2828 rFeats [i].Right = rFeats [i].Left;
2829 rFeats [i].Left = swap;
2830 }
2831 /* with trans-spliced genes the left and right values might not span all the intervals. */
2832 /* we will fix that */
2833 {
2834 int ivali;
2835 Int4 val;
2836 for (ivali = 0; ivali < rFeats [i].numivals; ++ivali) {
2837 val = rFeats[i].ivals[2*ivali];
2838 rFeats[i].Left = MIN( rFeats[i].Left, val );
2839 rFeats[i].Right = MAX( rFeats[i].Right, val );
2840 val = rFeats[i].ivals[2*ivali+1];
2841 rFeats[i].Left = MIN( rFeats[i].Left, val );
2842 rFeats[i].Right = MAX( rFeats[i].Right, val );
2843 }
2844 }
2845 if (GetSeqAnnotName(fContext.sap)) { /* save this feature's Annot Ptr if it is a named Seq Annot. */
2846 rFeats [i].sap = fContext.sap;
2847 }
2848 else {
2849 rFeats [i].sap = NULL;
2850 }
2851 i++;
2852 if (i >= RELEVANT_FEATS_PER_CHUNK) {
2853 i = 0;
2854 rFeats = MemNew (RELEVANT_FEATS_PER_CHUNK * sizeof (RelevantFeatureItem));
2855 VNPtail = ValNodeNew (VNPtail);
2856 if (rFeats == NULL || VNPtail == NULL) {
2857 ValNodeFreeData (vContext->featVNP);
2858 MemFree (rFeats);
2859 return FALSE;
2860 }
2861 VNPtail->data.ptrvalue = rFeats;
2862 }
2863
2864 sfp = SeqMgrGetNextFeature (vContext->BSP, sfp, 0, 0, &fContext);
2865 }
2866 if (vContext->featureCount == 0) {
2867 MemFree (rFeats);
2868 MemFree (vContext->featVNP);
2869 vContext->featVNP = NULL;
2870 }
2871 return TRUE;
2872 }
2873
2874 NLM_EXTERN RelevantFeaturesPtr CollectFeatures (
2875 BioseqPtr bsp
2876 )
2877
2878 {
2879 RelevantFeaturesPtr RFP;
2880 ViewerContext VC;
2881
2882 RFP = MemNew (sizeof (RelevantFeatures));
2883 if (RFP == NULL) return NULL;
2884 VC.BSP = bsp;
2885 if (! GetAndCountFeatures (&VC)) return NULL;
2886 RFP->featureCount = VC.featureCount;
2887 RFP->featVNP = VC.featVNP;
2888 RFP->sapCount = VC.sapCount;
2889 RFP->sapList = VC.sapList;
2890 return RFP;
2891 }
2892
2893 static Boolean EnsureFeatureHasSegment (
2894 FilterProcessStatePtr FPSP,
2895 Uint1 featdeftype,
2896 SegmenT parentSegment
2897 )
2898
2899 {
2900 AppearancePtr AppPtr;
2901 AppearanceItemPtr AIP;
2902 ViewerContextPtr vContext;
2903
2904 vContext = FPSP->vContext;
2905
2906
2907 if (parentSegment == NULL) {
2908 parentSegment = vContext->drawOnMe;
2909 }
2910
2911 AppPtr = vContext->AppPtr;
2912 if (FPSP->drawSegs [featdeftype] == NULL) {
2913 FPSP->drawSegs [featdeftype] = CreateSegment (parentSegment, 0, 0);
2914 FPSP->labelSegs [featdeftype] = CreateSegment (parentSegment, 0, 0);
2915 /* cleaup needed if program is supposed to recover from this !!! */
2916 if (FPSP->drawSegs [featdeftype] == NULL || FPSP->labelSegs [featdeftype] == NULL) return FALSE;
2917 AIP = AppPtr->FeaturesAppearanceItem [featdeftype];
2918 AddAttribute (FPSP->drawSegs [featdeftype],
2919 COLOR_ATT | SHADING_ATT | STYLE_ATT | WIDTH_ATT,
2920 AIP->Color, AIP->VibLinestyle, AIP->VibShading, 1, 0);
2921 AddAttribute (FPSP->labelSegs [featdeftype], COLOR_ATT, AIP->LabelColor, 0, 0, 0, 0);
2922 }
2923 return TRUE;
2924 }
2925
2926 /*
2927 return a string describing the sequences in this alignment,
2928 concatenating strings from all the seqid's of the sequences in this alignment
2929 except for the one in 'notthisRow' which ordinarly will be the bioseq.
2930 */
2931
2932 static Boolean SeqAlignContentLabel(SeqAlignPtr sap, SeqIdPtr notThisSID, CharPtr buf, Int4 buflen, Uint1 format)
2933 {
2934 Int4 r, rows, slen;
2935 Char localbuf[100];
2936 SeqIdPtr sid;
2937 Char rowDelim[] = ",";
2938 Int4 rowDelimLen = sizeof(rowDelim) - 1;
2939 Boolean firstTime = TRUE;
2940
2941 if (sap == NULL || buf == NULL) return FALSE;
2942
2943 rows = AlnMgr2GetNumRows(sap);
2944 if (rows < 1)
2945 rows = sap->dim;
2946 if (rows < 1)
2947 return FALSE;
2948
2949 for (r = 1; r <= rows; ++r)
2950 {
2951 sid = AlnMgr2GetNthSeqIdPtr(sap, r);
2952 if (sid == NULL) {
2953 sid = AlnMgr2GetNthSeqIdPtrStdSeg(sap, r);
2954 }
2955 if (sid == NULL)
2956 continue;
2957 if (SeqIdIn(sid, notThisSID))
2958 continue;
2959
2960 SeqIdWrite (sid, localbuf, format, sizeof (localbuf) - 1);
2961 slen = StringLen(localbuf);
2962 if (slen < buflen - rowDelimLen - 1)
2963 {
2964 if (!firstTime) {
2965 StringNCat(buf, rowDelim, buflen);
2966 buflen -= sizeof(rowDelim) - 1;
2967 }
2968 firstTime = FALSE;
2969 StringNCat(buf, localbuf, buflen);
2970 buflen -= slen + 1;
2971 }
2972 }
2973
2974 if (StringLen(buf) <= 0)
2975 return FALSE;
2976 return TRUE;
2977 }
2978
2979 static void AccumIvals(Int1* accumulator, Int4 accumBegin, Int4 accumLen, RelevantFeatureItemPtr RFIP);
2980 Int4 CountIvals(Int1* accumulator, Int4 accumLen);
2981 void MakeIvals(Int1* accumulator, Int4 accumBegin, Int4 accumLen, Int4Ptr ivalsOut, Int4 ivalsLen);
2982
2983 static RelevantFeatureItemPtr GetNextRFIPinAlignmentFilter (
2984 FilterProcessStatePtr FPSP
2985 )
2986
2987 {
2988 AlignmentFilterStatePtr alignSP;
2989 SeqAlignSortInfoPtr alignSorted;
2990 SeqAlignPtr SAlnP;
2991 Int4 start, stop;
2992 Uint1 segType;
2993 Int4 nsegs, i;
2994 SeqIdPtr SID;
2995 BioseqPtr BSP;
2996 RelevantFeatureItem RFI; /* holder for intermediate values we will merge together */
2997 RelevantFeatureItemPtr finalRFIP; /* Our return value. */
2998 ViewerContextPtr vContext;
2999 FilterItemPtr currentFIP;
3000 AppearanceItemPtr AIP;
3001 Char labelbuf[150];
3002 Uint1 strand;
3003 AlignSegIterator asi;
3004 ValNodePtr vnp;
3005
3006 if (FPSP == NULL) return NULL;
3007 vContext = FPSP->vContext;
3008 currentFIP = FPSP->currentFIP;
3009 if (vContext == NULL || currentFIP == NULL) return NULL;
3010
3011 BSP = vContext->BSP;
3012 SID = BSP->id;
3013 AIP = vContext->AppPtr->FeaturesAppearanceItem[APPEARANCEITEM_Alignment];
3014
3015
3016 alignSP = &FPSP->state.align;
3017 alignSorted = alignSP->alignSorted;
3018
3019 SAlnP = alignSorted[alignSP->alignIndex].sap;
3020
3021 /* create new RFIP based on this SeqAlignPtr */
3022 finalRFIP = MemNew (sizeof (RelevantFeatureItem));
3023 if (finalRFIP == NULL) {
3024 MemFree (finalRFIP);
3025 return NULL;
3026 }
3027 vnp = ValNodeAddPointer (&FPSP->lastInFreeList, 0, finalRFIP);
3028 if (vnp == NULL) {
3029 MemFree (finalRFIP);
3030 return NULL;
3031 }
3032 if (FPSP->needFreeList == NULL) {
3033 FPSP->needFreeList = FPSP->lastInFreeList;
3034 }
3035 FPSP->lastInFreeList = vnp;
3036
3037 /* where does this alignment start & stop in bioseq coords? */
3038 nsegs = AlignSegIteratorCreate(SAlnP, SID, &asi);
3039 strand = asi.strand;
3040 if (strand == Seq_strand_unknown)
3041 strand = Seq_strand_plus;
3042
3043 if (asi.start < 0 || asi.stop < 0)
3044 return NULL;
3045 finalRFIP->Left = asi.start;
3046 finalRFIP->Right = asi.stop;
3047 finalRFIP->featstrand = strand;
3048 finalRFIP->numivals = 1;
3049 finalRFIP->ivals = NULL;
3050 finalRFIP->featdeftype = APPEARANCEITEM_Alignment;
3051 finalRFIP->circularSpanningOrigin = FALSE;
3052 finalRFIP->entityID = SAlnP->idx.entityID;
3053 finalRFIP->itemID = SAlnP->idx.itemID;
3054 finalRFIP->itemType = SAlnP->idx.itemtype;
3055 labelbuf[0] = 0;
3056 if (SeqAlignContentLabel(SAlnP, SID, labelbuf, sizeof(labelbuf) - 1, AIP->format))
3057 {
3058 finalRFIP->ContentLabel = StringSave(labelbuf);
3059 }
3060
3061 if (nsegs > 1) {
3062 finalRFIP->ivals = MemNew (2 * nsegs * sizeof (Int4));
3063 if (finalRFIP->ivals == NULL)
3064 {
3065 MemFree(finalRFIP->ContentLabel);
3066 return NULL;
3067 } else {
3068 finalRFIP->numivals = 0;
3069 i = 0;
3070 while (AlignSegIteratorNext(&asi, &start, &stop, NULL, &segType))
3071 {
3072 /* ignore gaps on the bioseq */
3073 /* hence we may have less than nsegs ivals */
3074 if (segType == AM_GAP)
3075 continue;
3076
3077 if (segType == AM_INSERT) {
3078 if (i == 0)
3079 start = stop = finalRFIP->Left;
3080 else
3081 start = stop = finalRFIP->ivals[i - 1];
3082 }
3083 finalRFIP->ivals[i++] = start;
3084 finalRFIP->ivals[i++] = stop;
3085 finalRFIP->numivals++;
3086 }
3087 }
3088 }
3089
3090 ++alignSP->alignIndex;
3091 /*
3092 if we are not done with all the alignments and
3093 the next alignment(s) has the same accession and strand as this one does
3094 merge their segments together.
3095 */
3096 if (! AlignmentFilterStateDone(alignSP) &&
3097 alignSorted[alignSP->alignIndex - 1].strand == alignSorted[alignSP->alignIndex].strand &&
3098 StrNCmp(alignSorted[alignSP->alignIndex - 1].label,
3099 alignSorted[alignSP->alignIndex].label, MAX_ALIGN_SORT_LABEL) == 0) {
3100 Int4 *newIvals; /* pointer to merged ivals */
3101 Int4 newIvalsNum;
3102 Int1 *accumulator;
3103 Int4 accumBegin, accumEnd, accumLen;
3104
3105 /* keep track of where the segments fall in this array */
3106 /* 0 - a gap. 1 - a segment. 2 - an insert */
3107 accumBegin = finalRFIP->Left;
3108 accumEnd = vContext->seqLength;
3109 accumLen = accumEnd - accumBegin;
3110 accumulator = MemNew( accumLen * sizeof(Int1) );
3111 if (accumulator == NULL) {
3112 return NULL;
3113 }
3114
3115 AccumIvals(accumulator, accumBegin, accumLen, finalRFIP);
3116 for ( ;
3117 ! AlignmentFilterStateDone(alignSP) &&
3118 alignSorted[alignSP->alignIndex - 1].strand == alignSorted[alignSP->alignIndex].strand &&
3119 StrNCmp(alignSorted[alignSP->alignIndex - 1].label,
3120 alignSorted[alignSP->alignIndex].label, MAX_ALIGN_SORT_LABEL) == 0;
3121 ++alignSP->alignIndex ) {
3122
3123 SAlnP = alignSorted[alignSP->alignIndex].sap;
3124
3125 /* where does this alignment start & stop in bioseq coords? */
3126 nsegs = AlignSegIteratorCreate(SAlnP, SID, &asi);
3127
3128 if (asi.start < 0 || asi.stop < 0)
3129 continue;
3130 RFI.Left = asi.start;
3131 finalRFIP->Left = MIN(finalRFIP->Left, RFI.Left);
3132 RFI.Right = asi.stop;
3133 finalRFIP->Right = MAX(finalRFIP->Right, RFI.Right);
3134 RFI.numivals = 1;
3135 RFI.ivals = NULL;
3136
3137 #ifdef _DEBUG
3138 if (finalRFIP->Right > vContext->seqLength) {
3139 printf("finalRFIP->Right too big: %d\n", finalRFIP->Right); /* put a breakpoint here! */
3140 return NULL;
3141 }
3142 #endif
3143
3144 if (nsegs > 1) {
3145 RFI.ivals = MemNew (2 * nsegs * sizeof (Int4));
3146 if (RFI.ivals == NULL)
3147 {
3148 MemFree(RFI.ivals);
3149 } else {
3150 RFI.numivals = 0;
3151 i = 0;
3152 while (AlignSegIteratorNext(&asi, &start, &stop, NULL, &segType))
3153 {
3154 /* ignore gaps on the bioseq */
3155 /* hence we may have less than nsegs ivals */
3156 if (segType == AM_GAP)
3157 continue;
3158
3159 if (segType == AM_INSERT) {
3160 if (i == 0)
3161 start = stop = RFI.Left;
3162 else
3163 start = stop = RFI.ivals[i - 1];
3164 }
3165 RFI.ivals[i++] = start;
3166 RFI.ivals[i++] = stop;
3167 RFI.numivals++;
3168 }
3169 }
3170 }
3171 AccumIvals(accumulator, accumBegin, accumLen, &RFI);
3172 if (RFI.ivals != NULL)
3173 MemFree(RFI.ivals);
3174 }
3175 newIvalsNum = CountIvals(accumulator, accumLen);
3176 newIvals = MemNew( 2 * newIvalsNum * sizeof(Int4) );
3177 if (newIvals == NULL) {
3178 MemFree(accumulator);
3179 return NULL;
3180 }
3181 MakeIvals(accumulator, accumBegin, accumLen, newIvals, newIvalsNum);
3182 MemFree(accumulator);
3183
3184 if (finalRFIP->ivals != NULL)
3185 MemFree(finalRFIP->ivals);
3186 finalRFIP->numivals = newIvalsNum;
3187
3188 if (newIvalsNum > 1) {
3189 finalRFIP->ivals = newIvals;
3190 } else {
3191 MemFree(newIvals);
3192 finalRFIP->ivals = NULL;
3193 }
3194 }
3195
3196 /* remember to delete the final ivals array & label space */
3197 if (finalRFIP->numivals > 1)
3198 {
3199 vnp = ValNodeAddPointer(&FPSP->lastInFreeList, 0, finalRFIP->ivals);
3200 if (vnp == NULL) {
3201 MemFree(finalRFIP->ContentLabel);
3202 MemFree(finalRFIP->ivals);
3203 return NULL;
3204 }
3205 if (FPSP->needFreeList == NULL) {
3206 FPSP->needFreeList = FPSP->lastInFreeList;
3207 }
3208 FPSP->lastInFreeList = vnp;
3209 }
3210 vnp = ValNodeAddPointer(&FPSP->lastInFreeList, 0, finalRFIP->ContentLabel);
3211 if (vnp == NULL)
3212 {
3213 MemFree(finalRFIP->ContentLabel);
3214 return NULL;
3215 }
3216 if (FPSP->needFreeList == NULL) {
3217 FPSP->needFreeList = FPSP->lastInFreeList;
3218 }
3219 FPSP->lastInFreeList = vnp;
3220
3221 return finalRFIP;
3222 }
3223
3224
3225 void AccumIvals(Int1* accumulator, Int4 accumBegin, Int4 accumLen, RelevantFeatureItemPtr RFIP)
3226 {
3227 Int4 i, ai;
3228 Int4 blockstart, blockend;
3229
3230 /* mark everywhere segments spans. 0 in gaps, 1 in blocks, 2 at inserts */
3231 if (RFIP->numivals == 1) {
3232 blockstart = RFIP->Left - accumBegin;
3233 blockend = RFIP->Right - accumBegin;
3234
3235 for (ai = blockstart; ai <= blockend; ++ai)
3236 if (accumulator[ai] == 0)
3237 accumulator[ai] = 1;
3238 }
3239 else {
3240 for (i = 0; i < RFIP->numivals; ++i) {
3241 blockstart = RFIP->ivals[2*i] - accumBegin;
3242 blockend = RFIP->ivals[2*i + 1] - accumBegin;
3243
3244 #ifdef _DEBUG
3245 if (blockstart < 0 || accumLen < blockstart || blockend < 0 || accumLen < blockend) {
3246 printf("AccumIvals problem!"); /* put a breakpoint here! */
3247 return;
3248 }
3249 #endif
3250 if (blockstart == blockend) {
3251 accumulator[blockstart] = 2;
3252 } else {
3253 for (ai = blockstart; ai <= blockend; ++ai)
3254 if (accumulator[ai] == 0)
3255 accumulator[ai] = 1;
3256 }
3257 }
3258 }
3259 }
3260
3261 Int4 CountIvals(Int1* accumulator, Int4 accumLen)
3262 {
3263 Int4 numivalsOut;
3264 Int4 ai;
3265
3266 /* make new ivals */
3267 numivalsOut = 0;
3268
3269 for (ai = 0; ai < accumLen; ++ai) {
3270 if (accumulator[ai] == 0)
3271 continue;
3272 /* if it is an insert, add it */
3273 if (accumulator[ai] == 2) {
3274 ++numivalsOut;
3275 } else if (accumulator[ai] == 1) { /* beginning of a block */
3276 /* find end of block */
3277 for (; ai < accumLen; ++ai) {
3278 if (accumulator[ai] != 1)
3279 break;
3280 }
3281 --ai;
3282 ++numivalsOut;
3283 }
3284 }
3285 return numivalsOut;
3286 }
3287
3288 void MakeIvals(Int1* accumulator, Int4 accumBegin, Int4 accumLen, Int4Ptr ivalsOut, Int4 ivalsLen)
3289 {
3290 Int4 numivalsOut;
3291 Int4 ai, blocklen;
3292
3293 /* make new ivals */
3294 numivalsOut = 0;
3295
3296 for (ai = 0; ai < accumLen && numivalsOut < ivalsLen; ++ai) {
3297 /* ignore spots in gaps. */
3298 if (accumulator[ai] == 0)
3299 continue;
3300 /* if it is an insert, add it */
3301 if (accumulator[ai] == 2) {
3302 ivalsOut[numivalsOut * 2] = accumBegin + ai;
3303 ivalsOut[numivalsOut * 2 + 1] = accumBegin + ai;
3304 ++numivalsOut;
3305 } else if (accumulator[ai] == 1) { /* beginning of a block */
3306 /* find end of block */
3307 for (blocklen = 0; ai + blocklen < accumLen; ++blocklen) {
3308 if (accumulator[ai + blocklen] != 1)
3309 break;
3310 }
3311 ivalsOut[numivalsOut * 2] = accumBegin + ai;
3312 if (accumulator[ai + blocklen] == 2)
3313 ivalsOut[numivalsOut * 2 + 1] = accumBegin + ai + blocklen;
3314 else
3315 ivalsOut[numivalsOut * 2 + 1] = accumBegin + ai + blocklen - 1;
3316 ++numivalsOut;
3317 ai += blocklen - 1;
3318 }
3319 }
3320 }
3321
3322 /*
3323 For a given SeqAlign and a given SeqId for a Seq that participates in that SeqAlign,
3324 keep track of where we are in that alignment so we can iterate through all of that
3325 alignment's segments, returning information about each segment.
3326 Hides the differences between normal/indexable and StdSeg alignments.
3327 */
3328
3329 /*
3330 Create an structure to iterate through all of an alignment's segments.
3331 return a pointer to that iterator struct that must be deallocated.
3332 return the number of segments.
3333 */
3334 static
3335 Int4 AlignSegIteratorCreate(SeqAlignPtr sap, SeqIdPtr sip, AlignSegIteratorPtr asip)
3336 {
3337 Boolean stdSeg;
3338 Int4 swap;
3339
3340 if (sap == NULL || sip == NULL || asip == NULL)
3341 return 0;
3342
3343 AlnMgr2IndexSingleChildSeqAlign(sap);
3344 asip->sap = sap;
3345 asip->sip = sip;
3346
3347 stdSeg = (sap->segtype == SAS_STD);
3348 if ( ! stdSeg) {
3349 asip->nsegs = AlnMgr2GetNumSegs(sap);
3350 asip->alignRow = AlnMgr2GetFirstNForSipList (sap, sip);
3351 if (asip->alignRow == -1) {
3352 return 0;
3353 }
3354 AlnMgr2GetNthSeqRangeInSA(sap, asip->alignRow, &asip->start, &asip->stop);
3355 asip->strand = AlnMgr2GetNthStrand(sap, asip->alignRow);
3356 }
3357 else {
3358 asip->nsegs = AlnMgr2GetNumStdSegs(sap);
3359 asip->alignRow = 0;
3360 AlnMgr2GetSeqRangeForSipInSAStdSeg(sap, sip, &asip->start, &asip->stop, &asip->strand);
3361 }
3362
3363 if (asip->stop < asip->start) {
3364 swap = asip->stop;
3365 asip->stop = asip->start;
3366 asip->start = swap;
3367 }
3368
3369 asip->currentStdSeg = NULL;
3370 asip->currentSeg = 0;
3371
3372 return asip->nsegs;
3373 }
3374
3375 /*
3376 Given an AlignSegIterator return the information about the current segment
3377 in the pointer arguments, and advance the iterator to the next segment.
3378 Return false if there are no more segments in which case the output arguments
3379 will not be changed.
3380 */
3381 static
3382 Boolean AlignSegIteratorNext(
3383 AlignSegIteratorPtr asip,
3384 Int4Ptr startOut,
3385 Int4Ptr stopOut,
3386 Uint1Ptr strandOut,
3387 Uint1Ptr segTypeOut
3388 )
3389 {
3390 Int4 start, stop, swap;
3391 Uint1 strand, segType;
3392 Boolean stdSeg;
3393 Int4 iseg;
3394
3395
3396 if (asip == NULL)
3397 return FALSE; /* bad argument */
3398
3399 /* iterate */
3400 asip->currentSeg++;
3401 if (asip->currentSeg > asip->nsegs) /* no more segments */
3402 return FALSE;
3403
3404 if (asip->strand == Seq_strand_minus)
3405 iseg = asip->nsegs - asip->currentSeg + 1;
3406 else
3407 iseg = asip->currentSeg;
3408
3409 stdSeg = (asip->sap->segtype == SAS_STD);
3410 if ( ! stdSeg) {
3411 Int4 alignStart, alignStop;
3412 Int4 row2, seq2Start;
3413
3414 strand = asip->strand; /* all segments have the same strand */
3415 /* get segment location in alignment coordinates */
3416 AlnMgr2GetNthSegmentRange(asip->sap, iseg, &alignStart, &alignStop);
3417 /* convert to bioseq coordinates */
3418 start = AlnMgr2MapSeqAlignToBioseq(asip->sap, alignStart, asip->alignRow);
3419 if (alignStart != alignStop)
3420 stop = AlnMgr2MapSeqAlignToBioseq(asip->sap, alignStop , asip->alignRow);
3421 else
3422 stop = start;
3423
3424 /* Is this a insert (a gap on the bioseq)? */
3425 if (start == -2) {
3426 segType = AM_INSERT;
3427 } else {
3428 /* check the other sequence to see if there is a gap there. */
3429 if (asip->alignRow == 1)
3430 row2 = 2;
3431 else
3432 row2 = 1;
3433 seq2Start = AlnMgr2MapSeqAlignToBioseq(asip->sap, alignStart, row2);
3434
3435 if (seq2Start == -2 )
3436 segType = AM_GAP;
3437 else
3438 segType = AM_SEQ;
3439 }
3440 }
3441 else { /* stdSeg */
3442 asip->currentStdSeg = AlnMgr2GetNthStdSeg(asip->sap, iseg);
3443 if (asip->currentStdSeg == NULL)
3444 return FALSE; /* Logic Error. should not happen. */
3445
3446 AlnMgr2GetSeqRangeForSipInStdSeg(asip->currentStdSeg, asip->sip, &start, &stop, &strand, &segType);
3447 }
3448 if (stop < start) {
3449 swap = start;
3450 start = stop;
3451 stop = swap;
3452 }
3453
3454 /* take care of output arguments */
3455 if (startOut) *startOut = start;
3456 if (stopOut) *stopOut = stop;
3457 if (strandOut) *strandOut = strand;
3458 if (segTypeOut) *segTypeOut = segType;
3459
3460 return TRUE;
3461 }
3462
3463
3464 static RelevantFeatureItemPtr GetNextRFIPinFeatureFilter (
3465 FilterProcessStatePtr FPSP
3466 )
3467
3468 {
3469 ValNodePtr currentRFIPblockVNP;
3470 FeatureFilterStatePtr featSP;
3471 RelevantFeatureItemPtr RFIP = NULL;
3472 ViewerContextPtr vContext;
3473 FilterItemPtr currentFIP;
3474 FilterPtr FP;
3475
3476 if (FPSP == NULL) return NULL;
3477 vContext = FPSP->vContext;
3478 currentFIP = FPSP->currentFIP;
3479 if (vContext == NULL || currentFIP == NULL) return NULL;
3480 FP = vContext->FltPtr;
3481 if (FP == NULL) return NULL;
3482
3483 featSP = &FPSP->state.feat;
3484 for (; featSP->featureBlockOffset + featSP->indexInBlock < vContext->featureCount; featSP->indexInBlock++) {
3485 if (featSP->indexInBlock >= RELEVANT_FEATS_PER_CHUNK) {
3486 featSP->indexInBlock = 0;
3487 featSP->featureBlockOffset += RELEVANT_FEATS_PER_CHUNK;
3488 featSP->currentRFIPblockVNP = featSP->currentRFIPblockVNP->next;
3489 if (featSP->currentRFIPblockVNP == NULL) return NULL;
3490 }
3491 currentRFIPblockVNP = featSP->currentRFIPblockVNP;
3492 RFIP = (RelevantFeatureItemPtr) (currentRFIPblockVNP->data.ptrvalue) + featSP->indexInBlock;
3493
3494 if (FP->GroupByAnnot && RFIP->sap != vContext->currentSAP) continue;
3495
3496 if (! vContext->allFeatures
3497 && (RFIP->Right < vContext->from || RFIP->Left > vContext->to)) {
3498 continue;
3499 }
3500 if (FPSP->featuresProcessed [featSP->featureBlockOffset + featSP->indexInBlock]
3501 || (! currentFIP->IncludeFeature [RFIP->featdeftype])) continue;
3502 if (currentFIP->MatchStrand != BothStrands) {
3503 if (currentFIP->MatchStrand == MinusStrand && RFIP->featstrand != Seq_strand_minus) continue;
3504 if (currentFIP->MatchStrand == PlusStrand && RFIP->featstrand != Seq_strand_plus) continue;
3505 }
3506 FPSP->featuresProcessed [featSP->featureBlockOffset + featSP->indexInBlock] = TRUE;
3507 break;
3508 }
3509 if (featSP->featureBlockOffset + featSP->indexInBlock >= vContext->featureCount) return NULL;
3510 return RFIP;
3511 }
3512
3513
3514
3515 static RelevantFeatureItemPtr GetNextRFIPinFilterItem (
3516 FilterProcessStatePtr FPSP
3517 )
3518
3519 {
3520 AlignmentFilterStatePtr alignSP;
3521 RelevantFeatureItemPtr RFIP = NULL;
3522 ViewerContextPtr vContext;
3523 FilterItemPtr currentFIP;
3524
3525 /* called as an iterator by the rendering functions -- builds & returns the next feature (in an RFIP), or returns NULL if no more left in this Filter */
3526 if (FPSP == NULL) return NULL;
3527 vContext = FPSP->vContext;
3528 currentFIP = FPSP->currentFIP;
3529 if (vContext == NULL || currentFIP == NULL) return NULL;
3530 switch (currentFIP->Type) {
3531 case InvalidFilter:
3532 case GraphFilter:
3533 case BioseqFilter:
3534 return NULL;
3535 case AlignmentFilter:
3536 alignSP = &FPSP->state.align;
3537 while (!AlignmentFilterStateDone(alignSP)) {
3538 RFIP = GetNextRFIPinAlignmentFilter (FPSP);
3539 if (RFIP != NULL)
3540 return RFIP;
3541 }
3542 /* note: if control reaches here, then RFIP == NULL */
3543 break;
3544 case FeatureFilter:
3545 RFIP = GetNextRFIPinFeatureFilter (FPSP);
3546 break;
3547 }
3548 if (RFIP != NULL) {
3549 FPSP->featuresProcessedCount++;
3550 }
3551 return RFIP;
3552 }
3553
3554 static Boolean AddFeatureToRow (
3555 InternalRowPtr row,
3556 RelevantFeatureItemPtr RFIP,
3557 Boolean SkipSmearTest,
3558 FilterProcessStatePtr FPSP
3559 )
3560
3561 {
3562 ValNodePtr VNP;
3563 RelevantFeatureItemPtr newRFIP; /* for representing a multi-feature smear */
3564 RelevantFeatureItemPtr oldRFIP;
3565 ViewerContextPtr vContext;
3566
3567 vContext = FPSP->vContext;
3568
3569 if (row == NULL || RFIP == NULL) return FALSE;
3570
3571 if (!SkipSmearTest && row->rowFeatureCount &&
3572 TestForSmear (RFIP, (RelevantFeatureItemPtr) row->feats->data.ptrvalue, vContext->viewScale)) {
3573 /* if the last feature was not a smear-in-progress, allocate newRFIP, else re-use the current one */
3574 oldRFIP = (RelevantFeatureItemPtr) row->feats->data.ptrvalue;
3575 if (oldRFIP->entityID == 0 && oldRFIP->itemID == 0) {
3576 /* oldRFIP is already a smear-in-prorgess, just extend it */
3577 newRFIP = oldRFIP;
3578 } else {
3579 /* need to create a new smear */
3580 newRFIP = MemNew (sizeof (RelevantFeatureItem));
3581 VNP = MemNew (sizeof (ValNode));
3582 if (newRFIP == NULL || VNP == NULL) return FALSE;
3583 VNP->data.ptrvalue = newRFIP;
3584 VNP->next = FPSP->needFreeList;
3585 FPSP->needFreeList = VNP;
3586 row->feats->data.ptrvalue = newRFIP;
3587 newRFIP->featdeftype = oldRFIP->featdeftype;
3588 newRFIP->numivals = 1;
3589 }
3590
3591 newRFIP->Left = MIN (oldRFIP->Left, RFIP->Left);
3592 newRFIP->Right = MAX (oldRFIP->Right, RFIP->Right);
3593 } else {
3594
3595 VNP = MemNew (sizeof (ValNode));
3596 if (VNP == NULL) return FALSE;
3597 VNP->data.ptrvalue = RFIP;
3598 VNP->next = row->feats;
3599 row->feats = VNP;
3600 row->rowFeatureCount++;
3601 }
3602 return TRUE;
3603 }
3604
3605 static InternalRowPtr AddARow (
3606 InternalRowPtr sourceRow
3607 )
3608
3609 {
3610 InternalRowPtr IRP;
3611
3612 if (sourceRow == NULL) return NULL;
3613 IRP = MemNew (sizeof (InternalRow));
3614 if (IRP == NULL) return NULL;
3615 sourceRow->next = IRP;
3616 return IRP;
3617 }
3618
3619 static Uint2 SimpleDiagonalLayout (
3620 InternalRowPtr firstRow,
3621 FilterProcessStatePtr FPSP
3622 )
3623
3624 {
3625 Uint2 rows = 0;
3626 InternalRowPtr thisRow;
3627 RelevantFeatureItemPtr RFIP;
3628
3629 thisRow = firstRow;
3630 if (thisRow == NULL) return 0;
3631 thisRow->rowFeatureCount = 0;
3632 while ((RFIP = GetNextRFIPinFilterItem (FPSP)) != NULL) {
3633 AddFeatureToRow (thisRow, RFIP, TRUE, FPSP);
3634 thisRow = AddARow (thisRow);
3635 rows++;
3636 }
3637 return rows;
3638 }
3639
3640 /* this was copied from seqmgr.c (6.181, 27-feb-2002) */
3641 static Boolean CheckInternalExonBoundaries (Int2 numivalsCDS, Int4Ptr ivalsCDS, Int2 numivalsMRNA, Int4Ptr ivalsMRNA)
3642
3643 {
3644 Int2 i;
3645 Int2 j;
3646
3647 if (numivalsCDS > numivalsMRNA) return FALSE;
3648 if (ivalsCDS == NULL || ivalsMRNA == NULL) return TRUE;
3649
3650 /* scan first exon-intron boundary against candidate start positions */
3651
3652 for (i = 0; i <= numivalsMRNA - numivalsCDS; i++) {
3653 if (ivalsCDS [1] == ivalsMRNA [2 * i + 1]) break;
3654 }
3655 if (i > numivalsMRNA - numivalsCDS) return FALSE;
3656
3657 /* Addition by Eric: the first interval in the CDS must not be larger than the corresponding interval in the mRNA */
3658 if (ABS (ivalsCDS [0] - ivalsCDS [1]) > ABS (ivalsMRNA [2 * i] - ivalsMRNA [2 * i + 1])) return FALSE;
3659
3660 /* scan subsequent exon-intron and intron-exon boundaries */
3661
3662 for (j = 2; j <= 2 * numivalsCDS - 2; j++) {
3663 if (ivalsCDS [j] != ivalsMRNA [2 * i + j]) return FALSE;
3664 }
3665
3666 /* Addition by Eric: the last interval in the CDS must not be larger than the corresponding interval in the mRNA */
3667 if (ABS (ivalsCDS [j - 1] - ivalsCDS [j]) > ABS (ivalsMRNA [2 * i + j - 1] - ivalsMRNA [2 * i + j])) return FALSE;
3668
3669 return TRUE;
3670 }
3671
3672 static Boolean mRNAmatchesCDS (
3673 RelevantFeatureItemPtr mRNA,
3674 RelevantFeatureItemPtr CDS
3675 )
3676
3677 {
3678 /* the mRNA must be the larger feature */
3679 if (CDS->Left < mRNA->Left || CDS->Right > mRNA->Right) return FALSE;
3680 /* check strands (anything not equal to strand minus is equal to each other) */
3681 if (CDS->featstrand != mRNA->featstrand &&
3682 (CDS->featstrand == Seq_strand_minus || mRNA->featstrand == Seq_strand_minus))
3683 return FALSE;
3684 /* trivial case */
3685 if (CDS->numivals == 1 && mRNA->numivals == 1) return TRUE;
3686 /* . . . and the intervals must line up */
3687 return CheckInternalExonBoundaries (CDS->numivals, CDS->ivals, mRNA->numivals, mRNA->ivals);
3688 }
3689
3690 typedef struct rFIPentry {
3691 RelevantFeatureItemPtr RFIP;
3692 Int4 decorationLeft;
3693 Int4 decorationRight;
3694 Int4 Right;
3695 Int4 Left;
3696 Boolean used;
3697 } RFIPentry, PNTR RFIPentryPtr;
3698
3699 typedef struct rFIPgroup {
3700 Uint4 memberCount;
3701 Int4 decorationLeft;
3702 Int4 decorationRight;
3703 Int4 Left;
3704 Int4 Right;
3705 ValNodePtr members; /* data.ptrvalue = RFIPentryPtr */
3706 } RFIPgroup, PNTR RFIPgroupPtr;
3707
3708
3709 static Uint2 GeneProductsLayoutInternal (
3710 InternalRowPtr firstRow,
3711 FilterProcessStatePtr FPSP,
3712 Boolean MultiRender
3713 )
3714
3715 {
3716 Uint2 rows = 1, i;
3717 RelevantFeatureItemPtr RFIP, RFIPcds, RFIPmrna, tRFIP;
3718 InternalRowPtr thisRow, thisRow2, lastRow;
3719 ValNodePtr fifoHead = NULL, fifoTail = NULL;
3720 ValNodePtr bumpedListHead = NULL, bumpedListTail = NULL;
3721 ValNodePtr potCDSvnp, potRNAvnp;
3722 ValNodePtr GroupsHead = NULL, GroupsTailVNP, MemberTailVNP;
3723 ValNodePtr groupVNP, featVNP;
3724 RFIPentryPtr tRFIPentry;
3725 RFIPentryPtr bumpedListEntry;
3726 RFIPentryPtr potCDS, potRNA, GroupsTailMemberTail;
3727 Uint2 bumpedCount;
3728 Boolean foundRows, doneCollecting = FALSE;
3729 Int4 newLeft, featureStart, rowMaxRight;
3730 RenderInput dummyRI;
3731 RFIPgroupPtr currentGroup;
3732 Uint4 viewScale;
3733
3734 viewScale = FPSP->vContext->viewScale;
3735
3736 if (firstRow == NULL) return 0;
3737
3738 lastRow = firstRow;
3739 firstRow->layoutData.intvalue = -2000000000; /* the first feature will _always_ fit in the first row */
3740
3741 while (1) {
3742 if (doneCollecting) {
3743 break;
3744 }
3745 RFIP = GetNextRFIPinFilterItem (FPSP);
3746 if (RFIP == NULL) {
3747 doneCollecting = TRUE;
3748 bumpedListHead = fifoHead; /* no more incoming features, bump all features in the queue*/
3749 bumpedListTail = fifoTail;
3750 fifoHead = NULL;
3751 } else {
3752 if (! BuildRenderInputFromRFIP (&dummyRI, RFIP, FPSP)) {
3753 continue; /* either we're out of memory or this feature doesn't overlap the clipping SeqLoc */
3754 }
3755
3756 if ((tRFIPentry = MemNew (sizeof (RFIPentry))) == NULL) goto bail_out;
3757 if (fifoHead == NULL) {
3758 fifoTail = ValNodeAddPointer (&fifoHead, 0, tRFIPentry);
3759 } else {
3760 fifoTail = ValNodeAddPointer (&fifoTail, 0, tRFIPentry);
3761 }
3762 if (fifoTail == NULL) goto bail_out;
3763 tRFIPentry->RFIP = RFIP;
3764 tRFIPentry->Left = RFIP->Left;
3765 tRFIPentry->Right = RFIP->Right;
3766 tRFIPentry->decorationLeft = dummyRI.decorationLeft;
3767 tRFIPentry->decorationRight = dummyRI.decorationRight;
3768
3769 /*
3770 now find all features which can not overlap the next feature (in the sequence; decoration overlap doesn't matter)
3771 */
3772 newLeft = RFIP->Left;
3773
3774 bumpedCount = 0;
3775 bumpedListHead = fifoHead;
3776 for (featVNP = fifoHead;
3777 featVNP != NULL;
3778 featVNP = featVNP->next) {
3779 bumpedListEntry = featVNP->data.ptrvalue;
3780 RFIP = bumpedListEntry->RFIP;
3781 if (RFIP->Right > newLeft) break;
3782 bumpedListTail = featVNP;
3783 fifoHead = featVNP->next;
3784 bumpedCount++;
3785 }
3786 if (bumpedCount == 0) continue;
3787 }
3788 if (bumpedListTail != NULL) {
3789 bumpedListTail->next = NULL;
3790 }
3791 GroupsHead = GroupsTailVNP = NULL;
3792
3793 for (potCDSvnp = bumpedListHead; potCDSvnp != NULL; potCDSvnp = potCDSvnp->next) {
3794 /* this pass is only searching for CDS features (and correspondins mRNAs) */
3795 potCDS = potCDSvnp->data.ptrvalue;
3796 RFIPcds = potCDS->RFIP;
3797 if (RFIPcds->featdeftype != FEATDEF_CDS) continue;
3798 potCDS->used = TRUE;
3799
3800 if ((currentGroup = MemNew (sizeof (RFIPgroup))) == NULL) goto bail_out;
3801 if (GroupsHead == NULL) {
3802 GroupsTailVNP = ValNodeAddPointer (&GroupsHead, 0, currentGroup);
3803 } else {
3804 GroupsTailVNP = ValNodeAddPointer (&GroupsTailVNP, 0, currentGroup);
3805 }
3806 if (GroupsTailVNP == NULL) goto bail_out;
3807
3808 /* do not add the CDS to currentGroup->members yet, b/c we want mRNA features to appear first
3809 (but remember to add it after!) */
3810
3811 currentGroup->memberCount = 1;
3812 currentGroup->members = NULL;
3813
3814 currentGroup->Left = potCDS->Left;
3815 currentGroup->Right = potCDS->Right;
3816 currentGroup->decorationLeft = potCDS->decorationLeft;
3817 currentGroup->decorationRight = potCDS->decorationRight;
3818
3819 for (potRNAvnp = bumpedListHead; potRNAvnp != NULL; potRNAvnp = potRNAvnp->next) {
3820 potRNA = potRNAvnp->data.ptrvalue;
3821 RFIPmrna = potRNA->RFIP;
3822 if (RFIPmrna->featdeftype != FEATDEF_mRNA) continue;
3823 if (!MultiRender && potRNA->used) continue;
3824
3825 if (mRNAmatchesCDS (RFIPmrna, RFIPcds)) {
3826 potRNA->used = TRUE;
3827
3828 if ((tRFIPentry = MemNew (sizeof (RFIPentry))) == NULL) goto bail_out;
3829 if (ValNodeAddPointer (¤tGroup->members, 0, tRFIPentry) == NULL) goto bail_out;
3830
3831 MemCopy (tRFIPentry, potRNA, sizeof (RFIPentry));
3832
3833 currentGroup->memberCount++;
3834 currentGroup->Left = MIN (currentGroup->Left, RFIPmrna->Left);
3835 currentGroup->Right = MAX (currentGroup->Right, RFIPmrna->Right);
3836 currentGroup->decorationLeft = MIN (currentGroup->decorationLeft, potRNA->decorationLeft);
3837 currentGroup->decorationRight = MAX (currentGroup->decorationRight, potRNA->decorationRight);
3838 }
3839 }
3840
3841 if ((GroupsTailMemberTail = MemNew (sizeof (RFIPentry))) == NULL) goto bail_out;
3842 if (ValNodeAddPointer (¤tGroup->members, 0, GroupsTailMemberTail) == NULL) goto bail_out;
3843 MemCopy (GroupsTailMemberTail, potCDS, sizeof (RFIPentry));
3844
3845 }
3846 /*
3847 append all non-matched elements to the Groups list
3848 */
3849 for (featVNP = bumpedListHead; featVNP != NULL; featVNP = featVNP->next) {
3850 tRFIPentry = featVNP->data.ptrvalue;
3851 /* skip feature if it's been matched already */
3852 if (tRFIPentry->used) {
3853 continue;
3854 } else {
3855 /* add another singleton entry to Groups */
3856 tRFIP = tRFIPentry->RFIP;
3857
3858 if ((currentGroup = MemNew (sizeof (RFIPgroup))) == NULL) goto bail_out;
3859 if (GroupsHead == NULL) {
3860 GroupsTailVNP = ValNodeAddPointer (&GroupsHead, 0, currentGroup);
3861 } else {
3862 GroupsTailVNP = ValNodeAddPointer (&GroupsTailVNP, 0 ,currentGroup);
3863 }
3864 if (GroupsTailVNP == NULL) goto bail_out;
3865
3866 if ((GroupsTailMemberTail = MemNew (sizeof (RFIPentry))) == NULL) goto bail_out;
3867 if ((MemberTailVNP = ValNodeAddPointer (¤tGroup->members, 0, GroupsTailMemberTail)) == NULL) goto bail_out;
3868
3869 currentGroup->memberCount = 1;
3870 MemCopy (GroupsTailMemberTail, tRFIPentry, sizeof (RFIPentry));
3871
3872 currentGroup->Left = tRFIP->Left;
3873 currentGroup->Right = tRFIP->Right;
3874 currentGroup->decorationLeft = tRFIPentry->decorationLeft;
3875 currentGroup->decorationRight = tRFIPentry->decorationRight;
3876
3877 }
3878 }
3879
3880 /*
3881 now, assign each element in Groups to a row. algorithm is the same as in BubbleUpLayout,
3882 except that instead of looking for the first matching row, need to find (RFIPgroup->members)
3883 consecutive free rows.
3884 */
3885 for (groupVNP = GroupsHead; groupVNP != NULL; groupVNP = groupVNP->next) {
3886 currentGroup = groupVNP->data.ptrvalue;
3887
3888 featureStart = currentGroup->decorationLeft;
3889 for (thisRow = firstRow; thisRow != NULL; thisRow = thisRow->next) {
3890 foundRows = TRUE;
3891 for (i = 0, thisRow2 = thisRow, featVNP = currentGroup->members;
3892 featVNP != NULL && i < currentGroup->memberCount;
3893 thisRow2 = thisRow2->next, featVNP = featVNP->next, i++) {
3894 tRFIPentry = featVNP->data.ptrvalue;
3895 /*
3896 note: if thisRow2 ends up being NULL then it meas thisRow was a good starting point and we just need to add some rows
3897 */
3898 if (thisRow2 == NULL) {
3899 foundRows = TRUE;
3900 break;
3901 }
3902 rowMaxRight = thisRow2->layoutData.intvalue;
3903 if ( tRFIPentry->decorationLeft <= rowMaxRight ||
3904 NoVisibleGap(tRFIPentry->decorationLeft, rowMaxRight, viewScale) ) {
3905 foundRows = FALSE;
3906 if (thisRow2->next == NULL) {
3907 rows++;
3908 if ((lastRow = AddARow (lastRow)) == NULL) goto bail_out;
3909 lastRow->layoutData.intvalue = -2000000000;
3910 }
3911 break;
3912 }
3913 }
3914 if (foundRows) {
3915 for (i = 0,
3916 thisRow2 = thisRow,
3917 featVNP = currentGroup->members;
3918 tRFIPentry != NULL
3919 && i < currentGroup->memberCount;
3920 featVNP = featVNP->next,
3921 thisRow2 = thisRow2->next,
3922 i++) {
3923 tRFIPentry = featVNP->data.ptrvalue;
3924 RFIP = tRFIPentry->RFIP;
3925 if (thisRow2 == NULL) {
3926 rows++;
3927 if ((lastRow = AddARow (lastRow)) == NULL) goto bail_out;
3928 thisRow2 = lastRow;
3929 }
3930 AddFeatureToRow (thisRow2, RFIP, FALSE, FPSP);
3931 rowMaxRight = tRFIPentry->decorationRight;
3932 thisRow2->layoutData.intvalue = rowMaxRight;
3933 }
3934 break;
3935 }
3936 }
3937 }
3938 bumpedListHead = ValNodeFreeData (bumpedListHead);
3939 for (groupVNP = GroupsHead; groupVNP != NULL; groupVNP = groupVNP->next) {
3940 currentGroup = groupVNP->data.ptrvalue;
3941 ValNodeFreeData (currentGroup->members);
3942 }
3943 GroupsHead = ValNodeFreeData (GroupsHead);
3944 }
3945 bail_out:
3946 ValNodeFreeData (bumpedListHead);
3947 ValNodeFreeData (fifoHead);
3948 for (groupVNP = GroupsHead; groupVNP != NULL; groupVNP = groupVNP->next) {
3949 currentGroup = groupVNP->data.ptrvalue;
3950 ValNodeFreeData (currentGroup->members);
3951 }
3952 GroupsHead = ValNodeFreeData (GroupsHead);
3953 return rows;
3954 }
3955
3956 static Uint2 GeneProductsLayout (
3957 InternalRowPtr firstRow,
3958 FilterProcessStatePtr FPSP
3959 )
3960
3961 {
3962 return GeneProductsLayoutInternal (firstRow, FPSP, FALSE);
3963 }
3964
3965 static Uint2 GeneProductsLayoutX (
3966 InternalRowPtr firstRow,
3967 FilterProcessStatePtr FPSP
3968 )
3969
3970 {
3971 return GeneProductsLayoutInternal (firstRow, FPSP, TRUE);
3972 }
3973
3974 static Uint2 BubbleUpLayout (
3975 InternalRowPtr firstRow,
3976 FilterProcessStatePtr FPSP
3977 )
3978
3979 {
3980 Uint2 rows = 1;
3981 Int4 featureStart, rowMaxRight;
3982 RelevantFeatureItemPtr RFIP;
3983 InternalRowPtr thisRow, lastRow;
3984 RenderInput dummyRI;
3985 Uint4 viewScale;
3986
3987 viewScale = FPSP->vContext->viewScale;
3988 /*
3989 This uses InternalRow.layoutData as an Int4, which stores the (x) offset of the last used pixel.
3990 so a feature starting at (internalRow.layoutData + 1) or greater can be placed in the same row
3991 without a collision.
3992 */
3993
3994 /* add the 1st feature to the 1st row */
3995 do {
3996 RFIP = GetNextRFIPinFilterItem (FPSP);
3997 if (RFIP == NULL) return 0;
3998 } while (! BuildRenderInputFromRFIP (&dummyRI, RFIP, FPSP));
3999
4000 AddFeatureToRow (firstRow, RFIP, FALSE, FPSP);
4001 lastRow = firstRow;
4002 firstRow->layoutData.intvalue = dummyRI.decorationRight;
4003
4004 while ((RFIP = GetNextRFIPinFilterItem (FPSP)) != NULL) {
4005 if (! BuildRenderInputFromRFIP (&dummyRI, RFIP, FPSP)) {
4006 continue;
4007 }
4008 featureStart = dummyRI.decorationLeft;
4009 for (thisRow = firstRow; thisRow != NULL; thisRow = thisRow->next) {
4010 rowMaxRight = thisRow->layoutData.intvalue;
4011 if (featureStart >= rowMaxRight &&
4012 ! NoVisibleGap(featureStart, rowMaxRight, viewScale) ) {
4013 AddFeatureToRow (thisRow, RFIP, FALSE, FPSP);
4014 rowMaxRight = MAX (rowMaxRight, dummyRI.decorationRight);
4015 thisRow->layoutData.intvalue = rowMaxRight;
4016 RFIP = NULL;
4017 break;
4018 }
4019 }
4020 if (RFIP != NULL) {
4021 rows++;
4022 lastRow = AddARow (lastRow);
4023 AddFeatureToRow (lastRow, RFIP, FALSE, FPSP);
4024 rowMaxRight = dummyRI.decorationRight;
4025 lastRow->layoutData.intvalue = rowMaxRight;
4026 }
4027 }
4028 return rows;
4029 }
4030
4031 static Uint2 SingleRowLayout (
4032 InternalRowPtr firstRow,
4033 FilterProcessStatePtr FPSP
4034 )
4035
4036 {
4037 RelevantFeatureItemPtr RFIP, lastRFIP;
4038 ValNodePtr freeVNP, vnp;
4039 Uint4 smearStart, smearStop;
4040 Uint1 smearFeatdeftype;
4041 ViewerContextPtr vContext;
4042 Uint4 viewScale;
4043 Boolean adjacentNoGap;
4044 Boolean tooNarrow;
4045 Boolean smearing = FALSE, justSmeared = FALSE;
4046
4047 vContext = FPSP->vContext;
4048 viewScale = vContext->viewScale;
4049 lastRFIP = GetNextRFIPinFilterItem (FPSP);
4050 if (lastRFIP == NULL)
4051 return 0;
4052 smearFeatdeftype = lastRFIP->featdeftype;
4053
4054 while ((RFIP = GetNextRFIPinFilterItem (FPSP)) != NULL) {
4055 adjacentNoGap = PixelsBetweenSeqCoords(lastRFIP->Right, RFIP->Left, viewScale) < 2; /* was 3 */
4056 /* TestForSmearOverlap (lastRFIP->Right + 2 * vContext->viewScale, RFIP->Left, vContext); */
4057 tooNarrow = PixelsBetweenSeqCoords(RFIP->Left, RFIP->Right, viewScale) < 5;
4058 /* TestForSmearOverlap (RFIP->Left + 4 * vContext->viewScale, RFIP->Right, vContext); */
4059 if (adjacentNoGap && tooNarrow) {
4060 if (smearing == FALSE) {
4061 tooNarrow = PixelsBetweenSeqCoords(lastRFIP->Left, lastRFIP->Right, viewScale) < 5;
4062 /* TestForSmearOverlap (lastRFIP->Left + 4 * vContext->viewScale, lastRFIP->Right, vContext); */
4063 if (tooNarrow) {
4064 smearStart = lastRFIP->Left;
4065 } else {
4066 smearStart = RFIP->Left;
4067 }
4068 smearing = TRUE;
4069 }
4070 justSmeared = TRUE;
4071 if (smearFeatdeftype != RFIP->featdeftype) {
4072 smearFeatdeftype = FEATDEF_ANY;
4073 } else if (smearFeatdeftype == 0) {
4074 smearFeatdeftype = RFIP->featdeftype;
4075 }
4076 smearStop = RFIP->Right;
4077 continue;
4078 }
4079 /* VNP is non-NULL during a smear; this tests for regular features*/
4080 if (! justSmeared) {
4081 AddFeatureToRow (firstRow, lastRFIP, TRUE, FPSP);
4082 lastRFIP = RFIP;
4083 } else { /* we just finished a smear group */
4084 lastRFIP = MemNew (sizeof (RelevantFeatureItem));
4085 if (lastRFIP == NULL) return 1;
4086 lastRFIP->Left = smearStart;
4087 lastRFIP->Right = smearStop;
4088 lastRFIP->featstrand = Seq_strand_unknown;
4089 lastRFIP->circularSpanningOrigin = FALSE;
4090 lastRFIP->LeftEnd = lastRFIP->RightEnd = EndAbsolute;
4091 lastRFIP->circularSpanningOrigin = FALSE;
4092 lastRFIP->featdeftype = smearFeatdeftype;
4093 lastRFIP->numivals = 1;
4094 vnp = ValNodeAddPointer (&FPSP->lastInFreeList, 0, lastRFIP);
4095 if (FPSP->needFreeList == NULL) {
4096 FPSP->needFreeList = FPSP->lastInFreeList;
4097 }
4098 FPSP->lastInFreeList = vnp;
4099 smearing = FALSE;
4100 AddFeatureToRow (firstRow, lastRFIP, TRUE, FPSP);
4101 justSmeared = FALSE;
4102 lastRFIP = RFIP;
4103 }
4104 }
4105 if (! justSmeared) { /* the last feature was not in a smear group */
4106 AddFeatureToRow (firstRow, lastRFIP, TRUE, FPSP);
4107 } else {
4108 RFIP = MemNew (sizeof (RelevantFeatureItem));
4109 if (RFIP == NULL) return 1;
4110 RFIP->Left = smearStart;
4111 RFIP->Right = smearStop;
4112 RFIP->featstrand = Seq_strand_unknown;
4113 RFIP->circularSpanningOrigin = FALSE;
4114
4115 RFIP->LeftEnd = RFIP->RightEnd = EndAbsolute;
4116 RFIP->featdeftype = smearFeatdeftype;
4117 RFIP->numivals = 1;
4118
4119 if ((freeVNP = MemNew (sizeof (ValNode))) == NULL) {
4120 MemFree (RFIP);
4121 return 1;
4122 }
4123 freeVNP->data.ptrvalue = RFIP;
4124 freeVNP->next = FPSP->needFreeList;
4125 FPSP->needFreeList = freeVNP;
4126
4127 AddFeatureToRow (firstRow, RFIP, TRUE, FPSP);
4128 }
4129 return 1;
4130 }
4131
4132
4133 /*
4134 Call DrawNameAnnotbox() in a sub-function of FilterAndLayout, when you know that something
4135 will be drawn in as a result of this call to FilterAndLayout in the current sanLevelSeg.
4136 return FALSE if there is an error. Return true whether we draw anything or not.
4137 */
4138 static
4139 Boolean DrawNamedAnnotBox(FilterProcessStatePtr FPSP)
4140 {
4141 ViewerContextPtr vContext;
4142 CharPtr annotName;
4143 FilterPtr FP;
4144
4145 if (FPSP == NULL) /* something wrong !? */
4146 return FALSE;
4147 vContext = FPSP->vContext;
4148 if (vContext == NULL)
4149 return FALSE;
4150 if (vContext->sanLevelSeg == NULL)
4151 return FALSE;
4152 if ((FP = vContext->FltPtr) == NULL)
4153 return FALSE;
4154
4155 if (!FP->GroupByAnnot) /* we are not grouping by named annotations */
4156 return TRUE;
4157
4158 annotName = GetSeqAnnotName(vContext->currentSAP);
4159 if (annotName == NULL) /* we are currently not working on a named Seq Annot. */
4160 return TRUE;
4161
4162 if (FP->DrawAnnotBox && !FPSP->annotBoxDrawn) /* We should draw the box and it hasn't been done yet. */
4163 {
4164 AddAttribute (vContext->sanLevelSeg, COLOR_ATT, FP->AnnotBoxColor, 0, 0, 0, 0);
4165 AddSilentSegRect (vContext->sanLevelSeg, FALSE, 0);
4166 FPSP->ceiling -= 5;
4167 FPSP->annotBoxDrawn = TRUE;
4168 }
4169
4170 /* Have a label that should be drawn at the top of the box? */
4171 if (!FPSP->annotLabelDrawn && !StringHasNoText (annotName))
4172 {
4173 AddAttribute (vContext->sanLevelSeg, COLOR_ATT, FP->AnnotLabelColor, 0, 0, 0, 0);
4174 switch (FP->AnnotLabelLoc) {
4175 case LabelOnTop:
4176 AddTextLabel (vContext->sanLevelSeg, (vContext->from + vContext->to) / 2, FPSP->ceiling,
4177 annotName, FP->AnnotLabelFont, 1, LOWER_CENTER, 0);
4178 SelectFont(FP->AnnotLabelFont);
4179 FPSP->ceiling -= LineHeight () + 4;
4180 break;
4181 case LabelOnSide:
4182 AddTextLabel (vContext->sanLevelSeg, 0, FPSP->ceiling,
4183 annotName, FP->AnnotLabelFont, 1, LOWER_RIGHT, 0);
4184 break;
4185 default:
4186 break;
4187 }
4188 FPSP->annotLabelDrawn = TRUE;
4189 }
4190 return TRUE;
4191 }
4192
4193 /*
4194 Call DrawFilterItemBoxLabel() in a sub-function of FilterAndLayout, when you know that something
4195 will be drawn in as a result of this call to FilterAndLayout in the current filterSeg (vc->drawOnMe).
4196 return FALSE if there is an error. Return true whether we draw anything or not.
4197 */
4198 static Boolean DrawFilterItemBoxLabel(
4199 FilterProcessStatePtr FPSP,
4200 FilterItemPtr FIP
4201 )
4202 {
4203 ViewerContextPtr vContext;
4204 SegmenT invisibleSeg;
4205
4206 if (FPSP == NULL) /* something wrong !? */
4207 return FALSE;
4208 vContext = FPSP->vContext;
4209 if (vContext == NULL)
4210 return FALSE;
4211 if (vContext->drawOnMe == NULL)
4212 return FALSE;
4213
4214 if (FIP->DrawGroupBox && !FPSP->groupBoxDrawn) /* want to draw it, or already drawn. */
4215 {
4216 AddAttribute (vContext->drawOnMe, COLOR_ATT, FIP->GroupBoxColor, 0, 0, 0, 0);
4217 AddSilentSegRect (vContext->drawOnMe, FALSE, 0);
4218 FPSP->ceiling -= 5;
4219 /* add invisible line to force width of SegRect */
4220 invisibleSeg = CreateSegment (vContext->drawOnMe, 0, 0);
4221 SetSegmentVisibleFlag (invisibleSeg, FALSE);
4222 AddLine (invisibleSeg, vContext->from - 1 * vContext->viewScale , FPSP->ceiling ,
4223 vContext->to + 1 * vContext->viewScale , FPSP->ceiling, FALSE, 0);
4224 FPSP->groupBoxDrawn = TRUE;
4225 }
4226
4227 /* need to draw a label on top? */
4228 if (FIP->GroupLabelLoc == LabelOnTop && !FPSP->groupLabelDrawn && !StringHasNoText (FIP->GroupLabel)) {
4229 AddAttribute (vContext->drawOnMe, COLOR_ATT, FIP->GroupLabelColor, 0, 0, 0, 0);
4230 AddTextLabel (vContext->drawOnMe, (vContext->from + vContext->to) / 2, FPSP->ceiling,
4231 FIP->GroupLabel, FIP->GroupLabelFont, 1, LOWER_CENTER, 0);
4232 SelectFont (FIP->GroupLabelFont);
4233 FPSP->ceiling -= LineHeight () + 4;
4234 FPSP->groupLabelDrawn = TRUE;
4235 }
4236
4237 return TRUE;
4238 }
4239
4240
4241
4242 static const LayoutFunction LayoutAlgorithmTable [] = {
4243 BubbleUpLayout, /* placeholder for Layout_Inherit */
4244 SimpleDiagonalLayout, /* Layout_Diagonal */
4245 /* SimpleDiagonalLayout,*/ /* Layout_DiagonalSawtooth (to be implemented) */
4246 SingleRowLayout, /* Layout_FeatTypePerLine (same as single-row, but features are grouped by type before processing) */
4247 BubbleUpLayout, /* Layout_FeatTypePerLineGroup (same as bubble-up, but features are grouped by type before processing) */
4248 /*SingleRowLayout,*/ /* Layout_AllInOneLine (which isn't working currently, and may be less useful than expected*/
4249 BubbleUpLayout, /* Layout_PackUpward */
4250 GeneProductsLayout, /* Layout_GroupCorrespondingFeats (?working?) */
4251 GeneProductsLayoutX /* Layout_GroupCorrespondingFeatsRepeat (?working?) */
4252 };
4253
4254 /* non-leaf segments contain SEGMENT_TREE_BASE other segments */
4255 #define SEGMENT_TREE_BASE 16
4256 #define SEGMENT_TREE_BASE2 (SEGMENT_TREE_BASE * SEGMENT_TREE_BASE)
4257 #define SEGMENT_TREE_BASE3 (SEGMENT_TREE_BASE * SEGMENT_TREE_BASE * SEGMENT_TREE_BASE)
4258
4259 static Uint2 ProcessRows (
4260 LayoutAlgorithm layoutC,
4261 FilterProcessStatePtr FPSP,
4262 ViewerContextPtr vContext
4263 )
4264
4265 {
4266 Uint2 I, J, K, lastI, lastJ, lastK; /* for keeping track of which segment in the tree we're in*/
4267 Uint1 featdeftype;
4268 Int4 featMidPoint;
4269 Uint2 row, rowCount, rowHeight, totalHeight;
4270 Uint4 feat;
4271 InternalRowPtr firstRow, thisRow;
4272 ValNodePtr VNP;
4273 RelevantFeatureItemPtr RFIP;
4274 RenderInput RI; /* dummy used while finding height of each row */
4275 SegmenT SegmentTreeTop;
4276 SegmenT SegmentTreeMid;
4277 SegmenT SegmentTreeBot;
4278 Boolean SegmentChanged = TRUE;
4279 Boolean emptyRow = TRUE;
4280 Boolean allEmpty = TRUE;
4281 FilterItemPtr FIP;
4282
4283 firstRow = MemNew (sizeof (InternalRow));
4284 if (firstRow == NULL) return 0;
4285 firstRow->feats = NULL;
4286 VNP = FPSP->currentFilterVNP;
4287 if (VNP == NULL) return 0;
4288 FIP = (FilterItemPtr) VNP->data.ptrvalue;
4289
4290 rowCount = (*LayoutAlgorithmTable [layoutC]) (firstRow, FPSP);
4291
4292 thisRow = firstRow;
4293 totalHeight = 0;
4294
4295 for (row = 0; row < rowCount; row++) {
4296 if (thisRow == NULL) continue;
4297 /*First iterate through features to find the row's height */
4298 VNP = thisRow->feats;
4299 rowHeight = 0;
4300 if (thisRow->rowFeatureCount > 0) {
4301 allEmpty = FALSE;
4302 }
4303 for (feat = 0; feat < thisRow->rowFeatureCount; feat++) {
4304 RFIP = VNP->data.ptrvalue;
4305 if (VNP == NULL) break;
4306 VNP = VNP->next;
4307 if (RFIP == NULL) return 0;
4308 if (! BuildRenderInputFromRFIP (&RI, RFIP, FPSP)) {
4309 continue;
4310 }
4311 rowHeight = MAX (rowHeight, RI.decorationHeight);
4312 }
4313 if (!allEmpty)
4314 {
4315 DrawNamedAnnotBox(FPSP);
4316 DrawFilterItemBoxLabel(FPSP, FIP);
4317 }
4318
4319 /*Repeat, but actually draw them this time */
4320 VNP = thisRow->feats;
4321 RI.rowHeight = rowHeight;
4322 RI.yStart = FPSP->ceiling - totalHeight;
4323 if (thisRow->rowFeatureCount > 0) {
4324 emptyRow = FALSE;
4325 } else {
4326 emptyRow = TRUE;
4327 }
4328 I = J = K = 0;
4329 SegmentChanged = TRUE;
4330 for (feat = 0; feat < thisRow->rowFeatureCount; feat++) {
4331 if (VNP == NULL) break;
4332 if ((RFIP = VNP->data.ptrvalue) == NULL) return 0;
4333 VNP = VNP->next;
4334 featdeftype = RFIP->featdeftype;
4335 featMidPoint = (RFIP->Left + RFIP->Right) / 2;
4336 lastI = I;
4337 lastJ = J;
4338 lastK = K;
4339 I = (SEGMENT_TREE_BASE * featMidPoint) / vContext->seqLength;
4340 J = ((SEGMENT_TREE_BASE2 * featMidPoint) / vContext->seqLength) % SEGMENT_TREE_BASE;
4341 K = ((SEGMENT_TREE_BASE3 * featMidPoint) / vContext->seqLength) % SEGMENT_TREE_BASE;
4342
4343 if (I != lastI || SegmentChanged) {
4344 SegmentTreeTop = CreateSegment (vContext->drawOnMe, 0, 0);
4345 SegmentChanged = TRUE;
4346 }
4347 if (J != lastJ || SegmentChanged) {
4348 SegmentTreeMid = CreateSegment (SegmentTreeTop , 0, 0);
4349 SegmentChanged = TRUE;
4350 }
4351 if (K != lastK || SegmentChanged) {
4352 SegmentTreeBot = CreateSegment (SegmentTreeMid, 0, 0);
4353 SegmentChanged = TRUE;
4354 }
4355 if (SegmentChanged) {
4356 MemSet (FPSP->drawSegs, 0, sizeof (FPSP->drawSegs));
4357 MemSet (FPSP->labelSegs, 0, sizeof (FPSP->labelSegs));
4358 SegmentChanged = FALSE;
4359 }
4360 if (! EnsureFeatureHasSegment (FPSP, featdeftype, SegmentTreeBot)) return 0;
4361 if (! BuildRenderInputFromRFIP (&RI, RFIP, FPSP)) {
4362 continue;
4363 }
4364
4365 DrawFeatureAndLabel (&RI, vContext);
4366 }
4367 if (! emptyRow) {
4368 totalHeight += rowHeight + FPSP->currentFIP->IntraRowPaddingPixels;
4369 }
4370 if (thisRow->next == NULL) break;
4371 thisRow = thisRow->next;
4372 }
4373 if (allEmpty) {
4374 return 0;
4375 }
4376 return totalHeight;
4377 }
4378
4379 typedef struct scalesntdata {
4380 SegmenT seg;
4381 PrimitivE snt;
4382 BoxInfo box;
4383 Int4 length;
4384 Int4 labelOffset;
4385 BioseqAppearanceItemPtr bioseqAIP;
4386 Boolean disableLastLabel;
4387 Boolean disableFirstLabel;
4388 Int4 offset;
4389 } ScaleSntData, PNTR ScaleSntPtr;
4390
4391 static void ScaleSntDrawProc (
4392 BigScalar calldata,
4393 PrimDrawContext pdc
4394 )
4395
4396 {
4397 Int4 curScale;
4398 DrawInfoPtr dInfoPtr;
4399 Int4 i, j;
4400 RecT r;
4401 PntInfo pnt;
4402 PoinT pt;
4403 ScaleSntPtr ssp;
4404 BoxInfo tmpBox;
4405 Uint1 tickCount;
4406 Char buffer[16];
4407 BioseqAppearanceItemPtr bioseqAIP;
4408 Uint1 scaleHeight;
4409 Int4 from, to;
4410
4411 ssp = (ScaleSntPtr) calldata;
4412 if (ssp == NULL) return;
4413
4414 dInfoPtr = (DrawInfoPtr) pdc;
4415 tmpBox = ssp->box;
4416 bioseqAIP = ssp->bioseqAIP;
4417 scaleHeight = bioseqAIP->scaleHeight;
4418
4419 from = tmpBox.left;
4420 to = tmpBox.right;
4421
4422 curScale = dInfoPtr->scale.scaleX;
4423 r.left = (Int2) ((dInfoPtr->scale.offsetX + tmpBox.left) / curScale);
4424 r.right = (Int2) ((dInfoPtr->scale.offsetX + tmpBox.right) / curScale);
4425 SelectFont (bioseqAIP->scaleFont);
4426 SelectColor (bioseqAIP->scaleColor[0], bioseqAIP->scaleColor[1], bioseqAIP->scaleColor[2]);
4427
4428 /* if the right-most edge is visible, draw the final tick mark and a right-justified total length label */
4429 if (dInfoPtr->scale.worldWindow.right >= to - 100 * curScale) {
4430 pnt.x = to;
4431 pnt.y = tmpBox.top;
4432 MapWorldPointToPixel (&pt, &pnt, &dInfoPtr->scale);
4433 MoveTo (pt.x, pt.y);
4434 pnt.y = tmpBox.top - scaleHeight;
4435 MapWorldPointToPixel (&pt, &pnt, &dInfoPtr->scale);
4436 LineTo (pt.x, pt.y);
4437 sprintf (buffer, "%ld", (long)to + ssp->labelOffset + 1);
4438 pt.x += 3 - StringWidth (buffer);
4439 pt.y += 1 + Ascent ();
4440 PaintStringEx (buffer, pt.x, pt.y);
4441 }
4442
4443 /* if the left-most edge is visible, draw the first label, left-justified */
4444 if (dInfoPtr->scale.worldWindow.left - 400 * curScale <= from) {
4445 pnt.x = from;
4446 pnt.y = tmpBox.top - scaleHeight;
4447 sprintf (buffer, "%ld", (long)((from == 0) ? 1 : from) + ssp->labelOffset);
4448 MapWorldPointToPixel (&pt, &pnt, &dInfoPtr->scale);
4449 pt.y += 1 + Ascent ();
4450 PaintStringEx (buffer, pt.x, pt.y);
4451 }
4452
4453 if (tmpBox.left > dInfoPtr->scale.worldWindow.right ||
4454 tmpBox.right < dInfoPtr->scale.worldWindow.left ||
4455 tmpBox.top < dInfoPtr->scale.worldWindow.bottom ||
4456 tmpBox.bottom > dInfoPtr->scale.worldWindow.top)
4457 return;
4458
4459 if (dInfoPtr->checked == FALSE ) {
4460 if (tmpBox.left < dInfoPtr->scale.worldWindow16.left)
4461 tmpBox.left = dInfoPtr->scale.worldWindow16.left;
4462 if (tmpBox.right > dInfoPtr->scale.worldWindow16.right)
4463 tmpBox.right = dInfoPtr->scale.worldWindow16.right;
4464 if (tmpBox.top > dInfoPtr->scale.worldWindow16.top)
4465 tmpBox.top = dInfoPtr->scale.worldWindow16.top;
4466 if (tmpBox.bottom < dInfoPtr->scale.worldWindow16.bottom)
4467 tmpBox.bottom = dInfoPtr->scale.worldWindow16.bottom;
4468 }
4469
4470 i = MAX (dInfoPtr->scale.worldWindow.left, tmpBox.left);
4471 /* i = i + 10 * curScale - (i % (10 * curScale)) - 1;*/
4472 while (i % (10 * curScale) != 0) {
4473 i++; /* !!! do this the right way */
4474 }
4475 for (tickCount = (i / (10 * curScale)) % 10;
4476 i < MIN (dInfoPtr->scale.worldWindow.right, to);
4477 i += curScale * 10) {
4478 pnt.x = i;
4479 pnt.y = tmpBox.top;
4480 MapWorldPointToPixel (&pt, &pnt, &dInfoPtr->scale);
4481 MoveTo (pt.x, pt.y);
4482
4483 if (tickCount == 0 || tickCount == 5) {
4484 pnt.y = tmpBox.top - scaleHeight; /* draw full-height tick */
4485 MapWorldPointToPixel (&pt, &pnt, &dInfoPtr->scale);
4486 LineTo (pt.x, pt.y);
4487 if (tickCount == 0
4488 /* if i + 100curScale > the right boundary, this is the last label */
4489 && (!((i + 100 * curScale >= to) && ssp->disableLastLabel))
4490 && (!((i - 100 * curScale <= from) && ssp->disableFirstLabel))
4491 && (i != from)) {
4492 sprintf (buffer, "%ld", (long)((i == 0) ? 1 : i) + ssp->labelOffset); /* put the origin at 1 instead of 0 */
4493 pt.x -= StringWidth (buffer) / 2; /* center text around the tick mark*/
4494 pt.y += 1 + Ascent ();
4495 PaintStringEx (buffer, pt.x, pt.y);
4496 }
4497 /* disable the right-end one in the case of an overlap */
4498 } else {
4499 pnt.y = tmpBox.top - scaleHeight / 2;
4500 MapWorldPointToPixel (&pt, &pnt, &dInfoPtr->scale);
4501 LineTo (pt.x, pt.y);
4502 }
4503 tickCount = (tickCount + 1) % 10;
4504 }
4505
4506 /* also, we might need to redraw the labels just to the left or to the right of the update region. */
4507 i = MAX (dInfoPtr->scale.worldWindow.left, tmpBox.left);
4508 j = i; /* j = leftmost visible pixel in world coordinates */
4509 while (i % (100 * curScale) != 0) {
4510 i--;
4511 }
4512 pnt.x = i;
4513 sprintf (buffer, "%ld", (long)((i == 0) ? 1 : i) + ssp->labelOffset);
4514 i += curScale * ((StringWidth (buffer) / 2) + 1);
4515 if (i >= j
4516 && i > from
4517 && (!((pnt.x + 100 * curScale >= to) && ssp->disableLastLabel))
4518 && (!((pnt.x - 100 * curScale <= from) && ssp->disableFirstLabel))
4519 && pnt.x > from) {
4520 pnt.y = tmpBox.top - scaleHeight;
4521 MapWorldPointToPixel (&pt, &pnt, &dInfoPtr->scale);
4522 pt.x -= StringWidth (buffer) / 2; /* center text around the tick mark*/
4523 pt.y += 1 + Ascent ();
4524 PaintStringEx (buffer, pt.x, pt.y);
4525 }
4526 /* now check the right side*/
4527
4528 i = MIN (dInfoPtr->scale.worldWindow.right, to);
4529 j = i; /* j = rightmost visible pixel in world coordinates */
4530 while (i % (100 * curScale) != 0) {
4531 i++;
4532 }
4533 pnt.x = i;
4534 sprintf (buffer, "%ld", (long)i + ssp->labelOffset);
4535 i -= curScale * ((StringWidth (buffer) / 2) + 1);
4536 if (i <= j
4537 && (!((pnt.x + 100 * curScale >= to) && ssp->disableLastLabel))
4538 && (!((pnt.x - 100 * curScale <= from) && ssp->disableFirstLabel))
4539 && pnt.x < to) {
4540 pnt.y = tmpBox.top - scaleHeight;
4541 MapWorldPointToPixel (&pt, &pnt, &dInfoPtr->scale);
4542 pt.x -= StringWidth (buffer) / 2; /* center text around the tick mark*/
4543 pt.y += 1 + Ascent ();
4544 PaintStringEx (buffer, pt.x, pt.y);
4545 }
4546 }
4547
4548 static void ScaleSntCleanupProc (
4549 BigScalar calldata
4550 )
4551
4552 {
4553 ScaleSntPtr ssp;
4554
4555 ssp = (ScaleSntPtr) calldata;
4556 MemFree (ssp);
4557 }
4558
4559 static Boolean LIBCALLBACK Asn2gphSegmentExploreProc (
4560 SeqLocPtr slp,
4561 SeqMgrSegmentContextPtr context
4562 )
4563
4564 {
4565 /* context->userdata a pointer to vContext */
4566 RelevantFeatureItemPtr RFIP;
4567 SeqIdPtr sip, newid = NULL;
4568 Int4 gi;
4569 Char labelBuf [100];
4570 Int4 left, right;
4571 ViewerContextPtr vContext;
4572 AppearancePtr AP;
4573 BioseqAppearanceItemPtr BioAIP;
4574 BioseqPtr bsp;
4575
4576 if ((RFIP = MemNew (sizeof (RelevantFeatureItem))) == NULL) return FALSE;
4577 vContext = context->userdata;
4578 bsp = vContext->BSP;
4579 ValNodeAddPointer (&vContext->BSPsegmentVNP, 0, RFIP);
4580 sip = SeqLocId (slp);
4581 if (sip != NULL && sip->choice == SEQID_GI /* && BioseqFindCore (sip) != NULL */) {
4582 gi = sip->data.intvalue;
4583 newid = SeqIdStripLocus (GetSeqIdForGI (gi));
4584 sip = newid;
4585 if (newid != NULL) {
4586 ValNodeAddInt (&newid, SEQID_GI, gi);
4587 }
4588 }
4589
4590 AP = vContext->AppPtr;
4591 BioAIP = AP->bioseqAIP;
4592
4593 left = context->from;
4594 right = context->to - left + context->cumOffset;
4595 left = context->cumOffset;
4596 if (sip != NULL) {
4597 if (BioAIP->format != PRINTID_FASTA_LONG) {
4598 sip = SeqIdFindWorst (sip);
4599 }
4600 SeqIdWrite (sip, labelBuf, BioAIP->format, sizeof (labelBuf) - 1);
4601 RFIP->ContentLabel = StringSave (labelBuf); /* record this in a list of things to be freed so that we dont leak memory!!!!! */
4602 }
4603 SeqIdSetFree (newid);
4604 RFIP->Left = MIN (left, right);
4605 RFIP->Right = MAX (left, right);
4606 RFIP->entityID = context->entityID;
4607 RFIP->itemID = context->itemID;
4608 if (bsp->repr == Seq_repr_seg) {
4609 RFIP->itemType = OBJ_BIOSEQ_SEG;
4610 } else if (bsp->repr == Seq_repr_delta) {
4611 RFIP->itemType = OBJ_BIOSEQ_DELTA;
4612 } else {
4613 RFIP->itemType = OBJ_BIOSEQ_SEG;
4614 }
4615 RFIP->numivals = 1;
4616 RFIP->featdeftype = 0;
4617 RFIP->featstrand = context->strand;
4618 RFIP->circularSpanningOrigin = FALSE;
4619 return TRUE;
4620 }
4621
4622 static Int4 DrawBioseqSegments (
4623 Int4 initialYOffset,
4624 FilterItemPtr FIP,
4625 ViewerContextPtr vContext
4626 )
4627
4628 {
4629 ValNodePtr listHead = NULL, vnpSegment = NULL;
4630 Int4 segmentCount;
4631 Uint2 rowHeight, row = 0; /* row is either 0 or 1 */
4632 AppearanceItem segmentAI;
4633 AppearanceItemPtr oldAIPzero;
4634 AppearancePtr AP;
4635 BioseqAppearanceItemPtr BioAIP;
4636 RelevantFeatureItemPtr RFIP;
4637 FilterProcessState FPS;
4638 Uint2 oldMaxScale;
4639
4640 vContext->BSPsegmentVNP = NULL;
4641 SeqMgrExploreSegments (vContext->BSP, vContext, Asn2gphSegmentExploreProc);
4642 listHead = vContext->BSPsegmentVNP;
4643 segmentCount = 0;
4644 for (vnpSegment = listHead; vnpSegment != NULL; vnpSegment = vnpSegment->next) {
4645 segmentCount++;
4646 }
4647
4648 if (segmentCount <= 1) {
4649 ValNodeFreeData (listHead);
4650 return 0;
4651 }
4652
4653 oldMaxScale = vContext->FltPtr->MaxScaleWithLabels;
4654 vContext->FltPtr->MaxScaleWithLabels = 10000;
4655 AP = vContext->AppPtr;
4656 BioAIP = AP->bioseqAIP;
4657 MemCpy (segmentAI.LabelColor, BioAIP->labelColor, sizeof (segmentAI.LabelColor));
4658 MemCpy (segmentAI.Color, BioAIP->bioseqColor, sizeof (segmentAI.Color));
4659 segmentAI.RenderChoice = Render_Box;
4660 segmentAI.Height = BioAIP->height;
4661 segmentAI.AddDescToLabel = TRUE;
4662 segmentAI.AddTypeToLabel = FALSE;
4663 segmentAI.LabelFont = BioAIP->labelFont;
4664 segmentAI.LabelLoc = FIP->LabelLoc;
4665 FIP->LabelLoc = LabelAboveClip;
4666
4667 segmentAI.ShowArrow = FALSE;
4668 segmentAI.VibLinestyle = SOLID_LINE;
4669 segmentAI.VibShading = SOLID_SHADING;
4670 oldAIPzero = vContext->AppPtr->FeaturesAppearanceItem[0];
4671 vContext->AppPtr->FeaturesAppearanceItem[0] = &segmentAI;
4672
4673 MemSet (&FPS, 0, sizeof (FPS));
4674 FPS.currentFIP = FIP;
4675 FPS.ceiling = initialYOffset;
4676 FPS.vContext = vContext;
4677
4678 FPS.renderParm.AIP = &segmentAI;
4679 FPS.renderParm.FIP = FIP;
4680
4681 SelectFont (segmentAI.LabelFont);
4682 rowHeight = LineHeight () + segmentAI.Height + 3 + FIP->IntraRowPaddingPixels;
4683 row = 0;
4684
4685 for (vnpSegment = listHead; vnpSegment != NULL; vnpSegment = vnpSegment->next) {
4686
4687 RFIP = vnpSegment->data.ptrvalue;
4688 EnsureFeatureHasSegment (&FPS, 0, vContext->drawOnMe);
4689 if (!BuildRenderInputFromRFIP (&FPS.renderParm, RFIP, &FPS)) {
4690 continue;
4691 }
4692 row = 1 - row; /* alternate between 0 and 1 */
4693 FPS.renderParm.rowHeight += 2;
4694 FPS.renderParm.yStart = initialYOffset - (row * rowHeight);
4695 DrawFeatureAndLabel (&FPS.renderParm, vContext);
4696 }
4697 if (FPS.needFreeList != NULL) {
4698 FPS.needFreeList = ValNodeFreeData (FPS.needFreeList);
4699 FPS.lastInFreeList = NULL;
4700 }
4701 ValNodeFreeData (listHead);
4702 vContext->BSPsegmentVNP = NULL;
4703 vContext->AppPtr->FeaturesAppearanceItem[0] = oldAIPzero;
4704 vContext->FltPtr->MaxScaleWithLabels = oldMaxScale;
4705 return 2 * rowHeight + 7 + FIP->IntraRowPaddingPixels + FIP->GroupPadding;
4706 }
4707
4708 static Int4 DrawBioseq (
4709 Int4 initialYOffset,
4710 FilterItemPtr FIP,
4711 ViewerContextPtr vContext
4712 )
4713
4714 {
4715 PrimitivE thisPrim;
4716 Char labelbuf[128];
4717 BioseqPtr bsp;
4718 ScaleSntPtr ssp;
4719 Uint2 labelLineHeight, lastLabelWidth, firstLabelWidth;
4720 SegmenT seg;
4721 SeqIdPtr sip;
4722 BioseqAppearanceItemPtr bioseqAIP;
4723 Uint1 scaleHeight;
4724 Uint1 height;
4725 Int4 yOffset;
4726 Uint4 i, j;
4727 Boolean drawScale;
4728 AppearancePtr AP;
4729
4730 AP = vContext->AppPtr;
4731 bioseqAIP = AP->bioseqAIP;
4732 yOffset = initialYOffset;
4733 bsp = vContext->BSP;
4734
4735 drawScale = bioseqAIP->drawScale;
4736 if (FIP->DrawScale != TristateUnset) {
4737 drawScale = BOOL_FROM_SET_TRISTATE(FIP->DrawScale);
4738 }
4739
4740 scaleHeight = bioseqAIP->scaleHeight;
4741 if (bioseqAIP->format != PRINTID_FASTA_LONG) {
4742 sip = SeqIdFindWorst (bsp->id);
4743 } else {
4744 sip = bsp->id;
4745 }
4746 SeqIdWrite (sip, labelbuf, bioseqAIP->format, sizeof (labelbuf) - 1);
4747 seg = CreateSegment (vContext->topLevelSeg, 0, 0);
4748
4749 if (bioseqAIP->labelLoc == LabelOnTop) {
4750 AddAttribute (seg, COLOR_ATT, bioseqAIP->labelColor, 0, 0, 1, 0);
4751 thisPrim = AddTextLabel (seg, vContext->from, yOffset, labelbuf, bioseqAIP->labelFont, 0, LOWER_RIGHT, 0);
4752 SetPrimitiveIDs (thisPrim, bsp->idx.entityID, bsp->idx.itemID, OBJ_BIOSEQ, 0);
4753 SelectFont (bioseqAIP->labelFont);
4754 height = LineHeight() + 1;
4755 yOffset = initialYOffset - height;
4756 } else {
4757 height = 0;
4758 }
4759
4760 AddAttribute (seg, COLOR_ATT, bioseqAIP->bioseqColor, 0, 0, 1, 0);
4761 thisPrim = AddRectangle (seg, vContext->from, yOffset, vContext->to, yOffset - bioseqAIP->height, NO_ARROW, TRUE, 0);
4762 SetPrimitiveIDs (thisPrim, bsp->idx.entityID, bsp->idx.itemID, OBJ_BIOSEQ, 0);
4763 AddAttribute (seg, COLOR_ATT, bioseqAIP->labelColor, 0, 0, 1, 0);
4764
4765 height += bioseqAIP->height + 2;
4766 yOffset = initialYOffset - height;
4767
4768 if (bioseqAIP->labelLoc == LabelOnSide) {
4769 AddAttribute (seg, COLOR_ATT, bioseqAIP->labelColor, 0, 0, 1, 0);
4770 thisPrim = AddTextLabel (seg, vContext->from, yOffset, labelbuf, bioseqAIP->labelFont, 1, UPPER_LEFT, 0);
4771 SetPrimitiveIDs (thisPrim, bsp->idx.entityID, bsp->idx.itemID, OBJ_BIOSEQ, 0);
4772 } else if (bioseqAIP->labelLoc == LabelOnBottom) {
4773 AddAttribute (seg, COLOR_ATT, bioseqAIP->labelColor, 0, 0, 1, 0);
4774 thisPrim = AddTextLabel (seg, 0, yOffset, labelbuf, bioseqAIP->labelFont, 1, LOWER_RIGHT, 0);
4775 SetPrimitiveIDs (thisPrim, bsp->idx.entityID, bsp->idx.itemID, OBJ_BIOSEQ, 0);
4776 SelectFont (bioseqAIP->labelFont);
4777 height += LineHeight() + 2;
4778 yOffset = initialYOffset - height;
4779 }
4780
4781 if (drawScale) {
4782
4783 ssp = (ScaleSntPtr) MemNew (sizeof (ScaleSntData));
4784 if (ssp == NULL) return height;
4785 SelectFont (bioseqAIP->scaleFont);
4786 labelLineHeight = LineHeight();
4787 ssp->seg = seg;
4788 ssp->labelOffset = 0;
4789 ssp->length = vContext->to - vContext->from;
4790 ssp->box.left = vContext->from;
4791 ssp->box.right = vContext->to;
4792 ssp->box.top = yOffset;
4793 ssp->box.bottom = yOffset - 2 - scaleHeight - labelLineHeight;
4794 ssp->bioseqAIP = bioseqAIP;
4795
4796 i = vContext->to - vContext->to % (100 * vContext->viewScale); /* the last labelled tick-mark */
4797
4798 sprintf (labelbuf, "%ld", (long)i + ssp->labelOffset);
4799 j = StringWidth (labelbuf); /* j is the width (pixels) of the last tick mark's label */
4800
4801 sprintf (labelbuf, "%ld", (long)vContext->to + ssp->labelOffset);
4802 lastLabelWidth = (StringWidth (labelbuf) + 2) * vContext->viewScale;
4803
4804 if (vContext->from > 0) {
4805 sprintf (labelbuf, "%ld", (long)vContext->from + ssp->labelOffset);
4806 } else {
4807 sprintf (labelbuf, "1");
4808 }
4809 firstLabelWidth = StringWidth (labelbuf) * vContext->viewScale;
4810
4811 i += vContext->viewScale * j / 2; /* right-most edge of the centered label */
4812 j = MAX (j, 10); /* always leave at least 10 pixels between the last 2 labels */
4813 if (i + j * vContext->viewScale >= vContext->to - lastLabelWidth) {
4814 ssp->disableLastLabel = TRUE;
4815 } else {
4816 ssp->disableLastLabel = FALSE;
4817 }
4818
4819 i = vContext->from + (100 * vContext->viewScale) - vContext->from % (100 * vContext->viewScale); /* the second label (first is at the origin) */
4820 sprintf (labelbuf, "%ld", (long)vContext->from + ssp->labelOffset);
4821 if (i - ((StringWidth (labelbuf) / 2 + 5) * vContext->viewScale) <= vContext->from + firstLabelWidth) {
4822 ssp->disableFirstLabel = TRUE;
4823 } else {
4824 ssp->disableFirstLabel = FALSE;
4825 }
4826
4827 ssp->snt = AddSntRectangle (seg, vContext->from, yOffset,
4828 vContext->to + lastLabelWidth, yOffset - scaleHeight - labelLineHeight,
4829 ScaleSntDrawProc, (BigScalar) ssp, ScaleSntCleanupProc, 0);
4830 /* height += scaleHeight + labelLineHeight + 4;*/
4831 yOffset = ssp->box.bottom - 1 - 15;
4832 } else {
4833 yOffset++;
4834 }
4835 yOffset -= DrawBioseqSegments (yOffset, FIP, vContext);
4836 return initialYOffset - yOffset;
4837 }
4838
4839 /* -=-=-=-==-=-==-=-= GRAPH STUFF =-=-=-=-=-=-=-=-=-*/
4840
4841 typedef struct gphsentdata {
4842 Boolean flagIsGUI;
4843 SegmenT seg;
4844 PrimitivE snt;
4845 BoxInfo box;
4846 Int4 min;
4847 Int4 max;
4848 Int4 axis;
4849 Int4 bottom;
4850 FloatHi a;
4851 FloatHi b;
4852 SeqGraphPtr sgp;
4853 Uint1 red, green, blue;
4854 } GphSentData, PNTR GphSentPtr;
4855
4856 static void PlotTheWorkingArray (Int4Ptr xp, Int4 len, Int4 scaleX,
4857 Int4 gmin, RecT r, Uint1 uR, Uint1 uG,
4858 Uint1 uB, AttPData PNTR curattrib)
4859 {
4860 PoinT pt;
4861 Int4 i;
4862 Int4 j;
4863 Int4 max;
4864 Int4 min;
4865 Int4 val;
4866 Uint1 curR, curG, curB;
4867
4868 if (curattrib != NULL)
4869 {
4870 curR = curattrib->color[0];
4871 curG = curattrib->color[1];
4872 curB = curattrib->color[2];
4873 }
4874 else
4875 {
4876 curR = 0;
4877 curG = 0;
4878 curB = 0;
4879 }
4880
4881 SelectColor (uR, uG, uB);
4882 pt.x = r.left;
4883 i = 0;
4884 val = (Int4) *xp;
4885 pt.y = (Int2) (r.bottom - (Int2) (val - gmin));
4886 if (pt.y < r.top) {
4887 pt.y = r.top;
4888 }
4889 MoveTo (pt.x, pt.y);
4890 for (; i < len - scaleX; i += scaleX) {
4891 val = (Int4) *xp;
4892 min = (Int4) val;
4893 max = (Int4) val;
4894 for (j = 1; j < scaleX; j++) {
4895 xp++;
4896 val = (Int4) *xp;
4897 min = MIN (min, (Int4) val);
4898 max = MAX (max, (Int4) val);
4899 }
4900 xp++;
4901 pt.y = (Int2) (r.bottom - (Int2) (min - gmin));
4902 if (pt.y < r.top) {
4903 pt.y = r.top;
4904 }
4905 LineTo (pt.x, pt.y);
4906 pt.y = (Int2) (r.bottom - (Int2) (max - gmin));
4907 if (pt.y < r.top) {
4908 pt.y = r.top;
4909 }
4910 LineTo (pt.x, pt.y);
4911 (pt.x)++;
4912 }
4913 SelectColor (curR, curG, curB);
4914 return;
4915 }
4916
4917 static Int4Ptr MakeWorkingSeqGraphInt4Array (Pointer data, Uint1 type,
4918 Int4 pos, Int4 len,
4919 Boolean usescaleflags,
4920 FloatHi a, FloatHi b)
4921 {
4922 Int4 i;
4923 Int4Ptr xpoints, xp;
4924 FloatHi fval;
4925 Int4 ival;
4926 Byte bval;
4927 ByteStorePtr bs;
4928 BytePtr bp;
4929
4930 xpoints = (Int4Ptr) MemNew ((size_t) (sizeof (Int4) * (len + 10)));
4931
4932 if (xpoints == NULL)
4933 return xpoints;
4934
4935 xp = xpoints;
4936 switch (type) {
4937 default:
4938 case 1:
4939 for (i = 0; i < len; i++, pos++, xp++) {
4940 if (usescaleflags) {
4941 fval = a * (FloatHi) (((FloatHiPtr) data)[pos]) + b;
4942 } else {
4943 fval = (FloatHi) (((FloatHiPtr) data)[pos]);
4944 }
4945 *xp = (Int4) fval;
4946 }
4947 break;
4948 case 2:
4949 for (i = 0; i < len; i++, pos++, xp++) {
4950 if (usescaleflags) {
4951 ival = (Int4) (a * (FloatHi) (((Int4Ptr) data)[pos]) + b);
4952 } else {
4953 ival = (Int4) (((Int4Ptr) data)[pos]);
4954 }
4955 *xp = (Int4) ival;
4956 }
4957 break;
4958 case 3:
4959 bp = MemNew (sizeof (Byte) * (len + 10));
4960 bs = (ByteStorePtr) data;
4961 BSSeek (bs, pos, SEEK_SET);
4962 len = BSRead (bs, (Pointer) bp, len * sizeof (Byte));
4963 for (i = 0; i < len; i++, pos++, xp++) {
4964 if (usescaleflags) {
4965 bval = (Byte) (a * (FloatHi) (bp [i]) + b);
4966 } else {
4967 bval = (Byte) (bp [i]);
4968 }
4969 *xp = (Int4) bval;
4970 }
4971 MemFree (bp);
4972 break;
4973 }
4974 return xpoints;
4975 }
4976
4977 static void GphSentProc (BigScalar calldata, PrimDrawContext pdc)
4978 {
4979 BioseqPtr bsp;
4980 Int4 curScale;
4981 DrawInfoPtr dInfoPtr;
4982 GphSentPtr gsp;
4983 Int4 left;
4984 Int4 len, pos;
4985 RecT r;
4986 Int4 scaleX;
4987 Int4 scaleY;
4988 SeqGraphPtr sgp;
4989 BoxInfo tmpBox;
4990 Int4Ptr xpoints;
4991 Int4 tmpscaleX;
4992
4993 gsp = (GphSentPtr) calldata;
4994 if (gsp == NULL) return;
4995 sgp = gsp->sgp;
4996 if (sgp == NULL || sgp->values == NULL) return;
4997
4998 dInfoPtr = (DrawInfoPtr) pdc;
4999 tmpBox = gsp->box;
5000 if ( (tmpBox.left > dInfoPtr->scale.worldWindow.right ) ||
5001 (tmpBox.right < dInfoPtr->scale.worldWindow.left ) ||
5002 (tmpBox.top < dInfoPtr->scale.worldWindow.bottom) ||
5003 (tmpBox.bottom > dInfoPtr->scale.worldWindow.top ) )
5004 return;
5005
5006 if ( dInfoPtr->checked == FALSE ) {
5007 if ( tmpBox.left < dInfoPtr->scale.worldWindow16.left )
5008 tmpBox.left = dInfoPtr->scale.worldWindow16.left;
5009 if ( tmpBox.right > dInfoPtr->scale.worldWindow16.right )
5010 tmpBox.right = dInfoPtr->scale.worldWindow16.right;
5011 if ( tmpBox.top > dInfoPtr->scale.worldWindow16.top )
5012 tmpBox.top = dInfoPtr->scale.worldWindow16.top;
5013 if ( tmpBox.bottom < dInfoPtr->scale.worldWindow16.bottom )
5014 tmpBox.bottom = dInfoPtr->scale.worldWindow16.bottom;
5015 }
5016 scaleX = dInfoPtr->scale.scaleX;
5017 scaleY = dInfoPtr->scale.scaleY;
5018
5019 curScale = dInfoPtr->scale.scaleX;
5020 r.left = (Int2)((dInfoPtr->scale.offsetX + tmpBox.left ) / curScale);
5021 r.right = (Int2)((dInfoPtr->scale.offsetX + tmpBox.right) / curScale);
5022 curScale = dInfoPtr->scale.scaleY;
5023 r.top = (Int2)((dInfoPtr->scale.offsetY - tmpBox.top ) / curScale);
5024 r.bottom = (Int2)((dInfoPtr->scale.offsetY - tmpBox.bottom) / curScale);
5025
5026 bsp = BioseqFind (SeqLocId (sgp->loc));
5027 left = GetOffsetInBioseq (sgp->loc, bsp, SEQLOC_LEFT_END);
5028
5029 if (gsp->flagIsGUI)
5030 {
5031 len = tmpBox.right - tmpBox.left;
5032 pos = tmpBox.left - left;
5033 }
5034 else
5035 {
5036 /* for non-GUI, plot all the sgp values */
5037 len = sgp->numval;
5038 pos = 0;
5039 }
5040
5041 xpoints = MakeWorkingSeqGraphInt4Array (sgp->values, sgp->flags[2],
5042 pos, len,
5043 (Boolean) (sgp->flags[1] != 0),
5044 gsp->a, gsp->b);
5045 if (!gsp->flagIsGUI)
5046 {
5047 tmpscaleX = sgp->numval / (Int4) (tmpBox.right - tmpBox.left);
5048 if (tmpscaleX > scaleX)
5049 scaleX = tmpscaleX;
5050 }
5051
5052 PlotTheWorkingArray (xpoints, len, scaleX, gsp->min, r,
5053 gsp->red, gsp->green, gsp->blue,
5054 &(dInfoPtr->curattrib));
5055
5056 MemFree (xpoints);
5057 }
5058
5059 static void CleanGSP (BigScalar calldata)
5060 {
5061 GphSentPtr gsp;
5062
5063 gsp = (GphSentPtr) calldata;
5064 MemFree (gsp);
5065 }
5066
5067 static GphSentPtr AddGphSentinelToPicture (SeqGraphPtr sgp, BioseqPtr bsp,
5068 SegmenT pict, Int4 scaleX,
5069 Int4 top, Int2 start,
5070 Uint1Ptr uRGB, Boolean drawScale)
5071 {
5072 Int4 axis;
5073 GphSentPtr gsp;
5074 Int4 i;
5075 Boolean is_phrap;
5076 Int4 max;
5077 Int4 min;
5078 SegmenT seg;
5079 Char str [32];
5080 Int4 leftoff, rightoff;
5081
5082 if (sgp == NULL || bsp == NULL || pict == NULL)
5083 return NULL;
5084 gsp = MemNew (sizeof (GphSentData));
5085 if (gsp == NULL)
5086 return NULL;
5087 gsp->flagIsGUI = VibrantIsGUI ();
5088 if (uRGB != NULL)
5089 {
5090 gsp->red = uRGB[0];
5091 gsp->green = uRGB[1];
5092 gsp->blue = uRGB[2];
5093 }
5094 else
5095 {
5096 gsp->red = 0;
5097 gsp->green = 0;
5098 gsp->blue = 0;
5099 }
5100
5101 leftoff = GetOffsetInBioseq (sgp->loc, bsp, SEQLOC_LEFT_END);
5102 rightoff = GetOffsetInBioseq (sgp->loc, bsp, SEQLOC_RIGHT_END);
5103 if (!gsp->flagIsGUI)
5104 {
5105 leftoff /= scaleX;
5106 rightoff /= scaleX;
5107 }
5108 gsp->box.left = leftoff + start;
5109 gsp->box.right = rightoff - 1 + start;
5110
5111 gsp->sgp = sgp;
5112 gsp->a = sgp->a;
5113 gsp->b = sgp->b;
5114 is_phrap = (Boolean) (StringICmp (sgp->title, "Phrap Quality") == 0 ||
5115 StringICmp (sgp->title, "Phred Quality") == 0);
5116 switch (sgp->flags [2]) {
5117 case 1 :
5118 min = (Int4) sgp->min.realvalue;
5119 max = (Int4) sgp->max.realvalue;
5120 axis = (Int4) sgp->axis.realvalue;
5121 if (sgp->flags [1] != 0) {
5122 min = (Int4) (sgp->a * ((FloatHi) min) + sgp->b);
5123 max = (Int4) (sgp->a * ((FloatHi) max) + sgp->b);
5124 }
5125 break;
5126 case 2 :
5127 min = (Int4) sgp->min.intvalue;
5128 max = (Int4) sgp->max.intvalue;
5129 axis = (Int4) sgp->axis.intvalue;
5130 if (sgp->flags [1] != 0) {
5131 min = (Int4) (sgp->a * ((FloatHi) min) + sgp->b);
5132 max = (Int4) (sgp->a * ((FloatHi) max) + sgp->b);
5133 }
5134 break;
5135 case 3 :
5136 min = (Int4) sgp->min.intvalue;
5137 max = (Int4) sgp->max.intvalue;
5138 if (is_phrap) {
5139 min = MIN (0, min);
5140 max = MAX (100, max);
5141 }
5142 axis = (Int4) sgp->axis.intvalue;
5143 if (sgp->flags [1] != 0) {
5144 min = (Int4) (sgp->a * ((FloatHi) min) + sgp->b);
5145 max = (Int4) (sgp->a * ((FloatHi) max) + sgp->b);
5146 }
5147 break;
5148 default :
5149 min = (Int4) 0;
5150 max = (Int4) 100;
5151 axis = (Int4) 0;
5152 break;
5153 }
5154 gsp->seg = seg = CreateSegment (pict, 0, 0);
5155 gsp->bottom = top - (max - min) - 20;
5156
5157 if (drawScale && sgp->title != NULL) /* StringHasNoText -- vibforms */
5158 {
5159 if (StringLen (sgp->title) > 0)
5160 {
5161 AddLabel (seg,
5162 /* (gsp->box.left + gsp->box.right) / 2, */
5163 (start + bsp->length) / 2,
5164 top,
5165 sgp->title, SMALL_TEXT, 0, MIDDLE_CENTER, 0);
5166 }
5167 }
5168
5169 top -= 10;
5170 gsp->box.top = top;
5171 gsp->box.bottom = gsp->bottom;
5172 gsp->min = min;
5173 gsp->max = max;
5174 gsp->axis = axis;
5175 gsp->bottom += 10;
5176
5177 if (drawScale)
5178 {
5179 if (is_phrap)
5180 {
5181 for (i = 0; i <=100; i += 20) {
5182 sprintf (str, "%ld", (long) i);
5183 AddLabel (seg, gsp->box.left, gsp->bottom + i, str,
5184 SMALL_TEXT, 5, MIDDLE_LEFT, 0);
5185 }
5186 }
5187 else
5188 {
5189 sprintf (str, "%ld", (long) max);
5190 AddLabel (seg, gsp->box.left, top-10, str,
5191 SMALL_TEXT, 5, MIDDLE_LEFT, 0);
5192 sprintf (str, "%ld", (long) min);
5193 AddLabel (seg, gsp->box.left, gsp->bottom-10, str,
5194 SMALL_TEXT, 5, MIDDLE_LEFT, 0);
5195 if (min < 0 && max > 0)
5196 {
5197 sprintf (str, "%ld", 0L);
5198 AddLabel (seg, gsp->box.left, gsp->bottom-min-10, str,
5199 SMALL_TEXT, 5, MIDDLE_LEFT, 0);
5200 }
5201 }
5202 }
5203
5204 gsp->snt = AddSntRectangle (seg, gsp->box.left, gsp->box.top,
5205 gsp->box.right, gsp->box.bottom,
5206 GphSentProc, (BigScalar) gsp, CleanGSP, 0);
5207 return gsp;
5208 }
5209
5210 static void VisitAndListGraphs (SeqGraphPtr sgp, Pointer userdata)
5211
5212 {
5213 GphSentPtr gsp;
5214 ViewerContextPtr vContext;
5215 Boolean drawScale = FALSE;
5216
5217 vContext = (ViewerContextPtr) userdata;
5218 if (vContext == NULL) return;
5219
5220 if (vContext->gphseg == NULL) {
5221 vContext->gphseg = CreateSegment (vContext->drawOnMe, 0, 0);
5222
5223 /*
5224 this first time 'drawScale' stuff here and in AddGphSentinelToPicture
5225 assumes that all the graphs on this bioseq are the same type
5226 use the same legend and have the same label.
5227 */
5228 AddSegRect (vContext->gphseg, FALSE, 0); /* draw box around all the graphs, not each one individually */
5229 drawScale = TRUE; /* only draw scale on the first graph */
5230 }
5231
5232 gsp = AddGphSentinelToPicture (sgp, vContext->BSP, vContext->gphseg,
5233 vContext->viewScale, vContext->gphyOffset,
5234 0, NULL, drawScale);
5235 if (gsp == NULL) return;
5236 vContext->gphheight = MAX (vContext->gphheight, gsp->box.top - gsp->box.bottom);
5237 }
5238
5239 static Int4 DrawGraphs (
5240 Int4 yOffset,
5241 ViewerContextPtr vContext
5242 )
5243
5244 {
5245 vContext->gphheight = 0;
5246 vContext->gphseg = NULL;
5247 vContext->gphyOffset = yOffset - 16; /* (workaround) drawing the graphs touches some pixels above gphyOffset */
5248
5249 VisitGraphsOnBsp (vContext->BSP, (Pointer) vContext, VisitAndListGraphs);
5250
5251 return vContext->gphheight + 16;
5252 }
5253
5254 static void ResetFilterState (
5255 FilterProcessStatePtr FPSP
5256 )
5257
5258 {
5259 FilterItemPtr FIP;
5260 ViewerContextPtr vContext;
5261
5262
5263 if (FPSP == NULL) return;
5264 vContext = FPSP->vContext;
5265 FIP = FPSP->currentFIP;
5266 MemSet (&FPSP->state, 0, sizeof (FilterState));
5267 if (FIP->Type == FeatureFilter) {
5268 FPSP->state.feat.currentRFIPblockVNP = vContext->featVNP;
5269 }
5270 }
5271
5272
5273 /*
5274 Order by accession (label), strand and location
5275 for sorting.
5276 */
5277 static int LIBCALLBACK CompareAlignNameLoc(VoidPtr ptr1, VoidPtr ptr2)
5278 {
5279 SeqAlignSortInfoPtr saip1, saip2;
5280 Int2 labelcomp;
5281
5282 if (ptr1 != NULL && ptr2 != NULL) {
5283 saip1 = (SeqAlignSortInfoPtr) ptr1;
5284 saip2 = (SeqAlignSortInfoPtr) ptr2;
5285
5286 labelcomp = StrNCmp(saip1->label, saip2->label, MAX_ALIGN_SORT_LABEL);
5287 if (labelcomp != 0)
5288 return labelcomp;
5289
5290 if (saip1->strand < saip2->strand)
5291 return -1;
5292 if (saip1->strand > saip2->strand)
5293 return 1;
5294
5295 if (saip1->start < saip2->start)
5296 return -1;
5297 if (saip1->start > saip2->start)
5298 return 1;
5299 if (saip1->stop < saip2->stop)
5300 return -1;
5301 if (saip1->stop > saip2->stop)
5302 return 1;
5303 }
5304 return 0;
5305 }
5306
5307 static int LIBCALLBACK ScoreCompare( VoidPtr p1, VoidPtr p2)
5308 {
5309 if (p1 != NULL && p2 != NULL) {
5310 Int4 i1 = * (Int4Ptr) p1;
5311 Int4 i2 = * (Int4Ptr) p2;
5312
5313 return i1 - i2;
5314 }
5315 return 0;
5316 }
5317
5318 /*
5319 Take a number (rawscore) between min and max (inclusive)
5320 and linearly scale it into a number from 1 to ACCUMVALUE_MAX/256.
5321 We divide by 256 since we will be adding these numbers together when smearing.
5322 Hopefully we won't have more than 256 with large scores at any one point :)
5323 Do not call if min >= max.
5324 */
5325 AccumValue_t NormaliseScore(Int4 rawscore, Int4 min, Int4 max)
5326 {
5327 AccumValue_t retval;
5328 FloatHi fscore = rawscore - min;
5329 fscore *= ACCUMVALUE_MAX / 256 - 1;
5330 fscore /= (max - min);
5331 retval = fscore + 1;
5332 return retval;
5333 }
5334
5335
5336 static void FindCutoffScore(SeqAlignPtr sap, Int4 alignCnt, AlignmentFilterStatePtr afsp)
5337 {
5338 SeqAlignPtr sapIter;
5339 Int4Ptr allScores;
5340 Int4 i;
5341 /* Int4 cutoffScore; */ /* not normalized */
5342
5343 /* make array to hold all the scores. */
5344 allScores = MemNew(alignCnt * sizeof(Int4));
5345 if (allScores == NULL)
5346 return;
5347
5348 /* get all the scores */
5349 i = 0;
5350 for (sapIter = sap; sapIter != NULL; sapIter = sapIter->next) {
5351 allScores[i++] = WeightFromAlignScore(sapIter, afsp->scoreType);
5352 }
5353
5354 /* sort them */
5355 HeapSort ( allScores, alignCnt, sizeof(Int4), ScoreCompare);
5356
5357 /* find, normalise and return the cutoffPercent score
5358 and the min & max scores so we can normalise the rest of the scores later.
5359 */
5360 afsp->minScore = allScores[0];
5361 afsp->maxScore = allScores[alignCnt - 1];
5362 afsp->cutoffScoreHi = ACCUMVALUE_MAX; /* could add other controls to set this. */
5363 /* Cutoff by actual score, not by percentage.
5364 if (afsp->cutoffPercent == 100 ||
5365 afsp->scoreType == NLM_SCORE_COUNT ||
5366 afsp->minScore >= afsp->maxScore ) {
5367 afsp->cutoffScore = 0;
5368 }
5369 else {
5370 cutoffScore = allScores[ (100 - afsp->cutoffPercent) * alignCnt/100 ];
5371 afsp->cutoffScore = NormaliseScore(cutoffScore, afsp->minScore, afsp->maxScore);
5372 }
5373 */
5374 MemFree(allScores);
5375 }
5376
5377
5378 /* Gather all the SeqAligns whose normalised score is less than the cutoff score */
5379 static void GatherAlignInfo(
5380 SeqAlignPtr sap,
5381 Int4 alignCnt,
5382 SeqIdPtr bioSeqId,
5383 AlignmentFilterStatePtr afsp
5384 )
5385 {
5386 SeqAlignSortInfoPtr infoArray = NULL;
5387 Int4 infoIndex;
5388 SeqAlignPtr sapIter;
5389 Int4 nrows, alignRow;
5390 Int4 start, stop, swap;
5391 Uint1 strand;
5392 Int4 rawScore;
5393 AccumValue_t normScore;
5394
5395 infoArray = MemNew(alignCnt * sizeof(SeqAlignSortInfo));
5396 if (infoArray == NULL)
5397 return;
5398
5399 infoIndex = 0;
5400 for (sapIter = sap; sapIter != NULL; sapIter = sapIter->next)
5401 {
5402 /* is this alignment in the top percentile? */
5403 if (afsp->scoreType != NLM_SCORE_COUNT && afsp->minScore < afsp->maxScore ) {
5404 rawScore = WeightFromAlignScore(sapIter, afsp->scoreType);
5405 normScore = NormaliseScore( rawScore, afsp->minScore, afsp->maxScore);
5406 /* if (normScore < afsp->cutoffScore || afsp->cutoffScoreHi < normScore) */
5407 if (rawScore < afsp->cutoffScore || afsp->cutoffScoreHi < rawScore)
5408 {
5409 continue;
5410 }
5411 } else {
5412 normScore = 1;
5413 }
5414
5415 if (!AlnMgr2IndexSingleChildSeqAlign (sapIter)) continue; /* make sure we are indexed */
5416
5417 /* get dimensions of this alignment (number of sequences aligned) */
5418 nrows = AlnMgr2GetNumRows(sapIter);
5419 if (nrows < 1) {
5420 nrows = sapIter->dim;
5421 }
5422 if (nrows != 2) { /* can't handle 3+ dimension alignments */
5423 continue;
5424 }
5425
5426 /* Get the beginning and end points of this alignment in Bioseq coords. */
5427 if (sapIter->segtype != SAS_STD) {
5428 /* not Std Seg alignment, use indexed functions */
5429 alignRow = AlnMgr2GetFirstNForSipList (sapIter, bioSeqId);
5430 if (alignRow == -1) {
5431 continue;
5432 }
5433 AlnMgr2GetNthSeqRangeInSA(sapIter, alignRow, &start, &stop);
5434 strand = AlnMgr2GetNthStrand(sapIter, alignRow);
5435 } else {
5436 /* Std Seg alignment. Use special function */
5437 AlnMgr2GetSeqRangeForSipInSAStdSeg(sapIter, bioSeqId, &start, &stop, &strand);
5438 }
5439 if (start < 0) {
5440 continue;
5441 }
5442 if (stop < start) {
5443 swap = stop;
5444 stop = start;
5445 start = swap;
5446 }
5447
5448 /* populate the structure we will use to sort on. */
5449 infoArray[infoIndex].start = start;
5450 infoArray[infoIndex].stop = stop;
5451 infoArray[infoIndex].strand = strand;
5452 infoArray[infoIndex].sap = sapIter;
5453 infoArray[infoIndex].normScore = normScore;
5454 if (!SeqAlignContentLabel(sapIter, bioSeqId, infoArray[infoIndex].label, MAX_ALIGN_SORT_LABEL, PRINTID_TEXTID_ACC_VER)) {
5455 infoArray[infoIndex].label[0] = 0;
5456 }
5457 ++infoIndex;
5458 }
5459
5460 afsp->alignSortedLen = infoIndex;
5461
5462 if (infoIndex == 0) {
5463 MemFree(infoArray);
5464 infoArray = NULL;
5465 }
5466 afsp->alignSorted = infoArray;
5467 }
5468
5469 static Boolean AlignmentFilterStateInit(
5470 SeqAlignPtr sap, /* the head of hte chain of sequence alignments from the bioseq */
5471 SeqIdPtr sid, /* the id of the bioseq so we know how we are viewing the alignments */
5472 AlignmentFilterStatePtr afsp, /* What we are initializing. */
5473 GraphicViewExtrasPtr extras /* contains the score cuttoff percentage and the kind of scores we use */
5474 )
5475 {
5476 SeqAlignPtr sapIter;
5477 Int4 alignCnt;
5478 Uint1 scoreType = NLM_SCORE_COUNT;
5479 Int2 i = 0;
5480
5481 if (sap == NULL || sid == NULL || afsp == NULL)
5482 return FALSE;
5483
5484 /* what kind of score will we use to weight the alignments? */
5485 if (extras && extras->alignScoreName) {
5486 scoreType = StringIndexInStringList (extras->alignScoreName, AlnScoreStrings);
5487 if (scoreType >= NLM_SCORE_TOOBIG)
5488 scoreType = NLM_SCORE_COUNT;
5489 }
5490 afsp->scoreType = scoreType;
5491
5492 /* what percentile does an alignments score have to be to be displayed? */
5493 if (extras && extras->alignScoreCutoff) {
5494 i = StringIndexInStringList (extras->alignScoreCutoff, AlnScoreCutoffStrings);
5495 if (i < 0 || DIM (AlnScoreCutoffValues) <= i )
5496 i = 0;
5497 }
5498 /* afsp->cutoffPercent = AlnScoreCutoffValues[i]; */
5499 if (AlnScoreCutoffValues[i] < 0) {
5500 afsp->scoreType = NLM_SCORE_COUNT;
5501 } else {
5502 afsp->scoreType = NLM_SCORE_BIT;
5503 afsp->cutoffScore = AlnScoreCutoffValues[i];
5504 }
5505
5506 /* how many alignments? Count one time now */
5507 alignCnt = 0;
5508 for (sapIter = sap; sapIter != NULL; sapIter = sapIter->next) {
5509 ++alignCnt;
5510 }
5511
5512 FindCutoffScore(sap, alignCnt, afsp);
5513
5514 GatherAlignInfo(sap, alignCnt, sid, afsp);
5515 if (afsp->alignSorted == NULL || afsp->alignSortedLen == 0) {
5516 /* couldn't allocate memory, or no alignments - nothing to do. */
5517 return FALSE;
5518 }
5519 /* sort the alignments, first by accession, then by location on the bioseq. */
5520 HeapSort(afsp->alignSorted, afsp->alignSortedLen, sizeof(SeqAlignSortInfo), CompareAlignNameLoc);
5521 afsp->alignIndex = 0;
5522
5523 return TRUE;
5524 }
5525
5526 static Boolean AlignmentFilterStateDone(AlignmentFilterStatePtr afsp)
5527 {
5528 if (afsp->alignSorted != NULL &&
5529 afsp->alignIndex < afsp->alignSortedLen)
5530 return FALSE;
5531 return TRUE;
5532 }
5533
5534
5535 static void AlignmentFilterStateFree( AlignmentFilterStatePtr afsp)
5536 {
5537 if (afsp->alignSorted != NULL)
5538 MemFree(afsp->alignSorted);
5539 afsp->alignSorted = NULL;
5540 afsp->alignSortedLen = 0;
5541 }
5542
5543
5544
5545 static Int4 WeightFromAlignScore(SeqAlignPtr sap, Uint1 scoreType)
5546 {
5547 Int4 weight = 1;
5548 Int4 score, number;
5549 Nlm_FloatHi bit_score, evalue;
5550
5551 if (GetScoreAndEvalue(sap, &score, &bit_score, &evalue, &number)) {
5552 /* evaluate scores and get weight */
5553 switch (scoreType) {
5554 case NLM_SCORE_SCORE :
5555 weight = score;
5556 break;
5557 case NLM_SCORE_BIT :
5558 weight = bit_score;
5559 break;
5560 case NLM_SCORE_EVALUE :
5561 if (evalue > 0) {
5562 weight = -log(evalue);
5563 }
5564 else { /* 0 is the best value. */
5565 /*
5566 We can't use the maxScore here since we do not know it yet
5567 since this is where we collect the values.
5568 Our sample data has -log(evalue) ranging from 25 - 429
5569 so 500 just has to be bigger than anything else we will encounter.
5570 It will get normalised latter with it as the maxScore.
5571
5572 We could put a special sentinel value (very large or negative) here
5573 that gets replaced with the real maxScore later.
5574 (But then make sure it gets skipped when calculating the max and min).
5575 */
5576 weight = 500;
5577 }
5578 break;
5579 case NLM_SCORE_NUMBER :
5580 weight = number;
5581 break;
5582 case NLM_SCORE_COUNT :
5583 default:
5584 weight = 1;
5585 }
5586 }
5587
5588 return weight;
5589 }
5590
5591
5592 /*
5593 Interval Accumulator
5594 An object which can add or in some way (specified by accumop) intervals on a sequence,
5595 then from which can be extracted the resulting intervals.
5596 */
5597
5598 #define ACCUMVALUE_GAP -1
5599
5600 typedef enum AccumlatorOp {
5601 NLM_SUM_WEIGHT = 0,
5602 NLM_MAX_WEIGHT
5603 } AccumulatorOp;
5604
5605
5606 typedef struct AccumNode_s {
5607 Uint4 coord;
5608 AccumValue_t weight;
5609 struct AccumNode_s * next; /* makes a single-linked list. */
5610 } AccumNode, *AccumNodePtr;
5611
5612
5613 static AccumNodePtr
5614 InsertNodeAfter(AccumNodePtr node, Uint4 coord, AccumValue_t weight)
5615 {
5616 AccumNodePtr new_node = (AccumNodePtr) Nlm_MemNew(sizeof(AccumNode));
5617 if (new_node == NULL) return NULL;
5618
5619 new_node->coord = coord;
5620 new_node->weight = weight;
5621 if (node != NULL) {
5622 new_node->next = node->next;
5623 node->next = new_node;
5624 }
5625 return new_node;
5626 }
5627
5628 static AccumNodePtr
5629 AppendNode(AccumNodePtr head, Uint4 coord, AccumValue_t weight)
5630 {
5631 while (head->next != NULL)
5632 head = head->next;
5633 return InsertNodeAfter(head, coord, weight);
5634 }
5635
5636 static void
5637 FreeAccumNodes(AccumNodePtr node)
5638 {
5639 AccumNodePtr del_me;
5640 while (node) {
5641 del_me = node;
5642 node = node->next;
5643 Nlm_MemFree(del_me);
5644 }
5645 }
5646
5647 static void
5648 AccumulateWeight(AccumNodePtr node, AccumValue_t w2, AccumulatorOp op)
5649 {
5650 AccumValue_t w1;
5651
5652 if (w2 == 0)
5653 return;
5654
5655 w1 = node->weight;
5656
5657 /* gap trumps 0, any weight trumps a gap. */
5658 if ((w1 == ACCUMVALUE_GAP && w2 <= 0) ||
5659 (w2 == ACCUMVALUE_GAP && w1 <= 0)) {
5660 node->weight = ACCUMVALUE_GAP;
5661 } else if (w1 == ACCUMVALUE_GAP){
5662 node->weight = w2;
5663 } else if (w2 == ACCUMVALUE_GAP){
5664 node->weight = w1;
5665 } else if (op == NLM_MAX_WEIGHT) {
5666 /* max of the weights. */
5667 if (w2 > w1)
5668 node->weight = w2;
5669 } else {
5670 /* NLM_SUM_WEIGHT */
5671 if (node->weight < ACCUMVALUE_MAX - w2) /* avoid overflow. */
5672 node->weight += w2;
5673 else
5674 node->weight = ACCUMVALUE_MAX;
5675 }
5676 }
5677
5678
5679 typedef struct IntervalAccumulator {
5680 AccumNodePtr nodes;
5681 AccumulatorOp accumOp;
5682 AccumValue_t maxWeight;
5683 } IntervalAccumulator, PNTR IntervalAccumulatorPtr;
5684
5685
5686 static IntervalAccumulatorPtr
5687 NewIntervalAccumulator(Uint4 len, AccumulatorOp op)
5688 {
5689 AccumNodePtr tail_node;
5690 IntervalAccumulatorPtr IAP;
5691
5692 IAP = (IntervalAccumulatorPtr) Nlm_MemNew(sizeof(IntervalAccumulator));
5693 if (IAP == NULL) return NULL;
5694 IAP->nodes = InsertNodeAfter(NULL, 0, 0); /* header node. coord 0. */
5695 if (IAP->nodes == NULL) {
5696 Nlm_MemFree(IAP);
5697 return NULL;
5698 }
5699 tail_node = AppendNode(IAP->nodes, len, 0); /* tail node. max coord. */
5700 if (tail_node == NULL) {
5701 FreeAccumNodes(IAP->nodes);
5702 Nlm_MemFree(IAP);
5703 return NULL;
5704 }
5705 IAP->accumOp = op;
5706 return IAP;
5707 }
5708
5709 static void
5710 FreeIntervalAccumulator(IntervalAccumulatorPtr *iapp)
5711 {
5712 IntervalAccumulatorPtr IAP;
5713
5714 if (iapp == NULL || *iapp == NULL) return;
5715 IAP = *iapp;
5716 FreeAccumNodes(IAP->nodes);
5717 Nlm_MemFree(IAP);
5718 *iapp = NULL;
5719 }
5720
5721
5722 /* merge in a list of segments. */
5723 static void
5724 AccumSegments(IntervalAccumulatorPtr accum, AccumNodePtr new_nodes)
5725 {
5726
5727 AccumNodePtr prev_node = accum->nodes; /* add our node right before this one. */
5728 AccumValue_t old_weight = 0; /* the weight of the last old node passed. */
5729 AccumValue_t in_weight = 0; /* the weight of the last new node entered. */
5730
5731 AccumNodePtr in_node;
5732
5733 in_node = new_nodes;
5734 /* skip header node in the input, if we have one. */
5735 if (in_node->weight == 0 && in_node->coord == 0)
5736 in_node = in_node->next;
5737
5738 for (; in_node != NULL; in_node = in_node->next) {
5739
5740 /* we are adding in_node now. */
5741
5742 /* Find where to insert in_node. */
5743 /* while extending the range of the last node added. */
5744 while (prev_node->next != NULL &&
5745 in_node->coord > prev_node->next->coord) {
5746 prev_node = prev_node->next;
5747 old_weight = prev_node->weight;
5748 AccumulateWeight(prev_node, in_weight, accum->accumOp);
5749 }
5750 in_weight = in_node->weight;
5751
5752 /* insert at node. */
5753 if (in_node->coord == prev_node->next->coord) {
5754 prev_node = prev_node->next;
5755 old_weight = prev_node->weight;
5756 AccumulateWeight(prev_node, in_weight, accum->accumOp);
5757 } else {
5758 AccumulateWeight(in_node, old_weight, accum->accumOp);
5759 InsertNodeAfter(prev_node, in_node->coord, in_node->weight);
5760 prev_node = prev_node->next; /* skip the one we just inserted. */
5761 }
5762 }
5763
5764 ASSERT(in_weight > 0);
5765 /* extend last range to the end of the accumulator.
5766 if (in_weight > 0) {
5767 while (prev_node->next != NULL) {
5768 prev_node = prev_node->next;
5769 AccumulateWeight(prev_node, in_weight, accum->accumOp);
5770 }
5771 }
5772 */
5773 }
5774
5775
5776
5777
5778 /* Retrieve information. */
5779
5780 static AccumValue_t
5781 GetMaxWeight(const IntervalAccumulatorPtr IAP)
5782 {
5783 AccumNodePtr node;
5784 AccumValue_t max_weight = 0;
5785
5786 for (node = IAP->nodes->next; /* skip the header node. */
5787 node->next != NULL; /* skip the last (dummy) node. */
5788 node = node->next) {
5789 if (max_weight < node->weight)
5790 max_weight = node->weight;
5791 }
5792 return max_weight;
5793 }
5794
5795
5796 static AccumNodePtr
5797 GetIntervalFromAccumulator(
5798 IntervalAccumulatorPtr iap,
5799 AccumNodePtr nextPos,
5800 Uint4Ptr startp,
5801 Uint4Ptr stopp,
5802 AccumValuePtr_t weightp
5803 )
5804 {
5805 Uint4 start, stop;
5806 AccumValue_t weight = 0;
5807
5808 if (NULL == iap && nextPos == NULL) return NULL;
5809
5810 if (iap && nextPos == NULL)
5811 nextPos = iap->nodes->next; /* skip leading 0,0 node. */
5812
5813 /* are we at the end? */
5814 if (nextPos == NULL || nextPos->next == NULL) /* nextPos == NULL would be an error. */
5815 return NULL;
5816
5817 start = nextPos->coord;
5818 weight = nextPos->weight;
5819
5820 /* go to the next node. */
5821 nextPos = nextPos->next;
5822 /* skip redundant nodes. Those with the same weight as the preceding one. */
5823 while (nextPos->next && nextPos->weight == weight)
5824 nextPos = nextPos->next;
5825 stop = nextPos->coord;
5826
5827 if (startp) *startp = start;
5828 if (stopp) *stopp = stop;
5829 if (weightp) *weightp = weight;
5830
5831 return nextPos;
5832 }
5833
5834
5835
5836 static Uint2 SmearAlignments (
5837 FilterProcessStatePtr FPSP,
5838 ViewerContextPtr vContext
5839 )
5840
5841 {
5842 SeqAlignPtr SAP;
5843 BioseqPtr BSP;
5844 SeqIdPtr SID;
5845 AppearanceItemPtr AIP;
5846 FilterItemPtr FIP;
5847
5848 AlignmentFilterStatePtr alignSP;
5849 SeqAlignSortInfoPtr alignSorted;
5850 Int4 alignSortedLen;
5851 Int4 alignIndex;
5852 Int4 start, stop, maxDensity;
5853 Uint1 color[3], col;
5854 Uint1 minCol = 224; /* density == min -> light gray */
5855 Uint1 maxCol = 0; /* density == max -> black */
5856
5857 IntervalAccumulatorPtr plusIAP = NULL, minusIAP = NULL; /* Smear accumulators */
5858 AccumNodePtr thisAlignSegs = NULL; /* input to the accumulators per alignment */
5859 AccumNodePtr accumPos; /* output iterator on the accumulators. */
5860 Uint4 begin, end;
5861 Int4 space_pixs;
5862 AccumValue_t weight;
5863 AccumValue_t density;
5864
5865 Boolean smearedAlignsPlus = FALSE, smearedAlignsMinus = FALSE;
5866 AccumulatorOp sumOrMax = NLM_SUM_WEIGHT;
5867 Boolean separateStrands;
5868 const Uint1 minDensity = 1; /* minimum density we will display. */
5869 SegmenT seg;
5870 CharPtr annotName;
5871 Int4 height = 0;
5872 Uint2 space_line_height = 2;
5873
5874 if (FPSP == NULL || vContext == NULL) return 0;
5875 alignSP = &FPSP->state.align;
5876 alignSorted = alignSP->alignSorted;
5877 alignSortedLen = alignSP->alignSortedLen;
5878
5879 /* get the Appearance item for alignments */
5880 AIP = vContext->AppPtr->FeaturesAppearanceItem[APPEARANCEITEM_Alignment];
5881
5882 /* get the bioseq's id for picking out the right part of the alignments */
5883 BSP = vContext->BSP;
5884 SID = BSP->id;
5885
5886 /* Get this annotation's name to decide how to display this. */
5887 annotName = GetSeqAnnotName(vContext->currentSAP);
5888 separateStrands = FALSE;
5889 if (StringStr(annotName, "BLASTX - swissprot"))
5890 separateStrands = TRUE;
5891 else if (StringStr(annotName, "BLASTN - mrna"))
5892 separateStrands = TRUE;
5893 else if (StringStr(annotName, "BLASTN - est"))
5894 separateStrands = FALSE;
5895 else if (StringStr(annotName, "BLASTN - nr"))
5896 separateStrands = FALSE;
5897
5898 plusIAP = NewIntervalAccumulator(vContext->seqLength, sumOrMax);
5899 if (plusIAP == NULL) goto smearAlignmentsDone;
5900 minusIAP = NewIntervalAccumulator(vContext->seqLength, sumOrMax);
5901 if (minusIAP == NULL) goto smearAlignmentsDone;
5902
5903 /*
5904 for all the sorted alignments (from a single annotation in this BioSeq)
5905 treat all alignments with the same accession as one alignment
5906 */
5907 for (alignIndex = 0;
5908 alignIndex < alignSortedLen;
5909 ++alignIndex)
5910 {
5911 AlignSegIterator asi;
5912 Int4 nsegs;
5913 Uint1 segType;
5914 Uint1 strand;
5915
5916 SAP = alignSorted[alignIndex].sap;
5917
5918 /* sanity checks */
5919 if (alignSorted[alignIndex].start < 0 || alignSorted[alignIndex].stop < 0)
5920 continue;
5921
5922 weight = alignSorted[alignIndex].normScore;
5923 /* if (weight == 0)
5924 continue;
5925 */
5926 /*
5927 at the begining of an alignment
5928 if there was another alignment before this one,
5929 with the same accession, strand and that alignment ended before this one begins,
5930 treat that space as a gap.
5931 */
5932 if (alignIndex > 0 &&
5933 StrNCmp(alignSorted[alignIndex - 1].label, alignSorted[alignIndex].label, MAX_ALIGN_SORT_LABEL) == 0 &&
5934 alignSorted[alignIndex - 1].strand == alignSorted[alignIndex].strand &&
5935 alignSorted[alignIndex - 1].stop < alignSorted[alignIndex].start)
5936 {
5937 start = alignSorted[alignIndex - 1].stop;
5938 AppendNode(thisAlignSegs, start, ACCUMVALUE_GAP );
5939 } else {
5940 /* we are starting a new alignment. */
5941 /* Smear the last alignment's segments. */
5942 if (alignIndex > 0) {
5943 AppendNode(thisAlignSegs, alignSorted[alignIndex - 1].stop, 0);
5944 if (alignSorted[alignIndex - 1].strand != Seq_strand_minus || !separateStrands )
5945 AccumSegments(plusIAP, thisAlignSegs);
5946 else
5947 AccumSegments(minusIAP, thisAlignSegs);
5948 }
5949
5950 /* Prepare space for the new alignment's segment info. */
5951 FreeAccumNodes(thisAlignSegs);
5952 thisAlignSegs = InsertNodeAfter(NULL, 0, 0);
5953 }
5954
5955 /*
5956 for each segment in an alignment
5957 if the segment is block or a gap map it appropriately in the density arrays.
5958 */
5959 nsegs = AlignSegIteratorCreate(SAP, SID, &asi);
5960 if (nsegs == 0)
5961 continue;
5962 while (AlignSegIteratorNext(&asi, &start, &stop, &strand, &segType))
5963 {
5964 if (segType == AM_INSERT || start < 0 || stop < 0)
5965 continue;
5966
5967 if (segType == AM_GAP ) { /* a gap */
5968 AppendNode(thisAlignSegs, start, ACCUMVALUE_GAP );
5969 }
5970 else if (segType == AM_SEQ) { /* a real alignment. */
5971 AppendNode(thisAlignSegs, start, weight );
5972 if (strand != Seq_strand_minus || !separateStrands) {
5973 smearedAlignsPlus = TRUE;
5974 } else {
5975 smearedAlignsMinus = TRUE;
5976 }
5977 }
5978
5979 } /* for all segments in an alignment */
5980 } /* for all alignments in an annotation */
5981
5982 /* Smear the last alignment's segments. */
5983 if (alignIndex > 0) {
5984 AppendNode(thisAlignSegs, alignSorted[alignIndex - 1].stop, 0);
5985 if (alignSorted[alignIndex - 1].strand != Seq_strand_minus || !separateStrands )
5986 AccumSegments(plusIAP, thisAlignSegs);
5987 else
5988 AccumSegments(minusIAP, thisAlignSegs);
5989 }
5990
5991 if (!smearedAlignsPlus && !smearedAlignsMinus)
5992 goto smearAlignmentsDone; /* there was nothing to show. */
5993
5994 DrawNamedAnnotBox(FPSP);
5995 FIP = (FilterItemPtr) FPSP->currentFilterVNP->data.ptrvalue;
5996 DrawFilterItemBoxLabel(FPSP, FIP);
5997
5998 seg = CreateSegment ( vContext->drawOnMe, 0, 0);
5999
6000 if (smearedAlignsPlus || !separateStrands) {
6001 height += space_line_height;
6002 maxDensity = GetMaxWeight(plusIAP);
6003
6004 accumPos = GetIntervalFromAccumulator(plusIAP, NULL, &begin, &end, &density);
6005 while (accumPos != NULL) {
6006
6007 if (density > 0 && density != ACCUMVALUE_GAP) {
6008 /* convert (1 - maxDensity) to "color" number (224 - 0) */
6009 if (maxDensity == minDensity) {
6010 col = minCol;
6011 } else {
6012 col = (Uint1) (minCol + (density - minDensity)*(maxCol - minCol)/(maxDensity - minDensity));
6013 }
6014 color [2] = color [1] = color [0] = col; /* set to shade of grey. (minCol = 224) */
6015 AddAttribute (seg, COLOR_ATT, color, 0, 0, 1, 0);
6016 AddRectangle (seg, begin, FPSP->ceiling - height,
6017 end, FPSP->ceiling - height - (AIP->Height), NO_ARROW, TRUE, 0);
6018 }
6019 else if (density == ACCUMVALUE_GAP) {
6020 AddAttribute (seg, COLOR_ATT, NULL, 0, 0, 1, 0);
6021 AddLine (seg, begin, FPSP->ceiling - height - (AIP->Height)/2,
6022 end, FPSP->ceiling - height - (AIP->Height)/2, NO_ARROW, 0);
6023 } else { /* density == 0 */
6024 /* put a small line above spaces between blocks we draw */
6025 if (0 < begin && end < vContext->seqLength) { /* ignore gaps at beginning and end of bioseq */
6026 ASSERT(density == 0);
6027 space_pixs = (end - begin)/vContext->viewScale;
6028 /* if (3 <= space_pixs && space_pixs <= 10 && end < vContext->seqLength) { */
6029 if (space_pixs <= 20) { /* don't draw this line if it is more than 20 pixels long. */
6030 if (space_pixs < 3) { /* make sure bar is always at least 3 pixels long */
6031 int mid_point = end + begin;
6032 end = (mid_point + 3 * vContext->viewScale) /2;
6033 begin = (mid_point - 3 * vContext->viewScale) /2;
6034 }
6035 AddAttribute (seg, COLOR_ATT, NULL, 0, 0, 1, 0);
6036 AddLine (seg, begin, FPSP->ceiling + space_line_height,
6037 end - vContext->viewScale, FPSP->ceiling + space_line_height, NO_ARROW, 0);
6038 }
6039 }
6040 }
6041 accumPos = GetIntervalFromAccumulator(NULL, accumPos, &begin, &end, &density);
6042 }
6043 /* put a little arrow to show this is the plus strand */
6044 if (separateStrands) {
6045 AddAttribute (seg, COLOR_ATT, NULL, 0, 0, 1, 0);
6046 AddTextLabel (seg, 0 * vContext->viewScale, FPSP->ceiling - height - (AIP->Height)/2,
6047 ">", FIP->GroupLabelFont, 1, MIDDLE_LEFT, 0);
6048 }
6049 height += AIP->Height + FIP->IntraRowPaddingPixels;
6050 }
6051
6052 if (smearedAlignsMinus) {
6053 maxDensity = GetMaxWeight(minusIAP);
6054
6055 accumPos = GetIntervalFromAccumulator(minusIAP, NULL, &begin, &end, &density);
6056 while (accumPos != NULL) {
6057
6058 if (density > 0 && density != ACCUMVALUE_GAP) {
6059 /* convert (1 - maxDensity) to "color" number (224 - 0) */
6060 if (maxDensity == minDensity) {
6061 col = minCol;
6062 } else {
6063 col = (Uint1) (minCol + (density - minDensity)*(maxCol - minCol)/(maxDensity - minDensity));
6064 }
6065 color [2] = color [1] = color [0] = col; /* set to shade of grey. (minCol = 224) */
6066 AddAttribute (seg, COLOR_ATT, color, 0, 0, 1, 0);
6067 AddRectangle (seg, begin, FPSP->ceiling - height,
6068 end, FPSP->ceiling - height - (AIP->Height), NO_ARROW, TRUE, 0);
6069 }
6070 else if (density == ACCUMVALUE_GAP) {
6071 AddAttribute (seg, COLOR_ATT, NULL, 0, 0, 1, 0);
6072 AddLine (seg, begin, FPSP->ceiling - height - (AIP->Height)/2,
6073 end, FPSP->ceiling - height - (AIP->Height)/2, NO_ARROW, 0);
6074 } else {
6075 /* put a small line above spaces between blocks we draw */
6076 if (0 < begin && end < vContext->seqLength) { /* ignore gaps at beginning and end of bioseq */
6077 ASSERT(density == 0);
6078 space_pixs = (end - begin)/vContext->viewScale;
6079 /* if (3 <= space_pixs && space_pixs <= 10 && end < vContext->seqLength) { */
6080 if (space_pixs <= 20) { /* don't draw this line if it is more than 20 pixels long. */
6081 if (space_pixs < 3) { /* make sure bar is always at least 3 pixels long */
6082 int mid_point = end + begin;
6083 end = (mid_point + 3 * vContext->viewScale) /2;
6084 begin = (mid_point - 3 * vContext->viewScale) /2;
6085 }
6086 AddAttribute (seg, COLOR_ATT, NULL, 0, 0, 1, 0);
6087 AddLine (seg, begin, FPSP->ceiling - height - (AIP->Height) - space_line_height - 1,
6088 end - vContext->viewScale, FPSP->ceiling - height - (AIP->Height) - space_line_height - 1, NO_ARROW, 0);
6089 }
6090 }
6091 }
6092 accumPos = GetIntervalFromAccumulator(NULL, accumPos, &begin, &end, &density);
6093 }
6094 AddAttribute (seg, COLOR_ATT, NULL, 0, 0, 1, 0);
6095 AddTextLabel (seg, 0, FPSP->ceiling - height - (AIP->Height)/2,
6096 "<", FIP->GroupLabelFont, 1, MIDDLE_LEFT, 0);
6097
6098 height += space_line_height;
6099 height += AIP->Height + FIP->IntraRowPaddingPixels;
6100 }
6101
6102 smearAlignmentsDone:
6103
6104 FreeIntervalAccumulator(&plusIAP);
6105 FreeIntervalAccumulator(&minusIAP);
6106
6107 return height;
6108 }
6109
6110
6111 static Boolean FilterAndLayout (
6112 ViewerContextPtr vContext
6113 )
6114
6115 {
6116 FilterProcessState FPS;
6117 FilterItemPtr FIP;
6118 FilterPtr FP;
6119 AppearancePtr AP;
6120 FilterItem tempFI;
6121 Int1 featdeftype;
6122 LayoutAlgorithm layoutC;
6123 Int4 height, totalheight;
6124 SegmenT filterSeg, invisibleSeg;
6125 Uint1 featdefOrder;
6126 Boolean emptyFilterGroup;
6127 Int4 undoCeiling;
6128 BioseqPtr BSP;
6129 SeqAnnotPtr SAnnP;
6130 SeqAlignPtr SAlnP;
6131
6132
6133 if (vContext == NULL) return FALSE;
6134 MemSet (&FPS, 0, sizeof (FilterProcessState));
6135 FPS.vContext = vContext;
6136 if (vContext->ceiling != NULL) {
6137 FPS.ceiling = *vContext->ceiling;
6138 } else {
6139 FPS.ceiling = 0;
6140 }
6141 FPS.featuresProcessed = MemNew (vContext->featureCount * sizeof (Boolean));
6142 if (FPS.featuresProcessed == NULL && vContext->featureCount != 0) return FALSE;
6143 AP = vContext->AppPtr;
6144 vContext->sanLevelSeg = CreateSegment (vContext->topLevelSeg, 0, 0);
6145 FPS.annotBoxDrawn = FALSE;
6146 FPS.annotLabelDrawn = FALSE;
6147
6148 FP = vContext->FltPtr;
6149 if (! FP->AnnotBoxColorSet) {
6150 MemCopy (FP->AnnotBoxColor, AP->AnnotBoxColor, sizeof (Uint1 [3]));
6151 }
6152 if (! FP->AnnotLabelColorSet) {
6153 MemCopy (FP->AnnotLabelColor, AP->AnnotLabelColor, sizeof (Uint1 [3]));
6154 }
6155 if (! FP->AnnotLabelFontSet) {
6156 FP->AnnotLabelFont = AP->AnnotLabelFont;
6157 }
6158
6159 for (FPS.currentFilterVNP = FP->FilterItemList;
6160 FPS.currentFilterVNP != NULL;
6161 FPS.currentFilterVNP = FPS.currentFilterVNP->next) {
6162
6163 if (FPS.currentFilterVNP->data.ptrvalue == NULL) continue; /* this should not happen if config file parsing worked */
6164
6165 filterSeg = CreateSegment (vContext->sanLevelSeg, 0, 0);
6166 MemSet (FPS.labelSegs, 0, sizeof (FPS.labelSegs));
6167 MemSet (FPS.drawSegs, 0, sizeof (FPS.drawSegs));
6168 vContext->drawOnMe = filterSeg;
6169 emptyFilterGroup = TRUE;
6170 undoCeiling = FPS.ceiling;
6171 FPS.featuresProcessedCount = 0;
6172 FPS.groupBoxDrawn = FALSE;
6173 FPS.groupLabelDrawn = FALSE;
6174
6175 FIP = (FilterItemPtr) FPS.currentFilterVNP->data.ptrvalue;
6176
6177 if (! FIP->GroupBoxColorSet) {
6178 MemCopy (FIP->GroupBoxColor, AP->GroupBoxColor, sizeof (Uint1 [3]));
6179 }
6180 if (! FIP->GroupLabelColorSet) {
6181 MemCopy (FIP->GroupLabelColor, AP->GroupLabelColor, sizeof (Uint1 [3]));
6182 }
6183 if (! FIP->GroupLabelFontSet) {
6184 FIP->GroupLabelFont = AP->GroupLabelFont;
6185 }
6186
6187 switch (FIP->Type) {
6188 case InvalidFilter:
6189 break;
6190 case BioseqFilter:
6191 if (vContext->currentSAP)
6192 break;
6193 height = DrawBioseq (FPS.ceiling, FIP, vContext);
6194 emptyFilterGroup = FALSE;
6195 break;
6196 case GraphFilter:
6197 if (vContext->currentSAP)
6198 break;
6199 height = DrawGraphs (FPS.ceiling, vContext);
6200 if (height != 0) {
6201 emptyFilterGroup = FALSE;
6202 }
6203 break;
6204 case AlignmentFilter:
6205 BSP = vContext->BSP;
6206 height = 0;
6207 totalheight = 0;
6208 layoutC = (vContext->overrideLayout != Layout_Inherit) ? vContext->overrideLayout : FIP->LayoutChoice;
6209 FPS.currentFIP = FIP;
6210
6211 /*
6212 * Or we could move the current SAnnP into FPS.state.align and put all of this logic
6213 * into GetNextRFIPinAlignmentFilter() which SmearAlignments would call, making Alignment
6214 * processing more like Feature processing.
6215 */
6216 for (SAnnP = BSP->annot; SAnnP != NULL; SAnnP = SAnnP->next)
6217 {
6218 if (SAnnP->type != 2)
6219 continue; /* type 2 annotation is an alignment */
6220
6221 if (FP->GroupByAnnot) /* are we grouping by named annotations? */
6222 {
6223 if (GetSeqAnnotName(SAnnP)) /* this is a named annotation */
6224 {
6225 if (SAnnP != vContext->currentSAP) /* only do the named annotation we are currently doing. */
6226 continue;
6227 }
6228 else if (vContext->currentSAP) /* don't do any unnamed annotation if we are doing a particular named one. */
6229 continue;
6230 }
6231
6232 emptyFilterGroup = FALSE;
6233 SAlnP = (SeqAlignPtr) SAnnP->data;
6234
6235 ResetFilterState (&FPS);
6236 if ( ! AlignmentFilterStateInit(SAlnP, BSP->id ,&FPS.state.align, vContext->extras))
6237 continue;
6238
6239 switch (layoutC) {
6240 case Layout_FeatTypePerLine:
6241 height = SmearAlignments (&FPS, vContext);
6242 break;
6243 default:
6244 height = ProcessRows (layoutC, &FPS, vContext);
6245 break;
6246 }
6247 AlignmentFilterStateFree(&FPS.state.align);
6248
6249 totalheight += height;
6250 if (height > 0)
6251 FPS.ceiling -= height;
6252 } /* SAnnp, cycle through all SeqAnnots on this Bioseq */
6253 height = 0;
6254 break;
6255 case FeatureFilter:
6256 layoutC = (vContext->overrideLayout != Layout_Inherit) ? vContext->overrideLayout : FIP->LayoutChoice;
6257 /*
6258 Some layouts act to the user as if they are single FilterGroups, but internally use multiple
6259 consecutive FilterGroups
6260 (currently, Layout_FeatTypePerLine, Layout_FeatTypePerLineGroup, Layout_GroupCorrespondingFeats, and Layout_GroupCorrespondingFeatsRepeat).
6261 */
6262 /*
6263 FeatTypePerLineGroup is equiv. to using PackUpwards several times, with single-feature filteritems
6264 FeatTypePerLine is similar (but using AllInOneLine)
6265 */
6266 switch (layoutC) {
6267 case Layout_FeatTypePerLine:
6268 case Layout_FeatTypePerLineGroup:
6269 FPS.currentFIP = &tempFI;
6270 MemCopy (&tempFI, FIP, sizeof (FilterItem)); /* copy the filter . . . */
6271 MemSet (&tempFI.IncludeFeature, 0, sizeof (tempFI.IncludeFeature)); /* but don't include any features */
6272 tempFI.AddTypeToLabel = TristateFalse;
6273 for (featdefOrder = 1; featdefOrder < APPEARANCEITEM_MAX; featdefOrder++) {
6274 for (featdeftype = 1; featdeftype < APPEARANCEITEM_MAX; featdeftype++) {
6275 if (FIP->IncludeFeature [featdeftype] == featdefOrder) {
6276 ResetFilterState (&FPS);
6277 tempFI.IncludeFeature[featdeftype] = TRUE;
6278 height = ProcessRows (layoutC, &FPS, vContext);
6279 if (FPS.featuresProcessedCount != 0) {
6280 emptyFilterGroup = FALSE;
6281 }
6282 FPS.ceiling -= height;
6283 tempFI.IncludeFeature[featdeftype] = FALSE;
6284 }
6285 }
6286 }
6287 height = 0; /* prevent FPS.ceiling from being bumped again */
6288 break;
6289 case Layout_GroupCorrespondingFeats:
6290 case Layout_GroupCorrespondingFeatsRepeat:
6291 /*
6292 This uses 3 FilterItems:
6293 - All gene features (compact)
6294 - CDS & mRNA (grouped by products)
6295 - anything else included in the filter as specified by the user (compact)
6296 */
6297 FPS.currentFIP = &tempFI;
6298 MemCopy (&tempFI, FIP, sizeof (FilterItem)); /* copy the filter . . .*/
6299 MemSet (&tempFI.IncludeFeature, 0, sizeof (tempFI.IncludeFeature)); /* but don't include any features*/
6300 tempFI.GroupPadding = 0;
6301 tempFI.IncludeFeature [FEATDEF_GENE] = FIP->IncludeFeature [FEATDEF_GENE];
6302 ResetFilterState (&FPS);
6303 height = ProcessRows (Layout_PackUpward, &FPS, vContext);
6304 FPS.ceiling -= height;
6305
6306 ResetFilterState (&FPS);
6307 tempFI.IncludeFeature [FEATDEF_CDS] = FIP->IncludeFeature [FEATDEF_CDS];
6308 tempFI.IncludeFeature [FEATDEF_mRNA] = FIP->IncludeFeature [FEATDEF_mRNA];
6309 height = ProcessRows (layoutC, &FPS, vContext);
6310 FPS.ceiling -= height;
6311
6312 ResetFilterState (&FPS);
6313 MemCopy (&tempFI.IncludeFeature, &FIP->IncludeFeature, sizeof (tempFI.IncludeFeature));
6314 tempFI.GroupPadding = FIP->GroupPadding;
6315 height = ProcessRows (Layout_PackUpward, &FPS, vContext);
6316 FPS.ceiling -= height;
6317 height = 0;
6318 if (FPS.featuresProcessedCount != 0) {
6319 emptyFilterGroup = FALSE;
6320 }
6321
6322 break;
6323 default:
6324 FPS.currentFIP = FIP;
6325 ResetFilterState (&FPS);
6326 height = ProcessRows (layoutC, &FPS, vContext);
6327 if (FPS.featuresProcessedCount != 0) {
6328 emptyFilterGroup = FALSE;
6329 }
6330 break;
6331 } /* switch (layoutC) */
6332 break;
6333 } /* switch (FIP->type) */
6334 if (emptyFilterGroup) {
6335 FPS.ceiling = undoCeiling;
6336 continue;
6337 } else {
6338 switch (FIP->GroupLabelLoc) {
6339 default: break;
6340 case LabelOnTop:
6341 /* already done in DrawFilterItemBoxLabel() */
6342 break;
6343 case LabelOnSide:
6344 AddAttribute (vContext->drawOnMe, COLOR_ATT, FIP->GroupLabelColor, 0, 0, 0, 0);
6345 AddTextLabel (filterSeg, 0, FPS.ceiling - height / 2, FIP->GroupLabel,
6346 FIP->GroupLabelFont, 1, MIDDLE_RIGHT, 0);
6347 SelectFont (FIP->GroupLabelFont);
6348 height = MAX (height, LineHeight () + 3);
6349 FPS.groupLabelDrawn = TRUE;
6350 break;
6351 case LabelOnBottom:
6352 AddAttribute (vContext->drawOnMe, COLOR_ATT, FIP->GroupLabelColor, 0, 0, 0, 0);
6353 AddTextLabel (filterSeg, (vContext->from + vContext->to) / 2 , FPS.ceiling - height, FIP->GroupLabel,
6354 FIP->GroupLabelFont, 1, LOWER_CENTER, 0);
6355 SelectFont (FIP->GroupLabelFont);
6356 height += LineHeight () + 3;
6357 FPS.groupLabelDrawn = TRUE;
6358 break;
6359 }
6360 }
6361 if (FPS.groupBoxDrawn) {
6362 FPS.ceiling -= 10;
6363 }
6364 FPS.ceiling -= height + FIP->GroupPadding;
6365 if (FPS.needFreeList != NULL) {
6366 FPS.needFreeList = ValNodeFreeData (FPS.needFreeList);
6367 FPS.lastInFreeList = NULL;
6368 }
6369 } /* for ( FP->FilterItemList->next ) */
6370
6371 if (FP->GroupByAnnot && FP->AnnotLabelLoc == LabelOnBottom) {
6372 CharPtr annotName;
6373
6374 annotName = GetSeqAnnotName(vContext->currentSAP);
6375 if (annotName != NULL && !StringHasNoText(annotName))
6376 {
6377 AddAttribute (vContext->sanLevelSeg, COLOR_ATT, FP->AnnotLabelColor, 0, 0, 0, 0);
6378 AddTextLabel (vContext->sanLevelSeg, (vContext->from + vContext->to) / 2 , FPS.ceiling, annotName,
6379 FP->AnnotLabelFont, 1, LOWER_CENTER, 0);
6380 SelectFont (FP->AnnotLabelFont);
6381 FPS.ceiling -= LineHeight () + 3;
6382 FPS.annotLabelDrawn = TRUE;
6383 }
6384 }
6385 if (FPS.annotBoxDrawn) {
6386 /* add invisible line to force width of SegRect and space under group boxes. */
6387 invisibleSeg = CreateSegment (vContext->sanLevelSeg, 0, 0);
6388 SetSegmentVisibleFlag (invisibleSeg, FALSE);
6389 AddLine (invisibleSeg, vContext->from - 3 * vContext->viewScale , FPS.ceiling + 10,
6390 vContext->to + 3 * vContext->viewScale , FPS.ceiling + 10, FALSE, 0);
6391 FPS.ceiling -= 20;
6392 }
6393 if (FPS.needFreeList != NULL) {
6394 FPS.needFreeList = ValNodeFreeData (FPS.needFreeList);
6395 FPS.lastInFreeList = NULL;
6396 }
6397
6398 if (vContext->ceiling != NULL) {
6399 *vContext->ceiling = FPS.ceiling;
6400 }
6401 return TRUE;
6402 }
6403
6404 NLM_EXTERN RelevantFeaturesPtr FreeCollectedFeatures (
6405 RelevantFeaturesPtr RFP
6406 )
6407
6408 {
6409 if (RFP == NULL) return NULL;
6410 if (RFP->sapList) {
6411 MemFree (RFP->sapList);
6412 }
6413 if (RFP->featVNP != NULL) {
6414 ValNodeFreeData (RFP->featVNP);
6415 }
6416 MemFree (RFP);
6417 return NULL;
6418 }
6419
6420 NLM_EXTERN SegmenT CreateGraphicViewInternal (
6421 BioseqPtr bsp,
6422 Int4 from,
6423 Int4 to,
6424 Boolean allFeatures,
6425 RelevantFeaturesPtr feats,
6426 Int4 scale,
6427 Int4Ptr ceiling,
6428 SegmenT topLevel,
6429 AppearancePtr AP,
6430 FilterPtr FP,
6431 LayoutAlgorithm overrideLayout,
6432 GraphicViewExtrasPtr extras
6433 )
6434
6435 {
6436 ViewerContext VC;
6437 Int2 sapIndex;
6438 Int4 theCeiling = 0;
6439
6440 /*
6441 Removed checks feats->featureCount == 0 || feats->featVNP == NULL
6442 to allow display of BSP w/0 features on it.
6443 */
6444
6445 if (AP == NULL || FP == NULL) return NULL;
6446 MemSet ((Pointer) &VC, 0, sizeof (ViewerContext));
6447 VC.from = MIN (from, to);
6448 VC.to = MAX (from, to);
6449 VC.allFeatures = allFeatures;
6450 VC.BSP = bsp;
6451 VC.viewScale = scale;
6452 VC.sapList = feats->sapList;
6453 VC.sapCount = feats->sapCount;
6454 if (topLevel == NULL) {
6455 VC.drawOnMe = VC.sanLevelSeg = VC.topLevelSeg = CreatePicture ();
6456 } else {
6457 VC.drawOnMe = VC.sanLevelSeg = VC.topLevelSeg = topLevel;
6458 }
6459 VC.featureCount = feats->featureCount;
6460 VC.featVNP = feats->featVNP;
6461 VC.AppPtr = AP;
6462 VC.FltPtr = FP;
6463 VC.overrideLayout = overrideLayout;
6464 VC.seqLength = bsp->length;
6465 VC.extras = extras;
6466
6467 if (NULL == ceiling)
6468 VC.ceiling = &theCeiling;
6469 else
6470 VC.ceiling = ceiling;
6471
6472 VC.currentSAP = NULL;
6473 FilterAndLayout (&VC);
6474 /* do again for named Seq Annot's */
6475 if (FP->GroupByAnnot)
6476 {
6477 for (sapIndex = 0; sapIndex < VC.sapCount; ++sapIndex) {
6478 VC.currentSAP = VC.sapList[sapIndex];
6479 FilterAndLayout (&VC);
6480 }
6481 }
6482 return VC.topLevelSeg;
6483 }
6484
6485 /* returns the 1st segment in a linked list. caller must deallocate it */
6486 NLM_EXTERN SegmenT CreateGraphicViewFromBsp (
6487 BioseqPtr bsp,
6488 SeqLocPtr location,
6489 Int4 scale,
6490 Int4Ptr ceiling,
6491 SegmenT topLevel,
6492 AppearancePtr AP,
6493 FilterPtr FP,
6494 LayoutAlgorithm overrideLayout,
6495 GraphicViewExtrasPtr extras
6496 )
6497
6498 {
6499 RelevantFeaturesPtr RFP;
6500 SegmenT seg;
6501 SeqIntPtr sintp;
6502 BioseqPtr parent;
6503 SeqMgrSegmentContext context;
6504 Int4 from = 0;
6505 Int4 to = 0;
6506 Boolean allFeatures = TRUE;
6507
6508 if (location != NULL) {
6509 bsp = BioseqFindFromSeqLoc (location);
6510 if (bsp == NULL) return NULL;
6511 to = bsp->length - 1;
6512
6513 if (location->choice == SEQLOC_WHOLE) {
6514 location = NULL; /* no special behavior needed if it's whole */
6515 } else if (location->choice == SEQLOC_INT) {
6516 sintp = (SeqIntPtr) location->data.ptrvalue;
6517 if (sintp != NULL && sintp->from == 0 && sintp->to == bsp->length - 1) {
6518 location = NULL;
6519 } else if (sintp != NULL) {
6520 from = sintp->from;
6521 to = sintp->to;
6522 allFeatures = FALSE;
6523 }
6524 }
6525 } else if (bsp != NULL) {
6526 to = bsp->length - 1;
6527 }
6528 if (bsp == NULL) return NULL;
6529 parent = SeqMgrGetParentOfPart (bsp, &context);
6530 if (parent != NULL) {
6531 from = context.cumOffset;
6532 to = from + context.to - context.from;
6533 allFeatures = FALSE;
6534 bsp = parent;
6535 }
6536 RFP = CollectFeatures (bsp);
6537 if (RFP == NULL) return NULL;
6538 seg = CreateGraphicViewInternal (bsp, from, to, allFeatures, RFP, scale, ceiling, topLevel, AP, FP, overrideLayout, extras);
6539 FreeCollectedFeatures (RFP);
6540 return seg;
6541 }
6542
6543 NLM_EXTERN SegmenT CreateGraphicView (
6544 BioseqPtr bsp,
6545 SeqLocPtr location,
6546 Int4 scale,
6547 CharPtr styleName,
6548 CharPtr filterName,
6549 CharPtr overrideLayoutName,
6550 GraphicViewExtrasPtr extras
6551 )
6552
6553 {
6554 ViewerConfigsPtr myVCP;
6555 FilterPtr FP;
6556 AppearancePtr AP;
6557 LayoutAlgorithm overrideLayout;
6558 Int1 i;
6559
6560 if (bsp == NULL && location == NULL) return NULL;
6561 myVCP = GetGraphicConfigParseResults ();
6562
6563 AP = FindAppearanceByName (styleName, myVCP);
6564 FP = FindFilterByName (filterName, myVCP);
6565 i = StringIndexInStringList (overrideLayoutName, LayoutStrings);
6566 if (i >= 0 && i < DIM (LayoutValues)) {
6567 overrideLayout = LayoutValues[i];
6568 } else {
6569 overrideLayout = Layout_Inherit;
6570 }
6571
6572 return CreateGraphicViewFromBsp (bsp, location, scale, NULL, NULL, AP, FP, overrideLayout, extras);
6573 }
6574
6575 NLM_EXTERN Uint2 GetAppearanceCount (void)
6576
6577 {
6578 ViewerConfigsPtr VCP;
6579
6580 VCP = GetGraphicConfigParseResults ();
6581 if (VCP == NULL) return 0;
6582 return VCP->AppearanceCount;
6583 }
6584
6585 NLM_EXTERN Uint2 GetFilterCount (void)
6586
6587 {
6588 ViewerConfigsPtr VCP;
6589
6590 VCP = GetGraphicConfigParseResults ();
6591 if (VCP == NULL) return 0;
6592 return VCP->FilterCount;
6593 }
6594
6595 NLM_EXTERN Uint2 GetLayoutCount (void)
6596
6597 {
6598 return DIM (LayoutStrings);
6599 }
6600
6601 NLM_EXTERN Uint2 GetAlnScoreCount (void)
6602 {
6603 return DIM (AlnScoreStrings);
6604 }
6605
6606 NLM_EXTERN Uint2 GetAlnScoreCutoffCount (void)
6607 {
6608 return DIM (AlnScoreCutoffStrings);
6609 }
6610
6611 NLM_EXTERN CharPtr PNTR GetStyleNameList (void)
6612
6613 {
6614 ViewerConfigsPtr VCP;
6615
6616 VCP = GetGraphicConfigParseResults ();
6617 if (VCP == NULL) return NULL;
6618 return VCP->AppearanceNameArray;
6619 }
6620
6621 NLM_EXTERN CharPtr PNTR GetFilterNameList (void)
6622
6623 {
6624 ViewerConfigsPtr VCP;
6625
6626 VCP = GetGraphicConfigParseResults ();
6627 if (VCP == NULL) return NULL;
6628 return VCP->FilterNameArray;
6629 }
6630
6631 NLM_EXTERN CharPtr PNTR GetAlnScoreNameList(void)
6632 {
6633 return AlnScoreStrings;
6634 }
6635
6636 NLM_EXTERN CharPtr PNTR GetAlnScoreCutoffList(void)
6637 {
6638 return AlnScoreCutoffStrings;
6639 }
6640
6641 NLM_EXTERN CharPtr PNTR GetLayoutNameList (void)
6642
6643 {
6644 return LayoutStrings;
6645 }
6646
6647
6648 /* -=-=-=-=-=-=-=- append default-style.c contents after this point -=-=-=-=-=-=-=-=- */
6649
6650 /* default-style.c : creates a default style for the new graphic viewer
6651 This is an automatically generated file, which came from an asn2gph configuration file (asn2gph.default)
6652 It might be better to edit the input file and then re-run the script create-default-style.tcl than to
6653 edit this file directly.
6654 */
6655
6656
6657 typedef struct configFileLine {
6658 CharPtr key, value;
6659 } ConfigFileLine, PNTR ConfigFileLinePtr;
6660
6661 typedef struct staticConfigFile {
6662 ConfigFileLinePtr lines;
6663 CharPtr sectionName;
6664 } StaticConfigFile, PNTR StaticConfigFilePtr;
6665
6666
6667 /* [Styles] */
6668 static ConfigFileLine defaultStyleLines1 [] = {
6669 {"style00", "defaultStyle"},
6670 {"style100", "summary"},
6671 {NULL, NULL}
6672 };
6673
6674 /* [defaultStyle.master] */
6675 static ConfigFileLine defaultStyleLines2 [] = {
6676 {"name", "Default"},
6677 {"maxarrowscale", "200"},
6678 {"minarrowpixels", "5"},
6679 {"shadesmears", "false"},
6680 {"color", "black"},
6681 {"labelfont", "program"},
6682 {"labelcolor", "black"},
6683 {"label", "above"},
6684 {"grouplabelfont", "program"},
6685 {"grouplabelcolor", "dark gray"},
6686 {"groupboxcolor", "gray"},
6687 {"displaywith", "box"},
6688 {"height", "8"},
6689 {"gap", "line"},
6690 {"showarrow", "no"},
6691 {"showtype", "yes"},
6692 {"showcontent", "yes"},
6693 {"shadesmears", "false"},
6694 {"annotboxcolor", "100, 100, 100"},
6695 {"annotlabelcolor", "black"},
6696 {"annotlabelfont", "program"},
6697 {NULL, NULL}
6698 };
6699
6700 /* [defaultStyle.bioseq] */
6701 static ConfigFileLine defaultStyleLines3 [] = {
6702 {"label", "left"},
6703 {"format", "accn"},
6704 {"scale", "true"},
6705 {"labelfont", "program"},
6706 {"scalefont", "small"},
6707 {"height", "10"},
6708 {"scaleheight", "10"},
6709 {"color", "0, 0, 0"},
6710 {"labelcolor", "64, 64, 255"},
6711 {"scalecolor", "32, 32, 32"},
6712 {NULL, NULL}
6713 };
6714
6715 /* [defaultStyle.gene] */
6716 static ConfigFileLine defaultStyleLines4 [] = {
6717 {"label", "above"},
6718 {"color", "blue"},
6719 {"labelcolor", "blue"},
6720 {"showarrow", "true"},
6721 {NULL, NULL}
6722 };
6723
6724 /* [defaultStyle.mRNA] */
6725 static ConfigFileLine defaultStyleLines5 [] = {
6726 {"label", "above"},
6727 {"color", "cyan"},
6728 {"labelcolor", "cyan"},
6729 {"showarrow", "true"},
6730 {"gap", "line"},
6731 {NULL, NULL}
6732 };
6733
6734 /* [defaultStyle.cds] */
6735 static ConfigFileLine defaultStyleLines6 [] = {
6736 {"label", "above"},
6737 {"color", "magenta"},
6738 {"labelcolor", "magenta"},
6739 {"showarrow", "true"},
6740 {"gap", "angle"},
6741 {NULL, NULL}
6742 };
6743
6744 /* [defaultStyle.tRNA] */
6745 static ConfigFileLine defaultStyleLines7 [] = {
6746 {"label", "above"},
6747 {"color", "green"},
6748 {"labelcolor", "green"},
6749 {"showarrow", "true"},
6750 {"gap", "line"},
6751 {NULL, NULL}
6752 };
6753
6754 /* [defaultStyle.imp] */
6755 static ConfigFileLine defaultStyleLines8 [] = {
6756 {"showcontent", "no"},
6757 {"color", "gray"},
6758 {"labelcolor", "gray"},
6759 {NULL, NULL}
6760 };
6761
6762 /* [defaultStyle.exon] */
6763 static ConfigFileLine defaultStyleLines9 [] = {
6764 {"showcontent", "no"},
6765 {"color", "dark cyan"},
6766 {"labelcolor", "dark cyan"},
6767 {NULL, NULL}
6768 };
6769
6770 /* [defaultStyle.intron] */
6771 static ConfigFileLine defaultStyleLines10 [] = {
6772 {"showcontent", "no"},
6773 {"color", "light gray"},
6774 {"labelcolor", "light gray"},
6775 {NULL, NULL}
6776 };
6777
6778 /* [defaultStyle.bond] */
6779 static ConfigFileLine defaultStyleLines11 [] = {
6780 {"displaywith", "cappedline"},
6781 {NULL, NULL}
6782 };
6783
6784 /* [defaultStyle.align] */
6785 static ConfigFileLine defaultStyleLines12 [] = {
6786 {"label", "above"},
6787 {"color", "blue"},
6788 {"labelcolor", "blue"},
6789 {"showarrow", "true"},
6790 {"showtype", "no"},
6791 {"showcontent", "yes"},
6792 {"format", "accession"},
6793 {NULL, NULL}
6794 };
6795
6796 /* [summary.master] */
6797 static ConfigFileLine defaultStyleLines13 [] = {
6798 {"name", "Summary"},
6799 {"label", "none"},
6800 {"height", "3"},
6801 {"labelfont", "small"},
6802 {"grouplabelfont", "small"},
6803 {"annotlabelfont", "small"},
6804 {NULL, NULL}
6805 };
6806
6807 /* [summary.bioseq] */
6808 static ConfigFileLine defaultStyleLines14 [] = {
6809 {"label", "above"},
6810 {"format", "accn"},
6811 {"scale", "true"},
6812 {"labelfont", "program"},
6813 {"scalefont", "small"},
6814 {"height", "5"},
6815 {"scaleheight", "5"},
6816 {"color", "0, 0, 0"},
6817 {"labelcolor", "64, 64, 255"},
6818 {"scalecolor", "32, 32, 32"},
6819 {NULL, NULL}
6820 };
6821
6822 /* [summary.gene] */
6823 static ConfigFileLine defaultStyleLines15 [] = {
6824 {"label", "above"},
6825 {"color", "blue"},
6826 {"labelcolor", "blue"},
6827 {"showarrow", "true"},
6828 {NULL, NULL}
6829 };
6830
6831 /* [summary.mRNA] */
6832 static ConfigFileLine defaultStyleLines16 [] = {
6833 {"label", "above"},
6834 {"color", "cyan"},
6835 {"labelcolor", "cyan"},
6836 {"showarrow", "true"},
6837 {"gap", "line"},
6838 {NULL, NULL}
6839 };
6840
6841 /* [summary.cds] */
6842 static ConfigFileLine defaultStyleLines17 [] = {
6843 {"label", "above"},
6844 {"color", "magenta"},
6845 {"labelcolor", "magenta"},
6846 {"showarrow", "true"},
6847 {"gap", "angle"},
6848 {NULL, NULL}
6849 };
6850
6851 /* [summary.tRNA] */
6852 static ConfigFileLine defaultStyleLines18 [] = {
6853 {"label", "above"},
6854 {"color", "green"},
6855 {"labelcolor", "green"},
6856 {"showarrow", "true"},
6857 {"gap", "line"},
6858 {NULL, NULL}
6859 };
6860
6861 /* [summary.align] */
6862 static ConfigFileLine defaultStyleLines19 [] = {
6863 {"label", "above"},
6864 {"color", "blue"},
6865 {"labelcolor", "blue"},
6866 {"showarrow", "true"},
6867 {"showtype", "no"},
6868 {"showcontent", "yes"},
6869 {"format", "accession"},
6870 {NULL, NULL}
6871 };
6872
6873 /* [summary.imp] */
6874 static ConfigFileLine defaultStyleLines20 [] = {
6875 {"showcontent", "no"},
6876 {"color", "gray"},
6877 {"labelcolor", "gray"},
6878 {NULL, NULL}
6879 };
6880
6881 /* [summary.exon] */
6882 static ConfigFileLine defaultStyleLines21 [] = {
6883 {"showcontent", "no"},
6884 {"color", "dark cyan"},
6885 {"labelcolor", "dark cyan"},
6886 {NULL, NULL}
6887 };
6888
6889 /* [summary.intron] */
6890 static ConfigFileLine defaultStyleLines22 [] = {
6891 {"showcontent", "no"},
6892 {"color", "light gray"},
6893 {"labelcolor", "light gray"},
6894 {NULL, NULL}
6895 };
6896
6897 /* [summary.bond] */
6898 static ConfigFileLine defaultStyleLines23 [] = {
6899 {"displaywith", "cappedline"},
6900 {NULL, NULL}
6901 };
6902
6903 /* [Filters] */
6904 static ConfigFileLine defaultStyleLines24 [] = {
6905 {"filter00", "defaultFilt"},
6906 {"filter100", "summary"},
6907 {"maxlabelscale", "200"},
6908 {"grouppadding", "2"},
6909 {"rowpadding", "2"},
6910 {"annotgroup", "yes"},
6911 {"annotbox", "yes"},
6912 {"annotlabel", "above"},
6913 {NULL, NULL}
6914 };
6915
6916 /* [defaultFilt] */
6917 static ConfigFileLine defaultStyleLines25 [] = {
6918 {"name", "Default"},
6919 {"layout", "compact"},
6920 {"group1", "defaultFilt-operons"},
6921 {"group2", "defaultFilt-gene-cds-prot-mrna"},
6922 {"group3", "defaultFilt-other-rnas"},
6923 {"group4", "defaultFilt-exon-intron-label"},
6924 {"group5", "defaultFilt-variations"},
6925 {"group6", "defaultFilt-conflicts"},
6926 {"group7", "defaultFilt-STS"},
6927 {"group8", "defaultFilt-impfeats"},
6928 {"group9", "defaultFilt-alignments"},
6929 {"group10", "defaultFilt-everything-else-label"},
6930 {NULL, NULL}
6931 };
6932
6933 /* [filters.defaultFilt-gene-cds-prot-mrna] */
6934 static ConfigFileLine defaultStyleLines26 [] = {
6935 {"feature1", "gene"},
6936 {"feature2", "cds"},
6937 {"feature3", "prot"},
6938 {"feature4", "mrna"},
6939 {"name", "Gene-mRNA-CDS-Prots"},
6940 {"grouplabel", "none"},
6941 {"layout", "geneproducts"},
6942 {"showtype", "yes"},
6943 {"showcontent", "yes"},
6944 {"label", "above"},
6945 {NULL, NULL}
6946 };
6947
6948 /* [filters.defaultFilt-other-rnas] */
6949 static ConfigFileLine defaultStyleLines27 [] = {
6950 {"feature1", "rna"},
6951 {"name", "Structural RNAs"},
6952 {"grouplabel", "none"},
6953 {"label", "above"},
6954 {NULL, NULL}
6955 };
6956
6957 /* [filters.defaultFilt-operons] */
6958 static ConfigFileLine defaultStyleLines28 [] = {
6959 {"feature1", "operon"},
6960 {"name", "Operons"},
6961 {"grouplabel", "none"},
6962 {"label", "above"},
6963 {NULL, NULL}
6964 };
6965
6966 /* [filters.defaultFilt-exon-intron-label] */
6967 static ConfigFileLine defaultStyleLines29 [] = {
6968 {"feature1", "exon"},
6969 {"feature2", "intron"},
6970 {"name", "Introns and Exons"},
6971 {"grouplabel", "none"},
6972 {"label", "above"},
6973 {NULL, NULL}
6974 };
6975
6976 /* [filters.defaultFilt-variations] */
6977 static ConfigFileLine defaultStyleLines30 [] = {
6978 {"feature1", "variation"},
6979 {"name", "Variations"},
6980 {"groupbox", "true"},
6981 {"boxcolor", "red"},
6982 {"grouplabel", "above"},
6983 {"layout", "smear"},
6984 {"showtype", "no"},
6985 {"showcontent", "no"},
6986 {NULL, NULL}
6987 };
6988
6989 /* [filters.defaultFilt-conflicts] */
6990 static ConfigFileLine defaultStyleLines31 [] = {
6991 {"feature1", "conflict"},
6992 {"name", "Conflicts"},
6993 {"groupbox", "true"},
6994 {"boxcolor", "dark red"},
6995 {"grouplabel", "above"},
6996 {"layout", "smear"},
6997 {"showtype", "no"},
6998 {"showcontent", "no"},
6999 {NULL, NULL}
7000 };
7001
7002 /* [filters.defaultFilt-STS] */
7003 static ConfigFileLine defaultStyleLines32 [] = {
7004 {"feature1", "STS"},
7005 {"name", "STS"},
7006 {"groupbox", "true"},
7007 {"boxcolor", "red"},
7008 {"grouplabel", "above"},
7009 {"layout", "smear"},
7010 {"showtype", "no"},
7011 {"showcontent", "no"},
7012 {NULL, NULL}
7013 };
7014
7015 /* [filters.defaultFilt-impfeats] */
7016 static ConfigFileLine defaultStyleLines33 [] = {
7017 {"feature1", "import"},
7018 {"name", "Import Features"},
7019 {"grouplabel", "none"},
7020 {"label", "above"},
7021 {NULL, NULL}
7022 };
7023
7024 /* [filters.defaultFilt-alignments] */
7025 static ConfigFileLine defaultStyleLines34 [] = {
7026 {"feature1", "align"},
7027 {"name", "Alignments"},
7028 {"grouplabel", "none"},
7029 {"label", "above"},
7030 {"layout", "smear"},
7031 {"showtype", "no"},
7032 {NULL, NULL}
7033 };
7034
7035 /* [filters.defaultFilt-everything-else-label] */
7036 static ConfigFileLine defaultStyleLines35 [] = {
7037 {"feature1", "everything"},
7038 {"grouplabel", "none"},
7039 {"label", "above"},
7040 {NULL, NULL}
7041 };
7042
7043 /* [summary] */
7044 static ConfigFileLine defaultStyleLines36 [] = {
7045 {"group1", "summary-gene-rna-cds-nolabel"},
7046 {"group2", "summary-allelse"},
7047 {"group3", "summary-aligns-nolabel"},
7048 {"name", "Summary"},
7049 {"defaultlayout", "compact"},
7050 {"rowpadding", "3"},
7051 {"grouppadding", "1"},
7052 {"label", "none"},
7053 {"annotlabelfont", "small"},
7054 {NULL, NULL}
7055 };
7056
7057 /* [filters.summary-gene-rna-cds-nolabel] */
7058 static ConfigFileLine defaultStyleLines37 [] = {
7059 {"feature1", "gene"},
7060 {"feature2", "rna"},
7061 {"feature3", "cds"},
7062 {"layout", "geneproducts"},
7063 {"label", "none"},
7064 {NULL, NULL}
7065 };
7066
7067 /* [filters.summary-aligns-nolabel] */
7068 static ConfigFileLine defaultStyleLines38 [] = {
7069 {"feature1", "align"},
7070 {"label", "none"},
7071 {NULL, NULL}
7072 };
7073
7074 /* [filters.summary-allelse] */
7075 static ConfigFileLine defaultStyleLines39 [] = {
7076 {"feature1", "everything"},
7077 {"layout", "smear"},
7078 {"label", "none"},
7079 {NULL, NULL}
7080 };
7081
7082
7083 static StaticConfigFile defaultStyle [] = {
7084 {defaultStyleLines1, "Styles"},
7085 {defaultStyleLines2, "defaultStyle.master"},
7086 {defaultStyleLines3, "defaultStyle.bioseq"},
7087 {defaultStyleLines4, "defaultStyle.gene"},
7088 {defaultStyleLines5, "defaultStyle.mRNA"},
7089 {defaultStyleLines6, "defaultStyle.cds"},
7090 {defaultStyleLines7, "defaultStyle.tRNA"},
7091 {defaultStyleLines8, "defaultStyle.imp"},
7092 {defaultStyleLines9, "defaultStyle.exon"},
7093 {defaultStyleLines10, "defaultStyle.intron"},
7094 {defaultStyleLines11, "defaultStyle.bond"},
7095 {defaultStyleLines12, "defaultStyle.align"},
7096 {defaultStyleLines13, "summary.master"},
7097 {defaultStyleLines14, "summary.bioseq"},
7098 {defaultStyleLines15, "summary.gene"},
7099 {defaultStyleLines16, "summary.mRNA"},
7100 {defaultStyleLines17, "summary.cds"},
7101 {defaultStyleLines18, "summary.tRNA"},
7102 {defaultStyleLines19, "summary.align"},
7103 {defaultStyleLines20, "summary.imp"},
7104 {defaultStyleLines21, "summary.exon"},
7105 {defaultStyleLines22, "summary.intron"},
7106 {defaultStyleLines23, "summary.bond"},
7107 {defaultStyleLines24, "Filters"},
7108 {defaultStyleLines25, "defaultFilt"},
7109 {defaultStyleLines26, "filters.defaultFilt-gene-cds-prot-mrna"},
7110 {defaultStyleLines27, "filters.defaultFilt-other-rnas"},
7111 {defaultStyleLines28, "filters.defaultFilt-operons"},
7112 {defaultStyleLines29, "filters.defaultFilt-exon-intron-label"},
7113 {defaultStyleLines30, "filters.defaultFilt-variations"},
7114 {defaultStyleLines31, "filters.defaultFilt-conflicts"},
7115 {defaultStyleLines32, "filters.defaultFilt-STS"},
7116 {defaultStyleLines33, "filters.defaultFilt-impfeats"},
7117 {defaultStyleLines34, "filters.defaultFilt-alignments"},
7118 {defaultStyleLines35, "filters.defaultFilt-everything-else-label"},
7119 {defaultStyleLines36, "summary"},
7120 {defaultStyleLines37, "filters.summary-gene-rna-cds-nolabel"},
7121 {defaultStyleLines38, "filters.summary-aligns-nolabel"},
7122 {defaultStyleLines39, "filters.summary-allelse"},
7123 {NULL, NULL}
7124 };
7125
7126
7127 static void InitializeDefaultStyle (
7128 CharPtr configFileName
7129 )
7130
7131 {
7132 Uint2 sectionNum, lineNum;
7133 ConfigFileLinePtr lines;
7134 CharPtr sectionName;
7135
7136 for (sectionNum = 0; defaultStyle [sectionNum].lines != NULL; sectionNum++) {
7137 lines = defaultStyle [sectionNum].lines;
7138 sectionName = defaultStyle [sectionNum].sectionName;
7139 for (lineNum = 0; lines [lineNum].key != NULL && lines [lineNum].value != NULL; lineNum++) {
7140 TransientSetAppParam (configFileName, sectionName, lines [lineNum].key, lines [lineNum].value);
7141 }
7142 }
7143 }
7144
7145 /* End of automatically generated file. */
7146
7147 |
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more information. |