Private
Public Access
1
0

transcriptview perf: only draw the items that are actually visible.

This commit is contained in:
2025-06-16 20:09:56 -07:00
parent 2db0e3136e
commit c70ae00d5b
2 changed files with 69 additions and 18 deletions

View File

@@ -4,12 +4,25 @@ using Gee;
private class TranscriptDrawingArea : Widget
{
public bool show_sender = true;
public Adjustment? viewport {
get {
return _viewport;
}
set {
_viewport = value;
queue_draw();
}
}
private ArrayList<Message> _messages = new ArrayList<Message>();
private ArrayList<ChatItemLayout> _chat_items = new ArrayList<ChatItemLayout>();
private Adjustment? _viewport = null;
private const float bubble_margin = 18.0f;
private const bool debug_viewport = false;
public TranscriptDrawingArea() {
add_css_class("transcript-drawing-area");
}
@@ -51,33 +64,63 @@ private class TranscriptDrawingArea : Widget
}
public override void snapshot(Snapshot snapshot) {
float y_offset = 0;
var container_width = get_width();
const int viewport_y_padding = 50;
var viewport_rect = Graphene.Rect() {
origin = Graphene.Point() { x = 0, y = ((int)viewport.value - viewport_y_padding) },
size = Graphene.Size() { width = get_width(), height = (int)viewport.page_size + (viewport_y_padding * 2) }
};
if (debug_viewport) {
// Draw viewport outline for debugging
var color = Gdk.RGBA() { red = 1.0f, green = 0, blue = 0, alpha = 1.0f };
snapshot.append_border(
Gsk.RoundedRect().init_from_rect(viewport_rect, 0),
{ 1, 1, 1, 1 },
{ color, color, color, color }
);
}
// Draw each item in reverse order, since the messages are in reverse order
float y_offset = 0;
int container_width = get_width();
for (int i = _chat_items.size - 1; i >= 0; i--) {
var chat_item = _chat_items[i];
var item_width = chat_item.get_width();
var item_height = chat_item.get_height();
snapshot.save();
// Flip the y-axis, since our parent is upside down (so newest messages are at the bottom)
snapshot.scale(1.0f, -1.0f);
// Translate to the correct position
snapshot.translate(Graphene.Point() {
var origin = Graphene.Point() {
x = (chat_item.from_me ? (container_width - item_width - bubble_margin) : bubble_margin),
y = y_offset
});
};
// Undo the y-axis flip, origin is top left
snapshot.translate(Graphene.Point() { x = 0, y = -item_height });
var size = Graphene.Size() {
width = item_width,
height = item_height
};
chat_item.draw(snapshot);
snapshot.restore();
var rect = Graphene.Rect() {
origin = origin,
size = size
};
y_offset -= item_height + chat_item.vertical_padding;
// Skip drawing if this item is not in the viewport
if (viewport_rect.intersection(rect, null)) {
snapshot.save();
// Translate to the correct position
snapshot.translate(origin);
// Flip the y-axis, since our parent is upside down (so newest messages are at the bottom)
snapshot.scale(1.0f, -1.0f);
// Undo the y-axis flip, origin is top left
snapshot.translate(Graphene.Point() { x = 0, y = -item_height });
chat_item.draw(snapshot);
snapshot.restore();
}
y_offset += item_height + chat_item.vertical_padding;
}
}

View File

@@ -17,8 +17,10 @@ public class TranscriptView : Adw.Bin
_model = value;
if (value != null) {
// Reset scroll position
scrolled_window.vadjustment = new Gtk.Adjustment(0, 0, 0, 0, 0, 0);
// Reset scroll position by updating the existing adjustment
scrolled_window.vadjustment.value = 0;
scrolled_window.vadjustment.upper = 0;
scrolled_window.vadjustment.page_size = 0;
weak TranscriptView self = this;
messages_changed_handler_id = value.messages_changed.connect(() => {
@@ -56,8 +58,14 @@ public class TranscriptView : Adw.Bin
scrolled_window.set_child(transcript_drawing_area);
scrolled_window.add_css_class("message-list-scroller");
transcript_drawing_area.viewport = scrolled_window.vadjustment;
container.set_content(scrolled_window);
// Connect to the adjustment's value_changed signal
scrolled_window.vadjustment.value_changed.connect(() => {
transcript_drawing_area.viewport = scrolled_window.vadjustment;
});
var header_bar = new Adw.HeaderBar();
title_label.single_line_mode = true;
title_label.ellipsize = Pango.EllipsizeMode.END;