media_preview.c (3877B)
1 /* 2 This file is part of GNUnet. 3 Copyright (C) 2024 GNUnet e.V. 4 5 GNUnet is free software: you can redistribute it and/or modify it 6 under the terms of the GNU Affero General Public License as published 7 by the Free Software Foundation, either version 3 of the License, 8 or (at your option) any later version. 9 10 GNUnet is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Affero General Public License for more details. 14 15 You should have received a copy of the GNU Affero General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 SPDX-License-Identifier: AGPL3.0-or-later 19 */ 20 /* 21 * @author Tobias Frisch 22 * @file ui/media_preview.c 23 */ 24 25 #include "media_preview.h" 26 27 #include "../application.h" 28 #include "../file.h" 29 #include "../ui.h" 30 31 static gboolean 32 handle_preview_drawing_area_draw(GtkWidget* drawing_area, 33 cairo_t* cairo, 34 gpointer user_data) 35 { 36 g_assert((drawing_area) && (cairo) && (user_data)); 37 38 UI_MEDIA_PREVIEW_Handle *handle = (UI_MEDIA_PREVIEW_Handle*) user_data; 39 40 GtkStyleContext* context = gtk_widget_get_style_context(drawing_area); 41 42 const guint width = gtk_widget_get_allocated_width(drawing_area); 43 const guint height = gtk_widget_get_allocated_height(drawing_area); 44 45 gtk_render_background(context, cairo, 0, 0, width, height); 46 47 if (!(handle->file)) 48 return FALSE; 49 50 GdkPixbuf *image = file_get_current_preview_image(handle->file); 51 52 if (!image) 53 return FALSE; 54 55 int swidth = gdk_pixbuf_get_width(image); 56 int sheight = gdk_pixbuf_get_height(image); 57 58 int sx = 0; 59 int sy = 0; 60 61 if (swidth > sheight) 62 { 63 sx = swidth - sheight; 64 swidth -= sx; 65 sx /= 2; 66 } 67 else 68 { 69 sy = sheight - swidth; 70 sheight -= sy; 71 sy /= 2; 72 } 73 74 double ratio_width = 1.0 * width / swidth; 75 double ratio_height = 1.0 * height / sheight; 76 77 const double ratio = ratio_width < ratio_height? ratio_width : ratio_height; 78 79 const int interp_type = (ratio >= 1.0? 80 GDK_INTERP_NEAREST : 81 GDK_INTERP_BILINEAR 82 ); 83 84 GdkPixbuf* subimage = gdk_pixbuf_new_subpixbuf( 85 image, 86 sx, 87 sy, 88 swidth, 89 sheight 90 ); 91 92 GdkPixbuf* scaled = gdk_pixbuf_scale_simple( 93 subimage, 94 width, 95 height, 96 interp_type 97 ); 98 99 g_object_unref(subimage); 100 gtk_render_icon(context, cairo, scaled, 0, 0); 101 102 cairo_fill(cairo); 103 g_object_unref(scaled); 104 105 return FALSE; 106 } 107 108 UI_MEDIA_PREVIEW_Handle* 109 ui_media_preview_new(MESSENGER_Application *app) 110 { 111 g_assert(app); 112 113 UI_MEDIA_PREVIEW_Handle* handle = g_malloc(sizeof(UI_MEDIA_PREVIEW_Handle)); 114 115 handle->file = NULL; 116 117 handle->builder = ui_builder_from_resource( 118 application_get_resource_path(app, "ui/media_preview.ui") 119 ); 120 121 handle->media_box = GTK_WIDGET( 122 gtk_builder_get_object(handle->builder, "media_box") 123 ); 124 125 handle->preview_drawing_area = GTK_DRAWING_AREA( 126 gtk_builder_get_object(handle->builder, "preview_drawing_area") 127 ); 128 129 handle->app = app; 130 131 g_signal_connect( 132 handle->preview_drawing_area, 133 "draw", 134 G_CALLBACK(handle_preview_drawing_area_draw), 135 handle 136 ); 137 138 return handle; 139 } 140 141 void 142 ui_media_preview_update(UI_MEDIA_PREVIEW_Handle *handle, 143 struct GNUNET_CHAT_File *file) 144 { 145 g_assert(handle); 146 147 if (handle->file) 148 file_remove_widget_from_preview(handle->file, GTK_WIDGET(handle->preview_drawing_area)); 149 150 if (file) 151 { 152 file_load_preview_image(file); 153 file_add_widget_to_preview(file, GTK_WIDGET(handle->preview_drawing_area)); 154 } 155 156 handle->file = file; 157 } 158 159 void 160 ui_media_preview_delete(UI_MEDIA_PREVIEW_Handle *handle) 161 { 162 g_assert(handle); 163 164 ui_media_preview_update(handle, NULL); 165 166 g_object_unref(handle->builder); 167 168 g_free(handle); 169 }