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 752 //进行换行操作 753 if character == '\n' { 754 // 换行时还需要输出\r 755 send_to_default_serial8250_port(&[b'\r']); 756 if is_enable_window == true { 757 self.textui_new_line()?; 758 } 759 return Ok(()); 760 } 761 // 输出制表符 762 else if character == '\t' { 763 if is_enable_window == true { 764 if let TextuiVline::Chromatic(vline) = 765 &self.vlines[<LineId as Into<usize>>::into(self.vline_operating)] 766 { 767 //打印的空格数(注意将每行分成一个个表格,每个表格为8个字符) 768 let mut space_to_print = 8 - <LineIndex as Into<usize>>::into(vline.index) % 8; 769 while space_to_print > 0 { 770 self.true_textui_putchar_window(' ', frcolor, bkcolor)?; 771 space_to_print -= 1; 772 } 773 } 774 } 775 } 776 // 字符 '\x08' 代表 ASCII 码中的退格字符。它在输出中的作用是将光标向左移动一个位置,并在该位置上输出后续的字符,从而实现字符的删除或替换。 777 else if character == '\x08' { 778 if is_enable_window == true { 779 let mut tmp = LineIndex(0); 780 if let TextuiVline::Chromatic(vline) = 781 &mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)] 782 { 783 vline.index = vline.index - 1; 784 tmp = vline.index; 785 } 786 if <LineIndex as Into<i32>>::into(tmp) >= 0 { 787 if let TextuiVline::Chromatic(vline) = 788 &mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)] 789 { 790 if let Some(v_char) = 791 vline.chars.get_mut(<LineIndex as Into<usize>>::into(tmp)) 792 { 793 v_char.c = Some(' '); 794 795 v_char.bkcolor = bkcolor; 796 } 797 } 798 return self.textui_refresh_characters(self.vline_operating, tmp, 1); 799 } 800 // 需要向上缩一行 801 if <LineIndex as Into<i32>>::into(tmp) < 0 { 802 // 当前行为空,需要重新刷新 803 if let TextuiVline::Chromatic(vline) = 804 &mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)] 805 { 806 vline.index = LineIndex::new(0); 807 for i in 0..self.chars_per_line { 808 if let Some(v_char) = vline.chars.get_mut(i as usize) { 809 v_char.c = None; 810 v_char.frcolor = FontColor::BLACK; 811 v_char.bkcolor = FontColor::BLACK; 812 } 813 } 814 } 815 // 上缩一行 816 self.vline_operating = self.vline_operating - 1; 817 if self.vline_operating.data() < 0 { 818 self.vline_operating = LineId(self.vline_sum - 1); 819 } 820 821 // 考虑是否向上滚动(在top_vline上退格) 822 if self.vlines_used > actual_line_sum { 823 self.top_vline = self.top_vline - 1; 824 if <LineId as Into<i32>>::into(self.top_vline) < 0 { 825 self.top_vline = LineId(self.vline_sum - 1); 826 } 827 } 828 //因为上缩一行所以显示在屏幕中的虚拟行少一 829 self.vlines_used -= 1; 830 self.textui_refresh_vlines(self.top_vline, actual_line_sum)?; 831 } 832 } 833 } else { 834 // 输出其他字符 835 836 send_to_default_serial8250_port(&[character as u8]); 837 838 if is_enable_window == true { 839 if let TextuiVline::Chromatic(vline) = 840 &self.vlines[<LineId as Into<usize>>::into(self.vline_operating)] 841 { 842 if !vline.index.check(self.chars_per_line) { 843 self.textui_new_line()?; 844 } 845 846 return self.true_textui_putchar_window(character, frcolor, bkcolor); 847 } 848 } 849 } 850 851 return Ok(()); 852 } 853 } 854 impl Default for TextuiWindow { 855 fn default() -> Self { 856 TextuiWindow { 857 id: WindowId(0), 858 flags: WindowFlag::TEXTUI_CHROMATIC, 859 vline_sum: 0, 860 vlines_used: 1, 861 top_vline: LineId::new(0), 862 vlines: Vec::new(), 863 vline_operating: LineId::new(0), 864 chars_per_line: 0, 865 } 866 } 867 } 868 #[allow(dead_code)] 869 #[derive(Debug)] 870 pub struct TextUiFramework { 871 metadata: RwLock<ScmUiFrameworkMetadata>, 872 window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>>, 873 actual_line: AtomicI32, // 真实行的数量(textui的帧缓冲区能容纳的内容的行数) 874 current_window: Arc<SpinLock<TextuiWindow>>, // 当前的主窗口 875 default_window: Arc<SpinLock<TextuiWindow>>, // 默认print到的窗口 876 } 877 878 impl TextUiFramework { 879 pub fn new( 880 metadata: ScmUiFrameworkMetadata, 881 window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>>, 882 current_window: Arc<SpinLock<TextuiWindow>>, 883 default_window: Arc<SpinLock<TextuiWindow>>, 884 ) -> Self { 885 let actual_line = 886 AtomicI32::new((&metadata.buf_info().height() / TEXTUI_CHAR_HEIGHT) as i32); 887 let inner = TextUiFramework { 888 metadata: RwLock::new(metadata), 889 window_list, 890 actual_line, 891 current_window, 892 default_window, 893 }; 894 return inner; 895 } 896 } 897 898 impl ScmUiFramework for TextUiFramework { 899 // 安装ui框架的回调函数 900 fn install(&self) -> Result<i32, SystemError> { 901 send_to_default_serial8250_port("\ntextui_install_handler\n\0".as_bytes()); 902 return Ok(0); 903 } 904 // 卸载ui框架的回调函数 905 fn uninstall(&self) -> Result<i32, SystemError> { 906 return Ok(0); 907 } 908 // 启用ui框架的回调函数 909 fn enable(&self) -> Result<i32, SystemError> { 910 ENABLE_PUT_TO_WINDOW.store(true, Ordering::SeqCst); 911 return Ok(0); 912 } 913 // 禁用ui框架的回调函数 914 fn disable(&self) -> Result<i32, SystemError> { 915 ENABLE_PUT_TO_WINDOW.store(false, Ordering::SeqCst); 916 917 return Ok(0); 918 } 919 // 改变ui框架的帧缓冲区的回调函数 920 fn change(&self, buf_info: ScmBufferInfo) -> Result<i32, SystemError> { 921 let old_buf = textui_framework().metadata.read().buf_info(); 922 923 textui_framework().metadata.write().set_buf_info(buf_info); 924 925 let mut new_buf = textui_framework().metadata.read().buf_info(); 926 927 new_buf.copy_from_nonoverlapping(&old_buf); 928 kdebug!("textui change buf_info: old: {:?}", old_buf); 929 kdebug!("textui change buf_info: new: {:?}", new_buf); 930 931 return Ok(0); 932 } 933 /// 获取ScmUiFramework的元数据 934 /// ## 返回值 935 /// 936 /// -成功:Ok(ScmUiFramework的元数据) 937 /// -失败:Err(错误码) 938 fn metadata(&self) -> Result<ScmUiFrameworkMetadata, SystemError> { 939 let metadata = self.metadata.read().clone(); 940 941 return Ok(metadata); 942 } 943 } 944 945 /// Mapping from characters to glyph indices. 946 pub trait GlyphMapping: Sync { 947 /// Maps a character to a glyph index. 948 /// 949 /// If `c` isn't included in the font the index of a suitable replacement glyph is returned. 950 fn index(&self, c: char) -> usize; 951 } 952 953 impl<F> GlyphMapping for F 954 where 955 F: Sync + Fn(char) -> usize, 956 { 957 fn index(&self, c: char) -> usize { 958 self(c) 959 } 960 } 961 962 /// 在默认窗口上输出一个字符 963 /// ## 参数 964 /// - character 字符 965 /// - FRcolor 前景色(RGB) 966 /// - BKcolor 背景色(RGB) 967 968 #[no_mangle] 969 pub extern "C" fn rs_textui_putchar(character: u8, fr_color: u32, bk_color: u32) -> i32 { 970 return textui_putchar( 971 character as char, 972 FontColor::from(fr_color), 973 FontColor::from(bk_color), 974 ) 975 .map(|_| 0) 976 .unwrap_or_else(|e| e.to_posix_errno()); 977 } 978 979 pub fn textui_putchar( 980 character: char, 981 fr_color: FontColor, 982 bk_color: FontColor, 983 ) -> Result<(), SystemError> { 984 if unsafe { TEXTUI_IS_INIT } { 985 return textui_framework() 986 .current_window 987 .lock() 988 .textui_putchar_window( 989 character, 990 fr_color, 991 bk_color, 992 ENABLE_PUT_TO_WINDOW.load(Ordering::SeqCst), 993 ); 994 } else { 995 //未初始化暴力输出 996 return no_init_textui_putchar_window( 997 character, 998 fr_color, 999 bk_color, 1000 ENABLE_PUT_TO_WINDOW.load(Ordering::SeqCst), 1001 ); 1002 } 1003 } 1004 1005 /// 向默认窗口输出一个字符串 1006 pub fn textui_putstr( 1007 string: &str, 1008 fr_color: FontColor, 1009 bk_color: FontColor, 1010 ) -> Result<(), SystemError> { 1011 let window = if unsafe { TEXTUI_IS_INIT } { 1012 let fw = textui_framework(); 1013 let w = fw.current_window.clone(); 1014 Some(w) 1015 } else { 1016 None 1017 }; 1018 1019 let mut guard = window.as_ref().map(|w| w.lock()); 1020 1021 for character in string.chars() { 1022 if unsafe { TEXTUI_IS_INIT } { 1023 guard.as_mut().unwrap().textui_putchar_window( 1024 character, 1025 fr_color, 1026 bk_color, 1027 ENABLE_PUT_TO_WINDOW.load(Ordering::SeqCst), 1028 )?; 1029 } else { 1030 no_init_textui_putchar_window( 1031 character, 1032 fr_color, 1033 bk_color, 1034 ENABLE_PUT_TO_WINDOW.load(Ordering::SeqCst), 1035 )?; 1036 } 1037 } 1038 1039 return Ok(()); 1040 } 1041 1042 /// 初始化text ui框架 1043 1044 #[no_mangle] 1045 pub extern "C" fn rs_textui_init() -> i32 { 1046 let r = textui_init().unwrap_or_else(|e| e.to_posix_errno()); 1047 if r.is_negative() { 1048 send_to_default_serial8250_port("textui init failed.\n\0".as_bytes()); 1049 } 1050 return r; 1051 } 1052 1053 fn textui_init() -> Result<i32, SystemError> { 1054 unsafe { textui_framwork_init() }; 1055 1056 return Ok(0); 1057 } 1058