546e4b62f9c8abdda3576ce5b9bf8c4b82dc6b4e
braney
  Tue Mar 21 14:42:01 2023 -0700
make squishyPack work nicely with Javascript track reorder

diff --git src/hg/hgTracks/imageV2.h src/hg/hgTracks/imageV2.h
index 0907ad6..292fe4b 100644
--- src/hg/hgTracks/imageV2.h
+++ src/hg/hgTracks/imageV2.h
@@ -1,472 +1,473 @@
 // imageV2 - API for creating the image V2 features.
 
 /* Copyright (C) 2014 The Regents of the University of California 
  * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */
 
 #ifndef IMAGEV2_H
 #define IMAGEV2_H
 
 // DRAG_SCROLL means dragging the image left-right to reposition the viewing window on the chrom.
 // NOTE: 1x works fine and is released. Set IMAGEv2_DRAG_SCROLL_SZ > 1 (3=3x)
 //       to see hidden image while dragging.
 #ifndef IMAGEv2_DRAG_SCROLL_SZ
 #define IMAGEv2_DRAG_SCROLL_SZ 1
 #endif
 
 #if defined(IMAGEv2_DRAG_SCROLL_SZ) && (IMAGEv2_DRAG_SCROLL_SZ > 1)
     #define IMAGEv2_SHORT_MAPITEMS
     //#define IMAGEv2_SHORT_TOGGLE
     //#define IMAGEv2_NO_LEFTLABEL_ON_FULL
     // Because the sideLabel clipping will leave a no longer needed label
     // aligned with the centerLabel, we will need to either: remove sideLabels
     // (which otherwise work) OR add a new side-slice to match the centerlabel
 #endif //defined(IMAGEv2_DRAG_SCROLL_SZ) && (IMAGEv2_DRAG_SCROLL_SZ > 1)
 
 // CURRENT PROBLEMS with dragScroll > 1X:
 // o Dynamic height for data/label based on image map currently works EXCEPT,
 //   occasionally does not resize.  Consider resize while dragging!
 // o next item feature '>>' arrows should check if items are in the wings
 // o next exon feature '>>' arrows are only seen in the wings and only look beyond the wings
 
 // UNCOMMENT  USE_NAVIGATION_LINKS for so far experimental UI changes to replace buttons at top
 // with more streamlined links
 //#define USE_NAVIGATION_LINKS
 
 extern struct imgBox   *theImgBox;   // Make this global for now to avoid huge rewrite
 extern struct imgTrack *curImgTrack; // 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 independent of imageV2
 //       These should probably be moved to hgTracks.h
 /////////////////////////
 struct flatTracks // List of tracks in image, flattened to promote subtracks
     {
     struct flatTracks *next;   // Next on list.
     struct track *track;       // Track (the track list is still heirarchical
     int order;                 // Image order: This keeps track of dragReorder
     int maxHeight;             // largest height among all windows in image.
     };
 
 void flatTracksAdd(struct flatTracks **flatTracks,struct track *track,struct cart *cart, struct slName *orderedWiggles);
 // Adds one track into the flatTracks list
 
 int flatTracksCmp(const void *va, const void *vb);
 // Compare to sort on flatTrack->order
 
 void flatTracksSort(struct flatTracks **flatTracks);
 // This routine sorts the imgTracks then forces tight ordering, so new tracks wil go to the end
 
 void flatTracksFree(struct flatTracks **flatTracks);
 // Frees all memory used to support flatTracks (underlying tracks are untouched)
 
 /////////////////////////
 // JSON support.  Eventually the whole imgTbl could be written out as JSON
 void jsonTdbSettingsBuild(struct jsonElement *settings, struct track *track, boolean configurable);
 
 // Creates then successively adds trackDb settings to the jsonTdbSettingsString
 // Initially pass in NULL pointer to a dyString to properly begin building
 
 void jsonTdbSettingsUse(struct jsonElement *settings);
 // Closes and returns the contents of the jsonTdbSettingsString
 
 /////////////////////////
 // IMAGEv2
 // The new way to do images
 // Terms:
 // "image box": The new version of the image on the html page.  It is a table with rows that
 //              contain tracks which are made up of parts of images.
 //    "imgBox": This C struct contains all information to render the image box on the html page.
 //    "imgTbl": The HTML structure that contains individual track images.
 //              The javascript client controls the imgTbl.
 //              Thus cgi knows imgBox while html/js knows imgTbl.
 // "image": A single png.  An image may contain mutilple tracks.
 //          Even as a single track and image may contain a data image, centerLabel, sideLabel and button.
 // "map": (or "mapSet") The image map for providing links to items in a data image.
 //        An image and map are a 1 to 1 pair and pixel coordinates are always image relative.
 // "slice": (or "imgSlice") The cgi concept of the portion of an image that is sent to the
 //          html/js side.  If we are sending a 3X sized image, the "slice" spans the entire 3X.
 //          Almost always a subset of an image, but possibly the whole image.
 //          Even if the image is of a single track, it will still be cut into data image,
 //          sideLabel and centerLabel slices.
 // "sliceMap": The portion of a map that belongs to a slice. The pixel coordinates are always
 //             image relative, not slice relative.
 // "portal": (or "imgPortal") The html/js concept of the portion of a data slice that is visible in
 //          the browser. Thus, if we are sending a 3X sized data image slice, the "portal" seen
 //          in the browser spans only 1X.
 // "imgTrack": (or track image) The cgi side whole shabang for rendering one track.  It contains
 //             track specific information and four slices: data, centerLabel, sideLabel and button
 //             The imgBox contains N imgTracks.  Typically an ajax/JSON request gets a single
 //             imgTrack returned, which then is updated in the imgTbl containing multiple tracks.
 // image box support: This can contain all the support variables that are global to the image box
 //                    (like font size, box width, etc.).  At this point, lets not talk structure
 //                    or cgi vs. html/js but leave this container as a concept that we know
 //                    needs filling.
 // imgBox is the top level and contains all info to draw the image in HTML
 //    - contains slList of all imgTrack structs shown
 // imgTrack contains all info to display one track/subtrack in the imgBox
 //    - contains 4 imgSlice structs (data, centerLabel, sideLabel, button)
 // imgSlice contains all info to display a portion of an image file
 //    - contains 1 image struct
 // image contains all information about an image file and associated map box
 /////////////////////////
 
 /////////////////////// Maps
 struct mapItem // IMAGEv2: single map item in an image map.
     {
     struct mapItem *next;     // slList
     char *linkVar;            // the get variables associated with the map link
     char *title;              // item title
     int topLeftX;             // in pixels relative to image
     int topLeftY;             // in pixels relative to image
     int bottomRightX;         // in pixels relative to image
     int bottomRightY;         // in pixels relative to image
     char *id;                 // id; used by js right-click code to figure out what to do with
                               //     a map item (usually mapName)
     };
 
 struct mapSet // IMAGEv2: full map for image OR partial map for slice
     {
     char *name;               // to point an image to a map in HTML
     struct image *parentImg;  // points to the image this map belongs to
     char *linkRoot;           // the common or static portion of the link for the entire image
     struct mapItem *items;    // list of items
     };
 
 // To create map items which have mouse-over titles but no link, fill link with:
 #define TITLE_BUT_NO_LINK "noLink"
 
 struct mapSet *mapSetStart(char *name,struct image *img,char *linkRoot);
 // Starts a map (aka mapSet) which is the seet of links and image locations used in HTML.
 // Complete a map by adding items with mapItemAdd()
 
 struct mapSet *mapSetUpdate(struct mapSet *map,char *name,struct image *img,char *linkRoot);
 // Updates an existing map (aka mapSet)
 
 struct mapItem *mapSetItemFind(struct mapSet *map,int topLeftX,int topLeftY,
                                int bottomRightX,int bottomRightY);
 // Find a single mapItem based upon coordinates (within a pixel)
 
 struct mapItem *mapSetItemUpdate(struct mapSet *map,struct mapItem *item,char *link,char *title,
                                  int topLeftX,int topLeftY,int bottomRightX,int bottomRightY,
                                  char *id);
 // Update an already existing mapItem
 
 struct mapItem *mapSetItemAdd(struct mapSet *map,char *link,char *title,int topLeftX,int topLeftY,
                               int bottomRightX,int bottomRightY, char *id);
 // Add a single mapItem to a growing mapSet
 
 struct mapItem *mapSetItemUpdateOrAdd(struct mapSet *map,char *link,char *title,
                                       int topLeftX,int topLeftY,int bottomRightX,int bottomRightY,
                                       char *id);
 // Update or add a single mapItem
 
 struct mapItem *mapSetItemFindOrAdd(struct mapSet *map,char *link,char *title,
                                     int topLeftX,int topLeftY,int bottomRightX,int bottomRightY,
                                     char *id);
 // Finds or adds the map item
 
 void mapItemFree(struct mapItem **pItem);
 // frees all memory assocated with a single mapItem
 
 boolean mapItemConsistentWithImage(struct mapItem *item,struct image *img,boolean verbose);
 // Test whether a map item is consistent with the image it is supposed to be for
 
 boolean mapSetIsComplete(struct mapSet *map,boolean verbose);
 // Tests the completeness and consistency of this map (mapSet)
 
 void mapSetFree(struct mapSet **pMap);
 // frees all memory (including items) assocated with a single mapSet
 
 
 
 /////////////////////// Images
 struct image // IMAGEv2: single image which may have multiple imgSlices focused on it
     {
     struct image *next;       // slList (Not yet used)
     char *file;               // name of file that hold the image
     char *title;              // image wide title
     int  width;               // in pixels
     int  height;              // in pixels
     struct mapSet *map;       // map assocated with this image (may be NULL)
     };
 
 struct image *imgCreate(char *png,char *title,int width,int height);
 // Creates a single image container.
 // A map map be added with imgMapStart(),mapSetItemAdd()
 
 struct mapSet *imgMapStart(struct image *img,char *name,char *linkRoot);
 // Starts a map associated with an image.
 // Map items can then be added to the returned pointer with mapSetItemAdd()
 
 struct mapSet *imgGetMap(struct image *img);
 // Gets the map associated with this image.
 // Map items can then be added to the map with mapSetItemAdd()
 
 void imgFree(struct image **pImg);
 // frees all memory assocated with an image (including a map)
 
 
 
 /////////////////////// Slices
 enum sliceType
     {
     stUnknown=0,              // Invalid
     stData=1,                 // Data or track slice of an image
     stCenter=2,               // Top or centerLabel slice of an image
     stButton=3,               // Config button (by separating from side label, can have
                               // separate image which is colored/zipped by javascript)
     stSide=4,                 // Side or leftLabel slice of an image
     stInvalid=5               // Invalid
     };
 #define stMaxSliceTypes stInvalid
 
 struct imgSlice // IMAGEv2: the portion of an image that is displayable for one track
     {
     struct imgSlice *next;    // slList
     enum sliceType type;      // Type of slice (currently only 3)
     struct image *parentImg;  // the actual image/png
     char *title;              // slice wide title
     struct mapSet *map;       // A slice specific map.  It contains a subset of the img->map.
                               // Coordinates must be img relative NOT slice relative!
     char *link;               // If a slice has no map, it may have a whole slice link
     int  width;               // in pixels (differs from img->width if img contains sideLabel)
     int  height;              // in pixels (differs from img->height if
                               //                   img contains centerLabel and/or multiple tracks)
     int  offsetX;             // offset from left (when img->width > slice->width)
     int  offsetY;             // offset from top (when img->height > slice->height)
     };
 
 struct imgSlice *sliceCreate(enum sliceType type,struct image *img,char *title,
                              int width,int height,int offsetX,int offsetY);
 // Creates of a slice which is a portion of an image.
 // A slice specific map map be added with sliceMapStart(),mapSetItemAdd()
 
 struct imgSlice *sliceUpdate(struct imgSlice *slice,enum sliceType type,struct image *img,
                              char *title,int width,int height,int offsetX,int offsetY);
 // updates an already created slice
 
 char *sliceTypeToString(enum sliceType type);
 // Translate enum slice type to string
 
 struct imgSlice *sliceAddLink(struct imgSlice *slice,char *link,char *title);
 // Adds a slice wide link.  The link and map are mutually exclusive
 
 struct mapSet *sliceMapStart(struct imgSlice *slice,char *name,char *linkRoot);
 // Adds a slice specific map to a slice of an image.
 // Map items can then be added to the returned pointer with mapSetItemAdd()
 
 struct mapSet *sliceGetMap(struct imgSlice *slice,boolean sliceSpecific);
 // Gets the map associate with a slice which may be sliceSpecific or it may belong to the
 // slices' image.  Map items can then be added to the map returned with mapSetItemAdd().
 
 struct mapSet *sliceMapFindOrStart(struct imgSlice *slice,char *name,char *linkRoot);
 // Finds the slice specific map or starts it
 
 struct mapSet *sliceMapUpdateOrStart(struct imgSlice *slice,char *name,char *linkRoot);
 // Updates the slice specific map or starts it
 
 boolean sliceIsConsistent(struct imgSlice *slice,boolean verbose);
 // Test whether the slice and it's associated image and map are consistent with each other
 
 void sliceFree(struct imgSlice **pSlice);
 // frees all memory assocated with a slice
 // (not including the image or a map belonging to the image)
 
 
 
 /////////////////////// imgTracks
 enum centerLabelSeen
     {
     clUnknown=0,              // Invalid
     clAlways=1,               // Default is always seen
     clNowSeen=2,              // Conditionally and currently seen
     clNotSeen=3               // Conditionally and currently unseen
     };
 
 struct imgTrack // IMAGEv2: imageBox contains list of displayed imageTracks
     {
     struct imgTrack *next;    // slList
     struct trackDb *tdb;      // trackDb entry (should this be struct track* entry?)
     char *name;	              // It is possible to have an imgTrack without a tdb,
                               //    but then it must have a name
     char *db;                 // Image for db (species) (assert imgTrack matches imgBox)
     char *chrom;              // Image for chrom (assert imgTrack matches imgBox)
     long  chromStart;          // Image start (absolute, not portal position)
     long  chromEnd;            // Image end (absolute, not portal position)
     boolean plusStrand;       // Image covers plus strand, not minus strand
     boolean hasCenterLabel;   // A track may have a center label but not show it
     enum centerLabelSeen centerLabelSeen;  // Conditionally displayed center labels are always
                                            // there but sometimes hidden
     boolean reorderable;      // Is this track reorderable (by drag and drop) ?
     boolean ajaxRetrieval;    // This track needs to be retrieved via ajax
     int order;                // Image order: This keeps track of dragReorder
     enum trackVisibility vis; // Current visibility of track image
     struct imgSlice *slices;  // Currently there should be four slices for every track:
                               //      data, centerLabel, sideLabel, button
+    boolean linked;           // is this track linked to another track (like squishyPack)
     };
 
 #define IMG_ANYORDER -2
 #define IMG_FIXEDPOS -1
 #define IMG_ORDERTOP  10000
 #define IMG_ORDEREND  20000
 #define IMG_ORDER_VAR "imgOrd"
 
 struct imgTrack *imgTrackStart(struct trackDb *tdb,char *name,char *db,
                                char *chrom, long chromStart, long chromEnd, boolean plusStrand,
                                boolean hasCenterLabel, enum trackVisibility vis, int order);
 // Starts an image track which will contain all image slices needed to render one track
 // Must completed by adding slices with imgTrackAddSlice()
 
 struct imgTrack *imgTrackUpdate(struct imgTrack *imgTrack,struct trackDb *tdb,char *name,
                                 char *db,char *chrom, long chromStart, long chromEnd, boolean plusStrand,
                                 boolean hasCenterLabel, enum trackVisibility vis, int order);
 // Updates an already existing image track
 
 void imgTrackMarkForAjaxRetrieval(struct imgTrack *imgTrack,boolean ajaxRetrieval);
 // Updates the imgTrack to trigger an ajax callback from the html client to get this track
 
 #define imgTrackMarkedForAjaxRetrieval(imgTrack) ((imgTrack)->ajaxRetrieval)
 // Is this imgTrack marked for Ajax retrieval
 
 #define imgTrackUpdateCenterLabelSeen(slice,seen) { (slice)->centerLabelSeen = (seen); }
 // Center slices are occasionally unseen
 
 int imgTrackOrderCmp(const void *va, const void *vb);
 // Compare to sort on label.
 
 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 *imgTrackSliceGetByType(struct imgTrack *imgTrack,enum sliceType type);
 // Gets a specific slice already added to an image track.
 // Expected are types: stData, stButton, stSide and stCenter
 
 struct imgSlice *imgTrackSliceFindOrAdd(struct imgTrack *imgTrack,enum sliceType type,
                                         struct image *img,char *title,int width,int height,
                                         int offsetX,int offsetY);
 // Find the slice or adds it
 
 struct imgSlice *imgTrackSliceUpdateOrAdd(struct imgTrack *imgTrack,enum sliceType type,
                                           struct image *img,char *title,int width,int height,
                                           int offsetX,int offsetY);
 // Updates the slice or adds it
 
 int imgTrackCoordinates(struct imgTrack *imgTrack, int *leftX,int *topY,int *rightX,int *bottomY);
 // Fills in topLeft x,y and bottomRight x,y coordinates, returning topY.
 #define imgTrackTopY(imgTrack) imgTrackCoordinates(imgTrack,NULL,NULL,NULL,NULL)
 // Returns the Y coordinate of the top of the track.
 
 int imgTrackBottomY(struct imgTrack *imgTrack);
 // Returns the Y coordinate of the bottom of the track.
 
 struct mapSet *imgTrackGetMapByType(struct imgTrack *imgTrack,enum sliceType type);
 // Gets the map assocated with a specific slice belonging to the imgTrack
 
 int imgTrackAddMapItem(struct imgTrack *imgTrack,char *link,char *title,int topLeftX,int topLeftY,
                        int bottomRightX,int bottomRightY, char *id);
 // Will add a map item it an imgTrack's appropriate slice's map
 // Since a map item may span slices, the imgTrack is in the best position to determine where
 // to put the map item.
 // Returns count of map items added, which could be 0, 1 or more than one if item spans slices
 // NOTE: Precedence is given to first map item when adding items with same coordinates!
 
 boolean imgTrackIsComplete(struct imgTrack *imgTrack,boolean verbose);
 // Tests the completeness and consistency of this imgTrack (including slices)
 
 void imgTrackFree(struct imgTrack **pImgTrack);
 // frees all memory assocated with an imgTrack (including slices)
 
 
 /////////////////////// Image Box
 struct imgBox // IMAGEv2: imageBox conatins all the definitions to draw an image in hgTracks
     {
     char *db;                 // database (species)
     char *chrom;              // chrom
     long  chromStart;          // Image start (absolute, not portal position)
     long  chromEnd;            // Image end (absolute, not portal position)
     boolean plusStrand;       // imgBox currently shows plus strand, not minus strand
     struct image *images;     // Contains all images for the imgBox. TEMPORARY: hgTracks creates
                               //    it's current one image and I'll store it here
     struct image *bgImg;      // When track images are transparent, bgImage contains blue lines
                               //    that are db coordinate granularity.
     int  width;               // in pixels (note that portalWidth in visible position within
                               //    image position  in db coodinates)
     boolean showSideLabel;    // Initially display side label? (use 'plusStrand' for left/right)
     int  sideLabelWidth;      // in pixels (note this is needed when setting up a portal
                               //    and dragScrolling)
     boolean showPortal;       // Rather than showing the entire data range, only show a portion,
                               //    and allow dragScrolling
     double basesPerPixel;     // number of bases covered by a single pixel
     long  portalStart;         // initial visible portal within html image table (db coodinates)
                               //    [May be obsoleted by js client]
     long  portalEnd;           // initial visible portal within html image table (db coodinates)
                               //    [May be obsoleted by js client]
     int  portalWidth;         // in pixels (should be equal to the visible position of data slice)
     struct imgTrack *imgTracks; // slList of all images to display
     };
 
 struct imgBox *imgBoxStart(char *db, char *chrom, long chromStart, long chromEnd,
                            boolean plusStrand, int sideLabelWidth, int width);
 // Starts an imgBox which should contain all info needed to draw the hgTracks image with
 // multiple tracks. The image box must be completed using imgBoxImageAdd() and imgBoxTrackAdd()
 
 boolean imgBoxPortalDefine(struct imgBox *imgBox, long *chromStart, long *chromEnd,
                            int *imgWidth,double imageMultiple);
 // Defines the portal of the imgBox.  The portal is the initial viewable region when dragScroll
 // is being used.  The new chromStart,chromEnd and imgWidth are returned as OUTs, while the
 // portal becomes the initial defined size
 // Returns TRUE if successfully defined as having a portal.
 
 boolean imgBoxPortalRemove(struct imgBox *imgBox, long *chromStart, long *chromEnd, int *imgWidth);
 // Will redefine the imgBox as the portal dimensions and return the dimensions as OUTs.
 // Returns TRUE if a portal was defined in the first place
 
 boolean imgBoxPortalDimensions(struct imgBox *imgBox, long *chromStart, long *chromEnd,
                                int *imgWidth, int *sideLabelWidth,
                                long *portalStart, long *portalEnd, int *portalWidth,
                                double *basesPerPixel);
 // returns the imgBox portal dimensions in the OUTs  returns TRUE if portal defined
 
 struct image *imgBoxImageAdd(struct imgBox *imgBox,char *png,char *title,int width,int height,
                              boolean backGround);
 // Adds an image to an imgBox.  The image may be extended with imgMapStart(),mapSetItemAdd()
 
 struct image *imgBoxImageFind(struct imgBox *imgBox,char *png);
 // Finds a specific image already added to this imgBox
 
 struct imgTrack *imgBoxTrackAdd(struct imgBox *imgBox,struct trackDb *tdb,char *name,
                                 enum trackVisibility vis,boolean hasCenterLabel,int order);
 // Adds an imgTrack to an imgBox.  The imgTrack needs to be extended with imgTrackAddSlice()
 
 struct imgTrack *imgBoxTrackFind(struct imgBox *imgBox,struct trackDb *tdb,char *name);
 // Finds a specific imgTrack already added to this imgBox
 
 struct imgTrack *imgBoxTrackFindOrAdd(struct imgBox *imgBox,struct trackDb *tdb,char *name,
                                       enum trackVisibility vis,boolean hasCenterLabel,int order);
 // Find the imgTrack, or adds it if not found
 
 struct imgTrack *imgBoxTrackUpdateOrAdd(struct imgBox *imgBox,struct trackDb *tdb,char *name,
                                         enum trackVisibility vis,boolean hasCenterLabel,int order);
 // Updates the imgTrack, or adds it if not found
 
 void imgBoxTracksNormalizeOrder(struct imgBox *imgBox);
 // This routine sorts the imgTracks
 
 int imgBoxDropEmpties(struct imgBox *imgBox);
 // Empty imageTracks (without slices) is not an error but they should be dropped.
 // returns remaining current track count
 
 boolean imgBoxIsComplete(struct imgBox *imgBox,boolean verbose);
 // Tests the completeness and consistency of an imgBox.
 
 void imgBoxFree(struct imgBox **pImgBox);
 // frees all memory assocated with an imgBox (including images and imgTracks)
 
 /////////////////////// imageV2 UI API
 void imageBoxDraw(struct imgBox *imgBox);
 // writes a entire imgBox including all tracks as HTML
 
 #endif//ndef IMAGEV2_H