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