rat_popup/
lib.rs

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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#![doc = include_str!("../readme.md")]
//
#![allow(clippy::collapsible_else_if)]

use ratatui::layout::Rect;

mod popup;

pub use popup::*;

pub mod event {
    use rat_event::*;

    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
    pub enum PopupOutcome {
        /// The given event has not been used at all.
        Continue,
        /// The event has been recognized, but nothing noticeable has changed.
        /// Further processing for this event may stop.
        /// Rendering the ui is not necessary.
        Unchanged,
        /// The event has been recognized and there is some change due to it.
        /// Further processing for this event may stop.
        /// Rendering the ui is advised.
        Changed,
        /// Popup should be hidden.
        Hide,
    }

    impl ConsumedEvent for PopupOutcome {
        fn is_consumed(&self) -> bool {
            *self != PopupOutcome::Continue
        }
    }

    impl From<PopupOutcome> for Outcome {
        fn from(value: PopupOutcome) -> Self {
            match value {
                PopupOutcome::Continue => Outcome::Continue,
                PopupOutcome::Unchanged => Outcome::Unchanged,
                PopupOutcome::Changed => Outcome::Changed,
                PopupOutcome::Hide => Outcome::Changed,
            }
        }
    }
}

/// Placement of the popup.
///
/// This enum is for use in a widget that then uses PopupCore
/// internally. Expose Placement to the users of your widget
/// to let them define a popup placement. Convert the Placement
/// to a PopupConstraint internally when forwarding this
/// to PopupCore.
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum Placement {
    /// Use the render-area for the popup as is.
    #[default]
    None,
    /// Place the popup above the given area. Aligned left.
    AboveLeft,
    /// Place the popup above the given area. Aligned centered.
    AboveCenter,
    /// Place the popup above the given area. Aligned right.
    AboveRight,
    /// Place the popup to the left of the given area. Aligned to the top.
    LeftTop,
    /// Place the popup to the left of the given area. Aligned in the middle.
    LeftMiddle,
    /// Place the popup to the left of the given area. Aligned to the bottom.
    LeftBottom,
    /// Place the popup to the right of the given area. Aligned to the top.
    RightTop,
    /// Place the popup to the right of the given area. Aligned in the middle.
    RightMiddle,
    /// Place the popup to the right of the given area. Aligned to the bottom.
    RightBottom,
    /// Place the popup below the given area. Aligned left.
    BelowLeft,
    /// Place the popup below the given area. Aligned centered.
    BelowCenter,
    /// Place the popup below the given area. Aligned right.
    BelowRight,
    /// Place above. Aligned left.
    Above,
    /// Place below: Aligned right.
    Below,
    /// Place left. Aligned top.
    Left,
    /// Place right. Aligned top.
    Right,
    /// Above or below dependent on available space. Aligned left.
    AboveOrBelow,
    /// Below or above dependent on available space. Aligned left.
    BelowOrAbove,
    /// Use the render-area for the popup, but place it at position (x,y).
    Position(u16, u16),
}

impl Placement {
    pub fn into_constraint(self, rel_area: Rect) -> PopupConstraint {
        match self {
            Placement::None => PopupConstraint::None,
            Placement::AboveLeft => PopupConstraint::AboveLeft(rel_area),
            Placement::AboveCenter => PopupConstraint::AboveCenter(rel_area),
            Placement::AboveRight => PopupConstraint::AboveRight(rel_area),
            Placement::LeftTop => PopupConstraint::LeftTop(rel_area),
            Placement::LeftMiddle => PopupConstraint::LeftMiddle(rel_area),
            Placement::LeftBottom => PopupConstraint::LeftBottom(rel_area),
            Placement::RightTop => PopupConstraint::RightTop(rel_area),
            Placement::RightMiddle => PopupConstraint::RightMiddle(rel_area),
            Placement::RightBottom => PopupConstraint::RightBottom(rel_area),
            Placement::BelowLeft => PopupConstraint::BelowLeft(rel_area),
            Placement::BelowCenter => PopupConstraint::BelowCenter(rel_area),
            Placement::BelowRight => PopupConstraint::BelowRight(rel_area),
            Placement::Above => PopupConstraint::Above(rel_area),
            Placement::Below => PopupConstraint::Below(rel_area),
            Placement::Left => PopupConstraint::Left(rel_area),
            Placement::Right => PopupConstraint::Right(rel_area),
            Placement::AboveOrBelow => PopupConstraint::AboveOrBelow(rel_area),
            Placement::BelowOrAbove => PopupConstraint::BelowOrAbove(rel_area),
            Placement::Position(x, y) => PopupConstraint::Position(x, y),
        }
    }
}

/// Placement relative to the widget area + the widget area.
///
/// The render() call for PopupCore will only use the size of
/// the area given to the render call as the size of the popup.
/// It will calculate the position of the popup given one of
/// these constraints.
///
/// If you build a widget that uses a PopupCore internally you
/// will rather use Placement as a parameter
///
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum PopupConstraint {
    /// Use the render-area for the popup as is.
    #[default]
    None,
    /// Place the popup above the given area. Aligned left.
    AboveLeft(Rect),
    /// Place the popup above the given area. Aligned centered.
    AboveCenter(Rect),
    /// Place the popup above the given area. Aligned right.
    AboveRight(Rect),
    /// Place the popup to the left of the given area. Aligned to the top.
    LeftTop(Rect),
    /// Place the popup to the left of the given area. Aligned in the middle.
    LeftMiddle(Rect),
    /// Place the popup to the left of the given area. Aligned to the bottom.
    LeftBottom(Rect),
    /// Place the popup to the right of the given area. Aligned to the top.
    RightTop(Rect),
    /// Place the popup to the right of the given area. Aligned in the middle.
    RightMiddle(Rect),
    /// Place the popup to the right of the given area. Aligned to the bottom.
    RightBottom(Rect),
    /// Place the popup below the given area. Aligned left.
    BelowLeft(Rect),
    /// Place the popup below the given area. Aligned centered.
    BelowCenter(Rect),
    /// Place the popup below the given area. Aligned right.
    BelowRight(Rect),
    /// Place above. Aligned left.
    Above(Rect),
    /// Place below: Aligned right.
    Below(Rect),
    /// Place left. Aligned top.
    Left(Rect),
    /// Place right. Aligned top.
    Right(Rect),
    /// Above or below dependent on available space. Aligned left.
    AboveOrBelow(Rect),
    /// Below or above dependent on available space. Aligned left.
    BelowOrAbove(Rect),
    /// Use the render-area for the popup, but place it at position (x,y).
    Position(u16, u16),
}

mod _private {
    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct NonExhaustive;
}