slider.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871
  1. //*****************************************************************************
  2. //
  3. // slider.c - A simple slider widget class.
  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 "slider.h"
  28. //*****************************************************************************
  29. //
  30. //! \addtogroup slider_api
  31. //! @{
  32. //
  33. //*****************************************************************************
  34. //*****************************************************************************
  35. //
  36. // Make sure min and max are defined.
  37. //
  38. //*****************************************************************************
  39. #ifndef min
  40. #define min(a, b) (((a) < (b)) ? (a) : (b))
  41. #endif
  42. #ifndef max
  43. #define max(a, b) (((a) < (b)) ? (b) : (a))
  44. #endif
  45. //*****************************************************************************
  46. //
  47. // Converts a slider value to a position on the display.
  48. //
  49. // \param pSlider is a pointer to the slider widget for which the conversion is
  50. // being requested.
  51. // \param lValue is the slider value that is to be converted to a position.
  52. //
  53. // Converts a value within the range represented by a slider into a position
  54. // along the slider control. The function converts taking into account the
  55. // slider position and style as well as its range.
  56. //
  57. // \return Returns the screen position (x coordinate for horizontal sliders or
  58. // y coordinate for vertical ones) that represents the value passed.
  59. //
  60. //*****************************************************************************
  61. static short
  62. SliderValueToPosition(tSliderWidget *pSlider, int lValue)
  63. {
  64. unsigned short usSize;
  65. int lRange;
  66. int lPos;
  67. //
  68. // First look for the trivial cases. To ensure correct display and remove
  69. // artifacts caused by rounding errors, we specifically catch the cases
  70. // where the value provided is at either end of the slider range. In these
  71. // cases we return values that are outside the actual widget rectangle.
  72. // This is detected while drawing so that the relevant bars fill the full
  73. // area and don't leave single pixel lines at either end even when the
  74. // slider is at full scale. These cases also catch out-of-range values
  75. // and peg them at one end of the range or the other.
  76. //
  77. // First check for values at the top of the range.
  78. //
  79. if(lValue >= pSlider->lMax)
  80. {
  81. //
  82. // Is this a vertical slider?
  83. //
  84. if(pSlider->ulStyle & SL_STYLE_VERTICAL)
  85. {
  86. //
  87. // Vertical slider case. Return the top position.
  88. //
  89. lPos = pSlider->sBase.sPosition.sYMin - 1;
  90. //
  91. // Adjust by 1 to move past the border if this widget has one.
  92. //
  93. if(pSlider->ulStyle & SL_STYLE_OUTLINE)
  94. {
  95. lPos++;
  96. }
  97. }
  98. else
  99. {
  100. //
  101. // Horizontal slider case. Return the rightmost position.
  102. //
  103. lPos = pSlider->sBase.sPosition.sXMax + 1;
  104. //
  105. // Adjust by 1 to move past the border if this widget has one.
  106. //
  107. if(pSlider->ulStyle & SL_STYLE_OUTLINE)
  108. {
  109. lPos--;
  110. }
  111. }
  112. return((short)lPos);
  113. }
  114. //
  115. // Now look at the bottom end of the range.
  116. //
  117. if(lValue <= pSlider->lMin)
  118. {
  119. //
  120. // Is this a vertical slider?
  121. //
  122. if(pSlider->ulStyle & SL_STYLE_VERTICAL)
  123. {
  124. //
  125. // Vertical slider case. Return the bottom position.
  126. //
  127. lPos = pSlider->sBase.sPosition.sYMax + 1;
  128. //
  129. // Adjust by 1 to move past the border if this widget has one.
  130. //
  131. if(pSlider->ulStyle & SL_STYLE_OUTLINE)
  132. {
  133. lPos--;
  134. }
  135. }
  136. else
  137. {
  138. //
  139. // Horizontal slider case. Return the leftmost position.
  140. //
  141. lPos = pSlider->sBase.sPosition.sXMin - 1;
  142. //
  143. // Adjust by 1 to move past the border if this widget has one.
  144. //
  145. if(pSlider->ulStyle & SL_STYLE_OUTLINE)
  146. {
  147. lPos++;
  148. }
  149. }
  150. return((short)lPos);
  151. }
  152. //
  153. // What is the length of the whole slider?
  154. //
  155. if(pSlider->ulStyle & SL_STYLE_VERTICAL)
  156. {
  157. //
  158. // Vertical slider case.
  159. //
  160. usSize = (pSlider->sBase.sPosition.sYMax -
  161. pSlider->sBase.sPosition.sYMin) + 1;
  162. }
  163. else
  164. {
  165. //
  166. // Horizontal slider case.
  167. //
  168. usSize = (pSlider->sBase.sPosition.sXMax -
  169. pSlider->sBase.sPosition.sXMin) + 1;
  170. }
  171. //
  172. // Adjust the range if the slider has an outline (which removes 2 pixels).
  173. //
  174. if(pSlider->ulStyle & SL_STYLE_OUTLINE)
  175. {
  176. usSize -= 2;
  177. }
  178. //
  179. // Determine the range of the slider (the number of individual integers
  180. // represented by the widget).
  181. //
  182. lRange = (pSlider->lMax - pSlider->lMin) + 1;
  183. //
  184. // Now we can determine the relevant position relative to the start of the
  185. // slider.
  186. //
  187. lPos = ((lValue * (int)usSize) / lRange);
  188. //
  189. // Clip the calculated position to the valid range based on the slider
  190. // size.
  191. //
  192. lPos = max(lPos, 0);
  193. lPos = min(lPos, (int)usSize - 1);
  194. //
  195. // Adjust for the position of the widget relative to the screen origin.
  196. //
  197. if(pSlider->ulStyle & SL_STYLE_VERTICAL)
  198. {
  199. //
  200. // Vertical case - adjust the Y coordinate.
  201. //
  202. lPos = pSlider->sBase.sPosition.sYMax - lPos;
  203. }
  204. else
  205. {
  206. //
  207. // Horizontal case - adjust the X coordinate.
  208. //
  209. lPos += pSlider->sBase.sPosition.sXMin;
  210. }
  211. //
  212. // If the widget has an outline, make sure to adjust for this too.
  213. //
  214. lPos += ((pSlider->ulStyle & SL_STYLE_OUTLINE) ? 1 : 0);
  215. //
  216. // Convert to the expected return type and hand the caller the final
  217. // value.
  218. //
  219. return((short)lPos);
  220. }
  221. //*****************************************************************************
  222. //
  223. // Converts a slider position to a value within its range.
  224. //
  225. // \param pSlider is a pointer to the slider widget for which the conversion is
  226. // being requested.
  227. // \param usPos is a position within the slider. This is an x coordinate for
  228. // a horizontal slider or a y coordinate for a vertical one. In both cases,
  229. // the position is relative to the display origin.
  230. //
  231. // Converts a screen position into a value within the current range of the
  232. // slider. The function converts taking into account the slider position and
  233. // style as well as its range.
  234. //
  235. // \return Returns the slider value represented by the position passed.
  236. //
  237. //*****************************************************************************
  238. static int
  239. SliderPositionToValue(tSliderWidget *pSlider, short sPos)
  240. {
  241. short sMax;
  242. short sMin;
  243. int lValue;
  244. //
  245. // Determine the bounds of the control on the display.
  246. //
  247. if(pSlider->ulStyle & SL_STYLE_VERTICAL)
  248. {
  249. sMax = pSlider->sBase.sPosition.sYMax;
  250. sMin = pSlider->sBase.sPosition.sYMin;
  251. }
  252. else
  253. {
  254. sMax = pSlider->sBase.sPosition.sXMax;
  255. sMin = pSlider->sBase.sPosition.sXMin;
  256. }
  257. //
  258. // Adjust for the outline if present.
  259. //
  260. if(pSlider->ulStyle & SL_STYLE_OUTLINE)
  261. {
  262. sMax--;
  263. sMin--;
  264. }
  265. //
  266. // If the control is too narrow, this is a bug but handle it gracefully
  267. // rather than throwing a divide by zero later.
  268. //
  269. ASSERT(sMax > sMin);
  270. if(sMax <= sMin)
  271. {
  272. return(pSlider->lMin);
  273. }
  274. //
  275. // Clip the supplied position to the extent of the widget.
  276. //
  277. sPos = min(sMax, sPos);
  278. sPos = max(sMin, sPos);
  279. //
  280. // Adjust the position to make it relative to the start of the slider.
  281. //
  282. if(pSlider->ulStyle & SL_STYLE_VERTICAL)
  283. {
  284. sPos = sMax - sPos;
  285. }
  286. else
  287. {
  288. sPos -= sMin;
  289. }
  290. //
  291. // Calculate the value represented by this position.
  292. //
  293. lValue = ((int)sPos * ((pSlider->lMax - pSlider->lMin) + 1)) /
  294. (int)((sMax - sMin) + 1);
  295. //
  296. // Adjust for the bottom of the value range.
  297. //
  298. lValue += pSlider->lMin;
  299. //
  300. // Hand the conversion result back to the caller.
  301. //
  302. return(lValue);
  303. }
  304. //*****************************************************************************
  305. //
  306. //! Draws a slider.
  307. //!
  308. //! \param pWidget is a pointer to the slider widget to be drawn.
  309. //! \param pDirty is the subrectangle of the widget which is to be redrawn.
  310. //! This is expressed in screen coordinates.
  311. //!
  312. //! This function draws a slider on the display. This is called in response to
  313. //! a \b #WIDGET_MSG_PAINT message or when the slider position changes.
  314. //!
  315. //! \return None.
  316. //
  317. //*****************************************************************************
  318. static void
  319. SliderPaint(tWidget *pWidget, tRectangle *pDirty)
  320. {
  321. tRectangle sClipRect, sValueRect, sEmptyRect, sActiveClip;
  322. tSliderWidget *pSlider;
  323. tContext sCtx;
  324. int lX, lY, bIntersect;
  325. short sPos;
  326. //
  327. // Check the arguments.
  328. //
  329. ASSERT(pWidget);
  330. //
  331. // Convert the generic widget pointer into a slider widget pointer.
  332. //
  333. pSlider = (tSliderWidget *)pWidget;
  334. //
  335. // Initialize a drawing context.
  336. //
  337. GrContextInit(&sCtx, pWidget->pDisplay);
  338. //
  339. // Initialize the clipping region based on the update rectangle passed.
  340. //
  341. bIntersect = GrRectIntersectGet(pDirty, &(pSlider->sBase.sPosition),
  342. &sClipRect);
  343. GrContextClipRegionSet(&sCtx, &sClipRect);
  344. //
  345. // Draw the control outline if necessary.
  346. //
  347. if(pSlider->ulStyle & SL_STYLE_OUTLINE)
  348. {
  349. //
  350. // Outline the slider with the outline color.
  351. //
  352. GrContextForegroundSet(&sCtx, pSlider->ulOutlineColor);
  353. GrRectDraw(&sCtx, &(pWidget->sPosition));
  354. //
  355. // Adjust the clipping rectangle to prevent the outline from being
  356. // corrupted later.
  357. //
  358. if(sClipRect.sXMin == pWidget->sPosition.sXMin)
  359. {
  360. sClipRect.sXMin++;
  361. }
  362. if(sClipRect.sYMin == pWidget->sPosition.sYMin)
  363. {
  364. sClipRect.sYMin++;
  365. }
  366. if(sClipRect.sXMax == pWidget->sPosition.sXMax)
  367. {
  368. sClipRect.sXMax--;
  369. }
  370. if(sClipRect.sYMax == pWidget->sPosition.sYMax)
  371. {
  372. sClipRect.sYMax--;
  373. }
  374. }
  375. //
  376. // Determine the position associated with the current slider value.
  377. //
  378. sPos = SliderValueToPosition(pSlider, pSlider->lValue);
  379. //
  380. // Remember this so that the dirty rectangle code in the click handler
  381. // draws the correct thing the first time it is called.
  382. //
  383. pSlider->sPos = sPos;
  384. //
  385. // Determine the rectangles for the active and empty portions of the
  386. // widget.
  387. //
  388. if(pSlider->ulStyle & SL_STYLE_VERTICAL)
  389. {
  390. //
  391. // Determine the rectangle corresponding to the bottom (value) portion
  392. // of the slider.
  393. //
  394. sValueRect.sXMin = pWidget->sPosition.sXMin;
  395. sValueRect.sXMax = pWidget->sPosition.sXMax;
  396. sValueRect.sYMin = sPos;
  397. sValueRect.sYMax = pWidget->sPosition.sYMax;
  398. //
  399. // Determine the rectangle corresponding to the top (empty) portion
  400. // of the slider.
  401. //
  402. sEmptyRect.sXMin = pWidget->sPosition.sXMin;
  403. sEmptyRect.sXMax = pWidget->sPosition.sXMax;
  404. sEmptyRect.sYMin = pWidget->sPosition.sYMin;
  405. sEmptyRect.sYMax = max(sEmptyRect.sYMin, sValueRect.sYMin - 1);
  406. }
  407. else
  408. {
  409. //
  410. // Determine the rectangle corresponding to the bottom (value) portion
  411. // of the slider.
  412. //
  413. sValueRect.sYMin = pWidget->sPosition.sYMin;
  414. sValueRect.sYMax = pWidget->sPosition.sYMax;
  415. sValueRect.sXMin = pWidget->sPosition.sXMin;
  416. sValueRect.sXMax = sPos;
  417. //
  418. // Determine the rectangle corresponding to the top (empty) portion
  419. // of the slider.
  420. //
  421. sEmptyRect.sYMin = pWidget->sPosition.sYMin;
  422. sEmptyRect.sYMax = pWidget->sPosition.sYMax;
  423. sEmptyRect.sXMax = pWidget->sPosition.sXMax;
  424. sEmptyRect.sXMin = min(sEmptyRect.sXMax, sValueRect.sXMax + 1);
  425. }
  426. //
  427. // Compute the center of the slider. This will be needed later if drawing
  428. // text or an image.
  429. //
  430. lX = (pWidget->sPosition.sXMin +
  431. ((pWidget->sPosition.sXMax - pWidget->sPosition.sXMin + 1) / 2));
  432. lY = (pWidget->sPosition.sYMin +
  433. ((pWidget->sPosition.sYMax - pWidget->sPosition.sYMin + 1) / 2));
  434. //
  435. // Get the required clipping rectangle for the active/value part of
  436. // the slider.
  437. //
  438. bIntersect = GrRectIntersectGet(&sClipRect, &sValueRect, &sActiveClip);
  439. //
  440. // Does any part of the value rectangle intersect with the region we are
  441. // supposed to be redrawing?
  442. //
  443. if(bIntersect)
  444. {
  445. //
  446. // Yes - we have something to draw.
  447. //
  448. //
  449. // Set the new clipping rectangle.
  450. //
  451. GrContextClipRegionSet(&sCtx, &sActiveClip);
  452. //
  453. // Do we need to fill the active area with a color?
  454. //
  455. if(pSlider->ulStyle & SL_STYLE_FILL)
  456. {
  457. GrContextForegroundSet(&sCtx, pSlider->ulFillColor);
  458. GrRectFill(&sCtx, &sValueRect);
  459. }
  460. //
  461. // Do we need to draw an image in the active area?
  462. //
  463. if(pSlider->ulStyle & SL_STYLE_IMG)
  464. {
  465. GrContextForegroundSet(&sCtx, pSlider->ulTextColor);
  466. GrContextBackgroundSet(&sCtx, pSlider->ulFillColor);
  467. GrImageDraw(&sCtx, pSlider->pucImage,
  468. lX - (GrImageWidthGet(pSlider->pucImage) / 2),
  469. lY - (GrImageHeightGet(pSlider->pucImage) / 2));
  470. }
  471. //
  472. // Do we need to render a text string over the top of the active area?
  473. //
  474. if(pSlider->ulStyle & SL_STYLE_TEXT)
  475. {
  476. GrContextFontSet(&sCtx, pSlider->pFont);
  477. GrContextForegroundSet(&sCtx, pSlider->ulTextColor);
  478. GrContextBackgroundSet(&sCtx, pSlider->ulFillColor);
  479. GrStringDrawCentered(&sCtx, pSlider->pcText, -1, lX, lY,
  480. pSlider->ulStyle & SL_STYLE_TEXT_OPAQUE);
  481. }
  482. }
  483. //
  484. // Now get the required clipping rectangle for the background portion of
  485. // the slider.
  486. //
  487. bIntersect = GrRectIntersectGet(&sClipRect, &sEmptyRect, &sActiveClip);
  488. //
  489. // Does any part of the background rectangle intersect with the region we
  490. // are supposed to be redrawing?
  491. //
  492. if(bIntersect)
  493. {
  494. //
  495. // Yes - we have something to draw.
  496. //
  497. //
  498. // Set the new clipping rectangle.
  499. //
  500. GrContextClipRegionSet(&sCtx, &sActiveClip);
  501. //
  502. // Do we need to fill the active area with a color?
  503. //
  504. if(pSlider->ulStyle & SL_STYLE_BACKG_FILL)
  505. {
  506. GrContextForegroundSet(&sCtx, pSlider->ulBackgroundFillColor);
  507. GrRectFill(&sCtx, &sEmptyRect);
  508. }
  509. //
  510. // Do we need to draw an image in the active area?
  511. //
  512. if(pSlider->ulStyle & SL_STYLE_BACKG_IMG)
  513. {
  514. GrContextForegroundSet(&sCtx, pSlider->ulBackgroundTextColor);
  515. GrContextBackgroundSet(&sCtx, pSlider->ulBackgroundFillColor);
  516. GrImageDraw(&sCtx, pSlider->pucBackgroundImage,
  517. lX - (GrImageWidthGet(pSlider->pucBackgroundImage) / 2),
  518. lY - (GrImageHeightGet(pSlider->pucBackgroundImage) / 2));
  519. }
  520. //
  521. // Do we need to render a text string over the top of the active area?
  522. //
  523. if(pSlider->ulStyle & SL_STYLE_BACKG_TEXT)
  524. {
  525. GrContextFontSet(&sCtx, pSlider->pFont);
  526. GrContextForegroundSet(&sCtx, pSlider->ulBackgroundTextColor);
  527. GrContextBackgroundSet(&sCtx, pSlider->ulBackgroundFillColor);
  528. GrStringDrawCentered(&sCtx, pSlider->pcText, -1, lX, lY,
  529. pSlider->ulStyle & SL_STYLE_BACKG_TEXT_OPAQUE);
  530. }
  531. }
  532. }
  533. //*****************************************************************************
  534. //
  535. //! Handles pointer events for slider.
  536. //!
  537. //! \param pWidget is a pointer to the slider widget.
  538. //! \param ulMsg is the pointer event message.
  539. //! \param lX is the X coordinate of the pointer event.
  540. //! \param lY is the Y coordinate of the pointer event.
  541. //!
  542. //! This function processes pointer event messages for a slider. This is
  543. //! called in response to a \b #WIDGET_MSG_PTR_DOWN, \b #WIDGET_MSG_PTR_MOVE,
  544. //! and \b #WIDGET_MSG_PTR_UP messages.
  545. //!
  546. //! If the message is \b #WIDGET_MSG_PTR_MOVE or is \b #WIDGET_MSG_PTR_DOWN and
  547. //! the coordinates are within the bounds of the slider, the slider value is
  548. //! updated and, if changed, the slider's OnChange callback function is called.
  549. //!
  550. //! \return Returns 1 if the message was consumed by the slider and 0
  551. //! otherwise.
  552. //
  553. //*****************************************************************************
  554. static int
  555. SliderClick(tWidget *pWidget, unsigned int ulMsg, int lX, int lY)
  556. {
  557. tSliderWidget *pSlider;
  558. tRectangle sRedrawRect;
  559. short sPos;
  560. int lNewVal;
  561. //
  562. // Check the arguments.
  563. //
  564. ASSERT(pWidget);
  565. //
  566. // Convert the generic widget pointer into a slider widget pointer.
  567. //
  568. pSlider = (tSliderWidget *)pWidget;
  569. //
  570. // If the slider is locked, ignore all pointer messages.
  571. //
  572. if(pSlider->ulStyle & SL_STYLE_LOCKED)
  573. {
  574. return(0);
  575. }
  576. //
  577. // See if the given coordinates are within the extents of the slider.
  578. //
  579. if((ulMsg == WIDGET_MSG_PTR_MOVE) ||
  580. ((ulMsg == WIDGET_MSG_PTR_DOWN) &&
  581. (lX >= pWidget->sPosition.sXMin) &&
  582. (lX <= pWidget->sPosition.sXMax) &&
  583. (lY >= pWidget->sPosition.sYMin) &&
  584. (lY <= pWidget->sPosition.sYMax)))
  585. {
  586. //
  587. // Map the pointer position to a slider value.
  588. //
  589. lNewVal = SliderPositionToValue(pSlider,
  590. (pSlider->ulStyle & SL_STYLE_VERTICAL) ? lY : lX);
  591. //
  592. // Convert back to ensure that the dirty rectangle we calculate here
  593. // uses the same values as will be used when the widget is next
  594. // painted.
  595. //
  596. sPos = SliderValueToPosition(pSlider, lNewVal);
  597. //
  598. // Did the value change?
  599. //
  600. if(lNewVal != pSlider->lValue)
  601. {
  602. //
  603. // Yes - the value changed so report it to the app and redraw the
  604. // slider.
  605. //
  606. if(pSlider->pfnOnChange)
  607. {
  608. (pSlider->pfnOnChange)(pWidget, lNewVal);
  609. }
  610. //
  611. // Determine the rectangle that we need to redraw to update the
  612. // slider to the new position.
  613. //
  614. if(pSlider->ulStyle & SL_STYLE_VERTICAL)
  615. {
  616. //
  617. // Vertical slider case.
  618. //
  619. sRedrawRect.sYMin = min(pSlider->sPos, sPos);
  620. sRedrawRect.sYMax = max(pSlider->sPos, sPos);
  621. sRedrawRect.sXMin = pWidget->sPosition.sXMin;
  622. sRedrawRect.sXMax = pWidget->sPosition.sXMax;
  623. }
  624. else
  625. {
  626. //
  627. // Horizontal slider case.
  628. //
  629. sRedrawRect.sXMin = min(pSlider->sPos, sPos);
  630. sRedrawRect.sXMax = max(pSlider->sPos, sPos);
  631. sRedrawRect.sYMin = pWidget->sPosition.sYMin;
  632. sRedrawRect.sYMax = pWidget->sPosition.sYMax;
  633. }
  634. //
  635. // Update the widget value and position.
  636. //
  637. pSlider->lValue = lNewVal;
  638. pSlider->sPos = sPos;
  639. //
  640. // Redraw the area of the control that has changed.
  641. //
  642. SliderPaint(pWidget, &sRedrawRect);
  643. }
  644. //
  645. // These coordinates are within the extents of the slider widget.
  646. //
  647. return(1);
  648. }
  649. //
  650. // These coordinates are not within the extents of the slider widget.
  651. //
  652. return(0);
  653. }
  654. //*****************************************************************************
  655. //
  656. //! Handles messages for a slider widget.
  657. //!
  658. //! \param pWidget is a pointer to the slider widget.
  659. //! \param ulMsg is the message.
  660. //! \param ulParam1 is the first parameter to the message.
  661. //! \param ulParam2 is the second parameter to the message.
  662. //!
  663. //! This function receives messages intended for this slider widget and
  664. //! processes them accordingly. The processing of the message varies based on
  665. //! the message in question.
  666. //!
  667. //! Unrecognized messages are handled by calling WidgetDefaultMsgProc().
  668. //!
  669. //! \return Returns a value appropriate to the supplied message.
  670. //
  671. //*****************************************************************************
  672. int
  673. SliderMsgProc(tWidget *pWidget, unsigned int ulMsg,
  674. unsigned int ulParam1, unsigned int ulParam2)
  675. {
  676. //
  677. // Check the arguments.
  678. //
  679. ASSERT(pWidget);
  680. //
  681. // Determine which message is being sent.
  682. //
  683. switch(ulMsg)
  684. {
  685. //
  686. // The widget paint request has been sent.
  687. //
  688. case WIDGET_MSG_PAINT:
  689. {
  690. //
  691. // Handle the widget paint request.
  692. //
  693. SliderPaint(pWidget, &(pWidget->sPosition));
  694. //
  695. // Return one to indicate that the message was successfully
  696. // processed.
  697. //
  698. return(1);
  699. }
  700. //
  701. // One of the pointer requests has been sent.
  702. //
  703. case WIDGET_MSG_PTR_DOWN:
  704. case WIDGET_MSG_PTR_MOVE:
  705. case WIDGET_MSG_PTR_UP:
  706. {
  707. //
  708. // Handle the pointer request, returning the appropriate value.
  709. //
  710. return(SliderClick(pWidget, ulMsg, ulParam1, ulParam2));
  711. }
  712. //
  713. // An unknown request has been sent.
  714. //
  715. default:
  716. {
  717. //
  718. // Let the default message handler process this message.
  719. //
  720. return(WidgetDefaultMsgProc(pWidget, ulMsg, ulParam1, ulParam2));
  721. }
  722. }
  723. }
  724. //*****************************************************************************
  725. //
  726. //! Initializes a slider widget.
  727. //!
  728. //! \param pWidget is a pointer to the slider widget to initialize.
  729. //! \param pDisplay is a pointer to the display on which to draw the slider.
  730. //! \param lX is the X coordinate of the upper left corner of the slider.
  731. //! \param lY is the Y coordinate of the upper left corner of the slider.
  732. //! \param lWidth is the width of the slider.
  733. //! \param lHeight is the height of the slider.
  734. //!
  735. //! This function initializes the provided slider widget.
  736. //!
  737. //! \return None.
  738. //
  739. //*****************************************************************************
  740. void
  741. SliderInit(tSliderWidget *pWidget, const tDisplay *pDisplay, int lX, int lY,
  742. int lWidth, int lHeight)
  743. {
  744. unsigned int ulIdx;
  745. //
  746. // Check the arguments.
  747. //
  748. ASSERT(pWidget);
  749. ASSERT(pDisplay);
  750. //
  751. // Clear out the widget structure.
  752. //
  753. for(ulIdx = 0; ulIdx < sizeof(tSliderWidget); ulIdx += 4)
  754. {
  755. ((unsigned int *)pWidget)[ulIdx / 4] = 0;
  756. }
  757. //
  758. // Set the size of the slider widget structure.
  759. //
  760. pWidget->sBase.lSize = sizeof(tSliderWidget);
  761. //
  762. // Mark this widget as fully disconnected.
  763. //
  764. pWidget->sBase.pParent = 0;
  765. pWidget->sBase.pNext = 0;
  766. pWidget->sBase.pChild = 0;
  767. //
  768. // Save the display pointer.
  769. //
  770. pWidget->sBase.pDisplay = pDisplay;
  771. //
  772. // Set the extents of this slider.
  773. //
  774. pWidget->sBase.sPosition.sXMin = lX;
  775. pWidget->sBase.sPosition.sYMin = lY;
  776. pWidget->sBase.sPosition.sXMax = lX + lWidth - 1;
  777. pWidget->sBase.sPosition.sYMax = lY + lHeight - 1;
  778. //
  779. // Use the slider message handler to process messages to this widget.
  780. //
  781. pWidget->sBase.pfnMsgProc = SliderMsgProc;
  782. }
  783. //*****************************************************************************
  784. //
  785. // Close the Doxygen group.
  786. //! @}
  787. //
  788. //*****************************************************************************