mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 08:11:10 +02:00
Added captions to windows.
This commit is contained in:
@@ -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, ÷rRect, (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;
|
||||
|
||||
@@ -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, ÷rRect, (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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user