// Toggling audio streaming will need to apply to the music manager
        // and rediscover mods due to determining whether .scds will be loaded or not.
        private void DrawDisableSoundStreamingBox()
        {
            var tmp = Penumbra.Config.DisableSoundStreaming;

            if (ImGui.Checkbox("##streaming", ref tmp) && tmp != Penumbra.Config.DisableSoundStreaming)
            {
                Penumbra.Config.DisableSoundStreaming = tmp;
                Penumbra.Config.Save();
                if (tmp)
                {
                    _window._penumbra.MusicManager.DisableStreaming();
                }
                else
                {
                    _window._penumbra.MusicManager.EnableStreaming();
                }

                Penumbra.ModManager.DiscoverMods();
            }

            ImGui.SameLine();
            ImGuiUtil.LabeledHelpMarker("Enable Sound Modification",
                                        "Disable streaming in the games audio engine. The game enables this by default, and Penumbra should disable it.\n"
                                        + "If this is unchecked, you can not replace sound files in the game (*.scd files), they will be ignored by Penumbra.\n\n"
                                        + "Only touch this if you experience sound problems like audio stuttering.\n"
                                        + "If you toggle this, make sure no modified or to-be-modified sound file is currently playing or was recently playing, else you might crash.\n"
                                        + "You might need to restart your game for this to fully take effect.");
        }
        // 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);
            }
        }
Example #3
0
    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);
        }
    }
 private static void DrawReloadFontsButton()
 {
     if (ImGuiUtil.DrawDisabledButton("Reload Fonts", Vector2.Zero, "Force the game to reload its font files.", !FontReloader.Valid))
     {
         FontReloader.Reload();
     }
 }
Example #5
0
        private void BackupButtons(Vector2 buttonSize)
        {
            var backup = new ModBackup(_mod);
            var tt     = ModBackup.CreatingBackup
                ? "Already creating a backup."
                : backup.Exists
                    ? $"Overwrite current backup \"{backup.Name}\" with current mod."
                    : $"Create backup archive of current mod at \"{backup.Name}\".";

            if (ImGuiUtil.DrawDisabledButton("Create Backup", buttonSize, tt, ModBackup.CreatingBackup))
            {
                backup.CreateAsync();
            }

            ImGui.SameLine();
            tt = backup.Exists
                ? $"Delete existing backup file \"{backup.Name}\"."
                : $"Backup file \"{backup.Name}\" does not exist.";
            if (ImGuiUtil.DrawDisabledButton("Delete Backup", buttonSize, tt, !backup.Exists))
            {
                backup.Delete();
            }

            tt = backup.Exists
                ? $"Restore mod from backup file \"{backup.Name}\"."
                : $"Backup file \"{backup.Name}\" does not exist.";
            ImGui.SameLine();
            if (ImGuiUtil.DrawDisabledButton("Restore From Backup", buttonSize, tt, !backup.Exists))
            {
                backup.Restore();
            }
        }
Example #6
0
            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();
                }
            }
Example #7
0
        // Draw a directory picker button that toggles the directory picker.
        // Selecting a directory does behave the same as writing in the text input, i.e. needs to be saved.
        private void DrawDirectoryPickerButton()
        {
            if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Folder.ToIconString(), _window._iconButtonSize,
                                             "Select a directory via dialog.", false, true))
            {
                if (_dialogOpen)
                {
                    _dialogManager.Reset();
                    _dialogOpen = false;
                }
                else
                {
                    _newModDirectory ??= Penumbra.Config.ModDirectory;
                    // Use the current input as start directory if it exists,
                    // otherwise the current mod directory, otherwise the current application directory.
                    var startDir = Directory.Exists(_newModDirectory)
                        ? _newModDirectory
                        : Directory.Exists(Penumbra.Config.ModDirectory)
                            ? Penumbra.Config.ModDirectory
                            : ".";

                    _dialogManager.OpenFolderDialog("Choose Mod Directory", (b, s) =>
                    {
                        _newModDirectory = b ? s : _newModDirectory;
                        _dialogOpen      = false;
                    }, startDir);
                    _dialogOpen = true;
                }
            }
        }
 private void DrawDefaultCollectionSelector()
 {
     DrawCollectionSelector("##default", _window._inputTextWidth.X, ModCollection.Type.Default, true, null);
     ImGui.SameLine();
     ImGuiUtil.LabeledHelpMarker("Default Collection",
                                 "Mods in the default collection are loaded for any character that is not explicitly named in the character collections below.\n");
 }
        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();
            }
        }
        // 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.");
        }
Example #11
0
    protected override void DrawPopups()
    {
        _fileManager.Draw();
        DrawHelpPopup();
        DrawInfoPopup();

        if (ImGuiUtil.OpenNameField("Create New Mod", ref _newModName))
        {
            try
            {
                var newDir = Mod.CreateModFolder(Penumbra.ModManager.BasePath, _newModName);
                Mod.CreateMeta(newDir, _newModName, Penumbra.Config.DefaultModAuthor, string.Empty, "1.0", string.Empty);
                Mod.CreateDefaultFiles(newDir);
                Penumbra.ModManager.AddMod(newDir);
                _newModName = string.Empty;
            }
            catch (Exception e)
            {
                PluginLog.Error($"Could not create directory for new Mod {_newModName}:\n{e}");
            }
        }

        while (_modsToAdd.TryDequeue(out var dir))
        {
            Penumbra.ModManager.AddMod(dir);
            var mod = Penumbra.ModManager.LastOrDefault();
            if (mod != null)
            {
                MoveModToDefaultDirectory(mod);
                SelectByValue(mod);
            }
        }
    }
Example #12
0
        // The general edit row for non-detailed mod edits.
        private void EditButtons()
        {
            var buttonSize   = new Vector2(150 * ImGuiHelpers.GlobalScale, 0);
            var folderExists = Directory.Exists(_mod.ModPath.FullName);
            var tt           = folderExists
                ? $"Open \"{_mod.ModPath.FullName}\" in the file explorer of your choice."
                : $"Mod directory \"{_mod.ModPath.FullName}\" does not exist.";

            if (ImGuiUtil.DrawDisabledButton("Open Mod Directory", buttonSize, tt, !folderExists))
            {
                Process.Start(new ProcessStartInfo(_mod.ModPath.FullName)
                {
                    UseShellExecute = true
                });
            }

            ImGui.SameLine();
            if (ImGuiUtil.DrawDisabledButton("Reload Mod", buttonSize, "Reload the current mod from its files.\n"
                                             + "If the mod directory or meta file do not exist anymore or if the new mod name is empty, the mod is deleted instead.",
                                             false))
            {
                Penumbra.ModManager.ReloadMod(_mod.Index);
            }

            BackupButtons(buttonSize);
            MoveDirectory.Draw(_mod, buttonSize);

            ImGui.Dummy(_window._defaultSpace);
        }
Example #13
0
        // 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);
            }
        }
Example #14
0
            // Draw the line to add a new option.
            private static void DrawNewOption(Mod mod, int groupIdx, Vector2 iconButtonSize)
            {
                ImGui.TableNextColumn();
                ImGui.TableNextColumn();
                ImGui.SetNextItemWidth(-1);
                var tmp = _newOptionNameIdx == groupIdx ? _newOptionName : string.Empty;

                if (ImGui.InputTextWithHint("##newOption", "Add new option...", ref tmp, 256))
                {
                    _newOptionName    = tmp;
                    _newOptionNameIdx = groupIdx;
                }

                ImGui.TableNextColumn();
                var canAddGroup = mod.Groups[groupIdx].Type != SelectType.Multi || mod.Groups[groupIdx].Count < IModGroup.MaxMultiOptions;
                var validName   = _newOptionName.Length > 0 && _newOptionNameIdx == groupIdx;
                var tt          = canAddGroup
                    ? validName ? "Add a new option to this group." : "Please enter a name for the new option."
                    : $"Can not add more than {IModGroup.MaxMultiOptions} options to a multi group.";

                if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), iconButtonSize,
                                                 tt, !(canAddGroup && validName), true))
                {
                    Penumbra.ModManager.AddOption(mod, groupIdx, _newOptionName);
                    _newOptionName = string.Empty;
                }
            }
Example #15
0
            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;
            }
Example #16
0
            public static void Draw(Mod mod, Vector2 buttonSize)
            {
                ImGui.SetNextItemWidth(buttonSize.X * 2 + ImGui.GetStyle().ItemSpacing.X);
                var tmp = _currentModDirectory ?? mod.ModPath.Name;

                if (ImGui.InputText("##newModMove", ref tmp, 64))
                {
                    _currentModDirectory = tmp;
                    _state = Mod.Manager.NewDirectoryValid(mod.ModPath.Name, _currentModDirectory, out _);
                }

                var(disabled, tt) = _state switch
                {
                    Mod.Manager.NewDirectoryState.Identical => (true, "Current directory name is identical to new one."),
                    Mod.Manager.NewDirectoryState.Empty => (true, "Please enter a new directory name first."),
                    Mod.Manager.NewDirectoryState.NonExisting => (false, $"Move mod from {mod.ModPath.Name} to {_currentModDirectory}."),
                    Mod.Manager.NewDirectoryState.ExistsEmpty => (false, $"Move mod from {mod.ModPath.Name} to {_currentModDirectory}."),
                    Mod.Manager.NewDirectoryState.ExistsNonEmpty => (true, $"{_currentModDirectory} already exists and is not empty."),
                    Mod.Manager.NewDirectoryState.ExistsAsFile => (true, $"{_currentModDirectory} exists as a file."),
                    Mod.Manager.NewDirectoryState.ContainsInvalidSymbols => (true,
                                                                             $"{_currentModDirectory} contains invalid symbols for FFXIV."),
                    _ => (true, "Unknown error."),
                };
                ImGui.SameLine();
                if (ImGuiUtil.DrawDisabledButton("Rename Mod Directory", buttonSize, tt, disabled) && _currentModDirectory != null)
                {
                    Penumbra.ModManager.MoveModDirectory(mod.Index, _currentModDirectory);
                    Reset();
                }

                ImGui.SameLine();
                ImGuiComponents.HelpMarker(
                    "The mod directory name is used to correspond stored settings and sort orders, otherwise it has no influence on anything that is displayed.\n"
                    + "This can currently not be used on pre-existing folders and does not support merges or overwriting.");
            }
Example #17
0
        // 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);
            }
        }
 private void DrawCurrentCollectionSelector()
 {
     DrawCollectionSelector("##current", _window._inputTextWidth.X, ModCollection.Type.Current, false, null);
     ImGui.SameLine();
     ImGuiUtil.LabeledHelpMarker("Current Collection",
                                 "This collection will be modified when using the Installed Mods tab and making changes. It does not apply to anything by itself.");
 }
Example #19
0
        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());
            });
        }
        // 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);
            }
        }
Example #21
0
            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);
 }
        // Draw the version in the top-right corner.
        private void DrawVersion(float offset)
        {
            var oldPos = ImGui.GetCursorPos();

            ImGui.SetCursorPos(new Vector2(2 * offset + _modNameWidth - _modVersionWidth - ImGui.GetStyle().WindowPadding.X,
                                           ImGui.GetStyle().FramePadding.Y));
            ImGuiUtil.TextColored(Colors.MetaInfoText, _modVersion);
            ImGui.SetCursorPos(oldPos);
        }
Example #24
0
    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);
    }
        private static void DrawReloadResourceButton()
        {
            if (ImGui.Button("Reload Resident Resources"))
            {
                Penumbra.ResidentResources.Reload();
            }

            ImGuiUtil.HoverTooltip("Reload some specific files that the game keeps in memory at all times.\n"
                                   + "You usually should not need to do this.");
        }
Example #26
0
        // 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}");
            }
        }
 // Only gets drawn when actually relevant.
 private static void DrawCleanCollectionButton()
 {
     if (Penumbra.Config.ShowAdvanced && Penumbra.CollectionManager.Current.HasUnusedSettings)
     {
         ImGui.SameLine();
         if (ImGuiUtil.DrawDisabledButton("Clean Settings", Vector2.Zero
                                          , "Remove all stored settings for mods not currently available and fix invalid settings.\nUse at own risk."
                                          , false))
         {
             Penumbra.CollectionManager.Current.CleanUnavailableSettings();
         }
     }
 }
Example #28
0
        private static void DrawRediscoverButton()
        {
            DrawOpenDirectoryButton(0, Penumbra.ModManager.BasePath, Penumbra.ModManager.Valid);
            ImGui.SameLine();
            var tt = Penumbra.ModManager.Valid
                ? "Force Penumbra to completely re-scan your root directory as if it was restarted."
                : "The currently selected folder is not valid. Please select a different folder.";

            if (ImGuiUtil.DrawDisabledButton("Rediscover Mods", Vector2.Zero, tt, !Penumbra.ModManager.Valid))
            {
                Penumbra.ModManager.DiscoverMods();
            }
        }
Example #29
0
        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();
        }
Example #30
0
        public static void Draw(Mod.Editor editor, Vector2 buttonSize)
        {
            DrawRaceCodeCombo(buttonSize);
            ImGui.SameLine();
            ImGui.SetNextItemWidth(buttonSize.X);
            ImGui.InputTextWithHint("##suffixFrom", "From...", ref _materialSuffixFrom, 32);
            ImGui.SameLine();
            ImGui.SetNextItemWidth(buttonSize.X);
            ImGui.InputTextWithHint("##suffixTo", "To...", ref _materialSuffixTo, 32);
            ImGui.SameLine();
            var disabled = !Mod.Editor.ValidString(_materialSuffixTo);
            var tt       = _materialSuffixTo.Length == 0
                ? "Please enter a target suffix."
                : _materialSuffixFrom == _materialSuffixTo
                    ? "The source and target are identical."
                    : disabled
                        ? "The suffix is invalid."
                        : _materialSuffixFrom.Length == 0
                            ? _raceCode == GenderRace.Unknown
                                ? "Convert all skin material suffices to the target."
                                : "Convert all skin material suffices for the given race code to the target."
                            : _raceCode == GenderRace.Unknown
                                ? $"Convert all skin material suffices that are currently '{_materialSuffixFrom}' to '{_materialSuffixTo}'."
                                : $"Convert all skin material suffices for the given race code that are currently '{_materialSuffixFrom}' to '{_materialSuffixTo}'.";

            if (ImGuiUtil.DrawDisabledButton("Change Material Suffix", buttonSize, tt, disabled))
            {
                editor.ReplaceAllMaterials(_materialSuffixTo, _materialSuffixFrom, _raceCode);
            }

            var anyChanges = editor.ModelFiles.Any(m => m.Changed);

            if (ImGuiUtil.DrawDisabledButton("Save All Changes", buttonSize,
                                             anyChanges ? "Irreversibly rewrites all currently applied changes to model files." : "No changes made yet.", !anyChanges))
            {
                editor.SaveAllModels();
            }

            ImGui.SameLine();
            if (ImGuiUtil.DrawDisabledButton("Revert All Changes", buttonSize,
                                             anyChanges ? "Revert all currently made and unsaved changes." : "No changes made yet.", !anyChanges))
            {
                editor.RestoreAllModels();
            }

            ImGui.SameLine();
            ImGuiComponents.HelpMarker(
                "Model files refer to the skin material they should use. This skin material is always the same, but modders have started using different suffices to differentiate between body types.\n"
                + "This option allows you to switch the suffix of all model files to another. This changes the files, so you do this on your own risk.\n"
                + "If you do not know what the currently used suffix of this mod is, you can leave 'From' blank and it will replace all suffices with 'To', instead of only the matching ones.");
        }