home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / prgramer / slider / slider.txt < prev   
Text File  |  1992-09-08  |  36KB  |  905 lines

  1. Column Name: Advanced PM Programming
  2. Column Title: Using Sliders
  3.  
  4. by: Guy Scharf
  5. (c) Copyright 1992 Software Architects, Inc.
  6.  
  7.  
  8. Introducing Sliders
  9.  
  10. OS/2 2.0 introduces four new controls-slider, value set,
  11. notebook, and container.  We'll look this month at the
  12. slider.
  13.  
  14. The slider is best used for setting values that are more
  15. analog than digital in nature.  Visually, the slider is
  16. represented as a bar with a handle that can be moved to any
  17. location along the bar.  The user can grab the handle and
  18. move it to the desired location.  The slider can have detents
  19. that allow the user to set the slider to preselected values
  20. with a single click of the mouse.  Optional buttons can be
  21. used to move the slider bar one increment at a time.
  22.  
  23. Used for output, the slider control also makes an excellent
  24. progress or percentage complete bar.  Our example
  25. program shows sliders used for input and as a progress bar.
  26.  
  27.  
  28. CUA Controls Library/2
  29.  
  30. IBM has not forgotten OS/2 1.3 developers.  IBM's CUA
  31. Controls Library/2 product makes all of the OS/2 2.0
  32. controls as well as the standard font selection and file open
  33. dialogs available to both OS/2 1.3 and Windows
  34. developers.
  35.  
  36. This product provides OS/2 1.3 with the same API as with
  37. OS/2 2.0.  Converting a program using CUA Library/2
  38. controls to OS/2 2.0 requires making only minor changes:
  39. 1) a DosLoadModule call required to register the CUA
  40. Library/2 control is deleted, 2) if the control is defined in
  41. a resource script, the window class name is changed from
  42. CCL_SLIDER to WC_SLIDER and 3) a #include statement
  43. required for CUA Library/2 is deleted.  These are all the
  44. changes that are required, and selective use of #ifdef and
  45. #define can take care of most of these changes.  Messages
  46. sent to or received from the control remain unchanged.
  47.  
  48. The sample code in this article has been compiled using
  49. both OS/2 1.3 and OS/2 2.0 with just these changes.
  50.  
  51.  
  52. Converting from OS/2 1.3 to 2.0
  53.  
  54. Before examining the slider, let's look at some issues
  55. involved in developing applications for both OS/2 1.3 and
  56. OS/2 2.0.  A reader asks why the subclassing example of
  57. the column in the first issue does not work under OS/2 2.0. 
  58. Two minor changes are required to make that example
  59. work.  These are typical of the changes required when
  60. converting to OS/2 2.0.
  61.  
  62. First, the length of the message-number parameter in
  63. messages sent to windows must be changed from a
  64. USHORT to a ULONG.  In many OS/2 2.0 functions,
  65. parameters that were USHORTs in OS/2 1.3 have been
  66. changed to ULONGs. If you use the header files supplied
  67. with the toolkit, most of these changes should be nearly
  68. transparent.  If you have typed your own prototypes of
  69. OS/2 functions, you will probably need to update them.
  70.  
  71. I now define a MSGID type in my programs, and
  72. conditionally compile MSGID as a USHORT or a ULONG
  73. as appropriate for the target operating system.
  74.  
  75. The second change is caused by a change in the
  76. WinRegisterClass API.  In OS/2 1.3, this API was
  77. documented as requiring the existence of a message queue,
  78. but it does not.  In OS/2 2.0, this API is not documented
  79. as requiring existence of a message queue, but it does!  To
  80. fix SUBCLASS.C for OS/2 2.0, move the call to the class
  81. registering function to follow the creation of the message
  82. queue.
  83.  
  84.  
  85. Slider Basics
  86.  
  87. A slider can be used as an input control device or as a
  88. read-only display device.  While the latter is simply a
  89. variation on the input device, it is visually distinctive. 
  90. Figures 1 and 2 demonstrate these two appearances.
  91.  
  92. The most visible component of a slider is the slider shaft. 
  93. The width of the shaft can be varied, which is especially
  94. useful in displaying progress bars.  The shaft can be
  95. arranged horizontally or vertically.  The slider arm defines
  96. the position of the control along a scale of increments.  In
  97. an input control, this arm is represented by a handle that
  98. the user can grab and drag.  On an output control, the arm
  99. is a vertical line, usually with a different color, called a
  100. ribbon strip, on each side.
  101.  
  102. The bottom of the slider can be at either the left or right
  103. (top or bottom) of the control.  Labels, tick marks of
  104. various sizes, and detents can be placed above or below the
  105. shaft.
  106.  
  107. If the user clicks on the slider to either side of the slider
  108. arm, the arm is moved one increment in that direction. 
  109. Holding the mouse button down does not cause further
  110. movement.  Optional slider buttons at either end of the
  111. slider cause a single movement if clicked once, and
  112. continuing movement if the mouse button is held down.
  113.  
  114. A detent allows a user to move the slider arm to a
  115. prespecified value by clicking on the detent with the mouse
  116. button.
  117.  
  118.  
  119. Creating a Slider
  120.  
  121. As with most controls, you can create a control window
  122. using WinCreateWindow or you can define the control in a
  123. resource script.  However, unlike older controls, slider
  124. control windows require that some control data be supplied
  125. at the time the control is created.  The SLDCDATA
  126. structure defines the required data:
  127.  
  128.         typedef struct _SLDCDATA {
  129.         ULONG   cbSize;          // Size of control data 
  130.         USHORT  usScale1Increments;    // # of divisions
  131.         USHORT  usScale1Spacing;       // Space in pels
  132.         USHORT  usScale2Increments;    // # of divisions
  133.         USHORT  usScale2Spacing;       // Space in pels
  134.         } SLDCDATA;
  135.  
  136. The control data specifies the length of the slider, in
  137. arbitrary units called increments, and the distance between
  138. each increment, in pixels for two scales.  Scale 1, if used,
  139. appears above or to the left of the slider; scale 2, below or
  140. to the right.  Since calculating distances in pixels is a
  141. nuisance, the control will calculate it for you if the distance
  142. value is given as 0.  If the SLDCDATA structure is not
  143. provided, the slider is not created.  When defining a slider
  144. in a resource script, the CTLDATA statement can be used
  145. to create the required data structure.
  146.  
  147. After creating the basic slider control, the developer sends
  148. messages to the control to establish the size and placement
  149. of tick marks, text above one or more tick marks, detents,
  150. and the slider arm position.  You can also change the
  151. dimensions of the slider and modify other appearances of
  152. the control.  An owner-draw style is available, so that you
  153. can draw the control yourself.
  154.  
  155. You retrieve information from the slider by sending
  156. messages to it.  Some messages return values in
  157. increments; others, in pixels.  Some messages offer you a
  158. choice.
  159.  
  160.  
  161. Sliders in Dialog Resource Scripts
  162.  
  163. In our example, we have two sliders.  The first allows the
  164. user to choose a value of 0 to 90 seconds.  Having chosen
  165. that value using the slider, the user presses the OK button
  166. and a progress bar is displayed for that number of seconds. 
  167. The progress bar advances evenly over the number of
  168. seconds requested.
  169.  
  170. Let's look first at the resource script, SLIDER.RC in our
  171. example.  Both sliders are horizontally arranged with
  172. SLS_HORIZONTAL.  On the time-setting slider,
  173. SLS_PRIMARYSCALE1 says that we are going to write our
  174. tick marks and text above the slider shaft.  To make more
  175. room for this text in the control area, we move the slider
  176. shaft to the bottom of the control window with
  177. SLS_BOTTOM.  We define 0 as being at the left end of the
  178. slider with SLS_HOMELEFT.  We then request buttons at
  179. the right end of the control with SLS_BUTTONSRIGHT.
  180.  
  181. The CTLDATA statement defines the SLDCDATA structure. 
  182. The CTLDATA statement is followed by a series of numeric
  183. parameters.  These parameters are each converted by the
  184. resource compiler into a USHORT.  The complete string of
  185. USHORTs constitutes the data structure used by the dialog
  186. when creating the slider control window.  Since the first
  187. element of the SLDCDATA structure is a ULONG giving
  188. the total size of the structure, we must compose that
  189. ULONG with two USHORTs.  The total length of the data
  190. structure is 12 bytes.  Since Intel architecture places the
  191. least significant digits in the high-order bytes, we define a
  192. ULONG with a value of 12 as two USHORTs with values
  193. of 12 and 0.  We define this slider as having 91
  194. increments, allowing us to represent values from 0 through
  195. 90.  We set the pixel spacing of the increments to 0, to
  196. allow the dialog to compute the largest spacing that will fit
  197. within the bounds of the control.  We need to define only
  198. the scale that we are going to use; any definition we
  199. provide for the other scale is ignored.
  200.  
  201. Our definition for the progress bar is similar.  We put the
  202. slider in the center of the control window with
  203. SLS_CENTER.  We make it a read-only control, and thus
  204. having a vertical line instead of a handle as the slider arm,
  205. with SLS_READONLY.  We put the text below the slider by
  206. specifying SLS_PRIMARYSCALE2.  Finally, we ask that the
  207. slider have a different color on each side of the slider arm,
  208. making the appearance that of a horizontal bar.  This is
  209. called a ribbon strip and we request it with the
  210. SLS_RIBBONSTRIP style.
  211.  
  212. We define CTLDATA for this slider similarly.  The 101
  213. increments allow values of 0 through 100.
  214.  
  215.  
  216. Initializing the Slider
  217.  
  218. Sliders require more setup than older controls.  In the
  219. example, the setup code is isolated in the InitSlider()
  220. function.  We call this function during WM_INITDLG
  221. processing to initialize each slider.
  222.  
  223. As the first step, we obtain the increments and spacing
  224. values from the original CTLDATA structure (or as
  225. calculated by the control).  Most of the messages we will
  226. be sending the slider control will use increments.  Detents,
  227. however, are set in terms of pixels, as they are not required
  228. to be aligned with an increment.  Since our initialization
  229. function is a general utility, we obtain this information
  230. from the control rather than hard coding it or having it
  231. passed in by the caller.  We use
  232. WM_QUERYWINDOWPARAMS to obtain this control data. 
  233. Alternatively, we could have used the
  234. SLM_QUERYSLIDERINFO message to obtain most of the
  235. information we need.  This message returns four types of
  236. dimension information, either as increments or as pixel
  237. dimensions.  This message is used frequently when
  238. programming sliders.
  239.  
  240. If the caller wants the slider shaft to be larger, we change
  241. its dimensions using SLM_SETSLIDERINFO.  Again, this
  242. is a message that can set many values.  In our example, we
  243. increase the width when using the slider as a progress bar.
  244.  
  245. Ticks are set at specific increments.  (An increment is an
  246. arbitrary unit between 0 and the maximum specified in the
  247. CTLDATA statement.)  The programmer controls tick sizes. 
  248. In this example, we use two tick sizes, which we refer to
  249. as major and minor tick marks.  Detents are set similarly. 
  250. Our utility can set tick marks only on a linear scale.  You
  251. can set tick marks at any increment values, or at none.  We
  252. set no tick marks for the progress bar, as the absolute value
  253. is of little interest.
  254.  
  255. Text can also be set at increments.  While any text string
  256. can be set, we use numbers corresponding to the increment
  257. value.
  258.  
  259.  
  260. Looking at the Sample Program
  261.  
  262. The sample program is relatively simple-the slider control
  263. is easy to program and to use.  The main program simply
  264. starts a dialog to obtain a time interval between 0 and 90
  265. seconds.  When the user presses OK, that dialog starts a
  266. second dialog to count down that number of seconds the
  267. user specified.  The dialogs then return to the main
  268. program, which then terminates.  This demo program does
  269. not have a standard window.
  270.  
  271. The GetAmountDlgProc() dialog procedure is the dialog
  272. procedure for the IDLG_SETTIME dialog.  It initializes the
  273. slider during WM_INITDLG processing and waits for the
  274. user to press the OK or Cancel button.  When the user
  275. presses OK, the dialog reads the number of seconds set on
  276. the slider control and starts the progress display dialog,
  277. passing the number of seconds requested.
  278.  
  279. The ProgressDlgProc() dialog procedure is the dialog
  280. procedure for the IDLG_PROGRESS dialog.  It initializes
  281. its slider, using different parameters more appropriate to a
  282. progress bar.  It then sets up a repetitive timer using
  283. WinStartTimer().  Each time the timer sends a WM_TIMER
  284. message, the dialog computes the percentage complete and
  285. updates the slider if the percentage has changed.
  286.  
  287. The frequency of the timer is controlled by the
  288. TIMERINTERVAL #define statement.  We have defined the
  289. slider as having 100 increments, so the movement of the
  290. slider will never be finer than 1/100 of the total distance. 
  291. If the duration is large, then very frequent timer messages
  292. are wasteful, as the percentage complete will not change
  293. with each message.  However, if the timer intervals are
  294. large, then the progress bar does not move smoothly when
  295. the number of seconds is small.  Picking a good frequency
  296. for the timer depends on the use planned for the slider. 
  297. We used a rate of four per second in this example.
  298.  
  299. In a real application, you could use a progress bar like this
  300. to report the status of some time-consuming task.  That task
  301. could send periodic updates to the dialog, which would then
  302. update the progress bar to reflect the progress of the task. 
  303. Or, you could use a WM_TIMER message to poll the state
  304. of a task and update the progress bar appropriate.  We have
  305. used both approaches, depending on whether the task knew
  306. how to send messages or whether it could only update a
  307. counter.
  308.  
  309.  
  310. Summary
  311.  
  312. Sliders are very useful for obtaining or displaying analog
  313. values.  They excel when a bar representation fits the
  314. experience of the user.  Sliders also make great progress
  315. bars or percentage complete displays.
  316.  
  317. The programs in this article are available on the OS2DEV
  318. forum on CompuServe.  GO OS2DEV and download file
  319. SLIDER.ZIP from library 4, Ver 2.0.
  320.  
  321. ------------------------
  322.  
  323. Guy Scharf is president of Software Architects, Inc., 2163
  324. Jardin Drive, Mountain View, CA 94040.  Software
  325. Architects, Inc. specializes in OS/2 Presentation Manager
  326. software development and consulting.  Guy can be reached
  327. on the CompuServe OS2DEV forum or on CompuServe
  328. Mail at 76702,557 or through Internet at
  329. 76702.557@compuserve.com.
  330.  
  331.  
  332.  
  333. LISTING 1.  SLIDER.C
  334. ====================
  335.  
  336. // slider.c -- Sample program to demonstrate slider
  337.  
  338. //--------------------------------------------------------------
  339. //  slider.c
  340. //
  341. //      Sample program to demonstrate sliders.  
  342. //
  343. //  By: Guy Scharf                      (415) 948-9186
  344. //      Software Architects, Inc.       FAX: (415) 948-1620
  345. //      2163 Jardin Drive               
  346. //      Mountain View, CA   94040       
  347. //      CompuServe: 76702,557
  348. //      Internet: 76702.557@compuserve.com
  349. //  (c) Copyright 1992 Software Architects, Inc.  
  350. //
  351. //      All Rights Reserved.
  352. //
  353. //  Software Architects, Inc. develops software products for 
  354. //  independent software vendors using OS/2 and Presentation 
  355. //  Manager.
  356. //--------------------------------------------------------------
  357.  
  358. #define INCL_PM                         // Basic OS/2 PM
  359. #define INCL_BASE                       // components
  360. #include <OS2.H>
  361.  
  362. #include <stdlib.h>                     // C runtime library
  363. #include <string.h>
  364.  
  365. #include "slider.h"                     // Slider demo defs
  366.  
  367. //  Prototypes of dialog procedures
  368.  
  369. static MRESULT EXPENTRY GetAmountDlgProc (HWND, MSGID, MPARAM,
  370.                                           MPARAM);
  371. static MRESULT EXPENTRY ProgressDlgProc (HWND, MSGID, MPARAM,
  372.                                          MPARAM);
  373.  
  374. //--------------------------------------------------------------
  375. //                                                                          
  376. //  Main program to drive slider example
  377. //                                                                          
  378. //--------------------------------------------------------------
  379.  
  380. int main (void)
  381. {
  382.     HAB              hab;                        // Handle to anchor block
  383.     HMQ              hmqMsgQueue;                // Handle to msg queue
  384. #ifndef OS220
  385.     HMODULE hmodSlider;                 // Handle to slider mod
  386. #endif
  387.  
  388.     hab = WinInitialize (0);            // Initialize PM
  389.  
  390.     hmqMsgQueue = WinCreateMsgQueue (hab, 0); // Create msg queue
  391.  
  392. #ifndef OS220
  393.     if (DosLoadModule (NULL, 0, CCL_SLIDER_DLL, &hmodSlider))
  394.         return FALSE;
  395. #endif
  396.  
  397.     WinDlgBox (HWND_DESKTOP, HWND_DESKTOP, GetAmountDlgProc, 0,
  398.                IDLG_SETTIME, NULL);
  399.  
  400. #ifndef OS220
  401.     DosFreeModule (hmodSlider);
  402. #endif
  403.  
  404.     WinDestroyMsgQueue (hmqMsgQueue);   // Shutdown
  405.     WinTerminate       (hab);
  406.     return 0;
  407. }
  408.  
  409. //--------------------------------------------------------------
  410. //                                                                          
  411. //  GetAmountDlgProc() -- Determine time delay desired
  412. //                                                                          
  413. //--------------------------------------------------------------
  414.  
  415. static MRESULT EXPENTRY GetAmountDlgProc (
  416. HWND    hwndDlg,
  417. MSGID   msg,
  418. MPARAM  mp1,
  419. MPARAM  mp2)
  420. {
  421.     USHORT  usTime;                     // Time for progress
  422.  
  423.     switch(msg)
  424.     {
  425.         //------------------------------------------------------
  426.         //  Initialize dialog by setting labels, ticks, detents,
  427.         //  etc.  This must all be done programmatically.
  428.         //------------------------------------------------------
  429.         case WM_INITDLG:
  430.  
  431.             //--------------------------------------------------
  432.             //  Set the marks, detents, and labels
  433.             //  Set small tick marks every 1 second
  434.             //  Set large tick marks every 10 seconds
  435.             //  Set detent every 15 seconds
  436.             //--------------------------------------------------
  437.             InitSlider (hwndDlg, IDSL_SETTIME_TIME, 0,
  438.                         1,  4,
  439.                         10, 8,
  440.                         30, 30,
  441.                         "8.Courier");
  442.  
  443.             return 0;
  444.  
  445.         //------------------------------------------------------
  446.         //  Process pushbuttons.  Enter starts a progress bar.
  447.         //  Cancel (ESC) just quits quietly.
  448.         //------------------------------------------------------
  449.         case WM_COMMAND:
  450.             switch (SHORT1FROMMP(mp1))
  451.             {
  452.                                         // Cancel pressed
  453.                                         // Dismiss dialog
  454.                 case DID_CANCEL:
  455.                     WinDismissDlg (hwndDlg, FALSE);
  456.                     return 0;
  457.  
  458.                                         // OK button pressed
  459.                 case DID_OK:            // Read slider position
  460.                                         // from slider
  461.                     usTime = SHORT1FROMMR(WinSendDlgItemMsg(
  462.                                hwndDlg,
  463.                                IDSL_SETTIME_TIME,
  464.                                SLM_QUERYSLIDERINFO,
  465.                                MPFROM2SHORT(SMA_SLIDERARMPOSITION,
  466.                                             SMA_INCREMENTVALUE),
  467.                                0));
  468.                                         // Start progress bar
  469.                                         // dialog
  470.                     if (usTime > 0)
  471.                         WinDlgBox (HWND_DESKTOP, HWND_DESKTOP,
  472.                                    ProgressDlgProc, 0,
  473.                                    IDLG_PROGRESS, &usTime);
  474.                     return 0;
  475.             }
  476.             return 0;
  477.                                
  478.         //------------------------------------------------------
  479.         //  All other messages go to default window procedure
  480.         //------------------------------------------------------
  481.         default:
  482.             return (WinDefDlgProc (hwndDlg, msg, mp1, mp2));
  483.     }
  484.     return FALSE;
  485. }
  486.  
  487.  
  488. //--------------------------------------------------------------
  489. //                                                                          
  490. //  ProgressDlgProc() -- Show progress bar.  This is a minimal
  491. //  function dialog.  It just moves the progress bar along
  492. //  without reflecting any particular activity.
  493. //                                                                          
  494. //--------------------------------------------------------------
  495.  
  496. typedef struct
  497. {
  498.     USHORT  usTotalUnits;               // # units to count
  499.     USHORT  usUnitsSoFar;               // count so far
  500.     USHORT  usPctDone;                  // Last reported % done
  501. } PROG, *PPROG;
  502.  
  503. #define TIMERINTERVAL    4              // Timer checks per sec
  504.  
  505. static MRESULT EXPENTRY ProgressDlgProc (
  506. HWND    hwndDlg,
  507. MSGID   msg,
  508. MPARAM  mp1,
  509. MPARAM  mp2)
  510. {
  511.     PPROG   pprog;                      // Progress data
  512.  
  513.     switch(msg)
  514.     {
  515.         //------------------------------------------------------
  516.         //  Initialize dialog by constructing a work area and
  517.         //  establishing a pointer to it in the dialog window
  518.         //  word.  Set initial values to 0 and compute the
  519.         //  number of ticks desired from the passed value
  520.         //  (which is in seconds)
  521.         //------------------------------------------------------
  522.         case WM_INITDLG:                // Initialize data
  523.             pprog = malloc (sizeof (PROG));
  524.             WinSetWindowPtr (hwndDlg, QWL_USER, pprog);
  525.  
  526.             pprog->usUnitsSoFar = 0;    // Ticks so far
  527.             pprog->usPctDone = 0;       // Start at 0
  528.             pprog->usTotalUnits = (USHORT)(*(PUSHORT)mp2
  529.                                           * TIMERINTERVAL);
  530.  
  531.             //--------------------------------------------------
  532.             //  Set 2x wide slider, 
  533.             //  No small tick
  534.             //  No large ticks
  535.             //  No detents
  536.             //  0, 50, 100% complete
  537.             //--------------------------------------------------
  538.             InitSlider (hwndDlg, IDSL_PROGRESS_BAR, 2,
  539.                         0, 4,
  540.                         0, 8,
  541.                         0, 50,
  542.                         NULL);
  543.  
  544.             //--------------------------------------------------
  545.             //  Start the timer for periodic display
  546.             //--------------------------------------------------
  547.             WinStartTimer (WinQueryAnchorBlock (hwndDlg),
  548.                            hwndDlg, ID_TIMER,
  549.                            1000/TIMERINTERVAL);
  550.  
  551.             return 0;
  552.  
  553.         //------------------------------------------------------
  554.         //  When dialog is destroyed, we release any data
  555.         //  we have allocated.  This prevents memory leakage.
  556.         //------------------------------------------------------
  557.         case WM_DESTROY:                
  558.             pprog = WinQueryWindowPtr (hwndDlg, QWL_USER);
  559.                                         // Stop the timer
  560.             WinStopTimer (WinQueryAnchorBlock (hwndDlg),
  561.                           hwndDlg, ID_TIMER);
  562.             if (pprog != NULL)          // If data exists,
  563.                 free (pprog);           // free it
  564.             WinSetWindowPtr (hwndDlg, QWL_USER, NULL);
  565.  
  566.             return 0;
  567.  
  568.         //------------------------------------------------------
  569.         //  We support only a Cancel pushbutton
  570.         //------------------------------------------------------
  571.         case WM_COMMAND:
  572.             switch (SHORT1FROMMP(mp1))
  573.             {                           // Cancel key pressed
  574.                 case DID_CANCEL:        // Just quit quietly
  575.                     WinDismissDlg (hwndDlg, FALSE);
  576.                     return 0;
  577.             }
  578.             return 0;
  579.                      
  580.           
  581.         //------------------------------------------------------
  582.         //  On every timer tick, we computer the percent
  583.         //  complete.  If different than on the last timer
  584.         //  click, we update the progress bar.
  585.         //------------------------------------------------------
  586.         case WM_TIMER:
  587.         {
  588.             USHORT  usNewPctDone = 0;   // Percent complete
  589.  
  590.                                         // Get ptr to dialog data
  591.             pprog = WinQueryWindowPtr (hwndDlg, QWL_USER);
  592.  
  593.                                         // Compute % complete
  594.                                         // and update the slider
  595.             pprog->usUnitsSoFar++;
  596.                                         // Don't allow over 100
  597.             usNewPctDone = (USHORT)min((100*pprog->usUnitsSoFar)
  598.                                 / pprog->usTotalUnits, 100);
  599.  
  600.                                         // If % done is changed,
  601.                                         // update slider
  602.             if (usNewPctDone != pprog->usPctDone)
  603.             {
  604.                 pprog->usPctDone = usNewPctDone;
  605.                 
  606.                 WinSendDlgItemMsg (hwndDlg, IDSL_PROGRESS_BAR,
  607.                             SLM_SETSLIDERINFO,
  608.                             MPFROM2SHORT (SMA_SLIDERARMPOSITION,
  609.                                             SMA_INCREMENTVALUE),
  610.                             MPFROMSHORT (usNewPctDone));
  611.             }
  612.  
  613.                                         // If all done, quit
  614.             if (pprog->usUnitsSoFar > pprog->usTotalUnits)
  615.                 WinSendMsg (hwndDlg, WM_CLOSE, 0, 0);
  616.  
  617.             return 0;
  618.         }
  619.  
  620.         //------------------------------------------------------
  621.         //  All other messages go to default window procedure
  622.         //------------------------------------------------------
  623.         default:
  624.             return (WinDefDlgProc (hwndDlg, msg, mp1, mp2));
  625.     }
  626.  
  627.     return FALSE;
  628. }
  629.  
  630. //--------------------------------------------------------------
  631. // Function: InitSlider                                         
  632. // Outputs:  none                                               
  633. //                                                              
  634. // This function receives all parameters for configuring a
  635. // slider.  It sets tick marks, tick text, and detents 
  636. // according to the input parameters.  The scale text font is 
  637. // changed if requested.  This function works only on scale 1.
  638. //--------------------------------------------------------------
  639.  
  640. VOID InitSlider (                       // Initialize slider
  641. HWND    hwndDlg,                        // Handle of dialog
  642. ULONG   idSlider,                       // ID of slider control
  643. USHORT  usSizeMultiplier,               // Size multiplier
  644. USHORT  usMinorTickSpacing,             // Minor tick spacing
  645. USHORT  usMinorTickSize,                // Size of minor ticks
  646. USHORT  usMajorTickSpacing,             // Major tick spacing
  647. USHORT  usMajorTickSize,                // Size of major ticks
  648. USHORT  usDetentSpacing,                // Detent spacing
  649. USHORT  usTextSpacing,                  // Text label spacing
  650. PSZ     pszFont)                        // Font for text or NULL
  651. {
  652.     USHORT  i;                          // Loop index
  653.     CHAR    buffer[20];                 // String buffer
  654.     USHORT  usIncrements = 0;           // Number of increments
  655.     USHORT  usSpacing = 0;              // Spacing
  656.  
  657.     WNDPARAMS   wprm;                   // Window parameters ct;
  658.     SLDCDATA    sldcd;                  // Slider control data
  659.  
  660.     HWND    hwndSlider = WinWindowFromID (hwndDlg, idSlider);
  661.  
  662.     //----------------------------------------------------------
  663.     // Get original slider dimensions in increments for future
  664.     // calls.  (My thanks to Wayne Kovsky for this example of 
  665.     // using WM_QUERYWINDOWPARAMS.)
  666.     //----------------------------------------------------------
  667.     wprm.fsStatus   = WPM_CTLDATA;      // Request control data
  668.     wprm.cbCtlData  = sizeof (SLDCDATA);
  669.     wprm.pCtlData   = &sldcd;
  670.  
  671.     if (WinSendMsg (hwndSlider, WM_QUERYWINDOWPARAMS,
  672.                      MPFROMP(&wprm), 0))
  673.     {                                   // Copy fields we need
  674.         usIncrements = sldcd.usScale1Increments;
  675.         usSpacing    = sldcd.usScale1Spacing;
  676.     }
  677.     
  678.     //----------------------------------------------------------
  679.     //  If requested, change dimensions of the slider
  680.     //----------------------------------------------------------
  681.     if (usSizeMultiplier > 1)
  682.     {
  683.         MRESULT mr;
  684.         mr = WinSendMsg (hwndSlider,
  685.                          SLM_QUERYSLIDERINFO,
  686.                          MPFROMSHORT(SMA_SHAFTDIMENSIONS), 0);
  687.  
  688.         WinSendMsg (hwndSlider,
  689.                     SLM_SETSLIDERINFO,
  690.                     MPFROMSHORT(SMA_SHAFTDIMENSIONS),
  691.                     MPFROMSHORT (SHORT2FROMMR(mr) *
  692.                                              usSizeMultiplier));
  693.  
  694.     }
  695.  
  696.     //----------------------------------------------------------
  697.     //  If requested, set minor ticks along axis
  698.     //----------------------------------------------------------
  699.     if (usMinorTickSpacing != 0)
  700.         for (i = 0; i <= usIncrements; i += usMinorTickSpacing)
  701.         {
  702.             WinSendMsg (hwndSlider,     // Set minor tick
  703.                         SLM_SETTICKSIZE,
  704.                         MPFROM2SHORT(i, usMinorTickSize),
  705.                         NULL);
  706.         }
  707.  
  708.     //----------------------------------------------------------
  709.     //  If requested, set major ticks along axis
  710.     //----------------------------------------------------------
  711.     if (usMajorTickSpacing != 0)
  712.         for (i = 0; i <= usIncrements; i += usMajorTickSpacing)
  713.         {
  714.             WinSendMsg (hwndSlider,     // Set major tick
  715.                         SLM_SETTICKSIZE,
  716.                         MPFROM2SHORT(i, usMajorTickSize),
  717.                         NULL);
  718.         }
  719.  
  720.     //----------------------------------------------------------
  721.     //  If requested, set detents
  722.     //----------------------------------------------------------
  723.     if (usDetentSpacing != 0)
  724.         for (i = 0; i <= usIncrements; i += usDetentSpacing)
  725.         {
  726.             WinSendMsg (hwndSlider,     // Set the detent
  727.                    SLM_ADDDETENT,
  728.                    MPFROM2SHORT((i*usSpacing), usDetentSpacing),
  729.                    NULL);
  730.         }
  731.  
  732.     //----------------------------------------------------------
  733.     //  If requested, set text labels.  Also change font if
  734.     //  requested
  735.     //----------------------------------------------------------
  736.     if (usTextSpacing != 0)
  737.     {
  738.         if (pszFont != NULL)
  739.             WinSetPresParam (hwndSlider,
  740.                              PP_FONTNAMESIZE,
  741.                              (strlen(pszFont)+1),
  742.                              pszFont);
  743.         for (i = 0; i <= usIncrements; i += usTextSpacing)
  744.         {
  745.             itoa (i, buffer, 10);       // Convert to string
  746.             WinSendMsg (hwndSlider,     // Place in slider scale
  747.                         SLM_SETSCALETEXT,
  748.                         MPFROMSHORT(i),
  749.                         MPFROMP(buffer));
  750.         }
  751.     }
  752.  
  753.     return;
  754. }
  755.  
  756. LISTING 2.  SLIDER.H
  757. ====================
  758.  
  759. // slider.h -- Definitions for slider demo
  760.  
  761. //--------------------------------------------------------------
  762. //  Change the following as required for target system
  763. //--------------------------------------------------------------
  764. #define OS220                           // Define target system
  765.  
  766. #ifdef OS220
  767.     #define MSGID   ULONG               // OS/2 2.0
  768. #else
  769.     #define MSGID   USHORT              // OS/2 1.3
  770.     #include <fclsldp.h>                // CUA Library/2
  771.     #define WC_SLIDER CCL_SLIDER        // Window class
  772. #endif                               
  773.  
  774. //  Defines for dialogs, controls
  775.  
  776. #define IDLG_SETTIME                100 // Set time dialog
  777. #define IDSL_SETTIME_TIME           101
  778.  
  779. #define IDLG_PROGRESS               200 // Progress bar dialog
  780. #define IDSL_PROGRESS_BAR           201
  781.  
  782. #define ID_TIMER                      1 // For WinStartTimer
  783.  
  784. //  Prototypes for useful functions
  785.  
  786. VOID InitSlider (                       // Initialize slider
  787. HWND    hwndDlg,                        // Handle of dialog
  788. ULONG   idSlider,                       // ID of slider control
  789. USHORT  usSizeMultiplier,               // Size multiplier
  790. USHORT  usMinorTickSpacing,             // Minor tick spacing
  791. USHORT  usMinorTickSize,                // Size of minor ticks
  792. USHORT  usMajorTickSpacing,             // Major tick spacing
  793. USHORT  usMajorTickSize,                // Size of major ticks
  794. USHORT  usDetentSpacing,                // Detent spacing
  795. USHORT  usTextSpacing,                  // Text label spacing
  796. PSZ     pszFont);                       // Font for text or NULL
  797.  
  798. LISTING 3.  SLIDER.RC
  799. =====================
  800.  
  801. #include <os2.h>                        // OS/2 definitions
  802. #include "slider.h"                     // Application defs
  803.  
  804. DLGTEMPLATE IDLG_SETTIME LOADONCALL MOVEABLE DISCARDABLE
  805. BEGIN
  806.   DIALOG  "Set Time to Wait", IDLG_SETTIME, 66, 27, 203, 64, 
  807.           WS_VISIBLE, FCF_SYSMENU | FCF_TITLEBAR
  808.   BEGIN
  809.     CONTROL         "", IDSL_SETTIME_TIME, 15, 33, 173, 25, 
  810.                     WC_SLIDER,
  811.                     SLS_HORIZONTAL | SLS_BOTTOM | 
  812.                     SLS_SNAPTOINCREMENT | SLS_BUTTONSRIGHT | 
  813.                     SLS_HOMELEFT | SLS_PRIMARYSCALE1 | 
  814.                     WS_GROUP | WS_TABSTOP | WS_VISIBLE
  815.                     CTLDATA 12, 0, 91, 0, 0, 0
  816.     DEFPUSHBUTTON   "OK", DID_OK, 33, 10, 48, 14, WS_GROUP
  817.     PUSHBUTTON      "Cancel", DID_CANCEL, 113, 11, 48, 14, 
  818.                     NOT WS_TABSTOP
  819.   END
  820. END
  821.  
  822.  
  823. DLGTEMPLATE IDLG_PROGRESS LOADONCALL MOVEABLE DISCARDABLE
  824. BEGIN
  825.   DIALOG  "Percent Complete", IDLG_PROGRESS, 38, 57, 224, 73, 
  826.           WS_VISIBLE, FCF_SYSMENU | FCF_TITLEBAR
  827.   BEGIN
  828.     CONTROL         "", IDSL_PROGRESS_BAR, 18, 23, 189, 40, 
  829.                     WC_SLIDER, 
  830.                     SLS_HORIZONTAL | SLS_CENTER | SLS_READONLY
  831.                     SLS_RIBBONSTRIP | SLS_HOMELEFT | 
  832.                     SLS_PRIMARYSCALE2 | 
  833.                     WS_GROUP | WS_TABSTOP | WS_VISIBLE
  834.                     CTLDATA 12, 0, 101, 0, 101, 0
  835.     PUSHBUTTON      "Cancel", DID_CANCEL, 93, 4, 40, 14
  836.   END
  837. END
  838.  
  839. LISTING 4.  SLIDER.MAK
  840. ======================
  841.  
  842. # IBM Developer's Workframe/2 Make File Creation run at 14:39:08 on 06/30/92
  843.  
  844. # Make File Creation run in directory:
  845. #   D:\P\MAGAZINE\SLIDER;
  846.  
  847. .SUFFIXES:
  848.  
  849. .SUFFIXES: .c .rc
  850.  
  851. ALL: SLIDER.EXE \
  852.      SLIDER.RES
  853.  
  854. slider.exe:  \
  855.   SLIDER.OBJ \
  856.   SLIDER.RES \
  857.   SLIDER.MAK
  858.    @REM @<<SLIDER.@0
  859.      /A:16 /CO /F /M /ST:16384 /NOL /PM:PM +
  860.      SLIDER.OBJ
  861.      slider.exe
  862.      
  863.      
  864.      ;
  865. <<
  866.    LINK386.EXE @SLIDER.@0
  867.    RC SLIDER.RES slider.exe
  868.  
  869. {.}.rc.res:
  870.    RC -r .\$*.RC
  871.  
  872. {.}.c.obj:
  873.    ICC.EXE /Sm /Ss /Kbocgapexr /Ti /W2 /C .\$*.c
  874.  
  875. !include SLIDER.DEP
  876.  
  877.  
  878.  
  879. LISTING 5.  SLIDER.DEP
  880. ======================
  881.  
  882. # IBM Developer's Workframe/2 Make File Creation run at 14:39:08 on 06/30/92
  883.  
  884. # Make File Creation run in directory:
  885. #   D:\P\MAGAZINE\SLIDER;
  886.  
  887. # Assumed INCLUDE environment variable path:
  888. #   C:\TOOLKT20\C\OS2H;
  889. #   C:\TOOLKT20\ASM\OS2INC;
  890. #   C:\IBMC\INCLUDE;
  891.  
  892.  
  893. SLIDER.RES:  SLIDER.RC  \
  894. #  {.;$(INCLUDE)}OS2.H  \
  895.    {.;$(INCLUDE)}SLIDER.H  \
  896.    SLIDER.MAK
  897.  
  898. SLIDER.OBJ:  SLIDER.C  \
  899. #  {$(INCLUDE);}OS2.H  \
  900. #  {$(INCLUDE);}stdlib.h  \
  901. #  {$(INCLUDE);}string.h  \
  902. #  {$(INCLUDE);}fclsldp.h  \
  903.    {.;$(INCLUDE);}slider.h  \
  904.    SLIDER.MAK
  905.