winamp/Src/Plugins/General/gen_ml/skinnedcombo.cpp
2024-09-24 14:54:57 +02:00

444 lines
No EOL
12 KiB
C++

#include "./skinnedcombo.h"
#include "./skinnedheader.h"
#include "../winamp/wa_dlg.h"
#include "./skinning.h"
#include "../nu/trace.h"
#include <windowsx.h>
#include <strsafe.h>
#define COMBO_TEXT_MAX 512
SkinnedCombobox::SkinnedCombobox(void) : SkinnedWnd(FALSE), activeBorder(TRUE)
{
}
SkinnedCombobox::~SkinnedCombobox(void)
{
}
BOOL SkinnedCombobox::Attach(HWND hwndCombo)
{
if(!SkinnedWnd::Attach(hwndCombo)) return FALSE;
SetType(SKINNEDWND_TYPE_COMBOBOX);
activeBorder = TRUE;
COMBOBOXINFO cbi;
ZeroMemory(&cbi, sizeof(COMBOBOXINFO));
cbi.cbSize = sizeof(COMBOBOXINFO);
if (GetComboBoxInfo(hwnd, &cbi))
{
if (NULL != cbi.hwndItem) SkinWindowEx(cbi.hwndItem, SKINNEDWND_TYPE_EDIT, style);
if (NULL != cbi.hwndList)
{
SkinWindowEx(cbi.hwndList, SKINNEDWND_TYPE_LISTBOX, style);
}
}
SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
return TRUE;
}
BOOL SkinnedCombobox::SetStyle(UINT newStyle, BOOL bRedraw)
{
BOOL result = __super::SetStyle(newStyle, bRedraw);
if (hwnd)
{
COMBOBOXINFO cbi;
ZeroMemory(&cbi, sizeof(COMBOBOXINFO));
cbi.cbSize = sizeof(COMBOBOXINFO);
activeBorder = (0 == (SWCBS_TOOLBAR & style));
if (GetComboBoxInfo(hwnd, &cbi))
{
if (NULL != cbi.hwndItem) MLSkinnedWnd_SetStyle(cbi.hwndItem, style);
if (NULL != cbi.hwndList) MLSkinnedWnd_SetStyle(cbi.hwndList, style);
}
}
return result;
}
BOOL SkinnedCombobox::IsButtonDown(DWORD windowStyle)
{
if(GetAsyncKeyState((GetSystemMetrics(SM_SWAPBUTTON)) ? VK_RBUTTON : VK_LBUTTON) & 0x8000)
{
if (CBS_DROPDOWNLIST == (0x0F & windowStyle))
{
POINT pt;
RECT rc;
if (hwnd == GetFocus() && GetClientRect(hwnd, &rc))
{
GetCursorPos(&pt);
MapWindowPoints(HWND_DESKTOP, hwnd, &pt, 1);
return PtInRect(&rc, pt);
}
return FALSE;
}
COMBOBOXINFO cbi;
ZeroMemory(&cbi, sizeof(COMBOBOXINFO));
cbi.cbSize = sizeof(COMBOBOXINFO);
if (GetComboBoxInfo(hwnd, &cbi))
{
//check if in arrow down area
POINT pt;
GetCursorPos(&pt);
MapWindowPoints(HWND_DESKTOP, hwnd, &pt, 1);
return PtInRect(&cbi.rcButton, pt);
}
}
return FALSE;
}
void SkinnedCombobox::DrawButton(HDC hdc, RECT *prcButton, BOOL bPressed, BOOL bActive)
{
COLORREF rgbBkOld, rgbBk;
rgbBk = WADlg_getColor(WADLG_LISTHEADER_BGCOLOR);
rgbBkOld = SetBkColor(hdc, rgbBk);
ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, prcButton, NULL, 0, 0);
if (bActive)
{
HPEN pen, penOld;
pen = (HPEN)MlStockObjects_Get((bPressed) ? HEADERBOTTOM_PEN : HEADERTOP_PEN);
penOld = (HPEN)SelectObject(hdc, pen);
MoveToEx(hdc, prcButton->left, prcButton->top, NULL);
LineTo(hdc, prcButton->right, prcButton->top);
MoveToEx(hdc, prcButton->left, prcButton->top, NULL);
LineTo(hdc, prcButton->left, prcButton->bottom);
if (!bPressed)
{
SelectObject(hdc, penOld);
pen = (HPEN)MlStockObjects_Get(HEADERBOTTOM_PEN);
penOld = (HPEN)SelectObject(hdc, pen);
}
MoveToEx(hdc, prcButton->right - 1, prcButton->top, NULL);
LineTo(hdc, prcButton->right - 1, prcButton->bottom);
MoveToEx(hdc, prcButton->right - 1, prcButton->bottom - 1, NULL);
LineTo(hdc, prcButton->left - 1, prcButton->bottom - 1);
if (!bPressed)
{
SelectObject(hdc, penOld);
pen = (HPEN)MlStockObjects_Get(HEADERMIDDLE_PEN);
penOld = (HPEN)SelectObject(hdc, pen);
MoveToEx(hdc, prcButton->right - 2, prcButton->top + 1, NULL);
LineTo(hdc, prcButton->right - 2, prcButton->bottom - 2);
MoveToEx(hdc, prcButton->right - 2, prcButton->bottom - 2, NULL);
LineTo(hdc, prcButton->left, prcButton->bottom - 2);
}
SelectObject(hdc, penOld);
}
RECT r;
DWORD arrowSize = SkinnedHeader::GetSortArrowSize();
SetRect(&r, 0, 0, GET_X_LPARAM(arrowSize), GET_Y_LPARAM(arrowSize));
OffsetRect(&r,
prcButton->left + (prcButton->right - prcButton->left - r.right)/2 + (prcButton->right - prcButton->left - r.right)%2,
prcButton->top + (prcButton->bottom - prcButton->top - r.bottom)/2);
if (bPressed) OffsetRect(&r, 1, 1);
if (r.left > (prcButton->left + 1) && r.top > (prcButton->top + 1))
{
SkinnedHeader::DrawSortArrow(hdc, &r, rgbBk, WADlg_getColor(WADLG_LISTHEADER_FONTCOLOR), FALSE);
}
SetBkColor(hdc, rgbBkOld);
}
void SkinnedCombobox::OnPaint()
{
HDC hdc;
PAINTSTRUCT ps;
RECT rc;
COMBOBOXINFO cbi;
BOOL ctrlActive;
if (!GetClientRect(hwnd, &rc) || rc.bottom <= rc.top || rc.right <= rc.left) return;
hdc= BeginPaint(hwnd, &ps);
if (NULL == hdc) return;
ctrlActive = (activeBorder /*|| hwnd == GetFocus()*/);
if (SWCBS_TOOLBAR & style)
{
DrawBorder(hdc, &rc, BORDER_FLAT, (HPEN)MlStockObjects_Get(WNDBCK_PEN));
if (ctrlActive)
{
InflateRect(&rc, -1, -1);
DrawBorder(hdc, &rc, BORDER_FLAT, __super::GetBorderPen());
}
}
else DrawBorder(hdc, &rc, BORDER_FLAT, GetBorderPen());
InflateRect(&rc, -1, -1);
ZeroMemory(&cbi, sizeof(COMBOBOXINFO));
cbi.cbSize = sizeof(COMBOBOXINFO);
if (GetComboBoxInfo(hwnd, &cbi))
{
RECT r;
DWORD ws = GetWindowLongPtrW(hwnd, GWL_STYLE);
SetBkMode(hdc, OPAQUE);
SetBkColor(hdc, WADlg_getColor(WADLG_ITEMBG));
SetRect(&r, rc.left, rc.top, cbi.rcItem.left, rc.bottom);
if (r.left < r.right) ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &r, L"", 0, NULL);
SetRect(&r, cbi.rcItem.left, rc.top, cbi.rcItem.right, cbi.rcItem.top);
if (r.top < r.bottom) ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &r, L"", 0, NULL);
SetRect(&r, cbi.rcItem.left, cbi.rcItem.bottom, cbi.rcItem.right, rc.bottom);
if (r.top < r.bottom) ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &r, L"", 0, NULL);
if (cbi.rcButton.left != cbi.rcButton.right)
{
SetRect(&r, cbi.rcItem.right, rc.top, cbi.rcButton.left, rc.bottom);
if (r.left < r.right) ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &r, L"", 0, NULL);
SetRect(&r, cbi.rcButton.right, rc.top, rc.right, rc.bottom);
if (r.left < r.right) ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &r, L"", 0, NULL);
SetRect(&r, cbi.rcButton.left, rc.top, cbi.rcButton.right, cbi.rcButton.top);
if (r.top < r.bottom) ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &r, L"", 0, NULL);
SetRect(&r, cbi.rcButton.left, cbi.rcButton.bottom, cbi.rcButton.right, rc.bottom);
if (r.top < r.bottom) ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &r, L"", 0, NULL);
DrawButton(hdc, &cbi.rcButton, IsButtonDown(ws), ctrlActive);
}
else
{
SetRect(&r, cbi.rcItem.right, rc.top, rc.right, rc.bottom);
if (r.left < r.right) ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &r, L"", 0, NULL);
}
if (CBS_DROPDOWNLIST == (0x0F & ws))
{
INT cchText = (INT)SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0);
if (cchText)
{
HFONT hFont, hFontOld;
wchar_t szText[COMBO_TEXT_MAX] = {0};
SendMessageW(hwnd, WM_GETTEXT, (WPARAM)COMBO_TEXT_MAX, (LPARAM)szText);
hFont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0L);
if (!hFont) hFont = (HFONT)MlStockObjects_Get(DEFAULT_FONT);
hFontOld = (hFont) ? (HFONT)SelectObject(hdc, hFont) : NULL;
COLORREF rgbText;
BOOL bFocused = (hwnd == GetFocus() && !SendMessageW(hwnd, CB_GETDROPPEDSTATE, 0, 0L));
if (bFocused && 0 == (SWCBS_TOOLBAR & style))
{
rgbText = WADlg_getColor(WADLG_SELBAR_FGCOLOR);
SetBkColor(hdc, WADlg_getColor(WADLG_SELBAR_BGCOLOR));
}
else rgbText = WADlg_getColor(WADLG_ITEMFG);
if(!IsWindowEnabled(hwnd))
{
COLORREF rgbBack = GetBkColor(hdc);
rgbText = RGB((GetRValue(rgbText)+GetRValue(rgbBack))/2,
(GetGValue(rgbText)+GetGValue(rgbBack))/2,
(GetBValue(rgbText)+GetBValue(rgbBack))/2);
}
SetTextColor(hdc, rgbText);
ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &cbi.rcItem, L"", 0, NULL);
if (bFocused &&
0 == (0x01/*UISF_HIDEFOCUS*/ & uiState) &&
0 == (SWCBS_TOOLBAR & style))
{
COLORREF fg, bk;
fg = SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
bk = SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
DrawFocusRect(hdc, &cbi.rcItem);
SetTextColor(hdc, fg);
SetBkColor(hdc, bk);
}
InflateRect(&cbi.rcItem, -1, -1);
DrawTextW(hdc, szText, min(cchText,COMBO_TEXT_MAX), &cbi.rcItem, DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER);
if (hFontOld) SelectObject(hdc, hFontOld);
}
else
{
ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &cbi.rcItem, L"", 0, NULL);
}
}
}
EndPaint(hwnd, &ps);
}
void SkinnedCombobox::OnSkinUpdated(BOOL bNotifyChildren, BOOL bRedraw)
{
__super::OnSkinUpdated(bNotifyChildren, bRedraw);
if (SWS_USESKINFONT & style)
{
if (0 == (CBS_OWNERDRAWVARIABLE & GetWindowLongPtrW(hwnd, GWL_STYLE)))
{
HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS);
HFONT hf, hfo;
TEXTMETRIC tm;
hf = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0L);
if (NULL == hf) hf = (HFONT)MlStockObjects_Get(DEFAULT_FONT);
hfo = (HFONT)SelectObject(hdc, hf);
GetTextMetrics(hdc, &tm);
SendMessageW(hwnd, CB_SETITEMHEIGHT, -1, tm.tmHeight + 2);
SendMessageW(hwnd, CB_SETITEMHEIGHT, 0, tm.tmHeight + 2);
SelectObject(hdc, hfo);
ReleaseDC(hwnd, hdc);
}
}
}
INT SkinnedCombobox::OnNcHitTest(POINTS pts)
{
INT ht = __super::OnNcHitTest(pts);
if (ht > 0 && !activeBorder && (SWCBS_TOOLBAR & style) && IsChild(GetActiveWindow(), hwnd))
{
TRACKMOUSEEVENT track;
track.cbSize = sizeof(TRACKMOUSEEVENT);
track.dwFlags = TME_LEAVE;
track.hwndTrack = hwnd;
TrackMouseEvent(&track);
activeBorder = TRUE;
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
}
return ht;
}
void SkinnedCombobox::OnMouseLeave(void)
{
if (!activeBorder) return;
COMBOBOXINFO cbi;
ZeroMemory(&cbi, sizeof(COMBOBOXINFO));
cbi.cbSize = sizeof(COMBOBOXINFO);
if (GetComboBoxInfo(hwnd, &cbi) && IsWindowVisible(cbi.hwndList))
return;
activeBorder = FALSE;
if (SWCBS_TOOLBAR & style)
{
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
}
}
LRESULT SkinnedCombobox::SilenceMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT result;
UpdateWindow(hwnd);
CallDefWndProc(WM_SETREDRAW, FALSE, 0L);
result = __super::WindowProc(uMsg, wParam, lParam);
CallDefWndProc(WM_SETREDRAW, TRUE, 0L);
InvalidateRect(hwnd, NULL, TRUE);
return result;
}
static HWND hwndPreviousFocus = NULL;
LRESULT SkinnedCombobox::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (SWCBS_TOOLBAR & style)
{
switch(uMsg)
{
case WM_SETFOCUS:
hwndPreviousFocus = (HWND)wParam;
break;
case REFLECTED_COMMAND:
switch(HIWORD(wParam))
{
case CBN_CLOSEUP:
{
if (NULL != hwndPreviousFocus && hwnd == GetFocus())
{
do
{
if (IsWindowVisible(hwndPreviousFocus) && IsWindowEnabled(hwndPreviousFocus))
{
SetFocus(hwndPreviousFocus);
break;
}
} while (NULL != (hwndPreviousFocus = GetAncestor(hwndPreviousFocus, GA_PARENT)));
}
hwndPreviousFocus = NULL;
}
break;
}
break;
}
}
if (SWS_USESKINCOLORS & style)
{
switch(uMsg)
{
case WM_PAINT: OnPaint(); return 0;
case WM_ERASEBKGND: return 0;
case WM_MOUSELEAVE: OnMouseLeave(); break;
case WM_KILLFOCUS:
case WM_SETFOCUS:
case WM_COMMAND:
case WM_CAPTURECHANGED:
case 0x0128/*WM_UPDATEUISTATE*/:
SilenceMessage(uMsg, wParam, lParam);
return 0;
case WM_LBUTTONUP:
if (activeBorder && (SWCBS_TOOLBAR & style))
{
TRACKMOUSEEVENT track;
track.cbSize = sizeof(TRACKMOUSEEVENT);
track.dwFlags = TME_LEAVE;
track.hwndTrack = hwnd;
TrackMouseEvent(&track);
POINT pt;
pt.x = GET_X_LPARAM(lParam);
pt.y = GET_Y_LPARAM(lParam);
RECT rw;
if (GetWindowRect(hwnd, &rw))
{
MapWindowPoints(hwnd, HWND_DESKTOP, &pt, 1);
if (!PtInRect(&rw, pt))
{
INPUT pi[2];
ZeroMemory(&pi[0], sizeof(INPUT));
pi[0].type = INPUT_MOUSE;
pi[0].mi.dx = pt.x;
pi[0].mi.dy = pt.y;
pi[0].mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTDOWN;
CopyMemory(&pi[1], &pi[0], sizeof(INPUT));
pi[1].mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTUP;
SendInput(2, pi, sizeof(INPUT));
}
}
}
break;
case WM_LBUTTONDOWN:
if (!activeBorder && (SWCBS_TOOLBAR & style))
{
TRACKMOUSEEVENT track;
track.cbSize = sizeof(TRACKMOUSEEVENT);
track.dwFlags = TME_LEAVE;
track.hwndTrack = hwnd;
TrackMouseEvent(&track);
activeBorder = TRUE;
}
break;
}
}
return __super::WindowProc(uMsg, wParam, lParam);
}