commit 1049e99951c69db162f66eb6288450c2eacbbe15
parent 69e3d367f8e0d1168d5c6d6daebed1d2722b265c
Author: TheJackiMonster <thejackimonster@gmail.com>
Date: Mon, 10 Jan 2022 21:56:48 +0100
Added visual previews of files
Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>
Diffstat:
4 files changed, 242 insertions(+), 9 deletions(-)
diff --git a/resources/ui/message_content.ui b/resources/ui/message_content.ui
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2
-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
@@ -115,7 +115,7 @@ Author: Tobias Frisch
</packing>
</child>
<child>
- <object class="GtkProgressBar">
+ <object class="GtkProgressBar" id="file_progress_bar">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
@@ -141,7 +141,7 @@ Author: Tobias Frisch
<property name="valign">center</property>
<property name="relief">none</property>
<child>
- <object class="GtkImage">
+ <object class="GtkImage" id="file_status_image">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">folder-download-symbolic</property>
diff --git 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);
diff --git a/src/ui/message.h b/src/ui/message.h
@@ -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
@@ -63,8 +63,22 @@ typedef struct UI_MESSAGE_Handle
GtkStack *content_stack;
GtkLabel *text_label;
+
GtkRevealer *file_revealer;
+ GtkLabel *filename_label;
+ GtkProgressBar *file_progress_bar;
+ GtkButton *file_button;
+ GtkImage *file_status_image;
+
GtkDrawingArea *preview_drawing_area;
+
+ gulong preview_draw_signal;
+
+ GdkPixbuf *preview_image;
+ GdkPixbufAnimation *preview_animation;
+ GdkPixbufAnimationIter *preview_animation_iter;
+
+ guint redraw_animation;
} UI_MESSAGE_Handle;
UI_MESSAGE_Handle*
diff --git a/src/ui/send_file.c b/src/ui/send_file.c
@@ -85,17 +85,16 @@ handle_send_button_click(GtkButton *button,
UI_CHAT_ENTRY_Handle *entry = GNUNET_CHAT_context_get_user_pointer(context);
UI_CHAT_Handle *handle = entry? entry->chat : NULL;
+ UI_FILE_LOAD_ENTRY_Handle *file_load = NULL;
struct GNUNET_CHAT_File *file = NULL;
if ((context) && (handle))
{
- UI_FILE_LOAD_ENTRY_Handle *file_load = ui_file_load_entry_new(app);
+ file_load = ui_file_load_entry_new(app);
gtk_label_set_text(file_load->file_label, filename);
gtk_progress_bar_set_fraction(file_load->load_progress_bar, 0.0);
- ui_chat_add_file_load(handle, file_load);
-
file = GNUNET_CHAT_context_send_file(
context,
filename,
@@ -109,11 +108,16 @@ handle_send_button_click(GtkButton *button,
gtk_window_close(GTK_WINDOW(app->ui.send_file.dialog));
if (!file)
+ {
+ if (file_load)
+ ui_file_load_entry_delete(file_load);
+
return;
+ }
file_create_info(file);
- // TODO: create UI component?
+ ui_chat_add_file_load(handle, file_load);
}
static void