1 use crate::{
2 driver::{
3 serial::serial8250::send_to_default_serial8250_port,
4 tty::{tty_port::tty_port, virtual_terminal::virtual_console::CURRENT_VCNUM},
5 video::video_refresh_manager,
6 },
7 libs::{
8 lib_ui::font::FONT_8x16,
9 rwlock::RwLock,
10 spinlock::{SpinLock, SpinLockGuard},
11 },
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 ptr::copy_nonoverlapping,
20 sync::atomic::{AtomicBool, AtomicI32, AtomicU32, Ordering},
21 };
22 use log::{debug, info};
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 /// 启用将文本输出到窗口的功能。
textui_enable_put_to_window()46 pub fn textui_enable_put_to_window() {
47 ENABLE_PUT_TO_WINDOW.store(true, Ordering::SeqCst);
48 }
49
50 /// 禁用将文本输出到窗口的功能。
textui_disable_put_to_window()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`。
textui_is_enable_put_to_window() -> bool59 pub fn textui_is_enable_put_to_window() -> bool {
60 ENABLE_PUT_TO_WINDOW.load(Ordering::SeqCst)
61 }
62
63 /// 获取TEXTUI_FRAMEWORK的可变实例
textui_framework() -> Arc<TextUiFramework>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
textui_framwork_init()74 fn textui_framwork_init() {
75 if unsafe { __TEXTUI_FRAMEWORK.is_none() } {
76 info!("textuiframework init");
77 let metadata = ScmUiFrameworkMetadata::new("TextUI".to_string(), ScmFramworkType::Text);
78 debug!("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 debug!("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 {
new(num: i32) -> Self137 pub fn new(num: i32) -> Self {
138 LineId(num)
139 }
140
check(&self, max: i32) -> bool141 pub fn check(&self, max: i32) -> bool {
142 self.0 < max && self.0 >= 0
143 }
144
data(&self) -> i32145 pub fn data(&self) -> i32 {
146 self.0
147 }
148 }
149 impl Add<i32> for LineId {
150 type Output = LineId;
add(self, rhs: i32) -> Self::Output151 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
sub(self, rhs: i32) -> Self::Output158 fn sub(self, rhs: i32) -> Self::Output {
159 LineId::new(self.0 - rhs)
160 }
161 }
162 impl From<LineId> for i32 {
from(value: LineId) -> Self163 fn from(value: LineId) -> Self {
164 value.0
165 }
166 }
167 impl From<LineId> for u32 {
from(value: LineId) -> Self168 fn from(value: LineId) -> Self {
169 value.0 as u32
170 }
171 }
172 impl From<LineId> for usize {
from(value: LineId) -> Self173 fn from(value: LineId) -> Self {
174 value.0 as usize
175 }
176 }
177 impl Sub<LineId> for LineId {
178 type Output = LineId;
179
sub(mut self, rhs: LineId) -> Self::Output180 fn sub(mut self, rhs: LineId) -> Self::Output {
181 self.0 -= rhs.0;
182 return self;
183 }
184 }
185 impl AddAssign<LineId> for LineId {
add_assign(&mut self, rhs: 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 {
new(num: i32) -> Self193 pub fn new(num: i32) -> Self {
194 LineIndex(num)
195 }
check(&self, chars_per_line: i32) -> bool196 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
add(self, rhs: LineIndex) -> Self::Output203 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
add(self, rhs: i32) -> Self::Output211 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
sub(self, rhs: i32) -> Self::Output218 fn sub(self, rhs: i32) -> Self::Output {
219 LineIndex::new(self.0 - rhs)
220 }
221 }
222
223 impl From<LineIndex> for i32 {
from(val: LineIndex) -> Self224 fn from(val: LineIndex) -> Self {
225 val.0
226 }
227 }
228 impl From<LineIndex> for u32 {
from(value: LineIndex) -> Self229 fn from(value: LineIndex) -> Self {
230 value.0 as u32
231 }
232 }
233 impl From<LineIndex> for usize {
from(value: LineIndex) -> Self234 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
new(r: u8, g: u8, b: u8) -> Self252 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 {
from(value: u32) -> Self259 fn from(value: u32) -> Self {
260 return Self(value & 0x00ffffff);
261 }
262 }
263 impl From<FontColor> for usize {
from(value: FontColor) -> Self264 fn from(value: FontColor) -> Self {
265 value.0 as usize
266 }
267 }
268 impl From<FontColor> for u32 {
from(value: FontColor) -> Self269 fn from(value: FontColor) -> Self {
270 value.0
271 }
272 }
273 impl From<FontColor> for u16 {
from(value: FontColor) -> Self274 fn from(value: FontColor) -> Self {
275 value.0 as u16
276 }
277 }
278 impl From<FontColor> for u64 {
from(value: FontColor) -> Self279 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<'_> {
new(buf: &mut ScmBufferInfo) -> TextuiBuf307 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
buf_mut(&mut self) -> &mut [u8]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
put_color_in_pixel(&mut self, color: u32, index: usize)341 pub fn put_color_in_pixel(&mut self, color: u32, index: usize) {
342 let index = index as isize;
343 match self.bit_depth {
344 32 => {
345 let buf = self.buf_mut().as_mut_ptr() as *mut u32;
346 unsafe {
347 *buf.offset(index) = color;
348 }
349 }
350 24 => {
351 let buf = self.buf_mut().as_mut_ptr();
352 unsafe {
353 copy_nonoverlapping(&color as *const u32 as *const u8, buf.offset(index * 3), 3)
354 };
355 }
356 16 => {
357 let buf = self.buf_mut().as_mut_ptr();
358 unsafe {
359 copy_nonoverlapping(
360 &color as *const u32 as *const u8,
361 buf.offset(index * 2),
362 2,
363 );
364 };
365 }
366 _ => {
367 panic!("bidepth unsupported!")
368 }
369 }
370 }
get_index_of_next_line(now_index: usize) -> usize371 pub fn get_index_of_next_line(now_index: usize) -> usize {
372 textui_framework().metadata.read().buf_info().width() as usize + now_index
373 }
get_index_by_x_y(x: usize, y: usize) -> usize374 pub fn get_index_by_x_y(x: usize, y: usize) -> usize {
375 textui_framework().metadata.read().buf_info().width() as usize * y + x
376 }
377
get_start_index_by_lineid_lineindex(lineid: LineId, lineindex: LineIndex) -> usize378 pub fn get_start_index_by_lineid_lineindex(lineid: LineId, lineindex: LineIndex) -> usize {
379 // x 左上角列像素点位置
380 // y 左上角行像素点位置
381 let index_x: u32 = lineindex.into();
382 let x: u32 = index_x * TEXTUI_CHAR_WIDTH;
383
384 let id_y: u32 = lineid.into();
385 let y: u32 = id_y * TEXTUI_CHAR_HEIGHT;
386
387 TextuiBuf::get_index_by_x_y(x as usize, y as usize)
388 }
389 }
390
391 #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
392 pub struct Font([u8; 16]);
393 impl Font {
394 #[inline]
get_font(character: char) -> Font395 pub fn get_font(character: char) -> Font {
396 let x = FONT_8x16.char_map(character);
397
398 let mut data = [0u8; 16];
399 data.copy_from_slice(x);
400 return Font(data);
401 }
is_frcolor(&self, height: usize, width: usize) -> bool402 pub fn is_frcolor(&self, height: usize, width: usize) -> bool {
403 let w = self.0[height];
404 let testbit = 1 << (8 - width);
405 w & testbit != 0
406 }
407 }
408
409 impl TextuiCharChromatic {
new(c: Option<char>, frcolor: FontColor, bkcolor: FontColor) -> Self410 pub fn new(c: Option<char>, frcolor: FontColor, bkcolor: FontColor) -> Self {
411 TextuiCharChromatic {
412 c,
413 frcolor,
414 bkcolor,
415 }
416 }
417
418 /// 将该字符对象输出到缓冲区
419 /// ## 参数
420 /// -line_id 要放入的真实行号
421 /// -index 要放入的真实列号
textui_refresh_character( &self, lineid: LineId, lineindex: LineIndex, ) -> Result<i32, SystemError>422 pub fn textui_refresh_character(
423 &self,
424 lineid: LineId,
425 lineindex: LineIndex,
426 ) -> Result<i32, SystemError> {
427 // 找到要渲染的字符的像素点数据
428
429 let font: Font = Font::get_font(self.c.unwrap_or(' '));
430
431 let mut count = TextuiBuf::get_start_index_by_lineid_lineindex(lineid, lineindex);
432
433 let mut _binding = textui_framework().metadata.read().buf_info();
434
435 let mut buf = TextuiBuf::new(&mut _binding);
436
437 // 在缓冲区画出一个字体,每个字体有TEXTUI_CHAR_HEIGHT行,TEXTUI_CHAR_WIDTH列个像素点
438 for i in 0..TEXTUI_CHAR_HEIGHT {
439 let start = count;
440 for j in 0..TEXTUI_CHAR_WIDTH {
441 if font.is_frcolor(i as usize, j as usize) {
442 // 字,显示前景色
443 buf.put_color_in_pixel(self.frcolor.into(), count);
444 } else {
445 // 背景色
446 buf.put_color_in_pixel(self.bkcolor.into(), count);
447 }
448 count += 1;
449 }
450 count = TextuiBuf::get_index_of_next_line(start);
451 }
452
453 return Ok(0);
454 }
455
no_init_textui_render_chromatic(&self, lineid: LineId, lineindex: LineIndex)456 pub fn no_init_textui_render_chromatic(&self, lineid: LineId, lineindex: LineIndex) {
457 // 找到要渲染的字符的像素点数据
458 let font = Font::get_font(self.c.unwrap_or(' '));
459
460 // x 左上角列像素点位置
461 // y 左上角行像素点位置
462 let index_x: u32 = lineindex.into();
463 let x: u32 = index_x * TEXTUI_CHAR_WIDTH;
464
465 let id_y: u32 = lineid.into();
466 let y: u32 = id_y * TEXTUI_CHAR_HEIGHT;
467 let buf_depth = video_refresh_manager().device_buffer().bit_depth();
468 let buf_width = video_refresh_manager().device_buffer().width();
469 let byte_num_of_depth = (buf_depth / 8) as usize;
470
471 // 找到输入缓冲区的起始地址位置
472 let buf_start =
473 if let ScmBuffer::DeviceBuffer(vaddr) = video_refresh_manager().device_buffer().buf {
474 vaddr
475 } else {
476 panic!("device buffer is not init");
477 };
478
479 let mut testbit: u32; // 用来测试特定行的某列是背景还是字体本身
480
481 // 在缓冲区画出一个字体,每个字体有TEXTUI_CHAR_HEIGHT行,TEXTUI_CHAR_WIDTH列个像素点
482 for i in 0..TEXTUI_CHAR_HEIGHT {
483 // 计算出帧缓冲区每一行打印的起始位置的地址(起始位置+(y+i)*缓冲区的宽度+x)
484
485 let mut addr: *mut u8 = (buf_start
486 + buf_width as usize * byte_num_of_depth * (y as usize + i as usize)
487 + byte_num_of_depth * x as usize)
488 .data() as *mut u8;
489
490 testbit = 1 << (TEXTUI_CHAR_WIDTH + 1);
491
492 for _j in 0..TEXTUI_CHAR_WIDTH {
493 //该循环是渲染一行像素
494 //从左往右逐个测试相应位
495 testbit >>= 1;
496 if (font.0[i as usize] & testbit as u8) != 0 {
497 let color: u32 = self.frcolor.into();
498 unsafe {
499 copy_nonoverlapping(
500 &color as *const u32 as *const u8,
501 addr,
502 byte_num_of_depth,
503 )
504 }; // 字,显示前景色
505 } else {
506 let color: u32 = self.bkcolor.into();
507 unsafe {
508 copy_nonoverlapping(
509 &color as *const u32 as *const u8,
510 addr,
511 byte_num_of_depth,
512 )
513 };
514 }
515 unsafe {
516 addr = addr.add(byte_num_of_depth);
517 }
518 }
519 }
520 }
521 }
522
523 /// 单色显示的虚拟行结构体
524
525 #[derive(Clone, Debug, Default)]
526 pub struct TextuiVlineNormal {
527 _characters: Vec<TextuiCharNormal>, // 字符对象数组
528 _index: i16, // 当前操作的位置
529 }
530 /// 彩色显示的虚拟行结构体
531
532 #[derive(Clone, Debug, Default)]
533 pub struct TextuiVlineChromatic {
534 chars: Vec<TextuiCharChromatic>, // 字符对象数组
535 index: LineIndex, // 当前操作的位置
536 }
537 impl TextuiVlineChromatic {
new(char_num: usize) -> Self538 pub fn new(char_num: usize) -> Self {
539 let mut r = TextuiVlineChromatic {
540 chars: Vec::with_capacity(char_num),
541 index: LineIndex::new(0),
542 };
543
544 for _ in 0..char_num {
545 r.chars.push(TextuiCharChromatic::new(
546 None,
547 FontColor::BLACK,
548 FontColor::BLACK,
549 ));
550 }
551
552 return r;
553 }
554 }
555
556 #[derive(Clone, Debug)]
557 pub enum TextuiVline {
558 Chromatic(TextuiVlineChromatic),
559 _Normal(TextuiVlineNormal),
560 }
561
562 #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
563 pub struct WindowId(u32);
564
565 impl WindowId {
new() -> Self566 pub fn new() -> Self {
567 static MAX_ID: AtomicU32 = AtomicU32::new(0);
568 return WindowId(MAX_ID.fetch_add(1, Ordering::SeqCst));
569 }
570 }
571 #[allow(dead_code)]
572 #[derive(Clone, Debug)]
573 pub struct TextuiWindow {
574 // 虚拟行是个循环表,头和尾相接
575 id: WindowId,
576 // 虚拟行总数
577 vline_sum: i32,
578 // 当前已经使用了的虚拟行总数(即在已经输入到缓冲区(之后显示在屏幕上)的虚拟行数量)
579 vlines_used: i32,
580 // 位于最顶上的那一个虚拟行的行号
581 top_vline: LineId,
582 // 储存虚拟行的数组
583 vlines: Vec<TextuiVline>,
584 // 正在操作的vline
585 vline_operating: LineId,
586 // 每行最大容纳的字符数
587 chars_per_line: i32,
588 // 窗口flag
589 flags: WindowFlag,
590 }
591
592 impl TextuiWindow {
593 /// 使用参数初始化window对象
594 /// ## 参数
595 ///
596 /// -flags 标志位
597 /// -vlines_num 虚拟行的总数
598 /// -chars_num 每行最大的字符数
599
new(flags: WindowFlag, vlines_num: i32, chars_num: i32) -> Self600 pub fn new(flags: WindowFlag, vlines_num: i32, chars_num: i32) -> Self {
601 let mut initial_vlines = Vec::new();
602
603 for _ in 0..vlines_num {
604 let vline = TextuiVlineChromatic::new(chars_num as usize);
605
606 initial_vlines.push(TextuiVline::Chromatic(vline));
607 }
608 TextuiWindow {
609 id: WindowId::new(),
610 flags,
611 vline_sum: vlines_num,
612 vlines_used: 1,
613 top_vline: LineId::new(0),
614 vlines: initial_vlines,
615 vline_operating: LineId::new(0),
616 chars_per_line: chars_num,
617 }
618 }
619
620 /// 刷新某个窗口的缓冲区的某个虚拟行的连续n个字符对象
621 /// ## 参数
622 /// - window 窗口结构体
623 /// - vline_id 要刷新的虚拟行号
624 /// - start 起始字符号
625 /// - count 要刷新的字符数量
textui_refresh_characters( &mut self, vline_id: LineId, start: LineIndex, count: i32, ) -> Result<(), SystemError>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
textui_refresh_vline(&mut self, vline_id: LineId) -> Result<(), SystemError>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行(即将这些行输入到缓冲区)
textui_refresh_vlines(&mut self, start: LineId, count: i32) -> Result<i32, SystemError>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 虚拟行号
textui_new_line(&mut self) -> Result<i32, SystemError>711 fn textui_new_line(&mut self) -> Result<i32, SystemError> {
712 // todo: 支持在两个虚拟行之间插入一个新行
713 let actual_line_sum = textui_framework().actual_line.load(Ordering::SeqCst);
714 self.vline_operating = self.vline_operating + 1;
715 //如果已经到了最大行数,则重新从0开始
716 if !self.vline_operating.check(self.vline_sum) {
717 self.vline_operating = LineId::new(0);
718 }
719
720 if let TextuiVline::Chromatic(vline) =
721 &mut (self.vlines[<LineId as Into<usize>>::into(self.vline_operating)])
722 {
723 for i in 0..self.chars_per_line {
724 if let Some(v_char) = vline.chars.get_mut(i as usize) {
725 v_char.c = None;
726 v_char.frcolor = FontColor::BLACK;
727 v_char.bkcolor = FontColor::BLACK;
728 }
729 }
730 vline.index = LineIndex::new(0);
731 }
732 // 当已经使用的虚拟行总数等于真实行总数时,说明窗口中已经显示的文本行数已经达到了窗口的最大容量。这时,如果继续在窗口中添加新的文本,就会导致文本溢出窗口而无法显示。因此,需要往下滚动屏幕来显示更多的文本。
733
734 if self.vlines_used == actual_line_sum {
735 self.top_vline = self.top_vline + 1;
736
737 if !self.top_vline.check(self.vline_sum) {
738 self.top_vline = LineId::new(0);
739 }
740
741 // 刷新所有行
742 self.textui_refresh_vlines(self.top_vline, actual_line_sum)?;
743 } else {
744 //换行说明上一行已经在缓冲区中,所以已经使用的虚拟行总数+1
745 self.vlines_used += 1;
746 }
747
748 return Ok(0);
749 }
750
751 /// 真正向窗口的缓冲区上输入字符的函数(位置为window.vline_operating,window.vline_operating.index)
752 /// ## 参数
753 /// - window
754 /// - character
true_textui_putchar_window( &mut self, character: char, frcolor: FontColor, bkcolor: FontColor, ) -> Result<(), SystemError>755 fn true_textui_putchar_window(
756 &mut self,
757 character: char,
758 frcolor: FontColor,
759 bkcolor: FontColor,
760 ) -> Result<(), SystemError> {
761 // 启用彩色字符
762 if self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) {
763 let mut line_index = LineIndex::new(0); //操作的列号
764 if let TextuiVline::Chromatic(vline) =
765 &mut (self.vlines[<LineId as Into<usize>>::into(self.vline_operating)])
766 {
767 let index = <LineIndex as Into<usize>>::into(vline.index);
768
769 if let Some(v_char) = vline.chars.get_mut(index) {
770 v_char.c = Some(character);
771 v_char.frcolor = frcolor;
772 v_char.bkcolor = bkcolor;
773 }
774 line_index = vline.index;
775 vline.index = vline.index + 1;
776 }
777
778 self.textui_refresh_characters(self.vline_operating, line_index, 1)?;
779
780 // 加入光标后,因为会识别光标,所以需超过该行最大字符数才能创建新行
781 if !line_index.check(self.chars_per_line - 1) {
782 self.textui_new_line()?;
783 }
784 } else {
785 // todo: 支持纯文本字符
786 todo!();
787 }
788 return Ok(());
789 }
790 /// 根据输入的一个字符在窗口上输出
791 /// ## 参数
792
793 /// - window 窗口
794 /// - character 字符
795 /// - FRcolor 前景色(RGB)
796 /// - BKcolor 背景色(RGB)
797
textui_putchar_window( &mut self, character: char, frcolor: FontColor, bkcolor: FontColor, is_enable_window: bool, ) -> Result<(), SystemError>798 fn textui_putchar_window(
799 &mut self,
800 character: char,
801 frcolor: FontColor,
802 bkcolor: FontColor,
803 is_enable_window: bool,
804 ) -> Result<(), SystemError> {
805 let actual_line_sum = textui_framework().actual_line.load(Ordering::SeqCst);
806
807 //字符'\0'代表ASCII码表中的空字符,表示字符串的结尾
808 if unlikely(character == '\0') {
809 return Ok(());
810 }
811
812 if unlikely(character == '\r') {
813 return Ok(());
814 }
815
816 // 暂不支持纯文本窗口
817 if !self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) {
818 return Ok(());
819 }
820 send_to_default_serial8250_port(&[character as u8]);
821
822 //进行换行操作
823 if character == '\n' {
824 // 换行时还需要输出\r
825 send_to_default_serial8250_port(b"\r");
826 if is_enable_window {
827 self.textui_new_line()?;
828 }
829 return Ok(());
830 }
831 // 输出制表符
832 else if character == '\t' {
833 if is_enable_window {
834 if let TextuiVline::Chromatic(vline) =
835 &self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
836 {
837 //打印的空格数(注意将每行分成一个个表格,每个表格为8个字符)
838 let mut space_to_print = 8 - <LineIndex as Into<usize>>::into(vline.index) % 8;
839 while space_to_print > 0 {
840 self.true_textui_putchar_window(' ', frcolor, bkcolor)?;
841 space_to_print -= 1;
842 }
843 }
844 }
845 }
846 // 字符 '\x08' 代表 ASCII 码中的退格字符。它在输出中的作用是将光标向左移动一个位置,并在该位置上输出后续的字符,从而实现字符的删除或替换。
847 else if character == '\x08' {
848 if is_enable_window {
849 let mut tmp = LineIndex(0);
850 if let TextuiVline::Chromatic(vline) =
851 &mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
852 {
853 vline.index = vline.index - 1;
854 tmp = vline.index;
855 }
856 if <LineIndex as Into<i32>>::into(tmp) >= 0 {
857 if let TextuiVline::Chromatic(vline) =
858 &mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
859 {
860 if let Some(v_char) =
861 vline.chars.get_mut(<LineIndex as Into<usize>>::into(tmp))
862 {
863 v_char.c = Some(' ');
864
865 v_char.bkcolor = bkcolor;
866 }
867 }
868 return self.textui_refresh_characters(self.vline_operating, tmp, 1);
869 }
870 // 需要向上缩一行
871 if <LineIndex as Into<i32>>::into(tmp) < 0 {
872 // 当前行为空,需要重新刷新
873 if let TextuiVline::Chromatic(vline) =
874 &mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
875 {
876 vline.index = LineIndex::new(0);
877 for i in 0..self.chars_per_line {
878 if let Some(v_char) = vline.chars.get_mut(i as usize) {
879 v_char.c = None;
880 v_char.frcolor = FontColor::BLACK;
881 v_char.bkcolor = FontColor::BLACK;
882 }
883 }
884 }
885 // 上缩一行
886 self.vline_operating = self.vline_operating - 1;
887 if self.vline_operating.data() < 0 {
888 self.vline_operating = LineId(self.vline_sum - 1);
889 }
890
891 // 考虑是否向上滚动(在top_vline上退格)
892 if self.vlines_used > actual_line_sum {
893 self.top_vline = self.top_vline - 1;
894 if <LineId as Into<i32>>::into(self.top_vline) < 0 {
895 self.top_vline = LineId(self.vline_sum - 1);
896 }
897 }
898 //因为上缩一行所以显示在屏幕中的虚拟行少一
899 self.vlines_used -= 1;
900 self.textui_refresh_vlines(self.top_vline, actual_line_sum)?;
901 }
902 }
903 } else if is_enable_window {
904 if let TextuiVline::Chromatic(vline) =
905 &self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
906 {
907 if !vline.index.check(self.chars_per_line) {
908 self.textui_new_line()?;
909 }
910
911 return self.true_textui_putchar_window(character, frcolor, bkcolor);
912 }
913 }
914
915 return Ok(());
916 }
917 }
918 impl Default for TextuiWindow {
default() -> Self919 fn default() -> Self {
920 TextuiWindow {
921 id: WindowId(0),
922 flags: WindowFlag::TEXTUI_CHROMATIC,
923 vline_sum: 0,
924 vlines_used: 1,
925 top_vline: LineId::new(0),
926 vlines: Vec::new(),
927 vline_operating: LineId::new(0),
928 chars_per_line: 0,
929 }
930 }
931 }
932 #[allow(dead_code)]
933 #[derive(Debug)]
934 pub struct TextUiFramework {
935 metadata: RwLock<ScmUiFrameworkMetadata>,
936 window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>>,
937 actual_line: AtomicI32, // 真实行的数量(textui的帧缓冲区能容纳的内容的行数)
938 current_window: Arc<SpinLock<TextuiWindow>>, // 当前的主窗口
939 default_window: Arc<SpinLock<TextuiWindow>>, // 默认print到的窗口
940 }
941
942 impl TextUiFramework {
new( metadata: ScmUiFrameworkMetadata, window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>>, current_window: Arc<SpinLock<TextuiWindow>>, default_window: Arc<SpinLock<TextuiWindow>>, ) -> Self943 pub fn new(
944 metadata: ScmUiFrameworkMetadata,
945 window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>>,
946 current_window: Arc<SpinLock<TextuiWindow>>,
947 default_window: Arc<SpinLock<TextuiWindow>>,
948 ) -> Self {
949 let actual_line =
950 AtomicI32::new((metadata.buf_info().height() / TEXTUI_CHAR_HEIGHT) as i32);
951 let inner = TextUiFramework {
952 metadata: RwLock::new(metadata),
953 window_list,
954 actual_line,
955 current_window,
956 default_window,
957 };
958 return inner;
959 }
960 }
961
962 impl ScmUiFramework for TextUiFramework {
963 // 安装ui框架的回调函数
install(&self) -> Result<i32, SystemError>964 fn install(&self) -> Result<i32, SystemError> {
965 send_to_default_serial8250_port("\ntextui_install_handler\n\0".as_bytes());
966 return Ok(0);
967 }
968 // 卸载ui框架的回调函数
uninstall(&self) -> Result<i32, SystemError>969 fn uninstall(&self) -> Result<i32, SystemError> {
970 return Ok(0);
971 }
972 // 启用ui框架的回调函数
enable(&self) -> Result<i32, SystemError>973 fn enable(&self) -> Result<i32, SystemError> {
974 textui_enable_put_to_window();
975 return Ok(0);
976 }
977 // 禁用ui框架的回调函数
disable(&self) -> Result<i32, SystemError>978 fn disable(&self) -> Result<i32, SystemError> {
979 textui_disable_put_to_window();
980
981 return Ok(0);
982 }
983 // 改变ui框架的帧缓冲区的回调函数
change(&self, buf_info: ScmBufferInfo) -> Result<i32, SystemError>984 fn change(&self, buf_info: ScmBufferInfo) -> Result<i32, SystemError> {
985 let old_buf = textui_framework().metadata.read().buf_info();
986
987 textui_framework().metadata.write().set_buf_info(buf_info);
988
989 let mut new_buf = textui_framework().metadata.read().buf_info();
990
991 new_buf.copy_from_nonoverlapping(&old_buf);
992 debug!("textui change buf_info: old: {:?}", old_buf);
993 debug!("textui change buf_info: new: {:?}", new_buf);
994
995 return Ok(0);
996 }
997 /// 获取ScmUiFramework的元数据
998 /// ## 返回值
999 ///
1000 /// -成功:Ok(ScmUiFramework的元数据)
1001 /// -失败:Err(错误码)
metadata(&self) -> Result<ScmUiFrameworkMetadata, SystemError>1002 fn metadata(&self) -> Result<ScmUiFrameworkMetadata, SystemError> {
1003 let metadata = self.metadata.read().clone();
1004
1005 return Ok(metadata);
1006 }
1007 }
1008
1009 /// Mapping from characters to glyph indices.
1010 pub trait GlyphMapping: Sync {
1011 /// Maps a character to a glyph index.
1012 ///
1013 /// If `c` isn't included in the font the index of a suitable replacement glyph is returned.
index(&self, c: char) -> usize1014 fn index(&self, c: char) -> usize;
1015 }
1016
1017 impl<F> GlyphMapping for F
1018 where
1019 F: Sync + Fn(char) -> usize,
1020 {
index(&self, c: char) -> usize1021 fn index(&self, c: char) -> usize {
1022 self(c)
1023 }
1024 }
1025
1026 /// 在默认窗口上输出一个字符
1027 /// ## 参数
1028 /// - character 字符
1029 /// - FRcolor 前景色(RGB)
1030 /// - BKcolor 背景色(RGB)
1031
1032 #[no_mangle]
rs_textui_putchar(character: u8, fr_color: u32, bk_color: u32) -> i321033 pub extern "C" fn rs_textui_putchar(character: u8, fr_color: u32, bk_color: u32) -> i32 {
1034 let current_vcnum = CURRENT_VCNUM.load(Ordering::SeqCst);
1035 if current_vcnum != -1 {
1036 // tty已经初始化了之后才输出到屏幕
1037 let fr = (fr_color & 0x00ff0000) >> 16;
1038 let fg = (fr_color & 0x0000ff00) >> 8;
1039 let fb = fr_color & 0x000000ff;
1040 let br = (bk_color & 0x00ff0000) >> 16;
1041 let bg = (bk_color & 0x0000ff00) >> 8;
1042 let bb = bk_color & 0x000000ff;
1043 let buf = format!(
1044 "\x1B[38;2;{fr};{fg};{fb};48;2;{br};{bg};{bb}m{}\x1B[0m",
1045 character as char
1046 );
1047 let port = tty_port(current_vcnum as usize);
1048 let tty = port.port_data().internal_tty();
1049 if let Some(tty) = tty {
1050 send_to_default_serial8250_port(&[character]);
1051 return tty
1052 .write_without_serial(buf.as_bytes(), buf.len())
1053 .map(|_| 0)
1054 .unwrap_or_else(|e| e.to_posix_errno());
1055 }
1056 }
1057 return textui_putchar(
1058 character as char,
1059 FontColor::from(fr_color),
1060 FontColor::from(bk_color),
1061 )
1062 .map(|_| 0)
1063 .unwrap_or_else(|e| e.to_posix_errno());
1064 }
1065
textui_putchar( character: char, fr_color: FontColor, bk_color: FontColor, ) -> Result<(), SystemError>1066 pub fn textui_putchar(
1067 character: char,
1068 fr_color: FontColor,
1069 bk_color: FontColor,
1070 ) -> Result<(), SystemError> {
1071 if unsafe { TEXTUI_IS_INIT } {
1072 return textui_framework()
1073 .current_window
1074 .lock_irqsave()
1075 .textui_putchar_window(
1076 character,
1077 fr_color,
1078 bk_color,
1079 textui_is_enable_put_to_window(),
1080 );
1081 } else {
1082 //未初始化暴力输出
1083 return no_init_textui_putchar_window(
1084 character,
1085 fr_color,
1086 bk_color,
1087 textui_is_enable_put_to_window(),
1088 );
1089 }
1090 }
1091
1092 /// 向默认窗口输出一个字符串
textui_putstr( string: &str, fr_color: FontColor, bk_color: FontColor, ) -> Result<(), SystemError>1093 pub fn textui_putstr(
1094 string: &str,
1095 fr_color: FontColor,
1096 bk_color: FontColor,
1097 ) -> Result<(), SystemError> {
1098 let window = if unsafe { TEXTUI_IS_INIT } {
1099 let fw = textui_framework();
1100 let w = fw.current_window.clone();
1101 Some(w)
1102 } else {
1103 None
1104 };
1105
1106 let mut guard = window.as_ref().map(|w| w.lock_irqsave());
1107
1108 for character in string.chars() {
1109 if unsafe { TEXTUI_IS_INIT } {
1110 guard.as_mut().unwrap().textui_putchar_window(
1111 character,
1112 fr_color,
1113 bk_color,
1114 textui_is_enable_put_to_window(),
1115 )?;
1116 } else {
1117 no_init_textui_putchar_window(
1118 character,
1119 fr_color,
1120 bk_color,
1121 textui_is_enable_put_to_window(),
1122 )?;
1123 }
1124 }
1125
1126 return Ok(());
1127 }
1128
1129 /// 初始化text ui框架
1130 #[inline(never)]
textui_init() -> Result<i32, SystemError>1131 pub fn textui_init() -> Result<i32, SystemError> {
1132 #[cfg(target_arch = "x86_64")]
1133 textui_framwork_init();
1134
1135 return Ok(0);
1136 }
1137