mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-14 10:11:51 +02:00
739 lines
18 KiB
C++
739 lines
18 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
IceTech GPL Source Code
|
|
Copyright (C) 2026 Justin Marshall
|
|
|
|
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
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
IceTech 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 IceTech Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
In addition, the IceTech 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 IceTech 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 Justin Marshall, justinmarshall20@gmail.com
|
|
|
|
===========================================================================
|
|
*/
|
|
|
|
#include "precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#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*/)
|
|
: CDialog(ID, pParent)
|
|
{
|
|
m_DragTabActive = false;
|
|
}
|
|
|
|
BEGIN_MESSAGE_MAP(CTabsDlg, CDialog)
|
|
//}}AFX_MSG_MAP
|
|
// ON_NOTIFY(TCN_SELCHANGE, IDC_TAB1, OnTcnSelchangeTab1)
|
|
ON_WM_LBUTTONDOWN()
|
|
ON_WM_LBUTTONUP()
|
|
ON_WM_MOUSEMOVE()
|
|
ON_WM_DESTROY()
|
|
END_MESSAGE_MAP()
|
|
|
|
void CTabsDlg::DoDataExchange(CDataExchange* pDX)
|
|
{
|
|
CDialog::DoDataExchange(pDX);
|
|
DDX_Control(pDX, IDC_TAB_INSPECTOR, m_Tabs);
|
|
}
|
|
|
|
// CTabsDlg message handlers
|
|
|
|
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)
|
|
{
|
|
int ID = TabCtrl_GetCurSel(pNMHDR->hwndFrom);
|
|
|
|
if (ID >= 0)
|
|
{
|
|
TCITEM item;
|
|
item.mask = TCIF_PARAM;
|
|
|
|
ShowAllWindows(FALSE);
|
|
TabCtrl_GetItem(m_Tabs.GetSafeHwnd(), ID, &item);
|
|
|
|
DockedWindowInfo* info = (DockedWindowInfo*)item.lParam;
|
|
ASSERT(info);
|
|
|
|
info->m_TabControlIndex = ID;
|
|
info->m_Window->ShowWindow(TRUE);
|
|
TabsDlg_RefreshTopCaption(GetSafeHwnd());
|
|
}
|
|
}
|
|
|
|
void CTabsDlg::DockWindow(int ID, bool dock)
|
|
{
|
|
DockedWindowInfo* info = NULL;
|
|
m_Windows.Lookup((WORD)ID, (void*&)info);
|
|
|
|
ASSERT(info);
|
|
ASSERT(m_Tabs.GetSafeHwnd());
|
|
|
|
ShowAllWindows(FALSE);
|
|
|
|
if (!dock)
|
|
{
|
|
//make a containing window and assign the dialog to it
|
|
CRect rect;
|
|
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_Window->ShowWindow(TRUE);
|
|
|
|
info->m_Container.SetDockManager(this);
|
|
info->m_Container.ShowWindow(TRUE);
|
|
info->m_Container.SetDialog(info->m_Window, info->m_ID);
|
|
|
|
if (info->m_TabControlIndex >= 0)
|
|
{
|
|
m_Tabs.DeleteItem(info->m_TabControlIndex);
|
|
}
|
|
|
|
if (m_Tabs.GetItemCount() > 0)
|
|
{
|
|
m_Tabs.SetCurFocus(0);
|
|
}
|
|
|
|
CString placementName = info->m_Title + "Placement";
|
|
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_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);
|
|
|
|
//stupid hack to get the window reitself properly
|
|
rect.DeflateRect(0, 0, 0, 1);
|
|
MoveWindow(rect);
|
|
rect.InflateRect(0, 0, 0, 1);
|
|
MoveWindow(rect);
|
|
}
|
|
|
|
UpdateTabControlIndices();
|
|
FocusWindow(ID);
|
|
|
|
TabsDlg_InstallTopCaption(GetSafeHwnd());
|
|
TabsDlg_RefreshTopCaption(GetSafeHwnd());
|
|
|
|
if (info->m_DockCallback)
|
|
{
|
|
info->m_DockCallback(dock, info->m_ID, info->m_Window);
|
|
}
|
|
SaveWindowPlacement();
|
|
}
|
|
|
|
int CTabsDlg::PreTranslateMessage(MSG* msg)
|
|
{
|
|
if (msg->message == WM_LBUTTONDBLCLK && msg->hwnd == m_Tabs.GetSafeHwnd())
|
|
{
|
|
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);
|
|
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);
|
|
m_DragTabActive = false;
|
|
TabsDlg_RefreshTopCaption(GetSafeHwnd());
|
|
}
|
|
|
|
return CDialog::PreTranslateMessage(msg);
|
|
}
|
|
|
|
bool CTabsDlg::RectWithinDockManager(CRect& rect)
|
|
{
|
|
CRect tabsRect, intersectionRect;
|
|
|
|
m_Tabs.GetWindowRect(tabsRect);
|
|
intersectionRect.IntersectRect(tabsRect, rect);
|
|
|
|
return !(intersectionRect.IsRectEmpty());
|
|
}
|
|
|
|
void CTabsDlg::OnLButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
CDialog::OnLButtonDown(nFlags, 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)))
|
|
{
|
|
HandleUndock();
|
|
m_DragTabActive = false;
|
|
}
|
|
CDialog::OnLButtonUp(nFlags, point);
|
|
}
|
|
|
|
|
|
void CTabsDlg::HandleUndock()
|
|
{
|
|
TCITEM item;
|
|
item.mask = TCIF_PARAM;
|
|
|
|
int curSel = TabCtrl_GetCurSel(m_Tabs.GetSafeHwnd());
|
|
|
|
TabCtrl_GetItem(m_Tabs.GetSafeHwnd(), curSel, &item);
|
|
|
|
DockedWindowInfo* info = (DockedWindowInfo*)item.lParam;
|
|
ASSERT(info);
|
|
|
|
DockWindow(info->m_ID, false);
|
|
}
|
|
|
|
void CTabsDlg::OnMouseMove(UINT nFlags, CPoint point)
|
|
{
|
|
CDialog::OnMouseMove(nFlags, point);
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
ASSERT(wnd);
|
|
ASSERT(info == NULL);
|
|
|
|
dock = true;
|
|
|
|
info = new DockedWindowInfo(wnd, ID, imageID, title, dockCallback);
|
|
|
|
m_Windows.SetAt((WORD)ID, info);
|
|
DockWindow(ID, dock);
|
|
|
|
UpdateTabControlIndices();
|
|
TabsDlg_RefreshTopCaption(GetSafeHwnd());
|
|
}
|
|
|
|
void CTabsDlg::ShowAllWindows(bool show)
|
|
{
|
|
POSITION pos;
|
|
WORD ID;
|
|
DockedWindowInfo* info = 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)
|
|
{
|
|
info->m_Window->ShowWindow(show);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CTabsDlg::FocusWindow(int ID)
|
|
{
|
|
DockedWindowInfo* info = NULL;
|
|
m_Windows.Lookup((WORD)ID, (void*&)info);
|
|
|
|
ASSERT(info);
|
|
ASSERT(info->m_Window);
|
|
|
|
if (info->m_State == DockedWindowInfo::DOCKED)
|
|
{
|
|
TabCtrl_SetCurFocus(m_Tabs.GetSafeHwnd(), info->m_TabControlIndex);
|
|
}
|
|
else
|
|
{
|
|
info->m_Container.SetFocus();
|
|
}
|
|
|
|
TabsDlg_RefreshTopCaption(GetSafeHwnd());
|
|
}
|
|
|
|
void CTabsDlg::UpdateTabControlIndices()
|
|
{
|
|
TCITEM item;
|
|
item.mask = TCIF_PARAM;
|
|
|
|
DockedWindowInfo* info = NULL;
|
|
int itemCount = m_Tabs.GetItemCount();
|
|
|
|
for (int i = 0; i < itemCount; i++)
|
|
{
|
|
if (!m_Tabs.GetItem(i, &item))
|
|
{
|
|
Sys_Error("UpdateTabControlIndices(): GetItem failed!\n");
|
|
}
|
|
info = (DockedWindowInfo*)item.lParam;
|
|
|
|
info->m_TabControlIndex = i;
|
|
}
|
|
}
|
|
void CTabsDlg::OnDestroy()
|
|
{
|
|
TCITEM item;
|
|
item.mask = TCIF_PARAM;
|
|
|
|
DockedWindowInfo* info = NULL;
|
|
|
|
for (int i = 0; i < m_Tabs.GetItemCount(); i++)
|
|
{
|
|
m_Tabs.GetItem(i, &item);
|
|
info = (DockedWindowInfo*)item.lParam;
|
|
ASSERT(info);
|
|
|
|
delete info;
|
|
}
|
|
CDialog::OnDestroy();
|
|
}
|
|
|
|
|
|
bool CTabsDlg::IsDocked(CWnd* wnd)
|
|
{
|
|
bool docked = false;
|
|
DockedWindowInfo* info = NULL;
|
|
|
|
CString placementName;
|
|
POSITION pos;
|
|
WORD wID;
|
|
|
|
for (pos = m_Windows.GetStartPosition(); pos != NULL; )
|
|
{
|
|
m_Windows.GetNextAssoc(pos, wID, (void*&)info);
|
|
|
|
if (info->m_Window == wnd) {
|
|
docked = (info->m_State == DockedWindowInfo::DOCKED);
|
|
break;
|
|
}
|
|
}
|
|
return docked;
|
|
}
|
|
|
|
void CTabsDlg::SaveWindowPlacement(int ID)
|
|
{
|
|
DockedWindowInfo* info = NULL;
|
|
|
|
CString placementName;
|
|
POSITION pos;
|
|
WORD wID = ID;
|
|
|
|
for (pos = m_Windows.GetStartPosition(); pos != NULL; )
|
|
{
|
|
m_Windows.GetNextAssoc(pos, wID, (void*&)info);
|
|
|
|
if ((info->m_State == DockedWindowInfo::FLOATING) && ((ID == -1) || (ID == info->m_ID))) {
|
|
placementName = info->m_Title + "Placement";
|
|
::SaveWindowPlacement(info->m_Container.GetSafeHwnd(), placementName);
|
|
}
|
|
}
|
|
} |