显示之bmp数据提取
显示之文件操作
显示之界面切换(main_page)
1、显示之bmp数据提取
typedef struct PixelDatas { int iWidth; int iHeight; int iBpp; int iLineBytes; int iTotalBytes; unsigned char *aucPixelDatas;
}T_PixelDatas, *PT_PixelDatas;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
typedef struct PicFileParser { char *name; int (*isSupport)(PT_FileMap ptFileMap); int (*GetPixelDatas)(PT_FileMap ptFileMap, PT_PixelDatas ptPixelDatas); int (*FreePixelDatas)(PT_PixelDatas ptPixelDatas);
struct PicFileParser *ptNext;
}T_PicFileParser, *PT_PicFileParser;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
1、文件头信息
typedef struct tagBITMAPFILEHEADER { /* bmfh */ unsigned short bfType; unsigned long bfSize; unsigned short bfReserved1; unsigned short bfReserved2; unsigned long bfOffBits;
} BITMAPFILEHEADER;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
2、位图信息
typedef struct tagBITMAPINFOHEADER { /* bmih */ unsigned long biSize; unsigned long biWidth; unsigned long biHeight; unsigned short biPlanes; unsigned short biBitCount; unsigned long biCompression; unsigned long biSizeImage; unsigned long biXPelsPerMeter; unsigned long biYPelsPerMeter; unsigned long biClrUsed; unsigned long biClrImportant;
} BITMAPINFOHEADER;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
3、RGB颜色阵列:
static int CovertOneLine(int iWidth, int iSrcBpp, int iDstBpp, unsigned char *pudSrcDatas, unsigned char *pudDstDatas)
{
unsigned int dwRed;
unsigned int dwGreen;
unsigned int dwBlue;
unsigned int dwColor;
unsigned short *pwDstDatas16bpp = (unsigned short *)pudDstDatas;
unsigned int *pwDstDatas32bpp = (unsigned int *)pudDstDatas;
int i;
int pos = 0;
if (iSrcBpp != 24)
{ return -1;
}
if (iDstBpp == 24)
{ memcpy(pudDstDatas, pudSrcDatas, iWidth*3);
}
else
{ for (i = 0; i < iWidth; i++) { dwBlue = pudSrcDatas[pos++]; dwGreen = pudSrcDatas[pos++]; dwRed = pudSrcDatas[pos++]; if (iDstBpp == 32) { dwColor = (dwRed << 16) | (dwGreen << 8) | dwBlue; *pwDstDatas32bpp = dwColor; pwDstDatas32bpp++; } else if (iDstBpp == 16) { /* 565 */ dwRed = dwRed >> 3; dwGreen = dwGreen >> 2; dwBlue = dwBlue >> 3; dwColor = (dwRed << 11) | (dwGreen << 5) | (dwBlue); *pwDstDatas16bpp = dwColor; pwDstDatas16bpp++; } }
}
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
加载文件
得到图片属性,以及RGB数据。
- 加载头文件
- 加载位图信息头
- 行对齐
- 加载图片数据
- 绘制
static int GetPixelDatasFrmBMP(PT_FileMap ptFileMap, PT_PixelDatas ptPixelDatas)
{ BITMAPFILEHEADER *ptBITMAPFILEHEADER; BITMAPINFOHEADER *ptBITMAPINFOHEADER; unsigned char *aFileHead; int iWidth; int iHeight; int iBMPBpp; int y; unsigned char *pucSrc; unsigned char *pucDest; int iLineWidthAlign; int iLineWidthReal; aFileHead = ptFileMap->pucFileMapMem; ptBITMAPFILEHEADER = (BITMAPFILEHEADER *)aFileHead; ptBITMAPINFOHEADER = (BITMAPINFOHEADER *)(aFileHead + sizeof(BITMAPFILEHEADER)); iWidth = ptBITMAPINFOHEADER->biWidth; iHeight = ptBITMAPINFOHEADER->biHeight; iBMPBpp = ptBITMAPINFOHEADER->biBitCount; if (iBMPBpp != 24) { DBG_PRINTF("iBMPBpp = %d\n", iBMPBpp); DBG_PRINTF("sizeof(BITMAPFILEHEADER) = %d\n", sizeof(BITMAPFILEHEADER)); return -1; } ptPixelDatas->iWidth = iWidth; ptPixelDatas->iHeight = iHeight; //ptPixelDatas->iBpp= iBpp; ptPixelDatas->iLineBytes= iWidth * ptPixelDatas->iBpp / 8;
ptPixelDatas->iTotalBytes = ptPixelDatas->iHeight * ptPixelDatas->iLineBytes; ptPixelDatas->aucPixelDatas = malloc(ptPixelDatas->iTotalBytes); if (NULL == ptPixelDatas->aucPixelDatas) { return -1; } iLineWidthReal = iWidth * iBMPBpp / 8; iLineWidthAlign = (iLineWidthReal + 3) & ~0x3; /* 向4取整 */ pucSrc = aFileHead + ptBITMAPFILEHEADER->bfOffBits; pucSrc = pucSrc + (iHeight - 1) * iLineWidthAlign; pucDest = ptPixelDatas->aucPixelDatas; for (y = 0; y < iHeight; y++) { //memcpy(pucDest, pucSrc, iLineWidthReal); CovertOneLine(iWidth, iBMPBpp, ptPixelDatas->iBpp, pucSrc, pucDest); pucSrc -= iLineWidthAlign; pucDest += ptPixelDatas->iLineBytes; } return 0; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
2、显示之文件操作
定义文件结构体:
typedef struct FileMap { char strFileName[256]; // int iFd; FILE * tFp; int iFileSize; unsigned char *pucFileMapMem;
}T_FileMap, *PT_FileMap;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
typedef enum { FILETYPE_DIR = 0, FILETYPE_FILE,
}E_FileType;
- 1
- 2
- 3
- 4
typedef struct DirContent { char strName[256]; E_FileType eFileType; }T_DirContent, *PT_DirContent;
- 1
- 2
- 3
- 4
文件信息获取:
int MapFile(PT_FileMap ptFileMap)
{ int iFd;
FILE *tFp; struct stat tStat; /* 打开文件 */ tFp = fopen(ptFileMap->strFileName, "r+"); if (tFp == NULL) { DBG_PRINTF("can't open %s\n", ptFileMap->strFileName); return -1; } ptFileMap->tFp = tFp;
iFd = fileno(tFp); 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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
void UnMapFile(PT_FileMap ptFileMap)
{ munmap(ptFileMap->pucFileMapMem, ptFileMap->iFileSize); fclose(ptFileMap->tFp);
}
- 1
- 2
- 3
- 4
- 5
文件类型判断
static int isDir(char *strFilePath, char *strFileName)
{
char strTmp[256];
struct stat tStat;
snprintf(strTmp, 256, "%s/%s", strFilePath, strFileName);
strTmp[255] = '\0';
if ((stat(strTmp, &tStat) == 0) && S_ISDIR(tStat.st_mode))
{
return 1;
}
else
{
return 0;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
static int isRegFile(char *strFilePath, char *strFileName)
{
char strTmp[256];
struct stat tStat;
snprintf(strTmp, 256, "%s/%s", strFilePath, strFileName);
strTmp[255] = '\0';
if ((stat(strTmp, &tStat) == 0) && S_ISREG(tStat.st_mode))
{
return 1;
}
else
{
return 0;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
把某目录下所含的顶层子目录、顶层目录下的文件都记录下来
int GetDirContents(char *strDirName, PT_DirContent **pptDirContents, int *piNumber)
{
PT_DirContent *aptDirContents; struct dirent **aptNameList; int iNumber; int i; int j; /* 扫描目录,结果按名字排序,存在aptNameList[0],aptNameList[1],... */ iNumber = scandir(strDirName, &aptNameList, 0, alphasort); if (iNumber < 0) { DBG_PRINTF("scandir error : %s!\n", strDirName); return -1; } /* 忽略".", ".."这两个目录 */ aptDirContents = malloc(sizeof(PT_DirContent) * (iNumber - 2)); if (NULL == aptDirContents) { DBG_PRINTF("malloc error!\n"); return -1; }
*pptDirContents = aptDirContents; for (i = 0; i < iNumber - 2; i++) { aptDirContents[i] = malloc(sizeof(T_DirContent)); if (NULL == aptDirContents) { DBG_PRINTF("malloc error!\n"); return -1; } } /* 先把目录挑出来存入aptDirContents */ for (i = 0, j = 0; i < iNumber; i++) { /* 忽略".",".."这两个目录 */ if ((0 == strcmp(aptNameList[i]->d_name, ".")) || (0 == strcmp(aptNameList[i]->d_name, ".."))) continue;
/* 并不是所有的文件系统都支持d_type, 所以不能直接判断d_type */ /* if (aptNameList[i]->d_type == DT_DIR) */
if (isDir(strDirName, aptNameList[i]->d_name)) { strncpy(aptDirContents[j]->strName, aptNameList[i]->d_name, 256); aptDirContents[j]->strName[255] = '\0'; aptDirContents[j]->eFileType= FILETYPE_DIR;
free(aptNameList[i]);
aptNameList[i] = NULL; j++; } } /* 再把常规文件挑出来存入aptDirContents */ for (i = 0; i < iNumber; i++) {
if (aptNameList[i] == NULL)
continue; /* 忽略".",".."这两个目录 */ if ((0 == strcmp(aptNameList[i]->d_name, ".")) || (0 == strcmp(aptNameList[i]->d_name, ".."))) continue;
/* 并不是所有的文件系统都支持d_type, 所以不能直接判断d_type */ /* if (aptNameList[i]->d_type == DT_REG) */
if (isRegFile(strDirName, aptNameList[i]->d_name)) { strncpy(aptDirContents[j]->strName, aptNameList[i]->d_name, 256); aptDirContents[j]->strName[255] = '\0'; aptDirContents[j]->eFileType= FILETYPE_FILE;
free(aptNameList[i]);
aptNameList[i] = NULL; j++; } } /* 释放aptDirContents中未使用的项 */ for (i = j; i < iNumber - 2; i++) { free(aptDirContents[i]); } /* 释放scandir函数分配的内存 */ for (i = 0; i < iNumber; i++) {
if (aptNameList[i])
{ free(aptNameList[i]);
} } free(aptNameList); *piNumber = j; return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
以深度优先的方式获得目录下的文件
* 即: 先获得顶层目录下的文件, 再进入一级子目录A
* 先获得一级子目录A下的文件, 再进入二级子目录AA, ...
* 处理完一级子目录A后, 再进入一级子目录B
*
* "连播模式"下调用该函数获得要显示的文件
* 有两种方法获得这些文件:
* 1. 事先只需要调用一次函数,把所有文件的名字保存到某个缓冲区中
* 2. 要使用文件时再调用函数,只保存当前要使用的文件的名字
* 第1种方法比较简单,但是当文件很多时有可能导致内存不足.
* 我们使用第2种方法:
* 假设某目录(包括所有子目录)下所有的文件都给它编一个号
* piStartNumberToRecord : 从第几个文件开始取出它们的名字
* piCurFileNumber : 本次函数执行时读到的第1个文件的编号
* piFileCountHaveGet: 已经得到了多少个文件的名字
* iFileCountTotal : 总共要取出多少个文件的名字
*
*/
int GetFilesIndir(char *strDirName, int *piStartNumberToRecord, int *piCurFileNumber, int *piFileCountHaveGet, int iFileCountTotal, char apstrFileNames[][256])
{
int iError;
PT_DirContent *aptDirContents; /* 数组:存有目录下"顶层子目录","文件"的名字 */
int iDirContentsNumber; /* aptDirContents数组有多少项 */
int i;
char strSubDirName[256];
/* 为避免访问的目录互相嵌套, 设置能访问的目录深度为10 */
#define MAX_DIR_DEEPNESS 10
static int iDirDeepness = 0;
if (iDirDeepness > MAX_DIR_DEEPNESS)
{
return -1;
}
iDirDeepness++;
iError = GetDirContents(strDirName, &aptDirContents, &iDirContentsNumber);
if (iError)
{
DBG_PRINTF("GetDirContents error!\n");
iDirDeepness--;
return -1;
}
/* 先记录文件 */
for (i = 0; i < iDirContentsNumber; i++)
{
if (aptDirContents[i]->eFileType == FILETYPE_FILE)
{
if (*piCurFileNumber >= *piStartNumberToRecord)
{
snprintf(apstrFileNames[*piFileCountHaveGet], 256, "%s/%s", strDirName, aptDirContents[i]->strName);
(*piFileCountHaveGet)++;
(*piCurFileNumber)++;
(*piStartNumberToRecord)++;
if (*piFileCountHaveGet >= iFileCountTotal)
{
FreeDirContents(aptDirContents, iDirContentsNumber);
iDirDeepness--;
return 0;
}
}
else
{
(*piCurFileNumber)++;
}
}
}
/* 递归处理目录 */
for (i = 0; i < iDirContentsNumber; i++)
{
if ((aptDirContents[i]->eFileType == FILETYPE_DIR) && isRegDir(strDirName, aptDirContents[i]->strName))
{
snprintf(strSubDirName, 256, "%s/%s", strDirName, aptDirContents[i]->strName);
GetFilesIndir(strSubDirName, piStartNumberToRecord, piCurFileNumber, piFileCountHaveGet, iFileCountTotal, apstrFileNames);
if (*piFileCountHaveGet >= iFileCountTotal)
{
FreeDirContents(aptDirContents, iDirContentsNumber);
iDirDeepness--;
return 0;
}
}
}
FreeDirContents(aptDirContents, iDirContentsNumber);
iDirDeepness--;
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
3、显示之页面切换(main_page)
main中调用PagesInit();
int PagesInit(void)
{ int iError; iError = MainPageInit(); iError |= SettingPageInit(); iError |= IntervalPageInit(); iError |= BrowsePageInit(); iError |= AutoPageInit(); iError |= ManualPageInit(); return iError;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
注册
int MainPageInit(void)
{ return RegisterPageAction(&g_tMainPageAction);
}
int SettingPageInit(void)
{ return RegisterPageAction(&g_tSettingPageAction);
}
int IntervalPageInit(void)
{ return RegisterPageAction(&g_tIntervalPageAction);
}
int BrowsePageInit(void)
{ return RegisterPageAction(&g_tBrowsePageAction);
}
int AutoPageInit(void)
{ return RegisterPageAction(&g_tAutoPageAction);
}
int ManualPageInit(void)
{ return RegisterPageAction(&g_tManualPageAction);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
链表操作
int RegisterPageAction(PT_PageAction ptPageAction)
{ PT_PageAction ptTmp; if (!g_ptPageActionHead) { g_ptPageActionHead = ptPageAction; ptPageAction->ptNext = NULL; } else { ptTmp = g_ptPageActionHead; while (ptTmp->ptNext) { ptTmp = ptTmp->ptNext; } ptTmp->ptNext = ptPageAction; ptPageAction->ptNext = NULL; } return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
链表结构
typedef struct PageAction { char *name; void (*Run)(PT_PageParams ptParentPageParams); int (*GetInputEvent)(PT_PageLayout ptPageLayout, PT_InputEvent ptInputEvent); int (*Prepare)(void); struct PageAction *ptNext;
}T_PageAction, *PT_PageAction;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
现在逐一分析
主界面运行
int MainPageInit(void)
{ return RegisterPageAction(&g_tMainPageAction);
}
- 1
- 2
- 3
- 4
static T_PageAction g_tMainPageAction = { .name = "main", .Run = MainPageRun, .GetInputEvent = MainPageGetInputEvent, //.Prepare = MainPagePrepare;
};
- 1
- 2
- 3
- 4
- 5
- 6
分析Run = MainPageRun 函数指针:
- 显示页面
- 创建Prepare线程
- 调用GetInputEvent获得输入事件,进而处理
注释:
- 将屏幕显示在主界面后
- 按下按钮 (tInputEvent.iPressure == 0)->g_tInputEvent.iPressure
- iIndex != -1;
- iIndexPressed = iIndex
PressButton(&g_atMainPageIconsLayout[iIndexPressed]);//位图取反
松开按钮 (tInputEvent.iPressure != 0)->g_tInputEvent.iPressure
- PressButton(&g_atMainPageIconsLayout[iIndexPressed]);//位图取反
- 按下和松开按键一样 则进入选择:switch
static void MainPageRun(PT_PageParams ptParentPageParams)
{
int iIndex;
T_InputEvent tInputEvent;
int bPressed = 0;
int iIndexPressed = -1;
T_PageParams tPageParams;
tPageParams.iPageID = ID("main");
/* 1. 显示页面 */
ShowMainPage(&g_tMainPageLayout);
/* 2. 创建Prepare线程 */
/* 3. 调用GetInputEvent获得输入事件,进而处理 */
while (1)
{ iIndex = MainPageGetInputEvent(&g_tMainPageLayout, &tInputEvent); if (tInputEvent.iPressure == 0) { /* 如果是松开 */ if (bPressed) { /* 曾经有按钮被按下 */ ReleaseButton(&g_atMainPageIconsLayout[iIndexPressed]); bPressed = 0; if (iIndexPressed == iIndex) /* 按下和松开都是同一个按钮 */ { switch (iIndexPressed) { case 0: /* 浏览按钮 */ { /* tPageParams.strCurPictureFile[0]为'\0'时, 使用设置页面里选定的目录来显示 */ tPageParams.strCurPictureFile[0] = '\0'; Page("manual")->Run(&tPageParams); /* 从设置页面返回后显示当首的主页面 */ ShowMainPage(&g_tMainPageLayout); break; } case 1: /* 连播按钮 */ { Page("auto")->Run(&tPageParams); /* 从设置页面返回后显示当首的主页面 */ ShowMainPage(&g_tMainPageLayout); break; } case 2: /* 设置按钮 */ { Page("setting")->Run(&tPageParams); /* 从设置页面返回后显示当首的主页面 */ ShowMainPage(&g_tMainPageLayout); break; } default: { break; } } } iIndexPressed = -1; } } else { /* 按下状态 */ if (iIndex != -1) { if (!bPressed) { /* 未曾按下按钮 */ bPressed = 1; iIndexPressed = iIndex; PressButton(&g_atMainPageIconsLayout[iIndexPressed]); } } } }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
主菜单:
- manual 浏览
- auto 连播
- setting 设置
1、浏览模式
注册
int ManualPageInit(void)
{ return RegisterPageAction(&g_tManualPageAction);
}
- 1
- 2
- 3
- 4
static T_PageAction g_tManualPageAction = { .name = "manual", .Run = ManualPageRun,
};
- 1
- 2
- 3
- 4
/* manual页面的Run参数含义:
* 如果它的父页面是主页面 - 显示browse页面,
* 否则 - 显示图片
*/
static void ManualPageRun(PT_PageParams ptParentPageParams)
{ T_InputEvent tInputEvent; T_InputEvent tPreInputEvent; int bButtonPressed = 0; int bPicSlipping = 0; int iIndexPressed = -1;
int iIndex;
T_PageParams tPageParams;
int iError;
char strDirName[256];
char strFileName[256];
char strFullPathName[256];
PT_DirContent *aptDirContents;
int iDirContentsNumber;
int iPicFileIndex;
char *pcTmp;
PT_VideoMem ptDevVideoMem;
int iZoomedWidth;
int iZoomedHeight;
PT_PixelDatas ptZoomedPicPixelDatas = &g_tZoomedPicPixelDatas;
/* 这两句只是避免编译警告 */
tPreInputEvent.iX = 0;
tPreInputEvent.iY = 0;
tPageParams.iPageID = ID("manual");
if (ptParentPageParams->iPageID == ID("main"))
{
/* 如果它的父页面是主页面 - 显示browse页面*/
Page("browse")->Run(ptParentPageParams);
}
else
{
ptDevVideoMem = GetDevVideoMem();
strcpy(strFullPathName, ptParentPageParams->strCurPictureFile);
/* 显示菜单和图片文件 */
ShowManualPage(&g_tManualPageMenuIconsLayout, strFullPathName);
/* 取出目录名 */
strcpy(strDirName, ptParentPageParams->strCurPictureFile);
pcTmp = strrchr(strDirName, '/');
*pcTmp = '\0';
/* 取出文件名 */
strcpy(strFileName, pcTmp+1);
/* 获得当前目录下所有目录和文件的名字 */
iError = GetDirContents(strDirName, &aptDirContents, &iDirContentsNumber);
/* 确定当前显示的是哪一个文件 */
for (iPicFileIndex = 0; iPicFileIndex < iDirContentsNumber; iPicFileIndex++)
{
if (0 == strcmp(strFileName, aptDirContents[iPicFileIndex]->strName))
{
break;
}
}
while (1)
{
/* 先确定是否触摸了菜单图标 */
iIndex = ManualPageGetInputEvent(&g_tManualPageMenuIconsLayout, &tInputEvent); /* 如果是松开 */
if (tInputEvent.iPressure == 0)
{ bPicSlipping = 0;
if (bButtonPressed)
{
/* 曾经有按钮被按下 */
ReleaseButton(&g_atManualMenuIconsLayout[iIndexPressed]);
bButtonPressed = 0;
if (iIndexPressed == iIndex) /* 按下和松开都是同一个按钮 */
{
switch (iIndexPressed)
{
case 0: /* 返回按钮 */
{
return;
break;
}
case 1: /* 缩小按钮 */
{
/* 获得缩小后的数据 */
iZoomedWidth = (float)g_tZoomedPicPixelDatas.iWidth * ZOOM_RATIO;
iZoomedHeight = (float)g_tZoomedPicPixelDatas.iHeight * ZOOM_RATIO;
ptZoomedPicPixelDatas = GetZoomedPicPixelDatas(&g_tOriginPicPixelDatas, iZoomedWidth, iZoomedHeight);
/* 重新计算中心点 */
g_iXofZoomedPicShowInCenter = (float)g_iXofZoomedPicShowInCenter * ZOOM_RATIO;
g_iYofZoomedPicShowInCenter = (float)g_iYofZoomedPicShowInCenter * ZOOM_RATIO;
/* 显示新数据 */
ShowZoomedPictureInLayout(ptZoomedPicPixelDatas, ptDevVideoMem);
break;
}
case 2: /* 放大按钮 */
{
/* 获得放大后的数据 */
iZoomedWidth = (float)g_tZoomedPicPixelDatas.iWidth / ZOOM_RATIO;
iZoomedHeight = (float)g_tZoomedPicPixelDatas.iHeight / ZOOM_RATIO;
ptZoomedPicPixelDatas = GetZoomedPicPixelDatas(&g_tOriginPicPixelDatas, iZoomedWidth, iZoomedHeight);
/* 重新计算中心点 */
g_iXofZoomedPicShowInCenter = (float)g_iXofZoomedPicShowInCenter / ZOOM_RATIO;
g_iYofZoomedPicShowInCenter = (float)g_iYofZoomedPicShowInCenter / ZOOM_RATIO;
/* 显示新数据 */
ShowZoomedPictureInLayout(ptZoomedPicPixelDatas, ptDevVideoMem);
break;
}
case 3: /* "上一张"按钮 */
{
while (iPicFileIndex > 0)
{
iPicFileIndex--;
snprintf(strFullPathName, 256, "%s/%s", strDirName, aptDirContents[iPicFileIndex]->strName);
strFullPathName[255] = '\0';
if (isPictureFileSupported(strFullPathName))
{
ShowPictureInManualPage(ptDevVideoMem, strFullPathName);
break;
}
}
break;
}
case 4: /* "下一张"按钮 */
{
while (iPicFileIndex < iDirContentsNumber - 1)
{
iPicFileIndex++;
snprintf(strFullPathName, 256, "%s/%s", strDirName, aptDirContents[iPicFileIndex]->strName);
strFullPathName[255] = '\0';
if (isPictureFileSupported(strFullPathName))
{
ShowPictureInManualPage(ptDevVideoMem, strFullPathName);
break;
}
}
break;
}
case 5: /* "连播"按钮 */
{
/* Manual页面的触发有两个方法: 在主页面按"浏览模式"进入"浏览页面"->"选中某个文件", 在"连播页面"里点击正在显示的图片
* 如果是后者, 直接return就可以了:因为return后是返回到"连播页面"的, 它会继续"连播"
*/
if (ptParentPageParams->iPageID == ID("browse")) /* 触发自"浏览页面" */
{
strcpy(tPageParams.strCurPictureFile, strFullPathName);
Page("auto")->Run(&tPageParams); /* auto页面返回前,会把它正在显示的文件存在tPageParams.strCurPictureFile */
ShowManualPage(&g_tManualPageMenuIconsLayout, tPageParams.strCurPictureFile);
}
else /* 当前manual页面的父页面是auto页面, 直接返回即可 */
{
return;
}
break;
}
default:
{
break;
}
}
}
iIndexPressed = -1;
}
}
else /* 按下状态 */
{
/* 点击的是菜单按钮 */
if (iIndex != -1)
{
if (!bButtonPressed)
{
/* 未曾按下按钮 */
bButtonPressed = 1;
iIndexPressed = iIndex;
PressButton(&g_atManualMenuIconsLayout[iIndexPressed]);
}
} else /* 点击的是图片显示区域, 滑动图片 */ { /* 如果没有按钮被按下 */ if (!bButtonPressed && !bPicSlipping) { bPicSlipping = 1;
tPreInputEvent = tInputEvent; } if (bPicSlipping) {
/* 如果触点滑动距离大于规定值, 则挪动图片 */
if (DistanceBetweenTwoPoint(&tInputEvent, &tPreInputEvent) > SLIP_MIN_DISTANCE)
{
/* 重新计算中心点 */
g_iXofZoomedPicShowInCenter -= (tInputEvent.iX - tPreInputEvent.iX);
g_iYofZoomedPicShowInCenter -= (tInputEvent.iY - tPreInputEvent.iY);
/* 显示新数据 */
ShowZoomedPictureInLayout(ptZoomedPicPixelDatas, ptDevVideoMem);
/* 记录滑动点 */
tPreInputEvent = tInputEvent;
} } }
} }
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
连播
- /* 以深度优先的方式获得目录下的文件
-
- 即: 先获得顶层目录下的文件, 再进入一级子目录A
-
- 先获得一级子目录A下的文件, 再进入二级子目录AA, …
-
- 处理完一级子目录A后, 再进入一级子目录B
- *
-
- ”连播模式”下调用该函数获得要显示的文件
-
- 有两种方法获得这些文件:
-
-
- 事先只需要调用一次函数,把所有文件的名字保存到某个缓冲区中
-
-
-
- 要使用文件时再调用函数,只保存当前要使用的文件的名字
-
-
- 第1种方法比较简单,但是当文件很多时有可能导致内存不足.
-
- 我们使用第2种方法:
-
- 假设某目录(包括所有子目录)下所有的文件都给它编一个号
-
- g_iStartNumberToRecord : 从第几个文件开始取出它们的名字
-
- g_iCurFileNumber : 本次函数执行时读到的第1个文件的编号
-
- g_iFileCountHaveGet : 已经得到了多少个文件的名字
-
- g_iFileCountTotal : 每一次总共要取出多少个文件的名字
-
- g_iNextProcessFileIndex: 在g_apstrFileNames数组中即将要显示在LCD上的文件
- *
- */
static T_PageAction g_tAutoPageAction = { .name = "auto", .Run = AutoPageRun,
};
- 1
- 2
- 3
- 4
static void AutoPageRun(PT_PageParams ptParentPageParams)
{ T_InputEvent tInputEvent; int iRet;
char *pcTmp;
g_bAutoPlayThreadShouldExit = 0;
/* 获得配置值: 显示哪一个目录, 显示图片的间隔 */
GetPageCfg(&g_tPageCfg);
/* 如果ptParentPageParams.strCurPictureFile[0] != '\0'
* 自动播放这个目录下的图片: ptParentPageParams.strCurPictureFile
*/
if (ptParentPageParams->strCurPictureFile[0] != '\0')
{
strcpy(g_tPageCfg.strSeletedDir, ptParentPageParams->strCurPictureFile);
pcTmp = strrchr(g_tPageCfg.strSeletedDir, '/');
*pcTmp = '\0';
}
/* 1. 启动一个线程来连续显示图片 */
pthread_create(&g_tAutoPlayThreadID, NULL, AutoPlayThreadFunction, NULL);
/* 2. 当前线程等待触摸屏输入, 先做简单点: 如果点击了触摸屏, 让线程退出 */
while (1)
{
iRet = GetInputEvent(&tInputEvent);
if (0 == iRet)
{
pthread_mutex_lock(&g_tAutoPlayThreadMutex);
g_bAutoPlayThreadShouldExit = 1; /* AutoPlayThreadFunction线程检测到这个变量为1后会退出 */
pthread_mutex_unlock(&g_tAutoPlayThreadMutex);
pthread_join(g_tAutoPlayThreadID, NULL); /* 等待子线程退出 */
return;
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
设置
步骤1:显示界面 :
首先看出入参数结构
ShowMainPage(&g_tMainPageLayout);
static T_PageLayout g_tMainPageLayout = {
.iMaxTotalBytes = 0,
.atLayout = g_atMainPageIconsLayout,
};
- 1
- 2
- 3
- 4
g_atMainPageIconsLayout结构定义如下:
static T_Layout g_atMainPageIconsLayout[] = { {0, 0, 0, 0, "browse_mode.bmp"}, {0, 0, 0, 0, "continue_mod.bmp"}, {0, 0, 0, 0, "setting.bmp"}, {0, 0, 0, 0, NULL},
};
- 1
- 2
- 3
- 4
- 5
- 6
定义结构体如下:
typedef struct PageLayout { int iTopLeftX;/* 这个区域的左上角、右下角坐标 */ int iTopLeftY; int iBotRightX; int iBotRightY; int iBpp; int iMaxTotalBytes; PT_Layout atLayout; /* 这个区域分成好几个小区域 */
}T_PageLayout, *PT_PageLayout;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
PT_Layout 结构:
typedef struct Layout { int iTopLeftX; int iTopLeftY; int iBotRightX; int iBotRightY; char *strIconName;
}T_Layout, *PT_Layout;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
看一下showMainpage函数:
- 获得显存
- 描画数据
- 刷到设备上去
- 解放显存
static void ShowMainPage(PT_PageLayout ptPageLayout)
{
PT_VideoMem ptVideoMem;
int iError;
PT_Layout atLayout = ptPageLayout->atLayout;
/* 1. 获得显存 */
ptVideoMem = GetVideoMem(ID("main"), 1);
if (ptVideoMem == NULL)
{ DBG_PRINTF("can't get video mem for main page!\n"); return;
}
/* 2. 描画数据 */
/* 如果还没有计算过各图标的坐标 */
if (atLayout[0].iTopLeftX == 0)
{ CalcMainPageLayout(ptPageLayout);
}
iError = GeneratePage(ptPageLayout, ptVideoMem); /* 3. 刷到设备上去 */
FlushVideoMemToDev(ptVideoMem);
/* 4. 解放显存 */
PutVideoMem(ptVideoMem);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 获得显存
- 描画数据
- 刷到设备上去
- 解放显存
待添加:
步骤三:调用GetInputEvent获得输入事件,进而处理
iIndex = MainPageGetInputEvent(&g_tMainPageLayout, &tInputEvent);
static int MainPageGetInputEvent(PT_PageLayout ptPageLayout, PT_InputEvent ptInputEvent)
{ return GenericGetInputEvent(ptPageLayout, ptInputEvent);
}
- 1
- 2
- 3
- 4
传入参数分析:
typedef struct PageLayout { int iTopLeftX;/* 这个区域的左上角、右下角坐标 */ int iTopLeftY; int iBotRightX; int iBotRightY; int iBpp; int iMaxTotalBytes; PT_Layout atLayout; /* 这个区域分成好几个小区域 */
}T_PageLayout, *PT_PageLayout;
typedef struct InputEvent { struct timeval tTime; int iType; /* stdin, touchsceen */ int iX; int iY; int iKey; int iPressure;
}T_InputEvent, *PT_InputEvent;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
函数:
int GenericGetInputEvent(PT_PageLayout ptPageLayout, PT_InputEvent ptInputEvent)
{ T_InputEvent tInputEvent; int iRet; int i = 0; PT_Layout atLayout = ptPageLayout->atLayout; /* 获得原始的触摸屏数据 * 它是调用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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
int GetInputEvent(PT_InputEvent ptInputEvent)
{ /* 休眠 */ pthread_mutex_lock(&g_tMutex); pthread_cond_wait(&g_tConVar, &g_tMutex); /* 被唤醒后,返回数据 */ *ptInputEvent = g_tInputEvent; pthread_mutex_unlock(&g_tMutex); return 0; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
问题:g_tinputevent这个全局变量在哪里改变的。
触摸初始化:
InputInit();
AllInputDevicesInit();
- 1
- 2
InputInit();
int InputInit(void)
{ int iError = 0; // iError = StdinInit(); iError |= TouchScreenInit(); return iError;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
int TouchScreenInit(void)
{ return RegisterInputOpr(&g_tTouchScreenOpr);
}
- 1
- 2
- 3
- 4
static T_InputOpr g_tTouchScreenOpr = { .name = "touchscreen", .DeviceInit= TouchScreenDevInit, .DeviceExit= TouchScreenDevExit, .GetInputEvent = TouchScreenGetInputEvent,
};
- 1
- 2
- 3
- 4
- 5
- 6
TouchScreenDevInit
/* 注意: 由于要用到LCD的分辨率, 此函数要在SelectAndInitDisplay之后调用 */
static int TouchScreenDevInit(void)
{ char *pcTSName = NULL; int iBpp; if ((pcTSName = getenv("TSLIB_TSDEVICE")) != NULL ) { g_tTSDev = ts_open(pcTSName, 0); /* 以阻塞方式打开 */ } else { g_tTSDev = ts_open("/dev/event0", 1); } if (!g_tTSDev) { DBG_PRINTF(APP_ERR"ts_open error!\n"); return -1; } if (ts_config(g_tTSDev)) { DBG_PRINTF("ts_config error!\n"); return -1; } if (GetDispResolution(&giXres, &giYres, &iBpp)) { return -1; } return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
TouchScreenGetInputEvent
static int TouchScreenGetInputEvent(PT_InputEvent ptInputEvent)
{ struct ts_sample tSamp; int iRet; while (1) { 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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
AllInputDevicesInit();
int AllInputDevicesInit(void)
{ PT_InputOpr ptTmp = g_ptInputOprHead; int iError = -1; while (ptTmp) { if (0 == ptTmp->DeviceInit()) { /* 创建子线程 */ pthread_create(&ptTmp->tTreadID, NULL, InputEventThreadFunction, ptTmp->GetInputEvent); iError = 0; } ptTmp = ptTmp->ptNext; } return iError;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
InputEventThreadFunction线程
下面这个函数就是获得g_tInputEvent的数值
static void *InputEventThreadFunction(void *pVoid)
{ T_InputEvent tInputEvent; /* 定义函数指针 */ int (*GetInputEvent)(PT_InputEvent ptInputEvent); GetInputEvent = (int (*)(PT_InputEvent))pVoid; while (1) { if(0 == GetInputEvent(&tInputEvent)) { /* 唤醒主线程, 把tInputEvent的值赋给一个全局变量 */ /* 访问临界资源前,先获得互斥量 */ pthread_mutex_lock(&g_tMutex); g_tInputEvent = tInputEvent; /* 唤醒主线程 */ pthread_cond_signal(&g_tConVar); /* 释放互斥量 */ pthread_mutex_unlock(&g_tMutex); } } return NULL;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
待完善
文章来源: xuesong.blog.csdn.net,作者:内核笔记,版权归原作者所有,如需转载,请联系作者。
原文链接:xuesong.blog.csdn.net/article/details/78242707