xref: /DragonOS/kernel/src/libs/lib_ui/textui.rs (revision 6b4e7a2972cc06663754c0e35a0e541987006fa4)
1 use crate::{
2     driver::{
3         uart::uart_device::{c_uart_send, c_uart_send_str, UartPort},
4         video::video_refresh_manager,
5     },
6     kdebug, kinfo,
7     libs::{
8         lib_ui::font::FONT_8x16,
9         rwlock::RwLock,
10         spinlock::{SpinLock, SpinLockGuard},
11     },
12     syscall::SystemError,
13 };
14 use alloc::{boxed::Box, collections::LinkedList, string::ToString};
15 use alloc::{sync::Arc, vec::Vec};
16 use core::{
17     fmt::Debug,
18     intrinsics::unlikely,
19     ops::{Add, AddAssign, Sub},
20     sync::atomic::{AtomicBool, AtomicI32, AtomicU32, Ordering},
21 };
22 
23 use super::{
24     screen_manager::{
25         scm_register, ScmBuffer, ScmBufferInfo, ScmFramworkType, ScmUiFramework,
26         ScmUiFrameworkMetadata,
27     },
28     textui_no_alloc::no_init_textui_putchar_window,
29 };
30 
31 /// 声明全局的TEXTUI_FRAMEWORK
32 static mut __TEXTUI_FRAMEWORK: Option<Arc<TextUiFramework>> = None;
33 
34 /// 每个字符的宽度和高度(像素)
35 pub const TEXTUI_CHAR_WIDTH: u32 = 8;
36 
37 pub const TEXTUI_CHAR_HEIGHT: u32 = 16;
38 
39 pub static mut TEXTUI_IS_INIT: bool = false;
40 
41 pub static ENABLE_PUT_TO_WINDOW: AtomicBool = AtomicBool::new(true);
42 
43 /// 获取TEXTUI_FRAMEWORK的可变实例
44 pub fn textui_framework() -> Arc<TextUiFramework> {
45     unsafe {
46         return __TEXTUI_FRAMEWORK
47             .as_ref()
48             .expect("Textui framework has not been initialized yet!")
49             .clone();
50     }
51 }
52 
53 /// 初始化TEXTUI_FRAMEWORK
54 pub unsafe fn textui_framwork_init() {
55     if __TEXTUI_FRAMEWORK.is_none() {
56         kinfo!("textuiframework init");
57         let metadata = ScmUiFrameworkMetadata::new("TextUI".to_string(), ScmFramworkType::Text);
58         kdebug!("textui metadata: {:?}", metadata);
59         // 为textui框架生成第一个窗口
60         let vlines_num = (metadata.buf_info().height() / TEXTUI_CHAR_HEIGHT) as usize;
61 
62         let chars_num = (metadata.buf_info().width() / TEXTUI_CHAR_WIDTH) as usize;
63 
64         let initial_window = TextuiWindow::new(
65             WindowFlag::TEXTUI_CHROMATIC,
66             vlines_num as i32,
67             chars_num as i32,
68         );
69 
70         let current_window: Arc<SpinLock<TextuiWindow>> = Arc::new(SpinLock::new(initial_window));
71 
72         let default_window = current_window.clone();
73 
74         // 生成窗口链表,并把上面窗口添加进textui框架的窗口链表中
75         let window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>> =
76             Arc::new(SpinLock::new(LinkedList::new()));
77         window_list.lock().push_back(current_window.clone());
78 
79         __TEXTUI_FRAMEWORK = Some(Arc::new(TextUiFramework::new(
80             metadata,
81             window_list,
82             current_window,
83             default_window,
84         )));
85 
86         scm_register(textui_framework()).expect("register textui framework failed");
87         kdebug!("textui framework init success");
88 
89         c_uart_send_str(
90             UartPort::COM1.to_u16(),
91             "\ntext ui initialized\n\0".as_ptr(),
92         );
93         unsafe { TEXTUI_IS_INIT = true };
94     } else {
95         panic!("Try to init TEXTUI_FRAMEWORK twice!");
96     }
97 }
98 // window标志位
99 bitflags! {
100     pub struct WindowFlag: u8 {
101         // 采用彩色字符
102         const TEXTUI_CHROMATIC = 1 << 0;
103     }
104 }
105 
106 /**
107  * @brief 黑白字符对象
108  *
109  */
110 #[derive(Clone, Debug)]
111 struct TextuiCharNormal {
112     _data: u8,
113 }
114 
115 #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Default)]
116 pub struct LineId(i32);
117 impl LineId {
118     pub fn new(num: i32) -> Self {
119         LineId(num)
120     }
121 
122     pub fn check(&self, max: i32) -> bool {
123         self.0 < max && self.0 >= 0
124     }
125 
126     pub fn data(&self) -> i32 {
127         self.0
128     }
129 }
130 impl Add<i32> for LineId {
131     type Output = LineId;
132     fn add(self, rhs: i32) -> Self::Output {
133         LineId::new(self.0 + rhs)
134     }
135 }
136 impl Sub<i32> for LineId {
137     type Output = LineId;
138 
139     fn sub(self, rhs: i32) -> Self::Output {
140         LineId::new(self.0 - rhs)
141     }
142 }
143 
144 impl Into<i32> for LineId {
145     fn into(self) -> i32 {
146         self.0.clone()
147     }
148 }
149 impl Into<u32> for LineId {
150     fn into(self) -> u32 {
151         self.0.clone() as u32
152     }
153 }
154 impl Into<usize> for LineId {
155     fn into(self) -> usize {
156         self.0.clone() as usize
157     }
158 }
159 impl Sub<LineId> for LineId {
160     type Output = LineId;
161 
162     fn sub(mut self, rhs: LineId) -> Self::Output {
163         self.0 -= rhs.0;
164         return self;
165     }
166 }
167 impl AddAssign<LineId> for LineId {
168     fn add_assign(&mut self, rhs: LineId) {
169         self.0 += rhs.0;
170     }
171 }
172 #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Default)]
173 pub struct LineIndex(i32);
174 impl LineIndex {
175     pub fn new(num: i32) -> Self {
176         LineIndex(num)
177     }
178     pub fn check(&self, chars_per_line: i32) -> bool {
179         self.0 < chars_per_line && self.0 >= 0
180     }
181 }
182 impl Add<LineIndex> for LineIndex {
183     type Output = LineIndex;
184 
185     fn add(self, rhs: LineIndex) -> Self::Output {
186         LineIndex::new(self.0 + rhs.0)
187     }
188 }
189 impl Add<i32> for LineIndex {
190     // type Output = Self;
191     type Output = LineIndex;
192 
193     fn add(self, rhs: i32) -> Self::Output {
194         LineIndex::new(self.0 + rhs)
195     }
196 }
197 impl Sub<i32> for LineIndex {
198     type Output = LineIndex;
199 
200     fn sub(self, rhs: i32) -> Self::Output {
201         LineIndex::new(self.0 - rhs)
202     }
203 }
204 
205 impl Into<i32> for LineIndex {
206     fn into(self) -> i32 {
207         self.0.clone()
208     }
209 }
210 impl Into<u32> for LineIndex {
211     fn into(self) -> u32 {
212         self.0.clone() as u32
213     }
214 }
215 impl Into<usize> for LineIndex {
216     fn into(self) -> usize {
217         self.0.clone() as usize
218     }
219 }
220 #[derive(Copy, Clone, Debug)]
221 pub struct FontColor(u32);
222 #[allow(dead_code)]
223 impl FontColor {
224     pub const BLUE: FontColor = FontColor::new(0, 0, 0xff);
225     pub const RED: FontColor = FontColor::new(0xff, 0, 0);
226     pub const GREEN: FontColor = FontColor::new(0, 0xff, 0);
227     pub const WHITE: FontColor = FontColor::new(0xff, 0xff, 0xff);
228     pub const BLACK: FontColor = FontColor::new(0, 0, 0);
229     pub const YELLOW: FontColor = FontColor::new(0xff, 0xff, 0);
230     pub const ORANGE: FontColor = FontColor::new(0xff, 0x80, 0);
231     pub const INDIGO: FontColor = FontColor::new(0x00, 0xff, 0xff);
232     pub const PURPLE: FontColor = FontColor::new(0x80, 0x00, 0xff);
233 
234     pub const fn new(r: u8, g: u8, b: u8) -> Self {
235         let val = ((r as u32) << 16) | ((g as u32) << 8) | (b as u32);
236         return FontColor(val & 0x00ffffff);
237     }
238 }
239 
240 impl From<u32> for FontColor {
241     fn from(value: u32) -> Self {
242         return Self(value & 0x00ffffff);
243     }
244 }
245 impl Into<usize> for FontColor {
246     fn into(self) -> usize {
247         self.0.clone() as usize
248     }
249 }
250 impl Into<u32> for FontColor {
251     fn into(self) -> u32 {
252         self.0.clone()
253     }
254 }
255 impl Into<u16> for FontColor {
256     fn into(self) -> u16 {
257         self.0.clone() as u16
258     }
259 }
260 impl Into<u64> for FontColor {
261     fn into(self) -> u64 {
262         self.0.clone() as u64
263     }
264 }
265 
266 /// 彩色字符对象
267 
268 #[derive(Clone, Debug, Copy)]
269 pub struct TextuiCharChromatic {
270     c: Option<char>,
271 
272     // 前景色
273     frcolor: FontColor, // rgb
274 
275     // 背景色
276     bkcolor: FontColor, // rgb
277 }
278 
279 #[derive(Debug)]
280 pub struct TextuiBuf<'a> {
281     buf: Option<&'a mut [u32]>,
282     guard: Option<SpinLockGuard<'a, Box<[u32]>>>,
283 }
284 
285 impl TextuiBuf<'_> {
286     pub fn new(buf: &mut ScmBufferInfo) -> TextuiBuf {
287         let len = buf.buf_size() / 4;
288 
289         match &buf.buf {
290             ScmBuffer::DeviceBuffer(vaddr) => {
291                 return TextuiBuf {
292                     buf: Some(unsafe {
293                         core::slice::from_raw_parts_mut(vaddr.data() as *mut u32, len)
294                     }),
295                     guard: None,
296                 };
297             }
298 
299             ScmBuffer::DoubleBuffer(double_buffer) => {
300                 let guard: SpinLockGuard<'_, Box<[u32]>> = double_buffer.lock();
301 
302                 return TextuiBuf {
303                     buf: None,
304                     guard: Some(guard),
305                 };
306             }
307         }
308     }
309 
310     pub fn buf_mut(&mut self) -> &mut [u32] {
311         if let Some(buf) = &mut self.buf {
312             return buf;
313         } else {
314             return self.guard.as_mut().unwrap().as_mut();
315         }
316     }
317     pub fn put_color_in_pixel(&mut self, color: u32, index: usize) {
318         let buf: &mut [u32] = self.buf_mut();
319         buf[index] = color;
320     }
321     pub fn get_index_of_next_line(now_index: usize) -> usize {
322         textui_framework().metadata.read().buf_info().width() as usize + now_index
323     }
324     pub fn get_index_by_x_y(x: usize, y: usize) -> usize {
325         textui_framework().metadata.read().buf_info().width() as usize * y + x
326     }
327     pub fn get_start_index_by_lineid_lineindex(lineid: LineId, lineindex: LineIndex) -> usize {
328         //   x 左上角列像素点位置
329         //   y 左上角行像素点位置
330         let index_x: u32 = lineindex.into();
331         let x: u32 = index_x * TEXTUI_CHAR_WIDTH;
332 
333         let id_y: u32 = lineid.into();
334         let y: u32 = id_y * TEXTUI_CHAR_HEIGHT;
335 
336         TextuiBuf::get_index_by_x_y(x as usize, y as usize)
337     }
338 }
339 
340 #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
341 pub struct Font([u8; 16]);
342 impl Font {
343     #[inline]
344     pub fn get_font(character: char) -> Font {
345         let x = FONT_8x16.char_map(character);
346 
347         let mut data = [0u8; 16];
348         data.copy_from_slice(x);
349         return Font(data);
350     }
351     pub fn is_frcolor(&self, height: usize, width: usize) -> bool {
352         let w = self.0[height];
353         let testbit = 1 << (8 - width);
354         w & testbit != 0
355     }
356 }
357 
358 impl TextuiCharChromatic {
359     pub fn new(c: Option<char>, frcolor: FontColor, bkcolor: FontColor) -> Self {
360         TextuiCharChromatic {
361             c,
362             frcolor,
363             bkcolor,
364         }
365     }
366 
367     /// 将该字符对象输出到缓冲区
368     /// ## 参数
369     /// -line_id 要放入的真实行号
370     /// -index 要放入的真实列号
371     pub fn textui_refresh_character(
372         &self,
373         lineid: LineId,
374         lineindex: LineIndex,
375     ) -> Result<i32, SystemError> {
376         // 找到要渲染的字符的像素点数据
377 
378         let font: Font = Font::get_font(self.c.unwrap_or(' '));
379 
380         let mut count = TextuiBuf::get_start_index_by_lineid_lineindex(lineid, lineindex);
381 
382         let mut _binding = textui_framework().metadata.read().buf_info();
383 
384         let mut buf = TextuiBuf::new(&mut _binding);
385 
386         // 在缓冲区画出一个字体,每个字体有TEXTUI_CHAR_HEIGHT行,TEXTUI_CHAR_WIDTH列个像素点
387         for i in 0..TEXTUI_CHAR_HEIGHT {
388             let start = count;
389             for j in 0..TEXTUI_CHAR_WIDTH {
390                 if font.is_frcolor(i as usize, j as usize) {
391                     // 字,显示前景色
392                     buf.put_color_in_pixel(self.frcolor.into(), count);
393                 } else {
394                     // 背景色
395                     buf.put_color_in_pixel(self.bkcolor.into(), count);
396                 }
397                 count += 1;
398             }
399             count = TextuiBuf::get_index_of_next_line(start);
400         }
401 
402         return Ok(0);
403     }
404 
405     pub fn no_init_textui_render_chromatic(&self, lineid: LineId, lineindex: LineIndex) {
406         // 找到要渲染的字符的像素点数据
407         let font = Font::get_font(self.c.unwrap_or(' '));
408 
409         //   x 左上角列像素点位置
410         //   y 左上角行像素点位置
411         let index_x: u32 = lineindex.into();
412         let x: u32 = index_x * TEXTUI_CHAR_WIDTH;
413 
414         let id_y: u32 = lineid.into();
415         let y: u32 = id_y * TEXTUI_CHAR_HEIGHT;
416 
417         let buf_width = video_refresh_manager().device_buffer().width();
418         // 找到输入缓冲区的起始地址位置
419         let buf_start =
420             if let ScmBuffer::DeviceBuffer(vaddr) = video_refresh_manager().device_buffer().buf {
421                 vaddr
422             } else {
423                 panic!("device buffer is not init");
424             };
425 
426         let mut testbit: u32; // 用来测试特定行的某列是背景还是字体本身
427 
428         // 在缓冲区画出一个字体,每个字体有TEXTUI_CHAR_HEIGHT行,TEXTUI_CHAR_WIDTH列个像素点
429         for i in 0..TEXTUI_CHAR_HEIGHT {
430             // 计算出帧缓冲区每一行打印的起始位置的地址(起始位置+(y+i)*缓冲区的宽度+x)
431 
432             let mut addr: *mut u32 =
433                 (buf_start + buf_width as usize * 4 * (y as usize + i as usize) + 4 * x as usize)
434                     .data() as *mut u32;
435 
436             testbit = 1 << (TEXTUI_CHAR_WIDTH + 1);
437 
438             for _j in 0..TEXTUI_CHAR_WIDTH {
439                 //从左往右逐个测试相应位
440                 testbit >>= 1;
441                 if (font.0[i as usize] & testbit as u8) != 0 {
442                     unsafe { *addr = self.frcolor.into() }; // 字,显示前景色
443                 } else {
444                     unsafe { *addr = self.bkcolor.into() }; // 背景色
445                 }
446 
447                 unsafe {
448                     addr = (addr.offset(1)) as *mut u32;
449                 }
450             }
451         }
452     }
453 }
454 
455 /// 单色显示的虚拟行结构体
456 
457 #[derive(Clone, Debug, Default)]
458 pub struct TextuiVlineNormal {
459     _characters: Vec<TextuiCharNormal>, // 字符对象数组
460     _index: i16,                        // 当前操作的位置
461 }
462 /// 彩色显示的虚拟行结构体
463 
464 #[derive(Clone, Debug, Default)]
465 pub struct TextuiVlineChromatic {
466     chars: Vec<TextuiCharChromatic>, // 字符对象数组
467     index: LineIndex,                // 当前操作的位置
468 }
469 impl TextuiVlineChromatic {
470     pub fn new(char_num: usize) -> Self {
471         let mut r = TextuiVlineChromatic {
472             chars: Vec::with_capacity(char_num),
473             index: LineIndex::new(0),
474         };
475 
476         for _ in 0..char_num {
477             r.chars.push(TextuiCharChromatic::new(
478                 None,
479                 FontColor::BLACK,
480                 FontColor::BLACK,
481             ));
482         }
483 
484         return r;
485     }
486 }
487 
488 #[derive(Clone, Debug)]
489 pub enum TextuiVline {
490     Chromatic(TextuiVlineChromatic),
491     _Normal(TextuiVlineNormal),
492 }
493 
494 #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
495 pub struct WindowId(u32);
496 
497 impl WindowId {
498     pub fn new() -> Self {
499         static MAX_ID: AtomicU32 = AtomicU32::new(0);
500         return WindowId(MAX_ID.fetch_add(1, Ordering::SeqCst));
501     }
502 }
503 #[allow(dead_code)]
504 #[derive(Clone, Debug)]
505 pub struct TextuiWindow {
506     // 虚拟行是个循环表,头和尾相接
507     id: WindowId,
508     // 虚拟行总数
509     vline_sum: i32,
510     // 当前已经使用了的虚拟行总数(即在已经输入到缓冲区(之后显示在屏幕上)的虚拟行数量)
511     vlines_used: i32,
512     // 位于最顶上的那一个虚拟行的行号
513     top_vline: LineId,
514     // 储存虚拟行的数组
515     vlines: Vec<TextuiVline>,
516     // 正在操作的vline
517     vline_operating: LineId,
518     // 每行最大容纳的字符数
519     chars_per_line: i32,
520     // 窗口flag
521     flags: WindowFlag,
522 }
523 
524 impl TextuiWindow {
525     /// 使用参数初始化window对象
526     /// ## 参数
527     ///
528     /// -flags 标志位
529     /// -vlines_num 虚拟行的总数
530     /// -chars_num 每行最大的字符数
531 
532     pub fn new(flags: WindowFlag, vlines_num: i32, chars_num: i32) -> Self {
533         let mut initial_vlines = Vec::new();
534 
535         for _ in 0..vlines_num {
536             let vline = TextuiVlineChromatic::new(chars_num as usize);
537 
538             initial_vlines.push(TextuiVline::Chromatic(vline));
539         }
540         TextuiWindow {
541             id: WindowId::new(),
542             flags,
543             vline_sum: vlines_num,
544             vlines_used: 1,
545             top_vline: LineId::new(0),
546             vlines: initial_vlines,
547             vline_operating: LineId::new(0),
548             chars_per_line: chars_num,
549         }
550     }
551 
552     /// 刷新某个窗口的缓冲区的某个虚拟行的连续n个字符对象
553     /// ## 参数
554     /// - window 窗口结构体
555     /// - vline_id 要刷新的虚拟行号
556     /// - start 起始字符号
557     /// - count 要刷新的字符数量
558 
559     fn textui_refresh_characters(
560         &mut self,
561         vline_id: LineId,
562         start: LineIndex,
563         count: i32,
564     ) -> Result<(), SystemError> {
565         let actual_line_sum = textui_framework().actual_line.load(Ordering::SeqCst);
566 
567         // 判断虚拟行参数是否合法
568         if unlikely(
569             !vline_id.check(self.vline_sum)
570                 || (<LineIndex as Into<i32>>::into(start) + count) > self.chars_per_line,
571         ) {
572             return Err(SystemError::EINVAL);
573         }
574         // 计算虚拟行对应的真实行(即要渲染的行)
575         let mut actual_line_id = vline_id - self.top_vline; //为正说明虚拟行不在真实行显示的区域上面
576 
577         if <LineId as Into<i32>>::into(actual_line_id) < 0 {
578             //真实行数小于虚拟行数,则需要加上真实行数的位置,以便正确计算真实行
579             actual_line_id = actual_line_id + actual_line_sum;
580         }
581 
582         // 将此窗口的某个虚拟行的连续n个字符对象往缓存区写入
583         if self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) {
584             let vline = &mut self.vlines[<LineId as Into<usize>>::into(vline_id)];
585             let mut i = 0;
586             let mut index = start;
587 
588             while i < count {
589                 if let TextuiVline::Chromatic(vline) = vline {
590                     vline.chars[<LineIndex as Into<usize>>::into(index)]
591                         .textui_refresh_character(actual_line_id, index)?;
592 
593                     index = index + 1;
594                 }
595                 i += 1;
596             }
597         }
598 
599         return Ok(());
600     }
601 
602     /// 重新渲染某个窗口的某个虚拟行
603     /// ## 参数
604 
605     /// - window 窗口结构体
606     /// - vline_id 虚拟行号
607 
608     fn textui_refresh_vline(&mut self, vline_id: LineId) -> Result<(), SystemError> {
609         if self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) {
610             return self.textui_refresh_characters(
611                 vline_id,
612                 LineIndex::new(0),
613                 self.chars_per_line,
614             );
615         } else {
616             //todo支持纯文本字符()
617             todo!();
618         }
619     }
620 
621     // 刷新某个窗口的start 到start + count行(即将这些行输入到缓冲区)
622     fn textui_refresh_vlines(&mut self, start: LineId, count: i32) -> Result<i32, SystemError> {
623         let mut refresh_count = count;
624         for i in <LineId as Into<i32>>::into(start)
625             ..(self.vline_sum).min(<LineId as Into<i32>>::into(start) + count)
626         {
627             self.textui_refresh_vline(LineId::new(i))?;
628             refresh_count -= 1;
629         }
630         //因为虚拟行是循环表
631         let mut refresh_start = 0;
632         while refresh_count > 0 {
633             self.textui_refresh_vline(LineId::new(refresh_start))?;
634             refresh_start += 1;
635             refresh_count -= 1;
636         }
637         return Ok(0);
638     }
639 
640     /// 往某个窗口的缓冲区的某个虚拟行插入换行
641     /// ## 参数
642     /// - window 窗口结构体
643     /// - vline_id 虚拟行号
644 
645     fn textui_new_line(&mut self) -> Result<i32, SystemError> {
646         // todo: 支持在两个虚拟行之间插入一个新行
647         let actual_line_sum = textui_framework().actual_line.load(Ordering::SeqCst);
648         self.vline_operating = self.vline_operating + 1;
649         //如果已经到了最大行数,则重新从0开始
650         if !self.vline_operating.check(self.vline_sum) {
651             self.vline_operating = LineId::new(0);
652         }
653 
654         if let TextuiVline::Chromatic(vline) =
655             &mut (self.vlines[<LineId as Into<usize>>::into(self.vline_operating)])
656         {
657             for i in 0..self.chars_per_line {
658                 if let Some(v_char) = vline.chars.get_mut(i as usize) {
659                     v_char.c = None;
660                     v_char.frcolor = FontColor::BLACK;
661                     v_char.bkcolor = FontColor::BLACK;
662                 }
663             }
664             vline.index = LineIndex::new(0);
665         }
666         // 当已经使用的虚拟行总数等于真实行总数时,说明窗口中已经显示的文本行数已经达到了窗口的最大容量。这时,如果继续在窗口中添加新的文本,就会导致文本溢出窗口而无法显示。因此,需要往下滚动屏幕来显示更多的文本。
667 
668         if self.vlines_used == actual_line_sum {
669             self.top_vline = self.top_vline + 1;
670 
671             if !self.top_vline.check(self.vline_sum) {
672                 self.top_vline = LineId::new(0);
673             }
674 
675             // 刷新所有行
676             self.textui_refresh_vlines(self.top_vline, actual_line_sum)?;
677         } else {
678             //换行说明上一行已经在缓冲区中,所以已经使用的虚拟行总数+1
679             self.vlines_used += 1;
680         }
681 
682         return Ok(0);
683     }
684 
685     /// 真正向窗口的缓冲区上输入字符的函数(位置为window.vline_operating,window.vline_operating.index)
686     /// ## 参数
687     /// - window
688     /// - character
689 
690     fn true_textui_putchar_window(
691         &mut self,
692         character: char,
693         frcolor: FontColor,
694         bkcolor: FontColor,
695     ) -> Result<(), SystemError> {
696         // 启用彩色字符
697         if self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) {
698             let mut line_index = LineIndex::new(0); //操作的列号
699             if let TextuiVline::Chromatic(vline) =
700                 &mut (self.vlines[<LineId as Into<usize>>::into(self.vline_operating)])
701             {
702                 let index = <LineIndex as Into<usize>>::into(vline.index);
703 
704                 if let Some(v_char) = vline.chars.get_mut(index) {
705                     v_char.c = Some(character);
706                     v_char.frcolor = frcolor;
707                     v_char.bkcolor = bkcolor;
708                 }
709                 line_index = vline.index;
710                 vline.index = vline.index + 1;
711             }
712 
713             self.textui_refresh_characters(self.vline_operating, line_index, 1)?;
714 
715             // 加入光标后,因为会识别光标,所以需超过该行最大字符数才能创建新行
716             if !line_index.check(self.chars_per_line - 1) {
717                 self.textui_new_line()?;
718             }
719         } else {
720             // todo: 支持纯文本字符
721             todo!();
722         }
723         return Ok(());
724     }
725     /// 根据输入的一个字符在窗口上输出
726     /// ## 参数
727 
728     /// - window 窗口
729     /// - character 字符
730     /// - FRcolor 前景色(RGB)
731     /// - BKcolor 背景色(RGB)
732 
733     fn textui_putchar_window(
734         &mut self,
735         character: char,
736         frcolor: FontColor,
737         bkcolor: FontColor,
738         is_enable_window: bool,
739     ) -> Result<(), SystemError> {
740         let actual_line_sum = textui_framework().actual_line.load(Ordering::SeqCst);
741 
742         //字符'\0'代表ASCII码表中的空字符,表示字符串的结尾
743         if unlikely(character == '\0') {
744             return Ok(());
745         }
746 
747         if unlikely(character == '\r') {
748             return Ok(());
749         }
750 
751         // 暂不支持纯文本窗口
752         if !self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) {
753             return Ok(());
754         }
755 
756         //进行换行操作
757         if character == '\n' {
758             // 换行时还需要输出\r
759             c_uart_send(UartPort::COM1.to_u16(), b'\r');
760             if is_enable_window == true {
761                 self.textui_new_line()?;
762             }
763             return Ok(());
764         }
765         // 输出制表符
766         else if character == '\t' {
767             if is_enable_window == true {
768                 if let TextuiVline::Chromatic(vline) =
769                     &self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
770                 {
771                     //打印的空格数(注意将每行分成一个个表格,每个表格为8个字符)
772                     let mut space_to_print = 8 - <LineIndex as Into<usize>>::into(vline.index) % 8;
773                     while space_to_print > 0 {
774                         self.true_textui_putchar_window(' ', frcolor, bkcolor)?;
775                         space_to_print -= 1;
776                     }
777                 }
778             }
779         }
780         // 字符 '\x08' 代表 ASCII 码中的退格字符。它在输出中的作用是将光标向左移动一个位置,并在该位置上输出后续的字符,从而实现字符的删除或替换。
781         else if character == '\x08' {
782             if is_enable_window == true {
783                 let mut tmp = LineIndex(0);
784                 if let TextuiVline::Chromatic(vline) =
785                     &mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
786                 {
787                     vline.index = vline.index - 1;
788                     tmp = vline.index;
789                 }
790                 if <LineIndex as Into<i32>>::into(tmp) >= 0 {
791                     if let TextuiVline::Chromatic(vline) =
792                         &mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
793                     {
794                         if let Some(v_char) =
795                             vline.chars.get_mut(<LineIndex as Into<usize>>::into(tmp))
796                         {
797                             v_char.c = Some(' ');
798 
799                             v_char.bkcolor = bkcolor;
800                         }
801                     }
802                     return self.textui_refresh_characters(self.vline_operating, tmp, 1);
803                 }
804                 // 需要向上缩一行
805                 if <LineIndex as Into<i32>>::into(tmp) < 0 {
806                     // 当前行为空,需要重新刷新
807                     if let TextuiVline::Chromatic(vline) =
808                         &mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
809                     {
810                         vline.index = LineIndex::new(0);
811                         for i in 0..self.chars_per_line {
812                             if let Some(v_char) = vline.chars.get_mut(i as usize) {
813                                 v_char.c = None;
814                                 v_char.frcolor = FontColor::BLACK;
815                                 v_char.bkcolor = FontColor::BLACK;
816                             }
817                         }
818                     }
819                     // 上缩一行
820                     self.vline_operating = self.vline_operating - 1;
821                     if self.vline_operating.data() < 0 {
822                         self.vline_operating = LineId(self.vline_sum - 1);
823                     }
824 
825                     // 考虑是否向上滚动(在top_vline上退格)
826                     if self.vlines_used > actual_line_sum {
827                         self.top_vline = self.top_vline - 1;
828                         if <LineId as Into<i32>>::into(self.top_vline) < 0 {
829                             self.top_vline = LineId(self.vline_sum - 1);
830                         }
831                     }
832                     //因为上缩一行所以显示在屏幕中的虚拟行少一
833                     self.vlines_used -= 1;
834                     self.textui_refresh_vlines(self.top_vline, actual_line_sum)?;
835                 }
836             }
837         } else {
838             // 输出其他字符
839 
840             c_uart_send(UartPort::COM1.to_u16(), character as u8);
841 
842             if is_enable_window == true {
843                 if let TextuiVline::Chromatic(vline) =
844                     &self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
845                 {
846                     if !vline.index.check(self.chars_per_line) {
847                         self.textui_new_line()?;
848                     }
849 
850                     return self.true_textui_putchar_window(character, frcolor, bkcolor);
851                 }
852             }
853         }
854 
855         return Ok(());
856     }
857 }
858 impl Default for TextuiWindow {
859     fn default() -> Self {
860         TextuiWindow {
861             id: WindowId(0),
862             flags: WindowFlag::TEXTUI_CHROMATIC,
863             vline_sum: 0,
864             vlines_used: 1,
865             top_vline: LineId::new(0),
866             vlines: Vec::new(),
867             vline_operating: LineId::new(0),
868             chars_per_line: 0,
869         }
870     }
871 }
872 #[allow(dead_code)]
873 #[derive(Debug)]
874 pub struct TextUiFramework {
875     metadata: RwLock<ScmUiFrameworkMetadata>,
876     window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>>,
877     actual_line: AtomicI32, // 真实行的数量(textui的帧缓冲区能容纳的内容的行数)
878     current_window: Arc<SpinLock<TextuiWindow>>, // 当前的主窗口
879     default_window: Arc<SpinLock<TextuiWindow>>, // 默认print到的窗口
880 }
881 
882 impl TextUiFramework {
883     pub fn new(
884         metadata: ScmUiFrameworkMetadata,
885         window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>>,
886         current_window: Arc<SpinLock<TextuiWindow>>,
887         default_window: Arc<SpinLock<TextuiWindow>>,
888     ) -> Self {
889         let actual_line =
890             AtomicI32::new((&metadata.buf_info().height() / TEXTUI_CHAR_HEIGHT) as i32);
891         let inner = TextUiFramework {
892             metadata: RwLock::new(metadata),
893             window_list,
894             actual_line,
895             current_window,
896             default_window,
897         };
898         return inner;
899     }
900 }
901 
902 impl ScmUiFramework for TextUiFramework {
903     // 安装ui框架的回调函数
904     fn install(&self) -> Result<i32, SystemError> {
905         c_uart_send_str(
906             UartPort::COM1.to_u16(),
907             "\ntextui_install_handler\n\0".as_ptr(),
908         );
909         return Ok(0);
910     }
911     // 卸载ui框架的回调函数
912     fn uninstall(&self) -> Result<i32, SystemError> {
913         return Ok(0);
914     }
915     // 启用ui框架的回调函数
916     fn enable(&self) -> Result<i32, SystemError> {
917         ENABLE_PUT_TO_WINDOW.store(true, Ordering::SeqCst);
918         return Ok(0);
919     }
920     // 禁用ui框架的回调函数
921     fn disable(&self) -> Result<i32, SystemError> {
922         ENABLE_PUT_TO_WINDOW.store(false, Ordering::SeqCst);
923 
924         return Ok(0);
925     }
926     // 改变ui框架的帧缓冲区的回调函数
927     fn change(&self, buf_info: ScmBufferInfo) -> Result<i32, SystemError> {
928         let old_buf = textui_framework().metadata.read().buf_info();
929 
930         textui_framework().metadata.write().set_buf_info(buf_info);
931 
932         let mut new_buf = textui_framework().metadata.read().buf_info();
933 
934         new_buf.copy_from_nonoverlapping(&old_buf);
935         kdebug!("textui change buf_info: old: {:?}", old_buf);
936         kdebug!("textui change buf_info: new: {:?}", new_buf);
937 
938         return Ok(0);
939     }
940     ///  获取ScmUiFramework的元数据
941     ///  ## 返回值
942     ///
943     ///  -成功:Ok(ScmUiFramework的元数据)
944     ///  -失败:Err(错误码)
945     fn metadata(&self) -> Result<ScmUiFrameworkMetadata, SystemError> {
946         let metadata = self.metadata.read().clone();
947 
948         return Ok(metadata);
949     }
950 }
951 
952 /// Mapping from characters to glyph indices.
953 pub trait GlyphMapping: Sync {
954     /// Maps a character to a glyph index.
955     ///
956     /// If `c` isn't included in the font the index of a suitable replacement glyph is returned.
957     fn index(&self, c: char) -> usize;
958 }
959 
960 impl<F> GlyphMapping for F
961 where
962     F: Sync + Fn(char) -> usize,
963 {
964     fn index(&self, c: char) -> usize {
965         self(c)
966     }
967 }
968 
969 /// 在默认窗口上输出一个字符
970 /// ## 参数
971 /// - character 字符
972 /// - FRcolor 前景色(RGB)
973 /// - BKcolor 背景色(RGB)
974 
975 #[no_mangle]
976 pub extern "C" fn rs_textui_putchar(character: u8, fr_color: u32, bk_color: u32) -> i32 {
977     return textui_putchar(
978         character as char,
979         FontColor::from(fr_color),
980         FontColor::from(bk_color),
981     )
982     .map(|_| 0)
983     .unwrap_or_else(|e| e.to_posix_errno());
984 }
985 
986 pub fn textui_putchar(
987     character: char,
988     fr_color: FontColor,
989     bk_color: FontColor,
990 ) -> Result<(), SystemError> {
991     if unsafe { TEXTUI_IS_INIT } {
992         return textui_framework()
993             .current_window
994             .lock()
995             .textui_putchar_window(
996                 character,
997                 fr_color,
998                 bk_color,
999                 ENABLE_PUT_TO_WINDOW.load(Ordering::SeqCst),
1000             );
1001     } else {
1002         //未初始化暴力输出
1003         return no_init_textui_putchar_window(
1004             character,
1005             fr_color,
1006             bk_color,
1007             ENABLE_PUT_TO_WINDOW.load(Ordering::SeqCst),
1008         );
1009     }
1010 }
1011 
1012 /// 初始化text ui框架
1013 
1014 #[no_mangle]
1015 pub extern "C" fn rs_textui_init() -> i32 {
1016     let r = textui_init().unwrap_or_else(|e| e.to_posix_errno());
1017     if r.is_negative() {
1018         c_uart_send_str(UartPort::COM1.to_u16(), "textui init failed.\n\0".as_ptr());
1019     }
1020     return r;
1021 }
1022 
1023 fn textui_init() -> Result<i32, SystemError> {
1024     unsafe { textui_framwork_init() };
1025 
1026     return Ok(0);
1027 }
1028