PageRenderTime 51ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/src/Modules/Emotion/EmotionButton.cpp

https://gitlab.com/yoage/TTWinClient
C++ | 538 lines | 402 code | 81 blank | 55 comment | 92 complexity | 07549882e7d3de6daf5c241acdb104ee MD5 | raw file
Possible License(s): LGPL-3.0
  1. #include "stdafx.h"
  2. #include "resource.h"
  3. #include "EmotionButton.h"
  4. #include "utility/utilStrCodeAPI.h"
  5. #include "Modules/IEmotionModule.h"
  6. #include "TTLogic/ITcpClientModule.h"
  7. #include <Windows.h>
  8. CEmotionButton::CEmotionButton(void)
  9. {
  10. m_CxImages=NULL;
  11. //窗口大小
  12. QQFACEDLG_WIDTH = 446;
  13. QQFACEDLG_HEIGHT = 239;
  14. //网格左上角坐标
  15. CELLS_LEFT = 6;
  16. CELLS_TOP =3;
  17. CELLS_RIGHT = 441; //(6 + 29*15)
  18. CELLS_BOTTOM = 259; //(28 + 29*8)
  19. CELLSIZE = 29; //每个网格= 29*30,(图片尺寸是24*24)
  20. CELLCOUNT_LINE = 15; //每行
  21. CELLCOUNT_COLUMN = 8; //每列
  22. CELLCOUNT_PAGE = 120; //每页120个表情
  23. rcLeft.left = CELLS_LEFT+1;
  24. rcLeft.top = CELLS_TOP+1;
  25. rcLeft.right = rcLeft.left + (CELLSIZE*3-1);
  26. rcLeft.bottom = rcLeft.top + (CELLSIZE*3-1);
  27. rcRight.left = CELLS_LEFT+(CELLSIZE*12)+1;
  28. rcRight.top = CELLS_TOP+1;
  29. rcRight.right = rcRight.left + (CELLSIZE*3-1);
  30. rcRight.bottom = rcRight.top + (CELLSIZE*3-1);
  31. //开始时隐藏动画窗口
  32. pvstatus = _PVStatus::Hide;
  33. TCHAR facepath[MAX_PATH];
  34. GetFaceFolderPath(facepath, _T("..\\data\\Emotion\\Face"));
  35. //加载所有表情!
  36. m_ImageCount = LoadImages(facepath);
  37. //表情页数量
  38. m_PageCount = (m_ImageCount + CELLCOUNT_PAGE - 1) / CELLCOUNT_PAGE;
  39. curPage=0;
  40. //创建内存DC
  41. HDC hdc = GetDC(NULL);
  42. m_hMemDC = CreateCompatibleDC(hdc);
  43. m_hMemDCBkGnd = CreateCompatibleDC(hdc);
  44. m_hMemBitmap = CreateCompatibleBitmap(hdc, QQFACEDLG_WIDTH, QQFACEDLG_HEIGHT);
  45. m_hMemBitmapBkGnd = CreateCompatibleBitmap(hdc, QQFACEDLG_WIDTH, QQFACEDLG_HEIGHT);
  46. ReleaseDC(NULL, hdc);
  47. SelectObject(m_hMemDC, m_hMemBitmap);
  48. SelectObject(m_hMemDCBkGnd, m_hMemBitmapBkGnd);
  49. TCHAR szPageInfo[16];
  50. //设置页信息
  51. wsprintf(szPageInfo, _T("%d/%d"), curPage+1, m_PageCount);
  52. SwitchPage(curPage);
  53. }
  54. CEmotionButton::~CEmotionButton(void)
  55. {
  56. FreeImages();
  57. }
  58. int CEmotionButton::GetPageCount()
  59. {
  60. return m_PageCount;
  61. }
  62. //释放图片资源
  63. void CEmotionButton::FreeImages()
  64. {
  65. if(m_CxImages != NULL)
  66. {
  67. delete[] m_CxImages;
  68. m_CxImages = NULL;
  69. }
  70. m_ImageCount = 0;
  71. }
  72. //获取表情文件夹完整路径!
  73. void CEmotionButton::GetFaceFolderPath(TCHAR* path, TCHAR* folderName)
  74. {
  75. TCHAR *pChar;
  76. TCHAR temp[MAX_PATH];
  77. GetModuleFileName(NULL, temp, MAX_PATH);
  78. //查找倒数第一个反斜杠位置
  79. pChar=_tcsrchr(temp,'\\');
  80. if(pChar != NULL)
  81. *pChar = 0;//在反斜杠处截断字符串
  82. wsprintf(path, _T("%s\\%s"), temp, folderName);
  83. }
  84. void CEmotionButton::DoPaint(HDC hDC, const RECT& rcPaint)
  85. {
  86. ::BitBlt(hDC, 0, 0, QQFACEDLG_WIDTH, QQFACEDLG_HEIGHT, m_hMemDC, 0, 0, SRCCOPY);
  87. }
  88. int CEmotionButton::GetCurrentPage()
  89. {
  90. return curPage;
  91. }
  92. void CEmotionButton::SetPage(int page)
  93. {
  94. curPage = page;
  95. SwitchPage(curPage);
  96. }
  97. void CEmotionButton::DoEvent(TEventUI& event)
  98. {
  99. switch( event.Type)
  100. {
  101. case UIEVENT_MOUSEMOVE:
  102. {
  103. RECT rc1, rc2, invalidRect;
  104. int lastCol = -1, curCol = -1;
  105. unsigned char changetype = _PosChangeType::NoChange; //预览矩形是否需要改变
  106. POINT pt = event.ptMouse;
  107. int tmpSel = GetCellIndex(pt.x, pt.y);
  108. //是否超出了图片数量
  109. if((tmpSel + curPage * CELLCOUNT_PAGE) >= m_ImageCount)
  110. tmpSel = -1;
  111. if(tmpSel != curSel)
  112. {
  113. //两个cell 索引行进
  114. lastSel = curSel;
  115. curSel = tmpSel;
  116. curFrame = 0;
  117. //预览矩形需要移动吗?
  118. lastCol = (lastSel % 15);
  119. curCol = (curSel % 15); //每行15个
  120. GetBlueRect(lastSel, &rc1);
  121. GetBlueRect(curSel, &rc2);
  122. UnionRect(&invalidRect, &rc1, &rc2);
  123. invalidRect.right++;
  124. invalidRect.bottom++;
  125. //判断缩略矩形是否发生位置改变?
  126. if(pvstatus == _PVStatus::Hide)
  127. {
  128. if(curSel >= 0)
  129. {
  130. if((curSel%15) > 7)
  131. {
  132. pvstatus = _PVStatus::Left;
  133. changetype = _PosChangeType::HideToLeft;
  134. }
  135. else
  136. {
  137. pvstatus = _PVStatus::Right;
  138. changetype = _PosChangeType::HideToRight;
  139. }
  140. }
  141. }
  142. else if(pvstatus == _PVStatus::Left)
  143. {
  144. if(curSel < 0)
  145. {
  146. pvstatus = _PVStatus::Hide;
  147. changetype = _PosChangeType::LeftToHide;
  148. }
  149. else if(curCol < 4 || (curCol == 4 && lastCol == 4))
  150. {
  151. pvstatus = _PVStatus::Right;
  152. changetype = _PosChangeType::LeftToRight;
  153. }
  154. }
  155. else if(pvstatus == _PVStatus::Right)
  156. {
  157. if(curSel < 0)
  158. {
  159. pvstatus = _PVStatus::Hide;
  160. changetype = _PosChangeType::RightToHide;
  161. }
  162. else if(curCol > 10 || (curCol == 10 && lastCol == 10))
  163. {
  164. pvstatus = _PVStatus::Left;
  165. changetype = _PosChangeType::RightToLeft;
  166. }
  167. }
  168. //刷新蓝色矩形框
  169. UpdateSelectedFace(curPage, curSel, curFrame, pvstatus);
  170. this->Invalidate();
  171. if(changetype == _PosChangeType::NoChange)
  172. {
  173. //刷新预览图片
  174. if(pvstatus == _PVStatus::Left)
  175. {
  176. this->Invalidate();
  177. //InvalidateRect(hDlg, &rcLeft, FALSE);
  178. }
  179. else if(pvstatus == _PVStatus::Right)
  180. {
  181. this->Invalidate();
  182. //InvalidateRect(hDlg, &rcRight, FALSE);
  183. }
  184. }
  185. else
  186. {
  187. CopyRect(&rc1, &rcLeft);
  188. CopyRect(&rc2, &rcRight);
  189. rc1.right++;
  190. rc1.bottom++;
  191. rc2.right++;
  192. rc2.bottom++;
  193. //擦除原位置的缩略图
  194. switch(changetype & 0xf0)
  195. {
  196. case 0x00:
  197. break;
  198. case 0x10:
  199. this->Invalidate();
  200. //InvalidateRect(hDlg, &rc1, FALSE);
  201. break;
  202. case 0x20:
  203. this->Invalidate();
  204. //InvalidateRect(hDlg, &rc2, FALSE);
  205. break;
  206. }
  207. //显示新位置上的缩略图
  208. switch(changetype & 0x0f)
  209. {
  210. case 0x00:
  211. pvstatus = _PVStatus::Hide;
  212. break;
  213. case 0x01:
  214. this->Invalidate();
  215. //InvalidateRect(hDlg, &rc1, FALSE);
  216. break;
  217. case 0x02:
  218. this->Invalidate();
  219. //InvalidateRect(hDlg, &rc2, FALSE);
  220. break;
  221. }
  222. }
  223. //安装定时器(显示动画)
  224. if(curSel >= 0)
  225. {
  226. UINT frameDelay = 200;
  227. CxImage* pImg = GetSelectedImage(curPage, curSel);
  228. CxImage* pFrame = pImg->GetFrame(curFrame);
  229. //QQ表情的帧延时通常是10毫秒,显示速度过快,因此增大到50毫秒
  230. if(pFrame != NULL) frameDelay = max(frameDelay, pFrame->GetFrameDelay());
  231. frameCount = pImg->GetNumFrames();
  232. this->m_pManager->SetTimer(this, TIMER_SHOWGIF, frameDelay);
  233. }
  234. else
  235. {
  236. this->m_pManager->KillTimer(this, TIMER_SHOWGIF);
  237. }
  238. }
  239. //使系统通知我们 WM_MOUSELEAVE ;
  240. TrackMouseEvent(&m_tme); //注意版本需求:_WIN32_WINNT 0x0510
  241. }
  242. break;
  243. case UIEVENT_MOUSELEAVE:
  244. {
  245. if(curSel >= 0)
  246. {
  247. RECT rc;
  248. GetBlueRect(curSel, &rc);
  249. lastSel = curSel;
  250. curSel = -1;
  251. curFrame = 0;
  252. pvstatus = _PVStatus::Hide;
  253. UpdateSelectedFace(curPage, curSel, curFrame, pvstatus);
  254. this->Invalidate();
  255. //InvalidateRect(hDlg, &rc, FALSE);
  256. }
  257. }
  258. break;
  259. case UIEVENT_TIMER:
  260. {
  261. this->m_pManager->KillTimer(this, TIMER_SHOWGIF);
  262. if(curSel >= 0 && frameCount > 1)
  263. {
  264. CxImage *pImg = GetSelectedImage(curPage, curSel);
  265. CxImage *pFrame = NULL;
  266. UINT frameDelay = 200;
  267. LPRECT lpRect = (pvstatus == _PVStatus::Left)? &rcLeft:&rcRight;
  268. //移动到下一帧!
  269. curFrame = (curFrame + 1) % frameCount;
  270. //QQ表情的帧延时通常是10毫秒,显示速度过快,因此增大到100毫秒
  271. pFrame = pImg->GetFrame(curFrame);
  272. if(pFrame) frameDelay = max(frameDelay, pFrame->GetFrameDelay());
  273. UpdateSelectedFace(curPage, curSel, curFrame, pvstatus);
  274. this->Invalidate();
  275. //InvalidateRect(hDlg, lpRect, FALSE);
  276. //下一帧的定时时间
  277. this->m_pManager->SetTimer(this, TIMER_SHOWGIF, frameDelay);
  278. }
  279. }
  280. break;
  281. case UIEVENT_BUTTONUP:
  282. {
  283. POINT pt = event.ptMouse;
  284. int curSel = GetCellIndex(pt.x, pt.y);
  285. int index = curPage * CELLCOUNT_PAGE + curSel; //从页内相对索引计算出绝对索引。
  286. if (index > -1 && index < (int)m_mapImagePath.size())
  287. {
  288. CString strPath = m_mapImagePath[index];
  289. module::EmotionParam* pEmotionParam = new module::EmotionParam();
  290. pEmotionParam->sid = module::getEmotionModule()->getCurEmotionWndSessionId();
  291. pEmotionParam->strPath = strPath;
  292. logic::GetLogic()->asynNotifyObserver(module::KEY_EMOTION_SELECTED, std::shared_ptr<void>(pEmotionParam));
  293. ::ShowWindow(m_pManager->GetPaintWindow(), SW_HIDE);
  294. }
  295. }
  296. break;
  297. }
  298. }
  299. void CEmotionButton::Notify(TNotifyUI& msg)
  300. {
  301. if (0 == _tcsicmp(msg.sType, DUI_MSGTYPE_TIMER))
  302. {
  303. }
  304. }
  305. //切换当前页时需要进行的更新
  306. void CEmotionButton::SwitchPage(int curPage)
  307. {
  308. if(NULL == m_CxImages)
  309. return ;
  310. int index, count, left, top, width, height;
  311. RECT rc;
  312. this->Invalidate();
  313. //先画背景
  314. TCHAR szBKImg[MAX_PATH] = {0};
  315. _sntprintf(szBKImg, MAX_PATH - 1, _T("file='bg.png' corner='4,4,2,2' fade='100'"));
  316. CBitmap bmp;
  317. CString strBitmapPath = CPaintManagerUI::GetInstancePath() + _T("..\\data\\Emotion\\IDB_BKGND.bmp");
  318. HBITMAP hBlankBkGnd;
  319. hBlankBkGnd = (HBITMAP)LoadImage(AfxGetInstanceHandle(), strBitmapPath, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
  320. bmp.DeleteObject();
  321. HDC hTempDC = CreateCompatibleDC(m_hMemDCBkGnd);
  322. SelectObject(hTempDC, hBlankBkGnd);
  323. BitBlt(m_hMemDCBkGnd, 0, 0, QQFACEDLG_WIDTH, QQFACEDLG_HEIGHT, hTempDC, 0, 0, SRCCOPY);
  324. DeleteDC(hTempDC);
  325. DeleteObject(hBlankBkGnd);
  326. //绘制当前页面的所有表情
  327. //绘制本页内所有图片
  328. for(index = (curPage * CELLCOUNT_PAGE), count = 0; (index< m_ImageCount && count < CELLCOUNT_PAGE); index++, count++)
  329. {
  330. //居中绘制
  331. GetBlueRect(count, &rc);
  332. left = max(rc.left, (rc.left + rc.right - m_CxImages[index].GetWidth())/2);
  333. top = max(rc.top, (rc.top + rc.bottom - m_CxImages[index].GetHeight()) / 2);
  334. width = min(m_CxImages[index].GetWidth(), CELLSIZE);
  335. height = min(m_CxImages[index].GetHeight(), CELLSIZE);
  336. m_CxImages[index].GetFrame(0)->Draw(m_hMemDCBkGnd, left, top, width, height);
  337. }
  338. //传送到内存位图
  339. BitBlt(m_hMemDC, 0, 0, QQFACEDLG_WIDTH, QQFACEDLG_HEIGHT, m_hMemDCBkGnd, 0, 0, SRCCOPY);
  340. }
  341. //鼠标在窗口上移动时需要进行的更新
  342. void CEmotionButton::UpdateSelectedFace(int curPage, int curSel, int curFrame, int pvstatus)
  343. {
  344. HGDIOBJ hOldBrush = NULL, hOldPen = NULL, hTempPen, hTempBrush;
  345. HPEN hPen1 = NULL;
  346. HPEN hPen2 = NULL;
  347. LPRECT lpRect = NULL;
  348. RECT rc;
  349. int index;
  350. //贴背景
  351. BitBlt(m_hMemDC, 0, 0, QQFACEDLG_WIDTH, QQFACEDLG_HEIGHT, m_hMemDCBkGnd, 0, 0, SRCCOPY);
  352. //绘制蓝色选中框
  353. if(curSel >= 0)
  354. {
  355. hPen1 = CreatePen(PS_SOLID, 1, RGB(0, 0, 255));
  356. hTempPen = SelectObject(m_hMemDC, hPen1);
  357. hTempBrush = SelectObject(m_hMemDC, GetStockObject(NULL_BRUSH));
  358. GetBlueRect(curSel, &rc);
  359. Rectangle(m_hMemDC, rc.left, rc.top, rc.right, rc.bottom);
  360. if(hOldPen == NULL) hOldPen = hTempPen;
  361. if(hOldBrush == NULL) hOldBrush = hTempBrush;
  362. }
  363. //绘制左侧或者右侧的预览图
  364. if(pvstatus == _PVStatus::Left) lpRect = &rcLeft;
  365. else if(pvstatus == _PVStatus::Right) lpRect = &rcRight;
  366. if(lpRect != NULL)
  367. {
  368. index = curPage * CELLCOUNT_PAGE + curSel; //从页内相对索引计算出绝对索引。
  369. hPen2 = CreatePen(PS_SOLID, 1, RGB(0, 138, 255)); //淡蓝色画笔
  370. hTempPen = SelectObject(m_hMemDC, hPen2);
  371. hTempBrush = SelectObject(m_hMemDC, GetStockObject(WHITE_BRUSH)); //白色画刷
  372. Rectangle(m_hMemDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);
  373. //居中绘制
  374. int left = (lpRect->left + lpRect->right - m_CxImages[index].GetWidth())/2;
  375. int top = (lpRect->top + lpRect->bottom - m_CxImages[index].GetHeight())/2;
  376. //设置帧
  377. if(curFrame < m_CxImages[index].GetNumFrames())
  378. {
  379. CxImage* pFrame = m_CxImages[index].GetFrame(curFrame);
  380. if(pFrame) pFrame->Draw(m_hMemDC, left, top);
  381. //m_CxImages[index].Draw(m_hMemDC, left, top);
  382. }
  383. if(hOldBrush == NULL) hOldBrush = hTempBrush;
  384. if(hOldPen == NULL) hOldPen = hTempPen;
  385. }
  386. //恢复画刷,画笔
  387. if(hOldBrush != NULL) SelectObject(m_hMemDC, hOldBrush);
  388. if(hOldPen != NULL) SelectObject(m_hMemDC, hOldPen);
  389. if(hPen1 != NULL) DeleteObject(hPen1);
  390. if(hPen2 != NULL) DeleteObject(hPen2);
  391. }
  392. //提供客户区坐标,获取当前鼠标下方的网格索引
  393. int CEmotionButton::GetCellIndex(int x, int y)
  394. {
  395. //点是否在网格范围内?
  396. //注意x >= CELLS_RIGHT (包含等于)
  397. if(x < CELLS_LEFT || x >= CELLS_RIGHT || y < CELLS_TOP || y >= CELLS_BOTTOM)
  398. return -1;
  399. //每行 15 个 CELL
  400. return (y - CELLS_TOP) / CELLSIZE * 15 + (x - CELLS_LEFT) / CELLSIZE;
  401. }
  402. //获取某个Cell的蓝色矩形框(选中时绘制)
  403. void CEmotionButton::GetBlueRect(int cellIndex, LPRECT pRect)
  404. {
  405. pRect->left = CELLS_LEFT + CELLSIZE * (cellIndex % 15) + 1;
  406. pRect->top = CELLS_TOP + CELLSIZE * (cellIndex / 15) + 1;
  407. pRect->right = pRect->left + (CELLSIZE - 2);
  408. pRect->bottom = pRect->top + (CELLSIZE - 1);
  409. }
  410. //从指定的文件夹加载图片
  411. int CEmotionButton::LoadImages(LPTSTR folder)
  412. {
  413. TCHAR filter[MAX_PATH], filename[MAX_PATH];
  414. WIN32_FIND_DATA FindFileData;
  415. HANDLE hFind;
  416. int index = 0, count = 0;
  417. //遍历获取到文件数目
  418. wsprintf(filter, _T("%s\\*.gif"), folder);
  419. hFind = FindFirstFile(filter, &FindFileData);
  420. if (hFind == INVALID_HANDLE_VALUE)
  421. {
  422. return 0;
  423. }
  424. else
  425. {
  426. count++;
  427. while (FindNextFile(hFind, &FindFileData) != 0)
  428. {
  429. count++;
  430. }
  431. }
  432. FindClose(hFind);
  433. if(count>0)
  434. {
  435. m_CxImages = new CxImage[count];
  436. hFind = FindFirstFile(filter, &FindFileData);
  437. wsprintf(filename, _T("%s\\%s"), folder, FindFileData.cFileName);
  438. //m_Images[index++].Load(filename);
  439. m_CxImages[index].SetRetreiveAllFrames(true);
  440. m_mapImagePath[index] = filename;
  441. m_CxImages[index++].Load(filename, CXIMAGE_FORMAT_UNKNOWN);
  442. while (FindNextFile(hFind, &FindFileData) != 0)
  443. {
  444. wsprintf(filename, _T("%s\\%s"), folder, FindFileData.cFileName);
  445. //m_Images[index++].Load(filename);
  446. m_CxImages[index].SetRetreiveAllFrames(true);
  447. m_mapImagePath[index] = filename;
  448. m_CxImages[index++].Load(filename, CXIMAGE_FORMAT_UNKNOWN);
  449. }
  450. FindClose(hFind);
  451. }
  452. return count;
  453. }
  454. CxImage *CEmotionButton::GetSelectedImage(int curPage, int curSel)
  455. {
  456. return m_CxImages + (curPage * CELLCOUNT_PAGE + curSel);
  457. }