发布于 

30天自制操作系统(11)

DAY11_制作窗口

1.鼠标显示问题

  • 我们系统的鼠标不能够向右或向下移动到画面之外隐藏起来。为此我们修改HariMain


if (mx > binfo->scrnx - 16) { 
mx = binfo->scrnx - 16;
}
if (my > binfo->scrny - 16) {
my = binfo->scrny - 16;
}

修改为
if (mx > binfo->scrnx - 1) { 
mx = binfo->scrnx - 1;
}
if (my > binfo->scrny - 1) {
my = binfo->scrny - 1;
}

2.实现画面外的支持

3.shtctl的指定省略

仅仅是上下移动图层就必须指定ctl太麻烦了。修改将sheet_refresh、sheet_slide、sheet_free等函数,让它们不再指定ctl

void sheet_refresh(struct SHEET *sht, int bx0, int by0, int bx1, int by1) 
{
if (sht->height >= 0) { /* 如果正在显示,则按新图层的信息进行刷新*/
sheet_refreshsub(sht->ctl, sht->vx0 + bx0, sht->vy0 + by0, sht->vx0 + bx1, sht->vy0 + by1);
}
return;
}
void sheet_slide(struct SHEET *sht, int vx0, int vy0)
{
int old_vx0 = sht->vx0, old_vy0 = sht->vy0;
sht->vx0 = vx0;
sht->vy0 = vy0;
if (sht->height >= 0) { /* 如果正在显示,则按新图层的信息进行刷新 */
sheet_refreshsub(sht->ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 +
sht->bysize);
sheet_refreshsub(sht->ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize);
}
return;
}
void sheet_free(struct SHEET *sht)
{
if (sht->height >= 0) {
sheet_updown(sht, -1); /* 如果正在显示,则先设置为隐藏 */
}
sht->flags = 0; /* 未使用标记 */
return;
}

4.显示窗口

  • 先准备一张图层,然后在图层缓冲区内描绘一个貌似窗口的图就可以了。

只是对graph.c的init_screen8函数稍微进行修改。

void make_window8(unsigned char *buf, int xsize, int ysize, char *title) 
{
static char closebtn[14][16] = {
"OOOOOOOOOOOOOOO@",
"OQQQQQQQQQQQQQ$@",
"OQQQQQQQQQQQQQ$@",
"OQQQ@@QQQQ@@QQ$@",
"OQQQQ@@QQ@@QQQ$@",
"OQQQQQ@@@@QQQQ$@",
"OQQQQQQ@@QQQQQ$@",
"OQQQQQ@@@@QQQQ$@",
"OQQQQ@@QQ@@QQQ$@",
"OQQQ@@QQQQ@@QQ$@",
"OQQQQQQQQQQQQQ$@",
"OQQQQQQQQQQQQQ$@",
"O$$$$$$$$$$$$$$@",
"@@@@@@@@@@@@@@@@"
};
int x, y;
char c;
boxfill8(buf, xsize, COL8_C6C6C6, 0, 0, xsize - 1, 0 );
boxfill8(buf, xsize, COL8_FFFFFF, 1, 1, xsize - 2, 1 );
boxfill8(buf, xsize, COL8_C6C6C6, 0, 0, 0, ysize - 1);
boxfill8(buf, xsize, COL8_FFFFFF, 1, 1, 1, ysize - 2);
boxfill8(buf, xsize, COL8_848484, xsize - 2, 1, xsize - 2, ysize - 2);
boxfill8(buf, xsize, COL8_000000, xsize - 1, 0, xsize - 1, ysize - 1);
boxfill8(buf, xsize, COL8_C6C6C6, 2, 2, xsize - 3, ysize - 3);
boxfill8(buf, xsize, COL8_000084, 3, 3, xsize - 4, 20 );
boxfill8(buf, xsize, COL8_848484, 1, ysize - 2, xsize - 2, ysize - 2);
boxfill8(buf, xsize, COL8_000000, 0, ysize - 1, xsize - 1, ysize - 1);
putfonts8_asc(buf, xsize, 24, 4, COL8_FFFFFF, title);
for (y = 0; y < 14; y++) {
for (x = 0; x < 16; x++) {
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;
}
buf[(5 + y) * xsize + (xsize - 21 + x)] = c;
}
}
return;
}

5.小实验

HariMain中有设置图层高度的地方,如果像下面这样,把窗口图层放在最上面,光标图层放在其次,会变成什么样呢?

sheet_updown(sht_back, 0); 
sheet_updown(sht_mouse, 1);
sheet_updown(sht_win, 2);

鼠标会跑到窗口图层的下面。

6.高速计数器

  • 我们要做一个能够计数,并且能够把计数结果显示出来的窗口。
  • 但是在刷新的时候,总是先刷新refresh范围内的背景图层,然后再刷新窗口图层,导致数字闪烁。

7.消除闪烁(1)

  • 窗口图层刷新是因为窗口的内容有变化,所以要在画面上显示变化后的新内容。基本上来讲,可以认为其他图层的内容没有变化(如果其他图层的内容也变了,那么应该会随后执行该图层的刷新)。
    既然如此,图层内容没有变化也进行刷新的话就太浪费了。如果只是窗口变了,那背景就不
    用刷新了。假如上面有鼠标,但鼠标的图层没有变化,我们也必须要刷新。窗口的刷新,可能会覆盖鼠标的一部分显示区域。
  • 在sheet_slide函数里,图层的移动有时会导致下面的图层露出,所以要从最下面开始刷新。
    另一方面,在移动目标处,比新移来的图层位置还要低的图层没有什么变化,而且只是隐藏起来了,所以只要刷新移动的图层和它上面的图层就可以了。
  • 但是修改代码后,鼠标放在数字区的时候,鼠标又开始闪烁。

8.消除闪烁(2)

  • 闪烁现象是由于一会儿描绘一会儿消除造成的。所以说要想消除闪烁,就要在刷新窗口时避开鼠标所在的地方对VRAM进行写入处理。
  • 方法:先开辟一块儿内存,大小和VRAM一样,这块内存用来表示画面上的点是哪个图层的像素,相当于图层的地图。
    d11.1

  • 今后程序会对照map内容来向VRAM中写入,所以有时没必要从下面开始一直刷新到最上面
    一层。

  • 在sheet_slide函数里,首先重写map,分别对应移动前后的图层,然后调用sheet_refreshsub函数。在移动前的地方,只针对上层图层移走之后而露出的下层图层进行重绘就可以了。在移动目的地处仅重绘了一张移动过去的图层。