messenger-gtk

Gtk+3 graphical user interfaces for GNUnet Messenger
Log | Files | Refs | Submodules | README | LICENSE

commit bd545ea846e668112e5a54b702acc9c9f9231aea
parent d8a0d99da00d29ae50a0a8831d1d396769ed94f6
Author: TheJackiMonster <thejackimonster@gmail.com>
Date:   Tue, 21 Dec 2021 18:59:39 +0100

Implemented preview for sending files and added ui for message content

Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>

Diffstat:
Mresources/css/style.css | 4++++
Mresources/ui/message-sent.ui | 59++---------------------------------------------------------
Mresources/ui/message-status.ui | 106++++++++++++++++++++++++++-----------------------------------------------------
Mresources/ui/message.ui | 58++--------------------------------------------------------
Aresources/ui/message_content.ui | 187+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mresources/ui/send_file.ui | 1+
Msrc/event.c | 19+++++++++++++------
Msrc/ui/chat.c | 15+++++++++++++++
Msrc/ui/chat.h | 2++
Msrc/ui/message.c | 65++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Msrc/ui/message.h | 17+++++++++++++++--
Msrc/ui/new_contact.c | 2+-
Msrc/ui/send_file.c | 176+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/ui/send_file.h | 6++++++
14 files changed, 512 insertions(+), 205 deletions(-)

diff --git a/resources/css/style.css b/resources/css/style.css @@ -61,6 +61,10 @@ padding: 2px 4px; } +.timestamp-label { + font-size: x-small; +} + .picker-switcher-box { padding: 0px 8px; } diff --git a/resources/ui/message-sent.ui b/resources/ui/message-sent.ui @@ -50,68 +50,13 @@ Author: Tobias Frisch <property name="label-xalign">0</property> <property name="shadow-type">none</property> <child> - <object class="GtkBox"> + <object class="GtkBox" id="content_box"> <property name="visible">True</property> <property name="can-focus">False</property> <property name="orientation">vertical</property> - <property name="spacing">4</property> <child> - <object class="GtkLabel" id="text_label"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="wrap">True</property> - <property name="max-width-chars">64</property> - <property name="xalign">0</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> + <placeholder/> </child> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="spacing">4</property> - <child> - <object class="GtkImage" id="read_receipt_image"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="icon-name">emblem-default-symbolic</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="pack-type">end</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="timestamp_label"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <attributes> - <attribute name="weight" value="light"/> - </attributes> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="pack-type">end</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - <style> - <class name="message-content"/> - </style> </object> </child> <child type="label"> diff --git a/resources/ui/message-status.ui b/resources/ui/message-status.ui @@ -39,15 +39,23 @@ Author: Tobias Frisch <property name="can-focus">False</property> <property name="spacing">8</property> <child> - <object class="GtkButton" id="deny_button"> - <property name="can-focus">True</property> - <property name="receives-default">True</property> - <property name="relief">none</property> + <object class="GtkRevealer" id="deny_revealer"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="transition-type">slide-left</property> + <property name="reveal-child">True</property> <child> - <object class="GtkImage"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="icon-name">edit-delete-symbolic</property> + <object class="GtkButton" id="deny_button"> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="relief">none</property> + <child> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="icon-name">edit-delete-symbolic</property> + </object> + </child> </object> </child> </object> @@ -58,65 +66,12 @@ Author: Tobias Frisch </packing> </child> <child> - <object class="GtkBox"> + <object class="GtkBox" id="content_box"> <property name="visible">True</property> <property name="can-focus">False</property> <property name="orientation">vertical</property> <child> - <object class="GtkLabel" id="text_label"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="justify">center</property> - <property name="wrap">True</property> - <property name="xalign">0.5</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="spacing">4</property> - <child> - <object class="GtkImage" id="read_receipt_image"> - <property name="can-focus">False</property> - <property name="xalign">1</property> - <property name="icon-name">emblem-default-symbolic</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="pack-type">end</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="timestamp_label"> - <property name="can-focus">False</property> - <property name="justify">right</property> - <property name="xalign">1</property> - <attributes> - <attribute name="weight" value="light"/> - </attributes> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="pack-type">end</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="pack-type">end</property> - <property name="position">1</property> - </packing> + <placeholder/> </child> </object> <packing> @@ -126,22 +81,29 @@ Author: Tobias Frisch </packing> </child> <child> - <object class="GtkButton" id="accept_button"> - <property name="can-focus">True</property> - <property name="receives-default">True</property> - <property name="relief">none</property> + <object class="GtkRevealer" id="accept_revealer"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="transition-type">slide-right</property> + <property name="reveal-child">True</property> <child> - <object class="GtkImage"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="icon-name">emblem-ok-symbolic</property> + <object class="GtkButton" id="accept_button"> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="relief">none</property> + <child> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="icon-name">emblem-ok-symbolic</property> + </object> + </child> </object> </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> - <property name="pack-type">end</property> <property name="position">2</property> </packing> </child> diff --git a/resources/ui/message.ui b/resources/ui/message.ui @@ -49,67 +49,13 @@ Author: Tobias Frisch <property name="label-xalign">0</property> <property name="shadow-type">none</property> <child> - <object class="GtkBox"> + <object class="GtkBox" id="content_box"> <property name="visible">True</property> <property name="can-focus">False</property> <property name="orientation">vertical</property> - <property name="spacing">4</property> <child> - <object class="GtkLabel" id="text_label"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="wrap">True</property> - <property name="max-width-chars">64</property> - <property name="xalign">0</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> + <placeholder/> </child> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="spacing">4</property> - <child> - <object class="GtkImage" id="read_receipt_image"> - <property name="can-focus">False</property> - <property name="icon-name">emblem-default-symbolic</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="pack-type">end</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="timestamp_label"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <attributes> - <attribute name="weight" value="light"/> - </attributes> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="pack-type">end</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - <style> - <class name="message-content"/> - </style> </object> </child> <child type="label"> diff --git a/resources/ui/message_content.ui b/resources/ui/message_content.ui @@ -0,0 +1,187 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.38.2 + +Copyright (C) 2021 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 +by the Free Software Foundation, either version 3 of the License, +or (at your option) any later version. + +GNUnet is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +SPDX-License-Identifier: AGPL3.0-or-later +Author: Tobias Frisch + +--> +<interface> + <requires lib="gtk+" version="3.24"/> + <object class="GtkBox" id="message_content_box"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">4</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="spacing">4</property> + <child> + <object class="GtkImage" id="read_receipt_image"> + <property name="can-focus">False</property> + <property name="icon-name">emblem-default-symbolic</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack-type">end</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="timestamp_label"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <attributes> + <attribute name="weight" value="ultralight"/> + </attributes> + <style> + <class name="timestamp-label"/> + </style> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack-type">end</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack-type">end</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkStack"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <child> + <object class="GtkLabel" id="text_label"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="wrap">True</property> + <property name="max-width-chars">64</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="name">text_page</property> + </packing> + </child> + <child> + <object class="GtkRevealer" id="file_revealer"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="transition-type">none</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="spacing">4</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="valign">center</property> + <property name="orientation">vertical</property> + <property name="spacing">4</property> + <child> + <object class="GtkLabel" id="filename_label"> + <property name="visible">True</property> + <property name="can-focus">False</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkProgressBar"> + <property name="visible">True</property> + <property name="can-focus">False</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="file_button"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="halign">center</property> + <property name="valign">center</property> + <property name="relief">none</property> + <child> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="icon-name">folder-download-symbolic</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack-type">end</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> + <packing> + <property name="name">file_page</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkDrawingArea" id="preview_drawing_area"> + <property name="visible">True</property> + <property name="can-focus">False</property> + </object> + <packing> + <property name="name">preview_page</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <style> + <class name="message-content"/> + </style> + </object> +</interface> diff --git a/resources/ui/send_file.ui b/resources/ui/send_file.ui @@ -78,6 +78,7 @@ Author: Tobias Frisch <property name="spacing">4</property> <child> <object class="GtkDrawingArea" id="file_drawing_area"> + <property name="width-request">250</property> <property name="height-request">250</property> <property name="visible">True</property> <property name="can-focus">False</property> diff --git a/src/event.c b/src/event.c @@ -190,7 +190,10 @@ event_joining_contact(MESSENGER_Application *app, ui_chat_entry_update(handle, app, context); - UI_MESSAGE_Handle *message = ui_message_new(UI_MESSAGE_STATUS); + UI_MESSAGE_Handle *message = ui_message_new( + UI_MESSAGE_STATUS, + UI_MESSAGE_CONTENT_TEXT + ); struct GNUNET_CHAT_Contact *contact = GNUNET_CHAT_message_get_sender( msg @@ -209,7 +212,7 @@ event_joining_contact(MESSENGER_Application *app, message->message_box ); - ui_message_delete(message); + handle->chat->messages = g_list_append(handle->chat->messages, message); } void @@ -259,7 +262,10 @@ event_invitation(UNUSED MESSENGER_Application *app, if (!invitation) return; - UI_MESSAGE_Handle *message = ui_message_new(UI_MESSAGE_STATUS); + UI_MESSAGE_Handle *message = ui_message_new( + UI_MESSAGE_STATUS, + UI_MESSAGE_CONTENT_TEXT + ); const struct GNUNET_CHAT_Contact *contact = GNUNET_CHAT_message_get_sender( msg @@ -285,7 +291,7 @@ event_invitation(UNUSED MESSENGER_Application *app, message->message_box ); - ui_message_delete(message); + handle->chat->messages = g_list_append(handle->chat->messages, message); } void @@ -301,7 +307,8 @@ event_receive_message(UNUSED MESSENGER_Application *app, const int sent = GNUNET_CHAT_message_is_sent(msg); UI_MESSAGE_Handle *message = ui_message_new( - GNUNET_YES == sent? UI_MESSAGE_SENT : UI_MESSAGE_DEFAULT + GNUNET_YES == sent? UI_MESSAGE_SENT : UI_MESSAGE_DEFAULT, + UI_MESSAGE_CONTENT_TEXT ); const struct GNUNET_CHAT_Contact *contact = GNUNET_CHAT_message_get_sender( @@ -329,7 +336,7 @@ event_receive_message(UNUSED MESSENGER_Application *app, message->message_box ); - ui_message_delete(message); + handle->chat->messages = g_list_append(handle->chat->messages, message); gtk_label_set_text(handle->text_label, text? text : ""); gtk_label_set_text(handle->timestamp_label, time? time : ""); diff --git a/src/ui/chat.c b/src/ui/chat.c @@ -26,6 +26,7 @@ #include <gdk/gdkkeysyms.h> +#include "message.h" #include "messenger.h" #include "picker.h" #include "profile_entry.h" @@ -252,6 +253,8 @@ ui_chat_new(MESSENGER_Application *app) UI_CHAT_Handle *handle = g_malloc(sizeof(UI_CHAT_Handle)); UI_MESSENGER_Handle *messenger = &(app->ui.messenger); + handle->messages = NULL; + handle->builder = gtk_builder_new_from_file( "resources/ui/chat.ui" ); @@ -552,5 +555,17 @@ ui_chat_delete(UI_CHAT_Handle *handle) g_object_unref(handle->builder); + GList *list = handle->messages; + + while (list) { + if (list->data) + ui_message_delete((UI_MESSAGE_Handle*) list->data); + + list = list->next; + } + + if (handle->messages) + g_list_free(handle->messages); + g_free(handle); } diff --git a/src/ui/chat.h b/src/ui/chat.h @@ -36,6 +36,8 @@ typedef struct UI_PICKER_Handle UI_PICKER_Handle; typedef struct UI_CHAT_Handle { + GList *messages; + GtkBuilder *builder; GtkWidget *chat_box; diff --git a/src/ui/message.c b/src/ui/message.c @@ -27,7 +27,8 @@ #include "../application.h" UI_MESSAGE_Handle* -ui_message_new(UI_MESSAGE_Type type) +ui_message_new(UI_MESSAGE_Type type, + UI_MESSAGE_ContentType content_type) { UI_MESSAGE_Handle* handle = g_malloc(sizeof(UI_MESSAGE_Handle)); @@ -62,12 +63,16 @@ ui_message_new(UI_MESSAGE_Type type) gtk_builder_get_object(handle->builder, "sender_label") ); - handle->text_label = GTK_LABEL( - gtk_builder_get_object(handle->builder, "text_label") - ); - if (UI_MESSAGE_STATUS == handle->type) { + handle->deny_revealer = GTK_REVEALER( + gtk_builder_get_object(handle->builder, "deny_revealer") + ); + + handle->accept_revealer = GTK_REVEALER( + gtk_builder_get_object(handle->builder, "accept_revealer") + ); + handle->deny_button = GTK_BUTTON( gtk_builder_get_object(handle->builder, "deny_button") ); @@ -78,18 +83,64 @@ ui_message_new(UI_MESSAGE_Type type) } else { + handle->deny_revealer = NULL; + handle->accept_revealer = NULL; + handle->deny_button = NULL; handle->accept_button = NULL; } + GtkContainer *content_box = GTK_CONTAINER( + gtk_builder_get_object(handle->builder, "content_box") + ); + + GtkBuilder *builder = gtk_builder_new_from_file( + "resources/ui/message_content.ui" + ); + handle->timestamp_label = GTK_LABEL( - gtk_builder_get_object(handle->builder, "timestamp_label") + gtk_builder_get_object(builder, "timestamp_label") ); handle->read_receipt_image = GTK_IMAGE( - gtk_builder_get_object(handle->builder, "read_receipt_image") + gtk_builder_get_object(builder, "read_receipt_image") + ); + + handle->text_label = GTK_LABEL( + gtk_builder_get_object(builder, "text_label") + ); + + handle->file_revealer = GTK_REVEALER( + gtk_builder_get_object(builder, "file_revealer") ); + handle->preview_drawing_area = GTK_DRAWING_AREA( + gtk_builder_get_object(builder, "preview_drawing_area") + ); + + switch (handle->type) + { + case UI_MESSAGE_STATUS: + gtk_widget_set_visible(GTK_WIDGET(handle->timestamp_label), FALSE); + break; + default: + break; + } + + switch (content_type) + { + case UI_MESSAGE_CONTENT_FILE: + gtk_revealer_set_reveal_child(handle->file_revealer, TRUE); + break; + default: + break; + } + + gtk_container_add(content_box, GTK_WIDGET( + gtk_builder_get_object(builder, "message_content_box") + )); + + g_object_unref(builder); return handle; } diff --git a/src/ui/message.h b/src/ui/message.h @@ -39,6 +39,13 @@ typedef enum UI_MESSAGE_Type UI_MESSAGE_STATUS = 2 } UI_MESSAGE_Type; +typedef enum UI_MESSAGE_ContentType +{ + UI_MESSAGE_CONTENT_TEXT = 0, + UI_MESSAGE_CONTENT_FILE = 1, + UI_MESSAGE_CONTENT_PREVIEW = 2 +} UI_MESSAGE_ContentType; + typedef struct UI_MESSAGE_Handle { UI_MESSAGE_Type type; @@ -49,17 +56,23 @@ typedef struct UI_MESSAGE_Handle HdyAvatar *sender_avatar; GtkLabel *sender_label; - GtkLabel *text_label; + GtkRevealer *deny_revealer; + GtkRevealer *accept_revealer; GtkButton *deny_button; GtkButton *accept_button; GtkLabel *timestamp_label; GtkImage *read_receipt_image; + + GtkLabel *text_label; + GtkRevealer *file_revealer; + GtkDrawingArea *preview_drawing_area; } UI_MESSAGE_Handle; UI_MESSAGE_Handle* -ui_message_new(UI_MESSAGE_Type type); +ui_message_new(UI_MESSAGE_Type type, + UI_MESSAGE_ContentType content_type); void ui_message_delete(UI_MESSAGE_Handle *handle); diff --git a/src/ui/new_contact.c b/src/ui/new_contact.c @@ -69,7 +69,7 @@ handle_id_drawing_area_draw(GtkWidget* drawing_area, GdkPixbuf *image = NULL; if (!handle->image) - goto render_image; + return FALSE; uint w, h; zbar_image_get_size(handle->image, &w, &h); diff --git a/src/ui/send_file.c b/src/ui/send_file.c @@ -71,6 +71,146 @@ handle_dialog_destroy(UNUSED GtkWidget *window, ui_send_file_dialog_cleanup((UI_SEND_FILE_Handle*) user_data); } +static int +handle_file_redraw_animation(gpointer user_data) +{ + UI_SEND_FILE_Handle *handle = (UI_SEND_FILE_Handle*) user_data; + + handle->redraw_animation = 0; + + if (handle->file_drawing_area) + gtk_widget_queue_draw(GTK_WIDGET(handle->file_drawing_area)); + + return FALSE; +} + +static gboolean +handle_file_drawing_area_draw(GtkWidget* drawing_area, + cairo_t* cairo, + gpointer user_data) +{ + UI_SEND_FILE_Handle *handle = (UI_SEND_FILE_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->image; + + if (!handle->animation) + goto render_image; + + if (handle->animation_iter) + gdk_pixbuf_animation_iter_advance(handle->animation_iter, NULL); + else + handle->animation_iter = gdk_pixbuf_animation_get_iter( + handle->animation, NULL + ); + + image = gdk_pixbuf_animation_iter_get_pixbuf(handle->animation_iter); + + const int delay = gdk_pixbuf_animation_iter_get_delay_time( + handle->animation_iter + ); + + handle->redraw_animation = g_timeout_add( + delay, handle_file_redraw_animation, handle + ); + +render_image: + if (!image) + return FALSE; + + int dwidth = gdk_pixbuf_get_width(image); + int dheight = gdk_pixbuf_get_height(image); + + 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_file_preview_data(UI_SEND_FILE_Handle *handle) +{ + if (handle->image) + { + g_object_unref(handle->image); + handle->image = NULL; + } + + if (handle->redraw_animation) + { + g_source_remove(handle->redraw_animation); + handle->redraw_animation = 0; + } + + if (handle->animation_iter) + { + g_object_unref(handle->animation_iter); + handle->animation_iter = NULL; + } + + if (handle->animation) + { + g_object_unref(handle->animation); + handle->animation = NULL; + } +} + +static void +handle_file_chooser_button_file_set(GtkFileChooserButton *file_chooser_button, + gpointer user_data) +{ + UI_SEND_FILE_Handle *handle = (UI_SEND_FILE_Handle*) user_data; + + _clear_file_preview_data(handle); + + char *filename = gtk_file_chooser_get_filename( + GTK_FILE_CHOOSER(file_chooser_button) + ); + + if (filename) + { + handle->animation = gdk_pixbuf_animation_new_from_file(filename, NULL); + + if (!handle->animation) + handle->image = gdk_pixbuf_new_from_file(filename, NULL); + + g_free(filename); + } + + gtk_widget_queue_draw(GTK_WIDGET(handle->file_drawing_area)); +} + void ui_send_file_dialog_init(MESSENGER_Application *app, UI_SEND_FILE_Handle *handle) @@ -99,6 +239,20 @@ ui_send_file_dialog_init(MESSENGER_Application *app, gtk_builder_get_object(handle->builder, "file_chooser_button") ); + g_signal_connect( + handle->file_drawing_area, + "draw", + G_CALLBACK(handle_file_drawing_area_draw), + handle + ); + + g_signal_connect( + handle->file_chooser_button, + "file-set", + G_CALLBACK(handle_file_chooser_button_file_set), + handle + ); + handle->cancel_button = GTK_BUTTON( gtk_builder_get_object(handle->builder, "cancel_button") ); @@ -127,22 +281,36 @@ ui_send_file_dialog_init(MESSENGER_Application *app, G_CALLBACK(handle_dialog_destroy), handle ); + + handle->image = NULL; + handle->animation = NULL; + handle->animation_iter = NULL; + + handle->redraw_animation = 0; } void ui_send_file_dialog_update(UI_SEND_FILE_Handle *handle, const gchar *filename) { - if ((!filename) || (!gtk_file_chooser_set_filename( - GTK_FILE_CHOOSER(handle->file_chooser_button), - filename))) + if (!handle->file_chooser_button) return; - // TODO: update preview + gtk_file_chooser_set_filename( + GTK_FILE_CHOOSER(handle->file_chooser_button), + filename + ); + + handle_file_chooser_button_file_set( + handle->file_chooser_button, + handle + ); } void ui_send_file_dialog_cleanup(UI_SEND_FILE_Handle *handle) { + _clear_file_preview_data(handle); + g_object_unref(handle->builder); } diff --git a/src/ui/send_file.h b/src/ui/send_file.h @@ -39,6 +39,12 @@ typedef struct UI_SEND_FILE_Handle GtkButton *cancel_button; GtkButton *send_button; + + GdkPixbuf *image; + GdkPixbufAnimation *animation; + GdkPixbufAnimationIter *animation_iter; + + guint redraw_animation; } UI_SEND_FILE_Handle; void