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