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
use std::rc::Rc;
use std::cell::RefCell;
use crate::{ContainerWidget, DisplayBuffer, FrameWidget, PositioningAlgorithm, Widget};
use crate::common::{
BoundingBox,
BorderStyle
};
/// #### Description
/// A frame widget that has a border.
///
pub struct BorderedFrameWidget {
/// #### Description
/// A basic frame widget
///
frame: Rc<RefCell<FrameWidget>>,
/// #### Description
/// The style for the border of the widget
///
border_style: BorderStyle,
/// #### Description
/// The optional title of the frame
///
title: Option<String>
}
impl BorderedFrameWidget {
/// #### Description
/// Creates a bordered frame widget
///
/// #### Arguments
/// * `x`: [u32] - The x position of the widget
/// * `y`: [u32] - The y position of the widget
/// * `width`: [u32] - The width of the widget
/// * `height`: [u32] - The height of the widget
/// * `title`: [Option]<&[str]> - The optional title of the widget
/// * `border_style`: [BorderStyle] - The border style for the widget
///
/// #### Returns
/// [Rc]<[RefCell]<[BorderedFrameWidget]>> - A bordered frame widget with
/// the specified attributes
///
pub fn new(
x: i32,
y: i32,
width: u32,
height: u32,
title: Option<&str>,
border_style: BorderStyle
) -> Rc<RefCell<Self>> {
let frame = FrameWidget::new(x, y, width, height);
return Rc::new(RefCell::new(Self {
frame,
title: title.map(|str| {str.to_string()}),
border_style
}));
}
}
impl Widget for BorderedFrameWidget {
fn draw(
&mut self,
positioning_algorithm: &Box<dyn PositioningAlgorithm>,
display_buffer: &mut DisplayBuffer
) {
let bounds = self.frame.borrow().get_bounding_box();
// The position of the widget relative to the viewport
let abs_pos = positioning_algorithm.calculate_position(
bounds.get_position()
);
self.frame.borrow_mut().draw(positioning_algorithm, display_buffer);
// draw border and title
let left_bound = abs_pos.get_x();
let right_bound = left_bound + bounds.get_width() as i32;
let top_bound = abs_pos.get_y();
let bottom_bound = top_bound + bounds.get_height() as i32;
for y in top_bound..bottom_bound {
for x in left_bound..right_bound {
if x == left_bound && y == top_bound {
// top left
display_buffer.set_char(
self.border_style.get_top_left(),
x, y
);
}
else if x == right_bound - 1 && y == top_bound {
// top right
display_buffer.set_char(
self.border_style.get_top_right(),
x, y
);
}
else if x == left_bound && y == bottom_bound - 1 {
// bottom left
display_buffer.set_char(
self.border_style.get_bottom_left(),
x, y
);
}
else if x == right_bound - 1 && y == bottom_bound - 1 {
// bottom right
display_buffer.set_char(
self.border_style.get_bottom_right(),
x, y
);
}
else if x == left_bound || x == right_bound - 1 {
// vertical
display_buffer.set_char(
self.border_style.get_vertical(),
x, y
);
}
else if y == top_bound || y == bottom_bound - 1 {
// horizontal
display_buffer.set_char(
self.border_style.get_horizontal(),
x, y
);
}
}
}
if let Some(title) = &self.title {
if left_bound+1 <= right_bound-1 {
let chars = title.chars().collect::<Vec<_>>();
for x in left_bound+1..right_bound-1 {
if let Some(c) = chars.get((x - (left_bound + 1)) as usize) {
display_buffer.set_char(*c, x, top_bound);
}
else {
break;
}
}
}
}
}
fn get_bounding_box(&self) -> BoundingBox {
return self.frame.borrow().get_bounding_box();
}
}
impl ContainerWidget for BorderedFrameWidget {
fn add_child(
&mut self,
positioning_algorithm: Box<dyn PositioningAlgorithm>,
widget: Rc<RefCell<dyn Widget>>
) {
self.frame.borrow_mut().add_child(positioning_algorithm, widget);
}
}