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