Skip to content

Commit 77fb5f6

Browse files
committed
Feature: Shrinker.Avalonia - GLSL input can now be manually edited.
1 parent 0c5ad4d commit 77fb5f6

File tree

8 files changed

+177
-17
lines changed

8 files changed

+177
-17
lines changed

ShaderShrinker/Shrinker.Avalonia/Commands/FileOpenCommand.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
using System.Linq;
1515
using Avalonia;
1616
using Avalonia.Controls;
17-
using Avalonia.Controls.ApplicationLifetimes;
1817
using Avalonia.Platform.Storage;
18+
using Shrinker.Avalonia.Extensions;
1919

2020
namespace Shrinker.Avalonia.Commands;
2121

@@ -36,12 +36,12 @@ public FileOpenCommand(string title, string filterName, string[] filterExtension
3636

3737
public override async void Execute(object parameter)
3838
{
39-
if (Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop)
39+
if (Application.Current?.GetMainWindow() == null)
4040
return; // Cannot find the main application window.
4141

4242
var files =
4343
await TopLevel
44-
.GetTopLevel(desktop.MainWindow)
44+
.GetTopLevel(Application.Current?.GetMainWindow())
4545
.StorageProvider
4646
.OpenFilePickerAsync(
4747
new FilePickerOpenOptions

ShaderShrinker/Shrinker.Avalonia/Commands/FileSaveCommand.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
using System.Linq;
1515
using Avalonia;
1616
using Avalonia.Controls;
17-
using Avalonia.Controls.ApplicationLifetimes;
1817
using Avalonia.Platform.Storage;
18+
using Shrinker.Avalonia.Extensions;
1919

2020
namespace Shrinker.Avalonia.Commands;
2121

@@ -43,12 +43,12 @@ public override bool CanExecute(object parameter) =>
4343

4444
public override async void Execute(object parameter)
4545
{
46-
if (Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop)
46+
if (Application.Current?.GetMainWindow() == null)
4747
return; // Cannot find the main application window.
4848

4949
var selectedFile =
5050
await TopLevel
51-
.GetTopLevel(desktop.MainWindow)
51+
.GetTopLevel(Application.Current?.GetMainWindow())
5252
.StorageProvider
5353
.SaveFilePickerAsync(
5454
new FilePickerSaveOptions
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// -----------------------------------------------------------------------
2+
// <copyright file="ApplicationExtensions.cs" company="Dean Edis">
3+
// Copyright (c) 2023 Dean Edis. All rights reserved.
4+
// </copyright>
5+
// <summary>
6+
// This example is provided on an "as is" basis and without warranty of any kind.
7+
// Dean Edis. does not warrant or make any representations regarding the use or
8+
// results of use of this example.
9+
// </summary>
10+
// -----------------------------------------------------------------------
11+
12+
using Avalonia;
13+
using Avalonia.Controls;
14+
using Avalonia.Controls.ApplicationLifetimes;
15+
16+
namespace Shrinker.Avalonia.Extensions;
17+
18+
public static class ApplicationExtensions
19+
{
20+
public static Window GetMainWindow(this Application app) =>
21+
(app?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow;
22+
}

ShaderShrinker/Shrinker.Avalonia/ViewModels/AppViewModel.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111

1212
using System.Windows.Input;
1313
using Avalonia;
14-
using Avalonia.Controls.ApplicationLifetimes;
1514
using ReactiveUI;
1615
using Shrinker.Avalonia.Commands;
16+
using Shrinker.Avalonia.Extensions;
1717
using Shrinker.Avalonia.Views;
1818

1919
namespace Shrinker.Avalonia.ViewModels;
@@ -33,8 +33,7 @@ public AppViewModel()
3333
var dialog = new AboutDialog();
3434
dialog.Opened += (_, _) => isOpen = true;
3535
dialog.Closed += (_, _) => isOpen = false;
36-
var mainWindow = (Application.Current?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow;
37-
dialog.ShowDialog(mainWindow);
36+
dialog.ShowDialog(Application.Current?.GetMainWindow());
3837
});
3938
}
4039
}

ShaderShrinker/Shrinker.Avalonia/ViewModels/MainWindowViewModel.cs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,18 @@
55
using System.Linq;
66
using System.Threading.Tasks;
77
using System.Windows.Input;
8+
using Avalonia;
89
using Avalonia.Threading;
910
using AvaloniaEdit.Utils;
1011
using DialogHostAvalonia;
1112
using Material.Styles.Controls;
1213
using Material.Styles.Models;
1314
using ReactiveUI;
1415
using Shrinker.Avalonia.Commands;
16+
using Shrinker.Avalonia.Extensions;
1517
using Shrinker.Avalonia.Models;
1618
using Shrinker.Avalonia.Shadertoy;
19+
using Shrinker.Avalonia.Views;
1720
using Shrinker.Lexer;
1821
using Shrinker.Parser;
1922
using TextCopy;
@@ -26,6 +29,7 @@ public class MainWindowViewModel : ReactiveObject, IDisposable
2629
private ICommand m_importGlslFileCommand;
2730
private CommandBase m_importGlslShadertoyCommand;
2831
private CommandBase m_copyLeftCommand;
32+
private CommandBase m_editCodeCommand;
2933
private string m_shadertoyId;
3034
private CommandBase m_shrinkCommand;
3135
private CommandBase m_exportGlslClipboardCommand;
@@ -98,6 +102,7 @@ public ICommand ExportGlslFileCommand
98102
}
99103

100104
public ICommand CopyLeftCommand => m_copyLeftCommand ??= new RelayCommand(_ => ImportGlslFromRhs(), () => Diffs.HasRightContent());
105+
public ICommand EditCodeCommand => m_editCodeCommand ??= new RelayCommand(_ => EditGlsl(), () => !IsInstructionGlsl);
101106

102107
public string ShadertoyId
103108
{
@@ -137,12 +142,18 @@ public MainWindowViewModel()
137142
m_exportGlslClipboardCommand?.RaiseCanExecuteChanged();
138143
m_exportGlslFileCommand?.RaiseCanExecuteChanged();
139144
m_copyLeftCommand?.RaiseCanExecuteChanged();
145+
m_editCodeCommand?.RaiseCanExecuteChanged();
140146
};
141147
Hints.CollectionChanged += (_, _) =>
142148
{
143149
this.RaisePropertyChanged(nameof(HintCount));
144150
this.RaisePropertyChanged(nameof(HasHints));
145151
};
152+
PropertyChanged += (_, args) =>
153+
{
154+
if (args.PropertyName == nameof(IsInstructionGlsl))
155+
m_editCodeCommand?.RaiseCanExecuteChanged();
156+
};
146157
}
147158

148159
public bool IsInstructionGlsl
@@ -159,11 +170,8 @@ private void ImportGlslFromFile(FileInfo file)
159170
ImportGlslFromString(File.ReadAllText(file.FullName));
160171
}
161172

162-
private void ImportGlslFromRhs()
163-
{
164-
var glsl = Diffs.GetAllRightText().WithAppMessage();
165-
ImportGlslFromString(glsl);
166-
}
173+
private void ImportGlslFromRhs() =>
174+
ImportGlslFromString(Diffs.GetAllRightText());
167175

168176
private async void ImportGlslFromShadertoy(object o)
169177
{
@@ -270,6 +278,13 @@ private void ExportGlslToFile(FileInfo targetFile)
270278
writer.Write(IsOutputGlsl ? glsl : glsl.ToCCode());
271279
}
272280

281+
private async void EditGlsl()
282+
{
283+
var glsl = Diffs.GetAllLeftText();
284+
var editor = new CodeEditor { Glsl = glsl, Accept = ImportGlslFromString };
285+
await editor.ShowDialog(Application.Current?.GetMainWindow());
286+
}
287+
273288
public int OriginalSize
274289
{
275290
get => m_originalSize;
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<Window xmlns="https://github.com/avaloniaui"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
4+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
5+
xmlns:AvaloniaEdit="https://github.com/avaloniaui/avaloniaedit"
6+
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
7+
MinWidth="600" MinHeight="400"
8+
x:Class="Shrinker.Avalonia.Views.CodeEditor"
9+
WindowStartupLocation="CenterOwner"
10+
Title="Code Editor">
11+
<Window.Styles>
12+
<Style Selector="Button">
13+
<Setter Property="Foreground" Value="White" />
14+
<Setter Property="Padding" Value="16,6" />
15+
<Setter Property="Margin" Value="4,8" />
16+
</Style>
17+
</Window.Styles>
18+
19+
<Grid RowDefinitions="*,Auto">
20+
<Border BorderThickness="1"
21+
BorderBrush="{DynamicResource MaterialPrimaryLightBrush}"
22+
Margin="8,8,8,0" Padding="8">
23+
<AvaloniaEdit:TextEditor x:Name="m_editor"
24+
Loaded="OnTextEditorLoaded"
25+
FontFamily="Consolas"
26+
ShowLineNumbers="True" />
27+
</Border>
28+
<UniformGrid Grid.Row="1"
29+
Columns="2"
30+
HorizontalAlignment="Right"
31+
Margin="4,0">
32+
<Button Content="Accept" IsDefault="True" Click="OnAccept"/>
33+
<Button Content="Discard" IsCancel="True" Click="OnDiscard"/>
34+
</UniformGrid>
35+
</Grid>
36+
</Window>
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// -----------------------------------------------------------------------
2+
// <copyright file="CodeEditor.axaml.cs" company="Dean Edis">
3+
// Copyright (c) 2023 Dean Edis. All rights reserved.
4+
// </copyright>
5+
// <summary>
6+
// This example is provided on an "as is" basis and without warranty of any kind.
7+
// Dean Edis. does not warrant or make any representations regarding the use or
8+
// results of use of this example.
9+
// </summary>
10+
// -----------------------------------------------------------------------
11+
12+
using System;
13+
using Avalonia;
14+
using Avalonia.Controls;
15+
using Avalonia.Data;
16+
using Avalonia.Interactivity;
17+
using Avalonia.Media;
18+
using AvaloniaEdit;
19+
using AvaloniaEdit.Indentation.CSharp;
20+
21+
namespace Shrinker.Avalonia.Views;
22+
23+
public partial class CodeEditor : Window
24+
{
25+
private string m_glsl;
26+
public static readonly DirectProperty<CodeEditor, string> GlslProperty =
27+
AvaloniaProperty.RegisterDirect<CodeEditor, string>(
28+
nameof(Glsl),
29+
o => o.Glsl,
30+
(o, v) => o.Glsl = v,
31+
defaultBindingMode: BindingMode.TwoWay);
32+
private Action<string> m_accept;
33+
public static readonly DirectProperty<CodeEditor, Action<string>> AcceptProperty =
34+
AvaloniaProperty.RegisterDirect<CodeEditor, Action<string>>(
35+
nameof(Accept),
36+
o => o.Accept,
37+
(o, v) => o.Accept = v);
38+
39+
public string Glsl
40+
{
41+
get => m_glsl;
42+
set
43+
{
44+
if (SetAndRaise(GlslProperty, ref m_glsl, value))
45+
m_editor.Text = value;
46+
}
47+
}
48+
49+
public Action<string> Accept
50+
{
51+
get => m_accept;
52+
set => SetAndRaise(AcceptProperty, ref m_accept, value);
53+
}
54+
55+
public CodeEditor()
56+
{
57+
InitializeComponent();
58+
}
59+
60+
private void OnAccept(object sender, RoutedEventArgs e)
61+
{
62+
Accept?.Invoke(m_editor.Text);
63+
Close();
64+
}
65+
66+
private void OnDiscard(object sender, RoutedEventArgs e) =>
67+
Close();
68+
69+
private void OnTextEditorLoaded(object sender, RoutedEventArgs e)
70+
{
71+
var textEditor = (TextEditor)sender;
72+
textEditor.SyntaxHighlighting = CodeLineControl.SyntaxHighlighter;
73+
textEditor.TextArea.TextView.LinkTextForegroundBrush = Brushes.Cyan;
74+
textEditor.TextArea.IndentationStrategy = new CSharpIndentationStrategy();
75+
}
76+
}

ShaderShrinker/Shrinker.Avalonia/Views/MainWindow.axaml

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,25 @@
148148
<Setter Property="Padding" Value="0"/>
149149
<Setter Property="Margin" Value="6,0,0,6"/>
150150
</Style>
151+
<Style Selector="Button.SmallButton">
152+
<Setter Property="Width" Value="16"/>
153+
<Setter Property="Height" Value="16"/>
154+
<Setter Property="Margin" Value="4,0,4,2"/>
155+
<Setter Property="Padding" Value="0"/>
156+
<Setter Property="VerticalAlignment" Value="Center"/>
157+
</Style>
151158
</Grid.Styles>
152159

153160
<TextBlock Grid.Column="0" Grid.Row="0" Classes="Title" Text="Original" Margin="0,0,1,4"/>
161+
<Button Grid.Column="0" Grid.Row="0" Classes="SmallButton"
162+
HorizontalAlignment="Left"
163+
Command="{Binding EditCodeCommand}">
164+
<Avalonia:MaterialIcon Kind="FileTextEdit" Width="16" Height="16" />
165+
</Button>
166+
154167
<TextBlock Grid.Column="1" Grid.Row="0" Classes="Title" Text="Output" Margin="1,0,0,4" />
155-
<Button Grid.Column="1" Grid.Row="0"
156-
HorizontalAlignment="Left" VerticalAlignment="Center"
157-
Padding="0" Margin="4,0,4,2"
168+
<Button Grid.Column="1" Grid.Row="0" Classes="SmallButton"
169+
HorizontalAlignment="Left"
158170
ToolTip.Tip="Copy to Left Pane"
159171
Command="{Binding CopyLeftCommand}">
160172
<Avalonia:MaterialIcon Kind="ChevronDoubleLeft" Width="16" Height="16"/>

0 commit comments

Comments
 (0)