New editor tabs.

This commit is contained in:
Justin Marshall
2026-05-14 18:37:41 -07:00
parent 16bd1baf35
commit 44f2e67078
18 changed files with 2775 additions and 62 deletions
+701 -40
View File
@@ -42,6 +42,16 @@ If you have questions concerning this license or the applicable additional terms
#define WM_IDLEUPDATECMDUI 0x0363
#endif
#define ID_XYDOCK_TABS 0x7A00
#define ID_XYDOCK_XYPAGE 0x7A03
#define ID_XYDOCK_GAMEPAGE 0x7A04
#define ID_GAME_HOST 0x7A30
#define ID_GAME_FILL_FIT 0x7A40
#define ID_GAME_FILL_100 0x7A41
#define ID_GAME_FILL_75 0x7A42
#define ID_GAME_FILL_50 0x7A43
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
@@ -586,6 +596,16 @@ int CXYMDIContainerWnd::GetFixedZWidth() const {
return GetZWidth();
}
void CXYMDIContainerWnd::FocusXYWindow() {
if (m_pXYWnd && m_pXYWnd->GetSafeHwnd()) {
m_pXYWnd->SetFocus();
}
}
CWnd *CXYMDIContainerWnd::GetXYWindow() const {
return m_pXYWnd;
}
bool CXYMDIContainerWnd::HitTestSplitter(const CPoint &point) const {
return !m_rcSplitter.IsRectEmpty() && m_rcSplitter.PtInRect(point);
}
@@ -756,6 +776,421 @@ BOOL CXYMDIContainerWnd::OnCmdMsg(UINT nID, int nCode, void *pExtra, AFX_CMDHAND
return FALSE;
}
//=============================================================================
// CGameDockWnd
//=============================================================================
IMPLEMENT_DYNAMIC(CGameDockWnd, CWnd)
BEGIN_MESSAGE_MAP(CGameDockWnd, CWnd)
ON_WM_CREATE()
ON_WM_SIZE()
ON_WM_ERASEBKGND()
ON_WM_DESTROY()
ON_WM_SETFOCUS()
ON_BN_CLICKED(ID_GAME_FILL_FIT, OnFillFit)
ON_BN_CLICKED(ID_GAME_FILL_100, OnFill100)
ON_BN_CLICKED(ID_GAME_FILL_75, OnFill75)
ON_BN_CLICKED(ID_GAME_FILL_50, OnFill50)
END_MESSAGE_MAP()
CGameDockWnd::CGameDockWnd() {
m_hGameWnd = NULL;
m_hOldParent = NULL;
m_dwOldStyle = 0;
m_dwOldExStyle = 0;
m_nFillPercent = 0;
m_bActive = FALSE;
}
CGameDockWnd::~CGameDockWnd() {
}
BOOL CGameDockWnd::Create(CWnd *pParent, UINT nID) {
CString className = AfxRegisterWndClass(
CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS,
::LoadCursor(NULL, IDC_ARROW),
(HBRUSH)::GetStockObject(BLACK_BRUSH),
NULL
);
return CWnd::CreateEx(
0,
className,
"RadiantGameDockWnd",
WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
CRect(0, 0, 0, 0),
pParent,
nID
);
}
void CGameDockWnd::SendGameActivate(BOOL bActive) {
if (!m_hGameWnd || !::IsWindow(m_hGameWnd)) {
return;
}
//
// Doom 3's MainWndProc expects:
//
// LOWORD(wParam) = WA_ACTIVE / WA_INACTIVE
// HIWORD(wParam) = minimized flag
//
// We are not minimizing it when changing tabs, so HIWORD is FALSE.
//
const WPARAM activateParam = MAKEWPARAM(bActive ? WA_ACTIVE : WA_INACTIVE, FALSE);
//
// lParam is the other window involved in activation.
// For our embedded case, use the host when activating/deactivating.
//
HWND hOther = m_wndHost.GetSafeHwnd();
::SendMessage(m_hGameWnd, WM_ACTIVATE, activateParam, reinterpret_cast<LPARAM>(hOther));
common->ActivateTool(!bActive);
if (bActive) {
//
// WM_ACTIVATE updates win32.activeApp / mouse grabbing.
// SetFocus makes keyboard input go directly to the game HWND.
//
::SetFocus(m_hGameWnd);
::SendMessage(m_hGameWnd, WM_SETFOCUS, reinterpret_cast<WPARAM>(hOther), 0);
}
else {
::SendMessage(m_hGameWnd, WM_KILLFOCUS, reinterpret_cast<WPARAM>(hOther), 0);
}
}
int CGameDockWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) {
if (CWnd::OnCreate(lpCreateStruct) == -1) {
return -1;
}
CString hostClass = AfxRegisterWndClass(
CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS,
::LoadCursor(NULL, IDC_ARROW),
(HBRUSH)::GetStockObject(BLACK_BRUSH),
NULL
);
m_wndTitle.Create("GAME", WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE, CRect(0, 0, 0, 0), this);
m_btnFit.Create("FIT", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, CRect(0, 0, 0, 0), this, ID_GAME_FILL_FIT);
m_btn100.Create("100%", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, CRect(0, 0, 0, 0), this, ID_GAME_FILL_100);
m_btn75.Create("75%", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, CRect(0, 0, 0, 0), this, ID_GAME_FILL_75);
m_btn50.Create("50%", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, CRect(0, 0, 0, 0), this, ID_GAME_FILL_50);
if (!m_wndHost.CreateEx(
WS_EX_CLIENTEDGE,
hostClass,
"RadiantGameRenderHost",
WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
CRect(0, 0, 0, 0),
this,
ID_GAME_HOST
)) {
return -1;
}
return 0;
}
void CGameDockWnd::OnDestroy() {
DetachGameWindow(TRUE);
CWnd::OnDestroy();
}
void CGameDockWnd::OnSetFocus(CWnd *pOldWnd) {
CWnd::OnSetFocus(pOldWnd);
FocusGameWindow();
}
void CGameDockWnd::SetActive(BOOL bActive) {
const BOOL wasActive = m_bActive;
m_bActive = bActive;
if (m_hGameWnd && ::IsWindow(m_hGameWnd)) {
::ShowWindow(m_hGameWnd, bActive ? SW_SHOW : SW_HIDE);
if (bActive) {
LayoutGameWindow();
::InvalidateRect(m_hGameWnd, NULL, FALSE);
}
//
// Only synthesize WM_ACTIVATE on real active-state transitions.
// LayoutChildren() calls ShowActiveTab(), so without this guard the
// game would get repeated WA_ACTIVE messages every layout pass.
//
if (wasActive != m_bActive) {
SendGameActivate(m_bActive);
}
if (bActive) {
FocusGameWindow();
}
}
//
// Keep the engine/editor global mode in sync even if the HWND does not
// exist yet. This way attaching the game later starts in the correct mode.
//
if (bActive) {
common->ActivateTool(false);
}
else {
common->ActivateTool(true);
}
}
BOOL CGameDockWnd::IsGameWindowDocked() const {
return (m_hGameWnd && ::IsWindow(m_hGameWnd)) ? TRUE : FALSE;
}
HWND CGameDockWnd::GetGameWindow() const {
return (m_hGameWnd && ::IsWindow(m_hGameWnd)) ? m_hGameWnd : NULL;
}
void CGameDockWnd::FocusGameWindow() {
if (m_bActive && m_hGameWnd && ::IsWindow(m_hGameWnd)) {
::SetFocus(m_hGameWnd);
}
}
void CGameDockWnd::AttachGameWindow(HWND hGameWnd) {
if (!hGameWnd || !::IsWindow(hGameWnd) || !m_wndHost.GetSafeHwnd()) {
return;
}
if (m_hGameWnd == hGameWnd) {
LayoutGameWindow();
return;
}
DetachGameWindow(TRUE);
m_hGameWnd = hGameWnd;
m_hOldParent = ::GetParent(hGameWnd);
m_dwOldStyle = ::GetWindowLong(hGameWnd, GWL_STYLE);
m_dwOldExStyle = ::GetWindowLong(hGameWnd, GWL_EXSTYLE);
::SetParent(hGameWnd, m_wndHost.GetSafeHwnd());
LONG style = m_dwOldStyle;
style &= ~(WS_POPUP | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
style |= WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
::SetWindowLong(hGameWnd, GWL_STYLE, style);
LONG exStyle = m_dwOldExStyle;
exStyle &= ~(WS_EX_APPWINDOW | WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME);
exStyle |= WS_EX_CONTROLPARENT;
::SetWindowLong(hGameWnd, GWL_EXSTYLE, exStyle);
::SetWindowPos(
hGameWnd,
NULL,
0,
0,
0,
0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_SHOWWINDOW
);
LayoutGameWindow();
::ShowWindow(hGameWnd, m_bActive ? SW_SHOW : SW_HIDE);
Sys_GrabMouseCursor(m_bActive);
IceDI_ForceOverrideSkipCenter(!m_bActive);
if (m_bActive) {
//
// If the Game tab was already active before the HWND got attached,
// SetActive(TRUE) would not see a false->true transition, so force the
// initial activation here.
//
SendGameActivate(TRUE);
FocusGameWindow();
}
}
void CGameDockWnd::DetachGameWindow(BOOL bRestore) {
if (!m_hGameWnd || !::IsWindow(m_hGameWnd)) {
m_hGameWnd = NULL;
m_hOldParent = NULL;
m_dwOldStyle = 0;
m_dwOldExStyle = 0;
return;
}
HWND hGameWnd = m_hGameWnd;
m_hGameWnd = NULL;
::ShowWindow(hGameWnd, SW_HIDE);
if (bRestore) {
::SetParent(hGameWnd, m_hOldParent);
::SetWindowLong(hGameWnd, GWL_STYLE, m_dwOldStyle);
::SetWindowLong(hGameWnd, GWL_EXSTYLE, m_dwOldExStyle);
::SetWindowPos(
hGameWnd,
NULL,
0,
0,
0,
0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED
);
}
m_hOldParent = NULL;
m_dwOldStyle = 0;
m_dwOldExStyle = 0;
}
void CGameDockWnd::SetFillPercent(int percent) {
m_nFillPercent = percent;
LayoutGameWindow();
}
CRect CGameDockWnd::ComputeGameRect(const CRect &hostClient) const {
CRect rc = hostClient;
if (hostClient.Width() <= 0 || hostClient.Height() <= 0) {
return rc;
}
int targetW = hostClient.Width();
int targetH = hostClient.Height();
if (m_nFillPercent == 0) {
// Fit to a 16:9 frame while preserving aspect ratio.
targetW = hostClient.Width();
targetH = (targetW * 9) / 16;
if (targetH > hostClient.Height()) {
targetH = hostClient.Height();
targetW = (targetH * 16) / 9;
}
} else {
targetW = (hostClient.Width() * m_nFillPercent) / 100;
targetH = (hostClient.Height() * m_nFillPercent) / 100;
}
if (targetW < 1) {
targetW = 1;
}
if (targetH < 1) {
targetH = 1;
}
int x = hostClient.left + (hostClient.Width() - targetW) / 2;
int y = hostClient.top + (hostClient.Height() - targetH) / 2;
rc.SetRect(x, y, x + targetW, y + targetH);
return rc;
}
void CGameDockWnd::LayoutGameWindow() {
if (!m_hGameWnd || !::IsWindow(m_hGameWnd) || !m_wndHost.GetSafeHwnd()) {
return;
}
CRect hostClient;
m_wndHost.GetClientRect(hostClient);
CRect gameRect = ComputeGameRect(hostClient);
::MoveWindow(
m_hGameWnd,
gameRect.left,
gameRect.top,
gameRect.Width(),
gameRect.Height(),
TRUE
);
::InvalidateRect(m_hGameWnd, NULL, FALSE);
}
void CGameDockWnd::LayoutChildren() {
if (!GetSafeHwnd()) {
return;
}
CRect client;
GetClientRect(client);
const int stripH = 34;
const int gap = 6;
int x = client.left + 8;
int y = client.top + 4;
if (m_wndTitle.GetSafeHwnd()) {
m_wndTitle.MoveWindow(x, y, 90, 24, TRUE);
x += 100;
}
CWnd *buttons[] = { &m_btnFit, &m_btn100, &m_btn75, &m_btn50 };
for (int i = 0; i < 4; i++) {
if (buttons[i]->GetSafeHwnd()) {
buttons[i]->MoveWindow(x, y, 54, 24, TRUE);
x += 54 + gap;
}
}
CRect hostRect(
client.left + 4,
client.top + stripH + 4,
client.right - 4,
client.bottom - 4
);
if (hostRect.Width() < 1 || hostRect.Height() < 1) {
return;
}
if (m_wndHost.GetSafeHwnd()) {
m_wndHost.MoveWindow(hostRect, TRUE);
}
LayoutGameWindow();
}
void CGameDockWnd::OnSize(UINT nType, int cx, int cy) {
CWnd::OnSize(nType, cx, cy);
LayoutChildren();
}
BOOL CGameDockWnd::OnEraseBkgnd(CDC *pDC) {
CRect client;
GetClientRect(client);
pDC->FillSolidRect(client, RGB(18, 18, 18));
return TRUE;
}
void CGameDockWnd::OnFillFit() {
SetFillPercent(0);
FocusGameWindow();
}
void CGameDockWnd::OnFill100() {
SetFillPercent(100);
FocusGameWindow();
}
void CGameDockWnd::OnFill75() {
SetFillPercent(75);
FocusGameWindow();
}
void CGameDockWnd::OnFill50() {
SetFillPercent(50);
FocusGameWindow();
}
//=============================================================================
// CXYDockWnd
//=============================================================================
@@ -766,11 +1201,13 @@ BEGIN_MESSAGE_MAP(CXYDockWnd, CWnd)
ON_WM_SIZE()
ON_WM_ERASEBKGND()
ON_MESSAGE(WM_IDLEUPDATECMDUI, OnIdleUpdateCmdUI)
ON_NOTIFY(TCN_SELCHANGE, ID_XYDOCK_TABS, OnTabSelChange)
END_MESSAGE_MAP()
CXYDockWnd::CXYDockWnd() {
m_pToolBar = NULL;
m_bInLayout = false;
m_nActiveTab = XYDOCK_TAB_XY;
}
CXYDockWnd::~CXYDockWnd() {
@@ -803,15 +1240,69 @@ int CXYDockWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) {
if (CWnd::OnCreate(lpCreateStruct) == -1) {
return -1;
}
if (!m_wndMenuBar.Create(this, 0x7A01)) {
if (!m_wndTabs.Create(
WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TCS_TABS | TCS_SINGLELINE,
CRect(0, 0, 0, 0),
this,
ID_XYDOCK_TABS
)) {
return -1;
}
if (!m_wndMDIContainer.Create(this, 0x7A02)) {
TCITEM item;
memset(&item, 0, sizeof(item));
item.mask = TCIF_TEXT;
item.pszText = "XY";
m_wndTabs.InsertItem(XYDOCK_TAB_XY, &item);
item.pszText = "Game";
m_wndTabs.InsertItem(XYDOCK_TAB_GAME, &item);
CString pageClass = AfxRegisterWndClass(
CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS,
::LoadCursor(NULL, IDC_ARROW),
(HBRUSH)(COLOR_BTNFACE + 1),
NULL
);
if (!m_wndXYPage.CreateEx(
0,
pageClass,
"RadiantXYTabPage",
WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
CRect(0, 0, 0, 0),
&m_wndTabs,
ID_XYDOCK_XYPAGE
)) {
return -1;
}
if (!m_wndGamePage.Create(&m_wndTabs, ID_XYDOCK_GAMEPAGE)) {
return -1;
}
m_wndGamePage.ShowWindow(SW_HIDE);
if (!m_wndMenuBar.Create(&m_wndXYPage, 0x7A01)) {
return -1;
}
if (!m_wndMDIContainer.Create(&m_wndXYPage, 0x7A02)) {
return -1;
}
m_wndTabs.SetCurSel(XYDOCK_TAB_XY);
return 0;
}
CWnd *CXYDockWnd::GetXYPageParent() const {
if (m_wndXYPage.GetSafeHwnd()) {
return const_cast<CWnd *>(&m_wndXYPage);
}
return const_cast<CXYDockWnd *>(this);
}
void CXYDockWnd::SetChildWindows(CXYWnd *pXYWnd, CZWnd *pZWnd) {
m_wndMDIContainer.SetChildWindows(pXYWnd, pZWnd);
LayoutChildren();
@@ -825,15 +1316,14 @@ void CXYDockWnd::SetEmbeddedWindows(CWnd *pZWnd, CWnd *pXYWnd) {
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);
CWnd *toolbarParent = GetXYPageParent();
m_pToolBar->SetParent(toolbarParent);
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);
m_pToolBar->ModifyStyle(
WS_POPUP | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN
);
}
LayoutChildren();
}
@@ -858,6 +1348,10 @@ CWnd *CXYDockWnd::GetCommandTarget() const {
}
void CXYDockWnd::UpdateToolBarCmdUI(BOOL bDisableIfNoHndler) {
if (m_nActiveTab != XYDOCK_TAB_XY) {
return;
}
if (!m_pToolBar || !m_pToolBar->GetSafeHwnd() || !m_pToolBar->IsWindowVisible()) {
return;
}
@@ -923,6 +1417,121 @@ int CXYDockWnd::GetZPercent() const {
return GetZDockPercent();
}
void CXYDockWnd::ShowActiveTab() {
const BOOL xyActive = (m_nActiveTab == XYDOCK_TAB_XY);
const BOOL gameActive = (m_nActiveTab == XYDOCK_TAB_GAME);
if (m_wndXYPage.GetSafeHwnd()) {
m_wndXYPage.ShowWindow(xyActive ? SW_SHOW : SW_HIDE);
if (xyActive) {
m_wndXYPage.SetWindowPos(&wndTop, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
}
}
if (m_wndGamePage.GetSafeHwnd()) {
m_wndGamePage.ShowWindow(gameActive ? SW_SHOW : SW_HIDE);
if (gameActive) {
m_wndGamePage.SetWindowPos(&wndTop, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
}
m_wndGamePage.SetActive(gameActive);
}
}
void CXYDockWnd::SetActiveTab(int nTab) {
if (nTab != XYDOCK_TAB_XY && nTab != XYDOCK_TAB_GAME) {
nTab = XYDOCK_TAB_XY;
}
const BOOL changed = (m_nActiveTab != nTab);
m_nActiveTab = nTab;
if (m_wndTabs.GetSafeHwnd()) {
m_wndTabs.SetCurSel(nTab);
}
LayoutChildren();
if (changed) {
if (m_nActiveTab == XYDOCK_TAB_GAME) {
//
// Game tab selected:
// - editor tool input off
// - game HWND receives WM_ACTIVATE/WA_ACTIVE through SetActive(TRUE)
// - keyboard/mouse focus moves to game
//
common->ActivateTool(false);
if (m_wndGamePage.GetSafeHwnd()) {
m_wndGamePage.SetActive(TRUE);
}
FocusGameWindow();
}
else {
//
// XY tab selected:
// - game HWND receives WM_ACTIVATE/WA_INACTIVE through SetActive(FALSE)
// - editor tool input comes back
// - focus returns to XY
//
if (m_wndGamePage.GetSafeHwnd()) {
m_wndGamePage.SetActive(FALSE);
}
common->ActivateTool(true);
FocusXYWindow();
}
}
}
void CXYDockWnd::OnTabSelChange(NMHDR *pNMHDR, LRESULT *pResult) {
int sel = m_wndTabs.GetCurSel();
SetActiveTab(sel);
if (pResult) {
*pResult = 0;
}
}
void CXYDockWnd::SelectXYTab() {
SetActiveTab(XYDOCK_TAB_XY);
}
void CXYDockWnd::SelectGameTab() {
SetActiveTab(XYDOCK_TAB_GAME);
}
BOOL CXYDockWnd::IsGameTabActive() const {
return (m_nActiveTab == XYDOCK_TAB_GAME) ? TRUE : FALSE;
}
void CXYDockWnd::AttachGameWindow(HWND hGameWnd) {
m_wndGamePage.AttachGameWindow(hGameWnd);
m_wndGamePage.SetActive(IsGameTabActive());
}
void CXYDockWnd::DetachGameWindow(BOOL bRestore) {
m_wndGamePage.DetachGameWindow(bRestore);
}
BOOL CXYDockWnd::IsGameWindowDocked() const {
return m_wndGamePage.IsGameWindowDocked();
}
HWND CXYDockWnd::GetDockedGameWindow() const {
return m_wndGamePage.GetGameWindow();
}
void CXYDockWnd::FocusGameWindow() {
m_wndGamePage.FocusGameWindow();
}
void CXYDockWnd::FocusXYWindow() {
m_wndMDIContainer.FocusXYWindow();
}
void CXYDockWnd::LayoutChildren() {
if (!GetSafeHwnd() || m_bInLayout) {
return;
@@ -933,41 +1542,77 @@ void CXYDockWnd::LayoutChildren() {
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) {
if (client.Width() < 1 || client.Height() < 1) {
m_bInLayout = false;
return;
}
if (m_wndMDIContainer.GetSafeHwnd()) {
m_wndMDIContainer.MoveWindow(content, TRUE);
m_wndMDIContainer.LayoutChildren();
CRect pageRect(0, 0, client.Width(), client.Height());
if (m_wndTabs.GetSafeHwnd()) {
m_wndTabs.MoveWindow(client, TRUE);
// The tab pages are children of the tab control, so use tab-client
// coordinates here. Creating/moving them as siblings of the tab control
// can leave them behind the tab control's client area, which makes both
// tabs look empty even though their child windows exist.
m_wndTabs.GetClientRect(&pageRect);
m_wndTabs.AdjustRect(FALSE, &pageRect);
pageRect.DeflateRect(2, 2);
}
if (m_wndXYPage.GetSafeHwnd()) {
m_wndXYPage.MoveWindow(pageRect, TRUE);
}
if (m_wndGamePage.GetSafeHwnd()) {
m_wndGamePage.MoveWindow(pageRect, TRUE);
m_wndGamePage.LayoutChildren();
}
ShowActiveTab();
if (m_pToolBar && m_pToolBar->GetSafeHwnd() && m_wndXYPage.GetSafeHwnd()) {
if (::GetParent(m_pToolBar->GetSafeHwnd()) != m_wndXYPage.GetSafeHwnd()) {
m_pToolBar->SetParent(&m_wndXYPage);
}
}
if (m_wndXYPage.GetSafeHwnd()) {
CRect xyClient;
m_wndXYPage.GetClientRect(xyClient);
int y = xyClient.top;
const int width = xyClient.Width();
if (m_wndMenuBar.GetSafeHwnd()) {
if (m_wndMenuBar.GetMenuHandle()) {
m_wndMenuBar.ShowWindow(SW_SHOW);
const int menuHeight = m_wndMenuBar.PreferredHeight();
m_wndMenuBar.MoveWindow(xyClient.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(xyClient.left, y, width, toolbarHeight, TRUE);
y += toolbarHeight;
}
}
CRect content(xyClient.left, y, xyClient.right, xyClient.bottom);
if (content.Width() >= 1 && content.Height() >= 1 && m_wndMDIContainer.GetSafeHwnd()) {
m_wndMDIContainer.MoveWindow(content, TRUE);
m_wndMDIContainer.LayoutChildren();
}
}
m_bInLayout = false;
@@ -978,6 +1623,10 @@ void CXYDockWnd::RecalcLayout() {
}
BOOL CXYDockWnd::TrackMenuMnemonic(UINT nChar) {
if (m_nActiveTab != XYDOCK_TAB_XY) {
return FALSE;
}
if (m_wndMenuBar.GetSafeHwnd()) {
return m_wndMenuBar.TrackMnemonic(nChar);
}
@@ -999,6 +1648,10 @@ LRESULT CXYDockWnd::OnIdleUpdateCmdUI(WPARAM wParam, LPARAM lParam) {
}
BOOL CXYDockWnd::OnCommand(WPARAM wParam, LPARAM lParam) {
if (m_nActiveTab != XYDOCK_TAB_XY) {
return CWnd::OnCommand(wParam, lParam);
}
CWnd *commandTarget = GetCommandTarget();
if (commandTarget && commandTarget->GetSafeHwnd() && commandTarget != this) {
return static_cast<BOOL>(commandTarget->SendMessage(WM_COMMAND, wParam, lParam));
@@ -1007,6 +1660,10 @@ BOOL CXYDockWnd::OnCommand(WPARAM wParam, LPARAM lParam) {
}
BOOL CXYDockWnd::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT *pResult) {
if (wParam == ID_XYDOCK_TABS) {
return CWnd::OnNotify(wParam, lParam, pResult);
}
CWnd *commandTarget = GetCommandTarget();
if (commandTarget && commandTarget->GetSafeHwnd() && commandTarget != this) {
LRESULT result = commandTarget->SendMessage(WM_NOTIFY, wParam, lParam);
@@ -1026,6 +1683,10 @@ BOOL CXYDockWnd::OnCmdMsg(UINT nID, int nCode, void *pExtra, AFX_CMDHANDLERINFO
return TRUE;
}
if (m_nActiveTab != XYDOCK_TAB_XY) {
return FALSE;
}
CWnd *commandTarget = GetCommandTarget();
if (commandTarget && commandTarget->GetSafeHwnd() && commandTarget != this) {
return commandTarget->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);