1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Take a look at the license at the top of the repository in the LICENSE file.

use crate::{ActionMap, SimpleAction};
use glib::{IsA, Variant};

/// This struct defines a single action. It is for use with
/// [`ActionMapExtManual::add_action_entries()`][crate::prelude::ActionMapExtManual::add_action_entries()].
///
/// The order of the items in the structure are intended to reflect
/// frequency of use. It is permissible to use an incomplete initialiser
/// in order to leave some of the later values as [`None`]. All values
/// after `name` are optional. Additional optional fields may be added in
/// the future.
///
/// See [`ActionMapExtManual::add_action_entries()`][crate::prelude::ActionMapExtManual::add_action_entries()] for an example.
#[doc(alias = "GActionEntry")]
pub struct ActionEntry<O>
where
    O: IsA<ActionMap>,
{
    name: String,
    parameter_type: Option<String>,
    state: Option<String>,
    pub(crate) activate: Option<Box<dyn Fn(&O, &SimpleAction, Option<&Variant>) + 'static>>,
    pub(crate) change_state: Option<Box<dyn Fn(&O, &SimpleAction, Option<&Variant>) + 'static>>,
}

impl<O> ActionEntry<O>
where
    O: IsA<ActionMap>,
{
    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn parameter_type(&self) -> Option<&str> {
        self.parameter_type.as_deref()
    }

    pub fn state(&self) -> Option<&str> {
        self.state.as_deref()
    }

    pub fn builder(name: &str) -> ActionEntryBuilder<O> {
        ActionEntryBuilder::new(name)
    }
}

impl<O> std::fmt::Debug for ActionEntry<O>
where
    O: IsA<ActionMap>,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("ActionEntry")
            .field("name", &self.name())
            .field("parameter_type", &self.parameter_type())
            .field("state", &self.state())
            .finish()
    }
}

#[derive(Debug)]
pub struct ActionEntryBuilder<O>(ActionEntry<O>)
where
    O: IsA<ActionMap>;

impl<O> ActionEntryBuilder<O>
where
    O: IsA<ActionMap>,
{
    pub fn new(name: &str) -> Self {
        Self(ActionEntry {
            name: name.to_owned(),
            parameter_type: Default::default(),
            state: Default::default(),
            activate: Default::default(),
            change_state: Default::default(),
        })
    }

    pub fn parameter_type(mut self, parameter_type: &str) -> Self {
        self.0.parameter_type = Some(parameter_type.to_owned());
        self
    }

    pub fn state(mut self, state: &str) -> Self {
        self.0.state = Some(state.to_owned());
        self
    }

    pub fn activate<F: Fn(&O, &SimpleAction, Option<&Variant>) + 'static>(
        mut self,
        callback: F,
    ) -> Self {
        self.0.activate = Some(Box::new(callback));
        self
    }

    pub fn change_state<F: Fn(&O, &SimpleAction, Option<&Variant>) + 'static>(
        mut self,
        callback: F,
    ) -> Self {
        self.0.change_state = Some(Box::new(callback));
        self
    }

    pub fn build(self) -> ActionEntry<O> {
        self.0
    }
}

#[cfg(test)]
mod tests {
    use crate::prelude::*;

    use super::*;

    #[test]
    fn action_entry() {
        let app = crate::Application::new(None, Default::default());

        let close = ActionEntry::builder("close")
            .activate(move |_app, _, _| {
                //Do something
            })
            .build();
        app.add_action_entries(vec![close]).unwrap();
        assert!(app.lookup_action("close").is_some());
    }
}