April 18, 2024, 01:02:05 AM

News:

IonicWind Snippit Manager 2.xx Released!  Install it on a memory stick and take it with you!  With or without IWBasic!


15b. Saving Passed Parameters

Started by LarryMc, August 30, 2011, 10:31:14 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

LarryMc

August 30, 2011, 10:31:14 PM Last Edit: August 31, 2011, 10:00:02 PM by LarryMc
What we have left to do in this section is to add the code for each handler message that receives configuration data and stores it in g_dat.

We'll start with the portion of our handler that contains those messages:

....
     CASE GAGE_STYLE

        RETURN 0
     CASE GAGE_TITLE

        RETURN 0
     CASE GAGE_UNITS

        RETURN 0
     CASE GAGE_RAWRNG

        RETURN 0
     CASE GAGE_DIALRNG

        RETURN 0
     CASE GAGE_MULTI

        RETURN 0
     CASE GAGE_SETPANEL_COLOR

        RETURN 0
     CASE GAGE_DIAL_DARK

        RETURN 0
     CASE GAGE_CLKOFFSET

        RETURN 0
     CASE GAGE_SETPOS1

        RETURN 0
     CASE GAGE_SETPOS2

        RETURN 0
.....


For the most part it is simply a matter of loading the wparam or lparam value into the proper g_dat element.  But a few are a little more complicated.  We'll start with the simplest:

      CASE GAGE_STYLE
        #g_dat.sStyle = #<int>lParam
        RETURN 0


Notice that we used #<int>lParam instead of just lParam.  If you go back and look at the line where our handler is declared you will see that we defined the lparam parameter as ANYTYPE.  That means that each time we read/write that variable we have to specifiy what type of variable it currently contains.  If we don't specify or use the wrong type we can start overwriting memory and corrupt or crash the application.  We don't have to do this for the wParam parameter because we defined it as a UINT.

Now we will proceed with the simple handler cases:

     CASE GAGE_TITLE
        #g_dat.sName = ##<string>lParam
        RETURN 0


     CASE GAGE_UNITS
        #g_dat.sMultiUnits = ##<string>lParam
        RETURN 0


     CASE GAGE_RAWRNG
        #g_dat.nRangeMinAct = wParam
        #g_dat.nRangeMaxAct = #<int>lParam
        RETURN 0


     CASE GAGE_MULTI
        #g_dat.nDialMulti = #<int>lParam
        RETURN 0


    CASE GAGE_CLKOFFSET
        #g_dat.clockoffset = wParam
        RETURN 0


All the CASE statements we've covered so far have one thing in common.  They were sent from our ConfigGageRLM subroutine.  The significance of that is the presence of the GageInvalidateBackground function call at the end of the subroutine.  What we said about it at the time was
Quote"... it is used to insure that our control gets updated properly when the configuration is changed.".  
For the rest of our CASE statements we will have to take care of that ourselves.  The following OS function will cause a WM_PAINT message to be sent which will cause the current instance of the control to be redrawn:

        InvalidateRect(hWnd, NULL, FALSE)

The rest of our CASE statements will include the above call.

     CASE GAGE_SETPANEL_COLOR
        #g_dat.nPanelColor = wParam
        InvalidateRect(hWnd, NULL, FALSE)
        RETURN 0


     CASE GAGE_DIAL_DARK
        #g_dat.nGageColor = RGB(140,140,140)
        InvalidateRect(hWnd, NULL, FALSE)
        RETURN 0


     CASE GAGE_SETPOS1
        SELECT #g_dat.sStyle
           CASE ROUNDCLOCK12
           CASE& ROUNDCLOCK24
           DEFAULT
              #g_dat.nPos1 = wParam
        ENDSELECT
        InvalidateRect(hWnd, NULL, FALSE)
        RETURN 0


     CASE GAGE_SETPOS2
        #g_dat.nPos2 = wParam
        InvalidateRect(hWnd, NULL, FALSE)
        RETURN 0


For the CASE GAGE_SETPOS1 block (above) we needed to insert the added SELECT/ENDSELECT block. Since the clock hands are controlled internally by the PC's time we don't need to save the pointer position value. But we will use it to control how often the clocks are forced to redraw.

We saved the most complicated for last.  We'll start with the minimum:

     CASE GAGE_DIALRNG
        #g_dat.nRangeMinDial = wParam
        #g_dat.nRangeMaxDial = #<int>lParam
        RETURN 0


The rest of the code we are going to add to this CASE statement could be done in the portion of the handler that paints our gage. However, that would be highly inefficient since we really only need to execute the code we're going to add when the gage is configured. So what code are we talking about?

Our custom control is a ROUND gage.  As such a lot of our drawing will be based upon arcs of varying sizes. The placement of tick marks and the end points of pointers are all calculated based upon the sine and cosine of a specified angle.  The arc drawing function we will use assumes 0 degrees is at 3 o'clock and the numbers increase in a clockwise direction. We'll start with our 270 degree gages.  The standard placement is for the 90 degree empty segment to be center on the bottom of the gage.  The other three versions will be rotated by the proper amount from that standard position.  Our first added code will be:

  INT rot
  SELECT #g_dat.sStyle
     CASE ROUND270B
        rot=0
     CASE ROUND270T
        rot=180
     CASE ROUND270R
        rot=270
     CASE ROUND270L
        rot=90
  ENDSELECT


We've created a local variable to hold the amount of adjustment that needs to be made for each of the four 270 degree gages.

It must be noted that the remaining code we are going to add in this section was developed via trial and error during the course of developing the gage control originally. What we will do here is describe what we did and why we did it.
The next portion of code is another SELECT block:

     select #g_dat.sStyle
        case ROUND270B
        case& ROUND270R
        case& ROUND270L
        case& ROUND270T
           if #g_dat.nRangeMaxDial-#g_dat.nRangeMinDial <1 | #g_dat.nRangeMaxDial-#g_dat.nRangeMinDial >15
              #g_dat.nAngleStart = -230+rot
              #g_dat.nAngleEnd = 50+rot
              #g_dat.nRangeMinDial = 0
              #g_dat.nRangeMaxDial = 0
           endif
     ...


In this code we are checking to see if the user min and max dial range values are such that the range will be between 1 and 15.  This is because we want to limit the number of numbers displayed on the dial of this tpe of gage to prevent overcrowding.  If the value is outside the acceptable range we set some default values. Let's examine those defaults:

              #g_dat.nAngleStart = -230+rot
              #g_dat.nAngleEnd = 50+rot
              #g_dat.nRangeMinDial = 0
              #g_dat.nRangeMaxDial = 0


If you examine our GAGEPARAMS UDT you will notice there are no elements named nAngleStart and nAngleEnd.  The sine/cosine calculations we will use when drawing our gage will need a starting and an ending angle. So we need to add these two elements to our UDT which will now look like this:

TYPE GAGEPARAMS
 INT sStyle /*GAGE_STYLE*/
 STRING sName /*GAGE_TITLE*/
 STRING sMultiUnits /*GAGE_UNITS*/
 INT   nRangeMinAct /*GAGE_RAWRNG*/
 INT   nRangeMaxAct /*     "     */
 INT   nRangeMinDial /*GAGE_DIALRNG*/
 INT   nRangeMaxDial /*     "      */
 INT nDialMulti /*GAGE_MULTI*/
 UINT nPanelColor /*GAGE_SETPANEL_COLOR*/
 UINT nGageColor /*GAGE_DIAL_DARK*/
 INT clockoffset /*GAGE_CLKOFFSET*/
 INT   nPos1 /*GAGE_SETPOS1*/
 INT   nPos2 /*GAGE_SETPOS2*/
 FLOAT nAngleStart
 FLOAT nAngleEnd
ENDTYPE


Let's examine the following two lines of code closer:

              #g_dat.nAngleStart = -230+rot
              #g_dat.nAngleEnd      = 50+rot


A start angle of -230 degrees puts the min dial value at the 7:00 o'clock position.  It's a negative number because the 0 degree position for our drawing function is based at 3:00 o'clock. The end angle of 50 degrees is the max dial value at the 5:00 o'clock position.  We then shift the start/stop by the value of rot to account for our 4 different 270 type gages.  Doing the algebra we see that our default 270 gage really has a span of 280 degrees.  There is a very specific reason for the change.

We limit the number of major tick marks (and numbers ) on these gages to 16. Examples would be 0 to 15, -15 to 0, 40 to 55, etc.  The choice is up to the user.  It is then our task to evenly space those tick marks on our dial.  That means that the number of tick marks required has to evenly divide into our span.  And it just so happens that most of the numbers between 1 and 15 divide evenly into 280.  Where they don't divide evenly we have to adjust the start/stop to gives us a span that they will be evenly spaced.

We will now expand our code to make the necessary adjustments for 270 degree type gages.

     select #g_dat.sStyle
        case ROUND270B
        case& ROUND270R
        case& ROUND270L
        case& ROUND270T
           if #g_dat.nRangeMaxDial-#g_dat.nRangeMinDial <1 | #g_dat.nRangeMaxDial-#g_dat.nRangeMinDial >15
              #g_dat.nAngleStart = -230+rot
              #g_dat.nAngleEnd = 50+rot
              #g_dat.nRangeMinDial = 0
              #g_dat.nRangeMaxDial = 0
           endif
           select #g_dat.nRangeMaxDial-#g_dat.nRangeMinDial
              case 1
              case& 2
              case& 4
              case& 5
              case& 7
              case& 8
              case& 10
              case& 14
                 '280
                 #g_dat.nAngleStart = -230+rot
                 #g_dat.nAngleEnd = 50+rot
              case 3
                 '282
                 #g_dat.nAngleStart = -231+rot
                 #g_dat.nAngleEnd = 51+rot
              case 6
              case& 9
              case& 12
                 '288
                 #g_dat.nAngleStart = -234+rot
                 #g_dat.nAngleEnd = 54+rot
              case 11
              case& 13
                '286
                 #g_dat.nAngleStart = -233+rot
                 #g_dat.nAngleEnd = 53+rot
              case 15
                 #g_dat.nAngleStart = -225+rot
                 #g_dat.nAngleEnd = 45+rot
           endselect
....


Our last adjustment is for the 360 degree gages and the clocks.  This adjustment is made to make the starting point appear at the 12:00 o'clock position.  The code appears as:

case ROUND360SGL
case& ROUND360DBL
case& ROUNDCLOCK12
case& ROUNDCLOCK24
  '360
  #g_dat.nAngleStart = -90
  #g_dat.nAngleEnd = 270


The final code for the handler for the GAGE_DIALRNG message is:

case GAGE_DIALRNG
  #g_dat.nRangeMinDial = wParam
  #g_dat.nRangeMaxDial = #<int>lParam
  select #g_dat.sStyle
     case ROUND270B
                       rot=0
     case ROUND270T
 rot=180
     case ROUND270R
 rot=270
     case ROUND270L
        rot=90
  endselect
  select #g_dat.sStyle
     case ROUND270B
     case& ROUND270R
     case& ROUND270L
     case& ROUND270T
        if #g_dat.nRangeMaxDial-#g_dat.nRangeMinDial <1 | #g_dat.nRangeMaxDial-#g_dat.nRangeMinDial >15
  #g_dat.nAngleStart = -230+rot
  #g_dat.nAngleEnd = 50+rot
  #g_dat.nRangeMinDial = 0
  #g_dat.nRangeMaxDial = 0
endif
select #g_dat.nRangeMaxDial-#g_dat.nRangeMinDial
   case 1
   case& 2
   case& 4
   case& 5
   case& 7
   case& 8
   case& 10
   case& 14
      '280
#g_dat.nAngleStart = -230+rot
#g_dat.nAngleEnd = 50+rot
   case 3
'282
#g_dat.nAngleStart = -231+rot
#g_dat.nAngleEnd = 51+rot
   case 6
   case& 9
   case& 12
'288
#g_dat.nAngleStart = -234+rot
#g_dat.nAngleEnd = 54+rot
   case 11
   case& 13
'286
#g_dat.nAngleStart = -233+rot
#g_dat.nAngleEnd = 53+rot
   case 15
#g_dat.nAngleStart = -225+rot
#g_dat.nAngleEnd = 45+rot
endselect
     case ROUND360SGL
     case& ROUND360DBL
     case& ROUNDCLOCK12
     case& ROUNDCLOCK24
'360
#g_dat.nAngleStart = -90
#g_dat.nAngleEnd = 270
  endselect
                return 0


This completes the section on saving passed parameters.

____________________

Coming Next - Graphics Review
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library