mirror of
https://github.com/riegera2412/UVtools.git
synced 2026-08-01 21:32:18 +02:00
WPF Progress
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace UVtools.Core.Objects
|
||||
{
|
||||
public static class StaticObjects
|
||||
{
|
||||
public static SHA256 Sha256 { get; } = SHA256.Create();
|
||||
|
||||
// Compute the file's hash.
|
||||
public static byte[] GetHashSha256(string filename)
|
||||
{
|
||||
using (var stream = File.OpenRead(filename))
|
||||
{
|
||||
return Sha256.ComputeHash(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -162,6 +162,11 @@ namespace UVtools.WPF
|
||||
|
||||
public static Bitmap GetBitmapFromAsset(string url) => new Bitmap(GetAsset(url));
|
||||
|
||||
public static string GetApplicationPath()
|
||||
{
|
||||
return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
* Everyone is permitted to copy and distribute verbatim copies
|
||||
* of this license document, but changing it is not allowed.
|
||||
*/
|
||||
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Threading;
|
||||
@@ -44,6 +46,30 @@ namespace UVtools.WPF.Extensions
|
||||
=> await window.MessageBoxGeneric(message, title ?? $"{window.Title} - Question", buttons, Icon.Setting, WindowStartupLocation.CenterOwner, style);
|
||||
|
||||
|
||||
public static void ShowDialogSync(this Window window, Window parent = null)
|
||||
{
|
||||
if (parent is null) parent = window;
|
||||
using (var source = new CancellationTokenSource())
|
||||
{
|
||||
window.ShowDialog(parent).ContinueWith(t => source.Cancel(), TaskScheduler.FromCurrentSynchronizationContext());
|
||||
Dispatcher.UIThread.MainLoop(source.Token);
|
||||
}
|
||||
}
|
||||
|
||||
public static T ShowDialogSync<T>(this Window window, Window parent = null)
|
||||
{
|
||||
if (parent is null) parent = window;
|
||||
using (var source = new CancellationTokenSource())
|
||||
{
|
||||
var task = window.ShowDialog<T>(parent);
|
||||
task.ContinueWith(t => source.Cancel(), TaskScheduler.FromCurrentSynchronizationContext());
|
||||
Dispatcher.UIThread.MainLoop(source.Token);
|
||||
return task.Result;
|
||||
}
|
||||
|
||||
return default(T);
|
||||
}
|
||||
|
||||
public static void ResetDataContext(this Window window)
|
||||
{
|
||||
var old = window.DataContext;
|
||||
|
||||
@@ -584,6 +584,11 @@ namespace UVtools.WPF
|
||||
await new AboutWindow().ShowDialog(this);
|
||||
}
|
||||
|
||||
public async void MenuHelpInstallProfilesClicked()
|
||||
{
|
||||
await new PrusaSlicerManager().ShowDialog(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Media;
|
||||
using UVtools.Core.Objects;
|
||||
|
||||
namespace UVtools.WPF.Structures
|
||||
{
|
||||
public class PEProfileFolder : BindableBase
|
||||
{
|
||||
private ObservableCollection<CheckBox> _items = new ObservableCollection<CheckBox>();
|
||||
private ushort _installed;
|
||||
private ushort _updates;
|
||||
|
||||
public enum FolderType
|
||||
{
|
||||
Print,
|
||||
Printer
|
||||
}
|
||||
|
||||
public FolderType Type { get; }
|
||||
|
||||
public string SourcePath { get; }
|
||||
public string TargetPath { get; }
|
||||
|
||||
public ObservableCollection<CheckBox> Items
|
||||
{
|
||||
get => _items;
|
||||
set => RaiseAndSetIfChanged(ref _items, value);
|
||||
}
|
||||
|
||||
public ushort Installed
|
||||
{
|
||||
get => _installed;
|
||||
set => RaiseAndSetIfChanged(ref _installed, value);
|
||||
}
|
||||
|
||||
public ushort Updates
|
||||
{
|
||||
get => _updates;
|
||||
set => RaiseAndSetIfChanged(ref _updates, value);
|
||||
}
|
||||
|
||||
public PEProfileFolder(FolderType type)
|
||||
{
|
||||
Type = type;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case FolderType.Print:
|
||||
SourcePath = string.Format("{0}{1}Assets{1}PrusaSlicer{1}sla_print",
|
||||
App.GetApplicationPath(), Path.DirectorySeparatorChar);
|
||||
TargetPath = string.Format("{0}{1}PrusaSlicer{1}sla_print",
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||
Path.DirectorySeparatorChar);
|
||||
break;
|
||||
case FolderType.Printer:
|
||||
SourcePath = string.Format("{0}{1}Assets{1}PrusaSlicer{1}printer",
|
||||
App.GetApplicationPath(), Path.DirectorySeparatorChar);
|
||||
TargetPath = string.Format("{0}{1}PrusaSlicer{1}printer",
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||
Path.DirectorySeparatorChar);
|
||||
break;
|
||||
}
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Items.Clear();
|
||||
Updates = 0;
|
||||
Installed = 0;
|
||||
if (!Directory.Exists(SourcePath)) return;
|
||||
DirectoryInfo di = new DirectoryInfo(SourcePath);
|
||||
var files = di.GetFiles("*.ini");
|
||||
if (files.Length == 0) return;
|
||||
|
||||
bool folderExists = Directory.Exists(TargetPath);
|
||||
|
||||
for (int i = 0; i < files.Length; i++)
|
||||
{
|
||||
Items.Add(new CheckBox
|
||||
{
|
||||
Content = files[i].Name,
|
||||
Tag = files
|
||||
});
|
||||
|
||||
if (folderExists)
|
||||
{
|
||||
var targetFile = $"{TargetPath}{Path.DirectorySeparatorChar}{files[i].Name}";
|
||||
FileInfo targetFileInfo = new FileInfo(targetFile);
|
||||
if (targetFileInfo.Exists)
|
||||
{
|
||||
Installed++;
|
||||
if (targetFileInfo.Length != files[i].Length || !StaticObjects.GetHashSha256(targetFileInfo.FullName).SequenceEqual(StaticObjects.GetHashSha256(files[i].FullName)))
|
||||
{
|
||||
Items[i].Foreground = Brushes.Red;
|
||||
Items[i].IsChecked = true;
|
||||
Updates++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Items[i].Foreground = Brushes.Green;
|
||||
Items[i].IsEnabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectNone()
|
||||
{
|
||||
foreach (var checkBox in Items)
|
||||
{
|
||||
checkBox.IsChecked = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectAll()
|
||||
{
|
||||
foreach (var checkBox in Items)
|
||||
{
|
||||
checkBox.IsChecked = checkBox.IsEnabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,293 @@
|
||||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="1024" d:DesignHeight="700"
|
||||
x:Class="UVtools.WPF.Windows.PrusaSlicerManager"
|
||||
Title="Install profiles into PrusaSlicer"
|
||||
MinWidth="900"
|
||||
MinHeight="700"
|
||||
Icon="/Assets/Icons/UVtools.ico">
|
||||
|
||||
<DockPanel LastChildFill="True">
|
||||
<Grid DockPanel.Dock="Top"
|
||||
RowDefinitions="Auto"
|
||||
ColumnDefinitions="Auto,*">
|
||||
|
||||
<Border
|
||||
Margin="5,5,0,5"
|
||||
BorderBrush="LightBlue"
|
||||
BorderThickness="4"
|
||||
>
|
||||
|
||||
<StackPanel Orientation="Vertical">
|
||||
<TextBlock Padding="10" Background="LightBlue" FontWeight="Bold" Text="Legend"/>
|
||||
<StackPanel Margin="15" Orientation="Vertical" Spacing="15">
|
||||
<StackPanel Orientation="Horizontal" Spacing="5">
|
||||
<Border
|
||||
Width="18" Height="18"
|
||||
BorderBrush="Black"
|
||||
BorderThickness="2"
|
||||
Background="Green"></Border>
|
||||
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Text="Installed Profile - Files match, no need to update"/>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Spacing="5">
|
||||
<Border
|
||||
Width="18" Height="18"
|
||||
BorderBrush="Black"
|
||||
BorderThickness="2"
|
||||
Background="Red"></Border>
|
||||
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Text="Installed Profile - Files mismatch, update available"/>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Spacing="5">
|
||||
<Border
|
||||
Width="18" Height="18"
|
||||
BorderBrush="Black"
|
||||
BorderThickness="2"
|
||||
Background="Black"></Border>
|
||||
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Text="Uninstalled Profile - Not present on PrusaSlicer"/>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border
|
||||
Grid.Column="1"
|
||||
Margin="5"
|
||||
BorderBrush="LightBlue"
|
||||
BorderThickness="4"
|
||||
>
|
||||
|
||||
<StackPanel Orientation="Vertical">
|
||||
<TextBlock Padding="10" Background="LightBlue" FontWeight="Bold" Text="Information"/>
|
||||
<TextBlock
|
||||
TextWrapping="Wrap"
|
||||
Margin="15"
|
||||
Text="This will install and overwrite all checked profiles into PrusaSlicer.
|
||||

On PrusaSlicer access 'Printer' -> 'Notes' to change source parameters.
|
||||

NOTE: If you modify a base profile and save under PrusaSlicer, this tool will be mark it as 'update available' since it got modified, in those cases we always recommend to never update base profiles, instead clone it and give different name as your own profile." />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
</Grid>
|
||||
|
||||
<Border DockPanel.Dock="Bottom"
|
||||
Background="LightGray"
|
||||
Height="80"
|
||||
Padding="5,20,0,5"
|
||||
>
|
||||
|
||||
<Grid ColumnDefinitions="Auto,*" RowDefinitions="Auto">
|
||||
<Button
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Padding="10"
|
||||
Command="{Binding RefreshProfiles}"
|
||||
>
|
||||
<StackPanel Orientation="Horizontal" Spacing="10">
|
||||
<Image Source="/Assets/Icons/refresh-16x16.png"/>
|
||||
<TextBlock Text="Refresh profiles"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<StackPanel
|
||||
Margin="0,0,5,5"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Right"
|
||||
Orientation="Horizontal"
|
||||
Spacing="5">
|
||||
<Button Padding="10">
|
||||
<StackPanel Orientation="Horizontal" Spacing="10">
|
||||
<Image Source="/Assets/Icons/refresh-16x16.png"/>
|
||||
<TextBlock Text="Install selected profiles"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<Button Padding="10" Command="{Binding Close}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="10">
|
||||
<Image Source="/Assets/Icons/exit-16x16.png"/>
|
||||
<TextBlock Text="Close"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
|
||||
</Border>
|
||||
|
||||
<Grid
|
||||
ColumnDefinitions="*,*"
|
||||
RowDefinitions="*"
|
||||
>
|
||||
|
||||
<Border
|
||||
Grid.Column="0"
|
||||
Margin="5"
|
||||
BorderBrush="LightBlue"
|
||||
BorderThickness="4"
|
||||
>
|
||||
|
||||
<Grid RowDefinitions="Auto,Auto,*">
|
||||
|
||||
<TextBlock Padding="10" Background="LightBlue" FontWeight="Bold" Text="Printer profiles"/>
|
||||
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
Orientation="Horizontal" Spacing="5">
|
||||
<Button Padding="10"
|
||||
IsEnabled="{Binding Profiles[0].Updates}"
|
||||
Command="{Binding Profiles[0].SelectNone}"
|
||||
>
|
||||
<StackPanel Orientation="Horizontal" Spacing="5">
|
||||
<Image Source="/Assets/Icons/checkbox-unmarked-16x16.png"/>
|
||||
<TextBlock Text="Unselect all"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<Button Padding="10"
|
||||
IsEnabled="{Binding Profiles[0].Updates}"
|
||||
Command="{Binding Profiles[0].SelectAll}"
|
||||
>
|
||||
<StackPanel Orientation="Horizontal" Spacing="5">
|
||||
<Image Source="/Assets/Icons/checkbox-marked-16x16.png"/>
|
||||
<TextBlock Text="Select all"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
HorizontalAlignment="Right"
|
||||
Orientation="Horizontal"
|
||||
Spacing="5">
|
||||
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Profiles[0].Updates,
|
||||
StringFormat=\{0\} Update(s)}"/>
|
||||
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Text="|"/>
|
||||
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Profiles[0].Installed,
|
||||
StringFormat=\{0\} Installed}"/>
|
||||
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Text="|"/>
|
||||
|
||||
<TextBlock
|
||||
Margin="0,0,5,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Profiles[0].Items.Count,
|
||||
StringFormat=\{0\} Profiles}"/>
|
||||
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<ListBox
|
||||
Grid.Row="2"
|
||||
SelectionMode="Toggle"
|
||||
Items="{Binding Profiles[0].Items}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<Border
|
||||
Grid.Column="1"
|
||||
Margin="5"
|
||||
BorderBrush="LightBlue"
|
||||
BorderThickness="4"
|
||||
>
|
||||
|
||||
<Grid RowDefinitions="Auto,Auto,*">
|
||||
|
||||
<TextBlock Padding="10" Background="LightBlue" FontWeight="Bold" Text="Printer profiles"/>
|
||||
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
Orientation="Horizontal" Spacing="5">
|
||||
<Button Padding="10"
|
||||
IsEnabled="{Binding Profiles[1].Updates}"
|
||||
Command="{Binding Profiles[1].SelectNone}"
|
||||
>
|
||||
<StackPanel Orientation="Horizontal" Spacing="5">
|
||||
<Image Source="/Assets/Icons/checkbox-unmarked-16x16.png"/>
|
||||
<TextBlock Text="Unselect all"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<Button Padding="10"
|
||||
IsEnabled="{Binding Profiles[1].Updates}"
|
||||
Command="{Binding Profiles[1].SelectAll}"
|
||||
>
|
||||
<StackPanel Orientation="Horizontal" Spacing="5">
|
||||
<Image Source="/Assets/Icons/checkbox-marked-16x16.png"/>
|
||||
<TextBlock Text="Select all"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
HorizontalAlignment="Right"
|
||||
Orientation="Horizontal"
|
||||
Spacing="5">
|
||||
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Profiles[1].Updates,
|
||||
StringFormat=\{0\} Update(s)}"/>
|
||||
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Text="|"/>
|
||||
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Profiles[1].Installed,
|
||||
StringFormat=\{0\} Installed}"/>
|
||||
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Text="|"/>
|
||||
|
||||
<TextBlock
|
||||
Margin="0,0,5,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Profiles[1].Items.Count,
|
||||
StringFormat=\{0\} Profiles}"/>
|
||||
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<ListBox
|
||||
Grid.Row="2"
|
||||
SelectionMode="Toggle"
|
||||
Items="{Binding Profiles[1].Items}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
</Window>
|
||||
@@ -0,0 +1,38 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using UVtools.WPF.Controls;
|
||||
using UVtools.WPF.Structures;
|
||||
|
||||
namespace UVtools.WPF.Windows
|
||||
{
|
||||
public class PrusaSlicerManager : WindowEx
|
||||
{
|
||||
public PEProfileFolder[] Profiles { get;}
|
||||
|
||||
public PrusaSlicerManager()
|
||||
{
|
||||
InitializeComponent();
|
||||
Profiles = new[]
|
||||
{
|
||||
new PEProfileFolder(PEProfileFolder.FolderType.Print),
|
||||
new PEProfileFolder(PEProfileFolder.FolderType.Printer),
|
||||
};
|
||||
|
||||
DataContext = this;
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
public void RefreshProfiles()
|
||||
{
|
||||
foreach (var profile in Profiles)
|
||||
{
|
||||
profile.Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user