listbox.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  1. //*****************************************************************************
  2. //
  3. // listbox.c - A listbox widget.
  4. //
  5. // Copyright (c) 2008-2010 Texas Instruments Incorporated. All rights reserved.
  6. // Software License Agreement
  7. //
  8. // Texas Instruments (TI) is supplying this software for use solely and
  9. // exclusively on TI's microcontroller products. The software is owned by
  10. // TI and/or its suppliers, and is protected under applicable copyright
  11. // laws. You may not combine this software with "viral" open-source
  12. // software in order to form a larger program.
  13. //
  14. // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
  15. // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
  16. // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  17. // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
  18. // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
  19. // DAMAGES, FOR ANY REASON WHATSOEVER.
  20. //
  21. // This is part of revision 6288 of the Stellaris Graphics Library.
  22. //
  23. //*****************************************************************************
  24. #include "debug.h"
  25. #include "grlib.h"
  26. #include "widget.h"
  27. #include "listbox.h"
  28. //*****************************************************************************
  29. //
  30. //! \addtogroup listbox_api
  31. //! @{
  32. //
  33. //*****************************************************************************
  34. //*****************************************************************************
  35. //
  36. // Make sure that the abs() macro is defined.
  37. //
  38. //*****************************************************************************
  39. #ifndef abs
  40. #define abs(a) (((a) >= 0) ? (a) : (-(a)))
  41. #endif
  42. //*****************************************************************************
  43. //
  44. // Make sure min and max are defined.
  45. //
  46. //*****************************************************************************
  47. #ifndef min
  48. #define min(a, b) (((a) < (b)) ? (a) : (b))
  49. #endif
  50. #ifndef max
  51. #define max(a, b) (((a) < (b)) ? (b) : (a))
  52. #endif
  53. //*****************************************************************************
  54. //
  55. //! Draws the contents of a listbox.
  56. //!
  57. //! \param pWidget is a pointer to the listbox widget to be drawn.
  58. //!
  59. //! This function draws the contents of a listbox on the display. This is
  60. //! called in response to a \b #WIDGET_MSG_PAINT message.
  61. //!
  62. //! \return None.
  63. //
  64. //*****************************************************************************
  65. static void
  66. ListBoxPaint(tWidget *pWidget)
  67. {
  68. tListBoxWidget *pListBox;
  69. tContext sCtx;
  70. tRectangle sWidgetRect, sLineRect;
  71. short sHeight;
  72. int lWidth;
  73. unsigned short usCount, usString;
  74. //
  75. // Check the arguments.
  76. //
  77. ASSERT(pWidget);
  78. //
  79. // Convert the generic widget pointer into a listbox widget pointer.
  80. //
  81. pListBox = (tListBoxWidget *)pWidget;
  82. //
  83. // Initialize a drawing context.
  84. //
  85. GrContextInit(&sCtx, pWidget->pDisplay);
  86. GrContextFontSet(&sCtx, pListBox->pFont);
  87. //
  88. // Initialize the clipping region based on the extents of this listbox.
  89. //
  90. sWidgetRect = pWidget->sPosition;
  91. GrContextClipRegionSet(&sCtx, &sWidgetRect);
  92. //
  93. // See if the listbox outline style is selected.
  94. //
  95. if(pListBox->ulStyle & LISTBOX_STYLE_OUTLINE)
  96. {
  97. //
  98. // Outline the listbox with the outline color.
  99. //
  100. GrContextForegroundSet(&sCtx, pListBox->ulOutlineColor);
  101. GrRectDraw(&sCtx, &(pWidget->sPosition));
  102. //
  103. // Shrink the widget region by one pixel on each side and draw another
  104. // rectangle, this time in the background color. This ensures that the
  105. // text will not interfere with the colored border.
  106. //
  107. sWidgetRect.sXMin++;
  108. sWidgetRect.sYMin++;
  109. sWidgetRect.sXMax--;
  110. sWidgetRect.sYMax--;
  111. GrContextForegroundSet(&sCtx, pListBox->ulBackgroundColor);
  112. GrRectDraw(&sCtx, &sWidgetRect);
  113. //
  114. // Reduce the size of the rectangle by another pixel to get the final
  115. // area into which we will put the text.
  116. //
  117. sWidgetRect.sXMin++;
  118. sWidgetRect.sYMin++;
  119. sWidgetRect.sXMax--;
  120. sWidgetRect.sYMax--;
  121. GrContextClipRegionSet(&sCtx, &sWidgetRect);
  122. }
  123. //
  124. // Start drawing at the top of the widget.
  125. //
  126. sLineRect = sWidgetRect;
  127. usCount = 0;
  128. usString = pListBox->usStartEntry;
  129. sHeight = GrFontHeightGet(pListBox->pFont);
  130. //
  131. // Keep drawing until we reach the bottom of the listbox or run out of
  132. // strings to draw.
  133. //
  134. while((sLineRect.sYMin < sWidgetRect.sYMax) &&
  135. (usCount < pListBox->usPopulated))
  136. {
  137. //
  138. // Calculate the rectangle that will enclose this line of text.
  139. //
  140. sLineRect.sYMax = sLineRect.sYMin + sHeight - 1;
  141. //
  142. // Set foreground and background colors appropriately.
  143. //
  144. GrContextBackgroundSet(&sCtx, ((usString == pListBox->sSelected) ?
  145. pListBox->ulSelectedBackgroundColor :
  146. pListBox->ulBackgroundColor));
  147. GrContextForegroundSet(&sCtx, ((usString == pListBox->sSelected) ?
  148. pListBox->ulSelectedTextColor :
  149. pListBox->ulTextColor));
  150. //
  151. // Draw the text.
  152. //
  153. GrStringDraw(&sCtx, pListBox->ppcText[usString], -1, sLineRect.sXMin,
  154. sLineRect.sYMin, 1);
  155. //
  156. // Determine the width of the string we just rendered.
  157. //
  158. lWidth = GrStringWidthGet(&sCtx, pListBox->ppcText[usString], -1);
  159. //
  160. // Do we need to clear the area to the right of the string?
  161. //
  162. if(lWidth < (sLineRect.sXMax - sLineRect.sXMin + 1))
  163. {
  164. //
  165. // Yes - we need to fill the right side of this string with
  166. // background color.
  167. //
  168. GrContextForegroundSet(&sCtx, ((usString == pListBox->sSelected) ?
  169. pListBox->ulSelectedBackgroundColor :
  170. pListBox->ulBackgroundColor));
  171. sLineRect.sXMin += lWidth;
  172. GrRectFill(&sCtx, &sLineRect);
  173. sLineRect.sXMin = sWidgetRect.sXMin;
  174. }
  175. //
  176. // Move on to the next string.
  177. //
  178. usCount++;
  179. usString++;
  180. if(usString == pListBox->usMaxEntries)
  181. {
  182. usString = 0;
  183. }
  184. sLineRect.sYMin += sHeight;
  185. }
  186. //
  187. // Fill the remainder of the listbox area with the background color.
  188. //
  189. if(sLineRect.sYMin < sWidgetRect.sYMax)
  190. {
  191. //
  192. // Determine the rectangle to be filled.
  193. //
  194. sLineRect.sYMax = sWidgetRect.sYMax;
  195. //
  196. // Fill the rectangle with the background color.
  197. //
  198. GrContextForegroundSet(&sCtx, pListBox->ulBackgroundColor);
  199. GrRectFill(&sCtx, &sLineRect);
  200. }
  201. }
  202. //*****************************************************************************
  203. //
  204. // Handles pointer messages for a listbox widget.
  205. //
  206. // \param pListBox is a pointer to the listbox widget.
  207. // \param ulMsg is the message.
  208. // \param lX is the X coordinate of the pointer.
  209. // \param lY is the Y coordinate of the pointer.
  210. //
  211. // This function receives pointer messages intended for this listbox widget
  212. // and processes them accordingly.
  213. //
  214. // \return Returns a value appropriate to the supplied message.
  215. //
  216. //*****************************************************************************
  217. static int
  218. ListBoxPointer(tListBoxWidget *pListBox, unsigned int ulMsg, int lX, int lY)
  219. {
  220. int lLineNum, lEntry, lVisible, lMaxUp, lMaxDown, lScroll;
  221. switch(ulMsg)
  222. {
  223. //
  224. // The touchscreen has been pressed.
  225. //
  226. case WIDGET_MSG_PTR_DOWN:
  227. {
  228. //
  229. // Is the pointer press within the bounds of this widget?
  230. //
  231. if(!GrRectContainsPoint(&(pListBox->sBase.sPosition), lX, lY))
  232. {
  233. //
  234. // This is not a message for us so return 0 to indicate that
  235. // we did not process it.
  236. //
  237. return(0);
  238. }
  239. else
  240. {
  241. //
  242. // The pointer was pressed within this control. Remember the Y
  243. // coordinate and reset or scrolling flag.
  244. //
  245. pListBox->usScrolled = 0;
  246. pListBox->lPointerY = lY;
  247. //
  248. // Return 1 to indicate to the widget manager that we processed
  249. // the message. This widget will now receive all pointer move
  250. // messages until the pointer is released.
  251. //
  252. return(1);
  253. }
  254. }
  255. //
  256. // The touchscreen has been released.
  257. //
  258. case WIDGET_MSG_PTR_UP:
  259. {
  260. //
  261. // If the pointer is still within the bounds of the control and
  262. // we have not scrolled the contents since the last time the
  263. // pointer was pressed, we assume that this is a tap rather than
  264. // a drag and select the element that falls beneath the current
  265. // pointer position. If the pointer is outside our control, if
  266. // we have scrolled already or if the control is locked, don't
  267. // change the selection.
  268. //
  269. if((pListBox->usScrolled == 0) &&
  270. !(pListBox->ulStyle & LISTBOX_STYLE_LOCKED) &&
  271. GrRectContainsPoint(&(pListBox->sBase.sPosition), lX, lY))
  272. {
  273. //
  274. // It seems we need to change the selected element. What is
  275. // the display line number that has been clicked on?
  276. //
  277. lLineNum = (lY - (int)pListBox->sBase.sPosition.sYMin) /
  278. GrFontHeightGet(pListBox->pFont);
  279. //
  280. // We now know the location of the click as a number of text
  281. // lines from the top of the list box. Now determine what
  282. // entry is shown there, remembering that the index may wrap.
  283. //
  284. lEntry = ((int)pListBox->usStartEntry + lLineNum) %
  285. pListBox->usMaxEntries;
  286. //
  287. // If this is an unpopulated entry or the current selection,
  288. // clear the selection.
  289. //
  290. if((lEntry >= (int)pListBox->usPopulated) ||
  291. (lEntry == (int)pListBox->sSelected))
  292. {
  293. //
  294. // Yes - update the selection and force a repaint.
  295. //
  296. pListBox->sSelected = (short)0xFFFF;
  297. }
  298. else
  299. {
  300. //
  301. // The pointer was tapped on a valid entry other than the
  302. // current selection so change the selection.
  303. //
  304. pListBox->sSelected = (short)lEntry;
  305. }
  306. //
  307. // Force a repaint of the widget.
  308. //
  309. WidgetPaint((tWidget *)pListBox);
  310. //
  311. // Tell the client that the selection changed.
  312. //
  313. if(pListBox->pfnOnChange)
  314. {
  315. (pListBox->pfnOnChange)((tWidget *)pListBox,
  316. pListBox->sSelected);
  317. }
  318. }
  319. //
  320. // We process all pointer up messages so return 1 to tell the
  321. // widget manager this.
  322. //
  323. return(1);
  324. }
  325. //
  326. // The pointer is moving while pressed.
  327. //
  328. case WIDGET_MSG_PTR_MOVE:
  329. {
  330. //
  331. // How far has the pointer moved vertically from the point where it
  332. // was pressed or where we last registered a scroll? lLineNum will
  333. // be negative for downward scrolling.
  334. //
  335. lLineNum = pListBox->lPointerY - lY;
  336. //
  337. // If this distance is greater than or equal to the height of a
  338. // line of text, we need to check to see if we need to scroll the
  339. // list box contents.
  340. //
  341. if(abs(lLineNum) >= GrFontHeightGet(pListBox->pFont))
  342. {
  343. //
  344. // We have to scroll if this is possible. How many lines can
  345. // be visible on the display?
  346. //
  347. lVisible = (pListBox->sBase.sPosition.sYMax -
  348. pListBox->sBase.sPosition.sYMin) /
  349. (int)GrFontHeightGet(pListBox->pFont);
  350. //
  351. // If we have fewer strings in the listbox than there are lines
  352. // on the display, scrolling is not possible so give up now.
  353. //
  354. if(lVisible > (int)pListBox->usPopulated)
  355. {
  356. return(1);
  357. }
  358. //
  359. // How many lines of scrolling does the latest pointer position
  360. // indicate? A negative value implies downward scrolling (i.e.
  361. // showing earlier strings).
  362. //
  363. lScroll = lLineNum / (int)GrFontHeightGet(pListBox->pFont);
  364. //
  365. // What is the farthest we could scroll downwards (i.e. moving
  366. // the pointer towards the bottom of the screen)? Note - this
  367. // will be negative or 0.
  368. //
  369. lMaxDown = (pListBox->usStartEntry >= pListBox->usOldestEntry) ?
  370. (pListBox->usOldestEntry - pListBox->usStartEntry ) :
  371. ((pListBox->usOldestEntry - pListBox->usStartEntry) -
  372. pListBox->usMaxEntries);
  373. //
  374. // What is the farthest we could scroll upwards? Note - this
  375. // will be a positive number.
  376. //
  377. lMaxUp = ((int)pListBox->usPopulated - lVisible) + lMaxDown;
  378. //
  379. // Determine the actual scroll distance given the maximum
  380. // distances calculated.
  381. //
  382. lScroll = min(lScroll, lMaxUp);
  383. lScroll = max(lScroll, lMaxDown);
  384. if(lScroll)
  385. {
  386. int lTemp;
  387. //
  388. // Adjust the start entry appropriately, taking care to handle
  389. // the wrap case. The use of a temporary variable here is
  390. // required to work around a compiler bug which resulted in an
  391. // invalid value of pListBox->usStartEntry following the
  392. // calculation.
  393. //
  394. lTemp = pListBox->usStartEntry;
  395. lTemp += lScroll;
  396. lTemp %= (int)pListBox->usMaxEntries;
  397. pListBox->usStartEntry = (unsigned short)lTemp;
  398. //
  399. // Remember that we scrolled.
  400. //
  401. pListBox->usScrolled = 1;
  402. //
  403. // Adjust the pointer position we record to take into account
  404. // the amount we just scrolled.
  405. //
  406. pListBox->lPointerY -= (lScroll *
  407. GrFontHeightGet(pListBox->pFont));
  408. //
  409. // Repaint the contents of the widget.
  410. //
  411. WidgetPaint((tWidget *)pListBox);
  412. }
  413. }
  414. return(1);
  415. }
  416. }
  417. //
  418. // We don't handle any other messages so return 0 if we get these.
  419. //
  420. return(0);
  421. }
  422. //*****************************************************************************
  423. //
  424. //! Handles messages for a listbox widget.
  425. //!
  426. //! \param pWidget is a pointer to the listbox widget.
  427. //! \param ulMsg is the message.
  428. //! \param ulParam1 is the first parameter to the message.
  429. //! \param ulParam2 is the second parameter to the message.
  430. //!
  431. //! This function receives messages intended for this listbox widget and
  432. //! processes them accordingly. The processing of the message varies based on
  433. //! the message in question.
  434. //!
  435. //! Unrecognized messages are handled by calling WidgetDefaultMsgProc().
  436. //!
  437. //! \return Returns a value appropriate to the supplied message.
  438. //
  439. //*****************************************************************************
  440. int
  441. ListBoxMsgProc(tWidget *pWidget, unsigned int ulMsg, unsigned int ulParam1,
  442. unsigned int ulParam2)
  443. {
  444. tListBoxWidget *pListBox;
  445. //
  446. // Check the arguments.
  447. //
  448. ASSERT(pWidget);
  449. //
  450. // Convert the generic pointer to a list box pointer.
  451. //
  452. pListBox = (tListBoxWidget *)pWidget;
  453. //
  454. // Determine which message is being sent.
  455. //
  456. switch(ulMsg)
  457. {
  458. //
  459. // A pointer message has been received.
  460. //
  461. case WIDGET_MSG_PTR_DOWN:
  462. case WIDGET_MSG_PTR_UP:
  463. case WIDGET_MSG_PTR_MOVE:
  464. return(ListBoxPointer(pListBox, ulMsg, (int)ulParam1,
  465. (int)ulParam2));
  466. //
  467. // The widget paint request has been sent.
  468. //
  469. case WIDGET_MSG_PAINT:
  470. {
  471. //
  472. // Handle the widget paint request.
  473. //
  474. ListBoxPaint(pWidget);
  475. //
  476. // Return one to indicate that the message was successfully
  477. // processed.
  478. //
  479. return(1);
  480. }
  481. //
  482. // An unknown request has been sent.
  483. //
  484. default:
  485. {
  486. //
  487. // Let the default message handler process this message.
  488. //
  489. return(WidgetDefaultMsgProc(pWidget, ulMsg, ulParam1, ulParam2));
  490. }
  491. }
  492. }
  493. //*****************************************************************************
  494. //
  495. //! Initializes a listbox widget.
  496. //!
  497. //! \param pWidget is a pointer to the listbox widget to initialize.
  498. //! \param pDisplay is a pointer to the display on which to draw the listbox.
  499. //! \param ppcText is a pointer to an array of character pointers which will
  500. //! hold the strings that the listbox displays.
  501. //! \param usMaxEntries provides the total number of entries in the \e ppcText
  502. //! array.
  503. //! \param usPopulatedEntries provides the number of entries in the \e ppcText
  504. //! array which are populated.
  505. //! \param lX is the X coordinate of the upper left corner of the listbox.
  506. //! \param lY is the Y coordinate of the upper left corner of the listbox.
  507. //! \param lWidth is the width of the listbox.
  508. //! \param lHeight is the height of the listbox.
  509. //!
  510. //! This function initializes the provided listbox widget.
  511. //!
  512. //! \return None.
  513. //
  514. //*****************************************************************************
  515. void
  516. ListBoxInit(tListBoxWidget *pWidget, const tDisplay *pDisplay,
  517. const char **ppcText, unsigned short usMaxEntries,
  518. unsigned short usPopulatedEntries, int lX, int lY, int lWidth,
  519. int lHeight)
  520. {
  521. unsigned int ulIdx;
  522. //
  523. // Check the arguments.
  524. //
  525. ASSERT(pWidget);
  526. ASSERT(pDisplay);
  527. //
  528. // Clear out the widget structure.
  529. //
  530. for(ulIdx = 0; ulIdx < sizeof(tListBoxWidget); ulIdx += 4)
  531. {
  532. ((unsigned int *)pWidget)[ulIdx / 4] = 0;
  533. }
  534. //
  535. // Set the size of the listbox widget structure.
  536. //
  537. pWidget->sBase.lSize = sizeof(tListBoxWidget);
  538. //
  539. // Mark this widget as fully disconnected.
  540. //
  541. pWidget->sBase.pParent = 0;
  542. pWidget->sBase.pNext = 0;
  543. pWidget->sBase.pChild = 0;
  544. //
  545. // Save the display pointer.
  546. //
  547. pWidget->sBase.pDisplay = pDisplay;
  548. //
  549. // Set the extents of this listbox.
  550. //
  551. pWidget->sBase.sPosition.sXMin = lX;
  552. pWidget->sBase.sPosition.sYMin = lY;
  553. pWidget->sBase.sPosition.sXMax = lX + lWidth - 1;
  554. pWidget->sBase.sPosition.sYMax = lY + lHeight - 1;
  555. //
  556. // Use the listbox message handler to process messages to this listbox.
  557. //
  558. pWidget->sBase.pfnMsgProc = ListBoxMsgProc;
  559. //
  560. // Initialize some of the widget fields that are not accessible via
  561. // macros.
  562. //
  563. pWidget->ppcText = ppcText;
  564. pWidget->usMaxEntries = usMaxEntries;
  565. pWidget->usPopulated = usPopulatedEntries;
  566. pWidget->sSelected = (short)0xFFFF;
  567. }
  568. //*****************************************************************************
  569. //
  570. //! Adds a line of text to a listbox.
  571. //!
  572. //! \param pListBox is a pointer to the listbox widget that is to receive the
  573. //! new text string.
  574. //! \param pcTxt is a pointer to the string that is to be added to the listbox.
  575. //!
  576. //! This function adds a new string to the listbox. If the listbox has
  577. //! style \b #LISTBOX_STYLE_WRAP and the current string table is full, this
  578. //! function will discard the oldest string and replace it with the one passed
  579. //! here. If this style flag is absent, the function will return -1 if no
  580. //! empty entries exist in the string table for the widget.
  581. //!
  582. //! The display is not automatically updated as a result of this function call.
  583. //! An application must call WidgetPaint() to update the display after adding
  584. //! a new string to the listbox.
  585. //!
  586. //! \note To replace the string associated with a particular, existing element
  587. //! in the listbox, use ListBoxTextSet().
  588. //!
  589. //! \return Returns the string table index into which the new string has been
  590. //! placed if successful or -1 if the string table is full and
  591. //! \b #LISTBOX_STYLE_WRAP is not set.
  592. //
  593. //*****************************************************************************
  594. int ListBoxTextAdd(tListBoxWidget *pListBox, const char *pcTxt)
  595. {
  596. unsigned int ulIndex;
  597. //
  598. // Is the list box full?
  599. //
  600. if(pListBox->usPopulated == pListBox->usMaxEntries)
  601. {
  602. //
  603. // The box is already full. If the wrap style is not set, fail
  604. // the call.
  605. //
  606. if(!(pListBox->ulStyle & LISTBOX_STYLE_WRAP))
  607. {
  608. //
  609. // The listbox is full and it is not configured to wrap so we can't
  610. // add another string to it.
  611. //
  612. return(-1);
  613. }
  614. else
  615. {
  616. //
  617. // We are wrapping so replace the oldest entry in the box.
  618. //
  619. ulIndex = pListBox->usOldestEntry;
  620. //
  621. // Check to see if we are displaying the oldest entry and, if so,
  622. // move the start entry on by one to keep the display order
  623. // correct.
  624. //
  625. if(pListBox->usOldestEntry == pListBox->usStartEntry)
  626. {
  627. pListBox->usStartEntry++;
  628. if(pListBox->usStartEntry == pListBox->usMaxEntries)
  629. {
  630. pListBox->usStartEntry = 0;
  631. }
  632. }
  633. //
  634. // The new oldest entry is the next one. Update the index and
  635. // take care to wrap if we reach the end of the string table.
  636. //
  637. pListBox->usOldestEntry++;
  638. if(pListBox->usOldestEntry == pListBox->usMaxEntries)
  639. {
  640. pListBox->usOldestEntry = 0;
  641. }
  642. }
  643. }
  644. else
  645. {
  646. //
  647. // The listbox is not full so add the new string to the first free
  648. // slot in the string table.
  649. //
  650. ulIndex = pListBox->usPopulated;
  651. pListBox->usPopulated++;
  652. }
  653. //
  654. // Save the new string in the appropriate string table entry.
  655. //
  656. pListBox->ppcText[ulIndex] = pcTxt;
  657. //
  658. // Tell the caller which string table entry was added.
  659. //
  660. return((int)ulIndex);
  661. }
  662. //*****************************************************************************
  663. //
  664. // Close the Doxygen group.
  665. //! @}
  666. //
  667. //*****************************************************************************