1. 程式人生 > >數碼相框(五)--頁面規劃、輸入功能

數碼相框(五)--頁面規劃、輸入功能

一、頁面規劃
先實現螢幕顯示三個圖示,從上到下分別為:瀏覽模式、連播模式、設定。

/* 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]);
                }
            }
        }       
    }
}