feat: developer tools page, auto-test orchestrator, BIP display, tests redesign
Bundles several feature streams that have been iterating on the working tree: - Developer Tools page (Debug-only via DEVELOPER_TOOLS symbol): hosts the identification card, manual KWP write + transaction log, ROM/EEPROM dump card with progress banner and completion message, persisted custom-commands library, persisted EEPROM passwords library. New service primitives: IKwpService.SendRawCustomAsync / ReadEepromAsync / ReadRomEepromAsync. Persistence mirrors the Clients XML pattern in two new files (custom_commands.xml, eeprom_passwords.xml). - Auto-test orchestrator (IAutoTestOrchestrator + AutoTestState): linear K-Line read -> unlock -> bench-on -> test sequence with snackbar UI and progress dialog VM, gated on dashboard alarms. - BIP-STATUS display: BipDisplayViewModel + BipDisplayView, RAM read at 0x0106 via IKwpService.ReadBipStatusAsync; status definitions in BipStatusDefinition. - Tests page redesign: TestSectionCard + PhaseTileView replacing the old TestPlanView/TestRunningView/TestDoneView/TestPreconditionsView/ TestSectionView controls and their VMs. - Pump command sliders: Fluent thick-track style with overhang thumb, click-anywhere-and-drag, mouse-wheel adjustment. - Window startup: app.manifest declares PerMonitorV2 DPI awareness, MainWindow installs a WM_GETMINMAXINFO hook in OnSourceInitialized and maximizes there (after the hook is in place) so the app fits the work area exactly on any display configuration. - Misc: PercentToPixelsConverter, seed_aliases.py one-shot pump-alias importer, tools/Import-BipStatus.ps1, kline_eeprom_spec.md and dump-functions reference docs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -26,11 +26,11 @@
|
||||
|
||||
<!-- ── Zero buttons (docked bottom first) ─────────────────── -->
|
||||
<UniformGrid DockPanel.Dock="Bottom" Rows="1" Columns="2" Margin="0,10,0,0">
|
||||
<ui:Button Margin="0,0,4,0" Height="40"
|
||||
<ui:Button Margin="0,0,4,0" Height="40" HorizontalAlignment="Stretch"
|
||||
Content="{DynamicResource Bench.Advance.ZeroPsg}"
|
||||
Command="{Binding AngleDisplay.SetPsgZeroCommand}"
|
||||
Appearance="Secondary"/>
|
||||
<ui:Button Margin="4,0,0,0" Height="40"
|
||||
<ui:Button Margin="4,0,0,0" Height="40" HorizontalAlignment="Stretch"
|
||||
Content="{DynamicResource Bench.Advance.ZeroInj}"
|
||||
Command="{Binding AngleDisplay.SetInjZeroCommand}"
|
||||
Appearance="Secondary"/>
|
||||
|
||||
115
Views/UserControls/AutoTestSnackbarView.xaml
Normal file
115
Views/UserControls/AutoTestSnackbarView.xaml
Normal file
@@ -0,0 +1,115 @@
|
||||
<UserControl x:Class="HC_APTBS.Views.UserControls.AutoTestSnackbarView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="80" d:DesignWidth="700">
|
||||
|
||||
<!-- DataContext = AutoTestProgressViewModel (may be null — NullToVis collapses the border) -->
|
||||
<UserControl.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Border Visibility="{Binding Converter={StaticResource NullToVis}}"
|
||||
Style="{StaticResource SnackbarShell}"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Bottom"
|
||||
MinWidth="560" MaxWidth="860">
|
||||
|
||||
<DockPanel LastChildFill="True" Margin="16,10">
|
||||
|
||||
<!-- ── Leading state icon ────────────────────────────────────── -->
|
||||
<Grid DockPanel.Dock="Left" Width="30" Height="30" Margin="0,0,12,0">
|
||||
|
||||
<!-- In-progress spinner -->
|
||||
<ui:ProgressRing IsIndeterminate="True" Width="24" Height="24">
|
||||
<ui:ProgressRing.Style>
|
||||
<Style TargetType="ui:ProgressRing">
|
||||
<Setter Property="Visibility" Value="Visible"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsComplete}" Value="True">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ui:ProgressRing.Style>
|
||||
</ui:ProgressRing>
|
||||
|
||||
<!-- Success check -->
|
||||
<ui:SymbolIcon Symbol="CheckmarkCircle24" FontSize="24"
|
||||
Foreground="{DynamicResource SystemFillColorSuccessBrush}">
|
||||
<ui:SymbolIcon.Style>
|
||||
<Style TargetType="ui:SymbolIcon">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsSuccess}" Value="True">
|
||||
<Setter Property="Visibility" Value="Visible"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ui:SymbolIcon.Style>
|
||||
</ui:SymbolIcon>
|
||||
|
||||
<!-- Failure/cancel X -->
|
||||
<ui:SymbolIcon Symbol="DismissCircle24" FontSize="24"
|
||||
Foreground="{DynamicResource SystemFillColorCriticalBrush}">
|
||||
<ui:SymbolIcon.Style>
|
||||
<Style TargetType="ui:SymbolIcon">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
<Style.Triggers>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding IsComplete}" Value="True"/>
|
||||
<Condition Binding="{Binding IsSuccess}" Value="False"/>
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="Visibility" Value="Visible"/>
|
||||
</MultiDataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ui:SymbolIcon.Style>
|
||||
</ui:SymbolIcon>
|
||||
</Grid>
|
||||
|
||||
<!-- ── Trailing buttons ───────────────────────────────────────── -->
|
||||
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal" VerticalAlignment="Center" Margin="12,0,0,0">
|
||||
<TextBlock Text="{Binding Progress, StringFormat={}{0}%}"
|
||||
FontFamily="Consolas" FontSize="13" FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
|
||||
VerticalAlignment="Center" Margin="0,0,12,0"/>
|
||||
|
||||
<ui:Button Content="{DynamicResource Common.Cancel}"
|
||||
Command="{Binding CancelCommand}"
|
||||
Appearance="Caution"
|
||||
Visibility="{Binding IsCancellable, Converter={StaticResource BoolToVis}}"
|
||||
Height="30" Padding="12,4"/>
|
||||
|
||||
<ui:Button Content="{DynamicResource Common.Dismiss}"
|
||||
Click="OnDismissClick"
|
||||
Appearance="Secondary"
|
||||
Visibility="{Binding IsComplete, Converter={StaticResource BoolToVis}}"
|
||||
Height="30" Padding="12,4"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- ── Middle: type label + phase text + progress bar ─────────── -->
|
||||
<StackPanel VerticalAlignment="Center">
|
||||
<DockPanel>
|
||||
<TextBlock DockPanel.Dock="Left"
|
||||
Text="{Binding TypeLabel}"
|
||||
FontWeight="SemiBold" FontSize="12"
|
||||
Foreground="{DynamicResource AccentTextFillColorPrimaryBrush}"
|
||||
VerticalAlignment="Center" Margin="0,0,8,0"/>
|
||||
<TextBlock Text="{Binding PhaseText}"
|
||||
FontSize="12"
|
||||
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
|
||||
VerticalAlignment="Center"
|
||||
TextTrimming="CharacterEllipsis"/>
|
||||
</DockPanel>
|
||||
<ProgressBar Value="{Binding Progress, Mode=OneWay}"
|
||||
Minimum="0" Maximum="100" Height="3"
|
||||
Margin="0,4,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
</DockPanel>
|
||||
</Border>
|
||||
</UserControl>
|
||||
59
Views/UserControls/AutoTestSnackbarView.xaml.cs
Normal file
59
Views/UserControls/AutoTestSnackbarView.xaml.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Threading;
|
||||
using HC_APTBS.ViewModels.Dialogs;
|
||||
|
||||
namespace HC_APTBS.Views.UserControls
|
||||
{
|
||||
/// <summary>
|
||||
/// Shell-level snackbar that mirrors <see cref="UnlockSnackbarView"/> but binds to
|
||||
/// <see cref="AutoTestProgressViewModel"/>. Auto-dismisses three seconds after a
|
||||
/// successful run; a failed or cancelled run stays until the operator clicks Dismiss.
|
||||
/// </summary>
|
||||
public partial class AutoTestSnackbarView : UserControl
|
||||
{
|
||||
private DispatcherTimer? _autoHideTimer;
|
||||
|
||||
public AutoTestSnackbarView()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContextChanged += OnDataContextChanged;
|
||||
}
|
||||
|
||||
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.OldValue is AutoTestProgressViewModel oldVm)
|
||||
oldVm.PropertyChanged -= OnVmPropertyChanged;
|
||||
|
||||
if (e.NewValue is AutoTestProgressViewModel newVm)
|
||||
newVm.PropertyChanged += OnVmPropertyChanged;
|
||||
}
|
||||
|
||||
private void OnVmPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName != nameof(AutoTestProgressViewModel.IsSuccess)) return;
|
||||
if (DataContext is not AutoTestProgressViewModel vm) return;
|
||||
|
||||
if (vm.IsSuccess == true)
|
||||
{
|
||||
_autoHideTimer?.Stop();
|
||||
_autoHideTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(3) };
|
||||
_autoHideTimer.Tick += (_, _) =>
|
||||
{
|
||||
_autoHideTimer!.Stop();
|
||||
if (vm.CloseCommand.CanExecute(null))
|
||||
vm.CloseCommand.Execute(null);
|
||||
};
|
||||
_autoHideTimer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDismissClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is AutoTestProgressViewModel vm && vm.CloseCommand.CanExecute(null))
|
||||
vm.CloseCommand.Execute(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,31 +92,31 @@
|
||||
</Grid>
|
||||
|
||||
<!-- ── Preset RPM buttons 2×4 ──────────────────────────────── -->
|
||||
<UniformGrid Rows="2" Columns="4" Margin="0,0,0,10">
|
||||
<UniformGrid Rows="2" Columns="4" Margin="-2,0,-2,10">
|
||||
<ui:Button Content="100" CommandParameter="100"
|
||||
Command="{Binding BenchControl.SetQuickRpmCommand}"
|
||||
Appearance="Secondary" Height="40" Margin="2" FontSize="12"/>
|
||||
Appearance="Secondary" Height="40" HorizontalAlignment="Stretch" Margin="2" FontSize="12"/>
|
||||
<ui:Button Content="200" CommandParameter="200"
|
||||
Command="{Binding BenchControl.SetQuickRpmCommand}"
|
||||
Appearance="Secondary" Height="40" Margin="2" FontSize="12"/>
|
||||
Appearance="Secondary" Height="40" HorizontalAlignment="Stretch" Margin="2" FontSize="12"/>
|
||||
<ui:Button Content="500" CommandParameter="500"
|
||||
Command="{Binding BenchControl.SetQuickRpmCommand}"
|
||||
Appearance="Secondary" Height="40" Margin="2" FontSize="12"/>
|
||||
Appearance="Secondary" Height="40" HorizontalAlignment="Stretch" Margin="2" FontSize="12"/>
|
||||
<ui:Button Content="750" CommandParameter="750"
|
||||
Command="{Binding BenchControl.SetQuickRpmCommand}"
|
||||
Appearance="Secondary" Height="40" Margin="2" FontSize="12"/>
|
||||
Appearance="Secondary" Height="40" HorizontalAlignment="Stretch" Margin="2" FontSize="12"/>
|
||||
<ui:Button Content="1000" CommandParameter="1000"
|
||||
Command="{Binding BenchControl.SetQuickRpmCommand}"
|
||||
Appearance="Secondary" Height="40" Margin="2" FontSize="12"/>
|
||||
Appearance="Secondary" Height="40" HorizontalAlignment="Stretch" Margin="2" FontSize="12"/>
|
||||
<ui:Button Content="1250" CommandParameter="1250"
|
||||
Command="{Binding BenchControl.SetQuickRpmCommand}"
|
||||
Appearance="Secondary" Height="40" Margin="2" FontSize="12"/>
|
||||
Appearance="Secondary" Height="40" HorizontalAlignment="Stretch" Margin="2" FontSize="12"/>
|
||||
<ui:Button Content="1500" CommandParameter="1500"
|
||||
Command="{Binding BenchControl.SetQuickRpmCommand}"
|
||||
Appearance="Secondary" Height="40" Margin="2" FontSize="12"/>
|
||||
Appearance="Secondary" Height="40" HorizontalAlignment="Stretch" Margin="2" FontSize="12"/>
|
||||
<ui:Button Content="2000" CommandParameter="2000"
|
||||
Command="{Binding BenchControl.SetQuickRpmCommand}"
|
||||
Appearance="Secondary" Height="40" Margin="2" FontSize="12"/>
|
||||
Appearance="Secondary" Height="40" HorizontalAlignment="Stretch" Margin="2" FontSize="12"/>
|
||||
</UniformGrid>
|
||||
|
||||
<!-- ── Start / Stop ─────────────────────────────────────────── -->
|
||||
@@ -129,13 +129,13 @@
|
||||
<ui:Button Grid.Column="0"
|
||||
Content="{DynamicResource Bench.Start}"
|
||||
Command="{Binding BenchControl.StartBenchCommand}"
|
||||
Appearance="Primary" Height="46" FontWeight="Bold" FontSize="14">
|
||||
Appearance="Primary" Height="46" HorizontalAlignment="Stretch" FontWeight="Bold" FontSize="14">
|
||||
<ui:Button.Icon><ui:SymbolIcon Symbol="Play24"/></ui:Button.Icon>
|
||||
</ui:Button>
|
||||
<ui:Button Grid.Column="2"
|
||||
Content="{DynamicResource Bench.Stop}"
|
||||
Command="{Binding BenchControl.StopBenchCommand}"
|
||||
Appearance="Danger" Height="46" FontWeight="Bold" FontSize="14">
|
||||
Appearance="Danger" Height="46" HorizontalAlignment="Stretch" FontWeight="Bold" FontSize="14">
|
||||
<ui:Button.Icon><ui:SymbolIcon Symbol="Stop24"/></ui:Button.Icon>
|
||||
</ui:Button>
|
||||
</Grid>
|
||||
|
||||
113
Views/UserControls/BipDisplayView.xaml
Normal file
113
Views/UserControls/BipDisplayView.xaml
Normal file
@@ -0,0 +1,113 @@
|
||||
<UserControl x:Class="HC_APTBS.Views.UserControls.BipDisplayView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:conv="clr-namespace:HC_APTBS.Converters"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="160" d:DesignWidth="480">
|
||||
|
||||
<UserControl.Resources>
|
||||
<conv:HexColorToBrushConverter x:Key="HexToBrush"/>
|
||||
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
|
||||
</UserControl.Resources>
|
||||
|
||||
<!-- Outer visibility: hidden for non-PSG5-PI pumps -->
|
||||
<Grid Visibility="{Binding HasDefinition, Converter={StaticResource BoolToVis}}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Header bar: title + raw word chip -->
|
||||
<DockPanel Margin="0,0,0,4">
|
||||
<Border DockPanel.Dock="Right"
|
||||
Background="{DynamicResource ControlFillColorSecondaryBrush}"
|
||||
BorderBrush="{DynamicResource ControlStrokeColorDefaultBrush}"
|
||||
BorderThickness="1" CornerRadius="10" Padding="8,2">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<TextBlock Text="{DynamicResource Pump.Bip.RawLabel}" FontSize="11"
|
||||
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
|
||||
Margin="0,0,3,0"/>
|
||||
<TextBlock Text="{Binding RawValue}"
|
||||
FontSize="11" FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
|
||||
FontFamily="Consolas, Courier New"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<TextBlock Text="{DynamicResource Pump.Bip.Title}"
|
||||
FontSize="12" FontWeight="SemiBold"
|
||||
FontFamily="{DynamicResource ContentControlThemeFontFamily}"
|
||||
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
|
||||
VerticalAlignment="Center"/>
|
||||
</DockPanel>
|
||||
|
||||
<!-- BIP rows table -->
|
||||
<ItemsControl Grid.Row="1" ItemsSource="{Binding Rows}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Vertical"/>
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Margin="0,1" CornerRadius="4"
|
||||
BorderThickness="1"
|
||||
BorderBrush="{DynamicResource ControlStrokeColorDefaultBrush}"
|
||||
Padding="6,3"
|
||||
Background="{DynamicResource ControlFillColorDefaultBrush}"
|
||||
SnapsToDevicePixels="True">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="22"/>
|
||||
<ColumnDefinition Width="16"/>
|
||||
<ColumnDefinition Width="58"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Colour indicator dot -->
|
||||
<Ellipse Grid.Column="0"
|
||||
Width="10" Height="10"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Fill="{Binding Color, Converter={StaticResource HexToBrush}}"/>
|
||||
|
||||
<!-- Index label -->
|
||||
<TextBlock Grid.Column="1"
|
||||
Text="{Binding Index}"
|
||||
FontSize="11" FontWeight="SemiBold" VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource TextFillColorSecondaryBrush}"/>
|
||||
|
||||
<!-- HEX pattern -->
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="{Binding HexPattern}"
|
||||
FontSize="11" FontFamily="Consolas, Courier New"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource TextFillColorSecondaryBrush}"/>
|
||||
|
||||
<!-- Description -->
|
||||
<TextBlock Grid.Column="3"
|
||||
Text="{Binding Description}"
|
||||
FontSize="11" VerticalAlignment="Center"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
ToolTip="{Binding Description}"
|
||||
ToolTipService.InitialShowDelay="200"
|
||||
ToolTipService.ShowDuration="30000">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextFillColorPrimaryBrush}"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsActive}" Value="True">
|
||||
<Setter Property="Foreground" Value="#FF4444"/>
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
12
Views/UserControls/BipDisplayView.xaml.cs
Normal file
12
Views/UserControls/BipDisplayView.xaml.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace HC_APTBS.Views.UserControls
|
||||
{
|
||||
public partial class BipDisplayView : UserControl
|
||||
{
|
||||
public BipDisplayView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,9 @@
|
||||
Devices column — three equal-height tiles (CAN / K-Line / Bench).
|
||||
DataContext is DashboardPageViewModel; all commands/collections are under Devices.
|
||||
-->
|
||||
<UserControl.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
@@ -74,16 +77,29 @@
|
||||
Command="{Binding DataContext.Devices.ToggleDeviceCommand,
|
||||
RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||||
CommandParameter="{Binding}"
|
||||
IsEnabled="{Binding IsEnabled}">
|
||||
IsEnabled="{Binding IsEnabled}"
|
||||
ToolTip="{Binding StateLabel}">
|
||||
<DockPanel>
|
||||
<TextBlock Text="{Binding StateLabel}"
|
||||
DockPanel.Dock="Right"
|
||||
FontSize="11" FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
|
||||
VerticalAlignment="Center" Margin="6,0,0,0"/>
|
||||
VerticalAlignment="Center" Margin="6,0,0,0">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextFillColorTertiaryBrush}"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsConnected}" Value="True">
|
||||
<Setter Property="Foreground" Value="{DynamicResource SystemFillColorSuccessBrush}"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
<Ellipse DockPanel.Dock="Left">
|
||||
<Ellipse.Style>
|
||||
<Style TargetType="Ellipse" BasedOn="{StaticResource StatusDot}">
|
||||
<!-- Default gray: device enumerated but not owned. -->
|
||||
<Setter Property="Fill" Value="{DynamicResource TextFillColorTertiaryBrush}"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsConnected}" Value="True">
|
||||
<Setter Property="Fill" Value="{DynamicResource SystemFillColorSuccessBrush}"/>
|
||||
@@ -180,10 +196,15 @@
|
||||
<Ellipse DockPanel.Dock="Left">
|
||||
<Ellipse.Style>
|
||||
<Style TargetType="Ellipse" BasedOn="{StaticResource StatusDot}">
|
||||
<!-- Default blue: FTDI detected but no session. -->
|
||||
<Setter Property="Fill" Value="{DynamicResource AccentFillColorDefaultBrush}"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsConnected}" Value="True">
|
||||
<Setter Property="Fill" Value="{DynamicResource SystemFillColorSuccessBrush}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding IsFailed}" Value="True">
|
||||
<Setter Property="Fill" Value="{DynamicResource SystemFillColorCriticalBrush}"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Ellipse.Style>
|
||||
@@ -268,5 +289,7 @@
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- CAN connect/disconnect snackbar is anchored page-bottom in MainWindow.xaml. -->
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@@ -37,13 +37,13 @@
|
||||
VerticalAlignment="Center" Margin="0,0,8,0"/>
|
||||
<ComboBox Grid.Column="1"
|
||||
SelectedIndex="{Binding VersionIndex}"
|
||||
Height="28">
|
||||
Height="36">
|
||||
<ComboBoxItem Content="V1"/>
|
||||
<ComboBoxItem Content="V2"/>
|
||||
<ComboBoxItem Content="V3"/>
|
||||
<ComboBoxItem Content="V4"/>
|
||||
</ComboBox>
|
||||
<CheckBox Grid.Column="2"
|
||||
<CheckBox Grid.Column="2" HorizontalAlignment="Right"
|
||||
IsChecked="{Binding IsAutoMode}"
|
||||
Content="{DynamicResource Dfi.Auto}"
|
||||
FontSize="12"
|
||||
@@ -82,7 +82,7 @@
|
||||
Visibility="{Binding IsBusy, Converter={StaticResource BoolToVis}}"/>
|
||||
|
||||
<!-- ── DFI slider ─────────────────────────────────────────────── -->
|
||||
<Grid DockPanel.Dock="Top" Margin="0,0,0,8">
|
||||
<Grid DockPanel.Dock="Top" Margin="0,0,0,8" Height="64">
|
||||
<Slider Value="{Binding SliderRaw}"
|
||||
Minimum="-145" Maximum="145"
|
||||
TickFrequency="5" SmallChange="5" LargeChange="5"
|
||||
@@ -115,12 +115,12 @@
|
||||
<ColumnDefinition Width="8"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<ui:Button Grid.Column="0"
|
||||
<ui:Button Grid.Column="0" HorizontalAlignment="Stretch"
|
||||
Content="{DynamicResource Dfi.Read}"
|
||||
Command="{Binding ReadDfiCommand}"
|
||||
Appearance="Secondary"
|
||||
FontWeight="Bold" Height="32"/>
|
||||
<ui:Button Grid.Column="2"
|
||||
<ui:Button Grid.Column="2" HorizontalAlignment="Stretch"
|
||||
Content="{DynamicResource Dfi.Write}"
|
||||
Command="{Binding WriteDfiCommand}"
|
||||
Appearance="Primary"
|
||||
|
||||
@@ -27,11 +27,11 @@
|
||||
<ui:Button Content="{DynamicResource Dtc.Read}"
|
||||
Command="{Binding ReadCommand}"
|
||||
Appearance="Secondary"
|
||||
Height="28" Margin="0,0,6,0"/>
|
||||
Height="32" Margin="0,0,6,0"/>
|
||||
<ui:Button Content="{DynamicResource Dtc.Clear}"
|
||||
Command="{Binding ClearCommand}"
|
||||
Appearance="Secondary"
|
||||
Height="28"/>
|
||||
Height="32"/>
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
|
||||
|
||||
@@ -3,71 +3,107 @@
|
||||
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"
|
||||
xmlns:sys="clr-namespace:System;assembly=System.Runtime"
|
||||
xmlns:conv="clr-namespace:HC_APTBS.Converters"
|
||||
xmlns:vm="clr-namespace:HC_APTBS.ViewModels"
|
||||
mc:Ignorable="d"
|
||||
d:DataContext="{d:DesignInstance Type=vm:GraphicIndicatorViewModel, IsDesignTimeCreatable=False}">
|
||||
<!--
|
||||
Vertical progress bar showing a single measurement value against its
|
||||
expected value and tolerance band. Shared across phase cards and the
|
||||
Running view's live measurement table.
|
||||
Vertical min/max/target gauge. Fluent-styled with DynamicResource tokens so
|
||||
the control repaints on theme change. The bar fills from the bottom via an
|
||||
inner ProgressBar (native easing on Value changes). An overlay rectangle
|
||||
highlights the in-tolerance band; a thin accent line marks the target.
|
||||
Fill colour reacts live to IsWithinTolerance and locks on IsPhaseCompleted
|
||||
when the owning phase ends.
|
||||
-->
|
||||
<UserControl.Resources>
|
||||
<conv:PercentToPixelsConverter x:Key="PercentToPixels"/>
|
||||
<sys:Double x:Key="TrackHeightPx">92</sys:Double>
|
||||
|
||||
<!-- Fill-colour style for the inner ProgressBar. Triggers cascade:
|
||||
phase completed + failed → critical (locked);
|
||||
live out-of-tolerance → critical;
|
||||
else → accent. -->
|
||||
<Style x:Key="IndicatorFillStyle" TargetType="ProgressBar">
|
||||
<Setter Property="Foreground" Value="{DynamicResource AccentFillColorDefaultBrush}"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsWithinTolerance}" Value="False">
|
||||
<Setter Property="Foreground" Value="{DynamicResource SystemFillColorCriticalBrush}"/>
|
||||
</DataTrigger>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding IsPhaseCompleted}" Value="True"/>
|
||||
<Condition Binding="{Binding PhasePassed}" Value="False"/>
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="Foreground" Value="{DynamicResource SystemFillColorCriticalBrush}"/>
|
||||
</MultiDataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid Width="58" Margin="2,0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/> <!-- Max label -->
|
||||
<RowDefinition Height="90"/> <!-- Progress bar -->
|
||||
<RowDefinition Height="Auto"/> <!-- Min label -->
|
||||
<RowDefinition Height="Auto"/> <!-- Param name -->
|
||||
<RowDefinition Height="Auto"/> <!-- Max label -->
|
||||
<RowDefinition Height="92"/> <!-- Track -->
|
||||
<RowDefinition Height="Auto"/> <!-- Min label -->
|
||||
<RowDefinition Height="Auto"/> <!-- Param name -->
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Max bound -->
|
||||
<TextBlock Text="{Binding MaxBound, StringFormat=F1}"
|
||||
FontSize="9" Foreground="Gray"
|
||||
HorizontalAlignment="Center" Margin="0,0,0,1"/>
|
||||
FontSize="10"
|
||||
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
|
||||
HorizontalAlignment="Center" Margin="0,0,0,2"/>
|
||||
|
||||
<Grid Grid.Row="1">
|
||||
<Border BorderBrush="Black" BorderThickness="1" SnapsToDevicePixels="True"/>
|
||||
<!-- Gauge track -->
|
||||
<Grid Grid.Row="1" SnapsToDevicePixels="True">
|
||||
<!-- Track background -->
|
||||
<Border Background="{DynamicResource ControlFillColorDefaultBrush}"
|
||||
BorderBrush="{DynamicResource ControlStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="3"/>
|
||||
|
||||
<!-- In-tolerance band -->
|
||||
<Canvas ClipToBounds="True" Margin="1">
|
||||
<Rectangle Width="56"
|
||||
Fill="{DynamicResource AccentFillColorTertiaryBrush}"
|
||||
Opacity="0.10"
|
||||
Canvas.Left="0"
|
||||
Canvas.Top="{Binding ToleranceBandTopPercent,
|
||||
Converter={StaticResource PercentToPixels},
|
||||
ConverterParameter={StaticResource TrackHeightPx}}"
|
||||
Height="{Binding ToleranceBandHeightPercent,
|
||||
Converter={StaticResource PercentToPixels},
|
||||
ConverterParameter={StaticResource TrackHeightPx}}"/>
|
||||
|
||||
<!-- Target line (1 px accent) -->
|
||||
<Line X1="0" X2="56" StrokeThickness="0.4" Opacity="0.20"
|
||||
Stroke="{DynamicResource AccentTextFillColorPrimaryBrush}"
|
||||
Canvas.Top="{Binding ExpectedMarkerPercent,
|
||||
Converter={StaticResource PercentToPixels},
|
||||
ConverterParameter={StaticResource TrackHeightPx}}"/>
|
||||
</Canvas>
|
||||
|
||||
<!-- Fill bar (bottom-up) -->
|
||||
<ProgressBar Orientation="Vertical"
|
||||
Minimum="0" Maximum="100"
|
||||
Value="{Binding ProgressPercent, Mode=OneWay}"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
Background="White"
|
||||
Margin="1">
|
||||
<ProgressBar.Style>
|
||||
<Style TargetType="ProgressBar">
|
||||
<Setter Property="Foreground" Value="#4CAF50"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsWithinTolerance}" Value="False">
|
||||
<Setter Property="Foreground" Value="#FF5722"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ProgressBar.Style>
|
||||
</ProgressBar>
|
||||
|
||||
<Canvas ClipToBounds="True">
|
||||
<Line X1="0" X2="58" StrokeDashArray="3,2"
|
||||
Stroke="LightGray" StrokeThickness="1"
|
||||
Canvas.Top="18"/>
|
||||
<Line X1="0" X2="58" StrokeDashArray="3,2"
|
||||
Stroke="LightGray" StrokeThickness="1"
|
||||
Canvas.Top="72"/>
|
||||
</Canvas>
|
||||
|
||||
<TextBlock Text="{Binding ExpectedValue, StringFormat=F1}"
|
||||
FontSize="9" Foreground="#999999"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Margin="0,-14,0,0"/>
|
||||
Opacity="0.55"
|
||||
Margin="1"
|
||||
Style="{StaticResource IndicatorFillStyle}"/>
|
||||
|
||||
<!-- Numeric readout -->
|
||||
<TextBlock Text="{Binding DisplayValue}"
|
||||
FontSize="14" FontWeight="Black"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Margin="0,10,0,0">
|
||||
FontSize="14" FontWeight="SemiBold"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextFillColorPrimaryBrush}"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding HasValue}" Value="False">
|
||||
<Setter Property="Foreground" Value="#CCCCCC"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextFillColorTertiaryBrush}"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
@@ -75,16 +111,21 @@
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
|
||||
<!-- Min bound -->
|
||||
<TextBlock Grid.Row="2"
|
||||
Text="{Binding MinBound, StringFormat=F1}"
|
||||
FontSize="9" Foreground="Gray"
|
||||
HorizontalAlignment="Center" Margin="0,1,0,0"/>
|
||||
FontSize="10"
|
||||
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
|
||||
HorizontalAlignment="Center" Margin="0,2,0,0"/>
|
||||
|
||||
<!-- Parameter name -->
|
||||
<TextBlock Grid.Row="3"
|
||||
Text="{Binding ParameterName}"
|
||||
FontSize="9" FontWeight="SemiBold"
|
||||
FontSize="11" FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
|
||||
HorizontalAlignment="Center"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
ToolTip="{Binding ParameterName}"/>
|
||||
ToolTip="{Binding ParameterName}"
|
||||
Margin="0,1,0,0"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Border CornerRadius="3" Padding="10,6" Margin="0,4"
|
||||
<Border
|
||||
BorderThickness="1" CornerRadius="8" Padding="14,10" Margin="0,0,0,8"
|
||||
Visibility="{Binding IsVisible, Converter={StaticResource BoolToVis}}">
|
||||
<Border.Style>
|
||||
<Style TargetType="Border">
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
d:DataContext="{d:DesignInstance Type=vm:PhaseCardViewModel, IsDesignTimeCreatable=False}">
|
||||
<!--
|
||||
Single phase card. DataContext: PhaseCardViewModel.
|
||||
Shared between TestPlanView (shows ReadyValues/OperationValues and enable toggle)
|
||||
and TestRunningView (shows live ResultIndicators and pass/fail colour).
|
||||
Renders ReadyValues/OperationValues and the enable toggle when idle, and
|
||||
switches to live ResultIndicators with pass/fail colour while running.
|
||||
-->
|
||||
<UserControl.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
|
||||
|
||||
205
Views/UserControls/PhaseTileView.xaml
Normal file
205
Views/UserControls/PhaseTileView.xaml
Normal file
@@ -0,0 +1,205 @@
|
||||
<UserControl x:Class="HC_APTBS.Views.UserControls.PhaseTileView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
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"
|
||||
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
||||
xmlns:uc="clr-namespace:HC_APTBS.Views.UserControls"
|
||||
xmlns:vm="clr-namespace:HC_APTBS.ViewModels"
|
||||
mc:Ignorable="d"
|
||||
x:Name="Root"
|
||||
d:DataContext="{d:DesignInstance Type=vm:PhaseCardViewModel, IsDesignTimeCreatable=False}">
|
||||
<!--
|
||||
Fluent phase tile used by both the Plan and Running steps. Set
|
||||
Compact="true" in Plan to collapse the vertical indicators (showing the
|
||||
receive parameter list as chips instead) and keep the tile short.
|
||||
The hover tooltip replaces the old "Show values" toggle globally.
|
||||
-->
|
||||
<UserControl.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
|
||||
|
||||
<DataTemplate DataType="{x:Type vm:OperationValueViewModel}">
|
||||
<Grid Margin="0,1,0,1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Text="{Binding Name}" FontSize="11"
|
||||
Foreground="{DynamicResource TextFillColorSecondaryBrush}"/>
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="{Binding Value, StringFormat=F1}"
|
||||
FontSize="11" FontFamily="Consolas"
|
||||
Margin="12,0,0,0"
|
||||
Foreground="{DynamicResource TextFillColorPrimaryBrush}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- Full vertical indicator (used when NOT compact) -->
|
||||
<DataTemplate x:Key="FullIndicator" DataType="{x:Type vm:GraphicIndicatorViewModel}">
|
||||
<uc:GraphicIndicatorView/>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- Compact chip (name + expected±tolerance) for Plan step -->
|
||||
<DataTemplate x:Key="CompactIndicator" DataType="{x:Type vm:GraphicIndicatorViewModel}">
|
||||
<Border Background="{DynamicResource ControlFillColorSecondaryBrush}"
|
||||
BorderBrush="{DynamicResource ControlStrokeColorDefaultBrush}"
|
||||
BorderThickness="1" CornerRadius="8" Padding="6,1"
|
||||
Margin="0,1,3,1">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding ParameterName}" FontSize="10"
|
||||
Foreground="{DynamicResource TextFillColorPrimaryBrush}"/>
|
||||
<TextBlock Text=":" FontSize="10" Margin="1,0,2,0"
|
||||
Foreground="{DynamicResource TextFillColorSecondaryBrush}"/>
|
||||
<TextBlock FontSize="10" FontFamily="Consolas"
|
||||
Foreground="{DynamicResource TextFillColorSecondaryBrush}">
|
||||
<Run Text="{Binding ExpectedValue, StringFormat=F1, Mode=OneWay}"/>
|
||||
<Run Text="±"/>
|
||||
<Run Text="{Binding Tolerance, StringFormat=F1, Mode=OneWay}"/>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Border MinWidth="84"
|
||||
Cursor="Hand"
|
||||
ToolTipService.InitialShowDelay="200"
|
||||
ToolTipService.ShowDuration="30000"
|
||||
ToolTipService.Placement="Right">
|
||||
<Border.InputBindings>
|
||||
<MouseBinding Gesture="LeftClick"
|
||||
Command="{Binding ToggleEnabledCommand}"/>
|
||||
</Border.InputBindings>
|
||||
<Border.Style>
|
||||
<Style TargetType="Border" BasedOn="{StaticResource PhaseTile}">
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource ControlFillColorSecondaryBrush}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource AccentControlElevationBorderBrush}"/>
|
||||
</Trigger>
|
||||
<DataTrigger Binding="{Binding IsActive}" Value="True">
|
||||
<Setter Property="Background" Value="#FFE082"/>
|
||||
<Setter Property="BorderBrush" Value="#F9A825"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding IsPassed}" Value="True">
|
||||
<Setter Property="Background" Value="#C8E6C9"/>
|
||||
<Setter Property="BorderBrush" Value="#388E3C"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding IsFailed}" Value="True">
|
||||
<Setter Property="Background" Value="#FFCDD2"/>
|
||||
<Setter Property="BorderBrush" Value="#C62828"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding IsEnabled}" Value="False">
|
||||
<Setter Property="Background" Value="#3F808080"/>
|
||||
<Setter Property="BorderBrush" Value="#60808080"/>
|
||||
<Setter Property="Opacity" Value="0.6"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
|
||||
<Border.ToolTip>
|
||||
<ToolTip Padding="10" MaxWidth="260">
|
||||
<StackPanel>
|
||||
<TextBlock Text="{Binding Name}"
|
||||
FontSize="13" FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
|
||||
Margin="0,0,0,4"/>
|
||||
|
||||
<TextBlock Text="{DynamicResource Test.Critical}"
|
||||
FontSize="10" FontWeight="Bold" Foreground="#E65100"
|
||||
Margin="0,0,0,6"
|
||||
Visibility="{Binding IsCritical, Converter={StaticResource BoolToVis}}"/>
|
||||
|
||||
<StackPanel Visibility="{Binding ReadyValues.Count, FallbackValue=Collapsed}">
|
||||
<TextBlock Text="{DynamicResource Test.Required}"
|
||||
FontSize="10" FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
|
||||
Margin="0,2,0,2"/>
|
||||
<ItemsControl ItemsSource="{Binding ReadyValues}" Margin="0,0,0,4"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Visibility="{Binding OperationValues.Count, FallbackValue=Collapsed}">
|
||||
<TextBlock Text="{DynamicResource Test.TestLabel}"
|
||||
FontSize="10" FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
|
||||
Margin="0,2,0,2"/>
|
||||
<ItemsControl ItemsSource="{Binding OperationValues}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</ToolTip>
|
||||
</Border.ToolTip>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Row 0: name + critical dot (click the tile to toggle IsEnabled) -->
|
||||
<Grid Margin="0,0,0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="{Binding Name}"
|
||||
FontSize="11" FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
VerticalAlignment="Center"/>
|
||||
<Border Grid.Column="1"
|
||||
Width="8" Height="8" CornerRadius="4"
|
||||
Background="#E65100" Margin="4,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
ToolTip="{DynamicResource Test.Critical}"
|
||||
Visibility="{Binding IsCritical, Converter={StaticResource BoolToVis}}"/>
|
||||
</Grid>
|
||||
|
||||
<!-- Row 1: indicators — compact chips when Compact=true, else full bars -->
|
||||
<ItemsControl Grid.Row="1" ItemsSource="{Binding ResultIndicators}"
|
||||
Margin="0,2,0,0">
|
||||
<ItemsControl.Style>
|
||||
<Style TargetType="ItemsControl">
|
||||
<Setter Property="ItemTemplate" Value="{StaticResource FullIndicator}"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Compact, ElementName=Root}" Value="True">
|
||||
<Setter Property="ItemTemplate" Value="{StaticResource CompactIndicator}"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ItemsControl.Style>
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel Orientation="Horizontal" HorizontalAlignment="Center"/>
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
</ItemsControl>
|
||||
|
||||
<!-- Row 2: result label -->
|
||||
<TextBlock Grid.Row="2"
|
||||
Visibility="Collapsed"
|
||||
Text="{Binding ResultText}"
|
||||
FontSize="11" FontWeight="SemiBold"
|
||||
HorizontalAlignment="Center"
|
||||
Margin="0,3,0,0">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Foreground"
|
||||
Value="{DynamicResource TextFillColorSecondaryBrush}"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsPassed}" Value="True">
|
||||
<Setter Property="Foreground" Value="#2E7D32"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding IsFailed}" Value="True">
|
||||
<Setter Property="Foreground" Value="#B71C1C"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
</Border>
|
||||
</UserControl>
|
||||
31
Views/UserControls/PhaseTileView.xaml.cs
Normal file
31
Views/UserControls/PhaseTileView.xaml.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace HC_APTBS.Views.UserControls
|
||||
{
|
||||
/// <summary>
|
||||
/// Compact Fluent phase tile. Set <see cref="Compact"/>=<c>true</c> in the
|
||||
/// Plan step so the receives render as chips instead of tall vertical
|
||||
/// progress bars — keeps every section card under one screen.
|
||||
/// DataContext is expected to be a <see cref="HC_APTBS.ViewModels.PhaseCardViewModel"/>.
|
||||
/// </summary>
|
||||
public partial class PhaseTileView : UserControl
|
||||
{
|
||||
/// <summary>When true, receives render as small text chips instead of vertical indicators.</summary>
|
||||
public static readonly DependencyProperty CompactProperty =
|
||||
DependencyProperty.Register(nameof(Compact), typeof(bool), typeof(PhaseTileView),
|
||||
new PropertyMetadata(false));
|
||||
|
||||
/// <summary>Compact mode flag (see <see cref="CompactProperty"/>).</summary>
|
||||
public bool Compact
|
||||
{
|
||||
get => (bool)GetValue(CompactProperty);
|
||||
set => SetValue(CompactProperty, value);
|
||||
}
|
||||
|
||||
public PhaseTileView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="460" d:DesignWidth="260"
|
||||
d:DesignHeight="490" d:DesignWidth="260"
|
||||
IsEnabled="{Binding IsEnabled}">
|
||||
|
||||
<!-- DataContext = PumpControlViewModel (via {Binding PumpControl}) -->
|
||||
@@ -24,6 +24,7 @@
|
||||
<Setter Property="Margin" Value="0,2,0,0"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
|
||||
</UserControl.Resources>
|
||||
|
||||
<Border Style="{StaticResource PumpCard}">
|
||||
@@ -63,16 +64,16 @@
|
||||
Margin="0,4,0,2"/>
|
||||
|
||||
<!-- Vertical slider -->
|
||||
<Slider Orientation="Vertical"
|
||||
<Slider Style="{StaticResource FluentThickVerticalSlider}"
|
||||
Orientation="Vertical"
|
||||
Minimum="{Binding FbkwMin}" Maximum="{Binding FbkwMax}"
|
||||
Value="{Binding FbkwValue}"
|
||||
TickFrequency="{Binding FbkwStep}"
|
||||
TickPlacement="TopLeft"
|
||||
IsSnapToTickEnabled="True"
|
||||
AutoToolTipPrecision="2"
|
||||
Height="240" Width="32"
|
||||
Height="360" Width="52"
|
||||
HorizontalAlignment="Center"
|
||||
Focusable="False"/>
|
||||
Loaded="Slider_Loaded"/>
|
||||
|
||||
<!-- Min label -->
|
||||
<TextBlock Text="{Binding FbkwMin, StringFormat=F1}"
|
||||
@@ -123,16 +124,16 @@
|
||||
Style="{StaticResource PumpCommandLabel}"
|
||||
Margin="0,4,0,2"/>
|
||||
|
||||
<Slider Orientation="Vertical"
|
||||
<Slider Style="{StaticResource FluentThickVerticalSlider}"
|
||||
Orientation="Vertical"
|
||||
Minimum="{Binding MeMin}" Maximum="{Binding MeMax}"
|
||||
Value="{Binding MeValue}"
|
||||
TickFrequency="{Binding MeStep}"
|
||||
TickPlacement="TopLeft"
|
||||
IsSnapToTickEnabled="False"
|
||||
AutoToolTipPrecision="2"
|
||||
Height="240" Width="32"
|
||||
Height="360" Width="52"
|
||||
HorizontalAlignment="Center"
|
||||
Focusable="False"/>
|
||||
Loaded="Slider_Loaded"/>
|
||||
|
||||
<TextBlock Text="{Binding MeMin, StringFormat=F1}"
|
||||
Style="{StaticResource PumpCommandLabel}"
|
||||
@@ -180,16 +181,16 @@
|
||||
Style="{StaticResource PumpCommandLabel}"
|
||||
Margin="0,4,0,2"/>
|
||||
|
||||
<Slider Orientation="Vertical"
|
||||
<Slider Style="{StaticResource FluentThickVerticalSlider}"
|
||||
Orientation="Vertical"
|
||||
Minimum="{Binding PreInMin}" Maximum="{Binding PreInMax}"
|
||||
Value="{Binding PreInValue}"
|
||||
TickFrequency="{Binding PreInStep}"
|
||||
TickPlacement="TopLeft"
|
||||
IsSnapToTickEnabled="True"
|
||||
AutoToolTipPrecision="2"
|
||||
Height="240" Width="32"
|
||||
Height="360" Width="52"
|
||||
HorizontalAlignment="Center"
|
||||
Focusable="False"/>
|
||||
Loaded="Slider_Loaded"/>
|
||||
|
||||
<TextBlock Text="{Binding PreInMin, StringFormat=F1}"
|
||||
Style="{StaticResource PumpCommandLabel}"
|
||||
|
||||
@@ -1,9 +1,140 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace HC_APTBS.Views.UserControls
|
||||
{
|
||||
/// <summary>
|
||||
/// Pump command sliders. Code-behind only carries the click-anywhere-and-drag
|
||||
/// gesture for the custom <c>FluentThickVerticalSlider</c> template — clicking
|
||||
/// outside the thumb captures the mouse on the Slider and tracks the value
|
||||
/// against the Track's geometry until release.
|
||||
/// </summary>
|
||||
public partial class PumpCommandsCard : UserControl
|
||||
{
|
||||
public PumpCommandsCard() => InitializeComponent();
|
||||
|
||||
/// <summary>
|
||||
/// Wires the click-anywhere-and-drag handlers using
|
||||
/// <c>handledEventsToo: true</c> so they fire even if a class-level
|
||||
/// handler (e.g. <c>Slider.OnPreviewMouseLeftButtonDown</c> when
|
||||
/// <c>IsMoveToPointEnabled</c> is on) marks the event handled.
|
||||
/// </summary>
|
||||
private void Slider_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is not Slider slider) return;
|
||||
slider.AddHandler(PreviewMouseLeftButtonDownEvent,
|
||||
new MouseButtonEventHandler(Slider_PreviewMouseLeftButtonDown), true);
|
||||
slider.AddHandler(PreviewMouseLeftButtonUpEvent,
|
||||
new MouseButtonEventHandler(Slider_PreviewMouseLeftButtonUp), true);
|
||||
slider.AddHandler(MouseMoveEvent,
|
||||
new MouseEventHandler(Slider_MouseMove), true);
|
||||
slider.AddHandler(PreviewMouseWheelEvent,
|
||||
new MouseWheelEventHandler(Slider_PreviewMouseWheel), true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adjusts the Slider's value by one step per wheel notch while the cursor
|
||||
/// is over the slider. The step is taken from <see cref="Slider.TickFrequency"/>
|
||||
/// when available, falling back to <see cref="RangeBase.SmallChange"/>, then
|
||||
/// 1% of the slider's range. The event is marked handled so the wheel doesn't
|
||||
/// also scroll a parent <c>ScrollViewer</c>.
|
||||
/// </summary>
|
||||
private void Slider_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
|
||||
{
|
||||
if (sender is not Slider slider) return;
|
||||
|
||||
double step = slider.TickFrequency;
|
||||
if (step <= 0) step = slider.SmallChange;
|
||||
if (step <= 0) step = (slider.Maximum - slider.Minimum) * 0.01;
|
||||
if (step <= 0) return;
|
||||
|
||||
double notches = e.Delta / 120.0;
|
||||
double newValue = slider.Value + notches * step;
|
||||
if (newValue < slider.Minimum) newValue = slider.Minimum;
|
||||
else if (newValue > slider.Maximum) newValue = slider.Maximum;
|
||||
slider.Value = newValue;
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// On press outside the Thumb, captures the mouse on the Slider so the
|
||||
/// user can drag from any point on the track in one motion.
|
||||
/// </summary>
|
||||
private void Slider_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (sender is not Slider slider) return;
|
||||
if (slider.Template?.FindName("PART_Track", slider) is not Track track) return;
|
||||
|
||||
// Direct thumb press — let the Thumb's own drag handle it.
|
||||
if (IsClickInsideThumb(e.OriginalSource as DependencyObject, track.Thumb)) return;
|
||||
|
||||
UpdateValueFromPoint(slider, e.GetPosition(slider));
|
||||
slider.CaptureMouse();
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// While the Slider has mouse capture, continuously map the cursor
|
||||
/// position back to a Slider value.
|
||||
/// </summary>
|
||||
private void Slider_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (sender is not Slider slider || !slider.IsMouseCaptured) return;
|
||||
UpdateValueFromPoint(slider, e.GetPosition(slider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases the Slider's mouse capture on button-up.
|
||||
/// </summary>
|
||||
private void Slider_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (sender is Slider slider && slider.IsMouseCaptured)
|
||||
{
|
||||
slider.ReleaseMouseCapture();
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps a cursor position (in Slider coordinates) to a Slider value using
|
||||
/// the Slider's own bounds. Bypasses <c>Track.ValueFromPoint</c>, which
|
||||
/// can return scaled values for custom templates whose RepeatButton sizes
|
||||
/// don't match the Track's expected layout.
|
||||
/// </summary>
|
||||
private static void UpdateValueFromPoint(Slider slider, Point pointInSlider)
|
||||
{
|
||||
bool vertical = slider.Orientation == Orientation.Vertical;
|
||||
double length = vertical ? slider.ActualHeight : slider.ActualWidth;
|
||||
if (length <= 0) return;
|
||||
|
||||
double pos = vertical ? pointInSlider.Y : pointInSlider.X;
|
||||
double fraction = pos / length;
|
||||
if (fraction < 0) fraction = 0;
|
||||
else if (fraction > 1) fraction = 1;
|
||||
|
||||
// Vertical (default): top = Maximum. Horizontal (default): left = Minimum.
|
||||
// IsDirectionReversed flips that on each axis.
|
||||
bool flip = vertical ? !slider.IsDirectionReversed : slider.IsDirectionReversed;
|
||||
if (flip) fraction = 1.0 - fraction;
|
||||
|
||||
double value = slider.Minimum + fraction * (slider.Maximum - slider.Minimum);
|
||||
if (value < slider.Minimum) value = slider.Minimum;
|
||||
else if (value > slider.Maximum) value = slider.Maximum;
|
||||
slider.Value = value;
|
||||
}
|
||||
|
||||
private static bool IsClickInsideThumb(DependencyObject? src, Thumb? thumb)
|
||||
{
|
||||
if (thumb is null || src is null) return false;
|
||||
for (var node = src; node is not null; node = VisualTreeHelper.GetParent(node))
|
||||
{
|
||||
if (node == thumb) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="360" d:DesignWidth="320">
|
||||
d:DesignHeight="430" d:DesignWidth="490">
|
||||
|
||||
<!-- DataContext = PumpIdentificationViewModel (via {Binding Identification}) -->
|
||||
<UserControl.Resources>
|
||||
@@ -13,15 +13,15 @@
|
||||
|
||||
<Style x:Key="IdLabel" TargetType="TextBlock">
|
||||
<Setter Property="FontFamily" Value="{DynamicResource ContentControlThemeFontFamily}"/>
|
||||
<Setter Property="FontSize" Value="11"/>
|
||||
<Setter Property="FontSize" Value="15"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextFillColorSecondaryBrush}"/>
|
||||
<Setter Property="Width" Value="88"/>
|
||||
<Setter Property="Width" Value="100"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="IdValue" TargetType="TextBlock">
|
||||
<Setter Property="FontFamily" Value="Consolas"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="FontSize" Value="16"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextFillColorPrimaryBrush}"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="TextTrimming" Value="CharacterEllipsis"/>
|
||||
@@ -73,7 +73,7 @@
|
||||
</StackPanel>
|
||||
|
||||
<!-- ── ECU info: two columns ─────────────────────────────────── -->
|
||||
<Grid>
|
||||
<Grid HorizontalAlignment="Stretch" DockPanel.Dock="Top">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="8"/>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<UserControl x:Class="HC_APTBS.Views.UserControls.PumpIdentificationView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
>
|
||||
|
||||
<UserControl.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
|
||||
|
||||
@@ -27,10 +27,11 @@
|
||||
Style="{StaticResource PumpCardHeader}" Margin="0"/>
|
||||
</DockPanel>
|
||||
|
||||
<!-- ── Status displays (docked bottom so chart gets the middle) ── -->
|
||||
<!-- ── Status displays + BIP (docked bottom so chart gets the middle) ── -->
|
||||
<StackPanel DockPanel.Dock="Bottom" Margin="0,8,0,0">
|
||||
<uc:StatusDisplayView DataContext="{Binding StatusDisplay1}" Margin="0,0,0,8"/>
|
||||
<uc:StatusDisplayView DataContext="{Binding StatusDisplay2}"/>
|
||||
<uc:StatusDisplayView DataContext="{Binding StatusDisplay2}" Margin="0,0,0,8"/>
|
||||
<uc:BipDisplayView DataContext="{Binding BipDisplay}"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- ── RPM chart (docked bottom of the upper area) ──────────── -->
|
||||
|
||||
@@ -126,7 +126,7 @@
|
||||
<!-- Pump selector ComboBox -->
|
||||
<ComboBox ItemsSource="{Binding Identification.PumpIds}"
|
||||
SelectedItem="{Binding Identification.SelectedPumpId}"
|
||||
MinWidth="200" FontSize="13" Height="32"
|
||||
MinWidth="200" FontSize="13" Height="36"
|
||||
VerticalContentAlignment="Center"/>
|
||||
|
||||
<!-- Model / Brand badge -->
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
<UserControl x:Class="HC_APTBS.Views.UserControls.TestDoneView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
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"
|
||||
xmlns:uc="clr-namespace:HC_APTBS.Views.UserControls"
|
||||
xmlns:vmp="clr-namespace:HC_APTBS.ViewModels.Pages"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="560" d:DesignWidth="900"
|
||||
Background="#FFEDEDED" Foreground="Black"
|
||||
d:DataContext="{d:DesignInstance Type=vmp:TestsPageViewModel, IsDesignTimeCreatable=False}">
|
||||
<!--
|
||||
Done step of the Tests wizard. DataContext: TestsPageViewModel.
|
||||
Shows PASS/FAIL banner, embedded ResultDisplayView, and navigation buttons.
|
||||
-->
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Overall pass/fail banner -->
|
||||
<Border Padding="16,12" Margin="0,0,0,4">
|
||||
<Border.Style>
|
||||
<Style TargetType="Border">
|
||||
<Setter Property="Background" Value="#FFCDD2"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding ResultDisplay.OverallPassed}" Value="True">
|
||||
<Setter Property="Background" Value="#C8E6C9"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock FontSize="26" FontWeight="Bold" VerticalAlignment="Center">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="#B71C1C"/>
|
||||
<Setter Property="Text" Value="{DynamicResource Test.Done.Failed}"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding ResultDisplay.OverallPassed}" Value="True">
|
||||
<Setter Property="Foreground" Value="#2E7D32"/>
|
||||
<Setter Property="Text" Value="{DynamicResource Test.Done.Passed}"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
<TextBlock Text="{Binding ResultDisplay.TestName}"
|
||||
FontSize="14" FontStyle="Italic"
|
||||
Foreground="#555"
|
||||
VerticalAlignment="Bottom"
|
||||
Margin="16,0,0,4"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Inline results table -->
|
||||
<uc:ResultDisplayView Grid.Row="1"
|
||||
DataContext="{Binding ResultDisplay}"
|
||||
Margin="4"/>
|
||||
|
||||
<!-- Action row -->
|
||||
<Border Grid.Row="2" Padding="10,8"
|
||||
BorderBrush="#DDD" BorderThickness="0,1,0,0"
|
||||
Background="White">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button Grid.Column="0"
|
||||
Content="{DynamicResource Test.Done.ViewFullResults}"
|
||||
Command="{Binding ViewFullResultsCommand}"
|
||||
Padding="14,6" FontSize="12"/>
|
||||
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal">
|
||||
<Button Content="{DynamicResource Test.Report}"
|
||||
Command="{Binding Root.GenerateReportCommand}"
|
||||
Padding="14,6" FontSize="12" Margin="0,0,8,0"/>
|
||||
<Button Content="{DynamicResource Test.Done.RunAgain}"
|
||||
Command="{Binding RunAgainCommand}"
|
||||
Padding="18,6" FontSize="14" FontWeight="Bold"
|
||||
Background="#1565C0" Foreground="White" BorderThickness="0"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -1,16 +0,0 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace HC_APTBS.Views.UserControls
|
||||
{
|
||||
/// <summary>
|
||||
/// Done step of the Tests wizard — PASS/FAIL banner, results table, Run Again.
|
||||
/// DataContext is expected to be a <see cref="HC_APTBS.ViewModels.Pages.TestsPageViewModel"/>.
|
||||
/// </summary>
|
||||
public partial class TestDoneView : UserControl
|
||||
{
|
||||
public TestDoneView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
<UserControl x:Class="HC_APTBS.Views.UserControls.TestPlanView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
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"
|
||||
xmlns:uc="clr-namespace:HC_APTBS.Views.UserControls"
|
||||
xmlns:vm="clr-namespace:HC_APTBS.ViewModels"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="520" d:DesignWidth="900"
|
||||
Background="#FFEDEDED" Foreground="Black"
|
||||
d:DataContext="{d:DesignInstance Type=vm:TestPanelViewModel, IsDesignTimeCreatable=False}">
|
||||
<!--
|
||||
Plan step of the Tests wizard. DataContext: TestPanelViewModel.
|
||||
The operator picks which test phases to run — no Start/Stop/Report buttons,
|
||||
those live on the Preconditions step and in the wizard footer.
|
||||
-->
|
||||
<UserControl.Resources>
|
||||
<DataTemplate DataType="{x:Type vm:TestSectionViewModel}">
|
||||
<uc:TestSectionView/>
|
||||
</DataTemplate>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Toolbar -->
|
||||
<Border BorderBrush="Gray" BorderThickness="0,0,0,1" Padding="8,4">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<CheckBox IsChecked="{Binding ShowOperationValues}"
|
||||
VerticalAlignment="Center">
|
||||
<TextBlock Text="{DynamicResource Test.ShowValues}" FontSize="12"/>
|
||||
</CheckBox>
|
||||
|
||||
<Button Grid.Column="1" Margin="12,0,0,0"
|
||||
Command="{Binding ToggleCheckAllCommand}"
|
||||
Padding="6,2" ToolTip="Enable/disable all phases">
|
||||
<TextBlock Text="{DynamicResource Test.CheckAll}" FontSize="11"/>
|
||||
</Button>
|
||||
|
||||
<TextBlock Grid.Column="3" VerticalAlignment="Center"
|
||||
Foreground="DimGray" FontSize="12" Margin="0,0,4,0">
|
||||
<Run Text="~"/>
|
||||
<Run Text="{Binding RemainingSeconds, Mode=OneWay}"/>
|
||||
<Run Text="{DynamicResource Test.SecondsRemaining}"/>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- Test sections -->
|
||||
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
|
||||
<ItemsControl ItemsSource="{Binding Tests}" Margin="4"/>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -1,16 +0,0 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace HC_APTBS.Views.UserControls
|
||||
{
|
||||
/// <summary>
|
||||
/// Plan step of the Tests wizard — phase enable/disable and duration preview.
|
||||
/// DataContext is expected to be a <see cref="HC_APTBS.ViewModels.TestPanelViewModel"/>.
|
||||
/// </summary>
|
||||
public partial class TestPlanView : UserControl
|
||||
{
|
||||
public TestPlanView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,173 +0,0 @@
|
||||
<UserControl x:Class="HC_APTBS.Views.UserControls.TestPreconditionsView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
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"
|
||||
xmlns:vm="clr-namespace:HC_APTBS.ViewModels"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="520" d:DesignWidth="680"
|
||||
d:DataContext="{d:DesignInstance Type=vm:TestPreconditionsViewModel, IsDesignTimeCreatable=False}">
|
||||
<!--
|
||||
Preconditions checklist (Tests page wizard step 4b).
|
||||
DataContext: TestPreconditionsViewModel.
|
||||
Rows auto-refresh as underlying properties change; Start button is disabled
|
||||
until AllPassed is true.
|
||||
-->
|
||||
<UserControl.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Border Background="White" BorderBrush="#DDD" BorderThickness="1" CornerRadius="4" Padding="14">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Title -->
|
||||
<TextBlock Grid.Row="0"
|
||||
Text="{DynamicResource Test.Precheck.Title}"
|
||||
FontSize="16" FontWeight="SemiBold" Foreground="#222"
|
||||
Margin="0,0,0,10"/>
|
||||
|
||||
<!-- Auth gate (only when a required test has RequiresAuth=true) -->
|
||||
<Border Grid.Row="1"
|
||||
Background="#FFF8E1" BorderBrush="#F0C24A" BorderThickness="1"
|
||||
CornerRadius="3" Padding="10,8" Margin="0,0,0,10"
|
||||
Visibility="{Binding IsAuthRequired, Converter={StaticResource BoolToVis}}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Grid.Column="0" VerticalAlignment="Center">
|
||||
<TextBlock Text="{DynamicResource Test.Precheck.AuthBanner}"
|
||||
FontSize="12" FontWeight="SemiBold" Foreground="#7A5A00"/>
|
||||
<TextBlock Text="{Binding TestAuth.AuthenticatedUser}"
|
||||
FontSize="11" Foreground="#7A5A00"
|
||||
Visibility="{Binding TestAuth.IsAuthenticated, Converter={StaticResource BoolToVis}}"/>
|
||||
</StackPanel>
|
||||
<Button Grid.Column="1"
|
||||
Content="{DynamicResource Test.Precheck.AuthButton}"
|
||||
Command="{Binding TestAuth.AuthenticateCommand}"
|
||||
Padding="10,4" FontSize="12"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- Checklist -->
|
||||
<ScrollViewer Grid.Row="2" VerticalScrollBarVisibility="Auto">
|
||||
<ItemsControl ItemsSource="{Binding Items}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="{x:Type vm:PreconditionItemViewModel}">
|
||||
<Border BorderBrush="#EEE" BorderThickness="0,0,0,1" Padding="0,8">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="32"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Status glyph -->
|
||||
<Border Grid.Column="0" Width="20" Height="20"
|
||||
CornerRadius="10" VerticalAlignment="Center"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="0,0,8,0">
|
||||
<Border.Style>
|
||||
<Style TargetType="Border">
|
||||
<Setter Property="Background" Value="#E74C3C"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsSatisfied}" Value="True">
|
||||
<Setter Property="Background" Value="#26C200"/>
|
||||
</DataTrigger>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding IsSatisfied}" Value="False"/>
|
||||
<Condition Binding="{Binding IsRequired}" Value="False"/>
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="Background" Value="#BBB"/>
|
||||
</MultiDataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Foreground="White" FontSize="12" FontWeight="Bold">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Text" Value="✕"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsSatisfied}" Value="True">
|
||||
<Setter Property="Text" Value="✓"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
</Border>
|
||||
|
||||
<!-- Label + remediation text -->
|
||||
<StackPanel Grid.Column="1" VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding Label}" FontSize="13" Foreground="#222"/>
|
||||
<TextBlock Text="{Binding RemediationText}"
|
||||
FontSize="11" Foreground="#888">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Visibility" Value="Visible"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsSatisfied}" Value="True">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Fix-it button -->
|
||||
<Button Grid.Column="2"
|
||||
Content="{DynamicResource Test.Precheck.FixButton}"
|
||||
Command="{Binding NavigateToFixCommand}"
|
||||
Padding="8,3" FontSize="11" Margin="8,0,0,0"
|
||||
Visibility="{Binding HasRemediation, Converter={StaticResource BoolToVis}}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
|
||||
<!-- Start button row -->
|
||||
<Grid Grid.Row="3" Margin="0,14,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" VerticalAlignment="Center"
|
||||
FontSize="12" Foreground="#666"
|
||||
Text="{DynamicResource Test.Precheck.NotReady}">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Visibility" Value="Visible"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding AllPassed}" Value="True">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
<TextBlock Grid.Column="0" VerticalAlignment="Center"
|
||||
FontSize="12" Foreground="#26C200" FontWeight="SemiBold"
|
||||
Text="{DynamicResource Test.Precheck.Ready}"
|
||||
Visibility="{Binding AllPassed, Converter={StaticResource BoolToVis}}"/>
|
||||
|
||||
<Button Grid.Column="1"
|
||||
Content="{DynamicResource Test.StartTest}"
|
||||
Command="{Binding StartTestCommand}"
|
||||
Padding="18,6" FontSize="14" FontWeight="Bold"
|
||||
Background="#26C200" Foreground="White" BorderThickness="0"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
</UserControl>
|
||||
@@ -1,16 +0,0 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace HC_APTBS.Views.UserControls
|
||||
{
|
||||
/// <summary>
|
||||
/// Preconditions checklist for the Tests page wizard (§4b).
|
||||
/// DataContext is expected to be a <see cref="HC_APTBS.ViewModels.TestPreconditionsViewModel"/>.
|
||||
/// </summary>
|
||||
public partial class TestPreconditionsView : UserControl
|
||||
{
|
||||
public TestPreconditionsView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
<UserControl x:Class="HC_APTBS.Views.UserControls.TestRunningView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
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"
|
||||
xmlns:uc="clr-namespace:HC_APTBS.Views.UserControls"
|
||||
xmlns:vm="clr-namespace:HC_APTBS.ViewModels"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="640" d:DesignWidth="1000"
|
||||
Background="#FFEDEDED" Foreground="Black"
|
||||
d:DataContext="{d:DesignInstance Type=vm:TestPanelViewModel, IsDesignTimeCreatable=False}">
|
||||
<!--
|
||||
Running step of the Tests wizard. DataContext: TestPanelViewModel.
|
||||
Shows the active phase countdown, live phase-card updates, and the flowmeter /
|
||||
angle visuals. Pause / Retry-phase / Skip-phase buttons are rendered disabled —
|
||||
their IBenchService wiring is deferred (see docs/gap-test-running-controls.md).
|
||||
-->
|
||||
<UserControl.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
|
||||
|
||||
<DataTemplate DataType="{x:Type vm:TestSectionViewModel}">
|
||||
<uc:TestSectionView/>
|
||||
</DataTemplate>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/> <!-- Phase header + countdown -->
|
||||
<RowDefinition Height="*"/> <!-- Sections + live charts -->
|
||||
<RowDefinition Height="Auto"/> <!-- Control row -->
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Phase header + countdown + progress -->
|
||||
<Border Padding="10,8" BorderBrush="#DDD" BorderThickness="0,0,0,1"
|
||||
Background="White">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding CurrentPhaseName}"
|
||||
FontSize="16" FontWeight="SemiBold"
|
||||
Foreground="#222"/>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,1,0,0">
|
||||
<TextBlock Text="{Binding SectionLabel}"
|
||||
FontSize="11" FontStyle="Italic"
|
||||
Foreground="#666"/>
|
||||
<TextBlock Text="{Binding StatusText}"
|
||||
FontSize="11" FontStyle="Italic"
|
||||
Foreground="Gray" Margin="8,0,0,0"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal"
|
||||
VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding PhaseRemainingSeconds, Mode=OneWay}"
|
||||
FontSize="32" FontFamily="Impact"
|
||||
Foreground="#1565C0"
|
||||
VerticalAlignment="Center"/>
|
||||
<TextBlock Text="s" FontSize="18"
|
||||
Foreground="#1565C0"
|
||||
VerticalAlignment="Bottom" Margin="2,0,0,4"/>
|
||||
<TextBlock Foreground="#999" FontSize="11"
|
||||
VerticalAlignment="Bottom" Margin="8,0,0,4">
|
||||
<Run Text="/ "/>
|
||||
<Run Text="{Binding PhaseTotalSeconds, Mode=OneWay}"/>
|
||||
<Run Text="s"/>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<ProgressBar Grid.Row="1" Grid.ColumnSpan="2"
|
||||
Minimum="0" Maximum="1"
|
||||
Value="{Binding PhaseProgress, Mode=OneWay}"
|
||||
Height="6" Margin="0,6,0,0"
|
||||
Background="#EEE" Foreground="#1565C0"
|
||||
BorderThickness="0"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- Main body: test sections on left, live charts on right -->
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="420"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Live phase-card list (read-only during run, cards colour themselves) -->
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||
<ItemsControl ItemsSource="{Binding Tests}" Margin="4"/>
|
||||
</ScrollViewer>
|
||||
|
||||
<!-- Charts + angle display -->
|
||||
<Grid Grid.Column="1" Margin="4">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<uc:FlowmeterChartView Grid.Row="0"
|
||||
DataContext="{Binding DataContext.FlowmeterChart.Delivery,
|
||||
RelativeSource={RelativeSource AncestorType=Window}}"/>
|
||||
|
||||
<uc:FlowmeterChartView Grid.Row="1"
|
||||
DataContext="{Binding DataContext.FlowmeterChart.Over,
|
||||
RelativeSource={RelativeSource AncestorType=Window}}"
|
||||
Margin="0,4,0,0"/>
|
||||
|
||||
<uc:AngleDisplayView Grid.Row="2"
|
||||
DataContext="{Binding DataContext.AngleDisplay,
|
||||
RelativeSource={RelativeSource AncestorType=Window}}"
|
||||
Margin="0,4,0,0"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<!-- Control row -->
|
||||
<Border Grid.Row="2" Padding="10,8"
|
||||
BorderBrush="#DDD" BorderThickness="0,1,0,0"
|
||||
Background="White">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Grid.Column="0">
|
||||
<Button Content="{DynamicResource Test.Running.Pause}"
|
||||
IsEnabled="False"
|
||||
ToolTip="{DynamicResource Test.Running.ComingSoon}"
|
||||
Padding="12,5" FontSize="12" Margin="0,0,6,0"/>
|
||||
|
||||
<Button Content="{DynamicResource Test.Running.Retry}"
|
||||
IsEnabled="False"
|
||||
ToolTip="{DynamicResource Test.Running.ComingSoon}"
|
||||
Padding="12,5" FontSize="12" Margin="0,0,6,0"/>
|
||||
|
||||
<Button Content="{DynamicResource Test.Running.Skip}"
|
||||
IsEnabled="False"
|
||||
ToolTip="{DynamicResource Test.Running.ComingSoon}"
|
||||
Padding="12,5" FontSize="12"/>
|
||||
</StackPanel>
|
||||
|
||||
<Button Grid.Column="2"
|
||||
Content="{DynamicResource Test.Running.Abort}"
|
||||
Command="{Binding DataContext.TestsPage.AbortCommand,
|
||||
RelativeSource={RelativeSource AncestorType=Window}}"
|
||||
Padding="18,6" FontSize="14" FontWeight="Bold"
|
||||
Background="#C62828" Foreground="White" BorderThickness="0"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -1,16 +0,0 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace HC_APTBS.Views.UserControls
|
||||
{
|
||||
/// <summary>
|
||||
/// Running step of the Tests wizard — live phase progress, flowmeter charts, abort.
|
||||
/// DataContext is expected to be a <see cref="HC_APTBS.ViewModels.TestPanelViewModel"/>.
|
||||
/// </summary>
|
||||
public partial class TestRunningView : UserControl
|
||||
{
|
||||
public TestRunningView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
124
Views/UserControls/TestSectionCard.xaml
Normal file
124
Views/UserControls/TestSectionCard.xaml
Normal file
@@ -0,0 +1,124 @@
|
||||
<UserControl x:Class="HC_APTBS.Views.UserControls.TestSectionCard"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
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"
|
||||
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
||||
xmlns:uc="clr-namespace:HC_APTBS.Views.UserControls"
|
||||
xmlns:vm="clr-namespace:HC_APTBS.ViewModels"
|
||||
mc:Ignorable="d"
|
||||
x:Name="Root"
|
||||
Width="Auto"
|
||||
d:DataContext="{d:DesignInstance Type=vm:TestSectionViewModel, IsDesignTimeCreatable=False}">
|
||||
<!--
|
||||
Fluent card representing one test type (WL, DFI, F, SVME, UP, PFP).
|
||||
DataContext: TestSectionViewModel. Compact="true" renders phase tiles as
|
||||
chips (idle planning view); Compact="false" renders them with full vertical
|
||||
live-bar indicators (while a test is running).
|
||||
-->
|
||||
<UserControl.Resources>
|
||||
<DataTemplate DataType="{x:Type vm:PhaseCardViewModel}">
|
||||
<uc:PhaseTileView Compact="{Binding Compact,
|
||||
RelativeSource={RelativeSource AncestorType=uc:TestSectionCard}}"/>
|
||||
</DataTemplate>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Border Padding="10" Margin="4" Cursor="Hand">
|
||||
<Border.InputBindings>
|
||||
<MouseBinding Gesture="LeftClick"
|
||||
Command="{Binding ToggleAllPhasesCommand}"/>
|
||||
</Border.InputBindings>
|
||||
<Border.Style>
|
||||
<Style TargetType="Border" BasedOn="{StaticResource PumpCard}">
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource CardBackgroundFillColorSecondaryBrush}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource AccentControlElevationBorderBrush}"/>
|
||||
</Trigger>
|
||||
<DataTrigger Binding="{Binding IsActiveTest}" Value="True">
|
||||
<Setter Property="BorderBrush" Value="#F9A825"/>
|
||||
<Setter Property="BorderThickness" Value="2"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Header row -->
|
||||
<Grid Margin="0,0,0,6">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<ui:SymbolIcon Grid.Column="0"
|
||||
Symbol="{Binding IconSymbol}"
|
||||
FontSize="18"
|
||||
Foreground="{DynamicResource AccentTextFillColorPrimaryBrush}"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"/>
|
||||
|
||||
<StackPanel Grid.Column="1" VerticalAlignment="Center">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding TestName}"
|
||||
FontSize="15" FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextFillColorPrimaryBrush}"/>
|
||||
<TextBlock Text="{Binding Description}"
|
||||
FontSize="11" FontStyle="Italic"
|
||||
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
|
||||
Margin="8,0,0,0" VerticalAlignment="Bottom"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Metadata pills -->
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal" Margin="0,0,0,6">
|
||||
<Border Style="{StaticResource TestMetaPill}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{DynamicResource Test.Plan.MetaCond}"
|
||||
Style="{StaticResource TestMetaPillText}"/>
|
||||
<TextBlock Style="{StaticResource TestMetaPillText}" Margin="3,0,0,0">
|
||||
<Run Text="{Binding ConditioningTimeSec, Mode=OneWay}"/><Run Text="s"/>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border Style="{StaticResource TestMetaPill}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{DynamicResource Test.Plan.MetaMeas}"
|
||||
Style="{StaticResource TestMetaPillText}"/>
|
||||
<TextBlock Style="{StaticResource TestMetaPillText}" Margin="3,0,0,0">
|
||||
<Run Text="{Binding MeasurementTimeSec, Mode=OneWay}"/><Run Text="s"/>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border Style="{StaticResource TestMetaPill}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{DynamicResource Test.Plan.MetaMps}"
|
||||
Style="{StaticResource TestMetaPillText}"/>
|
||||
<TextBlock Style="{StaticResource TestMetaPillText}" Margin="3,0,0,0"
|
||||
Text="{Binding MeasurementsPerSecond, StringFormat=F1, Mode=OneWay}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
|
||||
|
||||
|
||||
<!-- Phase tiles (wrap horizontally inside the card) -->
|
||||
<ItemsControl Grid.Row="2" ItemsSource="{Binding Phases}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal"/>
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
</ItemsControl>
|
||||
</Grid>
|
||||
</Border>
|
||||
</UserControl>
|
||||
31
Views/UserControls/TestSectionCard.xaml.cs
Normal file
31
Views/UserControls/TestSectionCard.xaml.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace HC_APTBS.Views.UserControls
|
||||
{
|
||||
/// <summary>
|
||||
/// Fluent section card hosting a test type's phase tiles.
|
||||
/// Set <see cref="Compact"/>=<c>true</c> to render chips (idle state) or
|
||||
/// <c>false</c> to render full vertical live-bar indicators (running state).
|
||||
/// DataContext is expected to be a <see cref="HC_APTBS.ViewModels.TestSectionViewModel"/>.
|
||||
/// </summary>
|
||||
public partial class TestSectionCard : UserControl
|
||||
{
|
||||
/// <summary>Forwarded to every child <see cref="PhaseTileView.Compact"/>.</summary>
|
||||
public static readonly DependencyProperty CompactProperty =
|
||||
DependencyProperty.Register(nameof(Compact), typeof(bool), typeof(TestSectionCard),
|
||||
new PropertyMetadata(false));
|
||||
|
||||
/// <summary>Compact mode flag (see <see cref="CompactProperty"/>).</summary>
|
||||
public bool Compact
|
||||
{
|
||||
get => (bool)GetValue(CompactProperty);
|
||||
set => SetValue(CompactProperty, value);
|
||||
}
|
||||
|
||||
public TestSectionCard()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
<UserControl x:Class="HC_APTBS.Views.UserControls.TestSectionView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
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"
|
||||
xmlns:uc="clr-namespace:HC_APTBS.Views.UserControls"
|
||||
xmlns:vm="clr-namespace:HC_APTBS.ViewModels"
|
||||
mc:Ignorable="d"
|
||||
d:DataContext="{d:DesignInstance Type=vm:TestSectionViewModel, IsDesignTimeCreatable=False}">
|
||||
<!--
|
||||
Expander header + horizontal list of phase cards. DataContext: TestSectionViewModel.
|
||||
Used by TestPlanView and TestRunningView — both show the same structure, differing
|
||||
only in which card state is currently highlighted.
|
||||
-->
|
||||
<UserControl.Resources>
|
||||
<DataTemplate DataType="{x:Type vm:PhaseCardViewModel}">
|
||||
<uc:PhaseCardView/>
|
||||
</DataTemplate>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Expander IsExpanded="{Binding IsExpanded}" Margin="0,2,0,0">
|
||||
<Expander.Header>
|
||||
<Border Padding="4,2" CornerRadius="2">
|
||||
<Border.Style>
|
||||
<Style TargetType="Border">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsActiveTest}" Value="True">
|
||||
<Setter Property="Background" Value="#FFFFF3CD"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Text="{Binding TestName}"
|
||||
FontSize="20" FontFamily="Impact" FontStyle="Italic"
|
||||
VerticalAlignment="Center" Foreground="Black"
|
||||
Padding="4,0"/>
|
||||
|
||||
<TextBlock Grid.Column="1"
|
||||
Text="{Binding Description}"
|
||||
FontSize="14" FontStyle="Italic" FontFamily="Impact"
|
||||
VerticalAlignment="Bottom" Foreground="Gray"
|
||||
Padding="8,0,0,3"/>
|
||||
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal"
|
||||
VerticalAlignment="Center" Margin="16,0,0,0">
|
||||
<TextBlock FontSize="10" Foreground="DimGray">
|
||||
<Run Text="{DynamicResource Test.Condition}"/>
|
||||
<Run Text="{Binding ConditioningTimeSec, Mode=OneWay}"/>
|
||||
<Run Text="s"/>
|
||||
</TextBlock>
|
||||
<TextBlock FontSize="10" Foreground="DimGray" Margin="10,0,0,0">
|
||||
<Run Text="{DynamicResource Test.Measurement}"/>
|
||||
<Run Text="{Binding MeasurementTimeSec, Mode=OneWay}"/>
|
||||
<Run Text="s"/>
|
||||
</TextBlock>
|
||||
<TextBlock FontSize="10" Foreground="DimGray" Margin="10,0,0,0">
|
||||
<Run Text="{DynamicResource Test.MeasPerSec}"/>
|
||||
<Run Text="{Binding MeasurementsPerSecond, StringFormat=F1, Mode=OneWay}"/>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<CheckBox Grid.Column="3"
|
||||
IsChecked="{Binding AllPhasesChecked}"
|
||||
VerticalAlignment="Center" Margin="8,0"
|
||||
ToolTip="Enable/disable all phases in this test"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Expander.Header>
|
||||
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Auto"
|
||||
VerticalScrollBarVisibility="Disabled"
|
||||
Padding="0,4">
|
||||
<ItemsControl ItemsSource="{Binding Phases}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal"/>
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</Expander>
|
||||
</UserControl>
|
||||
@@ -1,16 +0,0 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace HC_APTBS.Views.UserControls
|
||||
{
|
||||
/// <summary>
|
||||
/// One test section — Expander header plus the horizontal row of phase cards.
|
||||
/// DataContext is expected to be a <see cref="HC_APTBS.ViewModels.TestSectionViewModel"/>.
|
||||
/// </summary>
|
||||
public partial class TestSectionView : UserControl
|
||||
{
|
||||
public TestSectionView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,6 +84,12 @@
|
||||
Visibility="{Binding IsCancellable, Converter={StaticResource BoolToVis}}"
|
||||
Height="30" Padding="12,4"/>
|
||||
|
||||
<ui:Button Content="{DynamicResource Dialog.Unlock.Retry}"
|
||||
Command="{Binding RetryCommand}"
|
||||
Appearance="Primary"
|
||||
Visibility="{Binding CanRetry, Converter={StaticResource BoolToVis}}"
|
||||
Height="30" Padding="12,4" Margin="0,0,6,0"/>
|
||||
|
||||
<ui:Button Content="{DynamicResource Common.Dismiss}"
|
||||
Click="OnDismissClick"
|
||||
Appearance="Secondary"
|
||||
|
||||
Reference in New Issue
Block a user