Percent struct

This commit is contained in:
Justin Swanson 2020-02-07 22:35:08 -06:00
parent 268b7335c1
commit b05c43661c
31 changed files with 547 additions and 141 deletions

View File

@ -79,8 +79,8 @@ namespace Wabbajack.Common
if (line.Length <= 4 || line[3] != '%') if (line.Length <= 4 || line[3] != '%')
continue; continue;
int.TryParse(line.Substring(0, 3), out var percent); int.TryParse(line.Substring(0, 3), out var percentInt);
Utils.Status($"Extracting {name} - {line.Trim()}", percent); Utils.Status($"Extracting {name} - {line.Trim()}", Percent.FactoryPutInRange(percentInt / 100d));
} }
} }
catch (Exception e) catch (Exception e)
@ -176,8 +176,8 @@ namespace Wabbajack.Common
if (line.Length <= 4 || line[3] != '%') continue; if (line.Length <= 4 || line[3] != '%') continue;
int.TryParse(line.Substring(0, 3), out var percent); int.TryParse(line.Substring(0, 3), out var percentInt);
Utils.Status($"Extracting {name} - {line.Trim()}", percent); Utils.Status($"Extracting {name} - {line.Trim()}", Percent.FactoryPutInRange(percentInt / 100d));
} }
} }
catch (Exception) catch (Exception)
@ -188,7 +188,7 @@ namespace Wabbajack.Common
if (p.ExitCode == 0) if (p.ExitCode == 0)
{ {
Utils.Status($"Extracting {name} - 100%", 100, alsoLog: true); Utils.Status($"Extracting {name} - 100%", Percent.One, alsoLog: true);
return; return;
} }
Utils.Error(new _7zipReturnError(p.ExitCode, source, dest, p.StandardOutput.ReadToEnd())); Utils.Error(new _7zipReturnError(p.ExitCode, source, dest, p.StandardOutput.ReadToEnd()));

View File

@ -44,9 +44,9 @@ namespace Wabbajack.Common
} }
if (_queue != null) if (_queue != null)
_queue.Report(_message, (int) (_inner.Position * 100 / _inner.Length)); _queue.Report(_message, Percent.FactoryPutInRange(_inner.Position, _inner.Length));
else else
Utils.Status(_message, (int) (_inner.Position * 100 / _inner.Length)); Utils.Status(_message, Percent.FactoryPutInRange(_inner.Position, _inner.Length));
} }
public override void Write(byte[] buffer, int offset, int count) public override void Write(byte[] buffer, int offset, int count)

View File

@ -15,8 +15,8 @@ namespace Wabbajack.Common
private Subject<int> _maxStep = new Subject<int>(); private Subject<int> _maxStep = new Subject<int>();
public IObservable<int> MaxStep => _maxStep; public IObservable<int> MaxStep => _maxStep;
private Subject<float> _progress = new Subject<float>(); private Subject<Percent> _progress = new Subject<Percent>();
public IObservable<float> Progress => _progress; public IObservable<Percent> Progress => _progress;
private int _internalCurrentStep; private int _internalCurrentStep;
private int _internalMaxStep; private int _internalMaxStep;
@ -37,24 +37,24 @@ namespace Wabbajack.Common
Utils.Log(name); Utils.Log(name);
_step.OnNext(_internalCurrentStep); _step.OnNext(_internalCurrentStep);
_stepName.OnNext(name); _stepName.OnNext(name);
MakeUpdate(0.0f); MakeUpdate(Percent.Zero);
} }
private float OverAllStatus(float sub_status) private Percent OverAllStatus(Percent sub_status)
{ {
var per_step = 1.0f / _internalMaxStep; var per_step = 1.0f / _internalMaxStep;
var macro = _internalCurrentStep * per_step; var macro = _internalCurrentStep * per_step;
return macro + (per_step * sub_status); return Percent.FactoryPutInRange(macro + (per_step * sub_status));
} }
public void MakeUpdate(float progress) public void MakeUpdate(Percent progress)
{ {
_progress.OnNext(OverAllStatus(progress)); _progress.OnNext(OverAllStatus(progress));
} }
public void MakeUpdate(int max, int curr) public void MakeUpdate(int max, int curr)
{ {
MakeUpdate((float)curr / (max == 0 ? 1 : max)); MakeUpdate(Percent.FactoryPutInRange(curr, max == 0 ? 1 : max));
} }
} }

View File

@ -0,0 +1,197 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Wabbajack.Common
{
public struct Percent : IComparable, IEquatable<Percent>
{
public static readonly Percent One = new Percent(1);
public static readonly Percent Zero = new Percent(0);
public readonly double Value;
public Percent Inverse => new Percent(1 - this.Value, check: false);
private Percent(double d, bool check)
{
if (!check || InRange(d))
{
this.Value = d;
}
else
{
throw new ArgumentException("Element out of range: " + d);
}
}
public Percent(double d)
: this(d, check: true)
{
}
public Percent(int i)
{
if (i < 0)
{
Value = 0;
}
else if (i > 100)
{
Value = 1;
}
else
{
Value = i / 100d;
}
}
public static bool InRange(double d)
{
return d >= 0 || d <= 1;
}
public static Percent operator +(Percent c1, Percent c2)
{
return new Percent(c1.Value + c2.Value);
}
public static Percent operator *(Percent c1, Percent c2)
{
return new Percent(c1.Value * c2.Value);
}
public static Percent operator -(Percent c1, Percent c2)
{
return new Percent(c1.Value - c2.Value);
}
public static Percent operator /(Percent c1, Percent c2)
{
return new Percent(c1.Value / c2.Value);
}
public static implicit operator double(Percent c1)
{
return c1.Value;
}
public static Percent FactoryPutInRange(double d)
{
if (double.IsNaN(d) || double.IsInfinity(d))
{
throw new ArgumentException();
}
if (d < 0)
{
return Percent.Zero;
}
else if (d > 1)
{
return Percent.One;
}
return new Percent(d, check: false);
}
public static Percent FactoryPutInRange(int cur, int max)
{
return FactoryPutInRange(1.0d * cur / max);
}
public static Percent FactoryPutInRange(long cur, long max)
{
return FactoryPutInRange(1.0d * cur / max);
}
public static Percent AverageFromPercents(params Percent[] ps)
{
double percent = 0;
foreach (var p in ps)
{
percent += p.Value;
}
return new Percent(percent / ps.Length, check: false);
}
public static Percent MultFromPercents(params Percent[] ps)
{
double percent = 1;
foreach (var p in ps)
{
percent *= p.Value;
}
return new Percent(percent, check: false);
}
public override bool Equals(object obj)
{
if (!(obj is Percent rhs)) return false;
return Equals(rhs);
}
public bool Equals(Percent other)
{
return this.Value == other.Value;
}
public override int GetHashCode()
{
return this.Value.GetHashCode();
}
public override string ToString()
{
return ToString(0);
}
public string ToString(string format)
{
return $"{(Value * 100).ToString(format)}%";
}
public string ToString(byte numDigits)
{
switch (numDigits)
{
case 0:
return ToString("n0");
case 1:
return ToString("n1");
case 2:
return ToString("n2");
case 3:
return ToString("n3");
case 4:
return ToString("n4");
case 5:
return ToString("n5");
case 6:
return ToString("n6");
default:
throw new NotImplementedException();
}
}
public int CompareTo(object obj)
{
if (obj is Percent rhs)
{
return this.Value.CompareTo(rhs.Value);
}
return 0;
}
public static bool TryParse(string str, out Percent p)
{
if (double.TryParse(str, out double d))
{
if (InRange(d))
{
p = new Percent(d);
return true;
}
}
p = default(Percent);
return false;
}
}
}

View File

@ -126,7 +126,7 @@ namespace Wabbajack.Common
} }
} }
public static void Status(string msg, int progress = 0, bool alsoLog = false) public static void Status(string msg, Percent progress, bool alsoLog = false)
{ {
WorkQueue.AsyncLocalCurrentQueue.Value?.Report(msg, progress); WorkQueue.AsyncLocalCurrentQueue.Value?.Report(msg, progress);
if (alsoLog) if (alsoLog)
@ -135,6 +135,11 @@ namespace Wabbajack.Common
} }
} }
public static void Status(string msg, bool alsoLog = false)
{
Status(msg, Percent.Zero, alsoLog: alsoLog);
}
public static void CatchAndLog(Action a) public static void CatchAndLog(Action a)
{ {
try try
@ -262,7 +267,7 @@ namespace Wabbajack.Common
if (read == 0) break; if (read == 0) break;
totalRead += read; totalRead += read;
ostream.Write(buffer, 0, read); ostream.Write(buffer, 0, read);
Status(status, (int) (totalRead * 100 / maxSize)); Status(status, Percent.FactoryPutInRange(totalRead, maxSize));
} }
} }
public static string xxHash(this byte[] data, bool nullOnIOError = false) public static string xxHash(this byte[] data, bool nullOnIOError = false)
@ -764,7 +769,7 @@ namespace Wabbajack.Common
var lst = coll.ToList(); var lst = coll.ToList();
lst.DoIndexed((idx, i) => lst.DoIndexed((idx, i) =>
{ {
Status(msg, idx * 100 / lst.Count); Status(msg, Percent.FactoryPutInRange(idx, lst.Count));
f(i); f(i);
}); });
} }

View File

@ -116,7 +116,7 @@ namespace Wabbajack.Common
{ {
while (true) while (true)
{ {
Report("Waiting", 0, false); Report("Waiting", Percent.Zero, false);
if (_shutdown.IsCancellationRequested) return; if (_shutdown.IsCancellationRequested) return;
@ -150,7 +150,7 @@ namespace Wabbajack.Common
{ {
Utils.Error($"Could not remove thread from workpool with CPU ID {cpuID}"); Utils.Error($"Could not remove thread from workpool with CPU ID {cpuID}");
} }
Report("Shutting down", 0, false); Report("Shutting down", Percent.Zero, false);
_cpuCountSubj.OnNext((_tasks.Count, DesiredNumWorkers)); _cpuCountSubj.OnNext((_tasks.Count, DesiredNumWorkers));
return; return;
} }
@ -165,13 +165,12 @@ namespace Wabbajack.Common
} }
} }
public void Report(string msg, int progress, bool isWorking = true) public void Report(string msg, Percent progress, bool isWorking = true)
{ {
_Status.OnNext( _Status.OnNext(
new CPUStatus new CPUStatus
{ {
Progress = progress, ProgressPercent = progress,
ProgressPercent = progress / 100f,
Msg = msg, Msg = msg,
ID = _cpuId.Value, ID = _cpuId.Value,
IsWorking = isWorking IsWorking = isWorking
@ -193,8 +192,7 @@ namespace Wabbajack.Common
public class CPUStatus public class CPUStatus
{ {
public int Progress { get; internal set; } public Percent ProgressPercent { get; internal set; }
public float ProgressPercent { get; internal set; }
public string Msg { get; internal set; } public string Msg { get; internal set; }
public int ID { get; internal set; } public int ID { get; internal set; }
public bool IsWorking { get; internal set; } public bool IsWorking { get; internal set; }

View File

@ -19,12 +19,12 @@ namespace Wabbajack.Lib
protected StatusUpdateTracker UpdateTracker { get; private set; } protected StatusUpdateTracker UpdateTracker { get; private set; }
private Subject<float> _percentCompleted { get; } = new Subject<float>(); private Subject<Percent> _percentCompleted { get; } = new Subject<Percent>();
/// <summary> /// <summary>
/// The current progress of the entire processing system on a scale of 0.0 to 1.0 /// The current progress of the entire processing system on a scale of 0.0 to 1.0
/// </summary> /// </summary>
public IObservable<float> PercentCompleted => _percentCompleted; public IObservable<Percent> PercentCompleted => _percentCompleted;
private Subject<string> _textStatus { get; } = new Subject<string>(); private Subject<string> _textStatus { get; } = new Subject<string>();
@ -51,7 +51,7 @@ namespace Wabbajack.Lib
// WorkQueue settings // WorkQueue settings
public BehaviorSubject<bool> ManualCoreLimit = new BehaviorSubject<bool>(true); public BehaviorSubject<bool> ManualCoreLimit = new BehaviorSubject<bool>(true);
public BehaviorSubject<byte> MaxCores = new BehaviorSubject<byte>(byte.MaxValue); public BehaviorSubject<byte> MaxCores = new BehaviorSubject<byte>(byte.MaxValue);
public BehaviorSubject<double> TargetUsagePercent = new BehaviorSubject<double>(1.0d); public BehaviorSubject<Percent> TargetUsagePercent = new BehaviorSubject<Percent>(Percent.One);
protected void ConfigureProcessor(int steps, IObservable<int> numThreads = null) protected void ConfigureProcessor(int steps, IObservable<int> numThreads = null)
{ {

View File

@ -54,7 +54,7 @@ namespace Wabbajack.Lib
public void Status(string msg) public void Status(string msg)
{ {
Queue.Report(msg, 0); Queue.Report(msg, Percent.Zero);
} }
public static void Error(string msg) public static void Error(string msg)

View File

@ -47,7 +47,7 @@ namespace Wabbajack.Lib
public void Status(string msg) public void Status(string msg)
{ {
Queue.Report(msg, 0); Queue.Report(msg, Percent.Zero);
} }
public void Error(string msg) public void Error(string msg)
@ -183,7 +183,7 @@ namespace Wabbajack.Lib
await vFiles.GroupBy(f => f.FromFile) await vFiles.GroupBy(f => f.FromFile)
.PDoIndexed(queue, (idx, group) => .PDoIndexed(queue, (idx, group) =>
{ {
Utils.Status("Installing files", idx * 100 / vFiles.Count); Utils.Status("Installing files", Percent.FactoryPutInRange(idx, vFiles.Count));
var firstDest = Path.Combine(OutputFolder, group.First().To); var firstDest = Path.Combine(OutputFolder, group.First().To);
CopyFile(group.Key.StagedPath, firstDest, true); CopyFile(group.Key.StagedPath, firstDest, true);

View File

@ -124,7 +124,7 @@ namespace Wabbajack.Lib.Downloaders
var secs = times.Download - times.CurrentTime; var secs = times.Download - times.CurrentTime;
for (int x = 0; x < secs; x++) for (int x = 0; x < secs; x++)
{ {
Utils.Status($"Waiting for {secs} at the request of {downloader.SiteName}", x * 100 / secs); Utils.Status($"Waiting for {secs} at the request of {downloader.SiteName}", Percent.FactoryPutInRange(x, secs));
await Task.Delay(1000); await Task.Delay(1000);
} }
Utils.Status("Retrying download"); Utils.Status("Retrying download");

View File

@ -133,7 +133,7 @@ namespace Wabbajack.Lib.Downloaders
var max_chunks = info.depot_list[0].file_list[0].chunk_count; var max_chunks = info.depot_list[0].file_list[0].chunk_count;
foreach (var chunk in info.depot_list[0].file_list[0].chunk_list.OrderBy(c => c.index)) foreach (var chunk in info.depot_list[0].file_list[0].chunk_list.OrderBy(c => c.index))
{ {
Utils.Status($"Downloading {a.Name}", chunk.index * 100 / max_chunks); Utils.Status($"Downloading {a.Name}", Percent.FactoryPutInRange(chunk.index, max_chunks));
var got = await client.GetAsync( var got = await client.GetAsync(
$"https://content.cdp.bethesda.net/{collected.CDPProductId}/{collected.CDPPropertiesId}/{chunk.sha}"); $"https://content.cdp.bethesda.net/{collected.CDPProductId}/{collected.CDPPropertiesId}/{chunk.sha}");
var data = await got.Content.ReadAsByteArrayAsync(); var data = await got.Content.ReadAsByteArrayAsync();

View File

@ -101,7 +101,7 @@ namespace Wabbajack.Lib.Downloaders
long totalRead = 0; long totalRead = 0;
var bufferSize = 1024 * 32; var bufferSize = 1024 * 32;
Utils.Status($"Starting Download {a?.Name ?? Url}", 0); Utils.Status($"Starting Download {a?.Name ?? Url}", Percent.Zero);
var response = await client.GetAsync(Url, HttpCompletionOption.ResponseHeadersRead); var response = await client.GetAsync(Url, HttpCompletionOption.ResponseHeadersRead);
TOP: TOP:
@ -179,7 +179,7 @@ TOP:
read_this_cycle += read; read_this_cycle += read;
if (read == 0) break; if (read == 0) break;
Utils.Status($"Downloading {a.Name}", (int)(totalRead * 100 / contentSize)); Utils.Status($"Downloading {a.Name}", Percent.FactoryPutInRange(totalRead, contentSize));
fs.Write(buffer, 0, read); fs.Write(buffer, 0, read);
totalRead += read; totalRead += read;

View File

@ -61,7 +61,7 @@ namespace Wabbajack.Lib.FileUploader
long sent = 0; long sent = 0;
using (var iqueue = new WorkQueue(MAX_CONNECTIONS)) using (var iqueue = new WorkQueue(MAX_CONNECTIONS))
{ {
iqueue.Report("Starting Upload", 1); iqueue.Report("Starting Upload", Percent.One);
await Blocks(fsize) await Blocks(fsize)
.PMap(iqueue, async block_idx => .PMap(iqueue, async block_idx =>
{ {

View File

@ -18,7 +18,7 @@ namespace Wabbajack.Lib
/// <summary> /// <summary>
/// The current progress of the entire processing system on a scale of 0.0 to 1.0 /// The current progress of the entire processing system on a scale of 0.0 to 1.0
/// </summary> /// </summary>
IObservable<float> PercentCompleted { get; } IObservable<Percent> PercentCompleted { get; }
/// <summary> /// <summary>
/// The current status of the processor as a text string /// The current status of the processor as a text string

View File

@ -20,6 +20,10 @@ namespace Wabbajack
new IntDownCastConverter(), new IntDownCastConverter(),
typeof(IBindingTypeConverter) typeof(IBindingTypeConverter)
); );
Locator.CurrentMutable.RegisterConstant(
new PercentToDoubleConverter(),
typeof(IBindingTypeConverter)
);
} }
} }
} }

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using Newtonsoft.Json;
using Wabbajack.Common;
namespace Wabbajack
{
public class PercentJsonConverter : JsonConverter<Percent>
{
public override Percent ReadJson(JsonReader reader, Type objectType, [AllowNull] Percent existingValue, bool hasExistingValue, JsonSerializer serializer)
{
double d = (double)reader.Value;
return Percent.FactoryPutInRange(d);
}
public override void WriteJson(JsonWriter writer, [AllowNull] Percent value, JsonSerializer serializer)
{
writer.WriteValue(value.Value);
}
}
}

View File

@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using ReactiveUI;
using Wabbajack.Common;
namespace Wabbajack
{
public class PercentToDoubleConverter : IBindingTypeConverter
{
public int GetAffinityForObjects(Type fromType, Type toType)
{
if (toType == typeof(double)) return 1;
if (toType == typeof(double?)) return 1;
if (toType == typeof(Percent)) return 1;
if (toType == typeof(Percent?)) return 1;
return 0;
}
public bool TryConvert(object from, Type toType, object conversionHint, out object result)
{
if (toType == typeof(double))
{
if (from is Percent p)
{
result = p.Value;
return true;
}
result = 0d;
return false;
}
if (toType == typeof(double?))
{
if (from is Percent p)
{
result = p.Value;
return true;
}
if (from == null)
{
result = default(double?);
return true;
}
result = default(double?);
return false;
}
if (toType == typeof(Percent))
{
if (from is double d)
{
result = Percent.FactoryPutInRange(d);
return true;
}
result = Percent.Zero;
return false;
}
if (toType == typeof(Percent?))
{
if (from is double d)
{
result = Percent.FactoryPutInRange(d);
return true;
}
if (from == null)
{
result = default(Percent?);
return true;
}
result = Percent.Zero;
return false;
}
result = null;
return false;
}
}
}

View File

@ -82,8 +82,8 @@ namespace Wabbajack
private byte _MaxCores = byte.MaxValue; private byte _MaxCores = byte.MaxValue;
public byte MaxCores { get => _MaxCores; set => this.RaiseAndSetIfChanged(ref _MaxCores, value); } public byte MaxCores { get => _MaxCores; set => this.RaiseAndSetIfChanged(ref _MaxCores, value); }
private double _TargetUsage = 1.0d; private Percent _TargetUsage = Percent.One;
public double TargetUsage { get => _TargetUsage; set => this.RaiseAndSetIfChanged(ref _TargetUsage, value); } public Percent TargetUsage { get => _TargetUsage; set => this.RaiseAndSetIfChanged(ref _TargetUsage, value); }
public void AttachToBatchProcessor(ABatchProcessor processor) public void AttachToBatchProcessor(ABatchProcessor processor)
{ {

View File

@ -65,6 +65,7 @@ namespace Wabbajack
.ToObservableChangeSet(x => x.ID) .ToObservableChangeSet(x => x.ID)
.Batch(TimeSpan.FromMilliseconds(50), RxApp.TaskpoolScheduler) .Batch(TimeSpan.FromMilliseconds(50), RxApp.TaskpoolScheduler)
.EnsureUniqueChanges() .EnsureUniqueChanges()
.ObserveOnGuiThread()
.TransformAndCache( .TransformAndCache(
onAdded: (key, cpu) => new CPUDisplayVM(cpu), onAdded: (key, cpu) => new CPUDisplayVM(cpu),
onUpdated: (change, vm) => vm.AbsorbStatus(change.Current)) onUpdated: (change, vm) => vm.AbsorbStatus(change.Current))
@ -72,7 +73,6 @@ namespace Wabbajack
.AutoRefresh(x => x.StartTime) .AutoRefresh(x => x.StartTime)
.Filter(i => i.IsWorking && i.ID != WorkQueue.UnassignedCpuId) .Filter(i => i.IsWorking && i.ID != WorkQueue.UnassignedCpuId)
.Sort(SortExpressionComparer<CPUDisplayVM>.Ascending(s => s.StartTime)) .Sort(SortExpressionComparer<CPUDisplayVM>.Ascending(s => s.StartTime))
.ObserveOnGuiThread()
.Bind(list) .Bind(list)
.Subscribe(); .Subscribe();
} }

View File

@ -20,7 +20,7 @@ namespace Wabbajack
[Reactive] [Reactive]
public string Msg { get; set; } public string Msg { get; set; }
[Reactive] [Reactive]
public float ProgressPercent { get; set; } public Percent ProgressPercent { get; set; }
public CPUDisplayVM() public CPUDisplayVM()
{ {

View File

@ -40,8 +40,8 @@ namespace Wabbajack
private readonly ObservableAsPropertyHelper<bool> _compiling; private readonly ObservableAsPropertyHelper<bool> _compiling;
public bool Compiling => _compiling.Value; public bool Compiling => _compiling.Value;
private readonly ObservableAsPropertyHelper<float> _percentCompleted; private readonly ObservableAsPropertyHelper<Percent> _percentCompleted;
public float PercentCompleted => _percentCompleted.Value; public Percent PercentCompleted => _percentCompleted.Value;
public ObservableCollectionExtended<CPUDisplayVM> StatusList { get; } = new ObservableCollectionExtended<CPUDisplayVM>(); public ObservableCollectionExtended<CPUDisplayVM> StatusList { get; } = new ObservableCollectionExtended<CPUDisplayVM>();
@ -169,9 +169,9 @@ namespace Wabbajack
{ {
if (compiler == null) if (compiler == null)
{ {
return Observable.Return<float>(completed != null ? 1f : 0f); return Observable.Return<Percent>(completed != null ? Percent.One : Percent.Zero);
} }
return compiler.PercentCompleted.StartWith(0); return compiler.PercentCompleted.StartWith(Percent.Zero);
}) })
.Switch() .Switch()
.Debounce(TimeSpan.FromMilliseconds(25), RxApp.MainThreadScheduler) .Debounce(TimeSpan.FromMilliseconds(25), RxApp.MainThreadScheduler)

View File

@ -68,8 +68,8 @@ namespace Wabbajack
private readonly ObservableAsPropertyHelper<string> _modListName; private readonly ObservableAsPropertyHelper<string> _modListName;
public string ModListName => _modListName.Value; public string ModListName => _modListName.Value;
private readonly ObservableAsPropertyHelper<float> _percentCompleted; private readonly ObservableAsPropertyHelper<Percent> _percentCompleted;
public float PercentCompleted => _percentCompleted.Value; public Percent PercentCompleted => _percentCompleted.Value;
public ObservableCollectionExtended<CPUDisplayVM> StatusList { get; } = new ObservableCollectionExtended<CPUDisplayVM>(); public ObservableCollectionExtended<CPUDisplayVM> StatusList { get; } = new ObservableCollectionExtended<CPUDisplayVM>();
public ObservableCollectionExtended<IStatusMessage> Log => MWVM.Log; public ObservableCollectionExtended<IStatusMessage> Log => MWVM.Log;
@ -238,9 +238,9 @@ namespace Wabbajack
{ {
if (installer == null) if (installer == null)
{ {
return Observable.Return<float>(completed != null ? 1f : 0f); return Observable.Return<Percent>(completed != null ? Percent.One : Percent.Zero);
} }
return installer.PercentCompleted.StartWith(0f); return installer.PercentCompleted.StartWith(Percent.Zero);
}) })
.Switch() .Switch()
.Debounce(TimeSpan.FromMilliseconds(25), RxApp.MainThreadScheduler) .Debounce(TimeSpan.FromMilliseconds(25), RxApp.MainThreadScheduler)

View File

@ -34,7 +34,7 @@ namespace Wabbajack
public string Location { get; } public string Location { get; }
[Reactive] [Reactive]
public double ProgressPercent { get; private set; } public Percent ProgressPercent { get; private set; }
[Reactive] [Reactive]
public bool IsBroken { get; private set; } public bool IsBroken { get; private set; }
@ -144,7 +144,7 @@ namespace Wabbajack
private async Task<bool> Download() private async Task<bool> Download()
{ {
ProgressPercent = 0d; ProgressPercent = Percent.Zero;
using (var queue = new WorkQueue(1)) using (var queue = new WorkQueue(1))
using (queue.Status.Select(i => i.ProgressPercent) using (queue.Status.Select(i => i.ProgressPercent)
.Subscribe(percent => ProgressPercent = percent)) .Subscribe(percent => ProgressPercent = percent))

View File

@ -0,0 +1,35 @@
<rxui:ReactiveUserControl
x:Class="Wabbajack.CpuLineView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Wabbajack"
xmlns:mahapps="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:rxui="http://reactiveui.net"
d:DesignHeight="65"
d:DesignWidth="400"
x:TypeArguments="local:CPUDisplayVM"
mc:Ignorable="d">
<Grid Background="{StaticResource WindowBackgroundBrush}">
<mahapps:MetroProgressBar
x:Name="BackgroundProgressBar"
Background="Transparent"
BorderThickness="0"
Foreground="{StaticResource DarkPrimaryVariantBrush}"
Maximum="1" />
<Grid Height="1" VerticalAlignment="Bottom">
<mahapps:MetroProgressBar
x:Name="ThinProgressBar"
Background="Transparent"
BorderThickness="0"
Foreground="{StaticResource DarkSecondaryBrush}"
Maximum="1" />
</Grid>
<TextBlock
x:Name="Text"
Margin="0,0,0,2"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap" />
</Grid>
</rxui:ReactiveUserControl>

View File

@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using ReactiveUI;
namespace Wabbajack
{
/// <summary>
/// Interaction logic for CpuLineView.xaml
/// </summary>
public partial class CpuLineView : ReactiveUserControl<CPUDisplayVM>
{
public CpuLineView()
{
InitializeComponent();
this.WhenActivated(dispose =>
{
this.WhenAny(x => x.ViewModel.ProgressPercent)
.Select(x => x.Value)
.BindToStrict(this, x => x.BackgroundProgressBar.Value)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.ProgressPercent)
.Select(x => x.Value)
.BindToStrict(this, x => x.BackgroundProgressBar.Opacity)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.ProgressPercent)
.Select(x => x.Value)
.BindToStrict(this, x => x.ThinProgressBar.Value)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.Msg)
.BindToStrict(this, x => x.Text.Text)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.Msg)
.BindToStrict(this, x => x.Text.ToolTip)
.DisposeWith(dispose);
});
}
}
}

View File

@ -4,14 +4,13 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Wabbajack" xmlns:local="clr-namespace:Wabbajack"
xmlns:mahapps="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="450" d:DesignHeight="450"
d:DesignWidth="800" d:DesignWidth="800"
x:TypeArguments="local:ICpuStatusVM" x:TypeArguments="local:ICpuStatusVM"
mc:Ignorable="d"> mc:Ignorable="d">
<Grid x:Name="ControlGrid" Background="Transparent"> <Grid x:Name="ControlGrid" Background="Transparent">
<Rectangle Fill="{StaticResource HeatedBorderBrush}" Opacity="{Binding ProgressPercent, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" /> <Rectangle x:Name="HeatedBorderRect" Fill="{StaticResource HeatedBorderBrush}" />
<Border BorderBrush="Transparent" BorderThickness="1" /> <Border BorderBrush="Transparent" BorderThickness="1" />
<Grid Margin="1" Background="{StaticResource DarkBackgroundBrush}"> <Grid Margin="1" Background="{StaticResource DarkBackgroundBrush}">
<Grid.RowDefinitions> <Grid.RowDefinitions>
@ -25,29 +24,7 @@
ScrollViewer.HorizontalScrollBarVisibility="Disabled"> ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemTemplate> <ListBox.ItemTemplate>
<DataTemplate> <DataTemplate>
<Grid Background="{StaticResource WindowBackgroundBrush}"> <local:CpuLineView ViewModel="{Binding}" />
<mahapps:MetroProgressBar
Background="Transparent"
BorderThickness="0"
Foreground="{StaticResource DarkPrimaryVariantBrush}"
Maximum="1"
Opacity="{Binding ProgressPercent, Mode=OneWay}"
Value="{Binding ProgressPercent, Mode=OneWay}" />
<Grid Height="1" VerticalAlignment="Bottom">
<mahapps:MetroProgressBar
Background="Transparent"
BorderThickness="0"
Foreground="{StaticResource DarkSecondaryBrush}"
Maximum="1"
Value="{Binding ProgressPercent, Mode=OneWay}" />
</Grid>
<TextBlock
Margin="0,0,0,2"
Text="{Binding Msg, Mode=OneWay}"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap"
ToolTip="{Binding Msg, Mode=OneWay}" />
</Grid>
</DataTemplate> </DataTemplate>
</ListBox.ItemTemplate> </ListBox.ItemTemplate>
</ListBox> </ListBox>

View File

@ -18,6 +18,7 @@ using ReactiveUI.Fody.Helpers;
using Wabbajack.Lib; using Wabbajack.Lib;
using System.Windows.Controls.Primitives; using System.Windows.Controls.Primitives;
using System.Reactive.Linq; using System.Reactive.Linq;
using Wabbajack.Common;
namespace Wabbajack namespace Wabbajack
{ {
@ -26,13 +27,13 @@ namespace Wabbajack
/// </summary> /// </summary>
public partial class CpuView : UserControlRx<ICpuStatusVM> public partial class CpuView : UserControlRx<ICpuStatusVM>
{ {
public double ProgressPercent public Percent ProgressPercent
{ {
get => (double)GetValue(ProgressPercentProperty); get => (Percent)GetValue(ProgressPercentProperty);
set => SetValue(ProgressPercentProperty, value); set => SetValue(ProgressPercentProperty, value);
} }
public static readonly DependencyProperty ProgressPercentProperty = DependencyProperty.Register(nameof(ProgressPercent), typeof(double), typeof(CpuView), public static readonly DependencyProperty ProgressPercentProperty = DependencyProperty.Register(nameof(ProgressPercent), typeof(Percent), typeof(CpuView),
new FrameworkPropertyMetadata(default(double))); new FrameworkPropertyMetadata(default(Percent), WireNotifyPropertyChanged));
public MainSettings SettingsHook public MainSettings SettingsHook
{ {
@ -55,28 +56,32 @@ namespace Wabbajack
this.WhenAny(x => x.SettingsHook.Performance.Manual) this.WhenAny(x => x.SettingsHook.Performance.Manual)
.StartWith(true), .StartWith(true),
resultSelector: (over, manual) => over && !manual) resultSelector: (over, manual) => over && !manual)
.Subscribe(showing => .Select(showing => showing ? Visibility.Visible : Visibility.Collapsed)
{ .BindToStrict(this, x => x.SettingsBar.Visibility)
SettingsBar.Visibility = showing ? Visibility.Visible : Visibility.Collapsed; .DisposeWith(disposable);
})
this.WhenAny(x => x.ViewModel.StatusList)
.BindToStrict(this, x => x.CpuListControl.ItemsSource)
.DisposeWith(disposable); .DisposeWith(disposable);
this.OneWayBindStrict(this.ViewModel, x => x.StatusList, x => x.CpuListControl.ItemsSource) this.Bind(this.ViewModel, x => x.MWVM.Settings.Performance.TargetUsage, x => x.TargetPercentageSlider.Value)
.DisposeWith(disposable); .DisposeWith(disposable);
this.BindStrict(this.ViewModel, x => x.MWVM.Settings.Performance.TargetUsage, x => x.TargetPercentageSlider.Value) this.WhenAny(x => x.ViewModel.MWVM.Settings.Performance.TargetUsage)
.DisposeWith(disposable); .Select(p => p.ToString(0))
.BindToStrict(this, x => x.PercentageText.Text)
this.OneWayBindStrict(this.ViewModel, x => x.MWVM.Settings.Performance.TargetUsage, x => x.PercentageText.Text, x => $"{x.ToString("f2")}%")
.DisposeWith(disposable); .DisposeWith(disposable);
this.WhenAny(x => x.ViewModel.CurrentCpuCount) this.WhenAny(x => x.ViewModel.CurrentCpuCount)
.DistinctUntilChanged() .DistinctUntilChanged()
.ObserveOnGuiThread() .Select(x => $"{x.CurrentCPUs} / {x.DesiredCPUs}")
.Subscribe(x => .BindToStrict(this, x => x.CpuCountText.Text)
{ .DisposeWith(disposable);
this.CpuCountText.Text = $"{x.CurrentCPUs} / {x.DesiredCPUs}";
}) // Progress
this.WhenAny(x => x.ProgressPercent)
.Select(p => p.Value)
.BindToStrict(this, x => x.HeatedBorderRect.Opacity)
.DisposeWith(disposable); .DisposeWith(disposable);
}); });
} }

View File

@ -1,4 +1,4 @@
<local:UserControlRx <local:UserControlRx
x:Class="Wabbajack.TopProgressView" x:Class="Wabbajack.TopProgressView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
@ -19,26 +19,17 @@
<RowDefinition Height="25" /> <RowDefinition Height="25" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Rectangle <Rectangle
x:Name="OverhangShadowRect"
Grid.Row="2" Grid.Row="2"
Height="25" Height="25"
VerticalAlignment="Top" VerticalAlignment="Top"
IsHitTestVisible="False" IsHitTestVisible="False">
Visibility="{Binding OverhangShadow, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Converter={StaticResource bool2VisibilityConverter}}">
<Rectangle.Fill> <Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="#AA000000" /> <GradientStop Offset="0" Color="#AA000000" />
<GradientStop Offset="1" Color="#00000000" /> <GradientStop Offset="1" Color="#00000000" />
</LinearGradientBrush> </LinearGradientBrush>
</Rectangle.Fill> </Rectangle.Fill>
<Rectangle.Style>
<Style TargetType="Rectangle">
<Style.Triggers>
<DataTrigger Binding="{Binding ShadowMargin, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" Value="True">
<Setter Property="Margin" Value="6,0" />
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle> </Rectangle>
<Rectangle Grid.Row="1" Fill="{StaticResource BackgroundBrush}" /> <Rectangle Grid.Row="1" Fill="{StaticResource BackgroundBrush}" />
<mahapps:MetroProgressBar <mahapps:MetroProgressBar
@ -51,8 +42,7 @@
Background="Transparent" Background="Transparent"
BorderBrush="Transparent" BorderBrush="Transparent"
Foreground="{StaticResource PrimaryVariantBrush}" Foreground="{StaticResource PrimaryVariantBrush}"
Maximum="1" Maximum="1">
Value="{Binding ProgressPercent, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}">
<mahapps:MetroProgressBar.Effect> <mahapps:MetroProgressBar.Effect>
<BlurEffect Radius="25" /> <BlurEffect Radius="25" />
</mahapps:MetroProgressBar.Effect> </mahapps:MetroProgressBar.Effect>
@ -69,9 +59,7 @@
Grid.ColumnSpan="4" Grid.ColumnSpan="4"
Background="#AA121212" Background="#AA121212"
BorderThickness="0" BorderThickness="0"
Maximum="1" Maximum="1">
Opacity="{Binding ProgressOpacityPercent, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
Value="{Binding ProgressPercent, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}">
<mahapps:MetroProgressBar.Foreground> <mahapps:MetroProgressBar.Foreground>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0"> <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Offset="0" Color="{StaticResource DarkerPrimaryVariant}" /> <GradientStop Offset="0" Color="{StaticResource DarkerPrimaryVariant}" />
@ -85,8 +73,7 @@
Grid.ColumnSpan="4" Grid.ColumnSpan="4"
Background="Transparent" Background="Transparent"
BorderThickness="0" BorderThickness="0"
Maximum="1" Maximum="1">
Value="{Binding ProgressPercent, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}">
<mahapps:MetroProgressBar.Foreground> <mahapps:MetroProgressBar.Foreground>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="#33000000" /> <GradientStop Offset="0" Color="#33000000" />
@ -95,6 +82,7 @@
</mahapps:MetroProgressBar.Foreground> </mahapps:MetroProgressBar.Foreground>
</mahapps:MetroProgressBar> </mahapps:MetroProgressBar>
<TextBlock <TextBlock
x:Name="StatePrefixText"
Grid.Column="0" Grid.Column="0"
Width="130" Width="130"
Margin="0,0,0,0" Margin="0,0,0,0"
@ -102,21 +90,19 @@
FontFamily="Lucida Sans" FontFamily="Lucida Sans"
FontWeight="Black" FontWeight="Black"
Foreground="{StaticResource ComplementaryBrush}" Foreground="{StaticResource ComplementaryBrush}"
Text="{Binding StatePrefixTitle, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" TextAlignment="Right" />
TextAlignment="Right"
Visibility="{Binding StatePrefixTitle, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Converter={StaticResource IsNotNullVisibilityConverter}}" />
<Rectangle <Rectangle
x:Name="PrefixSpacerRect"
Grid.Column="0" Grid.Column="0"
Width="50" Width="50" />
Visibility="{Binding StatePrefixTitle, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Converter={StaticResource IsNotNullVisibilityConverter}, ConverterParameter=False}" />
<TextBlock <TextBlock
x:Name="TitleText"
Grid.Column="1" Grid.Column="1"
Margin="15,0,0,0" Margin="15,0,0,0"
VerticalAlignment="Center" VerticalAlignment="Center"
FontFamily="Lucida Sans" FontFamily="Lucida Sans"
FontSize="25" FontSize="25"
FontWeight="Black" FontWeight="Black" />
Text="{Binding Title, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
<ContentControl Grid.Column="2" /> <ContentControl Grid.Column="2" />
</Grid> </Grid>
<mahapps:MetroProgressBar <mahapps:MetroProgressBar
@ -128,8 +114,7 @@
Background="Transparent" Background="Transparent"
BorderBrush="Transparent" BorderBrush="Transparent"
Foreground="{StaticResource SecondaryBrush}" Foreground="{StaticResource SecondaryBrush}"
Maximum="1" Maximum="1">
Value="{Binding ProgressPercent, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}">
<mahapps:MetroProgressBar.Effect> <mahapps:MetroProgressBar.Effect>
<BlurEffect Radius="8" /> <BlurEffect Radius="8" />
</mahapps:MetroProgressBar.Effect> </mahapps:MetroProgressBar.Effect>
@ -143,8 +128,7 @@
Background="Transparent" Background="Transparent"
BorderBrush="Transparent" BorderBrush="Transparent"
Foreground="{StaticResource SecondaryBrush}" Foreground="{StaticResource SecondaryBrush}"
Maximum="1" Maximum="1">
Value="{Binding ProgressPercent, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}">
<mahapps:MetroProgressBar.Effect> <mahapps:MetroProgressBar.Effect>
<BlurEffect Radius="15" /> <BlurEffect Radius="15" />
</mahapps:MetroProgressBar.Effect> </mahapps:MetroProgressBar.Effect>
@ -158,8 +142,7 @@
Background="Transparent" Background="Transparent"
BorderBrush="Transparent" BorderBrush="Transparent"
Foreground="{StaticResource SecondaryBrush}" Foreground="{StaticResource SecondaryBrush}"
Maximum="1" Maximum="1" />
Value="{Binding ProgressPercent, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
<mahapps:MetroProgressBar <mahapps:MetroProgressBar
x:Name="BottomProgressBarHighlight" x:Name="BottomProgressBarHighlight"
Grid.Row="1" Grid.Row="1"
@ -168,8 +151,7 @@
VerticalAlignment="Top" VerticalAlignment="Top"
Background="Transparent" Background="Transparent"
BorderBrush="Transparent" BorderBrush="Transparent"
Maximum="1" Maximum="1">
Value="{Binding ProgressPercent, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}">
<mahapps:MetroProgressBar.Foreground> <mahapps:MetroProgressBar.Foreground>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="#CCFFFFFF" /> <GradientStop Offset="0" Color="#CCFFFFFF" />

View File

@ -1,4 +1,4 @@
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using ReactiveUI; using ReactiveUI;
@ -28,7 +28,7 @@ namespace Wabbajack
set => SetValue(TitleProperty, value); set => SetValue(TitleProperty, value);
} }
public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(nameof(Title), typeof(string), typeof(TopProgressView), public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(nameof(Title), typeof(string), typeof(TopProgressView),
new FrameworkPropertyMetadata(default(string))); new FrameworkPropertyMetadata(default(string), WireNotifyPropertyChanged));
public string StatePrefixTitle public string StatePrefixTitle
{ {
@ -36,7 +36,7 @@ namespace Wabbajack
set => SetValue(StatePrefixTitleProperty, value); set => SetValue(StatePrefixTitleProperty, value);
} }
public static readonly DependencyProperty StatePrefixTitleProperty = DependencyProperty.Register(nameof(StatePrefixTitle), typeof(string), typeof(TopProgressView), public static readonly DependencyProperty StatePrefixTitleProperty = DependencyProperty.Register(nameof(StatePrefixTitle), typeof(string), typeof(TopProgressView),
new FrameworkPropertyMetadata(default(string))); new FrameworkPropertyMetadata(default(string), WireNotifyPropertyChanged));
public bool OverhangShadow public bool OverhangShadow
{ {
@ -44,7 +44,7 @@ namespace Wabbajack
set => SetValue(OverhangShadowProperty, value); set => SetValue(OverhangShadowProperty, value);
} }
public static readonly DependencyProperty OverhangShadowProperty = DependencyProperty.Register(nameof(OverhangShadow), typeof(bool), typeof(TopProgressView), public static readonly DependencyProperty OverhangShadowProperty = DependencyProperty.Register(nameof(OverhangShadow), typeof(bool), typeof(TopProgressView),
new FrameworkPropertyMetadata(true)); new FrameworkPropertyMetadata(true, WireNotifyPropertyChanged));
public bool ShadowMargin public bool ShadowMargin
{ {
@ -52,10 +52,7 @@ namespace Wabbajack
set => SetValue(ShadowMarginProperty, value); set => SetValue(ShadowMarginProperty, value);
} }
public static readonly DependencyProperty ShadowMarginProperty = DependencyProperty.Register(nameof(ShadowMargin), typeof(bool), typeof(TopProgressView), public static readonly DependencyProperty ShadowMarginProperty = DependencyProperty.Register(nameof(ShadowMargin), typeof(bool), typeof(TopProgressView),
new FrameworkPropertyMetadata(true)); new FrameworkPropertyMetadata(true, WireNotifyPropertyChanged));
[Reactive]
public double ProgressOpacityPercent { get; private set; }
public TopProgressView() public TopProgressView()
{ {
@ -63,11 +60,53 @@ namespace Wabbajack
this.WhenActivated(dispose => this.WhenActivated(dispose =>
{ {
this.WhenAny(x => x.ProgressPercent) this.WhenAny(x => x.ProgressPercent)
.Select(x => .Select(x => 0.3 + x * 0.7)
{ .BindToStrict(this, x => x.LargeProgressBar.Opacity)
return 0.3 + x * 0.7; .DisposeWith(dispose);
}) this.WhenAny(x => x.ProgressPercent)
.Subscribe(x => ProgressOpacityPercent = x) .BindToStrict(this, x => x.LargeProgressBar.Value)
.DisposeWith(dispose);
this.WhenAny(x => x.ProgressPercent)
.BindToStrict(this, x => x.BottomProgressBarDarkGlow.Value)
.DisposeWith(dispose);
this.WhenAny(x => x.ProgressPercent)
.BindToStrict(this, x => x.LargeProgressBarTopGlow.Value)
.DisposeWith(dispose);
this.WhenAny(x => x.ProgressPercent)
.BindToStrict(this, x => x.BottomProgressBarBrightGlow1.Value)
.DisposeWith(dispose);
this.WhenAny(x => x.ProgressPercent)
.BindToStrict(this, x => x.BottomProgressBarBrightGlow2.Value)
.DisposeWith(dispose);
this.WhenAny(x => x.ProgressPercent)
.BindToStrict(this, x => x.BottomProgressBar.Value)
.DisposeWith(dispose);
this.WhenAny(x => x.ProgressPercent)
.BindToStrict(this, x => x.BottomProgressBarHighlight.Value)
.DisposeWith(dispose);
this.WhenAny(x => x.OverhangShadow)
.Select(x => x ? Visibility.Visible : Visibility.Collapsed)
.BindToStrict(this, x => x.OverhangShadowRect.Visibility)
.DisposeWith(dispose);
this.WhenAny(x => x.ShadowMargin)
.DistinctUntilChanged()
.Select(x => x ? new Thickness(6, 0, 6, 0) : new Thickness(0))
.BindToStrict(this, x => x.OverhangShadowRect.Margin)
.DisposeWith(dispose);
this.WhenAny(x => x.Title)
.BindToStrict(this, x => x.TitleText.Text)
.DisposeWith(dispose);
this.WhenAny(x => x.StatePrefixTitle)
.Select(x => x == null ? Visibility.Visible : Visibility.Collapsed)
.BindToStrict(this, x => x.PrefixSpacerRect.Visibility)
.DisposeWith(dispose);
this.WhenAny(x => x.StatePrefixTitle)
.Select(x => x == null ? Visibility.Collapsed : Visibility.Visible)
.BindToStrict(this, x => x.StatePrefixText.Visibility)
.DisposeWith(dispose);
this.WhenAny(x => x.StatePrefixTitle)
.BindToStrict(this, x => x.StatePrefixText.Text)
.DisposeWith(dispose); .DisposeWith(dispose);
}); });
} }

View File

@ -1,8 +1,10 @@
using System; using System;
using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
using MahApps.Metro.Controls; using MahApps.Metro.Controls;
using Newtonsoft.Json;
using Wabbajack.Common; using Wabbajack.Common;
using Wabbajack.Lib.LibCefHelpers; using Wabbajack.Lib.LibCefHelpers;
using Application = System.Windows.Application; using Application = System.Windows.Application;
@ -48,6 +50,13 @@ namespace Wabbajack
}).FireAndForget(); }).FireAndForget();
// Load settings // Load settings
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
Converters = new List<JsonConverter>
{
new PercentJsonConverter()
}
};
if (CLIArguments.NoSettings || !MainSettings.TryLoadTypicalSettings(out var settings)) if (CLIArguments.NoSettings || !MainSettings.TryLoadTypicalSettings(out var settings))
{ {
_settings = new MainSettings(); _settings = new MainSettings();

View File

@ -15,6 +15,7 @@ using System.Windows.Media.Imaging;
using System.Windows.Navigation; using System.Windows.Navigation;
using System.Windows.Shapes; using System.Windows.Shapes;
using ReactiveUI; using ReactiveUI;
using Wabbajack.Common;
namespace Wabbajack namespace Wabbajack
{ {
@ -65,7 +66,7 @@ namespace Wabbajack
.DisposeWith(disposable); .DisposeWith(disposable);
this.BindStrict(this.ViewModel, x => x.TargetUsage, x => x.TargetUsageSpinner.Value) this.BindStrict(this.ViewModel, x => x.TargetUsage, x => x.TargetUsageSpinner.Value)
.DisposeWith(disposable); .DisposeWith(disposable);
this.BindStrict(this.ViewModel, x => x.TargetUsage, x => x.TargetUsageSlider.Value) this.Bind(this.ViewModel, x => x.TargetUsage, x => x.TargetUsageSlider.Value)
.DisposeWith(disposable); .DisposeWith(disposable);
}); });
} }