IonicWind Software

IWBasic => Tutorials => Create a Custom Control => Topic started by: LarryMc on September 19, 2011, 09:40:16 PM

Title: 21. Notifying the Parent
Post by: LarryMc on September 19, 2011, 09:40:16 PM
During our early review of message handlers and IWBasic windows and controls, we discussed how a control could send messages to its parent window.  This was the mechanism by which an event occurring within a control would be reported to the parent window's handler.  The best example of this was the clicking of a button.

What we will do in this section is add code within our gage's message handler to notify the parent that the user has clicked on gage.  We'll then modify the test program so the parent will respond to the events.  There are four messages, sent by the OS, that we are going to trap in the gage's handler.  We'll start by adding the following code to our gage handler:

...
     case WM_LBUTTONDOWN 'left mouse button down

RETURN 0
     case WM_LBUTTONUP 'left mouse button up

RETURN 0
     case WM_RBUTTONDOWN 'right mouse button down

RETURN 0
     case WM_RBUTTONUP   'right mouse button up

RETURN 0
...


Next, we need a function that will send a message.  We'll add the following subroutine in Section 9 of CCT_lib.iwb:

sub GageLMSendWM_NOTIFY(hWnd:UINT, code:UINT),UINT
NMHDR nmhdr
nmhdr.hwndFrom = hWnd
nmhdr.idFrom   = GetDlgCtrlID(hWnd)
nmhdr.code     = code
return(SENDMESSAGE(GetParent(hWnd), WM_NOTIFY, nmhdr.idFrom, &nmhdr))
endsub


When we call this subroutine we pass it the OS handle of the gage that is sending the message and the message we want to send.  The subroutine first creates a UDT variable using the OS NMHDR structure.  To the first element shown we assign our gage's handle. To the next element we use the OS API function, GetDlgCtrlID, to return the IWBasic ID that was used when the gage was created.  We then use the SENDMESSAGE command to send the information to the appropriate parent. Pretty straightword.

The next logical step in the process is to create our message constants to send.  We'll use the same sort of scheme that we used when we setting up the messages to configure the various aspects of our gages.  The result looks like this:

ENUM NOTIFY_MSG
GNMLDOWN = 0x501
GNMLUP
GNMRDOWN
GNMRUP
ENDENUM


As before we assigned values for our custom message constant above 0x400 so as to not interfere with any standard OS messages that are sent to the parent window.  This block of code is placed at the top of Section 2 of CCT_lib.iwb with our other message constants.

Since the test application is going to be receiving these messages they need to be declared there also.  We'll use the following:

const GNMLDOWN = 0x501
const GNMLUP = 0x502
const GNMRDOWN = 0x503
const GNMRUP = 0x504


We'll place this block of code at the bottom of Section 1 of CCT_test.iwb with the other message constants there.

We'll return back to the gage handler messages we started with and add the code to send the four messages when the associated events occur.

...
     case WM_LBUTTONDOWN
        GageLMSendWM_NOTIFY(hWnd, GNMLDOWN)
 RETURN 0
     case WM_LBUTTONUP
        GageLMSendWM_NOTIFY(hWnd, GNMLUP)
 RETURN 0
     case WM_RBUTTONDOWN
        GageLMSendWM_NOTIFY(hWnd, GNMRDOWN)
 RETURN 0
     case WM_RBUTTONUP
        GageLMSendWM_NOTIFY(hWnd, GNMRUP)
 RETURN 0
...


To respond to these messages and check out two remaining gage functions we haven't addressed  we'll start looking at the two command subroutines as we originally coded them.

SUB SetGagePanelColorRLM(win as WINDOW,id as UINT,pnlcolor as UINT)
SENDMESSAGE(win, GAGE_SETPANEL_COLOR, pnlcolor,0, id)
RETURN
ENDSUB

SUB SetGageDialDarkRLM(win as WINDOW,id as UINT)
SENDMESSAGE(win, GAGE_DIAL_DARK, 0,0, id)
RETURN
ENDSUB


They need to be modified to the following:

SUB SetGagePanelColorRLM(win as WINDOW,id as UINT,pnlcolor as UINT)
int r1,g1,b1
uint pcolor
GageunRGBLM(pnlcolor, r1, g1, b1)
pcolor = RGBA(r1,g1,b1,255)
SENDMESSAGE(win, GAGE_SETPANEL_COLOR, pcolor,0, id)
GageInvalidateBackground(win, id)
RETURN
ENDSUB

SUB SetGageDialDarkRLM(win as WINDOW,id as UINT,state as INT)
SENDMESSAGE(win, GAGE_DIAL_DARK, state,0, id)
GageInvalidateBackground(win, id)
RETURN
ENDSUB


The SetGagePanelColorRLM subroutine is changed to reflect the fact that the user will enter a RGB color value and our gage needs a RGBA color value.

The SetGageDialDarkRLM subroutine is changed so that the dark dial mode can be turned off once it is turned on.

Since both of these functions control variables that are used only for the background we had to add GageInvalidateBackground to both for any changes to be seen.

The handler routines for those command's messages were originally  setup as:

     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


The new modified code appears as:

     CASE GAGE_SETPANEL_COLOR
 #g_dat.nPanelColor = wParam
        RETURN 0
     CASE GAGE_DIAL_DARK
 if wParam = 1
#g_dat.nGageColor = RGBA(140,140,140,255)
 else
#g_dat.nGageColor = RGBA(255,255,255,255)
 endif
        RETURN 0


The InvalidateRect API function has been removed from both since we are now using our GageInvalidateBackground to force a redraw of the gage's background.

The GAGE_DIAL_DARK handler now switches between the two fixed colors.

Now we will turn our attention to testing the above changes. To our test program (CCT_test.iwb) main window handler we have the following code structure:

SUB mainHandler(),INT
SELECT @MESSAGE
CASE @IDCREATE
centerwindow main
CASE @IDCLOSEWINDOW
run = 0
      CASE @IDTIMER
...


To trap messages from child controls we need to trap WM_NOTIFY messages that are being sent.  Or, as we learned earlier, @IDCONTROL messages.  So we will add that case to the above:

SUB mainHandler(),INT
SELECT @MESSAGE
CASE @IDCREATE
centerwindow main
CASE @IDCLOSEWINDOW
run = 0
CASE @IDCONROL
      CASE @IDTIMER
...


Next we need to identify which control is sending the message. We do that with a SELECT block as follows:

SUB mainHandler(),INT
SELECT @MESSAGE
CASE @IDCREATE
centerwindow main
CASE @IDCLOSEWINDOW
run = 0
CASE @IDCONTROL
SELECT @CONTROLID
CASE 1
CASE& 2
CASE& 3
CASE& 4
CASE& 5
CASE& 6
CASE& 7
CASE& 8
CASE& 9
CASE& 10

ENDSELECT
      CASE @IDTIMER
...


With the above we will respond the same to all gages. This structure allows us to add other controls like buttons and such.

The next step is to determine which message one of the gages sent.  We'll do that with another SELECT block. We'll test wparm which is also @NOTIFYCODE. The SELECT block with the cases for each of our four messages appears as follows:

SUB mainHandler(),INT
SELECT @MESSAGE
CASE @IDCREATE
centerwindow main
CASE @IDCLOSEWINDOW
run = 0
CASE @IDCONTROL
SELECT @CONTROLID
CASE 1
CASE& 2
CASE& 3
CASE& 4
CASE& 5
CASE& 6
CASE& 7
CASE& 8
CASE& 9
CASE& 10
SELECT @NOTIFYCODE
CASE GNMLUP
SetGagePanelColorRLM(main,@CONTROLID,RGB(255,255,255))
CASE GNMLDOWN
SetGagePanelColorRLM(main,@CONTROLID,RGB(255,0,0))
CASE GNMRDOWN
SetGageDialDarkRLM(main,@CONTROLID,1)
CASE GNMRUP
SetGageDialDarkRLM(main,@CONTROLID,0)
ENDSELECT
ENDSELECT
      CASE @IDTIMER
...


When the project is compiled and ran the following will happen:

Each time the left mouse button is depressed over a gage, the rectangle containing the gage will turn red.  

When the left mouse button is released over a gage, the rectangle will turn white.

Each time the right mouse button is depressed over a gage, the gage face will turn grey.  

When the right mouse button is released over a gage, the gage face will turn white.

Challenge: Run the program and get all the gage's faces grey and all the surrounding rectangles red, AT THE SAME TIME.


This completes all the drawing coding for our gages.

____________________________

Coming Next - Creating the Static Lib File