/// <summary> /// Get the label of the timeline event /// </summary> /// <returns>The list of strings and colours which need to be joined to make a label</returns> public List <Tuple <string, WritableRgbaFloat> > Label() { Debug.Assert(_item is not null); if (_cachedLabel != null && _cachedLabelTheme == Themes.ThemeVariant) { return(_cachedLabel); } _cachedLabel = new List <Tuple <string, WritableRgbaFloat> >(); _cachedLabelTheme = Themes.ThemeVariant; WritableRgbaFloat textColour = Themes.GetThemeColourWRF(Themes.eThemeColour.WindowText); switch (_eventType) { case eTimelineEvent.ProcessStart: { TraceRecord trace = (TraceRecord)_item; _cachedLabel.Add(new Tuple <string, WritableRgbaFloat>($"Process ({trace.PID}) Started", textColour)); break; } case eTimelineEvent.ProcessEnd: { TraceRecord trace = (TraceRecord)_item; _cachedLabel.Add(new Tuple <string, WritableRgbaFloat>($"Process ({trace.PID}) Ended", textColour)); break; } case eTimelineEvent.ThreadStart: { ProtoGraph graph = (ProtoGraph)_item; _cachedLabel.Add(new Tuple <string, WritableRgbaFloat>($"Thread ({graph.ThreadID}) Started", textColour)); break; } case eTimelineEvent.ThreadEnd: { ProtoGraph graph = (ProtoGraph)_item; _cachedLabel.Add(new Tuple <string, WritableRgbaFloat>($"Thread ({graph.ThreadID}) Ended", textColour)); break; } case eTimelineEvent.APICall: { Logging.APICALL call = (Logging.APICALL)_item; NodeData n = call.Node !; var labelitems = n.CreateColourisedSymbolCall(call.Graph, call.Index, textColour, Themes.GetThemeColourWRF(Themes.eThemeColour.Emphasis1)); _cachedLabel.AddRange(labelitems); break; } default: _cachedLabel.Add(new Tuple <string, WritableRgbaFloat>($"Bad timeline event: ", textColour)); Debug.Assert(false, $"Bad timeline event: {_eventType}"); return(_cachedLabel); } return(_cachedLabel); }
private void DrawEventListTable(TraceRecord trace, SandboxChart.ItemNode?selectedNode) { if (chart is null) { return; } ImGui.PushStyleColor(ImGuiCol.Header, Themes.GetThemeColourUINT(Themes.eThemeColour.Emphasis2, 40)); TIMELINE_EVENT[] events = trace.GetTimeLineEntries(); if (ImGui.BeginTable("#TaTTFullList", 4, ImGuiTableFlags.Borders | ImGuiTableFlags.ScrollY | ImGuiTableFlags.Resizable | ImGuiTableFlags.RowBg)) { ImGui.TableSetupScrollFreeze(0, 1); ImGui.TableSetupColumn("#", ImGuiTableColumnFlags.WidthFixed, 50); ImGui.TableSetupColumn("Type", ImGuiTableColumnFlags.WidthFixed, 70); ImGui.TableSetupColumn("Module", ImGuiTableColumnFlags.WidthFixed, 70); ImGui.TableSetupColumn("Details", ImGuiTableColumnFlags.None); ImGui.TableHeadersRow(); var SelectedEntity = chart.SelectedEntity; var SelectedAPIEvent = chart.SelectedAPIEvent; bool ThreadNodeSelected = selectedNode is not null && Equals(selectedNode.reference.GetType(), typeof(ProtoGraph)); bool ProcessNodeSelected = selectedNode is not null && Equals(selectedNode.reference.GetType(), typeof(TraceRecord)); int i = 0; foreach (TIMELINE_EVENT TLevent in events) { i += 1; ImGui.TableNextRow(); if (TLevent.MetaError != null) { ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg0, Themes.GetThemeColourUINT(Themes.eThemeColour.BadStateColour)); ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg1, Themes.GetThemeColourUINT(Themes.eThemeColour.BadStateColour)); } bool selected = false; string eventType = ""; string module = ""; if (ImGui.TableNextColumn()) { switch (TLevent.TimelineEventType) { case eTimelineEvent.ProcessStart: case eTimelineEvent.ProcessEnd: eventType = "Process"; if (selectedNode != null) { selected = (ProcessNodeSelected && TLevent.ID == ((TraceRecord)selectedNode.reference).PID); } break; case eTimelineEvent.ThreadStart: case eTimelineEvent.ThreadEnd: eventType = "Thread"; if (selectedNode != null) { ProtoGraph currentEntryGraph = (ProtoGraph)TLevent.Item; selected = (ThreadNodeSelected && currentEntryGraph.ThreadID == ((ProtoGraph)selectedNode.reference).ThreadID); selected = selected || (ProcessNodeSelected && currentEntryGraph.TraceData.PID == ((TraceRecord)(selectedNode.reference)).PID); } break; case eTimelineEvent.APICall: { Logging.APICALL call = (Logging.APICALL)(TLevent.Item); selected = TLevent == SelectedAPIEvent; if (call.Node !.IsExternal) { eventType = "API - " + call.APIType(); module = Path.GetFileNameWithoutExtension(trace.DisassemblyData.GetModulePath(call.Node.GlobalModuleID)); //api call is selected if it is either directly activated, or interacts with a reference to the active entity //eg: if the file.txt node is selected, writefile to the relevant handle will also be selected selected = selected || (SelectedEntity != null && SelectedEntity == chart.GetInteractedEntity(TLevent)); if (!selected && selectedNode != null) { //select all apis called by selected thread node selected = selected || (ThreadNodeSelected && call.Graph !.ThreadID == ((ProtoGraph)selectedNode.reference).ThreadID); //select all apis called by selected process node selected = selected || (ProcessNodeSelected && call.Graph !.TraceData.PID == ((TraceRecord)selectedNode.reference).PID); } //WinAPIDetails.API_ENTRY = call.APIEntry; } else { eventType = "Internal"; } } break; } if (ImGui.Selectable(i.ToString(), selected, ImGuiSelectableFlags.SpanAllColumns) && !selected) { chart.SelectAPIEvent(TLevent); } }