// The headers for the different meta changes all have basically the same structure for different types. private void DrawEditHeader <T>(IReadOnlyCollection <T> items, string label, int numColumns, Action <T, Mod.Editor, Vector2> draw, Action <Mod.Editor, Vector2> drawNew) { const ImGuiTableFlags flags = ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.BordersInnerV; if (!ImGui.CollapsingHeader($"{items.Count} {label}")) { return; } using (var table = ImRaii.Table(label, numColumns, flags)) { if (table) { drawNew(_editor !, _iconSize); ImGui.Separator(); foreach (var(item, index) in items.ToArray().WithIndex()) { using var id = ImRaii.PushId(index); draw(item, _editor !, _iconSize); } } } ImGui.NewLine(); }
private ImGuiRaii?DrawTableHeader(int type) { const ImGuiTableFlags flags = ImGuiTableFlags.Hideable | ImGuiTableFlags.BordersOuter | ImGuiTableFlags.BordersInner | ImGuiTableFlags.SizingFixedSame; var list = type switch { 2 => VisorStateWeaponNames, 3 => CPoseManager.PoseNames, _ => VisorStateNames, }; var imgui = new ImGuiRaii(); if (!imgui.Begin(() => ImGui.BeginTable($"##table_{type}_{_currentPlayer}", list.Length + 1, flags), ImGui.EndTable)) { return(null); } ImGui.TableSetupColumn($"Job##empty_{type}_{_currentPlayer}", ImGuiTableColumnFlags.NoHide); foreach (var name in list) { ImGui.TableSetupColumn(name); } ImGui.TableHeadersRow(); return(imgui); }
public static void TableView(string label, Action callback, int column, ImGuiTableFlags flags = ImGuiTableFlags.None) { if (ImGui.BeginTable(label, column, flags)) { callback?.Invoke(); ImGui.EndTable(); } }
public static void TableView(string str_id, Action callback, ImGuiTableFlags flags, params string[] headers) { int len = headers.Length; if (ImGui.BeginTable(str_id, len, flags)) { ImGuiUtils.TableSetupHeaders(headers); callback?.Invoke(); ImGui.EndTable(); } }
public static void TableView(string label, Callback callback, ImGuiTableFlags flags, params string[] headers) { int len = headers.Length; if (ImGui.BeginTable(label, len, flags)) { ImGuiView.TableSetupHeaders(headers); callback?.Invoke(); ImGui.EndTable(); } }
protected override void OnDraw() { EntityWorld world = EntityWorld.Active; StructArray <EntityChunk> chunks = world.EntityManager.GetChunks(); for (int i = 0; i < chunks.Count; i++) { ref EntityChunk chunk = ref chunks[i]; bool open = ImGui.TreeNode($"[{i}] Chunk: {chunk.Count}/{chunk.Capacity}"); if (ImGui.IsItemHovered()) { ImGui.SetTooltip(chunk.Archetype.ToString()); } if (open) { ImGuiTableFlags tFlags = ImGuiTableFlags.RowBg | ImGuiTableFlags.Resizable; if (ImGui.BeginTable("Entities", 2, tFlags)) { ImGui.TableSetupColumn("Id"); ImGui.TableSetupColumn("Version"); ImGui.TableHeadersRow(); for (int e = 0; e < chunk.Count; e++) { Entity entity = chunk.GetEntity(e); ImGui.TableNextRow(); ImGui.TableNextColumn(); bool isSelected = ObjectSelections.CurrentObj?.Equals(entity) ?? false; if (ImGui.Selectable($"##{e}", isSelected, ImGuiSelectableFlags.SpanAllColumns)) { ObjectSelections.SelectObject(entity); } ImGui.SameLine(); ImGui.Text(entity.id.ToString()); ImGui.TableNextColumn(); ImGui.Text(entity.version.ToString()); } ImGui.Separator(); ImGui.EndTable(); } ImGui.TreePop(); } }
private void DrawFileSwapTab() { if (_editMode) { DrawFileSwapTabEdit(); return; } if (!Meta.FileSwaps.Any() || !ImGui.BeginTabItem(LabelFileSwapTab)) { return; } using var raii = ImGuiRaii.DeferredEnd(ImGui.EndTabItem); const ImGuiTableFlags flags = ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollX; ImGui.SetNextItemWidth(-1); if (!ImGui.BeginTable(LabelFileSwapHeader, 3, flags, AutoFillSize)) { return; } raii.Push(ImGui.EndTable); foreach (var(source, target) in Meta.FileSwaps) { ImGui.TableNextColumn(); ImGuiCustom.CopyOnClickSelectable(source); ImGui.TableNextColumn(); ImGuiCustom.PrintIcon(FontAwesomeIcon.LongArrowAltRight); ImGui.TableNextColumn(); ImGuiCustom.CopyOnClickSelectable(target); ImGui.TableNextRow(); } }
public void Draw() { var ret = ImGui.BeginTabItem(LabelTab); if (!ret) { return; } const ImGuiTableFlags flags = ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollX; if (ImGui.BeginTable("##effective_files", 3, flags, AutoFillSize)) { foreach (var file in _mods.ResolvedFiles) { DrawFileLine(file.Value, file.Key); ImGui.TableNextRow(); } ImGui.EndTable(); } ImGui.EndTabItem(); }
private void DrawSplash(rgatSettings.PathRecord[] recentBins, rgatSettings.PathRecord[] recentTraces) { ImGui.PushStyleVar(ImGuiStyleVar.CellPadding, Vector2.Zero); ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, Vector2.Zero); ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero); ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, Vector2.Zero); ImGui.PushStyleVar(ImGuiStyleVar.ItemInnerSpacing, Vector2.Zero); float regionHeight = ImGui.GetContentRegionAvail().Y; float regionWidth = ImGui.GetContentRegionAvail().X; float buttonBlockWidth = Math.Min(400f, regionWidth / 2.1f); float headerHeight = ImGui.GetWindowSize().Y / 3; float blockHeight = (regionHeight * 0.95f) - headerHeight; float blockStart = headerHeight + 40f; ImFontPtr titleFont = Controller.rgatLargeFont ?? Controller._originalFont !.Value; ImGui.PushFont(titleFont); Vector2 titleSize = ImGui.CalcTextSize("rgat"); ImGui.SetCursorScreenPos(new Vector2((ImGui.GetWindowContentRegionMax().X / 2) - (titleSize.X / 2), (ImGui.GetWindowContentRegionMax().Y / 5) - (titleSize.Y / 2))); ImGui.Text("rgat"); ImGui.PopFont(); //ImGui.PushStyleColor(ImGuiCol.ChildBg, 0xff0000ff); //ImGui.PushStyleColor(ImGuiCol.ChildBg, new WritableRgbaFloat(0, 0, 0, 255).ToUint()); bool boxBorders = false; //ImGui.PushStyleColor(ImGuiCol.HeaderHovered, 0x45ffffff); _splashHeaderHover = ImGui.GetMousePos().Y < (ImGui.GetWindowSize().Y / 3f); //ImGui.PopStyleColor(); //Run group float voidspace = Math.Max(0, (regionWidth - (2 * buttonBlockWidth)) / 3); float runGrpX = voidspace; float iconTableYSep = 18; float iconTitleYSep = 10; ImGuiTableFlags tblflags = ImGuiTableFlags.NoHostExtendX; if (boxBorders) { tblflags |= ImGuiTableFlags.Borders; } ImGui.SetCursorPos(new Vector2(runGrpX, blockStart)); ImGui.PushStyleColor(ImGuiCol.ChildBg, Themes.GetThemeColourUINT(Themes.eThemeColour.WindowBackground)); if (ImGui.BeginChild("##RunGroup", new Vector2(buttonBlockWidth, blockHeight), boxBorders)) { ImGui.PushFont(Controller.SplashLargeFont ?? Controller._originalFont !.Value); float captionHeight = ImGui.CalcTextSize("Load Binary").Y; if (ImGui.BeginTable("##LoadBinBtnBox", 3, tblflags)) { Vector2 LargeIconSize = Controller.LargeIconSize; float iconColumnWidth = 200; float paddingX = (buttonBlockWidth - iconColumnWidth) / 2; ImGui.TableSetupColumn("##BBSPadL", ImGuiTableColumnFlags.WidthFixed, paddingX); ImGui.TableSetupColumn("##LoadBinBtnIcn", ImGuiTableColumnFlags.WidthFixed, iconColumnWidth); ImGui.TableSetupColumn("##BBSPadR", ImGuiTableColumnFlags.WidthFixed, paddingX); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(1); Vector2 selectableSize = new Vector2(iconColumnWidth, captionHeight + LargeIconSize.Y + iconTitleYSep + 12); if (ImGui.Selectable("##Load Binary", false, ImGuiSelectableFlags.None, selectableSize)) { ToggleLoadExeWindow(); } Controller.PushUnicodeFont(); Widgets.SmallWidgets.MouseoverText("Load an executable or DLL for examination. It will not be executed at this stage."); ImGui.PopFont(); ImGui.SetCursorPosY(ImGui.GetCursorPosY() - ImGui.GetItemRectSize().Y); ImGuiUtils.DrawHorizCenteredText("Load Binary"); ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (iconColumnWidth / 2) - (LargeIconSize.X / 2)); ImGui.SetCursorPosY(ImGui.GetCursorPosY() + iconTitleYSep); Controller.PushBigIconFont(); ImGui.Text($"{ImGuiController.FA_ICON_SAMPLE}"); //If you change this be sure to update ImGuiController.BuildFonts ImGui.PopFont(); ImGui.EndTable(); } ImGui.PopFont(); ImGui.SetCursorPosY(ImGui.GetCursorPosY() + iconTableYSep); Vector2 tableSz = new Vector2(buttonBlockWidth, ImGui.GetContentRegionAvail().Y - 25); ImGui.PushStyleVar(ImGuiStyleVar.CellPadding, new Vector2(0, 2)); if (ImGui.BeginTable("#RecentBinTableList", 1, ImGuiTableFlags.ScrollY, tableSz)) { ImGui.Indent(5); ImGui.TableSetupColumn("Recent Binaries" + $"{(rgatState.ConnectedToRemote ? " (Remote Files)" : "")}"); ImGui.TableSetupScrollFreeze(0, 1); ImGui.TableHeadersRow(); if (recentBins?.Length > 0) { int bincount = Math.Min(GlobalConfig.Settings.UI.MaxStoredRecentPaths, recentBins.Length); for (var bini = 0; bini < bincount; bini++) { var entry = recentBins[bini]; ImGui.TableNextRow(); if (ImGui.TableNextColumn()) { if (DrawRecentPathEntry(entry, menu: false)) { if (File.Exists(entry.Path) || rgatState.ConnectedToRemote) { if (!LoadSelectedBinary(entry.Path, rgatState.ConnectedToRemote) && !_badPaths.Contains(entry.Path)) { _badPaths.Add(entry.Path); } } else if (!_missingPaths.Contains(entry.Path) && rgatState.ConnectedToRemote is false) { _scheduleMissingPathCheck = true; _missingPaths.Add(entry.Path); } } } } } ImGui.EndTable(); } ImGui.PopStyleVar(); ImGui.EndChild(); } ImGui.SetCursorPosY(blockStart); ImGui.SetCursorPosX(runGrpX + buttonBlockWidth + voidspace); if (ImGui.BeginChild("##LoadGroup", new Vector2(buttonBlockWidth, blockHeight), boxBorders)) { ImGui.PushFont(Controller.SplashLargeFont ?? Controller._originalFont !.Value); float captionHeight = ImGui.CalcTextSize("Load Trace").Y; if (ImGui.BeginTable("##LoadBtnBox", 3, tblflags)) { Vector2 LargeIconSize = Controller.LargeIconSize; float iconColumnWidth = 200; float paddingX = (buttonBlockWidth - iconColumnWidth) / 2; ImGui.TableSetupColumn("##LBSPadL", ImGuiTableColumnFlags.WidthFixed, paddingX); ImGui.TableSetupColumn("##LoadBtnIcn", ImGuiTableColumnFlags.WidthFixed, iconColumnWidth); ImGui.TableSetupColumn("##LBSPadR", ImGuiTableColumnFlags.WidthFixed, paddingX); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(1); Vector2 selectableSize = new Vector2(iconColumnWidth, captionHeight + LargeIconSize.Y + iconTitleYSep + 12); if (ImGui.Selectable("##Load Trace", false, ImGuiSelectableFlags.None, selectableSize)) { ToggleLoadTraceWindow(); } Controller.PushUnicodeFont(); Widgets.SmallWidgets.MouseoverText("Load a previously generated trace"); ImGui.PopFont(); ImGui.SetCursorPosY(ImGui.GetCursorPosY() - ImGui.GetItemRectSize().Y); ImGuiUtils.DrawHorizCenteredText("Load Trace"); ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (iconColumnWidth / 2) - (LargeIconSize.X / 2) + 8); //shift a bit to the right to balance it ImGui.SetCursorPosY(ImGui.GetCursorPosY() + iconTitleYSep); Controller.PushBigIconFont(); ImGui.Text($"{ImGuiController.FA_ICON_LOADFILE}");//If you change this be sure to update ImGuiController.BuildFonts ImGui.PopFont(); ImGui.EndTable(); } ImGui.PopFont(); ImGui.SetCursorPosY(ImGui.GetCursorPosY() + iconTableYSep); Vector2 tableSz = new Vector2(buttonBlockWidth, ImGui.GetContentRegionAvail().Y - 25); ImGui.PushStyleVar(ImGuiStyleVar.CellPadding, new Vector2(0, 2)); if (ImGui.BeginTable("#RecentTraceTableList", 1, ImGuiTableFlags.ScrollY, tableSz)) { ImGui.Indent(5); ImGui.TableSetupColumn("Recent Traces"); ImGui.TableSetupScrollFreeze(0, 1); ImGui.TableHeadersRow(); if (recentTraces?.Length > 0) { int traceCount = Math.Min(GlobalConfig.Settings.UI.MaxStoredRecentPaths, recentTraces.Length); for (var traceI = 0; traceI < traceCount; traceI++) { var entry = recentTraces[traceI]; ImGui.TableNextRow(); if (ImGui.TableNextColumn()) { if (DrawRecentPathEntry(entry, false)) { if (File.Exists(entry.Path)) { System.Threading.Tasks.Task.Run(() => LoadTraceByPath(entry.Path)); /* * if (!LoadTraceByPath(entry.Path) && !_badPaths.Contains(entry.Path)) * { * _badPaths.Add(entry.Path); * }*/ } else if (!_missingPaths.Contains(entry.Path)) { _scheduleMissingPathCheck = true; _missingPaths.Add(entry.Path); } } } } } ImGui.EndTable(); } ImGui.PopStyleVar(); ImGui.EndChild(); } ImGui.PopStyleVar(5); ImGui.BeginGroup(); string versionString = $"rgat {CONSTANTS.PROGRAMVERSION.RGAT_VERSION}"; float width = ImGui.CalcTextSize(versionString).X; ImGui.SetCursorPos(ImGui.GetContentRegionMax() - new Vector2(width + 25, 40)); ImGui.Text(versionString); if (GlobalConfig.NewVersionAvailable) { Version currentVersion = CONSTANTS.PROGRAMVERSION.RGAT_VERSION_SEMANTIC; Version newVersion = GlobalConfig.Settings.Updates.UpdateLastCheckVersion; string updateString; if (newVersion.Major > currentVersion.Major || (newVersion.Major == currentVersion.Major && newVersion.Minor > currentVersion.Minor)) { updateString = "New version available "; } else { updateString = "Updates available "; } updateString += $"({newVersion})"; Vector2 textSize = ImGui.CalcTextSize(updateString); ImGui.SetCursorPos(ImGui.GetContentRegionMax() - new Vector2(textSize.X + 25, 55)); if (ImGui.Selectable(updateString, false, flags: ImGuiSelectableFlags.None, size: new Vector2(textSize.X, textSize.Y))) { ImGui.OpenPopup("New Version Available"); } if (ImGui.IsItemHovered()) { Updates.ChangesCounts(out int changes, out int versions); if (changes > 0) { ImGui.BeginTooltip(); ImGui.Text($"Click to see {changes} changes in {versions} newer rgat versions"); ImGui.EndTooltip(); } } } ImGui.EndGroup(); ImGui.PopStyleColor(); if (GlobalConfig.Settings.UI.EnableTortoise) { _splashRenderer?.Draw(); } if (StartupProgress < 1) { float originalY = ImGui.GetCursorPosY(); float ypos = ImGui.GetWindowSize().Y - 12; ImGui.SetCursorPosY(ypos); ImGui.ProgressBar((float)StartupProgress, new Vector2(-1, 4f)); ImGui.SetCursorPosY(originalY); } if (ImGui.IsPopupOpen("New Version Available")) { ImGui.SetNextWindowSize(new Vector2(600, 500), ImGuiCond.FirstUseEver); ImGui.SetNextWindowPos((ImGui.GetWindowSize() / 2) - new Vector2(600f / 2f, 500f / 2f), ImGuiCond.Appearing); bool isopen = true; if (ImGui.BeginPopupModal("New Version Available", ref isopen, flags: ImGuiWindowFlags.Modal)) { Updates.DrawChangesDialog(); isopen = isopen && !ImGui.IsKeyDown(ImGui.GetKeyIndex(ImGuiKey.Escape)); if (!isopen) { ImGui.CloseCurrentPopup(); } ImGui.EndPopup(); } } }
public static void DrawChangesDialog() { ImGui.PushStyleColor(ImGuiCol.Text, 0xffffffff); ImGui.PushStyleColor(ImGuiCol.FrameBg, 0xff000000); Version currentVersion = CONSTANTS.PROGRAMVERSION.RGAT_VERSION_SEMANTIC; Version newVersion = GlobalConfig.Settings.Updates.UpdateLastCheckVersion; ImGui.Text($"Current Version: {currentVersion}. New Version: {newVersion}"); ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 5); string[] changes = GlobalConfig.Settings.Updates.UpdateLastChanges.Split('\n'); if (ImGui.BeginTabBar("#ChangesTabs")) { for (var i = 0; i < changes.Length; i++) { string item = changes[i].Trim(); if (item.StartsWith("####")) { string category = item.Substring(4, item.Length - 4); if (category.StartsWith("CHANGES")) { continue; } GetChangeIcon(category, out char icon, out WritableRgbaFloat colour); ImGui.PushStyleColor(ImGuiCol.Tab, colour.ToUint(customAlpha: 150)); ImGui.PushStyleColor(ImGuiCol.TabHovered, colour.ToUint(customAlpha: 190)); ImGui.PushStyleColor(ImGuiCol.TabActive, colour.ToUint(customAlpha: 255)); if (ImGui.BeginTabItem($"{icon} {category}##{i}")) { ImGuiTableFlags tableFlags = ImGuiTableFlags.ScrollY | ImGuiTableFlags.ScrollX | ImGuiTableFlags.RowBg; if (ImGui.BeginTable("#ChangesDlgChild", 1, flags: tableFlags, ImGui.GetContentRegionAvail() - new System.Numerics.Vector2(0, 30))) { i += 1; while (i < changes.Length) { string text = changes[i].Trim(); if (text.Length < 2) { i += 1; continue; } ImGui.TableNextRow(); ImGui.TableNextColumn(); ImGui.Text(text); i += 1; if (i < (changes.Length - 1) && changes[i + 1].StartsWith("####")) { break; } } ImGui.EndTable(); } ImGui.EndTabItem(); } ImGui.PopStyleColor(3); } } ImGui.EndTabBar(); } ImGui.PopStyleColor(2); if (_update_in_progress is false) { if (ImGui.Button($"{ImGuiController.FA_ICON_DOWNLOAD} Download and Install now")) { StartUpdater(delayed_install: false); } ImGui.SameLine(); if (ImGui.Button($"{ImGuiController.FA_ICON_CLOCK} Download now, Install on exit")) { StartUpdater(delayed_install: true); } } else { if (_download_complete) { if (Updates.PendingInstallPath != null) { ImGui.AlignTextToFramePadding(); ImGui.Text("Update will be installed on exit"); ImGui.SameLine(); if (ImGui.Button("Cancel")) { Updates.PendingInstallPath = null; _update_in_progress = false; } } else if (_update_style == "ONDOWNLOAD") { ImGui.AlignTextToFramePadding(); ImGui.Text("Exiting..."); } } else { if (_download_progress != -1) { ImGui.AlignTextToFramePadding(); ImGui.Text("Download Progress: "); ImGui.SameLine(); ImGui.ProgressBar(_download_progress, new System.Numerics.Vector2(80, 25)); ImGui.SameLine(); if (ImGui.Button("Cancel", new System.Numerics.Vector2(50, 25))) { _download_progress = -1; _update_in_progress = false; _download_cancel_tokensrc.Cancel(); } } } } }
private void WriteLogContentTable() { Logging.LOG_EVENT[] msgs = Logging.GetLogMessages(null, _LogFilters); int activeCount = _LogFilters.Where(x => x is true).Count(); _textFilterLen = Array.FindIndex(textFilterValue, x => x == '\0'); string textFilterString = Encoding.ASCII.GetString(textFilterValue, 0, _textFilterLen); ImGuiTableFlags tableFlags = ImGuiTableFlags.SizingStretchProp | ImGuiTableFlags.RowBg | ImGuiTableFlags.Borders | ImGuiTableFlags.Resizable | ImGuiTableFlags.Reorderable | ImGuiTableFlags.ScrollY | ImGuiTableFlags.ScrollX; //this is causing issues with the last column. using 4 columns makes it a bit better //tableFlags |= ImGuiTableFlags.Sortable; //tableFlags |= ImGuiTableFlags.SortMulti; if (ImGui.BeginTable("LogsTableContent", 3, tableFlags)) { var ss = ImGui.TableGetSortSpecs(); //if (ss.SpecsDirty || _refreshTimerFired) if (_refreshTimerFired) { RegenerateRows(new List <LOG_EVENT>(msgs)); _refreshTimerFired = false; _refreshTimer.Start(); } ImGui.TableSetupScrollFreeze(0, 1); ImGui.TableSetupColumn("Time", ImGuiTableColumnFlags.WidthFixed, 170); // | ImGuiTableColumnFlags.DefaultSort | ImGuiTableColumnFlags.PreferSortDescending); ImGui.TableSetupColumn("Source", ImGuiTableColumnFlags.WidthFixed, 200); //;//", ImGuiTableColumnFlags.WidthFixed); ImGui.TableSetupColumn("Details"); //, ImGuiTableColumnFlags.WidthStretch | ImGuiTableColumnFlags.NoSort); ImGui.TableHeadersRow(); for (var i = 0; i < _sortedMsgs.Count; i++) { LOG_EVENT msg = _sortedMsgs[i]; DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds(msg.EventTimeMS); string timeString = dateTimeOffset.ToString("HH:mm:ss:ff"); string msgString; string sourceString; switch (msg.LogType) { case eLogFilterBaseType.Text: { Logging.TEXT_LOG_EVENT text_evt = (Logging.TEXT_LOG_EVENT)msg; sourceString = $"{text_evt.Filter}"; msgString = text_evt.Text; break; } case eLogFilterBaseType.TimeLine: { Logging.TIMELINE_EVENT tl_evt = (Logging.TIMELINE_EVENT)msg; sourceString = $"{tl_evt.Filter}"; msgString = string.Join("", tl_evt.Label().Select(l => l.Item1)); break; } default: sourceString = ""; msgString = "Other event type " + msg.LogType.ToString(); break; } if (_textFilterLen > 0) { string lowerFilter = textFilterString.ToLowerInvariant(); if (!msgString.ToLowerInvariant().Contains(textFilterString) && !sourceString.ToLowerInvariant().Contains(textFilterString) && !timeString.Contains(textFilterString)) { continue; } } ImGui.TableNextRow(); ImGui.TableNextColumn(); ImGui.Text($"{ImGuiController.FA_ICON_ADDFILE} {timeString}"); if (ImGui.BeginPopupContextItem($"#LogClick{i}", ImGuiPopupFlags.MouseButtonLeft)) // <-- This is using IsItemHovered() { if (ImGui.MenuItem("Copy Details")) { ImGuiUtils.WriteToClipboard(msgString); } if (ImGui.MenuItem("Copy Line")) { ImGuiUtils.WriteToClipboard($"{timeString}; {sourceString}; {msgString}"); } ImGui.EndPopup(); } ImGui.TableNextColumn(); ImGui.Text(sourceString); ImGui.TableNextColumn(); ImGui.TextWrapped(msgString); } ImGui.EndTable(); } }