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