diff options
author | TheJackiMonster <thejackimonster@gmail.com> | 2022-01-10 21:56:48 +0100 |
---|---|---|
committer | TheJackiMonster <thejackimonster@gmail.com> | 2022-01-10 21:56:48 +0100 |
commit | 1049e99951c69db162f66eb6288450c2eacbbe15 (patch) | |
tree | 0e148d2f179a0889cc83385ee60a4eaac595cccd | |
parent | 69e3d367f8e0d1168d5c6d6daebed1d2722b265c (diff) | |
download | messenger-gtk-1049e99951c69db162f66eb6288450c2eacbbe15.tar.gz messenger-gtk-1049e99951c69db162f66eb6288450c2eacbbe15.zip |
Added visual previews of files
Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>
-rw-r--r-- | resources/ui/message_content.ui | 6 | ||||
-rw-r--r-- | src/ui/message.c | 217 | ||||
-rw-r--r-- | src/ui/message.h | 16 | ||||
-rw-r--r-- | src/ui/send_file.c | 12 |
4 files changed, 242 insertions, 9 deletions
diff --git a/resources/ui/message_content.ui b/resources/ui/message_content.ui index a59c59e..9c2bd22 100644 --- a/resources/ui/message_content.ui +++ b/resources/ui/message_content.ui | |||
@@ -1,7 +1,7 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8"?> | 1 | <?xml version="1.0" encoding="UTF-8"?> |
2 | <!-- Generated with glade 3.38.2 | 2 | <!-- Generated with glade 3.38.2 |
3 | 3 | ||
4 | Copyright (C) 2021 GNUnet e.V. | 4 | Copyright (C) 2021‑‑2022 GNUnet e.V. |
5 | 5 | ||
6 | GNUnet is free software: you can redistribute it and/or modify it | 6 | GNUnet is free software: you can redistribute it and/or modify it |
7 | under the terms of the GNU Affero General Public License as published | 7 | under the terms of the GNU Affero General Public License as published |
@@ -115,7 +115,7 @@ Author: Tobias Frisch | |||
115 | </packing> | 115 | </packing> |
116 | </child> | 116 | </child> |
117 | <child> | 117 | <child> |
118 | <object class="GtkProgressBar"> | 118 | <object class="GtkProgressBar" id="file_progress_bar"> |
119 | <property name="visible">True</property> | 119 | <property name="visible">True</property> |
120 | <property name="can-focus">False</property> | 120 | <property name="can-focus">False</property> |
121 | </object> | 121 | </object> |
@@ -141,7 +141,7 @@ Author: Tobias Frisch | |||
141 | <property name="valign">center</property> | 141 | <property name="valign">center</property> |
142 | <property name="relief">none</property> | 142 | <property name="relief">none</property> |
143 | <child> | 143 | <child> |
144 | <object class="GtkImage"> | 144 | <object class="GtkImage" id="file_status_image"> |
145 | <property name="visible">True</property> | 145 | <property name="visible">True</property> |
146 | <property name="can-focus">False</property> | 146 | <property name="can-focus">False</property> |
147 | <property name="icon-name">folder-download-symbolic</property> | 147 | <property name="icon-name">folder-download-symbolic</property> |
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 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | Copyright (C) 2021 GNUnet e.V. | 3 | Copyright (C) 2021--2022 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software: you can redistribute it and/or modify it | 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 | 6 | under the terms of the GNU Affero General Public License as published |
@@ -24,8 +24,143 @@ | |||
24 | 24 | ||
25 | #include "message.h" | 25 | #include "message.h" |
26 | 26 | ||
27 | #include <gnunet/gnunet_chat_lib.h> | ||
28 | |||
27 | #include "../application.h" | 29 | #include "../application.h" |
28 | 30 | ||
31 | static int | ||
32 | handle_message_redraw_animation(gpointer user_data) | ||
33 | { | ||
34 | UI_MESSAGE_Handle *handle = (UI_MESSAGE_Handle*) user_data; | ||
35 | |||
36 | handle->redraw_animation = 0; | ||
37 | |||
38 | if ((handle->preview_drawing_area) && | ||
39 | ((handle->preview_image) || | ||
40 | (handle->preview_animation) || | ||
41 | (handle->preview_animation_iter))) | ||
42 | gtk_widget_queue_draw(GTK_WIDGET(handle->preview_drawing_area)); | ||
43 | |||
44 | return FALSE; | ||
45 | } | ||
46 | |||
47 | static gboolean | ||
48 | handle_preview_drawing_area_draw(GtkWidget* drawing_area, | ||
49 | cairo_t* cairo, | ||
50 | gpointer user_data) | ||
51 | { | ||
52 | UI_MESSAGE_Handle *handle = (UI_MESSAGE_Handle*) user_data; | ||
53 | |||
54 | GtkStyleContext* context = gtk_widget_get_style_context(drawing_area); | ||
55 | |||
56 | const guint width = gtk_widget_get_allocated_width(drawing_area); | ||
57 | const guint height = gtk_widget_get_allocated_height(drawing_area); | ||
58 | |||
59 | gtk_render_background(context, cairo, 0, 0, width, height); | ||
60 | |||
61 | GdkPixbuf *image = handle->preview_image; | ||
62 | |||
63 | if (!(handle->preview_animation)) | ||
64 | goto render_image; | ||
65 | |||
66 | if (handle->preview_animation_iter) | ||
67 | gdk_pixbuf_animation_iter_advance(handle->preview_animation_iter, NULL); | ||
68 | else | ||
69 | handle->preview_animation_iter = gdk_pixbuf_animation_get_iter( | ||
70 | handle->preview_animation, NULL | ||
71 | ); | ||
72 | |||
73 | image = gdk_pixbuf_animation_iter_get_pixbuf(handle->preview_animation_iter); | ||
74 | |||
75 | const int delay = gdk_pixbuf_animation_iter_get_delay_time( | ||
76 | handle->preview_animation_iter | ||
77 | ); | ||
78 | |||
79 | handle->redraw_animation = g_timeout_add( | ||
80 | delay, handle_message_redraw_animation, handle | ||
81 | ); | ||
82 | |||
83 | render_image: | ||
84 | if (!image) | ||
85 | return FALSE; | ||
86 | |||
87 | int dwidth = gdk_pixbuf_get_width(image); | ||
88 | int dheight = gdk_pixbuf_get_height(image); | ||
89 | |||
90 | gint optimal_height = width * dheight / dwidth; | ||
91 | |||
92 | gtk_widget_set_size_request( | ||
93 | GTK_WIDGET(drawing_area), | ||
94 | width, | ||
95 | optimal_height | ||
96 | ); | ||
97 | |||
98 | double ratio_width = 1.0 * width / dwidth; | ||
99 | double ratio_height = 1.0 * height / dheight; | ||
100 | |||
101 | const double ratio = ratio_width < ratio_height? ratio_width : ratio_height; | ||
102 | |||
103 | dwidth = (int) (dwidth * ratio); | ||
104 | dheight = (int) (dheight * ratio); | ||
105 | |||
106 | double dx = (width - dwidth) * 0.5; | ||
107 | double dy = (height - dheight) * 0.5; | ||
108 | |||
109 | const int interp_type = (ratio >= 1.0? | ||
110 | GDK_INTERP_NEAREST : | ||
111 | GDK_INTERP_BILINEAR | ||
112 | ); | ||
113 | |||
114 | GdkPixbuf* scaled = gdk_pixbuf_scale_simple( | ||
115 | image, | ||
116 | dwidth, | ||
117 | dheight, | ||
118 | interp_type | ||
119 | ); | ||
120 | |||
121 | gtk_render_icon(context, cairo, scaled, dx, dy); | ||
122 | |||
123 | cairo_fill(cairo); | ||
124 | |||
125 | g_object_unref(scaled); | ||
126 | return FALSE; | ||
127 | } | ||
128 | |||
129 | static void | ||
130 | _clear_message_preview_data(UI_MESSAGE_Handle *handle) | ||
131 | { | ||
132 | if (handle->preview_image) | ||
133 | { | ||
134 | g_object_unref(handle->preview_image); | ||
135 | handle->preview_image = NULL; | ||
136 | } | ||
137 | |||
138 | if (handle->redraw_animation) | ||
139 | { | ||
140 | g_source_remove(handle->redraw_animation); | ||
141 | handle->redraw_animation = 0; | ||
142 | } | ||
143 | |||
144 | if (handle->preview_animation_iter) | ||
145 | { | ||
146 | g_object_unref(handle->preview_animation_iter); | ||
147 | handle->preview_animation_iter = NULL; | ||
148 | } | ||
149 | |||
150 | if (handle->preview_animation) | ||
151 | { | ||
152 | g_object_unref(handle->preview_animation); | ||
153 | handle->preview_animation = NULL; | ||
154 | } | ||
155 | |||
156 | if (handle->preview_drawing_area) | ||
157 | gtk_widget_set_size_request( | ||
158 | GTK_WIDGET(handle->preview_drawing_area), | ||
159 | -1, | ||
160 | -1 | ||
161 | ); | ||
162 | } | ||
163 | |||
29 | UI_MESSAGE_Handle* | 164 | UI_MESSAGE_Handle* |
30 | ui_message_new(MESSENGER_Application *app, | 165 | ui_message_new(MESSENGER_Application *app, |
31 | UI_MESSAGE_Type type) | 166 | UI_MESSAGE_Type type) |
@@ -120,10 +255,33 @@ ui_message_new(MESSENGER_Application *app, | |||
120 | gtk_builder_get_object(builder, "file_revealer") | 255 | gtk_builder_get_object(builder, "file_revealer") |
121 | ); | 256 | ); |
122 | 257 | ||
258 | handle->filename_label = GTK_LABEL( | ||
259 | gtk_builder_get_object(builder, "filename_label") | ||
260 | ); | ||
261 | |||
262 | handle->file_progress_bar = GTK_PROGRESS_BAR( | ||
263 | gtk_builder_get_object(builder, "file_progress_bar") | ||
264 | ); | ||
265 | |||
266 | handle->file_button = GTK_BUTTON( | ||
267 | gtk_builder_get_object(builder, "file_button") | ||
268 | ); | ||
269 | |||
270 | handle->file_status_image = GTK_IMAGE( | ||
271 | gtk_builder_get_object(builder, "file_status_image") | ||
272 | ); | ||
273 | |||
123 | handle->preview_drawing_area = GTK_DRAWING_AREA( | 274 | handle->preview_drawing_area = GTK_DRAWING_AREA( |
124 | gtk_builder_get_object(builder, "preview_drawing_area") | 275 | gtk_builder_get_object(builder, "preview_drawing_area") |
125 | ); | 276 | ); |
126 | 277 | ||
278 | handle->preview_draw_signal = g_signal_connect( | ||
279 | handle->preview_drawing_area, | ||
280 | "draw", | ||
281 | G_CALLBACK(handle_preview_drawing_area_draw), | ||
282 | handle | ||
283 | ); | ||
284 | |||
127 | switch (handle->type) | 285 | switch (handle->type) |
128 | { | 286 | { |
129 | case UI_MESSAGE_STATUS: | 287 | case UI_MESSAGE_STATUS: |
@@ -138,6 +296,13 @@ ui_message_new(MESSENGER_Application *app, | |||
138 | )); | 296 | )); |
139 | 297 | ||
140 | g_object_unref(builder); | 298 | g_object_unref(builder); |
299 | |||
300 | handle->preview_image = NULL; | ||
301 | handle->preview_animation = NULL; | ||
302 | handle->preview_animation_iter = NULL; | ||
303 | |||
304 | handle->redraw_animation = 0; | ||
305 | |||
141 | return handle; | 306 | return handle; |
142 | } | 307 | } |
143 | 308 | ||
@@ -150,6 +315,49 @@ ui_message_update(UI_MESSAGE_Handle *handle, | |||
150 | if (!file) | 315 | if (!file) |
151 | return; | 316 | return; |
152 | 317 | ||
318 | if (GNUNET_YES != GNUNET_CHAT_file_is_local(file)) | ||
319 | goto file_content; | ||
320 | |||
321 | if (!(handle->preview_drawing_area)) | ||
322 | goto file_progress; | ||
323 | |||
324 | const char *preview = GNUNET_CHAT_file_open_preview(file); | ||
325 | |||
326 | if (!preview) | ||
327 | goto file_progress; | ||
328 | |||
329 | handle->preview_animation = gdk_pixbuf_animation_new_from_file( | ||
330 | preview, NULL | ||
331 | ); | ||
332 | |||
333 | if (!(handle->preview_animation)) | ||
334 | handle->preview_image = gdk_pixbuf_new_from_file(preview, NULL); | ||
335 | |||
336 | if ((handle->preview_animation) || (handle->preview_animation)) | ||
337 | { | ||
338 | gtk_widget_set_size_request( | ||
339 | GTK_WIDGET(handle->preview_drawing_area), | ||
340 | 250, | ||
341 | -1 | ||
342 | ); | ||
343 | |||
344 | gtk_stack_set_visible_child( | ||
345 | handle->content_stack, | ||
346 | GTK_WIDGET(handle->preview_drawing_area) | ||
347 | ); | ||
348 | |||
349 | gtk_widget_queue_draw(GTK_WIDGET(handle->preview_drawing_area)); | ||
350 | return; | ||
351 | } | ||
352 | |||
353 | GNUNET_CHAT_file_close_preview(file); | ||
354 | |||
355 | file_progress: | ||
356 | gtk_progress_bar_set_fraction(handle->file_progress_bar, 1.0); | ||
357 | |||
358 | file_content: | ||
359 | gtk_label_set_text(handle->filename_label, GNUNET_CHAT_file_get_name(file)); | ||
360 | |||
153 | gtk_stack_set_visible_child( | 361 | gtk_stack_set_visible_child( |
154 | handle->content_stack, | 362 | handle->content_stack, |
155 | GTK_WIDGET(handle->file_revealer) | 363 | GTK_WIDGET(handle->file_revealer) |
@@ -161,6 +369,13 @@ ui_message_update(UI_MESSAGE_Handle *handle, | |||
161 | void | 369 | void |
162 | ui_message_delete(UI_MESSAGE_Handle *handle) | 370 | ui_message_delete(UI_MESSAGE_Handle *handle) |
163 | { | 371 | { |
372 | _clear_message_preview_data(handle); | ||
373 | |||
374 | g_signal_handler_disconnect( | ||
375 | handle->preview_drawing_area, | ||
376 | handle->preview_draw_signal | ||
377 | ); | ||
378 | |||
164 | g_object_unref(handle->builder); | 379 | g_object_unref(handle->builder); |
165 | 380 | ||
166 | g_free(handle); | 381 | g_free(handle); |
diff --git a/src/ui/message.h b/src/ui/message.h index f5883de..0463732 100644 --- a/src/ui/message.h +++ b/src/ui/message.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | Copyright (C) 2021 GNUnet e.V. | 3 | Copyright (C) 2021--2022 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software: you can redistribute it and/or modify it | 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 | 6 | under the terms of the GNU Affero General Public License as published |
@@ -63,8 +63,22 @@ typedef struct UI_MESSAGE_Handle | |||
63 | GtkStack *content_stack; | 63 | GtkStack *content_stack; |
64 | 64 | ||
65 | GtkLabel *text_label; | 65 | GtkLabel *text_label; |
66 | |||
66 | GtkRevealer *file_revealer; | 67 | GtkRevealer *file_revealer; |
68 | GtkLabel *filename_label; | ||
69 | GtkProgressBar *file_progress_bar; | ||
70 | GtkButton *file_button; | ||
71 | GtkImage *file_status_image; | ||
72 | |||
67 | GtkDrawingArea *preview_drawing_area; | 73 | GtkDrawingArea *preview_drawing_area; |
74 | |||
75 | gulong preview_draw_signal; | ||
76 | |||
77 | GdkPixbuf *preview_image; | ||
78 | GdkPixbufAnimation *preview_animation; | ||
79 | GdkPixbufAnimationIter *preview_animation_iter; | ||
80 | |||
81 | guint redraw_animation; | ||
68 | } UI_MESSAGE_Handle; | 82 | } UI_MESSAGE_Handle; |
69 | 83 | ||
70 | UI_MESSAGE_Handle* | 84 | UI_MESSAGE_Handle* |
diff --git a/src/ui/send_file.c b/src/ui/send_file.c index d998e24..42c5584 100644 --- a/src/ui/send_file.c +++ b/src/ui/send_file.c | |||
@@ -85,17 +85,16 @@ handle_send_button_click(GtkButton *button, | |||
85 | UI_CHAT_ENTRY_Handle *entry = GNUNET_CHAT_context_get_user_pointer(context); | 85 | UI_CHAT_ENTRY_Handle *entry = GNUNET_CHAT_context_get_user_pointer(context); |
86 | UI_CHAT_Handle *handle = entry? entry->chat : NULL; | 86 | UI_CHAT_Handle *handle = entry? entry->chat : NULL; |
87 | 87 | ||
88 | UI_FILE_LOAD_ENTRY_Handle *file_load = NULL; | ||
88 | struct GNUNET_CHAT_File *file = NULL; | 89 | struct GNUNET_CHAT_File *file = NULL; |
89 | 90 | ||
90 | if ((context) && (handle)) | 91 | if ((context) && (handle)) |
91 | { | 92 | { |
92 | UI_FILE_LOAD_ENTRY_Handle *file_load = ui_file_load_entry_new(app); | 93 | file_load = ui_file_load_entry_new(app); |
93 | 94 | ||
94 | gtk_label_set_text(file_load->file_label, filename); | 95 | gtk_label_set_text(file_load->file_label, filename); |
95 | gtk_progress_bar_set_fraction(file_load->load_progress_bar, 0.0); | 96 | gtk_progress_bar_set_fraction(file_load->load_progress_bar, 0.0); |
96 | 97 | ||
97 | ui_chat_add_file_load(handle, file_load); | ||
98 | |||
99 | file = GNUNET_CHAT_context_send_file( | 98 | file = GNUNET_CHAT_context_send_file( |
100 | context, | 99 | context, |
101 | filename, | 100 | filename, |
@@ -109,11 +108,16 @@ handle_send_button_click(GtkButton *button, | |||
109 | gtk_window_close(GTK_WINDOW(app->ui.send_file.dialog)); | 108 | gtk_window_close(GTK_WINDOW(app->ui.send_file.dialog)); |
110 | 109 | ||
111 | if (!file) | 110 | if (!file) |
111 | { | ||
112 | if (file_load) | ||
113 | ui_file_load_entry_delete(file_load); | ||
114 | |||
112 | return; | 115 | return; |
116 | } | ||
113 | 117 | ||
114 | file_create_info(file); | 118 | file_create_info(file); |
115 | 119 | ||
116 | // TODO: create UI component? | 120 | ui_chat_add_file_load(handle, file_load); |
117 | } | 121 | } |
118 | 122 | ||
119 | static void | 123 | static void |