Render avatar on demand
This commit is contained in:
parent
03a349bfaf
commit
ca331e85ef
|
@ -82,6 +82,7 @@ SOURCES
|
||||||
src/ui/add_conversation/select_contact_dialog.vala
|
src/ui/add_conversation/select_contact_dialog.vala
|
||||||
src/ui/add_conversation/select_jid_fragment.vala
|
src/ui/add_conversation/select_jid_fragment.vala
|
||||||
src/ui/avatar_generator.vala
|
src/ui/avatar_generator.vala
|
||||||
|
src/ui/avatar_image.vala
|
||||||
src/ui/chat_input/edit_history.vala
|
src/ui/chat_input/edit_history.vala
|
||||||
src/ui/chat_input/encryption_button.vala
|
src/ui/chat_input/encryption_button.vala
|
||||||
src/ui/chat_input/occupants_tab_completer.vala
|
src/ui/chat_input/occupants_tab_completer.vala
|
||||||
|
|
|
@ -9,9 +9,10 @@
|
||||||
<property name="column-spacing">10</property>
|
<property name="column-spacing">10</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkImage" id="image">
|
<object class="DinoUiAvatarImage" id="image">
|
||||||
<property name="height_request">30</property>
|
<property name="allow_gray">False</property>
|
||||||
<property name="width_request">30</property>
|
<property name="height">30</property>
|
||||||
|
<property name="width">30</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
|
|
|
@ -33,10 +33,11 @@
|
||||||
<property name="column-spacing">10</property>
|
<property name="column-spacing">10</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkImage" id="avatar">
|
<object class="DinoUiAvatarImage" id="avatar">
|
||||||
<property name="height_request">50</property>
|
<property name="height">50</property>
|
||||||
<property name="width_request">50</property>
|
<property name="width">50</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
<property name="allow_gray">False</property>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="left_attach">0</property>
|
<property name="left_attach">0</property>
|
||||||
|
|
|
@ -15,9 +15,9 @@
|
||||||
<property name="margin-right">14</property>
|
<property name="margin-right">14</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkImage" id="image">
|
<object class="DinoUiAvatarImage" id="image">
|
||||||
<property name="height_request">40</property>
|
<property name="height">40</property>
|
||||||
<property name="width_request">40</property>
|
<property name="width">40</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
|
|
|
@ -9,9 +9,9 @@
|
||||||
<property name="column-spacing">6</property>
|
<property name="column-spacing">6</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkImage" id="image">
|
<object class="DinoUiAvatarImage" id="image">
|
||||||
<property name="height_request">40</property>
|
<property name="height">40</property>
|
||||||
<property name="width_request">40</property>
|
<property name="width">40</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
|
|
|
@ -102,11 +102,12 @@
|
||||||
<class name="image-button"/>
|
<class name="image-button"/>
|
||||||
</style>
|
</style>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkImage" id="image">
|
<object class="DinoUiAvatarImage" id="image">
|
||||||
<property name="height_request">50</property>
|
<property name="height">50</property>
|
||||||
<property name="width_request">50</property>
|
<property name="width">50</property>
|
||||||
<property name="xalign">1</property>
|
<property name="xalign">1</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
<property name="allow_gray">False</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|
|
@ -12,9 +12,9 @@
|
||||||
<property name="column-spacing">10</property>
|
<property name="column-spacing">10</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkImage" id="image">
|
<object class="DinoUiAvatarImage" id="image">
|
||||||
<property name="height_request">30</property>
|
<property name="height">30</property>
|
||||||
<property name="width_request">30</property>
|
<property name="width">30</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
|
|
|
@ -94,7 +94,7 @@ internal class ConferenceListRow : ListRow {
|
||||||
via_label.visible = false;
|
via_label.visible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
image.set_from_pixbuf((new AvatarGenerator(35, 35)).set_stateless(true).draw_jid(stream_interactor, jid, account));
|
image.set_jid(stream_interactor, jid, account);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace Dino.Ui {
|
||||||
[GtkTemplate (ui = "/im/dino/Dino/add_conversation/list_row.ui")]
|
[GtkTemplate (ui = "/im/dino/Dino/add_conversation/list_row.ui")]
|
||||||
public class ListRow : ListBoxRow {
|
public class ListRow : ListBoxRow {
|
||||||
|
|
||||||
[GtkChild] public Image image;
|
[GtkChild] public AvatarImage image;
|
||||||
[GtkChild] public Label name_label;
|
[GtkChild] public Label name_label;
|
||||||
[GtkChild] public Label via_label;
|
[GtkChild] public Label via_label;
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ public class ListRow : ListBoxRow {
|
||||||
via_label.visible = false;
|
via_label.visible = false;
|
||||||
}
|
}
|
||||||
name_label.label = display_name;
|
name_label.label = display_name;
|
||||||
Util.image_set_from_scaled_pixbuf(image, (new AvatarGenerator(35, 35, image.scale_factor)).draw_jid(stream_interactor, jid, account));
|
image.set_jid(stream_interactor, jid, account);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ public class SelectJidFragment : Gtk.Box {
|
||||||
} else {
|
} else {
|
||||||
via_label.visible = false;
|
via_label.visible = false;
|
||||||
}
|
}
|
||||||
image.set_from_pixbuf((new AvatarGenerator(35, 35)).set_greyscale(true).draw_text("?"));
|
image.set_text("?");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,34 +26,36 @@ public class AvatarGenerator {
|
||||||
this.scale_factor = scale_factor;
|
this.scale_factor = scale_factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Pixbuf draw_jid(StreamInteractor stream_interactor, Jid jid_, Account account) {
|
public ImageSurface draw_jid(StreamInteractor stream_interactor, Jid jid_, Account account) {
|
||||||
Jid? jid = jid_;
|
Jid? jid = jid_;
|
||||||
this.stream_interactor = stream_interactor;
|
this.stream_interactor = stream_interactor;
|
||||||
Jid? real_jid = stream_interactor.get_module(MucManager.IDENTITY).get_real_jid(jid, account);
|
Jid? real_jid = stream_interactor.get_module(MucManager.IDENTITY).get_real_jid(jid, account);
|
||||||
if (real_jid != null && stream_interactor.get_module(AvatarManager.IDENTITY).get_avatar(account, real_jid) != null) {
|
if (real_jid != null && stream_interactor.get_module(AvatarManager.IDENTITY).get_avatar(account, real_jid) != null) {
|
||||||
jid = real_jid;
|
jid = real_jid;
|
||||||
}
|
}
|
||||||
return crop_corners(draw_tile(jid, account, width * scale_factor, height * scale_factor), 3 * scale_factor);
|
ImageSurface surface = crop_corners(draw_tile(jid, account, width * scale_factor, height * scale_factor), 3 * scale_factor);
|
||||||
|
surface.set_device_scale(scale_factor, scale_factor);
|
||||||
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Pixbuf draw_message(StreamInteractor stream_interactor, Message message) {
|
public ImageSurface draw_message(StreamInteractor stream_interactor, Message message) {
|
||||||
if (message.real_jid != null && stream_interactor.get_module(AvatarManager.IDENTITY).get_avatar(message.account, message.real_jid) != null) {
|
if (message.real_jid != null && stream_interactor.get_module(AvatarManager.IDENTITY).get_avatar(message.account, message.real_jid) != null) {
|
||||||
return draw_jid(stream_interactor, message.real_jid, message.account);
|
return draw_jid(stream_interactor, message.real_jid, message.account);
|
||||||
}
|
}
|
||||||
return draw_jid(stream_interactor, message.from, message.account);
|
return draw_jid(stream_interactor, message.from, message.account);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Pixbuf draw_conversation(StreamInteractor stream_interactor, Conversation conversation) {
|
public ImageSurface draw_conversation(StreamInteractor stream_interactor, Conversation conversation) {
|
||||||
return draw_jid(stream_interactor, conversation.counterpart, conversation.account);
|
return draw_jid(stream_interactor, conversation.counterpart, conversation.account);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Pixbuf draw_account(StreamInteractor stream_interactor, Account account) {
|
public ImageSurface draw_account(StreamInteractor stream_interactor, Account account) {
|
||||||
return draw_jid(stream_interactor, account.bare_jid, account);
|
return draw_jid(stream_interactor, account.bare_jid, account);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Pixbuf draw_text(string text) {
|
public ImageSurface draw_text(string text) {
|
||||||
Pixbuf pixbuf = draw_colored_rectangle_text(COLOR_GREY, text, width, height);
|
ImageSurface surface = draw_colored_rectangle_text(COLOR_GREY, text, width, height);
|
||||||
return crop_corners(pixbuf, 3 * scale_factor);
|
return crop_corners(surface, 3 * scale_factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AvatarGenerator set_greyscale(bool greyscale) {
|
public AvatarGenerator set_greyscale(bool greyscale) {
|
||||||
|
@ -75,33 +77,39 @@ public class AvatarGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void add_tile_to_pixbuf(Pixbuf pixbuf, Jid jid, Account account, int width, int height, int x, int y) {
|
private void add_tile_to_pixbuf(Pixbuf pixbuf, Jid jid, Account account, int width, int height, int x, int y) {
|
||||||
Pixbuf tile = draw_chat_tile(jid, account, width, height);
|
Pixbuf tile = pixbuf_get_from_surface(draw_chat_tile(jid, account, width, height), 0, 0, width, height);
|
||||||
tile.copy_area(0, 0, width, height, pixbuf, x, y);
|
tile.copy_area(0, 0, width, height, pixbuf, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Pixbuf draw_tile(Jid jid, Account account, int width, int height) {
|
private ImageSurface draw_tile(Jid jid, Account account, int width, int height) {
|
||||||
|
ImageSurface surface;
|
||||||
if (stream_interactor.get_module(MucManager.IDENTITY).is_groupchat(jid, account)) {
|
if (stream_interactor.get_module(MucManager.IDENTITY).is_groupchat(jid, account)) {
|
||||||
return draw_groupchat_tile(jid, account, width, height);
|
surface = draw_groupchat_tile(jid, account, width, height);
|
||||||
} else {
|
} else {
|
||||||
return draw_chat_tile(jid, account, width, height);
|
surface = draw_chat_tile(jid, account, width, height);
|
||||||
}
|
}
|
||||||
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Pixbuf draw_chat_tile(Jid jid, Account account, int width, int height) {
|
private ImageSurface draw_chat_tile(Jid jid, Account account, int width, int height) {
|
||||||
Pixbuf? avatar = stream_interactor.get_module(AvatarManager.IDENTITY).get_avatar(account, jid);
|
Pixbuf? pixbuf = stream_interactor.get_module(AvatarManager.IDENTITY).get_avatar(account, jid);
|
||||||
if (avatar != null) {
|
if (pixbuf != null) {
|
||||||
double desired_ratio = (double) width / height;
|
double desired_ratio = (double) width / height;
|
||||||
double avatar_ratio = (double) avatar.width / avatar.height;
|
double avatar_ratio = (double) pixbuf.width / pixbuf.height;
|
||||||
if (avatar_ratio > desired_ratio) {
|
if (avatar_ratio > desired_ratio) {
|
||||||
int comp_width = width * avatar.height / height;
|
int comp_width = width * pixbuf.height / height;
|
||||||
avatar = new Pixbuf.subpixbuf(avatar, avatar.width / 2 - comp_width / 2, 0, comp_width, avatar.height);
|
pixbuf = new Pixbuf.subpixbuf(pixbuf, pixbuf.width / 2 - comp_width / 2, 0, comp_width, pixbuf.height);
|
||||||
} else if (avatar_ratio < desired_ratio) {
|
} else if (avatar_ratio < desired_ratio) {
|
||||||
int comp_height = height * avatar.width / width;
|
int comp_height = height * pixbuf.width / width;
|
||||||
avatar = new Pixbuf.subpixbuf(avatar, 0, avatar.height / 2 - comp_height / 2, avatar.width, comp_height);
|
pixbuf = new Pixbuf.subpixbuf(pixbuf, 0, pixbuf.height / 2 - comp_height / 2, pixbuf.width, comp_height);
|
||||||
}
|
}
|
||||||
avatar = avatar.scale_simple(width, height, InterpType.BILINEAR);
|
pixbuf = pixbuf.scale_simple(width, height, InterpType.BILINEAR);
|
||||||
if (greyscale) avatar = convert_to_greyscale(avatar);
|
Context ctx = new Context(new ImageSurface(Format.ARGB32, pixbuf.width, pixbuf.height));
|
||||||
return avatar;
|
cairo_set_source_pixbuf(ctx, pixbuf, 0, 0);
|
||||||
|
ctx.paint();
|
||||||
|
ImageSurface avatar_surface = (ImageSurface) ctx.get_target();
|
||||||
|
if (greyscale) avatar_surface = convert_to_greyscale(avatar_surface);
|
||||||
|
return avatar_surface;
|
||||||
} else {
|
} else {
|
||||||
string display_name = Util.get_display_name(stream_interactor, jid, account);
|
string display_name = Util.get_display_name(stream_interactor, jid, account);
|
||||||
string color = greyscale ? COLOR_GREY : Util.get_avatar_hex_color(stream_interactor, account, jid);
|
string color = greyscale ? COLOR_GREY : Util.get_avatar_hex_color(stream_interactor, account, jid);
|
||||||
|
@ -109,7 +117,7 @@ public class AvatarGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Pixbuf draw_groupchat_tile(Jid jid, Account account, int width, int height) {
|
private ImageSurface draw_groupchat_tile(Jid jid, Account account, int width, int height) {
|
||||||
Gee.List<Jid>? occupants = stream_interactor.get_module(MucManager.IDENTITY).get_other_occupants(jid, account);
|
Gee.List<Jid>? occupants = stream_interactor.get_module(MucManager.IDENTITY).get_other_occupants(jid, account);
|
||||||
if (stateless || occupants == null || occupants.size == 0) {
|
if (stateless || occupants == null || occupants.size == 0) {
|
||||||
return draw_chat_tile(jid, account, width, height);
|
return draw_chat_tile(jid, account, width, height);
|
||||||
|
@ -139,15 +147,18 @@ public class AvatarGenerator {
|
||||||
if (occupants.size == 4) {
|
if (occupants.size == 4) {
|
||||||
add_tile_to_pixbuf(pixbuf, occupants[3], account, width / 2 - get_left_border(), height / 2 - get_left_border(), width / 2 + get_left_border(), height / 2 + get_left_border());
|
add_tile_to_pixbuf(pixbuf, occupants[3], account, width / 2 - get_left_border(), height / 2 - get_left_border(), width / 2 + get_left_border(), height / 2 + get_left_border());
|
||||||
} else if (occupants.size > 4) {
|
} else if (occupants.size > 4) {
|
||||||
Pixbuf plus_pixbuf = draw_colored_rectangle_text("555753", "+", width / 2 - get_left_border(), height / 2 - get_left_border());
|
ImageSurface plus_surface = draw_colored_rectangle_text("555753", "+", width / 2 - get_left_border(), height / 2 - get_left_border());
|
||||||
if (greyscale) plus_pixbuf = convert_to_greyscale(plus_pixbuf);
|
if (greyscale) plus_surface = convert_to_greyscale(plus_surface);
|
||||||
plus_pixbuf.copy_area(0, 0, width / 2 - get_left_border(), height / 2 - get_left_border(), pixbuf, width / 2 + get_left_border(), height / 2 + get_left_border());
|
pixbuf_get_from_surface(plus_surface, 0, 0, plus_surface.get_width(), plus_surface.get_height()).copy_area(0, 0, width / 2 - get_left_border(), height / 2 - get_left_border(), pixbuf, width / 2 + get_left_border(), height / 2 + get_left_border());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pixbuf;
|
Context ctx = new Context(new ImageSurface(Format.ARGB32, pixbuf.width, pixbuf.height));
|
||||||
|
cairo_set_source_pixbuf(ctx, pixbuf, 0, 0);
|
||||||
|
ctx.paint();
|
||||||
|
return (ImageSurface) ctx.get_target();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Pixbuf draw_colored_icon(string hex_color, string icon, int width, int height) {
|
public ImageSurface draw_colored_icon(string hex_color, string icon, int width, int height) {
|
||||||
int ICON_SIZE = width > 20 * scale_factor ? 17 * scale_factor : 14 * scale_factor;
|
int ICON_SIZE = width > 20 * scale_factor ? 17 * scale_factor : 14 * scale_factor;
|
||||||
|
|
||||||
Context rectancle_context = new Context(new ImageSurface(Format.ARGB32, width, height));
|
Context rectancle_context = new Context(new ImageSurface(Format.ARGB32, width, height));
|
||||||
|
@ -166,14 +177,14 @@ public class AvatarGenerator {
|
||||||
rectancle_context.paint();
|
rectancle_context.paint();
|
||||||
} catch (Error e) { warning(@"Icon $icon does not exist"); }
|
} catch (Error e) { warning(@"Icon $icon does not exist"); }
|
||||||
|
|
||||||
return pixbuf_get_from_surface(rectancle_context.get_target(), 0, 0, width, height);
|
return (ImageSurface) rectancle_context.get_target();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Pixbuf draw_colored_rectangle_text(string hex_color, string text, int width, int height) {
|
public ImageSurface draw_colored_rectangle_text(string hex_color, string text, int width, int height) {
|
||||||
Context ctx = new Context(new ImageSurface(Format.ARGB32, width, height));
|
Context ctx = new Context(new ImageSurface(Format.ARGB32, width, height));
|
||||||
draw_colored_rectangle(ctx, hex_color, width, height);
|
draw_colored_rectangle(ctx, hex_color, width, height);
|
||||||
draw_center_text(ctx, text, width < 40 * scale_factor ? 17 * scale_factor : 25 * scale_factor, width, height);
|
draw_center_text(ctx, text, width < 40 * scale_factor ? 17 * scale_factor : 25 * scale_factor, width, height);
|
||||||
return pixbuf_get_from_surface(ctx.get_target(), 0, 0, width, height);
|
return (ImageSurface) ctx.get_target();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void draw_center_text(Context ctx, string text, int fontsize, int width, int height) {
|
private static void draw_center_text(Context ctx, string text, int fontsize, int width, int height) {
|
||||||
|
@ -194,23 +205,22 @@ public class AvatarGenerator {
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Pixbuf convert_to_greyscale(Pixbuf pixbuf) {
|
private static ImageSurface convert_to_greyscale(ImageSurface surface) {
|
||||||
Surface surface = cairo_surface_create_from_pixbuf(pixbuf, 1, null);
|
|
||||||
Context context = new Context(surface);
|
Context context = new Context(surface);
|
||||||
// convert to greyscale
|
// convert to greyscale
|
||||||
context.set_operator(Operator.HSL_COLOR);
|
context.set_operator(Operator.HSL_COLOR);
|
||||||
context.set_source_rgb(1, 1, 1);
|
context.set_source_rgb(1, 1, 1);
|
||||||
context.rectangle(0, 0, pixbuf.width, pixbuf.height);
|
context.rectangle(0, 0, surface.get_width(), surface.get_height());
|
||||||
context.fill();
|
context.fill();
|
||||||
// make the visible part more light
|
// make the visible part more light
|
||||||
context.set_operator(Operator.ATOP);
|
context.set_operator(Operator.ATOP);
|
||||||
context.set_source_rgba(1, 1, 1, 0.7);
|
context.set_source_rgba(1, 1, 1, 0.7);
|
||||||
context.rectangle(0, 0, pixbuf.width, pixbuf.height);
|
context.rectangle(0, 0, surface.get_width(), surface.get_height());
|
||||||
context.fill();
|
context.fill();
|
||||||
return pixbuf_get_from_surface(context.get_target(), 0, 0, pixbuf.width, pixbuf.height);
|
return (ImageSurface) context.get_target();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Pixbuf crop_corners(Pixbuf pixbuf, double radius = 3) {
|
public static Pixbuf crop_corners_pixbuf(Pixbuf pixbuf, double radius = 3) {
|
||||||
Context ctx = new Context(new ImageSurface(Format.ARGB32, pixbuf.width, pixbuf.height));
|
Context ctx = new Context(new ImageSurface(Format.ARGB32, pixbuf.width, pixbuf.height));
|
||||||
cairo_set_source_pixbuf(ctx, pixbuf, 0, 0);
|
cairo_set_source_pixbuf(ctx, pixbuf, 0, 0);
|
||||||
double degrees = Math.PI / 180.0;
|
double degrees = Math.PI / 180.0;
|
||||||
|
@ -225,6 +235,21 @@ public class AvatarGenerator {
|
||||||
return pixbuf_get_from_surface(ctx.get_target(), 0, 0, pixbuf.width, pixbuf.height);
|
return pixbuf_get_from_surface(ctx.get_target(), 0, 0, pixbuf.width, pixbuf.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ImageSurface crop_corners(ImageSurface surface, double radius = 3) {
|
||||||
|
Context ctx = new Context(new ImageSurface(Format.ARGB32, surface.get_width(), surface.get_height()));
|
||||||
|
ctx.set_source_surface(surface, 0, 0);
|
||||||
|
double degrees = Math.PI / 180.0;
|
||||||
|
ctx.new_sub_path();
|
||||||
|
ctx.arc(surface.get_width() - radius, radius, radius, -90 * degrees, 0 * degrees);
|
||||||
|
ctx.arc(surface.get_width() - radius, surface.get_height() - radius, radius, 0 * degrees, 90 * degrees);
|
||||||
|
ctx.arc(radius, surface.get_height() - radius, radius, 90 * degrees, 180 * degrees);
|
||||||
|
ctx.arc(radius, radius, radius, 180 * degrees, 270 * degrees);
|
||||||
|
ctx.close_path();
|
||||||
|
ctx.clip();
|
||||||
|
ctx.paint();
|
||||||
|
return (ImageSurface) ctx.get_target();
|
||||||
|
}
|
||||||
|
|
||||||
private static Pixbuf initialize_pixbuf(int width, int height) {
|
private static Pixbuf initialize_pixbuf(int width, int height) {
|
||||||
Context ctx = new Context(new ImageSurface(Format.ARGB32, width, height));
|
Context ctx = new Context(new ImageSurface(Format.ARGB32, width, height));
|
||||||
ctx.set_source_rgba(1, 1, 1, 0);
|
ctx.set_source_rgba(1, 1, 1, 0);
|
||||||
|
|
302
main/src/ui/avatar_image.vala
Normal file
302
main/src/ui/avatar_image.vala
Normal file
|
@ -0,0 +1,302 @@
|
||||||
|
using Gtk;
|
||||||
|
using Dino.Entities;
|
||||||
|
using Xmpp;
|
||||||
|
|
||||||
|
namespace Dino.Ui {
|
||||||
|
|
||||||
|
public class AvatarImage : Misc {
|
||||||
|
public int height { get; set; default = 32; }
|
||||||
|
public int width { get; set; default = 32; }
|
||||||
|
public bool allow_gray { get; set; default = true; }
|
||||||
|
public Account account { get; private set; }
|
||||||
|
public StreamInteractor stream_interactor { get; set; }
|
||||||
|
public AvatarManager avatar_manager { owned get { return stream_interactor.get_module(AvatarManager.IDENTITY); } }
|
||||||
|
public MucManager muc_manager { owned get { return stream_interactor.get_module(MucManager.IDENTITY); } }
|
||||||
|
private Jid jid;
|
||||||
|
private string? text_only;
|
||||||
|
private bool with_plus;
|
||||||
|
private bool gray;
|
||||||
|
private Jid[] current_jids;
|
||||||
|
private Gdk.Pixbuf[] current_avatars;
|
||||||
|
|
||||||
|
public AvatarImage() {
|
||||||
|
can_focus = false;
|
||||||
|
get_style_context().add_class("avatar");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void get_preferred_width(out int minimum_width, out int natural_width) {
|
||||||
|
minimum_width = width;
|
||||||
|
natural_width = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void get_preferred_height(out int minimum_height, out int natural_height) {
|
||||||
|
minimum_height = height;
|
||||||
|
natural_height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Cairo.Surface sub_surface(Cairo.Context ctx, int idx, int width, int height, int font_factor = 1) {
|
||||||
|
Cairo.Surface buffer = new Cairo.Surface.similar(ctx.get_target(), Cairo.Content.COLOR_ALPHA, width, height);
|
||||||
|
Cairo.Context bufctx = new Cairo.Context(buffer);
|
||||||
|
if (idx == -1 || current_avatars[idx] == null) {
|
||||||
|
set_source_hex_color(bufctx, gray || idx == -1 ? "555753" : Util.get_avatar_hex_color(stream_interactor, account, current_jids[idx]));
|
||||||
|
bufctx.rectangle(0, 0, width, height);
|
||||||
|
bufctx.fill();
|
||||||
|
|
||||||
|
string text = text_only ?? (idx == -1 ? "…" : Util.get_display_name(stream_interactor, current_jids[idx], account).get_char(0).toupper().to_string());
|
||||||
|
bufctx.select_font_face(get_pango_context().get_font_description().get_family(), Cairo.FontSlant.NORMAL, Cairo.FontWeight.NORMAL);
|
||||||
|
bufctx.set_font_size(width / font_factor < 40 ? font_factor * 17 : font_factor * 25);
|
||||||
|
Cairo.TextExtents extents;
|
||||||
|
bufctx.text_extents(text, out extents);
|
||||||
|
double x_pos = width/2 - (extents.width/2 + extents.x_bearing);
|
||||||
|
double y_pos = height/2 - (extents.height/2 + extents.y_bearing);
|
||||||
|
bufctx.move_to(x_pos, y_pos);
|
||||||
|
bufctx.set_source_rgba(1, 1, 1, 1);
|
||||||
|
bufctx.show_text(text);
|
||||||
|
} else {
|
||||||
|
double w_scale = (double) width / current_avatars[idx].width;
|
||||||
|
double h_scale = (double) height / current_avatars[idx].height;
|
||||||
|
double scale = double.max(w_scale, h_scale);
|
||||||
|
bufctx.scale(scale, scale);
|
||||||
|
|
||||||
|
double x_off = 0, y_off = 0;
|
||||||
|
if (scale == h_scale) {
|
||||||
|
x_off = (width / scale - current_avatars[idx].width) / 2.0;
|
||||||
|
} else {
|
||||||
|
y_off = (height / scale - current_avatars[idx].height) / 2.0;
|
||||||
|
}
|
||||||
|
Gdk.cairo_set_source_pixbuf(bufctx, current_avatars[idx], x_off, y_off);
|
||||||
|
bufctx.get_source().set_filter(Cairo.Filter.BEST);
|
||||||
|
bufctx.paint();
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void set_source_hex_color(Cairo.Context ctx, string hex_color) {
|
||||||
|
ctx.set_source_rgba((double) hex_color.substring(0, 2).to_long(null, 16) / 255,
|
||||||
|
(double) hex_color.substring(2, 2).to_long(null, 16) / 255,
|
||||||
|
(double) hex_color.substring(4, 2).to_long(null, 16) / 255,
|
||||||
|
hex_color.length > 6 ? (double) hex_color.substring(6, 2).to_long(null, 16) / 255 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool draw(Cairo.Context ctx) {
|
||||||
|
if (text_only == null && (current_jids == null || current_avatars == null || current_jids.length == 0)) return false;
|
||||||
|
double radius = 3;
|
||||||
|
double degrees = Math.PI / 180.0;
|
||||||
|
ctx.new_sub_path();
|
||||||
|
ctx.arc(width - radius, radius, radius, -90 * degrees, 0 * degrees);
|
||||||
|
ctx.arc(width - radius, height - radius, radius, 0 * degrees, 90 * degrees);
|
||||||
|
ctx.arc(radius, height - radius, radius, 90 * degrees, 180 * degrees);
|
||||||
|
ctx.arc(radius, radius, radius, 180 * degrees, 270 * degrees);
|
||||||
|
ctx.close_path();
|
||||||
|
ctx.clip();
|
||||||
|
|
||||||
|
if (text_only != null) {
|
||||||
|
ctx.set_source_surface(sub_surface(ctx, -1, width, height), 0, 0);
|
||||||
|
ctx.paint();
|
||||||
|
} else if (current_jids.length == 4 || with_plus) {
|
||||||
|
Cairo.Surface buffer = new Cairo.Surface.similar(ctx.get_target(), Cairo.Content.COLOR_ALPHA, width, height);
|
||||||
|
Cairo.Context bufctx = new Cairo.Context(buffer);
|
||||||
|
bufctx.scale(0.5, 0.5);
|
||||||
|
bufctx.set_source_surface(sub_surface(ctx, 0, width - 1, height - 1, 2), 0, 0);
|
||||||
|
bufctx.paint();
|
||||||
|
bufctx.set_source_surface(sub_surface(ctx, 1, width - 1, height - 1, 2), width + 1, 0);
|
||||||
|
bufctx.paint();
|
||||||
|
bufctx.set_source_surface(sub_surface(ctx, 2, width - 1, height - 1, 2), 0, height + 1);
|
||||||
|
bufctx.paint();
|
||||||
|
if (with_plus) {
|
||||||
|
bufctx.set_source_surface(sub_surface(ctx, -1, width - 1, height - 1, 2), width + 1, height + 1);
|
||||||
|
bufctx.paint();
|
||||||
|
} else {
|
||||||
|
bufctx.set_source_surface(sub_surface(ctx, 3, width - 1, height - 1, 2), width + 1, height + 1);
|
||||||
|
bufctx.paint();
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.set_source_surface(buffer, 0, 0);
|
||||||
|
ctx.paint();
|
||||||
|
} else if (current_jids.length == 3) {
|
||||||
|
Cairo.Surface buffer = new Cairo.Surface.similar(ctx.get_target(), Cairo.Content.COLOR_ALPHA, width, height);
|
||||||
|
Cairo.Context bufctx = new Cairo.Context(buffer);
|
||||||
|
bufctx.scale(0.5, 0.5);
|
||||||
|
bufctx.set_source_surface(sub_surface(ctx, 0, width - 1, height - 1, 2), 0, 0);
|
||||||
|
bufctx.paint();
|
||||||
|
bufctx.set_source_surface(sub_surface(ctx, 1, width - 1, height * 2, 2), width + 1, 0);
|
||||||
|
bufctx.paint();
|
||||||
|
bufctx.set_source_surface(sub_surface(ctx, 2, width - 1 , height - 1, 2), 0, height + 1);
|
||||||
|
bufctx.paint();
|
||||||
|
|
||||||
|
ctx.set_source_surface(buffer, 0, 0);
|
||||||
|
ctx.paint();
|
||||||
|
} else if (current_jids.length == 2) {
|
||||||
|
Cairo.Surface buffer = new Cairo.Surface.similar(ctx.get_target(), Cairo.Content.COLOR_ALPHA, width, height);
|
||||||
|
Cairo.Context bufctx = new Cairo.Context(buffer);
|
||||||
|
bufctx.scale(0.5, 0.5);
|
||||||
|
bufctx.set_source_surface(sub_surface(ctx, 0, width - 1, height * 2, 2), 0, 0);
|
||||||
|
bufctx.paint();
|
||||||
|
bufctx.set_source_surface(sub_surface(ctx, 1, width - 1, height * 2, 2), width + 1, 0);
|
||||||
|
bufctx.paint();
|
||||||
|
|
||||||
|
ctx.set_source_surface(buffer, 0, 0);
|
||||||
|
ctx.paint();
|
||||||
|
} else if (current_jids.length == 1) {
|
||||||
|
ctx.set_source_surface(sub_surface(ctx, 0, width, height), 0, 0);
|
||||||
|
ctx.paint();
|
||||||
|
} else {
|
||||||
|
assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gray) {
|
||||||
|
// convert to greyscale
|
||||||
|
ctx.set_operator(Cairo.Operator.HSL_COLOR);
|
||||||
|
ctx.set_source_rgb(1, 1, 1);
|
||||||
|
ctx.rectangle(0, 0, width, height);
|
||||||
|
ctx.fill();
|
||||||
|
// make the visible part more light
|
||||||
|
ctx.set_operator(Cairo.Operator.ATOP);
|
||||||
|
ctx.set_source_rgba(1, 1, 1, 0.7);
|
||||||
|
ctx.rectangle(0, 0, width, height);
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void destroy() {
|
||||||
|
if (stream_interactor != null) {
|
||||||
|
stream_interactor.get_module(PresenceManager.IDENTITY).show_received.disconnect(on_show_received);
|
||||||
|
stream_interactor.get_module(AvatarManager.IDENTITY).received_avatar.disconnect(on_received_avatar);
|
||||||
|
stream_interactor.connection_manager.connection_state_changed.disconnect(on_connection_changed);
|
||||||
|
stream_interactor.get_module(RosterManager.IDENTITY).updated_roster_item.disconnect(on_roster_updated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set_jid(StreamInteractor stream_interactor, Jid jid_, Account account, bool force_update = false) {
|
||||||
|
this.account = account;
|
||||||
|
if (this.stream_interactor == null) {
|
||||||
|
this.stream_interactor = stream_interactor;
|
||||||
|
stream_interactor.get_module(PresenceManager.IDENTITY).show_received.connect(on_show_received);
|
||||||
|
stream_interactor.get_module(AvatarManager.IDENTITY).received_avatar.connect(on_received_avatar);
|
||||||
|
stream_interactor.connection_manager.connection_state_changed.connect(on_connection_changed);
|
||||||
|
stream_interactor.get_module(RosterManager.IDENTITY).updated_roster_item.connect(on_roster_updated);
|
||||||
|
}
|
||||||
|
if (muc_manager.is_groupchat(jid_, account)) {
|
||||||
|
// Groupchat
|
||||||
|
Gee.List<Jid>? occupants = muc_manager.get_other_occupants(jid_, account);
|
||||||
|
jid = jid_;
|
||||||
|
if (occupants == null || occupants.size == 0) {
|
||||||
|
if (force_update || current_jids.length != 1 || !current_jids[0].equals(jid_) || gray != (allow_gray && (occupants == null || !is_self_online()))) {
|
||||||
|
set_jids(new Jid[] {jid_}, false, occupants == null || !is_self_online());
|
||||||
|
}
|
||||||
|
} else if (occupants.size > 4) {
|
||||||
|
bool requires_update = force_update;
|
||||||
|
if (!with_plus) requires_update = true;
|
||||||
|
foreach (Jid jid in current_jids) {
|
||||||
|
if (!occupants.contains(jid)) {
|
||||||
|
requires_update = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (requires_update) {
|
||||||
|
set_jids(occupants.slice(0, 3).to_array(), true);
|
||||||
|
}
|
||||||
|
} else { // 1 <= occupants.size <= 4
|
||||||
|
bool requires_update = force_update;
|
||||||
|
if (with_plus) requires_update = true;
|
||||||
|
if (current_jids.length != occupants.size) requires_update = true;
|
||||||
|
foreach (Jid jid in current_jids) {
|
||||||
|
if (!occupants.contains(jid)) {
|
||||||
|
requires_update = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (requires_update) {
|
||||||
|
set_jids(occupants.to_array(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Single user
|
||||||
|
this.jid = jid_;
|
||||||
|
if (force_update || current_jids.length != 1 || !current_jids[0].equals(jid) || gray != (allow_gray && (!is_counterpart_online(jid) || !is_self_online()))) {
|
||||||
|
set_jids(new Jid[] { jid }, false, !is_counterpart_online(jid) || !is_self_online());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void on_show_received(Show show, Jid jid, Account account) {
|
||||||
|
if (!account.equals(this.account)) return;
|
||||||
|
if (jid.equals_bare(this.jid)) {
|
||||||
|
set_jid(stream_interactor, this.jid, account, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
foreach (Jid jid_ in current_jids) {
|
||||||
|
if (jid.equals_bare(jid_)) {
|
||||||
|
set_jid(stream_interactor, this.jid, account, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void on_received_avatar(Gdk.Pixbuf avatar, Jid jid, Account account) {
|
||||||
|
if (!account.equals(this.account)) return;
|
||||||
|
if (jid.equals_bare(this.jid)) {
|
||||||
|
set_jid(stream_interactor, this.jid, account, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
foreach (Jid jid_ in current_jids) {
|
||||||
|
if (jid.equals_bare(jid_)) {
|
||||||
|
set_jid(stream_interactor, this.jid, account, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void on_connection_changed(Account account, ConnectionManager.ConnectionState state) {
|
||||||
|
if (!account.equals(this.account)) return;
|
||||||
|
set_jid(stream_interactor, this.jid, account, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void on_roster_updated(Account account, Jid jid, Roster.Item roster_item) {
|
||||||
|
if (!account.equals(this.account)) return;
|
||||||
|
if (!jid.equals_bare(this.jid)) return;
|
||||||
|
set_jid(stream_interactor, this.jid, account, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool is_self_online() {
|
||||||
|
return stream_interactor.connection_manager.get_state(account) == ConnectionManager.ConnectionState.CONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool is_counterpart_online(Jid counterpart) {
|
||||||
|
return stream_interactor.get_module(PresenceManager.IDENTITY).get_full_jids(counterpart, account) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set_jids(Jid[] jids, bool with_plus = false, bool gray = false) {
|
||||||
|
assert(jids.length > 0);
|
||||||
|
assert(jids.length < 5);
|
||||||
|
assert(!with_plus || jids.length == 3);
|
||||||
|
this.text_only = null;
|
||||||
|
this.gray = gray && allow_gray;
|
||||||
|
this.with_plus = with_plus;
|
||||||
|
this.current_jids = jids;
|
||||||
|
this.current_avatars = new Gdk.Pixbuf[jids.length];
|
||||||
|
for (int i = 0; i < current_jids.length; ++i) {
|
||||||
|
Jid? real_jid = muc_manager.get_real_jid(current_jids[i], account);
|
||||||
|
if (real_jid != null) {
|
||||||
|
current_avatars[i] = avatar_manager.get_avatar(account, real_jid);
|
||||||
|
if (current_avatars[i] != null) {
|
||||||
|
current_jids[i] = real_jid;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current_avatars[i] = avatar_manager.get_avatar(account, current_jids[i]);
|
||||||
|
}
|
||||||
|
queue_draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set_text(string text, bool gray = true) {
|
||||||
|
this.text_only = text;
|
||||||
|
this.gray = gray;
|
||||||
|
this.with_plus = false;
|
||||||
|
this.current_jids = null;
|
||||||
|
this.current_avatars = null;
|
||||||
|
queue_draw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ namespace Dino.Ui.ContactDetails {
|
||||||
[GtkTemplate (ui = "/im/dino/Dino/contact_details_dialog.ui")]
|
[GtkTemplate (ui = "/im/dino/Dino/contact_details_dialog.ui")]
|
||||||
public class Dialog : Gtk.Dialog {
|
public class Dialog : Gtk.Dialog {
|
||||||
|
|
||||||
[GtkChild] public Image avatar;
|
[GtkChild] public AvatarImage avatar;
|
||||||
[GtkChild] public Util.EntryLabelHybrid name_hybrid;
|
[GtkChild] public Util.EntryLabelHybrid name_hybrid;
|
||||||
[GtkChild] public Label name_label;
|
[GtkChild] public Label name_label;
|
||||||
[GtkChild] public Label jid_label;
|
[GtkChild] public Label jid_label;
|
||||||
|
@ -70,7 +70,7 @@ public class Dialog : Gtk.Dialog {
|
||||||
}
|
}
|
||||||
jid_label.label = conversation.counterpart.to_string();
|
jid_label.label = conversation.counterpart.to_string();
|
||||||
account_label.label = "via " + conversation.account.bare_jid.to_string();
|
account_label.label = "via " + conversation.account.bare_jid.to_string();
|
||||||
Util.image_set_from_scaled_pixbuf(avatar, (new AvatarGenerator(50, 50, avatar.scale_factor)).draw_conversation(stream_interactor, conversation));
|
avatar.set_jid(stream_interactor, conversation.counterpart, conversation.account);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void add_entry(string category, string label, string? description, Object wo) {
|
private void add_entry(string category, string label, string? description, Object wo) {
|
||||||
|
|
|
@ -13,7 +13,7 @@ public abstract class ConversationRow : ListBoxRow {
|
||||||
|
|
||||||
public signal void closed();
|
public signal void closed();
|
||||||
|
|
||||||
[GtkChild] protected Image image;
|
[GtkChild] protected AvatarImage image;
|
||||||
[GtkChild] protected Label name_label;
|
[GtkChild] protected Label name_label;
|
||||||
[GtkChild] protected Label time_label;
|
[GtkChild] protected Label time_label;
|
||||||
[GtkChild] protected Label nick_label;
|
[GtkChild] protected Label nick_label;
|
||||||
|
@ -42,11 +42,10 @@ public abstract class ConversationRow : ListBoxRow {
|
||||||
this.stream_interactor = stream_interactor;
|
this.stream_interactor = stream_interactor;
|
||||||
|
|
||||||
x_button.clicked.connect(close_conversation);
|
x_button.clicked.connect(close_conversation);
|
||||||
|
image.set_jid(stream_interactor, conversation.counterpart, conversation.account);
|
||||||
conversation.notify["read-up-to"].connect(update_read);
|
conversation.notify["read-up-to"].connect(update_read);
|
||||||
stream_interactor.connection_manager.connection_state_changed.connect(update_avatar);
|
|
||||||
|
|
||||||
update_name_label();
|
update_name_label();
|
||||||
update_avatar();
|
|
||||||
message_received();
|
message_received();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -62,21 +61,6 @@ public abstract class ConversationRow : ListBoxRow {
|
||||||
update_read();
|
update_read();
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void on_show_received(Show presence) {
|
|
||||||
update_avatar();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void update_avatar() {
|
|
||||||
bool self_online = stream_interactor.connection_manager.get_state(conversation.account) == ConnectionManager.ConnectionState.CONNECTED;
|
|
||||||
bool counterpart_online = stream_interactor.get_module(PresenceManager.IDENTITY).get_full_jids(conversation.counterpart, conversation.account) != null;
|
|
||||||
bool greyscale = !self_online || !counterpart_online;
|
|
||||||
|
|
||||||
Pixbuf pixbuf = ((new AvatarGenerator(AVATAR_SIZE, AVATAR_SIZE, image.scale_factor))
|
|
||||||
.set_greyscale(greyscale)
|
|
||||||
.draw_conversation(stream_interactor, conversation));
|
|
||||||
Util.image_set_from_scaled_pixbuf(image, pixbuf, image.get_scale_factor());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void update_name_label(string? new_name = null) {
|
protected void update_name_label(string? new_name = null) {
|
||||||
name_label.label = Util.get_conversation_display_name(stream_interactor, conversation);
|
name_label.label = Util.get_conversation_display_name(stream_interactor, conversation);
|
||||||
}
|
}
|
||||||
|
@ -91,7 +75,7 @@ public abstract class ConversationRow : ListBoxRow {
|
||||||
protected virtual void update_message_label() {
|
protected virtual void update_message_label() {
|
||||||
if (last_message != null) {
|
if (last_message != null) {
|
||||||
message_label.visible = true;
|
message_label.visible = true;
|
||||||
message_label.label = last_message.body.replace("\n", " ");
|
message_label.label = (new Regex("\\s+")).replace_literal(last_message.body, -1, 0, " ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace Dino.Ui.ConversationSummary {
|
||||||
|
|
||||||
public class ConversationItemSkeleton : Box {
|
public class ConversationItemSkeleton : Box {
|
||||||
|
|
||||||
private Image image = new Image() { margin_top=2, valign=Align.START, visible=true };
|
private AvatarImage image = new AvatarImage() { margin_top=2, valign=Align.START, visible=true, allow_gray = false };
|
||||||
|
|
||||||
public StreamInteractor stream_interactor;
|
public StreamInteractor stream_interactor;
|
||||||
public Conversation conversation { get; set; }
|
public Conversation conversation { get; set; }
|
||||||
|
@ -24,7 +24,7 @@ public class ConversationItemSkeleton : Box {
|
||||||
this.stream_interactor = stream_interactor;
|
this.stream_interactor = stream_interactor;
|
||||||
|
|
||||||
if (item.requires_avatar) {
|
if (item.requires_avatar) {
|
||||||
Util.image_set_from_scaled_pixbuf(image, (new AvatarGenerator(32, 32, image.scale_factor)).set_greyscale(item.dim).draw_jid(stream_interactor, item.jid, conversation.account));
|
image.set_jid(stream_interactor, item.jid, conversation.account);
|
||||||
}
|
}
|
||||||
if (item.display_time != null) {
|
if (item.display_time != null) {
|
||||||
default_header = new DefaultSkeletonHeader(stream_interactor, conversation, item) { visible=true };
|
default_header = new DefaultSkeletonHeader(stream_interactor, conversation, item) { visible=true };
|
||||||
|
|
|
@ -54,7 +54,7 @@ public class ImageDisplay : Plugins.MetaConversationItem {
|
||||||
if (pixbuf.width > max_scaled_width) {
|
if (pixbuf.width > max_scaled_width) {
|
||||||
pixbuf = pixbuf.scale_simple(max_scaled_width, (int) ((double) max_scaled_width / pixbuf.width * pixbuf.height), Gdk.InterpType.BILINEAR);
|
pixbuf = pixbuf.scale_simple(max_scaled_width, (int) ((double) max_scaled_width / pixbuf.width * pixbuf.height), Gdk.InterpType.BILINEAR);
|
||||||
}
|
}
|
||||||
pixbuf = AvatarGenerator.crop_corners(pixbuf, 3 * image.get_scale_factor());
|
pixbuf = crop_corners(pixbuf, 3 * image.get_scale_factor());
|
||||||
Util.image_set_from_scaled_pixbuf(image, pixbuf);
|
Util.image_set_from_scaled_pixbuf(image, pixbuf);
|
||||||
Util.force_css(image, "* { box-shadow: 0px 0px 2px 0px rgba(0,0,0,0.1); margin: 2px; border-radius: 3px; }");
|
Util.force_css(image, "* { box-shadow: 0px 0px 2px 0px rgba(0,0,0,0.1); margin: 2px; border-radius: 3px; }");
|
||||||
|
|
||||||
|
@ -103,6 +103,21 @@ public class ImageDisplay : Plugins.MetaConversationItem {
|
||||||
return event_box;
|
return event_box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Gdk.Pixbuf crop_corners(Gdk.Pixbuf pixbuf, double radius = 3) {
|
||||||
|
Cairo.Context ctx = new Cairo.Context(new Cairo.ImageSurface(Cairo.Format.ARGB32, pixbuf.width, pixbuf.height));
|
||||||
|
Gdk.cairo_set_source_pixbuf(ctx, pixbuf, 0, 0);
|
||||||
|
double degrees = Math.PI / 180.0;
|
||||||
|
ctx.new_sub_path();
|
||||||
|
ctx.arc(pixbuf.width - radius, radius, radius, -90 * degrees, 0 * degrees);
|
||||||
|
ctx.arc(pixbuf.width - radius, pixbuf.height - radius, radius, 0 * degrees, 90 * degrees);
|
||||||
|
ctx.arc(radius, pixbuf.height - radius, radius, 90 * degrees, 180 * degrees);
|
||||||
|
ctx.arc(radius, radius, radius, 180 * degrees, 270 * degrees);
|
||||||
|
ctx.close_path();
|
||||||
|
ctx.clip();
|
||||||
|
ctx.paint();
|
||||||
|
return Gdk.pixbuf_get_from_surface(ctx.get_target(), 0, 0, pixbuf.width, pixbuf.height);
|
||||||
|
}
|
||||||
|
|
||||||
private void update_info(Label url_label, string? info) {
|
private void update_info(Label url_label, string? info) {
|
||||||
string url = info ?? "";
|
string url = info ?? "";
|
||||||
if (url.has_prefix("https://")) url = url.substring(8);
|
if (url.has_prefix("https://")) url = url.substring(8);
|
||||||
|
|
|
@ -7,7 +7,7 @@ namespace Dino.Ui.ManageAccounts {
|
||||||
[GtkTemplate (ui = "/im/dino/Dino/manage_accounts/account_row.ui")]
|
[GtkTemplate (ui = "/im/dino/Dino/manage_accounts/account_row.ui")]
|
||||||
public class AccountRow : Gtk.ListBoxRow {
|
public class AccountRow : Gtk.ListBoxRow {
|
||||||
|
|
||||||
[GtkChild] public Image image;
|
[GtkChild] public AvatarImage image;
|
||||||
[GtkChild] public Label jid_label;
|
[GtkChild] public Label jid_label;
|
||||||
[GtkChild] public Image icon;
|
[GtkChild] public Image icon;
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ public class AccountRow : Gtk.ListBoxRow {
|
||||||
public AccountRow(StreamInteractor stream_interactor, Account account) {
|
public AccountRow(StreamInteractor stream_interactor, Account account) {
|
||||||
this.stream_interactor = stream_interactor;
|
this.stream_interactor = stream_interactor;
|
||||||
this.account = account;
|
this.account = account;
|
||||||
Util.image_set_from_scaled_pixbuf(image, (new AvatarGenerator(40, 40, image.scale_factor)).draw_account(stream_interactor, account));
|
image.set_jid(stream_interactor, account.bare_jid, account);
|
||||||
jid_label.set_label(account.bare_jid.to_string());
|
jid_label.set_label(account.bare_jid.to_string());
|
||||||
|
|
||||||
stream_interactor.connection_manager.connection_error.connect((account, error) => {
|
stream_interactor.connection_manager.connection_error.connect((account, error) => {
|
||||||
|
|
|
@ -19,7 +19,7 @@ public class Dialog : Gtk.Dialog {
|
||||||
[GtkChild] public Button no_accounts_add;
|
[GtkChild] public Button no_accounts_add;
|
||||||
[GtkChild] public ToolButton add_account_button;
|
[GtkChild] public ToolButton add_account_button;
|
||||||
[GtkChild] public ToolButton remove_account_button;
|
[GtkChild] public ToolButton remove_account_button;
|
||||||
[GtkChild] public Image image;
|
[GtkChild] public AvatarImage image;
|
||||||
[GtkChild] public Button image_button;
|
[GtkChild] public Button image_button;
|
||||||
[GtkChild] public Label jid_label;
|
[GtkChild] public Label jid_label;
|
||||||
[GtkChild] public Label state_label;
|
[GtkChild] public Label state_label;
|
||||||
|
@ -185,14 +185,14 @@ public class Dialog : Gtk.Dialog {
|
||||||
|
|
||||||
private void on_received_avatar(Pixbuf pixbuf, Jid jid, Account account) {
|
private void on_received_avatar(Pixbuf pixbuf, Jid jid, Account account) {
|
||||||
if (selected_account.equals(account) && jid.equals(account.bare_jid)) {
|
if (selected_account.equals(account) && jid.equals(account.bare_jid)) {
|
||||||
Util.image_set_from_scaled_pixbuf(image, (new AvatarGenerator(50, 50, image.scale_factor)).draw_account(stream_interactor, account));
|
image.set_jid(stream_interactor, account.bare_jid, account);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void populate_grid_data(Account account) {
|
private void populate_grid_data(Account account) {
|
||||||
active_switch.state_set.disconnect(change_account_state);
|
active_switch.state_set.disconnect(change_account_state);
|
||||||
|
|
||||||
Util.image_set_from_scaled_pixbuf(image, (new AvatarGenerator(50, 50, image.scale_factor)).draw_account(stream_interactor, account));
|
image.set_jid(stream_interactor, account.bare_jid, account);
|
||||||
active_switch.set_active(account.enabled);
|
active_switch.set_active(account.enabled);
|
||||||
jid_label.label = account.bare_jid.to_string();
|
jid_label.label = account.bare_jid.to_string();
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,8 @@ public class Notifications : Object {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Icon get_pixbuf_icon(Gdk.Pixbuf avatar) throws Error {
|
private Icon get_pixbuf_icon(Cairo.ImageSurface surface) throws Error {
|
||||||
|
Gdk.Pixbuf avatar = Gdk.pixbuf_get_from_surface(surface, 0, 0, surface.get_width(), surface.get_height());
|
||||||
uint8[] buffer;
|
uint8[] buffer;
|
||||||
avatar.save_to_buffer(out buffer, "png");
|
avatar.save_to_buffer(out buffer, "png");
|
||||||
return new BytesIcon(new Bytes(buffer));
|
return new BytesIcon(new Bytes(buffer));
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace Dino.Ui.OccupantMenu {
|
||||||
[GtkTemplate (ui = "/im/dino/Dino/occupant_list_item.ui")]
|
[GtkTemplate (ui = "/im/dino/Dino/occupant_list_item.ui")]
|
||||||
public class ListRow : ListBoxRow {
|
public class ListRow : ListBoxRow {
|
||||||
|
|
||||||
[GtkChild] private Image image;
|
[GtkChild] private AvatarImage image;
|
||||||
[GtkChild] public Label name_label;
|
[GtkChild] public Label name_label;
|
||||||
|
|
||||||
public Account? account;
|
public Account? account;
|
||||||
|
@ -19,12 +19,12 @@ public class ListRow : ListBoxRow {
|
||||||
this.jid = jid;
|
this.jid = jid;
|
||||||
|
|
||||||
name_label.label = Util.get_display_name(stream_interactor, jid, account);
|
name_label.label = Util.get_display_name(stream_interactor, jid, account);
|
||||||
Util.image_set_from_scaled_pixbuf(image, (new AvatarGenerator(30, 30, image.scale_factor)).draw_jid(stream_interactor, jid, account));
|
image.set_jid(stream_interactor, jid, account);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ListRow.label(string c, string text) {
|
public ListRow.label(string c, string text) {
|
||||||
name_label.label = text;
|
name_label.label = text;
|
||||||
image.set_from_pixbuf((new AvatarGenerator(30, 30, 1)).set_greyscale(true).draw_text(c)); // why 1
|
image.set_text(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue