// Draw general information about mod and collection state. private void DrawDebugTabGeneral() { if (!ImGui.CollapsingHeader("General")) { return; } using var table = ImRaii.Table("##DebugGeneralTable", 2, ImGuiTableFlags.SizingFixedFit, new Vector2(-1, ImGui.GetTextLineHeightWithSpacing() * 1)); if (!table) { return; } var manager = Penumbra.ModManager; PrintValue("Penumbra Version", $"{Penumbra.Version} {DebugVersionString}"); PrintValue("Git Commit Hash", Penumbra.CommitHash); PrintValue("Current Collection", Penumbra.CollectionManager.Current.Name); PrintValue(" has Cache", Penumbra.CollectionManager.Current.HasCache.ToString()); PrintValue("Default Collection", Penumbra.CollectionManager.Default.Name); PrintValue(" has Cache", Penumbra.CollectionManager.Default.HasCache.ToString()); PrintValue("Mod Manager BasePath", manager.BasePath.Name); PrintValue("Mod Manager BasePath-Full", manager.BasePath.FullName); PrintValue("Mod Manager BasePath IsRooted", Path.IsPathRooted(Penumbra.Config.ModDirectory).ToString()); PrintValue("Mod Manager BasePath Exists", Directory.Exists(manager.BasePath.FullName).ToString()); PrintValue("Mod Manager Valid", manager.Valid.ToString()); PrintValue("Path Resolver Enabled", _window._penumbra.PathResolver.Enabled.ToString()); PrintValue("Music Manager Streaming Disabled", (!_window._penumbra.MusicManager.StreamingEnabled).ToString()); PrintValue("Web Server Enabled", (_window._penumbra.WebServer != null).ToString()); }
private unsafe void DrawResourceMap(ResourceCategory category, uint ext, StdMap <uint, Pointer <ResourceHandle> > *map) { if (map == null) { return; } var label = GetNodeLabel(( uint )category, ext, map->Count); using var tree = ImRaii.TreeNode(label); if (!tree || map->Count == 0) { return; } using var table = ImRaii.Table("##table", 4, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg); if (!table) { return; } ImGui.TableSetupColumn("Hash", ImGuiTableColumnFlags.WidthFixed, _hashColumnWidth); ImGui.TableSetupColumn("Ptr", ImGuiTableColumnFlags.WidthFixed, _hashColumnWidth); ImGui.TableSetupColumn("Path", ImGuiTableColumnFlags.WidthFixed, _pathColumnWidth); ImGui.TableSetupColumn("Refs", ImGuiTableColumnFlags.WidthFixed, _refsColumnWidth); ImGui.TableHeadersRow(); ResourceLoader.IterateResourceMap(map, (hash, r) => { // Filter unwanted names. if (_resourceManagerFilter.Length != 0 && !r->FileName.ToString().Contains(_resourceManagerFilter, StringComparison.InvariantCultureIgnoreCase)) { return; } var address = $"0x{( ulong )r:X}"; ImGuiUtil.TextNextColumn($"0x{hash:X8}"); ImGui.TableNextColumn(); ImGuiUtil.CopyOnClickSelectable(address); var resource = (Interop.Structs.ResourceHandle *)r; ImGui.TableNextColumn(); Text(resource); if (ImGui.IsItemClicked()) { var data = Interop.Structs.ResourceHandle.GetData(resource); if (data != null) { var length = ( int )Interop.Structs.ResourceHandle.GetLength(resource); ImGui.SetClipboardText(string.Join(" ", new ReadOnlySpan <byte>(data, length).ToArray().Select(b => b.ToString("X2")))); } } ImGuiUtil.HoverTooltip("Click to copy byte-wise file data to clipboard, if any."); ImGuiUtil.TextNextColumn(r->RefCount.ToString()); }); }
// 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 void DrawCharacterCollectionSelectors() { ImGui.Dummy(_window._defaultSpace); if (ImGui.CollapsingHeader("Active Collections", ImGuiTreeNodeFlags.DefaultOpen)) { ImGui.Dummy(_window._defaultSpace); DrawDefaultCollectionSelector(); ImGui.Dummy(_window._defaultSpace); foreach (var name in Penumbra.CollectionManager.Characters.Keys.OrderBy(k => k).ToArray()) { using var id = ImRaii.PushId(name); DrawCollectionSelector(string.Empty, _window._inputTextWidth.X, ModCollection.Type.Character, true, name); ImGui.SameLine(); if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Trash.ToIconString(), _window._iconButtonSize, string.Empty, false, true)) { Penumbra.CollectionManager.RemoveCharacterCollection(name); } ImGui.SameLine(); ImGui.AlignTextToFramePadding(); ImGui.TextUnformatted(name); } DrawNewCharacterCollection(); ImGui.NewLine(); } }
public static void Draw(ConfigWindow window, Mod mod) { using var spacing = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(3 * ImGuiHelpers.GlobalScale)); ImGui.SetNextItemWidth(window._inputTextWidth.X - window._iconButtonSize.X - 3 * ImGuiHelpers.GlobalScale); ImGui.InputTextWithHint("##newGroup", "Add new option group...", ref _newGroupName, 256); ImGui.SameLine(); var fileExists = File.Exists(mod.DefaultFile); var tt = fileExists ? "Open the default option json file in the text editor of your choice." : "The default option json file does not exist."; if (ImGuiUtil.DrawDisabledButton($"{FontAwesomeIcon.FileExport.ToIconString()}##defaultFile", window._iconButtonSize, tt, !fileExists, true)) { Process.Start(new ProcessStartInfo(mod.DefaultFile) { UseShellExecute = true }); } ImGui.SameLine(); var nameValid = Mod.Manager.VerifyFileName(mod, null, _newGroupName, false); tt = nameValid ? "Add new option group to the mod." : "Can not add a group of this name."; if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), window._iconButtonSize, tt, !nameValid, true)) { Penumbra.ModManager.AddModGroup(mod, SelectType.Single, _newGroupName); Reset(); } }
private void PathInputBox(string label, string hint, string tooltip, int which) { var tmp = which == 0 ? _pathLeft : _pathRight; using var spacing = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(3 * ImGuiHelpers.GlobalScale, 0)); ImGui.SetNextItemWidth(-ImGui.GetFrameHeight() - 3 * ImGuiHelpers.GlobalScale); ImGui.InputTextWithHint(label, hint, ref tmp, Utf8GamePath.MaxGamePathLength); if (ImGui.IsItemDeactivatedAfterEdit()) { UpdateImage(tmp, which); } ImGuiUtil.HoverTooltip(tooltip); ImGui.SameLine(); if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Folder.ToIconString(), new Vector2(ImGui.GetFrameHeight()), string.Empty, false, true)) { var startPath = Penumbra.Config.DefaultModImportPath.Length > 0 ? Penumbra.Config.DefaultModImportPath : _mod?.ModPath.FullName; void UpdatePath(bool success, List <string> paths) { if (success && paths.Count > 0) { UpdateImage(paths[0], which); } } _dialogManager.OpenFileDialog("Open Image...", "Textures{.png,.dds,.tex}", UpdatePath, 1, startPath); } }
// Draw either a website button if the source is a valid website address, // or a source text if it is not. private void DrawWebsite() { if (_websiteValid) { if (ImGui.SmallButton(_modWebsiteButton)) { try { var process = new ProcessStartInfo(_modWebsite) { UseShellExecute = true, }; Process.Start(process); } catch { // ignored } } ImGuiUtil.HoverTooltip(_modWebsite); } else { using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero); ImGuiUtil.TextColored(Colors.MetaInfoText, "from "); ImGui.SameLine(); style.Pop(); ImGui.TextUnformatted(_mod.Website); } }
// Draw information about the resident resource files. public unsafe void DrawDebugResidentResources() { if (!ImGui.CollapsingHeader("Resident Resources")) { return; } if (Penumbra.ResidentResources.Address == null || Penumbra.ResidentResources.Address->NumResources == 0) { return; } using var table = ImRaii.Table("##ResidentResources", 2, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit, -Vector2.UnitX); if (!table) { return; } for (var i = 0; i < Penumbra.ResidentResources.Address->NumResources; ++i) { var resource = Penumbra.ResidentResources.Address->ResourceList[i]; ImGui.TableNextColumn(); ImGui.TextUnformatted($"0x{( ulong )resource:X}"); ImGui.TableNextColumn(); Text(resource); } }
// Draw a tab to iterate over the main resource maps and see what resources are currently loaded. public void Draw() { if (!Penumbra.Config.DebugMode) { return; } using var tab = ImRaii.TabItem("Resource Manager"); if (!tab) { return; } // Filter for resources containing the input string. ImGui.SetNextItemWidth(-1); ImGui.InputTextWithHint("##resourceFilter", "Filter...", ref _resourceManagerFilter, Utf8GamePath.MaxGamePathLength); using var child = ImRaii.Child("##ResourceManagerTab", -Vector2.One); if (!child) { return; } unsafe { ResourceLoader.IterateGraphs(DrawCategoryContainer); } }
// Draw a single group selector as a combo box. // If a description is provided, add a help marker besides it. private void DrawSingleGroup(IModGroup group, int groupIdx) { if (group.Type != SelectType.Single || !group.IsOption) { return; } using var id = ImRaii.PushId(groupIdx); var selectedOption = _emptySetting ? 0 : ( int )_settings.Settings[groupIdx]; ImGui.SetNextItemWidth(_window._inputTextWidth.X * 3 / 4); using var combo = ImRaii.Combo(string.Empty, group[selectedOption].Name); if (combo) { for (var idx2 = 0; idx2 < group.Count; ++idx2) { if (ImGui.Selectable(group[idx2].Name, idx2 == selectedOption)) { Penumbra.CollectionManager.Current.SetModSetting(_mod.Index, groupIdx, ( uint )idx2); } } } combo.Dispose(); ImGui.SameLine(); if (group.Description.Length > 0) { ImGuiUtil.LabeledHelpMarker(group.Name, group.Description); } else { ImGui.TextUnformatted(group.Name); } }
private static void Target(ModPanel panel, IModGroup group, int groupIdx, int optionIdx) { // TODO drag options to other groups without options. using var target = ImRaii.DragDropTarget(); if (!target.Success || !ImGuiUtil.IsDropping(DragDropLabel)) { return; } if (_dragDropGroupIdx >= 0 && _dragDropOptionIdx >= 0) { if (_dragDropGroupIdx == groupIdx) { var sourceOption = _dragDropOptionIdx; panel._delayedActions.Enqueue(() => Penumbra.ModManager.MoveOption(panel._mod, groupIdx, sourceOption, optionIdx)); } else { // Move from one group to another by deleting, then adding the option. var sourceGroup = _dragDropGroupIdx; var sourceOption = _dragDropOptionIdx; var option = @group[_dragDropOptionIdx]; var priority = @group.OptionPriority(_dragDropGroupIdx); panel._delayedActions.Enqueue(() => { Penumbra.ModManager.DeleteOption(panel._mod, sourceGroup, sourceOption); Penumbra.ModManager.AddOption(panel._mod, groupIdx, option, priority); }); } } _dragDropGroupIdx = -1; _dragDropOptionIdx = -1; }
// Draw the text input for the mod directory, // as well as the directory picker button and the enter warning. private void DrawRootFolder() { _newModDirectory ??= Penumbra.Config.ModDirectory; var spacing = 3 * ImGuiHelpers.GlobalScale; using var group = ImRaii.Group(); ImGui.SetNextItemWidth(_window._inputTextWidth.X - spacing - _window._iconButtonSize.X); var save = ImGui.InputText("##rootDirectory", ref _newModDirectory, 64, ImGuiInputTextFlags.EnterReturnsTrue); using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(spacing, 0)); ImGui.SameLine(); DrawDirectoryPickerButton(); style.Pop(); ImGui.SameLine(); ImGuiUtil.LabeledHelpMarker("Root Directory", "This is where Penumbra will store your extracted mod files.\n" + "TTMP files are not copied, just extracted.\n" + "This directory needs to be accessible and you need write access here.\n" + "It is recommended that this directory is placed on a fast hard drive, preferably an SSD.\n" + "It should also be placed near the root of a logical drive - the shorter the total path to this folder, the better.\n" + "Definitely do not place it in your Dalamud directory or any sub-directory thereof."); group.Dispose(); ImGui.SameLine(); var pos = ImGui.GetCursorPosX(); ImGui.NewLine(); if (Penumbra.Config.ModDirectory != _newModDirectory && _newModDirectory.Length != 0 && DrawPressEnterWarning(_newModDirectory, Penumbra.Config.ModDirectory, pos, save)) { Penumbra.ModManager.DiscoverMods(_newModDirectory); } }
// Different supported sort modes as a combo. private void DrawFolderSortType() { var sortMode = Penumbra.Config.SortMode; ImGui.SetNextItemWidth(_window._inputTextWidth.X); using var combo = ImRaii.Combo("##sortMode", sortMode.Data().Name); if (combo) { foreach (var val in Enum.GetValues <SortMode>()) { var(name, desc) = val.Data(); if (ImGui.Selectable(name, val == sortMode) && val != sortMode) { Penumbra.Config.SortMode = val; _window._selector.SetFilterDirty(); Penumbra.Config.Save(); } ImGuiUtil.HoverTooltip(desc); } } combo.Dispose(); ImGuiUtil.LabeledHelpMarker("Sort Mode", "Choose the sort mode for the mod selector in the mods tab."); }
// Draw the whole settings tab as well as its contents. private void DrawSettingsTab() { using var tab = DrawTab(SettingsTabHeader, Tabs.Settings); if (!tab) { return; } using var child = ImRaii.Child("##settings"); if (!child) { return; } DrawInheritedWarning(); ImGui.Dummy(_window._defaultSpace); DrawEnabledInput(); ImGui.SameLine(); DrawPriorityInput(); DrawRemoveSettings(); ImGui.Dummy(_window._defaultSpace); for (var idx = 0; idx < _mod.Groups.Count; ++idx) { DrawSingleGroup(_mod.Groups[idx], idx); } ImGui.Dummy(_window._defaultSpace); for (var idx = 0; idx < _mod.Groups.Count; ++idx) { DrawMultiGroup(_mod.Groups[idx], idx); } }
// 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(); }
public static void DrawPopup(ConfigWindow window) { if (_mod == null) { return; } using var popup = ImRaii.Popup(PopupName); if (!popup) { return; } if (ImGui.IsWindowAppearing()) { ImGui.SetKeyboardFocusHere(); } ImGui.InputTextMultiline("##editDescription", ref _newDescription, 4096, ImGuiHelpers.ScaledVector2(800, 800)); ImGui.Dummy(window._defaultSpace); var buttonSize = ImGuiHelpers.ScaledVector2(100, 0); var width = 2 * buttonSize.X + 4 * ImGui.GetStyle().FramePadding.X + ImGui.GetStyle().ItemSpacing.X; ImGui.SetCursorPosX((800 * ImGuiHelpers.GlobalScale - width) / 2); var oldDescription = _newDescriptionIdx == Input.Description ? _mod.Description : _mod.Groups[_newDescriptionIdx].Description; var tooltip = _newDescription != oldDescription ? string.Empty : "No changes made yet."; if (ImGuiUtil.DrawDisabledButton("Save", buttonSize, tooltip, tooltip.Length > 0)) { switch (_newDescriptionIdx) { case Input.Description: Penumbra.ModManager.ChangeModDescription(_mod.Index, _newDescription); break; case >= 0: Penumbra.ModManager.ChangeGroupDescription(_mod, _newDescriptionIdx, _newDescription); break; } ImGui.CloseCurrentPopup(); } ImGui.SameLine(); if (ImGui.Button("Cancel", buttonSize) || ImGui.IsKeyPressed(ImGui.GetKeyIndex(ImGuiKey.Escape))) { _newDescriptionIdx = Input.None; _newDescription = string.Empty; ImGui.CloseCurrentPopup(); } }
// Draw the author text. private void DrawAuthor() { using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero); ImGuiUtil.TextColored(Colors.MetaInfoText, "by "); ImGui.SameLine(); style.Pop(); ImGui.TextUnformatted(_mod.Author); }
private static bool DrawMatrixInput(float width, ref Matrix4x4 matrix) { using var table = ImRaii.Table(string.Empty, 5, ImGuiTableFlags.BordersInner | ImGuiTableFlags.SizingFixedFit); if (!table) { return(false); } var changes = false; ImGui.TableNextColumn(); ImGui.TableNextColumn(); ImGuiUtil.Center("R"); ImGui.TableNextColumn(); ImGuiUtil.Center("G"); ImGui.TableNextColumn(); ImGuiUtil.Center("B"); ImGui.TableNextColumn(); ImGuiUtil.Center("A"); var inputWidth = width / 6; ImGui.TableNextColumn(); ImGui.AlignTextToFramePadding(); ImGui.Text("R "); changes |= DragFloat("##RR", inputWidth, ref matrix.M11); changes |= DragFloat("##RG", inputWidth, ref matrix.M12); changes |= DragFloat("##RB", inputWidth, ref matrix.M13); changes |= DragFloat("##RA", inputWidth, ref matrix.M14); ImGui.TableNextColumn(); ImGui.AlignTextToFramePadding(); ImGui.Text("G "); changes |= DragFloat("##GR", inputWidth, ref matrix.M21); changes |= DragFloat("##GG", inputWidth, ref matrix.M22); changes |= DragFloat("##GB", inputWidth, ref matrix.M23); changes |= DragFloat("##GA", inputWidth, ref matrix.M24); ImGui.TableNextColumn(); ImGui.AlignTextToFramePadding(); ImGui.Text("B "); changes |= DragFloat("##BR", inputWidth, ref matrix.M31); changes |= DragFloat("##BG", inputWidth, ref matrix.M32); changes |= DragFloat("##BB", inputWidth, ref matrix.M33); changes |= DragFloat("##BA", inputWidth, ref matrix.M34); ImGui.TableNextColumn(); ImGui.AlignTextToFramePadding(); ImGui.Text("A "); changes |= DragFloat("##AR", inputWidth, ref matrix.M41); changes |= DragFloat("##AG", inputWidth, ref matrix.M42); changes |= DragFloat("##AB", inputWidth, ref matrix.M43); changes |= DragFloat("##AA", inputWidth, ref matrix.M44); return(changes); }
public void Draw() { using var tab = ImRaii.TabItem("Collections"); if (!tab) { return; } DrawCharacterCollectionSelectors(); DrawMainSelectors(); }
// Draw information about the character utility class from SE, // displaying all files, their sizes, the default files and the default sizes. public unsafe void DrawDebugCharacterUtility() { if (!ImGui.CollapsingHeader("Character Utility")) { return; } using var table = ImRaii.Table("##CharacterUtility", 6, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit, -Vector2.UnitX); if (!table) { return; } for (var i = 0; i < CharacterUtility.RelevantIndices.Length; ++i) { var idx = CharacterUtility.RelevantIndices[i]; var resource = ( ResourceHandle * )Penumbra.CharacterUtility.Address->Resources[idx]; ImGui.TableNextColumn(); ImGui.TextUnformatted($"0x{( ulong )resource:X}"); ImGui.TableNextColumn(); Text(resource); ImGui.TableNextColumn(); ImGui.Selectable($"0x{resource->GetData().Data:X}"); if (ImGui.IsItemClicked()) { var(data, length) = resource->GetData(); if (data != IntPtr.Zero && length > 0) { ImGui.SetClipboardText(string.Join("\n", new ReadOnlySpan <byte>(( byte * )data, length).ToArray().Select(b => b.ToString("X2")))); } } ImGuiUtil.HoverTooltip("Click to copy bytes to clipboard."); ImGui.TableNextColumn(); ImGui.TextUnformatted($"{resource->GetData().Length}"); ImGui.TableNextColumn(); ImGui.Selectable($"0x{Penumbra.CharacterUtility.DefaultResources[ i ].Address:X}"); if (ImGui.IsItemClicked()) { ImGui.SetClipboardText(string.Join("\n", new ReadOnlySpan <byte>(( byte * )Penumbra.CharacterUtility.DefaultResources[i].Address, Penumbra.CharacterUtility.DefaultResources[i].Size).ToArray().Select(b => b.ToString("X2")))); } ImGuiUtil.HoverTooltip("Click to copy bytes to clipboard."); ImGui.TableNextColumn(); ImGui.TextUnformatted($"{Penumbra.CharacterUtility.DefaultResources[ i ].Size}"); } }
// Setup table sizes. private void SetupEffectiveSizes() { if (_effectiveUnscaledArrowLength == 0) { using var font = ImRaii.PushFont(UiBuilder.IconFont); _effectiveUnscaledArrowLength = ImGui.CalcTextSize(FontAwesomeIcon.LongArrowAltLeft.ToIconString()).X / ImGuiHelpers.GlobalScale; } _effectiveArrowLength = _effectiveUnscaledArrowLength * ImGuiHelpers.GlobalScale; _effectiveLeftTextLength = 450 * ImGuiHelpers.GlobalScale; _effectiveRightTextLength = ImGui.GetWindowSize().X - _effectiveArrowLength - _effectiveLeftTextLength; }
private void DrawMaterialChangeTab() { using var tab = ImRaii.TabItem("Model Materials"); if (!tab) { return; } if (_editor !.ModelFiles.Count == 0) { ImGui.NewLine(); ImGui.TextUnformatted("No .mdl files detected."); }
public static void DrawNew(Mod.Editor editor, Vector2 iconSize) { ImGui.TableNextColumn(); CopyToClipboardButton("Copy all current EQP manipulations to clipboard.", iconSize, editor.Meta.Eqp.Select(m => (MetaManipulation) m)); ImGui.TableNextColumn(); var canAdd = editor.Meta.CanAdd(_new); var tt = canAdd ? "Stage this edit." : "This entry is already edited."; var defaultEntry = ExpandedEqpFile.GetDefault(_new.SetId); if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), iconSize, tt, !canAdd, true)) { editor.Meta.Add(_new with { Entry = defaultEntry }); } // Identifier ImGui.TableNextColumn(); if (IdInput("##eqpId", IdWidth, _new.SetId, out var setId, ExpandedEqpGmpBase.Count - 1)) { _new = _new with { SetId = setId }; } ImGuiUtil.HoverTooltip("Model Set ID"); ImGui.TableNextColumn(); if (EqpEquipSlotCombo("##eqpSlot", _new.Slot, out var slot)) { _new = _new with { Slot = slot }; } ImGuiUtil.HoverTooltip("Equip Slot"); // Values ImGui.TableNextColumn(); using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(3 * ImGuiHelpers.GlobalScale, ImGui.GetStyle().ItemSpacing.Y)); foreach (var flag in Eqp.EqpAttributes[_new.Slot]) { var value = defaultEntry.HasFlag(flag); Checkmark("##eqp", flag.ToLocalName(), value, value, out _); ImGui.SameLine(); } ImGui.NewLine(); }
// Draw the edit tab that contains all things concerning editing the mod. private void DrawEditModTab() { using var tab = DrawTab(EditModTabHeader, Tabs.Edit); if (!tab) { return; } using var child = ImRaii.Child("##editChild", -Vector2.One); if (!child) { return; } _cellPadding = ImGui.GetStyle().CellPadding with { X = 2 * ImGuiHelpers.GlobalScale }; _itemSpacing = ImGui.GetStyle().CellPadding with { X = 4 * ImGuiHelpers.GlobalScale }; EditButtons(); EditRegularMeta(); ImGui.Dummy(_window._defaultSpace); if (Input.Text("Mod Path", Input.Path, Input.None, _leaf.FullName(), out var newPath, 256, _window._inputTextWidth.X)) { try { _window._penumbra.ModFileSystem.RenameAndMove(_leaf, newPath); } catch (Exception e) { PluginLog.Warning(e.Message); } } ImGui.Dummy(_window._defaultSpace); AddOptionGroup.Draw(_window, _mod); ImGui.Dummy(_window._defaultSpace); for (var groupIdx = 0; groupIdx < _mod.Groups.Count; ++groupIdx) { EditGroup(groupIdx); } EndActions(); DescriptionEdit.DrawPopup(_window); }
private static void Checkbox(string label, string tooltip, bool current, Action <bool> setter) { using var id = ImRaii.PushId(label); var tmp = current; if (ImGui.Checkbox(string.Empty, ref tmp) && tmp != current) { setter(tmp); Penumbra.Config.Save(); } ImGui.SameLine(); ImGuiUtil.LabeledHelpMarker(label, tooltip); }
private static void DrawOpenDirectoryButton(int id, DirectoryInfo directory, bool condition) { using var _ = ImRaii.PushId(id); var ret = ImGui.Button("Open Directory"); ImGuiUtil.HoverTooltip("Open this directory in your configured file explorer."); if (ret && condition && Directory.Exists(directory.FullName)) { Process.Start(new ProcessStartInfo(directory.FullName) { UseShellExecute = true, }); } }
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); }
// Anything about editing the regular meta information about the mod. private void EditRegularMeta() { if (Input.Text("Name", Input.Name, Input.None, _mod.Name, out var newName, 256, _window._inputTextWidth.X)) { Penumbra.ModManager.ChangeModName(_mod.Index, newName); } if (Input.Text("Author", Input.Author, Input.None, _mod.Author, out var newAuthor, 256, _window._inputTextWidth.X)) { Penumbra.ModManager.ChangeModAuthor(_mod.Index, newAuthor); } if (Input.Text("Version", Input.Version, Input.None, _mod.Version, out var newVersion, 32, _window._inputTextWidth.X)) { Penumbra.ModManager.ChangeModVersion(_mod.Index, newVersion); } if (Input.Text("Website", Input.Website, Input.None, _mod.Website, out var newWebsite, 256, _window._inputTextWidth.X)) { Penumbra.ModManager.ChangeModWebsite(_mod.Index, newWebsite); } var spacing = new Vector2(3 * ImGuiHelpers.GlobalScale); using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing); var reducedSize = new Vector2(_window._inputTextWidth.X - _window._iconButtonSize.X - spacing.X, 0); if (ImGui.Button("Edit Description", reducedSize)) { _delayedActions.Enqueue(() => DescriptionEdit.OpenPopup(_mod, Input.Description)); } ImGui.SameLine(); var fileExists = File.Exists(_mod.MetaFile.FullName); var tt = fileExists ? "Open the metadata json file in the text editor of your choice." : "The metadata json file does not exist."; if (ImGuiUtil.DrawDisabledButton($"{FontAwesomeIcon.FileExport.ToIconString()}##metaFile", _window._iconButtonSize, tt, !fileExists, true)) { Process.Start(new ProcessStartInfo(_mod.MetaFile.FullName) { UseShellExecute = true }); } }
// Draw the header line that can quick switch between collections. private void DrawHeaderLine() { using var style = ImRaii.PushStyle(ImGuiStyleVar.FrameRounding, 0).Push(ImGuiStyleVar.ItemSpacing, Vector2.Zero); var buttonSize = new Vector2(ImGui.GetContentRegionAvail().X / 8f, 0); DrawDefaultCollectionButton(3 * buttonSize); ImGui.SameLine(); DrawInheritedCollectionButton(3 * buttonSize); ImGui.SameLine(); DrawCollectionSelector("##collectionSelector", 2 * buttonSize.X, ModCollection.Type.Current, false, null); if (!Penumbra.CollectionManager.CurrentCollectionInUse) { ImGuiUtil.DrawTextButton("The currently selected collection is not used in any way.", -Vector2.UnitX, Colors.PressEnterWarningBg); } }
// Draw a full category for the resource manager. private unsafe void DrawCategoryContainer(ResourceCategory category, StdMap <uint, Pointer <StdMap <uint, Pointer <ResourceHandle> > > > *map) { if (map == null) { return; } using var tree = ImRaii.TreeNode($"({( uint )category:D2}) {category} - {map->Count}###{( uint )category}"); if (tree) { SetTableWidths(); ResourceLoader.IterateExtMap(map, (ext, m) => DrawResourceMap(category, ext, m)); } }