GUI: Implement all exports

This commit is contained in:
Katy Coe
2020-02-10 06:37:16 +01:00
parent 0ccae3fe50
commit 6afdd2c41c
2 changed files with 172 additions and 13 deletions

View File

@@ -183,6 +183,8 @@
<!-- Output configuration -->
<DockPanel Name="pnlOutputSettings" Grid.Row="0" Grid.Column="2" Grid.RowSpan="2">
<!-- Show preferences only when an image is selected -->
<DockPanel.Style>
<Style>
<Setter Property="DockPanel.Visibility" Value="Visible"/>
@@ -195,7 +197,17 @@
</DockPanel.Style>
<!-- Export button -->
<Button Name="btnExport" DockPanel.Dock="Bottom" Margin="2" HorizontalAlignment="Right" VerticalAlignment="Bottom" Style="{StaticResource LightBoxButton}" FontSize="18" Width="120">Export</Button>
<Button Name="btnExport" Click="BtnExport_OnClick" DockPanel.Dock="Bottom" Margin="2" HorizontalAlignment="Right" VerticalAlignment="Bottom" FontSize="18" Width="120" Content="Export">
<Button.Style>
<Style BasedOn="{StaticResource LightBoxButton}" TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=areaBusyIndicator, Path=Visibility}" Value="Visible">
<Setter Property="Button.IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
<DockPanel DockPanel.Dock="Top">
<!-- List of namespaces to export -->
@@ -240,7 +252,7 @@
</StackPanel>
</GroupBox>
<CheckBox Margin="2" Content="Don't nest folders (flatten hierarchy)">
<CheckBox Name="cbFlattenHierarchy" Margin="2" Content="Don't nest folders (flatten hierarchy)">
<CheckBox.Style>
<Style>
<Style.Triggers>
@@ -274,13 +286,13 @@
</Style>
</GroupBox.Style>
<StackPanel>
<RadioButton IsChecked="True">Alphabetical</RadioButton>
<RadioButton>Type definition index</RadioButton>
<RadioButton Name="rdoSortName" IsChecked="True">Alphabetical</RadioButton>
<RadioButton Name="rdoSortIndex">Type definition index</RadioButton>
</StackPanel>
</GroupBox>
<CheckBox Margin="2">Suppress pointer, offset and index metadata comments</CheckBox>
<CheckBox Margin="2" Content="Attempt to generate output that compiles">
<CheckBox Name="cbSuppressMetadata" Margin="2">Suppress pointer, offset and index metadata comments</CheckBox>
<CheckBox Name="cbMustCompile" Margin="2" Content="Attempt to generate output that compiles">
<CheckBox.Style>
<Style>
<Style.Triggers>
@@ -293,7 +305,7 @@
</CheckBox.Style>
</CheckBox>
<CheckBox Margin="2" Content="Place assembly-level attributes in separate files">
<CheckBox Name="cbSeparateAttributes" Margin="2" Content="Place assembly-level attributes in separate files">
<CheckBox.Style>
<Style>
<Setter Property="CheckBox.IsChecked" Value="True"/>

View File

@@ -23,6 +23,7 @@ using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Win32;
using Il2CppInspector;
using Il2CppInspector.Outputs;
using Il2CppInspector.Reflection;
using Ookii.Dialogs.Wpf;
using Path = System.IO.Path;
@@ -194,9 +195,7 @@ namespace Il2CppInspectorGUI
openFolderDialog.UseDescriptionForTitle = true;
while (openFolderDialog.ShowDialog() == true) {
if (!File.Exists(openFolderDialog.SelectedPath + @"\Editor\Data\Managed\UnityEditor.dll"))
MessageBox.Show(this, "Could not find Unity installation in this folder. Ensure the 'Editor' folder is a child of the selected folder and try again.", "Unity installation not found", MessageBoxButton.OK, MessageBoxImage.Error);
else {
if (ValidateUnityPath(openFolderDialog.SelectedPath)) {
txtUnityPath.Text = openFolderDialog.SelectedPath;
break;
}
@@ -215,14 +214,160 @@ namespace Il2CppInspectorGUI
openFolderDialog.UseDescriptionForTitle = true;
while (openFolderDialog.ShowDialog() == true) {
if (!File.Exists(openFolderDialog.SelectedPath + @"\UnityEngine.UI.dll"))
MessageBox.Show(this, "Could not find Unity assemblies in this folder. Ensure the selected folder contains UnityEngine.UI.dll and try again.", "Unity assemblies not found", MessageBoxButton.OK, MessageBoxImage.Error);
else {
if (ValidateUnityAssembliesPath(openFolderDialog.SelectedPath)) {
txtUnityScriptPath.Text = openFolderDialog.SelectedPath;
break;
}
}
}
private bool ValidateUnityPath(string path) {
if (File.Exists(path + @"\Editor\Data\Managed\UnityEditor.dll"))
return true;
MessageBox.Show(this, "Could not find Unity installation in this folder. Ensure the 'Editor' folder is a child of the selected folder and try again.", "Unity installation not found", MessageBoxButton.OK, MessageBoxImage.Error);
return false;
}
private bool ValidateUnityAssembliesPath(string path) {
if (File.Exists(path + @"\UnityEngine.UI.dll"))
return true;
MessageBox.Show(this, "Could not find Unity assemblies in this folder. Ensure the selected folder contains UnityEngine.UI.dll and try again.", "Unity assemblies not found", MessageBoxButton.OK, MessageBoxImage.Error);
return false;
}
/// <summary>
/// Perform export
/// </summary>
private void BtnExport_OnClick(object sender, RoutedEventArgs e) {
var app = (App) Application.Current;
var model = (Il2CppModel) lstImages.SelectedItem;
var unityPath = txtUnityPath.Text;
var unityAssembliesPath = txtUnityScriptPath.Text;
var sortOrder = rdoSortIndex.IsChecked == true ? "index" :
rdoSortName.IsChecked == true ? "name" :
"unknown";
var layout = rdoLayoutSingle.IsChecked == true? "single" :
rdoLayoutAssembly.IsChecked == true? "assembly" :
rdoLayoutNamespace.IsChecked == true? "namespace" :
rdoLayoutClass.IsChecked == true? "class" :
rdoLayoutTree.IsChecked == true? "tree" :
"unknown";
switch (this) {
// C# prototypes and Visual Studio solution
case { rdoOutputCSharp: var r, rdoOutputSolution: var s } when r.IsChecked == true || s.IsChecked == true:
var createSolution = rdoOutputSolution.IsChecked == true;
if (createSolution) {
if (!ValidateUnityPath(unityPath))
return;
if (!ValidateUnityAssembliesPath(unityAssembliesPath))
return;
}
// Get options
var excludedNamespaces = constructExcludedNamespaces((IEnumerable<CheckboxNode>) trvNamespaces.ItemsSource);
var writer = new CSharpCodeStubs(model) {
ExcludedNamespaces = excludedNamespaces.ToList(),
SuppressMetadata = cbSuppressMetadata.IsChecked == true,
MustCompile = cbMustCompile.IsChecked == true
};
var flattenHierarchy = cbFlattenHierarchy.IsChecked == true;
var separateAssemblyAttributesFiles = cbSeparateAttributes.IsChecked == true;
// Determine if we need a filename or a folder - file for single file, folder for everything else
var needsFolder = rdoOutputCSharp.IsChecked == false || rdoLayoutSingle.IsChecked == false;
var saveFolderDialog = new VistaFolderBrowserDialog {
Description = "Select save location",
UseDescriptionForTitle = true
};
var saveFileDialog = new SaveFileDialog {
Filter = "C# source files (*.cs)|*.cs|All files (*.*)|*.*",
CheckFileExists = false,
OverwritePrompt = true
};
if (needsFolder && saveFolderDialog.ShowDialog() == false)
return;
if (!needsFolder && saveFileDialog.ShowDialog() == false)
return;
var outPath = needsFolder ? saveFolderDialog.SelectedPath : saveFileDialog.FileName;
if (createSolution)
writer.WriteSolution(outPath, unityPath, unityAssembliesPath);
else
switch (layout, sortOrder) {
case ("single", "index"):
writer.WriteSingleFile(outPath, t => t.Index);
break;
case ("single", "name"):
writer.WriteSingleFile(outPath, t => t.Name);
break;
case ("namespace", "index"):
writer.WriteFilesByNamespace(outPath, t => t.Index, flattenHierarchy);
break;
case ("namespace", "name"):
writer.WriteFilesByNamespace(outPath, t => t.Name, flattenHierarchy);
break;
case ("assembly", "index"):
writer.WriteFilesByAssembly(outPath, t => t.Index, separateAssemblyAttributesFiles);
break;
case ("assembly", "name"):
writer.WriteFilesByAssembly(outPath, t => t.Name, separateAssemblyAttributesFiles);
break;
case ("class", _):
writer.WriteFilesByClass(outPath, flattenHierarchy);
break;
case ("tree", _):
writer.WriteFilesByClassTree(outPath, separateAssemblyAttributesFiles);
break;
}
break;
// IDA Python script
case { rdoOutputIDA: var r } when r.IsChecked == true:
var scriptSaveFileDialog = new SaveFileDialog {
Filter = "Python scripts (*.py)|*.py|All files (*.*)|*.*",
CheckFileExists = false,
OverwritePrompt = true
};
if (scriptSaveFileDialog.ShowDialog() == false)
return;
var outFile = scriptSaveFileDialog.FileName;
var idaWriter = new IDAPythonScript(model);
idaWriter.WriteScriptToFile(outFile);
break;
}
}
private IEnumerable<string> constructExcludedNamespaces(IEnumerable<CheckboxNode> nodes) {
var ns = new List<string>();
foreach (var node in nodes) {
if (node.IsChecked == false)
ns.Add(node.FullName);
else if (node.Children != null)
ns.AddRange(constructExcludedNamespaces(node.Children));
}
return ns;
}
}
// Replacement for TreeViewItem that includes checkbox state
@@ -242,6 +387,8 @@ namespace Il2CppInspectorGUI
}
}
public string FullName => (parent != null ? parent.FullName + "." : "") + Name;
public IEnumerable<CheckboxNode> Children {
get => children;
set {