Skip to content

Commit b7b9c11

Browse files
authored
Merge pull request #402 from ionite34/fixes
2 parents 0f4baaa + 5f15800 commit b7b9c11

File tree

11 files changed

+170
-5
lines changed

11 files changed

+170
-5
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2
1919
- Addons usually affect guidance like ControlNet, T2I, FreeU, and other addons to come. They apply to the individual sampler, so you can mix and match different ControlNets for Base and Hires Fix, or use the current output from a previous sampler as ControlNet guidance image for HighRes passes.
2020
- Added SD Turbo Scheduler
2121
- Added display names for new samplers ("Heun++ 2", "DDPM", "LCM")
22+
- Added Ctrl+Enter as a shortcut for the Generate Image button
2223
#### Accounts Settings Subpage
2324
- Lykos Account sign-up and login - currently for Patreon OAuth connections but GitHub requests caching and settings sync are planned
2425
- Supporters can now connect your Patreon accounts, then head to the Updates page to choose to receive auto-updates from the Dev or Preview channels
@@ -71,6 +72,7 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2
7172
- InvokeAI model links for T2I/IpAdapters now point to the correct folders
7273
- Added extra checks to help prevent settings resetting in certain scenarios
7374
- Fixed Refiner model enabled state not saving to Inference project files
75+
- Fixed NullReference error labels when clearing the Inference batch size settings, now shows improved message with minimum and maximum value constraints
7476

7577
## v2.7.0-pre.4
7678
### Added

StabilityMatrix.Avalonia/Controls/Inference/BatchSizeCard.axaml

+5-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
xmlns:icons="clr-namespace:Projektanker.Icons.Avalonia;assembly=Projektanker.Icons.Avalonia"
77
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
88
xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages"
9+
xmlns:converters="clr-namespace:StabilityMatrix.Avalonia.Converters"
910
x:DataType="vmInference:BatchSizeCardViewModel">
1011

1112
<Design.PreviewWith>
@@ -19,7 +20,7 @@
1920
</Design.PreviewWith>
2021

2122
<Style Selector="controls|BatchSizeCard">
22-
<!-- Set Defaults -->
23+
<Setter Property="Focusable" Value="True"/>
2324
<Setter Property="ContextFlyout">
2425
<ui:FAMenuFlyout Placement="BottomEdgeAlignedLeft">
2526
<ui:ToggleMenuFlyoutItem
@@ -48,7 +49,7 @@
4849
Minimum="1"
4950
Increment="1"
5051
ParsingNumberStyle="Integer"
51-
Value="{Binding BatchSize}"
52+
Value="{Binding BatchSize, Converter={x:Static converters:NullableDefaultNumericConverters.IntToDecimal}}"
5253
ClipValueToMinMax="True"/>
5354
</StackPanel>
5455

@@ -71,7 +72,7 @@
7172
Minimum="1"
7273
Increment="1"
7374
ParsingNumberStyle="Integer"
74-
Value="{Binding BatchCount}"
75+
Value="{Binding BatchCount, Converter={x:Static converters:NullableDefaultNumericConverters.IntToDecimal}}"
7576
ClipValueToMinMax="True"/>
7677
</StackPanel>
7778

@@ -99,7 +100,7 @@
99100
Maximum="{Binding BatchSize}"
100101
Increment="1"
101102
ParsingNumberStyle="Integer"
102-
Value="{Binding BatchIndex}"
103+
Value="{Binding BatchIndex, Converter={x:Static converters:NullableDefaultNumericConverters.IntToDecimal}}"
103104
ClipValueToMinMax="True"/>
104105
</StackPanel>
105106

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
using System;
2+
using System.ComponentModel;
3+
using System.Diagnostics.CodeAnalysis;
4+
using System.Globalization;
5+
using System.Numerics;
6+
using Avalonia.Data.Converters;
7+
8+
namespace StabilityMatrix.Avalonia.Converters;
9+
10+
/// <summary>
11+
/// Converts a possibly boxed nullable value type to its default value
12+
/// </summary>
13+
public class NullableDefaultNumericConverter<TSource, TTarget> : IValueConverter
14+
where TSource : unmanaged, INumber<TSource>
15+
where TTarget : unmanaged, INumber<TTarget>
16+
{
17+
public ReturnBehavior NanHandling { get; set; } = ReturnBehavior.DefaultValue;
18+
19+
/// <summary>
20+
/// Unboxes a nullable value type
21+
/// </summary>
22+
private TSource Unbox(TTarget? value)
23+
{
24+
if (!value.HasValue)
25+
{
26+
return default;
27+
}
28+
29+
if (TTarget.IsNaN(value.Value))
30+
{
31+
return NanHandling switch
32+
{
33+
ReturnBehavior.DefaultValue => default,
34+
ReturnBehavior.Throw => throw new InvalidCastException("Cannot convert NaN to a numeric type"),
35+
_
36+
=> throw new InvalidEnumArgumentException(
37+
nameof(NanHandling),
38+
(int)NanHandling,
39+
typeof(ReturnBehavior)
40+
)
41+
};
42+
}
43+
44+
return (TSource)System.Convert.ChangeType(value.Value, typeof(TSource));
45+
}
46+
47+
/// <summary>
48+
/// Convert a value type to a nullable value type
49+
/// </summary>
50+
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
51+
{
52+
if (targetType != typeof(TTarget?) && !targetType.IsAssignableTo(typeof(TTarget)))
53+
{
54+
// ReSharper disable once LocalizableElement
55+
throw new ArgumentException(
56+
$"Convert Target type {targetType.Name} must be assignable to {typeof(TTarget).Name}"
57+
);
58+
}
59+
60+
return (TTarget?)System.Convert.ChangeType(value, typeof(TTarget));
61+
}
62+
63+
/// <summary>
64+
/// Convert a nullable value type to a value type
65+
/// </summary>
66+
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
67+
{
68+
if (!targetType.IsAssignableTo(typeof(TSource)))
69+
{
70+
// ReSharper disable once LocalizableElement
71+
throw new ArgumentException(
72+
$"ConvertBack Target type {targetType.Name} must be assignable to {typeof(TSource).Name}"
73+
);
74+
}
75+
76+
return Unbox((TTarget?)value);
77+
}
78+
79+
public enum ReturnBehavior
80+
{
81+
DefaultValue,
82+
Throw
83+
}
84+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace StabilityMatrix.Avalonia.Converters;
2+
3+
public static class NullableDefaultNumericConverters
4+
{
5+
public static readonly NullableDefaultNumericConverter<int, decimal> IntToDecimal = new();
6+
}

StabilityMatrix.Avalonia/Models/AppArgs.cs

+6
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ public class AppArgs
5757
[Option("disable-gpu-rendering", HelpText = "Disable hardware acceleration / GPU rendering")]
5858
public bool DisableGpuRendering { get; set; }
5959

60+
/// <summary>
61+
/// Flag to use OpenGL rendering
62+
/// </summary>
63+
[Option("opengl", HelpText = "Prefer OpenGL rendering")]
64+
public bool UseOpenGlRendering { get; set; }
65+
6066
/// <summary>
6167
/// Override global app home directory
6268
/// Defaults to (%APPDATA%|~/.config)/StabilityMatrix

StabilityMatrix.Avalonia/Program.cs

+7
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,13 @@ public static AppBuilder BuildAvaloniaApp()
144144

145145
var app = AppBuilder.Configure<App>().UsePlatformDetect().WithInterFont().LogToTrace();
146146

147+
if (Args.UseOpenGlRendering)
148+
{
149+
app = app.With(
150+
new Win32PlatformOptions { RenderingMode = [Win32RenderingMode.Wgl, Win32RenderingMode.Software] }
151+
);
152+
}
153+
147154
if (Args.DisableGpuRendering)
148155
{
149156
app = app.With(new Win32PlatformOptions { RenderingMode = new[] { Win32RenderingMode.Software } })

StabilityMatrix.Avalonia/ViewModels/Inference/BatchSizeCardViewModel.cs

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using CommunityToolkit.Mvvm.ComponentModel;
1+
using System.ComponentModel.DataAnnotations;
2+
using CommunityToolkit.Mvvm.ComponentModel;
23
using StabilityMatrix.Avalonia.Controls;
34
using StabilityMatrix.Avalonia.Models.Inference;
45
using StabilityMatrix.Avalonia.ViewModels.Base;
@@ -12,16 +13,24 @@ namespace StabilityMatrix.Avalonia.ViewModels.Inference;
1213
[Transient]
1314
public partial class BatchSizeCardViewModel : LoadableViewModelBase, IComfyStep
1415
{
16+
[NotifyDataErrorInfo]
1517
[ObservableProperty]
18+
[Range(1, 1024)]
1619
private int batchSize = 1;
1720

21+
[NotifyDataErrorInfo]
1822
[ObservableProperty]
23+
[Range(1, int.MaxValue)]
1924
private int batchCount = 1;
2025

26+
[NotifyDataErrorInfo]
2127
[ObservableProperty]
28+
[Required]
2229
private bool isBatchIndexEnabled;
2330

31+
[NotifyDataErrorInfo]
2432
[ObservableProperty]
33+
[Range(1, 1024)]
2534
private int batchIndex = 1;
2635

2736
/// <summary>

StabilityMatrix.Avalonia/Views/Inference/InferenceImageToImageView.axaml

+2
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@
149149
Width="130"
150150
HorizontalAlignment="Stretch"
151151
Classes="accent"
152+
ToolTip.Tip="{Binding $self.HotKey}"
153+
HotKey="Ctrl+Enter"
152154
Command="{Binding GenerateImageCommand}"
153155
CommandParameter="{x:Static modelsInference:GenerateFlags.None}"
154156
IsVisible="{Binding !GenerateImageCommand.CanBeCanceled}">

StabilityMatrix.Avalonia/Views/Inference/InferenceImageUpscaleView.axaml

+2
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@
9898
Width="130"
9999
HorizontalAlignment="Stretch"
100100
Classes="accent"
101+
HotKey="Ctrl+Enter"
102+
ToolTip.Tip="{Binding $self.HotKey}"
101103
Command="{Binding GenerateImageCommand}"
102104
CommandParameter="{x:Static modelsInference:GenerateFlags.None}"
103105
IsVisible="{Binding !GenerateImageCommand.CanBeCanceled}">

StabilityMatrix.Avalonia/Views/Inference/InferenceTextToImageView.axaml

+2
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@
112112
HorizontalAlignment="Stretch"
113113
Classes="accent"
114114
Command="{Binding GenerateImageCommand}"
115+
ToolTip.Tip="{Binding $self.HotKey}"
116+
HotKey="Ctrl+Enter"
115117
CommandParameter="{x:Static modelsInference:GenerateFlags.None}"
116118
IsVisible="{Binding !GenerateImageCommand.CanBeCanceled}">
117119
<Panel>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using System.Globalization;
2+
using StabilityMatrix.Avalonia.Converters;
3+
4+
namespace StabilityMatrix.Tests.Avalonia.Converters;
5+
6+
[TestClass]
7+
public class NullableDefaultNumericConverterTests
8+
{
9+
[TestMethod]
10+
public void Convert_IntToDecimal_ValueReturnsNullable()
11+
{
12+
const int value = 123;
13+
14+
var converter = NullableDefaultNumericConverters.IntToDecimal;
15+
16+
var result = converter.Convert(value, typeof(decimal?), null, CultureInfo.InvariantCulture);
17+
18+
Assert.AreEqual((decimal?)123, result);
19+
}
20+
21+
[TestMethod]
22+
public void ConvertBack_IntToDecimal_NullableReturnsDefault()
23+
{
24+
decimal? value = null;
25+
26+
var converter = NullableDefaultNumericConverters.IntToDecimal;
27+
28+
var result = converter.ConvertBack(value, typeof(int), null, CultureInfo.InvariantCulture);
29+
30+
Assert.AreEqual(0, result);
31+
}
32+
33+
[TestMethod]
34+
public void ConvertBack_IntToDouble_NanReturnsDefault()
35+
{
36+
const double value = double.NaN;
37+
38+
var converter = new NullableDefaultNumericConverter<int, double>();
39+
40+
var result = converter.ConvertBack(value, typeof(int), null, CultureInfo.InvariantCulture);
41+
42+
Assert.AreEqual(0, result);
43+
}
44+
}

0 commit comments

Comments
 (0)