简介
看似立体的窗口、按钮、输入框等,全是在2维坐标中画出来的。
目标
绘制简单的文本输入框和按住鼠标左键移动窗口。
1.os.c
makeWindow函数绘制输入框在消息窗体上
static void makeWindow(SHTCTL *shtctl,SHEET *sht) {
static char closebtn[14][16] = {
"[email protected]", "[email protected]","[email protected]",
"[email protected]@[email protected]@[email protected]", "[email protected]@[email protected]@[email protected]", "[email protected]@@@[email protected]",
"[email protected]@[email protected]", "[email protected]@@@[email protected]", "[email protected]@[email protected]@[email protected]",
"[email protected]@[email protected]@[email protected]", "[email protected]", "[email protected]",
"[email protected]", "@@@@@@@@@@@@@@@@"
};
int bxsize = sht->width;
int bysize = sht->height;
sheet_fillRect(0,0,bxsize,1,COL8_C6C6C6,sht);
sheet_fillRect(1,1,bxsize-2,1,COL8_FFFFFF,sht);
sheet_fillRect(0,0,1,bysize,COL8_C6C6C6,sht);
sheet_fillRect(1,1,1,bysize-1,COL8_FFFFFF,sht);
sheet_fillRect(bxsize-2,1,1,1,COL8_848484,sht);
sheet_fillRect(bxsize-1,0,1,bysize,COL8_000000,sht);
sheet_fillRect(2,2,bxsize-4,bysize-4,COL8_C6C6C6,sht);
sheet_fillRect(3,3,bxsize-6,18,COL8_000084,sht);
sheet_fillRect(1,bysize-2,bxsize-2,1,COL8_848484,sht);
sheet_fillRect(0,bysize-1,bxsize,1,COL8_000000,sht);
static char title[] = "hello";
showString(_shtctl,_shtMsg,2,4,COL8_FFFFFF,COL8_000084,title);
for(int y = 0; y < 14; y++) {
for (int x = 0; x < 16; x++) {
char c = closebtn[y][x];
if (c == '@') {
c = COL8_000000;
}
else if (c == '$') {
c = COL8_848484;
}
else if (c == 'Q') {
c = COL8_C6C6C6;
}
else {
c = COL8_FFFFFF;
}
sht->buf[(5+y) * sht->width + (sht->width-20 + x)] = c;
}
}
//在窗体上回执文本输入框
//白色输入框4边 左、上、右、下
sheet_fillRect(8,33,2,34,COL8_848484,sht);
sheet_fillRect(10,33,142,2,COL8_848484,sht);
sheet_fillRect(150,33,2,34,COL8_848484,sht);
sheet_fillRect(8,65,144,2,COL8_848484,sht);
//白色输入框
sheet_fillRect(10,35,140,30,COL8_FFFFFF,sht);
}
修改 runloop 实现文本输入框光标闪烁和文本输入
static void runloop(){
AddrRangeDes *memDes = (AddrRangeDes *)mem_block_buf();
int memCount = mem_block_count();
int memId = -1;
int index = 0;
//如果变量是没有用static 修饰,变量分配在栈上则定时器不会正常工作;
//原因估计是因为段寄存器中ss 和 ds 不一样
static FIFO8 fifo1;
static char buf1[8];
fifo8_init(&fifo1,8,buf1);
TIMER *t1 = timer_alloc(&_timctl);
timer_init(t1,&fifo1,1);
timer_setTimeout(t1,500);
int charCount = 0;
for(; ;){
//鼠标移动事件
if(_mousebufInfo.len>0){
mouseCursorMoved(&_mouseDes,COLOR_INVISIBLE);
}
//输入框光标
if(fifo1.len>0){
int data = fifo8_get(&fifo1);
if(data == 1){
sheet_fillRect(10+charCount*8+1,38,2,24,COL8_000000,_shtMsg);
sheet_refreshRect(_shtctl,_shtMsg,_shtMsg->x+10+charCount*8+1,_shtMsg->y+38,2,24);
timer_init(t1,&fifo1,0);
timer_setTimeout(t1,500);
}
else{
sheet_fillRect(10+charCount*8+1,38,2,26,COL8_FFFFFF,_shtMsg);
sheet_refreshRect(_shtctl,_shtMsg,_shtMsg->x+10+charCount*8+1,_shtMsg->y+38,2,24);
timer_init(t1,&fifo1,1);
timer_setTimeout(t1,500);
}
}
//断码 = 通码 + 0x80
if(_keybufInfo.len>0){
char data = fifo8_get(&_keybufInfo);
if(data == 0x1c){
memId++;
if(memId==memCount){
memId=0;
}
showMemInfo(memDes+memId,memId);
}
else if(scanCode2Ascii(data)!=0 && (unsigned char)data<0x80){
}
}
}
}
虚拟机加载floppy.img 效果如下:
移动窗口
鼠标事件发生后,硬件会给端口发送鼠标相关数据,内核拿到数据后会进行解析,如果结构体mdec.btn的第0位设置成1的话,表明鼠标的左键按下了。
1.os.c
//鼠标移动处理
void mouseCursorMoved(MouseDes *mdec,char bc){
unsigned char val = fifo8_get(&_mousebufInfo);
//表示处理到第3步,需要绘制鼠标光标
if(mouse_decode(mdec,val) == 1) {
int oldX = mdec->x,oldY = mdec->y;
mdec->x += mdec->offX;
mdec->y += mdec->offY;
if(mdec->x < 0){
mdec->x = 0;
}
else if(mdec->x > _vram.screenW-10){
mdec->x = _vram.screenW-10;
}
if(mdec->y < 0 ){
mdec->y = 0;
}
else if(mdec->y > _vram.screenH - 16){
mdec->y = _vram.screenH - 16;
}
sheet_slide(_shtctl,_shtMouse,mdec->x,mdec->y);
int flag = (mdec->btn & 0x01)==1;
flag = flag && (oldX>= _shtMsg->x && oldX <= _shtMsg->x+_shtMsg->width);
flag = flag && (oldY>= _shtMsg->y && oldY <= _shtMsg->y+_shtMsg->height);
if(flag){
int tmpX = _shtMsg->x+mdec->x-oldX;
int tmpY = _shtMsg->y+mdec->y-oldY;
if(tmpX<=0){
tmpX = 0;
}
else if(tmpX+_shtMsg->width > _vram.screenW){
tmpX = _vram.screenW-_shtMsg->width;
}
if(tmpY<=0){
tmpY = 0;
}
else if(tmpY+_shtMsg->height > _vram.screenH){
tmpY = _vram.screenH-_shtMsg->height;
}
sheet_slide(_shtctl,_shtMsg,tmpX,tmpY);
}
}
}
runloop函数中键盘处理逻辑修改如下
......
else if(scanCode2Ascii(data)!=0 && (unsigned char)data<0x80){
int len = 0;
_tempArr[len++] = scanCode2Ascii(data);
_tempArr[len++] = 0;
//先刷新光标内存数据
sheet_fillRect(10+charCount*8+1,38,2,26,COL8_FFFFFF,_shtMsg);
sheet_refreshRect(_shtctl,_shtMsg,_shtMsg->x+10+charCount*8+1,_shtMsg->y+38,2,24);
showString(_shtctl,_shtMsg,10+charCount*8,44,COL8_000000,COL8_FFFFFF,_tempArr);
charCount++;
}
......
2.win_sheet.c
为进一步优化图形绘制的效率sheet_slide 函数修改如下
void sheet_slide(SHTCTL *ctl,SHEET *sht, int vx0, int vy0){
int oldX = sht->x,oldY = sht->y;
sht->x = vx0;
sht->y = vy0;
//绘制移动前后组成的最大矩形区域
int minX = oldX;
int minY = oldY;
int maxX = vx0;
int maxY = vy0;
if(minX>maxX){
int tmp = minX;
minX = maxX;
maxX = tmp;
}
if(minY>maxY){
int tmp = minY;
minY = maxY;
maxY = tmp;
}
sheet_refreshRect(ctl,ctl->sheets[0],minX,minY,maxX-minX+sht->width,maxY-minY+sht->height);
}
3.虚拟机加载运行floppy.img 移动窗口后效果如下:
注意
目前在移动窗体时窗体会有闪烁问题,但是不影响对操作系统本质的学习。暂不理会,除非有必要时在想办法做优化!