use std::hash::Hasher;
use djb_hash::{x33a_u32::X33aU32, HasherU32};
use gtk::{gdk, graphene, gsk, pango, prelude::*};
const NOTIFICATION_ICON_SIZE: i32 = 48;
const AVATAR_COLOR_LIST: [(&str, &str, &str); 14] = [
("#cfe1f5", "#83b6ec", "#337fdc"), ("#caeaf2", "#7ad9f1", "#0f9ac8"), ("#cef8d8", "#8de6b1", "#29ae74"), ("#e6f9d7", "#b5e98a", "#6ab85b"), ("#f9f4e1", "#f8e359", "#d29d09"), ("#ffead1", "#ffcb62", "#d68400"), ("#ffe5c5", "#ffa95a", "#ed5b00"), ("#f8d2ce", "#f78773", "#e62d42"), ("#fac7de", "#e973ab", "#e33b6a"), ("#e7c2e8", "#cb78d4", "#9945b5"), ("#d5d2f5", "#9e91e8", "#7a59ca"), ("#f2eade", "#e3cf9c", "#b08952"), ("#e5d6ca", "#be916d", "#785336"), ("#d8d7d3", "#c0bfbc", "#6e6d71"), ];
pub(crate) fn paintable_as_notification_icon(
paintable: &gdk::Paintable,
scale_factor: i32,
renderer: &gsk::Renderer,
) -> gdk::Texture {
let img_width = f64::from(paintable.intrinsic_width());
let img_height = f64::from(paintable.intrinsic_height());
let mut icon_size = f64::from(NOTIFICATION_ICON_SIZE * scale_factor);
let mut snap_width = img_width;
let mut snap_height = img_height;
let mut x_pos = 0.0;
let mut y_pos = 0.0;
if img_width > img_height {
if img_height > icon_size {
snap_height = icon_size;
snap_width = img_width * icon_size / img_height;
} else {
icon_size = img_height;
}
if snap_width > icon_size {
x_pos = ((snap_width - icon_size) / 2.0) as f32;
}
} else {
if img_width > icon_size {
snap_width = icon_size;
snap_height = img_height * icon_size / img_width;
} else {
icon_size = img_width;
}
if snap_height > icon_size {
y_pos = ((snap_height - icon_size) / 2.0) as f32;
}
}
let icon_size = icon_size as f32;
let snapshot = gtk::Snapshot::new();
let bounds = gsk::RoundedRect::from_rect(
graphene::Rect::new(x_pos, y_pos, icon_size, icon_size),
icon_size / 2.0,
);
snapshot.push_rounded_clip(&bounds);
paintable.snapshot(&snapshot, snap_width, snap_height);
snapshot.pop();
let node = snapshot.to_node().unwrap();
renderer.render_texture(node, None)
}
pub(crate) fn string_as_notification_icon(
string: &str,
scale_factor: i32,
layout: &pango::Layout,
renderer: &gsk::Renderer,
) -> gdk::Texture {
let mut hasher = X33aU32::new();
hasher.write(string.as_bytes());
let color_nb = hasher.finish_u32() as usize % AVATAR_COLOR_LIST.len();
let colors = AVATAR_COLOR_LIST[color_nb];
let icon_size = (NOTIFICATION_ICON_SIZE * scale_factor) as f32;
let snapshot = gtk::Snapshot::new();
let bounds = gsk::RoundedRect::from_rect(
graphene::Rect::new(0.0, 0.0, icon_size, icon_size),
icon_size / 2.0,
);
snapshot.push_rounded_clip(&bounds);
snapshot.append_linear_gradient(
&graphene::Rect::new(0.0, 0.0, icon_size, icon_size),
&graphene::Point::new(0.0, 0.0),
&graphene::Point::new(0.0, icon_size),
&[
gsk::ColorStop::new(0.0, gdk::RGBA::parse(colors.1).unwrap()),
gsk::ColorStop::new(1.0, gdk::RGBA::parse(colors.2).unwrap()),
],
);
snapshot.pop();
let initials = string
.split(char::is_whitespace)
.filter_map(|s| s.chars().next())
.collect::<String>();
layout.set_text(&initials);
if let Some(mut font_description) = layout
.font_description()
.or_else(|| layout.context().font_description())
{
font_description.set_weight(pango::Weight::Bold);
font_description.set_size(18 * scale_factor * pango::SCALE);
layout.set_font_description(Some(&font_description));
}
layout.set_width(icon_size as i32 * pango::SCALE);
layout.set_alignment(pango::Alignment::Center);
let (_, lay_height) = layout.pixel_size();
let lay_baseline = layout.baseline() / pango::SCALE;
let lay_padding = lay_height - lay_baseline;
let pos_y = (icon_size - lay_height as f32 - lay_padding as f32) / 2.0;
snapshot.translate(&graphene::Point::new(0.0, pos_y));
snapshot.append_layout(layout, &gdk::RGBA::parse(colors.0).unwrap());
let node = snapshot.to_node().unwrap();
renderer.render_texture(node, None)
}