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>
148 lines
7.9 KiB
XML
148 lines
7.9 KiB
XML
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
|
xmlns:conv="clr-namespace:HC_APTBS.Converters">
|
|
|
|
<!-- Shared converter: enum ↔ int for TabControl.SelectedIndex -->
|
|
<conv:EnumToIntConverter x:Key="EnumToInt"/>
|
|
|
|
<!-- TabControl that hides its tab strip so the nav rail is the only selector -->
|
|
<Style x:Key="HiddenTabsTabControl" TargetType="TabControl">
|
|
<Setter Property="BorderThickness" Value="0"/>
|
|
<Setter Property="Padding" Value="0"/>
|
|
<Setter Property="Background" Value="Transparent"/>
|
|
<Setter Property="Template">
|
|
<Setter.Value>
|
|
<ControlTemplate TargetType="TabControl">
|
|
<Grid>
|
|
<!-- TabPanel renders the headers; we collapse it entirely -->
|
|
<TabPanel x:Name="HeaderPanel" Visibility="Collapsed"
|
|
IsItemsHost="True"/>
|
|
<ContentPresenter x:Name="PART_SelectedContentHost"
|
|
ContentSource="SelectedContent"/>
|
|
</Grid>
|
|
</ControlTemplate>
|
|
</Setter.Value>
|
|
</Setter>
|
|
</Style>
|
|
|
|
<!--
|
|
Boxy nav item template: vertical icon-over-label tile inside a rounded
|
|
card. Replaces WPF-UI's default horizontal row layout
|
|
(LeftCompactNavigationViewItemTemplate) when assigned to
|
|
NavigationView.ItemTemplate.
|
|
|
|
Mechanism: WPF-UI's NavigationView assigns each NavigationViewItem's
|
|
Template programmatically via UpdateMenuItemsTemplate (in
|
|
NavigationView.Base.cs). A direct property assignment beats any
|
|
Style.Setter, so the only reliable way to override is to provide a
|
|
keyed ControlTemplate and assign it to NavigationView.ItemTemplate
|
|
from MainWindow.xaml.
|
|
|
|
Active = current page. Per user request, the active state is a muted
|
|
grey instead of a bright accent fill, signalling "you are here / not a
|
|
clickable destination right now". Hover and pressed states still
|
|
layer a transparent darkening overlay on top.
|
|
|
|
Triggers on IsActive (WPF-UI's selected-state DP on
|
|
NavigationViewItemBase), not IsSelected.
|
|
-->
|
|
<ControlTemplate x:Key="BoxyNavItemTemplate"
|
|
TargetType="{x:Type ui:NavigationViewItem}">
|
|
<!-- Asymmetric horizontal margin compensates for the 4px scrollbar
|
|
gutter that WPF-UI's NavigationView reserves on the right
|
|
(DynamicScrollViewer Padding="0,0,4,0"); this lands the visible
|
|
item edges at 10px from both the left and right of the pane. -->
|
|
<Grid Margin="6,3" MinHeight="80">
|
|
<!-- Background lives in Border.Style (level-8 style setter), NOT
|
|
as a local-value attribute (level 3), so the IsActive
|
|
template trigger below (level 7) can actually override it.
|
|
Setting Background="{DynamicResource ...}" as an attribute
|
|
here would silently block the trigger — same precedence
|
|
trap as Background="Transparent" on HoverOverlay. -->
|
|
<Border x:Name="Root"
|
|
CornerRadius="8"
|
|
BorderThickness="1"
|
|
BorderBrush="{DynamicResource ControlStrokeColorDefaultBrush}"
|
|
SnapsToDevicePixels="True">
|
|
<Border.Style>
|
|
<Style TargetType="Border">
|
|
<Setter Property="Background"
|
|
Value="{DynamicResource ControlFillColorDefaultBrush}"/>
|
|
</Style>
|
|
</Border.Style>
|
|
</Border>
|
|
<Grid Margin="6">
|
|
<Grid.RowDefinitions>
|
|
<RowDefinition Height="*"/>
|
|
<RowDefinition Height="Auto"/>
|
|
</Grid.RowDefinitions>
|
|
<!-- Icon: hosts the ui:SymbolIcon assigned via
|
|
NavigationViewItem.Icon. TextElement inheritance
|
|
propagates FontSize/Foreground into the SymbolIcon. -->
|
|
<ContentControl x:Name="IconHost"
|
|
Grid.Row="0"
|
|
Content="{TemplateBinding Icon}"
|
|
HorizontalAlignment="Center"
|
|
VerticalAlignment="Center"
|
|
Focusable="False"
|
|
IsTabStop="False"
|
|
TextElement.FontSize="32"
|
|
TextElement.Foreground="{DynamicResource TextFillColorPrimaryBrush}"/>
|
|
<ContentPresenter x:Name="LabelHost"
|
|
Grid.Row="1"
|
|
Content="{TemplateBinding Content}"
|
|
HorizontalAlignment="Center"
|
|
VerticalAlignment="Center"
|
|
Margin="0,4,0,0"
|
|
TextBlock.FontFamily="{DynamicResource ContentControlThemeFontFamily}"
|
|
TextBlock.FontSize="12"
|
|
TextBlock.FontWeight="SemiBold"
|
|
TextBlock.Foreground="{DynamicResource TextFillColorPrimaryBrush}"/>
|
|
</Grid>
|
|
<!-- Overlay darkens on hover/press/active without disturbing the
|
|
Root background colour. Background is intentionally LEFT
|
|
UNSET — assigning Background="Transparent" here would be a
|
|
local value, which beats template-trigger setters in WPF
|
|
property precedence and would silently block the
|
|
IsMouseOver/IsPressed/IsActive triggers below from changing
|
|
the colour. With Background unset, those triggers drive the
|
|
overlay. -->
|
|
<Border x:Name="HoverOverlay"
|
|
CornerRadius="8"
|
|
IsHitTestVisible="False"/>
|
|
</Grid>
|
|
<ControlTemplate.Triggers>
|
|
<Trigger Property="IsMouseOver" Value="True">
|
|
<Setter TargetName="HoverOverlay" Property="Background" Value="#18000000"/>
|
|
</Trigger>
|
|
<Trigger Property="IsPressed" Value="True">
|
|
<Setter TargetName="HoverOverlay" Property="Background" Value="#30000000"/>
|
|
</Trigger>
|
|
<!-- Active = current page: pressed-looking dark fill + muted
|
|
foreground, signalling "you are here / not a destination"
|
|
with a held-down feel.
|
|
|
|
IMPORTANT: we paint the dark fill onto Root directly with a
|
|
translucent-BLACK brush (#30000000 ≈ 19% black) instead of
|
|
going through HoverOverlay or a WPF-UI ControlFillColor*
|
|
brush. WPF-UI's ControlFillColorSecondaryBrush is
|
|
#80F9F9F9 (translucent WHITE) — over the white pane it
|
|
doesn't actually darken anything. A translucent-black brush
|
|
darkens reliably regardless of the parent colour and
|
|
matches the IsPressed overlay strength. -->
|
|
<Trigger Property="IsActive" Value="True">
|
|
<Setter TargetName="Root" Property="Background" Value="#30000000"/>
|
|
<Setter TargetName="IconHost" Property="TextElement.Foreground"
|
|
Value="{DynamicResource TextFillColorSecondaryBrush}"/>
|
|
<Setter TargetName="LabelHost" Property="TextBlock.Foreground"
|
|
Value="{DynamicResource TextFillColorSecondaryBrush}"/>
|
|
</Trigger>
|
|
<Trigger Property="IsEnabled" Value="False">
|
|
<Setter Property="Opacity" Value="0.4"/>
|
|
</Trigger>
|
|
</ControlTemplate.Triggers>
|
|
</ControlTemplate>
|
|
|
|
</ResourceDictionary>
|