avatar.rs 3.79 KB
Newer Older
1 2 3
extern crate gtk;
extern crate gdk;
extern crate gdk_pixbuf;
4
extern crate cairo;
5 6 7 8

use self::gtk::prelude::*;
pub use self::gtk::DrawingArea;
use self::gdk_pixbuf::Pixbuf;
9
use self::gdk_pixbuf::PixbufExt;
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
use self::gdk::ContextExt;


pub type Avatar = gtk::Box;

pub trait AvatarExt {
    fn avatar_new(size: Option<i32>) -> gtk::Box;
    fn circle_avatar(path: String, size: Option<i32>) -> gtk::Box;
    fn clean(&self);
    fn create_da(&self, size: Option<i32>) -> DrawingArea;

    fn circle(&self, path: String, size: Option<i32>);
    fn default(&self, icon: String, size: Option<i32>);
}

impl AvatarExt for gtk::Box {
    fn clean(&self) {
        for ch in self.get_children().iter() {
            self.remove(ch);
        }
    }

    fn create_da(&self, size: Option<i32>) -> DrawingArea {
        let da = DrawingArea::new();
34

35 36 37 38 39 40 41 42 43 44 45 46
        let s = size.unwrap_or(40);
        da.set_size_request(s, s);
        self.pack_start(&da, true, true, 0);
        self.show_all();

        da
    }

    fn avatar_new(size: Option<i32>) -> gtk::Box {
        let b = gtk::Box::new(gtk::Orientation::Horizontal, 0);
        b.create_da(size);
        b.show_all();
47 48 49
        if let Some(style) = b.get_style_context() {
            style.add_class("avatar");
        }
50 51 52 53 54 55 56 57 58

        b
    }

    fn circle_avatar(path: String, size: Option<i32>) -> gtk::Box {
        let b = gtk::Box::new(gtk::Orientation::Horizontal, 0);
        b.create_da(size);
        b.circle(path, size);
        b.show_all();
59 60 61
        if let Some(style) = b.get_style_context() {
            style.add_class("avatar");
        }
62 63 64 65 66 67 68

        b
    }

    fn default(&self, icon: String, size: Option<i32>) {
        self.clean();
        let da = self.create_da(size);
69
        let s = size.unwrap_or(40);
70

71 72 73 74 75 76 77 78
        let pixbuf = match gtk::IconTheme::get_default() {
            None => None,
            Some(i1) => match i1.load_icon(&icon[..], s, gtk::IconLookupFlags::empty()) {
                Err(_) => None,
                Ok(i2) => i2,
            }
        };

79 80 81
        da.connect_draw(move |da, g| {
            use std::f64::consts::PI;

82 83
            let width = s as f64;
            let height = s as f64;
84 85 86 87 88

            let context = da.get_style_context().unwrap();

            gtk::render_background(&context, g, 0.0, 0.0, width, height);

89 90
            if let Some(ref pb) = pixbuf {
                let hpos: f64 = (width - (pb.get_height()) as f64) / 2.0;
91

92 93
                g.arc(width / 2.0, height / 2.0, width.min(height) / 2.5, 0.0, 2.0 * PI);
                g.clip();
94

95 96 97 98
                g.set_source_pixbuf(&pb, 0.0, hpos);
                g.rectangle(0.0, 0.0, width, height);
                g.fill();
            }
99

100
            Inhibit(false)
101 102 103 104
        });
    }

    fn circle(&self, path: String, size: Option<i32>) {
105 106 107 108 109
        if path.starts_with("mxc:") {
            self.default(String::from("image-loading-symbolic"), size);
            return;
        }

110 111
        self.clean();
        let da = self.create_da(size);
112
        let s = size.unwrap_or(40);
113

114 115
        let pixbuf = Pixbuf::new_from_file_at_scale(&path, s, -1, true);

116 117
        da.connect_draw(move |da, g| {
            use std::f64::consts::PI;
118
            g.set_antialias(cairo::Antialias::Best);
119

120 121
            let width = s as f64;
            let height = s as f64;
122 123 124 125 126

            let context = da.get_style_context().unwrap();

            gtk::render_background(&context, g, 0.0, 0.0, width, height);

127
            if let Ok(ref pb) = pixbuf {
128
                let hpos: f64 = (width - (pb.get_height()) as f64) / 2.0;
129

130 131
                g.arc(width / 2.0, height / 2.0, width.min(height) / 2.0, 0.0, 2.0 * PI);
                g.clip();
132

133 134 135 136
                g.set_source_pixbuf(&pb, 0.0, hpos);
                g.rectangle(0.0, 0.0, width, height);
                g.fill();
            }
137

138
            Inhibit(false)
139 140 141
        });
    }
}