mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-15 15:51:07 +02:00
Editor theme and bug fixes.
This commit is contained in:
@@ -28,6 +28,598 @@ void Select_Ungroup();
|
||||
|
||||
IMPLEMENT_DYNAMIC(CEntityDlg, CDialog)
|
||||
|
||||
|
||||
#ifndef BS_TYPEMASK
|
||||
#define BS_TYPEMASK 0x0000000F
|
||||
#endif
|
||||
|
||||
static const COLORREF ENTITY_DARK_BG = RGB(17, 19, 23);
|
||||
static const COLORREF ENTITY_DARK_PANEL = RGB(24, 27, 32);
|
||||
static const COLORREF ENTITY_DARK_PANEL_ALT = RGB(29, 33, 39);
|
||||
static const COLORREF ENTITY_DARK_FIELD = RGB(14, 16, 20);
|
||||
static const COLORREF ENTITY_DARK_FIELD_ALT = RGB(18, 21, 26);
|
||||
static const COLORREF ENTITY_DARK_PROP_NAME = RGB(31, 36, 44);
|
||||
static const COLORREF ENTITY_DARK_PROP_NAME_SEL = RGB(54, 76, 105);
|
||||
static const COLORREF ENTITY_DARK_BORDER = RGB(55, 62, 72);
|
||||
static const COLORREF ENTITY_DARK_BORDER_HOT = RGB(87, 166, 255);
|
||||
static const COLORREF ENTITY_DARK_TEXT = RGB(226, 232, 240);
|
||||
static const COLORREF ENTITY_DARK_TEXT_MUTED = RGB(151, 163, 184);
|
||||
static const COLORREF ENTITY_DARK_TEXT_DISABLED = RGB(103, 112, 128);
|
||||
static const COLORREF ENTITY_DARK_ACCENT = RGB(87, 166, 255);
|
||||
|
||||
static const char* ENTITY_DARK_BUTTON_OLDPROC = "IceTech.Entity.DarkButtonOldProc";
|
||||
static const char* ENTITY_DARK_PROP_OLDPROC = "IceTech.Entity.DarkPropertyOldProc";
|
||||
static const char* ENTITY_DARK_PROP_DIVIDER = "IceTech.Entity.DarkPropertyDivider";
|
||||
static const char* ENTITY_DARK_FIELD_OLDPROC = "IceTech.Entity.DarkFieldOldProc";
|
||||
static const char* ENTITY_DARK_COMBO_OLDPROC = "IceTech.Entity.DarkComboOldProc";
|
||||
|
||||
static void EntityDark_FillRect(HDC hDC, const RECT& rc, COLORREF color) {
|
||||
HBRUSH brush = ::CreateSolidBrush(color);
|
||||
::FillRect(hDC, &rc, brush);
|
||||
::DeleteObject(brush);
|
||||
}
|
||||
|
||||
static void EntityDark_FrameRect(HDC hDC, const RECT& rc, COLORREF color) {
|
||||
HBRUSH brush = ::CreateSolidBrush(color);
|
||||
::FrameRect(hDC, &rc, brush);
|
||||
::DeleteObject(brush);
|
||||
}
|
||||
|
||||
static void EntityDark_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 isCheck = (type == BS_CHECKBOX || type == BS_AUTOCHECKBOX || type == BS_3STATE || type == BS_AUTO3STATE);
|
||||
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);
|
||||
|
||||
char text[256];
|
||||
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 ? ENTITY_DARK_TEXT : ENTITY_DARK_TEXT_DISABLED);
|
||||
|
||||
if (isCheck) {
|
||||
EntityDark_FillRect(hDC, rc, ENTITY_DARK_PANEL);
|
||||
|
||||
RECT box = rc;
|
||||
box.left += 3;
|
||||
box.right = box.left + 14;
|
||||
box.top += max(0, (rc.bottom - rc.top - 14) / 2);
|
||||
box.bottom = box.top + 14;
|
||||
|
||||
EntityDark_FillRect(hDC, box, enabled ? ENTITY_DARK_FIELD : RGB(20, 22, 26));
|
||||
EntityDark_FrameRect(hDC, box, checked ? ENTITY_DARK_ACCENT : ENTITY_DARK_BORDER);
|
||||
|
||||
if (checked) {
|
||||
HPEN pen = ::CreatePen(PS_SOLID, 2, enabled ? ENTITY_DARK_ACCENT : ENTITY_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) : ENTITY_DARK_PANEL_ALT;
|
||||
EntityDark_FillRect(hDC, rc, face);
|
||||
EntityDark_FrameRect(hDC, rc, enabled ? ENTITY_DARK_BORDER : RGB(39, 44, 52));
|
||||
|
||||
RECT inner = rc;
|
||||
::InflateRect(&inner, -1, -1);
|
||||
if (!pushed) {
|
||||
EntityDark_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 EntityDarkButtonProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
WNDPROC oldProc = (WNDPROC)::GetPropA(hWnd, ENTITY_DARK_BUTTON_OLDPROC);
|
||||
if (!oldProc) {
|
||||
return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
switch (uMsg) {
|
||||
case WM_ERASEBKGND:
|
||||
return 1;
|
||||
|
||||
case WM_PAINT:
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
HDC hDC = ::BeginPaint(hWnd, &ps);
|
||||
EntityDark_DrawButton(hWnd, hDC);
|
||||
::EndPaint(hWnd, &ps);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case WM_PRINTCLIENT:
|
||||
EntityDark_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, ENTITY_DARK_BUTTON_OLDPROC);
|
||||
return ::CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
}
|
||||
|
||||
return ::CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
static void EntityDark_SubclassButton(CWnd& wnd) {
|
||||
HWND hWnd = wnd.GetSafeHwnd();
|
||||
if (!hWnd || ::GetPropA(hWnd, ENTITY_DARK_BUTTON_OLDPROC)) {
|
||||
return;
|
||||
}
|
||||
WNDPROC oldProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_WNDPROC);
|
||||
::SetPropA(hWnd, ENTITY_DARK_BUTTON_OLDPROC, (HANDLE)oldProc);
|
||||
::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)EntityDarkButtonProc);
|
||||
::InvalidateRect(hWnd, NULL, TRUE);
|
||||
}
|
||||
|
||||
static void EntityDark_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 EntityDark_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 EntityDark_DrawFrame(HWND hWnd, COLORREF color) {
|
||||
HDC hDC = ::GetWindowDC(hWnd);
|
||||
if (!hDC) {
|
||||
return;
|
||||
}
|
||||
RECT rc;
|
||||
::GetWindowRect(hWnd, &rc);
|
||||
::OffsetRect(&rc, -rc.left, -rc.top);
|
||||
EntityDark_FrameRect(hDC, rc, color);
|
||||
::ReleaseDC(hWnd, hDC);
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK EntityDarkFieldProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
WNDPROC oldProc = (WNDPROC)::GetPropA(hWnd, ENTITY_DARK_FIELD_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);
|
||||
EntityDark_DrawFrame(hWnd, (::GetFocus() == hWnd) ? ENTITY_DARK_BORDER_HOT : ENTITY_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, ENTITY_DARK_FIELD_OLDPROC);
|
||||
return ::CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
}
|
||||
|
||||
return ::CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
static void EntityDark_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;
|
||||
|
||||
EntityDark_FillRect(hDC, rc, enabled ? ENTITY_DARK_FIELD : RGB(20, 22, 26));
|
||||
EntityDark_FrameRect(hDC, rc, focused ? ENTITY_DARK_BORDER_HOT : ENTITY_DARK_BORDER);
|
||||
|
||||
RECT arrow = rc;
|
||||
arrow.left = arrow.right - 22;
|
||||
EntityDark_FillRect(hDC, arrow, ENTITY_DARK_PANEL_ALT);
|
||||
EntityDark_FrameRect(hDC, arrow, ENTITY_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 ? ENTITY_DARK_TEXT : ENTITY_DARK_TEXT_DISABLED);
|
||||
HBRUSH oldBrush = (HBRUSH)::SelectObject(hDC, arrowBrush);
|
||||
HPEN arrowPen = ::CreatePen(PS_SOLID, 1, enabled ? ENTITY_DARK_TEXT : ENTITY_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 ? ENTITY_DARK_TEXT : ENTITY_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 EntityDarkComboProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
WNDPROC oldProc = (WNDPROC)::GetPropA(hWnd, ENTITY_DARK_COMBO_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);
|
||||
EntityDark_DrawCombo(hWnd, hDC);
|
||||
::EndPaint(hWnd, &ps);
|
||||
return 0;
|
||||
}
|
||||
LRESULT result = ::CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam);
|
||||
EntityDark_DrawFrame(hWnd, (::GetFocus() == hWnd || ::IsChild(hWnd, ::GetFocus())) ? ENTITY_DARK_BORDER_HOT : ENTITY_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, ENTITY_DARK_COMBO_OLDPROC);
|
||||
return ::CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
}
|
||||
|
||||
return ::CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
static void EntityDark_SubclassField(CWnd& wnd) {
|
||||
HWND hWnd = wnd.GetSafeHwnd();
|
||||
if (!hWnd || ::GetPropA(hWnd, ENTITY_DARK_FIELD_OLDPROC)) {
|
||||
return;
|
||||
}
|
||||
EntityDark_RemoveClientEdge(hWnd);
|
||||
EntityDark_ApplyNativeTheme(hWnd);
|
||||
WNDPROC oldProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_WNDPROC);
|
||||
::SetPropA(hWnd, ENTITY_DARK_FIELD_OLDPROC, (HANDLE)oldProc);
|
||||
::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)EntityDarkFieldProc);
|
||||
::InvalidateRect(hWnd, NULL, TRUE);
|
||||
}
|
||||
|
||||
static void EntityDark_SubclassCombo(CWnd& wnd) {
|
||||
HWND hWnd = wnd.GetSafeHwnd();
|
||||
if (!hWnd || ::GetPropA(hWnd, ENTITY_DARK_COMBO_OLDPROC)) {
|
||||
return;
|
||||
}
|
||||
EntityDark_RemoveClientEdge(hWnd);
|
||||
EntityDark_ApplyNativeTheme(hWnd);
|
||||
WNDPROC oldProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_WNDPROC);
|
||||
::SetPropA(hWnd, ENTITY_DARK_COMBO_OLDPROC, (HANDLE)oldProc);
|
||||
::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)EntityDarkComboProc);
|
||||
::InvalidateRect(hWnd, NULL, TRUE);
|
||||
}
|
||||
|
||||
static void EntityDark_SetPropertyListRowHeight(HWND hWnd) {
|
||||
if (!hWnd) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The old resource-sized rows were too tight after the dark-theme font pass.
|
||||
// Give every row enough breathing room so descenders (g, y, p, q) are not clipped at the bottom.
|
||||
::SendMessage(hWnd, LB_SETITEMHEIGHT, 0, 32);
|
||||
}
|
||||
|
||||
static void EntityDark_CopyPropText(char* out, int outSize, CPropertyItem* propItem, int index, HWND hWnd, bool wantValue) {
|
||||
if (!out || outSize <= 0) {
|
||||
return;
|
||||
}
|
||||
out[0] = '\0';
|
||||
|
||||
if (propItem && propItem != (CPropertyItem*)LB_ERR) {
|
||||
const char* src = wantValue ? propItem->m_curValue : propItem->m_propName;
|
||||
if (src && src[0]) {
|
||||
idStr::Copynz(out, src, outSize);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
char text[2048];
|
||||
text[0] = '\0';
|
||||
::SendMessageA(hWnd, LB_GETTEXT, (WPARAM)index, (LPARAM)text);
|
||||
|
||||
char* tab = strchr(text, '\t');
|
||||
if (tab) {
|
||||
if (wantValue) {
|
||||
idStr::Copynz(out, tab + 1, outSize);
|
||||
}
|
||||
else {
|
||||
*tab = '\0';
|
||||
idStr::Copynz(out, text, outSize);
|
||||
}
|
||||
}
|
||||
else if (!wantValue) {
|
||||
idStr::Copynz(out, text, outSize);
|
||||
}
|
||||
}
|
||||
|
||||
static void EntityDark_DrawPropertyList(HWND hWnd, HDC hDC) {
|
||||
RECT client;
|
||||
::GetClientRect(hWnd, &client);
|
||||
|
||||
EntityDark_FillRect(hDC, client, ENTITY_DARK_FIELD);
|
||||
|
||||
const int count = (int)::SendMessage(hWnd, LB_GETCOUNT, 0, 0);
|
||||
if (count <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int divider = (int)(INT_PTR)::GetPropA(hWnd, ENTITY_DARK_PROP_DIVIDER);
|
||||
if (divider <= 0) {
|
||||
divider = 170;
|
||||
}
|
||||
if (divider > client.right - 80) {
|
||||
divider = max(80, client.right / 2);
|
||||
}
|
||||
|
||||
const int topIndex = (int)::SendMessage(hWnd, LB_GETTOPINDEX, 0, 0);
|
||||
const int curSel = (int)::SendMessage(hWnd, LB_GETCURSEL, 0, 0);
|
||||
const bool focused = (::GetFocus() == hWnd || ::IsChild(hWnd, ::GetFocus())) ? true : false;
|
||||
|
||||
HFONT font = (HFONT)::SendMessage(hWnd, WM_GETFONT, 0, 0);
|
||||
HFONT oldFont = font ? (HFONT)::SelectObject(hDC, font) : NULL;
|
||||
::SetBkMode(hDC, TRANSPARENT);
|
||||
|
||||
for (int i = max(0, topIndex); i < count; i++) {
|
||||
RECT item;
|
||||
if ((int)::SendMessage(hWnd, LB_GETITEMRECT, (WPARAM)i, (LPARAM)&item) == LB_ERR) {
|
||||
break;
|
||||
}
|
||||
if (item.top >= client.bottom) {
|
||||
break;
|
||||
}
|
||||
if (item.bottom <= client.top) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool selected = (i == curSel);
|
||||
|
||||
RECT rowRect = item;
|
||||
rowRect.left = client.left;
|
||||
rowRect.right = client.right;
|
||||
EntityDark_FillRect(hDC, rowRect, selected ? RGB(31, 41, 55) : ENTITY_DARK_FIELD);
|
||||
|
||||
RECT nameRect = item;
|
||||
nameRect.left = client.left;
|
||||
nameRect.right = min(client.right, divider);
|
||||
EntityDark_FillRect(hDC, nameRect, selected ? ENTITY_DARK_PROP_NAME_SEL : ENTITY_DARK_PROP_NAME);
|
||||
|
||||
RECT valueRect = item;
|
||||
valueRect.left = min(client.right, divider + 1);
|
||||
valueRect.right = client.right;
|
||||
EntityDark_FillRect(hDC, valueRect, selected ? RGB(30, 43, 59) : ENTITY_DARK_FIELD);
|
||||
|
||||
CPropertyItem* propItem = (CPropertyItem*)::SendMessage(hWnd, LB_GETITEMDATA, (WPARAM)i, 0);
|
||||
|
||||
char nameText[1024];
|
||||
char valueText[2048];
|
||||
EntityDark_CopyPropText(nameText, sizeof(nameText), propItem, i, hWnd, false);
|
||||
EntityDark_CopyPropText(valueText, sizeof(valueText), propItem, i, hWnd, true);
|
||||
|
||||
RECT nameTextRect = nameRect;
|
||||
nameTextRect.left += 10;
|
||||
nameTextRect.right -= 10;
|
||||
nameTextRect.top += 3;
|
||||
nameTextRect.bottom -= 1;
|
||||
|
||||
RECT valueTextRect = valueRect;
|
||||
valueTextRect.left += 12;
|
||||
valueTextRect.right -= 10;
|
||||
valueTextRect.top += 3;
|
||||
valueTextRect.bottom -= 1;
|
||||
|
||||
::SetTextColor(hDC, selected ? RGB(255, 255, 255) : ENTITY_DARK_TEXT);
|
||||
::DrawTextA(hDC, nameText, -1, &nameTextRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
|
||||
|
||||
::SetTextColor(hDC, selected ? RGB(235, 245, 255) : RGB(206, 214, 226));
|
||||
::DrawTextA(hDC, valueText, -1, &valueTextRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
|
||||
|
||||
// Dark, vertical-only split. Do not draw horizontal row dividers; they were cutting through the value text.
|
||||
RECT dividerRect = item;
|
||||
dividerRect.left = min(client.right - 1, divider);
|
||||
dividerRect.right = dividerRect.left + 1;
|
||||
EntityDark_FillRect(hDC, dividerRect, RGB(42, 48, 58));
|
||||
}
|
||||
|
||||
if (focused) {
|
||||
RECT focusRect = client;
|
||||
::InflateRect(&focusRect, -1, -1);
|
||||
EntityDark_FrameRect(hDC, focusRect, ENTITY_DARK_BORDER_HOT);
|
||||
}
|
||||
else {
|
||||
RECT frameRect = client;
|
||||
::InflateRect(&frameRect, -1, -1);
|
||||
EntityDark_FrameRect(hDC, frameRect, ENTITY_DARK_BORDER);
|
||||
}
|
||||
|
||||
if (oldFont) {
|
||||
::SelectObject(hDC, oldFont);
|
||||
}
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK EntityDarkPropertyListProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
WNDPROC oldProc = (WNDPROC)::GetPropA(hWnd, ENTITY_DARK_PROP_OLDPROC);
|
||||
if (!oldProc) {
|
||||
return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
switch (uMsg) {
|
||||
case WM_PAINT:
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
HDC hDC = ::BeginPaint(hWnd, &ps);
|
||||
EntityDark_DrawPropertyList(hWnd, hDC);
|
||||
::EndPaint(hWnd, &ps);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case WM_PRINTCLIENT:
|
||||
EntityDark_DrawPropertyList(hWnd, (HDC)wParam);
|
||||
return 0;
|
||||
|
||||
case WM_ERASEBKGND:
|
||||
{
|
||||
RECT rc;
|
||||
::GetClientRect(hWnd, &rc);
|
||||
EntityDark_FillRect((HDC)wParam, rc, ENTITY_DARK_FIELD);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case WM_VSCROLL:
|
||||
case WM_HSCROLL:
|
||||
case WM_MOUSEWHEEL:
|
||||
case WM_SETFOCUS:
|
||||
case WM_KILLFOCUS:
|
||||
case LB_ADDSTRING:
|
||||
case LB_INSERTSTRING:
|
||||
case LB_DELETESTRING:
|
||||
case LB_RESETCONTENT:
|
||||
case LB_SETCURSEL:
|
||||
{
|
||||
LRESULT result = ::CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam);
|
||||
if (uMsg == LB_ADDSTRING || uMsg == LB_INSERTSTRING || uMsg == LB_RESETCONTENT) {
|
||||
EntityDark_SetPropertyListRowHeight(hWnd);
|
||||
}
|
||||
::InvalidateRect(hWnd, NULL, FALSE);
|
||||
return result;
|
||||
}
|
||||
|
||||
case WM_NCDESTROY:
|
||||
{
|
||||
::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldProc);
|
||||
::RemovePropA(hWnd, ENTITY_DARK_PROP_OLDPROC);
|
||||
::RemovePropA(hWnd, ENTITY_DARK_PROP_DIVIDER);
|
||||
return ::CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
}
|
||||
|
||||
return ::CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
static void EntityDark_SubclassPropertyList(CWnd& wnd, int divider) {
|
||||
HWND hWnd = wnd.GetSafeHwnd();
|
||||
if (!hWnd) {
|
||||
return;
|
||||
}
|
||||
::SetPropA(hWnd, ENTITY_DARK_PROP_DIVIDER, (HANDLE)(INT_PTR)divider);
|
||||
EntityDark_SetPropertyListRowHeight(hWnd);
|
||||
if (::GetPropA(hWnd, ENTITY_DARK_PROP_OLDPROC)) {
|
||||
::InvalidateRect(hWnd, NULL, TRUE);
|
||||
return;
|
||||
}
|
||||
WNDPROC oldProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_WNDPROC);
|
||||
::SetPropA(hWnd, ENTITY_DARK_PROP_OLDPROC, (HANDLE)oldProc);
|
||||
::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)EntityDarkPropertyListProc);
|
||||
::InvalidateRect(hWnd, NULL, TRUE);
|
||||
}
|
||||
|
||||
CEntityDlg::CEntityDlg(CWnd* pParent /*=NULL*/)
|
||||
: CDialog(CEntityDlg::IDD, pParent) {
|
||||
editEntity = NULL;
|
||||
@@ -37,14 +629,14 @@ CEntityDlg::CEntityDlg(CWnd* pParent /*=NULL*/)
|
||||
dict = NULL;
|
||||
themeInitialized = false;
|
||||
|
||||
colorBackground = RGB(245, 246, 248);
|
||||
colorPanel = RGB(255, 255, 255);
|
||||
colorPanelAlt = RGB(248, 249, 251);
|
||||
colorBorder = RGB(210, 214, 220);
|
||||
colorText = RGB(32, 36, 42);
|
||||
colorTextMuted = RGB(92, 99, 112);
|
||||
colorAccent = RGB(0, 122, 204);
|
||||
colorEditBg = RGB(255, 255, 255);
|
||||
colorBackground = RGB(17, 19, 23);
|
||||
colorPanel = RGB(26, 29, 34);
|
||||
colorPanelAlt = RGB(29, 33, 39);
|
||||
colorBorder = RGB(55, 62, 72);
|
||||
colorText = RGB(226, 232, 240);
|
||||
colorTextMuted = RGB(151, 163, 184);
|
||||
colorAccent = RGB(87, 166, 255);
|
||||
colorEditBg = RGB(14, 16, 20);
|
||||
}
|
||||
|
||||
CEntityDlg::~CEntityDlg() {
|
||||
@@ -273,6 +865,30 @@ void CEntityDlg::ApplyModernTheme() {
|
||||
editVal.SetMargins(6, 6);
|
||||
}
|
||||
|
||||
EntityDark_SubclassField(editKey);
|
||||
EntityDark_SubclassField(editVal);
|
||||
EntityDark_SubclassField(listKeyVal);
|
||||
EntityDark_SubclassField(listVars);
|
||||
EntityDark_SubclassField(slFrameSlider);
|
||||
EntityDark_SubclassCombo(comboClass);
|
||||
EntityDark_SubclassCombo(cbAnimations);
|
||||
|
||||
EntityDark_SubclassPropertyList(listKeyVal, 170);
|
||||
EntityDark_SubclassPropertyList(listVars, 170);
|
||||
|
||||
CWnd* darkButtons[] = {
|
||||
&btnCreate, &btnBrowse,
|
||||
&btnModel, &btnSound, &btnGui, &btnParticle, &btnSkin, &btnCurve,
|
||||
&btn135, &btn90, &btn45, &btn180, &btn360, &btn225, &btn270, &btn315, &btnUp, &btnDown,
|
||||
&btnPlayAnim, &btnStopAnim
|
||||
};
|
||||
for (int i = 0; i < (int)(sizeof(darkButtons) / sizeof(darkButtons[0])); i++) {
|
||||
if (darkButtons[i] && darkButtons[i]->GetSafeHwnd()) {
|
||||
EntityDark_ApplyNativeTheme(darkButtons[i]->GetSafeHwnd());
|
||||
EntityDark_SubclassButton(*darkButtons[i]);
|
||||
}
|
||||
}
|
||||
|
||||
staticTitle.SetWindowText("Entity Inspector");
|
||||
staticKey.SetWindowText("Key");
|
||||
staticVal.SetWindowText("Value");
|
||||
@@ -329,11 +945,17 @@ void CEntityDlg::DrawModernBackground(CDC& dc) {
|
||||
int contentBottom = rect.bottom - pad;
|
||||
int width = rect.Width();
|
||||
|
||||
if (width >= 560) {
|
||||
if (width >= 500) {
|
||||
const int editorH = 106;
|
||||
const int minToolH = 112;
|
||||
const int availableH = max(1, contentBottom - contentTop);
|
||||
// Give the two property grids the extra vertical space instead of capping them at 420px.
|
||||
// This keeps the edit/tools panels underneath and prevents the list controls from stacking over each other.
|
||||
int listH = max(180, availableH - editorH - minToolH - pad * 3);
|
||||
int leftW = (width - pad * 3) / 2;
|
||||
CRect vars(rect.left + pad, contentTop, rect.left + pad + leftW, contentTop + 220);
|
||||
CRect keyvals(vars.right + pad, contentTop, rect.right - pad, contentTop + 220);
|
||||
CRect editor(rect.left + pad, vars.bottom + pad, rect.right - pad, vars.bottom + 106);
|
||||
CRect vars(rect.left + pad, contentTop, rect.left + pad + leftW, contentTop + listH);
|
||||
CRect keyvals(vars.right + pad, contentTop, rect.right - pad, contentTop + listH);
|
||||
CRect editor(rect.left + pad, vars.bottom + pad, rect.right - pad, vars.bottom + editorH);
|
||||
CRect tools(rect.left + pad, editor.bottom + pad, rect.right - pad, contentBottom);
|
||||
|
||||
DrawPanel(dc, header, "", true);
|
||||
@@ -344,11 +966,14 @@ void CEntityDlg::DrawModernBackground(CDC& dc) {
|
||||
DrawPanel(dc, tools, "Tools", false);
|
||||
}
|
||||
else {
|
||||
int h = max(120, (contentBottom - contentTop - pad * 3) / 4);
|
||||
const int editorH = 106;
|
||||
const int minToolH = 112;
|
||||
const int availableH = max(1, contentBottom - contentTop);
|
||||
int h = max(140, (availableH - editorH - minToolH - pad * 3) / 2);
|
||||
|
||||
CRect vars(rect.left + pad, contentTop, rect.right - pad, contentTop + h);
|
||||
CRect keyvals(rect.left + pad, vars.bottom + pad, rect.right - pad, vars.bottom + h);
|
||||
CRect editor(rect.left + pad, keyvals.bottom + pad, rect.right - pad, keyvals.bottom + 106);
|
||||
CRect editor(rect.left + pad, keyvals.bottom + pad, rect.right - pad, keyvals.bottom + editorH);
|
||||
CRect tools(rect.left + pad, editor.bottom + pad, rect.right - pad, contentBottom);
|
||||
|
||||
DrawPanel(dc, header, "", true);
|
||||
@@ -419,8 +1044,10 @@ BOOL CEntityDlg::OnInitDialog() {
|
||||
InitModernTheme();
|
||||
|
||||
listKeyVal.SetUpdateInspectors(true);
|
||||
listKeyVal.SetDivider(120);
|
||||
listVars.SetDivider(120);
|
||||
listKeyVal.SetDivider(170);
|
||||
listVars.SetDivider(170);
|
||||
::SendMessage(listKeyVal.GetSafeHwnd(), LB_SETITEMHEIGHT, 0, 32);
|
||||
::SendMessage(listVars.GetSafeHwnd(), LB_SETITEMHEIGHT, 0, 32);
|
||||
|
||||
staticFrame.SetWindowText("0");
|
||||
|
||||
@@ -448,7 +1075,7 @@ void CEntityDlg::OnSize(UINT nType, int cx, int cy) {
|
||||
const int headerH = 42;
|
||||
const int classH = 52;
|
||||
const int editorH = 106;
|
||||
const int minToolH = 124;
|
||||
const int minToolH = 112;
|
||||
|
||||
CRect rect;
|
||||
GetClientRect(&rect);
|
||||
@@ -468,8 +1095,10 @@ void CEntityDlg::OnSize(UINT nType, int cx, int cy) {
|
||||
int contentTop = classPanel.bottom + pad;
|
||||
int contentBottom = rect.bottom - pad;
|
||||
|
||||
if (w >= 560) {
|
||||
int listH = max(120, min(260, (h - contentTop - editorH - minToolH - pad * 3)));
|
||||
if (w >= 500) {
|
||||
const int availableH = max(1, contentBottom - contentTop);
|
||||
// No upper cap: the grids now consume the extra dock/inspector height instead of staying squeezed at the top.
|
||||
int listH = max(180, availableH - editorH - minToolH - pad * 3);
|
||||
int leftW = (w - pad * 3) / 2;
|
||||
|
||||
CRect varsPanel(rect.left + pad, contentTop, rect.left + pad + leftW, contentTop + listH);
|
||||
@@ -534,8 +1163,8 @@ void CEntityDlg::OnSize(UINT nType, int cx, int cy) {
|
||||
MoveCtrl(staticFrame, animX + animW - 38, toolY + 68, 36, 20);
|
||||
}
|
||||
else {
|
||||
int available = contentBottom - contentTop;
|
||||
int listH = max(82, (available - editorH - minToolH - pad * 3) / 2);
|
||||
int available = max(1, contentBottom - contentTop);
|
||||
int listH = max(140, (available - editorH - minToolH - pad * 3) / 2);
|
||||
|
||||
CRect varsPanel(rect.left + pad, contentTop, rect.right - pad, contentTop + listH);
|
||||
CRect keyPanel(rect.left + pad, varsPanel.bottom + pad, rect.right - pad, varsPanel.bottom + pad + listH);
|
||||
|
||||
Reference in New Issue
Block a user