sysd-manager 2.19.4

Application to empower user to manage their <b>systemd units</b> via Graphical User Interface. Not only are you able to make changes to the enablement and running status of each of the units, but you will also be able to view and modify their unit files and check the journal logs.
use std::cell::Ref;

use super::data::{
    KEY_PREF_ORIENTATION_MODE, KEY_PREF_PREFERRED_COLOR_SCHEME, OrientationMode,
    PreferredColorScheme,
};
use adw::{prelude::*, subclass::prelude::*};
use gtk::glib::{self, translate::IntoGlib};

use sourceview5::prelude::ToValue;
use strum::IntoEnumIterator;

glib::wrapper! {
    pub struct DropDownItem(ObjectSubclass<imp::DropDownItemImpl>);
}

impl Default for DropDownItem {
    fn default() -> Self {
        glib::Object::new()
    }
}

impl DropDownItem {
    pub fn new(icon: &str, text: &str) -> Self {
        let o: DropDownItem = glib::Object::new();
        o.imp().assign(icon, text);
        o
    }
}

mod imp {
    use std::cell::RefCell;

    use gtk::{glib, prelude::*, subclass::prelude::*};

    #[derive(Debug, Default, glib::Properties)]
    #[properties(wrapper_type = super::DropDownItem)]
    pub struct DropDownItemImpl {
        #[property(get, set)]
        pub text: RefCell<String>,
        #[property(get, set)]
        pub icon: RefCell<String>,
    }

    impl DropDownItemImpl {
        pub(super) fn assign(&self, icon: &str, text: &str) {
            self.text.replace(text.to_owned());
            self.icon.replace(icon.to_owned());
        }
    }

    #[glib::object_subclass]
    impl ObjectSubclass for DropDownItemImpl {
        const NAME: &'static str = "DropDownItem";
        type Type = super::DropDownItem;
    }

    #[glib::derived_properties]
    impl ObjectImpl for DropDownItemImpl {}
}

pub(super) fn build_pane_orientation_selector(
    app_orientation: &adw::ComboRow,
    settings: &gio::Settings,
) {
    let store = gio::ListStore::new::<glib::BoxedAnyObject>();

    for color_scheme in OrientationMode::iter() {
        let boxed = glib::BoxedAnyObject::new(color_scheme);
        store.append(&boxed);
    }

    app_orientation.set_model(Some(&store));

    let factory = gtk::SignalListItemFactory::new();
    factory.connect_setup(|_, object| {
        let list_item = object
            .downcast_ref::<gtk::ListItem>()
            .expect("item.downcast_ref::<gtk::ListItem>()");

        let img = gtk::Image::new();
        let label = gtk::Label::builder()
            .xalign(0.0)
            .wrap_mode(gtk::pango::WrapMode::None)
            .build();

        let gbox = gtk::Box::new(gtk::Orientation::Horizontal, 5);

        gbox.append(&img);
        gbox.append(&label);
        //println!("tree {}", inscription.css_name());
        list_item.set_child(Some(&gbox));
    });
    factory.connect_bind(|_, object| {
        let list_item = object
            .downcast_ref::<gtk::ListItem>()
            .expect("item.downcast_ref::<gtk::ListItem>()");

        let gbox = list_item.child().and_downcast::<gtk::Box>().unwrap();

        let img = gbox
            .first_child()
            .expect("need a first_child")
            .downcast::<gtk::Image>()
            .expect("supposed to be gtk::Image");

        let label = gbox
            .last_child()
            .expect("need alast child")
            .downcast::<gtk::Label>()
            .expect("supposed to be gtk::Label");

        let boxed = list_item
            .item()
            .and_downcast::<glib::BoxedAnyObject>()
            .unwrap();

        let mode: Ref<'_, OrientationMode> = boxed.borrow();

        img.set_icon_name(mode.icon_name());
        label.set_label(&mode.label());
    });

    app_orientation.set_factory(Some(&factory));

    settings
        .bind(KEY_PREF_ORIENTATION_MODE, app_orientation, "selected")
        .mapping(|variant, _| {
            let orientation_mode_key = variant.get::<String>().unwrap_or_default();
            let orientation_mode: OrientationMode = orientation_mode_key.into();
            Some((orientation_mode as u32).to_value())
        })
        .set_mapping(|value, _| {
            let drop_own_index = value.get::<u32>().unwrap_or(0);
            let orientation_mode: OrientationMode = drop_own_index.into();
            Some(orientation_mode.key().to_variant())
        })
        .build();
}

pub(super) fn build_preferred_color_scheme(
    preferred_color_scheme: &adw::ComboRow,
    settings: &gio::Settings,
) {
    let model = gio::ListStore::new::<glib::BoxedAnyObject>();

    for color_scheme in PreferredColorScheme::iter() {
        let boxed = glib::BoxedAnyObject::new(color_scheme);
        model.append(&boxed);
    }

    preferred_color_scheme.set_model(Some(&model));

    let empty: [gtk::Expression; 0] = [];
    let expression = gtk::ClosureExpression::new::<String>(
        empty,
        glib::closure!(|o: glib::BoxedAnyObject| {
            let color_ref: Ref<'_, PreferredColorScheme> = o.borrow();
            color_ref.text()
        }),
    );

    preferred_color_scheme.set_expression(Some(expression));

    preferred_color_scheme.connect_selected_item_notify(|combo_box| {
        let selected_item = combo_box.selected_item();

        let Some(color_scheme) = selected_item else {
            return;
        };

        let binding = color_scheme
            .downcast::<glib::BoxedAnyObject>()
            .expect("Needs to be BoxedAnyObject");
        let color_scheme: Ref<'_, PreferredColorScheme> = binding.borrow();

        let manager = adw::StyleManager::default();
        manager.set_color_scheme(color_scheme.color_scheme());
    });

    settings
        .bind(
            KEY_PREF_PREFERRED_COLOR_SCHEME,
            preferred_color_scheme,
            "selected",
        )
        .mapping(|a, _| {
            let v = a.get::<i32>().unwrap();

            let drop_own_index = if let Some((drop_own_index, _)) = PreferredColorScheme::iter()
                .enumerate()
                .find(|(_idx, color_scheme)| v == color_scheme.color_scheme().into_glib())
            {
                drop_own_index as i32
            } else {
                0
            };

            let value = drop_own_index.to_value();
            Some(value)
        })
        .set_mapping(|value, _| {
            let drop_own_index = value.get::<u32>().unwrap();
            let mut color_scheme_selected = PreferredColorScheme::Default;
            for (idx, color_scheme) in PreferredColorScheme::iter().enumerate() {
                color_scheme_selected = color_scheme;
                if drop_own_index == idx as u32 {
                    break;
                }
            }

            let variant = color_scheme_selected
                .color_scheme()
                .into_glib()
                .to_variant();

            Some(variant)
        })
        .build();
}