transcriptview perf: only draw the items that are actually visible.
This commit is contained in:
@@ -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();
|
||||
|
||||
var origin = Graphene.Point() {
|
||||
x = (chat_item.from_me ? (container_width - item_width - bubble_margin) : bubble_margin),
|
||||
y = y_offset
|
||||
};
|
||||
|
||||
var size = Graphene.Size() {
|
||||
width = item_width,
|
||||
height = item_height
|
||||
};
|
||||
|
||||
var rect = Graphene.Rect() {
|
||||
origin = origin,
|
||||
size = size
|
||||
};
|
||||
|
||||
// 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);
|
||||
|
||||
// Translate to the correct position
|
||||
snapshot.translate(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 });
|
||||
|
||||
chat_item.draw(snapshot);
|
||||
snapshot.restore();
|
||||
}
|
||||
|
||||
y_offset -= item_height + chat_item.vertical_padding;
|
||||
y_offset += item_height + chat_item.vertical_padding;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user