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