mirror of
https://github.com/gwdevhub/Daybreak.git
synced 2026-09-19 06:45:08 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cd40e2de3 | ||
|
|
7745594bb6 | ||
|
|
e43bedf1c2 | ||
|
|
d6623a8646 | ||
|
|
403ba51a7d | ||
|
|
b185a606e6 | ||
|
|
342a9a4826 | ||
|
|
2df2e8a65e | ||
|
|
2d5e9231a9 | ||
|
|
818e2bf1d0 | ||
|
|
f0a876f7cc | ||
|
|
3fae8f91cb | ||
|
|
8b08056ca7 | ||
|
|
39eaf53deb | ||
|
|
4674d1d7e5 | ||
|
|
b8b5cc8b1d | ||
|
|
dc987233a7 | ||
|
|
266b400c22 | ||
|
|
a4ac083fd0 | ||
|
|
320dd16838 | ||
|
|
5c05c636bc | ||
|
|
7103a8a83a | ||
|
|
ad749d801a | ||
|
|
747e9a0490 | ||
|
|
836402bd0f | ||
|
|
a3d5e1ce1f | ||
|
|
f2cc59a4ab | ||
|
|
6ea77f7e05 | ||
|
|
5ea8df7cb9 | ||
|
|
c70e8ec90d | ||
|
|
210e3a8cb1 | ||
|
|
a0c3bb094c | ||
|
|
b4d932692a | ||
|
|
667534a07a | ||
|
|
159928f24b | ||
|
|
8a91ded610 | ||
|
|
4226b7eb32 | ||
|
|
b61c99dd1c | ||
|
|
1ccb0d5334 | ||
|
|
7fa01353dd | ||
|
|
4f849d880b | ||
|
|
4b60c96aad | ||
|
|
a4dc0d65cf | ||
|
|
85e017423f |
+5
-2
@@ -6,8 +6,8 @@ csharp_indent_labels = one_less_than_current
|
||||
csharp_using_directive_placement = outside_namespace:error
|
||||
csharp_prefer_simple_using_statement = true:error
|
||||
csharp_prefer_braces = true:silent
|
||||
csharp_style_namespace_declarations = block_scoped:silent
|
||||
csharp_style_prefer_method_group_conversion = true:silent
|
||||
csharp_style_namespace_declarations = file_scoped:error
|
||||
csharp_style_prefer_method_group_conversion = true:suggestion
|
||||
csharp_style_expression_bodied_methods = false:silent
|
||||
csharp_style_expression_bodied_constructors = false:silent
|
||||
csharp_style_expression_bodied_operators = false:silent
|
||||
@@ -46,6 +46,9 @@ csharp_style_prefer_extended_property_pattern = true:suggestion
|
||||
csharp_style_var_for_built_in_types = false:silent
|
||||
csharp_style_var_when_type_is_apparent = false:silent
|
||||
csharp_style_var_elsewhere = false:silent
|
||||
csharp_style_prefer_top_level_statements = true:suggestion
|
||||
csharp_style_prefer_utf8_string_literals = true:suggestion
|
||||
csharp_style_prefer_readonly_struct = true:suggestion
|
||||
|
||||
[*.{cs,vb}]
|
||||
#### Naming styles ####
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
targetplatform: [x86]
|
||||
targetplatform: [x64]
|
||||
|
||||
runs-on: windows-latest
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
targetplatform: [x86]
|
||||
targetplatform: [x64]
|
||||
|
||||
runs-on: windows-latest
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Platforms>AnyCPU;x86</Platforms>
|
||||
<Platforms>AnyCPU;x86;x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<Platforms>AnyCPU;x86</Platforms>
|
||||
<Platforms>AnyCPU;x86;x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -132,4 +132,55 @@ public class VersionTests
|
||||
action.Should().NotThrow<ArgumentException>();
|
||||
}
|
||||
}
|
||||
|
||||
[DataRow("v0.1.0.0.1", "v0.1.0.0.1", true)]
|
||||
[DataRow("v0.1.0.0.1.0.0.0.0", "v0.1.0.0.1", true)]
|
||||
[DataRow("v0.1.0", "v0.1", true)]
|
||||
[DataRow("0.1.0", "0.1", true)]
|
||||
[DataRow("v0.1.0.0.0", "v0.1", true)]
|
||||
[DataRow("0.1.0.0.0", "0.1", true)]
|
||||
[DataRow("v0", "v0", true)]
|
||||
[DataRow("0", "0", true)]
|
||||
[DataRow("v0.1", "v0.1", true)]
|
||||
[DataRow("0.1-release", "0.1-release", true)]
|
||||
[DataRow("v0.1-release", "v0.1-release", true)]
|
||||
[DataRow("v0.1.0.0", "v0.1.0.0.1", false)]
|
||||
[DataRow("v0.1.0.0.1", "v0.1.0.0", false)]
|
||||
[DataRow("v0.9.8.9", "v0.9.8.10", false)]
|
||||
[DataRow("0.1-release", "0.2-release", false)]
|
||||
[DataRow("v1.1-release", "v0.1-release", false)]
|
||||
[TestMethod]
|
||||
public void Equals(string version, string version2, bool result)
|
||||
{
|
||||
var parsedVersion1 = Version.Parse(version);
|
||||
var parsedVersion2 = Version.Parse(version2);
|
||||
|
||||
parsedVersion1.Equals(parsedVersion2).Should().Be(result);
|
||||
}
|
||||
|
||||
[DataRow("v0.1.0.0.1", "v0.1.0.0.1", 0)]
|
||||
[DataRow("v0.1.0.0.1.0.0.0.0", "v0.1.0.0.1", 0)]
|
||||
[DataRow("v0.1.0", "v0.1", 0)]
|
||||
[DataRow("0.1.0", "0.1", 0)]
|
||||
[DataRow("v0.1.0.0.0", "v0.1", 0)]
|
||||
[DataRow("0.1.0.0.0", "0.1", 0)]
|
||||
[DataRow("v0", "v0", 0)]
|
||||
[DataRow("0", "0", 0)]
|
||||
[DataRow("v0.1", "v0.1", 0)]
|
||||
[DataRow("0.1-release", "0.1-release", 0)]
|
||||
[DataRow("v0.1-release", "v0.1-release", 0)]
|
||||
[DataRow("v0.1.0.0", "v0.1.0.0.1", -1)]
|
||||
[DataRow("v0.1.0.0.1", "v0.1.0.0", 1)]
|
||||
[DataRow("v0.9.8.9", "v0.9.8.10", -1)]
|
||||
[DataRow("v0.9.8.10", "v0.9.8.9", 1)]
|
||||
[DataRow("0.1-release", "0.2-release", -1)]
|
||||
[DataRow("v1.1-release", "v0.1-release", 1)]
|
||||
[TestMethod]
|
||||
public void CompareTo(string version, string version2, int comparisonResult)
|
||||
{
|
||||
var parsedVersion1 = Version.Parse(version);
|
||||
var parsedVersion2 = Version.Parse(version2);
|
||||
|
||||
parsedVersion1.CompareTo(parsedVersion2).Should().Be(comparisonResult);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
using Daybreak.Configuration;
|
||||
using Daybreak.Services.Configuration;
|
||||
using Daybreak.Services.Options;
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Moq;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Tests.Services;
|
||||
|
||||
[TestClass]
|
||||
public class ApplicationConfigurationOptionsManagerTests
|
||||
{
|
||||
private ApplicationConfigurationOptionsManager applicationConfigurationOptionsManager;
|
||||
|
||||
[TestInitialize]
|
||||
public void TestInitialize()
|
||||
{
|
||||
var configurationManagerMock = new Mock<IConfigurationManager>();
|
||||
configurationManagerMock
|
||||
.Setup(u => u.GetConfiguration())
|
||||
.Returns(new ApplicationConfiguration());
|
||||
|
||||
this.applicationConfigurationOptionsManager = new ApplicationConfigurationOptionsManager(configurationManagerMock.Object);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetApplicationConfiguration_ReturnsObject()
|
||||
{
|
||||
var config = this.applicationConfigurationOptionsManager.GetOptions<ApplicationConfiguration>();
|
||||
|
||||
config.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetOtherOptions_ThrowsInvalidOperationException()
|
||||
{
|
||||
var action = new Action(() =>
|
||||
{
|
||||
this.applicationConfigurationOptionsManager.GetOptions<object>();
|
||||
});
|
||||
|
||||
action.Should().Throw<InvalidOperationException>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void UpdateOptions_OnApplicationConfiguration_Succeeds()
|
||||
{
|
||||
this.applicationConfigurationOptionsManager.UpdateOptions(new ApplicationConfiguration());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void UpdateOptions_OnOthers_ThrowsInvalidOperationException()
|
||||
{
|
||||
var action = new Action(() =>
|
||||
{
|
||||
this.applicationConfigurationOptionsManager.UpdateOptions(new object());
|
||||
});
|
||||
|
||||
action.Should().Throw<InvalidOperationException>();
|
||||
}
|
||||
}
|
||||
@@ -28,14 +28,14 @@ public class BuildTemplateManagerTests
|
||||
build.Primary.Should().Be(Profession.Assassin);
|
||||
build.Secondary.Should().Be(Profession.None);
|
||||
build.Attributes.Count.Should().Be(4);
|
||||
build.Attributes[0].Attribute.Should().Be(Attribute.DaggerMastery);
|
||||
build.Attributes[1].Attribute.Should().Be(Attribute.DaggerMastery);
|
||||
build.Attributes[1].Points.Should().Be(11);
|
||||
build.Attributes[2].Attribute.Should().Be(Attribute.DeadlyArts);
|
||||
build.Attributes[2].Points.Should().Be(1);
|
||||
build.Attributes[3].Attribute.Should().Be(Attribute.ShadowArts);
|
||||
build.Attributes[3].Points.Should().Be(5);
|
||||
build.Attributes[0].Attribute.Should().Be(Attribute.CriticalStrikes);
|
||||
build.Attributes[0].Points.Should().Be(11);
|
||||
build.Attributes[1].Attribute.Should().Be(Attribute.DeadlyArts);
|
||||
build.Attributes[1].Points.Should().Be(1);
|
||||
build.Attributes[2].Attribute.Should().Be(Attribute.ShadowArts);
|
||||
build.Attributes[2].Points.Should().Be(5);
|
||||
build.Attributes[3].Attribute.Should().Be(Attribute.CriticalStrikes);
|
||||
build.Attributes[3].Points.Should().Be(11);
|
||||
build.Skills.Count.Should().Be(8);
|
||||
build.Skills[0].Should().Be(Skill.UnsuspectingStrike);
|
||||
build.Skills[1].Should().Be(Skill.WildStrike);
|
||||
|
||||
@@ -34,33 +34,47 @@ EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Debug|x64.Build.0 = Debug|x64
|
||||
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Debug|x86.Build.0 = Debug|x86
|
||||
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Release|x64.ActiveCfg = Release|x64
|
||||
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Release|x64.Build.0 = Release|x64
|
||||
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Release|x86.ActiveCfg = Release|x86
|
||||
{AA45C2B1-8BD0-466C-9271-699F168905AF}.Release|x86.Build.0 = Release|x86
|
||||
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Debug|x64.Build.0 = Debug|x64
|
||||
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Debug|x86.Build.0 = Debug|x86
|
||||
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Release|x64.ActiveCfg = Release|x64
|
||||
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Release|x64.Build.0 = Release|x64
|
||||
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Release|x86.ActiveCfg = Release|x86
|
||||
{C911C1C2-6566-419C-89C7-F802EB3FE709}.Release|x86.Build.0 = Release|x86
|
||||
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|x64.Build.0 = Debug|x64
|
||||
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Debug|x86.Build.0 = Debug|x86
|
||||
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|x64.ActiveCfg = Release|x64
|
||||
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|x64.Build.0 = Release|x64
|
||||
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|x86.ActiveCfg = Release|x86
|
||||
{4E2BB805-135D-4F02-8C53-3D8B6876D323}.Release|x86.Build.0 = Release|x86
|
||||
EndGlobalSection
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using Daybreak.Validators;
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Attributes;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public sealed class OptionCustomValidatorAttribute<T> : Attribute
|
||||
where T : IValidator, new()
|
||||
{
|
||||
public IValidator Validator { get; }
|
||||
|
||||
public OptionCustomValidatorAttribute()
|
||||
{
|
||||
this.Validator = Activator.CreateInstance<T>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Attributes;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public sealed class OptionIgnoreAttribute : Attribute
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Attributes;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public sealed class OptionNameAttribute : Attribute
|
||||
{
|
||||
public string Name { get; init; } = string.Empty;
|
||||
public string Description { get; init; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Attributes;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public sealed class OptionRangeAttribute<T> : Attribute
|
||||
where T : IComparable<T>
|
||||
{
|
||||
public T MinValue { get; init; } = default!;
|
||||
public T MaxValue { get; init; } = default!;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Attributes;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public sealed class OptionsIgnoreAttribute : Attribute
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace Daybreak.Attributes;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public sealed class OptionsNameAttribute : Attribute
|
||||
{
|
||||
public string? Name { get; init; }
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
using Daybreak.Models;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Daybreak.Configuration;
|
||||
|
||||
public sealed class ApplicationConfiguration
|
||||
{
|
||||
[JsonProperty("SetGuildwarsWindowSizeOnLaunch")]
|
||||
public bool SetGuildwarsWindowSizeOnLaunch { get; set; }
|
||||
[JsonProperty("DesiredGuildwarsScreen")]
|
||||
public int DesiredGuildwarsScreen { get; set; }
|
||||
[JsonProperty("BrowsersEnabled")]
|
||||
public bool BrowsersEnabled { get; set; } = true;
|
||||
[JsonProperty("ToolboxPath")]
|
||||
public string? ToolboxPath { get; set; }
|
||||
[JsonProperty("TexmodPath")]
|
||||
public string? TexmodPath { get; set; }
|
||||
[JsonProperty("ToolboxAutoLaunch")]
|
||||
public bool ToolboxAutoLaunch { get; set; }
|
||||
[JsonProperty("LeftBrowserDefault")]
|
||||
public string? LeftBrowserDefault { get; set; } = "https://gwpvx.fandom.com/wiki/PvX_wiki";
|
||||
[JsonProperty("RightBrowserDefault")]
|
||||
public string? RightBrowserDefault { get; set; } = "https://wiki.guildwars.com/wiki/Quick_access_links";
|
||||
[JsonProperty("GuildwarsPaths")]
|
||||
public List<GuildwarsPath> GuildwarsPaths { get; set; } = new();
|
||||
[JsonProperty("ProtectedLoginCredentials")]
|
||||
public List<ProtectedLoginCredentials> ProtectedLoginCredentials { get; set; } = new();
|
||||
[JsonProperty("AddressBarReadonly")]
|
||||
public bool AddressBarReadonly { get; set; } = true;
|
||||
[JsonProperty("ExperimentalFeatures")]
|
||||
public ExperimentalFeatures ExperimentalFeatures { get; set; } = new();
|
||||
[JsonProperty("ShortcutLocation")]
|
||||
public string? ShortcutLocation { get; set; } = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||||
[JsonProperty("PlaceShortcut")]
|
||||
public bool PlaceShortcut { get; set; }
|
||||
[JsonProperty("AutoCheckUpdate")]
|
||||
public bool AutoCheckUpdate { get; set; } = true;
|
||||
[JsonProperty("ProtectedGraphAccessToken")]
|
||||
public string? ProtectedGraphAccessToken { get; set; }
|
||||
[JsonProperty("ProtectedGraphRefreshToken")]
|
||||
public string? ProtectedGraphRefreshToken { get; set; }
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using Daybreak.Models;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Daybreak.Configuration;
|
||||
|
||||
public sealed class ExperimentalFeatures
|
||||
{
|
||||
[JsonProperty("MultiLaunchSupport")]
|
||||
public bool MultiLaunchSupport { get; set; }
|
||||
[JsonProperty("ToolboxAutoLaunchDelay")]
|
||||
public int ToolboxAutoLaunchDelay { get; set; } = 5000;
|
||||
[JsonProperty("DynamicBuildLoading")]
|
||||
public bool DynamicBuildLoading { get; set; } = true;
|
||||
[JsonProperty("LaunchGuildwarsAsCurrentUser")]
|
||||
public bool LaunchGuildwarsAsCurrentUser { get; set; } = true;
|
||||
[JsonProperty("CanInterceptKeys")]
|
||||
public bool CanInterceptKeys { get; set; }
|
||||
[JsonProperty("DownloadIcons")]
|
||||
public bool DownloadIcons { get; set; }
|
||||
[JsonProperty("FocusViewEnabled")]
|
||||
public bool FocusViewEnabled { get; set; }
|
||||
[JsonProperty("Macros")]
|
||||
public List<KeyMacro> Macros { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Daybreak.Configuration.FocusView;
|
||||
|
||||
public enum ExperienceDisplay
|
||||
{
|
||||
TotalCurretAndTotalMax,
|
||||
CurrentLevelCurrentAndCurrentLevelMax,
|
||||
RemainingUntilNextLevel,
|
||||
Percentage
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Daybreak.Configuration.FocusView;
|
||||
|
||||
public enum PointsDisplay
|
||||
{
|
||||
CurrentAndMax,
|
||||
Remaining,
|
||||
Percentage
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Daybreak.Attributes;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsName(Name = "Browser")]
|
||||
public sealed class BrowserOptions
|
||||
{
|
||||
[JsonProperty(nameof(Enabled))]
|
||||
[OptionName(Name = "Enabled", Description = "If true, the browser component will be displayed")]
|
||||
public bool Enabled { get; set; } = true;
|
||||
|
||||
[JsonProperty(nameof(AddressBarReadonly))]
|
||||
[OptionName(Name = "Read-only Address Bar", Description = "If true, the browser component will force the address bar to be read-only")]
|
||||
public bool AddressBarReadonly { get; set; } = true;
|
||||
|
||||
[JsonProperty(nameof(DynamicBuildLoading))]
|
||||
[OptionName(Name = "Dynamic Build Loading", Description = "If true, the browser will dynamically parse build templates and prompt the user to load them")]
|
||||
public bool DynamicBuildLoading { get; set; } = true;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using Daybreak.Attributes;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsName(Name = "Build Synchronization")]
|
||||
[OptionsIgnore]
|
||||
public sealed class BuildSynchronizationOptions
|
||||
{
|
||||
[JsonProperty(nameof(ProtectedGraphAccessToken))]
|
||||
public string? ProtectedGraphAccessToken { get; set; }
|
||||
[JsonProperty(nameof(ProtectedGraphRefreshToken))]
|
||||
public string? ProtectedGraphRefreshToken { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
using Daybreak.Attributes;
|
||||
using Daybreak.Configuration.FocusView;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsName(Name = "Focus View")]
|
||||
public sealed class FocusViewOptions
|
||||
{
|
||||
[JsonProperty(nameof(Enabled))]
|
||||
[OptionName(Name = "Enabled", Description = "If true, the focus view is enabled, showing live information from the game")]
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
[JsonProperty(nameof(MemoryReaderFrequency))]
|
||||
[OptionRange<double>(MinValue = 16, MaxValue = 1000)]
|
||||
[OptionName(Name = "Memory Reader Frequency", Description = "Measured in ms. Sets how often should the launcher poll information from the game")]
|
||||
public double MemoryReaderFrequency { get; set; } = 16;
|
||||
|
||||
[JsonProperty(nameof(EnablePathfinding))]
|
||||
[OptionName(Name = "Enable Pathfinding", Description = "If true, the mini-map will attempt to produce paths from the player position to objectives")]
|
||||
public bool EnablePathfinding { get; set; } = true;
|
||||
|
||||
[JsonProperty(nameof(ExperienceDisplay))]
|
||||
[OptionName(Name = "Experience Display Mode", Description = "Sets how should the experience display show the information")]
|
||||
public ExperienceDisplay ExperienceDisplay { get; set; }
|
||||
|
||||
[JsonProperty(nameof(KurzickPointsDisplay))]
|
||||
[OptionName(Name = "Kurzick Points Display Mode", Description = "Sets how should the kurzick points display show the information")]
|
||||
public PointsDisplay KurzickPointsDisplay { get; set; }
|
||||
|
||||
[JsonProperty(nameof(LuxonPointsDisplay))]
|
||||
[OptionName(Name = "Luxon Points Display Mode", Description = "Sets how should the luxon points display show the information")]
|
||||
public PointsDisplay LuxonPointsDisplay { get; set; }
|
||||
|
||||
[JsonProperty(nameof(BalthazarPointsDisplay))]
|
||||
[OptionName(Name = "Balthazar Points Display Mode", Description = "Sets how should the balthazar points display show the information")]
|
||||
public PointsDisplay BalthazarPointsDisplay { get; set; }
|
||||
|
||||
[JsonProperty(nameof(ImperialPointsDisplay))]
|
||||
[OptionName(Name = "Imperial Points Display Mode", Description = "Sets how should the imperial points display show the information")]
|
||||
public PointsDisplay ImperialPointsDisplay { get; set; }
|
||||
|
||||
[JsonProperty(nameof(VanquishingDisplay))]
|
||||
[OptionName(Name = "Vanquishing Display Mode", Description = "Sets how should the vanquishing display show the information")]
|
||||
public PointsDisplay VanquishingDisplay { get; set; }
|
||||
|
||||
[JsonProperty(nameof(HealthDisplay))]
|
||||
[OptionName(Name = "Health Display Mode", Description = "Sets how should the health display show the information")]
|
||||
public PointsDisplay HealthDisplay { get; set; }
|
||||
|
||||
[JsonProperty(nameof(EnergyDisplay))]
|
||||
[OptionName(Name = "Energy Display Mode", Description = "Sets how should the energy display show the information")]
|
||||
public PointsDisplay EnergyDisplay { get; set; }
|
||||
|
||||
[JsonProperty(nameof(BrowserUrl))]
|
||||
[OptionIgnore]
|
||||
public string? BrowserUrl { get; set; } = "https://wiki.guildwars.com/wiki/Main_Page";
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using Daybreak.Attributes;
|
||||
using Daybreak.Models;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsName(Name = "Launcher")]
|
||||
public sealed class LauncherOptions
|
||||
{
|
||||
[JsonProperty(nameof(SetGuildwarsWindowSizeOnLaunch))]
|
||||
[OptionName(Name = "Set GuildWars Window Size On Launch", Description = "Sets the GuildWars window size and position on launch")]
|
||||
public bool SetGuildwarsWindowSizeOnLaunch { get; set; }
|
||||
|
||||
[JsonProperty(nameof(DesiredGuildwarsScreen))]
|
||||
[OptionName(Name = "Desired GuildWars Screen", Description = "Sets the screen on which the GuildWars window will be placed")]
|
||||
public int DesiredGuildwarsScreen { get; set; }
|
||||
|
||||
[JsonProperty(nameof(LaunchGuildwarsAsCurrentUser))]
|
||||
[OptionName(Name = "Launch GuildWars As Current User", Description = "If true, will attempt to launch GuildWars as the current user. Otherwise will attempt to launch as system user")]
|
||||
public bool LaunchGuildwarsAsCurrentUser { get; set; } = true;
|
||||
|
||||
[JsonProperty(nameof(GuildwarsPaths))]
|
||||
[OptionIgnore]
|
||||
public List<GuildwarsPath> GuildwarsPaths { get; set; } = new();
|
||||
|
||||
[JsonProperty(nameof(ProtectedLoginCredentials))]
|
||||
[OptionIgnore]
|
||||
public List<ProtectedLoginCredentials> ProtectedLoginCredentials { get; set; } = new();
|
||||
|
||||
[JsonProperty(nameof(ShortcutLocation))]
|
||||
[OptionName(Name = "Shortcut Location", Description = "Location where the shortcut will be placed")]
|
||||
public string? ShortcutLocation { get; set; } = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||||
|
||||
[JsonProperty(nameof(PlaceShortcut))]
|
||||
[OptionName(Name = "Shortcut Placed", Description = "If true, the shortcut will be placed. If false, the shortcut will be deleted")]
|
||||
public bool PlaceShortcut { get; set; }
|
||||
|
||||
[JsonProperty(nameof(AutoCheckUpdate))]
|
||||
[OptionName(Name = "Auto-Check For Updates", Description = "Automatically check for updates")]
|
||||
public bool AutoCheckUpdate { get; set; } = true;
|
||||
|
||||
[JsonProperty(nameof(MultiLaunchSupport))]
|
||||
[OptionName(Name = "Multi-Launch Support", Description = "If true, the launcher will support multiple executables being launched at the same time")]
|
||||
public bool MultiLaunchSupport { get; set; }
|
||||
|
||||
[JsonProperty(nameof(DownloadIcons))]
|
||||
[OptionName(Name = "Download Icons", Description = "If true, the launcher will perform a check on the local icon cache and download any missing or corrupt icons")]
|
||||
public bool DownloadIcons { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Daybreak.Attributes;
|
||||
|
||||
namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsName(Name = "Screen Manager")]
|
||||
[OptionsIgnore]
|
||||
public sealed class ScreenManagerOptions
|
||||
{
|
||||
public double X { get; set; }
|
||||
public double Y { get; set; }
|
||||
public double Width { get; set; }
|
||||
public double Height { get; set; }
|
||||
public double DpiX { get; set; }
|
||||
public double DpiY { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Daybreak.Attributes;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsName(Name = "GWToolbox")]
|
||||
public sealed class ToolboxOptions
|
||||
{
|
||||
[JsonProperty(nameof(Path))]
|
||||
[OptionName(Name = "Path", Description = "The path to the GWToolbox executable")]
|
||||
public string? Path { get; set; }
|
||||
|
||||
[JsonProperty(nameof(Enabled))]
|
||||
[OptionName(Name = "Enabled", Description = "If true, the launcher will also launch GWToolbox when launching GuildWars")]
|
||||
public bool Enabled { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Daybreak.Attributes;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Daybreak.Configuration.Options;
|
||||
|
||||
[OptionsName(Name = "uMod")]
|
||||
public sealed class UModOptions
|
||||
{
|
||||
[JsonProperty(nameof(Path))]
|
||||
[OptionName(Name = "Path", Description = "The path to the uMod executable")]
|
||||
public string? Path { get; set; }
|
||||
|
||||
[JsonProperty(nameof(Enabled))]
|
||||
[OptionName(Name = "Enabled", Description = "If true, the launcher will also launch uMod when launching GuildWars")]
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
[JsonProperty(nameof(AutoEnableMods))]
|
||||
[OptionName(Name = "Auto-Enable Mods", Description = "If true, mods downloaded through the launcher will be auto-placed in the managed mod list")]
|
||||
public bool AutoEnableMods { get; set; }
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
using Daybreak.Services.ApplicationLauncher;
|
||||
using Daybreak.Services.Bloogum;
|
||||
using Daybreak.Services.BuildTemplates;
|
||||
using Daybreak.Services.Configuration;
|
||||
using Daybreak.Services.Credentials;
|
||||
using Daybreak.Services.IconRetrieve;
|
||||
using Daybreak.Services.Logging;
|
||||
@@ -24,23 +23,44 @@ using Microsoft.CorrelationVector;
|
||||
using System.Logging;
|
||||
using Daybreak.Services.Updater.PostUpdate;
|
||||
using System.Core.Extensions;
|
||||
using Daybreak.Services.Updater.PostUpdate.Actions;
|
||||
using Daybreak.Services.Graph;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Daybreak.Services.Navigation;
|
||||
using Daybreak.Services.Onboarding;
|
||||
using Daybreak.Services.Menu;
|
||||
using Daybreak.Services.Scanner;
|
||||
using Daybreak.Services.Experience;
|
||||
using Daybreak.Services.Metrics;
|
||||
using Daybreak.Services.Monitoring;
|
||||
using System.Net.Http.Headers;
|
||||
using Daybreak.Services.Downloads;
|
||||
using Daybreak.Services.ExceptionHandling;
|
||||
using Daybreak.Services.Pathfinding;
|
||||
using Daybreak.Services.Startup;
|
||||
using Daybreak.Services.Startup.Actions;
|
||||
using Daybreak.Services.Drawing;
|
||||
using Daybreak.Services.Drawing.Modules.Entities;
|
||||
using Daybreak.Services.Drawing.Modules.MapIcons;
|
||||
using Daybreak.Services.Drawing.Modules;
|
||||
using Daybreak.Services.Guildwars;
|
||||
using Daybreak.Configuration.Options;
|
||||
using System.Configuration;
|
||||
using Daybreak.Services.UMod;
|
||||
using Daybreak.Services.Toolbox;
|
||||
using Daybreak.Views.Onboarding.UMod;
|
||||
using Daybreak.Views.Onboarding.Toolbox;
|
||||
|
||||
namespace Daybreak.Configuration;
|
||||
|
||||
public static class ProjectConfiguration
|
||||
{
|
||||
private const string DaybreakUserAgent = "Daybreak";
|
||||
|
||||
public static void RegisterResolvers(IServiceManager serviceManager)
|
||||
{
|
||||
serviceManager.ThrowIfNull();
|
||||
|
||||
serviceManager.RegisterOptionsManager<ApplicationConfigurationOptionsManager>();
|
||||
serviceManager.RegisterOptionsManager<OptionsManager>();
|
||||
serviceManager.RegisterResolver(new LoggerResolver());
|
||||
serviceManager
|
||||
.RegisterHttpClient<ApplicationUpdater>()
|
||||
@@ -49,6 +69,7 @@ public static class ProjectConfiguration
|
||||
var logger = sp.GetService<ILogger<ApplicationUpdater>>();
|
||||
return new LoggingHttpMessageHandler(logger!) { InnerHandler = new HttpClientHandler() };
|
||||
})
|
||||
.WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent)
|
||||
.Build()
|
||||
.RegisterHttpClient<BloogumClient>()
|
||||
.WithMessageHandler(sp =>
|
||||
@@ -56,6 +77,7 @@ public static class ProjectConfiguration
|
||||
var logger = sp.GetService<ILogger<BloogumClient>>();
|
||||
return new LoggingHttpMessageHandler(logger!) { InnerHandler = new HttpClientHandler() };
|
||||
})
|
||||
.WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent)
|
||||
.Build()
|
||||
.RegisterHttpClient<GraphClient>()
|
||||
.WithMessageHandler(sp =>
|
||||
@@ -63,6 +85,15 @@ public static class ProjectConfiguration
|
||||
var logger = sp.GetService<ILogger<GraphClient>>();
|
||||
return new LoggingHttpMessageHandler(logger!) { InnerHandler = new HttpClientHandler() };
|
||||
})
|
||||
.WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent)
|
||||
.Build()
|
||||
.RegisterHttpClient<DownloadService>()
|
||||
.WithMessageHandler(sp =>
|
||||
{
|
||||
var logger = sp.GetService<ILogger<GraphClient>>();
|
||||
return new LoggingHttpMessageHandler(logger!) { InnerHandler = new HttpClientHandler() };
|
||||
})
|
||||
.WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent)
|
||||
.Build();
|
||||
}
|
||||
|
||||
@@ -86,6 +117,8 @@ public static class ProjectConfiguration
|
||||
|
||||
services.AddScoped((sp) => new ScopeMetadata(new CorrelationVector()));
|
||||
services.AddSingleton<ViewManager>();
|
||||
services.AddSingleton<ProcessorUsageMonitor>();
|
||||
services.AddSingleton<MemoryUsageMonitor>();
|
||||
services.AddSingleton<IViewManager, ViewManager>(sp => sp.GetRequiredService<ViewManager>());
|
||||
services.AddSingleton<IViewProducer, ViewManager>(sp => sp.GetRequiredService<ViewManager>());
|
||||
services.AddSingleton<PostUpdateActionManager>();
|
||||
@@ -94,12 +127,16 @@ public static class ProjectConfiguration
|
||||
services.AddSingleton<IPostUpdateActionProvider>(sp => sp.GetRequiredService<PostUpdateActionManager>());
|
||||
services.AddSingleton<IMenuService, MenuService>();
|
||||
services.AddSingleton<IMenuServiceInitializer, MenuService>(sp => sp.GetRequiredService<IMenuService>().As<MenuService>());
|
||||
services.AddSingleton<IConfigurationManager, ConfigurationManager>();
|
||||
services.AddSingleton<ILiteDatabase, LiteDatabase>(sp => new LiteDatabase("Daybreak.db"));
|
||||
services.AddSingleton<IMutexHandler, MutexHandler>();
|
||||
services.AddSingleton<IShortcutManager, ShortcutManager>();
|
||||
services.AddSingleton<IIconBrowser, IconBrowser>();
|
||||
services.AddSingleton<IIconDownloader, IconDownloader>();
|
||||
services.AddSingleton<IMetricsService, MetricsService>();
|
||||
services.AddSingleton<IStartupActionProducer, StartupActionManager>();
|
||||
services.AddSingleton<IOptionsProducer, OptionsManager>(sp => sp.GetRequiredService<IOptionsManager>().As<OptionsManager>());
|
||||
services.AddSingleton<IOptionsUpdateHook, OptionsManager>(sp => sp.GetRequiredService<IOptionsManager>().As<OptionsManager>());
|
||||
services.AddSingleton<IOptionsProvider, OptionsManager>(sp => sp.GetRequiredService<IOptionsManager>().As<OptionsManager>());
|
||||
services.AddScoped<ICredentialManager, CredentialManager>();
|
||||
services.AddScoped<IApplicationLauncher, ApplicationLauncher>();
|
||||
services.AddScoped<IScreenshotProvider, ScreenshotProvider>();
|
||||
@@ -113,6 +150,17 @@ public static class ProjectConfiguration
|
||||
services.AddScoped<IOnboardingService, OnboardingService>();
|
||||
services.AddScoped<IGuildwarsMemoryReader, GuildwarsMemoryReader>();
|
||||
services.AddScoped<IMemoryScanner, MemoryScanner>();
|
||||
services.AddScoped<IExperienceCalculator, ExperienceCalculator>();
|
||||
services.AddScoped<IAttributePointCalculator, AttributePointCalculator>();
|
||||
services.AddScoped<IDownloadService, DownloadService>();
|
||||
services.AddScoped<IGuildwarsInstaller, GuildwarsInstaller>();
|
||||
services.AddScoped<IGuildwarsEntityDebouncer, GuildwarsEntityDebouncer>();
|
||||
services.AddScoped<IExceptionHandler, ExceptionHandler>();
|
||||
services.AddScoped<IPathfinder, StupidPathfinder>();
|
||||
services.AddScoped<IDrawingService, DrawingService>();
|
||||
services.AddScoped<IDrawingModuleProducer, DrawingService>(sp => sp.GetRequiredService<IDrawingService>().As<DrawingService>());
|
||||
services.AddScoped<IUModService, UModService>();
|
||||
services.AddScoped<IToolboxService, ToolboxService>();
|
||||
}
|
||||
|
||||
public static void RegisterViews(IViewProducer viewProducer)
|
||||
@@ -120,11 +168,10 @@ public static class ProjectConfiguration
|
||||
viewProducer.ThrowIfNull();
|
||||
|
||||
viewProducer.RegisterPermanentView<LauncherView>();
|
||||
viewProducer.RegisterView<SettingsView>();
|
||||
viewProducer.RegisterPermanentView<Views.FocusView>();
|
||||
viewProducer.RegisterView<AskUpdateView>();
|
||||
viewProducer.RegisterView<UpdateView>();
|
||||
viewProducer.RegisterView<AccountsView>();
|
||||
viewProducer.RegisterView<ExperimentalSettingsView>();
|
||||
viewProducer.RegisterView<ExecutablesView>();
|
||||
viewProducer.RegisterView<BuildTemplateView>();
|
||||
viewProducer.RegisterView<BuildsListView>();
|
||||
@@ -135,14 +182,83 @@ public static class ProjectConfiguration
|
||||
viewProducer.RegisterView<IconDownloadView>();
|
||||
viewProducer.RegisterView<GraphAuthorizationView>();
|
||||
viewProducer.RegisterView<BuildsSynchronizationView>();
|
||||
viewProducer.RegisterView<OnboardingView>();
|
||||
viewProducer.RegisterView<FocusView>();
|
||||
viewProducer.RegisterView<LauncherOnboardingView>();
|
||||
viewProducer.RegisterView<MetricsView>();
|
||||
viewProducer.RegisterView<GuildwarsDownloadView>();
|
||||
viewProducer.RegisterView<UModInstallingView>();
|
||||
viewProducer.RegisterView<UModInstallationChoiceView>();
|
||||
viewProducer.RegisterView<UModOnboardingEntryView>();
|
||||
viewProducer.RegisterView<UModSwitchView>();
|
||||
viewProducer.RegisterView<UModBrowserView>();
|
||||
viewProducer.RegisterView<ToolboxInstallationView>();
|
||||
viewProducer.RegisterView<ToolboxInstallationChoiceView>();
|
||||
viewProducer.RegisterView<ToolboxOnboardingEntryView>();
|
||||
viewProducer.RegisterView<ToolboxSwitchView>();
|
||||
viewProducer.RegisterView<ToolboxHomepageView>();
|
||||
viewProducer.RegisterView<OptionSectionView>();
|
||||
}
|
||||
|
||||
public static void RegisterStartupActions(IStartupActionProducer startupActionProducer)
|
||||
{
|
||||
startupActionProducer.ThrowIfNull();
|
||||
|
||||
startupActionProducer.RegisterAction<RenameInstallerAction>();
|
||||
}
|
||||
|
||||
public static void RegisterPostUpdateActions(IPostUpdateActionProducer postUpdateActionProducer)
|
||||
{
|
||||
postUpdateActionProducer.ThrowIfNull();
|
||||
}
|
||||
|
||||
postUpdateActionProducer.AddPostUpdateAction<RenameInstallerAction>();
|
||||
public static void RegisterDrawingModules(IDrawingModuleProducer drawingModuleProducer)
|
||||
{
|
||||
drawingModuleProducer.ThrowIfNull();
|
||||
|
||||
|
||||
drawingModuleProducer.RegisterDrawingModule<DeadEntityDrawingModule>();
|
||||
drawingModuleProducer.RegisterDrawingModule<NeutralEntityDrawingModule>();
|
||||
drawingModuleProducer.RegisterDrawingModule<AlliedCreatureEntityDrawingModule>();
|
||||
drawingModuleProducer.RegisterDrawingModule<AllyEntityDrawingModule>();
|
||||
drawingModuleProducer.RegisterDrawingModule<BossEntityDrawingModule>();
|
||||
drawingModuleProducer.RegisterDrawingModule<EnemyEntityDrawingModule>();
|
||||
drawingModuleProducer.RegisterDrawingModule<NpcEntityDrawingModule>();
|
||||
|
||||
drawingModuleProducer.RegisterDrawingModule<ResurrectionShrineDrawingModule>();
|
||||
drawingModuleProducer.RegisterDrawingModule<CollectorDrawingModule>();
|
||||
drawingModuleProducer.RegisterDrawingModule<GateDrawingModule>();
|
||||
drawingModuleProducer.RegisterDrawingModule<StairsDownDrawingModule>();
|
||||
drawingModuleProducer.RegisterDrawingModule<StairsUpDrawingModule>();
|
||||
drawingModuleProducer.RegisterDrawingModule<CircledStarDrawingModule>();
|
||||
drawingModuleProducer.RegisterDrawingModule<AreaMapDrawingModule>();
|
||||
drawingModuleProducer.RegisterDrawingModule<DungeonBossDrawingModule>();
|
||||
drawingModuleProducer.RegisterDrawingModule<DungeonKeyDrawingModule>();
|
||||
|
||||
drawingModuleProducer.RegisterDrawingModule<PathfindingDrawingModule>();
|
||||
drawingModuleProducer.RegisterDrawingModule<PlayerPositionHistoryDrawingModule>();
|
||||
drawingModuleProducer.RegisterDrawingModule<QuestObjectiveDrawingModule>();
|
||||
|
||||
drawingModuleProducer.RegisterDrawingModule<MainPlayerDrawingModule>();
|
||||
drawingModuleProducer.RegisterDrawingModule<PartyMemberDrawingModule>();
|
||||
drawingModuleProducer.RegisterDrawingModule<WorldPlayerDrawingModule>();
|
||||
|
||||
drawingModuleProducer.RegisterDrawingModule<EngagementAreaDrawingModule>();
|
||||
}
|
||||
|
||||
public static void RegisterOptions(IOptionsProducer optionsProducer)
|
||||
{
|
||||
optionsProducer.ThrowIfNull();
|
||||
|
||||
optionsProducer.RegisterOptions<BrowserOptions>();
|
||||
optionsProducer.RegisterOptions<BuildSynchronizationOptions>();
|
||||
optionsProducer.RegisterOptions<FocusViewOptions>();
|
||||
optionsProducer.RegisterOptions<LauncherOptions>();
|
||||
optionsProducer.RegisterOptions<ToolboxOptions>();
|
||||
optionsProducer.RegisterOptions<UModOptions>();
|
||||
optionsProducer.RegisterOptions<ScreenManagerOptions>();
|
||||
}
|
||||
|
||||
private static void SetupDaybreakUserAgent(HttpRequestHeaders httpRequestHeaders)
|
||||
{
|
||||
httpRequestHeaders.ThrowIfNull().TryAddWithoutValidation("User-Agent", DaybreakUserAgent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
Cursor="Hand"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Viewbox>
|
||||
<Grid>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
Cursor="Hand"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Viewbox>
|
||||
<Grid>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
Cursor="Hand"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Viewbox>
|
||||
<Grid>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
Cursor="Hand"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Viewbox>
|
||||
<Grid>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
Cursor="Hand"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<Ellipse x:Name="BackgroundEllipse" Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Visibility="Visible" Opacity="0.1" />
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
Cursor="Hand"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Viewbox>
|
||||
<Grid>
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
mc:Ignorable="d"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
Cursor="Hand"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Viewbox>
|
||||
<Grid>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
x:Name="_this"
|
||||
Cursor="Hand"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="50" d:DesignWidth="50">
|
||||
<Grid>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
xmlns:behaviors="clr-namespace:Daybreak.Behaviors"
|
||||
xmlns:converters="clr-namespace:Daybreak.Converters"
|
||||
x:Name="_this"
|
||||
Cursor="Hand"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<UserControl.Resources>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
Cursor="Hand"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Viewbox>
|
||||
<Grid>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
Cursor="Hand"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<UserControl.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"></BooleanToVisibilityConverter>
|
||||
@@ -20,13 +21,12 @@
|
||||
FontStretch="{Binding ElementName=_this, Path=FontStretch, Mode=OneWay}"
|
||||
FontWeight="{Binding ElementName=_this, Path=FontWeight, Mode=OneWay}"
|
||||
FontStyle="{Binding ElementName=_this, Path=FontStyle, Mode=OneWay}"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"></TextBlock>
|
||||
VerticalAlignment="{Binding ElementName=_this, Path=TextVerticalAlignment, Mode=OneWay}"
|
||||
HorizontalAlignment="{Binding ElementName=_this, Path=TextHorizontalAlignment, Mode=OneWay}"></TextBlock>
|
||||
<Rectangle Fill="{Binding ElementName=_this, Path=Highlight, Mode=OneWay}"
|
||||
Opacity="{Binding ElementName=_this, Path=HighlightOpacity, Mode=OneWay}"
|
||||
Visibility="{Binding ElementName=_this, Path=HighlightVisible, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}"></Rectangle>
|
||||
<Rectangle MouseEnter="Rectangle_MouseEnter" MouseLeave="Rectangle_MouseLeave"
|
||||
MouseLeftButtonDown="Rectangle_MouseLeftButtonDown" Fill="Transparent"
|
||||
Cursor="Hand"></Rectangle>
|
||||
MouseLeftButtonDown="Rectangle_MouseLeftButtonDown" Fill="Transparent"></Rectangle>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@@ -26,6 +26,10 @@ public partial class OpaqueButton : UserControl
|
||||
public double highlightOpacity;
|
||||
[GenerateDependencyProperty]
|
||||
public bool highlightVisible;
|
||||
[GenerateDependencyProperty(InitialValue = VerticalAlignment.Center)]
|
||||
public VerticalAlignment textVerticalAlignment;
|
||||
[GenerateDependencyProperty(InitialValue = HorizontalAlignment.Center)]
|
||||
public HorizontalAlignment textHorizontalAlignment;
|
||||
|
||||
public OpaqueButton()
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
x:Name="_this"
|
||||
Cursor="Hand"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Viewbox>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
Cursor="Hand"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Viewbox>
|
||||
<Grid>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
xmlns:behaviors="clr-namespace:Daybreak.Behaviors"
|
||||
xmlns:converters="clr-namespace:Daybreak.Converters"
|
||||
x:Name="_this"
|
||||
Cursor="Hand"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<UserControl.Resources>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
mc:Ignorable="d"
|
||||
Unloaded="UserControl_Unloaded"
|
||||
x:Name="_this"
|
||||
Initialized="UserControl_Initialized"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<UserControl.Resources>
|
||||
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" TriggerValue="True"></converters:BooleanToVisibilityConverter>
|
||||
@@ -19,7 +20,7 @@
|
||||
<ContextMenu.Template>
|
||||
<ControlTemplate>
|
||||
<StackPanel Margin="10">
|
||||
<local:OpaqueButton Text="Load build template" Foreground="White" Background="#F0202020" BackgroundOpacity="0.4"
|
||||
<local:OpaqueButton Text="Load build template" Foreground="White" Background="#F0212121" BackgroundOpacity="0.4"
|
||||
Clicked="LoadBuildTemplateButton_Click" FontSize="16" Height="40" Width="200"></local:OpaqueButton>
|
||||
</StackPanel>
|
||||
</ControlTemplate>
|
||||
@@ -33,7 +34,7 @@
|
||||
</Grid.RowDefinitions>
|
||||
<wv2:WebView2 x:Name="WebBrowser" Source="{Binding ElementName=_this, Path=Address, Mode=TwoWay}"
|
||||
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"></wv2:WebView2>
|
||||
<Grid Grid.Row="1" Background="#80808080" IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"
|
||||
<Grid Grid.Row="1" Background="#F0212121" IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"
|
||||
Visibility="{Binding ElementName=_this, Path=ControlsEnabled, Mode=OneWay, Converter={StaticResource ReverseBooleanToVisibilityConverter}}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"></ColumnDefinition>
|
||||
@@ -69,17 +70,19 @@
|
||||
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"></TextBox>
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal">
|
||||
<local:HomeButton Width="30" Height="30" Margin="5"
|
||||
Visibility="{Binding ElementName=_this, Path=HomeButtonVisible, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"
|
||||
Clicked="HomeButton_Clicked"></local:HomeButton>
|
||||
<local:StarGlyph Height="30" Width="30" Margin="5"
|
||||
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"
|
||||
Clicked="StarGlyph_Clicked" x:Name="FavoriteButton"></local:StarGlyph>
|
||||
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
Visibility="{Binding ElementName=_this, Path=HomeButtonVisible, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"
|
||||
Clicked="StarGlyph_Clicked" x:Name="FavoriteButton"></local:StarGlyph>
|
||||
<local:MaximizeButton Height="30" Width="30" Margin="5"
|
||||
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"
|
||||
Clicked="MaximizeButton_Clicked"></local:MaximizeButton>
|
||||
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"
|
||||
Clicked="MaximizeButton_Clicked"></local:MaximizeButton>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<Grid Grid.RowSpan="2" Background="Gray"
|
||||
@@ -95,6 +98,5 @@
|
||||
<TextBlock Foreground="White" Text="Restart after the installation." FontSize="26" TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Daybreak.Configuration;
|
||||
using Daybreak.Configuration.Options;
|
||||
using Daybreak.Models.Browser;
|
||||
using Daybreak.Models.Guildwars;
|
||||
using Daybreak.Services.BuildTemplates;
|
||||
@@ -8,8 +8,12 @@ using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Core.Extensions;
|
||||
using System.Diagnostics;
|
||||
using System.Extensions;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
@@ -26,23 +30,32 @@ public partial class ChromiumBrowserWrapper : UserControl
|
||||
{
|
||||
public static readonly DependencyProperty AddressProperty =
|
||||
DependencyPropertyExtensions.Register<ChromiumBrowserWrapper, string>(nameof(Address));
|
||||
|
||||
|
||||
private const string BrowserSearchPlaceholder = "[PLACEHOLDER]";
|
||||
private const string BrowserSearchLink = $"https://www.google.com/search?q={BrowserSearchPlaceholder}";
|
||||
private const string BrowserDownloadLink = "https://developer.microsoft.com/en-us/microsoft-edge/webview2/";
|
||||
|
||||
private static readonly Regex WebAddressRegex = new("^((http|ftp|https)://)?([\\w_-]+(?:(?:\\.[\\w_-]+)+))([\\w.,@?^=%&:/~+#-]*[\\w@?^=%&/~+#-])?", RegexOptions.Compiled);
|
||||
|
||||
private static CoreWebView2Environment? coreWebView2Environment;
|
||||
|
||||
public event EventHandler<string>? FavoriteUriChanged;
|
||||
public event EventHandler? MaximizeClicked;
|
||||
public event EventHandler<Build>? BuildDecoded;
|
||||
public event EventHandler<DownloadPayload>? DownloadingFile;
|
||||
public event EventHandler<string>? DownloadedFile;
|
||||
|
||||
private ILiveOptions<ApplicationConfiguration>? liveOptions;
|
||||
private ILogger<ChromiumBrowserWrapper>? logger;
|
||||
private IBuildTemplateManager? buildTemplateManager;
|
||||
private readonly Task initializationTask;
|
||||
private readonly ILiveOptions<BrowserOptions>? liveOptions;
|
||||
private readonly ILogger<ChromiumBrowserWrapper>? logger;
|
||||
private readonly IBuildTemplateManager? buildTemplateManager;
|
||||
|
||||
[GenerateDependencyProperty(InitialValue = true)]
|
||||
private bool canDownloadBuild;
|
||||
[GenerateDependencyProperty(InitialValue = true)]
|
||||
private bool canNavigate;
|
||||
[GenerateDependencyProperty(InitialValue = false)]
|
||||
private bool canDownloadFiles;
|
||||
[GenerateDependencyProperty(InitialValue = true)]
|
||||
private bool controlsEnabled;
|
||||
[GenerateDependencyProperty(InitialValue = null)]
|
||||
@@ -57,6 +70,13 @@ public partial class ChromiumBrowserWrapper : UserControl
|
||||
private string favoriteAddress = string.Empty;
|
||||
[GenerateDependencyProperty(InitialValue = false)]
|
||||
private bool preventDispose;
|
||||
[GenerateDependencyProperty(InitialValue = true)]
|
||||
private bool homeButtonVisible = true;
|
||||
[GenerateDependencyProperty(InitialValue = true)]
|
||||
private bool favoriteButtonVisible = true;
|
||||
[GenerateDependencyProperty]
|
||||
private string downloadsDirectory = string.Empty;
|
||||
|
||||
public string Address
|
||||
{
|
||||
get => this.GetTypedValue<string>(AddressProperty);
|
||||
@@ -70,9 +90,23 @@ public partial class ChromiumBrowserWrapper : UserControl
|
||||
}
|
||||
|
||||
public ChromiumBrowserWrapper()
|
||||
: this(Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<ILiveOptions<BrowserOptions>>(),
|
||||
Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IBuildTemplateManager>(),
|
||||
Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<ILogger<ChromiumBrowserWrapper>>())
|
||||
{
|
||||
}
|
||||
|
||||
public ChromiumBrowserWrapper(
|
||||
ILiveOptions<BrowserOptions> liveOptions,
|
||||
IBuildTemplateManager buildTemplateManager,
|
||||
ILogger<ChromiumBrowserWrapper> logger)
|
||||
{
|
||||
this.liveOptions = liveOptions.ThrowIfNull();
|
||||
this.buildTemplateManager = buildTemplateManager.ThrowIfNull();
|
||||
this.logger = logger.ThrowIfNull();
|
||||
this.initializationTask = this.InitializeBrowser();
|
||||
|
||||
this.InitializeComponent();
|
||||
this.WebBrowser.IsEnabled = false;
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
|
||||
@@ -84,35 +118,22 @@ public partial class ChromiumBrowserWrapper : UserControl
|
||||
}
|
||||
}
|
||||
|
||||
public async Task InitializeDefaultBrowser()
|
||||
public async Task ReinitializeBrowser()
|
||||
{
|
||||
var options = Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<ILiveOptions<ApplicationConfiguration>>();
|
||||
var buildTemplateManager = Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IBuildTemplateManager>();
|
||||
var logger = Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<ILogger<ChromiumBrowserWrapper>>();
|
||||
|
||||
await this.InitializeDefaultBrowser(options, buildTemplateManager, logger);
|
||||
}
|
||||
|
||||
public async Task InitializeDefaultBrowser(
|
||||
ILiveOptions<ApplicationConfiguration> liveOptions,
|
||||
IBuildTemplateManager buildTemplateManager,
|
||||
ILogger<ChromiumBrowserWrapper> logger)
|
||||
{
|
||||
this.liveOptions = liveOptions;
|
||||
this.buildTemplateManager = buildTemplateManager;
|
||||
this.logger = logger;
|
||||
this.InitializeEnvironment();
|
||||
await this.InitializeBrowser();
|
||||
}
|
||||
|
||||
public async void ReinitializeBrowser()
|
||||
public Task InitializationTask() => this.initializationTask;
|
||||
|
||||
private async void UserControl_Initialized(object sender, EventArgs e)
|
||||
{
|
||||
this.InitializeEnvironment();
|
||||
await this.InitializeBrowser();
|
||||
}
|
||||
|
||||
private void InitializeEnvironment()
|
||||
{
|
||||
if (this.liveOptions!.Value.BrowsersEnabled is false)
|
||||
if (this.liveOptions!.Value.Enabled is false)
|
||||
{
|
||||
this.BrowserSupported = false;
|
||||
return;
|
||||
@@ -120,7 +141,11 @@ public partial class ChromiumBrowserWrapper : UserControl
|
||||
|
||||
try
|
||||
{
|
||||
coreWebView2Environment ??= System.Extensions.TaskExtensions.RunSync(() => CoreWebView2Environment.CreateAsync(null, "BrowserData", null));
|
||||
coreWebView2Environment ??= System.Extensions.TaskExtensions.RunSync(() => CoreWebView2Environment.CreateAsync(null, "BrowserData", new CoreWebView2EnvironmentOptions
|
||||
{
|
||||
EnableTrackingPrevention = true,
|
||||
AllowSingleSignOnUsingOSPrimaryAccount = true
|
||||
}));
|
||||
|
||||
this.BrowserSupported = true;
|
||||
}
|
||||
@@ -139,7 +164,7 @@ public partial class ChromiumBrowserWrapper : UserControl
|
||||
this.BrowserEnabled = true;
|
||||
await this.WebBrowser.EnsureCoreWebView2Async(coreWebView2Environment);
|
||||
this.AddressBarReadonly = this.liveOptions!.Value.AddressBarReadonly;
|
||||
this.CanDownloadBuild = this.liveOptions.Value.ExperimentalFeatures.DynamicBuildLoading;
|
||||
this.CanDownloadBuild = this.liveOptions.Value.DynamicBuildLoading;
|
||||
this.WebBrowser.CoreWebView2.NewWindowRequested += (browser, args) => args.Handled = true;
|
||||
this.WebBrowser.NavigationStarting += (browser, args) =>
|
||||
{
|
||||
@@ -152,6 +177,35 @@ public partial class ChromiumBrowserWrapper : UserControl
|
||||
this.Navigating = true;
|
||||
}
|
||||
};
|
||||
this.WebBrowser.CoreWebView2.DownloadStarting += (browser, args) =>
|
||||
{
|
||||
if (this.CanDownloadFiles is false)
|
||||
{
|
||||
this.logger?.LogInformation("Downloads are disallowed. Cancelling download");
|
||||
args.Cancel = true;
|
||||
}
|
||||
|
||||
if (this.DownloadsDirectory.IsNullOrWhiteSpace())
|
||||
{
|
||||
this.logger?.LogInformation("No downloads directory specified. Downloading to default directory");
|
||||
return;
|
||||
}
|
||||
|
||||
var fileName = Path.GetFileName(args.ResultFilePath);
|
||||
var finalPath = Path.GetFullPath(Path.Combine(this.DownloadsDirectory, fileName));
|
||||
var downloadPayload = new DownloadPayload { ResultingFilePath = finalPath, CanDownload = true };
|
||||
this.DownloadingFile?.Invoke(this, downloadPayload);
|
||||
if (!downloadPayload.CanDownload)
|
||||
{
|
||||
args.Cancel = true;
|
||||
this.logger?.LogInformation("Download blocked by handler. Cancelling download");
|
||||
return;
|
||||
}
|
||||
|
||||
args.ResultFilePath = finalPath;
|
||||
|
||||
args.DownloadOperation.StateChanged += this.DownloadOperation_StateChanged;
|
||||
};
|
||||
this.WebBrowser.NavigationCompleted += (browser, args) => this.Navigating = false;
|
||||
this.WebBrowser.WebMessageReceived += this.CoreWebView2_WebMessageReceived!;
|
||||
this.WebBrowser.CoreWebView2.Settings.AreDevToolsEnabled = false;
|
||||
@@ -188,14 +242,19 @@ public partial class ChromiumBrowserWrapper : UserControl
|
||||
{
|
||||
if (e.Key == System.Windows.Input.Key.Enter)
|
||||
{
|
||||
var newAddress = sender.As<TextBox>().Text;
|
||||
newAddress = SanitizeAddress(newAddress);
|
||||
if (newAddress.IsNullOrWhiteSpace())
|
||||
var input = sender.As<TextBox>().Text;
|
||||
var maybeAddress = SanitizeAddress(input);
|
||||
// If input is address, navigate to address. Otherwise search for the text input in Google
|
||||
if (Uri.TryCreate(maybeAddress, UriKind.Absolute, out _))
|
||||
{
|
||||
return;
|
||||
this.Address = maybeAddress;
|
||||
}
|
||||
else
|
||||
{
|
||||
var address = BrowserSearchLink.Replace(BrowserSearchPlaceholder, maybeAddress);
|
||||
this.Address = address;
|
||||
}
|
||||
|
||||
this.Address = newAddress;
|
||||
this.WebBrowser.CoreWebView2.Navigate(this.Address);
|
||||
e.Handled = true;
|
||||
}
|
||||
@@ -251,6 +310,24 @@ public partial class ChromiumBrowserWrapper : UserControl
|
||||
}
|
||||
}
|
||||
|
||||
private void DownloadOperation_StateChanged(object? sender, object? e)
|
||||
{
|
||||
if (sender is not CoreWebView2DownloadOperation downloadOperation)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (downloadOperation.State != CoreWebView2DownloadState.Completed &&
|
||||
downloadOperation.State != CoreWebView2DownloadState.Interrupted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
downloadOperation.StateChanged -= this.DownloadOperation_StateChanged;
|
||||
var filePath = Path.GetFullPath(downloadOperation.ResultFilePath);
|
||||
this.DownloadedFile?.Invoke(this, filePath);
|
||||
}
|
||||
|
||||
private void LoadBuildTemplateButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
var build = this.ContextMenu.DataContext.As<Build>();
|
||||
@@ -326,6 +403,11 @@ public partial class ChromiumBrowserWrapper : UserControl
|
||||
return default!;
|
||||
}
|
||||
|
||||
if (WebAddressRegex.IsMatch(address) is false)
|
||||
{
|
||||
return address;
|
||||
}
|
||||
|
||||
if (address.StartsWith("www") is false &&
|
||||
address.StartsWith("http") is false)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
<UserControl x:Class="Daybreak.Controls.ExpandableMenuSection"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
xmlns:buttons="clr-namespace:Daybreak.Controls.Buttons"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<UserControl.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"></BooleanToVisibilityConverter>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<StackPanel Orientation="Vertical"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch">
|
||||
<buttons:MenuButton
|
||||
Cursor="Hand"
|
||||
HighlightColor="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
Title="{Binding ElementName=_this, Path=SectionTitle, Mode=OneWay}"
|
||||
FontSize="{Binding ElementName=_this, Path=FontSize, Mode=OneWay}"
|
||||
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
Clicked="MenuButton_Clicked"
|
||||
IsEnabled="{Binding ElementName=_this, Path=ExpanderButtonEnabled, Mode=OneWay}"
|
||||
Height="30"></buttons:MenuButton>
|
||||
<Rectangle Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Height="1"
|
||||
HorizontalAlignment="Stretch"></Rectangle>
|
||||
<Grid MaxHeight="{Binding ElementName=_this, Path=ExpanderHeight, Mode=OneWay}"
|
||||
Margin="10, 0, 0, 0">
|
||||
<ItemsControl x:Name="ContentListView"
|
||||
ItemsSource="{Binding ElementName=_this, Path=Children, Mode=OneWay}"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"></ItemsControl>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Extensions;
|
||||
using System.Windows.Media.Animation;
|
||||
|
||||
namespace Daybreak.Controls;
|
||||
/// <summary>
|
||||
/// Interaction logic for ExpandableMenuSection.xaml
|
||||
/// </summary>
|
||||
public partial class ExpandableMenuSection : UserControl
|
||||
{
|
||||
[GenerateDependencyProperty]
|
||||
private string sectionTitle = string.Empty;
|
||||
[GenerateDependencyProperty]
|
||||
private double expanderHeight = 0;
|
||||
[GenerateDependencyProperty(InitialValue = true)]
|
||||
private bool expanderButtonEnabled;
|
||||
[GenerateDependencyProperty(InitialValue = false)]
|
||||
private bool expanded = false;
|
||||
|
||||
public ObservableCollection<FrameworkElement> Children { get; } = new ObservableCollection<FrameworkElement>();
|
||||
|
||||
public ExpandableMenuSection()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
private void MenuButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
this.ExpanderButtonEnabled = false;
|
||||
var desiredHeight = 0d;
|
||||
foreach (var child in this.Children)
|
||||
{
|
||||
desiredHeight += child.DesiredSize.Height > 0 ?
|
||||
child.DesiredSize.Height :
|
||||
double.IsNaN(child.Height) ?
|
||||
0 :
|
||||
child.Height;
|
||||
}
|
||||
|
||||
var doubleAnimation = new DoubleAnimation();
|
||||
|
||||
if (this.expanded)
|
||||
{
|
||||
doubleAnimation.From = desiredHeight;
|
||||
doubleAnimation.To = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
doubleAnimation.From = 0;
|
||||
doubleAnimation.To = desiredHeight;
|
||||
}
|
||||
|
||||
doubleAnimation.AccelerationRatio = 0.3;
|
||||
doubleAnimation.DecelerationRatio = 0.3;
|
||||
doubleAnimation.Duration = TimeSpan.FromMilliseconds(100);
|
||||
doubleAnimation.Completed += (_, _) =>
|
||||
{
|
||||
this.Expanded = !this.Expanded;
|
||||
this.ExpanderButtonEnabled = true;
|
||||
};
|
||||
|
||||
this.BeginAnimation(ExpanderHeightProperty, doubleAnimation);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<UserControl x:Class="Daybreak.Controls.Glyphs.DownloadGlyph"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls.Glyphs"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Viewbox>
|
||||
<Grid>
|
||||
<Path Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" StrokeThickness="3"
|
||||
Data="m32,30.454c0,0 8.312,0 9.098,0c4.365,0 7.902,-3.537 7.902,-7.901s-3.537,-7.902 -7.902,-7.902c-0.02,0 -0.038,0.003 -0.058,0.003c0.061,-0.494 0.103,-0.994 0.103,-1.504c0,-6.71 -5.439,-12.15 -12.15,-12.15c-5.229,0 -9.672,3.309 -11.386,7.941c-1.087,-1.089 -2.591,-1.764 -4.251,-1.764c-3.319,0 -6.009,2.69 -6.009,6.008c0,0.085 0.01,0.167 0.013,0.251c-3.665,1.013 -6.36,4.362 -6.36,8.349c0,4.788 3.881,8.669 8.67,8.669c0.827,0 8.33,0 8.33,0"></Path>
|
||||
<Polyline Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Points="30,36 25,41 20,36" StrokeThickness="3"></Polyline>
|
||||
<Line X1="25" X2="25" Y1="21" Y2="41" Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" StrokeThickness="3"></Line>
|
||||
</Grid>
|
||||
</Viewbox>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Daybreak.Controls.Glyphs;
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for DownloadGlyph.xaml
|
||||
/// </summary>
|
||||
public partial class DownloadGlyph : UserControl
|
||||
{
|
||||
public DownloadGlyph()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,4 @@
|
||||
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.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Daybreak.Controls;
|
||||
|
||||
|
||||
@@ -1,17 +1,4 @@
|
||||
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.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Daybreak.Controls;
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<UserControl x:Class="Daybreak.Controls.Glyphs.GWToolboxGlyph"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls.Glyphs"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Viewbox>
|
||||
<TextBlock Text="G" Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></TextBlock>
|
||||
</Viewbox>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,26 @@
|
||||
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.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace Daybreak.Controls.Glyphs;
|
||||
/// <summary>
|
||||
/// Interaction logic for GWToolboxGlyph.xaml
|
||||
/// </summary>
|
||||
public partial class GWToolboxGlyph : UserControl
|
||||
{
|
||||
public GWToolboxGlyph()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<UserControl x:Class="Daybreak.Controls.Glyphs.GaugeGlyph"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls.Glyphs"
|
||||
mc:Ignorable="d"
|
||||
Name="_this"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Viewbox>
|
||||
<Grid>
|
||||
<Path Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
Data="m13.5,13.5c1.44772,-1.44772 2.5,-3.29086 2.5,-5.5c0,-4.41828 -3.58172,-8 -8,-8s-8,3.58172 -8,8c0,2.20914 1.05228,4.05228 2.5,5.5"></Path>
|
||||
<Path Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
Data="m8,8l-4,-4"></Path>
|
||||
<Ellipse Margin="6, 7.5, 6, 6" Width="1.5" Height="1.5"
|
||||
Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Ellipse>
|
||||
</Grid>
|
||||
</Viewbox>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Daybreak.Controls.Glyphs;
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for GaugeGlyph.xaml
|
||||
/// </summary>
|
||||
public partial class GaugeGlyph : UserControl
|
||||
{
|
||||
public GaugeGlyph()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,4 @@
|
||||
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.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Daybreak.Controls;
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<UserControl x:Class="Daybreak.Controls.Glyphs.MapGlyph"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls.Glyphs"
|
||||
mc:Ignorable="d"
|
||||
Name="_this"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Viewbox>
|
||||
<Grid>
|
||||
<Path Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
Data="m18.53,14.53a9.37,9.37 0 0 1 -9.26,9.47l0,0a9.5,9.5 0 0 1 -3.26,-18.33a9.61,9.61 0 0 0 0.77,1.82a14.22,14.22 0 0 0 2.51,3.25a14.06,14.06 0 0 0 2.49,-3.24a9.2,9.2 0 0 0 0.75,-1.83a9.47,9.47 0 0 1 6,8.86z"></Path>
|
||||
<Polyline Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
Points="9.270000457763672,24 9.270000457763672,23.989999771118164 9.270000457763672,10.739999771118164"></Polyline>
|
||||
<Path Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
Data="m9.27,24l0,0c-0.32,-0.22 -5.27,-3.85 -4.94,-10.1a11.36,11.36 0 0 1 2.44,-6.4"></Path>
|
||||
<Path Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
Data="m9.25,24a0,0 0 0 1 0,0l0,0c0.4,-0.29 5.25,-3.91 4.92,-10.1a11.35,11.35 0 0 0 -2.43,-6.39"></Path>
|
||||
<Line Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
X1="0" X2="18.53" Y1="14.53" Y2="14.53"></Line>
|
||||
<Path Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
Data="m12.35,1.89a3.81,3.81 0 0 0 -3.08,-1.89a3.82,3.82 0 0 0 -3.09,1.89a4.75,4.75 0 0 0 -0.19,3.78a9.61,9.61 0 0 0 0.77,1.82a14.22,14.22 0 0 0 2.51,3.25a14.06,14.06 0 0 0 2.49,-3.24a9.2,9.2 0 0 0 0.77,-1.83a4.79,4.79 0 0 0 -0.18,-3.78z"></Path>
|
||||
<Ellipse Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
Width="1.24" Height="1.26" Margin="8.6, 3" HorizontalAlignment="Left" VerticalAlignment="Top"></Ellipse>
|
||||
</Grid>
|
||||
</Viewbox>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Daybreak.Controls.Glyphs;
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for MapGlyph.xaml
|
||||
/// </summary>
|
||||
public partial class MapGlyph : UserControl
|
||||
{
|
||||
public MapGlyph()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<UserControl x:Class="Daybreak.Controls.Glyphs.UModGlyph"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls.Glyphs"
|
||||
x:Name="_this"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Viewbox>
|
||||
<TextBlock Text="U" Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></TextBlock>
|
||||
</Viewbox>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,26 @@
|
||||
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.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace Daybreak.Controls.Glyphs;
|
||||
/// <summary>
|
||||
/// Interaction logic for UModGlyph.xaml
|
||||
/// </summary>
|
||||
public partial class UModGlyph : UserControl
|
||||
{
|
||||
public UModGlyph()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<UserControl x:Class="Daybreak.Controls.GuildwarsMinimap"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
x:Name="_this"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
MouseWheel="GuildwarsMinimap_MouseWheel"
|
||||
MouseLeftButtonDown="GuildwarsMinimap_MouseLeftButtonDown"
|
||||
MouseLeftButtonUp="GuildwarsMinimap_MouseLeftButtonUp"
|
||||
MouseRightButtonDown="GuildwarsMinimap_MouseRightButtonDown"
|
||||
MouseRightButtonUp="GuildwarsMinimap_MouseRightButtonUp"
|
||||
MouseMove="GuildwarsMinimap_MouseMove"
|
||||
Loaded="GuildwarsMinimap_Loaded"
|
||||
Unloaded="GuildwarsMinimap_Unloaded">
|
||||
<UserControl.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"></BooleanToVisibilityConverter>
|
||||
<ContextMenu x:Key="WorldPlayerContextMenu">
|
||||
<ContextMenu.Template>
|
||||
<ControlTemplate>
|
||||
<local:WorldPlayerContextMenu DataContext="{Binding DataContext, RelativeSource={RelativeSource TemplatedParent}}"></local:WorldPlayerContextMenu>
|
||||
</ControlTemplate>
|
||||
</ContextMenu.Template>
|
||||
</ContextMenu>
|
||||
<ContextMenu x:Key="MainPlayerContextMenu">
|
||||
<ContextMenu.Template>
|
||||
<ControlTemplate>
|
||||
<local:MainPlayerContextMenu DataContext="{Binding DataContext, RelativeSource={RelativeSource TemplatedParent}}"></local:MainPlayerContextMenu>
|
||||
</ControlTemplate>
|
||||
</ContextMenu.Template>
|
||||
</ContextMenu>
|
||||
<ContextMenu x:Key="LivingEntityContextMenu">
|
||||
<ContextMenu.Template>
|
||||
<ControlTemplate>
|
||||
<local:LivingEntityContextMenu DataContext="{Binding DataContext, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
LivingEntityContextMenuClicked="LivingEntityContextMenu_LivingEntityContextMenuClicked"></local:LivingEntityContextMenu>
|
||||
</ControlTemplate>
|
||||
</ContextMenu.Template>
|
||||
</ContextMenu>
|
||||
<ContextMenu x:Key="PlayerContextMenu">
|
||||
<ContextMenu.Template>
|
||||
<ControlTemplate>
|
||||
<local:PlayerContextMenu DataContext="{Binding DataContext, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
PlayerContextMenuClicked="PlayerContextMenu_PlayerContextMenuClicked"></local:PlayerContextMenu>
|
||||
</ControlTemplate>
|
||||
</ContextMenu.Template>
|
||||
</ContextMenu>
|
||||
<ContextMenu x:Key="QuestContextMenu">
|
||||
<ContextMenu.Template>
|
||||
<ControlTemplate>
|
||||
<local:QuestContextMenu DataContext="{Binding DataContext, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
QuestContextMenuClicked="QuestContextMenu_QuestContextMenuClicked"></local:QuestContextMenu>
|
||||
</ControlTemplate>
|
||||
</ContextMenu.Template>
|
||||
</ContextMenu>
|
||||
<ContextMenu x:Key="MapIconContextMenu">
|
||||
<ContextMenu.Template>
|
||||
<ControlTemplate>
|
||||
<local:MapIconContextMenu DataContext="{Binding DataContext, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
MapIconContextMenuClicked="MapIconContextMenu_MapIconContextMenuClicked"></local:MapIconContextMenu>
|
||||
</ControlTemplate>
|
||||
</ContextMenu.Template>
|
||||
</ContextMenu>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Image x:Name="MapDrawingHost" VerticalAlignment="Top" HorizontalAlignment="Left" Stretch="Fill"/>
|
||||
<Image x:Name="EntitiesDrawingHost" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
|
||||
<Grid Background="#F0212121"
|
||||
VerticalAlignment="Bottom"
|
||||
HorizontalAlignment="Right"
|
||||
Visibility="{Binding ElementName=_this, Path=ControlsVisible, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||
<local:MaximizeButton Height="30" Width="30" Margin="5"
|
||||
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
Clicked="MaximizeButton_Clicked"></local:MaximizeButton>
|
||||
</Grid>
|
||||
<WrapPanel Background="#F0212121" VerticalAlignment="Top" HorizontalAlignment="Right" >
|
||||
<TextBlock Text="{Binding ElementName=_this, Path=TargetEntityId, Mode=OneWay}" Foreground="White"
|
||||
FontSize="16" Padding="5" ></TextBlock>
|
||||
<TextBlock Text=" - " Foreground="White"
|
||||
FontSize="16" Padding="5" ></TextBlock>
|
||||
<TextBlock Text="{Binding ElementName=_this, Path=TargetEntityModelId, Mode=OneWay}" Foreground="White"
|
||||
FontSize="16" Padding="5" ></TextBlock>
|
||||
</WrapPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,700 @@
|
||||
using Daybreak.Models.Guildwars;
|
||||
using Daybreak.Models;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Extensions;
|
||||
using System.Windows;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Media;
|
||||
using System;
|
||||
using System.Extensions;
|
||||
using Daybreak.Services.Scanner;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Core.Extensions;
|
||||
using System.Windows.Input;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Daybreak.Services.Pathfinding;
|
||||
using Daybreak.Services.Pathfinding.Models;
|
||||
using System.Windows.Threading;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Daybreak.Services.Drawing;
|
||||
|
||||
namespace Daybreak.Controls;
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Using source generators to auto-implement dependency properties")]
|
||||
/// <summary>
|
||||
/// Interaction logic for GuildwarsMinimap.xaml
|
||||
/// </summary>
|
||||
public partial class GuildwarsMinimap : UserControl
|
||||
{
|
||||
private const int MapDownscaleFactor = 10;
|
||||
private const int EntitySize = 100;
|
||||
private const float PositionRadius = 150;
|
||||
// Minimum amount of milliseconds to pass between calculating paths to objectives
|
||||
private const int MinPathCalculationFrequency = 500;
|
||||
|
||||
private readonly DispatcherTimer dispatcherTimer = new(DispatcherPriority.ApplicationIdle);
|
||||
private readonly List<Position> mainPlayerPositionHistory = new();
|
||||
private readonly IPathfinder pathfinder;
|
||||
private readonly IDrawingService drawingService;
|
||||
private readonly IGuildwarsEntityDebouncer guildwarsEntityDebouncer;
|
||||
private readonly Color outlineColor = Colors.Chocolate;
|
||||
private readonly TimeSpan offsetRevertDelay = TimeSpan.FromSeconds(3);
|
||||
|
||||
private bool calculatingPathToObjectives = false;
|
||||
private bool resizeEntities;
|
||||
private bool dragging;
|
||||
private double mapVirtualMinWidth;
|
||||
private double mapVirtualMinHeight;
|
||||
private double mapWidth;
|
||||
private double mapHeight;
|
||||
private DateTime offsetRevertTime = DateTime.Now;
|
||||
private double offsetRevert = 0;
|
||||
private Point originPoint = new(0, 0);
|
||||
private Vector originOffset = new(0, 0);
|
||||
private Point initialClickPoint = new(0, 0);
|
||||
private DebounceResponse? cachedDebounceResponse;
|
||||
private PathfindingCache? pathfindingCache;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private PathingData pathingData = new();
|
||||
[GenerateDependencyProperty]
|
||||
private GameData gameData = new();
|
||||
[GenerateDependencyProperty]
|
||||
private double zoom = 0.08;
|
||||
[GenerateDependencyProperty(InitialValue = true)]
|
||||
private bool drawPositionHistory = true;
|
||||
[GenerateDependencyProperty]
|
||||
private bool controlsVisible;
|
||||
[GenerateDependencyProperty]
|
||||
private int targetEntityId;
|
||||
[GenerateDependencyProperty]
|
||||
private int targetEntityModelId;
|
||||
|
||||
public event EventHandler? MaximizeClicked;
|
||||
public event EventHandler<QuestMetadata>? QuestMetadataClicked;
|
||||
public event EventHandler<LivingEntity>? LivingEntityClicked;
|
||||
public event EventHandler<PlayerInformation>? PlayerInformationClicked;
|
||||
public event EventHandler<MapIcon>? MapIconClicked;
|
||||
|
||||
public GuildwarsMinimap()
|
||||
:this(
|
||||
Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IPathfinder>(),
|
||||
Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IDrawingService>(),
|
||||
Launch.Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IGuildwarsEntityDebouncer>())
|
||||
{
|
||||
}
|
||||
|
||||
public GuildwarsMinimap(
|
||||
IPathfinder pathfinder,
|
||||
IDrawingService drawingService,
|
||||
IGuildwarsEntityDebouncer guildwarsEntityDebouncer)
|
||||
{
|
||||
this.pathfinder = pathfinder.ThrowIfNull();
|
||||
this.drawingService = drawingService.ThrowIfNull();
|
||||
this.guildwarsEntityDebouncer = guildwarsEntityDebouncer.ThrowIfNull();
|
||||
|
||||
this.dispatcherTimer.Tick += (_, _) => this.ApplyOffsetRevert();
|
||||
this.dispatcherTimer.Interval = TimeSpan.FromMilliseconds(16);
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnPropertyChanged(e);
|
||||
if (e.Property == ActualHeightProperty ||
|
||||
e.Property == ActualWidthProperty)
|
||||
{
|
||||
this.resizeEntities = true;
|
||||
}
|
||||
else if (e.Property == PathingDataProperty)
|
||||
{
|
||||
this.guildwarsEntityDebouncer.ClearCaches();
|
||||
this.mainPlayerPositionHistory.Clear();
|
||||
this.UpdateGameData();
|
||||
this.DrawMap();
|
||||
}
|
||||
else if (e.Property == ZoomProperty)
|
||||
{
|
||||
this.UpdateGameData();
|
||||
}
|
||||
else if (e.Property == GameDataProperty &&
|
||||
this.GameData.Valid)
|
||||
{
|
||||
this.UpdateGameData();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateGameData()
|
||||
{
|
||||
if(this.GameData.Valid is false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var debounceResponse = this.guildwarsEntityDebouncer.DebounceEntities(this.GameData);
|
||||
if (!double.IsFinite(this.mapWidth) ||
|
||||
!double.IsFinite(this.mapHeight) ||
|
||||
!double.IsFinite(this.mapVirtualMinWidth) ||
|
||||
!double.IsFinite(this.mapVirtualMinHeight) ||
|
||||
debounceResponse.MainPlayer.Position is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.TargetEntityId = this.GameData.Session?.CurrentTargetId ?? 0;
|
||||
this.TargetEntityModelId = (int?)this.GameData.LivingEntities?.FirstOrDefault(e => e.Id == this.TargetEntityId).ModelType ?? 0;
|
||||
var screenVirtualWidth = this.ActualWidth / this.Zoom;
|
||||
var screenVirtualHeight = this.ActualHeight / this.Zoom;
|
||||
var position = debounceResponse.MainPlayer.Position!.Value;
|
||||
this.originPoint = new Point(
|
||||
position.X - (screenVirtualWidth / 2) - (this.originOffset.X / this.Zoom),
|
||||
position.Y + (screenVirtualHeight / 2) + (this.originOffset.Y / this.Zoom));
|
||||
|
||||
var adjustedPosition = new Point((int)((position.X - this.mapVirtualMinWidth) * this.Zoom), (int)(this.mapHeight - position.Y + this.mapVirtualMinHeight) * this.Zoom);
|
||||
|
||||
this.MapDrawingHost.Margin = new Thickness(
|
||||
-adjustedPosition.X + (this.ActualWidth / 2) + this.originOffset.X,
|
||||
-adjustedPosition.Y + (this.ActualHeight / 2) + this.originOffset.Y,
|
||||
0,
|
||||
0);
|
||||
this.MapDrawingHost.Height = this.mapHeight * this.Zoom;
|
||||
this.MapDrawingHost.Width = this.mapWidth * this.Zoom;
|
||||
this.cachedDebounceResponse = debounceResponse;
|
||||
this.ManageMainPlayerPositionHistory();
|
||||
this.DrawEntities();
|
||||
}
|
||||
|
||||
private void ManageMainPlayerPositionHistory()
|
||||
{
|
||||
if (this.cachedDebounceResponse is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var currentPosition = this.cachedDebounceResponse.MainPlayer.Position ?? throw new InvalidOperationException("Unexpected main player null position");
|
||||
if (this.mainPlayerPositionHistory.Any(oldPosition => PositionsCollide(oldPosition, currentPosition)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.mainPlayerPositionHistory.Add(currentPosition);
|
||||
}
|
||||
|
||||
private void DrawMap()
|
||||
{
|
||||
if (this.PathingData.Trapezoids is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var maxWidth = double.MinValue;
|
||||
var maxHeight = double.MinValue;
|
||||
var minWidth = double.MaxValue;
|
||||
var minHeight = double.MaxValue;
|
||||
foreach (var trapezoid in this.PathingData.Trapezoids!)
|
||||
{
|
||||
if (trapezoid.YT < minHeight)
|
||||
{
|
||||
minHeight = trapezoid.YT;
|
||||
}
|
||||
|
||||
if (trapezoid.YB > maxHeight)
|
||||
{
|
||||
maxHeight = trapezoid.YB;
|
||||
}
|
||||
|
||||
if (trapezoid.XTL < minWidth)
|
||||
{
|
||||
minWidth = trapezoid.XTL;
|
||||
}
|
||||
|
||||
if (trapezoid.XBL < minWidth)
|
||||
{
|
||||
minWidth = trapezoid.XBL;
|
||||
}
|
||||
|
||||
if (trapezoid.XTR > maxWidth)
|
||||
{
|
||||
maxWidth = trapezoid.XTR;
|
||||
}
|
||||
|
||||
if (trapezoid.XBR > maxWidth)
|
||||
{
|
||||
maxWidth = trapezoid.XBR;
|
||||
}
|
||||
}
|
||||
|
||||
var width = maxWidth - minWidth;
|
||||
var height = maxHeight - minHeight;
|
||||
this.mapVirtualMinHeight = minHeight;
|
||||
this.mapVirtualMinWidth = minWidth;
|
||||
this.mapWidth = width;
|
||||
this.mapHeight = height;
|
||||
|
||||
if (width <= 0 || height <= 0 ||
|
||||
!double.IsFinite(width) ||
|
||||
!double.IsFinite(height))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var bitmap = BitmapFactory.New((int)(width / MapDownscaleFactor), (int)(height / MapDownscaleFactor));
|
||||
this.MapDrawingHost.Source = bitmap;
|
||||
this.MapDrawingHost.Width = width / MapDownscaleFactor;
|
||||
this.MapDrawingHost.Height = height / MapDownscaleFactor;
|
||||
|
||||
using var bitmapContext = bitmap.GetBitmapContext();
|
||||
bitmap.Clear(Colors.Transparent);
|
||||
|
||||
foreach (var trapezoid in this.PathingData.Trapezoids)
|
||||
{
|
||||
var a = new Point((int)((trapezoid.XTL - minWidth) / MapDownscaleFactor), (int)((height - trapezoid.YT + minHeight) / MapDownscaleFactor));
|
||||
var b = new Point((int)((trapezoid.XTR - minWidth) / MapDownscaleFactor), (int)((height - trapezoid.YT + minHeight) / MapDownscaleFactor));
|
||||
var c = new Point((int)((trapezoid.XBR - minWidth) / MapDownscaleFactor), (int)((height - trapezoid.YB + minHeight) / MapDownscaleFactor));
|
||||
var d = new Point((int)((trapezoid.XBL - minWidth) / MapDownscaleFactor), (int)((height - trapezoid.YB + minHeight) / MapDownscaleFactor));
|
||||
|
||||
bitmap.FillPolygon(new int[] { (int)a.X, (int)a.Y, (int)b.X, (int)b.Y, (int)c.X, (int)c.Y, (int)d.X, (int)d.Y, (int)a.X, (int)a.Y }, Colors.White);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawEntities()
|
||||
{
|
||||
if (this.ActualWidth == 0 || this.ActualHeight == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.EntitiesDrawingHost.Source is not WriteableBitmap bitmap ||
|
||||
this.resizeEntities ||
|
||||
bitmap.PixelHeight != (int)this.ActualHeight ||
|
||||
bitmap.PixelWidth != (int)this.ActualWidth)
|
||||
{
|
||||
bitmap = BitmapFactory.New((int)this.ActualWidth, (int)this.ActualHeight);
|
||||
this.EntitiesDrawingHost.Source = bitmap;
|
||||
this.resizeEntities = false;
|
||||
}
|
||||
|
||||
this.CalculatePathsToObjectives();
|
||||
|
||||
bitmap.Clear(Colors.Transparent);
|
||||
using var context = bitmap.GetBitmapContext();
|
||||
|
||||
this.drawingService.UpdateDrawingParameters(
|
||||
(int)this.ActualWidth,
|
||||
(int)this.ActualHeight,
|
||||
this.originPoint,
|
||||
this.Zoom,
|
||||
PositionRadius,
|
||||
EntitySize);
|
||||
this.drawingService.DrawEngagementArea(bitmap, this.cachedDebounceResponse ?? new DebounceResponse());
|
||||
this.drawingService.DrawMainPlayerPositionHistory(bitmap, this.mainPlayerPositionHistory);
|
||||
this.drawingService.DrawPaths(bitmap, this.pathfindingCache);
|
||||
this.drawingService.DrawQuestObjectives(bitmap, this.GameData.MainPlayer?.QuestLog ?? new List<QuestMetadata>());
|
||||
this.drawingService.DrawMapIcons(bitmap, this.GameData.MapIcons ?? new List<MapIcon>());
|
||||
this.drawingService.DrawEntities(bitmap, this.cachedDebounceResponse ?? new DebounceResponse(), this.TargetEntityId);
|
||||
}
|
||||
|
||||
private bool MouseOverEntity(IPositionalEntity entity, Point mousePosition)
|
||||
{
|
||||
var x = (int)((entity.Position!.Value.X - this.originPoint.X) * this.Zoom);
|
||||
var y = 0 - (int)((entity.Position!.Value.Y - this.originPoint.Y) * this.Zoom);
|
||||
|
||||
return Math.Pow(mousePosition.X - x, 2) + Math.Pow(mousePosition.Y - y, 2) < Math.Pow(EntitySize * this.Zoom, 2);
|
||||
}
|
||||
|
||||
private void DragMinimap()
|
||||
{
|
||||
if (this.dragging is false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var mousePosition = Mouse.GetPosition(this);
|
||||
this.offsetRevert = 0;
|
||||
this.originOffset = mousePosition - this.initialClickPoint;
|
||||
this.offsetRevertTime = DateTime.Now + this.offsetRevertDelay;
|
||||
this.UpdateGameData();
|
||||
}
|
||||
|
||||
private void ApplyOffsetRevert()
|
||||
{
|
||||
if (DateTime.Now < this.offsetRevertTime)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.ContextMenu?.IsOpen is true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.offsetRevert = 0.0001 + (this.offsetRevert * 1.0001);
|
||||
this.offsetRevert = Math.Min(99, this.offsetRevert);
|
||||
this.originOffset /= 1 + this.offsetRevert;
|
||||
this.UpdateGameData();
|
||||
}
|
||||
|
||||
private async void CalculatePathsToObjectives()
|
||||
{
|
||||
if (this.calculatingPathToObjectives)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.calculatingPathToObjectives = true;
|
||||
var currentMapQuests = this.GameData.MainPlayer?.QuestLog?.Where(q => IsValidPositionalEntity(q)).ToList();
|
||||
if (currentMapQuests is null)
|
||||
{
|
||||
this.calculatingPathToObjectives = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var pathfindingTasks = currentMapQuests
|
||||
.Select(questMetaData =>
|
||||
{
|
||||
return this.pathfinder.CalculatePath(
|
||||
this.PathingData,
|
||||
new Point
|
||||
{
|
||||
X = this.cachedDebounceResponse?.MainPlayer.Position?.X ?? 0,
|
||||
Y = this.cachedDebounceResponse?.MainPlayer.Position?.Y ?? 0,
|
||||
},
|
||||
new Point
|
||||
{
|
||||
X = questMetaData.Position!.Value.X,
|
||||
Y = questMetaData.Position!.Value.Y
|
||||
},
|
||||
CancellationToken.None);
|
||||
})
|
||||
.ToList();
|
||||
|
||||
await Task.WhenAll(pathfindingTasks.Append(Task.Delay(MinPathCalculationFrequency)));
|
||||
var paths = new List<PathfindingResponse>();
|
||||
var colors = new List<Color>();
|
||||
for(var i = 0; i < currentMapQuests.Count; i++)
|
||||
{
|
||||
var quest = currentMapQuests[i];
|
||||
var result = await pathfindingTasks[i];
|
||||
if (result.TryExtractSuccess(out var pathfindingResponse))
|
||||
{
|
||||
paths.Add(pathfindingResponse);
|
||||
var questColor = GetQuestColor(quest);
|
||||
var pathColor = Color.FromArgb(100, questColor.R, questColor.G, questColor.B);
|
||||
colors.Add(pathColor);
|
||||
}
|
||||
}
|
||||
|
||||
this.pathfindingCache = new PathfindingCache { PathfindingResponses = paths, Colors = colors };
|
||||
this.calculatingPathToObjectives = false;
|
||||
}
|
||||
|
||||
private IPositionalEntity? CheckMouseOverEntity(IEnumerable<IPositionalEntity>? maybeEntities)
|
||||
{
|
||||
if (maybeEntities is not IEnumerable<IPositionalEntity> entities)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
if (this.GameData.Valid is false)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
var mousePoint = Mouse.GetPosition(this);
|
||||
foreach(var entity in entities)
|
||||
{
|
||||
if (this.MouseOverEntity(entity, mousePoint))
|
||||
{
|
||||
this.Cursor = Cursors.Hand;
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
this.Cursor = default;
|
||||
return default;
|
||||
}
|
||||
|
||||
private Position ForceOnScreenPosition(Position entityPosition)
|
||||
{
|
||||
var screenVirtualWidth = this.ActualWidth / this.Zoom;
|
||||
var screenVirtualHeight = this.ActualHeight / this.Zoom;
|
||||
var finalEntitySize = EntitySize * this.Zoom;
|
||||
return new Position
|
||||
{
|
||||
X = (float)Math.Clamp(
|
||||
entityPosition.X,
|
||||
Math.Min(this.originPoint.X + finalEntitySize, this.originPoint.X + screenVirtualWidth - finalEntitySize),
|
||||
Math.Max(this.originPoint.X + finalEntitySize, this.originPoint.X + screenVirtualWidth - finalEntitySize)),
|
||||
Y = (float)Math.Clamp(
|
||||
entityPosition.Y,
|
||||
Math.Min(this.originPoint.Y - screenVirtualHeight + finalEntitySize, this.originPoint.Y - finalEntitySize),
|
||||
Math.Max(this.originPoint.Y - screenVirtualHeight + finalEntitySize, this.originPoint.Y - finalEntitySize)),
|
||||
};
|
||||
}
|
||||
|
||||
private void GuildwarsMinimap_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
this.initialClickPoint = Mouse.GetPosition(this) - this.originOffset;
|
||||
this.offsetRevert = 0;
|
||||
this.offsetRevertTime = DateTime.Now + this.offsetRevertDelay;
|
||||
this.dragging = true;
|
||||
}
|
||||
|
||||
private void GuildwarsMinimap_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
this.dragging = false;
|
||||
}
|
||||
|
||||
private void GuildwarsMinimap_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
var maybeOffScreenQuestMetadata = this.CheckMouseOverEntity(
|
||||
this.GameData.MainPlayer?.QuestLog?
|
||||
.Where(q => IsValidPositionalEntity(q))
|
||||
.Where(entity => !this.drawingService.IsEntityOnScreen(entity.Position, out _, out _))
|
||||
.Select(oldQuestMetadata =>
|
||||
{
|
||||
var onScreenPosition = this.ForceOnScreenPosition(oldQuestMetadata.Position!.Value);
|
||||
return new QuestMetadata
|
||||
{
|
||||
From = oldQuestMetadata.From,
|
||||
To = oldQuestMetadata.To,
|
||||
Quest = oldQuestMetadata.Quest,
|
||||
Position = onScreenPosition
|
||||
};
|
||||
})
|
||||
.OfType<IPositionalEntity>());
|
||||
if (maybeOffScreenQuestMetadata is QuestMetadata offscreenQuestMetadata &&
|
||||
this.TryFindResource("QuestContextMenu") is ContextMenu offscreenQuestContextMenu)
|
||||
{
|
||||
this.ContextMenu = offscreenQuestContextMenu;
|
||||
this.ContextMenu.DataContext = offscreenQuestMetadata;
|
||||
this.ContextMenu.IsOpen = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var maybeQuestMetadata = this.CheckMouseOverEntity(
|
||||
this.GameData.MainPlayer?.QuestLog?
|
||||
.OfType<IPositionalEntity>().Where(IsValidPositionalEntity)
|
||||
.Where(entity => this.drawingService.IsEntityOnScreen(entity.Position, out _, out _)));
|
||||
if (maybeQuestMetadata is QuestMetadata questMetadata &&
|
||||
this.TryFindResource("QuestContextMenu") is ContextMenu questContextMenu)
|
||||
{
|
||||
this.ContextMenu = questContextMenu;
|
||||
this.ContextMenu.DataContext = questMetadata;
|
||||
this.ContextMenu.IsOpen = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.CheckMouseOverEntity(Enumerable.Repeat(this.GameData.MainPlayer.As<IEntity>(), 1)) is MainPlayerInformation &&
|
||||
this.TryFindResource("MainPlayerContextMenu") is ContextMenu mainPlayerContextMenu)
|
||||
{
|
||||
this.ContextMenu = mainPlayerContextMenu;
|
||||
this.ContextMenu.DataContext = this.GameData.MainPlayer;
|
||||
this.ContextMenu.IsOpen = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var maybeWorldPlayer = this.CheckMouseOverEntity(this.GameData.WorldPlayers?.OfType<IEntity>().Where(IsValidPositionalEntity).OrderByDescending(p => p.Id == this.TargetEntityId));
|
||||
if (maybeWorldPlayer is WorldPlayerInformation worldPlayerInformation &&
|
||||
this.TryFindResource("WorldPlayerContextMenu") is ContextMenu worldPlayerContextMenu)
|
||||
{
|
||||
this.ContextMenu = worldPlayerContextMenu;
|
||||
this.ContextMenu.DataContext = worldPlayerInformation;
|
||||
this.ContextMenu.IsOpen = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var maybePartyMember = this.CheckMouseOverEntity(this.GameData.Party?.OfType<IEntity>().Where(IsValidPositionalEntity).OrderByDescending(p => p.Id == this.TargetEntityId));
|
||||
if (maybePartyMember is PlayerInformation partyMember &&
|
||||
this.TryFindResource("PlayerContextMenu") is ContextMenu playerContextMenu)
|
||||
{
|
||||
this.ContextMenu = playerContextMenu;
|
||||
this.ContextMenu.DataContext = partyMember;
|
||||
this.ContextMenu.IsOpen = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var maybeLivingEntity = this.CheckMouseOverEntity(this.GameData.LivingEntities?.OfType<IEntity>().Where(IsValidPositionalEntity).OrderByDescending(p => p.Id == this.TargetEntityId));
|
||||
if (maybeLivingEntity is LivingEntity livingEntity &&
|
||||
this.TryFindResource("LivingEntityContextMenu") is ContextMenu livingEntityContextMenu)
|
||||
{
|
||||
this.ContextMenu = livingEntityContextMenu;
|
||||
this.ContextMenu.DataContext = livingEntity;
|
||||
this.ContextMenu.IsOpen = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var maybeMapIcon = this.CheckMouseOverEntity(this.GameData.MapIcons?.OfType<IPositionalEntity>().Where(IsValidPositionalEntity));
|
||||
if (maybeMapIcon is MapIcon mapIcon &&
|
||||
this.TryFindResource("MapIconContextMenu") is ContextMenu mapIconContextMenu)
|
||||
{
|
||||
this.ContextMenu = mapIconContextMenu;
|
||||
this.ContextMenu.DataContext = mapIcon;
|
||||
this.ContextMenu.IsOpen = true;
|
||||
return;
|
||||
}
|
||||
|
||||
this.ContextMenu = default;
|
||||
}
|
||||
|
||||
private void GuildwarsMinimap_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
private void GuildwarsMinimap_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (this.GameData.Valid is false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.DragMinimap();
|
||||
if (this.CheckMouseOverEntity(this.GameData.Party!.OfType<IEntity>()) is not null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.CheckMouseOverEntity(this.GameData.WorldPlayers!.OfType<IEntity>()) is not null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.CheckMouseOverEntity(Enumerable.Repeat(this.GameData.MainPlayer.As<IEntity>(), 1)) is not null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.CheckMouseOverEntity(this.GameData.LivingEntities!.OfType<IEntity>()) is not null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.CheckMouseOverEntity(this.GameData.MapIcons!.OfType<IPositionalEntity>()) is not null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.CheckMouseOverEntity(this.GameData.MainPlayer!.Value.QuestLog!
|
||||
.Where(entity => this.drawingService.IsEntityOnScreen(entity.Position, out _, out _))
|
||||
.OfType<IPositionalEntity>()) is not null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.CheckMouseOverEntity(this.GameData.MainPlayer!.Value.QuestLog!
|
||||
.Where(entity => !this.drawingService.IsEntityOnScreen(entity.Position, out _, out _))
|
||||
.Select(oldQuestMetadata =>
|
||||
{
|
||||
var onScreenPosition = this.ForceOnScreenPosition(oldQuestMetadata.Position!.Value);
|
||||
return new QuestMetadata
|
||||
{
|
||||
From = oldQuestMetadata.From,
|
||||
To = oldQuestMetadata.To,
|
||||
Quest = oldQuestMetadata.Quest,
|
||||
Position = onScreenPosition
|
||||
};
|
||||
})
|
||||
.OfType<IPositionalEntity>()) is not null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void GuildwarsMinimap_MouseWheel(object sender, MouseWheelEventArgs e)
|
||||
{
|
||||
var delta = e.Delta > 0 ? 0.1 : -0.1;
|
||||
var previousZoom = this.Zoom;
|
||||
var newZoom = this.Zoom + this.Zoom * delta;
|
||||
this.originOffset *= newZoom / previousZoom;
|
||||
this.initialClickPoint = new Point(
|
||||
this.initialClickPoint.X * newZoom / previousZoom,
|
||||
this.initialClickPoint.Y * newZoom / previousZoom);
|
||||
|
||||
this.Zoom = newZoom;
|
||||
}
|
||||
|
||||
private void GuildwarsMinimap_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.dispatcherTimer.Start();
|
||||
}
|
||||
|
||||
private void GuildwarsMinimap_Unloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.dispatcherTimer.Stop();
|
||||
}
|
||||
|
||||
private void QuestContextMenu_QuestContextMenuClicked(object _, QuestMetadata? quest)
|
||||
{
|
||||
if (quest is not QuestMetadata)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.QuestMetadataClicked?.Invoke(this, quest.Value);
|
||||
}
|
||||
|
||||
private void PlayerContextMenu_PlayerContextMenuClicked(object _, PlayerInformation? playerInformation)
|
||||
{
|
||||
if (playerInformation is not PlayerInformation)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.PlayerInformationClicked?.Invoke(this, playerInformation.Value);
|
||||
}
|
||||
|
||||
private void LivingEntityContextMenu_LivingEntityContextMenuClicked(object _, LivingEntity? livingEntity)
|
||||
{
|
||||
if (livingEntity is not LivingEntity)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.LivingEntityClicked?.Invoke(this, livingEntity.Value);
|
||||
}
|
||||
|
||||
private void MapIconContextMenu_MapIconContextMenuClicked(object _, MapIcon? mapIcon)
|
||||
{
|
||||
if (mapIcon is not MapIcon)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.MapIconClicked?.Invoke(this, mapIcon.Value);
|
||||
}
|
||||
|
||||
private void MaximizeButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
this.MaximizeClicked?.Invoke(this, e);
|
||||
if (e is MouseButtonEventArgs mouseButtonEventArgs)
|
||||
{
|
||||
mouseButtonEventArgs.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool PositionsCollide(Position position1, Position position2)
|
||||
{
|
||||
var a = PositionRadius + PositionRadius;
|
||||
var dx = position1.X - position2.X;
|
||||
var dy = position1.Y - position2.Y;
|
||||
return a * a > ((dx * dx) + (dy * dy));
|
||||
}
|
||||
|
||||
private static bool IsValidPositionalEntity(IPositionalEntity entity)
|
||||
{
|
||||
if (entity.Position?.X == 0 &&
|
||||
entity.Position?.Y == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static Color GetQuestColor(QuestMetadata questMetadata)
|
||||
{
|
||||
return QuestObjectiveColors.Colors[questMetadata.Quest?.Id % QuestObjectiveColors.Colors.Count ?? 0];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<UserControl x:Class="Daybreak.Controls.HorizontalResourceBar"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<Viewbox VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Stretch="Fill">
|
||||
<Grid Height="1">
|
||||
<Rectangle
|
||||
Fill="{Binding ElementName=_this, Path=BarColor, Mode=OneWay}"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="{Binding ElementName=_this, Path=FillAlignment, Mode=OneWay}"
|
||||
Width="{Binding ElementName=_this, Path=MaxResourceValue, Mode=TwoWay}"></Rectangle>
|
||||
<Rectangle
|
||||
Fill="#F0202020"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"></Rectangle>
|
||||
<Rectangle
|
||||
Fill="{Binding ElementName=_this, Path=BarColor, Mode=OneWay}"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="{Binding ElementName=_this, Path=FillAlignment, Mode=OneWay}"
|
||||
Width="{Binding ElementName=_this, Path=CurrentResourceValue, Mode=TwoWay}"></Rectangle>
|
||||
</Grid>
|
||||
</Viewbox>
|
||||
<TextBlock
|
||||
FontSize="{Binding ElementName=_this, Path=FontSize, Mode=OneWay}"
|
||||
FontFamily="{Binding ElementName=_this, Path=FontFamily, Mode=OneWay}"
|
||||
Text="{Binding ElementName=_this, Path=Text, Mode=OneWay}"
|
||||
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"></TextBlock>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,34 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Extensions;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Daybreak.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for ResourceBar.xaml
|
||||
/// </summary>
|
||||
public partial class HorizontalResourceBar : UserControl
|
||||
{
|
||||
[GenerateDependencyProperty]
|
||||
private double currentResourceValue;
|
||||
[GenerateDependencyProperty]
|
||||
private double maxResourceValue;
|
||||
[GenerateDependencyProperty]
|
||||
private Brush barColor;
|
||||
[GenerateDependencyProperty]
|
||||
private string text;
|
||||
[GenerateDependencyProperty(InitialValue = HorizontalAlignment.Left)]
|
||||
private HorizontalAlignment fillAlignment;
|
||||
|
||||
public HorizontalResourceBar()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
this.MaxResourceValue = 1;
|
||||
this.CurrentResourceValue = 0;
|
||||
this.barColor = Brushes.Transparent;
|
||||
this.text = string.Empty;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<UserControl x:Class="Daybreak.Controls.LivingEntityContextMenu"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:guildwars="clr-namespace:Daybreak.Models.Guildwars"
|
||||
mc:Ignorable="d"
|
||||
Background="#F0212121"
|
||||
d:DataContext="{d:DesignInstance Type=guildwars:LivingEntity, IsDesignTimeCreatable=True}"
|
||||
d:DesignHeight="300" d:DesignWidth="100">
|
||||
<StackPanel Margin="5, 0, 5, 0">
|
||||
<TextBlock
|
||||
Text="{Binding Allegiance, Mode=OneWay}" FontSize="16" Foreground="White"></TextBlock>
|
||||
<TextBlock Text="{Binding NpcDefinition.Name}" Foreground="LightBlue" Cursor="Hand"
|
||||
MouseLeftButtonDown="TextBlock_MouseLeftButtonDown"></TextBlock>
|
||||
<WrapPanel>
|
||||
<TextBlock Text="Id: " Foreground="White"></TextBlock>
|
||||
<TextBlock Text="{Binding ModelType, Mode=OneWay}" Foreground="White"></TextBlock>
|
||||
</WrapPanel>
|
||||
<WrapPanel>
|
||||
<TextBlock Text="Lvl: " Foreground="White"></TextBlock>
|
||||
<TextBlock Text="{Binding Level, Mode=OneWay}" Foreground="White"></TextBlock>
|
||||
</WrapPanel>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,23 @@
|
||||
using Daybreak.Models.Guildwars;
|
||||
using System;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Daybreak.Controls;
|
||||
/// <summary>
|
||||
/// Interaction logic for LivingEntityContextMenu.xaml
|
||||
/// </summary>
|
||||
public partial class LivingEntityContextMenu : UserControl
|
||||
{
|
||||
public event EventHandler<LivingEntity?>? LivingEntityContextMenuClicked;
|
||||
|
||||
public LivingEntityContextMenu()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
private void TextBlock_MouseLeftButtonDown(object _, MouseButtonEventArgs e)
|
||||
{
|
||||
this.LivingEntityContextMenuClicked?.Invoke(this, this.DataContext as LivingEntity? ?? default);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<UserControl x:Class="Daybreak.Controls.MainPlayerContextMenu"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
xmlns:guildwars="clr-namespace:Daybreak.Models.Guildwars"
|
||||
mc:Ignorable="d"
|
||||
Background="#F0212121"
|
||||
d:DataContext="{d:DesignInstance Type=guildwars:MainPlayerInformation, IsDesignTimeCreatable=True}"
|
||||
d:DesignHeight="300" d:DesignWidth="100">
|
||||
<StackPanel Margin="5, 0, 5, 0">
|
||||
<TextBlock
|
||||
Text="{Binding Name, Mode=OneWay}" FontSize="16" Foreground="White"></TextBlock>
|
||||
<WrapPanel>
|
||||
<TextBlock Text="Lvl: " Foreground="White"></TextBlock>
|
||||
<TextBlock Text="{Binding Level, Mode=OneWay}" Foreground="White"></TextBlock>
|
||||
</WrapPanel>
|
||||
<WrapPanel>
|
||||
<TextBlock Text="{Binding PrimaryProfession.Alias, Mode=OneWay}" Foreground="White"></TextBlock>
|
||||
<TextBlock Text="/" Foreground="White"></TextBlock>
|
||||
<TextBlock Text="{Binding SecondaryProfession.Alias, Mode=OneWay}" Foreground="White"></TextBlock>
|
||||
</WrapPanel>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Daybreak.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for MainPlayerContextMenu.xaml
|
||||
/// </summary>
|
||||
public partial class MainPlayerContextMenu : UserControl
|
||||
{
|
||||
public MainPlayerContextMenu()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<UserControl x:Class="Daybreak.Controls.MapIconContextMenu"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
xmlns:guildwars="clr-namespace:Daybreak.Models.Guildwars"
|
||||
mc:Ignorable="d"
|
||||
Background="#F0212121"
|
||||
d:DataContext="{d:DesignInstance Type=guildwars:MapIcon, IsDesignTimeCreatable=True}"
|
||||
d:DesignHeight="300" d:DesignWidth="100">
|
||||
<StackPanel Margin="5, 0, 5, 0">
|
||||
<TextBlock Text="Map Icon" Foreground="White" FontSize="16"></TextBlock>
|
||||
<TextBlock Text="{Binding Icon.Name}" Foreground="LightBlue" Cursor="Hand"
|
||||
MouseLeftButtonDown="TextBlock_MouseLeftButtonDown" Margin="0, 0, 0, 10"></TextBlock>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,24 @@
|
||||
using Daybreak.Models.Guildwars;
|
||||
using System;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Daybreak.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for MapIconContextMenu.xaml
|
||||
/// </summary>
|
||||
public partial class MapIconContextMenu : UserControl
|
||||
{
|
||||
public event EventHandler<MapIcon?>? MapIconContextMenuClicked;
|
||||
|
||||
public MapIconContextMenu()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
private void TextBlock_MouseLeftButtonDown(object _, MouseButtonEventArgs e)
|
||||
{
|
||||
this.MapIconContextMenuClicked?.Invoke(this, this.DataContext as MapIcon? ?? default);
|
||||
}
|
||||
}
|
||||
@@ -5,89 +5,105 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
xmlns:buttons="clr-namespace:Daybreak.Controls.Buttons"
|
||||
xmlns:glyphs="clr-namespace:Daybreak.Controls.Glyphs"
|
||||
xmlns:options="clr-namespace:Daybreak.Controls.Options"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<StackPanel>
|
||||
<buttons:MenuButton Title="Game companion"
|
||||
<local:ExpandableMenuSection
|
||||
SectionTitle="Guild Wars" Foreground="White"
|
||||
FontSize="16">
|
||||
<local:ExpandableMenuSection.Children>
|
||||
<buttons:MenuButton Title="Game companion"
|
||||
Foreground="White"
|
||||
HighlightColor="White"
|
||||
Height="30"
|
||||
Cursor="Hand"
|
||||
Clicked="GameCompanionButton_Clicked">
|
||||
</buttons:MenuButton>
|
||||
<buttons:MenuButton Title="Manage builds"
|
||||
Foreground="White"
|
||||
HighlightColor="White"
|
||||
Height="30"
|
||||
Cursor="Hand"
|
||||
Clicked="ManageBuildsButton_Clicked">
|
||||
</buttons:MenuButton>
|
||||
<buttons:MenuButton Title="Download Guildwars"
|
||||
Foreground="White"
|
||||
HighlightColor="White"
|
||||
Height="30"
|
||||
Cursor="Hand"
|
||||
Clicked="DownloadGuildwarsButton_Clicked">
|
||||
</buttons:MenuButton>
|
||||
</local:ExpandableMenuSection.Children>
|
||||
</local:ExpandableMenuSection>
|
||||
<local:ExpandableMenuSection
|
||||
SectionTitle="Mods" Foreground="White"
|
||||
FontSize="16">
|
||||
<local:ExpandableMenuSection.Children>
|
||||
<buttons:MenuButton Title="uMod"
|
||||
Foreground="White"
|
||||
HighlightColor="White"
|
||||
Height="30"
|
||||
Clicked="GameCompanionButton_Clicked">
|
||||
<buttons:MenuButton.InnerContent>
|
||||
<local:GoldenArrowGlyph Foreground="White"
|
||||
Width="40"></local:GoldenArrowGlyph>
|
||||
</buttons:MenuButton.InnerContent>
|
||||
</buttons:MenuButton>
|
||||
<buttons:MenuButton Title="Manage builds"
|
||||
Cursor="Hand"
|
||||
Clicked="UModButton_Clicked">
|
||||
</buttons:MenuButton>
|
||||
<buttons:MenuButton Title="GWToolboxpp"
|
||||
Foreground="White"
|
||||
HighlightColor="White"
|
||||
Height="30"
|
||||
Clicked="ManageBuildsButton_Clicked">
|
||||
<buttons:MenuButton.InnerContent>
|
||||
<local:FireballGlyph Foreground="White"
|
||||
Width="40"></local:FireballGlyph>
|
||||
</buttons:MenuButton.InnerContent>
|
||||
</buttons:MenuButton>
|
||||
<buttons:MenuButton Title="Account settings"
|
||||
Cursor="Hand"
|
||||
Clicked="ToolboxButton_Clicked">
|
||||
</buttons:MenuButton>
|
||||
</local:ExpandableMenuSection.Children>
|
||||
</local:ExpandableMenuSection>
|
||||
<local:ExpandableMenuSection
|
||||
SectionTitle="Settings" Foreground="White"
|
||||
FontSize="16">
|
||||
<local:ExpandableMenuSection.Children>
|
||||
<buttons:MenuButton Title="Accounts"
|
||||
Foreground="White"
|
||||
HighlightColor="White"
|
||||
Height="30"
|
||||
Cursor="Hand"
|
||||
Clicked="AccountSettingsButton_Clicked">
|
||||
<buttons:MenuButton.InnerContent>
|
||||
<local:AvatarGlyph Foreground="White"
|
||||
Width="40"></local:AvatarGlyph>
|
||||
</buttons:MenuButton.InnerContent>
|
||||
</buttons:MenuButton>
|
||||
<buttons:MenuButton Title="Guildwars settings"
|
||||
</buttons:MenuButton>
|
||||
<buttons:MenuButton Title="Executables"
|
||||
Foreground="White"
|
||||
HighlightColor="White"
|
||||
Height="30"
|
||||
Cursor="Hand"
|
||||
Clicked="GuildwarsSettingsButton_Clicked">
|
||||
<buttons:MenuButton.InnerContent>
|
||||
<local:FileGlyph Foreground="White"
|
||||
Width="40"></local:FileGlyph>
|
||||
</buttons:MenuButton.InnerContent>
|
||||
</buttons:MenuButton>
|
||||
<buttons:MenuButton Title="Launcher settings"
|
||||
Foreground="White"
|
||||
HighlightColor="White"
|
||||
Height="30"
|
||||
Clicked="LauncherSettingsButton_Clicked">
|
||||
<buttons:MenuButton.InnerContent>
|
||||
<local:CogGlyph Foreground="White"
|
||||
Width="40"
|
||||
Height="20"></local:CogGlyph>
|
||||
</buttons:MenuButton.InnerContent>
|
||||
</buttons:MenuButton>
|
||||
<buttons:MenuButton Title="Experimental settings"
|
||||
Foreground="White"
|
||||
HighlightColor="White"
|
||||
Height="30"
|
||||
Clicked="ExperimentalSettingsButton_Clicked">
|
||||
<buttons:MenuButton.InnerContent>
|
||||
<local:ExperimentGlyph Foreground="White"
|
||||
Width="40"></local:ExperimentGlyph>
|
||||
</buttons:MenuButton.InnerContent>
|
||||
</buttons:MenuButton>
|
||||
<buttons:MenuButton Title="Manage client version"
|
||||
</buttons:MenuButton>
|
||||
<options:OptionsSection></options:OptionsSection>
|
||||
</local:ExpandableMenuSection.Children>
|
||||
</local:ExpandableMenuSection>
|
||||
<local:ExpandableMenuSection
|
||||
SectionTitle="Diagnostics" Foreground="White"
|
||||
FontSize="16">
|
||||
<local:ExpandableMenuSection.Children>
|
||||
<buttons:MenuButton Title="Manage client version"
|
||||
Foreground="White"
|
||||
HighlightColor="White"
|
||||
Height="30"
|
||||
Cursor="Hand"
|
||||
Clicked="VersionManagementButton_Clicked">
|
||||
<buttons:MenuButton.InnerContent>
|
||||
<local:StaticGlyph Foreground="White"
|
||||
Width="40"></local:StaticGlyph>
|
||||
</buttons:MenuButton.InnerContent>
|
||||
</buttons:MenuButton>
|
||||
<buttons:MenuButton Title="Logs"
|
||||
</buttons:MenuButton>
|
||||
<buttons:MenuButton Title="Logs"
|
||||
Foreground="White"
|
||||
HighlightColor="White"
|
||||
Height="30"
|
||||
Cursor="Hand"
|
||||
Clicked="LogsButton_Clicked">
|
||||
<buttons:MenuButton.InnerContent>
|
||||
<local:LogsGlyph Foreground="White"
|
||||
Width="40"></local:LogsGlyph>
|
||||
</buttons:MenuButton.InnerContent>
|
||||
</buttons:MenuButton>
|
||||
</buttons:MenuButton>
|
||||
<buttons:MenuButton Title="Metrics"
|
||||
Foreground="White"
|
||||
HighlightColor="White"
|
||||
Height="30"
|
||||
Cursor="Hand"
|
||||
Clicked="MetricsButton_Clicked">
|
||||
</buttons:MenuButton>
|
||||
</local:ExpandableMenuSection.Children>
|
||||
</local:ExpandableMenuSection>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
using Daybreak.Configuration;
|
||||
using Daybreak.Configuration.Options;
|
||||
using Daybreak.Launch;
|
||||
using Daybreak.Services.Navigation;
|
||||
using Daybreak.Views;
|
||||
using Daybreak.Views.Onboarding.Toolbox;
|
||||
using Daybreak.Views.Onboarding.UMod;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Core.Extensions;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Daybreak.Controls;
|
||||
@@ -14,64 +17,79 @@ namespace Daybreak.Controls;
|
||||
/// </summary>
|
||||
public partial class MenuList : UserControl
|
||||
{
|
||||
private readonly IViewManager viewManager;
|
||||
private readonly ILiveOptions<LauncherOptions> liveOptions;
|
||||
|
||||
public MenuList()
|
||||
: this(
|
||||
Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IViewManager>(),
|
||||
Launcher.Instance.ApplicationServiceProvider.GetRequiredService<ILiveOptions<LauncherOptions>>())
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
private MenuList(
|
||||
IViewManager viewManager,
|
||||
ILiveOptions<LauncherOptions> liveOptions)
|
||||
{
|
||||
this.viewManager = viewManager.ThrowIfNull();
|
||||
this.liveOptions = liveOptions.ThrowIfNull();
|
||||
}
|
||||
|
||||
private void GameCompanionButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
var viewManager = Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IViewManager>();
|
||||
viewManager.ShowView<LauncherView>();
|
||||
this.viewManager.ShowView<LauncherView>();
|
||||
}
|
||||
|
||||
private void AccountSettingsButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
var viewManager = Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IViewManager>();
|
||||
viewManager.ShowView<AccountsView>();
|
||||
this.viewManager.ShowView<AccountsView>();
|
||||
}
|
||||
|
||||
private void GuildwarsSettingsButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
var viewManager = Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IViewManager>();
|
||||
viewManager.ShowView<ExecutablesView>();
|
||||
}
|
||||
|
||||
private void LauncherSettingsButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
var viewManager = Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IViewManager>();
|
||||
viewManager.ShowView<SettingsView>();
|
||||
}
|
||||
|
||||
private void ExperimentalSettingsButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
var viewManager = Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IViewManager>();
|
||||
viewManager.ShowView<ExperimentalSettingsView>();
|
||||
this.viewManager.ShowView<ExecutablesView>();
|
||||
}
|
||||
|
||||
private void ManageBuildsButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
var viewManager = Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IViewManager>();
|
||||
var options = Launcher.Instance.ApplicationServiceProvider.GetRequiredService<ILiveOptions<ApplicationConfiguration>>();
|
||||
if (options.Value.ExperimentalFeatures.DownloadIcons)
|
||||
if (this.liveOptions.Value.DownloadIcons)
|
||||
{
|
||||
viewManager.ShowView<IconDownloadView>();
|
||||
this.viewManager.ShowView<IconDownloadView>();
|
||||
}
|
||||
else
|
||||
{
|
||||
viewManager.ShowView<BuildsListView>();
|
||||
this.viewManager.ShowView<BuildsListView>();
|
||||
}
|
||||
}
|
||||
|
||||
private void VersionManagementButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
var viewManager = Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IViewManager>();
|
||||
viewManager.ShowView<VersionManagementView>();
|
||||
this.viewManager.ShowView<VersionManagementView>();
|
||||
}
|
||||
|
||||
|
||||
private void LogsButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
var viewManager = Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IViewManager>();
|
||||
viewManager.ShowView<LogsView>();
|
||||
this.viewManager.ShowView<LogsView>();
|
||||
}
|
||||
|
||||
private void MetricsButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
this.viewManager.ShowView<MetricsView>();
|
||||
}
|
||||
|
||||
private void DownloadGuildwarsButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
this.viewManager.ShowView<GuildwarsDownloadView>();
|
||||
}
|
||||
|
||||
private void UModButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
this.viewManager.ShowView<UModOnboardingEntryView>();
|
||||
}
|
||||
|
||||
private void ToolboxButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
this.viewManager.ShowView<ToolboxOnboardingEntryView>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<UserControl x:Class="Daybreak.Controls.Options.BooleanOptionTemplate"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls.Options"
|
||||
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid VerticalAlignment="Center" HorizontalAlignment="Stretch">
|
||||
<mah:ToggleSwitch VerticalContentAlignment="Center"
|
||||
Foreground="White"
|
||||
HorizontalAlignment="Center"
|
||||
IsOn="{Binding ElementName=_this, Path=Value, Mode=TwoWay}"></mah:ToggleSwitch>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,66 @@
|
||||
using Daybreak.Models.Options;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Extensions;
|
||||
|
||||
namespace Daybreak.Controls.Options;
|
||||
/// <summary>
|
||||
/// Interaction logic for BooleanOptionTemplate.xaml
|
||||
/// </summary>
|
||||
public partial class BooleanOptionTemplate : UserControl
|
||||
{
|
||||
private OptionProperty optionProperty = default!;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private bool value;
|
||||
|
||||
public BooleanOptionTemplate()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
this.DataContextChanged += this.BooleanOptionTemplate_DataContextChanged;
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.Property == ValueProperty &&
|
||||
e.NewValue is bool newValue)
|
||||
{
|
||||
if (!this.IsChangeValid(newValue))
|
||||
{
|
||||
this.Value = (bool)e.OldValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.optionProperty.Setter(newValue);
|
||||
}
|
||||
}
|
||||
|
||||
base.OnPropertyChanged(e);
|
||||
}
|
||||
|
||||
private void BooleanOptionTemplate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.Property != DataContextProperty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.NewValue is not OptionProperty optionProperty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.optionProperty = optionProperty;
|
||||
if (this.optionProperty.Getter() is not bool boolValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.Value = boolValue;
|
||||
}
|
||||
|
||||
private bool IsChangeValid(bool newValue)
|
||||
{
|
||||
return this.optionProperty.Validator.IsValid(newValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<UserControl x:Class="Daybreak.Controls.Options.EnumOptionTemplate"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls.Options"
|
||||
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<mah:SplitButton ItemsSource="{Binding ElementName=_this, Path=PossibleEnumValues, Mode=OneWay}"
|
||||
FontSize="16"
|
||||
SelectedItem="{Binding ElementName=_this, Path=Value, Mode=TwoWay}"></mah:SplitButton>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,67 @@
|
||||
using Daybreak.Models.Options;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Extensions;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Extensions;
|
||||
|
||||
namespace Daybreak.Controls.Options;
|
||||
/// <summary>
|
||||
/// Interaction logic for EnumOptionTemplate.xaml
|
||||
/// </summary>
|
||||
public partial class EnumOptionTemplate : UserControl
|
||||
{
|
||||
private OptionProperty optionProperty = default!;
|
||||
|
||||
public ObservableCollection<object> PossibleEnumValues { get; } = new ObservableCollection<object>();
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private object value = default!;
|
||||
|
||||
public EnumOptionTemplate()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
this.DataContextChanged += this.EnumOptionTemplate_DataContextChanged;
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.Property == ValueProperty)
|
||||
{
|
||||
if (!this.IsChangeValid(e.NewValue))
|
||||
{
|
||||
this.Value = e.OldValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.optionProperty.Setter(e.NewValue);
|
||||
}
|
||||
}
|
||||
|
||||
base.OnPropertyChanged(e);
|
||||
}
|
||||
|
||||
private void EnumOptionTemplate_DataContextChanged(object _, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.Property != DataContextProperty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.NewValue is not OptionProperty optionProperty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.optionProperty = optionProperty;
|
||||
this.PossibleEnumValues.ClearAnd().AddRange(Enum.GetValues(this.optionProperty.Type).OfType<object>());
|
||||
this.Value = this.optionProperty.Getter();
|
||||
}
|
||||
|
||||
private bool IsChangeValid(object newValue)
|
||||
{
|
||||
return this.optionProperty.Validator.IsValid(newValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<UserControl x:Class="Daybreak.Controls.Options.OptionsSection"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls.Options"
|
||||
xmlns:models="clr-namespace:Daybreak.Models.Options"
|
||||
xmlns:buttons="clr-namespace:Daybreak.Controls.Buttons"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<ItemsControl ItemsSource="{Binding ElementName=_this, Path=Options, Mode=OneWay}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="{x:Type models:OptionSection}">
|
||||
<buttons:MenuButton Title="{Binding Name}"
|
||||
Foreground="White"
|
||||
HighlightColor="White"
|
||||
Height="30"
|
||||
Cursor="Hand"
|
||||
Clicked="MenuButton_Clicked"></buttons:MenuButton>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,101 @@
|
||||
using Daybreak.Attributes;
|
||||
using Daybreak.Controls.Buttons;
|
||||
using Daybreak.Launch;
|
||||
using Daybreak.Models.Options;
|
||||
using Daybreak.Services.Navigation;
|
||||
using Daybreak.Services.Options;
|
||||
using Daybreak.Views;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Core.Extensions;
|
||||
using System.Extensions;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Daybreak.Controls.Options;
|
||||
/// <summary>
|
||||
/// Interaction logic for OptionsSection.xaml
|
||||
/// </summary>
|
||||
public partial class OptionsSection : UserControl
|
||||
{
|
||||
private readonly IOptionsProvider optionsProvider;
|
||||
private readonly IViewManager viewManager;
|
||||
|
||||
public ObservableCollection<OptionSection> Options { get; } = new ObservableCollection<OptionSection>();
|
||||
|
||||
public OptionsSection(
|
||||
IOptionsProvider optionsProvider,
|
||||
IViewManager viewManager)
|
||||
{
|
||||
this.optionsProvider = optionsProvider.ThrowIfNull();
|
||||
this.viewManager = viewManager.ThrowIfNull();
|
||||
}
|
||||
|
||||
public OptionsSection()
|
||||
: this(Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IOptionsProvider>(),
|
||||
Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IViewManager>())
|
||||
{
|
||||
this.InitializeComponent();
|
||||
this.InitializeOptions();
|
||||
}
|
||||
|
||||
private void InitializeOptions()
|
||||
{
|
||||
var registeredOptions = this.optionsProvider.GetRegisteredOptionsTypes();
|
||||
foreach(var registeredType in registeredOptions)
|
||||
{
|
||||
if (!IsOptionsVisible(registeredType))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
this.Options.Add(new OptionSection
|
||||
{
|
||||
Name = GetOptionsName(registeredType),
|
||||
Type = registeredType
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetOptionsName(Type type)
|
||||
{
|
||||
if (type.GetCustomAttributes(true).FirstOrDefault(a => a.GetType() == typeof(OptionsNameAttribute)) is not OptionsNameAttribute optionsNameAttribute)
|
||||
{
|
||||
return type.Name;
|
||||
}
|
||||
|
||||
if (optionsNameAttribute.Name.IsNullOrWhiteSpace())
|
||||
{
|
||||
return type.Name;
|
||||
}
|
||||
|
||||
return optionsNameAttribute.Name!;
|
||||
}
|
||||
|
||||
private static bool IsOptionsVisible(Type optionType)
|
||||
{
|
||||
if (optionType.GetCustomAttribute<OptionsIgnoreAttribute>() is not null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void MenuButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
if (sender is not MenuButton button)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (button.DataContext is not OptionSection optionSection)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.viewManager.ShowView<OptionSectionView>(optionSection);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<UserControl x:Class="Daybreak.Controls.Options.PrimitiveRangeOptionTemplate"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls.Options"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="auto"></ColumnDefinition>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Slider IsMoveToPointEnabled="True"
|
||||
Minimum="{Binding ElementName=_this, Path=MinValue, Mode=OneWay}"
|
||||
Maximum="{Binding ElementName=_this, Path=MaxValue, Mode=OneWay}"
|
||||
Value="{Binding ElementName=_this, Path=Value, Mode=TwoWay}" />
|
||||
<TextBlock FontSize="16"
|
||||
Foreground="White"
|
||||
Grid.Column="1"
|
||||
Text="{Binding ElementName=_this, Path=Value, Mode=OneWay, StringFormat={}{0:#,#;-#,#;-}}"></TextBlock>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,69 @@
|
||||
using Daybreak.Models.Options;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Extensions;
|
||||
|
||||
namespace Daybreak.Controls.Options;
|
||||
/// <summary>
|
||||
/// Interaction logic for PrimitiveRangeOptionTemplate.xaml
|
||||
/// </summary>
|
||||
public partial class PrimitiveRangeOptionTemplate : UserControl
|
||||
{
|
||||
private OptionProperty optionProperty = default!;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private object value = default!;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private object minValue = default!;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private object maxValue = default!;
|
||||
|
||||
public PrimitiveRangeOptionTemplate(
|
||||
object minValue, object maxValue)
|
||||
{
|
||||
this.InitializeComponent();
|
||||
this.DataContextChanged += this.PrimitiveRangeOptionTemplate_DataContextChanged;
|
||||
this.MinValue = minValue;
|
||||
this.MaxValue = maxValue;
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.Property == ValueProperty)
|
||||
{
|
||||
if (!this.IsChangeValid(e.NewValue))
|
||||
{
|
||||
this.Value = e.OldValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.optionProperty.Setter(e.NewValue);
|
||||
}
|
||||
}
|
||||
|
||||
base.OnPropertyChanged(e);
|
||||
}
|
||||
|
||||
private void PrimitiveRangeOptionTemplate_DataContextChanged(object _, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.Property != DataContextProperty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.NewValue is not OptionProperty optionProperty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.optionProperty = optionProperty;
|
||||
this.Value = this.optionProperty.Getter();
|
||||
}
|
||||
|
||||
private bool IsChangeValid(object newValue)
|
||||
{
|
||||
return this.optionProperty.Validator.IsValid(newValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<UserControl x:Class="Daybreak.Controls.Options.StringOptionTemplate"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls.Options"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<TextBox Background="Transparent"
|
||||
Text="{Binding ElementName=_this, Path=Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
BorderBrush="Transparent"
|
||||
Foreground="White"
|
||||
FontSize="16"
|
||||
CaretBrush="White"
|
||||
VerticalContentAlignment="Center"
|
||||
VerticalAlignment="Stretch"
|
||||
TextWrapping="Wrap"></TextBox>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,66 @@
|
||||
using Daybreak.Models.Options;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Extensions;
|
||||
|
||||
namespace Daybreak.Controls.Options;
|
||||
/// <summary>
|
||||
/// Interaction logic for StringOptionTemplate.xaml
|
||||
/// </summary>
|
||||
public partial class StringOptionTemplate : UserControl
|
||||
{
|
||||
private OptionProperty optionProperty = default!;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private string value = string.Empty;
|
||||
|
||||
public StringOptionTemplate()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
this.DataContextChanged += this.StringOptionTemplate_DataContextChanged;
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.Property == ValueProperty &&
|
||||
e.NewValue is string newValue)
|
||||
{
|
||||
if (!this.IsChangeValid(newValue))
|
||||
{
|
||||
this.Value = e.OldValue as string;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.optionProperty.Setter(newValue);
|
||||
}
|
||||
}
|
||||
|
||||
base.OnPropertyChanged(e);
|
||||
}
|
||||
|
||||
private void StringOptionTemplate_DataContextChanged(object _, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.Property != DataContextProperty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.NewValue is not OptionProperty optionProperty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.optionProperty = optionProperty;
|
||||
if (this.optionProperty.Getter()?.ToString() is not string stringValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.Value = stringValue;
|
||||
}
|
||||
|
||||
private bool IsChangeValid(string newValue)
|
||||
{
|
||||
return this.optionProperty.Validator.IsValid(newValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<UserControl x:Class="Daybreak.Controls.PlayerContextMenu"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:guildwars="clr-namespace:Daybreak.Models.Guildwars"
|
||||
mc:Ignorable="d"
|
||||
d:DataContext="{d:DesignInstance Type=guildwars:PlayerInformation, IsDesignTimeCreatable=True}"
|
||||
d:DesignHeight="300" d:DesignWidth="100"
|
||||
Margin="5, 0, 5, 0">
|
||||
<StackPanel Background="#F0212121">
|
||||
<TextBlock Text="Party Member" FontSize="16" Foreground="White"></TextBlock>
|
||||
<TextBlock Text="{Binding NpcDefinition.Name}" Foreground="LightBlue" Cursor="Hand"
|
||||
MouseLeftButtonDown="TextBlock_MouseLeftButtonDown"></TextBlock>
|
||||
<WrapPanel>
|
||||
<TextBlock Text="Id: " Foreground="White"></TextBlock>
|
||||
<TextBlock Text="{Binding ModelType, Mode=OneWay}" Foreground="White"></TextBlock>
|
||||
</WrapPanel>
|
||||
<WrapPanel>
|
||||
<TextBlock Text="Lvl: " Foreground="White"></TextBlock>
|
||||
<TextBlock Text="{Binding Level, Mode=OneWay}" Foreground="White"></TextBlock>
|
||||
</WrapPanel>
|
||||
<WrapPanel>
|
||||
<TextBlock Text="{Binding PrimaryProfession.Alias, Mode=OneWay}" Foreground="White"></TextBlock>
|
||||
<TextBlock Text="/" Foreground="White"></TextBlock>
|
||||
<TextBlock Text="{Binding SecondaryProfession.Alias, Mode=OneWay}" Foreground="White"></TextBlock>
|
||||
</WrapPanel>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,23 @@
|
||||
using Daybreak.Models.Guildwars;
|
||||
using System;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Daybreak.Controls;
|
||||
/// <summary>
|
||||
/// Interaction logic for PlayerContextMenu.xaml
|
||||
/// </summary>
|
||||
public partial class PlayerContextMenu : UserControl
|
||||
{
|
||||
public event EventHandler<PlayerInformation?>? PlayerContextMenuClicked;
|
||||
|
||||
public PlayerContextMenu()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
private void TextBlock_MouseLeftButtonDown(object _, MouseButtonEventArgs e)
|
||||
{
|
||||
this.PlayerContextMenuClicked?.Invoke(this, this.DataContext as PlayerInformation? ?? default);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<UserControl x:Class="Daybreak.Controls.QuestContextMenu"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
xmlns:guildwars="clr-namespace:Daybreak.Models.Guildwars"
|
||||
mc:Ignorable="d"
|
||||
Background="#F0212121"
|
||||
d:DataContext="{d:DesignInstance Type=guildwars:QuestMetadata, IsDesignTimeCreatable=True}"
|
||||
d:DesignHeight="300" d:DesignWidth="100">
|
||||
<StackPanel Margin="5, 0, 5, 0">
|
||||
<TextBlock Text="{Binding Quest.Name}" FontSize="16" Foreground="White" TextWrapping="Wrap"></TextBlock>
|
||||
<TextBlock Text="{Binding Quest.WikiUrl}" TextWrapping="Wrap" Foreground="LightBlue" Cursor="Hand"
|
||||
MouseLeftButtonDown="TextBlock_MouseLeftButtonDown"></TextBlock>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,24 @@
|
||||
using Daybreak.Models.Guildwars;
|
||||
using System;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Daybreak.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for QuestContextMenu.xaml
|
||||
/// </summary>
|
||||
public partial class QuestContextMenu : UserControl
|
||||
{
|
||||
public event EventHandler<QuestMetadata?>? QuestContextMenuClicked;
|
||||
|
||||
public QuestContextMenu()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
private void TextBlock_MouseLeftButtonDown(object _, MouseButtonEventArgs e)
|
||||
{
|
||||
this.QuestContextMenuClicked?.Invoke(this, this.DataContext as QuestMetadata? ?? default);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Extensions;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Extensions;
|
||||
|
||||
|
||||
@@ -28,9 +28,9 @@
|
||||
<ColumnDefinition Width="auto"></ColumnDefinition>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock FontSize="16" Text="Username:" Foreground="White" Margin="5" Grid.Row="0" HorizontalAlignment="Right"></TextBlock>
|
||||
<TextBlock FontSize="16" Text="Password:" Foreground="White" Margin="5" Grid.Row="1" HorizontalAlignment="Right"></TextBlock>
|
||||
<TextBlock FontSize="16" Text="Character name:" Foreground="White" Margin="5" Grid.Row="2" HorizontalAlignment="Right"></TextBlock>
|
||||
<TextBlock FontSize="16" Text="Username:" Foreground="White" Margin="5" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Center"></TextBlock>
|
||||
<TextBlock FontSize="16" Text="Password:" Foreground="White" Margin="5" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Center"></TextBlock>
|
||||
<TextBlock FontSize="16" Text="Character name:" Foreground="White" Margin="5" Grid.Row="2" HorizontalAlignment="Right" VerticalAlignment="Center"></TextBlock>
|
||||
<TextBox Text="{Binding ElementName=_this, Path=Username, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Foreground="White" Background="Transparent"
|
||||
BorderThickness="1" HorizontalAlignment="Stretch" Grid.Row="0" Grid.Column="1"
|
||||
FontSize="16" TextChanged="UsernameTextbox_TextChanged" Margin="5"></TextBox>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Daybreak.Models.Builds;
|
||||
using Daybreak.Services.BuildTemplates;
|
||||
using System;
|
||||
using System.Core.Extensions;
|
||||
using System.Extensions;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
@@ -16,11 +18,15 @@ public partial class AttributeTemplate : UserControl
|
||||
{
|
||||
public event EventHandler<AttributeEntry>? HelpClicked;
|
||||
public event EventHandler<AttributeEntry>? AttributeChanged;
|
||||
|
||||
|
||||
private IAttributePointCalculator? attributePointCalculator;
|
||||
|
||||
[GenerateDependencyProperty(InitialValue = false)]
|
||||
private bool canAdd;
|
||||
[GenerateDependencyProperty(InitialValue = false)]
|
||||
private bool canSubtract;
|
||||
[GenerateDependencyProperty]
|
||||
private int attributePoints;
|
||||
|
||||
public AttributeTemplate()
|
||||
{
|
||||
@@ -28,6 +34,31 @@ public partial class AttributeTemplate : UserControl
|
||||
this.DataContextChanged += this.AttributeTemplate_DataContextChanged;
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnPropertyChanged(e);
|
||||
if (e.Property == AttributePointsProperty &&
|
||||
this.DataContext is AttributeEntry attributeEntry)
|
||||
{
|
||||
var remainingPoints = this.AttributePoints;
|
||||
var requiredPointsForNextLevel = this.attributePointCalculator?.GetPointsRequiredToIncreaseRank(attributeEntry.Points) ?? 0;
|
||||
if (remainingPoints < requiredPointsForNextLevel)
|
||||
{
|
||||
this.CanAdd = false;
|
||||
}
|
||||
else if (this.DataContext.As<AttributeEntry>().Points < 12)
|
||||
{
|
||||
this.CanAdd = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void InitializeAttributeTemplate(
|
||||
IAttributePointCalculator attributePointCalculator)
|
||||
{
|
||||
this.attributePointCalculator = attributePointCalculator.ThrowIfNull();
|
||||
}
|
||||
|
||||
private void AttributeTemplate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.NewValue is AttributeEntry attributeEntry)
|
||||
|
||||
@@ -4,9 +4,7 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
xmlns:interactivity="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:behaviors="clr-namespace:Daybreak.Behaviors"
|
||||
xmlns:converters="clr-namespace:Daybreak.Converters"
|
||||
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
Unloaded="BuildTemplate_Unloaded"
|
||||
@@ -30,20 +28,12 @@
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Text="Primary Profession: " FontSize="16" Foreground="White" Grid.Column="1"></TextBlock>
|
||||
<ListView FontSize="16" Foreground="White" Grid.Column="2" BorderThickness="0"
|
||||
Background="Transparent" ItemsSource="{Binding ElementName=_this, Path=Professions, Mode=OneWay}"
|
||||
SelectedItem="{Binding ElementName=_this, Path=PrimaryProfession, Mode=TwoWay}" Height="30"
|
||||
SelectionMode="Single" ScrollViewer.VerticalScrollBarVisibility="Disabled"
|
||||
PreviewMouseWheel="ListView_NavigateWithMouseWheel">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Name, Mode=OneWay}"></TextBlock>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<behaviors:ScrollIntoView></behaviors:ScrollIntoView>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
</ListView>
|
||||
<mah:SplitButton
|
||||
ItemsSource="{Binding ElementName=_this, Path=Professions, Mode=OneWay}"
|
||||
SelectedItem="{Binding ElementName=_this, Path=BuildEntry.Primary, Mode=TwoWay}"
|
||||
FontSize="16"
|
||||
Foreground="White"
|
||||
Grid.Column="2"></mah:SplitButton>
|
||||
<local:HelpButton Grid.Column="0" Foreground="White" Width="20" Height="20" Margin="3"
|
||||
Clicked="HelpButtonPrimary_Clicked" Cursor="Hand"></local:HelpButton>
|
||||
</Grid>
|
||||
@@ -54,29 +44,24 @@
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Text="Secondary Profession: " FontSize="16" Foreground="White" Grid.Column="1"></TextBlock>
|
||||
<ListView FontSize="16" Foreground="White" Grid.Column="2" BorderThickness="0"
|
||||
Background="Transparent" ItemsSource="{Binding ElementName=_this, Path=Professions, Mode=OneWay}"
|
||||
SelectedItem="{Binding ElementName=_this, Path=SecondaryProfession, Mode=TwoWay}" Height="30"
|
||||
SelectionMode="Single" ScrollViewer.VerticalScrollBarVisibility="Disabled"
|
||||
PreviewMouseWheel="ListView_NavigateWithMouseWheel">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Name, Mode=OneWay}"></TextBlock>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<behaviors:ScrollIntoView></behaviors:ScrollIntoView>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
</ListView>
|
||||
<mah:SplitButton
|
||||
ItemsSource="{Binding ElementName=_this, Path=Professions, Mode=OneWay}"
|
||||
SelectedItem="{Binding ElementName=_this, Path=BuildEntry.Secondary, Mode=TwoWay}"
|
||||
FontSize="16"
|
||||
Foreground="White"
|
||||
Grid.Column="2"></mah:SplitButton>
|
||||
<local:HelpButton Grid.Column="0" Foreground="White" Width="20" Height="20" Margin="3"
|
||||
Clicked="HelpButtonSecondary_Clicked" Cursor="Hand"></local:HelpButton>
|
||||
</Grid>
|
||||
<Grid Grid.Row="3">
|
||||
<ListBox Background="Transparent" ItemsSource="{Binding ElementName=_this, Path=Attributes, Mode=OneWay}"
|
||||
<ListBox Background="Transparent" ItemsSource="{Binding ElementName=_this, Path=BuildEntry.Attributes, Mode=OneWay}"
|
||||
HorizontalContentAlignment="Stretch" BorderThickness="0">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<local:AttributeTemplate HelpClicked="AttributeTemplate_HelpClicked" AttributeChanged="AttributeTemplate_AttributeChanged"></local:AttributeTemplate>
|
||||
<local:AttributeTemplate HelpClicked="AttributeTemplate_HelpClicked"
|
||||
AttributeChanged="AttributeTemplate_AttributeChanged"
|
||||
Loaded="AttributeTemplate_Loaded"
|
||||
AttributePoints="{Binding Path=AttributePoints, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"></local:AttributeTemplate>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
@@ -98,60 +83,60 @@
|
||||
</Grid.RowDefinitions>
|
||||
<local:SkillTemplate Grid.Column="0" x:Name="SkillTemplate0"
|
||||
Foreground="White" Cursor="Hand"
|
||||
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill0, Mode=TwoWay}"
|
||||
FontSize="22" DataContext="{Binding ElementName=_this, Path=BuildEntry.FirstSkill, Mode=TwoWay}"
|
||||
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
|
||||
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
|
||||
<local:SkillTemplate Grid.Column="1" x:Name="SkillTemplate1"
|
||||
Foreground="White" Cursor="Hand"
|
||||
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill1, Mode=TwoWay}"
|
||||
FontSize="22" DataContext="{Binding ElementName=_this, Path=BuildEntry.SecondSkill, Mode=TwoWay}"
|
||||
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
|
||||
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
|
||||
<local:SkillTemplate Grid.Column="2" x:Name="SkillTemplate2"
|
||||
Foreground="White" Cursor="Hand"
|
||||
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill2, Mode=TwoWay}"
|
||||
FontSize="22" DataContext="{Binding ElementName=_this, Path=BuildEntry.ThirdSkill, Mode=TwoWay}"
|
||||
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
|
||||
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
|
||||
<local:SkillTemplate Grid.Column="3" x:Name="SkillTemplate3"
|
||||
Foreground="White" Cursor="Hand"
|
||||
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill3, Mode=TwoWay}"
|
||||
FontSize="22" DataContext="{Binding ElementName=_this, Path=BuildEntry.FourthSkill, Mode=TwoWay}"
|
||||
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
|
||||
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
|
||||
<local:SkillTemplate Grid.Column="4" x:Name="SkillTemplate4"
|
||||
Foreground="White" Cursor="Hand"
|
||||
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill4, Mode=TwoWay}"
|
||||
FontSize="22" DataContext="{Binding ElementName=_this, Path=BuildEntry.FifthSkill, Mode=TwoWay}"
|
||||
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
|
||||
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
|
||||
<local:SkillTemplate Grid.Column="5" x:Name="SkillTemplate5"
|
||||
Foreground="White" Cursor="Hand"
|
||||
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill5, Mode=TwoWay}"
|
||||
FontSize="22" DataContext="{Binding ElementName=_this, Path=BuildEntry.SixthSkill, Mode=TwoWay}"
|
||||
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
|
||||
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
|
||||
<local:SkillTemplate Grid.Column="6" x:Name="SkillTemplate6"
|
||||
Foreground="White" Cursor="Hand"
|
||||
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill6, Mode=TwoWay}"
|
||||
FontSize="22" DataContext="{Binding ElementName=_this, Path=BuildEntry.SeventhSkill, Mode=TwoWay}"
|
||||
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
|
||||
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
|
||||
<local:SkillTemplate Grid.Column="7" x:Name="SkillTemplate7"
|
||||
Foreground="White" Cursor="Hand"
|
||||
FontSize="22" DataContext="{Binding ElementName=_this, Path=Skill7, Mode=TwoWay}"
|
||||
FontSize="22" DataContext="{Binding ElementName=_this, Path=BuildEntry.EigthSkill, Mode=TwoWay}"
|
||||
VerticalAlignment="Stretch" Clicked="SkillTemplate_Clicked"
|
||||
RemoveClicked="SkillTemplate_RemoveClicked"></local:SkillTemplate>
|
||||
<TextBlock Grid.Column="0" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
|
||||
Foreground="White" Text="{Binding ElementName=_this, Path=Skill0.Name, Mode=OneWay}"></TextBlock>
|
||||
Foreground="White" Text="{Binding ElementName=_this, Path=BuildEntry.FirstSkill.Name, Mode=OneWay}"></TextBlock>
|
||||
<TextBlock Grid.Column="1" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
|
||||
Foreground="White" Text="{Binding ElementName=_this, Path=Skill1.Name, Mode=OneWay}"></TextBlock>
|
||||
Foreground="White" Text="{Binding ElementName=_this, Path=BuildEntry.SecondSkill.Name, Mode=OneWay}"></TextBlock>
|
||||
<TextBlock Grid.Column="2" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
|
||||
Foreground="White" Text="{Binding ElementName=_this, Path=Skill2.Name, Mode=OneWay}"></TextBlock>
|
||||
Foreground="White" Text="{Binding ElementName=_this, Path=BuildEntry.ThirdSkill.Name, Mode=OneWay}"></TextBlock>
|
||||
<TextBlock Grid.Column="3" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
|
||||
Foreground="White" Text="{Binding ElementName=_this, Path=Skill3.Name, Mode=OneWay}"></TextBlock>
|
||||
Foreground="White" Text="{Binding ElementName=_this, Path=BuildEntry.FourthSkill.Name, Mode=OneWay}"></TextBlock>
|
||||
<TextBlock Grid.Column="4" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
|
||||
Foreground="White" Text="{Binding ElementName=_this, Path=Skill4.Name, Mode=OneWay}"></TextBlock>
|
||||
Foreground="White" Text="{Binding ElementName=_this, Path=BuildEntry.FifthSkill.Name, Mode=OneWay}"></TextBlock>
|
||||
<TextBlock Grid.Column="5" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
|
||||
Foreground="White" Text="{Binding ElementName=_this, Path=Skill5.Name, Mode=OneWay}"></TextBlock>
|
||||
Foreground="White" Text="{Binding ElementName=_this, Path=BuildEntry.SixthSkill.Name, Mode=OneWay}"></TextBlock>
|
||||
<TextBlock Grid.Column="6" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
|
||||
Foreground="White" Text="{Binding ElementName=_this, Path=Skill6.Name, Mode=OneWay}"></TextBlock>
|
||||
Foreground="White" Text="{Binding ElementName=_this, Path=BuildEntry.SeventhSkill.Name, Mode=OneWay}"></TextBlock>
|
||||
<TextBlock Grid.Column="7" Grid.Row="1" TextWrapping="Wrap" FontSize="16"
|
||||
Foreground="White" Text="{Binding ElementName=_this, Path=Skill7.Name, Mode=OneWay}"></TextBlock>
|
||||
Foreground="White" Text="{Binding ElementName=_this, Path=BuildEntry.EigthSkill.Name, Mode=OneWay}"></TextBlock>
|
||||
</Grid>
|
||||
<Grid Grid.Column="1" Grid.RowSpan="6">
|
||||
<local:ChromiumBrowserWrapper x:Name="SkillBrowser" ControlsEnabled="False" Width="0" AddressBarReadonly="True" CanNavigate="True"></local:ChromiumBrowserWrapper>
|
||||
@@ -170,10 +155,11 @@
|
||||
<ListView x:Name="SkillsListView"
|
||||
Grid.Row="1"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Hidden"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Auto"
|
||||
Background="Transparent"
|
||||
ScrollViewer.CanContentScroll="False"
|
||||
ItemsSource="{Binding ElementName=_this, Path=AvailableSkills, Mode=OneWay}"
|
||||
MouseDoubleClick="ListView_MouseDoubleClick">
|
||||
MouseDoubleClick="SkillListView_MouseDoubleClick">
|
||||
<ListView.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<VirtualizingStackPanel>
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
using Daybreak.Configuration;
|
||||
using Daybreak.Launch;
|
||||
using Daybreak.Models.Builds;
|
||||
using Daybreak.Models.Guildwars;
|
||||
using Daybreak.Services.BuildTemplates;
|
||||
using Daybreak.Services.IconRetrieve;
|
||||
using Daybreak.Utils;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Configuration;
|
||||
using System.ComponentModel;
|
||||
using System.Core.Extensions;
|
||||
using System.Extensions;
|
||||
using System.Linq;
|
||||
@@ -30,119 +29,44 @@ public partial class BuildTemplate : UserControl
|
||||
private const string InfoNamePlaceholder = "[NAME]";
|
||||
private const string BaseAddress = $"https://wiki.guildwars.com/wiki/{InfoNamePlaceholder}";
|
||||
|
||||
private bool suppressBuildChanged = false;
|
||||
private bool loadedProperties = false;
|
||||
private IIconBrowser? iconBrowser;
|
||||
private BuildEntry? loadedBuild;
|
||||
private bool showingSkillList = false;
|
||||
private bool replacingSecondaryProfession;
|
||||
private bool replacingPrimaryProfession;
|
||||
private IAttributePointCalculator? attributePointCalculator;
|
||||
private SkillTemplate? selectingSkillTemplate;
|
||||
private List<Skill>? skillListCache;
|
||||
private CancellationTokenSource? cancellationTokenSource = new();
|
||||
|
||||
public event EventHandler? BuildChanged;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private string skillSearchText = string.Empty;
|
||||
[GenerateDependencyProperty]
|
||||
private Profession primaryProfession = default!;
|
||||
private BuildEntry buildEntry;
|
||||
[GenerateDependencyProperty]
|
||||
private Profession secondaryProfession = default!;
|
||||
private int attributePoints;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private Skill skill0 = default!;
|
||||
[GenerateDependencyProperty]
|
||||
private Skill skill1 = default!;
|
||||
[GenerateDependencyProperty]
|
||||
private Skill skill2 = default!;
|
||||
[GenerateDependencyProperty]
|
||||
private Skill skill3 = default!;
|
||||
[GenerateDependencyProperty]
|
||||
private Skill skill4 = default!;
|
||||
[GenerateDependencyProperty]
|
||||
private Skill skill5 = default!;
|
||||
[GenerateDependencyProperty]
|
||||
private Skill skill6 = default!;
|
||||
[GenerateDependencyProperty]
|
||||
private Skill skill7 = default!;
|
||||
public ObservableCollection<Skill> AvailableSkills { get; } = new ObservableCollection<Skill>();
|
||||
public ObservableCollection<AttributeEntry> Attributes { get; } = new ObservableCollection<AttributeEntry>();
|
||||
public ObservableCollection<Profession> Professions { get; } = new ObservableCollection<Profession>(Profession.Professions);
|
||||
private List<Skill> availableSkills = new();
|
||||
|
||||
public event EventHandler? BuildChanged;
|
||||
public ObservableCollection<Profession> Professions { get; } = new ObservableCollection<Profession>();
|
||||
|
||||
public BuildTemplate()
|
||||
: this(Launcher.Instance.ApplicationServiceProvider.GetService<IAttributePointCalculator>()!)
|
||||
{
|
||||
this.InitializeComponent();
|
||||
this.InitializeProperties();
|
||||
this.DataContextChanged += this.BuildTemplate_DataContextChanged;
|
||||
|
||||
}
|
||||
|
||||
public async void InitializeTemplate(
|
||||
IIconCache iconRetriever,
|
||||
IIconBrowser iconBrowser,
|
||||
ILiveOptions<ApplicationConfiguration> liveOptions,
|
||||
IBuildTemplateManager buildTemplateManager,
|
||||
ILogger<ChromiumBrowserWrapper> logger)
|
||||
|
||||
public BuildTemplate(
|
||||
IAttributePointCalculator attributePointCalculator)
|
||||
{
|
||||
this.iconBrowser = iconBrowser.ThrowIfNull();
|
||||
await this.SkillBrowser.InitializeDefaultBrowser(liveOptions, buildTemplateManager, logger);
|
||||
this.SkillTemplate0.InitializeSkillTemplate(iconRetriever);
|
||||
this.SkillTemplate1.InitializeSkillTemplate(iconRetriever);
|
||||
this.SkillTemplate2.InitializeSkillTemplate(iconRetriever);
|
||||
this.SkillTemplate3.InitializeSkillTemplate(iconRetriever);
|
||||
this.SkillTemplate4.InitializeSkillTemplate(iconRetriever);
|
||||
this.SkillTemplate5.InitializeSkillTemplate(iconRetriever);
|
||||
this.SkillTemplate6.InitializeSkillTemplate(iconRetriever);
|
||||
this.SkillTemplate7.InitializeSkillTemplate(iconRetriever);
|
||||
this.attributePointCalculator = attributePointCalculator.ThrowIfNull();
|
||||
|
||||
this.InitializeComponent();
|
||||
this.HideSkillListView();
|
||||
this.HideInfoBrowser();
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnPropertyChanged(e);
|
||||
if (this.loadedProperties is false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Property == PrimaryProfessionProperty || e.Property == SecondaryProfessionProperty)
|
||||
{
|
||||
if (e.Property == PrimaryProfessionProperty)
|
||||
{
|
||||
this.loadedBuild!.Build!.Primary = this.PrimaryProfession;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.loadedBuild!.Build!.Secondary = this.SecondaryProfession;
|
||||
}
|
||||
|
||||
this.LoadSkills();
|
||||
this.LoadAttributes();
|
||||
if (this.suppressBuildChanged is false)
|
||||
{
|
||||
this.BuildChanged?.Invoke(this, new EventArgs());
|
||||
}
|
||||
}
|
||||
|
||||
if (e.Property == Skill0Property ||
|
||||
e.Property == Skill1Property ||
|
||||
e.Property == Skill2Property ||
|
||||
e.Property == Skill3Property ||
|
||||
e.Property == Skill4Property ||
|
||||
e.Property == Skill5Property ||
|
||||
e.Property == Skill6Property ||
|
||||
e.Property == Skill7Property)
|
||||
{
|
||||
if (this.suppressBuildChanged is false)
|
||||
{
|
||||
this.loadedBuild!.Build!.Skills[0] = this.Skill0;
|
||||
this.loadedBuild!.Build!.Skills[1] = this.Skill1;
|
||||
this.loadedBuild!.Build!.Skills[2] = this.Skill2;
|
||||
this.loadedBuild!.Build!.Skills[3] = this.Skill3;
|
||||
this.loadedBuild!.Build!.Skills[4] = this.Skill4;
|
||||
this.loadedBuild!.Build!.Skills[5] = this.Skill5;
|
||||
this.loadedBuild!.Build!.Skills[6] = this.Skill6;
|
||||
this.loadedBuild!.Build!.Skills[7] = this.Skill7;
|
||||
this.BuildChanged?.Invoke(this, new EventArgs());
|
||||
}
|
||||
}
|
||||
this.buildEntry = new BuildEntry();
|
||||
this.DataContextChanged += this.BuildTemplate_DataContextChanged;
|
||||
this.Professions.ClearAnd().AddRange(Profession.Professions);
|
||||
}
|
||||
|
||||
private void BuildTemplate_Unloaded(object sender, RoutedEventArgs e)
|
||||
@@ -150,144 +74,31 @@ public partial class BuildTemplate : UserControl
|
||||
this.cancellationTokenSource?.Cancel();
|
||||
}
|
||||
|
||||
private void InitializeProperties()
|
||||
{
|
||||
this.PrimaryProfession = Profession.None;
|
||||
this.SecondaryProfession = Profession.None;
|
||||
this.Skill0 = Skill.NoSkill;
|
||||
this.Skill1 = Skill.NoSkill;
|
||||
this.Skill2 = Skill.NoSkill;
|
||||
this.Skill3 = Skill.NoSkill;
|
||||
this.Skill4 = Skill.NoSkill;
|
||||
this.Skill5 = Skill.NoSkill;
|
||||
this.Skill6 = Skill.NoSkill;
|
||||
this.Skill7 = Skill.NoSkill;
|
||||
this.loadedProperties = true;
|
||||
}
|
||||
|
||||
private void BuildTemplate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if(e.NewValue is BuildEntry)
|
||||
if(e.NewValue is BuildEntry buildEntry)
|
||||
{
|
||||
this.LoadBuild();
|
||||
this.LoadSkills();
|
||||
this.LoadAttributes();
|
||||
}
|
||||
}
|
||||
|
||||
private void Grid_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
{
|
||||
this.HideSkillListView();
|
||||
this.HideInfoBrowser();
|
||||
}
|
||||
|
||||
private void LoadAttributes()
|
||||
{
|
||||
var possibleAttributes = new List<AttributeEntry>();
|
||||
if (this.PrimaryProfession != Profession.None)
|
||||
{
|
||||
possibleAttributes.Add(new AttributeEntry { Attribute = this.PrimaryProfession.PrimaryAttribute });
|
||||
possibleAttributes.AddRange(this.PrimaryProfession.Attributes!.Select(a => new AttributeEntry { Attribute = a }));
|
||||
}
|
||||
|
||||
if (this.SecondaryProfession != Profession.None && this.SecondaryProfession != this.PrimaryProfession)
|
||||
{
|
||||
possibleAttributes.AddRange(this.SecondaryProfession.Attributes!.Select(a => new AttributeEntry { Attribute = a }));
|
||||
}
|
||||
|
||||
this.Attributes.ClearAnd().AddRange(possibleAttributes.Select(entry =>
|
||||
{
|
||||
var maybePresentAttribute = this.loadedBuild!.Build!.Attributes.Where(buildEntry => entry.Attribute == buildEntry.Attribute).FirstOrDefault();
|
||||
if (maybePresentAttribute is null)
|
||||
if (this.BuildEntry is not null)
|
||||
{
|
||||
return entry;
|
||||
this.BuildEntry.PropertyChanged -= this.BuildEntry_Changed;
|
||||
}
|
||||
|
||||
this.BuildEntry = buildEntry;
|
||||
this.BuildEntry.PropertyChanged += this.BuildEntry_Changed;
|
||||
this.AttributePoints = this.attributePointCalculator!.GetRemainingFreePoints(this.BuildEntry.Build!);
|
||||
this.LoadSkills();
|
||||
}
|
||||
}
|
||||
|
||||
entry.Points = maybePresentAttribute.Points;
|
||||
return entry;
|
||||
}));
|
||||
|
||||
this.loadedBuild!.Build!.Attributes = this.Attributes.ToList();
|
||||
private void BuildEntry_Changed(object? sender, PropertyChangedEventArgs propertyChangedEventArgs)
|
||||
{
|
||||
this.LoadSkills();
|
||||
}
|
||||
|
||||
private async void LoadSkills()
|
||||
{
|
||||
if (this.Skill0.Profession != this.PrimaryProfession &&
|
||||
this.Skill0.Profession != this.SecondaryProfession &&
|
||||
this.Skill0.Profession != Profession.None)
|
||||
{
|
||||
this.Skill0 = Skill.NoSkill;
|
||||
}
|
||||
|
||||
if (this.Skill1.Profession != this.PrimaryProfession &&
|
||||
this.Skill1.Profession != this.SecondaryProfession &&
|
||||
this.Skill1.Profession != Profession.None)
|
||||
{
|
||||
this.Skill1 = Skill.NoSkill;
|
||||
}
|
||||
|
||||
if (this.Skill2.Profession != this.PrimaryProfession &&
|
||||
this.Skill2.Profession != this.SecondaryProfession &&
|
||||
this.Skill2.Profession != Profession.None)
|
||||
{
|
||||
this.Skill2 = Skill.NoSkill;
|
||||
}
|
||||
|
||||
if (this.Skill3.Profession != this.PrimaryProfession &&
|
||||
this.Skill3.Profession != this.SecondaryProfession &&
|
||||
this.Skill3.Profession != Profession.None)
|
||||
{
|
||||
this.Skill3 = Skill.NoSkill;
|
||||
}
|
||||
|
||||
if (this.Skill4.Profession != this.PrimaryProfession &&
|
||||
this.Skill4.Profession != this.SecondaryProfession &&
|
||||
this.Skill4.Profession != Profession.None)
|
||||
{
|
||||
this.Skill4 = Skill.NoSkill;
|
||||
}
|
||||
|
||||
if (this.Skill5.Profession != this.PrimaryProfession &&
|
||||
this.Skill5.Profession != this.SecondaryProfession &&
|
||||
this.Skill5.Profession != Profession.None)
|
||||
{
|
||||
this.Skill5 = Skill.NoSkill;
|
||||
}
|
||||
|
||||
if (this.Skill6.Profession != this.PrimaryProfession &&
|
||||
this.Skill6.Profession != this.SecondaryProfession &&
|
||||
this.Skill6.Profession != Profession.None)
|
||||
{
|
||||
this.Skill6 = Skill.NoSkill;
|
||||
}
|
||||
|
||||
if (this.Skill7.Profession != this.PrimaryProfession &&
|
||||
this.Skill7.Profession != this.SecondaryProfession &&
|
||||
this.Skill7.Profession != Profession.None)
|
||||
{
|
||||
this.Skill7 = Skill.NoSkill;
|
||||
}
|
||||
|
||||
var filteredSkills = await this.FilterSkills(this.SkillSearchText).ToListAsync().ConfigureAwait(true);
|
||||
this.AvailableSkills.ClearAnd().AddRange(filteredSkills);
|
||||
}
|
||||
|
||||
private void LoadBuild()
|
||||
{
|
||||
this.suppressBuildChanged = true;
|
||||
var build = this.DataContext.As<BuildEntry>();
|
||||
this.loadedBuild = build;
|
||||
this.PrimaryProfession = build.Build!.Primary;
|
||||
this.SecondaryProfession = build.Build.Secondary;
|
||||
this.Skill0 = build.Build.Skills[0];
|
||||
this.Skill1 = build.Build.Skills[1];
|
||||
this.Skill2 = build.Build.Skills[2];
|
||||
this.Skill3 = build.Build.Skills[3];
|
||||
this.Skill4 = build.Build.Skills[4];
|
||||
this.Skill5 = build.Build.Skills[5];
|
||||
this.Skill6 = build.Build.Skills[6];
|
||||
this.Skill7 = build.Build.Skills[7];
|
||||
this.suppressBuildChanged = false;
|
||||
this.PrepareSkillListCache(filteredSkills);
|
||||
}
|
||||
|
||||
private void BrowseToInfo(string infoName)
|
||||
@@ -301,8 +112,8 @@ public partial class BuildTemplate : UserControl
|
||||
{
|
||||
if (this.SkillBrowser.BrowserSupported is true)
|
||||
{
|
||||
this.HideSkillListView();
|
||||
this.SkillBrowser.Width = 400;
|
||||
this.SkillListContainer.Width = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,23 +127,89 @@ public partial class BuildTemplate : UserControl
|
||||
|
||||
private void ShowSkillListView()
|
||||
{
|
||||
this.SkillBrowser.Width = 0;
|
||||
this.HideInfoBrowser();
|
||||
this.SkillListContainer.Width = 400;
|
||||
}
|
||||
|
||||
private void HideSkillListView()
|
||||
{
|
||||
this.SkillListContainer.Width = 0;
|
||||
}
|
||||
|
||||
private void HelpButtonPrimary_Clicked(object sender, System.EventArgs e)
|
||||
{
|
||||
if (this.PrimaryProfession == Profession.None)
|
||||
this.SkillListContainer.Visibility = Visibility.Visible;
|
||||
this.showingSkillList = true;
|
||||
if (this.AvailableSkills is not null &&
|
||||
this.skillListCache?.Except(this.AvailableSkills).None() is true &&
|
||||
this.skillListCache.Count == this.AvailableSkills.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.BrowseToInfo(this.PrimaryProfession.Name!);
|
||||
this.AvailableSkills = this.skillListCache;
|
||||
}
|
||||
|
||||
private void HideSkillListView()
|
||||
{
|
||||
this.SkillListContainer.Visibility = Visibility.Hidden;
|
||||
this.SkillListContainer.Width = 0;
|
||||
this.showingSkillList = false;
|
||||
}
|
||||
|
||||
private void PrepareSkillListCache(List<Skill> skills)
|
||||
{
|
||||
/*
|
||||
* To improve application performance, only load the skill list when it is showing.
|
||||
* Otherwise, defer the loading to when the skill list will show.
|
||||
*/
|
||||
|
||||
this.skillListCache = skills;
|
||||
if (this.showingSkillList)
|
||||
{
|
||||
this.ShowSkillListView();
|
||||
}
|
||||
}
|
||||
|
||||
private async IAsyncEnumerable<Skill> FilterSkills(string searchTerm)
|
||||
{
|
||||
// Replace symbols to ease search
|
||||
searchTerm = searchTerm?.Replace("\"", "").Replace("!", "")!;
|
||||
|
||||
foreach (var skill in Skill.Skills)
|
||||
{
|
||||
if (skill == Skill.NoSkill)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (skill.Profession != this.BuildEntry!.Primary &&
|
||||
skill.Profession != this.BuildEntry!.Secondary &&
|
||||
skill.Profession != Profession.None)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (searchTerm.IsNullOrWhiteSpace())
|
||||
{
|
||||
yield return skill;
|
||||
continue;
|
||||
}
|
||||
|
||||
var matchesName = await Task.Run(() => StringUtils.MatchesSearchString(skill.Name!.Replace("\"", "").Replace("!", ""), searchTerm!));
|
||||
if (matchesName)
|
||||
{
|
||||
yield return skill;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Grid_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
{
|
||||
this.HideSkillListView();
|
||||
this.HideInfoBrowser();
|
||||
}
|
||||
|
||||
private void HelpButtonPrimary_Clicked(object sender, System.EventArgs e)
|
||||
{
|
||||
if (this.BuildEntry!.Primary == Profession.None)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.BrowseToInfo(this.BuildEntry.Primary.Name!);
|
||||
if (e is RoutedEventArgs routedEventArgs)
|
||||
{
|
||||
routedEventArgs.Handled = true;
|
||||
@@ -341,12 +218,12 @@ public partial class BuildTemplate : UserControl
|
||||
|
||||
private void HelpButtonSecondary_Clicked(object sender, System.EventArgs e)
|
||||
{
|
||||
if (this.SecondaryProfession == Profession.None)
|
||||
if (this.BuildEntry!.Secondary == Profession.None)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.BrowseToInfo(this.SecondaryProfession.Name!);
|
||||
this.BrowseToInfo(this.BuildEntry.Secondary.Name!);
|
||||
if (e is RoutedEventArgs routedEventArgs)
|
||||
{
|
||||
routedEventArgs.Handled = true;
|
||||
@@ -362,6 +239,7 @@ public partial class BuildTemplate : UserControl
|
||||
{
|
||||
e.ThrowIfNull();
|
||||
this.BuildChanged?.Invoke(this, new EventArgs());
|
||||
this.AttributePoints = this.attributePointCalculator!.GetRemainingFreePoints(this.BuildEntry.Build!);
|
||||
}
|
||||
|
||||
private void SkillTemplate_Clicked(object sender, RoutedEventArgs e)
|
||||
@@ -389,10 +267,41 @@ public partial class BuildTemplate : UserControl
|
||||
|
||||
private void SkillTemplate_RemoveClicked(object sender, System.EventArgs e)
|
||||
{
|
||||
sender.As<SkillTemplate>().DataContext = Skill.NoSkill;
|
||||
if (sender == this.SkillTemplate0)
|
||||
{
|
||||
this.BuildEntry.FirstSkill = Skill.NoSkill;
|
||||
}
|
||||
else if (sender == this.SkillTemplate1)
|
||||
{
|
||||
this.BuildEntry.SecondSkill = Skill.NoSkill;
|
||||
}
|
||||
else if (sender == this.SkillTemplate2)
|
||||
{
|
||||
this.BuildEntry.ThirdSkill = Skill.NoSkill;
|
||||
}
|
||||
else if (sender == this.SkillTemplate3)
|
||||
{
|
||||
this.BuildEntry.FourthSkill = Skill.NoSkill;
|
||||
}
|
||||
else if (sender == this.SkillTemplate4)
|
||||
{
|
||||
this.BuildEntry.FifthSkill = Skill.NoSkill;
|
||||
}
|
||||
else if (sender == this.SkillTemplate5)
|
||||
{
|
||||
this.BuildEntry.SixthSkill = Skill.NoSkill;
|
||||
}
|
||||
else if (sender == this.SkillTemplate6)
|
||||
{
|
||||
this.BuildEntry.SeventhSkill = Skill.NoSkill;
|
||||
}
|
||||
else if (sender == this.SkillTemplate7)
|
||||
{
|
||||
this.BuildEntry.EigthSkill = Skill.NoSkill;
|
||||
}
|
||||
}
|
||||
|
||||
private void ListView_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
private void SkillListView_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
{
|
||||
if (this.selectingSkillTemplate is null)
|
||||
{
|
||||
@@ -400,77 +309,45 @@ public partial class BuildTemplate : UserControl
|
||||
return;
|
||||
}
|
||||
|
||||
this.selectingSkillTemplate.DataContext = sender.As<ListView>().SelectedItem;
|
||||
var selectedSkilll = sender.As<ListView>().SelectedItem.As<Skill>();
|
||||
if (this.selectingSkillTemplate == this.SkillTemplate0)
|
||||
{
|
||||
this.BuildEntry.FirstSkill = selectedSkilll;
|
||||
}
|
||||
else if (this.selectingSkillTemplate == this.SkillTemplate1)
|
||||
{
|
||||
this.BuildEntry.SecondSkill = selectedSkilll;
|
||||
}
|
||||
else if (this.selectingSkillTemplate == this.SkillTemplate2)
|
||||
{
|
||||
this.BuildEntry.ThirdSkill = selectedSkilll;
|
||||
}
|
||||
else if (this.selectingSkillTemplate == this.SkillTemplate3)
|
||||
{
|
||||
this.BuildEntry.FourthSkill = selectedSkilll;
|
||||
}
|
||||
else if (this.selectingSkillTemplate == this.SkillTemplate4)
|
||||
{
|
||||
this.BuildEntry.FifthSkill = selectedSkilll;
|
||||
}
|
||||
else if (this.selectingSkillTemplate == this.SkillTemplate5)
|
||||
{
|
||||
this.BuildEntry.SixthSkill = selectedSkilll;
|
||||
}
|
||||
else if (this.selectingSkillTemplate == this.SkillTemplate6)
|
||||
{
|
||||
this.BuildEntry.SeventhSkill = selectedSkilll;
|
||||
}
|
||||
else if (this.selectingSkillTemplate == this.SkillTemplate7)
|
||||
{
|
||||
this.BuildEntry.EigthSkill = selectedSkilll;
|
||||
}
|
||||
|
||||
this.HideSkillListView();
|
||||
this.loadedBuild!.Build!.Skills[0] = this.Skill0;
|
||||
this.loadedBuild!.Build!.Skills[1] = this.Skill1;
|
||||
this.loadedBuild!.Build!.Skills[2] = this.Skill2;
|
||||
this.loadedBuild!.Build!.Skills[3] = this.Skill3;
|
||||
this.loadedBuild!.Build!.Skills[4] = this.Skill4;
|
||||
this.loadedBuild!.Build!.Skills[5] = this.Skill5;
|
||||
this.loadedBuild!.Build!.Skills[6] = this.Skill6;
|
||||
this.loadedBuild!.Build!.Skills[7] = this.Skill7;
|
||||
}
|
||||
|
||||
private void ListView_NavigateWithMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
|
||||
private void AttributeTemplate_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
if (e.Delta > 0)
|
||||
{
|
||||
sender.As<ListView>().SelectedIndex = sender.As<ListView>().SelectedIndex > 0 ?
|
||||
sender.As<ListView>().SelectedIndex - 1 :
|
||||
0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sender.As<ListView>().SelectedIndex = sender.As<ListView>().SelectedIndex < sender.As<ListView>().Items.Count - 1 ?
|
||||
sender.As<ListView>().SelectedIndex + 1 :
|
||||
sender.As<ListView>().Items.Count;
|
||||
}
|
||||
}
|
||||
|
||||
private void ScrollViewer_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
|
||||
{
|
||||
if (sender is not ScrollViewer scrollViewer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - e.Delta);
|
||||
}
|
||||
|
||||
private async IAsyncEnumerable<Skill> FilterSkills(string searchTerm)
|
||||
{
|
||||
// Replace symbols to ease search
|
||||
searchTerm = searchTerm?.Replace("\"", "").Replace("!", "")!;
|
||||
|
||||
foreach (var skill in Skill.Skills)
|
||||
{
|
||||
if (skill == Skill.NoSkill)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (skill.Profession != this.PrimaryProfession &&
|
||||
skill.Profession != this.SecondaryProfession &&
|
||||
skill.Profession != Profession.None)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (searchTerm.IsNullOrWhiteSpace())
|
||||
{
|
||||
yield return skill;
|
||||
continue;
|
||||
}
|
||||
|
||||
var matchesName = await Task.Run(() => StringUtils.MatchesSearchString(skill.Name!.Replace("\"", "").Replace("!", ""), searchTerm!));
|
||||
if (matchesName)
|
||||
{
|
||||
yield return skill;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
sender.As<AttributeTemplate>().InitializeAttributeTemplate(this.attributePointCalculator!);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="auto"></ColumnDefinition>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid HorizontalAlignment="Stretch">
|
||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Center">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"></RowDefinition>
|
||||
</Grid.RowDefinitions>
|
||||
@@ -26,10 +26,10 @@
|
||||
<ColumnDefinition Width="auto"></ColumnDefinition>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock FontSize="22" Text="Path:" Foreground="White" Margin="5" Grid.Row="0" HorizontalAlignment="Right"></TextBlock>
|
||||
<TextBlock FontSize="16" Text="Path:" Foreground="White" Margin="5" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Center"></TextBlock>
|
||||
<TextBox Foreground="White" Background="Transparent" Text="{Binding ElementName=_this, Path=Path, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
BorderThickness="1" HorizontalAlignment="Stretch" Grid.Row="0" Grid.Column="1"
|
||||
FontSize="22" TextChanged="TextBox_TextChanged" Margin="5"></TextBox>
|
||||
FontSize="16" TextChanged="TextBox_TextChanged" Margin="5"></TextBox>
|
||||
</Grid>
|
||||
<WrapPanel Grid.Column="1">
|
||||
<local:FilePickerGlyph Width="30" Height="30" Foreground="White" VerticalAlignment="Top" Margin="5"
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<UserControl x:Class="Daybreak.Controls.Templates.QuestLogTemplate"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls.Templates"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<StackPanel x:Name="ItemStackPanel">
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,170 @@
|
||||
using Daybreak.Models.Guildwars;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Extensions;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace Daybreak.Controls.Templates;
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for QuestLogTemplate.xaml
|
||||
/// </summary>
|
||||
public partial class QuestLogTemplate : UserControl
|
||||
{
|
||||
private const string UncategorizedQuestsString = "Uncategorized Quests";
|
||||
private List<IGrouping<Map?, QuestMetadata>>? questLogCache;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private List<QuestMetadata> quests;
|
||||
|
||||
public event EventHandler<Map?>? MapClicked;
|
||||
public event EventHandler<Quest?>? QuestClicked;
|
||||
|
||||
public QuestLogTemplate()
|
||||
{
|
||||
this.quests = new List<QuestMetadata>();
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnPropertyChanged(e);
|
||||
|
||||
if (e.Property == QuestsProperty)
|
||||
{
|
||||
this.DrawQuestLogLayout();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawQuestLogLayout()
|
||||
{
|
||||
var questLog = this.Quests?.GroupBy(q => q.From).OrderBy(g => g.Key?.Name).ToList();
|
||||
if (!this.DetectQuestLogChange(questLog))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.questLogCache = questLog;
|
||||
if (this.questLogCache is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.ItemStackPanel.Children.Clear();
|
||||
|
||||
foreach(var grouping in this.questLogCache)
|
||||
{
|
||||
var location = grouping.Key;
|
||||
var locationTextBlock = new OpaqueButton
|
||||
{
|
||||
Text = grouping.Key?.Name ?? UncategorizedQuestsString,
|
||||
FontSize = 18,
|
||||
Cursor = grouping.Key is null ? Cursors.Arrow : Cursors.Hand,
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
TextHorizontalAlignment = HorizontalAlignment.Left,
|
||||
Highlight = Brushes.White,
|
||||
HighlightOpacity = grouping.Key is null ? 0 : 0.6
|
||||
};
|
||||
|
||||
locationTextBlock.MouseLeftButtonDown += (_, _) => this.OnMapClicked(location);
|
||||
this.ItemStackPanel.Children.Add(locationTextBlock);
|
||||
var rectangle = new Rectangle
|
||||
{
|
||||
Height = 1,
|
||||
};
|
||||
|
||||
var rectangleForegroundBinding = new Binding("Foreground")
|
||||
{
|
||||
Source = this
|
||||
};
|
||||
|
||||
rectangle.SetBinding(Rectangle.FillProperty, rectangleForegroundBinding);
|
||||
this.ItemStackPanel.Children.Add(rectangle);
|
||||
foreach (var questMetadata in grouping)
|
||||
{
|
||||
var quest = questMetadata.Quest;
|
||||
var questTextBlock = new OpaqueButton
|
||||
{
|
||||
Text = quest?.Name,
|
||||
FontSize = 20,
|
||||
Cursor = Cursors.Hand,
|
||||
Highlight = Brushes.White,
|
||||
HighlightOpacity = 0.6,
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
TextHorizontalAlignment = HorizontalAlignment.Left
|
||||
};
|
||||
|
||||
questTextBlock.MouseLeftButtonDown += (_, _) => this.OnQuestClicked(quest);
|
||||
this.ItemStackPanel.Children.Add(questTextBlock);
|
||||
}
|
||||
|
||||
this.ItemStackPanel.Children.Add(new Rectangle
|
||||
{
|
||||
Fill = Brushes.Transparent,
|
||||
Height = 10,
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private bool DetectQuestLogChange(List<IGrouping<Map?, QuestMetadata>>? newQuestLog)
|
||||
{
|
||||
if (this.questLogCache is null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (newQuestLog is null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.questLogCache.Count != newQuestLog.Count)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
for (var i = 0; i < this.questLogCache.Count; i++)
|
||||
{
|
||||
var grouping1 = this.questLogCache[i];
|
||||
var grouping2 = newQuestLog[i];
|
||||
if (grouping1.Key?.Id != grouping2.Key?.Id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var cachedQuests = grouping1.ToList();
|
||||
var newQuests = grouping2.ToList();
|
||||
if (cachedQuests.Count != newQuests.Count)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
for (var j = 0; j < cachedQuests.Count; j++)
|
||||
{
|
||||
if (cachedQuests[j].Quest?.Id != newQuests[j].Quest?.Id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void OnMapClicked(Map? map)
|
||||
{
|
||||
this.MapClicked?.Invoke(this, map);
|
||||
}
|
||||
|
||||
private void OnQuestClicked(Quest? quest)
|
||||
{
|
||||
this.QuestClicked?.Invoke(this, quest);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
using Daybreak.Models.Guildwars;
|
||||
using Daybreak.Launch;
|
||||
using Daybreak.Models.Guildwars;
|
||||
using Daybreak.Services.IconRetrieve;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Core.Extensions;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Extensions;
|
||||
@@ -27,15 +30,16 @@ public partial class SkillTemplate : UserControl
|
||||
private double borderOpacity;
|
||||
|
||||
public SkillTemplate()
|
||||
: this(Launcher.Instance.ApplicationServiceProvider.GetRequiredService<IIconCache>())
|
||||
{
|
||||
this.InitializeComponent();
|
||||
this.DataContextChanged += this.SkillTemplate_DataContextChanged;
|
||||
}
|
||||
|
||||
public void InitializeSkillTemplate(IIconCache iconRetriever)
|
||||
public SkillTemplate(
|
||||
IIconCache iconCache)
|
||||
{
|
||||
this.iconRetriever = iconRetriever;
|
||||
this.SkillTemplate_DataContextChanged(this, new DependencyPropertyChangedEventArgs(UserControl.DataContextProperty, null, this.DataContext));
|
||||
this.iconRetriever = iconCache.ThrowIfNull();
|
||||
this.InitializeComponent();
|
||||
this.DataContextChanged += this.SkillTemplate_DataContextChanged;
|
||||
}
|
||||
|
||||
private async void SkillTemplate_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<UserControl x:Class="Daybreak.Controls.VerticalResourceBar"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<Viewbox VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Stretch="Fill">
|
||||
<Grid Width="1">
|
||||
<Rectangle
|
||||
Fill="{Binding ElementName=_this, Path=BarColor, Mode=OneWay}"
|
||||
VerticalAlignment="{Binding ElementName=_this, Path=FillAlignment, Mode=OneWay}"
|
||||
HorizontalAlignment="Stretch"
|
||||
Height="{Binding ElementName=_this, Path=MaxResourceValue, Mode=TwoWay}"></Rectangle>
|
||||
<Rectangle
|
||||
Fill="#F0212121"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"></Rectangle>
|
||||
<Rectangle
|
||||
Fill="{Binding ElementName=_this, Path=BarColor, Mode=OneWay}"
|
||||
VerticalAlignment="{Binding ElementName=_this, Path=FillAlignment, Mode=OneWay}"
|
||||
HorizontalAlignment="Stretch"
|
||||
Height="{Binding ElementName=_this, Path=CurrentResourceValue, Mode=TwoWay}"></Rectangle>
|
||||
</Grid>
|
||||
</Viewbox>
|
||||
<TextBlock
|
||||
FontSize="{Binding ElementName=_this, Path=FontSize, Mode=OneWay}"
|
||||
FontFamily="{Binding ElementName=_this, Path=FontFamily, Mode=OneWay}"
|
||||
Text="{Binding ElementName=_this, Path=Text, Mode=OneWay}"
|
||||
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"></TextBlock>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Extensions;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Daybreak.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for ResourceBar.xaml
|
||||
/// </summary>
|
||||
public partial class VerticalResourceBar : UserControl
|
||||
{
|
||||
[GenerateDependencyProperty]
|
||||
private double currentResourceValue;
|
||||
[GenerateDependencyProperty]
|
||||
private double maxResourceValue;
|
||||
[GenerateDependencyProperty]
|
||||
private Brush barColor;
|
||||
[GenerateDependencyProperty]
|
||||
private string text;
|
||||
[GenerateDependencyProperty(InitialValue = VerticalAlignment.Bottom)]
|
||||
private VerticalAlignment fillAlignment;
|
||||
|
||||
public VerticalResourceBar()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
this.MaxResourceValue = 1;
|
||||
this.CurrentResourceValue = 0;
|
||||
this.barColor = Brushes.Transparent;
|
||||
this.text = string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<UserControl x:Class="Daybreak.Controls.WorldPlayerContextMenu"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
xmlns:guildwars="clr-namespace:Daybreak.Models.Guildwars"
|
||||
mc:Ignorable="d"
|
||||
d:DataContext="{d:DesignInstance Type=guildwars:WorldPlayerInformation, IsDesignTimeCreatable=True}"
|
||||
d:DesignHeight="300" d:DesignWidth="100">
|
||||
<StackPanel Background="#F0212121">
|
||||
<TextBlock
|
||||
Margin="5, 0, 5, 0"
|
||||
Text="{Binding Name, Mode=OneWay}" FontSize="16" Foreground="White"></TextBlock>
|
||||
<WrapPanel
|
||||
Margin="5, 0, 5, 0">
|
||||
<TextBlock Text="Lvl: " Foreground="White"></TextBlock>
|
||||
<TextBlock Text="{Binding Level, Mode=OneWay}" Foreground="White"></TextBlock>
|
||||
</WrapPanel>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Daybreak.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for WorldPlayerContextMenu.xaml
|
||||
/// </summary>
|
||||
public partial class WorldPlayerContextMenu : UserControl
|
||||
{
|
||||
public WorldPlayerContextMenu()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
}
|
||||
+38
-58
@@ -8,16 +8,44 @@
|
||||
<UseWPF>true</UseWPF>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<Platforms>AnyCPU;x86</Platforms>
|
||||
<Platforms>AnyCPU;x86;x64</Platforms>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<ApplicationIcon>Daybreak.ico</ApplicationIcon>
|
||||
<IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation>
|
||||
<Version>0.9.8</Version>
|
||||
<Version>0.9.8.44</Version>
|
||||
<EnableWindowsTargeting>true</EnableWindowsTargeting>
|
||||
<UserSecretsId>cfb2a489-db80-448d-a969-80270f314c46</UserSecretsId>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Services\Drawing\Resources\Bag.svg" />
|
||||
<None Remove="Services\Drawing\Resources\CircledStar.svg" />
|
||||
<None Remove="Services\Drawing\Resources\Dungeon.svg" />
|
||||
<None Remove="Services\Drawing\Resources\DungeonBoss.svg" />
|
||||
<None Remove="Services\Drawing\Resources\DungeonKey.svg" />
|
||||
<None Remove="Services\Drawing\Resources\Scroll.svg" />
|
||||
<None Remove="Services\Drawing\Resources\Skull.svg" />
|
||||
<None Remove="Services\Drawing\Resources\StairsDown.svg" />
|
||||
<None Remove="Services\Drawing\Resources\StairsUp.svg" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Services\Drawing\Resources\Bag.svg" />
|
||||
<EmbeddedResource Include="Services\Drawing\Resources\CircledStar.svg" />
|
||||
<EmbeddedResource Include="Services\Drawing\Resources\Dungeon.svg" />
|
||||
<EmbeddedResource Include="Services\Drawing\Resources\DungeonBoss.svg" />
|
||||
<EmbeddedResource Include="Services\Drawing\Resources\Scroll.svg" />
|
||||
<EmbeddedResource Include="Services\Drawing\Resources\Skull.svg" />
|
||||
<EmbeddedResource Include="Services\Drawing\Resources\StairsDown.svg" />
|
||||
<EmbeddedResource Include="Services\Drawing\Resources\StairsUp.svg" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Services\Drawing\Resources\DungeonKey.svg" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\.editorconfig" Link=".editorconfig" />
|
||||
</ItemGroup>
|
||||
@@ -37,76 +65,28 @@
|
||||
</Target>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="LiteDB" Version="5.0.15" />
|
||||
<PackageReference Include="LiteDB" Version="5.0.16" />
|
||||
<PackageReference Include="MahApps.Metro" Version="2.4.9" />
|
||||
<PackageReference Include="Microsoft.CorrelationVector" Version="1.0.42" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1587.40" />
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1661.34" />
|
||||
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="ScottPlot.WPF" Version="4.1.63" />
|
||||
<PackageReference Include="securifybv.ShellLink" Version="0.1.0" />
|
||||
<PackageReference Include="Slim" Version="1.9.2" />
|
||||
<PackageReference Include="Svg" Version="3.4.4" />
|
||||
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
|
||||
<PackageReference Include="SystemExtensions.NetCore" Version="1.0.1" />
|
||||
<PackageReference Include="SystemExtensions.NetStandard" Version="1.5.0" />
|
||||
<PackageReference Include="WCL" Version="1.0.2" />
|
||||
<PackageReference Include="WpfExtended" Version="0.7.1" />
|
||||
<PackageReference Include="WpfExtended" Version="0.7.2" />
|
||||
<PackageReference Include="WpfExtended.SourceGeneration" Version="0.1.1" />
|
||||
<PackageReference Include="WpfScreenHelper" Version="2.1.0" />
|
||||
<PackageReference Include="WriteableBitmapEx" Version="1.6.8" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Controls\Buttons\SynchronizeButton.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Controls\Buttons\HelpButton.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Controls\Buttons\MinusButton.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Controls\Glyphs\StarGlyph.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Controls\Buttons\CancelButton.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Views\IconDownloadView.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\Buttons\SynchronizeButton.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Controls\Buttons\HelpButton.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Controls\Buttons\MinusButton.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Controls\Buttons\MaximizeButton.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Controls\Glyphs\StarGlyph.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Controls\Buttons\CancelButton.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Views\IconDownloadView.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(Configuration)' == 'Release'">
|
||||
<Exec Command="echo.>$(Version).version" />
|
||||
|
||||
+35
-57
@@ -1,16 +1,15 @@
|
||||
using Daybreak.Configuration;
|
||||
using Daybreak.Exceptions;
|
||||
using Daybreak.Services.Drawing;
|
||||
using Daybreak.Services.ExceptionHandling;
|
||||
using Daybreak.Services.Navigation;
|
||||
using Daybreak.Services.Options;
|
||||
using Daybreak.Services.Startup;
|
||||
using Daybreak.Services.Updater.PostUpdate;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Slim;
|
||||
using Slim.Integration.ServiceCollection;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Extensions;
|
||||
|
||||
@@ -21,12 +20,14 @@ public sealed class Launcher : ExtendedApplication<MainWindow>
|
||||
public readonly static Launcher Instance = new();
|
||||
|
||||
private ILogger? logger;
|
||||
private IExceptionHandler? exceptionHandler;
|
||||
|
||||
public System.IServiceProvider ApplicationServiceProvider => this.ServiceProvider;
|
||||
|
||||
[STAThread]
|
||||
public static int Main()
|
||||
{
|
||||
RegisterMahAppsStyle();
|
||||
return LaunchMainWindow();
|
||||
}
|
||||
|
||||
@@ -36,71 +37,30 @@ public sealed class Launcher : ExtendedApplication<MainWindow>
|
||||
ProjectConfiguration.RegisterResolvers(serviceManager);
|
||||
return services.BuildSlimServiceProvider(serviceManager);
|
||||
}
|
||||
|
||||
protected override void RegisterServices(IServiceCollection services)
|
||||
{
|
||||
ProjectConfiguration.RegisterServices(services);
|
||||
}
|
||||
|
||||
protected override bool HandleException(Exception e)
|
||||
{
|
||||
if (e is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.logger is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (e is FatalException fatalException)
|
||||
{
|
||||
this.logger.LogCritical(e, $"{nameof(FatalException)} encountered. Closing application");
|
||||
MessageBox.Show(fatalException.ToString());
|
||||
File.WriteAllText("crash.log", e.ToString());
|
||||
return false;
|
||||
}
|
||||
else if (e is TargetInvocationException targetInvocationException && e.InnerException is FatalException innerFatalException)
|
||||
{
|
||||
this.logger.LogCritical(e, $"{nameof(FatalException)} encountered. Closing application");
|
||||
MessageBox.Show(innerFatalException.ToString());
|
||||
File.WriteAllText("crash.log", e.ToString());
|
||||
return false;
|
||||
}
|
||||
else if (e is AggregateException aggregateException)
|
||||
{
|
||||
if (aggregateException.InnerExceptions.FirstOrDefault() is COMException comException &&
|
||||
comException.Message.Contains("Invalid window handle"))
|
||||
{
|
||||
/*
|
||||
* Ignore exception caused by browser failing to initialize due to missing window.
|
||||
* Likely caused by switching views before browser was initialized.
|
||||
*/
|
||||
this.logger.LogError(e, "Failed to initialize browser");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (e.Message.Contains("Invalid window handle.") && e.StackTrace?.Contains("CoreWebView2Environment.CreateCoreWebView2ControllerAsync") is true)
|
||||
{
|
||||
/*
|
||||
* Ignore exception caused by browser failing to initialize due to missing window.
|
||||
* Likely caused by switching views before the browser was initialized.
|
||||
*/
|
||||
this.logger.LogError(e, "Failed to initialize browser");
|
||||
return true;
|
||||
}
|
||||
|
||||
this.logger.LogError(e, $"Unhandled exception caught {e.GetType()}");
|
||||
MessageBox.Show(e.ToString());
|
||||
return true;
|
||||
return this.exceptionHandler?.HandleException(e) is true;
|
||||
}
|
||||
|
||||
protected override void ApplicationStarting()
|
||||
{
|
||||
ProjectConfiguration.RegisterViews(this.ServiceProvider.GetService<IViewManager>()!);
|
||||
ProjectConfiguration.RegisterPostUpdateActions(this.ServiceProvider.GetService<IPostUpdateActionProducer>()!);
|
||||
ProjectConfiguration.RegisterOptions(this.ServiceProvider.GetRequiredService<IOptionsProducer>()!);
|
||||
ProjectConfiguration.RegisterViews(this.ServiceProvider.GetRequiredService<IViewManager>()!);
|
||||
ProjectConfiguration.RegisterPostUpdateActions(this.ServiceProvider.GetRequiredService<IPostUpdateActionProducer>()!);
|
||||
ProjectConfiguration.RegisterStartupActions(this.ServiceProvider.GetRequiredService<IStartupActionProducer>()!);
|
||||
ProjectConfiguration.RegisterDrawingModules(this.ServiceProvider.GetRequiredService<IDrawingModuleProducer>()!);
|
||||
|
||||
this.logger = this.ServiceProvider.GetRequiredService<ILogger<Launcher>>();
|
||||
this.exceptionHandler = this.ServiceProvider.GetRequiredService<IExceptionHandler>();
|
||||
this.RegisterViewContainer();
|
||||
}
|
||||
|
||||
protected override void ApplicationClosing()
|
||||
{
|
||||
}
|
||||
@@ -111,8 +71,26 @@ public sealed class Launcher : ExtendedApplication<MainWindow>
|
||||
var mainWindow = this.ServiceProvider.GetRequiredService<MainWindow>();
|
||||
viewManager.RegisterContainer(mainWindow.Container);
|
||||
}
|
||||
|
||||
|
||||
private static int LaunchMainWindow()
|
||||
{
|
||||
return Instance.Run();
|
||||
}
|
||||
|
||||
private static void RegisterMahAppsStyle()
|
||||
{
|
||||
Instance.Resources.MergedDictionaries.Add(new ResourceDictionary
|
||||
{
|
||||
Source = new Uri("pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml", UriKind.RelativeOrAbsolute)
|
||||
});
|
||||
Instance.Resources.MergedDictionaries.Add(new ResourceDictionary
|
||||
{
|
||||
Source = new Uri("pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml", UriKind.RelativeOrAbsolute)
|
||||
});
|
||||
Instance.Resources.MergedDictionaries.Add(new ResourceDictionary
|
||||
{
|
||||
Source = new Uri("pack://application:,,,/MahApps.Metro;component/Styles/Themes/Dark.Steel.xaml", UriKind.RelativeOrAbsolute)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user