12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061 |
- use crate::{
- driver::{serial::serial8250::send_to_default_serial8250_port, video::video_refresh_manager},
- libs::{
- lib_ui::font::FONT_8x16,
- rwlock::RwLock,
- spinlock::{SpinLock, SpinLockGuard},
- },
- };
- use alloc::{boxed::Box, collections::LinkedList, string::ToString};
- use alloc::{sync::Arc, vec::Vec};
- use core::{
- fmt::Debug,
- intrinsics::unlikely,
- ops::{Add, AddAssign, Sub},
- ptr::copy_nonoverlapping,
- sync::atomic::{AtomicBool, AtomicI32, AtomicU32, Ordering},
- };
- use log::{debug, info};
- use system_error::SystemError;
- use super::{
- screen_manager::{
- scm_register, ScmBuffer, ScmBufferInfo, ScmFramworkType, ScmUiFramework,
- ScmUiFrameworkMetadata,
- },
- textui_no_alloc::no_init_textui_putchar_window,
- };
- /// 声明全局的TEXTUI_FRAMEWORK
- static mut __TEXTUI_FRAMEWORK: Option<Arc<TextUiFramework>> = None;
- /// 每个字符的宽度和高度(像素)
- pub const TEXTUI_CHAR_WIDTH: u32 = 8;
- pub const TEXTUI_CHAR_HEIGHT: u32 = 16;
- pub static mut TEXTUI_IS_INIT: bool = false;
- static ENABLE_PUT_TO_WINDOW: AtomicBool = AtomicBool::new(false);
- /// 启用将文本输出到窗口的功能。
- pub fn textui_enable_put_to_window() {
- ENABLE_PUT_TO_WINDOW.store(true, Ordering::SeqCst);
- }
- /// 禁用将文本输出到窗口的功能。
- pub fn textui_disable_put_to_window() {
- ENABLE_PUT_TO_WINDOW.store(false, Ordering::SeqCst);
- }
- /// 检查是否启用了将文本输出到窗口的功能。
- ///
- /// # 返回
- /// 如果启用了将文本输出到窗口的功能,则返回 `true`,否则返回 `false`。
- pub fn textui_is_enable_put_to_window() -> bool {
- ENABLE_PUT_TO_WINDOW.load(Ordering::SeqCst)
- }
- /// 获取TEXTUI_FRAMEWORK的可变实例
- pub fn textui_framework() -> Arc<TextUiFramework> {
- unsafe {
- return __TEXTUI_FRAMEWORK
- .as_ref()
- .expect("Textui framework has not been initialized yet!")
- .clone();
- }
- }
- /// 初始化TEXTUI_FRAMEWORK
- fn textui_framwork_init() {
- if unsafe { __TEXTUI_FRAMEWORK.is_none() } {
- info!("textuiframework init");
- let metadata = ScmUiFrameworkMetadata::new("TextUI".to_string(), ScmFramworkType::Text);
- debug!("textui metadata: {:?}", metadata);
- // 为textui框架生成第一个窗口
- let vlines_num = (metadata.buf_info().height() / TEXTUI_CHAR_HEIGHT) as usize;
- let chars_num = (metadata.buf_info().width() / TEXTUI_CHAR_WIDTH) as usize;
- let initial_window = TextuiWindow::new(
- WindowFlag::TEXTUI_CHROMATIC,
- vlines_num as i32,
- chars_num as i32,
- );
- let current_window: Arc<SpinLock<TextuiWindow>> = Arc::new(SpinLock::new(initial_window));
- let default_window = current_window.clone();
- // 生成窗口链表,并把上面窗口添加进textui框架的窗口链表中
- let window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>> =
- Arc::new(SpinLock::new(LinkedList::new()));
- window_list.lock().push_back(current_window.clone());
- unsafe {
- __TEXTUI_FRAMEWORK = Some(Arc::new(TextUiFramework::new(
- metadata,
- window_list,
- current_window,
- default_window,
- )))
- };
- scm_register(textui_framework()).expect("register textui framework failed");
- debug!("textui framework init success");
- send_to_default_serial8250_port("\ntext ui initialized\n\0".as_bytes());
- unsafe { TEXTUI_IS_INIT = true };
- } else {
- panic!("Try to init TEXTUI_FRAMEWORK twice!");
- }
- }
- // window标志位
- bitflags! {
- pub struct WindowFlag: u8 {
- // 采用彩色字符
- const TEXTUI_CHROMATIC = 1 << 0;
- }
- }
- /**
- * @brief 黑白字符对象
- *
- */
- #[derive(Clone, Debug)]
- struct TextuiCharNormal {
- _data: u8,
- }
- #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Default)]
- pub struct LineId(i32);
- impl LineId {
- pub fn new(num: i32) -> Self {
- LineId(num)
- }
- pub fn check(&self, max: i32) -> bool {
- self.0 < max && self.0 >= 0
- }
- pub fn data(&self) -> i32 {
- self.0
- }
- }
- impl Add<i32> for LineId {
- type Output = LineId;
- fn add(self, rhs: i32) -> Self::Output {
- LineId::new(self.0 + rhs)
- }
- }
- impl Sub<i32> for LineId {
- type Output = LineId;
- fn sub(self, rhs: i32) -> Self::Output {
- LineId::new(self.0 - rhs)
- }
- }
- impl From<LineId> for i32 {
- fn from(value: LineId) -> Self {
- value.0
- }
- }
- impl From<LineId> for u32 {
- fn from(value: LineId) -> Self {
- value.0 as u32
- }
- }
- impl From<LineId> for usize {
- fn from(value: LineId) -> Self {
- value.0 as usize
- }
- }
- impl Sub<LineId> for LineId {
- type Output = LineId;
- fn sub(mut self, rhs: LineId) -> Self::Output {
- self.0 -= rhs.0;
- return self;
- }
- }
- impl AddAssign<LineId> for LineId {
- fn add_assign(&mut self, rhs: LineId) {
- self.0 += rhs.0;
- }
- }
- #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Default)]
- pub struct LineIndex(i32);
- impl LineIndex {
- pub fn new(num: i32) -> Self {
- LineIndex(num)
- }
- pub fn check(&self, chars_per_line: i32) -> bool {
- self.0 < chars_per_line && self.0 >= 0
- }
- }
- impl Add<LineIndex> for LineIndex {
- type Output = LineIndex;
- fn add(self, rhs: LineIndex) -> Self::Output {
- LineIndex::new(self.0 + rhs.0)
- }
- }
- impl Add<i32> for LineIndex {
- // type Output = Self;
- type Output = LineIndex;
- fn add(self, rhs: i32) -> Self::Output {
- LineIndex::new(self.0 + rhs)
- }
- }
- impl Sub<i32> for LineIndex {
- type Output = LineIndex;
- fn sub(self, rhs: i32) -> Self::Output {
- LineIndex::new(self.0 - rhs)
- }
- }
- impl From<LineIndex> for i32 {
- fn from(val: LineIndex) -> Self {
- val.0
- }
- }
- impl From<LineIndex> for u32 {
- fn from(value: LineIndex) -> Self {
- value.0 as u32
- }
- }
- impl From<LineIndex> for usize {
- fn from(value: LineIndex) -> Self {
- value.0 as usize
- }
- }
- #[derive(Copy, Clone, Debug)]
- pub struct FontColor(u32);
- #[allow(dead_code)]
- impl FontColor {
- pub const BLUE: FontColor = FontColor::new(0, 0, 0xff);
- pub const RED: FontColor = FontColor::new(0xff, 0, 0);
- pub const GREEN: FontColor = FontColor::new(0, 0xff, 0);
- pub const WHITE: FontColor = FontColor::new(0xff, 0xff, 0xff);
- pub const BLACK: FontColor = FontColor::new(0, 0, 0);
- pub const YELLOW: FontColor = FontColor::new(0xff, 0xff, 0);
- pub const ORANGE: FontColor = FontColor::new(0xff, 0x80, 0);
- pub const INDIGO: FontColor = FontColor::new(0x00, 0xff, 0xff);
- pub const PURPLE: FontColor = FontColor::new(0x80, 0x00, 0xff);
- pub const fn new(r: u8, g: u8, b: u8) -> Self {
- let val = ((r as u32) << 16) | ((g as u32) << 8) | (b as u32);
- return FontColor(val & 0x00ffffff);
- }
- }
- impl From<u32> for FontColor {
- fn from(value: u32) -> Self {
- return Self(value & 0x00ffffff);
- }
- }
- impl From<FontColor> for usize {
- fn from(value: FontColor) -> Self {
- value.0 as usize
- }
- }
- impl From<FontColor> for u32 {
- fn from(value: FontColor) -> Self {
- value.0
- }
- }
- impl From<FontColor> for u16 {
- fn from(value: FontColor) -> Self {
- value.0 as u16
- }
- }
- impl From<FontColor> for u64 {
- fn from(value: FontColor) -> Self {
- value.0 as u64
- }
- }
- /// 彩色字符对象
- #[derive(Clone, Debug, Copy)]
- pub struct TextuiCharChromatic {
- c: Option<char>,
- // 前景色
- frcolor: FontColor, // rgb
- // 背景色
- bkcolor: FontColor, // rgb
- }
- #[derive(Debug)]
- pub struct TextuiBuf<'a> {
- buf: Option<&'a mut [u8]>,
- guard: Option<SpinLockGuard<'a, Box<[u8]>>>,
- bit_depth: u32,
- }
- impl TextuiBuf<'_> {
- pub fn new(buf: &mut ScmBufferInfo) -> TextuiBuf {
- let len = buf.buf_size() / 4;
- let depth = video_refresh_manager().device_buffer().bit_depth();
- match &buf.buf {
- ScmBuffer::DeviceBuffer(vaddr) => {
- return TextuiBuf {
- buf: Some(unsafe {
- core::slice::from_raw_parts_mut(vaddr.data() as *mut u8, len)
- }),
- guard: None,
- bit_depth: depth,
- };
- }
- ScmBuffer::DoubleBuffer(double_buffer) => {
- let guard: SpinLockGuard<'_, Box<[u8]>> = double_buffer.lock();
- return TextuiBuf {
- buf: None,
- guard: Some(guard),
- bit_depth: depth,
- };
- }
- }
- }
- pub fn buf_mut(&mut self) -> &mut [u8] {
- if let Some(buf) = &mut self.buf {
- return buf;
- } else {
- return self.guard.as_mut().unwrap().as_mut();
- }
- }
- pub fn put_color_in_pixel(&mut self, color: u32, index: usize) {
- let index = index as isize;
- match self.bit_depth {
- 32 => {
- let buf = self.buf_mut().as_mut_ptr() as *mut u32;
- unsafe {
- *buf.offset(index) = color;
- }
- }
- 24 => {
- let buf = self.buf_mut().as_mut_ptr();
- unsafe {
- copy_nonoverlapping(&color as *const u32 as *const u8, buf.offset(index * 3), 3)
- };
- }
- 16 => {
- let buf = self.buf_mut().as_mut_ptr();
- unsafe {
- copy_nonoverlapping(
- &color as *const u32 as *const u8,
- buf.offset(index * 2),
- 2,
- );
- };
- }
- _ => {
- panic!("bidepth unsupported!")
- }
- }
- }
- pub fn get_index_of_next_line(now_index: usize) -> usize {
- textui_framework().metadata.read().buf_info().width() as usize + now_index
- }
- pub fn get_index_by_x_y(x: usize, y: usize) -> usize {
- textui_framework().metadata.read().buf_info().width() as usize * y + x
- }
- pub fn get_start_index_by_lineid_lineindex(lineid: LineId, lineindex: LineIndex) -> usize {
- // x 左上角列像素点位置
- // y 左上角行像素点位置
- let index_x: u32 = lineindex.into();
- let x: u32 = index_x * TEXTUI_CHAR_WIDTH;
- let id_y: u32 = lineid.into();
- let y: u32 = id_y * TEXTUI_CHAR_HEIGHT;
- TextuiBuf::get_index_by_x_y(x as usize, y as usize)
- }
- }
- #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
- pub struct Font([u8; 16]);
- impl Font {
- #[inline]
- pub fn get_font(character: char) -> Font {
- let x = FONT_8x16.char_map(character);
- let mut data = [0u8; 16];
- data.copy_from_slice(x);
- return Font(data);
- }
- pub fn is_frcolor(&self, height: usize, width: usize) -> bool {
- let w = self.0[height];
- let testbit = 1 << (8 - width);
- w & testbit != 0
- }
- }
- impl TextuiCharChromatic {
- pub fn new(c: Option<char>, frcolor: FontColor, bkcolor: FontColor) -> Self {
- TextuiCharChromatic {
- c,
- frcolor,
- bkcolor,
- }
- }
- /// 将该字符对象输出到缓冲区
- /// ## 参数
- /// -line_id 要放入的真实行号
- /// -index 要放入的真实列号
- pub fn textui_refresh_character(
- &self,
- lineid: LineId,
- lineindex: LineIndex,
- ) -> Result<i32, SystemError> {
- // 找到要渲染的字符的像素点数据
- let font: Font = Font::get_font(self.c.unwrap_or(' '));
- let mut count = TextuiBuf::get_start_index_by_lineid_lineindex(lineid, lineindex);
- let mut _binding = textui_framework().metadata.read().buf_info();
- let mut buf = TextuiBuf::new(&mut _binding);
- // 在缓冲区画出一个字体,每个字体有TEXTUI_CHAR_HEIGHT行,TEXTUI_CHAR_WIDTH列个像素点
- for i in 0..TEXTUI_CHAR_HEIGHT {
- let start = count;
- for j in 0..TEXTUI_CHAR_WIDTH {
- if font.is_frcolor(i as usize, j as usize) {
- // 字,显示前景色
- buf.put_color_in_pixel(self.frcolor.into(), count);
- } else {
- // 背景色
- buf.put_color_in_pixel(self.bkcolor.into(), count);
- }
- count += 1;
- }
- count = TextuiBuf::get_index_of_next_line(start);
- }
- return Ok(0);
- }
- pub fn no_init_textui_render_chromatic(&self, lineid: LineId, lineindex: LineIndex) {
- // 找到要渲染的字符的像素点数据
- let font = Font::get_font(self.c.unwrap_or(' '));
- // x 左上角列像素点位置
- // y 左上角行像素点位置
- let index_x: u32 = lineindex.into();
- let x: u32 = index_x * TEXTUI_CHAR_WIDTH;
- let id_y: u32 = lineid.into();
- let y: u32 = id_y * TEXTUI_CHAR_HEIGHT;
- let buf_depth = video_refresh_manager().device_buffer().bit_depth();
- let buf_width = video_refresh_manager().device_buffer().width();
- let byte_num_of_depth = (buf_depth / 8) as usize;
- // 找到输入缓冲区的起始地址位置
- let buf_start =
- if let ScmBuffer::DeviceBuffer(vaddr) = video_refresh_manager().device_buffer().buf {
- vaddr
- } else {
- panic!("device buffer is not init");
- };
- let mut testbit: u32; // 用来测试特定行的某列是背景还是字体本身
- // 在缓冲区画出一个字体,每个字体有TEXTUI_CHAR_HEIGHT行,TEXTUI_CHAR_WIDTH列个像素点
- for i in 0..TEXTUI_CHAR_HEIGHT {
- // 计算出帧缓冲区每一行打印的起始位置的地址(起始位置+(y+i)*缓冲区的宽度+x)
- let mut addr: *mut u8 = (buf_start
- + buf_width as usize * byte_num_of_depth * (y as usize + i as usize)
- + byte_num_of_depth * x as usize)
- .data() as *mut u8;
- testbit = 1 << (TEXTUI_CHAR_WIDTH + 1);
- for _j in 0..TEXTUI_CHAR_WIDTH {
- //该循环是渲染一行像素
- //从左往右逐个测试相应位
- testbit >>= 1;
- if (font.0[i as usize] & testbit as u8) != 0 {
- let color: u32 = self.frcolor.into();
- unsafe {
- copy_nonoverlapping(
- &color as *const u32 as *const u8,
- addr,
- byte_num_of_depth,
- )
- }; // 字,显示前景色
- } else {
- let color: u32 = self.bkcolor.into();
- unsafe {
- copy_nonoverlapping(
- &color as *const u32 as *const u8,
- addr,
- byte_num_of_depth,
- )
- };
- }
- unsafe {
- addr = addr.add(byte_num_of_depth);
- }
- }
- }
- }
- }
- /// 单色显示的虚拟行结构体
- #[derive(Clone, Debug, Default)]
- pub struct TextuiVlineNormal {
- _characters: Vec<TextuiCharNormal>, // 字符对象数组
- _index: i16, // 当前操作的位置
- }
- /// 彩色显示的虚拟行结构体
- #[derive(Clone, Debug, Default)]
- pub struct TextuiVlineChromatic {
- chars: Vec<TextuiCharChromatic>, // 字符对象数组
- index: LineIndex, // 当前操作的位置
- }
- impl TextuiVlineChromatic {
- pub fn new(char_num: usize) -> Self {
- let mut r = TextuiVlineChromatic {
- chars: Vec::with_capacity(char_num),
- index: LineIndex::new(0),
- };
- for _ in 0..char_num {
- r.chars.push(TextuiCharChromatic::new(
- None,
- FontColor::BLACK,
- FontColor::BLACK,
- ));
- }
- return r;
- }
- }
- #[derive(Clone, Debug)]
- pub enum TextuiVline {
- Chromatic(TextuiVlineChromatic),
- _Normal(TextuiVlineNormal),
- }
- #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
- pub struct WindowId(u32);
- impl WindowId {
- pub fn new() -> Self {
- static MAX_ID: AtomicU32 = AtomicU32::new(0);
- return WindowId(MAX_ID.fetch_add(1, Ordering::SeqCst));
- }
- }
- #[allow(dead_code)]
- #[derive(Clone, Debug)]
- pub struct TextuiWindow {
- // 虚拟行是个循环表,头和尾相接
- id: WindowId,
- // 虚拟行总数
- vline_sum: i32,
- // 当前已经使用了的虚拟行总数(即在已经输入到缓冲区(之后显示在屏幕上)的虚拟行数量)
- vlines_used: i32,
- // 位于最顶上的那一个虚拟行的行号
- top_vline: LineId,
- // 储存虚拟行的数组
- vlines: Vec<TextuiVline>,
- // 正在操作的vline
- vline_operating: LineId,
- // 每行最大容纳的字符数
- chars_per_line: i32,
- // 窗口flag
- flags: WindowFlag,
- }
- impl TextuiWindow {
- /// 使用参数初始化window对象
- /// ## 参数
- ///
- /// -flags 标志位
- /// -vlines_num 虚拟行的总数
- /// -chars_num 每行最大的字符数
- pub fn new(flags: WindowFlag, vlines_num: i32, chars_num: i32) -> Self {
- let mut initial_vlines = Vec::new();
- for _ in 0..vlines_num {
- let vline = TextuiVlineChromatic::new(chars_num as usize);
- initial_vlines.push(TextuiVline::Chromatic(vline));
- }
- TextuiWindow {
- id: WindowId::new(),
- flags,
- vline_sum: vlines_num,
- vlines_used: 1,
- top_vline: LineId::new(0),
- vlines: initial_vlines,
- vline_operating: LineId::new(0),
- chars_per_line: chars_num,
- }
- }
- /// 刷新某个窗口的缓冲区的某个虚拟行的连续n个字符对象
- /// ## 参数
- /// - window 窗口结构体
- /// - vline_id 要刷新的虚拟行号
- /// - start 起始字符号
- /// - count 要刷新的字符数量
- fn textui_refresh_characters(
- &mut self,
- vline_id: LineId,
- start: LineIndex,
- count: i32,
- ) -> Result<(), SystemError> {
- let actual_line_sum = textui_framework().actual_line.load(Ordering::SeqCst);
- // 判断虚拟行参数是否合法
- if unlikely(
- !vline_id.check(self.vline_sum)
- || (<LineIndex as Into<i32>>::into(start) + count) > self.chars_per_line,
- ) {
- return Err(SystemError::EINVAL);
- }
- // 计算虚拟行对应的真实行(即要渲染的行)
- let mut actual_line_id = vline_id - self.top_vline; //为正说明虚拟行不在真实行显示的区域上面
- if <LineId as Into<i32>>::into(actual_line_id) < 0 {
- //真实行数小于虚拟行数,则需要加上真实行数的位置,以便正确计算真实行
- actual_line_id = actual_line_id + actual_line_sum;
- }
- // 将此窗口的某个虚拟行的连续n个字符对象往缓存区写入
- if self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) {
- let vline = &mut self.vlines[<LineId as Into<usize>>::into(vline_id)];
- let mut i = 0;
- let mut index = start;
- while i < count {
- if let TextuiVline::Chromatic(vline) = vline {
- vline.chars[<LineIndex as Into<usize>>::into(index)]
- .textui_refresh_character(actual_line_id, index)?;
- index = index + 1;
- }
- i += 1;
- }
- }
- return Ok(());
- }
- /// 重新渲染某个窗口的某个虚拟行
- /// ## 参数
- /// - window 窗口结构体
- /// - vline_id 虚拟行号
- fn textui_refresh_vline(&mut self, vline_id: LineId) -> Result<(), SystemError> {
- if self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) {
- return self.textui_refresh_characters(
- vline_id,
- LineIndex::new(0),
- self.chars_per_line,
- );
- } else {
- //todo支持纯文本字符()
- todo!();
- }
- }
- // 刷新某个窗口的start 到start + count行(即将这些行输入到缓冲区)
- fn textui_refresh_vlines(&mut self, start: LineId, count: i32) -> Result<i32, SystemError> {
- let mut refresh_count = count;
- for i in <LineId as Into<i32>>::into(start)
- ..(self.vline_sum).min(<LineId as Into<i32>>::into(start) + count)
- {
- self.textui_refresh_vline(LineId::new(i))?;
- refresh_count -= 1;
- }
- //因为虚拟行是循环表
- let mut refresh_start = 0;
- while refresh_count > 0 {
- self.textui_refresh_vline(LineId::new(refresh_start))?;
- refresh_start += 1;
- refresh_count -= 1;
- }
- return Ok(0);
- }
- /// 往某个窗口的缓冲区的某个虚拟行插入换行
- /// ## 参数
- /// - window 窗口结构体
- /// - vline_id 虚拟行号
- fn textui_new_line(&mut self) -> Result<i32, SystemError> {
- // todo: 支持在两个虚拟行之间插入一个新行
- let actual_line_sum = textui_framework().actual_line.load(Ordering::SeqCst);
- self.vline_operating = self.vline_operating + 1;
- //如果已经到了最大行数,则重新从0开始
- if !self.vline_operating.check(self.vline_sum) {
- self.vline_operating = LineId::new(0);
- }
- if let TextuiVline::Chromatic(vline) =
- &mut (self.vlines[<LineId as Into<usize>>::into(self.vline_operating)])
- {
- for i in 0..self.chars_per_line {
- if let Some(v_char) = vline.chars.get_mut(i as usize) {
- v_char.c = None;
- v_char.frcolor = FontColor::BLACK;
- v_char.bkcolor = FontColor::BLACK;
- }
- }
- vline.index = LineIndex::new(0);
- }
- // 当已经使用的虚拟行总数等于真实行总数时,说明窗口中已经显示的文本行数已经达到了窗口的最大容量。这时,如果继续在窗口中添加新的文本,就会导致文本溢出窗口而无法显示。因此,需要往下滚动屏幕来显示更多的文本。
- if self.vlines_used == actual_line_sum {
- self.top_vline = self.top_vline + 1;
- if !self.top_vline.check(self.vline_sum) {
- self.top_vline = LineId::new(0);
- }
- // 刷新所有行
- self.textui_refresh_vlines(self.top_vline, actual_line_sum)?;
- } else {
- //换行说明上一行已经在缓冲区中,所以已经使用的虚拟行总数+1
- self.vlines_used += 1;
- }
- return Ok(0);
- }
- /// 真正向窗口的缓冲区上输入字符的函数(位置为window.vline_operating,window.vline_operating.index)
- /// ## 参数
- /// - window
- /// - character
- fn true_textui_putchar_window(
- &mut self,
- character: char,
- frcolor: FontColor,
- bkcolor: FontColor,
- ) -> Result<(), SystemError> {
- // 启用彩色字符
- if self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) {
- let mut line_index = LineIndex::new(0); //操作的列号
- if let TextuiVline::Chromatic(vline) =
- &mut (self.vlines[<LineId as Into<usize>>::into(self.vline_operating)])
- {
- let index = <LineIndex as Into<usize>>::into(vline.index);
- if let Some(v_char) = vline.chars.get_mut(index) {
- v_char.c = Some(character);
- v_char.frcolor = frcolor;
- v_char.bkcolor = bkcolor;
- }
- line_index = vline.index;
- vline.index = vline.index + 1;
- }
- self.textui_refresh_characters(self.vline_operating, line_index, 1)?;
- // 加入光标后,因为会识别光标,所以需超过该行最大字符数才能创建新行
- if !line_index.check(self.chars_per_line - 1) {
- self.textui_new_line()?;
- }
- } else {
- // todo: 支持纯文本字符
- todo!();
- }
- return Ok(());
- }
- /// 根据输入的一个字符在窗口上输出
- /// ## 参数
- /// - window 窗口
- /// - character 字符
- /// - FRcolor 前景色(RGB)
- /// - BKcolor 背景色(RGB)
- fn textui_putchar_window(
- &mut self,
- character: char,
- frcolor: FontColor,
- bkcolor: FontColor,
- is_enable_window: bool,
- ) -> Result<(), SystemError> {
- let actual_line_sum = textui_framework().actual_line.load(Ordering::SeqCst);
- //字符'\0'代表ASCII码表中的空字符,表示字符串的结尾
- if unlikely(character == '\0') {
- return Ok(());
- }
- if unlikely(character == '\r') {
- return Ok(());
- }
- // 暂不支持纯文本窗口
- if !self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) {
- return Ok(());
- }
- send_to_default_serial8250_port(&[character as u8]);
- //进行换行操作
- if character == '\n' {
- // 换行时还需要输出\r
- send_to_default_serial8250_port(b"\r");
- if is_enable_window {
- self.textui_new_line()?;
- }
- return Ok(());
- }
- // 输出制表符
- else if character == '\t' {
- if is_enable_window {
- if let TextuiVline::Chromatic(vline) =
- &self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
- {
- //打印的空格数(注意将每行分成一个个表格,每个表格为8个字符)
- let mut space_to_print = 8 - <LineIndex as Into<usize>>::into(vline.index) % 8;
- while space_to_print > 0 {
- self.true_textui_putchar_window(' ', frcolor, bkcolor)?;
- space_to_print -= 1;
- }
- }
- }
- }
- // 字符 '\x08' 代表 ASCII 码中的退格字符。它在输出中的作用是将光标向左移动一个位置,并在该位置上输出后续的字符,从而实现字符的删除或替换。
- else if character == '\x08' {
- if is_enable_window {
- let mut tmp = LineIndex(0);
- if let TextuiVline::Chromatic(vline) =
- &mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
- {
- vline.index = vline.index - 1;
- tmp = vline.index;
- }
- if <LineIndex as Into<i32>>::into(tmp) >= 0 {
- if let TextuiVline::Chromatic(vline) =
- &mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
- {
- if let Some(v_char) =
- vline.chars.get_mut(<LineIndex as Into<usize>>::into(tmp))
- {
- v_char.c = Some(' ');
- v_char.bkcolor = bkcolor;
- }
- }
- return self.textui_refresh_characters(self.vline_operating, tmp, 1);
- }
- // 需要向上缩一行
- if <LineIndex as Into<i32>>::into(tmp) < 0 {
- // 当前行为空,需要重新刷新
- if let TextuiVline::Chromatic(vline) =
- &mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
- {
- vline.index = LineIndex::new(0);
- for i in 0..self.chars_per_line {
- if let Some(v_char) = vline.chars.get_mut(i as usize) {
- v_char.c = None;
- v_char.frcolor = FontColor::BLACK;
- v_char.bkcolor = FontColor::BLACK;
- }
- }
- }
- // 上缩一行
- self.vline_operating = self.vline_operating - 1;
- if self.vline_operating.data() < 0 {
- self.vline_operating = LineId(self.vline_sum - 1);
- }
- // 考虑是否向上滚动(在top_vline上退格)
- if self.vlines_used > actual_line_sum {
- self.top_vline = self.top_vline - 1;
- if <LineId as Into<i32>>::into(self.top_vline) < 0 {
- self.top_vline = LineId(self.vline_sum - 1);
- }
- }
- //因为上缩一行所以显示在屏幕中的虚拟行少一
- self.vlines_used -= 1;
- self.textui_refresh_vlines(self.top_vline, actual_line_sum)?;
- }
- }
- } else if is_enable_window {
- if let TextuiVline::Chromatic(vline) =
- &self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
- {
- if !vline.index.check(self.chars_per_line) {
- self.textui_new_line()?;
- }
- return self.true_textui_putchar_window(character, frcolor, bkcolor);
- }
- }
- return Ok(());
- }
- }
- impl Default for TextuiWindow {
- fn default() -> Self {
- TextuiWindow {
- id: WindowId(0),
- flags: WindowFlag::TEXTUI_CHROMATIC,
- vline_sum: 0,
- vlines_used: 1,
- top_vline: LineId::new(0),
- vlines: Vec::new(),
- vline_operating: LineId::new(0),
- chars_per_line: 0,
- }
- }
- }
- #[allow(dead_code)]
- #[derive(Debug)]
- pub struct TextUiFramework {
- metadata: RwLock<ScmUiFrameworkMetadata>,
- window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>>,
- actual_line: AtomicI32, // 真实行的数量(textui的帧缓冲区能容纳的内容的行数)
- current_window: Arc<SpinLock<TextuiWindow>>, // 当前的主窗口
- default_window: Arc<SpinLock<TextuiWindow>>, // 默认print到的窗口
- }
- impl TextUiFramework {
- pub fn new(
- metadata: ScmUiFrameworkMetadata,
- window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>>,
- current_window: Arc<SpinLock<TextuiWindow>>,
- default_window: Arc<SpinLock<TextuiWindow>>,
- ) -> Self {
- let actual_line =
- AtomicI32::new((metadata.buf_info().height() / TEXTUI_CHAR_HEIGHT) as i32);
- let inner = TextUiFramework {
- metadata: RwLock::new(metadata),
- window_list,
- actual_line,
- current_window,
- default_window,
- };
- return inner;
- }
- }
- impl ScmUiFramework for TextUiFramework {
- // 安装ui框架的回调函数
- fn install(&self) -> Result<i32, SystemError> {
- send_to_default_serial8250_port("\ntextui_install_handler\n\0".as_bytes());
- return Ok(0);
- }
- // 卸载ui框架的回调函数
- fn uninstall(&self) -> Result<i32, SystemError> {
- return Ok(0);
- }
- // 启用ui框架的回调函数
- fn enable(&self) -> Result<i32, SystemError> {
- textui_enable_put_to_window();
- return Ok(0);
- }
- // 禁用ui框架的回调函数
- fn disable(&self) -> Result<i32, SystemError> {
- textui_disable_put_to_window();
- return Ok(0);
- }
- // 改变ui框架的帧缓冲区的回调函数
- fn change(&self, buf_info: ScmBufferInfo) -> Result<i32, SystemError> {
- let old_buf = textui_framework().metadata.read().buf_info();
- textui_framework().metadata.write().set_buf_info(buf_info);
- let mut new_buf = textui_framework().metadata.read().buf_info();
- new_buf.copy_from_nonoverlapping(&old_buf);
- debug!("textui change buf_info: old: {:?}", old_buf);
- debug!("textui change buf_info: new: {:?}", new_buf);
- return Ok(0);
- }
- /// 获取ScmUiFramework的元数据
- /// ## 返回值
- ///
- /// -成功:Ok(ScmUiFramework的元数据)
- /// -失败:Err(错误码)
- fn metadata(&self) -> Result<ScmUiFrameworkMetadata, SystemError> {
- let metadata = self.metadata.read().clone();
- return Ok(metadata);
- }
- }
- /// Mapping from characters to glyph indices.
- pub trait GlyphMapping: Sync {
- /// Maps a character to a glyph index.
- ///
- /// If `c` isn't included in the font the index of a suitable replacement glyph is returned.
- fn index(&self, c: char) -> usize;
- }
- impl<F> GlyphMapping for F
- where
- F: Sync + Fn(char) -> usize,
- {
- fn index(&self, c: char) -> usize {
- self(c)
- }
- }
- /// 向默认窗口输出一个字符串
- pub fn textui_putstr(
- string: &str,
- fr_color: FontColor,
- bk_color: FontColor,
- ) -> Result<(), SystemError> {
- let window = if unsafe { TEXTUI_IS_INIT } {
- let fw = textui_framework();
- let w = fw.current_window.clone();
- Some(w)
- } else {
- None
- };
- let mut guard = window.as_ref().map(|w| w.lock_irqsave());
- for character in string.chars() {
- if unsafe { TEXTUI_IS_INIT } {
- guard.as_mut().unwrap().textui_putchar_window(
- character,
- fr_color,
- bk_color,
- textui_is_enable_put_to_window(),
- )?;
- } else {
- no_init_textui_putchar_window(
- character,
- fr_color,
- bk_color,
- textui_is_enable_put_to_window(),
- )?;
- }
- }
- return Ok(());
- }
- /// 初始化text ui框架
- #[inline(never)]
- pub fn textui_init() -> Result<i32, SystemError> {
- #[cfg(target_arch = "x86_64")]
- textui_framwork_init();
- return Ok(0);
- }
|