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