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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
use crate::{
    event::AnyCb,
    view::{Selector, View, ViewNotFound},
    views::BoxedView,
};

/// Identifies a screen in the cursive root.
pub type ScreenId = usize;

/// A view that can switch between different screens.
pub struct ScreensView<V = BoxedView> {
    screens: Vec<V>,
    active_screen: ScreenId,
}

new_default!(ScreensView<V>);

impl<V> ScreensView<V> {
    /// Creates a new empty `ScreensView`.
    pub fn new() -> Self {
        ScreensView {
            screens: Vec::new(),
            active_screen: 0,
        }
    }

    /// Creates a new `ScreensView` with a single screen.
    pub fn single_screen(v: V) -> Self {
        ScreensView {
            screens: vec![v],
            active_screen: 0,
        }
    }

    /// Returns a reference to the currently active screen.
    ///
    /// Returns `None` if there is no active screen.
    pub fn screen(&self) -> Option<&V> {
        self.screens.get(self.active_screen)
    }

    /// Returns a mutable reference to the currently active screen.
    pub fn screen_mut(&mut self) -> Option<&mut V> {
        let id = self.active_screen;
        self.screens.get_mut(id)
    }

    /// Returns the id of the currently active screen.
    pub fn active_screen(&self) -> ScreenId {
        self.active_screen
    }

    /// Adds a new screen, and returns its ID.
    pub fn add_screen(&mut self, v: V) -> ScreenId {
        let res = self.screens.len();
        self.screens.push(v);
        res
    }

    /// Convenient method to create a new screen, and set it as active.
    pub fn add_active_screen(&mut self, v: V) -> ScreenId {
        let res = self.add_screen(v);
        self.set_active_screen(res);
        res
    }

    /// Sets the active screen. Panics if no such screen exist.
    pub fn set_active_screen(&mut self, screen_id: ScreenId) {
        if screen_id >= self.screens.len() {
            panic!(
                "Tried to set an invalid screen ID: {}, but only {} \
                 screens present.",
                screen_id,
                self.screens.len()
            );
        }
        self.active_screen = screen_id;
    }
}

impl ScreensView<crate::views::StackView> {
    /// Draws the background.
    ///
    /// This is mostly used internally by cursive. You probably just want
    /// `View::draw`.
    pub fn draw_bg(&self, printer: &crate::Printer) {
        if let Some(screen) = self.screen() {
            screen.draw_bg(printer);
        }
    }

    /// Draws the foreground.
    ///
    /// This is mostly used internally by cursive. You probably just want
    /// `View::draw`.
    pub fn draw_fg(&self, printer: &crate::Printer) {
        if let Some(screen) = self.screen() {
            screen.draw_fg(printer);
        }
    }
}

impl<V> crate::view::ViewWrapper for ScreensView<V>
where
    V: View,
{
    type V = V;

    fn with_view<F, R>(&self, f: F) -> Option<R>
    where
        F: FnOnce(&Self::V) -> R,
    {
        self.screen().map(f)
    }

    fn with_view_mut<F, R>(&mut self, f: F) -> Option<R>
    where
        F: FnOnce(&mut Self::V) -> R,
    {
        self.screen_mut().map(f)
    }

    fn wrap_call_on_any<'a>(
        &mut self,
        selector: &Selector<'_>,
        callback: AnyCb<'a>,
    ) {
        for screen in &mut self.screens {
            screen.call_on_any(selector, callback);
        }
    }

    fn wrap_focus_view(
        &mut self,
        selector: &Selector<'_>,
    ) -> Result<(), ViewNotFound> {
        for (i, child) in self.screens.iter_mut().enumerate() {
            if child.focus_view(selector).is_ok() {
                self.active_screen = i;
                return Ok(());
            }
        }

        Err(ViewNotFound)
    }
}