mirror of
https://github.com/4sval/FModel.git
synced 2026-09-14 04:26:40 -05:00
added tab extra title
This commit is contained in:
@@ -6,14 +6,14 @@ using ICSharpCode.AvalonEdit.Document;
|
|||||||
|
|
||||||
namespace FModel.Extensions;
|
namespace FModel.Extensions;
|
||||||
|
|
||||||
public static class StringExtensions
|
public static partial class StringExtensions
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static string GetReadableSize(double size)
|
public static string GetReadableSize(double size)
|
||||||
{
|
{
|
||||||
if (size == 0) return "0 B";
|
if (size == 0) return "0 B";
|
||||||
|
|
||||||
string[] sizes = { "B", "KB", "MB", "GB", "TB" };
|
string[] sizes = ["B", "KB", "MB", "GB", "TB"];
|
||||||
var order = 0;
|
var order = 0;
|
||||||
while (size >= 1024 && order < sizes.Length - 1)
|
while (size >= 1024 && order < sizes.Length - 1)
|
||||||
{
|
{
|
||||||
@@ -27,21 +27,22 @@ public static class StringExtensions
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int GetNameLineNumber(this string s, string lineToFind)
|
public static int GetNameLineNumber(this string s, string lineToFind)
|
||||||
{
|
{
|
||||||
|
if (KismetRegex().IsMatch(lineToFind))
|
||||||
|
return s.GetKismetLineNumber(lineToFind);
|
||||||
if (int.TryParse(lineToFind, out var index))
|
if (int.TryParse(lineToFind, out var index))
|
||||||
return s.GetLineNumber(index);
|
return s.GetLineNumber(index);
|
||||||
|
|
||||||
lineToFind = $" \"Name\": \"{lineToFind}\",";
|
lineToFind = $" \"Name\": \"{lineToFind}\",";
|
||||||
using var reader = new StringReader(s);
|
using var reader = new StringReader(s);
|
||||||
var lineNum = 0;
|
var lineNum = 0;
|
||||||
string line;
|
while (reader.ReadLine() is { } line)
|
||||||
while ((line = reader.ReadLine()) != null)
|
|
||||||
{
|
{
|
||||||
lineNum++;
|
lineNum++;
|
||||||
if (line.Equals(lineToFind, StringComparison.OrdinalIgnoreCase))
|
if (line.Equals(lineToFind, StringComparison.OrdinalIgnoreCase))
|
||||||
return lineNum;
|
return lineNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@@ -64,18 +65,17 @@ public static class StringExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int GetKismetLineNumber(this string s, string input)
|
private static int GetKismetLineNumber(this string s, string input)
|
||||||
{
|
{
|
||||||
var match = Regex.Match(input, @"^(.+)\[(\d+)\]$");
|
var match = KismetRegex().Match(input);
|
||||||
var name = match.Groups[1].Value;
|
var name = match.Groups[1].Value;
|
||||||
int index = int.Parse(match.Groups[2].Value);
|
int index = int.Parse(match.Groups[2].Value);
|
||||||
var lineToFind = $" \"Name\": \"{name}\",";
|
var lineToFind = $" \"Name\": \"{name}\",";
|
||||||
var offset = $"\"StatementIndex\": {index}";
|
var offset = $"\"StatementIndex\": {index}";
|
||||||
using var reader = new StringReader(s);
|
using var reader = new StringReader(s);
|
||||||
var lineNum = 0;
|
var lineNum = 0;
|
||||||
string line;
|
|
||||||
|
|
||||||
while ((line = reader.ReadLine()) != null)
|
while (reader.ReadLine() is { } line)
|
||||||
{
|
{
|
||||||
lineNum++;
|
lineNum++;
|
||||||
if (line.Equals(lineToFind, StringComparison.OrdinalIgnoreCase))
|
if (line.Equals(lineToFind, StringComparison.OrdinalIgnoreCase))
|
||||||
@@ -91,7 +91,7 @@ public static class StringExtensions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@@ -99,8 +99,7 @@ public static class StringExtensions
|
|||||||
{
|
{
|
||||||
using var reader = new StringReader(s);
|
using var reader = new StringReader(s);
|
||||||
var lineNum = 0;
|
var lineNum = 0;
|
||||||
string line;
|
while (reader.ReadLine() is { } line)
|
||||||
while ((line = reader.ReadLine()) != null)
|
|
||||||
{
|
{
|
||||||
lineNum++;
|
lineNum++;
|
||||||
if (line.Equals(" {"))
|
if (line.Equals(" {"))
|
||||||
@@ -110,6 +109,9 @@ public static class StringExtensions
|
|||||||
return lineNum + 1;
|
return lineNum + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[GeneratedRegex(@"^(.+)\[(\d+)\]$", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)]
|
||||||
|
private static partial Regex KismetRegex();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -907,7 +907,10 @@ public class CUE4ParseViewModel : ViewModel
|
|||||||
{
|
{
|
||||||
var package = Provider.LoadPackage(entry);
|
var package = Provider.LoadPackage(entry);
|
||||||
|
|
||||||
TabControl.AddTab($"{entry.Name} (Metadata)");
|
if (TabControl.CanAddTabs) TabControl.AddTab(entry);
|
||||||
|
else TabControl.SelectedTab.SoftReset(entry);
|
||||||
|
|
||||||
|
TabControl.SelectedTab.TitleExtra = "Metadata";
|
||||||
TabControl.SelectedTab.Highlighter = AvalonExtensions.HighlighterSelector("");
|
TabControl.SelectedTab.Highlighter = AvalonExtensions.HighlighterSelector("");
|
||||||
|
|
||||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(package, Formatting.Indented), false, false);
|
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(package, Formatting.Indented), false, false);
|
||||||
|
|||||||
@@ -14,34 +14,34 @@ public class ImageCommand : ViewModelCommand<TabItem>
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Execute(TabItem contextViewModel, object parameter)
|
public override void Execute(TabItem tabViewModel, object parameter)
|
||||||
{
|
{
|
||||||
if (parameter == null || !contextViewModel.HasImage) return;
|
if (parameter == null || !tabViewModel.HasImage) return;
|
||||||
|
|
||||||
switch (parameter)
|
switch (parameter)
|
||||||
{
|
{
|
||||||
case "Open":
|
case "Open":
|
||||||
{
|
{
|
||||||
Helper.OpenWindow<AdonisWindow>(contextViewModel.SelectedImage.ExportName + " (Image)", () =>
|
Helper.OpenWindow<AdonisWindow>(tabViewModel.SelectedImage.ExportName + " (Image)", () =>
|
||||||
{
|
{
|
||||||
var popout = new ImagePopout
|
var popout = new ImagePopout
|
||||||
{
|
{
|
||||||
Title = contextViewModel.SelectedImage.ExportName + " (Image)",
|
Title = tabViewModel.SelectedImage.ExportName + " (Image)",
|
||||||
Width = contextViewModel.SelectedImage.Image.Width,
|
Width = tabViewModel.SelectedImage.Image.Width,
|
||||||
Height = contextViewModel.SelectedImage.Image.Height,
|
Height = tabViewModel.SelectedImage.Image.Height,
|
||||||
WindowState = contextViewModel.SelectedImage.Image.Height > 1000 ? WindowState.Maximized : WindowState.Normal,
|
WindowState = tabViewModel.SelectedImage.Image.Height > 1000 ? WindowState.Maximized : WindowState.Normal,
|
||||||
ImageCtrl = { Source = contextViewModel.SelectedImage.Image }
|
ImageCtrl = { Source = tabViewModel.SelectedImage.Image }
|
||||||
};
|
};
|
||||||
RenderOptions.SetBitmapScalingMode(popout.ImageCtrl, BoolToRenderModeConverter.Instance.Convert(contextViewModel.SelectedImage.RenderNearestNeighbor));
|
RenderOptions.SetBitmapScalingMode(popout.ImageCtrl, BoolToRenderModeConverter.Instance.Convert(tabViewModel.SelectedImage.RenderNearestNeighbor));
|
||||||
popout.Show();
|
popout.Show();
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "Copy":
|
case "Copy":
|
||||||
ClipboardExtensions.SetImage(contextViewModel.SelectedImage.ImageBuffer, $"{contextViewModel.SelectedImage.ExportName}.png");
|
ClipboardExtensions.SetImage(tabViewModel.SelectedImage.ImageBuffer, $"{tabViewModel.SelectedImage.ExportName}.png");
|
||||||
break;
|
break;
|
||||||
case "Save":
|
case "Save":
|
||||||
contextViewModel.SaveImage();
|
tabViewModel.SaveImage();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public class TabCommand : ViewModelCommand<TabItem>
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async void Execute(TabItem contextViewModel, object parameter)
|
public override async void Execute(TabItem tabViewModel, object parameter)
|
||||||
{
|
{
|
||||||
switch (parameter)
|
switch (parameter)
|
||||||
{
|
{
|
||||||
@@ -23,53 +23,53 @@ public class TabCommand : ViewModelCommand<TabItem>
|
|||||||
_applicationView.CUE4Parse.TabControl.RemoveTab(mdlClick);
|
_applicationView.CUE4Parse.TabControl.RemoveTab(mdlClick);
|
||||||
break;
|
break;
|
||||||
case "Close_Tab":
|
case "Close_Tab":
|
||||||
_applicationView.CUE4Parse.TabControl.RemoveTab(contextViewModel);
|
_applicationView.CUE4Parse.TabControl.RemoveTab(tabViewModel);
|
||||||
break;
|
break;
|
||||||
case "Close_All_Tabs":
|
case "Close_All_Tabs":
|
||||||
_applicationView.CUE4Parse.TabControl.RemoveAllTabs();
|
_applicationView.CUE4Parse.TabControl.RemoveAllTabs();
|
||||||
break;
|
break;
|
||||||
case "Close_Other_Tabs":
|
case "Close_Other_Tabs":
|
||||||
_applicationView.CUE4Parse.TabControl.RemoveOtherTabs(contextViewModel);
|
_applicationView.CUE4Parse.TabControl.RemoveOtherTabs(tabViewModel);
|
||||||
break;
|
break;
|
||||||
case "Asset_Export_Data":
|
case "Asset_Export_Data":
|
||||||
await _threadWorkerView.Begin(_ => _applicationView.CUE4Parse.ExportData(contextViewModel.Entry));
|
await _threadWorkerView.Begin(_ => _applicationView.CUE4Parse.ExportData(tabViewModel.Entry));
|
||||||
break;
|
break;
|
||||||
case "Asset_Save_Properties":
|
case "Asset_Save_Properties":
|
||||||
await _threadWorkerView.Begin(cancellationToken =>
|
await _threadWorkerView.Begin(cancellationToken =>
|
||||||
{
|
{
|
||||||
_applicationView.CUE4Parse.Extract(cancellationToken, contextViewModel.Entry, false, EBulkType.Properties);
|
_applicationView.CUE4Parse.Extract(cancellationToken, tabViewModel.Entry, false, EBulkType.Properties);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "Asset_Save_Textures":
|
case "Asset_Save_Textures":
|
||||||
await _threadWorkerView.Begin(cancellationToken =>
|
await _threadWorkerView.Begin(cancellationToken =>
|
||||||
{
|
{
|
||||||
_applicationView.CUE4Parse.Extract(cancellationToken, contextViewModel.Entry, false, EBulkType.Textures);
|
_applicationView.CUE4Parse.Extract(cancellationToken, tabViewModel.Entry, false, EBulkType.Textures);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "Asset_Save_Models":
|
case "Asset_Save_Models":
|
||||||
await _threadWorkerView.Begin(cancellationToken =>
|
await _threadWorkerView.Begin(cancellationToken =>
|
||||||
{
|
{
|
||||||
_applicationView.CUE4Parse.Extract(cancellationToken, contextViewModel.Entry, false, EBulkType.Meshes);
|
_applicationView.CUE4Parse.Extract(cancellationToken, tabViewModel.Entry, false, EBulkType.Meshes);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "Asset_Save_Animations":
|
case "Asset_Save_Animations":
|
||||||
await _threadWorkerView.Begin(cancellationToken =>
|
await _threadWorkerView.Begin(cancellationToken =>
|
||||||
{
|
{
|
||||||
_applicationView.CUE4Parse.Extract(cancellationToken, contextViewModel.Entry, false, EBulkType.Animations);
|
_applicationView.CUE4Parse.Extract(cancellationToken, tabViewModel.Entry, false, EBulkType.Animations);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "Open_Properties":
|
case "Open_Properties":
|
||||||
if (contextViewModel.Entry.Name == "New Tab" || contextViewModel.Document == null) return;
|
if (tabViewModel.Header == "New Tab" || tabViewModel.Document == null) return;
|
||||||
Helper.OpenWindow<AdonisWindow>(contextViewModel.Entry.Name + " (Properties)", () =>
|
Helper.OpenWindow<AdonisWindow>(tabViewModel.Header + " (Properties)", () =>
|
||||||
{
|
{
|
||||||
new PropertiesPopout(contextViewModel)
|
new PropertiesPopout(tabViewModel)
|
||||||
{
|
{
|
||||||
Title = contextViewModel.Entry.Name + " (Properties)"
|
Title = tabViewModel.Header + " (Properties)"
|
||||||
}.Show();
|
}.Show();
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "Copy_Asset_Path":
|
case "Copy_Asset_Path":
|
||||||
Clipboard.SetText(contextViewModel.Entry.Path);
|
Clipboard.SetText(tabViewModel.Entry.Path);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,7 +97,22 @@ public class TabItem : ViewModel
|
|||||||
public GameFile Entry
|
public GameFile Entry
|
||||||
{
|
{
|
||||||
get => _entry;
|
get => _entry;
|
||||||
set => SetProperty(ref _entry, value);
|
set
|
||||||
|
{
|
||||||
|
SetProperty(ref _entry, value);
|
||||||
|
RaisePropertyChanged(nameof(Header));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _titleExtra;
|
||||||
|
public string TitleExtra
|
||||||
|
{
|
||||||
|
get => _titleExtra;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetProperty(ref _titleExtra, value);
|
||||||
|
RaisePropertyChanged(nameof(Header));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool _hasSearchOpen;
|
private bool _hasSearchOpen;
|
||||||
@@ -194,6 +209,8 @@ public class TabItem : ViewModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string Header => $"{Entry.Name}{(string.IsNullOrEmpty(TitleExtra) ? "" : $" ({TitleExtra})")}";
|
||||||
|
|
||||||
public bool HasImage => SelectedImage != null;
|
public bool HasImage => SelectedImage != null;
|
||||||
public bool HasMultipleImages => _images.Count > 1;
|
public bool HasMultipleImages => _images.Count > 1;
|
||||||
public string Page => $"{_images.IndexOf(_selectedImage) + 1} / {_images.Count}";
|
public string Page => $"{_images.IndexOf(_selectedImage) + 1} / {_images.Count}";
|
||||||
@@ -219,6 +236,7 @@ public class TabItem : ViewModel
|
|||||||
public void SoftReset(GameFile entry)
|
public void SoftReset(GameFile entry)
|
||||||
{
|
{
|
||||||
Entry = entry;
|
Entry = entry;
|
||||||
|
TitleExtra = string.Empty;
|
||||||
ParentExportType = string.Empty;
|
ParentExportType = string.Empty;
|
||||||
ScrollTrigger = null;
|
ScrollTrigger = null;
|
||||||
Application.Current.Dispatcher.Invoke(() =>
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
@@ -389,7 +407,7 @@ public class TabControlViewModel : ViewModel
|
|||||||
public void AddTab(string title) => AddTab(new FakeGameFile(title));
|
public void AddTab(string title) => AddTab(new FakeGameFile(title));
|
||||||
public void AddTab(GameFile entry, string parentExportType = null)
|
public void AddTab(GameFile entry, string parentExportType = null)
|
||||||
{
|
{
|
||||||
if (SelectedTab?.Entry.Name == "New Tab")
|
if (SelectedTab?.Header == "New Tab")
|
||||||
{
|
{
|
||||||
SelectedTab.Entry = entry;
|
SelectedTab.Entry = entry;
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -76,28 +76,18 @@ public class GamePathVisualLineText : VisualLineText
|
|||||||
if (a.ParentVisualLine.Document.FileName.Equals(fullPath.SubstringBeforeLast('.'), StringComparison.OrdinalIgnoreCase) &&
|
if (a.ParentVisualLine.Document.FileName.Equals(fullPath.SubstringBeforeLast('.'), StringComparison.OrdinalIgnoreCase) &&
|
||||||
!a.ParentVisualLine.Document.GetText(firstLine.Offset, firstLine.Length).Equals(" \"Summary\": {")) // Show Metadata case
|
!a.ParentVisualLine.Document.GetText(firstLine.Offset, firstLine.Length).Equals(" \"Summary\": {")) // Show Metadata case
|
||||||
{
|
{
|
||||||
int lineNumber;
|
var lineNumber = a.ParentVisualLine.Document.Text.GetNameLineNumber(obj);
|
||||||
DocumentLine line;
|
if (lineNumber > -1)
|
||||||
|
|
||||||
if (Regex.IsMatch(obj, @"^(.+)\[(\d+)\]$"))
|
|
||||||
{
|
{
|
||||||
lineNumber = a.ParentVisualLine.Document.Text.GetKismetLineNumber(obj);
|
var line = a.ParentVisualLine.Document.GetLineByNumber(lineNumber);
|
||||||
line = a.ParentVisualLine.Document.GetLineByNumber(lineNumber);
|
AvalonEditor.YesWeEditor.Select(line.Offset, line.Length);
|
||||||
}
|
AvalonEditor.YesWeEditor.ScrollToLine(lineNumber);
|
||||||
else
|
return;
|
||||||
{
|
|
||||||
lineNumber = a.ParentVisualLine.Document.Text.GetNameLineNumber(obj);
|
|
||||||
line = a.ParentVisualLine.Document.GetLineByNumber(lineNumber);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AvalonEditor.YesWeEditor.Select(line.Offset, line.Length);
|
await _threadWorkerView.Begin(cancellationToken =>
|
||||||
AvalonEditor.YesWeEditor.ScrollToLine(lineNumber);
|
_applicationView.CUE4Parse.ExtractAndScroll(cancellationToken, fullPath, obj, parentExportType));
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await _threadWorkerView.Begin(cancellationToken =>
|
|
||||||
_applicationView.CUE4Parse.ExtractAndScroll(cancellationToken, fullPath, obj, parentExportType));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,6 +127,8 @@ public partial class AvalonEditor
|
|||||||
if (!tabItem.ShouldScroll) return;
|
if (!tabItem.ShouldScroll) return;
|
||||||
|
|
||||||
var lineNumber = avalonEditor.Document.Text.GetNameLineNumber(tabItem.ScrollTrigger);
|
var lineNumber = avalonEditor.Document.Text.GetNameLineNumber(tabItem.ScrollTrigger);
|
||||||
|
if (lineNumber == -1) lineNumber = 1;
|
||||||
|
|
||||||
var line = avalonEditor.Document.GetLineByNumber(lineNumber);
|
var line = avalonEditor.Document.GetLineByNumber(lineNumber);
|
||||||
avalonEditor.Select(line.Offset, line.Length);
|
avalonEditor.Select(line.Offset, line.Length);
|
||||||
avalonEditor.ScrollToLine(lineNumber);
|
avalonEditor.ScrollToLine(lineNumber);
|
||||||
|
|||||||
@@ -651,7 +651,7 @@
|
|||||||
<MouseBinding MouseAction="MiddleClick" Command="{Binding SelectedItem.TabCommand, ElementName=TabControlName}" CommandParameter="{Binding}" />
|
<MouseBinding MouseAction="MiddleClick" Command="{Binding SelectedItem.TabCommand, ElementName=TabControlName}" CommandParameter="{Binding}" />
|
||||||
</DockPanel.InputBindings>
|
</DockPanel.InputBindings>
|
||||||
|
|
||||||
<TextBlock DockPanel.Dock="Left" Text="{Binding Entry.Name}" TextTrimming="CharacterEllipsis" ToolTip="{Binding Entry.Name}">
|
<TextBlock DockPanel.Dock="Left" Text="{Binding Header}" TextTrimming="CharacterEllipsis" ToolTip="{Binding Text, RelativeSource={RelativeSource Self}}">
|
||||||
<TextBlock.Width>
|
<TextBlock.Width>
|
||||||
<MultiBinding Converter="{x:Static converters:TabSizeConverter.Instance}" ConverterParameter="6">
|
<MultiBinding Converter="{x:Static converters:TabSizeConverter.Instance}" ConverterParameter="6">
|
||||||
<Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type TabControl}}" />
|
<Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type TabControl}}" />
|
||||||
|
|||||||
Reference in New Issue
Block a user