8.4. Callback Functions - slider_callback, num_callback

Although this section is named "Callback Functions," the functions here do one or two things in addition to attaching callbacks. The first function works specifically with PtSlider widgets; the second with PtNumeric widgets.

   /*--------------------------------------------------------------------
    * Function:    slider_callback
    * Returns:     t or nil
    * Description: Attaches a callback and adds an exception function to
    *              a slider widget.  The callback writes a value to the
    *              datahub point specified, and the exception function
    *              assigns the value of the datahub point to the slider
    *              widget whenever the value of the point changes in the
    *              datahub.
    *------------------------------------------------------------------*/
   function slider_callback(sld, !pnt)
   {
     PtAttachCallback(sld, Pt_CB_SLIDER_MOVE,
                      `write_point(@pnt, ((@sld).gauge_value)));
     add_exception_function(eval(pnt),
                            `(@sld).gauge_value = (@eval(pnt)));
   }
   

In both of these functions, the callbacks are created using the Gamma function PtAttachCallback, while the exception function is added with the Gamma function add_exception_function.

In these functions the pnt parameter has an exclamation point (!) in front of it, indicating that it is passed in as a protected argument (as explained in the Function Arguments section of the Gamma manual), and thus is not evaluated. We do this because normally a function evaluates its arguments, but in the callback the Gamma write_point function uses the unevaluated name of the point as a parameter. However, the rest of the function has to refer to the point itself, and its value, so we use the Gamma eval function to evaluate it once to get the point name, and again to get its value.

Here also are more examples of the use of Gamma's quote operators. It is useful to know that the @ operator applies to the whole expression it precedes. For example, the expression @sld.gauge_value would allow for the evaluation of the current value of the slider at the time that this code is read. The expression (@sld).gauge_value evaluates the slider immediately, but the slider's gauge_value is not evaluated until an exception is received.

This explains an apparent inconsistency in the last expression of the add_exception_functions. In the slider_callback function you see the expression (@eval(pnt)), while in the num_callback function you see eval(@pnt). In both functions the pnt parameter passed in is protected from evaluation. This means it must be evaluated once to get the name of the point, and another time to get its value. In the slider_callback function, the expression (@eval(pnt)) allows both of these evaluations to occur, once by the @ symbol, and once by the eval function. In the num_callback function, there is an extra line of code that evaluates the pnt variable, and assigns it the resulting name of the datahub point. We use that name when we set up the function (hence the use of pnt and @pnt), and we protect the point from evaluation until a datahub exception is received by not using the @ symbol in front of the eval function.

[Note]

This function is an adaptation of the abstracted function anyver_numeric_callback explained in Tutorial Two.

   /*--------------------------------------------------------------------
    * Function:    num_callback
    * Returns:     t or nil
    * Description: Sets up a callback and an exception function for PtNumeric
    *              widgets to deal with sending changed values to and from
    *              the datahub.  Assigns initial values to the widgets.
    *------------------------------------------------------------------*/
   function num_callback(num, !pnt)
   {
     if(_os_ == "QNX4")
       {
         PtAttachCallback(num, Pt_CB_NUMERIC_CHANGED,
                          `write_point(@pnt, ((@eval(num)).numeric_value)));
         pnt = eval(pnt);
         num.numeric_value = eval(pnt);
         add_exception_function(pnt, `(@num).numeric_value = eval(@pnt));
       }
     else
       {
         
         /* Handle an annoying characteristic in Photon 2 (OS is QNX 6) whose
            PtNumericFloat widget does not work properly in Gamma. Thus we need
            to use a PtNumericInteger widget, and convert back and forth to write
            points and receive exceptions. The widget that corresponds to FREQ_001
            is a PtNumericInteger, which is already an integer.*/
         
         if (eval(pnt) != #FREQ_001)
           {
             PtAttachCallback(num, Pt_CB_NUMERIC_CHANGED,
                              `write_point(@pnt, ((@eval(num)).numeric_value) / 100.0));
             pnt = eval(pnt);
             num.numeric_value = round(eval(pnt) * 100);
             add_exception_function(pnt, `((@num).numeric_value = round(eval(@pnt) * 100)));
           }
         else
           {
             PtAttachCallback(num, Pt_CB_NUMERIC_CHANGED,
                              `write_point(@pnt, ((@eval(num)).numeric_value)));
             pnt = eval(pnt);
             num.numeric_value = eval(pnt);
             add_exception_function(pnt, `(@num).numeric_value = eval(@pnt));
           }
       }
   }