mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-09 11:16:47 +00:00
new: 初步完成了textui的基本显示功能
This commit is contained in:
parent
36d55511ba
commit
17d5fea2cf
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@ -117,7 +117,10 @@
|
||||
"sched.h": "c",
|
||||
"preempt.h": "c",
|
||||
"softirq.h": "c",
|
||||
"screen_manager.h": "c"
|
||||
"screen_manager.h": "c",
|
||||
"textui.h": "c",
|
||||
"atomic.h": "c",
|
||||
"uart.h": "c"
|
||||
},
|
||||
"C_Cpp.errorSquiggles": "Enabled",
|
||||
"esbonio.sphinx.confDir": ""
|
||||
|
@ -13,10 +13,11 @@
|
||||
#include <driver/video/video.h>
|
||||
#include "math.h"
|
||||
#include <common/string.h>
|
||||
#include <lib/libUI/textui.h>
|
||||
|
||||
struct printk_screen_info pos;
|
||||
|
||||
static spinlock_t printk_lock;
|
||||
static spinlock_t printk_lock={1};
|
||||
static bool sw_show_scroll_animation = false; // 显示换行动画的开关
|
||||
|
||||
/**
|
||||
@ -662,49 +663,6 @@ static char *write_float_point_num(char *str, double num, int field_width, int p
|
||||
return str;
|
||||
}
|
||||
|
||||
static void putchar(uint *fb, int Xsize, int x, int y, unsigned int FRcolor, unsigned int BKcolor, unsigned char font)
|
||||
{
|
||||
/**
|
||||
* @brief 在屏幕上指定位置打印字符
|
||||
*
|
||||
* @param fb 帧缓存线性地址
|
||||
* @param Xsize 行分辨率
|
||||
* @param x 左上角列像素点位置
|
||||
* @param y 左上角行像素点位置
|
||||
* @param FRcolor 字体颜色
|
||||
* @param BKcolor 背景颜色
|
||||
* @param font 字符的bitmap
|
||||
*/
|
||||
|
||||
//#if DEBUG
|
||||
uart_send(COM1, font);
|
||||
//#endif
|
||||
|
||||
unsigned char *font_ptr = font_ascii[font];
|
||||
unsigned int *addr;
|
||||
|
||||
int testbit; // 用来测试某位是背景还是字体本身
|
||||
|
||||
for (int i = 0; i < pos.char_size_y; ++i)
|
||||
{
|
||||
// 计算出帧缓冲区的地址
|
||||
addr = fb + Xsize * (y + i) + x;
|
||||
testbit = (1 << (pos.char_size_x + 1));
|
||||
for (int j = 0; j < pos.char_size_x; ++j)
|
||||
{
|
||||
//从左往右逐个测试相应位
|
||||
testbit >>= 1;
|
||||
if (*font_ptr & testbit)
|
||||
*addr = FRcolor; // 字,显示前景色
|
||||
else
|
||||
*addr = BKcolor; // 背景色
|
||||
|
||||
++addr;
|
||||
}
|
||||
++font_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 格式化打印字符串
|
||||
*
|
||||
@ -715,9 +673,6 @@ static void putchar(uint *fb, int Xsize, int x, int y, unsigned int FRcolor, uns
|
||||
int printk_color(unsigned int FRcolor, unsigned int BKcolor, const char *fmt, ...)
|
||||
{
|
||||
|
||||
uint64_t rflags = 0; // 加锁后rflags存储到这里
|
||||
spin_lock_irqsave(&printk_lock, rflags);
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
char buf[4096]; // vsprintf()的缓冲区
|
||||
@ -733,47 +688,43 @@ int printk_color(unsigned int FRcolor, unsigned int BKcolor, const char *fmt, ..
|
||||
//输出换行
|
||||
if (current == '\n')
|
||||
{
|
||||
pos.x = 0;
|
||||
++pos.y;
|
||||
auto_newline();
|
||||
}
|
||||
else if (current == '\t') // 输出制表符
|
||||
{
|
||||
int space_to_print = 8 - pos.x % 8;
|
||||
|
||||
while (space_to_print--)
|
||||
{
|
||||
putchar(pos.FB_address, pos.width, pos.x * pos.char_size_x, pos.y * pos.char_size_y, FRcolor, BKcolor, ' ');
|
||||
++pos.x;
|
||||
textui_putchar(current);
|
||||
}
|
||||
// else if (current == '\t') // 输出制表符
|
||||
// {
|
||||
// int space_to_print = 8 - pos.x % 8;
|
||||
|
||||
auto_newline();
|
||||
}
|
||||
}
|
||||
else if (current == '\b') // 退格
|
||||
{
|
||||
--pos.x;
|
||||
if (pos.x < 0)
|
||||
{
|
||||
--pos.y;
|
||||
if (pos.y <= 0)
|
||||
pos.x = pos.y = 0;
|
||||
else
|
||||
pos.x = pos.max_x;
|
||||
}
|
||||
// while (space_to_print--)
|
||||
// {
|
||||
// textui_putchar(' ');
|
||||
// ++pos.x;
|
||||
// }
|
||||
// }
|
||||
// else if (current == '\b') // 退格
|
||||
// {
|
||||
// --pos.x;
|
||||
// if (pos.x < 0)
|
||||
// {
|
||||
// --pos.y;
|
||||
// if (pos.y <= 0)
|
||||
// pos.x = pos.y = 0;
|
||||
// else
|
||||
// pos.x = pos.max_x;
|
||||
// }
|
||||
|
||||
putchar(pos.FB_address, pos.width, pos.x * pos.char_size_x, pos.y * pos.char_size_y, FRcolor, BKcolor, ' ');
|
||||
// textui_putchar(' ');
|
||||
|
||||
auto_newline();
|
||||
}
|
||||
// auto_newline();
|
||||
// }
|
||||
else
|
||||
{
|
||||
putchar(pos.FB_address, pos.width, pos.x * pos.char_size_x, pos.y * pos.char_size_y, FRcolor, BKcolor, current);
|
||||
++pos.x;
|
||||
auto_newline();
|
||||
if (current != '\0')
|
||||
textui_putchar(current);
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&printk_lock, rflags);
|
||||
// spin_unlock_irqrestore(&printk_lock, rflags);
|
||||
return i;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
all: screen_manager.o textui.o
|
||||
all: screen_manager.o textui.o textui-render.o
|
||||
|
||||
CFLAGS += -I .
|
||||
|
||||
@ -8,3 +8,6 @@ screen_manager.o: screen_manager.c
|
||||
|
||||
textui.o: textui.c
|
||||
gcc $(CFLAGS) -c textui.c -o textui.o
|
||||
|
||||
textui-render.o: textui-render.c
|
||||
gcc $(CFLAGS) -c textui-render.c -o textui-render.o
|
||||
|
@ -8,8 +8,6 @@
|
||||
#include <driver/uart/uart.h>
|
||||
#include <driver/video/video.h>
|
||||
|
||||
|
||||
|
||||
extern struct scm_buffer_info_t video_frame_buffer_info;
|
||||
static struct List scm_framework_list;
|
||||
static spinlock_t scm_register_lock; // 框架注册锁
|
||||
@ -32,7 +30,7 @@ static struct scm_buffer_info_t *__create_buffer(uint64_t type)
|
||||
|
||||
struct scm_buffer_info_t *buf = (struct scm_buffer_info_t *)kmalloc(sizeof(struct scm_buffer_info_t), 0);
|
||||
if (buf == NULL)
|
||||
return (void*)-ENOMEM;
|
||||
return (void *)-ENOMEM;
|
||||
memset(buf, 0, sizeof(struct scm_buffer_info_t));
|
||||
buf->bit_depth = video_frame_buffer_info.bit_depth;
|
||||
buf->flags = SCM_BF_DB;
|
||||
@ -52,7 +50,7 @@ static struct scm_buffer_info_t *__create_buffer(uint64_t type)
|
||||
return buf;
|
||||
failed:;
|
||||
kfree(buf);
|
||||
return (void*)-ENOMEM;
|
||||
return (void *)-ENOMEM;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -106,7 +104,7 @@ static int __check_ui_param(const char *name, const uint8_t type, const struct s
|
||||
{
|
||||
if (name == NULL)
|
||||
return -EINVAL;
|
||||
if (!(type == SCM_FRAMWORK_TYPE_GUI || type == SCM_FRAMWORK_TYPE_TEXT))
|
||||
if ((type == SCM_FRAMWORK_TYPE_GUI || type == SCM_FRAMWORK_TYPE_TEXT) == 0)
|
||||
return -EINVAL;
|
||||
if (ops == NULL)
|
||||
return -EINVAL;
|
||||
|
@ -9,8 +9,8 @@
|
||||
#define SCM_BF_PIXEL (1 << 3) // 使用图像模式
|
||||
|
||||
// ui框架类型
|
||||
#define SCM_FRAMWORK_TYPE_TEXT 0
|
||||
#define SCM_FRAMWORK_TYPE_GUI 1
|
||||
#define SCM_FRAMWORK_TYPE_TEXT (uint8_t)0
|
||||
#define SCM_FRAMWORK_TYPE_GUI (uint8_t)1
|
||||
|
||||
/**
|
||||
* @brief 帧缓冲区信息结构体
|
||||
@ -47,7 +47,7 @@ struct scm_ui_framework_t
|
||||
uint8_t type;
|
||||
struct scm_ui_framework_operations_t *ui_ops;
|
||||
struct scm_buffer_info_t *buf;
|
||||
} __attribute__((aligned(sizeof(uint64_t))));
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 初始化屏幕管理模块
|
||||
|
155
kernel/lib/libUI/textui-render.c
Normal file
155
kernel/lib/libUI/textui-render.c
Normal file
@ -0,0 +1,155 @@
|
||||
#include "textui.h"
|
||||
#include <driver/uart/uart.h>
|
||||
|
||||
#define WHITE 0x00ffffff //白
|
||||
#define BLACK 0x00000000 //黑
|
||||
#define RED 0x00ff0000 //红
|
||||
#define ORANGE 0x00ff8000 //橙
|
||||
#define YELLOW 0x00ffff00 //黄
|
||||
#define GREEN 0x0000ff00 //绿
|
||||
#define BLUE 0x000000ff //蓝
|
||||
#define INDIGO 0x0000ffff //靛
|
||||
#define PURPLE 0x008000ff //紫
|
||||
|
||||
// 根据rgb计算出最终的颜色值
|
||||
#define calculate_color(r, g, b) ((((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff)) & 0x00ffffff)
|
||||
|
||||
extern struct scm_ui_framework_t textui_framework;
|
||||
|
||||
static void __textui_render_chromatic(uint16_t actual_line, uint16_t index, struct textui_char_chromatic_t *character);
|
||||
|
||||
/**
|
||||
* @brief 重新渲染整个虚拟行
|
||||
*
|
||||
* @param window 窗口结构体
|
||||
* @param vline_id 虚拟行号
|
||||
* @return int 错误码
|
||||
*/
|
||||
int textui_refresh_vline(struct textui_window_t *window, uint16_t vline_id)
|
||||
{
|
||||
if (textui_is_chromatic(window->flags))
|
||||
return textui_refresh_characters(window, vline_id, 0, window->chars_per_line);
|
||||
else
|
||||
return textui_refresh_characters(window, vline_id, 0, window->chars_per_line);
|
||||
}
|
||||
|
||||
int textui_refresh_vlines(struct textui_window_t *window, uint16_t start, uint16_t count)
|
||||
{
|
||||
char bufff[16] = {0};
|
||||
// uart_send_str(COM1, " BEGIN ");
|
||||
for (int i = start; i < window->vlines_num && count > 0; ++i, --count)
|
||||
{
|
||||
// sprintk(bufff, "[ 1fresh: %d ] ", i);
|
||||
// uart_send_str(COM1, bufff);
|
||||
textui_refresh_vline(window, i);
|
||||
}
|
||||
start = 0;
|
||||
while (count>0)
|
||||
{
|
||||
// sprintk(bufff, "[ 2fresh: %d ] ", start);
|
||||
// uart_send_str(COM1, bufff);
|
||||
// sprintk(bufff, " index=%d ", (window->vlines.chromatic)[start].index);
|
||||
// uart_send_str(COM1, bufff);
|
||||
textui_refresh_vline(window, start);
|
||||
++start;
|
||||
--count;
|
||||
}
|
||||
// uart_send_str(COM1, " END ");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 刷新某个虚拟行的连续n个字符对象
|
||||
*
|
||||
* @param window 窗口结构体
|
||||
* @param vline_id 虚拟行号
|
||||
* @param start 起始字符号
|
||||
* @param count 要刷新的字符数量
|
||||
* @return int 错误码
|
||||
*/
|
||||
int textui_refresh_characters(struct textui_window_t *window, uint16_t vline_id, uint16_t start, uint16_t count)
|
||||
{
|
||||
if (window->id != __textui_get_current_window_id())
|
||||
return 0;
|
||||
// 判断虚拟行参数是否合法
|
||||
if (unlikely(vline_id >= window->vlines_num && (start + count) > window->chars_per_line))
|
||||
return -EINVAL;
|
||||
|
||||
// 计算虚拟行对应的真实行
|
||||
int actual_line_id = (int)vline_id - window->top_vline;
|
||||
if (actual_line_id < 0)
|
||||
actual_line_id += __textui_get_actual_lines();
|
||||
// 判断真实行id是否合理
|
||||
if (unlikely(actual_line_id < 0 || actual_line_id >= __textui_get_actual_lines()))
|
||||
return 0;
|
||||
|
||||
// 若是彩色像素模式
|
||||
if (textui_is_chromatic(window->flags))
|
||||
{
|
||||
struct textui_vline_chromatic_t *vline = &(window->vlines.chromatic)[vline_id];
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
|
||||
__textui_render_chromatic(actual_line_id, start + i, &vline->chars[start + i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 渲染彩色字符
|
||||
*
|
||||
* @param actual_line 真实行的行号
|
||||
* @param index 列号
|
||||
* @param character 要渲染的字符
|
||||
*/
|
||||
static void __textui_render_chromatic(uint16_t actual_line, uint16_t index, struct textui_char_chromatic_t *character)
|
||||
{
|
||||
/**
|
||||
* @brief 在屏幕上指定位置打印字符
|
||||
*
|
||||
* @param x 左上角列像素点位置
|
||||
* @param y 左上角行像素点位置
|
||||
* @param FRcolor 字体颜色
|
||||
* @param BKcolor 背景颜色
|
||||
* @param font 字符的bitmap
|
||||
*/
|
||||
|
||||
// #if DEBUG
|
||||
// uart_send(COM1, font);
|
||||
// #endif
|
||||
|
||||
unsigned char *font_ptr = font_ascii[(uint8_t)character->c];
|
||||
unsigned int *addr;
|
||||
uint32_t *fb = (uint32_t *)textui_framework.buf->vaddr;
|
||||
// uint32_t FRcolor = YELLOW;
|
||||
uint32_t FRcolor = calculate_color(character->Fr, character->Fg, character->Fb);
|
||||
// uint32_t BKcolor = BLACK;
|
||||
uint32_t BKcolor = calculate_color(character->Br, character->Bg, character->Bb);
|
||||
|
||||
uint32_t x = index * TEXTUI_CHAR_WIDTH;
|
||||
uint32_t y = actual_line * TEXTUI_CHAR_HEIGHT;
|
||||
|
||||
int testbit; // 用来测试某位是背景还是字体本身
|
||||
|
||||
for (int i = 0; i < TEXTUI_CHAR_HEIGHT; ++i)
|
||||
{
|
||||
// 计算出帧缓冲区的地址
|
||||
addr = (uint32_t *)(fb + textui_framework.buf->width * (y + i) + x);
|
||||
|
||||
testbit = (1 << (TEXTUI_CHAR_WIDTH + 1));
|
||||
for (int j = 0; j < TEXTUI_CHAR_WIDTH; ++j)
|
||||
{
|
||||
// 从左往右逐个测试相应位
|
||||
testbit >>= 1;
|
||||
if (*font_ptr & testbit)
|
||||
*addr = FRcolor; // 字,显示前景色
|
||||
else
|
||||
*addr = BKcolor; // 背景色
|
||||
|
||||
++addr;
|
||||
}
|
||||
++font_ptr;
|
||||
}
|
||||
}
|
@ -4,31 +4,93 @@
|
||||
#include "driver/uart/uart.h"
|
||||
#include <common/string.h>
|
||||
#include <common/printk.h>
|
||||
#include <common/atomic.h>
|
||||
|
||||
struct scm_ui_framework_t textui_framework;
|
||||
static spinlock_t __window_id_lock = {1};
|
||||
static uint32_t __window_max_id = 0;
|
||||
|
||||
// 暂时初始化16080个初始字符对象以及67个虚拟行对象
|
||||
#define INITIAL_CHARS 16080
|
||||
#define INITIAL_VLINES (int)(1080 / 16)
|
||||
static struct textui_char_chromatic_t __initial_chars[INITIAL_CHARS] = {0};
|
||||
static struct textui_vline_chromatic_t __initial_vlines[INITIAL_VLINES] = {0};
|
||||
static struct textui_window_t __initial_window = {0}; // 初始窗口
|
||||
static struct textui_private_info_t __private_info = {0};
|
||||
static struct List __windows_list;
|
||||
|
||||
/**
|
||||
* @brief 初始化window对象
|
||||
*
|
||||
* @param window 窗口对象
|
||||
* @param flags 标志位
|
||||
* @param vlines_num 虚拟行的总数
|
||||
* @param vlines_ptr 虚拟行数组指针
|
||||
* @param cperline 每行最大的字符数
|
||||
*/
|
||||
static int __textui_init_window(struct textui_window_t *window, uint8_t flags, uint16_t vlines_num, void *vlines_ptr, uint16_t cperline)
|
||||
{
|
||||
memset((window), 0, sizeof(struct textui_window_t));
|
||||
list_init(&(window)->list);
|
||||
window->lock.lock = 1;
|
||||
spin_lock(&__window_id_lock);
|
||||
window->id = __window_max_id++;
|
||||
spin_unlock(&__window_id_lock);
|
||||
window->flags = flags;
|
||||
window->vlines_num = vlines_num;
|
||||
window->vlines_used = 1;
|
||||
window->top_vline = 0;
|
||||
window->vline_operating = 0;
|
||||
window->chars_per_line = cperline;
|
||||
if (textui_is_chromatic(flags))
|
||||
window->vlines.chromatic = vlines_ptr;
|
||||
else
|
||||
window->vlines.normal = vlines_ptr;
|
||||
list_add(&__windows_list, &(window)->list);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化虚拟行对象
|
||||
*
|
||||
* @param vline 虚拟行对象指针
|
||||
* @param chars_ptr 字符对象数组指针
|
||||
*/
|
||||
#define __textui_init_vline(vline, chars_ptr) \
|
||||
do \
|
||||
{ \
|
||||
memset(vline, 0, sizeof(struct textui_vline_chromatic_t)); \
|
||||
(vline)->index = 0; \
|
||||
(vline)->chars = chars_ptr; \
|
||||
} while (0)
|
||||
|
||||
int textui_install_handler(struct scm_buffer_info_t *buf)
|
||||
{
|
||||
return printk_init(buf);
|
||||
// return printk_init(buf);
|
||||
uart_send_str(COM1, "textui_install_handler");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int textui_uninstall_handler(void *args)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int textui_enable_handler(void *args)
|
||||
{
|
||||
uart_send_str(COM1, "textui_enable_handler");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int textui_disable_handler(void *args)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int textui_change_handler(struct scm_buffer_info_t *buf)
|
||||
{
|
||||
memcpy((void*)buf->vaddr, (void*)(textui_framework.buf->vaddr), textui_framework.buf->size);
|
||||
memcpy((void *)buf->vaddr, (void *)(textui_framework.buf->vaddr), textui_framework.buf->size);
|
||||
textui_framework.buf = buf;
|
||||
set_pos_VBE_FB_addr((uint*)buf->vaddr);
|
||||
set_pos_VBE_FB_addr((uint *)buf->vaddr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -41,6 +103,172 @@ struct scm_ui_framework_operations_t textui_ops =
|
||||
.disable = &textui_disable_handler,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取textui的帧缓冲区能容纳的内容的行数
|
||||
*
|
||||
* @return uint16_t
|
||||
*/
|
||||
uint16_t __textui_get_actual_lines()
|
||||
{
|
||||
return __private_info.actual_line;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取当前渲染的窗口的id
|
||||
*
|
||||
* @return uint16_t
|
||||
*/
|
||||
uint32_t __textui_get_current_window_id()
|
||||
{
|
||||
return __private_info.current_window->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 插入换行
|
||||
*
|
||||
* @param window 窗口结构体
|
||||
* @param vline_id 虚拟行号
|
||||
* @return int
|
||||
*/
|
||||
static int __textui_new_line(struct textui_window_t *window, uint16_t vline_id)
|
||||
{
|
||||
// todo: 支持在两个虚拟行之间插入一个新行
|
||||
|
||||
++window->vline_operating;
|
||||
|
||||
if (unlikely(window->vline_operating == window->vlines_num))
|
||||
window->vline_operating = 0;
|
||||
struct textui_vline_chromatic_t *vline = &window->vlines.chromatic[window->vline_operating];
|
||||
memset(vline->chars, 0, sizeof(struct textui_char_chromatic_t) * window->chars_per_line);
|
||||
vline->index = 0;
|
||||
|
||||
if (likely(window->vlines_used == window->vlines_num)) // 需要滚动屏幕
|
||||
{
|
||||
// uart_send_str(COM1, " scroll, top vline= ");
|
||||
++window->top_vline;
|
||||
// uart_send(COM1, '0' + window->top_vline);
|
||||
if (unlikely(window->top_vline >= window->vlines_num))
|
||||
window->top_vline = 0;
|
||||
|
||||
// int delta = ABS((int)window->vline_operating - (int)window->top_vline);
|
||||
// 刷新所有行
|
||||
textui_refresh_vlines(window, window->top_vline, window->vlines_num);
|
||||
}
|
||||
else
|
||||
++window->vlines_used;
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int __textui_putchar_window(struct textui_window_t *window, uint16_t character)
|
||||
{
|
||||
if (textui_is_chromatic(window->flags)) // 启用彩色字符
|
||||
{
|
||||
struct textui_vline_chromatic_t *vline = &window->vlines.chromatic[window->vline_operating];
|
||||
|
||||
vline->chars[vline->index].c = character;
|
||||
vline->chars[vline->index].Fr = 0xff;
|
||||
vline->chars[vline->index].Fg = 0xff;
|
||||
vline->chars[vline->index].Fb = 0xff;
|
||||
vline->chars[vline->index].Br = 0;
|
||||
vline->chars[vline->index].Bg = 0;
|
||||
vline->chars[vline->index].Bb = 0;
|
||||
++vline->index;
|
||||
textui_refresh_characters(window, window->vline_operating, vline->index - 1, 1);
|
||||
// 换行
|
||||
if (vline->index >= window->chars_per_line)
|
||||
{
|
||||
__textui_new_line(window, window->vline_operating);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// todo: 支持纯文本字符
|
||||
while (1)
|
||||
pause();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* @brief 在指定窗口上输出一个字符
|
||||
*
|
||||
* @param window 窗口
|
||||
* @param character 字符
|
||||
* @return int
|
||||
*/
|
||||
int textui_putchar_window(struct textui_window_t *window, uint16_t character)
|
||||
{
|
||||
if (unlikely(character == '\0'))
|
||||
return 0;
|
||||
if (!textui_is_chromatic(window->flags)) // 暂不支持纯文本窗口
|
||||
return 0;
|
||||
|
||||
uint64_t rflags = 0; // 加锁后rflags存储到这里
|
||||
spin_lock_irqsave(&window->lock, rflags);
|
||||
uart_send(COM1, character);
|
||||
if (unlikely(character == '\n'))
|
||||
{
|
||||
__textui_new_line(window, window->vline_operating);
|
||||
spin_unlock_irqrestore(&window->lock, rflags);
|
||||
return 0;
|
||||
}
|
||||
else if (character == '\t') // 输出制表符
|
||||
{
|
||||
int space_to_print = 8 - window->vlines.chromatic[window->vline_operating].index % 8;
|
||||
|
||||
while (space_to_print--)
|
||||
{
|
||||
__textui_putchar_window(window, ' ');
|
||||
}
|
||||
}
|
||||
else if (character == '\b') // 退格
|
||||
{
|
||||
|
||||
--window->vlines.chromatic[window->vline_operating].index;
|
||||
{
|
||||
uint16_t tmp = window->vlines.chromatic[window->vline_operating].index;
|
||||
window->vlines.chromatic[window->vline_operating].chars[tmp].c = ' ';
|
||||
textui_refresh_characters(window, window->vline_operating, tmp, 1);
|
||||
}
|
||||
|
||||
// 需要向上缩一行
|
||||
if (window->vlines.chromatic[window->vline_operating].index < 0)
|
||||
{
|
||||
window->vlines.chromatic[window->vline_operating].index = 0;
|
||||
memset(window->vlines.chromatic[window->vline_operating].chars, 0, sizeof(struct textui_char_chromatic_t) * window->chars_per_line);
|
||||
--window->vline_operating;
|
||||
if (unlikely(window->vline_operating < 0))
|
||||
window->vline_operating = window->vlines_num - 1;
|
||||
|
||||
// 考虑是否向上滚动
|
||||
if (likely(window->vlines_used >= __private_info.actual_line))
|
||||
{
|
||||
--window->top_vline;
|
||||
if (unlikely(window->top_vline < 0))
|
||||
window->top_vline = window->vlines_num - 1;
|
||||
}
|
||||
--window->vlines_used;
|
||||
textui_refresh_vlines(window, window->top_vline, __private_info.actual_line);
|
||||
}
|
||||
}
|
||||
else
|
||||
__textui_putchar_window(window, character);
|
||||
|
||||
spin_unlock_irqrestore(&window->lock, rflags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 在默认窗口上输出一个字符
|
||||
*
|
||||
* @param character 字符
|
||||
* @return int
|
||||
*/
|
||||
int textui_putchar(uint16_t character)
|
||||
{
|
||||
|
||||
return textui_putchar_window(__private_info.default_window, character);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化text ui框架
|
||||
*
|
||||
@ -48,14 +276,20 @@ struct scm_ui_framework_operations_t textui_ops =
|
||||
*/
|
||||
int textui_init()
|
||||
{
|
||||
memset(&textui_framework, 0, sizeof(textui_framework));
|
||||
spin_init(&__window_id_lock);
|
||||
__window_max_id = 0;
|
||||
list_init(&__windows_list);
|
||||
memset(&textui_framework, 0, sizeof(struct scm_ui_framework_t));
|
||||
memset(&__private_info, 0, sizeof(struct textui_private_info_t));
|
||||
|
||||
io_mfence();
|
||||
char name[] = "textUI";
|
||||
strcpy(textui_framework.name, name);
|
||||
|
||||
textui_framework.ui_ops = &textui_ops;
|
||||
textui_framework.type = SCM_FRAMWORK_TYPE_TEXT;
|
||||
uart_send_str(COM1, "12121");
|
||||
textui_framework.type = 0;
|
||||
|
||||
// 注册框架到屏幕管理器
|
||||
int retval = scm_register(&textui_framework);
|
||||
if (retval != 0)
|
||||
{
|
||||
@ -63,6 +297,26 @@ int textui_init()
|
||||
while (1)
|
||||
pause();
|
||||
}
|
||||
|
||||
uint16_t chars_per_vline = textui_framework.buf->width / TEXTUI_CHAR_WIDTH;
|
||||
uint16_t total_vlines = textui_framework.buf->height / TEXTUI_CHAR_HEIGHT;
|
||||
int cnt = chars_per_vline * total_vlines;
|
||||
|
||||
struct textui_vline_chromatic_t *vl_ptr = __initial_vlines;
|
||||
struct textui_char_chromatic_t *ch_ptr = __initial_chars;
|
||||
|
||||
// 初始化虚拟行
|
||||
for (int i = 0; i < total_vlines; ++i)
|
||||
{
|
||||
__textui_init_vline((vl_ptr + i), (ch_ptr + i * chars_per_vline));
|
||||
}
|
||||
|
||||
// 初始化窗口
|
||||
__textui_init_window((&__initial_window), TEXTUI_WF_CHROMATIC, total_vlines, __initial_vlines, chars_per_vline);
|
||||
__private_info.current_window = &__initial_window;
|
||||
__private_info.default_window = &__initial_window;
|
||||
__private_info.actual_line = textui_framework.buf->height / TEXTUI_CHAR_HEIGHT;
|
||||
|
||||
uart_send_str(COM1, "text ui initialized");
|
||||
return 0;
|
||||
}
|
@ -1,4 +1,152 @@
|
||||
#pragma once
|
||||
#include <common/glib.h>
|
||||
#include <common/sys/types.h>
|
||||
#include <common/spinlock.h>
|
||||
|
||||
// 文本窗口标志位
|
||||
// 文本窗口是否为彩色
|
||||
#define TEXTUI_WF_CHROMATIC (1 << 0)
|
||||
|
||||
// 窗口是否启用彩色字符
|
||||
#define textui_is_chromatic(flag) ((flag)&TEXTUI_WF_CHROMATIC)
|
||||
|
||||
// 每个字符的宽度和高度(像素)
|
||||
#define TEXTUI_CHAR_WIDTH 8
|
||||
#define TEXTUI_CHAR_HEIGHT 16
|
||||
|
||||
/**
|
||||
* @brief 黑白字符对象
|
||||
*
|
||||
*/
|
||||
struct textui_char_normal_t
|
||||
{
|
||||
char c;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 彩色字符对象
|
||||
*
|
||||
*/
|
||||
struct textui_char_chromatic_t
|
||||
{
|
||||
uint16_t c; // 字符
|
||||
// 前景色
|
||||
uint8_t Fr; // 红
|
||||
uint8_t Fg; // 绿
|
||||
uint8_t Fb; // 蓝
|
||||
|
||||
// 背景色
|
||||
uint8_t Br;
|
||||
uint8_t Bg;
|
||||
uint8_t Bb;
|
||||
};
|
||||
|
||||
// 注意!!! 请保持vline结构体的大小、成员变量命名相等!
|
||||
/**
|
||||
* @brief 单色显示的虚拟行结构体
|
||||
*
|
||||
*/
|
||||
struct textui_vline_normal_t
|
||||
{
|
||||
struct textui_char_normal_t *chars; // 字符对象数组
|
||||
uint16_t index; // 当前操作的位置
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 彩色显示的虚拟行结构体
|
||||
*
|
||||
*/
|
||||
struct textui_vline_chromatic_t
|
||||
{
|
||||
struct textui_char_chromatic_t *chars;
|
||||
uint16_t index; // 当前操作的位置
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief textu ui 框架的文本窗口结构体
|
||||
*
|
||||
*/
|
||||
struct textui_window_t
|
||||
{
|
||||
struct List list;
|
||||
|
||||
uint32_t id; // 窗口id
|
||||
uint16_t vlines_num; // 虚拟行总数
|
||||
uint16_t vlines_used; // 当前已经使用了的虚拟行总数
|
||||
|
||||
// 指向虚拟行的数组的指针(二选一)
|
||||
union
|
||||
{
|
||||
struct textui_vline_normal_t *normal;
|
||||
struct textui_vline_chromatic_t *chromatic;
|
||||
} vlines;
|
||||
|
||||
uint16_t top_vline; // 位于最顶上的那一个虚拟行的行号
|
||||
uint16_t vline_operating; // 正在操作的vline
|
||||
uint16_t chars_per_line; // 每行最大容纳的字符数
|
||||
uint8_t flags; // 窗口flag
|
||||
spinlock_t lock; // 窗口操作锁
|
||||
};
|
||||
|
||||
struct textui_private_info_t
|
||||
{
|
||||
uint16_t actual_line; // 真实行的数量
|
||||
struct textui_window_t *current_window; // 当前的主窗口
|
||||
struct textui_window_t *default_window; // 默认print到的窗口
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 重新渲染整个虚拟行
|
||||
*
|
||||
* @param window 窗口结构体
|
||||
* @param vline_id 虚拟行号
|
||||
* @return int 错误码
|
||||
*/
|
||||
int textui_refresh_vline(struct textui_window_t *window, uint16_t vline_id);
|
||||
|
||||
int textui_refresh_vlines(struct textui_window_t *window, uint16_t start, uint16_t count);
|
||||
|
||||
/**
|
||||
* @brief 刷新某个虚拟行的连续n个字符对象
|
||||
*
|
||||
* @param window 窗口结构体
|
||||
* @param vline_id 虚拟行号
|
||||
* @param start 起始字符号
|
||||
* @param count 要刷新的字符数量
|
||||
* @return int 错误码
|
||||
*/
|
||||
int textui_refresh_characters(struct textui_window_t *window, uint16_t vline_id, uint16_t start, uint16_t count);
|
||||
|
||||
/**
|
||||
* @brief 在指定窗口上输出一个字符
|
||||
*
|
||||
* @param window 窗口
|
||||
* @param character 字符
|
||||
* @return int
|
||||
*/
|
||||
int textui_putchar_window(struct textui_window_t *window, uint16_t character);
|
||||
|
||||
/**
|
||||
* @brief 在默认窗口上输出一个字符
|
||||
*
|
||||
* @param character 字符
|
||||
* @return int
|
||||
*/
|
||||
int textui_putchar(uint16_t character);
|
||||
|
||||
/**
|
||||
* @brief 获取textui的帧缓冲区能容纳的内容的行数
|
||||
*
|
||||
* @return uint16_t
|
||||
*/
|
||||
uint16_t __textui_get_actual_lines();
|
||||
|
||||
/**
|
||||
* @brief 获取当前渲染的窗口的id
|
||||
*
|
||||
* @return uint16_t
|
||||
*/
|
||||
uint32_t __textui_get_current_window_id();
|
||||
|
||||
/**
|
||||
* @brief 初始化text ui框架
|
||||
|
@ -76,11 +76,9 @@ void system_initialize()
|
||||
|
||||
scm_init();
|
||||
textui_init();
|
||||
|
||||
kinfo("Kernel Starting...");
|
||||
// kinfo("Kernel Starting...");
|
||||
|
||||
// 重新加载gdt和idt
|
||||
|
||||
ul tss_item_addr = (ul)phys_2_virt(0x7c00);
|
||||
|
||||
_stack_start = head_stack_start; // 保存init proc的栈基地址(由于之后取消了地址重映射,因此必须在这里重新保存)
|
||||
@ -100,6 +98,7 @@ void system_initialize()
|
||||
|
||||
// 初始化内存管理单元
|
||||
mm_init();
|
||||
|
||||
// 内存管理单元初始化完毕后,需要立即重新初始化显示驱动。
|
||||
// 原因是,系统启动初期,framebuffer被映射到48M地址处,
|
||||
// mm初始化完毕后,若不重新初始化显示驱动,将会导致错误的数据写入内存,从而造成其他模块崩溃
|
||||
@ -165,7 +164,6 @@ void system_initialize()
|
||||
process_init();
|
||||
// 启用double buffer
|
||||
scm_enable_double_buffer();
|
||||
|
||||
io_mfence();
|
||||
|
||||
// fat32_init();
|
||||
@ -175,6 +173,7 @@ void system_initialize()
|
||||
// 系统初始化到此结束,剩下的初始化功能应当放在初始内核线程中执行
|
||||
apic_timer_init();
|
||||
io_mfence();
|
||||
while(1);
|
||||
}
|
||||
|
||||
//操作系统内核从这里开始执行
|
||||
|
Loading…
x
Reference in New Issue
Block a user