#include "menu.h"
#include "lcd_app.h"
int nSelectRecord[MAX_MENU_LAYERS];
int nCurrentLayer = 0;
// --------------------------------------------------------------------------------
// 描 述: 初始化菜单
// 参 数:
// pMenu 菜单指针
// bDirection 菜单的排列方向:DIRECTION_HORIZON 或 DIRECTION_VERTICAL
// nRows,nCols 显示菜单的行数与列数,如果小于实际行数与列数将滚动显示
// nHDistance, nVDistance 菜单项之间的象素距离
//
// 返回值: 无
// 注 意: 此函数应该在其它函数对该菜单的操作之前调用
// --------------------------------------------------------------------------------
void MenuInitialize(PPOSMENU pMenu, BOOL bDirection, int nRows, int nCols, int nHDistance, int nVDistance)
{
pMenu->nMenuItemCount = 0;
pMenu->bCanBeCancel = FALSE;
pMenu->bDirection = bDirection;
pMenu->nCols = nCols;
pMenu->nRows = nRows;
pMenu->nHDistance = nHDistance;
pMenu->nVDistance = nVDistance;
}
//--------------------------------------------------------------------------------
// 描 述: 清空菜单项,将菜单结构中的菜单项计数清零
// 参 数:
// pMenu 需要清空的菜单指针
//
// 返回值: 无
//--------------------------------------------------------------------------------
void MenuClearAllItems(PPOSMENU pMenu)
{
pMenu->nMenuItemCount = 0;
}
//--------------------------------------------------------------------------------
// 描 述: 设置菜单是否能够被 VK_CANCEL 键取消操作
// 参 数:
// pMenu 需要清空的菜单指针
//
// 返回值: 无
//--------------------------------------------------------------------------------
void MenuEnableCancel(PPOSMENU pMenu, BOOL bCanBeCancel)
{
pMenu->bCanBeCancel = bCanBeCancel;
}
//--------------------------------------------------------------------------------
// 描 述: 设置菜单风格
// 参 数:
// pMenu 菜单指针
// pItemString 添加的菜单项的字符串
//
// 返回值: 添加成功返回 TRUE,否则返回 FALSE(例如超过最大菜单项数)
//--------------------------------------------------------------------------------
BOOL MenuAppendItem(PPOSMENU pMenu, const char *pItemString)
{
if(pMenu->nMenuItemCount>=MAX_MENU_ITEMS)
return FALSE;
if(strlen((char*)pItemString)>MAX_MENU_ITEM_LENGTH)
{
memcpy(pMenu->strMenuItems[pMenu->nMenuItemCount], pItemString, MAX_MENU_ITEMS);
pMenu->strMenuItems[pMenu->nMenuItemCount][MAX_MENU_ITEM_LENGTH] = 0;
}
else
strcpy((char*)(pMenu->strMenuItems[pMenu->nMenuItemCount]), (char*)pItemString);
pMenu->nMenuItemCount++;
return TRUE;
}
//--------------------------------------------------------------------------------
// 描 述: 绘制菜单滚动时出现的三角形
// 参 数:
// pMenu 菜单指针
// nStartItem 当前屏第一行第一列的菜单项(起始菜单项)
// nCurItem 高亮显示的菜单项,为-1时表示无高亮显示项
//
// 返回值: 返回实际显示时位于第一行第一列的菜单项序号,即是当前屏菜单项的最小序号
//--------------------------------------------------------------------------------
void MenuDrawTriangle(int x, int y, int nDirection, unsigned char nColor)
{
int i, j;
switch(nDirection) // 判断三角形箭头的方向
{
case 1: // 向左
y+=4;
for(i=0; i<4; i++)
for(j=0; j<(i+1); j++)
{
putpixel(x+i, y+j, nColor);
putpixel(x+i, y-j, nColor);
}
break;
case 2: // 向右
y+=4; x+=4;
for(i=0; i<4; i++)
for(j=0; j<(i+1); j++)
{
putpixel(x-i, y+j, nColor);
putpixel(x-i, y-j, nColor);
}
break;
case 3: // 向下
x+=3;
for(i=0; i<4; i++)
for(j=0; j<(i+1); j++)
{
putpixel(x+j, y+i, nColor);
putpixel(x-j, y+i, nColor);
}
break;
case 4: // 向上
x+=3; y-=2;
for(i=0; i<4; i++)
for(j=0; j<(i+1); j++)
{
putpixel(x+j, y-i, nColor);
putpixel(x-j, y-i, nColor);
}
break;
}
}
// --------------------------------------------------------------------------------
// 描 述: 从第一行、第一列开始显示指定起始项的当前屏菜单项并高亮显示指定菜单项
// 参 数:
// pMenu 菜单指针
// nStartItem 当前屏第一行第一列的菜单项(起始菜单项)
// nCurItem 高亮显示的菜单项,为-1时表示无高亮显示项
//
// 返回值: 返回实际显示时位于第一行第一列的菜单项序号,即是当前屏菜单项的最小序号
// --------------------------------------------------------------------------------
int MenuDisplay(int x, int y, PPOSMENU pMenu, int nStartItem, int nCurItem)
{
int i, row, col;
int nMaxItem, uWidth, mWidth;
if(nStartItem>pMenu->nMenuItemCount || nStartItem<1)
return 0;
if(nCurItem>pMenu->nMenuItemCount || nCurItem<1)
return 0;
uWidth = CaculateStringWidth(12, pMenu->strMenuItems[0]);
if(!pMenu->bDirection) // 垂直方向排列
{
// 计算当前屏显示菜单的最大序号和最小序号
nMaxItem = nStartItem + pMenu->nRows * pMenu->nCols -1;
if(nMaxItem>pMenu->nMenuItemCount)
nMaxItem = pMenu->nMenuItemCount;
// 显示当前屏的菜单项
for(i=nStartItem; i<=nMaxItem; i++)
{
col = (i-nStartItem)/pMenu->nRows;
row = (i-nStartItem)%pMenu->nRows;
mWidth=CaculateStringWidth(12, pMenu->strMenuItems[nCurItem-1]);
if(i==nCurItem)
{
DrawRect(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12)-1,
x+col*(pMenu->nHDistance+uWidth)+mWidth-1, y+row*(pMenu->nVDistance+12)+12,1);
TextOut12I(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12), pMenu->strMenuItems[i-1]);
}
else
{
DrawRect(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12)-1,
x+col*(pMenu->nHDistance+uWidth)+mWidth-1, y+row*(pMenu->nVDistance+12)+12,0);
TextOut12(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12), pMenu->strMenuItems[i-1]);
}
}
// 菜单滚动时绘制箭头
row = y + pMenu->nRows*(pMenu->nVDistance+12);
col = x + pMenu->nCols*(pMenu->nHDistance+uWidth)-pMenu->nHDistance-6;
if(pMenu->nCols*pMenu->nRows < pMenu->nMenuItemCount)
{
// GUI_DrawRect(x+5, row+1, col-1, row+7);
if(nMaxItem<pMenu->nMenuItemCount)
MenuDrawTriangle(col, row, 2, 1);
else
MenuDrawTriangle(col, row, 2, 0);
if(nStartItem>1)
MenuDrawTriangle(x, row, 1, 1);
else
MenuDrawTriangle(x, row, 1, 0);
}
}
else // 水平方向排列
{
// 计算当前屏显示菜单的最大序号和最小序号
nMaxItem = nStartItem + pMenu->nCols * pMenu->nRows - 1;
if(nMaxItem>pMenu->nMenuItemCount)
nMaxItem = pMenu->nMenuItemCount;
// 显示当前屏的菜单项
for(i=nStartItem; i<=nMaxItem; i++)
{
row = (i-nStartItem)/pMenu->nCols;
col = (i-nStartItem)%pMenu->nCols;
mWidth=CaculateStringWidth(12, pMenu->strMenuItems[nCurItem-1]);
if(i==nCurItem)
{
DrawRect(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12)-1,
x+col*(pMenu->nHDistance+uWidth)+mWidth-1, y+row*(pMenu->nVDistance+12)+12,1);
TextOut12I(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12), pMenu->strMenuItems[i-1]);
}
else
{
DrawRect(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12)-1,
x+col*(pMenu->nHDistance+uWidth)+mWidth-1, y+row*(pMenu->nVDistance+12)+12,0);
TextOut12(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12), pMenu->strMenuItems[i-1]);
}
}
// 菜单滚动时绘制箭头
row = y + pMenu->nRows*(pMenu->nVDistance+12)-pMenu->nVDistance;
col = x + pMenu->nCols*(pMenu->nHDistance+uWidth)-pMenu->nHDistance+2;
if(pMenu->nCols*pMenu->nRows < pMenu->nMenuItemCount)
{
// GUI_DrawRect(col, y+5, col+6, row-7);
if(nMaxItem<pMenu->nMenuItemCount)
MenuDrawTriangle(col, row, 4, 1);
else
MenuDrawTriangle(col, row, 4, 0);
if(nStartItem>1)
MenuDrawTriangle(col, y, 3, 1);
else
MenuDrawTriangle(col, y, 3, 0);
}
}
return nStartItem;
}
// --------------------------------------------------------------------------------
// 描 述: 改变当前用户的菜单选项
// 参 数:
// x,y 菜单的左上角屏幕坐标(象素)
// pMenu 菜单指针
// pnMinItem,pnMaxItem 当前屏左上角菜单项序号和最大菜单项序号指针
// pnCurItem 当前所选的菜单项
// nNewItem 新菜单项
// 输 出:
// 如果选择中菜单发生滚动,将自动改变 pnMinItem 和 pnMaxItem 所指向的值
// 如果改变菜单选项成功,新菜单项序号将保存在 pnCurItem 所指向的值中
//
// 返回值: 如果新选项有效返回 TRUE,否则返回 FALSE
//--------------------------------------------------------------------------------
BOOL MenuMoveSel(int x, int y, PPOSMENU pMenu, int *pnMinItem, int *pnMaxItem, int *pnCurItem, int nNewItem)
{
int nCurItem = *pnCurItem, nMinItem = *pnMinItem, nMaxItem = *pnMaxItem, uTemp;
int row, col, uWidth,mWidth;
if(nNewItem>pMenu->nMenuItemCount)
nNewItem = pMenu->nMenuItemCount;
else if(nNewItem<1)
return FALSE;
if(nCurItem == nNewItem)
return TRUE;
uWidth = CaculateStringWidth(12, pMenu->strMenuItems[0]);
if(!pMenu->bDirection) // 如果菜单按照垂直方向排列
{
if(nNewItem>=(*pnMinItem) && nNewItem<=(*pnMaxItem)) // 如果在当前屏,不需要滚动显示
{
// 恢复旧选项的显示
col = (nCurItem-nMinItem)/pMenu->nRows;
row = (nCurItem-nMinItem)%pMenu->nRows;
mWidth=CaculateStringWidth(12, pMenu->strMenuItems[nCurItem-1]);
DrawRect(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12)-1,
x+col*(pMenu->nHDistance+uWidth)+mWidth-1, y+row*(pMenu->nVDistance+12)+12,0);
TextOut12(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12), pMenu->strMenuItems[nCurItem-1]);
// 高亮显示新选项
col = (nNewItem-nMinItem)/pMenu->nRows;
row = (nNewItem-nMinItem)%pMenu->nRows;
mWidth=CaculateStringWidth(12, pMenu->strMenuItems[nNewItem-1]);
DrawRect(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12)-1,
x+col*(pMenu->nHDistance+uWidth)+mWidth-1, y+row*(pMenu->nVDistance+12)+12,1);
TextOut12I(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12), pMenu->strMenuItems[nNewItem-1]);
LCD_ForceRefresh();
}
else // 如果不在当前屏,需要滚动显示
{
if(nNewItem>nMaxItem) // 如果需要向右滚动
{
while(nMaxItem<nNewItem)
{
nMinItem += pMenu->nRows;
nMaxItem += pMenu->nRows;
for(uTemp=pMenu->nMenuItemCount+1; uTemp<=nMaxItem; uTemp++)
{
col = x + (uTemp-nMinItem)/pMenu->nRows*(pMenu->nHDistance+uWidth);
row = y + (uTemp-nMinItem)%pMenu->nRows*(pMenu->nVDistance+12);
FillRect(col, row-1, col+uWidth-1, row+12, 0);
}
if(nMaxItem>pMenu->nMenuItemCount)
nMaxItem = pMenu->nMenuItemCount;
}
}
else // 如果需要向左滚动
{
while(nMinItem>nNewItem)
{
nMinItem -= pMenu->nRows;
nMaxItem = nMinItem + pMenu->nRows*pMenu->nCols - 1;
if(nMaxItem>pMenu->nMenuItemCount)
nMaxItem = pMenu->nMenuItemCount;
}
}
MenuDisplay(x, y, pMenu, nMinItem, nNewItem);
*pnMinItem = nMinItem;
*pnMaxItem = nMaxItem;
LCD_ForceRefresh();
}
}
else // 如果菜单按照水平方向排列
{
if(nNewItem>=(*pnMinItem) && nNewItem<=(*pnMaxItem)) // 如果在当前屏,不需要滚动显示
{
// 恢复旧选项的显示
row = (nCurItem-nMinItem)/pMenu->nCols;
col = (nCurItem-nMinItem)%pMenu->nCols;
mWidth=CaculateStringWidth(12, pMenu->strMenuItems[nCurItem-1]);
DrawRect(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12)-1,
x+col*(pMenu->nHDistance+uWidth)+mWidth-1, y+row*(pMenu->nVDistance+12)+12,0);
TextOut12(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12), pMenu->strMenuItems[nCurItem-1]);
// 高亮显示新选项
row = (nNewItem-nMinItem)/pMenu->nCols;
col = (nNewItem-nMinItem)%pMenu->nCols;
mWidth=CaculateStringWidth(12, pMenu->strMenuItems[nNewItem-1]);
DrawRect(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12)-1,
x+col*(pMenu->nHDistance+uWidth)+mWidth-1, y+row*(pMenu->nVDistance+12)+12,1);
TextOut12I(x+col*(pMenu->nHDistance+uWidth), y+row*(pMenu->nVDistance+12), pMenu->strMenuItems[nNewItem-1]);
LCD_ForceRefresh();
}
else
{
if(nNewItem>nMaxItem) // 如果需要向下滚动
{
while(nMaxItem<nNewItem)
{
nMinItem += pMenu->nCols;
nMaxItem += pMenu->nCols;
for(uTemp=pMenu->nMenuItemCount+1; uTemp<=nMaxItem; uTemp++)
{
col = x + (uTemp-nMinItem)%pMenu->nCols*(pMenu->nHDistance+uWidth);
row = y + (uTemp-nMinItem)/pMenu->nCols*(pMenu->nVDistance+12);
FillRect(col, row-1, col+uWidth-1, row+12, 0);
}
if(nMaxItem>pMenu->nMenuItemCount)
nMaxItem = pMenu->nMenuItemCount;
}
}
else // 如果需要向上滚动
{
while(nMinItem>nNewItem)
{
nMinItem -= pMenu->nCols;
nMaxItem = nMinItem + pMenu->nRows*pMenu->nCols - 1;
if(nMaxItem>pMenu->nMenuItemCount)
nMaxItem = pMenu->nMenuItemCount;
}
}
MenuDisplay(x, y, pMenu, nMinItem, nNewItem);
*pnMinItem = nMinItem;
*pnMaxItem = nMaxItem;
LCD_ForceRefresh();
}
}
*pnCurItem = nNewItem;
return TRUE;
}
// --------------------------------------------------------------------------------
// 描 述: 显示并让用户选择菜单
// 参 数:
// x,y 菜单的左上角屏幕坐标(象素)
// pMenu 菜单指针
// nDefaultItem 默认选择的菜单项,以1为基数
//
// 返回值: 所选择的菜单项,按照菜单项的添加顺序为1,2,3,…,出现错误或被取消返回0
// --------------------------------------------------------------------------------
int MenuDoModal(int x, int y, PPOSMENU pMenu, int nDefaultItem)
{
int i, nWidth, nTemp;
int nMinItem, nMaxItem; // 本屏显示的菜单项的最小序号和最大序号
int nCurItem = nDefaultItem;
u32 uKey;
if(nDefaultItem > pMenu->nMenuItemCount || nDefaultItem < 1)
return 0;
nWidth = CaculateStringWidth(12, pMenu->strMenuItems[0]);
if(!pMenu->bDirection) // 如果菜单按照垂直方向排列
{
// 计算当前屏菜单项最小序号(对应当前屏左上角第一行、第一列的菜单项)和最大序号
i = pMenu->nCols;
nTemp = (int)nDefaultItem;
while(nTemp>0 && i>0)
{
nTemp -= pMenu->nRows;
i--;
}
nTemp += pMenu->nRows;
nTemp = (nTemp-1)/pMenu->nRows * pMenu->nRows + 1;
nMinItem = (int)nTemp;
nMaxItem = nMinItem + pMenu->nCols * pMenu->nRows -1;
if(nMaxItem>pMenu->nMenuItemCount)
nMaxItem = pMenu->nMenuItemCount;
MenuDisplay(x, y, pMenu, nMinItem, nDefaultItem); // 从指定位置开始显示菜单
LCD_ForceRefresh();
// 键盘处理--菜单的选择与滚动处理
/*
uKey = WaitKey();
while(1)
{
// OSTimeDly(200);
switch(uKey)
{
case VK_CANCEL:
if(pMenu->bCanBeCancel)
return 0;
break;
case VK_LOGOUT:
return 0;
case VK_SURE:
return nCurItem;
case VK_UP:
MenuMoveSel(x, y, pMenu, &nMinItem, &nMaxItem, &nCurItem, nCurItem-1);
break;
case VK_DOWN:
MenuMoveSel(x, y, pMenu, &nMinItem, &nMaxItem, &nCurItem, nCurItem+1);
break;
case VK_LEFT:
MenuMoveSel(x, y, pMenu, &nMinItem, &nMaxItem, &nCurItem, nCurItem-pMenu->nRows);
break;
case VK_RIGHT:
MenuMoveSel(x, y, pMenu, &nMinItem, &nMaxItem, &nCurItem, nCurItem+pMenu->nRows);
break;
case VK_SHIFT:
if(nCurItem >= pMenu->nMenuItemCount)
MenuMoveSel(x, y, pMenu, &nMinItem, &nMaxItem, &nCurItem, 1);
else
MenuMoveSel(x, y, pMenu, &nMinItem, &nMaxItem, &nCurItem, nCurItem+1);
break;
}
uKey = WaitKey();
}*/
}
else // 菜单项按水平方向排列
{
// 计算当前屏菜单项最小序号和最大序号
i = pMenu->nRows;
nTemp = nDefaultItem;
while(nTemp>0 && i>0)
{
nTemp -= pMenu->nCols;
i--;
}
nTemp += pMenu->nCols;
nTemp = (nTemp-1)/pMenu->nCols * pMenu->nCols + 1;
nMinItem = nTemp;
nMaxItem = nMinItem + pMenu->nRows * pMenu->nCols -1;
if(nMaxItem>pMenu->nMenuItemCount)
nMaxItem = pMenu->nMenuItemCount;
MenuDisplay(x, y, pMenu, nMinItem, nDefaultItem);
LCD_ForceRefresh();
// 键盘处理--菜单的选择与滚动处理
/*
uKey = WaitKey();
while(1)
{
switch(uKey)
{
case VK_CANCEL:
if(pMenu->bCanBeCancel)
return 0;
break;
case VK_LOGOUT:
return 0;
case VK_SURE:
return nCurItem;
case VK_UP:
MenuMoveSel(x, y, pMenu, &nMinItem, &nMaxItem, &nCurItem, nCurItem-pMenu->nCols);
break;
case VK_DOWN:
MenuMoveSel(x, y, pMenu, &nMinItem, &nMaxItem, &nCurItem, nCurItem+pMenu->nCols);
break;
case VK_LEFT:
MenuMoveSel(x, y, pMenu, &nMinItem, &nMaxItem, &nCurItem, nCurItem-1);
break;
case VK_RIGHT:
MenuMoveSel(x, y, pMenu, &nMinItem, &nMaxItem, &nCurItem, nCurItem+1);
break;
case VK_SHIFT:
if(nCurItem >= pMenu->nMenuItemCount)
MenuMoveSel(x, y, pMenu, &nMinItem, &nMaxItem, &nCurItem, 1);
else
MenuMoveSel(x, y, pMenu, &nMinItem, &nMaxItem, &nCurItem, nCurItem+1);
break;
}
uKey = WaitKey();
}*/
}
//for test
// TextOut12(80,80,"门前大桥下");
// LCD_ForceRefresh();
return 0;
}