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 /// 启用将文本输出到窗口的功能。 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 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 { 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 impl From<LineId> for i32 { 162 fn from(value: LineId) -> Self { 163 value.0 164 } 165 } 166 impl From<LineId> for u32 { 167 fn from(value: LineId) -> Self { 168 value.0 as u32 169 } 170 } 171 impl From<LineId> for usize { 172 fn from(value: LineId) -> Self { 173 value.0 as usize 174 } 175 } 176 impl Sub<LineId> for LineId { 177 type Output = LineId; 178 179 fn sub(mut self, rhs: LineId) -> Self::Output { 180 self.0 -= rhs.0; 181 return self; 182 } 183 } 184 impl AddAssign<LineId> for 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 { 192 pub fn new(num: i32) -> Self { 193 LineIndex(num) 194 } 195 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 202 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 210 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 217 fn sub(self, rhs: i32) -> Self::Output { 218 LineIndex::new(self.0 - rhs) 219 } 220 } 221 222 impl From<LineIndex> for i32 { 223 fn from(val: LineIndex) -> Self { 224 val.0 225 } 226 } 227 impl From<LineIndex> for u32 { 228 fn from(value: LineIndex) -> Self { 229 value.0 as u32 230 } 231 } 232 impl From<LineIndex> for usize { 233 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 251 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 { 258 fn from(value: u32) -> Self { 259 return Self(value & 0x00ffffff); 260 } 261 } 262 impl From<FontColor> for usize { 263 fn from(value: FontColor) -> Self { 264 value.0 as usize 265 } 266 } 267 impl From<FontColor> for u32 { 268 fn from(value: FontColor) -> Self { 269 value.0 270 } 271 } 272 impl From<FontColor> for u16 { 273 fn from(value: FontColor) -> Self { 274 value.0 as u16 275 } 276 } 277 impl From<FontColor> for u64 { 278 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<'_> { 306 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 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 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 } 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 377 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] 394 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 } 401 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 { 409 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 要放入的真实列号 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 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 { 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 fn textui_refresh_characters( 626 &mut self, 627 vline_id: LineId, 628 start: LineIndex, 629 count: i32, 630 ) -> Result<(), SystemError> { 631 let actual_line_sum = textui_framework().actual_line.load(Ordering::SeqCst); 632 633 // 判断虚拟行参数是否合法 634 if unlikely( 635 !vline_id.check(self.vline_sum) 636 || (<LineIndex as Into<i32>>::into(start) + count) > self.chars_per_line, 637 ) { 638 return Err(SystemError::EINVAL); 639 } 640 // 计算虚拟行对应的真实行(即要渲染的行) 641 let mut actual_line_id = vline_id - self.top_vline; //为正说明虚拟行不在真实行显示的区域上面 642 643 if <LineId as Into<i32>>::into(actual_line_id) < 0 { 644 //真实行数小于虚拟行数,则需要加上真实行数的位置,以便正确计算真实行 645 actual_line_id = actual_line_id + actual_line_sum; 646 } 647 648 // 将此窗口的某个虚拟行的连续n个字符对象往缓存区写入 649 if self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) { 650 let vline = &mut self.vlines[<LineId as Into<usize>>::into(vline_id)]; 651 let mut i = 0; 652 let mut index = start; 653 654 while i < count { 655 if let TextuiVline::Chromatic(vline) = vline { 656 vline.chars[<LineIndex as Into<usize>>::into(index)] 657 .textui_refresh_character(actual_line_id, index)?; 658 659 index = index + 1; 660 } 661 i += 1; 662 } 663 } 664 665 return Ok(()); 666 } 667 668 /// 重新渲染某个窗口的某个虚拟行 669 /// ## 参数 670 671 /// - window 窗口结构体 672 /// - vline_id 虚拟行号 673 674 fn textui_refresh_vline(&mut self, vline_id: LineId) -> Result<(), SystemError> { 675 if self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) { 676 return self.textui_refresh_characters( 677 vline_id, 678 LineIndex::new(0), 679 self.chars_per_line, 680 ); 681 } else { 682 //todo支持纯文本字符() 683 todo!(); 684 } 685 } 686 687 // 刷新某个窗口的start 到start + count行(即将这些行输入到缓冲区) 688 fn textui_refresh_vlines(&mut self, start: LineId, count: i32) -> Result<i32, SystemError> { 689 let mut refresh_count = count; 690 for i in <LineId as Into<i32>>::into(start) 691 ..(self.vline_sum).min(<LineId as Into<i32>>::into(start) + count) 692 { 693 self.textui_refresh_vline(LineId::new(i))?; 694 refresh_count -= 1; 695 } 696 //因为虚拟行是循环表 697 let mut refresh_start = 0; 698 while refresh_count > 0 { 699 self.textui_refresh_vline(LineId::new(refresh_start))?; 700 refresh_start += 1; 701 refresh_count -= 1; 702 } 703 return Ok(0); 704 } 705 706 /// 往某个窗口的缓冲区的某个虚拟行插入换行 707 /// ## 参数 708 /// - window 窗口结构体 709 /// - vline_id 虚拟行号 710 fn textui_new_line(&mut self) -> Result<i32, SystemError> { 711 // todo: 支持在两个虚拟行之间插入一个新行 712 let actual_line_sum = textui_framework().actual_line.load(Ordering::SeqCst); 713 self.vline_operating = self.vline_operating + 1; 714 //如果已经到了最大行数,则重新从0开始 715 if !self.vline_operating.check(self.vline_sum) { 716 self.vline_operating = LineId::new(0); 717 } 718 719 if let TextuiVline::Chromatic(vline) = 720 &mut (self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]) 721 { 722 for i in 0..self.chars_per_line { 723 if let Some(v_char) = vline.chars.get_mut(i as usize) { 724 v_char.c = None; 725 v_char.frcolor = FontColor::BLACK; 726 v_char.bkcolor = FontColor::BLACK; 727 } 728 } 729 vline.index = LineIndex::new(0); 730 } 731 // 当已经使用的虚拟行总数等于真实行总数时,说明窗口中已经显示的文本行数已经达到了窗口的最大容量。这时,如果继续在窗口中添加新的文本,就会导致文本溢出窗口而无法显示。因此,需要往下滚动屏幕来显示更多的文本。 732 733 if self.vlines_used == actual_line_sum { 734 self.top_vline = self.top_vline + 1; 735 736 if !self.top_vline.check(self.vline_sum) { 737 self.top_vline = LineId::new(0); 738 } 739 740 // 刷新所有行 741 self.textui_refresh_vlines(self.top_vline, actual_line_sum)?; 742 } else { 743 //换行说明上一行已经在缓冲区中,所以已经使用的虚拟行总数+1 744 self.vlines_used += 1; 745 } 746 747 return Ok(0); 748 } 749 750 /// 真正向窗口的缓冲区上输入字符的函数(位置为window.vline_operating,window.vline_operating.index) 751 /// ## 参数 752 /// - window 753 /// - character 754 fn true_textui_putchar_window( 755 &mut self, 756 character: char, 757 frcolor: FontColor, 758 bkcolor: FontColor, 759 ) -> Result<(), SystemError> { 760 // 启用彩色字符 761 if self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) { 762 let mut line_index = LineIndex::new(0); //操作的列号 763 if let TextuiVline::Chromatic(vline) = 764 &mut (self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]) 765 { 766 let index = <LineIndex as Into<usize>>::into(vline.index); 767 768 if let Some(v_char) = vline.chars.get_mut(index) { 769 v_char.c = Some(character); 770 v_char.frcolor = frcolor; 771 v_char.bkcolor = bkcolor; 772 } 773 line_index = vline.index; 774 vline.index = vline.index + 1; 775 } 776 777 self.textui_refresh_characters(self.vline_operating, line_index, 1)?; 778 779 // 加入光标后,因为会识别光标,所以需超过该行最大字符数才能创建新行 780 if !line_index.check(self.chars_per_line - 1) { 781 self.textui_new_line()?; 782 } 783 } else { 784 // todo: 支持纯文本字符 785 todo!(); 786 } 787 return Ok(()); 788 } 789 /// 根据输入的一个字符在窗口上输出 790 /// ## 参数 791 792 /// - window 窗口 793 /// - character 字符 794 /// - FRcolor 前景色(RGB) 795 /// - BKcolor 背景色(RGB) 796 797 fn textui_putchar_window( 798 &mut self, 799 character: char, 800 frcolor: FontColor, 801 bkcolor: FontColor, 802 is_enable_window: bool, 803 ) -> Result<(), SystemError> { 804 let actual_line_sum = textui_framework().actual_line.load(Ordering::SeqCst); 805 806 //字符'\0'代表ASCII码表中的空字符,表示字符串的结尾 807 if unlikely(character == '\0') { 808 return Ok(()); 809 } 810 811 if unlikely(character == '\r') { 812 return Ok(()); 813 } 814 815 // 暂不支持纯文本窗口 816 if !self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) { 817 return Ok(()); 818 } 819 send_to_default_serial8250_port(&[character as u8]); 820 821 //进行换行操作 822 if character == '\n' { 823 // 换行时还需要输出\r 824 send_to_default_serial8250_port(b"\r"); 825 if is_enable_window { 826 self.textui_new_line()?; 827 } 828 return Ok(()); 829 } 830 // 输出制表符 831 else if character == '\t' { 832 if is_enable_window { 833 if let TextuiVline::Chromatic(vline) = 834 &self.vlines[<LineId as Into<usize>>::into(self.vline_operating)] 835 { 836 //打印的空格数(注意将每行分成一个个表格,每个表格为8个字符) 837 let mut space_to_print = 8 - <LineIndex as Into<usize>>::into(vline.index) % 8; 838 while space_to_print > 0 { 839 self.true_textui_putchar_window(' ', frcolor, bkcolor)?; 840 space_to_print -= 1; 841 } 842 } 843 } 844 } 845 // 字符 '\x08' 代表 ASCII 码中的退格字符。它在输出中的作用是将光标向左移动一个位置,并在该位置上输出后续的字符,从而实现字符的删除或替换。 846 else if character == '\x08' { 847 if is_enable_window { 848 let mut tmp = LineIndex(0); 849 if let TextuiVline::Chromatic(vline) = 850 &mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)] 851 { 852 vline.index = vline.index - 1; 853 tmp = vline.index; 854 } 855 if <LineIndex as Into<i32>>::into(tmp) >= 0 { 856 if let TextuiVline::Chromatic(vline) = 857 &mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)] 858 { 859 if let Some(v_char) = 860 vline.chars.get_mut(<LineIndex as Into<usize>>::into(tmp)) 861 { 862 v_char.c = Some(' '); 863 864 v_char.bkcolor = bkcolor; 865 } 866 } 867 return self.textui_refresh_characters(self.vline_operating, tmp, 1); 868 } 869 // 需要向上缩一行 870 if <LineIndex as Into<i32>>::into(tmp) < 0 { 871 // 当前行为空,需要重新刷新 872 if let TextuiVline::Chromatic(vline) = 873 &mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)] 874 { 875 vline.index = LineIndex::new(0); 876 for i in 0..self.chars_per_line { 877 if let Some(v_char) = vline.chars.get_mut(i as usize) { 878 v_char.c = None; 879 v_char.frcolor = FontColor::BLACK; 880 v_char.bkcolor = FontColor::BLACK; 881 } 882 } 883 } 884 // 上缩一行 885 self.vline_operating = self.vline_operating - 1; 886 if self.vline_operating.data() < 0 { 887 self.vline_operating = LineId(self.vline_sum - 1); 888 } 889 890 // 考虑是否向上滚动(在top_vline上退格) 891 if self.vlines_used > actual_line_sum { 892 self.top_vline = self.top_vline - 1; 893 if <LineId as Into<i32>>::into(self.top_vline) < 0 { 894 self.top_vline = LineId(self.vline_sum - 1); 895 } 896 } 897 //因为上缩一行所以显示在屏幕中的虚拟行少一 898 self.vlines_used -= 1; 899 self.textui_refresh_vlines(self.top_vline, actual_line_sum)?; 900 } 901 } 902 } else if is_enable_window { 903 if let TextuiVline::Chromatic(vline) = 904 &self.vlines[<LineId as Into<usize>>::into(self.vline_operating)] 905 { 906 if !vline.index.check(self.chars_per_line) { 907 self.textui_new_line()?; 908 } 909 910 return self.true_textui_putchar_window(character, frcolor, bkcolor); 911 } 912 } 913 914 return Ok(()); 915 } 916 } 917 impl Default for TextuiWindow { 918 fn default() -> Self { 919 TextuiWindow { 920 id: WindowId(0), 921 flags: WindowFlag::TEXTUI_CHROMATIC, 922 vline_sum: 0, 923 vlines_used: 1, 924 top_vline: LineId::new(0), 925 vlines: Vec::new(), 926 vline_operating: LineId::new(0), 927 chars_per_line: 0, 928 } 929 } 930 } 931 #[allow(dead_code)] 932 #[derive(Debug)] 933 pub struct TextUiFramework { 934 metadata: RwLock<ScmUiFrameworkMetadata>, 935 window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>>, 936 actual_line: AtomicI32, // 真实行的数量(textui的帧缓冲区能容纳的内容的行数) 937 current_window: Arc<SpinLock<TextuiWindow>>, // 当前的主窗口 938 default_window: Arc<SpinLock<TextuiWindow>>, // 默认print到的窗口 939 } 940 941 impl TextUiFramework { 942 pub fn new( 943 metadata: ScmUiFrameworkMetadata, 944 window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>>, 945 current_window: Arc<SpinLock<TextuiWindow>>, 946 default_window: Arc<SpinLock<TextuiWindow>>, 947 ) -> Self { 948 let actual_line = 949 AtomicI32::new((metadata.buf_info().height() / TEXTUI_CHAR_HEIGHT) as i32); 950 let inner = TextUiFramework { 951 metadata: RwLock::new(metadata), 952 window_list, 953 actual_line, 954 current_window, 955 default_window, 956 }; 957 return inner; 958 } 959 } 960 961 impl ScmUiFramework for TextUiFramework { 962 // 安装ui框架的回调函数 963 fn install(&self) -> Result<i32, SystemError> { 964 send_to_default_serial8250_port("\ntextui_install_handler\n\0".as_bytes()); 965 return Ok(0); 966 } 967 // 卸载ui框架的回调函数 968 fn uninstall(&self) -> Result<i32, SystemError> { 969 return Ok(0); 970 } 971 // 启用ui框架的回调函数 972 fn enable(&self) -> Result<i32, SystemError> { 973 textui_enable_put_to_window(); 974 return Ok(0); 975 } 976 // 禁用ui框架的回调函数 977 fn disable(&self) -> Result<i32, SystemError> { 978 textui_disable_put_to_window(); 979 980 return Ok(0); 981 } 982 // 改变ui框架的帧缓冲区的回调函数 983 fn change(&self, buf_info: ScmBufferInfo) -> Result<i32, SystemError> { 984 let old_buf = textui_framework().metadata.read().buf_info(); 985 986 textui_framework().metadata.write().set_buf_info(buf_info); 987 988 let mut new_buf = textui_framework().metadata.read().buf_info(); 989 990 new_buf.copy_from_nonoverlapping(&old_buf); 991 debug!("textui change buf_info: old: {:?}", old_buf); 992 debug!("textui change buf_info: new: {:?}", new_buf); 993 994 return Ok(0); 995 } 996 /// 获取ScmUiFramework的元数据 997 /// ## 返回值 998 /// 999 /// -成功:Ok(ScmUiFramework的元数据) 1000 /// -失败:Err(错误码) 1001 fn metadata(&self) -> Result<ScmUiFrameworkMetadata, SystemError> { 1002 let metadata = self.metadata.read().clone(); 1003 1004 return Ok(metadata); 1005 } 1006 } 1007 1008 /// Mapping from characters to glyph indices. 1009 pub trait GlyphMapping: Sync { 1010 /// Maps a character to a glyph index. 1011 /// 1012 /// If `c` isn't included in the font the index of a suitable replacement glyph is returned. 1013 fn index(&self, c: char) -> usize; 1014 } 1015 1016 impl<F> GlyphMapping for F 1017 where 1018 F: Sync + Fn(char) -> usize, 1019 { 1020 fn index(&self, c: char) -> usize { 1021 self(c) 1022 } 1023 } 1024 1025 /// 在默认窗口上输出一个字符 1026 /// ## 参数 1027 /// - character 字符 1028 /// - FRcolor 前景色(RGB) 1029 /// - BKcolor 背景色(RGB) 1030 1031 #[no_mangle] 1032 pub extern "C" fn rs_textui_putchar(character: u8, fr_color: u32, bk_color: u32) -> i32 { 1033 if let Some(current_vc) = vc_manager().current_vc() { 1034 // tty已经初始化了之后才输出到屏幕 1035 let fr = (fr_color & 0x00ff0000) >> 16; 1036 let fg = (fr_color & 0x0000ff00) >> 8; 1037 let fb = fr_color & 0x000000ff; 1038 let br = (bk_color & 0x00ff0000) >> 16; 1039 let bg = (bk_color & 0x0000ff00) >> 8; 1040 let bb = bk_color & 0x000000ff; 1041 let buf = format!( 1042 "\x1B[38;2;{fr};{fg};{fb};48;2;{br};{bg};{bb}m{}\x1B[0m", 1043 character as char 1044 ); 1045 let port = current_vc.port(); 1046 let tty = port.port_data().internal_tty(); 1047 if let Some(tty) = tty { 1048 send_to_default_serial8250_port(&[character]); 1049 return tty 1050 .write_without_serial(buf.as_bytes(), buf.len()) 1051 .map(|_| 0) 1052 .unwrap_or_else(|e| e.to_posix_errno()); 1053 } 1054 } 1055 return textui_putchar( 1056 character as char, 1057 FontColor::from(fr_color), 1058 FontColor::from(bk_color), 1059 ) 1060 .map(|_| 0) 1061 .unwrap_or_else(|e| e.to_posix_errno()); 1062 } 1063 1064 pub fn textui_putchar( 1065 character: char, 1066 fr_color: FontColor, 1067 bk_color: FontColor, 1068 ) -> Result<(), SystemError> { 1069 if unsafe { TEXTUI_IS_INIT } { 1070 return textui_framework() 1071 .current_window 1072 .lock_irqsave() 1073 .textui_putchar_window( 1074 character, 1075 fr_color, 1076 bk_color, 1077 textui_is_enable_put_to_window(), 1078 ); 1079 } else { 1080 //未初始化暴力输出 1081 return no_init_textui_putchar_window( 1082 character, 1083 fr_color, 1084 bk_color, 1085 textui_is_enable_put_to_window(), 1086 ); 1087 } 1088 } 1089 1090 /// 向默认窗口输出一个字符串 1091 pub fn textui_putstr( 1092 string: &str, 1093 fr_color: FontColor, 1094 bk_color: FontColor, 1095 ) -> Result<(), SystemError> { 1096 let window = if unsafe { TEXTUI_IS_INIT } { 1097 let fw = textui_framework(); 1098 let w = fw.current_window.clone(); 1099 Some(w) 1100 } else { 1101 None 1102 }; 1103 1104 let mut guard = window.as_ref().map(|w| w.lock_irqsave()); 1105 1106 for character in string.chars() { 1107 if unsafe { TEXTUI_IS_INIT } { 1108 guard.as_mut().unwrap().textui_putchar_window( 1109 character, 1110 fr_color, 1111 bk_color, 1112 textui_is_enable_put_to_window(), 1113 )?; 1114 } else { 1115 no_init_textui_putchar_window( 1116 character, 1117 fr_color, 1118 bk_color, 1119 textui_is_enable_put_to_window(), 1120 )?; 1121 } 1122 } 1123 1124 return Ok(()); 1125 } 1126 1127 /// 初始化text ui框架 1128 #[inline(never)] 1129 pub fn textui_init() -> Result<i32, SystemError> { 1130 #[cfg(target_arch = "x86_64")] 1131 textui_framwork_init(); 1132 1133 return Ok(0); 1134 } 1135