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