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