mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-16 00:01:53 +02:00
Editor theme and bug fixes.
This commit is contained in:
@@ -29,13 +29,212 @@ along with IceTech Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "Radiant.h"
|
||||
#include "OutlinerDlg.h"
|
||||
#include "InspectorDialog.h"
|
||||
#include <commctrl.h>
|
||||
|
||||
#pragma comment(lib, "comctl32.lib")
|
||||
|
||||
IMPLEMENT_DYNAMIC(COutlinerDlg, CWnd)
|
||||
|
||||
static const COLORREF OUTLINER_BG = RGB(245, 247, 250);
|
||||
static const COLORREF OUTLINER_PANEL_BG = RGB(255, 255, 255);
|
||||
static const COLORREF OUTLINER_TEXT = RGB(32, 36, 42);
|
||||
static const COLORREF OUTLINER_MUTED_TEXT = RGB(88, 96, 105);
|
||||
static const COLORREF OUTLINER_BG = RGB(17, 19, 23);
|
||||
static const COLORREF OUTLINER_PANEL_BG = RGB(14, 16, 20);
|
||||
static const COLORREF OUTLINER_TEXT = RGB(226, 232, 240);
|
||||
static const COLORREF OUTLINER_MUTED_TEXT = RGB(151, 163, 184);
|
||||
|
||||
static const COLORREF OUTLINER_FIELD_BG = RGB(14, 16, 20);
|
||||
static const COLORREF OUTLINER_BORDER = RGB(55, 62, 72);
|
||||
static const COLORREF OUTLINER_ACCENT = RGB(87, 166, 255);
|
||||
static const char* OUTLINER_TREE_OLDPROC = "IceTech.Outliner.TreeOldProc";
|
||||
|
||||
static void Outliner_ApplyNativeDarkTheme(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 Outliner_FillRect(HDC hDC, const RECT& rc, COLORREF color) {
|
||||
HBRUSH brush = ::CreateSolidBrush(color);
|
||||
::FillRect(hDC, &rc, brush);
|
||||
::DeleteObject(brush);
|
||||
}
|
||||
|
||||
static void Outliner_FrameRect(HDC hDC, const RECT& rc, COLORREF color) {
|
||||
HBRUSH brush = ::CreateSolidBrush(color);
|
||||
::FrameRect(hDC, &rc, brush);
|
||||
::DeleteObject(brush);
|
||||
}
|
||||
|
||||
static HBITMAP Outliner_CreateDarkCheckBitmap(bool checked) {
|
||||
HDC screenDC = ::GetDC(NULL);
|
||||
HDC memDC = ::CreateCompatibleDC(screenDC);
|
||||
HBITMAP bitmap = ::CreateCompatibleBitmap(screenDC, 16, 16);
|
||||
HBITMAP oldBitmap = (HBITMAP)::SelectObject(memDC, bitmap);
|
||||
|
||||
RECT rc = { 0, 0, 16, 16 };
|
||||
Outliner_FillRect(memDC, rc, RGB(255, 0, 255));
|
||||
|
||||
RECT box = { 2, 2, 14, 14 };
|
||||
Outliner_FillRect(memDC, box, OUTLINER_FIELD_BG);
|
||||
Outliner_FrameRect(memDC, box, checked ? OUTLINER_ACCENT : OUTLINER_BORDER);
|
||||
|
||||
if (checked) {
|
||||
HPEN pen = ::CreatePen(PS_SOLID, 2, OUTLINER_ACCENT);
|
||||
HPEN oldPen = (HPEN)::SelectObject(memDC, pen);
|
||||
::MoveToEx(memDC, 5, 8, NULL);
|
||||
::LineTo(memDC, 7, 11);
|
||||
::LineTo(memDC, 12, 4);
|
||||
::SelectObject(memDC, oldPen);
|
||||
::DeleteObject(pen);
|
||||
}
|
||||
|
||||
::SelectObject(memDC, oldBitmap);
|
||||
::DeleteDC(memDC);
|
||||
::ReleaseDC(NULL, screenDC);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
static HIMAGELIST Outliner_GetDarkCheckImageList() {
|
||||
static HIMAGELIST imageList = NULL;
|
||||
if (imageList) {
|
||||
return imageList;
|
||||
}
|
||||
|
||||
imageList = ::ImageList_Create(16, 16, ILC_COLOR24 | ILC_MASK, 2, 0);
|
||||
if (!imageList) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
HBITMAP uncheckedBitmap = Outliner_CreateDarkCheckBitmap(false);
|
||||
HBITMAP checkedBitmap = Outliner_CreateDarkCheckBitmap(true);
|
||||
::ImageList_AddMasked(imageList, uncheckedBitmap, RGB(255, 0, 255));
|
||||
::ImageList_AddMasked(imageList, checkedBitmap, RGB(255, 0, 255));
|
||||
::DeleteObject(uncheckedBitmap);
|
||||
::DeleteObject(checkedBitmap);
|
||||
|
||||
return imageList;
|
||||
}
|
||||
|
||||
static void Outliner_ApplyDarkTreeImages(HWND hTree) {
|
||||
HIMAGELIST imageList = Outliner_GetDarkCheckImageList();
|
||||
if (hTree && imageList) {
|
||||
::SendMessage(hTree, TVM_SETIMAGELIST, TVSIL_STATE, (LPARAM)imageList);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool Outliner_TreeItemHasStateImage(HWND hTree, HTREEITEM item) {
|
||||
if (!hTree || !item) {
|
||||
return false;
|
||||
}
|
||||
TVITEM tvi;
|
||||
memset(&tvi, 0, sizeof(tvi));
|
||||
tvi.mask = TVIF_STATE;
|
||||
tvi.hItem = item;
|
||||
tvi.stateMask = TVIS_STATEIMAGEMASK;
|
||||
if (!TreeView_GetItem(hTree, &tvi)) {
|
||||
return false;
|
||||
}
|
||||
return (tvi.state & TVIS_STATEIMAGEMASK) != 0;
|
||||
}
|
||||
|
||||
static bool Outliner_TreePointInCheckZone(HWND hTree, HTREEITEM item, const POINT& point, UINT flags) {
|
||||
if (!item || !Outliner_TreeItemHasStateImage(hTree, item)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (flags & TVHT_ONITEMSTATEICON) {
|
||||
return true;
|
||||
}
|
||||
|
||||
RECT label;
|
||||
if (!TreeView_GetItemRect(hTree, item, &label, TRUE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RECT row;
|
||||
if (!TreeView_GetItemRect(hTree, item, &row, FALSE)) {
|
||||
row = label;
|
||||
}
|
||||
|
||||
// Make the checkbox easier to hit than the stock 16px state image. The
|
||||
// actual checkbox remains on the left, but clicks in a wider leading gutter
|
||||
// are treated as checkbox clicks instead of requiring pixel-perfect aim.
|
||||
RECT checkZone;
|
||||
checkZone.left = max(0, label.left - 30);
|
||||
checkZone.right = label.left + 10;
|
||||
checkZone.top = row.top;
|
||||
checkZone.bottom = row.bottom;
|
||||
|
||||
return ::PtInRect(&checkZone, point) ? true : false;
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK Outliner_TreeProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
WNDPROC oldProc = (WNDPROC)::GetPropA(hWnd, OUTLINER_TREE_OLDPROC);
|
||||
if (!oldProc) {
|
||||
return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
switch (uMsg) {
|
||||
case WM_LBUTTONDOWN:
|
||||
{
|
||||
POINT point;
|
||||
point.x = (short)LOWORD(lParam);
|
||||
point.y = (short)HIWORD(lParam);
|
||||
|
||||
TVHITTESTINFO hit;
|
||||
memset(&hit, 0, sizeof(hit));
|
||||
hit.pt = point;
|
||||
HTREEITEM item = TreeView_HitTest(hWnd, &hit);
|
||||
if (item && Outliner_TreePointInCheckZone(hWnd, item, point, hit.flags)) {
|
||||
BOOL checked = TreeView_GetCheckState(hWnd, item) ? TRUE : FALSE;
|
||||
TreeView_SelectItem(hWnd, item);
|
||||
TreeView_SetCheckState(hWnd, item, checked ? FALSE : TRUE);
|
||||
HWND parent = ::GetParent(hWnd);
|
||||
if (parent) {
|
||||
::SendMessage(parent, COutlinerDlg::WM_OUTLINER_APPLY_CHECK, (WPARAM)item, 0);
|
||||
}
|
||||
::InvalidateRect(hWnd, NULL, FALSE);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_NCDESTROY:
|
||||
{
|
||||
::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)oldProc);
|
||||
::RemovePropA(hWnd, OUTLINER_TREE_OLDPROC);
|
||||
return ::CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
}
|
||||
|
||||
return ::CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
static void Outliner_SubclassTreeForCheckClicks(HWND hTree) {
|
||||
if (!hTree || ::GetPropA(hTree, OUTLINER_TREE_OLDPROC)) {
|
||||
return;
|
||||
}
|
||||
WNDPROC oldProc = (WNDPROC)::GetWindowLongPtr(hTree, GWLP_WNDPROC);
|
||||
::SetPropA(hTree, OUTLINER_TREE_OLDPROC, (HANDLE)oldProc);
|
||||
::SetWindowLongPtr(hTree, GWLP_WNDPROC, (LONG_PTR)Outliner_TreeProc);
|
||||
}
|
||||
|
||||
static HBRUSH Outliner_BackgroundBrush() {
|
||||
static HBRUSH hBrush = ::CreateSolidBrush(OUTLINER_BG);
|
||||
return hBrush;
|
||||
}
|
||||
|
||||
static const int OUTLINER_MARGIN = 6;
|
||||
static const int OUTLINER_FILTER_LABEL_W = 42;
|
||||
@@ -222,7 +421,7 @@ BOOL COutlinerDlg::Create(CWnd* pParentWnd) {
|
||||
CString className = AfxRegisterWndClass(
|
||||
CS_DBLCLKS,
|
||||
::LoadCursor(NULL, IDC_ARROW),
|
||||
(HBRUSH)(COLOR_BTNFACE + 1),
|
||||
Outliner_BackgroundBrush(),
|
||||
NULL
|
||||
);
|
||||
|
||||
@@ -278,8 +477,16 @@ int COutlinerDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) {
|
||||
this,
|
||||
IDC_OUTLINER_TREE
|
||||
);
|
||||
m_tree.ModifyStyleEx(0, WS_EX_CLIENTEDGE, SWP_FRAMECHANGED);
|
||||
m_filter.ModifyStyleEx(WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED);
|
||||
m_tree.ModifyStyleEx(WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED);
|
||||
m_tree.SetItemHeight(20);
|
||||
m_tree.SetBkColor(OUTLINER_PANEL_BG);
|
||||
m_tree.SetTextColor(OUTLINER_TEXT);
|
||||
Outliner_ApplyNativeDarkTheme(GetSafeHwnd());
|
||||
Outliner_ApplyNativeDarkTheme(m_filter.GetSafeHwnd());
|
||||
Outliner_ApplyNativeDarkTheme(m_tree.GetSafeHwnd());
|
||||
Outliner_ApplyDarkTreeImages(m_tree.GetSafeHwnd());
|
||||
Outliner_SubclassTreeForCheckClicks(m_tree.GetSafeHwnd());
|
||||
|
||||
ApplyFont();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user