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