數碼相框(五)--頁面規劃、輸入功能
阿新 • • 發佈:2018-12-31
一、頁面規劃
先實現螢幕顯示三個圖示,從上到下分別為:瀏覽模式、連播模式、設定。
/* 2. 描畫資料:確定數組裡三項圖示的位置,在videoMem裡描繪出來 */
static void ShowMainPage(PT_Layout atLayout)
{
if (ptVideoMem->ePicState != PS_GENERATED)
{
/* 獲得解析度 */
GetDispResolution(&iXres, &iYres, &iBpp);
/* 圖示高度 */
iIconHeight = iYres * 2 / 10;
/* 圖示寬度 */
iIconWidth = iIconHeight * 2;
/*x座標 */
iIconX = (iXres - iIconWidth)/2;
/* y座標 */
iIconY = iYres / 10;
/* 設定儲存圖示的格式 */
tIconPixelDatas.iBpp = iBpp;
tIconPixelDatas.iWidth = iIconWidth;
tIconPixelDatas. iHeight = iIconHeight;
tIconPixelDatas.iLineBytes = iIconWidth * iBpp / 8;
tIconPixelDatas.iTotalBytes = tIconPixelDatas.iLineBytes * iIconHeight;
tIconPixelDatas.aucPixelDatas = malloc(tIconPixelDatas.iTotalBytes);
if (tIconPixelDatas.aucPixelDatas == NULL)
{
free(tIconPixelDatas. aucPixelDatas);
return;
}
while (atLayout->strIconName)
{
atLayout->iTopLeftX = iIconX;
atLayout->iTopLeftY = iIconY;
atLayout->iBotRightX = iIconX + iIconWidth - 1;
atLayout->iBotRightY = iIconY + iIconHeight - 1;
/* 獲得圖示的畫素資訊 */
iError = GetPixelDatasForIcon(atLayout->strIconName, &tOriginIconPixelDatas);
if (iError)
{
DBG_PRINTF("GetPixelDatasForIcon error!\n");
return;
}
/* 原始圖示縮放為設定儲存圖示格式*/
PicZoom(&tOriginIconPixelDatas, &tIconPixelDatas);
/* 縮放後的圖示合併到視訊記憶體 */
PicMerge(iIconX, iIconY, &tIconPixelDatas, &ptVideoMem->tPixelDatas);
FreePixelDatasForIcon(&tOriginIconPixelDatas);
/* 操作下一個圖示,設定Y座標*/
atLayout++;
iIconY += iYres * 3 / 10;
}
free(tIconPixelDatas.aucPixelDatas);
ptVideoMem->ePicState = PS_GENERATED;
}
}
分析:
page_maneger.h定義圖示的輪廓
/* 輪廓 */
typedef struct Layout {
/* 左上*/
int iTopLeftX;
int iTopLeftY;
/* 右下 */
int iBotRightX;
int iBotRightY;
char *strIconName;
}T_Layout, *PT_Layout;
render.c
中實現圖示畫素獲取
/* 獲得圖示的畫素資訊 */
int GetPixelDatasForIcon(char *strFileName, PT_PixelDatas ptPixelDatas)
{
T_FileMap tFileMap;
int iError;
int iXres, iYres, iBpp;
/* 將ICON_PATH路徑下的strFileName檔案列印到tFileMap.strFileName陣列
圖示存在 /etc/digitpic/icons */
snprintf(tFileMap.strFileName, 128, "%s/%s", ICON_PATH, strFileName);tFileMap.strFileName陣列
tFileMap.strFileName[127] = '\0';
/* 給檔案分配空間 */
iError = MapFile(&tFileMap);
if (iError)
{
DBG_PRINTF("MapFile %s error!\n", strFileName);
return -1;
}
/* 是否支援檔案 */
iError = g_tBMPParser->isSupport(tFileMap.pucFileMapMem);
if (iError == 0)
{
DBG_PRINTF("%s is not bmp file\n", strFileName);
return -1;
}
/* 獲得解析度 */
GetDispResolution(&iXres, &iYres, &iBpp);
/* 設定解析度 */
ptPixelDatas->iBpp = iBpp;
/* 獲得bmp檔案的影象資料 */
iError = g_tBMPParser->GetPixelDatas(tFileMap.pucFileMapMem, ptPixelDatas);
if (iError)
{
DBG_PRINTF("GetPixelDatas for %s error!\n", strFileName);
return -1;
}
return 0;
}
在獲取圖示的畫素資訊函式中,我們將圖示當做檔案來處理。實現file.c。
file.h
中定義檔案結構體
#ifndef _FILE_H
#define _FILE_H
typedef struct FileMap {
char strFileName[128];
int iFd;
int iFileSize;
unsigned char *pucFileMapMem;
}T_FileMap, *PT_FileMap;
int MapFile(PT_FileMap ptFileMap);
void UnMapFile(PT_FileMap ptFileMap);
#endif /* _FILE_H */
file.c
開啟檔案、獲取檔案資訊並分配記憶體
#include <file.h>
int MapFile(PT_FileMap ptFileMap)
{
int iFd;
struct stat tStat;
/* 開啟檔案 */
iFd = open(ptFileMap->strFileName, O_RDWR);
if (iFd == -1)
{
DBG_PRINTF("can't open %s\n", ptFileMap->strFileName);
return -1;
}
ptFileMap->iFd = iFd;
/* 獲得檔案資訊 */
fstat(iFd, &tStat);
ptFileMap->iFileSize = tStat.st_size;
/* 分配記憶體 */
ptFileMap->pucFileMapMem = (unsigned char *)mmap(NULL , tStat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, iFd, 0);
if (ptFileMap->pucFileMapMem == (unsigned char *)-1)
{
DBG_PRINTF("mmap error!\n");
return -1;
}
return 0;
}
void UnMapFile(PT_FileMap ptFileMap)
{
unmap(ptFileMap->pucFileMapMem);
close(ptFileMap->iFd);
}
描畫資料流程:獲得解析度、Bpp,算出圖示大小、位置,設定儲存圖示的格式資訊然後分配記憶體,根據bmp檔名找到檔案,獲取檔案資訊,縮放好放入儲存圖示的位置。
render.c 實現圖示資訊刷到裝置視訊記憶體
void FlushVideoMemToDev(PT_VideoMem ptVideoMem)
{
//memcpy(GetDefaultDispDev()->pucDispMem, ptVideoMem->tPixelDatas.aucPixelDatas, ptVideoMem.tPixelDatas.iHeight * ptVideoMem.tPixelDatas.iLineBytes);
/* 判斷不在framebuffer中,然後刷到FLASH */
if (!ptVideoMem->bDevFrameBuffer)
{
GetDefaultDispDev()->ShowPage(ptVideoMem);
}
}
整個顯示頁面ShowMainPage
流程:獲得視訊記憶體,描畫資料,影象已經產生直接刷到FLASH;if (ptVideoMem->ePicState != PS_GENERATED)如果沒有生成就描畫圖示資訊,圖示縮放後合併到視訊記憶體裡面。ShowMainPage執行結束,從視訊記憶體連結串列中取出一塊空閒的視訊記憶體VideoMen,構造資料,刷到framebuffer,最後將使用視訊記憶體的釋放。
描畫資料流程:獲得解析度、Bpp,算出圖示大小、位置,設定儲存圖示的格式資訊然後分配記憶體,根據bmp檔名找到檔案,獲取檔案資訊,縮放好放入儲存圖示的位置。
二、輸入功能
input_manager.h
定義輸入事件結構體
/* 輸入事件結構體 */
typedef struct InputEvent {
struct timeval tTime;
int iType; /* stdin, touchsceen */
int iX;
int iY;
int iKey;
int iPressure;/* 壓力值 */
}T_InputEvent, *PT_InputEvent;
touchscreen.c
獲得輸入事件並處理
static int TouchScreenGetInputEvent(PT_InputEvent ptInputEvent)
{
struct ts_sample tSamp;
struct ts_sample tSampPressed;
struct ts_sample tSampReleased;
int iRet;
int bStart = 0;
int iDelta;
static struct timeval tPreTime;
while (1)
{
/*ts_read函式獲得tSamp(取樣值) */
iRet = ts_read(g_tTSDev, &tSamp, 1); /* 如果無資料則休眠 */
/* 有按鍵按下記錄引數 */
if (iRet == 1)
{
ptInputEvent->tTime = tSamp.tv;
ptInputEvent->iType = INPUT_TYPE_TOUCHSCREEN;
ptInputEvent->iX = tSamp.x;
ptInputEvent->iY = tSamp.y;
ptInputEvent->iPressure = tSamp.pressure;
return 0;
}
else
{
return -1;
}
}
return 0;
}
main_page.c
主頁面獲得輸入事件,處理,返回圖示引數
int MainPageGetInputEvent(PT_Layout atLayout, PT_InputEvent ptInputEvent)
{
T_InputEvent tInputEvent;
int iRet;
int i = 0;
/* 獲得原始的觸控式螢幕資料
* 它是呼叫input_manager.c的函式,此函式會讓當前線否休眠
* 當觸控式螢幕執行緒獲得資料後,會把它喚醒
*/
iRet = GetInputEvent(&tInputEvent);
if (iRet)
{
return -1;
}
/* 不是觸控式螢幕事件 * /
if (tInputEvent.iType != INPUT_TYPE_TOUCHSCREEN)
{
return -1;
}
*ptInputEvent = tInputEvent;
/* 處理資料 */
/* 確定觸點位於哪一個按鈕上 */
while (atLayout[i].strIconName)
{
if ((tInputEvent.iX >= atLayout[i].iTopLeftX) && (tInputEvent.iX <= atLayout[i].iBotRightX) \
(tInputEvent.iY >= atLayout[i].iTopLeftY) && (tInputEvent.iY <= atLayout[i].iBotRightY))
{
/* 找到了被點中的按鈕 */
return i;
}
else
{
i++;
}
}
/* 觸點沒有落在按鈕上 */
return -1;
}
獲得輸入事件後執行MainPageRun
static void MainPageRun(void)
{
int iIndex;
T_InputEvent tInputEvent;
int bPressed = 0;
int iIndexPressed = -1;
/* 1. 顯示頁面 */
ShowMainPage(g_atMainPageLayout);
/* 2. 建立Prepare執行緒 */
/* 3. 呼叫GetInputEvent獲得輸入事件,進而處理 */
while (1)
{
/* 獲得輸入事件 */
iIndex = MainPageGetInputEvent(g_atMainPageLayout, &tInputEvent);
if (tInputEvent.iPressure == 0)
{
/* 如果是鬆開 */
if (bPressed)
{
/* 曾經有按鈕被按下 */
ReleaseButton(&g_atMainPageLayout[iIndexPressed]);
bPressed = 0;
iIndexPressed = -1;
}
}
else
{
/* 按下狀態 */
if (iIndex != -1)
{
if (!bPressed)
{
/* 未曾按下按鈕 */
bPressed = 1;
iIndexPressed = iIndex;
PressButton(&g_atMainPageLayout[iIndexPressed]);
}
}
}
}
}