icons.rs 4.89 KB
Newer Older
Bilal Elmoussaoui's avatar
Bilal Elmoussaoui committed
1 2 3
use super::icon::Icon;
use crate::config;

Julian Hofer's avatar
Julian Hofer committed
4
use anyhow::Result;
Bilal Elmoussaoui's avatar
Bilal Elmoussaoui committed
5 6
use gtk::prelude::*;
use std::cell::RefCell;
7
use std::collections::BTreeMap;
Bilal Elmoussaoui's avatar
Bilal Elmoussaoui committed
8 9 10 11
use std::fs::File;
use std::io::BufReader;
use std::path::PathBuf;

12 13 14 15 16 17 18
#[derive(Clone, Debug)]
pub struct IconsContext {
    pub context: String,
    pub icons: Vec<Icon>,
    pub is_system: bool,
}

Bilal Elmoussaoui's avatar
Bilal Elmoussaoui committed
19
pub struct IconsModel {
20 21
    pub system_icons: RefCell<BTreeMap<String, IconsContext>>,
    pub shipped_icons: RefCell<BTreeMap<String, IconsContext>>,
Bilal Elmoussaoui's avatar
Bilal Elmoussaoui committed
22 23 24
}

impl IconsModel {
Bilal Elmoussaoui's avatar
Bilal Elmoussaoui committed
25
    pub fn new() -> Self {
26 27 28
        let system_icons = RefCell::new(BTreeMap::new());
        let shipped_icons = RefCell::new(BTreeMap::new());
        let model = Self { system_icons, shipped_icons };
Bilal Elmoussaoui's avatar
Bilal Elmoussaoui committed
29 30
        model.init();
        model
Bilal Elmoussaoui's avatar
Bilal Elmoussaoui committed
31 32
    }

33 34 35 36
    fn get_icons(&self) -> Vec<Icon> {
        // Fusion the system and shipped icons into one big thing
        let mut system_icons: Vec<Icon> = self
            .system_icons
Bilal Elmoussaoui's avatar
Bilal Elmoussaoui committed
37 38
            .borrow()
            .clone()
Bilal Elmoussaoui's avatar
Bilal Elmoussaoui committed
39
            .into_iter()
40
            .map(|(_, icons_context)| icons_context.icons)
Bilal Elmoussaoui's avatar
Bilal Elmoussaoui committed
41 42
            .flatten()
            .collect();
43 44 45 46 47 48 49 50 51 52
        let shipped_icons: Vec<Icon> = self
            .shipped_icons
            .borrow()
            .clone()
            .into_iter()
            .map(|(_, icons_context)| icons_context.icons)
            .flatten()
            .collect();
        system_icons.extend_from_slice(&shipped_icons);
        system_icons
Bilal Elmoussaoui's avatar
Bilal Elmoussaoui committed
53 54
    }

55 56 57 58 59 60 61 62 63 64
    pub fn get_icon_byname(&self, icon_name: &str) -> Option<Icon> {
        let found_icons: Vec<Icon> = self
            .get_icons()
            .into_iter()
            .filter(|icon| {
                // filter out unneeded icons
                icon.name == icon_name
            })
            .collect();
        Some(found_icons.get(0)?.clone())
Bilal Elmoussaoui's avatar
Bilal Elmoussaoui committed
65 66
    }

67 68
    pub fn filter(&self, terms: Vec<&str>) -> Vec<Icon> {
        self.get_icons()
Bilal Elmoussaoui's avatar
Bilal Elmoussaoui committed
69
            .into_iter()
70 71 72
            .filter(|icon| {
                // filter out unneeded icons
                terms.iter().any(|k| icon.should_display(k))
Bilal Elmoussaoui's avatar
Bilal Elmoussaoui committed
73 74 75 76
            })
            .collect()
    }

Bilal Elmoussaoui's avatar
Bilal Elmoussaoui committed
77 78 79 80 81 82 83
    fn init(&self) {
        if let Err(err) = self.init_shipped_icons() {
            error!("Failed to init the shipped icons?? {}", err);
        }
        if let Err(err) = self.init_system_icons() {
            error!("Failed to init system icons?? {}", err)
        }
84 85
    }

Julian Hofer's avatar
Julian Hofer committed
86
    fn init_shipped_icons(&self) -> Result<()> {
Bilal Elmoussaoui's avatar
Bilal Elmoussaoui committed
87
        let dev_kit_file: PathBuf = [config::PKGDATADIR, "icons_dev_kit.json"].iter().collect();
88
        let file = File::open(dev_kit_file)?;
Bilal Elmoussaoui's avatar
Bilal Elmoussaoui committed
89 90
        let reader = BufReader::new(file);

91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
        let dev_kit_icons: Vec<Icon> = serde_json::from_reader(reader)?;
        dev_kit_icons.iter().for_each(|icon| {
            self.shipped_icons
                .borrow_mut()
                .entry(icon.context.clone())
                .and_modify(|current_icons| {
                    current_icons.icons.push(icon.clone());
                })
                .or_insert(IconsContext {
                    icons: vec![icon.clone()],
                    context: icon.context.clone(),
                    is_system: icon.is_system,
                });
        });
        Ok(())
    }
Bilal Elmoussaoui's avatar
Bilal Elmoussaoui committed
107

Julian Hofer's avatar
Julian Hofer committed
108
    fn init_system_icons(&self) -> Result<()> {
Bilal Elmoussaoui's avatar
Bilal Elmoussaoui committed
109 110 111 112 113 114 115 116 117 118 119
        // Load default theme icons
        let theme = gtk::IconTheme::get_default().unwrap();
        let legacy_contexts = vec!["Legacy"];
        let icons_blacklist = vec![
            "gesture-rotate-clockwise-symbolic",
            "gesture-pinch-symbolic",
            "gesture-two-finger-swipe-left-symbolic",
            "gesture-two-finger-swipe-right-symbolic",
            "gesture-stretch-symbolic",
            "gesture-rotate-anticlockwise-symbolic",
        ];
120
        for context in theme.list_contexts().iter() {
Bilal Elmoussaoui's avatar
Bilal Elmoussaoui committed
121 122 123 124 125 126 127 128 129 130
            let context_str = context.as_str();
            if legacy_contexts.contains(&context_str) {
                continue;
            }

            let mut icons: Vec<Icon> = theme
                .list_icons(Some(context_str))
                .into_iter()
                .filter(|icon_name| {
                    // filter out unneeded icons
131
                    !icons_blacklist.contains(&icon_name.as_str()) && icon_name.ends_with("-symbolic") && !icon_name.contains('.')
Bilal Elmoussaoui's avatar
Bilal Elmoussaoui committed
132 133 134 135
                })
                .map(|icon_name| Icon {
                    name: icon_name.as_str().to_string(),
                    is_system: true,
136 137
                    tags: Vec::new(),
                    context: context_str.to_string(),
Bilal Elmoussaoui's avatar
Bilal Elmoussaoui committed
138 139
                })
                .collect();
140
            icons.sort_by(|a, b| a.name.cmp(&b.name));
141 142 143
            if icons.is_empty() {
                continue;
            }
144 145 146 147 148 149 150 151 152
            let context = context_str.to_string();
            self.system_icons.borrow_mut().insert(
                context.clone(),
                IconsContext {
                    icons,
                    is_system: true,
                    context,
                },
            );
Bilal Elmoussaoui's avatar
Bilal Elmoussaoui committed
153
        }
154
        Ok(())
Bilal Elmoussaoui's avatar
Bilal Elmoussaoui committed
155 156
    }
}