// Sets the resource logger state when toggled, // and the filter when entered. private void DrawRequestedResourceLogging() { var tmp = Penumbra.Config.EnableResourceLogging; if (ImGui.Checkbox("##resourceLogging", ref tmp)) { _window._penumbra.ResourceLogger.SetState(tmp); } ImGui.SameLine(); ImGuiUtil.LabeledHelpMarker("Enable Requested Resource Logging", "Log all game paths FFXIV requests to the plugin log.\n" + "You can filter the logged paths for those containing the entered string or matching the regex, if the entered string compiles to a valid regex.\n" + "Red boundary indicates invalid regex."); ImGui.SameLine(); // Red borders if the string is not a valid regex. var tmpString = Penumbra.Config.ResourceLoggingFilter; using var color = ImRaii.PushColor(ImGuiCol.Border, Colors.RegexWarningBorder, !_window._penumbra.ResourceLogger.ValidRegex); using var style = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, ImGuiHelpers.GlobalScale, !_window._penumbra.ResourceLogger.ValidRegex); ImGui.SetNextItemWidth(-1); if (ImGui.InputTextWithHint("##ResourceLogFilter", "Filter...", ref tmpString, Utf8GamePath.MaxGamePathLength)) { _window._penumbra.ResourceLogger.SetFilter(tmpString); } }
private bool _dialogOpen; // For toggling on/off. // Do not change the directory without explicitly pressing enter or this button. // Shows up only if the current input does not correspond to the current directory. private static bool DrawPressEnterWarning(string newName, string old, float width, bool saved) { using var color = ImRaii.PushColor(ImGuiCol.Button, Colors.PressEnterWarningBg); var w = new Vector2(width, 0); var symbol = '\0'; var(text, valid) = newName.Length > RootDirectoryMaxLength ? ($"Path is too long. The maximum length is {RootDirectoryMaxLength}.", false) : newName.Any(c => (symbol = c) > ( char )0x7F) ? ($"Path contains invalid symbol {symbol}. Only ASCII is allowed.", false) : ($"Press Enter or Click Here to Save (Current Directory: {old})", true); return((ImGui.Button(text, w) || saved) && valid); }
// Draw a big red bar if the current setting is inherited. private void DrawInheritedWarning() { if (!_inherited) { return; } using var color = ImRaii.PushColor(ImGuiCol.Button, Colors.PressEnterWarningBg); var width = new Vector2(ImGui.GetContentRegionAvail().X, 0); if (ImGui.Button($"These settings are inherited from {_collection.Name}.", width)) { Penumbra.CollectionManager.Current.SetModInheritance(_mod.Index, false); } ImGuiUtil.HoverTooltip("You can click this button to copy the current settings to the current selection.\n" + "You can also just change any setting, which will copy the settings with the single setting changed to the current selection."); }
// If any conflicts exist, show them in this tab. private unsafe void DrawConflictsTab() { using var tab = DrawTab(ConflictTabHeader, Tabs.Conflicts); if (!tab) { return; } using var box = ImRaii.ListBox("##conflicts", -Vector2.One); if (!box) { return; } foreach (var conflict in Penumbra.CollectionManager.Current.Conflicts(_mod)) { if (ImGui.Selectable(conflict.Mod2.Name) && conflict.Mod2 is Mod mod) { _window._selector.SelectByValue(mod); } ImGui.SameLine(); using (var color = ImRaii.PushColor(ImGuiCol.Text, conflict.HasPriority ? ColorId.HandledConflictMod.Value() : ColorId.ConflictingMod.Value())) { var priority = conflict.Mod2.Index < 0 ? conflict.Mod2.Priority : Penumbra.CollectionManager.Current[conflict.Mod2.Index].Settings !.Priority; ImGui.TextUnformatted($"(Priority {priority})"); } using var indent = ImRaii.PushIndent(30f); foreach (var data in conflict.Conflicts) { var _ = data switch { Utf8GamePath p => ImGuiNative.igSelectable_Bool(p.Path.Path, 0, ImGuiSelectableFlags.None, Vector2.Zero) > 0, MetaManipulation m => ImGui.Selectable(m.Manipulation?.ToString() ?? string.Empty), _ => false, }; } } }
// Draw the mod name in the game font with a 2px border, centered, // with at least the width of the version space to each side. private float DrawModName() { var decidingWidth = Math.Max(_secondRowWidth, ImGui.GetWindowWidth()); var offsetWidth = (decidingWidth - _modNameWidth) / 2; var offsetVersion = _modVersion.Length > 0 ? _modVersionWidth + ImGui.GetStyle().ItemSpacing.X + ImGui.GetStyle().WindowPadding.X : 0; var offset = Math.Max(offsetWidth, offsetVersion); if (offset > 0) { ImGui.SetCursorPosX(offset); } using var color = ImRaii.PushColor(ImGuiCol.Border, Colors.MetaInfoText); using var style = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, 2 * ImGuiHelpers.GlobalScale); using var font = ImRaii.PushFont(_nameFont.ImFont, _nameFont.Available); ImGuiUtil.DrawTextButton(_modName, Vector2.Zero, 0); return(offset); }
public static void DrawDiscordButton(float width) { const string discord = "Join Discord for Support"; const string address = @"https://discord.gg/kVva7DHV4r"; using var color = ImRaii.PushColor(ImGuiCol.Button, Colors.DiscordColor); if (ImGui.Button(discord, new Vector2(width, 0))) { try { var process = new ProcessStartInfo(address) { UseShellExecute = true, }; Process.Start(process); } catch { // ignored } } ImGuiUtil.HoverTooltip($"Open {address}"); }
// Draw a simple clipped table containing all changed items. private void DrawChangedItemTab() { // Functions in here for less pollution. bool FilterChangedItem(KeyValuePair <string, (SingleArray <IMod>, object?)> item) => (_changedItemFilter.IsEmpty || ChangedItemName(item.Key, item.Value.Item2) .Contains(_changedItemFilter.Lower, StringComparison.InvariantCultureIgnoreCase)) && (_changedItemModFilter.IsEmpty || item.Value.Item1.Any(m => m.Name.Contains(_changedItemModFilter))); void DrawChangedItemColumn(KeyValuePair <string, (SingleArray <IMod>, object?)> item) { ImGui.TableNextColumn(); DrawChangedItem(item.Key, item.Value.Item2, false); ImGui.TableNextColumn(); if (item.Value.Item1.Count > 0) { ImGui.TextUnformatted(item.Value.Item1[0].Name); if (item.Value.Item1.Count > 1) { ImGuiUtil.HoverTooltip(string.Join("\n", item.Value.Item1.Skip(1).Select(m => m.Name))); } } ImGui.TableNextColumn(); if (item.Value.Item2 is Item it) { using var color = ImRaii.PushColor(ImGuiCol.Text, ColorId.ItemId.Value()); ImGuiUtil.RightAlign($"({( ( Quad )it.ModelMain ).A})"); } } using var tab = ImRaii.TabItem("Changed Items"); if (!tab) { return; } // Draw filters. var varWidth = ImGui.GetContentRegionAvail().X - 400 * ImGuiHelpers.GlobalScale - ImGui.GetStyle().ItemSpacing.X; ImGui.SetNextItemWidth(400 * ImGuiHelpers.GlobalScale); LowerString.InputWithHint("##changedItemsFilter", "Filter Item...", ref _changedItemFilter, 128); ImGui.SameLine(); ImGui.SetNextItemWidth(varWidth); LowerString.InputWithHint("##changedItemsModFilter", "Filter Mods...", ref _changedItemModFilter, 128); using var child = ImRaii.Child("##changedItemsChild", -Vector2.One); if (!child) { return; } // Draw table of changed items. var height = ImGui.GetTextLineHeightWithSpacing() + 2 * ImGui.GetStyle().CellPadding.Y; var skips = ImGuiClip.GetNecessarySkips(height); using var list = ImRaii.Table("##changedItems", 3, ImGuiTableFlags.RowBg, -Vector2.One); if (!list) { return; } const ImGuiTableColumnFlags flags = ImGuiTableColumnFlags.NoResize | ImGuiTableColumnFlags.WidthFixed; ImGui.TableSetupColumn("items", flags, 400 * ImGuiHelpers.GlobalScale); ImGui.TableSetupColumn("mods", flags, varWidth - 100 * ImGuiHelpers.GlobalScale); ImGui.TableSetupColumn("id", flags, 100 * ImGuiHelpers.GlobalScale); var items = Penumbra.CollectionManager.Current.ChangedItems; var rest = _changedItemFilter.IsEmpty && _changedItemModFilter.IsEmpty ? ImGuiClip.ClippedDraw(items, skips, DrawChangedItemColumn, items.Count) : ImGuiClip.FilteredClippedDraw(items, skips, FilterChangedItem, DrawChangedItemColumn); ImGuiClip.DrawEndDummy(rest, height); }