Source code of Windows XP (NT5)
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.

503 lines
11 KiB

  1. #define OEMRESOURCE // setting this gets OBM_ constants in windows.h
  2. #include <windows.h>
  3. #include "ctls.h"
  4. #pragma hdrstop
  5. #define MyModuleHandle GetModuleHandle( NULL )
  6. #define MYASSERT(x)
  7. #define MyFree(x) LocalFree( x )
  8. PWSTR DuplicateString( PWSTR pszOriginal )
  9. {
  10. PWSTR pszCopy;
  11. pszCopy = LocalAlloc( LPTR, ( 1 + lstrlenW( pszOriginal ) ) * sizeof( *pszOriginal ) );
  12. if ( NULL != pszCopy )
  13. {
  14. lstrcpy( pszCopy, pszOriginal );
  15. }
  16. return pszCopy;
  17. }
  18. ////////////////////////////////////////////
  19. //
  20. // Bitmap control
  21. //
  22. ////////////////////////////////////////////
  23. PCWSTR szBMPCLASS = L"_mybmp";
  24. LRESULT
  25. BmpClassWndProc(
  26. IN HWND hwnd,
  27. IN UINT msg,
  28. IN WPARAM wParam,
  29. IN LPARAM lParam
  30. );
  31. BOOL
  32. InitializeBmpClass(
  33. VOID
  34. )
  35. {
  36. WNDCLASS wc;
  37. BOOL b;
  38. if(GetClassInfo(MyModuleHandle,szBMPCLASS,&wc)) {
  39. b = TRUE;
  40. } else {
  41. wc.lpszClassName = szBMPCLASS;
  42. wc.style = CS_GLOBALCLASS;
  43. wc.lpfnWndProc = BmpClassWndProc;
  44. wc.hInstance = MyModuleHandle;
  45. wc.hIcon = NULL;
  46. wc.hCursor = LoadCursor(NULL,IDC_ARROW);
  47. wc.hbrBackground = NULL;
  48. wc.lpszMenuName = NULL;
  49. wc.cbClsExtra = 0;
  50. wc.cbWndExtra = 0;
  51. b = RegisterClass(&wc);
  52. }
  53. return(b);
  54. }
  55. VOID
  56. DestroyBmpClass(
  57. VOID
  58. )
  59. {
  60. WNDCLASS wc;
  61. if(GetClassInfo(MyModuleHandle,szBMPCLASS,&wc)) {
  62. //
  63. // Hope there are no more windows using the class!
  64. //
  65. MYASSERT(!FindWindow(szBMPCLASS,NULL));
  66. UnregisterClass(szBMPCLASS,MyModuleHandle);
  67. }
  68. }
  69. VOID
  70. BmpClassPaint(
  71. IN HWND hwnd
  72. )
  73. {
  74. PAINTSTRUCT ps;
  75. unsigned BmpId;
  76. HDC hdc, hdcMem;
  77. HBITMAP hbm,hbmOld;
  78. BITMAP bm;
  79. BmpId = GetDlgCtrlID(hwnd);
  80. hdc = BeginPaint(hwnd,&ps);
  81. if(hbm = LoadBitmap((HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),MAKEINTRESOURCE(BmpId))) {
  82. GetObject(hbm, sizeof(bm),&bm);
  83. if(hdcMem = CreateCompatibleDC(hdc)) {
  84. if(hbmOld = SelectObject(hdcMem,hbm)) {
  85. BitBlt(hdc,0,0,bm.bmWidth,bm.bmHeight,hdcMem,0,0,SRCCOPY);
  86. SelectObject(hdcMem,hbmOld);
  87. }
  88. DeleteDC(hdcMem);
  89. }
  90. DeleteObject(hbm);
  91. }
  92. EndPaint(hwnd,&ps);
  93. }
  94. LRESULT
  95. BmpClassWndProc(
  96. IN HWND hwnd,
  97. IN UINT msg,
  98. IN WPARAM wParam,
  99. IN LPARAM lParam
  100. )
  101. {
  102. switch(msg) {
  103. case WM_NCCREATE:
  104. SetWindowLong(
  105. hwnd,
  106. GWL_STYLE,
  107. GetWindowLong(hwnd,GWL_STYLE) | WS_BORDER
  108. );
  109. return(TRUE);
  110. case WM_PAINT:
  111. BmpClassPaint(hwnd);
  112. return(0);
  113. }
  114. return(DefWindowProc(hwnd,msg,wParam,lParam));
  115. }
  116. ////////////////////////////////////////////
  117. //
  118. // Action item list control
  119. //
  120. ////////////////////////////////////////////
  121. //
  122. // Define locations in extra window storage
  123. //
  124. #define AIL_FONT (0)
  125. #define AIL_BOLDFONT (sizeof(LONG))
  126. #define AIL_BOLDITEM (2*sizeof(LONG))
  127. #define AIL_TEXT (3*sizeof(LONG))
  128. #define AIL_LINECOUNT (4*sizeof(LONG))
  129. #define AIL_FREEFONTS (5*sizeof(LONG))
  130. #define AIL_EXTRA 6
  131. PCWSTR szActionItemListClassName = L"$$$ActionItemList";
  132. VOID
  133. ActionItemListPaint(
  134. IN HWND hwnd
  135. )
  136. {
  137. PAINTSTRUCT PaintStruct;
  138. PWSTR p,Text;
  139. UINT LineCount;
  140. HFONT OldFont,Font,BoldFont;
  141. UINT HighlightedItem;
  142. UINT i;
  143. int Length;
  144. int y;
  145. int yDelta;
  146. HBITMAP Bitmap,OldBitmap;
  147. BITMAP bitmap;
  148. HDC MemoryDC;
  149. SIZE Size;
  150. RECT rect;
  151. int Spacing;
  152. #define BORDER 3
  153. if(!BeginPaint(hwnd,&PaintStruct)) {
  154. return;
  155. }
  156. //
  157. // If no text, nothing to do.
  158. //
  159. if(Text = (PWSTR)GetWindowLong(hwnd,AIL_TEXT)) {
  160. LineCount = (UINT)GetWindowLong(hwnd,AIL_LINECOUNT);
  161. }
  162. if(!Text || !LineCount) {
  163. return;
  164. }
  165. //
  166. // Get value indicating which item is to be bolded.
  167. //
  168. HighlightedItem = (UINT)GetWindowLong(hwnd,AIL_BOLDITEM);
  169. //
  170. // Get font handles.
  171. //
  172. Font = (HFONT)GetWindowLong(hwnd,AIL_FONT);
  173. BoldFont = (HFONT)GetWindowLong(hwnd,AIL_BOLDFONT);
  174. //
  175. // Select the non-boldface font to get the handle of
  176. // the currently selected font.
  177. //
  178. OldFont = SelectObject(PaintStruct.hdc,Font);
  179. //
  180. // Set text background color.
  181. //
  182. SetBkColor(PaintStruct.hdc,GetSysColor(COLOR_3DFACE));
  183. //
  184. // Load the little triangle bitmap and create a compatible DC for it.
  185. //
  186. Bitmap = LoadBitmap(NULL,MAKEINTRESOURCE(OBM_MNARROW));
  187. if(MemoryDC = CreateCompatibleDC(PaintStruct.hdc)) {
  188. OldBitmap = SelectObject(MemoryDC,Bitmap);
  189. GetObject(Bitmap,sizeof(BITMAP),&bitmap);
  190. }
  191. Spacing = GetSystemMetrics(SM_CXICON) / 2;
  192. //
  193. // Treat the text as a series of lines and draw each one.
  194. //
  195. p = Text;
  196. y = 0;
  197. for(i=0; i<LineCount; i++) {
  198. //
  199. // Calculate the line's height based on the boldface font.
  200. // This is used to get to the y coord of the next line.
  201. //
  202. SelectObject(PaintStruct.hdc,BoldFont);
  203. GetClientRect(hwnd,&rect);
  204. rect.left = (2 * BORDER) + Spacing;
  205. rect.bottom = 0;
  206. DrawText(PaintStruct.hdc,p,lstrlen(p),&rect,DT_CALCRECT|DT_WORDBREAK);
  207. yDelta = rect.bottom + (2*BORDER);
  208. //
  209. // Change font to non-boldface for this line if necessary.
  210. //
  211. if(i != HighlightedItem) {
  212. SelectObject(PaintStruct.hdc,Font);
  213. }
  214. rect.top = y + BORDER;
  215. rect.left = (2 * BORDER) + Spacing;
  216. rect.bottom = rect.top + yDelta;
  217. //
  218. // Draw the line's text.
  219. //
  220. Length = lstrlen(p);
  221. DrawText(PaintStruct.hdc,p,Length,&rect,DT_WORDBREAK);
  222. //
  223. // Draw the little triangle thing if necessary.
  224. //
  225. if((i == HighlightedItem) && Bitmap && MemoryDC) {
  226. GetTextExtentPoint(PaintStruct.hdc,L"WWWWW",5,&Size);
  227. BitBlt(
  228. PaintStruct.hdc,
  229. BORDER,
  230. y + ((Size.cy - bitmap.bmHeight) / 2) + BORDER,
  231. bitmap.bmWidth,
  232. bitmap.bmHeight,
  233. MemoryDC,
  234. 0,0,
  235. 0x220326 // (NOT src) AND dest [DSna]
  236. );
  237. }
  238. //
  239. // Point to next line's text.
  240. //
  241. p += Length + 1;
  242. y += yDelta;
  243. }
  244. //
  245. // Clean up.
  246. //
  247. if(OldFont) {
  248. SelectObject(PaintStruct.hdc,OldFont);
  249. }
  250. if(MemoryDC) {
  251. if(OldBitmap) {
  252. SelectObject(MemoryDC,OldBitmap);
  253. }
  254. if(Bitmap) {
  255. DeleteObject(Bitmap);
  256. }
  257. DeleteDC(MemoryDC);
  258. }
  259. EndPaint(hwnd,&PaintStruct);
  260. }
  261. LRESULT
  262. ActionItemListWndProc(
  263. IN HWND hwnd,
  264. IN UINT msg,
  265. IN WPARAM wParam,
  266. IN LPARAM lParam
  267. )
  268. {
  269. LRESULT rc;
  270. HFONT OldFont,Font,BoldFont;
  271. LOGFONT LogFont;
  272. PWSTR Text;
  273. PWSTR p;
  274. UINT LineCount;
  275. BOOL FreeFont,FreeBoldFont;
  276. switch(msg) {
  277. case WM_CREATE:
  278. //
  279. // Create fonts.
  280. //
  281. OldFont = (HFONT)SendMessage(GetParent(hwnd),WM_GETFONT,0,0);
  282. if(!OldFont) {
  283. //
  284. // Using system font.
  285. //
  286. OldFont = GetStockObject(DEFAULT_GUI_FONT);
  287. }
  288. FreeFont = TRUE;
  289. FreeBoldFont = TRUE;
  290. if(OldFont && GetObject(OldFont,sizeof(LOGFONT),&LogFont)) {
  291. LogFont.lfWeight = 400;
  292. Font = CreateFontIndirect(&LogFont);
  293. if(!Font) {
  294. Font = GetStockObject(DEFAULT_GUI_FONT);
  295. FreeFont = FALSE;
  296. }
  297. LogFont.lfWeight = 700;
  298. BoldFont = CreateFontIndirect(&LogFont);
  299. if(!BoldFont) {
  300. BoldFont = Font;
  301. FreeBoldFont = FALSE;
  302. }
  303. }
  304. SetWindowLong(hwnd,AIL_FONT,(LONG)Font);
  305. SetWindowLong(hwnd,AIL_BOLDFONT,(LONG)BoldFont);
  306. SetWindowLong(hwnd,AIL_BOLDITEM,0);
  307. SetWindowLong(hwnd,AIL_TEXT,0);
  308. SetWindowLong(hwnd,AIL_LINECOUNT,0);
  309. SetWindowLong(hwnd,AIL_FREEFONTS,MAKELONG(FreeFont,FreeBoldFont));
  310. rc = 0;
  311. break;
  312. case WM_DESTROY:
  313. //
  314. // Get rid of fonts we created if necessary.
  315. //
  316. FreeFont = (BOOL)GetWindowLong(hwnd,AIL_FREEFONTS);
  317. FreeBoldFont = HIWORD(FreeFont);
  318. FreeFont = LOWORD(FreeFont);
  319. if(FreeFont && (Font = (HFONT)GetWindowLong(hwnd,AIL_FONT))) {
  320. DeleteObject(Font);
  321. }
  322. if(FreeBoldFont && (BoldFont = (HFONT)GetWindowLong(hwnd,AIL_BOLDFONT))) {
  323. DeleteObject(BoldFont);
  324. }
  325. if(Text = (PWSTR)GetWindowLong(hwnd,AIL_TEXT)) {
  326. MyFree(Text);
  327. }
  328. rc = 0;
  329. break;
  330. case WM_SETTEXT:
  331. //
  332. // Free old text and remember new text.
  333. //
  334. if(Text = (PWSTR)GetWindowLong(hwnd,AIL_TEXT)) {
  335. MyFree(Text);
  336. }
  337. LineCount = 0;
  338. if(Text = DuplicateString((PVOID)lParam)) {
  339. //
  340. // Count lines in the text. This is equal to the number of
  341. // newlines. We require that the last line have a newline
  342. // to be counted.
  343. //
  344. for(LineCount=0,p=Text; *p; p++) {
  345. if(*p == L'\r') {
  346. *p = L' ';
  347. } else {
  348. if(*p == L'\n') {
  349. *p = 0;
  350. LineCount++;
  351. }
  352. }
  353. }
  354. }
  355. //
  356. // Cheat a little: we expect wParam to be the 0-based index
  357. // of the boldfaced line. Callers will have to use SendMessage
  358. // instead of SetWindowText().
  359. //
  360. SetWindowLong(hwnd,AIL_BOLDITEM,(LONG)wParam);
  361. SetWindowLong(hwnd,AIL_LINECOUNT,LineCount);
  362. SetWindowLong(hwnd,AIL_TEXT,(LONG)Text);
  363. rc = (Text != NULL);
  364. break;
  365. case WM_PAINT:
  366. ActionItemListPaint(hwnd);
  367. rc = 0;
  368. break;
  369. default:
  370. rc = DefWindowProc(hwnd,msg,wParam,lParam);
  371. break;
  372. }
  373. return(rc);
  374. }
  375. BOOL
  376. RegisterActionItemListControl(
  377. IN BOOL Init
  378. )
  379. {
  380. WNDCLASS wc;
  381. BOOL b;
  382. static BOOL Registered;
  383. if(Init) {
  384. if(Registered) {
  385. b = TRUE;
  386. } else {
  387. wc.style = CS_PARENTDC;
  388. wc.lpfnWndProc = ActionItemListWndProc;
  389. wc.cbClsExtra = 0;
  390. wc.cbWndExtra = AIL_EXTRA * sizeof(LONG);
  391. wc.hInstance = MyModuleHandle;
  392. wc.hIcon = NULL;
  393. wc.hCursor = LoadCursor(NULL,IDC_ARROW);
  394. wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
  395. wc.lpszMenuName = NULL;
  396. wc.lpszClassName = szActionItemListClassName;
  397. if(b = (RegisterClass(&wc) != 0)) {
  398. Registered = TRUE;
  399. }
  400. }
  401. } else {
  402. if(Registered) {
  403. if(b = UnregisterClass(szActionItemListClassName,MyModuleHandle)) {
  404. Registered = FALSE;
  405. }
  406. } else {
  407. b = TRUE;
  408. }
  409. }
  410. return(b);
  411. }