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

844 lines
24 KiB

  1. /**************************** Module Header ********************************\
  2. * Module Name: lboxrare.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * Infrequently Used List Box Routines
  7. *
  8. * History:
  9. * ??-???-???? ianja Ported from Win 3.0 sources
  10. * 14-Feb-1991 mikeke Added Revalidation code
  11. \***************************************************************************/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. extern LOOKASIDE ListboxLookaside;
  15. /***************************************************************************\
  16. * LBSetCItemFullMax
  17. *
  18. * History:
  19. * 03-04-92 JimA Ported from Win 3.1 sources.
  20. \***************************************************************************/
  21. void LBSetCItemFullMax(
  22. PLBIV plb)
  23. {
  24. if (plb->OwnerDraw != OWNERDRAWVAR) {
  25. plb->cItemFullMax = CItemInWindow(plb, FALSE);
  26. } else if (plb->cMac < 2) {
  27. plb->cItemFullMax = 1;
  28. } else {
  29. int height;
  30. RECT rect;
  31. int i;
  32. int j = 0;
  33. _GetClientRect(plb->spwnd, &rect);
  34. height = rect.bottom;
  35. plb->cItemFullMax = 0;
  36. for (i = plb->cMac - 1; i >= 0; i--, j++) {
  37. height -= LBGetVariableHeightItemHeight(plb, i);
  38. if (height < 0) {
  39. plb->cItemFullMax = j;
  40. break;
  41. }
  42. }
  43. if (!plb->cItemFullMax)
  44. plb->cItemFullMax = j;
  45. }
  46. }
  47. /***************************************************************************\
  48. * xxxCreateLBox
  49. *
  50. * History:
  51. * 16-Apr-1992 beng Added LBS_NODATA
  52. \***************************************************************************/
  53. LONG xxxLBCreate(
  54. PLBIV plb, PWND pwnd, LPCREATESTRUCT lpcs)
  55. {
  56. UINT style;
  57. MEASUREITEMSTRUCT measureItemStruct;
  58. TL tlpwndParent;
  59. HDC hdc;
  60. /*
  61. * Once we make it here, nobody can change the ownerdraw style bits
  62. * by calling SetWindowLong. The window style must match the flags in plb
  63. *
  64. */
  65. plb->fInitialized = TRUE;
  66. style = pwnd->style;
  67. /*
  68. * Compatibility hack.
  69. */
  70. if (pwnd->spwndParent == NULL)
  71. Lock(&(plb->spwndParent), _GetDesktopWindow());
  72. else
  73. Lock(&(plb->spwndParent), REBASEPWND(pwnd, spwndParent));
  74. /*
  75. * Break out the style bits
  76. */
  77. plb->fRedraw = ((style & LBS_NOREDRAW) == 0);
  78. plb->fDeferUpdate = FALSE;
  79. plb->fNotify = (UINT)((style & LBS_NOTIFY) != 0);
  80. plb->fVertBar = ((style & WS_VSCROLL) != 0);
  81. plb->fHorzBar = ((style & WS_HSCROLL) != 0);
  82. if (!TestWF(pwnd, WFWIN40COMPAT)) {
  83. // for 3.x apps, if either scroll bar was specified, the app got BOTH
  84. if (plb->fVertBar || plb->fHorzBar)
  85. plb->fVertBar = plb->fHorzBar = TRUE;
  86. }
  87. plb->fRtoLReading = (TestWF(pwnd, WEFRTLREADING) != 0);
  88. plb->fRightAlign = (TestWF(pwnd, WEFRIGHT) != 0);
  89. plb->fDisableNoScroll = ((style & LBS_DISABLENOSCROLL) != 0);
  90. plb->fSmoothScroll = TRUE;
  91. /*
  92. * LBS_NOSEL gets priority over any other selection style. Next highest
  93. * priority goes to LBS_EXTENDEDSEL. Then LBS_MULTIPLESEL.
  94. */
  95. if (TestWF(pwnd, WFWIN40COMPAT) && (style & LBS_NOSEL)) {
  96. plb->wMultiple = SINGLESEL;
  97. plb->fNoSel = TRUE;
  98. } else if (style & LBS_EXTENDEDSEL) {
  99. plb->wMultiple = EXTENDEDSEL;
  100. } else {
  101. plb->wMultiple = (UINT)((style & LBS_MULTIPLESEL) ? MULTIPLESEL : SINGLESEL);
  102. }
  103. plb->fNoIntegralHeight = ((style & LBS_NOINTEGRALHEIGHT) != 0);
  104. plb->fWantKeyboardInput = ((style & LBS_WANTKEYBOARDINPUT) != 0);
  105. plb->fUseTabStops = ((style & LBS_USETABSTOPS) != 0);
  106. if (plb->fUseTabStops) {
  107. /*
  108. * Set tab stops every <default> dialog units.
  109. */
  110. LBSetTabStops(plb, 0, NULL);
  111. }
  112. plb->fMultiColumn = ((style & LBS_MULTICOLUMN) != 0);
  113. plb->fHasStrings = TRUE;
  114. plb->iLastSelection = -1;
  115. plb->iMouseDown = -1; /* Anchor point for multi selection */
  116. plb->iLastMouseMove = -1;
  117. /*
  118. * Get ownerdraw style bits
  119. */
  120. if ((style & LBS_OWNERDRAWFIXED)) {
  121. plb->OwnerDraw = OWNERDRAWFIXED;
  122. } else if ((style & LBS_OWNERDRAWVARIABLE) && !plb->fMultiColumn) {
  123. plb->OwnerDraw = OWNERDRAWVAR;
  124. /*
  125. * Integral height makes no sense with var height owner draw
  126. */
  127. plb->fNoIntegralHeight = TRUE;
  128. }
  129. if (plb->OwnerDraw && !(style & LBS_HASSTRINGS)) {
  130. /*
  131. * If owner draw, do they want the listbox to maintain strings?
  132. */
  133. plb->fHasStrings = FALSE;
  134. }
  135. /*
  136. * If user specifies sort and not hasstrings, then we will send
  137. * WM_COMPAREITEM messages to the parent.
  138. */
  139. plb->fSort = ((style & LBS_SORT) != 0);
  140. /*
  141. * "No data" lazy-eval listbox mandates certain other style settings
  142. */
  143. plb->fHasData = TRUE;
  144. if (style & LBS_NODATA) {
  145. if (plb->OwnerDraw != OWNERDRAWFIXED || plb->fSort || plb->fHasStrings) {
  146. RIPERR0(ERROR_INVALID_FLAGS, RIP_WARNING,
  147. "NODATA listbox must be OWNERDRAWFIXED, w/o SORT or HASSTRINGS");
  148. } else {
  149. plb->fHasData = FALSE;
  150. }
  151. }
  152. plb->dwLocaleId = GetThreadLocale();
  153. /*
  154. * Check if this is part of a combo box
  155. */
  156. if ((style & LBS_COMBOBOX) != 0) {
  157. /*
  158. * Get the pcbox structure contained in the parent window's extra data
  159. * pointer. Check cbwndExtra to ensure compatibility with SQL windows.
  160. */
  161. if (plb->spwndParent->cbwndExtra != 0)
  162. plb->pcbox = ((PCOMBOWND)(plb->spwndParent))->pcbox;
  163. }
  164. /*
  165. * No need to set these to 0 since that was done for us when we Alloced
  166. * the PLBIV.
  167. */
  168. /*
  169. * plb->rgpch = (PBYTE)0;
  170. */
  171. /*
  172. * plb->iSelBase = plb->iTop = 0;
  173. */
  174. /*
  175. * plb->fMouseDown = FALSE;
  176. */
  177. /*
  178. * plb->fCaret = FALSE;
  179. */
  180. /*
  181. * plb->fCaretOn = FALSE;
  182. */
  183. /*
  184. * plb->maxWidth = 0;
  185. */
  186. plb->iSel = -1;
  187. plb->hdc = NULL;
  188. /*
  189. * Set the keyboard state so that when the user keyboard clicks he selects
  190. * an item.
  191. */
  192. plb->fNewItemState = TRUE;
  193. InitHStrings(plb);
  194. if (plb->fHasStrings && plb->hStrings == NULL) {
  195. return -1L;
  196. }
  197. hdc = NtUserGetDC(HWq(pwnd));
  198. plb->cxChar = GdiGetCharDimensions(hdc, NULL, &plb->cyChar);
  199. NtUserReleaseDC(HWq(pwnd), hdc);
  200. if (plb->cxChar == 0) {
  201. RIPMSG0(RIP_WARNING, "xxxLBCreate: GdiGetCharDimensions failed");
  202. plb->cxChar = gpsi->cxSysFontChar;
  203. plb->cyChar = gpsi->cySysFontChar;
  204. }
  205. if (plb->OwnerDraw == OWNERDRAWFIXED) {
  206. /*
  207. * Query for item height only if we are fixed height owner draw. Note
  208. * that we don't care about an item's width for listboxes.
  209. */
  210. measureItemStruct.CtlType = ODT_LISTBOX;
  211. measureItemStruct.CtlID = PtrToUlong(pwnd->spmenu);
  212. /*
  213. * System font height is default height
  214. */
  215. measureItemStruct.itemHeight = plb->cyChar;
  216. measureItemStruct.itemWidth = 0;
  217. measureItemStruct.itemData = 0;
  218. /*
  219. * IanJa: #ifndef WIN16 (32-bit Windows), plb->id gets extended
  220. * to LONG wParam automatically by the compiler
  221. */
  222. ThreadLock(plb->spwndParent, &tlpwndParent);
  223. SendMessage(HW(plb->spwndParent), WM_MEASUREITEM,
  224. measureItemStruct.CtlID,
  225. (LPARAM)&measureItemStruct);
  226. ThreadUnlock(&tlpwndParent);
  227. /*
  228. * Use default height if given 0. This prevents any possible future
  229. * div-by-zero errors.
  230. */
  231. if (measureItemStruct.itemHeight)
  232. plb->cyChar = measureItemStruct.itemHeight;
  233. if (plb->fMultiColumn) {
  234. /*
  235. * Get default column width from measure items struct if we are a
  236. * multicolumn listbox.
  237. */
  238. plb->cxColumn = measureItemStruct.itemWidth;
  239. }
  240. } else if (plb->OwnerDraw == OWNERDRAWVAR)
  241. plb->cyChar = 0;
  242. if (plb->fMultiColumn) {
  243. /*
  244. * Set these default values till we get the WM_SIZE message and we
  245. * calculate them properly. This is because some people create a
  246. * 0 width/height listbox and size it later. We don't want to have
  247. * problems with invalid values in these fields
  248. */
  249. if (plb->cxColumn <= 0)
  250. plb->cxColumn = 15 * plb->cxChar;
  251. plb->numberOfColumns = plb->itemsPerColumn = 1;
  252. }
  253. LBSetCItemFullMax(plb);
  254. // Don't do this for 4.0 apps. It'll make everyone's lives easier and
  255. // fix the anomaly that a combo & list created the same width end up
  256. // different when all is done.
  257. // B#1520
  258. if (!TestWF(pwnd, WFWIN40COMPAT)) {
  259. plb->fIgnoreSizeMsg = TRUE;
  260. NtUserMoveWindow(HWq(pwnd),
  261. lpcs->x - SYSMET(CXBORDER),
  262. lpcs->y - SYSMET(CYBORDER),
  263. lpcs->cx + SYSMET(CXEDGE),
  264. lpcs->cy + SYSMET(CYEDGE),
  265. FALSE);
  266. plb->fIgnoreSizeMsg = FALSE;
  267. }
  268. if (!plb->fNoIntegralHeight) {
  269. /*
  270. * Send a message to ourselves to resize the listbox to an integral
  271. * height. We need to do it this way because at create time we are all
  272. * mucked up with window rects etc...
  273. * IanJa: #ifndef WIN16 (32-bit Windows), wParam 0 gets extended
  274. * to wParam 0L automatically by the compiler.
  275. */
  276. PostMessage(HWq(pwnd), WM_SIZE, 0, 0L);
  277. }
  278. return 1L;
  279. }
  280. /***************************************************************************\
  281. * xxxLBoxDoDeleteItems
  282. *
  283. * Send DELETEITEM message for all the items in the ownerdraw listbox.
  284. *
  285. * History:
  286. * 16-Apr-1992 beng Nodata case
  287. \***************************************************************************/
  288. void xxxLBoxDoDeleteItems(
  289. PLBIV plb)
  290. {
  291. INT sItem;
  292. CheckLock(plb->spwnd);
  293. /*
  294. * Send WM_DELETEITEM message for ownerdraw listboxes which are
  295. * being deleted. (NODATA listboxes don't send such, though.)
  296. */
  297. if (plb->OwnerDraw && plb->cMac && plb->fHasData) {
  298. for (sItem = plb->cMac - 1; sItem >= 0; sItem--) {
  299. xxxLBoxDeleteItem(plb, sItem);
  300. }
  301. }
  302. }
  303. /***************************************************************************\
  304. * xxxDestroyLBox
  305. *
  306. * History:
  307. \***************************************************************************/
  308. void xxxDestroyLBox(
  309. PLBIV pLBIV,
  310. PWND pwnd)
  311. {
  312. PWND pwndParent;
  313. CheckLock(pwnd);
  314. if (pLBIV != NULL) {
  315. CheckLock(pLBIV->spwnd);
  316. /*
  317. * If ownerdraw, send deleteitem messages to parent
  318. */
  319. xxxLBoxDoDeleteItems(pLBIV);
  320. if (pLBIV->rgpch != NULL) {
  321. UserLocalFree(pLBIV->rgpch);
  322. pLBIV->rgpch = NULL;
  323. }
  324. if (pLBIV->hStrings != NULL) {
  325. UserLocalFree(pLBIV->hStrings);
  326. pLBIV->hStrings = NULL;
  327. }
  328. if (pLBIV->iTabPixelPositions != NULL) {
  329. UserLocalFree((HANDLE)pLBIV->iTabPixelPositions);
  330. pLBIV->iTabPixelPositions = NULL;
  331. }
  332. Unlock(&pLBIV->spwnd);
  333. Unlock(&pLBIV->spwndParent);
  334. if (pLBIV->pszTypeSearch) {
  335. UserLocalFree(pLBIV->pszTypeSearch);
  336. }
  337. FreeLookasideEntry(&ListboxLookaside, pLBIV);
  338. }
  339. /*
  340. * Set the window's fnid status so that we can ignore rogue messages
  341. */
  342. NtUserSetWindowFNID(HWq(pwnd), FNID_CLEANEDUP_BIT);
  343. /*
  344. * If we're part of a combo box, let it know we're gone
  345. */
  346. pwndParent = REBASEPWND(pwnd, spwndParent);
  347. if (pwndParent && GETFNID(pwndParent) == FNID_COMBOBOX) {
  348. ComboBoxWndProcWorker(pwndParent, WM_PARENTNOTIFY,
  349. MAKELONG(WM_DESTROY, PTR_TO_ID(pwnd->spmenu)), (LPARAM)HWq(pwnd), FALSE);
  350. }
  351. }
  352. /***************************************************************************\
  353. * xxxLBSetFont
  354. *
  355. * History:
  356. \***************************************************************************/
  357. void xxxLBSetFont(
  358. PLBIV plb,
  359. HANDLE hFont,
  360. BOOL fRedraw)
  361. {
  362. HDC hdc;
  363. HANDLE hOldFont = NULL;
  364. int iHeight;
  365. CheckLock(plb->spwnd);
  366. plb->hFont = hFont;
  367. hdc = NtUserGetDC(HWq(plb->spwnd));
  368. if (hFont) {
  369. hOldFont = SelectObject(hdc, hFont);
  370. if (!hOldFont) {
  371. plb->hFont = NULL;
  372. }
  373. }
  374. plb->cxChar = GdiGetCharDimensions(hdc, NULL, &iHeight);
  375. if (plb->cxChar == 0) {
  376. RIPMSG0(RIP_WARNING, "xxxLBSetFont: GdiGetCharDimensions failed");
  377. plb->cxChar = gpsi->cxSysFontChar;
  378. iHeight = gpsi->cySysFontChar;
  379. }
  380. if (!plb->OwnerDraw && (plb->cyChar != iHeight)) {
  381. /*
  382. * We don't want to mess up the cyChar height for owner draw listboxes
  383. * so don't do this.
  384. */
  385. plb->cyChar = iHeight;
  386. /*
  387. * Only resize the listbox for 4.0 dudes, or combo dropdowns.
  388. * Macromedia Director 4.0 GP-faults otherwise.
  389. */
  390. if (!plb->fNoIntegralHeight &&
  391. (plb->pcbox || TestWF(plb->spwnd, WFWIN40COMPAT))) {
  392. xxxLBSize(plb,
  393. plb->spwnd->rcClient.right - plb->spwnd->rcClient.left,
  394. plb->spwnd->rcClient.bottom - plb->spwnd->rcClient.top);
  395. }
  396. }
  397. if (hOldFont) {
  398. SelectObject(hdc, hOldFont);
  399. }
  400. /*
  401. * IanJa: was ReleaseDC(hwnd, hdc);
  402. */
  403. NtUserReleaseDC(HWq(plb->spwnd), hdc);
  404. if (plb->fMultiColumn) {
  405. LBCalcItemRowsAndColumns(plb);
  406. }
  407. LBSetCItemFullMax(plb);
  408. if (fRedraw)
  409. xxxCheckRedraw(plb, FALSE, 0);
  410. }
  411. /***************************************************************************\
  412. * xxxLBSize
  413. *
  414. * History:
  415. \***************************************************************************/
  416. void xxxLBSize(
  417. PLBIV plb,
  418. INT cx,
  419. INT cy)
  420. {
  421. RECT rc;
  422. int iTopOld;
  423. BOOL fSizedSave;
  424. CheckLock(plb->spwnd);
  425. if (!plb->fNoIntegralHeight) {
  426. int cBdrs = GetWindowBorders(plb->spwnd->style, plb->spwnd->ExStyle, TRUE, TRUE);
  427. CopyInflateRect(&rc, KPRECT_TO_PRECT(&plb->spwnd->rcWindow), 0, -cBdrs * SYSMET(CYBORDER));
  428. // Size the listbox to fit an integral # of items in its client
  429. if ((rc.bottom - rc.top) % plb->cyChar) {
  430. int iItems = (rc.bottom - rc.top);
  431. // B#2285 - If its a 3.1 app its SetWindowPos needs
  432. // to be window based dimensions not Client !
  433. // this crunches Money into using a scroll bar
  434. if ( ! TestWF( plb->spwnd, WFWIN40COMPAT ) )
  435. iItems += (cBdrs * SYSMET(CYEDGE)); // so add it back in
  436. iItems /= plb->cyChar;
  437. NtUserSetWindowPos(HWq(plb->spwnd), HWND_TOP, 0, 0, rc.right - rc.left,
  438. iItems * plb->cyChar + (SYSMET(CYEDGE) * cBdrs),
  439. SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
  440. /*
  441. * Changing the size causes us to recurse. Upon return
  442. * the state is where it should be and nothing further
  443. * needs to be done.
  444. */
  445. return;
  446. }
  447. }
  448. if (plb->fMultiColumn) {
  449. /*
  450. * Compute the number of DISPLAYABLE rows and columns in the listbox
  451. */
  452. LBCalcItemRowsAndColumns(plb);
  453. } else {
  454. /*
  455. * Adjust the current horizontal position to eliminate as much
  456. * empty space as possible from the right side of the items.
  457. */
  458. _GetClientRect(plb->spwnd, &rc);
  459. if ((plb->maxWidth - plb->xOrigin) < (rc.right - rc.left))
  460. plb->xOrigin = max(0, plb->maxWidth - (rc.right - rc.left));
  461. }
  462. LBSetCItemFullMax(plb);
  463. /*
  464. * Adjust the top item in the listbox to eliminate as much empty space
  465. * after the last item as possible
  466. * (fix for bugs #8490 & #3836)
  467. */
  468. iTopOld = plb->iTop;
  469. fSizedSave = plb->fSized;
  470. plb->fSized = FALSE;
  471. xxxNewITop(plb, plb->iTop);
  472. /*
  473. * If changing the top item index caused a resize, there is no
  474. * more work to be done here.
  475. */
  476. if (plb->fSized)
  477. return;
  478. plb->fSized = fSizedSave;
  479. if (IsLBoxVisible(plb)) {
  480. /*
  481. * This code no longer blows because it's fixed right!!! We could
  482. * optimize the fMultiColumn case with some more code to figure out
  483. * if we really need to invalidate the whole thing but note that some
  484. * 3.0 apps depend on this extra invalidation (AMIPRO 2.0, bug 14620)
  485. *
  486. * For 3.1 apps, we blow off the invalidaterect in the case where
  487. * cx and cy are 0 because this happens during the processing of
  488. * the posted WM_SIZE message when we are created which would otherwise
  489. * cause us to flash.
  490. */
  491. if ((plb->fMultiColumn && !(cx == 0 && cy == 0)) ||
  492. plb->iTop != iTopOld)
  493. NtUserInvalidateRect(HWq(plb->spwnd), NULL, TRUE);
  494. else if (plb->iSelBase >= 0) {
  495. /*
  496. * Invalidate the item with the caret so that if the listbox
  497. * grows horizontally, we redraw it properly.
  498. */
  499. LBGetItemRect(plb, plb->iSelBase, &rc);
  500. NtUserInvalidateRect(HWq(plb->spwnd), &rc, FALSE);
  501. }
  502. } else if (!plb->fRedraw)
  503. plb->fDeferUpdate = TRUE;
  504. /*
  505. * Send "fake" scroll bar messages to update the scroll positions since we
  506. * changed size.
  507. */
  508. if (TestWF(plb->spwnd, WFVSCROLL)) {
  509. xxxLBoxCtlScroll(plb, SB_ENDSCROLL, 0);
  510. }
  511. /*
  512. * We count on this to call LBShowHideScrollBars except when plb->cMac == 0!
  513. */
  514. xxxLBoxCtlHScroll(plb, SB_ENDSCROLL, 0);
  515. /*
  516. * Show/hide scroll bars depending on how much stuff is visible...
  517. *
  518. * Note: Now we only call this guy when cMac == 0, because it is
  519. * called inside the LBoxCtlHScroll with SB_ENDSCROLL otherwise.
  520. */
  521. if (plb->cMac == 0)
  522. xxxLBShowHideScrollBars(plb);
  523. }
  524. /***************************************************************************\
  525. * LBSetTabStops
  526. *
  527. * Sets the tab stops for this listbox. Returns TRUE if successful else FALSE.
  528. *
  529. * History:
  530. \***************************************************************************/
  531. BOOL LBSetTabStops(
  532. PLBIV plb,
  533. INT count,
  534. LPINT lptabstops)
  535. {
  536. PINT ptabs;
  537. if (!plb->fUseTabStops) {
  538. RIPERR0(ERROR_LB_WITHOUT_TABSTOPS, RIP_VERBOSE, "");
  539. return FALSE;
  540. }
  541. if (count) {
  542. /*
  543. * Allocate memory for the tab stops. The first byte in the
  544. * plb->iTabPixelPositions array will contain a count of the number
  545. * of tab stop positions we have.
  546. */
  547. ptabs = (LPINT)UserLocalAlloc(HEAP_ZERO_MEMORY, (count + 1) * sizeof(int));
  548. if (ptabs == NULL)
  549. return FALSE;
  550. if (plb->iTabPixelPositions != NULL)
  551. UserLocalFree(plb->iTabPixelPositions);
  552. plb->iTabPixelPositions = ptabs;
  553. /*
  554. * Set the count of tab stops
  555. */
  556. *ptabs++ = count;
  557. for (; count > 0; count--) {
  558. /*
  559. * Convert the dialog unit tabstops into pixel position tab stops.
  560. */
  561. *ptabs++ = MultDiv(*lptabstops, plb->cxChar, 4);
  562. lptabstops++;
  563. }
  564. } else {
  565. /*
  566. * Set default 8 system font ave char width tabs. So free the memory
  567. * associated with the tab stop list.
  568. */
  569. if (plb->iTabPixelPositions != NULL) {
  570. UserLocalFree((HANDLE)plb->iTabPixelPositions);
  571. plb->iTabPixelPositions = NULL;
  572. }
  573. }
  574. return TRUE;
  575. }
  576. /***************************************************************************\
  577. * InitHStrings
  578. *
  579. * History:
  580. \***************************************************************************/
  581. void InitHStrings(
  582. PLBIV plb)
  583. {
  584. if (plb->fHasStrings) {
  585. plb->ichAlloc = 0;
  586. plb->cchStrings = 0;
  587. plb->hStrings = UserLocalAlloc(0, 0L);
  588. }
  589. }
  590. /***************************************************************************\
  591. * LBDropObjectHandler
  592. *
  593. * Handles a WM_DROPITEM message on this listbox
  594. *
  595. * History:
  596. \***************************************************************************/
  597. void LBDropObjectHandler(
  598. PLBIV plb,
  599. PDROPSTRUCT pds)
  600. {
  601. LONG mouseSel;
  602. if (ISelFromPt(plb, pds->ptDrop, &mouseSel)) {
  603. /*
  604. * User dropped in empty space at bottom of listbox
  605. */
  606. pds->dwControlData = (DWORD)-1L;
  607. } else {
  608. pds->dwControlData = mouseSel;
  609. }
  610. }
  611. /***************************************************************************\
  612. * LBGetSetItemHeightHandler()
  613. *
  614. * Sets/Gets the height associated with each item. For non ownerdraw
  615. * and fixed height ownerdraw, the item number is ignored.
  616. *
  617. * History:
  618. \***************************************************************************/
  619. int LBGetSetItemHeightHandler(
  620. PLBIV plb,
  621. UINT message,
  622. int item,
  623. UINT height)
  624. {
  625. if (message == LB_GETITEMHEIGHT) {
  626. /*
  627. * All items are same height for non ownerdraw and for fixed height
  628. * ownerdraw.
  629. */
  630. if (plb->OwnerDraw != OWNERDRAWVAR)
  631. return plb->cyChar;
  632. if (plb->cMac && item >= plb->cMac) {
  633. RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
  634. return LB_ERR;
  635. }
  636. return (int)LBGetVariableHeightItemHeight(plb, (INT)item);
  637. }
  638. if (!height || height > 255) {
  639. RIPERR1(ERROR_INVALID_PARAMETER,
  640. RIP_WARNING,
  641. "Invalid parameter \"height\" (%ld) to LBGetSetItemHeightHandler",
  642. height);
  643. return LB_ERR;
  644. }
  645. if (plb->OwnerDraw != OWNERDRAWVAR)
  646. plb->cyChar = height;
  647. else {
  648. if (item < 0 || item >= plb->cMac) {
  649. RIPERR1(ERROR_INVALID_PARAMETER,
  650. RIP_WARNING,
  651. "Invalid parameter \"item\" (%ld) to LBGetSetItemHeightHandler",
  652. item);
  653. return LB_ERR;
  654. }
  655. LBSetVariableHeightItemHeight(plb, (INT)item, (INT)height);
  656. }
  657. if (plb->fMultiColumn)
  658. LBCalcItemRowsAndColumns(plb);
  659. LBSetCItemFullMax(plb);
  660. return(0);
  661. }
  662. /*****************************************************************************\
  663. *
  664. * LBEvent()
  665. *
  666. * This is for item focus & selection events in listboxes.
  667. *
  668. \*****************************************************************************/
  669. void LBEvent(PLBIV plb, UINT uEvent, int iItem)
  670. {
  671. switch (uEvent) {
  672. case EVENT_OBJECT_SELECTIONREMOVE:
  673. if (plb->wMultiple != SINGLESEL) {
  674. break;
  675. }
  676. iItem = -1;
  677. //
  678. // FALL THRU
  679. //
  680. case EVENT_OBJECT_SELECTIONADD:
  681. if (plb->wMultiple == MULTIPLESEL) {
  682. uEvent = EVENT_OBJECT_SELECTION;
  683. }
  684. break;
  685. case EVENT_OBJECT_SELECTIONWITHIN:
  686. iItem = -1;
  687. break;
  688. }
  689. NotifyWinEvent(uEvent, HW(plb->spwnd), OBJID_CLIENT, iItem+1);
  690. }