├── .github └── workflows │ └── dotnet-desktop.yml ├── .gitignore ├── BflytPreview ├── App.config ├── Automation │ ├── BflanTemplates.cs │ ├── ValueImportForm.Designer.cs │ ├── ValueImportForm.cs │ └── ValueImportForm.resx ├── BflanEditor.Designer.cs ├── BflanEditor.cs ├── BflanEditor.resx ├── BflanTemplates │ ├── ColorAnimation.json │ └── ColorAnimation.template ├── BflytPreview.csproj ├── EditorForms │ ├── HexEditorForm.cs │ ├── IFileProvider.cs │ ├── InputDialog.cs │ ├── LayoutDiffForm.Designer.cs │ ├── LayoutDiffForm.cs │ ├── LayoutDiffForm.resx │ ├── SzsEditor.Designer.cs │ ├── SzsEditor.cs │ └── SzsEditor.resx ├── EditorView.Designer.cs ├── EditorView.cs ├── EditorView.resx ├── MainForm.Designer.cs ├── MainForm.cs ├── MainForm.resx ├── OpenTK.dll.config ├── Program.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── Settings.Designer.cs ├── Settings.settings ├── SettingsWindow.Designer.cs ├── SettingsWindow.cs ├── SettingsWindow.resx ├── favicon.ico ├── icon.ico └── packages.config ├── LICENSE ├── README.md ├── Screenshot.png ├── Screenshots ├── Dragging.gif ├── EditorPreview.png ├── Example.png ├── LayoutEditing.png ├── MainMenu.png ├── PaneMenu.png ├── PropertiesMenu.png ├── SaveFile.png ├── Settings.png ├── Szs-loading.png └── SzsEditor.png ├── SwitchLayoutEditor.sln ├── docs └── EditorAutoUpdate.xml └── dragdroptree.txt /.github/workflows/dotnet-desktop.yml: -------------------------------------------------------------------------------- 1 | name: LayoutEditor 2 | on: 3 | workflow_dispatch: 4 | push: 5 | pull_request: 6 | jobs: 7 | Build: 8 | runs-on: windows-latest 9 | steps: 10 | - name: Setup msbuild 11 | uses: microsoft/setup-msbuild@v1.0.2 12 | # Needs switchThemesCommon to build 13 | - uses: actions/checkout@v3 14 | with: 15 | repository: 'exelix11/SwitchThemeInjector' 16 | path: 'SwitchThemeInjector' 17 | - uses: actions/checkout@v3 18 | with: 19 | path: 'SwitchLayoutEditor' 20 | - name: Restore packages 21 | run: | 22 | cd %GITHUB_WORKSPACE%/SwitchLayoutEditor 23 | mkdir packages 24 | cd packages 25 | nuget install %GITHUB_WORKSPACE%/SwitchLayoutEditor/BflytPreview/packages.config 26 | shell: cmd 27 | - name: Build project 28 | run: | 29 | cd %GITHUB_WORKSPACE%\SwitchLayoutEditor\ 30 | msbuild -p:Configuration=Release 31 | del %GITHUB_WORKSPACE%\SwitchLayoutEditor\BflytPreview\bin\Release\*.xml 32 | shell: cmd 33 | - uses: actions/upload-artifact@v4 34 | with: 35 | name: LayoutEditor 36 | path: ${{ github.workspace }}/SwitchLayoutEditor/BflytPreview/bin/Release/ 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | [Bb]uild/ 27 | 28 | # Visual Studio 2015/2017 cache/options directory 29 | .vs/ 30 | # Uncomment if you have tasks that create the project's static files in wwwroot 31 | #wwwroot/ 32 | 33 | # Visual Studio 2017 auto generated files 34 | Generated\ Files/ 35 | 36 | # MSTest test Results 37 | [Tt]est[Rr]esult*/ 38 | [Bb]uild[Ll]og.* 39 | 40 | # NUNIT 41 | *.VisualState.xml 42 | TestResult.xml 43 | 44 | # Build Results of an ATL Project 45 | [Dd]ebugPS/ 46 | [Rr]eleasePS/ 47 | dlldata.c 48 | 49 | # Benchmark Results 50 | BenchmarkDotNet.Artifacts/ 51 | 52 | # .NET Core 53 | project.lock.json 54 | project.fragment.lock.json 55 | artifacts/ 56 | **/Properties/launchSettings.json 57 | 58 | # StyleCop 59 | StyleCopReport.xml 60 | 61 | # Files built by Visual Studio 62 | *_i.c 63 | *_p.c 64 | *_i.h 65 | *.ilk 66 | *.meta 67 | *.obj 68 | *.iobj 69 | *.pch 70 | *.pdb 71 | *.ipdb 72 | *.pgc 73 | *.pgd 74 | *.rsp 75 | *.sbr 76 | *.tlb 77 | *.tli 78 | *.tlh 79 | *.tmp 80 | *.tmp_proj 81 | *.log 82 | *.vspscc 83 | *.vssscc 84 | .builds 85 | *.pidb 86 | *.svclog 87 | *.scc 88 | 89 | # Chutzpah Test files 90 | _Chutzpah* 91 | 92 | # Visual C++ cache files 93 | ipch/ 94 | *.aps 95 | *.ncb 96 | *.opendb 97 | *.opensdf 98 | *.sdf 99 | *.cachefile 100 | *.VC.db 101 | *.VC.VC.opendb 102 | 103 | # Visual Studio profiler 104 | *.psess 105 | *.vsp 106 | *.vspx 107 | *.sap 108 | 109 | # Visual Studio Trace Files 110 | *.e2e 111 | 112 | # TFS 2012 Local Workspace 113 | $tf/ 114 | 115 | # Guidance Automation Toolkit 116 | *.gpState 117 | 118 | # ReSharper is a .NET coding add-in 119 | _ReSharper*/ 120 | *.[Rr]e[Ss]harper 121 | *.DotSettings.user 122 | 123 | # JustCode is a .NET coding add-in 124 | .JustCode 125 | 126 | # TeamCity is a build add-in 127 | _TeamCity* 128 | 129 | # DotCover is a Code Coverage Tool 130 | *.dotCover 131 | 132 | # AxoCover is a Code Coverage Tool 133 | .axoCover/* 134 | !.axoCover/settings.json 135 | 136 | # Visual Studio code coverage results 137 | *.coverage 138 | *.coveragexml 139 | 140 | # NCrunch 141 | _NCrunch_* 142 | .*crunch*.local.xml 143 | nCrunchTemp_* 144 | 145 | # MightyMoose 146 | *.mm.* 147 | AutoTest.Net/ 148 | 149 | # Web workbench (sass) 150 | .sass-cache/ 151 | 152 | # Installshield output folder 153 | [Ee]xpress/ 154 | 155 | # DocProject is a documentation generator add-in 156 | DocProject/buildhelp/ 157 | DocProject/Help/*.HxT 158 | DocProject/Help/*.HxC 159 | DocProject/Help/*.hhc 160 | DocProject/Help/*.hhk 161 | DocProject/Help/*.hhp 162 | DocProject/Help/Html2 163 | DocProject/Help/html 164 | 165 | # Click-Once directory 166 | publish/ 167 | 168 | # Publish Web Output 169 | *.[Pp]ublish.xml 170 | *.azurePubxml 171 | # Note: Comment the next line if you want to checkin your web deploy settings, 172 | # but database connection strings (with potential passwords) will be unencrypted 173 | *.pubxml 174 | *.publishproj 175 | 176 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 177 | # checkin your Azure Web App publish settings, but sensitive information contained 178 | # in these scripts will be unencrypted 179 | PublishScripts/ 180 | 181 | # NuGet Packages 182 | *.nupkg 183 | # The packages folder can be ignored because of Package Restore 184 | **/[Pp]ackages/* 185 | # except build/, which is used as an MSBuild target. 186 | !**/[Pp]ackages/build/ 187 | # Uncomment if necessary however generally it will be regenerated when needed 188 | #!**/[Pp]ackages/repositories.config 189 | # NuGet v3's project.json files produces more ignorable files 190 | *.nuget.props 191 | *.nuget.targets 192 | 193 | # Microsoft Azure Build Output 194 | csx/ 195 | *.build.csdef 196 | 197 | # Microsoft Azure Emulator 198 | ecf/ 199 | rcf/ 200 | 201 | # Windows Store app package directories and files 202 | AppPackages/ 203 | BundleArtifacts/ 204 | Package.StoreAssociation.xml 205 | _pkginfo.txt 206 | *.appx 207 | 208 | # Visual Studio cache files 209 | # files ending in .cache can be ignored 210 | *.[Cc]ache 211 | # but keep track of directories ending in .cache 212 | !*.[Cc]ache/ 213 | 214 | # Others 215 | ClientBin/ 216 | ~$* 217 | *~ 218 | *.dbmdl 219 | *.dbproj.schemaview 220 | *.jfm 221 | *.pfx 222 | *.publishsettings 223 | orleans.codegen.cs 224 | 225 | # Including strong name files can present a security risk 226 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 227 | #*.snk 228 | 229 | # Since there are multiple workflows, uncomment next line to ignore bower_components 230 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 231 | #bower_components/ 232 | 233 | # RIA/Silverlight projects 234 | Generated_Code/ 235 | 236 | # Backup & report files from converting an old project file 237 | # to a newer Visual Studio version. Backup files are not needed, 238 | # because we have git ;-) 239 | _UpgradeReport_Files/ 240 | Backup*/ 241 | UpgradeLog*.XML 242 | UpgradeLog*.htm 243 | ServiceFabricBackup/ 244 | *.rptproj.bak 245 | 246 | # SQL Server files 247 | *.mdf 248 | *.ldf 249 | *.ndf 250 | 251 | # Business Intelligence projects 252 | *.rdl.data 253 | *.bim.layout 254 | *.bim_*.settings 255 | *.rptproj.rsuser 256 | 257 | # Microsoft Fakes 258 | FakesAssemblies/ 259 | 260 | # GhostDoc plugin setting file 261 | *.GhostDoc.xml 262 | 263 | # Node.js Tools for Visual Studio 264 | .ntvs_analysis.dat 265 | node_modules/ 266 | 267 | # Visual Studio 6 build log 268 | *.plg 269 | 270 | # Visual Studio 6 workspace options file 271 | *.opt 272 | 273 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 274 | *.vbw 275 | 276 | # Visual Studio LightSwitch build output 277 | **/*.HTMLClient/GeneratedArtifacts 278 | **/*.DesktopClient/GeneratedArtifacts 279 | **/*.DesktopClient/ModelManifest.xml 280 | **/*.Server/GeneratedArtifacts 281 | **/*.Server/ModelManifest.xml 282 | _Pvt_Extensions 283 | 284 | # Paket dependency manager 285 | .paket/paket.exe 286 | paket-files/ 287 | 288 | # FAKE - F# Make 289 | .fake/ 290 | 291 | # JetBrains Rider 292 | .idea/ 293 | *.sln.iml 294 | 295 | # CodeRush 296 | .cr/ 297 | 298 | # Python Tools for Visual Studio (PTVS) 299 | __pycache__/ 300 | *.pyc 301 | 302 | # Cake - Uncomment if you are using it 303 | # tools/** 304 | # !tools/packages.config 305 | 306 | # Tabs Studio 307 | *.tss 308 | 309 | # Telerik's JustMock configuration file 310 | *.jmconfig 311 | 312 | # BizTalk build output 313 | *.btp.cs 314 | *.btm.cs 315 | *.odx.cs 316 | *.xsd.cs 317 | 318 | # OpenCover UI analysis results 319 | OpenCover/ 320 | 321 | # Azure Stream Analytics local run output 322 | ASALocalRun/ 323 | 324 | # MSBuild Binary and Structured Log 325 | *.binlog 326 | 327 | # NVidia Nsight GPU debugger configuration file 328 | *.nvuser 329 | 330 | # MFractors (Xamarin productivity tool) working folder 331 | .mfractor/ 332 | *.szs 333 | *.nxtheme 334 | *.o 335 | *.d 336 | *.elf 337 | *.nacp 338 | *.nro 339 | *.nso 340 | *.pfs0 341 | *.map 342 | *.lst 343 | *.7z 344 | *.zip 345 | -------------------------------------------------------------------------------- /BflytPreview/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Black 16 | 17 | 18 | Red 19 | 20 | 21 | LightGreen 22 | 23 | 24 | 25 | 26 | 27 | False 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /BflytPreview/Automation/BflanTemplates.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using SwitchThemes.Common.Serializers; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using static SwitchThemes.Common.Bflan.Pai1Section; 9 | 10 | namespace BflytPreview.Automation 11 | { 12 | public enum BflanTemplateKind 13 | { 14 | Pai1, // then FileName Contains PaiEntry[] 15 | PaiEntry, // ... contains PaiTag[] 16 | PaiTag, // ... contains PaiTagEntry[] 17 | PaiTagEntry, // ... contains Keyframe[] 18 | } 19 | 20 | public enum ReplaceValueKind 21 | { 22 | String, 23 | Int, 24 | Float 25 | } 26 | 27 | public class ValueReplacement 28 | { 29 | public ReplaceValueKind Kind; 30 | public string Keyword; 31 | public string Name; 32 | public string Default; 33 | } 34 | 35 | public class BflanTemplate 36 | { 37 | public string Name; 38 | public string FileName; 39 | public BflanTemplateKind Target; 40 | public List Parameters; 41 | 42 | public object[] DeserializeContent(string json) 43 | { 44 | switch (Target) 45 | { 46 | case BflanTemplateKind.Pai1: 47 | return JsonConvert.DeserializeObject(json).Select(x => x.Deserialize()).ToArray(); 48 | case BflanTemplateKind.PaiEntry: 49 | return JsonConvert.DeserializeObject(json).Select(x => x.Deserialize()).ToArray(); 50 | case BflanTemplateKind.PaiTag: 51 | return JsonConvert.DeserializeObject(json).Select(x => x.Deserialize()).ToArray(); 52 | case BflanTemplateKind.PaiTagEntry: 53 | return JsonConvert.DeserializeObject(json).Select(x => x.Deserialize()).ToArray(); 54 | default: 55 | throw new Exception("Unknown BflanTemplateKind"); 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /BflytPreview/Automation/ValueImportForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace BflytPreview.Automation 2 | { 3 | partial class ValueImportForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.propertyGrid1 = new System.Windows.Forms.PropertyGrid(); 32 | this.btnOK = new System.Windows.Forms.Button(); 33 | this.btnCancel = new System.Windows.Forms.Button(); 34 | this.SuspendLayout(); 35 | // 36 | // propertyGrid1 37 | // 38 | this.propertyGrid1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 39 | | System.Windows.Forms.AnchorStyles.Left) 40 | | System.Windows.Forms.AnchorStyles.Right))); 41 | this.propertyGrid1.Location = new System.Drawing.Point(2, 3); 42 | this.propertyGrid1.Name = "propertyGrid1"; 43 | this.propertyGrid1.Size = new System.Drawing.Size(573, 408); 44 | this.propertyGrid1.TabIndex = 0; 45 | // 46 | // btnOK 47 | // 48 | this.btnOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 49 | this.btnOK.Location = new System.Drawing.Point(500, 417); 50 | this.btnOK.Name = "btnOK"; 51 | this.btnOK.Size = new System.Drawing.Size(75, 23); 52 | this.btnOK.TabIndex = 1; 53 | this.btnOK.Text = "OK"; 54 | this.btnOK.UseVisualStyleBackColor = true; 55 | this.btnOK.Click += new System.EventHandler(this.btnOK_Click); 56 | // 57 | // btnCancel 58 | // 59 | this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 60 | this.btnCancel.Location = new System.Drawing.Point(419, 417); 61 | this.btnCancel.Name = "btnCancel"; 62 | this.btnCancel.Size = new System.Drawing.Size(75, 23); 63 | this.btnCancel.TabIndex = 2; 64 | this.btnCancel.Text = "Cancel"; 65 | this.btnCancel.UseVisualStyleBackColor = true; 66 | this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); 67 | // 68 | // ValueImportForm 69 | // 70 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 71 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 72 | this.ClientSize = new System.Drawing.Size(578, 444); 73 | this.Controls.Add(this.btnCancel); 74 | this.Controls.Add(this.btnOK); 75 | this.Controls.Add(this.propertyGrid1); 76 | this.Name = "ValueImportForm"; 77 | this.Text = "Edit template"; 78 | this.Load += new System.EventHandler(this.ValueImportForm_Load); 79 | this.ResumeLayout(false); 80 | 81 | } 82 | 83 | #endregion 84 | 85 | private System.Windows.Forms.PropertyGrid propertyGrid1; 86 | private System.Windows.Forms.Button btnOK; 87 | private System.Windows.Forms.Button btnCancel; 88 | } 89 | } -------------------------------------------------------------------------------- /BflytPreview/Automation/ValueImportForm.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json.Linq; 2 | using System; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using System.ComponentModel; 6 | using System.Data; 7 | using System.Drawing; 8 | using System.Dynamic; 9 | using System.Linq; 10 | using System.Text; 11 | using System.Threading.Tasks; 12 | using System.Windows.Controls; 13 | using System.Windows.Forms; 14 | 15 | namespace BflytPreview.Automation 16 | { 17 | public partial class ValueImportForm : Form 18 | { 19 | public string Result = null; 20 | 21 | readonly string source; 22 | readonly BflanTemplate template; 23 | readonly Dictionary Values = new Dictionary(); 24 | 25 | public ValueImportForm(BflanTemplate template, string json) 26 | { 27 | InitializeComponent(); 28 | 29 | source = json; 30 | this.template = template; 31 | 32 | Values = template.Parameters.ToDictionary(x => x.Name, x => x.Default); 33 | 34 | this.propertyGrid1.SelectedObject = new DictionaryPropertyGridAdapter(Values); 35 | } 36 | 37 | private void ValueImportForm_Load(object sender, EventArgs e) 38 | { 39 | 40 | } 41 | 42 | private void btnCancel_Click(object sender, EventArgs e) 43 | { 44 | this.Close(); 45 | } 46 | 47 | bool ValidateValues() 48 | { 49 | List invalid = new List(); 50 | 51 | foreach (var templ in template.Parameters) 52 | { 53 | var value = Values[templ.Name]; 54 | 55 | if (templ.Kind == ReplaceValueKind.Float) 56 | if (!float.TryParse((string)value, out var _)) 57 | invalid.Add(templ.Name); 58 | 59 | if (templ.Kind == ReplaceValueKind.Int) 60 | if (!int.TryParse((string)value, out var _)) 61 | invalid.Add(templ.Name); 62 | } 63 | 64 | if (invalid.Count > 0) 65 | { 66 | MessageBox.Show("The values for the following properties are not valid: " + string.Join(", ", invalid)); 67 | return false; 68 | } 69 | 70 | return true; 71 | } 72 | 73 | private void btnOK_Click(object sender, EventArgs e) 74 | { 75 | if (!ValidateValues()) 76 | return; 77 | 78 | Result = source; 79 | foreach (var par in template.Parameters) 80 | { 81 | var value = Values[par.Name]; 82 | 83 | if (par.Kind == ReplaceValueKind.String) 84 | Result = Result.Replace(par.Keyword, $"\"{value}\""); 85 | else 86 | Result = Result.Replace(par.Keyword, value); 87 | } 88 | 89 | this.Close(); 90 | } 91 | } 92 | 93 | class DictionaryPropertyGridAdapter : ICustomTypeDescriptor 94 | { 95 | IDictionary _dictionary; 96 | 97 | public DictionaryPropertyGridAdapter(IDictionary d) 98 | { 99 | _dictionary = d; 100 | } 101 | 102 | public string GetComponentName() 103 | { 104 | return TypeDescriptor.GetComponentName(this, true); 105 | } 106 | 107 | public EventDescriptor GetDefaultEvent() 108 | { 109 | return TypeDescriptor.GetDefaultEvent(this, true); 110 | } 111 | 112 | public string GetClassName() 113 | { 114 | return TypeDescriptor.GetClassName(this, true); 115 | } 116 | 117 | public EventDescriptorCollection GetEvents(Attribute[] attributes) 118 | { 119 | return TypeDescriptor.GetEvents(this, attributes, true); 120 | } 121 | 122 | EventDescriptorCollection System.ComponentModel.ICustomTypeDescriptor.GetEvents() 123 | { 124 | return TypeDescriptor.GetEvents(this, true); 125 | } 126 | 127 | public TypeConverter GetConverter() 128 | { 129 | return TypeDescriptor.GetConverter(this, true); 130 | } 131 | 132 | public object GetPropertyOwner(PropertyDescriptor pd) 133 | { 134 | return _dictionary; 135 | } 136 | 137 | public AttributeCollection GetAttributes() 138 | { 139 | return TypeDescriptor.GetAttributes(this, true); 140 | } 141 | 142 | public object GetEditor(Type editorBaseType) 143 | { 144 | return TypeDescriptor.GetEditor(this, editorBaseType, true); 145 | } 146 | 147 | public PropertyDescriptor GetDefaultProperty() 148 | { 149 | return null; 150 | } 151 | 152 | PropertyDescriptorCollection 153 | System.ComponentModel.ICustomTypeDescriptor.GetProperties() 154 | { 155 | return ((ICustomTypeDescriptor)this).GetProperties(new Attribute[0]); 156 | } 157 | 158 | public PropertyDescriptorCollection GetProperties(Attribute[] attributes) 159 | { 160 | ArrayList properties = new ArrayList(); 161 | foreach (DictionaryEntry e in _dictionary) 162 | { 163 | properties.Add(new DictionaryPropertyDescriptor(_dictionary, e.Key)); 164 | } 165 | 166 | PropertyDescriptor[] props = 167 | (PropertyDescriptor[])properties.ToArray(typeof(PropertyDescriptor)); 168 | 169 | return new PropertyDescriptorCollection(props); 170 | } 171 | } 172 | 173 | class DictionaryPropertyDescriptor : PropertyDescriptor 174 | { 175 | IDictionary _dictionary; 176 | object _key; 177 | 178 | internal DictionaryPropertyDescriptor(IDictionary d, object key) 179 | : base(key.ToString(), null) 180 | { 181 | _dictionary = d; 182 | _key = key; 183 | } 184 | 185 | public override Type PropertyType 186 | { 187 | get { return _dictionary[_key].GetType(); } 188 | } 189 | 190 | public override void SetValue(object component, object value) 191 | { 192 | _dictionary[_key] = value; 193 | } 194 | 195 | public override object GetValue(object component) 196 | { 197 | return _dictionary[_key]; 198 | } 199 | 200 | public override bool IsReadOnly 201 | { 202 | get { return false; } 203 | } 204 | 205 | public override Type ComponentType 206 | { 207 | get { return null; } 208 | } 209 | 210 | public override bool CanResetValue(object component) 211 | { 212 | return false; 213 | } 214 | 215 | public override void ResetValue(object component) 216 | { 217 | } 218 | 219 | public override bool ShouldSerializeValue(object component) 220 | { 221 | return false; 222 | } 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /BflytPreview/Automation/ValueImportForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /BflytPreview/BflanEditor.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace BflytPreview 2 | { 3 | partial class BflanEditor 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.components = new System.ComponentModel.Container(); 32 | this.propertyGrid1 = new System.Windows.Forms.PropertyGrid(); 33 | this.treeView1 = new System.Windows.Forms.TreeView(); 34 | this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); 35 | this.addEntryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 36 | this.duplicateToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 37 | this.deleteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 38 | this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); 39 | this.expandAllToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 40 | this.menuStrip1 = new System.Windows.Forms.MenuStrip(); 41 | this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 42 | this.saveAsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 43 | this.saveToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 44 | this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); 45 | this.exportToJSONToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 46 | this.importFromJSONToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 47 | this.ByteOrderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 48 | this.SwitchByteOrderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 49 | this.splitContainer1 = new System.Windows.Forms.SplitContainer(); 50 | this.templatesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 51 | this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator(); 52 | this.noTemplatesAvailableToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 53 | this.contextMenuStrip1.SuspendLayout(); 54 | this.menuStrip1.SuspendLayout(); 55 | ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); 56 | this.splitContainer1.Panel1.SuspendLayout(); 57 | this.splitContainer1.Panel2.SuspendLayout(); 58 | this.splitContainer1.SuspendLayout(); 59 | this.SuspendLayout(); 60 | // 61 | // propertyGrid1 62 | // 63 | this.propertyGrid1.Dock = System.Windows.Forms.DockStyle.Fill; 64 | this.propertyGrid1.Location = new System.Drawing.Point(0, 0); 65 | this.propertyGrid1.Name = "propertyGrid1"; 66 | this.propertyGrid1.Size = new System.Drawing.Size(356, 391); 67 | this.propertyGrid1.TabIndex = 0; 68 | this.propertyGrid1.PropertyValueChanged += new System.Windows.Forms.PropertyValueChangedEventHandler(this.PropertyGrid1_PropertyValueChanged); 69 | // 70 | // treeView1 71 | // 72 | this.treeView1.ContextMenuStrip = this.contextMenuStrip1; 73 | this.treeView1.Dock = System.Windows.Forms.DockStyle.Fill; 74 | this.treeView1.Location = new System.Drawing.Point(0, 0); 75 | this.treeView1.Name = "treeView1"; 76 | this.treeView1.Size = new System.Drawing.Size(180, 391); 77 | this.treeView1.TabIndex = 1; 78 | this.treeView1.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.TreeView1_AfterSelect); 79 | // 80 | // contextMenuStrip1 81 | // 82 | this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 83 | this.addEntryToolStripMenuItem, 84 | this.duplicateToolStripMenuItem, 85 | this.deleteToolStripMenuItem, 86 | this.toolStripSeparator3, 87 | this.templatesToolStripMenuItem, 88 | this.toolStripSeparator2, 89 | this.expandAllToolStripMenuItem}); 90 | this.contextMenuStrip1.Name = "contextMenuStrip1"; 91 | this.contextMenuStrip1.Size = new System.Drawing.Size(181, 148); 92 | // 93 | // addEntryToolStripMenuItem 94 | // 95 | this.addEntryToolStripMenuItem.Name = "addEntryToolStripMenuItem"; 96 | this.addEntryToolStripMenuItem.Size = new System.Drawing.Size(180, 22); 97 | this.addEntryToolStripMenuItem.Text = "Add entry"; 98 | this.addEntryToolStripMenuItem.Click += new System.EventHandler(this.AddEntryToolStripMenuItem_Click); 99 | // 100 | // duplicateToolStripMenuItem 101 | // 102 | this.duplicateToolStripMenuItem.Name = "duplicateToolStripMenuItem"; 103 | this.duplicateToolStripMenuItem.Size = new System.Drawing.Size(180, 22); 104 | this.duplicateToolStripMenuItem.Text = "Duplicate"; 105 | this.duplicateToolStripMenuItem.Click += new System.EventHandler(this.duplicateToolStripMenuItem_Click); 106 | // 107 | // deleteToolStripMenuItem 108 | // 109 | this.deleteToolStripMenuItem.Name = "deleteToolStripMenuItem"; 110 | this.deleteToolStripMenuItem.Size = new System.Drawing.Size(180, 22); 111 | this.deleteToolStripMenuItem.Text = "Delete"; 112 | this.deleteToolStripMenuItem.Click += new System.EventHandler(this.DeleteToolStripMenuItem_Click); 113 | // 114 | // toolStripSeparator2 115 | // 116 | this.toolStripSeparator2.Name = "toolStripSeparator2"; 117 | this.toolStripSeparator2.Size = new System.Drawing.Size(177, 6); 118 | // 119 | // expandAllToolStripMenuItem 120 | // 121 | this.expandAllToolStripMenuItem.Name = "expandAllToolStripMenuItem"; 122 | this.expandAllToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.L))); 123 | this.expandAllToolStripMenuItem.Size = new System.Drawing.Size(180, 22); 124 | this.expandAllToolStripMenuItem.Text = "Expand all"; 125 | this.expandAllToolStripMenuItem.Click += new System.EventHandler(this.expandAllToolStripMenuItem_Click); 126 | // 127 | // menuStrip1 128 | // 129 | this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 130 | this.fileToolStripMenuItem, 131 | this.ByteOrderToolStripMenuItem}); 132 | this.menuStrip1.Location = new System.Drawing.Point(0, 0); 133 | this.menuStrip1.Name = "menuStrip1"; 134 | this.menuStrip1.Size = new System.Drawing.Size(540, 24); 135 | this.menuStrip1.TabIndex = 2; 136 | this.menuStrip1.Text = "menuStrip1"; 137 | // 138 | // fileToolStripMenuItem 139 | // 140 | this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { 141 | this.saveAsToolStripMenuItem, 142 | this.saveToolStripMenuItem, 143 | this.toolStripSeparator1, 144 | this.exportToJSONToolStripMenuItem, 145 | this.importFromJSONToolStripMenuItem}); 146 | this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; 147 | this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); 148 | this.fileToolStripMenuItem.Text = "File"; 149 | // 150 | // saveAsToolStripMenuItem 151 | // 152 | this.saveAsToolStripMenuItem.Name = "saveAsToolStripMenuItem"; 153 | this.saveAsToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Shift) 154 | | System.Windows.Forms.Keys.S))); 155 | this.saveAsToolStripMenuItem.Size = new System.Drawing.Size(212, 22); 156 | this.saveAsToolStripMenuItem.Text = "Save as"; 157 | this.saveAsToolStripMenuItem.Click += new System.EventHandler(this.SaveToolStripMenuItem_Click); 158 | // 159 | // saveToolStripMenuItem 160 | // 161 | this.saveToolStripMenuItem.Name = "saveToolStripMenuItem"; 162 | this.saveToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.S))); 163 | this.saveToolStripMenuItem.Size = new System.Drawing.Size(212, 22); 164 | this.saveToolStripMenuItem.Text = "Save"; 165 | this.saveToolStripMenuItem.Visible = false; 166 | this.saveToolStripMenuItem.Click += new System.EventHandler(this.SaveAsToArchiveToolStripMenuItem_Click); 167 | // 168 | // toolStripSeparator1 169 | // 170 | this.toolStripSeparator1.Name = "toolStripSeparator1"; 171 | this.toolStripSeparator1.Size = new System.Drawing.Size(209, 6); 172 | // 173 | // exportToJSONToolStripMenuItem 174 | // 175 | this.exportToJSONToolStripMenuItem.Name = "exportToJSONToolStripMenuItem"; 176 | this.exportToJSONToolStripMenuItem.Size = new System.Drawing.Size(212, 22); 177 | this.exportToJSONToolStripMenuItem.Text = "Export to JSON"; 178 | this.exportToJSONToolStripMenuItem.Click += new System.EventHandler(this.ExportToJSONToolStripMenuItem_Click); 179 | // 180 | // importFromJSONToolStripMenuItem 181 | // 182 | this.importFromJSONToolStripMenuItem.Name = "importFromJSONToolStripMenuItem"; 183 | this.importFromJSONToolStripMenuItem.Size = new System.Drawing.Size(212, 22); 184 | this.importFromJSONToolStripMenuItem.Text = "Import from JSON"; 185 | this.importFromJSONToolStripMenuItem.Click += new System.EventHandler(this.ImportFromJSONToolStripMenuItem_Click); 186 | // 187 | // ByteOrderToolStripMenuItem 188 | // 189 | this.ByteOrderToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { 190 | this.SwitchByteOrderToolStripMenuItem}); 191 | this.ByteOrderToolStripMenuItem.Name = "ByteOrderToolStripMenuItem"; 192 | this.ByteOrderToolStripMenuItem.Size = new System.Drawing.Size(113, 20); 193 | this.ByteOrderToolStripMenuItem.Text = "Big endian (Wii u)"; 194 | // 195 | // SwitchByteOrderToolStripMenuItem 196 | // 197 | this.SwitchByteOrderToolStripMenuItem.Name = "SwitchByteOrderToolStripMenuItem"; 198 | this.SwitchByteOrderToolStripMenuItem.Size = new System.Drawing.Size(234, 22); 199 | this.SwitchByteOrderToolStripMenuItem.Text = "Switch to little endian (Switch)"; 200 | this.SwitchByteOrderToolStripMenuItem.Click += new System.EventHandler(this.SwitchByteOrderToolStripMenuItem_Click); 201 | // 202 | // splitContainer1 203 | // 204 | this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; 205 | this.splitContainer1.Location = new System.Drawing.Point(0, 24); 206 | this.splitContainer1.Name = "splitContainer1"; 207 | // 208 | // splitContainer1.Panel1 209 | // 210 | this.splitContainer1.Panel1.Controls.Add(this.treeView1); 211 | // 212 | // splitContainer1.Panel2 213 | // 214 | this.splitContainer1.Panel2.Controls.Add(this.propertyGrid1); 215 | this.splitContainer1.Size = new System.Drawing.Size(540, 391); 216 | this.splitContainer1.SplitterDistance = 180; 217 | this.splitContainer1.TabIndex = 3; 218 | // 219 | // templatesToolStripMenuItem 220 | // 221 | this.templatesToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { 222 | this.noTemplatesAvailableToolStripMenuItem}); 223 | this.templatesToolStripMenuItem.Name = "templatesToolStripMenuItem"; 224 | this.templatesToolStripMenuItem.Size = new System.Drawing.Size(180, 22); 225 | this.templatesToolStripMenuItem.Text = "Insert template"; 226 | this.templatesToolStripMenuItem.DropDownOpening += new System.EventHandler(this.templatesToolStripMenuItem_DropDownOpening); 227 | // 228 | // toolStripSeparator3 229 | // 230 | this.toolStripSeparator3.Name = "toolStripSeparator3"; 231 | this.toolStripSeparator3.Size = new System.Drawing.Size(177, 6); 232 | // 233 | // noTemplatesAvailableToolStripMenuItem 234 | // 235 | this.noTemplatesAvailableToolStripMenuItem.Name = "noTemplatesAvailableToolStripMenuItem"; 236 | this.noTemplatesAvailableToolStripMenuItem.Size = new System.Drawing.Size(194, 22); 237 | this.noTemplatesAvailableToolStripMenuItem.Text = "No templates available"; 238 | // 239 | // BflanEditor 240 | // 241 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 242 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 243 | this.ClientSize = new System.Drawing.Size(540, 415); 244 | this.Controls.Add(this.splitContainer1); 245 | this.Controls.Add(this.menuStrip1); 246 | this.KeyPreview = true; 247 | this.MainMenuStrip = this.menuStrip1; 248 | this.Name = "BflanEditor"; 249 | this.Text = "BflanEditor"; 250 | this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.BflanEditor_FormClosing); 251 | this.Load += new System.EventHandler(this.BflanEditor_Load); 252 | this.LocationChanged += new System.EventHandler(this.BflanEditor_LocationChanged); 253 | this.Click += new System.EventHandler(this.BflanEditor_Click); 254 | this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.BflanEditor_KeyDown); 255 | this.contextMenuStrip1.ResumeLayout(false); 256 | this.menuStrip1.ResumeLayout(false); 257 | this.menuStrip1.PerformLayout(); 258 | this.splitContainer1.Panel1.ResumeLayout(false); 259 | this.splitContainer1.Panel2.ResumeLayout(false); 260 | ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); 261 | this.splitContainer1.ResumeLayout(false); 262 | this.ResumeLayout(false); 263 | this.PerformLayout(); 264 | 265 | } 266 | 267 | #endregion 268 | 269 | private System.Windows.Forms.PropertyGrid propertyGrid1; 270 | private System.Windows.Forms.TreeView treeView1; 271 | private System.Windows.Forms.MenuStrip menuStrip1; 272 | private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem; 273 | private System.Windows.Forms.ToolStripMenuItem saveAsToolStripMenuItem; 274 | private System.Windows.Forms.ToolStripMenuItem saveToolStripMenuItem; 275 | private System.Windows.Forms.ContextMenuStrip contextMenuStrip1; 276 | private System.Windows.Forms.ToolStripMenuItem addEntryToolStripMenuItem; 277 | private System.Windows.Forms.ToolStripMenuItem deleteToolStripMenuItem; 278 | private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; 279 | private System.Windows.Forms.ToolStripMenuItem exportToJSONToolStripMenuItem; 280 | private System.Windows.Forms.ToolStripMenuItem importFromJSONToolStripMenuItem; 281 | private System.Windows.Forms.ToolStripMenuItem ByteOrderToolStripMenuItem; 282 | private System.Windows.Forms.ToolStripMenuItem SwitchByteOrderToolStripMenuItem; 283 | private System.Windows.Forms.SplitContainer splitContainer1; 284 | private System.Windows.Forms.ToolStripSeparator toolStripSeparator2; 285 | private System.Windows.Forms.ToolStripMenuItem expandAllToolStripMenuItem; 286 | private System.Windows.Forms.ToolStripMenuItem duplicateToolStripMenuItem; 287 | private System.Windows.Forms.ToolStripSeparator toolStripSeparator3; 288 | private System.Windows.Forms.ToolStripMenuItem templatesToolStripMenuItem; 289 | private System.Windows.Forms.ToolStripMenuItem noTemplatesAvailableToolStripMenuItem; 290 | } 291 | } -------------------------------------------------------------------------------- /BflytPreview/BflanEditor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | using System.IO; 11 | using SwitchThemes.Common; 12 | using BflytPreview.EditorForms; 13 | using Newtonsoft.Json; 14 | using SwitchThemes.Common.Serializers; 15 | using SwitchThemes.Common.Bflan; 16 | using System.Diagnostics; 17 | using BflytPreview.Automation; 18 | 19 | namespace BflytPreview 20 | { 21 | public partial class BflanEditor : Form 22 | { 23 | readonly LoadedTemplate[] BflanTemplates; 24 | 25 | BflanFile file = null; 26 | 27 | IFileWriter _saveTo; 28 | public IFileWriter SaveTo 29 | { 30 | get => _saveTo; 31 | set 32 | { 33 | _saveTo?.EditorClosed(); 34 | _saveTo = value; 35 | saveToolStripMenuItem.Visible = _saveTo != null; 36 | this.Text = value?.ToString() ?? ""; 37 | } 38 | } 39 | 40 | class LoadedTemplate 41 | { 42 | public BflanTemplate Manifest; 43 | public string FullPathToTemplate; 44 | 45 | public static LoadedTemplate FromJsonManifest(string path) 46 | { 47 | path = Path.GetFullPath(path); 48 | var res = new LoadedTemplate 49 | { 50 | Manifest = JsonConvert.DeserializeObject(File.ReadAllText(path)) 51 | }; 52 | 53 | if (res.Manifest == null) 54 | throw new Exception("Couldn't load the json for " + path); 55 | 56 | if (Path.IsPathRooted(res.Manifest.FileName)) 57 | { 58 | res.FullPathToTemplate = res.Manifest.FileName; 59 | } 60 | else 61 | { 62 | var root = Path.GetDirectoryName(path); 63 | res.FullPathToTemplate = Path.Combine(root, res.Manifest.FileName); 64 | } 65 | 66 | if (!File.Exists(res.FullPathToTemplate)) 67 | throw new Exception($"Couldn't find the template file for {path}, tried searchingi n {res.FullPathToTemplate}"); 68 | 69 | return res; 70 | } 71 | } 72 | 73 | public BflanEditor(BflanFile _file, IFileWriter saveTo) 74 | { 75 | InitializeComponent(); 76 | file = _file; 77 | SaveTo = saveTo; 78 | 79 | try 80 | { 81 | if (Directory.Exists("BflanTemplates")) 82 | BflanTemplates = Directory.EnumerateFiles("BflanTemplates", "*.json") 83 | .Select(x => LoadedTemplate.FromJsonManifest(x)) 84 | .ToArray(); 85 | else 86 | BflanTemplates = new LoadedTemplate[0]; 87 | } 88 | catch (Exception ex) 89 | { 90 | MessageBox.Show("Error while loading BFLAn template: " + ex.Message + "\r\n\r\nFix the issue then close and reopen this editor to reload the files"); 91 | BflanTemplates = new LoadedTemplate[0]; 92 | } 93 | } 94 | 95 | private void BflanEditor_Load(object sender, EventArgs e) 96 | { 97 | if (file == null) this.Close(); 98 | UpdateTreeview(); 99 | FormBringToFront(); 100 | } 101 | 102 | void UpdateByteOrder() 103 | { 104 | ByteOrderToolStripMenuItem.Text = 105 | file.byteOrder == Syroot.BinaryData.ByteOrder.BigEndian ? 106 | "Big endian (Wii u)" : "Little endian (Switch/3DS)"; 107 | SwitchByteOrderToolStripMenuItem.Text = 108 | file.byteOrder == Syroot.BinaryData.ByteOrder.BigEndian ? 109 | "Change to little endian" : "Change to big endian"; 110 | } 111 | 112 | void UpdateTreeview() 113 | { 114 | UpdateByteOrder(); 115 | treeView1.Nodes.Clear(); 116 | foreach (var section in file.Sections) 117 | BflanObjectTonode(section, treeView1.Nodes); 118 | } 119 | 120 | void BflanObjectTonode(object obj, TreeNodeCollection parent) 121 | { 122 | var subnode = parent.Add(obj.ToString()); 123 | subnode.Tag = obj; 124 | BflanObjectChildrenToNode(obj, subnode); 125 | } 126 | 127 | void BflanObjectChildrenToNode(object obj, TreeNode node) 128 | { 129 | if (obj is Pai1Section paisection) 130 | { 131 | foreach (var entry in paisection.Entries) 132 | BflanObjectTonode(entry, node.Nodes); 133 | } 134 | else if (obj is Pai1Section.PaiEntry paientry) 135 | { 136 | foreach (var tag in paientry.Tags) 137 | BflanObjectTonode(tag, node.Nodes); 138 | } 139 | else if (obj is Pai1Section.PaiTag paitag) 140 | { 141 | foreach (var entry in paitag.Entries) 142 | BflanObjectTonode(entry, node.Nodes); 143 | } 144 | } 145 | 146 | private void TreeView1_AfterSelect(object sender, TreeViewEventArgs e) => 147 | propertyGrid1.SelectedObject = e.Node.Tag; 148 | 149 | private void SaveToolStripMenuItem_Click(object sender, EventArgs e) 150 | { 151 | SaveFileDialog sav = new SaveFileDialog() { Filter = "Bflan file|*.bflan" }; 152 | if (sav.ShowDialog() != DialogResult.OK) return; 153 | SaveTo = new DiskFileProvider(sav.FileName); 154 | SaveTo.Save(file.WriteFile()); 155 | } 156 | 157 | private void SaveAsToArchiveToolStripMenuItem_Click(object sender, EventArgs e) 158 | { 159 | if (_saveTo != null) 160 | _saveTo.Save(file.WriteFile()); 161 | else saveAsToolStripMenuItem.PerformClick(); 162 | } 163 | 164 | private void BflanEditor_FormClosing(object sender, FormClosingEventArgs e) 165 | { 166 | SaveTo?.EditorClosed(); 167 | Settings.Default.ShowImage = false; 168 | } 169 | 170 | void FormBringToFront() 171 | { 172 | this.Activate(); 173 | this.BringToFront(); 174 | this.Focus(); 175 | } 176 | 177 | private void BflanEditor_Click(object sender, EventArgs e) => FormBringToFront(); 178 | private void BflanEditor_LocationChanged(object sender, EventArgs e) => FormBringToFront(); 179 | 180 | private void InsertEntry(object target, object entry, TreeNode viewNode) 181 | { 182 | if (target is Pai1Section sect && entry is Pai1Section.PaiEntry paiEntry) 183 | sect.Entries.Add(paiEntry); 184 | else if (target is Pai1Section.PaiEntry targetPai && entry is Pai1Section.PaiTag paiTag) 185 | targetPai.Tags.Add(paiTag); 186 | else if (target is Pai1Section.PaiTag targetPaiTag && entry is Pai1Section.PaiTagEntry paiTagEntry) 187 | targetPaiTag.Entries.Add(paiTagEntry); 188 | else 189 | { 190 | MessageBox.Show("Can't insert the parent object here"); 191 | return; 192 | } 193 | 194 | BflanObjectTonode(entry, viewNode.Nodes); 195 | } 196 | 197 | private void AddEntryToolStripMenuItem_Click(object sender, EventArgs e) 198 | { 199 | var parent = treeView1.SelectedNode.Tag; 200 | object entry = null; 201 | 202 | if (parent is Pai1Section) 203 | entry = new Pai1Section.PaiEntry() { Name = "NEW-" }; 204 | else if (parent is Pai1Section.PaiEntry) 205 | entry = new Pai1Section.PaiTag() { TagType = "NEW-" }; 206 | else if (parent is Pai1Section.PaiTag paiTag) 207 | entry = new Pai1Section.PaiTagEntry() { FLEUEntryName = paiTag.IsFLEU ? "New FLEU entry" : null }; 208 | else 209 | { 210 | MessageBox.Show("Can't add an entry to the parent object"); 211 | return; 212 | } 213 | 214 | if (entry != null) 215 | InsertEntry(parent, entry, treeView1.SelectedNode); 216 | } 217 | 218 | private void duplicateToolStripMenuItem_Click(object sender, EventArgs e) 219 | { 220 | if (treeView1.SelectedNode == null || treeView1.SelectedNode.Parent == null) return; 221 | 222 | var clone = ((ICloneable)treeView1.SelectedNode.Tag).Clone(); 223 | 224 | // Can names be duplicate ? 225 | var parent = treeView1.SelectedNode.Parent; 226 | InsertEntry(parent.Tag, clone, parent); 227 | } 228 | 229 | private void DeleteToolStripMenuItem_Click(object sender, EventArgs e) 230 | { 231 | var selected = treeView1.SelectedNode; 232 | var parent = treeView1.SelectedNode?.Parent; 233 | if (selected.Tag is Pai1Section.PaiEntry entry) 234 | { 235 | var par = (Pai1Section)parent.Tag; 236 | par.Entries.Remove(entry); 237 | } 238 | else if (selected.Tag is Pai1Section.PaiTag tag) 239 | { 240 | var par = (Pai1Section.PaiEntry)parent.Tag; 241 | par.Tags.Remove(tag); 242 | } 243 | else if (selected.Tag is Pai1Section.PaiTagEntry tagEntry) 244 | { 245 | var par = (Pai1Section.PaiTag)parent.Tag; 246 | par.Entries.Remove(tagEntry); 247 | } 248 | else 249 | { 250 | MessageBox.Show("Can't remove this element"); 251 | return; 252 | } 253 | 254 | parent.Nodes.Remove(selected); 255 | } 256 | 257 | private void ExportToJSONToolStripMenuItem_Click(object sender, EventArgs e) 258 | { 259 | SaveFileDialog sav = new SaveFileDialog() { Filter = "JSON file|*.json" }; 260 | if (sav.ShowDialog() != DialogResult.OK) return; 261 | File.WriteAllText(sav.FileName, JsonConvert.SerializeObject(BflanSerializer.Serialize(file), Formatting.Indented)); 262 | } 263 | 264 | private void ImportFromJSONToolStripMenuItem_Click(object sender, EventArgs e) 265 | { 266 | OpenFileDialog opn = new OpenFileDialog() { Filter = "JSON file|*.json" }; 267 | if (opn.ShowDialog() != DialogResult.OK) return; 268 | var SerializedFile = JsonConvert.DeserializeObject(File.ReadAllText(opn.FileName)); 269 | var newFile = SerializedFile.Deserialize(); 270 | if (file != null && newFile.Version != file.Version) 271 | { 272 | if (MessageBox.Show("Do you want to keep the format version of the original file ?\n(You should for custom themes)", "", MessageBoxButtons.YesNo) == DialogResult.Yes) 273 | newFile.Version = file.Version; 274 | } 275 | file = newFile; 276 | UpdateTreeview(); 277 | } 278 | 279 | public static Form OpenFromJson() 280 | { 281 | var b = new BflanEditor(null, null); 282 | b.ImportFromJSONToolStripMenuItem_Click(null,null); 283 | if (b.file == null) return null; 284 | return b; 285 | } 286 | 287 | private void PropertyGrid1_PropertyValueChanged(object s, PropertyValueChangedEventArgs e) 288 | { 289 | treeView1.SelectedNode.Text = treeView1.SelectedNode.Tag.ToString(); 290 | treeView1.Invalidate(); 291 | } 292 | 293 | private void SwitchByteOrderToolStripMenuItem_Click(object sender, EventArgs e) 294 | { 295 | file.byteOrder = file.byteOrder == Syroot.BinaryData.ByteOrder.BigEndian ? 296 | Syroot.BinaryData.ByteOrder.LittleEndian : Syroot.BinaryData.ByteOrder.BigEndian; 297 | UpdateByteOrder(); 298 | } 299 | 300 | private void BflanEditor_KeyDown(object sender, KeyEventArgs e) 301 | { 302 | e.SuppressKeyPress = true; 303 | if (e.Shift && e.Control && e.KeyCode == Keys.S) 304 | saveAsToolStripMenuItem.PerformClick(); 305 | else if (e.Control && e.KeyCode == Keys.S) 306 | saveToolStripMenuItem.PerformClick(); 307 | else if (e.Control && e.KeyCode == Keys.L) 308 | treeView1.ExpandAll(); 309 | else if (e.Control && e.KeyCode == Keys.K) 310 | treeView1.CollapseAll(); 311 | else e.SuppressKeyPress = false; 312 | } 313 | 314 | private void expandAllToolStripMenuItem_Click(object sender, EventArgs e) => 315 | treeView1.ExpandAll(); 316 | 317 | private void templatesToolStripMenuItem_DropDownOpening(object sender, EventArgs e) 318 | { 319 | templatesToolStripMenuItem.DropDownItems.Clear(); 320 | 321 | var currentItem = treeView1.SelectedNode?.Tag; 322 | LoadedTemplate[] templates = null; 323 | 324 | if (currentItem != null) 325 | { 326 | if (!(currentItem is IBflanGenericCollection)) 327 | return; 328 | 329 | if (currentItem is Pai1Section) // Contains PaiEntry[] 330 | templates = BflanTemplates.Where(x => x.Manifest.Target == Automation.BflanTemplateKind.Pai1).ToArray(); 331 | else if (currentItem is Pai1Section.PaiEntry) // contains PaiTag[] 332 | templates = BflanTemplates.Where(x => x.Manifest.Target == Automation.BflanTemplateKind.PaiEntry).ToArray(); 333 | else if (currentItem is Pai1Section.PaiTag) // contains PaiTagEntry[] 334 | templates = BflanTemplates.Where(x => x.Manifest.Target == Automation.BflanTemplateKind.PaiTag).ToArray(); 335 | else if (currentItem is Pai1Section.PaiTagEntry) // contains Keyframe[] 336 | templates = BflanTemplates.Where(x => x.Manifest.Target == Automation.BflanTemplateKind.PaiTagEntry).ToArray(); 337 | } 338 | 339 | if (templates != null && templates.Length != 0) 340 | { 341 | foreach (var t in templates) 342 | { 343 | var item = templatesToolStripMenuItem.DropDownItems.Add(t.Manifest.Name); 344 | item.Tag = t; 345 | item.Click += templateDynamicItem_Click; 346 | } 347 | } 348 | else 349 | { 350 | templatesToolStripMenuItem.DropDownItems.Add("No templates available for this item"); 351 | } 352 | } 353 | 354 | private void templateDynamicItem_Click(object sender, EventArgs e) 355 | { 356 | if (!(treeView1.SelectedNode?.Tag is IBflanGenericCollection bflanItem)) 357 | return; 358 | 359 | var template = ((ToolStripItem)sender).Tag as LoadedTemplate; 360 | if (template == null) return; 361 | 362 | if (!File.Exists(template.FullPathToTemplate)) 363 | { 364 | MessageBox.Show($"The file {template.FullPathToTemplate} associated with this template was not found"); 365 | return; 366 | } 367 | 368 | var content = File.ReadAllText(template.FullPathToTemplate); 369 | using var importer = new ValueImportForm(template.Manifest, content); 370 | importer.ShowDialog(); 371 | 372 | if (importer.Result == null) 373 | return; 374 | 375 | object[] deserialized = template.Manifest.DeserializeContent(importer.Result); 376 | 377 | foreach (var obj in deserialized) 378 | bflanItem.InsertElement(obj); 379 | 380 | treeView1.SelectedNode.Nodes.Clear(); 381 | BflanObjectChildrenToNode(bflanItem, treeView1.SelectedNode); 382 | } 383 | } 384 | } 385 | -------------------------------------------------------------------------------- /BflytPreview/BflanEditor.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 132, 17 122 | 123 | 124 | 17, 17 125 | 126 | -------------------------------------------------------------------------------- /BflytPreview/BflanTemplates/ColorAnimation.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "Animate color RGBA", 3 | "FileName": "ColorAnimation.template", 4 | "Target": "PaiEntry", 5 | "Parameters": [ 6 | { 7 | "Kind": "Int", 8 | "Name": "Start frame", 9 | "Default": "0", 10 | "Keyword": "%START_FRAME%" 11 | }, 12 | { 13 | "Kind": "Int", 14 | "Name": "End frame", 15 | "Default": "20", 16 | "Keyword": "%END_FRAME%" 17 | }, 18 | { 19 | "Kind": "Int", 20 | "Name": "Red start value", 21 | "Default": "255", 22 | "Keyword": "%RED_START_VAL%" 23 | }, 24 | { 25 | "Kind": "Int", 26 | "Name": "Red end value", 27 | "Default": "0", 28 | "Keyword": "%RED_END_VAL%" 29 | }, 30 | { 31 | "Kind": "Int", 32 | "Name": "Green start value", 33 | "Default": "255", 34 | "Keyword": "%GREEN_START_VAL%" 35 | }, 36 | { 37 | "Kind": "Int", 38 | "Name": "Green end value", 39 | "Default": "0", 40 | "Keyword": "%GREEN_END_VAL%" 41 | }, 42 | { 43 | "Kind": "Int", 44 | "Name": "Blue start value", 45 | "Default": "255", 46 | "Keyword": "%BLUE_START_VAL%" 47 | }, 48 | { 49 | "Kind": "Int", 50 | "Name": "Blue end value", 51 | "Default": "0", 52 | "Keyword": "%BLUE_END_VAL%" 53 | }, 54 | { 55 | "Kind": "Int", 56 | "Name": "Alpha start value", 57 | "Default": "255", 58 | "Keyword": "%ALPHA_START_VAL%" 59 | }, 60 | { 61 | "Kind": "Int", 62 | "Name": "Alpha end value", 63 | "Default": "0", 64 | "Keyword": "%ALPHA_END_VAL%" 65 | } 66 | ] 67 | } -------------------------------------------------------------------------------- /BflytPreview/BflanTemplates/ColorAnimation.template: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Unknown": 0, 4 | "TagType": "FLVC", 5 | "Entries": [ 6 | { 7 | "Index": 0, 8 | "AnimationTarget": 0, 9 | "DataType": 2, 10 | "KeyFrames": [ 11 | { "Frame": %START_FRAME%, "Value": %RED_START_VAL%, "Blend": 0 }, 12 | { "Frame": %END_FRAME%, "Value": %RED_END_VAL%, "Blend": 0 } 13 | ], 14 | "FLEUUnknownInt": 0, 15 | "FLEUEntryName": "" 16 | }, 17 | { 18 | "Index": 0, 19 | "AnimationTarget": 4, 20 | "DataType": 2, 21 | "KeyFrames": [ 22 | { "Frame": %START_FRAME%, "Value": %RED_START_VAL%, "Blend": 0 }, 23 | { "Frame": %END_FRAME%, "Value": %RED_END_VAL%, "Blend": 0 } 24 | ], 25 | "FLEUUnknownInt": 0, 26 | "FLEUEntryName": "" 27 | }, 28 | { 29 | "Index": 0, 30 | "AnimationTarget": 8, 31 | "DataType": 2, 32 | "KeyFrames": [ 33 | { "Frame": %START_FRAME%, "Value": %RED_START_VAL%, "Blend": 0 }, 34 | { "Frame": %END_FRAME%, "Value": %RED_END_VAL%, "Blend": 0 } 35 | ], 36 | "FLEUUnknownInt": 0, 37 | "FLEUEntryName": "" 38 | }, 39 | { 40 | "Index": 0, 41 | "AnimationTarget": 12, 42 | "DataType": 2, 43 | "KeyFrames": [ 44 | { "Frame": %START_FRAME%, "Value": %RED_START_VAL%, "Blend": 0 }, 45 | { "Frame": %END_FRAME%, "Value": %RED_END_VAL%, "Blend": 0 } 46 | ], 47 | "FLEUUnknownInt": 0, 48 | "FLEUEntryName": "" 49 | } 50 | ] 51 | } 52 | ] -------------------------------------------------------------------------------- /BflytPreview/BflytPreview.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {D59C0348-7D8E-46DF-8761-1CA9C5FF5556} 8 | WinExe 9 | BflytPreview 10 | Switch Layout Editor 11 | v4.8 12 | 512 13 | true 14 | 15 | 16 | publish\ 17 | true 18 | Disk 19 | false 20 | Foreground 21 | 7 22 | Days 23 | false 24 | false 25 | true 26 | 0 27 | 1.0.0.%2a 28 | false 29 | false 30 | true 31 | 32 | 33 | 34 | AnyCPU 35 | true 36 | full 37 | false 38 | bin\Debug\ 39 | TRACE;DEBUG;WIN;LYTEDITOR 40 | prompt 41 | 4 42 | 8.0 43 | 44 | 45 | AnyCPU 46 | none 47 | true 48 | bin\Release\ 49 | TRACE;WIN;LYTEDITOR 50 | prompt 51 | 4 52 | 8.0 53 | false 54 | 55 | 56 | icon.ico 57 | 58 | 59 | true 60 | 61 | 62 | 63 | ..\packages\Newtonsoft.Json.13.0.2\lib\net45\Newtonsoft.Json.dll 64 | 65 | 66 | ..\packages\Octokit.5.0.0\lib\netstandard2.0\Octokit.dll 67 | 68 | 69 | ..\packages\OpenTK.3.3.3\lib\net20\OpenTK.dll 70 | 71 | 72 | ..\packages\OpenTK.GLControl.3.3.3\lib\net20\OpenTK.GLControl.dll 73 | 74 | 75 | 76 | 77 | 78 | ..\packages\System.Collections.Specialized.4.3.0\lib\net46\System.Collections.Specialized.dll 79 | True 80 | True 81 | 82 | 83 | 84 | 85 | ..\packages\System.ComponentModel.Primitives.4.3.0\lib\net45\System.ComponentModel.Primitives.dll 86 | True 87 | True 88 | 89 | 90 | 91 | 92 | 93 | ..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll 94 | 95 | 96 | 97 | ..\packages\System.IO.Compression.ZipFile.4.3.0\lib\net46\System.IO.Compression.ZipFile.dll 98 | 99 | 100 | ..\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll 101 | True 102 | True 103 | 104 | 105 | ..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll 106 | True 107 | True 108 | 109 | 110 | ..\packages\System.IO.FileSystem.Watcher.4.3.0\lib\net46\System.IO.FileSystem.Watcher.dll 111 | True 112 | True 113 | 114 | 115 | ..\packages\System.Reflection.TypeExtensions.4.7.0\lib\net461\System.Reflection.TypeExtensions.dll 116 | 117 | 118 | ..\packages\System.Runtime.4.3.1\lib\net462\System.Runtime.dll 119 | True 120 | True 121 | 122 | 123 | ..\packages\System.Runtime.Extensions.4.3.1\lib\net462\System.Runtime.Extensions.dll 124 | True 125 | True 126 | 127 | 128 | ..\packages\System.Runtime.InteropServices.4.3.0\lib\net463\System.Runtime.InteropServices.dll 129 | True 130 | True 131 | 132 | 133 | ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll 134 | True 135 | True 136 | 137 | 138 | ..\packages\System.Threading.Thread.4.3.0\lib\net46\System.Threading.Thread.dll 139 | True 140 | True 141 | 142 | 143 | ..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | Form 163 | 164 | 165 | ValueImportForm.cs 166 | 167 | 168 | Form 169 | 170 | 171 | BflanEditor.cs 172 | 173 | 174 | 175 | 176 | 177 | Form 178 | 179 | 180 | LayoutDiffForm.cs 181 | 182 | 183 | Form 184 | 185 | 186 | SzsEditor.cs 187 | 188 | 189 | Form 190 | 191 | 192 | EditorView.cs 193 | 194 | 195 | Form 196 | 197 | 198 | MainForm.cs 199 | 200 | 201 | 202 | 203 | True 204 | True 205 | Settings.settings 206 | 207 | 208 | Form 209 | 210 | 211 | SettingsWindow.cs 212 | 213 | 214 | ValueImportForm.cs 215 | 216 | 217 | BflanEditor.cs 218 | 219 | 220 | LayoutDiffForm.cs 221 | 222 | 223 | SzsEditor.cs 224 | 225 | 226 | EditorView.cs 227 | 228 | 229 | MainForm.cs 230 | 231 | 232 | ResXFileCodeGenerator 233 | Resources.Designer.cs 234 | Designer 235 | 236 | 237 | True 238 | Resources.resx 239 | True 240 | 241 | 242 | SettingsWindow.cs 243 | 244 | 245 | PreserveNewest 246 | 247 | 248 | PreserveNewest 249 | 250 | 251 | 252 | 253 | SettingsSingleFileGenerator 254 | Settings.Designer.cs 255 | 256 | 257 | True 258 | Settings.settings 259 | True 260 | 261 | 262 | SettingsSingleFileGenerator 263 | Settings.Designer.cs 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | False 276 | Microsoft .NET Framework 4.6.1 %28x86 et x64%29 277 | true 278 | 279 | 280 | False 281 | .NET Framework 3.5 SP1 282 | false 283 | 284 | 285 | 286 | 287 | -------------------------------------------------------------------------------- /BflytPreview/EditorForms/HexEditorForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.Design; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows.Forms; 8 | 9 | namespace BflytPreview.EditorForms 10 | { 11 | public class HexEditorForm 12 | { 13 | public static void Show(byte[] data) 14 | { 15 | Form f = new Form(); 16 | f.Text = "Hex editor"; 17 | ByteViewer bv = new ByteViewer(); 18 | bv.Dock = DockStyle.Fill; 19 | f.Controls.Add(bv); 20 | bv.SetBytes(data); 21 | f.TopMost = true; 22 | f.Show(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /BflytPreview/EditorForms/IFileProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace BflytPreview 8 | { 9 | public interface IFileWriter 10 | { 11 | void Save(byte[] Data); 12 | void EditorClosed(); 13 | 14 | string Path { get; } 15 | } 16 | 17 | public class DiskFileProvider : IFileWriter 18 | { 19 | public DiskFileProvider(string path) => 20 | Path = path; 21 | 22 | public string Path { get; set; } 23 | 24 | public void EditorClosed() { } 25 | 26 | public void Save(byte[] Data) => 27 | System.IO.File.WriteAllBytes(Path, Data); 28 | 29 | public override string ToString() => Path; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /BflytPreview/EditorForms/InputDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows.Forms; 8 | 9 | namespace BflytPreview.EditorForms 10 | { 11 | public static class InputDialog 12 | { 13 | public static DialogResult Show(string title, string promptText, ref string value) 14 | { 15 | Form form = new Form(); 16 | Label label = new Label(); 17 | TextBox textBox = new TextBox(); 18 | Button buttonOk = new Button(); 19 | Button buttonCancel = new Button(); 20 | 21 | form.Text = title; 22 | label.Text = promptText; 23 | textBox.Text = value; 24 | 25 | buttonOk.Text = "OK"; 26 | buttonCancel.Text = "Cancel"; 27 | buttonOk.DialogResult = DialogResult.OK; 28 | buttonCancel.DialogResult = DialogResult.Cancel; 29 | 30 | label.SetBounds(9, 20, 372, 13); 31 | textBox.SetBounds(12, 36, 372, 20); 32 | buttonOk.SetBounds(228, 72, 75, 23); 33 | buttonCancel.SetBounds(309, 72, 75, 23); 34 | 35 | label.AutoSize = true; 36 | textBox.Anchor = textBox.Anchor | AnchorStyles.Right; 37 | buttonOk.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; 38 | buttonCancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; 39 | 40 | form.ClientSize = new Size(396, 107); 41 | form.Controls.AddRange(new Control[] { label, textBox, buttonOk, buttonCancel }); 42 | form.ClientSize = new Size(Math.Max(300, label.Right + 10), form.ClientSize.Height); 43 | form.FormBorderStyle = FormBorderStyle.FixedDialog; 44 | form.StartPosition = FormStartPosition.CenterScreen; 45 | form.MinimizeBox = false; 46 | form.MaximizeBox = false; 47 | form.AcceptButton = buttonOk; 48 | form.CancelButton = buttonCancel; 49 | 50 | DialogResult dialogResult = form.ShowDialog(); 51 | value = textBox.Text; 52 | return dialogResult; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /BflytPreview/EditorForms/LayoutDiffForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace BflytPreview.EditorForms 2 | { 3 | partial class LayoutDiffForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(LayoutDiffForm)); 32 | this.button1 = new System.Windows.Forms.Button(); 33 | this.button2 = new System.Windows.Forms.Button(); 34 | this.label1 = new System.Windows.Forms.Label(); 35 | this.label2 = new System.Windows.Forms.Label(); 36 | this.textBox1 = new System.Windows.Forms.TextBox(); 37 | this.textBox2 = new System.Windows.Forms.TextBox(); 38 | this.label3 = new System.Windows.Forms.Label(); 39 | this.button3 = new System.Windows.Forms.Button(); 40 | this.label4 = new System.Windows.Forms.Label(); 41 | this.cb11Compat = new System.Windows.Forms.CheckBox(); 42 | this.cbIgnoreMissingPanes = new System.Windows.Forms.CheckBox(); 43 | this.SuspendLayout(); 44 | // 45 | // button1 46 | // 47 | this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); 48 | this.button1.Location = new System.Drawing.Point(487, 65); 49 | this.button1.Name = "button1"; 50 | this.button1.Size = new System.Drawing.Size(32, 23); 51 | this.button1.TabIndex = 0; 52 | this.button1.Text = "..."; 53 | this.button1.UseVisualStyleBackColor = true; 54 | this.button1.Click += new System.EventHandler(this.button1_Click); 55 | // 56 | // button2 57 | // 58 | this.button2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); 59 | this.button2.Location = new System.Drawing.Point(487, 112); 60 | this.button2.Name = "button2"; 61 | this.button2.Size = new System.Drawing.Size(32, 23); 62 | this.button2.TabIndex = 1; 63 | this.button2.Text = "..."; 64 | this.button2.UseVisualStyleBackColor = true; 65 | this.button2.Click += new System.EventHandler(this.button2_Click); 66 | // 67 | // label1 68 | // 69 | this.label1.AutoSize = true; 70 | this.label1.Location = new System.Drawing.Point(12, 50); 71 | this.label1.Name = "label1"; 72 | this.label1.Size = new System.Drawing.Size(63, 13); 73 | this.label1.TabIndex = 2; 74 | this.label1.Text = "Original szs:"; 75 | // 76 | // label2 77 | // 78 | this.label2.AutoSize = true; 79 | this.label2.Location = new System.Drawing.Point(12, 99); 80 | this.label2.Name = "label2"; 81 | this.label2.Size = new System.Drawing.Size(58, 13); 82 | this.label2.TabIndex = 3; 83 | this.label2.Text = "Edited szs:"; 84 | // 85 | // textBox1 86 | // 87 | this.textBox1.AllowDrop = true; 88 | this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 89 | | System.Windows.Forms.AnchorStyles.Right))); 90 | this.textBox1.Location = new System.Drawing.Point(15, 67); 91 | this.textBox1.Name = "textBox1"; 92 | this.textBox1.ReadOnly = true; 93 | this.textBox1.Size = new System.Drawing.Size(466, 20); 94 | this.textBox1.TabIndex = 4; 95 | this.textBox1.DragDrop += new System.Windows.Forms.DragEventHandler(this.textBox1_DragDrop); 96 | this.textBox1.DragEnter += new System.Windows.Forms.DragEventHandler(this.tbDragEnter); 97 | // 98 | // textBox2 99 | // 100 | this.textBox2.AllowDrop = true; 101 | this.textBox2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 102 | | System.Windows.Forms.AnchorStyles.Right))); 103 | this.textBox2.Location = new System.Drawing.Point(15, 115); 104 | this.textBox2.Name = "textBox2"; 105 | this.textBox2.ReadOnly = true; 106 | this.textBox2.Size = new System.Drawing.Size(466, 20); 107 | this.textBox2.TabIndex = 5; 108 | this.textBox2.DragDrop += new System.Windows.Forms.DragEventHandler(this.textBox2_DragDrop); 109 | this.textBox2.DragEnter += new System.Windows.Forms.DragEventHandler(this.tbDragEnter); 110 | // 111 | // label3 112 | // 113 | this.label3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 114 | | System.Windows.Forms.AnchorStyles.Right))); 115 | this.label3.Location = new System.Drawing.Point(2, 4); 116 | this.label3.Name = "label3"; 117 | this.label3.Size = new System.Drawing.Size(528, 42); 118 | this.label3.TabIndex = 6; 119 | this.label3.Text = "Use this tool to generate a custom theme JSON file.\r\nThis will compare layout fil" + 120 | "es from two szs archives (generated layouts are compatible with Switch Themes In" + 121 | "jector)."; 122 | // 123 | // button3 124 | // 125 | this.button3.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 126 | this.button3.Location = new System.Drawing.Point(417, 348); 127 | this.button3.Name = "button3"; 128 | this.button3.Size = new System.Drawing.Size(102, 23); 129 | this.button3.TabIndex = 7; 130 | this.button3.Text = "Generate diff"; 131 | this.button3.UseVisualStyleBackColor = true; 132 | this.button3.Click += new System.EventHandler(this.button3_Click); 133 | // 134 | // label4 135 | // 136 | this.label4.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 137 | | System.Windows.Forms.AnchorStyles.Right))); 138 | this.label4.AutoEllipsis = true; 139 | this.label4.Location = new System.Drawing.Point(5, 150); 140 | this.label4.Name = "label4"; 141 | this.label4.Size = new System.Drawing.Size(514, 69); 142 | this.label4.TabIndex = 8; 143 | this.label4.Text = resources.GetString("label4.Text"); 144 | // 145 | // cb11Compat 146 | // 147 | this.cb11Compat.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 148 | | System.Windows.Forms.AnchorStyles.Right))); 149 | this.cb11Compat.Location = new System.Drawing.Point(12, 267); 150 | this.cb11Compat.Name = "cb11Compat"; 151 | this.cb11Compat.Size = new System.Drawing.Size(499, 70); 152 | this.cb11Compat.TabIndex = 9; 153 | this.cb11Compat.Text = "Emulate 10.X layout on 11.0+\r\nThis options removes the \"Switch online\" button and" + 154 | " positions from the home menu, enabling this will make old layouts work on 11.0 " + 155 | "and later firmware.\r\n"; 156 | this.cb11Compat.UseVisualStyleBackColor = true; 157 | this.cb11Compat.Visible = false; 158 | // 159 | // cbIgnoreMissingPanes 160 | // 161 | this.cbIgnoreMissingPanes.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 162 | | System.Windows.Forms.AnchorStyles.Right))); 163 | this.cbIgnoreMissingPanes.Location = new System.Drawing.Point(9, 218); 164 | this.cbIgnoreMissingPanes.Name = "cbIgnoreMissingPanes"; 165 | this.cbIgnoreMissingPanes.Size = new System.Drawing.Size(499, 49); 166 | this.cbIgnoreMissingPanes.TabIndex = 10; 167 | this.cbIgnoreMissingPanes.Text = "Ignore missing panes between the two files.\r\nThis is a development option and you" + 168 | " should not use it, may produce broken layouts."; 169 | this.cbIgnoreMissingPanes.UseVisualStyleBackColor = true; 170 | // 171 | // LayoutDiffForm 172 | // 173 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 174 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 175 | this.ClientSize = new System.Drawing.Size(531, 376); 176 | this.Controls.Add(this.cbIgnoreMissingPanes); 177 | this.Controls.Add(this.label4); 178 | this.Controls.Add(this.button3); 179 | this.Controls.Add(this.label3); 180 | this.Controls.Add(this.textBox2); 181 | this.Controls.Add(this.textBox1); 182 | this.Controls.Add(this.label2); 183 | this.Controls.Add(this.label1); 184 | this.Controls.Add(this.button2); 185 | this.Controls.Add(this.button1); 186 | this.Controls.Add(this.cb11Compat); 187 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); 188 | this.MaximizeBox = false; 189 | this.MinimizeBox = false; 190 | this.Name = "LayoutDiffForm"; 191 | this.Text = "Layout Diff"; 192 | this.Load += new System.EventHandler(this.LayoutDiffForm_Load); 193 | this.ResumeLayout(false); 194 | this.PerformLayout(); 195 | 196 | } 197 | 198 | #endregion 199 | 200 | private System.Windows.Forms.Button button1; 201 | private System.Windows.Forms.Button button2; 202 | private System.Windows.Forms.Label label1; 203 | private System.Windows.Forms.Label label2; 204 | private System.Windows.Forms.TextBox textBox1; 205 | private System.Windows.Forms.TextBox textBox2; 206 | private System.Windows.Forms.Label label3; 207 | private System.Windows.Forms.Button button3; 208 | private System.Windows.Forms.Label label4; 209 | private System.Windows.Forms.CheckBox cb11Compat; 210 | private System.Windows.Forms.CheckBox cbIgnoreMissingPanes; 211 | } 212 | } -------------------------------------------------------------------------------- /BflytPreview/EditorForms/LayoutDiffForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using System.Windows.Forms; 11 | using SARCExt; 12 | using SwitchThemes.Common; 13 | 14 | namespace BflytPreview.EditorForms 15 | { 16 | public partial class LayoutDiffForm : Form 17 | { 18 | public LayoutDiffForm(SarcData _Original = null, SarcData _Edited = null) 19 | { 20 | InitializeComponent(); 21 | if (_Original != null) 22 | { 23 | textBox1.Text = ""; 24 | button1.Enabled = false; 25 | textBox1.Enabled = false; 26 | textBox1.AllowDrop = false; 27 | Original = _Original; 28 | } 29 | if (_Edited != null) 30 | { 31 | textBox2.Text = ""; 32 | button2.Enabled = false; 33 | textBox2.Enabled = false; 34 | textBox2.AllowDrop = false; 35 | Edited = _Edited; 36 | } 37 | 38 | EnableResidentMenuCheckbox(_Original ?? _Edited); 39 | } 40 | 41 | void EnableResidentMenuCheckbox(SarcData sarc) 42 | { 43 | if (cb11Compat.Tag != null) return; 44 | if (sarc == null) return; 45 | cb11Compat.Visible = (DefaultTemplates.GetFor(sarc)?.NXThemeName ?? "home") == "home"; 46 | cb11Compat.Tag = "checked"; 47 | } 48 | 49 | SarcData Original = null; 50 | SarcData Edited = null; 51 | 52 | private void button1_Click(object sender, EventArgs e) => 53 | Original = SelectFile(ref textBox1) ?? Original; 54 | 55 | private void button2_Click(object sender, EventArgs e) => 56 | Edited = SelectFile(ref textBox2) ?? Edited; 57 | 58 | private void textBox1_DragDrop(object sender, DragEventArgs e) => 59 | Original = SelectFile(ref textBox1, e) ?? Original; 60 | 61 | private void textBox2_DragDrop(object sender, DragEventArgs e) => 62 | Edited = SelectFile(ref textBox2, e) ?? Edited; 63 | 64 | private void tbDragEnter(object sender, DragEventArgs e) 65 | { 66 | if (e.Data.GetDataPresent(DataFormats.FileDrop)) 67 | e.Effect = DragDropEffects.Copy; 68 | } 69 | 70 | SarcData SelectFile(ref TextBox target, string name = null) 71 | { 72 | if (name is null) 73 | { 74 | OpenFileDialog opn = new OpenFileDialog() { Filter = "szs files|*.szs" }; 75 | if (opn.ShowDialog() != DialogResult.OK) return null; 76 | name = opn.FileName; 77 | } 78 | target.Text = name; 79 | var sarc = SARC.Unpack(ManagedYaz0.Decompress(File.ReadAllBytes(target.Text))); 80 | EnableResidentMenuCheckbox(sarc); 81 | return sarc; 82 | } 83 | 84 | SarcData SelectFile(ref TextBox target, DragEventArgs e) 85 | { 86 | var f = (string[])e.Data.GetData(DataFormats.FileDrop); 87 | if (f.Any()) 88 | return SelectFile(ref target, f.First()); 89 | return null; 90 | } 91 | 92 | private void LayoutDiffForm_Load(object sender, EventArgs e) 93 | { 94 | 95 | } 96 | 97 | private void button3_Click(object sender, EventArgs e) 98 | { 99 | try 100 | { 101 | bool HideOnlineButton = false; 102 | if (cb11Compat.Visible) 103 | HideOnlineButton = cb11Compat.Checked; 104 | 105 | var diff = new LayoutDiff(Original, Edited, new LayoutDiff.DiffOptions { 106 | HideOnlineButton = HideOnlineButton, 107 | IgnoreMissingPanes = cbIgnoreMissingPanes.Checked, 108 | // Also ignore these since we can't shouldn't import animations if panes are missing 109 | IgnoreAnimations = cbIgnoreMissingPanes.Checked, 110 | IgnoreGroups = cbIgnoreMissingPanes.Checked, 111 | IgnoreMaterials = cbIgnoreMissingPanes.Checked, 112 | }); 113 | 114 | var res = diff.ComputeDiff(); 115 | var log = diff.OutputLog; 116 | 117 | if (!string.IsNullOrWhiteSpace(log)) 118 | MessageBox.Show(log); 119 | 120 | if (res != null) 121 | { 122 | SaveFileDialog sav = new SaveFileDialog() { Filter = "json file|*.json" }; 123 | if (sav.ShowDialog() != DialogResult.OK) return; 124 | File.WriteAllText(sav.FileName, res.AsJson()); 125 | } 126 | } 127 | catch (Exception ex) 128 | { 129 | MessageBox.Show(ex.Message); 130 | } 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /BflytPreview/EditorForms/SzsEditor.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace BflytPreview.EditorForms 2 | { 3 | partial class SzsEditor 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.components = new System.ComponentModel.Container(); 32 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SzsEditor)); 33 | this.listBox1 = new System.Windows.Forms.ListBox(); 34 | this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); 35 | this.copyNameToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 36 | this.renameToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 37 | this.extractToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 38 | this.replaceToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); 39 | this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); 40 | this.deleteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 41 | this.numericUpDown1 = new System.Windows.Forms.NumericUpDown(); 42 | this.label1 = new System.Windows.Forms.Label(); 43 | this.saveSzsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 44 | this.saveAsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 45 | this.saveToSzsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 46 | this.addFilesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 47 | this.extractAllFilesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 48 | this.menuStrip1 = new System.Windows.Forms.MenuStrip(); 49 | this.toolsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 50 | this.layoutDiffToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 51 | this.thisFileIsTheOriginalSzsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 52 | this.thisFileIsTheEditedSzsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 53 | this.loadJSONPatchToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 54 | this.extractNamesInClipboardToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 55 | this.tb_search = new System.Windows.Forms.TextBox(); 56 | this.exportFileListToClipboardToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 57 | this.contextMenuStrip1.SuspendLayout(); 58 | ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).BeginInit(); 59 | this.menuStrip1.SuspendLayout(); 60 | this.SuspendLayout(); 61 | // 62 | // listBox1 63 | // 64 | this.listBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 65 | | System.Windows.Forms.AnchorStyles.Left) 66 | | System.Windows.Forms.AnchorStyles.Right))); 67 | this.listBox1.ContextMenuStrip = this.contextMenuStrip1; 68 | this.listBox1.FormattingEnabled = true; 69 | this.listBox1.Location = new System.Drawing.Point(0, 27); 70 | this.listBox1.Name = "listBox1"; 71 | this.listBox1.SelectionMode = System.Windows.Forms.SelectionMode.MultiExtended; 72 | this.listBox1.Size = new System.Drawing.Size(303, 212); 73 | this.listBox1.Sorted = true; 74 | this.listBox1.TabIndex = 4; 75 | this.listBox1.DoubleClick += new System.EventHandler(this.listBox1_DoubleClick); 76 | this.listBox1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.listBox1_KeyDown); 77 | // 78 | // contextMenuStrip1 79 | // 80 | this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 81 | this.copyNameToolStripMenuItem, 82 | this.renameToolStripMenuItem, 83 | this.extractToolStripMenuItem, 84 | this.replaceToolStripMenuItem1, 85 | this.toolStripSeparator1, 86 | this.deleteToolStripMenuItem}); 87 | this.contextMenuStrip1.Name = "contextMenuStrip1"; 88 | this.contextMenuStrip1.Size = new System.Drawing.Size(136, 120); 89 | // 90 | // copyNameToolStripMenuItem 91 | // 92 | this.copyNameToolStripMenuItem.Name = "copyNameToolStripMenuItem"; 93 | this.copyNameToolStripMenuItem.Size = new System.Drawing.Size(135, 22); 94 | this.copyNameToolStripMenuItem.Text = "Copy name"; 95 | this.copyNameToolStripMenuItem.Click += new System.EventHandler(this.copyNameToolStripMenuItem_Click); 96 | // 97 | // renameToolStripMenuItem 98 | // 99 | this.renameToolStripMenuItem.Name = "renameToolStripMenuItem"; 100 | this.renameToolStripMenuItem.Size = new System.Drawing.Size(135, 22); 101 | this.renameToolStripMenuItem.Text = "Rename"; 102 | this.renameToolStripMenuItem.Click += new System.EventHandler(this.renameToolStripMenuItem_Click); 103 | // 104 | // extractToolStripMenuItem 105 | // 106 | this.extractToolStripMenuItem.Name = "extractToolStripMenuItem"; 107 | this.extractToolStripMenuItem.Size = new System.Drawing.Size(135, 22); 108 | this.extractToolStripMenuItem.Text = "Extract"; 109 | this.extractToolStripMenuItem.Click += new System.EventHandler(this.extractToolStripMenuItem_Click); 110 | // 111 | // replaceToolStripMenuItem1 112 | // 113 | this.replaceToolStripMenuItem1.Name = "replaceToolStripMenuItem1"; 114 | this.replaceToolStripMenuItem1.Size = new System.Drawing.Size(135, 22); 115 | this.replaceToolStripMenuItem1.Text = "Replace"; 116 | this.replaceToolStripMenuItem1.Click += new System.EventHandler(this.replaceToolStripMenuItem1_Click); 117 | // 118 | // toolStripSeparator1 119 | // 120 | this.toolStripSeparator1.Name = "toolStripSeparator1"; 121 | this.toolStripSeparator1.Size = new System.Drawing.Size(132, 6); 122 | // 123 | // deleteToolStripMenuItem 124 | // 125 | this.deleteToolStripMenuItem.Name = "deleteToolStripMenuItem"; 126 | this.deleteToolStripMenuItem.Size = new System.Drawing.Size(135, 22); 127 | this.deleteToolStripMenuItem.Text = "Delete"; 128 | this.deleteToolStripMenuItem.Click += new System.EventHandler(this.deleteToolStripMenuItem_Click); 129 | // 130 | // numericUpDown1 131 | // 132 | this.numericUpDown1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); 133 | this.numericUpDown1.Location = new System.Drawing.Point(130, 253); 134 | this.numericUpDown1.Maximum = new decimal(new int[] { 135 | 9, 136 | 0, 137 | 0, 138 | 0}); 139 | this.numericUpDown1.Name = "numericUpDown1"; 140 | this.numericUpDown1.Size = new System.Drawing.Size(55, 20); 141 | this.numericUpDown1.TabIndex = 7; 142 | this.numericUpDown1.Value = new decimal(new int[] { 143 | 3, 144 | 0, 145 | 0, 146 | 0}); 147 | // 148 | // label1 149 | // 150 | this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); 151 | this.label1.AutoSize = true; 152 | this.label1.Location = new System.Drawing.Point(8, 256); 153 | this.label1.Name = "label1"; 154 | this.label1.Size = new System.Drawing.Size(122, 13); 155 | this.label1.TabIndex = 6; 156 | this.label1.Text = "Compression level [0-9] :"; 157 | // 158 | // saveSzsToolStripMenuItem 159 | // 160 | this.saveSzsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { 161 | this.saveAsToolStripMenuItem, 162 | this.saveToSzsToolStripMenuItem}); 163 | this.saveSzsToolStripMenuItem.Name = "saveSzsToolStripMenuItem"; 164 | this.saveSzsToolStripMenuItem.Size = new System.Drawing.Size(43, 20); 165 | this.saveSzsToolStripMenuItem.Text = "Save"; 166 | // 167 | // saveAsToolStripMenuItem 168 | // 169 | this.saveAsToolStripMenuItem.Name = "saveAsToolStripMenuItem"; 170 | this.saveAsToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Shift) 171 | | System.Windows.Forms.Keys.S))); 172 | this.saveAsToolStripMenuItem.Size = new System.Drawing.Size(190, 22); 173 | this.saveAsToolStripMenuItem.Text = "Save as.."; 174 | this.saveAsToolStripMenuItem.Click += new System.EventHandler(this.saveAsToolStripMenuItem_Click); 175 | // 176 | // saveToSzsToolStripMenuItem 177 | // 178 | this.saveToSzsToolStripMenuItem.Name = "saveToSzsToolStripMenuItem"; 179 | this.saveToSzsToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.S))); 180 | this.saveToSzsToolStripMenuItem.Size = new System.Drawing.Size(190, 22); 181 | this.saveToSzsToolStripMenuItem.Text = "Save"; 182 | this.saveToSzsToolStripMenuItem.Visible = false; 183 | this.saveToSzsToolStripMenuItem.Click += new System.EventHandler(this.saveToSzsToolStripMenuItem_Click); 184 | // 185 | // addFilesToolStripMenuItem 186 | // 187 | this.addFilesToolStripMenuItem.Name = "addFilesToolStripMenuItem"; 188 | this.addFilesToolStripMenuItem.Size = new System.Drawing.Size(65, 20); 189 | this.addFilesToolStripMenuItem.Text = "Add files"; 190 | this.addFilesToolStripMenuItem.Click += new System.EventHandler(this.addFilesToolStripMenuItem_Click); 191 | // 192 | // extractAllFilesToolStripMenuItem 193 | // 194 | this.extractAllFilesToolStripMenuItem.Name = "extractAllFilesToolStripMenuItem"; 195 | this.extractAllFilesToolStripMenuItem.Size = new System.Drawing.Size(94, 20); 196 | this.extractAllFilesToolStripMenuItem.Text = "Extract all files"; 197 | this.extractAllFilesToolStripMenuItem.Click += new System.EventHandler(this.extractAllFilesToolStripMenuItem_Click); 198 | // 199 | // menuStrip1 200 | // 201 | this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 202 | this.saveSzsToolStripMenuItem, 203 | this.addFilesToolStripMenuItem, 204 | this.extractAllFilesToolStripMenuItem, 205 | this.toolsToolStripMenuItem}); 206 | this.menuStrip1.Location = new System.Drawing.Point(0, 0); 207 | this.menuStrip1.Name = "menuStrip1"; 208 | this.menuStrip1.Size = new System.Drawing.Size(303, 24); 209 | this.menuStrip1.TabIndex = 5; 210 | this.menuStrip1.Text = "menuStrip1"; 211 | // 212 | // toolsToolStripMenuItem 213 | // 214 | this.toolsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { 215 | this.layoutDiffToolStripMenuItem, 216 | this.loadJSONPatchToolStripMenuItem, 217 | this.extractNamesInClipboardToolStripMenuItem, 218 | this.exportFileListToClipboardToolStripMenuItem}); 219 | this.toolsToolStripMenuItem.Name = "toolsToolStripMenuItem"; 220 | this.toolsToolStripMenuItem.Size = new System.Drawing.Size(46, 20); 221 | this.toolsToolStripMenuItem.Text = "Tools"; 222 | // 223 | // layoutDiffToolStripMenuItem 224 | // 225 | this.layoutDiffToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { 226 | this.thisFileIsTheOriginalSzsToolStripMenuItem, 227 | this.thisFileIsTheEditedSzsToolStripMenuItem}); 228 | this.layoutDiffToolStripMenuItem.Name = "layoutDiffToolStripMenuItem"; 229 | this.layoutDiffToolStripMenuItem.Size = new System.Drawing.Size(269, 22); 230 | this.layoutDiffToolStripMenuItem.Text = "Layout diff"; 231 | // 232 | // thisFileIsTheOriginalSzsToolStripMenuItem 233 | // 234 | this.thisFileIsTheOriginalSzsToolStripMenuItem.Name = "thisFileIsTheOriginalSzsToolStripMenuItem"; 235 | this.thisFileIsTheOriginalSzsToolStripMenuItem.Size = new System.Drawing.Size(206, 22); 236 | this.thisFileIsTheOriginalSzsToolStripMenuItem.Text = "This file is the original szs"; 237 | this.thisFileIsTheOriginalSzsToolStripMenuItem.Click += new System.EventHandler(this.thisFileIsTheOriginalSzsToolStripMenuItem_Click); 238 | // 239 | // thisFileIsTheEditedSzsToolStripMenuItem 240 | // 241 | this.thisFileIsTheEditedSzsToolStripMenuItem.Name = "thisFileIsTheEditedSzsToolStripMenuItem"; 242 | this.thisFileIsTheEditedSzsToolStripMenuItem.Size = new System.Drawing.Size(206, 22); 243 | this.thisFileIsTheEditedSzsToolStripMenuItem.Text = "This file is the edited szs"; 244 | this.thisFileIsTheEditedSzsToolStripMenuItem.Click += new System.EventHandler(this.thisFileIsTheEditedSzsToolStripMenuItem_Click); 245 | // 246 | // loadJSONPatchToolStripMenuItem 247 | // 248 | this.loadJSONPatchToolStripMenuItem.Name = "loadJSONPatchToolStripMenuItem"; 249 | this.loadJSONPatchToolStripMenuItem.Size = new System.Drawing.Size(269, 22); 250 | this.loadJSONPatchToolStripMenuItem.Text = "Load JSON patch"; 251 | this.loadJSONPatchToolStripMenuItem.Click += new System.EventHandler(this.loadJSONPatchToolStripMenuItem_Click); 252 | // 253 | // extractNamesInClipboardToolStripMenuItem 254 | // 255 | this.extractNamesInClipboardToolStripMenuItem.Name = "extractNamesInClipboardToolStripMenuItem"; 256 | this.extractNamesInClipboardToolStripMenuItem.Size = new System.Drawing.Size(269, 22); 257 | this.extractNamesInClipboardToolStripMenuItem.Text = "Extract file names from the clipboard"; 258 | this.extractNamesInClipboardToolStripMenuItem.Click += new System.EventHandler(this.extractNamesInClipboardToolStripMenuItem_Click); 259 | // 260 | // tb_search 261 | // 262 | this.tb_search.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 263 | | System.Windows.Forms.AnchorStyles.Right))); 264 | this.tb_search.Location = new System.Drawing.Point(195, 253); 265 | this.tb_search.Name = "tb_search"; 266 | this.tb_search.Size = new System.Drawing.Size(100, 20); 267 | this.tb_search.TabIndex = 8; 268 | this.tb_search.Text = "Search"; 269 | this.tb_search.TextChanged += new System.EventHandler(this.tb_search_TextChanged); 270 | // 271 | // exportFileListToClipboardToolStripMenuItem 272 | // 273 | this.exportFileListToClipboardToolStripMenuItem.Name = "exportFileListToClipboardToolStripMenuItem"; 274 | this.exportFileListToClipboardToolStripMenuItem.Size = new System.Drawing.Size(269, 22); 275 | this.exportFileListToClipboardToolStripMenuItem.Text = "Write file list to clipboard"; 276 | this.exportFileListToClipboardToolStripMenuItem.Click += new System.EventHandler(this.exportFileListToClipboardToolStripMenuItem_Click); 277 | // 278 | // SzsEditor 279 | // 280 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 281 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 282 | this.ClientSize = new System.Drawing.Size(303, 279); 283 | this.Controls.Add(this.tb_search); 284 | this.Controls.Add(this.listBox1); 285 | this.Controls.Add(this.menuStrip1); 286 | this.Controls.Add(this.numericUpDown1); 287 | this.Controls.Add(this.label1); 288 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); 289 | this.KeyPreview = true; 290 | this.Name = "SzsEditor"; 291 | this.Text = "Szs editor"; 292 | this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.SzsEditor_FormClosing); 293 | this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.SzsEditor_FormClosed); 294 | this.Load += new System.EventHandler(this.SzsEditor_Load); 295 | this.LocationChanged += new System.EventHandler(this.SzsEditor_LocationChanged); 296 | this.Click += new System.EventHandler(this.SzsEditor_Click); 297 | this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.SzsEditor_KeyDown); 298 | this.contextMenuStrip1.ResumeLayout(false); 299 | ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).EndInit(); 300 | this.menuStrip1.ResumeLayout(false); 301 | this.menuStrip1.PerformLayout(); 302 | this.ResumeLayout(false); 303 | this.PerformLayout(); 304 | 305 | } 306 | 307 | #endregion 308 | 309 | private System.Windows.Forms.ListBox listBox1; 310 | private System.Windows.Forms.ContextMenuStrip contextMenuStrip1; 311 | private System.Windows.Forms.ToolStripMenuItem copyNameToolStripMenuItem; 312 | private System.Windows.Forms.ToolStripMenuItem renameToolStripMenuItem; 313 | private System.Windows.Forms.ToolStripMenuItem extractToolStripMenuItem; 314 | private System.Windows.Forms.ToolStripMenuItem replaceToolStripMenuItem1; 315 | private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; 316 | private System.Windows.Forms.ToolStripMenuItem deleteToolStripMenuItem; 317 | private System.Windows.Forms.NumericUpDown numericUpDown1; 318 | private System.Windows.Forms.Label label1; 319 | private System.Windows.Forms.ToolStripMenuItem saveSzsToolStripMenuItem; 320 | private System.Windows.Forms.ToolStripMenuItem saveAsToolStripMenuItem; 321 | private System.Windows.Forms.ToolStripMenuItem saveToSzsToolStripMenuItem; 322 | private System.Windows.Forms.ToolStripMenuItem addFilesToolStripMenuItem; 323 | private System.Windows.Forms.ToolStripMenuItem extractAllFilesToolStripMenuItem; 324 | private System.Windows.Forms.MenuStrip menuStrip1; 325 | private System.Windows.Forms.ToolStripMenuItem toolsToolStripMenuItem; 326 | private System.Windows.Forms.ToolStripMenuItem layoutDiffToolStripMenuItem; 327 | private System.Windows.Forms.ToolStripMenuItem thisFileIsTheOriginalSzsToolStripMenuItem; 328 | private System.Windows.Forms.ToolStripMenuItem thisFileIsTheEditedSzsToolStripMenuItem; 329 | private System.Windows.Forms.ToolStripMenuItem loadJSONPatchToolStripMenuItem; 330 | private System.Windows.Forms.TextBox tb_search; 331 | private System.Windows.Forms.ToolStripMenuItem extractNamesInClipboardToolStripMenuItem; 332 | private System.Windows.Forms.ToolStripMenuItem exportFileListToClipboardToolStripMenuItem; 333 | } 334 | } -------------------------------------------------------------------------------- /BflytPreview/EditorForms/SzsEditor.cs: -------------------------------------------------------------------------------- 1 | using SARCExt; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.Data; 6 | using System.Drawing; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | using System.Windows.Forms; 12 | using SwitchThemes.Common; 13 | using SwitchThemes.Common.Serializers; 14 | using SwitchThemes.Common.Bntxx; 15 | using Syroot.BinaryData; 16 | using SwitchThemes.Common.Bflyt; 17 | 18 | namespace BflytPreview.EditorForms 19 | { 20 | public partial class SzsEditor : Form 21 | { 22 | public class SzsFileProvider : IFileWriter 23 | { 24 | private SzsEditor Parent; 25 | internal Form EditorForm; 26 | public string Path { get; internal set; } 27 | 28 | public SzsFileProvider(SzsEditor parent, string path) => 29 | (Parent, Path) = (parent, path); 30 | 31 | public void EditorClosed() => 32 | Parent.CloseFileProvider(this); 33 | 34 | public void Save(byte[] Data) => 35 | Parent.SaveFromProvider(this, Data); 36 | 37 | public override string ToString() => $"Szs file : {Path}"; 38 | } 39 | 40 | internal List FileProviders = new List(); 41 | 42 | internal void CloseFileProvider(SzsFileProvider file) => 43 | FileProviders.Remove(file); 44 | 45 | internal void SaveFromProvider(SzsFileProvider file, byte[] Data) 46 | { 47 | if (!FileProviders.Contains(file)) throw new Exception("file is not a registered IFileWriter"); 48 | loadedSarc.Files[file.Path] = Data; 49 | } 50 | 51 | IFileWriter _saveTo; 52 | public IFileWriter SaveTo 53 | { 54 | get => _saveTo; 55 | set 56 | { 57 | _saveTo?.EditorClosed(); 58 | _saveTo = value; 59 | saveToSzsToolStripMenuItem.Visible = _saveTo != null; 60 | this.Text = value?.ToString() ?? ""; 61 | } 62 | } 63 | 64 | SarcData loadedSarc; 65 | MainForm MainForm; 66 | 67 | public SzsEditor(SARCExt.SarcData _sarc, IFileWriter saveTo, MainForm _parentForm) 68 | { 69 | InitializeComponent(); 70 | loadedSarc = _sarc; 71 | MainForm = _parentForm; 72 | SaveTo = saveTo; 73 | } 74 | 75 | private void SzsEditor_Load(object sender, EventArgs e) 76 | { 77 | #if !DEBUG 78 | extractNamesInClipboardToolStripMenuItem.Visible = false; 79 | exportFileListToClipboardToolStripMenuItem.Visible = false; 80 | #endif 81 | 82 | if (loadedSarc == null) 83 | { 84 | MessageBox.Show("No sarc has been loaded"); 85 | this.Close(); 86 | } 87 | else 88 | { 89 | listBox1.Items.AddRange(loadedSarc.Files.Keys.ToArray()); 90 | FormBringToFront(); 91 | } 92 | } 93 | 94 | private void SzsEditor_FormClosing(object sender, FormClosingEventArgs e) 95 | { 96 | if (FileProviders.Count != 0) 97 | { 98 | if (MessageBox.Show("There are some files of this SZS opened, this will close all of them and all the unsaved edits will be lost, do you want to continue ?", this.Text, MessageBoxButtons.YesNo) == DialogResult.No) 99 | e.Cancel = true; 100 | else 101 | { 102 | foreach (var k in FileProviders.ToArray()) 103 | k.EditorForm?.Close(); 104 | if (FileProviders.Count != 0) 105 | { 106 | MessageBox.Show($"Failed to close {FileProviders.Count} editors"); 107 | e.Cancel = true; 108 | } 109 | } 110 | } 111 | } 112 | 113 | private void extractAllFilesToolStripMenuItem_Click(object sender, EventArgs e) 114 | { 115 | ExtractMultipleFiles(loadedSarc.Files.Keys.ToArray()); 116 | } 117 | 118 | void ExtractMultipleFiles(IEnumerable files) 119 | { 120 | var dlg = new FolderBrowserDialog(); 121 | if (dlg.ShowDialog() != DialogResult.OK) 122 | return; 123 | foreach (string f in files) 124 | { 125 | string fOut = Path.Combine(dlg.SelectedPath, f); 126 | DirectoryInfo dir = new DirectoryInfo(Path.GetDirectoryName(fOut)); 127 | if (!dir.Exists) 128 | dir.Create(); 129 | File.WriteAllBytes(fOut, loadedSarc.Files[f]); 130 | } 131 | } 132 | 133 | private void extractToolStripMenuItem_Click(object sender, EventArgs e) 134 | { 135 | if (listBox1.SelectedItems.Count > 1) 136 | ExtractMultipleFiles(listBox1.SelectedItems.Cast()); 137 | else 138 | { 139 | var sav = new SaveFileDialog() { FileName = listBox1.SelectedItem.ToString() }; 140 | if (sav.ShowDialog() != DialogResult.OK) 141 | return; 142 | File.WriteAllBytes(sav.FileName, loadedSarc.Files[listBox1.SelectedItem.ToString()]); 143 | } 144 | } 145 | 146 | private void deleteToolStripMenuItem_Click(object sender, EventArgs e) 147 | { 148 | if (loadedSarc.HashOnly) 149 | { 150 | MessageBox.Show("Can't remove files from a hash only sarc"); 151 | return; 152 | } 153 | string[] Targets = listBox1.SelectedItems.Cast().ToArray(); 154 | foreach (var item in Targets) 155 | { 156 | loadedSarc.Files.Remove(item); 157 | listBox1.Items.Remove(item); 158 | } 159 | } 160 | 161 | private void addFilesToolStripMenuItem_Click(object sender, EventArgs e) 162 | { 163 | if (loadedSarc.HashOnly) 164 | { 165 | MessageBox.Show("Can't add files to a hash only sarc"); 166 | return; 167 | } 168 | var opn = new OpenFileDialog() { Multiselect = true }; 169 | if (opn.ShowDialog() != DialogResult.OK) 170 | return; 171 | foreach (var f in opn.FileNames) 172 | { 173 | string name = Path.GetFileName(f); 174 | if (InputDialog.Show("File name", "Write the name for this file, use / to place it in a folder", ref name) != DialogResult.OK) 175 | return; 176 | 177 | if (loadedSarc.Files.ContainsKey(name)) 178 | { 179 | MessageBox.Show($"File {name} already in szs"); 180 | continue; 181 | } 182 | loadedSarc.Files.Add(name, File.ReadAllBytes(f)); 183 | listBox1.Items.Add(name); 184 | } 185 | } 186 | 187 | byte[] PackArchive() 188 | { 189 | if (numericUpDown1.Value == 0) 190 | return SARC.Pack(loadedSarc).Item2; 191 | else 192 | { 193 | var s = SARC.Pack(loadedSarc); 194 | return ManagedYaz0.Compress(s.Item2, (int)numericUpDown1.Value, s.Item1); 195 | } 196 | } 197 | 198 | void SaveSzsAs() 199 | { 200 | var sav = new SaveFileDialog() { Filter = "szs file|*.szs|sarc file|*.sarc" }; 201 | if (sav.ShowDialog() != DialogResult.OK) 202 | return; 203 | SaveTo = new DiskFileProvider(sav.FileName); 204 | SaveTo.Save(PackArchive()); 205 | } 206 | 207 | private void saveAsToolStripMenuItem_Click(object sender, EventArgs e) => 208 | SaveSzsAs(); 209 | 210 | private void listBox1_DoubleClick(object sender, EventArgs e) 211 | { 212 | if (listBox1.SelectedItem == null) 213 | return; 214 | var Fname = listBox1.SelectedItem.ToString(); 215 | 216 | var alreadyOpened = FileProviders.Where(x => x.Path == Fname); 217 | if (alreadyOpened.FirstOrDefault() != null) 218 | { 219 | alreadyOpened.FirstOrDefault().EditorForm.Focus(); 220 | return; 221 | } 222 | 223 | var provider = new SzsFileProvider(this, Fname); 224 | var form = MainForm.OpenFile(loadedSarc.Files[Fname], provider); 225 | if (form != null) 226 | { 227 | provider.EditorForm = form; 228 | FileProviders.Add(provider); 229 | } 230 | } 231 | 232 | private void replaceToolStripMenuItem1_Click(object sender, EventArgs e) 233 | { 234 | if (listBox1.SelectedItem == null) return; 235 | var opn = new OpenFileDialog(); 236 | if (opn.ShowDialog() != DialogResult.OK) return; 237 | loadedSarc.Files[listBox1.SelectedItem.ToString()] = File.ReadAllBytes(opn.FileName); 238 | } 239 | 240 | private void copyNameToolStripMenuItem_Click(object sender, EventArgs e) 241 | { 242 | if (listBox1.SelectedItem == null) return; 243 | Clipboard.SetText(listBox1.SelectedItem.ToString()); 244 | } 245 | 246 | private void renameToolStripMenuItem_Click(object sender, EventArgs e) 247 | { 248 | if (listBox1.SelectedItem == null) return; 249 | string originalName = listBox1.SelectedItem.ToString(); 250 | string name = Path.GetFileName(originalName); 251 | if (InputDialog.Show("File name", "Write the name for this file, use / to place it in a folder", ref name) != DialogResult.OK) 252 | return; 253 | 254 | if (loadedSarc.Files.ContainsKey(name)) 255 | { 256 | MessageBox.Show($"File {name} already in szs"); 257 | return; 258 | } 259 | loadedSarc.Files.Add(name, loadedSarc.Files[originalName]); 260 | loadedSarc.Files.Remove(originalName); 261 | listBox1.Items.Add(name); 262 | listBox1.Items.Remove(originalName); 263 | } 264 | 265 | private void saveToSzsToolStripMenuItem_Click(object sender, EventArgs e) 266 | { 267 | if (SaveTo == null) 268 | SaveSzsAs(); 269 | else SaveTo.Save(PackArchive()); 270 | } 271 | 272 | void FormBringToFront() 273 | { 274 | this.Activate(); 275 | this.BringToFront(); 276 | this.Focus(); 277 | } 278 | 279 | private void SzsEditor_Click(object sender, EventArgs e) => FormBringToFront(); 280 | private void SzsEditor_LocationChanged(object sender, EventArgs e) => FormBringToFront(); 281 | 282 | private void SzsEditor_FormClosed(object sender, FormClosedEventArgs e) => 283 | SaveTo?.EditorClosed(); 284 | 285 | private void thisFileIsTheOriginalSzsToolStripMenuItem_Click(object sender, EventArgs e) 286 | => new LayoutDiffForm(loadedSarc, null).ShowDialog(); 287 | 288 | private void thisFileIsTheEditedSzsToolStripMenuItem_Click(object sender, EventArgs e) 289 | => new LayoutDiffForm(null, loadedSarc).ShowDialog(); 290 | 291 | private void SzsEditor_KeyDown(object sender, KeyEventArgs e) 292 | { 293 | e.SuppressKeyPress = true; 294 | if (e.Shift && e.Control && e.KeyCode == Keys.S) 295 | saveAsToolStripMenuItem.PerformClick(); 296 | else if (e.Control && e.KeyCode == Keys.S) 297 | saveToSzsToolStripMenuItem.PerformClick(); 298 | else e.SuppressKeyPress = false; 299 | } 300 | 301 | private void loadJSONPatchToolStripMenuItem_Click(object sender, EventArgs e) 302 | { 303 | var opn = new OpenFileDialog(); 304 | if (opn.ShowDialog() != DialogResult.OK) return; 305 | 306 | SzsPatcher P = new SzsPatcher(loadedSarc); 307 | LayoutPatch JSONLayout = LayoutPatch.Load(File.ReadAllText(opn.FileName)); 308 | 309 | if (JSONLayout.IsCompatible(loadedSarc)) 310 | { 311 | if (P.PatchLayouts(JSONLayout)) 312 | { 313 | loadedSarc = P.GetFinalSarc(); 314 | MessageBox.Show("Loaded JSON patch"); 315 | } 316 | else MessageBox.Show("Failed to load the JSON patch."); 317 | } 318 | 319 | } 320 | 321 | private void listBox1_KeyDown(object sender, KeyEventArgs e) 322 | { 323 | if (listBox1.SelectedItem == null) return; 324 | if (e.KeyCode == Keys.Q) 325 | HexEditorForm.Show(loadedSarc.Files[listBox1.SelectedItem as string]); 326 | else if (e.KeyCode == Keys.Return) 327 | listBox1_DoubleClick(sender, null); 328 | } 329 | 330 | private void tb_search_TextChanged(object sender, EventArgs e) 331 | { 332 | listBox1.Items.Clear(); 333 | if (tb_search.Text.Trim() == "") 334 | listBox1.Items.AddRange(loadedSarc.Files.Keys.ToArray()); 335 | else 336 | foreach (var k in loadedSarc.Files.Keys) 337 | if (k.IndexOf(tb_search.Text, StringComparison.InvariantCultureIgnoreCase) != -1) 338 | listBox1.Items.Add(k); 339 | } 340 | 341 | private void extractNamesInClipboardToolStripMenuItem_Click(object sender, EventArgs e) 342 | { 343 | var names = Clipboard.GetText() 344 | .Split('\n') 345 | .Select(x => x.Trim()) 346 | .Where(x => x != "") 347 | .ToArray(); 348 | 349 | ExtractMultipleFiles(names); 350 | } 351 | 352 | private void exportFileListToClipboardToolStripMenuItem_Click(object sender, EventArgs e) 353 | { 354 | var names = loadedSarc.Files.Keys 355 | .Select(x => x.Trim()) 356 | .Where(x => x != "") 357 | .ToArray(); 358 | Clipboard.SetText(string.Join("\n", names)); 359 | } 360 | 361 | //private void openAllBflanToolStripMenuItem_Click(object sender, EventArgs e) 362 | //{ 363 | // foreach (var k in loadedSarc.Files.Keys) 364 | // if (k.EndsWith("bflan")) 365 | // MainForm.OpenFile(loadedSarc.Files[k], k); 366 | //} 367 | } 368 | } 369 | -------------------------------------------------------------------------------- /BflytPreview/MainForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace BflytPreview 2 | { 3 | partial class MainForm 4 | { 5 | /// 6 | /// Variabile di progettazione necessaria. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Pulire le risorse in uso. 12 | /// 13 | /// ha valore true se le risorse gestite devono essere eliminate, false in caso contrario. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Codice generato da Progettazione Windows Form 24 | 25 | /// 26 | /// Metodo necessario per il supporto della finestra di progettazione. Non modificare 27 | /// il contenuto del metodo con l'editor di codice. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); 32 | this.menuStrip1 = new System.Windows.Forms.MenuStrip(); 33 | this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 34 | this.openBFLYTToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 35 | this.importJSONToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 36 | this.bFLANToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 37 | this.createSzsFromFolderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 38 | this.toolsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 39 | this.layoutDiffToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 40 | this.checkUpdateToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 41 | this.splitContainer1 = new System.Windows.Forms.SplitContainer(); 42 | this.splitContainer2 = new System.Windows.Forms.SplitContainer(); 43 | this.treeView1 = new System.Windows.Forms.TreeView(); 44 | this.zoomSlider = new System.Windows.Forms.TrackBar(); 45 | this.propertyGrid1 = new System.Windows.Forms.PropertyGrid(); 46 | this.panel1 = new System.Windows.Forms.Panel(); 47 | this.pictureBox1 = new System.Windows.Forms.PictureBox(); 48 | this.pnlSubSystem = new System.Windows.Forms.Panel(); 49 | this.menuStrip1.SuspendLayout(); 50 | ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); 51 | this.splitContainer1.Panel1.SuspendLayout(); 52 | this.splitContainer1.Panel2.SuspendLayout(); 53 | this.splitContainer1.SuspendLayout(); 54 | ((System.ComponentModel.ISupportInitialize)(this.splitContainer2)).BeginInit(); 55 | this.splitContainer2.Panel1.SuspendLayout(); 56 | this.splitContainer2.Panel2.SuspendLayout(); 57 | this.splitContainer2.SuspendLayout(); 58 | ((System.ComponentModel.ISupportInitialize)(this.zoomSlider)).BeginInit(); 59 | this.panel1.SuspendLayout(); 60 | ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); 61 | this.SuspendLayout(); 62 | // 63 | // menuStrip1 64 | // 65 | this.menuStrip1.ImageScalingSize = new System.Drawing.Size(20, 20); 66 | this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 67 | this.fileToolStripMenuItem, 68 | this.toolsToolStripMenuItem, 69 | this.checkUpdateToolStripMenuItem}); 70 | this.menuStrip1.Location = new System.Drawing.Point(0, 0); 71 | this.menuStrip1.Name = "menuStrip1"; 72 | this.menuStrip1.Padding = new System.Windows.Forms.Padding(4, 2, 0, 2); 73 | this.menuStrip1.Size = new System.Drawing.Size(672, 24); 74 | this.menuStrip1.TabIndex = 1; 75 | this.menuStrip1.Text = "menuStrip1"; 76 | // 77 | // fileToolStripMenuItem 78 | // 79 | this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { 80 | this.openBFLYTToolStripMenuItem, 81 | this.importJSONToolStripMenuItem, 82 | this.createSzsFromFolderToolStripMenuItem}); 83 | this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; 84 | this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); 85 | this.fileToolStripMenuItem.Text = "File"; 86 | // 87 | // openBFLYTToolStripMenuItem 88 | // 89 | this.openBFLYTToolStripMenuItem.Name = "openBFLYTToolStripMenuItem"; 90 | this.openBFLYTToolStripMenuItem.Size = new System.Drawing.Size(190, 22); 91 | this.openBFLYTToolStripMenuItem.Text = "Open file"; 92 | this.openBFLYTToolStripMenuItem.Click += new System.EventHandler(this.openBFLYTToolStripMenuItem_Click); 93 | // 94 | // importJSONToolStripMenuItem 95 | // 96 | this.importJSONToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { 97 | this.bFLANToolStripMenuItem}); 98 | this.importJSONToolStripMenuItem.Name = "importJSONToolStripMenuItem"; 99 | this.importJSONToolStripMenuItem.Size = new System.Drawing.Size(190, 22); 100 | this.importJSONToolStripMenuItem.Text = "Import JSON"; 101 | // 102 | // bFLANToolStripMenuItem 103 | // 104 | this.bFLANToolStripMenuItem.Name = "bFLANToolStripMenuItem"; 105 | this.bFLANToolStripMenuItem.Size = new System.Drawing.Size(180, 22); 106 | this.bFLANToolStripMenuItem.Text = "BFLAN Animation"; 107 | this.bFLANToolStripMenuItem.Click += new System.EventHandler(this.BFLANToolStripMenuItem_Click); 108 | // 109 | // createSzsFromFolderToolStripMenuItem 110 | // 111 | this.createSzsFromFolderToolStripMenuItem.Name = "createSzsFromFolderToolStripMenuItem"; 112 | this.createSzsFromFolderToolStripMenuItem.Size = new System.Drawing.Size(190, 22); 113 | this.createSzsFromFolderToolStripMenuItem.Text = "Create Szs from folder"; 114 | this.createSzsFromFolderToolStripMenuItem.Click += new System.EventHandler(this.createSzsFromFolderToolStripMenuItem_Click); 115 | // 116 | // toolsToolStripMenuItem 117 | // 118 | this.toolsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { 119 | this.layoutDiffToolStripMenuItem}); 120 | this.toolsToolStripMenuItem.Name = "toolsToolStripMenuItem"; 121 | this.toolsToolStripMenuItem.Size = new System.Drawing.Size(46, 20); 122 | this.toolsToolStripMenuItem.Text = "Tools"; 123 | // 124 | // layoutDiffToolStripMenuItem 125 | // 126 | this.layoutDiffToolStripMenuItem.Name = "layoutDiffToolStripMenuItem"; 127 | this.layoutDiffToolStripMenuItem.Size = new System.Drawing.Size(180, 22); 128 | this.layoutDiffToolStripMenuItem.Text = "Layout diff"; 129 | this.layoutDiffToolStripMenuItem.Click += new System.EventHandler(this.layoutDiffToolStripMenuItem_Click); 130 | // 131 | // checkUpdateToolStripMenuItem 132 | // 133 | this.checkUpdateToolStripMenuItem.Name = "checkUpdateToolStripMenuItem"; 134 | this.checkUpdateToolStripMenuItem.Size = new System.Drawing.Size(115, 20); 135 | this.checkUpdateToolStripMenuItem.Text = "Check for updates"; 136 | this.checkUpdateToolStripMenuItem.Click += new System.EventHandler(this.checkUpdateToolStripMenuItem_Click); 137 | // 138 | // splitContainer1 139 | // 140 | this.splitContainer1.BackColor = System.Drawing.SystemColors.ControlDarkDark; 141 | this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; 142 | this.splitContainer1.Location = new System.Drawing.Point(0, 24); 143 | this.splitContainer1.Name = "splitContainer1"; 144 | // 145 | // splitContainer1.Panel1 146 | // 147 | this.splitContainer1.Panel1.Controls.Add(this.splitContainer2); 148 | // 149 | // splitContainer1.Panel2 150 | // 151 | this.splitContainer1.Panel2.Controls.Add(this.panel1); 152 | this.splitContainer1.Size = new System.Drawing.Size(672, 424); 153 | this.splitContainer1.SplitterDistance = 223; 154 | this.splitContainer1.TabIndex = 4; 155 | // 156 | // splitContainer2 157 | // 158 | this.splitContainer2.Dock = System.Windows.Forms.DockStyle.Fill; 159 | this.splitContainer2.Location = new System.Drawing.Point(0, 0); 160 | this.splitContainer2.Name = "splitContainer2"; 161 | this.splitContainer2.Orientation = System.Windows.Forms.Orientation.Horizontal; 162 | // 163 | // splitContainer2.Panel1 164 | // 165 | this.splitContainer2.Panel1.Controls.Add(this.treeView1); 166 | // 167 | // splitContainer2.Panel2 168 | // 169 | this.splitContainer2.Panel2.BackColor = System.Drawing.SystemColors.Control; 170 | this.splitContainer2.Panel2.Controls.Add(this.zoomSlider); 171 | this.splitContainer2.Panel2.Controls.Add(this.propertyGrid1); 172 | this.splitContainer2.Size = new System.Drawing.Size(223, 424); 173 | this.splitContainer2.SplitterDistance = 211; 174 | this.splitContainer2.TabIndex = 4; 175 | // 176 | // treeView1 177 | // 178 | this.treeView1.Dock = System.Windows.Forms.DockStyle.Fill; 179 | this.treeView1.Enabled = false; 180 | this.treeView1.Location = new System.Drawing.Point(0, 0); 181 | this.treeView1.Name = "treeView1"; 182 | this.treeView1.Size = new System.Drawing.Size(223, 211); 183 | this.treeView1.TabIndex = 3; 184 | this.treeView1.Visible = false; 185 | // 186 | // zoomSlider 187 | // 188 | this.zoomSlider.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 189 | this.zoomSlider.Enabled = false; 190 | this.zoomSlider.LargeChange = 1; 191 | this.zoomSlider.Location = new System.Drawing.Point(115, 155); 192 | this.zoomSlider.Name = "zoomSlider"; 193 | this.zoomSlider.Size = new System.Drawing.Size(104, 45); 194 | this.zoomSlider.TabIndex = 1; 195 | this.zoomSlider.Value = 5; 196 | this.zoomSlider.Visible = false; 197 | // 198 | // propertyGrid1 199 | // 200 | this.propertyGrid1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 201 | | System.Windows.Forms.AnchorStyles.Left) 202 | | System.Windows.Forms.AnchorStyles.Right))); 203 | this.propertyGrid1.Enabled = false; 204 | this.propertyGrid1.Location = new System.Drawing.Point(3, 3); 205 | this.propertyGrid1.Name = "propertyGrid1"; 206 | this.propertyGrid1.Size = new System.Drawing.Size(219, 203); 207 | this.propertyGrid1.TabIndex = 0; 208 | this.propertyGrid1.Visible = false; 209 | // 210 | // panel1 211 | // 212 | this.panel1.AutoScroll = true; 213 | this.panel1.AutoSize = true; 214 | this.panel1.Controls.Add(this.pictureBox1); 215 | this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; 216 | this.panel1.Location = new System.Drawing.Point(0, 0); 217 | this.panel1.Name = "panel1"; 218 | this.panel1.Size = new System.Drawing.Size(445, 424); 219 | this.panel1.TabIndex = 0; 220 | // 221 | // pictureBox1 222 | // 223 | this.pictureBox1.Enabled = false; 224 | this.pictureBox1.Location = new System.Drawing.Point(0, 0); 225 | this.pictureBox1.Name = "pictureBox1"; 226 | this.pictureBox1.Size = new System.Drawing.Size(441, 421); 227 | this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; 228 | this.pictureBox1.TabIndex = 0; 229 | this.pictureBox1.TabStop = false; 230 | this.pictureBox1.Visible = false; 231 | // 232 | // pnlSubSystem 233 | // 234 | this.pnlSubSystem.AllowDrop = true; 235 | this.pnlSubSystem.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 236 | | System.Windows.Forms.AnchorStyles.Left) 237 | | System.Windows.Forms.AnchorStyles.Right))); 238 | this.pnlSubSystem.Location = new System.Drawing.Point(0, 24); 239 | this.pnlSubSystem.Name = "pnlSubSystem"; 240 | this.pnlSubSystem.Size = new System.Drawing.Size(672, 424); 241 | this.pnlSubSystem.TabIndex = 5; 242 | this.pnlSubSystem.DragDrop += new System.Windows.Forms.DragEventHandler(this.pnlSubSystem_DragDrop); 243 | this.pnlSubSystem.DragEnter += new System.Windows.Forms.DragEventHandler(this.pnlSubSystem_DragEnter); 244 | // 245 | // MainForm 246 | // 247 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 248 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 249 | this.ClientSize = new System.Drawing.Size(672, 448); 250 | this.Controls.Add(this.pnlSubSystem); 251 | this.Controls.Add(this.splitContainer1); 252 | this.Controls.Add(this.menuStrip1); 253 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); 254 | this.MainMenuStrip = this.menuStrip1; 255 | this.Name = "MainForm"; 256 | this.Text = "Switch Layout Editor"; 257 | this.Load += new System.EventHandler(this.Form1_Load); 258 | this.menuStrip1.ResumeLayout(false); 259 | this.menuStrip1.PerformLayout(); 260 | this.splitContainer1.Panel1.ResumeLayout(false); 261 | this.splitContainer1.Panel2.ResumeLayout(false); 262 | this.splitContainer1.Panel2.PerformLayout(); 263 | ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); 264 | this.splitContainer1.ResumeLayout(false); 265 | this.splitContainer2.Panel1.ResumeLayout(false); 266 | this.splitContainer2.Panel2.ResumeLayout(false); 267 | this.splitContainer2.Panel2.PerformLayout(); 268 | ((System.ComponentModel.ISupportInitialize)(this.splitContainer2)).EndInit(); 269 | this.splitContainer2.ResumeLayout(false); 270 | ((System.ComponentModel.ISupportInitialize)(this.zoomSlider)).EndInit(); 271 | this.panel1.ResumeLayout(false); 272 | ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); 273 | this.ResumeLayout(false); 274 | this.PerformLayout(); 275 | 276 | } 277 | 278 | #endregion 279 | private System.Windows.Forms.MenuStrip menuStrip1; 280 | private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem; 281 | private System.Windows.Forms.ToolStripMenuItem openBFLYTToolStripMenuItem; 282 | private System.Windows.Forms.SplitContainer splitContainer1; 283 | private System.Windows.Forms.SplitContainer splitContainer2; 284 | private System.Windows.Forms.TreeView treeView1; 285 | private System.Windows.Forms.PropertyGrid propertyGrid1; 286 | private System.Windows.Forms.TrackBar zoomSlider; 287 | private System.Windows.Forms.Panel panel1; 288 | private System.Windows.Forms.PictureBox pictureBox1; 289 | private System.Windows.Forms.Panel pnlSubSystem; 290 | private System.Windows.Forms.ToolStripMenuItem toolsToolStripMenuItem; 291 | private System.Windows.Forms.ToolStripMenuItem layoutDiffToolStripMenuItem; 292 | private System.Windows.Forms.ToolStripMenuItem checkUpdateToolStripMenuItem; 293 | private System.Windows.Forms.ToolStripMenuItem importJSONToolStripMenuItem; 294 | private System.Windows.Forms.ToolStripMenuItem bFLANToolStripMenuItem; 295 | private System.Windows.Forms.ToolStripMenuItem createSzsFromFolderToolStripMenuItem; 296 | } 297 | } 298 | 299 | -------------------------------------------------------------------------------- /BflytPreview/MainForm.cs: -------------------------------------------------------------------------------- 1 | using SwitchThemes.Common; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.IO; 6 | using System.Windows.Forms; 7 | using Syroot.BinaryData; 8 | using System.Threading.Tasks; 9 | using SwitchThemes.Common.Bflyt; 10 | using SwitchThemes.Common.Bflan; 11 | using System.Text; 12 | using System.Linq; 13 | using SARCExt; 14 | 15 | namespace BflytPreview 16 | { 17 | public partial class MainForm : Form 18 | { 19 | public static void CheckForUpdates(bool showErrors) 20 | { 21 | try 22 | { 23 | var githubClient = new Octokit.GitHubClient(new Octokit.ProductHeaderValue("SwitchLayoutEditor")); 24 | var ver = githubClient.Repository.Release.GetAll("FuryBaguette", "SwitchLayoutEditor").GetAwaiter().GetResult(); 25 | if (ver.Count > Program.AppRelease) 26 | { 27 | if (MessageBox.Show($"A new version has been found: {ver[0].Name}\r\n{ver[0].Body}\r\nOpen the github page ?", "", MessageBoxButtons.YesNo) == DialogResult.Yes) 28 | System.Diagnostics.Process.Start("https://github.com/FuryBaguette/SwitchLayoutEditor/releases/latest"); 29 | } 30 | else if (showErrors) 31 | MessageBox.Show("You're running the latest version :)"); 32 | } 33 | catch (Exception ex) 34 | { 35 | if (showErrors) 36 | MessageBox.Show("Error while searching for updates:\r\n" + ex.ToString()); 37 | } 38 | } 39 | 40 | public MainForm(string[] args = null) 41 | { 42 | InitializeComponent(); 43 | 44 | foreach (string s in args) 45 | if (File.Exists(s)) 46 | OpenFileFromDisk(s); 47 | } 48 | 49 | private void openBFLYTToolStripMenuItem_Click(object sender, EventArgs e) 50 | { 51 | OpenFileDialog opn = new OpenFileDialog() { Filter = "Supported files (bflyt,szs,bflan)|*.bflyt;*.szs;*.bflan|All files|*.*" }; 52 | if (opn.ShowDialog() != DialogResult.OK) return; 53 | OpenFileFromDisk(opn.FileName); 54 | } 55 | 56 | private void Form1_Load(object sender, System.EventArgs e) 57 | { 58 | this.Text += $" - Release {Program.AppRelease}"; 59 | #if DEBUG 60 | this.Text += " - This is a debug build, auto updates are disabled."; 61 | createSzsFromFolderToolStripMenuItem.Visible = true; 62 | #else 63 | Task.Run(() => CheckForUpdates(false)); 64 | createSzsFromFolderToolStripMenuItem.Visible = false; 65 | #endif 66 | //#if DEBUG 67 | // string AutoLaunch = @"RdtBase.bflyt"; 68 | // if (!File.Exists(AutoLaunch)) return; 69 | // OpenFile(File.ReadAllBytes(AutoLaunch), AutoLaunch); 70 | //#endif 71 | } 72 | 73 | public void OpenForm(Form f) 74 | { 75 | this.IsMdiContainer = true; 76 | f.TopLevel = false; 77 | f.Parent = pnlSubSystem; 78 | f.Show(); 79 | } 80 | 81 | public Form OpenFileFromDisk(string path) => 82 | OpenFile(File.ReadAllBytes(path), new DiskFileProvider(path)); 83 | 84 | public Form OpenFile(byte[] File, IFileWriter saveTo) 85 | { 86 | string Magic = Encoding.ASCII.GetString(File, 0, 4); 87 | Form result = null; 88 | if (Magic == "Yaz0") 89 | return OpenFile(ManagedYaz0.Decompress(File), saveTo); 90 | else if (Magic == "SARC") 91 | result = new EditorForms.SzsEditor(SARCExt.SARC.Unpack(File), saveTo, this); 92 | else if (Magic == "FLYT") 93 | result = new EditorView(new BflytFile(File), saveTo); 94 | else if (Magic == "FLAN") 95 | result = new BflanEditor(new BflanFile(File), saveTo); 96 | 97 | if (result != null) 98 | OpenForm(result); 99 | 100 | return result; 101 | } 102 | 103 | private void pnlSubSystem_DragEnter(object sender, DragEventArgs e) 104 | {if (e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effect = DragDropEffects.Copy;} 105 | 106 | private void pnlSubSystem_DragDrop(object sender, DragEventArgs e) 107 | { 108 | string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); 109 | foreach (string file in files) 110 | OpenFileFromDisk(file); 111 | } 112 | 113 | private void layoutDiffToolStripMenuItem_Click(object sender, EventArgs e) 114 | => new EditorForms.LayoutDiffForm().Show(); 115 | 116 | private void checkUpdateToolStripMenuItem_Click(object sender, EventArgs e) 117 | { 118 | CheckForUpdates(true); 119 | } 120 | 121 | private void BFLANToolStripMenuItem_Click(object sender, EventArgs e) 122 | { 123 | try 124 | { 125 | var f = BflanEditor.OpenFromJson(); 126 | if (f != null) OpenForm(f); 127 | } 128 | catch (Exception ex) 129 | { 130 | MessageBox.Show( 131 | "Error while opening the provided file: " + ex.Message + "\r\n" + 132 | "This often happens when trying to open a json file that doesn't contain animations. " + 133 | "If you want to open a json layout open the target szs first and then load it from the window that appears.\r\n\r\n" + 134 | "More details: " + ex.ToString()); 135 | } 136 | } 137 | 138 | private void createSzsFromFolderToolStripMenuItem_Click(object sender, EventArgs e) 139 | { 140 | using var folderBrowser = new FolderBrowserDialog(); 141 | if (folderBrowser.ShowDialog() == DialogResult.OK) 142 | { 143 | using var saveFileDialog = new SaveFileDialog 144 | { 145 | Filter = "szs files|*.szs", 146 | FileName = "new.szs" 147 | }; 148 | 149 | if (saveFileDialog.ShowDialog() != DialogResult.OK) 150 | return; 151 | 152 | var root = folderBrowser.SelectedPath; 153 | var files = Directory.GetFiles(folderBrowser.SelectedPath, "*", SearchOption.AllDirectories) 154 | .Select(x => x.Remove(0, root.Length + 1)) 155 | .ToArray(); 156 | 157 | var szs = new SARCExt.SarcData(); 158 | foreach (var file in files) 159 | { 160 | var name = file.Replace('\\', '/'); 161 | var data = File.ReadAllBytes(Path.Combine(root, file)); 162 | szs.Files.Add(name, data); 163 | } 164 | 165 | var s = SARC.Pack(szs); 166 | File.WriteAllBytes(saveFileDialog.FileName, ManagedYaz0.Compress(s.Item2, 3, s.Item1)); 167 | } 168 | } 169 | } 170 | 171 | public class Vector3Converter : System.ComponentModel.TypeConverter 172 | { 173 | public override bool GetPropertiesSupported(ITypeDescriptorContext context) => true; 174 | 175 | public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, Type sourceType) 176 | { 177 | return sourceType == typeof(string); 178 | } 179 | 180 | public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) 181 | { 182 | string[] tokens = ((string)value).Split(';'); 183 | return new Vector3( 184 | float.Parse(tokens[0]), 185 | float.Parse(tokens[1]), 186 | float.Parse(tokens[2])); 187 | } 188 | 189 | public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) 190 | { 191 | var v = (Vector3)value; 192 | return $"{v.X};{v.Y};{v.Z}"; 193 | } 194 | } 195 | 196 | public class Vector2Converter : System.ComponentModel.TypeConverter 197 | { 198 | public override bool GetPropertiesSupported(ITypeDescriptorContext context) => true; 199 | 200 | public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, Type sourceType) 201 | { 202 | return sourceType == typeof(string); 203 | } 204 | 205 | public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) 206 | { 207 | string[] tokens = ((string)value).Split(';'); 208 | return new Vector2( 209 | float.Parse(tokens[0]), 210 | float.Parse(tokens[1])); 211 | } 212 | 213 | public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) 214 | { 215 | var v = (Vector2)value; 216 | return $"{v.X};{v.Y}"; 217 | } 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /BflytPreview/OpenTK.dll.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /BflytPreview/Program.cs: -------------------------------------------------------------------------------- 1 | using SwitchThemes.Common; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.Drawing.Design; 6 | using System.Linq; 7 | using System.Threading.Tasks; 8 | using System.Windows.Forms; 9 | 10 | namespace BflytPreview 11 | { 12 | static class Program 13 | { 14 | //Increase this by one for each release on github 15 | public const int AppRelease = 16; 16 | 17 | /// 18 | /// Punto di ingresso principale dell'applicazione. 19 | /// 20 | [STAThread] 21 | static void Main(params string[] args) 22 | { 23 | TypeDescriptor.AddAttributes(typeof(Vector3), new TypeConverterAttribute(typeof(Vector3Converter))); 24 | TypeDescriptor.AddAttributes(typeof(Vector2), new TypeConverterAttribute(typeof(Vector2Converter))); 25 | 26 | Application.EnableVisualStyles(); 27 | Application.SetCompatibleTextRenderingDefault(false); 28 | Application.Run(new MainForm(args)); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /BflytPreview/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // Le informazioni generali relative a un assembly sono controllate dal seguente 6 | // set di attributi. Modificare i valori di questi attributi per modificare le informazioni 7 | // associate a un assembly. 8 | [assembly: AssemblyTitle("BflytPreview")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("BflytPreview")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Se si imposta ComVisible su false, i tipi in questo assembly non saranno visibili 18 | // ai componenti COM. Se è necessario accedere a un tipo in questo assembly da 19 | // COM, impostare su true l'attributo ComVisible per tale tipo. 20 | [assembly: ComVisible(false)] 21 | 22 | // Se il progetto viene esposto a COM, il GUID seguente verrà utilizzato come ID della libreria dei tipi 23 | [assembly: Guid("d59c0348-7d8e-46df-8761-1ca9c5ff5556")] 24 | 25 | // Le informazioni sulla versione di un assembly sono costituite dai seguenti quattro valori: 26 | // 27 | // Versione principale 28 | // Versione secondaria 29 | // Numero di build 30 | // Revisione 31 | // 32 | // È possibile specificare tutti i valori oppure impostare valori predefiniti per i numeri relativi alla revisione e alla build 33 | // usando l'asterisco '*' come illustrato di seguito: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.16")] 36 | [assembly: AssemblyFileVersion("1.0.0.16")] 37 | -------------------------------------------------------------------------------- /BflytPreview/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // Il codice è stato generato da uno strumento. 4 | // Versione runtime:4.0.30319.42000 5 | // 6 | // Le modifiche apportate a questo file possono provocare un comportamento non corretto e andranno perse se 7 | // il codice viene rigenerato. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace BflytPreview.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// Classe di risorse fortemente tipizzata per la ricerca di stringhe localizzate e così via. 17 | /// 18 | // Questa classe è stata generata automaticamente dalla classe StronglyTypedResourceBuilder. 19 | // tramite uno strumento quale ResGen o Visual Studio. 20 | // Per aggiungere o rimuovere un membro, modificare il file con estensione ResX ed eseguire nuovamente ResGen 21 | // con l'opzione /str oppure ricompilare il progetto VS. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Restituisce l'istanza di ResourceManager nella cache utilizzata da questa classe. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("BflytPreview.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Esegue l'override della proprietà CurrentUICulture del thread corrente per tutte le 51 | /// ricerche di risorse eseguite utilizzando questa classe di risorse fortemente tipizzata. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /BflytPreview/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /BflytPreview/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // Il codice è stato generato da uno strumento. 4 | // Versione runtime:4.0.30319.42000 5 | // 6 | // Le modifiche apportate a questo file possono provocare un comportamento non corretto e andranno perse se 7 | // il codice viene rigenerato. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace BflytPreview.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.5.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /BflytPreview/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /BflytPreview/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // Il codice è stato generato da uno strumento. 4 | // Versione runtime:4.0.30319.42000 5 | // 6 | // Le modifiche apportate a questo file possono provocare un comportamento non corretto e andranno perse se 7 | // il codice viene rigenerato. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace BflytPreview { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.5.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | 26 | [global::System.Configuration.UserScopedSettingAttribute()] 27 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 28 | [global::System.Configuration.DefaultSettingValueAttribute("Black")] 29 | public global::System.Drawing.Color PaneColor { 30 | get { 31 | return ((global::System.Drawing.Color)(this["PaneColor"])); 32 | } 33 | set { 34 | this["PaneColor"] = value; 35 | } 36 | } 37 | 38 | [global::System.Configuration.UserScopedSettingAttribute()] 39 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 40 | [global::System.Configuration.DefaultSettingValueAttribute("Red")] 41 | public global::System.Drawing.Color SelectedColor { 42 | get { 43 | return ((global::System.Drawing.Color)(this["SelectedColor"])); 44 | } 45 | set { 46 | this["SelectedColor"] = value; 47 | } 48 | } 49 | 50 | [global::System.Configuration.UserScopedSettingAttribute()] 51 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 52 | [global::System.Configuration.DefaultSettingValueAttribute("LightGreen")] 53 | public global::System.Drawing.Color OutlineColor { 54 | get { 55 | return ((global::System.Drawing.Color)(this["OutlineColor"])); 56 | } 57 | set { 58 | this["OutlineColor"] = value; 59 | } 60 | } 61 | 62 | [global::System.Configuration.UserScopedSettingAttribute()] 63 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 64 | [global::System.Configuration.DefaultSettingValueAttribute("")] 65 | public string BgFileName { 66 | get { 67 | return ((string)(this["BgFileName"])); 68 | } 69 | set { 70 | this["BgFileName"] = value; 71 | } 72 | } 73 | 74 | [global::System.Configuration.UserScopedSettingAttribute()] 75 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 76 | [global::System.Configuration.DefaultSettingValueAttribute("False")] 77 | public bool ShowImage { 78 | get { 79 | return ((bool)(this["ShowImage"])); 80 | } 81 | set { 82 | this["ShowImage"] = value; 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /BflytPreview/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Black 7 | 8 | 9 | Red 10 | 11 | 12 | LightGreen 13 | 14 | 15 | 16 | 17 | 18 | False 19 | 20 | 21 | -------------------------------------------------------------------------------- /BflytPreview/SettingsWindow.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace BflytPreview 2 | { 3 | partial class SettingsWindow 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SettingsWindow)); 32 | this.label1 = new System.Windows.Forms.Label(); 33 | this.pickColor = new System.Windows.Forms.Button(); 34 | this.selectedColor = new System.Windows.Forms.Button(); 35 | this.label2 = new System.Windows.Forms.Label(); 36 | this.outlineColor = new System.Windows.Forms.Button(); 37 | this.label3 = new System.Windows.Forms.Label(); 38 | this.loadBackgroundImage = new System.Windows.Forms.Button(); 39 | this.pictureBox1 = new System.Windows.Forms.PictureBox(); 40 | this.showImg = new System.Windows.Forms.Button(); 41 | ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); 42 | this.SuspendLayout(); 43 | // 44 | // label1 45 | // 46 | this.label1.AutoSize = true; 47 | this.label1.Location = new System.Drawing.Point(13, 13); 48 | this.label1.Name = "label1"; 49 | this.label1.Size = new System.Drawing.Size(59, 13); 50 | this.label1.TabIndex = 0; 51 | this.label1.Text = "Pane Color"; 52 | // 53 | // pickColor 54 | // 55 | this.pickColor.Location = new System.Drawing.Point(96, 8); 56 | this.pickColor.Name = "pickColor"; 57 | this.pickColor.Size = new System.Drawing.Size(75, 23); 58 | this.pickColor.TabIndex = 1; 59 | this.pickColor.UseVisualStyleBackColor = true; 60 | this.pickColor.Click += new System.EventHandler(this.pickColor_Click); 61 | // 62 | // selectedColor 63 | // 64 | this.selectedColor.Location = new System.Drawing.Point(96, 37); 65 | this.selectedColor.Name = "selectedColor"; 66 | this.selectedColor.Size = new System.Drawing.Size(75, 23); 67 | this.selectedColor.TabIndex = 2; 68 | this.selectedColor.UseVisualStyleBackColor = true; 69 | this.selectedColor.Click += new System.EventHandler(this.selectedColor_Click); 70 | // 71 | // label2 72 | // 73 | this.label2.AutoSize = true; 74 | this.label2.Location = new System.Drawing.Point(13, 43); 75 | this.label2.Name = "label2"; 76 | this.label2.Size = new System.Drawing.Size(76, 13); 77 | this.label2.TabIndex = 3; 78 | this.label2.Text = "Selected Color"; 79 | // 80 | // outlineColor 81 | // 82 | this.outlineColor.Location = new System.Drawing.Point(96, 67); 83 | this.outlineColor.Name = "outlineColor"; 84 | this.outlineColor.Size = new System.Drawing.Size(75, 23); 85 | this.outlineColor.TabIndex = 4; 86 | this.outlineColor.UseVisualStyleBackColor = true; 87 | this.outlineColor.Click += new System.EventHandler(this.outlineColor_Click); 88 | // 89 | // label3 90 | // 91 | this.label3.AutoSize = true; 92 | this.label3.Location = new System.Drawing.Point(13, 72); 93 | this.label3.Name = "label3"; 94 | this.label3.Size = new System.Drawing.Size(67, 13); 95 | this.label3.TabIndex = 5; 96 | this.label3.Text = "Outline Color"; 97 | // 98 | // loadBackgroundImage 99 | // 100 | this.loadBackgroundImage.Location = new System.Drawing.Point(13, 102); 101 | this.loadBackgroundImage.Name = "loadBackgroundImage"; 102 | this.loadBackgroundImage.Size = new System.Drawing.Size(158, 23); 103 | this.loadBackgroundImage.TabIndex = 6; 104 | this.loadBackgroundImage.Text = "Set Background Image"; 105 | this.loadBackgroundImage.UseVisualStyleBackColor = true; 106 | this.loadBackgroundImage.Click += new System.EventHandler(this.loadBackgroundImage_Click); 107 | // 108 | // pictureBox1 109 | // 110 | this.pictureBox1.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; 111 | this.pictureBox1.Location = new System.Drawing.Point(177, 8); 112 | this.pictureBox1.Name = "pictureBox1"; 113 | this.pictureBox1.Size = new System.Drawing.Size(206, 117); 114 | this.pictureBox1.TabIndex = 7; 115 | this.pictureBox1.TabStop = false; 116 | // 117 | // showImg 118 | // 119 | this.showImg.Location = new System.Drawing.Point(13, 132); 120 | this.showImg.Name = "showImg"; 121 | this.showImg.Size = new System.Drawing.Size(158, 23); 122 | this.showImg.TabIndex = 8; 123 | this.showImg.Text = "Show Image"; 124 | this.showImg.UseVisualStyleBackColor = true; 125 | this.showImg.Click += new System.EventHandler(this.showImg_Click); 126 | // 127 | // SettingsWindow 128 | // 129 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 130 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 131 | this.ClientSize = new System.Drawing.Size(393, 173); 132 | this.Controls.Add(this.showImg); 133 | this.Controls.Add(this.pictureBox1); 134 | this.Controls.Add(this.loadBackgroundImage); 135 | this.Controls.Add(this.label3); 136 | this.Controls.Add(this.outlineColor); 137 | this.Controls.Add(this.label2); 138 | this.Controls.Add(this.selectedColor); 139 | this.Controls.Add(this.pickColor); 140 | this.Controls.Add(this.label1); 141 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); 142 | this.Name = "SettingsWindow"; 143 | this.Text = "Settings"; 144 | this.Load += new System.EventHandler(this.SettingsWindow_Load); 145 | ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); 146 | this.ResumeLayout(false); 147 | this.PerformLayout(); 148 | 149 | } 150 | 151 | #endregion 152 | 153 | private System.Windows.Forms.Label label1; 154 | private System.Windows.Forms.Button pickColor; 155 | private System.Windows.Forms.Button selectedColor; 156 | private System.Windows.Forms.Label label2; 157 | private System.Windows.Forms.Button outlineColor; 158 | private System.Windows.Forms.Label label3; 159 | private System.Windows.Forms.Button loadBackgroundImage; 160 | private System.Windows.Forms.PictureBox pictureBox1; 161 | private System.Windows.Forms.Button showImg; 162 | } 163 | } -------------------------------------------------------------------------------- /BflytPreview/SettingsWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace BflytPreview 12 | { 13 | public partial class SettingsWindow : Form 14 | { 15 | public SettingsWindow() 16 | { 17 | InitializeComponent(); 18 | } 19 | 20 | private void SettingsWindow_Load(object sender, EventArgs e) 21 | { 22 | pickColor.BackColor = Settings.Default.PaneColor; 23 | selectedColor.BackColor = Settings.Default.SelectedColor; 24 | outlineColor.BackColor = Settings.Default.OutlineColor; 25 | Console.WriteLine(Settings.Default.BgFileName); 26 | if (!string.IsNullOrEmpty(Settings.Default.BgFileName)) 27 | { 28 | pictureBox1.BackgroundImage = Image.FromFile(Settings.Default.BgFileName); 29 | EditorView.texture = EditorView.LoadBgImage(Settings.Default.BgFileName, false, true); 30 | } 31 | if (Settings.Default.ShowImage) 32 | showImg.Text = "Hide Image"; 33 | } 34 | 35 | private void SettingsWindow_FormClosing(object sender, FormClosingEventArgs e) 36 | { 37 | 38 | Settings.Default.PaneColor = pickColor.BackColor; 39 | Settings.Default.SelectedColor = selectedColor.BackColor; 40 | Settings.Default.OutlineColor = outlineColor.BackColor; 41 | Settings.Default.OutlineColor = outlineColor.BackColor; 42 | Settings.Default.Save(); 43 | } 44 | 45 | private void pickColor_Click(object sender, EventArgs e) 46 | { 47 | ColorDialog MyDialog = new ColorDialog(); 48 | MyDialog.ShowHelp = true; 49 | MyDialog.Color = Settings.Default.PaneColor; 50 | 51 | if (MyDialog.ShowDialog() == DialogResult.OK) 52 | Settings.Default.PaneColor = pickColor.BackColor = MyDialog.Color; 53 | } 54 | 55 | private void selectedColor_Click(object sender, EventArgs e) 56 | { 57 | ColorDialog MyDialog = new ColorDialog(); 58 | MyDialog.ShowHelp = true; 59 | MyDialog.Color = Settings.Default.SelectedColor; 60 | 61 | if (MyDialog.ShowDialog() == DialogResult.OK) 62 | Settings.Default.SelectedColor = selectedColor.BackColor = MyDialog.Color; 63 | } 64 | 65 | private void outlineColor_Click(object sender, EventArgs e) 66 | { 67 | ColorDialog MyDialog = new ColorDialog(); 68 | MyDialog.ShowHelp = true; 69 | MyDialog.Color = Settings.Default.OutlineColor; 70 | 71 | if (MyDialog.ShowDialog() == DialogResult.OK) 72 | Settings.Default.OutlineColor = outlineColor.BackColor = MyDialog.Color; 73 | } 74 | 75 | private void loadBackgroundImage_Click(object sender, EventArgs e) 76 | { 77 | OpenFileDialog opn = new OpenFileDialog() { Filter = "Supported files (jpg,jpeg,png)|*.jpg;*.jpeg;*.png|All files|*.*" }; 78 | if (opn.ShowDialog() != DialogResult.OK) return; 79 | 80 | pictureBox1.BackgroundImage = Image.FromFile(opn.FileName); 81 | Settings.Default.BgFileName = opn.FileName; 82 | EditorView.texture = EditorView.LoadBgImage(opn.FileName, false, true); 83 | } 84 | 85 | private void showImg_Click(object sender, EventArgs e) 86 | { 87 | if (!Settings.Default.ShowImage) 88 | { 89 | Settings.Default.ShowImage = true; 90 | showImg.Text = "Hide Image"; 91 | } 92 | else 93 | { 94 | Settings.Default.ShowImage = false; 95 | showImg.Text = "Show Image"; 96 | } 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /BflytPreview/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuryBaguette/SwitchLayoutEditor/139adf8fa2ae3f59eee61c4465f213c30527d8e6/BflytPreview/favicon.ico -------------------------------------------------------------------------------- /BflytPreview/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuryBaguette/SwitchLayoutEditor/139adf8fa2ae3f59eee61c4465f213c30527d8e6/BflytPreview/icon.ico -------------------------------------------------------------------------------- /BflytPreview/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SwitchLayoutEditor 2 | This program can edit and render BFLYT and BFLAN files commonly used for layouts in Switch interfaces and games. It enables you to easily create/edit themes. As this is a work in progress, builds may get outdated quickly, you should check this page often. 3 | 4 | ## Usage / Wiki 5 | Just launch the exe and open a SZS/BFLYT/BFLAN file. \ 6 | BFLYT/BFLAN files are commonly found in SZS archives, when opening a SZS file you can double click on the files in the list to edit them (if they're supported). \ 7 | For a more in depth guide, [click here](https://github.com/FuryBaguette/SwitchLayoutEditor/wiki) to go to the wiki. 8 | 9 | ## Features 10 | - Layout loading, editing and saving 11 | - Rendering the bounding boxes of the components 12 | - SZS editing 13 | - Drag and drop 14 | - Simultaneous file editing 15 | - Import/Export JSON patch (Compatible with Switch themes) 16 | - Animations editing 17 | 18 | ## Support 19 | - Use the github issues to report problems/bugs **OR** 20 | - Join the [discord server](https://discord.gg/ap6yfR2) for support, news/announcements before anyone, be a tester or just talk. 21 | 22 | ## Screenshot 23 | This is using the original from the Switch's home menu: 24 | ![](https://github.com/FuryBaguette/SwitchLayoutEditor/blob/master/Screenshots/MainMenu.png) 25 | 26 | Example of a custom layout: 27 | ![](https://github.com/FuryBaguette/SwitchLayoutEditor/blob/master/Screenshots/Example.png) 28 | 29 | ## Building 30 | To build you need the SwitchThemesCommon shared project from [this repo](https://github.com/exelix11/SwitchThemeInjector). 31 | In case of issues try using a version from commit from the same day as the last commit on this repo. 32 | 33 | ## Credits 34 | - [FuryBaguette](https://github.com/FuryBaguette) - Development 35 | - [exelix](https://github.com/exelix11) - Base of the editor & Continuous development 36 | - [Aboud](https://github.com/aboood40091) - [Sarc Tool](https://github.com/aboood40091/SARC-Tool) 37 | - [Syroot](https://gitlab.com/Syroot) - [Binary Data](https://gitlab.com/Syroot/BinaryData) 38 | -------------------------------------------------------------------------------- /Screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuryBaguette/SwitchLayoutEditor/139adf8fa2ae3f59eee61c4465f213c30527d8e6/Screenshot.png -------------------------------------------------------------------------------- /Screenshots/Dragging.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuryBaguette/SwitchLayoutEditor/139adf8fa2ae3f59eee61c4465f213c30527d8e6/Screenshots/Dragging.gif -------------------------------------------------------------------------------- /Screenshots/EditorPreview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuryBaguette/SwitchLayoutEditor/139adf8fa2ae3f59eee61c4465f213c30527d8e6/Screenshots/EditorPreview.png -------------------------------------------------------------------------------- /Screenshots/Example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuryBaguette/SwitchLayoutEditor/139adf8fa2ae3f59eee61c4465f213c30527d8e6/Screenshots/Example.png -------------------------------------------------------------------------------- /Screenshots/LayoutEditing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuryBaguette/SwitchLayoutEditor/139adf8fa2ae3f59eee61c4465f213c30527d8e6/Screenshots/LayoutEditing.png -------------------------------------------------------------------------------- /Screenshots/MainMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuryBaguette/SwitchLayoutEditor/139adf8fa2ae3f59eee61c4465f213c30527d8e6/Screenshots/MainMenu.png -------------------------------------------------------------------------------- /Screenshots/PaneMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuryBaguette/SwitchLayoutEditor/139adf8fa2ae3f59eee61c4465f213c30527d8e6/Screenshots/PaneMenu.png -------------------------------------------------------------------------------- /Screenshots/PropertiesMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuryBaguette/SwitchLayoutEditor/139adf8fa2ae3f59eee61c4465f213c30527d8e6/Screenshots/PropertiesMenu.png -------------------------------------------------------------------------------- /Screenshots/SaveFile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuryBaguette/SwitchLayoutEditor/139adf8fa2ae3f59eee61c4465f213c30527d8e6/Screenshots/SaveFile.png -------------------------------------------------------------------------------- /Screenshots/Settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuryBaguette/SwitchLayoutEditor/139adf8fa2ae3f59eee61c4465f213c30527d8e6/Screenshots/Settings.png -------------------------------------------------------------------------------- /Screenshots/Szs-loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuryBaguette/SwitchLayoutEditor/139adf8fa2ae3f59eee61c4465f213c30527d8e6/Screenshots/Szs-loading.png -------------------------------------------------------------------------------- /Screenshots/SzsEditor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuryBaguette/SwitchLayoutEditor/139adf8fa2ae3f59eee61c4465f213c30527d8e6/Screenshots/SzsEditor.png -------------------------------------------------------------------------------- /SwitchLayoutEditor.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29020.237 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BflytPreview", "BflytPreview\BflytPreview.csproj", "{D59C0348-7D8E-46DF-8761-1CA9C5FF5556}" 7 | EndProject 8 | Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "SwitchThemesCommon", "..\SwitchThemeInjector\SwitchThemesCommon\SwitchThemesCommon.shproj", "{11174F92-402D-4064-B278-F52842A48251}" 9 | EndProject 10 | Global 11 | GlobalSection(SharedMSBuildProjectFiles) = preSolution 12 | ..\SwitchThemeInjector\SwitchThemesCommon\SwitchThemesCommon.projitems*{11174f92-402d-4064-b278-f52842a48251}*SharedItemsImports = 13 13 | ..\SwitchThemeInjector\SwitchThemesCommon\SwitchThemesCommon.projitems*{d59c0348-7d8e-46df-8761-1ca9c5ff5556}*SharedItemsImports = 4 14 | EndGlobalSection 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {D59C0348-7D8E-46DF-8761-1CA9C5FF5556}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {D59C0348-7D8E-46DF-8761-1CA9C5FF5556}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {D59C0348-7D8E-46DF-8761-1CA9C5FF5556}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {D59C0348-7D8E-46DF-8761-1CA9C5FF5556}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {69ED960A-80B0-4EEB-B308-2DD5CC30E367} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /docs/EditorAutoUpdate.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.0.1.0 4 | https://github.com/FuryBaguette/SwitchLayoutEditor/releases/download/v1.0.0-beta5/Release.zip 5 | 6 | https://git.io/fjZv0 7 | - Animations editor (.bflan files) 8 | - Group (grp panes) editing for bflyt files 9 | - Fix for a some crashes and some minor improvements 10 | 11 | false 12 | 13 | -------------------------------------------------------------------------------- /dragdroptree.txt: -------------------------------------------------------------------------------- 1 | treeView1.AllowDrop = true; 2 | treeView1.ItemDrag += new ItemDragEventHandler(treeView1_ItemDrag); 3 | treeView1.DragEnter += new DragEventHandler(treeView1_DragEnter); 4 | treeView1.DragOver += new DragEventHandler(treeView1_DragOver); 5 | treeView1.DragDrop += new DragEventHandler(treeView1_DragDrop); 6 | 7 | #region Drag tree node 8 | private void treeView1_ItemDrag(object sender, ItemDragEventArgs e) 9 | { 10 | if (e.Button == MouseButtons.Left) 11 | { 12 | DoDragDrop(e.Item, DragDropEffects.Move); 13 | } 14 | 15 | else if (e.Button == MouseButtons.Right) 16 | { 17 | DoDragDrop(e.Item, DragDropEffects.Copy); 18 | } 19 | } 20 | 21 | private void treeView1_DragEnter(object sender, DragEventArgs e) 22 | { 23 | e.Effect = e.AllowedEffect; 24 | } 25 | 26 | private void treeView1_DragOver(object sender, DragEventArgs e) 27 | { 28 | Point targetPoint = treeView1.PointToClient(new Point(e.X, e.Y)); 29 | treeView1.SelectedNode = treeView1.GetNodeAt(targetPoint); 30 | } 31 | 32 | private void treeView1_DragDrop(object sender, DragEventArgs e) 33 | { 34 | Point targetPoint = treeView1.PointToClient(new Point(e.X, e.Y)); 35 | TreeNode targetNode = treeView1.GetNodeAt(targetPoint); 36 | TreeNode draggedNode = (TreeNode)e.Data.GetData(typeof(TreeNode)); 37 | 38 | if (!draggedNode.Equals(targetNode) && !ContainsNode(draggedNode, targetNode)) 39 | { 40 | if (e.Effect == DragDropEffects.Move) 41 | { 42 | draggedNode.Remove(); 43 | targetNode.Nodes.Add(draggedNode); 44 | } 45 | 46 | else if (e.Effect == DragDropEffects.Copy) 47 | { 48 | targetNode.Nodes.Add((TreeNode)draggedNode.Clone()); 49 | } 50 | 51 | targetNode.Expand(); 52 | } 53 | } 54 | 55 | private bool ContainsNode(TreeNode node1, TreeNode node2) 56 | { 57 | if (node2.Parent == null) return false; 58 | if (node2.Parent.Equals(node1)) return true; 59 | 60 | return ContainsNode(node1, node2.Parent); 61 | } 62 | #endregion --------------------------------------------------------------------------------