Added captions to windows.

This commit is contained in:
Justin Marshall
2026-05-14 19:58:13 -07:00
parent d5f59f06e1
commit 3cad87be0a
2 changed files with 561 additions and 117 deletions
+64 -7
View File
@@ -1003,7 +1003,9 @@ 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_CAPTION_HEIGHT 30
#define CAMWND_MENU_HEIGHT 22
#define CAMWND_TOPBAR_HEIGHT (CAMWND_CAPTION_HEIGHT + CAMWND_MENU_HEIGHT)
#define CAMWND_MENU_CHILD_ID 62000
#define CAMWND_MENU_CMD_REALTIME_LIGHTING 62100
#define CAMWND_MENU_CMD_SHOW_WORLD 62101
@@ -1026,7 +1028,7 @@ static const char* CAMWND_PROP_FILTER_MASK = "QER_CamWnd_FilterMask";
static LRESULT CALLBACK CamWnd_MenuBarProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static int CamWnd_GetMenuHeight() {
return CAMWND_MENU_HEIGHT;
return CAMWND_TOPBAR_HEIGHT;
}
static int CamWnd_GetIntProp(HWND hWnd, const char* name, int defaultValue = 0) {
@@ -1092,8 +1094,8 @@ static void CamWnd_RequestRedraw(CCamWnd* cam) {
static void CamWnd_GetMenuItemRect(HWND hWnd, int item, RECT& rect) {
GetClientRect(hWnd, &rect);
rect.top = 1;
rect.bottom = CAMWND_MENU_HEIGHT - 1;
rect.top = CAMWND_CAPTION_HEIGHT + 1;
rect.bottom = CAMWND_TOPBAR_HEIGHT - 1;
if (item == 0) {
rect.left = 4;
@@ -1317,7 +1319,7 @@ static HWND CamWnd_EnsureMenuBar(CCamWnd* cam) {
0,
0,
rect.Width(),
CAMWND_MENU_HEIGHT,
CAMWND_TOPBAR_HEIGHT,
cam->GetSafeHwnd(),
(HMENU)CAMWND_MENU_CHILD_ID,
AfxGetInstanceHandle(),
@@ -1343,7 +1345,7 @@ static void CamWnd_LayoutMenuBar(CCamWnd* cam) {
CRect rect;
cam->GetClientRect(rect);
MoveWindow(hBar, 0, 0, rect.Width(), CAMWND_MENU_HEIGHT, TRUE);
MoveWindow(hBar, 0, 0, rect.Width(), CAMWND_TOPBAR_HEIGHT, TRUE);
}
static void CamWnd_DestroyMenuBar(CCamWnd* cam) {
@@ -1581,6 +1583,39 @@ static bool CamWnd_MenuFilterBrush(CCamWnd* cam, brush_t* brush) {
return false;
}
static COLORREF CamWnd_LerpColor(COLORREF a, COLORREF b, float t) {
const int ar = GetRValue(a);
const int ag = GetGValue(a);
const int ab = GetBValue(a);
const int br = GetRValue(b);
const int bg = GetGValue(b);
const int bb = GetBValue(b);
const int r = ar + (int)((br - ar) * t);
const int g = ag + (int)((bg - ag) * t);
const int bl = ab + (int)((bb - ab) * t);
return RGB(r, g, bl);
}
static void CamWnd_FillHorizontalGradient(HDC hDC, const RECT& rect, COLORREF leftColor, COLORREF rightColor) {
const int width = rect.right - rect.left;
if (width <= 0) {
return;
}
for (int x = 0; x < width; x++) {
const float t = (width > 1) ? ((float)x / (float)(width - 1)) : 0.0f;
const COLORREF color = CamWnd_LerpColor(leftColor, rightColor, t);
HPEN pen = CreatePen(PS_SOLID, 1, color);
HPEN oldPen = (HPEN)SelectObject(hDC, pen);
MoveToEx(hDC, rect.left + x, rect.top, NULL);
LineTo(hDC, rect.left + x, rect.bottom);
SelectObject(hDC, oldPen);
DeleteObject(pen);
}
}
static LRESULT CALLBACK CamWnd_MenuBarProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_ERASEBKGND:
@@ -1615,10 +1650,25 @@ static LRESULT CALLBACK CamWnd_MenuBarProc(HWND hWnd, UINT uMsg, WPARAM wParam,
RECT rect;
GetClientRect(hWnd, &rect);
FillRect(hDC, &rect, (HBRUSH)(COLOR_BTNFACE + 1));
RECT captionRect = rect;
captionRect.top = 0;
captionRect.bottom = CAMWND_CAPTION_HEIGHT;
RECT menuRect = rect;
menuRect.top = CAMWND_CAPTION_HEIGHT;
menuRect.bottom = CAMWND_TOPBAR_HEIGHT;
CamWnd_FillHorizontalGradient(hDC, captionRect, RGB(24, 82, 150), RGB(92, 96, 104));
FillRect(hDC, &menuRect, (HBRUSH)(COLOR_BTNFACE + 1));
RECT dividerRect = rect;
dividerRect.top = CAMWND_CAPTION_HEIGHT - 1;
dividerRect.bottom = CAMWND_CAPTION_HEIGHT;
FillRect(hDC, &dividerRect, (HBRUSH)(COLOR_3DSHADOW + 1));
RECT lineRect = rect;
lineRect.top = CAMWND_MENU_HEIGHT - 1;
lineRect.top = CAMWND_TOPBAR_HEIGHT - 1;
lineRect.bottom = CAMWND_TOPBAR_HEIGHT;
FillRect(hDC, &lineRect, (HBRUSH)(COLOR_3DSHADOW + 1));
HFONT font = (HFONT)SendMessage(hWnd, WM_GETFONT, 0, 0);
@@ -1628,6 +1678,13 @@ static LRESULT CALLBACK CamWnd_MenuBarProc(HWND hWnd, UINT uMsg, WPARAM wParam,
}
SetBkMode(hDC, TRANSPARENT);
RECT captionTextRect = captionRect;
captionTextRect.left += 8;
captionTextRect.right -= 8;
SetTextColor(hDC, RGB(235, 242, 255));
DrawText(hDC, "Viewport", -1, &captionTextRect, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS);
SetTextColor(hDC, GetSysColor(COLOR_BTNTEXT));
RECT itemRect;
+497 -110
View File
@@ -2,9 +2,9 @@
===========================================================================
IceTech GPL Source Code
Copyright (C) 2026 Justin Marshall
Copyright (C) 2026 Justin Marshall
This file is part of the IceTech GPL Source Code (?IceTech Source Code?).
This file is part of the IceTech GPL Source Code (?IceTech Source Code?).
IceTech Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -31,10 +31,384 @@ If you have questions concerning this license or the applicable additional terms
#include "QE3.H"
#include "TabsDlg.h"
/*
========================
Tabs dialog top caption
Draws a non-layout-changing caption at the top of the tab dialog. This is an
overlay child window, so it does not move the tab control, docked children, or
floating/docking logic. The caption text follows the currently selected tab.
========================
*/
static const char* TABSDLG_TOP_CAPTION_CLASS = "QER_TabsDlgTopCaption";
static const char* TABSDLG_TOP_CAPTION_STATE_PROP = "QER_TabsDlgTopCaptionState";
static const char* TABSDLG_TAB_NOTIFY_STATE_PROP = "QER_TabsDlgTabNotifyState";
static const int TABSDLG_TOP_CAPTION_HEIGHT = 28;
static const int TABSDLG_TOP_CAPTION_CHILD_ID = 64010;
struct tabsDlgTopCaptionState_t {
WNDPROC oldProc;
HWND captionWnd;
};
struct tabsDlgTabNotifyState_t {
WNDPROC oldProc;
HWND parentWnd;
};
static LRESULT CALLBACK TabsDlg_TopCaptionProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK TabsDlg_ParentProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK TabsDlg_TabNotifyProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static WNDPROC TabsDlg_GetWindowProc(HWND hWnd) {
#ifdef _WIN64
return (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC);
#else
return (WNDPROC)GetWindowLong(hWnd, GWL_WNDPROC);
#endif
}
static void TabsDlg_SetWindowProc(HWND hWnd, WNDPROC proc) {
#ifdef _WIN64
SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)proc);
#else
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)proc);
#endif
}
static COLORREF TabsDlg_LerpColor(COLORREF a, COLORREF b, float t) {
const int ar = GetRValue(a);
const int ag = GetGValue(a);
const int ab = GetBValue(a);
const int br = GetRValue(b);
const int bg = GetGValue(b);
const int bb = GetBValue(b);
const int r = ar + (int)((br - ar) * t);
const int g = ag + (int)((bg - ag) * t);
const int bl = ab + (int)((bb - ab) * t);
return RGB(r, g, bl);
}
static void TabsDlg_FillHorizontalGradient(HDC hDC, const RECT& rect, COLORREF leftColor, COLORREF rightColor) {
const int width = rect.right - rect.left;
if (width <= 0) {
return;
}
for (int x = 0; x < width; x++) {
const float t = (width > 1) ? ((float)x / (float)(width - 1)) : 0.0f;
const COLORREF color = TabsDlg_LerpColor(leftColor, rightColor, t);
HPEN pen = CreatePen(PS_SOLID, 1, color);
HPEN oldPen = (HPEN)SelectObject(hDC, pen);
MoveToEx(hDC, rect.left + x, rect.top, NULL);
LineTo(hDC, rect.left + x, rect.bottom);
SelectObject(hDC, oldPen);
DeleteObject(pen);
}
}
static tabsDlgTopCaptionState_t* TabsDlg_GetTopCaptionState(HWND hWnd) {
return (tabsDlgTopCaptionState_t*)GetProp(hWnd, TABSDLG_TOP_CAPTION_STATE_PROP);
}
static tabsDlgTabNotifyState_t* TabsDlg_GetTabNotifyState(HWND hTabs) {
return (tabsDlgTabNotifyState_t*)GetProp(hTabs, TABSDLG_TAB_NOTIFY_STATE_PROP);
}
static HWND TabsDlg_GetTabControl(HWND hWnd) {
HWND hTabs = GetDlgItem(hWnd, IDC_TAB_INSPECTOR);
return IsWindow(hTabs) ? hTabs : NULL;
}
static CString TabsDlg_GetCurrentTopCaption(HWND hWnd) {
HWND hTabs = TabsDlg_GetTabControl(hWnd);
if (!hTabs) {
return "Viewport";
}
int curSel = TabCtrl_GetCurSel(hTabs);
if (curSel < 0 && TabCtrl_GetItemCount(hTabs) > 0) {
curSel = 0;
}
if (curSel >= 0) {
char text[256];
text[0] = '\0';
TCITEM item;
memset(&item, 0, sizeof(item));
item.mask = TCIF_TEXT;
item.pszText = text;
item.cchTextMax = sizeof(text);
if (TabCtrl_GetItem(hTabs, curSel, &item) && text[0] != '\0') {
return text;
}
}
return "Viewport";
}
static void TabsDlg_RegisterTopCaptionClass() {
static bool registered = false;
if (registered) {
return;
}
WNDCLASS wc;
memset(&wc, 0, sizeof(wc));
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = TabsDlg_TopCaptionProc;
wc.hInstance = AfxGetInstanceHandle();
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszClassName = TABSDLG_TOP_CAPTION_CLASS;
AfxRegisterClass(&wc);
registered = true;
}
static void TabsDlg_DrawTopCaption(HWND hCaption, HDC hDC) {
HWND hParent = GetParent(hCaption);
RECT rect;
GetClientRect(hCaption, &rect);
TabsDlg_FillHorizontalGradient(
hDC,
rect,
RGB(24, 82, 150),
RGB(92, 96, 104)
);
RECT dividerRect = rect;
dividerRect.top = rect.bottom - 1;
dividerRect.bottom = rect.bottom;
FillRect(hDC, &dividerRect, (HBRUSH)(COLOR_3DSHADOW + 1));
HFONT font = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
HFONT oldFont = NULL;
if (font) {
oldFont = (HFONT)SelectObject(hDC, font);
}
SetBkMode(hDC, TRANSPARENT);
SetTextColor(hDC, RGB(235, 242, 255));
RECT textRect = rect;
textRect.left += 8;
textRect.right -= 8;
CString caption = TabsDlg_GetCurrentTopCaption(hParent);
DrawText(
hDC,
caption,
-1,
&textRect,
DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS
);
if (oldFont) {
SelectObject(hDC, oldFont);
}
}
static LRESULT CALLBACK TabsDlg_TopCaptionProc(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_PAINT:
{
PAINTSTRUCT ps;
HDC hDC = BeginPaint(hWnd, &ps);
TabsDlg_DrawTopCaption(hWnd, hDC);
EndPaint(hWnd, &ps);
return 0;
}
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
static void TabsDlg_LayoutTopCaption(HWND hWnd) {
tabsDlgTopCaptionState_t* state = TabsDlg_GetTopCaptionState(hWnd);
if (!state || !IsWindow(state->captionWnd)) {
return;
}
RECT clientRect;
GetClientRect(hWnd, &clientRect);
int width = clientRect.right - clientRect.left;
if (width < 1) {
width = 1;
}
SetWindowPos(
state->captionWnd,
HWND_TOP,
0,
0,
width,
TABSDLG_TOP_CAPTION_HEIGHT,
SWP_NOACTIVATE | SWP_SHOWWINDOW
);
}
static void TabsDlg_RefreshTopCaption(HWND hWnd) {
tabsDlgTopCaptionState_t* state = TabsDlg_GetTopCaptionState(hWnd);
if (!state || !IsWindow(state->captionWnd)) {
return;
}
TabsDlg_LayoutTopCaption(hWnd);
InvalidateRect(state->captionWnd, NULL, FALSE);
UpdateWindow(state->captionWnd);
}
static void TabsDlg_UninstallTabNotify(HWND hTabs) {
tabsDlgTabNotifyState_t* state = TabsDlg_GetTabNotifyState(hTabs);
if (!state) {
return;
}
TabsDlg_SetWindowProc(hTabs, state->oldProc);
RemoveProp(hTabs, TABSDLG_TAB_NOTIFY_STATE_PROP);
delete state;
}
static LRESULT CALLBACK TabsDlg_TabNotifyProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
tabsDlgTabNotifyState_t* state = TabsDlg_GetTabNotifyState(hWnd);
WNDPROC oldProc = state ? state->oldProc : NULL;
HWND parentWnd = state ? state->parentWnd : GetParent(hWnd);
switch (uMsg) {
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_KEYDOWN:
case WM_KEYUP:
case TCM_SETCURSEL:
case TCM_SETCURFOCUS:
{
LRESULT result = oldProc ? CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam) : DefWindowProc(hWnd, uMsg, wParam, lParam);
TabsDlg_RefreshTopCaption(parentWnd);
return result;
}
case WM_NCDESTROY:
{
TabsDlg_UninstallTabNotify(hWnd);
return oldProc ? CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam) : DefWindowProc(hWnd, uMsg, wParam, lParam);
}
}
return oldProc ? CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam) : DefWindowProc(hWnd, uMsg, wParam, lParam);
}
static void TabsDlg_InstallTabNotify(HWND hWnd) {
HWND hTabs = TabsDlg_GetTabControl(hWnd);
if (!hTabs || TabsDlg_GetTabNotifyState(hTabs)) {
return;
}
tabsDlgTabNotifyState_t* state = new tabsDlgTabNotifyState_t;
state->oldProc = TabsDlg_GetWindowProc(hTabs);
state->parentWnd = hWnd;
SetProp(hTabs, TABSDLG_TAB_NOTIFY_STATE_PROP, (HANDLE)state);
TabsDlg_SetWindowProc(hTabs, TabsDlg_TabNotifyProc);
}
static LRESULT CALLBACK TabsDlg_ParentProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
tabsDlgTopCaptionState_t* state = TabsDlg_GetTopCaptionState(hWnd);
WNDPROC oldProc = state ? state->oldProc : NULL;
switch (uMsg) {
case WM_SIZE:
case WM_WINDOWPOSCHANGED:
{
LRESULT result = oldProc ? CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam) : DefWindowProc(hWnd, uMsg, wParam, lParam);
TabsDlg_LayoutTopCaption(hWnd);
return result;
}
case WM_NCDESTROY:
{
HWND hTabs = TabsDlg_GetTabControl(hWnd);
if (hTabs) {
TabsDlg_UninstallTabNotify(hTabs);
}
HWND hCaption = state ? state->captionWnd : NULL;
if (IsWindow(hCaption)) {
DestroyWindow(hCaption);
}
if (oldProc) {
TabsDlg_SetWindowProc(hWnd, oldProc);
}
RemoveProp(hWnd, TABSDLG_TOP_CAPTION_STATE_PROP);
if (state) {
delete state;
}
return oldProc ? CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam) : DefWindowProc(hWnd, uMsg, wParam, lParam);
}
}
return oldProc ? CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam) : DefWindowProc(hWnd, uMsg, wParam, lParam);
}
static void TabsDlg_InstallTopCaption(HWND hWnd) {
if (!IsWindow(hWnd)) {
return;
}
tabsDlgTopCaptionState_t* state = TabsDlg_GetTopCaptionState(hWnd);
if (!state) {
TabsDlg_RegisterTopCaptionClass();
state = new tabsDlgTopCaptionState_t;
memset(state, 0, sizeof(*state));
state->oldProc = TabsDlg_GetWindowProc(hWnd);
SetProp(hWnd, TABSDLG_TOP_CAPTION_STATE_PROP, (HANDLE)state);
TabsDlg_SetWindowProc(hWnd, TabsDlg_ParentProc);
}
if (!IsWindow(state->captionWnd)) {
state->captionWnd = CreateWindowEx(
0,
TABSDLG_TOP_CAPTION_CLASS,
"",
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
0,
0,
1,
TABSDLG_TOP_CAPTION_HEIGHT,
hWnd,
(HMENU)TABSDLG_TOP_CAPTION_CHILD_ID,
AfxGetInstanceHandle(),
NULL);
}
TabsDlg_InstallTabNotify(hWnd);
TabsDlg_LayoutTopCaption(hWnd);
TabsDlg_RefreshTopCaption(hWnd);
}
// CTabsDlg dialog
//IMPLEMENT_DYNAMIC ( CTabsDlg , CDialog )
CTabsDlg::CTabsDlg(UINT ID , CWnd* pParent /*=NULL*/)
CTabsDlg::CTabsDlg(UINT ID, CWnd* pParent /*=NULL*/)
: CDialog(ID, pParent)
{
m_DragTabActive = false;
@@ -61,127 +435,135 @@ BOOL CTabsDlg::OnInitDialog()
{
CDialog::OnInitDialog();
TabsDlg_InstallTopCaption(GetSafeHwnd());
return TRUE; // return TRUE unless you set the focus to a control
}
void CTabsDlg::OnTcnSelchange(NMHDR *pNMHDR, LRESULT *pResult)
void CTabsDlg::OnTcnSelchange(NMHDR* pNMHDR, LRESULT* pResult)
{
int ID = TabCtrl_GetCurSel ( pNMHDR->hwndFrom );
int ID = TabCtrl_GetCurSel(pNMHDR->hwndFrom);
if ( ID >= 0 )
if (ID >= 0)
{
TCITEM item;
item.mask = TCIF_PARAM;
ShowAllWindows ( FALSE );
TabCtrl_GetItem (m_Tabs.GetSafeHwnd() , ID , &item);
ShowAllWindows(FALSE);
TabCtrl_GetItem(m_Tabs.GetSafeHwnd(), ID, &item);
DockedWindowInfo* info = (DockedWindowInfo*)item.lParam;
ASSERT ( info );
ASSERT(info);
info->m_TabControlIndex = ID;
info->m_Window->ShowWindow(TRUE);
TabsDlg_RefreshTopCaption(GetSafeHwnd());
}
}
void CTabsDlg::DockWindow ( int ID , bool dock )
void CTabsDlg::DockWindow(int ID, bool dock)
{
DockedWindowInfo* info = NULL;
m_Windows.Lookup ( (WORD)ID , (void*&)info );
m_Windows.Lookup((WORD)ID, (void*&)info);
ASSERT ( info );
ASSERT ( m_Tabs.GetSafeHwnd() );
ShowAllWindows ( FALSE );
ASSERT(info);
ASSERT(m_Tabs.GetSafeHwnd());
if ( !dock )
{
ShowAllWindows(FALSE);
if (!dock)
{
//make a containing window and assign the dialog to it
CRect rect;
CString classname = AfxRegisterWndClass ( CS_DBLCLKS , 0 , 0 , 0 );
CString classname = AfxRegisterWndClass(CS_DBLCLKS, 0, 0, 0);
info->m_State = DockedWindowInfo::FLOATING;
info->m_Window->GetWindowRect(rect);
info->m_Container.CreateEx ( WS_EX_TOOLWINDOW , classname , info->m_Title , WS_THICKFRAME | WS_SYSMENU | WS_POPUP | WS_CAPTION, rect , this , 0 );
info->m_Window->SetParent ( &info->m_Container );
info->m_Container.CreateEx(WS_EX_TOOLWINDOW, classname, info->m_Title, WS_THICKFRAME | WS_SYSMENU | WS_POPUP | WS_CAPTION, rect, this, 0);
info->m_Window->SetParent(&info->m_Container);
info->m_Window->ShowWindow(TRUE);
info->m_Container.SetDockManager(this);
info->m_Container.ShowWindow(TRUE);
info->m_Container.SetDialog ( info->m_Window , info->m_ID );
info->m_Container.SetDialog(info->m_Window, info->m_ID);
if (info->m_TabControlIndex >= 0 )
if (info->m_TabControlIndex >= 0)
{
m_Tabs.DeleteItem( info->m_TabControlIndex );
}
m_Tabs.DeleteItem(info->m_TabControlIndex);
}
if ( m_Tabs.GetItemCount() > 0 )
if (m_Tabs.GetItemCount() > 0)
{
m_Tabs.SetCurFocus( 0 );
}
m_Tabs.SetCurFocus(0);
}
CString placementName = info->m_Title + "Placement";
LoadWindowPlacement(info->m_Container , placementName);
LoadWindowPlacement(info->m_Container, placementName);
}
else
{
info->m_State = DockedWindowInfo::DOCKED;
info->m_TabControlIndex = m_Tabs.InsertItem( TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM , 0 , info->m_Title , info->m_ImageID , (LPARAM)info);
{
info->m_State = DockedWindowInfo::DOCKED;
info->m_Window->SetParent ( this );
info->m_Window->ShowWindow (TRUE);
info->m_Container.SetDockManager( NULL ); //so it doesn't try to call back and redock this window
info->m_Container.DestroyWindow ();
info->m_TabControlIndex = m_Tabs.InsertItem(TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM, 0, info->m_Title, info->m_ImageID, (LPARAM)info);
info->m_Window->SetParent(this);
info->m_Window->ShowWindow(TRUE);
info->m_Container.SetDockManager(NULL); //so it doesn't try to call back and redock this window
info->m_Container.DestroyWindow();
CRect rect;
GetWindowRect ( rect );
GetWindowRect(rect);
//stupid hack to get the window reitself properly
rect.DeflateRect(0,0,0,1);
MoveWindow(rect);
rect.InflateRect(0,0,0,1);
MoveWindow(rect);
rect.DeflateRect(0, 0, 0, 1);
MoveWindow(rect);
rect.InflateRect(0, 0, 0, 1);
MoveWindow(rect);
}
UpdateTabControlIndices ();
FocusWindow ( ID );
UpdateTabControlIndices();
FocusWindow(ID);
if ( info->m_DockCallback )
TabsDlg_InstallTopCaption(GetSafeHwnd());
TabsDlg_RefreshTopCaption(GetSafeHwnd());
if (info->m_DockCallback)
{
info->m_DockCallback ( dock , info->m_ID , info->m_Window );
info->m_DockCallback(dock, info->m_ID, info->m_Window);
}
SaveWindowPlacement ();
SaveWindowPlacement();
}
int CTabsDlg::PreTranslateMessage ( MSG* msg )
int CTabsDlg::PreTranslateMessage(MSG* msg)
{
if ( msg->message == WM_LBUTTONDBLCLK && msg->hwnd == m_Tabs.GetSafeHwnd() )
if (msg->message == WM_LBUTTONDBLCLK && msg->hwnd == m_Tabs.GetSafeHwnd())
{
HandleUndock ();
HandleUndock();
return TRUE;
}
//steal lbutton clicks for the main dialog too, but let the tabs do their default thing as well
if ( msg->message == WM_LBUTTONDOWN && msg->hwnd == m_Tabs.GetSafeHwnd()) {
m_Tabs.SendMessage ( msg->message , msg->wParam , msg->lParam );
if (msg->message == WM_LBUTTONDOWN && msg->hwnd == m_Tabs.GetSafeHwnd()) {
m_Tabs.SendMessage(msg->message, msg->wParam, msg->lParam);
m_DragTabActive = true;
TabsDlg_RefreshTopCaption(GetSafeHwnd());
}
else if ( msg->message == WM_LBUTTONUP && msg->hwnd == m_Tabs.GetSafeHwnd()) {
m_Tabs.SendMessage ( msg->message , msg->wParam , msg->lParam );
else if (msg->message == WM_LBUTTONUP && msg->hwnd == m_Tabs.GetSafeHwnd()) {
m_Tabs.SendMessage(msg->message, msg->wParam, msg->lParam);
m_DragTabActive = false;
TabsDlg_RefreshTopCaption(GetSafeHwnd());
}
return CDialog::PreTranslateMessage(msg);
}
bool CTabsDlg::RectWithinDockManager ( CRect& rect )
bool CTabsDlg::RectWithinDockManager(CRect& rect)
{
CRect tabsRect,intersectionRect;
CRect tabsRect, intersectionRect;
m_Tabs.GetWindowRect ( tabsRect );
intersectionRect.IntersectRect( tabsRect , rect );
m_Tabs.GetWindowRect(tabsRect);
intersectionRect.IntersectRect(tabsRect, rect);
return !(intersectionRect.IsRectEmpty());
}
@@ -192,9 +574,9 @@ void CTabsDlg::OnLButtonDown(UINT nFlags, CPoint point)
}
void CTabsDlg::OnLButtonUp(UINT nFlags, CPoint point)
{
if ( m_DragTabActive && ((abs ( point.x - m_DragDownPoint.x ) > 50) || (abs ( point.y - m_DragDownPoint.y ) > 50)))
{
{
if (m_DragTabActive && ((abs(point.x - m_DragDownPoint.x) > 50) || (abs(point.y - m_DragDownPoint.y) > 50)))
{
HandleUndock();
m_DragTabActive = false;
}
@@ -202,19 +584,19 @@ void CTabsDlg::OnLButtonUp(UINT nFlags, CPoint point)
}
void CTabsDlg::HandleUndock ()
void CTabsDlg::HandleUndock()
{
TCITEM item;
item.mask = TCIF_PARAM;
int curSel = TabCtrl_GetCurSel ( m_Tabs.GetSafeHwnd());
int curSel = TabCtrl_GetCurSel(m_Tabs.GetSafeHwnd());
TabCtrl_GetItem (m_Tabs.GetSafeHwnd() , curSel , &item);
TabCtrl_GetItem(m_Tabs.GetSafeHwnd(), curSel, &item);
DockedWindowInfo* info = (DockedWindowInfo*)item.lParam;
ASSERT ( info );
ASSERT(info);
DockWindow ( info->m_ID , false );
DockWindow(info->m_ID, false);
}
void CTabsDlg::OnMouseMove(UINT nFlags, CPoint point)
@@ -223,69 +605,74 @@ void CTabsDlg::OnMouseMove(UINT nFlags, CPoint point)
}
void CTabsDlg::AddDockedWindow ( CWnd* wnd , int ID , int imageID , const CString& title , bool dock , pfnOnDockEvent dockCallback )
void CTabsDlg::AddDockedWindow(CWnd* wnd, int ID, int imageID, const CString& title, bool dock, pfnOnDockEvent dockCallback)
{
DockedWindowInfo* info = NULL;
m_Windows.Lookup( (WORD)ID , (void*&)info);
m_Windows.Lookup((WORD)ID, (void*&)info);
ASSERT ( wnd );
ASSERT ( info == NULL );
ASSERT(wnd);
ASSERT(info == NULL);
info = new DockedWindowInfo ( wnd , ID , imageID , title , dockCallback);
dock = true;
m_Windows.SetAt ( (WORD)ID , info );
DockWindow ( ID , dock );
info = new DockedWindowInfo(wnd, ID, imageID, title, dockCallback);
UpdateTabControlIndices ();
m_Windows.SetAt((WORD)ID, info);
DockWindow(ID, dock);
UpdateTabControlIndices();
TabsDlg_RefreshTopCaption(GetSafeHwnd());
}
void CTabsDlg::ShowAllWindows ( bool show )
void CTabsDlg::ShowAllWindows(bool show)
{
POSITION pos;
WORD ID;
DockedWindowInfo* info = NULL;
for( pos = m_Windows.GetStartPosition(); pos != NULL ; )
for (pos = m_Windows.GetStartPosition(); pos != NULL; )
{
m_Windows.GetNextAssoc( pos, ID, (void*&)info );
ASSERT ( info->m_Window );
if ( info->m_State == DockedWindowInfo::DOCKED )
m_Windows.GetNextAssoc(pos, ID, (void*&)info);
ASSERT(info->m_Window);
if (info->m_State == DockedWindowInfo::DOCKED)
{
info->m_Window->ShowWindow( show );
}
info->m_Window->ShowWindow(show);
}
}
}
void CTabsDlg::FocusWindow ( int ID )
void CTabsDlg::FocusWindow(int ID)
{
DockedWindowInfo* info = NULL;
m_Windows.Lookup( (WORD)ID , (void*&)info);
m_Windows.Lookup((WORD)ID, (void*&)info);
ASSERT ( info );
ASSERT ( info->m_Window );
if ( info->m_State == DockedWindowInfo::DOCKED )
ASSERT(info);
ASSERT(info->m_Window);
if (info->m_State == DockedWindowInfo::DOCKED)
{
TabCtrl_SetCurFocus ( m_Tabs.GetSafeHwnd() , info->m_TabControlIndex );
TabCtrl_SetCurFocus(m_Tabs.GetSafeHwnd(), info->m_TabControlIndex);
}
else
{
info->m_Container.SetFocus();
}
TabsDlg_RefreshTopCaption(GetSafeHwnd());
}
void CTabsDlg::UpdateTabControlIndices ()
{
void CTabsDlg::UpdateTabControlIndices()
{
TCITEM item;
item.mask = TCIF_PARAM;
DockedWindowInfo* info = NULL;
int itemCount = m_Tabs.GetItemCount();
for ( int i = 0 ; i < itemCount ; i ++ )
for (int i = 0; i < itemCount; i++)
{
if ( !m_Tabs.GetItem( i , &item ) )
if (!m_Tabs.GetItem(i, &item))
{
Sys_Error ( "UpdateTabControlIndices(): GetItem failed!\n" );
Sys_Error("UpdateTabControlIndices(): GetItem failed!\n");
}
info = (DockedWindowInfo*)item.lParam;
@@ -299,32 +686,32 @@ void CTabsDlg::OnDestroy()
DockedWindowInfo* info = NULL;
for ( int i = 0 ; i < m_Tabs.GetItemCount() ; i ++ )
for (int i = 0; i < m_Tabs.GetItemCount(); i++)
{
m_Tabs.GetItem( i , &item );
m_Tabs.GetItem(i, &item);
info = (DockedWindowInfo*)item.lParam;
ASSERT( info );
ASSERT(info);
delete info;
}
}
CDialog::OnDestroy();
}
bool CTabsDlg::IsDocked ( CWnd* wnd )
bool CTabsDlg::IsDocked(CWnd* wnd)
{
bool docked = false;
DockedWindowInfo* info = NULL;
CString placementName;
CString placementName;
POSITION pos;
WORD wID;
for( pos = m_Windows.GetStartPosition(); pos != NULL ; )
for (pos = m_Windows.GetStartPosition(); pos != NULL; )
{
m_Windows.GetNextAssoc( pos, wID, (void*&)info );
m_Windows.GetNextAssoc(pos, wID, (void*&)info);
if ( info->m_Window == wnd ) {
if (info->m_Window == wnd) {
docked = (info->m_State == DockedWindowInfo::DOCKED);
break;
}
@@ -332,21 +719,21 @@ bool CTabsDlg::IsDocked ( CWnd* wnd )
return docked;
}
void CTabsDlg::SaveWindowPlacement( int ID )
void CTabsDlg::SaveWindowPlacement(int ID)
{
DockedWindowInfo* info = NULL;
CString placementName;
CString placementName;
POSITION pos;
WORD wID = ID;
for( pos = m_Windows.GetStartPosition(); pos != NULL ; )
for (pos = m_Windows.GetStartPosition(); pos != NULL; )
{
m_Windows.GetNextAssoc( pos, wID, (void*&)info );
m_Windows.GetNextAssoc(pos, wID, (void*&)info);
if ( (info->m_State == DockedWindowInfo::FLOATING) && ((ID == -1) || (ID == info->m_ID))) {
if ((info->m_State == DockedWindowInfo::FLOATING) && ((ID == -1) || (ID == info->m_ID))) {
placementName = info->m_Title + "Placement";
::SaveWindowPlacement(info->m_Container.GetSafeHwnd() , placementName);
::SaveWindowPlacement(info->m_Container.GetSafeHwnd(), placementName);
}
}
}