From 3b2a75a4e08e13a35b6995d0295a96559beddb85 Mon Sep 17 00:00:00 2001 From: Trey Moen <50057480+greatgitsby@users.noreply.github.com> Date: Sat, 19 Sep 2026 18:41:58 -0700 Subject: [PATCH] cabana: resize heatmap and prevent signal clipping (#38975) * cabana: allow heatmap resizing without clipping * cabana: keep outer grid lines inside the heatmap * cabana: add a visible heatmap resize handle * cabana: use the standard pane divider for resizing --- .../tools/cabana/ui/widgets/binaryview.cc | 4 +-- .../tools/cabana/ui/widgets/detailwidget.cc | 26 ++++++++++++++----- .../tools/cabana/ui/widgets/detailwidget.h | 1 + 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/openpilot/tools/cabana/ui/widgets/binaryview.cc b/openpilot/tools/cabana/ui/widgets/binaryview.cc index 56f67075f4..818f8b42a8 100644 --- a/openpilot/tools/cabana/ui/widgets/binaryview.cc +++ b/openpilot/tools/cabana/ui/widgets/binaryview.cc @@ -348,8 +348,8 @@ void BinaryView::draw() { const float x = std::clamp(grid_pos_.x + IM_ROUND(column * column_width_), grid_pos_.x + 0.5f, right - 0.5f); painter->AddLine(ImVec2(x, grid_pos_.y), ImVec2(x, bottom), grid_color); } - for (int row = 0; row <= rows; ++row) { - const float y = grid_pos_.y + row * CELL_HEIGHT; + for (int row = 0; rows > 0 && row <= rows; ++row) { + const float y = std::clamp(grid_pos_.y + row * CELL_HEIGHT, grid_pos_.y + 0.5f, bottom - 0.5f); painter->AddLine(ImVec2(grid_pos_.x, y), ImVec2(right, y), grid_color); } diff --git a/openpilot/tools/cabana/ui/widgets/detailwidget.cc b/openpilot/tools/cabana/ui/widgets/detailwidget.cc index 67169e5561..6378d2f8ca 100644 --- a/openpilot/tools/cabana/ui/widgets/detailwidget.cc +++ b/openpilot/tools/cabana/ui/widgets/detailwidget.cc @@ -233,16 +233,29 @@ void DetailWidget::drawTabWidget() { page_tabs_.draw(); if (tab_widget_index_ == 0) { if (heatmap_visible_) { - // Keep most of a short window available for signal rows. + // Allow the heatmap to grow while reserving room for signal rows. + const float handle_height = style.DockingSeparatorSize; const float avail = ImGui::GetContentRegionAvail().y; - const float max_height = std::max(avail - style.ItemSpacing.y - SignalView::minimumHeight(), 1.0f); - const float height = std::min(binary_view_->minimumSizeHint().y, max_height); - ImGui::BeginChild("binary_view", ImVec2(0, std::max(height, 1.0f)), ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar); + const float max_height = std::max(avail - handle_height - style.ItemSpacing.y * 2 - SignalView::minimumHeight(), 1.0f); + const float min_height = std::min(ImGui::GetFrameHeight(), max_height); + float height = std::clamp(heatmap_height_ < 0 ? binary_view_->minimumSizeHint().y : heatmap_height_, min_height, max_height); + ImGui::BeginChild("binary_view", ImVec2(0, height), ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar); binary_view_rect_ = ImGui::GetCurrentWindow()->Rect(); binary_view_->draw(); ImGui::EndChild(); + + const ImVec2 pos = ImGui::GetCursorScreenPos(); + const ImVec2 size(std::max(ImGui::GetContentRegionAvail().x, 1.0f), handle_height); + const ImRect splitter(pos, ImVec2(pos.x + size.x, pos.y + size.y)); + float signal_height = std::max(avail - height - handle_height - style.ItemSpacing.y * 2, SignalView::minimumHeight()); + if (ImGui::SplitterBehavior(splitter, ImGui::GetID("##heatmap_resize"), ImGuiAxis_Y, + &height, &signal_height, min_height, SignalView::minimumHeight(), 4.0f)) { + heatmap_height_ = height; + } + ImGui::Dummy(size); } - ImGui::BeginChild("signal_view", ImVec2(0, 0), ImGuiChildFlags_None, + const float signal_height = std::max(ImGui::GetContentRegionAvail().y, SignalView::minimumHeight()); + ImGui::BeginChild("signal_view", ImVec2(0, signal_height), ImGuiChildFlags_None, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse); signal_view_rect_ = ImGui::GetCurrentWindow()->Rect(); signal_view_->draw(); @@ -254,8 +267,7 @@ void DetailWidget::drawTabWidget() { void DetailWidget::draw() { tabbar_.draw(); - ImGui::BeginChild("message_content", ImVec2(0, 0), ImGuiChildFlags_AlwaysUseWindowPadding, - ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse); + ImGui::BeginChild("message_content", ImVec2(0, 0), ImGuiChildFlags_AlwaysUseWindowPadding); drawToolBar(); if (warning_widget_visible_) { diff --git a/openpilot/tools/cabana/ui/widgets/detailwidget.h b/openpilot/tools/cabana/ui/widgets/detailwidget.h index 6c64a33bf8..f752488ee1 100644 --- a/openpilot/tools/cabana/ui/widgets/detailwidget.h +++ b/openpilot/tools/cabana/ui/widgets/detailwidget.h @@ -88,6 +88,7 @@ private: bool action_remove_msg_enabled_ = false; bool heatmap_live_ = true; bool heatmap_visible_ = true; + float heatmap_height_ = -1.0f; std::string heatmap_all_text_ = "All"; ImRect binary_view_rect_, signal_view_rect_; // child window rects of the last drawTabWidget std::unique_ptr history_log_;