From a0802658ea0a4328ce35c8c006d7d80ccbd48da5 Mon Sep 17 00:00:00 2001 From: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> Date: Sun, 16 Aug 2026 17:13:18 +0200 Subject: [PATCH 1/5] Feature: Add start & pause button per group in ping monitor --- .../Resources/Strings.Designer.cs | 20 +- .../Resources/Strings.resx | 6 + .../ViewModels/PingMonitorHostViewModel.cs | 22 ++ .../Views/PingMonitorHostView.xaml | 227 +++++++++++++----- Website/docs/changelog/next-release.md | 1 + 5 files changed, 211 insertions(+), 65 deletions(-) diff --git a/Source/NETworkManager.Localization/Resources/Strings.Designer.cs b/Source/NETworkManager.Localization/Resources/Strings.Designer.cs index 3cf04e06e4..2966877d93 100644 --- a/Source/NETworkManager.Localization/Resources/Strings.Designer.cs +++ b/Source/NETworkManager.Localization/Resources/Strings.Designer.cs @@ -1898,7 +1898,25 @@ public static string CloseGroup { return ResourceManager.GetString("CloseGroup", resourceCulture); } } - + + /// + /// Looks up a localized string similar to Start group. + /// + public static string StartGroup { + get { + return ResourceManager.GetString("StartGroup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Pause group. + /// + public static string PauseGroup { + get { + return ResourceManager.GetString("PauseGroup", resourceCulture); + } + } + /// /// Looks up a localized string similar to Closing in {0} seconds.... /// diff --git a/Source/NETworkManager.Localization/Resources/Strings.resx b/Source/NETworkManager.Localization/Resources/Strings.resx index 9c69a5b26d..fb08530760 100644 --- a/Source/NETworkManager.Localization/Resources/Strings.resx +++ b/Source/NETworkManager.Localization/Resources/Strings.resx @@ -3892,6 +3892,12 @@ Try again in a few seconds. Close group + + Start group + + + Pause group + Run command... (Ctrl+Shift+P) diff --git a/Source/NETworkManager/ViewModels/PingMonitorHostViewModel.cs b/Source/NETworkManager/ViewModels/PingMonitorHostViewModel.cs index f50cf2cafe..a25bf063a8 100644 --- a/Source/NETworkManager/ViewModels/PingMonitorHostViewModel.cs +++ b/Source/NETworkManager/ViewModels/PingMonitorHostViewModel.cs @@ -239,6 +239,28 @@ private void CloseGroupAction(object group) RemoveGroup(group.ToString()); } + /// + /// Gets the command to start every host in a group that is not currently running. + /// + public ICommand StartGroupCommand => new RelayCommand(StartGroupAction); + + private void StartGroupAction(object group) + { + foreach (var host in Hosts.Where(host => host.Group.Equals(group.ToString()) && !host.IsRunning)) + host.Start(); + } + + /// + /// Gets the command to pause every host in a group that is currently running. + /// + public ICommand PauseGroupCommand => new RelayCommand(PauseGroupAction); + + private void PauseGroupAction(object group) + { + foreach (var host in Hosts.Where(host => host.Group.Equals(group.ToString()) && host.IsRunning)) + host.Stop(); + } + #endregion #region Methods diff --git a/Source/NETworkManager/Views/PingMonitorHostView.xaml b/Source/NETworkManager/Views/PingMonitorHostView.xaml index 46ddaa631e..2394d72076 100644 --- a/Source/NETworkManager/Views/PingMonitorHostView.xaml +++ b/Source/NETworkManager/Views/PingMonitorHostView.xaml @@ -196,8 +196,8 @@ + Visibility="{Binding Path=Hosts.Count, Converter={StaticResource ResourceKey=IntNotZeroToVisibilityCollapsedConverter}}" + Background="Transparent"> @@ -216,92 +216,191 @@ + - + Orientation="Horizontal" + VerticalAlignment="Center"> + - + - - + + - + Style="{StaticResource ResourceKey=DefaultTextBlock}" + Foreground="{DynamicResource ResourceKey=MahApps.Brushes.Gray5}" + Margin="6,0,6,0" /> + - + - - + + + Style="{StaticResource ResourceKey=DefaultTextBlock}" + Foreground="{DynamicResource ResourceKey=MahApps.Brushes.Gray5}" + Margin="6,0,6,0" + Visibility="{Binding ElementName=PausedText, Path=Visibility}" /> + Style="{StaticResource ResourceKey=DefaultTextBlock}" + Foreground="{DynamicResource ResourceKey=MahApps.Brushes.Gray5}"> - + - - + + - + - + - + + + + + + + + + + + + + + + + + + + + @@ -337,8 +436,8 @@ Focusable="False" Style="{StaticResource ResourceKey=VerticalGridSplitter}" /> + ProfileItemTemplate="{StaticResource ResourceKey=PingMonitorProfileItemTemplate}" + ProfileContextMenuExtraItems="{StaticResource ResourceKey=PingMonitorProfileContextMenuExtraItems}" + RunProfileCommand="{Binding Path=PingProfileCommand}" /> \ No newline at end of file diff --git a/Website/docs/changelog/next-release.md b/Website/docs/changelog/next-release.md index beeb7c68ab..c143c31b3d 100644 --- a/Website/docs/changelog/next-release.md +++ b/Website/docs/changelog/next-release.md @@ -55,6 +55,7 @@ Release date: **xx.xx.2026** **Ping Monitor** - Added a live count of hosts up/down (and paused, if any) per group, next to the group's close button. [#3572](https://github.com/BornToBeRoot/NETworkManager/pull/3572) +- Added **Start** and **Pause** buttons to each group header (shown next to the close button on mouse-over), to start every paused host in the group or pause every running one at once. [#XXXX](https://github.com/BornToBeRoot/NETworkManager/pull/XXXX) - Reworked each monitored host's card: the collapsed quick info now shows labeled values (`Received: X · Lost: Y · Packet loss: Z%`) instead of unlabeled numbers, the expanded view shows only the latency chart (with more room, since Hostname/IP address are already visible in the header) and the last status change time moved to a tooltip on the connectivity icon. The **Status change** field was also renamed to **Last status change**. [#3572](https://github.com/BornToBeRoot/NETworkManager/pull/3572) - Host input now accepts newline-separated hosts (one per line, e.g. a column pasted from Excel), converted automatically to the semicolon-separated form. [#3568](https://github.com/BornToBeRoot/NETworkManager/pull/3568) - Host input now supports shorthand IPv4 ranges like `192.168.0.1-100`, in addition to the existing `192.168.0.0-192.168.0.100` and `192.168.[0-100].1` range formats. [#3568](https://github.com/BornToBeRoot/NETworkManager/pull/3568) From a626bd02b1859ac724b5096ef517e2bd44c5a8cb Mon Sep 17 00:00:00 2001 From: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> Date: Sun, 16 Aug 2026 17:16:33 +0200 Subject: [PATCH 2/5] Docs: update docs #3575 --- Website/docs/application/ping-monitor.md | 12 ++++++++++++ Website/docs/changelog/next-release.md | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Website/docs/application/ping-monitor.md b/Website/docs/application/ping-monitor.md index 6391f00de4..d731b89879 100644 --- a/Website/docs/application/ping-monitor.md +++ b/Website/docs/application/ping-monitor.md @@ -52,6 +52,18 @@ You can interact with the chart to inspect past results: When you zoom or pan, the chart leaves live mode and stops scrolling. A **Live** button then appears in the top-right corner of the chart — click it to return to live mode and resume auto-scrolling. +### Groups + +Hosts are grouped by their profile group (or **Hosts** if none is set). Each group header shows a live count of hosts that are up, down and paused (**Paused** is only shown while at least one host in the group is paused). + +Hover over a group header to reveal its action buttons: + +| Action | Description | +|--------|-------------| +| **Start** | Starts every host in the group that isn't currently running | +| **Pause** | Pauses every host in the group that's currently running | +| **Close** | Stops and removes every host in the group | + ### Context menu Right-click a monitored host (anywhere except the chart) to open the context menu: diff --git a/Website/docs/changelog/next-release.md b/Website/docs/changelog/next-release.md index c143c31b3d..919e0a8504 100644 --- a/Website/docs/changelog/next-release.md +++ b/Website/docs/changelog/next-release.md @@ -55,7 +55,7 @@ Release date: **xx.xx.2026** **Ping Monitor** - Added a live count of hosts up/down (and paused, if any) per group, next to the group's close button. [#3572](https://github.com/BornToBeRoot/NETworkManager/pull/3572) -- Added **Start** and **Pause** buttons to each group header (shown next to the close button on mouse-over), to start every paused host in the group or pause every running one at once. [#XXXX](https://github.com/BornToBeRoot/NETworkManager/pull/XXXX) +- Added **Start** and **Pause** buttons to each group header (shown next to the close button on mouse-over), to start every paused host in the group or pause every running one at once. [#3575](https://github.com/BornToBeRoot/NETworkManager/pull/3575) - Reworked each monitored host's card: the collapsed quick info now shows labeled values (`Received: X · Lost: Y · Packet loss: Z%`) instead of unlabeled numbers, the expanded view shows only the latency chart (with more room, since Hostname/IP address are already visible in the header) and the last status change time moved to a tooltip on the connectivity icon. The **Status change** field was also renamed to **Last status change**. [#3572](https://github.com/BornToBeRoot/NETworkManager/pull/3572) - Host input now accepts newline-separated hosts (one per line, e.g. a column pasted from Excel), converted automatically to the semicolon-separated form. [#3568](https://github.com/BornToBeRoot/NETworkManager/pull/3568) - Host input now supports shorthand IPv4 ranges like `192.168.0.1-100`, in addition to the existing `192.168.0.0-192.168.0.100` and `192.168.[0-100].1` range formats. [#3568](https://github.com/BornToBeRoot/NETworkManager/pull/3568) From 6dce9177155d24c3bfcc1f27fb3d0073f77b254a Mon Sep 17 00:00:00 2001 From: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> Date: Sun, 16 Aug 2026 17:56:33 +0200 Subject: [PATCH 3/5] Fix: Touch / keyboard behaviour - auto close after 20 seconds --- .../Resources/Strings.Designer.cs | 9 ++ .../Resources/Strings.resx | 3 + .../Views/PingMonitorHostView.xaml | 50 +++++++---- .../Views/PingMonitorHostView.xaml.cs | 86 +++++++++++++++++++ Website/docs/application/ping-monitor.md | 2 +- Website/docs/changelog/next-release.md | 2 +- 6 files changed, 133 insertions(+), 19 deletions(-) diff --git a/Source/NETworkManager.Localization/Resources/Strings.Designer.cs b/Source/NETworkManager.Localization/Resources/Strings.Designer.cs index 2966877d93..8df05e8a07 100644 --- a/Source/NETworkManager.Localization/Resources/Strings.Designer.cs +++ b/Source/NETworkManager.Localization/Resources/Strings.Designer.cs @@ -1908,6 +1908,15 @@ public static string StartGroup { } } + /// + /// Looks up a localized string similar to Group actions. + /// + public static string GroupActions { + get { + return ResourceManager.GetString("GroupActions", resourceCulture); + } + } + /// /// Looks up a localized string similar to Pause group. /// diff --git a/Source/NETworkManager.Localization/Resources/Strings.resx b/Source/NETworkManager.Localization/Resources/Strings.resx index fb08530760..5533818793 100644 --- a/Source/NETworkManager.Localization/Resources/Strings.resx +++ b/Source/NETworkManager.Localization/Resources/Strings.resx @@ -3895,6 +3895,9 @@ Try again in a few seconds. Start group + + Group actions + Pause group diff --git a/Source/NETworkManager/Views/PingMonitorHostView.xaml b/Source/NETworkManager/Views/PingMonitorHostView.xaml index 2394d72076..e56b3f785b 100644 --- a/Source/NETworkManager/Views/PingMonitorHostView.xaml +++ b/Source/NETworkManager/Views/PingMonitorHostView.xaml @@ -208,7 +208,8 @@ - + @@ -292,23 +293,38 @@ - - - - - - - - + + + + + + + + + + + Visibility="{Binding Path=IsChecked, ElementName=GroupActionsToggle, Converter={StaticResource ResourceKey=BooleanToVisibilityCollapsedConverter}}"> diff --git a/Source/NETworkManager/Views/PingMonitorHostView.xaml.cs b/Source/NETworkManager/Views/PingMonitorHostView.xaml.cs index 14ef172187..c9617551dc 100644 --- a/Source/NETworkManager/Views/PingMonitorHostView.xaml.cs +++ b/Source/NETworkManager/Views/PingMonitorHostView.xaml.cs @@ -1,9 +1,21 @@ +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Input; +using System.Windows.Threading; using NETworkManager.ViewModels; namespace NETworkManager.Views; public partial class PingMonitorHostView { + /// + /// Delay before a group's action buttons (Start/Pause/Close), revealed via mouse-over or by + /// clicking/tapping the "..." toggle, are hidden again after the last interaction. + /// + private static readonly TimeSpan GroupActionsAutoCloseDelay = TimeSpan.FromSeconds(20); + private readonly PingMonitorHostViewModel _viewModel = new(); public PingMonitorHostView() @@ -27,4 +39,78 @@ public void OnViewVisible() { _viewModel.OnViewVisible(); } + + /// + /// Reveals the group's action buttons and cancels any pending auto-close, so hovering the + /// header keeps them visible for as long as the mouse stays over it. + /// + private void GroupHeader_MouseEnter(object sender, MouseEventArgs e) + { + if (((Grid)sender).FindName("GroupActionsToggle") is not ToggleButton toggle) + return; + + StopGroupActionsAutoCloseTimer(toggle); + toggle.IsChecked = true; + } + + /// + /// Starts the auto-close countdown once the mouse leaves the header, instead of hiding the + /// action buttons immediately - this avoids them flickering away while moving the mouse + /// from the header onto one of the buttons. + /// + private void GroupHeader_MouseLeave(object sender, MouseEventArgs e) + { + if (((Grid)sender).FindName("GroupActionsToggle") is not ToggleButton toggle) + return; + + if (toggle.IsChecked == true) + StartGroupActionsAutoCloseTimer(toggle); + } + + /// + /// Starts the auto-close countdown when the toggle is checked by a click/tap rather than by + /// hovering the header ( already handles the hover case, + /// and cancels this if the mouse is still over the header). + /// + private void GroupActionsToggle_Checked(object sender, RoutedEventArgs e) + { + var toggle = (ToggleButton)sender; + + if (!IsMouseOverGroupHeader(toggle)) + StartGroupActionsAutoCloseTimer(toggle); + } + + private void GroupActionsToggle_Unchecked(object sender, RoutedEventArgs e) + { + StopGroupActionsAutoCloseTimer((ToggleButton)sender); + } + + private static bool IsMouseOverGroupHeader(ToggleButton toggle) + { + return toggle.Parent is Grid headerGrid && headerGrid.IsMouseOver; + } + + private static void StartGroupActionsAutoCloseTimer(ToggleButton toggle) + { + StopGroupActionsAutoCloseTimer(toggle); + + var timer = new DispatcherTimer { Interval = GroupActionsAutoCloseDelay }; + timer.Tick += (_, _) => + { + StopGroupActionsAutoCloseTimer(toggle); + toggle.IsChecked = false; + }; + + toggle.Tag = timer; + timer.Start(); + } + + private static void StopGroupActionsAutoCloseTimer(ToggleButton toggle) + { + if (toggle.Tag is not DispatcherTimer timer) + return; + + timer.Stop(); + toggle.Tag = null; + } } diff --git a/Website/docs/application/ping-monitor.md b/Website/docs/application/ping-monitor.md index d731b89879..0c5d7425f2 100644 --- a/Website/docs/application/ping-monitor.md +++ b/Website/docs/application/ping-monitor.md @@ -56,7 +56,7 @@ When you zoom or pan, the chart leaves live mode and stops scrolling. A **Live** Hosts are grouped by their profile group (or **Hosts** if none is set). Each group header shows a live count of hosts that are up, down and paused (**Paused** is only shown while at least one host in the group is paused). -Hover over a group header to reveal its action buttons: +Hover over a group header to reveal its action buttons. Without a mouse (touch or keyboard), click/tap the **⋮** icon on the right instead - the buttons then stay visible for 20 seconds, or as long as you keep hovering. | Action | Description | |--------|-------------| diff --git a/Website/docs/changelog/next-release.md b/Website/docs/changelog/next-release.md index 919e0a8504..41200f1d7b 100644 --- a/Website/docs/changelog/next-release.md +++ b/Website/docs/changelog/next-release.md @@ -55,7 +55,7 @@ Release date: **xx.xx.2026** **Ping Monitor** - Added a live count of hosts up/down (and paused, if any) per group, next to the group's close button. [#3572](https://github.com/BornToBeRoot/NETworkManager/pull/3572) -- Added **Start** and **Pause** buttons to each group header (shown next to the close button on mouse-over), to start every paused host in the group or pause every running one at once. [#3575](https://github.com/BornToBeRoot/NETworkManager/pull/3575) +- Added **Start** and **Pause** buttons to each group header, to start every paused host in the group or pause every running one at once. They're shown next to the close button on mouse-over, or by clicking/tapping the **⋮** icon (for touch and keyboard use). [#3575](https://github.com/BornToBeRoot/NETworkManager/pull/3575) - Reworked each monitored host's card: the collapsed quick info now shows labeled values (`Received: X · Lost: Y · Packet loss: Z%`) instead of unlabeled numbers, the expanded view shows only the latency chart (with more room, since Hostname/IP address are already visible in the header) and the last status change time moved to a tooltip on the connectivity icon. The **Status change** field was also renamed to **Last status change**. [#3572](https://github.com/BornToBeRoot/NETworkManager/pull/3572) - Host input now accepts newline-separated hosts (one per line, e.g. a column pasted from Excel), converted automatically to the semicolon-separated form. [#3568](https://github.com/BornToBeRoot/NETworkManager/pull/3568) - Host input now supports shorthand IPv4 ranges like `192.168.0.1-100`, in addition to the existing `192.168.0.0-192.168.0.100` and `192.168.[0-100].1` range formats. [#3568](https://github.com/BornToBeRoot/NETworkManager/pull/3568) From 1aad253b4ed9949337c2c78647e6ebeb739d11a3 Mon Sep 17 00:00:00 2001 From: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> Date: Sun, 16 Aug 2026 18:48:43 +0200 Subject: [PATCH 4/5] Fix: Claude review --- Source/NETworkManager/Views/PingMonitorHostView.xaml | 4 +++- .../NETworkManager/Views/PingMonitorHostView.xaml.cs | 12 +++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Source/NETworkManager/Views/PingMonitorHostView.xaml b/Source/NETworkManager/Views/PingMonitorHostView.xaml index e56b3f785b..8faf93a788 100644 --- a/Source/NETworkManager/Views/PingMonitorHostView.xaml +++ b/Source/NETworkManager/Views/PingMonitorHostView.xaml @@ -208,7 +208,8 @@ - @@ -300,6 +301,7 @@ ToolTip="{x:Static Member=localization:Strings.GroupActions}" Checked="GroupActionsToggle_Checked" Unchecked="GroupActionsToggle_Unchecked" + Unloaded="GroupActionsToggle_Unloaded" Visibility="{Binding Path=IsChecked, RelativeSource={RelativeSource Mode=Self}, Converter={StaticResource ResourceKey=BooleanReverseToVisibilityCollapsedConverter}}"> diff --git a/Source/NETworkManager/Views/PingMonitorHostView.xaml.cs b/Source/NETworkManager/Views/PingMonitorHostView.xaml.cs index c9617551dc..d25c6ccc94 100644 --- a/Source/NETworkManager/Views/PingMonitorHostView.xaml.cs +++ b/Source/NETworkManager/Views/PingMonitorHostView.xaml.cs @@ -85,9 +85,19 @@ private void GroupActionsToggle_Unchecked(object sender, RoutedEventArgs e) StopGroupActionsAutoCloseTimer((ToggleButton)sender); } + /// + /// Stops any pending auto-close timer when the group (and its toggle) is torn down, e.g. + /// because the group was closed - otherwise the timer would keep the detached toggle alive + /// until it fires. + /// + private void GroupActionsToggle_Unloaded(object sender, RoutedEventArgs e) + { + StopGroupActionsAutoCloseTimer((ToggleButton)sender); + } + private static bool IsMouseOverGroupHeader(ToggleButton toggle) { - return toggle.Parent is Grid headerGrid && headerGrid.IsMouseOver; + return toggle.FindName("GroupHeaderGrid") is Grid headerGrid && headerGrid.IsMouseOver; } private static void StartGroupActionsAutoCloseTimer(ToggleButton toggle) From 2c08bfaf317ff9e24065c88f46d655ccbd007f27 Mon Sep 17 00:00:00 2001 From: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> Date: Sun, 16 Aug 2026 21:12:49 +0200 Subject: [PATCH 5/5] Fix: Use context menu instead of buttons --- .../Views/PingMonitorHostView.xaml | 166 ++++++------------ .../Views/PingMonitorHostView.xaml.cs | 97 +--------- Website/docs/application/ping-monitor.md | 2 +- Website/docs/changelog/next-release.md | 4 +- 4 files changed, 69 insertions(+), 200 deletions(-) diff --git a/Source/NETworkManager/Views/PingMonitorHostView.xaml b/Source/NETworkManager/Views/PingMonitorHostView.xaml index 8faf93a788..048c2fe6c1 100644 --- a/Source/NETworkManager/Views/PingMonitorHostView.xaml +++ b/Source/NETworkManager/Views/PingMonitorHostView.xaml @@ -26,6 +26,10 @@ + + @@ -208,9 +212,7 @@ - + @@ -294,15 +296,13 @@ - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/NETworkManager/Views/PingMonitorHostView.xaml.cs b/Source/NETworkManager/Views/PingMonitorHostView.xaml.cs index d25c6ccc94..42366d6a88 100644 --- a/Source/NETworkManager/Views/PingMonitorHostView.xaml.cs +++ b/Source/NETworkManager/Views/PingMonitorHostView.xaml.cs @@ -1,21 +1,11 @@ -using System; using System.Windows; using System.Windows.Controls; -using System.Windows.Controls.Primitives; -using System.Windows.Input; -using System.Windows.Threading; using NETworkManager.ViewModels; namespace NETworkManager.Views; public partial class PingMonitorHostView { - /// - /// Delay before a group's action buttons (Start/Pause/Close), revealed via mouse-over or by - /// clicking/tapping the "..." toggle, are hidden again after the last interaction. - /// - private static readonly TimeSpan GroupActionsAutoCloseDelay = TimeSpan.FromSeconds(20); - private readonly PingMonitorHostViewModel _viewModel = new(); public PingMonitorHostView() @@ -41,86 +31,15 @@ public void OnViewVisible() } /// - /// Reveals the group's action buttons and cancels any pending auto-close, so hovering the - /// header keeps them visible for as long as the mouse stays over it. - /// - private void GroupHeader_MouseEnter(object sender, MouseEventArgs e) - { - if (((Grid)sender).FindName("GroupActionsToggle") is not ToggleButton toggle) - return; - - StopGroupActionsAutoCloseTimer(toggle); - toggle.IsChecked = true; - } - - /// - /// Starts the auto-close countdown once the mouse leaves the header, instead of hiding the - /// action buttons immediately - this avoids them flickering away while moving the mouse - /// from the header onto one of the buttons. - /// - private void GroupHeader_MouseLeave(object sender, MouseEventArgs e) - { - if (((Grid)sender).FindName("GroupActionsToggle") is not ToggleButton toggle) - return; - - if (toggle.IsChecked == true) - StartGroupActionsAutoCloseTimer(toggle); - } - - /// - /// Starts the auto-close countdown when the toggle is checked by a click/tap rather than by - /// hovering the header ( already handles the hover case, - /// and cancels this if the mouse is still over the header). - /// - private void GroupActionsToggle_Checked(object sender, RoutedEventArgs e) - { - var toggle = (ToggleButton)sender; - - if (!IsMouseOverGroupHeader(toggle)) - StartGroupActionsAutoCloseTimer(toggle); - } - - private void GroupActionsToggle_Unchecked(object sender, RoutedEventArgs e) - { - StopGroupActionsAutoCloseTimer((ToggleButton)sender); - } - - /// - /// Stops any pending auto-close timer when the group (and its toggle) is torn down, e.g. - /// because the group was closed - otherwise the timer would keep the detached toggle alive - /// until it fires. + /// Opens the group actions context menu on a normal click (not just right-click), so it + /// works the same way for mouse, touch and keyboard activation. PlacementTarget is set + /// explicitly since it isn't populated automatically when opening the menu this way, and + /// the menu items rely on it to reach the group name (see Button.Tag in the XAML). /// - private void GroupActionsToggle_Unloaded(object sender, RoutedEventArgs e) - { - StopGroupActionsAutoCloseTimer((ToggleButton)sender); - } - - private static bool IsMouseOverGroupHeader(ToggleButton toggle) + private void GroupActionsButton_Click(object sender, RoutedEventArgs e) { - return toggle.FindName("GroupHeaderGrid") is Grid headerGrid && headerGrid.IsMouseOver; - } - - private static void StartGroupActionsAutoCloseTimer(ToggleButton toggle) - { - StopGroupActionsAutoCloseTimer(toggle); - - var timer = new DispatcherTimer { Interval = GroupActionsAutoCloseDelay }; - timer.Tick += (_, _) => - { - StopGroupActionsAutoCloseTimer(toggle); - toggle.IsChecked = false; - }; - - toggle.Tag = timer; - timer.Start(); - } - - private static void StopGroupActionsAutoCloseTimer(ToggleButton toggle) - { - if (toggle.Tag is not DispatcherTimer timer) - return; - - timer.Stop(); - toggle.Tag = null; + var button = (Button)sender; + button.ContextMenu.PlacementTarget = button; + button.ContextMenu.IsOpen = true; } } diff --git a/Website/docs/application/ping-monitor.md b/Website/docs/application/ping-monitor.md index 0c5d7425f2..03e953395f 100644 --- a/Website/docs/application/ping-monitor.md +++ b/Website/docs/application/ping-monitor.md @@ -56,7 +56,7 @@ When you zoom or pan, the chart leaves live mode and stops scrolling. A **Live** Hosts are grouped by their profile group (or **Hosts** if none is set). Each group header shows a live count of hosts that are up, down and paused (**Paused** is only shown while at least one host in the group is paused). -Hover over a group header to reveal its action buttons. Without a mouse (touch or keyboard), click/tap the **⋮** icon on the right instead - the buttons then stay visible for 20 seconds, or as long as you keep hovering. +Click/tap the **⋮** icon on the right of a group header to open its action menu: | Action | Description | |--------|-------------| diff --git a/Website/docs/changelog/next-release.md b/Website/docs/changelog/next-release.md index 41200f1d7b..33e29c9986 100644 --- a/Website/docs/changelog/next-release.md +++ b/Website/docs/changelog/next-release.md @@ -54,8 +54,8 @@ Release date: **xx.xx.2026** **Ping Monitor** -- Added a live count of hosts up/down (and paused, if any) per group, next to the group's close button. [#3572](https://github.com/BornToBeRoot/NETworkManager/pull/3572) -- Added **Start** and **Pause** buttons to each group header, to start every paused host in the group or pause every running one at once. They're shown next to the close button on mouse-over, or by clicking/tapping the **⋮** icon (for touch and keyboard use). [#3575](https://github.com/BornToBeRoot/NETworkManager/pull/3575) +- Added a live count of hosts up/down (and paused, if any) to each group header. [#3572](https://github.com/BornToBeRoot/NETworkManager/pull/3572) +- Added **Start** and **Pause** actions to each group header (next to the existing **Close**), to start every paused host in the group or pause every running one at once. Click/tap the **⋮** icon to open the group's action menu. [#3575](https://github.com/BornToBeRoot/NETworkManager/pull/3575) - Reworked each monitored host's card: the collapsed quick info now shows labeled values (`Received: X · Lost: Y · Packet loss: Z%`) instead of unlabeled numbers, the expanded view shows only the latency chart (with more room, since Hostname/IP address are already visible in the header) and the last status change time moved to a tooltip on the connectivity icon. The **Status change** field was also renamed to **Last status change**. [#3572](https://github.com/BornToBeRoot/NETworkManager/pull/3572) - Host input now accepts newline-separated hosts (one per line, e.g. a column pasted from Excel), converted automatically to the semicolon-separated form. [#3568](https://github.com/BornToBeRoot/NETworkManager/pull/3568) - Host input now supports shorthand IPv4 ranges like `192.168.0.1-100`, in addition to the existing `192.168.0.0-192.168.0.100` and `192.168.[0-100].1` range formats. [#3568](https://github.com/BornToBeRoot/NETworkManager/pull/3568)