From 7e8a94aa4a02db781010c109bd2473990d4540b2 Mon Sep 17 00:00:00 2001 From: Atria1234 Date: Thu, 23 Dec 2021 15:49:55 +0100 Subject: [PATCH 1/3] Created layout preset library dialog (#375) --- AnnoDesigner.Core/Layout/LayoutLoader.cs | 16 + AnnoDesigner.Core/Layout/Models/LayoutFile.cs | 11 +- .../Layout/Presets/IPresetLayout.cs | 7 + .../Layout/Presets/LayoutPresetInfo.cs | 20 ++ .../Layout/Presets/MultilangInfo.cs | 78 +++++ .../Layout/Presets/PresetLayout.cs | 21 ++ .../Layout/Presets/PresetLayoutDirectory.cs | 11 + .../Layout/Presets/PresetLayoutLoader.cs | 102 ++++++ AnnoDesigner.Core/Models/IAppSettings.cs | 1 + AnnoDesigner/AnnoDesigner.csproj | 7 + AnnoDesigner/Constants.cs | 5 + .../Converters/ReferenceToBooleanConverter.cs | 24 ++ ...ataIO.cs => FrameworkElementExtensions.cs} | 29 +- AnnoDesigner/ImageWindow.xaml | 19 ++ AnnoDesigner/ImageWindow.xaml.cs | 27 ++ AnnoDesigner/Layouts/LayoutInfoSchema.json | 54 ++++ AnnoDesigner/Layouts/Readme.md | 14 + AnnoDesigner/Localization/Localization.cs | 3 +- AnnoDesigner/Localization/LocalizeBinding.cs | 59 ++++ AnnoDesigner/MainWindow.xaml | 2 + AnnoDesigner/Models/AppSettings.cs | 6 + AnnoDesigner/Models/CanvasRenderSetting.cs | 17 + .../PreferencesPages/GeneralSettingsPage.xaml | 59 +++- AnnoDesigner/PresetLayoutViewModel.cs | 92 ++++++ AnnoDesigner/PresetLayoutWindow.xaml | 94 ++++++ AnnoDesigner/PresetLayoutWindow.xaml.cs | 72 +++++ AnnoDesigner/Properties/Settings.Designer.cs | 12 + AnnoDesigner/Properties/Settings.settings | 3 + .../ViewModels/GeneralSettingsViewModel.cs | 59 +++- AnnoDesigner/ViewModels/MainViewModel.cs | 291 +++++++++++------- AnnoDesigner/app.config | 3 + 31 files changed, 1079 insertions(+), 139 deletions(-) create mode 100644 AnnoDesigner.Core/Layout/Presets/IPresetLayout.cs create mode 100644 AnnoDesigner.Core/Layout/Presets/LayoutPresetInfo.cs create mode 100644 AnnoDesigner.Core/Layout/Presets/MultilangInfo.cs create mode 100644 AnnoDesigner.Core/Layout/Presets/PresetLayout.cs create mode 100644 AnnoDesigner.Core/Layout/Presets/PresetLayoutDirectory.cs create mode 100644 AnnoDesigner.Core/Layout/Presets/PresetLayoutLoader.cs create mode 100644 AnnoDesigner/Converters/ReferenceToBooleanConverter.cs rename AnnoDesigner/{DataIO.cs => FrameworkElementExtensions.cs} (57%) create mode 100644 AnnoDesigner/ImageWindow.xaml create mode 100644 AnnoDesigner/ImageWindow.xaml.cs create mode 100644 AnnoDesigner/Layouts/LayoutInfoSchema.json create mode 100644 AnnoDesigner/Layouts/Readme.md create mode 100644 AnnoDesigner/Models/CanvasRenderSetting.cs create mode 100644 AnnoDesigner/PresetLayoutViewModel.cs create mode 100644 AnnoDesigner/PresetLayoutWindow.xaml create mode 100644 AnnoDesigner/PresetLayoutWindow.xaml.cs diff --git a/AnnoDesigner.Core/Layout/LayoutLoader.cs b/AnnoDesigner.Core/Layout/LayoutLoader.cs index 79e80cee..a54e7bc8 100644 --- a/AnnoDesigner.Core/Layout/LayoutLoader.cs +++ b/AnnoDesigner.Core/Layout/LayoutLoader.cs @@ -64,6 +64,17 @@ public LayoutFile LoadLayout(Stream streamWithLayout, bool forceLoad = false) return Load(jsonString, forceLoad); } + public async Task LoadLayoutAsync(Stream streamWithLayout, bool forceLoad = false) + { + if (streamWithLayout == null) + { + throw new ArgumentNullException(nameof(streamWithLayout)); + } + using var sr = new StreamReader(streamWithLayout); + var jsonString = await sr.ReadToEndAsync(); + return await LoadAsync(jsonString, forceLoad); + } + private LayoutFile Load(string jsonString, bool forceLoad) { var layoutVersion = new LayoutFileVersionContainer() { FileVersion = 0 }; @@ -88,5 +99,10 @@ private LayoutFile Load(string jsonString, bool forceLoad) _ => throw new NotImplementedException() }; } + + private Task LoadAsync(string jsonString, bool forceLoad) + { + return Task.Run(() => Load(jsonString, forceLoad)); + } } } diff --git a/AnnoDesigner.Core/Layout/Models/LayoutFile.cs b/AnnoDesigner.Core/Layout/Models/LayoutFile.cs index e3b7fd02..475a163b 100644 --- a/AnnoDesigner.Core/Layout/Models/LayoutFile.cs +++ b/AnnoDesigner.Core/Layout/Models/LayoutFile.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using AnnoDesigner.Core.Models; @@ -21,5 +22,13 @@ public LayoutFile(IEnumerable objects) FileVersion = CoreConstants.LayoutFileVersion; Objects = objects.ToList(); } + + public LayoutFile(LayoutFile copy) + { + FileVersion = copy.FileVersion; + LayoutVersion = (Version)copy.LayoutVersion.Clone(); + Modified = copy.Modified; + Objects = copy.Objects.Select(x => new AnnoObject(x)).ToList(); + } } } \ No newline at end of file diff --git a/AnnoDesigner.Core/Layout/Presets/IPresetLayout.cs b/AnnoDesigner.Core/Layout/Presets/IPresetLayout.cs new file mode 100644 index 00000000..790c7cc6 --- /dev/null +++ b/AnnoDesigner.Core/Layout/Presets/IPresetLayout.cs @@ -0,0 +1,7 @@ +namespace AnnoDesigner.Core.Layout.Presets +{ + public interface IPresetLayout + { + public MultilangInfo Name { get; } + } +} diff --git a/AnnoDesigner.Core/Layout/Presets/LayoutPresetInfo.cs b/AnnoDesigner.Core/Layout/Presets/LayoutPresetInfo.cs new file mode 100644 index 00000000..2c4c73e4 --- /dev/null +++ b/AnnoDesigner.Core/Layout/Presets/LayoutPresetInfo.cs @@ -0,0 +1,20 @@ +namespace AnnoDesigner.Core.Layout.Presets +{ + public class LayoutPresetInfo + { + public MultilangInfo Name { get; set; } + + public MultilangInfo Description { get; set; } + + public string Author { get; set; } + + public string AuthorContact { get; set; } + + public LayoutPresetInfo() { } + + public LayoutPresetInfo(string name) + { + Name = name; + } + } +} diff --git a/AnnoDesigner.Core/Layout/Presets/MultilangInfo.cs b/AnnoDesigner.Core/Layout/Presets/MultilangInfo.cs new file mode 100644 index 00000000..53a5390c --- /dev/null +++ b/AnnoDesigner.Core/Layout/Presets/MultilangInfo.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; + +namespace AnnoDesigner.Core.Layout.Presets +{ + [JsonConverter(typeof(MultilangInfoConverter))] + public class MultilangInfo + { + private class MultilangInfoConverter : JsonConverter + { + public override MultilangInfo ReadJson(JsonReader reader, Type objectType, MultilangInfo existingValue, bool hasExistingValue, JsonSerializer serializer) + { + switch (reader.TokenType) + { + case JsonToken.String: + return reader.Value as string; + case JsonToken.StartObject: + return serializer.Deserialize>(reader); + default: + throw new JsonSerializationException($"Unexpected token during deserialization of {nameof(MultilangInfo)}"); + } + } + + public override void WriteJson(JsonWriter writer, MultilangInfo value, JsonSerializer serializer) + { + serializer.Serialize(writer, (object)value.Default ?? value.Translations); + } + } + + private Dictionary Translations { get; set; } + + private string Default { get; set; } + + public string this[string language] + { + set + { + Translations ??= new Dictionary(); + Translations[language] = value; + } + } + + public string Translate(string language) + { + return Default ?? ( + Translations.TryGetValue(language, out var translation) + ? translation + : Translations.Count > 0 + ? $"{Translations.FirstOrDefault().Value} ({Translations.FirstOrDefault().Key})" + : string.Empty + ); + } + + public static implicit operator MultilangInfo(string value) + { + return new MultilangInfo() + { + Default = value + }; + } + + public static implicit operator MultilangInfo(Dictionary value) + { + return new MultilangInfo() + { + Translations = value + }; + } + + public static explicit operator string(MultilangInfo info) + { + var first = info.Translations.FirstOrDefault(); + return info.Default ?? (info.Translations.Count > 0 ? $"{first.Value} ({first.Key})" : string.Empty); + } + } +} diff --git a/AnnoDesigner.Core/Layout/Presets/PresetLayout.cs b/AnnoDesigner.Core/Layout/Presets/PresetLayout.cs new file mode 100644 index 00000000..35b14b61 --- /dev/null +++ b/AnnoDesigner.Core/Layout/Presets/PresetLayout.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using System.Windows.Media; +using AnnoDesigner.Core.Layout.Models; + +namespace AnnoDesigner.Core.Layout.Presets +{ + public class PresetLayout : IPresetLayout + { + public MultilangInfo Name => Info.Name; + + public LayoutPresetInfo Info { get; set; } + + public string Author { get; set; } + + public string AuthorContact { get; set; } + + public LayoutFile Layout { get; set; } + + public List Images { get; set; } + } +} diff --git a/AnnoDesigner.Core/Layout/Presets/PresetLayoutDirectory.cs b/AnnoDesigner.Core/Layout/Presets/PresetLayoutDirectory.cs new file mode 100644 index 00000000..ac990162 --- /dev/null +++ b/AnnoDesigner.Core/Layout/Presets/PresetLayoutDirectory.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace AnnoDesigner.Core.Layout.Presets +{ + public class PresetLayoutDirectory : IPresetLayout + { + public MultilangInfo Name { get; set; } + + public List Presets { get; set; } + } +} diff --git a/AnnoDesigner.Core/Layout/Presets/PresetLayoutLoader.cs b/AnnoDesigner.Core/Layout/Presets/PresetLayoutLoader.cs new file mode 100644 index 00000000..6eb0f7ac --- /dev/null +++ b/AnnoDesigner.Core/Layout/Presets/PresetLayoutLoader.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Abstractions; +using System.IO.Compression; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using AnnoDesigner.Core.Layout.Models; +using Newtonsoft.Json; +using NLog; + +namespace AnnoDesigner.Core.Layout.Presets +{ + public class PresetLayoutLoader + { + private readonly IFileSystem _fileSystem; + private static readonly Logger Logger = LogManager.GetLogger(nameof(PresetLayoutLoader)); + + public Func RenderLayoutToImage { get; set; } + public PresetLayoutLoader(Func renderLayoutToImage, IFileSystem fileSystem = null) + { + RenderLayoutToImage = renderLayoutToImage; + _fileSystem = fileSystem ?? new FileSystem(); + } + + public async Task> LoadAsync(string rootDirectory) + { + var data = await LoadDirectoryAsync(rootDirectory); + + return data.Presets; + } + + private async Task LoadDirectoryAsync(string directory) + { + var subdirectories = await Task.WhenAll(_fileSystem.Directory.GetDirectories(directory).Select(LoadDirectoryAsync)); + var layouts = await Task.WhenAll(_fileSystem.Directory.GetFiles(directory, "*.zip").Select(LoadLayout)); + return new PresetLayoutDirectory() + { + Name = _fileSystem.Path.GetFileName(directory), + Presets = subdirectories.Cast().Concat(layouts.Where(f => f != null)).ToList() + }; + } + + private async Task LoadLayout(string file) + { + try + { + using var zipFile = ZipFile.OpenRead(file); + using var layoutFile = zipFile.GetEntry("layout.ad").Open(); + using var infoFile = zipFile.GetEntry("info.json")?.Open() ?? Stream.Null; + using var infoStream = new StreamReader(infoFile); + + var layout = await new LayoutLoader().LoadLayoutAsync(layoutFile, true); + if (layout != null) + { + var info = JsonConvert.DeserializeObject(await infoStream.ReadToEndAsync()) ?? new LayoutPresetInfo(_fileSystem.Path.GetFileNameWithoutExtension(file)); + var images = new List() + { + RenderLayoutToImage(layout) + }; + + foreach (var item in zipFile.Entries) + { + using var stream = item.Open(); + switch (_fileSystem.Path.GetExtension(item.FullName).ToLowerInvariant()) + { + case ".png": + case ".jpg": + case ".jpeg": + await Task.Yield(); + + var imageStream = new MemoryStream(); + stream.CopyTo(imageStream); + var image = new BitmapImage(); + image.BeginInit(); + image.StreamSource = imageStream; + image.EndInit(); + image.Freeze(); + images.Add(image); + break; + } + } + + return new PresetLayout() + { + Info = info, + Layout = layout, + Images = images + }; + } + } + catch (Exception e) + { + Logger.Warn(e, $"Failed to parse loadout preset {file}"); + } + + return null; + } + } +} diff --git a/AnnoDesigner.Core/Models/IAppSettings.cs b/AnnoDesigner.Core/Models/IAppSettings.cs index 005e1db3..4a7b3b25 100644 --- a/AnnoDesigner.Core/Models/IAppSettings.cs +++ b/AnnoDesigner.Core/Models/IAppSettings.cs @@ -56,5 +56,6 @@ public interface IAppSettings bool InvertScrollingDirection { get; set; } bool ShowScrollbars { get; set; } bool IncludeRoadsInStatisticCalculation { get; set; } + string PresetLayoutLocation { get; set; } } } diff --git a/AnnoDesigner/AnnoDesigner.csproj b/AnnoDesigner/AnnoDesigner.csproj index c8685b16..cf5be003 100644 --- a/AnnoDesigner/AnnoDesigner.csproj +++ b/AnnoDesigner/AnnoDesigner.csproj @@ -56,6 +56,12 @@ PreserveNewest + + Always + + + Always + SettingsSingleFileGenerator Settings.Designer.cs @@ -83,6 +89,7 @@ + diff --git a/AnnoDesigner/Constants.cs b/AnnoDesigner/Constants.cs index fc65bb50..ebdf8469 100644 --- a/AnnoDesigner/Constants.cs +++ b/AnnoDesigner/Constants.cs @@ -108,5 +108,10 @@ public static class Constants /// The default number of recent files to show. /// public const int MaxRecentFiles = 10; + + /// + /// Default location of preset layout folder. + /// + public const string DefaultPresetLayoutLocation = ".\\Layouts"; } } diff --git a/AnnoDesigner/Converters/ReferenceToBooleanConverter.cs b/AnnoDesigner/Converters/ReferenceToBooleanConverter.cs new file mode 100644 index 00000000..5f711fa1 --- /dev/null +++ b/AnnoDesigner/Converters/ReferenceToBooleanConverter.cs @@ -0,0 +1,24 @@ +using System; +using System.Globalization; +using System.Windows.Data; + +namespace AnnoDesigner.Converters +{ + [ValueConversion(typeof(object), typeof(object))] + public class ReferenceToValueConverter : IValueConverter + { + public object NullValue { get; set; } + + public object NotNullValue { get; set; } + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return value == null ? NullValue : NotNullValue; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/AnnoDesigner/DataIO.cs b/AnnoDesigner/FrameworkElementExtensions.cs similarity index 57% rename from AnnoDesigner/DataIO.cs rename to AnnoDesigner/FrameworkElementExtensions.cs index 9478db85..2d170b9b 100644 --- a/AnnoDesigner/DataIO.cs +++ b/AnnoDesigner/FrameworkElementExtensions.cs @@ -3,26 +3,35 @@ using System.Windows.Media; using System.Windows.Media.Imaging; -namespace AnnoDesigner +namespace AnnoDesigner.Core.Extensions { /// - /// Provides I/O methods + /// Provides extension methods for framework elements to render it to multiple targets. /// - public static class DataIO + public static class FrameworkElementExtensions { - #region Render to file - /// - /// Renders the given target to an image file, png encoded. + /// Renders the given target to a bitmap. /// /// target to be rendered - /// output filename - public static void RenderToFile(FrameworkElement target, string filename) + /// Bitmap containing rendered framework element + public static RenderTargetBitmap RenderToBitmap(this FrameworkElement target) { - // render control const int dpi = 96; var rtb = new RenderTargetBitmap((int)target.ActualWidth, (int)target.ActualHeight, dpi, dpi, PixelFormats.Default); rtb.Render(target); + + return rtb; + } + + /// + /// Renders the given target to an image file, png encoded. + /// + /// target to be rendered + /// output filename + public static void RenderToFile(this FrameworkElement target, string filename) + { + var rtb = target.RenderToBitmap(); // put result into bitmap var encoder = Constants.GetExportImageEncoder(); encoder.Frames.Add(BitmapFrame.Create(rtb)); @@ -32,7 +41,5 @@ public static void RenderToFile(FrameworkElement target, string filename) encoder.Save(file); } } - - #endregion } } \ No newline at end of file diff --git a/AnnoDesigner/ImageWindow.xaml b/AnnoDesigner/ImageWindow.xaml new file mode 100644 index 00000000..c5633525 --- /dev/null +++ b/AnnoDesigner/ImageWindow.xaml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + diff --git a/AnnoDesigner/ImageWindow.xaml.cs b/AnnoDesigner/ImageWindow.xaml.cs new file mode 100644 index 00000000..03521afd --- /dev/null +++ b/AnnoDesigner/ImageWindow.xaml.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; + +namespace AnnoDesigner +{ + /// + /// Interaction logic for ImageWindow.xaml + /// + public partial class ImageWindow : Window + { + public ImageWindow() + { + InitializeComponent(); + } + } +} diff --git a/AnnoDesigner/Layouts/LayoutInfoSchema.json b/AnnoDesigner/Layouts/LayoutInfoSchema.json new file mode 100644 index 00000000..068488f2 --- /dev/null +++ b/AnnoDesigner/Layouts/LayoutInfoSchema.json @@ -0,0 +1,54 @@ +{ + "$schema": "https://json-schema.org/draft-04/schema", + "type": "object", + "definitions": { + "multilang": { + "oneOf": [ + { + "type": "string", + "description": "Single value used for all languages" + }, + { + "type": "object", + "properties": { + "eng": { + "type": "string" + }, + "ger": { + "type": "string" + }, + "fra": { + "type": "string" + }, + "esp": { + "type": "string" + }, + "pol": { + "type": "string" + }, + "rus": { + "type": "string" + } + } + } + ] + } + }, + "properties": { + "Name": { + "#ref": "/definitions/multilang" + }, + "Description": { + "#ref": "/definitions/multilang" + }, + "Author": { + "type": "string" + }, + "AuthorContact": { + "type": "string" + } + }, + "required": [ + "Name" + ] +} \ No newline at end of file diff --git a/AnnoDesigner/Layouts/Readme.md b/AnnoDesigner/Layouts/Readme.md new file mode 100644 index 00000000..bde70c90 --- /dev/null +++ b/AnnoDesigner/Layouts/Readme.md @@ -0,0 +1,14 @@ +Each ZIP file in this folder and all subfolders should contain information about layout preset + +Layout preset must have: +- layout file named layout.ad + +Layout preset can have: +- info file names info.json + - JSON schema of this file is defined in LayoutInfoSchema.json in this folder + - if not provided the layout preset's name will be the ZIP file name +- any number of image files which should be associated with that layout + - supported file types are "png", "jpg" and "jpeg" (case insensitive) + +ZIP files which fail to load as layout preset are ignored and not shown in AnnoDesigner +Info about ZIP file failing to load is writen to the application log diff --git a/AnnoDesigner/Localization/Localization.cs b/AnnoDesigner/Localization/Localization.cs index 60cf4386..40b8ffee 100644 --- a/AnnoDesigner/Localization/Localization.cs +++ b/AnnoDesigner/Localization/Localization.cs @@ -36,7 +36,7 @@ private Localization() { } private static IDictionary> TranslationsRaw { get; set; } - private string SelectedLanguageCode => _commons.CurrentLanguageCode; + public string SelectedLanguageCode => _commons.CurrentLanguageCode; public static IDictionary Translations => TranslationsRaw[Instance.SelectedLanguageCode]; @@ -1283,6 +1283,7 @@ private void Commons_SelectedLanguageChanged(object sender, EventArgs e) { OnPropertyChanged(nameof(Translations)); OnPropertyChanged(nameof(InstanceTranslations)); + OnPropertyChanged(nameof(SelectedLanguageCode)); } public string GetLocalization(string valueToTranslate) diff --git a/AnnoDesigner/Localization/LocalizeBinding.cs b/AnnoDesigner/Localization/LocalizeBinding.cs index 528fb51c..9ca89da7 100644 --- a/AnnoDesigner/Localization/LocalizeBinding.cs +++ b/AnnoDesigner/Localization/LocalizeBinding.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.Windows; using System.Windows.Data; +using AnnoDesigner.Core.Layout.Presets; namespace AnnoDesigner.Localization { @@ -92,4 +94,61 @@ public DynamicLocalize(string keyPath) : this() KeyPath = keyPath; } } + + public class Multilang : MultiBinding + { + private class MultilangInfoConverter : IMultiValueConverter + { + public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) + { + if (values.Length == 2) + { + if (values[0] == DependencyProperty.UnsetValue || values[1] == DependencyProperty.UnsetValue) + { + return DependencyProperty.UnsetValue; + } + + if (values[1] is null) + { + return null; + } + + if (values[0] is string language && values[1] is MultilangInfo translations) + { + return translations.Translate(language); + } + } + throw new Exception($"Incorrect Multilang parameters. {values[1]}"); + } + + public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } + + private static MultilangInfoConverter SingletonConverter { get; } = new MultilangInfoConverter(); + + public string Path + { + set + { + Bindings.Add(new Binding(value)); + } + } + + public Multilang() + { + Bindings.Add(new Binding(nameof(Localization.Instance.SelectedLanguageCode)) + { + Source = Localization.Instance + }); + Converter = SingletonConverter; + } + + public Multilang(string path) : this() + { + Path = path; + } + } } diff --git a/AnnoDesigner/MainWindow.xaml b/AnnoDesigner/MainWindow.xaml index 6849678e..bcdb3c8e 100644 --- a/AnnoDesigner/MainWindow.xaml +++ b/AnnoDesigner/MainWindow.xaml @@ -199,6 +199,8 @@ Command="{Binding CanvasResetZoomCommand}" /> + diff --git a/AnnoDesigner/Models/AppSettings.cs b/AnnoDesigner/Models/AppSettings.cs index af57f83e..c524f19b 100644 --- a/AnnoDesigner/Models/AppSettings.cs +++ b/AnnoDesigner/Models/AppSettings.cs @@ -293,6 +293,12 @@ public bool IncludeRoadsInStatisticCalculation get => Settings.Default.IncludeRoadsInStatisticCalculation; set => Settings.Default.IncludeRoadsInStatisticCalculation = value; } + + public string PresetLayoutLocation + { + get => Settings.Default.PresetLayoutLocation; + set => Settings.Default.PresetLayoutLocation = value; + } } } diff --git a/AnnoDesigner/Models/CanvasRenderSetting.cs b/AnnoDesigner/Models/CanvasRenderSetting.cs new file mode 100644 index 00000000..af28fabd --- /dev/null +++ b/AnnoDesigner/Models/CanvasRenderSetting.cs @@ -0,0 +1,17 @@ +namespace AnnoDesigner.Models +{ + public class CanvasRenderSetting + { + public int? GridSize { get; set; } + + public bool RenderStatistics { get; set; } + public bool RenderVersion { get; set; } + public bool RenderGrid { get; set; } + public bool RenderIcon { get; set; } + public bool RenderLabel { get; set; } + public bool RenderHarborBlockedArea { get; set; } + public bool RenderPanorama { get; set; } + public bool RenderTrueInfluenceRange { get; set; } + public bool RenderInfluences { get; set; } + } +} diff --git a/AnnoDesigner/PreferencesPages/GeneralSettingsPage.xaml b/AnnoDesigner/PreferencesPages/GeneralSettingsPage.xaml index f5d79630..1715ab4d 100644 --- a/AnnoDesigner/PreferencesPages/GeneralSettingsPage.xaml +++ b/AnnoDesigner/PreferencesPages/GeneralSettingsPage.xaml @@ -22,7 +22,8 @@ + Margin="10,5,0,0" + Grid.IsSharedSizeScope="True"> @@ -33,7 +34,8 @@ + Width="Auto" + SharedSizeGroup="TitleColumn"/> @@ -74,12 +76,11 @@ Visibility="{Binding IsGridLineColorPickerVisible, Converter={StaticResource converterBoolToVisibilityCollapsed}}" /> - + + SharedSizeGroup="TitleColumn" /> @@ -120,12 +121,11 @@ Visibility="{Binding IsObjectBorderLineColorPickerVisible, Converter={StaticResource converterBoolToVisibilityCollapsed}}" /> - + + SharedSizeGroup="TitleColumn" /> @@ -190,7 +190,6 @@ - @@ -204,7 +203,8 @@ + Width="Auto" + SharedSizeGroup="TitleColumn"/> @@ -241,5 +241,44 @@ + + + + + + + + + + + + + + + + + + + + +