Commit 061f801b authored by Mohammed Sadiq's avatar Mohammed Sadiq
Browse files

avatar: Port to use HandyAvatar

So that we follow HIG and we can keep chatty-avatar simple
parent 833f8b64
Pipeline #66656 passed with stages
in 10 minutes and 20 seconds
......@@ -13,7 +13,7 @@
# include "config.h"
#endif
#include <math.h>
#include <handy.h>
#include "users/chatty-pp-buddy.h"
#include "chatty-settings.h"
......@@ -30,210 +30,36 @@
* @include: "chatty-avatar.h"
*/
#define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
#define DEFAULT_SIZE 32
struct _ChattyAvatar
{
GtkImage parent_instance;
GtkBin parent_instance;
char *title;
GtkWidget *avatar;
ChattyItem *item;
};
G_DEFINE_TYPE (ChattyAvatar, chatty_avatar, GTK_TYPE_IMAGE)
G_DEFINE_TYPE (ChattyAvatar, chatty_avatar, GTK_TYPE_BIN)
enum {
PROP_0,
PROP_ITEM,
PROP_SIZE,
N_PROPS
};
static GParamSpec *properties[N_PROPS];
static GdkRGBA
get_rgba_for_str (const gchar *str)
{
/* XXX: Remove colors with contrast issues */
/* https://gitlab.gnome.org/Teams/Design/HIG-app-icons/blob/master/GNOME%20HIG.gpl */
static guchar color_palette[][3] = {
{153, 193, 241}, /* Blue 1 */
{98, 160, 234}, /* Blue 2 */
{53, 132, 228}, /* Blue 3 */
{28, 113, 216}, /* Blue 4 */
{26, 95, 180}, /* Blue 5 */
{143, 240, 164}, /* Green 1 */
{87, 227, 137}, /* Green 2 */
{51, 209, 122}, /* Green 3 */
{46, 194, 126}, /* Green 4 */
{38, 162, 105}, /* Green 5 */
{249, 240, 107}, /* Yellow 1 */
{248, 228, 92}, /* Yellow 2 */
{246, 211, 45}, /* Yellow 3 */
{245, 194, 17}, /* Yellow 4 */
{229, 165, 10}, /* Yellow 5 */
{255, 190, 111}, /* Orange 1 */
{255, 163, 72}, /* Orange 2 */
{255, 120, 0}, /* Orange 3 */
{230, 97, 0}, /* Orange 4 */
{198, 70, 0}, /* Orange 5 */
{246, 97, 81}, /* Red 1 */
{237, 51, 59}, /* Red 2 */
{224, 27, 36}, /* Red 3 */
{192, 28, 40}, /* Red 4 */
{165, 29, 45}, /* Red 5 */
{220, 138, 221}, /* Purple 1 */
{192, 97, 203}, /* Purple 2 */
{145, 65, 172}, /* Purple 3 */
{129, 61, 156}, /* Purple 4 */
{97, 53, 131}, /* Purple 5 */
{205, 171, 143}, /* Brown 1 */
{181, 131, 90}, /* Brown 2 */
{152, 106, 68}, /* Brown 3 */
{134, 94, 60}, /* Brown 4 */
{99, 69, 44} /* Brown 5 */
};
GdkRGBA rgba = { 0.0, 0.0, 0.0, 1.0 };
guint hash;
int n_colors;
int index;
if (!str || !*str)
return rgba;
hash = g_str_hash (str);
n_colors = G_N_ELEMENTS (color_palette);
index = hash % n_colors;
rgba.red = color_palette[index][0] / 255.0;
rgba.green = color_palette[index][1] / 255.0;
rgba.blue = color_palette[index][2] / 255.0;
return rgba;
}
static void
chatty_avatar_draw_pixbuf (cairo_t *cr,
GdkPixbuf *pixbuf,
gint size)
{
g_autoptr(GdkPixbuf) image = NULL;
int width, height;
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
image = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, size, size);
gdk_pixbuf_scale (pixbuf, image, 0, 0,
size, size,
0, 0,
(double)size / width,
(double)size / height,
GDK_INTERP_BILINEAR);
gdk_cairo_set_source_pixbuf (cr, image, 0, 0);
cairo_arc (cr, size / 2.0, size / 2.0, size / 2.0, 0, 2 * G_PI);
cairo_clip (cr);
cairo_paint (cr);
}
static void
chatty_avatar_draw_label (ChattyAvatar *self,
cairo_t *cr,
const char *label)
{
PangoFontDescription *font_desc;
PangoLayout *layout;
const char *text_end;
g_autofree char *font = NULL;
g_autofree char *upcase_str = NULL;
GdkRGBA bg, fg;
int pango_width, pango_height;
int width, height;
guint size;
gboolean blur = FALSE;
if (CHATTY_IS_CONTACT (self->item) &&
chatty_contact_is_dummy (CHATTY_CONTACT (self->item))) {
/*
* Dummy contact is used as a placeholder to create new contacts,
* So the avatar is always blurred with a ‘+’ symbol on it.
*/
blur = TRUE;
label = "+";
}
width = gtk_widget_get_allocated_width (GTK_WIDGET (self));
height = gtk_widget_get_allocated_width (GTK_WIDGET (self));
size = MIN (width, height);
/* Paint background circle */
bg = get_rgba_for_str (label);
cairo_arc (cr, size / 2.0, size / 2.0, size / 2.0, 0, 2 * G_PI);
if (blur)
bg.red = 0.4, bg.green = 0.4, bg.blue = 0.4;
if (INTENSITY (bg.red, bg.green, bg.blue) > 0.50)
fg.red = 0.1, fg.blue = 0.1, fg.green = 0.1;
else
fg.red = 0.95, fg.green = 0.95, fg.blue = 0.95;
cairo_set_source_rgb (cr, bg.red, bg.green, bg.blue);
cairo_fill (cr);
font = g_strdup_printf ("Sans %d", (int)ceil (size / 2.5));
layout = pango_cairo_create_layout (cr);
font_desc = pango_font_description_from_string (font);
pango_layout_set_font_description (layout, font_desc);
pango_font_description_free (font_desc);
/* Use the first utf-8 letter from name */
text_end = g_utf8_next_char (label);
upcase_str = g_utf8_strup (label, text_end - label);
pango_layout_set_text (layout, upcase_str, -1);
pango_layout_get_size (layout, &pango_width, &pango_height);
cairo_set_source_rgb (cr, fg.red, fg.blue, fg.green);
cairo_translate (cr, size / 2.0, size / 2.0);
cairo_move_to (cr,
-((double)pango_width / PANGO_SCALE) / 2,
-((double)pango_height / PANGO_SCALE) / 2);
pango_cairo_show_layout (cr, layout);
}
static gboolean
chatty_avatar_draw (GtkWidget *widget,
cairo_t *cr)
avatar_changed_cb (ChattyAvatar *self)
{
ChattyAvatar *self = (ChattyAvatar *)widget;
GdkPixbuf *avatar = NULL;
const gchar *name = NULL;
int width, height;
guint size;
GLoadableIcon *avatar = NULL;
width = gtk_widget_get_allocated_width (GTK_WIDGET (self));
height = gtk_widget_get_allocated_width (GTK_WIDGET (self));
size = MIN (width, height);
g_assert (CHATTY_IS_AVATAR (self));
if (self->item)
avatar = chatty_item_get_avatar (self->item);
/* Prefer the custom title over user’s name */
if (!avatar && self->title)
name = self->title;
else if (self->item)
name = chatty_item_get_name (self->item);
if (avatar)
chatty_avatar_draw_pixbuf (cr, avatar, size);
else if (name && *name == '@' &&
(CHATTY_IS_MA_BUDDY (self->item) || CHATTY_IS_MA_CHAT (self->item)))
chatty_avatar_draw_label (self, cr, name + 1);
else if (name && *name)
chatty_avatar_draw_label (self, cr, name);
return GTK_WIDGET_CLASS (chatty_avatar_parent_class)->draw (widget, cr);
avatar = (GLoadableIcon *)chatty_item_get_avatar (self->item);
hdy_avatar_set_loadable_icon (HDY_AVATAR (self->avatar), avatar);
}
static void
......@@ -246,8 +72,8 @@ chatty_avatar_set_property (GObject *object,
switch (prop_id)
{
case PROP_ITEM:
chatty_avatar_set_item (self, g_value_get_object (value));
case PROP_SIZE:
hdy_avatar_set_size (HDY_AVATAR (self->avatar), g_value_get_int (value));
break;
default:
......@@ -261,7 +87,6 @@ chatty_avatar_dispose (GObject *object)
ChattyAvatar *self = (ChattyAvatar *)object;
g_clear_object (&self->item);
g_clear_pointer (&self->title, g_free);
G_OBJECT_CLASS (chatty_avatar_parent_class)->dispose (object);
}
......@@ -270,19 +95,16 @@ static void
chatty_avatar_class_init (ChattyAvatarClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->set_property = chatty_avatar_set_property;
object_class->dispose = chatty_avatar_dispose;
widget_class->draw = chatty_avatar_draw;
properties[PROP_ITEM] =
g_param_spec_object ("item",
"Item",
"An Account, Buddy, Contact or Chat",
CHATTY_TYPE_ITEM,
G_PARAM_WRITABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
properties[PROP_SIZE] =
g_param_spec_int ("size",
"Size",
"Size of avatar",
0, 96, 32,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPS, properties);
}
......@@ -290,16 +112,12 @@ chatty_avatar_class_init (ChattyAvatarClass *klass)
static void
chatty_avatar_init (ChattyAvatar *self)
{
}
GtkWidget *
chatty_avatar_new (ChattyItem *item)
{
g_return_val_if_fail (CHATTY_IS_ITEM (item), NULL);
self->avatar = g_object_new (HDY_TYPE_AVATAR,
"visible", TRUE,
"show-initials", TRUE,
NULL);
return g_object_new (CHATTY_TYPE_AVATAR,
"item", item,
NULL);
gtk_container_add (GTK_CONTAINER (self), self->avatar);
}
/**
......@@ -317,11 +135,16 @@ chatty_avatar_set_title (ChattyAvatar *self,
{
g_return_if_fail (CHATTY_IS_AVATAR (self));
if (title && !*title)
title = NULL;
/* Skip '@' prefix common in matrix usernames */
if (title && title[0] == '@' && title[1])
title++;
/* We use dummy contact as a placeholder to create new chat */
if (CHATTY_IS_CONTACT (self->item) &&
chatty_contact_is_dummy (CHATTY_CONTACT (self->item)))
title = "+";
g_free (self->title);
self->title = g_strdup (title);
hdy_avatar_set_text (HDY_AVATAR (self->avatar), title);
}
void
......@@ -334,25 +157,18 @@ chatty_avatar_set_item (ChattyAvatar *self,
if (!g_set_object (&self->item, item))
return;
gtk_widget_set_visible (GTK_WIDGET (self), !!self->item);
chatty_avatar_set_title (self, NULL);
avatar_changed_cb (self);
/* We don’t emit notify signals as we don’t need it */
if (self->item)
{
ChattySettings *settings;
chatty_avatar_set_title (self, chatty_item_get_name (self->item));
g_signal_connect_swapped (self->item, "deleted",
G_CALLBACK (g_clear_object), &self->item);
g_signal_connect_object (self->item, "avatar-changed",
G_CALLBACK (gtk_widget_queue_draw), self,
G_CALLBACK (avatar_changed_cb), self,
G_CONNECT_SWAPPED);
settings = chatty_settings_get_default ();
g_object_connect (settings,
"swapped-object-signal::notify::indicate-unknown-contacts",
G_CALLBACK (gtk_widget_queue_draw), self,
"swapped-object-signal::notify::blur-idle-buddies",
G_CALLBACK (gtk_widget_queue_draw), self,
NULL);
}
gtk_widget_queue_draw (GTK_WIDGET (self));
}
......@@ -17,9 +17,8 @@ G_BEGIN_DECLS
#define CHATTY_TYPE_AVATAR (chatty_avatar_get_type ())
G_DECLARE_FINAL_TYPE (ChattyAvatar, chatty_avatar, CHATTY, AVATAR, GtkImage)
G_DECLARE_FINAL_TYPE (ChattyAvatar, chatty_avatar, CHATTY, AVATAR, GtkBin)
GtkWidget *chatty_avatar_new (ChattyItem *item);
void chatty_avatar_set_title (ChattyAvatar *item,
const char *title);
void chatty_avatar_set_item (ChattyAvatar *self,
......
......@@ -111,7 +111,7 @@
<child>
<object class="ChattyAvatar" id="avatar">
<property name="visible">1</property>
<property name="pixel-size">96</property>
<property name="size">96</property>
</object>
</child>
</object>
......
......@@ -14,7 +14,6 @@
<object class="ChattyAvatar" id="avatar">
<property name="visible">True</property>
<property name="valign">center</property>
<property name="pixel-size">36</property>
</object>
<packing>
<property name="left-attach">0</property>
......
......@@ -24,7 +24,6 @@
<object class="ChattyAvatar" id="avatar_image">
<property name="visible">True</property>
<property name="valign">start</property>
<property name="pixel-size">36</property>
<property name="no-show-all">True</property>
</object>
<packing>
......
......@@ -301,7 +301,7 @@
<child>
<object class="ChattyAvatar" id="avatar_image">
<property name="visible">True</property>
<property name="pixel_size">96</property>
<property name="size">96</property>
</object>
</child>
</object>
......
......@@ -284,10 +284,9 @@
<property name="valign">center</property>
<child>
<object class="ChattyAvatar" id="sub_header_icon">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="pixel-size">28</property>
<property name="size">28</property>
</object>
</child>
<child>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment