/* =========================================================================== IceTech GPL Source Code Copyright (C) 2026 Justin Marshall This file is part of the IceTech GPL Source Code (?IceTech Source Code?). IceTech Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. IceTech Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with IceTech Source Code. If not, see . In addition, the IceTech Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the IceTech Source Code. If not, please request a copy in writing from id Software at the address below. If you have questions concerning this license or the applicable additional terms, you may contact in writing Justin Marshall, justinmarshall20@gmail.com =========================================================================== */ #include "precompiled.h" #pragma hdrstop #include "qe3.h" #include "Radiant.h" #include "SurfaceDlg.h" #include "mainfrm.h" #include #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif // -------------------------------------------------------------------------- // IceTech dark MFC/common-control helper // -------------------------------------------------------------------------- #ifndef BS_TYPEMASK #define BS_TYPEMASK 0x0000000F #endif static const COLORREF ICE_DARK_BG = RGB(17, 19, 23); static const COLORREF ICE_DARK_PANEL = RGB(24, 27, 32); static const COLORREF ICE_DARK_PANEL_ALT = RGB(29, 33, 39); static const COLORREF ICE_DARK_FIELD = RGB(14, 16, 20); static const COLORREF ICE_DARK_BORDER = RGB(55, 62, 72); static const COLORREF ICE_DARK_BORDER_HOT = RGB(87, 166, 255); static const COLORREF ICE_DARK_TEXT = RGB(226, 232, 240); static const COLORREF ICE_DARK_TEXT_MUTED = RGB(151, 163, 184); static const COLORREF ICE_DARK_TEXT_DISABLED = RGB(103, 112, 128); static const COLORREF ICE_DARK_ACCENT = RGB(87, 166, 255); static const char* ICE_DARK_PARENT_OLDPROC = "IceTech.Dark.ParentOldProc"; static const char* ICE_DARK_CONTROL_OLDPROC = "IceTech.Dark.ControlOldProc"; static int IceDark_MaxInt(int a, int b) { return (a > b) ? a : b; } static HBRUSH IceDark_BgBrush() { static HBRUSH hBrush = ::CreateSolidBrush(ICE_DARK_BG); return hBrush; } static HBRUSH IceDark_PanelBrush() { static HBRUSH hBrush = ::CreateSolidBrush(ICE_DARK_PANEL); return hBrush; } static HBRUSH IceDark_FieldBrush() { static HBRUSH hBrush = ::CreateSolidBrush(ICE_DARK_FIELD); return hBrush; } static void IceDark_FillRect(HDC hDC, const RECT& rc, COLORREF color) { HBRUSH brush = ::CreateSolidBrush(color); ::FillRect(hDC, &rc, brush); ::DeleteObject(brush); } static void IceDark_FrameRect(HDC hDC, const RECT& rc, COLORREF color) { HBRUSH brush = ::CreateSolidBrush(color); ::FrameRect(hDC, &rc, brush); ::DeleteObject(brush); } static void IceDark_ApplyNativeTheme(HWND hWnd) { if (!hWnd) { return; } typedef HRESULT (WINAPI *SetWindowThemeProc)(HWND, LPCWSTR, LPCWSTR); typedef BOOL (WINAPI *AllowDarkModeForWindowProc)(HWND, BOOL); static HMODULE hUxTheme = ::LoadLibraryA("uxtheme.dll"); static SetWindowThemeProc pSetWindowTheme = hUxTheme ? (SetWindowThemeProc)::GetProcAddress(hUxTheme, "SetWindowTheme") : NULL; static AllowDarkModeForWindowProc pAllowDarkModeForWindow = hUxTheme ? (AllowDarkModeForWindowProc)::GetProcAddress(hUxTheme, MAKEINTRESOURCEA(133)) : NULL; if (pAllowDarkModeForWindow) { pAllowDarkModeForWindow(hWnd, TRUE); } if (pSetWindowTheme) { pSetWindowTheme(hWnd, L"DarkMode_Explorer", NULL); } ::SendMessage(hWnd, WM_THEMECHANGED, 0, 0); } static void IceDark_RemoveClientEdge(HWND hWnd) { if (!hWnd) { return; } LONG exStyle = ::GetWindowLong(hWnd, GWL_EXSTYLE); if (exStyle & WS_EX_CLIENTEDGE) { ::SetWindowLong(hWnd, GWL_EXSTYLE, exStyle & ~WS_EX_CLIENTEDGE); ::SetWindowPos(hWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED); } } static void IceDark_DrawFrame(HWND hWnd, COLORREF color) { HDC hDC = ::GetWindowDC(hWnd); if (!hDC) { return; } RECT rc; ::GetWindowRect(hWnd, &rc); ::OffsetRect(&rc, -rc.left, -rc.top); IceDark_FrameRect(hDC, rc, color); ::ReleaseDC(hWnd, hDC); } static void IceDark_DrawButton(HWND hWnd, HDC hDC) { RECT rc; ::GetClientRect(hWnd, &rc); const UINT style = (UINT)::GetWindowLong(hWnd, GWL_STYLE); const UINT type = style & BS_TYPEMASK; const bool enabled = ::IsWindowEnabled(hWnd) ? true : false; const bool pushed = (::SendMessage(hWnd, BM_GETSTATE, 0, 0) & BST_PUSHED) != 0; const bool checked = (::SendMessage(hWnd, BM_GETCHECK, 0, 0) == BST_CHECKED); const bool isCheck = (type == BS_CHECKBOX || type == BS_AUTOCHECKBOX || type == BS_3STATE || type == BS_AUTO3STATE); const bool isRadio = (type == BS_RADIOBUTTON || type == BS_AUTORADIOBUTTON); const bool isGroup = (type == BS_GROUPBOX); char text[512]; text[0] = '\0'; ::GetWindowTextA(hWnd, text, sizeof(text)); HFONT font = (HFONT)::SendMessage(hWnd, WM_GETFONT, 0, 0); HFONT oldFont = font ? (HFONT)::SelectObject(hDC, font) : NULL; ::SetBkMode(hDC, TRANSPARENT); ::SetTextColor(hDC, enabled ? ICE_DARK_TEXT : ICE_DARK_TEXT_DISABLED); if (isGroup) { IceDark_FillRect(hDC, rc, ICE_DARK_BG); RECT textRect = rc; textRect.left += 10; textRect.right -= 8; textRect.bottom = textRect.top + 18; SIZE textSize; textSize.cx = textSize.cy = 0; ::GetTextExtentPoint32A(hDC, text, (int)strlen(text), &textSize); RECT frame = rc; frame.top += 8; HPEN pen = ::CreatePen(PS_SOLID, 1, ICE_DARK_BORDER); HPEN oldPen = (HPEN)::SelectObject(hDC, pen); HBRUSH oldBrush = (HBRUSH)::SelectObject(hDC, ::GetStockObject(NULL_BRUSH)); ::RoundRect(hDC, frame.left, frame.top, frame.right, frame.bottom, 8, 8); ::SelectObject(hDC, oldBrush); ::SelectObject(hDC, oldPen); ::DeleteObject(pen); RECT fillLabel = textRect; fillLabel.right = fillLabel.left + textSize.cx + 8; IceDark_FillRect(hDC, fillLabel, ICE_DARK_BG); ::SetTextColor(hDC, ICE_DARK_TEXT_MUTED); ::DrawTextA(hDC, text, -1, &textRect, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_END_ELLIPSIS); } else if (isCheck || isRadio) { IceDark_FillRect(hDC, rc, ICE_DARK_BG); RECT box = rc; box.left += 3; box.right = box.left + 15; box.top += IceDark_MaxInt(0, (rc.bottom - rc.top - 15) / 2); box.bottom = box.top + 15; if (isRadio) { HPEN pen = ::CreatePen(PS_SOLID, 1, checked ? ICE_DARK_ACCENT : ICE_DARK_BORDER); HPEN oldPen = (HPEN)::SelectObject(hDC, pen); HBRUSH brush = ::CreateSolidBrush(enabled ? ICE_DARK_FIELD : RGB(20, 22, 26)); HBRUSH oldBrush = (HBRUSH)::SelectObject(hDC, brush); ::Ellipse(hDC, box.left, box.top, box.right, box.bottom); ::SelectObject(hDC, oldBrush); ::DeleteObject(brush); ::SelectObject(hDC, oldPen); ::DeleteObject(pen); if (checked) { RECT dot = box; ::InflateRect(&dot, -4, -4); HBRUSH dotBrush = ::CreateSolidBrush(enabled ? ICE_DARK_ACCENT : ICE_DARK_TEXT_DISABLED); HBRUSH oldDotBrush = (HBRUSH)::SelectObject(hDC, dotBrush); HPEN dotPen = ::CreatePen(PS_SOLID, 1, enabled ? ICE_DARK_ACCENT : ICE_DARK_TEXT_DISABLED); HPEN oldDotPen = (HPEN)::SelectObject(hDC, dotPen); ::Ellipse(hDC, dot.left, dot.top, dot.right, dot.bottom); ::SelectObject(hDC, oldDotPen); ::DeleteObject(dotPen); ::SelectObject(hDC, oldDotBrush); ::DeleteObject(dotBrush); } } else { IceDark_FillRect(hDC, box, enabled ? ICE_DARK_FIELD : RGB(20, 22, 26)); IceDark_FrameRect(hDC, box, checked ? ICE_DARK_ACCENT : ICE_DARK_BORDER); if (checked) { HPEN pen = ::CreatePen(PS_SOLID, 2, enabled ? ICE_DARK_ACCENT : ICE_DARK_TEXT_DISABLED); HPEN oldPen = (HPEN)::SelectObject(hDC, pen); ::MoveToEx(hDC, box.left + 3, box.top + 7, NULL); ::LineTo(hDC, box.left + 6, box.top + 10); ::LineTo(hDC, box.right - 3, box.top + 3); ::SelectObject(hDC, oldPen); ::DeleteObject(pen); } } RECT textRect = rc; textRect.left = box.right + 7; textRect.right -= 2; ::DrawTextA(hDC, text, -1, &textRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS); } else { COLORREF face = pushed ? RGB(22, 25, 30) : ICE_DARK_PANEL_ALT; IceDark_FillRect(hDC, rc, face); IceDark_FrameRect(hDC, rc, enabled ? ICE_DARK_BORDER : RGB(39, 44, 52)); RECT inner = rc; ::InflateRect(&inner, -1, -1); if (!pushed) { IceDark_FrameRect(hDC, inner, RGB(35, 40, 47)); } RECT textRect = rc; if (pushed) { ::OffsetRect(&textRect, 1, 1); } ::DrawTextA(hDC, text, -1, &textRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS); } if (oldFont) { ::SelectObject(hDC, oldFont); } } static LRESULT CALLBACK IceDark_ButtonProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { WNDPROC oldProc = (WNDPROC)::GetPropA(hWnd, ICE_DARK_CONTROL_OLDPROC); if (!oldProc) { return ::DefWindowProc(hWnd, uMsg, wParam, lParam); } switch (uMsg) { case WM_ERASEBKGND: return 1; case WM_PAINT: { UINT style = (UINT)::GetWindowLong(hWnd, GWL_STYLE); if (style & (BS_BITMAP | BS_ICON)) { LRESULT result = ::CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam); IceDark_DrawFrame(hWnd, ICE_DARK_BORDER); return result; } PAINTSTRUCT ps; HDC hDC = ::BeginPaint(hWnd, &ps); IceDark_DrawButton(hWnd, hDC); ::EndPaint(hWnd, &ps); return 0; } case WM_PRINTCLIENT: IceDark_DrawButton(hWnd, (HDC)wParam); return 0; case WM_MOUSEMOVE: case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_ENABLE: case WM_SETTEXT: case BM_SETCHECK: case BM_SETSTATE: { LRESULT result = ::CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam); ::InvalidateRect(hWnd, NULL, FALSE); return result; } case WM_NCDESTROY: { ::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldProc); ::RemovePropA(hWnd, ICE_DARK_CONTROL_OLDPROC); return ::CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam); } } return ::CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam); } static void IceDark_DrawCombo(HWND hWnd, HDC hDC) { RECT rc; ::GetClientRect(hWnd, &rc); const bool enabled = ::IsWindowEnabled(hWnd) ? true : false; const bool focused = (::GetFocus() == hWnd || ::IsChild(hWnd, ::GetFocus())) ? true : false; IceDark_FillRect(hDC, rc, enabled ? ICE_DARK_FIELD : RGB(20, 22, 26)); IceDark_FrameRect(hDC, rc, focused ? ICE_DARK_BORDER_HOT : ICE_DARK_BORDER); RECT arrow = rc; arrow.left = arrow.right - 22; IceDark_FillRect(hDC, arrow, ICE_DARK_PANEL_ALT); IceDark_FrameRect(hDC, arrow, ICE_DARK_BORDER); POINT pts[3]; int cx = arrow.left + (arrow.right - arrow.left) / 2; int cy = arrow.top + (arrow.bottom - arrow.top) / 2 + 1; pts[0].x = cx - 4; pts[0].y = cy - 2; pts[1].x = cx + 4; pts[1].y = cy - 2; pts[2].x = cx; pts[2].y = cy + 3; HBRUSH arrowBrush = ::CreateSolidBrush(enabled ? ICE_DARK_TEXT : ICE_DARK_TEXT_DISABLED); HBRUSH oldBrush = (HBRUSH)::SelectObject(hDC, arrowBrush); HPEN arrowPen = ::CreatePen(PS_SOLID, 1, enabled ? ICE_DARK_TEXT : ICE_DARK_TEXT_DISABLED); HPEN oldPen = (HPEN)::SelectObject(hDC, arrowPen); ::Polygon(hDC, pts, 3); ::SelectObject(hDC, oldPen); ::DeleteObject(arrowPen); ::SelectObject(hDC, oldBrush); ::DeleteObject(arrowBrush); char text[512]; text[0] = '\0'; int sel = (int)::SendMessage(hWnd, CB_GETCURSEL, 0, 0); if (sel >= 0) { ::SendMessageA(hWnd, CB_GETLBTEXT, (WPARAM)sel, (LPARAM)text); } else { ::GetWindowTextA(hWnd, text, sizeof(text)); } HFONT font = (HFONT)::SendMessage(hWnd, WM_GETFONT, 0, 0); HFONT oldFont = font ? (HFONT)::SelectObject(hDC, font) : NULL; ::SetBkMode(hDC, TRANSPARENT); ::SetTextColor(hDC, enabled ? ICE_DARK_TEXT : ICE_DARK_TEXT_DISABLED); RECT textRect = rc; textRect.left += 7; textRect.right = arrow.left - 3; ::DrawTextA(hDC, text, -1, &textRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS); if (oldFont) { ::SelectObject(hDC, oldFont); } } static LRESULT CALLBACK IceDark_ComboProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { WNDPROC oldProc = (WNDPROC)::GetPropA(hWnd, ICE_DARK_CONTROL_OLDPROC); if (!oldProc) { return ::DefWindowProc(hWnd, uMsg, wParam, lParam); } switch (uMsg) { case WM_ERASEBKGND: return 1; case WM_PAINT: { UINT comboType = (UINT)::GetWindowLong(hWnd, GWL_STYLE) & 0x00000003; if (comboType == CBS_DROPDOWNLIST) { PAINTSTRUCT ps; HDC hDC = ::BeginPaint(hWnd, &ps); IceDark_DrawCombo(hWnd, hDC); ::EndPaint(hWnd, &ps); return 0; } LRESULT result = ::CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam); IceDark_DrawFrame(hWnd, (::GetFocus() == hWnd || ::IsChild(hWnd, ::GetFocus())) ? ICE_DARK_BORDER_HOT : ICE_DARK_BORDER); return result; } case WM_SETFOCUS: case WM_KILLFOCUS: case WM_ENABLE: case WM_SETTEXT: case CB_SETCURSEL: case CB_ADDSTRING: case CB_DELETESTRING: case CB_RESETCONTENT: { LRESULT result = ::CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam); ::InvalidateRect(hWnd, NULL, FALSE); return result; } case WM_NCDESTROY: { ::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldProc); ::RemovePropA(hWnd, ICE_DARK_CONTROL_OLDPROC); return ::CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam); } } return ::CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam); } static LRESULT CALLBACK IceDark_FieldProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { WNDPROC oldProc = (WNDPROC)::GetPropA(hWnd, ICE_DARK_CONTROL_OLDPROC); if (!oldProc) { return ::DefWindowProc(hWnd, uMsg, wParam, lParam); } switch (uMsg) { case WM_NCPAINT: case WM_PAINT: { LRESULT result = ::CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam); IceDark_DrawFrame(hWnd, (::GetFocus() == hWnd) ? ICE_DARK_BORDER_HOT : ICE_DARK_BORDER); return result; } case WM_SETFOCUS: case WM_KILLFOCUS: case WM_ENABLE: { LRESULT result = ::CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam); ::RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_UPDATENOW); return result; } case WM_NCDESTROY: { ::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldProc); ::RemovePropA(hWnd, ICE_DARK_CONTROL_OLDPROC); return ::CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam); } } return ::CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam); } static LRESULT CALLBACK IceDark_ParentProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { WNDPROC oldProc = (WNDPROC)::GetPropA(hWnd, ICE_DARK_PARENT_OLDPROC); if (!oldProc) { return ::DefWindowProc(hWnd, uMsg, wParam, lParam); } switch (uMsg) { case WM_ERASEBKGND: { RECT rc; ::GetClientRect(hWnd, &rc); IceDark_FillRect((HDC)wParam, rc, ICE_DARK_BG); return 1; } case WM_CTLCOLORDLG: return (LRESULT)IceDark_BgBrush(); case WM_CTLCOLORSTATIC: { HDC hDC = (HDC)wParam; ::SetTextColor(hDC, ICE_DARK_TEXT_MUTED); ::SetBkMode(hDC, TRANSPARENT); return (LRESULT)IceDark_BgBrush(); } case WM_CTLCOLOREDIT: case WM_CTLCOLORLISTBOX: { HDC hDC = (HDC)wParam; ::SetTextColor(hDC, ICE_DARK_TEXT); ::SetBkColor(hDC, ICE_DARK_FIELD); return (LRESULT)IceDark_FieldBrush(); } case WM_CTLCOLORBTN: { HDC hDC = (HDC)wParam; ::SetTextColor(hDC, ICE_DARK_TEXT); ::SetBkColor(hDC, ICE_DARK_BG); return (LRESULT)IceDark_BgBrush(); } case WM_NCDESTROY: { ::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldProc); ::RemovePropA(hWnd, ICE_DARK_PARENT_OLDPROC); return ::CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam); } } return ::CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam); } static void IceDark_Subclass(HWND hWnd, WNDPROC proc, const char* propName) { if (!hWnd || ::GetPropA(hWnd, propName)) { return; } WNDPROC oldProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_WNDPROC); ::SetPropA(hWnd, propName, (HANDLE)oldProc); ::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)proc); } static bool IceDark_IsClass(HWND hWnd, const char* className) { char actual[128]; actual[0] = '\0'; ::GetClassNameA(hWnd, actual, sizeof(actual)); return ::lstrcmpiA(actual, className) == 0; } static bool IceDark_IsKnownControl(HWND hWnd) { return IceDark_IsClass(hWnd, "Button") || IceDark_IsClass(hWnd, "Edit") || IceDark_IsClass(hWnd, "ComboBox") || IceDark_IsClass(hWnd, "ListBox") || IceDark_IsClass(hWnd, "SysTreeView32") || IceDark_IsClass(hWnd, "SysListView32") || IceDark_IsClass(hWnd, "msctls_trackbar32") || IceDark_IsClass(hWnd, "msctls_updown32") || IceDark_IsClass(hWnd, "ScrollBar") || IceDark_IsClass(hWnd, "SysTabControl32"); } static void IceDark_ApplyToWindowAndChildren(HWND hWnd) { if (!hWnd) { return; } IceDark_ApplyNativeTheme(hWnd); IceDark_RemoveClientEdge(hWnd); if (IceDark_IsClass(hWnd, "Button")) { IceDark_Subclass(hWnd, IceDark_ButtonProc, ICE_DARK_CONTROL_OLDPROC); } else if (IceDark_IsClass(hWnd, "ComboBox")) { IceDark_Subclass(hWnd, IceDark_ComboProc, ICE_DARK_CONTROL_OLDPROC); } else if (IceDark_IsClass(hWnd, "Edit") || IceDark_IsClass(hWnd, "ListBox") || IceDark_IsClass(hWnd, "SysTreeView32") || IceDark_IsClass(hWnd, "SysListView32")) { IceDark_Subclass(hWnd, IceDark_FieldProc, ICE_DARK_CONTROL_OLDPROC); } else if (!IceDark_IsKnownControl(hWnd)) { IceDark_Subclass(hWnd, IceDark_ParentProc, ICE_DARK_PARENT_OLDPROC); } if (IceDark_IsClass(hWnd, "SysTreeView32")) { ::SendMessage(hWnd, TVM_SETBKCOLOR, 0, (LPARAM)ICE_DARK_FIELD); ::SendMessage(hWnd, TVM_SETTEXTCOLOR, 0, (LPARAM)ICE_DARK_TEXT); } if (IceDark_IsClass(hWnd, "SysListView32")) { ::SendMessage(hWnd, LVM_SETBKCOLOR, 0, (LPARAM)ICE_DARK_FIELD); ::SendMessage(hWnd, LVM_SETTEXTBKCOLOR, 0, (LPARAM)ICE_DARK_FIELD); ::SendMessage(hWnd, LVM_SETTEXTCOLOR, 0, (LPARAM)ICE_DARK_TEXT); } for (HWND child = ::GetWindow(hWnd, GW_CHILD); child != NULL; child = ::GetWindow(child, GW_HWNDNEXT)) { IceDark_ApplyToWindowAndChildren(child); } ::InvalidateRect(hWnd, NULL, TRUE); } static void IceDark_ApplyToDialog(CWnd* wnd) { if (wnd && wnd->GetSafeHwnd()) { IceDark_ApplyToWindowAndChildren(wnd->GetSafeHwnd()); } } ///////////////////////////////////////////////////////////////////////////// // CSurfaceDlg dialog CSurfaceDlg g_dlgSurface; CSurfaceDlg::CSurfaceDlg(CWnd* pParent /*=NULL*/) : CDialog(CSurfaceDlg::IDD, pParent) { //{{AFX_DATA_INIT(CSurfaceDlg) m_nHorz = 3; m_nVert = 3; m_horzScale = 1.0f; m_horzShift = 0.5f; m_rotate = 15.0f; m_vertScale = 1.0f; m_vertShift = 0.5f; m_strMaterial = _T(""); m_subdivide = FALSE; m_fHeight = 1.0f; m_fWidth = 1.0f; m_absolute = FALSE; //}}AFX_DATA_INIT } void CSurfaceDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CSurfaceDlg) DDX_Control(pDX, IDC_ROTATE, m_wndRotateEdit); DDX_Control(pDX, IDC_EDIT_VERT, m_wndVert); DDX_Control(pDX, IDC_EDIT_HORZ, m_wndHorz); DDX_Control(pDX, IDC_SLIDER_VERT, m_wndVerticalSubdivisions); DDX_Control(pDX, IDC_SLIDER_HORZ, m_wndHorzSubdivisions); DDX_Control(pDX, IDC_SPIN_WIDTH, m_wndWidth); DDX_Control(pDX, IDC_SPIN_HEIGHT, m_wndHeight); DDX_Control(pDX, IDC_SPIN_VSHIFT, m_wndVShift); DDX_Control(pDX, IDC_SPIN_ROTATE, m_wndRotate); DDX_Control(pDX, IDC_SPIN_HSHIFT, m_wndHShift); DDX_Text(pDX, IDC_EDIT_HORZ, m_nHorz); DDV_MinMaxInt(pDX, m_nHorz, 1, 64); DDX_Text(pDX, IDC_EDIT_VERT, m_nVert); DDV_MinMaxInt(pDX, m_nVert, 1, 64); DDX_Text(pDX, IDC_HSCALE, m_horzScale); DDX_Text(pDX, IDC_HSHIFT, m_horzShift); DDX_Text(pDX, IDC_ROTATE, m_rotate); DDX_Text(pDX, IDC_VSCALE, m_vertScale); DDX_Text(pDX, IDC_VSHIFT, m_vertShift); DDX_Text(pDX, IDC_TEXTURE, m_strMaterial); DDX_Check(pDX, IDC_CHECK_SUBDIVIDE, m_subdivide); DDX_Text(pDX, IDC_EDIT_HEIGHT, m_fHeight); DDX_Text(pDX, IDC_EDIT_WIDTH, m_fWidth); DDX_Check(pDX, IDC_CHECK_ABSOLUTE, m_absolute); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CSurfaceDlg, CDialog) //{{AFX_MSG_MAP(CSurfaceDlg) ON_WM_HSCROLL() ON_WM_KEYDOWN() ON_WM_VSCROLL() ON_WM_CLOSE() ON_WM_DESTROY() ON_BN_CLICKED(IDCANCEL, OnBtnCancel) ON_BN_CLICKED(IDC_BTN_COLOR, OnBtnColor) ON_WM_CTLCOLOR() ON_WM_CREATE() ON_NOTIFY(UDN_DELTAPOS, IDC_SPIN_HSHIFT, OnDeltaPosSpin) ON_BN_CLICKED(IDC_BTN_PATCHDETAILS, OnBtnPatchdetails) ON_BN_CLICKED(IDC_BTN_PATCHNATURAL, OnBtnPatchnatural) ON_BN_CLICKED(IDC_BTN_PATCHRESET, OnBtnPatchreset) ON_BN_CLICKED(IDC_BTN_AXIAL, OnBtnAxial) ON_BN_CLICKED(IDC_BTN_BRUSHFIT, OnBtnBrushfit) ON_BN_CLICKED(IDC_BTN_FACEFIT, OnBtnFacefit) ON_BN_CLICKED(IDC_CHECK_SUBDIVIDE, OnCheckSubdivide) ON_EN_CHANGE(IDC_EDIT_HORZ, OnChangeEditHorz) ON_EN_CHANGE(IDC_EDIT_VERT, OnChangeEditVert) ON_EN_SETFOCUS(IDC_HSCALE, OnSetfocusHscale) ON_EN_KILLFOCUS(IDC_HSCALE, OnKillfocusHscale) ON_EN_KILLFOCUS(IDC_VSCALE, OnKillfocusVscale) ON_EN_SETFOCUS(IDC_VSCALE, OnSetfocusVscale) ON_EN_KILLFOCUS(IDC_EDIT_WIDTH, OnKillfocusEditWidth) ON_EN_SETFOCUS(IDC_EDIT_WIDTH, OnSetfocusEditWidth) ON_EN_KILLFOCUS(IDC_EDIT_HEIGHT, OnKillfocusEditHeight) ON_EN_SETFOCUS(IDC_EDIT_HEIGHT, OnSetfocusEditHeight) ON_BN_CLICKED(IDC_BTN_FLIPX, OnBtnFlipx) ON_BN_CLICKED(IDC_BTN_FLIPY, OnBtnFlipy) ON_NOTIFY(UDN_DELTAPOS, IDC_SPIN_ROTATE, OnDeltaPosSpin) ON_NOTIFY(UDN_DELTAPOS, IDC_SPIN_VSHIFT, OnDeltaPosSpin) ON_EN_KILLFOCUS(IDC_ROTATE, OnKillfocusRotate) ON_EN_SETFOCUS(IDC_ROTATE, OnSetfocusRotate) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CSurfaceDlg message handlers /* =================================================== SURFACE INSPECTOR =================================================== */ texdef_t g_old_texdef; texdef_t g_patch_texdef; HWND g_surfwin = NULL; bool g_changed_surface; /* ============== SetTexMods Set the fields to the current texdef if one face selected -> will read this face texdef, else current texdef if only patches selected, will read the patch texdef =============== */ extern void Face_GetScale_BrushPrimit(face_t *face, float *s, float *t, float *rot); void CSurfaceDlg::SetTexMods() { UpdateData(TRUE); // Default to the current texture window material. m_strMaterial = g_qeglobals.d_texturewin.texdef.name; patchMesh_t* p = SinglePatchSelected(); if (p) { m_subdivide = p->explicitSubdivisions; if (p->d_texture) { m_strMaterial = p->d_texture->GetName(); } m_horzScale = 1.0f; m_vertScale = 1.0f; UpdateData(FALSE); return; } m_subdivide = false; int faceCount = g_ptrSelectedFaces.GetSize(); face_t* selFace = NULL; if (faceCount) { selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(0)); } else { if (selected_brushes.next != &selected_brushes) { brush_t* b = selected_brushes.next; if (!b->pPatch) { selFace = b->brush_faces; } } } if (selFace) { // Fill the surface material textbox with the selected face material. if (selFace->d_texture) { m_strMaterial = selFace->d_texture->GetName(); } else if (selFace->texdef.name[0]) { m_strMaterial = selFace->texdef.name; } float rot; Face_GetScale_BrushPrimit(selFace, &m_horzScale, &m_vertScale, &rot); } else { m_horzScale = 1.0f; m_vertScale = 1.0f; } UpdateData(FALSE); } bool g_bNewFace = false; bool g_bNewApplyHandling = false; bool g_bGatewayhack = false; /* ================= UpdateSpinners ================= */ void CSurfaceDlg::UpdateSpinners(bool up, int nID) { UpdateData(TRUE); float hdiv = 0.0f; float vdiv = 0.0f; switch (nID) { case IDC_SPIN_ROTATE : Select_RotateTexture((up) ? m_rotate : -m_rotate); break; case IDC_SPIN_HSCALE : m_horzScale += (up) ? 0.1f : -0.1f; hdiv = (m_horzScale == 0.0f) ? 1.0f : m_horzScale; Select_ScaleTexture( 1.0f / hdiv, 0.0f, true, ( m_absolute != FALSE ) ); UpdateData(FALSE); break; case IDC_SPIN_VSCALE : m_vertScale += (up) ? 0.1f : -0.1f; vdiv = (m_vertScale == 0.0f) ? 1.0f : m_vertScale; Select_ScaleTexture( 0.0f, 1.0f / vdiv, true, ( m_absolute != FALSE ) ); UpdateData(FALSE); break; case IDC_SPIN_HSHIFT : Select_ShiftTexture((up) ? m_horzShift : -m_horzShift, 0); break; case IDC_SPIN_VSHIFT : Select_ShiftTexture(0, (up) ? m_vertShift : -m_vertShift); break; } g_changed_surface = true; } void CSurfaceDlg::UpdateSpinners(int nScrollCode, int nPos, CScrollBar* pBar) { return; UpdateData(TRUE); if ((nScrollCode != SB_LINEUP) && (nScrollCode != SB_LINEDOWN)) { return; } bool up = (nScrollCode == SB_LINEUP); // FIXME: bad resource define #define IDC_ROTATEA 0 #define IDC_HSCALEA 0 #define IDC_VSCALEA 0 #define IDC_HSHIFTA 0 #define IDC_VSHIFTA 0 if (pBar->GetSafeHwnd() == ::GetDlgItem(GetSafeHwnd(), IDC_ROTATEA)) { Select_RotateTexture((up) ? m_rotate : -m_rotate); } else if (pBar->GetSafeHwnd() == ::GetDlgItem(GetSafeHwnd(), IDC_HSCALEA)) { Select_ScaleTexture((up) ? -m_horzScale : m_horzScale, 0, true, ( m_absolute != FALSE ) ); } else if (pBar->GetSafeHwnd() == ::GetDlgItem(GetSafeHwnd(), IDC_VSCALEA)) { Select_ScaleTexture(0, (up) ? -m_vertScale : m_vertScale, true, ( m_absolute != FALSE ) ); } else if (pBar->GetSafeHwnd() == ::GetDlgItem(GetSafeHwnd(), IDC_HSHIFTA)) { Select_ShiftTexture((up) ? -m_horzShift : m_horzShift, 0); } else if (pBar->GetSafeHwnd() == ::GetDlgItem(GetSafeHwnd(), IDC_VSHIFTA)) { Select_ShiftTexture((up) ? -m_vertShift : m_vertShift, 0); } g_changed_surface = true; } void UpdateSurfaceDialog() { if (g_surfwin) { g_dlgSurface.SetTexMods(); } g_pParentWnd->UpdateTextureBar(); } bool ByeByeSurfaceDialog(); void DoSurface (void) { g_bNewFace = ( g_PrefsDlg.m_bFace != FALSE ); g_bNewApplyHandling = ( g_PrefsDlg.m_bNewApplyHandling != FALSE ); g_bGatewayhack = ( g_PrefsDlg.m_bGatewayHack != FALSE ); // save current state for cancel g_old_texdef = g_qeglobals.d_texturewin.texdef; g_changed_surface = false; if (g_surfwin == NULL && g_dlgSurface.GetSafeHwnd() == NULL) { g_patch_texdef.scale[0] = 0.05f; g_patch_texdef.scale[1] = 0.05f; g_patch_texdef.shift[0] = 0.05f; g_patch_texdef.shift[1] = 0.05f; // use rotation increment from preferences g_patch_texdef.rotate = g_PrefsDlg.m_nRotation; g_dlgSurface.Create(IDD_SURFACE); CRect rct; LONG lSize = sizeof(rct); if (LoadRegistryInfo("radiant_SurfaceWindow", &rct, &lSize)) { g_dlgSurface.SetWindowPos( NULL, rct.left, rct.top, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW ); } g_dlgSurface.ShowWindow(SW_SHOW); Sys_UpdateWindows(W_ALL); } else { g_surfwin = g_dlgSurface.GetSafeHwnd(); g_dlgSurface.SetTexMods (); g_dlgSurface.ShowWindow(SW_SHOW); } } bool ByeByeSurfaceDialog() { if (g_surfwin) { if (g_bGatewayhack) { PostMessage(g_surfwin, WM_COMMAND, IDC_APPLY, 0); } else { PostMessage(g_surfwin, WM_COMMAND, IDCANCEL, 0); } return true; } else { return false; } } BOOL CSurfaceDlg::OnInitDialog() { CDialog::OnInitDialog(); IceDark_ApplyToDialog(this); g_surfwin = GetSafeHwnd(); SetTexMods (); //m_wndHScale.SetRange(0, 100); //m_wndVScale.SetRange(0, 100); m_wndHShift.SetRange(0, 100); m_wndVShift.SetRange(0, 100); m_wndRotate.SetRange(0, 100); m_wndWidth.SetRange(1, 32); m_wndHeight.SetRange(1, 32); m_wndVerticalSubdivisions.SetRange(1, 32); m_wndVerticalSubdivisions.SetBuddy(&m_wndVert, FALSE); m_wndHorzSubdivisions.SetRange(1, 32); m_wndHorzSubdivisions.SetBuddy(&m_wndHorz, FALSE); m_wndVerticalSubdivisions.SetPos(m_nVert); m_wndHorzSubdivisions.SetPos(m_nHorz); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } void CSurfaceDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { UpdateData(TRUE); if (pScrollBar->IsKindOf(RUNTIME_CLASS(CSliderCtrl))) { CSliderCtrl *ctrl = reinterpret_cast(pScrollBar); assert(ctrl); if (ctrl == &m_wndVerticalSubdivisions) { m_nVert = ctrl->GetPos(); } else { m_nHorz = ctrl->GetPos(); } UpdateData(FALSE); if (m_subdivide) { Patch_SubdivideSelected( ( m_subdivide != FALSE ), m_nHorz, m_nVert ); } } Sys_UpdateWindows(W_CAMERA | W_XY); } void CSurfaceDlg::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { CDialog::OnKeyDown(nChar, nRepCnt, nFlags); } void CSurfaceDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { //UpdateSpinners(nSBCode, nPos, pScrollBar); //Sys_UpdateWindows(W_CAMERA); } void CSurfaceDlg::OnOK() { //GetTexMods(); UpdateData(TRUE); if (m_strMaterial.Find(":") >= 0) { const idMaterial *mat = declManager->FindMaterial(m_strMaterial); Select_UpdateTextureName(m_strMaterial); } g_surfwin = NULL; CDialog::OnOK(); Sys_UpdateWindows(W_ALL); } void CSurfaceDlg::OnClose() { g_surfwin = NULL; CDialog::OnClose(); } void CSurfaceDlg::OnCancel() { if (g_bGatewayhack) { OnOK(); } else { OnBtnCancel(); } } void CSurfaceDlg::OnDestroy() { if (GetSafeHwnd()) { CRect rct; GetWindowRect(rct); SaveRegistryInfo("radiant_SurfaceWindow", &rct, sizeof(rct)); } CDialog::OnDestroy(); g_surfwin = NULL; Sys_UpdateWindows(W_ALL); } void CSurfaceDlg::OnBtnCancel() { g_qeglobals.d_texturewin.texdef = g_old_texdef; if (g_changed_surface) { //++timo if !g_qeglobals.m_bBrushPrimitMode send a NULL brushprimit_texdef if (!g_qeglobals.m_bBrushPrimitMode) { common->Printf("Warning : non brush primitive mode call to CSurfaceDlg::GetTexMods broken\n"); common->Printf(" ( Select_SetTexture not called )\n"); } // Select_SetTexture(&g_qeglobals.d_texturewin.texdef); } g_surfwin = NULL; DestroyWindow(); } void CSurfaceDlg::OnBtnColor() { } HBRUSH CSurfaceDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); if (!pDC) { return hbr; } switch (nCtlColor) { case CTLCOLOR_DLG: pDC->SetBkColor(ICE_DARK_BG); return IceDark_BgBrush(); case CTLCOLOR_STATIC: pDC->SetTextColor(ICE_DARK_TEXT_MUTED); pDC->SetBkMode(TRANSPARENT); return IceDark_BgBrush(); case CTLCOLOR_EDIT: case CTLCOLOR_LISTBOX: pDC->SetTextColor(ICE_DARK_TEXT); pDC->SetBkColor(ICE_DARK_FIELD); return IceDark_FieldBrush(); case CTLCOLOR_BTN: pDC->SetTextColor(ICE_DARK_TEXT); pDC->SetBkColor(ICE_DARK_BG); return IceDark_BgBrush(); } return hbr; } int CSurfaceDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CDialog::OnCreate(lpCreateStruct) == -1) return -1; return 0; } BOOL CSurfaceDlg::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Add your specialized code here and/or call the base class return CDialog::PreCreateWindow(cs); } void CSurfaceDlg::OnDeltaPosSpin(NMHDR* pNMHDR, LRESULT* pResult) { NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR; UpdateSpinners((pNMUpDown->iDelta > 0), pNMUpDown->hdr.idFrom); *pResult = 0; } void CSurfaceDlg::OnBtnPatchdetails() { Patch_NaturalizeSelected(true); g_pParentWnd->GetCamera()->MarkWorldDirty (); Sys_UpdateWindows(W_ALL); } void CSurfaceDlg::OnBtnPatchnatural() { Select_SetTexture (&g_qeglobals.d_texturewin.texdef, &g_qeglobals.d_texturewin.brushprimit_texdef, false); Patch_NaturalizeSelected(); g_pParentWnd->GetCamera()->MarkWorldDirty (); g_changed_surface = true; Sys_UpdateWindows(W_ALL); } void CSurfaceDlg::OnBtnPatchreset() { //CTextureLayout dlg; //if (dlg.DoModal() == IDOK) { // Patch_ResetTexturing(dlg.m_fX, dlg.m_fY); //} //Sys_UpdateWindows(W_ALL); } void CSurfaceDlg::OnBtnAxial() { } void CSurfaceDlg::OnBtnBrushfit() { // TODO: Add your control notification handler code here } void CSurfaceDlg::OnBtnFacefit() { UpdateData(TRUE); /* brush_t *b; for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) { if (!b->patchBrush) { for (face_t* pFace = b->brush_faces; pFace; pFace = pFace->next) { g_ptrSelectedFaces.Add(pFace); g_ptrSelectedFaceBrushes.Add(b); } } } */ Select_FitTexture(m_fHeight, m_fWidth); g_pParentWnd->GetCamera()->MarkWorldDirty (); //SetTexMods(); g_changed_surface = true; Sys_UpdateWindows(W_ALL); } void CSurfaceDlg::OnCheckSubdivide() { UpdateData( TRUE ); // turn any patches in explicit subdivides Patch_SubdivideSelected( ( m_subdivide != FALSE ), m_nHorz, m_nVert ); g_pParentWnd->GetCamera()->MarkWorldDirty (); Sys_UpdateWindows( W_CAMERA | W_XY ); } void CSurfaceDlg::OnChangeEditHorz() { // TODO: If this is a RICHEDIT control, the control will not // send this notification unless you override the CDialog::OnInitDialog() // function and call CRichEditCtrl().SetEventMask() // with the ENM_CHANGE flag ORed into the mask. // TODO: Add your control notification handler code here UpdateData(TRUE); // turn any patches in explicit subdivides Patch_SubdivideSelected( ( m_subdivide != FALSE ), m_nHorz, m_nVert ); Sys_UpdateWindows(W_CAMERA | W_XY); } void CSurfaceDlg::OnChangeEditVert() { // TODO: If this is a RICHEDIT control, the control will not // send this notification unless you override the CDialog::OnInitDialog() // function and call CRichEditCtrl().SetEventMask() // with the ENM_CHANGE flag ORed into the mask. // TODO: Add your control notification handler code here UpdateData(TRUE); // turn any patches in explicit subdivides Patch_SubdivideSelected( ( m_subdivide != FALSE ), m_nHorz, m_nVert ); Sys_UpdateWindows(W_CAMERA | W_XY); } BOOL CSurfaceDlg::PreTranslateMessage(MSG* pMsg) { if (pMsg->message == WM_KEYDOWN) { if (pMsg->wParam == VK_RETURN) { if (focusControl) { UpdateData(TRUE); if (focusControl == &m_wndHScale) { Select_ScaleTexture( m_horzScale, 1.0f, true, ( m_absolute != FALSE ) ); } else if (focusControl == &m_wndVScale) { Select_ScaleTexture( 1.0f, m_vertScale, true, ( m_absolute != FALSE ) ); } else if (focusControl == &m_wndRotateEdit) { Select_RotateTexture( m_rotate, true ); } else if (focusControl == &m_wndHeight || focusControl == &m_wndWidth) { Select_FitTexture( m_fHeight, m_fWidth ); } } return TRUE; } } return CDialog::PreTranslateMessage(pMsg); } void CSurfaceDlg::OnSetfocusHscale() { focusControl = &m_wndHScale; } void CSurfaceDlg::OnKillfocusHscale() { focusControl = NULL; } void CSurfaceDlg::OnKillfocusVscale() { focusControl = NULL; } void CSurfaceDlg::OnSetfocusVscale() { focusControl = &m_wndVScale; } void CSurfaceDlg::OnKillfocusEditWidth() { focusControl = NULL; } void CSurfaceDlg::OnSetfocusEditWidth() { focusControl = &m_wndWidth; } void CSurfaceDlg::OnKillfocusEditHeight() { focusControl = NULL; } void CSurfaceDlg::OnSetfocusEditHeight() { focusControl = &m_wndHeight; } void CSurfaceDlg::OnBtnFlipx() { Select_FlipTexture(false); } void CSurfaceDlg::OnBtnFlipy() { Select_FlipTexture(true); } void CSurfaceDlg::OnKillfocusRotate() { focusControl = NULL; } void CSurfaceDlg::OnSetfocusRotate() { focusControl = &m_wndRotateEdit; }