06d7be056190c14b85e71bc12523f18ea6815b5e markd Mon Dec 7 00:50:29 2020 -0800 BLAT mmap index support merge with master diff --git src/hg/hgTracks/hgTracks.c src/hg/hgTracks/hgTracks.c index b47b461..1eea6ae 100644 --- src/hg/hgTracks/hgTracks.c +++ src/hg/hgTracks/hgTracks.c @@ -61,30 +61,31 @@ #include "errCatch.h" #include "iupac.h" #include "botDelay.h" #include "chromInfo.h" #include "extTools.h" #include "basicBed.h" #include "customFactory.h" #include "genbank.h" #include "bigWarn.h" #include "wigCommon.h" #include "knetUdc.h" #include "hex.h" #include <openssl/sha.h> #include "customComposite.h" #include "chromAlias.h" +#include "jsonWrite.h" //#include "bed3Sources.h" /* Other than submit and Submit all these vars should start with hgt. * to avoid weeding things out of other program's namespaces. * Because the browser is a central program, most of its cart * variables are not hgt. qualified. It's a good idea if other * program's unique variables be qualified with a prefix though. */ char *excludeVars[] = { "submit", "Submit", "dirty", "hgt.reset", "hgt.in1", "hgt.in2", "hgt.in3", "hgt.inBase", "hgt.out1", "hgt.out2", "hgt.out3", "hgt.out4", "hgt.left1", "hgt.left2", "hgt.left3", "hgt.right1", "hgt.right2", "hgt.right3", "hgt.dinkLL", "hgt.dinkLR", "hgt.dinkRL", "hgt.dinkRR", "hgt.tui", "hgt.hideAll", "hgt.visAllFromCt", @@ -148,30 +149,40 @@ boolean hideControls = FALSE; /* Hide all controls? */ boolean trackImgOnly = FALSE; /* caller wants just the track image and track table html */ boolean ideogramToo = FALSE; /* caller wants the ideoGram (when requesting just one track) */ /* Structure returned from resolvePosition. * We use this to to expand any tracks to full * that were found to contain the searched-upon * position string */ struct hgPositions *hgp = NULL; /* Other global variables. */ struct group *groupList = NULL; /* List of all tracks. */ char *browserName; /* Test, preview, or public browser */ char *organization; /* UCSC */ +/* mouseOver popUp global data, each track that wants to send json + * data will need to know the json file name from mouseOverJson + * and will write the track data to mouseOverJson. The structure + * of the data in the json output will depend upon what the track needs + * to send. + */ +boolean enableMouseOver = FALSE; +struct tempName *mouseOverJsonFile = NULL; +struct jsonWrite *mouseOverJson = NULL; + struct hash *trackHash = NULL; /* Hash of the tracks by their name. */ #ifdef DEBUG void uglySnoopTrackList(int depth, struct track *trackList) /* Print out some info on track list. */ { struct track *track; for (track = trackList; track != NULL; track = track->next) { if (stringIn("FaireH1h", track->track)) { repeatCharOut(uglyOut, '+', depth); } uglySnoopTrackList(depth+1, track->subtracks); } @@ -620,30 +631,33 @@ cytoband track where the starts and ends of two bands overlaps by one. */ if (winEnd > cb->chromStart && winEnd <= cb->chromEnd) { safef(endBand, buffSize, "%s", cb->name); } } } static void maybeNewFonts(struct hvGfx *hvg) /* Check to see if we want to use the alternate font engine (FreeType2). */ { if (sameString(cfgOptionDefault("freeType", "off"), "on")) { + if (sameString(tl.textFont, "Bitmap")) + return; + char *fontDir = cfgOptionDefault("freeTypeDir", "/usr/share/fonts/default/Type1"); char buffer[4096]; extern char *freeTypeFontNames[]; extern char *freeTypeFontFiles[]; int ii; for(ii=0; ii < 33; ii++) if (sameString(freeTypeFontNames[ii], tl.textFont)) break; char *fontFile = freeTypeFontFiles[ii]; char *fontName = freeTypeFontNames[ii]; safef(buffer, sizeof buffer, "%s/%s", fontDir, fontFile); hvGfxSetFontMethod(hvg, FONT_METHOD_FREETYPE, fontName, buffer ); } } @@ -5029,30 +5043,49 @@ imagePixelHeight = pixHeight; if (psOutput) { hvg = hvGfxOpenPostScript(pixWidth, pixHeight, psOutput); hvgSide = hvg; // Always only one image } else { boolean transparentImage = FALSE; if (theImgBox!=NULL) transparentImage = TRUE; // transparent because BG (blue ruler lines) is separate image if (measureTiming) measureTime("Time at start of obtaining trash hgt png image file"); trashDirFile(&pngTn, "hgt", "hgt", ".png"); + if (enableMouseOver) + { /* created here at this time to get the same name as .png file + * it is copied from pngTn since if we repeated trashFileDir() + * to get the name, it could be different since there is a + * timestamp involved in making the name. + */ + /* will open this file upon successful exit to write the data */ + AllocVar(mouseOverJsonFile); + char *tmpStr = cloneString(pngTn.forCgi); + char *jsonStr = replaceChars(tmpStr, ".png", ".json"); + safef(mouseOverJsonFile->forCgi, ArraySize(mouseOverJsonFile->forCgi), "%s", jsonStr); + freeMem(tmpStr); + freeMem(jsonStr); + tmpStr = cloneString(pngTn.forHtml); + jsonStr = replaceChars(tmpStr, ".png", ".json"); + safef(mouseOverJsonFile->forHtml, ArraySize(mouseOverJsonFile->forHtml), "%s", jsonStr); + freeMem(tmpStr); + freeMem(jsonStr); + } hvg = hvGfxOpenPng(pixWidth, pixHeight, pngTn.forCgi, transparentImage); if (theImgBox) { // Adds one single image for all tracks (COULD: build the track by track images) theOneImg = imgBoxImageAdd(theImgBox,pngTn.forHtml,NULL,pixWidth, pixHeight,FALSE); theSideImg = theOneImg; // Unlkess this is overwritten below, there is a single image } hvgSide = hvg; // Unless this is overwritten below, there is a single image if (theImgBox && theImgBox->showPortal && withLeftLabels) { // TODO: It would be great to make the two images smaller, // but keeping both the same full size for now @@ -6950,30 +6983,44 @@ if (cartOptionalString(cart, "hgt.trackNameFilter") == NULL) { // If a single track was asked for and it is from a hub, then it is already in trackList loadTrackHubs(&trackList, &grpList); } loadCustomTracks(&trackList); groupTracks( &trackList, pGroupList, grpList, vis); setSearchedTrackToPackOrFull(trackList); boolean hideTracks = cgiOptionalString( "hideTracks") != NULL; if (hideTracks) changeTrackVis(groupList, NULL, tvHide); // set all top-level tracks to hide /* Get visibility values if any from ui. */ struct hash *superTrackHash = newHash(5); // cache whether supertrack is hiding tracks or not char buffer[4096]; +// Check to see if we have a versioned default gene track and let the knownGene +// cart variable determine its visibility +char *defaultGeneTrack = NULL; +char *knownDb = hdbDefaultKnownDb(database); +if (differentString(knownDb, database)) + defaultGeneTrack = hdbGetMasterGeneTrack(knownDb); + +if (defaultGeneTrack) + { + char *s = cartOptionalString(cart, "knownGene"); + if ((s != NULL) && (differentString(s, "hide"))) + cartSetString(cart, defaultGeneTrack, s); + } + for (track = trackList; track != NULL; track = track->next) { // deal with any supertracks we're seeing for the first time if (tdbIsSuperTrackChild(track->tdb)) { struct hashEl *hel = NULL; if ((hel = hashLookup(superTrackHash, track->tdb->parent->track)) == NULL) // we haven't seen this guy { // first deal with visibility of super track char *s = hideTracks ? cgiOptionalString(track->tdb->parent->track) : cartOptionalString(cart, track->tdb->parent->track); if (s) { track->tdb->parent->visibility = hTvFromString(s) ; cartSetString(cart, track->tdb->parent->track, s); @@ -8664,30 +8711,34 @@ { // TODO should be more than this. But at least this makes the same trackList mods to the other windows. if (nukeIdeoFromList) { struct track *ideoTrack = chromIdeoTrack(window->trackList); if (ideoTrack) { slRemoveEl(&window->trackList, ideoTrack); } } } } setGlobalsFromWindow(windows); // first window // restore globals +/* DBG - a message box to display information from the javascript +hPrintf("<div id='mouseDbg'><span id='dbgMouseOver'><p>. . . dbgMouseOver</p></span></div>\n"); + */ + #ifdef USE_NAVIGATION_LINKS hPrintf("<TABLE BORDER=0 CELLPADDING=0 width='%d'><tr style='font-size:small;'>\n", tl.picWidth);//min(tl.picWidth, 800)); hPrintf("<td width='40' align='left'><a href='?hgt.left3=1' " "title='move 95% to the left'><<<</a>\n"); hPrintf("<td width='30' align='left'><a href='?hgt.left2=1' " "title='move 47.5% to the left'><<</a>\n"); hPrintf("<td width='20' align='left'><a href='?hgt.left1=1' " "title='move 10% to the left'><</a>\n"); hPrintf("<td> </td>\n"); // Without width cell expands table with, forcing others to sides hPrintf("<td width='40' align='left'><a href='?hgt.in1=1' " "title='zoom in 1.5x'>> <</a>\n"); hPrintf("<td width='60' align='left'><a href='?hgt.in2=1' " "title='zoom in 3x'>>> <<</a>\n"); @@ -8740,31 +8791,31 @@ hPrintf("<TABLE BORDER=0 CELLSPACING=1 CELLPADDING=1 WIDTH=%d COLS=%d><TR>\n", tl.picWidth, 27); #ifndef USE_NAVIGATION_LINKS hPrintf("<TD COLSPAN=6 ALIGN=left NOWRAP>"); hPrintf("move start<BR>"); hButtonWithOnClick("hgt.dinkLL", " < ", "move start position to the left", "return imageV2.navigateButtonClick(this);"); hTextVar("dinkL", cartUsualString(cart, "dinkL", "2.0"), 3); hButtonWithOnClick("hgt.dinkLR", " > ", "move start position to the right", "return imageV2.navigateButtonClick(this);"); hPrintf("</TD>"); hPrintf("<td width='30'> </td>\n"); #endif//ndef USE_NAVIGATION_LINKS hPrintf("<TD class='infoText' COLSPAN=15 style=\"white-space:normal\">"); // allow this text to wrap hWrites("Click on a feature for details. "); - hWrites("Click or drag in the base position track to zoom in. "); + hWrites("Click+shift+drag to zoom in. "); hWrites("Click side bars for track options. "); hWrites("Drag side bars or labels up or down to reorder tracks. "); hWrites("Drag tracks left or right to new position. "); hWrites("Press \"?\" for keyboard shortcuts. "); hPrintf("</TD>"); #ifndef USE_NAVIGATION_LINKS hPrintf("<td width='30'> </td>\n"); hPrintf("<TD COLSPAN=6 ALIGN=right NOWRAP>"); hPrintf("move end<BR>"); hButtonWithOnClick("hgt.dinkRL", " < ", "move end position to the left", "return imageV2.navigateButtonClick(this);"); hTextVar("dinkR", cartUsualString(cart, "dinkR", "2.0"), 3); hButtonWithOnClick("hgt.dinkRR", " > ", "move end position to the right", "return imageV2.navigateButtonClick(this);"); hPrintf("</TD>"); @@ -9794,30 +9845,31 @@ if (virtWinEnd > virtSeqBaseCount) { virtWinEnd = virtSeqBaseCount; } if (virtWinStart > virtSeqBaseCount) { virtWinStart = virtSeqBaseCount - 1000; } virtWinBaseCount = virtWinEnd - virtWinStart; if (virtWinBaseCount <= 0) hUserAbort("Window out of range on %s", virtChromName); + if (!cartUsualBoolean(cart, "hgt.psOutput", FALSE) && !cartUsualBoolean(cart, "hgt.imageV1" , FALSE)) { // TODO GALT Guidelines broken on virtChrom for 3X. // works in demo0 or real chrom. Only the guidelines seem to be messed up. // Other stuff works. 1X works too. // Since we are not using 3X for now, I will leave this for a future fix. // To test 3X, do make clean; make CFLAGS=-DIMAGEv2_DRAG_SCROLL_SZ=3 // Start an imagebox (global for now to avoid huge rewrite of hgTracks) // Set up imgBox dimensions int sideSliceWidth = 0; // Just being explicit if (withLeftLabels) sideSliceWidth = (fullInsideX - gfxBorder*3) + 2; @@ -10522,30 +10574,47 @@ cartSetString(cart, "highlight", newHighlight); cartRemove(cart, "addHighlight"); } } extern boolean issueBotWarning; void doMiddle(struct cart *theCart) /* Print the body of an html file. */ { cart = theCart; measureTiming = hPrintStatus() && isNotEmpty(cartOptionalString(cart, "measureTiming")); if (measureTiming) measureTime("Startup (bottleneck %d ms) ", botDelayMillis); +char *mouseOverEnabled = cfgOption("mouseOverEnabled"); +if (sameWordOk(mouseOverEnabled, "on")) + { + enableMouseOver = TRUE; + /* mouseOverJsonFile will be initializes and created at the same + * time as the browser .png image file + */ + mouseOverJson = jsonWriteNew(); + jsonWriteObjectStart(mouseOverJson, NULL); + /* this jsonWrite structure will finish off upon successful exit. + * each track will start a list with the track name: + * jsonWriteListStart(mouseOverJson, tg->track); + */ + } +else + enableMouseOver = FALSE; + if (issueBotWarning) { char *ip = getenv("REMOTE_ADDR"); botDelayMessage(ip, botDelayMillis); } char *debugTmp = NULL; /* Uncomment this to see parameters for debugging. */ /* struct dyString *state = NULL; */ /* Initialize layout and database. */ if (measureTiming) measureTime("Get cart of %d for user:%s session:%s", theCart->hash->elCount, theCart->userId, theCart->sessionId); /* #if 1 this to see parameters for debugging. */ /* Be careful though, it breaks if custom track @@ -10612,55 +10681,57 @@ jsIncludeFile("jquery-ui.js", NULL); jsIncludeFile("utils.js", NULL); jsIncludeFile("ajax.js", NULL); jsIncludeFile("jquery.watermarkinput.js", NULL); if(!searching) { jsIncludeFile("jquery.history.js", NULL); jsIncludeFile("jquery.imgareaselect.js", NULL); } jsIncludeFile("autocomplete.js", NULL); jsIncludeFile("es5-shim.4.0.3.min.js", NULL); jsIncludeFile("es5-sham.4.0.3.min.js", NULL); jsIncludeFile("lodash.3.10.0.compat.min.js", NULL); jsIncludeFile("autocompleteCat.js", NULL); jsIncludeFile("hgTracks.js", NULL); -// jsIncludeFile("mouseOver.js", NULL); jsIncludeFile("spectrum.min.js", NULL); #ifdef LOWELAB jsIncludeFile("lowetooltip.js", NULL); #endif///def LOWELAB webIncludeResourceFile("spectrum.min.css"); webIncludeResourceFile("jquery-ui.css"); -// webIncludeResourceFile("mouseOver.css"); + if (enableMouseOver) + webIncludeResourceFile("mouseOver.css"); + if (!searching) // NOT doing search { webIncludeResourceFile("jquery.contextmenu.css"); jsIncludeFile("jquery.contextmenu.js", NULL); webIncludeResourceFile("ui.dropdownchecklist.css"); jsIncludeFile("ui.dropdownchecklist.js", NULL); jsIncludeFile("ddcl.js", NULL); } hPrintf("<div id='hgTrackUiDialog' style='display: none'></div>\n"); hPrintf("<div id='hgTracksDialog' style='display: none'></div>\n"); cartFlushHubWarnings(); } + if (cartVarExists(cart, "chromInfoPage")) { cartRemove(cart, "chromInfoPage"); chromInfoPage(); } else if (differentString(cartUsualString(cart, TRACK_SEARCH,"0"),"0")) { doSearchTracks(groupList); } else if (sameWord(configPageCall, "configure") || sameWord(configPageCall, "configure tracks and display")) { cartRemove(cart, "hgTracksConfigPage"); configPage(); } @@ -10733,30 +10804,54 @@ jsonObjectAdd(jsonForClient, "measureTiming", newJsonBoolean(measureTiming)); // js code needs to know if a highlightRegion is defined for this db checkAddHighlight(); // call again in case tracksDisplay's call to resolvePosition changed vars char *highlightDef = cartOptionalString(cart, "highlight"); if (highlightDef) jsonObjectAdd(jsonForClient, "highlight", newJsonString(highlightDef)); jsonObjectAdd(jsonForClient, "enableHighlightingDialog", newJsonBoolean(cartUsualBoolean(cart, "enableHighlightingDialog", TRUE))); struct dyString *dy = dyStringNew(1024); jsonDyStringPrint(dy, (struct jsonElement *) jsonForClient, "hgTracks", 0); jsInline(dy->string); dyStringFree(&dy); +dy = dyStringNew(1024); +if (enableMouseOver) + { + jsonWriteObjectEnd(mouseOverJson); + /* if any data was written, it is longer than 4 bytes */ + if (strlen(mouseOverJson->dy->string) > 4) + { + FILE *trashJson = mustOpen(mouseOverJsonFile->forCgi, "w"); + fputs(mouseOverJson->dy->string,trashJson); + carefulClose(&trashJson); + } + + hPrintf("<div id='mouseOverVerticalLine' class='mouseOverVerticalLine'></div>\n"); + hPrintf("<div id='mouseOverText' class='mouseOverText'></div>\n"); + dyStringPrintf(dy, "window.browserTextSize=%s;\n", tl.textSize); + dyStringPrintf(dy, "window.mouseOverEnabled=true;\n"); + } +else + { + dyStringPrintf(dy, "window.mouseOverEnabled=false;\n"); + } +jsInline(dy->string); +dyStringFree(&dy); + if (measureTiming) measureTime("Time at end of doMiddle, next up cart write"); if (cartOptionalString(cart, "udcTimeout")) { warn("The Genome Browser cart currently includes the \"udcTimeout\" string. " "While this is useful for debugging hubs, it may negatively impact " "performance. To clear this variable, click " "<A HREF='hgTracks?hgsid=%s|url|&udcTimeout=[]'>here</A>.",cartSessionId(cart)); } } void labelTrackAsFilteredNumber(struct track *tg, unsigned numOut) /* add text to track long label to indicate filter is active */ {