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