简介

看似立体的窗口、按钮、输入框等,全是在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 效果如下:
26.绘制文本框和移动窗口

移动窗口

鼠标事件发生后,硬件会给端口发送鼠标相关数据,内核拿到数据后会进行解析,如果结构体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 移动窗口后效果如下:
26.绘制文本框和移动窗口

注意

目前在移动窗体时窗体会有闪烁问题,但是不影响对操作系统本质的学习。暂不理会,除非有必要时在想办法做优化!

相关文章: