feat(web): add right-click context menu and search/navigation to Web GUI#10946
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces several new features to the web-based layout viewer, mirroring capabilities from the Qt GUI. These additions include a canvas right-click context menu for selecting and highlighting connected objects, search and navigation dialogs (Find and Go to Position), and a WYSIWYG layout capture tool that composites Leaflet layers and SVG overlays into a downloadable PNG. On the backend, support has been added for handling find and context action requests, rendering colored polygons, and serving image downloads via a new HTTP route. The review feedback highlights a few important issues: an uninitialized Color bg struct in web.cpp that could lead to undefined behavior, a logic flaw in capture.js where transparent background values prevent the fallback color from being applied, and a duplicate hex color code for dark_magenta in context-menu.js.
|
|
||
| // Background color (RRGGBB hex) so the saved image matches the viewer's | ||
| // background; absent => transparent. | ||
| Color bg; // {0,0,0,0} |
There was a problem hiding this comment.
The Color bg; variable is declared on the stack without initialization. In C++, POD structs are not zero-initialized by default when declared on the stack, which leads to undefined behavior (reading garbage values from the stack for the background color of the exported image). Value-initializing it with {} ensures it is safely zero-initialized (transparent).
| Color bg; // {0,0,0,0} | |
| Color bg{}; // {0,0,0,0} |
| canvas.height = h; | ||
| const ctx = canvas.getContext('2d'); | ||
| // Background matches the viewer (--bg-map). | ||
| ctx.fillStyle = getComputedStyle(container).backgroundColor || '#111'; |
There was a problem hiding this comment.
In JavaScript, standard transparent background values like 'transparent' or 'rgba(0, 0, 0, 0)' are truthy strings. Therefore, the logical OR fallback || '#111' will never be triggered if the computed background is transparent. This results in a transparent background in the exported PNG, making light-colored layout elements invisible on standard white image viewers. Checking for these transparent values explicitly ensures the fallback background color is correctly applied.
| ctx.fillStyle = getComputedStyle(container).backgroundColor || '#111'; | |
| ctx.fillStyle = (getComputedStyle(container).backgroundColor !== 'transparent' && getComputedStyle(container).backgroundColor !== 'rgba(0, 0, 0, 0)') ? (getComputedStyle(container).backgroundColor || '#111') : '#111'; |
| { name: 'magenta', hex: '#ff00ff' }, | ||
| { name: 'red', hex: '#ff0000' }, | ||
| { name: 'dark_green', hex: '#008000' }, | ||
| { name: 'dark_magenta', hex: '#800080' }, |
There was a problem hiding this comment.
The hex color for dark_magenta is set to #800080, which is identical to the hex color for purple (also #800080). Standard dark magenta is #8b008b. Correcting this hex value avoids duplicate colors and ensures the color swatches in the context menu are distinct.
| { name: 'dark_magenta', hex: '#800080' }, | |
| { name: 'dark_magenta', hex: '#8b008b' }, |
c3691c3 to
ec12f88
Compare
Brings Qt-GUI parity (issue The-OpenROAD-Project#10619 tables 2.7 and 2.8) to the web viewer. Table 2.7 - right-click context menu: - Select -> Connected insts / output / input / all nets / buffer trees - Highlight with the 8-color highlight groups - Save layout (visible viewport and entire design) - Clear (selections / focus nets / route guides / rulers / all) - Menu items enable/disable based on the type under the cursor; the View submenu is replaced by an on-canvas Fit control next to zoom. Table 2.8 - search & navigation: - Find by name/glob (fnmatch) with auto-zoom to the result - Go to position (x, y, size) - Ctrl/Cmd+F and Shift+G shortcuts Save layout is a client-side WYSIWYG composite of the displayed scene (base layers + heatmap + highlights/selection + rulers), for both the current viewport and the whole design (fit -> wait for tiles -> capture -> restore view). Backend: WebSocket handlers (handleSelect / handleFind / handleContextAction) in request_handler, whole-die image render in tile_generator, and a /download/image route with exception-free query parsing in web.cpp. Tests: FindHandler gtests plus JS unit tests for the context menu, search & navigation, and layout capture. Signed-off-by: Jorge Ferreira <jorge.ferreira@precisioninno.com>
ec12f88 to
a6d9141
Compare
Addresses a portion of #10619
2.7 Right-click context menu
LayoutViewer::selectHighlightConnectedInst/Nets/BufferTrees→Gui::selectHighlightConnected*context_action(select_connected_insts/select_connected_output+inputnets /select_connected_nets/select_connected_buffer_trees); the serverhandleContextActionbuilds the set once viacomputeConnectedSet. The buffer-tree walk can toggle whether inverters are followed, and the number of objects added is surfaced as a toastLayoutViewer::updateContextMenuItems()+Gui::anyObjectInSet()disablingmenu_actions_[kSelect*Act]sel_has_inst/sel_has_net(addSelectionTypeFlags); the menu greys out items that don't apply — e.g. over a net only Connected Insts is enabled, and both submenus are disabled with nothing selectedhighlight_group, colored byPainter::kHighlightcontext_actions with a group index and a 4×4 color-picker; overlay shapes (rects and flight lines for unrouted nets) reuse the 2.6 highlight pipeline (16 groups)LayoutViewer::zoomIn/zoomOut,Gui::zoomToL.Controlnext to Leaflet's built-in zoom ± buttons (plus thefshortcut), where users expect itGui::saveImage/gui::save_image(server-side render)capture.js) of the displayed scene — base tiles + heatmap + highlight/selection overlay + ruler/label SVG panes — drawn onto a canvas via per-tilegetBoundingClientRect(correct under fractional zoom); Visible captures the viewport, Entire fits the whole design, waits for the tiles to settle, captures, then restores the previous viewGui::clearSelections/clearHighlights/clearRulerscontext_actionclear_selections/clear_focus_nets/clear_route_guides/clear_all; rulers are cleared client-side2.8 Search & navigation
MainWindow::showFindDialog→FindObjectDialog→block->findInst/findNetWebSocketRequest::kFind+SelectHandler::handleFind:{obj_type: inst|net|port, pattern, match_case}, matched by glob (fnmatch, optional case-fold), selection capped at 1000; a modal (type dropdown + Match Case + close button) drives it. Web addition: the view auto-zooms to the union bbox of the matches (map.fitBounds) — the Qt dialog only selects — and the hit count is reportedMainWindow::showGotoDialog→GotoLocationDialogmap.setView, orfitBoundsa box of the requested size;Shift+Gshortcut