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