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
//! Commands that control toggle.

use parking_lot::Mutex;
use std::{fmt, sync::Arc};
use zng_var::AnyVarValue;

use zng_wgt::prelude::*;

use super::SELECTOR;

command! {
    /// Represents the **toggle** action.
    ///
    /// # Handlers
    ///
    /// * [`checked`]: The property toggles for no param and or sets to the `bool` param or to
    /// the `Option<bool>` param coercing `None` to `false`.
    ///
    /// * [`checked_opt`]: The property cycles or toggles depending on [`tristate`] for no params, otherwise
    /// it sets the `bool` or `Option<bool>` param.
    ///
    /// * [`value`]: The property toggles select/unselect the value for no params, otherwise it selects the value
    /// for param `true` or `Some(true)` and deselects the value for param `false` or `None::<bool>`. Note that you
    /// can also use the [`SELECT_CMD`] for value.
    ///
    /// [`checked`]: fn@super::checked
    /// [`checked_opt`]: fn@super::checked_opt
    /// [`tristate`]: fn@super::tristate
    /// [`value`]: fn@super::value
    pub static TOGGLE_CMD;

    /// Represents the **select** action.
    ///
    /// # Handlers
    ///
    /// * [`value`]: The property selects the value if the command has no param.
    ///
    /// * [`selector`]: The property applies the [`SelectOp`] param.
    ///
    /// [`value`]: fn@super::value
    /// [`selector`]: fn@super::selector
    pub static SELECT_CMD;
}

/// Represents a select operation that can be send to [`selector`] using [`SELECT_CMD`].
///
/// [`selector`]: fn@super::selector
#[derive(Clone)]
pub struct SelectOp {
    op: Arc<Mutex<dyn FnMut() + Send>>,
}
impl fmt::Debug for SelectOp {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("SelectOp").finish_non_exhaustive()
    }
}
impl SelectOp {
    /// New (de)select operation.
    ///
    /// The [`selector`] property handles [`SELECT_CMD`] by calling `op` during event handling.
    /// You can use [`SELECTOR`] to get and set the selection.
    ///
    /// [`selector`]: fn@super::selector
    pub fn new(op: impl FnMut() + Send + 'static) -> Self {
        Self {
            op: Arc::new(Mutex::new(op)),
        }
    }

    /// Select the `value`.
    pub fn select(value: Box<dyn AnyVarValue>) -> Self {
        let mut value = Some(value);
        Self::new(move || {
            if let Some(value) = value.take() {
                if let Err(e) = SELECTOR.get().select(value) {
                    tracing::error!("select error: {e}");
                }
            }
        })
    }

    /// Deselect the `value`.
    pub fn deselect(value: Box<dyn AnyVarValue>) -> Self {
        Self::new(move || {
            if let Err(e) = SELECTOR.get().deselect(&*value) {
                tracing::error!("deselect error: {e}");
            }
        })
    }

    /// Run the operation.
    pub fn call(&self) {
        (self.op.lock())()
    }
}