Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15498845
  • 博文数量: 2005
  • 博客积分: 11986
  • 博客等级: 上将
  • 技术积分: 22535
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-17 13:56
文章分类

全部博文(2005)

文章存档

2014年(2)

2013年(2)

2012年(16)

2011年(66)

2010年(368)

2009年(743)

2008年(491)

2007年(317)

分类: C/C++

2007-07-13 10:43:15

浅析μC/GUI-v3.90a之WM_ITERATE_START剪切域计算宏

文章来源:http://gliethttp.cublog.cn

接续《浅析μC/GUI-v3.90a之GUI_DispString函数》讨论WM_ITERATE_START剪切域计算宏
//剪切域宗旨:本hWin内部被控件占用的部分不用绘制;窗体Z序中比本hWin窗体高的窗体遮盖住本hWin的部分不用绘制;
//本hWin超出parent窗体边界的部分不用绘制;窗体的窗体Z序比本hWin的parent窗体高的窗体遮盖住本hWin需要绘制的部分不需要绘制;
//这就是剪切域绘制的宗旨,让绘制部分最小,通过复杂的cpu计算,避免窗体互相遮盖部分的重复绘制,提高显式速度,增加lcd使用寿命.[gliethttp]
//计算完剪切域之后,通过WM__ActivateClipRect()将会使_ClipContext.CurRect传递给GUI_Context.ClipRect,最终影响绘图的有效空间
//拿对当前hWin进行GUI_Clear()来说,剪切域的绘制顺序是上到下窄条依次绘制,在上到下的过程中又会由左到右依次计算绘制
-------------------------------------------------------------------------------------
1.
    ...
    {
    r = *pr;
    #if GUI_WINSUPPORT
    WM_ADDORG(r.x0, r.y0);
    WM_ADDORG(r.x1, r.y1);                                 //平移矩形r
    WM_ITERATE_START(&r) {                                 //计算r矩形区域内的剪切域
    #endif
      GUI_Context.DispPosX = r.x0;
      GUI_Context.DispPosY = r.y0;
      _DispLine(s, MaxNumChars, &r);
    #if GUI_WINSUPPORT
    } WM_ITERATE_END();
    #endif
  }
  ...
-------------------------------------------------------------------------------------
2.WM_ITERATE_START宏
gui/wm/WM_GUI.h
#define WM_ITERATE_START(pRect) \
  { \
    if (WM__InitIVRSearch(pRect)) \                        //构造循环体
      do {
-------------------------------------------------------------------------------------
3.WM__InitIVRSearch()函数
gui/wm/WM.c
int WM__InitIVRSearch(const GUI_RECT* pMaxRect) {
  GUI_RECT r;
  WM_Obj* pAWin;
  GUI_ASSERT_LOCK();
  if (WM_IsActive==0) {
    WM__ActivateClipRect();
    return 1;
  }
  if (++_ClipContext.EntranceCnt > 1)                      //如果重入,返回,保持计算操作的唯一性
    return 1;
  pAWin = WM_H2P(GUI_Context.hAWin);                       //当前句柄,详情请参考《浅析μC/GUI-v3.98之WM_H2P()句柄hWin转内存函数》
  _ClipContext.Cnt = -1;
  if (WM__PaintCallbackCnt) {                              //从回调函数进入的剪切计算
    WM__GetInvalidRectAbs(pAWin, &r);                      //r=pWin->InvalidRect;r存放pWin失效矩形区
  } else {
    if (pAWin->Status & WM_SF_ISVIS) {
      r = pAWin->Rect;                                     //不是回调函数引起的剪切计算,那么整个pWin窗体作为失效区域
    } else {
      --_ClipContext.EntranceCnt;                          //窗体属性为不可见
      return 0;
    }
  }
  if (pMaxRect) {
    GUI__IntersectRect(&r, pMaxRect);                      //r依据pMaxRect,缩小自己的矩形区域
  }
  /* If user has reduced the cliprect size, reduce the rectangle */
  if (GUI_Context.WM__pUserClipRect) {
    WM_Obj* pWin = pAWin;                                  //用户指定了失效重绘区域,那么继续缩小r的矩形区域
    GUI_RECT rUser = *(GUI_Context.WM__pUserClipRect);
    #if WM_SUPPORT_TRANSPARENCY
      if (WM__hATransWindow) {                             //具有半透明属性
        pWin = WM_H2P(WM__hATransWindow);
      }
    #endif
    WM__Client2Screen(pWin, &rUser);                       //以pWin(x0,y0)位坐标原点,平移rUser矩形
    GUI__IntersectRect(&r, &rUser);                        //继续缩小r矩形区
  }
  #if WM_SUPPORT_TRANSPARENCY
    if (WM__hATransWindow) {                               //如果有半透明窗体,那么需要继续缩小剪切域r
      if (WM__ClipAtParentBorders(&r, WM__hATransWindow) == 0) {
        --_ClipContext.EntranceCnt;
        return 0;
      }
    }
  #endif
//主要进行如下五步操作:
//一.以上所有工作主要是是计算当前激活窗体hWin自身与pMaxRect的平面剪切区域r,
//二.接下来WM__ClipAtParentBorders()函数完成和hWin所有父窗体边框剪切,如果有一个父窗体属性为不可见,直接0退出
  if (WM__ClipAtParentBorders(&r, GUI_Context.hAWin) == 0) {
    --_ClipContext.EntranceCnt;
    return 0;
  }
  _ClipContext.ClientRect = r;                             //保存r重绘区域到IVR专用单元_ClipContext.ClientRect
  return WM__GetNextIVR();                                 //hWin自己的、所有父窗体的同级兄弟窗体与该r进行平面、三维立体z序混合剪切
}                                                          //pWin->hNext其实从窗口Z序来讲,是在pWin上面的控件,而不把pWin->hNext叫作hWin的兄弟
                                                           //pWin->hNext以及hNext->hNext都有权力覆盖hWin窗体,因为他们在窗口Z序的比hWin更靠近顶层处
-------------------------------------------------------------------------------------
4.WM__GetInvalidRectAbs()函数
gui/wm/WM.c
static void WM__GetInvalidRectAbs(WM_Obj* pWin, GUI_RECT* pRect) {
  *pRect = pWin->InvalidRect;
}
-------------------------------------------------------------------------------------
5.WM__GetNextIVR()函数
gui/wm/WM.c
int WM__GetNextIVR(void) {
  #if GUI_SUPPORT_CURSOR
    static char _CursorHidden;
  #endif
  if (WM_IsActive==0) {
    return 0;
  }
  if (_ClipContext.EntranceCnt > 1) {
    _ClipContext.EntranceCnt--;
    return 0;
  }                                                        //非法性检查
  #if GUI_SUPPORT_CURSOR
    if (_CursorHidden) {
      _CursorHidden = 0;
      (*GUI_CURSOR_pfTempUnhide) ();                       //如果当前鼠标,即上一次进入时鼠标不可见,那么显示鼠标
    }
  #endif
  ++_ClipContext.Cnt;
  /* Find next rectangle and use it as ClipRect */
//三.与窗口Z序比hWin->parent大的窗体进行剪切计算,缩小本次hWin绘制的区域
//四.与窗口Z序比hWin大的窗体进行剪切计算,继续缩小本次hWin绘制的区域
//五.与hWin窗体内部所有Child控件进行剪切计算,继继续缩小本次hWin绘制的区域
  if (!_FindNext_IVR()) {                                  //见函数6的注解
    _ClipContext.EntranceCnt--;
    return 0;
  }
  WM__ActivateClipRect();
  /* Hide cursor if necessary */
  #if GUI_SUPPORT_CURSOR
    if (GUI_CURSOR_pfTempHide) {
      _CursorHidden = (*GUI_CURSOR_pfTempHide) ( &_ClipContext.CurRect);
    }
  #endif
  return 1;
}
-------------------------------------------------------------------------------------
6._FindNext_IVR()函数
//2007-07-11 gliethttp宗旨就是:本hWin内部被控件占用的部分不用绘制,窗体Z序中比本hWin窗体高的窗体遮盖住本hWin的部分不用绘制
//本hWin超出parent窗体边界的部分不用绘制,窗体的窗体Z序比本hWin的parent窗体高的窗体遮盖住本hWin需要绘制的部分不需要绘制
//这样就是剪切域绘制的宗旨了,让绘制部分最小,通过复杂的cpu计算,避免窗体遮盖部分的重复绘制,提高显式速度,增加lcd使用寿命.
gui/wm/WM.c
static int _FindNext_IVR(void) {
  WM_HMEM hParent;
  GUI_RECT r;
  WM_Obj* pAWin;
  WM_Obj* pParent;
  r = _ClipContext.CurRect;
  //1.设置r的初始化值
  if (_ClipContext.Cnt == 0) {                             //如果从WM__InitIVRSearch()->WM__GetNextIVR()->_FindNext_IVR()进入
    r.x0 = _ClipContext.ClientRect.x0;                   //那么_ClipContext.Cnt==0成立,将WM__InitIVRSearch()计算的存储到_ClipContext.ClientRect的剪切域
    r.y0 = _ClipContext.ClientRect.y0;                     //读取到r中
  } else {
    r.x0 = _ClipContext.CurRect.x1+1;                      //接续上一已经绘制的窄条剪切域,继续进行其它窄条剪切域的计算
    r.y0 = _ClipContext.CurRect.y0;                        //绘制顺序是上到下窄条依次绘制,在上到下的过程中又会由左到右依次计算绘制
    if (r.x0 > _ClipContext.ClientRect.x1) {
NextStripe: /* go down to next stripe */
      r.x0 = _ClipContext.ClientRect.x0;
      r.y0 = _ClipContext.CurRect.y1+1;
    }
  }
  //2.检测剪切计算完成否
  if (r.y0 >_ClipContext.ClientRect.y1) {
    return 0;
  }
  //3.寻找pRect->y1这个下边沿在所有和pRect存在剪切关系控件窗体中的最小位置,即:"r.y1靠上计算"
  pAWin = WM_H2P(GUI_Context.hAWin);
  if (r.x0 == _ClipContext.ClientRect.x0) {
    r.y1 = _ClipContext.ClientRect.y1;
    r.x1 = _ClipContext.ClientRect.x1;
    /* Iterate over all windows which are above */
    /* Check all siblings above (Iterate over Parents and top siblings (hNext) */
    for (hParent = GUI_Context.hAWin; hParent; hParent = pParent->hParent) {
  //_Findy1就是寻找pRect->y1这个下边沿的最小位置
      pParent = WM_H2P(hParent);                           //计算GUI_Context.hAWin自己的哥们窗体[Z序比hWin高的窗口],
      _Findy1(pParent->hNext, &r, NULL);                   //和父窗体的哥们窗体分别和r剪切域[Z序比老爹高的窗口]
  //2007-07-11 gliethttp _Findy1()计算pParent->hNext和hNext->hNext等窗口Z序比pParent窗口Z序大的r剪切域
  //举例:如A,B两个窗口,A窗口Z序比B窗口Z序大,那么A就在B的上面,A可以覆盖B,但B不能覆盖A,因为A窗口Z序比B窗口Z序大
    }
    /* Check all children */
    _Findy1(pAWin->hFirstChild, &r, NULL);                 //对pWin窗体内部的所有孩子控件进行同样的r剪切计算
  }
  //4.调整pRect->x0到所有存在剪切关系的控件窗口的最右边rWinClipped.x1+1处,即:"r.x0靠右计算"
Find_x0:
  r.x1 = r.x0;
  {
    hParent = GUI_Context.hAWin;
  }
  for (; hParent; hParent = pParent->hParent) {
    pParent = WM_H2P(hParent);
    if (_Findx0(pParent->hNext, &r, NULL)) {
      goto Find_x0;                                        //如果pParent的窗口Z序上层中存在和该r剪切区域,调整r.x0到
    }                                                      //相应窗口Z序对应窗口的x1+1处,goto Find_x0继续计算接下来的pParent
  }                                                        //就这样一直将r.x0调整到所有与r存在剪切关系的窗口Z序上层窗体的右边x1+1处
  /* Check all children */
  if (_Findx0(pAWin->hFirstChild, &r, NULL)) {             //在自己hWin窗体内的所有孩子控件进行r.x0靠右计算
    goto Find_x0;
  }
  //5.如果r.x0 > r.x1即,r的右边框,那么该窄条剪切域完毕.goto NextStripe去找下一个窄条剪切域
  r.x1 = _ClipContext.ClientRect.x1;                       //恢复"r.x0靠右计算"中破坏了的r.x1
  if (r.x1 < r.x0) {
    _ClipContext.CurRect = r;
    goto NextStripe;                                       //x0过界,计算下一个需要重绘窄条剪切域
  }
  //6.调整pRect->x1到所有存在剪切关系的控件窗口的最左边rWinClipped.x0-1处,即:"r.x1靠左计算"
  {
    hParent = GUI_Context.hAWin;
  }
  for (; hParent; hParent = pParent->hParent) {
    pParent = WM_H2P(hParent);
    _Findx1(pParent->hNext, &r, NULL);
  }
  /* Check all children */
  _Findx1(pAWin->hFirstChild, &r, NULL);                   //在自己hWin窗体内的所有孩子控件进行r.x1靠左计算
  if (_ClipContext.Cnt >200) {
    return 0;                                              //最大嵌套数目
  }
  _ClipContext.CurRect = r;
  return 1;                                                //2007-07-11 gliethttp计算完毕;通过WM__ActivateClipRect()将会使
}                                                          //_ClipContext.CurRect传递给GUI_Context.ClipRect,来影响绘图的有效空间
-------------------------------------------------------------------------------------
6._Findy1()函数
gui/wm/WM.c
static void _Findy1(WM_HWIN iWin, GUI_RECT* pRect, GUI_RECT* pParentRect) {
  WM_Obj* pWin;                                            //_Findy1就是寻找pRect->y1这个下边沿的最小位置
  for (; iWin; iWin = pWin->hNext) {                       //窗体z序比hWin高的所有窗体中,剪切遮盖住本pRect的部分[gliethttp]:找y1.
    int Status = (pWin = WM_H2P(iWin))->Status;
    if (Status & WM_SF_ISVIS) {
      GUI_RECT rWinClipped;
      if (pParentRect) {                                   //指定了剪切参考
        GUI__IntersectRects(&rWinClipped, &pWin->Rect, pParentRect);
      } else {
        rWinClipped = pWin->Rect;                          //pWin->Rect作为剪切参考
      }
      if (GUI_RectsIntersect(pRect, &rWinClipped)) {
        if ((Status & WM_SF_HASTRANS) == 0) {
          if (pWin->Rect.y0 > pRect->y0) {
            ASSIGN_IF_LESS(pRect->y1, rWinClipped.y0 - 1); //将pRect->y1和rWinClipped矩形的上边延y0对齐
          } else {
            ASSIGN_IF_LESS(pRect->y1, rWinClipped.y1);     //将pRect->y1和rWinClipped矩形的下边延y1对齐
          }
        } else {
          /* Check all children*/
          WM_HWIN hChild;
          WM_Obj* pChild;
          for (hChild = pWin->hFirstChild; hChild; hChild = pChild->hNext) {
            pChild = WM_H2P(hChild);
            _Findy1(hChild, pRect, &rWinClipped);
          }
        }
      }
    }
  }
}
-------------------------------------------------------------------------------------
6._Findx0()函数
gui/wm/WM.c
static int _Findx0(WM_HWIN hWin, GUI_RECT* pRect, GUI_RECT* pParentRect) {
  WM_Obj* pWin;
  int r = 0;
  for (; hWin; hWin = pWin->hNext) {                       //窗体z序比hWin高的所有窗体中,剪切遮盖住本pRect的部分[gliethttp]:找x0.
    int Status = (pWin = WM_H2P(hWin))->Status;
    if (Status & WM_SF_ISVIS) {
      GUI_RECT rWinClipped;
      if (pParentRect) {
        GUI__IntersectRects(&rWinClipped, &pWin->Rect, pParentRect);
      } else {
        rWinClipped = pWin->Rect;
      }
      if (GUI_RectsIntersect(pRect, &rWinClipped)) {
        if ((Status & WM_SF_HASTRANS) == 0) {
          pRect->x0 = rWinClipped.x1+1;                    //调整pRect->x0到所有存在剪切关系的控件窗口的右边rWinClipped.x1+1处
          r = 1;
        } else {
          /* Check all children */                         //半透明处理
          WM_HWIN hChild;
          WM_Obj* pChild;
          for (hChild = pWin->hFirstChild; hChild; hChild = pChild->hNext) {
            pChild = WM_H2P(hChild);
            if (_Findx0(hChild, pRect, &rWinClipped)) {
              r = 1;
            }
          }
        }
      }
    }
  }
  return r;
}
-------------------------------------------------------------------------------------
6._Findx1()函数
static void _Findx1(WM_HWIN hWin, GUI_RECT* pRect, GUI_RECT* pParentRect) {
  WM_Obj* pWin;
  for (; hWin; hWin = pWin->hNext) {                       //窗体z序比hWin高的所有窗体中,剪切遮盖住本pRect的部分[gliethttp]:找x1.
    int Status = (pWin = WM_H2P(hWin))->Status;
    if (Status & WM_SF_ISVIS) {
      GUI_RECT rWinClipped;
      if (pParentRect) {
        GUI__IntersectRects(&rWinClipped, &pWin->Rect, pParentRect);
      } else {
        rWinClipped = pWin->Rect;
      }
      if (GUI_RectsIntersect(pRect, &rWinClipped)) {
        if ((Status & WM_SF_HASTRANS) == 0) {
          pRect->x1 = rWinClipped.x0-1;                    //调整pRect->x1到所有存在剪切关系的控件窗口的左边rWinClipped.x0-1处
        } else {
          /* Check all children */                         //半透明处理
          WM_HWIN hChild;
          WM_Obj* pChild;
          for (hChild = pWin->hFirstChild; hChild; hChild = pChild->hNext) {
            pChild = WM_H2P(hChild);
            _Findx1(hChild, pRect, &rWinClipped);
          }
        }
      }
    }
  }
}

阅读(2972) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~