TabCtrl.cpp 21 KB

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