Private
Public Access
1
0

Add 'gtk/' from commit '7d0dfb455aa86245231b383a92e79b3c08a12d5e'

git-subtree-dir: gtk
git-subtree-mainline: c710c6e053
git-subtree-split: 7d0dfb455a
This commit is contained in:
2025-09-06 19:34:30 -07:00
39 changed files with 3599 additions and 0 deletions

View File

@@ -0,0 +1,140 @@
using Gee;
using Gtk;
private class SizeCache
{
private static SizeCache instance = null;
private HashMap<string, Graphene.Size?> size_cache = new HashMap<string, Graphene.Size?>();
public static SizeCache get_instance() {
if (instance == null) {
instance = new SizeCache();
}
return instance;
}
public Graphene.Size? get_size(string image_path) {
return size_cache.get(image_path);
}
public void set_size(string image_path, Graphene.Size size) {
size_cache.set(image_path, size);
}
}
private class ImageBubbleLayout : BubbleLayout
{
public string image_path;
public bool is_downloaded;
public string? attachment_guid;
private Graphene.Size image_size;
private Gdk.Texture? cached_texture = null;
public ImageBubbleLayout(string image_path, bool from_me, Widget parent, float max_width, Graphene.Size? image_size = null) {
base(parent, max_width);
this.from_me = from_me;
this.image_path = image_path;
this.is_downloaded = false;
// Calculate image dimensions for layout
calculate_image_dimensions(image_size);
}
private void calculate_image_dimensions(Graphene.Size? image_size) {
if (image_size != null) {
this.image_size = image_size;
return;
}
var cached_size = SizeCache.get_instance().get_size(image_path);
if (cached_size != null) {
this.image_size = cached_size;
return;
}
// Try to load the image to get its dimensions
try {
warning("No image size provided, loading image to get dimensions");
var texture = Gdk.Texture.from_filename(image_path);
var original_width = (float)texture.get_width();
var original_height = (float)texture.get_height();
this.image_size = Graphene.Size() { width = original_width, height = original_height };
SizeCache.get_instance().set_size(image_path, this.image_size);
} catch (Error e) {
// Fallback dimensions if image can't be loaded
warning("Failed to load image %s: %s", image_path, e.message);
this.image_size = Graphene.Size() { width = 200.0f, height = 150.0f };
}
}
private void load_image_if_needed() {
if (cached_texture != null) {
return;
}
if (!is_downloaded) {
return;
}
try {
cached_texture = Gdk.Texture.from_filename(image_path);
} catch (Error e) {
warning("Failed to load image %s: %s", image_path, e.message);
}
}
private float intrinsic_height {
get {
var scale_factor = float.min(max_width / image_size.width, 1.0f);
return image_size.height * scale_factor;
}
}
private float intrinsic_width {
get {
var scale_factor = float.min(max_width / image_size.width, 1.0f);
return image_size.width * scale_factor;
}
}
public override float get_height() {
return float.max(intrinsic_height, 100.0f);
}
public override float get_width() {
return float.max(intrinsic_width, 200.0f);
}
public override void draw_content(Snapshot snapshot) {
load_image_if_needed();
snapshot.save();
var image_rect = Graphene.Rect () {
origin = Graphene.Point() { x = 0, y = 0 },
size = Graphene.Size() { width = intrinsic_width, height = intrinsic_height }
};
// Center image in the bubble (if it's smaller than the bubble)
snapshot.translate(Graphene.Point() {
x = (get_width() - intrinsic_width) / 2,
y = (get_height() - intrinsic_height) / 2
});
if (cached_texture != null) {
snapshot.append_texture(cached_texture, image_rect);
} else {
snapshot.append_color(Gdk.RGBA() { red = 0.6f, green = 0.6f, blue = 0.6f, alpha = 0.5f }, image_rect);
}
snapshot.restore();
}
public override void copy(Gdk.Clipboard clipboard) {
clipboard.set_texture(cached_texture);
}
}