diff options
Diffstat (limited to 'src/ui/message.c')
-rw-r--r-- | src/ui/message.c | 217 |
1 files changed, 216 insertions, 1 deletions
diff --git a/src/ui/message.c b/src/ui/message.c index da6bb97..4aa7a85 100644 --- a/src/ui/message.c +++ b/src/ui/message.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2021 GNUnet e.V. + Copyright (C) 2021--2022 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -24,8 +24,143 @@ #include "message.h" +#include <gnunet/gnunet_chat_lib.h> + #include "../application.h" +static int +handle_message_redraw_animation(gpointer user_data) +{ + UI_MESSAGE_Handle *handle = (UI_MESSAGE_Handle*) user_data; + + handle->redraw_animation = 0; + + if ((handle->preview_drawing_area) && + ((handle->preview_image) || + (handle->preview_animation) || + (handle->preview_animation_iter))) + gtk_widget_queue_draw(GTK_WIDGET(handle->preview_drawing_area)); + + return FALSE; +} + +static gboolean +handle_preview_drawing_area_draw(GtkWidget* drawing_area, + cairo_t* cairo, + gpointer user_data) +{ + UI_MESSAGE_Handle *handle = (UI_MESSAGE_Handle*) user_data; + + GtkStyleContext* context = gtk_widget_get_style_context(drawing_area); + + const guint width = gtk_widget_get_allocated_width(drawing_area); + const guint height = gtk_widget_get_allocated_height(drawing_area); + + gtk_render_background(context, cairo, 0, 0, width, height); + + GdkPixbuf *image = handle->preview_image; + + if (!(handle->preview_animation)) + goto render_image; + + if (handle->preview_animation_iter) + gdk_pixbuf_animation_iter_advance(handle->preview_animation_iter, NULL); + else + handle->preview_animation_iter = gdk_pixbuf_animation_get_iter( + handle->preview_animation, NULL + ); + + image = gdk_pixbuf_animation_iter_get_pixbuf(handle->preview_animation_iter); + + const int delay = gdk_pixbuf_animation_iter_get_delay_time( + handle->preview_animation_iter + ); + + handle->redraw_animation = g_timeout_add( + delay, handle_message_redraw_animation, handle + ); + +render_image: + if (!image) + return FALSE; + + int dwidth = gdk_pixbuf_get_width(image); + int dheight = gdk_pixbuf_get_height(image); + + gint optimal_height = width * dheight / dwidth; + + gtk_widget_set_size_request( + GTK_WIDGET(drawing_area), + width, + optimal_height + ); + + double ratio_width = 1.0 * width / dwidth; + double ratio_height = 1.0 * height / dheight; + + const double ratio = ratio_width < ratio_height? ratio_width : ratio_height; + + dwidth = (int) (dwidth * ratio); + dheight = (int) (dheight * ratio); + + double dx = (width - dwidth) * 0.5; + double dy = (height - dheight) * 0.5; + + const int interp_type = (ratio >= 1.0? + GDK_INTERP_NEAREST : + GDK_INTERP_BILINEAR + ); + + GdkPixbuf* scaled = gdk_pixbuf_scale_simple( + image, + dwidth, + dheight, + interp_type + ); + + gtk_render_icon(context, cairo, scaled, dx, dy); + + cairo_fill(cairo); + + g_object_unref(scaled); + return FALSE; +} + +static void +_clear_message_preview_data(UI_MESSAGE_Handle *handle) +{ + if (handle->preview_image) + { + g_object_unref(handle->preview_image); + handle->preview_image = NULL; + } + + if (handle->redraw_animation) + { + g_source_remove(handle->redraw_animation); + handle->redraw_animation = 0; + } + + if (handle->preview_animation_iter) + { + g_object_unref(handle->preview_animation_iter); + handle->preview_animation_iter = NULL; + } + + if (handle->preview_animation) + { + g_object_unref(handle->preview_animation); + handle->preview_animation = NULL; + } + + if (handle->preview_drawing_area) + gtk_widget_set_size_request( + GTK_WIDGET(handle->preview_drawing_area), + -1, + -1 + ); +} + UI_MESSAGE_Handle* ui_message_new(MESSENGER_Application *app, UI_MESSAGE_Type type) @@ -120,10 +255,33 @@ ui_message_new(MESSENGER_Application *app, gtk_builder_get_object(builder, "file_revealer") ); + handle->filename_label = GTK_LABEL( + gtk_builder_get_object(builder, "filename_label") + ); + + handle->file_progress_bar = GTK_PROGRESS_BAR( + gtk_builder_get_object(builder, "file_progress_bar") + ); + + handle->file_button = GTK_BUTTON( + gtk_builder_get_object(builder, "file_button") + ); + + handle->file_status_image = GTK_IMAGE( + gtk_builder_get_object(builder, "file_status_image") + ); + handle->preview_drawing_area = GTK_DRAWING_AREA( gtk_builder_get_object(builder, "preview_drawing_area") ); + handle->preview_draw_signal = g_signal_connect( + handle->preview_drawing_area, + "draw", + G_CALLBACK(handle_preview_drawing_area_draw), + handle + ); + switch (handle->type) { case UI_MESSAGE_STATUS: @@ -138,6 +296,13 @@ ui_message_new(MESSENGER_Application *app, )); g_object_unref(builder); + + handle->preview_image = NULL; + handle->preview_animation = NULL; + handle->preview_animation_iter = NULL; + + handle->redraw_animation = 0; + return handle; } @@ -150,6 +315,49 @@ ui_message_update(UI_MESSAGE_Handle *handle, if (!file) return; + if (GNUNET_YES != GNUNET_CHAT_file_is_local(file)) + goto file_content; + + if (!(handle->preview_drawing_area)) + goto file_progress; + + const char *preview = GNUNET_CHAT_file_open_preview(file); + + if (!preview) + goto file_progress; + + handle->preview_animation = gdk_pixbuf_animation_new_from_file( + preview, NULL + ); + + if (!(handle->preview_animation)) + handle->preview_image = gdk_pixbuf_new_from_file(preview, NULL); + + if ((handle->preview_animation) || (handle->preview_animation)) + { + gtk_widget_set_size_request( + GTK_WIDGET(handle->preview_drawing_area), + 250, + -1 + ); + + gtk_stack_set_visible_child( + handle->content_stack, + GTK_WIDGET(handle->preview_drawing_area) + ); + + gtk_widget_queue_draw(GTK_WIDGET(handle->preview_drawing_area)); + return; + } + + GNUNET_CHAT_file_close_preview(file); + +file_progress: + gtk_progress_bar_set_fraction(handle->file_progress_bar, 1.0); + +file_content: + gtk_label_set_text(handle->filename_label, GNUNET_CHAT_file_get_name(file)); + gtk_stack_set_visible_child( handle->content_stack, GTK_WIDGET(handle->file_revealer) @@ -161,6 +369,13 @@ ui_message_update(UI_MESSAGE_Handle *handle, void ui_message_delete(UI_MESSAGE_Handle *handle) { + _clear_message_preview_data(handle); + + g_signal_handler_disconnect( + handle->preview_drawing_area, + handle->preview_draw_signal + ); + g_object_unref(handle->builder); g_free(handle); |