From 1a08d4af90940201163d4db3372318477554dc02 Mon Sep 17 00:00:00 2001 From: Justin Marshall Date: Wed, 6 May 2026 12:47:20 -0700 Subject: [PATCH] Added new editor layout similar to idTech 5. Cleaned up the entity inspector. Fixed numerous radiant bugs. --- neo/framework/Licensee.h | 7 +- neo/tools/radiant/CamWnd.cpp | 569 +++++++++- neo/tools/radiant/EntityDlg.cpp | 1407 ++++++++++++++++--------- neo/tools/radiant/EntityDlg.h | 154 ++- neo/tools/radiant/InspectorDialog.cpp | 342 ++++-- neo/tools/radiant/InspectorDialog.h | 13 + neo/tools/radiant/MainFrm.cpp | 856 +++++++++++++-- neo/tools/radiant/MainFrm.h | 116 +- neo/tools/radiant/SurfaceDlg.cpp | 43 +- neo/tools/radiant/XYWnd.cpp | 934 +++++++++++++++- neo/tools/radiant/XYWnd.h | 165 +++ 11 files changed, 3883 insertions(+), 723 deletions(-) diff --git a/neo/framework/Licensee.h b/neo/framework/Licensee.h index 8bc1ddb1..9c66bcdd 100644 --- a/neo/framework/Licensee.h +++ b/neo/framework/Licensee.h @@ -101,9 +101,14 @@ If you have questions concerning this license or the applicable additional terms #define RENDERDEMO_VERSION 2 // editor info + +#ifdef PREY +#define EDITOR_DEFAULT_PROJECT "prey.qe4" +#else #define EDITOR_DEFAULT_PROJECT "doom.qe4" +#endif #define EDITOR_REGISTRY_KEY "DOOMRadiant" -#define EDITOR_WINDOWTEXT "IceEdit2(for " GAME_NAME " )" +#define EDITOR_WINDOWTEXT "IceEdit2 for " GAME_NAME "" // win32 info #define WIN32_CONSOLE_CLASS "DOOM 3 WinConsole" diff --git a/neo/tools/radiant/CamWnd.cpp b/neo/tools/radiant/CamWnd.cpp index e03b277e..6c7d7168 100644 --- a/neo/tools/radiant/CamWnd.cpp +++ b/neo/tools/radiant/CamWnd.cpp @@ -826,6 +826,496 @@ static void CameraNav_DrawOverlay(CCamWnd* cam) { } +/* +======================== +Camera window embedded menu bar + +The camera view is an OpenGL window, so the menu is a real child window at the +very top of the camera client area. CCamWnd reserves that strip in OnSize() and +all GL viewports/scissors use the reduced camera height, which keeps the camera +view from drawing underneath the menu. +======================== +*/ +bool IsBModel(brush_t* b); + +static const char* CAMWND_MENU_BAR_CLASS = "QER_CamWndMenuBar"; +static const char* CAMWND_PROP_MENU_BAR = "QER_CamWnd_MenuBar"; +static const char* CAMWND_PROP_RENDER_MODE = "QER_CamWnd_RenderMode"; +static const char* CAMWND_PROP_REBUILD_MODE = "QER_CamWnd_RebuildMode"; +static const char* CAMWND_PROP_ENTITY_MODE = "QER_CamWnd_EntityMode"; +static const char* CAMWND_PROP_FILTER_MASK = "QER_CamWnd_FilterMask"; + +#define CAMWND_MENU_HEIGHT 22 +#define CAMWND_MENU_CHILD_ID 62000 +#define CAMWND_MENU_CMD_REALTIME_LIGHTING 62100 +#define CAMWND_MENU_CMD_SHOW_WORLD 62101 +#define CAMWND_MENU_CMD_SHOW_PATCHES 62102 +#define CAMWND_MENU_CMD_SHOW_MODELS 62103 +#define CAMWND_MENU_CMD_SHOW_ENTITIES 62104 +#define CAMWND_MENU_CMD_SHOW_LIGHTS 62105 +#define CAMWND_MENU_CMD_RESET_FILTERS 62106 + +#define CAMWND_FILTER_HIDE_WORLD 0x00000001 +#define CAMWND_FILTER_HIDE_PATCHES 0x00000002 +#define CAMWND_FILTER_HIDE_MODELS 0x00000004 +#define CAMWND_FILTER_HIDE_ENTITIES 0x00000008 +#define CAMWND_FILTER_HIDE_LIGHTS 0x00000010 + +static LRESULT CALLBACK CamWnd_MenuBarProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +static int CamWnd_GetMenuHeight() { + return CAMWND_MENU_HEIGHT; +} + +static int CamWnd_GetIntProp(HWND hWnd, const char* name, int defaultValue = 0) { + if (!hWnd) { + return defaultValue; + } + HANDLE value = GetProp(hWnd, name); + if (!value) { + return defaultValue; + } + return (int)(INT_PTR)value; +} + +static void CamWnd_SetIntProp(HWND hWnd, const char* name, int value) { + if (!hWnd) { + return; + } + if (value == 0) { + RemoveProp(hWnd, name); + } + else { + SetProp(hWnd, name, (HANDLE)(INT_PTR)value); + } +} + +static int CamWnd_GetFilterMask(CCamWnd* cam) { + return cam ? CamWnd_GetIntProp(cam->GetSafeHwnd(), CAMWND_PROP_FILTER_MASK, 0) : 0; +} + +static void CamWnd_SetFilterMask(CCamWnd* cam, int mask) { + if (!cam) { + return; + } + CamWnd_SetIntProp(cam->GetSafeHwnd(), CAMWND_PROP_FILTER_MASK, mask); +} + +static CCamWnd* CamWnd_FromMenuBar(HWND hWnd) { + HWND parent = GetParent(hWnd); + if (!parent) { + return NULL; + } + CWnd* wnd = CWnd::FromHandlePermanent(parent); + return DYNAMIC_DOWNCAST(CCamWnd, wnd); +} + +static HWND CamWnd_GetMenuBar(CCamWnd* cam) { + if (!cam || !cam->GetSafeHwnd()) { + return NULL; + } + HWND hBar = (HWND)GetProp(cam->GetSafeHwnd(), CAMWND_PROP_MENU_BAR); + return IsWindow(hBar) ? hBar : NULL; +} + +static void CamWnd_RequestRedraw(CCamWnd* cam) { + if (cam && cam->GetSafeHwnd()) { + cam->InvalidateRect(NULL, FALSE); + } + Sys_UpdateWindows(W_CAMERA); + if (g_pParentWnd) { + g_pParentWnd->PostMessage(WM_TIMER, 0, 0); + } +} + +static void CamWnd_GetMenuItemRect(HWND hWnd, int item, RECT& rect) { + GetClientRect(hWnd, &rect); + rect.top = 1; + rect.bottom = CAMWND_MENU_HEIGHT - 1; + + if (item == 0) { + rect.left = 4; + rect.right = 86; + } + else { + rect.left = 86; + rect.right = 156; + } +} + +static int CamWnd_MenuHitTest(HWND hWnd, int x, int y) { + RECT rect; + for (int i = 0; i < 2; i++) { + CamWnd_GetMenuItemRect(hWnd, i, rect); + if (x >= rect.left && x < rect.right && y >= rect.top && y < rect.bottom) { + return i; + } + } + return -1; +} + +static bool CamWnd_RealtimeLightingEnabled(CCamWnd* cam) { + if (!cam || !cam->GetSafeHwnd()) { + return false; + } + const HWND hWnd = cam->GetSafeHwnd(); + return CamWnd_GetIntProp(hWnd, CAMWND_PROP_RENDER_MODE, 0) != 0 && + CamWnd_GetIntProp(hWnd, CAMWND_PROP_REBUILD_MODE, 0) != 0; +} + +static void CamWnd_SetRealtimeLighting(CCamWnd* cam, bool enabled) { + if (!cam || !cam->GetSafeHwnd()) { + return; + } + + const HWND hWnd = cam->GetSafeHwnd(); + bool renderMode = CamWnd_GetIntProp(hWnd, CAMWND_PROP_RENDER_MODE, 0) != 0; + bool rebuildMode = CamWnd_GetIntProp(hWnd, CAMWND_PROP_REBUILD_MODE, 0) != 0; + + if (enabled) { + if (!renderMode) { + cam->ToggleRenderMode(); + } + if (!rebuildMode) { + cam->ToggleRebuildMode(); + } + } + else { + if (rebuildMode) { + cam->ToggleRebuildMode(); + } + if (renderMode) { + cam->ToggleRenderMode(); + } + } + + CamWnd_RequestRedraw(cam); +} + +static void CamWnd_ToggleRealtimeLighting(CCamWnd* cam) { + CamWnd_SetRealtimeLighting(cam, !CamWnd_RealtimeLightingEnabled(cam)); +} + +static void CamWnd_ToggleFilterBit(CCamWnd* cam, int bit) { + int mask = CamWnd_GetFilterMask(cam); + mask ^= bit; + CamWnd_SetFilterMask(cam, mask); + CamWnd_RequestRedraw(cam); +} + +static void CamWnd_ResetFilters(CCamWnd* cam) { + CamWnd_SetFilterMask(cam, 0); + CamWnd_RequestRedraw(cam); +} + +static void CamWnd_HandleMenuCommand(CCamWnd* cam, int command) { + switch (command) { + case CAMWND_MENU_CMD_REALTIME_LIGHTING: + CamWnd_ToggleRealtimeLighting(cam); + break; + case CAMWND_MENU_CMD_SHOW_WORLD: + CamWnd_ToggleFilterBit(cam, CAMWND_FILTER_HIDE_WORLD); + break; + case CAMWND_MENU_CMD_SHOW_PATCHES: + CamWnd_ToggleFilterBit(cam, CAMWND_FILTER_HIDE_PATCHES); + break; + case CAMWND_MENU_CMD_SHOW_MODELS: + CamWnd_ToggleFilterBit(cam, CAMWND_FILTER_HIDE_MODELS); + break; + case CAMWND_MENU_CMD_SHOW_ENTITIES: + CamWnd_ToggleFilterBit(cam, CAMWND_FILTER_HIDE_ENTITIES); + break; + case CAMWND_MENU_CMD_SHOW_LIGHTS: + CamWnd_ToggleFilterBit(cam, CAMWND_FILTER_HIDE_LIGHTS); + break; + case CAMWND_MENU_CMD_RESET_FILTERS: + CamWnd_ResetFilters(cam); + break; + } +} + +static void CamWnd_AppendVisibleFilterItem(HMENU menu, int mask, int bit, UINT command, const char* text) { + UINT flags = MF_STRING; + if ((mask & bit) == 0) { + flags |= MF_CHECKED; + } + AppendMenu(menu, flags, command, text); +} + +static void CamWnd_ShowLightingMenu(HWND hWnd, CCamWnd* cam) { + RECT itemRect; + POINT pt; + HMENU menu; + int command; + + CamWnd_GetMenuItemRect(hWnd, 0, itemRect); + pt.x = itemRect.left; + pt.y = itemRect.bottom; + ClientToScreen(hWnd, &pt); + + menu = CreatePopupMenu(); + AppendMenu(menu, MF_STRING | (CamWnd_RealtimeLightingEnabled(cam) ? MF_CHECKED : 0), CAMWND_MENU_CMD_REALTIME_LIGHTING, "Real-time lighting"); + + command = TrackPopupMenu(menu, TPM_RETURNCMD | TPM_LEFTALIGN | TPM_TOPALIGN, pt.x, pt.y, 0, hWnd, NULL); + DestroyMenu(menu); + + if (command) { + CamWnd_HandleMenuCommand(cam, command); + } +} + +static void CamWnd_ShowFiltersMenu(HWND hWnd, CCamWnd* cam) { + RECT itemRect; + POINT pt; + HMENU menu; + int command; + int mask = CamWnd_GetFilterMask(cam); + + CamWnd_GetMenuItemRect(hWnd, 1, itemRect); + pt.x = itemRect.left; + pt.y = itemRect.bottom; + ClientToScreen(hWnd, &pt); + + menu = CreatePopupMenu(); + CamWnd_AppendVisibleFilterItem(menu, mask, CAMWND_FILTER_HIDE_WORLD, CAMWND_MENU_CMD_SHOW_WORLD, "Show world geometry"); + CamWnd_AppendVisibleFilterItem(menu, mask, CAMWND_FILTER_HIDE_PATCHES, CAMWND_MENU_CMD_SHOW_PATCHES, "Show patches"); + CamWnd_AppendVisibleFilterItem(menu, mask, CAMWND_FILTER_HIDE_MODELS, CAMWND_MENU_CMD_SHOW_MODELS, "Show models"); + CamWnd_AppendVisibleFilterItem(menu, mask, CAMWND_FILTER_HIDE_ENTITIES, CAMWND_MENU_CMD_SHOW_ENTITIES, "Show entities"); + CamWnd_AppendVisibleFilterItem(menu, mask, CAMWND_FILTER_HIDE_LIGHTS, CAMWND_MENU_CMD_SHOW_LIGHTS, "Show lights"); + AppendMenu(menu, MF_SEPARATOR, 0, NULL); + AppendMenu(menu, MF_STRING, CAMWND_MENU_CMD_RESET_FILTERS, "Reset filters"); + + command = TrackPopupMenu(menu, TPM_RETURNCMD | TPM_LEFTALIGN | TPM_TOPALIGN, pt.x, pt.y, 0, hWnd, NULL); + DestroyMenu(menu); + + if (command) { + CamWnd_HandleMenuCommand(cam, command); + } +} + +static void CamWnd_ShowTopMenu(HWND hWnd, int item) { + CCamWnd* cam = CamWnd_FromMenuBar(hWnd); + if (!cam) { + return; + } + if (item == 0) { + CamWnd_ShowLightingMenu(hWnd, cam); + } + else if (item == 1) { + CamWnd_ShowFiltersMenu(hWnd, cam); + } +} + +static void CamWnd_RegisterMenuBarClass() { + static bool registered = false; + if (registered) { + return; + } + + WNDCLASS wc; + memset(&wc, 0, sizeof(wc)); + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = CamWnd_MenuBarProc; + wc.hInstance = AfxGetInstanceHandle(); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); + wc.lpszClassName = CAMWND_MENU_BAR_CLASS; + AfxRegisterClass(&wc); + registered = true; +} + +static HWND CamWnd_EnsureMenuBar(CCamWnd* cam) { + if (!cam || !cam->GetSafeHwnd()) { + return NULL; + } + + HWND hBar = CamWnd_GetMenuBar(cam); + if (hBar) { + return hBar; + } + + CamWnd_RegisterMenuBarClass(); + + CRect rect; + cam->GetClientRect(rect); + hBar = CreateWindowEx( + 0, + CAMWND_MENU_BAR_CLASS, + "", + WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, + 0, + 0, + rect.Width(), + CAMWND_MENU_HEIGHT, + cam->GetSafeHwnd(), + (HMENU)CAMWND_MENU_CHILD_ID, + AfxGetInstanceHandle(), + NULL); + + if (hBar) { + SetProp(cam->GetSafeHwnd(), CAMWND_PROP_MENU_BAR, hBar); + SendMessage(hBar, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), FALSE); + } + + return hBar; +} + +static void CamWnd_LayoutMenuBar(CCamWnd* cam) { + if (!cam || !cam->GetSafeHwnd()) { + return; + } + + HWND hBar = CamWnd_EnsureMenuBar(cam); + if (!hBar) { + return; + } + + CRect rect; + cam->GetClientRect(rect); + MoveWindow(hBar, 0, 0, rect.Width(), CAMWND_MENU_HEIGHT, TRUE); +} + +static void CamWnd_DestroyMenuBar(CCamWnd* cam) { + if (!cam || !cam->GetSafeHwnd()) { + return; + } + HWND hBar = CamWnd_GetMenuBar(cam); + if (hBar) { + DestroyWindow(hBar); + } + RemoveProp(cam->GetSafeHwnd(), CAMWND_PROP_MENU_BAR); + RemoveProp(cam->GetSafeHwnd(), CAMWND_PROP_RENDER_MODE); + RemoveProp(cam->GetSafeHwnd(), CAMWND_PROP_REBUILD_MODE); + RemoveProp(cam->GetSafeHwnd(), CAMWND_PROP_ENTITY_MODE); + RemoveProp(cam->GetSafeHwnd(), CAMWND_PROP_FILTER_MASK); +} + +static bool CamWnd_PointInMenuBar(CCamWnd* cam, const CPoint& point) { + if (!cam || !cam->GetSafeHwnd()) { + return false; + } + return point.y >= 0 && point.y < CAMWND_MENU_HEIGHT; +} + +static void CamWnd_UpdateRuntimeState(CCamWnd* cam, bool renderMode, bool rebuildMode, bool entityMode) { + if (!cam || !cam->GetSafeHwnd()) { + return; + } + const HWND hWnd = cam->GetSafeHwnd(); + CamWnd_SetIntProp(hWnd, CAMWND_PROP_RENDER_MODE, renderMode ? 1 : 0); + CamWnd_SetIntProp(hWnd, CAMWND_PROP_REBUILD_MODE, rebuildMode ? 1 : 0); + CamWnd_SetIntProp(hWnd, CAMWND_PROP_ENTITY_MODE, entityMode ? 1 : 0); + + HWND hBar = CamWnd_GetMenuBar(cam); + if (hBar) { + InvalidateRect(hBar, NULL, FALSE); + } +} + +static bool CamWnd_MenuFilterBrush(CCamWnd* cam, brush_t* brush) { + if (!cam || !brush) { + return false; + } + + const int mask = CamWnd_GetFilterMask(cam); + if (mask == 0) { + return false; + } + + const bool hasOwner = (brush->owner != NULL && brush->owner->eclass != NULL); + const bool isLight = hasOwner && ((brush->owner->eclass->nShowFlags & ECLASS_LIGHT) != 0); + const bool isPatch = (brush->pPatch != NULL); + const bool isModel = (brush->modelHandle > 0) || (hasOwner && brush->owner->eclass->entityModel) || brush->entityModel; + const bool isBrushModel = hasOwner && IsBModel(brush); + const bool isFixedEntity = hasOwner && brush->owner->eclass->fixedsize; + const bool isEntity = isLight || isModel || isBrushModel || isFixedEntity; + + if ((mask & CAMWND_FILTER_HIDE_LIGHTS) && isLight) { + return true; + } + if ((mask & CAMWND_FILTER_HIDE_MODELS) && isModel) { + return true; + } + if ((mask & CAMWND_FILTER_HIDE_ENTITIES) && isEntity) { + return true; + } + if ((mask & CAMWND_FILTER_HIDE_PATCHES) && isPatch) { + return true; + } + if ((mask & CAMWND_FILTER_HIDE_WORLD) && !isEntity && !isPatch && !isModel) { + return true; + } + + return false; +} + +static LRESULT CALLBACK CamWnd_MenuBarProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + switch (uMsg) { + case WM_ERASEBKGND: + return 1; + + case WM_SETCURSOR: + SetCursor(LoadCursor(NULL, IDC_ARROW)); + return TRUE; + + case WM_LBUTTONDOWN: + SetCapture(hWnd); + return 0; + + case WM_LBUTTONUP: + { + if (GetCapture() == hWnd) { + ReleaseCapture(); + } + const int x = (short)LOWORD(lParam); + const int y = (short)HIWORD(lParam); + const int item = CamWnd_MenuHitTest(hWnd, x, y); + if (item >= 0) { + CamWnd_ShowTopMenu(hWnd, item); + } + return 0; + } + + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hDC = BeginPaint(hWnd, &ps); + RECT rect; + GetClientRect(hWnd, &rect); + + FillRect(hDC, &rect, (HBRUSH)(COLOR_BTNFACE + 1)); + + RECT lineRect = rect; + lineRect.top = CAMWND_MENU_HEIGHT - 1; + FillRect(hDC, &lineRect, (HBRUSH)(COLOR_3DSHADOW + 1)); + + HFONT font = (HFONT)SendMessage(hWnd, WM_GETFONT, 0, 0); + HFONT oldFont = NULL; + if (font) { + oldFont = (HFONT)SelectObject(hDC, font); + } + + SetBkMode(hDC, TRANSPARENT); + SetTextColor(hDC, GetSysColor(COLOR_BTNTEXT)); + + RECT itemRect; + CamWnd_GetMenuItemRect(hWnd, 0, itemRect); + DrawText(hDC, "Lighting", -1, &itemRect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); + CamWnd_GetMenuItemRect(hWnd, 1, itemRect); + DrawText(hDC, "Filters", -1, &itemRect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); + + if (oldFont) { + SelectObject(hDC, oldFont); + } + EndPaint(hWnd, &ps); + return 0; + } + } + + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + + int g_axialAnchor = -1; int g_axialDest = -1; bool g_bAxialMode = false; @@ -969,6 +1459,10 @@ BOOL CCamWnd::PreCreateWindow(CREATESTRUCT& cs) { cs.style = QE3_SPLITTER_STYLE; } + // Keep the OpenGL camera surface out of child-window areas such as the + // embedded menu bar. + cs.style |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS; + BOOL bResult = CWnd::PreCreateWindow(cs); // @@ -1000,6 +1494,8 @@ void CCamWnd::OnPaint() { bool bPaint = true; UpdateCaption(); + CamWnd_EnsureMenuBar(this); + CamWnd_LayoutMenuBar(this); idGraphicsDeviceContextHelper context(dc.m_hDC, hglrc); @@ -1026,6 +1522,7 @@ void CCamWnd::SetXYFriend(CXYWnd* pWnd) { ======================================================================================================================= */ void CCamWnd::OnDestroy() { + CamWnd_DestroyMenuBar(this); CWnd::OnDestroy(); } @@ -1078,12 +1575,14 @@ void CCamWnd::OnMouseMove(UINT nFlags, CPoint point) { ======================================================================================================================= */ void CCamWnd::OnLButtonDown(UINT nFlags, CPoint point) { + if (CamWnd_PointInMenuBar(this, point)) { + return; + } + m_ptLastCursor = point; if (CameraNav_IsActive(this)) { - CRect r; - GetClientRect(r); - int x = r.Width() / 2; - int y = r.Height() / 2; + int x = m_Camera.width / 2; + int y = m_Camera.height / 2; Cam_MouseDown(x, y, MK_LBUTTON); Cam_MouseUp(x, y, 0); Sys_UpdateWindows(W_ALL); @@ -1105,6 +1604,10 @@ void CCamWnd::OnLButtonUp(UINT nFlags, CPoint point) { ======================================================================================================================= */ void CCamWnd::OnMButtonDown(UINT nFlags, CPoint point) { + if (CamWnd_PointInMenuBar(this, point)) { + return; + } + OriginalMouseDown(nFlags, point); } @@ -1121,6 +1624,10 @@ void CCamWnd::OnMButtonUp(UINT nFlags, CPoint point) { ======================================================================================================================= */ void CCamWnd::OnRButtonDown(UINT nFlags, CPoint point) { + if (CamWnd_PointInMenuBar(this, point)) { + return; + } + m_ptLastCursor = point; if (!(nFlags & (MK_SHIFT | MK_CONTROL)) && CameraNav_Begin(this)) { return; @@ -1213,6 +1720,10 @@ int CCamWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) { common->Printf("GL_VERSION: %s\n", glGetString(GL_VERSION)); common->Printf("GL_EXTENSIONS: %s\n", glGetString(GL_EXTENSIONS)); + CamWnd_UpdateRuntimeState(this, renderMode, rebuildMode, entityMode); + CamWnd_EnsureMenuBar(this); + CamWnd_LayoutMenuBar(this); + return 0; } @@ -1791,6 +2302,7 @@ void CCamWnd::Cam_Draw() { glViewport(0, 0, m_Camera.width, m_Camera.height); + glEnable(GL_SCISSOR_TEST); glScissor(0, 0, m_Camera.width, m_Camera.height); glClearColor(g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][0], g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][1], g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][2], 0); @@ -1821,6 +2333,10 @@ void CCamWnd::Cam_Draw() { continue; } + if (CamWnd_MenuFilterBrush(this, brush)) { + continue; + } + if (renderMode) { if (!(entityMode && brush->owner->eclass->fixedsize)) { continue; @@ -1842,6 +2358,9 @@ void CCamWnd::Cam_Draw() { if (!renderMode) { // draw normally for (brush = pList->next; brush != pList; brush = brush->next) { + if (CamWnd_MenuFilterBrush(this, brush)) { + continue; + } if (brush->pPatch) { continue; } @@ -1860,6 +2379,9 @@ void CCamWnd::Cam_Draw() { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); globalImages->BindNull(); for (brush = pList->next; brush != pList; brush = brush->next) { + if (CamWnd_MenuFilterBrush(this, brush)) { + continue; + } if (brush->pPatch || brush->modelHandle > 0) { Brush_Draw(brush, true); @@ -1905,6 +2427,9 @@ void CCamWnd::Cam_Draw() { glColor3f(1, 1, 1); for (brush = pList->next; brush != pList; brush = brush->next) { + if (CamWnd_MenuFilterBrush(this, brush)) { + continue; + } if (brush->pPatch || brush->modelHandle > 0) { continue; } @@ -1964,6 +2489,7 @@ void CCamWnd::Cam_Draw() { CameraNav_DrawOverlay(this); + glDisable(GL_SCISSOR_TEST); glFinish(); QE_CheckOpenGLForErrors(); @@ -1982,8 +2508,13 @@ void CCamWnd::OnSize(UINT nType, int cx, int cy) { CRect rect; GetClientRect(rect); - m_Camera.width = rect.right; - m_Camera.height = rect.bottom; + CamWnd_EnsureMenuBar(this); + CamWnd_LayoutMenuBar(this); + m_Camera.width = rect.Width(); + m_Camera.height = rect.Height() - CamWnd_GetMenuHeight(); + if (m_Camera.height < 1) { + m_Camera.height = 1; + } InvalidateRect(NULL, false); } @@ -2225,11 +2756,14 @@ static unsigned int EditorHashBrushGeometry(brush_t* brush, const idVec3& origin return hash; } -static unsigned int EditorHashBModelGeometry(entity_t* ent) { +static unsigned int EditorHashBModelGeometry(CCamWnd* cam, entity_t* ent) { unsigned int hash = EDITOR_RENDER_HASH_INIT; hash = EditorHashString(hash, ValueForKey(ent, "name")); for (brush_t* brush = ent->brushes.onext; brush != &ent->brushes; brush = brush->onext) { + if (FilterBrush(brush) || CamWnd_MenuFilterBrush(cam, brush) || Map_IsBrushFiltered(brush)) { + continue; + } const unsigned int brushHash = EditorHashBrushGeometry(brush, ent->origin); hash = EditorHashInt(hash, brushHash); } @@ -2281,11 +2815,14 @@ static idRenderModel* EditorBuildSingleBrushModel(brush_t* brush, const idVec3& return model; } -static idRenderModel* EditorBuildBModel(entity_t* ent, const char* name) { +static idRenderModel* EditorBuildBModel(CCamWnd* cam, entity_t* ent, const char* name) { idTriList tris(1024); idMatList mats(1024); for (brush_t* brush = ent->brushes.onext; brush != &ent->brushes; brush = brush->onext) { + if (FilterBrush(brush) || CamWnd_MenuFilterBrush(cam, brush) || Map_IsBrushFiltered(brush)) { + continue; + } Brush_ToTris(brush, &tris, &mats, false, true); } @@ -2384,6 +2921,9 @@ static bool EditorWorldBrushRenderable(CCamWnd* cam, brush_t* brush) { if (FilterBrush(brush)) { return false; } + if (CamWnd_MenuFilterBrush(cam, brush)) { + return false; + } if (cam->CullBrush(brush, true)) { return false; } @@ -2631,6 +3171,7 @@ void CCamWnd::BuildEntityRenderState(entity_t* ent, bool update) { // If the entity is no longer renderable, remove only this entity's defs. if (ent->brushes.onext == &ent->brushes || FilterBrush(ent->brushes.onext) || + CamWnd_MenuFilterBrush(this, ent->brushes.onext) || CullBrush(ent->brushes.onext, true) || Map_IsBrushFiltered(ent->brushes.onext)) { EditorFreeEntityModelDef(entityState, ent); @@ -2655,7 +3196,7 @@ void CCamWnd::BuildEntityRenderState(entity_t* ent, bool update) { // Brush model entity. Rebuild the renderModel only when the // entity-local brush geometry/materials changed. Plain movement // is handled by UpdateEntityDef below. - const unsigned int geometryHash = EditorHashBModelGeometry(ent); + const unsigned int geometryHash = EditorHashBModelGeometry(this, ent); editorRenderBModelState_t* bmodelState = EditorTouchBModelState(ent); idRenderModel* oldModel = NULL; @@ -2665,7 +3206,7 @@ void CCamWnd::BuildEntityRenderState(entity_t* ent, bool update) { idStr::Icmp(bmodelState->modelName.c_str(), name) != 0); if (geometryChanged) { - idRenderModel* newModel = EditorBuildBModel(ent, name); + idRenderModel* newModel = EditorBuildBModel(this, ent, name); if (newModel) { oldModel = bmodelState->model; bmodelState->model = newModel; @@ -3229,6 +3770,7 @@ void CCamWnd::UpdateCaption() { strCaption += (animationMode) ? " +anim" : ""; } strCaption += (soundMode) ? " +snd" : ""; + CamWnd_UpdateRuntimeState(this, renderMode, rebuildMode, entityMode); SetWindowText(strCaption); } @@ -3379,6 +3921,10 @@ void CCamWnd::DrawEntityData() { continue; } + if (CamWnd_MenuFilterBrush(this, brush)) { + continue; + } + if ((pass == 1 && selectMode) || (entityMode && pass == 0 && brush->owner->lightDef >= 0)) { Brush_DrawXY(brush, 0, true, true); } @@ -3413,6 +3959,8 @@ void CCamWnd::Cam_Render() { // save the editor state //glPushAttrib( GL_ALL_ATTRIB_BITS ); + glViewport(0, 0, m_Camera.width, m_Camera.height); + glEnable(GL_SCISSOR_TEST); glClearColor(0.1f, 0.1f, 0.1f, 0.0f); glScissor(0, 0, m_Camera.width, m_Camera.height); glClear(GL_COLOR_BUFFER_BIT); @@ -3453,6 +4001,7 @@ void CCamWnd::Cam_Render() { //wglSwapBuffers(dc.m_hDC); // get back to the editor state + glDisable(GL_SCISSOR_TEST); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); Cam_BuildMatrix(); diff --git a/neo/tools/radiant/EntityDlg.cpp b/neo/tools/radiant/EntityDlg.cpp index c27541ac..62ad5384 100644 --- a/neo/tools/radiant/EntityDlg.cpp +++ b/neo/tools/radiant/EntityDlg.cpp @@ -2,26 +2,9 @@ =========================================================================== Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. +Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. -This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?). - -Doom 3 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. - -Doom 3 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 Doom 3 Source Code. If not, see . - -In addition, the Doom 3 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 Doom 3 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 id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. +Modernized Entity Inspector UI pass by Justin / IceBridge workflow. =========================================================================== */ @@ -39,34 +22,49 @@ If you have questions concerning this license or the applicable additional terms #include "../../renderer/model_local.h" // for idRenderModelPrt -void Select_Ungroup(); +void Select_Ungroup(); // CEntityDlg dialog IMPLEMENT_DYNAMIC(CEntityDlg, CDialog) + CEntityDlg::CEntityDlg(CWnd* pParent /*=NULL*/) - : CDialog(CEntityDlg::IDD, pParent) -{ + : CDialog(CEntityDlg::IDD, pParent) { editEntity = NULL; multipleEntities = false; currentAnimation = NULL; + currentAnimationFrame = 0; + 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); } -CEntityDlg::~CEntityDlg() -{ +CEntityDlg::~CEntityDlg() { + DestroyModernTheme(); } -void CEntityDlg::DoDataExchange(CDataExchange* pDX) -{ +void CEntityDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); + DDX_Control(pDX, IDC_LIST_KEYVAL, listKeyVal); DDX_Control(pDX, IDC_COMBO_CLASS, comboClass); DDX_Control(pDX, IDC_EDIT_KEY, editKey); DDX_Control(pDX, IDC_EDIT_VAL, editVal); + DDX_Control(pDX, IDC_STATIC_TITLE, staticTitle); DDX_Control(pDX, IDC_STATIC_KEY, staticKey); DDX_Control(pDX, IDC_STATIC_VAL, staticVal); + DDX_Control(pDX, IDC_BUTTON_BROWSE, btnBrowse); + DDX_Control(pDX, IDC_E_135, btn135); DDX_Control(pDX, IDC_E_90, btn90); DDX_Control(pDX, IDC_E_45, btn45); @@ -77,6 +75,7 @@ void CEntityDlg::DoDataExchange(CDataExchange* pDX) DDX_Control(pDX, IDC_E_315, btn315); DDX_Control(pDX, IDC_E_UP, btnUp); DDX_Control(pDX, IDC_E_DOWN, btnDown); + DDX_Control(pDX, IDC_BUTTON_MODEL, btnModel); DDX_Control(pDX, IDC_BUTTON_SOUND, btnSound); DDX_Control(pDX, IDC_BUTTON_GUI, btnGui); @@ -84,48 +83,25 @@ void CEntityDlg::DoDataExchange(CDataExchange* pDX) DDX_Control(pDX, IDC_BUTTON_SKIN, btnSkin); DDX_Control(pDX, IDC_BUTTON_CURVE, btnCurve); DDX_Control(pDX, IDC_BUTTON_CREATE, btnCreate); + DDX_Control(pDX, IDC_LIST_VARS, listVars); - DDX_Control(pDX, IDC_ENTITY_ANIMATIONS , cbAnimations); - DDX_Control(pDX, IDC_ANIMATION_SLIDER , slFrameSlider); - DDX_Control(pDX, IDC_ENTITY_CURRENT_ANIM , staticFrame); - DDX_Control(pDX, IDC_ENTITY_PLAY_ANIM , btnPlayAnim); - DDX_Control(pDX, IDC_ENTITY_STOP_ANIM , btnStopAnim); -} - - - -BOOL CEntityDlg::OnInitDialog() -{ - CDialog::OnInitDialog(); - listKeyVal.SetUpdateInspectors(true); - listKeyVal.SetDivider(100); - listVars.SetDivider(100); - staticFrame.SetWindowText ( "0" ); - - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - -INT_PTR CEntityDlg::OnToolHitTest(CPoint point, TOOLINFO* pTI) const -{ - // TODO: Add your specialized code here and/or call the base class - - return CDialog::OnToolHitTest(point, pTI); -} - - -void CEntityDlg::AddClassNames() { - comboClass.ResetContent(); - for (eclass_t *pec = eclass; pec; pec = pec->next) { - comboClass.AddString(pec->name); - } + DDX_Control(pDX, IDC_ENTITY_ANIMATIONS, cbAnimations); + DDX_Control(pDX, IDC_ANIMATION_SLIDER, slFrameSlider); + DDX_Control(pDX, IDC_ENTITY_CURRENT_ANIM, staticFrame); + DDX_Control(pDX, IDC_ENTITY_PLAY_ANIM, btnPlayAnim); + DDX_Control(pDX, IDC_ENTITY_STOP_ANIM, btnStopAnim); } BEGIN_MESSAGE_MAP(CEntityDlg, CDialog) ON_WM_SIZE() + ON_WM_CTLCOLOR() + ON_WM_ERASEBKGND() + ON_WM_PAINT() + ON_CBN_SELCHANGE(IDC_COMBO_CLASS, OnCbnSelchangeComboClass) ON_LBN_SELCHANGE(IDC_LIST_KEYVAL, OnLbnSelchangeListkeyval) + ON_BN_CLICKED(IDC_E_135, OnBnClickedE135) ON_BN_CLICKED(IDC_E_90, OnBnClickedE90) ON_BN_CLICKED(IDC_E_45, OnBnClickedE45) @@ -136,138 +112,536 @@ BEGIN_MESSAGE_MAP(CEntityDlg, CDialog) ON_BN_CLICKED(IDC_E_315, OnBnClickedE315) ON_BN_CLICKED(IDC_E_UP, OnBnClickedEUp) ON_BN_CLICKED(IDC_E_DOWN, OnBnClickedEDown) + ON_BN_CLICKED(IDC_BUTTON_MODEL, OnBnClickedButtonModel) ON_BN_CLICKED(IDC_BUTTON_SOUND, OnBnClickedButtonSound) ON_BN_CLICKED(IDC_BUTTON_GUI, OnBnClickedButtonGui) ON_BN_CLICKED(IDC_BUTTON_BROWSE, OnBnClickedButtonBrowse) ON_CBN_DBLCLK(IDC_COMBO_CLASS, OnCbnDblclkComboClass) ON_BN_CLICKED(IDC_BUTTON_CREATE, OnBnClickedButtonCreate) + ON_LBN_DBLCLK(IDC_LIST_KEYVAL, OnLbnDblclkListkeyval) ON_LBN_SELCHANGE(IDC_LIST_VARS, OnLbnSelchangeListVars) ON_LBN_DBLCLK(IDC_LIST_VARS, OnLbnDblclkListVars) + ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_ANIMATION_SLIDER, OnNMReleasedcaptureSlider1) + ON_BN_CLICKED(IDC_BUTTON_PARTICLE, OnBnClickedButtonParticle) ON_BN_CLICKED(IDC_BUTTON_SKIN, OnBnClickedButtonSkin) ON_BN_CLICKED(IDC_BUTTON_CURVE, OnBnClickedButtonCurve) + ON_CBN_SELCHANGE(IDC_ENTITY_ANIMATIONS, OnCbnAnimationChange) - ON_BN_CLICKED(IDC_ENTITY_PLAY_ANIM , OnBnClickedStartAnimation) - ON_BN_CLICKED(IDC_ENTITY_STOP_ANIM , OnBnClickedStopAnimation) + ON_BN_CLICKED(IDC_ENTITY_PLAY_ANIM, OnBnClickedStartAnimation) + ON_BN_CLICKED(IDC_ENTITY_STOP_ANIM, OnBnClickedStopAnimation) + ON_WM_TIMER() ON_BN_CLICKED(IDOK, OnOK) END_MESSAGE_MAP() -void CEntityDlg::OnSize(UINT nType, int cx, int cy) -{ +// -------------------------------------------------------------------------- +// Modern theme helpers +// -------------------------------------------------------------------------- + +void CEntityDlg::DestroyModernTheme() { + if (fontTitle.GetSafeHandle()) { + fontTitle.DeleteObject(); + } + if (fontSection.GetSafeHandle()) { + fontSection.DeleteObject(); + } + if (fontNormal.GetSafeHandle()) { + fontNormal.DeleteObject(); + } + if (fontMono.GetSafeHandle()) { + fontMono.DeleteObject(); + } + + if (brushBackground.GetSafeHandle()) { + brushBackground.DeleteObject(); + } + if (brushPanel.GetSafeHandle()) { + brushPanel.DeleteObject(); + } + if (brushPanelAlt.GetSafeHandle()) { + brushPanelAlt.DeleteObject(); + } + if (brushEdit.GetSafeHandle()) { + brushEdit.DeleteObject(); + } + if (brushStatic.GetSafeHandle()) { + brushStatic.DeleteObject(); + } + + themeInitialized = false; +} + +void CEntityDlg::InitModernTheme() { + if (themeInitialized) { + return; + } + + NONCLIENTMETRICS ncm; + memset(&ncm, 0, sizeof(ncm)); + ncm.cbSize = sizeof(ncm); + SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0); + + LOGFONT lf = ncm.lfMessageFont; + strcpy(lf.lfFaceName, "Segoe UI"); + lf.lfHeight = -12; + lf.lfWeight = FW_NORMAL; + fontNormal.CreateFontIndirect(&lf); + + lf.lfHeight = -17; + lf.lfWeight = FW_SEMIBOLD; + fontTitle.CreateFontIndirect(&lf); + + lf.lfHeight = -12; + lf.lfWeight = FW_SEMIBOLD; + fontSection.CreateFontIndirect(&lf); + + strcpy(lf.lfFaceName, "Consolas"); + lf.lfHeight = -12; + lf.lfWeight = FW_NORMAL; + fontMono.CreateFontIndirect(&lf); + + brushBackground.CreateSolidBrush(colorBackground); + brushPanel.CreateSolidBrush(colorPanel); + brushPanelAlt.CreateSolidBrush(colorPanelAlt); + brushEdit.CreateSolidBrush(colorEditBg); + brushStatic.CreateSolidBrush(colorPanel); + + themeInitialized = true; +} + +void CEntityDlg::SetCtrlFont(CWnd& wnd, CFont* font) { + if (wnd.GetSafeHwnd() && font && font->GetSafeHandle()) { + wnd.SetFont(font, FALSE); + } +} + +void CEntityDlg::SetCtrlFont(int id, CFont* font) { + CWnd* wnd = GetDlgItem(id); + if (wnd && wnd->GetSafeHwnd() && font && font->GetSafeHandle()) { + wnd->SetFont(font, FALSE); + } +} + +void CEntityDlg::ApplyModernTheme() { + InitModernTheme(); + + SetCtrlFont(staticTitle, &fontTitle); + SetCtrlFont(staticKey, &fontSection); + SetCtrlFont(staticVal, &fontSection); + SetCtrlFont(staticFrame, &fontNormal); + + SetCtrlFont(comboClass, &fontNormal); + SetCtrlFont(cbAnimations, &fontNormal); + + SetCtrlFont(editKey, &fontMono); + SetCtrlFont(editVal, &fontMono); + SetCtrlFont(listKeyVal, &fontMono); + SetCtrlFont(listVars, &fontNormal); + + SetCtrlFont(btnCreate, &fontSection); + SetCtrlFont(btnBrowse, &fontSection); + + SetCtrlFont(btnModel, &fontNormal); + SetCtrlFont(btnSound, &fontNormal); + SetCtrlFont(btnGui, &fontNormal); + SetCtrlFont(btnParticle, &fontNormal); + SetCtrlFont(btnSkin, &fontNormal); + SetCtrlFont(btnCurve, &fontNormal); + + SetCtrlFont(btn135, &fontNormal); + SetCtrlFont(btn90, &fontNormal); + SetCtrlFont(btn45, &fontNormal); + SetCtrlFont(btn180, &fontNormal); + SetCtrlFont(btn360, &fontNormal); + SetCtrlFont(btn225, &fontNormal); + SetCtrlFont(btn270, &fontNormal); + SetCtrlFont(btn315, &fontNormal); + SetCtrlFont(btnUp, &fontNormal); + SetCtrlFont(btnDown, &fontNormal); + + SetCtrlFont(btnPlayAnim, &fontNormal); + SetCtrlFont(btnStopAnim, &fontNormal); + + if (editKey.GetSafeHwnd()) { + editKey.SetMargins(6, 6); + } + if (editVal.GetSafeHwnd()) { + editVal.SetMargins(6, 6); + } + + staticTitle.SetWindowText("Entity Inspector"); + staticKey.SetWindowText("Key"); + staticVal.SetWindowText("Value"); +} + +void CEntityDlg::MoveCtrl(CWnd& wnd, int x, int y, int w, int h, UINT flags) { + if (wnd.GetSafeHwnd()) { + wnd.SetWindowPos(NULL, x, y, max(1, w), max(1, h), flags | SWP_NOZORDER); + } +} + +void CEntityDlg::MoveCtrl(int id, int x, int y, int w, int h, UINT flags) { + CWnd* wnd = GetDlgItem(id); + if (wnd && wnd->GetSafeHwnd()) { + wnd->SetWindowPos(NULL, x, y, max(1, w), max(1, h), flags | SWP_NOZORDER); + } +} + +void CEntityDlg::DrawPanel(CDC& dc, const CRect& r, const char* title, bool accent) { + CBrush* oldBrush = dc.SelectObject(&brushPanel); + CPen borderPen(PS_SOLID, 1, accent ? colorAccent : colorBorder); + CPen* oldPen = dc.SelectObject(&borderPen); + + dc.RoundRect(r.left, r.top, r.right, r.bottom, 8, 8); + + if (title && title[0]) { + CRect titleRect = r; + titleRect.left += 10; + titleRect.top += 6; + titleRect.bottom = titleRect.top + 18; + + CFont* oldFont = dc.SelectObject(&fontSection); + dc.SetBkMode(TRANSPARENT); + dc.SetTextColor(accent ? colorAccent : colorTextMuted); + dc.DrawText(title, -1, &titleRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE); + dc.SelectObject(oldFont); + } + + dc.SelectObject(oldPen); + dc.SelectObject(oldBrush); +} + +void CEntityDlg::DrawModernBackground(CDC& dc) { + CRect rect; + GetClientRect(&rect); + + dc.FillSolidRect(&rect, colorBackground); + + const int pad = 8; + CRect header(rect.left + pad, rect.top + pad, rect.right - pad, rect.top + 42); + CRect classPanel(rect.left + pad, header.bottom + pad, rect.right - pad, header.bottom + 52 + pad); + + int contentTop = classPanel.bottom + pad; + int contentBottom = rect.bottom - pad; + int width = rect.Width(); + + if (width >= 560) { + 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 tools(rect.left + pad, editor.bottom + pad, rect.right - pad, contentBottom); + + DrawPanel(dc, header, "", true); + DrawPanel(dc, classPanel, "Class", false); + DrawPanel(dc, vars, "Spawn Args / Help", false); + DrawPanel(dc, keyvals, "Key / Value Pairs", true); + DrawPanel(dc, editor, "Edit Property", false); + DrawPanel(dc, tools, "Tools", false); + } + else { + int h = max(120, (contentBottom - contentTop - pad * 3) / 4); + + 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 tools(rect.left + pad, editor.bottom + pad, rect.right - pad, contentBottom); + + DrawPanel(dc, header, "", true); + DrawPanel(dc, classPanel, "Class", false); + DrawPanel(dc, vars, "Spawn Args / Help", false); + DrawPanel(dc, keyvals, "Key / Value Pairs", true); + DrawPanel(dc, editor, "Edit Property", false); + DrawPanel(dc, tools, "Tools", false); + } +} + +BOOL CEntityDlg::OnEraseBkgnd(CDC* pDC) { + if (pDC) { + DrawModernBackground(*pDC); + } + return TRUE; +} + +void CEntityDlg::OnPaint() { + CPaintDC dc(this); + DrawModernBackground(dc); +} + +HBRUSH CEntityDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { + HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); + + if (!themeInitialized) { + return hbr; + } + + const int id = pWnd ? pWnd->GetDlgCtrlID() : 0; + + switch (nCtlColor) { + case CTLCOLOR_STATIC: + pDC->SetTextColor((id == IDC_STATIC_TITLE) ? colorText : colorTextMuted); + pDC->SetBkMode(TRANSPARENT); + return (HBRUSH)brushPanel.GetSafeHandle(); + + case CTLCOLOR_EDIT: + pDC->SetTextColor(colorText); + pDC->SetBkColor(colorEditBg); + return (HBRUSH)brushEdit.GetSafeHandle(); + + case CTLCOLOR_LISTBOX: + pDC->SetTextColor(colorText); + pDC->SetBkColor(colorEditBg); + return (HBRUSH)brushEdit.GetSafeHandle(); + + case CTLCOLOR_BTN: + pDC->SetTextColor(colorText); + pDC->SetBkColor(colorPanelAlt); + return (HBRUSH)brushPanelAlt.GetSafeHandle(); + + case CTLCOLOR_DLG: + return (HBRUSH)brushBackground.GetSafeHandle(); + } + + return hbr; +} + +// -------------------------------------------------------------------------- +// Dialog init / layout +// -------------------------------------------------------------------------- + +BOOL CEntityDlg::OnInitDialog() { + CDialog::OnInitDialog(); + + InitModernTheme(); + + listKeyVal.SetUpdateInspectors(true); + listKeyVal.SetDivider(120); + listVars.SetDivider(120); + + staticFrame.SetWindowText("0"); + + ApplyModernTheme(); + + ModifyStyleEx(0, WS_EX_CONTROLPARENT); + Invalidate(FALSE); + + return TRUE; +} + +INT_PTR CEntityDlg::OnToolHitTest(CPoint point, TOOLINFO* pTI) const { + return CDialog::OnToolHitTest(point, pTI); +} + +void CEntityDlg::OnSize(UINT nType, int cx, int cy) { + CDialog::OnSize(nType, cx, cy); + if (staticTitle.GetSafeHwnd() == NULL) { return; } - CDialog::OnSize(nType, cx, cy); - CRect rect, crect, crect2; - GetClientRect(rect); - int bh = (float)rect.Height() * (rect.Height() - 210) / rect.Height() / 2; - staticTitle.GetWindowRect(crect); - staticTitle.SetWindowPos(NULL, 4, 4, rect.Width() -8, crect.Height(), SWP_SHOWWINDOW); - int top = 4 + crect.Height() + 4; - comboClass.GetWindowRect(crect); - btnCreate.GetWindowRect(crect2); - comboClass.SetWindowPos(NULL, 4, top, rect.Width() - 12 - crect2.Width(), crect.Height(), SWP_SHOWWINDOW); - btnCreate.SetWindowPos(NULL, rect.Width() - crect2.Width() - 4, top, crect2.Width(), crect.Height(), SWP_SHOWWINDOW); - top += crect.Height() + 4; - listVars.SetWindowPos(NULL, 4, top, rect.Width() - 8, bh, SWP_SHOWWINDOW); - top += bh + 4; - listKeyVal.SetWindowPos(NULL, 4, top, rect.Width() - 8, bh, SWP_SHOWWINDOW); - top += bh + 4; - staticKey.GetWindowRect(crect); - staticKey.SetWindowPos(NULL, 4, top + 2, crect.Width(), crect.Height(), SWP_SHOWWINDOW); - int left = 4 + crect.Width() + 4; - int pad = crect.Width(); - editKey.GetWindowRect(crect); - editKey.SetWindowPos(NULL, left, top, rect.Width() - 12 - pad, crect.Height(), SWP_SHOWWINDOW); - top += crect.Height() + 4; - staticVal.GetWindowRect(crect); - staticVal.SetWindowPos(NULL, 4, top + 2, crect.Width(), crect.Height(), SWP_SHOWWINDOW); - editVal.GetWindowRect(crect); - bh = crect.Height(); - editVal.SetWindowPos(NULL, left, top, rect.Width() - 16 - bh - pad, crect.Height(), SWP_SHOWWINDOW); - btnBrowse.SetWindowPos(NULL, rect.right - 4 - bh, top, bh, bh, SWP_SHOWWINDOW); - top += crect.Height() + 8; - btnModel.GetWindowRect(crect); - btnModel.SetWindowPos(NULL, rect.right - 4 - crect.Width(), top + 8, crect.Width(), crect.Height(), SWP_SHOWWINDOW); - btnSound.SetWindowPos(NULL, rect.right - 4 - crect.Width(), top + 12 + crect.Height(), crect.Width(), crect.Height(), SWP_SHOWWINDOW); - btnGui.SetWindowPos(NULL, rect.right - 4 - crect.Width(), top + 16 + crect.Height() * 2, crect.Width(), crect.Height(), SWP_SHOWWINDOW); - btnParticle.SetWindowPos(NULL, rect.right - 8 - (crect.Width() * 2), top + 16 + crect.Height() * 2, crect.Width(), crect.Height(), SWP_SHOWWINDOW); - btnSkin.SetWindowPos( NULL, rect.right - 8 - ( crect.Width() * 2 ), top + 12 + crect.Height(), crect.Width(), crect.Height(), SWP_SHOWWINDOW ); - btnCurve.SetWindowPos( NULL, rect.right - 8 - ( crect.Width() * 2 ), top + 8, crect.Width(), crect.Height(), SWP_SHOWWINDOW ); - //************************************* - //animation controls - //************************************* - int rightAnimAreaBorder = rect.right - 75 - crect.Width (); /*models, etc button width*/ + const int pad = 8; + const int inner = 10; + const int headerH = 42; + const int classH = 52; + const int editorH = 106; + const int minToolH = 124; - btnStopAnim.GetWindowRect(crect); - btnStopAnim.SetWindowPos(NULL,rightAnimAreaBorder - crect.Width (), - top + 8 ,crect.Width(),crect.Height(),SWP_SHOWWINDOW); + CRect rect; + GetClientRect(&rect); - left = rightAnimAreaBorder - crect.Width() - 4; - btnPlayAnim.GetWindowRect(crect); - btnPlayAnim.SetWindowPos(NULL,left-crect.Width () ,top + 8 , crect.Width(),crect.Height(),SWP_SHOWWINDOW); + int w = max(1, rect.Width()); + int h = max(1, rect.Height()); - left -= crect.Width() + 4; - cbAnimations.GetWindowRect(crect); - cbAnimations.SetWindowPos(NULL,left-crect.Width (),top + 8 ,crect.Width(),crect.Height(),SWP_SHOWWINDOW); + CRect header(rect.left + pad, rect.top + pad, rect.right - pad, rect.top + pad + headerH); + MoveCtrl(staticTitle, header.left + 12, header.top + 8, header.Width() - 24, 24); - staticFrame.GetWindowRect(crect); - staticFrame.SetWindowPos(NULL,rightAnimAreaBorder - crect.Width (), - top + 34 ,crect.Width(),crect.Height(),SWP_SHOWWINDOW); + CRect classPanel(rect.left + pad, header.bottom + pad, rect.right - pad, header.bottom + pad + classH); + int classY = classPanel.top + 22; + int createW = 82; + MoveCtrl(comboClass, classPanel.left + inner, classY, classPanel.Width() - inner * 3 - createW, 22); + MoveCtrl(btnCreate, classPanel.right - inner - createW, classY, createW, 22); - left = rightAnimAreaBorder - crect.Width () - 4; + int contentTop = classPanel.bottom + pad; + int contentBottom = rect.bottom - pad; - slFrameSlider.GetWindowRect(crect); - slFrameSlider.SetWindowPos(NULL,left - crect.Width (), - top + 32 ,crect.Width(),crect.Height(),SWP_SHOWWINDOW); + if (w >= 560) { + int listH = max(120, min(260, (h - contentTop - editorH - minToolH - pad * 3))); + int leftW = (w - pad * 3) / 2; - //************************************* - //************************************* + CRect varsPanel(rect.left + pad, contentTop, rect.left + pad + leftW, contentTop + listH); + CRect keyPanel(varsPanel.right + pad, contentTop, rect.right - pad, contentTop + listH); - btn135.GetWindowRect(crect); - bh = crect.Width(); - btn135.SetWindowPos(NULL, 4, top, bh, bh, SWP_SHOWWINDOW); - btn90.SetWindowPos(NULL, 4 + 2 + bh, top, bh, bh, SWP_SHOWWINDOW); - btn45.SetWindowPos(NULL, 4 + 2 + 2 + bh * 2, top, bh, bh, SWP_SHOWWINDOW); - btnUp.SetWindowPos(NULL, 4 + 2 + 2 + 6 + bh * 3, top + bh / 2,bh,bh, SWP_SHOWWINDOW); - btnDown.SetWindowPos(NULL, 4 + 2 + 2 + 6 + bh *3, top + bh / 2 + bh + 2,bh,bh, SWP_SHOWWINDOW); - top += bh + 2; - btn180.SetWindowPos(NULL, 4, top, bh, bh, SWP_SHOWWINDOW); - btn360.SetWindowPos(NULL, 4 + 2 + 2 + bh * 2, top, bh, bh, SWP_SHOWWINDOW); - top += bh + 2; - btn225.SetWindowPos(NULL, 4, top, bh, bh, SWP_SHOWWINDOW); - btn270.SetWindowPos(NULL, 4 + 2 + bh, top, bh, bh, SWP_SHOWWINDOW); - btn315.SetWindowPos(NULL, 4 + 2 + 2 + bh * 2, top, bh, bh, SWP_SHOWWINDOW); - Invalidate(); + MoveCtrl(listVars, varsPanel.left + inner, varsPanel.top + 28, varsPanel.Width() - inner * 2, varsPanel.Height() - 38); + MoveCtrl(listKeyVal, keyPanel.left + inner, keyPanel.top + 28, keyPanel.Width() - inner * 2, keyPanel.Height() - 38); + + CRect editPanel(rect.left + pad, varsPanel.bottom + pad, rect.right - pad, varsPanel.bottom + pad + editorH); + + int labelW = 52; + int browseW = 28; + int rowH = 22; + int rowY = editPanel.top + 30; + + MoveCtrl(staticKey, editPanel.left + inner, rowY + 2, labelW, rowH); + MoveCtrl(editKey, editPanel.left + inner + labelW + 6, rowY, editPanel.Width() - inner * 2 - labelW - 6, rowH); + + rowY += rowH + 10; + + MoveCtrl(staticVal, editPanel.left + inner, rowY + 2, labelW, rowH); + MoveCtrl(editVal, editPanel.left + inner + labelW + 6, rowY, editPanel.Width() - inner * 2 - labelW - 6 - browseW - 6, rowH); + MoveCtrl(btnBrowse, editPanel.right - inner - browseW, rowY, browseW, rowH); + + CRect toolsPanel(rect.left + pad, editPanel.bottom + pad, rect.right - pad, contentBottom); + + int toolY = toolsPanel.top + 28; + int toolX = toolsPanel.left + inner; + + int b = 30; + MoveCtrl(btn135, toolX, toolY, b, b); + MoveCtrl(btn90, toolX + b + 4, toolY, b, b); + MoveCtrl(btn45, toolX + (b + 4) * 2, toolY, b, b); + + MoveCtrl(btn180, toolX, toolY + b + 4, b, b); + MoveCtrl(btn360, toolX + (b + 4) * 2, toolY + b + 4, b, b); + + MoveCtrl(btn225, toolX, toolY + (b + 4) * 2, b, b); + MoveCtrl(btn270, toolX + b + 4, toolY + (b + 4) * 2, b, b); + MoveCtrl(btn315, toolX + (b + 4) * 2, toolY + (b + 4) * 2, b, b); + + MoveCtrl(btnUp, toolX + (b + 4) * 3 + 8, toolY + 16, b + 8, b); + MoveCtrl(btnDown, toolX + (b + 4) * 3 + 8, toolY + 16 + b + 6, b + 8, b); + + int mediaX = toolX + 190; + int mediaW = 76; + int mediaH = 24; + MoveCtrl(btnModel, mediaX, toolY, mediaW, mediaH); + MoveCtrl(btnSound, mediaX, toolY + mediaH + 6, mediaW, mediaH); + MoveCtrl(btnGui, mediaX, toolY + (mediaH + 6) * 2, mediaW, mediaH); + + MoveCtrl(btnCurve, mediaX + mediaW + 8, toolY, mediaW, mediaH); + MoveCtrl(btnSkin, mediaX + mediaW + 8, toolY + mediaH + 6, mediaW, mediaH); + MoveCtrl(btnParticle, mediaX + mediaW + 8, toolY + (mediaH + 6) * 2, mediaW, mediaH); + + int animX = mediaX + (mediaW + 8) * 2 + 18; + int animW = max(120, toolsPanel.right - animX - inner); + MoveCtrl(cbAnimations, animX, toolY, animW, 24); + MoveCtrl(btnPlayAnim, animX, toolY + 32, 54, 24); + MoveCtrl(btnStopAnim, animX + 60, toolY + 32, 54, 24); + MoveCtrl(slFrameSlider, animX, toolY + 66, max(80, animW - 44), 24); + MoveCtrl(staticFrame, animX + animW - 38, toolY + 68, 36, 20); + } + else { + int available = contentBottom - contentTop; + int listH = max(82, (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); + + MoveCtrl(listVars, varsPanel.left + inner, varsPanel.top + 28, varsPanel.Width() - inner * 2, varsPanel.Height() - 38); + MoveCtrl(listKeyVal, keyPanel.left + inner, keyPanel.top + 28, keyPanel.Width() - inner * 2, keyPanel.Height() - 38); + + CRect editPanel(rect.left + pad, keyPanel.bottom + pad, rect.right - pad, keyPanel.bottom + pad + editorH); + + int labelW = 48; + int browseW = 28; + int rowH = 22; + int rowY = editPanel.top + 30; + + MoveCtrl(staticKey, editPanel.left + inner, rowY + 2, labelW, rowH); + MoveCtrl(editKey, editPanel.left + inner + labelW + 6, rowY, editPanel.Width() - inner * 2 - labelW - 6, rowH); + + rowY += rowH + 10; + + MoveCtrl(staticVal, editPanel.left + inner, rowY + 2, labelW, rowH); + MoveCtrl(editVal, editPanel.left + inner + labelW + 6, rowY, editPanel.Width() - inner * 2 - labelW - 6 - browseW - 6, rowH); + MoveCtrl(btnBrowse, editPanel.right - inner - browseW, rowY, browseW, rowH); + + CRect toolsPanel(rect.left + pad, editPanel.bottom + pad, rect.right - pad, contentBottom); + + int toolY = toolsPanel.top + 28; + int toolX = toolsPanel.left + inner; + int b = 26; + + MoveCtrl(btn135, toolX, toolY, b, b); + MoveCtrl(btn90, toolX + b + 4, toolY, b, b); + MoveCtrl(btn45, toolX + (b + 4) * 2, toolY, b, b); + + MoveCtrl(btn180, toolX, toolY + b + 4, b, b); + MoveCtrl(btn360, toolX + (b + 4) * 2, toolY + b + 4, b, b); + + MoveCtrl(btn225, toolX, toolY + (b + 4) * 2, b, b); + MoveCtrl(btn270, toolX + b + 4, toolY + (b + 4) * 2, b, b); + MoveCtrl(btn315, toolX + (b + 4) * 2, toolY + (b + 4) * 2, b, b); + + MoveCtrl(btnUp, toolX + (b + 4) * 3 + 6, toolY + 12, b + 8, b); + MoveCtrl(btnDown, toolX + (b + 4) * 3 + 6, toolY + 12 + b + 6, b + 8, b); + + int mediaX = toolX + 152; + int mediaW = max(58, (toolsPanel.right - mediaX - inner - 8) / 2); + int mediaH = 22; + + MoveCtrl(btnModel, mediaX, toolY, mediaW, mediaH); + MoveCtrl(btnSound, mediaX, toolY + mediaH + 5, mediaW, mediaH); + MoveCtrl(btnGui, mediaX, toolY + (mediaH + 5) * 2, mediaW, mediaH); + + MoveCtrl(btnCurve, mediaX + mediaW + 8, toolY, mediaW, mediaH); + MoveCtrl(btnSkin, mediaX + mediaW + 8, toolY + mediaH + 5, mediaW, mediaH); + MoveCtrl(btnParticle, mediaX + mediaW + 8, toolY + (mediaH + 5) * 2, mediaW, mediaH); + + int animY = toolY + 88; + MoveCtrl(cbAnimations, toolX, animY, toolsPanel.Width() - inner * 2, 22); + MoveCtrl(btnPlayAnim, toolX, animY + 28, 54, 22); + MoveCtrl(btnStopAnim, toolX + 60, animY + 28, 54, 22); + MoveCtrl(slFrameSlider, toolX + 120, animY + 28, toolsPanel.Width() - inner * 2 - 162, 22); + MoveCtrl(staticFrame, toolsPanel.right - inner - 36, animY + 30, 36, 18); + } + + Invalidate(FALSE); } -void CEntityDlg::OnCbnSelchangeComboClass() -{ +// -------------------------------------------------------------------------- +// Entity/class/keyval behavior +// -------------------------------------------------------------------------- + +void CEntityDlg::AddClassNames() { + comboClass.ResetContent(); + + for (eclass_t* pec = eclass; pec; pec = pec->next) { + comboClass.AddString(pec->name); + } +} + +void CEntityDlg::OnCbnSelchangeComboClass() { int index = comboClass.GetCurSel(); + if (index != LB_ERR) { CString str; comboClass.GetLBText(index, str); - eclass_t *ent = Eclass_ForName (str, false); + + eclass_t* ent = Eclass_ForName(str, false); if (ent) { if (selected_brushes.next == &selected_brushes) { editEntity = world_entity; multipleEntities = false; - } else { + } + else { editEntity = selected_brushes.next->owner; - for (brush_t *b = selected_brushes.next->next; b != &selected_brushes; b = b->next) { + multipleEntities = false; + + for (brush_t* b = selected_brushes.next->next; b != &selected_brushes; b = b->next) { if (b->owner != editEntity) { multipleEntities = true; break; } } } + listVars.ResetContent(); - CPropertyItem *pi = new CPropertyItem("Usage:", ent->desc.c_str(), PIT_VAR, ""); + + CPropertyItem* pi = new CPropertyItem("Usage:", ent->desc.c_str(), PIT_VAR, ""); listVars.AddPropItem(pi); int c = ent->vars.Num(); @@ -276,20 +650,20 @@ void CEntityDlg::OnCbnSelchangeComboClass() pi->SetData(ent->vars[i].type); listVars.AddPropItem(pi); } + listVars.Invalidate(); SetKeyValPairs(); } } } -const char *CEntityDlg::TranslateString(const char *buf) { +const char* CEntityDlg::TranslateString(const char* buf) { static char buf2[32768]; - int i, l; - char *out; - l = strlen(buf); - out = buf2; - for (i = 0; i < l; i++) { + int l = strlen(buf); + char* out = buf2; + + for (int i = 0; i < l; i++) { if (buf[i] == '\n') { *out++ = '\r'; *out++ = '\n'; @@ -300,66 +674,76 @@ const char *CEntityDlg::TranslateString(const char *buf) { } *out++ = 0; - return buf2; - } void CEntityDlg::UpdateFromListBox() { if (editEntity == NULL) { return; } + int c = listKeyVal.GetCount(); - for (int i = 0 ; i < c; i++) { + for (int i = 0; i < c; i++) { CPropertyItem* pItem = (CPropertyItem*)listKeyVal.GetItemDataPtr(i); if (pItem) { editEntity->epairs.Set(pItem->m_propName, pItem->m_curValue); } } + SetKeyValPairs(); } -void CEntityDlg::SetKeyValPairs( bool updateAnims ) { +void CEntityDlg::SetKeyValPairs(bool updateAnims) { if (editEntity) { listKeyVal.ResetContent(); + int c = editEntity->epairs.GetNumKeyVals(); for (int i = 0; i < c; i++) { - const idKeyValue *kv = editEntity->epairs.GetKeyVal(i); - CPropertyItem *pi = new CPropertyItem(kv->GetKey().c_str(), kv->GetValue().c_str(), PIT_EDIT, ""); + const idKeyValue* kv = editEntity->epairs.GetKeyVal(i); + CPropertyItem* pi = new CPropertyItem(kv->GetKey().c_str(), kv->GetValue().c_str(), PIT_EDIT, ""); + bool found = false; int vc = editEntity->eclass->vars.Num(); + for (int j = 0; j < vc; j++) { if (editEntity->eclass->vars[j].name.Icmp(kv->GetKey()) == 0) { switch (editEntity->eclass->vars[j].type) { - case EVAR_STRING : - case EVAR_INT : - case EVAR_FLOAT : - pi->m_nItemType = PIT_EDIT; - break; - case EVAR_BOOL : - pi->m_nItemType = PIT_EDIT; - //pi->m_cmbItems = "0|1"; - break; - case EVAR_COLOR : - pi->m_nItemType = PIT_COLOR; - break; - case EVAR_MATERIAL : - pi->m_nItemType = PIT_MATERIAL; - break; - case EVAR_MODEL : - pi->m_nItemType = PIT_MODEL; - break; - case EVAR_GUI : - pi->m_nItemType = PIT_GUI; - break; - case EVAR_SOUND : - pi->m_nItemType = PIT_SOUND; - break; + case EVAR_STRING: + case EVAR_INT: + case EVAR_FLOAT: + pi->m_nItemType = PIT_EDIT; + break; + + case EVAR_BOOL: + pi->m_nItemType = PIT_EDIT; + break; + + case EVAR_COLOR: + pi->m_nItemType = PIT_COLOR; + break; + + case EVAR_MATERIAL: + pi->m_nItemType = PIT_MATERIAL; + break; + + case EVAR_MODEL: + pi->m_nItemType = PIT_MODEL; + break; + + case EVAR_GUI: + pi->m_nItemType = PIT_GUI; + break; + + case EVAR_SOUND: + pi->m_nItemType = PIT_SOUND; + break; } + found = true; break; } } + if (!found) { if (kv->GetKey().Icmp("model") == 0) { pi->m_nItemType = PIT_MODEL; @@ -380,33 +764,36 @@ void CEntityDlg::SetKeyValPairs( bool updateAnims ) { pi->m_nItemType = PIT_SOUND; } } + listKeyVal.AddPropItem(pi); } - if ( updateAnims ) { + if (updateAnims) { int i, num; cbAnimations.ResetContent(); - num = gameEdit->ANIM_GetNumAnimsFromEntityDef( &editEntity->eclass->defArgs ); - for( i = 0; i < num; i++ ) { - cbAnimations.AddString( gameEdit->ANIM_GetAnimNameFromEntityDef( &editEntity->eclass->defArgs, i ) ); + + num = gameEdit->ANIM_GetNumAnimsFromEntityDef(&editEntity->eclass->defArgs); + for (i = 0; i < num; i++) { + cbAnimations.AddString(gameEdit->ANIM_GetAnimNameFromEntityDef(&editEntity->eclass->defArgs, i)); } - const idKeyValue* kv = editEntity->epairs.FindKey ( "anim" ); - if ( kv ) { - int selIndex = cbAnimations.FindStringExact( 0 , kv->GetValue().c_str() ); - if ( selIndex != -1 ) { - cbAnimations.SetCurSel( selIndex ); - OnCbnAnimationChange (); + const idKeyValue* kv = editEntity->epairs.FindKey("anim"); + if (kv) { + int selIndex = cbAnimations.FindStringExact(0, kv->GetValue().c_str()); + if (selIndex != -1) { + cbAnimations.SetCurSel(selIndex); + OnCbnAnimationChange(); } } } } } -void CEntityDlg::UpdateEntitySel(eclass_t *ent) { - assert ( ent ); - assert ( ent->name ); +void CEntityDlg::UpdateEntitySel(eclass_t* ent) { + assert(ent); + assert(ent->name); + int index = comboClass.FindString(-1, ent->name); if (index != LB_ERR) { comboClass.SetCurSel(index); @@ -414,17 +801,19 @@ void CEntityDlg::UpdateEntitySel(eclass_t *ent) { } } -void CEntityDlg::OnLbnSelchangeListkeyval() -{ +void CEntityDlg::OnLbnSelchangeListkeyval() { int index = listKeyVal.GetCurSel(); + if (index != LB_ERR) { CString str; listKeyVal.GetText(index, str); + int i; for (i = 0; str[i] != '\t' && str[i] != '\0'; i++) { } idStr key = str.Left(i); + while (str[i] == '\t' && str[i] != '\0') { i++; } @@ -439,7 +828,6 @@ void CEntityDlg::OnLbnSelchangeListkeyval() static int TabOrder[] = { IDC_COMBO_CLASS, IDC_BUTTON_CREATE, - //IDC_EDIT_INFO, IDC_LIST_KEYVAL, IDC_EDIT_KEY, IDC_EDIT_VAL, @@ -470,25 +858,23 @@ void CEntityDlg::DelProp() { } editKey.GetWindowText(key); + if (multipleEntities) { - for (brush_t *b = selected_brushes.next; b != &selected_brushes; b = b->next) { + for (brush_t* b = selected_brushes.next; b != &selected_brushes; b = b->next) { DeleteKey(b->owner, key); - Entity_UpdateCurveData( b->owner ); + Entity_UpdateCurveData(b->owner); } - } else { + } + else { DeleteKey(editEntity, key); - Entity_UpdateCurveData( editEntity ); + Entity_UpdateCurveData(editEntity); } - // refresh the prop listbox SetKeyValPairs(); - Sys_UpdateWindows( W_ENTITY | W_XY | W_CAMERA ); + Sys_UpdateWindows(W_ENTITY | W_XY | W_CAMERA); } - -BOOL CEntityDlg::PreTranslateMessage(MSG* pMsg) -{ - +BOOL CEntityDlg::PreTranslateMessage(MSG* pMsg) { if (pMsg->hwnd == editVal.GetSafeHwnd()) { if (pMsg->message == WM_LBUTTONDOWN) { editVal.SetFocus(); @@ -504,15 +890,14 @@ BOOL CEntityDlg::PreTranslateMessage(MSG* pMsg) } if (GetFocus() == &editVal || GetFocus() == &editKey) { - if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN ) { - AddProp(); - return TRUE; + if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN) { + AddProp(); + return TRUE; } - } if (GetFocus() == listKeyVal.GetEditBox()) { - if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN ) { + if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN) { listKeyVal.OnChangeEditBox(); listKeyVal.OnSelchange(); listKeyVal.OnKillfocusEditBox(); @@ -526,75 +911,79 @@ BOOL CEntityDlg::PreTranslateMessage(MSG* pMsg) if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_DELETE && editEntity) { DelProp(); return TRUE; - } + } } if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE) { - if (pMsg->wParam == VK_ESCAPE) { - g_pParentWnd->GetCamera()->SetFocus(); - Select_Deselect(); - } + g_pParentWnd->GetCamera()->SetFocus(); + Select_Deselect(); return TRUE; } - if ( pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN ) { - // keeps ENTER from closing the dialog + if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN) { return TRUE; } if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_TAB) { if (GetFocus()) { int id = GetFocus()->GetDlgCtrlID(); + for (int i = 0; i < TabCount; i++) { if (TabOrder[i] == id) { i++; if (i >= TabCount) { i = 0; } - CWnd *next = GetDlgItem(TabOrder[i]); + + CWnd* next = GetDlgItem(TabOrder[i]); if (next) { next->SetFocus(); + if (TabOrder[i] == IDC_EDIT_VAL) { editVal.SetSel(0, -1); } + return TRUE; } } } } } - + if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RIGHT && pMsg->hwnd == slFrameSlider.GetSafeHwnd()) { + int maxRange = slFrameSlider.GetRangeMax(); + if (maxRange <= 0) { + return TRUE; + } + int pos = slFrameSlider.GetPos() + 1; - pos = (pos % slFrameSlider.GetRangeMax()); - slFrameSlider.SetPos ( pos ); - UpdateFromAnimationFrame (); + pos = (pos % maxRange); + slFrameSlider.SetPos(pos); + UpdateFromAnimationFrame(); return TRUE; } if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_LEFT && pMsg->hwnd == slFrameSlider.GetSafeHwnd()) { - int pos = slFrameSlider.GetPos() - 1; - - if ( pos < 1 ) { - pos = slFrameSlider.GetRangeMax(); + int maxRange = slFrameSlider.GetRangeMax(); + if (maxRange <= 0) { + return TRUE; } - slFrameSlider.SetPos ( pos ); - UpdateFromAnimationFrame (); + int pos = slFrameSlider.GetPos() - 1; + + if (pos < 1) { + pos = maxRange; + } + + slFrameSlider.SetPos(pos); + UpdateFromAnimationFrame(); return TRUE; } return CDialog::PreTranslateMessage(pMsg); } - -/* - ======================================================================================================================= - AddProp - ======================================================================================================================= - */ void CEntityDlg::AddProp() { - if (editEntity == NULL) { return; } @@ -605,15 +994,15 @@ void CEntityDlg::AddProp() { bool isName = (stricmp(Key, "name") == 0); bool isModel = static_cast((stricmp(Key, "model") == 0 && Value.GetLength() > 0)); - bool isOrigin = ( idStr::Icmp( Key, "origin" ) == 0 ); + bool isOrigin = (idStr::Icmp(Key, "origin") == 0); if (multipleEntities) { - brush_t *b; - for (b = selected_brushes.next; b != &selected_brushes; b = b->next) { + for (brush_t* b = selected_brushes.next; b != &selected_brushes; b = b->next) { if (isName) { Entity_SetName(b->owner, Value); - } else { - if ( ! ( ( isModel || isOrigin ) && ( b->owner->eclass->nShowFlags & ECLASS_WORLDSPAWN ) ) ) { + } + else { + if (!((isModel || isOrigin) && (b->owner->eclass->nShowFlags & ECLASS_WORLDSPAWN))) { SetKeyValue(b->owner, Key, Value); } } @@ -622,44 +1011,47 @@ void CEntityDlg::AddProp() { else { if (isName) { Entity_SetName(editEntity, Value); - } else { - if ( ! ( ( isModel || isOrigin ) && ( editEntity->eclass->nShowFlags & ECLASS_WORLDSPAWN ) ) ) { + } + else { + if (!((isModel || isOrigin) && (editEntity->eclass->nShowFlags & ECLASS_WORLDSPAWN))) { SetKeyValue(editEntity, Key, Value); } } - if ( isModel && !( editEntity->eclass->nShowFlags & ECLASS_WORLDSPAWN ) ) { - idBounds bo; - idVec3 mins, maxs; + if (isModel && !(editEntity->eclass->nShowFlags & ECLASS_WORLDSPAWN)) { + idBounds bo; + idVec3 mins, maxs; - selected_brushes.next->modelHandle = renderModelManager->FindModel( Value ); - if ( dynamic_cast( selected_brushes.next->modelHandle ) || dynamic_cast( selected_brushes.next->modelHandle ) ) { + selected_brushes.next->modelHandle = renderModelManager->FindModel(Value); + + if (dynamic_cast(selected_brushes.next->modelHandle) || + dynamic_cast(selected_brushes.next->modelHandle)) { bo.Zero(); - bo.ExpandSelf( 12.0f ); - } else { - bo = selected_brushes.next->modelHandle->Bounds( NULL ); + bo.ExpandSelf(12.0f); + } + else { + bo = selected_brushes.next->modelHandle->Bounds(NULL); } VectorCopy(bo[0], mins); VectorCopy(bo[1], maxs); VectorAdd(mins, editEntity->origin, mins); VectorAdd(maxs, editEntity->origin, maxs); + Brush_RebuildBrush(selected_brushes.next, mins, maxs, false); - Brush_Build ( selected_brushes.next , false, false , false, true ); + Brush_Build(selected_brushes.next, false, false, false, true); } } - // refresh the prop listbox SetKeyValPairs(); Sys_UpdateWindows(W_ALL); - } -const char *CEntityDlg::AngleKey() { +const char* CEntityDlg::AngleKey() { if (editEntity == NULL) { return ""; } - + if (editEntity->eclass->nShowFlags & ECLASS_MOVER) { return "movedir"; } @@ -667,197 +1059,225 @@ const char *CEntityDlg::AngleKey() { return "angle"; } - -void CEntityDlg::OnBnClickedE135() -{ +void CEntityDlg::OnBnClickedE135() { if (editEntity == NULL) { return; } + editKey.SetWindowText(AngleKey()); editVal.SetWindowText("135"); AddProp(); } -void CEntityDlg::OnBnClickedE90() -{ +void CEntityDlg::OnBnClickedE90() { if (editEntity == NULL) { return; } + editKey.SetWindowText(AngleKey()); editVal.SetWindowText("90"); AddProp(); } -void CEntityDlg::OnBnClickedE45() -{ +void CEntityDlg::OnBnClickedE45() { if (editEntity == NULL) { return; } + editKey.SetWindowText(AngleKey()); editVal.SetWindowText("45"); AddProp(); } -void CEntityDlg::OnBnClickedE180() -{ +void CEntityDlg::OnBnClickedE180() { if (editEntity == NULL) { return; } + editKey.SetWindowText(AngleKey()); editVal.SetWindowText("180"); AddProp(); } -void CEntityDlg::OnBnClickedE0() -{ +void CEntityDlg::OnBnClickedE0() { if (editEntity == NULL) { return; } + editKey.SetWindowText(AngleKey()); editVal.SetWindowText("0"); AddProp(); } -void CEntityDlg::OnBnClickedE225() -{ +void CEntityDlg::OnBnClickedE225() { if (editEntity == NULL) { return; } + editKey.SetWindowText(AngleKey()); editVal.SetWindowText("225"); AddProp(); } -void CEntityDlg::OnBnClickedE270() -{ +void CEntityDlg::OnBnClickedE270() { if (editEntity == NULL) { return; } + editKey.SetWindowText(AngleKey()); editVal.SetWindowText("270"); AddProp(); } -void CEntityDlg::OnBnClickedE315() -{ +void CEntityDlg::OnBnClickedE315() { if (editEntity == NULL) { return; } + editKey.SetWindowText(AngleKey()); editVal.SetWindowText("315"); AddProp(); } -void CEntityDlg::OnBnClickedEUp() -{ +void CEntityDlg::OnBnClickedEUp() { if (editEntity == NULL) { return; } + editKey.SetWindowText(AngleKey()); editVal.SetWindowText("-1"); AddProp(); } -void CEntityDlg::OnBnClickedEDown() -{ +void CEntityDlg::OnBnClickedEDown() { if (editEntity == NULL) { return; } + editKey.SetWindowText(AngleKey()); editVal.SetWindowText("-2"); AddProp(); } -CPreviewDlg *CEntityDlg::ShowModelChooser() { +// -------------------------------------------------------------------------- +// Choosers +// -------------------------------------------------------------------------- + +CPreviewDlg* CEntityDlg::ShowModelChooser() { static CPreviewDlg modelDlg; modelDlg.SetMode(CPreviewDlg::MODELS); modelDlg.SetModal(); + if (modelDlg.GetSafeHwnd() == NULL) { modelDlg.Create(MAKEINTRESOURCE(IDD_DIALOG_PREVIEW)); } - modelDlg.ShowWindow( SW_SHOW ); + + modelDlg.ShowWindow(SW_SHOW); modelDlg.BringWindowToTop(); + while (modelDlg.Waiting()) { } + return &modelDlg; } -CPreviewDlg *CEntityDlg::ShowParticleChooser() { +CPreviewDlg* CEntityDlg::ShowParticleChooser() { static CPreviewDlg modelDlg; modelDlg.SetMode(CPreviewDlg::PARTICLES); modelDlg.SetModal(); + if (modelDlg.GetSafeHwnd() == NULL) { modelDlg.Create(MAKEINTRESOURCE(IDD_DIALOG_PREVIEW)); } + modelDlg.ShowWindow(SW_SHOW); modelDlg.BringWindowToTop(); + while (modelDlg.Waiting()) { } + return &modelDlg; } -CPreviewDlg *CEntityDlg::ShowSkinChooser(entity_t *ent) { +CPreviewDlg* CEntityDlg::ShowSkinChooser(entity_t* ent) { static CPreviewDlg modelDlg; modelDlg.SetMode(CPreviewDlg::SKINS); modelDlg.SetModal(); + if (modelDlg.GetSafeHwnd() == NULL) { modelDlg.Create(MAKEINTRESOURCE(IDD_DIALOG_PREVIEW)); } - modelDlg.RebuildTree( ( ent ) ? ent->epairs.GetString( "model" ) : "" ); + + modelDlg.RebuildTree((ent) ? ent->epairs.GetString("model") : ""); modelDlg.ShowWindow(SW_SHOW); modelDlg.BringWindowToTop(); + while (modelDlg.Waiting()) { } + return &modelDlg; } -CPreviewDlg *CEntityDlg::ShowGuiChooser() { +CPreviewDlg* CEntityDlg::ShowGuiChooser() { static CPreviewDlg guiDlg; guiDlg.SetMode(CPreviewDlg::GUIS); guiDlg.SetModal(); + if (guiDlg.GetSafeHwnd() == NULL) { guiDlg.Create(MAKEINTRESOURCE(IDD_DIALOG_PREVIEW)); } + guiDlg.ShowWindow(SW_SHOW); guiDlg.BringWindowToTop(); + while (guiDlg.Waiting()) { } + return &guiDlg; } -CPreviewDlg *CEntityDlg::ShowSoundChooser() { +CPreviewDlg* CEntityDlg::ShowSoundChooser() { static CPreviewDlg soundDlg; soundDlg.SetMode(CPreviewDlg::SOUNDS); soundDlg.SetModal(); + if (soundDlg.GetSafeHwnd() == NULL) { soundDlg.Create(MAKEINTRESOURCE(IDD_DIALOG_PREVIEW)); } + soundDlg.ShowWindow(SW_SHOW); + while (soundDlg.Waiting()) { } + return &soundDlg; } -CPreviewDlg *CEntityDlg::ShowMaterialChooser() { +CPreviewDlg* CEntityDlg::ShowMaterialChooser() { static CPreviewDlg matDlg; matDlg.SetMode(CPreviewDlg::MATERIALS); matDlg.SetModal(); + if (matDlg.GetSafeHwnd() == NULL) { matDlg.Create(MAKEINTRESOURCE(IDD_DIALOG_PREVIEW)); } + matDlg.ShowWindow(SW_SHOW); matDlg.BringWindowToTop(); + while (matDlg.Waiting()) { } + return &matDlg; } -void CEntityDlg::AssignModel () -{ +void CEntityDlg::AssignModel() { OnBnClickedButtonModel(); } + void CEntityDlg::OnBnClickedButtonModel() { - CPreviewDlg *dlg = ShowModelChooser(); + CPreviewDlg* dlg = ShowModelChooser(); + if (dlg->returnCode == IDOK) { editKey.SetWindowText("model"); editVal.SetWindowText(dlg->mediaName); @@ -866,7 +1286,8 @@ void CEntityDlg::OnBnClickedButtonModel() { } void CEntityDlg::OnBnClickedButtonSound() { - CPreviewDlg *dlg = ShowSoundChooser(); + CPreviewDlg* dlg = ShowSoundChooser(); + if (dlg->returnCode == IDOK) { editKey.SetWindowText("s_shader"); editVal.SetWindowText(dlg->mediaName); @@ -875,7 +1296,8 @@ void CEntityDlg::OnBnClickedButtonSound() { } void CEntityDlg::OnBnClickedButtonGui() { - CPreviewDlg *dlg = ShowGuiChooser(); + CPreviewDlg* dlg = ShowGuiChooser(); + if (dlg->returnCode == IDOK) { editKey.SetWindowText("gui"); editVal.SetWindowText(dlg->mediaName); @@ -884,7 +1306,8 @@ void CEntityDlg::OnBnClickedButtonGui() { } void CEntityDlg::OnBnClickedButtonParticle() { - CPreviewDlg *dlg = ShowParticleChooser(); + CPreviewDlg* dlg = ShowParticleChooser(); + if (dlg->returnCode == IDOK) { editKey.SetWindowText("model"); editVal.SetWindowText(dlg->mediaName); @@ -893,34 +1316,40 @@ void CEntityDlg::OnBnClickedButtonParticle() { } void CEntityDlg::OnBnClickedButtonSkin() { - CPreviewDlg *dlg = ShowSkinChooser( editEntity ); + CPreviewDlg* dlg = ShowSkinChooser(editEntity); + if (dlg->returnCode == IDOK) { editKey.SetWindowText("skin"); editVal.SetWindowText(dlg->mediaName); AddProp(); } - } void CEntityDlg::OnBnClickedButtonCurve() { CCurveDlg dlg; - if ( dlg.DoModal() == IDOK ) { - if ( editEntity ) { + + if (dlg.DoModal() == IDOK) { + if (editEntity) { idStr str = "curve_" + dlg.strCurveType; - editKey.SetWindowText( str ); + editKey.SetWindowText(str); + idVec3 org = editEntity->origin; str = "3 ( "; str += org.ToString(); + org.x += 64; str += " "; str += org.ToString(); + org.y += 64; str += " "; str += org.ToString(); + str += " )"; - editVal.SetWindowText( str ); + + editVal.SetWindowText(str); AddProp(); - Entity_SetCurveData( editEntity ); + Entity_SetCurveData(editEntity); } } } @@ -929,29 +1358,24 @@ void CEntityDlg::OnBnClickedButtonBrowse() { DelProp(); } -void CEntityDlg::OnCbnDblclkComboClass() -{ - // TODO: Add your control notification handler code here +void CEntityDlg::OnCbnDblclkComboClass() { } -// -// ======================================================================================================================= -// CreateEntity Creates a new entity based on the currently selected brush and entity type. -// ======================================================================================================================= -// -void CEntityDlg::CreateEntity() { - entity_t *petNew; - bool forceFixed = false; +// -------------------------------------------------------------------------- +// Entity creation +// -------------------------------------------------------------------------- - // check to make sure we have a brush - CXYWnd *pWnd = g_pParentWnd->ActiveXY(); +void CEntityDlg::CreateEntity() { + entity_t* petNew; + bool forceFixed = false; + + CXYWnd* pWnd = g_pParentWnd->ActiveXY(); if (pWnd) { - CRect rctZ; + CRect rctZ; pWnd->GetClientRect(rctZ); - brush_t *pBrush; if (selected_brushes.next == &selected_brushes) { - pBrush = CreateEntityBrush(g_nSmartX, rctZ.Height() - 1 - g_nSmartY, pWnd); + CreateEntityBrush(g_nSmartX, rctZ.Height() - 1 - g_nSmartY, pWnd); forceFixed = true; } } @@ -967,7 +1391,7 @@ void CEntityDlg::CreateEntity() { MessageBox("You must have a selected class to create an entity", "info", 0); return; } - + CString str; comboClass.GetLBText(index, str); @@ -976,29 +1400,35 @@ void CEntityDlg::CreateEntity() { return; } - eclass_t *pecNew = Eclass_ForName (str, false); + eclass_t* pecNew = Eclass_ForName(str, false); - // create it if ((GetAsyncKeyState(VK_CONTROL) & 0x8000)) { - // MAJOR hack for xian -extern void Brush_CopyList(brush_t *pFrom, brush_t *pTo); + extern void Brush_CopyList(brush_t * pFrom, brush_t * pTo); + brush_t temp_brushes; temp_brushes.next = &temp_brushes; + Brush_CopyList(&selected_brushes, &temp_brushes); Select_Deselect(); - brush_t *pBrush = temp_brushes.next; + + brush_t* pBrush = temp_brushes.next; while (pBrush != NULL && pBrush != &temp_brushes) { - brush_t *pNext = pBrush->next; + brush_t* pNext = pBrush->next; + Brush_RemoveFromList(pBrush); Brush_AddToList(pBrush, &selected_brushes); + pBrush = pNext; + petNew = Entity_Create(pecNew, forceFixed); Select_Deselect(); } - } else if ((GetAsyncKeyState(VK_SHIFT) & 0x8000)) { + } + else if ((GetAsyncKeyState(VK_SHIFT) & 0x8000)) { Select_Ungroup(); petNew = Entity_Create(pecNew, forceFixed); - } else { + } + else { petNew = Entity_Create(pecNew, forceFixed); } @@ -1020,39 +1450,45 @@ extern void Brush_CopyList(brush_t *pFrom, brush_t *pTo); Sys_UpdateWindows(W_ALL); } -void CEntityDlg::OnBnClickedButtonCreate() -{ +void CEntityDlg::OnBnClickedButtonCreate() { CreateEntity(); } -void CEntityDlg::OnLbnDblclkListkeyval() -{ +void CEntityDlg::OnLbnDblclkListkeyval() { CString Key, Value; idStr work; - editKey.GetWindowText( Key ); - editVal.GetWindowText( Value ); - if ( stricmp( Key, "script" ) == 0 ) { + + editKey.GetWindowText(Key); + editVal.GetWindowText(Value); + + if (stricmp(Key, "script") == 0) { Key = Value; Value = "script/" + Key; - if ( fileSystem->ReadFile( Value, NULL, NULL ) == -1) { - sprintf( work, "// Script for %s\n// \n\nvoid main() {\n\n}\n\n", currentmap ); - fileSystem->WriteFile( Value, work.c_str(), work.Length(), "fs_devpath" ); + + if (fileSystem->ReadFile(Value, NULL, NULL) == -1) { + sprintf(work, "// Script for %s\n// \n\nvoid main() {\n\n}\n\n", currentmap); + fileSystem->WriteFile(Value, work.c_str(), work.Length(), "fs_devpath"); } - work = fileSystem->RelativePathToOSPath( Value ); - WinExec( va( "notepad.exe %s", work.c_str() ), SW_SHOW ); + + work = fileSystem->RelativePathToOSPath(Value); + WinExec(va("notepad.exe %s", work.c_str()), SW_SHOW); } } void CEntityDlg::OnLbnSelchangeListVars() { - } void CEntityDlg::OnLbnDblclkListVars() { if (editEntity == NULL) { return; } + int sel = listVars.GetCurSel(); - CPropertyItem *pi = (CPropertyItem*)listVars.GetItemDataPtr(sel); + if (sel == LB_ERR) { + return; + } + + CPropertyItem* pi = (CPropertyItem*)listVars.GetItemDataPtr(sel); if (pi) { if (editEntity->epairs.FindKey(pi->m_propName) == NULL) { editKey.SetWindowText(pi->m_propName); @@ -1062,71 +1498,75 @@ void CEntityDlg::OnLbnDblclkListVars() { } } - -void CEntityDlg::UpdateKeyVal(const char *key, const char *val) { +void CEntityDlg::UpdateKeyVal(const char* key, const char* val) { if (editEntity) { editEntity->epairs.Set(key, val); SetKeyValPairs(); + g_pParentWnd->GetCamera()->BuildEntityRenderState(editEntity, true); Entity_UpdateSoundEmitter(editEntity); } } +// -------------------------------------------------------------------------- +// Animation +// -------------------------------------------------------------------------- -void CEntityDlg::OnNMReleasedcaptureSlider1(NMHDR *pNMHDR, LRESULT *pResult) -{ - if ( !editEntity ) - { +void CEntityDlg::OnNMReleasedcaptureSlider1(NMHDR* pNMHDR, LRESULT* pResult) { + if (!editEntity) { return; } - - UpdateFromAnimationFrame (); + + UpdateFromAnimationFrame(); *pResult = 0; } -void CEntityDlg::UpdateFromAnimationFrame ( bool updateKeyValueDisplay ) -{ - int frame = slFrameSlider.GetPos (); - editEntity->epairs.SetInt( "frame" , frame ); - SetDlgItemText ( IDC_ENTITY_CURRENT_ANIM , va ( "%i" , frame)); - if ( updateKeyValueDisplay ) { +void CEntityDlg::UpdateFromAnimationFrame(bool updateKeyValueDisplay) { + if (!editEntity) { + return; + } + + int frame = slFrameSlider.GetPos(); + + editEntity->epairs.SetInt("frame", frame); + SetDlgItemText(IDC_ENTITY_CURRENT_ANIM, va("%i", frame)); + + if (updateKeyValueDisplay) { SetKeyValPairs(); } - g_pParentWnd->GetCamera ()->BuildEntityRenderState (editEntity , true ); - Sys_UpdateWindows ( W_ALL ); - + g_pParentWnd->GetCamera()->BuildEntityRenderState(editEntity, true); + Sys_UpdateWindows(W_ALL); } -void CEntityDlg::OnCbnAnimationChange () -{ - if ( !editEntity ) - { +void CEntityDlg::OnCbnAnimationChange() { + if (!editEntity) { return; } int sel = cbAnimations.GetCurSel(); CString animName; + currentAnimation = NULL; + int currFrame = 0; - if ( sel != -1 ) { - cbAnimations.GetLBText( sel , animName ); - if ( animName.GetLength() > 0 ) { - //preserve the existing frame number - currFrame = editEntity->epairs.GetInt ( "frame" , "1" ); + if (sel != -1) { + cbAnimations.GetLBText(sel, animName); - editEntity->epairs.Set("anim" , animName.GetBuffer(0)); - SetKeyValPairs(false/*don't update anims combo box :)*/ ); - - //update the slider - currentAnimation = gameEdit->ANIM_GetAnimFromEntityDef(editEntity->eclass->name , animName.GetBuffer(0)); + if (animName.GetLength() > 0) { + currFrame = editEntity->epairs.GetInt("frame", "1"); + + editEntity->epairs.Set("anim", animName.GetBuffer(0)); + SetKeyValPairs(false); + + currentAnimation = gameEdit->ANIM_GetAnimFromEntityDef(editEntity->eclass->name, animName.GetBuffer(0)); currentAnimationFrame = 0; - if ( currentAnimation ) { - slFrameSlider.SetRange( 1 , gameEdit->ANIM_GetNumFrames( currentAnimation ), TRUE ); - slFrameSlider.SetPos( currFrame ); + if (currentAnimation) { + slFrameSlider.SetRange(1, gameEdit->ANIM_GetNumFrames(currentAnimation), TRUE); + slFrameSlider.SetPos(currFrame); currentAnimationFrame = currFrame; } @@ -1135,77 +1575,89 @@ void CEntityDlg::OnCbnAnimationChange () } } -void CEntityDlg::OnBnClickedStartAnimation() -{ +void CEntityDlg::OnBnClickedStartAnimation() { if (!editEntity) { return; } - SetTimer ( 0 , 1000/24 , NULL ); + + SetTimer(0, 1000 / 24, NULL); } -void CEntityDlg::OnBnClickedStopAnimation() -{ - KillTimer ( 0 ); +void CEntityDlg::OnBnClickedStopAnimation() { + KillTimer(0); } -void CEntityDlg::OnTimer(UINT_PTR nIDEvent) -{ - if ( !editEntity ) { - OnBnClickedStopAnimation (); +void CEntityDlg::OnTimer(UINT_PTR nIDEvent) { + if (!editEntity) { + OnBnClickedStopAnimation(); return; } - - if ( currentAnimation ) { - currentAnimationFrame = ( (currentAnimationFrame++) % gameEdit->ANIM_GetNumFrames( currentAnimation ) ); - editEntity->epairs.SetInt ( "frame" , currentAnimationFrame ); - slFrameSlider.SetPos ( currentAnimationFrame ); - UpdateFromAnimationFrame (false/*don't update key/value display*/); - Sys_UpdateWindows ( W_CAMERA | W_XY ); + if (currentAnimation) { + int numFrames = gameEdit->ANIM_GetNumFrames(currentAnimation); + if (numFrames <= 0) { + return; + } + + currentAnimationFrame = ((currentAnimationFrame++) % numFrames); + + editEntity->epairs.SetInt("frame", currentAnimationFrame); + slFrameSlider.SetPos(currentAnimationFrame); + + UpdateFromAnimationFrame(false); + + Sys_UpdateWindows(W_CAMERA | W_XY); } } +// -------------------------------------------------------------------------- +// Curves +// -------------------------------------------------------------------------- + void CEntityDlg::AddCurvePoints() { - if ( editEntity == NULL || editEntity->curve == NULL ) { + if (editEntity == NULL || editEntity->curve == NULL) { return; } - // add one point 64 units from the direction of the two points int he curve int c = editEntity->curve->GetNumValues(); + idVec3 start; idVec3 end; - if ( c > 1 ) { - start = editEntity->curve->GetValue( c - 2 ); - end = editEntity->curve->GetValue( c - 1 ); + + if (c > 1) { + start = editEntity->curve->GetValue(c - 2); + end = editEntity->curve->GetValue(c - 1); + idVec3 dir = end - start; dir.Normalize(); + start = end + 64 * dir; - } else if ( c > 0 ) { - start = editEntity->curve->GetValue( 0 ); + } + else if (c > 0) { + start = editEntity->curve->GetValue(0); start.x += 64; - start.y += 64; - } else { + start.y += 64; + } + else { start = editEntity->origin; } - - editEntity->curve->AddValue( editEntity->curve->GetNumValues() * 100, start ); - if ( g_qeglobals.d_select_mode == sel_editpoint ) { + editEntity->curve->AddValue(editEntity->curve->GetNumValues() * 100, start); + + if (g_qeglobals.d_select_mode == sel_editpoint) { g_qeglobals.d_select_mode = sel_brush; EditCurvePoints(); } - Sys_UpdateWindows( W_CAMERA | W_XY ); - + Sys_UpdateWindows(W_CAMERA | W_XY); } void CEntityDlg::EditCurvePoints() { - - if ( editEntity == NULL || editEntity->curve == NULL ) { + if (editEntity == NULL || editEntity->curve == NULL) { return; } - if ( g_qeglobals.d_select_mode == sel_editpoint ) { + if (g_qeglobals.d_select_mode == sel_editpoint) { g_qeglobals.d_select_mode = sel_brush; return; } @@ -1214,153 +1666,163 @@ void CEntityDlg::EditCurvePoints() { g_qeglobals.d_numpoints = 0; g_qeglobals.d_num_move_points = 0; + int c = editEntity->curve->GetNumValues(); - for ( int i = 0; i < c; i++ ) { - if ( g_qeglobals.d_numpoints < MAX_POINTS - 1 ) { - g_qeglobals.d_points[g_qeglobals.d_numpoints++] = editEntity->curve->GetValue( i ); + + for (int i = 0; i < c; i++) { + if (g_qeglobals.d_numpoints < MAX_POINTS - 1) { + g_qeglobals.d_points[g_qeglobals.d_numpoints++] = editEntity->curve->GetValue(i); } } - Sys_UpdateWindows( W_XY | W_CAMERA ); + Sys_UpdateWindows(W_XY | W_CAMERA); } void CEntityDlg::InsertCurvePoint() { - if ( editEntity == NULL || editEntity->curve == NULL ) { + if (editEntity == NULL || editEntity->curve == NULL) { return; } - if ( g_qeglobals.d_select_mode != sel_editpoint ) { + if (g_qeglobals.d_select_mode != sel_editpoint) { return; } - if ( g_qeglobals.d_num_move_points == 0 ) { + if (g_qeglobals.d_num_move_points == 0) { return; } - for ( int i = 0; i < editEntity->curve->GetNumValues(); i++ ) { - if ( PointInMoveList( editEntity->curve->GetValueAddress( i ) ) >= 0 ) { - if ( i == editEntity->curve->GetNumValues() - 1 ) { - // just do an add + for (int i = 0; i < editEntity->curve->GetNumValues(); i++) { + if (PointInMoveList(editEntity->curve->GetValueAddress(i)) >= 0) { + if (i == editEntity->curve->GetNumValues() - 1) { AddCurvePoints(); - } else { - idCurve *newCurve = Entity_MakeCurve( editEntity ); + } + else { + idCurve* newCurve = Entity_MakeCurve(editEntity); - if ( newCurve == NULL ) { + if (newCurve == NULL) { return; } - for ( int j = 0; j < editEntity->curve->GetNumValues(); j++ ) { - if ( j == i ) { + for (int j = 0; j < editEntity->curve->GetNumValues(); j++) { + if (j == i) { idVec3 start; idVec3 end; - if ( i > 0 ) { - start = editEntity->curve->GetValue( i - 1 ); - end = editEntity->curve->GetValue( i ); + + if (i > 0) { + start = editEntity->curve->GetValue(i - 1); + end = editEntity->curve->GetValue(i); + start += end; start *= 0.5f; - } else { - start = editEntity->curve->GetValue( 0 ); - if ( editEntity->curve->GetNumValues() > 1 ) { + } + else { + start = editEntity->curve->GetValue(0); + + if (editEntity->curve->GetNumValues() > 1) { end = start; - start = editEntity->curve->GetValue ( 1 ); + start = editEntity->curve->GetValue(1); + idVec3 dir = end - start; dir.Normalize(); + start = end + 64 * dir; - } else { + } + else { end = start; end.x += 64; end.y += 64; } } - newCurve->AddValue( newCurve->GetNumValues() * 100, start ); - } - newCurve->AddValue( newCurve->GetNumValues() * 100, editEntity->curve->GetValue( j ) ); + + newCurve->AddValue(newCurve->GetNumValues() * 100, start); + } + + newCurve->AddValue(newCurve->GetNumValues() * 100, editEntity->curve->GetValue(j)); } + delete editEntity->curve; editEntity->curve = newCurve; } + g_qeglobals.d_num_move_points = 0; break; } } + UpdateEntityCurve(); - Sys_UpdateWindows( W_XY | W_CAMERA ); - + Sys_UpdateWindows(W_XY | W_CAMERA); } void CEntityDlg::DeleteCurvePoint() { - - if ( editEntity == NULL || editEntity->curve == NULL ) { + if (editEntity == NULL || editEntity->curve == NULL) { return; } - if ( g_qeglobals.d_select_mode != sel_editpoint ) { + if (g_qeglobals.d_select_mode != sel_editpoint) { return; } - - if ( g_qeglobals.d_num_move_points == 0 ) { + if (g_qeglobals.d_num_move_points == 0) { return; } - for ( int i = 0; i < editEntity->curve->GetNumValues(); i++ ) { - if ( PointInMoveList( editEntity->curve->GetValueAddress( i ) ) >= 0 ) { - editEntity->curve->RemoveIndex( i ); + for (int i = 0; i < editEntity->curve->GetNumValues(); i++) { + if (PointInMoveList(editEntity->curve->GetValueAddress(i)) >= 0) { + editEntity->curve->RemoveIndex(i); g_qeglobals.d_num_move_points = 0; break; } } + UpdateEntityCurve(); - Sys_UpdateWindows( W_XY | W_CAMERA ); - + Sys_UpdateWindows(W_XY | W_CAMERA); } - void CEntityDlg::UpdateEntityCurve() { - - if ( editEntity == NULL ) { + if (editEntity == NULL) { return; } - Entity_UpdateCurveData( editEntity ); + Entity_UpdateCurveData(editEntity); - if ( g_qeglobals.d_select_mode == sel_editpoint ) { + if (g_qeglobals.d_select_mode == sel_editpoint) { g_qeglobals.d_numpoints = 0; + int c = editEntity->curve->GetNumValues(); - for ( int i = 0; i < c; i++ ) { - if ( g_qeglobals.d_numpoints < MAX_POINTS - 1 ) { - g_qeglobals.d_points[g_qeglobals.d_numpoints++] = editEntity->curve->GetValue( i ); + + for (int i = 0; i < c; i++) { + if (g_qeglobals.d_numpoints < MAX_POINTS - 1) { + g_qeglobals.d_points[g_qeglobals.d_numpoints++] = editEntity->curve->GetValue(i); } } } - Sys_UpdateWindows( W_ENTITY ); + Sys_UpdateWindows(W_ENTITY); } - -void CEntityDlg::SelectCurvePointByRay(const idVec3 &org, const idVec3 &dir, int buttons) { - int i, besti; - float d, bestd; - idVec3 temp; - - if ( editEntity == NULL ) { +void CEntityDlg::SelectCurvePointByRay(const idVec3& org, const idVec3& dir, int buttons) { + if (editEntity == NULL) { return; } - // find the point closest to the ray - float scale = g_pParentWnd->ActiveXY()->Scale(); - besti = -1; - bestd = 8 / scale / 2; - //bestd = 8; - for (i = 0; i < g_qeglobals.d_numpoints; i++) { - temp = g_qeglobals.d_points[i] - org; - d = temp * dir; + int besti = -1; + + float scale = g_pParentWnd->ActiveXY()->Scale(); + float bestd = 8 / scale / 2; + + for (int i = 0; i < g_qeglobals.d_numpoints; i++) { + idVec3 temp = g_qeglobals.d_points[i] - org; + + float d = temp * dir; + temp = org + d * dir; temp = g_qeglobals.d_points[i] - temp; + d = temp.Length(); - if ( d <= bestd ) { + + if (d <= bestd) { bestd = d; besti = i; } @@ -1371,7 +1833,8 @@ void CEntityDlg::SelectCurvePointByRay(const idVec3 &org, const idVec3 &dir, int } g_qeglobals.d_num_move_points = 0; - assert ( besti < editEntity->curve->GetNumValues() ); - g_qeglobals.d_move_points[ g_qeglobals.d_num_move_points++ ] = editEntity->curve->GetValueAddress( besti ); -} + assert(besti < editEntity->curve->GetNumValues()); + + g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = editEntity->curve->GetValueAddress(besti); +} \ No newline at end of file diff --git a/neo/tools/radiant/EntityDlg.h b/neo/tools/radiant/EntityDlg.h index 44d48d9d..c73a0bb4 100644 --- a/neo/tools/radiant/EntityDlg.h +++ b/neo/tools/radiant/EntityDlg.h @@ -2,30 +2,14 @@ =========================================================================== Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. +Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. -This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?). - -Doom 3 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. - -Doom 3 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 Doom 3 Source Code. If not, see . - -In addition, the Doom 3 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 Doom 3 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 id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. +Modernized Entity Inspector UI pass by Justin / IceBridge workflow. =========================================================================== */ #pragma once + #include "afxcmn.h" #include "afxwin.h" #include "PropertyList.h" @@ -33,30 +17,32 @@ If you have questions concerning this license or the applicable additional terms // CEntityDlg dialog - - -class CEntityDlg : public CDialog -{ +class CEntityDlg : public CDialog { DECLARE_DYNAMIC(CEntityDlg) + public: - CEntityDlg(CWnd* pParent = NULL); // standard constructor + CEntityDlg(CWnd* pParent = NULL); virtual ~CEntityDlg(); - void SetDict(idDict *_dict) { - dict = dict; + + void SetDict(idDict* _dict) { + dict = _dict; } - void SetEditEntity(entity_t *ent) { + + void SetEditEntity(entity_t* ent) { editEntity = ent; } + void CreateEntity(); - void AssignModel (); - static CPreviewDlg *ShowModelChooser(); - static CPreviewDlg *ShowGuiChooser(); - static CPreviewDlg *ShowSoundChooser(); - static CPreviewDlg *ShowMaterialChooser(); - static CPreviewDlg *ShowParticleChooser(); - static CPreviewDlg *ShowSkinChooser( entity_t *ent ); - - void SetKeyVal(const char *key, const char *val) { + void AssignModel(); + + static CPreviewDlg* ShowModelChooser(); + static CPreviewDlg* ShowGuiChooser(); + static CPreviewDlg* ShowSoundChooser(); + static CPreviewDlg* ShowMaterialChooser(); + static CPreviewDlg* ShowParticleChooser(); + static CPreviewDlg* ShowSkinChooser(entity_t* ent); + + void SetKeyVal(const char* key, const char* val) { editKey.SetWindowText(key); editVal.SetWindowText(val); } @@ -66,55 +52,103 @@ public: void InsertCurvePoint(); void DeleteCurvePoint(); -// Dialog Data enum { IDD = IDD_DIALOG_ENTITY }; protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual void DoDataExchange(CDataExchange* pDX); - //DECLARE_MESSAGE_MAP() public: - virtual BOOL OnInitDialog(); virtual INT_PTR OnToolHitTest(CPoint point, TOOLINFO* pTI) const; + void AddClassNames(); - void UpdateEntitySel(eclass_t *ent); - void SetKeyValPairs( bool updateAnims = true ); - static const char *TranslateString(const char *p); + void UpdateEntitySel(eclass_t* ent); + void SetKeyValPairs(bool updateAnims = true); + static const char* TranslateString(const char* p); + void AddProp(); void DelProp(); void UpdateFromListBox(); + CEdit editKey; CEdit editVal; - void UpdateKeyVal(const char *key, const char *val); - void SelectCurvePointByRay(const idVec3 &org, const idVec3 &dir, int buttons); - void UpdateEntityCurve(); + void UpdateKeyVal(const char* key, const char* val); + void SelectCurvePointByRay(const idVec3& org, const idVec3& dir, int buttons); + void UpdateEntityCurve(); + void UpdateFromAnimationFrame(bool updateKeyValueDisplay = true); private: - entity_t *editEntity; + entity_t* editEntity; bool multipleEntities; + CPropertyList listKeyVal; CPropertyList listVars; CComboBox comboClass; - idDict *dict; + + idDict* dict; + const idMD5Anim* currentAnimation; int currentAnimationFrame; - const char *AngleKey(); + const char* AngleKey(); idPointListInterface curvePoints; + + // -------------------------------------------------------------------- + // Modern inspector theme + // -------------------------------------------------------------------- + CFont fontTitle; + CFont fontSection; + CFont fontNormal; + CFont fontMono; + + CBrush brushBackground; + CBrush brushPanel; + CBrush brushPanelAlt; + CBrush brushEdit; + CBrush brushStatic; + + COLORREF colorBackground; + COLORREF colorPanel; + COLORREF colorPanelAlt; + COLORREF colorBorder; + COLORREF colorText; + COLORREF colorTextMuted; + COLORREF colorAccent; + COLORREF colorEditBg; + + bool themeInitialized; + + void InitModernTheme(); + void ApplyModernTheme(); + void DestroyModernTheme(); + + void MoveCtrl(CWnd& wnd, int x, int y, int w, int h, UINT flags = SWP_SHOWWINDOW); + void MoveCtrl(int id, int x, int y, int w, int h, UINT flags = SWP_SHOWWINDOW); + void SetCtrlFont(CWnd& wnd, CFont* font); + void SetCtrlFont(int id, CFont* font); + + void DrawModernBackground(CDC& dc); + void DrawPanel(CDC& dc, const CRect& r, const char* title, bool accent = false); + public: - void UpdateFromAnimationFrame ( bool updateKeyValueDisplay = true); DECLARE_MESSAGE_MAP() + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg void OnPaint(); + CStatic staticTitle; CStatic staticKey; CStatic staticVal; CStatic staticFrame; + CButton btnPlayAnim; CButton btnStopAnim; CButton btnBrowse; + CButton btn135; CButton btn90; CButton btn45; @@ -125,17 +159,23 @@ public: CButton btn315; CButton btnUp; CButton btnDown; + CButton btnModel; CButton btnSound; CButton btnGui; CButton btnParticle; CButton btnSkin; CButton btnCurve; + CButton btnCreate; + CComboBox cbAnimations; CSliderCtrl slFrameSlider; + afx_msg void OnCbnSelchangeComboClass(); afx_msg void OnLbnSelchangeListkeyval(); + virtual BOOL PreTranslateMessage(MSG* pMsg); + afx_msg void OnBnClickedE135(); afx_msg void OnBnClickedE90(); afx_msg void OnBnClickedE45(); @@ -146,6 +186,7 @@ public: afx_msg void OnBnClickedE315(); afx_msg void OnBnClickedEUp(); afx_msg void OnBnClickedEDown(); + afx_msg void OnBnClickedButtonModel(); afx_msg void OnBnClickedButtonSound(); afx_msg void OnBnClickedButtonGui(); @@ -154,15 +195,16 @@ public: afx_msg void OnBnClickedButtonCreate(); afx_msg void OnBnClickedStartAnimation(); afx_msg void OnBnClickedStopAnimation(); - CButton btnCreate; + afx_msg void OnLbnDblclkListkeyval(); afx_msg void OnLbnSelchangeListVars(); afx_msg void OnLbnDblclkListVars(); - void OnNMReleasedcaptureSlider1(NMHDR *pNMHDR, LRESULT *pResult); - afx_msg void OnCbnAnimationChange (); - void OnTimer(UINT_PTR nIDEvent); + + afx_msg void OnNMReleasedcaptureSlider1(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnCbnAnimationChange(); + afx_msg void OnTimer(UINT_PTR nIDEvent); + afx_msg void OnBnClickedButtonParticle(); afx_msg void OnBnClickedButtonSkin(); afx_msg void OnBnClickedButtonCurve(); - -}; +}; \ No newline at end of file diff --git a/neo/tools/radiant/InspectorDialog.cpp b/neo/tools/radiant/InspectorDialog.cpp index db9435f2..9428bc82 100644 --- a/neo/tools/radiant/InspectorDialog.cpp +++ b/neo/tools/radiant/InspectorDialog.cpp @@ -2,26 +2,7 @@ =========================================================================== Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?). - -Doom 3 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. - -Doom 3 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 Doom 3 Source Code. If not, see . - -In addition, the Doom 3 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 Doom 3 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 id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. +Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. =========================================================================== */ @@ -36,71 +17,156 @@ If you have questions concerning this license or the applicable additional terms #include "InspectorDialog.h" #include "TabsDlg.h" -CInspectorDialog *g_Inspectors = NULL; -// CInspectorDialog dialog +CInspectorDialog* g_Inspectors = NULL; -void InspectorsDockingCallback ( bool docked , int ID , CWnd* wnd ) -{ - g_Inspectors->SetDockedTabs( docked , ID ); +static const COLORREF INSPECTOR_BG = RGB(245, 247, 250); +static const COLORREF INSPECTOR_PANEL_BG = RGB(255, 255, 255); +static const COLORREF INSPECTOR_TEXT = RGB(32, 36, 42); +static const COLORREF INSPECTOR_MUTED_TEXT = RGB(88, 96, 105); +static const COLORREF INSPECTOR_BORDER = RGB(218, 223, 230); + +static const int INSPECTOR_MARGIN = 8; +static const int INSPECTOR_TAB_HEIGHT = 42; +static const int INSPECTOR_DIVIDER_HEIGHT = 1; + +void InspectorsDockingCallback(bool docked, int ID, CWnd* wnd) { + if (g_Inspectors) { + g_Inspectors->SetDockedTabs(docked, ID); + } } // CInspectorDialog dialog -//IMPLEMENT_DYNAMIC(CInspectorDialog,CTabsDlg) + CInspectorDialog::CInspectorDialog(CWnd* pParent /*=NULL*/) - : CTabsDlg(CInspectorDialog::IDD, pParent) -{ + : CTabsDlg(CInspectorDialog::IDD, pParent) { initialized = false; dockedTabs = W_CONSOLE | W_TEXTURE | W_MEDIA; } -CInspectorDialog::~CInspectorDialog() -{ +CInspectorDialog::~CInspectorDialog() { + if (modernFont.GetSafeHandle()) { + modernFont.DeleteObject(); + } + if (bgBrush.GetSafeHandle()) { + bgBrush.DeleteObject(); + } + if (editBrush.GetSafeHandle()) { + editBrush.DeleteObject(); + } + if (staticBrush.GetSafeHandle()) { + staticBrush.DeleteObject(); + } } BEGIN_MESSAGE_MAP(CInspectorDialog, CTabsDlg) - ON_NOTIFY(TCN_SELCHANGE, IDC_TAB_INSPECTOR, OnTcnSelchange ) + ON_NOTIFY(TCN_SELCHANGE, IDC_TAB_INSPECTOR, OnTcnSelchange) ON_WM_SIZE() ON_WM_DESTROY() ON_WM_CLOSE() + ON_WM_CTLCOLOR() + ON_WM_ERASEBKGND() + ON_WM_PAINT() END_MESSAGE_MAP() -// CInspectorDialog message handlers - -BOOL CInspectorDialog::OnInitDialog() -{ +BOOL CInspectorDialog::OnInitDialog() { CTabsDlg::OnInitDialog(); - ASSERT ( m_Tabs.GetSafeHwnd() ); + ASSERT(m_Tabs.GetSafeHwnd()); - LoadWindowPlacement(GetSafeHwnd() , "radiant_InspectorsWindow" ); + LoadWindowPlacement(GetSafeHwnd(), "radiant_InspectorsWindow"); consoleWnd.Create(IDD_DIALOG_CONSOLE, this); texWnd.Create(TEXTURE_WINDOW_CLASS, "", QE3_SPLITTER_STYLE, CRect(5, 5, 10, 10), this, 1299); mediaDlg.Create(IDD_DIALOG_TEXTURELIST, this); entityDlg.Create(IDD_DIALOG_ENTITY, this); - dockedTabs = GetCvarInt ( "radiant_InspectorDockedDialogs" , W_CONSOLE | W_TEXTURE | W_MEDIA ); + dockedTabs = GetCvarInt("radiant_InspectorDockedDialogs", W_CONSOLE | W_TEXTURE | W_MEDIA); + + AddDockedWindow(&consoleWnd, W_CONSOLE, 1, "Console", (dockedTabs & W_CONSOLE) != 0, InspectorsDockingCallback); + AddDockedWindow(&texWnd, W_TEXTURE, 2, "Textures", (dockedTabs & W_TEXTURE) != 0, InspectorsDockingCallback); + AddDockedWindow(&mediaDlg, W_MEDIA, 3, "Media", (dockedTabs & W_MEDIA) != 0, InspectorsDockingCallback); + AddDockedWindow(&entityDlg, W_ENTITY, 4, "Entity", (dockedTabs & W_ENTITY) != 0, InspectorsDockingCallback); + + ApplyModernTheme(); + + SetMode(W_CONSOLE); - AddDockedWindow ( &consoleWnd , W_CONSOLE , 1 , "Console" , (dockedTabs & W_CONSOLE ) != 0 , InspectorsDockingCallback ); - AddDockedWindow ( &texWnd , W_TEXTURE , 2 , "Textures" , (dockedTabs & W_TEXTURE ) != 0 , InspectorsDockingCallback ); - AddDockedWindow ( &mediaDlg , W_MEDIA , 3 , "Media" , (dockedTabs & W_MEDIA ) != 0 , InspectorsDockingCallback ); - AddDockedWindow ( &entityDlg , W_ENTITY , 4 , "Entity" , (dockedTabs & W_ENTITY ) != 0 , InspectorsDockingCallback ); - - SetMode(W_CONSOLE); initialized = true; - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE + CRect rc; + GetClientRect(&rc); + LayoutModern(rc.Width(), rc.Height()); + + return TRUE; +} + +void CInspectorDialog::ApplyModernTheme() { + if (!modernFont.GetSafeHandle()) { + LOGFONT lf; + memset(&lf, 0, sizeof(lf)); + + HDC hDC = ::GetDC(GetSafeHwnd()); + const int dpiY = GetDeviceCaps(hDC, LOGPIXELSY); + ::ReleaseDC(GetSafeHwnd(), hDC); + + lf.lfHeight = -MulDiv(9, dpiY, 72); + lf.lfWeight = FW_NORMAL; + lf.lfQuality = CLEARTYPE_QUALITY; + + strncpy(lf.lfFaceName, "Segoe UI", sizeof(lf.lfFaceName) - 1); + lf.lfFaceName[sizeof(lf.lfFaceName) - 1] = '\0'; + + modernFont.CreateFontIndirect(&lf); + } + + if (!bgBrush.GetSafeHandle()) { + bgBrush.CreateSolidBrush(INSPECTOR_BG); + } + if (!editBrush.GetSafeHandle()) { + editBrush.CreateSolidBrush(INSPECTOR_PANEL_BG); + } + if (!staticBrush.GetSafeHandle()) { + staticBrush.CreateSolidBrush(INSPECTOR_BG); + } + + SetFont(&modernFont, FALSE); + + if (m_Tabs.GetSafeHwnd()) { + m_Tabs.SetFont(&modernFont, FALSE); + m_Tabs.ModifyStyleEx(WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED); + } + + ApplyModernFontRecursive(&consoleWnd); + ApplyModernFontRecursive(&mediaDlg); + ApplyModernFontRecursive(&entityDlg); + + ModifyStyleEx(WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED); + + Invalidate(TRUE); +} + +void CInspectorDialog::ApplyModernFontRecursive(CWnd* wnd) { + if (!wnd || !wnd->GetSafeHwnd() || !modernFont.GetSafeHandle()) { + return; + } + + wnd->SetFont(&modernFont, FALSE); + + CWnd* child = wnd->GetWindow(GW_CHILD); + while (child) { + child->SetFont(&modernFont, FALSE); + child = child->GetNextWindow(); + } } void CInspectorDialog::SetMode(int mode, bool updateTabs) { - FocusWindow ( mode ); + FocusWindow(mode); } -void CInspectorDialog::UpdateEntitySel(eclass_t *ent) { +void CInspectorDialog::UpdateEntitySel(eclass_t* ent) { entityDlg.UpdateEntitySel(ent); } @@ -112,80 +178,183 @@ void CInspectorDialog::UpdateSelectedEntity() { entityDlg.SetKeyValPairs(); } -bool CInspectorDialog::GetSelectAllCriteria(idStr &key, idStr &val) { - CString k, v; +bool CInspectorDialog::GetSelectAllCriteria(idStr& key, idStr& val) { + CString k; + CString v; + entityDlg.editKey.GetWindowText(k); entityDlg.editVal.GetWindowText(v); + key = k; val = v; + return true; } +void CInspectorDialog::LayoutModern(int cx, int cy) { + if (!initialized || cx <= 0 || cy <= 0) { + return; + } + const int margin = INSPECTOR_MARGIN; -void CInspectorDialog::OnSize(UINT nType, int cx, int cy) -{ - CTabsDlg::OnSize(nType, cx, cy); + CRect tabRect; + tabRect.left = margin; + tabRect.right = cx - margin; + tabRect.bottom = cy - margin; + tabRect.top = tabRect.bottom - INSPECTOR_TAB_HEIGHT; + + if (tabRect.top < margin) { + tabRect.top = margin; + } + + if (m_Tabs.GetSafeHwnd()) { + m_Tabs.SetWindowPos( + NULL, + tabRect.left, + tabRect.top, + tabRect.Width(), + tabRect.Height(), + SWP_NOZORDER | SWP_NOACTIVATE + ); + } + + CRect childRect; + childRect.left = margin; + childRect.top = margin; + childRect.right = cx - margin; + childRect.bottom = tabRect.top - margin; + + if (childRect.right < childRect.left) { + childRect.right = childRect.left; + } + if (childRect.bottom < childRect.top) { + childRect.bottom = childRect.top; + } DockedWindowInfo* info = NULL; POSITION pos; WORD wID; + for (pos = m_Windows.GetStartPosition(); pos != NULL; ) { + m_Windows.GetNextAssoc(pos, wID, (void*&)info); + + if (info && info->m_Window && info->m_Window->GetSafeHwnd() && info->m_State == DockedWindowInfo::DOCKED) { + info->m_Window->SetWindowPos( + NULL, + childRect.left, + childRect.top, + childRect.Width(), + childRect.Height(), + SWP_NOZORDER | SWP_NOACTIVATE + ); + + info->m_Window->ModifyStyleEx(WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED); + } + } +} + +void CInspectorDialog::OnSize(UINT nType, int cx, int cy) { + CTabsDlg::OnSize(nType, cx, cy); + if (!initialized) { return; } - CRect rect; - GetClientRect(rect); + LayoutModern(cx, cy); + Invalidate(FALSE); +} - CRect tabRect; - m_Tabs.GetWindowRect(tabRect); - // retain vert size but size 4 in from edges and 4 up from bottom - tabRect.left = 4; - tabRect.right = rect.Width() - 4; - tabRect.top = rect.Height() - tabRect.Height() - 4; - tabRect.bottom = rect.Height() - 4; - // adjust rect for children size - rect.bottom -= 5 + tabRect.Height(); +BOOL CInspectorDialog::OnEraseBkgnd(CDC* pDC) { + CRect rc; + GetClientRect(&rc); - m_Tabs.SetWindowPos(NULL, tabRect.left, tabRect.top, tabRect.Width(), tabRect.Height(), 0); + pDC->FillSolidRect(&rc, INSPECTOR_BG); - for( pos = m_Windows.GetStartPosition(); pos != NULL ; ) - { - m_Windows.GetNextAssoc( pos, wID, (void*&)info ); + return TRUE; +} - if ( (info->m_State == DockedWindowInfo::DOCKED) ) { - info->m_Window->SetWindowPos(NULL, rect.left, rect.top, rect.Width(), rect.Height(), 0); - } +void CInspectorDialog::OnPaint() { + CPaintDC dc(this); + CRect rc; + GetClientRect(&rc); + + dc.FillSolidRect(&rc, INSPECTOR_BG); + + if (m_Tabs.GetSafeHwnd()) { + CRect tabRect; + m_Tabs.GetWindowRect(&tabRect); + ScreenToClient(&tabRect); + + CRect lineRect; + lineRect.left = INSPECTOR_MARGIN; + lineRect.right = rc.Width() - INSPECTOR_MARGIN; + lineRect.top = tabRect.top - (INSPECTOR_MARGIN / 2); + lineRect.bottom = lineRect.top + INSPECTOR_DIVIDER_HEIGHT; + + dc.FillSolidRect(&lineRect, INSPECTOR_BORDER); } } -void CInspectorDialog::OnDestroy() -{ - ::SaveWindowPlacement(GetSafeHwnd() , "radiant_InspectorsWindow" ); - SetCvarInt("radiant_InspectorDockedDialogs" , dockedTabs ); +HBRUSH CInspectorDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { + HBRUSH hbr = CTabsDlg::OnCtlColor(pDC, pWnd, nCtlColor); + + if (!pDC) { + return hbr; + } + + pDC->SetTextColor(INSPECTOR_TEXT); + + switch (nCtlColor) { + case CTLCOLOR_DLG: + pDC->SetBkColor(INSPECTOR_BG); + return (HBRUSH)bgBrush.GetSafeHandle(); + + case CTLCOLOR_STATIC: + pDC->SetBkColor(INSPECTOR_BG); + pDC->SetTextColor(INSPECTOR_MUTED_TEXT); + return (HBRUSH)staticBrush.GetSafeHandle(); + + case CTLCOLOR_EDIT: + case CTLCOLOR_LISTBOX: + pDC->SetBkColor(INSPECTOR_PANEL_BG); + pDC->SetTextColor(INSPECTOR_TEXT); + return (HBRUSH)editBrush.GetSafeHandle(); + + case CTLCOLOR_BTN: + pDC->SetBkColor(INSPECTOR_BG); + pDC->SetTextColor(INSPECTOR_TEXT); + return (HBRUSH)bgBrush.GetSafeHandle(); + + default: + break; + } + + return hbr; +} + +void CInspectorDialog::OnDestroy() { + ::SaveWindowPlacement(GetSafeHwnd(), "radiant_InspectorsWindow"); + SetCvarInt("radiant_InspectorDockedDialogs", dockedTabs); CTabsDlg::OnDestroy(); } -void CInspectorDialog::OnClose() -{ +void CInspectorDialog::OnClose() { CTabsDlg::OnClose(); } -BOOL CInspectorDialog::PreTranslateMessage(MSG* pMsg) -{ - // TODO: Add your specialized code here and/or call the base class - if ( pMsg->message == WM_KEYDOWN || pMsg->message == WM_KEYUP) { +BOOL CInspectorDialog::PreTranslateMessage(MSG* pMsg) { + if (pMsg->message == WM_KEYDOWN || pMsg->message == WM_KEYUP) { g_pParentWnd->PostMessage(pMsg->message, pMsg->wParam, pMsg->lParam); } + return CTabsDlg::PreTranslateMessage(pMsg); } -void CInspectorDialog::SetDockedTabs ( bool docked , int ID ) -{ - if ( docked ) { +void CInspectorDialog::SetDockedTabs(bool docked, int ID) { + if (docked) { dockedTabs |= ID; } else { @@ -193,7 +362,6 @@ void CInspectorDialog::SetDockedTabs ( bool docked , int ID ) } } -void CInspectorDialog::AssignModel () -{ +void CInspectorDialog::AssignModel() { entityDlg.AssignModel(); -} +} \ No newline at end of file diff --git a/neo/tools/radiant/InspectorDialog.h b/neo/tools/radiant/InspectorDialog.h index 9c0ab4c9..76fa961e 100644 --- a/neo/tools/radiant/InspectorDialog.h +++ b/neo/tools/radiant/InspectorDialog.h @@ -45,7 +45,20 @@ public: // Dialog Data enum { IDD = IDD_DIALOG_INSPECTORS }; +protected: + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg void OnPaint(); +private: + CFont modernFont; + CBrush bgBrush; + CBrush editBrush; + CBrush staticBrush; + + void ApplyModernTheme(); + void ApplyModernFontRecursive(CWnd* wnd); + void LayoutModern(int cx, int cy); protected: bool initialized; unsigned int dockedTabs; diff --git a/neo/tools/radiant/MainFrm.cpp b/neo/tools/radiant/MainFrm.cpp index d534c961..b8117fc9 100644 --- a/neo/tools/radiant/MainFrm.cpp +++ b/neo/tools/radiant/MainFrm.cpp @@ -711,6 +711,556 @@ static UINT indicators[] = { ID_SEPARATOR, // status line indicator }; +//============================================================================= +// CMainFrameLeftPaneWnd +//============================================================================= +IMPLEMENT_DYNAMIC(CMainFrameLeftPaneWnd, CWnd) + +BEGIN_MESSAGE_MAP(CMainFrameLeftPaneWnd, CWnd) + ON_WM_SIZE() + ON_WM_PAINT() + ON_WM_LBUTTONDOWN() + ON_WM_LBUTTONUP() + ON_WM_MOUSEMOVE() + ON_WM_SETCURSOR() + ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + +CMainFrameLeftPaneWnd::CMainFrameLeftPaneWnd() { + m_pCameraWnd = NULL; + m_pInspectorWnd = NULL; + m_nCameraPercent = 45; + m_nCameraHeight = 0; + m_nSplitterHeight = 5; + m_bInLayout = false; + m_bTrackingSplitter = false; + m_nDragStartY = 0; + m_nDragStartCameraHeight = 0; + m_rcSplitter.SetRectEmpty(); +} + +CMainFrameLeftPaneWnd::~CMainFrameLeftPaneWnd() { +} + +BOOL CMainFrameLeftPaneWnd::Create(CWnd *pParent, UINT nID) { + CString className = AfxRegisterWndClass( + CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, + ::LoadCursor(NULL, IDC_ARROW), + (HBRUSH)(COLOR_BTNFACE + 1), + NULL + ); + return CWnd::CreateEx( + 0, + className, + "RadiantMainFrameLeftPaneWnd", + WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, + CRect(0, 0, 0, 0), + pParent, + nID + ); +} + +void CMainFrameLeftPaneWnd::AttachChild(CWnd *pWnd) { + if (!pWnd || !pWnd->GetSafeHwnd() || !GetSafeHwnd()) { + return; + } + + if (::GetParent(pWnd->GetSafeHwnd()) != GetSafeHwnd()) { + pWnd->SetParent(this); + } + + LONG style = ::GetWindowLong(pWnd->GetSafeHwnd(), GWL_STYLE); + style &= ~(WS_POPUP | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX); + style |= WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; + ::SetWindowLong(pWnd->GetSafeHwnd(), GWL_STYLE, style); + + LONG exStyle = ::GetWindowLong(pWnd->GetSafeHwnd(), GWL_EXSTYLE); + exStyle &= ~(WS_EX_DLGMODALFRAME | WS_EX_TOOLWINDOW | WS_EX_APPWINDOW | WS_EX_WINDOWEDGE); + exStyle |= WS_EX_CONTROLPARENT; + ::SetWindowLong(pWnd->GetSafeHwnd(), GWL_EXSTYLE, exStyle); + + ::SetWindowPos( + pWnd->GetSafeHwnd(), + NULL, + 0, + 0, + 0, + 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED + ); +} + +bool CMainFrameLeftPaneWnd::IsWindowUsable(CWnd *pWnd) const { + return pWnd && pWnd->GetSafeHwnd(); +} + +void CMainFrameLeftPaneWnd::SetEmbeddedWindows(CWnd *pCameraWnd, CWnd *pInspectorWnd) { + m_pCameraWnd = pCameraWnd; + m_pInspectorWnd = pInspectorWnd; + AttachChild(m_pCameraWnd); + AttachChild(m_pInspectorWnd); + LayoutChildren(); +} + +int CMainFrameLeftPaneWnd::ClampCameraHeight(int cameraHeight, const CRect &client) const { + const int height = client.Height(); + const int available = height - m_nSplitterHeight; + if (available <= 2) { + return height / 2; + } + + const int minCamera = 96; + const int minInspector = 120; + int minHeight = minCamera; + int maxHeight = available - minInspector; + + if (maxHeight < minHeight) { + minHeight = 1; + maxHeight = available - 1; + if (maxHeight < minHeight) { + maxHeight = minHeight; + } + } + + if (cameraHeight < minHeight) { + cameraHeight = minHeight; + } + if (cameraHeight > maxHeight) { + cameraHeight = maxHeight; + } + return cameraHeight; +} + +bool CMainFrameLeftPaneWnd::HitTestSplitter(const CPoint &point) const { + return !m_rcSplitter.IsRectEmpty() && m_rcSplitter.PtInRect(point); +} + +void CMainFrameLeftPaneWnd::DrawSplitter(CDC *pDC) { + if (!pDC || m_rcSplitter.IsRectEmpty()) { + return; + } + + CRect rc = m_rcSplitter; + CBrush brush(::GetSysColor(COLOR_BTNFACE)); + pDC->FillRect(rc, &brush); + pDC->Draw3dRect(rc, ::GetSysColor(COLOR_3DHILIGHT), ::GetSysColor(COLOR_3DSHADOW)); + + int y = rc.top + rc.Height() / 2; + CPen pen(PS_SOLID, 1, ::GetSysColor(COLOR_3DSHADOW)); + CPen *oldPen = pDC->SelectObject(&pen); + pDC->MoveTo(rc.left + 6, y); + pDC->LineTo(rc.right - 6, y); + pDC->SelectObject(oldPen); +} + +void CMainFrameLeftPaneWnd::LayoutChildren() { + if (!GetSafeHwnd() || m_bInLayout) { + return; + } + + m_bInLayout = true; + + CRect client; + GetClientRect(client); + if (client.Width() < 1 || client.Height() < 1) { + m_rcSplitter.SetRectEmpty(); + m_bInLayout = false; + return; + } + + bool cameraVisible = IsWindowUsable(m_pCameraWnd) && m_pCameraWnd->IsWindowVisible(); + bool inspectorVisible = IsWindowUsable(m_pInspectorWnd) && m_pInspectorWnd->IsWindowVisible(); + + if (cameraVisible && !inspectorVisible) { + m_rcSplitter.SetRectEmpty(); + m_pCameraWnd->MoveWindow(client, TRUE); + m_bInLayout = false; + return; + } + + if (!cameraVisible && inspectorVisible) { + m_rcSplitter.SetRectEmpty(); + m_pInspectorWnd->MoveWindow(client, TRUE); + m_bInLayout = false; + return; + } + + if (!cameraVisible && !inspectorVisible) { + m_rcSplitter.SetRectEmpty(); + m_bInLayout = false; + return; + } + + int cameraHeight = m_bTrackingSplitter ? m_nCameraHeight : (client.Height() * m_nCameraPercent) / 100; + cameraHeight = ClampCameraHeight(cameraHeight, client); + m_nCameraHeight = cameraHeight; + + CRect cameraRect(client.left, client.top, client.right, client.top + cameraHeight); + m_rcSplitter.SetRect(client.left, cameraRect.bottom, client.right, cameraRect.bottom + m_nSplitterHeight); + CRect inspectorRect(client.left, m_rcSplitter.bottom, client.right, client.bottom); + + m_pCameraWnd->MoveWindow(cameraRect, TRUE); + m_pInspectorWnd->MoveWindow(inspectorRect, TRUE); + + Invalidate(FALSE); + m_bInLayout = false; +} + +void CMainFrameLeftPaneWnd::RecalcLayout() { + LayoutChildren(); +} + +void CMainFrameLeftPaneWnd::OnSize(UINT nType, int cx, int cy) { + CWnd::OnSize(nType, cx, cy); + LayoutChildren(); +} + +void CMainFrameLeftPaneWnd::OnPaint() { + CPaintDC dc(this); + DrawSplitter(&dc); +} + +void CMainFrameLeftPaneWnd::OnLButtonDown(UINT nFlags, CPoint point) { + if (HitTestSplitter(point)) { + m_bTrackingSplitter = true; + m_nDragStartY = point.y; + m_nDragStartCameraHeight = m_nCameraHeight; + SetCapture(); + ::SetCursor(::LoadCursor(NULL, IDC_SIZENS)); + return; + } + CWnd::OnLButtonDown(nFlags, point); +} + +void CMainFrameLeftPaneWnd::OnLButtonUp(UINT nFlags, CPoint point) { + if (m_bTrackingSplitter) { + m_bTrackingSplitter = false; + if (GetCapture() == this) { + ReleaseCapture(); + } + LayoutChildren(); + return; + } + CWnd::OnLButtonUp(nFlags, point); +} + +void CMainFrameLeftPaneWnd::OnMouseMove(UINT nFlags, CPoint point) { + if (m_bTrackingSplitter) { + CRect client; + GetClientRect(client); + m_nCameraHeight = ClampCameraHeight(m_nDragStartCameraHeight + point.y - m_nDragStartY, client); + if (client.Height() > m_nSplitterHeight) { + m_nCameraPercent = (m_nCameraHeight * 100) / client.Height(); + } + LayoutChildren(); + ::SetCursor(::LoadCursor(NULL, IDC_SIZENS)); + return; + } + + if (HitTestSplitter(point)) { + ::SetCursor(::LoadCursor(NULL, IDC_SIZENS)); + } + + CWnd::OnMouseMove(nFlags, point); +} + +BOOL CMainFrameLeftPaneWnd::OnSetCursor(CWnd *pWnd, UINT nHitTest, UINT message) { + CPoint point; + GetCursorPos(&point); + ScreenToClient(&point); + if (m_bTrackingSplitter || HitTestSplitter(point)) { + ::SetCursor(::LoadCursor(NULL, IDC_SIZENS)); + return TRUE; + } + return CWnd::OnSetCursor(pWnd, nHitTest, message); +} + +BOOL CMainFrameLeftPaneWnd::OnEraseBkgnd(CDC *pDC) { + CRect client; + GetClientRect(client); + CBrush brush(::GetSysColor(COLOR_BTNFACE)); + pDC->FillRect(client, &brush); + DrawSplitter(pDC); + return TRUE; +} + +//============================================================================= +// CMainFrameLayoutWnd +//============================================================================= +IMPLEMENT_DYNAMIC(CMainFrameLayoutWnd, CWnd) + +BEGIN_MESSAGE_MAP(CMainFrameLayoutWnd, CWnd) + ON_WM_SIZE() + ON_WM_PAINT() + ON_WM_LBUTTONDOWN() + ON_WM_LBUTTONUP() + ON_WM_MOUSEMOVE() + ON_WM_SETCURSOR() + ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + +CMainFrameLayoutWnd::CMainFrameLayoutWnd() { + m_pXYDockWnd = NULL; + m_nLeftPercent = 36; + m_nLeftWidth = 0; + m_nSplitterWidth = 5; + m_bInLayout = false; + m_bTrackingSplitter = false; + m_nDragStartX = 0; + m_nDragStartLeftWidth = 0; + m_rcSplitter.SetRectEmpty(); +} + +CMainFrameLayoutWnd::~CMainFrameLayoutWnd() { +} + +BOOL CMainFrameLayoutWnd::Create(CWnd *pParent, UINT nID) { + CString className = AfxRegisterWndClass( + CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, + ::LoadCursor(NULL, IDC_ARROW), + (HBRUSH)(COLOR_BTNFACE + 1), + NULL + ); + + if (!CWnd::CreateEx( + 0, + className, + "RadiantMainFrameLayoutWnd", + WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, + CRect(0, 0, 0, 0), + pParent, + nID + )) { + return FALSE; + } + + return m_wndLeftPane.Create(this, 0x7B20); +} + +CWnd *CMainFrameLayoutWnd::GetLeftPaneWnd() { + return &m_wndLeftPane; +} + +void CMainFrameLayoutWnd::AttachChild(CWnd *pWnd) { + if (!pWnd || !pWnd->GetSafeHwnd() || !GetSafeHwnd()) { + return; + } + + if (::GetParent(pWnd->GetSafeHwnd()) != GetSafeHwnd()) { + pWnd->SetParent(this); + } + + LONG style = ::GetWindowLong(pWnd->GetSafeHwnd(), GWL_STYLE); + style &= ~(WS_POPUP | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX); + style |= WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; + ::SetWindowLong(pWnd->GetSafeHwnd(), GWL_STYLE, style); + + ::SetWindowPos( + pWnd->GetSafeHwnd(), + NULL, + 0, + 0, + 0, + 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED + ); +} + +bool CMainFrameLayoutWnd::IsWindowUsable(CWnd *pWnd) const { + return pWnd && pWnd->GetSafeHwnd(); +} + +void CMainFrameLayoutWnd::SetEmbeddedWindows(CWnd *pCameraWnd, CWnd *pInspectorWnd, CWnd *pXYDockWnd) { + m_pXYDockWnd = pXYDockWnd; + AttachChild(m_pXYDockWnd); + m_wndLeftPane.SetEmbeddedWindows(pCameraWnd, pInspectorWnd); + LayoutChildren(); +} + +int CMainFrameLayoutWnd::ClampLeftWidth(int leftWidth, const CRect &client) const { + const int width = client.Width(); + const int available = width - m_nSplitterWidth; + if (available <= 2) { + return width / 2; + } + + const int minLeft = 280; + const int minRight = 420; + int minWidth = minLeft; + int maxWidth = available - minRight; + + if (maxWidth < minWidth) { + minWidth = 1; + maxWidth = available - 1; + if (maxWidth < minWidth) { + maxWidth = minWidth; + } + } + + if (leftWidth < minWidth) { + leftWidth = minWidth; + } + if (leftWidth > maxWidth) { + leftWidth = maxWidth; + } + return leftWidth; +} + +bool CMainFrameLayoutWnd::HitTestSplitter(const CPoint &point) const { + return !m_rcSplitter.IsRectEmpty() && m_rcSplitter.PtInRect(point); +} + +void CMainFrameLayoutWnd::DrawSplitter(CDC *pDC) { + if (!pDC || m_rcSplitter.IsRectEmpty()) { + return; + } + + CRect rc = m_rcSplitter; + CBrush brush(::GetSysColor(COLOR_BTNFACE)); + pDC->FillRect(rc, &brush); + pDC->Draw3dRect(rc, ::GetSysColor(COLOR_3DHILIGHT), ::GetSysColor(COLOR_3DSHADOW)); + + int x = rc.left + rc.Width() / 2; + CPen pen(PS_SOLID, 1, ::GetSysColor(COLOR_3DSHADOW)); + CPen *oldPen = pDC->SelectObject(&pen); + pDC->MoveTo(x, rc.top + 6); + pDC->LineTo(x, rc.bottom - 6); + pDC->SelectObject(oldPen); +} + +void CMainFrameLayoutWnd::LayoutChildren() { + if (!GetSafeHwnd() || m_bInLayout) { + return; + } + + m_bInLayout = true; + + CRect client; + GetClientRect(client); + if (client.Width() < 1 || client.Height() < 1) { + m_rcSplitter.SetRectEmpty(); + m_bInLayout = false; + return; + } + + bool rightVisible = IsWindowUsable(m_pXYDockWnd) && m_pXYDockWnd->IsWindowVisible(); + bool leftVisible = m_wndLeftPane.GetSafeHwnd() && m_wndLeftPane.IsWindowVisible(); + + if (leftVisible && !rightVisible) { + m_rcSplitter.SetRectEmpty(); + m_wndLeftPane.MoveWindow(client, TRUE); + m_wndLeftPane.LayoutChildren(); + m_bInLayout = false; + return; + } + + if (!leftVisible && rightVisible) { + m_rcSplitter.SetRectEmpty(); + m_pXYDockWnd->MoveWindow(client, TRUE); + m_bInLayout = false; + return; + } + + if (!leftVisible && !rightVisible) { + m_rcSplitter.SetRectEmpty(); + m_bInLayout = false; + return; + } + + int leftWidth = m_bTrackingSplitter ? m_nLeftWidth : (client.Width() * m_nLeftPercent) / 100; + leftWidth = ClampLeftWidth(leftWidth, client); + m_nLeftWidth = leftWidth; + + CRect leftRect(client.left, client.top, client.left + leftWidth, client.bottom); + m_rcSplitter.SetRect(leftRect.right, client.top, leftRect.right + m_nSplitterWidth, client.bottom); + CRect rightRect(m_rcSplitter.right, client.top, client.right, client.bottom); + + m_wndLeftPane.MoveWindow(leftRect, TRUE); + m_wndLeftPane.LayoutChildren(); + m_pXYDockWnd->MoveWindow(rightRect, TRUE); + + Invalidate(FALSE); + m_bInLayout = false; +} + +void CMainFrameLayoutWnd::RecalcLayout() { + LayoutChildren(); +} + +void CMainFrameLayoutWnd::OnSize(UINT nType, int cx, int cy) { + CWnd::OnSize(nType, cx, cy); + LayoutChildren(); +} + +void CMainFrameLayoutWnd::OnPaint() { + CPaintDC dc(this); + DrawSplitter(&dc); +} + +void CMainFrameLayoutWnd::OnLButtonDown(UINT nFlags, CPoint point) { + if (HitTestSplitter(point)) { + m_bTrackingSplitter = true; + m_nDragStartX = point.x; + m_nDragStartLeftWidth = m_nLeftWidth; + SetCapture(); + ::SetCursor(::LoadCursor(NULL, IDC_SIZEWE)); + return; + } + CWnd::OnLButtonDown(nFlags, point); +} + +void CMainFrameLayoutWnd::OnLButtonUp(UINT nFlags, CPoint point) { + if (m_bTrackingSplitter) { + m_bTrackingSplitter = false; + if (GetCapture() == this) { + ReleaseCapture(); + } + LayoutChildren(); + return; + } + CWnd::OnLButtonUp(nFlags, point); +} + +void CMainFrameLayoutWnd::OnMouseMove(UINT nFlags, CPoint point) { + if (m_bTrackingSplitter) { + CRect client; + GetClientRect(client); + m_nLeftWidth = ClampLeftWidth(m_nDragStartLeftWidth + point.x - m_nDragStartX, client); + if (client.Width() > m_nSplitterWidth) { + m_nLeftPercent = (m_nLeftWidth * 100) / client.Width(); + } + LayoutChildren(); + ::SetCursor(::LoadCursor(NULL, IDC_SIZEWE)); + return; + } + + if (HitTestSplitter(point)) { + ::SetCursor(::LoadCursor(NULL, IDC_SIZEWE)); + } + + CWnd::OnMouseMove(nFlags, point); +} + +BOOL CMainFrameLayoutWnd::OnSetCursor(CWnd *pWnd, UINT nHitTest, UINT message) { + CPoint point; + GetCursorPos(&point); + ScreenToClient(&point); + if (m_bTrackingSplitter || HitTestSplitter(point)) { + ::SetCursor(::LoadCursor(NULL, IDC_SIZEWE)); + return TRUE; + } + return CWnd::OnSetCursor(pWnd, nHitTest, message); +} + +BOOL CMainFrameLayoutWnd::OnEraseBkgnd(CDC *pDC) { + CRect client; + GetClientRect(client); + CBrush brush(::GetSysColor(COLOR_BTNFACE)); + pDC->FillRect(client, &brush); + DrawSplitter(pDC); + return TRUE; +} + /* ======================================================================================================================= ======================================================================================================================= @@ -754,6 +1304,8 @@ CMainFrame::CMainFrame() { m_pXYWnd = NULL; m_pCamWnd = NULL; m_pZWnd = NULL; + m_pXYDockWnd = NULL; + m_hMovedMenu = NULL; m_pYZWnd = NULL; m_pXZWnd = NULL; m_pActiveXY = NULL; @@ -768,6 +1320,95 @@ CMainFrame::CMainFrame() { CMainFrame::~CMainFrame() { } +/* + ======================================================================================================================= + ======================================================================================================================= + */ +CMenu *CMainFrame::GetMenu() const { + if (m_pXYDockWnd && m_pXYDockWnd->GetSafeHwnd() && m_pXYDockWnd->GetMenuHandle()) { + return CMenu::FromHandle(m_pXYDockWnd->GetMenuHandle()); + } + if (m_hMovedMenu) { + return CMenu::FromHandle(m_hMovedMenu); + } + return const_cast(this)->CFrameWnd::GetMenu(); +} + +/* + ======================================================================================================================= + ======================================================================================================================= + */ +static HMENU RadiantMainMenuHandle() { + if (g_pParentWnd) { + CMenu *pMenu = g_pParentWnd->GetMenu(); + if (pMenu && pMenu->GetSafeHmenu()) { + return pMenu->GetSafeHmenu(); + } + } + return NULL; +} + +/* + ======================================================================================================================= + ======================================================================================================================= + */ +BOOL CMainFrame::CreateEmbeddedMainToolBar(UINT nID) { + CWnd *pToolBarParent = m_pXYDockWnd ? static_cast(m_pXYDockWnd) : static_cast(this); + if (!m_wndToolBar.CreateEx(pToolBarParent, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || !m_wndToolBar.LoadToolBar(nID)) { + TRACE0("Failed to create toolbar\n"); + return FALSE; + } + + m_wndToolBar.SetOwner(this); + if (m_pXYDockWnd) { + m_pXYDockWnd->SetEmbeddedToolBar(&m_wndToolBar); + } + return TRUE; +} + +/* + ======================================================================================================================= + ======================================================================================================================= + */ +void CMainFrame::MoveFrameMenuIntoXYWnd() { + if (!m_pXYDockWnd || !m_pXYDockWnd->GetSafeHwnd()) { + return; + } + + HMENU hMenu = ::GetMenu(GetSafeHwnd()); + if (!hMenu) { + hMenu = m_hMovedMenu; + } + if (!hMenu) { + return; + } + + m_hMovedMenu = hMenu; + m_pXYDockWnd->SetMenuHandle(hMenu); + + if (::GetMenu(GetSafeHwnd()) == hMenu) { + ::SetMenu(GetSafeHwnd(), NULL); + ::DrawMenuBar(GetSafeHwnd()); + } +} + +/* + ======================================================================================================================= + ======================================================================================================================= + */ +void CMainFrame::RecalcXYDockLayout() { + if (m_pXYDockWnd && m_pXYDockWnd->GetSafeHwnd()) { + m_pXYDockWnd->RecalcLayout(); + } +} + +void CMainFrame::RecalcMainLayout() { + if (m_wndMainLayout.GetSafeHwnd()) { + m_wndMainLayout.RecalcLayout(); + } + RecalcXYDockLayout(); +} + /* ======================================================================================================================= ======================================================================================================================= @@ -937,7 +1578,10 @@ void CMainFrame::SetButtonMenuStates() { // FillTextureMenu(); // redundant but i'll clean it up later.. yeah right.. FillBSPMenu(); LoadMruInReg(g_qeglobals.d_lpMruMenu, "Software\\" EDITOR_REGISTRY_KEY "\\MRU" ); - PlaceMenuMRUItem(g_qeglobals.d_lpMruMenu, ::GetSubMenu(::GetMenu(GetSafeHwnd()), 0), ID_FILE_EXIT); + HMENU hMenu = RadiantMainMenuHandle(); + if (hMenu) { + PlaceMenuMRUItem(g_qeglobals.d_lpMruMenu, ::GetSubMenu(hMenu, 0), ID_FILE_EXIT); + } } } @@ -946,6 +1590,9 @@ void CMainFrame::SetButtonMenuStates() { ======================================================================================================================= */ void CMainFrame::ShowMenuItemKeyBindings(CMenu *pMenu) { + if (!pMenu) { + return; + } int i, j; char key[1024], *ptr; MENUITEMINFO MenuItemInfo; @@ -1097,12 +1744,12 @@ int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { UINT nID = (g_PrefsDlg.m_bWideToolbar) ? IDR_TOOLBAR_ADVANCED : IDR_TOOLBAR1; - if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP - | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || !m_wndToolBar.LoadToolBar(nID)) { - TRACE0("Failed to create toolbar\n"); + if (!CreateEmbeddedMainToolBar(nID)) { return -1; // fail to create } + MoveFrameMenuIntoXYWnd(); + if (!m_wndStatusBar.Create(this) || !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators) / sizeof(UINT))) { TRACE0("Failed to create status bar\n"); return -1; // fail to create @@ -1124,15 +1771,14 @@ int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { m_wndToolBar.GetToolBarCtrl().CheckButton(ID_SOUND_SHOWSOUNDVOLUMES,g_qeglobals.d_savedinfo.showSoundAlways); m_wndToolBar.GetToolBarCtrl().CheckButton(ID_SOUND_SHOWSELECTEDSOUNDVOLUMES,g_qeglobals.d_savedinfo.showSoundWhenSelected); - m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); - DockControlBar(&m_wndToolBar); + RecalcXYDockLayout(); g_nScaleHow = 0; - m_wndTextureBar.Create(this, IDD_TEXTUREBAR, CBRS_BOTTOM, 7433); - m_wndTextureBar.EnableDocking(CBRS_ALIGN_ANY); - DockControlBar(&m_wndTextureBar); + //m_wndTextureBar.Create(this, IDD_TEXTUREBAR, CBRS_BOTTOM, 7433); + //m_wndTextureBar.EnableDocking(CBRS_ALIGN_ANY); + //DockControlBar(&m_wndTextureBar); g_qeglobals.d_lpMruMenu = CreateMruMenuDefault(); @@ -1170,7 +1816,7 @@ int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { SetGridStatus(); SetTexValStatus(); SetButtonMenuStates(); - LoadBarState("RadiantToolBars2"); + //LoadBarState("RadiantToolBars2"); SetActiveXY(m_pXYWnd); m_pXYWnd->SetFocus(); @@ -1472,11 +2118,16 @@ void CMainFrame::OnDestroy() { SaveWindowPlacement(GetSafeHwnd(), "radiant_MainWindowPlace"); - SaveWindowPlacement(m_pXYWnd->GetSafeHwnd(), "radiant_xywindow"); + if (m_pXYDockWnd && m_pXYDockWnd->GetSafeHwnd()) { + SaveWindowPlacement(m_pXYDockWnd->GetSafeHwnd(), "radiant_xywindow"); + } else if (m_pXYWnd && m_pXYWnd->GetSafeHwnd()) { + SaveWindowPlacement(m_pXYWnd->GetSafeHwnd(), "radiant_xywindow"); + } SaveWindowPlacement(m_pXZWnd->GetSafeHwnd(), "radiant_xzwindow"); SaveWindowPlacement(m_pYZWnd->GetSafeHwnd(), "radiant_yzwindow"); SaveWindowPlacement(m_pCamWnd->GetSafeHwnd(), "radiant_camerawindow"); - SaveWindowPlacement(m_pZWnd->GetSafeHwnd(), "radiant_zwindow"); + // Z is docked inside XY, so do not overwrite the old floating Z placement. + // SaveWindowPlacement(m_pZWnd->GetSafeHwnd(), "radiant_zwindow"); SaveWindowState(g_Inspectors->texWnd.GetSafeHwnd(), "radiant_texwindow"); if (m_pXYWnd->GetSafeHwnd()) { @@ -1507,6 +2158,12 @@ void CMainFrame::OnDestroy() { delete m_pZWnd; m_pZWnd = NULL; + if (m_pXYDockWnd && m_pXYDockWnd->GetSafeHwnd()) { + m_pXYDockWnd->SendMessage(WM_DESTROY, 0, 0); + } + delete m_pXYDockWnd; + m_pXYDockWnd = NULL; + if (m_pCamWnd->GetSafeHwnd()) { m_pCamWnd->SendMessage(WM_DESTROY, 0, 0); } @@ -1701,37 +2358,31 @@ void CMainFrame::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { */ BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext *pContext) { + if (!m_wndMainLayout.Create(this, AFX_IDW_PANE_FIRST)) { + return FALSE; + } + g_Inspectors = new CInspectorDialog( this ); - g_Inspectors->Create(IDD_DIALOG_INSPECTORS, this); - - LoadWindowPlacement(g_Inspectors->GetSafeHwnd(), "radiant_InspectorsWindow"); + g_Inspectors->Create(IDD_DIALOG_INSPECTORS, m_wndMainLayout.GetLeftPaneWnd()); g_Inspectors->ShowWindow(SW_SHOW); - CRect r; - g_Inspectors->GetWindowRect ( r ); - - //stupid hack to get the window resize itself properly - r.DeflateRect(0,0,0,1); - g_Inspectors->MoveWindow(r); - r.InflateRect(0,0,0,1); - g_Inspectors->MoveWindow(r); - if (!LoadWindowPlacement(GetSafeHwnd(), "radiant_MainWindowPlace")) { } - CRect rect(5, 25, 100, 100); - CRect rctParent; - GetClientRect(rctParent); + CRect rect(0, 0, 64, 64); m_pCamWnd = new CCamWnd(); - m_pCamWnd->Create(CAMERA_WINDOW_CLASS, "", QE3_CHILDSTYLE, rect, this, 1234); + m_pCamWnd->Create(CAMERA_WINDOW_CLASS, "", QE3_CHILDSTYLE, rect, m_wndMainLayout.GetLeftPaneWnd(), 1234); + + m_pXYDockWnd = new CXYDockWnd(); + m_pXYDockWnd->Create(rect, &m_wndMainLayout, 1239); m_pZWnd = new CZWnd(); - m_pZWnd->Create(Z_WINDOW_CLASS, "", QE3_CHILDSTYLE, rect, this, 1238); + m_pZWnd->Create(Z_WINDOW_CLASS, "", QE3_CHILDSTYLE, rect, m_pXYDockWnd, 1238); m_pXYWnd = new CXYWnd(); - m_pXYWnd->Create(XY_WINDOW_CLASS, "", QE3_CHILDSTYLE, rect, this, 1235); + m_pXYWnd->Create(XY_WINDOW_CLASS, "", QE3_CHILDSTYLE, rect, m_pXYDockWnd, 1235); m_pXYWnd->SetViewType(XY); m_pXZWnd = new CXYWnd(); @@ -1743,14 +2394,18 @@ BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext *pContext) { m_pYZWnd->SetViewType(YZ); m_pCamWnd->SetXYFriend(m_pXYWnd); + m_pXYDockWnd->SetEmbeddedWindows(m_pZWnd, m_pXYWnd); + m_wndMainLayout.SetEmbeddedWindows(m_pCamWnd, g_Inspectors, m_pXYDockWnd); CRect rctWork; - LoadWindowPlacement(m_pXYWnd->GetSafeHwnd(), "radiant_xywindow"); + // The main workspace is now proportional and splitter-managed. Do not load + // old child-window placements here; they will fight the container layout and + // can leave the Z/XY area cramped at startup. LoadWindowPlacement(m_pXZWnd->GetSafeHwnd(), "radiant_xzwindow"); LoadWindowPlacement(m_pYZWnd->GetSafeHwnd(), "radiant_yzwindow"); - LoadWindowPlacement(m_pCamWnd->GetSafeHwnd(), "radiant_camerawindow"); - LoadWindowPlacement(m_pZWnd->GetSafeHwnd(), "radiant_zwindow"); + // Z is docked inside the XY container; its size is managed by CXYDockWnd. + // LoadWindowPlacement(m_pZWnd->GetSafeHwnd(), "radiant_zwindow"); if (!g_PrefsDlg.m_bXZVis) { m_pXZWnd->ShowWindow(SW_HIDE); @@ -1764,6 +2419,8 @@ BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext *pContext) { m_pZWnd->ShowWindow(SW_HIDE); } + RecalcMainLayout(); + CreateQEChildren(); if (m_pXYWnd) { @@ -1805,6 +2462,8 @@ void CMainFrame::OnSize(UINT nType, int cx, int cy) { m_wndStatusBar.GetPaneInfo( 5, nID, nStyle, nWidth); m_wndStatusBar.SetPaneInfo( 5, nID, nStyle, rctParent.Width() * 0.01f ); } + + RecalcMainLayout(); } void OpenDialog(void); @@ -2077,8 +2736,10 @@ BOOL DoMru(HWND hWnd,WORD wId) DelMenuItem(g_qeglobals.d_lpMruMenu,wId,TRUE); // Refresh the File menu. - PlaceMenuMRUItem(g_qeglobals.d_lpMruMenu,GetSubMenu(GetMenu(hWnd),0), - ID_FILE_EXIT); + HMENU hMenu = RadiantMainMenuHandle(); + if (hMenu) { + PlaceMenuMRUItem(g_qeglobals.d_lpMruMenu, GetSubMenu(hMenu, 0), ID_FILE_EXIT); + } return fExist; } @@ -2214,7 +2875,7 @@ void CMainFrame::OnViewShowblocks() { g_qeglobals.show_blocks = !(g_qeglobals.show_blocks); CheckMenuItem ( - ::GetMenu(GetSafeHwnd()), + RadiantMainMenuHandle(), ID_VIEW_SHOWBLOCKS, MF_BYCOMMAND | (g_qeglobals.show_blocks ? MF_CHECKED : MF_UNCHECKED) ); @@ -2227,10 +2888,10 @@ void CMainFrame::OnViewShowblocks() { */ void CMainFrame::OnViewShowclip() { if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_CLIP) & EXCLUDE_CLIP) { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOWCLIP, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOWCLIP, MF_BYCOMMAND | MF_UNCHECKED); } else { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOWCLIP, MF_BYCOMMAND | MF_CHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOWCLIP, MF_BYCOMMAND | MF_CHECKED); } Sys_UpdateWindows(W_XY | W_CAMERA); @@ -2242,10 +2903,10 @@ void CMainFrame::OnViewShowclip() { */ void CMainFrame::OnViewShowTriggers() { if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_TRIGGERS) & EXCLUDE_TRIGGERS) { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOWTRIGGERS, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOWTRIGGERS, MF_BYCOMMAND | MF_UNCHECKED); } else { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOWTRIGGERS, MF_BYCOMMAND | MF_CHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOWTRIGGERS, MF_BYCOMMAND | MF_CHECKED); } Sys_UpdateWindows(W_XY | W_CAMERA); @@ -2259,7 +2920,7 @@ void CMainFrame::OnViewShowcoordinates() { g_qeglobals.d_savedinfo.show_coordinates ^= 1; CheckMenuItem ( - ::GetMenu(GetSafeHwnd()), + RadiantMainMenuHandle(), ID_VIEW_SHOWCOORDINATES, MF_BYCOMMAND | (g_qeglobals.d_savedinfo.show_coordinates ? MF_CHECKED : MF_UNCHECKED) ); @@ -2272,10 +2933,10 @@ void CMainFrame::OnViewShowcoordinates() { */ void CMainFrame::OnViewShowent() { if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_ENT) & EXCLUDE_ENT) { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOWENT, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOWENT, MF_BYCOMMAND | MF_UNCHECKED); } else { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOWENT, MF_BYCOMMAND | MF_CHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOWENT, MF_BYCOMMAND | MF_CHECKED); } Sys_UpdateWindows(W_XY | W_CAMERA); @@ -2287,10 +2948,10 @@ void CMainFrame::OnViewShowent() { */ void CMainFrame::OnViewShowlights() { if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_LIGHTS) & EXCLUDE_LIGHTS) { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOWLIGHTS, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOWLIGHTS, MF_BYCOMMAND | MF_UNCHECKED); } else { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOWLIGHTS, MF_BYCOMMAND | MF_CHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOWLIGHTS, MF_BYCOMMAND | MF_CHECKED); } Sys_UpdateWindows(W_XY | W_CAMERA); @@ -2304,7 +2965,7 @@ void CMainFrame::OnViewShownames() { g_qeglobals.d_savedinfo.show_names = !(g_qeglobals.d_savedinfo.show_names); CheckMenuItem ( - ::GetMenu(GetSafeHwnd()), + RadiantMainMenuHandle(), ID_VIEW_SHOWNAMES, MF_BYCOMMAND | (g_qeglobals.d_savedinfo.show_names ? MF_CHECKED : MF_UNCHECKED) ); @@ -2318,10 +2979,10 @@ void CMainFrame::OnViewShownames() { */ void CMainFrame::OnViewShowpath() { if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_PATHS) & EXCLUDE_PATHS) { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOWPATH, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOWPATH, MF_BYCOMMAND | MF_UNCHECKED); } else { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOWPATH, MF_BYCOMMAND | MF_CHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOWPATH, MF_BYCOMMAND | MF_CHECKED); } Sys_UpdateWindows(W_XY | W_CAMERA); @@ -2333,10 +2994,10 @@ void CMainFrame::OnViewShowpath() { */ void CMainFrame::OnViewShowCombatNodes() { if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_COMBATNODES) & EXCLUDE_COMBATNODES) { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOWCOMBATNODES, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOWCOMBATNODES, MF_BYCOMMAND | MF_UNCHECKED); } else { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOWCOMBATNODES, MF_BYCOMMAND | MF_CHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOWCOMBATNODES, MF_BYCOMMAND | MF_CHECKED); } Sys_UpdateWindows(W_XY | W_CAMERA); @@ -2348,10 +3009,10 @@ void CMainFrame::OnViewShowCombatNodes() { */ void CMainFrame::OnViewShowwater() { if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_DYNAMICS) & EXCLUDE_DYNAMICS) { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOWWATER, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOWWATER, MF_BYCOMMAND | MF_UNCHECKED); } else { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOWWATER, MF_BYCOMMAND | MF_CHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOWWATER, MF_BYCOMMAND | MF_CHECKED); } Sys_UpdateWindows(W_XY | W_CAMERA); @@ -2363,10 +3024,10 @@ void CMainFrame::OnViewShowwater() { */ void CMainFrame::OnViewShowworld() { if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_WORLD) & EXCLUDE_WORLD) { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOWWORLD, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOWWORLD, MF_BYCOMMAND | MF_UNCHECKED); } else { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOWWORLD, MF_BYCOMMAND | MF_CHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOWWORLD, MF_BYCOMMAND | MF_CHECKED); } Sys_UpdateWindows(W_XY | W_CAMERA); @@ -3788,6 +4449,7 @@ void CMainFrame::OnTogglecamera() { } else { m_pCamWnd->ShowWindow(SW_SHOW); } + RecalcMainLayout(); } @@ -3796,12 +4458,14 @@ void CMainFrame::OnTogglecamera() { ======================================================================================================================= */ void CMainFrame::OnToggleview() { - if (m_pXYWnd && m_pXYWnd->GetSafeHwnd()) { - if (m_pXYWnd->IsWindowVisible()) { - m_pXYWnd->ShowWindow(SW_HIDE); + CWnd *pViewWnd = (m_pXYDockWnd && m_pXYDockWnd->GetSafeHwnd()) ? static_cast(m_pXYDockWnd) : static_cast(m_pXYWnd); + if (pViewWnd && pViewWnd->GetSafeHwnd()) { + if (pViewWnd->IsWindowVisible()) { + pViewWnd->ShowWindow(SW_HIDE); } else { - m_pXYWnd->ShowWindow(SW_SHOW); + pViewWnd->ShowWindow(SW_SHOW); } + RecalcMainLayout(); } } @@ -3816,6 +4480,8 @@ void CMainFrame::OnTogglez() { } else { m_pZWnd->ShowWindow(SW_SHOW); } + RecalcXYDockLayout(); + Sys_UpdateWindows(W_XY | W_Z); } } @@ -4080,12 +4746,17 @@ void CMainFrame::OnToggleviewYz() { void CMainFrame::OnToggleToolbar() { - ShowControlBar(&m_wndToolBar, !m_wndToolBar.IsWindowVisible(), false); + BOOL bShow = !m_wndToolBar.IsWindowVisible(); + if (m_pXYDockWnd && m_pXYDockWnd->GetSafeHwnd()) { + m_pXYDockWnd->ShowEmbeddedToolBar(bShow); + } else { + m_wndToolBar.ShowWindow(bShow ? SW_SHOW : SW_HIDE); + } } void CMainFrame::OnToggleTextureBar() { - ShowControlBar(&m_wndTextureBar, !m_wndTextureBar.IsWindowVisible(), false); + //ShowControlBar(&m_wndTextureBar, !m_wndTextureBar.IsWindowVisible(), false); } @@ -4598,7 +5269,7 @@ void CMainFrame::OnSelectionTextureShiftup() { ======================================================================================================================= */ void CMainFrame::SetGridChecks(int id) { - HMENU hMenu = ::GetMenu(GetSafeHwnd()); + HMENU hMenu = RadiantMainMenuHandle(); CheckMenuItem(hMenu, ID_GRID_1, MF_BYCOMMAND | MF_UNCHECKED); CheckMenuItem(hMenu, ID_GRID_2, MF_BYCOMMAND | MF_UNCHECKED); CheckMenuItem(hMenu, ID_GRID_4, MF_BYCOMMAND | MF_UNCHECKED); @@ -4930,9 +5601,7 @@ void CMainFrame::OnSelectionPrint() { ======================================================================================================================= */ void CMainFrame::UpdateTextureBar() { - if (m_wndTextureBar.GetSafeHwnd()) { - m_wndTextureBar.GetSurfaceAttributes(); - } + } bool g_bTABDown = false; @@ -5106,10 +5775,10 @@ void CMainFrame::OnFileExportmap() { */ void CMainFrame::OnViewShowcurves() { if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_CURVES) & EXCLUDE_CURVES) { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOWCURVES, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOWCURVES, MF_BYCOMMAND | MF_UNCHECKED); } else { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOWCURVES, MF_BYCOMMAND | MF_CHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOWCURVES, MF_BYCOMMAND | MF_CHECKED); } Sys_UpdateWindows(W_XY | W_CAMERA); @@ -5234,6 +5903,25 @@ void CMainFrame::NudgeSelection(int nDirection, float fAmount) { ======================================================================================================================= */ BOOL CMainFrame::PreTranslateMessage(MSG *pMsg) { + if (pMsg && m_pXYDockWnd && m_pXYDockWnd->GetSafeHwnd()) { + BOOL menuKey = FALSE; + + if (pMsg->message == WM_SYSKEYDOWN) { + menuKey = TRUE; + } else if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_F10) { + menuKey = TRUE; + } + + if (menuKey) { + UINT nChar = static_cast(pMsg->wParam); + if (nChar != VK_LEFT && nChar != VK_RIGHT && nChar != VK_UP && nChar != VK_DOWN) { + if (m_pXYDockWnd->TrackMenuMnemonic(nChar)) { + return TRUE; + } + } + } + } + return CFrameWnd::PreTranslateMessage(pMsg); } @@ -6011,10 +6699,10 @@ void CMainFrame::OnViewEntitiesasWireframe() { */ void CMainFrame::OnViewShowhint() { if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_HINT) & EXCLUDE_HINT) { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOWHINT, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOWHINT, MF_BYCOMMAND | MF_UNCHECKED); } else { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOWHINT, MF_BYCOMMAND | MF_CHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOWHINT, MF_BYCOMMAND | MF_CHECKED); } Sys_UpdateWindows(W_XY | W_CAMERA); @@ -6049,7 +6737,7 @@ void CMainFrame::OnViewOpengllighting() { g_PrefsDlg.SavePrefs(); CheckMenuItem ( - ::GetMenu(GetSafeHwnd()), + RadiantMainMenuHandle(), ID_VIEW_OPENGLLIGHTING, MF_BYCOMMAND | (g_PrefsDlg.m_bGLLighting) ? MF_CHECKED : MF_UNCHECKED ); @@ -6070,10 +6758,10 @@ void CMainFrame::OnSelectAll() { */ void CMainFrame::OnViewShowcaulk() { if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_CAULK) & EXCLUDE_CAULK) { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOWCAULK, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOWCAULK, MF_BYCOMMAND | MF_UNCHECKED); } else { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOWCAULK, MF_BYCOMMAND | MF_CHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOWCAULK, MF_BYCOMMAND | MF_CHECKED); } Sys_UpdateWindows(W_XY | W_CAMERA); @@ -6117,10 +6805,10 @@ void CMainFrame::OnSelectReselect() { */ void CMainFrame::OnViewShowangles() { if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_ANGLES) & EXCLUDE_ANGLES) { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOWANGLES, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOWANGLES, MF_BYCOMMAND | MF_UNCHECKED); } else { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOWANGLES, MF_BYCOMMAND | MF_CHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOWANGLES, MF_BYCOMMAND | MF_CHECKED); } Sys_UpdateWindows(W_XY | W_CAMERA); @@ -6255,7 +6943,7 @@ void CMainFrame::OnViewHideshowShowhidden() { void CMainFrame::OnTexturesShadersShow() { // // g_PrefsDlg.m_bShowShaders ^= 1; CheckMenuItem ( - // ::GetMenu(GetSafeHwnd()), ID_TEXTURES_SHADERS_SHOW, MF_BYCOMMAND | + // RadiantMainMenuHandle(), ID_TEXTURES_SHADERS_SHOW, MF_BYCOMMAND | // ((g_PrefsDlg.m_bShowShaders) ? MF_CHECKED : MF_UNCHECKED )); // Sys_UpdateWindows(W_TEXTURE); // @@ -6588,7 +7276,7 @@ void CMainFrame::OnShowDoom() void CMainFrame::OnViewRendermode() { m_pCamWnd->ToggleRenderMode(); - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_RENDERMODE, MF_BYCOMMAND | (m_pCamWnd->GetRenderMode()) ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_RENDERMODE, MF_BYCOMMAND | (m_pCamWnd->GetRenderMode()) ? MF_CHECKED : MF_UNCHECKED); Sys_UpdateWindows(W_ALL); } @@ -6604,21 +7292,21 @@ void CMainFrame::OnViewRebuildrenderdata() void CMainFrame::OnViewRealtimerebuild() { m_pCamWnd->ToggleRebuildMode(); - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_REALTIMEREBUILD, MF_BYCOMMAND | (m_pCamWnd->GetRebuildMode()) ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_REALTIMEREBUILD, MF_BYCOMMAND | (m_pCamWnd->GetRebuildMode()) ? MF_CHECKED : MF_UNCHECKED); Sys_UpdateWindows(W_ALL); } void CMainFrame::OnViewRenderentityoutlines() { m_pCamWnd->ToggleEntityMode(); - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_RENDERENTITYOUTLINES, MF_BYCOMMAND | (m_pCamWnd->GetEntityMode()) ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_RENDERENTITYOUTLINES, MF_BYCOMMAND | (m_pCamWnd->GetEntityMode()) ? MF_CHECKED : MF_UNCHECKED); Sys_UpdateWindows(W_ALL); } void CMainFrame::OnViewMaterialanimation() { m_pCamWnd->ToggleAnimationMode(); - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_MATERIALANIMATION, MF_BYCOMMAND | (m_pCamWnd->GetAnimationMode()) ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_MATERIALANIMATION, MF_BYCOMMAND | (m_pCamWnd->GetAnimationMode()) ? MF_CHECKED : MF_UNCHECKED); Sys_UpdateWindows(W_ALL); } @@ -6695,7 +7383,7 @@ void CMainFrame::OnSelectionVisibleOff() { void CMainFrame::OnViewRenderselection() { m_pCamWnd->ToggleSelectMode(); - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_RENDERSELECTION, MF_BYCOMMAND | (m_pCamWnd->GetSelectMode()) ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_RENDERSELECTION, MF_BYCOMMAND | (m_pCamWnd->GetSelectMode()) ? MF_CHECKED : MF_UNCHECKED); Sys_UpdateWindows(W_CAMERA); } @@ -6708,10 +7396,10 @@ void CMainFrame::OnSelectNomodels() void CMainFrame::OnViewShowShowvisportals() { if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_VISPORTALS) & EXCLUDE_VISPORTALS) { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOW_SHOWVISPORTALS, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOW_SHOWVISPORTALS, MF_BYCOMMAND | MF_UNCHECKED); } else { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOW_SHOWVISPORTALS, MF_BYCOMMAND | MF_CHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOW_SHOWVISPORTALS, MF_BYCOMMAND | MF_CHECKED); } Sys_UpdateWindows(W_XY | W_CAMERA); @@ -6720,10 +7408,10 @@ void CMainFrame::OnViewShowShowvisportals() void CMainFrame::OnViewShowNoDraw() { if ((g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_NODRAW) & EXCLUDE_NODRAW) { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOW_NODRAW, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOW_NODRAW, MF_BYCOMMAND | MF_UNCHECKED); } else { - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_SHOW_NODRAW, MF_BYCOMMAND | MF_CHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_SHOW_NODRAW, MF_BYCOMMAND | MF_CHECKED); } Sys_UpdateWindows(W_XY | W_CAMERA); @@ -6734,7 +7422,7 @@ void CMainFrame::OnViewShowNoDraw() void CMainFrame::OnViewRendersound() { m_pCamWnd->ToggleSoundMode(); - CheckMenuItem(::GetMenu(GetSafeHwnd()), ID_VIEW_RENDERSOUND, MF_BYCOMMAND | (m_pCamWnd->GetSoundMode()) ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(RadiantMainMenuHandle(), ID_VIEW_RENDERSOUND, MF_BYCOMMAND | (m_pCamWnd->GetSoundMode()) ? MF_CHECKED : MF_UNCHECKED); Sys_UpdateWindows(W_CAMERA); } diff --git a/neo/tools/radiant/MainFrm.h b/neo/tools/radiant/MainFrm.h index 7b25bf3e..18738839 100644 --- a/neo/tools/radiant/MainFrm.h +++ b/neo/tools/radiant/MainFrm.h @@ -60,6 +60,111 @@ struct SKeyInfo }; +//============================================================================= +// CMainFrameLeftPaneWnd +// +// Left workspace stack: +// [ Camera ] +// [ splitter ] +// [ Inspector] +// +// The first layout pass uses a percentage instead of loading child window +// placement from radiant.ini / the registry. Dragging the splitter updates the +// percentage so the split remains proportional when the frame is resized. +//============================================================================= +class CMainFrameLeftPaneWnd : public CWnd +{ + DECLARE_DYNAMIC(CMainFrameLeftPaneWnd) +public: + CMainFrameLeftPaneWnd(); + virtual ~CMainFrameLeftPaneWnd(); + + BOOL Create(CWnd *pParent, UINT nID); + void SetEmbeddedWindows(CWnd *pCameraWnd, CWnd *pInspectorWnd); + void LayoutChildren(); + void RecalcLayout(); + +protected: + CWnd *m_pCameraWnd; + CWnd *m_pInspectorWnd; + int m_nCameraPercent; + int m_nCameraHeight; + int m_nSplitterHeight; + bool m_bInLayout; + bool m_bTrackingSplitter; + int m_nDragStartY; + int m_nDragStartCameraHeight; + CRect m_rcSplitter; + + void AttachChild(CWnd *pWnd); + bool IsWindowUsable(CWnd *pWnd) const; + int ClampCameraHeight(int cameraHeight, const CRect &client) const; + bool HitTestSplitter(const CPoint &point) const; + void DrawSplitter(CDC *pDC); + + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnPaint(); + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg BOOL OnSetCursor(CWnd *pWnd, UINT nHitTest, UINT message); + afx_msg BOOL OnEraseBkgnd(CDC *pDC); + + DECLARE_MESSAGE_MAP() +}; + +//============================================================================= +// CMainFrameLayoutWnd +// +// Main workspace split: +// [ Camera/Inspector stack ] [ splitter ] [ XYDock: menu, toolbar, Z | XY ] +// +// XYDock already owns the Z/XY splitter. This wrapper supplies the missing +// MainFrm-level split and gives startup proportions like the reference image. +//============================================================================= +class CMainFrameLayoutWnd : public CWnd +{ + DECLARE_DYNAMIC(CMainFrameLayoutWnd) +public: + CMainFrameLayoutWnd(); + virtual ~CMainFrameLayoutWnd(); + + BOOL Create(CWnd *pParent, UINT nID = AFX_IDW_PANE_FIRST); + void SetEmbeddedWindows(CWnd *pCameraWnd, CWnd *pInspectorWnd, CWnd *pXYDockWnd); + CWnd *GetLeftPaneWnd(); + void LayoutChildren(); + void RecalcLayout(); + +protected: + CMainFrameLeftPaneWnd m_wndLeftPane; + CWnd *m_pXYDockWnd; + int m_nLeftPercent; + int m_nLeftWidth; + int m_nSplitterWidth; + bool m_bInLayout; + bool m_bTrackingSplitter; + int m_nDragStartX; + int m_nDragStartLeftWidth; + CRect m_rcSplitter; + + void AttachChild(CWnd *pWnd); + bool IsWindowUsable(CWnd *pWnd) const; + int ClampLeftWidth(int leftWidth, const CRect &client) const; + bool HitTestSplitter(const CPoint &point) const; + void DrawSplitter(CDC *pDC); + + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnPaint(); + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg BOOL OnSetCursor(CWnd *pWnd, UINT nHitTest, UINT message); + afx_msg BOOL OnEraseBkgnd(CDC *pDC); + + DECLARE_MESSAGE_MAP() +}; + + class CMainFrame : public CFrameWnd @@ -122,6 +227,10 @@ public: CXYWnd* GetYZWnd() {return m_pYZWnd;}; CCamWnd* GetCamera() {return m_pCamWnd;}; CZWnd* GetZWnd() {return m_pZWnd;}; + CXYDockWnd* GetXYDockWnd() { return m_pXYDockWnd; }; + CMenu* GetMenu() const; + void RecalcMainLayout(); + void RecalcXYDockLayout(); void SetActiveXY(CXYWnd* p) { @@ -142,7 +251,8 @@ public: protected: // control bar embedded members CStatusBar m_wndStatusBar; CToolBar m_wndToolBar; - CTextureBar m_wndTextureBar; + //CTextureBar m_wndTextureBar; + CMainFrameLayoutWnd m_wndMainLayout; CSplitterWnd m_wndSplit; CSplitterWnd m_wndSplit2; CSplitterWnd m_wndSplit3; @@ -151,6 +261,8 @@ protected: // control bar embedded members CXYWnd* m_pXZWnd; CCamWnd* m_pCamWnd; CZWnd* m_pZWnd; + CXYDockWnd* m_pXYDockWnd; + HMENU m_hMovedMenu; CString m_strStatus[15]; CXYWnd* m_pActiveXY; bool m_bCamPreview; @@ -161,6 +273,8 @@ protected: // control bar embedded members protected: bool m_bDoLoop; void CreateQEChildren(); + BOOL CreateEmbeddedMainToolBar(UINT nID); + void MoveFrameMenuIntoXYWnd(); void LoadCommandMap(); void SaveCommandMap(); void ShowMenuItemKeyBindings(CMenu *pMenu); diff --git a/neo/tools/radiant/SurfaceDlg.cpp b/neo/tools/radiant/SurfaceDlg.cpp index 20f1d33f..5558898d 100644 --- a/neo/tools/radiant/SurfaceDlg.cpp +++ b/neo/tools/radiant/SurfaceDlg.cpp @@ -163,22 +163,36 @@ 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(); + + patchMesh_t* p = SinglePatchSelected(); if (p) { m_subdivide = p->explicitSubdivisions; - m_strMaterial = p->d_texture->GetName(); - } else { - m_subdivide = false; + + 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; + face_t* selFace = NULL; + if (faceCount) { - selFace = reinterpret_cast < face_t * > (g_ptrSelectedFaces.GetAt(0)); - } else { + selFace = reinterpret_cast(g_ptrSelectedFaces.GetAt(0)); + } + else { if (selected_brushes.next != &selected_brushes) { - brush_t *b = selected_brushes.next; + brush_t* b = selected_brushes.next; if (!b->pPatch) { selFace = b->brush_faces; } @@ -186,9 +200,18 @@ void CSurfaceDlg::SetTexMods() { } 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 { + Face_GetScale_BrushPrimit(selFace, &m_horzScale, &m_vertScale, &rot); + } + else { m_horzScale = 1.0f; m_vertScale = 1.0f; } diff --git a/neo/tools/radiant/XYWnd.cpp b/neo/tools/radiant/XYWnd.cpp index 8646c0a7..c69cbebf 100644 --- a/neo/tools/radiant/XYWnd.cpp +++ b/neo/tools/radiant/XYWnd.cpp @@ -32,11 +32,16 @@ If you have questions concerning this license or the applicable additional terms #include "qe3.h" #include "Radiant.h" #include "XYWnd.h" +#include "ZWnd.h" #include "DialogInfo.h" #include "splines.h" #include "../../renderer/tr_local.h" #include "../../renderer/model_local.h" // for idRenderModelLiquid +#ifndef WM_IDLEUPDATECMDUI +#define WM_IDLEUPDATECMDUI 0x0363 +#endif + #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE @@ -110,6 +115,926 @@ CMemFile g_PatchClipboard(4096); extern int pressx; extern int pressy; +//============================================================================= +// CXYMenuBar +//============================================================================= +IMPLEMENT_DYNAMIC(CXYMenuBar, CWnd) + +BEGIN_MESSAGE_MAP(CXYMenuBar, CWnd) + ON_WM_PAINT() + ON_WM_LBUTTONDOWN() + ON_WM_MOUSEMOVE() + ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + +CXYMenuBar::CXYMenuBar() { + m_nItemRects = 0; + m_nHotItem = -1; +} + +CXYMenuBar::~CXYMenuBar() { + if (m_menu.GetSafeHmenu()) { + m_menu.DestroyMenu(); + } +} + +BOOL CXYMenuBar::Create(CWnd *pParent, UINT nID) { + CString className = AfxRegisterWndClass( + CS_HREDRAW | CS_VREDRAW, + ::LoadCursor(NULL, IDC_ARROW), + (HBRUSH)(COLOR_MENU + 1), + NULL + ); + return CWnd::CreateEx( + 0, + className, + "RadiantEmbeddedMenuBar", + WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, + CRect(0, 0, 0, 0), + pParent, + nID + ); +} + +BOOL CXYMenuBar::AttachMenu(HMENU hMenu) { + if (!hMenu) { + return FALSE; + } + if (m_menu.GetSafeHmenu()) { + m_menu.DestroyMenu(); + } + m_menu.Attach(hMenu); + Invalidate(FALSE); + return TRUE; +} + +BOOL CXYMenuBar::LoadMenu(UINT nID) { + if (m_menu.GetSafeHmenu()) { + m_menu.DestroyMenu(); + } + BOOL result = m_menu.LoadMenu(nID); + Invalidate(FALSE); + return result; +} + +CMenu *CXYMenuBar::GetMenu() { + return m_menu.GetSafeHmenu() ? &m_menu : NULL; +} + +HMENU CXYMenuBar::GetMenuHandle() const { + return m_menu.GetSafeHmenu(); +} + +int CXYMenuBar::PreferredHeight() const { + int h = ::GetSystemMetrics(SM_CYMENU) + 4; + return (h < 22) ? 22 : h; +} + +void CXYMenuBar::RebuildItemRects(CDC &dc) { + m_nItemRects = 0; + + if (!m_menu.GetSafeHmenu()) { + return; + } + + int x = 4; + const int y = 1; + const int h = PreferredHeight() - 2; + const int count = m_menu.GetMenuItemCount(); + + for (int i = 0; i < count; i++) { + CString text; + m_menu.GetMenuString(i, text, MF_BYPOSITION); + if (m_nItemRects >= 64) { + break; + } + + if (text.IsEmpty()) { + m_itemRects[m_nItemRects++] = CRect(x, y, x + 8, y + h); + x += 8; + continue; + } + + CSize size = dc.GetTextExtent(text); + CRect rect(x, y, x + size.cx + 20, y + h); + m_itemRects[m_nItemRects++] = rect; + x = rect.right + 1; + } +} + +int CXYMenuBar::HitTest(const CPoint &point) const { + for (int i = 0; i < m_nItemRects; i++) { + if (m_itemRects[i].PtInRect(point)) { + return i; + } + } + return -1; +} + +void CXYMenuBar::TrackTopLevelMenu(int nIndex) { + if (!m_menu.GetSafeHmenu() || nIndex < 0 || nIndex >= m_menu.GetMenuItemCount()) { + return; + } + + CMenu *subMenu = m_menu.GetSubMenu(nIndex); + if (!subMenu || !subMenu->GetSafeHmenu()) { + return; + } + + CRect rect; + if (nIndex < m_nItemRects) { + rect = m_itemRects[nIndex]; + } else { + GetClientRect(rect); + } + + CPoint pt(rect.left, rect.bottom); + ClientToScreen(&pt); + + m_nHotItem = nIndex; + Invalidate(FALSE); + UpdateWindow(); + + CWnd *commandTarget = GetCommandTarget(); + CWnd *popupOwner = (commandTarget && commandTarget->GetSafeHwnd()) ? commandTarget : static_cast(this); + + if (popupOwner && popupOwner->GetSafeHwnd()) { + CWnd *topLevelOwner = popupOwner->GetTopLevelParent(); + if (topLevelOwner && topLevelOwner->GetSafeHwnd()) { + topLevelOwner->SetForegroundWindow(); + } else { + popupOwner->SetForegroundWindow(); + } + } + + // The popup owner must be the frame, not this embedded menu-bar window. + // That keeps WM_INITMENUPOPUP, WM_MENUSELECT, command routing, MRU updates, + // and ON_UPDATE_COMMAND_UI handling in CMainFrame where the old menu used them. + UINT command = subMenu->TrackPopupMenu( + TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RETURNCMD, + pt.x, + pt.y, + popupOwner + ); + + if (command != 0 && commandTarget && commandTarget->GetSafeHwnd()) { + commandTarget->SendMessage(WM_COMMAND, MAKEWPARAM(command, 0), 0); + } + + m_nHotItem = -1; + Invalidate(FALSE); + if (popupOwner && popupOwner->GetSafeHwnd()) { + popupOwner->PostMessage(WM_NULL, 0, 0); + } else { + PostMessage(WM_NULL, 0, 0); + } +} + +CWnd *CXYMenuBar::GetCommandTarget() const { + CWnd *commandTarget = AfxGetMainWnd(); + if (commandTarget && commandTarget->GetSafeHwnd() && commandTarget != this) { + return commandTarget; + } + + for (CWnd *parent = GetParent(); parent && parent->GetSafeHwnd(); parent = parent->GetParent()) { + if (parent != this && parent->IsKindOf(RUNTIME_CLASS(CFrameWnd))) { + return parent; + } + } + + return NULL; +} + +static int XYMenuBarUpper(int ch) { + if (ch >= 'a' && ch <= 'z') { + return ch - 'a' + 'A'; + } + return ch; +} + +BOOL CXYMenuBar::TrackMnemonic(UINT nChar) { + if (!m_menu.GetSafeHmenu()) { + return FALSE; + } + + if (nChar == VK_F10) { + TrackTopLevelMenu(0); + return TRUE; + } + + if (nChar > 255) { + return FALSE; + } + + const int wanted = XYMenuBarUpper(static_cast(nChar)); + const int count = m_menu.GetMenuItemCount(); + for (int i = 0; i < count; i++) { + CString text; + m_menu.GetMenuString(i, text, MF_BYPOSITION); + const int len = text.GetLength(); + for (int j = 0; j < len; j++) { + if (text[j] != '&') { + continue; + } + if (j + 1 >= len) { + break; + } + if (text[j + 1] == '&') { + j++; + continue; + } + if (XYMenuBarUpper(static_cast(text[j + 1])) == wanted) { + TrackTopLevelMenu(i); + return TRUE; + } + } + } + + return FALSE; +} + +void CXYMenuBar::OnPaint() { + CPaintDC dc(this); + CRect client; + GetClientRect(client); + + CBrush backBrush(::GetSysColor(COLOR_MENU)); + dc.FillRect(client, &backBrush); + + RebuildItemRects(dc); + + if (m_menu.GetSafeHmenu()) { + const int count = m_menu.GetMenuItemCount(); + for (int i = 0; i < count && i < m_nItemRects; i++) { + CString text; + m_menu.GetMenuString(i, text, MF_BYPOSITION); + CRect itemRect = m_itemRects[i]; + + if (i == m_nHotItem) { + dc.Draw3dRect(itemRect, ::GetSysColor(COLOR_3DHILIGHT), ::GetSysColor(COLOR_3DSHADOW)); + itemRect.DeflateRect(1, 1); + } + + dc.SetBkMode(TRANSPARENT); + dc.SetTextColor(::GetSysColor(COLOR_MENUTEXT)); + dc.DrawText(text, itemRect, DT_SINGLELINE | DT_VCENTER | DT_CENTER); + } + } + + CPen shadowPen(PS_SOLID, 1, ::GetSysColor(COLOR_3DSHADOW)); + CPen *oldPen = dc.SelectObject(&shadowPen); + dc.MoveTo(client.left, client.bottom - 1); + dc.LineTo(client.right, client.bottom - 1); + dc.SelectObject(oldPen); +} + +void CXYMenuBar::OnLButtonDown(UINT nFlags, CPoint point) { + CClientDC dc(this); + RebuildItemRects(dc); + TrackTopLevelMenu(HitTest(point)); +} + +void CXYMenuBar::OnMouseMove(UINT nFlags, CPoint point) { + CClientDC dc(this); + RebuildItemRects(dc); + int hotItem = HitTest(point); + if (hotItem != m_nHotItem) { + m_nHotItem = hotItem; + Invalidate(FALSE); + } + CWnd::OnMouseMove(nFlags, point); +} + +BOOL CXYMenuBar::OnEraseBkgnd(CDC *pDC) { + return TRUE; +} + +BOOL CXYMenuBar::OnCommand(WPARAM wParam, LPARAM lParam) { + CWnd *commandTarget = GetCommandTarget(); + if (commandTarget && commandTarget->GetSafeHwnd() && commandTarget != this) { + return static_cast(commandTarget->SendMessage(WM_COMMAND, wParam, lParam)); + } + return CWnd::OnCommand(wParam, lParam); +} + +BOOL CXYMenuBar::OnCmdMsg(UINT nID, int nCode, void *pExtra, AFX_CMDHANDLERINFO *pHandlerInfo) { + if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) { + return TRUE; + } + + CWnd *commandTarget = GetCommandTarget(); + if (commandTarget && commandTarget->GetSafeHwnd() && commandTarget != this) { + return commandTarget->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); + } + + return FALSE; +} + +//============================================================================= +// CXYMDIContainerWnd +//============================================================================= +IMPLEMENT_DYNAMIC(CXYMDIContainerWnd, CWnd) + +BEGIN_MESSAGE_MAP(CXYMDIContainerWnd, CWnd) + ON_WM_SIZE() + ON_WM_PAINT() + ON_WM_LBUTTONDOWN() + ON_WM_LBUTTONUP() + ON_WM_MOUSEMOVE() + ON_WM_SETCURSOR() + ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + +CXYMDIContainerWnd::CXYMDIContainerWnd() { + m_pXYWnd = NULL; + m_pZWnd = NULL; + m_nZDockPercent = 5; + m_nZWidth = 0; + m_nSplitterWidth = 5; + m_bZStartupSized = false; + m_bInLayout = false; + m_bTrackingSplitter = false; + m_nDragStartX = 0; + m_nDragStartZWidth = 0; + m_rcSplitter.SetRectEmpty(); +} + +CXYMDIContainerWnd::~CXYMDIContainerWnd() { +} + +BOOL CXYMDIContainerWnd::Create(CWnd *pParent, UINT nID) { + CLIENTCREATESTRUCT clientCreate; + memset(&clientCreate, 0, sizeof(clientCreate)); + clientCreate.hWindowMenu = NULL; + clientCreate.idFirstChild = 0x7B00; + + return CWnd::CreateEx( + 0, + "MDICLIENT", + "RadiantXYMDIContainer", + WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, + CRect(0, 0, 0, 0), + pParent, + nID, + &clientCreate + ); +} + +void CXYMDIContainerWnd::AttachChild(CWnd *pWnd) { + if (!pWnd || !pWnd->GetSafeHwnd() || !GetSafeHwnd()) { + return; + } + + if (::GetParent(pWnd->GetSafeHwnd()) != GetSafeHwnd()) { + pWnd->SetParent(this); + } + + LONG style = ::GetWindowLong(pWnd->GetSafeHwnd(), GWL_STYLE); + style &= ~(WS_POPUP | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX); + style |= WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; + ::SetWindowLong(pWnd->GetSafeHwnd(), GWL_STYLE, style); + ::SetWindowPos( + pWnd->GetSafeHwnd(), + NULL, + 0, + 0, + 0, + 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED + ); +} + +void CXYMDIContainerWnd::SetChildWindows(CXYWnd *pXYWnd, CZWnd *pZWnd) { + m_pXYWnd = pXYWnd; + m_pZWnd = pZWnd; + AttachChild(m_pZWnd); + AttachChild(m_pXYWnd); + LayoutChildren(); +} + +void CXYMDIContainerWnd::SetEmbeddedWindows(CWnd *pZWnd, CWnd *pXYWnd) { + m_pZWnd = pZWnd; + m_pXYWnd = pXYWnd; + AttachChild(m_pZWnd); + AttachChild(m_pXYWnd); + LayoutChildren(); +} + +bool CXYMDIContainerWnd::IsZVisible() const { + return m_pZWnd && m_pZWnd->GetSafeHwnd() && m_pZWnd->IsWindowVisible(); +} + +int CXYMDIContainerWnd::ClampZWidth(int zWidth, const CRect &client) const { + const int width = client.Width(); + if (width <= m_nSplitterWidth + 1) { + return 0; + } + + const int minZ = 1; + const int minXY = 64; + const int available = width - m_nSplitterWidth; + int maxZ = available - minXY; + if (maxZ < minZ) { + maxZ = available - 1; + } + if (maxZ < minZ) { + return 0; + } + + if (zWidth < minZ) { + zWidth = minZ; + } + if (zWidth > maxZ) { + zWidth = maxZ; + } + return zWidth; +} + +int CXYMDIContainerWnd::ComputeInitialZWidth(const CRect &client) const { + const int width = client.Width(); + if (width <= 1) { + return 0; + } + + int zWidth = (width * m_nZDockPercent) / 100; + if (zWidth < 1) { + zWidth = 1; + } + return ClampZWidth(zWidth, client); +} + +void CXYMDIContainerWnd::SetZDockPercent(int percent) { + // Keep legacy MainFrm calls such as SetZDockPercent(20) from changing the + // required startup size. The embedded Z pane starts at 5%, then the user can + // drag the splitter to any practical width. + m_nZDockPercent = 5; + + if (!m_bZStartupSized) { + LayoutChildren(); + } +} + +int CXYMDIContainerWnd::GetZDockPercent() const { + return m_nZDockPercent; +} + +int CXYMDIContainerWnd::GetZWidth() const { + return m_nZWidth; +} + +int CXYMDIContainerWnd::GetFixedZWidth() const { + return GetZWidth(); +} + +bool CXYMDIContainerWnd::HitTestSplitter(const CPoint &point) const { + return !m_rcSplitter.IsRectEmpty() && m_rcSplitter.PtInRect(point); +} + +void CXYMDIContainerWnd::DrawSplitter(CDC *pDC) { + if (!pDC || m_rcSplitter.IsRectEmpty()) { + return; + } + + CRect rc = m_rcSplitter; + CBrush brush(::GetSysColor(COLOR_BTNFACE)); + pDC->FillRect(rc, &brush); + pDC->Draw3dRect(rc, ::GetSysColor(COLOR_3DHILIGHT), ::GetSysColor(COLOR_3DSHADOW)); + + int x = rc.left + rc.Width() / 2; + CPen pen(PS_SOLID, 1, ::GetSysColor(COLOR_3DSHADOW)); + CPen *oldPen = pDC->SelectObject(&pen); + pDC->MoveTo(x, rc.top + 3); + pDC->LineTo(x, rc.bottom - 3); + pDC->SelectObject(oldPen); +} + +void CXYMDIContainerWnd::LayoutChildren() { + if (!GetSafeHwnd() || m_bInLayout) { + return; + } + + m_bInLayout = true; + + CRect client; + GetClientRect(client); + + if (client.Width() < 1 || client.Height() < 1) { + m_rcSplitter.SetRectEmpty(); + m_bInLayout = false; + return; + } + + bool zVisible = IsZVisible(); + int zWidth = 0; + int splitterWidth = 0; + + if (zVisible) { + if (!m_bZStartupSized) { + m_nZWidth = ComputeInitialZWidth(client); + m_bZStartupSized = true; + } + + zWidth = ClampZWidth(m_nZWidth, client); + m_nZWidth = zWidth; + if (zWidth > 0 && client.Width() > zWidth + m_nSplitterWidth) { + splitterWidth = m_nSplitterWidth; + } + } + + if (m_pZWnd && m_pZWnd->GetSafeHwnd()) { + if (zVisible && zWidth > 0) { + m_pZWnd->MoveWindow(client.left, client.top, zWidth, client.Height(), TRUE); + m_pZWnd->Invalidate(FALSE); + } + } + + if (zVisible && zWidth > 0 && splitterWidth > 0) { + m_rcSplitter.SetRect(client.left + zWidth, client.top, client.left + zWidth + splitterWidth, client.bottom); + } else { + m_rcSplitter.SetRectEmpty(); + } + + if (m_pXYWnd && m_pXYWnd->GetSafeHwnd()) { + int xyLeft = client.left + zWidth + splitterWidth; + if (xyLeft > client.right - 1) { + xyLeft = client.left; + } + CRect xyRect(xyLeft, client.top, client.right, client.bottom); + m_pXYWnd->MoveWindow(xyRect, TRUE); + m_pXYWnd->Invalidate(FALSE); + } + + Invalidate(FALSE); + m_bInLayout = false; +} + +void CXYMDIContainerWnd::OnSize(UINT nType, int cx, int cy) { + CWnd::OnSize(nType, cx, cy); + LayoutChildren(); +} + +void CXYMDIContainerWnd::OnPaint() { + CPaintDC dc(this); + DrawSplitter(&dc); +} + +void CXYMDIContainerWnd::OnLButtonDown(UINT nFlags, CPoint point) { + if (HitTestSplitter(point)) { + m_bTrackingSplitter = true; + m_nDragStartX = point.x; + m_nDragStartZWidth = m_nZWidth; + SetCapture(); + ::SetCursor(::LoadCursor(NULL, IDC_SIZEWE)); + return; + } + + CWnd::OnLButtonDown(nFlags, point); +} + +void CXYMDIContainerWnd::OnLButtonUp(UINT nFlags, CPoint point) { + if (m_bTrackingSplitter) { + m_bTrackingSplitter = false; + if (GetCapture() == this) { + ReleaseCapture(); + } + LayoutChildren(); + return; + } + + CWnd::OnLButtonUp(nFlags, point); +} + +void CXYMDIContainerWnd::OnMouseMove(UINT nFlags, CPoint point) { + if (m_bTrackingSplitter) { + CRect client; + GetClientRect(client); + m_nZWidth = ClampZWidth(m_nDragStartZWidth + point.x - m_nDragStartX, client); + LayoutChildren(); + ::SetCursor(::LoadCursor(NULL, IDC_SIZEWE)); + return; + } + + if (HitTestSplitter(point)) { + ::SetCursor(::LoadCursor(NULL, IDC_SIZEWE)); + } + + CWnd::OnMouseMove(nFlags, point); +} + +BOOL CXYMDIContainerWnd::OnSetCursor(CWnd *pWnd, UINT nHitTest, UINT message) { + CPoint point; + GetCursorPos(&point); + ScreenToClient(&point); + if (m_bTrackingSplitter || HitTestSplitter(point)) { + ::SetCursor(::LoadCursor(NULL, IDC_SIZEWE)); + return TRUE; + } + return CWnd::OnSetCursor(pWnd, nHitTest, message); +} + +BOOL CXYMDIContainerWnd::OnEraseBkgnd(CDC *pDC) { + DrawSplitter(pDC); + return TRUE; +} + +BOOL CXYMDIContainerWnd::OnCommand(WPARAM wParam, LPARAM lParam) { + CWnd *commandTarget = AfxGetMainWnd(); + if (commandTarget && commandTarget->GetSafeHwnd() && commandTarget != this) { + return static_cast(commandTarget->SendMessage(WM_COMMAND, wParam, lParam)); + } + return CWnd::OnCommand(wParam, lParam); +} + +BOOL CXYMDIContainerWnd::OnCmdMsg(UINT nID, int nCode, void *pExtra, AFX_CMDHANDLERINFO *pHandlerInfo) { + if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) { + return TRUE; + } + CWnd *commandTarget = AfxGetMainWnd(); + if (commandTarget && commandTarget->GetSafeHwnd() && commandTarget != this) { + return commandTarget->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); + } + return FALSE; +} + +//============================================================================= +// CXYDockWnd +//============================================================================= +IMPLEMENT_DYNAMIC(CXYDockWnd, CWnd) + +BEGIN_MESSAGE_MAP(CXYDockWnd, CWnd) + ON_WM_CREATE() + ON_WM_SIZE() + ON_WM_ERASEBKGND() + ON_MESSAGE(WM_IDLEUPDATECMDUI, OnIdleUpdateCmdUI) +END_MESSAGE_MAP() + +CXYDockWnd::CXYDockWnd() { + m_pToolBar = NULL; + m_bInLayout = false; +} + +CXYDockWnd::~CXYDockWnd() { +} + +BOOL CXYDockWnd::Create(CWnd *pParent, UINT nID) { + CRect rect(0, 0, 0, 0); + return Create(rect, pParent, nID); +} + +BOOL CXYDockWnd::Create(const RECT &rect, CWnd *pParent, UINT nID) { + CString className = AfxRegisterWndClass( + CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, + ::LoadCursor(NULL, IDC_ARROW), + (HBRUSH)(COLOR_BTNFACE + 1), + NULL + ); + return CWnd::CreateEx( + 0, + className, + "RadiantXYDockWnd", + WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, + rect, + pParent, + nID + ); +} + +int CXYDockWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) { + if (CWnd::OnCreate(lpCreateStruct) == -1) { + return -1; + } + if (!m_wndMenuBar.Create(this, 0x7A01)) { + return -1; + } + if (!m_wndMDIContainer.Create(this, 0x7A02)) { + return -1; + } + return 0; +} + +void CXYDockWnd::SetChildWindows(CXYWnd *pXYWnd, CZWnd *pZWnd) { + m_wndMDIContainer.SetChildWindows(pXYWnd, pZWnd); + LayoutChildren(); +} + +void CXYDockWnd::SetEmbeddedWindows(CWnd *pZWnd, CWnd *pXYWnd) { + m_wndMDIContainer.SetEmbeddedWindows(pZWnd, pXYWnd); + LayoutChildren(); +} + +void CXYDockWnd::SetToolBar(CToolBar *pToolBar) { + m_pToolBar = pToolBar; + if (m_pToolBar && m_pToolBar->GetSafeHwnd()) { + CWnd *commandTarget = GetCommandTarget(); + if (!commandTarget || !commandTarget->GetSafeHwnd()) { + commandTarget = this; + } + + m_pToolBar->SetParent(this); + m_pToolBar->SetOwner(this); + m_pToolBar->SetDlgCtrlID(AFX_IDW_TOOLBAR); + m_pToolBar->ModifyStyle(WS_POPUP | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN); + } + LayoutChildren(); +} + +void CXYDockWnd::SetEmbeddedToolBar(CToolBar *pToolBar) { + SetToolBar(pToolBar); +} + +CWnd *CXYDockWnd::GetCommandTarget() const { + CWnd *commandTarget = AfxGetMainWnd(); + if (commandTarget && commandTarget->GetSafeHwnd() && commandTarget != this) { + return commandTarget; + } + + for (CWnd *parent = GetParent(); parent && parent->GetSafeHwnd(); parent = parent->GetParent()) { + if (parent != this && parent->IsKindOf(RUNTIME_CLASS(CFrameWnd))) { + return parent; + } + } + + return NULL; +} + +void CXYDockWnd::UpdateToolBarCmdUI(BOOL bDisableIfNoHndler) { + if (!m_pToolBar || !m_pToolBar->GetSafeHwnd() || !m_pToolBar->IsWindowVisible()) { + return; + } + + CWnd *commandTarget = GetCommandTarget(); + if (!commandTarget || !commandTarget->GetSafeHwnd()) { + return; + } + + if (commandTarget->IsKindOf(RUNTIME_CLASS(CFrameWnd))) { + m_pToolBar->OnUpdateCmdUI(static_cast(commandTarget), bDisableIfNoHndler); + } +} + +void CXYDockWnd::ShowEmbeddedToolBar(BOOL bShow) { + if (m_pToolBar && m_pToolBar->GetSafeHwnd()) { + m_pToolBar->ShowWindow(bShow ? SW_SHOW : SW_HIDE); + } + LayoutChildren(); +} + +BOOL CXYDockWnd::AttachMenu(HMENU hMenu) { + BOOL result = m_wndMenuBar.AttachMenu(hMenu); + LayoutChildren(); + return result; +} + +void CXYDockWnd::SetMenuHandle(HMENU hMenu) { + AttachMenu(hMenu); +} + +BOOL CXYDockWnd::LoadMenu(UINT nID) { + BOOL result = m_wndMenuBar.LoadMenu(nID); + LayoutChildren(); + return result; +} + +CMenu *CXYDockWnd::GetEmbeddedMenu() { + return m_wndMenuBar.GetMenu(); +} + +HMENU CXYDockWnd::GetEmbeddedMenuHandle() const { + return m_wndMenuBar.GetMenuHandle(); +} + +HMENU CXYDockWnd::GetMenuHandle() const { + return GetEmbeddedMenuHandle(); +} + +void CXYDockWnd::SetZDockPercent(int percent) { + m_wndMDIContainer.SetZDockPercent(percent); +} + +void CXYDockWnd::SetZPercent(int percent) { + SetZDockPercent(percent); +} + +int CXYDockWnd::GetZDockPercent() const { + return m_wndMDIContainer.GetZDockPercent(); +} + +int CXYDockWnd::GetZPercent() const { + return GetZDockPercent(); +} + +void CXYDockWnd::LayoutChildren() { + if (!GetSafeHwnd() || m_bInLayout) { + return; + } + + m_bInLayout = true; + + CRect client; + GetClientRect(client); + + int y = client.top; + const int width = client.Width(); + + if (m_wndMenuBar.GetSafeHwnd()) { + if (m_wndMenuBar.GetMenuHandle()) { + m_wndMenuBar.ShowWindow(SW_SHOW); + const int menuHeight = m_wndMenuBar.PreferredHeight(); + m_wndMenuBar.MoveWindow(client.left, y, width, menuHeight, TRUE); + y += menuHeight; + } else { + m_wndMenuBar.ShowWindow(SW_HIDE); + } + } + + if (m_pToolBar && m_pToolBar->GetSafeHwnd()) { + if (m_pToolBar->IsWindowVisible()) { + CSize toolbarSize = m_pToolBar->CalcFixedLayout(FALSE, TRUE); + int toolbarHeight = toolbarSize.cy; + if (toolbarHeight < 24) { + toolbarHeight = 24; + } + m_pToolBar->MoveWindow(client.left, y, width, toolbarHeight, TRUE); + y += toolbarHeight; + } + } + + CRect content(client.left, y, client.right, client.bottom); + if (content.Width() < 1 || content.Height() < 1) { + m_bInLayout = false; + return; + } + + if (m_wndMDIContainer.GetSafeHwnd()) { + m_wndMDIContainer.MoveWindow(content, TRUE); + m_wndMDIContainer.LayoutChildren(); + } + + m_bInLayout = false; +} + +void CXYDockWnd::RecalcLayout() { + LayoutChildren(); +} + +BOOL CXYDockWnd::TrackMenuMnemonic(UINT nChar) { + if (m_wndMenuBar.GetSafeHwnd()) { + return m_wndMenuBar.TrackMnemonic(nChar); + } + return FALSE; +} + +void CXYDockWnd::OnSize(UINT nType, int cx, int cy) { + CWnd::OnSize(nType, cx, cy); + LayoutChildren(); +} + +BOOL CXYDockWnd::OnEraseBkgnd(CDC *pDC) { + return TRUE; +} + +LRESULT CXYDockWnd::OnIdleUpdateCmdUI(WPARAM wParam, LPARAM lParam) { + UpdateToolBarCmdUI(static_cast(wParam)); + return 0L; +} + +BOOL CXYDockWnd::OnCommand(WPARAM wParam, LPARAM lParam) { + CWnd *commandTarget = GetCommandTarget(); + if (commandTarget && commandTarget->GetSafeHwnd() && commandTarget != this) { + return static_cast(commandTarget->SendMessage(WM_COMMAND, wParam, lParam)); + } + return CWnd::OnCommand(wParam, lParam); +} + +BOOL CXYDockWnd::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT *pResult) { + CWnd *commandTarget = GetCommandTarget(); + if (commandTarget && commandTarget->GetSafeHwnd() && commandTarget != this) { + LRESULT result = commandTarget->SendMessage(WM_NOTIFY, wParam, lParam); + if (pResult) { + *pResult = result; + } + if (result != 0) { + return TRUE; + } + } + + return CWnd::OnNotify(wParam, lParam, pResult); +} + +BOOL CXYDockWnd::OnCmdMsg(UINT nID, int nCode, void *pExtra, AFX_CMDHANDLERINFO *pHandlerInfo) { + if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) { + return TRUE; + } + + CWnd *commandTarget = GetCommandTarget(); + if (commandTarget && commandTarget->GetSafeHwnd() && commandTarget != this) { + return commandTarget->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); + } + + return FALSE; +} + + /* ======================================================================================================================= ======================================================================================================================= @@ -594,6 +1519,7 @@ BOOL CXYWnd::PreCreateWindow(CREATESTRUCT &cs) { if (cs.style != QE3_CHILDSTYLE) { cs.style = QE3_SPLITTER_STYLE; } + cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN; return CWnd::PreCreateWindow(cs); } @@ -2732,7 +3658,7 @@ bool CXYWnd::XY_MouseMoved(int x, int y, int buttons) { /* ======================================================================================================================= - DRAWING £ + DRAWING £ XY_DrawGrid ======================================================================================================================= */ @@ -3304,7 +4230,7 @@ bool FilterBrush(brush_t *pb) { /* ======================================================================================================================= - PATH LINES £ + PATH LINES £ DrawPathLines Draws connections between entities. Needs to consider all entities, not just ones on screen, because the lines can be visible when neither end is. Called for both camera view and xy view. ======================================================================================================================= @@ -3535,6 +4461,10 @@ extern void DrawBrushEntityName(brush_t *b); ======================================================================================================================= */ void CXYWnd::XY_Draw() { + if (m_nWidth <= 0 || m_nHeight <= 0) { + return; + } + brush_t *brush; float w, h; entity_t *e; diff --git a/neo/tools/radiant/XYWnd.h b/neo/tools/radiant/XYWnd.h index da9d51ef..71c4ac7d 100644 --- a/neo/tools/radiant/XYWnd.h +++ b/neo/tools/radiant/XYWnd.h @@ -40,6 +40,171 @@ If you have questions concerning this license or the applicable additional terms #include "qe3.h" #include "CamWnd.h" + +class CXYWnd; +class CZWnd; + +//============================================================================= +// CXYMenuBar +// +// Lightweight in-client menu bar used by CXYDockWnd. The old Radiant menu is +// detached from CMainFrame and attached here, so existing command IDs and menu +// check states continue to be used. +//============================================================================= +class CXYMenuBar : public CWnd +{ + DECLARE_DYNAMIC(CXYMenuBar) +public: + CXYMenuBar(); + virtual ~CXYMenuBar(); + + BOOL Create(CWnd *pParent, UINT nID); + BOOL AttachMenu(HMENU hMenu); + BOOL LoadMenu(UINT nID); + CMenu *GetMenu(); + HMENU GetMenuHandle() const; + int PreferredHeight() const; + BOOL TrackMnemonic(UINT nChar); + +protected: + CMenu m_menu; + CRect m_itemRects[64]; + int m_nItemRects; + int m_nHotItem; + + void RebuildItemRects(CDC &dc); + int HitTest(const CPoint &point) const; + void TrackTopLevelMenu(int nIndex); + CWnd *GetCommandTarget() const; + + afx_msg void OnPaint(); + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg BOOL OnEraseBkgnd(CDC *pDC); + virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam); + virtual BOOL OnCmdMsg(UINT nID, int nCode, void *pExtra, AFX_CMDHANDLERINFO *pHandlerInfo); + + DECLARE_MESSAGE_MAP() +}; + +//============================================================================= +// CXYMDIContainerWnd +// +// Hosts the docked Z and XY top child windows inside an MDI client container. +// The initial Z pane is 5% of this container. After startup, the user can drag +// the splitter bar between Z and XY top to resize both panes interactively. +//============================================================================= +class CXYMDIContainerWnd : public CWnd +{ + DECLARE_DYNAMIC(CXYMDIContainerWnd) +public: + CXYMDIContainerWnd(); + virtual ~CXYMDIContainerWnd(); + + BOOL Create(CWnd *pParent, UINT nID); + void SetChildWindows(CXYWnd *pXYWnd, CZWnd *pZWnd); + void SetEmbeddedWindows(CWnd *pZWnd, CWnd *pXYWnd); + void LayoutChildren(); + void SetZDockPercent(int percent); + int GetZDockPercent() const; + int GetZWidth() const; + int GetFixedZWidth() const; + +protected: + CWnd *m_pXYWnd; + CWnd *m_pZWnd; + int m_nZDockPercent; + int m_nZWidth; + int m_nSplitterWidth; + bool m_bZStartupSized; + bool m_bInLayout; + bool m_bTrackingSplitter; + int m_nDragStartX; + int m_nDragStartZWidth; + CRect m_rcSplitter; + + void AttachChild(CWnd *pWnd); + bool IsZVisible() const; + int ComputeInitialZWidth(const CRect &client) const; + int ClampZWidth(int zWidth, const CRect &client) const; + bool HitTestSplitter(const CPoint &point) const; + void DrawSplitter(CDC *pDC); + + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnPaint(); + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg BOOL OnSetCursor(CWnd *pWnd, UINT nHitTest, UINT message); + afx_msg BOOL OnEraseBkgnd(CDC *pDC); + virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam); + virtual BOOL OnCmdMsg(UINT nID, int nCode, void *pExtra, AFX_CMDHANDLERINFO *pHandlerInfo); + + DECLARE_MESSAGE_MAP() +}; + +//============================================================================= +// CXYDockWnd +// +// Owns the embedded XY editor layout: +// [ menu bar ] +// [ toolbar ] +// [ MDI client: Z window | splitter | XY top render window ] +// +// The docked Z window starts at 5% of the MDI container width. The divider in +// the MDI client can be dragged to resize the Z and XY top panes. +//============================================================================= +class CXYDockWnd : public CWnd +{ + DECLARE_DYNAMIC(CXYDockWnd) +public: + CXYDockWnd(); + virtual ~CXYDockWnd(); + + BOOL Create(CWnd *pParent, UINT nID = AFX_IDW_PANE_FIRST); + BOOL Create(const RECT &rect, CWnd *pParent, UINT nID); + + void SetChildWindows(CXYWnd *pXYWnd, CZWnd *pZWnd); + void SetEmbeddedWindows(CWnd *pZWnd, CWnd *pXYWnd); + + void SetToolBar(CToolBar *pToolBar); + void SetEmbeddedToolBar(CToolBar *pToolBar); + void ShowEmbeddedToolBar(BOOL bShow); + void UpdateToolBarCmdUI(BOOL bDisableIfNoHndler); + + BOOL AttachMenu(HMENU hMenu); + void SetMenuHandle(HMENU hMenu); + BOOL LoadMenu(UINT nID); + CMenu *GetEmbeddedMenu(); + HMENU GetEmbeddedMenuHandle() const; + HMENU GetMenuHandle() const; + + void LayoutChildren(); + void RecalcLayout(); + BOOL TrackMenuMnemonic(UINT nChar); + void SetZDockPercent(int percent); + void SetZPercent(int percent); + int GetZDockPercent() const; + int GetZPercent() const; + +protected: + CXYMenuBar m_wndMenuBar; + CXYMDIContainerWnd m_wndMDIContainer; + CToolBar *m_pToolBar; + bool m_bInLayout; + + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg BOOL OnEraseBkgnd(CDC *pDC); + afx_msg LRESULT OnIdleUpdateCmdUI(WPARAM wParam, LPARAM lParam); + virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam); + virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT *pResult); + virtual BOOL OnCmdMsg(UINT nID, int nCode, void *pExtra, AFX_CMDHANDLERINFO *pHandlerInfo); + CWnd *GetCommandTarget() const; + + DECLARE_MESSAGE_MAP() +}; + const int SCALE_X = 0x01; const int SCALE_Y = 0x02; const int SCALE_Z = 0x04;