Example #1
0
    // 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();
    }
Example #2
0
        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);
        }
Example #3
0
 public static void TableView(string label, Action callback, int column, ImGuiTableFlags flags = ImGuiTableFlags.None)
 {
     if (ImGui.BeginTable(label, column, flags))
     {
         callback?.Invoke();
         ImGui.EndTable();
     }
 }
Example #4
0
        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();
            }
        }
Example #5
0
        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();
            }
        }
Example #6
0
        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();
                }
            }
Example #7
0
            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();
                }
            }
Example #8
0
            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();
            }
Example #9
0
        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();
                }
            }
        }
Example #10
0
        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();
                        }
                    }
                }
            }
        }
Example #11
0
        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();
            }
        }