Skip to content

Commit

Permalink
Merge pull request #227 from sirdoombox/main
Browse files Browse the repository at this point in the history
Add the ability to transition between background shaders.
  • Loading branch information
kikipoulet authored Jun 25, 2024
2 parents 1147e48 + 6752de6 commit b8339c0
Show file tree
Hide file tree
Showing 16 changed files with 232 additions and 81 deletions.
2 changes: 1 addition & 1 deletion SukiUI.Demo/Assets/clouds.sksl
Original file line number Diff line number Diff line change
Expand Up @@ -106,5 +106,5 @@ half4 main( vec2 fragCoord ) {

vec3 result = mix(skycolour, clamp(skytint * skycolour + cloudcolour, 0.0, 1.0), clamp(f + c, 0.0, 1.0));

return vec4( result, 1.0 );
return vec4( result, iAlpha);
}
2 changes: 1 addition & 1 deletion SukiUI.Demo/Assets/space.sksl
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,5 @@ half4 main( vec2 fragCoord )
s+=stepsize;
}
v=mix(vec3(length(v)),v,saturation); //color adjust
return vec4(v*.01,1.);
return vec4(v*.01,iAlpha);
}
2 changes: 1 addition & 1 deletion SukiUI.Demo/Assets/weird.sksl
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,5 @@ half4 main(float2 FC) {
g += e = max(p.x,p.z) / 1e3 - .01;
o.rgb += .1/exp(cos(v*g*.1+n)+3.+1e4*e);
}
return o.xyz1;
return half4(o.xyz, iAlpha);
}
16 changes: 15 additions & 1 deletion SukiUI.Demo/Features/Theming/ThemingView.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="models:SukiColorTheme">

<RadioButton Width="50"
Height="50"
Classes="GigaChips"
Expand Down Expand Up @@ -112,6 +111,21 @@
TextWrapping="Wrap" />
</StackPanel>
</DockPanel>
<DockPanel>
<ToggleButton VerticalAlignment="Top"
Classes="Switch"
DockPanel.Dock="Right"
IsChecked="{Binding BackgroundTransitions}" />
<StackPanel HorizontalAlignment="Left">
<TextBlock FontSize="16"
FontWeight="DemiBold"
Text="Background Transitions" />
<TextBlock Margin="0,12,70,0"
Foreground="{DynamicResource SukiLowText}"
Text="Enable/disable the transitions for the background, these will fade between the active effects when changed."
TextWrapping="Wrap" />
</StackPanel>
</DockPanel>
<DockPanel>
<ComboBox DockPanel.Dock="Right"
ItemsSource="{Binding AvailableBackgroundStyles}"
Expand Down
15 changes: 10 additions & 5 deletions SukiUI.Demo/Features/Theming/ThemingViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ namespace SukiUI.Demo.Features.Theming;

public partial class ThemingViewModel : DemoPageBase
{
public Action<SukiBackgroundStyle> BackgroundStyleChanged { get; set; }
public Action<bool> BackgroundAnimationsChanged { get; set; }
public Action<string?> CustomBackgroundStyleChanged { get; set; }
public Action<SukiBackgroundStyle>? BackgroundStyleChanged { get; set; }
public Action<bool>? BackgroundAnimationsChanged { get; set; }
public Action<bool>? BackgroundTransitionsChanged { get; set; }
public Action<string?>? CustomBackgroundStyleChanged { get; set; }

public IAvaloniaReadOnlyList<SukiColorTheme> AvailableColors { get; }
public IAvaloniaReadOnlyList<SukiBackgroundStyle> AvailableBackgroundStyles { get; }
Expand All @@ -24,6 +25,7 @@ public partial class ThemingViewModel : DemoPageBase
[ObservableProperty] private bool _isLightTheme;
[ObservableProperty] private SukiBackgroundStyle _backgroundStyle ;
[ObservableProperty] private bool _backgroundAnimations;
[ObservableProperty] private bool _backgroundTransitions;

private string? _customShader = null;

Expand All @@ -36,7 +38,7 @@ public ThemingViewModel() : base("Theming", MaterialIconKind.PaletteOutline, -20
IsLightTheme = variant == ThemeVariant.Light;
_theme.OnColorThemeChanged += theme =>
{
// TODO: Implement a way to make the correct, might need to wrap the thing in a VM, this isn't ideal.
// TODO: Implement a way to make this correct, might need to wrap the thing in a VM, this isn't ideal.
};
}

Expand All @@ -52,7 +54,10 @@ partial void OnBackgroundStyleChanged(SukiBackgroundStyle value) =>

partial void OnBackgroundAnimationsChanged(bool value) =>
BackgroundAnimationsChanged?.Invoke(value);


partial void OnBackgroundTransitionsChanged(bool value) =>
BackgroundTransitionsChanged?.Invoke(value);

[RelayCommand]
private void TryCustomShader(string shaderType)
{
Expand Down
6 changes: 6 additions & 0 deletions SukiUI.Demo/SukiUIDemoView.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
BackgroundAnimationEnabled="{Binding AnimationsEnabled}"
BackgroundShaderFile="{Binding CustomShaderFile}"
BackgroundStyle="{Binding BackgroundStyle}"
BackgroundTransitionsEnabled="{Binding TransitionsEnabled}"
CanMinimize="{Binding !WindowLocked}"
CanMove="{Binding !WindowLocked}"
CanResize="{Binding !WindowLocked}"
Expand Down Expand Up @@ -84,6 +85,11 @@
<avalonia:MaterialIcon Kind="{Binding AnimationsEnabled, Converter={x:Static converters:BoolToIconConverters.Animation}}" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Command="{Binding ToggleTransitionsCommand}" Header="Transitions">
<MenuItem.Icon>
<avalonia:MaterialIcon Kind="{Binding TransitionsEnabled, Converter={x:Static converters:BoolToIconConverters.Animation}}" />
</MenuItem.Icon>
</MenuItem>
</MenuItem>
</suki:SukiWindow.MenuItems>
<suki:SukiSideMenu ItemsSource="{Binding DemoPages}" SelectedItem="{Binding ActivePage}">
Expand Down
17 changes: 17 additions & 0 deletions SukiUI.Demo/SukiUIDemoViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public partial class SukiUIDemoViewModel : ObservableObject
[ObservableProperty] private SukiBackgroundStyle _backgroundStyle = SukiBackgroundStyle.Gradient;
[ObservableProperty] private bool _animationsEnabled;
[ObservableProperty] private string? _customShaderFile;
[ObservableProperty] private bool _transitionsEnabled;
[ObservableProperty] private double _transitionTime;

private readonly SukiTheme _theme;
private readonly ThemingViewModel _theming;
Expand All @@ -43,6 +45,7 @@ public SukiUIDemoViewModel(IEnumerable<DemoPageBase> demoPages, PageNavigationSe
_theming.BackgroundStyleChanged += style => BackgroundStyle = style;
_theming.BackgroundAnimationsChanged += enabled => AnimationsEnabled = enabled;
_theming.CustomBackgroundStyleChanged += shader => CustomShaderFile = shader;
_theming.BackgroundTransitionsChanged += enabled => TransitionsEnabled = enabled;

BackgroundStyles = new AvaloniaList<SukiBackgroundStyle>(Enum.GetValues<SukiBackgroundStyle>());
_theme = SukiTheme.GetInstance();
Expand Down Expand Up @@ -81,6 +84,17 @@ private Task ToggleAnimations()
return SukiHost.ShowToast(title, content);
}

[RelayCommand]
private Task ToggleTransitions()
{
TransitionsEnabled = !TransitionsEnabled;
var title = TransitionsEnabled ? "Transitions Enabled" : "Transitions Disabled";
var content = TransitionsEnabled
? "Background transitions are now enabled."
: "Background transitions are now disabled.";
return SukiHost.ShowToast(title, content);
}

[RelayCommand]
private void ToggleBaseTheme() =>
_theme.SwitchBaseTheme();
Expand Down Expand Up @@ -118,4 +132,7 @@ partial void OnBackgroundStyleChanged(SukiBackgroundStyle value) =>

partial void OnAnimationsEnabledChanged(bool value) =>
_theming.BackgroundAnimations = value;

partial void OnTransitionsEnabledChanged(bool value) =>
_theming.BackgroundTransitions = value;
}
2 changes: 1 addition & 1 deletion SukiUI/Content/Shaders/cells.sksl
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,5 @@ vec4 main(vec2 fragCoord)

vec3 col = mix(iPrimary, iAccent, clamp(vorv.x * 2.2 + vorv.y, -1., 1.) * 0.5 + 0.5);
vec3 comp = blendOverlay(iBase, col);
return vec4(comp, 1.);
return vec4(comp, iAlpha);
}
2 changes: 1 addition & 1 deletion SukiUI/Content/Shaders/flat.sksl
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
vec4 main(vec2 fragCoord) {
return vec4(iBase, 1.0);
return vec4(iBase, iAlpha);
}
2 changes: 1 addition & 1 deletion SukiUI/Content/Shaders/gradient.sksl
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,5 @@ vec4 main(vec2 fragCoord) {
col = blendOverlayDark(iBase, finalComp);
}

return vec4(col, 1.0);
return vec4(col, iAlpha);
}
2 changes: 1 addition & 1 deletion SukiUI/Content/Shaders/waves.sksl
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,5 @@ vec4 main(vec2 fragCoord )
vec3 col = mix(iPrimary, iAccent, uv.x);
voronoi(uv * 4.0 - 1.0, col);
vec3 finalCol = blendOverlay(iBase, col);
return vec4(finalCol,1.0);
return vec4(finalCol,iAlpha);
}
67 changes: 51 additions & 16 deletions SukiUI/Controls/SukiBackground.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,12 @@ namespace SukiUI.Controls
{
public class SukiBackground : Control
{

public static readonly StyledProperty<SukiBackgroundStyle> StyleProperty =
AvaloniaProperty.Register<SukiWindow, SukiBackgroundStyle>(nameof(Style),
defaultValue: SukiBackgroundStyle.Gradient);

/// <summary>
/// Which of the default background styles to use.
/// Which of the default background styles to use - DEFAULT: Gradient
/// </summary>
public SukiBackgroundStyle Style
{
Expand Down Expand Up @@ -52,26 +51,64 @@ public string? ShaderCode
get => GetValue(ShaderCodeProperty);
set => SetValue(ShaderCodeProperty, value);
}

public static readonly StyledProperty<bool> AnimationEnabledProperty =
AvaloniaProperty.Register<SukiWindow, bool>(nameof(AnimationEnabled), defaultValue: false);


/// <summary>
/// Enables/disables animations - DEFAULT: False
/// </summary>
public bool AnimationEnabled
{
get => GetValue(AnimationEnabledProperty);
set => SetValue(AnimationEnabledProperty, value);
}

public static readonly StyledProperty<bool> TransitionsEnabledProperty =
AvaloniaProperty.Register<SukiBackground, bool>(nameof(TransitionsEnabled), defaultValue: false);

/// <summary>
/// Enables/disables transition animations when switching backgrounds - DEFAULT: False
/// </summary>
public bool TransitionsEnabled
{
get => GetValue(TransitionsEnabledProperty);
set => SetValue(TransitionsEnabledProperty, value);
}

public static readonly StyledProperty<double> TransitionTimeProperty =
AvaloniaProperty.Register<SukiBackground, double>(nameof(TransitionTime), defaultValue: 1.0);

/// <summary>
/// The amount of time in seconds the background transition will take - DEFAULT: 1.0
/// </summary>
public double TransitionTime
{
get => GetValue(TransitionTimeProperty);
set => SetValue(TransitionTimeProperty, value);
}

private readonly ShaderBackgroundDraw _draw;
private SukiBackgroundEffect _effect;
private readonly IDisposable _observables;

public SukiBackground()
{
IsHitTestVisible = false;
_draw = new ShaderBackgroundDraw(new Rect(0, 0, Bounds.Width, Bounds.Height));
var bgStyleObs = this.GetObservable(StyleProperty)
var transEnabledObs = this.GetObservable(TransitionsEnabledProperty)
.Do(enabled => _draw.TransitionsEnabled = enabled)
.Select(_ => Unit.Default);
var transTime = this.GetObservable(TransitionTimeProperty)
.Do(time => _draw.TransitionTime = time)
.Select(_ => Unit.Default)
.Merge(transEnabledObs);
var animObs = this.GetObservable(AnimationEnabledProperty)
.Do(enabled => _draw.AnimEnabled = enabled)
.Select(_ => Unit.Default)
.Merge(transTime);
var bgStyleObs = this.GetObservable(StyleProperty)
.Select(_ => Unit.Default)
.Merge(animObs);
var bgShaderFileObs = this.GetObservable(ShaderFileProperty)
.Select(_ => Unit.Default)
.Merge(bgStyleObs);
Expand All @@ -82,24 +119,22 @@ public SukiBackground()
.ObserveOn(new AvaloniaSynchronizationContext());
_observables = bgShaderCodeObs.Subscribe();
}

public override void Render(DrawingContext context)
{
_draw.Bounds = Bounds;
_draw.Effect = _effect;
_draw.AnimEnabled = AnimationEnabled;
context.Custom(_draw);
Dispatcher.UIThread.InvokeAsync(InvalidateVisual, DispatcherPriority.Background);
}

private void HandleBackgroundStyleChanges()
{
if (ShaderFile is not null)
_effect = SukiBackgroundEffect.FromEmbeddedResource(ShaderFile);
else if (ShaderCode is not null)
_effect = SukiBackgroundEffect.FromString(ShaderCode);
_draw.Effect = SukiBackgroundEffect.FromEmbeddedResource(ShaderFile);
else if (ShaderCode is not null)
_draw.Effect = SukiBackgroundEffect.FromString(ShaderCode);
else
_effect = SukiBackgroundEffect.FromEmbeddedResource(Style.ToString());
_draw.Effect = SukiBackgroundEffect.FromEmbeddedResource(Style.ToString());
}

protected override void OnUnloaded(RoutedEventArgs e)
Expand Down
4 changes: 3 additions & 1 deletion SukiUI/Controls/SukiWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
AnimationEnabled="{TemplateBinding BackgroundAnimationEnabled}"
ShaderCode="{TemplateBinding BackgroundShaderCode}"
ShaderFile="{TemplateBinding BackgroundShaderFile}"
Style="{TemplateBinding BackgroundStyle}" />
Style="{TemplateBinding BackgroundStyle}"
TransitionTime="{TemplateBinding BackgroundTransitionTime}"
TransitionsEnabled="{TemplateBinding BackgroundTransitionsEnabled}" />
<DockPanel LastChildFill="True">
<Panel DockPanel.Dock="Top">
<Panel.Styles>
Expand Down
37 changes: 25 additions & 12 deletions SukiUI/Controls/SukiWindow.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,8 @@ public bool BackgroundAnimationEnabled
AvaloniaProperty.Register<SukiWindow, SukiBackgroundStyle>(nameof(BackgroundStyle),
defaultValue: SukiBackgroundStyle.Gradient);

/// <summary>
/// Which of the default background styles to use.
/// </summary>

/// <inheritdoc cref="SukiBackground.Style"/>
public SukiBackgroundStyle BackgroundStyle
{
get => GetValue(BackgroundStyleProperty);
Expand All @@ -128,10 +127,7 @@ public SukiBackgroundStyle BackgroundStyle
public static readonly StyledProperty<string?> BackgroundShaderFileProperty =
AvaloniaProperty.Register<SukiWindow, string?>(nameof(BackgroundShaderFile));

/// <summary>
/// Specify a filename of an EMBEDDED RESOURCE file of type `.SkSL` with or without extension and it will be loaded and displayed.
/// This takes priority over the <see cref="BackgroundShaderCode"/> property, which in turns takes priority over <see cref="BackgroundStyle"/>.
/// </summary>
/// <inheritdoc cref="SukiBackground.ShaderFile"/>
public string? BackgroundShaderFile
{
get => GetValue(BackgroundShaderFileProperty);
Expand All @@ -141,23 +137,40 @@ public string? BackgroundShaderFile
public static readonly StyledProperty<string?> BackgroundShaderCodeProperty =
AvaloniaProperty.Register<SukiWindow, string?>(nameof(BackgroundShaderCode));

/// <summary>
/// Specify the shader code to use directly, simpler if you don't want to create an .SkSL file or want to generate the shader effect at runtime in some way.
/// This takes priority over the <see cref="BackgroundStyle"/> property, but is second in priority to <see cref="BackgroundShaderFile"/> if it is set.
/// </summary>

/// <inheritdoc cref="SukiBackground.ShaderCode"/>
public string? BackgroundShaderCode
{
get => GetValue(BackgroundShaderCodeProperty);
set => SetValue(BackgroundShaderCodeProperty, value);
}

public static readonly StyledProperty<bool> BackgroundTransitionsEnabledProperty =
AvaloniaProperty.Register<SukiBackground, bool>(nameof(BackgroundTransitionsEnabled), defaultValue: false);

/// <inheritdoc cref="SukiBackground.TransitionsEnabled"/>
public bool BackgroundTransitionsEnabled
{
get => GetValue(BackgroundTransitionsEnabledProperty);
set => SetValue(BackgroundTransitionsEnabledProperty, value);
}

public static readonly StyledProperty<double> BackgroundTransitionTimeProperty =
AvaloniaProperty.Register<SukiBackground, double>(nameof(BackgroundTransitionTime), defaultValue: 1.0);

/// <inheritdoc cref="SukiBackground.TransitionTime"/>
public double BackgroundTransitionTime
{
get => GetValue(BackgroundTransitionTimeProperty);
set => SetValue(BackgroundTransitionTimeProperty, value);
}

public SukiWindow()
{
MenuItems = new AvaloniaList<MenuItem>();
}

private IDisposable? _subscriptionDisposables;
private SukiBackground _background;

protected override void OnLoaded(RoutedEventArgs e)
{
Expand Down
Loading

0 comments on commit b8339c0

Please sign in to comment.