diff --git a/src/view/src/rocprofvis_event_search.cpp b/src/view/src/rocprofvis_event_search.cpp index 62f5cc8a..00f6046a 100644 --- a/src/view/src/rocprofvis_event_search.cpp +++ b/src/view/src/rocprofvis_event_search.cpp @@ -6,6 +6,7 @@ #include "icons/rocprovfis_icon_defines.h" #include "rocprofvis_event_manager.h" #include "rocprofvis_settings_manager.h" +#include "rocprofvis_timeline_selection.h" #include "rocprofvis_utils.h" #include "spdlog/spdlog.h" #include "widgets/rocprofvis_notification_manager.h" @@ -22,7 +23,7 @@ constexpr const char* ID_COLUMN_NAME = "__uuid"; constexpr const char* EVENT_ID_COLUMN_NAME = "id"; constexpr const char* NAME_COLUMN_NAME = "name"; -EventSearch::EventSearch(DataProvider& dp) +EventSearch::EventSearch(DataProvider& dp, std::shared_ptr timeline_selection) : InfiniteScrollTable(dp, TableType::kEventSearchTable) , m_should_open(false) , m_should_close(false) @@ -32,6 +33,7 @@ EventSearch::EventSearch(DataProvider& dp) , m_searched(false) , m_width(1000.0f) , m_text_input("\0") +, m_timeline_selection(timeline_selection) { m_widget_name = GenUniqueName("Event Search Table"); } @@ -193,6 +195,10 @@ EventSearch::Clear() m_text_input[0] = '\0'; m_searched = false; m_should_close = true; + if(m_timeline_selection) + { + m_timeline_selection->ClearSearchHighlights(); + } } void @@ -306,6 +312,32 @@ EventSearch::RowSelected(const ImGuiMouseButton mouse_button) { SelectedRowNavigateEvent(m_important_column_idxs[kTrackId], m_important_column_idxs[kStreamId]); + + if(m_timeline_selection && m_selected_row >= 0) + { + const std::vector>& table_data = + m_data_provider.DataModel().GetTables().GetTableData(m_table_type); + if(m_selected_row < static_cast(table_data.size())) + { + uint64_t uuid = INVALID_UINT64_INDEX; + uint64_t track_id = SelectedRowToTrackID( + m_important_column_idxs[kTrackId], + m_important_column_idxs[kStreamId]); + if(m_important_column_idxs[kUUId] != INVALID_UINT64_INDEX && + m_important_column_idxs[kUUId] < table_data[m_selected_row].size()) + { + uuid = std::stoull( + table_data[m_selected_row][m_important_column_idxs[kUUId]]); + } + if(uuid != INVALID_UINT64_INDEX && track_id != INVALID_UINT64_INDEX) + { + m_timeline_selection->UnselectAllEvents(); + m_timeline_selection->ClearSearchHighlights(); + m_timeline_selection->SearchHighlightEvent(track_id, uuid); + } + } + } + m_should_close = true; } else if(mouse_button == ImGuiMouseButton_Right) diff --git a/src/view/src/rocprofvis_event_search.h b/src/view/src/rocprofvis_event_search.h index 2eab969e..fc326eb7 100644 --- a/src/view/src/rocprofvis_event_search.h +++ b/src/view/src/rocprofvis_event_search.h @@ -5,6 +5,7 @@ #include "imgui.h" #include "widgets/rocprofvis_infinite_scroll_table.h" +#include #include namespace RocProfVis @@ -12,10 +13,12 @@ namespace RocProfVis namespace View { +class TimelineSelection; + class EventSearch : public InfiniteScrollTable { public: - EventSearch(DataProvider& dp); + EventSearch(DataProvider& dp, std::shared_ptr timeline_selection); void Update() override; void Render() override; @@ -48,6 +51,8 @@ class EventSearch : public InfiniteScrollTable float m_width; char m_text_input[256]; + + std::shared_ptr m_timeline_selection; }; } // namespace View diff --git a/src/view/src/rocprofvis_flame_track_item.cpp b/src/view/src/rocprofvis_flame_track_item.cpp index 33b6369d..549ade6f 100644 --- a/src/view/src/rocprofvis_flame_track_item.cpp +++ b/src/view/src/rocprofvis_flame_track_item.cpp @@ -198,6 +198,7 @@ FlameTrackItem::ExtractPointsFromData() const TraceEvent& event = events_data[i]; m_chart_items[i].event = event; m_chart_items[i].selected = m_timeline_selection->EventSelected(event.m_id.uuid); + m_chart_items[i].search_highlighted = m_timeline_selection->EventSearchHighlighted(event.m_id.uuid); if(m_chart_items[i].event.m_child_count > 1) { m_chart_items[i].name_hash = @@ -294,6 +295,7 @@ FlameTrackItem::HandleTimelineSelectionChanged(std::shared_ptr e) for(ChartItem& item : m_chart_items) { item.selected = m_timeline_selection->EventSelected(item.event.m_id.uuid); + item.search_highlighted = m_timeline_selection->EventSearchHighlighted(item.event.m_id.uuid); } } } @@ -364,6 +366,11 @@ FlameTrackItem::DrawBox(ImVec2 start_position, int color_index, ChartItem& chart if(ImGui::IsMouseClicked(ImGuiMouseButton_Right)) { TimelineFocusManager::GetInstance().SetRightClickLayer(Layer::kGraphLayer); + m_timeline_selection->ClearSearchHighlights(); + for(ChartItem& item : m_chart_items) + { + item.search_highlighted = false; + } } // Select on click @@ -382,6 +389,11 @@ FlameTrackItem::DrawBox(ImVec2 start_position, int color_index, ChartItem& chart true; // Ensure only one click is handled per render cycle chart_item.selected = !chart_item.selected; + m_timeline_selection->ClearSearchHighlights(); + for(ChartItem& item : m_chart_items) + { + item.search_highlighted = false; + } //Control to multiselect const ImGuiIO& io = ImGui::GetIO(); @@ -410,6 +422,10 @@ FlameTrackItem::DrawBox(ImVec2 start_position, int color_index, ChartItem& chart { m_selected_chart_items.push_back(chart_item); } + if(chart_item.search_highlighted) + { + m_search_highlighted_chart_items.push_back(chart_item); + } } void @@ -681,6 +697,37 @@ FlameTrackItem::RenderChart(float graph_width) } m_selected_chart_items.clear(); + + for(ChartItem& item : m_search_highlighted_chart_items) + { + ImVec2 container_pos = ImGui::GetWindowPos(); + double normalized_start = + container_pos.x + m_tpt->RawTimeToPixel(item.event.m_start_ts); + + double normalized_duration = + std::max(item.event.m_duration * m_tpt->GetPixelsPerNs(), 1.0); + + ImVec2 start_position; + float rounding = 2.0f; + start_position = ImVec2(static_cast(normalized_start), + item.event.m_level * m_level_height); + + ImVec2 cursor_position = ImGui::GetCursorScreenPos(); + ImVec2 content_size = ImGui::GetContentRegionAvail(); + + ImVec2 rectMin = ImVec2(start_position.x - HIGHLIGHT_THICKNESS_HALF, + start_position.y + cursor_position.y + + HIGHLIGHT_THICKNESS_HALF - ANTI_ALIASING_WORKAROUND); + ImVec2 rectMax = + ImVec2(start_position.x + static_cast(normalized_duration) + + HIGHLIGHT_THICKNESS_HALF, + start_position.y + m_level_height + cursor_position.y - + HIGHLIGHT_THICKNESS_HALF + ANTI_ALIASING_WORKAROUND); + draw_list->AddRect(rectMin, rectMax, m_settings.GetColor(Colors::kSearchHighlight), + rounding, 0, HIGHLIGHT_THICKNESS); + } + + m_search_highlighted_chart_items.clear(); m_deferred_click_handled = false; ImGui::EndChild(); diff --git a/src/view/src/rocprofvis_flame_track_item.h b/src/view/src/rocprofvis_flame_track_item.h index b8195d73..7f05080e 100644 --- a/src/view/src/rocprofvis_flame_track_item.h +++ b/src/view/src/rocprofvis_flame_track_item.h @@ -80,6 +80,7 @@ class FlameTrackItem : public TrackItem { TraceEvent event; bool selected; + bool search_highlighted; size_t name_hash; std::vector child_info; }; @@ -109,6 +110,7 @@ class FlameTrackItem : public TrackItem bool m_deferred_click_handled; bool m_has_drawn_tool_tip; std::vector m_selected_chart_items; + std::vector m_search_highlighted_chart_items; EventManager::SubscriptionToken m_timeline_event_selection_changed_token; ImVec2 m_tooltip_size; diff --git a/src/view/src/rocprofvis_settings_manager.cpp b/src/view/src/rocprofvis_settings_manager.cpp index aba4e599..9b6a36d2 100644 --- a/src/view/src/rocprofvis_settings_manager.cpp +++ b/src/view/src/rocprofvis_settings_manager.cpp @@ -59,6 +59,7 @@ constexpr std::array DARK_THEME_COLORS = { IM_COL32(52, 54, 58, 255), // kTableRowBg IM_COL32(58, 60, 64, 255), // kTableRowBgAlt IM_COL32(0, 200, 255, 160), // kEventHighlight + IM_COL32(255, 160, 40, 180), // kSearchHighlight IM_COL32(235, 235, 240, 69), // kLineChartColor IM_COL32(100, 100, 110, 255), // kButton IM_COL32(130, 130, 140, 255), // kButtonHovered @@ -127,6 +128,7 @@ constexpr std::array LIGHT_THEME_COLORS = { IM_COL32(255, 253, 250, 255), // Colors::kTableRowBg IM_COL32(252, 250, 248, 255), // Colors::kTableRowBgAlt IM_COL32(0, 140, 200, 180), // Colors::kEventHighlight + IM_COL32(220, 130, 20, 200), // Colors::kSearchHighlight IM_COL32(0, 0, 0, 69), // Colors::kLineChartColor IM_COL32(230, 230, 230, 255), // Colors::kButton IM_COL32(210, 210, 210, 255), // Colors::kButtonHovered diff --git a/src/view/src/rocprofvis_settings_manager.h b/src/view/src/rocprofvis_settings_manager.h index e3b1cfec..64b3df90 100644 --- a/src/view/src/rocprofvis_settings_manager.h +++ b/src/view/src/rocprofvis_settings_manager.h @@ -93,6 +93,7 @@ enum class Colors kTableRowBg, kTableRowBgAlt, kEventHighlight, + kSearchHighlight, kLineChartColor, kButton, kButtonHovered, diff --git a/src/view/src/rocprofvis_timeline_selection.cpp b/src/view/src/rocprofvis_timeline_selection.cpp index 12e3d15f..2796b5f2 100644 --- a/src/view/src/rocprofvis_timeline_selection.cpp +++ b/src/view/src/rocprofvis_timeline_selection.cpp @@ -207,5 +207,35 @@ TimelineSelection::HasSelectedEvents() const return !m_selected_event_ids.empty(); } +void +TimelineSelection::SearchHighlightEvent(uint64_t track_id, uint64_t event_id) +{ + m_search_highlighted_event_ids.clear(); + m_search_highlighted_event_ids.insert(event_id); + SendEventSelectionChanged(event_id, track_id, true); +} + +void +TimelineSelection::ClearSearchHighlights() +{ + if(!m_search_highlighted_event_ids.empty()) + { + m_search_highlighted_event_ids.clear(); + SendEventSelectionChanged(INVALID_SELECTION_ID, INVALID_SELECTION_ID, false, true); + } +} + +bool +TimelineSelection::EventSearchHighlighted(uint64_t event_id) const +{ + return m_search_highlighted_event_ids.count(event_id) > 0; +} + +bool +TimelineSelection::HasSearchHighlightedEvents() const +{ + return !m_search_highlighted_event_ids.empty(); +} + } // namespace View } // namespace RocProfVis diff --git a/src/view/src/rocprofvis_timeline_selection.h b/src/view/src/rocprofvis_timeline_selection.h index a18b8f41..19a82fd7 100644 --- a/src/view/src/rocprofvis_timeline_selection.h +++ b/src/view/src/rocprofvis_timeline_selection.h @@ -42,6 +42,11 @@ class TimelineSelection bool HasSelectedEvents() const; bool GetSelectedEventsTimeRange(double& start_ts_out, double& end_ts_out) const; + void SearchHighlightEvent(uint64_t track_id, uint64_t event_id); + void ClearSearchHighlights(); + bool EventSearchHighlighted(uint64_t event_id) const; + bool HasSearchHighlightedEvents() const; + static constexpr double INVALID_SELECTION_TIME = std::numeric_limits::lowest(); static constexpr uint64_t INVALID_SELECTION_ID = std::numeric_limits::max(); @@ -61,6 +66,7 @@ class TimelineSelection double m_selected_range_end; std::unordered_set m_selected_event_ids; + std::unordered_set m_search_highlighted_event_ids; }; } // namespace View diff --git a/src/view/src/rocprofvis_trace_view.cpp b/src/view/src/rocprofvis_trace_view.cpp index 7a82dffe..b1529faa 100644 --- a/src/view/src/rocprofvis_trace_view.cpp +++ b/src/view/src/rocprofvis_trace_view.cpp @@ -233,7 +233,7 @@ TraceView::CreateView() m_track_topology = std::make_shared(m_data_provider); m_timeline_view = std::make_shared(m_data_provider, m_timeline_selection, m_annotations); - m_event_search = std::make_shared(m_data_provider); + m_event_search = std::make_shared(m_data_provider, m_timeline_selection); m_summary_view = std::make_shared(m_data_provider); m_minimap = std::make_shared(m_data_provider, m_timeline_view.get()); auto m_histogram_widget = std::make_shared(