<commit_before>use gdk;
use glib::object::Cast;
use gtk::{self, BoxExt, ContainerExt};
use gtk::{ToggleButtonExt, Widget, WindowExt};
use gtk::prelude::{Inhibit, WidgetExt};
use sysinfo;

use std::cell::RefCell;
use std::iter;
use std::rc::Rc;

use graph::Graph;
use notebook::NoteBook;
use utils::RotateVec;

macro_rules! clone {
    (@param _) => ( _ );
    (@param $x:ident) => ( $x );
    ($($n:ident),+ => move || $body:expr) => (
        {
            $( let $n = $n.clone(); )+
            move || $body
        }
    );
    ($($n:ident),+ => move |$($p:tt),+| $body:expr) => (
        {
            $( let $n = $n.clone(); )+
            move |$(clone!(@param $p),)+| $body
        }
    );
}

fn create_header(label_text: &str, parent_layout: &gtk::Box) -> gtk::CheckButton {
    let check_box = gtk::CheckButton::new_with_label("Graph view");
    let label = gtk::Label::new(Some(label_text));
    let empty = gtk::Label::new(None);
    let grid = gtk::Grid::new();
    let horizontal_layout = gtk::Box::new(gtk::Orientation::Horizontal, 0);
    horizontal_layout.pack_start(&gtk::Label::new(None), true, true, 0);
    horizontal_layout.pack_start(&check_box, false, false, 0);
    grid.attach(&empty, 0, 0, 3, 1);
    grid.attach_next_to(&label, Some(&empty), gtk::PositionType::Right, 3, 1);
    grid.attach_next_to(&horizontal_layout, Some(&label),
                        gtk::PositionType::Right, 3, 1);
    grid.set_column_homogeneous(true);
    parent_layout.pack_start(&grid, false, false, 15);
    check_box
}

fn create_progress_bar(non_graph_layout: &gtk::Grid, line: i32, label: &str,
                       text: &str) -> gtk::ProgressBar {
    let p = gtk::ProgressBar::new();
    let l = gtk::Label::new(Some(label));

    p.set_text(Some(text));
    p.set_show_text(true);
    non_graph_layout.attach(&l, 0, line, 1, 1);
    non_graph_layout.attach(&p, 1, line, 11, 1);
    p
}

#[allow(dead_code)]
pub struct DisplaySysInfo {
    procs: Rc<RefCell<Vec<gtk::ProgressBar>>>,
    ram: gtk::ProgressBar,
    swap: gtk::ProgressBar,
    vertical_layout: gtk::Box,
    components: Vec<gtk::Label>,
    cpu_usage_history: Rc<RefCell<Graph>>,
    // 0 = RAM
    // 1 = SWAP
    ram_usage_history: Rc<RefCell<Graph>>,
    temperature_usage_history: Rc<RefCell<Graph>>,
    pub ram_check_box: gtk::CheckButton,
    pub swap_check_box: gtk::CheckButton,
    pub temperature_check_box: Option<gtk::CheckButton>,
}

impl DisplaySysInfo {
    pub fn new(sys1: Rc<RefCell<sysinfo::System>>, note: &mut NoteBook,
               win: &gtk::Window) -> DisplaySysInfo {
        let vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0);
        let mut procs = Vec::new();
        let scroll = gtk::ScrolledWindow::new(None, None);
        let mut components = vec!();
        let mut cpu_usage_history = Graph::new();
        let mut ram_usage_history = Graph::new();
        let mut temperature_usage_history = Graph::new();
        let mut check_box3 = None;

        vertical_layout.set_spacing(5);

        let non_graph_layout = gtk::Grid::new();
        non_graph_layout.set_column_homogeneous(true);
        non_graph_layout.set_margin_right(5);
        let non_graph_layout2 = gtk::Grid::new();
        non_graph_layout2.set_column_homogeneous(true);
        non_graph_layout2.set_margin_right(5);
        let non_graph_layout3 = gtk::Box::new(gtk::Orientation::Vertical, 0);

        vertical_layout.pack_start(&gtk::Label::new(Some("Total CPU usage")), false, false, 7);
        procs.push(gtk::ProgressBar::new());
        {
            let p: &gtk::ProgressBar = &procs[0];
            let s = sys1.borrow();
            let pro = &s.get_processor_list()[0];

            p.set_margin_right(5);
            p.set_margin_left(5);
            p.set_text(Some(&format!("{:.2} %", pro.get_cpu_usage() * 100.)));
            p.set_show_text(true);
            p.set_fraction(pro.get_cpu_usage() as f64);
            vertical_layout.add(p);
        }

        let check_box = create_header("Process usage", &vertical_layout);
        for (i, pro) in sys1.borrow().get_processor_list().iter().skip(1).enumerate() {
            let i = i + 1;
            procs.push(gtk::ProgressBar::new());
            let p: &gtk::ProgressBar = &procs[i];
            let l = gtk::Label::new(Some(&format!("{}", i)));

            p.set_text(Some(&format!("{:.2} %", pro.get_cpu_usage() * 100.)));
            p.set_show_text(true);
            p.set_fraction(pro.get_cpu_usage() as f64);
            non_graph_layout.attach(&l, 0, i as i32 - 1, 1, 1);
            non_graph_layout.attach(p, 1, i as i32 - 1, 11, 1);
            cpu_usage_history.push(RotateVec::new(iter::repeat(0f64).take(61).collect()),
                                   &format!("process {}", i), None);
        }
        vertical_layout.add(&non_graph_layout);
        cpu_usage_history.attach_to(&vertical_layout);

        let check_box2 = create_header("Memory usage", &vertical_layout);
        let ram = create_progress_bar(&non_graph_layout2, 0, "RAM", "");
        let swap = create_progress_bar(&non_graph_layout2, 1, "Swap", "");
        vertical_layout.pack_start(&non_graph_layout2, false, false, 15);
        //vertical_layout.add(&non_graph_layout2);
        ram_usage_history.push(RotateVec::new(iter::repeat(0f64).take(61).collect()),
                               "RAM", Some(4));
        ram_usage_history.push(RotateVec::new(iter::repeat(0f64).take(61).collect()),
                               "Swap", Some(2));
        ram_usage_history.attach_to(&vertical_layout);

        if sys1.borrow().get_components_list().len() > 0 {
            check_box3 = Some(create_header("Components' temperature", &vertical_layout));
            for component in sys1.borrow().get_components_list() {
                let horizontal_layout = gtk::Box::new(gtk::Orientation::Horizontal, 10);
                // TODO: add max and critical temperatures as well
                let temp = gtk::Label::new(Some(&format!("{:.1} °C", component.temperature)));
                horizontal_layout.pack_start(&gtk::Label::new(Some(&component.label)),
                                             true, false, 0);
                horizontal_layout.pack_start(&temp, true, false, 0);
                horizontal_layout.set_homogeneous(true);
                non_graph_layout3.add(&horizontal_layout);
                components.push(temp);
                temperature_usage_history.push(RotateVec::new(iter::repeat(0f64).take(61).collect()),
                                               &component.label, None);
            }
            vertical_layout.add(&non_graph_layout3);
            temperature_usage_history.attach_to(&vertical_layout);
        }

        let area = cpu_usage_history.area.clone();
        let area2 = ram_usage_history.area.clone();
        let area3 = temperature_usage_history.area.clone();
        let cpu_usage_history = connect_graph(cpu_usage_history);
        let ram_usage_history = connect_graph(ram_usage_history);
        let temperature_usage_history = connect_graph(temperature_usage_history);

        scroll.add(&vertical_layout);
        let scroll : Widget = scroll.upcast();
        note.create_tab("System usage", &scroll);

        let mut tmp = DisplaySysInfo {
            procs: Rc::new(RefCell::new(procs)),
            ram: ram.clone(),
            swap: swap.clone(),
            vertical_layout: vertical_layout,
            components: components,
            cpu_usage_history: cpu_usage_history.clone(),
            ram_usage_history: ram_usage_history.clone(),
            ram_check_box: check_box.clone(),
            swap_check_box: check_box2.clone(),
            temperature_usage_history: temperature_usage_history.clone(),
            temperature_check_box: check_box3.clone(),
        };
        tmp.update_ram_display(&sys1.borrow(), false);

        win.add_events(gdk::EventType::Configure as i32);
        // ugly way to resize drawing area, I should find a better way
        win.connect_configure_event(move |w, _| {
            let w = w.clone().upcast::<gtk::Window>().get_size().0 - 130;
            area.set_size_request(w, 200);
            area2.set_size_request(w, 200);
            area3.set_size_request(w, 200);
            false
        });

        check_box.clone().upcast::<gtk::ToggleButton>()
                 .connect_toggled(clone!(non_graph_layout, cpu_usage_history => move |c| {
            show_if_necessary(c, &cpu_usage_history.borrow(), &non_graph_layout);
        }));
        check_box2.clone().upcast::<gtk::ToggleButton>()
                  .connect_toggled(clone!(non_graph_layout2, ram_usage_history => move |c| {
            show_if_necessary(c, &ram_usage_history.borrow(), &non_graph_layout2);
        }));
        if let Some(ref check_box3) = check_box3 {
            check_box3.clone().upcast::<gtk::ToggleButton>()
                 .connect_toggled(clone!(non_graph_layout3, temperature_usage_history => move |c| {
                show_if_necessary(c, &temperature_usage_history.borrow(), &non_graph_layout3);
            }));
        }

        scroll.connect_show(clone!(cpu_usage_history, ram_usage_history => move |_| {
            show_if_necessary(&check_box.clone().upcast::<gtk::ToggleButton>(),
                              &cpu_usage_history.borrow(), &non_graph_layout);
            show_if_necessary(&check_box2.clone().upcast::<gtk::ToggleButton>(),
                              &ram_usage_history.borrow(), &non_graph_layout2);
            if let Some(ref check_box3) = check_box3 {
                show_if_necessary(&check_box3.clone().upcast::<gtk::ToggleButton>(),
                                  &temperature_usage_history.borrow(), &non_graph_layout3);
            }
        }));
        tmp
    }

    pub fn update_ram_display(&mut self, sys: &sysinfo::System, display_fahrenheit: bool) {
        let total = sys.get_total_memory();
        let used = sys.get_used_memory();
        let disp = if total < 100000 {
            format!("{} / {} kB", used, total)
        } else if total < 10000000 {
            format!("{} / {} MB", used / 1024, total / 1024)
        } else if total < 10000000000 {
            format!("{} / {} GB", used / 1048576, total / 1048576)
        } else {
            format!("{} / {} TB", used / 1073741824, total / 1073741824)
        };

        self.ram.set_text(Some(&disp));
        self.ram.set_fraction(used as f64 / total as f64);
        {
            let mut r = self.ram_usage_history.borrow_mut();
            r.data[0].move_start();
            *r.data[0].get_mut(0).unwrap() = used as f64 / total as f64;
        }

        let total = sys.get_total_swap();
        let used = sys.get_used_swap();
        let disp = if total < 100000 {
            format!("{} / {} kB", used, total)
        } else if total < 10000000 {
            format!("{} / {} MB", used / 1024, total / 1024)
        } else if total < 10000000000 {
            format!("{} / {} GB", used / 1048576, total / 1048576)
        } else {
            format!("{} / {} TB", used / 1073741824, total / 1073741824)
        };

        self.swap.set_text(Some(&disp));

        let mut fraction = used as f64 / total as f64;
        if fraction.is_nan() {
            fraction = 0 as f64;
        }
        self.swap.set_fraction(fraction);
        {
            let mut r = self.ram_usage_history.borrow_mut();
            r.data[1].move_start();
            *r.data[1].get_mut(0).unwrap() = used as f64 / total as f64;
        }

        let mut t = self.temperature_usage_history.borrow_mut();
        for (pos, (component, label)) in sys.get_components_list()
                                            .iter().zip(self.components.iter()).enumerate() {
            t.data[pos].move_start();
            if let Some(critical) = component.critical {
                *t.data[pos].get_mut(0).unwrap() = component.temperature as f64 / critical as f64;
            } else {
                *t.data[pos].get_mut(0).unwrap() = component.temperature as f64 / component.max as f64;
            }
            if display_fahrenheit {
                label.set_text(&format!("{:.1} °F", component.temperature * 1.8 + 32.));
            } else {
                label.set_text(&format!("{:.1} °C", component.temperature));
            }
        }
    }

    pub fn update_process_display(&mut self, sys: &sysinfo::System) {
        let v = &*self.procs.borrow_mut();
        let mut h = &mut *self.cpu_usage_history.borrow_mut();

        for (i, pro) in sys.get_processor_list().iter().enumerate() {
            v[i].set_text(Some(&format!("{:.1} %", pro.get_cpu_usage() * 100.)));
            v[i].set_show_text(true);
            v[i].set_fraction(pro.get_cpu_usage() as f64);
            if i > 0 {
                h.data[i - 1].move_start();
                *h.data[i - 1].get_mut(0).unwrap() = pro.get_cpu_usage() as f64;
            }
        }
        h.invalidate();
        self.ram_usage_history.borrow().invalidate();
        self.temperature_usage_history.borrow().invalidate();
    }
}

fn connect_graph(graph: Graph) -> Rc<RefCell<Graph>> {
    let area = graph.area.clone();
    let graph = Rc::new(RefCell::new(graph));
    let c_graph = graph.clone();
    area.connect_draw(move |w, c| {
        let graph = c_graph.borrow();
        graph.draw(&c,
                   w.get_allocated_width() as f64,
                   w.get_allocated_height() as f64);
        Inhibit(false)
    });
    graph
}

fn show_if_necessary<T: WidgetExt>(check_box: &gtk::ToggleButton, proc_horizontal_layout: &Graph,
                                   non_graph_layout: &T) {
    if check_box.get_active() {
        proc_horizontal_layout.show_all();
        non_graph_layout.hide();
    } else {
        non_graph_layout.show_all();
        proc_horizontal_layout.hide();
    }
}
<commit_msg>Use same computation for memory and swap string<commit_after>use gdk;
use glib::object::Cast;
use gtk::{self, BoxExt, ContainerExt};
use gtk::{ToggleButtonExt, Widget, WindowExt};
use gtk::prelude::{Inhibit, WidgetExt};
use sysinfo;

use std::cell::RefCell;
use std::iter;
use std::rc::Rc;

use graph::Graph;
use notebook::NoteBook;
use utils::RotateVec;

macro_rules! clone {
    (@param _) => ( _ );
    (@param $x:ident) => ( $x );
    ($($n:ident),+ => move || $body:expr) => (
        {
            $( let $n = $n.clone(); )+
            move || $body
        }
    );
    ($($n:ident),+ => move |$($p:tt),+| $body:expr) => (
        {
            $( let $n = $n.clone(); )+
            move |$(clone!(@param $p),)+| $body
        }
    );
}

fn create_header(label_text: &str, parent_layout: &gtk::Box) -> gtk::CheckButton {
    let check_box = gtk::CheckButton::new_with_label("Graph view");
    let label = gtk::Label::new(Some(label_text));
    let empty = gtk::Label::new(None);
    let grid = gtk::Grid::new();
    let horizontal_layout = gtk::Box::new(gtk::Orientation::Horizontal, 0);
    horizontal_layout.pack_start(&gtk::Label::new(None), true, true, 0);
    horizontal_layout.pack_start(&check_box, false, false, 0);
    grid.attach(&empty, 0, 0, 3, 1);
    grid.attach_next_to(&label, Some(&empty), gtk::PositionType::Right, 3, 1);
    grid.attach_next_to(&horizontal_layout, Some(&label),
                        gtk::PositionType::Right, 3, 1);
    grid.set_column_homogeneous(true);
    parent_layout.pack_start(&grid, false, false, 15);
    check_box
}

fn create_progress_bar(non_graph_layout: &gtk::Grid, line: i32, label: &str,
                       text: &str) -> gtk::ProgressBar {
    let p = gtk::ProgressBar::new();
    let l = gtk::Label::new(Some(label));

    p.set_text(Some(text));
    p.set_show_text(true);
    non_graph_layout.attach(&l, 0, line, 1, 1);
    non_graph_layout.attach(&p, 1, line, 11, 1);
    p
}

#[allow(dead_code)]
pub struct DisplaySysInfo {
    procs: Rc<RefCell<Vec<gtk::ProgressBar>>>,
    ram: gtk::ProgressBar,
    swap: gtk::ProgressBar,
    vertical_layout: gtk::Box,
    components: Vec<gtk::Label>,
    cpu_usage_history: Rc<RefCell<Graph>>,
    // 0 = RAM
    // 1 = SWAP
    ram_usage_history: Rc<RefCell<Graph>>,
    temperature_usage_history: Rc<RefCell<Graph>>,
    pub ram_check_box: gtk::CheckButton,
    pub swap_check_box: gtk::CheckButton,
    pub temperature_check_box: Option<gtk::CheckButton>,
}

impl DisplaySysInfo {
    pub fn new(sys1: Rc<RefCell<sysinfo::System>>, note: &mut NoteBook,
               win: &gtk::Window) -> DisplaySysInfo {
        let vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0);
        let mut procs = Vec::new();
        let scroll = gtk::ScrolledWindow::new(None, None);
        let mut components = vec!();
        let mut cpu_usage_history = Graph::new();
        let mut ram_usage_history = Graph::new();
        let mut temperature_usage_history = Graph::new();
        let mut check_box3 = None;

        vertical_layout.set_spacing(5);

        let non_graph_layout = gtk::Grid::new();
        non_graph_layout.set_column_homogeneous(true);
        non_graph_layout.set_margin_right(5);
        let non_graph_layout2 = gtk::Grid::new();
        non_graph_layout2.set_column_homogeneous(true);
        non_graph_layout2.set_margin_right(5);
        let non_graph_layout3 = gtk::Box::new(gtk::Orientation::Vertical, 0);

        vertical_layout.pack_start(&gtk::Label::new(Some("Total CPU usage")), false, false, 7);
        procs.push(gtk::ProgressBar::new());
        {
            let p: &gtk::ProgressBar = &procs[0];
            let s = sys1.borrow();
            let pro = &s.get_processor_list()[0];

            p.set_margin_right(5);
            p.set_margin_left(5);
            p.set_text(Some(&format!("{:.2} %", pro.get_cpu_usage() * 100.)));
            p.set_show_text(true);
            p.set_fraction(pro.get_cpu_usage() as f64);
            vertical_layout.add(p);
        }

        let check_box = create_header("Process usage", &vertical_layout);
        for (i, pro) in sys1.borrow().get_processor_list().iter().skip(1).enumerate() {
            let i = i + 1;
            procs.push(gtk::ProgressBar::new());
            let p: &gtk::ProgressBar = &procs[i];
            let l = gtk::Label::new(Some(&format!("{}", i)));

            p.set_text(Some(&format!("{:.2} %", pro.get_cpu_usage() * 100.)));
            p.set_show_text(true);
            p.set_fraction(pro.get_cpu_usage() as f64);
            non_graph_layout.attach(&l, 0, i as i32 - 1, 1, 1);
            non_graph_layout.attach(p, 1, i as i32 - 1, 11, 1);
            cpu_usage_history.push(RotateVec::new(iter::repeat(0f64).take(61).collect()),
                                   &format!("process {}", i), None);
        }
        vertical_layout.add(&non_graph_layout);
        cpu_usage_history.attach_to(&vertical_layout);

        let check_box2 = create_header("Memory usage", &vertical_layout);
        let ram = create_progress_bar(&non_graph_layout2, 0, "RAM", "");
        let swap = create_progress_bar(&non_graph_layout2, 1, "Swap", "");
        vertical_layout.pack_start(&non_graph_layout2, false, false, 15);
        //vertical_layout.add(&non_graph_layout2);
        ram_usage_history.push(RotateVec::new(iter::repeat(0f64).take(61).collect()),
                               "RAM", Some(4));
        ram_usage_history.push(RotateVec::new(iter::repeat(0f64).take(61).collect()),
                               "Swap", Some(2));
        ram_usage_history.attach_to(&vertical_layout);

        if sys1.borrow().get_components_list().len() > 0 {
            check_box3 = Some(create_header("Components' temperature", &vertical_layout));
            for component in sys1.borrow().get_components_list() {
                let horizontal_layout = gtk::Box::new(gtk::Orientation::Horizontal, 10);
                // TODO: add max and critical temperatures as well
                let temp = gtk::Label::new(Some(&format!("{:.1} °C", component.temperature)));
                horizontal_layout.pack_start(&gtk::Label::new(Some(&component.label)),
                                             true, false, 0);
                horizontal_layout.pack_start(&temp, true, false, 0);
                horizontal_layout.set_homogeneous(true);
                non_graph_layout3.add(&horizontal_layout);
                components.push(temp);
                temperature_usage_history.push(RotateVec::new(iter::repeat(0f64).take(61).collect()),
                                               &component.label, None);
            }
            vertical_layout.add(&non_graph_layout3);
            temperature_usage_history.attach_to(&vertical_layout);
        }

        let area = cpu_usage_history.area.clone();
        let area2 = ram_usage_history.area.clone();
        let area3 = temperature_usage_history.area.clone();
        let cpu_usage_history = connect_graph(cpu_usage_history);
        let ram_usage_history = connect_graph(ram_usage_history);
        let temperature_usage_history = connect_graph(temperature_usage_history);

        scroll.add(&vertical_layout);
        let scroll : Widget = scroll.upcast();
        note.create_tab("System usage", &scroll);

        let mut tmp = DisplaySysInfo {
            procs: Rc::new(RefCell::new(procs)),
            ram: ram.clone(),
            swap: swap.clone(),
            vertical_layout: vertical_layout,
            components: components,
            cpu_usage_history: cpu_usage_history.clone(),
            ram_usage_history: ram_usage_history.clone(),
            ram_check_box: check_box.clone(),
            swap_check_box: check_box2.clone(),
            temperature_usage_history: temperature_usage_history.clone(),
            temperature_check_box: check_box3.clone(),
        };
        tmp.update_ram_display(&sys1.borrow(), false);

        win.add_events(gdk::EventType::Configure as i32);
        // ugly way to resize drawing area, I should find a better way
        win.connect_configure_event(move |w, _| {
            let w = w.clone().upcast::<gtk::Window>().get_size().0 - 130;
            area.set_size_request(w, 200);
            area2.set_size_request(w, 200);
            area3.set_size_request(w, 200);
            false
        });

        check_box.clone().upcast::<gtk::ToggleButton>()
                 .connect_toggled(clone!(non_graph_layout, cpu_usage_history => move |c| {
            show_if_necessary(c, &cpu_usage_history.borrow(), &non_graph_layout);
        }));
        check_box2.clone().upcast::<gtk::ToggleButton>()
                  .connect_toggled(clone!(non_graph_layout2, ram_usage_history => move |c| {
            show_if_necessary(c, &ram_usage_history.borrow(), &non_graph_layout2);
        }));
        if let Some(ref check_box3) = check_box3 {
            check_box3.clone().upcast::<gtk::ToggleButton>()
                 .connect_toggled(clone!(non_graph_layout3, temperature_usage_history => move |c| {
                show_if_necessary(c, &temperature_usage_history.borrow(), &non_graph_layout3);
            }));
        }

        scroll.connect_show(clone!(cpu_usage_history, ram_usage_history => move |_| {
            show_if_necessary(&check_box.clone().upcast::<gtk::ToggleButton>(),
                              &cpu_usage_history.borrow(), &non_graph_layout);
            show_if_necessary(&check_box2.clone().upcast::<gtk::ToggleButton>(),
                              &ram_usage_history.borrow(), &non_graph_layout2);
            if let Some(ref check_box3) = check_box3 {
                show_if_necessary(&check_box3.clone().upcast::<gtk::ToggleButton>(),
                                  &temperature_usage_history.borrow(), &non_graph_layout3);
            }
        }));
        tmp
    }

    pub fn update_ram_display(&mut self, sys: &sysinfo::System, display_fahrenheit: bool) {
        let disp = |total, used| {
            if total < 100000 {
                format!("{} / {} kB", used, total)
            } else if total < 10000000 {
                format!("{} / {} MB", used / 1024, total / 1024)
            } else if total < 10000000000 {
                format!("{} / {} GB", used / 1048576, total / 1048576)
            } else {
                format!("{} / {} TB", used / 1073741824, total / 1073741824)
            }
        };

        let total = sys.get_total_memory();
        let used = sys.get_used_memory();
        self.ram.set_text(Some(&disp(total, used)));
        self.ram.set_fraction(used as f64 / total as f64);
        {
            let mut r = self.ram_usage_history.borrow_mut();
            r.data[0].move_start();
            *r.data[0].get_mut(0).unwrap() = used as f64 / total as f64;
        }

        let total = sys.get_total_swap();
        let used = sys.get_used_swap();
        self.swap.set_text(Some(&disp(total, used)));

        let mut fraction = used as f64 / total as f64;
        if fraction.is_nan() {
            fraction = 0 as f64;
        }
        self.swap.set_fraction(fraction);
        {
            let mut r = self.ram_usage_history.borrow_mut();
            r.data[1].move_start();
            *r.data[1].get_mut(0).unwrap() = used as f64 / total as f64;
        }

        let mut t = self.temperature_usage_history.borrow_mut();
        for (pos, (component, label)) in sys.get_components_list()
                                            .iter().zip(self.components.iter()).enumerate() {
            t.data[pos].move_start();
            if let Some(critical) = component.critical {
                *t.data[pos].get_mut(0).unwrap() = component.temperature as f64 / critical as f64;
            } else {
                *t.data[pos].get_mut(0).unwrap() = component.temperature as f64 / component.max as f64;
            }
            if display_fahrenheit {
                label.set_text(&format!("{:.1} °F", component.temperature * 1.8 + 32.));
            } else {
                label.set_text(&format!("{:.1} °C", component.temperature));
            }
        }
    }

    pub fn update_process_display(&mut self, sys: &sysinfo::System) {
        let v = &*self.procs.borrow_mut();
        let mut h = &mut *self.cpu_usage_history.borrow_mut();

        for (i, pro) in sys.get_processor_list().iter().enumerate() {
            v[i].set_text(Some(&format!("{:.1} %", pro.get_cpu_usage() * 100.)));
            v[i].set_show_text(true);
            v[i].set_fraction(pro.get_cpu_usage() as f64);
            if i > 0 {
                h.data[i - 1].move_start();
                *h.data[i - 1].get_mut(0).unwrap() = pro.get_cpu_usage() as f64;
            }
        }
        h.invalidate();
        self.ram_usage_history.borrow().invalidate();
        self.temperature_usage_history.borrow().invalidate();
    }
}

fn connect_graph(graph: Graph) -> Rc<RefCell<Graph>> {
    let area = graph.area.clone();
    let graph = Rc::new(RefCell::new(graph));
    let c_graph = graph.clone();
    area.connect_draw(move |w, c| {
        let graph = c_graph.borrow();
        graph.draw(&c,
                   w.get_allocated_width() as f64,
                   w.get_allocated_height() as f64);
        Inhibit(false)
    });
    graph
}

fn show_if_necessary<T: WidgetExt>(check_box: &gtk::ToggleButton, proc_horizontal_layout: &Graph,
                                   non_graph_layout: &T) {
    if check_box.get_active() {
        proc_horizontal_layout.show_all();
        non_graph_layout.hide();
    } else {
        non_graph_layout.show_all();
        proc_horizontal_layout.hide();
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::HashMap;
use std::f64;

use crate::bbox::BoundingBox;
use crate::coord_units::CoordUnits;
use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::filter::Filter;
use crate::parsers::CustomIdent;
use crate::properties::ComputedValues;
use crate::rect::{IRect, Rect};
use crate::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};
use crate::transform::Transform;

use super::error::FilterError;
use super::Input;

/// A filter primitive output.
#[derive(Debug, Clone)]
pub struct FilterOutput {
    /// The surface after the filter primitive was applied.
    pub surface: SharedImageSurface,

    /// The filter primitive subregion.
    pub bounds: IRect,
}

/// A filter primitive result.
#[derive(Debug, Clone)]
pub struct FilterResult {
    /// The name of this result: the value of the `result` attribute.
    pub name: Option<CustomIdent>,

    /// The output.
    pub output: FilterOutput,
}

/// An input to a filter primitive.
#[derive(Debug, Clone)]
pub enum FilterInput {
    /// One of the standard inputs.
    StandardInput(SharedImageSurface),
    /// Output of another filter primitive.
    PrimitiveOutput(FilterOutput),
}

/// The filter rendering context.
pub struct FilterContext {
    /// Bounding box of node being filtered
    node_bbox: BoundingBox,
    /// Values from the node which referenced this filter.
    computed_from_node_being_filtered: ComputedValues,
    /// The source graphic surface.
    source_surface: SharedImageSurface,
    /// Output of the last filter primitive.
    last_result: Option<FilterOutput>,
    /// Surfaces of the previous filter primitives by name.
    previous_results: HashMap<CustomIdent, FilterOutput>,
    /// The background surface. Computed lazily.
    background_surface: RefCell<Option<Result<SharedImageSurface, FilterError>>>,
    /// Primtive units
    primitive_units: CoordUnits,
    /// The filter effects region.
    effects_region: BoundingBox,
    /// Whether the currently rendered filter primitive uses linear RGB for color operations.
    ///
    /// This affects `get_input()` and `store_result()` which should perform linearization and
    /// unlinearization respectively when this is set to `true`.
    processing_linear_rgb: bool,

    /// The filter element affine matrix.
    ///
    /// If `filterUnits == userSpaceOnUse`, equal to the drawing context matrix, so, for example,
    /// if the target node is in a group with `transform="translate(30, 20)"`, this will be equal
    /// to a matrix that translates to 30, 20 (and does not scale). Note that the target node
    /// bounding box isn't included in the computations in this case.
    ///
    /// If `filterUnits == objectBoundingBox`, equal to the target node bounding box matrix
    /// multiplied by the drawing context matrix, so, for example, if the target node is in a group
    /// with `transform="translate(30, 20)"` and also has `x="1", y="1", width="50", height="50"`,
    /// this will be equal to a matrix that translates to 31, 21 and scales to 50, 50.
    ///
    /// This is to be used in conjunction with setting the viewbox size to account for the scaling.
    /// For `filterUnits == userSpaceOnUse`, the viewbox will have the actual resolution size, and
    /// for `filterUnits == objectBoundingBox`, the viewbox will have the size of 1, 1.
    _affine: Transform,

    /// The filter primitive affine matrix.
    ///
    /// See the comments for `_affine`, they largely apply here.
    paffine: Transform,
}

impl FilterContext {
    /// Creates a new `FilterContext`.
    pub fn new(
        filter: &Filter,
        computed_from_node_being_filtered: &ComputedValues,
        source_surface: SharedImageSurface,
        draw_ctx: &mut DrawingCtx,
        draw_transform: Transform,
        node_bbox: BoundingBox,
    ) -> Self {
        // The rect can be empty (for example, if the filter is applied to an empty group).
        // However, with userSpaceOnUse it's still possible to create images with a filter.
        let bbox_rect = node_bbox.rect.unwrap_or_default();

        let filter_units = filter.get_filter_units();
        let affine = match filter_units {
            CoordUnits::UserSpaceOnUse => draw_transform,
            CoordUnits::ObjectBoundingBox => Transform::new_unchecked(
                bbox_rect.width(),
                0.0,
                0.0,
                bbox_rect.height(),
                bbox_rect.x0,
                bbox_rect.y0,
            )
            .post_transform(&draw_transform),
        };

        let primitive_units = filter.get_primitive_units();
        let paffine = match primitive_units {
            CoordUnits::UserSpaceOnUse => draw_transform,
            CoordUnits::ObjectBoundingBox => Transform::new_unchecked(
                bbox_rect.width(),
                0.0,
                0.0,
                bbox_rect.height(),
                bbox_rect.x0,
                bbox_rect.y0,
            )
            .post_transform(&draw_transform),
        };

        let effects_region = {
            let params = draw_ctx.push_coord_units(filter_units);
            let filter_rect = filter.get_rect(&computed_from_node_being_filtered, &params);

            let mut bbox = BoundingBox::new();
            let other_bbox = BoundingBox::new()
                .with_transform(affine)
                .with_rect(filter_rect);

            // At this point all of the previous viewbox and matrix business gets converted to pixel
            // coordinates in the final surface, because bbox is created with an identity transform.
            bbox.insert(&other_bbox);

            // Finally, clip to the width and height of our surface.
            let (width, height) = (source_surface.width(), source_surface.height());
            let rect = Rect::from_size(f64::from(width), f64::from(height));
            let other_bbox = BoundingBox::new().with_rect(rect);
            bbox.clip(&other_bbox);

            bbox
        };

        Self {
            node_bbox,
            computed_from_node_being_filtered: computed_from_node_being_filtered.clone(),
            source_surface,
            last_result: None,
            previous_results: HashMap::new(),
            background_surface: RefCell::new(None),
            primitive_units,
            effects_region,
            processing_linear_rgb: false,
            _affine: affine,
            paffine,
        }
    }

    /// Returns the computed values from the node that referenced this filter.
    #[inline]
    pub fn get_computed_values_from_node_being_filtered(&self) -> &ComputedValues {
        &self.computed_from_node_being_filtered
    }

    /// Returns the surface corresponding to the source graphic.
    #[inline]
    pub fn source_graphic(&self) -> &SharedImageSurface {
        &self.source_surface
    }

    /// Returns the surface corresponding to the background image snapshot.
    pub fn background_image(
        &self,
        draw_ctx: &DrawingCtx,
    ) -> Result<SharedImageSurface, FilterError> {
        {
            // At this point either no, or only immutable references to background_surface exist, so
            // it's ok to make an immutable reference.
            let bg = self.background_surface.borrow();

            // If background_surface was already computed, return the immutable reference. It will
            // get bound to the &self lifetime by the function return type.
            if let Some(ref result) = *bg {
                return result.clone();
            }
        }

        // If we got here, then background_surface hasn't been computed yet. This means there are
        // no references to it and we can create a mutable reference.
        let mut bg = self.background_surface.borrow_mut();

        *bg = Some(
            draw_ctx
                .get_snapshot(self.source_surface.width(), self.source_surface.height())
                .map_err(FilterError::CairoError),
        );

        // Return the only existing reference as immutable.
        bg.as_ref()
            .unwrap()
            .as_ref()
            .map(|surf| surf.clone())
            .map_err(|e| e.clone())
    }

    /// Converts this `FilterContext` into the surface corresponding to the output of the filter
    /// chain.
    ///
    /// The returned surface is in the sRGB color space.
    // TODO: sRGB conversion should probably be done by the caller.
    #[inline]
    pub fn into_output(self) -> Result<SharedImageSurface, cairo::Status> {
        match self.last_result {
            Some(FilterOutput { surface, bounds }) => surface.to_srgb(bounds),
            None => SharedImageSurface::empty(
                self.source_surface.width(),
                self.source_surface.height(),
                SurfaceType::AlphaOnly,
            ),
        }
    }

    /// Stores a filter primitive result into the context.
    #[inline]
    pub fn store_result(&mut self, result: FilterResult) -> Result<(), FilterError> {
        if let Some(name) = result.name {
            self.previous_results.insert(name, result.output.clone());
        }

        self.last_result = Some(result.output);
        Ok(())
    }

    /// Returns the paffine matrix.
    #[inline]
    pub fn paffine(&self) -> Transform {
        self.paffine
    }

    /// Returns the primitive units.
    #[inline]
    pub fn primitive_units(&self) -> CoordUnits {
        self.primitive_units
    }

    /// Returns the filter effects region.
    #[inline]
    pub fn effects_region(&self) -> BoundingBox {
        self.effects_region
    }

    pub fn get_computed_from_node_being_filtered(&self) -> &ComputedValues {
        &self.computed_from_node_being_filtered
    }

    /// Retrieves the filter input surface according to the SVG rules.
    ///
    /// Does not take `processing_linear_rgb` into account.
    fn get_input_raw(
        &self,
        acquired_nodes: &mut AcquiredNodes<'_>,
        draw_ctx: &mut DrawingCtx,
        in_: Option<&Input>,
    ) -> Result<FilterInput, FilterError> {
        if in_.is_none() {
            // No value => use the last result.
            // As per the SVG spec, if the filter primitive is the first in the chain, return the
            // source graphic.
            if let Some(output) = self.last_result.as_ref() {
                return Ok(FilterInput::PrimitiveOutput(output.clone()));
            } else {
                return Ok(FilterInput::StandardInput(self.source_graphic().clone()));
            }
        }

        let values = &self.computed_from_node_being_filtered;

        match *in_.unwrap() {
            Input::SourceGraphic => Ok(FilterInput::StandardInput(self.source_graphic().clone())),

            Input::SourceAlpha => self
                .source_graphic()
                .extract_alpha(self.effects_region().rect.unwrap().into())
                .map_err(FilterError::CairoError)
                .map(FilterInput::StandardInput),

            Input::BackgroundImage => self
                .background_image(draw_ctx)
                .map(FilterInput::StandardInput),

            Input::BackgroundAlpha => self
                .background_image(draw_ctx)
                .and_then(|surface| {
                    surface
                        .extract_alpha(self.effects_region().rect.unwrap().into())
                        .map_err(FilterError::CairoError)
                })
                .map(FilterInput::StandardInput),

            Input::FillPaint => draw_ctx
                .get_paint_server_surface(
                    self.source_surface.width(),
                    self.source_surface.height(),
                    acquired_nodes,
                    &values.fill().0,
                    values.fill_opacity().0,
                    &self.node_bbox,
                    self.computed_from_node_being_filtered.color().0,
                    &values,
                )
                .map_err(FilterError::CairoError)
                .map(FilterInput::StandardInput),

            Input::StrokePaint => draw_ctx
                .get_paint_server_surface(
                    self.source_surface.width(),
                    self.source_surface.height(),
                    acquired_nodes,
                    &values.stroke().0,
                    values.stroke_opacity().0,
                    &self.node_bbox,
                    self.computed_from_node_being_filtered.color().0,
                    &values,
                )
                .map_err(FilterError::CairoError)
                .map(FilterInput::StandardInput),

            Input::FilterOutput(ref name) => self
                .previous_results
                .get(name)
                .cloned()
                .map(FilterInput::PrimitiveOutput)
                .ok_or(FilterError::InvalidInput),
        }
    }

    /// Retrieves the filter input surface according to the SVG rules.
    pub fn get_input(
        &self,
        acquired_nodes: &mut AcquiredNodes<'_>,
        draw_ctx: &mut DrawingCtx,
        in_: Option<&Input>,
    ) -> Result<FilterInput, FilterError> {
        let raw = self.get_input_raw(acquired_nodes, draw_ctx, in_)?;

        // Convert the input surface to the desired format.
        let (surface, bounds) = match raw {
            FilterInput::StandardInput(ref surface) => {
                (surface, self.effects_region().rect.unwrap().into())
            }
            FilterInput::PrimitiveOutput(FilterOutput {
                ref surface,
                ref bounds,
            }) => (surface, *bounds),
        };

        let surface = if self.processing_linear_rgb {
            surface.to_linear_rgb(bounds)
        } else {
            surface.to_srgb(bounds)
        };
        surface
            .map_err(FilterError::CairoError)
            .map(|surface| match raw {
                FilterInput::StandardInput(_) => FilterInput::StandardInput(surface),
                FilterInput::PrimitiveOutput(ref output) => {
                    FilterInput::PrimitiveOutput(FilterOutput { surface, ..*output })
                }
            })
    }

    /// Calls the given closure with linear RGB processing enabled.
    #[inline]
    pub fn with_linear_rgb<T, F: FnOnce(&mut FilterContext) -> T>(&mut self, f: F) -> T {
        self.processing_linear_rgb = true;
        let rv = f(self);
        self.processing_linear_rgb = false;
        rv
    }

    /// Applies the `primitiveUnits` coordinate transformation to a non-x or y distance.
    #[inline]
    pub fn transform_dist(&self, d: f64) -> f64 {
        d * (self.paffine.xx.powi(2) + self.paffine.yy.powi(2)).sqrt() / f64::consts::SQRT_2
    }
}

impl FilterInput {
    /// Retrieves the surface from `FilterInput`.
    #[inline]
    pub fn surface(&self) -> &SharedImageSurface {
        match *self {
            FilterInput::StandardInput(ref surface) => surface,
            FilterInput::PrimitiveOutput(FilterOutput { ref surface, .. }) => surface,
        }
    }
}
<commit_msg>filters: remove unused method<commit_after>use std::cell::RefCell;
use std::collections::HashMap;
use std::f64;

use crate::bbox::BoundingBox;
use crate::coord_units::CoordUnits;
use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::filter::Filter;
use crate::parsers::CustomIdent;
use crate::properties::ComputedValues;
use crate::rect::{IRect, Rect};
use crate::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};
use crate::transform::Transform;

use super::error::FilterError;
use super::Input;

/// A filter primitive output.
#[derive(Debug, Clone)]
pub struct FilterOutput {
    /// The surface after the filter primitive was applied.
    pub surface: SharedImageSurface,

    /// The filter primitive subregion.
    pub bounds: IRect,
}

/// A filter primitive result.
#[derive(Debug, Clone)]
pub struct FilterResult {
    /// The name of this result: the value of the `result` attribute.
    pub name: Option<CustomIdent>,

    /// The output.
    pub output: FilterOutput,
}

/// An input to a filter primitive.
#[derive(Debug, Clone)]
pub enum FilterInput {
    /// One of the standard inputs.
    StandardInput(SharedImageSurface),
    /// Output of another filter primitive.
    PrimitiveOutput(FilterOutput),
}

/// The filter rendering context.
pub struct FilterContext {
    /// Bounding box of node being filtered
    node_bbox: BoundingBox,
    /// Values from the node which referenced this filter.
    computed_from_node_being_filtered: ComputedValues,
    /// The source graphic surface.
    source_surface: SharedImageSurface,
    /// Output of the last filter primitive.
    last_result: Option<FilterOutput>,
    /// Surfaces of the previous filter primitives by name.
    previous_results: HashMap<CustomIdent, FilterOutput>,
    /// The background surface. Computed lazily.
    background_surface: RefCell<Option<Result<SharedImageSurface, FilterError>>>,
    /// Primtive units
    primitive_units: CoordUnits,
    /// The filter effects region.
    effects_region: BoundingBox,
    /// Whether the currently rendered filter primitive uses linear RGB for color operations.
    ///
    /// This affects `get_input()` and `store_result()` which should perform linearization and
    /// unlinearization respectively when this is set to `true`.
    processing_linear_rgb: bool,

    /// The filter element affine matrix.
    ///
    /// If `filterUnits == userSpaceOnUse`, equal to the drawing context matrix, so, for example,
    /// if the target node is in a group with `transform="translate(30, 20)"`, this will be equal
    /// to a matrix that translates to 30, 20 (and does not scale). Note that the target node
    /// bounding box isn't included in the computations in this case.
    ///
    /// If `filterUnits == objectBoundingBox`, equal to the target node bounding box matrix
    /// multiplied by the drawing context matrix, so, for example, if the target node is in a group
    /// with `transform="translate(30, 20)"` and also has `x="1", y="1", width="50", height="50"`,
    /// this will be equal to a matrix that translates to 31, 21 and scales to 50, 50.
    ///
    /// This is to be used in conjunction with setting the viewbox size to account for the scaling.
    /// For `filterUnits == userSpaceOnUse`, the viewbox will have the actual resolution size, and
    /// for `filterUnits == objectBoundingBox`, the viewbox will have the size of 1, 1.
    _affine: Transform,

    /// The filter primitive affine matrix.
    ///
    /// See the comments for `_affine`, they largely apply here.
    paffine: Transform,
}

impl FilterContext {
    /// Creates a new `FilterContext`.
    pub fn new(
        filter: &Filter,
        computed_from_node_being_filtered: &ComputedValues,
        source_surface: SharedImageSurface,
        draw_ctx: &mut DrawingCtx,
        draw_transform: Transform,
        node_bbox: BoundingBox,
    ) -> Self {
        // The rect can be empty (for example, if the filter is applied to an empty group).
        // However, with userSpaceOnUse it's still possible to create images with a filter.
        let bbox_rect = node_bbox.rect.unwrap_or_default();

        let filter_units = filter.get_filter_units();
        let affine = match filter_units {
            CoordUnits::UserSpaceOnUse => draw_transform,
            CoordUnits::ObjectBoundingBox => Transform::new_unchecked(
                bbox_rect.width(),
                0.0,
                0.0,
                bbox_rect.height(),
                bbox_rect.x0,
                bbox_rect.y0,
            )
            .post_transform(&draw_transform),
        };

        let primitive_units = filter.get_primitive_units();
        let paffine = match primitive_units {
            CoordUnits::UserSpaceOnUse => draw_transform,
            CoordUnits::ObjectBoundingBox => Transform::new_unchecked(
                bbox_rect.width(),
                0.0,
                0.0,
                bbox_rect.height(),
                bbox_rect.x0,
                bbox_rect.y0,
            )
            .post_transform(&draw_transform),
        };

        let effects_region = {
            let params = draw_ctx.push_coord_units(filter_units);
            let filter_rect = filter.get_rect(&computed_from_node_being_filtered, &params);

            let mut bbox = BoundingBox::new();
            let other_bbox = BoundingBox::new()
                .with_transform(affine)
                .with_rect(filter_rect);

            // At this point all of the previous viewbox and matrix business gets converted to pixel
            // coordinates in the final surface, because bbox is created with an identity transform.
            bbox.insert(&other_bbox);

            // Finally, clip to the width and height of our surface.
            let (width, height) = (source_surface.width(), source_surface.height());
            let rect = Rect::from_size(f64::from(width), f64::from(height));
            let other_bbox = BoundingBox::new().with_rect(rect);
            bbox.clip(&other_bbox);

            bbox
        };

        Self {
            node_bbox,
            computed_from_node_being_filtered: computed_from_node_being_filtered.clone(),
            source_surface,
            last_result: None,
            previous_results: HashMap::new(),
            background_surface: RefCell::new(None),
            primitive_units,
            effects_region,
            processing_linear_rgb: false,
            _affine: affine,
            paffine,
        }
    }

    /// Returns the computed values from the node that referenced this filter.
    #[inline]
    pub fn get_computed_values_from_node_being_filtered(&self) -> &ComputedValues {
        &self.computed_from_node_being_filtered
    }

    /// Returns the surface corresponding to the source graphic.
    #[inline]
    pub fn source_graphic(&self) -> &SharedImageSurface {
        &self.source_surface
    }

    /// Returns the surface corresponding to the background image snapshot.
    pub fn background_image(
        &self,
        draw_ctx: &DrawingCtx,
    ) -> Result<SharedImageSurface, FilterError> {
        {
            // At this point either no, or only immutable references to background_surface exist, so
            // it's ok to make an immutable reference.
            let bg = self.background_surface.borrow();

            // If background_surface was already computed, return the immutable reference. It will
            // get bound to the &self lifetime by the function return type.
            if let Some(ref result) = *bg {
                return result.clone();
            }
        }

        // If we got here, then background_surface hasn't been computed yet. This means there are
        // no references to it and we can create a mutable reference.
        let mut bg = self.background_surface.borrow_mut();

        *bg = Some(
            draw_ctx
                .get_snapshot(self.source_surface.width(), self.source_surface.height())
                .map_err(FilterError::CairoError),
        );

        // Return the only existing reference as immutable.
        bg.as_ref()
            .unwrap()
            .as_ref()
            .map(|surf| surf.clone())
            .map_err(|e| e.clone())
    }

    /// Converts this `FilterContext` into the surface corresponding to the output of the filter
    /// chain.
    ///
    /// The returned surface is in the sRGB color space.
    // TODO: sRGB conversion should probably be done by the caller.
    #[inline]
    pub fn into_output(self) -> Result<SharedImageSurface, cairo::Status> {
        match self.last_result {
            Some(FilterOutput { surface, bounds }) => surface.to_srgb(bounds),
            None => SharedImageSurface::empty(
                self.source_surface.width(),
                self.source_surface.height(),
                SurfaceType::AlphaOnly,
            ),
        }
    }

    /// Stores a filter primitive result into the context.
    #[inline]
    pub fn store_result(&mut self, result: FilterResult) -> Result<(), FilterError> {
        if let Some(name) = result.name {
            self.previous_results.insert(name, result.output.clone());
        }

        self.last_result = Some(result.output);
        Ok(())
    }

    /// Returns the paffine matrix.
    #[inline]
    pub fn paffine(&self) -> Transform {
        self.paffine
    }

    /// Returns the primitive units.
    #[inline]
    pub fn primitive_units(&self) -> CoordUnits {
        self.primitive_units
    }

    /// Returns the filter effects region.
    #[inline]
    pub fn effects_region(&self) -> BoundingBox {
        self.effects_region
    }

    /// Retrieves the filter input surface according to the SVG rules.
    ///
    /// Does not take `processing_linear_rgb` into account.
    fn get_input_raw(
        &self,
        acquired_nodes: &mut AcquiredNodes<'_>,
        draw_ctx: &mut DrawingCtx,
        in_: Option<&Input>,
    ) -> Result<FilterInput, FilterError> {
        if in_.is_none() {
            // No value => use the last result.
            // As per the SVG spec, if the filter primitive is the first in the chain, return the
            // source graphic.
            if let Some(output) = self.last_result.as_ref() {
                return Ok(FilterInput::PrimitiveOutput(output.clone()));
            } else {
                return Ok(FilterInput::StandardInput(self.source_graphic().clone()));
            }
        }

        let values = &self.computed_from_node_being_filtered;

        match *in_.unwrap() {
            Input::SourceGraphic => Ok(FilterInput::StandardInput(self.source_graphic().clone())),

            Input::SourceAlpha => self
                .source_graphic()
                .extract_alpha(self.effects_region().rect.unwrap().into())
                .map_err(FilterError::CairoError)
                .map(FilterInput::StandardInput),

            Input::BackgroundImage => self
                .background_image(draw_ctx)
                .map(FilterInput::StandardInput),

            Input::BackgroundAlpha => self
                .background_image(draw_ctx)
                .and_then(|surface| {
                    surface
                        .extract_alpha(self.effects_region().rect.unwrap().into())
                        .map_err(FilterError::CairoError)
                })
                .map(FilterInput::StandardInput),

            Input::FillPaint => draw_ctx
                .get_paint_server_surface(
                    self.source_surface.width(),
                    self.source_surface.height(),
                    acquired_nodes,
                    &values.fill().0,
                    values.fill_opacity().0,
                    &self.node_bbox,
                    self.computed_from_node_being_filtered.color().0,
                    &values,
                )
                .map_err(FilterError::CairoError)
                .map(FilterInput::StandardInput),

            Input::StrokePaint => draw_ctx
                .get_paint_server_surface(
                    self.source_surface.width(),
                    self.source_surface.height(),
                    acquired_nodes,
                    &values.stroke().0,
                    values.stroke_opacity().0,
                    &self.node_bbox,
                    self.computed_from_node_being_filtered.color().0,
                    &values,
                )
                .map_err(FilterError::CairoError)
                .map(FilterInput::StandardInput),

            Input::FilterOutput(ref name) => self
                .previous_results
                .get(name)
                .cloned()
                .map(FilterInput::PrimitiveOutput)
                .ok_or(FilterError::InvalidInput),
        }
    }

    /// Retrieves the filter input surface according to the SVG rules.
    pub fn get_input(
        &self,
        acquired_nodes: &mut AcquiredNodes<'_>,
        draw_ctx: &mut DrawingCtx,
        in_: Option<&Input>,
    ) -> Result<FilterInput, FilterError> {
        let raw = self.get_input_raw(acquired_nodes, draw_ctx, in_)?;

        // Convert the input surface to the desired format.
        let (surface, bounds) = match raw {
            FilterInput::StandardInput(ref surface) => {
                (surface, self.effects_region().rect.unwrap().into())
            }
            FilterInput::PrimitiveOutput(FilterOutput {
                ref surface,
                ref bounds,
            }) => (surface, *bounds),
        };

        let surface = if self.processing_linear_rgb {
            surface.to_linear_rgb(bounds)
        } else {
            surface.to_srgb(bounds)
        };
        surface
            .map_err(FilterError::CairoError)
            .map(|surface| match raw {
                FilterInput::StandardInput(_) => FilterInput::StandardInput(surface),
                FilterInput::PrimitiveOutput(ref output) => {
                    FilterInput::PrimitiveOutput(FilterOutput { surface, ..*output })
                }
            })
    }

    /// Calls the given closure with linear RGB processing enabled.
    #[inline]
    pub fn with_linear_rgb<T, F: FnOnce(&mut FilterContext) -> T>(&mut self, f: F) -> T {
        self.processing_linear_rgb = true;
        let rv = f(self);
        self.processing_linear_rgb = false;
        rv
    }

    /// Applies the `primitiveUnits` coordinate transformation to a non-x or y distance.
    #[inline]
    pub fn transform_dist(&self, d: f64) -> f64 {
        d * (self.paffine.xx.powi(2) + self.paffine.yy.powi(2)).sqrt() / f64::consts::SQRT_2
    }
}

impl FilterInput {
    /// Retrieves the surface from `FilterInput`.
    #[inline]
    pub fn surface(&self) -> &SharedImageSurface {
        match *self {
            FilterInput::StandardInput(ref surface) => surface,
            FilterInput::PrimitiveOutput(FilterOutput { ref surface, .. }) => surface,
        }
    }
}
<|endoftext|>


<commit_before>#![warn(bad_style,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results)]

extern crate twitter_api as twitter;
extern crate rustc_serialize as rustc_serialize;
extern crate oauth_client as oauth;

use std::io;
use std::io::prelude::*;
use std::env;
use std::fs::{File, OpenOptions};
use std::path::Path;
use std::path::PathBuf;
use rustc_serialize::Decodable;
use rustc_serialize::json::{self, Json};
use oauth::Token;

const TWITTER_CONF_FILENAME: &'static str = ".twitter.conf";

fn get_home_dir() -> PathBuf{
    match env::home_dir() {
        Some(p) => p,
        None => {
            panic!("Impossible to get your home dir!");
        }
    }
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Config {
    pub consumer_key: String,
    pub consumer_secret: String,
    pub access_key: String,
    pub access_secret: String
}

impl Config {
    pub fn read(path_file : &Path) -> Option<Config> {
        let mut file = match File::open(path_file) {
            Ok(f) => f,
            Err(_) => return None
        };
        let conf = Json::from_reader(&mut file).unwrap();
        Decodable::decode(&mut json::Decoder::new(conf)).ok()
    }

    pub fn write(&self, path_file : &Path) {
        let mut file = match OpenOptions::new().write(true).open(path_file) {
            Ok(f) => f,
            Err(e) => panic!("{}", e)
        };
        let _ = write!(&mut file, "{}\n", &json::encode(self).unwrap());
    }

    pub fn create(path_file : &Path) {
        match File::create(path_file) {
            Ok(_) => println!("File created!"),
            Err(_) => panic!("Problem to create the file...\nProgram aborted!")
        }
    }
}

fn console_input(prompt: &str) -> String {
    print!("{}\n\t", prompt);
    let mut line = String::new();
    let _ = io::stdin().read_line(&mut line).unwrap();
    line.trim().to_string()
}

fn main() {
    //Get the full path of the Twitter configuration path
    let mut twitter_conf_file_path : PathBuf = get_home_dir();
    twitter_conf_file_path.push(Path::new(TWITTER_CONF_FILENAME));

    let conf = match Config::read(&twitter_conf_file_path) {
        Some(c) => c,
        None => {

            Config::create(&twitter_conf_file_path);

            let consumer_key    = console_input("input your consumer key:");
            let consumer_secret = console_input("input your consumer secret:");
            let consumer = Token::new(consumer_key, consumer_secret);

            let request = twitter::get_request_token(&consumer);
            println!("open the following url:");
            println!("\t{}", twitter::get_authorize_url(&request));
            let pin = console_input("input pin:");
            let access = twitter::get_access_token(&consumer, &request, &pin);

            let c = Config {
                consumer_key: consumer.key.to_string(),
                consumer_secret: consumer.secret.to_string(),
                access_key: access.key.to_string(),
                access_secret: access.secret.to_string()
            };

            c.write(&twitter_conf_file_path);
            c
        }
    };

    let consumer = Token::new(conf.consumer_key, conf.consumer_secret);
    let access = Token::new(conf.access_key, conf.access_secret);

    let status = console_input("What's happening?");
    twitter::update_status(&consumer, &access, &status);
}
<commit_msg>examples/tweet.rs : Debugging console_input()<commit_after>#![warn(bad_style,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results)]

extern crate twitter_api as twitter;
extern crate rustc_serialize as rustc_serialize;
extern crate oauth_client as oauth;

use std::io;
use std::io::prelude::*;
use std::env;
use std::fs::{File, OpenOptions};
use std::path::Path;
use std::path::PathBuf;
use rustc_serialize::Decodable;
use rustc_serialize::json::{self, Json};
use oauth::Token;

const TWITTER_CONF_FILENAME: &'static str = ".twitter.conf";

fn get_home_dir() -> PathBuf{
    match env::home_dir() {
        Some(p) => p,
        None => {
            panic!("Impossible to get your home dir!");
        }
    }
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Config {
    pub consumer_key: String,
    pub consumer_secret: String,
    pub access_key: String,
    pub access_secret: String
}

impl Config {
    pub fn read(path_file : &Path) -> Option<Config> {
        let mut file = match File::open(path_file) {
            Ok(f) => f,
            Err(_) => return None
        };
        let conf = Json::from_reader(&mut file).unwrap();
        Decodable::decode(&mut json::Decoder::new(conf)).ok()
    }

    pub fn write(&self, path_file : &Path) {
        let mut file = match OpenOptions::new().write(true).open(path_file) {
            Ok(f) => f,
            Err(e) => panic!("{}", e)
        };
        let _ = write!(&mut file, "{}\n", &json::encode(self).unwrap());
    }

    pub fn create(path_file : &Path) {
        match File::create(path_file) {
            Ok(_) => println!("File created!"),
            Err(_) => panic!("Problem to create the file...\nProgram aborted!")
        }
    }
}

fn console_input(prompt: &str) -> String {
    println!("{} : ", prompt);
    let mut line = String::new();
    let _ = io::stdin().read_line(&mut line).unwrap();
    line.trim().to_string()
}

fn main() {
    //Get the full path of the Twitter configuration path
    let mut twitter_conf_file_path : PathBuf = get_home_dir();
    twitter_conf_file_path.push(Path::new(TWITTER_CONF_FILENAME));

    let conf = match Config::read(&twitter_conf_file_path) {
        Some(c) => c,
        None => {

            Config::create(&twitter_conf_file_path);

            let consumer_key    = console_input("input your consumer key:");
            let consumer_secret = console_input("input your consumer secret:");
            let consumer = Token::new(consumer_key, consumer_secret);

            let request = twitter::get_request_token(&consumer);
            println!("open the following url:");
            println!("\t{}", twitter::get_authorize_url(&request));
            let pin = console_input("input pin:");
            let access = twitter::get_access_token(&consumer, &request, &pin);

            let c = Config {
                consumer_key: consumer.key.to_string(),
                consumer_secret: consumer.secret.to_string(),
                access_key: access.key.to_string(),
                access_secret: access.secret.to_string()
            };

            c.write(&twitter_conf_file_path);
            c
        }
    };

    let consumer = Token::new(conf.consumer_key, conf.consumer_secret);
    let access = Token::new(conf.access_key, conf.access_secret);

    let status = console_input("What's happening?");
    twitter::update_status(&consumer, &access, &status);
}
<|endoftext|>


<commit_before>// use to create a .so/.dll
#![crate_type = "dylib"]

// we use crate collections which contains only
// collections that does not need the runtime to run by default
extern crate collections;
extern crate native;
extern crate libc;

// NOTE: at first I wanted to push the example further and not to
// include the std crate, which is basically what you would want to
// do for system programming
//
// but too much features will not be available without implemenenting
// your own memory allocator
// i.e  "".to_string  or insertion in collection etc.
//
// waiting to write a dedicated example about building without std
// here is basically what you need to append at top of your file
//
//#![no_std]
//#![crate_type = "dylib"]
//#![feature(phase)]
//
//#[phase(plugin,link)]
//extern crate core;

// we need to use TreeMap, and not HashMap
// because HashMap use a RNG running in a local thread
// that is init by rust runtime

// note that I could use HashMap with SipHash and own seeded RNG
use collections::TreeMap;

#[no_mangle]
pub extern fn create_hash() -> Box<TreeMap<String,String>> {
    let mut english_to_french =  box TreeMap::new();
    english_to_french.insert("one".to_string(), "un".to_string());
    english_to_french.insert("two".to_string(), "deux".to_string());

    english_to_french
}

#[no_mangle]
pub extern fn print_hash(english_to_french: Box<TreeMap<String,String>>) {
    for (english, french) in english_to_french.iter() {
        println!(
            "in french '{}' is '{}'",
            *english,
            *french
        );
    }

}
<commit_msg>remove unused crate<commit_after>// use to create a .so/.dll
#![crate_type = "dylib"]

// we use crate collections which contains only
// collections that does not need the runtime to run by default
extern crate collections;

// NOTE: at first I wanted to push the example further and not to
// include the std crate, which is basically what you would want to
// do for system programming
//
// but too much features will not be available without implemenenting
// your own memory allocator
// i.e  "".to_string  or insertion in collection etc.
//
// waiting to write a dedicated example about building without std
// here is basically what you need to append at top of your file
//
//#![no_std]
//#![crate_type = "dylib"]
//#![feature(phase)]
//
//#[phase(plugin,link)]
//extern crate core;

// we need to use TreeMap, and not HashMap
// because HashMap use a RNG running in a local thread
// that is init by rust runtime

// note that I could use HashMap with SipHash and own seeded RNG
use collections::TreeMap;

#[no_mangle]
pub extern fn create_hash() -> Box<TreeMap<String,String>> {
    let mut english_to_french =  box TreeMap::new();
    english_to_french.insert("one".to_string(), "un".to_string());
    english_to_french.insert("two".to_string(), "deux".to_string());

    english_to_french
}

#[no_mangle]
pub extern fn print_hash(english_to_french: Box<TreeMap<String,String>>) {
    for (english, french) in english_to_french.iter() {
        println!(
            "in french '{}' is '{}'",
            *english,
            *french
        );
    }

}
<|endoftext|>


<commit_before>//! I guess these docs will never appear since we re-export the canvas
//! module from graphics...
use gfx::format::{Format, Swizzle};
use gfx::handle::RawRenderTargetView;
use gfx::memory::{Bind, Usage};
use gfx::texture::{AaMode, Kind};
use gfx::Factory;

use crate::conf;
use crate::context::DebugId;
use crate::error::*;
use crate::graphics::*;
use crate::Context;

/// A generic canvas independent of graphics backend. This type should
/// never need to be used directly; use [`graphics::Canvas`](type.Canvas.html)
/// instead.
#[derive(Debug)]
pub struct CanvasGeneric<Spec>
where
    Spec: BackendSpec,
{
    target: RawRenderTargetView<Spec::Resources>,
    image: Image,
    debug_id: DebugId,
}

/// A canvas that can be rendered to instead of the screen (sometimes referred
/// to as "render target" or "render to texture"). Set the canvas with the
/// [`graphics::set_canvas()`](fn.set_canvas.html) function, and then anything you
/// draw will be drawn to the canvas instead of the screen.
///
/// Resume drawing to the screen by calling `graphics::set_canvas(None)`.
///
/// A `Canvas` allows graphics to be rendered to images off-screen
/// in order to do things like saving to an image file or creating cool effects
/// by using shaders that render to an image.
/// If you just want to draw multiple things efficiently, look at
/// [`SpriteBatch`](spritebatch/struct.Spritebatch.html).
pub type Canvas = CanvasGeneric<GlBackendSpec>;

impl<S> CanvasGeneric<S>
where
    S: BackendSpec,
{
    /// Create a new `Canvas` with the given size and number of samples.
    pub fn new(
        ctx: &mut Context,
        width: u16,
        height: u16,
        samples: conf::NumSamples,
        color_format: Format,
    ) -> GameResult<Canvas> {
        let debug_id = DebugId::get(ctx);
        let aa = match samples {
            conf::NumSamples::One => AaMode::Single,
            s => AaMode::Multi(s as u8),
        };
        let kind = Kind::D2(width, height, aa);
        let levels = 1;
        let factory = &mut ctx.gfx_context.factory;
        let texture_create_info = gfx::texture::Info {
            kind,
            levels,
            format: color_format.0,
            bind: Bind::SHADER_RESOURCE | Bind::RENDER_TARGET | Bind::TRANSFER_SRC,
            usage: Usage::Data,
        };
        let tex = factory.create_texture_raw(texture_create_info, Some(color_format.1), None)?;
        let resource_desc = gfx::texture::ResourceDesc {
            channel: color_format.1,
            layer: None,
            min: 0,
            max: levels - 1,
            swizzle: Swizzle::new(),
        };
        let resource = factory.view_texture_as_shader_resource_raw(&tex, resource_desc)?;
        let render_desc = gfx::texture::RenderDesc {
            channel: color_format.1,
            level: 0,
            layer: None,
        };
        let target = factory.view_texture_as_render_target_raw(&tex, render_desc)?;
        Ok(Canvas {
            target,
            image: Image {
                texture: resource,
                texture_handle: tex,
                sampler_info: ctx.gfx_context.default_sampler_info,
                blend_mode: None,
                width,
                height,
                debug_id,
            },
            debug_id,
        })
    }

    /// Create a new `Canvas` with the current window dimensions.
    pub fn with_window_size(ctx: &mut Context) -> GameResult<Canvas> {
        use crate::graphics;
        let (w, h) = graphics::drawable_size(ctx);
        // Default to no multisampling
        Canvas::new(
            ctx,
            w as u16,
            h as u16,
            conf::NumSamples::One,
            get_window_color_format(ctx),
        )
    }

    /// Gets the backend `Image` that is being rendered to.
    pub fn image(&self) -> &Image {
        &self.image
    }

    /// Gets the backend `Target` that is being rendered to.
    pub fn target(&self) -> &RawRenderTargetView<S::Resources> {
        &self.target
    }

    /// Get the filter mode for the image.
    pub fn filter(&self) -> FilterMode {
        self.image.filter()
    }

    /// Set the filter mode for the canvas.
    pub fn set_filter(&mut self, mode: FilterMode) {
        self.image.set_filter(mode)
    }

    /// Destroys the `Canvas` and returns the `Image` it contains.
    pub fn into_inner(self) -> Image {
        // TODO: This texture is created with different settings
        // than the default; does that matter?
        // Test; we really just need to add Bind::TRANSFER_SRC
        // and change the Usage's to match to make them identical.
        // Ask termhn maybe?
        self.image
    }
}

impl Drawable for Canvas {
    fn draw(&self, ctx: &mut Context, param: DrawParam) -> GameResult {
        self.debug_id.assert(ctx);
        // Gotta flip the image on the Y axis here
        // to account for OpenGL's origin being at the bottom-left.
        match param.trans {
            Transform::Values { scale, dest, .. } => {
                let new_scale = mint::Vector2 {
                    x: scale.x,
                    y: scale.y * -1.0,
                };
                let new_dest = mint::Point2 {
                    x: dest.x,
                    y: dest.y + f32::from(self.image.height()) * new_scale.y,
                };
                let new_param = param.dest(new_dest).scale(new_scale);
                self.image.draw(ctx, new_param)
            }
            Transform::Matrix(_) => self.image.draw(ctx, param),
        }
    }
    fn dimensions(&self, _: &mut Context) -> Option<Rect> {
        Some(self.image.dimensions())
    }
    fn set_blend_mode(&mut self, mode: Option<BlendMode>) {
        self.image.blend_mode = mode;
    }
    fn blend_mode(&self) -> Option<BlendMode> {
        self.image.blend_mode
    }
}

/// Set the `Canvas` to render to. Specifying `Option::None` will cause all
/// rendering to be done directly to the screen.
pub fn set_canvas(ctx: &mut Context, target: Option<&Canvas>) {
    match target {
        Some(surface) => {
            surface.debug_id.assert(ctx);
            ctx.gfx_context.data.out = surface.target.clone();
        }
        None => {
            ctx.gfx_context.data.out = ctx.gfx_context.screen_render_target.clone();
        }
    };
}
<commit_msg>Fix scaling bug for canvases<commit_after>//! I guess these docs will never appear since we re-export the canvas
//! module from graphics...
use gfx::format::{Format, Swizzle};
use gfx::handle::RawRenderTargetView;
use gfx::memory::{Bind, Usage};
use gfx::texture::{AaMode, Kind};
use gfx::Factory;

use crate::conf;
use crate::context::DebugId;
use crate::error::*;
use crate::graphics::*;
use crate::Context;

/// A generic canvas independent of graphics backend. This type should
/// never need to be used directly; use [`graphics::Canvas`](type.Canvas.html)
/// instead.
#[derive(Debug)]
pub struct CanvasGeneric<Spec>
where
    Spec: BackendSpec,
{
    target: RawRenderTargetView<Spec::Resources>,
    image: Image,
    debug_id: DebugId,
}

/// A canvas that can be rendered to instead of the screen (sometimes referred
/// to as "render target" or "render to texture"). Set the canvas with the
/// [`graphics::set_canvas()`](fn.set_canvas.html) function, and then anything you
/// draw will be drawn to the canvas instead of the screen.
///
/// Resume drawing to the screen by calling `graphics::set_canvas(None)`.
///
/// A `Canvas` allows graphics to be rendered to images off-screen
/// in order to do things like saving to an image file or creating cool effects
/// by using shaders that render to an image.
/// If you just want to draw multiple things efficiently, look at
/// [`SpriteBatch`](spritebatch/struct.Spritebatch.html).
pub type Canvas = CanvasGeneric<GlBackendSpec>;

impl<S> CanvasGeneric<S>
where
    S: BackendSpec,
{
    /// Create a new `Canvas` with the given size and number of samples.
    pub fn new(
        ctx: &mut Context,
        width: u16,
        height: u16,
        samples: conf::NumSamples,
        color_format: Format,
    ) -> GameResult<Canvas> {
        let debug_id = DebugId::get(ctx);
        let aa = match samples {
            conf::NumSamples::One => AaMode::Single,
            s => AaMode::Multi(s as u8),
        };
        let kind = Kind::D2(width, height, aa);
        let levels = 1;
        let factory = &mut ctx.gfx_context.factory;
        let texture_create_info = gfx::texture::Info {
            kind,
            levels,
            format: color_format.0,
            bind: Bind::SHADER_RESOURCE | Bind::RENDER_TARGET | Bind::TRANSFER_SRC,
            usage: Usage::Data,
        };
        let tex = factory.create_texture_raw(texture_create_info, Some(color_format.1), None)?;
        let resource_desc = gfx::texture::ResourceDesc {
            channel: color_format.1,
            layer: None,
            min: 0,
            max: levels - 1,
            swizzle: Swizzle::new(),
        };
        let resource = factory.view_texture_as_shader_resource_raw(&tex, resource_desc)?;
        let render_desc = gfx::texture::RenderDesc {
            channel: color_format.1,
            level: 0,
            layer: None,
        };
        let target = factory.view_texture_as_render_target_raw(&tex, render_desc)?;
        Ok(Canvas {
            target,
            image: Image {
                texture: resource,
                texture_handle: tex,
                sampler_info: ctx.gfx_context.default_sampler_info,
                blend_mode: None,
                width,
                height,
                debug_id,
            },
            debug_id,
        })
    }

    /// Create a new `Canvas` with the current window dimensions.
    pub fn with_window_size(ctx: &mut Context) -> GameResult<Canvas> {
        use crate::graphics;
        let (w, h) = graphics::drawable_size(ctx);
        // Default to no multisampling
        Canvas::new(
            ctx,
            w as u16,
            h as u16,
            conf::NumSamples::One,
            get_window_color_format(ctx),
        )
    }

    /// Gets the backend `Image` that is being rendered to.
    pub fn image(&self) -> &Image {
        &self.image
    }

    /// Gets the backend `Target` that is being rendered to.
    pub fn target(&self) -> &RawRenderTargetView<S::Resources> {
        &self.target
    }

    /// Get the filter mode for the image.
    pub fn filter(&self) -> FilterMode {
        self.image.filter()
    }

    /// Set the filter mode for the canvas.
    pub fn set_filter(&mut self, mode: FilterMode) {
        self.image.set_filter(mode)
    }

    /// Destroys the `Canvas` and returns the `Image` it contains.
    pub fn into_inner(self) -> Image {
        // TODO: This texture is created with different settings
        // than the default; does that matter?
        // Test; we really just need to add Bind::TRANSFER_SRC
        // and change the Usage's to match to make them identical.
        // Ask termhn maybe?
        self.image
    }
}

impl Drawable for Canvas {
    fn draw(&self, ctx: &mut Context, param: DrawParam) -> GameResult {
        self.debug_id.assert(ctx);
        // Gotta flip the image on the Y axis here
        // to account for OpenGL's origin being at the bottom-left.
        match param.trans {
            Transform::Values { scale, dest, .. } => {
                let new_scale = mint::Vector2 {
                    x: scale.x,
                    y: scale.y * -1.0,
                };
                let new_dest = mint::Point2 {
                    x: dest.x,
                    y: dest.y + f32::from(self.image.height()) * scale.y,
                };
                let new_param = param.dest(new_dest).scale(new_scale);
                self.image.draw(ctx, new_param)
            }
            Transform::Matrix(_) => self.image.draw(ctx, param),
        }
    }
    fn dimensions(&self, _: &mut Context) -> Option<Rect> {
        Some(self.image.dimensions())
    }
    fn set_blend_mode(&mut self, mode: Option<BlendMode>) {
        self.image.blend_mode = mode;
    }
    fn blend_mode(&self) -> Option<BlendMode> {
        self.image.blend_mode
    }
}

/// Set the `Canvas` to render to. Specifying `Option::None` will cause all
/// rendering to be done directly to the screen.
pub fn set_canvas(ctx: &mut Context, target: Option<&Canvas>) {
    match target {
        Some(surface) => {
            surface.debug_id.assert(ctx);
            ctx.gfx_context.data.out = surface.target.clone();
        }
        None => {
            ctx.gfx_context.data.out = ctx.gfx_context.screen_render_target.clone();
        }
    };
}
<|endoftext|>


<commit_before>#![cfg(feature = "std")]

extern crate bytes;
#[macro_use]
extern crate combine;

extern crate futures;
extern crate partial_io;
extern crate tokio_io;

use std::rc::Rc;
use std::cell::Cell;
use std::str;
use std::io::Cursor;

use bytes::BytesMut;

use tokio_io::codec::Decoder;

use combine::error::StreamError;
use combine::stream::{PartialStream, RangeStream, StreamErrorFor};
use combine::combinator::{any_partial_state, AnyPartialState};
use combine::parser::range::{range, recognize, take};
use combine::{skip_many, skip_many1};
use combine::stream::easy;
use combine::parser::byte::digit;

pub struct LanguageServerDecoder {
    state: AnyPartialState,
    content_length_parses: Rc<Cell<i32>>,
}

impl LanguageServerDecoder {
    pub fn new() -> LanguageServerDecoder {
        LanguageServerDecoder {
            state: Default::default(),
            content_length_parses: Rc::new(Cell::new(0)),
        }
    }
}

/// Parses blocks of data with length headers
///
/// ```
/// Content-Length: 18
///
/// { "some": "data" }
/// ```
parser! {
    type PartialState = AnyPartialState;
    fn decode_parser['a, I](content_length_parses: Rc<Cell<i32>>)(I) -> Vec<u8>
    where [ I: RangeStream<Item = u8, Range = &'a [u8]>, ]
    {
        let content_length =
            range(&b"Content-Length: "[..])
                .with(
                    recognize(skip_many1(digit()))
                        .and_then(|digits: &[u8]|
                            str::from_utf8(digits).unwrap().parse::<usize>()
                                // Convert the error from `.parse` into an error combine understands
                                .map_err(StreamErrorFor::<I>::other)
                        )
                )
                .map(|x| {
                    content_length_parses.set(content_length_parses.get() + 1);
                    x
                });
        any_partial_state((
            skip_many(range(&b"\r\n"[..])),
            content_length,
            range(&b"\r\n\r\n"[..]).map(|_| ()),
        )
            .then_partial(|&mut (_, message_length, _)| take(message_length).map(|bytes: &[u8]| bytes.to_owned())))
    }
}

impl Decoder for LanguageServerDecoder {
    type Item = String;
    type Error = Box<::std::error::Error + Send + Sync>;

    fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
        println!("Decoding `{:?}`", str::from_utf8(src).unwrap_or("NOT UTF8"));

        let (opt, removed_len) = combine::stream::decode(
            decode_parser(self.content_length_parses.clone()),
            easy::Stream(PartialStream(&src[..])),
            &mut self.state,
        ).map_err(|err| {
            // Since err contains references into `src` we must replace these before
            // we can return an error or call `split_to` to remove the input we
            // just consumed
            let err = err.map_range(|r| {
                str::from_utf8(r)
                    .ok()
                    .map_or_else(|| format!("{:?}", r), |s| s.to_string())
            }).map_position(|p| p.translate_position(&src[..]));
            format!("{}\nIn input: `{}`", err, str::from_utf8(src).unwrap())
        })?;

        println!(
            "Accepted {} bytes: `{:?}`",
            removed_len,
            str::from_utf8(&src[..removed_len]).unwrap_or("NOT UTF8")
        );
        src.split_to(removed_len);
        match opt {
            None => {
                println!("Requesting more input!");
                Ok(None)
            }
            Some(output) => {
                let value = String::from_utf8(output)?;
                println!("Decoded `{}`", value);
                Ok(Some(value))
            }
        }
    }
}

fn main() {
    use futures::{Future, Stream};
    use tokio_io::codec::FramedRead;
    use partial_io::{PartialAsyncRead, PartialOp};

    let input = "Content-Length: 6\r\n\
                 \r\n\
                 123456\r\n\
                 Content-Length: 4\r\n\
                 \r\n\
                 true";

    let seq = vec![
        PartialOp::Limited(20),
        PartialOp::Limited(1),
        PartialOp::Limited(2),
        PartialOp::Limited(3),
    ];
    let ref mut reader = Cursor::new(input.as_bytes());
    // Using the `partial_io` crate we emulate the partial reads that would happen when reading
    // asynchronously from an io device.
    let partial_reader = PartialAsyncRead::new(reader, seq);

    let decoder = LanguageServerDecoder::new();
    let content_length_parses = decoder.content_length_parses.clone();

    let result = FramedRead::new(partial_reader, decoder).collect().wait();

    assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
    let values = result.unwrap();

    let expected_values = ["123456", "true"];
    assert_eq!(values, expected_values);

    assert_eq!(content_length_parses.get(), expected_values.len() as i32);

    println!("Successfully parsed: `{}`", input);
    println!(
        "Found {} items and never repeated a completed parse!",
        values.len(),
    );
    println!("Result: {:?}", values);
}
<commit_msg>doc: Add comments from the blog post to the async example<commit_after>#![cfg(feature = "std")]

extern crate bytes;
#[macro_use]
extern crate combine;

extern crate futures;
extern crate partial_io;
extern crate tokio_io;

use std::rc::Rc;
use std::cell::Cell;
use std::str;
use std::io::Cursor;

use bytes::BytesMut;

use tokio_io::codec::Decoder;

use combine::error::StreamError;
use combine::stream::{PartialStream, RangeStream, StreamErrorFor};
use combine::combinator::{any_partial_state, AnyPartialState};
use combine::parser::range::{range, recognize, take};
use combine::{skip_many, skip_many1};
use combine::stream::easy;
use combine::parser::byte::digit;

pub struct LanguageServerDecoder {
    state: AnyPartialState,
    content_length_parses: Rc<Cell<i32>>,
}

impl LanguageServerDecoder {
    pub fn new() -> LanguageServerDecoder {
        LanguageServerDecoder {
            state: Default::default(),
            content_length_parses: Rc::new(Cell::new(0)),
        }
    }
}

/// Parses blocks of data with length headers
///
/// ```
/// Content-Length: 18
///
/// { "some": "data" }
/// ```
parser! {
    // To avoid writing out the state type we Box it using `AnyPartialState`
    // and the `any_partial_state` parser combinator
    type PartialState = AnyPartialState;

    // The syntax of the parser macro follows normal function declarations as
    // closely as possible but requires brackets (`[]`) around the type
    // parameters and around the where clause.
    // It also requires extra bit of information between the arguments and
    // the return type which marks what input the parser takes.
    // In this case the input is `I: RangeStream`.

    // The `content_length_parses` parameter only exists to demonstrate that `content_length` only
    // gets parsed once per message
    fn decode_parser['a, I](content_length_parses: Rc<Cell<i32>>)(I) -> Vec<u8>
    where [ I: RangeStream<Item = u8, Range = &'a [u8]>, ]
    {
        let content_length =
            range(&b"Content-Length: "[..])
                .with(
                    recognize(skip_many1(digit()))
                        .and_then(|digits: &[u8]|
                            str::from_utf8(digits).unwrap().parse::<usize>()
                                // Convert the error from `.parse` into an error combine understands
                                .map_err(StreamErrorFor::<I>::other)
                        )
                )
                .map(|x| {
                    content_length_parses.set(content_length_parses.get() + 1);
                    x
                });
        any_partial_state((
            skip_many(range(&b"\r\n"[..])),
            content_length,
            range(&b"\r\n\r\n"[..]).map(|_| ()),
        )
            .then_partial(|&mut (_, message_length, _)| take(message_length).map(|bytes: &[u8]| bytes.to_owned())))
    }
}

impl Decoder for LanguageServerDecoder {
    type Item = String;
    type Error = Box<::std::error::Error + Send + Sync>;

    fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
        println!("Decoding `{:?}`", str::from_utf8(src).unwrap_or("NOT UTF8"));

        let (opt, removed_len) = combine::stream::decode(
            decode_parser(self.content_length_parses.clone()),
            // easy::Stream gives us nice error messages
            // (the same error messages that combine has had since its inception)
            // PartialStream lets the parser know that more input should be
            // expected if end of input is unexpectedly reached
            easy::Stream(PartialStream(&src[..])),
            &mut self.state,
        ).map_err(|err| {
            // Since err contains references into `src` we must replace these before
            // we can return an error or call `split_to` to remove the input we
            // just consumed
            let err = err.map_range(|r| {
                str::from_utf8(r)
                    .ok()
                    .map_or_else(|| format!("{:?}", r), |s| s.to_string())
            }).map_position(|p| p.translate_position(&src[..]));
            format!("{}\nIn input: `{}`", err, str::from_utf8(src).unwrap())
        })?;

        println!(
            "Accepted {} bytes: `{:?}`",
            removed_len,
            str::from_utf8(&src[..removed_len]).unwrap_or("NOT UTF8")
        );

        // Remove the input we just consumed.
        // Ideally this would be done automatically by the call to
        // `stream::decode` but it does unfortunately not work due
        // to lifetime issues (Non lexical lifetimes might fix it!)
        src.split_to(removed_len);

        match opt {
            // `None` means we did not have enough input and we require that the
            // caller of `decode` supply more before calling us again
            None => {
                println!("Requesting more input!");
                Ok(None)
            }

            // `Some` means that a message was successfully decoded
            // (and that we are ready to start decoding the next message)
            Some(output) => {
                let value = String::from_utf8(output)?;
                println!("Decoded `{}`", value);
                Ok(Some(value))
            }
        }
    }
}

fn main() {
    use futures::{Future, Stream};
    use tokio_io::codec::FramedRead;
    use partial_io::{PartialAsyncRead, PartialOp};

    let input = "Content-Length: 6\r\n\
                 \r\n\
                 123456\r\n\
                 Content-Length: 4\r\n\
                 \r\n\
                 true";

    let seq = vec![
        PartialOp::Limited(20),
        PartialOp::Limited(1),
        PartialOp::Limited(2),
        PartialOp::Limited(3),
    ];
    let ref mut reader = Cursor::new(input.as_bytes());
    // Using the `partial_io` crate we emulate the partial reads that would happen when reading
    // asynchronously from an io device.
    let partial_reader = PartialAsyncRead::new(reader, seq);

    let decoder = LanguageServerDecoder::new();
    let content_length_parses = decoder.content_length_parses.clone();

    let result = FramedRead::new(partial_reader, decoder).collect().wait();

    assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
    let values = result.unwrap();

    let expected_values = ["123456", "true"];
    assert_eq!(values, expected_values);

    assert_eq!(content_length_parses.get(), expected_values.len() as i32);

    println!("Successfully parsed: `{}`", input);
    println!(
        "Found {} items and never repeated a completed parse!",
        values.len(),
    );
    println!("Result: {:?}", values);
}
<|endoftext|>


<commit_before>extern crate time;
extern crate daylight;
extern crate hyper;
extern crate rustc_serialize;

use time::{at, now};
use daylight::calculate_daylight;

use std::io::Read;

use hyper::Client;
use hyper::header::Connection;
use hyper::header::ConnectionOption;

use rustc_serialize::json::Json;

fn main() {
    // create client
    let mut client = Client::new();

    // create request
    let mut res = client.get("http://freegeoip.net/json/")
        // set a header
        .header(Connection(vec![ConnectionOption::Close]))
        // let 'er go!
        .send().unwrap();

    // Read the response.
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();

    let data = Json::from_str(&body).unwrap();

    let obj = data.as_object().unwrap();

    let lat = obj.get("latitude").unwrap().as_f64().unwrap();
    let long = obj.get("longitude").unwrap().as_f64().unwrap();
    let city = obj.get("city").unwrap().as_string().unwrap();
    let timezone = obj.get("time_zone").unwrap().as_string().unwrap();
    let today = now();

    let daylight = calculate_daylight(today, lat, long);

    let daylength_total_minutes = daylight.daylength.num_minutes();
    let daylength_hours = daylength_total_minutes / 60;
    let daylength_minutes = daylength_total_minutes % 60;

    println!("Sunrise and set times based on IP");
    println!("=================================");

    println!("Date:                 {}", today.asctime());
    println!("Timezone:             {}", timezone);
    println!("Latitude/Longitude:   {}/{} ({})", lat, long, city);
    println!("Declination:          {}°", daylight.declination);
    println!("Daylength:            {}:{}", daylength_hours, daylength_minutes);
    println!("Twilight AM:          {}", at(daylight.twilight_morning).asctime());
    println!("Sunrise:              {}", at(daylight.sunrise).asctime());
    println!("Noon:                 {}", at(daylight.noon).asctime());
    println!("Sunset:               {}", at(daylight.sunset).asctime());
    println!("Twilight PM:          {}", at(daylight.twilight_evening).asctime());
    println!("Sun altitude:         {}°", daylight.sun_altitude)
}
<commit_msg>Solved warning<commit_after>extern crate time;
extern crate daylight;
extern crate hyper;
extern crate rustc_serialize;

use time::{at, now};
use daylight::calculate_daylight;

use std::io::Read;

use hyper::Client;
use hyper::header::Connection;
use hyper::header::ConnectionOption;

use rustc_serialize::json::Json;

fn main() {
    // create client
    let client = Client::new();

    // create request
    let mut res = client.get("http://freegeoip.net/json/")
        // set a header
        .header(Connection(vec![ConnectionOption::Close]))
        // let 'er go!
        .send().unwrap();

    // Read the response.
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();

    let data = Json::from_str(&body).unwrap();

    let obj = data.as_object().unwrap();

    let lat = obj.get("latitude").unwrap().as_f64().unwrap();
    let long = obj.get("longitude").unwrap().as_f64().unwrap();
    let city = obj.get("city").unwrap().as_string().unwrap();
    let timezone = obj.get("time_zone").unwrap().as_string().unwrap();
    let today = now();

    let daylight = calculate_daylight(today, lat, long);

    let daylength_total_minutes = daylight.daylength.num_minutes();
    let daylength_hours = daylength_total_minutes / 60;
    let daylength_minutes = daylength_total_minutes % 60;

    println!("Sunrise and set times based on IP");
    println!("=================================");

    println!("Date:                 {}", today.asctime());
    println!("Timezone:             {}", timezone);
    println!("Latitude/Longitude:   {}/{} ({})", lat, long, city);
    println!("Declination:          {}°", daylight.declination);
    println!("Daylength:            {}:{}", daylength_hours, daylength_minutes);
    println!("Twilight AM:          {}", at(daylight.twilight_morning).asctime());
    println!("Sunrise:              {}", at(daylight.sunrise).asctime());
    println!("Noon:                 {}", at(daylight.noon).asctime());
    println!("Sunset:               {}", at(daylight.sunset).asctime());
    println!("Twilight PM:          {}", at(daylight.twilight_evening).asctime());
    println!("Sun altitude:         {}°", daylight.sun_altitude)
}
<|endoftext|>