浅析μ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(); }
|