feat(windows): UI overhaul -- toolbar, unified log, PM windows, channel counts, output volume
- Voice actions (Join Voice, Share Screen Audio) moved to a ToolStrip toolbar and
a new Voice menu in the menu bar; removed from the bottom voice panel
- Activity log and chat log collapsed into a single RichTextBox (rtbLog); activity
events appear in gray, chat messages in default color
- Private messaging reworked: each conversation opens in its own modeless
PrivateMessageForm instead of sharing the main chat log via a scope dropdown;
cboScope removed; main compose bar always sends to the current channel
- New "Messages -> New Private Message..." menu item (Ctrl+P) opens a UserPickerDialog
listing all connected server users (not just the current channel) so you can PM
anyone on the server
- Channel tree now shows live user counts, e.g. "General (3)" -- counts sourced from
the existing _users dictionary which already tracks all server users with channel IDs
- Global output volume slider (TrackBar, 0-100, default 80) added to the right panel;
wired to new vc_set_output_volume C ABI function that applies a master gain multiplier
in the audio engine playback callback after mixing all streams
- vc_set_output_volume added end-to-end: voicecat.h, audio_engine.h/.cpp,
client.h/.cpp, voicecat.cpp, NativeMethods.cs, VoiceCatClient.cs
- Documented Windows PowerShell ctest requirement in AGENTS.md and CLAUDE.md:
MinGW binaries exit 0xc0000139 in Git Bash; always run ctest/.exe via PowerShell
22/22 ctest green (PowerShell); dotnet build 0 warnings.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 14:24:54 +02:00
|
|
|
using VoiceCat.Interop;
|
|
|
|
|
|
|
|
|
|
namespace VoiceCat.App.Forms;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Modeless window for a single private message conversation.
|
|
|
|
|
/// Created by MainForm and shown non-modally; MainForm routes incoming PMs here.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public sealed class PrivateMessageForm : Form
|
|
|
|
|
{
|
|
|
|
|
private readonly VoiceCatClient _client;
|
|
|
|
|
private readonly uint _userId;
|
|
|
|
|
private readonly uint _selfUserId;
|
|
|
|
|
|
|
|
|
|
private readonly RichTextBox _rtbHistory;
|
|
|
|
|
private readonly TextBox _txtCompose;
|
|
|
|
|
private readonly Button _btnSend;
|
|
|
|
|
|
|
|
|
|
public PrivateMessageForm(VoiceCatClient client, uint userId, string nickname, uint selfUserId)
|
|
|
|
|
{
|
|
|
|
|
_client = client;
|
|
|
|
|
_userId = userId;
|
|
|
|
|
_selfUserId = selfUserId;
|
|
|
|
|
|
|
|
|
|
Text = $"Private Message — {nickname}";
|
|
|
|
|
ClientSize = new Size(480, 360);
|
|
|
|
|
MinimumSize = new Size(320, 240);
|
|
|
|
|
StartPosition = FormStartPosition.Manual;
|
2026-06-24 12:30:48 +02:00
|
|
|
KeyPreview = true;
|
|
|
|
|
KeyDown += (_, e) =>
|
|
|
|
|
{
|
|
|
|
|
if (e.KeyCode == Keys.Escape) { e.Handled = e.SuppressKeyPress = true; Close(); }
|
|
|
|
|
};
|
feat(windows): UI overhaul -- toolbar, unified log, PM windows, channel counts, output volume
- Voice actions (Join Voice, Share Screen Audio) moved to a ToolStrip toolbar and
a new Voice menu in the menu bar; removed from the bottom voice panel
- Activity log and chat log collapsed into a single RichTextBox (rtbLog); activity
events appear in gray, chat messages in default color
- Private messaging reworked: each conversation opens in its own modeless
PrivateMessageForm instead of sharing the main chat log via a scope dropdown;
cboScope removed; main compose bar always sends to the current channel
- New "Messages -> New Private Message..." menu item (Ctrl+P) opens a UserPickerDialog
listing all connected server users (not just the current channel) so you can PM
anyone on the server
- Channel tree now shows live user counts, e.g. "General (3)" -- counts sourced from
the existing _users dictionary which already tracks all server users with channel IDs
- Global output volume slider (TrackBar, 0-100, default 80) added to the right panel;
wired to new vc_set_output_volume C ABI function that applies a master gain multiplier
in the audio engine playback callback after mixing all streams
- vc_set_output_volume added end-to-end: voicecat.h, audio_engine.h/.cpp,
client.h/.cpp, voicecat.cpp, NativeMethods.cs, VoiceCatClient.cs
- Documented Windows PowerShell ctest requirement in AGENTS.md and CLAUDE.md:
MinGW binaries exit 0xc0000139 in Git Bash; always run ctest/.exe via PowerShell
22/22 ctest green (PowerShell); dotnet build 0 warnings.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 14:24:54 +02:00
|
|
|
|
|
|
|
|
_rtbHistory = new RichTextBox
|
|
|
|
|
{
|
|
|
|
|
ReadOnly = true,
|
|
|
|
|
Dock = DockStyle.Fill,
|
|
|
|
|
ScrollBars = RichTextBoxScrollBars.Vertical,
|
|
|
|
|
BackColor = SystemColors.Window,
|
|
|
|
|
AccessibleName = "Message history",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var composePanel = new TableLayoutPanel
|
|
|
|
|
{
|
|
|
|
|
Dock = DockStyle.Bottom,
|
|
|
|
|
Height = 34,
|
|
|
|
|
ColumnCount = 2,
|
|
|
|
|
RowCount = 1,
|
|
|
|
|
Padding = new Padding(0, 3, 0, 0),
|
|
|
|
|
};
|
|
|
|
|
composePanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
|
|
|
|
|
composePanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 68F));
|
|
|
|
|
composePanel.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
|
|
|
|
|
|
|
|
|
|
_txtCompose = new TextBox
|
|
|
|
|
{
|
|
|
|
|
Dock = DockStyle.Fill,
|
|
|
|
|
AccessibleName = "Message text",
|
|
|
|
|
};
|
|
|
|
|
_btnSend = new Button
|
|
|
|
|
{
|
|
|
|
|
Text = "&Send",
|
|
|
|
|
Dock = DockStyle.Fill,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
composePanel.Controls.Add(_txtCompose, 0, 0);
|
|
|
|
|
composePanel.Controls.Add(_btnSend, 1, 0);
|
|
|
|
|
|
|
|
|
|
Controls.Add(_rtbHistory);
|
|
|
|
|
Controls.Add(composePanel);
|
|
|
|
|
|
|
|
|
|
_txtCompose.KeyDown += (_, e) =>
|
|
|
|
|
{
|
|
|
|
|
if (e.KeyCode == Keys.Enter) { Send(); e.Handled = e.SuppressKeyPress = true; }
|
|
|
|
|
};
|
|
|
|
|
_btnSend.Click += (_, _) => Send();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Called by MainForm when a PM message arrives (or we send one and the server echoes it).
|
|
|
|
|
public void AppendMessage(string time, bool isSelf, string sender, string text)
|
|
|
|
|
{
|
|
|
|
|
if (IsDisposed) return;
|
|
|
|
|
string line = $"[{time}] {sender}: {text}\n";
|
|
|
|
|
int selStart = _rtbHistory.TextLength;
|
|
|
|
|
_rtbHistory.AppendText(line);
|
|
|
|
|
if (isSelf)
|
|
|
|
|
{
|
|
|
|
|
_rtbHistory.Select(selStart, line.Length);
|
|
|
|
|
_rtbHistory.SelectionColor = Color.Gray;
|
|
|
|
|
_rtbHistory.Select(_rtbHistory.TextLength, 0);
|
|
|
|
|
_rtbHistory.SelectionColor = _rtbHistory.ForeColor;
|
|
|
|
|
}
|
|
|
|
|
_rtbHistory.ScrollToCaret();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Called by MainForm for status events (e.g., the other user disconnected).
|
|
|
|
|
public void AppendActivity(string text)
|
|
|
|
|
{
|
|
|
|
|
if (IsDisposed) return;
|
|
|
|
|
string line = $"[{DateTime.Now:HH:mm}] {text}\n";
|
|
|
|
|
int selStart = _rtbHistory.TextLength;
|
|
|
|
|
_rtbHistory.AppendText(line);
|
|
|
|
|
_rtbHistory.Select(selStart, line.Length);
|
|
|
|
|
_rtbHistory.SelectionColor = Color.Gray;
|
|
|
|
|
_rtbHistory.Select(_rtbHistory.TextLength, 0);
|
|
|
|
|
_rtbHistory.SelectionColor = _rtbHistory.ForeColor;
|
|
|
|
|
_rtbHistory.ScrollToCaret();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Send()
|
|
|
|
|
{
|
|
|
|
|
string msg = _txtCompose.Text.Trim();
|
|
|
|
|
if (string.IsNullOrEmpty(msg)) return;
|
|
|
|
|
_client.SendText(VcTextScope.Private, _userId, msg);
|
|
|
|
|
_txtCompose.Clear();
|
|
|
|
|
// No optimistic echo: the server relays our own message back, so AppendMessage is
|
|
|
|
|
// called from MainForm.HandleTextMessage when the echo arrives.
|
|
|
|
|
}
|
|
|
|
|
}
|