infoWidget.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. #include "main.h"
  2. #include "./infoWidget.h"
  3. #define INFOWIDGET_OFFSET_LEFT_DLU 4
  4. #define INFOWIDGET_OFFSET_TOP_DLU 2
  5. #define INFOWIDGET_OFFSET_RIGHT_DLU 4
  6. #define INFOWIDGET_OFFSET_BOTTOM_DLU 2
  7. #define INFOWIDGET_MIN_WIDTH_DLU (8*4)
  8. #define INFOWIDGET_MAX_WIDTH_DLU (48*4)
  9. #define INFOWIDGET_TITLE_OFFSET_BOTTOM_DLU 24
  10. #define INFOWIDGET_IMAGE_OFFSET_BOTTOM_DLU 24
  11. typedef struct InfoWidget
  12. {
  13. wchar_t *title;
  14. wchar_t *text;
  15. wchar_t *imagePath;
  16. HBITMAP image;
  17. RECT titleRect;
  18. RECT textRect;
  19. RECT imageRect;
  20. BackBuffer backBuffer;
  21. } InfoWidget;
  22. typedef struct InfoWidgetParam
  23. {
  24. const wchar_t *title;
  25. const wchar_t *text;
  26. const wchar_t *imagePath;
  27. } InfoWidgetParam;
  28. static BOOL
  29. InfoWidget_InitCb(HWND hwnd, void **object, void *param)
  30. {
  31. InfoWidget *self;
  32. const InfoWidgetParam *createParam;
  33. self = (InfoWidget*)malloc(sizeof(InfoWidget));
  34. if (NULL == self)
  35. return FALSE;
  36. ZeroMemory(self, sizeof(InfoWidget));
  37. createParam = (InfoWidgetParam*)param;
  38. if (NULL != createParam)
  39. {
  40. wchar_t buffer[4096] = {0};
  41. if (FALSE != IS_INTRESOURCE(createParam->title))
  42. {
  43. if (NULL != WASABI_API_LNG)
  44. {
  45. WASABI_API_LNGSTRINGW_BUF((int)(INT_PTR)createParam->title, buffer, ARRAYSIZE(buffer));
  46. self->title = String_Duplicate(buffer);
  47. }
  48. else
  49. self->title = NULL;
  50. }
  51. else
  52. self->title = String_Duplicate(createParam->title);
  53. if (FALSE != IS_INTRESOURCE(createParam->text))
  54. {
  55. if (NULL != WASABI_API_LNG)
  56. {
  57. WASABI_API_LNGSTRINGW_BUF((int)(INT_PTR)createParam->text, buffer, ARRAYSIZE(buffer));
  58. self->text = String_Duplicate(buffer);
  59. }
  60. else
  61. self->text = NULL;
  62. }
  63. else
  64. self->text = String_Duplicate(createParam->text);
  65. self->imagePath = ResourceString_Duplicate(createParam->imagePath);
  66. }
  67. BackBuffer_Initialize(&self->backBuffer, hwnd);
  68. *object = self;
  69. return TRUE;
  70. }
  71. static void
  72. InfoWidget_DestroyCb(InfoWidget *self, HWND hwnd)
  73. {
  74. if (NULL == self)
  75. return;
  76. String_Free(self->title);
  77. String_Free(self->text);
  78. ResourceString_Free(self->imagePath);
  79. if (NULL != self->image)
  80. DeleteObject(self->image);
  81. BackBuffer_Uninitialize(&self->backBuffer);
  82. free(self);
  83. }
  84. static HBITMAP
  85. InfoWidget_GetImage(InfoWidget *self, WidgetStyle *style)
  86. {
  87. if (NULL == self->image)
  88. {
  89. unsigned int flags;
  90. flags = IMAGE_FILTER_BLEND;
  91. if (FALSE == IS_INTRESOURCE(self->imagePath))
  92. flags |= ISF_LOADFROMFILE;
  93. self->image = Image_LoadSkinned(self->imagePath, SRC_TYPE_PNG, flags,
  94. 0, 0,
  95. WIDGETSTYLE_IMAGE_BACK_COLOR(style),
  96. WIDGETSTYLE_IMAGE_FRONT_COLOR(style),
  97. WIDGETSTYLE_BACK_COLOR(style));
  98. }
  99. return self->image;
  100. }
  101. static BOOL
  102. InfoWidget_GetImageSize(InfoWidget *self, WidgetStyle *style, SIZE *size)
  103. {
  104. HBITMAP image;
  105. BITMAP imageInfo;
  106. image = InfoWidget_GetImage(self, style);
  107. if (NULL == image)
  108. return FALSE;
  109. if (sizeof(imageInfo) != GetObject(image, sizeof(imageInfo), &imageInfo))
  110. return FALSE;
  111. size->cx = imageInfo.bmWidth;
  112. size->cy = imageInfo.bmHeight;
  113. if (size->cy < 0)
  114. size->cy = -size->cy;
  115. return TRUE;
  116. }
  117. static BOOL
  118. InfoWidget_GetTextSize(HDC hdc, HFONT font, const wchar_t *text, long width,
  119. unsigned int format, SIZE *size)
  120. {
  121. RECT rect;
  122. BOOL result;
  123. HFONT prevFont;
  124. if (FALSE != IS_STRING_EMPTY(text))
  125. {
  126. size->cx = 0;
  127. size->cy = 0;
  128. return TRUE;
  129. }
  130. prevFont = SelectFont(hdc, font);
  131. SetRect(&rect, 0, 0, width, 0);
  132. result = DrawText(hdc, text, -1, &rect, DT_CALCRECT | format);
  133. if (FALSE != result)
  134. {
  135. size->cx = RECTWIDTH(rect);
  136. size->cy = RECTHEIGHT(rect);
  137. }
  138. SelectFont(hdc, prevFont);
  139. return result;
  140. }
  141. static long
  142. InfoWidget_GetClientWidth(WidgetStyle *style, long viewWidth)
  143. {
  144. long test;
  145. viewWidth -= (WIDGETSTYLE_DLU_TO_HORZ_PX(style, INFOWIDGET_OFFSET_LEFT_DLU) +
  146. WIDGETSTYLE_DLU_TO_HORZ_PX(style, INFOWIDGET_OFFSET_RIGHT_DLU));
  147. test = WIDGETSTYLE_DLU_TO_HORZ_PX(style, INFOWIDGET_MIN_WIDTH_DLU);
  148. if (viewWidth < test)
  149. return test;
  150. test = WIDGETSTYLE_DLU_TO_HORZ_PX(style, INFOWIDGET_MAX_WIDTH_DLU);
  151. if (viewWidth > test)
  152. return test;
  153. return viewWidth;
  154. }
  155. static void
  156. InfoWidget_LayoutCb(InfoWidget *self, HWND hwnd, WidgetStyle *style,
  157. const RECT *clientRect, SIZE *viewSize, BOOL redraw)
  158. {
  159. HDC windowDC;
  160. LONG offsetX, offsetY;
  161. SIZE widgetSize;
  162. RECT offsetRect;
  163. if (NULL == self || NULL == style)
  164. return;
  165. windowDC = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS);
  166. if (NULL == windowDC)
  167. return;
  168. offsetRect.left = WIDGETSTYLE_DLU_TO_HORZ_PX(style, INFOWIDGET_OFFSET_LEFT_DLU);
  169. offsetRect.top = WIDGETSTYLE_DLU_TO_VERT_PX(style, INFOWIDGET_OFFSET_TOP_DLU);
  170. offsetRect.right = WIDGETSTYLE_DLU_TO_HORZ_PX(style, INFOWIDGET_OFFSET_RIGHT_DLU);
  171. offsetRect.bottom = WIDGETSTYLE_DLU_TO_VERT_PX(style, INFOWIDGET_OFFSET_BOTTOM_DLU);
  172. widgetSize.cx = InfoWidget_GetClientWidth(style, RECTWIDTH(*clientRect));
  173. widgetSize.cy = 0;
  174. SetRectEmpty(&self->imageRect);
  175. if (FALSE != InfoWidget_GetImageSize(self, style, ((SIZE*)&self->imageRect) + 1))
  176. {
  177. if (widgetSize.cx < self->imageRect.right)
  178. widgetSize.cx = self->imageRect.right;
  179. widgetSize.cy += self->imageRect.bottom;
  180. if (0 != self->imageRect.bottom)
  181. widgetSize.cy += WIDGETSTYLE_DLU_TO_VERT_PX(style, INFOWIDGET_IMAGE_OFFSET_BOTTOM_DLU);
  182. }
  183. SetRectEmpty(&self->titleRect);
  184. if (FALSE != InfoWidget_GetTextSize(windowDC, style->titleFont, self->title, widgetSize.cx,
  185. DT_LEFT | DT_TOP | DT_NOPREFIX | DT_WORDBREAK, ((SIZE*)&self->titleRect) + 1))
  186. {
  187. widgetSize.cy += self->titleRect.bottom;
  188. if (0 != self->titleRect.bottom)
  189. widgetSize.cy += WIDGETSTYLE_DLU_TO_VERT_PX(style, INFOWIDGET_TITLE_OFFSET_BOTTOM_DLU);
  190. }
  191. SetRectEmpty(&self->textRect);
  192. if (FALSE != InfoWidget_GetTextSize(windowDC, style->textFont, self->text, widgetSize.cx,
  193. DT_LEFT | DT_TOP | DT_NOPREFIX | DT_WORDBREAK, ((SIZE*)&self->textRect) + 1))
  194. {
  195. widgetSize.cy += self->textRect.bottom;
  196. }
  197. if ((widgetSize.cx + (offsetRect.left + offsetRect.right)) < RECTWIDTH(*clientRect))
  198. offsetX = clientRect->left + (RECTWIDTH(*clientRect) - widgetSize.cx)/2;
  199. else
  200. offsetX = clientRect->left + offsetRect.left;
  201. if ((widgetSize.cy + (offsetRect.top + offsetRect.bottom)) < RECTHEIGHT(*clientRect))
  202. offsetY = clientRect->top + (RECTHEIGHT(*clientRect) - widgetSize.cy)/2;
  203. else
  204. offsetY = clientRect->top + offsetRect.top;
  205. if (FALSE == IsRectEmpty(&self->titleRect))
  206. {
  207. OffsetRect(&self->titleRect, offsetX + (widgetSize.cx - self->titleRect.right)/2, offsetY);
  208. offsetY = self->titleRect.bottom;
  209. offsetY += WIDGETSTYLE_DLU_TO_VERT_PX(style, INFOWIDGET_TITLE_OFFSET_BOTTOM_DLU);
  210. }
  211. if (FALSE == IsRectEmpty(&self->imageRect))
  212. {
  213. OffsetRect(&self->imageRect, offsetX + (widgetSize.cx - self->imageRect.right)/2, offsetY);
  214. offsetY = self->imageRect.bottom;
  215. offsetY += WIDGETSTYLE_DLU_TO_VERT_PX(style, INFOWIDGET_IMAGE_OFFSET_BOTTOM_DLU);
  216. }
  217. if (FALSE == IsRectEmpty(&self->textRect))
  218. {
  219. OffsetRect(&self->textRect, offsetX + (widgetSize.cx - self->textRect.right)/2, offsetY);
  220. }
  221. ReleaseDC(hwnd, windowDC);
  222. viewSize->cx = widgetSize.cx + offsetRect.left + offsetRect.right;
  223. viewSize->cy = widgetSize.cy + offsetRect.top + offsetRect.bottom;
  224. }
  225. static BOOL
  226. InfoWidget_PaintCb(InfoWidget *self, HWND hwnd, WidgetStyle *style, HDC hdc, const RECT *paintRect, BOOL erase)
  227. {
  228. RECT intersectRect;
  229. FillRegion fillRegion;
  230. FillRegion_Init(&fillRegion, paintRect);
  231. if (FALSE == IS_STRING_EMPTY(self->title) &&
  232. FALSE != IntersectRect(&intersectRect, &self->titleRect, paintRect))
  233. {
  234. if (FALSE != BackBuffer_DrawTextEx(&self->backBuffer, hdc, self->title, -1, &self->titleRect,
  235. DT_CENTER | DT_NOPREFIX | DT_WORDBREAK,
  236. style->titleFont, style->backColor, style->titleColor, OPAQUE))
  237. {
  238. FillRegion_ExcludeRect(&fillRegion, &intersectRect);
  239. }
  240. }
  241. if (NULL != self->image &&
  242. FALSE != IntersectRect(&intersectRect, &self->imageRect, paintRect))
  243. {
  244. HDC windowDC = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS);
  245. if (NULL != windowDC)
  246. {
  247. HDC sourceDC = CreateCompatibleDC(windowDC);
  248. if (NULL != sourceDC)
  249. {
  250. HBITMAP prevBitmap = SelectBitmap(sourceDC, self->image);
  251. if (FALSE != BitBlt(hdc, intersectRect.left, intersectRect.top,
  252. RECTWIDTH(intersectRect), RECTHEIGHT(intersectRect),
  253. sourceDC,
  254. intersectRect.left - self->imageRect.left,
  255. intersectRect.top - self->imageRect.top,
  256. SRCCOPY))
  257. {
  258. FillRegion_ExcludeRect(&fillRegion, &intersectRect);
  259. }
  260. SelectBitmap(sourceDC, prevBitmap);
  261. DeleteDC(sourceDC);
  262. }
  263. ReleaseDC(hwnd, windowDC);
  264. }
  265. }
  266. if (FALSE == IS_STRING_EMPTY(self->text) &&
  267. FALSE != IntersectRect(&intersectRect, &self->textRect, paintRect))
  268. {
  269. if (FALSE != BackBuffer_DrawTextEx(&self->backBuffer, hdc, self->text, -1, &self->textRect,
  270. DT_CENTER | DT_NOPREFIX | DT_WORDBREAK,
  271. style->textFont, style->backColor, style->textColor, OPAQUE))
  272. {
  273. FillRegion_ExcludeRect(&fillRegion, &intersectRect);
  274. }
  275. }
  276. if (FALSE != erase)
  277. FillRegion_BrushFill(&fillRegion, hdc, style->backBrush);
  278. FillRegion_Uninit(&fillRegion);
  279. return TRUE;
  280. }
  281. static void
  282. InfoWidget_StyleColorChangedCb(InfoWidget *self, HWND hwnd, WidgetStyle *style)
  283. {
  284. if (NULL == self)
  285. return;
  286. if (NULL != self->image)
  287. {
  288. if (NULL != self->image)
  289. DeleteObject(self->image);
  290. self->image = NULL;
  291. InfoWidget_GetImage(self, style);
  292. }
  293. }
  294. HWND InfoWidget_CreateWindow(unsigned int type, const wchar_t *title, const wchar_t *text,
  295. const wchar_t *imagePath, HWND parentWindow,
  296. int x, int y, int width, int height, BOOL border, unsigned int controlId)
  297. {
  298. const static WidgetInterface infoWidgetInterface =
  299. {
  300. (WidgetInitCallback)InfoWidget_InitCb,
  301. (WidgetDestroyCallback)InfoWidget_DestroyCb,
  302. (WidgetLayoutCallback)InfoWidget_LayoutCb,
  303. (WidgetPaintCallback)InfoWidget_PaintCb,
  304. (WidgetStyleCallback)InfoWidget_StyleColorChangedCb,
  305. };
  306. InfoWidgetParam param;
  307. param.title = title;
  308. param.text = text;
  309. param.imagePath = imagePath;
  310. return Widget_CreateWindow(type,
  311. &infoWidgetInterface,
  312. NULL,
  313. (FALSE != border) ? WS_EX_CLIENTEDGE : 0,
  314. 0,
  315. x, y, width, height,
  316. parentWindow,
  317. controlId, &param);
  318. }