Add project files.

This commit is contained in:
Joshua Askharoun
2021-04-25 22:59:36 -05:00
parent b998a3a1f7
commit bd946f2700
50 changed files with 2166 additions and 0 deletions
+43
View File
@@ -0,0 +1,43 @@
using OwlCore.AbstractUI.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using ZuneModCore.Mods;
namespace ZuneModCore
{
public abstract class Mod
{
/// <summary>
/// A list of all available mods
/// </summary>
public static readonly IReadOnlyList<Mod> AvailableMods = new List<Mod>
{
new FeaturesOverrideMod(),
new VideoSyncMod(),
new WebservicesMod(),
}.AsReadOnly();
public static string ZuneInstallDir { get; set; } = @"C:\Program Files\Zune\";
public abstract string Id { get; }
public abstract string Title { get; }
public abstract string Description { get; }
public virtual Task Init() => Task.CompletedTask;
public abstract Task<bool> Apply();
public abstract Task<bool> Reset();
public abstract AbstractUIElementGroup? OptionsUI { get; }
public string StorageDirectory => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"ZuneModCore", Id);
public abstract IReadOnlyList<Type>? DependentMods { get; }
}
}
+92
View File
@@ -0,0 +1,92 @@
using OwlCore.AbstractUI.Models;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ZuneModCore.Mods
{
public class FeaturesOverrideMod : Mod
{
private const string ZUNE_FEATURESOVERRIDE_REGKEY = RegEdit.ZUNE_REG_PATH + "FeaturesOverride";
public override string Id => nameof(FeaturesOverrideMod);
public override string Title => "Features Override";
public override string Description => "Re-enables access to some features disabled by Microsoft, such as the Social and Marketplace tabs.\r\n" +
"Does not restore functionality of those features, but shows them in the software.";
public override AbstractUIElementGroup OptionsUI => new(nameof(FeaturesOverrideMod))
{
Title = "Select features:",
Items =
{
// We don't know what some of these overrides do exactly, so hide them from the user.
// The ID is the name of the registry key, the label is the display name
new AbstractBooleanUIElement("Apps", "Apps"),
//new AbstractBooleanUIElement("Art", "Art"),
new AbstractBooleanUIElement("Channels", "Channels"),
//new AbstractBooleanUIElement("FirstLaunchIntroVideo", "First Launch Intro Video"),
new AbstractBooleanUIElement("Games", "Games"),
new AbstractBooleanUIElement("Marketplace", "Marketplace"),
//new AbstractBooleanUIElement("MBRPreview", "MBRPreview"),
//new AbstractBooleanUIElement("MBRPurchase", "MBRPurchase"),
//new AbstractBooleanUIElement("MBRRental", "MBRRental"),
new AbstractBooleanUIElement("Music", "Music"),
new AbstractBooleanUIElement("MusicVideos", "MusicVideos"),
new AbstractBooleanUIElement("Nowplaying", "Now Playing"),
//new AbstractBooleanUIElement("NowplayingArt", "Now Playing Art"),
new AbstractBooleanUIElement("Picks", "Picks"),
new AbstractBooleanUIElement("Podcasts", "Podcasts"),
new AbstractBooleanUIElement("QuickMixLocal", "Quick Mix (Local)"),
//new AbstractBooleanUIElement("QuickMixZMP", "Quick Mix (ZMP)"),
new AbstractBooleanUIElement("Quickplay", "Quickplay"),
//new AbstractBooleanUIElement("Sign In Available", "Sign In"),
new AbstractBooleanUIElement("Social", "Social"),
//new AbstractBooleanUIElement("SocialMarketplace", "Social Marketplace"),
//new AbstractBooleanUIElement("SubscriptionFreeTracks", "Subscription Free Tracks"),
new AbstractBooleanUIElement("Videos", "Videos"),
}
};
public override IReadOnlyList<Type>? DependentMods => null;
public override Task Init()
{
foreach (AbstractUIElement uiElem in OptionsUI.Items)
if (uiElem is AbstractBooleanUIElement boolElem)
boolElem.ChangeState(GetFeatureOverride(boolElem.Id));
return Task.CompletedTask;
}
public override Task<bool> Apply()
{
return Task.FromResult(true);
foreach (AbstractUIElement uiElem in OptionsUI.Items)
if (uiElem is AbstractBooleanUIElement boolElem && boolElem.State)
SetFeatureOverride(boolElem.Id, true);
return Task.FromResult(true);
}
public override Task<bool> Reset()
{
foreach (AbstractUIElement uiElem in OptionsUI.Items)
if (uiElem is AbstractBooleanUIElement boolElem)
ResetFeatureOverride(boolElem.Id);
return Task.FromResult(true);
}
public static void SetFeatureOverride(string feature, bool value) =>
RegEdit.CurrentUserSetBoolValue(ZUNE_FEATURESOVERRIDE_REGKEY, feature, value);
public static bool GetFeatureOverride(string feature) =>
RegEdit.CurrentUserGetBoolValue(ZUNE_FEATURESOVERRIDE_REGKEY, feature);
public static void ResetFeatureOverride(string feature) =>
RegEdit.CurrentUserDeleteValue(RegEdit.ZUNE_REG_PATH + "FeaturesOverride", feature);
}
}
+56
View File
@@ -0,0 +1,56 @@
using OwlCore.AbstractUI.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
namespace ZuneModCore.Mods
{
public class VideoSyncMod : Mod
{
public VideoSyncMod()
{
testButton.Clicked += TestButton_Clicked;
}
private void TestButton_Clicked(object? sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine("Howdy, Zune! How are ya?");
}
public override string Title => "Fix Video Sync";
public override string Description =>
"Resolves \"Error C00D11CD\" when attempting to sync video to a Zune device using Windows 10 1607 (Anniversary Update) or newer";
public override string Id => nameof(VideoSyncMod);
public override AbstractUIElementGroup OptionsUI => new(nameof(VideoSyncMod))
{
Title = Title,
Items =
{
new AbstractBooleanUIElement("test", "Is this is test?"),
testButton
}
};
private readonly AbstractButton testButton = new(nameof(testButton), "Howdy Zune!", type: AbstractButtonType.Generic);
public override Task<bool> Apply()
{
var writer = File.CreateText(Path.Combine(StorageDirectory, "1.log"));
writer.WriteLine("Hello world");
writer.Flush();
writer.Close();
return Task.FromResult(true);
}
public override Task<bool> Reset()
{
return Task.FromResult(true);
}
public override IReadOnlyList<Type>? DependentMods => null;
}
}
+80
View File
@@ -0,0 +1,80 @@
using OwlCore.AbstractUI.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using static ZuneModCore.Mods.FeaturesOverrideMod;
#if DEBUG
using System.Diagnostics;
#endif
namespace ZuneModCore.Mods
{
public class WebservicesMod : Mod
{
private readonly byte[] ZUNE_4_8_VERSION_BYTES =
{
0x34, 0x2E, 0x38
};
private const int ZUNESERVICES_ENDPOINTS_BLOCK_OFFSET = 0x14D60;
private const int ZUNESERVICES_ENDPOINTS_BLOCK_LENGTH = 0x884;
public override string Id => nameof(WebservicesMod);
public override string Title => "Community Webservices";
public override string Description => "Partially restores online features such as the Marketplace by patching the Zune desktop software " +
"to use the community's recreation of Microsoft's Zune servers at zunes.tk (instead of zune.net).";
public override AbstractUIElementGroup? OptionsUI => null;
public override IReadOnlyList<Type>? DependentMods => null;
public override async Task<bool> Apply()
{
// Open ZuneServices.dll
FileInfo zsDllInfo = new(Path.Combine(ZuneInstallDir, "ZuneService.dll"));
if (!zsDllInfo.Exists)
return false;
using FileStream zsDll = zsDllInfo.Open(FileMode.Open);
using BinaryWriter zsDllWriter = new(zsDll);
using BinaryReader zsDllReader = new(zsDll);
// Verify that the DLL is from v4.8 (other versions not tested)
zsDllReader.BaseStream.Position = 0x12C824;
var versionBytes = zsDllReader.ReadBytes(ZUNE_4_8_VERSION_BYTES.Length * 2);
if (versionBytes[0] != '4' || versionBytes[2] != '.' || versionBytes[4] != '8')
return false;
// Patch ZuneServices.dll to use zunes.tk instead of zune.net
zsDllReader.BaseStream.Position = ZUNESERVICES_ENDPOINTS_BLOCK_OFFSET;
string endpointBlock = System.Text.Encoding.Unicode.GetString(zsDllReader.ReadBytes(ZUNESERVICES_ENDPOINTS_BLOCK_LENGTH));
endpointBlock = endpointBlock.Replace("zune.net", "zunes.tk");
byte[] endpointBytes = System.Text.Encoding.Unicode.GetBytes(endpointBlock);
if (endpointBytes.Length != ZUNESERVICES_ENDPOINTS_BLOCK_LENGTH)
return false;
zsDllWriter.Seek(ZUNESERVICES_ENDPOINTS_BLOCK_OFFSET, SeekOrigin.Begin);
zsDllWriter.Write(endpointBytes);
// Enable all feature overrides affected by new servers
SetFeatureOverride("Apps", true);
SetFeatureOverride("Channels", true);
SetFeatureOverride("Games", true);
SetFeatureOverride("Marketplace", true);
SetFeatureOverride("Music", true);
SetFeatureOverride("MusicVideos", true);
SetFeatureOverride("Podcasts", true);
SetFeatureOverride("Social", true);
SetFeatureOverride("Videos", true);
return true;
}
public override Task<bool> Reset()
{
throw new NotImplementedException();
}
}
}
+64
View File
@@ -0,0 +1,64 @@
using Microsoft.Win32;
namespace ZuneModCore
{
#pragma warning disable CA1416 // Validate platform compatibility
public class RegEdit
{
public const string ZUNE_REG_PATH = @"SOFTWARE\Microsoft\Zune\";
public static void CurrentUserSetBoolValue(string key, string name, bool value)
{
RegistryKey? regKey = Registry.CurrentUser.OpenSubKey(key, true);
if (regKey == null)
regKey = Registry.CurrentUser.CreateSubKey(key, true);
regKey.SetValue(name, value, RegistryValueKind.DWord);
regKey.Close();
regKey.Dispose();
}
public static bool CurrentUserGetBoolValue(string key, string name)
{
using RegistryKey? regKey = Registry.CurrentUser.OpenSubKey(key, true);
if (regKey == null)
return false;
int? value = regKey.GetValue(name, false) as int?;
return value.HasValue && value != 0;
}
public static void CurrentUserDeleteKey(string key)
{
string[] targetKeySplit = key.Split('\\', System.StringSplitOptions.RemoveEmptyEntries);
using RegistryKey? targetKey = Registry.CurrentUser.OpenSubKey(key, true);
if (targetKey == null)
// Key is already deleted
return;
// Delete all subkeys
RegistryKey? hdr = targetKey.OpenSubKey(targetKeySplit[^1], true);
if (hdr != null)
foreach (string subKey in hdr.GetSubKeyNames())
hdr.DeleteSubKey(subKey);
hdr?.Close();
// Delete target key
targetKey.DeleteSubKeyTree(targetKeySplit[^1]);
}
public static void CurrentUserDeleteValue(string key, string name)
{
using RegistryKey? regKey = Registry.CurrentUser.OpenSubKey(key, true);
if (regKey == null)
return;
regKey.DeleteValue(name);
}
}
#pragma warning restore CA1416 // Validate platform compatibility
}
+14
View File
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>9</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="OwlCore" Version="0.0.1" />
</ItemGroup>
</Project>
+31
View File
@@ -0,0 +1,31 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31205.134
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZuneModdingHelper", "ZuneModdingHelper\ZuneModdingHelper.csproj", "{A4AE840D-BC01-4E60-B106-289218D9479F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZuneModCore", "ZuneModCore\ZuneModCore.csproj", "{4B1587B5-0DE2-4E94-87FC-239D5E7FC4E7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A4AE840D-BC01-4E60-B106-289218D9479F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A4AE840D-BC01-4E60-B106-289218D9479F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A4AE840D-BC01-4E60-B106-289218D9479F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A4AE840D-BC01-4E60-B106-289218D9479F}.Release|Any CPU.Build.0 = Release|Any CPU
{4B1587B5-0DE2-4E94-87FC-239D5E7FC4E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4B1587B5-0DE2-4E94-87FC-239D5E7FC4E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4B1587B5-0DE2-4E94-87FC-239D5E7FC4E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4B1587B5-0DE2-4E94-87FC-239D5E7FC4E7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {CB6377CF-90C6-4056-BA04-3AF40B6CEE1B}
EndGlobalSection
EndGlobal
@@ -0,0 +1,17 @@
using OwlCore.AbstractUI.Models;
using System.Windows;
using System.Windows.Controls;
namespace ZuneModdingHelper.AbstractUI.Controls
{
/// <summary>
/// A control that displays an <see cref="AbstractBooleanUIElement"/>.
/// </summary>
public sealed partial class AbstractBooleanUIElementPresenter : Control
{
static AbstractBooleanUIElementPresenter()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(AbstractBooleanUIElementPresenter), new FrameworkPropertyMetadata(typeof(AbstractBooleanUIElementPresenter)));
}
}
}
@@ -0,0 +1,20 @@
using OwlCore.AbstractUI.Models;
using System.Windows;
using System.Windows.Controls;
namespace ZuneModdingHelper.AbstractUI.Controls
{
/// <summary>
/// A control that displays an <see cref="AbstractButton"/>.
/// </summary>
public sealed partial class AbstractButtonPresenter : Control
{
/// <summary>
/// Creates a new instance of <see cref="AbstractButtonPresenter"/>.
/// </summary>
public AbstractButtonPresenter()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(AbstractButtonPresenter), new FrameworkPropertyMetadata(typeof(AbstractButtonPresenter)));
}
}
}
@@ -0,0 +1,17 @@
using System.Windows;
using System.Windows.Controls;
using OwlCore.AbstractUI.Models;
namespace ZuneModdingHelper.AbstractUI.Controls
{
/// <summary>
/// A control that displays an <see cref="AbstractDataList"/>.
/// </summary>
public sealed partial class AbstractDataListPresenter : Control
{
static AbstractDataListPresenter()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(AbstractDataListPresenter), new FrameworkPropertyMetadata(typeof(AbstractDataListPresenter)));
}
}
}
@@ -0,0 +1,17 @@
using System.Windows;
using System.Windows.Controls;
using OwlCore.AbstractUI.Models;
namespace ZuneModdingHelper.AbstractUI.Controls
{
/// <summary>
/// A control that displays an <see cref="AbstractMultiChoiceUIElement"/>.
/// </summary>
public sealed partial class AbstractMultiChoicePresenter : Control
{
static AbstractMultiChoicePresenter()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(AbstractMultiChoicePresenter), new FrameworkPropertyMetadata(typeof(AbstractMultiChoicePresenter)));
}
}
}
@@ -0,0 +1,17 @@
using System.Windows;
using System.Windows.Controls;
using OwlCore.AbstractUI.Models;
namespace ZuneModdingHelper.AbstractUI.Controls
{
/// <summary>
/// A control that displays an <see cref="AbstractMutableDataList"/>.
/// </summary>
public sealed partial class AbstractMutableDataListPresenter : Control
{
static AbstractMutableDataListPresenter()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(AbstractMutableDataListPresenter), new FrameworkPropertyMetadata(typeof(AbstractMutableDataListPresenter)));
}
}
}
@@ -0,0 +1,17 @@
using System.Windows;
using System.Windows.Controls;
using OwlCore.AbstractUI.Models;
namespace ZuneModdingHelper.AbstractUI.Controls
{
/// <summary>
/// A control that displays an <see cref="AbstractProgressUIElement"/>.
/// </summary>
public sealed partial class AbstractProgessUIElementPresenter : Control
{
static AbstractProgessUIElementPresenter()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(AbstractProgessUIElementPresenter), new FrameworkPropertyMetadata(typeof(AbstractProgessUIElementPresenter)));
}
}
}
@@ -0,0 +1,17 @@
using System.Windows;
using System.Windows.Controls;
using OwlCore.AbstractUI.Models;
namespace ZuneModdingHelper.AbstractUI.Controls
{
/// <summary>
/// A control that displays an <see cref="AbstractTextBox"/>.
/// </summary>
public sealed partial class AbstractRichTextBlockPresenter : Control
{
static AbstractRichTextBlockPresenter()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(AbstractRichTextBlockPresenter), new FrameworkPropertyMetadata(typeof(AbstractRichTextBlockPresenter)));
}
}
}
@@ -0,0 +1,17 @@
using System.Windows;
using System.Windows.Controls;
using OwlCore.AbstractUI.Models;
namespace ZuneModdingHelper.AbstractUI.Controls
{
/// <summary>
/// A control that displays an <see cref="AbstractTextBox"/>.
/// </summary>
public sealed partial class AbstractTextBoxPresenter : Control
{
static AbstractTextBoxPresenter()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(AbstractTextBoxPresenter), new FrameworkPropertyMetadata(typeof(AbstractTextBoxPresenter)));
}
}
}
@@ -0,0 +1,109 @@
using System.Windows;
using System.Windows.Controls;
using OwlCore.AbstractUI.ViewModels;
using Microsoft.Toolkit.Diagnostics;
using OwlCore.AbstractUI.Models;
namespace ZuneModdingHelper.AbstractUI.Controls
{
/// <summary>
/// The template selector used to display Abstract UI elements. Use this to define your own custom styles for each control. You may specify the existing, default styles for those you don't want to override.
/// </summary>
public class AbstractUIGroupItemTemplateSelector : DataTemplateSelector
{
/// <summary>
/// Creates a new instance of <see cref="AbstractUIGroupItemTemplateSelector"/>.
/// </summary>
public AbstractUIGroupItemTemplateSelector()
{
object textBoxTemplate = new Themes.AbstractTextBoxStyle()["DefaultAbstractTextBoxTemplate"];
if (textBoxTemplate == null)
ThrowHelper.ThrowArgumentNullException<DataTemplate>(nameof(textBoxTemplate));
object dataListTemplate = new Themes.AbstractDataListStyle()["DefaultAbstractDataListTemplate"];
if (dataListTemplate == null)
ThrowHelper.ThrowArgumentNullException<DataTemplate>(nameof(dataListTemplate));
object mutableDataListTemplate = new Themes.AbstractMutableDataListStyle()["DefaultAbstractMutableDataListTemplate"];
if (mutableDataListTemplate == null)
ThrowHelper.ThrowArgumentNullException<DataTemplate>(nameof(mutableDataListTemplate));
object buttonTemplate = new Themes.AbstractButtonStyle()["DefaultAbstractButtonTemplate"];
if (buttonTemplate == null)
ThrowHelper.ThrowArgumentNullException<DataTemplate>(nameof(buttonTemplate));
object multiChoiceTemplate = new Themes.AbstractMultiChoiceUIElementStyle()["DefaultAbstractMultipleChoiceTemplate"];
if (multiChoiceTemplate == null)
ThrowHelper.ThrowArgumentNullException<DataTemplate>(nameof(multiChoiceTemplate));
object booleanTemplate = new Themes.AbstractBooleanUIElementStyle()["DefaultAbstractBooleanUIElementTemplate"];
if (booleanTemplate == null)
ThrowHelper.ThrowArgumentNullException<DataTemplate>(nameof(booleanTemplate));
object progressTemplate = new Themes.AbstractProgressUIElementStyle()["DefaultAbstractProgressUIElementTemplate"];
if (progressTemplate == null)
ThrowHelper.ThrowArgumentNullException<DataTemplate>(nameof(progressTemplate));
TextBoxTemplate = (DataTemplate)textBoxTemplate;
DataListTemplate = (DataTemplate)dataListTemplate;
ButtonTemplate = (DataTemplate)buttonTemplate;
MutableDataListTemplate = (DataTemplate)mutableDataListTemplate;
MultiChoiceTemplate = (DataTemplate)multiChoiceTemplate;
BooleanTemplate = (DataTemplate)booleanTemplate;
ProgressTemplate = (DataTemplate)progressTemplate;
}
/// <summary>
/// The data template used to display an <see cref="AbstractTextBox"/>.
/// </summary>
public DataTemplate TextBoxTemplate { get; set; }
/// <summary>
/// The data template used to display an <see cref="AbstractDataList"/>.
/// </summary>
public DataTemplate DataListTemplate { get; set; }
/// <summary>
/// The data template used to display an <see cref="AbstractMutableDataList"/>.
/// </summary>
public DataTemplate MutableDataListTemplate { get; set; }
/// <summary>
/// The data template used to display an <see cref="AbstractButton"/>.
/// </summary>
public DataTemplate ButtonTemplate { get; set; }
/// <summary>
/// The data template used to display an <see cref="AbstractBooleanUIElement"/>.
/// </summary>
public DataTemplate BooleanTemplate { get; set; }
/// <summary>
/// The data template used to display an <see cref="AbstractProgressUIElement"/>.
/// </summary>
public DataTemplate ProgressTemplate { get; set; }
/// <summary>
/// The data template used to display an <see cref="AbstractMultiChoiceUIElement"/>.
/// </summary>
public DataTemplate MultiChoiceTemplate { get; set; }
/// <inheritdoc />
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
System.Diagnostics.Debug.WriteLine($"{item.GetType()} template selecting for {nameof(AbstractUIGroupItemTemplateSelector)}");
return item switch
{
AbstractTextBoxViewModel _ => TextBoxTemplate,
AbstractDataListViewModel _ => DataListTemplate,
AbstractButtonViewModel _ => ButtonTemplate,
AbstractMutableDataListViewModel _ => MutableDataListTemplate,
AbstractMultiChoiceUIElementViewModel _ => MultiChoiceTemplate,
AbstractBooleanViewModel _ => BooleanTemplate,
AbstractProgressUIElement _ => ProgressTemplate,
_ => base.SelectTemplate(item, container)
};
}
}
}
@@ -0,0 +1,117 @@
using System.Windows;
using System.Windows.Controls;
using OwlCore.AbstractUI.ViewModels;
using OwlCore.AbstractUI.Models;
namespace ZuneModdingHelper.AbstractUI.Controls
{
/// <summary>
/// Displays a group of abstract UI elements.
/// </summary>
public sealed partial class AbstractUIGroupPresenter : Control
{
private bool _dataContextBeingSet;
/// <summary>
/// Backing property for <see cref="ViewModel"/>.
/// </summary>
public static readonly DependencyProperty ViewModelProperty =
DependencyProperty.Register(nameof(ViewModel), typeof(AbstractUIElementGroupViewModel), typeof(AbstractUIGroupPresenter), new PropertyMetadata(null, (d, e) => ((AbstractUIGroupPresenter)d).OnViewModelChanged()));
/// <summary>
/// Backing property for <see cref="TemplateSelector"/>.
/// </summary>
public static readonly DependencyProperty TemplateSelectorProperty =
DependencyProperty.Register(nameof(TemplateSelector), typeof(DataTemplateSelector), typeof(AbstractUIGroupPresenter), new PropertyMetadata(null));
/// <summary>
/// The ViewModel for this UserControl.
/// </summary>
public AbstractUIElementGroupViewModel? ViewModel
{
get => (AbstractUIElementGroupViewModel)GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
/// <summary>
/// The template selector used to display Abstract UI elements. Use this to define your own custom styles for each control. You may specify the existing, default styles for those you don't want to override.
/// </summary>
public DataTemplateSelector? TemplateSelector
{
get => (DataTemplateSelector)GetValue(TemplateSelectorProperty);
set => SetValue(TemplateSelectorProperty, value);
}
/// <summary>
/// Creates a new instance of <see cref="AbstractUIGroupPresenter"/>.
/// </summary>
public AbstractUIGroupPresenter()
{
AttachEvents();
}
static AbstractUIGroupPresenter()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(AbstractUIGroupPresenter), new FrameworkPropertyMetadata(typeof(AbstractUIGroupPresenter)));
}
private void AttachEvents()
{
Loaded += OnLoaded;
DataContextChanged += OnDataContextChanged;
}
private void DetachEvents()
{
DataContextChanged -= OnDataContextChanged;
}
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (_dataContextBeingSet)
return;
_dataContextBeingSet = true;
if (DataContext is AbstractUIElementGroup elementGroup)
ViewModel = new AbstractUIElementGroupViewModel(elementGroup);
if (DataContext is AbstractUIElementGroupViewModel elementGroupViewModel)
ViewModel = elementGroupViewModel;
_dataContextBeingSet = false;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
Loaded -= OnLoaded;
Unloaded += OnUnloaded;
}
private void OnUnloaded(object sender, RoutedEventArgs e)
{
Unloaded -= OnUnloaded;
DetachEvents();
}
/// <summary>
/// Raised when the <see cref="ViewModel"/> changes.
/// </summary>
public void OnViewModelChanged()
{
if (_dataContextBeingSet)
return;
_dataContextBeingSet = true;
DataContext = ViewModel;
_dataContextBeingSet = false;
if (GetTemplateChild("GroupItemsControl") is ItemsControl ic)
{
ic.ItemsSource = ViewModel.Items;
}
}
}
}
@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace ZuneModdingHelper.AbstractUI.Controls
{
/// <summary>
/// Follow steps 1a or 1b and then 2 to use this custom control in a XAML file.
///
/// Step 1a) Using this custom control in a XAML file that exists in the current project.
/// Add this XmlNamespace attribute to the root element of the markup file where it is
/// to be used:
///
/// xmlns:MyNamespace="clr-namespace:ZuneModdingHelper.AbstractUI.Controls"
///
///
/// Step 1b) Using this custom control in a XAML file that exists in a different project.
/// Add this XmlNamespace attribute to the root element of the markup file where it is
/// to be used:
///
/// xmlns:MyNamespace="clr-namespace:ZuneModdingHelper.AbstractUI.Controls;assembly=ZuneModdingHelper.AbstractUI.Controls"
///
/// You will also need to add a project reference from the project where the XAML file lives
/// to this project and Rebuild to avoid compilation errors:
///
/// Right click on the target project in the Solution Explorer and
/// "Add Reference"->"Projects"->[Browse to and select this project]
///
///
/// Step 2)
/// Go ahead and use your control in the XAML file.
///
/// <MyNamespace:CustomControl1/>
///
/// </summary>
public class CustomControl1 : Control
{
static CustomControl1()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1)));
}
}
}
@@ -0,0 +1,53 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ZuneModdingHelper.AbstractUI.Themes.AbstractBooleanUIElementStyle"
xmlns:abstractUI="clr-namespace:OwlCore.AbstractUI.ViewModels;assembly=OwlCore"
xmlns:controls="clr-namespace:ZuneModdingHelper.AbstractUI.Controls"
xmlns:b="http://schemas.microsoft.com/xaml/behaviors">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/AbstractUI/Themes/AbstractUIResources.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style TargetType="{x:Type controls:AbstractButtonPresenter}">
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:AbstractButtonPresenter}">
<ContentControl ContentTemplate="{StaticResource DefaultAbstractBooleanUIElementTemplate}"
HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
<DataTemplate x:Key="DefaultAbstractBooleanUIElementTemplate" DataType="{x:Type abstractUI:AbstractBooleanViewModel}">
<StackPanel>
<TextBlock Text="{Binding Title}" FontSize="{StaticResource DefaultAbstractUITitleFontSize}" ToolTip="{Binding TooltipText}" />
<TextBlock Text="{Binding Subtitle}" FontSize="{StaticResource DefaultAbstractUISubtitleFontSize}"
FontWeight="{StaticResource DefaultAbstractUISubtitleFontWeight}"
Opacity="{StaticResource DefaultAbstractUISubtitleOpacity}"/>
<!--Visibility="{Binding convertvis:NotNullOrEmptyToVisibilityConverter.Convert(Subtitle), Mode=OneWay}"/>-->
<CheckBox ToolTip="{Binding TooltipText, Mode=OneWay}" Content="{Binding Label, Mode=OneWay}" IsChecked="{Binding IsToggled, Mode=TwoWay}">
<b:Interaction.Triggers>
<b:EventTrigger EventName="Toggled">
<b:InvokeCommandAction Command="{Binding ToggledCommand}" />
</b:EventTrigger>
</b:Interaction.Triggers>
</CheckBox>
<!--<ToggleSwitch ToolTip="{Binding TooltipText, Mode=OneWay}" OffContent="{Binding Label, Mode=OneWay}" OnContent="{Binding Label, Mode=OneWay}" IsOn="{Binding IsToggled, Mode=TwoWay}">
<b:Interaction.Triggers>
<b:EventTrigger EventName="Toggled">
<b:InvokeCommandAction Command="{Binding ToggledCommand}" />
</b:EventTrigger>
</b:Interaction.Triggers>
</ToggleSwitch>-->
</StackPanel>
</DataTemplate>
</ResourceDictionary>
@@ -0,0 +1,12 @@
using System.Windows;
namespace ZuneModdingHelper.AbstractUI.Themes
{
public sealed partial class AbstractBooleanUIElementStyle : ResourceDictionary
{
public AbstractBooleanUIElementStyle()
{
InitializeComponent();
}
}
}

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