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.

2992 lines
108 KiB

  1. // ==================================================================================================
  2. // COPYRIGHT 1992,1993 MICROSOFT CORP ALL RIGHTS RESERVED
  3. // ==================================================================================================
  4. //
  5. // - Custom control to display Columns/Titles above a list box
  6. //
  7. // TERMINOLOGY:
  8. // PHYSICAL COLUMNS: The index of the original columns in their original order
  9. // VIRtUAL COLUMNS: The index of the column as the display is currently showing it based on
  10. // the current order.
  11. //
  12. // History:
  13. // -------
  14. // RickD 04/10/92 created TitleListBox
  15. // Tom Laird-McConnell 12/30/92 Ported to Win32, added to BH project
  16. // Tom Laird-McConnell 05/01/93 gutted titlelist and used as base for complete rewrite as ColumnLB
  17. // Tom Laird-McConnell 08/18/93 Added tabbed-delimited string support
  18. // Arth 03/24/94 Added Unicode support
  19. // ==================================================================================================
  20. #define STRICT 1
  21. #include "switches.h"
  22. #include <windows.h>
  23. #include <windowsx.h>
  24. #include <string.h>
  25. #include <stdlib.h>
  26. // #include <dprintf.h>
  27. #include "columnlb.h"
  28. #include "vlist.h"
  29. #include "utils.h"
  30. #include "debug.h"
  31. #include "mem.h"
  32. //#define DEBUG_HSCROLL 1
  33. #define WHITESPACE 8
  34. #define IDL_COLUMNLISTBOX (CLB_BASE + 1)
  35. #define IDL_COLUMNTITLELISTBOX (CLB_BASE + 2)
  36. #define LB16_ADDSTRING (WM_USER+1)
  37. #define LB16_INSERTSTRING (WM_USER+2)
  38. typedef struct _COLRECORD
  39. {
  40. DWORD_PTR itemData;
  41. LPTSTR pString[];
  42. } COLRECORD;
  43. typedef COLRECORD *LPCOLRECORD;
  44. // -------------------------------------------------------------------------------------
  45. //
  46. // window procs
  47. //
  48. LRESULT CALLBACK ColumnLBClass_ListBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  49. LRESULT CALLBACK ColumnLBClass_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  50. //
  51. // system message handlers
  52. //
  53. BOOL ColumnLBClass_OnNCCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct);
  54. void ColumnLBClass_OnNCDestroy(HWND hwnd);
  55. void ColumnLBClass_OnDestroy(HWND hwnd);
  56. void ColumnLBClass_OnPaint(HWND hwnd);
  57. void ColumnLBClass_OnSize(HWND hwnd, UINT state, int cx, int cy);
  58. void ColumnLBClass_OnSetFont(HWND hwnd, HFONT hfont, BOOL fRedraw);
  59. LRESULT ColumnLBClass_OnHScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos);
  60. void ColumnLBClass_OnDrawItem(HWND hwnd, const DRAWITEMSTRUCT * lpDrawItem);
  61. void ColumnLBClass_OnMeasureItem(HWND hwnd, LPMEASUREITEMSTRUCT lpMeasureItem);
  62. void ColumnLBClass_OnDeleteItem(HWND hwnd, const DELETEITEMSTRUCT *lpDeleteItem);
  63. int ColumnLBClass_OnCharToItem(HWND hwnd, UINT ch, HWND hwndListbox, int iCaret);
  64. //
  65. // WM_USER message handlers
  66. //
  67. BYTE ColumnLBClass_OnNumberCols(HWND hwnd, BYTE NewNumberCols, BOOL fSetColumns);
  68. int ColumnLBClass_OnColWidth(HWND hwnd, BYTE Column, int NewWidth, BOOL fSetWidth);
  69. LPTSTR ColumnLBClass_OnColTitle(HWND hwnd, BYTE Column, LPTSTR lpTitle, BOOL fSetTitle);
  70. BYTE ColumnLBClass_OnSortCol(HWND hwnd, BYTE NewSortCol, BOOL fSetSortCol);
  71. LPBYTE ColumnLBClass_OnColOrder(HWND hwnd, LPBYTE NewColOrder, BOOL fSetOrder);
  72. LPINT ColumnLBClass_OnColOffsets(HWND hwnd, LPINT NewOffsetTable, BOOL fSetOffsets);
  73. LRESULT ColumnLBClass_OnAutoWidth(HWND hwnd, BYTE ColumnToCompute);
  74. //
  75. // mouse movement messages
  76. //
  77. void ColumnLBClass_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags);
  78. void ColumnLBClass_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags);
  79. void ColumnLBClass_OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags);
  80. void ColumnLBClass_OnRButtonDown (HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags);
  81. // helper functions
  82. int ColumnLBClass_ComputeOffsets(HWND hwnd);
  83. // -------------------------------------------------------------------------------------
  84. //
  85. // Locals
  86. //
  87. BOOL fWIN32s; // flag for whether win32s (instead of win32/NT)
  88. // -----------------------------------------------------------------
  89. //
  90. // ColumnLBClass_Register()
  91. //
  92. // This function is used to register the Column LB class with the system
  93. //
  94. // HISTORY:
  95. // Tom Laird-McConnell 4/17/93 Created
  96. //
  97. // -----------------------------------------------------------------
  98. BOOL ColumnLBClass_Register(HINSTANCE hInstance)
  99. {
  100. WNDCLASS WndClass;
  101. fWIN32s = ((DWORD)GetVersion() & 0x80000000) ? TRUE : FALSE;
  102. //
  103. // Create the COLUMNLISTBOX class
  104. //
  105. WndClass.style = CS_PARENTDC | CS_DBLCLKS; // CS_GLOBALCLASS;
  106. WndClass.lpfnWndProc = ColumnLBClass_WndProc;
  107. WndClass.cbClsExtra = 0;
  108. WndClass.cbWndExtra = sizeof(LPCOLUMNLBSTRUCT); // we store a pointer as instance data
  109. WndClass.hInstance = hInstance;
  110. WndClass.hIcon = 0;
  111. WndClass.hCursor = LoadCursor(0, IDC_ARROW);
  112. WndClass.hbrBackground = 0;
  113. WndClass.lpszMenuName = 0;
  114. WndClass.lpszClassName = COLUMNLBCLASS_CLASSNAME;
  115. /* Register the normal title list box control */
  116. return RegisterClass((LPWNDCLASS)&WndClass);
  117. }
  118. // -----------------------------------------------------------------
  119. //
  120. // ColumnVLBClass_Register()
  121. //
  122. // This function is used to register the Column VLIST LB class with the system
  123. //
  124. // HISTORY:
  125. // Tom Laird-McConnell 4/17/93 Created
  126. //
  127. // -----------------------------------------------------------------
  128. BOOL ColumnVLBClass_Register(HINSTANCE hInstance)
  129. {
  130. WNDCLASS WndClass;
  131. fWIN32s = ((DWORD)GetVersion() & 0x80000000) ? TRUE : FALSE;
  132. //
  133. // Create the COLUMNVLISTBOX class
  134. //
  135. WndClass.style = CS_PARENTDC | CS_DBLCLKS; // CS_GLOBALCLASS;
  136. WndClass.lpfnWndProc = ColumnLBClass_WndProc;
  137. WndClass.cbClsExtra = 0;
  138. WndClass.cbWndExtra = sizeof(LPCOLUMNLBSTRUCT); // we store a pointer as instance data
  139. WndClass.hInstance = hInstance;
  140. WndClass.hIcon = 0;
  141. WndClass.hCursor = LoadCursor(0, IDC_ARROW);
  142. WndClass.hbrBackground = 0;
  143. WndClass.lpszMenuName = 0;
  144. WndClass.lpszClassName = COLUMNVLBCLASS_CLASSNAME; // NOTE: this is a different name
  145. /* Register the new control */
  146. return(RegisterClass((LPWNDCLASS)&WndClass));
  147. }
  148. // -----------------------------------------------------------------
  149. //
  150. // ColumnLBClass_Unregister()
  151. //
  152. // This function is used to deregister the Column LB class with the system
  153. //
  154. // HISTORY:
  155. // Tom Laird-McConnell 4/17/93 Created
  156. //
  157. // -----------------------------------------------------------------
  158. BOOL ColumnLBClass_Unregister(HINSTANCE hInstance)
  159. {
  160. return(UnregisterClass(COLUMNLBCLASS_CLASSNAME, hInstance));
  161. }
  162. // -----------------------------------------------------------------
  163. //
  164. // ColumnVLBClass_Unregister()
  165. //
  166. // This function is used to deregister the Column VLIST LB class with the system
  167. //
  168. // HISTORY:
  169. // Tom Laird-McConnell 4/17/93 Created
  170. //
  171. // -----------------------------------------------------------------
  172. BOOL ColumnVLBClass_Unregister(HINSTANCE hInstance)
  173. {
  174. return(UnregisterClass(COLUMNVLBCLASS_CLASSNAME, hInstance));
  175. }
  176. // -----------------------------------------------------------------
  177. // ColumnLBClass_ListBoxWndProc
  178. //
  179. // Window proc used in sub-classing the internal listbox to catch
  180. // internal scroll events to keep title in sync with it...
  181. //
  182. // HISTORY:
  183. // Tom Laird-McConnell 4/17/93 Created
  184. //
  185. // -----------------------------------------------------------------
  186. LRESULT CALLBACK ColumnLBClass_ListBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  187. {
  188. LRESULT result;
  189. LPCOLUMNLBSTRUCT lpColumnLB;
  190. // Everthing goes to normal listbox for processing
  191. lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(GetParent(hwnd), (DWORD)0);
  192. // preprocessing
  193. switch (msg)
  194. {
  195. case WM_HSCROLL:
  196. // do title hscroll first..
  197. result = SendMessage(lpColumnLB->hwndTitleList, WM_HSCROLL, wParam, lParam);
  198. break;
  199. case WM_SETFOCUS:
  200. lpColumnLB->fHasFocus = TRUE;
  201. //dprintf ("SetFocus to ColumnLB\n");
  202. break;
  203. case WM_KILLFOCUS:
  204. lpColumnLB->fHasFocus = FALSE;
  205. //dprintf ("KillFocus to ColumnLB\n");
  206. break;
  207. }
  208. //
  209. // call the original listbox window proc
  210. //
  211. result = CallWindowProc((WNDPROC)(lpColumnLB->OldListboxProc), hwnd, msg, (WPARAM) wParam, (LPARAM)lParam);
  212. //
  213. // or if our parent has CLBS_NOTIFYLMOUSE style, then foward LMOUSE buttons
  214. // or if our parent has CLBS_NOTIFYRMOUSE style, then foward RMOUSE buttons
  215. //
  216. switch (msg)
  217. {
  218. case WM_HSCROLL:
  219. //
  220. // if it is a Horizontal scrolls, then we foward to our parent so title can be moved
  221. // in sync with listbox....
  222. //
  223. SendMessage(GetParent(hwnd), CLB_HSCROLL, wParam, lParam );
  224. break;
  225. case VLB_RESETCONTENT:
  226. case LB_RESETCONTENT:
  227. //
  228. // if it is a LB_RESETCONTENT, or VLB_RESETCONTENT, then reset x position
  229. //
  230. SendMessage(GetParent(hwnd), CLB_HSCROLL, (WPARAM)SB_TOP, (LPARAM)NULL);
  231. break;
  232. case WM_LBUTTONDOWN :
  233. case WM_LBUTTONUP :
  234. case WM_LBUTTONDBLCLK :
  235. //
  236. // forward message to parent
  237. //
  238. if (GetWindowLong(GetParent(hwnd), GWL_EXSTYLE) & CLBS_NOTIFYLMOUSE)
  239. SendMessage(GetParent(hwnd), msg, wParam, lParam);
  240. break;
  241. case WM_RBUTTONDOWN :
  242. // case WM_RBUTTONUP :
  243. case WM_RBUTTONDBLCLK :
  244. //
  245. // forward message to parent
  246. //
  247. // if (GetWindowLong(GetParent(hwnd), GWL_EXSTYLE) & CLBS_NOTIFYRMOUSE)
  248. SendMessage(GetParent(hwnd), msg, wParam, lParam);
  249. break;
  250. default:
  251. break;
  252. }
  253. return(result);
  254. }
  255. // -----------------------------------------------------------------
  256. // ColumnLBClass_TitleListBoxWndProc
  257. //
  258. // Window proc used in sub-classing the internal Title listbox to catch
  259. // internal mouse click events...
  260. //
  261. // HISTORY:
  262. // Tom Laird-McConnell 4/17/93 Created
  263. //
  264. // -----------------------------------------------------------------
  265. LRESULT CALLBACK ColumnLBClass_TitleListBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  266. {
  267. LRESULT result;
  268. LPCOLUMNLBSTRUCT lpColumnLB;
  269. // Everthing goes to normal listbox for processing
  270. lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(GetParent(hwnd), (DWORD)0);
  271. //
  272. // call the original listbox window proc
  273. //
  274. result = CallWindowProc((WNDPROC)(lpColumnLB->OldTitleListboxProc) , hwnd, msg, (WPARAM) wParam, (LPARAM)lParam);
  275. //
  276. // foward LMOUSE buttons, foward RMOUSE buttons
  277. //
  278. switch (msg)
  279. {
  280. #ifdef DEBUG_HSCROLL
  281. case WM_HSCROLL:
  282. dprintf(TEXT("ColumnLBClass_TitleListBoxProc: CallWindowProc(OldListboxProc) returned %ld to hwnd=%lx, wParam=%u, lParam=%u\n"), hwnd, wParam, lParam);
  283. break;
  284. #endif
  285. case WM_MOUSEMOVE:
  286. case WM_LBUTTONDOWN :
  287. case WM_LBUTTONUP :
  288. case WM_LBUTTONDBLCLK :
  289. case WM_RBUTTONDOWN :
  290. case WM_RBUTTONUP :
  291. case WM_RBUTTONDBLCLK :
  292. SendMessage(GetParent(hwnd), msg, wParam, lParam);
  293. break;
  294. case WM_SETFOCUS:
  295. // we don't ever want the focus, so give it back to the parent...
  296. SendMessage(GetParent(hwnd), msg, wParam, lParam);
  297. break;
  298. case WM_SIZE:
  299. // we need to reset our idea of what our current scroll position is...
  300. break;
  301. }
  302. return(result);
  303. }
  304. // -----------------------------------------------------------------
  305. // ColumnLBClass_WndProc
  306. //
  307. // Main window proc for handling messages for both the ColumnLB and
  308. // ColumnVLB classes...
  309. //
  310. // HISTORY:
  311. // Tom Laird-McConnell 4/17/93 Created
  312. //
  313. // -----------------------------------------------------------------
  314. LRESULT CALLBACK ColumnLBClass_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  315. {
  316. LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0);
  317. LPCOLRECORD lpRecord;
  318. LRESULT result;
  319. //
  320. // check for ListBox message coming from application
  321. // and forward them onto the listbox itself...
  322. //
  323. if ( ((fWIN32s == TRUE) && (msg >= WM_USER && msg < (WM_USER + LB_MSGMAX - LB_ADDSTRING + 1)) ) || // WIN32s version BUGBUG
  324. ((fWIN32s == FALSE) && (msg >= LB_ADDSTRING && msg < LB_MSGMAX)) || // NT version BUGBUG
  325. ((msg >= VLB_TOVLIST_MSGMIN) && (msg <= VLB_TOVLIST_MSGMAX)) // vlb sepcific APP->VLIST messages should be fowarded...
  326. )
  327. {
  328. //
  329. // OWNERDRAW parent, so just send it to the hwnd list child
  330. //
  331. return(SendMessage(lpColumnLB->hwndList, msg, wParam, lParam));
  332. }
  333. //
  334. // check to see if message is a TO APPLCATION message from the child listbox
  335. // which should be forwarded to application parent window
  336. //
  337. if ((msg >= VLB_TOAPP_MSGMIN) && (msg <= VLB_TOAPP_MSGMAX))
  338. return(SendMessage(GetParent(hwnd), msg, wParam, lParam)); // forward to parent...
  339. //
  340. // since it's not a message passing through, then process this message
  341. // as our own...
  342. //
  343. switch (msg)
  344. {
  345. HANDLE_MSG(hwnd, WM_NCCREATE, ColumnLBClass_OnNCCreate);
  346. HANDLE_MSG(hwnd, WM_NCDESTROY, ColumnLBClass_OnNCDestroy);
  347. HANDLE_MSG(hwnd, WM_DESTROY, ColumnLBClass_OnDestroy);
  348. HANDLE_MSG(hwnd, WM_PAINT, ColumnLBClass_OnPaint);
  349. HANDLE_MSG(hwnd, WM_SIZE, ColumnLBClass_OnSize);
  350. HANDLE_MSG(hwnd, WM_DRAWITEM, ColumnLBClass_OnDrawItem);
  351. HANDLE_MSG(hwnd, WM_MEASUREITEM, ColumnLBClass_OnMeasureItem);
  352. HANDLE_MSG(hwnd, WM_DELETEITEM, ColumnLBClass_OnDeleteItem);
  353. HANDLE_MSG(hwnd, WM_LBUTTONDOWN, ColumnLBClass_OnLButtonDown);
  354. HANDLE_MSG(hwnd, WM_LBUTTONDBLCLK, ColumnLBClass_OnLButtonDown);
  355. HANDLE_MSG(hwnd, WM_LBUTTONUP, ColumnLBClass_OnLButtonUp);
  356. HANDLE_MSG(hwnd, WM_MOUSEMOVE, ColumnLBClass_OnMouseMove);
  357. case WM_RBUTTONDOWN:
  358. // figure out what item we are on and tell our parent.
  359. HANDLE_WM_RBUTTONDOWN ( hwnd, wParam, lParam, ColumnLBClass_OnRButtonDown );
  360. break;
  361. case WM_CREATE:
  362. {
  363. LPCREATESTRUCT lpCreate = (LPCREATESTRUCT) lParam;
  364. ColumnLBClass_OnSize(hwnd, SIZE_RESTORED, lpCreate->cx, lpCreate->cy);
  365. }
  366. break;
  367. // -------------------------------------------------------------------
  368. // put System messages here which explicitly need to be passed to LISTBOX
  369. //
  370. case WM_SETFONT:
  371. HANDLE_WM_SETFONT(hwnd, wParam, lParam, ColumnLBClass_OnSetFont);
  372. break;
  373. // put the focus on the list box if we get it
  374. case WM_SETFOCUS:
  375. lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0);
  376. SetFocus(lpColumnLB->hwndList);
  377. break;
  378. case SBM_SETPOS :
  379. case SBM_SETRANGE :
  380. case SBM_SETRANGEREDRAW :
  381. //
  382. // need to foward SBM messages to both listboxes...
  383. //
  384. SendMessage(lpColumnLB->hwndTitleList, msg, wParam, lParam);
  385. return(SendMessage(lpColumnLB->hwndList, msg, wParam, lParam));
  386. case SBM_GETPOS :
  387. case SBM_GETRANGE :
  388. case SBM_ENABLE_ARROWS :
  389. return(SendMessage(lpColumnLB->hwndList, msg, wParam, lParam));
  390. // ------------------------------------------------------------------------------
  391. //
  392. // LB_XXXXXXX Messages (disguised as CLB_XXXXXX messages)
  393. // to pass on to child listbox, if the parent didn't want us to
  394. // be owner draw, then we implement ownerddraw default behavior ourself
  395. //
  396. // ------------------------------------------------------------------------------
  397. case CLB_ADDSTRING:
  398. case CLB_INSERTSTRING:
  399. //
  400. // if the parent is NOT handling OWNERDRAW, then we need to handle
  401. //
  402. if ( ! (lpColumnLB->Style & (LBS_OWNERDRAWFIXED | VLBS_OWNERDRAWFIXED)) )
  403. {
  404. LPTSTR lpColStart,lpTab;
  405. LPTSTR lpStringBuffer;
  406. int i;
  407. lpRecord = (LPCOLRECORD)GlobalAllocPtr(GPTR, sizeof(COLRECORD) + sizeof(LPTSTR) * lpColumnLB->nColumns);
  408. lpStringBuffer = (LPTSTR) GlobalAllocPtr(GPTR, (lstrlen((LPTSTR)lParam) * sizeof(TCHAR)) + sizeof(TCHAR));
  409. if ((lpRecord) && (lpStringBuffer))
  410. {
  411. // now parse the tab-deliminated string and put into each pointer
  412. lstrcpy(lpStringBuffer, (LPTSTR)lParam);
  413. lpColStart = lpStringBuffer;
  414. lpTab = lstrchr(lpStringBuffer, TEXT('\t'));
  415. // fill in pointer table
  416. for (i=0; i < lpColumnLB->nColumns; i++)
  417. {
  418. if (lpTab)
  419. *lpTab = '\0';
  420. else
  421. {
  422. // there was an error, not enough tabs!
  423. GlobalFreePtr(lpRecord);
  424. GlobalFreePtr(lpStringBuffer);
  425. return(LB_ERR);
  426. }
  427. // store this pointer.
  428. lpRecord->pString[i] = lpColStart;
  429. // advance to next column text
  430. lpColStart = lpTab + 1;
  431. lpTab = lstrchr(lpColStart, TEXT('\t'));
  432. }
  433. lpRecord->itemData = 0;
  434. // and now pass on our new lpRecord as the item being added to the listbox
  435. return(SendMessage(lpColumnLB->hwndList, msg - CLB_BASE, wParam, (LPARAM)lpRecord));
  436. }
  437. else // an error has occured, free up any memory and return failure
  438. {
  439. if (lpStringBuffer)
  440. GlobalFreePtr(lpStringBuffer);
  441. if (lpRecord)
  442. GlobalFreePtr(lpRecord);
  443. return(LB_ERR);
  444. }
  445. }
  446. else
  447. //
  448. // Parent is owner draw, so send it to the hwnd list child,
  449. // but translate the message first to real LB_ message
  450. //
  451. return(SendMessage(lpColumnLB->hwndList, msg - CLB_BASE, wParam, lParam));
  452. // and we also need to check for LB_GETTEXT to make it look like a string
  453. case CLB_GETTEXT:
  454. //
  455. // if the parent is NOT handling OWNERDRAW, then we need to handle
  456. //
  457. if ( ! (lpColumnLB->Style & (LBS_OWNERDRAWFIXED | VLBS_OWNERDRAWFIXED)) )
  458. {
  459. LPTSTR p = (LPTSTR)lParam;
  460. DWORD Length = 0;
  461. DWORD x;
  462. int i;
  463. *p = '\0';
  464. // and now pass on to get the text...
  465. lpRecord = (LPCOLRECORD)SendMessage(lpColumnLB->hwndList, LB_GETITEMDATA, wParam, 0);
  466. if (lpRecord == (LPCOLRECORD)LB_ERR)
  467. return(LB_ERR);
  468. for (i=0; i < lpColumnLB->nColumns ; i++ )
  469. {
  470. lstrcpy(p, lpRecord->pString[lpColumnLB->ColumnOrderTable[i]]);
  471. lstrcat(p, TEXT("\t"));
  472. x = lstrlen(p);
  473. Length += x + sizeof(TCHAR);
  474. p += x;
  475. }
  476. return(Length);
  477. }
  478. else
  479. //
  480. // Parent is owner draw, so send it to the hwnd list child,
  481. // but translate the message first to real LB_ message
  482. //
  483. return(SendMessage(lpColumnLB->hwndList, msg - CLB_BASE, wParam, lParam));
  484. case CLB_GETTEXTPTRS:
  485. if ( ! (lpColumnLB->Style & (LBS_OWNERDRAWFIXED | VLBS_OWNERDRAWFIXED)) )
  486. {
  487. lpRecord = (LPCOLRECORD)SendMessage(lpColumnLB->hwndList, LB_GETITEMDATA, wParam, 0);
  488. if (lpRecord == (LPCOLRECORD)LB_ERR)
  489. return(LB_ERR);
  490. return (LRESULT)lpRecord->pString;
  491. }
  492. else
  493. return (LRESULT)NULL;
  494. // we need to handle LB_GETTEXTLEN to return full tabbed length...
  495. case CLB_GETTEXTLEN:
  496. //
  497. // if the parent is NOT handling OWNERDRAW, then we need to handle
  498. //
  499. if ( ! (lpColumnLB->Style & (LBS_OWNERDRAWFIXED | VLBS_OWNERDRAWFIXED)) )
  500. {
  501. LPTSTR p = (LPTSTR)lParam;
  502. DWORD Length = 0;
  503. int i;
  504. // and now pass on to get the text...
  505. lpRecord = (LPCOLRECORD)SendMessage(lpColumnLB->hwndList, LB_GETITEMDATA, wParam, 0);
  506. if (lpRecord == (LPCOLRECORD)LB_ERR)
  507. return(LB_ERR);
  508. for (i=0; i < lpColumnLB->nColumns ; i++ )
  509. {
  510. Length += lstrlen(lpRecord->pString[lpColumnLB->ColumnOrderTable[i]]) + sizeof(TCHAR);
  511. }
  512. return(Length);
  513. }
  514. else
  515. //
  516. // Parent is owner draw, so send it to the hwnd list child,
  517. // but translate the message first to real LB_ message
  518. //
  519. return(SendMessage(lpColumnLB->hwndList, msg - CLB_BASE, wParam, lParam));
  520. case CLB_GETITEMDATA:
  521. //
  522. // if the parent is NOT handling OWNERDRAW, then we need to handle
  523. //
  524. if ( ! (lpColumnLB->Style & (LBS_OWNERDRAWFIXED | VLBS_OWNERDRAWFIXED)) )
  525. {
  526. lpRecord = (LPCOLRECORD)SendMessage(lpColumnLB->hwndList, LB_GETITEMDATA, wParam, 0);
  527. if (lpRecord != (LPCOLRECORD)LB_ERR)
  528. return(lpRecord->itemData);
  529. else
  530. return(LB_ERR);
  531. }
  532. else
  533. //
  534. // Parent is owner draw, so send it to the hwnd list child,
  535. // but translate the message first to real LB_ message
  536. //
  537. return(SendMessage(lpColumnLB->hwndList, msg - CLB_BASE, wParam, lParam));
  538. case CLB_SETITEMDATA:
  539. //
  540. // if the parent is NOT handling OWNERDRAW, then we need to handle
  541. //
  542. if ( ! (lpColumnLB->Style & (LBS_OWNERDRAWFIXED | VLBS_OWNERDRAWFIXED)) )
  543. {
  544. lpRecord = (LPCOLRECORD)SendMessage(lpColumnLB->hwndList, LB_GETITEMDATA, wParam, 0);
  545. if (lpRecord != (LPCOLRECORD)LB_ERR)
  546. return (LRESULT)(lpRecord->itemData = lParam);
  547. else
  548. return(LB_ERR);
  549. }
  550. else
  551. //
  552. // Parent is owner draw, so send it to the hwnd list child,
  553. // but translate the message first to real LB_ message
  554. //
  555. return(SendMessage(lpColumnLB->hwndList, msg - CLB_BASE, wParam, lParam));
  556. //
  557. // if it is a HORIZONTAL exntent message, then we need to massage...
  558. //
  559. case CLB_SETHORIZONTALEXTENT :
  560. //
  561. // send the message to the title listbox as well
  562. //
  563. SendMessage(lpColumnLB->hwndTitleList, LB_SETHORIZONTALEXTENT, wParam, lParam);
  564. //
  565. // pass it on to the child listbox, using VLB_SETHOR if appropriate...
  566. //
  567. return(SendMessage(lpColumnLB->hwndList,
  568. (lpColumnLB->fUseVlist) ? VLB_SETHORIZONTALEXTENT : LB_SETHORIZONTALEXTENT,
  569. wParam, lParam));
  570. //
  571. // we need to massage the GETITEMRECT to handle the incorrect rect returned due to titlelistbox.
  572. //
  573. case CLB_GETITEMRECT:
  574. {
  575. LRESULT retcode;
  576. int height;
  577. LPRECT lpRect = (LPRECT)lParam;
  578. //
  579. // send it to the hwnd list child, but translate the message first to real LB_ message
  580. //
  581. retcode = SendMessage(lpColumnLB->hwndList, msg - CLB_BASE, wParam, lParam);
  582. height = lpRect->bottom-lpRect->top;
  583. lpRect->top = lpRect->bottom + 1;
  584. lpRect->bottom = lpRect->top + height;
  585. return(retcode);
  586. }
  587. break;
  588. case CLB_DELETESTRING :
  589. case CLB_SELITEMRANGEEX :
  590. case CLB_RESETCONTENT :
  591. case CLB_SETSEL :
  592. case CLB_SETCURSEL :
  593. case CLB_GETSEL :
  594. case CLB_GETCURSEL :
  595. case CLB_GETCOUNT :
  596. case CLB_SELECTSTRING :
  597. case CLB_DIR :
  598. case CLB_GETTOPINDEX :
  599. case CLB_FINDSTRING :
  600. case CLB_GETSELCOUNT :
  601. case CLB_GETSELITEMS :
  602. case CLB_SETTABSTOPS :
  603. case CLB_GETHORIZONTALEXTENT :
  604. case CLB_SETCOLUMNWIDTH :
  605. case CLB_ADDFILE :
  606. case CLB_SETTOPINDEX :
  607. case CLB_SELITEMRANGE :
  608. case CLB_SETANCHORINDEX :
  609. case CLB_GETANCHORINDEX :
  610. case CLB_SETCARETINDEX :
  611. case CLB_GETCARETINDEX :
  612. case CLB_SETITEMHEIGHT :
  613. case CLB_GETITEMHEIGHT :
  614. case CLB_FINDSTRINGEXACT :
  615. case CLB_SETLOCALE :
  616. case CLB_GETLOCALE :
  617. case CLB_SETCOUNT :
  618. //
  619. // Simply send it to the hwnd list child, but translate the message first to real LB_ message
  620. //
  621. return(SendMessage(lpColumnLB->hwndList, msg - CLB_BASE, wParam, lParam));
  622. // -------------------------------------------------------------------
  623. // put messages here which explicitly need to be passed to our PARENT
  624. //
  625. case WM_COMMAND:
  626. /* if this is a notification message from our child translate */
  627. /* it to look like it is from us and pass on to our parent */
  628. if (LOWORD(wParam) == IDL_COLUMNLISTBOX)
  629. return(SendMessage( GetParent(hwnd),
  630. msg,
  631. MAKELONG( GetDlgCtrlID(hwnd) ,HIWORD(wParam)),
  632. (LPARAM)hwnd )); // make it look like we were the ones sending the message...
  633. else
  634. return(SendMessage(GetParent(hwnd), msg, wParam, (LPARAM)hwnd));
  635. case WM_VKEYTOITEM:
  636. // pass on to our parent but using our hwnd...
  637. if (lpColumnLB->Style & (LBS_WANTKEYBOARDINPUT | VLBS_WANTKEYBOARDINPUT) )
  638. return(SendMessage(GetParent(hwnd), msg, wParam, (LPARAM)hwnd));
  639. else
  640. return(-1); // perform default action...
  641. case WM_CHARTOITEM:
  642. if (lpColumnLB->Style & (LBS_WANTKEYBOARDINPUT | VLBS_WANTKEYBOARDINPUT) )
  643. if ((result = SendMessage(GetParent(hwnd), msg, wParam, (LPARAM)hwnd)) != -1)
  644. return(result);
  645. return HANDLE_WM_CHARTOITEM(hwnd, wParam, lParam, ColumnLBClass_OnCharToItem);
  646. case WM_COMPAREITEM:
  647. {
  648. LPCOMPAREITEMSTRUCT lpCompareItem = (LPCOMPAREITEMSTRUCT)lParam;
  649. LRESULT result;
  650. if ((lpColumnLB->Style & LBS_OWNERDRAWFIXED) ||
  651. (lpColumnLB->Style & VLBS_OWNERDRAWFIXED))
  652. {
  653. //
  654. // substitute our values in the COMPAREITEMSTRUCT...
  655. //
  656. lpCompareItem->CtlID = GetDlgCtrlID(hwnd);
  657. lpCompareItem->hwndItem = hwnd;
  658. //
  659. // then pass to our parent as our WM_COMPAREITEM, with the current physcial sort column as wParam
  660. //
  661. result = (int)SendMessage(GetParent(hwnd), WM_COMPAREITEM, (WPARAM)lpColumnLB->SortColumn, (LPARAM)lpCompareItem);
  662. return(result);
  663. }
  664. else
  665. {
  666. LPTSTR lpString1;
  667. LPTSTR lpString2;
  668. LPCOLRECORD lpColRecord1;
  669. LPCOLRECORD lpColRecord2;
  670. // handle ourselves assuming item data is pointer to array of LPTSTR's
  671. lpColRecord1 = (LPCOLRECORD)lpCompareItem->itemData1;
  672. lpColRecord2 = (LPCOLRECORD)lpCompareItem->itemData2;
  673. lpString1 = lpColRecord1->pString[lpColumnLB->SortColumn];
  674. lpString2 = lpColRecord2->pString[lpColumnLB->SortColumn];
  675. if (lpString1 && lpString2)
  676. return(lstrcmpi(lpString1, lpString2));
  677. else
  678. return(0);
  679. }
  680. }
  681. break;
  682. // ---------------------------------------------------------
  683. // handle our own messages
  684. // ---------------------------------------------------------
  685. //
  686. // NUMBER COLUMNS
  687. //
  688. case CLB_GETNUMBERCOLS : // get the number of columns (ret=NumCols)
  689. return ColumnLBClass_OnNumberCols(hwnd, 0, FALSE);
  690. case CLB_SETNUMBERCOLS : // set the number of columns (wparam=NumCols)
  691. return ColumnLBClass_OnNumberCols(hwnd, (BYTE)wParam, TRUE);
  692. // ----------------------------------------------------------------
  693. // Following messages use physical column numbers
  694. // ----------------------------------------------------------------
  695. //
  696. // COLUMN WIDTH
  697. //
  698. case CLB_GETCOLWIDTH : // get a column width (wParm=Physical Column ret=ColWidth in LU's)
  699. return ColumnLBClass_OnColWidth(hwnd, (BYTE)wParam, (int)0, FALSE);
  700. case CLB_SETCOLWIDTH : // set a column width (wParm=Physical Column lParam=Width)
  701. return ColumnLBClass_OnColWidth(hwnd, (BYTE)wParam, (int)lParam, TRUE);
  702. case CLB_AUTOWIDTH : // auto-matically set column widths using titles... (wParam = Physical Column to auto width)
  703. return ColumnLBClass_OnAutoWidth(hwnd, (BYTE)wParam);
  704. //
  705. // COLUMN TITLE
  706. //
  707. case CLB_GETCOLTITLE : // get a column's title (wParm=Physical Column, ret=Title)
  708. return (LRESULT)ColumnLBClass_OnColTitle(hwnd, (BYTE)wParam, (LPTSTR)NULL, FALSE);
  709. case CLB_SETCOLTITLE : // set a column's title (wParm=Physical Col, lParm=Title)
  710. return (LRESULT)ColumnLBClass_OnColTitle(hwnd, (BYTE)wParam, (LPTSTR)lParam, TRUE);
  711. case CLB_GETROWCOLTEXT:
  712. //
  713. // if the parent is NOT handling OWNERDRAW, then we need to handle
  714. //
  715. if ( ! (lpColumnLB->Style & (LBS_OWNERDRAWFIXED | VLBS_OWNERDRAWFIXED)) )
  716. {
  717. INT WhichCol = (INT)(wParam);
  718. INT WhichRow = (INT)(lParam);
  719. // and now pass on to get the text...
  720. lpRecord = (LPCOLRECORD)SendMessage(lpColumnLB->hwndList, LB_GETITEMDATA, WhichRow, 0);
  721. if (lpRecord == (LPCOLRECORD)LB_ERR)
  722. return((LRESULT)NULL);
  723. return (LRESULT)lpRecord->pString[WhichCol];
  724. }
  725. return((LRESULT)NULL); // owner draw, the owner has to figure this out themselves
  726. //
  727. // SORT COLUMN
  728. //
  729. case CLB_GETSORTCOL : // get the physical sort column (ret=Physical Col)
  730. return (LRESULT)ColumnLBClass_OnSortCol(hwnd, 0, FALSE);
  731. case CLB_SETSORTCOL : // set the physical sort column (wParm=Physical Col)
  732. return (LRESULT)ColumnLBClass_OnSortCol(hwnd, (BYTE)wParam, TRUE);
  733. //
  734. // COLUMN ORDER
  735. //
  736. case CLB_GETCOLORDER : // get the virtual order of physical columns (ret = LPDWORD order table)
  737. return (LRESULT)ColumnLBClass_OnColOrder(hwnd, (LPBYTE)0, FALSE);
  738. case CLB_SETCOLORDER : // get the virtual order of physical columns (wParam = LPDWORD order table)
  739. return (LRESULT)ColumnLBClass_OnColOrder(hwnd, (LPBYTE)lParam, TRUE);
  740. case CLB_CHECKFOCUS: // does the listbox have the focus?
  741. // if (lpColumnLB->fUseVlist) // then we have to ask vlist the info
  742. // return
  743. // else
  744. return lpColumnLB->fHasFocus;
  745. // ----------------------------------------------------------------
  746. // Following messages use virtual column numbers
  747. // ----------------------------------------------------------------
  748. //
  749. // COLUMN OFFSETS
  750. //
  751. case CLB_GETCOLOFFSETS : // gets the incremental virtual col offsets (ret=LPDWORD)
  752. return (LRESULT)ColumnLBClass_OnColOffsets(hwnd, (LPINT)wParam, FALSE);
  753. // case CLB_SETCOLOFFSETS : // gets the incremental virtual col offsets (ret=LPDWORD)
  754. // return (LRESULT)ColumnLBClass_OnColOffsets(hwnd, (LPDWORD)wParam, TRUE);
  755. // =================================================================
  756. // INTERNAL
  757. //
  758. case CLB_HSCROLL : // a hscroll event (INTERNAL)
  759. return ColumnLBClass_OnHScroll(hwnd, (HWND)(lParam), (int)LOWORD(wParam), (int)HIWORD(wParam));
  760. //
  761. // GET FOCUS
  762. //
  763. case CLB_GETFOCUS : // get the handle for the window of CLB with the key focus
  764. if ( lpColumnLB->fUseVlist )
  765. // we must ask the column list box below us for the information.
  766. return SendMessage ( lpColumnLB->hwndList, VLB_GETFOCUSHWND, 0,0 );
  767. return (LRESULT) lpColumnLB->hwndList;
  768. default:
  769. return(DefWindowProc(hwnd, msg, wParam, lParam));
  770. }
  771. return(TRUE);
  772. }
  773. // ------------------------------------------------------------------
  774. // ColumnLBClass_OnNCCreate()
  775. //
  776. // Handles WM_NCCCREATE message
  777. //
  778. // HISTORY:
  779. // Tom Laird-McConnell 4/18/93 Created
  780. // ------------------------------------------------------------------
  781. BOOL ColumnLBClass_OnNCCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct)
  782. {
  783. LPCOLUMNLBSTRUCT lpColumnLB;
  784. HWND hwndList;
  785. HWND hwndTitleList;
  786. BOOL fUseVlist;
  787. HDC hdc;
  788. TEXTMETRIC tm;
  789. RECT rect;
  790. WORD ncxBorder;
  791. WORD ncyBorder;
  792. WORD yTitle;
  793. ncxBorder = (WORD) GetSystemMetrics(SM_CXBORDER);
  794. ncyBorder = (WORD) GetSystemMetrics(SM_CYBORDER);
  795. //
  796. // if the classname is for ColumnVLB class, then they want the Column Virtual list box...
  797. //
  798. if (lstrcmpi(lpCreateStruct->lpszClass, COLUMNVLBCLASS_CLASSNAME) == 0)
  799. fUseVlist = TRUE;
  800. else
  801. fUseVlist = FALSE;
  802. hdc = GetDC(hwnd);
  803. GetTextMetrics(hdc, &tm);
  804. ReleaseDC(hwnd, hdc);
  805. yTitle = (WORD)(tm.tmHeight + 2*ncyBorder);
  806. GetClientRect(hwnd, &rect);
  807. //
  808. // create the title list box window...
  809. //
  810. hwndTitleList = CreateWindow( (LPTSTR) TEXT("LISTBOX"),
  811. (LPTSTR) TEXT(""),
  812. (lpCreateStruct->style & ~WS_BORDER) |
  813. LBS_NOINTEGRALHEIGHT |
  814. LBS_OWNERDRAWFIXED |
  815. WS_VISIBLE |
  816. WS_CHILD,
  817. ncxBorder,
  818. ncyBorder,
  819. lpCreateStruct->cx - (2*ncxBorder) - GetSystemMetrics(SM_CXVSCROLL),
  820. yTitle,
  821. hwnd,
  822. (HMENU)IDL_COLUMNTITLELISTBOX,
  823. lpCreateStruct->hInstance,
  824. NULL);
  825. if (fUseVlist == TRUE)
  826. //
  827. // create a Vlist window...
  828. //
  829. hwndList = CreateWindow((LPTSTR)VLIST_CLASSNAME,
  830. (LPTSTR) TEXT(""),
  831. (lpCreateStruct->style & ~(WS_BORDER | VLBS_HASSTRINGS)) | // NOTE: This can _never_ be hasstrings
  832. VLBS_NOTIFY |
  833. VLBS_USETABSTOPS |
  834. VLBS_NOINTEGRALHEIGHT |
  835. VLBS_OWNERDRAWFIXED | // we always force this as either we will owner draw, or our parent will
  836. WS_HSCROLL |
  837. WS_VSCROLL |
  838. VLBS_DISABLENOSCROLL |
  839. WS_VISIBLE |
  840. WS_CHILD,
  841. ncxBorder,
  842. yTitle + ncyBorder,
  843. lpCreateStruct->cx - ncxBorder, // -(2*ncxBorder)
  844. lpCreateStruct->cy - yTitle - ncyBorder,
  845. hwnd,
  846. (HMENU)IDL_COLUMNLISTBOX,
  847. lpCreateStruct->hInstance,
  848. NULL);
  849. else
  850. //
  851. // create a list box window...
  852. //
  853. #ifdef H_SCROLL
  854. hwndList = CreateWindow((LPTSTR) TEXT("LISTBOX"),
  855. (LPTSTR) TEXT(""),
  856. (lpCreateStruct->style & ~(WS_BORDER | LBS_HASSTRINGS)) | // NOTE: This can _never_ be hasstrings
  857. LBS_NOTIFY |
  858. LBS_USETABSTOPS |
  859. LBS_NOINTEGRALHEIGHT |
  860. LBS_OWNERDRAWFIXED | // we always force this as either we will owner draw, or our parent will
  861. WS_HSCROLL |
  862. WS_VSCROLL |
  863. LBS_DISABLENOSCROLL |
  864. WS_VISIBLE |
  865. WS_CHILD,
  866. ncxBorder,
  867. yTitle + ncyBorder,
  868. lpCreateStruct->cx - ncxBorder, // -(2*ncxBorder)
  869. lpCreateStruct->cy - yTitle - ncyBorder,
  870. hwnd,
  871. (HMENU)IDL_COLUMNLISTBOX,
  872. lpCreateStruct->hInstance,
  873. NULL);
  874. #else
  875. hwndList = CreateWindow((LPTSTR) TEXT("LISTBOX"),
  876. (LPTSTR) TEXT(""),
  877. (lpCreateStruct->style & ~(WS_BORDER | LBS_HASSTRINGS)) | // NOTE: This can _never_ be hasstrings
  878. LBS_NOTIFY |
  879. LBS_USETABSTOPS |
  880. LBS_NOINTEGRALHEIGHT |
  881. LBS_OWNERDRAWFIXED | // we always force this as either we will owner draw, or our parent will
  882. WS_VSCROLL |
  883. LBS_DISABLENOSCROLL |
  884. WS_VISIBLE |
  885. WS_CHILD,
  886. ncxBorder,
  887. yTitle + ncyBorder,
  888. lpCreateStruct->cx - ncxBorder, // -(2*ncxBorder)
  889. lpCreateStruct->cy - yTitle - ncyBorder,
  890. hwnd,
  891. (HMENU)IDL_COLUMNLISTBOX,
  892. lpCreateStruct->hInstance,
  893. NULL);
  894. #endif
  895. //
  896. // if we succeeded...
  897. //
  898. if (hwndList)
  899. {
  900. //
  901. // create a ColumnLB struct to keep track of all of the pertinent instance
  902. // info for this instance of a ColumnLB window
  903. //
  904. lpColumnLB = (LPCOLUMNLBSTRUCT)GlobalAllocPtr(GPTR, sizeof(COLUMNLBSTRUCT));
  905. if (lpColumnLB)
  906. {
  907. BYTE i;
  908. //
  909. // store it in the window data for this window
  910. //
  911. SetWindowLongPtr(hwnd, 0, (LONG_PTR) lpColumnLB);
  912. memset(lpColumnLB, '\0', sizeof(COLUMNLBSTRUCT));
  913. //
  914. // fill in pertinent info
  915. //
  916. lpColumnLB->Style = lpCreateStruct->style;
  917. lpColumnLB->hInstance = (HINSTANCE)GetWindowLong(hwnd, GWLP_HINSTANCE);
  918. lpColumnLB->fUseVlist = (UCHAR) fUseVlist;
  919. lpColumnLB->fSorting = FALSE;
  920. lpColumnLB->fMouseState = 0;
  921. lpColumnLB->hwndList = hwndList;
  922. lpColumnLB->OldListboxProc = (FARPROC)GetWindowLong(hwndList, GWLP_WNDPROC);
  923. lpColumnLB->NewListboxProc = MakeProcInstance((FARPROC)ColumnLBClass_ListBoxWndProc, hInst);
  924. lpColumnLB->hwndTitleList = hwndTitleList;
  925. lpColumnLB->OldTitleListboxProc = (FARPROC)GetWindowLong(hwndTitleList, GWLP_WNDPROC);
  926. lpColumnLB->NewTitleListboxProc = MakeProcInstance((FARPROC)ColumnLBClass_TitleListBoxWndProc, hInst);
  927. lpColumnLB->nColumns=1;
  928. lpColumnLB->yTitle = yTitle;
  929. //
  930. // init sort order
  931. //
  932. for (i=0; i < MAX_COLUMNS ; i++ )
  933. lpColumnLB->ColumnOrderTable[i] = i;
  934. //
  935. // sub-class the listbox window by substituting our window proc for the
  936. // normal one...
  937. //
  938. SetWindowLongPtr(hwndList, GWLP_WNDPROC,(DWORD_PTR)lpColumnLB->NewListboxProc);
  939. //
  940. // sub-class the title listbox window by substituting our window proc for the
  941. // normal one...
  942. //
  943. SetWindowLongPtr(hwndTitleList, GWLP_WNDPROC,(DWORD_PTR)lpColumnLB->NewTitleListboxProc);
  944. //
  945. // add the lpColumnLB struct as the only item in the title listbox
  946. //
  947. ListBox_AddString(lpColumnLB->hwndTitleList, (DWORD_PTR)lpColumnLB);
  948. //
  949. // pass this on to the default window proc
  950. //
  951. return(FORWARD_WM_NCCREATE(hwnd, lpCreateStruct, DefWindowProc));
  952. }
  953. else
  954. {
  955. return(FALSE);
  956. }
  957. }
  958. else
  959. return(FALSE);
  960. }
  961. // ------------------------------------------------------------------
  962. // ColumnLBClass_OnDestroy()
  963. //
  964. // Handles WM_DESTROY message
  965. //
  966. // HISTORY:
  967. // Tom Laird-McConnell 7/18/93 Created
  968. // ------------------------------------------------------------------
  969. void ColumnLBClass_OnDestroy(HWND hwnd)
  970. {
  971. LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0);
  972. DestroyWindow(lpColumnLB->hwndTitleList);
  973. DestroyWindow(lpColumnLB->hwndList);
  974. }
  975. // ------------------------------------------------------------------
  976. // ColumnLBClass_OnNCDestroy()
  977. //
  978. // Handles WM_NCDESTROY
  979. //
  980. // HISTORY:
  981. // Tom Laird-McConnell 4/18/93 Created
  982. // ------------------------------------------------------------------
  983. void ColumnLBClass_OnNCDestroy(HWND hwnd)
  984. {
  985. LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0);
  986. FreeProcInstance(lpColumnLB->NewListboxProc);
  987. GlobalFreePtr(lpColumnLB);
  988. }
  989. // ------------------------------------------------------------------
  990. // ColumnLBClass_OnPaint()
  991. //
  992. // Handles WM_PAINT message, draws column titles as appropriate...
  993. //
  994. // HISTORY:
  995. // Tom Laird-McConnell 4/18/93 Created
  996. // ------------------------------------------------------------------
  997. void ColumnLBClass_OnPaint(HWND hwnd)
  998. {
  999. LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0);
  1000. PAINTSTRUCT ps;
  1001. HBRUSH hFrameBrush, hGreyBrush;
  1002. RECT rect;
  1003. HDC hdc;
  1004. int ncxBorder = GetSystemMetrics(SM_CXBORDER);
  1005. int ncyBorder = GetSystemMetrics(SM_CYBORDER);
  1006. BeginPaint(hwnd, (LPPAINTSTRUCT)&ps);
  1007. // Draw border around title and listbox
  1008. GetClientRect(hwnd, (LPRECT)&rect);
  1009. hdc = ps.hdc;
  1010. hFrameBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOWFRAME));
  1011. FrameRect(hdc, (LPRECT)&rect, hFrameBrush);
  1012. // make bottom the height of a HSCROLL bar
  1013. // make left side the width of a VSCROLL bar
  1014. rect.top += ncyBorder;
  1015. rect.right -= ncxBorder;
  1016. rect.left = rect.right - GetSystemMetrics(SM_CXVSCROLL);
  1017. rect.bottom = lpColumnLB->yTitle+ncyBorder;
  1018. hGreyBrush = CreateSolidBrush(GetSysColor(COLOR_SCROLLBAR));
  1019. FillRect(hdc, &rect, hGreyBrush);
  1020. rect.right = rect.left+1;
  1021. FillRect(hdc, &rect, hFrameBrush);
  1022. // destroy brushes...
  1023. DeleteBrush(hFrameBrush);
  1024. DeleteBrush(hGreyBrush);
  1025. EndPaint(hwnd, (LPPAINTSTRUCT)&ps);
  1026. }
  1027. // ------------------------------------------------------------------
  1028. // ColumnLBClass_OnSize()
  1029. //
  1030. // Handles WM_SIZE message
  1031. //
  1032. // HISTORY:
  1033. // Tom Laird-McConnell 4/18/93 Created
  1034. // ------------------------------------------------------------------
  1035. void ColumnLBClass_OnSize(HWND hwnd, UINT state, int cx, int cy)
  1036. {
  1037. WORD ncxBorder;
  1038. WORD ncyBorder;
  1039. RECT rect;
  1040. DWORD cxExtent;
  1041. LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0);
  1042. if (lpColumnLB->hwndList != (HWND)NULL)
  1043. {
  1044. ncxBorder = (WORD)GetSystemMetrics(SM_CXBORDER);
  1045. ncyBorder = (WORD)GetSystemMetrics(SM_CYBORDER);
  1046. // position title listbox at top
  1047. MoveWindow(lpColumnLB->hwndTitleList,
  1048. ncxBorder,
  1049. ncyBorder,
  1050. cx-(2*ncxBorder) - GetSystemMetrics(SM_CXVSCROLL),
  1051. lpColumnLB->yTitle,
  1052. TRUE);
  1053. // position list box below title listbox
  1054. MoveWindow(lpColumnLB->hwndList,
  1055. ncxBorder,
  1056. lpColumnLB->yTitle + ncyBorder,
  1057. cx - ncxBorder, // -(2*ncxBorder)
  1058. cy-lpColumnLB->yTitle - ncyBorder,
  1059. TRUE);
  1060. cxExtent = ColumnLBClass_ComputeOffsets(hwnd);
  1061. GetClientRect(hwnd, &rect);
  1062. //
  1063. // if the new extent is smaller then the space available, move the position
  1064. //
  1065. if ((DWORD)rect.right > cxExtent)
  1066. {
  1067. // #ifdef DEBUG
  1068. // dprintf(TEXT("Reset HSCROLL pos to far left\n"));
  1069. // #endif
  1070. // move position to far left
  1071. SendMessage(lpColumnLB->hwndList,
  1072. (lpColumnLB->fUseVlist) ? VLB_HSCROLL : WM_HSCROLL,
  1073. MAKEWPARAM(SB_TOP, 0), 0);
  1074. // do the same for the title list
  1075. SendMessage(lpColumnLB->hwndTitleList,
  1076. WM_HSCROLL, MAKEWPARAM(SB_TOP, 0), 0);
  1077. }
  1078. InvalidateRect(lpColumnLB->hwndList, NULL, TRUE);
  1079. InvalidateRect(lpColumnLB->hwndTitleList, NULL, TRUE);
  1080. }
  1081. InvalidateRect(lpColumnLB->hwndTitleList, 0, TRUE);
  1082. InvalidateRect(lpColumnLB->hwndList, 0, TRUE);
  1083. }
  1084. // ------------------------------------------------------------------
  1085. // ColumnLBClass_OnSetFont()
  1086. //
  1087. // Handles WM_SETFONT message
  1088. //
  1089. // HISTORY:
  1090. // Tom Laird-McConnell 4/18/93 Created
  1091. // ------------------------------------------------------------------
  1092. void ColumnLBClass_OnSetFont(HWND hwnd, HFONT hFont, BOOL fRedraw)
  1093. {
  1094. LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0);
  1095. HDC hdc;
  1096. TEXTMETRIC tm;
  1097. RECT rect;
  1098. lpColumnLB->hFont = hFont;
  1099. hdc = GetDC(hwnd);
  1100. SelectFont(hdc, (HFONT)hFont);
  1101. GetTextMetrics(hdc, &tm);
  1102. //
  1103. // forward on to listbox window
  1104. //
  1105. if (lpColumnLB->hwndList != (HWND)NULL)
  1106. FORWARD_WM_SETFONT(lpColumnLB->hwndList, hFont, fRedraw, SendMessage);
  1107. if (lpColumnLB->hwndTitleList != (HWND)NULL)
  1108. FORWARD_WM_SETFONT(lpColumnLB->hwndTitleList, hFont, fRedraw, SendMessage);
  1109. //
  1110. // store text height...
  1111. //
  1112. lpColumnLB->yTitle = tm.tmHeight + 2*GetSystemMetrics(SM_CYBORDER);
  1113. //
  1114. // change height appropriately
  1115. //
  1116. ListBox_SetItemHeight(lpColumnLB->hwndTitleList, 0, lpColumnLB->yTitle);
  1117. SendMessage(lpColumnLB->hwndList,
  1118. (lpColumnLB->fUseVlist) ? VLB_SETITEMHEIGHT : LB_SETITEMHEIGHT,
  1119. 0,
  1120. tm.tmHeight);
  1121. //
  1122. // since we changed the font size, forze a WM_SIZE to recalc the size of the window
  1123. //
  1124. GetClientRect(hwnd, &rect);
  1125. ColumnLBClass_OnSize(hwnd, SIZE_RESTORED, rect.right-rect.left, rect.bottom-rect.top);
  1126. ReleaseDC(hwnd, hdc);
  1127. }
  1128. // ------------------------------------------------------------------
  1129. // ColumnLBClass_OnHScroll()
  1130. //
  1131. //
  1132. // Handles OnHScroll messages to keep title bar in ssync with listbox...
  1133. //
  1134. // HISTORY:
  1135. // Tom Laird-McConnell 5/1/93 Created
  1136. // ------------------------------------------------------------------
  1137. LRESULT ColumnLBClass_OnHScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos)
  1138. {
  1139. LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0);
  1140. long lPos;
  1141. WORD nPos;
  1142. RECT rect;
  1143. int cxExtent;
  1144. switch (code)
  1145. {
  1146. case SB_THUMBPOSITION:
  1147. case SB_THUMBTRACK:
  1148. nPos = (WORD) pos;
  1149. break;
  1150. case SB_LINEUP:
  1151. case SB_LINEDOWN:
  1152. case SB_PAGEUP:
  1153. case SB_PAGEDOWN:
  1154. case SB_TOP:
  1155. case SB_BOTTOM:
  1156. case SB_ENDSCROLL:
  1157. if (lpColumnLB->fUseVlist)
  1158. nPos = (WORD)SendMessage(lpColumnLB->hwndList, VLB_GETSCROLLPOS, 0, 0);
  1159. else
  1160. nPos = (WORD) GetScrollPos((hwndCtl) ? hwndCtl : lpColumnLB->hwndList, SB_HORZ);
  1161. // nPos = GetScrollPos(lpColumnLB->hwndList, SB_HORZ);
  1162. break;
  1163. default:
  1164. return(TRUE);
  1165. }
  1166. GetClientRect(lpColumnLB->hwndList, (LPRECT)&rect);
  1167. //... if it is a VLIST, then there is an error in the client calculation when it has VSCROLL bars, so
  1168. // we need to adjust ourselves by width of VSCROLL bar...
  1169. if (lpColumnLB->fUseVlist)
  1170. rect.right -= GetSystemMetrics(SM_CXVSCROLL);
  1171. cxExtent = (DWORD)SendMessage(lpColumnLB->hwndList,
  1172. (lpColumnLB->fUseVlist) ? VLB_GETHORIZONTALEXTENT : LB_GETHORIZONTALEXTENT, 0, 0L);
  1173. if (cxExtent >= rect.right)
  1174. {
  1175. // then the listbox size is > then client's display size
  1176. // so we need to calculate how much is not on the client display
  1177. cxExtent -= rect.right;
  1178. }
  1179. else
  1180. // else set the amount left over to 0 to nullify (technical term) the
  1181. // effects of this calculation...
  1182. cxExtent = 0;
  1183. lPos = -(((LONG)nPos*(LONG)cxExtent)/100);
  1184. if (lPos > 0)
  1185. lpColumnLB->xPos = 0;
  1186. else
  1187. if (lPos < -cxExtent)
  1188. lpColumnLB->xPos = -cxExtent;
  1189. else
  1190. lpColumnLB->xPos = (int)lPos;
  1191. return(TRUE);
  1192. }
  1193. // ------------------------------------------------------------------
  1194. // ColumnLBClass_OnMeasureItem()
  1195. //
  1196. //
  1197. // Handles telling the parent how to draw each column accordingly...
  1198. //
  1199. //
  1200. // HISTORY:
  1201. // Tom Laird-McConnell 4/18/93 Created
  1202. // ------------------------------------------------------------------
  1203. void ColumnLBClass_OnMeasureItem(HWND hwnd, LPMEASUREITEMSTRUCT lpMeasureItem)
  1204. {
  1205. LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L);
  1206. TEXTMETRIC tm;
  1207. HDC hdc;
  1208. if (lpMeasureItem->CtlID == IDL_COLUMNTITLELISTBOX)
  1209. {
  1210. if (lpColumnLB)
  1211. lpMeasureItem->itemHeight = lpColumnLB->yTitle;
  1212. else
  1213. {
  1214. hdc = GetDC(hwnd);
  1215. GetTextMetrics(hdc, &tm);
  1216. ReleaseDC(hwnd, hdc);
  1217. lpMeasureItem->itemHeight = tm.tmHeight;
  1218. }
  1219. }
  1220. else
  1221. //
  1222. // it should be passed to parent
  1223. //
  1224. FORWARD_WM_MEASUREITEM(GetParent(hwnd), lpMeasureItem, SendMessage);
  1225. }
  1226. // ------------------------------------------------------------------
  1227. // ColumnLBClass_OnDeleteItem()
  1228. //
  1229. //
  1230. // Handles deleting items if necessary...
  1231. //
  1232. //
  1233. // HISTORY:
  1234. // Tom Laird-McConnell 08/18/93 Created
  1235. // ------------------------------------------------------------------
  1236. void ColumnLBClass_OnDeleteItem(HWND hwnd, const DELETEITEMSTRUCT *lpDeleteItem)
  1237. {
  1238. LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L);
  1239. LPCOLRECORD lpRecord;
  1240. // don't actually do the delete if we are sorting...
  1241. if (lpColumnLB->fSorting == TRUE)
  1242. return;
  1243. if (lpDeleteItem->CtlID == IDL_COLUMNLISTBOX)
  1244. {
  1245. // if the style is that the owner is handling the owner draw stuff
  1246. // then we need to pass to the parent ELSE free our memory...
  1247. if ((lpColumnLB) && (lpColumnLB->Style & LBS_OWNERDRAWFIXED))
  1248. //
  1249. // it should be passed to parent
  1250. //
  1251. FORWARD_WM_DELETEITEM(GetParent(hwnd), lpDeleteItem, SendMessage);
  1252. else
  1253. // this is our item data, so we need to free it
  1254. if (lpDeleteItem->itemData)
  1255. {
  1256. lpRecord = (LPCOLRECORD)lpDeleteItem->itemData;
  1257. // NOTE that the first pointer is actually the string buffer...
  1258. if (lpRecord->pString[0])
  1259. GlobalFreePtr(lpRecord->pString[0]);
  1260. GlobalFreePtr(lpRecord);
  1261. }
  1262. }
  1263. }
  1264. // ------------------------------------------------------------------
  1265. // ColumnLBClass_OnDrawItem()
  1266. //
  1267. //
  1268. // Handles telling the parent to draw each column accordingly...
  1269. //
  1270. //
  1271. // HISTORY:
  1272. // Tom Laird-McConnell 4/18/93 Created
  1273. // ------------------------------------------------------------------
  1274. void ColumnLBClass_OnDrawItem(HWND hwnd, const DRAWITEMSTRUCT * lpDrawItem)
  1275. {
  1276. LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L);
  1277. HWND hwndParent = GetParent(hwnd);
  1278. BYTE i;
  1279. BYTE PhysCol;
  1280. CLBDRAWITEMSTRUCT CLBDrawItemStruct;
  1281. RECT rect;
  1282. int ncxBorder = GetSystemMetrics(SM_CXBORDER);
  1283. int ncyBorder = GetSystemMetrics(SM_CYBORDER);
  1284. HPEN hFramePen;
  1285. HPEN hShadowPen;
  1286. HPEN hHighlightPen;
  1287. HPEN hOldPen;
  1288. HBRUSH hBackgroundBrush;
  1289. DWORD Col;
  1290. DWORD cyChar;
  1291. TEXTMETRIC tm;
  1292. BYTE PhysColumn;
  1293. RECT ClientRect;
  1294. GetClientRect(lpDrawItem->hwndItem, &ClientRect);
  1295. //
  1296. // figure out which window sent us the DrawItem
  1297. //
  1298. switch (lpDrawItem->CtlID)
  1299. {
  1300. //
  1301. // handle drawing the title listbox
  1302. //
  1303. case IDL_COLUMNTITLELISTBOX:
  1304. {
  1305. LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0);
  1306. if (lpDrawItem->itemAction == ODA_DRAWENTIRE)
  1307. {
  1308. GetTextMetrics(lpDrawItem->hDC, &tm);
  1309. cyChar = tm.tmHeight;
  1310. //
  1311. // create all of our pens for our drawing
  1312. //
  1313. hHighlightPen = CreatePen(PS_SOLID, ncyBorder, GetSysColor(COLOR_BTNHIGHLIGHT));
  1314. hShadowPen = CreatePen(PS_SOLID, ncyBorder, GetSysColor(COLOR_BTNSHADOW));
  1315. hFramePen = CreatePen(PS_SOLID, ncyBorder, GetSysColor(COLOR_WINDOWFRAME));
  1316. hBackgroundBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
  1317. //
  1318. // get the window rect we are going to work with
  1319. //
  1320. CopyRect(&rect, &lpDrawItem->rcItem);
  1321. FillRect(lpDrawItem->hDC, &rect, hBackgroundBrush);
  1322. //
  1323. // Draw frame color line below title section of property window
  1324. //
  1325. hOldPen = SelectObject(lpDrawItem->hDC, hFramePen);
  1326. MoveToEx(lpDrawItem->hDC, rect.left, rect.bottom, NULL);
  1327. LineTo(lpDrawItem->hDC, rect.right, rect.bottom);
  1328. //
  1329. // we start at the current left
  1330. //
  1331. rect.top += 2*ncyBorder;
  1332. SetTextColor(lpDrawItem->hDC, GetSysColor(COLOR_BTNTEXT));
  1333. SetBkColor(lpDrawItem->hDC, GetSysColor(COLOR_BTNFACE));
  1334. SetBkMode(lpDrawItem->hDC, TRANSPARENT);
  1335. for (Col=0; Col < lpColumnLB->nColumns; Col++)
  1336. {
  1337. //
  1338. // get the index number of the current column
  1339. //
  1340. PhysColumn = lpColumnLB->ColumnOrderTable[Col];
  1341. //
  1342. // adjust right side to be left side plus width of current column
  1343. //
  1344. rect.right = rect.left + lpColumnLB->ColumnInfoTable[PhysColumn].Width;
  1345. //
  1346. // if the button is dpressed, then draw it that way
  1347. //
  1348. if (lpColumnLB->ColumnInfoTable[PhysColumn].fDepressed)
  1349. {
  1350. //
  1351. // pick the shadow pen and draw the top-left depressed
  1352. //
  1353. SelectObject(lpDrawItem->hDC, hShadowPen);
  1354. MoveToEx(lpDrawItem->hDC, rect.left, rect.bottom, NULL);
  1355. LineTo(lpDrawItem->hDC, rect.left, rect.top-2*ncyBorder); // bottom-left --> top-left
  1356. LineTo(lpDrawItem->hDC, rect.right, rect.top-2*ncyBorder); // top-left --> top-right
  1357. //
  1358. // pick the Frame pen and draw the Column seperater
  1359. //
  1360. SelectObject(lpDrawItem->hDC, hFramePen);
  1361. MoveToEx(lpDrawItem->hDC, rect.right+ncxBorder, rect.top-2*ncyBorder, NULL);
  1362. LineTo(lpDrawItem->hDC, rect.right+ncxBorder, rect.bottom); // bottom-left --> top-left
  1363. //
  1364. // move the cursor for whitespace to draw text
  1365. //
  1366. rect.left += WHITESPACE/2;
  1367. // draw the title of the column in the current slot
  1368. DrawText(lpDrawItem->hDC,
  1369. lpColumnLB->ColumnInfoTable[PhysColumn].lpTitle,
  1370. -1,
  1371. (LPRECT)&rect,
  1372. DT_SINGLELINE | DT_LEFT | DT_TOP);
  1373. rect.left -= WHITESPACE/2; // restore the left position...
  1374. }
  1375. else
  1376. {
  1377. // it is not depressed, draw it normal
  1378. //
  1379. // pick the white pen and draw the top-left highlight
  1380. //
  1381. SelectObject(lpDrawItem->hDC, hHighlightPen);
  1382. MoveToEx(lpDrawItem->hDC, rect.left, rect.bottom-ncyBorder, NULL);
  1383. LineTo(lpDrawItem->hDC, rect.left, rect.top-2*ncyBorder); // bottom-left --> top-left
  1384. LineTo(lpDrawItem->hDC, rect.right, rect.top-2*ncyBorder); // top-left --> top-right
  1385. //
  1386. // pick the shadow pen and draw the bottom-right dark shadow
  1387. //
  1388. SelectObject(lpDrawItem->hDC, hShadowPen);
  1389. LineTo(lpDrawItem->hDC, rect.right, rect.bottom-ncyBorder); // top-right --> bottom-right
  1390. LineTo(lpDrawItem->hDC, rect.left, rect.bottom-ncyBorder); // bottom-right --> bottom-left
  1391. //
  1392. // pick the Frame pen and draw the Column seperater
  1393. //
  1394. SelectObject(lpDrawItem->hDC, hFramePen);
  1395. MoveToEx(lpDrawItem->hDC, rect.right+ncxBorder, rect.top-2*ncyBorder, NULL);
  1396. LineTo(lpDrawItem->hDC, rect.right+ncxBorder, rect.bottom); // bottom-left --> top-left
  1397. //
  1398. // move the cursor for whitespace to draw text
  1399. //
  1400. rect.left += WHITESPACE/4;
  1401. rect.top -= ncyBorder;
  1402. // draw the title of the column in the current slot
  1403. DrawText(lpDrawItem->hDC,
  1404. lpColumnLB->ColumnInfoTable[PhysColumn].lpTitle,
  1405. -1,
  1406. (LPRECT)&rect,
  1407. DT_SINGLELINE | DT_LEFT | DT_TOP);
  1408. rect.top += ncyBorder;
  1409. }
  1410. //
  1411. // adjust the left side of the rect for the width of this column
  1412. //
  1413. rect.left = rect.right+2*ncxBorder;
  1414. }
  1415. // select the original brush
  1416. SelectObject(lpDrawItem->hDC, hOldPen);
  1417. // delete my pens
  1418. DeletePen(hFramePen);
  1419. DeletePen(hHighlightPen);
  1420. DeletePen(hShadowPen);
  1421. DeleteBrush(hBackgroundBrush);
  1422. }
  1423. }
  1424. break;
  1425. //
  1426. // handle sending CLB_DRAWITEM MESSAGES to parent
  1427. //
  1428. case IDL_COLUMNLISTBOX:
  1429. {
  1430. //
  1431. // make a copy of the drawitem portion of the struct
  1432. //
  1433. memcpy(&CLBDrawItemStruct.DrawItemStruct, lpDrawItem, sizeof(DRAWITEMSTRUCT));
  1434. //
  1435. // fake parent window into thinking our id is the listbox
  1436. //
  1437. CLBDrawItemStruct.DrawItemStruct.CtlID = GetDlgCtrlID(hwnd);
  1438. CLBDrawItemStruct.lpColOrder = lpColumnLB->ColumnOrderTable;
  1439. CLBDrawItemStruct.nColumns = lpColumnLB->nColumns;
  1440. CopyRect(&rect, &lpDrawItem->rcItem);
  1441. //
  1442. // move the cursor for whitespace to draw text
  1443. //
  1444. rect.left += WHITESPACE/4;
  1445. //
  1446. // tell the parent to draw each physical column in the appropriate rectangle
  1447. //
  1448. for (i=0; i < lpColumnLB->nColumns ;i++ )
  1449. {
  1450. //
  1451. // get physical column number
  1452. //
  1453. PhysCol = lpColumnLB->ColumnOrderTable[i];
  1454. //
  1455. // massage the rect's right to be the left plus the width of the column
  1456. //
  1457. rect.right = rect.left + lpColumnLB->ColumnInfoTable[PhysCol].Width - WHITESPACE/4;
  1458. //
  1459. // copy it
  1460. //
  1461. CopyRect(&CLBDrawItemStruct.rect[i], &rect);
  1462. //
  1463. // massage the rect's left to be the right + 1
  1464. //
  1465. rect.left = rect.right + WHITESPACE/4 + 2*ncxBorder ;
  1466. }
  1467. if ((lpColumnLB->Style & LBS_OWNERDRAWFIXED) ||
  1468. (lpColumnLB->Style & VLBS_OWNERDRAWFIXED) )
  1469. //
  1470. // send a draw message with the physical column order list
  1471. // to the parent as they want to draw it
  1472. //
  1473. SendMessage(hwndParent, CLBN_DRAWITEM, (WPARAM)0, (WPARAM)&CLBDrawItemStruct);
  1474. else
  1475. {
  1476. //
  1477. // we want to draw it ourselves...
  1478. // NOTE: This assumes that we are LBS_HASSTRINGS and NOT LBS_OWNERDRAWFIXED
  1479. //
  1480. switch(lpDrawItem->itemAction)
  1481. {
  1482. case ODA_FOCUS:
  1483. DrawFocusRect(lpDrawItem->hDC,(LPRECT)&(lpDrawItem->rcItem));
  1484. break;
  1485. case ODA_DRAWENTIRE:
  1486. case ODA_SELECT:
  1487. // only if we have data...
  1488. if (lpDrawItem->itemData)
  1489. {
  1490. LPCOLRECORD lpColRecord = (LPCOLRECORD)lpDrawItem->itemData;
  1491. if ((lpColRecord == NULL) ||
  1492. (lpColRecord == (LPCOLRECORD)LB_ERR))
  1493. break; // bogus data
  1494. // Are we highlighted? (highlit?)
  1495. if (lpDrawItem->itemState & ODS_SELECTED)
  1496. {
  1497. hBackgroundBrush = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));
  1498. SetBkColor(lpDrawItem->hDC, GetSysColor(COLOR_HIGHLIGHT));
  1499. SetTextColor(lpDrawItem->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
  1500. }
  1501. else
  1502. {
  1503. hBackgroundBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
  1504. SetBkColor(lpDrawItem->hDC, GetSysColor(COLOR_WINDOW));
  1505. SetTextColor(lpDrawItem->hDC, GetSysColor(COLOR_WINDOWTEXT));
  1506. }
  1507. // FillRect(lpDrawItem->hDC,(LPRECT)&(lpDrawItem->rcItem), hBackgroundBrush);
  1508. //
  1509. // either way, draw column borders now...
  1510. //
  1511. hFramePen = CreatePen(PS_SOLID, ncyBorder, GetSysColor(COLOR_WINDOWFRAME));
  1512. hOldPen = SelectObject(lpDrawItem->hDC, hFramePen);
  1513. //
  1514. // now draw each column in the approved order...
  1515. //
  1516. for (i=0; i < CLBDrawItemStruct.nColumns ; i++)
  1517. {
  1518. //
  1519. // draw line of text...
  1520. //
  1521. ExtTextOut( lpDrawItem->hDC,
  1522. CLBDrawItemStruct.rect[i].left,
  1523. CLBDrawItemStruct.rect[i].top,
  1524. ETO_CLIPPED | ETO_OPAQUE,
  1525. &CLBDrawItemStruct.rect[i],
  1526. lpColRecord->pString[CLBDrawItemStruct.lpColOrder[i]], // pointer to string
  1527. lstrlen(lpColRecord->pString[CLBDrawItemStruct.lpColOrder[i]]), // length
  1528. (LPINT)NULL);
  1529. // draw column seperator
  1530. ColumnLB_DrawColumnBorder( lpDrawItem->hDC, &CLBDrawItemStruct.rect[i], ClientRect.bottom, hBackgroundBrush);
  1531. }
  1532. // restore old pen
  1533. SelectObject(lpDrawItem->hDC, hOldPen);
  1534. // destroy pen
  1535. DeletePen(hFramePen);
  1536. DeleteBrush(hBackgroundBrush);
  1537. }
  1538. break;
  1539. } // end of switch on drawitem action
  1540. }
  1541. }
  1542. break;
  1543. }
  1544. }
  1545. // ------------------------------------------------------------------
  1546. // ColumnLBClass_OnCharToItem()
  1547. //
  1548. // Handles converting keystrokes to items
  1549. //
  1550. // HISTORY:
  1551. // Tom Laird-McConnell 10/18/93 Created
  1552. // ------------------------------------------------------------------
  1553. int ColumnLBClass_OnCharToItem(HWND hwnd, UINT ch, HWND hwndListbox, int iCaret)
  1554. {
  1555. LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0);
  1556. LPCOLRECORD lpColRecord;
  1557. int nCount;
  1558. int nCurSel;
  1559. int nNewSel;
  1560. TCHAR cKey;
  1561. TCHAR cLBText;
  1562. if (hwndListbox != lpColumnLB->hwndTitleList)
  1563. {
  1564. RECT ClientRect;
  1565. GetClientRect(hwnd, &ClientRect);
  1566. //
  1567. // if the parent is NOT ownerdraw, then we are doing it ourselves, and
  1568. // so need to translate the WM_CHAR --> the correct item based on the
  1569. // current sort column...
  1570. //
  1571. if (! (lpColumnLB->Style & (LBS_OWNERDRAWFIXED | VLBS_OWNERDRAWFIXED)) )
  1572. {
  1573. nCurSel = ListBox_GetCurSel(lpColumnLB->hwndList);
  1574. if (IsCharAlphaNumeric((TCHAR)ch))
  1575. {
  1576. nNewSel = nCurSel + 1;
  1577. nCount = ListBox_GetCount(lpColumnLB->hwndList);
  1578. cKey = (TCHAR) toupper( (TCHAR)ch );
  1579. // loop thru items starting with the one just after
  1580. // the current selection, until we are too far along,
  1581. // then wrap around to the beginning and
  1582. // keep going until we hit our original selection.
  1583. for (; nNewSel != nCurSel ; nNewSel++ )
  1584. {
  1585. // make sure that we do't try to compare at location -1
  1586. if( nNewSel == -1)
  1587. continue;
  1588. lpColRecord = (LPCOLRECORD)ListBox_GetItemData(lpColumnLB->hwndList, nNewSel);
  1589. // if this comes back as LB_ERR then we are off the end of the list
  1590. if( lpColRecord == (LPCOLRECORD)LB_ERR )
  1591. {
  1592. nNewSel = -1; // increment will move to 0
  1593. continue;
  1594. }
  1595. cLBText = (TCHAR) toupper( *lpColRecord->pString[
  1596. lpColumnLB->ColumnOrderTable[
  1597. lpColumnLB->SortColumn ]] );
  1598. if ( cLBText == cKey )
  1599. {
  1600. // we found it ...
  1601. // change the current selection
  1602. if( lpColumnLB->Style & LBS_MULTIPLESEL )
  1603. {
  1604. // multiple selection LB, just move fuzzy rect
  1605. ListBox_SetCaretIndex(lpColumnLB->hwndList, nNewSel);
  1606. // BUGBUG change of caret does not have a notification?
  1607. }
  1608. else
  1609. {
  1610. // single sel LB, change the sel
  1611. ListBox_SetCurSel(lpColumnLB->hwndList, nNewSel);
  1612. // notify our parent if we need to
  1613. if( lpColumnLB->Style & LBS_NOTIFY )
  1614. {
  1615. SendMessage( GetParent( hwnd ),
  1616. WM_COMMAND,
  1617. MAKEWPARAM( GetDlgCtrlID( hwnd), LBN_SELCHANGE),
  1618. (LPARAM)hwnd); // NOTE: substitute ourselves
  1619. // as the source of the message
  1620. }
  1621. }
  1622. return(-1); // we handled it...
  1623. }
  1624. else if (nNewSel == nCount-1)
  1625. {
  1626. // we have gone beyond it
  1627. // or are at the end of the list...
  1628. // we need to wrap to the beginning
  1629. // (this will get incremented above prior to use)
  1630. nNewSel = -1;
  1631. continue;
  1632. }
  1633. }
  1634. // we did not find our target
  1635. return(nCurSel);
  1636. }
  1637. else
  1638. // not an alphanumeric, just return the current selection
  1639. return(nCurSel);
  1640. }
  1641. else
  1642. //
  1643. // pass on to parent as a WM_CHARTOITEM, but with the HIWORD(wParam) == SORT COLUMN
  1644. //
  1645. return((int)SendMessage( GetParent(hwnd),
  1646. CLBN_CHARTOITEM,
  1647. MAKEWPARAM(ch, lpColumnLB->SortColumn),
  1648. (LPARAM)hwnd));
  1649. } else {
  1650. return 0;
  1651. }
  1652. }
  1653. // ------------------------------------------------------------------
  1654. // ColumnLBClass_OnNumberCols()
  1655. //
  1656. // case CLB_GETNUMBERCOLS : // get the number of columns (ret=NumCols)
  1657. // case CLB_SETNUMBERCOLS : // set the number of columns (wparam=NumCols)
  1658. //
  1659. // HISTORY:
  1660. // Tom Laird-McConnell 4/18/93 Created
  1661. // ------------------------------------------------------------------
  1662. BYTE ColumnLBClass_OnNumberCols(HWND hwnd, BYTE NewNumberCols, BOOL fSetColumns)
  1663. {
  1664. LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L);
  1665. //
  1666. // if we are modifying it
  1667. //
  1668. if (fSetColumns)
  1669. {
  1670. //
  1671. // if the value is a new value
  1672. //
  1673. if (lpColumnLB->nColumns != NewNumberCols)
  1674. {
  1675. lpColumnLB->nColumns = NewNumberCols;
  1676. // force a redraw of the entire columnlb...
  1677. InvalidateRect(hwnd, NULL, TRUE);
  1678. }
  1679. }
  1680. return lpColumnLB->nColumns;
  1681. }
  1682. // ------------------------------------------------------------------
  1683. // ColumnLBClass_OnColWidth()
  1684. //
  1685. // case CLB_GETCOLWIDTH : // get a column width (wParm=Physical Column ret=ColWidth in DU's)
  1686. // case CLB_SETCOLWIDTH : // set a column width (wParm=Physical Column lParam=Width)
  1687. //
  1688. // HISTORY:
  1689. // Tom Laird-McConnell 4/18/93 Created
  1690. // ------------------------------------------------------------------
  1691. int ColumnLBClass_OnColWidth(HWND hwnd, BYTE Column, int NewWidth, BOOL fSetWidth)
  1692. {
  1693. LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L);
  1694. int cxExtent;
  1695. RECT rect;
  1696. //
  1697. // if we are modifying it
  1698. //
  1699. if (fSetWidth)
  1700. {
  1701. //
  1702. // if the value is a new value
  1703. //
  1704. if (lpColumnLB->ColumnInfoTable[Column].Width != NewWidth)
  1705. {
  1706. lpColumnLB->ColumnInfoTable[Column].Width = NewWidth;
  1707. cxExtent = ColumnLBClass_ComputeOffsets(hwnd);
  1708. GetClientRect(hwnd, &rect);
  1709. //
  1710. // send the message to the title listbox as well
  1711. //
  1712. SendMessage(lpColumnLB->hwndTitleList, LB_SETHORIZONTALEXTENT, cxExtent, 0L);
  1713. //
  1714. // pass it on to the child listbox, using VLB_SETHOR if appropriate...
  1715. //
  1716. SendMessage(lpColumnLB->hwndList,
  1717. (lpColumnLB->fUseVlist) ? VLB_SETHORIZONTALEXTENT : LB_SETHORIZONTALEXTENT, cxExtent, 0L);
  1718. //
  1719. // if the new extent is smaller then the space available, move the position
  1720. //
  1721. if (rect.right > cxExtent)
  1722. {
  1723. // #ifdef DEBUG
  1724. // dprintf(TEXT("Reset HSCROLL pos to far left\n"));
  1725. // #endif
  1726. // move position to far left
  1727. SendMessage(lpColumnLB->hwndList,
  1728. (lpColumnLB->fUseVlist) ? VLB_HSCROLL : WM_HSCROLL,
  1729. MAKEWPARAM(SB_TOP, 0), 0);
  1730. // do the same for the title list
  1731. SendMessage(lpColumnLB->hwndTitleList,
  1732. WM_HSCROLL, MAKEWPARAM(SB_TOP, 0), 0);
  1733. }
  1734. InvalidateRect(lpColumnLB->hwndList, NULL, TRUE);
  1735. InvalidateRect(lpColumnLB->hwndTitleList, NULL, TRUE);
  1736. }
  1737. }
  1738. return (DWORD)lpColumnLB->ColumnInfoTable[Column].Width;
  1739. }
  1740. // ------------------------------------------------------------------
  1741. // ColumnLBClass_OnColTitle()
  1742. //
  1743. // case CLB_GETCOLTITLE : // get a column's title (wParm=Physical Column, ret=Title)
  1744. // case CLB_SETCOLTITLE : // set a column's title (wParm=Physical Col, lParm=Title)
  1745. //
  1746. // HISTORY:
  1747. // Tom Laird-McConnell 4/18/93 Created
  1748. // ------------------------------------------------------------------
  1749. LPTSTR ColumnLBClass_OnColTitle(HWND hwnd, BYTE Column, LPTSTR lpTitle, BOOL fSetTitle)
  1750. {
  1751. LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L);
  1752. //
  1753. // if we are modifying it
  1754. //
  1755. if (fSetTitle)
  1756. {
  1757. //
  1758. // if the value is a new value
  1759. //
  1760. if (lpColumnLB->ColumnInfoTable[Column].lpTitle != lpTitle)
  1761. {
  1762. //
  1763. // BUGBUG, is there more to do here?
  1764. //
  1765. lpColumnLB->ColumnInfoTable[Column].lpTitle = lpTitle;
  1766. //
  1767. // invalidate the title
  1768. //
  1769. InvalidateRect(lpColumnLB->hwndTitleList, NULL, TRUE);
  1770. }
  1771. }
  1772. return (LPTSTR)lpColumnLB->ColumnInfoTable[Column].lpTitle;
  1773. }
  1774. // ------------------------------------------------------------------
  1775. // ColumnLBClass_OnSortCol()
  1776. //
  1777. // case CLB_GETSORTCOL : // get the sort column (ret=Physical Col)
  1778. // case CLB_SETSORTCOL : // set the sort column (wParm=Physical Col)
  1779. //
  1780. // HISTORY:
  1781. // Tom Laird-McConnell 4/18/93 Created
  1782. // ------------------------------------------------------------------
  1783. BYTE ColumnLBClass_OnSortCol(HWND hwnd, BYTE NewSortCol, BOOL fSetSortCol)
  1784. {
  1785. LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L);
  1786. DWORD nCount;
  1787. PDWORD_PTR lpListboxContents;
  1788. DWORD i;
  1789. int nCurSel;
  1790. DWORD_PTR ItemData;
  1791. HCURSOR hCursor;
  1792. //
  1793. // if we are modifying it
  1794. //
  1795. if (fSetSortCol)
  1796. {
  1797. hCursor = SetCursor(LoadCursor(0, IDC_WAIT));
  1798. // set new sort value
  1799. lpColumnLB->SortColumn = NewSortCol;
  1800. // need to resort listbox
  1801. nCount = ListBox_GetCount(lpColumnLB->hwndList);
  1802. // need to get current select
  1803. nCurSel = ListBox_GetCurSel(lpColumnLB->hwndList);
  1804. // and it's item data
  1805. ItemData = ListBox_GetItemData(lpColumnLB->hwndList, nCurSel);
  1806. SetWindowRedraw(lpColumnLB->hwndList, FALSE);
  1807. //
  1808. // allocate space for the listbox contents
  1809. //
  1810. lpListboxContents = (PDWORD_PTR) GlobalAllocPtr(GPTR, sizeof(DWORD_PTR) * nCount);
  1811. //
  1812. // retrieve all of the data values
  1813. //
  1814. for (i=0; i<nCount; i++)
  1815. lpListboxContents[i] = ListBox_GetItemData(lpColumnLB->hwndList, i);
  1816. //
  1817. // reset the listbox contents
  1818. //
  1819. lpColumnLB->fSorting = TRUE; // disable deleting while sorting...
  1820. SendMessage(lpColumnLB->hwndList, LB_RESETCONTENT, 0, 0);
  1821. lpColumnLB->fSorting = FALSE; // reenable it...
  1822. //
  1823. // now re-add all of the items, with the new sort column
  1824. //
  1825. for (i=0; i<nCount ; i++ )
  1826. {
  1827. nCurSel = ListBox_AddString(lpColumnLB->hwndList, lpListboxContents[i]);
  1828. }
  1829. // reselect selected item...
  1830. for (i=0; i < nCount ; i++)
  1831. {
  1832. if (ItemData == (DWORD)ListBox_GetItemData(lpColumnLB->hwndList, i))
  1833. // then select it
  1834. ListBox_SetCurSel(lpColumnLB->hwndList, i);
  1835. }
  1836. GlobalFreePtr(lpListboxContents);
  1837. SetWindowRedraw(lpColumnLB->hwndList, TRUE);
  1838. InvalidateRect(lpColumnLB->hwndList, NULL, TRUE);
  1839. SetCursor(hCursor);
  1840. }
  1841. return lpColumnLB->SortColumn;
  1842. }
  1843. // ------------------------------------------------------------------
  1844. // ColumnLBClass_OnColOrder()
  1845. //
  1846. // case CLB_GETCOLORDER : // get the virtual order of the physical columns (ret=LPDWORD order table)
  1847. // case CLB_SETCOLORDER : // set the virtual order of the physical columns (ret=LPDWORD order table, wParamn=LPDWORD new order)
  1848. //
  1849. // HISTORY:
  1850. // Tom Laird-McConnell 4/18/93 Created
  1851. // ------------------------------------------------------------------
  1852. LPBYTE ColumnLBClass_OnColOrder(HWND hwnd, LPBYTE NewColOrder, BOOL fSetOrder)
  1853. {
  1854. LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L);
  1855. //
  1856. // if we are modifying it
  1857. //
  1858. if (fSetOrder)
  1859. {
  1860. //
  1861. // copy the new order over the old order
  1862. //
  1863. memcpy(lpColumnLB->ColumnOrderTable, NewColOrder, lpColumnLB->nColumns);
  1864. ColumnLBClass_ComputeOffsets(hwnd);
  1865. //
  1866. // cause listbox to be redrawn
  1867. //
  1868. InvalidateRect(lpColumnLB->hwndTitleList, NULL, TRUE);
  1869. InvalidateRect(lpColumnLB->hwndList, NULL, TRUE);
  1870. }
  1871. return lpColumnLB->ColumnOrderTable;
  1872. }
  1873. // ------------------------------------------------------------------
  1874. // ColumnLBClass_OnColOffsets()
  1875. //
  1876. // case CLB_GETCOLOFFSETS : // gets the incremental col offsets (ret=LPDWORD)
  1877. // case CLB_SETCOLOFFSETS : // sets the incremental col offsets (wParam = LPDWORD)
  1878. //
  1879. // HISTORY:
  1880. // Tom Laird-McConnell 4/18/93 Created
  1881. // ------------------------------------------------------------------
  1882. LPINT ColumnLBClass_OnColOffsets(HWND hwnd, LPINT NewOffsetTable, BOOL fSetOffsets)
  1883. {
  1884. LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L);
  1885. //
  1886. // if we are modifying it
  1887. //
  1888. // if (fSetOffsets)
  1889. // {
  1890. // for (i=0; i < lpColumnLB->nColumns ; i++ )
  1891. // {
  1892. // lpColumnLB->ColumnOffsetTable[i] = NewOffsetTable[i];
  1893. // }
  1894. // }
  1895. return (lpColumnLB->ColumnOffsetTable);
  1896. }
  1897. // ------------------------------------------------------------------
  1898. // ColumnLBClass_OnAutoWidths()
  1899. //
  1900. //
  1901. // Handles CLB_AUTOWIDTHS messages to calculate the width of each field, and
  1902. // to calculate the offsets automatically... (if column is -1 , then all columns)
  1903. // ColumnToCompute is in Physical Columns
  1904. //
  1905. // returns: The horiztonal extent of all of the columns...
  1906. //
  1907. // HISTORY:
  1908. // Tom Laird-McConnell 5/1/93 Created
  1909. // ------------------------------------------------------------------
  1910. LRESULT ColumnLBClass_OnAutoWidth(HWND hwnd, BYTE ColumnToCompute)
  1911. {
  1912. HDC hdc;
  1913. BYTE nColumn;
  1914. LONG cxExtent;
  1915. SIZE Size;
  1916. TEXTMETRIC tm;
  1917. LPCOLUMNINFO lpColumnInfo, lpPrevColumnInfo;
  1918. LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0);
  1919. HFONT hOldFont;
  1920. DWORD_PTR OldStyle, NewStyle;
  1921. hdc = GetDC(hwnd);
  1922. GetTextMetrics(hdc, &tm);
  1923. hOldFont = SelectFont(hdc, lpColumnLB->hFont);
  1924. lpPrevColumnInfo = NULL;
  1925. //
  1926. // based on column order, compute the widths and offsets of each column
  1927. // NOTE: nColumn is the physical column
  1928. //
  1929. lpColumnInfo = lpColumnLB->ColumnInfoTable;
  1930. cxExtent = 0;
  1931. for (nColumn=0; nColumn < lpColumnLB->nColumns; nColumn++, lpColumnInfo++)
  1932. {
  1933. // bail out if column title is not there...
  1934. if ((lpColumnInfo->lpTitle == NULL) ||
  1935. (lpColumnInfo->lpTitle[0] == '\0'))
  1936. continue; // try next column
  1937. //
  1938. // only if it is a column we are supposed to change
  1939. //
  1940. if ((ColumnToCompute == (BYTE)-1) ||
  1941. (nColumn == ColumnToCompute))
  1942. {
  1943. GetTextExtentPoint( hdc,
  1944. (LPTSTR)lpColumnInfo->lpTitle,
  1945. lstrlen(lpColumnInfo->lpTitle),
  1946. &Size);
  1947. //
  1948. // the width is the text extent of the string plus some whitespace
  1949. //
  1950. lpColumnInfo->Width = (WHITESPACE/2) + Size.cx;
  1951. }
  1952. }
  1953. SelectFont(hdc, hOldFont);
  1954. ReleaseDC(hwnd, hdc);
  1955. //
  1956. // now adjust the offsets to show new values
  1957. //
  1958. cxExtent = ColumnLBClass_ComputeOffsets(hwnd);
  1959. if (lpColumnLB->fUseVlist)
  1960. OldStyle = SendMessage(lpColumnLB->hwndList, VLB_GETLISTBOXSTYLE, 0L, 0L);
  1961. else
  1962. OldStyle = GetWindowLongPtr(lpColumnLB->hwndList, GWL_STYLE);
  1963. //
  1964. // send the message to the title listbox as well
  1965. //
  1966. SendMessage(lpColumnLB->hwndTitleList, LB_SETHORIZONTALEXTENT, cxExtent, 0L);
  1967. SendMessage(lpColumnLB->hwndList,
  1968. (lpColumnLB->fUseVlist) ? VLB_SETHORIZONTALEXTENT : LB_SETHORIZONTALEXTENT, cxExtent, 0L);
  1969. if (lpColumnLB->fUseVlist)
  1970. NewStyle = SendMessage(lpColumnLB->hwndList, VLB_GETLISTBOXSTYLE, 0L, 0L);
  1971. else
  1972. NewStyle = GetWindowLongPtr(lpColumnLB->hwndList, GWL_STYLE);
  1973. //
  1974. // if the horizontal scroll bar is gone, then reset hscroll position
  1975. //
  1976. if ((NewStyle & WS_HSCROLL) !=
  1977. (OldStyle & WS_HSCROLL))
  1978. {
  1979. // move position to far left
  1980. SendMessage(lpColumnLB->hwndList,
  1981. (lpColumnLB->fUseVlist) ? VLB_HSCROLL : WM_HSCROLL,
  1982. MAKEWPARAM(SB_TOP, 0), 0);
  1983. }
  1984. InvalidateRect(lpColumnLB->hwndList, NULL, TRUE);
  1985. InvalidateRect(lpColumnLB->hwndTitleList, NULL, TRUE);
  1986. return(cxExtent);
  1987. }
  1988. // ------------------------------------------------------------------
  1989. // ColumnLBClass_ComputeOffsets()
  1990. //
  1991. // returns text extent...
  1992. //
  1993. // HISTORY:
  1994. // Tom Laird-McConnell 5/3/93 Created
  1995. // ------------------------------------------------------------------
  1996. int ColumnLBClass_ComputeOffsets(HWND hwnd)
  1997. {
  1998. BYTE i;
  1999. LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L);
  2000. LPINT lpOffset;
  2001. LPBYTE lpOrder;
  2002. LPCOLUMNINFO lpColumnInfo;
  2003. BYTE PhysColumn;
  2004. int ncxBorder = GetSystemMetrics(SM_CXBORDER);
  2005. //
  2006. // recalc the offsets table using the current virtual order
  2007. //
  2008. lpOffset = lpColumnLB->ColumnOffsetTable;
  2009. lpOrder = lpColumnLB->ColumnOrderTable;
  2010. lpColumnInfo = lpColumnLB->ColumnInfoTable;
  2011. //
  2012. // first offset is always 0
  2013. //
  2014. lpOffset[0] = 0;
  2015. for (i=1; i < lpColumnLB->nColumns + 1 ; i++ )
  2016. {
  2017. PhysColumn = lpOrder[i-1];
  2018. //
  2019. // this offset is the previous offset plus the previous width
  2020. //
  2021. lpOffset[i] = lpOffset[i-1] + lpColumnInfo[PhysColumn].Width + 2 * ncxBorder;
  2022. }
  2023. //
  2024. // last offset is also new text extent...
  2025. return(lpOffset[lpColumnLB->nColumns]);
  2026. }
  2027. // ------------------------------------------------------------------
  2028. // ColumnLBClass_OnLButtonDown()
  2029. //
  2030. // Handles WM_LBUTTONDOWN and WM_LBUTTONDBLCLK messages from the client
  2031. // area above the listbox
  2032. //
  2033. //
  2034. // HISTORY:
  2035. // Tom Laird-McConnell 5/3/93 Created
  2036. // ------------------------------------------------------------------
  2037. void ColumnLBClass_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
  2038. {
  2039. LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L);
  2040. BYTE i;
  2041. int AdjustedX = x - lpColumnLB->xPos;
  2042. HCURSOR hCursor;
  2043. BYTE PhysColumn;
  2044. BYTE VirtColumn;
  2045. RECT rect;
  2046. POINT point;
  2047. point.x = x;
  2048. point.y = y;
  2049. GetClientRect(lpColumnLB->hwndTitleList, &rect);
  2050. // only if this is a right mouse button from
  2051. if (PtInRect(&rect, point))
  2052. {
  2053. //
  2054. // if this is a down-click, and it is on a column border, then go into resize mode
  2055. //
  2056. for(i=1; i < lpColumnLB->nColumns+1; i++)
  2057. {
  2058. //
  2059. // check to see if this is a column offset
  2060. //
  2061. if ((AdjustedX > lpColumnLB->ColumnOffsetTable[i]-4) &&
  2062. (AdjustedX < lpColumnLB->ColumnOffsetTable[i]+4))
  2063. {
  2064. VirtColumn = i-1;
  2065. PhysColumn = lpColumnLB->ColumnOrderTable[VirtColumn];
  2066. //
  2067. // x is the right-side of the column i-1
  2068. //
  2069. lpColumnLB->fMouseState = MOUSE_COLUMNRESIZE;
  2070. lpColumnLB->xPrevPos = 0;
  2071. lpColumnLB->ColClickStart = VirtColumn; // virtual column
  2072. SetCapture(hwnd);
  2073. hCursor = LoadCursor(lpColumnLB->hInstance, TEXT("SizebarHCursor"));
  2074. SetCursor(hCursor);
  2075. return;
  2076. }
  2077. #ifdef DRAG
  2078. else
  2079. //
  2080. // if this is a down-click, and it is on a column title,
  2081. //
  2082. if ((AdjustedX > lpColumnLB->ColumnOffsetTable[i-1]) &&
  2083. (AdjustedX < lpColumnLB->ColumnOffsetTable[i]))
  2084. {
  2085. //
  2086. // whether it is a double-or single click, we need to draw down button state
  2087. //
  2088. VirtColumn = i-1;
  2089. PhysColumn = lpColumnLB->ColumnOrderTable[VirtColumn];
  2090. lpColumnLB->ColumnInfoTable[PhysColumn].fDepressed = TRUE;
  2091. GetClientRect(lpColumnLB->hwndTitleList, &rect);
  2092. rect.left = lpColumnLB->ColumnOffsetTable[VirtColumn] + lpColumnLB->xPos;
  2093. rect.right = lpColumnLB->ColumnOffsetTable[VirtColumn+1] + lpColumnLB->xPos;
  2094. //
  2095. // if this is a double-click, AND we are in sort mode then handle this as a sort request on the
  2096. // column double-clicked on
  2097. //
  2098. if (fDoubleClick)
  2099. {
  2100. if (GetWindowLong(hwnd, GWL_STYLE) & LBS_SORT)
  2101. {
  2102. //
  2103. // then default to doing a sort
  2104. //
  2105. SendMessage(hwnd, CLB_SETSORTCOL, (WPARAM)PhysColumn, (LPARAM)0);
  2106. }
  2107. else
  2108. {
  2109. //
  2110. // tell parent that the user double-clicked on PhysColumn
  2111. //
  2112. SendMessage(GetParent(hwnd), CLBN_TITLEDBLCLK, (WPARAM)GetDlgCtrlID(hwnd), (LPARAM) PhysColumn);
  2113. }
  2114. //
  2115. // we are done with double-click, so redraw window
  2116. //
  2117. lpColumnLB->ColumnInfoTable[PhysColumn].fDepressed = FALSE;
  2118. InvalidateRect(lpColumnLB->hwndTitleList, &rect, FALSE);
  2119. return;
  2120. }
  2121. else
  2122. {
  2123. // then go into single click mode/or column drag mode
  2124. //
  2125. // then x, y is in column i-1
  2126. //
  2127. lpColumnLB->fMouseState = MOUSE_COLUMNCLICK;
  2128. lpColumnLB->ColClickStart = VirtColumn;
  2129. CopyRect(&lpColumnLB->ColClickRect, &rect);
  2130. // lpColumnLB->ColClickRect.left += (lpColumnLB->ColClickRect.right - lpColumnLB->ColClickRect.left)/3;
  2131. // lpColumnLB->ColClickRect.right -= (lpColumnLB->ColClickRect.right - lpColumnLB->ColClickRect.left)/3;
  2132. SetCapture(hwnd);
  2133. InvalidateRect(lpColumnLB->hwndTitleList, &rect, FALSE);
  2134. GetWindowRect(lpColumnLB->hwndTitleList, &rect);
  2135. ClipCursor(&rect);
  2136. return;
  2137. }
  2138. }
  2139. #endif
  2140. }
  2141. }
  2142. }
  2143. // ------------------------------------------------------------------
  2144. // ColumnLBClass_OnMouseMove()
  2145. //
  2146. // Handles Mouse movement messages from the client
  2147. // area above the listbox
  2148. //
  2149. //
  2150. // HISTORY:
  2151. // Tom Laird-McConnell 5/3/93 Created
  2152. // ------------------------------------------------------------------
  2153. void ColumnLBClass_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags)
  2154. {
  2155. LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L);
  2156. RECT rect;
  2157. HDC hdc;
  2158. BYTE i;
  2159. int AdjustedX = x - lpColumnLB->xPos;
  2160. POINT Point;
  2161. HCURSOR hCursor;
  2162. switch (lpColumnLB->fMouseState)
  2163. {
  2164. case 0 : // not in mouse mode at all, so just track changing cursor when over column border
  2165. for(i=1; i < lpColumnLB->nColumns + 1; i++)
  2166. {
  2167. //
  2168. // check to see if this is a column offset
  2169. //
  2170. if ((AdjustedX > lpColumnLB->ColumnOffsetTable[i]-4) &&
  2171. (AdjustedX < lpColumnLB->ColumnOffsetTable[i]+4))
  2172. {
  2173. //
  2174. // it is, so set the cursor and return
  2175. //
  2176. hCursor = LoadCursor(lpColumnLB->hInstance, TEXT("SizebarHCursor"));
  2177. SetCursor(hCursor);
  2178. return;
  2179. }
  2180. }
  2181. SetCursor(LoadCursor(0,IDC_ARROW));
  2182. break;
  2183. case MOUSE_COLUMNRESIZE:
  2184. GetClientRect(hwnd, &rect);
  2185. //
  2186. // as long as we haven't moved past the previous column, and we haven't moved out of the rect
  2187. //
  2188. if (AdjustedX < lpColumnLB->ColumnOffsetTable[lpColumnLB->ColClickStart]+8)
  2189. {
  2190. x += (lpColumnLB->ColumnOffsetTable[lpColumnLB->ColClickStart]+8)-AdjustedX;
  2191. AdjustedX = lpColumnLB->ColumnOffsetTable[lpColumnLB->ColClickStart]+8;
  2192. }
  2193. if (x < rect.right)
  2194. {
  2195. hdc = GetDC(hwnd);
  2196. // un invert previous postion
  2197. if (lpColumnLB->xPrevPos)
  2198. {
  2199. rect.left = lpColumnLB->xPrevPos;
  2200. rect.right = rect.left+1;
  2201. InvertRect(hdc, &rect);
  2202. }
  2203. lpColumnLB->xPrevPos = x;
  2204. // invert new position
  2205. rect.left = x;
  2206. rect.right = rect.left+1;
  2207. InvertRect(hdc, &rect);
  2208. ReleaseDC(hwnd, hdc);
  2209. }
  2210. break;
  2211. case MOUSE_COLUMNDRAG:
  2212. //
  2213. // if this is a column drag, we track the messages until the mouse has moved
  2214. // back INTO the original column rectangle, if it does this, then we switchback to
  2215. // COLUMNCLICK mode, until they let go, or move back out
  2216. //
  2217. Point.x = x;
  2218. Point.y = y;
  2219. GetClientRect(lpColumnLB->hwndTitleList, &rect);
  2220. // if it is on far RIGHT generate WM_HSCROLL right message
  2221. if (x >= rect.right-2)
  2222. {
  2223. SendMessage(lpColumnLB->hwndList, (lpColumnLB->fUseVlist) ? VLB_HSCROLL : WM_HSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM)NULL);
  2224. return;
  2225. }
  2226. // if it is on far RIGHT generate WM_HSCROLL left message
  2227. if (x <= rect.left+2)
  2228. {
  2229. SendMessage(lpColumnLB->hwndList, (lpColumnLB->fUseVlist) ? VLB_HSCROLL : WM_HSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM)NULL);
  2230. return;
  2231. }
  2232. // rect.right -= lpColumnLB->xPos;
  2233. //
  2234. // //
  2235. // // it if is out of the title area, or if it is in the original column
  2236. // //
  2237. // if ((PtInRect(&lpColumnLB->ColClickRect, Point) == TRUE) || // original column
  2238. // (PtInRect(&rect, Point) == FALSE) ) // title area
  2239. // {
  2240. // //
  2241. // // then it has moved back into the original column, switch to
  2242. // //COLUMNCLICK mode
  2243. // //
  2244. // lpColumnLB->fMouseState = MOUSE_COLUMNCLICK;
  2245. //
  2246. // SetCursor(LoadCursor(0, IDC_ARROW));
  2247. // return;
  2248. // }
  2249. break;
  2250. case MOUSE_COLUMNCLICK:
  2251. //
  2252. // if this is a column click, we track the messages until the mouse has moved
  2253. // outside of the original column rectangle, if it does this, then we switch to
  2254. // COLUMNDRAG mode, until they let go, or until they move back to the original
  2255. // column.
  2256. //
  2257. Point.x = x;
  2258. Point.y = y;
  2259. GetClientRect(lpColumnLB->hwndTitleList, &rect);
  2260. rect.right -= lpColumnLB->xPos;
  2261. //
  2262. // if it is outside of the original column, and inside title area, then swtich to
  2263. // DRAG mode
  2264. //
  2265. if ((PtInRect(&lpColumnLB->ColClickRect, Point) == FALSE) && //
  2266. (PtInRect(&rect, Point) == TRUE) ) // title area
  2267. {
  2268. //
  2269. // then it has moved outside of the column, switch to
  2270. //COLUMNDRAG mode
  2271. //
  2272. lpColumnLB->fMouseState = MOUSE_COLUMNDRAG;
  2273. hCursor = LoadCursor(lpColumnLB->hInstance, TEXT("ColDragCursor"));
  2274. SetCursor(hCursor);
  2275. }
  2276. break;
  2277. }
  2278. }
  2279. // ------------------------------------------------------------------
  2280. // ColumnLBClass_OnLButtonUp()
  2281. //
  2282. // Handles WM_LBUTTONUp messages from the client
  2283. // area above the listbox
  2284. //
  2285. //
  2286. // HISTORY:
  2287. // Tom Laird-McConnell 5/3/93 Created
  2288. // ------------------------------------------------------------------
  2289. void ColumnLBClass_OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags)
  2290. {
  2291. LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L);
  2292. BYTE PhysColumn = lpColumnLB->ColumnOrderTable[lpColumnLB->ColClickStart];
  2293. BYTE PhysSourceColumn;
  2294. int AdjustedX = x - lpColumnLB->xPos;
  2295. POINT Point;
  2296. BYTE NewOrderTable[MAX_COLUMNS];
  2297. LPBYTE lpNewOrderTable = NewOrderTable;
  2298. LPBYTE lpOrderTable = lpColumnLB->ColumnOrderTable;
  2299. BYTE CurrentCol;
  2300. BYTE DestCol;
  2301. BYTE SourceCol;
  2302. TCHAR Direction;
  2303. BYTE i;
  2304. HDC hdc;
  2305. RECT rect;
  2306. SetCursor(LoadCursor(0, IDC_ARROW)); // go back to arrow
  2307. switch (lpColumnLB->fMouseState)
  2308. {
  2309. case MOUSE_COLUMNRESIZE:
  2310. //
  2311. // if we were in resize column mode, then resize the column to the left of the border
  2312. //
  2313. ReleaseCapture();
  2314. ClipCursor(NULL);
  2315. lpColumnLB->fMouseState = 0;
  2316. // clean up line
  2317. GetClientRect(hwnd, &rect);
  2318. hdc = GetDC(hwnd);
  2319. // massage the value to make sure it's in the right range...
  2320. if (AdjustedX < lpColumnLB->ColumnOffsetTable[lpColumnLB->ColClickStart]+8)
  2321. AdjustedX = lpColumnLB->ColumnOffsetTable[lpColumnLB->ColClickStart]+8;
  2322. // un invert previous postion
  2323. if (lpColumnLB->xPrevPos)
  2324. {
  2325. rect.left = lpColumnLB->xPrevPos;
  2326. rect.right = rect.left+1;
  2327. InvertRect(hdc, &rect);
  2328. }
  2329. ReleaseDC(hwnd, hdc);
  2330. //
  2331. // set the physical column width to be the current x position - the current virtual column offset
  2332. //
  2333. SendMessage(hwnd,
  2334. CLB_SETCOLWIDTH,
  2335. (WPARAM)PhysColumn,
  2336. (LPARAM)AdjustedX - lpColumnLB->ColumnOffsetTable[lpColumnLB->ColClickStart]);
  2337. break;
  2338. case MOUSE_COLUMNDRAG:
  2339. lpColumnLB->fMouseState = 0;
  2340. ReleaseCapture();
  2341. ClipCursor(NULL);
  2342. lpColumnLB->ColumnInfoTable[PhysColumn].fDepressed = FALSE;
  2343. //
  2344. // we need to figure out what column we ended up on
  2345. //
  2346. for(i=1; i < lpColumnLB->nColumns+1; i++)
  2347. {
  2348. //
  2349. // if it fits in this columns area, then this is the destination column
  2350. //
  2351. if ((AdjustedX > lpColumnLB->ColumnOffsetTable[i-1]) &&
  2352. (AdjustedX < lpColumnLB->ColumnOffsetTable[i]))
  2353. {
  2354. //
  2355. // make duplicate of the table
  2356. //
  2357. memcpy(NewOrderTable, lpOrderTable, sizeof(BYTE)*lpColumnLB->nColumns);
  2358. //
  2359. // i-1 is the destination column! (virtual)
  2360. //
  2361. SourceCol = lpColumnLB->ColClickStart; // virtual
  2362. DestCol = i-1; // virtual
  2363. PhysSourceColumn = lpColumnLB->ColumnOrderTable[SourceCol]; // physical
  2364. Direction = (SourceCol > DestCol) ? -1 : 1;
  2365. CurrentCol = SourceCol;
  2366. while (CurrentCol != DestCol)
  2367. {
  2368. NewOrderTable[CurrentCol] = NewOrderTable[CurrentCol + Direction];
  2369. CurrentCol += Direction;
  2370. }
  2371. //
  2372. // ok, it's equal to destination, so let's put the source Physical value into the destination
  2373. //
  2374. NewOrderTable[CurrentCol] = PhysSourceColumn;
  2375. //
  2376. // ok, so now set the order to the new order
  2377. //
  2378. SendMessage(hwnd, CLB_SETCOLORDER, (WPARAM)0, (LPARAM)NewOrderTable);
  2379. }
  2380. }
  2381. GetClientRect(lpColumnLB->hwndTitleList, &rect);
  2382. rect.left = lpColumnLB->ColumnOffsetTable[lpColumnLB->ColClickStart] + lpColumnLB->xPos;
  2383. rect.right = lpColumnLB->ColumnOffsetTable[lpColumnLB->ColClickStart+1] + lpColumnLB->xPos;
  2384. InvalidateRect(lpColumnLB->hwndTitleList, &rect, FALSE);
  2385. break;
  2386. case MOUSE_COLUMNCLICK:
  2387. //
  2388. // if this is a column click, we track the messages until the mouse has moved
  2389. //
  2390. lpColumnLB->fMouseState = 0;
  2391. ReleaseCapture();
  2392. ClipCursor(NULL);
  2393. lpColumnLB->ColumnInfoTable[PhysColumn].fDepressed = FALSE;
  2394. GetClientRect(lpColumnLB->hwndTitleList, &rect);
  2395. rect.left = lpColumnLB->ColumnOffsetTable[lpColumnLB->ColClickStart] + lpColumnLB->xPos;
  2396. rect.right = lpColumnLB->ColumnOffsetTable[lpColumnLB->ColClickStart+1] + lpColumnLB->xPos;
  2397. InvalidateRect(lpColumnLB->hwndTitleList, &rect, FALSE);
  2398. //
  2399. // now send a CLBN_SINGLECLICK message to the parent, only if the mousebutton was let up in the original
  2400. // column
  2401. //
  2402. Point.x = AdjustedX;
  2403. Point.y = y;
  2404. if (PtInRect(&lpColumnLB->ColClickRect, Point) == TRUE)
  2405. SendMessage(GetParent(hwnd), CLBN_TITLESINGLECLK, (WPARAM)GetDlgCtrlID(hwnd), (LPARAM)PhysColumn);
  2406. return;
  2407. }
  2408. }
  2409. // ------------------------------------------------------------------
  2410. // ColumnLBClass_OnRButtonDown()
  2411. //
  2412. // Handles WM_RBUTTON_DOWN messages
  2413. // alg:
  2414. //
  2415. // figure out where we are
  2416. // determine listbox item
  2417. // find height of rows
  2418. // translate mouse Y into a row number
  2419. // are we VLIST?
  2420. // Yes, Get TopIndex
  2421. // are we Owner Draw?
  2422. // Yes
  2423. // Send message to VLIST to get the data for row number
  2424. // No
  2425. // item number + TopIndex is the info the parent needs.
  2426. // No
  2427. // item number is the info the parent needs
  2428. // determine column
  2429. // calc which column taking into account scrolling
  2430. // send message to parent with info
  2431. // The parent will receive the column in wParam and the item in lParam. lParam
  2432. // needs to be the item because it might be the owner draw data.
  2433. //
  2434. //
  2435. //
  2436. // HISTORY:
  2437. // Steve Hiskey 10/19/93 Created
  2438. // ------------------------------------------------------------------
  2439. void ColumnLBClass_OnRButtonDown (HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
  2440. {
  2441. LPCOLUMNLBSTRUCT lpColumnLB = (LPCOLUMNLBSTRUCT)GetWindowLong(hwnd, 0L);
  2442. // get the item height here and not when the OnFont message is
  2443. // processed. ?? we get different/wrong results otherwise.
  2444. int ItemHeight = (int)ListBox_GetItemHeight(hwnd,1);
  2445. int Item = y / ItemHeight;
  2446. BYTE i;
  2447. int AdjustedX = x - lpColumnLB->xPos;
  2448. BYTE VirtColumn;
  2449. DWORD TopIndex;
  2450. CLBRBUTTONSTRUCT RButtonStruct;
  2451. BOOL GotOne = FALSE;
  2452. BOOL fTemp;
  2453. RButtonStruct.x = x;
  2454. RButtonStruct.y = y + lpColumnLB->yTitle;
  2455. RButtonStruct.hwndChild = hwnd;
  2456. //
  2457. // we already have the item (non VList), figure out which column
  2458. //
  2459. for(i=1; i < lpColumnLB->nColumns+1; i++)
  2460. {
  2461. if ((AdjustedX > lpColumnLB->ColumnOffsetTable[i-1]) &&
  2462. (AdjustedX < lpColumnLB->ColumnOffsetTable[i]))
  2463. {
  2464. //
  2465. // we have our column. Get the Physical Column. The parent of this column
  2466. // list box know what columns are interesting... and how the physical columns
  2467. // map to the virtual columns.
  2468. //
  2469. VirtColumn = i-1;
  2470. RButtonStruct.PhysColumn = lpColumnLB->ColumnOrderTable[VirtColumn];
  2471. GotOne = TRUE;
  2472. break;
  2473. }
  2474. }
  2475. if ( !GotOne)
  2476. return;
  2477. // are we VLIST?
  2478. if ( lpColumnLB->fUseVlist )
  2479. {
  2480. DWORD Style;
  2481. // are we owner draw? If so, then we don't care about TopIndex, we just want
  2482. // the instance data
  2483. Style = (DWORD)SendMessage(lpColumnLB->hwndList, VLB_GETVLISTSTYLE, 0, 0L);
  2484. if ( Style && VLBS_USEDATAVALUES )
  2485. {
  2486. // we are use data values. This means that we must ask the VList for the
  2487. // data and this is the data is the identifier of the row. ie, the data the
  2488. // VList stores is the structure needed to identify and display the line.
  2489. RButtonStruct.Index = ListBox_GetItemData(lpColumnLB->hwndList, Item );
  2490. }
  2491. else
  2492. {
  2493. // we are a normal vlist box. Get the top index and add our offset
  2494. // from top of listbox to it.
  2495. TopIndex = (DWORD)SendMessage(lpColumnLB->hwndList, LB_GETTOPINDEX, 0, 0L);
  2496. RButtonStruct.Index = TopIndex + Item;
  2497. }
  2498. }
  2499. else
  2500. {
  2501. // we are a normal list box. We need to know what item we are looking at.
  2502. // ask the listbox for the top index.
  2503. TopIndex = (DWORD)SendMessage(lpColumnLB->hwndList, LB_GETTOPINDEX, 0, 0L);
  2504. RButtonStruct.Index = TopIndex + Item;
  2505. }
  2506. // if they have hit rButton, we should set the focus to this item (lButton)... since
  2507. // WE are providing the CLB_SETCURSEL, we must tell the parent... some weird rule about
  2508. // if the user does a set cur sel, then the parent is notified, but if the parent does
  2509. // the set cur sel, the parent is not notified... since we are neither the parent or the
  2510. // user, we have to do both.
  2511. // if VLIST, we need to send just the item, top TopIndex + Item...
  2512. if ( lpColumnLB->fUseVlist )
  2513. fTemp = ListBox_SetCurSel(lpColumnLB->hwndList, Item);
  2514. else
  2515. fTemp = ListBox_SetCurSel(lpColumnLB->hwndList, RButtonStruct.Index);
  2516. if ( fTemp )
  2517. SendMessage(GetParent(hwnd), WM_COMMAND,
  2518. GetDlgCtrlID( lpColumnLB->hwndList),
  2519. MAKELPARAM(lpColumnLB->hwndList, LBN_SELCHANGE));
  2520. // we are ready to send which column and which row to the parent.
  2521. SendMessage ( GetParent (hwnd), CLBN_RBUTTONDOWN, (WORD)0, (LPARAM) &RButtonStruct );
  2522. }
  2523. // ------------------------------------------------------------------
  2524. // ColumnLBClass_DrawColumnBorder()
  2525. //
  2526. //
  2527. // HISTORY:
  2528. // Tom Laird-McConnell 3/15/94 created
  2529. // ------------------------------------------------------------------
  2530. void ColumnLB_DrawColumnBorder(HDC hDC, RECT *lpRect, int Bottom, HBRUSH hBackgroundBrush)
  2531. {
  2532. int ncxBorder = GetSystemMetrics(SM_CXBORDER);
  2533. RECT rect;
  2534. CopyRect(&rect, lpRect);
  2535. // fill in left side of rect
  2536. rect.right = rect.left;
  2537. rect.left -= (WHITESPACE/4);
  2538. FillRect(hDC, &rect, hBackgroundBrush);
  2539. // fill in right side of rect
  2540. rect.left = lpRect->right;
  2541. rect.right = lpRect->right + ncxBorder;
  2542. FillRect(hDC, &rect, hBackgroundBrush);
  2543. // draw the line itself
  2544. MoveToEx( hDC, rect.right, rect.top, NULL);
  2545. LineTo( hDC, rect.right, Bottom);
  2546. }