From b3ed7bc141773518d46db7d493a15abce16a74f9 Mon Sep 17 00:00:00 2001 From: Cyd Date: Fri, 7 Aug 2026 09:55:10 -0500 Subject: [PATCH] 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) --- RP_L4/RPL4FE.cpp | 87 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/RP_L4/RPL4FE.cpp b/RP_L4/RPL4FE.cpp index c3254d1..34c31b1 100644 --- a/RP_L4/RPL4FE.cpp +++ b/RP_L4/RPL4FE.cpp @@ -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; }