diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/Library/ml_devices/infoWidget.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/Plugins/Library/ml_devices/infoWidget.cpp')
-rw-r--r-- | Src/Plugins/Library/ml_devices/infoWidget.cpp | 399 |
1 files changed, 399 insertions, 0 deletions
diff --git a/Src/Plugins/Library/ml_devices/infoWidget.cpp b/Src/Plugins/Library/ml_devices/infoWidget.cpp new file mode 100644 index 00000000..7a85e9bc --- /dev/null +++ b/Src/Plugins/Library/ml_devices/infoWidget.cpp @@ -0,0 +1,399 @@ +#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); +}
\ No newline at end of file |