Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15502878
  • 博文数量: 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-10 10:44:06

浅析μC/GUI-v3.98之WM_CreateWindowAsChild窗体创建函数

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

-------------------------------------------------------------------------------------
1.WM_CreateWindowAsChild()函数
gui/wm/WM.c
WM_HWIN WM_CreateWindowAsChild( int x0, int y0, int width, int height
                               ,WM_HWIN hParent, U16 Style, WM_CALLBACK* cb
                               ,int NumExtraBytes) {
  WM_Obj* pWin;
  WM_HWIN hWin;
  WM_ASSERT_NOT_IN_PAINT();
  WM_LOCK();                                               //以上为保护措
  Style |= WM__CreateFlags;
  /* Default parent is Desktop 0 */
  if (!hParent) {
    if (WM__NumWindows) {                                  //hParent=0表示以Desktop为本窗体的父窗体
    #if GUI_NUM_LAYERS == 1
      hParent = WM__ahDesktopWin[0];
    #else
      hParent = WM__ahDesktopWin[GUI_Context.SelLayer];
    #endif
    }
  }
  if (hParent == WM_UNATTACHED) {
    hParent = WM_HWIN_NULL;                                //本窗体为没人管的窗体
  }
  if (hParent) {
//WM_H2P将句柄hParent换算成内存空间,具体细节请参考《浅析μC/GUI-v3.98之WM_H2P()句柄hWin转内存函数 》
    WM_Obj* pParent = WM_H2P(hParent);
    x0 += pParent->Rect.x0;                                //以父窗体的(x0,y0)左上角坐标为本窗体的(0,0)坐标,进行绝对坐标调整
    y0 += pParent->Rect.y0;
    if (width==0) {
      width = pParent->Rect.x1 - pParent->Rect.x0+1;
    }
    if (height==0) {
      height = pParent->Rect.y1 - pParent->Rect.y0+1;
    }
  }
//GUI_ALLOC_AllocZero申请指定大小的连续空间,返回该空间索引,具体细节请参考《浅析μC/GUI-v3.98之GUI_ALLOC_AllocZero()内存申请转句柄hWin函数 》
  if ((hWin = (WM_HWIN) GUI_ALLOC_AllocZero(NumExtraBytes + sizeof(WM_Obj))) == 0) {
    GUI_DEBUG_ERROROUT("WM_CreateWindow: No memory to create window");
  } else {
    WM__NumWindows++;
    pWin = WM_H2P(hWin);                                   //2007-07-10 gliethttp
    pWin->Rect.x0 = x0;
    pWin->Rect.y0 = y0;
    pWin->Rect.x1 = x0 + width - 1;
    pWin->Rect.y1 = y0 + height - 1;
    pWin->cb = cb;                                         //消息事件响应函数cb
    /* Copy the flags which can simply be accepted */
    pWin->Status |= (Style & (WM_CF_SHOW |                 //Sytle合法性拷贝

                              WM_SF_MEMDEV |
                              WM_CF_MEMDEV_ON_REDRAW |
                              WM_SF_STAYONTOP |
                              WM_CF_DISABLED |
                              WM_SF_CONST_OUTLINE |
                              WM_SF_HASTRANS |
                              WM_CF_ANCHOR_RIGHT |
                              WM_CF_ANCHOR_BOTTOM |
                              WM_CF_ANCHOR_LEFT |
                              WM_CF_ANCHOR_TOP |
                              WM_CF_LATE_CLIP));
    /* Add to linked lists */
    _AddToLinList(hWin);                                   //简单的把本窗体添加到GUI管理控件维护list中
    WM__InsertWindowIntoList(hWin, hParent);               //就像linux下vm_area倒挂的树一样,将本hWin也倒挂到hParent这颗树下
    /* Activate window if WM_CF_ACTIVATE is specified */
    if (Style & WM_CF_ACTIVATE) {
      WM_SelectWindow(hWin);                               //设置该hWin窗体有效
    }
    /* Handle the Style flags, one at a time */
    #if WM_SUPPORT_TRANSPARENCY
      if (Style & WM_SF_HASTRANS) {
        WM__TransWindowCnt++; /* Increment counter for transparency windows */
      }
    #endif
    if (Style & WM_CF_BGND) {
      WM_BringToBottom(hWin);                              //将hWin链接成pParent->hFirstChild第一个孩子
    }
    if (Style & WM_CF_SHOW) {
      pWin->Status |= WM_SF_ISVIS; /* Set Visibility flag */
      WM_InvalidateWindow(hWin);                           //另一篇《浅析μC/GUI-v3.98之WM_InvalidateWindow函数》再详解
    }
    WM__SendMsgNoData(hWin, WM_CREATE);
  }
  WM_UNLOCK();
  return hWin;
}
-------------------------------------------------------------------------------------
2._AddToLinList()函数
gui/wm/WM.c
static void _AddToLinList(WM_HWIN hNew) {
  WM_Obj* pFirst;
  WM_Obj* pNew;
  if (WM__FirstWin) {
    pFirst = WM_H2P(WM__FirstWin);
    pNew = WM_H2P(hNew);
    pNew->hNextLin = pFirst->hNextLin;                     //将hNew插入到链表头,作为pFirst->hNextLin的第一个链表元素
    pFirst->hNextLin = hNew;
  } else {
    WM__FirstWin = hNew;
  }
}
-------------------------------------------------------------------------------------
3.WM__InsertWindowIntoList()函数
gui/wm/WM.c
void WM__InsertWindowIntoList(WM_HWIN hWin, WM_HWIN hParent) {
  int OnTop;
  WM_HWIN hi;
  WM_Obj * pWin;
  WM_Obj * pParent;
  WM_Obj * pi;
  if (hParent) {
    pWin = WM_H2P(hWin);
    pWin->hNext = 0;
    pWin->hParent = hParent;
    pParent = WM_H2P(hParent);
    OnTop = pWin->Status & WM_CF_STAYONTOP;
    hi = pParent->hFirstChild;                             //取出hParent的第一个孩子
    /* Put it at beginning of the list if there is no child */
    if (hi == 0) { /* No child yet ... Makes things easy ! */
      pParent->hFirstChild = hWin;
      return; /* Early out ... We are done */
    }
    /* Put it at beginning of the list if first child is a TOP window and new one is not */
    pi = WM_H2P(hi);
    if (!OnTop) {                                          //hWin窗体非OnTop最顶层显示
      if (pi->Status & WM_SF_STAYONTOP) {                  //hParent的第一个孩子就是OnTop类型,那么直接赋值ok返回
        pWin->hNext = hi;
        pParent->hFirstChild = hWin;
        return; /* Early out ... We are done */
      }
    }
    /* Put it at the end of the list or before the last non "STAY-ON-TOP" child */
    do {
      WM_Obj* pNext;
      WM_HWIN hNext;
      if ((hNext = pi->hNext) == 0) {                      //就没有OnTop类型孩子,那么到达hParent的孩子链表的最后单元
        pi->hNext = hWin; /* Then modify this last element to point to new one and we are done */
        break;
      }
      pNext = WM_H2P(hNext);
      if (!OnTop) {                                        //hWin窗体非OnTop最顶层显示
        if (pNext->Status & WM_SF_STAYONTOP) {             //那么将hWin放在本hParent管理的链表中所有非OnTop类型窗体之后,第一个OnTop类型之前
          pi->hNext = hWin;
          pWin->hNext = hNext;
          break;
        }
      }
      pi = pNext;
    } while (1);
    #if WM_SUPPORT_NOTIFY_VIS_CHANGED
      WM__NotifyVisChanged(hWin, &pWin->Rect);             //如果WM_SUPPORT_NOTIFY_VIS_CHANGED非0,那么即时进行窗体剪切绘制
    #endif
  }
}
-------------------------------------------------------------------------------------
4.WM__NotifyVisChanged()和_NotifyVisChanged()函数
gui/wm/WM__NotifyVisChanged.c
void WM__NotifyVisChanged(WM_HWIN hWin, GUI_RECT * pRect) {
  WM_Obj * pWin;
  WM_HWIN hParent;
  pWin = WM_H2P(hWin);
  hParent = pWin->hParent;                                 //取出本hWin的hParent
  if (hParent) {
    _NotifyVisChanged(hParent, pRect);//绘制hParent下的所有与本hWin剪切的同级孩子,通过递归调用,绘制同级孩子下的孩子
  }
}
static void _NotifyVisChanged(WM_HWIN hWin, GUI_RECT * pRect) {
  WM_Obj* pWin;
//hParent的孩子是这样创建的:将本窗体添加到hParent窗体链表的最前面,控件Z序剪切绘制时也将是最先绘制,被剪切的也最多
  for (hWin = WM_GetFirstChild(hWin); hWin; hWin = pWin->hNext) {
    pWin = WM_H2P(hWin);
    if (pWin->Status & WM_SF_ISVIS) {
//2007-09-10 gliethttp
//μC/GUI-v3.98存在根据窗体创建先后,制作的创建顺序链表,从平面的角度来说,存在平面x,y轴的控件单元平铺关系
//通过_NotifyVisChanged递归调用和本hParent最后创建的控件在孩子链表的第一个的特性,实现了一个hParent窗体内
//控件的三维z序剪切描述,姑且叫它:控件Z序;但缺乏维护窗体之间在三维空间中的z轴层与层之间关系的数据链表结构,
//即常说的“窗口Z序”,加之控件本身也调用WM_CreateWindowAsChild来创建,这样WM_CreateWindowAsChild程序被最大的复用,
//但没有单独的将创建标志为windows窗体的hWin单独拿出来维护一个单独的windows窗体z序链表,所以z序窗口剪切算法在
//μC/GUI-v3.98中排不上用场了,不过通过_NotifyVisChanged函数的递归调用,μC/GUI-v3.98巧妙的实现了一个hParent下所有
//孩子以及孩子的孩子的剪切绘制这样的绘制可以等同“窗口Z序”剪切绘制,姑且叫它:控件Z序,所以我想将创建标志为windows
//窗体的hWin单独拿出来维护一个单独的windows窗体z序链表,μC/GUI-v3.98就可以有表达力更丰富的窗口Z序三维空间描述了,
//不过需要在简洁实用中权衡添加窗口Z序的意义
//因为是递归调用,所以对堆、栈空间是一个严峻的考验,一个hParent下创建的控件,以及控件下的控件个数需要考虑
//不过,默认没有使用该方式
      if (GUI_RectsIntersect(&pWin->Rect, pRect)) {        //通过递归实现Z序窗口剪切绘制
        WM__SendMsgNoData(hWin, WM_NOTIFY_VIS_CHANGED);
        _NotifyVisChanged(hWin, pRect);                    //递归检测本hWin的孩子是否存在与该Rect区域交叠,存在则绘之
      }
    }
  }
}
-------------------------------------------------------------------------------------
5.WM_SelectWindow()函数
gui/wm/WM.c
WM_HWIN WM_SelectWindow(WM_HWIN hWin) {
  WM_HWIN hWinPrev;
  WM_Obj* pObj;
  WM_ASSERT_NOT_IN_PAINT();
  WM_LOCK();
  hWinPrev = GUI_Context.hAWin;
  if (hWin == 0) {
    hWin = WM__FirstWin;
  }
  /* Select new window */
  GUI_Context.hAWin = hWin;                                //当前有效窗体GUI_Context.hAWin
  #if GUI_NUM_LAYERS > 1
  {                                                        //如果支持多个LCD屏幕,那么找到该hWin的所属LCD
    WM_HWIN hTop;
    int LayerIndex;
    hTop = _GetTopLevelWindow(hWin);
    LayerIndex = _DesktopHandle2Index(hTop);
    if (LayerIndex >= 0) {
      GUI_SelectLayer(LayerIndex);
    }
  }
  #endif
  pObj = WM_H2P(hWin);
  LCD_SetClipRectMax();
  GUI_Context.xOff = pObj->Rect.x0;
  GUI_Context.yOff = pObj->Rect.y0;
  WM_UNLOCK();
  return hWinPrev;
}
-------------------------------------------------------------------------------------
5.WM_SelectWindow()函数
gui/wm/WM_BringToBottom.c
void WM_BringToBottom(WM_HWIN hWin) {
  WM_HWIN hParent;
  WM_HWIN hPrev;
  WM_Obj* pWin;
  WM_Obj* pPrev;
  WM_Obj* pParent;
  WM_LOCK();
  if (hWin) {
    pWin = WM_H2P(hWin);
    hPrev = WM__GetPrevSibling(hWin);                      //取得hWin->hParent下hWin的前一个孩子
    if (hPrev) { /* If there is no previous one, there is nothing to do ! */
      hParent = WM_GetParent(hWin);
      /* Invalidate window area */
      if (pWin->Status & WM_SF_ISVIS) {
        WM__InvalidateRectEx(&pWin->Rect, hParent, pWin->hNext);
      }
      pParent = WM_H2P(hParent);
      /* Unlink hWin */
      pPrev = WM_H2P(hPrev);
      pPrev->hNext = pWin->hNext;                          //将hWin摘下来放到pParent->hFirstChild
      /* Link from parent (making it the first child) */
      pWin->hNext = pParent->hFirstChild;
      pParent->hFirstChild = hWin;
    }
  }
  WM_UNLOCK();
}

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