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
Binary file modified App/Dialogs/HelpDialog.cs
Binary file not shown.
135 changes: 0 additions & 135 deletions App/Dialogs/QuickHelpDialog.cs

This file was deleted.

1 change: 0 additions & 1 deletion App/Keybindings/DefaultKeybindings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ public interface IKeybindingActions
// Navigation
void SwitchPane();
void ShowHelp();
void ShowQuickHelp();

// Address Space
void SubscribeSelected();
Expand Down
5 changes: 0 additions & 5 deletions App/Keybindings/KeybindingContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,6 @@ public enum KeybindingContext
/// </summary>
Scope,

/// <summary>
/// Keybindings active when TrendPlotView is displayed.
/// </summary>
TrendPlot,

/// <summary>
/// Keybindings active in dialogs.
/// </summary>
Expand Down
4 changes: 1 addition & 3 deletions App/Keybindings/KeybindingManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,6 @@ public static string GetContextDisplayName(KeybindingContext context)
KeybindingContext.AddressSpace => "Address Space",
KeybindingContext.MonitoredVariables => "Monitored Variables",
KeybindingContext.Scope => "Scope View",
KeybindingContext.TrendPlot => "Trend Plot",
KeybindingContext.Dialog => "Dialog",
_ => context.ToString()
};
Expand All @@ -279,8 +278,7 @@ private static int GetContextOrder(KeybindingContext context)
KeybindingContext.AddressSpace => 1,
KeybindingContext.MonitoredVariables => 2,
KeybindingContext.Scope => 3,
KeybindingContext.TrendPlot => 4,
KeybindingContext.Dialog => 5,
KeybindingContext.Dialog => 4,
_ => 99
};
}
Expand Down
52 changes: 30 additions & 22 deletions App/MainWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ public class MainWindow : Toplevel, DefaultKeybindings.IKeybindingActions
private View? _focusedPanel;
private FocusManager? _focusManager;

// Stored so it can be unsubscribed from the static Application event in Dispose
private readonly EventHandler<SizeChangedEventArgs> _sizeChangingHandler;

// Lazygit-inspired keybinding system
private readonly KeybindingManager _keybindingManager;

Expand Down Expand Up @@ -223,7 +226,8 @@ public MainWindow()
ApplyTheme();

// Handle window resize to update connection status label position
Application.SizeChanging += (s, e) => UiThread.Run(UpdateConnectionStatusLabelPosition);
_sizeChangingHandler = (s, e) => UiThread.Run(UpdateConnectionStatusLabelPosition);
Application.SizeChanging += _sizeChangingHandler;

// Run status bar startup sequence
RunStatusBarStartup();
Expand Down Expand Up @@ -295,8 +299,7 @@ private MenuBar CreateMenuBar()
new MenuItem("_Save Config", "", SaveConfig, shortcutKey: Key.S.WithCtrl),
new MenuItem("Save Config _As...", "", SaveConfigAs, shortcutKey: Key.S.WithCtrl.WithShift),
null!, // Separator
new MenuItem("Start Recording...", "", () => OnRecordRequested(), shortcutKey: Key.R.WithCtrl),
new MenuItem("Stop Recording", "", () => OnStopRecordingRequested()),
new MenuItem("Toggle Recording", "", ToggleRecording, shortcutKey: Key.R.WithCtrl),
null!, // Separator
new MenuItem("E_xit", "", () => RequestStop(), shortcutKey: Key.Q.WithCtrl)
}),
Expand Down Expand Up @@ -761,15 +764,6 @@ private void UpdateStatusBarShortcuts()
_statusBar.SetNeedsLayout();
}

/// <summary>
/// Shows context-sensitive quick help overlay (lazygit-inspired ? menu).
/// </summary>
private void ShowQuickHelp()
{
using var dialog = new QuickHelpDialog(_keybindingManager);
Application.Run(dialog);
}

#endregion

#region Global Keyboard Shortcuts
Expand Down Expand Up @@ -867,14 +861,6 @@ private void OnConnectionStateChanged(ConnectionState state)
});
}

private void OnClientDisconnected()
{
UiThread.Run(() =>
{
UpdateConnectionStatus(isConnected: false);
});
}

private void OnConnectionError(string message)
{
UiThread.Run(() =>
Expand Down Expand Up @@ -1111,7 +1097,7 @@ private void ShowHelp()

private void ShowAbout()
{
var version = Assembly.GetExecutingAssembly().GetName().Version?.ToString(3) ?? "0.0.0";
var version = GetDisplayVersion();
var titleLine = $"opcilloscope v{version}";
var titlePadded = titleLine.PadLeft((38 + titleLine.Length) / 2).PadRight(38);

Expand Down Expand Up @@ -1140,6 +1126,28 @@ industrial automation data in real-time.
MessageBox.Query("About opcilloscope", about, "OK");
}

/// <summary>
/// Gets the application version for display. MinVer writes the full semver to
/// <see cref="AssemblyInformationalVersionAttribute"/> (AssemblyVersion is frozen at
/// MAJOR.0.0.0), so prefer that and strip any "+commitsha" build metadata.
/// </summary>
private static string GetDisplayVersion()
{
var assembly = Assembly.GetExecutingAssembly();
var informational = assembly
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?
.InformationalVersion;

if (!string.IsNullOrEmpty(informational))
{
var metadataIndex = informational.IndexOf('+');
return metadataIndex >= 0 ? informational[..metadataIndex] : informational;
}

// Fall back to the assembly version if the attribute is missing
return assembly.GetName().Version?.ToString(3) ?? "0.0.0";
}

#region Configuration File Handling

/// <summary>
Expand Down Expand Up @@ -1399,7 +1407,6 @@ public void LoadConfigFromCommandLine(string configPath)

void DefaultKeybindings.IKeybindingActions.SwitchPane() => _focusManager?.FocusNext();
void DefaultKeybindings.IKeybindingActions.ShowHelp() => ShowHelp();
void DefaultKeybindings.IKeybindingActions.ShowQuickHelp() => ShowQuickHelp();
void DefaultKeybindings.IKeybindingActions.SubscribeSelected() => SubscribeSelected();
void DefaultKeybindings.IKeybindingActions.RefreshTree() => RefreshTree();
void DefaultKeybindings.IKeybindingActions.UnsubscribeSelected() => UnsubscribeSelected();
Expand Down Expand Up @@ -1442,6 +1449,7 @@ protected override void Dispose(bool disposing)
}

Application.KeyDown -= OnApplicationKeyDown;
Application.SizeChanging -= _sizeChangingHandler;

_connectionManager.Dispose();
}
Expand Down
4 changes: 4 additions & 0 deletions App/Views/LogView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ protected override void Dispose(bool disposing)
{
if (disposing)
{
if (_logger != null)
{
_logger.LogAdded -= OnLogAdded;
}
_copyButton.Accepting -= OnCopyClicked;
_listView.RowRender -= OnRowRender;
ThemeManager.ThemeChanged -= OnThemeChanged;
Expand Down
17 changes: 14 additions & 3 deletions App/Views/NodeDetailsView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ public async Task ShowNodeByIdAsync(NodeId? nodeId)

Application.Invoke(() =>
{
// Guard against stale responses: rapid selection changes can complete
// out of order, so only apply this result if it is still the current node.
if (!Equals(_currentNodeId, nodeId))
return;

if (attrs == null)
{
_detailsLabel.Text = $"NodeId: {nodeId}\nFailed to read attributes";
Expand Down Expand Up @@ -165,14 +170,20 @@ public async Task ShowNodeAsync(BrowsedNode? node)
return;
}

_currentNodeId = node.NodeId;
var attrs = await _nodeBrowser.GetNodeAttributesAsync(node.NodeId);
var nodeId = node.NodeId;
_currentNodeId = nodeId;
var attrs = await _nodeBrowser.GetNodeAttributesAsync(nodeId);

Application.Invoke(() =>
{
// Guard against stale responses: rapid selection changes can complete
// out of order, so only apply this result if it is still the current node.
if (!Equals(_currentNodeId, nodeId))
return;

if (attrs == null)
{
_detailsLabel.Text = $"NodeId: {node.NodeId}\nFailed to read attributes";
_detailsLabel.Text = $"NodeId: {nodeId}\nFailed to read attributes";
_copyButton.Enabled = false;
SetNormalColor();
return;
Expand Down
6 changes: 5 additions & 1 deletion App/Views/ScopeView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,11 @@ private void DrawXAxisLabels(AppTheme theme, int plotLeft, int labelY,
int x = plotLeft + (int)(fraction * (plotWidth - 1));
// Center the label around x
int labelX = x - label.Length / 2;
labelX = Math.Clamp(labelX, plotLeft, plotLeft + plotWidth - label.Length);
int maxLabelX = plotLeft + plotWidth - label.Length;
if (maxLabelX < plotLeft)
continue; // Label wider than the plot area (tiny terminal) - skip it

labelX = Math.Clamp(labelX, plotLeft, maxLabelX);

Move(labelX, labelY);
Driver!.AddStr(label);
Expand Down
3 changes: 1 addition & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,7 @@ Opcilloscope/
│ │ ├── ScopeDialog.cs # Multi-signal scope dialog (up to 5 signals)
│ │ ├── SaveConfigDialog.cs # Save configuration file dialog
│ │ ├── SaveRecordingDialog.cs # Save CSV recording dialog
│ │ ├── HelpDialog.cs # Full help/documentation dialog
│ │ └── QuickHelpDialog.cs # Quick keyboard shortcuts reference
│ │ └── HelpDialog.cs # Full help/documentation dialog
│ ├── Keybindings/
│ │ ├── Keybinding.cs # Keybinding model (key, action, context)
│ │ ├── KeybindingContext.cs # Context enum (Global, AddressSpace, etc.)
Expand Down
2 changes: 1 addition & 1 deletion Configuration/Models/OpcilloscopeConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public class SubscriptionSettings
/// <summary>
/// Publishing interval (in milliseconds) for the OPC UA subscription.
/// Controls how often the server sends data-change notifications to the client.
/// This directly determines the data resolution for Scope, Trend Plot, and CSV recording:
/// This directly determines the data resolution for Scope and CSV recording:
/// a 1000 ms interval means roughly one data point per second per variable.
/// Valid range: 100-10000 ms (values outside this range will be clamped by SubscriptionManager).
/// </summary>
Expand Down
Loading
Loading