2.2. Specifying Widget Flags

The syntax for handling widget flags in Gamma is somewhat unique. What follows is a brief description of how to set, test, and clear flags on widgets in two different ways. The first is through a non-standard use of the assignment operator, and the second is through method calls. Following these is a short discussion on using bitmasks for flags that are not independent. For more examples, see the tutorial Set, Test, and Clear Widget Flags in the Building Applications - a Tutorial chapter.

2.2.1. Setting Flags

Flags can be set for widget instance variables using the = (assignment) operator and the name of the flag.

[Important]

The = operator is used in a unique way in Gamma for setting widget flags. It does NOT assign a completely new value to the variable. Rather, it adds or removes the value of a flag in the variable. The = operator in this context of Gamma has the same effect as the |= operator in C.

For example, to highlight a pane called Pane1, you would set the Pt_HIGHLIGHTED flag in the Pane1.flags variable, as follows.

Gamma> Pane1.flags = Pt_HIGHLIGHTED;
256

You can set several flags at once as long as you separate them by the | (bitwise or) operator. For example, to set Pane1 and etch its highlight, you would do this:

Gamma> Pane1.flags = Pt_SET | Pt_ETCH_HIGHLIGHT;
514

You can also set flags on a widget by assigning the value of the flags variable from another widget. When doing this, it is possible to mask one or more of the flags, so that they aren't set on the second widget. This requires conjoining the variable with negated constant(s) using the & (bitwise and) and ~ (bitwise not) operators. For example, to copy the flags from the example above to another pane called Pane2 without the Pt_ETCH_HIGHLIGHT flag or the Pt_SET flags on, you could do the following:

Gamma> Pane2.flags = Pane1.flags & ~Pt_ETCH_HIGHLIGHT & ~Pt_SET;
256

2.2.2. Testing Flags

If you need to check a variable to see if a constant flag is set on it or not, you can test it. Testing is done with the & (bitwise and) operator, the same as in C. However, once the flags variable has been conjoined with the constant, that value must be checked to see if it is equal to 0. This is because in Gamma 0 does not have the logical value of false. You have to make an explicit logical test.

For example, to test Pane1 and Pane2 for Pt_ETCH_HIGHLIGHT, you could do this:

Gamma> (Pane1.flags & Pt_ETCH_HIGHLIGHT) != 0;
t
Gamma> (Pane2.flags & Pt_ETCH_HIGHLIGHT) != 0;
nil

Gamma returns t if the flag variable is set, or nil if it is not set.

2.2.3. Clearing Flags

Flags are cleared using the cons function and nil. You make a cons cell with the flag as its first element and nil as its second element. This has the effect of giving the flag a value of 0, like using the &= and ~ operators together in C. For example, to clear the Pt_ETCH_HIGHLIGHT and Pt_HIGHLIGHTED flags from Pane1, you would do this:

Gamma> Pane1.flags = cons(Pt_ETCH_HIGHLIGHT, nil);
(512)
Gamma> Pane1.flags = cons(Pt_HIGHLIGHTED, nil);
(256)
Gamma> (Pane1.flags & (Pt_ETCH_HIGHLIGHT | Pt_HIGHLIGHT)) != 0;
nil

Incidentally, the cons function can also be used to set flags. Just cons the flag to t instead of nil. For example, to set the Pt_SET flag on Pane2, you could do this:

Gamma> Pane2.flags = cons(Pt_SET,t);
(2 . t)
Gamma> (Pane2.flags & Pt_SET) != 0;
t

2.2.4. Using Widget Method Calls

As an alternative to using the assignment operator, you can set, test, and clear instance variable flags on widgets using the SetBit, TestBit, and ClearBit methods of PtWidget, which is the parent widget for all of the Widget Classes. (See PtWidget for more information.) These methods are in the PhotonWidgets.lsp library, so you must make a call to require_lisp("PhotonWidgets.lsp") before using them.

Continuing with the example of Pane1 from above, you could set, test, and clear its Pt_HIGHLIGHTED flag as follows:

Gamma> require_lisp("PhotonWidgets.lsp");
"<pathname>PhotonWidgets.lsp"
Gamma> Pane1.SetBit(#flags, Pt_HIGHLIGHTED);
256
Gamma> Pane1.TestBit(#flags, Pt_HIGHLIGHTED);
t
Gamma> Pane1.ClearBit(#flags, Pt_HIGHLIGHTED);
(256)
Gamma> Pane1.TestBit(#flags, Pt_HIGHLIGHTED);
nil

Using these methods and/or the assignment operator as explained here, you should have no problem setting flags on most widgets.

2.2.5. Using Bitmasks and cons

Some flags are exclusive, meaning there can be only one of a group of them set at any given time. Setting one of these flags requires that any others in the group be unset first, but without unsetting those flags on the variable that are not part of the group. The easy way to do this is to use bitmasks and the cons function.

A bitmask consists of all the exclusive flags in the group ORed together. To set a flag, you simply cons it to the bitmask. For example, the RtTrend widget has a variable named rttrend_flags, with three flags that must be set exclusively: Rt_GRID_IS_TRANSLUCENT, Rt_GRID_ABOVE_TRENDS, and Rt_TRENDS_ABOVE_GRID. To set, for example, Rt_GRID_ABOVE_TRENDS, you would do this:

Gamma>  mask = Rt_GRID_IS_TRANSLUCENT
               | Rt_GRID_ABOVE_TRENDS
               | Rt_TRENDS_ABOVE_GRID;
1792
Gamma> trend.rttrend_flags = cons(Rt_GRID_ABOVE_TRENDS, mask);
(256 . 1792)
Gamma> (trend.rttrend_flags & Rt_GRID_ABOVE_TRENDS) != 0; 
t

Doing this:

cons(flags, mask)

is exactly equivalent to doing this:

(original & ~mask) | flags

where original is the original value of the variable. To illustrate what happens at bitwise level, let's look at two flags on an imaginary variable:

Flag 1       0010000
Flag 2       0001000
Bitmask      0011000

Suppose Flags 1 and 2 must be set exclusively from each other. In the example below, the variable has a few flags set already, including Flag 1. We want set Flag 1 OFF and Flag 2 ON. Using the Bitmask, we AND the original flags of the variable to the inverse of the bitmask, turning both flags OFF. Then we OR the result to Flag 2 to turn Flag 2 ON.

					
original:       10100010   Flag 1 and other flags are ON, Flag 2 is OFF.
AND ~Bitmask    11001111 
                --------
results:        10000010   Flag 1 is now OFF.


                10000010   The other flags are still ON.
OR Flag 2       00010000
                --------
final result:   10010010   Flag 2 is now ON as well.

2.2.6. Using cons: a Summary

The cons can be used in Gamma in different ways for different purposes. The following table gives a summary of how cons is used for handling widget flags.

Table 2.1. Using cons with widget flags.

Gamma SyntaxMeaning
widget.variable = flags;widget.variable = (original | flags)
widget.variable = cons(flags, t);widget.variable = (original | flags)
widget.variable = cons(flags, nil);widget.variable = (original & ~flags)
widget.variable = cons(flags, mask);widget.variable = (original & ~mask) | flags