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