From bd77ca8061e7f6f40c7e1895dda96eb82f0f7ef0 Mon Sep 17 00:00:00 2001 From: DJRobX Date: Fri, 2 Nov 2007 09:19:38 +0000 Subject: [PATCH] Fix debug assertion on link options dialog Fix tab control offset problem Enhance tab controls by graying out inoperable tabs Fix locked aspect ratio in Direct3D mode git-svn-id: https://svn.code.sf.net/p/vbam/code/trunk@14 a31d4220-a93d-0410-bf67-fe4944624d44 --- res/VBA.rc | 28 +++-- src/win32/Direct3D.cpp | 2 +- src/win32/LinkOptions.cpp | 246 ++++++++++++++++++++++++++++++++++++-- src/win32/LinkOptions.h | 28 ++++- 4 files changed, 277 insertions(+), 27 deletions(-) diff --git a/res/VBA.rc b/res/VBA.rc index 913ac89f..2b5a61b1 100644 --- a/res/VBA.rc +++ b/res/VBA.rc @@ -71,23 +71,23 @@ END // Dialog // -IDD_LINKTAB DIALOG 0, 0, 225, 162 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +IDD_LINKTAB DIALOGEX 0, 0, 254, 203 +STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Link Options" -FONT 8, "MS Sans Serif" +FONT 8, "MS Sans Serif", 0, 0, 0x0 BEGIN - CONTROL "Tab1",IDC_TAB1,"SysTabControl32",0x0,7,7,210,130 - PUSHBUTTON "OK",ID_OK,31,140,60,15 - PUSHBUTTON "Cancel",ID_CANCEL,114,140,57,15 + CONTROL "Tab1",IDC_TAB1,"SysTabControl32",0x0,9,6,240,162 + PUSHBUTTON "OK",ID_OK,57,180,60,15 + PUSHBUTTON "Cancel",ID_CANCEL,140,180,57,15 END -IDD_LINKTAB1 DIALOG 0, 0, 210, 130 +IDD_LINKTAB1 DIALOGEX 0, 0, 184, 79 STYLE DS_SETFONT | WS_CHILD | WS_VISIBLE -FONT 8, "MS Sans Serif" +FONT 8, "MS Sans Serif", 0, 0, 0x0 BEGIN LTEXT "Link timeout (in milliseconds)",IDC_STATIC,17,12,92,16 EDITTEXT IDC_LINKTIMEOUT,116,10,53,14,ES_AUTOHSCROLL | ES_NUMBER - CONTROL "Single Computer",IDC_LINK_SINGLE,"Button",BS_AUTORADIOBUTTON,17,27,71,16 + CONTROL "Single Computer",IDC_LINK_SINGLE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,17,27,71,16 CONTROL "Network",IDC_LINK_LAN,"Button",BS_AUTORADIOBUTTON,17,43,70,16 END @@ -106,9 +106,9 @@ BEGIN CONTROL "Speed hacks",IDC_SSPEED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,76,70,57,12 END -IDD_LINKTAB3 DIALOG 0, 0, 210, 108 +IDD_LINKTAB3 DIALOGEX 0, 0, 188, 108 STYLE DS_SETFONT | WS_CHILD -FONT 8, "MS Sans Serif" +FONT 8, "MS Sans Serif", 0, 0, 0x0 BEGIN CONTROL "TCP/IP",IDC_CLINKTCP,"Button",BS_AUTORADIOBUTTON | WS_GROUP,58,20,39,12 CONTROL "UDP",IDC_CLINKUDP,"Button",BS_AUTORADIOBUTTON | WS_DISABLED,118,20,32,12 @@ -1119,6 +1119,12 @@ END #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO BEGIN + IDD_LINKTAB, DIALOG + BEGIN + RIGHTMARGIN, 225 + BOTTOMMARGIN, 162 + END + IDD_OPENDLG, DIALOG BEGIN RIGHTMARGIN, 165 diff --git a/src/win32/Direct3D.cpp b/src/win32/Direct3D.cpp index 315412fd..6b22ce38 100644 --- a/src/win32/Direct3D.cpp +++ b/src/win32/Direct3D.cpp @@ -131,7 +131,7 @@ Direct3DDisplay::Direct3DDisplay() width = 0; height = 0; filterDisabled = false; - keepAspectRatio = true; // theApp.d3dKeepAspectRatio; + keepAspectRatio = false; // theApp.d3dKeepAspectRatio; lockableBuffer = false; } diff --git a/src/win32/LinkOptions.cpp b/src/win32/LinkOptions.cpp index 690f6608..c337c0d5 100644 --- a/src/win32/LinkOptions.cpp +++ b/src/win32/LinkOptions.cpp @@ -48,7 +48,6 @@ void LinkOptions::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(LinkOptions) - DDX_Control(pDX, IDC_TAB1, m_tabctrl); //}}AFX_DATA_MAP } @@ -59,13 +58,14 @@ BOOL LinkOptions::OnInitDialog(){ CDialog::OnInitDialog(); + m_tabctrl.SubclassDlgItem(IDC_TAB1, this); + tabitem.mask = TCIF_TEXT; for(i=0;i<3;i++){ tabitem.pszText = tabtext[i]; m_tabctrl.InsertItem(i, &tabitem); } - m_tabctrl.m_tabdialog[0]->Create(IDD_LINKTAB1, this); m_tabctrl.m_tabdialog[1]->Create(IDD_LINKTAB2, this); m_tabctrl.m_tabdialog[2]->Create(IDD_LINKTAB3, this); @@ -81,6 +81,15 @@ BOOL LinkOptions::OnInitDialog(){ } + BOOL LinkOptions::PreTranslateMessage(MSG* pMsg) + { + return m_tabctrl.TranslatePropSheetMsg(pMsg) ? TRUE : + CDialog::PreTranslateMessage(pMsg); + } + + + + BEGIN_MESSAGE_MAP(LinkOptions, CDialog) //{{AFX_MSG_MAP(LinkOptions) ON_NOTIFY(TCN_SELCHANGE, IDC_TAB1, OnSelchangeTab1) @@ -205,24 +214,233 @@ void LinkOptions::OnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult) *pResult = 0; } +IMPLEMENT_DYNAMIC(CMyTabCtrl, CTabCtrl) +BEGIN_MESSAGE_MAP(CMyTabCtrl, CTabCtrl) + ON_NOTIFY_REFLECT(TCN_SELCHANGING, OnSelChanging) +END_MESSAGE_MAP() + +BOOL CMyTabCtrl::SubclassDlgItem(UINT nID, CWnd* pParent) +{ + if (!CTabCtrl::SubclassDlgItem(nID, pParent)) + return FALSE; + + ModifyStyle(0, TCS_OWNERDRAWFIXED); + + // If first tab is disabled, go to next enabled tab + if (!IsTabEnabled(0)) { + int iTab = NextEnabledTab(0, TRUE); + SetActiveTab(iTab); + } + return TRUE; +} + +BOOL CMyTabCtrl::IsTabEnabled(int iTab) +{ + if (!lanlink.active && iTab > 0) + return false; + return true; +} + +////////////////// +// Draw the tab: mimic SysTabControl32, except use gray if tab is disabled +// +void CMyTabCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) +{ + DRAWITEMSTRUCT& ds = *lpDrawItemStruct; + + int iItem = ds.itemID; + + // Get tab item info + char text[128]; + TCITEM tci; + tci.mask = TCIF_TEXT; + tci.pszText = text; + tci.cchTextMax = sizeof(text); + GetItem(iItem, &tci); + + // use draw item DC + CDC dc; + dc.Attach(ds.hDC); + + // calculate text rectangle and color + CRect rc = ds.rcItem; + rc += CPoint(1,4); // ?? by trial and error + + // draw the text + OnDrawText(dc, rc, text, !IsTabEnabled(iItem)); + + dc.Detach(); +} + +////////////////// +// Draw tab text. You can override to use different color/font. +// +void CMyTabCtrl::OnDrawText(CDC& dc, CRect rc, + CString sText, BOOL bDisabled) +{ + dc.SetTextColor(GetSysColor(bDisabled ? COLOR_3DHILIGHT : COLOR_BTNTEXT)); + dc.DrawText(sText, &rc, DT_CENTER|DT_VCENTER); + + if (bDisabled) { + // disabled: draw again shifted northwest for shadow effect + rc += CPoint(-1,-1); + dc.SetTextColor(GetSysColor(COLOR_GRAYTEXT)); + dc.DrawText(sText, &rc, DT_CENTER|DT_VCENTER); + } +} + +////////////////// +// Selection is changing: disallow if tab is disabled +// +void CMyTabCtrl::OnSelChanging(NMHDR* pnmh, LRESULT* pRes) +{ + TRACE("CMyTabCtrl::OnSelChanging\n"); + + // Figure out index of new tab we are about to go to, as opposed + // to the current one we're at. Believe it or not, Windows doesn't + // pass this info + // + TC_HITTESTINFO htinfo; + GetCursorPos(&htinfo.pt); + ScreenToClient(&htinfo.pt); + int iNewTab = HitTest(&htinfo); + + if (iNewTab >= 0 && !IsTabEnabled(iNewTab)) + *pRes = TRUE; // tab disabled: prevent selection +} + +////////////////// +// Trap arrow-left key to skip disabled tabs. +// This is the only way to know where we're coming from--ie from +// arrow-left (prev) or arrow-right (next). +// +BOOL CMyTabCtrl::PreTranslateMessage(MSG* pMsg) +{ + if (pMsg->message == WM_KEYDOWN && + (pMsg->wParam == VK_LEFT || pMsg->wParam == VK_RIGHT)) { + + int iNewTab = (pMsg->wParam == VK_LEFT) ? + PrevEnabledTab(GetCurSel(), FALSE) : + NextEnabledTab(GetCurSel(), FALSE); + if (iNewTab >= 0) + SetActiveTab(iNewTab); + return TRUE; + } + return CTabCtrl::PreTranslateMessage(pMsg); +} + +//////////////// +// Translate parent property sheet message. Translates Control-Tab and +// Control-Shift-Tab keys. These are normally handled by the property +// sheet, so you must call this function from your prop sheet's +// PreTranslateMessage function. +// +BOOL CMyTabCtrl::TranslatePropSheetMsg(MSG* pMsg) +{ + WPARAM key = pMsg->wParam; + if (pMsg->message == WM_KEYDOWN && GetAsyncKeyState(VK_CONTROL) < 0 && + (key == VK_TAB || key == VK_PRIOR || key == VK_NEXT)) { + + int iNewTab = (key==VK_PRIOR || GetAsyncKeyState(VK_SHIFT) < 0) ? + PrevEnabledTab(GetCurSel(), TRUE) : + NextEnabledTab(GetCurSel(), TRUE); + if (iNewTab >= 0) + SetActiveTab(iNewTab); + return TRUE; + } + return FALSE; +} + +////////////////// +// Helper to set the active page, when moving backwards (left-arrow and +// Control-Shift-Tab). Must simulate Windows messages to tell parent I +// am changing the tab; SetCurSel does not do this!! +// +// In normal operation, this fn will always succeed, because I don't call it +// unless I already know IsTabEnabled() = TRUE; but if you call SetActiveTab +// with a random value, it could fail. +// +BOOL CMyTabCtrl::SetActiveTab(UINT iNewTab) +{ + TRACE("CMyTabCtrl::SetActiveTab\n"); + + // send the parent TCN_SELCHANGING + NMHDR nmh; + nmh.hwndFrom = m_hWnd; + nmh.idFrom = GetDlgCtrlID(); + nmh.code = TCN_SELCHANGING; + + if (GetParent()->SendMessage(WM_NOTIFY, nmh.idFrom, (LPARAM)&nmh) >=0) { + // OK to change: set the new tab + SetCurSel(iNewTab); + + // send parent TCN_SELCHANGE + nmh.code = TCN_SELCHANGE; + GetParent()->SendMessage(WM_NOTIFY, nmh.idFrom, (LPARAM)&nmh); + return TRUE; + } + return FALSE; +} + +///////////////// +// Return the index of the next enabled tab after a given index, or -1 if none +// (0 = first tab). +// If bWrap is TRUE, wrap from beginning to end; otherwise stop at zero. +// +int CMyTabCtrl::NextEnabledTab(int iCurrentTab, BOOL bWrap) +{ + int nTabs = GetItemCount(); + for (int iTab = iCurrentTab+1; iTab != iCurrentTab; iTab++) { + if (iTab >= nTabs) { + if (!bWrap) + return -1; + iTab = 0; + } + if (IsTabEnabled(iTab)) { + return iTab; + } + } + return -1; +} + +///////////////// +// Return the index of the previous enabled tab before a given index, or -1. +// (0 = first tab). +// If bWrap is TRUE, wrap from beginning to end; otherwise stop at zero. +// +int CMyTabCtrl::PrevEnabledTab(int iCurrentTab, BOOL bWrap) +{ + for (int iTab = iCurrentTab-1; iTab != iCurrentTab; iTab--) { + if (iTab < 0) { + if (!bWrap) + return -1; + iTab = GetItemCount() - 1; + } + if (IsTabEnabled(iTab)) { + return iTab; + } + } + return -1; +} + + void CMyTabCtrl::OnSwitchTabs(void) { - CRect tabRect, itemRect; - int nX, nY, nXc, nYc, i; + CRect clientRect, wndRect; + int i; - GetClientRect(&tabRect); - GetItemRect(0, &itemRect); - - nX=itemRect.left+10; - nY=itemRect.bottom+12; - nXc=tabRect.right-itemRect.left-2; - nYc=tabRect.bottom-nY+8; + GetClientRect(clientRect); + AdjustRect(FALSE, clientRect); + GetWindowRect(wndRect); + GetParent()->ScreenToClient(wndRect); + clientRect.OffsetRect(wndRect.left, wndRect.top); - if(lanlink.active==0) SetCurSel(0); + if(lanlink.active==0) + SetCurSel(0); for(i=0;i<3;i++){ if(i==GetCurSel()){ - m_tabdialog[i]->SetWindowPos(&wndTop, nX, nY, nXc, nYc, SWP_SHOWWINDOW); + m_tabdialog[i]->SetWindowPos(&wndTop, clientRect.left, clientRect.top, clientRect.Width(), clientRect.Height(), SWP_SHOWWINDOW); } else { m_tabdialog[i]->ShowWindow(SW_HIDE); } @@ -242,12 +460,14 @@ void LinkGeneral::OnRadio1() { m_type = 0; lanlink.active = 0; + GetParent()->Invalidate(); } void LinkGeneral::OnRadio2() { m_type = 1; lanlink.active = 1; + GetParent()->Invalidate(); } BOOL LinkGeneral::OnInitDialog(){ diff --git a/src/win32/LinkOptions.h b/src/win32/LinkOptions.h index 2bb4b6c2..f1ca0e8c 100644 --- a/src/win32/LinkOptions.h +++ b/src/win32/LinkOptions.h @@ -7,13 +7,35 @@ // LinkOptions.h : header file // -class CMyTabCtrl : public CTabCtrl -{ +class CMyTabCtrl : public CTabCtrl { + DECLARE_DYNAMIC(CMyTabCtrl) public: CMyTabCtrl(void); ~CMyTabCtrl(void); + + BOOL IsTabEnabled(int iTab); // you must override + BOOL TranslatePropSheetMsg(MSG* pMsg); // call from prop sheet + BOOL SubclassDlgItem(UINT nID, CWnd* pParent); // non-virtual override + + // helpers + int NextEnabledTab(int iTab, BOOL bWrap); // get next enabled tab + int PrevEnabledTab(int iTab, BOOL bWrap); // get prev enabled tab + BOOL SetActiveTab(UINT iNewTab); // set tab (fail if disabled) + CDialog *m_tabdialog[3]; + void OnSwitchTabs(void); +protected: + DECLARE_MESSAGE_MAP() + afx_msg void OnSelChanging(NMHDR* pNmh, LRESULT* pRes); + + // MFC overrides + virtual BOOL PreTranslateMessage(MSG* pMsg); + virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); + + // override to draw text only; eg, colored text or different font + virtual void OnDrawText(CDC& dc, CRect rc, CString sText, BOOL bDisabled); + }; ///////////////////////////////////////////////////////////////////////////// @@ -73,6 +95,8 @@ public: // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(LinkOptions) + public: + virtual BOOL PreTranslateMessage(MSG* pMsg); protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL