今天讨论关于GUI的另一个话题:如何在两个界面切换中表现出比较炫一点的效果,比如渐变、缩放等等。同样我们还是用组件的方式来做。IGSlider,负责管理两个IControl切换的动态效果,它的使用比较简单:
static void loadMenu(DisplayFavt * pMe,uint16 wParam) ... { TItemData *pData; IControl * p1,*p2; uint16 style; pData=NULL; //加载第一个IControl,即起始界面 if(pMe->pCurrentTabOpt && pMe->pCurrentTabOpt->pMenu) ...{ ICONTROL_SetActive(pMe->pCurrentTabOpt->pMenu,FALSE); p1=pMe->pCurrentTabOpt->pMenu; } //得到第二个IControl,即结束界面 pMe->currentTab=IGTABPANECTL_GetSel(pMe->pApp->pMenuTab); MainItemQueue_FindById(pMe->pApp->pTabList,pMe->currentTab,&pData); if(pData==NULL) return; IGTABPANECTL_GetItemData(pMe->pApp->pMenuTab,pMe->currentTab,(uint32*)&pMe->pCurrentTabOpt); p2=pMe->pCurrentTabOpt->pMenu; //设置切换效果的风格 //style =(wParam==0)?0:((wParam==AVK_LEFT)?SLIDER_STYLE_RTOL:SLIDER_STYLE_LTOR); style=(wParam==0)?0:SLIDER_STYLE_DTOB; if(p1 && p2 && style!=0) ...{ AEERect rec; SET_CTL_RECT(&rec); //两个界面应该同样大小 IGSLIDER_SetRect(pMe->pApp->pSlider,&rec); //将两个界面IControl加入IGSlider if(IGSLIDER_AddControls(pMe->pApp->pSlider,p1,p2)) ...{ //初始化,设置回调、风格、动态效果显示时长 IGSLIDER_Init(pMe->pApp->pSlider,style,3,(PFNNOTIFY)loadMenuDone,(void*)pMe); //启动 IGSLIDER_Start(pMe->pApp->pSlider); return; } } ...{ ICONTROL_SetActive((IControl*)pMe->pCurrentTabOpt->pMenu,TRUE); ICONTROL_Redraw(pMe->pCurrentTabOpt->pMenu); pMe->pApp->state=STATE_COMMAND; }}原理比较简单:1、我们要将两个 IControl绘入两个IBitmap中,然后才能进行各种图像操作(渐变、淡化、缩放等)。2、用一个定时器来控制这个切换时的效果显示。3、需要一个回调函数,在完成切换时需要调一下它,来处理善后事项。先看看这个组件包含的成员,如上所述,除了两个ICotrol和两个IBitmap以外,还要那个回调m_cbDone、风格m_style、时间控制m_delay等等。
struct _IGSlider ... { const AEEVTBL(IGSlider) * pvt; uint32 m_nRefs; IShell *m_pIShell; IDisplay *m_pIDisplay; IModule *m_pIModule; IControl *m_pFirst; IControl *m_pSecond; int m_delay; int m_style; boolean m_isActive; PFNNOTIFY m_cbDone; void *m_pNotifyData; AEERect m_Rect; IBitmap *pFirst; IBitmap *pSecond; int tick; uint8 flag; IBitmap *pTemp;} ;然后需要声明的接口函数包括以下几个:
AEEINTERFACE(IGSlider) ... { DECLARE_IBASE(IGSlider) boolean (*Redraw) (IGSlider * po); void (*SetRect) (IGSlider * po, const AEERect *); boolean (*AddControls) (IGSlider * po, IControl * p1,IControl * p2); boolean (*AddControlsD) (IGSlider * po, IControl * p1,IControl * p2); boolean (*AddControlFrom) (IGSlider * po,IControl * p1); boolean (*AddControlTo) (IGSlider * po,IControl * p2); boolean (*AddControlFromBitmap) (IGSlider * po,IBitmap * p1); boolean (*AddControlToBitmap) (IGSlider * po,IBitmap * p2); IBitmap* (*GetBitmapFirst) (IGSlider * po); IBitmap* (*GetBitmapSecond) (IGSlider * po); boolean (*IsActive) (IGSlider * po); void (*Init) (IGSlider * po, uint16 style,uint32 delay,PFNNOTIFY cbDone,void * pUser); void (*Start) (IGSlider * po); void (*Stop) (IGSlider * po); } ;实现方面主要是这个addControls函数,在加入两个ICotrol同时,将它绘制到IBitmap上去。
static boolean IGSlider_AddControls(IGSlider * pMe,IControl * p1,IControl * p2) ... { AEERect r; if(SUCCESS!=IDISPLAY_SetDestination(pMe->m_pIDisplay,pMe->pFirst)) return FALSE; SETAEERECT(&r,0,0,pMe->m_Rect.dx,pMe->m_Rect.dy); ICONTROL_SetRect(p1,&r); ICONTROL_Redraw(p1); IDISPLAY_Update(pMe->m_pIDisplay); ICONTROL_SetRect(p1,&pMe->m_Rect); if(SUCCESS!=IDISPLAY_SetDestination(pMe->m_pIDisplay,pMe->pSecond)) return FALSE; SETAEERECT(&r,0,0,pMe->m_Rect.dx,pMe->m_Rect.dy); ICONTROL_SetRect(p2,&r); ICONTROL_Redraw(p2); IDISPLAY_Update(pMe->m_pIDisplay); ICONTROL_SetRect(p2,&pMe->m_Rect); IDISPLAY_SetDestination(pMe->m_pIDisplay,NULL); return TRUE;}启动效果切换的工作是根据当前设置的风格调用不同的图像处理函数,还要提供一个停止函数来随时中止效果变化(其实就是Cancel掉定时器罢了)。
static void IGSlider_Start(IGSlider * pMe) ... { pMe->tick = 0; pMe->flag=0; pMe->m_isActive=TRUE; if(pMe->m_style==SLIDER_STYLE_RTOL) drawRTOL(pMe); else if(pMe->m_style==SLIDER_STYLE_LTOR) drawLTOR(pMe); else if(pMe->m_style==SLIDER_STYLE_DARK) drawDARK(pMe); else if(pMe->m_style==SLIDER_STYLE_BRIT) drawBRIT(pMe); else if(pMe->m_style==SLIDER_STYLE_SIZE) drawSize(pMe); else if(pMe->m_style==SLIDER_STYLE_GRID) drawGRID(pMe); else if(pMe->m_style==SLIDER_STYLE_SIZE2) drawSize2(pMe); else if(pMe->m_style==SLIDER_STYLE_LTORD) drawLTORD(pMe); else if(pMe->m_style==SLIDER_STYLE_RTOLD) drawRTOLD(pMe); else if(pMe->m_style==SLIDER_STYLE_BTOT) drawBTOT(pMe); else if(pMe->m_style==SLIDER_STYLE_TTOB) drawTTOB(pMe); else if(pMe->m_style==SLIDER_STYLE_DTOB) drawDTOB(pMe);} static void IGSlider_Stop(IGSlider * pMe) ... { pMe->m_isActive=FALSE; ISHELL_CancelTimer(pMe->m_pIShell,NULL,(void*)pMe);}各种效果的实现并不复杂,去google一下就能得到很多图像处理方法了。下面给出两个典型的处理,一是由暗变亮的实现,即第一个界面由亮变暗而第二个界面由暗变亮。
static void drawDTOB(IGSlider * pMe) ... { ITransform *pTransform; AEEBitmapInfo inf; IBitmap *bmp; AEETransformMatrix matrix; int x,y; pMe->tick++; IBITMAP_SetTransparencyColor(pMe->pFirst,MAKE_RGB(0,0,0)); if(pMe->flag==0) ...{ IBITMAP_GetInfo(pMe->pFirst,&inf,sizeof(AEEBitmapInfo)); for(x=0;x<inf.cx;x++) for(y=0;y<inf.cy;y++) ...{ NativeColor tc; RGBVAL ocolor,ncolor; IBITMAP_GetPixel(pMe->pFirst,x,y,&tc); ocolor=IBITMAP_NativeToRGB(pMe->pFirst,tc); ncolor = __transColor(pMe,ocolor,-50); tc= IBITMAP_RGBToNative(pMe->pFirst,ncolor); IBITMAP_DrawPixel(pMe->pFirst,x,y,tc,AEE_RO_COPY); } IDISPLAY_BitBlt(pMe->m_pIDisplay,pMe->m_Rect.x,pMe->m_Rect.y,pMe->m_Rect.dx,pMe->m_Rect.dy,pMe->pFirst,0,0,AEE_RO_TRANSPARENT); IDISPLAY_Update(pMe->m_pIDisplay); if(pMe->tick<pMe->m_delay) ISHELL_SetTimer(pMe->m_pIShell,5,(PFNNOTIFY)drawDTOB,(void*)pMe); else ...{ pMe->flag=1; pMe->tick=1; } } if(pMe->flag==1) ...{ IBITMAP_GetInfo(pMe->pSecond,&inf,sizeof(AEEBitmapInfo)); if(pMe->pTemp) IBITMAP_Release(pMe->pTemp); IBITMAP_CreateCompatibleBitmap(pMe->pSecond,&pMe->pTemp,inf.cx,inf.cy); for(x=0;x<inf.cx;x++) for(y=0;y<inf.cy;y++) ...{ NativeColor tc; RGBVAL ocolor,ncolor; IBITMAP_GetPixel(pMe->pSecond,x,y,&tc);