Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 51 additions & 53 deletions src/ProcessBus.App.Wpf/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="18"/>
<ColumnDefinition x:Name="HeaderIdentityGap" Width="18"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
Expand All @@ -183,7 +183,7 @@
Orientation="Horizontal"
VerticalAlignment="Center">

<Border Width="38"
<Border x:Name="HeaderProductLogo" Width="38"
Height="38"
CornerRadius="8"
Background="#102A43"
Expand All @@ -196,12 +196,12 @@
</Border>

<StackPanel VerticalAlignment="Center">
<TextBlock Text="Process Bus Insight"
<TextBlock x:Name="HeaderProductTitle" Text="Process Bus Insight"
FontSize="15"
FontWeight="SemiBold"
Foreground="{StaticResource TextPrimaryBrush}"/>

<TextBlock Text="IEC 61850 · SV / GOOSE / PTP"
<TextBlock x:Name="HeaderProductSubtitle" Text="IEC 61850 · SV / GOOSE / PTP"
Margin="0,2,0,0"
FontSize="11"
Foreground="#7FA8CC"/>
Expand Down Expand Up @@ -317,48 +317,19 @@
</StackPanel>
</RadioButton>

<RadioButton x:Name="FramesWorkspaceButton"
GroupName="WorkspaceTabs"
Style="{StaticResource AnalyzerTabButtonStyle}"
Tag="4"
Click="WorkspaceTabButton_Click">
<StackPanel Orientation="Horizontal" IsHitTestVisible="False">
<Viewbox Width="14" Height="14" Margin="0,0,8,0" VerticalAlignment="Center">
<Path Style="{StaticResource NavVectorIconStyle}" Data="{StaticResource IconDiagnosticsGeometry}"/>
</Viewbox>
<TextBlock Text="Validation"
FontWeight="SemiBold"
Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType=RadioButton}}"/>
</StackPanel>
</RadioButton>

<RadioButton x:Name="AdvancedWorkspaceButton"
GroupName="WorkspaceTabs"
Style="{StaticResource AnalyzerTabButtonStyle}"
Tag="6"
Click="WorkspaceTabButton_Click">
<StackPanel Orientation="Horizontal" IsHitTestVisible="False">
<Viewbox Width="14" Height="14" Margin="0,0,8,0" VerticalAlignment="Center">
<Path Style="{StaticResource NavVectorIconStyle}" Data="{StaticResource IconFramesGeometry}"/>
</Viewbox>
<TextBlock Text="Advanced"
FontWeight="SemiBold"
Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType=RadioButton}}"/>
</StackPanel>
</RadioButton>
</StackPanel>
</Grid>
</Border>

<!-- Fixed 20-DIP breathing room between the workspace switcher and adapter.
Never let the tab pill visually merge into the adapter frame. -->
<StackPanel Grid.Column="3"
<StackPanel x:Name="HeaderCaptureToolbar" Grid.Column="3"
Margin="20,0,0,0"
Orientation="Horizontal"
VerticalAlignment="Center"
HorizontalAlignment="Right">

<ComboBox Width="250"
<ComboBox x:Name="HeaderAdapterComboBox" Width="250"
Style="{StaticResource ToolbarAdapterComboBoxStyle}"
IsEnabled="{Binding IsRunning, Converter={StaticResource InverseBooleanConverter}}"
ItemsSource="{Binding Adapters}"
Expand Down Expand Up @@ -446,6 +417,49 @@
</Button.Style>
</Button>

<!-- Specialist tools are available without crowding the primary navigator. -->
<Button x:Name="ToolsWorkspaceButton"
Style="{StaticResource HeaderCircleButtonStyle}"
Width="34" Height="34" Margin="7,0,0,0"
ToolTip="More tools: Validation and Advanced"
Click="WorkspaceToolsButton_Click"
AutomationProperties.Name="More tools: Validation and Advanced">
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="15"
Text="&#xE713;" Foreground="#BED7EA"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Button.ContextMenu>
<ContextMenu Background="#0C2032" BorderBrush="#315270"
BorderThickness="1" Padding="5" Placement="Bottom">
<ContextMenu.Resources>
<Style TargetType="MenuItem">
<Setter Property="Foreground" Value="#E8F5FF"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="MenuItem">
<Border x:Name="MenuSurface" Background="Transparent"
CornerRadius="5" Padding="14,9" MinWidth="142">
<ContentPresenter ContentSource="Header"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsHighlighted" Value="True">
<Setter TargetName="MenuSurface" Property="Background" Value="#174B77"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ContextMenu.Resources>
<MenuItem Header="Validation" Tag="4" Click="WorkspaceToolMenuItem_Click"
ToolTip="Compare SCL engineering with live traffic"/>
<MenuItem Header="Advanced" Tag="6" Click="WorkspaceToolMenuItem_Click"
ToolTip="Raw packet decode, estimator and performance"/>
Comment on lines +455 to +458

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add navigation regression coverage and documentation

This moves Validation and Advanced from first-level tabs into a new menu and changes the visible navigation state, but the commit updates only MainWindow.xaml and its code-behind. Add regression coverage for selecting indices 4/6 and returning to a primary tab, and update the operator documentation to describe the new route; repository policy explicitly requires both for runtime and user-visible changes.

AGENTS.md reference: AGENTS.md:L67-L67

Useful? React with 👍 / 👎.

</ContextMenu>
</Button.ContextMenu>
</Button>

<Button Style="{StaticResource HeaderCircleButtonStyle}"
Width="34"
Height="34"
Expand Down Expand Up @@ -3984,15 +3998,7 @@
Foreground="#8FAAC3"
FontSize="11"/>
</StackPanel>
<Border HorizontalAlignment="Right"
VerticalAlignment="Top"
Background="#071A2B"
BorderBrush="#1F4E76"
BorderThickness="1"
CornerRadius="10"
Padding="10,5">
<TextBlock Text="{Binding SclWorkspaceStatusText}" Foreground="#8FCBFF" FontSize="10.5" FontWeight="SemiBold" MaxWidth="180" TextTrimming="CharacterEllipsis" ToolTip="{Binding SclWorkspaceStatusText}"/>
</Border>

</DockPanel>

<DataGrid Grid.Row="2"
Expand Down Expand Up @@ -4094,15 +4100,7 @@
Foreground="#8FAAC3"
FontSize="11"/>
</StackPanel>
<Border HorizontalAlignment="Right"
VerticalAlignment="Top"
Background="#071A2B"
BorderBrush="#1F4E76"
BorderThickness="1"
CornerRadius="10"
Padding="10,5">
<TextBlock Text="{Binding SclBindingSummaryText}" Foreground="#F6D781" FontSize="10.5" FontWeight="SemiBold" MaxWidth="230" TextTrimming="CharacterEllipsis" ToolTip="{Binding SclBindingSummaryText}"/>
</Border>

</DockPanel>

<DataGrid Grid.Row="6"
Expand Down
62 changes: 58 additions & 4 deletions src/ProcessBus.App.Wpf/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ public MainWindow()
InitializeComponent();
if (DataContext is MainWindowViewModel viewModel) { }

Loaded += (_, _) => UpdateWorkspaceActivePill(animate: false);
Loaded += (_, _) => { UpdateHeaderDensity(); UpdateWorkspaceActivePill(animate: false); };
SizeChanged += (_, _) => UpdateHeaderDensity();
Closing += MainWindow_Closing;
Closed += (_, _) => Application.Current?.Shutdown();
WorkspaceSegmentRail.SizeChanged += (_, _) => UpdateWorkspaceActivePill(animate: false);
Expand Down Expand Up @@ -86,6 +87,45 @@ private void LockedFeature_Click(object sender, RoutedEventArgs e)
MessageBoxImage.Information);
}

// Specialist pages are preserved but intentionally excluded from the operator tab rail.
private void WorkspaceToolsButton_Click(object sender, RoutedEventArgs e)
{
if (ToolsWorkspaceButton.ContextMenu is not { } menu)
return;

menu.PlacementTarget = ToolsWorkspaceButton;
menu.IsOpen = true;
}

private void WorkspaceToolMenuItem_Click(object sender, RoutedEventArgs e)
=> WorkspaceTabButton_Click(sender, e);

// The original header had seven fixed-width tabs and clipped at desktop sizes.
// Choose compact dimensions only on narrow windows; no data/capture refresh.
private bool _compactHeader;
private void UpdateHeaderDensity()
{
if (!IsLoaded || HeaderAdapterComboBox is null || WorkspaceSegmentButtons is null)
return;

var compact = ActualWidth < 1450;
if (_compactHeader == compact && HeaderAdapterComboBox.Width == (compact ? 180 : 250))
return;

_compactHeader = compact;
HeaderProductSubtitle.Visibility = compact ? Visibility.Collapsed : Visibility.Visible;
HeaderProductLogo.Width = compact ? 32 : 38;
HeaderProductLogo.Height = compact ? 32 : 38;
HeaderProductTitle.FontSize = compact ? 13 : 15;
HeaderIdentityGap.Width = new GridLength(compact ? 12 : 18);
HeaderAdapterComboBox.Width = compact ? 180 : 250;
HeaderCaptureToolbar.Margin = new Thickness(compact ? 14 : 20, 0, 0, 0);
foreach (var tab in WorkspaceSegmentButtons.Children.OfType<RadioButton>())
tab.Width = compact ? 94 : 112;

UpdateWorkspaceActivePill(animate: false);
Comment on lines +123 to +126

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Clear active animations before repositioning the pill

After any animated tab switch, both pill properties retain animations with the default FillBehavior.HoldEnd; crossing the 1450-DIP threshold then changes every tab's width and calls this non-animated update, but assigning the base X and Width values cannot override those active animations. Consequently, the highlighted pill can remain at its pre-resize offset or width until another tab is clicked. Remove the existing animations before applying the immediate values, or replace them with non-holding animations.

Useful? React with 👍 / 👎.

}

private void WorkspaceTabButton_Click(object sender, RoutedEventArgs e)
{
if (sender is not FrameworkElement { Tag: string tag } ||
Expand Down Expand Up @@ -138,10 +178,24 @@ WorkspaceActivePillTransform is null ||
WorkspaceSegmentButtons is null)
return;

var selectedButton = WorkspaceSegmentButtons.Children
.OfType<RadioButton>()
.FirstOrDefault(button => string.Equals(button.Tag?.ToString(), WorkspaceTabs.SelectedIndex.ToString(), StringComparison.Ordinal));
var primaryTabs = WorkspaceSegmentButtons.Children.OfType<RadioButton>().ToArray();
var selectedButton = primaryTabs.FirstOrDefault(button =>
string.Equals(button.Tag?.ToString(), WorkspaceTabs.SelectedIndex.ToString(), StringComparison.Ordinal));

// Tab selection may also originate in the VM, keyboard navigation, or Tools.
foreach (var tab in primaryTabs)
tab.IsChecked = ReferenceEquals(tab, selectedButton);

bool inTools = WorkspaceTabs.SelectedIndex is 4 or 6;
ToolsWorkspaceButton.ToolTip = inTools
? (WorkspaceTabs.SelectedIndex == 4 ? "Validation · select another tool" : "Advanced · select another tool")
: "More tools: Validation and Advanced";
ToolsWorkspaceButton.Background = inTools
? new SolidColorBrush(Color.FromRgb(22, 76, 119))
: Brushes.Transparent;

// No blue primary-tab pill should remain selected when a specialist page is open.
WorkspaceActivePill.Visibility = selectedButton is null ? Visibility.Collapsed : Visibility.Visible;
if (selectedButton is null || selectedButton.ActualWidth <= 0)
return;

Expand Down
Loading