The drop-down boxes stop being Windows-coloured
CBS_OWNERDRAWFIXED only hands over the item area, so while the list rows came out green on black, the closed box kept the system's frame and drop arrow - a white/grey Windows control sitting in the middle of a black panel. The closed box is painted here now: black field, dim green border, bright green text, and a plain green triangle instead of a themed button. The control keeps doing everything else, including dropping its list, so this is a subclass over WM_PAINT rather than a reimplementation. Still system-drawn: the scrollbar inside a dropped list, which only appears on the two lists longer than twelve rows - vehicle and track. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -652,6 +652,83 @@ namespace
|
||||
// The combo id is its group, so CBN_SELCHANGE says which list moved.
|
||||
const int kComboIdBase = 100;
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// CBS_OWNERDRAWFIXED only hands us the item area: the frame around
|
||||
// the closed box and its drop arrow are still drawn by the system,
|
||||
// which lands a white/grey Windows control in the middle of a black
|
||||
// panel. So the closed box is painted here instead - black field,
|
||||
// dim green border, bright green text and arrow - and the control
|
||||
// keeps doing everything else, including the list it drops.
|
||||
//---------------------------------------------------------------
|
||||
WNDPROC gComboProc = NULL;
|
||||
|
||||
LRESULT CALLBACK ComboSubclassProc(
|
||||
HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (message == WM_ERASEBKGND)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (message == WM_PAINT)
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
HDC dc = BeginPaint(hwnd, &ps);
|
||||
|
||||
RECT rc;
|
||||
GetClientRect(hwnd, &rc);
|
||||
|
||||
HBRUSH field = CreateSolidBrush(kBlack);
|
||||
FillRect(dc, &rc, field);
|
||||
DeleteObject(field);
|
||||
|
||||
HBRUSH edge = CreateSolidBrush(kGreenDim);
|
||||
FrameRect(dc, &rc, edge);
|
||||
DeleteObject(edge);
|
||||
|
||||
int arrow_w = rc.bottom - rc.top;
|
||||
|
||||
char text[128];
|
||||
text[0] = '\0';
|
||||
int sel = (int) SendMessageA(hwnd, CB_GETCURSEL, 0, 0);
|
||||
if (sel >= 0)
|
||||
{
|
||||
SendMessageA(hwnd, CB_GETLBTEXT, sel, (LPARAM) text);
|
||||
}
|
||||
|
||||
HFONT font = (HFONT) SendMessageA(hwnd, WM_GETFONT, 0, 0);
|
||||
HGDIOBJ old_font = (font != NULL) ? SelectObject(dc, font) : NULL;
|
||||
SetBkMode(dc, TRANSPARENT);
|
||||
SetTextColor(dc, kGreenBright);
|
||||
|
||||
RECT label = rc;
|
||||
label.left += 6;
|
||||
label.right -= arrow_w;
|
||||
DrawTextA(dc, text, -1, &label,
|
||||
DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
|
||||
|
||||
// the arrow, a plain triangle rather than a themed button
|
||||
int cx = rc.right - arrow_w / 2;
|
||||
int cy = (rc.top + rc.bottom) / 2;
|
||||
int r = arrow_w / 6;
|
||||
POINT tri[3];
|
||||
tri[0].x = cx - r; tri[0].y = cy - r / 2;
|
||||
tri[1].x = cx + r; tri[1].y = cy - r / 2;
|
||||
tri[2].x = cx; tri[2].y = cy + r;
|
||||
HBRUSH tip = CreateSolidBrush(kGreenBright);
|
||||
HGDIOBJ old_brush = SelectObject(dc, tip);
|
||||
HGDIOBJ old_pen = SelectObject(dc, GetStockObject(NULL_PEN));
|
||||
Polygon(dc, tri, 3);
|
||||
SelectObject(dc, old_pen);
|
||||
SelectObject(dc, old_brush);
|
||||
DeleteObject(tip);
|
||||
|
||||
if (old_font != NULL) SelectObject(dc, old_font);
|
||||
EndPaint(hwnd, &ps);
|
||||
return 0;
|
||||
}
|
||||
return CallWindowProcA(gComboProc, hwnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
void DestroyCombos(FEState *fe)
|
||||
{
|
||||
for (int g = 0; g < GroupCount; ++g)
|
||||
@@ -827,6 +904,14 @@ namespace
|
||||
SendMessageA(box, WM_SETFONT, (WPARAM) fe->textFont, TRUE);
|
||||
SendMessageA(box, CB_SETITEMHEIGHT, (WPARAM) -1, row_h);
|
||||
SendMessageA(box, CB_SETITEMHEIGHT, 0, row_h);
|
||||
|
||||
// paint the closed box ourselves - see ComboSubclassProc
|
||||
WNDPROC previous = (WNDPROC) SetWindowLongPtrA(
|
||||
box, GWLP_WNDPROC, (LONG_PTR) ComboSubclassProc);
|
||||
if (gComboProc == NULL)
|
||||
{
|
||||
gComboProc = previous;
|
||||
}
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
SendMessageA(box, CB_ADDSTRING, 0, (LPARAM) ItemName(group, i));
|
||||
@@ -1104,6 +1189,8 @@ namespace
|
||||
{
|
||||
fe->selection[group] = pick;
|
||||
}
|
||||
// the closed box is ours to redraw now
|
||||
InvalidateRect(fe->combo[group], NULL, FALSE);
|
||||
InvalidateRect(fe->menuWindow, NULL, FALSE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user