messenger-gtk

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

commit 0518055b9f4b773eb4097623abfed8e791216945
parent 310a225cf85a371d1243c8667991cf86b467316f
Author: Jacki <jacki@thejackimonster.de>
Date:   Wed, 13 Mar 2024 16:57:37 +0100

Implement adding and removing tags on messages with flow boxes

Signed-off-by: Jacki <jacki@thejackimonster.de>

Diffstat:
Mresources/ui/chat.ui | 1+
Mresources/ui/message-sent.ui | 17+++++++++++++++++
Mresources/ui/message-status.ui | 121+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Mresources/ui/message.ui | 16++++++++++++++++
Msrc/event.c | 37++++++++++++++++++++++++++++++++++---
Msrc/ui/message.c | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/ui/message.h | 27+++++++++++++++++++++++++++
7 files changed, 258 insertions(+), 49 deletions(-)

diff --git a/resources/ui/chat.ui b/resources/ui/chat.ui @@ -307,6 +307,7 @@ Author: Tobias Frisch <object class="GtkScrolledWindow" id="chat_scrolled_window"> <property name="visible">True</property> <property name="can-focus">True</property> + <property name="hscrollbar-policy">never</property> <child> <object class="GtkViewport"> <property name="visible">True</property> diff --git a/resources/ui/message-sent.ui b/resources/ui/message-sent.ui @@ -55,6 +55,23 @@ Author: Tobias Frisch <property name="can-focus">False</property> <property name="orientation">vertical</property> <child> + <object class="GtkFlowBox" id="tag_flow_box"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="column-spacing">2</property> + <property name="min-children-per-line">1</property> + <property name="max-children-per-line">5</property> + <property name="selection-mode">none</property> + <property name="activate-on-single-click">False</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> <placeholder/> </child> </object> diff --git a/resources/ui/message-status.ui b/resources/ui/message-status.ui @@ -37,79 +37,108 @@ Author: Tobias Frisch <object class="GtkBox"> <property name="visible">True</property> <property name="can-focus">False</property> - <property name="spacing">8</property> + <property name="orientation">vertical</property> <child> - <object class="GtkRevealer" id="deny_revealer"> + <object class="GtkBox"> <property name="visible">True</property> <property name="can-focus">False</property> - <property name="transition-type">slide-left</property> + <property name="spacing">8</property> <child> - <object class="GtkButton" id="deny_button"> + <object class="GtkRevealer" id="deny_revealer"> <property name="visible">True</property> - <property name="can-focus">True</property> - <property name="receives-default">True</property> - <property name="relief">none</property> + <property name="can-focus">False</property> + <property name="transition-type">slide-left</property> <child> - <object class="GtkImage"> + <object class="GtkButton" id="deny_button"> <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="icon-name">edit-delete-symbolic</property> + <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> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkBox" id="content_box"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="orientation">vertical</property> <child> - <placeholder/> + <object class="GtkBox" id="content_box"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="orientation">vertical</property> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">True</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">1</property> - </packing> - </child> - <child> - <object class="GtkRevealer" id="accept_revealer"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="transition-type">slide-right</property> <child> - <object class="GtkButton" id="accept_button"> + <object class="GtkRevealer" id="accept_revealer"> <property name="visible">True</property> - <property name="can-focus">True</property> - <property name="receives-default">True</property> - <property name="relief">none</property> + <property name="can-focus">False</property> + <property name="transition-type">slide-right</property> <child> - <object class="GtkImage"> + <object class="GtkButton" id="accept_button"> <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="icon-name">emblem-ok-symbolic</property> + <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="position">2</property> + </packing> </child> + <style> + <class name="message-content"/> + </style> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkFlowBox" id="tag_flow_box"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="column-spacing">2</property> + <property name="min-children-per-line">1</property> + <property name="max-children-per-line">5</property> + <property name="selection-mode">none</property> + <property name="activate-on-single-click">False</property> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> - <property name="position">2</property> + <property name="pack-type">end</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.ui b/resources/ui/message.ui @@ -56,6 +56,22 @@ Author: Tobias Frisch <child> <placeholder/> </child> + <child> + <object class="GtkFlowBox" id="tag_flow_box"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="column-spacing">2</property> + <property name="max-children-per-line">5</property> + <property name="selection-mode">none</property> + <property name="activate-on-single-click">False</property> + </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> <child type="label"> diff --git a/src/event.c b/src/event.c @@ -763,7 +763,9 @@ skip_message: } static void -_event_update_tag_message_state(const struct GNUNET_CHAT_Message *msg) +_event_update_tag_message_state(MESSENGER_Application *app, + struct GNUNET_CHAT_Context *context, + const struct GNUNET_CHAT_Message *msg) { g_assert((msg) && (GNUNET_CHAT_KIND_TAG == GNUNET_CHAT_message_get_kind(msg))); @@ -778,6 +780,35 @@ _event_update_tag_message_state(const struct GNUNET_CHAT_Message *msg) if (contact) contact_update_info(contact); + + UI_CHAT_ENTRY_Handle *handle = GNUNET_CHAT_context_get_user_pointer(context); + + if ((!handle) || (!(handle->chat))) + return; + + GList *rows = gtk_container_get_children( + GTK_CONTAINER(handle->chat->messages_listbox) + ); + + for (GList *row = rows; row; row = row->next) + { + UI_MESSAGE_Handle *message = (UI_MESSAGE_Handle*) g_object_get_qdata( + G_OBJECT(row->data), app->quarks.ui + ); + + if ((message) && (message->msg == target)) + { + if (GNUNET_YES == GNUNET_CHAT_message_is_deleted(msg)) + ui_message_remove_tag(message, app, msg); + else + ui_message_add_tag(message, app, msg); + + break; + } + } + + if (rows) + g_list_free(rows); } void @@ -813,7 +844,7 @@ event_delete_message(MESSENGER_Application *app, g_list_free(rows); if (GNUNET_CHAT_KIND_TAG == GNUNET_CHAT_message_get_kind(msg)) - _event_update_tag_message_state(msg); + _event_update_tag_message_state(app, context, msg); enqueue_chat_entry_update(handle); } @@ -829,7 +860,7 @@ event_tag_message(MESSENGER_Application *app, const struct GNUNET_CHAT_Message *target = GNUNET_CHAT_message_get_target(msg); - _event_update_tag_message_state(msg); + _event_update_tag_message_state(app, context, msg); if ((!handle) || (!(handle->chat))) return; diff --git a/src/ui/message.c b/src/ui/message.c @@ -375,6 +375,10 @@ ui_message_new(MESSENGER_Application *app, gtk_builder_get_object(handle->builder[0], "content_box") ); + handle->tag_flow_box = GTK_FLOW_BOX( + gtk_builder_get_object(handle->builder[0], "tag_flow_box") + ); + handle->builder[1] = gtk_builder_new_from_resource( application_get_resource_path(app, "ui/message_content.ui") ); @@ -780,6 +784,90 @@ ui_message_set_contact(UI_MESSAGE_Handle *handle, } void +ui_message_add_tag(UI_MESSAGE_Handle *handle, + MESSENGER_Application *app, + const struct GNUNET_CHAT_Message *tag_message) +{ + g_assert((handle) && (app) && (tag_message)); + + if ((GNUNET_CHAT_KIND_TAG != GNUNET_CHAT_message_get_kind(tag_message)) || + (GNUNET_CHAT_message_get_target(tag_message) != handle->msg)) + return; + + const char *tag_value = GNUNET_CHAT_message_get_text(tag_message); + + if ((!tag_value) || (!tag_value[0])) + return; + + GtkLabel *tag_label = GTK_LABEL(gtk_label_new(NULL)); + + if (!tag_label) + return; + + ui_label_set_text(tag_label, tag_value); + gtk_label_set_ellipsize(tag_label, PANGO_ELLIPSIZE_END); + + g_object_set_qdata(G_OBJECT(tag_label), app->quarks.data, (gpointer) tag_message); + + gtk_container_add(GTK_CONTAINER(handle->tag_flow_box), GTK_WIDGET(tag_label)); + gtk_widget_show_all(GTK_WIDGET(tag_label)); +} + +void +ui_message_remove_tag(UI_MESSAGE_Handle *handle, + MESSENGER_Application *app, + const struct GNUNET_CHAT_Message *tag_message) +{ + g_assert((handle) && (app) && (tag_message)); + + if ((GNUNET_CHAT_KIND_TAG != GNUNET_CHAT_message_get_kind(tag_message)) || + (GNUNET_CHAT_message_get_target(tag_message) != handle->msg)) + return; + + GList *children = gtk_container_get_children(GTK_CONTAINER(handle->tag_flow_box)); + + if (!children) + return; + + GtkWidget *removable = NULL; + + GList *list = children; + while (list) + { + GtkFlowBoxChild *child = GTK_FLOW_BOX_CHILD(list->data); + GList *items = gtk_container_get_children(GTK_CONTAINER(child)); + + if (items) + { + GtkLabel *tag_label = GTK_LABEL(items->data); + + const struct GNUNET_CHAT_Message *msg = g_object_get_qdata( + G_OBJECT(tag_label), + app->quarks.data + ); + + if (tag_message == msg) + removable = GTK_WIDGET(child); + + g_list_free(items); + } + + list = list->next; + + if (removable) + break; + } + + g_list_free(children); + + if (!removable) + return; + + gtk_container_remove(GTK_CONTAINER(handle->tag_flow_box), removable); + gtk_widget_destroy(removable); +} + +void ui_message_delete(UI_MESSAGE_Handle *handle) { g_assert(handle); diff --git a/src/ui/message.h b/src/ui/message.h @@ -51,6 +51,7 @@ typedef struct UI_MESSAGE_Handle GtkBuilder *builder [2]; GtkWidget *message_box; + GtkFlowBox *tag_flow_box; HdyAvatar *sender_avatar; GtkLabel *sender_label; @@ -138,6 +139,32 @@ ui_message_set_contact(UI_MESSAGE_Handle *handle, const struct GNUNET_CHAT_Contact *contact); /** + * Adds a widget to represent a given tag message + * to another message handle. + * + * @param handle Message handle + * @param app Messenger application + * @param tag_message Chat tag message + */ +void +ui_message_add_tag(UI_MESSAGE_Handle *handle, + MESSENGER_Application *app, + const struct GNUNET_CHAT_Message *tag_message); + +/** + * Remove a widget representing a given tag message + * from another message handle. + * + * @param handle Message handle + * @param app Messenger application + * @param tag_message Chat tag message + */ +void +ui_message_remove_tag(UI_MESSAGE_Handle *handle, + MESSENGER_Application *app, + const struct GNUNET_CHAT_Message *tag_message); + +/** * Frees its resources and destroys a given * message handle. *