From 4539c393099460ee67ff5de41fce0ffe64560dce Mon Sep 17 00:00:00 2001 From: usagirei Date: Sat, 27 May 2017 19:54:03 -0300 Subject: [PATCH] * Edge Bleeding on Non POT Images * Import/Export Color/Flags Metadata File (Text) * Allow Changing Default Theme (default_body_lz.bin on Root) * Fade-Out Non-Provided Image Drop-Zones --- SharedAssemblyInfo.cs | 6 +- ThemeEditor.Common/Graphics/RawTexture.cs | 92 ++++++++-- ThemeEditor.WPF/Effects/FxBin/WarpEffect.ps | Bin 1396 -> 1396 bytes ThemeEditor.WPF/Extensions.cs | 122 ++++++++++++- ThemeEditor.WPF/MainWindow.Images.cs | 123 +++++++------ ThemeEditor.WPF/MainWindow.Themes.cs | 168 +++++++++++++++++- ThemeEditor.WPF/MainWindow.xaml | 29 ++- ThemeEditor.WPF/Themes/TextureViewModel.cs | 6 + .../Themes/ThemeViewModel.Rules.cs | 2 +- 9 files changed, 448 insertions(+), 100 deletions(-) diff --git a/SharedAssemblyInfo.cs b/SharedAssemblyInfo.cs index 9493d72..9d35478 100644 --- a/SharedAssemblyInfo.cs +++ b/SharedAssemblyInfo.cs @@ -12,7 +12,7 @@ // [assembly: AssemblyVersion("1.0.*")] // Shared (File) Version -[assembly: AssemblyFileVersion("1.0.11.0")] +[assembly: AssemblyFileVersion("1.0.12.0")] [assembly: AssemblyCompany("Usagirei")] [assembly: AssemblyCopyright("Copyright © Usagirei 2016-2017")] [assembly: AssemblyCulture("")] @@ -25,10 +25,10 @@ // ThemeEditor.Common #if COMMON -[assembly: AssemblyVersion("1.0.11.0")] +[assembly: AssemblyVersion("1.0.12.0")] #endif // ThemeEditor.WPF #if WPF_EDITOR -[assembly: AssemblyVersion("1.0.11.0")] +[assembly: AssemblyVersion("1.0.12.0")] #endif \ No newline at end of file diff --git a/ThemeEditor.Common/Graphics/RawTexture.cs b/ThemeEditor.Common/Graphics/RawTexture.cs index 125a01e..be4d810 100644 --- a/ThemeEditor.Common/Graphics/RawTexture.cs +++ b/ThemeEditor.Common/Graphics/RawTexture.cs @@ -27,7 +27,7 @@ public RawTexture(int width, int height, DataFormat format) { Width = width; Height = height; - var tgtSize = (int) format * width * height; + var tgtSize = (int)format * width * height; Format = format; Data = new byte[tgtSize]; } @@ -101,6 +101,7 @@ private static int GreatestCommonMultiple(int num, int mult) return gcm; } + private static int NextLargestPowerOfTwo(int x) { x--; @@ -132,7 +133,7 @@ public void Encode(byte[] bgrData, int width, int height, DataFormat format) { Width = width; Height = height; - var tgtSize = (int) format * width * height; + var tgtSize = (int)format * width * height; Format = format; Data = new byte[tgtSize]; } @@ -157,6 +158,59 @@ public void Encode(byte[] bgrData) } } + public void EdgeBleed(int x, int y, int sx, int sy) + { + byte[] bgrData = Decode(); + int eSize = 3; // BGR Data + + void EdgeBleedY(int r, int y0, int y1) + { + if (y0 > y1) + { + int t = y1; + y1 = y0; + y0 = t; + } + + int dSize = Width * 3; + byte[] line = new byte[dSize]; + Buffer.BlockCopy(bgrData, r * dSize, line, 0, dSize); + for (int i = y0; i <= y1; i++) + Buffer.BlockCopy(line, 0, bgrData, i * dSize, dSize); + } + + void EdgeBleedX(int r, int x0, int x1) + { + byte[] bd = bgrData; + int es = eSize; + int w = Width; + + if (x0 > x1) + { + int t = x1; + x1 = x0; + x0 = t; + } + + int dSize = Height * eSize; + byte[] line = new byte[dSize]; + for (int j = 0; j < Height; j++) + Buffer.BlockCopy(bd, (j * w + r) * es, line, j * es, es); + + for (int i = x0; i <= x1; i++) + for (int j = 0; j < Height; j++) + Buffer.BlockCopy(line, j * es, bd, (j * w + i) * es, es); + + } + + EdgeBleedX(x, 0, x); + EdgeBleedX(x + sx - 1, x + sx - 1, Width - 1); + EdgeBleedY(y, 0, y); + EdgeBleedY(y + sy - 1, y + sy - 1, Height - 1); + + Encode(bgrData); + } + public void Read(Stream s) { if (s.Length - s.Position < Data.Length) @@ -185,8 +239,8 @@ private byte[] Decode_A8() DecToCoord(i % 64, out x, out y); uint tile = i / 64; - x += (uint) (tile % p) * 8; - y += (uint) (tile / p) * 8; + x += (uint)(tile % p) * 8; + y += (uint)(tile / p) * 8; var idx = 3 * (y * Width + x); @@ -210,16 +264,16 @@ private byte[] Decode_Bgr565() { int px = (Data[i + 1] << 8 | Data[i]); - byte r = (byte) (((px >> 11) & 0x1f) << 3); // 5 - byte g = (byte) (((px >> 5) & 0x3f) << 2); // 6 - byte b = (byte) (((px >> 0) & 0x1f) << 3); // 5 + byte r = (byte)(((px >> 11) & 0x1f) << 3); // 5 + byte g = (byte)(((px >> 5) & 0x3f) << 2); // 6 + byte b = (byte)(((px >> 0) & 0x1f) << 3); // 5 uint x, y; DecToCoord(j % 64, out x, out y); uint tile = j / 64; - x += (uint) (tile % p) * 8; - y += (uint) (tile / p) * 8; + x += (uint)(tile % p) * 8; + y += (uint)(tile / p) * 8; var idx = 3 * (y * Width + x); @@ -249,8 +303,8 @@ private byte[] Decode_Bgr888() DecToCoord(j % 64, out x, out y); uint tile = j / 64; - x += (uint) (tile % p) * 8; - y += (uint) (tile / p) * 8; + x += (uint)(tile % p) * 8; + y += (uint)(tile / p) * 8; var idx = 3 * (y * Width + x); @@ -283,8 +337,8 @@ private void Encode_A8(byte[] bgrData) DecToCoord(i % 64, out x, out y); uint tile = i / 64; - x += (uint) (tile % p) * 8; - y += (uint) (tile / p) * 8; + x += (uint)(tile % p) * 8; + y += (uint)(tile / p) * 8; var idx = 3 * (y * Width + x); var g = gscData[idx + 0]; @@ -311,8 +365,8 @@ private void Encode_Rgb565(byte[] bgrData) DecToCoord(j % 64, out x, out y); uint tile = j / 64; - x += (uint) (tile % p) * 8; - y += (uint) (tile / p) * 8; + x += (uint)(tile % p) * 8; + y += (uint)(tile / p) * 8; var idx = 3 * (y * Width + x); @@ -322,8 +376,8 @@ private void Encode_Rgb565(byte[] bgrData) int px = (r << 11 | g << 5 | b) & 0xffff; - Data[k + 0] = (byte) (px >> 0 & 0xFF); - Data[k + 1] = (byte) (px >> 8 & 0xFF); + Data[k + 0] = (byte)(px >> 0 & 0xFF); + Data[k + 1] = (byte)(px >> 8 & 0xFF); } } @@ -342,8 +396,8 @@ private void Encode_Rgb888(byte[] bgrData) DecToCoord(j % 64, out x, out y); uint tile = j / 64; - x += (uint) (tile % p) * 8; - y += (uint) (tile / p) * 8; + x += (uint)(tile % p) * 8; + y += (uint)(tile / p) * 8; var idx = 3 * (y * Width + x); diff --git a/ThemeEditor.WPF/Effects/FxBin/WarpEffect.ps b/ThemeEditor.WPF/Effects/FxBin/WarpEffect.ps index 6b61f2afce1f34d5eda6102cb2a8cd18e9f568ae..13b39896be15543779ca1cf1c4a76b61fc981cb9 100644 GIT binary patch delta 696 zcmZWmJ5Iwu6rA-siETcSfC525foP+kpa@#-V2RuKe|@Y5Yu0d0l4y<;yR z^WHJK_Jk(@8Bkiud%|QEP+J5x;u-r~nA*6=cCP!bB;R2l*!sLe--d>OKw)nBLK1Ya z#8!#KO}v%dxpe_2wM3}<_Q$};MUw&bli{3?+Ws+68~0kx8XIas;ssn2Y zhM|tEX=Vr3G9PiNsI8!wM3q29LEhdb?8y+{Kupa9d&dmFg}>tXmOPDhJ-Yb@ D>W6$$ delta 696 zcmZWnJ8r^25PdsqjO~1ok|vUi6j53vh*HpU2TR<>%Ne-9(nY2r$4Hwq_z0wS-ppcx z6v>un-p;)DcE+dbR2_fZY&Bo5=BxMR{B5yV;IPZ&W3~o7FbhC`MA7dKQnv-OA!Gob z6jwm3(8O0_4r1rG=;Iw<2Z%!%O2%W4Lla25cjU==KJqZ|slPdvIJnYO|HFw+-t$2aSc<( zL%3nizh$e!0>wHrLo7VlG!$#BZ^Rt#&(o}FwAM-33RM`KkWLZg(ls#R?RU-O`4@XR Bg9-ou diff --git a/ThemeEditor.WPF/Extensions.cs b/ThemeEditor.WPF/Extensions.cs index b2d9fe7..fd1abd5 100644 --- a/ThemeEditor.WPF/Extensions.cs +++ b/ThemeEditor.WPF/Extensions.cs @@ -6,6 +6,8 @@ using System.Collections; using System.Collections.Generic; using System.Drawing; +using System.Globalization; +using System.Linq; using System.Reflection; using System.Resources; using System.Text.RegularExpressions; @@ -13,6 +15,7 @@ using System.Windows.Media; using System.Windows.Media.Imaging; using ThemeEditor.Common.Graphics; +using ThemeEditor.WPF.Themes; using Color = System.Windows.Media.Color; using PixelFormat = System.Drawing.Imaging.PixelFormat; @@ -151,10 +154,10 @@ public static Color Blend(this Color bg, Color fg, float factor) float newAlpha = alphaFg + alphaBg * (1 - alphaFg); - byte newR = (byte) ((preRfg + preRbg * (1 - alphaFg)) / newAlpha).Clamp(0, 255); - byte newG = (byte) ((preGfg + preGbg * (1 - alphaFg)) / newAlpha).Clamp(0, 255); - byte newB = (byte) ((preBfg + preBbg * (1 - alphaFg)) / newAlpha).Clamp(0, 255); - byte newA = (byte) (newAlpha * 255).Clamp(0, 255); + byte newR = (byte)((preRfg + preRbg * (1 - alphaFg)) / newAlpha).Clamp(0, 255); + byte newG = (byte)((preGfg + preGbg * (1 - alphaFg)) / newAlpha).Clamp(0, 255); + byte newB = (byte)((preBfg + preBbg * (1 - alphaFg)) / newAlpha).Clamp(0, 255); + byte newA = (byte)(newAlpha * 255).Clamp(0, 255); return Color.FromArgb(newA, newR, newG, newB); } @@ -194,7 +197,7 @@ public static byte[] GetBgr24Data(this BitmapSource bmp) var dict = new Dictionary(); foreach (DictionaryEntry res in reader) { - var path = (string) res.Key; + var path = (string)res.Key; if (Regex.IsMatch(path, pattern)) dict.Add(path, res.Value); } @@ -220,5 +223,114 @@ public static Color ToMediaColor(this ColorArgb8888 c) { return Color.FromArgb(c.A, c.R, c.G, c.B); } + + + public static Dictionary GetMetadata(this ViewModelBase arg, params string[] basePath) + { + Dictionary meta = new Dictionary(); + Stack pathStack = new Stack(basePath); + void GetMetadataInner(ViewModelBase ivm) + { + var props = ivm.GetType().GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance); + foreach (var p in props) + { + object value = p.GetValue(ivm); + if (value is ViewModelBase) + { + pathStack.Push(p.Name); + GetMetadataInner((ViewModelBase)value); + pathStack.Pop(); + } + else if(p.CanRead && p.CanWrite) + { + var pathStr = string.Join(".", pathStack.Reverse()) + "." + p.Name; + if (value is Color || value is Boolean || value is Enum || value is double) + { + meta.Add(pathStr, Convert.ToString(value, CultureInfo.InvariantCulture)); + + } + } + } + } + + foreach (string p in basePath) + { + var type = arg.GetType(); + var info = type.GetProperty(p); + if (!typeof(ViewModelBase).IsAssignableFrom(info.PropertyType)) + return meta; + arg = (ViewModelBase)info.GetValue(arg); + } + GetMetadataInner(arg); + return meta; + } + + public static void SetMetadata(this ViewModelBase arg, Dictionary metadata, params string[] basePath) + { + + void SetMetadataInner(string path, string value) + { + object cur = arg; + var parts = path.Split('.'); + for (var i = 0; i < parts.Length; i++) + { + var part = parts[i]; + var type = cur.GetType(); + var info = type.GetProperty(part, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance); + if (info == null) + return; + if (i == parts.Length - 1) + { + try + { + if (info.PropertyType == typeof(Color)) + { + + var col = System.Windows.Media.ColorConverter.ConvertFromString(value); + info.SetValue(cur, col); + + } + else if (info.PropertyType == typeof(double)) + { + if (double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var res)) + info.SetValue(cur, res); + } + else if (info.PropertyType == typeof(bool)) + { + if (bool.TryParse(value, out var res)) + info.SetValue(cur, res); + } + else if (info.PropertyType.IsEnum) + { + if (!Enum.IsDefined(info.PropertyType, value)) + return; + info.SetValue(cur, Enum.Parse(info.PropertyType, value)); + } + } + catch (Exception ex) + { + if (!(ex is FormatException) && + !(ex is ArgumentException)) + throw; + } + + } + else + { + cur = info.GetValue(cur); + } + } + } + + var append = string.Join(".", basePath); + if (append.Length > 0) + append += "."; + + foreach (var pair in metadata) + { + SetMetadataInner(append + pair.Key, pair.Value); + } + } + } } \ No newline at end of file diff --git a/ThemeEditor.WPF/MainWindow.Images.cs b/ThemeEditor.WPF/MainWindow.Images.cs index 2ea66e4..31d330a 100644 --- a/ThemeEditor.WPF/MainWindow.Images.cs +++ b/ThemeEditor.WPF/MainWindow.Images.cs @@ -21,7 +21,7 @@ namespace ThemeEditor.WPF { partial class MainWindow { - static readonly string[] VALID_IMAGE_EXT = {".jpg", ".jpeg", ".png", ".bmp"}; + static readonly string[] VALID_IMAGE_EXT = { ".jpg", ".jpeg", ".png", ".bmp" }; public ICommand CopyResizeSMDHIconCommandCommand { get; private set; } public ICommand DragImageCommand { get; set; } @@ -102,7 +102,7 @@ private Task DropImage_Execute(DragEventArgs args, TargetImage }; if (args.Data.GetDataPresent(DataFormats.FileDrop)) { - string[] files = (string[]) args.Data.GetData(DataFormats.FileDrop); + string[] files = (string[])args.Data.GetData(DataFormats.FileDrop); var file = files[0]; try { @@ -115,6 +115,9 @@ private Task DropImage_Execute(DragEventArgs args, TargetImage bmp.EndInit(); bmp.Freeze(); + results.OriginalWidth = bmp.PixelWidth; + results.OriginalHeight = bmp.PixelHeight; + var potBmp = bmp.CreateResizedNextPot(); potBmp.Freeze(); @@ -250,6 +253,9 @@ private Task LoadImage_Execute(TargetImage targetImage) bmp.EndInit(); bmp.Freeze(); + results.OriginalWidth = bmp.PixelWidth; + results.OriginalHeight = bmp.PixelHeight; + BitmapSource bmpSrc; switch (targetImage) @@ -304,57 +310,58 @@ private void LoadImage_PostExecute(LoadImageResults args) switch (target) { case TargetImage.Top: - { - ViewModel.Textures.Top.EncodeTexture(args.Image, targetSize.Format); - break; - } + { + ViewModel.Textures.Top.EncodeTexture(args.Image, targetSize.Format); + break; + } case TargetImage.Bottom: - { - ViewModel.Textures.Bottom.EncodeTexture(args.Image, targetSize.Format); - break; - } + { + ViewModel.Textures.Bottom.EncodeTexture(args.Image, targetSize.Format); + break; + } case TargetImage.FileLarge: - { - ViewModel.Textures.FileLarge.EncodeTexture(args.Image, targetSize.Format); - break; - } + { + ViewModel.Textures.FileLarge.EncodeTexture(args.Image, targetSize.Format); + break; + } case TargetImage.FileSmall: - { - ViewModel.Textures.FileSmall.EncodeTexture(args.Image, targetSize.Format); - break; - } + { + ViewModel.Textures.FileSmall.EncodeTexture(args.Image, targetSize.Format); + break; + } case TargetImage.FolderOpen: - { - ViewModel.Textures.FolderOpen.EncodeTexture(args.Image, targetSize.Format); - break; - } + { + ViewModel.Textures.FolderOpen.EncodeTexture(args.Image, targetSize.Format); + break; + } case TargetImage.FolderClosed: - { - ViewModel.Textures.FolderClosed.EncodeTexture(args.Image, targetSize.Format); - break; - } + { + ViewModel.Textures.FolderClosed.EncodeTexture(args.Image, targetSize.Format); + break; + } case TargetImage.TopAlt: - { - ViewModel.Textures.TopAlt.EncodeTexture(args.Image, targetSize.Format); - break; - } + { + ViewModel.Textures.TopAlt.EncodeTexture(args.Image, targetSize.Format); + break; + } case TargetImage.SmallIcon: - { - ViewModel.Info.SmallIcon.EncodeTexture(args.Image, targetSize.Format); - break; - } + { + ViewModel.Info.SmallIcon.EncodeTexture(args.Image, targetSize.Format); + break; + } case TargetImage.LargeIcon: - { - ViewModel.Info.LargeIcon.EncodeTexture(args.Image, targetSize.Format); - var sml = Extensions.CreateResizedImage(args.Image, 24, 24); - ViewModel.Info.SmallIcon.EncodeTexture((BitmapSource) sml, targetSize.Format); - break; - } + { + ViewModel.Info.LargeIcon.EncodeTexture(args.Image, targetSize.Format); + var sml = Extensions.CreateResizedImage(args.Image, 24, 24); + ViewModel.Info.SmallIcon.EncodeTexture((BitmapSource)sml, targetSize.Format); + break; + } default: - { - throw new ArgumentOutOfRangeException(); - } + { + throw new ArgumentOutOfRangeException(); + } } + ViewModel.Textures.Top.EdgeBleed(0, 0, args.OriginalWidth, args.OriginalHeight); } catch (InvalidOperationException) { @@ -396,19 +403,19 @@ private void RemoveImage_Execute(TargetImage args) ViewModel.Textures.TopAlt.ClearTexture(); break; case TargetImage.SmallIcon: - { - var icex = new IconExtension(@"/ThemeEditor.WPF;component/Resources/Icons/app_icn.ico", 24); - var large = ((BitmapSource) icex.ProvideValue(null)).CreateResizedImage(24, 24); - ViewModel.Info.SmallIcon.EncodeTexture(large, RawTexture.DataFormat.Bgr565); - break; - } + { + var icex = new IconExtension(@"/ThemeEditor.WPF;component/Resources/Icons/app_icn.ico", 24); + var large = ((BitmapSource)icex.ProvideValue(null)).CreateResizedImage(24, 24); + ViewModel.Info.SmallIcon.EncodeTexture(large, RawTexture.DataFormat.Bgr565); + break; + } case TargetImage.LargeIcon: - { - var icex = new IconExtension(@"/ThemeEditor.WPF;component/Resources/Icons/app_icn.ico", 48); - var large = ((BitmapSource) icex.ProvideValue(null)).CreateResizedImage(48, 48); - ViewModel.Info.LargeIcon.EncodeTexture(large, RawTexture.DataFormat.Bgr565); - break; - } + { + var icex = new IconExtension(@"/ThemeEditor.WPF;component/Resources/Icons/app_icn.ico", 48); + var large = ((BitmapSource)icex.ProvideValue(null)).CreateResizedImage(48, 48); + ViewModel.Info.LargeIcon.EncodeTexture(large, RawTexture.DataFormat.Bgr565); + break; + } default: throw new ArgumentOutOfRangeException(); } @@ -456,12 +463,12 @@ private void CopySMDHLargeToSmall_Execute(bool direction) if (direction) { var sml = Extensions.CreateResizedImage(ViewModel.Info.LargeIcon.Bitmap, 24, 24); - ViewModel.Info.SmallIcon.EncodeTexture((BitmapSource) sml, ViewModel.Info.SmallIcon.DataFormat); + ViewModel.Info.SmallIcon.EncodeTexture((BitmapSource)sml, ViewModel.Info.SmallIcon.DataFormat); } else { var sml = Extensions.CreateResizedImage(ViewModel.Info.SmallIcon.Bitmap, 48, 48); - ViewModel.Info.LargeIcon.EncodeTexture((BitmapSource) sml, ViewModel.Info.LargeIcon.DataFormat); + ViewModel.Info.LargeIcon.EncodeTexture((BitmapSource)sml, ViewModel.Info.LargeIcon.DataFormat); } } @@ -474,6 +481,8 @@ private class SaveImageResults private class LoadImageResults { + public int OriginalWidth; + public int OriginalHeight; public BitmapSource Image; public bool Loaded; public TargetImage Target; diff --git a/ThemeEditor.WPF/MainWindow.Themes.cs b/ThemeEditor.WPF/MainWindow.Themes.cs index 1e16733..c2a3918 100644 --- a/ThemeEditor.WPF/MainWindow.Themes.cs +++ b/ThemeEditor.WPF/MainWindow.Themes.cs @@ -3,12 +3,14 @@ // -------------------------------------------------- using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Linq; using System.Net; using System.Net.Sockets; +using System.Reflection; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -50,6 +52,10 @@ partial class MainWindow public ICommand SendThemeCHMM2Command { get; private set; } + public ICommand ExportMetadataCommand { get; private set; } + public ICommand ImportMetadataCommand { get; private set; } + + public string ThemePath { get { return _themePath; } @@ -81,8 +87,17 @@ private Task LoadNullTheme_Execute(bool start) }; BusyText = busyLoadingTheme; - var res = Extensions.GetResources("body_lz\\.bin"); - using (var fs = (Stream) res.Values.First()) + Stream fs; + if (!File.Exists("default_body_lz.bin")) + { + var res = Extensions.GetResources("body_lz\\.bin"); + fs = (Stream)res.Values.First(); + } + else + { + fs = File.OpenRead("default_body_lz.bin"); + } + using (fs) using (var ms = new MemoryStream()) { try @@ -192,9 +207,9 @@ private void LoadTheme_PostExecute(LoadThemeResults result) if (result.Info == null) { IconExtension icex = new IconExtension(@"/ThemeEditor.WPF;component/Resources/Icons/app_icn.ico", 48); - var large = ((BitmapSource) icex.ProvideValue(null)).CreateResizedImage(48, 48); + var large = ((BitmapSource)icex.ProvideValue(null)).CreateResizedImage(48, 48); icex.Size = 24; - var small = ((BitmapSource) icex.ProvideValue(null)).CreateResizedImage(24, 24); + var small = ((BitmapSource)icex.ProvideValue(null)).CreateResizedImage(24, 24); ViewModel.Info.LargeIcon.Bitmap = large; ViewModel.Info.SmallIcon.Bitmap = small; @@ -441,11 +456,138 @@ private void SaveTheme_PostExecute(SaveThemeResults result) CanExecute_LoadedFromFile, PreExecute_SetBusy, LoadBGM_PostExecute); + + ExportMetadataCommand = new RelayCommandAsync(SaveMetadata_Execute, + str => CanExecute_ViewModelLoaded(), + str => PreExecute_SetBusy(), + (r) => IsBusy = false); + + ImportMetadataCommand = new RelayCommandAsync(LoadMetadata_Execute, + str => CanExecute_ViewModelLoaded(), + str => PreExecute_SetBusy(), + ImportMetadata_PostExecute); + + } + + private void ImportMetadata_PostExecute(LoadMetadataResults r) + { + ViewModel.Rules.Pause(); + ViewModel.SetMetadata(r.Data); + ViewModel.Rules.Apply(ViewModel.Flags); + ViewModel.Rules.Apply(ViewModel.Colors); + ViewModel.Rules.Resume(); + IsBusy = false; + } + + private Task LoadMetadata_Execute(string rootProps) + { + var viewModel = ViewModel; + var busyPickingFile = MainResources.Busy_PickingFile; + var busySavingTheme = MainResources.Busy_SavingTheme; + string[] splProps = (rootProps ?? String.Empty).Split('.'); + var task = new Task(() => + { + BusyText = busyPickingFile; + + var result = new LoadMetadataResults() + { + Loaded = false, + Data = new Dictionary() + }; + + var opfl = new OpenFileDialog + { + Filter = "Metadata File|*.meta", + }; + var dlg = opfl.ShowDialog(); + if (dlg.HasValue && !dlg.Value) + return result; + var dataFile = opfl.FileName; + + BusyText = busySavingTheme; + + try + { + using (var fs = File.OpenText(dataFile)) + { + while (!fs.EndOfStream) + { + string s = fs.ReadLine(); + if (s.StartsWith(";")) + continue; + var kv = s.Split(':'); + result.Data.Add(kv[0].Trim(), kv[1].Trim()); + } + } + result.Loaded = true; + } + catch + { + //... + } + + return result; + }, + TaskCreationOptions.LongRunning); + task.Start(); + return task; + } + + private Task SaveMetadata_Execute(string rootProps) + { + var viewModel = ViewModel; + var busyPickingFile = MainResources.Busy_PickingFile; + var busySavingTheme = MainResources.Busy_SavingTheme; + string[] splProps = rootProps.Split('.'); + var task = new Task(() => + { + BusyText = busyPickingFile; + + var result = new SaveMetadataResults() + { + Saved = false, + Path = null + }; + + + var svfl = new SaveFileDialog + { + Filter = "Metadata File|*.meta", + FileName = splProps.LastOrDefault()?.ToLower() ?? "metadata" + }; + var dlg = svfl.ShowDialog(); + if (dlg.HasValue && !dlg.Value) + return result; + result.Path = svfl.FileName; + + BusyText = busySavingTheme; + + try + { + Dictionary data = viewModel.GetMetadata(splProps); + var maxl = data.Keys.Max(s => s.Length); + using (var fs = File.CreateText(result.Path)) + { + foreach (var pair in data) + fs.WriteLine("{0}: {1}", pair.Key.PadRight(maxl), pair.Value); + } + result.Saved = true; + } + catch (Exception ex) + { + //... + } + + return result; + }, + TaskCreationOptions.LongRunning); + task.Start(); + return task; } private Task DropTheme_Execute(DragEventArgs args) { - return LoadTheme_Execute(((string[]) args.Data.GetData(DataFormats.FileDrop))[0], true); + return LoadTheme_Execute(((string[])args.Data.GetData(DataFormats.FileDrop))[0], true); } private void DragTheme_Execute(DragEventArgs args) @@ -537,7 +679,7 @@ private Task SendTheme_Execute(string ip, bool start) var toWrite = result.Zip.Data.Length; var offset = 0; - var fLen = (float) result.Zip.Data.Length / 100; + var fLen = (float)result.Zip.Data.Length / 100; Stopwatch sw = new Stopwatch(); sw.Start(); @@ -558,7 +700,7 @@ private Task SendTheme_Execute(string ip, bool start) averageSample = (averageSample * 0.75f) + (delta / trans * 0.25f); BusyText = $"Sending: {offset / fLen:f2}%" + Environment.NewLine + - $"Rate: {(int) (averageSample / 1.024)}KB/s"; + $"Rate: {(int)(averageSample / 1.024)}KB/s"; sw.Restart(); } @@ -617,5 +759,17 @@ private class SaveThemeResults public string Path; public bool Saved; } + + private class LoadMetadataResults + { + public Dictionary Data; + public bool Loaded; + } + + private class SaveMetadataResults + { + public string Path; + public bool Saved; + } } } \ No newline at end of file diff --git a/ThemeEditor.WPF/MainWindow.xaml b/ThemeEditor.WPF/MainWindow.xaml index d41dd96..eb85347 100644 --- a/ThemeEditor.WPF/MainWindow.xaml +++ b/ThemeEditor.WPF/MainWindow.xaml @@ -34,7 +34,7 @@ 1.0 - 0.5 + 0.25 @@ -486,6 +486,12 @@ IsEnabled="False" /> + + + + + + - + diff --git a/ThemeEditor.WPF/Themes/TextureViewModel.cs b/ThemeEditor.WPF/Themes/TextureViewModel.cs index 41763d8..95dc56f 100644 --- a/ThemeEditor.WPF/Themes/TextureViewModel.cs +++ b/ThemeEditor.WPF/Themes/TextureViewModel.cs @@ -64,6 +64,12 @@ public void EncodeTexture(BitmapSource bitmap, RawTexture.DataFormat targetForma Invalidate(); } + public void EdgeBleed(int x, int y, int sx, int sy) + { + Model.EdgeBleed(x, y, sx, sy); + Invalidate(); + } + public void Invalidate() { var oldBitmap = _src; diff --git a/ThemeEditor.WPF/Themes/ThemeViewModel.Rules.cs b/ThemeEditor.WPF/Themes/ThemeViewModel.Rules.cs index 1bb1ff2..3d037c1 100644 --- a/ThemeEditor.WPF/Themes/ThemeViewModel.Rules.cs +++ b/ThemeEditor.WPF/Themes/ThemeViewModel.Rules.cs @@ -13,7 +13,7 @@ namespace ThemeEditor.WPF.Themes { partial class ThemeViewModel { - private ViewModelRules Rules { get; set; } + public ViewModelRules Rules { get; set; } private T FilterEnum(T newValue, T oldValue, params T[] valid) where T : struct, IConvertible {