399 lines
10 KiB
C++
399 lines
10 KiB
C++
|
#include "main.h"
|
||
|
#include "./infoWidget.h"
|
||
|
|
||
|
#define INFOWIDGET_OFFSET_LEFT_DLU 4
|
||
|
#define INFOWIDGET_OFFSET_TOP_DLU 2
|
||
|
#define INFOWIDGET_OFFSET_RIGHT_DLU 4
|
||
|
#define INFOWIDGET_OFFSET_BOTTOM_DLU 2
|
||
|
|
||
|
#define INFOWIDGET_MIN_WIDTH_DLU (8*4)
|
||
|
#define INFOWIDGET_MAX_WIDTH_DLU (48*4)
|
||
|
|
||
|
#define INFOWIDGET_TITLE_OFFSET_BOTTOM_DLU 24
|
||
|
#define INFOWIDGET_IMAGE_OFFSET_BOTTOM_DLU 24
|
||
|
|
||
|
|
||
|
typedef struct InfoWidget
|
||
|
{
|
||
|
wchar_t *title;
|
||
|
wchar_t *text;
|
||
|
wchar_t *imagePath;
|
||
|
HBITMAP image;
|
||
|
RECT titleRect;
|
||
|
RECT textRect;
|
||
|
RECT imageRect;
|
||
|
BackBuffer backBuffer;
|
||
|
} InfoWidget;
|
||
|
|
||
|
typedef struct InfoWidgetParam
|
||
|
{
|
||
|
const wchar_t *title;
|
||
|
const wchar_t *text;
|
||
|
const wchar_t *imagePath;
|
||
|
} InfoWidgetParam;
|
||
|
|
||
|
static BOOL
|
||
|
InfoWidget_InitCb(HWND hwnd, void **object, void *param)
|
||
|
{
|
||
|
InfoWidget *self;
|
||
|
const InfoWidgetParam *createParam;
|
||
|
|
||
|
self = (InfoWidget*)malloc(sizeof(InfoWidget));
|
||
|
if (NULL == self)
|
||
|
return FALSE;
|
||
|
|
||
|
ZeroMemory(self, sizeof(InfoWidget));
|
||
|
|
||
|
|
||
|
createParam = (InfoWidgetParam*)param;
|
||
|
|
||
|
if (NULL != createParam)
|
||
|
{
|
||
|
wchar_t buffer[4096] = {0};
|
||
|
|
||
|
if (FALSE != IS_INTRESOURCE(createParam->title))
|
||
|
{
|
||
|
if (NULL != WASABI_API_LNG)
|
||
|
{
|
||
|
WASABI_API_LNGSTRINGW_BUF((int)(INT_PTR)createParam->title, buffer, ARRAYSIZE(buffer));
|
||
|
self->title = String_Duplicate(buffer);
|
||
|
}
|
||
|
else
|
||
|
self->title = NULL;
|
||
|
}
|
||
|
else
|
||
|
self->title = String_Duplicate(createParam->title);
|
||
|
|
||
|
if (FALSE != IS_INTRESOURCE(createParam->text))
|
||
|
{
|
||
|
if (NULL != WASABI_API_LNG)
|
||
|
{
|
||
|
WASABI_API_LNGSTRINGW_BUF((int)(INT_PTR)createParam->text, buffer, ARRAYSIZE(buffer));
|
||
|
self->text = String_Duplicate(buffer);
|
||
|
}
|
||
|
else
|
||
|
self->text = NULL;
|
||
|
}
|
||
|
else
|
||
|
self->text = String_Duplicate(createParam->text);
|
||
|
|
||
|
self->imagePath = ResourceString_Duplicate(createParam->imagePath);
|
||
|
}
|
||
|
|
||
|
BackBuffer_Initialize(&self->backBuffer, hwnd);
|
||
|
|
||
|
*object = self;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
InfoWidget_DestroyCb(InfoWidget *self, HWND hwnd)
|
||
|
{
|
||
|
if (NULL == self)
|
||
|
return;
|
||
|
|
||
|
String_Free(self->title);
|
||
|
String_Free(self->text);
|
||
|
ResourceString_Free(self->imagePath);
|
||
|
|
||
|
if (NULL != self->image)
|
||
|
DeleteObject(self->image);
|
||
|
|
||
|
BackBuffer_Uninitialize(&self->backBuffer);
|
||
|
free(self);
|
||
|
}
|
||
|
|
||
|
|
||
|
static HBITMAP
|
||
|
InfoWidget_GetImage(InfoWidget *self, WidgetStyle *style)
|
||
|
{
|
||
|
if (NULL == self->image)
|
||
|
{
|
||
|
unsigned int flags;
|
||
|
|
||
|
flags = IMAGE_FILTER_BLEND;
|
||
|
|
||
|
if (FALSE == IS_INTRESOURCE(self->imagePath))
|
||
|
flags |= ISF_LOADFROMFILE;
|
||
|
|
||
|
self->image = Image_LoadSkinned(self->imagePath, SRC_TYPE_PNG, flags,
|
||
|
0, 0,
|
||
|
WIDGETSTYLE_IMAGE_BACK_COLOR(style),
|
||
|
WIDGETSTYLE_IMAGE_FRONT_COLOR(style),
|
||
|
WIDGETSTYLE_BACK_COLOR(style));
|
||
|
|
||
|
}
|
||
|
|
||
|
return self->image;
|
||
|
}
|
||
|
|
||
|
static BOOL
|
||
|
InfoWidget_GetImageSize(InfoWidget *self, WidgetStyle *style, SIZE *size)
|
||
|
{
|
||
|
HBITMAP image;
|
||
|
BITMAP imageInfo;
|
||
|
|
||
|
image = InfoWidget_GetImage(self, style);
|
||
|
if (NULL == image)
|
||
|
return FALSE;
|
||
|
|
||
|
if (sizeof(imageInfo) != GetObject(image, sizeof(imageInfo), &imageInfo))
|
||
|
return FALSE;
|
||
|
|
||
|
size->cx = imageInfo.bmWidth;
|
||
|
size->cy = imageInfo.bmHeight;
|
||
|
if (size->cy < 0)
|
||
|
size->cy = -size->cy;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static BOOL
|
||
|
InfoWidget_GetTextSize(HDC hdc, HFONT font, const wchar_t *text, long width,
|
||
|
unsigned int format, SIZE *size)
|
||
|
{
|
||
|
RECT rect;
|
||
|
BOOL result;
|
||
|
HFONT prevFont;
|
||
|
|
||
|
if (FALSE != IS_STRING_EMPTY(text))
|
||
|
{
|
||
|
size->cx = 0;
|
||
|
size->cy = 0;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
prevFont = SelectFont(hdc, font);
|
||
|
|
||
|
SetRect(&rect, 0, 0, width, 0);
|
||
|
result = DrawText(hdc, text, -1, &rect, DT_CALCRECT | format);
|
||
|
if (FALSE != result)
|
||
|
{
|
||
|
size->cx = RECTWIDTH(rect);
|
||
|
size->cy = RECTHEIGHT(rect);
|
||
|
}
|
||
|
|
||
|
SelectFont(hdc, prevFont);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
static long
|
||
|
InfoWidget_GetClientWidth(WidgetStyle *style, long viewWidth)
|
||
|
{
|
||
|
long test;
|
||
|
|
||
|
viewWidth -= (WIDGETSTYLE_DLU_TO_HORZ_PX(style, INFOWIDGET_OFFSET_LEFT_DLU) +
|
||
|
WIDGETSTYLE_DLU_TO_HORZ_PX(style, INFOWIDGET_OFFSET_RIGHT_DLU));
|
||
|
|
||
|
test = WIDGETSTYLE_DLU_TO_HORZ_PX(style, INFOWIDGET_MIN_WIDTH_DLU);
|
||
|
if (viewWidth < test)
|
||
|
return test;
|
||
|
|
||
|
test = WIDGETSTYLE_DLU_TO_HORZ_PX(style, INFOWIDGET_MAX_WIDTH_DLU);
|
||
|
if (viewWidth > test)
|
||
|
return test;
|
||
|
|
||
|
return viewWidth;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
InfoWidget_LayoutCb(InfoWidget *self, HWND hwnd, WidgetStyle *style,
|
||
|
const RECT *clientRect, SIZE *viewSize, BOOL redraw)
|
||
|
{
|
||
|
HDC windowDC;
|
||
|
LONG offsetX, offsetY;
|
||
|
SIZE widgetSize;
|
||
|
RECT offsetRect;
|
||
|
|
||
|
if (NULL == self || NULL == style)
|
||
|
return;
|
||
|
|
||
|
windowDC = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS);
|
||
|
if (NULL == windowDC)
|
||
|
return;
|
||
|
|
||
|
offsetRect.left = WIDGETSTYLE_DLU_TO_HORZ_PX(style, INFOWIDGET_OFFSET_LEFT_DLU);
|
||
|
offsetRect.top = WIDGETSTYLE_DLU_TO_VERT_PX(style, INFOWIDGET_OFFSET_TOP_DLU);
|
||
|
offsetRect.right = WIDGETSTYLE_DLU_TO_HORZ_PX(style, INFOWIDGET_OFFSET_RIGHT_DLU);
|
||
|
offsetRect.bottom = WIDGETSTYLE_DLU_TO_VERT_PX(style, INFOWIDGET_OFFSET_BOTTOM_DLU);
|
||
|
|
||
|
widgetSize.cx = InfoWidget_GetClientWidth(style, RECTWIDTH(*clientRect));
|
||
|
widgetSize.cy = 0;
|
||
|
|
||
|
SetRectEmpty(&self->imageRect);
|
||
|
if (FALSE != InfoWidget_GetImageSize(self, style, ((SIZE*)&self->imageRect) + 1))
|
||
|
{
|
||
|
if (widgetSize.cx < self->imageRect.right)
|
||
|
widgetSize.cx = self->imageRect.right;
|
||
|
|
||
|
widgetSize.cy += self->imageRect.bottom;
|
||
|
if (0 != self->imageRect.bottom)
|
||
|
widgetSize.cy += WIDGETSTYLE_DLU_TO_VERT_PX(style, INFOWIDGET_IMAGE_OFFSET_BOTTOM_DLU);
|
||
|
}
|
||
|
|
||
|
SetRectEmpty(&self->titleRect);
|
||
|
if (FALSE != InfoWidget_GetTextSize(windowDC, style->titleFont, self->title, widgetSize.cx,
|
||
|
DT_LEFT | DT_TOP | DT_NOPREFIX | DT_WORDBREAK, ((SIZE*)&self->titleRect) + 1))
|
||
|
{
|
||
|
widgetSize.cy += self->titleRect.bottom;
|
||
|
if (0 != self->titleRect.bottom)
|
||
|
widgetSize.cy += WIDGETSTYLE_DLU_TO_VERT_PX(style, INFOWIDGET_TITLE_OFFSET_BOTTOM_DLU);
|
||
|
}
|
||
|
|
||
|
SetRectEmpty(&self->textRect);
|
||
|
if (FALSE != InfoWidget_GetTextSize(windowDC, style->textFont, self->text, widgetSize.cx,
|
||
|
DT_LEFT | DT_TOP | DT_NOPREFIX | DT_WORDBREAK, ((SIZE*)&self->textRect) + 1))
|
||
|
{
|
||
|
widgetSize.cy += self->textRect.bottom;
|
||
|
}
|
||
|
|
||
|
|
||
|
if ((widgetSize.cx + (offsetRect.left + offsetRect.right)) < RECTWIDTH(*clientRect))
|
||
|
offsetX = clientRect->left + (RECTWIDTH(*clientRect) - widgetSize.cx)/2;
|
||
|
else
|
||
|
offsetX = clientRect->left + offsetRect.left;
|
||
|
|
||
|
if ((widgetSize.cy + (offsetRect.top + offsetRect.bottom)) < RECTHEIGHT(*clientRect))
|
||
|
offsetY = clientRect->top + (RECTHEIGHT(*clientRect) - widgetSize.cy)/2;
|
||
|
else
|
||
|
offsetY = clientRect->top + offsetRect.top;
|
||
|
|
||
|
|
||
|
if (FALSE == IsRectEmpty(&self->titleRect))
|
||
|
{
|
||
|
OffsetRect(&self->titleRect, offsetX + (widgetSize.cx - self->titleRect.right)/2, offsetY);
|
||
|
offsetY = self->titleRect.bottom;
|
||
|
offsetY += WIDGETSTYLE_DLU_TO_VERT_PX(style, INFOWIDGET_TITLE_OFFSET_BOTTOM_DLU);
|
||
|
}
|
||
|
|
||
|
if (FALSE == IsRectEmpty(&self->imageRect))
|
||
|
{
|
||
|
OffsetRect(&self->imageRect, offsetX + (widgetSize.cx - self->imageRect.right)/2, offsetY);
|
||
|
offsetY = self->imageRect.bottom;
|
||
|
offsetY += WIDGETSTYLE_DLU_TO_VERT_PX(style, INFOWIDGET_IMAGE_OFFSET_BOTTOM_DLU);
|
||
|
}
|
||
|
|
||
|
if (FALSE == IsRectEmpty(&self->textRect))
|
||
|
{
|
||
|
OffsetRect(&self->textRect, offsetX + (widgetSize.cx - self->textRect.right)/2, offsetY);
|
||
|
}
|
||
|
|
||
|
ReleaseDC(hwnd, windowDC);
|
||
|
|
||
|
viewSize->cx = widgetSize.cx + offsetRect.left + offsetRect.right;
|
||
|
viewSize->cy = widgetSize.cy + offsetRect.top + offsetRect.bottom;
|
||
|
}
|
||
|
|
||
|
|
||
|
static BOOL
|
||
|
InfoWidget_PaintCb(InfoWidget *self, HWND hwnd, WidgetStyle *style, HDC hdc, const RECT *paintRect, BOOL erase)
|
||
|
{
|
||
|
RECT intersectRect;
|
||
|
FillRegion fillRegion;
|
||
|
|
||
|
FillRegion_Init(&fillRegion, paintRect);
|
||
|
|
||
|
if (FALSE == IS_STRING_EMPTY(self->title) &&
|
||
|
FALSE != IntersectRect(&intersectRect, &self->titleRect, paintRect))
|
||
|
{
|
||
|
if (FALSE != BackBuffer_DrawTextEx(&self->backBuffer, hdc, self->title, -1, &self->titleRect,
|
||
|
DT_CENTER | DT_NOPREFIX | DT_WORDBREAK,
|
||
|
style->titleFont, style->backColor, style->titleColor, OPAQUE))
|
||
|
{
|
||
|
FillRegion_ExcludeRect(&fillRegion, &intersectRect);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (NULL != self->image &&
|
||
|
FALSE != IntersectRect(&intersectRect, &self->imageRect, paintRect))
|
||
|
{
|
||
|
HDC windowDC = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS);
|
||
|
if (NULL != windowDC)
|
||
|
{
|
||
|
HDC sourceDC = CreateCompatibleDC(windowDC);
|
||
|
if (NULL != sourceDC)
|
||
|
{
|
||
|
HBITMAP prevBitmap = SelectBitmap(sourceDC, self->image);
|
||
|
if (FALSE != BitBlt(hdc, intersectRect.left, intersectRect.top,
|
||
|
RECTWIDTH(intersectRect), RECTHEIGHT(intersectRect),
|
||
|
sourceDC,
|
||
|
intersectRect.left - self->imageRect.left,
|
||
|
intersectRect.top - self->imageRect.top,
|
||
|
SRCCOPY))
|
||
|
{
|
||
|
FillRegion_ExcludeRect(&fillRegion, &intersectRect);
|
||
|
}
|
||
|
|
||
|
SelectBitmap(sourceDC, prevBitmap);
|
||
|
DeleteDC(sourceDC);
|
||
|
}
|
||
|
ReleaseDC(hwnd, windowDC);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (FALSE == IS_STRING_EMPTY(self->text) &&
|
||
|
FALSE != IntersectRect(&intersectRect, &self->textRect, paintRect))
|
||
|
{
|
||
|
if (FALSE != BackBuffer_DrawTextEx(&self->backBuffer, hdc, self->text, -1, &self->textRect,
|
||
|
DT_CENTER | DT_NOPREFIX | DT_WORDBREAK,
|
||
|
style->textFont, style->backColor, style->textColor, OPAQUE))
|
||
|
{
|
||
|
FillRegion_ExcludeRect(&fillRegion, &intersectRect);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if (FALSE != erase)
|
||
|
FillRegion_BrushFill(&fillRegion, hdc, style->backBrush);
|
||
|
|
||
|
FillRegion_Uninit(&fillRegion);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
InfoWidget_StyleColorChangedCb(InfoWidget *self, HWND hwnd, WidgetStyle *style)
|
||
|
{
|
||
|
if (NULL == self)
|
||
|
return;
|
||
|
|
||
|
if (NULL != self->image)
|
||
|
{
|
||
|
if (NULL != self->image)
|
||
|
DeleteObject(self->image);
|
||
|
|
||
|
self->image = NULL;
|
||
|
InfoWidget_GetImage(self, style);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HWND InfoWidget_CreateWindow(unsigned int type, const wchar_t *title, const wchar_t *text,
|
||
|
const wchar_t *imagePath, HWND parentWindow,
|
||
|
int x, int y, int width, int height, BOOL border, unsigned int controlId)
|
||
|
{
|
||
|
const static WidgetInterface infoWidgetInterface =
|
||
|
{
|
||
|
(WidgetInitCallback)InfoWidget_InitCb,
|
||
|
(WidgetDestroyCallback)InfoWidget_DestroyCb,
|
||
|
(WidgetLayoutCallback)InfoWidget_LayoutCb,
|
||
|
(WidgetPaintCallback)InfoWidget_PaintCb,
|
||
|
(WidgetStyleCallback)InfoWidget_StyleColorChangedCb,
|
||
|
};
|
||
|
|
||
|
InfoWidgetParam param;
|
||
|
|
||
|
param.title = title;
|
||
|
param.text = text;
|
||
|
param.imagePath = imagePath;
|
||
|
|
||
|
return Widget_CreateWindow(type,
|
||
|
&infoWidgetInterface,
|
||
|
NULL,
|
||
|
(FALSE != border) ? WS_EX_CLIENTEDGE : 0,
|
||
|
0,
|
||
|
x, y, width, height,
|
||
|
parentWindow,
|
||
|
controlId, ¶m);
|
||
|
}
|