diff --git a/EngineeringNavigationRoute.cs b/EngineeringNavigationRoute.cs new file mode 100644 index 000000000..9af4453a5 --- /dev/null +++ b/EngineeringNavigationRoute.cs @@ -0,0 +1,35 @@ +namespace ArIED61850Tester; + +/// +/// Operator header order is intentionally independent of the stable WPF +/// workspace indices. Preserve legacy bindings and passive monitors while +/// removing the redundant Live Monitor destination from operator navigation. +/// The legacy live view at index 1 has no navigable header button. +/// +public static class EngineeringNavigationRoute +{ + public const int SmvWorkspaceIndex = 8; + + // Visible header: Browser, Devices, Events, Annunciator, GOOSE, SMV, + // Signal Testing, Diagnostics. Values are real MainTabs indices. + private static readonly int[] WorkspaceByButton = [7, 0, 2, 3, 4, 8, 6, 5]; + + public static int TabForButton(int button) + => button is >= 0 and < 8 + ? WorkspaceByButton[button] + : throw new ArgumentOutOfRangeException(nameof(button)); + + public static int ButtonForTab(int tab) + => tab switch + { + 7 => 0, // IED Browser + 0 or 1 => 1, // Device Explorer and unreachable legacy Live Monitor + 2 => 2, // Event Logs + 3 => 3, // Annunciator + 4 => 4, // GOOSE Sniff + 8 => 5, // SMV + 6 => 6, // Signal Testing + 5 => 7, // Diagnostics + _ => 1 // Unspecified internal workspace is never shown as SMV + }; +} diff --git a/MainWindow.IedSmvQuickStart.cs b/MainWindow.IedSmvQuickStart.cs index 6e602641e..55cbeda2b 100644 --- a/MainWindow.IedSmvQuickStart.cs +++ b/MainWindow.IedSmvQuickStart.cs @@ -92,7 +92,26 @@ private void IedSmvQuickStart_Click(object sender, RoutedEventArgs e) if (sender is not Button { CommandParameter: Iec61850MonitorDevice device }) return; + OpenSmvWorkspaceForDevice(device); + } + + private void ActivateSelectedSmvWorkspace() + { + if (SelectedDevice is { } device) + OpenSmvWorkspaceForDevice(device); + else if (SmvWorkspaceStatus is not null) + SmvWorkspaceStatus.Text = "Select an IED in Device Explorer, then open SMV capture."; + } + + private void OpenSmvCapture_Click(object sender, RoutedEventArgs e) + => ActivateSelectedSmvWorkspace(); + + private void OpenSmvWorkspaceForDevice(Iec61850MonitorDevice device) + { SelectedDevice = device; + if (SmvWorkspaceStatus is not null) + SmvWorkspaceStatus.Text = + "SMV capture for " + device.Name + " · existing verified viewer"; if (_activeSmvViewerWindow is { IsLoaded: true } existing) { diff --git a/MainWindow.NavigationLayoutFix.cs b/MainWindow.NavigationLayoutFix.cs index bf1ff226b..f087445d1 100644 --- a/MainWindow.NavigationLayoutFix.cs +++ b/MainWindow.NavigationLayoutFix.cs @@ -27,26 +27,26 @@ internal static class MainWindowNavigationLayoutFix private static readonly string[] FullLabels = [ - "IEC 61850 Explorer", - "Live Monitor", - "Event Log", - "Alarm", - "GOOSE Subscriber", - "Diagnostics", - "FAT", - "IED Browser" + "IED Browser", + "Device Explorer", + "Event Logs", + "Annunciator", + "GOOSE Sniff", + "SMV", + "Signal Testing", + "Diagnostics" ]; private static readonly string[] CompactLabels = [ - "Explorer", - "Live", + "IED Browser", + "Devices", "Events", "Alarm", "GOOSE", - "Diagnostics", - "FAT", - "Browser" + "SMV", + "Testing", + "Diagnostics" ]; [ModuleInitializer] @@ -98,7 +98,7 @@ private static void OnMainWindowButtonClick(object sender, RoutedEventArgs e) if (sender is not MainWindow window || e.Source is not Button button) return; - if (button.Name is not ("NavExplorerButton" or "NavLiveButton" or "NavEventsButton" or "NavAlarmButton" or "NavGooseButton" or "NavDiagnosticsButton" or "NavNativeFatButton" or "NavIedBrowserButton")) + if (button.Name is not ("NavIedBrowserButton" or "NavExplorerButton" or "NavEventsButton" or "NavAlarmButton" or "NavGooseButton" or "NavSmvButton" or "NavNativeFatButton" or "NavDiagnosticsButton")) return; // A repeated click on the already-selected tab does not raise SelectionChanged, @@ -160,7 +160,7 @@ private static void ApplyResponsiveLayout(MainWindow window) // Diagnostics owns a StackPanel containing its text plus the red alert // badge. Never replace that Content tree while changing layout density. - if (index != 5 && index < labels.Length) + if (index != 7 && index < labels.Length) { // Preserve the operator SVG glyphs across Loaded/resize. Replacing // Content here would silently erase icons declared in MainWindow.xaml. @@ -189,14 +189,14 @@ private static void ApplyResponsiveLayout(MainWindow window) private static Button?[] GetNavigationButtons(MainWindow window) => [ + window.FindName("NavIedBrowserButton") as Button, window.FindName("NavExplorerButton") as Button, - window.FindName("NavLiveButton") as Button, window.FindName("NavEventsButton") as Button, window.FindName("NavAlarmButton") as Button, window.FindName("NavGooseButton") as Button, - window.FindName("NavDiagnosticsButton") as Button, + window.FindName("NavSmvButton") as Button, window.FindName("NavNativeFatButton") as Button, - window.FindName("NavIedBrowserButton") as Button + window.FindName("NavDiagnosticsButton") as Button ]; private static void UpdatePillGeometry(MainWindow window, double shellWidth) @@ -240,7 +240,7 @@ private static void PositionPill(MainWindow window, bool animate) contentWidth = Math.Max(0d, shell.Width - shell.Padding.Left - shell.Padding.Right); var cellWidth = contentWidth / 8d; - var target = Math.Clamp(tabs.SelectedIndex, 0, 7) * cellWidth; + var target = EngineeringNavigationRoute.ButtonForTab(tabs.SelectedIndex) * cellWidth; pill.Width = Math.Max(1d, cellWidth - 2d); translate.BeginAnimation(TranslateTransform.XProperty, null); diff --git a/MainWindow.xaml b/MainWindow.xaml index c2ee8877a..24bc6d710 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -109,47 +109,47 @@ - - - - - - - -