ucgui的menu的改进

来源:互联网 发布:excel2003删除重复数据 编辑:程序博客网 时间:2024/06/05 04:06
/*  *********************************************************************************************************  *                                                uC/GUI  *                        Universal graphic software for embedded applications  *  *                       (c) Copyright 2002, Micrium Inc., Weston, FL  *                       (c) Copyright 2002, SEGGER Microcontroller Systeme GmbH  *  *              µC/GUI is protected by international copyright laws. Knowledge of the  *              source code may not be used to write a similar product. This file may  *              only be used in accordance with a license and should not be redistributed  *              in any way. We appreciate your understanding and fairness.  *  ----------------------------------------------------------------------  File        : MENU.c  Purpose     : Implementation of menu widget  ---------------------------END-OF-HEADER------------------------------  */      #include <stdlib.h>   #include <string.h>      #define MENU_C       /* Required to generate intermodule data */      #include "MENU.h"   #include "MENU_Private.h"   #include "GUIDebug.h"   #include "GUI_Protected.h"      #if GUI_WINSUPPORT      /*********************************************************************  *  *       Private config defaults  *  **********************************************************************  */      /* Define default font */   #ifndef MENU_FONT_DEFAULT     #define MENU_FONT_DEFAULT         &GUI_Font13_1   #endif      /* Define default effect */   #ifndef MENU_EFFECT_DEFAULT     #define MENU_EFFECT_DEFAULT       &WIDGET_Effect_3D1L   #endif      /* Define colors, index 0, enabled, not selected */   #ifndef MENU_TEXTCOLOR0_DEFAULT     #define MENU_TEXTCOLOR0_DEFAULT   GUI_BLACK   #endif      #ifndef MENU_BKCOLOR0_DEFAULT     #define MENU_BKCOLOR0_DEFAULT     GUI_LIGHTGRAY   #endif      /* Define colors, index 1, enabled, selected */   #ifndef MENU_TEXTCOLOR1_DEFAULT     #define MENU_TEXTCOLOR1_DEFAULT   GUI_WHITE   #endif      #ifndef MENU_BKCOLOR1_DEFAULT     #define MENU_BKCOLOR1_DEFAULT     0x980000   #endif      /* Define colors, index 2, disabled, not selected */   #ifndef MENU_TEXTCOLOR2_DEFAULT     #define MENU_TEXTCOLOR2_DEFAULT   0x7C7C7C   #endif      #ifndef MENU_BKCOLOR2_DEFAULT     #define MENU_BKCOLOR2_DEFAULT     GUI_LIGHTGRAY   #endif      /* Define colors, index 3, disabled, selected */   #ifndef MENU_TEXTCOLOR3_DEFAULT     #define MENU_TEXTCOLOR3_DEFAULT   GUI_LIGHTGRAY   #endif      #ifndef MENU_BKCOLOR3_DEFAULT     #define MENU_BKCOLOR3_DEFAULT     0x980000   #endif      /* Define colors, index 4, active submenu */   #ifndef MENU_TEXTCOLOR4_DEFAULT     #define MENU_TEXTCOLOR4_DEFAULT   GUI_WHITE   #endif      #ifndef MENU_BKCOLOR4_DEFAULT     #define MENU_BKCOLOR4_DEFAULT     0x7C7C7C   #endif      /* Define borders */   #ifndef MENU_BORDER_LEFT_DEFAULT     #define MENU_BORDER_LEFT_DEFAULT    4   #endif      #ifndef MENU_BORDER_RIGHT_DEFAULT     #define MENU_BORDER_RIGHT_DEFAULT   4   #endif      #ifndef MENU_BORDER_TOP_DEFAULT     #define MENU_BORDER_TOP_DEFAULT     2   #endif      #ifndef MENU_BORDER_BOTTOM_DEFAULT     #define MENU_BORDER_BOTTOM_DEFAULT  2   #endif      /*********************************************************************  *  *       Static data  *  **********************************************************************  */      MENU_PROPS MENU__DefaultProps = {     MENU_TEXTCOLOR0_DEFAULT,     MENU_TEXTCOLOR1_DEFAULT,     MENU_TEXTCOLOR2_DEFAULT,     MENU_TEXTCOLOR3_DEFAULT,     MENU_TEXTCOLOR4_DEFAULT,     MENU_BKCOLOR0_DEFAULT,     MENU_BKCOLOR1_DEFAULT,     MENU_BKCOLOR2_DEFAULT,     MENU_BKCOLOR3_DEFAULT,     MENU_BKCOLOR4_DEFAULT,     MENU_BORDER_LEFT_DEFAULT,     MENU_BORDER_RIGHT_DEFAULT,     MENU_BORDER_TOP_DEFAULT,     MENU_BORDER_BOTTOM_DEFAULT,     MENU_FONT_DEFAULT   };      const WIDGET_EFFECT* MENU__pDefaultEffect = MENU_EFFECT_DEFAULT;      /*********************************************************************  *  *       Macros for internal use  *  **********************************************************************  */      #if GUI_DEBUG_LEVEL >= GUI_DEBUG_LEVEL_CHECK_ALL     #define OBJECT_ID 0x7843   /* Magic nubmer, should be unique if possible */     #define INIT_ID(p)   p->DebugId = OBJECT_ID     #define DEINIT_ID(p) p->DebugId = 0   #else     #define INIT_ID(p)     #define DEINIT_ID(p)   #endif      /*********************************************************************  *  *       Static routines, for higher debug level only  *  **********************************************************************  */   /*********************************************************************  *  *       MENU_h2p  */   #if GUI_DEBUG_LEVEL >= GUI_DEBUG_LEVEL_CHECK_ALL   MENU_Obj* MENU_h2p(MENU_Handle h) {     MENU_Obj* p = (MENU_Obj*)GUI_ALLOC_h2p(h);     if (p) {       if (p->DebugId != OBJECT_ID) {         GUI_DEBUG_ERROROUT("MENU.c: Wrong handle type or Object not init'ed");         return 0;       }     }     return p;   }   #endif      /*********************************************************************  *  *       Static routines  *  **********************************************************************  */   /*********************************************************************  *  *       _IsTopLevelMenu  */   static char _IsTopLevelMenu(MENU_Handle hObj, const MENU_Obj* pObj) {     if (MENU__SendMenuMessage(hObj, pObj->hOwner, MENU_IS_MENU, 0) == 0) {       return 1;     }     return 0;   }      /*********************************************************************  *  *       _GetTopLevelMenu  *  * Purpose:  *   The function returns the top level menu of the given menu.  *  * Parameter:  *   hObj, pObj                  : Obvious  *   phObjTopLevel, ppObjTopLevel: Pointer to handle and object pointer for the result  *   pSubSel                     : Pointer to an integer variable for returning the current   *                                 selection of the last open sub menu.  */   static void _GetTopLevelMenu(MENU_Handle hObj, MENU_Obj * pObj, MENU_Handle * phObjTopLevel, MENU_Obj ** ppObjTopLevel, int * pSubSel) {     MENU_Handle hObjTopLevel;     MENU_Obj * pObjTopLevel;     pObjTopLevel = pObj;     if (_IsTopLevelMenu(hObj, pObj)) {       hObjTopLevel = hObj;       pObjTopLevel = pObj;     } else {       do {         hObjTopLevel = pObjTopLevel->hOwner;         pObjTopLevel = (MENU_Obj *)GUI_ALLOC_h2p(hObjTopLevel);         if (_IsTopLevelMenu(hObjTopLevel, pObjTopLevel)) {           break;         } else {           if (pSubSel) {             *pSubSel = pObjTopLevel->Sel;           }         }       } while (1);     }     *phObjTopLevel = hObjTopLevel;     *ppObjTopLevel = pObjTopLevel;   }         /*********************************************************************  *  *       _HasEffect  */   static int _HasEffect(MENU_Handle hObj, MENU_Obj* pObj) {     if (!(pObj->Flags & MENU_SF_POPUP)) {       if (_IsTopLevelMenu(hObj, pObj)) {         return 0;       }     }     return 1;   }      /*********************************************************************  *  *       _GetEffectSize  */   static int _GetEffectSize(MENU_Handle hObj, MENU_Obj* pObj) {     int r = 0;     if (_HasEffect(hObj, pObj)) {        r = pObj->Widget.pEffect->EffectSize;     }     return r;   }      /*********************************************************************  *  *       _CalcTextWidth  */   static int _CalcTextWidth(MENU_Obj* pObj, const char GUI_UNI_PTR* sText) {     int TextWidth = 0;     if (sText) {       const GUI_FONT GUI_UNI_PTR* pOldFont;       pOldFont  = GUI_SetFont(pObj->Props.pFont);       TextWidth = GUI_GetStringDistX(sText);       GUI_SetFont(pOldFont);     }     return TextWidth;   }      /*********************************************************************  *  *       _GetItemWidth  */   static int _GetItemWidth(MENU_Handle hObj, MENU_Obj* pObj, unsigned Index) {     int ItemWidth;     if (pObj->Width && (pObj->Flags & MENU_SF_VERTICAL)) {       ItemWidth = pObj->Width - (_GetEffectSize(hObj, pObj) << 1);     } else {       MENU_ITEM* pItem = (MENU_ITEM*)GUI_ARRAY_GetpItem(&pObj->ItemArray, Index);       if ((pObj->Flags & MENU_SF_VERTICAL) || !(pItem->Flags & MENU_IF_SEPARATOR)) {         ItemWidth = pItem->TextWidth;       } else {         ItemWidth = 3;      }       ItemWidth += pObj->Props.aBorder[MENU_BI_LEFT] + pObj->Props.aBorder[MENU_BI_RIGHT];     }     return ItemWidth;   }      /*********************************************************************  *  *       _GetItemHeight  */   static int _GetItemHeight(MENU_Handle hObj, MENU_Obj* pObj, unsigned Index) {     int ItemHeight;     if (pObj->Height && !(pObj->Flags & MENU_SF_VERTICAL)) {       ItemHeight = pObj->Height - (_GetEffectSize(hObj, pObj) << 1);     } else {       ItemHeight = GUI_GetYDistOfFont(pObj->Props.pFont);       if (pObj->Flags & MENU_SF_VERTICAL) {         MENU_ITEM* pItem = (MENU_ITEM*)GUI_ARRAY_GetpItem(&pObj->ItemArray, Index);         if (pItem->Flags & MENU_IF_SEPARATOR) {           ItemHeight = 3;         }       }       ItemHeight += pObj->Props.aBorder[MENU_BI_TOP] + pObj->Props.aBorder[MENU_BI_BOTTOM];     }     return ItemHeight;   }      /*********************************************************************  *  *       _CalcMenuSizeX  */   static int _CalcMenuSizeX(MENU_Handle hObj, MENU_Obj* pObj) {     unsigned i, NumItems = MENU__GetNumItems(pObj);     int xSize = 0;     if (pObj->Flags & MENU_SF_VERTICAL) {       int ItemWidth;       for (i = 0; i < NumItems; i++) {         ItemWidth = _GetItemWidth(hObj, pObj, i);         if (ItemWidth > xSize) {           xSize = ItemWidth;         }       }     } else {       for (i = 0; i < NumItems; i++) {         xSize += _GetItemWidth(hObj, pObj, i);       }     }     xSize += (_GetEffectSize(hObj, pObj) << 1);     return xSize;   }      /*********************************************************************  *  *       _CalcMenuSizeY  */   static int _CalcMenuSizeY(MENU_Handle hObj, MENU_Obj* pObj) {     unsigned i, NumItems = MENU__GetNumItems(pObj);     int ySize = 0;     if (pObj->Flags & MENU_SF_VERTICAL) {       for (i = 0; i < NumItems; i++) {         ySize += _GetItemHeight(hObj, pObj, i);       }     } else {       int ItemHeight;       for (i = 0; i < NumItems; i++) {         ItemHeight = _GetItemHeight(hObj, pObj, i);         if (ItemHeight > ySize) {           ySize = ItemHeight;         }       }     }     ySize += (_GetEffectSize(hObj, pObj) << 1);     return ySize;   }      /*********************************************************************  *  *       _CalcWindowSizeX  */   static int _CalcWindowSizeX(MENU_Handle hObj, MENU_Obj* pObj) {     int xSize = pObj->Width;     if (xSize == 0) {       xSize = _CalcMenuSizeX(hObj, pObj);     }     return xSize;   }      /*********************************************************************  *  *       _CalcWindowSizeY  */   static int _CalcWindowSizeY(MENU_Handle hObj, MENU_Obj* pObj) {     int ySize = pObj->Height;     if (ySize == 0) {       ySize = _CalcMenuSizeY(hObj, pObj);     }     return ySize;   }      /*********************************************************************  *  *       _GetItemFromPos  *  * Return value:  *   Zero based index of item at given position or -1.  *  * NOTE:  *   This function has to ensure that index is always less than the  *   maximum number of items.  */   static int _GetItemFromPos(MENU_Handle hObj, MENU_Obj* pObj, int x, int y) {     int xSize, ySize, EffectSize, r = -1;     ySize = _CalcMenuSizeY(hObj, pObj);     if ((pObj->Height) && (pObj->Height < ySize)) {       ySize = pObj->Height;     }     xSize = _CalcMenuSizeX(hObj, pObj);     if ((pObj->Width) && (pObj->Width < xSize)) {       xSize = pObj->Width;     }     EffectSize = _GetEffectSize(hObj, pObj);     x     -= EffectSize;     y     -= EffectSize;     xSize -= (EffectSize << 1);     ySize -= (EffectSize << 1);     if ((x >= 0) && (y >= 0) && (x < xSize) && (y < ySize)) {       unsigned i, NumItems = MENU__GetNumItems(pObj);       if (pObj->Flags & MENU_SF_VERTICAL) {         int yPos = 0;         for (i = 0; i < NumItems; i++) {           yPos += _GetItemHeight(hObj, pObj, i);           if (y < yPos) {             r = i;             break;           }         }       } else {         int xPos = 0;         for (i = 0; i < NumItems; i++) {           xPos += _GetItemWidth(hObj, pObj, i);           if (x < xPos) {             r = i;             break;           }         }       }     }     return r;   }      /*********************************************************************  *  *       _GetItemPos  */   static void _GetItemPos(MENU_Handle hObj, MENU_Obj* pObj, unsigned Index, int* px, int* py) {     int i, EffectSize;     EffectSize = _GetEffectSize(hObj, pObj);     if (pObj->Flags & MENU_SF_VERTICAL) {       int yPos = 0;       for (i = 0; i < (int)Index; i++) {         yPos += _GetItemHeight(hObj, pObj, i);       }       *px = EffectSize;       *py = EffectSize + yPos;     } else {       int xPos = 0;       for (i = 0; i < (int)Index; i++) {         xPos += _GetItemWidth(hObj, pObj, i);       }       *px = EffectSize + xPos;       *py = EffectSize;     }   }      /*********************************************************************  *  *       _SetCapture  */   static void _SetCapture(MENU_Handle hObj, const MENU_Obj* pObj) {     if (pObj->IsSubmenuActive == 0) {       if (WM_HasCaptured(hObj) == 0) {         WM_SetCapture(hObj, 0);       }     }   }      /*********************************************************************  *  *       _ReleaseCapture  */   static void _ReleaseCapture(MENU_Handle hObj, const MENU_Obj* pObj) {     if (WM_HasCaptured(hObj)) {       if (_IsTopLevelMenu(hObj, pObj) && !(pObj->Flags & MENU_SF_POPUP)) {         WM_ReleaseCapture();       }     }   }      /*********************************************************************  *  *       _CloseSubmenu  */   static void _CloseSubmenu(MENU_Handle hObj, MENU_Obj* pObj) {     if (pObj->Flags & MENU_SF_ACTIVE) {       if (pObj->IsSubmenuActive) {         MENU_ITEM* pItem = (MENU_ITEM*)GUI_ARRAY_GetpItem(&pObj->ItemArray, pObj->Sel);         /* Inform submenu about its deactivation and detach it */         MENU__SendMenuMessage(hObj, pItem->hSubmenu, MENU_ON_CLOSE, 0);         WM_DetachWindow(pItem->hSubmenu);         pObj->IsSubmenuActive = 0;         /*         * Keep capture in menu widget. The capture may only released         * by clicking outside the menu or when mouse moved out.         * And it may only released from a top level menu.         */         _SetCapture(hObj, pObj);         /* Invalidate menu item. This is needed because the appearance may have changed */         MENU__InvalidateItem(hObj, pObj, pObj->Sel);       }     }   }      /*********************************************************************  *  *       _OpenSubmenu  */   static void _OpenSubmenu(MENU_Handle hObj, MENU_Obj* pObj, unsigned Index) {     if (pObj->Flags & MENU_SF_ACTIVE) {       MENU_ITEM* pItem;       char PrevActiveSubmenu;       PrevActiveSubmenu = pObj->IsSubmenuActive;       /* Close previous submenu (if needed) */       _CloseSubmenu(hObj, pObj);       pItem = (MENU_ITEM*)GUI_ARRAY_GetpItem(&pObj->ItemArray, Index);       if (pItem->hSubmenu) {         if ((pItem->Flags & MENU_IF_DISABLED) == 0) {           int x, y, EffectSize;           /* Calculate position of submenu */           EffectSize = _GetEffectSize(hObj, pObj);           _GetItemPos(hObj, pObj, Index, &x, &y);           if (pObj->Flags & MENU_SF_VERTICAL) {             x += _CalcMenuSizeX(hObj, pObj) - (_GetEffectSize(hObj, pObj) << 1);             y -= EffectSize;           } else {             y += _CalcMenuSizeY(hObj, pObj) - (_GetEffectSize(hObj, pObj) << 1);             x -= EffectSize;  //  x=0;        }           x += WM_GetWindowOrgX(hObj);           y += WM_GetWindowOrgY(hObj);           /*           * Notify owner window when for the first time open a menu (when no           * other submenu was open), so it can initialize the menu items.           */           if (PrevActiveSubmenu == 0) {             if (_IsTopLevelMenu(hObj, pObj)) {               MENU__SendMenuMessage(hObj, pObj->hOwner, MENU_ON_INITMENU, 0);             }           }           /* Notify owner window when a submenu opens, so it can initialize the menu items. */           MENU__SendMenuMessage(hObj, pObj->hOwner, MENU_ON_INITSUBMENU, pItem->Id);           /* Set active menu as owner of submenu. */           MENU_SetOwner(pItem->hSubmenu, hObj);           /* Attach submenu and inform it about its activation. */           WM_AttachWindowAt(pItem->hSubmenu, WM_HBKWIN, x, y);           MENU__SendMenuMessage(hObj, pItem->hSubmenu, MENU_ON_OPEN, 0);           pObj->IsSubmenuActive = 1;           /* Invalidate menu item. This is needed because the appearance may have changed. */           MENU__InvalidateItem(hObj, pObj, Index);         }       }     }   }      /*********************************************************************  *  *       _ClosePopup  */   static void _ClosePopup(MENU_Handle hObj, MENU_Obj* pObj) {     if (pObj->Flags & MENU_SF_POPUP) {       pObj->Flags &= ~(MENU_SF_POPUP);       WM_DetachWindow(hObj);       WM_ReleaseCapture();     }   }      /*********************************************************************  *  *       _SetSelection  */   static void _SetSelection(MENU_Handle hObj, MENU_Obj* pObj, int Index) {     if (Index != pObj->Sel) {       MENU__InvalidateItem(hObj, pObj, pObj->Sel); /* Invalidate previous selection */       MENU__InvalidateItem(hObj, pObj, Index);     /* Invalidate new selection */       pObj->Sel = Index;     }   }  /////////liu//////////////////////////////////////////////////////////////////////////////////////***********************************************************************       MENU__GetpString**  Returns:*    Pointer to the specified item*/const char* MENU__GetpString(const MENU_Obj* pObj, int Index) {  const char* s = NULL;  MENU_ITEM* pItem = (MENU_ITEM*)GUI_ARRAY_GetpItem(&pObj->ItemArray, Index);  if (pItem) {    s = pItem->acText;  }  return s;}/***********************************************************************       MENU_OwnerDraw*/int MENU_OwnerDraw(const WIDGET_ITEM_DRAW_INFO* pDrawItemInfo) {      MENU_Obj* pObj;      MENU_ITEM* pItem;      WM_HMEM hItem;      GUI_RECT r;      int FontDistY;      int ItemIndex = pDrawItemInfo->ItemIndex;      const char* s;      int ColorIndex;      char IsDisabled;      char IsSelected;      pObj = MENU_H2P(pDrawItemInfo->hWin);      hItem = GUI_ARRAY_GethItem(&pObj->ItemArray, ItemIndex);      pItem = (MENU_ITEM *)GUI_ALLOC_h2p(hItem);      WM_GetInsideRect(&r);      FontDistY = GUI_GetFontDistY();//      /* Calculate color index *///      IsDisabled = (pItem->Status & MENU_ITEM_DISABLED) ? 1 : 0;//      IsSelected = (pItem->Status & MENU_ITEM_SELECTED) ? 1 : 0;//      if (pObj->Flags & MENU_SF_MULTISEL) {//        if (IsDisabled) {//          ColorIndex = 3;//        } else {//          ColorIndex = (IsSelected) ? 2 : 0;//        }//      } else {//        if (IsDisabled) {//          ColorIndex = 3;//        } else {//          if (ItemIndex == pObj->Sel) {//            ColorIndex = (pObj->Widget.State & WIDGET_STATE_FOCUS) ? 2 : 1;//          } else {//            ColorIndex = 0;//          }//        }//      }      /* Display item *///      LCD_SetBkColor(pObj->Props.aBackColor[ColorIndex]);//      LCD_SetColor  (pObj->Props.aTextColor[ColorIndex]);      s = MENU__GetpString(pObj, ItemIndex);      GUI_SetTextMode(GUI_TM_TRANS);      GUI_Clear();      GUI_DispStringAt(s, pDrawItemInfo->x0 + 1, pDrawItemInfo->y0);//      /* Display focus rectangle *///      if ((pObj->Flags & MENU_SF_MULTISEL) && (ItemIndex == pObj->Sel)) {//        GUI_RECT rFocus;//        rFocus.x0 = pDrawItemInfo->x0;//        rFocus.y0 = pDrawItemInfo->y0;//        rFocus.x1 = r.x1;//        rFocus.y1 = pDrawItemInfo->y0 + FontDistY - 1;//        LCD_SetColor(GUI_WHITE - pObj->Props.aBackColor[ColorIndex]);//        GUI_DrawFocusRect(&rFocus, 0);////}  return 0;}/***********************************************************************       MENU__InvalidateInsideArea*/void MENU__InvalidateInsideArea(MENU_Handle hObj) {  GUI_RECT Rect;  WM_GetInsideRectExScrollbar(hObj, &Rect);  WM_InvalidateRect(hObj, &Rect);}/***********************************************************************       _GetItemSizeX*/static int _GetItemSizeX(MENU_Handle hObj, const MENU_Obj* pObj, unsigned Index) {  MENU_ITEM* pItem;  int xSize = 0;  pItem = (MENU_ITEM*)GUI_ARRAY_GetpItem(&pObj->ItemArray, Index);  if (pItem) {//    xSize = pItem->xSize;  }  if (xSize == 0) {    const GUI_FONT GUI_UNI_PTR* pOldFont;    pOldFont = GUI_SetFont(pObj->Props.pFont);//    xSize    = _CallOwnerDraw(hObj, pObj, WIDGET_ITEM_GET_XSIZE, Index);    GUI_SetFont(pOldFont);  }  if (pItem) {//    pItem->xSize = xSize;  }  return xSize;}///*********************************************************************//*//*       MENU__SetScrollbarWidth//*/void MENU__SetScrollbarWidth(MENU_Handle hObj, const MENU_Obj* pObj) {  WM_HWIN hBarH, hBarV;  int Width;  Width = pObj->ScrollbarWidth;  if (Width == 0) {    Width = SCROLLBAR_GetDefaultWidth();  }  hBarH = WM_GetDialogItem(hObj, GUI_ID_HSCROLL);  hBarV = WM_GetDialogItem(hObj, GUI_ID_VSCROLL);  SCROLLBAR_SetWidth(hBarH, Width);  SCROLLBAR_SetWidth(hBarV, Width);}/***********************************************************************       _CalcScrollParas*/static int _CalcScrollParas(MENU_Handle hObj) {  GUI_RECT Rect;  MENU_Obj* pObj = MENU_H2P(hObj);  /* Calc vertical scroll parameters */  pObj->ScrollStateV.NumItems = MENU__GetNumItems(pObj);  pObj->ScrollStateV.PageSize = _GetNumVisItems(pObj, hObj);  /* Calc horizontal scroll parameters */  WM_GetInsideRectExScrollbar(hObj, &Rect);  pObj->ScrollStateH.NumItems = _GetContentsSizeX(hObj);  pObj->ScrollStateH.PageSize = Rect.x1 - Rect.x0 + 1;  return _UpdateScrollPos(hObj, pObj);}/***********************************************************************       _ManageAutoScroll*/static void _ManageAutoScroll(MENU_Handle hObj) {  char IsRequired;  MENU_Obj* pObj = MENU_H2P(hObj);  if (pObj->Flags & MENU_SF_AUTOSCROLLBAR_V) {    IsRequired = (_GetNumVisItems(pObj, hObj) < MENU__GetNumItems(pObj));    WM_SetScrollbarV(hObj, IsRequired);  }  if (pObj->Flags & MENU_SF_AUTOSCROLLBAR_H) {    GUI_RECT Rect;    int xSize, xSizeContents;    xSizeContents = _GetContentsSizeX(hObj);    WM_GetInsideRectExScrollbar(hObj, &Rect);    xSize = Rect.x1 - Rect.x0 + 1;    IsRequired = (xSizeContents > xSize);    WM_SetScrollbarH(hObj, IsRequired);  }  if (pObj->ScrollbarWidth) {    MENU__SetScrollbarWidth(hObj, pObj);  }}/***********************************************************************       MENU_UpdateScrollers*/int MENU_UpdateScrollers(MENU_Handle hObj) {  _ManageAutoScroll(hObj);  return _CalcScrollParas(hObj);}/***********************************************************************       _CallOwnerDraw*/static int _CallOwnerDraw(MENU_Handle hObj, const MENU_Obj* pObj, int Cmd, int ItemIndex) {  WIDGET_ITEM_DRAW_INFO ItemInfo;  int r;  ItemInfo.Cmd       = Cmd;  ItemInfo.hWin      = hObj;  ItemInfo.ItemIndex = ItemIndex;//  if (pObj->pfDrawItem) {//    r = pObj->pfDrawItem(&ItemInfo);//  } else {//    r = MENU_OwnerDraw(&ItemInfo);//  }  return r;}/***********************************************************************       _GetItemSizeY*/static int _GetItemSizeY(MENU_Handle hObj, const MENU_Obj* pObj, unsigned Index) {  MENU_ITEM* pItem;  int ySize = 0;  pItem = (MENU_ITEM*)GUI_ARRAY_GetpItem(&pObj->ItemArray, Index);  if (pItem) {//    ySize = pItem->ySize;  }  if (ySize == 0) {    const GUI_FONT GUI_UNI_PTR* pOldFont;    pOldFont = GUI_SetFont(pObj->Props.pFont);//    ySize    = _CallOwnerDraw(hObj, pObj, WIDGET_ITEM_GET_YSIZE, Index);ySize = _GetItemHeight(hObj, pObj, Index);//liu add    GUI_SetFont(pOldFont);  }  if (pItem) {//    pItem->ySize = ySize;  }  return ySize;}/***********************************************************************       _GetYSize*/static int _GetYSize(MENU_Handle hObj) {  GUI_RECT Rect;  WM_GetInsideRectExScrollbar(hObj, &Rect);  return (Rect.y1 - Rect.y0 + 1);}/***********************************************************************       _GetItemPosY*/static int _GetItemPosY(MENU_Handle hObj, const MENU_Obj* pObj, unsigned Index) {  if (Index < MENU__GetNumItems(pObj)) {    if ((int)Index >= pObj->ScrollStateV.v) {      unsigned i;      int PosY = 0;      for (i = pObj->ScrollStateV.v; i < Index; i++) {        PosY += _GetItemSizeY(hObj, pObj, i);      }      return PosY;    }  }  return -1;}/***********************************************************************       _IsPartiallyVis*/static int _IsPartiallyVis(MENU_Handle hObj, const MENU_Obj* pObj) {  int Index;  Index = pObj->Sel;  if (Index < (int)MENU__GetNumItems(pObj)) {    if (Index >= pObj->ScrollStateV.v) {      int y;      y  = _GetItemPosY (hObj, pObj, Index);      y += _GetItemSizeY(hObj, pObj, Index);      if (y > _GetYSize(hObj)) {        return 1;      }    }  }  return 0;}/***********************************************************************       _UpdateScrollPos** Purpose:*   Checks whether if we must scroll up or scroll down to ensure*   that selection is in the visible area. This function also*   makes sure that scroll positions are in valid ranges.** Return value:*   Difference between old and new vertical scroll pos.*/static int _UpdateScrollPos(MENU_Handle hObj, MENU_Obj* pObj) {  int PrevScrollStateV;  PrevScrollStateV = pObj->ScrollStateV.v;  if (pObj->Sel >= 0) {    /* Check upper limit */    if (_IsPartiallyVis(hObj, pObj)) {      pObj->ScrollStateV.v = pObj->Sel - (pObj->ScrollStateV.PageSize - 1);    }    /* Check lower limit */    if (pObj->Sel < pObj->ScrollStateV.v) {      pObj->ScrollStateV.v = pObj->Sel;    }  }  WM_CheckScrollBounds(&pObj->ScrollStateV);  WM_CheckScrollBounds(&pObj->ScrollStateH);  WIDGET__SetScrollState(hObj, &pObj->ScrollStateV, &pObj->ScrollStateH);  return pObj->ScrollStateV.v - PrevScrollStateV;} /********************************************************************add by liuxizhen*//***********************************************************************       MENU__InvalidateItemSize*/void MENU__InvalidateItemSize(const MENU_Obj* pObj, unsigned Index) {  MENU_ITEM* pItem;  pItem = (MENU_ITEM*)GUI_ARRAY_GetpItem(&pObj->ItemArray, Index);  if (pItem) {//    pItem->xSize = 0;//    pItem->ySize = 0;  }}/***********************************************************************       _GetNumVisItems**  Returns:*   Number of fully or partially visible items*/static unsigned _GetNumVisItems(const MENU_Obj* pObj, MENU_Handle hObj) {  int NumItems, r = 1;  NumItems = MENU__GetNumItems(pObj);  if (NumItems > 1) {    int i, ySize, DistY = 0;    ySize = _GetYSize(hObj);    for (i = NumItems - 1; i >= 0; i--) {      DistY += _GetItemSizeY(hObj, pObj, i);      if (DistY > ySize) {        break;      }    }    r = NumItems - i - 1;    if (r < 1) {      return 1;    }  }  return r;}/***********************************************************************       _GetContentsSizeX*/static int _GetContentsSizeX(MENU_Handle hObj) {  MENU_Obj* pObj;  int i, NumItems, SizeX;  int Result = 0;  pObj = MENU_H2P(hObj);  NumItems = MENU__GetNumItems(pObj);  for (i = 0; i < NumItems; i++) {    SizeX = _GetItemSizeX(hObj, pObj, i);    if (Result < SizeX) {      Result = SizeX;    }  }  return Result;}static void MenuBox_SetSel(MENU_Handle hObj, int NewSel){//_SetSelection(hObj,pObj,Index);if (hObj) {    MENU_Obj* pObj;    int MaxSel;    WM_LOCK();    pObj = MENU_H2P(hObj);    MaxSel = MENU__GetNumItems(pObj);    MaxSel = MaxSel ? MaxSel - 1 : 0;    if (NewSel > MaxSel) {      NewSel = MaxSel;    }    if (NewSel < 0) {      NewSel = -1;    } else {      WM_HMEM hItem = GUI_ARRAY_GethItem(&pObj->ItemArray, NewSel);      if (hItem) {        MENU_ITEM* pItem = (MENU_ITEM*)GUI_ALLOC_h2p(hItem);//        if (pItem->Status & MENU_ITEM_DISABLED) {//          NewSel = -1;//        }      }    }    if (NewSel != pObj->Sel) {      int OldSel;      OldSel    = pObj->Sel;      pObj->Sel = NewSel;      if (_UpdateScrollPos(hObj, pObj)) {        MENU__InvalidateInsideArea(hObj);      } else {        MENU__InvalidateItem(hObj, pObj, OldSel);        MENU__InvalidateItem(hObj, pObj, NewSel);      } //     _NotifyOwner(hObj, WM_NOTIFICATION_SEL_CHANGED);    }    WM_UNLOCK();  }}   /*********************************************************************  *  *       _SelectItem  */   static void _SelectItem(MENU_Handle hObj, MENU_Obj* pObj, unsigned Index) {     if (pObj->Sel != (int)Index) {       _SetCapture(hObj, pObj);       _OpenSubmenu(hObj, pObj, Index);       _SetSelection(hObj, pObj, Index);     }   }      /*********************************************************************  *  *       _DeselectItem  */   static void _DeselectItem(MENU_Handle hObj, MENU_Obj* pObj) {     if (pObj->IsSubmenuActive == 0) {       _SetSelection(hObj, pObj, -1);       _ReleaseCapture(hObj, pObj);     }   }      /*********************************************************************  *  *       _ActivateItem  */   static void _ActivateItem(MENU_Handle hObj, MENU_Obj* pObj, unsigned Index) {     MENU_ITEM* pItem;     pItem = (MENU_ITEM*)GUI_ARRAY_GetpItem(&pObj->ItemArray, Index);     if (pItem->hSubmenu == 0) {       if ((pItem->Flags & (MENU_IF_DISABLED | MENU_IF_SEPARATOR)) == 0) {         _ClosePopup(hObj, pObj);         /* Send item select message to owner. */         MENU__SendMenuMessage(hObj, pObj->hOwner, MENU_ON_ITEMSELECT, pItem->Id);       }     }   }      /*********************************************************************  *  *       _ActivateMenu  */   static void _ActivateMenu(MENU_Handle hObj, MENU_Obj* pObj, unsigned Index) {     if ((pObj->Flags & MENU_SF_OPEN_ON_POINTEROVER) == 0) {       MENU_ITEM* pItem;       pItem = (MENU_ITEM*)GUI_ARRAY_GetpItem(&pObj->ItemArray, Index);       if (pItem->hSubmenu) {         if ((pItem->Flags & MENU_IF_DISABLED) == 0) {           if ((pObj->Flags & MENU_SF_ACTIVE) == 0) {             pObj->Flags |= MENU_SF_ACTIVE;             _OpenSubmenu(hObj, pObj, Index);             _SetSelection(hObj, pObj, Index);           } else if (pObj->Flags & MENU_SF_CLOSE_ON_SECOND_CLICK) {             if ((int)Index == pObj->Sel) {               _CloseSubmenu(hObj, pObj);               pObj->Flags &= ~MENU_SF_ACTIVE;             }           }         }       }     }   }      /*********************************************************************  *  *       _DeactivateMenu  */   static void _DeactivateMenu(MENU_Handle hObj, MENU_Obj* pObj) {     _CloseSubmenu(hObj, pObj);     if ((pObj->Flags & MENU_SF_OPEN_ON_POINTEROVER) == 0) {       pObj->Flags &= ~MENU_SF_ACTIVE;     }   }      /*******************************************************************  *  *       _ForwardMouseOverMsg  */   static int _ForwardMouseOverMsg(MENU_Handle hObj, MENU_Obj* pObj, int x, int y) {   #if (GUI_SUPPORT_MOUSE)     if ((pObj->IsSubmenuActive == 0) && !(pObj->Flags & MENU_SF_POPUP)) {       if (_IsTopLevelMenu(hObj, pObj)) {         WM_HWIN hBelow;         x += WM_GetWindowOrgX(hObj);         y += WM_GetWindowOrgY(hObj);         hBelow = WM_Screen2hWin(x, y);         if (hBelow && (hBelow != hObj)) {           WM_MESSAGE Msg;           GUI_PID_STATE State;           x -= WM_GetWindowOrgX(hBelow);           y -= WM_GetWindowOrgY(hBelow);           State.Pressed = 0;           State.x = x;           State.y = y;           Msg.Data.p = &State;           Msg.MsgId = WM_MOUSEOVER;           WM__SendMessage(hBelow, &Msg);           return 1;         }       }     }   #endif     return 0;   }      /*********************************************************************  *  *       _HandlePID  *  * Return values:  *   1 = We need to forward PID message to owner.  *   0 = We do not need to inform owner.  */   static char _HandlePID(MENU_Handle hObj, MENU_Obj* pObj, int x, int y, int Pressed) {     GUI_PID_STATE PrevState;     char XYInWidget = 0;     WM_PID__GetPrevState(&PrevState);     /*     * Check if coordinates are inside the widget.     */     if ((x >= 0) && (y >= 0)) {       GUI_RECT r;       WM__GetClientRectWin(&pObj->Widget.Win, &r);       if ((x <= r.x1) && (y <= r.y1)) {         XYInWidget = 1;       }     }        if (XYInWidget) {       int ItemIndex;       ItemIndex = _GetItemFromPos(hObj, pObj, x, y);       /*        * Handle PID when coordinates are inside the widget.       */       if (ItemIndex >= 0) {         /*          * Coordinates are inside the menu.         */         if (Pressed == 1) {           if (PrevState.Pressed == 0) {  /* Clicked */             _ActivateMenu(hObj, pObj, ItemIndex);           }           _SelectItem(hObj, pObj, ItemIndex);         } else if ((Pressed == 0) && (PrevState.Pressed == 1)) {  /* Released */           _ActivateItem(hObj, pObj, ItemIndex);         } else if (Pressed < 0) {  /* Mouse moved */           if (_ForwardMouseOverMsg(hObj, pObj, x, y) == 0) {             _SelectItem(hObj, pObj, ItemIndex);           } else {             _DeselectItem(hObj, pObj);           }         }       } else {         /*          * Coordinates are outside the menu but inside the widget.         */         if (Pressed == 1) {           if (PrevState.Pressed == 0) {  /* Clicked */             /*              * User has clicked outside the menu. Close the active submenu.             * The widget itself must be closed (if needed) by the owner.             */             _DeactivateMenu(hObj, pObj);           }           _DeselectItem(hObj, pObj);         } else if (Pressed < 0) {  /* Moved out or mouse moved */           _DeselectItem(hObj, pObj);         }       }       return 0;     } else {       /*        * Handle PID when coordinates are outside the widget.       */       if ((Pressed == 1) && (PrevState.Pressed == 0)) {         /*          * User has clicked outside the menu. Close the active submenu.         * The widget itself must be closed (if needed) by the owner.         */         _DeactivateMenu(hObj, pObj);         _ClosePopup(hObj, pObj);       }       _DeselectItem(hObj, pObj);       _ForwardMouseOverMsg(hObj, pObj, x, y);     }     return 1;   /* Coordinates are not in widget, we need to forward PID message to owner */   }      /*********************************************************************  *  *       _ForwardPIDMsgToOwner  */   static void _ForwardPIDMsgToOwner(MENU_Handle hObj, MENU_Obj* pObj, WM_MESSAGE* pMsg) {     if (_IsTopLevelMenu(hObj, pObj) == 0) {       WM_HWIN hOwner;       hOwner = pObj->hOwner ? pObj->hOwner : WM_GetParent(hObj);       if (hOwner) {         if (pMsg->Data.p) {           GUI_PID_STATE* pState;           pState = (GUI_PID_STATE*)pMsg->Data.p;           pState->x += WM_GetWindowOrgX(hObj) - WM_GetWindowOrgX(hOwner);           pState->y += WM_GetWindowOrgY(hObj) - WM_GetWindowOrgY(hOwner);         }         WM__SendMessage(hOwner, pMsg);       }     }   }      /*********************************************************************  *  *       Static routines, callback  *  **********************************************************************  */   /*********************************************************************  *  *       _OnMenu  */   static void _OnMenu(MENU_Handle hObj, MENU_Obj* pObj, WM_MESSAGE* pMsg) {     const MENU_MSG_DATA* pData = (const MENU_MSG_DATA*)pMsg->Data.p;     if (pData) {       switch (pData->MsgType) {       case MENU_ON_ITEMSELECT:         _DeactivateMenu(hObj, pObj);         _DeselectItem(hObj, pObj);         _ClosePopup(hObj, pObj);         /* No break here. We need to forward message to owner. */       case MENU_ON_INITMENU:       case MENU_ON_INITSUBMENU:         /* Forward message to owner. */         {           WM_HWIN hOwner;           hOwner = pObj->hOwner ? pObj->hOwner : WM_GetParent(hObj);           if (hOwner) {             pMsg->hWinSrc = hObj;             WM__SendMessage(hOwner, pMsg);           }         }         break;       case MENU_ON_OPEN:         pObj->Sel = -1;         pObj->IsSubmenuActive = 0;         pObj->Flags |= MENU_SF_ACTIVE | MENU_SF_OPEN_ON_POINTEROVER;         _SetCapture(hObj, pObj);         MENU__ResizeMenu(hObj, pObj);         break;       case MENU_ON_CLOSE:         _CloseSubmenu(hObj, pObj);         break;       case MENU_IS_MENU:         pMsg->Data.v = 1;         break;       }     }   }      /*********************************************************************  *  *       _OnTouch  */   static char _OnTouch(MENU_Handle hObj, MENU_Obj* pObj, WM_MESSAGE* pMsg) {     const GUI_PID_STATE* pState = (const GUI_PID_STATE*)pMsg->Data.p;     if (pState) {  /* Something happened in our area (pressed or released) */       return _HandlePID(hObj, pObj, pState->x, pState->y, pState->Pressed);     }     return _HandlePID(hObj, pObj, -1, -1, -1); /* Moved out */   }      /*********************************************************************  *  *       _OnMouseOver  */   #if (GUI_SUPPORT_MOUSE)   static char _OnMouseOver(MENU_Handle hObj, MENU_Obj* pObj, WM_MESSAGE* pMsg) {     const GUI_PID_STATE* pState = (const GUI_PID_STATE *)pMsg->Data.p;     if (pState) {       return _HandlePID(hObj, pObj, pState->x, pState->y, -1);     }     return 0;   }   #endif      /*********************************************************************  *  *       _SetPaintColors  */   static void _SetPaintColors(const MENU_Obj* pObj, const MENU_ITEM* pItem, int ItemIndex) {     char Selected;     unsigned ColorIndex;     Selected = (ItemIndex == pObj->Sel) ? 1 : 0;     if (pObj->IsSubmenuActive && Selected) {       ColorIndex = MENU_CI_ACTIVE_SUBMENU;     } else if (pItem->Flags & MENU_IF_SEPARATOR) {       ColorIndex = MENU_CI_ENABLED;     } else {       ColorIndex = (Selected) ? MENU_CI_SELECTED : MENU_CI_ENABLED;       if (pItem->Flags & MENU_IF_DISABLED) {         if (pObj->Flags & MENU_CF_HIDE_DISABLED_SEL) {           ColorIndex = MENU_CI_DISABLED;         } else {           ColorIndex += MENU_CI_DISABLED;         }       }     }     GUI_SetBkColor(pObj->Props.aBkColor[ColorIndex]);     GUI_SetColor(pObj->Props.aTextColor[ColorIndex]);   }      /*********************************************************************  *  *       _OnPaint  *pObj->ScrollStateV.v*/  static void _OnPaint(MENU_Handle hObj, MENU_Obj* pObj,WM_MESSAGE* pMsg) {     GUI_RECT FillRect, TextRect,ClipRect;     MENU_ITEM* pItem;     unsigned TextWidth, NumItems, i;     U8 BorderLeft   = pObj->Props.aBorder[MENU_BI_LEFT];     U8 BorderTop    = pObj->Props.aBorder[MENU_BI_TOP];     int FontHeight  = GUI_GetYDistOfFont(pObj->Props.pFont);     int EffectSize  = _GetEffectSize(hObj, pObj);   /* Calculate clipping rectangle */  ClipRect = *(const GUI_RECT*)pMsg->Data.p;  NumItems = MENU__GetNumItems(pObj);     WM__GetClientRectWin(&pObj->Widget.Win, &FillRect);     GUI__ReduceRect(&FillRect, &FillRect, EffectSize);     GUI_SetFont(pObj->Props.pFont);     if (pObj->Flags & MENU_SF_VERTICAL) {       int ItemHeight, xSize;       xSize = _CalcMenuSizeX(hObj, pObj);       FillRect.x1 = xSize - EffectSize - 1;       TextRect.x0 = FillRect.x0 + BorderLeft;       for (i = pObj->ScrollStateV.v; i < NumItems; i++) {         pItem = (MENU_ITEM*)GUI_ARRAY_GetpItem(&pObj->ItemArray, i);   ///* Break when all other rows are outside the drawing area *///    if (RectItem.y0 > ClipRect.y1) {//      break;//    }      ItemHeight = _GetItemHeight(hObj, pObj, i);         _SetPaintColors(pObj, pItem, i);         FillRect.y1 = FillRect.y0 + ItemHeight - 1;         if (pItem->Flags & MENU_IF_SEPARATOR) {           GUI_ClearRectEx(&FillRect);           GUI_SetColor(0x7C7C7C);           GUI_DrawHLine(FillRect.y0 + BorderTop + 1, FillRect.x0 + 2, FillRect.x1 - 2);         } else {           TextWidth = pItem->TextWidth;           TextRect.x1 = TextRect.x0 + TextWidth - 1;           TextRect.y0 = FillRect.y0 + BorderTop;           TextRect.y1 = TextRect.y0 + FontHeight - 1;           WIDGET__FillStringInRect(pItem->acText, &FillRect, &TextRect, &TextRect);         }         FillRect.y0 += ItemHeight;    /* Break when all other rows are outside the drawing area */    if (FillRect.y0> ClipRect.y1) {      break;    }    }     } else {       int ItemWidth, ySize;       ySize = _CalcMenuSizeY(hObj, pObj);       FillRect.y1 = ySize - EffectSize - 1;       TextRect.y0 = FillRect.y0 + BorderTop;       TextRect.y1 = TextRect.y0 + FontHeight - 1;       for (i = 0; i < NumItems; i++) {         pItem = (MENU_ITEM*)GUI_ARRAY_GetpItem(&pObj->ItemArray, i);         ItemWidth = _GetItemWidth(hObj, pObj, i);         _SetPaintColors(pObj, pItem, i);         FillRect.x1 = FillRect.x0 + ItemWidth - 1;         if (pItem->Flags & MENU_IF_SEPARATOR) {           GUI_ClearRectEx(&FillRect);           GUI_SetColor(0x7C7C7C);           GUI_DrawVLine(FillRect.x0 + BorderLeft + 1, FillRect.y0 + 2, FillRect.y1 - 2);         } else {           TextWidth = pItem->TextWidth;           TextRect.x0 = FillRect.x0 + BorderLeft;           TextRect.x1 = TextRect.x0 + TextWidth - 1;           WIDGET__FillStringInRect(pItem->acText, &FillRect, &TextRect, &TextRect);         }         FillRect.x0 += ItemWidth;       }     }     if (pObj->Width || pObj->Height) {       GUI_RECT r;       WM__GetClientRectWin(&pObj->Widget.Win, &r);       GUI__ReduceRect(&r, &r, EffectSize);       GUI_SetBkColor(pObj->Props.aBkColor[MENU_CI_ENABLED]);       GUI_ClearRect(FillRect.x1 + 1, EffectSize, r.x1, FillRect.y1);       GUI_ClearRect(EffectSize, FillRect.y1 + 1, r.x1, r.y1);     }     /* Draw 3D effect (if configured) */     if (_HasEffect(hObj, pObj)) {       pObj->Widget.pEffect->pfDrawUp();     }   }    static void _OnPaintBK(MENU_Handle hObj, MENU_Obj* pObj) {     GUI_RECT FillRect, TextRect;     MENU_ITEM* pItem;     unsigned TextWidth, NumItems, i;     U8 BorderLeft   = pObj->Props.aBorder[MENU_BI_LEFT];     U8 BorderTop    = pObj->Props.aBorder[MENU_BI_TOP];     int FontHeight  = GUI_GetYDistOfFont(pObj->Props.pFont);     int EffectSize  = _GetEffectSize(hObj, pObj);     NumItems = MENU__GetNumItems(pObj);     WM__GetClientRectWin(&pObj->Widget.Win, &FillRect);     GUI__ReduceRect(&FillRect, &FillRect, EffectSize);     GUI_SetFont(pObj->Props.pFont);     if (pObj->Flags & MENU_SF_VERTICAL) {       int ItemHeight, xSize;       xSize = _CalcMenuSizeX(hObj, pObj);       FillRect.x1 = xSize - EffectSize - 1;       TextRect.x0 = FillRect.x0 + BorderLeft;       for (i = 0; i < NumItems; i++) {         pItem = (MENU_ITEM*)GUI_ARRAY_GetpItem(&pObj->ItemArray, i);         ItemHeight = _GetItemHeight(hObj, pObj, i);         _SetPaintColors(pObj, pItem, i);         FillRect.y1 = FillRect.y0 + ItemHeight - 1;         if (pItem->Flags & MENU_IF_SEPARATOR) {           GUI_ClearRectEx(&FillRect);           GUI_SetColor(0x7C7C7C);           GUI_DrawHLine(FillRect.y0 + BorderTop + 1, FillRect.x0 + 2, FillRect.x1 - 2);         } else {           TextWidth = pItem->TextWidth;           TextRect.x1 = TextRect.x0 + TextWidth - 1;           TextRect.y0 = FillRect.y0 + BorderTop;           TextRect.y1 = TextRect.y0 + FontHeight - 1;           WIDGET__FillStringInRect(pItem->acText, &FillRect, &TextRect, &TextRect);         }         FillRect.y0 += ItemHeight;       }     } else {       int ItemWidth, ySize;       ySize = _CalcMenuSizeY(hObj, pObj);       FillRect.y1 = ySize - EffectSize - 1;       TextRect.y0 = FillRect.y0 + BorderTop;       TextRect.y1 = TextRect.y0 + FontHeight - 1;       for (i = 0; i < NumItems; i++) {         pItem = (MENU_ITEM*)GUI_ARRAY_GetpItem(&pObj->ItemArray, i);         ItemWidth = _GetItemWidth(hObj, pObj, i);         _SetPaintColors(pObj, pItem, i);         FillRect.x1 = FillRect.x0 + ItemWidth - 1;         if (pItem->Flags & MENU_IF_SEPARATOR) {           GUI_ClearRectEx(&FillRect);           GUI_SetColor(0x7C7C7C);           GUI_DrawVLine(FillRect.x0 + BorderLeft + 1, FillRect.y0 + 2, FillRect.y1 - 2);         } else {           TextWidth = pItem->TextWidth;           TextRect.x0 = FillRect.x0 + BorderLeft;           TextRect.x1 = TextRect.x0 + TextWidth - 1;           WIDGET__FillStringInRect(pItem->acText, &FillRect, &TextRect, &TextRect);         }         FillRect.x0 += ItemWidth;       }     }     if (pObj->Width || pObj->Height) {       GUI_RECT r;       WM__GetClientRectWin(&pObj->Widget.Win, &r);       GUI__ReduceRect(&r, &r, EffectSize);       GUI_SetBkColor(pObj->Props.aBkColor[MENU_CI_ENABLED]);       GUI_ClearRect(FillRect.x1 + 1, EffectSize, r.x1, FillRect.y1);       GUI_ClearRect(EffectSize, FillRect.y1 + 1, r.x1, r.y1);     }     /* Draw 3D effect (if configured) */     if (_HasEffect(hObj, pObj)) {       pObj->Widget.pEffect->pfDrawUp();     }   }      /*********************************************************************  *  *       _MoveSel  *  * Purpose:  *   Moves the selection of the given menu to the desired direction.  *   If the last or the first item is selected, the selection moves to the begin or the end.  *   Separators will be skipped.  */   static void _MoveSel(MENU_Handle hObj, int Dir) {     MENU_Obj * pObj;     int NewIndex, Index, NumItems, Cnt = 0;     pObj = (MENU_Obj*) GUI_ALLOC_h2p(hObj);     Index = pObj->Sel;     NewIndex = -1;     NumItems = pObj->ItemArray.NumItems;     do {       MENU_ITEM * pItem;       Index += Dir;       if (Index >= NumItems) {         Index = 0;         Cnt++;       } else if (Index < 0) {         Index = NumItems - 1;         Cnt++;       }       pItem = (MENU_ITEM*)GUI_ARRAY_GetpItem(&pObj->ItemArray, Index);       if (!(pItem->Flags & MENU_IF_SEPARATOR)) {         NewIndex = Index;       }     } while ((NewIndex < 0) && (Cnt < 2));     if (NewIndex >= 0) {       //_SetSelection(hObj, pObj, Index);    MenuBox_SetSel(hObj,Index);   }   }      /*********************************************************************  *  *       _OpenMenu  */   static void _OpenMenu(MENU_Handle hObj, MENU_Obj * pObj, int Index, int SubSel) {     MENU_ITEM * pItem;     MENU_Obj  * pSubObj;     pItem = (MENU_ITEM *)GUI_ARRAY_GetpItem(&pObj->ItemArray, Index);     pObj->Flags |= MENU_SF_ACTIVE;     _OpenSubmenu(hObj, pObj, Index);     pSubObj = (MENU_Obj *) GUI_ALLOC_h2p(pItem->hSubmenu);     if (SubSel >= pSubObj->ItemArray.NumItems) {       SubSel = pSubObj->ItemArray.NumItems - 1;     }     _SetSelection(pItem->hSubmenu, pSubObj, SubSel);     WM_SetFocus(pItem->hSubmenu);     _SetSelection(hObj, pObj, Index);   }      /*********************************************************************  *  *       _OnKey  */   static int _OnKey(MENU_Handle hObj, MENU_Obj * pObj, int Key) {     int KeyOpen, KeyBack, KeyNext, KeyPrev, Index, SubSel = 0;     MENU_ITEM * pItem;     MENU_Handle hObjTopLevel;     MENU_Obj * pObjTopLevel;     Index = pObj->Sel;     _GetTopLevelMenu(hObj, pObj, &hObjTopLevel, &pObjTopLevel, &SubSel);     if (Index < 0) {       if (Key != GUI_KEY_ESCAPE) {         _SetSelection(hObj, pObj, 0);         _SetCapture(hObj, pObj);       }       else if ((hObjTopLevel == hObj) && (pObjTopLevel->Flags & MENU_CF_VERTICAL)) {           WM_SetFocus(pObj->hOwner);           //_DeactivateMenu(hObj, pObj);           _ClosePopup(hObj, pObj);       }       return 0;     }     if (pObj->Flags & MENU_CF_VERTICAL) {       KeyOpen = GUI_KEY_RIGHT;       KeyBack = GUI_KEY_LEFT;       KeyNext = GUI_KEY_DOWN;       KeyPrev = GUI_KEY_UP;     } else {       KeyOpen = GUI_KEY_DOWN;       KeyBack = 0;       KeyNext = GUI_KEY_RIGHT;       KeyPrev = GUI_KEY_LEFT;     }     pItem = (MENU_ITEM *)GUI_ARRAY_GetpItem(&pObj->ItemArray, Index);     if (pItem->hSubmenu && ((Key == KeyOpen) || (Key == GUI_KEY_ENTER))) {       /*       *  If the current menu item is a submenu and <ENTER> or KeyOpen has been pressed, open the submenu       */       _OpenMenu(hObj, pObj, Index, 0);     } else if (!pItem->hSubmenu && (Key == GUI_KEY_ENTER)) {       /*       *  If the current menu item is not a submenu and <ENTER> has been pressed,       *  set the focus to the top level menu, close the submenus and send an MENU_ON_ITEMSELECT message to the owner       */       WM_SetFocus(hObjTopLevel);       _ActivateItem(hObj, pObj, Index);     } else if (((hObjTopLevel != hObj) && !(pObjTopLevel->Flags & MENU_CF_VERTICAL) && (Key == KeyOpen) && (!pItem->hSubmenu)) ||                ((hObjTopLevel != hObj) && !(pObjTopLevel->Flags & MENU_CF_VERTICAL) && (Key == KeyBack) && (hObjTopLevel == pObj->hOwner))) {       /*       *  If the current menu is not the top level menu and the top level menu is horizontal       *  and <GUI_KEY_RIGHT> or <GUI_KEY_LEFT> has been pressed close the current submenus,       *  move the selection of the top level menu to next/previous item and open it       */       pObj->Flags &= ~MENU_SF_ACTIVE;       /* Set focus to top level menu */       WM_SetFocus(hObjTopLevel);       /* Move selection of top level menu */       if (Key == KeyOpen) {         _MoveSel(hObjTopLevel, +1);       } else {         _MoveSel(hObjTopLevel, -1);       }       /* Open top level menu */       _OpenMenu(hObjTopLevel, pObjTopLevel, pObjTopLevel->Sel, (Key == KeyBack) ? SubSel : 0);     //} else if ((hObjTopLevel != hObj) &&      //           ((Key == GUI_KEY_ESCAPE) || ((Key == KeyBack) && ((!(pObjTopLevel->Flags & MENU_CF_VERTICAL)) && (!pItem->hSubmenu) && (hObjTopLevel != pObj->hOwner)) || (pObjTopLevel->Flags & MENU_CF_VERTICAL)))) {     } else if ((hObjTopLevel != hObj) &&                 ((Key == GUI_KEY_ESCAPE) ||                 ((Key == KeyBack) && ((pObjTopLevel->Flags & MENU_CF_VERTICAL) && (!pItem->hSubmenu))))) {       /*       *  If the current menu is not the top level menu and the top level menu is vertical and <GUI_KEY_LEFT> has been pressed       *  or the top level menu is vertical or horizontal and <GUI_KEY_ESCAPE> has been pressed,       *  close the current submenu       */       WM_SetFocus(pObj->hOwner);       _CloseSubmenu(hObjTopLevel, pObjTopLevel);     } else if ((hObjTopLevel == hObj) && (Key == GUI_KEY_ESCAPE) && (pObjTopLevel->Flags & MENU_CF_VERTICAL)) {       /*       *  If the current menu is not the top level menu and the top level menu is vertical and <GUI_KEY_LEFT> has been pressed       *  or the top level menu is vertical or horizontal and <GUI_KEY_ESCAPE> has been pressed,       *  close the current submenu       */       WM_SetFocus(pObj->hOwner);       //_DeactivateMenu(hObj, pObj);       _ClosePopup(hObj, pObj);     } else if ((hObjTopLevel == hObj) && (Key == GUI_KEY_ESCAPE)) {       /*       *  If the current menu is the top level menu and <GUI_KEY_ESCAPE> has been pressed,       *  unselect the menu and release capture       */       _SetSelection(hObj, pObj, -1);       _ReleaseCapture(hObj, pObj);     } else if (Key == KeyNext) {       /*       *  If KeyNext has been pressed move the selection to the next menu item       */       _CloseSubmenu(hObj, pObj);       _MoveSel(hObj, +1);     } else if (Key == KeyPrev) {       /*       *  If KeyPrev has been pressed move the selection to the previous menu item       */       _CloseSubmenu(hObj, pObj);       _MoveSel(hObj, -1);     } else {       return 1;     }     return 0;   }         /*********************************************************************  *  *       _MENU_Callback  */   static void _MENU_Callback(WM_MESSAGE* pMsg) {     MENU_Handle hObj;     MENU_Obj* pObj;     hObj = pMsg->hWin;     if (pMsg->MsgId != WM_PID_STATE_CHANGED) {       /* Let widget handle the standard messages */       if (WIDGET_HandleActive(hObj, pMsg) == 0) {         return;       }     }     pObj = (MENU_Obj*) GUI_ALLOC_h2p(hObj);     switch (pMsg->MsgId) {     case WM_MENU:       _OnMenu(hObj, pObj, pMsg);       return;     /* Message handled, do not call WM_DefaultProc() here. */     case WM_TOUCH:       if (_OnTouch(hObj, pObj, pMsg)) {         _ForwardPIDMsgToOwner(hObj, pObj, pMsg);       }       break;   #if (GUI_SUPPORT_MOUSE)     case WM_MOUSEOVER:       if (_OnMouseOver(hObj, pObj, pMsg)) {         _ForwardPIDMsgToOwner(hObj, pObj, pMsg);       }       break;   #endif     case WM_KEY:       if (((const WM_KEY_INFO*)(pMsg->Data.p))->PressedCnt > 0) {         if (!_OnKey(hObj, pObj, ((const WM_KEY_INFO*)(pMsg->Data.p))->Key)) {           return;         }       }       break;     case WM_PAINT:       _OnPaint(hObj, pObj,pMsg);       break;     case WM_DELETE:       GUI_ARRAY_Delete(&pObj->ItemArray);       break;      /* No return here ... WM_DefaultProc needs to be called */     }     WM_DefaultProc(pMsg);   }      /*********************************************************************  *  *       Public code, Create  *  **********************************************************************  */   /*********************************************************************  *  *       MENU_CreateEx  */   MENU_Handle MENU_CreateEx(int x0, int y0, int xSize, int ySize, WM_HWIN hParent, int WinFlags, int ExFlags, int Id) {     MENU_Handle hObj;     /* Create the window */     hObj = WM_CreateWindowAsChild(x0, y0, xSize, ySize, hParent, WM_CF_SHOW | WM_CF_STAYONTOP | WinFlags, &_MENU_Callback,                                   sizeof(MENU_Obj) - sizeof(WM_Obj));     if (hObj) {       MENU_Obj* pObj;       WM_LOCK();       pObj = (MENU_Obj*)GUI_ALLOC_h2p(hObj);        /* Init sub-classes */       GUI_ARRAY_CREATE(&pObj->ItemArray);       /* init widget specific variables */       WIDGET__Init(&pObj->Widget, Id, WIDGET_STATE_FOCUSSABLE);       /* init member variables */       if (ExFlags & MENU_SF_OPEN_ON_POINTEROVER) {         ExFlags |= MENU_SF_ACTIVE;       } else {         ExFlags &= ~(MENU_SF_ACTIVE);       }       pObj->Props           = MENU__DefaultProps;       pObj->Flags           = ExFlags;       pObj->Width           = ((xSize > 0) ? xSize : 0);       pObj->Height          = ((ySize > 0) ? ySize : 0);       pObj->Sel             = -1;       pObj->hOwner          = 0;       pObj->IsSubmenuActive = 0;       WIDGET_SetEffect(hObj, MENU__pDefaultEffect);       INIT_ID(pObj);   MENU_UpdateScrollers(hObj);//add liu    WM_UNLOCK();     } else {       GUI_DEBUG_ERROROUT_IF(hObj==0, "MENU_CreateEx failed")     }     return hObj;   }      /*********************************************************************  *  *       Public code, modul internal functions  *  **********************************************************************  */   /*********************************************************************  *  *       MENU__GetNumItems  */   unsigned MENU__GetNumItems(MENU_Obj* pObj) {     return GUI_ARRAY_GetNumItems(&pObj->ItemArray);   }      /*********************************************************************  *  *       MENU__InvalidateItem  */   void MENU__InvalidateItem(MENU_Handle hObj, const MENU_Obj* pObj, unsigned Index) {     GUI_USE_PARA(pObj);     GUI_USE_PARA(Index);     WM_InvalidateWindow(hObj);  /* Can be optimized, no need to invalidate all items */   }      /*********************************************************************  *  *       MENU__RecalcTextWidthOfItems  */   void MENU__RecalcTextWidthOfItems(MENU_Obj* pObj) {     const GUI_FONT GUI_UNI_PTR* pOldFont;     MENU_ITEM* pItem;     unsigned i, NumItems;     NumItems = MENU__GetNumItems(pObj);     pOldFont  = GUI_SetFont(pObj->Props.pFont);     for (i = 0; i < NumItems; i++) {       pItem = (MENU_ITEM*)GUI_ARRAY_GetpItem(&pObj->ItemArray, i);       pItem->TextWidth = GUI_GetStringDistX(pItem->acText);     }     GUI_SetFont(pOldFont);   }      /*********************************************************************  *  *       MENU__ResizeMenu  */   void MENU__ResizeMenu(MENU_Handle hObj, MENU_Obj* pObj) {     int xSize, ySize;     xSize = _CalcWindowSizeX(hObj, pObj);     ySize = _CalcWindowSizeY(hObj, pObj);  //xSize=50;//ySize=100;  WM_SetSize(hObj, xSize, ySize);     WM_InvalidateWindow(hObj);   }      /*********************************************************************  *  *       MENU__SetItem  */   char MENU__SetItem(MENU_Handle hObj, MENU_Obj* pObj, unsigned Index, const MENU_ITEM_DATA* pItemData) {     MENU_ITEM Item = {0};     const char* pText;     pText = pItemData->pText;     if (!pText) {       pText = "";     }     Item.Id        = pItemData->Id;     Item.Flags     = pItemData->Flags;     Item.hSubmenu  = pItemData->hSubmenu;     Item.TextWidth = _CalcTextWidth(pObj, pText);     if (Item.Flags & MENU_IF_SEPARATOR) {       Item.hSubmenu = 0;   /* Ensures that no separator is a submenu */     }     if (GUI_ARRAY_SetItem(&pObj->ItemArray, Index, &Item, sizeof(MENU_ITEM) + strlen(pText)) != 0) {       MENU_ITEM* pItem = (MENU_ITEM*)GUI_ARRAY_GetpItem(&pObj->ItemArray, Index);       strcpy(pItem->acText, pText);       MENU_SetOwner(Item.hSubmenu, hObj);       return 1;     }     return 0;   }      /*********************************************************************  *  *       MENU__SetItemFlags  */   void MENU__SetItemFlags(MENU_Obj* pObj, unsigned Index, U16 Mask, U16 Flags) {     MENU_ITEM* pItem = (MENU_ITEM*)GUI_ARRAY_GetpItem(&pObj->ItemArray, Index);     pItem->Flags &= ~Mask;     pItem->Flags |= Flags;   }      /*********************************************************************  *  *       MENU__SendMenuMessage  */   int MENU__SendMenuMessage(MENU_Handle hObj, WM_HWIN hDestWin, U16 MsgType, U16 ItemId) {     MENU_MSG_DATA MsgData;     WM_MESSAGE    Msg = {0};     MsgData.MsgType   = MsgType;     MsgData.ItemId    = ItemId;     Msg.MsgId         = WM_MENU;     Msg.Data.p        = &MsgData;     Msg.hWinSrc       = hObj;     if (!hDestWin) {       hDestWin = WM_GetParent(hObj);     }     if (hDestWin) {       WM__SendMessage(hDestWin, &Msg);       return Msg.Data.v;     }     return 0;   }      /*********************************************************************  *  *       Public code, member functions  *  **********************************************************************  */   /*********************************************************************  *  *       MENU_AddItem  */   void MENU_AddItem(MENU_Handle hObj, const MENU_ITEM_DATA* pItemData) {     if (hObj && pItemData) {       MENU_Obj* pObj;       WM_LOCK();       pObj = MENU_H2P(hObj);       if (pObj) {         if (GUI_ARRAY_AddItem(&pObj->ItemArray, NULL, 0) == 0) {           unsigned Index;           Index = MENU__GetNumItems(pObj) - 1;           if (MENU__SetItem(hObj, pObj, Index, pItemData) == 0) {             GUI_ARRAY_DeleteItem(&pObj->ItemArray, Index);           } else {             MENU__ResizeMenu(hObj, pObj);   // LIU ADD    MENU__InvalidateItemSize(pObj, Index);MENU_UpdateScrollers(hObj);MENU__InvalidateItem(hObj, pObj, Index);        }         }       }       WM_UNLOCK();     }   }      /*********************************************************************  *  *       MENU_SetOwner  */   void MENU_SetOwner(MENU_Handle hObj, WM_HWIN hOwner) {     if (hObj) {       MENU_Obj* pObj;       WM_LOCK();       pObj = MENU_H2P(hObj);       if (pObj) {         pObj->hOwner = hOwner;       }       WM_UNLOCK();     }   }      #else  /* avoid empty object files */     void Menu_C(void);     void Menu_C(void) {}   #endif      /*************************** End of file ****************************/   

原创粉丝点击