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.

484 lines
15 KiB

  1. #include <windows.h>
  2. #include <custcntl.h>
  3. #include <commdlg.h>
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include "hlist.h"
  8. typedef DWORD (CALLBACK* HLISTCALLBACK)(LPDWORD,LPSTR*,LPSTR,DWORD,DWORD);
  9. #define XBITMAP 16
  10. #define YBITMAP 16
  11. #define MARGIN 6
  12. #define INDENT (XBITMAP + MARGIN)
  13. #define MIDDLE ((XBITMAP/2) + MARGIN)
  14. #define LINE_COLOR RGB(255,0,0)
  15. #define CLASS_NAME "HList"
  16. #define DESCRIPTION "Heir List Box"
  17. #define DEFAULT_STYLE WS_CHILD | \
  18. WS_VISIBLE | \
  19. WS_VSCROLL | \
  20. WS_HSCROLL | \
  21. WS_BORDER | \
  22. LBS_NOTIFY | \
  23. LBS_NOINTEGRALHEIGHT | \
  24. LBS_WANTKEYBOARDINPUT | \
  25. LBS_SORT | \
  26. LBS_OWNERDRAWFIXED
  27. typedef struct _HLISTTYPE {
  28. struct _HLISTTYPE *next;
  29. DWORD type;
  30. HBITMAP bitmap;
  31. } HLISTTYPE, *LPHLISTTYPE;
  32. typedef struct _HLISTINFO {
  33. HWND hwndList;
  34. LPHLISTTYPE typeList;
  35. HLISTCALLBACK lpCallback;
  36. } HLISTINFO, *LPHLISTINFO;
  37. typedef struct _ITEMDATA {
  38. struct _ITEMDATA *parent;
  39. DWORD type;
  40. DWORD level;
  41. DWORD nchild;
  42. DWORD childnum;
  43. LPSTR str;
  44. HBITMAP bitmap;
  45. } ITEMDATA, *LPITEMDATA;
  46. static HMODULE hInstance;
  47. LRESULT HListWndProc(HWND,UINT,WPARAM,LPARAM);
  48. BOOL
  49. HListInitialize(
  50. HMODULE hModule
  51. )
  52. {
  53. WNDCLASS wndclass;
  54. hInstance = hModule;
  55. wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS;
  56. wndclass.lpfnWndProc = HListWndProc;
  57. wndclass.cbClsExtra = 0;
  58. wndclass.cbWndExtra = 4;
  59. wndclass.hInstance = hInstance;
  60. wndclass.hIcon = NULL;
  61. wndclass.hCursor = LoadCursor( NULL, IDC_ARROW );
  62. wndclass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  63. wndclass.lpszMenuName = NULL;
  64. wndclass.lpszClassName = CLASS_NAME;
  65. if (!RegisterClass( &wndclass )) {
  66. return FALSE;
  67. }
  68. return TRUE;
  69. }
  70. VOID
  71. CollapseNode(
  72. HWND hwnd,
  73. LPITEMDATA lpid,
  74. DWORD nItem
  75. )
  76. {
  77. DWORD i;
  78. LPITEMDATA lpidChild;
  79. for (i=0; i<lpid->nchild; i++) {
  80. lpidChild = (LPITEMDATA) SendMessage( hwnd, LB_GETITEMDATA, nItem, 0 );
  81. if (lpidChild->nchild) {
  82. CollapseNode( hwnd, lpidChild, nItem+1 );
  83. }
  84. SendMessage( hwnd, LB_DELETESTRING, nItem, 0 );
  85. }
  86. lpid->nchild = 0;
  87. }
  88. LRESULT
  89. HListWndProc(
  90. HWND hwnd,
  91. UINT message,
  92. WPARAM wParam,
  93. LPARAM lParam
  94. )
  95. {
  96. RECT cRect;
  97. HFONT hFont;
  98. LPHLISTINFO hli;
  99. LPHLISTTYPE hlt;
  100. LPHLISTTYPE hltNext;
  101. LPMEASUREITEMSTRUCT lpmis;
  102. LPDELETEITEMSTRUCT lplis;
  103. LPDRAWITEMSTRUCT lpdis;
  104. HBITMAP hbmp;
  105. HBITMAP hbmpOld;
  106. HDC hdc;
  107. TEXTMETRIC tm;
  108. int x;
  109. int y;
  110. int nItem;
  111. RECT rcBitmap;
  112. LPITEMDATA lpid;
  113. LPITEMDATA lpidParent;
  114. DWORD type;
  115. LPSTR str;
  116. DWORD rval;
  117. DWORD level;
  118. LPSTR ref;
  119. LPSTR p;
  120. POINT pt;
  121. DWORD childnum;
  122. DWORD i;
  123. HPEN hpen;
  124. HPEN oldhpen;
  125. switch (message) {
  126. case WM_CREATE:
  127. hli = (LPHLISTINFO) malloc( sizeof(HLISTINFO) );
  128. ZeroMemory( hli, sizeof(HLISTINFO) );
  129. GetClientRect( hwnd, &cRect );
  130. hli->hwndList = CreateWindow(
  131. "LISTBOX",
  132. NULL,
  133. DEFAULT_STYLE,
  134. cRect.left,
  135. cRect.top,
  136. cRect.right - cRect.left,
  137. cRect.bottom - cRect.top,
  138. hwnd,
  139. NULL,
  140. GetModuleHandle(NULL),
  141. NULL );
  142. hFont = GetStockObject( SYSTEM_FIXED_FONT );
  143. SendMessage( hli->hwndList, WM_SETFONT, (WPARAM)hFont, (LPARAM)FALSE );
  144. SetFocus( hli->hwndList );
  145. SetWindowLong( hwnd, 0, (DWORD)hli );
  146. break;
  147. case WM_SIZE:
  148. hli = (LPHLISTINFO) GetWindowLong( hwnd, 0 );
  149. GetClientRect( hwnd, &cRect );
  150. MoveWindow(
  151. hli->hwndList,
  152. cRect.left,
  153. cRect.top,
  154. cRect.right - cRect.left,
  155. cRect.bottom - cRect.top,
  156. TRUE );
  157. break;
  158. case WM_DESTROY:
  159. hli = (LPHLISTINFO) GetWindowLong( hwnd, 0 );
  160. hlt = hli->typeList;
  161. while (hlt) {
  162. hltNext = hlt->next;
  163. free( hlt );
  164. hlt = hltNext;
  165. }
  166. DestroyWindow( hli->hwndList );
  167. hli->hwndList = NULL;
  168. free( hli );
  169. SetWindowLong( hwnd, 0, 0 );
  170. break;
  171. case WM_COMMAND:
  172. if (HIWORD(wParam) == LBN_DBLCLK) {
  173. hli = (LPHLISTINFO) GetWindowLong( hwnd, 0 );
  174. if (hli->lpCallback) {
  175. nItem = SendMessage( hli->hwndList, LB_GETCURSEL, 0, 0 );
  176. lpidParent = (LPITEMDATA) SendMessage( hli->hwndList, LB_GETITEMDATA, nItem, 0 );
  177. y = 0;
  178. lpid = lpidParent;
  179. while (lpid) {
  180. y += (strlen(lpid->str) + 1);
  181. lpid = lpid->parent;
  182. }
  183. y += 16;
  184. p = ref = malloc( y );
  185. lpid = lpidParent;
  186. while (lpid) {
  187. strcpy( p, lpid->str );
  188. p += (strlen(p) + 1);
  189. lpid = lpid->parent;
  190. }
  191. *p = '\0';
  192. level = lpidParent->level + 1;
  193. type = lpidParent->type;
  194. str = lpidParent->str;
  195. rval = (hli->lpCallback)( &type, &str, ref, level, lpidParent->nchild );
  196. if (rval == HLB_COLLAPSE) {
  197. CollapseNode( hli->hwndList, lpidParent, nItem+1 );
  198. break;
  199. }
  200. childnum = 1;
  201. while (rval != HLB_END) {
  202. if (rval == HLB_EXPAND) {
  203. hlt = hli->typeList;
  204. while (hlt && hlt->type != type) {
  205. hlt = hlt->next;
  206. }
  207. if (!hlt) {
  208. break;
  209. }
  210. lpidParent->nchild++;
  211. lpid = (LPITEMDATA) malloc( sizeof(ITEMDATA) );
  212. lpid->type = type;
  213. lpid->nchild = 0;
  214. lpid->level = level;
  215. lpid->bitmap = hlt->bitmap;
  216. lpid->str = _strdup( (LPSTR)str );
  217. lpid->parent = lpidParent;
  218. lpid->childnum = childnum++;
  219. nItem = SendMessage( hli->hwndList, LB_INSERTSTRING, nItem+1, (LPARAM)lpid->str );
  220. SendMessage( hli->hwndList, LB_SETITEMDATA, nItem, (LPARAM) lpid );
  221. }
  222. rval = (hli->lpCallback)( &type, &str, ref, level, 0 );
  223. }
  224. free( ref );
  225. }
  226. }
  227. break;
  228. case HLB_REGISTER_CALLBACK:
  229. hli = (LPHLISTINFO) GetWindowLong( hwnd, 0 );
  230. hli->lpCallback = (HLISTCALLBACK) lParam;
  231. return 1;
  232. case HLB_REGISTER_TYPE:
  233. //
  234. // wParam = type token
  235. // lParam = the bitmap
  236. //
  237. hli = (LPHLISTINFO) GetWindowLong( hwnd, 0 );
  238. if (!hli->typeList) {
  239. hli->typeList = (LPHLISTTYPE) malloc( sizeof(HLISTTYPE) );
  240. hlt = hli->typeList;
  241. } else {
  242. hlt = hli->typeList;
  243. while (hlt->next) {
  244. hlt = hlt->next;
  245. }
  246. hlt->next = (LPHLISTTYPE) malloc( sizeof(HLISTTYPE) );
  247. hlt = hlt->next;
  248. }
  249. hlt->type = (WPARAM) wParam;
  250. hlt->bitmap = (HBITMAP) lParam;
  251. hlt->next = NULL;
  252. return 1;
  253. case HLB_ADDSTRING:
  254. //
  255. // wParam = type
  256. // lParam = string
  257. //
  258. hli = (LPHLISTINFO) GetWindowLong( hwnd, 0 );
  259. hlt = hli->typeList;
  260. while (hlt && hlt->type != wParam) {
  261. hlt = hlt->next;
  262. }
  263. if (!hlt) {
  264. return 0;
  265. }
  266. lpid = (LPITEMDATA) malloc( sizeof(ITEMDATA) );
  267. lpid->type = hlt->type;
  268. lpid->level = 0;
  269. lpid->nchild = 0;
  270. lpid->bitmap = hlt->bitmap;
  271. lpid->str = _strdup( (LPSTR)lParam );
  272. lpid->parent = NULL;
  273. lpid->childnum = 0;
  274. nItem = SendMessage( hli->hwndList, LB_ADDSTRING, 0, (LPARAM)lpid->str );
  275. SendMessage( hli->hwndList, LB_SETITEMDATA, nItem, (LPARAM) lpid );
  276. return 1;
  277. case WM_MEASUREITEM:
  278. lpmis = (LPMEASUREITEMSTRUCT) lParam;
  279. lpmis->itemHeight = YBITMAP;
  280. return 1;
  281. case WM_DELETEITEM:
  282. lplis = (LPDELETEITEMSTRUCT) lParam;
  283. lpid = (LPITEMDATA) lplis->itemData;
  284. free( lpid->str );
  285. free( lpid );
  286. return 1;
  287. case WM_DRAWITEM:
  288. lpdis = (LPDRAWITEMSTRUCT) lParam;
  289. if (lpdis->itemID == -1) {
  290. break;
  291. }
  292. switch (lpdis->itemAction) {
  293. case ODA_SELECT:
  294. case ODA_DRAWENTIRE:
  295. lpid = (LPITEMDATA) SendMessage( lpdis->hwndItem, LB_GETITEMDATA, lpdis->itemID, 0 );
  296. hbmp = lpid->bitmap;
  297. hdc = CreateCompatibleDC( lpdis->hDC );
  298. hbmpOld = SelectObject( hdc, hbmp );
  299. lpdis->rcItem.left += (lpid->level * INDENT);
  300. BitBlt(
  301. lpdis->hDC,
  302. lpdis->rcItem.left,
  303. lpdis->rcItem.top,
  304. lpdis->rcItem.right - lpdis->rcItem.left,
  305. lpdis->rcItem.bottom - lpdis->rcItem.top,
  306. hdc,
  307. 0,
  308. 0,
  309. SRCCOPY );
  310. GetTextMetrics( lpdis->hDC, &tm );
  311. y = (lpdis->rcItem.bottom + lpdis->rcItem.top - tm.tmHeight) / 2;
  312. TextOut( lpdis->hDC, XBITMAP + MARGIN + (lpid->level * INDENT), y, lpid->str, strlen(lpid->str) );
  313. SelectObject( hdc, hbmpOld );
  314. //
  315. // now draw lines
  316. //
  317. if (lpid->level) {
  318. hpen = CreatePen( PS_SOLID, 1, LINE_COLOR );
  319. oldhpen = SelectObject( lpdis->hDC, hpen );
  320. y = lpdis->rcItem.top + ((lpdis->rcItem.bottom - lpdis->rcItem.top) / 2);
  321. MoveToEx(
  322. lpdis->hDC,
  323. lpdis->rcItem.left - 1,
  324. y,
  325. &pt );
  326. LineTo(
  327. lpdis->hDC,
  328. lpdis->rcItem.left - MIDDLE,
  329. y );
  330. MoveToEx(
  331. lpdis->hDC,
  332. lpdis->rcItem.left - MIDDLE,
  333. lpdis->rcItem.top,
  334. &pt );
  335. if (lpid->childnum < lpid->parent->nchild) {
  336. y = lpdis->rcItem.bottom;
  337. } else {
  338. y++;
  339. }
  340. LineTo(
  341. lpdis->hDC,
  342. lpdis->rcItem.left - MIDDLE,
  343. y );
  344. if (lpid->level > 1) {
  345. x = lpdis->rcItem.left - MIDDLE;
  346. y = lpdis->rcItem.top;
  347. for (i=1; i<lpid->level; i++) {
  348. MoveToEx(
  349. lpdis->hDC,
  350. x - (i * INDENT),
  351. y,
  352. &pt );
  353. LineTo(
  354. lpdis->hDC,
  355. x - (i * INDENT),
  356. lpdis->rcItem.bottom );
  357. }
  358. }
  359. SelectObject( lpdis->hDC, oldhpen );
  360. DeleteObject( hpen );
  361. }
  362. DeleteDC( hdc );
  363. if (lpdis->itemState & ODS_SELECTED) {
  364. rcBitmap.left = lpdis->rcItem.left;
  365. rcBitmap.top = lpdis->rcItem.top;
  366. rcBitmap.right = lpdis->rcItem.left + XBITMAP + (tm.tmMaxCharWidth * strlen(lpid->str)) + MARGIN + 2;
  367. rcBitmap.bottom = lpdis->rcItem.top + YBITMAP;
  368. DrawFocusRect( lpdis->hDC, &rcBitmap );
  369. }
  370. break;
  371. case ODA_FOCUS:
  372. break;
  373. }
  374. return 1;
  375. case LB_ADDSTRING:
  376. return SendMessage( hwnd, HLB_ADDSTRING, 1, lParam );
  377. case LB_INSERTSTRING:
  378. case LB_DELETESTRING:
  379. case LB_SELITEMRANGEEX:
  380. case LB_RESETCONTENT:
  381. case LB_SETSEL:
  382. case LB_SETCURSEL:
  383. case LB_GETSEL:
  384. case LB_GETCURSEL:
  385. case LB_GETTEXT:
  386. case LB_GETTEXTLEN:
  387. case LB_GETCOUNT:
  388. case LB_SELECTSTRING:
  389. case LB_DIR:
  390. case LB_ADDFILE:
  391. case LB_GETTOPINDEX:
  392. case LB_FINDSTRING:
  393. case LB_GETSELCOUNT:
  394. case LB_GETSELITEMS:
  395. case LB_SETTABSTOPS:
  396. case LB_GETHORIZONTALEXTENT:
  397. case LB_SETHORIZONTALEXTENT:
  398. case LB_SETCOLUMNWIDTH:
  399. case LB_SETTOPINDEX:
  400. case LB_GETITEMRECT:
  401. case LB_GETITEMDATA:
  402. case LB_SETITEMDATA:
  403. case LB_SELITEMRANGE:
  404. case LB_SETANCHORINDEX:
  405. case LB_GETANCHORINDEX:
  406. case LB_SETCARETINDEX:
  407. case LB_GETCARETINDEX:
  408. case LB_SETITEMHEIGHT:
  409. case LB_GETITEMHEIGHT:
  410. case LB_FINDSTRINGEXACT:
  411. case LB_SETLOCALE:
  412. case LB_GETLOCALE:
  413. case LB_SETCOUNT:
  414. hli = (LPHLISTINFO) GetWindowLong( hwnd, 0 );
  415. return SendMessage( hli->hwndList, message, wParam, lParam );
  416. }
  417. return DefWindowProc( hwnd, message, wParam, lParam );
  418. }