avatar.rs 4.98 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
        });
    }
}
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188


pub enum AdminColor {
    Gold,
    Silver,
}


pub fn admin_badge(kind: AdminColor, size: Option<i32>) -> gtk::DrawingArea {
    let s = size.unwrap_or(10);

    let da = DrawingArea::new();
    da.set_size_request(s, s);

    let color = match kind {
        AdminColor::Gold => (237.0, 212.0, 0.0),
        AdminColor::Silver => (186.0, 186.0, 186.0),
    };

    let border = match kind {
        AdminColor::Gold => (107.0, 114.0, 0.0),
        AdminColor::Silver => (137.0, 137.0, 137.0),
    };

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

        let width = s as f64;
        let height = s as f64;

        let context = da.get_style_context().unwrap();
        gtk::render_background(&context, g, 0.0, 0.0, width, height);

        g.set_source_rgba(color.0 / 256.0, color.1 / 256.0, color.2 / 256.0, 1.);
        g.arc(width / 2.0, height / 2.0, width.min(height) / 2.5, 0.0, 2.0 * PI);
        g.fill();

        g.set_source_rgba(border.0 / 256.0, border.1 / 256.0, border.2 / 256.0, 0.5);
        g.arc(width / 2.0, height / 2.0, width.min(height) / 2.5, 0.0, 2.0 * PI);
        g.stroke();

        Inhibit(false)
    });

    da
}