3 移动窗口(harib21c)

窗口切换的功能已经做的差不多了,这次我们来实现窗口的移动。之前我们只能移动task_a的窗口,这次的目标是实现像Windows一样的窗口移动功能。不过要如何才能实现呢……

当鼠标左键点击窗口时,如果点击位置位于窗口的标题栏区域,则进入“窗口移动模式”,使窗口的位置追随鼠标指针的移动,当放开鼠标左键时,退出“窗口移动模式”,返回通常模式。

要实现窗口的移动,我们需要记录鼠标指针所移动的距离,为此我们添加了两个变量:mmx和mmy,mm是“move mode”的缩写,这两个变量所记录的是移动之前的坐标。由于鼠标指针不会跑到画面以外,因此我们规定当mmx为负数时代表当前不处于窗口移动模式。

■■■■■

本次的bootpack.c节选

  1. void HariMain(void)
  2. {
  3. (中略)
  4. int j, x, y, mmx = -1, mmy = -1; /*这里!*/
  5. struct SHEET *sht = 0; /*这里!*/
  6. (中略)
  7. for (;;) {
  8. (中略)
  9. if (fifo32_status(&fifo) == 0) {
  10. (中略)
  11. } else {
  12. (中略)
  13. if (256 <= i && i <= 511) { /*键盘数据*/
  14. (中略)
  15. } else if (512 <= i && i <= 767) { /*鼠标数据*/
  16. if (mouse_decode(&mdec, i - 512) != 0) {
  17. /*鼠标指针移动*/
  18. (中略)
  19. if ((mdec.btn & 0x01) != 0) {
  20. /*按下左键*/
  21. /*从此开始*/ if (mmx < 0) {
  22. /*如果处于通常模式*/
  23. /*按照从上到下的顺序寻找鼠标所指向的图层*/
  24. for (j = shtctl->top - 1; j > 0; j--) {
  25. sht = shtctl->sheets[j];
  26. x = mx - sht->vx0;
  27. y = my - sht->vy0;
  28. if (0 <= x && x < sht->bxsize && 0 <= y && y < sht->bysize) {
  29. if (sht->buf[y * sht->bxsize + x] != sht->col_inv) {
  30. sheet_updown(sht, shtctl->top - 1);
  31. if (3 <= x && x < sht->bxsize - 3 && 3 <= y && y < 21) {
  32. mmx = mx; /*进入窗口移动模式*/
  33. mmy = my;
  34. }
  35. break;
  36. }
  37. }
  38. }
  39. } else {
  40. /*如果处于窗口移动模式*/
  41. x = mx - mmx; /*计算鼠标的移动距离*/
  42. y = my - mmy;
  43. sheet_slide(sht, sht->vx0 + x, sht->vy0 + y);
  44. mmx = mx; /*更新为移动后的坐标*/
  45. mmy = my;
  46. }
  47. } else {
  48. /*没有按下左键*/
  49. /*到此结束*/ mmx = -1; /*返回通常模式*/
  50. }
  51. }
  52. } else if (i <= 1) { /*光标用定时器*/
  53. (中略)
  54. }
  55. }
  56. }
  57. }

虽然代码有点长,不过静下心来仔细读一定能看懂的。

■■■■■

我们来“make run”试试看,能不能成功呢……哦哦,成功了!

3 移动窗口(harib21c) - 图1

可以像这样自由自在地移动哦

不过命令行窗口的移动速度太慢了!这大概是QEMU的原因,在真机环境下窗口的移动一定可以达到可接受的速度。还是有点不放心,于是在真机环境下测试了一下,不错,虽然还是有一点慢,不过这个速度也没什么问题。