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>