019341f44cfc8fe9619366bff4d04e15233dd6a8 chmalee Fri Apr 18 16:17:45 2025 -0700 Fix invalid tag in filterBy
\n", selectIdPrefix,ix,filterBy->htmlName); + printf( "\n", selectIdPrefix,ix,filterBy->htmlName); + printf( "\n"); puts(""); } puts(""); } void filterBySetCfgUi(struct cart *cart, struct trackDb *tdb, filterBy_t *filterBySet, boolean onOneLine, char *prefix) /* Does the filter UI for a list of filterBy structure */ { char selectIdPrefix[4096]; safef(selectIdPrefix, sizeof(selectIdPrefix), "fbc_%s", prefix); // Our checklists use ddcl.js, which doesn't seem to play nicely when elements have id strings that include '.' replaceChar(selectIdPrefix, '.', '_'); filterBySetCfgUiGuts(cart, tdb, filterBySet, onOneLine, "Filter", selectIdPrefix, "All", prefix, FALSE); } void highlightBySetCfgUi(struct cart *cart, struct trackDb *tdb, filterBy_t *filterBySet, boolean onOneLine, char *prefix, boolean isHighlight) /* Does the highlight UI for a list of filterBy structure */ { char selectIdPrefix[4096]; safef(selectIdPrefix, sizeof(selectIdPrefix), "hbc_%s", prefix); // Our checklists use ddcl.js, which doesn't seem to play nicely when elements have id strings that include '.' replaceChar(selectIdPrefix, '.', '_'); filterBySetCfgUiGuts(cart, tdb, filterBySet, onOneLine, "Highlight", selectIdPrefix, "None", prefix, TRUE); } #define COLOR_BG_DEFAULT_IX 0 #define COLOR_BG_ALTDEFAULT_IX 1 #define DIVIDING_LINE "
\n" #define DIVIDER_PRINT(color) printf(DIVIDING_LINE,COLOR_BG_DEFAULT,(color)) static boolean divisionIfNeeded(char **lastDivide,dividers_t *dividers,membership_t *membership) // Keeps track of location within subtracks in order to provide requested division lines { boolean division = FALSE; if (dividers) { if (lastDivide != NULL) { int ix; for (ix=0;ixcount;ix++) { int sIx = stringArrayIx(dividers->subgroups[ix],membership->subgroups, membership->count); if ((lastDivide[ix] == (void*)NULL && sIx >= 0) || (lastDivide[ix] != (void*)NULL && sIx < 0) || (strcmp(lastDivide[ix],membership->membership[sIx]) != 0) ) { division = TRUE; if (lastDivide[ix] != (void*)NULL) freeMem(lastDivide[ix]); lastDivide[ix] = (sIx<0 ? (void*)NULL : cloneString(membership->membership[sIx])); } } } //if (division) // DIVIDER_PRINT(COLOR_DARKGREEN); } return division; } static void indentIfNeeded(hierarchy_t*hierarchy,membership_t *membership) // inserts any needed indents { int indent = 0; if (hierarchy && hierarchy->count>0) { int ix; for (ix=0;ixcount;ix++) { int iIx = stringArrayIx(membership->membership[ix], hierarchy->membership, hierarchy->count); if (iIx >= 0) { indent = hierarchy->indents[iIx]; break; // Only one } } } for (;indent>0;indent--) puts("   "); } // FIXME FIXME Should be able to use membersForAll struct to set default sort order from subGroups // FIXME FIXME This should be done in hgTrackDb at load time and should change tag values to // FIXME FIXME ensure js still works boolean tdbAddPrioritiesFromCart(struct cart *cart, struct trackDb *tdbList) // Updates the tdb->priority from cart for all tracks in list and their descendents. { char htmlIdentifier[1024]; struct trackDb *tdb; boolean cartPriorities = FALSE; for (tdb = tdbList; tdb != NULL; tdb = tdb->next) { safef(htmlIdentifier, sizeof(htmlIdentifier), "%s.priority", tdb->track); char *cartHas = cartOptionalString(cart,htmlIdentifier); if (cartHas != NULL) { tdb->priority = atof(cartHas); cartPriorities = TRUE; } if (tdbAddPrioritiesFromCart(cart, tdb->subtracks)) cartPriorities = TRUE; } return cartPriorities; } boolean tdbSortPrioritiesFromCart(struct cart *cart, struct trackDb **tdbList) // Updates the tdb->priority from cart then sorts the list anew. // Returns TRUE if priorities obtained from cart { boolean cartPriorities = tdbAddPrioritiesFromCart(cart, *tdbList); slSort(tdbList, trackDbCmp); return cartPriorities; } boolean tdbRefSortPrioritiesFromCart(struct cart *cart, struct slRef **tdbRefList) // Updates the tdb->priority from cart then sorts the list anew. // Returns TRUE if priorities obtained from cart { char htmlIdentifier[128]; struct slRef *tdbRef; boolean cartPriorities = FALSE; for (tdbRef = *tdbRefList; tdbRef != NULL; tdbRef = tdbRef->next) { struct trackDb *tdb = tdbRef->val; safef(htmlIdentifier, sizeof(htmlIdentifier), "%s.priority", tdb->track); char *cartHas = cartOptionalString(cart,htmlIdentifier); if (cartHas != NULL) { tdb->priority = atof(cartHas); cartPriorities = TRUE; } } slSort(tdbRefList, trackDbRefCmp); return cartPriorities; } void bigRmskCfgUi(char *db, struct cart *cart, struct trackDb *tdb, char *name, char *title, boolean boxed) /* UI for the bigRmsk track */ { boxed = cfgBeginBoxAndTitle(tdb, boxed, title); boolean showUnalignedExtents = cartUsualBoolean(cart, BIGRMSK_SHOW_UNALIGNED_EXTENTS, BIGRMSK_SHOW_UNALIGNED_EXTENTS_DEFAULT); boolean showLabels = cartUsualBoolean(cart, BIGRMSK_SHOW_LABELS, BIGRMSK_SHOW_LABELS_DEFAULT); boolean origPackViz = cartUsualBoolean(cart, BIGRMSK_ORIG_PACKVIZ, BIGRMSK_ORIG_PACKVIZ_DEFAULT); boolean regexpFilter = cartUsualBoolean(cart, BIGRMSK_REGEXP_FILTER, BIGRMSK_REGEXP_FILTER_DEFAULT); char * nameFilter = cartUsualString(cart, BIGRMSK_NAME_FILTER, BIGRMSK_NAME_FILTER_DEFAULT); puts("
"); printf("Filter by 'name#class/subclass' field (e.g. '*Alu*' would match 'FRAM#SINE/Alu'): "); cgiMakeTextVar(BIGRMSK_NAME_FILTER, cartUsualString(cart, BIGRMSK_NAME_FILTER, nameFilter), 20); cgiMakeCheckBox(BIGRMSK_REGEXP_FILTER, regexpFilter); puts(" regular expression

"); cgiMakeCheckBox(BIGRMSK_SHOW_UNALIGNED_EXTENTS, showUnalignedExtents); puts(" Show unaligned repeat regions

"); cgiMakeCheckBox(BIGRMSK_SHOW_LABELS, showLabels); puts(" Show annotation labels

"); cgiMakeCheckBox(BIGRMSK_ORIG_PACKVIZ, origPackViz); puts(" Display original pack visualization

"); cfgEndBox(boxed); } void lollyCfgUi(char *db, struct cart *cart, struct trackDb *tdb, char *name, char *title, boolean boxed) /* UI for the wiggle track */ { int maxHeightPixels; int minHeightPixels; char option[256]; int defaultHeight; /* pixels per item */ int settingsDefault; #define MIN_HEIGHT_LOLLY 32 cartTdbFetchMinMaxPixels(cart, tdb, MIN_HEIGHT_LOLLY, atoi(DEFAULT_HEIGHT_PER), atoi(DEFAULT_HEIGHT_PER), &minHeightPixels, &maxHeightPixels, &settingsDefault, &defaultHeight); boxed = cfgBeginBoxAndTitle(tdb, boxed, title); printf(""); printf(""); double minY; /* from trackDb or cart */ double maxY; /* from trackDb or cart */ double tDbMinY; /* data range limits from trackDb type line */ double tDbMaxY; /* data range limits from trackDb type line */ char *words[8]; /* to parse the trackDb type line */ int wordCount = 0; /* to parse the trackDb type line */ wigFetchMinMaxYWithCart(cart, tdb, name, &minY, &maxY, &tDbMinY, &tDbMaxY, wordCount, words); printf("" ""); printf("
Track height:"); safef(option, sizeof(option), "%s.%s", name, HEIGHTPER ); cgiMakeIntVarWithLimits(option, defaultHeight, "Track height",0, minHeightPixels, maxHeightPixels); printf("pixels (range: %d to %d)", minHeightPixels, maxHeightPixels); char *autoScale; wigFetchAutoScaleWithCart(cart,tdb,name, &autoScale); printf("
Data view scaling:"); safef(option, sizeof(option), "%s.%s", name, AUTOSCALE ); wiggleScaleDropDown(option, autoScale); void wiggleScaleDropDownJavascript(char *name); wiggleScaleDropDownJavascript(name); puts("
Vertical viewing range: min: ", name); safef(option, sizeof(option), "%s.%s", name, MIN_Y ); cgiMakeDoubleVarWithLimits(option, minY, "Range min", 0, NO_VALUE, NO_VALUE); printf("max: "); safef(option, sizeof(option), "%s.%s", name, MAX_Y ); cgiMakeDoubleVarWithLimits(option, maxY, "Range max", 0, NO_VALUE, NO_VALUE); /* printf("
Drawing method:"); safef(option, sizeof(option), "%s.%s", name, POPMETHOD); char *popMethodVal = cartOrTdbString(cart, tdb, "popMethod", NULL); cgiMakeDropListFull(option, popMethodLabels, popMethodValues, ArraySize(popMethodValues), popMethodVal, NULL, NULL); */ puts("
"); cfgEndBox(boxed); } void labelMakeCheckBox(struct cart *cart, struct trackDb *tdb, char *sym, char *desc, boolean defaultOn) /* add a checkbox for the user to select a component of a label (e.g. ID, name, other info). * NOTE: This does not have a track name argument, so the correct tdb must be passed in: * if setting is at composite level, then pass in composite tdb, likewise for view. */ { char suffix[512]; safef(suffix, sizeof(suffix), "label.%s", sym); boolean option = cartUsualBooleanClosestToHome(cart, tdb, FALSE, suffix, defaultOn); char cartVar[1024]; safef(cartVar, sizeof cartVar, "%s.%s", tdb->track, suffix); cgiMakeCheckBox(cartVar, option); printf(" %s   ", desc); } void geneTrackMakeCheckBox(struct cart *cart, struct trackDb *tdb, char *sym, char *desc, boolean defaultOn) /* add a checkbox for the user to select a component of a label (e.g. ID, name, other info). * NOTE: This does not have a track name argument, so the correct tdb must be passed in: * if setting is at composite level, then pass in composite tdb, likewise for view. */ { char suffix[512]; safef(suffix, sizeof(suffix), "geneTrack.%s", sym); boolean option = cartUsualBooleanClosestToHome(cart, tdb, FALSE, suffix, defaultOn); char cartVar[1024]; safef(cartVar, sizeof cartVar, "%s.%s", tdb->track, suffix); cgiMakeCheckBox(cartVar, option); printf(" %s   ", desc); } static void freqSourceSelect(struct cart *cart, struct trackDb *tdb, char *name) /* Make a select input for preferred source of allele frequencies from * trackDb setting freqSourceOrder. */ { char *freqSourceOrder = cloneString(trackDbSetting(tdb, "freqSourceOrder")); if (isEmpty(freqSourceOrder)) return; int fsCount = countSeparatedItems(freqSourceOrder, ','); char *values[fsCount]; chopCommas(freqSourceOrder, values); char *menu[fsCount]; int i; for (i = 0; i < fsCount; i++) { // Change label of GnomAD to "GnomAD genomes" for clarity when "GnomAD_exomes" is present. if (sameString(values[i], "GnomAD") && stringIx("GnomAD_exomes", values) >= 0) menu[i] = "GnomAD genomes"; else { menu[i] = cloneString(values[i]); strSwapChar(menu[i], '_', ' '); } } boolean parentLevel = isNameAtParentLevel(tdb, name); char *freqProj = cartOptionalStringClosestToHome(cart, tdb, parentLevel, "freqProj"); puts("Frequency source/project to use for Minor Allele Frequency (MAF):"); char cartVar[1024]; safef(cartVar, sizeof cartVar, "%s.freqProj", name); cgiMakeDropListWithVals(cartVar, menu, values, ArraySize(menu), freqProj); puts("
"); } struct trackDb *tdbOrAncestorByName(struct trackDb *tdb, char *name) /* For reasons Angie cannot fathom, if a composite or view is passed to cfgByCfgType then * cfgByCfgType passes a leaf subtrack to its callees like bigDbSnpCfgUi. That is why we * see so many calls to isNameAtParentLevel, which returns true if the tdb was originally * at the composite or view level, which we can only tell by comparing with the original track name. * labelMakeCheckBox, called by many handlers in hgTrackUi that must be always top-level * (or have a special handler that bypasses cfgByCfgType like refSeqComposite), * is blissfully unaware of this. It uses the same tdb for looking in cart ClosestToHome * and for making the HTML element's cart var name, trusting that the correct tdb has been * handed to it. * So in order for a callee of cfgByCfgType to call labelMakeCheckBox with the correct tdb, * we need to walk back up comparing name like isNameAtParentLevel does. * If name doesn't match tdb or any of its ancestors then this returns NULL. */ { struct trackDb *correctTdb; for (correctTdb = tdb; correctTdb != NULL; correctTdb = correctTdb->parent) if (startsWithWordByDelimiter(correctTdb->track, '.', name)) return correctTdb; return NULL; } void snp153MakeCheckboxGroupSetClearButton(char *buttonVar, boolean isSet) /* Make a button for setting or clearing a set of checkboxes with the same name. * Uses only javascript to change the checkboxes, no resubmit. */ { char id[256]; char javascript[256]; safef(javascript, sizeof(javascript), "$(\"input:checkbox[name^='%s']\").each(function(){this.checked = %s;$(this).trigger('change');})", buttonVar, isSet ? "true" : "false"); safef(id, sizeof id, "%s_grp%sBut", buttonVar, isSet ? "Set" : "Clr"); cgiMakeOnClickButton(id, javascript, isSet ? JS_SET_ALL_BUTTON_LABEL : JS_CLEAR_ALL_BUTTON_LABEL); } struct trackDb *snp125FetchGeneTracks(char *database, struct cart *cart) /* Get a list of genePred tracks. */ { struct trackDb *tdbList = NULL; struct hash *trackHash = trackHashMakeWithComposites(database,NULL,&tdbList,FALSE); struct sqlConnection *conn = hAllocConn(database); struct slName *justGenePredTables = hTrackTablesOfType(conn, "genePred%%"), *gt; struct slName *bigGenePredTables = hTrackTablesOfType(conn, "bigGenePred%%"); struct slName *genePredTables = slCat(justGenePredTables,bigGenePredTables); struct trackDb *geneTdbList = NULL, *gTdb; if (genePredTables != NULL) { for (gt = genePredTables; gt != NULL; gt = gt->next) { gTdb = hashFindVal(trackHash, gt->name); if (gTdb && sameString(gTdb->grp, "genes")) { // We are going to overwrite gTdb's next pointer and possibly its priority, // so make a shallow copy: gTdb = CloneVar(gTdb); if (gTdb->parent) gTdb->priority = (gTdb->parent->priority + gTdb->priority/1000); slAddHead(&geneTdbList, gTdb); } } slSort(&geneTdbList, trackDbCmp); } hFreeConn(&conn); return geneTdbList; } void snp153OfferGeneTracksForFunction(char *database, struct cart *cart, char *name, struct trackDb *tdb, struct trackDb *correctTdb) /* Get a list of genePred tracks and make checkboxes to enable hgc's functional * annotations. */ { struct trackDb *geneTdbList = NULL, *gTdb; geneTdbList = snp125FetchGeneTracks(database, cart); if (geneTdbList) { char sectionVar[256]; safef(sectionVar, sizeof(sectionVar), "%s.geneTracks", name); jsBeginCollapsibleSection(cart, name, sectionVar, "Use Gene Tracks for Functional Annotation", FALSE); printf("
On details page, show function and coding differences relative to: \n"); char buttonVarPrefix[256]; safef(buttonVarPrefix, sizeof(buttonVarPrefix), "%s.geneTrack", name); snp153MakeCheckboxGroupSetClearButton(buttonVarPrefix, TRUE); snp153MakeCheckboxGroupSetClearButton(buttonVarPrefix, FALSE); struct slName *defaultGeneTracks = slNameListFromComma(trackDbSetting(tdb, "defaultGeneTracks")); int i; int numCols = 4; int menuSize = slCount(geneTdbList); char **values = needMem(menuSize*sizeof(char *)); char **labels = needMem(menuSize*sizeof(char *)); for (i = 0, gTdb = geneTdbList; i < menuSize && gTdb != NULL; i++, gTdb = gTdb->next) { values[i] = gTdb->track; if (gTdb->parent != NULL) { struct dyString *dy = dyStringNew(0); if (gTdb->parent->parent != NULL && !startsWith(gTdb->parent->parent->shortLabel, gTdb->parent->shortLabel)) dyStringPrintf(dy, "%s: ", gTdb->parent->parent->shortLabel); if (!startsWith(gTdb->parent->shortLabel, gTdb->shortLabel)) dyStringPrintf(dy, "%s: ", gTdb->parent->shortLabel); dyStringPrintf(dy, "%s", gTdb->shortLabel); labels[i] = dyStringCannibalize(&dy); } else labels[i] = gTdb->shortLabel; } printf("
\n"); puts(""); for (i = 0; i < menuSize; ++i) { if (i > 0 && (i % numCols) == 0) printf(""); printf(""); } if ((i % numCols) != 0) while ((i++ % numCols) != 0) printf(""); puts("
"); geneTrackMakeCheckBox(cart, correctTdb, values[i], labels[i], slNameInList(defaultGeneTracks, values[i]) ); printf("
"); jsEndCollapsibleSection(); } } void bigDbSnpCfgUi(char *db, struct cart *cart, struct trackDb *leafTdb, char *name, char *title, boolean boxed) /* UI for bigDbSnp a.k.a. "dbSNP 2.0". */ { boxed = cfgBeginBoxAndTitle(leafTdb, boxed, title); freqSourceSelect(cart, leafTdb, name); puts("
"); puts("Label:"); struct trackDb *correctTdb = tdbOrAncestorByName(leafTdb, name); labelMakeCheckBox(cart, correctTdb, "rsId", "rs# identifier", TRUE); labelMakeCheckBox(cart, correctTdb, "refAlt", "reference/alternate allele", TRUE); labelMakeCheckBox(cart, correctTdb, "majMin", "major/minor allele", FALSE); labelMakeCheckBox(cart, correctTdb, "maf", "MAF if available", FALSE); labelMakeCheckBox(cart, correctTdb, "func", "Most severe functional impact on gene if any", FALSE); puts("
"); scoreCfgUi(db, cart, leafTdb, name, "", 0, FALSE); puts("For more information about the "Interesting or anomalous properties", " "see below."); puts("

"); puts("Minimum MAF:"); boolean parentLevel = isNameAtParentLevel(leafTdb, name); double minMaf = cartUsualDoubleClosestToHome(cart, leafTdb, parentLevel, "minMaf", 0.0); char cartVar[1024]; safef(cartVar, sizeof cartVar, "%s.minMaf", name); cgiMakeDoubleVarWithLimits(cartVar, minMaf, "MAF", 0, 0.0, 0.5); puts("range: 0.0 - 0.5
"); // Make wrapper table for collapsible sections: puts(""); snp153OfferGeneTracksForFunction(db, cart, name, leafTdb, correctTdb); // End wrapper table for collapsible sections: puts("
"); wigOption(cart, name, title, leafTdb); cfgEndBox(boxed); } void cfgByCfgType(eCfgType cType,char *db, struct cart *cart, struct trackDb *tdb,char *prefix, char *title, boolean boxed) // Methods for putting up type specific cfgs used by composites/subtracks in hui.c { // When only one subtrack, then show it's cfg settings instead of composite/view level settings // This simplifies the UI where hgTrackUi won't have 2 levels of cfg, // while hgTracks still supports rightClick cfg of the subtrack. if (configurableByAjax(tdb,cType) > 0) // Only if subtrack's configurable by ajax do we { // consider this option if (tdbIsComposite(tdb) // called for the composite && !isCustomComposite(tdb) && !tdbIsCompositeView(tdb->subtracks) // and there is no view level && slCount(tdb->subtracks) == 1) // and there is only one subtrack { tdb = tdb->subtracks; // show subtrack cfg instead prefix = tdb->track; } else if (tdbIsSubtrack(tdb) // called with subtrack && tdbIsCompositeView(tdb->parent) // subtrack has view && differentString(prefix,tdb->track) // and this has been called FOR the view && slCount(tdb->parent->subtracks) == 1) // and view has only one subtrack prefix = tdb->track; // removes reference to view level } // Cfg could be explicitly blocked, but if tdb is example subtrack // then blocking should have occurred before we got here. if (!tdbIsSubtrack(tdb) && trackDbSettingBlocksConfiguration(tdb,FALSE)) return; // composite/view must pass in example subtrack // NOTE: if subtrack types vary then there shouldn't be cfg at composite/view level! while (tdb->subtracks) tdb = tdb->subtracks; switch(cType) { case cfgBedScore: { char *scoreMax = trackDbSettingClosestToHome(tdb, SCORE_FILTER _MAX); int maxScore = (scoreMax ? sqlUnsigned(scoreMax):1000); scoreCfgUi(db, cart,tdb,prefix,title,maxScore,boxed); if(startsWith("bigBed", tdb->type)) { labelCfgUi(db, cart, tdb, prefix); mergeSpanCfgUi(cart, tdb, prefix); wigOption(cart, prefix, title, tdb); } } break; case cfgPeak: encodePeakCfgUi(cart,tdb,prefix,title,boxed); break; case cfgWig: wigCfgUi(cart,tdb,prefix,title,boxed); break; case cfgWigMaf: wigMafCfgUi(cart,tdb,prefix,title,boxed, db); break; case cfgGenePred: genePredCfgUi(db, cart,tdb,prefix,title,boxed); if(startsWith("bigGenePred", tdb->type)) { char *scoreMax = trackDbSettingClosestToHome(tdb, SCORE_FILTER _MAX); int maxScore = (scoreMax ? sqlUnsigned(scoreMax):1000); scoreCfgUi(db, cart,tdb,prefix,title,maxScore,boxed); } break; case cfgChain: chainCfgUi(db,cart,tdb,prefix,title,boxed, NULL); break; case cfgNetAlign: netAlignCfgUi(db,cart,tdb,prefix,title,boxed); break; case cfgBedFilt: bedFiltCfgUi(cart,tdb,prefix,title, boxed); break; case cfgBam: bamCfgUi(cart, tdb, prefix, title, boxed); break; case cfgVcf: vcfCfgUi(cart, tdb, prefix, title, boxed); break; case cfgLong: longRangeCfgUi(cart, tdb, prefix, title, boxed); break; case cfgSnake: snakeCfgUi(cart, tdb, prefix, title, boxed); break; case cfgPsl: pslCfgUi(db,cart,tdb,prefix,title,boxed); break; case cfgBarChart: barChartCfgUi(db,cart,tdb,prefix,title,boxed); break; case cfgInteract: interactCfgUi(db,cart,tdb,prefix,title,boxed); break; case cfgBigRmsk: bigRmskCfgUi(db,cart,tdb,prefix,title,boxed); break; case cfgLollipop: lollyCfgUi(db,cart,tdb,prefix,title,boxed); scoreCfgUi(db, cart,tdb,prefix,title,1000,boxed); break; case cfgHic: hicCfgUi(db,cart,tdb,prefix,title,boxed); break; case cfgBigDbSnp: bigDbSnpCfgUi(db, cart, tdb, prefix, title, boxed); break; default: warn("Track type is not known to multi-view composites. type is: %d ", cType); break; } } char *encodeRestrictionDate(char *db,struct trackDb *trackDb,boolean excludePast) // Create a string for ENCODE restriction date of this track // if return is not null, then free it after use { if (!trackDb) return NULL; char *date = NULL; if (metadataForTable(db,trackDb,NULL) != NULL) { date = cloneString((char *)metadataFindValue(trackDb,"dateUnrestricted")); if (date != NULL) date = strSwapChar(date, ' ', 0); // Truncate time (not expected, but just in case) if (excludePast && !isEmpty(date) && dateIsOld(date, MDB_ENCODE_DATE_FORMAT)) freez(&date); } return date; } /* Subtrack configuration settings */ struct subtrackConfigSettings { sortOrder_t *sortOrder; /* from trackDb setting */ boolean useDragAndDrop; /* from trackDb setting */ boolean restrictions; /* from metadata ? */ boolean colorPatch; /* from trackDb setting */ boolean displayAll; /* from radiobutton */ int bgColorIx; /* from logic over other settings */ int columnCount; /* determined from trackDb settings */ }; #define LARGE_COMPOSITE_CUTOFF 30 static void printSubtrackListRadioButtons(char *parentTrack, int subCount, boolean displayAll) // Print radio buttons for all/select { printf("List subtracks: "); char javascript[JBUFSIZE]; safef(javascript, sizeof(javascript), "showOrHideSelectedSubtracks(true);"); char buffer[SMALLBUF]; if (subCount > LARGE_COMPOSITE_CUTOFF) safef(buffer,SMALLBUF,"%s.displaySubtracks", parentTrack); else safecpy(buffer,SMALLBUF,"displaySubtracks"); cgiMakeOnEventRadioButtonWithClass(buffer, "selected", !displayAll, "allOrOnly", "click", javascript); puts("only selected/visible   "); safef(javascript, sizeof(javascript), "showOrHideSelectedSubtracks(false);"); cgiMakeOnEventRadioButtonWithClass(buffer, "all", displayAll, "allOrOnly", "click", javascript); printf("all"); if (subCount > 5) printf("    ()"); } static void printSubtrackTableHeader(struct trackDb *parentTdb, struct slRef *subtrackRefList, struct subtrackConfigSettings *settings) /* Print header of subtrack table, including classes describing display appearance and behavior. Return number of columns */ { boolean useDragAndDrop = settings->useDragAndDrop; sortOrder_t *sortOrder = settings->sortOrder; if (sortOrder != NULL) puts(""); else puts(""); int colspan = 3; if (sortOrder != NULL) colspan = sortOrder->count+2; else if (!tdbIsMultiTrack(parentTdb)) // An extra column for subVis/wrench so dragAndDrop works colspan++; if (settings->colorPatch) colspan++; int columnCount = 0; if (sortOrder != NULL) printf("\n", useDragAndDrop ? " nodrop nodrag" : ""); else { printf("", useDragAndDrop ? " id='noDrag' class='nodrop nodrag'" : ""); // First table row contains the display "selected/visible" or "all" radio buttons // NOTE: list subtrack radio buttons are inside tracklist table header if // there are no sort columns. The reason is to ensure spacing of lines // column headers when the only column header is "Restricted Until" printf("", colspan); int subCount = slCount(subtrackRefList); printSubtrackListRadioButtons(parentTdb->track, subCount, settings->displayAll); puts(""); columnCount = colspan; } // Add column headers which are sort button links if (sortOrder != NULL) { printf(" \n", sortOrder->htmlId, sortOrder->sortOrder); // keeing track of sortOrder columnCount++; if (!tdbIsMultiTrack(parentTdb)) // An extra column for subVis/wrench so dragAndDrop works { printf("\n"); columnCount++; } // Columns in tdb order (unchanging), sort in cart order (changed by user action) int sIx=0; for (sIx=0;sIxcount;sIx++) { if (sameString(SORT_ON_TRACK_NAME,sortOrder->column[sIx])) break; // All wrangler requested sort orders have been done. if (sameString(SORT_ON_RESTRICTED,sortOrder->column[sIx])) break; // All wrangler requested sort orders have been done. printf("%s", sortOrder->column[sIx], (sortOrder->forward[sIx] ? "" : " sortRev"),sortOrder->order[sIx], sortOrder->title[sIx]); jsOnEventById("click", sortOrder->column[sIx], "tableSortAtButtonPress(this);"); printf("%s",(sortOrder->forward[sIx]?"↓":"↑")); if (sortOrder->count > 1) printf("%d",sortOrder->order[sIx]); printf(""); puts(""); columnCount++; } // longLabel column assert(sameString(SORT_ON_TRACK_NAME,sortOrder->column[sIx])); printf("  Track Name", sortOrder->column[sIx],(sortOrder->forward[sIx]?"":" sortRev"),sortOrder->order[sIx]); jsOnEventById("click", sortOrder->column[sIx], "tableSortAtButtonPress(this);"); printf("%s%d",(sortOrder->forward[sIx]?"↓":"↑"),sortOrder->order[sIx]); puts(""); columnCount++; } puts(" "); // schema column columnCount++; // Finally there may be a restricted until column if (settings->restrictions) { if (sortOrder != NULL) { int sIx=sortOrder->count-1; assert(sameString(SORT_ON_RESTRICTED,sortOrder->column[sIx])); printf(" Restricted Until", sortOrder->column[sIx], (sortOrder->forward[sIx]?"":" sortRev"),sortOrder->order[sIx]); jsOnEventById("click", sortOrder->column[sIx], "tableSortAtButtonPress(this);"); printf("%s%d",(sortOrder->forward[sIx] ? "↓" : "↑"), sortOrder->order[sIx]); puts(""); } else { printf(" "); printf("Restricted Until", ENCODE_DATA_RELEASE_POLICY); puts(" "); } columnCount++; } puts(""); // The end of the header section. settings->columnCount = columnCount; } static void printSubtrackTableFooter(int subCount, struct subtrackConfigSettings *settings) /* Print footer with restriction policy if needed */ { boolean restrictions = settings->restrictions; sortOrder_t *sortOrder = settings->sortOrder; int columnCount = settings->columnCount; if (subCount > 5 || (restrictions && sortOrder != NULL)) { printf("", COLOR_BG_DEFAULT_DARKER); if (restrictions && sortOrder != NULL) printf("    ",columnCount-1); else printf("    ",columnCount); // Count of subtracks is filled in by javascript. if (subCount > 5) printf("\n"); printf("\n"); // Restriction policy needs a link if (restrictions && sortOrder != NULL) printf("Restriction Policy", ENCODE_DATA_RELEASE_POLICY); printf("\n"); } } /********************/ /* Basic info for a controlled vocabulary term */ struct vocabBasic { struct vocabBasic *next; char *term; char *description; char *url; }; boolean vocabSettingIsEncode(char *setting) /* Distinguish ENCODE controlled vocab settings (first arg is cv.ra filename) from non-ENCODE (table-based vocabs) */ { if (setting && (strchr(cloneFirstWord(setting), '=') == NULL)) return TRUE; return FALSE; } char *vocabLink(struct hash *vocabFieldHash, char *term, char *title) /* Make an anchor with mouseover containing description and link if present */ { struct vocabBasic *vocab = hashFindVal(vocabFieldHash, term); if (vocab == NULL) return NULL; struct dyString *ds = dyStringNew(0); if (vocab->url == NULL || strlen(vocab->url) == 0) dyStringPrintf(ds, "%s", vocab->description, term); else dyStringPrintf(ds, "%s\n", vocab->description, vocab->url, term); return dyStringCannibalize(&ds); } struct hash *vocabBasicFromSetting(struct trackDb *parentTdb, struct cart *cart) /* Get description and URL for all vocabTables. Returns a hash of hashes */ { char *spec = trackDbSetting(parentTdb, "controlledVocabulary"); if (!spec) return NULL; // Not yet implemented for ENCODE-style CV if (vocabSettingIsEncode(spec)) return NULL; struct slPair *vocabTables = slPairFromString(spec); struct slPair *vocabTable = NULL; struct hash *tableHash = hashNew(0); struct sqlResult *sr; char **row; char query[256]; char *database = cartString(cart, "db"); for (vocabTable = vocabTables; vocabTable != NULL; vocabTable = vocabTable->next) { char *db = database; char *tableSpec = (char *)vocabTable->val; char *tableName = chopPrefix(tableSpec); if (differentString(tableName, tableSpec)) { chopSuffix(tableSpec); db = tableSpec; } struct sqlConnection *conn = hAllocConn(db); boolean hasUrl = FALSE; struct hash *subgroupHash = hashNew(0); hashAdd(tableHash, vocabTable->name, subgroupHash); if (hHasField(db, tableName, "url")) { sqlSafef(query, sizeof(query), "select term, description, url from %s", tableName); hasUrl = TRUE; } else sqlSafef(query, sizeof(query), "select term, description from %s", tableName); sr = sqlGetResult(conn, query); while ((row = sqlNextRow(sr)) != NULL) { struct vocabBasic *vocab = NULL; AllocVar(vocab); vocab->term = cloneString(row[0]); vocab->description = cloneString(row[1]); if (hasUrl) vocab->url = cloneString(row[2]); hashAdd(subgroupHash, vocab->term, vocab); } sqlFreeResult(&sr); hFreeConn(&conn); } return tableHash; } static void printSubtrackTableBody(struct trackDb *parentTdb, struct slRef *subtrackRefList, struct subtrackConfigSettings *settings, struct cart *cart) /* Print list of subtracks */ { sortOrder_t *sortOrder = settings->sortOrder; boolean useDragAndDrop = settings->useDragAndDrop; boolean restrictions = settings->restrictions; struct dyString *dyHtml = dyStringNew(SMALLBUF); char buffer[SMALLBUF]; char id[SMALLBUF]; char *db = cartString(cart, "db"); // The subtracks need to be sorted by priority but only sortable and dragable will have // non-default (cart) priorities to sort on if (sortOrder != NULL || useDragAndDrop) { // preserves user's prev sort/drags, ignore returned value about where // priorities come from (void) tdbRefSortPrioritiesFromCart(cart, &subtrackRefList); printf("\n", (sortOrder != NULL ? "sortable " : "") ); } else { slSort(&subtrackRefList, trackDbRefCmp); // straight from trackDb.ra puts(""); } // Finally the big "for loop" to list each subtrack as a table row. printf("\n\n"); membersForAll_t* membersForAll = membersForAllSubGroupsGet(parentTdb,NULL); struct hash *vocabHash = vocabBasicFromSetting(parentTdb, cart); struct slRef *subtrackRef; /* Color handling ?? */ //char *colors[2] = { COLOR_BG_DEFAULT, // COLOR_BG_ALTDEFAULT }; char *colors[2] = { "bgLevel1", "bgLevel1" }; int colorIx = settings->bgColorIx; for (subtrackRef = subtrackRefList; subtrackRef != NULL; subtrackRef = subtrackRef->next) { struct trackDb *subtrack = subtrackRef->val; int ix; // Determine whether subtrack is checked, visible, configurable, has group membership, etc. int fourState = subtrackFourStateChecked(subtrack,cart); boolean checkedCB = fourStateChecked(fourState); boolean enabledCB = fourStateEnabled(fourState); boolean visibleCB = fourStateVisible(fourState); membership_t *membership = subgroupMembershipGet(subtrack); eCfgType cType = cfgNone; if (!tdbIsMultiTrack(parentTdb)) // MultiTracks never have configurable subtracks! cType = cfgTypeFromTdb(subtrack,FALSE); if (cType != cfgNone) { // Turn off configuring for certain track type or if explicitly turned off int cfgSubtrack = configurableByAjax(subtrack,cType); if (cfgSubtrack <= cfgNone) cType = cfgNone; else if (membersForAll->members[dimV] && membership != NULL) { // subtrack only configurable if more than one subtrack in view // find "view" in subgroup membership: e.g. "signal" if (-1 != (ix = stringArrayIx(membersForAll->members[dimV]->groupTag, membership->subgroups, membership->count))) { int ix2; // find "signal" in set of all views if (-1 != (ix2 = stringArrayIx(membership->membership[ix], membersForAll->members[dimV]->tags, membersForAll->members[dimV]->count))) { if (membersForAll->members[dimV]->subtrackCount[ix2] < 2) cType = cfgNone; } } } else if (slCount(subtrackRefList) < 2 // don't bother if there is a single subtrack && cfgTypeFromTdb(parentTdb,FALSE) != cfgNone) // but the composite is configurable. cType = cfgNone; } if (sortOrder == NULL && !useDragAndDrop) { char **lastDivide = NULL; dividers_t *dividers = dividersSettingGet(parentTdb); if (dividers) lastDivide = needMem(sizeof(char*)*dividers->count); if (membership && divisionIfNeeded(lastDivide,dividers,membership) ) colorIx = (colorIx == COLOR_BG_DEFAULT_IX ? COLOR_BG_ALTDEFAULT_IX : COLOR_BG_DEFAULT_IX); dividersFree(÷rs); } safef(id, sizeof(id), "%s_sel", subtrack->track); printf("\n",id,(!visibleCB && !settings->displayAll?" style='display:none'":"")); // Now the TD that holds the checkbox printf("", (enabledCB?"":" title='view is hidden'"), (useDragAndDrop?" class='dragHandle' title='Drag to reorder'":"")); // A hidden field to keep track of subtrack order if it could change if (sortOrder != NULL || useDragAndDrop) { safef(buffer, sizeof(buffer), "%s.priority", subtrack->track); float priority = (float)cartUsualDouble(cart, buffer, subtrack->priority); printf("", buffer, priority); // keeing track of priority } // The checkbox has identifying classes including subCB and the tag for each dimension // (e.g. class='subCB GM12878 CTCF Peak') dyStringClear(dyHtml); dyStringAppend(dyHtml, "subCB"); // always first int di; if (membersForAll->dimensions && membership != NULL) { for (di=dimX;didimMax;di++) { if (membersForAll->members[di] && -1 != (ix = stringArrayIx(membersForAll->members[di]->groupTag, membership->subgroups, membership->count))) dyStringPrintf(dyHtml," %s",membership->membership[ix]); } } else if (membersForAll->abcCount && membership != NULL) // "dimensions" don't exist but may be subgroups anyway { for (di=dimA;didimMax;di++) { if (membersForAll->members[di] && -1 != (ix = stringArrayIx(membersForAll->members[di]->groupTag, membership->subgroups, membership->count))) dyStringPrintf(dyHtml," %s",membership->membership[ix]); } } if (membersForAll->members[dimV] && membership != NULL && -1 != (ix = stringArrayIx(membersForAll->members[dimV]->groupTag, membership->subgroups, membership->count))) dyStringPrintf(dyHtml, " %s",membership->membership[ix]); // Saved view for last // And finally the checkBox is made! safef(buffer, sizeof(buffer), "%s_sel", subtrack->track); if (!enabledCB) { dyStringAppend(dyHtml, " disabled"); cgiMakeCheckBoxFourWay(buffer,checkedCB,enabledCB,id,dyStringContents(dyHtml), "style='cursor:pointer' title='view is hidden'"); jsOnEventById("click", id, "matSubCbClick(this);"); } else { cgiMakeCheckBoxFourWay(buffer,checkedCB,enabledCB,id,dyStringContents(dyHtml), "style='cursor:pointer'"); jsOnEventById("click", id, "matSubCbClick(this);"); } if (useDragAndDrop) printf(" "); if (!tdbIsMultiTrack(parentTdb)) // MultiTracks never have independent vis { printf(""); // An extra column for subVis/wrench so dragAndDrop works enum trackVisibility vis = tdbVisLimitedByAncestors(cart,subtrack,FALSE,FALSE); char *view = NULL; if (membersForAll->members[dimV] && membership !=NULL && -1 != (ix = stringArrayIx(membersForAll->members[dimV]->groupTag, membership->subgroups, membership->count))) view = membership->membership[ix]; char classList[256]; if (view != NULL) safef(classList,sizeof(classList),"clickable fauxInput%s subVisDD %s", (visibleCB ? "":" disabled"),view); // view should be last! else safef(classList,sizeof(classList),"clickable fauxInput%s subVisDD", (visibleCB ? "":" disabled")); #define SUBTRACK_CFG_VIS "
%s
\n" printf(SUBTRACK_CFG_VIS,subtrack->track,classList,hStringFromTv(vis)); char id[256]; safef(id, sizeof id, "%s_faux", subtrack->track); jsOnEventByIdF("click", id, "return subCfg.replaceWithVis(this,\"%s\",true);", subtrack->track); if (cType != cfgNone) // make a wrench { safef(id, sizeof id, "%s_toggle", subtrack->track); #define SUBTRACK_CFG_WRENCH "" \ " Configure\n" printf(SUBTRACK_CFG_WRENCH,id, (visibleCB ? "":" disabled")); jsOnEventByIdF("click", id, "return subCfg.cfgToggle(this,\"%s\");", subtrack->track); } } printf(""); // If sortable, then there must be a column per sortable dimension if (sortOrder != NULL) { int sIx=0; for (sIx=0; sIx count; sIx++) { ix = -1; char *col = sortOrder->column[sIx]; if (membership) ix = stringArrayIx(col, membership->subgroups, membership->count); // TODO: Sort needs to expand from subGroups to labels as well // only print the warning message for trackDb errors and not for the // default sortable columns of trackName and dateUnrestricted if ( (!membership || (membership && ix == -1) ) && !(sameString(col, "trackName") || sameString(col, "dateUnrestricted") || sameString(col, "subtrackColor")) ) { printf("Missing subgroup"); } else { if (ix >= 0) { char *term = membership->membership[ix]; char *title = membership->titles[ix]; char *titleRoot=NULL; if (cvTermIsEmpty(col, title)) titleRoot = cloneString("  "); else titleRoot = labelRoot(title, NULL); // Each sortable column requires hidden goop (in the "abbr" field currently) // which is the actual sort on value printf("", subtrack->track, col, term); printf(" "); char *link = NULL; if (vocabHash) { struct hash *colHash = hashFindVal(vocabHash, col); if (colHash) link = vocabLink(colHash, term, titleRoot); } printf("%s", link ? link : titleRoot); puts(""); freeMem(titleRoot); } else if (sameString(col, SUBTRACK_COLOR_SUBGROUP)) { char *hue = subtrackColorToCompare(subtrack); printf("" "    ", subtrack->track, col, hue, subtrack->colorR, subtrack->colorG, subtrack->colorB); } } } } else // Non-sortable tables do not have sort by columns but will display a short label { // (which may be a configurable link) if (settings->colorPatch) { printf("    ", subtrack->colorR, subtrack->colorG, subtrack->colorB); } printf(" "); hierarchy_t *hierarchy = hierarchySettingGet(parentTdb); indentIfNeeded(hierarchy,membership); hierarchyFree(&hierarchy); printf("%s",subtrack->shortLabel); puts(""); } // The long label column (note that it may have a metadata dropdown) printf(" %s", subtrack->longLabel); if (trackDbSetting(parentTdb, "wgEncode") && trackDbSetting(subtrack, "accession")) printf(" [GEO:%s]", trackDbSetting(subtrack, "accession")); compositeMetadataToggle(db,subtrack,NULL,TRUE,FALSE); printf(" "); // Embedded cfg dialogs are within the TD that contains the longLabel. // This allows a wide item to be embedded in the table if (cType != cfgNone) { // How to make this thing float to the left? Container is overflow:visible // and contained (made in js) is position:relative; left: -{some pixels} #define CFG_SUBTRACK_DIV "" #define MAKE_CFG_SUBTRACK_DIV(table,view) \ printf(CFG_SUBTRACK_DIV,(table),(view)?(view):"noView") char * view = NULL; if (membersForAll->members[dimV] && membership != NULL && -1 != (ix = stringArrayIx(membersForAll->members[dimV]->groupTag, membership->subgroups, membership->count))) view = membership->membership[ix]; MAKE_CFG_SUBTRACK_DIV(subtrack->track,view); } // A schema link for each track printf("\n "); makeSchemaLink(db,subtrack,"Data format"); printf(" "); // Do we have a restricted until date? if (restrictions) { char *dateDisplay = encodeRestrictionDate(db,subtrack,FALSE); // includes dates in the past if (dateDisplay) { if (dateIsOld(dateDisplay, MDB_ENCODE_DATE_FORMAT)) printf("\n %s ", dateDisplay); else printf("\n %s ", dateDisplay); } } // End of row and free ourselves of this subtrack puts("\n"); boolean showCfg = trackDbSettingOn(subtrack, "showCfg"); if (showCfg) jsInlineF(" subCfg.cfgToggle(document.getElementById(\"%s_toggle\"),\"%s\");", subtrack->track, subtrack->track); } // End of the table puts(""); dyStringFree(&dyHtml); membersForAllSubGroupsFree(parentTdb,&membersForAll); } static boolean membersHaveMatrix(membersForAll_t *membersForAll) /* Check for matrix */ { if (membersForAll->members[dimX] == NULL && membersForAll->members[dimY] == NULL) return FALSE; return TRUE; } static void printSubtrackTable(struct trackDb *parentTdb, struct slRef *subtrackRefList, struct subtrackConfigSettings *settings, struct cart *cart) /* Print table of subtracks */ { // Print table tag printf("\nsortOrder != NULL) dyStringPrintf(dyHtml, "sortable"); if (settings->useDragAndDrop) { if (dyStringLen(dyHtml) > 0) dyStringAppendC(dyHtml,' '); dyStringPrintf(dyHtml, "tableWithDragAndDrop"); } printf(" class='subtracks"); if (dyStringLen(dyHtml) > 0) { printf(" bglevel1 %s'",dyStringContents(dyHtml)); settings->bgColorIx = COLOR_BG_ALTDEFAULT_IX; } else settings->bgColorIx = COLOR_BG_DEFAULT_IX; // Start with non-default allows alternation puts("'>"); dyStringFree(&dyHtml); // save count of subtracks for use by footer code int subCount = slCount(subtrackRefList); printSubtrackTableHeader(parentTdb, subtrackRefList, settings); printSubtrackTableBody(parentTdb, subtrackRefList, settings, cart); printSubtrackTableFooter(subCount, settings); puts("
"); } boolean compositeHideEmptySubtracksSetting(struct trackDb *tdb, boolean *retDefault, char **retMultiBedFile, char **retSubtrackIdFile) /* Parse hideEmptySubtracks settings * Format: hideEmptySubtracks on|off * Optional index files for performance: * hideEmptySubtracksMultiBedUrl multiBed.bigBed * hideEmptySubtracksSourceUrl subtrackIds.tab * MultiBed.bed is a bed3Sources bigBed, generated with UCSC tool trackDbIndexBb * (for single view subtracks, can use bedtools multiinter * post-processed by UCSC multiBed.pl tool) * subtrackIds.tab is a tab-sep file: id subtrackName * * Return TRUE if setting is present. retDefault is TRUE if set to 'on', o/w FALSE */ { if (!tdbIsComposite(tdb)) return FALSE; char *hideEmpties = cloneString(trackDbSetting(tdb, SUBTRACK_HIDE_EMPTY)); if (!hideEmpties) return FALSE; boolean deflt = FALSE; if (sameString(hideEmpties, "on")) deflt = TRUE; else if (differentString(hideEmpties, "off")) { warn("Track %s %s setting invalid: %s", tdb->track, SUBTRACK_HIDE_EMPTY, hideEmpties); return FALSE; } if (retDefault) *retDefault = deflt; if (retMultiBedFile != NULL && retSubtrackIdFile != NULL) { char *file = cloneString(trackDbSetting(tdb, SUBTRACK_HIDE_EMPTY_MULTIBED_URL)); if (file != NULL) { // multi-bed specified to speed display *retMultiBedFile = cloneString(hReplaceGbdb(file)); file = cloneString(trackDbSetting(tdb, SUBTRACK_HIDE_EMPTY_SOURCES_URL)); if (file == NULL) { warn("Track %s missing setting: %s", tdb->track, SUBTRACK_HIDE_EMPTY_SOURCES_URL); return FALSE; } *retSubtrackIdFile = cloneString(hReplaceGbdb(file)); } } return TRUE; } boolean compositeHideEmptySubtracks(struct cart *cart, struct trackDb *tdb, char **retMultiBedFile, char **retSubtrackIdFile) /* Parse hideEmptySubtracks setting and check cart * Return TRUE if we should hide empties */ { boolean deflt = FALSE; if (!compositeHideEmptySubtracksSetting(tdb, &deflt, retMultiBedFile, retSubtrackIdFile)) return FALSE; char buf[128]; safef(buf, sizeof buf, "%s.%s", tdb->track, SUBTRACK_HIDE_EMPTY); return cartUsualBoolean(cart, buf, deflt); } boolean compositeChildHideEmptySubtracks(struct cart *cart, struct trackDb *childTdb, char **retMultiBedFile, char **retSubtrackIdFile) /* Parse hideEmptySubtracks setting and check cart * Return TRUE if we should hide empties */ { struct trackDb *tdb = tdbGetComposite(childTdb); if (!tdb) return FALSE; return compositeHideEmptySubtracks(cart, tdb, retMultiBedFile, retSubtrackIdFile); } static void compositeUiSubtracks(char *db, struct cart *cart, struct trackDb *parentTdb) // Display list of subtracks and descriptions with checkboxes to control visibility and // possibly other nice things including links to schema and metadata and a release date. { char buffer[SMALLBUF]; struct trackDb *subtrack; // Get list of leaf subtracks to work with struct slRef *subtrackRef, *subtrackRefList = trackDbListGetRefsToDescendantLeaves(parentTdb->subtracks); membersForAll_t* membersForAll = membersForAllSubGroupsGet(parentTdb,NULL); sortOrder_t* sortOrder = sortOrderGet(cart, parentTdb); char *displaySubs = NULL; int subCount = slCount(subtrackRefList); if (subCount > LARGE_COMPOSITE_CUTOFF && membersForAll->dimensions != NULL) { // ignore displaySubtracks setting for large composites with a matrix as // matrix effectively shows all safef(buffer, SMALLBUF,"%s.displaySubtracks", parentTdb->track); displaySubs = cartUsualString(cart, buffer,"some"); // track specific defaults to only selected } else { displaySubs = cartUsualString(cart, "displaySubtracks", "all"); // browser wide defaults to all } boolean displayAll = sameString(displaySubs, "all"); // Table wraps around entire list so that "Top" link can float to the correct place. cgiDown(0.7); printf("
"); printf(""); if (sortOrder != NULL) { // First table row contains the display "selected/visible" or "all" radio buttons // NOTE: list subtrack radio buttons are inside tracklist table header if // there are no sort columns. The reason is to ensure spacing of lines // column headers when the only column header is "Restricted Until" printSubtrackListRadioButtons(parentTdb->track, subCount, displayAll); if (membersHaveMatrix(membersForAll)) makeTopLink(parentTdb); printf("
"); } else { if (membersHaveMatrix(membersForAll)) makeTopLink(parentTdb); } // Get info for subtrack list struct subtrackConfigSettings *settings = NULL; AllocVar(settings); // Determine whether there is a restricted until date column settings->restrictions = FALSE; for (subtrackRef = subtrackRefList; subtrackRef != NULL; subtrackRef = subtrackRef->next) { subtrack = subtrackRef->val; (void)metadataForTable(db,subtrack,NULL); if (NULL != metadataFindValue(subtrack,"dateUnrestricted")) { settings->restrictions = TRUE; break; } } settings->useDragAndDrop = sameOk("subTracks",trackDbSetting(parentTdb, "dragAndDrop")); settings->sortOrder = sortOrder; settings->displayAll = displayAll; settings->colorPatch = (trackDbSetting(parentTdb, SUBTRACK_COLOR_PATCH) != NULL); printSubtrackTable(parentTdb, subtrackRefList, settings, cart); if (sortOrder == NULL) printf(""); membersForAllSubGroupsFree(parentTdb,&membersForAll); sortOrderFree(&sortOrder); } static void compositeUiSubtracksMatchingPrimary(char *db, struct cart *cart, struct trackDb *parentTdb,char *primarySubtrack) // Display list of subtracks associated with a primary subtrack for the hgTables merge function { assert(primarySubtrack != NULL); char *primaryType = getPrimaryType(primarySubtrack, parentTdb); char htmlIdentifier[SMALLBUF]; // Get list of leaf subtracks to work with and sort them struct slRef *subtrackRef, *subtrackRefList = trackDbListGetRefsToDescendantLeaves(parentTdb->subtracks); if (NULL != trackDbSetting(parentTdb, "sortOrder") || NULL != trackDbSetting(parentTdb, "dragAndDrop")) tdbRefSortPrioritiesFromCart(cart, &subtrackRefList); // preserves user's prev sort/drags else slSort(&subtrackRefList, trackDbRefCmp); // straight from trackDb.ra // Now we can start in on the table of subtracks printf("\n" "\n\n",parentTdb->track); for (subtrackRef = subtrackRefList; subtrackRef != NULL; subtrackRef = subtrackRef->next) { struct trackDb *subtrack = subtrackRef->val; int fourState = subtrackFourStateChecked(subtrack,cart); boolean checkedCB = fourStateChecked(fourState); boolean enabledCB = fourStateEnabled(fourState); safef(htmlIdentifier, sizeof(htmlIdentifier), "%s_sel", subtrack->track); if (sameString(subtrack->track, primarySubtrack)) { puts("\n", subtrack->longLabel); } else if (hSameTrackDbType(primaryType, subtrack->type)) { puts("\n", subtrack->longLabel); } } puts(""); puts("
"); cgiMakeHiddenBoolean(htmlIdentifier, TRUE); puts("[on] "); printf("%s [selected on main page]
"); cgiMakeCheckBox(htmlIdentifier, checkedCB && enabledCB); printf("%s
"); if (slCount(subtrackRefList) > 5) puts("    "); puts("

"); if (!primarySubtrack) jsInline("matInitializeMatrix();\n"); } static void makeAddClearButtonPair(char *idPrefix, char *class,char *separator) // Print an [Add][Clear] button pair that uses javascript to check subtracks { char buf[256]; if (class) safef(buf, sizeof buf,"matSetMatrixCheckBoxes(true,'%s'); return false;", class); else safef(buf, sizeof buf,"matSetMatrixCheckBoxes(true); return false;"); char id[256]; safef(id, sizeof id, "%s_add", idPrefix); cgiMakeOnClickButton(id, buf, ADD_BUTTON_LABEL); if (separator) printf("%s",separator); if (class) safef(buf, sizeof buf,"matSetMatrixCheckBoxes(false,'%s'); return false;", class); else safef(buf, sizeof buf,"matSetMatrixCheckBoxes(false); return false;"); safef(id, sizeof id, "%s_clr", idPrefix); cgiMakeOnClickButton(id, buf, CLEAR_BUTTON_LABEL); } #define MANY_SUBTRACKS 8 #define WIGGLE_HELP_PAGE "../goldenPath/help/hgWiggleTrackHelp.html" boolean cfgBeginBoxAndTitle(struct trackDb *tdb, boolean boxed, char *title) // Handle start of box and title for individual track type settings { if (!boxed) { boxed = trackDbSettingOn(tdb,"boxedCfg"); if (boxed) printf("
"); } if (boxed) { printf("
", COLOR_BG_ALTDEFAULT); if (title) printf("
%s Configuration
\n", title); } else if (title) printf("

%s  ", title ); else printf("

"); return boxed; } void cfgEndBox(boolean boxed) // Handle end of box and title for individual track type settings { if (boxed) puts("

"); } void snakeOption(struct cart *cart, char *name, char *title, struct trackDb *tdb) /* let the user choose to see the track in snake mode */ { if (!cfgOptionBooleanDefault("canSnake", TRUE)) return; printf("
Display data as a rearrangement graph: "); boolean option = cartOrTdbBoolean(cart, tdb, "doSnake", FALSE); char varName[1024]; safef(varName, sizeof(varName), "%s.doSnake", name); cgiMakeCheckBox(varName, option); printf("
\n"); //char *style = option ? "display:block" : "display:none"; //printf("

\n", style); //printf("
\n\n"); jsInlineF("$(\"input[name='%s']\").click( function() { $('#snakeGraphOptions').toggle();} );\n" , varName); // XSS FILTER? } void squishyPackOption(struct cart *cart, char *name, char *title, struct trackDb *tdb) /* let the user choose to see the track in wiggle mode */ { char option[256]; char buffer[4096]; char *field = trackDbSetting(tdb, "squishyPackField"); if (field == NULL) return; char *fieldLabel = trackDbSetting(tdb, "squishyPackLabel"); if (fieldLabel == NULL) { fieldLabel = buffer; safef(buffer, sizeof buffer, "Reduce (squish) the height of items that have a %s value greater than", field); } double squishyPackPoint = cartOrTdbDouble(cart, tdb, "squishyPackPoint", 999); printf("
%s ", fieldLabel); safef(option, sizeof(option), "%s.%s", name, "squishyPackPoint" ); cgiMakeDoubleVarWithLimits(option, squishyPackPoint, "Range min", 0, NO_VALUE, NO_VALUE); } void wigOption(struct cart *cart, char *name, char *title, struct trackDb *tdb) /* let the user choose to see the track in wiggle mode */ { printf("

Display data as a density graph: "); boolean option = cartOrTdbBoolean(cart, tdb, "doWiggle", FALSE); char varName[1024]; safef(varName, sizeof(varName), "%s.doWiggle", name); cgiMakeCheckBox(varName, option); printf("
\n"); char *style = option ? "display:block" : "display:none"; printf("
\n", name, style); // we need to fool the wiggle dialog into defaulting to autoscale and maximum char *origType = tdb->type; tdb->type = "bedGraph"; if (hashFindVal(tdb->settingsHash, AUTOSCALE) == NULL) hashAdd(tdb->settingsHash, AUTOSCALE, "on"); if (hashFindVal(tdb->settingsHash, WINDOWINGFUNCTION) == NULL) hashAdd(tdb->settingsHash, WINDOWINGFUNCTION, wiggleWindowingEnumToString( wiggleWindowingMean)); wigCfgUi(cart,tdb,name,title,TRUE); tdb->type = origType; printf("
\n\n"); jsInlineF("$(\"input[name='%s']\").click( function() { $('#densGraphOptions%s').toggle();} );\n" , varName, name); // XSS FILTER? } void filterNameOption(struct cart *cart, char *name, struct trackDb *tdb) /* filter by feature names text input box */ { printf("
Show only transcripts with these accessions: "); char varName[1024]; safef(varName, sizeof(varName), "%s.nameFilter", name); char *onlyTransStr = cartUsualString(cart, varName, ""); cgiMakeTextVar(varName, onlyTransStr, 60); printInfoIcon("Enter the primary accession of the track, so RefSeq IDs for the RefSeq track, Gencode IDs for the Gencode track, etc. Separate multiple accessions with commas."); puts("
\n\n"); } void colorTrackOption(struct cart *cart, char *name, struct trackDb *tdb) /* color picker for overriding track color */ { char varName[1024]; safef(varName, sizeof(varName), "%s.colorOverride", name); char *colorValue = cartUsualString(cart, varName, ""); printf(" 
", name); jsInlineF("makeHighlightPicker('%s', document.getElementById('colorPicker_%s'), '%s', 'Change track color:  ', '%s');", varName, name, name, colorValue); // id="xx" is necessary as id contains a dot puts("
\n\n"); } void wiggleScaleDropDownJavascript(char *name) /* print some js that deactivates the min/max range if autoscaling is activated */ { struct dyString *dy = dyStringNew(1024); dyStringPrintf(dy, " $(\"[name='%s.autoScale']\").change(function()\n", name); dyStringPrintf(dy, " {\n"); dyStringPrintf(dy, " val= $(this).find(':selected').val(); \n"); dyStringPrintf(dy, " if (val!=\"use vertical viewing range setting\")\n"); dyStringPrintf(dy, " {\n"); dyStringPrintf(dy, " $(\"[name='%s.minY']\")[0].disabled=true;\n", name); dyStringPrintf(dy, " $(\"[name='%s.maxY']\")[0].disabled=true;\n", name); dyStringPrintf(dy, " $(\".%sAutoScaleDesc\").attr('style', 'color:grey;');\n", name); dyStringPrintf(dy, " }\n"); dyStringPrintf(dy, " else\n"); dyStringPrintf(dy, " {\n"); dyStringPrintf(dy, " $(\"[name='%s.minY']\")[0].disabled=false;\n", name); dyStringPrintf(dy, " $(\"[name='%s.maxY']\")[0].disabled=false;\n", name); dyStringPrintf(dy, " $(\".%sAutoScaleDesc\").attr('style', 'color:black;');\n", name); dyStringPrintf(dy, " }\n"); dyStringPrintf(dy, " });\n"); dyStringPrintf(dy, "\n"); dyStringPrintf(dy, " $( document ).ready(function()\n"); dyStringPrintf(dy, " {\n"); dyStringPrintf(dy, " val= $(\"[name='%s.autoScale']\").find(':selected').val(); \n", name); dyStringPrintf(dy, " if (val==\"auto-scale to data view\")\n"); dyStringPrintf(dy, " {\n"); dyStringPrintf(dy, " $(\"[name='%s.minY']\")[0].disabled=true;\n", name); dyStringPrintf(dy, " $(\"[name='%s.maxY']\")[0].disabled=true;\n", name); dyStringPrintf(dy, " $(\".%sAutoScaleDesc\").attr('style', 'color:grey;');\n", name); dyStringPrintf(dy, " }\n"); dyStringPrintf(dy, " });\n"); jsInline(dy->string); dyStringFree(&dy); } void wigCfgUi(struct cart *cart, struct trackDb *tdb, char *name, char *title, boolean boxed) /* UI for the wiggle track */ { char *typeLine = NULL; /* to parse the trackDb type line */ char *words[8]; /* to parse the trackDb type line */ int wordCount = 0; /* to parse the trackDb type line */ char option[256]; double minY; /* from trackDb or cart */ double maxY; /* from trackDb or cart */ double tDbMinY; /* data range limits from trackDb type line */ double tDbMaxY; /* data range limits from trackDb type line */ char *horizontalGrid = NULL; /* Grid lines, off by default */ char *transformFunc = NULL; /* function to transform data points */ char *alwaysZero = NULL; /* Always include 0 in range */ char *lineBar; /* Line or Bar graph */ char *autoScale; /* Auto scaling on or off */ char *windowingFunction; /* Maximum, Mean, or Minimum */ char *smoothingWindow; /* OFF or [2:16] */ char *yLineMarkOnOff; /* user defined Y marker line to draw */ double yLineMark; /* from trackDb or cart */ int maxHeightPixels = atoi(DEFAULT_HEIGHT_PER); int minHeightPixels = MIN_HEIGHT_PER; int defaultHeight = maxHeightPixels; /* pixels per item */ boxed = cfgBeginBoxAndTitle(tdb, boxed, title); wigFetchMinMaxPixelsWithCart(cart,tdb,name,&minHeightPixels, &maxHeightPixels, &defaultHeight); typeLine = cloneString(tdb->type); wordCount = chopLine(typeLine,words); wigFetchMinMaxYWithCart(cart, tdb, name, &minY, &maxY, &tDbMinY, &tDbMaxY, wordCount, words); freeMem(typeLine); wigFetchTransformFuncWithCart(cart,tdb,name, &transformFunc); wigFetchAlwaysZeroWithCart(cart,tdb,name, &alwaysZero); wigFetchHorizontalGridWithCart(cart,tdb,name, &horizontalGrid); wigFetchAutoScaleWithCart(cart,tdb,name, &autoScale); wigFetchGraphTypeWithCart(cart,tdb,name, &lineBar); wigFetchWindowingFunctionWithCart(cart,tdb,name, &windowingFunction); wigFetchSmoothingWindowWithCart(cart,tdb,name, &smoothingWindow); wigFetchYLineMarkWithCart(cart,tdb,name, &yLineMarkOnOff); wigFetchYLineMarkValueWithCart(cart,tdb,name, &yLineMark); boolean doNegative = wigFetchDoNegativeWithCart(cart,tdb,tdb->track, (char **) NULL); boolean doSequenceLogo = wigFetchDoSequenceLogoWithCart(cart,tdb,tdb->track, (char **) NULL); printf(""); boolean isLogo = ((tdb->parent != NULL) && trackDbSetting(tdb->parent, "logo") != NULL); boolean parentLevel = isNameAtParentLevel(tdb, name); boolean didAggregate = FALSE; if (parentLevel && !isLogo) { assert(tdb->parent != NULL); char *aggregate = trackDbSetting(tdb->parent, "aggregate"); if (aggregate != NULL && parentLevel) { char *aggregateVal = cartOrTdbString(cart, tdb->parent, "aggregate", NULL); safef(option, sizeof(option), "%s.%s", name, AGGREGATE); if (isCustomComposite(tdb)) { printf(""); if (sameString(aggregateVal, WIG_AGGREGATE_STACKED) && sameString(windowingFunction, "mean+whiskers")) { windowingFunction = "maximum"; } didAggregate = TRUE; } if (isCustomComposite(tdb)) { /* char *viewFuncVal = cartOrTdbString(cart, tdb->parent, "viewFunc", NULL); printf(""); } printf(""); printf(""); } printf("" ""); printf(""); if (!isLogo) { printf(""); printf(""); printf(""); printf(""); printf("" "" "
Merge method:"); aggregateExtraDropDown(option, aggregateVal); } else { printf("
Overlay method:"); aggregateDropDown(option, aggregateVal); } puts("
Math method:"); safef(option, sizeof(option), "%s.%s", name, VIEWFUNC); viewFuncDropDown(option, viewFuncVal); */ printf("
Missing data treatment:"); char *missingMethodVal = cartOrTdbString(cart, tdb->parent, "missingMethod", NULL); boolean missingIsZero = (missingMethodVal == NULL) || differentString(missingMethodVal, "missing"); char buffer[1024]; safef(buffer, sizeof buffer, "%s.missingMethod",name); cgiMakeOnEventRadioButtonWithClass(buffer, "zero", missingIsZero, "allOrOnly", "click", NULL); puts("missing is zero  "); cgiMakeOnEventRadioButtonWithClass(buffer, "missing", !missingIsZero, "allOrOnly", "click", NULL); printf("math with missing values is missing"); } } if (!isLogo) { printf("
Type of graph:"); safef( option, sizeof(option), "%s.%s", name, LINEBAR ); wiggleGraphDropDown(option, lineBar); if (boxed) { printf(""); printf("Graph configuration help",WIGGLE_HELP_PAGE); } puts("
Track height:"); safef(option, sizeof(option), "%s.%s", name, HEIGHTPER ); cgiMakeIntVarWithLimits(option, defaultHeight, "Track height",0, minHeightPixels, maxHeightPixels); printf("pixels (range: %d to %d)", minHeightPixels, maxHeightPixels); puts("
Data view scaling:"); safef(option, sizeof(option), "%s.%s", name, AUTOSCALE ); if (tdb->parent || tdb->subtracks) wiggleScaleDropDownParent(option, autoScale); else wiggleScaleDropDown(option, autoScale); wiggleScaleDropDownJavascript(name); if (!isLogo) { safef(option, sizeof(option), "%s.%s", name, ALWAYSZERO); printf("Always include zero: "); wiggleAlwaysZeroDropDown(option, alwaysZero); puts("
Vertical viewing range: min: ", name); safef(option, sizeof(option), "%s.%s", name, MIN_Y ); cgiMakeDoubleVarWithLimits(option, minY, "Range min", 0, NO_VALUE, NO_VALUE); printf("max: "); safef(option, sizeof(option), "%s.%s", name, MAX_Y ); cgiMakeDoubleVarWithLimits(option, maxY, "Range max", 0, NO_VALUE, NO_VALUE); if (!isCustomComposite(tdb)) printf(" (range: %g to %g)", tDbMinY, tDbMaxY); puts("
Transform function:"); safef(option, sizeof(option), "%s.%s", name, TRANSFORMFUNC); printf("Transform data points by: "); wiggleTransformFuncDropDown(option, transformFunc); puts("
Windowing function:"); safef(option, sizeof(option), "%s.%s", name, WINDOWINGFUNCTION ); wiggleWindowingDropDown(option, windowingFunction); puts("Smoothing window:"); safef(option, sizeof(option), "%s.%s", name, SMOOTHINGWINDOW ); wiggleSmoothingDropDown(option, smoothingWindow); puts(" pixels
Negate values:"); safef(option, sizeof(option), "%s.%s", name, DONEGATIVEMODE ); cgiMakeCheckBox(option, doNegative); puts("
Draw y indicator lines:"); printf("at y = 0.0:"); safef(option, sizeof(option), "%s.%s", name, HORIZGRID ); wiggleGridDropDown(option, horizontalGrid); printf("   at y ="); safef(option, sizeof(option), "%s.%s", name, YLINEMARK ); cgiMakeDoubleVarInRange(option, yLineMark, "Indicator at Y", 0, NULL, NULL); safef(option, sizeof(option), "%s.%s", name, YLINEONOFF ); wiggleYLineMarkDropDown(option, yLineMarkOnOff); char *logoMaf = trackDbSetting(tdb, "logoMaf"); if (logoMaf) { printf("
Draw sequence logo when near base level:"); safef(option, sizeof(option), "%s.%s", name, DOSEQUENCELOGOMODE ); cgiMakeCheckBox(option, doSequenceLogo); } } if (boxed) puts("
"); else { puts(""); if (!isLogo) printf("Graph configuration help",WIGGLE_HELP_PAGE); } // add a little javascript call to make sure we don't get whiskers with stacks in multiwigs if (didAggregate) jsInlineF("$(function () { multiWigSetupOnChange('%s'); });\n", name); cfgEndBox(boxed); } void filterButtons(char *filterTypeVar, char *filterTypeVal, boolean none) /* Put up some filter buttons. */ { printf("Filter: "); radioButton(filterTypeVar, filterTypeVal, "red"); radioButton(filterTypeVar, filterTypeVal, "green"); radioButton(filterTypeVar, filterTypeVal, "blue"); radioButton(filterTypeVar, filterTypeVal, "exclude"); radioButton(filterTypeVar, filterTypeVal, "include"); if (none) radioButton(filterTypeVar, filterTypeVal, "none"); } void radioButton(char *var, char *val, char *ourVal) /* Print one radio button */ { cgiMakeRadioButton(var, ourVal, sameString(ourVal, val)); printf("%s ", ourVal); } void oneMrnaFilterUi(struct controlGrid *cg, struct trackDb *tdb, char *text, char *var, char *suffix, struct cart *cart) /* Print out user interface for one type of mrna filter. */ { controlGridStartCell(cg); printf("%s:
", text); boolean parentLevel = isNameAtParentLevel(tdb,var); cgiMakeTextVar(var, cartUsualStringClosestToHome(cart, tdb, parentLevel,suffix, ""), 19); controlGridEndCell(cg); } void bedFiltCfgUi(struct cart *cart, struct trackDb *tdb, char *prefix, char *title, boolean boxed) /* Put up UI for an "bedFilter" tracks. */ { struct mrnaUiData *mud = newBedUiData(prefix); struct mrnaFilter *fil; struct controlGrid *cg = NULL; boolean parentLevel = isNameAtParentLevel(tdb,prefix); char *filterTypeVal = cartUsualStringClosestToHome(cart, tdb, parentLevel, mud->filterTypeSuffix, "red"); boxed = cfgBeginBoxAndTitle(tdb, boxed, title); /* Define type of filter. */ printf("
\n"); char buffer[256]; safef(buffer, sizeof buffer,"%s.%s",prefix,mud->filterTypeSuffix); filterButtons(buffer, filterTypeVal, FALSE); printf("
"); /* List various fields you can filter on. */ cg = startControlGrid(4, NULL); for (fil = mud->filterList; fil != NULL; fil = fil->next) { safef(buffer, sizeof buffer,"%s.%s",prefix,fil->suffix); oneMrnaFilterUi(cg, tdb, fil->label, buffer, fil->suffix, cart); } endControlGrid(&cg); cfgEndBox(boxed); } void genbankShowPatentControl(struct cart *cart, struct trackDb *tdb, char *prefix) /* controls for enabling display of GENBANK RNA patent sequences */ { char name[256]; safef(name, sizeof(name), "%s.%s", prefix, SHOW_PATENT_SEQUENCES_SUFFIX); printf("

Show patent sequences:"); cgiMakeCheckBox(name, cartUsualBoolean(cart, name, FALSE)); } void mrnaCfgUi(struct cart *cart, struct trackDb *tdb, char *prefix, char *title, boolean boxed) /* Put up UI for an mRNA (or EST) track. */ { boolean isXeno = (sameString(tdb->track, "xenoMrna") || sameString(tdb->track, "xenoEst")); struct mrnaUiData *mud = newMrnaUiData(prefix, isXeno); struct mrnaFilter *fil; struct controlGrid *cg = NULL; boolean parentLevel = isNameAtParentLevel(tdb,prefix); char *filterTypeVal = cartUsualStringClosestToHome(cart, tdb, parentLevel, mud->filterTypeSuffix,"red"); char *logicTypeVal = cartUsualStringClosestToHome(cart, tdb, parentLevel, mud->logicTypeSuffix, "and"); boxed = cfgBeginBoxAndTitle(tdb, boxed, title); /* Define type of filter. */ char buffer[256]; safef(buffer,sizeof buffer,"%s.%s",prefix,mud->filterTypeSuffix); filterButtons(buffer, filterTypeVal, FALSE); printf(" Combination Logic: "); safef(buffer,sizeof buffer,"%s.%s",prefix,mud->logicTypeSuffix); radioButton(buffer, logicTypeVal, "and"); radioButton(buffer, logicTypeVal, "or"); printf("
\n"); /* List various fields you can filter on. */ printf("\n"); cg = startControlGrid(4, NULL); for (fil = mud->filterList; fil != NULL; fil = fil->next) { safef(buffer,sizeof buffer,"%s.%s",prefix,fil->suffix); oneMrnaFilterUi(cg, tdb, fil->label, buffer, fil->suffix, cart); } endControlGrid(&cg); baseColorDrawOptDropDown(cart, tdb); indelShowOptions(cart, tdb); if (sameString(tdb->track, "mrna") || sameString(tdb->track, "xenoMrna")) genbankShowPatentControl(cart, tdb, prefix); wigOption(cart, prefix, title, tdb); cfgEndBox(boxed); } void scoreGrayLevelCfgUi(struct cart *cart, struct trackDb *tdb, char *prefix, int scoreMax) // If scoreMin has been set, let user select the shade of gray for that score, in case // the default is too light to see or darker than necessary. { boolean parentLevel = isNameAtParentLevel(tdb,prefix); char *scoreMinStr = trackDbSettingClosestToHome(tdb, GRAY_LEVEL_SCORE_MIN); if (scoreMinStr != NULL) { int scoreMin = atoi(scoreMinStr); // maxShade=9 taken from hgTracks/simpleTracks.c. Ignore the 10 in shadesOfGray[10+1] -- // maxShade is used to access the array. int maxShade = 9; int scoreMinGrayLevel = scoreMin * maxShade/scoreMax; if (scoreMinGrayLevel <= 0) scoreMinGrayLevel = 1; char *setting = trackDbSettingClosestToHome(tdb, MIN_GRAY_LEVEL); int minGrayLevel = cartUsualIntClosestToHome(cart, tdb, parentLevel, MIN_GRAY_LEVEL, setting ? atoi(setting) : scoreMinGrayLevel); if (minGrayLevel <= 0) minGrayLevel = 1; if (minGrayLevel > maxShade) minGrayLevel = maxShade; puts("\nShade of lowest-scoring items: "); // Add javascript to select so that its color is consistent with option colors: int level = 255 - (255*minGrayLevel / maxShade); printf("\n"); } } static boolean getScoreDefaultsFromTdb(struct trackDb *tdb, char *scoreName,char *defaults, char**min,char**max) // returns TRUE if defaults exist and sets the string pointer (because they may be float or int) // if min or max are set, then they should be freed { if (min) *min = NULL; // default these outs! if (max) *max = NULL; char *setting = trackDbSettingClosestToHome(tdb, scoreName); if (setting) { if (strchr(setting,':') != NULL) return colonPairToStrings(setting,min,max); else if (min) *min = cloneString(setting); return TRUE; } return FALSE; } static void setAsNewFilterType(struct trackDb *tdb, char *name, char *field) /* put the full name of the trackDb variable in a hash of field names if it's specified in the "new" way */ { struct hash *hash = tdb->isNewFilterHash; if (hash == NULL) hash = tdb->isNewFilterHash = newHash(5); hashAdd(hash, field, name); } static char *isNewFilterType(struct trackDb *tdb, char *name) /* check to see if a field name is in the "new" hash. If it is, return the full trackDb variable name */ { if ((tdb == NULL) || (tdb->isNewFilterHash == NULL)) return NULL; struct hashEl *hel = hashLookup(tdb->isNewFilterHash, name); if (hel == NULL) return NULL; return hel->val; } char *getScoreNameAdd(struct trackDb *tdb, char *scoreName, char *add) // Add a suffix to a filter for more information { char scoreLimitName[1024]; char *name = cloneString(scoreName); char *dot = strchr(name, '.'); if ((dot != NULL) && (isNewFilterType(tdb, dot+1) != NULL)) { *dot++ = 0; safef(scoreLimitName, sizeof(scoreLimitName), "%s%s.%s", name, add, dot); } else safef(scoreLimitName, sizeof(scoreLimitName), "%s%s", scoreName, add); return cloneString(scoreLimitName); } static boolean getScoreLimitsFromTdb(struct trackDb *tdb, char *scoreName,char *defaults, char**min,char**max) // returns TRUE if limits exist and sets the string pointer (because they may be float or int) // if min or max are set, then they should be freed { if (min) *min = NULL; // default these outs! if (max) *max = NULL; char *scoreLimitName = getScoreNameAdd(tdb, scoreName, _LIMITS); char *setting = trackDbSettingClosestToHome(tdb, scoreLimitName); if (setting) { return colonPairToStrings(setting,min,max); } else { if (min) { scoreLimitName = getScoreNameAdd(tdb, scoreName, _MIN); setting = trackDbSettingClosestToHome(tdb, scoreLimitName); if (setting) *min = cloneString(setting); } if (max) { scoreLimitName = getScoreNameAdd(tdb, scoreName, _MAX); setting = trackDbSettingClosestToHome(tdb, scoreLimitName); if (setting) *max = cloneString(setting); } return TRUE; } if (defaults != NULL && ((min && *min == NULL) || (max && *max == NULL))) { char *minLoc=NULL; char *maxLoc=NULL; if (colonPairToStrings(defaults,&minLoc,&maxLoc)) { if (min && *min == NULL && minLoc != NULL) *min=minLoc; else freeMem(minLoc); if (max && *max == NULL && maxLoc != NULL) *max=maxLoc; else freeMem(maxLoc); return TRUE; } } return FALSE; } void getScoreIntRangeFromCart(struct cart *cart, struct trackDb *tdb, boolean parentLevel, char *scoreName, int *limitMin, int *limitMax,int *min,int *max) // gets an integer score range from the cart, but the limits from trackDb // for any of the pointers provided, will return a value found, if found, else it's contents // are undisturbed (use NO_VALUE to recognize unavaliable values) { char scoreLimitName[128]; char *deMin=NULL,*deMax=NULL; if ((limitMin || limitMax) && getScoreLimitsFromTdb(tdb,scoreName,NULL,&deMin,&deMax)) { if (deMin != NULL && limitMin) *limitMin = atoi(deMin); if (deMax != NULL && limitMax) *limitMax = atoi(deMax); freeMem(deMin); freeMem(deMax); } if ((min || max) && getScoreDefaultsFromTdb(tdb,scoreName,NULL,&deMin,&deMax)) { if (deMin != NULL && min) *min = atoi(deMin); if (deMax != NULL && max) *max =atoi(deMax); freeMem(deMin); freeMem(deMax); } if (max) { safef(scoreLimitName, sizeof(scoreLimitName), "%s%s", scoreName, _MAX); deMax = cartOptionalStringClosestToHome(cart, tdb,parentLevel,scoreLimitName); if (deMax != NULL) *max = atoi(deMax); } if (min) { // Warning: name changes if max! safef(scoreLimitName, sizeof(scoreLimitName), "%s%s", scoreName, (max && deMax? _MIN:"")); deMin = cartOptionalStringClosestToHome(cart, tdb,parentLevel,scoreLimitName); if (deMin != NULL) *min = atoi(deMin); } // Defaulting min and max within limits. Sorry for the horizontal ifs, // but stacking the group makes them easier to follow if (min && limitMin && *limitMin != NO_VALUE && (*min == NO_VALUE || *min < *limitMin)) *min = *limitMin; if (min && limitMax && *limitMax != NO_VALUE && *min > *limitMax) *min = *limitMax; if (max && limitMax && *limitMax != NO_VALUE && (*max == NO_VALUE || *max > *limitMax)) *max = *limitMax; if (max && limitMin && *limitMin != NO_VALUE && *max < *limitMin) *max = *limitMin; } void getScoreFloatRangeFromCart(struct cart *cart, struct trackDb *tdb, boolean parentLevel, char *scoreName, double *limitMin,double *limitMax,double*min,double*max) // gets an double score range from the cart, but the limits from trackDb // for any of the pointers provided, will return a value found, if found, else it's contents // are undisturbed (use NO_VALUE to recognize unavaliable values) { char *deMin=NULL,*deMax=NULL; if ((limitMin || limitMax) && getScoreLimitsFromTdb(tdb,scoreName,NULL,&deMin,&deMax)) { if (deMin != NULL && limitMin) *limitMin = strtod(deMin,NULL); if (deMax != NULL && limitMax) *limitMax =strtod(deMax,NULL); freeMem(deMin); freeMem(deMax); } if ((min || max) && getScoreDefaultsFromTdb(tdb,scoreName,NULL,&deMin,&deMax)) { if (deMin != NULL && min) *min = strtod(deMin,NULL); if (deMax != NULL && max) *max =strtod(deMax,NULL); freeMem(deMin); freeMem(deMax); } if (max) { char *scoreLimitName = getScoreNameAdd(tdb, scoreName, _MAX); deMax = cartOptionalStringClosestToHome(cart, tdb,parentLevel,scoreLimitName); if (deMax != NULL) *max = strtod(deMax,NULL); } if (min) { // name is always {filterName}Min char *scoreLimitName = getScoreNameAdd(tdb, scoreName, _MIN); deMin = cartOptionalStringClosestToHome(cart, tdb,parentLevel,scoreLimitName); if (deMin == NULL) deMin = cartOptionalStringClosestToHome(cart, tdb,parentLevel,scoreName); if (deMin != NULL) *min = strtod(deMin,NULL); } // Defaulting min and max within limits. Sorry for the horizontal ifs, // but stacking the group makes them easier to follow if (min && limitMin && (int)(*limitMin) != NO_VALUE && ((int)(*min) == NO_VALUE || *min < *limitMin)) *min = *limitMin; if (min && limitMax && (int)(*limitMax) != NO_VALUE && *min > *limitMax) *min = *limitMax; if (max && limitMax && (int)(*limitMax) != NO_VALUE && ((int)(*max) == NO_VALUE || *max > *limitMax)) *max = *limitMax; if (max && limitMin && (int)(*limitMin) != NO_VALUE && *max < *limitMin) *max = *limitMin; } static boolean showScoreFilter(struct cart *cart, struct trackDb *tdb, boolean *opened, boolean boxed, boolean parentLevel,char *name, char *title, char *label, char *scoreName, boolean isHighlight) // Shows a score filter control with minimum value and optional range { char *setting = trackDbSetting(tdb, scoreName); if (setting) { if (*opened == FALSE) { boxed = cfgBeginBoxAndTitle(tdb, boxed, title); puts("
"); *opened = TRUE; } printf("
%s:",label); char varName[256]; char altLabel[256]; char *filterName = getScoreNameAdd(tdb, scoreName, _BY_RANGE); boolean filterByRange = trackDbSettingClosestToHomeOn(tdb, filterName); double minLimit=NO_VALUE,maxLimit=NO_VALUE; double minVal=minLimit,maxVal=maxLimit; colonPairToDoubles(setting,&minVal,&maxVal); getScoreFloatRangeFromCart(cart,tdb,parentLevel,scoreName,&minLimit,&maxLimit, &minVal, &maxVal); filterName = getScoreNameAdd(tdb, scoreName, filterByRange ? _MIN:""); safef(varName, sizeof(varName), "%s.%s", name, filterName); safef(altLabel, sizeof(altLabel), "%s%s", (filterByRange ? "Minimum " : ""), htmlEncode(htmlTextStripTags(label))); cgiMakeDoubleVarWithLimits(varName,minVal, altLabel, 0,minLimit, maxLimit); if (filterByRange) { printf("to"); filterName = getScoreNameAdd(tdb, scoreName, _MAX); safef(varName, sizeof(varName), "%s.%s", name, filterName); safef(altLabel, sizeof(altLabel), "%s%s", (filterByRange?"Maximum ":""), label); cgiMakeDoubleVarWithLimits(varName,maxVal, altLabel, 0,minLimit, maxLimit); } safef(altLabel, sizeof(altLabel), "%s", (filterByRange?"": "colspan=3")); if (minLimit != NO_VALUE && maxLimit != NO_VALUE) printf(" (%s to %s)",altLabel,shorterDouble(minLimit), shorterDouble(maxLimit)); else if (minLimit != NO_VALUE) printf(" (minimum %s)",altLabel,shorterDouble(minLimit)); else if (maxLimit != NO_VALUE) printf(" (maximum %s)",altLabel,shorterDouble(maxLimit)); else printf(""); return TRUE; } return FALSE; } struct trackDbFilter *tdbGetTrackFilters( struct trackDb *tdb, char * lowWild, char * lowName, char * capWild, char * capName) // figure out which of the ways to specify trackDb filter variables we're using // and return the setting { struct trackDbFilter *trackDbFilterList = NULL; struct slName *filterSettings = trackDbSettingsWildMatch(tdb, lowWild); if (filterSettings) { struct trackDbFilter *tdbFilter; struct slName *filter = NULL; while ((filter = slPopHead(&filterSettings)) != NULL) { AllocVar(tdbFilter); slAddHead(&trackDbFilterList, tdbFilter); tdbFilter->name = cloneString(filter->name); tdbFilter->setting = trackDbSetting(tdb, filter->name); tdbFilter->fieldName = extractFieldNameNew(filter->name, lowName); setAsNewFilterType(tdb, tdbFilter->name, tdbFilter->fieldName); } } filterSettings = trackDbSettingsWildMatch(tdb, capWild); if (filterSettings) { struct trackDbFilter *tdbFilter; struct slName *filter = NULL; while ((filter = slPopHead(&filterSettings)) != NULL) { if (differentString(filter->name,NO_SCORE_FILTER)) { AllocVar(tdbFilter); slAddHead(&trackDbFilterList, tdbFilter); tdbFilter->name = cloneString(filter->name); tdbFilter->setting = trackDbSetting(tdb, filter->name); tdbFilter->fieldName = extractFieldNameOld(filter->name, capName); char *name; if ((name = isNewFilterType(tdb, tdbFilter->fieldName) ) != NULL) errAbort("error specifying a field's filters in both old (%s) and new format (%s).", tdbFilter->name, name); } } } return trackDbFilterList; } struct trackDbFilter *tdbGetTrackNumFilters( struct trackDb *tdb) // get the number filters out of trackDb { return tdbGetTrackFilters( tdb, FILTER_NUMBER_WILDCARD_LOW, FILTER_NUMBER_NAME_LOW, FILTER_NUMBER_WILDCARD_CAP, FILTER_NUMBER_NAME_CAP); } struct trackDbFilter *tdbGetTrackTextFilters( struct trackDb *tdb) // get the text filters out of trackDb { return tdbGetTrackFilters( tdb, FILTER_TEXT_WILDCARD_LOW, FILTER_TEXT_NAME_LOW, FILTER_TEXT_WILDCARD_CAP, FILTER_TEXT_NAME_CAP); } struct trackDbFilter *tdbGetTrackFilterByFilters( struct trackDb *tdb) // get the values filters out of trackDb { return tdbGetTrackFilters( tdb, FILTER_VALUES_WILDCARD_LOW, FILTER_VALUES_NAME_LOW, FILTER_VALUES_WILDCARD_CAP, FILTER_VALUES_NAME_CAP); } struct trackDbFilter *tdbGetTrackNumHighlights( struct trackDb *tdb) // get the number filters out of trackDb { return tdbGetTrackFilters( tdb, HIGHLIGHT_NUMBER_WILDCARD_LOW, HIGHLIGHT_NUMBER_NAME_LOW, HIGHLIGHT_NUMBER_WILDCARD_CAP, HIGHLIGHT_NUMBER_NAME_CAP); } struct trackDbFilter *tdbGetTrackTextHighlights( struct trackDb *tdb) // get the text filters out of trackDb { return tdbGetTrackFilters( tdb, HIGHLIGHT_TEXT_WILDCARD_LOW, HIGHLIGHT_TEXT_NAME_LOW, HIGHLIGHT_TEXT_WILDCARD_CAP, HIGHLIGHT_TEXT_NAME_CAP); } struct trackDbFilter *tdbGetTrackHighlightByHighlights( struct trackDb *tdb) // get the values filters out of trackDb { return tdbGetTrackFilters( tdb, HIGHLIGHT_VALUES_WILDCARD_LOW, HIGHLIGHT_VALUES_NAME_LOW, HIGHLIGHT_VALUES_WILDCARD_CAP, HIGHLIGHT_VALUES_NAME_CAP); } char *prevHighlightColor(struct cart *cart, struct trackDb *tdb) /* Return the cart string for the highlight color if it has been changed else the default */ { return cartOrTdbString(cart, tdb, HIGHLIGHT_COLOR_CART_VAR, HIGHLIGHT_COLOR_DEFAULT); } static boolean didHighlightSelector = FALSE; void printHighlightColorPicker(struct cart *cart, struct trackDb *tdb) { if (didHighlightSelector) return; jsIncludeFile("ajax.js", NULL); jsIncludeFile("hui.js", NULL); puts("
"); char *text = "Note that multiple highlight selections use the same color, and are applied successively. So any item that meets at least one criteria will be highlighted."; printInfoIcon(text); puts("
"); puts("
"); jsInlineF("var cartHighlightColor = \"%s\"\n;", prevHighlightColor(cart, tdb)); jsInlineF("makeHighlightPicker(\"%s.highlightColor\", document.getElementById(\"hgTrackUiColorPicker\"), \"%s\");\n", tdb->track, tdb->track); } int defaultFieldLocation(char *field) /* Sometimes we get bigBed filters with field names that are not in the AS file. * Try to guess what the user means. */ { if (sameString("score", field)) return 4; if (sameString("signal", field)) return 6; if (sameString("signalValue", field)) return 6; if (sameString("pValue", field)) return 7; if (sameString("qValue", field)) return 8; return -1; } static int numericFiltersShowAll(char *db, struct cart *cart, struct trackDb *tdb, boolean *opened, boolean boxed, boolean parentLevel,char *name, char *title, boolean isHighlight) // Shows all *Filter style filters. Note that these are in random order and have no graceful title { int count = 0; struct trackDbFilter *trackDbFilters = NULL; if (isHighlight) trackDbFilters = tdbGetTrackNumHighlights(tdb); else trackDbFilters = tdbGetTrackNumFilters(tdb); if (trackDbFilters) { puts("
"); struct trackDbFilter *filter = NULL; struct sqlConnection *conn = NULL; if (!isHubTrack(db)) conn = hAllocConnTrack(db, tdb); struct asObject *as = asForTdb(conn, tdb); hFreeConn(&conn); while ((filter = slPopHead(&trackDbFilters)) != NULL) { char *field = filter->fieldName; char *scoreName = cloneString(filter->name); char *trackDbLabel = getLabelSetting(cart, tdb, field); if (as != NULL) { struct asColumn *asCol = asColumnFind(as, field); if (asCol != NULL) { // Found label so replace field field = asCol->comment; } else if (defaultFieldLocation(field) < 0) errAbort("Building filter on field %s which is not in AS file.", field); } char labelBuf[1024]; char *label = labelBuf; char *filterName = getScoreNameAdd(tdb, scoreName, _BY_RANGE); boolean filterByRange = trackDbSettingClosestToHomeOn(tdb, filterName); if (trackDbLabel) label = trackDbLabel; else { if (isHighlight) safef(labelBuf, sizeof(labelBuf),"%s%s", filterByRange ? "": "Highlight items with Minimum ", field ); else safef(labelBuf, sizeof(labelBuf),"%s%s", filterByRange ? "": "Minimum ", field); } if (isHighlight && count == 0) printHighlightColorPicker(cart, tdb); showScoreFilter(cart,tdb,opened,boxed,parentLevel,name,title,label,scoreName,isHighlight); count++; } if (as != NULL) asObjectFree(&as); } if (count > 0) puts("
"); return count; } boolean bedHasFilters(struct trackDb *tdb) // Does track have filters { if (trackDbSettingClosestToHome(tdb, FILTER_BY)) return TRUE; if (trackDbSettingClosestToHome(tdb, GRAY_LEVEL_SCORE_MIN)) return TRUE; struct trackDbFilter *filterSettings = tdbGetTrackNumFilters( tdb); if (filterSettings != NULL) return TRUE; filterSettings = tdbGetTrackTextFilters( tdb); if (filterSettings != NULL) return TRUE; filterSettings = tdbGetTrackFilterByFilters( tdb); if (filterSettings != NULL) return TRUE; return FALSE; } boolean bedScoreHasCfgUi(struct trackDb *tdb) // Confirms that this track has a bedScore Cfg UI { // Assumes that cfgType == cfgBedScore if (trackDbSettingClosestToHome(tdb, FILTER_BY)) return TRUE; if (trackDbSettingClosestToHome(tdb, GRAY_LEVEL_SCORE_MIN)) return TRUE; boolean blocked = FALSE; struct trackDbFilter *filterSettings = tdbGetTrackNumFilters( tdb); if (filterSettings != NULL) { boolean one = FALSE; struct trackDbFilter *oneFilter = filterSettings; char *noScoreFilter = trackDbSetting(tdb, NO_SCORE_FILTER); if (noScoreFilter) blocked = TRUE; for (;oneFilter != NULL;oneFilter=oneFilter->next) { if (differentString(oneFilter->fieldName,"score")) // scoreFilter is implicit { // but could be blocked one = TRUE; break; } } if (one) return TRUE; } if (!blocked) // scoreFilter is implicit unless NO_SCORE_FILTER return TRUE; return FALSE; } char *getFilterType(struct cart *cart, struct trackDb *tdb, char *field, char *def) // figure out how the trackDb is specifying the FILTER_TYPE variable and return its setting { char settingString[4096]; safef(settingString, sizeof settingString, "%s.%s", FILTER_TYPE_NAME_LOW, field); char *setting = cartOrTdbString(cart, tdb, settingString, NULL); if (setting == NULL) { safef(settingString, sizeof settingString, "%s.%s", field, FILTER_TYPE_NAME_CAP); setting = cartOrTdbString(cart, tdb, settingString, NULL); } if (setting == NULL) { safef(settingString, sizeof settingString, "%s%s", field, FILTER_TYPE_NAME_CAP); setting = cartOrTdbString(cart, tdb, settingString, def); } return setting; } static int textFiltersShowAll(char *db, struct cart *cart, struct trackDb *tdb, boolean isHighlight) /* Show all the text filters for this track. */ { int count = 0; struct trackDbFilter *trackDbFilters = NULL; if (isHighlight) trackDbFilters = tdbGetTrackTextHighlights(tdb); else trackDbFilters = tdbGetTrackTextFilters(tdb); if (trackDbFilters) { puts("
"); struct trackDbFilter *filter = NULL; struct sqlConnection *conn = NULL; if (!isHubTrack(db)) conn = hAllocConnTrack(db, tdb); struct asObject *as = asForTdb(conn, tdb); hFreeConn(&conn); while ((filter = slPopHead(&trackDbFilters)) != NULL) { char *trackDbLabel = getLabelSetting(cart, tdb, filter->fieldName); char *value = cartUsualStringClosestToHome(cart, tdb, FALSE, filter->name, filter->setting); if (as != NULL) { struct asColumn *asCol = asColumnFind(as, filter->fieldName); if (asCol != NULL) { if (trackDbLabel == NULL) trackDbLabel = asCol->comment; } else if (defaultFieldLocation(filter->fieldName) < 0) errAbort("Building filter on field %s which is not in AS file.", filter->fieldName); } if (trackDbLabel == NULL) trackDbLabel = filter->fieldName; if (isHighlight && count == 0) printHighlightColorPicker(cart, tdb); count++; printf("

%s items in '%s' field: ", isHighlight ? "Highlight": "Filter", trackDbLabel); char cgiVar[128]; safef(cgiVar,sizeof(cgiVar),"%s.%s",tdb->track,filter->name); cgiMakeTextVar(cgiVar, value, 45); char *setting = getFilterType(cart, tdb, filter->fieldName, FILTERTEXT_WILDCARD); safef(cgiVar,sizeof(cgiVar),"%s.%s.%s",tdb->track,FILTER_TYPE_NAME_LOW, filter->fieldName); printf(" using "); printf(""); printf("  \n", tdb->track); printf("

"); } // using jquery id= syntax to make sure that selector works even if trackname has a dot in it jsInlineF("$('[class=\"buttonClear-%s\"]').click( function(ev) { \n" "$(ev.target).prevAll('input').val('*').trigger('change');\n" "$(ev.target).prevAll('select').val('%s');\n" "ev.preventDefault();\n" "});", tdb->track, FILTERTEXT_WILDCARD); } return count; } void scoreCfgUi(char *db, struct cart *cart, struct trackDb *tdb, char *name, char *title, int maxScore, boolean boxed) // Put up UI for filtering bed track based on a score { char option[256]; if (cartOptionalString(cart, "ajax") == NULL) { webIncludeResourceFile("ui.dropdownchecklist.css"); jsIncludeFile("ui.dropdownchecklist.js",NULL); jsIncludeFile("ddcl.js",NULL); } boolean parentLevel = isNameAtParentLevel(tdb,name); if (parentLevel) if (trackDbSettingOn(tdb->parent, "noParentConfig")) return; boolean skipScoreFilter = FALSE; // Numeric filters are first boolean isBoxOpened = FALSE; if (numericFiltersShowAll(db, cart, tdb, &isBoxOpened, boxed, parentLevel, name, title, FALSE) > 0) skipScoreFilter = TRUE; if (textFiltersShowAll(db, cart, tdb, FALSE)) skipScoreFilter = TRUE; // Add any multi-selects next filterBy_t *filterBySet = filterBySetGet(tdb,cart,name); if (filterBySet != NULL) { if (!tdbIsComposite(tdb) && cartOptionalString(cart, "ajax") == NULL) jsIncludeFile("hui.js",NULL); if (!isBoxOpened) // Note filterBy boxes are not double "boxed", printf("
"); // if there are no other filters filterBySetCfgUi(cart,tdb,filterBySet,TRUE, name); filterBySetFree(&filterBySet); skipScoreFilter = TRUE; } // add any highlights: // Numeric highlights are first if (numericFiltersShowAll(db, cart, tdb, &isBoxOpened, boxed, parentLevel, name, title, TRUE) > 0) { didHighlightSelector = TRUE; skipScoreFilter = TRUE; } if (textFiltersShowAll(db, cart, tdb, TRUE)) { didHighlightSelector = TRUE; skipScoreFilter = TRUE; } filterBy_t *highlightBySet = highlightBySetGet(tdb,cart,name); if (highlightBySet != NULL) { if (!tdbIsComposite(tdb) && cartOptionalString(cart, "ajax") == NULL) jsIncludeFile("hui.js",NULL); if (!didHighlightSelector) printHighlightColorPicker(cart, tdb); if (!isBoxOpened) // Note filterBy boxes are not double "boxed", printf("
"); // if there are no other filters highlightBySetCfgUi(cart,tdb,highlightBySet,TRUE, name, TRUE); filterBySetFree(&highlightBySet); skipScoreFilter = TRUE; } boolean scoreFilterOk = (trackDbSettingClosestToHome(tdb, NO_SCORE_FILTER) == NULL) && !skipScoreFilter; boolean glvlScoreMin = (trackDbSettingClosestToHome(tdb, GRAY_LEVEL_SCORE_MIN) != NULL); if (! (scoreFilterOk || glvlScoreMin)) { cfgEndBox(boxed); return; } boxed = cfgBeginBoxAndTitle(tdb, boxed, title); if (scoreFilterOk) { int minLimit=0,maxLimit=maxScore,minVal=0,maxVal=maxScore; getScoreIntRangeFromCart(cart,tdb,parentLevel,SCORE_FILTER,&minLimit,&maxLimit, &minVal, &maxVal); boolean filterByRange = trackDbSettingClosestToHomeOn(tdb, SCORE_FILTER _BY_RANGE); if (filterByRange) { puts("Filter score range: min:"); safef(option, sizeof(option), "%s.%s", name,SCORE_FILTER _MIN); cgiMakeIntVarWithLimits(option, minVal, "Minimum score",0, minLimit,maxLimit); puts("max:"); safef(option, sizeof(option), "%s.%s", name,SCORE_FILTER _MAX); cgiMakeIntVarWithLimits(option, maxVal, "Maximum score",0,minLimit,maxLimit); printf("(%d to %d)\n",minLimit,maxLimit); } else { char* scoreLabel = trackDbSettingClosestToHomeOrDefault(tdb, SCORE_LABEL, "score"); printf("Show only items with %s at or above: ", scoreLabel); safef(option, sizeof(option), "%s.%s", name,SCORE_FILTER); cgiMakeIntVarWithLimits(option, minVal, "Minimum score",0, minLimit,maxLimit); printf("  (range: %d to %d)\n", minLimit, maxLimit); if (!boxed) printf("
\n"); } if (glvlScoreMin) printf("
"); } if (glvlScoreMin) scoreGrayLevelCfgUi(cart, tdb, name, maxScore); // filter top-scoring N items in track char *scoreCtString = trackDbSettingClosestToHome(tdb, "filterTopScorers"); if (scoreCtString != NULL) { // show only top-scoring items. This option only displayed if trackDb // setting exists. Format: filterTopScorers char *words[2]; char *scoreFilterCt = NULL; chopLine(cloneString(scoreCtString), words); safef(option, sizeof(option), "%s.filterTopScorersOn", name); bool doScoreCtFilter = cartUsualBooleanClosestToHome(cart, tdb, parentLevel, "filterTopScorersOn", sameString(words[0], "on")); puts("

"); cgiMakeCheckBox(option, doScoreCtFilter); safef(option, sizeof(option), "%s.filterTopScorersCt", name); scoreFilterCt = cartUsualStringClosestToHome(cart, tdb, parentLevel, "filterTopScorersCt", words[1]); puts("  Show only items in top-scoring "); cgiMakeIntVarWithLimits(option,atoi(scoreFilterCt),"Top-scoring count",0,1,100000); //* Only check size of table if track does not have subtracks */ if ( !parentLevel && hTableExists(db, tdb->table)) printf("  (range: 1 to 100,000 total items: %d)\n",getTableSize(db, tdb->table)); else printf("  (range: 1 to 100,000)\n"); } cfgEndBox(boxed); } // Moved from hgTrackUi for consistency static void filterByChromCfgUi(struct cart *cart, struct trackDb *tdb) { char filterVar[256]; char *filterVal = ""; printf("

Filter by chromosome (e.g. chr10): "); safef(filterVar, sizeof(filterVar), "%s.chromFilter", tdb->track); (void) cartUsualString(cart, filterVar, filterVal); // ignore returned setting cgiMakeTextVar(filterVar, cartUsualString(cart, filterVar, ""), 15); } // Moved from hgTrackUi for consistency void crossSpeciesCfgUi(struct cart *cart, struct trackDb *tdb) // Put up UI for selecting rainbow chromosome color or intensity score. { char colorVar[256]; char *colorSetting; // initial value of chromosome coloring option is "on", unless // overridden by the colorChromDefault setting in the track char *colorDefault = trackDbSettingOrDefault(tdb, "colorChromDefault", "on"); printf("

Color track based on chromosome: "); safef(colorVar, sizeof(colorVar), "%s.color", tdb->track); colorSetting = cartUsualString(cart, colorVar, colorDefault); cgiMakeRadioButton(colorVar, "on", sameString(colorSetting, "on")); printf(" on "); cgiMakeRadioButton(colorVar, "off", sameString(colorSetting, "off")); printf(" off "); printf("

"); filterByChromCfgUi(cart,tdb); } struct slPair *buildFieldList(struct trackDb *tdb, char *trackDbVar, struct asObject *as) /* Build up a hash of a list of fields in an AS file. */ { char *fields = trackDbSettingClosestToHome(tdb, trackDbVar); if (fields == NULL) return NULL; if (sameString(fields, "none")) return slPairNew("none", NULL); struct slPair *list = NULL; struct slName *thisField, *fieldList = slNameListFromComma(fields); for(thisField = fieldList; thisField; thisField = thisField->next) { char *trimLabel = trimSpaces(thisField->name); unsigned colNum = asColumnFindIx(as->columnList, trimLabel); if (colNum == -1) errAbort("cannot find field named '%s' in AS file '%s'", trimLabel, as->name); slAddHead(&list, slPairNew(trimLabel, NULL + colNum)); } slReverse(&list); return list; } void labelCfgUi(char *db, struct cart *cart, struct trackDb *tdb, char *prefix) /* If there is a labelFields for a bigBed, this routine is called to put up the label options. */ { // composites can't label because they don't have an autoSql if (tdbIsComposite(tdb)) return; if (trackDbSettingClosestToHomeOn(tdb, "linkIdInName")) return; struct asObject *as = asForDb(tdb, db); if (as == NULL) return; struct slPair *labelList = buildFieldList(tdb, "labelFields", as); struct slPair *defaultLabelList = buildFieldList(tdb, "defaultLabelFields", as); char varName[1024]; if ((labelList == NULL) || sameString(labelList->name, "none")) return; struct slPair *thisLabel = labelList; if (thisLabel->next == NULL) // If there's only one option we either show the label or not. { printf("Show Label: "); safef(varName, sizeof(varName), "%s.label.%s", prefix, thisLabel->name); boolean option = cartUsualBoolean(cart, varName, TRUE); cgiMakeCheckBox(varName, option); } else { printf("Label: "); for(; thisLabel; thisLabel = thisLabel->next) { safef(varName, sizeof(varName), "%s.label.%s", prefix, thisLabel->name); boolean isDefault = FALSE; if (defaultLabelList == NULL) isDefault = (thisLabel == labelList); else if (sameString(defaultLabelList->name, "none")) isDefault = FALSE; else isDefault = (slPairFind(defaultLabelList, thisLabel->name) != NULL); boolean option = cartUsualBoolean(cart, varName, isDefault); cgiMakeCheckBox(varName, option); // find comment for the column listed struct asColumn *col = as->columnList; unsigned num = ptToInt(thisLabel->val); for(; col && num--; col = col->next) ; assert(col); printf(" %s   ", col->comment); } } } void mergeSpanCfgUi(struct cart *cart, struct trackDb *tdb, char *prefix) /* If this track offers a merge spanned items option, put up the cfg for it, which * is just a checkbox with a small explanation. Comparing tdb->track to prefix * ensures we don't offer this control at the composite level, as this is a * subtrack only config */ { if (trackDbSettingOn(tdb, MERGESPAN_TDB_SETTING) && sameString(tdb->track, prefix)) { boolean curOpt = trackDbSettingOn(tdb, "mergeSpannedItems"); char mergeSetting[256]; safef(mergeSetting, sizeof(mergeSetting), "%s.%s", tdb->track, MERGESPAN_CART_SETTING); if (cartVarExists(cart, mergeSetting)) curOpt = cartBoolean(cart, mergeSetting); printf("Merge items that span the current region:"); cgiMakeCheckBox(mergeSetting, curOpt); } } void pslCfgUi(char *db, struct cart *cart, struct trackDb *tdb, char *name, char *title, boolean boxed) /* Put up UI for psl tracks */ { boxed = cfgBeginBoxAndTitle(tdb, boxed, title); char *typeLine = cloneString(tdb->type); char *words[8]; int wordCount = wordCount = chopLine(typeLine, words); if (sameString(tdb->type, "bigPsl")) labelCfgUi(db, cart, tdb, name); if (wordCount == 3 && sameWord(words[1], "xeno")) crossSpeciesCfgUi(cart,tdb); baseColorDropLists(cart, tdb, name); indelShowOptionsWithName(cart, tdb, name); wigOption(cart, name, title, tdb); snakeOption(cart, name, title, tdb); cfgEndBox(boxed); } void netAlignCfgUi(char *db, struct cart *cart, struct trackDb *tdb, char *prefix, char *title, boolean boxed) /* Put up UI for net tracks */ { boxed = cfgBeginBoxAndTitle(tdb, boxed, title); boolean parentLevel = isNameAtParentLevel(tdb,prefix); enum netColorEnum netColor = netFetchColorOption(cart, tdb, parentLevel); char optString[256]; /* our option strings here */ safef(optString, ArraySize(optString), "%s.%s", prefix, NET_COLOR ); printf("

Color nets by: "); netColorDropDown(optString, netColorEnumToString(netColor)); #ifdef NOT_YET enum netLevelEnum netLevel = netFetchLevelOption(cart, tdb, parentLevel); safef( optString, ArraySize(optString), "%s.%s", prefix, NET_LEVEL ); printf("

Limit display of nets to: "); netLevelDropDown(optString, netLevelEnumToString(netLevel)); #endif cfgEndBox(boxed); } void chainCfgUi(char *db, struct cart *cart, struct trackDb *tdb, char *prefix, char *title, boolean boxed, char *chromosome) /* Put up UI for chain tracks */ { boxed = cfgBeginBoxAndTitle(tdb, boxed, title); boolean parentLevel = isNameAtParentLevel(tdb,prefix); enum chainColorEnum chainColor = chainFetchColorOption(cart, tdb, parentLevel); /* check if we have normalized scores available */ boolean normScoreAvailable = chainDbNormScoreAvailable(tdb); char optString[256]; if (normScoreAvailable) { safef(optString, ArraySize(optString), "%s.%s", prefix, OPT_CHROM_COLORS ); printf("

Color chains by: "); chainColorDropDown(optString, chainColorEnumToString(chainColor)); } else { printf("

Color track based on chromosome: "); char optString[256]; /* initial value of chromosome coloring option is "on", unless * overridden by the colorChromDefault setting in the track */ char *binaryColorDefault = trackDbSettingClosestToHomeOrDefault(tdb, "colorChromDefault", "on"); /* allow cart to override trackDb setting */ safef(optString, sizeof(optString), "%s.color", prefix); char * colorSetting = cartUsualStringClosestToHome(cart, tdb, parentLevel, "color", binaryColorDefault); cgiMakeRadioButton(optString, "on", sameString(colorSetting, "on")); printf(" on "); cgiMakeRadioButton(optString, "off", sameString(colorSetting, "off")); printf(" off "); printf("
\n"); } printf("

Filter by chromosome (e.g. chr10): "); safef(optString, ArraySize(optString), "%s.%s", prefix, OPT_CHROM_FILTER); cgiMakeTextVar(optString, cartUsualStringClosestToHome(cart, tdb, parentLevel, OPT_CHROM_FILTER, ""), 15); if (normScoreAvailable) scoreCfgUi(db, cart,tdb,prefix,NULL,CHAIN_SCORE_MAXIMUM,FALSE); wigOption(cart, prefix, title, tdb); snakeOption(cart, prefix, title, tdb); cfgEndBox(boxed); } struct dyString *dyAddFilterAsInt(struct cart *cart, struct trackDb *tdb, struct dyString *extraWhere,char *filter, char *defaultLimits, char*field, boolean *and) // creates the where clause condition to support numeric int filter range. // Filters are expected to follow // {fiterName}: trackDb min or min:max - default value(s); // {filterName}Min or {filterName}: min (user supplied) cart variable; // {filterName}Max: max (user supplied) cart variable; // {filterName}Limits: trackDb allowed range "0:1000" Optional // uses:{filterName}Min: old trackDb value if {filterName}Limits not found // {filterName}Max: old trackDb value if {filterName}Limits not found // defaultLimits: function param if no tdb limits settings found) // The 'and' param and dyString in/out allows stringing multiple where clauses together { char filterLimitName[64]; if (sameWord(filter,NO_SCORE_FILTER)) safef(filterLimitName, sizeof(filterLimitName), "%s", NO_SCORE_FILTER); else safef(filterLimitName, sizeof(filterLimitName), "%s%s", filter,_NO); if (trackDbSettingClosestToHome(tdb, filterLimitName) != NULL) return extraWhere; char *setting = NULL; if (differentWord(filter,SCORE_FILTER)) setting = trackDbSettingClosestToHome(tdb, filter); else setting = trackDbSettingClosestToHomeOrDefault(tdb, filter,"0:1000"); if (setting || sameWord(filter,NO_SCORE_FILTER)) { boolean invalid = FALSE; int minValueTdb = 0,maxValueTdb = NO_VALUE; colonPairToInts(setting,&minValueTdb,&maxValueTdb); int minLimit=NO_VALUE,maxLimit=NO_VALUE,min=minValueTdb,max=maxValueTdb; colonPairToInts(defaultLimits,&minLimit,&maxLimit); getScoreIntRangeFromCart(cart,tdb,FALSE,filter,&minLimit,&maxLimit,&min,&max); if (minLimit != NO_VALUE || maxLimit != NO_VALUE) { // assume tdb default values within range! // (don't give user errors that have no consequence) if ((min != minValueTdb && ((minLimit != NO_VALUE && min < minLimit) || (maxLimit != NO_VALUE && min > maxLimit))) || (max != maxValueTdb && ((minLimit != NO_VALUE && max < minLimit) || (maxLimit != NO_VALUE && max > maxLimit)))) { invalid = TRUE; char value[64]; if (max == NO_VALUE) // min only is allowed, but max only is not safef(value, sizeof(value), "entered minimum (%d)", min); else safef(value, sizeof(value), "entered range (min:%d and max:%d)", min, max); char limits[64]; if (minLimit != NO_VALUE && maxLimit != NO_VALUE) safef(limits, sizeof(limits), "violates limits (%d to %d)", minLimit, maxLimit); else if (minLimit != NO_VALUE) safef(limits, sizeof(limits), "violates lower limit (%d)", minLimit); else //if (maxLimit != NO_VALUE) safef(limits, sizeof(limits), "violates uppper limit (%d)", maxLimit); warn("invalid filter by %s: %s %s for track %s", field, value, limits, tdb->track); } } // else no default limits! if (invalid) { safef(filterLimitName, sizeof(filterLimitName), "%s%s", filter, (max!=NO_VALUE?_MIN:"")); cartRemoveVariableClosestToHome(cart,tdb,FALSE,filterLimitName); safef(filterLimitName, sizeof(filterLimitName), "%s%s", filter, _MAX); cartRemoveVariableClosestToHome(cart,tdb,FALSE,filterLimitName); } else if ((min != NO_VALUE && (minLimit == NO_VALUE || minLimit != min)) || (max != NO_VALUE && (maxLimit == NO_VALUE || maxLimit != max))) // Assumes min==NO_VALUE or min==minLimit is no filter // Assumes max==NO_VALUE or max==maxLimit is no filter! { if (max == NO_VALUE || (maxLimit != NO_VALUE && maxLimit == max)) { if (*and) sqlDyStringPrintf(extraWhere, " and "); sqlDyStringPrintf(extraWhere, "(%s >= %d)", field, min); // min only } else if (min == NO_VALUE || (minLimit != NO_VALUE && minLimit == min)) { if (*and) sqlDyStringPrintf(extraWhere, " and "); sqlDyStringPrintf(extraWhere, "(%s <= %d)", field, max); // max only } else { if (*and) sqlDyStringPrintf(extraWhere, " and "); sqlDyStringPrintf(extraWhere, "(%s BETWEEN %d and %d)", field, min, max); // both } *and=TRUE; } } //if (dyStringLen(extraWhere)) // warn("SELECT FROM %s WHERE %s",tdb->table,dyStringContents(extraWhere)); return extraWhere; } struct dyString *dyAddFilterAsDouble(struct cart *cart, struct trackDb *tdb, struct dyString *extraWhere,char *filter, char *defaultLimits, char*field, boolean *and) // creates the where clause condition to support numeric double filters. // Filters are expected to follow // {fiterName}: trackDb min or min:max - default value(s); // {filterName}Min or {filterName}: min (user supplied) cart variable; // {filterName}Max: max (user supplied) cart variable; // {filterName}Limits: trackDb allowed range "0.0:10.0" Optional // uses: defaultLimits: function param if no tdb limits settings found) // The 'and' param and dyString in/out allows stringing multiple where clauses together { char *setting = trackDbSettingClosestToHome(tdb, filter); if (setting) { boolean invalid = FALSE; double minValueTdb = 0,maxValueTdb = NO_VALUE; colonPairToDoubles(setting,&minValueTdb,&maxValueTdb); double minLimit=NO_VALUE,maxLimit=NO_VALUE,min=minValueTdb,max=maxValueTdb; colonPairToDoubles(defaultLimits,&minLimit,&maxLimit); getScoreFloatRangeFromCart(cart,tdb,FALSE,filter,&minLimit,&maxLimit,&min,&max); if ((int)minLimit != NO_VALUE || (int)maxLimit != NO_VALUE) { // assume tdb default values within range! // (don't give user errors that have no consequence) if ((min != minValueTdb && (((int)minLimit != NO_VALUE && min < minLimit) || ((int)maxLimit != NO_VALUE && min > maxLimit))) || (max != maxValueTdb && (((int)minLimit != NO_VALUE && max < minLimit) || ((int)maxLimit != NO_VALUE && max > maxLimit)))) { invalid = TRUE; char value[64]; if ((int)max == NO_VALUE) // min only is allowed, but max only is not safef(value, sizeof(value), "entered minimum (%g)", min); else safef(value, sizeof(value), "entered range (min:%g and max:%g)", min, max); char limits[64]; if ((int)minLimit != NO_VALUE && (int)maxLimit != NO_VALUE) safef(limits, sizeof(limits), "violates limits (%g to %g)", minLimit, maxLimit); else if ((int)minLimit != NO_VALUE) safef(limits, sizeof(limits), "violates lower limit (%g)", minLimit); else //if ((int)maxLimit != NO_VALUE) safef(limits, sizeof(limits), "violates uppper limit (%g)", maxLimit); warn("invalid filter by %s: %s %s for track %s", field, value, limits, tdb->track); } } if (invalid) { char filterLimitName[64]; safef(filterLimitName, sizeof(filterLimitName), "%s%s", filter, _MIN); cartRemoveVariableClosestToHome(cart,tdb,FALSE,filterLimitName); safef(filterLimitName, sizeof(filterLimitName), "%s%s", filter, _MAX); cartRemoveVariableClosestToHome(cart,tdb,FALSE,filterLimitName); } else if (((int)min != NO_VALUE && ((int)minLimit == NO_VALUE || minLimit != min)) || ((int)max != NO_VALUE && ((int)maxLimit == NO_VALUE || maxLimit != max))) // Assumes min==NO_VALUE or min==minLimit is no filter // Assumes max==NO_VALUE or max==maxLimit is no filter! { if ((int)max == NO_VALUE || ((int)maxLimit != NO_VALUE && maxLimit == max)) { if (*and) sqlDyStringPrintf(extraWhere, " and "); sqlDyStringPrintf(extraWhere, "(%s >= %g)", field, min); // min only } else if ((int)min == NO_VALUE || ((int)minLimit != NO_VALUE && minLimit == min)) { if (*and) sqlDyStringPrintf(extraWhere, " and "); sqlDyStringPrintf(extraWhere, "(%s <= %g)", field, max); // max only } else { if (*and) sqlDyStringPrintf(extraWhere, " and "); sqlDyStringPrintf(extraWhere, "(%s BETWEEN %g and %g)", field,min,max); // both } *and=TRUE; } } //if (dyStringLen(extraWhere)) // warn("SELECT FROM %s WHERE %s",tdb->table,dyStringContents(extraWhere)); return extraWhere; } struct dyString *dyAddAllScoreFilters(struct cart *cart, struct trackDb *tdb, struct dyString *extraWhere,boolean *and) // creates the where clause condition to gather together all random double filters // Filters are expected to follow // {fiterName}: trackDb min or min:max - default value(s); // {filterName}Min or {filterName}: min (user supplied) cart variable; // {filterName}Max: max (user supplied) cart variable; // {filterName}Limits: trackDb allowed range "0.0:10.0" Optional // uses: defaultLimits: function param if no tdb limits settings found) // The 'and' param and dyString in/out allows stringing multiple where clauses together { struct slName *filterSettings = trackDbSettingsWildMatch(tdb, FILTER_NUMBER_WILDCARD_CAP); if (filterSettings) { struct slName *filter = NULL; while ((filter = slPopHead(&filterSettings)) != NULL) { if (differentString(filter->name,"noScoreFilter") && differentString(filter->name,"scoreFilter")) // TODO: scoreFilter could be included { char *field = cloneString(filter->name); int ix = strlen(field) - strlen("filter"); assert(ix > 0); field[ix] = '\0'; char *setting = trackDbSetting(tdb, filter->name); // How to determine float or int ? // If actual tracDb setting has decimal places, then float! if (strchr(setting,'.') == NULL) extraWhere = dyAddFilterAsInt(cart,tdb,extraWhere,filter->name,"0:1000",field,and); else extraWhere = dyAddFilterAsDouble(cart,tdb,extraWhere,filter->name,NULL,field,and); } slNameFree(&filter); } } return extraWhere; } boolean encodePeakHasCfgUi(struct trackDb *tdb) // Confirms that this track has encode Peak cfgUI { if (sameWord("narrowPeak",tdb->type) || sameWord("broadPeak", tdb->type) || sameWord("bigNarrowPeak", tdb->type) || sameWord("encodePeak",tdb->type) || sameWord("gappedPeak",tdb->type)) { return (trackDbSettingClosestToHome(tdb, SCORE_FILTER ) || trackDbSettingClosestToHome(tdb, SIGNAL_FILTER) || trackDbSettingClosestToHome(tdb, PVALUE_FILTER) || trackDbSettingClosestToHome(tdb, QVALUE_FILTER) || trackDbSettingClosestToHome(tdb, SCORE_FILTER )); } return FALSE; } void encodePeakCfgUi(struct cart *cart, struct trackDb *tdb, char *name, char *title, boolean boxed) // Put up UI for filtering wgEnocde peaks based on score, Pval and Qval { boolean parentLevel = isNameAtParentLevel(tdb,name); boolean opened = FALSE; showScoreFilter(cart,tdb,&opened,boxed,parentLevel,name,title, "Minimum Signal value", SIGNAL_FILTER, FALSE); showScoreFilter(cart,tdb,&opened,boxed,parentLevel,name,title, "Minimum P-Value (-log10)",PVALUE_FILTER, FALSE); showScoreFilter(cart,tdb,&opened,boxed,parentLevel,name,title, "Minimum Q-Value (-log10)",QVALUE_FILTER, FALSE); char *setting = trackDbSettingClosestToHomeOrDefault(tdb, SCORE_FILTER,NULL);//"0:1000"); if (setting) { if (!opened) { boxed = cfgBeginBoxAndTitle(tdb, boxed, title); puts("

"); opened = TRUE; } char varName[256]; int minLimit=0,maxLimit=1000,minVal=0,maxVal=NO_VALUE; colonPairToInts(setting,&minVal,&maxVal); getScoreIntRangeFromCart(cart,tdb,parentLevel,SCORE_FILTER,&minLimit,&maxLimit, &minVal, &maxVal); if (maxVal != NO_VALUE) puts(""); } } if (opened) { puts("
Score range: min:"); else puts("
Minimum score:"); safef(varName, sizeof(varName), "%s%s", SCORE_FILTER, _BY_RANGE); boolean filterByRange = trackDbSettingClosestToHomeOn(tdb, varName); safef(varName, sizeof(varName), "%s.%s%s", name, SCORE_FILTER, (filterByRange?_MIN:"")); cgiMakeIntVarWithLimits(varName, minVal, "Minimum score", 0, minLimit, maxLimit); if (filterByRange) { if (maxVal == NO_VALUE) maxVal = maxLimit; puts("to"); safef(varName, sizeof(varName), "%s.%s%s", name, SCORE_FILTER,_MAX); cgiMakeIntVarWithLimits(varName, maxVal, "Maximum score", 0, minLimit, maxLimit); } printf(" (%d to %d)",(filterByRange?"":" colspan=3"),minLimit, maxLimit); if (trackDbSettingClosestToHome(tdb, GRAY_LEVEL_SCORE_MIN) != NULL) { printf("
"); scoreGrayLevelCfgUi(cart, tdb, name, 1000); puts("
"); cfgEndBox(boxed); } } static void gencodeLabelControls(char *db, struct cart *cart, struct trackDb *tdb, char *name, boolean parentLevel) /* generate label checkboxes for GENCODE. */ { // See hgTracks/gencodeTracks.c:registerProductionTrackHandlers() // and hgTracks/gencodeTracks.c:assignConfiguredName() char *labelsNames[][2] = { {"gene name", "geneName"}, {"gene id", "geneId"}, {"transcript id", "transcriptId"}, {NULL, NULL} }; int i; for (i = 0; labelsNames[i][0] != NULL; i++) { char varName[64], varSuffix[64]; safef(varSuffix, sizeof(varSuffix), "label.%s", labelsNames[i][1]); safef(varName, sizeof(varName), "%s.%s", name, varSuffix); char *value = cartUsualStringClosestToHome(cart, tdb, parentLevel, varSuffix, NULL); boolean checked = (value != NULL) && !sameString(value, "0"); printf("%s%s: ", (i > 0) ? "  " : "", labelsNames[i][0]); cgiMakeCheckBoxMore(varName, checked, NULL); } } static void gencodeMaxTransControl(char *db, struct cart *cart, struct trackDb *tdb, char *name, boolean parentLevel) { static char *varSuffix = "maxTrans"; char varName[64]; safef(varName, sizeof(varName), "%s.%s", name, varSuffix); int maxTrans = cartUsualIntClosestToHome(cart, tdb, parentLevel, varSuffix, 0); printf("
Maximum number of transcripts to display: "); cgiMakeIntVar(varName, maxTrans, 5); printf(" (0 to display all)"); } static void gencodeDisplayControls(char *db, struct cart *cart, struct trackDb *tdb, char *name, boolean parentLevel) /* generate display controls */ { if (trackDbSettingClosestToHome(tdb, "maxTransEnabled")) gencodeMaxTransControl(db, cart, tdb, name, parentLevel); } static void newGencodeShowOptions(struct cart *cart, struct trackDb *tdb) /* Put up line of controls that describe what parts to show. */ { char varName[64]; printf("
Show: "); safef(varName, sizeof(varName), "%s.show.noncoding", tdb->track); boolean option = cartUsualBoolean(cart, varName, TRUE); cgiMakeCheckBox(varName, option); printf(" %s   ", "non-coding genes"); safef(varName, sizeof(varName), "%s.show.spliceVariants", tdb->track); option = cartUsualBoolean(cart, varName, TRUE); cgiMakeCheckBox(varName, option); printf(" %s   ", "splice variants"); safef(varName, sizeof(varName), "%s.show.pseudo", tdb->track); option = cartUsualBoolean(cart, varName, FALSE); cgiMakeCheckBox(varName, option); printf(" %s   ", "pseudogenes"); printf("
Tagged Sets: "); safef(varName, sizeof(varName), "%s.show.set", tdb->track); char *setString = cartUsualString(cart, varName, "basic"); cgiMakeRadioButton(varName, "MANE_Select", sameString(setString, "MANE_Select")); printf(" %s   ", "MANE only"); cgiMakeRadioButton(varName, "basic", sameString(setString, "basic")); printf(" %s   ", "BASIC only"); cgiMakeRadioButton(varName, "all", sameString(setString, "all")); printf(" %s   ", "All"); } void genePredCfgUi(char *db, struct cart *cart, struct trackDb *tdb, char *name, char *title, boolean boxed) /* Put up genePred-specific controls */ { char varName[64]; boolean parentLevel = isNameAtParentLevel(tdb,name); char *geneLabel = cartUsualStringClosestToHome(cart, tdb,parentLevel, "label", "gene"); boxed = cfgBeginBoxAndTitle(tdb, boxed, title); labelCfgUi(db, cart, tdb, name); boolean isGencode3 = trackDbSettingOn(tdb, "isGencode3"); if (sameString(name, "acembly")) { char *acemblyClass = cartUsualStringClosestToHome(cart,tdb,parentLevel,"type", acemblyEnumToString(0)); printf("

Gene Class: "); acemblyDropDown("acembly.type", acemblyClass); printf(" "); } else if (isGencode3) { newGencodeShowOptions(cart, tdb); } else if (startsWith("wgEncodeGencode", name)) { // new GENCODEs gencodeLabelControls(db, cart, tdb, name, parentLevel); gencodeDisplayControls(db, cart, tdb, name, parentLevel); } else if (sameString("wgEncodeSangerGencode", name) || (startsWith("encodeGencode", name) && !sameString("encodeGencodeRaceFrags", name))) { // GENCODE pilot (see hgTracks/gencodeTracks.c:registerPilotTrackHandlers() // and hgTracks/simpleTracks.c:genePredAssignConfiguredName() printf("Label: "); safef(varName, sizeof(varName), "%s.label", name); cgiMakeRadioButton(varName, "gene", sameString("gene", geneLabel)); printf("%s ", "gene"); cgiMakeRadioButton(varName, "accession", sameString("accession", geneLabel)); printf("%s ", "accession"); cgiMakeRadioButton(varName, "both", sameString("both", geneLabel)); printf("%s ", "both"); cgiMakeRadioButton(varName, "none", sameString("none", geneLabel)); printf("%s ", "none"); } if (trackDbSettingClosestToHomeOn(tdb, "nmdFilter")) { boolean nmdDefault = FALSE; safef(varName, sizeof(varName), "hgt.%s.nmdFilter", name); nmdDefault = cartUsualBoolean(cart,varName, FALSE); // TODO: var name (hgt prefix) needs changing before ClosesToHome can be used printf("

Filter out NMD targets."); cgiMakeCheckBox(varName, nmdDefault); } if (!sameString(tdb->track, "tigrGeneIndex") && !sameString(tdb->track, "ensGeneNonCoding") && !sameString(tdb->track, "encodeGencodeRaceFrags")) baseColorDropLists(cart, tdb, name); filterBy_t *filterBySet = filterBySetGet(tdb,cart,name); if (filterBySet != NULL) { printf("
"); filterBySetCfgUi(cart,tdb,filterBySet,FALSE, name); filterBySetFree(&filterBySet); } filterBy_t *highlightBySet = highlightBySetGet(tdb,cart,name); if (highlightBySet != NULL) { printf("
"); highlightBySetCfgUi(cart,tdb,highlightBySet,FALSE, name, TRUE); filterBySetFree(&highlightBySet); } squishyPackOption(cart, name, title, tdb); filterNameOption(cart, name, tdb); colorTrackOption(cart, name, tdb); wigOption(cart, name, title, tdb); cfgEndBox(boxed); } static boolean isSpeciesOn(struct cart *cart, struct trackDb *tdb, char *species, char *option, int optionSize, boolean defaultState) /* check the cart to see if species is turned off or on (default is defaultState) */ { boolean parentLevel = isNameAtParentLevel(tdb,option); if (*option == '\0') safef(option, optionSize, "%s.%s", tdb->track, species); else { char *suffix = option + strlen(option); int suffixSize = optionSize - strlen(option); safef(suffix,suffixSize,".%s",species); } return cartUsualBooleanClosestToHome(cart,tdb, parentLevel, species,defaultState); } char **wigMafGetSpecies(struct cart *cart, struct trackDb *tdb, char *prefix, char *db, struct wigMafSpecies **list, int *groupCt) { int speciesCt = 0; char *speciesGroup = trackDbSetting(tdb, SPECIES_GROUP_VAR); char *speciesUseFile = trackDbSetting(tdb, SPECIES_USE_FILE); char *speciesOrder = trackDbSetting(tdb, SPECIES_ORDER_VAR); #define MAX_SP_SIZE 2000 #define MAX_GROUPS 1000 char sGroup[MAX_SP_SIZE]; //Ochar *groups[20]; struct wigMafSpecies *wmSpecies, *wmSpeciesList = NULL; int group; int i; char *species[MAX_SP_SIZE]; char option[MAX_SP_SIZE]; *list = NULL; *groupCt = 0; /* determine species and groups for pairwise -- create checkboxes */ if (speciesOrder == NULL && speciesGroup == NULL && speciesUseFile == NULL) { if (isCustomTrack(tdb->track)) return NULL; errAbort("Track %s missing required trackDb setting: speciesOrder, speciesGroups, or speciesUseFile", tdb->track); } char **groups = needMem(MAX_GROUPS * sizeof (char *)); *groupCt = 1; if (speciesGroup) *groupCt = chopByWhite(speciesGroup, groups, MAX_GROUPS); if (speciesUseFile) { if ((speciesGroup != NULL) || (speciesOrder != NULL)) errAbort("Can't specify speciesUseFile and speciesGroup or speciesOrder"); speciesOrder = cartGetOrderFromFile(db, cart, speciesUseFile); // Not sure why this is in cart } // not tdb based so no ClosestToHome for (group = 0; group < *groupCt; group++) { if (*groupCt != 1 || !speciesOrder) { safef(sGroup, sizeof sGroup, "%s%s", SPECIES_GROUP_PREFIX, groups[group]); speciesOrder = trackDbRequiredSetting(tdb, sGroup); } speciesCt = chopLine(speciesOrder, species); for (i = 0; i < speciesCt; i++) { AllocVar(wmSpecies); wmSpecies->name = cloneString(species[i]); safecpy(option,sizeof option,prefix); wmSpecies->on = isSpeciesOn(cart, tdb, wmSpecies->name, option, sizeof option, TRUE); wmSpecies->group = group; slAddHead(&wmSpeciesList, wmSpecies); } } slReverse(&wmSpeciesList); *list = wmSpeciesList; return groups; } struct wigMafSpecies * wigMafSpeciesTable(struct cart *cart, struct trackDb *tdb, char *name, char *db) { int groupCt; #define MAX_SP_SIZE 2000 char option[MAX_SP_SIZE]; int group, prevGroup; int i,j; struct hash *labelHash = mafGetLabelHash(tdb); bool lowerFirstChar = TRUE; struct wigMafSpecies *wmSpeciesList; char **groups = wigMafGetSpecies(cart, tdb, name, db, &wmSpeciesList, &groupCt); struct wigMafSpecies *wmSpecies = wmSpeciesList; struct slName *speciesList = NULL; for(; wmSpecies; wmSpecies = wmSpecies->next) { struct slName *newName = slNameNew(wmSpecies->name); slAddHead(&speciesList, newName); } slReverse(&speciesList); int numberPerRow; boolean lineBreakJustPrinted; char *words[MAX_SP_SIZE]; int defaultOffSpeciesCnt = 0; if (cartOptionalString(cart, "ajax") == NULL) jsIncludeFile("utils.js",NULL); //jsInit(); puts("\n

Species selection: "); cgiContinueHiddenVar("g"); char id[256]; PLUS_BUTTON( "id", "plus_pw","cb_maf_","_maf_") MINUS_BUTTON("id","minus_pw","cb_maf_","_maf_") char prefix[512]; safef(prefix, sizeof prefix, "%s.", name); char *defaultOffSpecies = trackDbSetting(tdb, "speciesDefaultOff"); struct hash *offHash = NULL; if (defaultOffSpecies) { offHash = newHash(5); DEFAULT_BUTTON( "id", "default_pw","cb_maf_","_maf_") int wordCt = chopLine(defaultOffSpecies, words); defaultOffSpeciesCnt = wordCt; /* build hash of species that should be off */ int ii; for(ii=0; ii < wordCt; ii++) hashAdd(offHash, words[ii], NULL); } if (groupCt == 1) puts("\n"); group = -1; lineBreakJustPrinted = FALSE; for (wmSpecies = wmSpeciesList, i = 0, j = 0; wmSpecies != NULL; wmSpecies = wmSpecies->next, i++) { char *label; prevGroup = group; group = wmSpecies->group; if (groupCt != 1 && group != prevGroup) { i = 0; j = 0; if (group != 0) puts("
\n"); /* replace underscores in group names */ subChar(groups[group], '_', ' '); printf("

  %s", groups[group]); printf("  "); safef(option, sizeof(option), "plus_%s", groups[group]); PLUS_BUTTON( "id",option,"cb_maf_",groups[group]) safef(option, sizeof(option),"minus_%s", groups[group]); MINUS_BUTTON("id",option,"cb_maf_",groups[group]) puts("\n"); } numberPerRow = 5; /* new logic to decide if line break should be displayed here */ if ((j != 0 && (j % numberPerRow) == 0) && (lineBreakJustPrinted == FALSE)) { puts(""); lineBreakJustPrinted = TRUE; } char id[MAX_SP_SIZE]; if (defaultOffSpeciesCnt > 0) { if (stringArrayIx(wmSpecies->name,words,defaultOffSpeciesCnt) == -1) safef(id, sizeof(id), "cb_maf_%s_%s", groups[group], wmSpecies->name); else { safef(id, sizeof(id), "cb_maf_%s_%s_defOff", groups[group], wmSpecies->name); } } else safef(id, sizeof(id), "cb_maf_%s_%s", groups[group], wmSpecies->name); puts(""); lineBreakJustPrinted = FALSE; j++; } puts("
"); boolean defaultState = TRUE; if (offHash != NULL) defaultState = (hashLookup(offHash, wmSpecies->name) == NULL); safecpy(option, sizeof(option), name); wmSpecies->on = isSpeciesOn(cart, tdb, wmSpecies->name, option, sizeof option, defaultState ); cgiMakeCheckBoxWithId(option, wmSpecies->on,id); char *remapName = NULL; if ((labelHash != NULL) && (remapName = hashFindVal(labelHash,wmSpecies->name))) label = remapName; else { label = hOrganism(wmSpecies->name); if (label == NULL) label = wmSpecies->name; if (lowerFirstChar) *label = tolower(*label); } printf("%s
", label); puts("

\n"); return wmSpeciesList; } void wigMafCfgUi(struct cart *cart, struct trackDb *tdb,char *name, char *title, boolean boxed, char *db) /* UI for maf/wiggle track * NOTE: calls wigCfgUi */ { int i; char option[MAX_SP_SIZE]; boolean parentLevel = isNameAtParentLevel(tdb,name); boxed = cfgBeginBoxAndTitle(tdb, boxed, title); char *defaultCodonSpecies = trackDbSetting(tdb, SPECIES_CODON_DEFAULT); char *framesTable = trackDbSetting(tdb, "frames"); char *snpTable = trackDbSetting(tdb, "snpTable"); char *treeImage = NULL; struct consWiggle *consWig, *consWiggles = wigMafWiggles(db, tdb); boolean isWigMafProt = FALSE; if (strstr(tdb->type, "wigMafProt")) isWigMafProt = TRUE; puts("
"); if (consWiggles && consWiggles->next) { /* check for alternate conservation wiggles -- create checkboxes */ puts("

Conservation:" ); boolean first = TRUE; for (consWig = consWiggles; consWig != NULL; consWig = consWig->next) { char *wigVarSuffix = NULL; char *wigVar = wigMafWiggleVar(name, consWig, &wigVarSuffix); cgiMakeCheckBox(wigVar, cartUsualBooleanClosestToHome(cart,tdb,parentLevel,wigVarSuffix,first)); freeMem(wigVar); first = FALSE; subChar(consWig->uiLabel, '_', ' '); printf ("%s ", consWig->uiLabel); } } struct wigMafSpecies *wmSpeciesList = wigMafSpeciesTable(cart, tdb, name, db); struct wigMafSpecies *wmSpecies; if (isWigMafProt) puts("Multiple alignment amino acid-level:
" ); else puts("Multiple alignment base-level:
" ); boolean mafDotIsOn = trackDbSettingClosestToHomeOn(tdb, MAF_DOT_VAR); safef(option, sizeof option, "%s.%s", name, MAF_DOT_VAR); cgiMakeCheckBox(option, cartUsualBooleanClosestToHome(cart, tdb, parentLevel,MAF_DOT_VAR, mafDotIsOn)); if (isWigMafProt) puts("Display amino acids identical to reference as dots
" ); else puts("Display bases identical to reference as dots
" ); safef(option, sizeof option, "%s.%s", name, MAF_CHAIN_VAR); cgiMakeCheckBox(option, cartUsualBooleanClosestToHome(cart,tdb,parentLevel,MAF_CHAIN_VAR,TRUE)); char *irowStr = trackDbSetting(tdb, "irows"); boolean doIrows = (irowStr == NULL) || !sameString(irowStr, "off"); if (isCustomTrack(tdb->track) || doIrows) puts("Display chains between alignments
"); else { if (isWigMafProt) puts("Display unaligned amino acids with spanning chain as 'o's
"); else puts("Display unaligned bases with spanning chain as 'o's
"); } safef(option, sizeof option, "%s.%s", name, MAF_SHOW_SNP); if (snpTable) { printf("
Codon Changes:
"); cgiMakeCheckBox(option, cartOrTdbBoolean(cart, tdb, MAF_SHOW_SNP,FALSE)); puts("Display synonymous and non-synonymous changes in coding exons.
"); } safef(option, sizeof option, "%s.%s", name, "codons"); if (framesTable) { char *nodeNames[512]; char buffer[128]; printf("
Codon Translation:
"); printf("Default species to establish reading frame: "); nodeNames[0] = db; for (wmSpecies = wmSpeciesList, i = 1; wmSpecies != NULL; wmSpecies = wmSpecies->next, i++) { nodeNames[i] = wmSpecies->name; } cgiMakeDropList(SPECIES_CODON_DEFAULT, nodeNames, i, // tdb independent var cartUsualString(cart, SPECIES_CODON_DEFAULT, defaultCodonSpecies)); puts("
"); char *cartVal = cartUsualStringClosestToHome(cart, tdb, parentLevel, "codons","codonDefault"); safef(buffer, sizeof(buffer), "%s.codons",name); cgiMakeRadioButton(buffer,"codonNone", sameWord(cartVal,"codonNone")); printf("No codon translation
"); cgiMakeRadioButton(buffer,"codonDefault", sameWord(cartVal,"codonDefault")); printf("Use default species reading frames for translation
"); cgiMakeRadioButton(buffer,"codonFrameNone",sameWord(cartVal,"codonFrameNone")); printf("Use reading frames for species if available, otherwise no translation
"); cgiMakeRadioButton(buffer,"codonFrameDef", sameWord(cartVal,"codonFrameDef")); printf("Use reading frames for species if available, otherwise use default species
"); } else { /* Codon highlighting does not apply to wigMafProt type */ if (!strstr(tdb->type, "wigMafProt")) { puts("

Codon highlighting:
" ); #ifdef GENE_FRAMING safef(option, sizeof(option), "%s.%s", name, MAF_FRAME_VAR); char *currentCodonMode = cartCgiUsualString(cart, option, MAF_FRAME_GENE); /* Disable codon highlighting */ cgiMakeRadioButton(option, MAF_FRAME_NONE, sameString(MAF_FRAME_NONE, currentCodonMode)); puts("None  "); /* Use gene pred */ cgiMakeRadioButton(option, MAF_FRAME_GENE, sameString(MAF_FRAME_GENE, currentCodonMode)); puts("CDS-annotated frame based on"); safef(option, sizeof(option), "%s.%s", name, MAF_GENEPRED_VAR); genePredDropDown(cart, makeTrackHash(db, chromosome), NULL, option); #else safef(option, sizeof(option), "%s.%s", name, BASE_COLORS_VAR); puts("  Alternate colors every"); cgiMakeIntVar(option, cartCgiUsualInt(cart, option, 0), 1); puts("bases
"); safef(option, sizeof(option), "%s.%s", name, BASE_COLORS_OFFSET_VAR); puts("  Offset alternate colors by"); cgiMakeIntVar(option, cartCgiUsualInt(cart, option, 0), 1); puts("bases
"); #endif } } treeImage = trackDbSetting(tdb, "treeImage"); if (treeImage) printf("

", treeImage); else puts("

"); if (trackDbSetting(tdb, CONS_WIGGLE) != NULL) { wigCfgUi(cart,tdb,name,"Conservation graph:",FALSE); } cfgEndBox(boxed); } static char *grayLabels[] = { "alignment quality", "base qualities", "unpaired ends", }; static char *grayValues[] = { BAM_GRAY_MODE_ALI_QUAL, BAM_GRAY_MODE_BASE_QUAL, BAM_GRAY_MODE_UNPAIRED, }; // When a child input of a radio set is changed, click its radio button: #define UPDATE_RADIO_FORMAT_JS "\ var inputs = document.getElementsByName('%s'); \ if (inputs) { \ for (var i=0; i < inputs.length; i++) { \ if (inputs[i].type == 'radio') { \ inputs[i].checked = (inputs[i].value == '%s'); \ } \ } \ }" void bamCfgUi(struct cart *cart, struct trackDb *tdb, char *name, char *title, boolean boxed) /* BAM: short-read-oriented alignment file format. */ { boxed = cfgBeginBoxAndTitle(tdb, boxed, title); char cartVarName[1024]; printf("",boxed?" width='100%'":""); bamAddBaseAndIndelSettings(tdb); // Deal with tdb being from a subtrack when a view is being configured, ugh: if (differentString(tdb->track, name) && tdb->parent != NULL && sameString(tdb->parent->type, "bam")) bamAddBaseAndIndelSettings(tdb->parent); #ifdef NOTNOW // temporarily (?) remove this check box because code doesn't allow for setting wiggle options char *showWig = cartOrTdbString(cart, tdb, BAMWIG_MODE, "0"); safef(cartVarName, sizeof(cartVarName), "%s.%s", name, BAMWIG_MODE); cgiMakeCheckBox(cartVarName, SETTING_IS_ON(showWig)); printf("Only show coverage of reads"); #endif printf("\n"); printf("\n"); char *showNames = cartOrTdbString(cart, tdb, BAM_SHOW_NAMES, "0"); safef(cartVarName, sizeof(cartVarName), "%s.%s", name, BAM_SHOW_NAMES); cgiMakeCheckBox(cartVarName, SETTING_IS_ON(showNames)); printf("Display read names"); if (boxed && fileExists(hHelpFile("hgBamTrackHelp"))) printf("BAM configuration help"); printf("\n"); boolean canPair = (cartOrTdbString(cart, tdb, BAM_PAIR_ENDS_BY_NAME, NULL) != NULL); if (canPair) { char *doPairing = cartOrTdbString(cart, tdb, BAM_PAIR_ENDS_BY_NAME, "0"); printf(""); safef(cartVarName, sizeof(cartVarName), "%s." BAM_PAIR_ENDS_BY_NAME, name); cgiMakeCheckBox(cartVarName, SETTING_IS_ON(doPairing)); printf("Attempt to join paired end reads by name\n"); } printf("Minimum alignment quality:\n"); safef(cartVarName, sizeof(cartVarName), "%s." BAM_MIN_ALI_QUAL, name); cgiMakeIntVar(cartVarName, atoi(cartOrTdbString(cart, tdb, BAM_MIN_ALI_QUAL, BAM_MIN_ALI_QUAL_DEFAULT)), 4); printf(""); baseColorDropLists(cart, tdb, name); puts("
"); indelShowOptionsWithName(cart, tdb, name); printf("
\n"); printf("Additional coloring modes:
\n"); safef(cartVarName, sizeof(cartVarName), "%s." BAM_COLOR_MODE, name); char *selected = cartOrTdbString(cart, tdb, BAM_COLOR_MODE, BAM_COLOR_MODE_DEFAULT); cgiMakeRadioButton(cartVarName, BAM_COLOR_MODE_STRAND, sameString(selected, BAM_COLOR_MODE_STRAND)); printf("Color by strand (blue for +, red for -)
\n"); cgiMakeRadioButton(cartVarName, BAM_COLOR_MODE_GRAY, sameString(selected, BAM_COLOR_MODE_GRAY)); printf("Use gray for\n"); char cartVarName2[1024]; safef(cartVarName2, sizeof(cartVarName2), "%s." BAM_GRAY_MODE, name); int grayMenuSize = canPair ? ArraySize(grayLabels) : ArraySize(grayLabels)-1; char *sel2 = cartOrTdbString(cart, tdb, BAM_GRAY_MODE, BAM_GRAY_MODE_DEFAULT); char onChange[2048]; safef(onChange, sizeof(onChange), UPDATE_RADIO_FORMAT_JS, cartVarName, BAM_COLOR_MODE_GRAY); cgiMakeDropListFull(cartVarName2, grayLabels, grayValues, grayMenuSize, sel2, "change", onChange); printf("
\n"); if (trackDbSettingClosestToHome(tdb, "noColorTag") == NULL) { cgiMakeRadioButton(cartVarName, BAM_COLOR_MODE_TAG, sameString(selected, BAM_COLOR_MODE_TAG)); printf("Use R,G,B colors specified in user-defined tag "); safef(cartVarName2, sizeof(cartVarName2), "%s." BAM_COLOR_TAG, name); sel2 = cartOrTdbString(cart, tdb, BAM_COLOR_TAG, BAM_COLOR_TAG_DEFAULT); safef(onChange, sizeof(onChange), UPDATE_RADIO_FORMAT_JS, cartVarName, BAM_COLOR_MODE_TAG); cgiMakeTextVarWithJs(cartVarName2, sel2, 30, "keypress", onChange); printf("
\n"); } cgiMakeRadioButton(cartVarName, BAM_COLOR_MODE_OFF, sameString(selected, BAM_COLOR_MODE_OFF)); printf("No additional coloring"); // let the user choose to see the track in wiggle mode wigOption(cart, name, title, tdb); //TODO: include / exclude flags if (!boxed && fileExists(hHelpFile("hgBamTrackHelp"))) printf("

BAM " "configuration help

"); cfgEndBox(boxed); } void lrgCfgUi(struct cart *cart, struct trackDb *tdb, char *name, char *title, boolean boxed) /* LRG: Locus Reference Genomic sequences mapped to assembly. */ { boxed = cfgBeginBoxAndTitle(tdb, boxed, title); printf("",boxed?" width='100%'":""); baseColorDrawOptDropDown(cart, tdb); indelShowOptionsWithNameExt(cart, tdb, name, "LRG sequence", FALSE, FALSE); cfgEndBox(boxed); } void lrgTranscriptAliCfgUi(struct cart *cart, struct trackDb *tdb, char *name, char *title, boolean boxed) /* LRG Transcripts: Locus Reference Genomic transcript sequences mapped to assembly. */ { boxed = cfgBeginBoxAndTitle(tdb, boxed, title); printf("",boxed?" width='100%'":""); baseColorDrawOptDropDown(cart, tdb); indelShowOptionsWithNameExt(cart, tdb, name, "LRG transcript sequence", FALSE, FALSE); cfgEndBox(boxed); } struct trackDb *rFindView(struct trackDb *forest, char *view) // Return the trackDb on the list that matches the view tag. Prefers ancestors before decendents { struct trackDb *tdb; for (tdb = forest; tdb != NULL; tdb = tdb->next) { char *viewSetting = trackDbSetting(tdb, "view"); if (sameOk(viewSetting, view) || sameOk(tagEncode(viewSetting), view)) return tdb; } for (tdb = forest; tdb != NULL; tdb = tdb->next) { struct trackDb *viewTdb = rFindView(tdb->subtracks, view); if (viewTdb != NULL) return viewTdb; } return NULL; } static boolean compositeViewCfgExpandedByDefault(struct trackDb *parentTdb,char *view, char **retVisibility) // returns true if the view cfg is expanded by default. Optionally allocates string of view // setting (eg 'dense') { boolean expanded = FALSE; if ( retVisibility != NULL ) *retVisibility = cloneString(hStringFromTv(parentTdb->visibility)); struct trackDb *viewTdb = rFindView(parentTdb->subtracks, view); if (viewTdb == NULL) return FALSE; if (retVisibility != NULL) *retVisibility = cloneString(hStringFromTv(viewTdb->visibility)); if (trackDbSetting(viewTdb, "viewUi")) expanded = TRUE; return expanded; } enum trackVisibility visCompositeViewDefault(struct trackDb *parentTdb,char *view) // returns the default track visibility of particular view within a composite track { char *visibility = NULL; compositeViewCfgExpandedByDefault(parentTdb,view,&visibility); enum trackVisibility vis = hTvFromString(visibility); freeMem(visibility); return vis; } static boolean hCompositeDisplayViewDropDowns(char *db, struct cart *cart, struct trackDb *parentTdb) // UI for composite view drop down selections. { int ix; char classes[SMALLBUF]; char javascript[JBUFSIZE]; char id[256]; #define CFG_LINK "%s ▾" #define CFG_LINK_JS "return (showConfigControls('%s') == false);" #define MAKE_CFG_LINK(name,title,viewTrack,open) \ safef(id, sizeof id, "%s_link", (name)); \ printf(CFG_LINK, (name),id,(title),(title),(viewTrack),((open)?"on":"off")); \ safef(javascript, sizeof javascript, CFG_LINK_JS, (name)); \ jsOnEventById("click", id, javascript); // membersForAll is generated once per track, then cached membersForAll_t *membersForAll = membersForAllSubGroupsGet(parentTdb, cart); members_t *membersOfView = membersForAll->members[dimV]; if (membersOfView == NULL) return FALSE; char configurable[membersOfView->count]; memset(configurable,cfgNone,sizeof(configurable)); int firstOpened = -1; boolean makeCfgRows = FALSE; struct trackDb **matchedViewTracks = needMem(sizeof(struct trackDb *) * membersOfView->count); for (ix = 0; ix < membersOfView->count; ix++) { if (membersOfView->subtrackList != NULL && membersOfView->subtrackList[ix] != NULL) { struct trackDb *subtrack = membersOfView->subtrackList[ix]->val; matchedViewTracks[ix] = subtrack->parent; configurable[ix] = (char)cfgTypeFromTdb(subtrack, TRUE); if (configurable[ix] != cfgNone && trackDbSettingBlocksConfiguration(subtrack,FALSE)) configurable[ix] = cfgNone; if (configurable[ix] != cfgNone) { if (firstOpened == -1) { if (cartOrTdbBoolean(cart, matchedViewTracks[ix], "showCfg", FALSE)) firstOpened = ix; } makeCfgRows = TRUE; } } } toLowerN(membersOfView->groupTitle, 1); printf("Select %s (Help):\n", membersOfView->groupTitle); printf("\n"); // Make row of vis drop downs for (ix = 0; ix < membersOfView->count; ix++) { char *viewName = membersOfView->tags[ix]; if (matchedViewTracks[ix] != NULL) { printf(""); char varName[SMALLBUF]; safef(varName, sizeof(varName), "%s", matchedViewTracks[ix]->track); enum trackVisibility tv = hTvFromString(cartUsualString(cart,varName, hStringFromTv(visCompositeViewDefault(parentTdb,viewName)))); struct slPair *events = NULL; safef(javascript, sizeof(javascript), "matSelectViewForSubTracks(this,'%s');", viewName); slPairAdd(&events, "change", cloneString(javascript)); safef(javascript, sizeof(javascript), "this.lastIndex=this.selectedIndex;"); slPairAdd(&events, "focus", cloneString(javascript)); printf(""); } } puts(""); // Make row of cfg boxes if needed if (makeCfgRows) { puts("
"); if (configurable[ix] != cfgNone) { MAKE_CFG_LINK(membersOfView->tags[ix],membersOfView->titles[ix], matchedViewTracks[ix]->track,(firstOpened == ix)) } else printf("%s",membersOfView->titles[ix]); puts(""); safef(classes, sizeof(classes), "viewDD normalText %s", membersOfView->tags[ix]); hTvDropDownClassWithJavascript(varName, NULL, tv, parentTdb->canPack, classes, events); puts("      
"); for (ix = 0; ix < membersOfView->count; ix++) { struct trackDb *view = matchedViewTracks[ix]; if (view != NULL) { char *viewName = membersOfView->tags[ix]; printf("tags[ix],NULL)) || (firstOpened != -1 && firstOpened != ix)) printf(" style=\"display:none\""); printf(">"); int ix2=ix; while (0 < ix2--) printf(""); printf(""); } } } puts("
  ",membersOfView->count+1); if (configurable[ix] != cfgNone) { // Hint: subtrack is model but named for view cfgByCfgType(configurable[ix],db,cart,view->subtracks,view->track, membersOfView->titles[ix],TRUE); } printf("
"); freeMem(matchedViewTracks); return TRUE; } char *compositeLabelWithVocabLink(char *db,struct trackDb *parentTdb, struct trackDb *childTdb, char *vocabType, char *label) // If the parentTdb has a controlledVocabulary setting and the vocabType is found, // then label will be wrapped with the link to display it. Return string is cloned. { char *vocab = trackDbSetting(parentTdb, "controlledVocabulary"); // WARNING: this is needed to cache metadata in trackDb object (accessed by metadataFindValue) (void)metadataForTable(db,childTdb,NULL); if (vocab == NULL) return cloneString(label); // No wrapping! // Currently implemented just for ENCODE style vocab if (!vocabSettingIsEncode(vocab)) return cloneString(label); char *words[SMALLBUF]; int count; if ((count = chopByWhite(cloneString(vocab), words, SMALLBUF)) <= 1) return cloneString(label); char *suffix = NULL; char *rootLabel = labelRoot(label, &suffix); boolean found = FALSE; int ix; for (ix=1;ix" #define PM_BUTTON_UC_JS "return (matSetMatrixCheckBoxes(%s%s%s%s%s%s) == false);" #define PM_MAKE_BUTTON_UC(s1,s2,s3,s4,s5,s6,name,img) \ safef(id, sizeof id, "btn_%s", (name)); \ printf(PM_BUTTON_UC, id, (img)); \ safef(javascript, sizeof javascript, PM_BUTTON_UC_JS, (s1),(s2),(s3),(s4),(s5),(s6)); \ jsOnEventById("click", id, javascript); #define MATRIX_RIGHT_BUTTONS_AFTER 8 #define MATRIX_BOTTOM_BUTTONS_AFTER 20 static void buttonsForAll(boolean left, boolean top) { char id[256]; char javascript[1024]; char fullname[256]; safef(fullname, sizeof fullname, "plus_all_%s_%s", left ? "left" : "right", top ? "top" : "bottom"); PM_MAKE_BUTTON_UC("true", "", "", "", "", "", fullname, "add_sm.gif") safef(fullname, sizeof fullname, "minus_all_%s_%s", left ? "left" : "right", top ? "top" : "bottom"); PM_MAKE_BUTTON_UC("false","", "", "", "", "", fullname, "remove_sm.gif") } static void buttonsForOne(char *class, boolean vertical, boolean left, boolean top) { char id[256]; char javascript[1024]; char fullname[256]; safef(fullname, sizeof fullname, "plus_%s_all_%s_%s" , class, left ? "left" : "right", top ? "top" : "bottom"); PM_MAKE_BUTTON_UC("true", ",'", class, "'", "", "", fullname, "add_sm.gif") if (vertical) puts("
"); safef(fullname, sizeof fullname, "minus_%s_all_%s_%s", class, left ? "left" : "right", top ? "top" : "bottom"); PM_MAKE_BUTTON_UC("false", ",'", class, "'", "", "", fullname, "remove_sm.gif") } #define MATRIX_SQUEEZE 10 static boolean matrixSqueeze(membersForAll_t* membersForAll) // Returns non-zero if the matrix will be squeezed. Non-zero is actually squeezedLabelHeight { char *browserVersion; if (btIE == cgiClientBrowser(&browserVersion, NULL, NULL) && *browserVersion < '9') return 0; members_t *dimensionX = membersForAll->members[dimX]; members_t *dimensionY = membersForAll->members[dimY]; if (dimensionX && dimensionY) { if (dimensionX->count>MATRIX_SQUEEZE) { int ixX,cntX=0; for (ixX = 0; ixX < dimensionX->count; ixX++) { if (dimensionX->subtrackList && dimensionX->subtrackList[ixX] && dimensionX->subtrackList[ixX]->val) cntX++; } if (cntX>MATRIX_SQUEEZE) return TRUE; } } return FALSE; } static void matrixXheadingsRow1(char *db, struct trackDb *parentTdb, boolean squeeze, membersForAll_t* membersForAll, boolean top) // prints the top row of a matrix: 'All' buttons; X titles; buttons 'All' { members_t *dimensionX = membersForAll->members[dimX]; members_t *dimensionY = membersForAll->members[dimY]; printf("\n",top?"BOTTOM":"TOP"); if (dimensionX && dimensionY) { printf("",top?"TOP":"BOTTOM"); //printf("",(top == squeeze)?"BOTTOM":"TOP");//"TOP":"BOTTOM"); buttonsForAll(TRUE, top); puts(" All"); } // If there is an X dimension, then titles go across the top if (dimensionX) { int ixX,cntX=0; if (dimensionY) { if (squeeze) printf("
%s
", (top?"up45":"dn45"), dimensionX->groupTitle); else printf("%s", dimensionX->groupTitle); } else printf("  %s", (top ? "TOP" : "BOTTOM"), dimensionX->groupTitle); for (ixX = 0; ixX < dimensionX->count; ixX++) { if (dimensionX->subtrackList && dimensionX->subtrackList[ixX] && dimensionX->subtrackList[ixX]->val) { if (dimensionY && squeeze) { // Breaks must be removed! strSwapStrs(dimensionX->titles[ixX],strlen(dimensionX->titles[ixX]),"
"," "); printf("
%s
\n", dimensionX->tags[ixX],(top?"up45":"dn45"), compositeLabelWithVocabLink(db,parentTdb,dimensionX->subtrackList[ixX]->val, dimensionX->groupTag,dimensionX->titles[ixX])); } else { char *label =replaceChars(dimensionX->titles[ixX]," (","
("); printf(" %s ", dimensionX->tags[ixX], compositeLabelWithVocabLink(db,parentTdb,dimensionX->subtrackList[ixX]->val, dimensionX->groupTag,label)); freeMem(label); } cntX++; } } // If dimension is big enough, then add Y buttons to right as well if (cntX>MATRIX_RIGHT_BUTTONS_AFTER) { if (dimensionY) { if (squeeze) printf("
%s
", (top?"up45":"dn45"), dimensionX->groupTitle); else printf("%s", dimensionX->groupTitle); printf("All ",top?"TOP":"BOTTOM"); buttonsForAll(FALSE, top); puts(""); } else printf("%s  ", top ? "TOP" : "BOTTOM", dimensionX->groupTitle); } } else if (dimensionY) { printf(""); printf("%s", dimensionY->groupTitle); printf(""); buttonsForAll(FALSE, top); puts(""); } puts("\n"); } static void matrixXheadingsRow2(struct trackDb *parentTdb, boolean squeeze, membersForAll_t* membersForAll, boolean top) // prints the 2nd row of a matrix: Y title; X buttons; title Y { members_t *dimensionX = membersForAll->members[dimX]; members_t *dimensionY = membersForAll->members[dimY]; // If there are both X and Y dimensions, then there is a row of buttons in X if (dimensionX && dimensionY) { int ixX,cntX=0; printf("%s", dimensionY->groupTitle); for (ixX = 0; ixX < dimensionX->count; ixX++) // Special row of +- +- +- { if (dimensionX->subtrackList && dimensionX->subtrackList[ixX] && dimensionX->subtrackList[ixX]->val) { printf("\n",dimensionX->tags[ixX]); buttonsForOne(dimensionX->tags[ixX], squeeze, TRUE, top); puts(""); cntX++; } } // If dimension is big enough, then add Y buttons to right as well if (cntX>MATRIX_RIGHT_BUTTONS_AFTER) printf("%s", dimensionY->groupTitle); puts("\n"); } } static boolean matrixXheadings(char *db,struct trackDb *parentTdb, membersForAll_t* membersForAll, boolean top) // UI for X headings in matrix { boolean squeeze = matrixSqueeze(membersForAll); if (top) matrixXheadingsRow1(db, parentTdb, squeeze, membersForAll, top); matrixXheadingsRow2(parentTdb, squeeze, membersForAll, top); if (!top) matrixXheadingsRow1(db, parentTdb, squeeze, membersForAll, top); return squeeze; } static void matrixYheadings(char *db,struct trackDb *parentTdb, membersForAll_t* membersForAll, int ixY, boolean left) // prints the column of Y labels and buttons { members_t *dimensionX = membersForAll->members[dimX]; members_t *dimensionY = membersForAll->members[dimY]; struct trackDb *childTdb = NULL; if (dimensionY && dimensionY->subtrackList && dimensionY->subtrackList[ixY] && dimensionY->subtrackList[ixY]->val) childTdb = dimensionY->subtrackList[ixY]->val; if (dimensionX && dimensionY && childTdb != NULL) // Both X and Y, then column of buttons { printf("", dimensionY->tags[ixY],left?"RIGHT":"LEFT"); if (left) printf("%s ",compositeLabelWithVocabLink(db,parentTdb,childTdb,dimensionY->groupTag, dimensionY->titles[ixY])); buttonsForOne(dimensionY->tags[ixY], FALSE, left, FALSE); if (!left) printf(" %s",compositeLabelWithVocabLink(db,parentTdb,childTdb,dimensionY->groupTag, dimensionY->titles[ixY])); puts(""); } else if (dimensionX) { printf("",left?"RIGHT":"LEFT"); buttonsForAll(TRUE, TRUE); puts(""); } else if (left && dimensionY && childTdb != NULL) printf("%s\n",dimensionY->tags[ixY], compositeLabelWithVocabLink(db,parentTdb,childTdb,dimensionY->groupTag, dimensionY->titles[ixY])); } static int displayABCdimensions(char *db,struct cart *cart, struct trackDb *parentTdb, struct slRef *subtrackRefList, membersForAll_t* membersForAll) // This will walk through all declared nonX&Y dimensions (X and Y is the 2D matrix of CBs. // NOTE: ABC dims are only supported if there are X & Y both. // Also expected number should be passed in { int count=0,ix; for (ix=dimA;ixdimMax;ix++) { if (membersForAll->members[ix]==NULL) continue; if (membersForAll->members[ix]->count<1) continue; count++; if (count==1) // First time set up a table puts("
"); printf("", membersForAll->members[ix]->groupTitle); int aIx; for (aIx=0;aIxmembers[ix]->count;aIx++) { if (membersForAll->members[ix]->tags[aIx] != NULL) { assert(membersForAll->members[ix]->subtrackList[aIx]->val != NULL); printf(""); } } puts(""); } if (count>0) puts("
  %s:"); char objName[SMALLBUF]; char other[JBUFSIZE]; boolean alreadySet=FALSE; if (membersForAll->members[ix]->selected != NULL) alreadySet = membersForAll->members[ix]->selected[aIx]; safef(objName, sizeof(objName), "%s.mat_%s_dim%c_cb",parentTdb->track, membersForAll->members[ix]->tags[aIx],membersForAll->letters[ix]); safef(other, sizeof other, "class='matCB abc %s'", membersForAll->members[ix]->tags[aIx]); cgiMakeCheckBoxIdAndMore(objName,alreadySet,objName,other); jsOnEventById("click", objName, "matCbClick(this);"); printf("%s",compositeLabelWithVocabLink(db,parentTdb, membersForAll->members[ix]->subtrackList[aIx]->val, membersForAll->members[ix]->groupTag, membersForAll->members[ix]->titles[aIx])); puts("
"); return count; } #ifdef DEBUG static void dumpDimension(members_t *dimension, char *name, FILE *f) /* Dump out information on dimension. */ { int count = dimension->count; fprintf(f, "%s: count=%d tag=%s title=%s setting=%s
\n", name, count, dimension->tag, dimension->title, dimension->setting); int i; for (i=0; inames[i], dimension->values[i]); fprintf(f, "
\n"); } #endif /* DEBUG */ static char *labelWithVocabLinkForMultiples(char *db,struct trackDb *parentTdb, members_t* members) // If the parentTdb has a controlledVocabulary setting and the vocabType is found, // then label will be wrapped with the link to all relevent terms. Return string is cloned. { assert(members->subtrackList != NULL); char *vocab = cloneString(trackDbSetting(parentTdb, "controlledVocabulary")); if (vocab == NULL) return cloneString(members->groupTitle); // No link wrapping! char *words[15]; int count,ix; boolean found=FALSE; if ((count = chopByWhite(vocab, words,15)) <= 1) // vocab now contains just the file name return cloneString(members->groupTitle); char *mdbVar = NULL; // Find mdb var to look up based upon the groupTag and cv setting for (ix=1;ixgroupTag,words[ix])) // controlledVocabulary setting matches tag { // so all labels are linked mdbVar = members->groupTag; break; } else if (startsWithWordByDelimiter(members->groupTag,'=',words[ix])) { mdbVar = words[ix] + strlen(members->groupTag) + 1; break; } } if (mdbVar == NULL) { freeMem(vocab); return cloneString(members->groupTitle); } #define VOCAB_MULTILINK_BEG "%s" struct dyString *dyLink = dyStringCreate(VOCAB_MULTILINK_BEG, (sameWord(mdbVar,"antibody")?"target":"term")); // Now build the comma delimited string of mdb vals (all have same mdb var) boolean first = TRUE; for (ix=0;ixcount;ix++) { if (members->subtrackList[ix] != NULL && members->subtrackList[ix]->val != NULL) { struct trackDb *childTdb = members->subtrackList[ix]->val; (void)metadataForTable(db,childTdb,NULL); // Makes sure this has been populated const char * mdbVal = metadataFindValue(childTdb,mdbVar); // one for each is enough if (mdbVal != NULL) { if (!first) dyStringAppendC(dyLink,','); dyStringAppend(dyLink,(char *)mdbVal); first = FALSE; } } } dyStringPrintf(dyLink,VOCAB_MULTILINK_END,members->groupTitle,members->groupTitle); freeMem(vocab); return dyStringCannibalize(&dyLink); } static boolean compositeUiByFilter(char *db, struct cart *cart, struct trackDb *parentTdb, char *formName) // UI for composite tracks: filter subgroups by multiselects to select subtracks. { membersForAll_t* membersForAll = membersForAllSubGroupsGet(parentTdb,cart); if (membersForAll == NULL || membersForAll->filters == FALSE) // Not Matrix or filters return FALSE; if (cartOptionalString(cart, "ajax") == NULL) { webIncludeResourceFile("ui.dropdownchecklist.css"); jsIncludeFile("ui.dropdownchecklist.js",NULL); jsIncludeFile("ddcl.js",NULL); } cgiDown(0.7); printf("Select subtracks %sby: (select multiple %sitems - %s)
\n", (membersForAll->members[dimX] != NULL || membersForAll->members[dimY] != NULL ? "further ":""), (membersForAll->dimMax == dimA?"":"categories and "),FILTERBY_HELP_LINK); printf("\n"); char id[256]; char javascript[1024]; // Do All [+][-] buttons if (membersForAll->members[dimX] == NULL && membersForAll->members[dimY] == NULL) // No matrix { printf("\n"); } // Now make a filterComp box for each ABC dimension int dimIx=dimA; for (dimIx=dimA;dimIxdimMax;dimIx++) { printf("\n"); } printf("
All:
"); // TODO: Test when a real world case actually calls this. Currently no trackDb.ra cases exist #define PM_BUTTON_FILTER_COMP "" #define PM_BUTTON_FILTER_COMP_JS "waitOnFunction(filterCompositeSet,this,%s);return false;" #define MAKE_PM_BUTTON_FILTER_COMP(tf,fc,plmi) \ safef(id, sizeof id, "btn_%s", (fc)); \ printf(PM_BUTTON_FILTER_COMP, id, (plmi)); \ safef(javascript, sizeof javascript, PM_BUTTON_FILTER_COMP_JS, (tf)); \ jsOnEventById("click", id, javascript); MAKE_PM_BUTTON_FILTER_COMP("true", "plus_fc",'+') MAKE_PM_BUTTON_FILTER_COMP("false","minus_fc",'-') printf("
%s:
\n", labelWithVocabLinkForMultiples(db,parentTdb,membersForAll->members[dimIx])); safef(id, sizeof id, "fc%d",dimIx); printf( ""); if (membersForAll->members[dimIx]->fcType == fctOneOnly) printf(" (select only one)"); printf("
\n"); puts("
\n"); return TRUE; } void fastMatixToSubtrackMap() // prints out the "common" globals json hash // This hash is the one utils.js and therefore all CGIs know about { struct dyString *dy = dyStringNew(1024); dyStringPrintf(dy, "var mtxSubMap = {};\n" "$( document ).ready(function()\n" "{\n" "matCB = $('input.matCB:first');\n" "if (!matCB)\n" " return;\n" "var matClassList = $( matCB ).attr('class').split(' ');\n" "matClassList = aryRemove(matClassList,['matCB','changed','disabled','abc']);\n" "if (matClassList.length === 0 )\n" " return;\n" "subCBs = $('input.subCB');\n" "$( subCBs ).each( function (i) { \n" " // class='subCB BS-Seq Mantle_Cell_Lymphoma venous_blood A007MCL CNAG CPG_methylation_cov signal' \n" " var classList = $( this ).attr('class').split(' ');\n" " if (matClassList.length === 1) {\n" " var classes = '.' + classList[1]; // dimX or dimY \n" " } else {\n" " var classes = '.' + classList[1] + '.' + classList[2]; // dimX and dimY \n" " }\n" " if (mtxSubMap[classes] === undefined) {\n" " mtxSubMap[classes] = [this];\n" " } else {\n" " mtxSubMap[classes].push(this);\n" " }\n" "});\n" "});\n" ); jsInline(dy->string); dyStringFree(&dy); } static boolean compositeUiByMatrix(char *db, struct cart *cart, struct trackDb *parentTdb, char *formName) // UI for composite tracks: matrix of checkboxes. { //int ix; char objName[SMALLBUF]; membersForAll_t* membersForAll = membersForAllSubGroupsGet(parentTdb,cart); if (membersForAll == NULL || membersForAll->dimensions == NULL) // Not Matrix! return FALSE; int ixX,ixY; members_t *dimensionX = membersForAll->members[dimX]; members_t *dimensionY = membersForAll->members[dimY]; // use array of char determine all the cells (in X,Y,Z dimensions) that are actually populated char *value; int sizeOfX = dimensionX?dimensionX->count:1; int sizeOfY = dimensionY?dimensionY->count:1; int cells[sizeOfX][sizeOfY]; // There needs to be atleast one element in dimension int chked[sizeOfX][sizeOfY]; // How many subCBs are checked per matCB? int enabd[sizeOfX][sizeOfY]; // How many subCBs are enabled per matCB? memset(cells, 0, sizeof(cells)); memset(chked, 0, sizeof(chked)); memset(enabd, 0, sizeof(chked)); struct slRef *subtrackRef, *subtrackRefList = trackDbListGetRefsToDescendantLeaves(parentTdb->subtracks); struct trackDb *subtrack; if (dimensionX || dimensionY) // Must be an X or Y dimension { // Fill the cells based upon subtrack membership for (subtrackRef = subtrackRefList; subtrackRef != NULL; subtrackRef = subtrackRef->next) { subtrack = subtrackRef->val; ixX = (dimensionX ? -1 : 0 ); ixY = (dimensionY ? -1 : 0 ); if (dimensionX && subgroupFind(subtrack,dimensionX->groupTag,&value)) { ixX = stringArrayIx(value,dimensionX->tags,dimensionX->count); subgroupFree(&value); } if (dimensionY && subgroupFind(subtrack,dimensionY->groupTag,&value)) { ixY = stringArrayIx(value,dimensionY->tags,dimensionY->count); subgroupFree(&value); } if (ixX > -1 && ixY > -1) { cells[ixX][ixY]++; int fourState = subtrackFourStateChecked(subtrack,cart); // hidden views are handled by 4-way CBs: only count enabled if (fourStateEnabled(fourState)) { // Only bother if the subtrack is found in all ABC dims checked if (subtrackInAllCurrentABCs(subtrack,membersForAll)) { enabd[ixX][ixY]++; if (fourStateChecked(fourState) == 1) chked[ixX][ixY]++; } } } } } // If there is no matrix and if there is a filterComposite, then were are done. if (dimensionX == NULL && dimensionY == NULL) { if (compositeUiByFilter(db, cart, parentTdb, formName)) return FALSE; } // Tell the user what to do: char javascript[JBUFSIZE]; //puts("Select subtracks by characterization:
"); printf("Select subtracks by "); if (dimensionX && !dimensionY) safef(javascript, sizeof(javascript), "%s:",dimensionX->groupTitle); else if (!dimensionX && dimensionY) safef(javascript, sizeof(javascript), "%s:",dimensionY->groupTitle); else if (dimensionX && dimensionY) safef(javascript, sizeof(javascript), "%s and %s:", dimensionX->groupTitle,dimensionY->groupTitle); else safef(javascript, sizeof(javascript), "multiple variables:"); puts(strLower(javascript)); if (!subgroupingExists(parentTdb,"view")) puts("(help)\n"); puts("
\n"); if (membersForAll->abcCount > 0 && membersForAll->filters == FALSE) { displayABCdimensions(db,cart,parentTdb,subtrackRefList,membersForAll); } // Could have been just filterComposite. Must be an X or Y dimension if (dimensionX == NULL && dimensionY == NULL) return FALSE; // if there is a treeimage, put it beside the matrix in the green box char *treeImage = trackDbSetting(parentTdb, "treeImage"); if (treeImage != NULL) { printf("
"); printf("\n", COLOR_BG_ALTDEFAULT); } else printf("
\n", COLOR_BG_ALTDEFAULT); (void)matrixXheadings(db,parentTdb,membersForAll,TRUE); // Now the Y by X matrix int cntX=0,cntY=0; for (ixY = 0; ixY < sizeOfY; ixY++) { if (dimensionY == NULL || (dimensionY->tags[ixY])) { cntY++; assert(!dimensionY || ixY < dimensionY->count); printf(""); matrixYheadings(db,parentTdb, membersForAll,ixY,TRUE); #define MAT_CB_SETUP "" #define MAT_CB(name,js) printf(MAT_CB_SETUP,(name),(name),(js)); for (ixX = 0; ixX < sizeOfX; ixX++) { if (dimensionX == NULL || (dimensionX->tags[ixX])) { assert(!dimensionX || ixX < dimensionX->count); if (cntY==1) // Only do this on the first good Y cntX++; if (dimensionX && ixX == dimensionX->count) break; char *ttlX = NULL; char *ttlY = NULL; if (dimensionX) { ttlX = cloneString(dimensionX->titles[ixX]); stripString(ttlX,""); stripString(ttlX,""); } if (dimensionY != NULL) { ttlY = cloneString(dimensionY->titles[ixY]); stripString(ttlY,""); stripString(ttlY,""); } if (cells[ixX][ixY] > 0) { boolean halfChecked = ( chked[ixX][ixY] > 0 && chked[ixX][ixY] < enabd[ixX][ixY]); struct dyString *dySettings = dyStringNew(256); if (dimensionX && dimensionY) { safef(objName, sizeof(objName), "mat_%s_%s_cb", dimensionX->tags[ixX],dimensionY->tags[ixY]); } else { safef(objName, sizeof(objName), "mat_%s_cb", (dimensionX ? dimensionX->tags[ixX] : dimensionY->tags[ixY])); } if (ttlX && ttlY) printf(""); } else { if (ttlX && ttlY) printf("\n", dimensionX->tags[ixX],dimensionY->tags[ixY]); else printf("\n", (dimensionX ? dimensionX->tags[ixX] : dimensionY->tags[ixY])); } } } if (dimensionX && cntX>MATRIX_RIGHT_BUTTONS_AFTER) matrixYheadings(db,parentTdb, membersForAll,ixY,FALSE); puts("\n"); } } if (dimensionY && cntY>MATRIX_BOTTOM_BUTTONS_AFTER) matrixXheadings(db,parentTdb,membersForAll,FALSE); puts("
\n", dimensionX->tags[ixX],dimensionY->tags[ixY]); else printf("\n", (dimensionX ? dimensionX->tags[ixX] : dimensionY->tags[ixY])); dyStringPrintf(dySettings, " class=\"matCB"); if (halfChecked) dyStringPrintf(dySettings, " disabled"); // appears disabled but still clickable! if (dimensionX) dyStringPrintf(dySettings, " %s",dimensionX->tags[ixX]); if (dimensionY) dyStringPrintf(dySettings, " %s",dimensionY->tags[ixY]); dyStringAppendC(dySettings,'"'); if (chked[ixX][ixY] > 0) dyStringAppend(dySettings," CHECKED"); if (halfChecked) dyStringAppend(dySettings," title='Not all associated subtracks have been selected'"); MAT_CB(objName,dyStringCannibalize(&dySettings)); jsOnEventById("click", objName, "matCbClick(this);"); // X&Y are set by javascript puts("
"); // if there is a treeImage, put it beside the matrix if (treeImage != NULL) printf("
", treeImage); // If any filter additional filter composites, they can be added at the end. compositeUiByFilter(db, cart, parentTdb, formName); fastMatixToSubtrackMap(); return TRUE; } static boolean compositeUiAllButtons(char *db, struct cart *cart, struct trackDb *parentTdb, char *formName) // UI for composite tracks: all/none buttons only (as opposed to matrix or lots of buttons { if (trackDbCountDescendantLeaves(parentTdb) <= 1) return FALSE; if (dimensionsExist(parentTdb)) return FALSE; #define PM_BUTTON_GLOBAL "" #define PM_BUTTON_GLOBAL_JS "matSubCBsCheck(%s);" char id[256]; safef(id, sizeof id, "btn_plus_all"); printf(PM_BUTTON_GLOBAL, id, "add_sm.gif"); jsOnEventByIdF("click", id, PM_BUTTON_GLOBAL_JS, "true"); safef(id, sizeof id, "btn_minus_all"); printf(PM_BUTTON_GLOBAL, id, "remove_sm.gif"); jsOnEventByIdF("click", id, PM_BUTTON_GLOBAL_JS, "false"); puts(" Select all subtracks
"); return TRUE; } static boolean compositeUiNoMatrix(char *db, struct cart *cart, struct trackDb *parentTdb, char *formName) // UI for composite tracks: subtrack selection. This is the default UI // without matrix controls. { int i, j, k; char *words[SMALLBUF]; char option[SMALLBUF]; int wordCnt; char *name, *value; char buttonVar[1024]; char setting[] = "subGroupN"; char *button; struct trackDb *subtrack; bool hasSubgroups = (trackDbSetting(parentTdb, "subGroup1") != NULL); if (dimensionsExist(parentTdb)) return FALSE; puts(""); if (hasSubgroups) { puts("Select subtracks:"); puts(""); puts("
    All           " "          "); } else { puts("
All subtracks:"); } safef(buttonVar, sizeof buttonVar, "%s", "button_all"); if (formName) { makeAddClearButtonPair("cpmUiNoMtx_but_all", NULL,""); // NULL means all } else { cgiMakeButton(buttonVar, ADD_BUTTON_LABEL); puts(""); cgiMakeButton(buttonVar, CLEAR_BUTTON_LABEL); } button = cgiOptionalString(buttonVar); if (isNotEmpty(button)) { struct slRef *tdbRefList = trackDbListGetRefsToDescendantLeaves(parentTdb->subtracks); struct slRef *tdbRef; for (tdbRef = tdbRefList; tdbRef != NULL; tdbRef = tdbRef->next) { subtrack = tdbRef->val; boolean newVal = FALSE; safef(option, sizeof(option), "%s_sel", subtrack->track); newVal = sameString(button, ADD_BUTTON_LABEL); cartSetBoolean(cart, option, newVal); } } puts("
"); // generate set & clear buttons for subgroups for (i = 0; i < MAX_SUBGROUP; i++) { char *subGroup; safef(setting, sizeof setting, "subGroup%d", i+1); if (trackDbSetting(parentTdb, setting) == NULL) break; wordCnt = chopLine(cloneString(trackDbSetting(parentTdb, setting)), words); if (wordCnt < 2) continue; subGroup = cloneString(words[0]); if (sameWord(subGroup,"view")) continue; // Multi-view should have taken care of "view" subgroup already puts(""); printf("", words[1]); for (j = 2; j < wordCnt; j++) { if (!parseAssignment(words[j], &name, &value)) continue; printf(""); button = cgiOptionalString(buttonVar); if (isEmpty(button)) continue; struct slRef *tdbRefList = trackDbListGetRefsToDescendantLeaves(parentTdb->subtracks); struct slRef *tdbRef; for (tdbRef = tdbRefList; tdbRef != NULL; tdbRef = tdbRef->next) { subtrack = tdbRef->val; char *p; int n; if ((p = trackDbSetting(subtrack, "subGroups")) == NULL) continue; n = chopLine(cloneString(p), words); for (k = 0; k < n; k++) { char *subName, *subValue; if (!parseAssignment(words[k], &subName, &subValue)) continue; if (sameString(subName, subGroup) && sameString(subValue, name)) { boolean newVal = FALSE; safef(option, sizeof(option),"%s_sel", subtrack->track); newVal = sameString(button, ADD_BUTTON_LABEL); cartSetBoolean(cart, option, newVal); } } } } puts("
    %s
            %s", value); safef(buttonVar, sizeof buttonVar, "%s_%s", subGroup, name); if (formName) { char id[256]; safef(id, sizeof id, "cpmUiNoMtx_but_%d_%d", i, j); makeAddClearButtonPair(id, name,""); } else { cgiMakeButton(buttonVar, ADD_BUTTON_LABEL); puts(""); cgiMakeButton(buttonVar, CLEAR_BUTTON_LABEL); } puts("
"); } return TRUE; } static bool mouseOverJsDone = FALSE; void printInfoIconSvg() /* Print just info icon (i) as svg tag to stdout */ { puts(""); puts(""); puts(""); puts(""); puts(""); } void printInfoIcon(char *mouseover) /* Print info icon (i) with explanatory text on mouseover */ { // see https://www.svgrepo.com/svg/524660/info-circle printf("", mouseover); printInfoIconSvg(); puts(""); if (!mouseOverJsDone) { jsInline("convertTitleTagsToMouseovers();\n"); mouseOverJsDone = TRUE; } } void hCompositeUi(char *db, struct cart *cart, struct trackDb *tdb, char *primarySubtrack, char *fakeSubmit, char *formName) // UI for composite tracks: subtrack selection. If primarySubtrack is // non-NULL, don't allow it to be cleared and only offer subtracks // that have the same type. If fakeSubmit is non-NULL, add a hidden // var with that name so it looks like it was pressed. { bool hasSubgroups = (trackDbSetting(tdb, "subGroup1") != NULL); boolean isMatrix = dimensionsExist(tdb); boolean viewsOnly = FALSE; if (primarySubtrack == NULL && !cartVarExists(cart, "ajax")) { if (trackDbSetting(tdb, "dragAndDrop") != NULL) jsIncludeFile("jquery.tablednd.js", NULL); jsIncludeFile("ajax.js",NULL); jsIncludeFile("hui.js",NULL); jsIncludeFile("subCfg.js",NULL); jsIncludeFile("ddcl.js", NULL); webIncludeResourceFile("ui.dropdownchecklist.css"); jsIncludeFile("ui.dropdownchecklist.js",NULL); } cgiDown(0.3); boolean hideSubtracksDefault; // TODO: Gray out or otherwise suppress when in multi-region mode if (compositeHideEmptySubtracksSetting(tdb, &hideSubtracksDefault, NULL, NULL)) { char *hideLabel = "Hide empty subtracks"; hideLabel = trackDbSettingOrDefault(tdb, SUBTRACK_HIDE_EMPTY_LABEL, hideLabel); printf("

%s:  ", hideLabel); char buf[128]; safef(buf, sizeof buf, "%s.%s", tdb->track, SUBTRACK_HIDE_EMPTY); boolean doHideEmpties = compositeHideEmptySubtracks(cart, tdb, NULL, NULL); cgiMakeCheckBox(buf, doHideEmpties); // info icon with explanatory text on mouseover char *info = "Subtracks with no data in the browser window are hidden. Changing the browser window" " by zooming or scrolling may result in display of a different selection of tracks."; printInfoIcon(info); printf("

"); } if (trackDbCountDescendantLeaves(tdb) < MANY_SUBTRACKS && !hasSubgroups) { if (primarySubtrack) compositeUiSubtracksMatchingPrimary(db, cart, tdb,primarySubtrack); else compositeUiSubtracks(db, cart, tdb); return; } if (fakeSubmit) cgiMakeHiddenVar(fakeSubmit, "submit"); if (primarySubtrack == NULL) { if (subgroupingExists(tdb,"view")) { hCompositeDisplayViewDropDowns(db, cart,tdb); if (subgroupCount(tdb) <= 1) viewsOnly = TRUE; } if (!viewsOnly) { cgiDown(0.7); if (trackDbSettingOn(tdb, "allButtonPair")) { compositeUiAllButtons(db, cart, tdb, formName); } else if (!hasSubgroups || !isMatrix) { compositeUiNoMatrix(db, cart, tdb, formName); } else { compositeUiByMatrix(db, cart, tdb, formName); } } } cartSaveSession(cart); cgiContinueHiddenVar("g"); if (primarySubtrack) compositeUiSubtracksMatchingPrimary(db, cart, tdb,primarySubtrack); else compositeUiSubtracks(db, cart, tdb); if (primarySubtrack == NULL) // primarySubtrack is set for tableBrowser but not hgTrackUi { if (trackDbCountDescendantLeaves(tdb) > 5) { cgiDown(0.7); cgiMakeButton("Submit", "Submit"); } } } boolean superTrackDropDownWithExtra(struct cart *cart, struct trackDb *tdb, int visibleChild, struct slPair *events) // Displays hide/show dropdown for supertrack. // Set visibleChild to indicate whether 'show' should be grayed // out to indicate that no supertrack members are visible: // 0 to gray out (no visible children) // 1 don't gray out (there are visible children) // -1 don't know (this function should determine) // If -1,i the subtracks field must be populated with the child trackDbs. // Returns false if not a supertrack { if (!tdbIsSuperTrack(tdb)) return FALSE; // determine if supertrack is show/hide boolean show = FALSE; char *setting = cartUsualString(cart, tdb->track, tdb->isShow ? "show" : "hide"); if (sameString("show", setting)) show = TRUE; // Determine if any tracks in supertrack are visible; if not, the 'show' is grayed out if (show && (visibleChild == -1)) { visibleChild = 0; struct slRef *childRef; for ( childRef = tdb->children; childRef != NULL; childRef = childRef->next) { struct trackDb *cTdb = childRef->val; cTdb->visibility = hTvFromString(cartUsualString(cart, cTdb->track, hStringFromTv(cTdb->visibility))); if (cTdb->visibility != tvHide) visibleChild = 1; } } hideShowDropDownWithClassAndExtra(tdb->track, NULL, show, (show && visibleChild) ? "normalText visDD" : "hiddenText visDD", events); return TRUE; } int tvConvertToNumericOrder(enum trackVisibility v) { return ((v) == tvShow ? 5 : \ (v) == tvFull ? 4 : \ (v) == tvPack ? 3 : \ (v) == tvSquish ? 2 : \ (v) == tvDense ? 1 : 0); } int tvCompare(enum trackVisibility a, enum trackVisibility b) /* enum trackVis isn't in numeric order by visibility, so compare * symbolically: */ { return (tvConvertToNumericOrder(b) - tvConvertToNumericOrder(a)); } enum trackVisibility tvMin(enum trackVisibility a, enum trackVisibility b) /* Return the less visible of a and b. */ { if (tvCompare(a, b) >= 0) return a; else return b; } enum trackVisibility tdbLocalVisibility(struct cart *cart, struct trackDb *tdb, boolean *subtrackOverride) // returns visibility NOT limited by ancestry. // Fills optional boolean if subtrack specific vis is found // If not NULL cart will be examined without ClosestToHome. // Folders/supertracks resolve to hide/full { if (subtrackOverride != NULL) *subtrackOverride = FALSE; // default // tdb->visibility should reflect local trackDb setting enum trackVisibility vis = tdb->visibility; if (tdbIsSuperTrack(tdb)) vis = (tdb->isShow ? tvFull : tvHide); if (cart != NULL) // cart is optional { char *cartVis = cartOptionalString(cart, tdb->track); boolean cgiVar = FALSE; // check hub tracks for visibility settings without the hub prefix if (startsWith("hub_", tdb->track) && (cartVis == NULL)) { cartVis = cgiOptionalString( trackHubSkipHubName(tdb->track)); cgiVar = TRUE; } if (cartVis != NULL) { vis = hTvFromString(cartVis); if (subtrackOverride != NULL && tdbIsContainerChild(tdb)) *subtrackOverride = TRUE; if (cgiVar) { cartSetString(cart, tdb->track, cartVis); // add the decorated visibility to the cart cartRemove(cart, trackHubSkipHubName(tdb->track)); // remove the undecorated version } } } return vis; } enum trackVisibility tdbVisLimitedByAncestors(struct cart *cart, struct trackDb *tdb, boolean checkBoxToo, boolean foldersToo) // returns visibility limited by ancestry. // This includes subtrack vis override and parents limit maximum. // cart may be null, in which case, only trackDb settings (default state) are examined // checkBoxToo means ensure subtrack checkbox state is visible // foldersToo means limit by folders (aka superTracks) as well. { boolean subtrackOverride = FALSE; enum trackVisibility vis = tdbLocalVisibility(cart,tdb,&subtrackOverride); if (tdbIsContainerChild(tdb)) { // subtracks without explicit (cart) vis but are selected, should get inherited vis if (!subtrackOverride) vis = tvFull; // subtracks with checkbox that says no, are stopped cold if (checkBoxToo && !fourStateVisible(subtrackFourStateChecked(tdb,cart))) vis = tvHide; // Checkbox says no } if (subtrackOverride) return vis; // aka superTrack if (vis == tvHide || tdb->parent == NULL || (!foldersToo && tdbIsFolder(tdb->parent))) return vis; // end of line return tvMin(vis,tdbVisLimitedByAncestors(cart,tdb->parent,checkBoxToo,foldersToo)); } char *compositeViewControlNameFromTdb(struct trackDb *tdb) // Returns a string with the composite view control name if one exists { char *stView = NULL; char *name = NULL; char *rootName = NULL; // This routine should give these results: compositeName.viewName or else subtrackName.viewName // or else compositeName or else subtrackName if (tdbIsCompositeChild(tdb) == TRUE && trackDbLocalSetting(tdb, "parent") != NULL) { if (trackDbSettingClosestToHomeOn(tdb, "configurable")) rootName = tdb->track; // subtrackName else rootName = firstWordInLine(cloneString(trackDbLocalSetting(tdb, "parent"))); } if (rootName != NULL) { if (subgroupFind(tdb,"view",&stView)) { int len = strlen(rootName) + strlen(stView) + 3; name = needMem(len); safef(name,len,"%s.%s",rootName,stView); subgroupFree(&stView); } else name = cloneString(rootName); } else name = cloneString(tdb->track); return name; } void compositeViewControlNameFree(char **name) // frees a string allocated by compositeViewControlNameFromTdb { if (name && *name) freez(name); } boolean isNameAtParentLevel(struct trackDb *tdb,char *name) // cfgUi controls are passed a prefix name that may be at the composite, view or subtrack level // returns TRUE if name at view or composite level { struct trackDb *parent; for (parent = tdb->parent; parent != NULL; parent = parent->parent) if (startsWithWordByDelimiter(parent->track, '.', name)) return TRUE; return FALSE; } boolean chainDbNormScoreAvailable(struct trackDb *tdb) /* check if normScore column is specified in trackDb as available */ { boolean normScoreAvailable = FALSE; char * normScoreTest = trackDbSettingClosestToHomeOrDefault(tdb, "chainNormScoreAvailable", "no"); if (differentWord(normScoreTest, "no")) normScoreAvailable = TRUE; return normScoreAvailable; } void hPrintAbbreviationTable(struct sqlConnection *conn, char *sourceTable, char *label) /* Print out table of abbreviations. */ { char query[256]; sqlSafef(query, sizeof(query), "select name,description from %s order by name", sourceTable); struct sqlResult *sr = sqlGetResult(conn, query); webPrintLinkTableStart(); webPrintLabelCell("Symbol"); webPrintLabelCell(label); char **row; while ((row = sqlNextRow(sr)) != NULL) { printf("\n"); char *name = row[0]; char *description = row[1]; webPrintLinkCell(name); webPrintLinkCell(description); } sqlFreeResult(&sr); webPrintLinkTableEnd(); } /* Special info (cell type abbreviations) for factorSource tracks */ struct factorSourceInfo /* Cell type and description */ { struct factorSourceInfo *next; char *name; char *description; }; static int factorSourceInfoCmp(const void *va, const void *vb) /* Compare two factorSourceInfo's, sorting on name and then description fields */ { static char bufA[64], bufB[64]; const struct factorSourceInfo *a = *((struct factorSourceInfo **)va); const struct factorSourceInfo *b = *((struct factorSourceInfo **)vb); safef(bufA, 64, "%s+%s", a->name, a->description); safef(bufB, 64, "%s+%s", b->name, b->description); return strcmp(bufA, bufB); } void hPrintFactorSourceAbbrevTable(struct sqlConnection *conn, struct trackDb *tdb) /* Print out table of abbreviations. With 'pack' setting, * show cell name only (before '+') and uniqify */ { char *label = "Cell Type"; char *sourceTable = trackDbRequiredSetting(tdb, SOURCE_TABLE); char query[256]; sqlSafef(query, sizeof(query), "select name,description from %s order by name", sourceTable); struct sqlResult *sr = sqlGetResult(conn, query); webPrintLinkTableStart(); webPrintLabelCell("Symbol"); webPrintLabelCell(label); char **row; char *plus; struct factorSourceInfo *source = NULL, *sources = NULL; while ((row = sqlNextRow(sr)) != NULL) { char *name = row[0]; char *description = row[1]; // truncate description to just the cell type if ((plus = strchr(description, '+')) != NULL) *plus = 0; AllocVar(source); source->name = cloneString(name); source->description = cloneString(description); slAddHead(&sources, source); } slUniqify(&sources, factorSourceInfoCmp, NULL); int count = 0; while ((source = slPopHead(&sources)) != NULL) { printf("\n"); webPrintLinkCell(source->name); webPrintLinkCellStart(); fputs(source->description, stdout); count++; while (sources && sameString(sources->name, source->name)) { source = slPopHead(&sources); fputs(", ", stdout); fputs(source->description, stdout); count++; } webPrintLinkCellEnd(); } sqlFreeResult(&sr); webPrintLinkTableEnd(); printf("Total: %d\n", count); } static char *makeOnePennantIcon(char *setting, char **hintRet) // Builds a string with pennantIcon HTML and returns it. Also returns hint. */ { setting = cloneString(setting); char *icon = nextWord(&setting); char buffer[4096]; char *src = NULL; char *url = NULL, *hint = NULL, *color = NULL; boolean isTextIcon = FALSE; if (!(endsWith(icon, ".jpg") || endsWith(icon, ".png"))) { isTextIcon = TRUE; color = nextWord(&setting); src = strLower(icon); } else if (startsWith("http://", icon) || startsWith("https://", icon) || startsWith("ftp://", icon)) src = htmlEncode(icon); else { safef(buffer, sizeof buffer, "../images/%s", icon); src = htmlEncode(buffer); } if (setting) { url = nextWord(&setting); if (setting) { hint = htmlEncode(stripEnclosingDoubleQuotes(setting)); } } struct dyString *ds = dyStringNew(0); // generate markup if (url) dyStringPrintf(ds, ""); // add text or image if (isTextIcon) dyStringPrintf(ds, "%s", src); else dyStringPrintf(ds, "", src); // close tags if (url) dyStringAppend(ds, ""); else if (isTextIcon) dyStringAppend(ds, ""); dyStringAppend(ds, "\n"); if (hint && hintRet) *hintRet = cloneString(hint); return dyStringCannibalize(&ds); } static struct slPair *makePennantIcons(struct trackDb *tdb) /* Return a list of pairs of pennantIcon HTML and note strings. */ { char *setting = trackDbSetting(tdb, "pennantIcon"); if (setting == NULL || sameString(setting, "none")) return NULL; struct slPair *list = NULL; int maxPennants = 3; char *pennants[maxPennants]; int numPennants = chopByChar(setting, ';', pennants, ArraySize(pennants)); int i; for (i = 0; i < numPennants; i++) { char *hint = NULL; char *html = makeOnePennantIcon(pennants[i], &hint); slPairAdd(&list, html, hint); freeMem(html); } slReverse(&list); return list; } void hPrintIcons(struct trackDb *tdb) /* prints optional folder and pennants icons and a space, if any icons were printed */ { bool hasIcon = hPrintPennantIcon(tdb); if (tdbIsSuper(tdb) || tdbIsComposite(tdb)) { // this is the folder.svg icon from the font-awesome collection. // the icon collection also contains a "fa fa-folder-o" icon, which is the outlined version // It was decided to use only the filled out icon for now and use the same icon for super // and composite tracks. Adding the SVG removes a dependency and makes the icons show up instantly, // instead of the short delay when using fonts. Github uses icons like this. hPrintf("" ""); hasIcon = TRUE; } if (hasIcon) hPrintf(" "); } boolean hPrintPennantIcon(struct trackDb *tdb) // Returns TRUE and prints out the "pennantIcon" when found. // Example: ENCODE tracks in hgTracks config list. { if (trackDbSetting(tdb, "wgEncode") != NULL) { hPrintf("\n"); } struct slPair *list = makePennantIcons(tdb), *el; boolean gotPennant = (list != NULL); for (el = list; el != NULL; el = el->next) hPrintf("%s\n", el->name); slPairFreeValsAndList(&list); return gotPennant; } boolean printPennantIconNote(struct trackDb *tdb) // Returns TRUE and prints out the "pennantIcon" and note when found. //This is used by hgTrackUi and hgc before printing out trackDb "html" { struct slPair *list = makePennantIcons(tdb), *el; boolean gotPennant = (list != NULL); for (el = list; el != NULL; el = el->next) { printf("
%s\n", el->name); char *hint = el->val; if (hint) printf("Note: %s\n", hint); } slPairFreeValsAndList(&list); return gotPennant; } void printUpdateTime(char *database, struct trackDb *tdb, struct customTrack *ct) /* display table update time */ { if (trackHubDatabase(database)) return; /* have not decided what to do for a composite container */ if (tdbIsComposite(tdb) || tdbIsSuper(tdb)) return; struct sqlConnection *conn = NULL; char *tableName = NULL; if (isCustomTrack(tdb->track)) { if (ct) { conn = hAllocConn(CUSTOM_TRASH); tableName = ct->dbTableName; } } else if (startsWith("big", tdb->type)) { char *tableName = hTableForTrack(database, tdb->table); struct sqlConnection *conn = hAllocConnTrack(database, tdb); char *bbiFileName = bbiNameFromSettingOrTable(tdb, conn, tableName); hFreeConn(&conn); struct bbiFile *bbi = NULL; if (startsWith("bigWig", tdb->type)) bbi = bigWigFileOpen(bbiFileName); else bbi = bigBedFileOpen(bbiFileName); time_t timep = 0; if (bbi) { timep = bbiUpdateTime(bbi); bbiFileClose(&bbi); } printBbiUpdateTime(&timep); } else { tableName = hTableForTrack(database, tdb->table); conn = hAllocConnTrack(database, tdb); } if (tableName) { char *date = firstWordInLine(sqlTableUpdate(conn, tableName)); if (date != NULL) printf("Data last updated at UCSC: %s
\n", date); } hFreeConn(&conn); } void printBbiUpdateTime(time_t *timep) /* for bbi files, print out the timep value */ { printf("Data last updated at UCSC: %s
\n", sqlUnixTimeToDate(timep, FALSE)); } static boolean tableDescriptionsExists(struct sqlConnection *conn) /* Cache flag for whether tableDescriptions exists in conn, in case we will need to * fetch a lot of descriptions from tableDescriptions. */ { static struct hash *hash = NULL; if (hash == NULL) hash = hashNew(0); char *db = sqlGetDatabase(conn); int exists = hashIntValDefault(hash, db, -1); if (exists < 0) { exists = sqlTableExists(conn, "tableDescriptions"); hashAddInt(hash, db, exists); } return (boolean)exists; } struct asObject *asFromTableDescriptions(struct sqlConnection *conn, char *table) // If there is a tableDescriptions table and it has an entry for table, return // a parsed autoSql object; otherwise return NULL. { struct asObject *asObj = NULL; if (tableDescriptionsExists(conn)) { char query[PATH_LEN*2]; // Try unsplit table first. sqlSafef(query, sizeof(query), "select autoSqlDef from tableDescriptions where tableName='%s'", table); char *asText = sqlQuickString(conn, query); // If no result try split table. if (asText == NULL) { sqlSafef(query, sizeof(query), "select autoSqlDef from tableDescriptions where tableName='chrN_%s'", table); asText = sqlQuickString(conn, query); } if (isNotEmpty(asText)) asObj = asParseText(asText); freez(&asText); } return asObj; } static struct asObject *asForTdbOrDie(struct sqlConnection *conn, struct trackDb *tdb) // Get autoSQL description if any associated with tdb. // Abort if there's a problem { struct asObject *asObj = NULL; if (tdbIsBigBed(tdb)) { char *fileName = hReplaceGbdb(tdbBigFileName(conn, tdb)); if (fileName == NULL) return NULL; asObj = bigBedFileAsObjOrDefault(fileName); freeMem(fileName); } // TODO: standardize to a wig as //else if (tdbIsBigWig(tdb)) // asObj = asObjFrombigBed(conn,tdb); else if (tdbIsLongTabix(tdb)) asObj = longTabixAsObj(); else if (tdbIsBam(tdb)) asObj = bamAsObj(); else if (tdbIsVcf(tdb)) asObj = vcfAsObj(); else if (startsWithWord("makeItems", tdb->type)) asObj = makeItemsItemAsObj(); else if (sameWord("bedDetail", tdb->type)) asObj = bedDetailAsObj(); else if (sameWord("pgSnp", tdb->type)) asObj = pgSnpAsObj(); else if (sameWord("barChart", tdb->type)) asObj = asParseText(barChartAutoSqlString); else if (sameWord("interact", tdb->type)) asObj = interactAsObj(); else if (sameWord("hic", tdb->type)) // HI-C data are stored in .hic files, but parsed into interact objects asObj = interactAsObj(); else asObj = asFromTableDescriptions(conn, tdb->table); return asObj; } struct asObject *asForTdb(struct sqlConnection *conn, struct trackDb *tdb) // Get autoSQL description if any associated with table, ignoring errAborts if any. { struct errCatch *errCatch = errCatchNew(); struct asObject *asObj = NULL; // Wrap some error catching around asForTdbOrDie. if (errCatchStart(errCatch)) { asObj = asForTdbOrDie(conn, tdb); } errCatchEnd(errCatch); errCatchFree(&errCatch); return asObj; } struct asObject *asForDb(struct trackDb *tdb, char* database) /* return asObject given the database. NULL if not found */ { struct sqlConnection *conn = NULL ; if (!trackHubDatabase(database)) conn = hAllocConnTrack(database, tdb); struct asObject *as = asForTdb(conn, tdb); hFreeConn(&conn); return as; } #ifdef OLD /* This got moved to main library . */ struct asColumn *asColumnFind(struct asObject *asObj, char *name) // Return named column. { struct asColumn *asCol = NULL; if (asObj!= NULL) { for (asCol = asObj->columnList; asCol != NULL; asCol = asCol->next) if (sameString(asCol->name, name)) break; } return asCol; } #endif /* OLD */ struct slName *asColNames(struct asObject *as) // Get list of column names. { struct slName *list = NULL, *el; struct asColumn *col; for (col = as->columnList; col != NULL; col = col->next) { el = slNameNew(col->name); slAddHead(&list, el); } slReverse(&list); return list; } static struct dyString *subMultiField(char *pattern, int fieldCount, char *in[], char *out[]) /* Substitute $in with out values in pattern */ { int i; struct dyString *s = dyStringNew(256), *d = NULL; dyStringAppend(s, pattern); for (i=0; istring)) { d = dyStringSub(s->string, strictSpec, out[i]); s = d; } // the user may have both a ${} enclosed instance and a non-enclosed one! d = dyStringSub(s->string, spec, out[i]); dyStringFree(&s); freeMem(spec); freeMem(strictSpec); s = d; d = NULL; } return s; } char *replaceFieldInPattern(char *pattern, int fieldCount, char **fieldNames, char **fieldVals) /* Replace $fieldName in pattern with value. Used in trackDb mouseOver setting */ { struct dyString *ds = subMultiField(pattern, fieldCount, fieldNames, fieldVals); return dyStringCannibalize(&ds); } static struct dyString *subMulti(char *orig, int subCount, char *in[], char *out[]) /* Perform multiple substitions on orig. */ { int i; struct dyString *s = dyStringNew(256), *d = NULL; dyStringAppend(s, orig); for (i=0; istring, in[i], out[i]); dyStringFree(&s); s = d; d = NULL; } return s; } char *replaceInUrl(char *url, char *idInUrl, struct cart *cart, char *db, char *seqName, int winStart, int winEnd, char *track, boolean encode, struct slPair *fields) /* replace $$ in url with idInUrl. Supports many other wildchards, and custom fields $ * XX Do we have readable docs for these parameters somewhere? * Look at http://genome.ucsc.edu/goldenpath/help/trackDb/trackDbHub.html */ { struct dyString *uUrl = NULL; struct dyString *eUrl = NULL; char startString[64], endString[64],oneBasedStart[64]; char *ins[14], *outs[14]; char *eItem = (encode ? cgiEncode(idInUrl) : cloneString(idInUrl)); char *scName = NULL; // try to avoid the mysql query it not necessary if (stringIn("$n", url)) { char *tmp = hScientificName(db); scName = replaceChars(tmp, " ", "_"); freeMem(tmp); } char *taxId = NULL; // try to avoid the mysql query it not necessary if (stringIn("$taxId", url)) { char query[256]; struct sqlConnection *centralConn = hConnectCentral(); sqlSafef(query, sizeof(query), "select taxId from %s " "where name='%s'", dbDbTable(), db); taxId = sqlQuickString(centralConn, query); hDisconnectCentral(¢ralConn); } safef(startString, sizeof startString, "%d", winStart); safef(endString, sizeof endString, "%d", winEnd); ins[0] = "$$"; outs[0] = idInUrl; ins[1] = "$T"; outs[1] = track; ins[2] = "$S"; outs[2] = seqName; ins[3] = "$["; outs[3] = startString; ins[4] = "$]"; outs[4] = endString; ins[5] = "$s"; outs[5] = skipChr(seqName); ins[6] = "$D"; outs[6] = trackHubSkipHubName(db); ins[7] = "$P"; /* for an item name of the form: prefix:suffix */ ins[8] = "$p"; /* the P is the prefix, the p is the suffix */ if (stringIn(":", idInUrl)) { char *itemClone = cloneString(idInUrl); char *suffix = stringIn(":", itemClone); char *suffixClone = cloneString(suffix+1); /* +1 skip the : */ char *nextColon = stringIn(":", suffixClone+1); if (nextColon) /* terminate suffixClone suffix */ *nextColon = '\0'; /* when next colon is present */ *suffix = '\0'; /* terminate itemClone prefix */ outs[7] = itemClone; outs[8] = suffixClone; /* small memory leak here for these cloned strings */ /* not important for a one-time operation in a CGI that will exit */ } else { outs[7] = idInUrl; /* otherwise, these are not expected */ outs[8] = idInUrl; /* to be used */ } // URL may now contain item boundaries ins[9] = "${"; ins[10] = "$}"; ins[13] = "$#"; if (cart!=NULL && cartOptionalString(cart, "o") && cartOptionalString(cart, "t")) { char *itemBeg = cartString(cart, "o"); // unexpected commas? char *itemEnd = cartString(cart, "t"); outs[9] = itemBeg; outs[10] = itemEnd; safef(oneBasedStart, sizeof(oneBasedStart), "%d", cartInt(cart, "o") + 1); outs[13] = oneBasedStart; } else // should never be but I am unwilling to bet the farm { outs[9] = startString; outs[10] = endString; safef(oneBasedStart, sizeof(oneBasedStart), "%d", winStart + 1); outs[13] = oneBasedStart; } ins[11] = "$n"; outs[11] = scName; ins[12] = "$taxId"; outs[12] = taxId; uUrl = subMulti(url, ArraySize(ins), ins, outs); outs[0] = eItem; eUrl = subMulti(url, ArraySize(ins), ins, outs); dyStringFree(&uUrl); freeMem(eItem); freeMem(scName); // substitute $ variables if (!fields) return eUrl->string; int fieldCount = slCount(fields); char **fieldNames = NULL, **fieldVals = NULL; AllocArray(fieldNames, fieldCount); AllocArray(fieldVals, fieldCount); int i; struct slPair *field; for (i=0, field=fields; inext) { char buf[64]; safef(buf, sizeof buf, "$<%s>", field->name); fieldNames[i] = cloneString(buf); fieldVals[i] = (char *)field->val; } struct dyString *fUrl = subMulti(eUrl->string, fieldCount, fieldNames, fieldVals); return fUrl->string; } char *checkDataVersion(char *database, struct trackDb *tdb) /* see if trackDb has a dataVersion setting and check that file for version */ { // try the metadata metadataForTable(database, tdb, NULL); char *version = (char *)metadataFindValue(tdb, "dataVersion"); // try trackDb itself, this automatically will go up the hierarchy if (version == NULL) version = trackDbSetting(tdb, "dataVersion"); if (version != NULL) { // dataVersion can also be the path to a local file, for otto tracks if (!trackHubDatabase(database) && !isHubTrack(tdb->table) && startsWith("/", version)) { char *path = replaceInUrl(version, "", NULL, database, "", 0, 0, tdb->track, FALSE, NULL); struct lineFile* lf = lineFileMayOpen(path, TRUE); if (lf) version = lineFileReadAll(lf); else version = NULL; lineFileClose(&lf); } } return version; } void printDataVersion(char *database, struct trackDb *tdb) /* If this annotation has a dataVersion setting, print it. * check hgFixed.trackVersion, meta data and trackDb 'dataVersion'. */ { char *version = checkDataVersion(database, tdb); if (version == NULL) { // try the hgFixed.trackVersion table struct trackVersion *trackVersion = getTrackVersion(database, tdb->track); // try trackVersion table with parent, for composites/superTracks if (trackVersion == NULL && tdb->parent != NULL) trackVersion = getTrackVersion(database, tdb->parent->track); if (trackVersion != NULL) version = trackVersion->version; } if (isNotEmpty(version)) printf("Source data version: %s
\n", version); } void printRelatedTracks(char *database, struct hash *trackHash, struct trackDb *tdb, struct cart *cart) /* Maybe print a "related track" section */ { if (trackHubDatabase(database)) return; char *relatedTrackTable = cfgOptionDefault("db.relatedTrack","relatedTrack"); struct sqlConnection *conn = hAllocConn(database); if (!sqlTableExists(conn, relatedTrackTable)) { hFreeConn(&conn); return; } char query[256]; sqlSafef(query, sizeof(query), "select track2, why from %s where track1='%s'", relatedTrackTable, tdb->track); char **row; struct sqlResult *sr; sr = sqlGetResult(conn, query); row = sqlNextRow(sr); if (row != NULL) { puts("Related tracks\n"); puts("
    \n"); struct hash *otherTracksAndDesc = hashNew(0); char *why, *otherTrack; for (; row != NULL; row = sqlNextRow(sr)) { otherTrack = row[0]; why = row[1]; // hopefully relatedTracks.ra doesn't have dupes but hash them just in case hashReplace(otherTracksAndDesc, cloneString(otherTrack), cloneString(why)); } struct hashEl *hel, *helList = hashElListHash(otherTracksAndDesc); for (hel = helList; hel != NULL; hel = hel->next) { char *otherTrack = (char *)hel->name; char *why = (char *)hel->val; struct trackDb *otherTdb = hashFindVal(trackHash, otherTrack); // super tracks are not in the hash: if (!otherTdb) otherTdb = tdbForTrack(database, otherTrack, NULL); if (otherTdb) { puts("
  • "); printf("%s", hTrackUiForTrack(otherTdb->track), otherTdb->track, cartSidUrlString(cart), otherTdb->shortLabel); puts(": "); puts(why); } } puts("
\n"); } sqlFreeResult(&sr); hFreeConn(&conn); }