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