├── .editorconfig ├── .github └── workflows │ └── dotnet.yml ├── .gitignore ├── .gitmodules ├── CustomizePlus.sln ├── CustomizePlus ├── CustomizePlus.csproj ├── DalamudPackager.targets ├── Extensions │ └── CommandManagerExtensions.cs ├── GlobalSuppressions.cs ├── Helpers │ ├── ChatHelper.cs │ └── CtrlHelper.cs ├── Plugin.cs ├── Services │ └── DalamudServices.cs ├── UI │ ├── UserInterfaceBase.cs │ ├── UserInterfaceManager.cs │ ├── WindowBase.cs │ └── Windows │ │ └── MainWindow.cs └── customizePlus.json ├── Data ├── NotoSansCJKjp-Medium.otf ├── customizePlus.json ├── gamesym.ttf └── icon.png ├── LICENSE.md └── README.md /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | file_header_template = © Customize+.\nLicensed under the MIT license. 4 | 5 | dotnet_diagnostic.sa1000.severity = none 6 | dotnet_diagnostic.sa1027.severity = none 7 | dotnet_diagnostic.sa1600.severity = none 8 | dotnet_diagnostic.sa1503.severity = none 9 | dotnet_diagnostic.sa1633.severity = none 10 | dotnet_diagnostic.sa1401.severity = none 11 | dotnet_diagnostic.sa1601.severity = none 12 | dotnet_diagnostic.sa1602.severity = none 13 | dotnet_diagnostic.sa1516.severity = none 14 | dotnet_diagnostic.sa1618.severity = none 15 | dotnet_diagnostic.sa1611.severity = none 16 | dotnet_diagnostic.sa1615.severity = none 17 | dotnet_diagnostic.sa1011.severity = none 18 | dotnet_diagnostic.sa1134.severity = none 19 | 20 | dotnet_diagnostic.ide0011.severity = none 21 | dotnet_diagnostic.ide0022.severity = none 22 | dotnet_diagnostic.ide0023.severity = none 23 | dotnet_diagnostic.ide1006.severity = warning 24 | dotnet_diagnostic.ide0044.severity = suggestion 25 | dotnet_diagnostic.ide0058.severity = none 26 | dotnet_diagnostic.ide0073.severity = warning 27 | dotnet_diagnostic.ide0025.severity = none 28 | dotnet_diagnostic.ide0027.severity = none 29 | dotnet_diagnostic.ide0059.severity = none 30 | dotnet_diagnostic.ide0065.severity = none 31 | 32 | dotnet_diagnostic.unt0001.severity = warning 33 | dotnet_diagnostic.unt0002.severity = warning 34 | dotnet_diagnostic.unt0003.severity = warning 35 | dotnet_diagnostic.unt0004.severity = warning 36 | dotnet_diagnostic.unt0005.severity = warning 37 | dotnet_diagnostic.unt0006.severity = warning 38 | dotnet_diagnostic.unt0007.severity = warning 39 | dotnet_diagnostic.unt0008.severity = warning 40 | dotnet_diagnostic.unt0009.severity = warning 41 | dotnet_diagnostic.unt0010.severity = warning 42 | dotnet_diagnostic.unt0011.severity = warning 43 | dotnet_diagnostic.unt0012.severity = warning 44 | dotnet_diagnostic.unt0013.severity = none 45 | dotnet_diagnostic.unt0014.severity = warning 46 | dotnet_diagnostic.unt0015.severity = warning 47 | dotnet_diagnostic.unt0016.severity = warning 48 | dotnet_diagnostic.unt0017.severity = warning 49 | dotnet_diagnostic.unt0018.severity = warning 50 | dotnet_diagnostic.unt0019.severity = warning 51 | dotnet_diagnostic.unt0020.severity = warning 52 | 53 | dotnet_diagnostic.cs1591.severity = none 54 | dotnet_diagnostic.cs0067.severity = none 55 | 56 | dotnet_diagnostic.ca1416.severity = none 57 | dotnet_diagnostic.ca2201.severity = none 58 | 59 | # SA1101: Prefix local calls with this 60 | dotnet_diagnostic.sa1101.severity = silent 61 | 62 | # CS8602: Dereference of a possibly null reference. 63 | dotnet_diagnostic.cs8602.severity = silent 64 | 65 | # CS0168: Variable is declared but never used 66 | dotnet_diagnostic.cs0168.severity = silent 67 | 68 | # CS8600: Converting null literal or possible null value to non-nullable type. 69 | dotnet_diagnostic.cs8600.severity = suggestion 70 | 71 | [*.{cs,vb}] 72 | dotnet_style_operator_placement_when_wrapping = beginning_of_line 73 | tab_width = 4 74 | indent_size = 4 75 | end_of_line = crlf 76 | dotnet_style_coalesce_expression = true:suggestion 77 | dotnet_style_null_propagation = true:suggestion 78 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion 79 | dotnet_style_prefer_auto_properties = true:silent 80 | dotnet_style_object_initializer = true:suggestion 81 | dotnet_style_collection_initializer = true:suggestion 82 | dotnet_style_prefer_simplified_boolean_expressions = true:suggestion 83 | dotnet_style_prefer_conditional_expression_over_assignment = true:silent 84 | dotnet_style_prefer_conditional_expression_over_return = true:silent 85 | dotnet_style_explicit_tuple_names = true:suggestion 86 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 87 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion 88 | dotnet_style_prefer_compound_assignment = true:suggestion 89 | dotnet_style_prefer_simplified_interpolation = true:suggestion 90 | dotnet_style_namespace_match_folder = true:suggestion 91 | [*.{cs,vb}] 92 | #### Naming styles #### 93 | 94 | # Naming rules 95 | 96 | dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion 97 | dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface 98 | dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i 99 | 100 | dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion 101 | dotnet_naming_rule.types_should_be_pascal_case.symbols = types 102 | dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case 103 | 104 | dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion 105 | dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members 106 | dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case 107 | 108 | # Symbol specifications 109 | 110 | dotnet_naming_symbols.interface.applicable_kinds = interface 111 | dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 112 | dotnet_naming_symbols.interface.required_modifiers = 113 | 114 | dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum 115 | dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 116 | dotnet_naming_symbols.types.required_modifiers = 117 | 118 | dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method 119 | dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 120 | dotnet_naming_symbols.non_field_members.required_modifiers = 121 | 122 | # Naming styles 123 | 124 | dotnet_naming_style.begins_with_i.required_prefix = I 125 | dotnet_naming_style.begins_with_i.required_suffix = 126 | dotnet_naming_style.begins_with_i.word_separator = 127 | dotnet_naming_style.begins_with_i.capitalization = pascal_case 128 | 129 | dotnet_naming_style.pascal_case.required_prefix = 130 | dotnet_naming_style.pascal_case.required_suffix = 131 | dotnet_naming_style.pascal_case.word_separator = 132 | dotnet_naming_style.pascal_case.capitalization = pascal_case 133 | 134 | dotnet_naming_style.pascal_case.required_prefix = 135 | dotnet_naming_style.pascal_case.required_suffix = 136 | dotnet_naming_style.pascal_case.word_separator = 137 | dotnet_naming_style.pascal_case.capitalization = pascal_case 138 | 139 | # Default severity for analyzer diagnostics with category 'StyleCop.CSharp.SpacingRules' 140 | dotnet_analyzer_diagnostic.category-stylecop.csharp.spacingrules.severity = silent 141 | 142 | # Default severity for analyzer diagnostics with category 'StyleCop.CSharp.ReadabilityRules' 143 | dotnet_analyzer_diagnostic.category-stylecop.csharp.readabilityrules.severity = silent 144 | 145 | # Default severity for analyzer diagnostics with category 'StyleCop.CSharp.LayoutRules' 146 | dotnet_analyzer_diagnostic.category-stylecop.csharp.layoutrules.severity = silent 147 | 148 | # Default severity for analyzer diagnostics with category 'StyleCop.CSharp.OrderingRules' 149 | dotnet_analyzer_diagnostic.category-stylecop.csharp.orderingrules.severity = silent 150 | 151 | [*.{asax,ascx,aspx,axaml,cs,cshtml,htm,html,master,paml,razor,skin,vb,xaml,xamlx,xoml}] 152 | indent_style = space 153 | indent_size = 4 154 | tab_width = 4 155 | 156 | [*.{appxmanifest,axml,build,config,csproj,dbml,discomap,dtd,jsproj,lsproj,njsproj,nuspec,proj,props,resw,resx,StyleCop,targets,tasks,vbproj,xml,xsd}] 157 | indent_style = space 158 | indent_size = 2 159 | tab_width = 2 160 | 161 | [*] 162 | 163 | # Microsoft .NET properties 164 | csharp_new_line_before_members_in_object_initializers = false 165 | csharp_preferred_modifier_order = public, private, protected, internal, file, new, static, abstract, virtual, sealed, readonly, override, extern, unsafe, volatile, async, required:suggestion 166 | csharp_style_prefer_utf8_string_literals = true:suggestion 167 | csharp_style_var_elsewhere = true:suggestion 168 | csharp_style_var_for_built_in_types = true:suggestion 169 | csharp_style_var_when_type_is_apparent = true:suggestion 170 | dotnet_naming_rule.private_constants_rule.import_to_resharper = as_predefined 171 | dotnet_naming_rule.private_constants_rule.resharper_style = Label + AaBb, AaBb 172 | dotnet_naming_rule.private_constants_rule.severity = warning 173 | dotnet_naming_rule.private_constants_rule.style = label_upper_camel_case_style 174 | dotnet_naming_rule.private_constants_rule.symbols = private_constants_symbols 175 | dotnet_naming_style.label_upper_camel_case_style.capitalization = pascal_case 176 | dotnet_naming_style.label_upper_camel_case_style.required_prefix = Label 177 | dotnet_naming_symbols.private_constants_symbols.applicable_accessibilities = private 178 | dotnet_naming_symbols.private_constants_symbols.applicable_kinds = field 179 | dotnet_naming_symbols.private_constants_symbols.required_modifiers = const 180 | dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none 181 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:none 182 | dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none 183 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion 184 | dotnet_style_predefined_type_for_member_access = true:suggestion 185 | dotnet_style_qualification_for_event = false:suggestion 186 | dotnet_style_qualification_for_field = false:suggestion 187 | dotnet_style_qualification_for_method = false:suggestion 188 | dotnet_style_qualification_for_property = false:suggestion 189 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion 190 | 191 | # ReSharper inspection severities 192 | resharper_arrange_redundant_parentheses_highlighting = hint 193 | resharper_arrange_this_qualifier_highlighting = hint 194 | resharper_arrange_type_member_modifiers_highlighting = hint 195 | resharper_arrange_type_modifiers_highlighting = hint 196 | resharper_built_in_type_reference_style_for_member_access_highlighting = hint 197 | resharper_built_in_type_reference_style_highlighting = hint 198 | resharper_redundant_base_qualifier_highlighting = warning 199 | resharper_suggest_var_or_type_built_in_types_highlighting = hint 200 | resharper_suggest_var_or_type_elsewhere_highlighting = hint 201 | resharper_suggest_var_or_type_simple_types_highlighting = hint 202 | csharp_indent_labels = one_less_than_current 203 | csharp_using_directive_placement = outside_namespace:silent 204 | csharp_prefer_simple_using_statement = true:suggestion 205 | csharp_prefer_braces = true:silent 206 | csharp_style_namespace_declarations = block_scoped:silent 207 | csharp_style_expression_bodied_methods = false:silent 208 | csharp_style_expression_bodied_constructors = false:silent 209 | csharp_style_expression_bodied_operators = false:silent 210 | csharp_style_expression_bodied_properties = true:silent 211 | csharp_style_expression_bodied_indexers = true:silent 212 | csharp_style_expression_bodied_accessors = true:silent 213 | csharp_style_expression_bodied_lambdas = true:silent 214 | csharp_style_expression_bodied_local_functions = false:silent 215 | csharp_style_throw_expression = true:suggestion 216 | csharp_style_prefer_null_check_over_type_check = true:suggestion 217 | csharp_prefer_simple_default_expression = true:suggestion 218 | csharp_style_prefer_local_over_anonymous_function = true:suggestion 219 | csharp_style_prefer_index_operator = true:suggestion 220 | csharp_style_prefer_range_operator = true:suggestion 221 | csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion 222 | csharp_style_prefer_tuple_swap = true:suggestion 223 | csharp_style_prefer_method_group_conversion = true:silent 224 | csharp_style_prefer_top_level_statements = true:silent -------------------------------------------------------------------------------- /.github/workflows/dotnet.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a .NET project 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net 3 | 4 | name: .NET Build 5 | 6 | on: 7 | push: 8 | branches: 9 | - main 10 | - structureRework 11 | tags-ignore: '*' 12 | pull_request: 13 | types: [opened, reopened] 14 | 15 | jobs: 16 | build: 17 | runs-on: windows-latest 18 | steps: 19 | - uses: actions/checkout@v3.5.2 20 | with: 21 | submodules: true 22 | - name: Setup .NET 23 | uses: actions/setup-dotnet@v3.0.3 24 | with: 25 | dotnet-version: '7.x.x' 26 | - name: Restore dependencies 27 | run: dotnet restore 28 | - name: Download Dalamud 29 | run: | 30 | Invoke-WebRequest -Uri https://goatcorp.github.io/dalamud-distrib/stg/latest.zip -OutFile latest.zip 31 | Expand-Archive -Force latest.zip "$env:AppData\XIVLauncher\addon\Hooks\dev\" 32 | - name: Build 33 | run: | 34 | dotnet build --no-restore --configuration Release --nologo 35 | - name: Rename file 36 | run: mv ${{ github.workspace }}/CustomizePlus/bin/x64/Release/CustomizePlus/latest.zip ${{ github.workspace }}/CustomizePlus/bin/x64/Release/CustomizePlus/CustomizePlus.zip 37 | - name: Upload a Build Artifact 38 | uses: actions/upload-artifact@v3.1.2 39 | with: 40 | path: | 41 | ${{ github.workspace }}/CustomizePlus/bin/x64/Release/ 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | publish/ 2 | \.vs/ 3 | packages/ 4 | *.user 5 | bin/ 6 | obj/ 7 | deploy/ 8 | Setup/Release/ 9 | Setup/Debug/ 10 | *.tlog 11 | *.iobj 12 | *.ipdb 13 | *.filters 14 | *.pdb 15 | *.log 16 | *.obj 17 | *.idb 18 | *.recipe 19 | *.ilk 20 | \.vscode/ 21 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Lib/XivToolsWpf"] 2 | path = Lib/XivToolsWpf 3 | url = https://github.com/XIV-Tools/XivToolsWpf 4 | [submodule "Lib/XivtoolsWpf"] 5 | path = Lib/XivtoolsWpf 6 | url = https://github.com/XIV-Tools/XivToolsWpf.git 7 | -------------------------------------------------------------------------------- /CustomizePlus.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.1.31911.260 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4CF55D1D-C5C5-4368-89D6-31D79EF6978C}" 7 | ProjectSection(SolutionItems) = preProject 8 | .editorconfig = .editorconfig 9 | ..\..\..\..\Users\yuuki\AppData\Roaming\XIVLauncher\dalamud.log = ..\..\..\..\Users\yuuki\AppData\Roaming\XIVLauncher\dalamud.log 10 | repo.json = repo.json 11 | EndProjectSection 12 | EndProject 13 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CustomizePlus", "CustomizePlus\CustomizePlus.csproj", "{5BA385F5-C17E-4CE4-828A-24F7F19C434B}" 14 | EndProject 15 | Global 16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 17 | Debug|Any CPU = Debug|Any CPU 18 | Debug|x64 = Debug|x64 19 | Release|Any CPU = Release|Any CPU 20 | Release|x64 = Release|x64 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {5BA385F5-C17E-4CE4-828A-24F7F19C434B}.Debug|Any CPU.ActiveCfg = Debug|x64 24 | {5BA385F5-C17E-4CE4-828A-24F7F19C434B}.Debug|Any CPU.Build.0 = Debug|x64 25 | {5BA385F5-C17E-4CE4-828A-24F7F19C434B}.Debug|x64.ActiveCfg = Debug|x64 26 | {5BA385F5-C17E-4CE4-828A-24F7F19C434B}.Debug|x64.Build.0 = Debug|x64 27 | {5BA385F5-C17E-4CE4-828A-24F7F19C434B}.Release|Any CPU.ActiveCfg = Release|x64 28 | {5BA385F5-C17E-4CE4-828A-24F7F19C434B}.Release|Any CPU.Build.0 = Release|x64 29 | {5BA385F5-C17E-4CE4-828A-24F7F19C434B}.Release|x64.ActiveCfg = Release|x64 30 | {5BA385F5-C17E-4CE4-828A-24F7F19C434B}.Release|x64.Build.0 = Release|x64 31 | EndGlobalSection 32 | GlobalSection(SolutionProperties) = preSolution 33 | HideSolutionNode = FALSE 34 | EndGlobalSection 35 | GlobalSection(ExtensibilityGlobals) = postSolution 36 | SolutionGuid = {B17E85B1-5F60-4440-9F9A-3DDE877E8CDF} 37 | EndGlobalSection 38 | EndGlobal 39 | -------------------------------------------------------------------------------- /CustomizePlus/CustomizePlus.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 1.2.6.10 8 | CustomizePlus 9 | 10 | https://github.com/XIV-Tools/CustomizePlus 11 | true 12 | 13 | 14 | 15 | net8.0-windows 16 | x64 17 | enable 18 | latest 19 | true 20 | false 21 | false 22 | true 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | PreserveNewest 34 | false 35 | 36 | 37 | 38 | 39 | $(appdata)\XIVLauncher\addon\Hooks\dev\ 40 | True 41 | 42 | 43 | 44 | 45 | 46 | 47 | all 48 | runtime; build; native; contentfiles; analyzers; buildtransitive 49 | 50 | 51 | $(DalamudLibPath)Newtonsoft.Json.dll 52 | false 53 | 54 | 55 | $(DalamudLibPath)Dalamud.dll 56 | false 57 | 58 | 59 | $(DalamudLibPath)ImGui.NET.dll 60 | false 61 | 62 | 63 | $(DalamudLibPath)ImGuiScene.dll 64 | false 65 | 66 | 67 | $(DalamudLibPath)Lumina.dll 68 | false 69 | 70 | 71 | $(DalamudLibPath)Lumina.Excel.dll 72 | false 73 | 74 | 75 | $(DalamudLibPath)FFXIVClientStructs.dll 76 | false 77 | 78 | 79 | 80 | 81 | 82 | PreserveNewest 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /CustomizePlus/DalamudPackager.targets: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /CustomizePlus/Extensions/CommandManagerExtensions.cs: -------------------------------------------------------------------------------- 1 | // © Customize+. 2 | // Licensed under the MIT license. 3 | 4 | using System.Collections.Generic; 5 | using CustomizePlus.Services; 6 | using Dalamud.Game.Command; 7 | using Dalamud.Plugin.Services; 8 | 9 | namespace CustomizePlus.Extensions 10 | { 11 | public static class CommandManagerExtensions 12 | { 13 | private static readonly List BoundCommands = new(); 14 | 15 | public static void AddCommand(this ICommandManager self, CommandInfo.HandlerDelegate handler, string command, 16 | string help) 17 | { 18 | var info = new CommandInfo(handler) 19 | { 20 | HelpMessage = help 21 | }; 22 | 23 | if (!command.StartsWith('/')) 24 | { 25 | command = '/' + command; 26 | } 27 | 28 | BoundCommands.Add(command); 29 | 30 | self.AddHandler(command, info); 31 | } 32 | 33 | public static void Dispose() 34 | { 35 | foreach (var command in BoundCommands) 36 | { 37 | DalamudServices.CommandManager.RemoveHandler(command); 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /CustomizePlus/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | // © Customize+. 2 | // Licensed under the MIT license. 3 | 4 | using System.Diagnostics.CodeAnalysis; 5 | 6 | [assembly: 7 | SuppressMessage("StyleCop.CSharp.NamingRules", "SA1309:Field names should not begin with underscore", 8 | Justification = "Supressed in favor of CA1500. Use _camelCase for private fields.", 9 | Scope = "namespaceanddescendants", Target = "~N:CustomizePlus")] -------------------------------------------------------------------------------- /CustomizePlus/Helpers/ChatHelper.cs: -------------------------------------------------------------------------------- 1 | // © Customize+. 2 | // Licensed under the MIT license. 3 | 4 | using CustomizePlus.Services; 5 | using Dalamud.Game.Text.SeStringHandling; 6 | 7 | namespace CustomizePlus.Helpers 8 | { 9 | internal static class ChatHelper 10 | { 11 | public static void PrintInChat(string message) 12 | { 13 | var stringBuilder = new SeStringBuilder(); 14 | stringBuilder.AddUiForeground(45); 15 | stringBuilder.AddText($"[Customize+] {message}"); 16 | stringBuilder.AddUiForegroundOff(); 17 | DalamudServices.ChatGui.Print(stringBuilder.BuiltString); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /CustomizePlus/Helpers/CtrlHelper.cs: -------------------------------------------------------------------------------- 1 | // © Customize+. 2 | // Licensed under the MIT license. 3 | 4 | using System; 5 | using Dalamud.Interface; 6 | using Dalamud.Utility; 7 | using ImGuiNET; 8 | 9 | namespace CustomizePlus.Helpers 10 | { 11 | public static class CtrlHelper 12 | { 13 | /// 14 | /// Gets the width of an icon button, checkbox, etc... 15 | /// 16 | /// per https://github.com/ocornut/imgui/issues/3714#issuecomment-759319268 17 | public static float IconButtonWidth => ImGui.GetFrameHeight() + (2 * ImGui.GetStyle().ItemInnerSpacing.X); 18 | 19 | public static bool TextBox(string label, ref string value) 20 | { 21 | ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X); 22 | return ImGui.InputText(label, ref value, 1024); 23 | } 24 | 25 | public static bool TextPropertyBox(string label, Func get, Action set) 26 | { 27 | var temp = get(); 28 | var result = TextBox(label, ref temp); 29 | if (result) 30 | { 31 | set(temp); 32 | } 33 | 34 | return result; 35 | } 36 | 37 | public static bool Checkbox(string label, ref bool value) 38 | { 39 | return ImGui.Checkbox(label, ref value); 40 | } 41 | 42 | public static bool CheckboxWithTextAndHelp(string label, string text, string helpText, ref bool value) 43 | { 44 | var checkBoxState = ImGui.Checkbox(label, ref value); 45 | ImGui.SameLine(); 46 | ImGui.PushFont(UiBuilder.IconFont); 47 | ImGui.Text(FontAwesomeIcon.InfoCircle.ToIconString()); 48 | ImGui.PopFont(); 49 | AddHoverText(helpText); 50 | ImGui.SameLine(); 51 | ImGui.Text(text); 52 | 53 | AddHoverText(helpText); 54 | 55 | return checkBoxState; 56 | } 57 | 58 | public static bool CheckboxToggle(string label, in bool shown, Action toggle) 59 | { 60 | var temp = shown; 61 | var toggled = ImGui.Checkbox(label, ref temp); 62 | 63 | if (toggled) 64 | { 65 | toggle(temp); 66 | } 67 | 68 | return toggled; 69 | } 70 | 71 | public static bool ArrowToggle(string label, ref bool value) 72 | { 73 | var toggled = ImGui.ArrowButton(label, value ? ImGuiDir.Down : ImGuiDir.Right); 74 | 75 | if (toggled) 76 | { 77 | value = !value; 78 | } 79 | 80 | return value; 81 | } 82 | 83 | public static void AddHoverText(string text) 84 | { 85 | if (ImGui.IsItemHovered()) 86 | { 87 | ImGui.SetTooltip(text); 88 | } 89 | } 90 | 91 | public enum TextAlignment { Left, Center, Right }; 92 | public static void StaticLabel(string? text, TextAlignment align = TextAlignment.Left, string tooltip = "") 93 | { 94 | if (text != null) 95 | { 96 | if (align == TextAlignment.Center) 97 | { 98 | ImGui.Dummy(new System.Numerics.Vector2((ImGui.GetContentRegionAvail().X - ImGui.CalcTextSize(text).X) / 2, 0)); 99 | ImGui.SameLine(); 100 | } 101 | else if (align == TextAlignment.Right) 102 | { 103 | ImGui.Dummy(new System.Numerics.Vector2(ImGui.GetContentRegionAvail().X - ImGui.CalcTextSize(text).X, 0)); 104 | ImGui.SameLine(); 105 | } 106 | 107 | ImGui.Text(text); 108 | if (!tooltip.IsNullOrWhitespace()) 109 | { 110 | AddHoverText(tooltip); 111 | } 112 | } 113 | } 114 | 115 | public static void StaticLabelWithIconOnBothSides(FontAwesomeIcon icon, string? text, TextAlignment align = TextAlignment.Left, string tooltip = "") 116 | { 117 | if (text != null) 118 | { 119 | if (align == TextAlignment.Center) 120 | { 121 | ImGui.Dummy(new System.Numerics.Vector2((ImGui.GetContentRegionAvail().X - ImGui.CalcTextSize(text).X - 30) / 2, 0)); 122 | ImGui.SameLine(); 123 | } 124 | else if (align == TextAlignment.Right) 125 | { 126 | ImGui.Dummy(new System.Numerics.Vector2(ImGui.GetContentRegionAvail().X - ImGui.CalcTextSize(text).X - 30, 0)); 127 | ImGui.SameLine(); 128 | } 129 | 130 | ImGui.PushFont(UiBuilder.IconFont); 131 | ImGui.Text(icon.ToIconString()); 132 | ImGui.PopFont(); 133 | ImGui.SameLine(); 134 | ImGui.Text(text); 135 | ImGui.SameLine(); 136 | ImGui.PushFont(UiBuilder.IconFont); 137 | ImGui.Text(icon.ToIconString()); 138 | ImGui.PopFont(); 139 | 140 | if (!tooltip.IsNullOrWhitespace()) 141 | { 142 | AddHoverText(tooltip); 143 | } 144 | } 145 | } 146 | 147 | public static void LabelWithIcon(FontAwesomeIcon icon, string text) 148 | { 149 | ImGui.SameLine(); 150 | ImGui.PushFont(UiBuilder.IconFont); 151 | ImGui.Text(icon.ToIconString()); 152 | ImGui.PopFont(); 153 | ImGui.SameLine(); 154 | ImGui.TextWrapped(text); 155 | } 156 | } 157 | } -------------------------------------------------------------------------------- /CustomizePlus/Plugin.cs: -------------------------------------------------------------------------------- 1 | // © Customize+. 2 | // Licensed under the MIT license. 3 | 4 | // Signautres stolen from: 5 | // https://github.com/0ceal0t/DXTest/blob/8e9aef4f6f871e7743aafe56deb9e8ad4dc87a0d/SamplePlugin/Plugin.DX.cs 6 | // I don't know how they work, but they do! 7 | 8 | using System; 9 | using CustomizePlus.Extensions; 10 | using CustomizePlus.Helpers; 11 | using CustomizePlus.Services; 12 | using CustomizePlus.UI; 13 | using CustomizePlus.UI.Windows; 14 | using Dalamud.Logging; 15 | using Dalamud.Plugin; 16 | using FFXIVClientStructs.FFXIV.Client.UI; 17 | 18 | namespace CustomizePlus 19 | { 20 | public sealed class Plugin : IDalamudPlugin 21 | { 22 | public string Name => "Customize Plus"; 23 | 24 | public static UserInterfaceManager InterfaceManager { get; } = new(); 25 | 26 | public Plugin(DalamudPluginInterface pluginInterface) 27 | { 28 | try 29 | { 30 | DalamudServices.Initialize(pluginInterface); 31 | DalamudServices.PluginInterface.UiBuilder.DisableGposeUiHide = true; 32 | 33 | DalamudServices.CommandManager.AddCommand((s, t) => MainWindow.Toggle(), "/customize", 34 | "Toggles the Customize+ configuration window."); 35 | DalamudServices.CommandManager.AddCommand((s, t) => MainWindow.Toggle(), "/c+", 36 | "Toggles the Customize+ configuration window."); 37 | 38 | DalamudServices.PluginInterface.UiBuilder.Draw += InterfaceManager.Draw; 39 | DalamudServices.PluginInterface.UiBuilder.OpenConfigUi += MainWindow.Toggle; 40 | 41 | MainWindow.Show(); 42 | 43 | ChatHelper.PrintInChat("Customize+ Started!"); 44 | 45 | UIModule.PlayChatSoundEffect(11); 46 | ChatHelper.PrintInChat("CUSTOMIZE+ IS NO LONGER FUNCTIONAL, OPEN SETTINGS FOR DETAILS"); 47 | } 48 | catch (Exception ex) 49 | { 50 | PluginLog.Error(ex, "Error instantiating plugin"); 51 | ChatHelper.PrintInChat( 52 | "An error occurred while starting Customize+. See the Dalamud log for more details"); 53 | } 54 | } 55 | 56 | public void Dispose() 57 | { 58 | InterfaceManager.Dispose(); 59 | 60 | CommandManagerExtensions.Dispose(); 61 | 62 | DalamudServices.PluginInterface.UiBuilder.Draw -= InterfaceManager.Draw; 63 | DalamudServices.PluginInterface.UiBuilder.OpenConfigUi -= MainWindow.Show; 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /CustomizePlus/Services/DalamudServices.cs: -------------------------------------------------------------------------------- 1 | // © Customize+. 2 | // Licensed under the MIT license. 3 | 4 | using Dalamud.Game; 5 | using Dalamud.IoC; 6 | using Dalamud.Plugin; 7 | using Dalamud.Plugin.Services; 8 | 9 | namespace CustomizePlus.Services 10 | { 11 | public class DalamudServices 12 | { 13 | 14 | 15 | [PluginService] 16 | [RequiredVersion("1.0")] 17 | public static DalamudPluginInterface PluginInterface { get; private set; } = null!; 18 | 19 | [PluginService] 20 | [RequiredVersion("1.0")] 21 | public static ISigScanner SigScanner { get; private set; } = null!; 22 | 23 | [PluginService] 24 | public static IFramework Framework { get; private set; } = null!; 25 | 26 | [PluginService] 27 | [RequiredVersion("1.0")] 28 | public static IObjectTable ObjectTable { get; private set; } = null!; 29 | 30 | [PluginService] 31 | [RequiredVersion("1.0")] 32 | public static ICommandManager CommandManager { get; private set; } = null!; 33 | 34 | [PluginService] 35 | [RequiredVersion("1.0")] 36 | public static IChatGui ChatGui { get; private set; } = null!; 37 | 38 | [PluginService] 39 | [RequiredVersion("1.0")] 40 | public static IClientState ClientState { get; private set; } = null!; 41 | 42 | [PluginService] 43 | [RequiredVersion("1.0")] 44 | public static IGameGui GameGui { get; private set; } = null!; 45 | 46 | [PluginService] 47 | [RequiredVersion("1.0")] 48 | internal static IGameInteropProvider Hooker { get; private set; } = null!; 49 | 50 | public static void Initialize(DalamudPluginInterface pluginInterface) 51 | { 52 | pluginInterface.Create(); 53 | } 54 | 55 | public static void Destroy() 56 | { 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /CustomizePlus/UI/UserInterfaceBase.cs: -------------------------------------------------------------------------------- 1 | // © Customize+. 2 | // Licensed under the MIT license. 3 | 4 | using System; 5 | 6 | namespace CustomizePlus.UI 7 | { 8 | public abstract class UserInterfaceBase : IDisposable 9 | { 10 | public bool IsOpen { get; private set; } 11 | 12 | protected int Index { get; private set; } 13 | protected UserInterfaceManager Manager => Plugin.InterfaceManager; 14 | 15 | protected virtual bool SingleInstance => false; 16 | 17 | public virtual void Dispose() 18 | { 19 | } 20 | 21 | public virtual void Open() 22 | { 23 | if (SingleInstance) 24 | { 25 | var instance = Manager.GetUserInterface(GetType()); 26 | if (instance != null) 27 | { 28 | instance?.Focus(); 29 | return; 30 | } 31 | } 32 | 33 | IsOpen = true; 34 | } 35 | 36 | public virtual void Focus() 37 | { 38 | // ?? 39 | } 40 | 41 | public abstract void Draw(); 42 | 43 | public virtual void Close() 44 | { 45 | IsOpen = false; 46 | } 47 | 48 | internal void DoDraw(int index) 49 | { 50 | Index = index; 51 | Draw(); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /CustomizePlus/UI/UserInterfaceManager.cs: -------------------------------------------------------------------------------- 1 | // © Customize+. 2 | // Licensed under the MIT license. 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | 7 | namespace CustomizePlus.UI 8 | { 9 | public class UserInterfaceManager : IDisposable 10 | { 11 | private readonly List _interfaces = new(); 12 | 13 | public void Dispose() 14 | { 15 | foreach (var iface in _interfaces) 16 | { 17 | iface.Close(); 18 | iface.Dispose(); 19 | } 20 | 21 | _interfaces.Clear(); 22 | } 23 | 24 | public void Draw() 25 | { 26 | if (_interfaces.Count <= 0) 27 | { 28 | return; 29 | } 30 | 31 | for (var i = _interfaces.Count - 1; i >= 0; i--) 32 | { 33 | _interfaces[i].DoDraw(i); 34 | 35 | if (!_interfaces[i].IsOpen) 36 | { 37 | _interfaces[i].Dispose(); 38 | _interfaces.RemoveAt(i); 39 | } 40 | } 41 | } 42 | 43 | public T Show() 44 | where T : UserInterfaceBase 45 | { 46 | //todo: do not allow more than a single instance of the same window? 47 | var ui = Activator.CreateInstance(); 48 | ui.Open(); 49 | 50 | if (ui.IsOpen) 51 | { 52 | _interfaces.Add(ui); 53 | } 54 | 55 | return ui; 56 | } 57 | 58 | // Added this so you can close with /customize. This may need a rework in the future to access the broader usecase of the rest of the methods. But this should serve for now? 59 | public void Toggle() 60 | where T : UserInterfaceBase, new() 61 | { 62 | if (_interfaces.Count <= 0) 63 | { 64 | new InvalidOperationException("Interfaces is empty."); 65 | } 66 | 67 | // Close all windows, if we closed any window set 'switchedOff' to true so we know we are hiding interfaces. 68 | // If we did not turn anything off, we probably want to show our window. 69 | if (!CloseAllUserInterfaces()) 70 | { 71 | Show(); 72 | } 73 | } 74 | 75 | // Closes all Interfaces, returns true if at least one Interface was closed. 76 | public bool CloseAllUserInterfaces() 77 | { 78 | var interfaceWasClosed = false; 79 | foreach (var currentInterface in _interfaces) 80 | { 81 | if (currentInterface.IsOpen) 82 | { 83 | currentInterface.Close(); 84 | interfaceWasClosed = true; 85 | } 86 | } 87 | 88 | return interfaceWasClosed; 89 | } 90 | 91 | public UserInterfaceBase? GetUserInterface(Type type) 92 | { 93 | foreach (var ui in _interfaces) 94 | { 95 | if (ui.GetType().IsAssignableTo(type)) 96 | { 97 | return ui; 98 | } 99 | } 100 | 101 | return null; 102 | } 103 | } 104 | } -------------------------------------------------------------------------------- /CustomizePlus/UI/WindowBase.cs: -------------------------------------------------------------------------------- 1 | // © Customize+. 2 | // Licensed under the MIT license. 3 | 4 | using System.Numerics; 5 | using ImGuiNET; 6 | 7 | namespace CustomizePlus.UI 8 | { 9 | public abstract class WindowBase : UserInterfaceBase 10 | { 11 | private bool _isAlwaysVisibleDummy = true; //dummy variable for LockCloseButton = true 12 | private bool _isVisible; 13 | 14 | protected abstract string Title { get; } 15 | 16 | protected virtual Vector2? ForcedSize { get; set; } 17 | protected virtual Vector2 MinSize => new(600, 256); 18 | protected virtual Vector2 MaxSize => new(2560, 1440); 19 | 20 | protected virtual ImGuiWindowFlags WindowFlags { get; set; } = ImGuiWindowFlags.None; 21 | protected virtual bool LockCloseButton { get; set; } 22 | 23 | /// 24 | /// Gets normally you wouldn't want to override this. 25 | /// 26 | protected virtual string DrawTitle => $"{Title}"; 27 | 28 | public override void Open() 29 | { 30 | base.Open(); 31 | _isVisible = true; 32 | } 33 | 34 | public override void Focus() 35 | { 36 | ImGui.SetWindowFocus(DrawTitle); 37 | base.Focus(); 38 | } 39 | 40 | public sealed override void Draw() 41 | { 42 | ImGui.SetNextWindowSizeConstraints(MinSize, MaxSize); 43 | 44 | if (ForcedSize != null) 45 | { 46 | ImGui.SetNextWindowSize((Vector2)ForcedSize); 47 | } 48 | 49 | if (ImGui.Begin(DrawTitle, ref LockCloseButton ? ref _isAlwaysVisibleDummy : ref _isVisible, WindowFlags)) 50 | { 51 | DrawContents(); 52 | } 53 | 54 | ImGui.End(); 55 | 56 | if (!_isVisible) 57 | { 58 | Close(); 59 | } 60 | } 61 | 62 | protected abstract void DrawContents(); 63 | } 64 | } -------------------------------------------------------------------------------- /CustomizePlus/UI/Windows/MainWindow.cs: -------------------------------------------------------------------------------- 1 | // © Customize+. 2 | // Licensed under the MIT license. 3 | 4 | using System.Diagnostics; 5 | using System.Drawing; 6 | using System.Numerics; 7 | using System.Windows.Forms; 8 | using CustomizePlus.Helpers; 9 | using Dalamud.Interface; 10 | using ImGuiNET; 11 | 12 | namespace CustomizePlus.UI.Windows 13 | { 14 | public class MainWindow : WindowBase 15 | { 16 | private static Vector4 WarningColor = new Vector4(1, 0.5f, 0, 1); 17 | 18 | protected override string Title => "Customize+"; 19 | protected override bool SingleInstance => true; 20 | 21 | public static void Show() 22 | { 23 | Plugin.InterfaceManager.Show(); 24 | } 25 | 26 | public static void Toggle() 27 | { 28 | Plugin.InterfaceManager.Toggle(); 29 | } 30 | 31 | protected override void DrawContents() 32 | { 33 | ImGui.PushStyleColor(ImGuiCol.Text, WarningColor); 34 | CtrlHelper.StaticLabelWithIconOnBothSides(FontAwesomeIcon.ExclamationTriangle, "ATTENTION, PLEASE READ!", CtrlHelper.TextAlignment.Center); 35 | ImGui.PopStyleColor(); 36 | CtrlHelper.StaticLabel("You need to update Customize+ to latest version. Currently installed version is no longer functional.", CtrlHelper.TextAlignment.Center); 37 | CtrlHelper.StaticLabel("Please delete your current version, remove XIV-Tools repository if you are using it and install Customize+ from the following url: https://github.com/Aether-Tools/CustomizePlus", CtrlHelper.TextAlignment.Center); 38 | ImGui.PushStyleColor(ImGuiCol.Text, WarningColor); 39 | CtrlHelper.StaticLabelWithIconOnBothSides(FontAwesomeIcon.ExclamationTriangle, "Your settings will be automatically migrated to new version.", CtrlHelper.TextAlignment.Center); 40 | ImGui.PopStyleColor(); 41 | 42 | CtrlHelper.StaticLabel("If you need help, feel free to join support discord: https://discord.gg/KvGJCCnG8t", CtrlHelper.TextAlignment.Center); 43 | 44 | ImGui.Dummy(new Vector2((ImGui.GetContentRegionAvail().X / 2) - 150, 0)); 45 | ImGui.SameLine(); 46 | if (ImGui.Button("Copy Repository Link")) 47 | { 48 | Clipboard.SetText("https://raw.githubusercontent.com/Aether-Tools/DalamudPlugins/main/repo.json"); 49 | } 50 | ImGui.SameLine(); 51 | if (ImGui.Button("Open Link to GitHub")) 52 | { 53 | Process.Start(new ProcessStartInfo("https://github.com/Aether-Tools/CustomizePlus") { UseShellExecute = true }); 54 | } 55 | ImGui.Dummy(new Vector2((ImGui.GetContentRegionAvail().X / 2) - 75, 0)); 56 | ImGui.SameLine(); 57 | if (ImGui.Button("Join Support Discord")) 58 | { 59 | Process.Start(new ProcessStartInfo("https://discord.gg/KvGJCCnG8t") { UseShellExecute = true }); 60 | } 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /CustomizePlus/customizePlus.json: -------------------------------------------------------------------------------- 1 | { 2 | "Author": "XIV Tools", 3 | "Name": "Customize+", 4 | "Punchline": "Customize your character beyond FFXIV's limitations.", 5 | "Description": "A plugin that allows you to create and apply Anamnesis-style body scaling full time.", 6 | "InternalName": "CustomizePlus", 7 | "ApplicableVersion": "any", 8 | "DalamudApiLevel": 9, 9 | "Tags": [ 10 | "anamnesis", 11 | "customize", 12 | "XIV Tools" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /Data/NotoSansCJKjp-Medium.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XIV-Tools/CustomizePlus/7c5aaed442c5e3b4fb61a511adfce3d9b4a319c0/Data/NotoSansCJKjp-Medium.otf -------------------------------------------------------------------------------- /Data/customizePlus.json: -------------------------------------------------------------------------------- 1 | { 2 | "Author": "XIV Tools", 3 | "Name": "Customize Plus", 4 | "Punchline": "Customize your character beyond FFXIV's limitations.", 5 | "Description": "A plugin that allows you to create and apply Anamnesis-style body scaling full time.", 6 | "InternalName": "CustomizePlus", 7 | "ApplicableVersion": "any", 8 | "Tags": [ 9 | "anamnesis", 10 | "customize", 11 | "XIV Tools" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /Data/gamesym.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XIV-Tools/CustomizePlus/7c5aaed442c5e3b4fb61a511adfce3d9b4a319c0/Data/gamesym.ttf -------------------------------------------------------------------------------- /Data/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XIV-Tools/CustomizePlus/7c5aaed442c5e3b4fb61a511adfce3d9b4a319c0/Data/icon.png -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021-2023 Customize+ Contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Repository has been moved 2 | Customize+ repository is now located at https://github.com/Aether-Tools/CustomizePlus --------------------------------------------------------------------------------