feat: Implement chat line wrapping and viewport resizing for message display

This commit is contained in:
HueByte
2026-02-19 09:11:01 +01:00
parent 96b31ec568
commit bed6040f7c
3 changed files with 82 additions and 4 deletions
+52
View File
@@ -35,6 +35,58 @@ public partial class ChatLine
public override string ToString() => string.Concat(Segments.Select(s => s.Text));
/// <summary>
/// Wrap this line into multiple lines that fit within the given width.
/// Continuation lines are indented with the specified number of spaces.
/// </summary>
public List<ChatLine> Wrap(int width, int continuationIndent = 0)
{
if (width <= 0 || TextLength <= width)
return [this];
var results = new List<ChatLine>();
var currentSegments = new List<ChatSegment>();
int col = 0;
foreach (var segment in Segments)
{
int segPos = 0;
while (segPos < segment.Text.Length)
{
int remaining = width - col;
if (remaining <= 0)
{
// Emit current line and start a new one
results.Add(new ChatLine(currentSegments));
currentSegments = [];
// Add indent for continuation
if (continuationIndent > 0)
{
currentSegments.Add(new ChatSegment(new string(' ', continuationIndent), null));
col = continuationIndent;
}
else
{
col = 0;
}
remaining = width - col;
}
int take = Math.Min(segment.Text.Length - segPos, remaining);
currentSegments.Add(new ChatSegment(segment.Text.Substring(segPos, take), segment.Color));
col += take;
segPos += take;
}
}
if (currentSegments.Count > 0)
results.Add(new ChatLine(currentSegments));
return results;
}
/// <summary>
/// Parse a string containing ANSI 24-bit color escape codes into colored segments.
/// Format: \x1b[38;2;R;G;Bm (foreground color), \x1b[0m (reset)
+28 -3
View File
@@ -45,6 +45,7 @@ public sealed class MainWindow : Runnable
private readonly Dictionary<string, string?> _channelTopics = [];
private string _currentChannel = string.Empty;
private string _currentUser = string.Empty;
private int _lastChatWidth;
/// <summary>
/// Fired when the user selects a channel. Parameter is the channel name.
@@ -192,6 +193,9 @@ public sealed class MainWindow : Runnable
// Apply our custom color schemes to all views
ApplyColorSchemes();
// Re-wrap messages when the chat area is resized
_messageList.ViewportChanged += (_, _) => OnChatViewportChanged();
// Window-level key handling for Ctrl+C (quit)
KeyDown += OnWindowKeyDown;
}
@@ -368,6 +372,16 @@ public sealed class MainWindow : Runnable
}
}
private void OnChatViewportChanged()
{
var newWidth = _messageList.Viewport.Width;
if (newWidth > 0 && newWidth != _lastChatWidth)
{
_lastChatWidth = newWidth;
RefreshMessages();
}
}
private void OnWindowKeyDown(object? sender, Key e)
{
// Ctrl+C quits from anywhere
@@ -588,11 +602,22 @@ public sealed class MainWindow : Runnable
{
if (_channelMessages.TryGetValue(_currentChannel, out var messages))
{
var width = _messageList.Viewport.Width;
var source = new ChatListSource();
source.AddRange(messages);
if (width > 0)
{
foreach (var line in messages)
source.AddRange(line.Wrap(width));
}
else
{
source.AddRange(messages);
}
_messageList.Source = source;
if (messages.Count > 0)
_messageList.SelectedItem = messages.Count - 1;
if (source.Count > 0)
_messageList.SelectedItem = source.Count - 1;
}
else
{
+2 -1
View File
@@ -146,7 +146,8 @@ public sealed class UserPanelDialog
Width = Dim.Fill(1),
Height = 3,
Text = bioText,
ReadOnly = true
ReadOnly = true,
WordWrap = true
};
bioView.SetScheme(new Scheme
{