UI/HDTWelcome.xaml
|
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Hephaestus Deployment Toolkit" Height="740" Width="760" WindowStartupLocation="CenterScreen" ResizeMode="NoResize" WindowStyle="None" Background="#FF1E1E1E"> <!-- THE BUTTON TEMPLATE, and it is here because of a real defect: WPF's DEFAULT button template paints its own light hover chrome UNDERNEATH the content, so white text on a dark button becomes unreadable the moment the mouse touches it. Setting Background alone does not fix it - the default template ignores it on hover. So the template is replaced outright with a Border and a ContentPresenter, and the hover and pressed states set the FOREGROUND to black against a light surface. A technician must be able to read the button they are about to press. INLINE, NOT AN EXTERNAL ResourceDictionary. A merged dictionary is another file that has to reach the RAM disk intact, and tests/contract/WinPeUiStack.Contract.Tests.ps1 refuses one. --> <Window.Resources> <Style TargetType="Button"> <Setter Property="Foreground" Value="White" /> <Setter Property="BorderThickness" Value="0" /> <Setter Property="FontSize" Value="16" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Button"> <Border x:Name="HDTButtonSurface" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" /> </Border> <ControlTemplate.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter TargetName="HDTButtonSurface" Property="Background" Value="#FFE6E6E6" /> <Setter Property="Foreground" Value="Black" /> </Trigger> <Trigger Property="IsPressed" Value="True"> <Setter TargetName="HDTButtonSurface" Property="Background" Value="#FFBDBDBD" /> <Setter Property="Foreground" Value="Black" /> </Trigger> <Trigger Property="IsEnabled" Value="False"> <Setter TargetName="HDTButtonSurface" Property="Background" Value="#FF2A2A2A" /> <Setter Property="Foreground" Value="#FF6E6E6E" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> <!-- THE EYE, and it gets its own template for the same reason Button does: WPF's default ToggleButton chrome paints light-on-light on hover, and an eye you cannot see is worse than no eye. THE GLYPH IS A VECTOR, NOT A FONT CHARACTER. Segoe MDL2 Assets is not guaranteed to be in a WinPE image built from the ADK, and a missing glyph renders as a box - so the eye is drawn from geometry that needs no font at all. Its colour follows the button's Foreground so the hover trigger recolours the drawing too. --> <Style TargetType="ToggleButton"> <Setter Property="Foreground" Value="#FFCCCCCC" /> <Setter Property="Background" Value="#FF2D2D30" /> <Setter Property="BorderThickness" Value="0" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ToggleButton"> <Border x:Name="HDTToggleSurface" Background="{TemplateBinding Background}"> <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" /> </Border> <ControlTemplate.Triggers> <Trigger Property="IsChecked" Value="True"> <Setter TargetName="HDTToggleSurface" Property="Background" Value="#FF0E639C" /> <Setter Property="Foreground" Value="White" /> </Trigger> <Trigger Property="IsMouseOver" Value="True"> <Setter TargetName="HDTToggleSurface" Property="Background" Value="#FFE6E6E6" /> <Setter Property="Foreground" Value="Black" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> <!-- THE ADDRESS BOXES FOLLOW THE RADIO, DECLARATIVELY. A DataTrigger bound to HDTUseStaticRadio.IsChecked - no code-behind, because there is no compiler in WinPE and the contract refuses one. READ-ONLY, NOT DISABLED. Under DHCP these boxes SHOW THE LEASE the machine actually got - address, mask, gateway, DNS - so a technician can read what it was given before deciding whether to override it. A disabled box greys its text out and is harder to read, which defeats the point; read-only keeps it legible and uncopyable-over. --> <!-- EVERY FIELD ON THIS SCREEN IS 34 HIGH, AND IT IS SET HERE BECAUSE THIS WINDOW DOES NOT LOAD HDTTheme.xaml. It carries its own copy of the styles it needs - it is the one screen that runs before the share is reachable - so the theme's HDTFieldHeight token does not reach it, and a change made there alone leaves this screen behind. Measured after exactly that mistake: the address boxes stayed 32 while the theme said 34. AND WITHOUT AN IMPLICIT STYLE, A BOX HAS NO HEIGHT AT ALL. The deploy-root box carried Height="32" as a local value; removing that in favour of "the style will do it" left it 19.95 high, because there was no TextBox style for it to inherit from. The two implicit styles below are what make that true now. --> <Style TargetType="TextBox"> <Setter Property="Height" Value="34" /> <Setter Property="VerticalContentAlignment" Value="Center" /> </Style> <Style TargetType="PasswordBox"> <Setter Property="Height" Value="34" /> <Setter Property="VerticalContentAlignment" Value="Center" /> </Style> <Style x:Key="HDTAddressBox" TargetType="TextBox"> <Setter Property="Height" Value="34" /> <Setter Property="VerticalContentAlignment" Value="Center" /> <Setter Property="BorderBrush" Value="#FF3F3F46" /> <Setter Property="IsReadOnly" Value="True" /> <Setter Property="Background" Value="#FF232326" /> <Setter Property="Foreground" Value="#FF9A9A9A" /> <Style.Triggers> <DataTrigger Binding="{Binding IsChecked, ElementName=HDTUseStaticRadio}" Value="True"> <Setter Property="IsReadOnly" Value="False" /> <Setter Property="Background" Value="#FF2D2D30" /> <Setter Property="Foreground" Value="White" /> </DataTrigger> </Style.Triggers> </Style> </Window.Resources> <!-- NO TITLE BAR, AND THEREFORE NO X. In WinPE there is no desktop, no taskbar and nothing to switch to, so the chrome is vestigial - but the close button is worse than vestigial: it is a third way out of the wizard that goes round the buttons. Show-HDTWizard maps a dismissed window to Cancel precisely so that cannot mean "yes", but a technician who closes the deployment wizard lands at a bare X:\Windows\System32> prompt with no idea what happened. Cancel and Open CMD are the two ways out, and both of them say what they do. MDT's LiteTouch fills the screen for the same reason. --> <!-- THE WELCOME SCREEN - MDT's LiteTouch Welcome, rebuilt. THIS IS THE ONE PANE THAT MUST LIVE IN THE BOOT IMAGE, and not by preference: it runs BEFORE any share is reachable, so it cannot be read from one. Every pane after it - task sequence, computer name, summary, progress - lives on the share under Scripts\UI\ and is read after connecting, exactly as MDT reads DeployWiz_*.xml, so those can be redesigned without rebuilding anything. THREE PANES, EACH INDEPENDENTLY HIDEABLE (MDT's Skip* properties, under the HDT prefix, resolved by the ordinary rules engine): HDTSkipStaticIp hides the network group; DHCP is used HDTSkipDeployRoot hides the share box; bootstrap.json's value wins HDTSkipCredential hides the account group; the embedded one wins HDTSkipWelcome skips this window entirely A pane appears only when it has something to ask or a rule asks for it, because the UNATTENDED PATH IS THE DEFAULT: an image carrying an embedded credential and a resolved task sequence still deploys with nobody present, and the zero-keystroke E2E proves it. STATIC IP IS APPLIED THROUGH WMI, not NetTCPIP. SPIKES S14: Get-NetIPAddress does not exist in a WinPE image built from the ADK - it is what killed the first SMB probe. Win32_NetworkAdapterConfiguration is guaranteed by WinPE-WMI. No x:Class, no code-behind, no external resource dictionary - there is no compiler in WinPE and every extra file is another thing that has to reach the RAM disk intact. tests/contract/WinPeUiStack.Contract.Tests.ps1 asserts all three, over every window. --> <Grid Background="#FF1E1E1E"> <Grid.RowDefinitions> <RowDefinition Height="104" /> <RowDefinition Height="*" /> <RowDefinition Height="72" /> </Grid.RowDefinitions> <Border Grid.Row="0" Background="#FF0E639C" x:Name="HDTDragBanner"> <StackPanel VerticalAlignment="Center" Margin="28,0,28,0"> <TextBlock x:Name="HDTWelcomeTitleText" Foreground="White" FontSize="30" FontWeight="SemiBold" /> <TextBlock x:Name="HDTWelcomeSubtitleText" Foreground="#FFD6E9F5" FontSize="16" Margin="0,4,0,0" /> </StackPanel> </Border> <!-- NO ScrollViewer. A deployment wizard that scrolls hides a field from a technician who does not know it is there, and this screen is fixed - three panes, known size - so it is laid out to fit instead. The window is sized to the content rather than the content squeezed into the window. --> <StackPanel Grid.Row="1" Margin="28,18,28,0"> <!-- ============ network ============ --> <StackPanel x:Name="HDTNetworkPane"> <TextBlock x:Name="HDTWelcomeNetworkHeading" Foreground="White" FontSize="19" FontWeight="SemiBold" /> <RadioButton x:Name="HDTUseDhcpRadio" GroupName="HDTAddressMode" IsChecked="True" Foreground="#FFCCCCCC" FontSize="16" Margin="0,10,0,0" /> <RadioButton x:Name="HDTUseStaticRadio" GroupName="HDTAddressMode" Foreground="#FFCCCCCC" FontSize="16" Margin="0,6,0,0" /> <Grid x:Name="HDTStaticGrid" Margin="22,8,0,0"> <Grid.ColumnDefinitions> <ColumnDefinition Width="155" /> <ColumnDefinition Width="220" /> <ColumnDefinition Width="130" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="36" /> <RowDefinition Height="36" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <TextBlock Grid.Row="0" Grid.Column="0" x:Name="HDTWelcomeIpAddressLabel" Foreground="#FFCCCCCC" FontSize="15" VerticalAlignment="Center" /> <TextBox Grid.Row="0" Grid.Column="1" x:Name="HDTIpAddressBox" Style="{StaticResource HDTAddressBox}" /> <TextBlock Grid.Row="0" Grid.Column="2" x:Name="HDTWelcomeSubnetMaskLabel" Foreground="#FFCCCCCC" FontSize="15" VerticalAlignment="Center" Margin="12,0,0,0" /> <TextBox Grid.Row="0" Grid.Column="3" x:Name="HDTSubnetMaskBox" Style="{StaticResource HDTAddressBox}" /> <TextBlock Grid.Row="1" Grid.Column="0" x:Name="HDTWelcomeGatewayLabel" Foreground="#FFCCCCCC" FontSize="15" VerticalAlignment="Center" /> <TextBox Grid.Row="1" Grid.Column="1" x:Name="HDTGatewayBox" Style="{StaticResource HDTAddressBox}" /> <TextBlock Grid.Row="1" Grid.Column="2" x:Name="HDTWelcomeDnsLabel" Foreground="#FFCCCCCC" FontSize="15" VerticalAlignment="Center" Margin="12,0,0,0" /> <TextBox Grid.Row="1" Grid.Column="3" x:Name="HDTDnsBox" Style="{StaticResource HDTAddressBox}" /> <!-- UNDER THE BOX IT DESCRIBES, NOT A TOOLTIP. It sat under the IP address column while describing a box two columns to its right, which is worse than not being there. A tooltip was the alternative and is wrong here for two reasons: the credential pane already puts its hint directly under the Domain box, so a tooltip would be the one inconsistent affordance on the screen; and hover is invisible - a technician on a bench in WinPE has no reason to discover it, and Set-HDTStaticAddress genuinely needs the comma to split the list. --> <TextBlock Grid.Row="2" Grid.Column="3" x:Name="HDTDnsHint" Foreground="#FF8A8A8A" FontSize="14" Margin="2,2,0,0" TextWrapping="Wrap" /> </Grid> </StackPanel> <!-- ============ share ============ --> <StackPanel x:Name="HDTDeployRootPane" Margin="0,22,0,0"> <TextBlock x:Name="HDTWelcomeShareHeading" Foreground="White" FontSize="19" FontWeight="SemiBold" /> <Grid Margin="0,10,0,0"> <Grid.ColumnDefinitions> <ColumnDefinition Width="155" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <TextBlock Grid.Row="0" Grid.Column="0" x:Name="HDTWelcomeShareLabel" Foreground="#FFCCCCCC" FontSize="15" VerticalAlignment="Center" /> <TextBox Grid.Row="0" Grid.Column="1" x:Name="HDTDeployRootBox" VerticalContentAlignment="Center" Background="#FF2D2D30" Foreground="White" BorderBrush="#FF3F3F46" /> <!-- THE BOX IS EMPTY AND NOBODY IS COMING TO FILL IT. An image built with no deployRoot reaches this screen with nothing to connect to, and an empty box on its own reads as "optional". This says otherwise, and it is amber rather than red because nothing has failed yet - the technician simply has to type it. Collapsed by default: the host shows it only when the boot image carried no share. --> <TextBlock Grid.Row="1" Grid.Column="1" x:Name="HDTDeployRootHint" Visibility="Collapsed" Foreground="#FFD9A441" FontSize="14" TextWrapping="Wrap" Margin="2,6,0,0" /> </Grid> </StackPanel> <!-- ============ account ============ --> <StackPanel x:Name="HDTCredentialPane" Margin="0,22,0,0"> <TextBlock x:Name="HDTWelcomeAccountHeading" Foreground="White" FontSize="19" FontWeight="SemiBold" /> <Grid Margin="0,10,0,0"> <Grid.ColumnDefinitions> <ColumnDefinition Width="155" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="36" /> <RowDefinition Height="36" /> <RowDefinition Height="20" /> <RowDefinition Height="36" /> </Grid.RowDefinitions> <TextBlock Grid.Row="0" Grid.Column="0" x:Name="HDTWelcomeUserIdLabel" Foreground="#FFCCCCCC" FontSize="15" VerticalAlignment="Center" /> <TextBox Grid.Row="0" Grid.Column="1" x:Name="HDTUserIdBox" VerticalContentAlignment="Center" Background="#FF2D2D30" Foreground="White" BorderBrush="#FF3F3F46" /> <TextBlock Grid.Row="1" Grid.Column="0" x:Name="HDTWelcomeUserDomainLabel" Foreground="#FFCCCCCC" FontSize="15" VerticalAlignment="Center" /> <TextBox Grid.Row="1" Grid.Column="1" x:Name="HDTUserDomainBox" VerticalContentAlignment="Center" Background="#FF2D2D30" Foreground="White" BorderBrush="#FF3F3F46" /> <TextBlock Grid.Row="2" Grid.Column="1" x:Name="HDTUserDomainHint" Foreground="#FF8A8A8A" FontSize="14" Margin="2,0,0,0" /> <TextBlock Grid.Row="3" Grid.Column="0" x:Name="HDTWelcomePasswordLabel" Foreground="#FFCCCCCC" FontSize="15" VerticalAlignment="Center" /> <!-- TWO BOXES IN ONE CELL, and only one of them visible at a time. PasswordBox.Password is not a DependencyProperty, so it cannot be bound and the reveal cannot be done declaratively: the host swaps the text and the visibility (New-HDTWizardHost), which is why both carry x:Name. --> <Grid Grid.Row="3" Grid.Column="1"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="Auto" /> </Grid.ColumnDefinitions> <PasswordBox Grid.Column="0" x:Name="HDTPasswordBox" VerticalContentAlignment="Center" Background="#FF2D2D30" Foreground="White" BorderBrush="#FF3F3F46" /> <TextBox Grid.Column="0" x:Name="HDTPasswordRevealBox" Visibility="Collapsed" VerticalContentAlignment="Center" Background="#FF2D2D30" Foreground="White" BorderBrush="#FF3F3F46" /> <ToggleButton Grid.Column="1" x:Name="HDTPasswordRevealToggle" Width="38" Height="34" Margin="6,0,0,0"> <Grid Width="22" Height="16"> <Path Data="M 1,8 C 5,2.5 17,2.5 21,8 C 17,13.5 5,13.5 1,8 Z" Stroke="{Binding Foreground, RelativeSource={RelativeSource AncestorType=ToggleButton}}" StrokeThickness="1.3" /> <Ellipse Width="6" Height="6" HorizontalAlignment="Center" VerticalAlignment="Center" Fill="{Binding Foreground, RelativeSource={RelativeSource AncestorType=ToggleButton}}" /> </Grid> </ToggleButton> </Grid> </Grid> </StackPanel> <TextBlock x:Name="HDTMessageText" Text="" Foreground="#FFF48771" FontSize="15" Margin="0,18,0,12" TextWrapping="Wrap" /> </StackPanel> <!-- A GRID, NOT A StackPanel, because the footer now has two ends: the command prompt on the left and the wizard's own buttons on the right. HDTOpenCmdButton is MDT's "Exit to Command Prompt" - the escape hatch a technician reaches for when the network is wrong, a driver is missing, or they simply need diskpart. WinPE gives it on F8, but F8 is folklore; a button is discoverable. --> <Border Grid.Row="2" Background="#FF252526"> <Grid Margin="28,0,28,0"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Button Grid.Column="0" x:Name="HDTOpenCmdButton" Width="120" Height="34" HorizontalAlignment="Left" VerticalAlignment="Center" Background="#FF3C3C3C" BorderThickness="0" /> <StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center"> <Button x:Name="HDTCancelButton" Width="112" Height="34" Margin="0,0,12,0" Background="#FF3C3C3C" BorderThickness="0" /> <Button x:Name="HDTNextButton" Width="112" Height="34" Background="#FF0E639C" BorderThickness="0" IsDefault="True" /> </StackPanel> </Grid> </Border> </Grid> </Window> |