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