Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

707 lines
19 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Copyright (C) 1993-1996 Microsoft Corporation. All Rights Reserved.
  3. //
  4. // MODULE: PickGrp.cpp
  5. //
  6. // PURPOSE: Dialog to allow the user to select groups to post to in the
  7. // send note window.
  8. //
  9. #include "pch.hxx"
  10. #include <iert.h>
  11. #include "pickgrp.h"
  12. #include "grplist2.h"
  13. #include "shlwapip.h"
  14. #include "resource.h"
  15. #include "strconst.h"
  16. #include "demand.h"
  17. CPickGroupDlg::CPickGroupDlg()
  18. {
  19. m_cRef = 1;
  20. m_ppszGroups = 0;
  21. m_hwndPostTo = 0;
  22. m_fPoster = FALSE;
  23. m_hIcon = NULL;
  24. m_pGrpList = NULL;
  25. m_pszAcct = NULL;
  26. m_idAcct = FOLDERID_INVALID;
  27. }
  28. CPickGroupDlg::~CPickGroupDlg()
  29. {
  30. if (m_hIcon)
  31. SideAssert(DestroyIcon(m_hIcon));
  32. if (m_pGrpList != NULL)
  33. m_pGrpList->Release();
  34. }
  35. HRESULT STDMETHODCALLTYPE CPickGroupDlg::QueryInterface(REFIID riid, void **ppvObj)
  36. {
  37. if (IsEqualIID(riid, IID_IUnknown))
  38. *ppvObj = (void*) (IUnknown *)(IGroupListAdvise *)this;
  39. else if (IsEqualIID(riid, IID_IGroupListAdvise))
  40. *ppvObj = (void*) (IGroupListAdvise *) this;
  41. else
  42. {
  43. *ppvObj = NULL;
  44. return E_NOINTERFACE;
  45. }
  46. AddRef();
  47. return S_OK;
  48. }
  49. ULONG STDMETHODCALLTYPE CPickGroupDlg::AddRef()
  50. {
  51. return ++m_cRef;
  52. }
  53. ULONG STDMETHODCALLTYPE CPickGroupDlg::Release()
  54. {
  55. if (--m_cRef == 0)
  56. {
  57. delete this;
  58. return 0;
  59. }
  60. return m_cRef;
  61. }
  62. //
  63. // FUNCTION: CPickGroupsDlg::FCreate()
  64. //
  65. // PURPOSE: Handles initialization of the data and creation of the pick
  66. // groups dialog.
  67. //
  68. // PARAMETERS:
  69. // hwndOwner - Window that will own this dialog.
  70. // pszAccount - account to use initially.
  71. // ppszGroups - This is where we return the last selected group
  72. //
  73. // RETURN VALUE:
  74. // Returns TRUE if successful, or FALSE otherwise.
  75. //
  76. BOOL CPickGroupDlg::FCreate(HWND hwndOwner, FOLDERID idServer, LPSTR *ppszGroups, BOOL fPoster)
  77. {
  78. int iret;
  79. HRESULT hr;
  80. FOLDERID idAcct;
  81. FOLDERINFO info;
  82. char szAcct[CCHMAX_ACCOUNT_NAME];
  83. Assert(ppszGroups != NULL);
  84. m_pGrpList = new CGroupList;
  85. if (m_pGrpList == NULL)
  86. return(FALSE);
  87. m_ppszGroups = ppszGroups;
  88. m_fPoster = fPoster;
  89. hr = g_pStore->GetFolderInfo(idServer, &info);
  90. if (FAILED(hr))
  91. return(FALSE);
  92. StrCpyN(szAcct, info.pszName, ARRAYSIZE(szAcct));
  93. g_pStore->FreeRecord(&info);
  94. m_pszAcct = szAcct;
  95. m_idAcct = idServer;
  96. // Now create the dialog.
  97. iret = (int) DialogBoxParam(g_hLocRes, MAKEINTRESOURCE(iddPickGroup), hwndOwner, PickGrpDlgProc, (LPARAM)this);
  98. return(iret == IDOK);
  99. }
  100. INT_PTR CALLBACK CPickGroupDlg::PickGrpDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  101. {
  102. BOOL fRet;
  103. CPickGroupDlg *pThis;
  104. fRet = TRUE;
  105. pThis = (CPickGroupDlg *)GetWindowLongPtr(hwnd, DWLP_USER);
  106. switch (msg)
  107. {
  108. case WM_INITDIALOG:
  109. Assert(pThis == NULL);
  110. Assert(lParam != NULL);
  111. pThis = (CPickGroupDlg *)lParam;
  112. SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM)pThis);
  113. fRet = pThis->_OnInitDialog(hwnd);
  114. break;
  115. case WM_CLOSE:
  116. pThis->_OnClose(hwnd);
  117. break;
  118. case WM_COMMAND:
  119. pThis->_OnCommand(hwnd, LOWORD(wParam), (HWND)lParam, HIWORD(wParam));
  120. break;
  121. case WM_NOTIFY:
  122. pThis->_OnNotify(hwnd, (int)wParam, (LPNMHDR)lParam);
  123. break;
  124. case WM_TIMER:
  125. pThis->_OnTimer(hwnd, (UINT)wParam);
  126. break;
  127. case WM_PAINT:
  128. pThis->_OnPaint(hwnd);
  129. break;
  130. case NVM_CHANGESERVERS:
  131. pThis->_OnChangeServers(hwnd);
  132. break;
  133. default:
  134. fRet = FALSE;
  135. break;
  136. }
  137. return(fRet);
  138. }
  139. //
  140. // FUNCTION: CPickGroupDlg::OnInitDialog()
  141. //
  142. // PURPOSE: Handles initializing the PickGroup dialog. Initializes the
  143. // dependant classes, list view, buttons, etc.
  144. //
  145. // PARAMETERS:
  146. // hwnd - Handle of the dialog box.
  147. // hwndFocus - Handle of the control that will get focus if TRUE is returned.
  148. // lParam - Contains a pointer to a string of newsgroups the user has
  149. // already selected.
  150. //
  151. // RETURN VALUE:
  152. // Returns TRUE to set the focus to hwndFocus, or FALSE otherwise.
  153. //
  154. BOOL CPickGroupDlg::_OnInitDialog(HWND hwnd)
  155. {
  156. char szTitle[256];
  157. LV_COLUMN lvc;
  158. RECT rc;
  159. LONG cx;
  160. HDC hdc;
  161. TEXTMETRIC tm;
  162. HIMAGELIST himl;
  163. HRESULT hr;
  164. HWND hwndList;
  165. CColumns *pColumns;
  166. m_hwnd = hwnd;
  167. m_hwndPostTo = GetDlgItem(hwnd, idcPostTo);
  168. hwndList = GetDlgItem(hwnd, idcGroupList);
  169. pColumns = new CColumns;
  170. if (pColumns == NULL)
  171. {
  172. EndDialog(hwnd, IDCANCEL);
  173. return(FALSE);
  174. }
  175. pColumns->Initialize(hwndList, COLUMN_SET_PICKGRP);
  176. pColumns->ApplyColumns(COLUMN_LOAD_DEFAULT, 0, 0);
  177. Assert(m_pGrpList != NULL);
  178. hr = m_pGrpList->Initialize((IGroupListAdvise *)this, pColumns, hwndList, FOLDER_NEWS);
  179. Assert(SUCCEEDED(hr));
  180. pColumns->Release();
  181. // Bug #21471 - Add the server name to the dialog box title
  182. GetWindowText(hwnd, szTitle, ARRAYSIZE(szTitle));
  183. Assert(m_pszAcct);
  184. StrCatBuff(szTitle, m_pszAcct, ARRAYSIZE(szTitle));
  185. SetWindowText(hwnd, szTitle);
  186. GetClientRect(m_hwndPostTo, &rc);
  187. // Set the image lists for the listview
  188. himl = ImageList_LoadBitmap(g_hLocRes, MAKEINTRESOURCE(idbFolders), 16, 0, RGB(255, 0, 255));
  189. Assert(himl);
  190. // Group name column
  191. lvc.mask = LVCF_SUBITEM | LVCF_WIDTH;
  192. lvc.cx = rc.right;
  193. lvc.iSubItem = 0;
  194. ListView_InsertColumn(m_hwndPostTo, 0, &lvc);
  195. // Make the second listview have images too
  196. ListView_SetImageList(m_hwndPostTo, himl, LVSIL_SMALL);
  197. hdc = GetDC(hwndList);
  198. if (GetTextMetrics(hdc, &tm))
  199. {
  200. cx = tm.tmAveCharWidth * 150;
  201. ListView_SetColumnWidth(hwndList, 0, cx);
  202. ListView_SetColumnWidth(m_hwndPostTo, 0, cx);
  203. }
  204. ReleaseDC(hwndList, hdc);
  205. SendDlgItemMessage(hwnd, idcShowFavorites, BM_SETCHECK, TRUE, 0L);
  206. if (!m_fPoster)
  207. ShowWindow(GetDlgItem(hwnd, idcEmailAuthor), SW_HIDE);
  208. m_hIcon = (HICON)LoadImage(g_hLocRes, MAKEINTRESOURCE(idiNewsGroup), IMAGE_ICON, 16, 16, 0);
  209. SendDlgItemMessage(hwnd, idcShowFavorites, BM_SETIMAGE, IMAGE_ICON, (LPARAM)m_hIcon);
  210. PostMessage(hwnd, NVM_CHANGESERVERS, 0, 0L);
  211. return(FALSE);
  212. }
  213. BOOL CPickGroupDlg::_OnFilter(HWND hwnd)
  214. {
  215. UINT cch;
  216. LPSTR pszText;
  217. HRESULT hr;
  218. BOOL fSub;
  219. HWND hwndEdit;
  220. pszText = NULL;
  221. hwndEdit = GetDlgItem(hwnd, idcFindText);
  222. cch = GetWindowTextLength(hwndEdit);
  223. if (cch > 0)
  224. {
  225. cch++;
  226. if (!MemAlloc((void **)&pszText, cch + 1))
  227. return(FALSE);
  228. GetWindowText(hwndEdit, pszText, cch);
  229. }
  230. fSub = (IsDlgButtonChecked(hwnd, idcShowFavorites));
  231. hr = m_pGrpList->Filter(pszText, fSub ? SUB_TAB_SUBSCRIBED : SUB_TAB_ALL, FALSE);
  232. Assert(SUCCEEDED(hr));
  233. if (pszText != NULL)
  234. MemFree(pszText);
  235. return(TRUE);
  236. }
  237. void CPickGroupDlg::_OnChangeServers(HWND hwnd)
  238. {
  239. LPSTR pszTok, pszToken;
  240. UINT index;
  241. HRESULT hr;
  242. FOLDERINFO Folder;
  243. // TODO: we need to fix the initialization so the filtering is only performed
  244. // once (we should call IGroupList::Filter once and then IGroupList::SetServer once
  245. // during creation of the dialog)
  246. UpdateWindow(hwnd);
  247. _OnFilter(hwnd);
  248. hr = m_pGrpList->SetServer(m_idAcct);
  249. Assert(SUCCEEDED(hr));
  250. if (m_ppszGroups)
  251. {
  252. pszTok = *m_ppszGroups;
  253. pszToken = StrTokEx(&pszTok, c_szDelimiters);
  254. while (pszToken != NULL)
  255. {
  256. if (m_fPoster && 0 == lstrcmpi(pszToken, c_szPosterKeyword))
  257. CheckDlgButton(hwnd, idcEmailAuthor, TRUE);
  258. ZeroMemory(&Folder, sizeof(FOLDERINFO));
  259. Folder.idParent = m_idAcct;
  260. Folder.pszName = pszToken;
  261. if (DB_S_FOUND == g_pStore->FindRecord(IINDEX_ALL, COLUMNS_ALL, &Folder, NULL))
  262. {
  263. _InsertList(Folder.idFolder);
  264. g_pStore->FreeRecord(&Folder);
  265. }
  266. pszToken = StrTokEx(&pszTok, c_szDelimiters);
  267. }
  268. MemFree(*m_ppszGroups);
  269. *m_ppszGroups = 0;
  270. }
  271. // Bug #17674 - Make sure the post-to listview has an initial selection.
  272. ListView_SetItemState(m_hwndPostTo, 0, LVIS_SELECTED, LVIS_SELECTED);
  273. _UpdateStateUI(hwnd);
  274. }
  275. //
  276. // FUNCTION: CPickGroupDlg::OnCommand()
  277. //
  278. // PURPOSE: Processes the WM_COMMAND messages for the pick group dialog.
  279. //
  280. // PARAMETERS:
  281. // hwnd - Handle of the dialog window.
  282. // id - ID of the control which sent the message.
  283. // hwndCtl - Handle of the control sending the message.
  284. // codeNotify - Notification code being sent.
  285. //
  286. void CPickGroupDlg::_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  287. {
  288. switch (id)
  289. {
  290. case idcAddGroup:
  291. _AddGroup();
  292. break;
  293. case idcRemoveGroup:
  294. _RemoveGroup();
  295. break;
  296. case IDOK:
  297. if (_OnOK(hwnd))
  298. EndDialog(hwnd, IDOK);
  299. break;
  300. case IDCANCEL:
  301. EndDialog(hwnd, IDCANCEL);
  302. break;
  303. case idcShowFavorites:
  304. _OnFilter(hwnd);
  305. _UpdateStateUI(hwnd);
  306. break;
  307. case idcFindText:
  308. // This is generated when someone types in the find text edit box.
  309. // We set a timer and when that timer expires we assume the user is
  310. // done typing and go ahead and perform the query.
  311. if (EN_CHANGE == codeNotify)
  312. {
  313. KillTimer(hwnd, idtFindDelay);
  314. SetTimer(hwnd, idtFindDelay, dtFindDelay, NULL);
  315. }
  316. break;
  317. }
  318. }
  319. HRESULT CPickGroupDlg::ItemUpdate(void)
  320. {
  321. _UpdateStateUI(m_hwnd);
  322. return(S_OK);
  323. }
  324. HRESULT CPickGroupDlg::ItemActivate(FOLDERID id)
  325. {
  326. _AddGroup();
  327. return(S_OK);
  328. }
  329. //
  330. // FUNCTION: CPickGroupDlg::OnNotify()
  331. //
  332. // PURPOSE: Handles notification messages from the group list listview.
  333. //
  334. // PARAMETERS:
  335. // hwnd - Handle of the pick group dialog.
  336. // idFrom - ID of the control sending the notification.
  337. // pnmhdr - Pointer to the NMHDR struct with the notification info.
  338. //
  339. // RETURN VALUE:
  340. // Dependent on the notification.
  341. //
  342. LRESULT CPickGroupDlg::_OnNotify(HWND hwnd, int idFrom, LPNMHDR pnmhdr)
  343. {
  344. HRESULT hr;
  345. LRESULT lRes;
  346. hr = m_pGrpList->HandleNotify(hwnd, idFrom, pnmhdr, &lRes);
  347. if (hr == S_OK)
  348. return(lRes);
  349. switch (pnmhdr->code)
  350. {
  351. case NM_DBLCLK:
  352. if (pnmhdr->hwndFrom == m_hwndPostTo)
  353. _RemoveGroup();
  354. break;
  355. case LVN_ITEMCHANGED:
  356. _UpdateStateUI(hwnd);
  357. break;
  358. }
  359. return(0);
  360. }
  361. void CPickGroupDlg::_OnTimer(HWND hwnd, UINT id)
  362. {
  363. KillTimer(hwnd, id);
  364. _OnFilter(hwnd);
  365. _UpdateStateUI(hwnd);
  366. }
  367. void CPickGroupDlg::_OnClose(HWND hwnd)
  368. {
  369. int iReturn;
  370. iReturn = AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthenaNews),
  371. MAKEINTRESOURCEW(idsDoYouWantToSave), 0,
  372. MB_YESNOCANCEL | MB_ICONEXCLAMATION );
  373. if (iReturn == IDYES)
  374. _OnCommand(hwnd, IDOK, 0, 0);
  375. else if (iReturn == IDNO)
  376. _OnCommand(hwnd, IDCANCEL, 0, 0);
  377. }
  378. //
  379. // FUNCTION: CPickGroupDlg::OnOK()
  380. //
  381. // PURPOSE: This function copies the group names from the dialog that
  382. // the user has selected and returns them in the pointer the
  383. // caller provided.
  384. //
  385. // RETURN VALUE:
  386. // Returns TRUE if the copy was successful, or FALSE otherwise.
  387. //
  388. // COMMENTS:
  389. // Note - 1000 characters is a good maximum line length (specified by the
  390. // Son-of-RFC 1036 doc) so we limit the number of groups based on
  391. // this line limit.
  392. //
  393. //
  394. BOOL CPickGroupDlg::_OnOK(HWND hwnd)
  395. {
  396. // OK, we've got the entire sorted list. Create a string with all the groups
  397. // and put it in the edit control.
  398. char szGroups[c_cchLineMax], szGroup[256];
  399. int cGroups;
  400. LPSTR psz;
  401. LV_ITEM lvi;
  402. int cchGroups = 0, cch;
  403. szGroups[0] = 0;
  404. if (m_fPoster && IsDlgButtonChecked(hwnd, idcEmailAuthor))
  405. {
  406. StrCatBuff(szGroups, c_szPosterKeyword, ARRAYSIZE(szGroups));
  407. cchGroups += lstrlen(c_szPosterKeyword);
  408. }
  409. if (cGroups = ListView_GetItemCount(m_hwndPostTo))
  410. {
  411. lvi.mask = LVIF_TEXT;
  412. lvi.iSubItem = 0;
  413. lvi.pszText = szGroup;
  414. lvi.cchTextMax = ARRAYSIZE(szGroup);
  415. for (lvi.iItem = 0; lvi.iItem < cGroups; lvi.iItem++)
  416. {
  417. // Get the item
  418. ListView_GetItem(m_hwndPostTo, &lvi);
  419. // Make sure the length of this next group doesn't push us over
  420. // the max line length.
  421. cch = lstrlen(lvi.pszText);
  422. if ((cch + cchGroups + 2) > c_cchLineMax)
  423. {
  424. // Bug #24156 - If we have to truncate, then let the user know.
  425. AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthenaNews),
  426. MAKEINTRESOURCEW(idsErrNewsgroupLineTooLong), 0, MB_OK | MB_ICONINFORMATION);
  427. return (FALSE);
  428. }
  429. if (cchGroups)
  430. {
  431. StrCatBuff(szGroups, ", ", ARRAYSIZE(szGroups));
  432. }
  433. StrCatBuff(szGroups, lvi.pszText, ARRAYSIZE(szGroups));
  434. cchGroups += (cch + 2);
  435. }
  436. }
  437. // Now that we're done building this marvelous string, copy it to
  438. // the buffer for returning.
  439. if (!MemAlloc((LPVOID *)&psz, cchGroups + 1))
  440. return(FALSE);
  441. StrCpyN(psz, szGroups, cchGroups + 1);
  442. *m_ppszGroups = psz;
  443. return(TRUE);
  444. }
  445. //
  446. // FUNCTION: CPickGroupDlg::AddGroup()
  447. //
  448. // PURPOSE: Takes the group names selected in the ListView and adds them
  449. // to the selected groups Post To list.
  450. //
  451. void CPickGroupDlg::_AddGroup(void)
  452. {
  453. FOLDERID *pid;
  454. DWORD cid, i;
  455. HCURSOR hcur;
  456. HRESULT hr;
  457. hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  458. SetWindowRedraw(m_hwndPostTo, FALSE);
  459. hr = m_pGrpList->GetSelectedCount(&cid);
  460. if (SUCCEEDED(hr) && cid > 0)
  461. {
  462. if (MemAlloc((void **)&pid, cid * sizeof(FOLDERID)))
  463. {
  464. hr = m_pGrpList->GetSelected(pid, &cid);
  465. if (SUCCEEDED(hr))
  466. {
  467. for (i = 0; i < cid; i++)
  468. {
  469. _InsertList(pid[i]);
  470. }
  471. }
  472. MemFree(pid);
  473. }
  474. }
  475. if (-1 == ListView_GetNextItem(m_hwndPostTo, -1, LVNI_ALL | LVNI_SELECTED))
  476. ListView_SetItemState(m_hwndPostTo, 0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
  477. SetWindowRedraw(m_hwndPostTo, TRUE);
  478. InvalidateRect(m_hwndPostTo, NULL, TRUE);
  479. SetCursor(hcur);
  480. }
  481. //
  482. // FUNCTION: CPickGroupDlg::InsertList()
  483. //
  484. // PURPOSE: Given a index into the CGroupList's newsgroup list, that group
  485. // is inserted into the Post To list.
  486. //
  487. // PARAMETERS:
  488. // index - Index of a newsgroup in the CGroupList newsgroup list.
  489. //
  490. void CPickGroupDlg::_InsertList(FOLDERID id)
  491. {
  492. LV_ITEM lvi;
  493. int count;
  494. FOLDERINFO info;
  495. HRESULT hr;
  496. count = ListView_GetItemCount(m_hwndPostTo);
  497. // First make sure this isn't a duplicate.
  498. lvi.mask = LVIF_PARAM;
  499. lvi.iSubItem = 0;
  500. for (lvi.iItem = 0; lvi.iItem < count; lvi.iItem++)
  501. {
  502. ListView_GetItem(m_hwndPostTo, &lvi);
  503. if (id == (FOLDERID)lvi.lParam)
  504. return;
  505. }
  506. hr = g_pStore->GetFolderInfo(id, &info);
  507. if (SUCCEEDED(hr))
  508. {
  509. lvi.mask = LVIF_TEXT | LVIF_PARAM;
  510. lvi.iItem = 0;
  511. lvi.iSubItem = 0;
  512. lvi.pszText = info.pszName;
  513. if (!!(info.dwFlags & FOLDER_SUBSCRIBED))
  514. {
  515. lvi.iImage = iNewsGroup;
  516. lvi.mask |= LVIF_IMAGE;
  517. }
  518. lvi.lParam = (LPARAM)id;
  519. ListView_InsertItem(m_hwndPostTo, &lvi);
  520. g_pStore->FreeRecord(&info);
  521. }
  522. }
  523. void CPickGroupDlg::_RemoveGroup(void)
  524. {
  525. int index, count, iItemFocus;
  526. HCURSOR hcur;
  527. hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  528. SetWindowRedraw(m_hwndPostTo, FALSE);
  529. count = ListView_GetItemCount(m_hwndPostTo);
  530. iItemFocus = ListView_GetNextItem(m_hwndPostTo, -1, LVNI_FOCUSED);
  531. // Loop through all the selected items and remove them from the ListView
  532. for (index = count; index >= 0; index--)
  533. {
  534. if (ListView_GetItemState(m_hwndPostTo, index, LVIS_SELECTED))
  535. ListView_DeleteItem(m_hwndPostTo, index);
  536. }
  537. // Bug #22189 - Make sure the focus/selection goes somewhere after we delete.
  538. iItemFocus--;
  539. if (iItemFocus < 0 || ListView_GetItemCount(m_hwndPostTo) < iItemFocus)
  540. iItemFocus = 0;
  541. ListView_SetItemState(m_hwndPostTo, iItemFocus, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
  542. SetWindowRedraw(m_hwndPostTo, TRUE);
  543. InvalidateRect(m_hwndPostTo, NULL, TRUE);
  544. SetCursor(hcur);
  545. }
  546. void CPickGroupDlg::_UpdateStateUI(HWND hwnd)
  547. {
  548. DWORD cid;
  549. HRESULT hr;
  550. hr = m_pGrpList->GetSelectedCount(&cid);
  551. if (FAILED(hr))
  552. return;
  553. EnableWindow(GetDlgItem(hwnd, idcAddGroup), cid > 0);
  554. EnableWindow(GetDlgItem(hwnd, idcRemoveGroup), ListView_GetSelectedCount(m_hwndPostTo));
  555. }
  556. void CPickGroupDlg::_OnPaint(HWND hwnd)
  557. {
  558. RECT rc;
  559. HDC hdc;
  560. PAINTSTRUCT ps;
  561. HFONT hf;
  562. char szBuffer[CCHMAX_STRINGRES];
  563. hdc = BeginPaint(hwnd, &ps);
  564. // Only do this if the button is available
  565. if (IsWindow(GetDlgItem(hwnd, idcShowFavorites)))
  566. {
  567. // Get the position of the toggle button
  568. GetClientRect(GetDlgItem(hwnd, idcShowFavorites), &rc);
  569. MapWindowPoints(GetDlgItem(hwnd, idcShowFavorites), hwnd, (LPPOINT) &rc, 1);
  570. rc.left += (rc.right + 4);
  571. rc.right = rc.left + 300;
  572. rc.top += 1;
  573. rc.bottom += rc.top;
  574. AthLoadString(idsShowFavorites, szBuffer, ARRAYSIZE(szBuffer));
  575. hf = (HFONT) SelectObject(hdc, (HFONT) SendMessage(hwnd, WM_GETFONT, 0, 0));
  576. SetBkMode(hdc, TRANSPARENT);
  577. SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
  578. DrawText(hdc, szBuffer, lstrlen(szBuffer),
  579. &rc, DT_SINGLELINE | DT_VCENTER | DT_NOCLIP);
  580. SelectObject(hdc, hf);
  581. }
  582. EndPaint(hwnd, &ps);
  583. }