Compare commits

...
75 Commits
Author SHA1 Message Date
amacocianandGitHub 338ac100a1 Realm of torment npcs (#288) 2023-06-27 16:55:44 +00:00
amacocianandGitHub 01badcee6a More nightfall npcs (#287) 2023-06-27 11:26:25 +00:00
amacocianandGitHub 302cf1114c Fix bug with trader messages options (#286)
Reorder options
2023-06-26 19:05:13 +00:00
amacocianandGitHub 613e03dc75 High def skill icons (#284)
* Use high-definition skill icons

* Increment version
2023-06-26 17:42:38 +00:00
amacocianandGitHub 4267359cb2 DSOAL support (#282)
Reworked mod support
2023-06-26 13:16:29 +00:00
amacocianandGitHub daac8ec787 More nightfall npcs (#281)
Fixes for quests and npcs
UTs for quests, npcs and items
2023-06-26 10:00:17 +00:00
amacocianandGitHub 857adec459 More vabbian npcs (#280)
* More vabbian npcs

* Increment version
2023-06-23 08:50:56 +00:00
amacocianandGitHub b46e10a1a6 Vabbian npcs (#279) 2023-06-22 12:50:18 +00:00
amacocianandGitHub 10799b7e9c Fix modifiers view (#278)
Show modifiers for unknown items
Fix enemy drawing
Added some npcs
2023-06-21 20:19:44 +00:00
amacocianandGitHub 6bbeaa1738 More Kournan npcs (#277) 2023-06-21 17:36:43 +00:00
amacocianandGitHub 1a0f1cbf9a Performance improvements to images (#275) 2023-06-21 09:20:23 +00:00
amacocianandGitHub 68e708fe96 Price history improvements (#274)
Inventory view improvements
Base for inscriptions
Base for runes
2023-06-20 00:32:28 +00:00
amacocianandGitHub a2166f2327 Add Guild Hall npcs (#272) 2023-06-18 15:24:23 +00:00
amacocianandGitHub 6d55366bdc Mark unknown entities with a question mark (#271) 2023-06-18 11:58:39 +00:00
amacocianandGitHub 28fcaa81cf Installer fix (#270)
Closes #269
2023-06-17 18:52:01 +00:00
amacocianandGitHub c5efc2990e Guildwars copy service (#268)
Fix one focus view bug
2023-06-17 14:18:35 +02:00
amacocianandGitHub 597010b9a1 Memory reader base pointer fixes (#267)
Installer fixes
2023-06-16 16:17:20 +00:00
amacocianandGitHub 1f71816256 Make regex trade searches case-insensitive (#264) 2023-06-16 13:09:37 +00:00
amacocianandGitHub 7c3618d2b5 Trade alerts (#263)
Notifications improvements
2023-06-16 11:06:18 +00:00
amacocianandGitHub df9038039c Highlight color specific trading words (#262) 2023-06-09 10:13:36 +00:00
amacocianandGitHub 9a4b23976a Release v56 (#259)
Inventory Component toggle
Fix inventory component visibility
Inventory component performance improvements
2023-06-08 21:33:13 +00:00
amacocianandGitHub 8732e0fe5e Release v55 (#256)
Sounds
Split FocusView into components
Focus view inventory component
Notifications view
Internet connectivity
2023-06-08 19:58:26 +00:00
amacocianandGitHub c23b84c4d5 Improve pathfinding algorithm (#255)
Improve minimap color contrasts
2023-06-01 20:56:49 +00:00
amacocianandGitHub 345b6a792a Color coded boss icons based on primary profession (#254) 2023-05-30 22:00:00 +00:00
amacocianandGitHub d9ae52165d Show npc profession in context menu (#252) 2023-05-30 20:54:03 +00:00
amacocianandGitHub 4f40e8328b Release v51 (#251)
* Release v51
Fixes duplicate npcs
Adds npcs for all games
Improve focus view memory reading latency
Clean up metrics
Closes #202
Closes #203
Closes #201

* Small fixes
2023-05-30 17:08:25 +00:00
amacocianandGitHub ebdd828b06 Improve the price chart date visibility (#250) 2023-05-22 18:49:41 +00:00
amacocianandGitHub 711acb55db Release v49 (#249)
Cache loaded images to improve performance
Separate quotes from trade views
Implement price history view
Local price history database
Fix notification popups
Fix icon caching

Closes #248
Closes #247
Closes #246
Closes #245
2023-05-19 20:08:43 +00:00
amacocianandGitHub 7dfc21bfe0 Setup NotificationService (#244)
Separate price quotes from trades
2023-05-16 20:05:28 +00:00
amacocianandGitHub 78644a6eec Add Flag and Person minimap icons (#242) 2023-05-15 20:41:11 +00:00
amacocianandGitHub 30b1d77575 Implement trade chat views (#239)
More UI improvements
Much better IconCache implementation
Re-enable screen selector
2023-05-15 17:55:25 +00:00
amacocianandGitHub a9626d03a4 Update README.md (#238)
Signed-off-by: Macocian Alexandru Victor <amacocian@yahoo.com>
2023-05-14 20:57:05 +02:00
amacocianandGitHub be731bbffb Unify UI buttons (#237)
* Unify UI buttons
Use Theme Accent as highlight
Fix browser concurrency issues
Fix browser enable/disable during runtime
Unify button sizes and looks

Closes #235
Closes #236

* Increment version
2023-05-10 20:35:24 +00:00
amacocianandGitHub 8cd40e2de3 Dynamic Options View (#234)
Import MahApps Metro
2023-05-08 18:52:10 +00:00
amacocianandGitHub 7745594bb6 Draw engagement area for party (#233)
Clean uMod installation
Closes #232
Closes #220
2023-05-07 13:07:37 +00:00
amacocianandGitHub e43bedf1c2 Fix auto-load template procedure (#229)
Fix character name loading on guildwars startup
Closes #126
2023-05-03 21:22:32 +00:00
amacocianandGitHub d6623a8646 Automatically add downloaded tpfs to mod list (#228)
* Automatically add downloaded tpfs to mod list
Closes #227

* Increment version
2023-05-03 16:33:25 +00:00
amacocianandGitHub 403ba51a7d Add possibility to download tpf files from the uMod browser page (#226)
* Add possibility to download tpf files from the uMod browser page
* Organize menu by sections
* Limit logs to improve performance
* Fix screenmanageroptions name
* Fix focusview default webpage
2023-05-03 15:04:40 +00:00
amacocianandGitHub b185a606e6 Integrate with mods (#223)
* Integrate with GWToolboxpp and uMod
* Separate configuration into multiple extensible parts
* Generalize downloading service
2023-05-03 11:10:18 +00:00
amacocianandGitHub 342a9a4826 Add more minimap icons (#221)
Support for team colored icons
2023-05-01 11:36:22 +00:00
amacocianandGitHub 2df2e8a65e Added support for multi-color SVG icons (#219) 2023-04-30 16:04:09 +00:00
amacocianandGitHub 2d5e9231a9 Minimap improvements (#217)
Map icons have overload for minimum size
Pathfinding now finds paths even when start/end points are not on the map
Map can now draw SVGs
2023-04-30 12:31:11 +00:00
amacocianandGitHub 818e2bf1d0 Drawing bugfixes (#210) 2023-04-10 18:47:03 +02:00
amacocianandGitHub f0a876f7cc Rework minimap drawing (#208)
Setup extensible drawing modules
2023-04-10 13:57:35 +00:00
amacocianandGitHub 3fae8f91cb Add support for map icons (#207)
Add res-shrine icons to minimap
2023-04-09 20:26:15 +00:00
amacocianandGitHub 8b08056ca7 Show targeted npc details (#206) 2023-04-09 18:30:25 +00:00
amacocianandGitHub 39eaf53deb Setup startup actions (#204)
Rename temp installer on startup
2023-04-09 16:21:11 +00:00
amacocianandGitHub 4674d1d7e5 Add support for npc types and names (#200)
* Introduce npcs and support for npc names

* Update version
2023-04-07 10:34:11 +00:00
amacocianandGitHub b8b5cc8b1d Optimize pathfinding (#198)
* Optimize pathfinding
Simplified initial search to no longer take distance into account
Metrics for pathfinding

* Increment version
2023-04-05 15:30:48 +00:00
amacocianandGitHub dc987233a7 Retry pathfinding loading on failure (#197) 2023-04-04 21:35:16 +00:00
amacocianandGitHub 266b400c22 Pathfinding v1 (#196)
* Pathfinding algorithm for minimap

* Fix adjacency lists

* Better adjancency list generation

* Improve pathfinding algorithm

* Some other tries

* Pathfinding algorithm for minimap

* Fix adjacency lists

* Better adjancency list generation

* Improve pathfinding algorithm

* Some other tries

* Improvements to the minimap and pathing

* Improve pathfinder

* Draw path forests

* Implement working pathfinding solution
2023-04-04 20:43:14 +00:00
amacocianandGitHub a4ac083fd0 General client improvements (#195)
Hit-target for off-screen quest markers
Save window position on every move instead of only on closing
2023-04-03 20:21:12 +00:00
amacocianandGitHub 320dd16838 Show objective direction for loaded quests (#194) 2023-04-02 19:22:17 +00:00
amacocianandGitHub 5c05c636bc Add quest marker functionality to the minimap (#192) 2023-04-02 14:57:49 +00:00
amacocianandGitHub 7103a8a83a Show party member context (#190)
Fix one Map id
2023-03-25 18:30:29 +00:00
amacocianandGitHub ad749d801a Minimap improvements (#189)
Closes #187
Closes #188

Minimap performance improvements
Add context menues for main player and living entities
2023-03-25 08:36:15 +00:00
amacocianandGitHub 747e9a0490 Minimap improvements (#186)
Closes #185
Closes #184
Closes #183
Show player information when right clicking on minimap
Allow minimap fullscreen
Decouple scrolling from memory reading frequency
Ignore task cancelled exceptions
2023-03-24 22:39:52 +00:00
amacocianandGitHub 836402bd0f Draw player position history on the minimap (#182) 2023-03-21 15:19:25 +00:00
amacocianandGitHub a3d5e1ce1f Add another check for corrupted images (#181)
* Add another check for corrupted images

* Check validity of icons on startup
Improve screen position saving
2023-03-21 08:45:22 +00:00
f2cc59a4ab Daybreak 0.9.8.18 (#179)
* Minimap implementation

* Fix minimap

* Add debounce logic to entities positions

* Cleanup

* Fix x64 build memory reading
Move build to x64
Fix entity debouncing
Added some backstops to prevent reading corrupted memory

* Add minimap zooming and panning functionality
Add main window position saving procedure

* Increment version

---------

Co-authored-by: Alex Macocian <amacocian@hotmail.com>
2023-03-20 21:38:53 +02:00
amacocianandGitHub 6ea77f7e05 Bugfixes and improvements (#176)
Closes #175
Closes #174
Closes #173
2023-03-09 19:53:28 +00:00
amacocianandGitHub 5ea8df7cb9 Bugfixes to memory reader (#172) 2023-03-08 20:17:58 +00:00
amacocianandGitHub c70e8ec90d Implement Guildwars downloader (#171) 2023-03-08 13:24:14 +00:00
amacocianandGitHub 210e3a8cb1 Add title data to memory retrieval (#169)
Add metrics for diagnostics
Add metrics view
2023-03-07 17:20:20 +00:00
amacocianandGitHub a0c3bb094c Performance improvements (#168)
* Performance improvements and bugfixes

* Increment version

* Better builds links

* Unify loading widget size
2023-03-05 08:55:21 +01:00
amacocianandGitHub b4d932692a Reduce words in FocusView character line (#167) 2023-03-04 17:18:03 +00:00
amacocianandGitHub 667534a07a Fix version parsing (#166) 2023-03-04 18:06:53 +01:00
amacocianandGitHub 159928f24b Integrate builds with Focus view (#164)
* Integrate builds with Focus view
Detect when GameData is invalid
Detect when reading memory is faulty
Show current character data in Focus View
Closes #161
Closes #162
Closes #163

* Increment version

* Bugfix version comparison script
2023-03-04 17:21:08 +01:00
amacocianandGitHub 8a91ded610 Fix buildtemplate skill removal (#160)
Closes #159
2023-03-03 22:28:27 +00:00
amacocianandGitHub 4226b7eb32 Improve performance of buildtemplateview (#158) 2023-03-03 21:50:25 +00:00
amacocianandGitHub b61c99dd1c Fix build template failing to load secondary attributes (#157)
Improve build template handling logic
Add attribute points calculator
2023-03-03 20:51:03 +00:00
amacocianandGitHub 1ccb0d5334 Add map entry to FocusView (#155)
Fix Icon Downloader
Improve settings navigation
Change multiple views to match the design of the rest of the application
2023-03-02 20:11:00 +01:00
amacocianandGitHub 7fa01353dd UX Bugfixes and improvements (#151)
Fix memory reading issues when restarting the game
Fixed current energy and health retrieval and calculation
Added health and energy bars in focus view
Fixed focus view size calculation
Improved buildtemplate performance
Improved buildtemplate navigation
Added loading widgets to menus that are loading asynchronously
2023-03-02 16:49:00 +00:00
amacocianandGitHub 4f849d880b Ux improvements (#148)
Rearrange quest log layout
Fix some quest names
Fix some buttons ux
Mitigate issues when reading guildwars memory
2023-03-02 01:58:07 +00:00
amacocianandGitHub 4b60c96aad Closes #146 #145 (#147) 2023-03-02 00:39:52 +00:00
621 changed files with 27222 additions and 4492 deletions
+5 -2
View File
@@ -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 ####
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
strategy:
matrix:
targetplatform: [x86]
targetplatform: [x64]
runs-on: windows-latest
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
strategy:
matrix:
targetplatform: [x86]
targetplatform: [x64]
runs-on: windows-latest
+1 -1
View File
@@ -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>
+18 -13
View File
@@ -14,6 +14,12 @@ if (File.Exists(tempFile) is false)
return;
}
while (Process.GetProcesses().Where(p => p.ProcessName == "Daybreak").FirstOrDefault()?.HasExited is false)
{
Console.WriteLine($"Detected Daybreak process is still running. Waiting 5s and retrying");
await Task.Delay(5000);
}
Console.WriteLine("Unpacking files...");
try
{
@@ -23,32 +29,31 @@ catch
{
}
Console.WriteLine("Deleting package");
try
{
File.Delete(tempFile);
}
catch(Exception e)
{
Console.WriteLine($"Failed to delete {tempFile}.\n{e}");
}
Console.WriteLine("Deleting browser caches");
try
{
Directory.Delete("BrowserData", true);
}
catch(Exception e)
catch(Exception)
{
Console.WriteLine($"Failed to delete BrowserData.\n{e}");
}
try
{
Directory.Delete("Daybreak.exe.WebView2", true);
}
catch(Exception e)
catch(Exception)
{
Console.WriteLine($"Failed to delete Daybreak.exe.WebView2.\n{e}");
}
Console.WriteLine("Deleting package");
try
{
File.Delete(tempFile);
}
catch (Exception e)
{
Console.WriteLine($"Failed to delete {tempFile}.\n{e}");
}
Console.WriteLine("Launching application");
+9 -6
View File
@@ -3,16 +3,19 @@
<PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework>
<IsPackable>false</IsPackable>
<Platforms>AnyCPU;x86</Platforms>
<Platforms>AnyCPU;x86;x64</Platforms>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.10.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="FluentAssertions" Version="6.11.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.1" />
<PackageReference Include="Moq" Version="4.18.4" />
<PackageReference Include="MSTest.TestAdapter" Version="3.0.2" />
<PackageReference Include="MSTest.TestFramework" Version="3.0.2" />
<PackageReference Include="coverlet.collector" Version="3.2.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.0.4" />
<PackageReference Include="MSTest.TestFramework" Version="3.0.4" />
<PackageReference Include="coverlet.collector" Version="6.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
</ItemGroup>
+15
View File
@@ -0,0 +1,15 @@
using Daybreak.Models.Guildwars;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using System.Extensions;
using System.Linq;
using System.Reflection;
using System.Text;
namespace Daybreak.Tests.Models;
[TestClass]
public sealed class InscriptionTests : ItemTestsBase<Inscription>
{
protected override IEnumerable<Inscription> AllItems { get; } = Inscription.Inscriptions;
}
+74
View File
@@ -0,0 +1,74 @@
using Daybreak.Models.Guildwars;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using System.Text;
using System;
using System.Linq;
namespace Daybreak.Tests.Models;
[TestClass]
public sealed class ItemBaseTests
{
[TestMethod]
public void TryParse_UnknownId_Fails()
{
var found = ItemBase.TryParse(int.MaxValue, modifiers: default, out var item);
found.Should().BeFalse();
item.Should().BeNull();
}
[TestMethod]
public void Parse_UnknownId_ThrowsInvalidOperationException()
{
var action = () => ItemBase.Parse(int.MaxValue, modifiers: default);
action.Should().Throw<InvalidOperationException>();
}
[TestMethod]
public void TryParse_KnownId_Succeeds()
{
var found = ItemBase.TryParse(Inscription.WeaponInscription.Id, Inscription.WeaponInscription.Modifiers, out var inscription);
found.Should().BeTrue();
inscription.Should().Be(Inscription.WeaponInscription);
}
[TestMethod]
public void Parse_KnownId_ReturnsExpected()
{
var inscription = ItemBase.Parse(Inscription.WeaponInscription.Id, Inscription.WeaponInscription.Modifiers);
inscription.Should().Be(Inscription.WeaponInscription);
}
[TestMethod]
public void ItemList_Should_ContainOnlyUniqueItems()
{
var itemMap = new Dictionary<ItemBase, int>();
foreach (var item in ItemBase.AllItems)
{
if (!itemMap.TryGetValue(item, out _))
{
itemMap[item] = 0;
}
itemMap[item] += 1;
}
var errorMessage = new StringBuilder("Duplicated item entries: ");
foreach (var tuple in itemMap)
{
if (tuple.Value > 1)
{
errorMessage.Append(tuple.Key.Name);
errorMessage.Append(", ");
}
}
if (itemMap.Any(kvp => kvp.Value > 1))
{
Assert.Fail(errorMessage.ToString());
}
}
}
+78
View File
@@ -0,0 +1,78 @@
using Daybreak.Models.Guildwars;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using System.Extensions;
using System.Linq;
using System.Reflection;
using System.Text;
namespace Daybreak.Tests.Models;
public abstract class ItemTestsBase<T>
where T : ItemBase
{
protected abstract IEnumerable<T> AllItems { get; }
[TestMethod]
public void InscriptionList_Should_ContainOnlyUniqueItems()
{
var itemMap = new Dictionary<T, int>();
foreach (var item in this.AllItems)
{
if (!itemMap.TryGetValue(item, out _))
{
itemMap[item] = 0;
}
itemMap[item] += 1;
}
var errorMessage = new StringBuilder($"Duplicated {typeof(T).Name} entries: ");
foreach (var tuple in itemMap)
{
if (tuple.Value > 1)
{
errorMessage.Append(tuple.Key.Name);
errorMessage.Append(", ");
}
}
if (itemMap.Any(kvp => kvp.Value > 1))
{
Assert.Fail(errorMessage.ToString());
}
}
[TestMethod]
public void InscriptionList_Should_ContainAllNpcs()
{
var itemMap = new Dictionary<T, bool>();
var definedItemFields = typeof(T).GetFields(BindingFlags.Static | BindingFlags.Public).Where(f => f.FieldType == typeof(T));
foreach (var field in definedItemFields)
{
var item = field.GetValue(default).Cast<T>();
itemMap[item] = false;
}
foreach (var item in this.AllItems)
{
itemMap[item] = true;
}
var errorMessage = new StringBuilder($"{typeof(T).Name} entries not in list: ");
foreach (var tuple in itemMap)
{
if (tuple.Value is false)
{
errorMessage.Append(tuple.Key.Name);
errorMessage.Append(", ");
}
}
if (itemMap.Any(kvp => kvp.Value is false))
{
Assert.Fail(errorMessage.ToString());
}
}
}
+11
View File
@@ -0,0 +1,11 @@
using Daybreak.Models.Guildwars;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
namespace Daybreak.Tests.Models;
[TestClass]
public sealed class MaterialTests : ItemTestsBase<Material>
{
protected override IEnumerable<Material> AllItems { get; } = Material.All;
}
+108
View File
@@ -0,0 +1,108 @@
using Daybreak.Models.Guildwars;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Extensions;
using System.Linq;
using System.Reflection;
using System.Text;
namespace Daybreak.Tests.Models;
[TestClass]
public sealed class NpcTests
{
[TestMethod]
public void TryParse_UnknownId_Fails()
{
var found = Npc.TryParse(int.MaxValue, out var npc);
found.Should().BeFalse();
npc.Should().BeNull();
}
[TestMethod]
public void Parse_UnknownId_ThrowsInvalidOperationException()
{
var action = () => Npc.Parse(int.MaxValue);
action.Should().Throw<InvalidOperationException>();
}
[TestMethod]
public void TryParse_KnownId_Succeeds()
{
var found = Npc.TryParse(Npc.Kormir.Ids.FirstOrDefault(), out var npc);
found.Should().BeTrue();
npc.Should().Be(Npc.Kormir);
}
[TestMethod]
public void Parse_KnownId_ReturnsExpected()
{
var npc = Npc.Parse(Npc.Kormir.Ids.FirstOrDefault());
npc.Should().Be(Npc.Kormir);
}
[TestMethod]
public void NpcList_Should_ContainOnlyUniqueItems()
{
var npcMap = new Dictionary<string, int>();
foreach(var npc in Npc.Npcs)
{
if (!npcMap.TryGetValue(npc.Name.ToLower(), out _))
{
npcMap[npc.Name.ToLower()] = 0;
}
npcMap[npc.Name.ToLower()] += 1;
}
var errorMessage = new StringBuilder("Duplicated npc entries: ");
foreach(var tuple in npcMap)
{
if (tuple.Value > 1)
{
errorMessage.Append(tuple.Key);
errorMessage.Append(", ");
}
}
if (npcMap.Any(kvp => kvp.Value > 1))
{
Assert.Fail(errorMessage.ToString());
}
}
[TestMethod]
public void NpcList_Should_ContainAllNpcs()
{
var npcMap = new Dictionary<Npc, bool>();
var definedNpcsFields = typeof(Npc).GetFields(BindingFlags.Static | BindingFlags.Public).Where(f => f.FieldType == typeof(Npc));
foreach(var field in definedNpcsFields)
{
var npc = field.GetValue(default).Cast<Npc>();
npcMap[npc] = false;
}
foreach(var npc in Npc.Npcs)
{
npcMap[npc] = true;
}
var errorMessage = new StringBuilder("Npcs not in list: ");
foreach(var tuple in npcMap)
{
if (tuple.Value is false)
{
errorMessage.Append(tuple.Key.Name);
errorMessage.Append(", ");
}
}
if (npcMap.Any(kvp => kvp.Value is false))
{
Assert.Fail(errorMessage.ToString());
}
}
}
+108
View File
@@ -0,0 +1,108 @@
using Daybreak.Models.Guildwars;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System;
using System.Linq;
using System.Extensions;
namespace Daybreak.Tests.Models;
[TestClass]
public sealed class QuestTests
{
[TestMethod]
public void TryParse_UnknownId_Fails()
{
var found = Quest.TryParse(int.MaxValue, out var quest);
found.Should().BeFalse();
quest.Should().BeNull();
}
[TestMethod]
public void Parse_UnknownId_ThrowsInvalidOperationException()
{
var action = () => Quest.Parse(int.MaxValue);
action.Should().Throw<InvalidOperationException>();
}
[TestMethod]
public void TryParse_KnownId_Succeeds()
{
var found = Quest.TryParse(Quest.RaisuPalaceZaishenQuest.Id, out var quest);
found.Should().BeTrue();
quest.Should().Be(Quest.RaisuPalaceZaishenQuest);
}
[TestMethod]
public void Parse_KnownId_ReturnsExpected()
{
var quest = Quest.Parse(Quest.RaisuPalaceZaishenQuest.Id);
quest.Should().Be(Quest.RaisuPalaceZaishenQuest);
}
[TestMethod]
public void QuestList_Should_ContainOnlyUniqueItems()
{
var questMap = new Dictionary<int, int>();
foreach (var quest in Quest.Quests)
{
if (!questMap.TryGetValue(quest.Id, out _))
{
questMap[quest.Id] = 0;
}
questMap[quest.Id] += 1;
}
var errorMessage = new StringBuilder("Duplicated quest entries: ");
foreach (var tuple in questMap)
{
if (tuple.Value > 1)
{
errorMessage.Append(tuple.Key);
errorMessage.Append(", ");
}
}
if (questMap.Any(kvp => kvp.Value > 1))
{
Assert.Fail(errorMessage.ToString());
}
}
[TestMethod]
public void QuestList_Should_ContainAllNpcs()
{
var questMap = new Dictionary<Quest, bool>();
var definedNpcsFields = typeof(Quest).GetFields(BindingFlags.Static | BindingFlags.Public).Where(f => f.FieldType == typeof(Quest));
foreach (var field in definedNpcsFields)
{
var quest = field.GetValue(default).Cast<Quest>();
questMap[quest] = false;
}
foreach (var quest in Quest.Quests)
{
questMap[quest] = true;
}
var errorMessage = new StringBuilder("Quests not in list: ");
foreach (var tuple in questMap)
{
if (tuple.Value is false)
{
errorMessage.Append(tuple.Key.Name);
errorMessage.Append(", ");
}
}
if (questMap.Any(kvp => kvp.Value is false))
{
Assert.Fail(errorMessage.ToString());
}
}
}
+11
View File
@@ -0,0 +1,11 @@
using Daybreak.Models.Guildwars;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
namespace Daybreak.Tests.Models;
[TestClass]
public sealed class RuneTests : ItemTestsBase<Rune>
{
protected override IEnumerable<Rune> AllItems { get; } = Rune.Runes;
}
+51
View File
@@ -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);
@@ -21,7 +21,7 @@ public class JsonLoggerProviderTests
{
File.Delete("Daybreak.db");
this.liteDatabase = new LiteDatabase("Daybreak.db");
this.logsManager = new JsonLogsManager(this.liteDatabase);
this.logsManager = new JsonLogsManager(this.liteDatabase.GetCollection<Daybreak.Models.Log>());
this.loggerProvider = new CVLoggerProvider(this.logsManager);
}
+14
View File
@@ -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!;
}
+17
View File
@@ -0,0 +1,17 @@
using System;
using System.Windows.Controls;
namespace Daybreak.Attributes;
/// <summary>
/// Mark a custom view that is supposed to set the value of the option.
/// In the option view, a button will be displayed that will redirect to the custom view.
/// The custom view must be registered in the <see cref="Services.Navigation.IViewManager"/>
/// </summary>
/// <typeparam name="T">Type of view. Has to be registered in the <see cref="Services.Navigation.IViewManager"./></typeparam>
[AttributeUsage(AttributeTargets.Property)]
public sealed class OptionSetterView<T> : Attribute
where T : UserControl
{
public string Action { get; set; } = "Set";
}
@@ -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,47 +0,0 @@
using Daybreak.Configuration.FocusView;
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; }
[JsonProperty("FocusViewOptions")]
public FocusViewOptions FocusViewOptions { get; set; } = new FocusViewOptions();
}
@@ -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();
}
@@ -1,8 +1,9 @@
namespace Daybreak.Configuration.FocusView;
public enum EnergyDisplay
public enum ExperienceDisplay
{
TotalCurretAndTotalMax,
CurrentLevelCurrentAndCurrentLevelMax,
RemainingUntilNextLevel
RemainingUntilNextLevel,
Percentage
}
@@ -1,19 +0,0 @@
using Newtonsoft.Json;
namespace Daybreak.Configuration.FocusView;
public sealed class FocusViewOptions
{
[JsonProperty("EnergyDisplay")]
public EnergyDisplay EnergyDisplay { get; set; }
[JsonProperty("KurzickPointsDisplay")]
public PointsDisplay KurzickPointsDisplay { get; set; }
[JsonProperty("LuxonPointsDisplay")]
public PointsDisplay LuxonPointsDisplay { get; set; }
[JsonProperty("BalthazarPointsDisplay")]
public PointsDisplay BalthazarPointsDisplay { get; set; }
[JsonProperty("ImperialPointsDisplay")]
public PointsDisplay ImperialPointsDisplay { get; set; }
[JsonProperty("BrowserUrl")]
public string? BrowserUrl { get; set; } = string.Empty;
}
@@ -3,5 +3,6 @@
public enum PointsDisplay
{
CurrentAndMax,
Remaining
Remaining,
Percentage
}
@@ -0,0 +1,12 @@
using Daybreak.Attributes;
namespace Daybreak.Configuration.Options;
[OptionsName(Name = "Ascalon Trade Chat")]
[OptionsIgnore]
public sealed class AscalonTradeChatOptions : ITradeChatOptions
{
public string HttpsUri { get; set; } = "https://ascalon.gwtoolbox.com/";
public string WssUri { get; set; } = "wss://ascalon.gwtoolbox.com/";
}
@@ -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,15 @@
using Daybreak.Attributes;
using Newtonsoft.Json;
namespace Daybreak.Configuration.Options;
[OptionsName(Name = "DSOAL")]
public sealed class DSOALOptions
{
[JsonProperty(nameof(Path))]
[OptionName(Name = "Path", Description = "The path to the DSOAL installation")]
public string? Path { get; set; }
[JsonProperty(nameof(Enabled))]
[OptionName(Name = "Enabled", Description = "If true, the launcher will also launch DSOAL when launching GuildWars")]
public bool Enabled { get; set; }
}
@@ -0,0 +1,57 @@
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 = 0, MaxValue = 1000)]
[OptionName(Name = "Memory Reader Frequency", Description = "Measured in ms. Sets how often should the launcher poll information from the game. Actual frequency is capped by the memory reading speed")]
public double MemoryReaderFrequency { get; set; } = 0;
[OptionName(Name = "Inventory Component Enabled", Description = "If true, the focus view will show a component with the inventory contents")]
public bool InventoryComponentVisible { get; set; }
[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,10 @@
namespace Daybreak.Configuration.Options;
public interface ILiteCollectionOptions<T> : ILiteCollectionOptions
{
}
public interface ILiteCollectionOptions
{
string CollectionName { get; }
}
@@ -0,0 +1,8 @@
namespace Daybreak.Configuration.Options;
public interface ITradeChatOptions
{
string HttpsUri { get; set; }
string WssUri { get; set; }
}
@@ -0,0 +1,12 @@
using Daybreak.Attributes;
namespace Daybreak.Configuration.Options;
[OptionsName(Name = "Kamadan Trade Chat")]
[OptionsIgnore]
public sealed class KamadanTradeChatOptions : ITradeChatOptions
{
public string HttpsUri { get; set; } = "https://kamadan.gwtoolbox.com/";
public string WssUri { get; set; } = "wss://kamadan.gwtoolbox.com/";
}
@@ -0,0 +1,53 @@
using Daybreak.Attributes;
using Daybreak.Models;
using Daybreak.Views;
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")]
[OptionSetterView<ScreenChoiceView>(Action = "Screen Selector")]
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 download icons that are not found in the local cache")]
public bool DownloadIcons { get; set; } = true;
}
@@ -0,0 +1,10 @@
using Daybreak.Attributes;
namespace Daybreak.Configuration.Options;
[OptionsName(Name = "Logging Options")]
[OptionsIgnore]
public sealed class LoggingOptions : ILiteCollectionOptions<Models.Log>
{
public string CollectionName => "logs";
}
@@ -0,0 +1,10 @@
using Daybreak.Attributes;
using Daybreak.Services.Notifications.Models;
namespace Daybreak.Configuration.Options;
[OptionsIgnore]
internal sealed class NotificationStorageOptions : ILiteCollectionOptions<NotificationDTO>
{
public string CollectionName => "notifications";
}
@@ -0,0 +1,16 @@
using Daybreak.Attributes;
using Newtonsoft.Json;
namespace Daybreak.Configuration.Options;
[OptionsName(Name = "Pathfinding")]
public sealed class PathfindingOptions
{
[JsonProperty(nameof(EnablePathfinding))]
[OptionName(Name = "Enable Pathfinding", Description = "If true, the pathfinder will attempt to produce paths from the player position to objectives")]
public bool EnablePathfinding { get; set; } = true;
[JsonProperty(nameof(ImprovedPathfinding))]
[OptionName(Name = "Distance-Based Pathfinding", Description = "If true, the pathfinder will attempt use an improved algorithm to find paths. Slower but generally more precise")]
public bool ImprovedPathfinding { get; set; } = true;
}
@@ -0,0 +1,19 @@
using Daybreak.Attributes;
using Daybreak.Services.TradeChat.Models;
using System;
using System.Collections.Generic;
namespace Daybreak.Configuration.Options;
[OptionsName(Name = "Price History")]
[OptionsIgnore]
public sealed class PriceHistoryOptions : ILiteCollectionOptions<TraderQuoteDTO>
{
public string HttpsUri { get; set; } = "https://kamadan.gwtoolbox.com/";
public string CollectionName => "price_history";
public TimeSpan UpdateInterval { get; set; } = TimeSpan.FromHours(1);
public Dictionary<string, DateTime> ItemHistoryMetadata { get; set; } = new();
}
@@ -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,10 @@
using Daybreak.Attributes;
namespace Daybreak.Configuration.Options;
[OptionsName(Name = "Sounds")]
public sealed class SoundOptions
{
[OptionName(Name = "Sounds Enabled", Description = "If enabled, the client will play sounds.")]
public bool Enabled { get; set; }
}
@@ -0,0 +1,14 @@
using Daybreak.Attributes;
using Daybreak.Models;
namespace Daybreak.Configuration.Options;
[OptionsName(Name = "Theme")]
public sealed class ThemeOptions
{
[OptionName(Name = "Dark Mode", Description = "If true, the client will switch to dark mode")]
public bool DarkMode { get; set; } = true;
[OptionName(Name = "Color Scheme", Description = "The client will apply the selected color scheme")]
public ColorScheme Theme { get; set; } = ColorScheme.Steel;
}
@@ -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,14 @@
using Daybreak.Attributes;
using Daybreak.Models.Trade;
using System;
using System.Collections.Generic;
namespace Daybreak.Configuration.Options;
[OptionsIgnore]
public sealed class TradeAlertingOptions
{
public TimeSpan MaxLookbackPeriod { get; set; } = TimeSpan.FromDays(31);
public DateTime LastCheckTime { get; set; } = DateTime.MinValue;
public List<TradeAlert> Alerts { get; set; } = new();
}
@@ -0,0 +1,10 @@
using Daybreak.Attributes;
using Daybreak.Services.TradeChat.Models;
namespace Daybreak.Configuration.Options;
[OptionsIgnore]
public sealed class TraderMessagesOptions : ILiteCollectionOptions<TraderMessageDTO>
{
public string CollectionName => "trader_messages";
}
@@ -0,0 +1,18 @@
using Daybreak.Attributes;
using System;
namespace Daybreak.Configuration.Options;
[OptionsName(Name = "Trader Quotes")]
public sealed class TraderQuotesOptions
{
[OptionIgnore]
public string HttpsUri { get; set; } = "https://kamadan.gwtoolbox.com/";
[OptionIgnore]
public DateTime LastCheckTime { get; set;} = DateTime.MinValue;
[OptionName(Name = "Cache Update Interval", Description = "The amount of minutes in between cache updates")]
[OptionRange<double>(MinValue = 30d, MaxValue = 1440d)]
public double CacheUpdateInterval { get; set; } = 60;
}
@@ -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; }
}
+272 -28
View File
@@ -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,7 +23,6 @@ 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;
@@ -32,38 +30,100 @@ 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;
using Daybreak.Services.Themes;
using Daybreak.Services.TradeChat;
using Daybreak.Views.Trade;
using System.Net.WebSockets;
using Daybreak.Utils;
using Daybreak.Services.Notifications;
using Microsoft.Extensions.Options;
using Daybreak.Services.TradeChat.Models;
using Daybreak.Services.Charts;
using Daybreak.Services.Images;
using Daybreak.Services.Drawing.Modules.Bosses;
using Daybreak.Services.InternetChecker;
using System;
using Daybreak.Services.Sounds;
using Daybreak.Services.Notifications.Models;
using Daybreak.Models.Notifications.Handling;
using Daybreak.Services.TradeChat.Notifications;
using Daybreak.Views.Copy;
using Daybreak.Services.DSOAL;
using Daybreak.Services.Mods;
using Daybreak.Views.Onboarding.DSOAL;
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.RegisterResolver(new ClientWebSocketResolver());
serviceManager
.RegisterHttpClient<ApplicationUpdater>()
.WithMessageHandler(sp =>
{
var logger = sp.GetService<ILogger<ApplicationUpdater>>();
return new LoggingHttpMessageHandler(logger!) { InnerHandler = new HttpClientHandler() };
})
.WithMessageHandler(SetupLoggingAndMetrics<ApplicationUpdater>)
.WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent)
.Build()
.RegisterHttpClient<BloogumClient>()
.WithMessageHandler(sp =>
{
var logger = sp.GetService<ILogger<BloogumClient>>();
return new LoggingHttpMessageHandler(logger!) { InnerHandler = new HttpClientHandler() };
})
.WithMessageHandler(SetupLoggingAndMetrics<BloogumClient>)
.WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent)
.Build()
.RegisterHttpClient<GraphClient>()
.WithMessageHandler(sp =>
{
var logger = sp.GetService<ILogger<GraphClient>>();
return new LoggingHttpMessageHandler(logger!) { InnerHandler = new HttpClientHandler() };
})
.WithMessageHandler(SetupLoggingAndMetrics<GraphClient>)
.WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent)
.Build()
.RegisterHttpClient<DownloadService>()
.WithMessageHandler(SetupLoggingAndMetrics<DownloadService>)
.WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent)
.Build()
.RegisterHttpClient<TradeChatService<KamadanTradeChatOptions>>()
.WithMessageHandler(SetupLoggingAndMetrics<TradeChatService<KamadanTradeChatOptions>>)
.WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent)
.Build()
.RegisterHttpClient<TradeChatService<AscalonTradeChatOptions>>()
.WithMessageHandler(SetupLoggingAndMetrics<TradeChatService<AscalonTradeChatOptions>>)
.WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent)
.Build()
.RegisterHttpClient<IconCache>()
.WithMessageHandler(SetupLoggingAndMetrics<IconCache>)
.WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent)
.Build()
.RegisterHttpClient<TraderQuoteService>()
.WithMessageHandler(SetupLoggingAndMetrics<TraderQuoteService>)
.WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent)
.Build()
.RegisterHttpClient<PriceHistoryService>()
.WithMessageHandler(SetupLoggingAndMetrics<PriceHistoryService>)
.WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent)
.Build()
.RegisterHttpClient<InternetCheckingService>()
.WithMessageHandler(SetupLoggingAndMetrics<InternetCheckingService>)
.WithDefaultRequestHeadersSetup(SetupDaybreakUserAgent)
.Build();
}
@@ -87,6 +147,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,13 +156,27 @@ public static class ProjectConfiguration
services.AddSingleton<IPostUpdateActionProducer>(sp => sp.GetRequiredService<PostUpdateActionManager>());
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<IMenuServiceInitializer, MenuService>(sp => sp.GetRequiredService<IMenuService>().As<MenuService>()!);
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.AddSingleton<IThemeManager, ThemeManager>();
services.AddSingleton<INotificationService, NotificationService>();
services.AddSingleton<INotificationProducer, NotificationService>(sp => sp.GetRequiredService<INotificationService>().As<NotificationService>()!);
services.AddSingleton<INotificationHandlerProducer, NotificationService>(sp => sp.GetRequiredService<INotificationService>().As<NotificationService>()!);
services.AddSingleton<ILiveChartInitializer, LiveChartInitializer>();
services.AddSingleton<IImageCache, ImageCache>();
services.AddSingleton<ISoundService, SoundService>();
services.AddSingleton<IInternetCheckingService, InternetCheckingService>();
services.AddSingleton<IConnectivityStatus, ConnectivityStatus>();
services.AddSingleton<INotificationStorage, NotificationStorage>();
services.AddSingleton<ITradeAlertingService, TradeAlertingService>();
services.AddSingleton<IModsManager, ModsManager>();
services.AddScoped<ICredentialManager, CredentialManager>();
services.AddScoped<IApplicationLauncher, ApplicationLauncher>();
services.AddScoped<IScreenshotProvider, ScreenshotProvider>();
@@ -115,19 +191,34 @@ public static class ProjectConfiguration
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<ITradeChatService<KamadanTradeChatOptions>, TradeChatService<KamadanTradeChatOptions>>();
services.AddScoped<ITradeChatService<AscalonTradeChatOptions>, TradeChatService<AscalonTradeChatOptions>>();
services.AddScoped<ITraderQuoteService, TraderQuoteService>();
services.AddScoped<IPriceHistoryDatabase, PriceHistoryDatabase>();
services.AddScoped<IPriceHistoryService, PriceHistoryService>();
services.AddScoped<IWordHighlightingService, WordHighlightingService>();
services.AddScoped<ITradeHistoryDatabase, TradeHistoryDatabase>();
services.AddScoped<IGuildwarsCopyService, GuildwarsCopyService>();
services.AddScoped<IItemHashService, ItemHashService>();
}
public static void RegisterViews(IViewProducer viewProducer)
{
viewProducer.ThrowIfNull();
viewProducer.RegisterPermanentView<LauncherView>();
viewProducer.RegisterPermanentView<Views.FocusView>();
viewProducer.RegisterView<SettingsView>();
viewProducer.RegisterView<LauncherView>();
viewProducer.RegisterView<AskUpdateView>();
viewProducer.RegisterView<UpdateView>();
viewProducer.RegisterView<AccountsView>();
viewProducer.RegisterView<ExperimentalSettingsView>();
viewProducer.RegisterView<ExecutablesView>();
viewProducer.RegisterView<BuildTemplateView>();
viewProducer.RegisterView<BuildsListView>();
@@ -135,16 +226,169 @@ public static class ProjectConfiguration
viewProducer.RegisterView<ScreenChoiceView>();
viewProducer.RegisterView<VersionManagementView>();
viewProducer.RegisterView<LogsView>();
viewProducer.RegisterView<IconDownloadView>();
viewProducer.RegisterView<GraphAuthorizationView>();
viewProducer.RegisterView<BuildsSynchronizationView>();
viewProducer.RegisterView<OnboardingView>();
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>();
viewProducer.RegisterView<KamadanTradeChatView>();
viewProducer.RegisterView<AscalonTradeChatView>();
viewProducer.RegisterView<PriceQuotesView>();
viewProducer.RegisterView<PriceHistoryView>();
viewProducer.RegisterView<NotificationsView>();
viewProducer.RegisterView<TradeAlertsView>();
viewProducer.RegisterView<TradeAlertSetupView>();
viewProducer.RegisterView<TradeNotificationView>();
viewProducer.RegisterView<GuildwarsCopySelectionView>();
viewProducer.RegisterView<GuildwarsCopyView>();
viewProducer.RegisterView<DSOALInstallingView>();
viewProducer.RegisterView<DSOALOnboardingEntryView>();
viewProducer.RegisterView<DSOALSwitchView>();
viewProducer.RegisterView<DSOALHomepageView>();
viewProducer.RegisterView<DSOALBrowserView>();
}
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<NeutralBossEntityDrawingModule>();
drawingModuleProducer.RegisterDrawingModule<WarriorBossEntityDrawingModule>();
drawingModuleProducer.RegisterDrawingModule<RangerBossEntityDrawingModule>();
drawingModuleProducer.RegisterDrawingModule<MesmerBossEntityDrawingModule>();
drawingModuleProducer.RegisterDrawingModule<NecromancerBossEntityDrawingModule>();
drawingModuleProducer.RegisterDrawingModule<MonkBossEntityDrawingModule>();
drawingModuleProducer.RegisterDrawingModule<ElementalistBossEntityDrawingModule>();
drawingModuleProducer.RegisterDrawingModule<AssassinBossEntityDrawingModule>();
drawingModuleProducer.RegisterDrawingModule<RitualistBossEntityDrawingModule>();
drawingModuleProducer.RegisterDrawingModule<DervishBossEntityDrawingModule>();
drawingModuleProducer.RegisterDrawingModule<ParagonBossEntityDrawingModule>();
drawingModuleProducer.RegisterDrawingModule<EnemyEntityDrawingModule>();
drawingModuleProducer.RegisterDrawingModule<NpcEntityDrawingModule>();
drawingModuleProducer.RegisterDrawingModule<UnknownEntityDrawingModule>();
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<FlagDrawingModule>();
drawingModuleProducer.RegisterDrawingModule<PersonDrawingModule>();
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<SoundOptions>();
optionsProducer.RegisterOptions<ThemeOptions>();
optionsProducer.RegisterOptions<BrowserOptions>();
optionsProducer.RegisterOptions<BuildSynchronizationOptions>();
optionsProducer.RegisterOptions<FocusViewOptions>();
optionsProducer.RegisterOptions<LauncherOptions>();
optionsProducer.RegisterOptions<ToolboxOptions>();
optionsProducer.RegisterOptions<UModOptions>();
optionsProducer.RegisterOptions<DSOALOptions>();
optionsProducer.RegisterOptions<ScreenManagerOptions>();
optionsProducer.RegisterOptions<KamadanTradeChatOptions>();
optionsProducer.RegisterOptions<AscalonTradeChatOptions>();
optionsProducer.RegisterOptions<LoggingOptions>();
optionsProducer.RegisterOptions<PriceHistoryOptions>();
optionsProducer.RegisterOptions<TraderQuotesOptions>();
optionsProducer.RegisterOptions<PathfindingOptions>();
optionsProducer.RegisterOptions<NotificationStorageOptions>();
optionsProducer.RegisterOptions<TradeAlertingOptions>();
optionsProducer.RegisterOptions<TraderMessagesOptions>();
}
public static void RegisterLiteCollections(IServiceCollection services)
{
RegisterLiteCollection<Models.Log, LoggingOptions>(services);
RegisterLiteCollection<TraderQuoteDTO, PriceHistoryOptions>(services);
RegisterLiteCollection<NotificationDTO, NotificationStorageOptions>(services);
RegisterLiteCollection<TraderMessageDTO, TraderMessagesOptions>(services);
}
public static void RegisterNotificationHandlers(INotificationHandlerProducer notificationHandlerProducer)
{
notificationHandlerProducer.RegisterNotificationHandler<NoActionHandler>();
notificationHandlerProducer.RegisterNotificationHandler<MessageBoxHandler>();
notificationHandlerProducer.RegisterNotificationHandler<TradeMessageNotificationHandler>();
}
public static void RegisterMods(IModsManager modsManager)
{
modsManager.RegisterMod<IToolboxService, ToolboxService>();
modsManager.RegisterMod<IUModService, UModService>();
modsManager.RegisterMod<IDSOALService, DSOALService>();
}
private static void RegisterLiteCollection<TCollectionType, TOptionsType>(IServiceCollection services)
where TOptionsType : class, ILiteCollectionOptions<TCollectionType>
{
services.AddSingleton(sp =>
{
var options = sp.GetRequiredService<IOptions<TOptionsType>>();
var liteDatabase = sp.GetRequiredService<ILiteDatabase>();
return liteDatabase.GetCollection<TCollectionType>(options.Value.CollectionName, BsonAutoId.Int64);
});
}
private static void SetupDaybreakUserAgent(HttpRequestHeaders httpRequestHeaders)
{
httpRequestHeaders.ThrowIfNull().TryAddWithoutValidation("User-Agent", DaybreakUserAgent);
}
private static HttpMessageHandler SetupLoggingAndMetrics<T>(System.IServiceProvider serviceProvider)
{
var logger = serviceProvider.GetRequiredService<ILogger<T>>();
var metricsService = serviceProvider.GetRequiredService<IMetricsService>();
return new MetricsHttpMessageHandler<T>(
metricsService,
new LoggingHttpMessageHandler(logger!) { InnerHandler = new HttpClientHandler() });
}
}
+45
View File
@@ -0,0 +1,45 @@
<UserControl x:Class="Daybreak.Controls.BagItemContextMenu"
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"
Background="{StaticResource Daybreak.Brushes.Background}"
d:DataContext="{d:DesignInstance Type=guildwars:BagItem, IsDesignTimeCreatable=True}"
BorderBrush="{StaticResource MahApps.Brushes.ThemeForeground}"
BorderThickness="1"
x:Name="_this"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<StackPanel Margin="5, 0, 5, 0">
<TextBlock
Text="{Binding Item.Name, Mode=OneWay}"
FontSize="16"
Foreground="{StaticResource MahApps.Brushes.ThemeForeground}" />
<WrapPanel>
<TextBlock
Text="Wiki: "
FontSize="16"
Foreground="{StaticResource MahApps.Brushes.ThemeForeground}" />
<TextBlock
Text="{Binding Item.WikiUrl, Mode=OneWay}"
FontSize="16"
Foreground="{StaticResource MahApps.Brushes.Accent}"
Cursor="Hand"
MouseLeftButtonDown="WikiTextBlock_MouseLeftButtonDown"/>
</WrapPanel>
<WrapPanel>
<TextBlock
Text="Price history: "
FontSize="16"
Foreground="{StaticResource MahApps.Brushes.ThemeForeground}" />
<TextBlock
Text="Check"
FontSize="16"
Foreground="{StaticResource MahApps.Brushes.Accent}"
Cursor="Hand"
MouseLeftButtonDown="PriceHistoryTextBlock_MouseLeftButtonDown"/>
</WrapPanel>
</StackPanel>
</UserControl>
@@ -0,0 +1,41 @@
using Daybreak.Models.Guildwars;
using System;
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for BagItemContextMenu.xaml
/// </summary>
public partial class BagItemContextMenu : UserControl
{
public event EventHandler<ItemBase>? PriceHistoryClicked;
public event EventHandler<ItemBase>? WikiClicked;
public BagItemContextMenu()
{
this.InitializeComponent();
}
private void WikiTextBlock_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (this.DataContext is not BagItem bagItem ||
bagItem.Item is not ItemBase itemBase)
{
return;
}
this.WikiClicked?.Invoke(this, itemBase);
}
private void PriceHistoryTextBlock_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (this.DataContext is not BagItem bagItem ||
bagItem.Item is not ItemBase itemBase)
{
return;
}
this.PriceHistoryClicked?.Invoke(this, itemBase);
}
}
+19 -14
View File
@@ -1,22 +1,27 @@
<UserControl x:Class="Daybreak.Controls.AddButton"
<UserControl x:Class="Daybreak.Controls.Buttons.AddButton"
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:local="clr-namespace:Daybreak.Controls.Buttons"
mc:Ignorable="d"
x:Name="_this"
Cursor="Hand"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
<Ellipse x:Name="BackgroundEllipse" Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Visibility="Visible" Opacity="0.1" />
<Path Data="m13,26a13,13 0 1 1 13,-13a13,13 0 0 1 -13,13zm0,-24a11,11 0 1 0 11,11a11,11 0 0 0 -11,-11z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Path>
<Path Data="m13,20a1,1 0 0 1 -1,-1l0,-12a1,1 0 0 1 2,0l0,12a1,1 0 0 1 -1,1z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Path>
<Path Data="m19,14l-12,0a1,1 0 0 1 0,-2l12,0a1,1 0 0 1 0,2z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Path>
<Ellipse Fill="Transparent" MouseEnter="Ellipse_MouseEnter" MouseLeave="Ellipse_MouseLeave" MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"></Ellipse>
</Grid>
</Viewbox>
<Grid>
<local:CircularButton Foreground="{StaticResource MahApps.Brushes.ThemeForeground}"
Highlight="{StaticResource MahApps.Brushes.Accent}"
Clicked="HighlightButton_Clicked">
<local:CircularButton.Content>
<Viewbox Stretch="Fill" Width="60" Height="60">
<Grid Width="25" Height="25">
<Path Data="m13,20a1,1 0 0 1 -1,-1l0,-12a1,1 0 0 1 2,0l0,12a1,1 0 0 1 -1,1z"
Fill="{StaticResource MahApps.Brushes.ThemeForeground}"></Path>
<Path Data="m19,14l-12,0a1,1 0 0 1 0,-2l12,0a1,1 0 0 1 0,2z"
Fill="{StaticResource MahApps.Brushes.ThemeForeground}"></Path>
</Grid>
</Viewbox>
</local:CircularButton.Content>
</local:CircularButton>
</Grid>
</UserControl>
+3 -17
View File
@@ -1,8 +1,7 @@
using System;
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls;
namespace Daybreak.Controls.Buttons;
/// <summary>
/// Interaction logic for AddButton.xaml
@@ -16,21 +15,8 @@ public partial class AddButton : UserControl
this.InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
private void HighlightButton_Clicked(object sender, EventArgs e)
{
this.BackgroundEllipse.Opacity = 0.6;
}
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
Clicked?.Invoke(this, e);
}
this.Clicked?.Invoke(this, e);
}
}
+17 -12
View File
@@ -1,20 +1,25 @@
<UserControl x:Class="Daybreak.Controls.BackButton"
<UserControl x:Class="Daybreak.Controls.Buttons.BackButton"
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:local="clr-namespace:Daybreak.Controls.Buttons"
mc:Ignorable="d"
x:Name="_this"
Cursor="Hand"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
<Ellipse x:Name="BackgroundEllipse" Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Visibility="Visible" Opacity="0.1" />
<Path Fill="{Binding Foreground, ElementName=_this, Mode=OneWay}"
Data="m30,15a15,15 0 1 1 -15,-15a15,15 0 0 1 15,15zm-28,0a13,13 0 1 0 13,-13a13,13 0 0 0 -13,13z"></Path>
<Path Fill="{Binding Foreground, ElementName=_this, Mode=OneWay}"
Data="m18.87,9.41l-5.58,5.59l5.58,5.59a1,1 0 0 1 0,1.41l0,0a1,1 0 0 1 -1.41,0l-6.36,-6.36a0.91,0.91 0 0 1 0,-1.28l6.36,-6.36a1,1 0 0 1 1.41,0l0,0a1,1 0 0 1 0,1.41z"></Path>
<Ellipse Fill="Transparent" MouseEnter="Ellipse_MouseEnter" MouseLeave="Ellipse_MouseLeave" MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"></Ellipse>
</Grid>
</Viewbox>
<Grid>
<local:CircularButton Foreground="{DynamicResource MahApps.Brushes.ThemeForeground}"
Highlight="{DynamicResource MahApps.Brushes.Accent}"
Clicked="HighlightButton_Clicked">
<local:CircularButton.Content>
<Viewbox Stretch="Fill" Width="60" Height="60">
<Grid Width="30" Height="30" Margin="-2, 0, 0 ,0">
<Path Fill="{DynamicResource MahApps.Brushes.ThemeForeground}" VerticalAlignment="Top" HorizontalAlignment="Left"
Data="m18.87,9.41l-5.58,5.59l5.58,5.59a1,1 0 0 1 0,1.41l0,0a1,1 0 0 1 -1.41,0l-6.36,-6.36a0.91,0.91 0 0 1 0,-1.28l6.36,-6.36a1,1 0 0 1 1.41,0l0,0a1,1 0 0 1 0,1.41z"></Path>
</Grid>
</Viewbox>
</local:CircularButton.Content>
</local:CircularButton>
</Grid>
</UserControl>
+3 -17
View File
@@ -1,8 +1,7 @@
using System;
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls;
namespace Daybreak.Controls.Buttons;
/// <summary>
/// Interaction logic for BackButton.xaml
@@ -16,21 +15,8 @@ public partial class BackButton : UserControl
this.InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
private void HighlightButton_Clicked(object sender, EventArgs e)
{
this.BackgroundEllipse.Opacity = 0.6;
}
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
Clicked?.Invoke(this, e);
}
this.Clicked?.Invoke(this, e);
}
}
+27 -22
View File
@@ -1,30 +1,35 @@
<UserControl x:Class="Daybreak.Controls.BinButton"
<UserControl x:Class="Daybreak.Controls.Buttons.BinButton"
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:local="clr-namespace:Daybreak.Controls.Buttons"
mc:Ignorable="d"
x:Name="_this"
Cursor="Hand"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
<Ellipse x:Name="BackgroundEllipse" Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Width="80" Height="80" Opacity="0.6"
Visibility="Hidden"></Ellipse>
<Path Data="m40,7l-2,0l0,-5l-18,0l0,5l-2,0l0,-6a1,1 0 0 1 1,-1l20,0a1,1 0 0 1 1,1l0,6z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Margin="11"></Path>
<Path Data="m58,14l-2,0l0,-3l-54,0l0,3l-2,0l0,-4a1,1 0 0 1 1,-1l56,0a1,1 0 0 1 1,1l0,4z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Margin="11"></Path>
<Path Data="m51,64l-44,0a1,1 0 0 1 -1,-1l0,-48l2,0l0,47l42,0l0,-47l2,0l0,48a1,1 0 0 1 -1,1z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Margin="11"></Path>
<Rectangle Margin="38, 32, 0, 0" Width="2" Height="32" Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
VerticalAlignment="Top" HorizontalAlignment="Left"></Rectangle>
<Rectangle Margin="26, 35, 0, 0" Width="2" Height="32" Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
VerticalAlignment="Top" HorizontalAlignment="Left"></Rectangle>
<Rectangle Margin="50, 35, 0, 0" Width="2" Height="32" Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
VerticalAlignment="Top" HorizontalAlignment="Left"></Rectangle>
<Ellipse Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" StrokeThickness="3" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Fill="Transparent"
MouseLeftButtonDown="Ellipse_MouseLeftButtonDown" MouseEnter="Ellipse_MouseEnter" MouseLeave="Ellipse_MouseLeave"></Ellipse>
</Grid>
</Viewbox>
<Grid>
<local:CircularButton Foreground="{StaticResource MahApps.Brushes.ThemeForeground}"
Highlight="{StaticResource MahApps.Brushes.Accent}"
Clicked="HighlightButton_Clicked">
<local:CircularButton.Content>
<Viewbox Width="60" Height="60">
<Grid Margin="10">
<Path Data="m40,7l-2,0l0,-5l-18,0l0,5l-2,0l0,-6a1,1 0 0 1 1,-1l20,0a1,1 0 0 1 1,1l0,6z"
Fill="{StaticResource MahApps.Brushes.ThemeForeground}" Margin="11"></Path>
<Path Data="m58,14l-2,0l0,-3l-54,0l0,3l-2,0l0,-4a1,1 0 0 1 1,-1l56,0a1,1 0 0 1 1,1l0,4z"
Fill="{StaticResource MahApps.Brushes.ThemeForeground}" Margin="11"></Path>
<Path Data="m51,64l-44,0a1,1 0 0 1 -1,-1l0,-48l2,0l0,47l42,0l0,-47l2,0l0,48a1,1 0 0 1 -1,1z"
Fill="{StaticResource MahApps.Brushes.ThemeForeground}" Margin="11"></Path>
<Rectangle Margin="38, 32, 0, 0" Width="2" Height="32" Stroke="{StaticResource MahApps.Brushes.ThemeForeground}"
VerticalAlignment="Top" HorizontalAlignment="Left"></Rectangle>
<Rectangle Margin="26, 35, 0, 0" Width="2" Height="32" Stroke="{StaticResource MahApps.Brushes.ThemeForeground}"
VerticalAlignment="Top" HorizontalAlignment="Left"></Rectangle>
<Rectangle Margin="50, 35, 0, 0" Width="2" Height="32" Stroke="{StaticResource MahApps.Brushes.ThemeForeground}"
VerticalAlignment="Top" HorizontalAlignment="Left"></Rectangle>
</Grid>
</Viewbox>
</local:CircularButton.Content>
</local:CircularButton>
</Grid>
</UserControl>
+4 -17
View File
@@ -1,8 +1,7 @@
using System;
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls;
namespace Daybreak.Controls.Buttons;
/// <summary>
/// Interaction logic for BinButton.xaml
@@ -10,26 +9,14 @@ namespace Daybreak.Controls;
public partial class BinButton : UserControl
{
public event EventHandler? Clicked;
public BinButton()
{
this.InitializeComponent();
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
private void HighlightButton_Clicked(object sender, EventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
this.Clicked?.Invoke(this, e);
}
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Visibility = System.Windows.Visibility.Visible;
}
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Visibility = System.Windows.Visibility.Hidden;
this.Clicked?.Invoke(this, e);
}
}
+17 -11
View File
@@ -1,19 +1,25 @@
<UserControl x:Class="Daybreak.Controls.CancelButton"
<UserControl x:Class="Daybreak.Controls.Buttons.CancelButton"
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:local="clr-namespace:Daybreak.Controls.Buttons"
mc:Ignorable="d"
x:Name="_this"
Cursor="Hand"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
<Ellipse x:Name="BackgroundEllipse" Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Visibility="Visible" Opacity="0.1" />
<Ellipse StrokeThickness="2" Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Width="30" Height="30"></Ellipse>
<Line X1="7" X2="23" Y1="7" Y2="23" StrokeThickness="2" Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Line>
<Line X1="23" X2="7" Y1="7" Y2="23" StrokeThickness="2" Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Line>
<Ellipse Fill="Transparent" MouseEnter="Ellipse_MouseEnter" MouseLeave="Ellipse_MouseLeave" MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"></Ellipse>
</Grid>
</Viewbox>
<Grid>
<local:CircularButton Foreground="{StaticResource MahApps.Brushes.ThemeForeground}"
Highlight="{StaticResource MahApps.Brushes.Accent}"
Clicked="HighlightButton_Clicked">
<local:CircularButton.Content>
<Viewbox Width="60" Height="60">
<Grid Width="30" Height="30">
<Line X1="7" X2="23" Y1="7" Y2="23" StrokeThickness="2" Stroke="{StaticResource MahApps.Brushes.ThemeForeground}"></Line>
<Line X1="23" X2="7" Y1="7" Y2="23" StrokeThickness="2" Stroke="{StaticResource MahApps.Brushes.ThemeForeground}"></Line>
</Grid>
</Viewbox>
</local:CircularButton.Content>
</local:CircularButton>
</Grid>
</UserControl>
+3 -17
View File
@@ -1,8 +1,7 @@
using System;
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls;
namespace Daybreak.Controls.Buttons;
/// <summary>
/// Interaction logic for BackButton.xaml
@@ -16,21 +15,8 @@ public partial class CancelButton : UserControl
this.InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
private void HighlightButton_Clicked(object sender, EventArgs e)
{
this.BackgroundEllipse.Opacity = 0.6;
}
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
Clicked?.Invoke(this, e);
}
this.Clicked?.Invoke(this, e);
}
}
@@ -0,0 +1,24 @@
<UserControl x:Class="Daybreak.Controls.Buttons.CircularButton"
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.Buttons"
x:Name="_this"
Cursor="Hand"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"></BooleanToVisibilityConverter>
</UserControl.Resources>
<Viewbox>
<Grid>
<Ellipse Fill="{Binding ElementName=_this, Path=Highlight, Mode=OneWay}"
Visibility="{Binding ElementName=_this, Path=IsHighlighted, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}" Opacity="0.6" />
<Ellipse Stroke="{DynamicResource MahApps.Brushes.ThemeForeground}" StrokeThickness="3"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"></Ellipse>
<ContentPresenter Content="{Binding ElementName=_this, Path=Content, Mode=OneWay}"></ContentPresenter>
<Ellipse Fill="Transparent" MouseEnter="Ellipse_MouseEnter" MouseLeave="Ellipse_MouseLeave" MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"></Ellipse>
</Grid>
</Viewbox>
</UserControl>
@@ -0,0 +1,43 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
using System.Windows.Media;
namespace Daybreak.Controls.Buttons;
/// <summary>
/// Interaction logic for HighlightButton.xaml
/// </summary>
public partial class CircularButton : UserControl
{
public event EventHandler Clicked;
[GenerateDependencyProperty]
private Brush highlight = default!;
[GenerateDependencyProperty]
private bool isHighlighted;
[GenerateDependencyProperty]
private FrameworkElement content = default!;
public CircularButton()
{
this.InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
this.IsHighlighted = true;
}
private void Ellipse_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
this.IsHighlighted = false;
}
private void Ellipse_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
this.Clicked?.Invoke(this, e);
}
}
+26
View File
@@ -0,0 +1,26 @@
<UserControl x:Class="Daybreak.Controls.Buttons.CopyButton"
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.Buttons"
xmlns:controls="clr-namespace:Daybreak.Controls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<local:CircularButton Foreground="{StaticResource MahApps.Brushes.ThemeForeground}"
Highlight="{StaticResource MahApps.Brushes.Accent}"
Clicked="HighlightButton_Clicked">
<local:CircularButton.Content>
<Viewbox Stretch="Fill" Width="60" Height="60">
<Grid Width="80" Height="80">
<Path Data="m28,0l-24,0c-2.21,0 -4,1.79 -4,4l0,28l4,0l0,-28l24,0l0,-4zm6,8l-22,0c-2.21,0 -4,1.79 -4,4l0,28c0,2.21 1.79,4 4,4l22,0c2.21,0 4,-1.79 4,-4l0,-28c0,-2.21 -1.79,-4 -4,-4zm0,32l-22,0l0,-28l22,0l0,28z"
Fill="{StaticResource MahApps.Brushes.ThemeForeground}"
VerticalAlignment="Center"
HorizontalAlignment="Center"/>
</Grid>
</Viewbox>
</local:CircularButton.Content>
</local:CircularButton>
</Grid>
</UserControl>
@@ -0,0 +1,21 @@
using System;
using System.Windows.Controls;
namespace Daybreak.Controls.Buttons;
/// <summary>
/// Interaction logic for CopyButton.xaml
/// </summary>
public partial class CopyButton : UserControl
{
public event EventHandler? Clicked;
public CopyButton()
{
this.InitializeComponent();
}
private void HighlightButton_Clicked(object sender, EventArgs e)
{
this.Clicked?.Invoke(this, e);
}
}
@@ -0,0 +1,25 @@
<UserControl x:Class="Daybreak.Controls.Buttons.FilePickerButton"
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.Buttons"
xmlns:glyphs="clr-namespace:Daybreak.Controls.Glyphs"
mc:Ignorable="d"
x:Name="_this"
Cursor="Hand"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<local:CircularButton Foreground="{StaticResource MahApps.Brushes.ThemeForeground}"
Highlight="{StaticResource MahApps.Brushes.Accent}"
Clicked="HighlightButton_Clicked">
<local:CircularButton.Content>
<Viewbox Width="60" Height="60">
<Grid>
<glyphs:ThreeDotsGlyph Foreground="{StaticResource MahApps.Brushes.ThemeForeground}" Padding="0.5"></glyphs:ThreeDotsGlyph>
</Grid>
</Viewbox>
</local:CircularButton.Content>
</local:CircularButton>
</Grid>
</UserControl>
@@ -0,0 +1,22 @@
using System;
using System.Windows.Controls;
namespace Daybreak.Controls.Buttons;
/// <summary>
/// Interaction logic for FilePickerGlyph.xaml
/// </summary>
public partial class FilePickerButton : UserControl
{
public event EventHandler? Clicked;
public FilePickerButton()
{
this.InitializeComponent();
}
private void HighlightButton_Clicked(object sender, EventArgs e)
{
this.Clicked?.Invoke(this, e);
}
}
@@ -1,20 +0,0 @@
<UserControl x:Class="Daybreak.Controls.FilePickerGlyph"
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>
<Ellipse x:Name="BackgroundEllipse" Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Visibility="Visible" Opacity="0.1" />
<Viewbox Stretch="Fill">
<Grid>
<Ellipse Height="4" Width="4" StrokeThickness="0.2" Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Ellipse>
<local:ThreeDotsGlyph Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Padding="0.5"></local:ThreeDotsGlyph>
</Grid>
</Viewbox>
<Ellipse Fill="Transparent" MouseEnter="Ellipse_MouseEnter" MouseLeave="Ellipse_MouseLeave" MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"></Ellipse>
</Grid>
</UserControl>
@@ -1,36 +0,0 @@
using System;
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for FilePickerGlyph.xaml
/// </summary>
public partial class FilePickerGlyph : UserControl
{
public event EventHandler? Clicked;
public FilePickerGlyph()
{
this.InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0.6;
}
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
this.Clicked?.Invoke(this, e);
}
}
}
+17 -11
View File
@@ -1,19 +1,25 @@
<UserControl x:Class="Daybreak.Controls.HelpButton"
<UserControl x:Class="Daybreak.Controls.Buttons.HelpButton"
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:local="clr-namespace:Daybreak.Controls.Buttons"
mc:Ignorable="d"
x:Name="_this"
Cursor="Hand"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
<Ellipse x:Name="BackgroundEllipse" Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Visibility="Visible" Opacity="0.1" Width="30" Height="30" />
<Ellipse Width="30" Height="30" StrokeThickness="2" Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Ellipse>
<Path Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" VerticalAlignment="Center" HorizontalAlignment="Center"
Data="m4.99353,17.899l0,-1.47c0,-1.436 0.322,-2.188 1.075,-3.229l2.404,-3.3c1.254,-1.721 1.684,-2.546 1.684,-3.766c0,-2.044 -1.434,-3.335 -3.479,-3.335c-2.008,0 -3.299,1.219 -3.729,3.407c-0.036,0.215 -0.179,0.323 -0.395,0.287l-2.259,-0.395c-0.216,-0.036 -0.323,-0.179 -0.288,-0.395c0.539,-3.443 3.014,-5.703 6.744,-5.703c3.872,0 6.49,2.546 6.49,6.097c0,1.722 -0.608,2.977 -1.828,4.663l-2.403,3.3c-0.717,0.968 -0.933,1.47 -0.933,2.689l0,1.147c0,0.215 -0.143,0.358 -0.358,0.358l-2.367,0c-0.215,0.004 -0.358,-0.14 -0.358,-0.355zm-0.179,3.444c0,-0.215 0.143,-0.358 0.359,-0.358l2.726,0c0.215,0 0.358,0.144 0.358,0.358l0,3.084c0,0.216 -0.144,0.358 -0.358,0.358l-2.726,0c-0.217,0 -0.359,-0.143 -0.359,-0.358l0,-3.084z"></Path>
<Ellipse Fill="Transparent" MouseEnter="Ellipse_MouseEnter" MouseLeave="Ellipse_MouseLeave" MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"></Ellipse>
</Grid>
</Viewbox>
<Grid>
<local:CircularButton Foreground="{StaticResource MahApps.Brushes.ThemeForeground}"
Highlight="{StaticResource MahApps.Brushes.Accent}"
Clicked="HighlightButton_Clicked">
<local:CircularButton.Content>
<Viewbox Width="60" Height="60">
<Grid Width="30" Height="35">
<Path Fill="{StaticResource MahApps.Brushes.ThemeForeground}" VerticalAlignment="Center" HorizontalAlignment="Center"
Data="m4.99353,17.899l0,-1.47c0,-1.436 0.322,-2.188 1.075,-3.229l2.404,-3.3c1.254,-1.721 1.684,-2.546 1.684,-3.766c0,-2.044 -1.434,-3.335 -3.479,-3.335c-2.008,0 -3.299,1.219 -3.729,3.407c-0.036,0.215 -0.179,0.323 -0.395,0.287l-2.259,-0.395c-0.216,-0.036 -0.323,-0.179 -0.288,-0.395c0.539,-3.443 3.014,-5.703 6.744,-5.703c3.872,0 6.49,2.546 6.49,6.097c0,1.722 -0.608,2.977 -1.828,4.663l-2.403,3.3c-0.717,0.968 -0.933,1.47 -0.933,2.689l0,1.147c0,0.215 -0.143,0.358 -0.358,0.358l-2.367,0c-0.215,0.004 -0.358,-0.14 -0.358,-0.355zm-0.179,3.444c0,-0.215 0.143,-0.358 0.359,-0.358l2.726,0c0.215,0 0.358,0.144 0.358,0.358l0,3.084c0,0.216 -0.144,0.358 -0.358,0.358l-2.726,0c-0.217,0 -0.359,-0.143 -0.359,-0.358l0,-3.084z"></Path>
</Grid>
</Viewbox>
</local:CircularButton.Content>
</local:CircularButton>
</Grid>
</UserControl>
+3 -17
View File
@@ -1,8 +1,7 @@
using System;
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls;
namespace Daybreak.Controls.Buttons;
/// <summary>
/// Interaction logic for AddButton.xaml
@@ -16,21 +15,8 @@ public partial class HelpButton : UserControl
this.InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
private void HighlightButton_Clicked(object sender, EventArgs e)
{
this.BackgroundEllipse.Opacity = 0.6;
}
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
this.Clicked?.Invoke(this, e);
}
this.Clicked?.Invoke(this, e);
}
}
@@ -0,0 +1,36 @@
<UserControl x:Class="Daybreak.Controls.Buttons.HighlightButton"
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.Buttons"
xmlns:converters="clr-namespace:Daybreak.Converters"
x:Name="_this"
Cursor="Hand"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<converters:MenuButtonHighlightConverter x:Key="HighlightConverter"></converters:MenuButtonHighlightConverter>
</UserControl.Resources>
<Grid>
<Rectangle
Fill="{Binding ElementName=_this, Path=HighlightColor, Mode=OneWay}"
Opacity="{Binding ElementName=_this, Path=Highlighted, Converter={StaticResource HighlightConverter}}">
</Rectangle>
<TextBlock Text="{Binding ElementName=_this, Path=Title, Mode=OneWay}"
FontSize="{Binding ElementName=_this, Path=FontSize, Mode=OneWay}"
FontFamily="{Binding ElementName=_this, Path=FontFamily, Mode=OneWay}"
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
VerticalAlignment="{Binding ElementName=_this, Path=VerticalContentAlignment, Mode=OneWay}"
HorizontalAlignment="{Binding ElementName=_this, Path=HorizontalContentAlignment, Mode=OneWay}"
TextWrapping="{Binding ElementName=_this, Path=TextWrapping, Mode=OneWay}"
TextAlignment="{Binding ElementName=_this, Path=TextAlignment, Mode=OneWay}"
Padding="{Binding ElementName=_this, Path=TextPadding, Mode=OneWay}"/>
<ContentPresenter
Content="{Binding ElementName=_this, Path=ButtonContent, Mode=OneWay}"/>
<Rectangle Fill="Transparent"
MouseEnter="Grid_MouseEnter"
MouseLeave="Grid_MouseLeave"
MouseLeftButtonDown="Rectangle_MouseLeftButtonDown" />
</Grid>
</UserControl>
@@ -0,0 +1,54 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
using System.Windows.Input;
using System.Windows.Media;
namespace Daybreak.Controls.Buttons;
/// <summary>
/// Interaction logic for HighlightButton.xaml
/// </summary>
public partial class HighlightButton : UserControl
{
public event EventHandler? Clicked;
[GenerateDependencyProperty]
private bool highlighted;
[GenerateDependencyProperty]
private Brush highlightColor = default!;
[GenerateDependencyProperty(InitialValue = "")]
private string title = string.Empty;
[GenerateDependencyProperty(InitialValue = HorizontalAlignment.Left)]
private HorizontalAlignment horizontalContentAlignment = HorizontalAlignment.Left;
[GenerateDependencyProperty(InitialValue = VerticalAlignment.Top)]
private VerticalAlignment verticalContentAlignment = VerticalAlignment.Top;
[GenerateDependencyProperty(InitialValue = TextAlignment.Center)]
private TextAlignment textAlignment = TextAlignment.Center;
[GenerateDependencyProperty(InitialValue = TextWrapping.Wrap)]
private TextWrapping textWrapping = TextWrapping.Wrap;
[GenerateDependencyProperty]
private Thickness textPadding = new Thickness(0);
[GenerateDependencyProperty]
private UIElement buttonContent = default!;
public HighlightButton()
{
this.InitializeComponent();
}
private void Grid_MouseEnter(object sender, MouseEventArgs e)
{
this.Highlighted = true;
}
private void Grid_MouseLeave(object sender, MouseEventArgs e)
{
this.Highlighted = false;
}
private void Rectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.Clicked?.Invoke(this, e);
}
}
+22 -18
View File
@@ -1,25 +1,29 @@
<UserControl x:Class="Daybreak.Controls.HomeButton"
<UserControl x:Class="Daybreak.Controls.Buttons.HomeButton"
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"
xmlns:local="clr-namespace:Daybreak.Controls.Buttons"
mc:Ignorable="d"
x:Name="_this"
Cursor="Hand"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
<Ellipse x:Name="BackgroundEllipse" Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Visibility="Visible" Opacity="0.1" />
<Ellipse Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" StrokeThickness="3" Width="60" Height="60"></Ellipse>
<Grid VerticalAlignment="Center" HorizontalAlignment="Center">
<Path Data="m42,45.384l-14,0l0,-13l-8,0l0,13l-14,0l0,-21c0,-0.552 0.447,-1 1,-1s1,0.448 1,1l0,19l10,0l0,-13l12,0l0,13l10,0l0,-18c0,-0.552 0.447,-1 1,-1s1,0.448 1,1l0,20z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Path>
<Path Data="m47,24.384c-0.249,0 -0.497,-0.092 -0.691,-0.277l-22.309,-21.339l-22.309,21.339c-0.399,0.381 -1.032,0.368 -1.414,-0.031c-0.382,-0.399 -0.367,-1.032 0.031,-1.414l23.692,-22.662l23.691,22.661c0.398,0.382 0.413,1.015 0.031,1.414c-0.196,0.205 -0.458,0.309 -0.722,0.309z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Path>
<Path Data="m39,12.384c-0.553,0 -1,-0.448 -1,-1l0,-6l-6,0c-0.553,0 -1,-0.448 -1,-1s0.447,-1 1,-1l8,0l0,8c0,0.552 -0.447,1 -1,1z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Path>
</Grid>
<Ellipse Fill="Transparent" MouseEnter="Ellipse_MouseEnter" MouseLeave="Ellipse_MouseLeave" MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"></Ellipse>
</Grid>
</Viewbox>
<Grid>
<local:CircularButton Foreground="{DynamicResource MahApps.Brushes.ThemeForeground}"
Highlight="{DynamicResource MahApps.Brushes.Accent}"
Clicked="HighlightButton_Clicked">
<local:CircularButton.Content>
<Viewbox Stretch="Fill">
<Grid>
<Path Data="m42,45.384l-14,0l0,-13l-8,0l0,13l-14,0l0,-21c0,-0.552 0.447,-1 1,-1s1,0.448 1,1l0,19l10,0l0,-13l12,0l0,13l10,0l0,-18c0,-0.552 0.447,-1 1,-1s1,0.448 1,1l0,20z"
Fill="{DynamicResource MahApps.Brushes.ThemeForeground}"></Path>
<Path Data="m47,24.384c-0.249,0 -0.497,-0.092 -0.691,-0.277l-22.309,-21.339l-22.309,21.339c-0.399,0.381 -1.032,0.368 -1.414,-0.031c-0.382,-0.399 -0.367,-1.032 0.031,-1.414l23.692,-22.662l23.691,22.661c0.398,0.382 0.413,1.015 0.031,1.414c-0.196,0.205 -0.458,0.309 -0.722,0.309z"
Fill="{DynamicResource MahApps.Brushes.ThemeForeground}"></Path>
<Path Data="m39,12.384c-0.553,0 -1,-0.448 -1,-1l0,-6l-6,0c-0.553,0 -1,-0.448 -1,-1s0.447,-1 1,-1l8,0l0,8c0,0.552 -0.447,1 -1,1z"
Fill="{DynamicResource MahApps.Brushes.ThemeForeground}"></Path>
</Grid>
</Viewbox>
</local:CircularButton.Content>
</local:CircularButton>
</Grid>
</UserControl>
+3 -17
View File
@@ -1,8 +1,7 @@
using System;
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls;
namespace Daybreak.Controls.Buttons;
/// <summary>
/// Interaction logic for HomeButton.xaml
@@ -16,21 +15,8 @@ public partial class HomeButton : UserControl
this.InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
private void HighlightButton_Clicked(object sender, EventArgs e)
{
this.BackgroundEllipse.Opacity = 0.6;
}
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
Clicked?.Invoke(this, e);
}
this.Clicked?.Invoke(this, e);
}
}
+21 -29
View File
@@ -1,39 +1,31 @@
<UserControl x:Class="Daybreak.Controls.MaximizeButton"
<UserControl x:Class="Daybreak.Controls.Buttons.MaximizeButton"
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:local="clr-namespace:Daybreak.Controls.Buttons"
x:Name="_this"
Cursor="Hand"
mc:Ignorable="d"
d:DesignHeight="50" d:DesignWidth="50">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.3*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="0.3*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="0.3*" />
<RowDefinition Height="1*" />
<RowDefinition Height="0.3*" />
</Grid.RowDefinitions>
<Ellipse x:Name="BackgroundEllipse" Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Opacity="0.6" Visibility="Hidden" Grid.RowSpan="3" Grid.ColumnSpan="3"></Ellipse>
<Viewbox Grid.Row="1" Grid.Column="1">
<Grid>
<Path Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Data="m30,0l-24,0a5.9966,5.9966 0 0 0 -6,6l0,24a6,6 0 0 0 12,0l0,-18l18,0a6,6 0 0 0 0,-12z"></Path>
<Path Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Data="m90,0l-24,0a6,6 0 0 0 0,12l18,0l0,18a6,6 0 0 0 12,0l0,-24a5.9966,5.9966 0 0 0 -6,-6z"></Path>
<Path Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Data="m30,84l-18,0l0,-18a6,6 0 0 0 -12,0l0,24a5.9966,5.9966 0 0 0 6,6l24,0a6,6 0 0 0 0,-12z"></Path>
<Path Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Data="m90,60a5.9966,5.9966 0 0 0 -6,6l0,18l-18,0a6,6 0 0 0 0,12l24,0a5.9966,5.9966 0 0 0 6,-6l0,-24a5.9966,5.9966 0 0 0 -6,-6z"></Path>
</Grid>
</Viewbox>
<Ellipse Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" StrokeThickness="1" Fill="Transparent"
MouseEnter="Ellipse_MouseEnter" MouseLeave="Ellipse_MouseLeave" MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"
Grid.RowSpan="3" Grid.ColumnSpan="3"></Ellipse>
<local:CircularButton Foreground="{DynamicResource MahApps.Brushes.ThemeForeground}"
Highlight="{DynamicResource MahApps.Brushes.Accent}"
Clicked="HighlightButton_Clicked">
<local:CircularButton.Content>
<Viewbox Stretch="Fill" Width="60" Height="60">
<Grid Width="130" Height="130" Margin="35, 35, 0, 0">
<Path Fill="{DynamicResource MahApps.Brushes.ThemeForeground}"
Data="m30,0l-24,0a5.9966,5.9966 0 0 0 -6,6l0,24a6,6 0 0 0 12,0l0,-18l18,0a6,6 0 0 0 0,-12z"></Path>
<Path Fill="{DynamicResource MahApps.Brushes.ThemeForeground}"
Data="m90,0l-24,0a6,6 0 0 0 0,12l18,0l0,18a6,6 0 0 0 12,0l0,-24a5.9966,5.9966 0 0 0 -6,-6z"></Path>
<Path Fill="{DynamicResource MahApps.Brushes.ThemeForeground}"
Data="m30,84l-18,0l0,-18a6,6 0 0 0 -12,0l0,24a5.9966,5.9966 0 0 0 6,6l24,0a6,6 0 0 0 0,-12z"></Path>
<Path Fill="{DynamicResource MahApps.Brushes.ThemeForeground}"
Data="m90,60a5.9966,5.9966 0 0 0 -6,6l0,18l-18,0a6,6 0 0 0 0,12l24,0a5.9966,5.9966 0 0 0 6,-6l0,-24a5.9966,5.9966 0 0 0 -6,-6z"></Path>
</Grid>
</Viewbox>
</local:CircularButton.Content>
</local:CircularButton>
</Grid>
</UserControl>
@@ -1,8 +1,7 @@
using System;
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls;
namespace Daybreak.Controls.Buttons;
/// <summary>
/// Interaction logic for SaveButton.xaml
@@ -16,21 +15,8 @@ public partial class MaximizeButton : UserControl
this.InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
private void HighlightButton_Clicked(object sender, EventArgs e)
{
this.BackgroundEllipse.Visibility = System.Windows.Visibility.Visible;
}
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Visibility = System.Windows.Visibility.Hidden;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
Clicked?.Invoke(this, e);
}
this.Clicked?.Invoke(this, e);
}
}
+4 -1
View File
@@ -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>
@@ -23,7 +24,9 @@
Opacity="{Binding ElementName=_this, Path=Highlighted, Converter={StaticResource HighlightConverter}}"
Grid.ColumnSpan="2">
</Rectangle>
<ContentPresenter Margin="5"
<ContentPresenter Margin="5"
HorizontalAlignment="{Binding ElementName=_this, Path=HorizontalContentAlignment, Mode=OneWay}"
VerticalAlignment="{Binding ElementName=_this, Path=VerticalContentAlignment, Mode=OneWay}"
Content="{Binding ElementName=_this, Path=InnerContent, Mode=OneWay}" />
<TextBlock Grid.Column="1"
Text="{Binding ElementName=_this, Path=Title, Mode=OneWay}"
+8 -3
View File
@@ -3,6 +3,7 @@ using System.Windows.Extensions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Input;
namespace Daybreak.Controls.Buttons;
@@ -21,23 +22,27 @@ public partial class MenuButton : UserControl
private FrameworkElement innerContent = default!;
[GenerateDependencyProperty(InitialValue = "")]
private string title = string.Empty;
[GenerateDependencyProperty]
private HorizontalAlignment horizontalContentAlignment = HorizontalAlignment.Left;
[GenerateDependencyProperty]
private VerticalAlignment verticalContentAlignment = VerticalAlignment.Top;
public MenuButton()
{
this.InitializeComponent();
}
private void Grid_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
private void Grid_MouseEnter(object sender, MouseEventArgs e)
{
this.Highlighted = true;
}
private void Grid_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
private void Grid_MouseLeave(object sender, MouseEventArgs e)
{
this.Highlighted = false;
}
private void Rectangle_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
private void Rectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.Clicked?.Invoke(this, e);
}
+17 -12
View File
@@ -1,20 +1,25 @@
<UserControl x:Class="Daybreak.Controls.MinusButton"
<UserControl x:Class="Daybreak.Controls.Buttons.MinusButton"
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:local="clr-namespace:Daybreak.Controls.Buttons"
mc:Ignorable="d"
x:Name="_this"
Cursor="Hand"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
<Ellipse x:Name="BackgroundEllipse" Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Visibility="Visible" Opacity="0.1" />
<Path Data="m13,26a13,13 0 1 1 13,-13a13,13 0 0 1 -13,13zm0,-24a11,11 0 1 0 11,11a11,11 0 0 0 -11,-11z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Path>
<Path Data="m19,14l-12,0a1,1 0 0 1 0,-2l12,0a1,1 0 0 1 0,2z"
Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></Path>
<Ellipse Fill="Transparent" MouseEnter="Ellipse_MouseEnter" MouseLeave="Ellipse_MouseLeave" MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"></Ellipse>
</Grid>
</Viewbox>
<Grid>
<local:CircularButton Foreground="{StaticResource MahApps.Brushes.ThemeForeground}"
Highlight="{StaticResource MahApps.Brushes.Accent}"
Clicked="HighlightButton_Clicked">
<local:CircularButton.Content>
<Viewbox Stretch="Fill" Width="60" Height="60">
<Grid Width="25" Height="25">
<Path Data="m19,14l-12,0a1,1 0 0 1 0,-2l12,0a1,1 0 0 1 0,2z"
Fill="{StaticResource MahApps.Brushes.ThemeForeground}"></Path>
</Grid>
</Viewbox>
</local:CircularButton.Content>
</local:CircularButton>
</Grid>
</UserControl>
+3 -17
View File
@@ -1,8 +1,7 @@
using System;
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls;
namespace Daybreak.Controls.Buttons;
/// <summary>
/// Interaction logic for AddButton.xaml
@@ -16,21 +15,8 @@ public partial class MinusButton : UserControl
this.InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
private void HighlightButton_Clicked(object sender, EventArgs e)
{
this.BackgroundEllipse.Opacity = 0.6;
}
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
Clicked?.Invoke(this, e);
}
this.Clicked?.Invoke(this, e);
}
}
@@ -1,32 +0,0 @@
<UserControl x:Class="Daybreak.Controls.OpaqueButton"
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">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"></BooleanToVisibilityConverter>
</UserControl.Resources>
<Grid>
<Rectangle Fill="{Binding ElementName=_this, Path=TransparentBackground, Mode=OneWay}"
Opacity="{Binding ElementName=_this, Path=BackgroundOpacity, Mode=OneWay}"></Rectangle>
<TextBlock Background="Transparent" Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Text="{Binding ElementName=_this, Path=Text, Mode=OneWay}"
FontSize="{Binding ElementName=_this, Path=FontSize, Mode=OneWay}"
FontFamily="{Binding ElementName=_this, Path=FontFamily, Mode=OneWay}"
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>
<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>
</Grid>
</UserControl>
@@ -1,49 +0,0 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
using System.Windows.Input;
using System.Windows.Media;
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for OpaqueButton.xaml
/// </summary>
public partial class OpaqueButton : UserControl
{
public event EventHandler? Clicked;
[GenerateDependencyProperty(InitialValue = "")]
private string text = string.Empty;
[GenerateDependencyProperty]
private Brush transparentBackground = default!;
[GenerateDependencyProperty]
private Brush highlight = default!;
[GenerateDependencyProperty]
public double backgroundOpacity;
[GenerateDependencyProperty]
public double highlightOpacity;
[GenerateDependencyProperty]
public bool highlightVisible;
public OpaqueButton()
{
this.InitializeComponent();
}
private void Rectangle_MouseEnter(object sender, MouseEventArgs e)
{
this.HighlightVisible = true;
}
private void Rectangle_MouseLeave(object sender, MouseEventArgs e)
{
this.HighlightVisible = false;
}
private void Rectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.Clicked?.Invoke(this, e);
}
}
@@ -0,0 +1,21 @@
<UserControl x:Class="Daybreak.Controls.Buttons.RefreshButton"
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.Buttons"
xmlns:glyphs="clr-namespace:Daybreak.Controls.Glyphs"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<local:CircularButton Foreground="{DynamicResource MahApps.Brushes.ThemeForeground}"
Highlight="{DynamicResource MahApps.Brushes.Accent}"
Clicked="HighlightButton_Clicked">
<local:CircularButton.Content>
<Viewbox Width="60" Height="60">
<glyphs:RefreshGlyph Foreground="{DynamicResource MahApps.Brushes.ThemeForeground}" Margin="0, 60, 60, 120"></glyphs:RefreshGlyph>
</Viewbox>
</local:CircularButton.Content>
</local:CircularButton>
</Grid>
</UserControl>
@@ -0,0 +1,21 @@
using System;
using System.Windows.Controls;
namespace Daybreak.Controls.Buttons;
/// <summary>
/// Interaction logic for RefreshButton.xaml
/// </summary>
public partial class RefreshButton : UserControl
{
public event EventHandler? Clicked;
public RefreshButton()
{
this.InitializeComponent();
}
private void HighlightButton_Clicked(object sender, EventArgs e)
{
this.Clicked?.Invoke(this, e);
}
}
+25 -20
View File
@@ -1,28 +1,33 @@
<UserControl x:Class="Daybreak.Controls.SaveButton"
<UserControl x:Class="Daybreak.Controls.Buttons.SaveButton"
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:local="clr-namespace:Daybreak.Controls.Buttons"
x:Name="_this"
Cursor="Hand"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
<Ellipse x:Name="BackgroundEllipse" Fill="{Binding ElementName=_this, Path=Foreground}"
Opacity="0.6" Visibility="Hidden"></Ellipse>
<Path Data="m76.996,0l-3.385,0l-38.651,0l-29.759,0c-2.868,0 -5.201,2.333 -5.201,5.201l0,75.6c0,2.866 2.333,5.199 5.201,5.199l3.199,0l69.061,0l3.34,0c2.867,0 5.199,-2.333 5.199,-5.199l0,-71.796l-9.004,-9.005zm-5.385,2l0,15.802c0,1.764 -1.436,3.198 -3.199,3.198l-29.25,0c-1.766,0 -3.202,-1.435 -3.202,-3.198l0,-15.802l35.651,0zm-61.211,82l0,-45.251c0,-1.764 1.437,-3.199 3.201,-3.199l58.66,0c1.764,0 3.199,1.435 3.199,3.199l0,45.251l-65.06,0zm73.6,-3.199c0,1.764 -1.436,3.199 -3.199,3.199l-3.34,0l0,-45.251c0,-2.867 -2.332,-5.199 -5.199,-5.199l-58.66,0c-2.868,0 -5.201,2.333 -5.201,5.199l0,45.251l-3.199,0c-1.765,0 -3.202,-1.435 -3.202,-3.199l0,-75.6c0,-1.765 1.437,-3.201 3.201,-3.201l28.759,0l0,15.802c0,2.866 2.334,5.198 5.202,5.198l29.25,0c2.867,0 5.199,-2.332 5.199,-5.198l0,-15.802l2.557,0l7.832,7.833l0,70.968z"
Stroke="{Binding ElementName=_this, Path=Foreground}" StrokeThickness="3" Margin="22"/>
<Rectangle Stroke="{Binding ElementName=_this, Path=Foreground}" Margin="84.352, 25.201, 0, 0"
VerticalAlignment="Top" HorizontalAlignment="Left" StrokeThickness="3" Width="4.209" Height="12.473" />
<Rectangle Stroke="{Binding ElementName=_this, Path=Foreground}" Margin="39.375, 67.25, 0, 0"
VerticalAlignment="Top" HorizontalAlignment="Left" StrokeThickness="3" Width="47.25" Height="3" />
<Rectangle Stroke="{Binding ElementName=_this, Path=Foreground}" Margin="39.375, 76.875, 0, 0"
VerticalAlignment="Top" HorizontalAlignment="Left" StrokeThickness="3" Width="47.25" Height="3" />
<Rectangle Stroke="{Binding ElementName=_this, Path=Foreground}" Margin="39.375, 85.625, 0, 0"
VerticalAlignment="Top" HorizontalAlignment="Left" StrokeThickness="3" Width="47.25" Height="3" />
<Ellipse Stroke="{Binding ElementName=_this, Path=Foreground}" Width="128" Height="128" StrokeThickness="8" Fill="Transparent"
MouseEnter="Ellipse_MouseEnter" MouseLeave="Ellipse_MouseLeave" MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"></Ellipse>
</Grid>
</Viewbox>
<Grid>
<local:CircularButton Foreground="{StaticResource MahApps.Brushes.ThemeForeground}"
Highlight="{StaticResource MahApps.Brushes.Accent}"
Clicked="HighlightButton_Clicked">
<local:CircularButton.Content>
<Viewbox Stretch="Fill" Width="60" Height="60">
<Grid Width="150" Height="150" Margin="20, 20, 0, 0">
<Path Data="m76.996,0l-3.385,0l-38.651,0l-29.759,0c-2.868,0 -5.201,2.333 -5.201,5.201l0,75.6c0,2.866 2.333,5.199 5.201,5.199l3.199,0l69.061,0l3.34,0c2.867,0 5.199,-2.333 5.199,-5.199l0,-71.796l-9.004,-9.005zm-5.385,2l0,15.802c0,1.764 -1.436,3.198 -3.199,3.198l-29.25,0c-1.766,0 -3.202,-1.435 -3.202,-3.198l0,-15.802l35.651,0zm-61.211,82l0,-45.251c0,-1.764 1.437,-3.199 3.201,-3.199l58.66,0c1.764,0 3.199,1.435 3.199,3.199l0,45.251l-65.06,0zm73.6,-3.199c0,1.764 -1.436,3.199 -3.199,3.199l-3.34,0l0,-45.251c0,-2.867 -2.332,-5.199 -5.199,-5.199l-58.66,0c-2.868,0 -5.201,2.333 -5.201,5.199l0,45.251l-3.199,0c-1.765,0 -3.202,-1.435 -3.202,-3.199l0,-75.6c0,-1.765 1.437,-3.201 3.201,-3.201l28.759,0l0,15.802c0,2.866 2.334,5.198 5.202,5.198l29.25,0c2.867,0 5.199,-2.332 5.199,-5.198l0,-15.802l2.557,0l7.832,7.833l0,70.968z"
Stroke="{StaticResource MahApps.Brushes.ThemeForeground}" StrokeThickness="3" Margin="22"/>
<Rectangle Stroke="{StaticResource MahApps.Brushes.ThemeForeground}" Margin="84.352, 25.201, 0, 0"
VerticalAlignment="Top" HorizontalAlignment="Left" StrokeThickness="3" Width="4.209" Height="12.473" />
<Rectangle Stroke="{StaticResource MahApps.Brushes.ThemeForeground}" Margin="39.375, 67.25, 0, 0"
VerticalAlignment="Top" HorizontalAlignment="Left" StrokeThickness="3" Width="47.25" Height="3" />
<Rectangle Stroke="{StaticResource MahApps.Brushes.ThemeForeground}" Margin="39.375, 76.875, 0, 0"
VerticalAlignment="Top" HorizontalAlignment="Left" StrokeThickness="3" Width="47.25" Height="3" />
<Rectangle Stroke="{StaticResource MahApps.Brushes.ThemeForeground}" Margin="39.375, 85.625, 0, 0"
VerticalAlignment="Top" HorizontalAlignment="Left" StrokeThickness="3" Width="47.25" Height="3" />
</Grid>
</Viewbox>
</local:CircularButton.Content>
</local:CircularButton>
</Grid>
</UserControl>
+3 -17
View File
@@ -1,8 +1,7 @@
using System;
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls;
namespace Daybreak.Controls.Buttons;
/// <summary>
/// Interaction logic for SaveButton.xaml
@@ -16,21 +15,8 @@ public partial class SaveButton : UserControl
this.InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
private void HighlightButton_Clicked(object sender, EventArgs e)
{
this.BackgroundEllipse.Visibility = System.Windows.Visibility.Visible;
}
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Visibility = System.Windows.Visibility.Hidden;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
Clicked?.Invoke(this, e);
}
this.Clicked?.Invoke(this, e);
}
}
+23
View File
@@ -0,0 +1,23 @@
<UserControl x:Class="Daybreak.Controls.Buttons.StarButton"
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.Buttons"
xmlns:glyphs="clr-namespace:Daybreak.Controls.Glyphs"
x:Name="_this"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<local:CircularButton Foreground="{StaticResource MahApps.Brushes.ThemeForeground}"
Highlight="{StaticResource MahApps.Brushes.Accent}"
Clicked="HighlightButton_Clicked">
<local:CircularButton.Content>
<Viewbox Stretch="Fill" Width="60" Height="60">
<glyphs:StarGlyph Foreground="{StaticResource MahApps.Brushes.ThemeForeground}" Margin="10"
IsEnabled="{Binding ElementName=_this, Path=IsEnabled, Mode=OneWay}"></glyphs:StarGlyph>
</Viewbox>
</local:CircularButton.Content>
</local:CircularButton>
</Grid>
</UserControl>
@@ -0,0 +1,21 @@
using System;
using System.Windows.Controls;
namespace Daybreak.Controls.Buttons;
/// <summary>
/// Interaction logic for StarButton.xaml
/// </summary>
public partial class StarButton : UserControl
{
public event EventHandler? Clicked;
public StarButton()
{
this.InitializeComponent();
}
private void HighlightButton_Clicked(object sender, EventArgs e)
{
this.Clicked?.Invoke(this, e);
}
}
@@ -1,36 +1,40 @@
<UserControl x:Class="Daybreak.Controls.SynchronizeButton"
<UserControl x:Class="Daybreak.Controls.Buttons.SynchronizeButton"
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:local="clr-namespace:Daybreak.Controls.Buttons"
mc:Ignorable="d"
x:Name="_this"
Cursor="Hand"
d:DesignHeight="450" d:DesignWidth="800">
<Viewbox>
<Grid>
<Ellipse x:Name="BackgroundEllipse" Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}" Visibility="Visible" Opacity="0.1" Width="35" Height="35" />
<Ellipse Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
StrokeThickness="3"/>
<Grid VerticalAlignment="Center"
HorizontalAlignment="Center">
<Path Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
StrokeThickness="1.5"
Data="m19,15.6073c1.4937,-0.5852 3,-1.9184 3,-4.6073c0,-4 -3.3333,-5 -5,-5c0,-2 0,-6 -6,-6c-6,0 -6,4 -6,6c-1.66667,0 -5,1 -5,5c0,2.6889 1.50628,4.0221 3,4.6073" />
<Path StrokeThickness="1.5"
Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Data="m6,17l1.76777,1.7678c1.56214,1.5621 4.09474,1.5621 5.65684,0l0.3536,-0.3536" />
<Path StrokeThickness="1.5"
Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Data="m6.35355,19.4749l-0.35355,-2.4749l2.47482,0.3536l-2.12127,2.1213z" />
<Path StrokeThickness="1.5"
Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Data="m14.77821,14.93927l-1.7678,-1.7677c-1.5621,-1.5621 -4.0948,-1.5621 -5.65685,0l-0.35356,0.3535" />
<Path StrokeThickness="1.5"
Stroke="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Data="m14.1213,12l0.3536,2.4749l-2.4749,-0.3536l2.1213,-2.1213z" />
</Grid>
<Ellipse Fill="Transparent" MouseEnter="Ellipse_MouseEnter" MouseLeave="Ellipse_MouseLeave" MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"></Ellipse>
</Grid>
</Viewbox>
<Grid>
<local:CircularButton Foreground="{StaticResource MahApps.Brushes.ThemeForeground}"
Highlight="{StaticResource MahApps.Brushes.Accent}"
Clicked="HighlightButton_Clicked">
<local:CircularButton.Content>
<Viewbox Stretch="Fill" Width="60" Height="60">
<Grid>
<Grid Width="30" Height="30" Margin="7.5, 7.5, 0, 0">
<Path Stroke="{StaticResource MahApps.Brushes.ThemeForeground}"
StrokeThickness="2"
Data="m19,15.6073c1.4937,-0.5852 3,-1.9184 3,-4.6073c0,-4 -3.3333,-5 -5,-5c0,-2 0,-6 -6,-6c-6,0 -6,4 -6,6c-1.66667,0 -5,1 -5,5c0,2.6889 1.50628,4.0221 3,4.6073" />
<Path StrokeThickness="2"
Stroke="{StaticResource MahApps.Brushes.ThemeForeground}"
Data="m6,17l1.76777,1.7678c1.56214,1.5621 4.09474,1.5621 5.65684,0l0.3536,-0.3536" />
<Path StrokeThickness="2"
Stroke="{StaticResource MahApps.Brushes.ThemeForeground}"
Data="m6.35355,19.4749l-0.35355,-2.4749l2.47482,0.3536l-2.12127,2.1213z" />
<Path StrokeThickness="2"
Stroke="{StaticResource MahApps.Brushes.ThemeForeground}"
Data="m14.77821,14.93927l-1.7678,-1.7677c-1.5621,-1.5621 -4.0948,-1.5621 -5.65685,0l-0.35356,0.3535" />
<Path StrokeThickness="2"
Stroke="{StaticResource MahApps.Brushes.ThemeForeground}"
Data="m14.1213,12l0.3536,2.4749l-2.4749,-0.3536l2.1213,-2.1213z" />
</Grid>
</Grid>
</Viewbox>
</local:CircularButton.Content>
</local:CircularButton>
</Grid>
</UserControl>
@@ -1,8 +1,7 @@
using System;
using System.Windows.Controls;
using System.Windows.Input;
namespace Daybreak.Controls;
namespace Daybreak.Controls.Buttons;
/// <summary>
/// Interaction logic for SynchronizeButton.xaml
@@ -16,21 +15,8 @@ public partial class SynchronizeButton : UserControl
this.InitializeComponent();
}
private void Ellipse_MouseEnter(object sender, MouseEventArgs e)
private void HighlightButton_Clicked(object sender, EventArgs e)
{
this.BackgroundEllipse.Opacity = 0.6;
}
private void Ellipse_MouseLeave(object sender, MouseEventArgs e)
{
this.BackgroundEllipse.Opacity = 0;
}
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
this.Clicked?.Invoke(this, e);
}
this.Clicked?.Invoke(this, e);
}
}
-45
View File
@@ -1,45 +0,0 @@
<UserControl x:Class="Daybreak.Controls.TileButton"
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:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:behaviors="clr-namespace:Daybreak.Behaviors"
xmlns:converters="clr-namespace:Daybreak.Converters"
x:Name="_this"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<converters:TileButtonHighlightConverter x:Key="HighlightConverter"></converters:TileButtonHighlightConverter>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<ContentPresenter Margin="5"
Content="{Binding ElementName=_this, Path=InnerContent}"></ContentPresenter>
<Border BorderBrush="{Binding ElementName=_this, Path=BorderBrush}"
BorderThickness="{Binding ElementName=_this, Path=BorderThickness}"
Opacity="{Binding ElementName=_this, Path=Highlighted, Converter={StaticResource HighlightConverter}}"
Grid.RowSpan="2">
</Border>
<TextBlock Grid.Row="1" Text="{Binding ElementName=_this, Path=Title}"
FontSize="{Binding ElementName=_this, Path=FontSize}"
FontFamily="{Binding ElementName=_this, Path=FontFamily}"
Foreground="{Binding ElementName=_this, Path=Foreground}"
VerticalAlignment="Center" HorizontalAlignment="Stretch" TextWrapping="Wrap"
TextAlignment="Center">
<i:Interaction.Behaviors>
<behaviors:ScaleFontWithSize MaxFontSize="22"></behaviors:ScaleFontWithSize>
</i:Interaction.Behaviors>
</TextBlock>
<Rectangle Fill="Transparent"
MouseEnter="Grid_MouseEnter"
MouseLeave="Grid_MouseLeave"
MouseLeftButtonDown="Rectangle_MouseLeftButtonDown"
Grid.RowSpan="2">
</Rectangle>
</Grid>
</UserControl>
@@ -1,44 +0,0 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Extensions;
using System.Windows.Media;
namespace Daybreak.Controls;
/// <summary>
/// Interaction logic for TileButton.xaml
/// </summary>
public partial class TileButton : UserControl
{
public event EventHandler? Clicked;
[GenerateDependencyProperty]
public bool highlighted;
[GenerateDependencyProperty(InitialValue = "")]
public string title = string.Empty;
[GenerateDependencyProperty]
public FrameworkElement InnerContent = default!;
[GenerateDependencyProperty]
public Brush HighlightColor = default!;
public TileButton()
{
this.InitializeComponent();
}
private void Grid_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
this.Highlighted = true;
}
private void Grid_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
this.Highlighted = false;
}
private void Rectangle_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
this.Clicked?.Invoke(this, e);
}
}
+52 -41
View File
@@ -6,21 +6,27 @@
xmlns:wv2="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
xmlns:local="clr-namespace:Daybreak.Controls"
xmlns:converters="clr-namespace:Daybreak.Converters"
xmlns:buttons="clr-namespace:Daybreak.Controls.Buttons"
mc:Ignorable="d"
Loaded="UserControl_Loaded"
Unloaded="UserControl_Unloaded"
x:Name="_this"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" TriggerValue="True"></converters:BooleanToVisibilityConverter>
<converters:BooleanToVisibilityConverter x:Key="ReverseBooleanToVisibilityConverter" TriggerValue="False"></converters:BooleanToVisibilityConverter>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"></BooleanToVisibilityConverter>
<converters:BooleanToVisibilityConverter x:Key="ReverseBooleanToVisibilityConverter" TriggerValue="True"></converters:BooleanToVisibilityConverter>
</UserControl.Resources>
<UserControl.ContextMenu>
<ContextMenu>
<ContextMenu.Template>
<ControlTemplate>
<StackPanel Margin="10">
<local:OpaqueButton Text="Load build template" Foreground="White" Background="#F0202020" BackgroundOpacity="0.4"
Clicked="LoadBuildTemplateButton_Click" FontSize="16" Height="40" Width="200"></local:OpaqueButton>
<buttons:MenuButton Title="Load build template" Foreground="{DynamicResource MahApps.Brushes.ThemeForeground}"
Background="{DynamicResource MahApps.Brushes.ThemeBackground}"
HighlightColor="{DynamicResource MahApps.Brushes.Accent}"
Clicked="LoadBuildTemplateButton_Click" FontSize="16" Height="40" Width="200"
BorderBrush="{StaticResource MahApps.Brushes.ThemeForeground}"
BorderThickness="1"></buttons:MenuButton>
</StackPanel>
</ControlTemplate>
</ContextMenu.Template>
@@ -31,33 +37,33 @@
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</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}"
Visibility="{Binding ElementName=_this, Path=ControlsEnabled, Mode=OneWay, Converter={StaticResource ReverseBooleanToVisibilityConverter}}">
<wv2:WebView2 x:Name="WebBrowser"
Margin="{Binding ElementName=_this, Path=BorderThickness, Mode=OneWay}"
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"
Visibility="{Binding ElementName=_this, Path=BrowserEnabled, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}"></wv2:WebView2>
<Grid Grid.Row="1" Background="{DynamicResource Daybreak.Brushes.Background}" IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"
Visibility="{Binding ElementName=_this, Path=ControlsEnabled, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<WrapPanel>
<local:BackButton Height="30" Width="30" Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
<buttons:BackButton Height="30" Width="30"
Clicked="BackButton_Clicked" Margin="5" Cursor="Hand"
IsEnabled="{Binding ElementName=WebBrowser, Path=CanGoBack, Mode=OneWay}"></local:BackButton>
<local:BackButton Height="30" Width="30" Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
IsEnabled="{Binding ElementName=WebBrowser, Path=CanGoBack, Mode=OneWay}"></buttons:BackButton>
<buttons:BackButton Height="30" Width="30"
Clicked="ForwardButton_Clicked" Margin="5" Cursor="Hand"
IsEnabled="{Binding ElementName=WebBrowser, Path=CanGoForward, Mode=OneWay}">
<local:BackButton.RenderTransform>
<buttons:BackButton.RenderTransform>
<RotateTransform Angle="180" CenterX="15" CenterY="15"></RotateTransform>
</local:BackButton.RenderTransform>
</local:BackButton>
</buttons:BackButton.RenderTransform>
</buttons:BackButton>
<Grid Height="30" Width="30" Margin="5">
<local:RefreshGlyph Height="30" Width="30" Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Clicked="RefreshGlyph_Clicked" Cursor="Hand"
Visibility="{Binding ElementName=_this, Path=Navigating, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}"></local:RefreshGlyph>
<local:CancelButton Height="30" Width="30" Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Clicked="CancelGlyph_Clicked" Cursor="Hand"
Visibility="{Binding ElementName=_this, Path=Navigating, Mode=OneWay, Converter={StaticResource ReverseBooleanToVisibilityConverter}}"></local:CancelButton>
<buttons:RefreshButton Height="30" Width="30" Clicked="RefreshGlyph_Clicked" Cursor="Hand"
Visibility="{Binding ElementName=_this, Path=Navigating, Mode=OneWay, Converter={StaticResource ReverseBooleanToVisibilityConverter}}"></buttons:RefreshButton>
<buttons:RefreshButton Height="30" Width="30" Clicked="CancelGlyph_Clicked" Cursor="Hand"
Visibility="{Binding ElementName=_this, Path=Navigating, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}"></buttons:RefreshButton>
</Grid>
</WrapPanel>
<TextBox Text="{Binding ElementName=_this, Path=Address, Mode=OneWay}" FontSize="16"
@@ -68,35 +74,40 @@
PreviewKeyDown="TextBox_PreviewKeyDown"
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}"
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>
<buttons:HomeButton Width="30" Height="30" Margin="5"
Visibility="{Binding ElementName=_this, Path=HomeButtonVisible, Mode=OneWay, Converter={StaticResource ReverseBooleanToVisibilityConverter}}"
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"
Clicked="HomeButton_Clicked"></buttons:HomeButton>
<buttons:StarButton Height="30" Width="30" Margin="5"
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
Visibility="{Binding ElementName=_this, Path=HomeButtonVisible, Mode=OneWay, Converter={StaticResource ReverseBooleanToVisibilityConverter}}"
IsEnabled="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay}"
Clicked="StarGlyph_Clicked" x:Name="FavoriteButton"></buttons:StarButton>
<buttons: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"></buttons:MaximizeButton>
</StackPanel>
</Grid>
<Grid Grid.RowSpan="2" Background="Gray"
Visibility="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay,Converter={StaticResource BooleanToVisibilityConverter}}">
<Grid Grid.RowSpan="2" Background="{StaticResource Daybreak.Brushes.Background}"
Visibility="{Binding ElementName=_this, Path=BrowserSupported, Mode=OneWay,Converter={StaticResource ReverseBooleanToVisibilityConverter}}">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock Foreground="White" Text="Browser not supported." FontSize="26" TextWrapping="Wrap"></TextBlock>
<TextBlock Foreground="White" Text="Download the Evergreen Bootstrapper from here:" FontSize="26" TextWrapping="Wrap" />
<TextBlock Foreground="{StaticResource MahApps.Brushes.ThemeForeground}" Text="Browser not supported." FontSize="26" TextWrapping="Wrap"></TextBlock>
<TextBlock Foreground="{StaticResource MahApps.Brushes.ThemeForeground}" Text="Download the Evergreen Bootstrapper from here:" FontSize="26" TextWrapping="Wrap" />
<TextBox Background="Transparent" BorderBrush="Transparent" BorderThickness="0"
Text="https://go.microsoft.com/fwlink/p/?LinkId=2124703"
IsReadOnly="True" Margin="0, 0, 0, 30" FontSize="22" Foreground="Blue"
IsReadOnly="True" Margin="0, 0, 0, 30" FontSize="22" Foreground="{StaticResource MahApps.Brushes.Accent}"
PreviewMouseLeftButtonDown="Hyperlink_PreviewMouseLeftButtonDown" Cursor="Hand"
TextWrapping="Wrap"></TextBox>
<TextBlock Foreground="White" Text="Restart after the installation." FontSize="26" TextWrapping="Wrap" />
<TextBlock Foreground="{StaticResource MahApps.Brushes.ThemeForeground}" Text="Restart after the installation." FontSize="26" TextWrapping="Wrap" />
</StackPanel>
</Grid>
<Grid Grid.RowSpan="2" Background="{StaticResource Daybreak.Brushes.Background}"
Visibility="{Binding ElementName=_this, Path=ShowBrowserDisabledMessage, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock Foreground="{StaticResource MahApps.Brushes.ThemeForeground}" Text="Browser is disabled." FontSize="26" TextWrapping="Wrap"></TextBlock>
</StackPanel>
</Grid>
</Grid>
</UserControl>
+205 -80
View File
@@ -1,15 +1,23 @@
using Daybreak.Configuration;
using Daybreak.Configuration.Options;
using Daybreak.Models.Browser;
using Daybreak.Models.Guildwars;
using Daybreak.Services.BuildTemplates;
using Daybreak.Services.Options;
using Daybreak.Utils;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Web.WebView2.Core;
using Microsoft.Web.WebView2.Wpf;
using Newtonsoft.Json.Linq;
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;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
@@ -26,30 +34,40 @@ 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 CoreWebView2Environment? coreWebView2Environment;
private static readonly Regex WebAddressRegex = new("^((http|ftp|https)://)?([\\w_-]+(?:(?:\\.[\\w_-]+)+))([\\w.,@?^=%&:/~+#-]*[\\w@?^=%&/~+#-])?", RegexOptions.Compiled);
private static readonly object Lock = new();
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)]
private bool? browserSupported;
[GenerateDependencyProperty(InitialValue = false)]
private bool browserSupported;
[GenerateDependencyProperty]
private bool addressBarReadonly;
[GenerateDependencyProperty]
[GenerateDependencyProperty(InitialValue = false)]
private bool browserEnabled;
[GenerateDependencyProperty]
private bool navigating;
@@ -61,71 +79,81 @@ public partial class ChromiumBrowserWrapper : UserControl
private bool homeButtonVisible = true;
[GenerateDependencyProperty(InitialValue = true)]
private bool favoriteButtonVisible = true;
[GenerateDependencyProperty]
private string downloadsDirectory = string.Empty;
[GenerateDependencyProperty]
private bool showBrowserDisabledMessage;
private bool browserInitialized = false;
public string Address
{
get => this.GetTypedValue<string>(AddressProperty);
set
{
if (this.BrowserSupported is true)
{
this.SetValue(AddressProperty, value);
}
}
set => this.SetValue(AddressProperty, value);
}
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.InitializeEnvironment();
this.InitializeComponent();
this.WebBrowser.IsEnabled = false;
this.initializationTask = Task.Run(this.InitializeBrowserSafe);
}
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (e.Property == AddressProperty || e.Property == FavoriteAddressProperty)
if (e.Property == AddressProperty)
{
if (this.BrowserSupported is true &&
this.browserInitialized is true &&
this.WebBrowser is not null &&
Uri.TryCreate(this.Address, UriKind.RelativeOrAbsolute, out var uri))
{
this.WebBrowser.Source = uri;
}
}
else if (e.Property == FavoriteAddressProperty)
{
this.CheckFavoriteAddress();
}
}
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);
await this.InitializeBrowserSafe();
}
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()
{
await this.InitializeBrowser();
}
public Task InitializationTask() => this.initializationTask;
private void InitializeEnvironment()
{
if (this.liveOptions!.Value.BrowsersEnabled is false)
{
this.BrowserSupported = false;
return;
}
try
{
coreWebView2Environment ??= System.Extensions.TaskExtensions.RunSync(() => CoreWebView2Environment.CreateAsync(null, "BrowserData", null));
if (CoreWebView2Environment is not null)
{
this.BrowserSupported = true;
return;
}
CoreWebView2Environment ??= System.Extensions.TaskExtensions.RunSync(() => CoreWebView2Environment.CreateAsync(null, "BrowserData", new CoreWebView2EnvironmentOptions
{
EnableTrackingPrevention = true,
AllowSingleSignOnUsingOSPrimaryAccount = true
}));
this.BrowserSupported = true;
}
@@ -136,44 +164,107 @@ public partial class ChromiumBrowserWrapper : UserControl
}
}
private async Task InitializeBrowserSafe()
{
await this.Dispatcher.InvokeAsync(async () =>
{
while (!Monitor.TryEnter(Lock))
{
await Task.Delay(100);
}
try
{
this.InitializeEnvironment();
await this.InitializeBrowser().ConfigureAwait(true);
}
finally
{
Monitor.Exit(Lock);
}
});
}
private async Task InitializeBrowser()
{
if (this.BrowserSupported is true)
this.BrowserEnabled = this.liveOptions!.Value.Enabled;
this.ShowBrowserDisabledMessage = this.BrowserSupported && !this.BrowserEnabled;
if (!this.BrowserSupported ||
!this.BrowserEnabled)
{
this.WebBrowser.IsEnabled = true;
this.BrowserEnabled = true;
await this.WebBrowser.EnsureCoreWebView2Async(coreWebView2Environment);
this.AddressBarReadonly = this.liveOptions!.Value.AddressBarReadonly;
this.CanDownloadBuild = this.liveOptions.Value.ExperimentalFeatures.DynamicBuildLoading;
this.WebBrowser.CoreWebView2.NewWindowRequested += (browser, args) => args.Handled = true;
this.WebBrowser.NavigationStarting += (browser, args) =>
{
if (this.CanNavigate is false && args.Uri != this.Address)
{
args.Cancel = true;
}
else
{
this.Navigating = true;
}
};
this.WebBrowser.NavigationCompleted += (browser, args) => this.Navigating = false;
this.WebBrowser.WebMessageReceived += this.CoreWebView2_WebMessageReceived!;
this.WebBrowser.CoreWebView2.Settings.AreDevToolsEnabled = false;
this.WebBrowser.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false;
if (this.CanDownloadBuild)
{
await this.WebBrowser.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync(Scripts.SendSelectionOnContextMenu);
}
return;
}
this.ShowBrowserDisabledMessage = false;
await this.WebBrowser.EnsureCoreWebView2Async(CoreWebView2Environment);
if (this.Address is not null &&
Uri.TryCreate(this.Address, UriKind.RelativeOrAbsolute, out var uri))
{
this.WebBrowser.Source = uri;
}
this.WebBrowser.SourceChanged += (_, args) => this.Address = this.WebBrowser.Source.ToString();
this.AddressBarReadonly = this.liveOptions!.Value.AddressBarReadonly;
this.CanDownloadBuild = this.liveOptions.Value.DynamicBuildLoading;
this.WebBrowser.CoreWebView2.NewWindowRequested += (browser, args) => args.Handled = true;
this.WebBrowser.NavigationStarting += (browser, args) =>
{
if (this.CanNavigate is false && args.Uri != this.Address)
{
args.Cancel = true;
}
else
{
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;
this.WebBrowser.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false;
if (this.CanDownloadBuild)
{
await this.WebBrowser.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync(Scripts.SendSelectionOnContextMenu);
}
this.browserInitialized = true;
}
private async void RetryInitializeButton_Clicked(object sender, EventArgs e)
{
this.InitializeEnvironment();
try
{
await this.InitializeBrowser();
await this.InitializeBrowserSafe();
}
catch
{
@@ -193,14 +284,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;
}
@@ -256,6 +352,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>();
@@ -263,6 +377,11 @@ public partial class ChromiumBrowserWrapper : UserControl
this.BuildDecoded?.Invoke(this, build);
}
private async void UserControl_Loaded(object sender, RoutedEventArgs e)
{
await this.InitializeBrowserSafe();
}
private void UserControl_Unloaded(object sender, RoutedEventArgs e)
{
if (this.PreventDispose)
@@ -271,6 +390,7 @@ public partial class ChromiumBrowserWrapper : UserControl
}
this.WebBrowser?.Dispose();
this.browserInitialized = false;
}
private void BackButton_Clicked(object sender, EventArgs e)
@@ -331,6 +451,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)
{
+18 -18
View File
@@ -376,7 +376,7 @@
<Viewbox>
<Canvas x:Name="LayoutRoot" VerticalAlignment="Top" Height="88" Width="88">
<Grid Width="10.734" Height="10.004" Canvas.Left="38.614" Canvas.Top="0.331">
<Rectangle Fill="White" x:Name="block" RenderTransformOrigin="0.5,4.3689" OpacityMask="#00000000" VerticalAlignment="Top" Height="10.004">
<Rectangle Fill="{StaticResource MahApps.Brushes.ThemeForeground}" x:Name="block" RenderTransformOrigin="0.5,4.3689" OpacityMask="#00000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform/>
@@ -386,7 +386,7 @@
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block1" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#0C000000" VerticalAlignment="Top" Height="10.004">
<Rectangle x:Name="block1" Fill="{StaticResource MahApps.Brushes.ThemeForeground}" RenderTransformOrigin="0.5,4.3689" OpacityMask="#0C000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
@@ -396,7 +396,7 @@
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block2" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#19000000" VerticalAlignment="Top" Height="10.004">
<Rectangle x:Name="block2" Fill="{StaticResource MahApps.Brushes.ThemeForeground}" RenderTransformOrigin="0.5,4.3689" OpacityMask="#19000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform/>
@@ -406,7 +406,7 @@
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block3" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#26000000" VerticalAlignment="Top" Height="10.004">
<Rectangle x:Name="block3" Fill="{StaticResource MahApps.Brushes.ThemeForeground}" RenderTransformOrigin="0.5,4.3689" OpacityMask="#26000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
@@ -416,7 +416,7 @@
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block4" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#3D000000" VerticalAlignment="Top" Height="10.004">
<Rectangle x:Name="block4" Fill="{StaticResource MahApps.Brushes.ThemeForeground}" RenderTransformOrigin="0.5,4.3689" OpacityMask="#3D000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
@@ -426,7 +426,7 @@
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block5" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#56000000" VerticalAlignment="Top" Height="10.004">
<Rectangle x:Name="block5" Fill="{StaticResource MahApps.Brushes.ThemeForeground}" RenderTransformOrigin="0.5,4.3689" OpacityMask="#56000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
@@ -436,7 +436,7 @@
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block6" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#64000000" VerticalAlignment="Top" Height="10.004">
<Rectangle x:Name="block6" Fill="{StaticResource MahApps.Brushes.ThemeForeground}" RenderTransformOrigin="0.5,4.3689" OpacityMask="#64000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform/>
@@ -446,7 +446,7 @@
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block7" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#72000000" VerticalAlignment="Top" Height="10.004">
<Rectangle x:Name="block7" Fill="{StaticResource MahApps.Brushes.ThemeForeground}" RenderTransformOrigin="0.5,4.3689" OpacityMask="#72000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
@@ -456,7 +456,7 @@
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block8" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#80000000" VerticalAlignment="Top" Height="10.004">
<Rectangle x:Name="block8" Fill="{StaticResource MahApps.Brushes.ThemeForeground}" RenderTransformOrigin="0.5,4.3689" OpacityMask="#80000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform/>
@@ -466,8 +466,8 @@
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block9" Fill="White" OpacityMask="#8E000000" RenderTransformOrigin="0.5,4.3689" VerticalAlignment="Top" Height="10.004"/>
<Rectangle x:Name="block10" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#9C000000" VerticalAlignment="Top" Height="10.004">
<Rectangle x:Name="block9" Fill="{StaticResource MahApps.Brushes.ThemeForeground}" OpacityMask="#8E000000" RenderTransformOrigin="0.5,4.3689" VerticalAlignment="Top" Height="10.004"/>
<Rectangle x:Name="block10" Fill="{StaticResource MahApps.Brushes.ThemeForeground}" RenderTransformOrigin="0.5,4.3689" OpacityMask="#9C000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform/>
@@ -477,7 +477,7 @@
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block11" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#AA000000" VerticalAlignment="Top" Height="10.004">
<Rectangle x:Name="block11" Fill="{StaticResource MahApps.Brushes.ThemeForeground}" RenderTransformOrigin="0.5,4.3689" OpacityMask="#AA000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
@@ -487,7 +487,7 @@
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block12" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#B8000000" VerticalAlignment="Top" Height="10.004">
<Rectangle x:Name="block12" Fill="{StaticResource MahApps.Brushes.ThemeForeground}" RenderTransformOrigin="0.5,4.3689" OpacityMask="#B8000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform/>
@@ -497,7 +497,7 @@
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block13" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#C6000000" VerticalAlignment="Top" Height="10.004">
<Rectangle x:Name="block13" Fill="{StaticResource MahApps.Brushes.ThemeForeground}" RenderTransformOrigin="0.5,4.3689" OpacityMask="#C6000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
@@ -507,7 +507,7 @@
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block14" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#D4000000" VerticalAlignment="Top" Height="10.004">
<Rectangle x:Name="block14" Fill="{StaticResource MahApps.Brushes.ThemeForeground}" RenderTransformOrigin="0.5,4.3689" OpacityMask="#D4000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
@@ -517,7 +517,7 @@
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block15" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#E2000000" VerticalAlignment="Top" Height="10.004">
<Rectangle x:Name="block15" Fill="{StaticResource MahApps.Brushes.ThemeForeground}" RenderTransformOrigin="0.5,4.3689" OpacityMask="#E2000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
@@ -527,7 +527,7 @@
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block16" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="#F0000000" VerticalAlignment="Top" Height="10.004">
<Rectangle x:Name="block16" Fill="{StaticResource MahApps.Brushes.ThemeForeground}" RenderTransformOrigin="0.5,4.3689" OpacityMask="#F0000000" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform/>
@@ -537,7 +537,7 @@
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="block17" Fill="White" RenderTransformOrigin="0.5,4.3689" OpacityMask="Black" VerticalAlignment="Top" Height="10.004">
<Rectangle x:Name="block17" Fill="{StaticResource MahApps.Brushes.ThemeForeground}" RenderTransformOrigin="0.5,4.3689" OpacityMask="Black" VerticalAlignment="Top" Height="10.004">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.99999999999999989" ScaleY="0.99999999999999989"/>
@@ -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"
Foreground="{DynamicResource MahApps.Brushes.ThemeForeground}"
HighlightColor="{DynamicResource MahApps.Brushes.Accent}"
Title="{Binding ElementName=_this, Path=SectionTitle, Mode=OneWay}"
FontSize="{Binding ElementName=_this, Path=FontSize, 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,32 @@
<UserControl x:Class="Daybreak.Controls.FocusViewComponents.CurrentMapComponent"
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.FocusViewComponents"
xmlns:buttons="clr-namespace:Daybreak.Controls.Buttons"
Background="{DynamicResource Daybreak.Brushes.Background}"
BorderBrush="{DynamicResource MahApps.Brushes.ThemeForeground}"
BorderThickness="1"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<StackPanel>
<TextBlock
FontSize="18"
Foreground="{DynamicResource MahApps.Brushes.ThemeForeground}"
Margin="10"
Text="Current Map"></TextBlock>
<Rectangle
Height="1"
Fill="{DynamicResource MahApps.Brushes.ThemeForeground}"></Rectangle>
<buttons:MenuButton
Title="{Binding Path=Name, Mode=OneWay}"
HighlightColor="{DynamicResource MahApps.Brushes.Accent}"
Foreground="{DynamicResource MahApps.Brushes.ThemeForeground}"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Left"
Cursor="Hand"
FontSize="20"
MouseLeftButtonDown="CurrentMap_MouseLeftButtonDown"></buttons:MenuButton>
</StackPanel>
</UserControl>

Some files were not shown because too many files have changed in this diff Show More