diff --git a/IoFatPreviewGlobalUsings.cs b/IoFatPreviewGlobalUsings.cs new file mode 100644 index 0000000..870d464 --- /dev/null +++ b/IoFatPreviewGlobalUsings.cs @@ -0,0 +1,4 @@ +// Copyright 2026 Ari Sulistiono +// SPDX-License-Identifier: GPL-3.0-or-later + +global using System.Windows.Controls.Primitives; diff --git a/IoListTestingWindow.GridConverters.cs b/IoListTestingWindow.GridConverters.cs new file mode 100644 index 0000000..2a226bd --- /dev/null +++ b/IoListTestingWindow.GridConverters.cs @@ -0,0 +1,87 @@ +using System.Globalization; +using System.Windows.Data; +using System.Windows.Media; +using ArIED61850Tester.Models.IoTesting; + +namespace ArIED61850Tester; + +internal sealed class IoFatBooleanValueBrushConverter : IValueConverter +{ + private static readonly Brush TrueBrush = Brush(229, 72, 77); + private static readonly Brush FalseBrush = Brush(22, 166, 106); + private static readonly Brush NeutralBrush = Brush(17, 24, 39); + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + var text = value?.ToString()?.Trim() ?? string.Empty; + if (text.Equals("True", StringComparison.OrdinalIgnoreCase) || text == "1") return TrueBrush; + if (text.Equals("False", StringComparison.OrdinalIgnoreCase) || text == "0") return FalseBrush; + return NeutralBrush; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => Binding.DoNothing; + private static Brush Brush(byte r, byte g, byte b) { var value = new SolidColorBrush(Color.FromRgb(r, g, b)); value.Freeze(); return value; } +} + +internal sealed class IoFatLiveBrushConverter : IValueConverter +{ + private static readonly Brush LiveBrush = Brush(22, 132, 90); + private static readonly Brush MutedBrush = Brush(101, 117, 139); + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) => value is true ? LiveBrush : MutedBrush; + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => Binding.DoNothing; + private static Brush Brush(byte r, byte g, byte b) { var value = new SolidColorBrush(Color.FromRgb(r, g, b)); value.Freeze(); return value; } +} + +internal sealed class IoFatEvidenceBrushConverter : IValueConverter +{ + private static readonly Brush SuccessBrush = Brush(22, 132, 90); + private static readonly Brush MutedBrush = Brush(138, 151, 169); + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) => value == null ? MutedBrush : SuccessBrush; + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => Binding.DoNothing; + private static Brush Brush(byte r, byte g, byte b) { var result = new SolidColorBrush(Color.FromRgb(r, g, b)); result.Freeze(); return result; } +} + +internal sealed class IoFatQualityBrushConverter : IValueConverter +{ + private static readonly Brush GoodBrush = Brush(22, 132, 90); + private static readonly Brush BadBrush = Brush(197, 58, 69); + private static readonly Brush MutedBrush = Brush(96, 112, 137); + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + var text = value?.ToString()?.Trim() ?? string.Empty; + if (text.Equals("good", StringComparison.OrdinalIgnoreCase)) return GoodBrush; + if (text.Contains("invalid", StringComparison.OrdinalIgnoreCase) || text.Contains("bad", StringComparison.OrdinalIgnoreCase)) return BadBrush; + return MutedBrush; + } + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => Binding.DoNothing; + private static Brush Brush(byte r, byte g, byte b) { var result = new SolidColorBrush(Color.FromRgb(r, g, b)); result.Freeze(); return result; } +} + +internal sealed class IoFatStateBrushConverter : IValueConverter +{ + private static readonly Brush PassBrush = Brush(22, 132, 90); + private static readonly Brush ReviewBrush = Brush(154, 101, 0); + private static readonly Brush FailBrush = Brush(197, 58, 69); + private static readonly Brush MutedBrush = Brush(96, 112, 137); + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) => value switch + { + IoTestPointState.Passed => PassBrush, + IoTestPointState.Review => ReviewBrush, + IoTestPointState.Failed => FailBrush, + _ => MutedBrush + }; + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => Binding.DoNothing; + private static Brush Brush(byte r, byte g, byte b) { var result = new SolidColorBrush(Color.FromRgb(r, g, b)); result.Freeze(); return result; } +} + +internal sealed class IoFatResultTextConverter : IValueConverter +{ + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) => value switch + { + IoTestPointState.Passed => "✔ PASS", + IoTestPointState.Review => "⚠ REVIEW", + IoTestPointState.Failed => "✖ FAILED", + _ => "—" + }; + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => Binding.DoNothing; +} diff --git a/IoListTestingWindow.PrintPreview.cs b/IoListTestingWindow.PrintPreview.cs index 1db01c0..71cb50b 100644 --- a/IoListTestingWindow.PrintPreview.cs +++ b/IoListTestingWindow.PrintPreview.cs @@ -1,6 +1,10 @@ using System.ComponentModel; +using System.Globalization; 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.Threading; using ArIED61850Tester.Services.IoTesting; @@ -14,10 +18,10 @@ public partial class IoListTestingWindow private bool _printPreviewActive; private DataGrid? _signalWorkspaceGrid; private Grid? _printPreviewHost; - private WebBrowser? _printPreviewBrowser; + private DocumentViewer? _printPreviewDocumentViewer; private Button? _printPreviewToggle; - private TextBlock? _printPreviewTitle; - private TextBlock? _printPreviewSubtitle; + private TextBlock? _printPreviewZoomText; + private TextBlock? _printPreviewPageText; private DispatcherTimer? _preparationStateGuard; protected override void OnContentRendered(EventArgs e) @@ -39,12 +43,8 @@ private void InstallPerIedPrintPreview() if (Content is not Grid root) return; - var middle = root.Children - .OfType() - .FirstOrDefault(child => Grid.GetRow(child) == 2); - var workspaceBorder = middle?.Children - .OfType() - .FirstOrDefault(child => Grid.GetColumn(child) == 2); + var middle = root.Children.OfType().FirstOrDefault(child => Grid.GetRow(child) == 2); + var workspaceBorder = middle?.Children.OfType().FirstOrDefault(child => Grid.GetColumn(child) == 2); if (workspaceBorder?.Child is not Grid workspaceGrid) return; @@ -52,6 +52,7 @@ private void InstallPerIedPrintPreview() if (_signalWorkspaceGrid == null) return; + InstallSignalGridPolish(_signalWorkspaceGrid); RemoveMainPreparationSurface(workspaceGrid); InstallPreviewToggle(root); _printPreviewHost = BuildPrintPreviewHost(); @@ -63,11 +64,9 @@ private static void RemoveMainPreparationSurface(Grid workspaceGrid) { var preparationSurface = workspaceGrid.Children .OfType() - .FirstOrDefault(border => Grid.GetRow(border) == 1 && - border.Descendants().Any(progress => progress.IsIndeterminate)); + .FirstOrDefault(border => Grid.GetRow(border) == 1 && border.Descendants().Any(progress => progress.IsIndeterminate)); if (preparationSurface != null) workspaceGrid.Children.Remove(preparationSurface); - if (workspaceGrid.RowDefinitions.Count > 1) workspaceGrid.RowDefinitions[1].Height = new GridLength(0); if (workspaceGrid.RowDefinitions.Count > 2) @@ -76,21 +75,17 @@ private static void RemoveMainPreparationSurface(Grid workspaceGrid) private void InstallPreviewToggle(Grid root) { - var headerBorder = root.Children - .OfType() - .FirstOrDefault(child => Grid.GetRow(child) == 0); - var headerGrid = headerBorder?.Child as Grid; - var actions = headerGrid?.Children.OfType().FirstOrDefault(); + var headerBorder = root.Children.OfType().FirstOrDefault(child => Grid.GetRow(child) == 0); + var actions = (headerBorder?.Child as Grid)?.Children.OfType().FirstOrDefault(); if (actions == null) return; - _printPreviewToggle = BuildButton("Print Preview", TogglePrintPreview_Click, primary: false); - _printPreviewToggle.ToolTip = "Preview the selected IED report in the workspace"; - var pdfButtonIndex = actions.Children - .OfType