546e4b62f9c8abdda3576ce5b9bf8c4b82dc6b4e braney Tue Mar 21 14:42:01 2023 -0700 make squishyPack work nicely with Javascript track reorder diff --git src/hg/hgTracks/imageV2.c src/hg/hgTracks/imageV2.c index 8fdbdb6..cdfd9f2 100644 --- src/hg/hgTracks/imageV2.c +++ src/hg/hgTracks/imageV2.c @@ -21,60 +21,67 @@ struct imgBox *theImgBox = NULL; // Make this global for now to avoid huge rewrite struct imgTrack *curImgTrack = NULL; // Make this global for now to avoid huge rewrite ///////////////////////// // FLAT TRACKS // A simplistic way of flattening the track list before building the image // NOTE: Strategy is NOT to use imgBox->imgTracks, since this should be independednt of imageV2 ///////////////////////// void flatTracksAdd(struct flatTracks **flatTracks,struct track *track,struct cart *cart, struct slName *orderedWiggles) // Adds one track into the flatTracks list { struct flatTracks *flatTrack; AllocVar(flatTrack); flatTrack->track = track; char var[256]; // The whole reason to do this is to reorder tracks/subtracks in the image! +if (track->originalTrack != NULL) + safef(var,sizeof(var),"%s_%s",track->originalTrack,IMG_ORDER_VAR); +else safef(var,sizeof(var),"%s_%s",track->tdb->track,IMG_ORDER_VAR); flatTrack->order = cartUsualInt(cart, var,IMG_ANYORDER); if (flatTrack->order >= IMG_ORDERTOP) { cartRemove(cart,var); flatTrack->order = IMG_ANYORDER; } static int topOrder = IMG_ORDERTOP; // keep track of the order added to top of image static int lastOrder = IMG_ORDEREND; // keep track of the order added and beyond end if ( flatTrack->order == IMG_ANYORDER) { int index; if (track->customTrack) flatTrack->order = ++topOrder; // Custom tracks go to top else if ((orderedWiggles != NULL) && ((index = slNameFindIx(orderedWiggles, track->track)) != -1)) flatTrack->order = topOrder + index + 1; else flatTrack->order = ++lastOrder; } slAddHead(flatTracks,flatTrack); } int flatTracksCmp(const void *va, const void *vb) // Compare to sort on flatTrack->order { const struct flatTracks *a = *((struct flatTracks **)va); const struct flatTracks *b = *((struct flatTracks **)vb); if (a->order == b->order) + { + if ((a->track->originalTrack != NULL) || (b->track->originalTrack != NULL)) + return a->track->visibility - b->track->visibility; return tgCmpPriority(&(a->track),&(b->track)); + } return (a->order - b->order); } void flatTracksSort(struct flatTracks **flatTracks) // This routine sorts the imgTracks then forces tight ordering, so new tracks wil go to the end { // flatTracks list has 2 sets of "order": those already dragReordered (below IMG_ORDERTOP) // and those not yet reordered (above). Within those not yet dragReordered are 2 sets: // Those that begin numbering at IMG_ORDERTOP and those that begin at IMG_ORDEREND. // This routine must determine if there are any already dragOrdered, and if so, position the // newcomers in place. Newly appearing customTracks will appear at top, while newly appearing // standard tracks appear at the end of the image. int haveBeenOrderd = 0, imgOrdHighest=0; // Keep track of reordered count and position int notYetOrdered = 0, toBeTopHighest=0; // Keep track of those to be reordered, and top ordered @@ -985,30 +992,32 @@ } return imgTrack; } void imgTrackMarkForAjaxRetrieval(struct imgTrack *imgTrack,boolean ajaxRetrieval) // Updates the imgTrack to trigger an ajax callback from the html client to get this track { imgTrack->ajaxRetrieval = ajaxRetrieval; } int imgTrackOrderCmp(const void *va, const void *vb) // Compare to sort on imgTrack->order { const struct imgTrack *a = *((struct imgTrack **)va); const struct imgTrack *b = *((struct imgTrack **)vb); +if (a->order == b->order) + return a->vis - b->vis; return (a->order - b->order); } struct imgSlice *imgTrackSliceAdd(struct imgTrack *imgTrack,enum sliceType type, struct image *img, char *title,int width,int height,int offsetX,int offsetY) // Adds slices to an image track. Expected are types: stData, stButton, stSide and stCenter { struct imgSlice *slice = sliceCreate(type,img,title,width,height,offsetX,offsetY); if (slice) slAddHead(&(imgTrack->slices),slice); return imgTrack->slices; //slAddTail(&(imgTrack->slices),slice); //return slice; } @@ -1966,30 +1975,62 @@ } else hPrintf(" TITLE='Click for: 
%s'", attributeEncode(slice->title) ); } hPrintf(">\n" ); } imageDraw(imgBox,imgTrack,slice,name,offsetX,offsetY,useMap); if (slice->link != NULL) hPrintf("</A>"); if (slice->parentImg) hPrintf("</div>"); } +struct imgTrack *smashSquish(struct imgTrack *imgTrackList) +/* Javascript doesn't know about our trick to do squishyPack so we need to pass it a single div instead of two. + * We assume that the linked track immediately follows the original track in the sorted list. */ +{ +struct imgTrack *nextImg, *imgTrack; + +for (imgTrack = imgTrackList; imgTrack!=NULL;imgTrack = nextImg) + { + nextImg = imgTrack->next; + boolean joinNext = ((nextImg != NULL) && nextImg->linked); + + if (joinNext) // Smash these together + { + struct imgSlice *packedSlices = imgTrack->slices; + struct imgSlice *squishSlices = imgTrack->next->slices; + for(; packedSlices; packedSlices = packedSlices->next, squishSlices = squishSlices->next) + { + if (packedSlices->type != stCenter) + { + if ((packedSlices->map != NULL) && (squishSlices->map != NULL)) + packedSlices->map->items = slCat(packedSlices->map->items, squishSlices->map->items); + packedSlices->height += squishSlices->height; + } + } + imgTrack->next = nextImg->next; + nextImg = nextImg->next; + } + } + +return imgTrackList; +} + void imageBoxDraw(struct imgBox *imgBox) // writes a entire imgBox including all tracksas HTML { if (imgBox->imgTracks == NULL) // Not an error to have an empty image return; imgBoxDropEmpties(imgBox); boolean verbose = (hIsPrivateHost()); // Warnings for hgwdev only if (!imgBoxIsComplete(imgBox,verbose)) // dorps empties as okay return; char name[256]; imgBoxTracksNormalizeOrder(imgBox); //if (verbose) // imgBoxShow(NULL,imgBox,0); @@ -2032,31 +2073,31 @@ jsonObjectAdd(jsonForClient,"imgBoxPortalOffsetX", newJsonNumber( (long)((imgBox->portalStart - imgBox->chromStart) / imgBox->basesPerPixel))); jsonObjectAdd(jsonForClient,"imgBoxBasesPerPixel", newJsonDouble(imgBox->basesPerPixel)); } else jsonObjectAdd(jsonForClient,"imgBoxPortal", newJsonBoolean(FALSE)); hPrintf("<TABLE id='imgTbl' cellspacing='0' cellpadding='0'"); hPrintf(" width='%d'",imgBox->showPortal?(imgBox->portalWidth+imgBox->sideLabelWidth):imgBox->width); hPrintf(" class='tableWithDragAndDrop'>\n"); struct jsonElement *jsonTdbVars = newJsonObject(newHash(8)); jsonTdbSettingsInit(jsonTdbVars); char *newLine = NEWLINE_TO_USE(cgiClientBrowser(NULL,NULL,NULL)); -struct imgTrack *imgTrack = imgBox->imgTracks; +struct imgTrack *imgTrack = smashSquish(imgBox->imgTracks); for (;imgTrack!=NULL;imgTrack=imgTrack->next) { char *trackName = (imgTrack->name != NULL ? imgTrack->name : imgTrack->tdb->track ); struct track *track = hashFindVal(trackHash, trackName); if (track) jsonTdbSettingsBuild(jsonTdbVars, track, TRUE); hPrintf("<TR id='tr_%s' abbr='%d' class='imgOrd%s%s%s'>\n",trackName,imgTrack->order, (imgTrack->reorderable ? " trDraggable" : " nodrop nodrag"), (imgTrack->centerLabelSeen != clAlways ? " clOpt" : ""), (imgTrack->ajaxRetrieval ? " mustRetrieve" : "")); if (imgBox->showSideLabel && imgBox->plusStrand) { // button safef(name, sizeof(name), "btn_%s", trackName);