TabCtrl.cpp 21 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082
  1. // SheetCtrl.cpp : implementation file
  2. //
  3. #include "stdafx.h"
  4. #include "TabCtrl.h"
  5. #ifdef _DEBUG
  6. #define new DEBUG_NEW
  7. #undef THIS_FILE
  8. static char THIS_FILE[] = __FILE__;
  9. #endif
  10. #define TEXT_PAD 7
  11. #define SPIN_PAD 3
  12. #define SHIFT_UNITS 10
  13. #define COLOR_WHITE RGB(255, 255, 255)
  14. #define COLOR_GRAY RGB(128, 128, 128)
  15. #define COLOR_MEDGRAY GetSysColor(COLOR_BTNFACE)
  16. #define COLOR_DARKGRAY RGB(64, 64, 64)
  17. #define ID_SCROLL_TIMER 0x1010
  18. #define VK_TILDAE 0xC0
  19. /////////////////////////////////////////////////////////////////////////////
  20. // CTabCtrlEx
  21. CTabCtrlEx::CTabCtrlEx()
  22. {
  23. m_nStyle = 0;
  24. m_nActiveTab = -1;
  25. m_nTabHeight = 19;
  26. m_btnState[0] = BtnUp;
  27. m_btnState[1] = BtnUp;
  28. m_bBtnEnabled[0] = false;
  29. m_bBtnEnabled[1] = false;
  30. m_nLeftShifted = 0;
  31. m_nPrevWidth = 0;
  32. m_pFntText = NULL;
  33. m_pFntBoldText = NULL;
  34. m_bSetFocusToNewlySelectedTab = true;
  35. m_SelectedColor = (COLORREF)GetSysColor(COLOR_BTNFACE);
  36. m_NonSelectedColor = RGB(255, 251, 233);
  37. }
  38. CTabCtrlEx::~CTabCtrlEx()
  39. {
  40. if (m_pFntText)
  41. delete m_pFntText;
  42. m_pFntText = NULL;
  43. if (m_pFntBoldText)
  44. delete m_pFntBoldText;
  45. m_pFntBoldText = NULL;
  46. }
  47. BEGIN_MESSAGE_MAP(CTabCtrlEx, CWnd)
  48. //{{AFX_MSG_MAP(CTabCtrlEx)
  49. ON_WM_PAINT()
  50. ON_WM_CREATE()
  51. ON_WM_LBUTTONDOWN()
  52. ON_WM_MOUSEMOVE()
  53. ON_WM_LBUTTONUP()
  54. ON_WM_SIZE()
  55. ON_WM_TIMER()
  56. ON_WM_SHOWWINDOW()
  57. //}}AFX_MSG_MAP
  58. END_MESSAGE_MAP()
  59. /////////////////////////////////////////////////////////////////////////////
  60. // CTabCtrlEx message handlers
  61. BOOL CTabCtrlEx::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
  62. {
  63. // Get the sheet styles alone
  64. m_nStyle = short(dwStyle & 0xFFFF);
  65. // Remove the sheet styles and create the window
  66. dwStyle &= 0xFFFF0000;
  67. // If the window border style is set, change it to sheet border style
  68. if (dwStyle & WS_BORDER)
  69. {
  70. m_nStyle |= SCS_BORDER;
  71. dwStyle &= ~WS_BORDER;
  72. }
  73. // Register the class
  74. WNDCLASS wndClass;
  75. memset(&wndClass, 0, sizeof(wndClass));
  76. BOOL bRet = false;
  77. HINSTANCE hInst = AfxGetInstanceHandle();
  78. if (::GetClassInfo(hInst, SHEET_CLASSNAME, &wndClass))
  79. {
  80. bRet = (wndClass.style == SHEET_CLASSTYLE);
  81. }
  82. if (bRet == FALSE)
  83. {
  84. memset(&wndClass, 0, sizeof(wndClass));
  85. wndClass.style = SHEET_CLASSTYLE;
  86. wndClass.lpfnWndProc = ::DefWindowProc;
  87. wndClass.cbClsExtra = wndClass.cbWndExtra = 0;
  88. wndClass.hInstance = hInst;
  89. wndClass.hIcon = NULL;
  90. wndClass.hCursor = NULL;
  91. wndClass.hbrBackground = NULL;
  92. wndClass.lpszMenuName = NULL;
  93. wndClass.lpszClassName = SHEET_CLASSNAME;
  94. if ((bRet = AfxRegisterClass(&wndClass)) == FALSE)
  95. ASSERT(FALSE);
  96. }
  97. if (bRet)
  98. bRet = CWnd::Create(SHEET_CLASSNAME, _T(""), dwStyle, rect, pParentWnd, nID);
  99. return bRet;
  100. }
  101. int CTabCtrlEx::OnCreate(LPCREATESTRUCT lpCreateStruct)
  102. {
  103. if (CWnd::OnCreate(lpCreateStruct) == -1)
  104. return -1;
  105. // Create the brushes, pens
  106. m_brSelectedTab.CreateSolidBrush(m_SelectedColor);
  107. m_brNonSelectedTab.CreateSolidBrush(m_NonSelectedColor);
  108. m_penGray.CreatePen(PS_SOLID, 1, RGB(172, 168, 153));
  109. m_penBlack.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
  110. SetTabHeight(m_nTabHeight);
  111. return 0;
  112. }
  113. void CTabCtrlEx::SetTabHeight(int nTabHeight)
  114. {
  115. m_nTabHeight = nTabHeight;
  116. // Delete the old font and create a new one
  117. if (m_pFntText)
  118. delete m_pFntText;
  119. m_pFntText = new CFont;
  120. if (m_pFntText)
  121. {
  122. // Set the regular font
  123. m_pFntText->CreateFont(-(m_nTabHeight*7/10), 0, 0, 0, FW_LIGHT, FALSE, FALSE, 0, DEFAULT_CHARSET,
  124. OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, _T("@Arial Unicode MS"));
  125. }
  126. // Delete the old font and create a new one
  127. if (m_pFntBoldText)
  128. delete m_pFntBoldText;
  129. m_pFntBoldText = new CFont;
  130. if (m_pFntBoldText)
  131. {
  132. // Set the bold font
  133. m_pFntBoldText->CreateFont(-(m_nTabHeight*7/10), 0, 0, 0, FW_SEMIBOLD, FALSE, FALSE, 0, DEFAULT_CHARSET,
  134. OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, _T("@Arial Unicode MS"));
  135. }
  136. }
  137. bool CTabCtrlEx::AddItem(const CString& csTabTitle, CWnd* pTabWnd)
  138. {
  139. return InsertItem(m_Tabs.GetSize(), csTabTitle, pTabWnd);
  140. }
  141. bool CTabCtrlEx::InsertItem(int nTab, const CString& csTabTitle, CWnd* pTabWnd)
  142. {
  143. CTab tab;
  144. tab.csTitle = csTabTitle;
  145. tab.pWnd = pTabWnd;
  146. tab.lWidth = GetTextWidth(csTabTitle);
  147. tab.clrUnderline = -1;
  148. m_Tabs.InsertAt(nTab, tab);
  149. if(nTab <= m_nActiveTab)
  150. m_nActiveTab++;
  151. // Redraw the window
  152. RedrawWindow();
  153. return true;
  154. }
  155. bool CTabCtrlEx::ReplaceItem(int nTab, const CString &csTabTitle, CWnd* pTabWnd)
  156. {
  157. if ((nTab >= 0) && (nTab < m_Tabs.GetSize()))
  158. {
  159. if(m_Tabs[nTab].pWnd)
  160. m_Tabs[nTab].pWnd->ShowWindow(SW_HIDE);
  161. m_Tabs[nTab].csTitle = csTabTitle;
  162. m_Tabs[nTab].pWnd = pTabWnd;
  163. m_Tabs[nTab].lWidth = GetTextWidth(csTabTitle);
  164. if(pTabWnd)
  165. pTabWnd->ShowWindow(SW_SHOW);
  166. SetActiveTab(m_nActiveTab);
  167. return true;
  168. }
  169. return false;
  170. }
  171. bool CTabCtrlEx::DeleteItem(int nTab)
  172. {
  173. if ((nTab >= 0) && (nTab < m_Tabs.GetSize()))
  174. {
  175. // Remove the tab
  176. m_Tabs.RemoveAt(nTab);
  177. // Set the new active tab
  178. if (nTab == GetActiveTab())
  179. {
  180. if(nTab > 0)
  181. nTab--;
  182. SetActiveTab(nTab, true);
  183. }
  184. // Redraw the window
  185. RedrawWindow();
  186. return true;
  187. }
  188. return false;
  189. }
  190. bool CTabCtrlEx::DeleteAllItems()
  191. {
  192. // Remove all the tab
  193. m_Tabs.RemoveAll();
  194. // Reset the active tab
  195. m_nActiveTab = -1;
  196. // Redraw the window
  197. RedrawWindow();
  198. return true;
  199. }
  200. void CTabCtrlEx::UnderlineTabTitle(int nTab, COLORREF clr)
  201. {
  202. if ((nTab >= 0) && (nTab < m_Tabs.GetSize()))
  203. {
  204. m_Tabs[nTab].clrUnderline = clr;
  205. Invalidate();
  206. }
  207. }
  208. int CTabCtrlEx::GetTextWidth(const CString& csText)
  209. {
  210. CDC *pDC = GetDC();
  211. if (pDC)
  212. {
  213. // Select the font
  214. CFont *pPrevFont = pDC->SelectObject(m_pFntBoldText);
  215. // Get the width
  216. int nWidth = pDC->GetTextExtent(csText).cx;
  217. // Restore the font
  218. pDC->SelectObject(pPrevFont);
  219. ReleaseDC(pDC);
  220. return (nWidth + 2*TEXT_PAD);
  221. }
  222. return 0;
  223. }
  224. int CTabCtrlEx::GetDisplayWidth()
  225. {
  226. CRect rcWnd;
  227. GetClientRect(rcWnd);
  228. // If all the tabs cannot fit, then the spinner is visiable
  229. if (GetTabsWidth() > rcWnd.Width())
  230. return rcWnd.Width()-GetSpinnerWidth();
  231. return rcWnd.Width();
  232. }
  233. int CTabCtrlEx::GetTabsWidth()
  234. {
  235. int nWidth = 0;
  236. // Get the width for all tabs
  237. for (int iTab=0; iTab<m_Tabs.GetSize(); iTab++)
  238. nWidth += m_Tabs[iTab].lWidth;
  239. nWidth += TEXT_PAD;
  240. return nWidth;
  241. }
  242. int CTabCtrlEx::GetSpinnerWidth()
  243. {
  244. int nSpinWidth = m_nTabHeight-2*1;
  245. return (2*nSpinWidth + SPIN_PAD);
  246. }
  247. void CTabCtrlEx::GetFullRect(CRect& rcTab)
  248. {
  249. // Get the area of the full sheet window
  250. GetClientRect(rcTab);
  251. // Get the full tab area
  252. if (m_nStyle & SCS_TOP)
  253. rcTab.bottom = m_nTabHeight;
  254. else
  255. rcTab.top = rcTab.Height()-m_nTabHeight;
  256. }
  257. void CTabCtrlEx::GetTabListRect(CRect& rcTab)
  258. {
  259. // Get the full tab area
  260. GetFullRect(rcTab);
  261. // Get the area for the tabs
  262. if (m_nStyle & SCS_TOP)
  263. rcTab.bottom -= 1;
  264. else
  265. rcTab.top += 1;
  266. }
  267. void CTabCtrlEx::GetTabRect(int nTab, CRect& rcTab)
  268. {
  269. // Get the area for the tabs
  270. GetTabListRect(rcTab);
  271. rcTab.top += 2;
  272. int nLeft = 0;
  273. // Get the area for the current tab
  274. for (int iTab=0; iTab<m_Tabs.GetSize(); iTab++)
  275. {
  276. if (iTab == nTab)
  277. {
  278. rcTab.left = nLeft;
  279. rcTab.right = nLeft+m_Tabs[iTab].lWidth;
  280. break;
  281. }
  282. nLeft += m_Tabs[iTab].lWidth;
  283. }
  284. }
  285. void CTabCtrlEx::GetSpinnerRect(CRect& rcSpin)
  286. {
  287. // Get the area for the tabs
  288. GetTabListRect(rcSpin);
  289. // If all the tabs cannot fit, then show the spinner
  290. if (GetTabsWidth() > rcSpin.Width())
  291. rcSpin.left = rcSpin.right-GetSpinnerWidth();
  292. // Set the spinner width to zero
  293. else
  294. rcSpin.SetRectEmpty();
  295. }
  296. void CTabCtrlEx::GetButtonRect(int nBtn, CRect& rcBtn)
  297. {
  298. GetSpinnerRect(rcBtn);
  299. rcBtn.DeflateRect(SPIN_PAD, 0, 0, 0);
  300. rcBtn.DeflateRect(1, 1);
  301. if (nBtn == 0)
  302. rcBtn.right = rcBtn.left + rcBtn.Width()/2;
  303. else if (nBtn == 1)
  304. rcBtn.left = rcBtn.left + rcBtn.Width()/2;
  305. else
  306. rcBtn.SetRectEmpty();
  307. }
  308. CString CTabCtrlEx::GetTabTitle(int nTab)
  309. {
  310. if ((nTab >= 0) && (nTab < m_Tabs.GetSize()))
  311. return m_Tabs[nTab].csTitle;
  312. return "";
  313. }
  314. bool CTabCtrlEx::SetTabTitle(int nTab, const CString& csTabTitle)
  315. {
  316. if ((nTab >= 0) && (nTab < m_Tabs.GetSize()))
  317. {
  318. m_Tabs[nTab].csTitle = csTabTitle;
  319. m_Tabs[nTab].lWidth = GetTextWidth(csTabTitle);
  320. // Redraw the window
  321. RedrawWindow();
  322. return true;
  323. }
  324. return false;
  325. }
  326. bool CTabCtrlEx::SetTabItemData(int nTab, long lItemData)
  327. {
  328. if ((nTab >= 0) && (nTab < m_Tabs.GetSize()))
  329. {
  330. m_Tabs[nTab].lItemData = lItemData;
  331. return true;
  332. }
  333. return false;
  334. }
  335. long CTabCtrlEx::GetTabItemData(int nTab)
  336. {
  337. if ((nTab >= 0) && (nTab < m_Tabs.GetSize()))
  338. {
  339. return m_Tabs[nTab].lItemData;
  340. }
  341. return -1;
  342. }
  343. int CTabCtrlEx::GetActiveTab()
  344. {
  345. return m_nActiveTab;
  346. }
  347. int CTabCtrlEx::GetTabCount()
  348. {
  349. return m_Tabs.GetSize();
  350. }
  351. void CTabCtrlEx::SetActiveTab(int nTab, bool bNotify)
  352. {
  353. ActivateTab(nTab, bNotify);
  354. }
  355. void CTabCtrlEx::ActivateTab(int nTab, bool bNotify, bool bOnSize)
  356. {
  357. if ((nTab >= 0) && (nTab < m_Tabs.GetSize()))
  358. {
  359. // Set the new active tab
  360. int nOldTab = GetActiveTab();
  361. m_nActiveTab = nTab;
  362. // Resize the tab windows
  363. ResizeTabWindow(nOldTab, GetActiveTab(), bNotify, bOnSize);
  364. // Make the tab visible
  365. MakeTabVisible(GetActiveTab());
  366. // Redraw the tabs
  367. if (bOnSize)
  368. InvalidateRect(NULL);
  369. else
  370. RedrawWindow();
  371. }
  372. }
  373. void CTabCtrlEx::ResizeTabWindow(int nOldTab, int nNewTab, bool bNotify, bool bOnSize)
  374. {
  375. long lOldItemData = -1;
  376. long lNewItemData = -1;
  377. if ((nOldTab >= 0) && nOldTab < GetTabCount())
  378. {
  379. lOldItemData = m_Tabs[nOldTab].lItemData;
  380. CWnd* pPrevWnd = m_Tabs[nOldTab].pWnd;
  381. // Hide the previous tab
  382. if (pPrevWnd && IsWindow(pPrevWnd->m_hWnd))
  383. pPrevWnd->ShowWindow(SW_HIDE);
  384. }
  385. if ((nNewTab >= 0) && nNewTab < GetTabCount())
  386. {
  387. CRect rcWnd;
  388. //GetClientRect(rcWnd);
  389. GetWindowRect(rcWnd);
  390. lNewItemData = m_Tabs[nNewTab].lItemData;
  391. CWnd *pParentWnd = GetParent();
  392. if (pParentWnd && IsWindow(pParentWnd->m_hWnd))
  393. pParentWnd->ScreenToClient(rcWnd);
  394. int nPad = 0;
  395. CWnd* pNextWnd = m_Tabs[nNewTab].pWnd;;
  396. // Show the new tab and bring it to the top, set the focus to the new tab
  397. if (pNextWnd && IsWindow(pNextWnd->m_hWnd))
  398. {
  399. // Resize the tab window
  400. if (m_nStyle & SCS_TOP)
  401. {
  402. pNextWnd->SetWindowPos(&wndTop, rcWnd.left+nPad, rcWnd.top+m_nTabHeight+nPad,
  403. rcWnd.Width()-2*nPad, rcWnd.Height()-m_nTabHeight-2*nPad, SWP_SHOWWINDOW);
  404. }
  405. else
  406. {
  407. pNextWnd->SetWindowPos(&wndTop, rcWnd.left+nPad, rcWnd.top+nPad,
  408. rcWnd.Width()-2*nPad, rcWnd.Height()-m_nTabHeight-2*nPad, SWP_SHOWWINDOW);
  409. }
  410. if(m_bSetFocusToNewlySelectedTab)
  411. {
  412. // Set the focus
  413. if (bOnSize == FALSE)
  414. pNextWnd->SetFocus();
  415. }
  416. }
  417. }
  418. if (bNotify)
  419. {
  420. // Send a notification message to the parent window
  421. CWnd *pParentWnd = GetParent();
  422. if (pParentWnd && IsWindow(pParentWnd->m_hWnd))
  423. {
  424. NMTABCHANGE nmTab;
  425. ZeroMemory(&nmTab, sizeof(nmTab));
  426. nmTab.hdr.code = SN_SETACTIVETAB;
  427. nmTab.hdr.hwndFrom = GetSafeHwnd();
  428. nmTab.hdr.idFrom = GetDlgCtrlID();
  429. nmTab.lOldTab = nOldTab;
  430. nmTab.lNewTab = nNewTab;
  431. nmTab.lOldItemData = lOldItemData;
  432. nmTab.lNewItemData = lNewItemData;
  433. pParentWnd->SendMessage(WM_NOTIFY, (WPARAM) nmTab.hdr.idFrom, (LPARAM) &nmTab);
  434. }
  435. }
  436. }
  437. void CTabCtrlEx::MakeTabVisible(int nTab)
  438. {
  439. CRect rcTab;
  440. GetTabRect(nTab, rcTab);
  441. rcTab.OffsetRect(-m_nLeftShifted, 0);
  442. if (rcTab.right > GetDisplayWidth())
  443. m_nLeftShifted += (rcTab.right-GetDisplayWidth()+TEXT_PAD);
  444. GetTabRect(nTab, rcTab);
  445. rcTab.OffsetRect(-m_nLeftShifted, 0);
  446. if (rcTab.left <= 0)
  447. {
  448. m_nLeftShifted += rcTab.left;
  449. if (m_nLeftShifted < 0)
  450. {
  451. ASSERT(FALSE);
  452. m_nLeftShifted = 0;
  453. }
  454. }
  455. }
  456. void CTabCtrlEx::OnPaint()
  457. {
  458. CPaintDC dc(this); // device context for painting
  459. CRect rcUpdate(0, 0, 0, 0);
  460. // Enable spinners
  461. EnableSpinners();
  462. if (m_nActiveTab < 0)
  463. {
  464. // Set the first window to be the active tab
  465. ActivateTab(0, true, true);
  466. }
  467. // Draw the tabs
  468. DrawTabs(&dc);
  469. }
  470. void CTabCtrlEx::EnableSpinners()
  471. {
  472. int nDispWidth = GetDisplayWidth();
  473. if (nDispWidth >= GetTabsWidth())
  474. {
  475. // We have enough space, disable the spinners
  476. m_nLeftShifted = 0;
  477. m_bBtnEnabled[0] = false;
  478. m_bBtnEnabled[1] = false;
  479. }
  480. else
  481. {
  482. // Enable/Disable the spinner buttons
  483. m_bBtnEnabled[0] = (m_nLeftShifted > 0);
  484. m_bBtnEnabled[1] = ((m_nLeftShifted+nDispWidth) < GetTabsWidth());
  485. }
  486. }
  487. void CTabCtrlEx::DrawTabs(CDC *pDC)
  488. {
  489. // Draw the bar
  490. DrawBar(pDC);
  491. CRect rcTab;
  492. // Draw all the tabs but the active tab
  493. for (int iTab=0; iTab<m_Tabs.GetSize(); iTab++)
  494. {
  495. if (iTab == GetActiveTab())
  496. continue;
  497. GetTabRect(iTab, rcTab);
  498. rcTab.OffsetRect(-m_nLeftShifted, 0);
  499. DrawTab(iTab, pDC, rcTab);
  500. }
  501. // Draw the active tab
  502. GetTabRect(GetActiveTab(), rcTab);
  503. rcTab.OffsetRect(-m_nLeftShifted, 0);
  504. if (GetActiveTab() < m_Tabs.GetSize())
  505. DrawTab(GetActiveTab(), pDC, rcTab);
  506. // Draw the spinner buttons
  507. DrawSpinner(pDC);
  508. }
  509. void CTabCtrlEx::DrawBar(CDC* pDC)
  510. {
  511. CRect rcBar;
  512. GetFullRect(rcBar);
  513. // Set the background color for the tabs
  514. pDC->FillRect(rcBar, &m_brNonSelectedTab);
  515. if (m_nStyle & SCS_BOLD)
  516. {
  517. // Draw the line
  518. if (m_nStyle & SCS_TOP)
  519. {
  520. pDC->MoveTo(CPoint(rcBar.left, rcBar.bottom-1));
  521. pDC->LineTo(CPoint(rcBar.right, rcBar.bottom-1));
  522. }
  523. else
  524. {
  525. pDC->MoveTo(rcBar.TopLeft());
  526. pDC->LineTo(CPoint(rcBar.right, rcBar.top));
  527. }
  528. }
  529. }
  530. void CTabCtrlEx::DrawTab(int nTab, CDC *pDC, CRect& rcTab)
  531. {
  532. if(nTab < 0)
  533. return;
  534. DrawTabEx(nTab, pDC, rcTab);
  535. return;
  536. // Paint the text centered.
  537. CPoint ptArr[5];
  538. if (m_nStyle & SCS_TOP)
  539. {
  540. ptArr[0] = CPoint(rcTab.left, rcTab.bottom-1);
  541. ptArr[1] = CPoint(rcTab.left+TEXT_PAD, rcTab.top);
  542. ptArr[2] = CPoint(rcTab.right, rcTab.top);
  543. ptArr[3] = CPoint(rcTab.right+TEXT_PAD, rcTab.bottom);
  544. ptArr[4] = CPoint(rcTab.left, rcTab.bottom);
  545. }
  546. else
  547. {
  548. ptArr[0] = rcTab.TopLeft();
  549. ptArr[1] = CPoint(rcTab.left+TEXT_PAD, rcTab.bottom-1);
  550. ptArr[2] = CPoint(rcTab.right, rcTab.bottom-1);
  551. ptArr[3] = CPoint(rcTab.right+TEXT_PAD, rcTab.top-1);
  552. ptArr[4] = rcTab.TopLeft();
  553. }
  554. // Draw the Tab
  555. CRgn rgn;
  556. if (rgn.CreatePolygonRgn(ptArr, 4, WINDING) == FALSE)
  557. return;
  558. CFont *pFont = NULL;
  559. if (nTab == GetActiveTab())
  560. {
  561. pDC->FillRgn(&rgn, &m_brSelectedTab);
  562. pFont = m_pFntBoldText;
  563. }
  564. else
  565. {
  566. pDC->FillRgn(&rgn, &m_brNonSelectedTab);
  567. pFont = m_pFntText;
  568. }
  569. CPen *pPen = NULL;
  570. if ((m_nStyle & SCS_BOLD) == 0)
  571. pPen = &m_penGray;
  572. CPen *pPrevPen = pDC->SelectObject(pPen);
  573. pDC->Polyline(ptArr, 4);
  574. pDC->SelectObject(pPrevPen);
  575. // Draw the text
  576. CFont *pPrevFont = pDC->SelectObject(pFont);
  577. rcTab.right += TEXT_PAD;
  578. pDC->SetBkMode(TRANSPARENT);
  579. pDC->DrawText(m_Tabs[nTab].csTitle, rcTab, DT_CENTER|DT_VCENTER|DT_END_ELLIPSIS);
  580. pDC->SelectObject(pPrevFont);
  581. if (m_Tabs[nTab].clrUnderline != -1)
  582. {
  583. pDC->Draw3dRect(CRect(rcTab.left+TEXT_PAD+2, rcTab.bottom-2, rcTab.right-TEXT_PAD-2, rcTab.bottom),
  584. m_Tabs[nTab].clrUnderline, m_Tabs[nTab].clrUnderline);
  585. }
  586. }
  587. void CTabCtrlEx::DrawTabEx(int nTab, CDC *pDC, CRect& rcTab)
  588. {
  589. if(nTab < 0)
  590. return;
  591. CRect rcOrig(rcTab);
  592. rcTab.OffsetRect(1, 1);
  593. CFont *pFont = NULL;
  594. if (nTab == GetActiveTab())
  595. {
  596. pDC->FillSolidRect(rcTab, m_SelectedColor);
  597. pFont = m_pFntBoldText;
  598. }
  599. else
  600. {
  601. pDC->FillSolidRect(rcTab, m_NonSelectedColor);
  602. pFont = m_pFntText;
  603. }
  604. //Don't draw a line on the item before the selected tab
  605. if (nTab != GetActiveTab()-1)
  606. {
  607. int nBottomOffset = 0;
  608. int nTopOffset = 0;
  609. CPen *pPen = NULL;
  610. if (nTab == GetActiveTab())
  611. {
  612. pPen = &m_penBlack;
  613. nTopOffset = -1;
  614. }
  615. else
  616. {
  617. pPen = &m_penGray;
  618. nBottomOffset = 3;
  619. nTopOffset = 2;
  620. }
  621. CPen *pPrevPen = pDC->SelectObject(pPen);
  622. pDC->MoveTo(CPoint(rcTab.right-1, rcTab.bottom-nBottomOffset));
  623. pDC->LineTo(CPoint(rcTab.right-1, rcTab.top+nTopOffset));
  624. pDC->SelectObject(pPrevPen);
  625. }
  626. // Draw the text
  627. CFont *pPrevFont = pDC->SelectObject(pFont);
  628. pDC->SetBkMode(TRANSPARENT);
  629. pDC->DrawText(m_Tabs[nTab].csTitle, rcOrig, DT_CENTER|DT_VCENTER|DT_END_ELLIPSIS);
  630. pDC->SelectObject(pPrevFont);
  631. }
  632. void CTabCtrlEx::DrawSpinner(CDC *pDC)
  633. {
  634. CRect rcSpin;
  635. GetSpinnerRect(rcSpin);
  636. if (rcSpin.Width() == 0)
  637. return;
  638. // Set the background color
  639. pDC->FillRect(rcSpin, &m_brNonSelectedTab);
  640. // Draw the line
  641. pDC->MoveTo(CPoint(rcSpin.left+1, rcSpin.top));
  642. pDC->LineTo(CPoint(rcSpin.left+1, rcSpin.bottom));
  643. rcSpin.DeflateRect(SPIN_PAD, 0, 0, 0);
  644. CRect rcBtn;
  645. GetButtonRect(0, rcBtn);
  646. DrawButton(pDC, rcBtn, m_btnState[0], ArrowLeft, m_bBtnEnabled[0]);
  647. GetButtonRect(1, rcBtn);
  648. DrawButton(pDC, rcBtn, m_btnState[1], ArrowRight, m_bBtnEnabled[1]);
  649. }
  650. void CTabCtrlEx::DrawButton(CDC *pDC, CRect& rcBtn, ButtonState btnState,
  651. ButtonStyle btnStyle, bool bEnable)
  652. {
  653. // Draw the arrow
  654. CPoint ptArr[3];
  655. int x = rcBtn.left + rcBtn.Width()/3;
  656. int y = rcBtn.top + rcBtn.Height()/2;
  657. long lHeight = rcBtn.Height()/4;
  658. CPen *pPen = NULL;
  659. // Change pen if button disabled
  660. if (bEnable == false)
  661. pPen = &m_penGray;
  662. CPen *pPrevPen = pDC->SelectObject(pPen);
  663. // Draw the left arrow
  664. if (btnStyle == ArrowLeft)
  665. {
  666. for (int iHt=0; iHt<=lHeight; x++, iHt++)
  667. {
  668. pDC->MoveTo(x, y-iHt);
  669. pDC->LineTo(x, y+iHt+1);
  670. }
  671. }
  672. // Draw the right arrow
  673. else
  674. {
  675. for (int iHt=lHeight; iHt>=0; x++, iHt--)
  676. {
  677. pDC->MoveTo(x, y-iHt);
  678. pDC->LineTo(x, y+iHt+1);
  679. }
  680. }
  681. pDC->SelectObject(pPrevPen);
  682. // Draw the button frame
  683. if (btnState == BtnUp)
  684. pDC->Draw3dRect(rcBtn, COLOR_WHITE, COLOR_DARKGRAY);
  685. else// if (btnState == BtnDown)
  686. pDC->Draw3dRect(rcBtn, COLOR_DARKGRAY, COLOR_WHITE);
  687. }
  688. void CTabCtrlEx::OnLButtonDown(UINT nFlags, CPoint point)
  689. {
  690. CRect rcBtn;
  691. bool bOnButton = false;
  692. for (int iBtn=0; iBtn<2; iBtn++)
  693. {
  694. GetButtonRect(iBtn, rcBtn);
  695. if (rcBtn.PtInRect(point) && m_bBtnEnabled[iBtn])
  696. {
  697. m_btnState[iBtn] = BtnDown;
  698. bOnButton = true;
  699. }
  700. }
  701. if (bOnButton)
  702. {
  703. // Get the mouse capture
  704. SetCapture();
  705. // Start the timer message
  706. SetTimer(ID_SCROLL_TIMER, 100, NULL);
  707. // Redraw the buttons
  708. RedrawWindow();
  709. }
  710. CWnd::OnLButtonDown(nFlags, point);
  711. }
  712. void CTabCtrlEx::OnTimer(UINT nIDEvent)
  713. {
  714. if (nIDEvent == ID_SCROLL_TIMER)
  715. {
  716. CPoint point(0, 0);
  717. GetCursorPos(&point);
  718. ScreenToClient(&point);
  719. ScrollTab(point);
  720. // Redraw the buttons and tabs
  721. RedrawWindow();
  722. }
  723. CWnd::OnTimer(nIDEvent);
  724. }
  725. void CTabCtrlEx::OnMouseMove(UINT nFlags, CPoint point)
  726. {
  727. /*
  728. CRect rcBtn;
  729. bool bRedrawButton = false;
  730. for (int iBtn=0; iBtn<2; iBtn++)
  731. {
  732. GetButtonRect(iBtn, rcBtn);
  733. if (rcBtn.PtInRect(point) && m_bBtnEnabled[iBtn])
  734. {
  735. if (m_btnState[iBtn] != BtnHover)
  736. {
  737. m_btnState[iBtn] = BtnHover;
  738. bRedrawButton = true;
  739. // Get the mouse capture
  740. SetCapture();
  741. }
  742. }
  743. else
  744. {
  745. if (m_btnState[iBtn] != BtnUp)
  746. {
  747. m_btnState[iBtn] = BtnUp;
  748. bRedrawButton = true;
  749. // Release the mouse capture
  750. ReleaseCapture();
  751. }
  752. }
  753. }
  754. if (bRedrawButton)
  755. {
  756. // Redraw the buttons
  757. RedrawWindow();
  758. }
  759. */
  760. CWnd::OnMouseMove(nFlags, point);
  761. }
  762. void CTabCtrlEx::OnLButtonUp(UINT nFlags, CPoint point)
  763. {
  764. // Release the mouse capture
  765. ReleaseCapture();
  766. // End the timer
  767. KillTimer(ID_SCROLL_TIMER);
  768. // Check and scroll the tabs
  769. ScrollTab(point);
  770. // Set the button state
  771. for (int iBtn=0; iBtn<2; iBtn++)
  772. m_btnState[iBtn] = BtnUp;
  773. // Redraw the buttons
  774. RedrawWindow();
  775. CWnd::OnLButtonUp(nFlags, point);
  776. }
  777. void CTabCtrlEx::ScrollTab(CPoint point)
  778. {
  779. CRect rcBtn;
  780. for (int iBtn=0; iBtn<2; iBtn++)
  781. {
  782. GetButtonRect(iBtn, rcBtn);
  783. if (rcBtn.PtInRect(point))
  784. {
  785. if (m_bBtnEnabled[iBtn])
  786. {
  787. m_btnState[iBtn] = BtnDown;
  788. if (iBtn == 0)
  789. {
  790. m_nLeftShifted -= SHIFT_UNITS;
  791. if (m_nLeftShifted < 0)
  792. m_nLeftShifted = 0;
  793. }
  794. else
  795. {
  796. m_nLeftShifted += SHIFT_UNITS;
  797. }
  798. }
  799. else
  800. {
  801. m_btnState[iBtn] = BtnUp;
  802. }
  803. }
  804. else
  805. {
  806. m_btnState[iBtn] = BtnUp;
  807. }
  808. }
  809. CRect rcSpin;
  810. GetSpinnerRect(rcSpin);
  811. if (rcSpin.PtInRect(point) == FALSE)
  812. {
  813. // Adjust for the shift
  814. point.Offset(m_nLeftShifted, 0);
  815. CRect rcTab;
  816. for (int iTab=0; iTab<m_Tabs.GetSize(); iTab++)
  817. {
  818. GetTabRect(iTab, rcTab);
  819. if (rcTab.PtInRect(point))
  820. {
  821. // Show the appropriate tab window
  822. ActivateTab(iTab, true);
  823. }
  824. }
  825. }
  826. }
  827. void CTabCtrlEx::OnSize(UINT nType, int cx, int cy)
  828. {
  829. CWnd::OnSize(nType, cx, cy);
  830. // Resize the tabs
  831. if (m_nLeftShifted && (cx > m_nPrevWidth))
  832. {
  833. int nDispWidth = cx-GetSpinnerWidth();
  834. if ((nDispWidth+m_nLeftShifted) >= GetTabsWidth())
  835. {
  836. m_nLeftShifted -= (cx-m_nPrevWidth);
  837. if (m_nLeftShifted <= GetSpinnerWidth())
  838. m_nLeftShifted = 0;
  839. }
  840. }
  841. ActivateTab(GetActiveTab(), false, true);
  842. m_nPrevWidth = cx;
  843. }
  844. BOOL CTabCtrlEx::PreTranslateMessage(MSG* pMsg)
  845. {
  846. switch (pMsg->message)
  847. {
  848. case WM_KEYDOWN:
  849. if (GetKeyState(VK_CONTROL) & 0x8000)
  850. {
  851. if (pMsg->wParam == VK_TILDAE)
  852. {
  853. SwitchTabs((GetKeyState(VK_SHIFT) & 0x8000) == 0);
  854. return TRUE;
  855. }
  856. else if (((pMsg->wParam - '1') >= 0) && ((pMsg->wParam - '1') < (UINT) m_Tabs.GetSize()))
  857. {
  858. // Set the new active tab
  859. ActivateTab(pMsg->wParam - '1', true);
  860. return TRUE;
  861. }
  862. }
  863. break;
  864. }
  865. return FALSE;
  866. }
  867. void CTabCtrlEx::SwitchTabs(bool bNext)
  868. {
  869. int nNewTab = GetActiveTab();
  870. if (bNext)
  871. nNewTab++;
  872. else
  873. nNewTab--;
  874. if (nNewTab < 0)
  875. nNewTab = m_Tabs.GetSize()-1;
  876. else if (nNewTab >= m_Tabs.GetSize())
  877. nNewTab = 0;
  878. // Set the new active tab
  879. ActivateTab(nNewTab, true);
  880. }
  881. void CTabCtrlEx::OnShowWindow(BOOL bShow, UINT nStatus)
  882. {
  883. if (bShow)
  884. {
  885. // Show the active tab
  886. SetActiveTab(GetActiveTab(), false);
  887. }
  888. else
  889. {
  890. // Hide the active tab
  891. if (GetActiveTab() >= 0)
  892. {
  893. CWnd* pWnd = m_Tabs[GetActiveTab()].pWnd;
  894. if (pWnd && IsWindow(pWnd->m_hWnd))
  895. pWnd->ShowWindow(SW_HIDE);
  896. }
  897. }
  898. }