1e82a3b6411cc32e625b36911f4949b552ffba3d
jrobinso
  Mon Sep 15 19:05:40 2025 -0700
Add igv configuration menu to name panel.  Also expose igv.js createIcon function

diff --git src/hg/js/igvFileHelper.js src/hg/js/igvFileHelper.js
index 6794987c226..eb01d4cfc6c 100644
--- src/hg/js/igvFileHelper.js
+++ src/hg/js/igvFileHelper.js
@@ -374,70 +374,98 @@
                     }
                 }
             });
         });
 
 
         /**
          * Update the track names in the left hand column of the IGV row in the image table.
          */
         function updateTrackNames() {
             // Add track names to the left hand column.
             const allTracks = igvBrowser.findTracks(t => t.type);
             let top = 0;
             document.getElementById('igv_namediv').innerHTML = ""; // Clear any existing content
             for (let track of allTracks) {
-                const trackLabelDiv = document.createElement('div');
-                trackLabelDiv.setAttribute('data-track-id', track.id); // Set the track ID attribute
-                trackLabelDiv.textContent = track.name; // Set the track name as the label
-                trackLabelDiv.style.marginBottom = '5px'; // Optional: Add spacing between labels
-                trackLabelDiv.style.position = 'absolute'; // Use absolute positioning
-                trackLabelDiv.style.top = `${top}px`; // Position the element at the current value of "top"
-                trackLabelDiv.style.right = '5px'; // Set a fixed width for the label div
-                trackLabelDiv.style.textAlign = 'right'; // Right-justify the text
-                document.getElementById('igv_namediv').appendChild(trackLabelDiv);
 
-                trackLabelDiv.addEventListener('contextmenu', (e) => {
+                if('sequence' !== track.type) {
+                    const labelContainer = document.createElement('div');
+                    labelContainer.style.position = 'absolute'; // Use relative positioning
+                    labelContainer.style.top = `${top}px`; // Position the element at the current value of "top"
+                    labelContainer.style.left = '0';
+                    labelContainer.style.right = '0';       // span full width of the enclosing td via igv_namediv
+                    labelContainer.style.width = '100%';    // optional, for clarity
+
+                    const gearDiv = document.createElement('div');
+                    gearDiv.style.position = 'absolute';
+                    gearDiv.style.left = '5px';
+                    gearDiv.style.width = '15px';
+                    gearDiv.style.height = '15px';
+                    gearDiv.style.maxWidth = '15px';
+                    gearDiv.style.maxHeight = '15px';
+                    gearDiv.style.overflow = 'hidden';
+
+                    const cog = igv.createIcon('cog', 'grey');
+                    // Ensure the underlying SVG is 15x15
+                    const svg = cog.tagName && cog.tagName.toLowerCase() === 'svg' ? cog : cog.querySelector('svg');
+                    if (svg) {
+                        svg.setAttribute('width', '15');
+                        svg.setAttribute('height', '1');
+                        svg.style.width = '15px';
+                        svg.style.height = '15px';
+                    }
+
+                    gearDiv.appendChild(cog);
+                    gearDiv.setAttribute('data-track-id', track.id); // Set the track ID attribute
+                    labelContainer.appendChild(gearDiv);
+                    gearDiv.addEventListener("click", (e) => {
                         e.stopPropagation();
                         e.preventDefault();
                         const trackId = e.currentTarget.getAttribute('data-track-id');
                         const matchingTracks = igvBrowser.findTracks(t => t.id === trackId);
                         if (matchingTracks.length > 0) {
                             const trackView = matchingTracks[0].trackView;
                             trackView.trackGearPopup.presentMenuList(
                                 trackView,
                                 igvBrowser.menuUtils.trackMenuItemList(trackView),
                                 igvBrowser.config);
                         }
                     });
 
+                    const trackLabelDiv = document.createElement('div');
+                    trackLabelDiv.textContent = track.name; // Set the track name as the label
+                    trackLabelDiv.style.right = '5px'; // Set a fixed width for the label div
+                    trackLabelDiv.style.textAlign = 'right'; // Right-justify the text
+                    labelContainer.appendChild(trackLabelDiv);
+
+                    document.getElementById('igv_namediv').appendChild(labelContainer);
+                }
                 top += track.trackView.viewports[0].viewportElement.clientHeight; // Adjust top for the next element
             }
         }
 
         function insertIGVRow() {
-            // Insert the IGV row into the image table.
             const imgTbl = document.getElementById('imgTbl');
             const tbody = imgTbl.querySelector('tbody');
             const igvRow = document.createElement('tr');
             igvRow.id = "tr_igv";
             igvRow.innerHTML = `
                 <td style="background: grey">
                     <div style="width:13px"></div>
                 </td>
                 <td style="position: relative">
-                <div id = "igv_namediv" style="width: 140px;position: absolute;top: 0; bottom: 0;"></div>
+                    <div id="igv_namediv" style="position:absolute; top:0; bottom:0; left:0; right:0;"></div>
                 </td>
                 <td>
                     <div id="igv_div" style="width: auto"></div>
                 </td>
             `;
             tbody.appendChild(igvRow);
             return igvRow;
         }
 
         /**
          * Create an IGV browser instance and insert it into the image table as a new row. The IGV browser essentially becomes
          * a track in the UCSC browser context.  This function is called when the user adds the first IGV track, or
          * the igv session is restored on page reload.
          *
          * @param config -- The IGV browser configuration object.  Must include a reference genome, but might also include